diff --git a/include/tcap.h b/include/tcap.h index a17833385..ec5e9a336 100644 --- a/include/tcap.h +++ b/include/tcap.h @@ -9,6 +9,7 @@ #define TCAP_H #ifndef MICRO +/* NLE: We use ANSI_DEFAULT for terminal handling*/ #ifndef RL_GRAPHICS #define TERMLIB /* include termcap code */ #endif diff --git a/win/Qt/Info.plist b/win/Qt/Info.plist deleted file mode 100644 index f2e9195ee..000000000 --- a/win/Qt/Info.plist +++ /dev/null @@ -1,20 +0,0 @@ - - - - - CFBundleGetInfoHTML - http://www.nethack.org - CFBundleGetInfoString - Copyright (C) 1985-2003 Stichting Mathematisch Centrum - CFBundleIconFile - nethack.icns - CFBundleIdentifier - org.nethack.qt - CFBundlePackageType - APPL - CFBundleShortVersionString - 3.5.0 - CFBundleSignature - NHak - - diff --git a/win/Qt/Install.Qt b/win/Qt/Install.Qt deleted file mode 100644 index 6a3de9c3e..000000000 --- a/win/Qt/Install.Qt +++ /dev/null @@ -1,113 +0,0 @@ -Installing NetHack with a Qt or KDE interface ---------------------------------------------- -$NHDT-Date: 1524689332 2018/04/25 20:48:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.11 $ -# Copyright (c) 2004 by Warwick Allison -# NetHack may be freely redistributed. See license for details. - -This document describes the installation of NetHack with a Qt interface -on UNIX/X11 or Mac OS X. This code should also work with Qt/Windows, but -support for that is not currently official. - -You can download Qt from http://www.trolltech.com. -You need Qt 2.0 or later to use this code. - -To use this code on UNIX (not Mac OS X): - - 1. follow the directions for the UNIX installation (in ../../sys/unix) - to create the Makefiles. - - 2. ../../include/config.h - - define QT_GRAPHICS (search for it). You can comment out - TTY_GRAPHICS if you want to, or leave it in to support both - interfaces (in which case be sure you have the right curses - libraries etc. required for that interface). - - 3. ../../src/Makefile - - ensure your QTDIR environment variable was set correctly when - you installed Qt - $QTDIR/include/qwidget.h should exist, for - example. - - ensure CXX and LINK are set to the compiler and linker you need - for compiling and linking C++ software (e.g., set both to g++). - - add $(WINQTSRC), $(WINQTOBJ), and $(WINQTLIB) to WINSRC, WINOBJ, - and WINLIB respectively, and compile. This will give you an - executable supporting both Qt and tty windowing. - - 4. ../../Makefile (the top-level makefile) - - Just change the VARDATND setting to contain the files - "x11tiles", "rip.xpm", and "nhsplash.xpm": - - VARDATND = x11tiles rip.xpm nhsplash.xpm - - 5. Follow all the instructions in ../../sys/unix/Install.unx for - the remainder of the installation process. - - 6. Consider adding the lines below to your .nethackrc, as they are - likely to give the best interface for this window port: - - OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp - OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt - -If you are using KDE, you may want to also try the KDE version. It just -uses the KDE menubar and follows other KDE conventions - there is no -extra functionality. To do so: - - 1. Ensure that you have KDE 2.x libraries on your system - (in 1999 KDE 1.x was the norm) - - 2. ../../src/Makefile - - Add $(KDECXXFLAGS) to the CXXFLAGS definition, $(KDELFLAGS) to - the LFLAGS definition and $(WINKDELIB) to WINLIB. - - 3. Some additional files here - knh-mini.xpm, knh.xpm, and - knethack.lnk are useful if you want to install "knethack" in - the KDE games directory. - -If you are using Qtopia, you can compile NetHack for that environment -with the following additional steps: - - 1. First be sure that you can build a simple Qtopia application, - such as the examples that ship with Qtopia. Do not attempt - something as challenging to compile as NetHack before you can - already build a Qtopia application for your target device. - - 2. If you are cross-compiling (eg. targetting an ARM-based handheld), - be sure to follow the steps for cross-compiling in the Makefile.src - and Makefile.utl files. - - 3. To CXXFLAGS in Makefile.src, add: - -DQWS -I$(QPEDIR)/include -fno-rtti -fno-exceptions - - 4. Rather than -lqt in WINQTLIB, have: - -L$(QPEDIR)/lib -lqpe -lqte - - 5. After building, use the "mkipks" program that ships with Qtopia - to package the result into an ipk file. - -To use this code on Mac OS X: - - 1. follow the directions for the UNIX installation (in ../../sys/unix) - to create the Makefiles. - - 2. quite a number of changes are required to the Makefiles. They are - slowly being made 'official', but for now they are all in the patch - nethack-macosx-qt.patch: - - cd ../.. - patch -p0 < win/Qt/nethack-macosx-qt.patch - - 3. Follow all the instructions in ../../sys/unix/Install.unx for - the remainder of the installation process (basically run "make install"). - - 4. Consider adding the lines below to a file called "NetHack Defaults", - in your "Library/Preferences" folder, as they are likely to give - the best interface for this window port: - - OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp - OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt - diff --git a/win/Qt/Qt-issues.txt b/win/Qt/Qt-issues.txt new file mode 100644 index 000000000..1de8b9c8c --- /dev/null +++ b/win/Qt/Qt-issues.txt @@ -0,0 +1,68 @@ +Qt-NetHack issues +----- + +Urgent: if the program crashes on OSX, a dialog box asking the user +whether to [ignore], [report...], or [re-open] will eventually appear +(it's slow). That should be repressed even if the report choice could +be directed at nethack.org. + +Launching Qt nethack as a synchronous subprocess (ie, no trailing '&') +from a Terminal window, changing focus back to that terminal after +NetHack has started, and typing ^C was sending the program into an +endless loop in qt_nhgetch() with repeated messages to stderr +(the terminal) complaining that the event loop is already running. +Triggered by yn_function("Really quit?") in the core. That situation +has been reduced to a single event loop complaint, so downgraded from +"Urgent", but the prompt is auto-answered with ESC instead of letting +the user respond. + +On OSX, if the program is run from nethackdir/nethack rather than from +NetHack.app/Contents/MacOS/nethack (plus having NetHack.app/Contents/ +Info.plist containing pertinent information) then the menu bar at the +top of the screen won't accept mouse clicks and the application menu +entry in that menu bar will show as "nethack" (filename) rather than +"NetHack" (intended application name). The click issue can be worked +around by giving focus to some other application (which will put up +its own menu bar) and then back to nethack (thereby reloading nethack's +menu bar). + +Sometimes scrolling a menu leaves the displayed text not matching what +nethack thinks is displayed, so making a selection by mouse click may +occasionally pick the wrong item. There's usually a visual clue when +this happens. As long as it's not a pick-one menu, scrolling up and +down or back and worth a few times will usually get things back in +sync, then you can click on the wrong entry to uncheck it and then on +the right entry to check that. Making a selection by typing its +letter doesn't suffer from this, but isn't always possible (ie, long +menu like 'O's where first 52 items have letters but remainder don't). + +On OSX, command+Q while a menu (which has its own key event handler) +is popped up gets ignored. It should at least close the popup like +ESC and maybe also initiate quitting. + +Map column #0, which the core reserves for its own purposes and isn't +intended to be displayed, is displayed (as blank terrain). + +5.0 status conditions haven't been implemented. + +3.6 status conditions (Stone, Slime, Strngl, Deaf, Lev, Fly, Ride) +have been implemented but need icon artwork (one 40x40 tile for each). + +Clicking on window close button pops up a confirmation dialog with + [ Save and exit ] [__Quit_without_saving__] +with the second one highlighted. Internally they're specified as +"&Save" and "&Quit". Typing or picks Quit, but +typing 'Q' or 'q' picks Save-and-exit because Alt+Q is expected for +the keyboard shortcut. + +The status window can't be resized while hitpointbar is active. +Toggling it off, resizing as desired, then toggling it back on is a +viable workaround. + +When choosing a saved game to restore ('selectsaved' option), the +selection dialog does not provide any way to scroll if there are more +games than will fit on the screen. Access to "New game" and "Quit" +isn't affected because those both have distinct buttons rather than +rely on fake save file entries at the end of the list. + +----- diff --git a/win/Qt/knethack.lnk b/win/Qt/knethack.lnk deleted file mode 100644 index 35e01f920..000000000 --- a/win/Qt/knethack.lnk +++ /dev/null @@ -1,18 +0,0 @@ -# KDE Config File -# Call this file knethack.kdelnk or knethack.desktop -[KDE Desktop Entry] -Name=Nethack -Name[fr]=Nethack -Name[hu]=Nethack -Name[no]=Nethack -Name[sk]=Nethack -Name[cs]=Nethack -Name[hr]=Nethack -Name[pt]=Nethack -Name[pt_BR]=Nethack -Icon=knh.xpm -Exec=knethack -caption "%c" %i %m -Type=Application -DocPath=knethack/index.html -Comment=The classic Unix role-playing game - fight monsters and seek the Amulet of Yendor for your god! - diff --git a/win/Qt/knh-mini.xpm b/win/Qt/knh-mini.xpm deleted file mode 100644 index 05bd70e6f..000000000 --- a/win/Qt/knh-mini.xpm +++ /dev/null @@ -1,30 +0,0 @@ -/* XPM */ -static char *noname[] = { -/* width height ncolors chars_per_pixel */ -"16 16 7 1", -/* colors */ -" c #000000", -". c #DCDCDC", -"X c #008080", -"o c #A0A0A0", -"O c None", -"+ c #FFFFFF", -"@ c #C3C3C3", -/* pixels */ -"OOOOOOOOOOOOOOOO", -"OOO+O+++@@@O@OOO", -"O+O+++++@@@@@O.O", -"O+o+XXXXX X @ . ", -"O+o+XXXX X X@ . ", -"OO +XXXXX X @ O ", -"OOO+XXXX X X@ OO", -"OOO+XXXXX X @ OO", -"OOO+XXXX X X@ OO", -"OOOO+XXXX X@ OO", -"OOOO+XXX X . OO", -"OOO+O+XXX . . OO", -"OO+++ +X . ... O", -"O+++. O+. .... ", -"OO+. OOOOOO.. O", -"OOOOOOOOOOOOOOOO" -}; diff --git a/win/Qt/knh.xpm b/win/Qt/knh.xpm deleted file mode 100644 index 9c0312796..000000000 --- a/win/Qt/knh.xpm +++ /dev/null @@ -1,67 +0,0 @@ -/* XPM */ -static char *noname[] = { -/* width height ncolors chars_per_pixel */ -"40 40 20 1", -/* colors */ -" c #000000", -". c #0000C0", -"X c #FFC0FF", -"o c #FFC0C0", -"O c #DCDCDC", -"+ c #C0C0FF", -"@ c #008080", -"# c #A0A0A0", -"$ c None", -"% c #000080", -"& c #585858", -"* c #800080", -"= c #FFFFFF", -"- c #FFFFC0", -"; c #00C0C0", -": c #C0FFFF", -"> c #C0FFC0", -", c #C3C3C3", -"< c #FFDCA8", -"1 c #0000FF", -/* pixels */ -"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", -"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", -"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", -"$$$$$$$$=$$$$$$=,==<,=<,$$$$$$,$$$$$$$$$", -"$$$$$$$$==$$$=====,=<>,<><$$$<>$$$$$$$$$", -"$$$$$$$$===$====,==>,=<,<,,$,,<$$$$$$$$$", -"$$$==$$$==========<=<,><,><<><,$$$,<$$$$", -"$$$====$========,==,,=<>,<,>,<,$<><,$$$$", -"$$$====$==========<=<,,<<><,<><$,,<>$$$$", -"$$$$#&&&==$#$#$#@#$&@#&&@&&&&,, && $$", -"$$$;#@&@==;#;#;#$;&#@&@$&@&@$>< &@ $$", -"$$$====&==###1##.##@&#&@&&$&&<, <>O< $$", -"$$$====&==$;##;##;&#@&@$&@&@&>, O<,> $$", -"$$$==&@&==#1#;##.##@&#&@&$@$&,< ,< $$", -"$$$$ ==###1#;##.#@$&&&@&&@-, $ $$", -"$$$$$ =X;#;###&;#&@#&@$&@$&,< $$ $$$", -"$$$$$$ ==#$+@+1##@#&@&$@&&&@<> $$$$$$", -"$$$$$$$$=X;#1#$#@##@&#@&&&@$&<, $$$$$$", -"$$$$$$$$==##;#;##1$#@&$@$&&@&>< $$$$$$", -"$$$$$$$$=X;###1#@##@&#@&&@$&&O, $$$$$$", -"$$$$$$$$==#1#;##;#.#@&&$@&@&@<> $$$$$$", -"$$$$$$$$$==###;#*;#&@#&@&&$&O< $$$$$$$", -"$$$$$$$$$==;#1,$;#&#@$@&$@&@<, $$$$$$$", -"$$$$$$$$$$=X####.##@&#&&@&& ><, $$$$$$", -"$$$$$$====@&=O##@#;&@#&&,< <,>< $$$$$", -"$$$$$===#$== ==$1#&#&@&O> ,<$#,,> $$$$", -"$$$$===#;#== ==$#;&@#O, >,#;&<,< $$$$", -"$$$==$#;*@O< ====Oo,> <,&$#@&O, $$$", -"$$$==;$#&&<, $===<,< < $$", -"$$$==##;&O>, $$==,> $$ ,<&&#$@o, $$", -"$$$===X=O,< $$$$$$$$$$$$$>OO,Oo> $$$", -"$$$$====,< $$$$$$$$$$$$$$,<,>,<, $$$$", -"$$$$$===<> $$$$$$$$$$$$$$$$><,<> $$$$", -"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", -"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", -"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", -"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" -}; diff --git a/win/Qt/qpe-nethack.control b/win/Qt/qpe-nethack.control deleted file mode 100644 index c8b73f5f7..000000000 --- a/win/Qt/qpe-nethack.control +++ /dev/null @@ -1,9 +0,0 @@ -Files: bin/nethack pics/NetHack.png apps/Games/nethack.desktop games/lib/nethackdir/[a-r]* games/lib/nethackdir/[t-z]* games/lib/nethackdir/save games/lib/nethackdir/s*.* games/lib/nethackdir/[A-Z0-9]* -Priority: optional -Section: qpe/games -Maintainer: Warwick Allison -Architecture: arm -Version: 3.5.0-1 -Depends: qpe-base ($QPE_VERSION) -Description: NetHack - The Dungeon Game - Graphical version of NetHack for Qtopia diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp new file mode 100644 index 000000000..feb716a2d --- /dev/null +++ b/win/Qt/qt_bind.cpp @@ -0,0 +1,1331 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_bind.cpp -- bindings between the Qt 4 interface and the main code + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#include +#if defined(USER_SOUNDS) && !defined(QT_NO_SOUND) +#if QT_VERSION < 0x050000 +#include +#elif QT_VERSION < 0x060000 +#include +#include +#else +/* Qt6 or above */ +#include +#include +#endif /* QT_VERSION */ +#endif /* USER_SOUNDS && !QT_NO_SOUND */ +#include "qt_post.h" +#include "qt_bind.h" +#include "qt_click.h" +#ifdef TIMED_DELAY +#include "qt_delay.h" +#endif +#include "qt_xcmd.h" +#include "qt_key.h" +#include "qt_map.h" +#include "qt_menu.h" +#include "qt_msg.h" +#include "qt_plsel.h" +#include "qt_svsel.h" +#include "qt_set.h" +#include "qt_stat.h" +#include "qt_streq.h" +#include "qt_yndlg.h" +#include "qt_str.h" + +extern "C" { +#include "dlb.h" +} + +// temporary +extern int qt_compact_mode; +// end temporary + +namespace nethack_qt_ { + +// XXX Should be from Options [or from Qt Settings (aka Preferences)]. +// +// XXX Hmm. Tricky part is that perhaps some macros should only be active +// XXX when a key is about to be gotten. For example, the user could +// XXX define "-" to do "E-yyyyyyyy\r", but would still need "-" for +// XXX other purposes. Maybe just too bad. +// +static struct key_macro_rec { + int key; + uint state; + const char *macro, *numpad_macro; +} key_macro[]={ + { Qt::Key_F1, 0U, "100.", "n100." }, // Rest (x100) + { Qt::Key_F2, 0U, "20s", "n20s" }, // Search (x20) + { Qt::Key_Tab, 0U, "\001", "\001" }, // ^A (Do-again) + { 0, 0U, (const char *) 0, (const char *) 0 } +}; + +#ifdef IDLECHECKPOINT +#ifndef IDLECHECKPOINT_WAIT_TIME +#define IDLECHECKPOINT_WAIT_TIME 10 +#endif +static void qt_timer_fire(void); +QTimer *qt_input_timer; +#endif + +static QPen *pen = (QPen *) 0; + +NetHackQtBind::NetHackQtBind(int& argc, char** argv) : +#ifdef KDE + KApplication(argc,argv) +#elif defined(QWS) // not quite the right condition + QPEApplication(argc,argv) +#else + QApplication(argc,argv) +#endif +{ + splash = 0; + if (iflags.wc_splash_screen) + NetHackQtBind::qt_Splash(); // show something while starting up + + // these used to be in MainWindow but we want them before QtSettings + // which we want before MainWindow... + QCoreApplication::setOrganizationName("The NetHack DevTeam"); + QCoreApplication::setOrganizationDomain("nethack.org"); + QCoreApplication::setApplicationName("NetHack-Qt"); // Qt NetHack + { + char cvers[BUFSZ]; + QString qvers = QString(::version_string(cvers, sizeof cvers)); + QCoreApplication::setApplicationVersion(qvers); + } +#ifdef MACOS + /* without this, neither control+x nor option+x do anything; + with it, control+x is ^X and option+x still does nothing */ + QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta); +#endif + + qt_settings = new NetHackQtSettings(); /*(main->width(),main->height());*/ + + main = new NetHackQtMainWindow(keybuffer); + connect(qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit())); + msgs_strings = new QStringList(); + msgs_initd = false; + msgs_saved = false; +} + +// before the game windows have been rendered, display a small, centered +// window showing a flying red dragon ridden by someone wielding a lance, +// with caption "Loading..." +void +NetHackQtBind::qt_Splash() +{ + QPixmap pm("nhsplash.xpm"); // load splash image from a file in HACKDIR + if (!pm.isNull()) { + splash = new QFrame(NULL, (Qt::FramelessWindowHint + | Qt::X11BypassWindowManagerHint + | Qt::WindowStaysOnTopHint)); + QVBoxLayout *vb = new QVBoxLayout(splash); + QLabel *lsplash = new QLabel(splash); + vb->addWidget(lsplash); + lsplash->setAlignment(Qt::AlignCenter); + lsplash->setPixmap(pm); + lsplash->setFixedSize(pm.size()); + //lsplash->setMask(pm.mask()); + QLabel *capt = new QLabel("Loading...", splash); + vb->addWidget(capt); + capt->setAlignment(Qt::AlignCenter); + +#if QT_VERSION < 0x060000 + QSize screensize = QApplication::desktop()->size(); +#else + QSize screensize = splash->screen()->size(); +#endif + splash->move((screensize.width() - pm.width()) / 2, + (screensize.height() - pm.height()) / 2); + //splash->setGeometry(0,0,100,100); + if (qt_compact_mode) { + splash->showMaximized(); + } else { +#if __cplusplus >= 202002L + splash->setFrameStyle(static_cast(QFrame::WinPanel) + | static_cast(QFrame::Raised)); +#else + splash->setFrameStyle(QFrame::WinPanel | QFrame::Raised); +#endif + splash->setLineWidth(10); + splash->adjustSize(); + splash->show(); + } + + // force content refresh outside event loop + splash->repaint(); + lsplash->repaint(); + capt->repaint(); + qApp->processEvents(); + } else { + splash = 0; // caller has already done this... + } +} + +void NetHackQtBind::qt_init_nhwindows(int *argc, char **argv) +{ + // menu entries use embedded to align fields; + // it could be toggled off via 'O', but only when in wizard mode + ::iflags.menu_tab_sep = true; + + // force high scores display to be shown in a window, and don't allow + // that to be toggled off via 'O' (note: 'nethack -s' won't reach here; + // its output goes to stdout so can potentially be redirected into a file) + ::iflags.toptenwin = true; + ::set_option_mod_status("toptenwin", ::set_in_config); + +#ifdef UNIX +// Userid control +// +// Michael Hohmuth ... +// +// As the game runs setuid games, it must seteuid(getuid()) before +// calling XOpenDisplay(), and reset the euid afterwards. +// Otherwise, it can't read the $HOME/.Xauthority file and whines about +// not being able to open the X display (if a magic-cookie +// authorization mechanism is being used). + + uid_t gamesuid=geteuid(); + seteuid(getuid()); +#endif + + instance=new NetHackQtBind(*argc,argv); + +#ifdef UNIX + seteuid(gamesuid); +#endif + +#ifdef _WS_WIN_ + // This nethack engine feature should be moved into windowport API + nt_kbhit = NetHackQtBind::qt_kbhit; +#endif + +#ifndef DYNAMIC_STATUSLINES + // 'statuslines' option can be set in config file but not via 'O' + set_wc2_option_mod_status(WC2_STATUSLINES, set_gameview); +#endif +#if defined(SND_LIB_QTSOUND) && !defined(QT_NO_SOUND) + /* assign_soundlib() just flags to NetHack which soundlib + * should be loaded by activate_chosen_soundlib() shortly. + * gc.chosen_soundlib is initialized to soundlib_nosound. + */ + if (gc.chosen_soundlib == (uint32_t) soundlib_nosound) { + uint32_t soundlibchoice = (uint32_t) soundlib_qtsound; + + assign_soundlib(soundlibchoice); + } +#endif +} + +int NetHackQtBind::qt_kbhit() +{ + return !keybuffer.Empty(); +} + + +static bool have_asked = false; + +void NetHackQtBind::qt_player_selection() +{ + if ( !have_asked ) + qt_askname(); +} + +void NetHackQtBind::qt_askname() +{ + char default_plname[PL_NSIZ]; + int ch = -1; // -1 => new game + + have_asked = true; + str_copy(default_plname, svp.plname, PL_NSIZ); + + // We do it all here (plus qt_plsel.cpp and qt_svsel.cpp), + // nothing in player_selection(). + +#ifdef SELECTSAVED + char **saved = 0; + if (::iflags.wc2_selectsaved) + saved = get_saved_games(); + if (saved && *saved) { + if (splash) + splash->hide(); + NetHackQtSavedGameSelector sgsel((const char **) saved); + ch = sgsel.choose(); + if (ch >= 0) + str_copy(svp.plname, saved[ch], SIZE(svp.plname)); + // caller needs new lock name even if plname[] hasn't changed + // because successful get_saved_games() clobbers gs.SAVEF[] + ::iflags.renameinprogress = TRUE; + } + free_saved_games(saved); +#endif + + switch (ch) { + case -1: + // New Game + if (splash) + splash->hide(); + if (NetHackQtPlayerSelector(keybuffer).Choose()) { + // success; handle plname[] verification below prior to returning + break; + } + FALLTHROUGH; + /*FALLTHRU*/ + case -2: + // Quit + clearlocks(); + qt_exit_nhwindows(0); + nh_terminate(0); + /*NOTREACHED*/ + break; + default: + // picked a character from the saved games list + break; + } + + if (!*svp.plname) + // in case Choose() returns with plname[] empty + Strcpy(svp.plname, default_plname); + else if (strcmp(svp.plname, default_plname) != 0) + // caller needs to set new lock file name + ::iflags.renameinprogress = TRUE; + return; +} + +void NetHackQtBind::qt_get_nh_event() +{ +} + +#if defined(QWS) +// Kludge to access lastWindowClosed() signal. +class TApp : public QApplication { +public: + TApp(int& c, char**v) : QApplication(c,v) {} + void lwc() { emit lastWindowClosed(); } +}; +#endif + +void NetHackQtBind::qt_exit_nhwindows(const char *) +{ +#ifdef IDLECHECKPOINT + if (qt_input_timer) { + NetHackQtBind::free_qt_input_timer(); + } +#endif +#if defined(QWS) + // Avoids bug in SHARP SL5500 + ((TApp*)qApp)->lwc(); + qApp->quit(); +#endif + + delete instance; // ie. qApp +} + +void NetHackQtBind::qt_suspend_nhwindows(const char *) +{ +} + +void NetHackQtBind::qt_resume_nhwindows() +{ +} + +static QVector id_to_window; + +winid NetHackQtBind::qt_create_nhwindow(int type) +{ + winid id; + for (id = 0; id < (winid) id_to_window.size(); id++) { + if ( !id_to_window[(int)id] ) + break; + } + if ( id == (winid) id_to_window.size() ) + id_to_window.resize(id+1); + + NetHackQtWindow* window=0; + + switch (type) { + case NHW_MAP: { + NetHackQtMapWindow2* w=new NetHackQtMapWindow2(clickbuffer); + main->AddMapWindow(w); + window=w; + break; + } + case NHW_MESSAGE: { + NetHackQtMessageWindow* w=new NetHackQtMessageWindow; + main->AddMessageWindow(w); + window=w; + break; + } + case NHW_STATUS: { + NetHackQtStatusWindow* w=new NetHackQtStatusWindow; + main->AddStatusWindow(w); + window=w; + break; + } + case NHW_MENU: + window=new NetHackQtMenuOrTextWindow(mainWidget()); + break; + case NHW_TEXT: + window=new NetHackQtTextWindow(mainWidget()); + break; + } + + window->nhid = id; + + // Note: use of isHidden does not work with Qt 2.1 + if ( splash +#if QT_VERSION >= 300 + && !main->isHidden() +#else + && main->isVisible() +#endif + ) { + delete splash; + splash = 0; + } + + id_to_window[(int)id] = window; + return id; +} + +void NetHackQtBind::qt_clear_nhwindow(winid wid) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + if (window) + window->Clear(); +} + +void NetHackQtBind::qt_display_nhwindow(winid wid, boolean block) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + if (window) + window->Display(block); +} + +void NetHackQtBind::qt_destroy_nhwindow(winid wid) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + if (window) { + main->RemoveWindow(window); + if (window->Destroy()) + delete window; + id_to_window[(int) wid] = 0; + } +} + +void NetHackQtBind::qt_curs(winid wid, int x, int y) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + window->CursorTo(x,y); +} + +void NetHackQtBind::qt_putstr(winid wid, int attr, const char *text) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + window->PutStr(attr,QString::fromLatin1(text)); +} + +void NetHackQtBind::qt_putstr(winid wid, int attr, const std::string& text) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + window->PutStr(attr,QString::fromLatin1(text.c_str(), text.size())); +} + +void NetHackQtBind::qt_putstr(winid wid, int attr, const QString& text) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + window->PutStr(attr,text); +} + +void NetHackQtBind::qt_display_file(const char *filename, boolean must_exist) +{ + NetHackQtTextWindow* window=new NetHackQtTextWindow(mainWidget()); + bool complain = false; + + { + dlb *f; + char buf[BUFSZ]; + char *cr; + + window->Clear(); + f = dlb_fopen(filename, "r"); + if (!f) { + complain = must_exist; + } else { + while (dlb_fgets(buf, BUFSZ, f)) { + if ((cr = strchr(buf, '\n')) != 0) *cr = 0; +#ifdef MSDOS + if ((cr = strchr(buf, '\r')) != 0) *cr = 0; +#endif + window->PutStr(ATR_NONE, tabexpand(buf)); + } + window->Display(false); + (void) dlb_fclose(f); + } + } + + if (complain) { + QString message = nh_qsprintf("File not found: %s\n",filename); + QMessageBox::warning(NULL, "File Error", message, QMessageBox::Ignore); + } +} + +void NetHackQtBind::qt_start_menu(winid wid, unsigned long mbehavior UNUSED) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + window->StartMenu(wid == WIN_INVEN); +} + +void NetHackQtBind::qt_add_menu(winid wid, const glyph_info *glyphinfo, + const ANY_P * identifier, char ch, char gch, int attr, int clr, + const char *str, unsigned itemflags) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + window->AddMenu(glyphinfo->glyph, identifier, ch, gch, attr, clr, + QString::fromLatin1(str), + itemflags); +} + +void NetHackQtBind::qt_end_menu(winid wid, const char *prompt) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + window->EndMenu(prompt); +} + +int NetHackQtBind::qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + return window->SelectMenu(how,menu_list); +} + +void NetHackQtBind::qt_update_inventory(int arg UNUSED) +{ + if (main) + main->updateInventory(); // update the paper doll inventory subset + + /* doesn't work yet + if (program_state.something_worth_saving && iflags.perm_invent) + repopulate_perminvent(); + */ +} + +win_request_info *NetHackQtBind::qt_ctrl_nhwindow( + winid wid, + int request, + win_request_info *wri) +{ + NetHackQtWindow* window UNUSED =id_to_window[(int)wid]; + + if (!wri) + return (win_request_info *) 0; + + switch(request) { + case set_mode: + case request_settings: + break; + case set_menu_promptstyle: + /* = wri->fromcore.menu_promptstyle; */ + break; + default: + break; + } + return wri; +} + +void NetHackQtBind::qt_mark_synch() +{ +} + +void NetHackQtBind::qt_wait_synch() +{ +} + +void NetHackQtBind::qt_cliparound(int x, int y) +{ + // XXXNH - winid should be a parameter! + qt_cliparound_window(WIN_MAP,x,y); +} + +void NetHackQtBind::qt_cliparound_window(winid wid, int x, int y) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + window->ClipAround(x,y); +} + +void NetHackQtBind::qt_print_glyph( + winid wid, coordxy x, coordxy y, + const glyph_info *glyphinfo, + const glyph_info *bkglyphinfo) +{ + /* TODO: bkglyph */ + NetHackQtWindow *window = id_to_window[(int) wid]; + window->PrintGlyph(x, y, glyphinfo, bkglyphinfo); +} + +#if 0 +void NetHackQtBind::qt_print_glyph_compose( + winid wid, coordxy x, coordxy y, int glyph1, int glyph2) +{ + NetHackQtWindow *window = id_to_window[(int) wid]; + window->PrintGlyphCompose(x, y, glyph1, glyph2); +} +#endif /*0*/ + +// +// FIXME: sending output to stdout can mean that the player never sees it. +// +void NetHackQtBind::qt_raw_print(const char *str) +{ + puts(str); +} + +void NetHackQtBind::qt_raw_print_bold(const char *str) +{ + qt_raw_print(str); +} + +const QPen NetHackQtBind::nhcolor_to_pen(uint32_t c) +{ + if (!pen) { + pen = new QPen[17]; + + pen[ 0] = QColor(64, 64, 64); // black + pen[ 1] = QColor(Qt::red); + pen[ 2] = QColor(0, 191, 0); // green + pen[ 3] = QColor(127, 127, 0); // brownish + pen[ 4] = QColor(Qt::blue); + pen[ 5] = QColor(Qt::magenta); + pen[ 6] = QColor(Qt::cyan); + pen[ 7] = QColor(Qt::gray); + // on tty, "light" variations are "bright" instead; here they're paler + pen[ 8] = QColor(Qt::white); // no color + pen[ 9] = QColor(255, 127, 0); // orange + pen[10] = QColor(127, 255, 127); // light green + pen[11] = QColor(Qt::yellow); + pen[12] = QColor(127, 127, 255); // light blue + pen[13] = QColor(255, 127, 255); // light magenta + pen[14] = QColor(127, 255, 255); // light cyan + pen[15] = QColor(Qt::white); + // ? out of range for 0..15 + pen[16] = QColor(Qt::black); + } + +#ifdef ENHANCED_SYMBOLS + if (c & 0x80000000) { + return QColor( + (c >> 16) & 0xFF, + (c >> 8) & 0xFF, + (c >> 0) & 0xFF); + } else +#endif + { + return pen[c]; + } +} + +int NetHackQtBind::qt_nhgetch() +{ + if (main) + main->fadeHighlighting(true); + + // Process events until a key arrives. + // + while (keybuffer.Empty()) { + int exc = qApp->exec(); + /* + * On OSX (possibly elsewhere), this prevents an infinite + * loop repeatedly issuing the complaint: +QCoreApplication::exec: The event loop is already running + * to stderr if you synchronously start nethack from a terminal + * then switch focus back to that terminal and type ^C. + * SIGINT -> done1() -> done2() -> yn_function("Really quit?") + * in the core asks for another keystroke. + * + * However, it still issues one such complaint, and whatever + * prompt wanted a response ("Really quit?") is shown in the + * message window but is auto-answered with ESC. + */ + if (exc == -1) + keybuffer.Put('\033'); + } + + // after getting a key rather than before + if (main) + main->fadeHighlighting(false); + + return keybuffer.GetAscii(); +} + +#ifdef IDLECHECKPOINT +void +NetHackQtBind::free_qt_input_timer(void) +{ + if (qt_input_timer) { + if (qt_input_timer->isActive()) + qt_input_timer->stop(); + if (qt_input_timer) + delete qt_input_timer; + qt_input_timer = 0; + } +} + +static void +qt_timer_fire(void) +{ + if (iflags.idlecheckpoint) { + /* no input for 30 seconds, so let's take + * advantage and do a game checkpoint, + * then resume the wait. + */ +#if defined(INSURANCE) + save_currentstate(); +#endif /* INSURANCE */ + } + if (qt_input_timer->isActive()) + qt_input_timer->stop(); +} + +//void +//cancel_qt_input_timer(void) +//{ +// +//} +#endif /* IDLECHECKPOINT */ + +int NetHackQtBind::qt_nh_poskey(coordxy *x, coordxy *y, int *mod) +{ + if (main) + main->fadeHighlighting(true); + +#ifdef IDLECHECKPOINT + if (iflags.idlecheckpoint) { + if (!qt_input_timer) { + qt_input_timer = new QTimer(); + qt_input_timer->setSingleShot(true); + connect(qt_input_timer, &QTimer::timeout, &qt_timer_fire); + } + if (!qt_input_timer->isActive()) + qt_input_timer->start(IDLECHECKPOINT_WAIT_TIME * 1000); + } +#endif + // Process events until a key or map-click arrives. + // + while (keybuffer.Empty() && clickbuffer.Empty()) { + int exc = qApp->exec(); + // [see comment above in qt_nhgetch()] + if (exc == -1) + keybuffer.Put('\033'); + } + + // after getting a key or click rather than before + if (main) + main->fadeHighlighting(false); + + if (!keybuffer.Empty()) { +#ifdef IDLECHECKPOINT + if (qt_input_timer->isActive()) + qt_input_timer->stop(); +#endif + return keybuffer.GetAscii(); + } else { + *x=clickbuffer.NextX(); + *y=clickbuffer.NextY(); + *mod=clickbuffer.NextMod(); + clickbuffer.Get(); +#ifdef IDLECHECKPOINT + if (qt_input_timer->isActive()) + qt_input_timer->stop(); +#endif + return 0; + } +} + +void NetHackQtBind::qt_nhbell() +{ + if (!::flags.silent) + QApplication::beep(); +} + +int NetHackQtBind::qt_doprev_message() +{ + // Don't need it - uses scrollbar + // XXX but could make this a shortcut + return 0; +} + +// display "--More--" as a prompt and wait for a response from the user +// +// Used by qt_display_nhwindow(WIN_MESSAGE, TRUE) where second argument +// True requests blocking. We need it to support MSGTYPE=stop but the +// core also uses that in various other situations. +char NetHackQtBind::qt_more() +{ + char ch = '\033'; + + // without this gameover hack, quitting via menu or window close + // button ends up provoking a complaint from qt_nhgetch() [see the + // ^C comment in that routine] when the core triggers --More-- via + // done2() -> really_done() -> display_nhwindow(WIN_MESSAGE, TRUE) + // (get rid of this if the exec() loop issue gets properly fixed) + if (::program_state.gameover) + return ch; // bypass --More-- and just continue with program exit + + NetHackQtMessageWindow *mesgwin = main ? main->GetMessageWindow() : NULL; + + // kill any typeahead; for '!popup_dialog' this forces qt_nhgetch() + keybuffer.Drain(); + + if (mesgwin && !::iflags.wc_popup_dialog && WIN_MESSAGE != WIN_ERR) { + + mesgwin->AddToStr("--More--"); + bool retry = false; + int complain = 0; + do { + ch = NetHackQtBind::qt_nhgetch(); + if (::program_state.savefile_completed) { + retry = false; + break; + } + switch (ch) { + case '\0': // hypothetical + ch = '\033'; + FALLTHROUGH; + /*FALLTHRU*/ + case ' ': + case '\n': + case '\r': + case '\033': + retry = false; + break; + default: + if (++complain > 1) + NetHackQtBind::qt_nhbell(); + // typing anything caused the most recent message line + // (which happens to our prompt) from having highlighting + // be removed; put that back + if (mesgwin) + mesgwin->RehighlightPrompt(); + retry = true; + break; + } + } while (retry); + // unhighlight the line with the prompt; does not erase the window + NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); + + } else { + // use a popup dialog box; unlike yn_function(), we don't show + // the prompt+response in the message window + NetHackQtYnDialog dialog(main, "--More--", " \033\n\r", ' '); + ch = dialog.Exec(); + if (ch == '\0') { + ch = '\033'; + } + // discard any input that YnDialog() might have left pending + keybuffer.Drain(); + } + + return ch; +} + +char NetHackQtBind::qt_yn_function(const char *question_, + const char *choices, char def) +{ + QString question(QString::fromLatin1(question_)); + QString message; + char yn_esc_map='\033'; + int result = -1; + + if (choices) { + QString choicebuf; + for (const char *p = choices; *p; ++p) { + if (*p == '\033') // and anything beyond is hidden + break; + choicebuf += visctrl(*p); + } + choicebuf.truncate(QBUFSZ - 1); // no effect if already shorter + message = QString("%1 [%2] ").arg(question, choicebuf); + if (def) + message += QString("(%1) ").arg(QChar(def)); + // escape maps to 'q' or 'n' or default, in that order + yn_esc_map = strchr(choices, 'q') ? 'q' + : strchr(choices, 'n') ? 'n' + : def; + } else { + message = question; + } + + if ( + /* + * The 'Settings' dialog doesn't present prompting-in-message-window + * as a candidate for customization but core supports 'popup_dialog' + * option so let player use that instead. + */ +#if 0 + qt_settings->ynInMessages() +#else + !::iflags.wc_popup_dialog +#endif + && WIN_MESSAGE != WIN_ERR) { + // Similar to X11 windowport `slow' feature. + + char cbuf[20]; + cbuf[0] = '\0'; + + // add the prompt to the message window + NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); + + while (result < 0) { + cbuf[0] = '\0'; + char ch=NetHackQtBind::qt_nhgetch(); + if (ch=='\033') { + result=yn_esc_map; + Strcpy(cbuf, "ESC"); + } else if (choices && !strchr(choices,ch)) { + if (def && (ch==' ' || ch=='\r' || ch=='\n')) { + result=def; + Strcpy(cbuf, visctrl(def)); + } else { + NetHackQtBind::qt_nhbell(); + // typing anything caused the most recent message line + // (which happens to our prompt) from having highlighting + // be removed; put that back + NetHackQtMessageWindow + *mesgwin = main ? main->GetMessageWindow() : NULL; + if (mesgwin) + mesgwin->RehighlightPrompt(); + // and try again... + } + } else { + result=ch; + Strcpy(cbuf, visctrl(ch)); + } + } + + // update the prompt message line to include the response + if (cbuf[0]) { + if (!strcmp(cbuf, " ")) + Strcpy(cbuf, "SPC"); + + NetHackQtMessageWindow *mesgwin = main->GetMessageWindow(); + if (mesgwin) + mesgwin->AddToStr(cbuf); + } + + } else { + // use a popup dialog box + NetHackQtYnDialog dialog(main, question, choices, def); + char ret = dialog.Exec(); + if (ret == 0) { + ret = '\033'; + } + // discard any input that YnDialog() might have left pending + keybuffer.Drain(); + + // combine the prompt and result + char cbuf[40]; + Strcpy(cbuf, (ret == '\033') ? "ESC" + : (ret == ' ') ? "SPC" + : visctrl(ret)); + if (ret == '#' && choices && !strncmp(choices, "yn#", (size_t) 3)) + Sprintf(eos(cbuf), " %ld", ::yn_number); + message += QString(" %1").arg(cbuf); + + // add the prompt with appended response to the message window + if (WIN_MESSAGE != WIN_ERR) + NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); + + result = ret; + } + + // unhighlight the prompt; does not erase the multi-line message window + if (WIN_MESSAGE != WIN_ERR) + NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); + + return (char) result; +} + +void NetHackQtBind::qt_getlin(const char *prompt, char *line) +{ + NetHackQtStringRequestor requestor(mainWidget(),prompt); + if (!requestor.Get(line, BUFSZ, 40)) { + Strcpy(line, "\033"); + // discard any input that Get() might have left pending + keybuffer.Drain(); + } + + // add the prompt with appended response to the message window + char buf[BUFSZ + 20], *q; /* +20: plenty of extra room for visctrl() */ + copynchars(buf, prompt, BUFSZ - 1); + q = eos(buf); + *q++ = ' '; /* guaranteed to fit; temporary lack of terminator is ok */ + + if (line[0] == '\033') { + Strcpy(q, "ESC"); + } else if (line[0] == ' ' && !line[1]) { + Strcpy(q, "SPC"); + } else { + /* buf[] has more than enough room to hold one extra visctrl() + in case q is at the last viable slot and *p yields "M-^c" */ + for (char *p = line; *p && q < &buf[BUFSZ - 1]; ++p, q = eos(q)) + Strcpy(q, visctrl(*p)); + } + if (q > &buf[BUFSZ - 1]) + q = &buf[BUFSZ - 1]; + *q = '\0'; + + NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, buf); + // unhighlight the prompt; does not erase the multi-line message window + NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); +} + +// User has typed '#' to begin entering an extended command; core calls us. +int NetHackQtBind::qt_get_ext_cmd() +{ + NetHackQtExtCmdRequestor *xcmd; + int result; + do { + xcmd = new NetHackQtExtCmdRequestor(mainWidget()); + result = xcmd->get(); + delete xcmd; + } while (result == xcmdNoMatch); + // refresh message window after extended command dialog is dismissed + NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); + return result; +} + +void NetHackQtBind::qt_number_pad(int) +{ + // Ignore. +} + +void NetHackQtBind::qt_delay_output() +{ +#ifdef TIMED_DELAY + NetHackQtDelay delay(50); + delay.wait(); +#endif +} + +#ifdef CHANGE_COLOR +void NetHackQtBind::qt_change_color(int color, long rgb, int reverse UNUSED) +{ + int r, g, b; + + r = (rgb >> 16) & 0xFF; + g = (rgb >> 8) & 0xFF; + b = rgb & 0xFF; + if (!pen) { + (void) NetHackQtBind::nhcolor_to_pen(0); /* init pen[] */ + } + pen[color % 16] = QColor(r, g, b); +} + +char * +NetHackQtBind::qt_get_color_string(void) +{ + return (char *) 0; +} + +#endif + +void NetHackQtBind::qt_outrip(winid wid, int how, time_t when) +{ + NetHackQtWindow* window=id_to_window[(int)wid]; + window->UseRIP(how, when); +} + +void NetHackQtBind::qt_preference_update(const char *optname) +{ +#ifdef DYNAMIC_STATUSLINES // defined in qt_main.h + if (!strcmp(optname, "statuslines")) { + // delete and recreate status window + // to toggle statuslines from 2 to 3 or vice versa + id_to_window[WIN_STATUS] = main->redoStatus(); + } +#else + nhUse(optname); +#endif +} + +char *NetHackQtBind::qt_getmsghistory(boolean init) +{ + NetHackQtMessageWindow *window = main->GetMessageWindow(); + if (window) + return (char *) window->GetStr((bool) init); + return NULL; +} + +void NetHackQtBind::qt_putmsghistory(const char *msg, boolean is_restoring) +{ + NetHackQtMessageWindow *window = main->GetMessageWindow(); + if (!window) + return; + + if (is_restoring && !msgs_initd) { + /* we're restoring history from the previous session, but new + messages have already been issued this session */ + int i = 0; + const char *str; + + while ((str = window->GetStr((bool) (i == 0))) != 0) { + msgs_strings->append(str); + i++; + } + msgs_initd = true; + msgs_saved = (i > 0); + window->ClearMessages(); + } + + if (msg) { + //raw_printf("msg='%s'", msg); + window->PutStr(ATR_NONE, QString::fromLatin1(msg)); +#ifdef DUMPLOG_CORE + dumplogmsg(msg); +#endif + } else if (msgs_saved) { + /* restore strings */ + for (int i = 0; i < msgs_strings->size(); ++i) { + const QString &nxtmsg = msgs_strings->at(i); + window->PutStr(ATR_NONE, nxtmsg); +#ifdef DUMPLOG_CORE + dumplogmsg(nxtmsg.toLatin1().constData()); +#endif + } + delete msgs_strings; + msgs_initd = false; + } +} + +// event loop callback +bool NetHackQtBind::notify(QObject *receiver, QEvent *event) +{ + // Ignore Alt-key navigation to menubar, it's annoying when you + // use Alt-Direction to move around. + if (main && receiver == main && event->type() == QEvent::KeyRelease + && ((QKeyEvent *) event)->key() == Qt::Key_Alt) + return true; + + bool result = QApplication::notify(receiver, event); + int evtyp = event->type(); + + if (evtyp == QEvent::KeyPress) { + QKeyEvent *key_event = (QKeyEvent *) event; + + if (!key_event->isAccepted()) { + Qt::KeyboardModifiers mod = key_event->modifiers(); + const int k = key_event->key(); + for (int i = 0; key_macro[i].key; i++) { + if (key_macro[i].key == k + && ((key_macro[i].state & mod) == key_macro[i].state)) { + // matched macro; put its expansion into the input buffer + keybuffer.Put(!::iflags.num_pad ? key_macro[i].macro + : key_macro[i].numpad_macro); + key_event->accept(); + qApp->exit(); + return true; + } + } + QString key = key_event->text(); + QChar ch = !key.isEmpty() ? key.at(0) : QChar(0); + if (ch > QChar(128)) + ch = QChar(0); + // on OSX, ascii control codes are not sent, force them + if (ch == 0 && (mod & Qt::ControlModifier) != 0) { + if (k >= Qt::Key_A && k <= Qt::Key_Underscore) + ch = (QChar) (k - (Qt::Key_A - 1)); + } + //raw_printf("notify()=%d \"%s\"", k, visctrl(ch.cell())); + // if we have a valid character, queue it up + if (ch != 0) { + bool alt = ((mod & Qt::AltModifier) != 0 + || (k >= Qt::Key_0 && k <= Qt::Key_9 + && (mod & Qt::ControlModifier) != 0)); + keybuffer.Put(k, ch.cell() + (alt ? 128 : 0), (uint) mod); + key_event->accept(); + qApp->exit(); + result = true; + } + +#if 0 /* this was a failed attempt to prevent qt_more() from looping + * after command+q (on OSX) is used to bring up the quit dialog; + * now qt_more() uses an early return if program_state.gameover + * is set */ + } else if (evtyp == QEvent::FocusOut + || evtyp == QEvent::ShortcutOverride + || evtyp == QEvent::PlatformSurface) { + // leave qt_nhgetch()'s event loop if focus switches somewhere else + qApp->exit(); + result = false; +#endif + } + } + return result; +} + +NetHackQtBind* NetHackQtBind::instance=0; +NetHackQtKeyBuffer NetHackQtBind::keybuffer; +NetHackQtClickBuffer NetHackQtBind::clickbuffer; +NetHackQtMainWindow* NetHackQtBind::main=0; +QFrame* NetHackQtBind::splash=0; +QStringList *NetHackQtBind::msgs_strings; +boolean NetHackQtBind::msgs_saved = false; +boolean NetHackQtBind::msgs_initd = false; +#if 0 +static void Qt_positionbar(char *) {} +#endif + +#if defined(SND_LIB_QTSOUND) && !defined(QT_NO_SOUND) +void NetHackQtBind::qtsound_init_nhsound(void) +{ +} + +void NetHackQtBind::qtsound_exit_nhsound(const char *reason UNUSED) +{ +} + +void NetHackQtBind::qtsound_achievement(schar ach1 UNUSED, schar ach2 UNUSED, int32_t repeat UNUSED) +{ +} + +void NetHackQtBind::qtsound_soundeffect(char *desc UNUSED, int32_t seid UNUSED, int32_t volume UNUSED) +{ +} + +void NetHackQtBind::qtsound_hero_playnotes(int32_t instrument UNUSED, const char *str UNUSED, int32_t volume UNUSED) +{ +} +void NetHackQtBind::qtsound_ambience(int32_t ambienceid UNUSED, int32_t ambience_action UNUSED, int32_t proximity UNUSED) +{ +} +void NetHackQtBind::qtsound_verbal(char *text UNUSED, int32_t gender UNUSED, int32_t tone UNUSED, int32_t vol UNUSED, int32_t moreinfo UNUSED) +{ +} + +QSoundEffect *effect = NULL; + +void NetHackQtBind::qtsound_play_usersound(char *filename, int32_t volume, int32_t idx UNUSED) +{ + if (!effect) + effect = new QSoundEffect(nethack_qt_::NetHackQtBind::mainWidget()); + if (effect) { + effect->setLoopCount(1); + effect->setVolume((1.00f * volume) / 100.0f); + effect->setSource(QUrl::fromLocalFile(filename)); + effect->play(); + } +} +#endif + +} // namespace nethack_qt_ + +struct window_procs Qt_procs = { + WPID(Qt), + (WC_COLOR | WC_HILITE_PET + | WC_ASCII_MAP | WC_TILED_MAP + | WC_FONT_MAP | WC_TILE_FILE | WC_TILE_WIDTH | WC_TILE_HEIGHT + | WC_POPUP_DIALOG | WC_PLAYER_SELECTION | WC_SPLASH_SCREEN), + (WC2_HITPOINTBAR +#ifdef SELECTSAVED + | WC2_SELECTSAVED +#endif +#ifdef ENHANCED_SYMBOLS + | WC2_U_UTF8STR +#endif + | WC2_EXTRACOLORS + | WC2_STATUSLINES), + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ + nethack_qt_::NetHackQtBind::qt_init_nhwindows, + nethack_qt_::NetHackQtBind::qt_player_selection, + nethack_qt_::NetHackQtBind::qt_askname, + nethack_qt_::NetHackQtBind::qt_get_nh_event, + nethack_qt_::NetHackQtBind::qt_exit_nhwindows, + nethack_qt_::NetHackQtBind::qt_suspend_nhwindows, + nethack_qt_::NetHackQtBind::qt_resume_nhwindows, + nethack_qt_::NetHackQtBind::qt_create_nhwindow, + nethack_qt_::NetHackQtBind::qt_clear_nhwindow, + nethack_qt_::NetHackQtBind::qt_display_nhwindow, + nethack_qt_::NetHackQtBind::qt_destroy_nhwindow, + nethack_qt_::NetHackQtBind::qt_curs, + nethack_qt_::NetHackQtBind::qt_putstr, + genl_putmixed, + nethack_qt_::NetHackQtBind::qt_display_file, + nethack_qt_::NetHackQtBind::qt_start_menu, + nethack_qt_::NetHackQtBind::qt_add_menu, + nethack_qt_::NetHackQtBind::qt_end_menu, + nethack_qt_::NetHackQtBind::qt_select_menu, + genl_message_menu, /* no need for Qt-specific handling */ + nethack_qt_::NetHackQtBind::qt_mark_synch, + nethack_qt_::NetHackQtBind::qt_wait_synch, +#ifdef CLIPPING + nethack_qt_::NetHackQtBind::qt_cliparound, +#endif +#ifdef POSITIONBAR + nethack_qt_::Qt_positionbar, +#endif + nethack_qt_::NetHackQtBind::qt_print_glyph, + //NetHackQtBind::qt_print_glyph_compose, + nethack_qt_::NetHackQtBind::qt_raw_print, + nethack_qt_::NetHackQtBind::qt_raw_print_bold, + nethack_qt_::NetHackQtBind::qt_nhgetch, + nethack_qt_::NetHackQtBind::qt_nh_poskey, + nethack_qt_::NetHackQtBind::qt_nhbell, + nethack_qt_::NetHackQtBind::qt_doprev_message, + nethack_qt_::NetHackQtBind::qt_yn_function, + nethack_qt_::NetHackQtBind::qt_getlin, + nethack_qt_::NetHackQtBind::qt_get_ext_cmd, + nethack_qt_::NetHackQtBind::qt_number_pad, + nethack_qt_::NetHackQtBind::qt_delay_output, +#ifdef CHANGE_COLOR + nethack_qt_::NetHackQtBind::qt_change_color, +#ifdef MAC /* old OS 9, not OSX */ + donull, + donull, +#endif + nethack_qt_::NetHackQtBind::qt_get_color_string, +#endif +#ifdef GRAPHIC_TOMBSTONE + nethack_qt_::NetHackQtBind::qt_outrip, +#else + genl_outrip, +#endif + nethack_qt_::NetHackQtBind::qt_preference_update, + nethack_qt_::NetHackQtBind::qt_getmsghistory, + nethack_qt_::NetHackQtBind::qt_putmsghistory, + genl_status_init, + genl_status_finish, genl_status_enablefield, +#ifdef STATUS_HILITES + genl_status_update, +#else + genl_status_update, +#endif + genl_can_suspend_yes, + nethack_qt_::NetHackQtBind::qt_update_inventory, + nethack_qt_::NetHackQtBind::qt_ctrl_nhwindow, +}; + +#if defined(SND_LIB_QTSOUND) && !defined(QT_NO_SOUND) +struct sound_procs qtsound_procs = { + SOUNDID(qtsound), + SOUND_TRIGGER_USERSOUNDS, + nethack_qt_::NetHackQtBind::qtsound_init_nhsound, + nethack_qt_::NetHackQtBind::qtsound_exit_nhsound, + nethack_qt_::NetHackQtBind::qtsound_achievement, + nethack_qt_::NetHackQtBind::qtsound_soundeffect, + nethack_qt_::NetHackQtBind::qtsound_hero_playnotes, + nethack_qt_::NetHackQtBind::qtsound_play_usersound, + nethack_qt_::NetHackQtBind::qtsound_ambience, + nethack_qt_::NetHackQtBind::qtsound_verbal, +}; +#endif /* SND_LIB_QTSOUND and !QT_NO_SOUND */ + +//qt_bind.cpp diff --git a/win/Qt/qt_bind.h b/win/Qt/qt_bind.h new file mode 100644 index 000000000..17dad758c --- /dev/null +++ b/win/Qt/qt_bind.h @@ -0,0 +1,123 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_bind.h -- bindings between the Qt 4 interface and the main code + +#ifndef QT4BIND_H +#define QT4BIND_H + +#include "qt_main.h" + +namespace nethack_qt_ { + +class NetHackQtClickBuffer; + +#ifdef KDE +#define NetHackQtBindBase KApplication +#elif defined(QWS) +#define NetHackQtBindBase QPEApplication +#else +#define NetHackQtBindBase QApplication +#endif + +class NetHackQtBind : NetHackQtBindBase { +private: + // Single-instance preservation... + NetHackQtBind(int& argc, char** argv); + + static NetHackQtBind* instance; + + static NetHackQtKeyBuffer keybuffer; + static NetHackQtClickBuffer clickbuffer; + + static QFrame* splash; + static NetHackQtMainWindow* main; + +public: + static void qt_Splash(); + + /* window interface */ + + static void qt_init_nhwindows(int* argc, char** argv); + static void qt_player_selection(); + static void qt_askname(); + static void qt_get_nh_event(); + static void qt_exit_nhwindows(const char *); + static void qt_suspend_nhwindows(const char *); + static void qt_resume_nhwindows(); + static winid qt_create_nhwindow(int type); + static void qt_clear_nhwindow(winid wid); + static void qt_display_nhwindow(winid wid, boolean block); + static void qt_destroy_nhwindow(winid wid); + static void qt_curs(winid wid, int x, int y); + static void qt_putstr(winid wid, int attr, const char *text); + static void qt_putstr(winid wid, int attr, const std::string& text); + static void qt_putstr(winid wid, int attr, const QString& text); + static void qt_display_file(const char *filename, boolean must_exist); + static void qt_start_menu(winid wid, unsigned long mbehavior); + static void qt_add_menu(winid wid, const glyph_info *glyphinfo, + const ANY_P * identifier, char ch, char gch, int attr, int clr, + const char *str, unsigned int itemflags); + static void qt_end_menu(winid wid, const char *prompt); + static int qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list); + static void qt_mark_synch(); + static void qt_wait_synch(); + + static void qt_cliparound(int x, int y); + static void qt_cliparound_window(winid wid, int x, int y); + static void qt_print_glyph(winid wid, coordxy x, coordxy y, + const glyph_info *glyphingo, + const glyph_info *bkglyphinfo); + static void qt_raw_print(const char *str); + static void qt_raw_print_bold(const char *str); + static const QPen nhcolor_to_pen(uint32_t c); + static void qt_change_color(int color, long rgb, int reverse UNUSED); + static char *qt_get_color_string(void); + static int qt_nhgetch(); + static int qt_nh_poskey(coordxy *x, coordxy *y, int *mod); + static void qt_nhbell(); + static int qt_doprev_message(); + static char qt_more(); + static char qt_yn_function(const char *question, + const char *choices, char def); + static void qt_getlin(const char *prompt, char *line); + static int qt_get_ext_cmd(); + static void qt_number_pad(int); + static void qt_delay_output(); + + static void qt_preference_update(const char *optname); + static char *qt_getmsghistory(boolean init); + static void qt_putmsghistory(const char *msg, boolean is_restoring); + + static void qt_outrip(winid wid, int how, time_t when); + static int qt_kbhit(); + static void qt_update_inventory(int); + static win_request_info *qt_ctrl_nhwindow(winid, int, win_request_info *); + static QWidget *mainWidget() { return main; } +#if defined(SND_LIB_QTSOUND) && !defined(QT_NO_SOUND) + /* sound interface */ + static void qtsound_init_nhsound(void); + static void qtsound_exit_nhsound(const char *); + static void qtsound_achievement(schar, schar, int32_t); + static void qtsound_soundeffect(char *, int32_t, int32_t); + static void qtsound_hero_playnotes(int32_t instrument, const char *str, int32_t volume); + static void qtsound_play_usersound(char *, int32_t, int32_t); + static void qtsound_ambience(int32_t, int32_t, int32_t); + static void qtsound_verbal(char *text, int32_t gender, int32_t tone, int32_t vol, int32_t moreinfo); +#endif +#ifdef IDLECHECKPOINT + static void free_qt_input_timer(void); +#endif + +private: + virtual bool notify(QObject *receiver, QEvent *event); + + static QStringList *msgs_strings; + static boolean msgs_saved; + static boolean msgs_initd; +}; + +} // namespace nethack_qt_ + +#endif diff --git a/win/Qt4/qt4click.cpp b/win/Qt/qt_click.cpp similarity index 77% rename from win/Qt4/qt4click.cpp rename to win/Qt/qt_click.cpp index 78177a14f..d8f5030b7 100644 --- a/win/Qt4/qt4click.cpp +++ b/win/Qt/qt_click.cpp @@ -2,23 +2,18 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4click.cpp -- a mouse click buffer +// qt_click.cpp -- a mouse click buffer +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include -#include "qt4click.h" +#include "qt_post.h" +#include "qt_click.h" -namespace nethack_qt4 { +namespace nethack_qt_ { NetHackQtClickBuffer::NetHackQtClickBuffer() : in(0), out(0) @@ -45,4 +40,4 @@ void NetHackQtClickBuffer::Get() out=(out+1)%maxclick; } -} // namespace nethack_qt4 +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4click.h b/win/Qt/qt_click.h similarity index 85% rename from win/Qt4/qt4click.h rename to win/Qt/qt_click.h index 50fd8b1cc..325f455fd 100644 --- a/win/Qt4/qt4click.h +++ b/win/Qt/qt_click.h @@ -2,12 +2,12 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4click.h -- a mouse click buffer +// qt_click.h -- a mouse click buffer #ifndef QT4CLICK_H #define QT4CLICK_H -namespace nethack_qt4 { +namespace nethack_qt_ { class NetHackQtClickBuffer { public: @@ -32,6 +32,6 @@ class NetHackQtClickBuffer { int in,out; }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_clust.cpp b/win/Qt/qt_clust.cpp index c5063a6a3..d63d2d7de 100644 --- a/win/Qt/qt_clust.cpp +++ b/win/Qt/qt_clust.cpp @@ -1,168 +1,169 @@ -/* NetHack 3.6 qt_clust.cpp $NHDT-Date: 1524684507 2018/04/25 19:28:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.8 $ */ +/* SCCS Id: @(#)qt_clust.cpp 3.4 1999/11/19 */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #include "qt_clust.h" -static -void include(QRect& r, const QRect& rect) +static void include(QRect& r, const QRect& rect) { - if (rect.left()r.right()) { - r.setRight(rect.right()); - } - if (rect.top()r.bottom()) { - r.setBottom(rect.bottom()); - } + if (rect.left() < r.left()) { + r.setLeft(rect.left()); + } + if (rect.right() > r.right()) { + r.setRight(rect.right()); + } + if (rect.top() < r.top()) { + r.setTop(rect.top()); + } + if (rect.bottom() > r.bottom()) { + r.setBottom(rect.bottom()); + } } /* -A Clusterizer groups rectangles (QRects) into non-overlapping rectangles -by a merging heuristic. -*/ + * A Clusterizer groups rectangles (QRects) into non-overlapping + * rectangles by a merging heuristic. + */ Clusterizer::Clusterizer(int maxclusters) : - cluster(new QRect[maxclusters]), - count(0), - max(maxclusters) -{ } + cluster(new QRect[maxclusters]), + count(0), + max(maxclusters) +{ +} Clusterizer::~Clusterizer() { - delete [] cluster; + delete [] cluster; } void Clusterizer::clear() { - count=0; + count = 0; } void Clusterizer::add(int x, int y) { - add(QRect(x,y,1,1)); + add(QRect(x, y, 1, 1)); } void Clusterizer::add(int x, int y, int w, int h) { - add(QRect(x,y,w,h)); + add(QRect(x, y, w, h)); } void Clusterizer::add(const QRect& rect) { - QRect biggerrect(rect.x()-1,rect.y()-1,rect.width()+2,rect.height()+2); - - //assert(rect.width()>0 && rect.height()>0); - - int cursor; - - for (cursor=0; cursor=0) { - include(cluster[cheapest],rect); - return; - } - - if (count < max) { - cluster[count++]=rect; - return; - } - - // Do cheapest of: - // add to closest cluster - // do cheapest cluster merge, add to new cluster - - lowestcost=9999999; - cheapest=-1; - for (cursor=0; cursor=0) { - include(cluster[cheapestmerge1],cluster[cheapestmerge2]); - cluster[cheapestmerge2]=cluster[count--]; - } else { - // if (!cheapest) debugRectangles(rect); - include(cluster[cheapest],rect); - } - - // NB: clusters do not intersect (or intersection will - // overwrite). This is a result of the above algorithm, - // given the assumption that (x,y) are ordered topleft - // to bottomright. + QRect biggerrect(rect.x() - 1, rect.y() - 1, + rect.width() + 2, rect.height() + 2); + + //assert(rect.width() > 0 && rect.height() > 0); + + int cursor; + + for (cursor=0; cursor < count; cursor++) { + if (cluster[cursor].contains(rect)) { + // Wholly contained already. + return; + } + } + + int lowestcost = 9999999; + int cheapest = -1; + for (cursor = 0; cursor < count; cursor++) { + if (cluster[cursor].intersects(biggerrect)) { + QRect larger=cluster[cursor]; + include(larger,rect); + int cost = larger.width() * larger.height() + - cluster[cursor].width() * cluster[cursor].height(); + + if (cost < lowestcost) { + bool bad = false; + for (int c = 0; c < count && !bad; c++) { + bad = cluster[c].intersects(larger) && c != cursor; + } + if (!bad) { + cheapest = cursor; + lowestcost = cost; + } + } + } + } + if (cheapest >= 0) { + include(cluster[cheapest], rect); + return; + } + + if (count < max) { + cluster[count++] = rect; + return; + } + + // Do cheapest of: + // add to closest cluster + // do cheapest cluster merge, add to new cluster + + lowestcost = 9999999; + cheapest = -1; + for (cursor = 0; cursor < count; cursor++) { + QRect larger = cluster[cursor]; + include(larger, rect); + int cost = larger.width() * larger.height() + - cluster[cursor].width() * cluster[cursor].height(); + if (cost < lowestcost) { + bool bad = false; + for (int c = 0; c < count && !bad; c++) { + bad = cluster[c].intersects(larger) && c != cursor; + } + if (!bad) { + cheapest = cursor; + lowestcost = cost; + } + } + } + + // XXX could make an heuristic guess as to whether we + // XXX need to bother looking for a cheap merge. + + int cheapestmerge1 = -1; + int cheapestmerge2 = -1; + + for (int merge1 = 0; merge1 < count; merge1++) { + for (int merge2 = 0; merge2 < count; merge2++) { + if (merge1 != merge2) { + QRect larger = cluster[merge1]; + include(larger, cluster[merge2]); + int cost = larger.width() * larger.height() + - cluster[merge1].width() * cluster[merge1].height() + - cluster[merge2].width() * cluster[merge2].height(); + if (cost < lowestcost) { + bool bad = false; + for (int c = 0; c < count && !bad; c++) { + bad = cluster[c].intersects(larger) && c != cursor; + } + if (!bad) { + cheapestmerge1 = merge1; + cheapestmerge2 = merge2; + lowestcost = cost; + } + } + } + } + } + + if (cheapestmerge1 >= 0) { + include(cluster[cheapestmerge1], cluster[cheapestmerge2]); + cluster[cheapestmerge2] = cluster[count--]; + } else { + // if (!cheapest) debugRectangles(rect); + include(cluster[cheapest],rect); + } + + // NB: clusters do not intersect (or intersection will + // overwrite). This is a result of the above algorithm, + // given the assumption that (x,y) are ordered topleft + // to bottomright. } const QRect& Clusterizer::operator[](int i) { - return cluster[i]; + return cluster[i]; } diff --git a/win/Qt4/qt4clust.h b/win/Qt/qt_clust.h similarity index 100% rename from win/Qt4/qt4clust.h rename to win/Qt/qt_clust.h diff --git a/win/Qt4/qt4delay.cpp b/win/Qt/qt_delay.cpp similarity index 63% rename from win/Qt4/qt4delay.cpp rename to win/Qt/qt_delay.cpp index eadf42a94..0fa3003ce 100644 --- a/win/Qt4/qt4delay.cpp +++ b/win/Qt/qt_delay.cpp @@ -2,23 +2,18 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4delay.cpp -- implement a delay +// qt_delay.cpp -- implement a delay +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include -#include "qt4delay.h" +#include "qt_post.h" +#include "qt_delay.h" -namespace nethack_qt4 { +namespace nethack_qt_ { // RLC Can we use QTimer::single_shot for this? NetHackQtDelay::NetHackQtDelay(int ms) : @@ -32,11 +27,11 @@ void NetHackQtDelay::wait() m_loop.exec(); } -void NetHackQtDelay::timerEvent(QTimerEvent* timer) +void NetHackQtDelay::timerEvent(QTimerEvent* timer UNUSED) { m_loop.exit(); killTimer(m_timer); m_timer = 0; } -} // namespace nethack_qt4 +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4delay.h b/win/Qt/qt_delay.h similarity index 82% rename from win/Qt4/qt4delay.h rename to win/Qt/qt_delay.h index 2e0085edf..8c918856f 100644 --- a/win/Qt4/qt4delay.h +++ b/win/Qt/qt_delay.h @@ -2,12 +2,12 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4delay.h -- implement a delay +// qt_delay.h -- implement a delay #ifndef QT4DELAY_H #define QT4DELAY_H -namespace nethack_qt4 { +namespace nethack_qt_ { class NetHackQtDelay : QObject { private: @@ -21,6 +21,6 @@ class NetHackQtDelay : QObject { virtual void timerEvent(QTimerEvent* timer); }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_glyph.cpp b/win/Qt/qt_glyph.cpp new file mode 100644 index 000000000..9aa739fce --- /dev/null +++ b/win/Qt/qt_glyph.cpp @@ -0,0 +1,278 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_glyph.cpp -- class to manage the glyphs in a tile set + +extern "C" { +#include "hack.h" +#include "tile2x11.h" /* x11tiles is potential fallback for nhtiles.bmp */ +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_glyph.h" +#include "qt_bind.h" +#include "qt_set.h" +#include "qt_inv.h" +#include "qt_map.h" +#include "qt_str.h" + +extern short glyph2tile[]; // from tile.c + +namespace nethack_qt_ { + +static int tilefile_tile_W=16; +static int tilefile_tile_H=16; + +// Debian uses a separate PIXMAPDIR +#ifndef PIXMAPDIR +# ifdef HACKDIR +# define PIXMAPDIR HACKDIR +# else +# define PIXMAPDIR "." +# endif +#endif + +NetHackQtGlyphs::NetHackQtGlyphs() +{ + boolean tilesok = TRUE, user_tiles = (::iflags.wc_tile_file != NULL); + char cbuf[BUFSZ]; + const char *tile_file = NULL, *tile_list[2]; + + this->no_tiles = false; + tiles_per_row = TILES_PER_ROW; + + if (user_tiles) { + tile_list[0] = ::iflags.wc_tile_file; + Snprintf(cbuf, sizeof cbuf, "%s/%s", PIXMAPDIR, tile_list[0]); + tile_list[1] = cbuf; + } else { + tile_list[0] = PIXMAPDIR "/nhtiles.bmp"; + tile_list[1] = PIXMAPDIR "/x11tiles"; + } + + if (img.load(tile_list[0])) + tile_file = tile_list[0]; + else if (img.load(tile_list[1])) + tile_file = tile_list[1]; + + if (!tile_file) { + tilesok = FALSE; + QString msg = nh_qsprintf("Cannot load '%s'.", + user_tiles ? tile_list[0] + // mismatched quotes match format + : "nhtiles.bmp' or 'x11tiles"); + QMessageBox::warning(0, "IO Error", msg); + } else { + if (img.width() % tiles_per_row) { + tilesok = FALSE; + impossible( + "Tile file \"%s\" has %d columns, not multiple of row count (%d)", + tile_file, img.width(), tiles_per_row); + } + } + + if (!tilesok) { + this->no_tiles = true; + /* tiles wouldn't load so force ascii map */ + ::iflags.wc_ascii_map = 1; + ::iflags.wc_tiled_map = 0; + /* tiles wouldn't load so don't allow toggling to tiled map */ + ::set_wc_option_mod_status(WC_ASCII_MAP | WC_TILED_MAP, + ::set_in_config); + tiles_per_row = 40; // arbitrary to avoid potential divide-by-0 + } + + if (iflags.wc_tile_width) + tilefile_tile_W = iflags.wc_tile_width; + else if (iflags.wc_ascii_map) + tilefile_tile_W = 16; + else + tilefile_tile_W = img.width() / tiles_per_row; + + if (iflags.wc_tile_height) + tilefile_tile_H = iflags.wc_tile_height; + else + tilefile_tile_H = tilefile_tile_W; + + setSize(tilefile_tile_W, tilefile_tile_H); +} + +// display a map tile somewhere other than the map; +// used for paper doll and also role/race selection +void +NetHackQtGlyphs::drawGlyph( + QPainter& painter, + int glyph, int tileidx, + int x, int y, + bool reversed) +{ + if (!reversed) { +#if 0 + int tile = glyph2tile[glyph]; +#else + int tile = tileidx; +#endif + int px = (tile % tiles_per_row) * width(); + int py = tile / tiles_per_row * height(); + + painter.drawPixmap(x, y, pm, px, py, width(), height()); + } else { + // for paper doll; mirrored image for left side of two-handed weapon + painter.drawPixmap(x, y, reversed_pixmap(glyph, tileidx), + 0, 0, width(), height()); + } +} + +// draw a tile into the paper doll +void +NetHackQtGlyphs::drawCell( + QPainter& painter, + int glyph, int tileidx, + int cellx, int celly) +{ + drawGlyph(painter, glyph, tileidx, cellx * width(), celly * height(), + false); +} + +// draw a tile into the paper doll and then draw a BUC border around it +void +NetHackQtGlyphs::drawBorderedCell( + QPainter& painter, + int glyph, int tileidx, + int cellx, int celly, + int border, bool reversed) +{ + int wd = width(), + ht = height(), + yoffset = 1, // tiny extra margin at top + lox = cellx * (wd + 2), + loy = celly * (ht + 2) + yoffset; + + drawGlyph(painter, glyph, tileidx, lox + 1, loy + 1, reversed); + + if (border != NO_BORDER) { + // gray would be a better mid-point between red and cyan but it + // doesn't show up well enough against the wall tile background + painter.setPen((border == BORDER_CURSED) ? Qt::red + : (border == BORDER_UNCURSED) ? Qt::yellow + : (border == BORDER_BLESSED) ? Qt::cyan + : Qt::white); // BORDER_DEFAULT + // assuming 32x32, draw 34x34 rectangle from 0..33x0..33, outside glyph +#if 0 /* Qt 5.11 drawRect(x,y,width,height) seems to have an off by 1 bug; + * drawRect(0,0,34,34) is drawing at 0..34x0..34 which is 35x35; + * should subtract 1 when adding width and/or height to base coord; + * the relevant code in QtCore/QRect.h is correct so this observable + * misbehavior is a mystery... */ + painter.drawRect(lox, loy, wd + 2, ht + 2); +#else + painter.drawLine(lox, loy, lox + wd + 1, loy); // 0,0->33,0 + painter.drawLine(lox, loy + ht + 1, lox + wd + 1, loy + ht + 1); + painter.drawLine(lox, loy, lox, loy + ht + 1); // 0,0->0,33 + painter.drawLine(lox + wd + 1, loy, lox + wd + 1, loy + ht + 1); +#endif + if (border != BORDER_DEFAULT) { + // assuming 32x32, draw rectangle from 1..32x1..32, inside glyph +#if 0 /* (see above) */ + painter.drawRect(lox + 1, loy + 1, wd, ht); +#else + painter.drawLine(lox + 1, loy + 1, lox + wd, loy + 1); // 1,1->32,1 + painter.drawLine(lox + 1, loy + ht, lox + wd, loy + ht); + painter.drawLine(lox + 1, loy + 1, lox + 1, loy + ht); // 1,1->1,32 + painter.drawLine(lox + wd, loy + 1, lox + wd, loy + ht); +#endif + for (int i = lox + 2; i < lox + wd - 1; i += 2) { + // assuming 32x32, draw points along <2..31,2> and <2..31,31> + painter.drawPoint(i, loy + 2); + painter.drawPoint(i + 1, loy + ht - 1); + } + for (int j = loy + 2; j < loy + ht - 1; j += 2) { + // assuming 32x32, draw points along <2,2..31> and <31,2..31> + painter.drawPoint(lox + 2, j); + painter.drawPoint(lox + wd - 1, j + 1); + } + } + } +} + +// mis-named routine to get the pixmap for a particular glyph +QPixmap +NetHackQtGlyphs::glyph( + int glyphindx UNUSED, + int tileidx) +{ +#if 0 + int tile = glyph2tile[glyphindx]; +#else + int tile = tileidx; +#endif + int px = (tile % tiles_per_row) * tilefile_tile_W; + int py = tile / tiles_per_row * tilefile_tile_H; + + return QPixmap::fromImage(img.copy(px, py, + tilefile_tile_W, tilefile_tile_H)); +} + +// transpose a glyph's tile horizontally, scaled for use in paper doll +QPixmap +NetHackQtGlyphs::reversed_pixmap( + int glyphindx, int tileidx) +{ + QPixmap pxmp = glyph(glyphindx, tileidx); +#ifdef ENHANCED_PAPERDOLL + qreal wid = (qreal) pxmp.width(), + //hgt = (qreal) pxmp.height(), + xscale = (qreal) qt_settings->dollWidth / (qreal) tilefile_tile_W, + yscale = (qreal) qt_settings->dollHeight / (qreal) tilefile_tile_H; + QTransform *mirrormatrix = new QTransform( + // negate x coordinates to flip the image across the y-axis + -1.0 * xscale, 0.0, 0.0, yscale, + // slide flipped image to the right to make things positive again + wid * xscale, 0.0 + ); + return pxmp.transformed(*mirrormatrix); +#else + return pxmp; +#endif +} + +void NetHackQtGlyphs::setSize(int w, int h) +{ + if (size == QSize(w, h)) + return; + size = QSize(w, h); + if (!w || !h) + return; // Still not decided + + if (size == pm1.size()) { // not zoomed + pm = pm1; + return; + } + if (size == pm2.size()) { // zoomed + pm = pm2; + return; + } + + bool was1 = (size == pm1.size()); + if (w == tilefile_tile_W && h == tilefile_tile_H) { + pm.convertFromImage(img); + } else { + QApplication::setOverrideCursor(Qt::WaitCursor); + QImage scaled = img.scaled( + w * img.width() / tilefile_tile_W, + h * img.height() / tilefile_tile_H, + Qt::IgnoreAspectRatio, + Qt::FastTransformation + ); + pm.convertFromImage(scaled, Qt::ThresholdDither | Qt::PreferDither); + QApplication::restoreOverrideCursor(); + } + (was1 ? pm2 : pm1) = pm; +} + +} // namespace nethack_qt_ diff --git a/win/Qt/qt_glyph.h b/win/Qt/qt_glyph.h new file mode 100644 index 000000000..8f5e9c65a --- /dev/null +++ b/win/Qt/qt_glyph.h @@ -0,0 +1,49 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_glyph.h -- class to manage the glyphs in a tile set + +#ifndef QT4GLYPH_H +#define QT4GLYPH_H + +namespace nethack_qt_ { + +enum border_code { + NO_BORDER, BORDER_DEFAULT, + BORDER_CURSED, BORDER_UNCURSED, BORDER_BLESSED +}; + +class NetHackQtGlyphs { +public: + bool no_tiles; + + NetHackQtGlyphs(); + + int width() const { return size.width(); } + int height() const { return size.height(); } + void toggleSize(); + void setSize(int w, int h); + + void drawGlyph(QPainter &, int glyph, int tileidx, + int pixelx, int pixely, + bool reversed = false); + void drawCell(QPainter &, int glyph, int tileidx, + int cellx, int celly); + void drawBorderedCell(QPainter &, int glyph, int tileidx, + int cellx, int celly, int bordercode, + bool reversed); + QPixmap glyph(int glyphindx, int tileidx); + QPixmap reversed_pixmap(int glyphindx, int tileidx); + +private: + QImage img; + QPixmap pm,pm1, pm2; + QSize size; + int tiles_per_row; + //QTransform *mirrormatrix; +}; + +} // namespace nethack_qt_ + +#endif diff --git a/win/Qt/qt_icon.cpp b/win/Qt/qt_icon.cpp new file mode 100644 index 000000000..488584f0c --- /dev/null +++ b/win/Qt/qt_icon.cpp @@ -0,0 +1,256 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_icon.cpp -- a labelled icon for display in the status window +// +// TODO? +// When the label specifies two values separated by a slash (curHP/maxHP, +// curEn/maxEn, XpLevel/ExpPoints when 'showexp' is On), highlighting +// for changes is all or nothing based on which field caller passes +// as the value to use for comparison. curHP and curEn go up and down +// without any change to the corresponding maximum all the time. Much +// rarer, but when maxHP and maxEn go up with level gain, the hero +// could be injured by a passive counterattack or collateral damage +// from an area effect--or much simpler, the casting cost of a spell +// that killed a monster and produced the level gain--so the current +// value could stay the same or even go down at same time max goes up. +// Likewise, Exp goes up a lot but Xp relatively rarely. (On the very +// rare occasions where either goes down, they'll both do so.) +// Highlighting two slash-separated values independently would be +// worthwhile but with the 'single label using a style sheet for color' +// approach it isn't going to happen. +// FIXME: +// Every LabelledIcon duplicates hl_better, hl_worse, hl_changd. +// + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_icon.h" +#include "qt_str.h" + +namespace nethack_qt_ { + +NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget *parent, const char *l) : + QWidget(parent), + label(new QLabel(l,this)), + icon(NULL), + comp_mode(BiggerIsBetter), + prev_value(NoNum), + turn_count(-1L) +{ + initHighlight(); +} + +NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget *parent, const char *l, + const QPixmap &i) : + QWidget(parent), + label(new QLabel(l,this)), + icon(new QLabel(this)), + comp_mode(BiggerIsBetter), + prev_value(NoNum), + turn_count(-1L) +{ + setIcon(i); + initHighlight(); +} + +// set up the style sheet strings used to specify color for status field +// labels [done "once", but once for each LabelledIcon that's constructed, +// so about 30 copies overall with 3.6's status conditions] +void NetHackQtLabelledIcon::initHighlight() +{ + // note: string "green" is much darker than enum Qt::green + // QColor("green") => #00ff00 + // QColor(Qt::green) => #008000 + // QColor("green").lighter(150) => #00c000 /* hitpoint bar's green */ + hl_better = "QLabel { background-color : #00c000 ; color : white }"; + hl_worse = "QLabel { background-color : red ; color : white }"; + hl_changd = "QLabel { background-color : blue ; color : white }"; +} + +void NetHackQtLabelledIcon::setLabel(const QString &t, bool lower) +{ + if (!label) { + label=new QLabel(this); + label->setFont(font()); + } + if (label->text() != t) { + label->setText(t); + ForceResize(); + if (comp_mode != NoCompare) { + highlight((comp_mode == NeitherIsBetter) ? hl_changd + : (comp_mode == (lower ? SmallerIsBetter + : BiggerIsBetter)) ? hl_better + : hl_worse); + } else if (turn_count) { + // if we don't want to highlight this status field but it is + // currently highlighted (perhaps optional Score recently went + // up and has just been toggled off), remove the highlight + unhighlight(); + } + } +} + +void NetHackQtLabelledIcon::setLabel(const QString& t, long v, long cv, + const QString& tail) +{ + QString buf; + if (v==NoNum) { + buf = ""; + } else { + buf = nh_qsprintf("%ld", v); + } + setLabel(t + buf + tail, cv < prev_value); + prev_value=cv; +} + +void NetHackQtLabelledIcon::setLabel(const QString& t, long v, + const QString& tail) +{ + setLabel(t,v,v,tail); +} + +void NetHackQtLabelledIcon::setIcon( + const QPixmap& i, + const QString& tooltip) +{ + if (!icon) + icon = new QLabel(this); + icon->setPixmap(i); + if (!tooltip.isNull() && !tooltip.isEmpty()) + icon->setToolTip(" " + tooltip + " "); + ForceResize(); + icon->resize(i.width(), i.height()); +} + +void NetHackQtLabelledIcon::setFont(const QFont& f) +{ + QWidget::setFont(f); + if (label) label->setFont(f); +} + +// used to highlight status conditions going from Off (blank) to On as "Worse" +void NetHackQtLabelledIcon::show() +{ + // Hunger and Encumbrance are worse when going from not shown + // to anything and they're set to SmallerIsBetter, so both + // BiggerIsBetter and SmallerIsBetter warrant hl_worse here. + // Fly, Lev, and Ride are set NeitherIsBetter so that when + // they appear they won't be classified as worse. + if (isHidden() && comp_mode != NoCompare) + highlight((comp_mode != NeitherIsBetter) ? hl_worse : hl_changd); + QWidget::show(); +} + +QSize NetHackQtLabelledIcon::sizeHint() const +{ + QSize iconsize, textsize; + + if (label && !icon) return label->sizeHint(); + if (icon && !label) return icon->sizeHint(); + if (!label && !icon) return QWidget::sizeHint(); + + iconsize = icon->sizeHint(); + textsize = label->sizeHint(); + return QSize( + std::max(iconsize.width(), textsize.width()), + iconsize.height() + textsize.height()); +} + +QSize NetHackQtLabelledIcon::minimumSizeHint() const +{ + QSize iconsize, textsize; + + if (label && !icon) return label->minimumSizeHint(); + if (icon && !label) return icon->minimumSizeHint(); + if (!label && !icon) return QWidget::minimumSizeHint(); + + iconsize = icon->minimumSizeHint(); + textsize = label->minimumSizeHint(); + return QSize( + std::max(iconsize.width(), textsize.width()), + iconsize.height() + textsize.height()); +} + +void NetHackQtLabelledIcon::highlightWhenChanging() +{ + turn_count = 0; // turn_count starts negative (as flag to not highlight) +} + +// set comp_mode to one of NoCompare or {Bigger,Smaller,Neither}IsBetter +void NetHackQtLabelledIcon::setCompareMode(int newmode) +{ + comp_mode = newmode; +} + +void NetHackQtLabelledIcon::unhighlight() +{ + if (label) { // Surely it is?! + label->setStyleSheet(""); + } + if (turn_count > 0) + turn_count = 0; +} + +void NetHackQtLabelledIcon::highlight(const QString& hl) +{ + if (label) { // Surely it is?! + if (turn_count >= 0) { + label->setStyleSheet(hl); + turn_count = 4; + // 4 includes this turn, so dissipates after 3 more keypresses. + } else { + unhighlight(); + } + } +} + +void NetHackQtLabelledIcon::dissipateHighlight() +{ + if (turn_count > 0) { + if (!--turn_count) + unhighlight(); + } +} + +// used when label (most status fields) or pixmap (alignment, hunger, +// encumbrance) changes value +void NetHackQtLabelledIcon::ForceResize() +{ + this->resizeEvent((QResizeEvent *) NULL); +} + +void NetHackQtLabelledIcon::resizeEvent(QResizeEvent*) +{ + setAlignments(); + + //int labw=label ? label->fontMetrics().width(label->text()) : 0; + int labh=label ? label->fontMetrics().height() : 0; + int icoh=icon ? icon->height() : 0; + int h=icoh+labh; + int icoy=(h>height() ? height()-labh-icoh : height()/2-h/2); + int laby=icoy+icoh; + if (icon) { + icon->setGeometry(0,icoy,width(),icoh); + } + if (label) { + label->setGeometry(0,laby,width(),labh); + } +} + +void NetHackQtLabelledIcon::setAlignments() +{ + if (label) label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter); + if (icon) icon->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter); +} + +} // namespace nethack_qt_ diff --git a/win/Qt/qt_icon.h b/win/Qt/qt_icon.h new file mode 100644 index 000000000..dddcda7ff --- /dev/null +++ b/win/Qt/qt_icon.h @@ -0,0 +1,64 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_icon.cpp -- a labelled icon + +#ifndef QT4ICON_H +#define QT4ICON_H + +namespace nethack_qt_ { + +enum CompareMode { + NoCompare = -1, BiggerIsBetter = 0, + SmallerIsBetter = 1, NeitherIsBetter = 2 +}; + +class NetHackQtLabelledIcon : public QWidget { +public: + NetHackQtLabelledIcon(QWidget *parent, const char *label); + NetHackQtLabelledIcon(QWidget *parent, const char *label, + const QPixmap &icon); + + enum { NoNum = -99999L }; + void setLabel(const QString &, bool lower=true); // string + void setLabel(const QString &, long, const QString &tail=""); // number + void setLabel(const QString &, long show_value, + long comparative_value, const QString &tail=""); + void setIcon(const QPixmap &, const QString &tooltip=NULL); + virtual void setFont(const QFont &); + //QString labelText() { return QString(this->label->text()); } + + void highlightWhenChanging(); + void setCompareMode(int newmode); + void dissipateHighlight(); + void ForceResize(); + + virtual void show(); + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + + QLabel *label; + QLabel *icon; + +protected: + void resizeEvent(QResizeEvent*); + +private: + void initHighlight(); + void setAlignments(); + void highlight(const QString& highlight); + void unhighlight(); + + int comp_mode; /* compareMode; default is BiggerIsBetter */ + long prev_value; + long turn_count; /* last time the value changed */ + + QString hl_better; + QString hl_worse; + QString hl_changd; +}; + +} // namespace nethack_qt_ + +#endif diff --git a/win/Qt/qt_inv.cpp b/win/Qt/qt_inv.cpp new file mode 100644 index 000000000..76bc06cff --- /dev/null +++ b/win/Qt/qt_inv.cpp @@ -0,0 +1,343 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_inv.cpp -- inventory subset of equipment in use, +// displayed in a rectangular grid of object tiles +// +// Essentially a "paper doll" style display. [grep fodder] +// +// This is at the top center of the main window, between messages and +// status. Qt settings (non-OSX) or Preferences (OSX) has a checkbox to +// show it or hide it, plus the tile size to use (independent of map's +// tile size). Supported tile size is 6..48x6..48 with default of 32x32. +// +// TODO? +// When yn_function() is asking for an inventory letter (not sure whether +// that is currently discernable...), allow clicking on a cell in the +// paper doll grid to return the invlet of the item clicked upon. +// + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_inv.h" +#include "qt_glyph.h" +#include "qt_main.h" +#include "qt_set.h" + +namespace nethack_qt_ { + +static struct obj * +find_tool(int tooltyp) +{ + struct obj *o; + + for (o = gi.invent; o; o = o->nobj) { + if ((tooltyp == LEASH && o->otyp == LEASH && o->leashmon) + // OIL_LAMP is used for candles, lamps, lantern, candelabrum too + || (tooltyp == OIL_LAMP && o->lamplit)) + break; + } + return o; +} + +NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget *parent) : + QWidget(parent) +{ + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + // needed to enable tool tips + setMouseTracking(true); + + /* + * TODO: + * Add support for clicking on a paperdoll cell and have that + * run itemactions(invent.c) for the object shown in the cell. + */ + + // paperdoll is 6x3 but the indices are column oriented: 0..2x0..5 + for (int x = 0; x <= 2; ++x) + for (int y = 0; y <= 5; ++y) + tips[x][y] = NULL; +} + +NetHackQtInvUsageWindow::~NetHackQtInvUsageWindow() +{ + for (int x = 0; x <= 2; ++x) + for (int y = 0; y <= 5; ++y) + if (tips[x][y]) + free((void *) tips[x][y]), tips[x][y] = NULL; +} + +void NetHackQtInvUsageWindow::drawWorn( + QPainter &painter, + obj *nhobj, + int x, int y, // cell index, not pixels + const char *alttip, + int flags) +{ + short int glyph; + glyph_info gi; + int border; + char tipstr[1 + BUFSZ + 1]; // extra room for leading and trailing space + bool rev = (flags == dollReverse), + canbe = (flags != dollUnused); + + if (nhobj) { + border = BORDER_DEFAULT; + // don't expect this to happen but check just in case; + // learn_unseen_invent() is normally called when regaining sight + // and sets dknown and maybe bknown, then updates perm_invent (do + // it regardless of ENHANCED_PAPERDOLL for same effect either way) + if (!Blind && (!nhobj->dknown + || (Role_if(PM_CLERIC) && !nhobj->bknown))) + ::learn_unseen_invent(); +#ifdef ENHANCED_PAPERDOLL + // color margin around cell containing item whose BUC state is known + if (nhobj->bknown) + border = nhobj->cursed ? BORDER_CURSED + : !nhobj->blessed ? BORDER_UNCURSED + : BORDER_BLESSED; + + // border color is used to indicate BUC state; make tip text match + boolean save_implicit_uncursed = ::flags.implicit_uncursed; + ::flags.implicit_uncursed = FALSE; + // set up a tool tip describing the item that will be displayed here + Sprintf(tipstr, " %s ", // extra spaces for enhanced readability + // xprname: invlet, space, dash, space, object description + xprname(nhobj, (char *) NULL, nhobj->invlet, FALSE, 0L, 0L)); + ::flags.implicit_uncursed = save_implicit_uncursed; + + // tips are managed with nethack's alloc(); we don't track allocation + // amount; allocated buffers get reused when big enough (usual case + // since paperdoll updates occur more often than equipment changes) + if (tips[x][y] && strlen(tipstr) > strlen(tips[x][y])) + free((void *) tips[x][y]), tips[x][y] = NULL; + + if (tips[x][y]) + Strcpy(tips[x][y], tipstr); // guaranteed to fit + else + tips[x][y] = dupstr(tipstr); +#endif + glyph = obj_to_glyph(nhobj, rn2_on_display_rng); + } else { + border = NO_BORDER; +#ifdef ENHANCED_PAPERDOLL + // caller usually passes an alternate tool tip for empty cells + size_t altlen = alttip ? 1U + strlen(alttip) + 1U : 0U; + if (tips[x][y] && (!alttip || altlen > strlen(tips[x][y]))) + free((void *) tips[x][y]), tips[x][y] = NULL; + + if (alttip) { + Sprintf(tipstr, " %s ", alttip); + if (tips[x][y]) + Strcpy(tips[x][y], tipstr); // guaranteed to fit + else + tips[x][y] = dupstr(tipstr); + } +#else + nhUse(alttip); +#endif + // an empty slot is shown as floor tile unless it's always empty + glyph = canbe ? fn_cmap_to_glyph(S_room) : GLYPH_UNEXPLORED; + } + map_glyphinfo(0, 0, glyph, 0, &gi); /* this skirts the defined + * interface unfortunately */ + qt_settings->glyphs().drawBorderedCell(painter, glyph, gi.gm.tileidx, + x, y, border, rev); +} + +// called to update the paper doll inventory subset +void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*) +{ + // Paper doll is a 6 row by 3 column grid of worn and wielded + // equipment showing the map tiles that the inventory objects + // would be displayed as if they were on the floor. + // + // 0 1 2 two- dual + // [ old ] normal hander wielding legend + // 0 [x H b] q H b q H b q H b q quiver H helmet b eyewear + // 1 [S " w] w " S W " W w " X w weapon " amulet S shield + // 2 [G C G] x C G x C G . C G x alt-weap C cloak G gloves + // 3 [= A =] = A = = A = = A = = right rg A suit = left ring + // 4 [. U .] L U l L U l L U l L light U shirt l leash + // 5 [. F .] . F . . F . . F . . blank F boots . blank + // W wielded two-handed weapon + // X wielded secondary weapon + // + // 5.0: use a different layout (also different legend for it, above): + // invert so grid is facing player, with right hand on screen left; + // show gloves in only one slot; + // move alternate weapon to former right hand glove slot; + // move blindfold to former alternate weapon slot; + // add quiver to former blindfold slot; + // show secondary weapon in shield slot when two-weapon is active; + // show two-handed primary weapon in both shield and uwep slots; + // add lit lamp/lantern/candle/candelabrum on lower left side; + // add leash-in-use on lower right side + // + // Actually indexed by grid[column][row]. + +#ifdef ENHANCED_PAPERDOLL + if (qt_settings->doll_is_shown && ::iflags.wc_ascii_map + && qt_settings->glyphs().no_tiles) + qt_settings->doll_is_shown = false; + if (!qt_settings->doll_is_shown) + return; + // set glyphs() for the paper doll; might be different size than map's + qt_settings->glyphs().setSize(qt_settings->dollWidth, + qt_settings->dollHeight); + + /* for drawWorn()'s use of obj->invlet */ + if (!::flags.invlet_constant) + reassign(); +#endif + + QPainter painter; + painter.begin(this); + + // String argument is for a tool tip when the object in question is Null. + // + // left grid column (depicts hero's right side) + drawWorn(painter, uquiver, 0, 0, "nothing readied for firing"); // quiver + drawWorn(painter, uwep, 0, 1, "no weapon"); + /* uswapwep slot varies depending upon dual-wielding state; + shown in shield slot when actively wielded, so uswapwep slot is empty + then and an alternate tool tip is used to explain that emptiness */ + if (!u.twoweap) + drawWorn(painter, uswapwep, 0, 2, "no alternate weapon"); + else + drawWorn(painter, NULL, 0, 2, "secondary weapon is wielded"); + drawWorn(painter, uright, 0, 3, "no right ring"); + /* OIL_LAMP matches lit candles, lamps, lantern, and candelabrum + (and might also duplicate Sunsword when it is wielded--hence lit-- + depending upon whether another light source precedes it in invent) */ + drawWorn(painter, find_tool(OIL_LAMP), 0, 4, "no active light sources"); + drawWorn(painter, NULL, 0, 5, NULL, dollUnused); // always blank + + // middle grid column; no unused slots + drawWorn(painter, uarmh, 1, 0, "no helmet"); + drawWorn(painter, uamul, 1, 1, "no amulet"); + drawWorn(painter, uarmc, 1, 2, "no cloak"); + drawWorn(painter, uarm, 1, 3, "no suit"); + drawWorn(painter, uarmu, 1, 4, "no shirt"); + drawWorn(painter, uarmf, 1, 5, "no boots"); + + // right grid column (depicts hero's left side) + drawWorn(painter, ublindf, 2, 0, "no eyewear"); // bf|towel|lenses + /* shield slot varies depending upon weapon usage; + no alt tool tip is needed for first two cases because object will + never be Null when the corresponding tests pass */ + if (u.twoweap) + drawWorn(painter, uswapwep, 2, 1, NULL); // secondary weapon, in use + else if (uwep && bimanual(uwep)) // show two-handed uwep twice + drawWorn(painter, uwep, 2, 1, NULL, dollReverse); // uwep on right + else + drawWorn(painter, uarms, 2, 1, "no shield"); + drawWorn(painter, uarmg, 2, 2, "no gloves"); + drawWorn(painter, uleft, 2, 3, "no left ring"); + /* light source and leash aren't unique and don't have pointers defined */ + drawWorn(painter, find_tool(LEASH), 2, 4, "no leashes in use"); + drawWorn(painter, NULL, 2, 5, NULL, dollUnused); // always blank + + painter.end(); + +#ifdef ENHANCED_PAPERDOLL + // reset glyphs() to the ones being used for the map + qt_settings->glyphs().setSize(qt_settings->tileWidth, + qt_settings->tileHeight); +#endif +} + +QSize NetHackQtInvUsageWindow::sizeHint(void) const +{ + if (qt_settings) { + int w = 0, h = 1; // one pixel margin at top + // 1+X+1: one pixel border surrounding each tile in the paper doll, + // so +1 left and +1 right, also +1 above and +1 below +#ifdef ENHANCED_PAPERDOLL + if (iflags.wc_ascii_map) + qt_settings->doll_is_shown = false; + if (qt_settings->doll_is_shown) { + w += (1 + qt_settings->dollWidth + 1) * 3; + h += (1 + qt_settings->dollHeight + 1) * 6; + } +#else + if (iflags.wc_tiled_map) { + w += (1 + qt_settings->glyphs().width() + 1) * 3; + h += (1 + qt_settings->glyphs().height() + 1) * 6; + } +#endif + return QSize(w, h); + } else { + return QWidget::sizeHint(); + } +} + +// ENHANCED_PAPERDOLL - called when a tool tip is triggered by hovering mouse +bool NetHackQtInvUsageWindow::tooltip_event(QHelpEvent *tipevent) +{ +#ifdef ENHANCED_PAPERDOLL + if (iflags.wc_ascii_map) + qt_settings->doll_is_shown = false; + if (!qt_settings->doll_is_shown) { + tipevent->ignore(); + return false; + } + int wd = qt_settings->dollWidth, + ht = qt_settings->dollHeight; + + // inverse of drawBorderedCell(); + int yoffset = 1, // tiny extra margin at top + ex = tipevent->pos().x(), + ey = tipevent->pos().y() - yoffset, + // KISS: treat 1-pixel margin around cells as part of enclosed cell + cellx = ex / (wd + 2), + celly = ey / (ht + 2); + + const char *tip = (cellx >= 0 && cellx <= 2 && celly >= 0 && celly <= 5) + ? tips[cellx][celly] : NULL; + if (tip && *tip) { + QToolTip::showText(tipevent->globalPos(), QString(tip)); + } else { + QToolTip::hideText(); + tipevent->ignore(); + } +#else + nhUse(tipevent); +#endif /* ENHANCED_PAPERDOLL */ + return true; +} + +// ENHANCED_PAPERDOLL - event handler is necessary to support tool tips +bool NetHackQtInvUsageWindow::event(QEvent *event) +{ +#ifdef ENHANCED_PAPERDOLL + if (event->type() == QEvent::ToolTip) { + QHelpEvent *tipevent = static_cast (event); + return tooltip_event(tipevent); + } +#endif + // with this routine intercepting events, we need to pass along + // paint and mouse-press events to have them handled + return QWidget::event(event); + +} + +// ENHANCED_PAPERDOLL - clicking on the PaperDoll runs #seeall ('*') +void NetHackQtInvUsageWindow::mousePressEvent(QMouseEvent *event UNUSED) +{ +#ifdef ENHANCED_PAPERDOLL + QWidget *main = NetHackQtBind::mainWidget(); + (static_cast (main))->FuncAsCommand(doprinuse); +#endif +} + +} // namespace nethack_qt_ diff --git a/win/Qt/qt_inv.h b/win/Qt/qt_inv.h new file mode 100644 index 000000000..2c1c694e0 --- /dev/null +++ b/win/Qt/qt_inv.h @@ -0,0 +1,37 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_inv.h -- inventory usage window +// This is at the top center of the main window + +#ifndef QT4INV_H +#define QT4INV_H + +namespace nethack_qt_ { + +// for calls to drawWorn +enum drawWornFlag { dollNoFlag = 0, dollUnused = 1, dollReverse = 2 }; + +class NetHackQtInvUsageWindow : public QWidget { +public: + NetHackQtInvUsageWindow(QWidget* parent); + virtual ~NetHackQtInvUsageWindow(); + virtual void paintEvent(QPaintEvent*); + virtual QSize sizeHint(void) const; + +protected: + virtual bool event(QEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + +private: + void drawWorn(QPainter &painter, obj *nhobj, int x, int y, + const char *alttip, int flags = dollNoFlag); + bool tooltip_event(QHelpEvent *tipevent); + + char *tips[3][6]; // PAPERDOLL is a grid of 3x6 cells for tiles +}; + +} // namespace nethack_qt_ + +#endif diff --git a/win/Qt4/qt4kde0.h b/win/Qt/qt_kde0.h similarity index 91% rename from win/Qt4/qt4kde0.h rename to win/Qt/qt_kde0.h index 27a678c01..8ac1f9595 100644 --- a/win/Qt4/qt4kde0.h +++ b/win/Qt/qt_kde0.h @@ -4,7 +4,7 @@ #ifndef QT_DUMMYKDE #define QT_DUMMYKDE -namespace nethack_qt4 { +namespace nethack_qt_ { class KTopLevelWidget : public QMainWindow { Q_OBJECT diff --git a/win/Qt/qt_key.cpp b/win/Qt/qt_key.cpp new file mode 100644 index 000000000..b598d6b1d --- /dev/null +++ b/win/Qt/qt_key.cpp @@ -0,0 +1,126 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_key.cpp -- a key buffer + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#include "qt_post.h" +#include "qt_key.h" + +namespace nethack_qt_ { + +// convert a Qt key event into a simple ASCII character +uchar keyValue(QKeyEvent *key_event) +{ + // key_event manipulation derived from NetHackQtBind::notify(); + // used for menus and text windows in qt_menu.cpp, also for + // extended commands in xcmd.cpp and popup yn_function in qt_yndlg.cpp + + const int k = key_event->key(); + Qt::KeyboardModifiers mod = key_event->modifiers(); + const QString &txt = key_event->text(); + QChar ch = !txt.isEmpty() ? txt.at(0) : QChar(0); + + if (ch >= QChar(128)) + ch = QChar(0); + // on OSX, ascii control codes are not sent, force them + if (ch == 0 && (mod & Qt::ControlModifier) != 0) { + if (k >= Qt::Key_A && k <= Qt::Key_Underscore) + ch = QChar((k - (Qt::Key_A - 1))); + } + + uchar result = (uchar) ch.cell(); + //raw_printf("kV: k=%d, ch=%u", k, (unsigned) result); + return result; +} + +NetHackQtKeyBuffer::NetHackQtKeyBuffer() : + in(0), out(0) +{ +} + +bool NetHackQtKeyBuffer::Empty() const +{ + return (in == out); +} + +bool NetHackQtKeyBuffer::Full() const +{ + return (((in + 1) % maxkey) == out); +} + +void NetHackQtKeyBuffer::Put(int k, int a, uint kbstate) +{ + //raw_printf("k:%3d a:'%s' s:0x%08x", k, visctrl((char) a), kbstate); + if (Full()) + return; // Safety + key[in] = k; + ascii[in] = a; + state[in] = (Qt::KeyboardModifiers) kbstate; + in = (in + 1) % maxkey; +} + +void NetHackQtKeyBuffer::Put(char a) +{ + Put(0, a, 0U); +} + +void NetHackQtKeyBuffer::Put(const char* str) +{ + while (*str) Put(*str++); +} + +int NetHackQtKeyBuffer::GetKey() +{ + if ( Empty() ) return 0; + int r=TopKey(); + out=(out+1)%maxkey; + return r; +} + +int NetHackQtKeyBuffer::GetAscii() +{ + if ( Empty() ) return 0; // Safety + int r=TopAscii(); + out=(out+1)%maxkey; + return r; +} + +Qt::KeyboardModifiers NetHackQtKeyBuffer::GetState() +{ + if ( Empty() ) return Qt::NoModifier; + Qt::KeyboardModifiers r=TopState(); + out=(out+1)%maxkey; + return r; +} + +int NetHackQtKeyBuffer::TopKey() const +{ + if ( Empty() ) return 0; + return key[out]; +} + +int NetHackQtKeyBuffer::TopAscii() const +{ + if ( Empty() ) return 0; + return ascii[out]; +} + +Qt::KeyboardModifiers NetHackQtKeyBuffer::TopState() const +{ + if ( Empty() ) return Qt::NoModifier; + return state[out]; +} + +void NetHackQtKeyBuffer::Drain() +{ + in = out = 0; +} + +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4key.h b/win/Qt/qt_key.h similarity index 70% rename from win/Qt4/qt4key.h rename to win/Qt/qt_key.h index 0333269cd..f2e2c2084 100644 --- a/win/Qt4/qt4key.h +++ b/win/Qt/qt_key.h @@ -2,12 +2,15 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4key.h -- a key buffer +// qt_key.h -- a key buffer #ifndef QT4KEY_H #define QT4KEY_H -namespace nethack_qt4 { +namespace nethack_qt_ { + +// not part of any class; used in qt_menu.cpp, qt_xcmd.cpp, qt_yndlg.cpp +extern uchar keyValue(QKeyEvent *key_event); class NetHackQtKeyBuffer { public: @@ -16,7 +19,7 @@ class NetHackQtKeyBuffer { bool Empty() const; bool Full() const; - void Put(int k, int ascii, int state); + void Put(int k, int ascii, uint state); void Put(char a); void Put(const char* str); int GetKey(); @@ -27,6 +30,8 @@ class NetHackQtKeyBuffer { int TopAscii() const; Qt::KeyboardModifiers TopState() const; + void Drain(); + private: enum { maxkey=64 }; int key[maxkey]; @@ -35,6 +40,6 @@ class NetHackQtKeyBuffer { int in,out; }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt4/qt4line.cpp b/win/Qt/qt_line.cpp similarity index 71% rename from win/Qt4/qt4line.cpp rename to win/Qt/qt_line.cpp index dd9b18c5f..482122589 100644 --- a/win/Qt4/qt4line.cpp +++ b/win/Qt/qt_line.cpp @@ -2,33 +2,28 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4line.cpp -- a one line input window +// qt_line.cpp -- a one line input window +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif -#include "qt4line.h" +#include "qt_post.h" +#include "qt_line.h" -namespace nethack_qt4 { +namespace nethack_qt_ { NetHackQtLineEdit::NetHackQtLineEdit() : QLineEdit(0) { } -NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name) : +NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name UNUSED) : QLineEdit(parent) { } @@ -39,4 +34,4 @@ void NetHackQtLineEdit::fakeEvent(int key, int ascii, Qt::KeyboardModifiers stat keyPressEvent(&fake); } -} // namespace nethack_qt4 +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4line.h b/win/Qt/qt_line.h similarity index 81% rename from win/Qt4/qt4line.h rename to win/Qt/qt_line.h index bb5067f79..4b3c10cef 100644 --- a/win/Qt4/qt4line.h +++ b/win/Qt/qt_line.h @@ -2,12 +2,12 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4line.h -- a one line input window +// qt_line.h -- a one line input window #ifndef QT4LINE_H #define QT4LINE_H -namespace nethack_qt4 { +namespace nethack_qt_ { class NetHackQtLineEdit : public QLineEdit { public: @@ -17,6 +17,6 @@ class NetHackQtLineEdit : public QLineEdit { void fakeEvent(int key, int ascii, Qt::KeyboardModifiers state); }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_main.cpp b/win/Qt/qt_main.cpp new file mode 100644 index 000000000..14a4f51f6 --- /dev/null +++ b/win/Qt/qt_main.cpp @@ -0,0 +1,1465 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_main.cpp -- the main window + +extern "C" { +#include "hack.h" +#define CTRL(c) (0x1f & (c)) // substitute for C() from global.h, for ^V hack +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x060000 +#include +#elif QT_VERSION >= 0x050000 +#include +#endif + +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_main.h" +#include "qt_main.moc" +#include "qt_bind.h" +#include "qt_glyph.h" +#include "qt_inv.h" +#include "qt_key.h" +#include "qt_map.h" +#include "qt_msg.h" +#include "qt_set.h" +#include "qt_stat.h" +#include "qt_str.h" + +#ifndef KDE +#include "qt_kde0.moc" +#endif + +// temporary +extern char *qt_tilewidth; +extern char *qt_tileheight; +extern int qt_compact_mode; +// end temporary + +namespace nethack_qt_ { + +// temporary +void centerOnMain( QWidget* w ); +// end temporary + +/* XPM */ +static const char * nh_icon[] = { +"40 40 6 1", +" s None c none", +". c #ffffff", +"X c #dadab6", +"o c #6c91b6", +"O c #476c6c", +"+ c #000000", +" ", +" ", +" ", +" . .X..XX.XX X ", +" .. .....X.XXXXXX XX ", +" ... ....X..XX.XXXXX XXX ", +" .. ..........X.XXXXXXXXXXX XX ", +" .... ........X..XX.XXXXXXXXX XXXX ", +" .... ..........X.XXXXXXXXXXX XXXX ", +" ooOOO..ooooooOooOOoOOOOOOOXX+++OO++ ", +" ooOOO..ooooooooOoOOOOOOOOOXX+++OO++ ", +" ....O..ooooooOooOOoOOOOOOOXX+XXXX++ ", +" ....O..ooooooooOoOOOOOOOOOXX+XXXX++ ", +" ..OOO..ooooooOooOOoOOOOOOOXX+++XX++ ", +" ++++..ooooooooOoOOOOOOOOOXX+++ +++ ", +" +++..ooooooOooOOoOOOOOOOXX+++ + ", +" ++..ooooooooOoOOOOOOOOOXX+++ ", +" ..ooooooOooOOoOOOOOOOXX+++ ", +" ..ooooooooOoOOOOOOOOOXX+++ ", +" ..ooooooOooOOoOOOOOOOXX+++ ", +" ..ooooooooOoOOOOOOOOOXX+++ ", +" ..oooooOooOOoOOOOOOXX+++ ", +" ..oooooooOoOOOOOOOOXX+++ ", +" ..ooooOooOOoOOOOOXX+++ ", +" ..ooooooOoOOOOOOOXX++++ ", +" ..o..oooOooOOoOOOOXX+XX+++ ", +" ...o..oooooOoOOOOOXX++XXX++ ", +" ....OO..ooOooOOoOOXX+++XXXX++ ", +" ...oo..+..oooOoOOOXX++XXooXXX++ ", +" ...ooo..++..OooOOoXX+++XXooOXXX+ ", +" ..oooOOXX+++....XXXX++++XXOOoOOXX+ ", +" ..oooOOXX+++ ...XXX+++++XXOOooOXX++ ", +" ..oooOXXX+++ ..XX+++ +XXOOooOXX++ ", +" .....XXX++++ XXXXXXX++ ", +" ....XX++++ XXXXXXX+ ", +" ...XX+++ XXXXX++ ", +" ", +" ", +" ", +" "}; +/* XPM */ +static const char * nh_icon_small[] = { +/* width height ncolors chars_per_pixel */ +"16 16 16 1", +/* colors */ +" c #587070", +". c #D1D5C9", +"X c #8B8C84", +"o c #2A2A28", +"O c #9AABA9", +"+ c #6A8FB2", +"@ c #C4CAC4", +"# c #B6BEB6", +"$ c None", +"% c #54564E", +"& c #476C6C", +"* c #ADB2AB", +"= c #ABABA2", +"- c #5E8295", +"; c #8B988F", +": c #E8EAE7", +/* pixels */ +"$$$$$$$$$$$$$$$$", +"$$$.$#::.#==*$$$", +"$.*:::::....#*=$", +"$@#:..@#*==#;XX;", +"$@O:+++- &&; X%X", +"$#%.+++- &&;% oX", +"$$o.++-- &&;%%X$", +"$$$:++-- &&;%%$$", +"$$$.O++- &&=o $$", +"$$$=:++- & XoX$$", +"$$*:@O-- ;%Xo$$", +"$*:O#$+--;oOOX $", +"$:+ =o::=oo=-;%X", +"$::.%o$*;X;##@%$", +"$$@# ;$$$$$=*;X$", +"$$$$$$$$$$$$$$$$" +}; + +#if 0 // RLC +/* XPM */ +static const char * map_xpm[] = { +"12 13 4 1", +". c None", +" c #000000000000", +"X c #0000B6DAFFFF", +"o c #69A69248B6DA", +" .", +" XXXXX ooo ", +" XoooX o ", +" XoooX o o ", +" XoooX ooo ", +" XXoXX o ", +" oooooXXX ", +" oo o oooX ", +" o XooX ", +" oooo XooX ", +" o o XXXX ", +" ", +". "}; +/* XPM */ +static const char * msg_xpm[] = { +"12 13 4 1", +". c None", +" c #FFFFFFFFFFFF", +"X c #69A69248B6DA", +"o c #000000000000", +" .", +" XXX XXX X o", +" o", +" XXXXX XX o", +" o", +" XX XXXXX o", +" o", +" XXXXXX o", +" o", +" XX XXX XX o", +" o", +" o", +".ooooooooooo"}; +/* XPM */ +static const char * stat_xpm[] = { +"12 13 5 1", +" c None", +". c #FFFF00000000", +"X c #000000000000", +"o c #FFFFFFFF0000", +"O c #69A6FFFF0000", +" ", +" ", +"... ", +"...X ", +"...X ... ", +"oooX oooX", +"oooXooo oooX", +"OOOXOOOXOOOX", +"OOOXOOOXOOOX", +"OOOXOOOXOOOX", +"OOOXOOOXOOOX", +"OOOXOOOXOOOX", +" XXXXXXXXXXX"}; +#endif +/* XPM */ +static const char * info_xpm[] = { +"12 13 4 1", +" c None", +". c #00000000FFFF", +"X c #FFFFFFFFFFFF", +"o c #000000000000", +" ... ", +" ....... ", +" ...XXX... ", +" .........o ", +"...XXXX.... ", +"....XXX....o", +"....XXX....o", +"....XXX....o", +" ...XXX...oo", +" ..XXXXX..o ", +" .......oo ", +" o...ooo ", +" ooo "}; + + +/* XPM */ +static const char * again_xpm[] = { +"12 13 2 1", +" c None", +". c #000000000000", +" .. ", +" .. ", +" ..... ", +" ....... ", +"... .. .. ", +".. .. .. ", +".. ..", +".. ..", +".. ..", +" .. .. ", +" .......... ", +" ...... ", +" "}; +/* XPM */ +static const char * kick_xpm[] = { +"12 13 3 1", +" c None", +". c #000000000000", +"X c #FFFF6DB60000", +" ", +" ", +" . . . ", +" ... . . ", +" ... . ", +" ... . ", +" ... ", +"XXX ... ", +"XXX. ... ", +"XXX. ... ", +"XXX. .. ", +" ... ", +" "}; +/* XPM */ +static const char * throw_xpm[] = { +"12 13 3 1", +" c None", +". c #FFFF6DB60000", +"X c #000000000000", +" ", +" ", +" ", +" ", +".... X ", +"....X X ", +"....X XXXXXX", +"....X X ", +" XXXX X ", +" ", +" ", +" ", +" "}; +/* XPM */ +static const char * fire_xpm[] = { +"12 13 5 1", +" c None", +". c #B6DA45140000", +"X c #FFFFB6DA9658", +"o c #000000000000", +"O c #FFFF6DB60000", +" . ", +" X. ", +" X . ", +" X .o ", +" X . o ", +" X .o o ", +"OOOOOOOOoooo", +" X .o o ", +" X . o o ", +" X .o ", +" X. o ", +" . o ", +" o "}; +/* XPM */ +static const char * pickup_xpm[] = { +"12 13 3 1", +" c None", +". c #000000000000", +"X c #FFFF6DB60000", +" ", +" . ", +" ... ", +" . . . ", +" . ", +" . ", +" ", +" XXXXX ", +" XXXXX. ", +" XXXXX. ", +" XXXXX. ", +" ..... ", +" "}; +/* XPM */ +static const char * drop_xpm[] = { +"12 13 3 1", +" c None", +". c #FFFF6DB60000", +"X c #000000000000", +" ", +" ..... ", +" .....X ", +" .....X ", +" .....X ", +" XXXXX ", +" ", +" X ", +" X ", +" X X X ", +" XXX ", +" X ", +" "}; +/* XPM */ +static const char * eat_xpm[] = { +"12 13 4 1", +" c None", +". c #000000000000", +"X c #FFFFB6DA9658", +"o c #FFFF6DB60000", +" .X. .. ", +" .X. .. ", +" .X. .. ", +" .X. .. ", +" ... .. ", +" .. .. ", +" .. .. ", +" oo oo ", +" oo oo ", +" oo oo ", +" oo oo ", +" oo oo ", +" oo oo "}; +/* XPM */ +static const char * search_xpm[] = { +"12 13 3 1", +" c None", +". c #FFFFFFFF0000", +"X c #7F0000000000", +" ", +" XXXXX ", +" X ... X ", +" X.....X ", +" X.....X ", +" X ... X ", +" XXXXX ", +" X ", +" X ", +" X ", +" X ", +" X ", +" "}; +/* XPM */ +static const char * rest_xpm[] = { +"12 13 2 1", +" c None", +". c #000000000000", +" ..... ", +" . ", +" . ", +" . ....", +" ..... . ", +" . ", +" ....", +" ", +" .... ", +" . ", +" . ", +" .... ", +" "}; +/* XPM */ +static const char * cast_a_xpm[] UNUSED = { +"12 13 3 1", +" c None", +". c #FFFF6DB60000", +"X c #000000000000", +" . ", +" . ", +" .. ", +" .. ", +" .. . ", +" .. . ", +" ...... ", +" .. .. XX ", +" .. X X ", +" .. X X ", +" .. XXXX ", +" . X X ", +" . X X "}; +/* XPM */ +static const char * cast_b_xpm[] UNUSED = { +"12 13 3 1", +" c None", +". c #FFFF6DB60000", +"X c #000000000000", +" . ", +" . ", +" .. ", +" .. ", +" .. . ", +" .. . ", +" ...... ", +" .. .. XXX ", +" .. X X ", +" .. XXX ", +" .. X X ", +" . X X ", +" . XXX "}; +/* XPM */ +static const char * cast_c_xpm[] UNUSED = { +"12 13 3 1", +" c None", +". c #FFFF6DB60000", +"X c #000000000000", +" . ", +" . ", +" .. ", +" .. ", +" .. . ", +" .. . ", +" ...... ", +" .. .. XX ", +" .. X X ", +" .. X ", +" .. X ", +" . X X ", +" . XX "}; + +static QString +aboutMsg() +{ + char *p, vbuf[BUFSZ]; + /* nethack's getversionstring() includes a final period + but we're using it mid-sentence so strip period off */ + if ((p = strrchr(::getversionstring(vbuf, sizeof vbuf), '.')) != 0 + && *(p + 1) == '\0') + *p = '\0'; + /* it's also long; break it into two pieces */ + (void) strsubst(vbuf, " - ", "\n- "); + QString msg = nh_qsprintf( + // format + "NetHack-Qt is a version of NetHack built using" // no newline +#ifdef KDE + " KDE and" // ditto +#endif + " the Qt %d GUI toolkit.\n" // short Qt version + "\n" + "This is %s%s and Lua %s.\n" // long nethack version, Qt & Lua versions + "\n" + "NetHack's Qt interface originally developed by Warwick Allison.\n" + "\n" +#if 0 + "Homepage:\n http://trolls.troll.no/warwick/nethack/\n" //obsolete +#endif +#ifdef KDE + "KDE:\n https://kde.org/\n" +#endif +#if 1 + "Qt:\n https://qt.io/\n" +#else + "Qt:\n http://www.troll.no/\n" // obsolete +#endif + "Lua:\n https://lua.org/\n" + "NetHack:\n %s\n", // DEVTEAM_URL + // arguments +#ifdef QT_VERSION_MAJOR + QT_VERSION_MAJOR, +#else + 5, // Qt version macro should exist; if not, assume Qt5 +#endif + vbuf, // nethack version +#ifdef QT_VERSION_STR + " with Qt " QT_VERSION_STR, +#else + "", +#endif + ::get_lua_version(), + DEVTEAM_URL); + return msg; +} + +class SmallToolButton : public QToolButton { +public: + SmallToolButton(const QPixmap &pm, const QString &textLabel, + const QString &grouptext, + QObject *receiver, const char *slot, + QWidget *parent) : + QToolButton(parent) + { + setIcon(QIcon(pm)); + setToolTip(textLabel); + setStatusTip(grouptext); + connect(this, SIGNAL(clicked(bool)), receiver, slot); + } + + QSize sizeHint() const + { + // get just a couple more pixels for the map + return QToolButton::sizeHint()-QSize(0,2); + } +}; + +NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : + message(0), map(0), status(0), invusage(0), + hsplitter(0), vsplitter(0), + keysink(ks), dirkey(0) +{ + QToolBar* toolbar = new QToolBar(this); + toolbar->setMovable(false); + toolbar->setFocusPolicy(Qt::NoFocus); + addToolBar(toolbar); + menubar = menuBar(); + + setWindowTitle("NetHack-Qt"); + setWindowIcon(QIcon(QPixmap(qt_compact_mode ? nh_icon_small : nh_icon))); + +#ifdef MACOS + /* + * MacOS Note: + * The toolbar on MacOS starts with a system menu labeled with the + * Apple logo and an application menu labeled with the application's + * name (taken from Info.plist if present, otherwise the base name + * of the running program). After that, application-specific menus + * (in our case "game",...,"help") follow. Several menu entry + * names ("About", "Quit"/"Exit", "Preferences"/"Options"/ + * "Settings"/"Setup"/"Config") get hijacked and placed in the + * application menu (and renamed in the process) even if the code + * here tries to put them in another menu. + * See QtWidgets/doc/qmenubar.html for slightly more information. + * setMenuRole() can be used to override this behavior. + */ +#endif + +#ifdef CTRL_V_HACK + // NetHackQtBind::notify() sees all control characters except for ^V + QShortcut *c_V = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_V), this); + connect(c_V, &QShortcut::activated, this, &NetHackQtMainWindow::CtrlV); +#endif + + QMenu* game=new QMenu; + QMenu* apparel=new QMenu; + QMenu* act1=new QMenu; + QMenu* act2 = qt_compact_mode ? new QMenu : act1; + QMenu* magic=new QMenu; + QMenu* info=new QMenu; + + QMenu *help; +#ifdef KDE + help = kapp->getHelpMenu( true, "" ); + help->addSeparator(); +#else + help = qt_compact_mode ? info : new QMenu; +#endif + + enum { OnDesktop=1, OnHandhelds=2 }; + struct Macro { + QMenu *menu; + const char *name; + int flags; // 1 desktop, 2 handheld, 3 either/both + int (*funct)(void); + } item[] = { + { game, 0, 3, (int (*)(void)) 0}, + { game, "Extended-commands", 3, doextcmd }, + { game, 0, 3, (int (*)(void)) 0}, + { game, "Version", 3, doversion}, + { game, "Compilation", 3, doextversion}, + { game, "History", 3, dohistory}, + { game, "Redraw", 0, doredraw}, // useless + { game, +#ifdef MACOS + /* Qt on OSX would rename "Options" to "Preferences..." and + move it from intended destination to the application menu; + the ampersand produces &O which makes Alt+O into a keyboard + shortcut--except those are disabled by default by Qt on OSX */ + "Run-time &" // rely on adjacent string concatenation +#endif + "Options", 3, doset}, + { game, "Explore mode", 3, enter_explore_mode}, + { game, 0, 3, (int (*)(void)) 0}, + { game, "Save-and-exit", 3, dosave}, + { game, +#ifdef MACOS + /* need something to prevent matching leading "quit" so that it + isn't hijacked for the application menu; the ampersand is to + make &Q be a keyboard shortcut (but see Options above) */ + "\177&" +#endif + "Quit-without-saving", 3, done2}, + + { apparel, "Apparel off", 2, doddoremarm}, + { apparel, "Remove many", 1, doddoremarm}, + { apparel, 0, 3, (int (*)(void)) 0}, + { apparel, "Wield weapon", 3, dowield}, + { apparel, "Exchange weapons", 3, doswapweapon}, + { apparel, "Two weapon combat", 3, dotwoweapon}, + { apparel, "Load quiver", 3, dowieldquiver}, + { apparel, 0, 3, (int (*)(void)) 0}, + { apparel, "Wear armor", 3, dowear}, + { apparel, "Take off armor", 3, dotakeoff}, + { apparel, 0, 3, (int (*)(void)) 0}, + { apparel, "Put on accessories", 3, doputon}, + { apparel, "Remove accessories", 3, doremring}, + + /* { act1, "Again\tCtrl+A", "\001", 2}, + { act1, 0, 0, 3}, */ + { act1, "Apply", 3, doapply}, + { act1, "Chat", 3, dotalk}, + { act1, "Close door", 3, doclose}, + { act1, "Down", 3, dodown}, + { act1, "Drop many", 2, doddrop}, + { act1, "Drop", 2, dodrop}, + { act1, "Eat", 2, doeat}, + { act1, "Engrave", 3, doengrave}, + /* { act1, "Fight\tShift+F", "F", 3}, */ + { act1, "Fire from quiver", 2, dofire}, + { act1, "Force", 3, doforce}, + { act1, "Jump", 3, dojump}, + { act2, "Kick", 2, dokick}, + { act2, "Loot", 3, doloot}, + { act2, "Open door", 3, doopen}, + { act2, "Pay", 3, dopay}, + // calling this "Get" was confusing to experienced players + { act1, "Pick up (was Get)", 3, dopickup}, + { act2, "Rest", 2, donull}, + { act2, "Ride", 3, doride}, + { act2, "Search", 3, dosearch}, + { act2, "Sit", 3, dosit}, + { act2, "Throw", 2, dothrow}, + { act2, "Untrap", 3, dountrap}, + { act2, "Up", 3, doup}, + { act2, "Wipe face", 3, dowipe}, + + { magic, "Quaff potion", 3, dodrink}, + { magic, "Read scroll/book", 3, doread}, + { magic, "Zap wand", 3, dozap}, + { magic, "Zap spell", 3, docast}, + { magic, "Dip", 3, dodip}, + { magic, "Rub", 3, dorub}, + { magic, "Invoke", 3, doinvoke}, + { magic, 0, 3, (int (*)(void)) 0}, + { magic, "Offer", 3, dosacrifice}, + { magic, "Pray", 3, dopray}, + { magic, 0, 3, (int (*)(void)) 0}, + { magic, "Teleport", 3, dotelecmd}, + { magic, "Monster action", 3, domonability}, + { magic, "Turn undead", 3, doturn}, + + { help, "Help", 3, dohelp}, + { help, 0, 3, (int (*)(void)) 0}, + { help, "What is here", 3, dolook}, + { help, "What is there", 3, doquickwhatis}, + { help, "What is...", 2, dowhatis}, + { help, 0, 1, (int (*)(void)) 0}, + + { info, "Inventory", 3, ddoinv}, + { info, "Attributes (extended status)", 3, doattributes }, + { info, "Overview", 3, dooverview }, + { info, "Conduct", 3, doconduct}, + { info, "Discoveries", 3, dodiscovered}, + { info, "List/reorder spells", 3, dovspell}, + { info, "Adjust inventory letters", 3, doorganize }, + { info, 0, 3, (int (*)(void)) 0}, + { info, "Name object or creature", 3, docallcmd}, + { info, "Annotate level", 3, donamelevel }, + { info, 0, 3, (int (*)(void)) 0}, + { info, "Skills", 3, enhance_weapon_skill}, + + { 0, 0, 0, (int (*)(void)) 0 } + }; + + QAction *actn; +#ifndef MACOS + (void) game->addAction("Qt settings...", this, SLOT(doQtSettings(bool))); +#else + /* on OSX, put this in the application menu instead of the game menu; + Qt would change the action name behind our backs; do it explicitly */ + actn = game->addAction("Preferences...", this, SLOT(doQtSettings(bool))); + actn->setMenuRole(QWidgetAction::PreferencesRole); + /* we also want a "Quit NetHack" entry in the application menu; + when "_Quit-without-saving" was called "Quit" it got intercepted + for that, but now this needs to be added separately; we'll use a + handy menu and let the interception put it in the intended place; + unlike About, it is not a duplicate; _Quit-without-saving runs + nethack's #quit command with "really quit?" prompt, this quit--with + Command+q as shortcut--pops up a dialog to choose between quit or + cancel-and-resume-playing */ + actn = game->addAction("Quit NetHack-Qt", this, SLOT(doQuit(bool))); + actn->setMenuRole(QWidgetAction::QuitRole); +#endif + + actn = help->addAction("About NetHack-Qt", this, SLOT(doAbout(bool))); +#ifdef MACOS + actn->setMenuRole(QWidgetAction::AboutRole); + /* for OSX, the preceding "About" went into the application menu; + now add another duplicate one to the Help dropdown menu */ + actn = help->addAction("About NetHack-Qt", this, SLOT(doAbout(bool))); + actn->setMenuRole(QWidgetAction::NoRole); +#else + nhUse(actn); +#endif + help->addSeparator(); + + //help->addAction("NetHack Guidebook", this, SLOT(doGuidebook(bool))); + //help->addSeparator(); + + for (int i = 0; item[i].menu; ++i) { + if ( item[i].flags & (qt_compact_mode ? 1 : 2) ) { + if (item[i].name) { + char actchar[32]; + char menuitem[BUFSZ]; + actchar[0] = actchar[1] = '\0'; + if (item[i].funct) { + actchar[0] = cmd_from_func(item[i].funct); + if (actchar[0] + /* M-c won't work; translation between character + sets by the QString class can classify such + characters as erroneous and change them to '?' */ + && ((actchar[0] & 0x7f) != actchar[0] + /* the vi movement keys won't work reliably + because toggling number_pad affects them but + doesn't redo these menus */ + || strchr("hjklyubnHJKLYUBN", actchar[0]) + || strchr("hjklyubn", (actchar[0] | 0x60)))) + actchar[0] = '\0'; + } + if (actchar[0] && !qt_compact_mode) + Sprintf(menuitem, "%.50s\t%.9s", item[i].name, + visctrl(actchar[0])); + else + Sprintf(menuitem, "%s", item[i].name); + + if (item[i].funct && !actchar[0]) { + actchar[0] = '#'; + (void) cmdname_from_func(item[i].funct, + &actchar[1], FALSE); + } + if (actchar[0]) { + QString name = menuitem; + QAction *action = item[i].menu->addAction(name); +#if QT_VERSION < 0x060000 + action->setData(actchar); +#else + action->setData(QString(actchar)); +#endif + } + } else { + item[i].menu->addSeparator(); + } + } + } + + game->setTitle("Game"); + menubar->addMenu(game); + apparel->setTitle("Gear"); + menubar->addMenu(apparel); + + if ( qt_compact_mode ) { + act1->setTitle("A-J"); + menubar->addMenu(act1); + act2->setTitle("K-Z"); + menubar->addMenu(act2); + magic->setTitle("Magic"); + menubar->addMenu(magic); + info->setIcon(QIcon(QPixmap(info_xpm))); + info->setTitle("Info"); + menubar->addMenu(info); + //menubar->insertItem(QPixmap(map_xpm), this, SLOT(raiseMap())); + //menubar->insertItem(QPixmap(msg_xpm), this, SLOT(raiseMessages())); + //menubar->insertItem(QPixmap(stat_xpm), this, SLOT(raiseStatus())); + info->addSeparator(); + info->addAction("Map", this, SLOT(raiseMap())); + info->addAction("Messages", this, SLOT(raiseMessages())); + info->addAction("Status", this, SLOT(raiseStatus())); + } else { + act1->setTitle("Action"); + menubar->addMenu(act1); + magic->setTitle("Magic"); + menubar->addMenu(magic); + info->setTitle("Info"); + menubar->addMenu(info); + menubar->addSeparator(); +#ifndef MACOS + help->setTitle("Help"); +#else + // On OSX, an entry in the menubar called "Help" will get an + // extra action, "Search [______]", inserted as the first entry. + // We have no control over what it does and don't want it. + // + // Using actions() to fetch a list of all entries doesn't find it, + // so we don't have its widget pointer to pass to removeAction(). + // + // Altering the name with an invisible character to inhibit + // string matching is ludicrous but keeps the unwanted action + // from getting inserted into the "Help" menu behind our back. + // Underscore works too and is more robust but unless we prepend + // it to every entry, "_Help" would stand out as strange. + help->setTitle("\177Help"); + // (Renaming back to "Help" after the fact does reset the menu's + // name but it also results in the Search action being added. + // Perhaps a custom context menu that changes its name to "Help" + // as it is being shown--and possibly changes back afterward-- + // would work but the name mangling hack is much simpler.) +#endif + menubar->addMenu(help); + } + + // order changed: was Again, Get, Kick, Throw, Fire, Drop, Eat, Rest + // now Again, PickUp, Drop, Kick, Throw, Fire, Eat, Rest + QSignalMapper* sm = new QSignalMapper(this); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + connect(sm, SIGNAL(mappedString(const QString&)), + this, SLOT(doKeys(const QString&))); +#else + connect(sm, SIGNAL(mapped(const QString&)), + this, SLOT(doKeys(const QString&))); +#endif + AddToolButton(toolbar, sm, "Again", do_repeat, QPixmap(again_xpm)); + // this used to be called "Get" which is confusing to experienced players + AddToolButton(toolbar, sm, "Pick up", dopickup, QPixmap(pickup_xpm)); + AddToolButton(toolbar, sm, "Drop", doddrop, QPixmap(drop_xpm)); + AddToolButton(toolbar, sm, "Kick", dokick, QPixmap(kick_xpm)); + AddToolButton(toolbar, sm, "Throw", dothrow, QPixmap(throw_xpm)); + AddToolButton(toolbar, sm, "Fire", dofire, QPixmap(fire_xpm)); + AddToolButton(toolbar, sm, "Eat", doeat, QPixmap(eat_xpm)); + AddToolButton(toolbar, sm, "Search", dosearch, QPixmap(search_xpm)); + AddToolButton(toolbar, sm, "Rest", donull, QPixmap(rest_xpm)); + + connect(game, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + connect(apparel, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + connect(act1, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + if (act2 != act1) + connect(act2, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + connect(magic, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + connect(info, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + connect(help, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + +#ifdef KDE + setMenu (menubar); +#endif + +#if QT_VERSION < 0x060000 + QSize screensize = QApplication::desktop()->size(); +#else + QSize screensize = screen()->size(); +#endif + int x=0,y=0; + int w=screensize.width()-10; // XXX arbitrary extra space for frame + int h=screensize.height()-50; + + int maxwn = 1400; + int maxhn = 1024; + if (qt_settings != NULL) { + auto glyphs = &qt_settings->glyphs(); + if (glyphs != NULL) { + maxwn = glyphs->width() * (COLNO + 1); + maxhn = glyphs->height() * ROWNO * 6/4 + glyphs->height() * 10; + } + } + + // Be exactly the size we want to be - full map... + if (w>maxwn) { + x+=(w-maxwn)/2; + w=maxwn; // Doesn't need to be any wider + } + if (h>maxhn) { + y+=(h-maxhn)/2; + h=maxhn; // Doesn't need to be any taller + } + + setGeometry(x,y,w,h); + + if ( qt_compact_mode ) { + stack = new QStackedWidget(this); + setCentralWidget(stack); + } else { + vsplitter = new QSplitter(Qt::Vertical); + setCentralWidget(vsplitter); + hsplitter = new QSplitter(Qt::Horizontal); + invusage = new NetHackQtInvUsageWindow(hsplitter); + vsplitter->insertWidget(0, hsplitter); + hsplitter->insertWidget(1, invusage); + } +} + +#ifdef CTRL_V_HACK +// called when ^V is typed while the main window has keyboard focus; +// all other control characters go through NetHackQtBind::notify() +void NetHackQtMainWindow::CtrlV() +{ + static const char cV[] = { CTRL('V'), '\0' }; + doKeys(cV); +} +#endif + +// add a toolbar button to invoke command 'name' via function '(*func)()' +void NetHackQtMainWindow::AddToolButton(QToolBar *toolbar, QSignalMapper *sm, + const char *name, int (*func)(void), + QPixmap xpm) +{ + char actchar[2]; + uchar key; + + key = (uchar) cmd_from_func(func); + + // if key is valid, add a button for it; otherwise omit the command + // (won't work as intended if a different command is bound to same key) + if (key) { + QToolButton *tb = new SmallToolButton(xpm, QString(name), "Action", + sm, SLOT(map()), toolbar); + actchar[0] = '\0'; + sm->setMapping(tb, strkitten(actchar, (char) key)); + toolbar->addWidget(tb); + } +} + +void NetHackQtMainWindow::zoomMap() +{ + qt_settings->toggleGlyphSize(); +} + +void NetHackQtMainWindow::raiseMap() +{ + if ( stack->currentWidget() == map->Widget() ) { + zoomMap(); + } else { + stack->setCurrentWidget(map->Widget()); + } +} + +void NetHackQtMainWindow::raiseMessages() +{ + stack->setCurrentWidget(message->Widget()); +} + +void NetHackQtMainWindow::raiseStatus() +{ + stack->setCurrentWidget(status->Widget()); +} + +#if 0 // RLC this isn't used +class NetHackMimeSourceFactory : public Q3MimeSourceFactory { +public: + const QMimeSource* data(const QString& abs_name) const + { + const QMimeSource* r = 0; + if ( (NetHackMimeSourceFactory *) this + == Q3MimeSourceFactory::defaultFactory() ) + r = Q3MimeSourceFactory::data(abs_name); + else + r = Q3MimeSourceFactory::defaultFactory()->data(abs_name); + if ( !r ) { + int sl = abs_name.length(); + do { + sl = abs_name.lastIndexOf('/',sl-1); + QString name = sl>=0 ? abs_name.mid(sl+1) : abs_name; + int dot = name.lastIndexOf('.'); + if ( dot >= 0 ) + name = name.left(dot); + if ( name == "map" ) + r = new Q3ImageDrag(QImage(map_xpm)); + else if ( name == "msg" ) + r = new Q3ImageDrag(QImage(msg_xpm)); + else if ( name == "stat" ) + r = new Q3ImageDrag(QImage(stat_xpm)); + } while (!r && sl>0); + } + return r; + } +}; +#endif + +/* used by doMenuItem() and for the toolbar buttons */ +bool NetHackQtMainWindow::ok_for_command() +{ + /* + * If the core expects text to be entered (perhaps typing in a wish, + * assigning a name to something, or answering a y/n prompt), or a + * map position or a direction is being picked, don't accept commands + * from the toolbar. + * + * FIXME: it would be much better to gray-out inapplicable entries + * when popping up a command menu instead of needing this. + */ + if (::program_state.input_state != commandInp) { + NetHackQtBind::qt_nhbell(); + // possibly call doKeys("\033"); here? + return false; + } + return true; +} + +void NetHackQtMainWindow::doMenuItem(QAction *action) +{ + if (!ok_for_command()) + return; + /* this converts meta characters to '?'; menu processing has been + changed to send multi-character "#abc" instead (already needed + for commands that didn't have either a regular keystroke or a + meta shortcut); it must send just enough to disambiguate from + other extended command names, otherwise the remainder would be + left in the queue for subsequent handling as additional commands */ + doKeys(action->data().toString()); +} + +void NetHackQtMainWindow::doQtSettings(bool) +{ + centerOnMain(qt_settings); + qt_settings->show(); +} + +void NetHackQtMainWindow::doAbout(bool) +{ + QMessageBox::about(this, "About NetHack-Qt", aboutMsg()); +} + +// on OSX, "quit nethack" has been selected in the application menu or +// "Command+Q" has been typed -- user is asking to quit the application; +// unlike with the window's Close button, user has a chance to back out +void NetHackQtMainWindow::doQuit(bool) +{ + // there is a separate Quit-without-saving menu entry in the game menu + // that leads to nethack's "Really quit?" prompt; OSX players can use + // either one, other implementations only have that other one (plus + // nethack's #quit command itself) but this routine is unconditional + // in case someone wants to change that +#ifdef MACOS + QString info = nh_qsprintf("This will end your NetHack session.%s", + !program_state.something_worth_saving ? "" + : "\n(Cancel quitting and use the Save command" + "\nto save your current game.)"); + /* this is similar to closeEvent but the details are different; + first choice (Cancel) is the default action for most arbitrary keys; + the second choice (Quit) is the action for or ; + leaves the popup waiting for some other response; + the & settings for Alt+ shortcuts don't work on OSX */ + int act = QMessageBox::information(this, "NetHack", info, + "&Cancel and return to game", + "&Quit without saving", + 0, 1); + switch (act) { + case 0: + // cancel + break; // return to game + case 1: + // quit -- bypass the prompting preformed by done2() + program_state.stopprint++; + ::done(QUIT); + /*NOTREACHED*/ + break; + } +#endif + return; +} + +#if 0 // RLC this isn't used +void NetHackQtMainWindow::doGuidebook(bool) +{ + QDialog dlg(this); + new QVBoxLayout(&dlg); + Q3TextBrowser browser(&dlg); + NetHackMimeSourceFactory ms; + browser.setMimeSourceFactory(&ms); + browser.setSource(QDir::currentPath()+"/Guidebook.html"); + if ( qt_compact_mode ) + dlg.showMaximized(); + dlg.exec(); +} +#endif + +void NetHackQtMainWindow::doKeys(const char *cmds) +{ + keysink.Put(cmds); + qApp->exit(); +} + +void NetHackQtMainWindow::doKeys(const QString& k) +{ + /* [this should probably be using toLocal8Bit(); + toAscii() is not offered as an alternative...] */ + doKeys(k.toLatin1().constData()); +} + +// queue up the command name for a function, as if user had typed it +void NetHackQtMainWindow::FuncAsCommand(int (*func)(void)) +{ + char cmdbuf[32]; + Strcpy(cmdbuf, "#"); + (void) cmdname_from_func(func, &cmdbuf[1], FALSE); + doKeys(cmdbuf); +} + +void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window) +{ + message=window; + if (!qt_compact_mode) + hsplitter->insertWidget(0, message->Widget()); + ShowIfReady(); +} + +NetHackQtMessageWindow * NetHackQtMainWindow::GetMessageWindow() +{ + return message; +} + +void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow2* window) +{ + + map=window; + if (!qt_compact_mode) + vsplitter->insertWidget(1, map->Widget()); + ShowIfReady(); + connect(map,SIGNAL(resized()),this,SLOT(layout())); +} + +void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window) +{ + status=window; + if (!qt_compact_mode) + hsplitter->insertWidget(2, status->Widget()); + ShowIfReady(); +} + +void NetHackQtMainWindow::RemoveWindow(NetHackQtWindow* window) +{ + if (window==status) { + status=0; + ShowIfReady(); + } else if (window==map) { + map=0; + ShowIfReady(); + } else if (window==message) { + message=0; + ShowIfReady(); + } +} + +void NetHackQtMainWindow::updateInventory() +{ + if (invusage) { + invusage->repaint(); + } +} + +void NetHackQtMainWindow::fadeHighlighting(bool before_key) +{ + if (before_key) { + // status highlighting fades at start of turn + if (status) + status->fadeHighlighting(); + } else { + // message highlighting fades after user has given input + if (message && message->hilit_mesgs()) + message->unhighlight_mesgs(); + } +} + +void NetHackQtMainWindow::layout() +{ +#if 0 + if ( qt_compact_mode ) + return; + if (message && map && status) { + QSize maxs=map->Widget()->maximumSize(); + int maph=std::min(height()*2/3,maxs.height()); + + QWidget* c = centralWidget(); + int h=c->height(); + int toph=h-maph; + int iuw=3*qt_settings->glyphs().width(); + int topw=(c->width()-iuw)/2; + + message->Widget()->setGeometry(0,0,topw,toph); + invusage->setGeometry(topw,0,iuw,toph); + status->Widget()->setGeometry(topw+iuw,0,topw,toph); + map->Widget()->setGeometry(std::max(0,(c->width()-maxs.width())/2), + toph,c->width(),maph); + } +#endif + + if (qt_settings && !qt_compact_mode + && map && message && status && invusage) { + // For the initial PaperDoll sizing, message window + // and/or status window might still be empty; + // widen them before changing PaperDoll to use saved settings. + QList splittersizes = hsplitter->sizes(); +#define MIN_WIN_WIDTH 400 + if (splittersizes[0] < MIN_WIN_WIDTH + || splittersizes[2] < MIN_WIN_WIDTH) { + if (splittersizes[0] < MIN_WIN_WIDTH) + splittersizes[0] = MIN_WIN_WIDTH; +#ifndef ENHANCED_PAPERDOLL + if (splittersizes[1] < 6) // TILEWMIN + splittersizes[1] = 16; // 16x16 +#endif + if (splittersizes[2] < MIN_WIN_WIDTH) + splittersizes[2] = MIN_WIN_WIDTH; + hsplitter->setSizes(splittersizes); + } +#ifdef ENHANCED_PAPERDOLL + // call resizePaperDoll() indirectly... + qt_settings->resizeDoll(); +#endif + // reset widths + int w = width(); /* of main window */ + int d = invusage->width(); + splittersizes[2] = w / 2 - (d * 1 / 4); // status + splittersizes[1] = d; // invusage + splittersizes[0] = w / 2 - (d * 3 / 4); // messages + hsplitter->setSizes(splittersizes); + } +} + +#ifdef DYNAMIC_STATUSLINES +// called when 'statuslines' changes from 2 to 3 or vice versa; simpler to +// destroy and recreate the status window than to adjust existing fields +NetHackQtWindow *NetHackQtMainWindow::redoStatus() +{ + NetHackQtStatusWindow *oldstatus = this->status; + if (!oldstatus) + return NULL; // not ready yet? + this->status = new NetHackQtStatusWindow; + + if (!qt_compact_mode) + hsplitter->replaceWidget(2, this->status->Widget()); + + delete oldstatus; + ShowIfReady(); + + return (NetHackQtWindow *) this->status; +} +#endif + +void NetHackQtMainWindow::resizePaperDoll(bool showdoll) +{ +#ifdef ENHANCED_PAPERDOLL + // this is absurd... + NetHackQtInvUsageWindow *w = static_cast + (NetHackQtBind::mainWidget())->invusage; + QList hsplittersizes = hsplitter->sizes(), + vsplittersizes = vsplitter->sizes(); + w->resize(w->sizeHint()); + + int oldwidth = hsplittersizes[1], + newwidth = w->width(); + if (newwidth != oldwidth) { + if (oldwidth > newwidth) + hsplittersizes[0] += (oldwidth - newwidth); + else + hsplittersizes[2] += (newwidth - oldwidth); + hsplittersizes[1] = newwidth; + hsplitter->setSizes(hsplittersizes); + } + + // Height limit is 48+2 pixels per doll cell plus 1 pixel margin at top; + // values greater than 44+2 need taller window which pushes the map down + // (when font size 'Large' is used for messages and status; threshold + // may vary by 1 or 2 for other sizes). + // FIXME: this doesn't shrink the window back if size is reduced from 45+ + int oldheight = vsplittersizes[0], + newheight = w->height(); + if (newheight > oldheight && oldheight > 0 && vsplittersizes[1] > 0) { + vsplittersizes[0] = newheight; + vsplitter->setSizes(vsplittersizes); + } + + if (showdoll) { + if (w->isHidden()) + w->show(); + else + w->repaint(); + } else { + if (w->isVisible()) + w->hide(); + } +#else + nhUse(showdoll); +#endif /* ENHANCED_PAPERDOLL */ +} + +void NetHackQtMainWindow::resizeEvent(QResizeEvent*) +{ + layout(); +#ifdef KDE + updateRects(); +#endif +} + +void NetHackQtMainWindow::keyReleaseEvent(QKeyEvent* event) +{ + if ( dirkey ) { + doKeys(QString(QChar(dirkey))); + if ( !event->isAutoRepeat() ) + dirkey = 0; + } +} + +void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event) +{ + // Global key controls + + // For desktop, arrow keys scroll map, since we don't want players + // to think that's the way to move. For handhelds, the normal way is to + // click-to-travel, so we allow the cursor keys for fine movements. + + // 321 + // 4 0 + // 567 + + if ( event->isAutoRepeat() && + event->key() >= Qt::Key_Left && event->key() <= Qt::Key_Down ) + return; + + const char* d = gc.Cmd.dirchars; + switch (event->key()) { + case Qt::Key_Up: + if ( dirkey == d[0] ) + dirkey = d[1]; + else if ( dirkey == d[4] ) + dirkey = d[3]; + else + dirkey = d[2]; + break; + case Qt::Key_Down: + if ( dirkey == d[0] ) + dirkey = d[7]; + else if ( dirkey == d[4] ) + dirkey = d[5]; + else + dirkey = d[6]; + break; + case Qt::Key_Left: + if ( dirkey == d[2] ) + dirkey = d[1]; + else if ( dirkey == d[6] ) + dirkey = d[7]; + else + dirkey = d[0]; + break; + case Qt::Key_Right: + if ( dirkey == d[2] ) + dirkey = d[3]; + else if ( dirkey == d[6] ) + dirkey = d[5]; + else + dirkey = d[4]; + break; + case Qt::Key_PageUp: + dirkey = 0; + if (message) message->Scroll(0,-1); + break; + case Qt::Key_PageDown: + dirkey = 0; + if (message) message->Scroll(0,+1); + break; + case Qt::Key_Space: + //if (flags.rest_on_space) { + event->ignore(); // punt to NetHackQtBind::notify() + return; + //} + case Qt::Key_Enter: + if ( map ) + map->clickCursor(); + break; + default: + dirkey = 0; + event->ignore(); + break; + } +} + +// game window's Close button has been activated +void NetHackQtMainWindow::closeEvent(QCloseEvent *e UNUSED) +{ + int ok = 0; + if ( program_state.something_worth_saving ) { + /* this used to offer "Save" and "Cancel" + but cancel (ignoring the close attempt) won't work + if user has clicked on the window's Close button */ + int act = QMessageBox::information(this, "NetHack", + "This will end your NetHack session.", + "&Save and exit", "&Quit without saving", 0, 1); + switch (act) { + case 0: + // save portion of save-and-exit + ok = dosave0(); + break; + case 1: + // quit -- bypass the prompting preformed by done2() + ok = 1; + program_state.stopprint++; + ::done(QUIT); + /*NOTREACHED*/ + break; + } + } else { + /* nothing worth saving; just close/quit */ + ok = 1; + } + /* if !ok, we should try to continue, but we don't... */ + nhUse(ok); + u.uhp = -1; + NetHackQtBind::qt_exit_nhwindows(0); + nh_terminate(EXIT_SUCCESS); +} + +void NetHackQtMainWindow::ShowIfReady() +{ + if (message && map && status) { + QWidget* hp = qt_compact_mode ? static_cast(stack) + : static_cast(hsplitter); + QWidget* vp = qt_compact_mode ? static_cast(stack) + : static_cast(vsplitter); + message->Widget()->setParent(hp); + map->Widget()->setParent(vp); + status->Widget()->setParent(hp); + if ( qt_compact_mode ) { + message->setMap(map); + stack->addWidget(map->Widget()); + stack->addWidget(message->Widget()); + stack->addWidget(status->Widget()); + raiseMap(); + } else { + layout(); + } + showNormal(); + } else if (isVisible()) { + hide(); + } +} + +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4main.h b/win/Qt/qt_main.h similarity index 64% rename from win/Qt4/qt4main.h rename to win/Qt/qt_main.h index a3ec15ac2..3aa5de79c 100644 --- a/win/Qt4/qt4main.h +++ b/win/Qt/qt_main.h @@ -2,7 +2,7 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4main.h -- the main window +// qt_main.h -- the main window #ifndef QT4MAIN_H #define QT4MAIN_H @@ -11,10 +11,22 @@ #include #include #else -#include "qt4kde0.h" +#include "qt_kde0.h" #endif -namespace nethack_qt4 { +// Allow changing 'statuslines:2' to 'statuslines:3' or vice versa +// while the game is running; deletes and re-creates the status window. +// [Used in qt_bind.cpp and qt_main.cpp, but not referenced in qt_stat.cpp.] +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) +#define DYNAMIC_STATUSLINES +#endif + +// NetHackQtBind::notify() doesn't see ^V on OSX +#ifdef MACOS +#define CTRL_V_HACK +#endif + +namespace nethack_qt_ { class NetHackQtInvUsageWindow; class NetHackQtKeyBuffer; @@ -47,13 +59,23 @@ class NetHackQtMainWindow : public KTopLevelWidget { void RemoveWindow(NetHackQtWindow* window); void updateInventory(); - void fadeHighlighting(); + void fadeHighlighting(bool before_key); + + void FuncAsCommand(int (*func)(void)); + // this is unconditional in case qt_main.h comes before qt_set.h + void resizePaperDoll(bool); // ENHANCED_PAPERDOLL +#ifdef DYNAMIC_STATUSLINES + // called when 'statuslines' option has been changed + NetHackQtWindow *redoStatus(); +#endif public slots: void doMenuItem(QAction *); void doQtSettings(bool); void doAbout(bool); + void doQuit(bool); //RLC void doGuidebook(bool); + void doKeys(const char *); void doKeys(const QString&); protected: @@ -68,9 +90,15 @@ private slots: void zoomMap(); void raiseMessages(); void raiseStatus(); +#ifdef CTRL_V_HACK + void CtrlV(); +#endif private: void ShowIfReady(); + void AddToolButton(QToolBar *toolbar, QSignalMapper *sm, + const char *name, int (*func)(void), QPixmap xpm); + static bool ok_for_command(); #ifdef KDE KMenuBar* menubar; @@ -90,6 +118,6 @@ private slots: int dirkey; }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_map.cpp b/win/Qt/qt_map.cpp new file mode 100644 index 000000000..85817dabf --- /dev/null +++ b/win/Qt/qt_map.cpp @@ -0,0 +1,1066 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_map.cpp -- the map window + +extern "C" { +#include "hack.h" + +extern glyph_map glyphmap[MAX_GLYPH]; /* from tile.c */ +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_map.h" +#include "qt_map.moc" +#include "qt_click.h" +#include "qt_glyph.h" +#include "qt_set.h" +#include "qt_str.h" + +// pet- and pile-mark xpm arrays moved out of qt_xpms.h so that we don't +// include it here anymore; including that header in two files resulted in +// two copies of all the static xpm data and all the rest is for qt_stat.cpp +// +/* XPM */ +static const char *pet_mark_xpm[] = { +/* width height ncolors chars_per_pixel */ +"8 7 2 1", +/* colors */ +". c None", +" c #FF0000", +/* pixels */ +"........", +".. . .", +". ", +". ", +".. .", +"... ..", +".... ..." +}; +/* XPM */ +static const char *pet_mark_small_xpm[] = { +/* width height ncolors chars_per_pixel */ +"5 5 2 1", +/* colors */ +". c None", +"X c #FF0000", +/* pixels */ +".X.X.", +"XXXXX", +".XXX.", +"..X.." +}; +/* XPM */ +static const char *pile_mark_xpm[] = { +/* width height ncolors chars_per_pixel */ +"5 5 2 1", +/* colors */ +". c None", +"X c #00FF00", +/* pixels */ +"..X..", +"..X..", +"XXXXX", +"..X..", +"..X.." +}; + +// temporary +extern int qt_compact_mode; +// end temporary + +namespace nethack_qt_ { + + +NetHackQtMapViewport::NetHackQtMapViewport(NetHackQtClickBuffer& click_sink) : + QWidget(NULL), + rogue_font(NULL), + clicksink(click_sink), + change(10) +{ + pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm + : pet_mark_xpm); + pile_annotation = QPixmap(pile_mark_xpm); + + Clear(); // initializes glyph[][], glyphttychar, glyphcolor, glyphflags + cursor.setX(0); + cursor.setY(0); +} + +NetHackQtMapViewport::~NetHackQtMapViewport(void) +{ + delete rogue_font; //rogue_font = NULL; +} + +// pick a font to use for text map; rogue level is always displayed as text +void NetHackQtMapViewport::SetupTextmapFont(QPainter &painter) +{ + QString fontfamily = iflags.wc_font_map ? iflags.wc_font_map + : "Monospace"; + int maybebold = QFont::Normal; + if (fontfamily.right(5).toLower() == "-bold") { + fontfamily.truncate(fontfamily.length() - 5); + maybebold = QFont::Bold; + } + // Find font... + int pts = 5; + while (pts < 32) { + QFont f(fontfamily, pts, maybebold); + painter.setFont(QFont(fontfamily, pts)); + QFontMetrics fm = painter.fontMetrics(); + if (fm.QFM_WIDTH("M") > qt_settings->glyphs().width()) + break; + if (fm.height() > qt_settings->glyphs().height()) + break; + pts++; + } + rogue_font = new QFont(fontfamily, pts - 1); +} + +void NetHackQtMapViewport::paintEvent(QPaintEvent* event) +{ + NetHackQtGlyphs &glyphs = qt_settings->glyphs(); + int gW = glyphs.width(), + gH = glyphs.height(); + QRect area = event->rect(); + QRect garea; + garea.setCoords(std::max(0, area.left() / gW), + std::max(0, area.top() / gH), + std::min(COLNO - 1, area.right() / gW), + std::min(ROWNO - 1, area.bottom() / gH)); + + QPainter painter; + painter.begin(this); + + unsigned special, tileidx; + uint32 color; + uint32 framecolor; + + if (Is_rogue_level(&u.uz) || iflags.wc_ascii_map) { + // You enter a VERY primitive world! + + painter.setClipRect( event->rect() ); // (normally we don't clip) + painter.fillRect( event->rect(), Qt::black ); + + if (!rogue_font) + SetupTextmapFont(painter); + painter.setFont(*rogue_font); + + for (int j = garea.top(); j <= garea.bottom(); j++) { + for (int i = garea.left(); i <= garea.right(); i++) { + char32_t ch = Glyphttychar(i, j); + + special = Glyphflags(i, j); + if (SYMHANDLING(H_IBM)) { + ch = cp437(ch); + } + color = Glyphcolor(i, j); + painter.setPen(NetHackQtBind::nhcolor_to_pen(color)); + if (!DrawWalls(painter, i * gW, j * gH, gW, gH, ch)) { + ushort utf16[3]; + if (ch < 0x10000) { + utf16[0] = static_cast(ch); + utf16[1] = 0; + } else { + utf16[0] = static_cast((ch >> 10) + 0xD7C0); + utf16[1] = static_cast((ch & 0x3FF) + 0xDC00); + utf16[2] = 0; + } + painter.drawText(i * gW, j * gH, gW, gH, Qt::AlignCenter, + QString::fromUtf16(utf16)); + } + if ((special & MG_PET) != 0 && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i * gW, j * gH), + pet_annotation); + } else if ((special & MG_OBJPILE) != 0 + && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i * gW, j * gH), + pile_annotation); + } + framecolor = GlyphFramecolor(i, j); + if (framecolor != NO_COLOR) { + painter.setPen(NetHackQtBind::nhcolor_to_pen(framecolor)); + painter.drawRect(i * qt_settings->glyphs().width(), + j * qt_settings->glyphs().height(), + qt_settings->glyphs().width() - 1, + qt_settings->glyphs().height() - 1); + } + } + } + + painter.setFont(font()); + } else { // tiles + for (int j = garea.top(); j <= garea.bottom(); j++) { + for (int i = garea.left(); i <= garea.right(); i++) { + unsigned short g = Glyph(i, j); + + special = Glyphflags(i, j); + tileidx = Glyphtileidx(i, j); + glyphs.drawCell(painter, g, tileidx, i, j); + + if ((special & MG_PET) != 0 && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i * gW, j * gH), + pet_annotation); + } else if ((special & MG_OBJPILE) != 0 + && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i * gW, j * gH), + pile_annotation); + } + framecolor = GlyphFramecolor(i, j); + if (framecolor != NO_COLOR) { + painter.setPen(NetHackQtBind::nhcolor_to_pen(framecolor)); + painter.drawRect(i * qt_settings->glyphs().width(), + j * qt_settings->glyphs().height(), + qt_settings->glyphs().width() - 1, + qt_settings->glyphs().height() - 1); + } + } + } + } + + if (garea.contains(cursor)) { + if (Is_rogue_level(&u.uz)) { + painter.setPen( Qt::white ); + } else { + int hp = !Upolyd ? u.uhp : u.mh, + hpmax = !Upolyd ? u.uhpmax : u.mhmax, + hp100 = hpmax ? (hp * 100 / hpmax) : 100; + + // this uses a different color scheme from hitpoint bar but has + // the same cutoff thresholds (except for lack of separate 100%) + if (hp100 < 10 || hp < 5) + painter.setPen(Qt::magenta); + else if (hp100 < 25 || hp < 10 ) + painter.setPen(Qt::red); + else if (hp100 < 50) + painter.setPen(QColor(0xff, 0xbf, 0x00)); // orange + else if (hp100 < 75) + painter.setPen(Qt::yellow); + else + painter.setPen(Qt::white); + } + + painter.drawRect(cursor.x() * gW, cursor.y() * gH, gW - 1, gH - 1); + } + +#if 0 + if (area.intersects(messages_rect)) { + painter.setPen(Qt::black); + painter.drawText(viewport.contentsX() + 1, viewport.contentsY() + 1, + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), messages); + painter.setPen(Qt::white); + painter.drawText(viewport.contentsX(), viewport.contentsY(), + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), messages); + } +#endif + + painter.end(); +} + +bool NetHackQtMapViewport::DrawWalls(QPainter& painter, int x, int y, + int w, int h, unsigned short ch) +{ + enum wallbits { + w_left = 0x01, + w_right = 0x02, + w_up = 0x04, + w_down = 0x08, + w_sq_top = 0x10, + w_sq_bottom = 0x20, + w_sq_left = 0x40, + w_sq_right = 0x80 + }; + unsigned linewidth; + unsigned walls; + int x1, y1, x2, y2, x3, y3; + + linewidth = ((w < h) ? w : h) / 8; + if (linewidth == 0) + linewidth = 1; + + // Single walls + walls = 0; + switch (ch) { + case 0x2500: // box drawings light horizontal + walls = w_left | w_right; + break; + case 0x2502: // box drawings light vertical + walls = w_up | w_down; + break; + case 0x250C: // box drawings light down and right + walls = w_down | w_right; + break; + case 0x2510: // box drawings light down and left + walls = w_down | w_left; + break; + case 0x2514: // box drawings light up and right + walls = w_up | w_right; + break; + case 0x2518: // box drawings light up and left + walls = w_up | w_left; + break; + case 0x251C: // box drawings light vertical and right + walls = w_up | w_down | w_right; + break; + case 0x2524: // box drawings light vertical and left + walls = w_up | w_down | w_left; + break; + case 0x252C: // box drawings light down and horizontal + walls = w_down | w_left | w_right; + break; + case 0x2534: // box drawings light up and horizontal + walls = w_up | w_left | w_right; + break; + case 0x253C: // box drawings light vertical and horizontal + walls = w_up | w_down | w_left | w_right; + break; + } + + if (walls != 0) { + x1 = x + w / 2; + switch (walls & (w_up | w_down)) { + case w_up: + painter.drawLine(x1, y, x1, y + h / 2); + break; + case w_down: + painter.drawLine(x1, y + h / 2, x1, y + h - 1); + break; + case w_up | w_down: + painter.drawLine(x1, y, x1, y + h - 1); + break; + } + + y1 = y + h / 2; + switch (walls & (w_left | w_right)) { + case w_left: + painter.drawLine(x, y1, x + w / 2, y1); + break; + case w_right: + painter.drawLine(x + w / 2, y1, x + w - 1, y1); + break; + case w_left | w_right: + painter.drawLine(x, y1, x + w - 1, y1); + break; + } + + return true; + } + + // Double walls + walls = 0; + switch (ch) { + case 0x2550: // box drawings double horizontal + walls = w_left | w_right | w_sq_top | w_sq_bottom; + break; + case 0x2551: // box drawings double vertical + walls = w_up | w_down | w_sq_left | w_sq_right; + break; + case 0x2554: // box drawings double down and right + walls = w_down | w_right | w_sq_top | w_sq_left; + break; + case 0x2557: // box drawings double down and left + walls = w_down | w_left | w_sq_top | w_sq_right; + break; + case 0x255A: // box drawings double up and right + walls = w_up | w_right | w_sq_bottom | w_sq_left; + break; + case 0x255D: // box drawings double up and left + walls = w_up | w_left | w_sq_bottom | w_sq_right; + break; + case 0x2560: // box drawings double vertical and right + walls = w_up | w_down | w_right | w_sq_left; + break; + case 0x2563: // box drawings double vertical and left + walls = w_up | w_down | w_left | w_sq_right; + break; + case 0x2566: // box drawings double down and horizontal + walls = w_down | w_left | w_right | w_sq_top; + break; + case 0x2569: // box drawings double up and horizontal + walls = w_up | w_left | w_right | w_sq_bottom; + break; + case 0x256C: // box drawings double vertical and horizontal + walls = w_up | w_down | w_left | w_right; + break; + } + + if (walls != 0) { + x1 = x + w / 2 - linewidth; + x2 = x + w / 2 + linewidth; + x3 = x + w - 1; + y1 = y + h / 2 - linewidth; + y2 = y + h / 2 + linewidth; + y3 = y + h - 1; + if (walls & w_up) { + painter.drawLine(x1, y, x1, y1); + painter.drawLine(x2, y, x2, y1); + } + if (walls & w_down) { + painter.drawLine(x1, y2, x1, y3); + painter.drawLine(x2, y2, x2, y3); + } + if (walls & w_left) { + painter.drawLine(x, y1, x1, y1); + painter.drawLine(x, y2, x1, y2); + } + if (walls & w_right) { + painter.drawLine(x2, y1, x3, y1); + painter.drawLine(x2, y2, x3, y2); + } + if (walls & w_sq_top) { + painter.drawLine(x1, y1, x2, y1); + } + if (walls & w_sq_bottom) { + painter.drawLine(x1, y2, x2, y2); + } + if (walls & w_sq_left) { + painter.drawLine(x1, y1, x1, y2); + } + if (walls & w_sq_right) { + painter.drawLine(x2, y1, x2, y2); + } + + return true; + } + + // Solid blocks + if (0x2591 <= ch && ch <= 0x2593) { + unsigned shade = ch - 0x2590; + QColor rgb(painter.pen().color()); + QColor rgb2(rgb.red() * shade / 4, + rgb.green() * shade / 4, + rgb.blue() * shade / 4); + painter.fillRect(x, y, w, h, rgb2); + return true; + } + + return false; +} + +void NetHackQtMapViewport::mousePressEvent(QMouseEvent* event) +{ + clicksink.Put(event->pos().x() / qt_settings->glyphs().width(), + event->pos().y() / qt_settings->glyphs().height(), + (event->button() == Qt::LeftButton) ? CLICK_1 : CLICK_2); + qApp->exit(); +} + +void NetHackQtMapViewport::updateTiles() +{ + change.clear(); + change.add(0, 0, COLNO, ROWNO); + delete rogue_font; rogue_font = NULL; +} + +QSize NetHackQtMapViewport::sizeHint() const +{ + return QSize(qt_settings->glyphs().width() * COLNO, + qt_settings->glyphs().height() * ROWNO); +} + +QSize NetHackQtMapViewport::minimumSizeHint() const +{ + return sizeHint(); +} + +void NetHackQtMapViewport::clickCursor() +{ + clicksink.Put(cursor.x(), cursor.y(), CLICK_1); + qApp->exit(); +} + +// [re-]init map display to unexplored with no changed cells +void NetHackQtMapViewport::Clear() +{ + for (int j = 0; j < ROWNO; ++j) { + // + // FIXME: map column 0 should be suppressed from being displayed + // + Glyph(0, j) = GLYPH_NOTHING; + Glyphttychar(0, j) = ' '; + Glyphcolor(0, j) = NO_COLOR; + GlyphFramecolor(0, j) = NO_COLOR; + Glyphflags(0, j) = 0U; + Glyphtileidx(0, j) = ::glyphmap[GLYPH_NOTHING].tileidx; + + for (int i = 1; i < COLNO; ++i) { + Glyph(i, j) = GLYPH_UNEXPLORED; + Glyphttychar(i, j) = ' '; + Glyphcolor(i, j) = NO_COLOR; + GlyphFramecolor(i, j) = NO_COLOR; + Glyphflags(i, j) = 0U; + Glyphtileidx(i, j) = ::glyphmap[GLYPH_UNEXPLORED].tileidx; + } + } + + change.clear(); + change.add(0, 0, COLNO, ROWNO); +} + +void NetHackQtMapViewport::Display(bool block) +{ + int gW = qt_settings->glyphs().width(), + gH = qt_settings->glyphs().height(); + + for (int i = 0; i < change.clusters(); i++) { + const QRect& chg = change[i]; + repaint(chg.x() * gW, chg.y() * gH, + chg.width() * gW, chg.height() * gH); + } + change.clear(); + + if (block) { + yn_function("Press a key when done viewing", NULL, '\0', TRUE); + } +} + +void NetHackQtMapViewport::CursorTo(int x,int y) +{ + Changed(cursor.x(), cursor.y()); + cursor.setX(x); + cursor.setY(y); + Changed(cursor.x(), cursor.y()); +} + +void NetHackQtMapViewport::PrintGlyph(int x, int y, + const glyph_info *glyphinfo, + const glyph_info *bkglyphinfo) +{ + Glyph(x, y) = (unsigned short) glyphinfo->glyph; + Glyphttychar(x, y) = (char32_t) glyphinfo->ttychar; + Glyphcolor(x, y) = (uint32) glyphinfo->gm.sym.color; + GlyphFramecolor(x, y) = (uint32) bkglyphinfo->framecolor; +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8) && glyphinfo->gm.u && glyphinfo->gm.u->utf8str) { + Glyphttychar(x, y) = glyphinfo->gm.u->utf32ch; + } +#endif + if (glyphinfo->gm.customcolor != 0) { + uint32 nhcolor = COLORVAL(glyphinfo->gm.customcolor); + if (glyphinfo->gm.customcolor == nhcolor) { + /* 24-bit color */ + Glyphcolor(x, y) = COLORVAL(glyphinfo->gm.customcolor) | 0x80000000; + } else { + /* NH_BASIC_COLOR */ + Glyphcolor(x, y) = COLORVAL(glyphinfo->gm.customcolor); + } + } + Glyphflags(x, y) = glyphinfo->gm.glyphflags; + Glyphtileidx(x, y) = (unsigned short) glyphinfo->gm.tileidx; + Changed(x, y); +} + +void NetHackQtMapViewport::Changed(int x, int y) +{ + change.add(x, y); +} + +NetHackQtMapWindow2::NetHackQtMapWindow2(NetHackQtClickBuffer& click_sink) : + QScrollArea(NULL), + m_viewport(new NetHackQtMapViewport(click_sink)) +{ + QPalette palette; + palette.setColor(backgroundRole(), Qt::black); + setPalette(palette); + + setWidget(m_viewport); + + connect(qt_settings, SIGNAL(tilesChanged()), this, SLOT(updateTiles())); + updateTiles(); +} + +void NetHackQtMapWindow2::updateTiles() +{ + NetHackQtGlyphs& glyphs = qt_settings->glyphs(); + int gW = glyphs.width(); + int gH = glyphs.height(); + // Be exactly the size we want to be - full map... + m_viewport->resize(COLNO * gW, ROWNO * gH); + + verticalScrollBar()->setSingleStep(gH); + verticalScrollBar()->setPageStep(gH); + horizontalScrollBar()->setSingleStep(gW); + horizontalScrollBar()->setPageStep(gW); + + m_viewport->updateTiles(); + Display(false); + + emit resized(); +} + +void NetHackQtMapWindow2::clearMessages() +{ + messages = ""; + update(messages_rect); + messages_rect = QRect(); +} + +void NetHackQtMapWindow2::putMessage(int attr UNUSED, const QString& text) +{ + if (!messages.isEmpty()) + messages += "\n"; + messages += QString(text).replace(QChar(0x200B), ""); +#if 0 + QFontMetrics fm = fontMetrics(); + messages_rect = fm.boundingRect(viewport.contentsX(), viewport.contentsY(), + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), + messages); + update(messages_rect); +#endif +} + +void NetHackQtMapWindow2::clickCursor() +{ + m_viewport->clickCursor(); +} + +QWidget *NetHackQtMapWindow2::Widget() +{ + return this; +} + +void NetHackQtMapWindow2::Clear() +{ + m_viewport->Clear(); +} + +void NetHackQtMapWindow2::Display(bool block) +{ + m_viewport->Display(block); +} + +void NetHackQtMapWindow2::CursorTo(int x,int y) +{ + m_viewport->CursorTo(x, y); +} + +void NetHackQtMapWindow2::PutStr(int attr UNUSED, const QString& text UNUSED) +{ + puts("unexpected PutStr in MapWindow"); +} + +void NetHackQtMapWindow2::ClipAround(int x,int y) +{ + // Convert to pixel of center of tile + x=x*qt_settings->glyphs().width()+qt_settings->glyphs().width()/2; + y=y*qt_settings->glyphs().height()+qt_settings->glyphs().height()/2; + + // Then ensure that pixel is visible + ensureVisible(x,y,width()*0.45,height()*0.45); +} + +void NetHackQtMapWindow2::PrintGlyph(int x,int y, + const glyph_info *glyphinfo, + const glyph_info *bkglyphinfo) +{ + m_viewport->PrintGlyph(x, y, glyphinfo, bkglyphinfo); +} + +#if 0 //RLC +// XXX Hmmm... crash after saving bones file if Map window is +// XXX deleted. Strange bug somewhere. +bool NetHackQtMapWindow::Destroy() { return false; } + +NetHackQtMapWindow::NetHackQtMapWindow(NetHackQtClickBuffer& click_sink) : + clicksink(click_sink), + change(10), + rogue_font(0) +{ + viewport.addChild(this); + + QPalette palette; + palette.setColor(backgroundRole(), Qt::black); + setPalette(palette); + palette.setColor(viewport.backgroundRole(), Qt::black); + viewport.setPalette(palette); + + pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm + : pet_mark_xpm); + pile_annotation = QPixmap(pile_mark_xpm); + + cursor.setX(0); + cursor.setY(0); + Clear(); + + connect(qt_settings,SIGNAL(tilesChanged()),this,SLOT(updateTiles())); + connect(&viewport, SIGNAL(contentsMoving(int,int)), this, + SLOT(moveMessages(int,int))); + + updateTiles(); + //setFocusPolicy(Qt::StrongFocus); +} + +void NetHackQtMapWindow::moveMessages(int x, int y) +{ + QRect u = messages_rect; + messages_rect.moveTopLeft(QPoint(x,y)); + u |= messages_rect; + update(u); +} + +void NetHackQtMapWindow::clearMessages() +{ + messages = ""; + update(messages_rect); + messages_rect = QRect(); +} + +void NetHackQtMapWindow::putMessage(int attr, const QString& text) +{ + if ( !messages.isEmpty() ) + messages += "\n"; + messages += QString(text).replace(QChar(0x200B), ""); + QFontMetrics fm = fontMetrics(); + messages_rect = fm.boundingRect(viewport.contentsX(), viewport.contentsY(), + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), + messages); + update(messages_rect); +} + +void NetHackQtMapWindow::updateTiles() +{ + NetHackQtGlyphs& glyphs = qt_settings->glyphs(); + int gw = glyphs.width(); + int gh = glyphs.height(); + // Be exactly the size we want to be - full map... + resize(COLNO*gw,ROWNO*gh); + + viewport.verticalScrollBar()->setSingleStep(gh); + viewport.verticalScrollBar()->setPageStep(gh); + viewport.horizontalScrollBar()->setSingleStep(gw); + viewport.horizontalScrollBar()->setPageStep(gw); + /* + viewport.setMaximumSize( + gw*COLNO + viewport.verticalScrollBar()->width(), + gh*ROWNO + viewport.horizontalScrollBar()->height() + ); + */ + viewport.updateScrollBars(); + + change.clear(); + change.add(0,0,COLNO,ROWNO); + delete rogue_font; rogue_font = 0; + Display(false); + + emit resized(); +} + +NetHackQtMapWindow::~NetHackQtMapWindow() +{ + // Remove from viewport porthole, since that is a destructible member. + viewport.removeChild(this); + setParent(0,0); +} + +QWidget* NetHackQtMapWindow::Widget() +{ + return &viewport; +} + +void NetHackQtMapWindow::Scroll(int dx, int dy) +{ + if (viewport.horizontalScrollBar()->isVisible()) { + while (dx<0) { viewport.horizontalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub); dx++; } + while (dx>0) { viewport.horizontalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd); dx--; } + } + if (viewport.verticalScrollBar()->isVisible()) { + while (dy<0) { viewport.verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub); dy++; } + while (dy>0) { viewport.verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd); dy--; } + } +} + +void NetHackQtMapWindow::Clear() +{ + for (int j = 0; j < ROWNO; ++j) { + Glyph(0, j) = GLYPH_NOTHING; + Glyphcolor(0, j) = NO_COLOR; + GlyphFramecolor(0, j) = NO_COLOR; + Glyphttychar(0, j) = ' '; + Glyphflags(0, j) = 0; + Glyphtileidx(0, j) = ::glyphmap[GLYPH_NOTHING].tileidx; + + for (int i = 1; i < COLNO; ++i) { + Glyph(i, j) = GLYPH_UNEXPLORED; + Glyphcolor(i, j) = NO_COLOR; + GlyphFramecolor(i, j) = NO_COLOR; + Glyphttychar(i, j) = ' '; + Glyphflags(i, j) = 0; + Glyphtileidx(i, j) = ::glyphmap[GLYPH_UNEXPLORED].tileidx; + } + } + + change.clear(); + change.add(0,0,COLNO,ROWNO); +} + +void NetHackQtMapWindow::clickCursor() +{ + clicksink.Put(cursor.x(),cursor.y(),CLICK_1); + qApp->exit(); +} + +void NetHackQtMapWindow::mousePressEvent(QMouseEvent* event) +{ + clicksink.Put( + event->pos().x()/qt_settings->glyphs().width(), + event->pos().y()/qt_settings->glyphs().height(), + event->button()==Qt::LeftButton ? CLICK_1 : CLICK_2 + ); + qApp->exit(); +} + +void NetHackQtMapWindow::paintEvent(QPaintEvent* event) +{ + QRect area=event->rect(); + QRect garea; + garea.setCoords( + std::max(0,area.left()/qt_settings->glyphs().width()), + std::max(0,area.top()/qt_settings->glyphs().height()), + std::min(COLNO-1,area.right()/qt_settings->glyphs().width()), + std::min(ROWNO-1,area.bottom()/qt_settings->glyphs().height()) + ); + + QPainter painter; + + painter.begin(this); + + if (is_rogue_level(&u.uz) || iflags.wc_ascii_map) { + // You enter a VERY primitive world! + + painter.setClipRect( event->rect() ); // (normally we don't clip) + painter.fillRect( event->rect(), Qt::black ); + + if ( !rogue_font ) { + // Find font... + int pts = 5; + QString fontfamily = iflags.wc_font_map + ? iflags.wc_font_map : "Courier"; + bool bold = false; + if ( fontfamily.right(5).toLower() == "-bold" ) { + fontfamily.truncate(fontfamily.length()-5); + bold = true; + } + while ( pts < 32 ) { + QFont f(fontfamily, pts, bold ? QFont::Bold : QFont::Normal); + painter.setFont(QFont(fontfamily, pts)); + QFontMetrics fm = painter.fontMetrics(); + if ( fm.width("M") > qt_settings->glyphs().width() ) + break; + if ( fm.height() > qt_settings->glyphs().height() ) + break; + pts++; + } + rogue_font = new QFont(fontfamily,pts-1); + } + painter.setFont(*rogue_font); + + for (int j=garea.top(); j<=garea.bottom(); j++) { + for (int i=garea.left(); i<=garea.right(); i++) { + unsigned short g=Glyph(i,j); + uint32 color = Glyphcolor(i,j); + uint32 framecolor = GlyphFramecolor(i,j); + char32_t ch = Glyphttychar(i,j); + unsigned special = Glyphflags(i,j); + + if (framecolor != NO_COLOR) { + painter.fillRect(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height(), + qt_settings->glyphs().width()-1, + qt_settings->glyphs().height()-1, + nhcolor_to_pen(framecolor).color()); + } + painter.setPen( Qt::green ); + painter.setPen( nhcolor_to_pen(color) ); + painter.drawText( + i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height(), + qt_settings->glyphs().width(), + qt_settings->glyphs().height(), + Qt::AlignCenter, + QString(QChar(ch)).left(1) + ); + if ((special & MG_PET) != 0 && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height()), + pet_annotation); + } else if ((special & MG_OBJPILE) != 0 + && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height()), + pile_annotation); + } + if (framecolor != NO_COLOR) { + painter.setPen( nhcolor_to_pen(framecolor) ); + painter.drawRect(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height(), + qt_settings->glyphs().width()-1, + qt_settings->glyphs().height()-1); + } + } + } + + painter.setFont(font()); + } else { + for (int j=garea.top(); j<=garea.bottom(); j++) { + for (int i=garea.left(); i<=garea.right(); i++) { + unsigned short g=Glyph(i,j); + unsigned special = Glyphflags(i,j); + unsigned short tileidx = Glyphtileidx(i,j); + uint32 framecolor = GlyphFramecolor(i,j); + + qt_settings->glyphs().drawCell(painter, g, tileidx, i, j); + if ((special & MG_PET) != 0 && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height()), + pet_annotation); + } else if ((special & MG_OBJPILE) != 0 + && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height()), + pile_annotation); + } + if (framecolor != NO_COLOR) { + painter.setPen( nhcolor_to_pen(framecolor) ); + painter.drawRect(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height(), + qt_settings->glyphs().width()-1, + qt_settings->glyphs().height()-1); + } + } + } + } + + if (garea.contains(cursor)) { + if (Is_rogue_level(&u.uz)) { + painter.setPen( Qt::white ); + } else { + int hp100; + if (Upolyd) { + hp100=u.mhmax ? u.mh*100/u.mhmax : 100; + } else { + hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100; + } + + if (hp100 > 75) + painter.setPen(Qt::white); + else if (hp100 > 50) + painter.setPen(Qt::yellow); + else if (hp100 > 25) + painter.setPen(QColor(0xff, 0xbf, 0x00)); // orange + else if (hp100 > 10) + painter.setPen(Qt::red); + else + painter.setPen(Qt::magenta); + } + + painter.drawRect(cursor.x() * qt_settings->glyphs().width(), + cursor.y() * qt_settings->glyphs().height(), + qt_settings->glyphs().width() - 1, + qt_settings->glyphs().height() - 1); + } + + if (area.intersects(messages_rect)) { + painter.setPen(Qt::black); + painter.drawText(viewport.contentsX() + 1, viewport.contentsY() + 1, + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), messages); + painter.setPen(Qt::white); + painter.drawText(viewport.contentsX(), viewport.contentsY(), + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), messages); + } + + painter.end(); +} + +void NetHackQtMapWindow::Display(bool block) +{ + for (int i=0; iglyphs().width(), + ch.y()*qt_settings->glyphs().height(), + ch.width()*qt_settings->glyphs().width(), + ch.height()*qt_settings->glyphs().height() + ); + } + + change.clear(); + + if (block) { + yn_function("Press a key when done viewing",0,'\0'); + } +} + +void NetHackQtMapWindow::CursorTo(int x,int y) +{ + Changed(cursor.x(),cursor.y()); + cursor.setX(x); + cursor.setY(y); + Changed(cursor.x(),cursor.y()); +} + +void NetHackQtMapWindow::PutStr(int attr, const QString& text) +{ + puts("unexpected PutStr in MapWindow"); +} + +void NetHackQtMapWindow::ClipAround(int x,int y) +{ + // Convert to pixel of center of tile + x=x*qt_settings->glyphs().width()+qt_settings->glyphs().width()/2; + y=y*qt_settings->glyphs().height()+qt_settings->glyphs().height()/2; + + // Then ensure that pixel is visible + viewport.center(x,y,0.45,0.45); +} + +void NetHackQtMapWindow::PrintGlyph(int x,int y, const glyph_info *glyphinfo) +{ + Glyph(x,y)=glyphinfo->glyph; + Glyphttychar(x,y)=glyphinfo->ttychar; + Glyphcolor(x,y)=glyphinfo->color; + GlyphFramecolor(x,y)=bkglyphinfo->framecolor; +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8) + && glyphinfo->gm.u + && glyphinfo->gm.u->utf8str) { + Glyphttychar(x, y) = glyphinfo->gm.u->utf32ch; + if (glyphinfo->gm.u->ucolor != 0) { + Glyphcolor(x, y) = glyphinfo->gm.u->ucolor | 0x80000000; + } + } +#endif + Glyphflags(x,y)=glyphinfo->glyphflags; + Glyphtileidx(x,y)=glyphinfo->tileidx; + Changed(x,y); +} + +//void NetHackQtMapWindow::PrintGlyphCompose(int x,int y,int glyph1, int glyph2) +//{ + // TODO: composed graphics +//} + +void NetHackQtMapWindow::Changed(int x, int y) +{ + change.add(x,y); +} +#endif /* 0 //RLC */ + +} // namespace nethack_qt_ diff --git a/win/Qt/qt_map.h b/win/Qt/qt_map.h new file mode 100644 index 000000000..321db2541 --- /dev/null +++ b/win/Qt/qt_map.h @@ -0,0 +1,106 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_map.h -- the map window + +#ifndef QT4MAP_H +#define QT4MAP_H + +#include "qt_win.h" +#include "qt_clust.h" + +namespace nethack_qt_ { + +class NetHackQtClickBuffer; + +class NetHackQtMapViewport : public QWidget { + Q_OBJECT +public: + NetHackQtMapViewport(NetHackQtClickBuffer& click_sink); + ~NetHackQtMapViewport(void); + +protected: + virtual void paintEvent(QPaintEvent* event); + bool DrawWalls(QPainter& painter, int x, int y, + int w, int h, unsigned short ch); + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + virtual void mousePressEvent(QMouseEvent* event); + +private: + QFont *rogue_font; + unsigned short glyph[ROWNO][COLNO]; + unsigned short &Glyph(int x, int y) { + return glyph[y][x]; + } + char32_t glyphttychar[ROWNO][COLNO]; + char32_t &Glyphttychar(int x, int y) { + return glyphttychar[y][x]; + } + uint32 glyphcolor[ROWNO][COLNO]; + uint32 &Glyphcolor(int x, int y) { + return glyphcolor[y][x]; + } + uint32 glyphframecolor[ROWNO][COLNO]; + uint32 &GlyphFramecolor(int x, int y) { + return glyphframecolor[y][x]; + } + unsigned int glyphflags[ROWNO][COLNO]; + unsigned int &Glyphflags(int x, int y) { + return glyphflags[y][x]; + } + unsigned short glyphtileidx[ROWNO][COLNO]; + unsigned short &Glyphtileidx(int x, int y) { + return glyphtileidx[y][x]; + } + QPoint cursor; + QPixmap pet_annotation; + QPixmap pile_annotation; + NetHackQtClickBuffer &clicksink; + Clusterizer change; + + void clickCursor(); + void Clear(); + void Display(bool block); + void CursorTo(int x,int y); + void PrintGlyph(int x,int y, const glyph_info *glyphinfo, const glyph_info *bkglyphinfo); + void Changed(int x, int y); + void updateTiles(); + void SetupTextmapFont(QPainter &painter); + + // NetHackQtMapWindow2 passes through many calls to the viewport + friend class NetHackQtMapWindow2; +}; + +class NetHackQtMapWindow2 : public QScrollArea, public NetHackQtWindow { + Q_OBJECT +public: + NetHackQtMapWindow2(NetHackQtClickBuffer& click_sink); + void clearMessages(); + void putMessage(int attr, const QString& text); + void clickCursor(); + virtual QWidget *Widget(); + + virtual void Clear(); + virtual void Display(bool block); + virtual void CursorTo(int x,int y); + virtual void PutStr(int attr, const QString& text); + virtual void ClipAround(int x,int y); + virtual void PrintGlyph(int x,int y, const glyph_info *glyphinfo, const glyph_info *bkglyphinfo); + +signals: + void resized(); + +private slots: + void updateTiles(); + +private: + NetHackQtMapViewport *m_viewport; + QRect messages_rect; + QString messages; +}; + +} // namespace nethack_qt_ + +#endif diff --git a/win/Qt/qt_menu.cpp b/win/Qt/qt_menu.cpp new file mode 100644 index 000000000..f469597e2 --- /dev/null +++ b/win/Qt/qt_menu.cpp @@ -0,0 +1,1318 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_menu.cpp -- a menu or text-list widget + +// +// TODO: +// inventory menus reuse the same menu window over and over (in the core); +// it isn't resizing properly to reflect each new instance's content; +// [temporary 'fix' allocates at least 15 lines in case a really short +// subset is displayed before a full inventory; but all inventory menus +// will be padded to that length when they might otherwise show all the +// entries with less, and inventories which have more will need to be +// scrolled to see the excess even if a taller menu would fit on the +// screen; code now has to distinguish between inventory menu and +// 'other' menu so that the latter isn't padded too] +// implement next_page, prev_page, first_page, and last_page to work +// like they do for X11: scroll menu window as if it were paginated; +// entering a count that uses more digits than the previous biggest count +// widens count field but fails to widen the whole menu so a horizontal +// scrollbar might appear; +// create and use custom check-box icons to visually distinguish +// pre-selected entries and numeric subset entries from ordinary select +// and unselected. +// + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_menu.h" +#include "qt_menu.moc" +#include "qt_key.h" // for keyValue() +#include "qt_glyph.h" +#include "qt_set.h" +#include "qt_streq.h" +#include "qt_str.h" + +// temporary +extern "C" int qt_compact_mode; +// end temporary + +/* for documentation rather than necessity; hack.h -> decl.h declares this */ +extern "C" struct menucoloring *menu_colorings; + +namespace nethack_qt_ { + +// temporary +void centerOnMain( QWidget* w ); +// end temporary + +QSize NetHackQtTextListBox::sizeHint() const +{ + QScrollBar *hscroll = horizontalScrollBar(); + int hsize = hscroll ? hscroll->height() : 0; + return QSize(TotalWidth()+hsize, TotalHeight()+hsize); +} + +int NetHackQtMenuListBox::TotalWidth() const +{ + int width = 0; + + for (int col = 0; col < columnCount(); ++col) { + width += columnWidth(col); + } + return width; +} + +int NetHackQtMenuListBox::TotalHeight() const +{ + int row, rowheight, height = 0; + + for (row = 0; row < rowCount(); ++row) { + height += rowHeight(row); + } + // 20: arbitrary; should always have at least 1 row so it shouldn't matter + rowheight = (row > 0) ? rowHeight(row - 1) : 20; + + // + // FIXME: + // The core reuses one window for inventory displays and this + // part of sizeHint() is working for the initial size but is + // ineffective for later resizes. + // + + // TEMPORARY: + // in case first inventory menu displayed is a short one pad it + // with blank lines so later long ones won't be far too short + if ((dynamic_cast (parent()))->is_invent) { + if (row < 15) + height += (15 - row) * rowheight; + } + + // include extra height so that there will be a blank gap after the + // last entry to show that there is nothing to scroll forward too + height += rowheight / 2; + return height; +} + +QSize NetHackQtMenuListBox::sizeHint() const +{ + QScrollBar *hscroll = horizontalScrollBar(), + *vscroll = verticalScrollBar(); + int hsize = (hscroll && hscroll->isVisible()) ? hscroll->height() : 0, + vsize = (vscroll && vscroll->isVisible()) ? vscroll->width() : 0; + hsize += MENU_WIDTH_SLOP, vsize += MENU_WIDTH_SLOP; + // note: a vertical scrollbar affects widget width, a horizontal one height + return QSize(TotalWidth() + vsize, TotalHeight() + hsize); +} + +// +// FIXME: +// Inventory displays reuse the same menu window and so far this +// is not updating the size as intended. The size of the first +// instance persists. +// + +// resize current menu window and the table (rows of entries) inside it +void NetHackQtMenuWindow::MenuResize() +{ + // when this was just 'adjustSize()', our sizeHints() was not + // being called so explicitly indicate the table widget + table->adjustSize(); + this->adjustSize(); + + // Temporary? workaround for scrolling becoming wedged if using + // all/none/invert removes all counts so we narrow a non-empty + // count column to empty. [That can take away the horizontal + // scroll bar but should not be affecting the vertical one, yet + // is (Qt 5.11.3).] Typing any digit restored normal scrolling + // and the only significant thing about that is that it updates + // the prompt line which is outside the table of menu items where + // scrolling takes place. Oddly, both prompt changes are needed + // (possibly the unnecessary space in the first is being optimized + // away but the second call to remove it isn't aware of that, or + // perhaps the 'fix' only happens when the line gets shorter). + prompt.setText(promptstr + " "); + prompt.setText(promptstr); + // [Later: becoming wedged doesn't just occur after shrinking the + // count column and seems to be triggered by table->adjustSize().] +} + +// Table view columns (0..4): +// +// [pick-count] [check-box] [object-glyph] [selector-letter] [description] +// +// pick-count is normally empty and gets wider as needed. +// +NetHackQtMenuWindow::NetHackQtMenuWindow(QWidget *parent) : + QDialog(parent), + is_invent(false), // reset to True when window is core's WIN_INVEN + table(new NetHackQtMenuListBox()), + prompt(0), + biggestcount(0L), // largest subset amount that user has entered + countdigits(0), // number of digits needed by biggestcount + counting(false), // user has typed a digit and more might follow + searching(false) // user has begun entering a search target string +{ + // setFont() was in SelectMenu(), in time to be rendered but too late + // when measuring the width and height that will be needed + QFont tablefont(qt_settings->normalFixedFont()); + table->setFont(tablefont); + + QGridLayout *grid = new QGridLayout(); + table->setColumnCount(5); +#if __cplusplus >= 202002L + table->setFrameStyle(static_cast(QFrame::Panel) + | static_cast(QFrame::Sunken)); +#else + table->setFrameStyle(QFrame::Panel|QFrame::Sunken); +#endif + table->setLineWidth(2); // note: this is not row spacing + table->setShowGrid(false); + table->horizontalHeader()->hide(); + table->verticalHeader()->hide(); + + ok=new QPushButton("Ok"); + connect(ok,SIGNAL(clicked()),this,SLOT(accept())); + + cancel=new QPushButton("Cancel"); + connect(cancel,SIGNAL(clicked()),this,SLOT(reject())); + + all=new QPushButton("All"); + connect(all,SIGNAL(clicked()),this,SLOT(All())); + + none=new QPushButton("None"); + connect(none,SIGNAL(clicked()),this,SLOT(ChooseNone())); + + invert=new QPushButton("Invert"); + connect(invert,SIGNAL(clicked()),this,SLOT(Invert())); + + search=new QPushButton("Search"); + connect(search,SIGNAL(clicked()),this,SLOT(Search())); + + QPoint pos(0,ok->height()); + move(pos); + prompt.setParent(this); + prompt.move(pos); + + grid->addWidget(ok, 0, 0); + grid->addWidget(cancel, 0, 1); + grid->addWidget(all, 0, 2); + grid->addWidget(none, 0, 3); + grid->addWidget(invert, 0, 4); + grid->addWidget(search, 0, 5); + grid->addWidget(&prompt, 1, 0, 1, 7); + grid->addWidget(table, 2, 0, 1, 7); + grid->setColumnStretch(6, 1); + grid->setRowStretch(2, 1); + setFocusPolicy(Qt::StrongFocus); + table->setFocusPolicy(Qt::NoFocus); + connect(table, SIGNAL(cellClicked(int,int)), + this, SLOT(TableCellClicked(int,int))); + + setLayout(grid); + setModal(true); +} + +NetHackQtMenuWindow::~NetHackQtMenuWindow() +{ +} + +QWidget* NetHackQtMenuWindow::Widget() { return this; } + +// +// Note: inventory menus reuse the same menu window over and over +// so StartMenu(), AddMenu(), EndMenu(), and SelectMenu() +// can't rely on the MenuWindow constructor for initialization. +// + +void NetHackQtMenuWindow::StartMenu(bool using_WIN_INVEN) +{ + itemcount = 0; + table->setRowCount(itemcount); + next_accel = 0; + has_glyphs = false; + biggestcount = 0L; + countdigits = 0; + ClearCount(); // reset 'counting' flag and digit string 'countstr' + ClearSearch(); // reset 'searching' flag + + is_invent = using_WIN_INVEN; +} + +NetHackQtMenuWindow::MenuItem::MenuItem() : + str("") +{ +} + +NetHackQtMenuWindow::MenuItem::~MenuItem() +{ +} + +void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P *identifier, + char ch, char gch, int attr, int clr, + const QString& str, unsigned itemflags) +{ + bool presel = (itemflags & MENU_ITEMFLAGS_SELECTED) != 0; + if (!ch && identifier->a_void!=0) { + // Supply a keyboard accelerator. Limited supply. + static char accel[] + = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (accel[next_accel]) { + ch=accel[next_accel++]; + } + } + + if ((int)itemlist.size() < itemcount+1) { + itemlist.resize(itemcount*4+10); + } + itemlist[itemcount].glyph = glyph; + itemlist[itemcount].identifier = *identifier; + itemlist[itemcount].ch = ch; + itemlist[itemcount].gch = gch; + itemlist[itemcount].attr = attr; + itemlist[itemcount].color = clr; + itemlist[itemcount].str = str; + itemlist[itemcount].selected = itemlist[itemcount].preselected = presel; + itemlist[itemcount].itemflags = itemflags; + itemlist[itemcount].count = -1L; + // Display the boulder symbol correctly + if (str.left(8) == "boulder\t") { + int bracket = str.indexOf('['); + if (bracket != -1) { + itemlist[itemcount].str = str.left(bracket+1) + + QChar(cp437(str.at(bracket+1).unicode())) + + str.mid(bracket+2); + } + } + ++itemcount; + + if (glyph != NO_GLYPH) + has_glyphs = true; +} + +void NetHackQtMenuWindow::EndMenu(const QString& p) +{ + prompt.setText(p); + promptstr = p; +} + +int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list) +{ + table->setRowCount(itemcount); + + how=h; + + int presel_ct = 0; + for (int i = 0; i < itemcount; ++i) + if (itemlist[i].preselected) + ++presel_ct; + bool ok_ok = (how != PICK_ONE || presel_ct == 1); + ok->setEnabled(ok_ok); ok->setDefault(ok_ok); + cancel->setEnabled(true); + all->setEnabled(how == PICK_ANY || (how == PICK_ONE && itemcount == 1)); + none->setEnabled(how == PICK_ANY || (how == PICK_ONE && presel_ct == 1)); + invert->setEnabled(how == PICK_ANY || (how == PICK_ONE && itemcount == 1)); + search->setEnabled(how != PICK_NONE); + + setResult(-1); + + // Set contents of table + QFontMetrics fm(table->font()); + for (int col = 0; col < 5; ++col) { + table->setColumnWidth(col, 0); + } + // default height is way too big; rows end up being double-spaced with it + int rowheight = fm.height() * 3 / 5; + for (int row = 0; row < itemcount; ++row) { + AddRow(row, itemlist[row]); + table->setRowHeight(row, rowheight); + } + PadMenuColumns(::iflags.menu_tab_sep ? true : false); + + MenuResize(); + + //old FIXME: size for compact mode + //resize(this->width(), parent()->height()*7/8); + move(0, 0); + centerOnMain(this); + + exec(); + int result = this->result(); + + *menu_list = (MENU_ITEM_P *) 0; + if (result > 0 && how != PICK_NONE) { + int n = 0; + for (int i = 0; i < itemcount; ++i) + if (itemlist[i].selected) + ++n; + if (n) { + *menu_list = (MENU_ITEM_P *) alloc(n * sizeof(MENU_ITEM_P)); + n = 0; + for (int i = 0; i < itemcount; ++i) { + if (itemlist[i].selected) { + (*menu_list)[n].item = itemlist[i].identifier; + (*menu_list)[n].count = count(i); + ++n; + } + } + } + return n; + } else { + return -1; + } +} + +// pad the menu columns so that they all line up +void NetHackQtMenuWindow::PadMenuColumns(bool split_descr) +{ + QFontMetrics fm(table->font()); + QString col0width_str = ""; + if (biggestcount > 0L) + col0width_str = nh_qsprintf("%*ld", std::max(countdigits, 1), + biggestcount); + int col0width_int = (int) fm.QFM_WIDTH(col0width_str) + MENU_WIDTH_SLOP; + if (col0width_int > table->columnWidth(0)) + WidenColumn(0, col0width_int); + + // If the description (column 4) is a tab separated list, split + // it into fields and figure out how wide each field should be. + // Needs to be done at most once for any given menu instantiation. + std::vector col_widths(1, 0); // start with 1 element init'd to 0 + if (split_descr) { + for (int row = 0; row < itemcount; ++row) { + QTableWidgetItem *twi = table->item(row, 4); // description + if (twi == NULL) + continue; + // if a header/footnote/&c with no sub-fields, don't inflate + // the size of col_widths[0] + if (!itemlist[row].Selectable() + && !itemlist[row].str.contains(QChar('\t'))) + continue; + // determine column widths of sub-fields within description + QStringList columns = itemlist[row].str.split("\t"); + for (int fld = 0; fld < (int) columns.size(); ++fld) { + bool lastcol = (fld == (int) columns.size() - 1); + int w = fm.QFM_WIDTH(columns[fld] + (lastcol ? "" : " ")); + if (fld >= (int) col_widths.size()) { + col_widths.push_back(w); // add another element + } else if (col_widths[fld] < w) { + col_widths[fld] = w; + } + } + } + } // split_descr + + // Reformat all counts so that they line up right justified and + // pad each field within description to fill that field's width. + int widest4 = 0; + for (int row = 0; row < (int) itemlist.size(); ++row) { + // column 0 (subset count); format as right-justified number + QTableWidgetItem *cnt = table->item(row, 0); + if (cnt != NULL) { + QString Amt = ""; + long amt = count(row); // fetch item(row,0) as a number + if (amt > 0L) + Amt = nh_qsprintf("%*ld", countdigits, amt); + cnt->setText(Amt); + } + + // column 4 (item description) + QTableWidgetItem *twi = table->item(row, 4); + if (twi == NULL) + continue; + QString text = twi->text(); + if (split_descr) { + QStringList columns = text.split("\t"); + for (int fld = 0; fld < (int) columns.size() - 1; ++fld) { + //columns[fld] += "\t"; /* (used to pad with tabs) */ + int width = col_widths[fld]; + while (fm.QFM_WIDTH(columns[fld]) < width) + columns[fld] += " "; //"\t"; + } + text = columns.join(""); + twi->setText(text); + } + // TODO? if description needs to wrap, increase the height of this row + int wid = fm.QFM_WIDTH(text) + MENU_WIDTH_SLOP; + if (wid > widest4) + widest4 = wid; + } + if (widest4 > table->columnWidth(4)) + WidenColumn(4, widest4); +} + +// got a bigger count than previously; might need to widen column 0 +// (or possibly had all counts removed and need to shrink column 0) +void NetHackQtMenuWindow::UpdateCountColumn(long newcount) +{ + if (newcount < 0L) { + // this will happen if user clicks on [all],[none],[invert] buttons; + // they clear all pending counts while selecting or unselecting + biggestcount = 0L; + countdigits = 0; + table->setColumnWidth(0, 0); + WidenColumn(0, MENU_WIDTH_SLOP); + } else { + biggestcount = std::max(biggestcount, newcount); + QString num; + num = nh_qsprintf("%*ld", std::max(countdigits, 1), biggestcount); + int numlen = (int) num.length(); + if (numlen % 2) + ++numlen; + if (numlen <= countdigits) + return; + countdigits = numlen; + // FIXME: neither adjusting the table size (below) nor the + // menu widget size (also below) is making the menu widget + // bigger after the count column has been expanded + } + + PadMenuColumns(false); + + MenuResize(); + table->repaint(); +} + +void NetHackQtMenuWindow::SetTwiAttr(QTableWidgetItem *twi, int color, int attr) +{ + if (color != NO_COLOR) { + const QPen qp = NetHackQtBind::nhcolor_to_pen(color); + twi->setForeground(qp.color()); + } + + if (attr != ATR_NONE) { + QFont itemfont(table->font()); + switch (attr) { + case ATR_BOLD: + itemfont.setWeight(QFont::Bold); + twi->setFont(itemfont); + break; + case ATR_ITALIC: + itemfont.setItalic(true); + twi->setFont(itemfont); + break; + case ATR_DIM: + twi->setFlags(Qt::NoItemFlags); + break; + case ATR_ULINE: + itemfont.setUnderline(true); + twi->setFont(itemfont); + break; + case ATR_INVERSE: { + QBrush fg = twi->foreground(); + QBrush bg = twi->background(); + if (fg.color() == bg.color()) { + // default foreground and background come up the same for + // some unknown reason + //[pr: both are set to 'Qt::color1' which has same RGB + // value as 'Qt::black'; X11 on OSX behaves similarly] + if (fg.color() == Qt::color1) { + fg = Qt::black; + bg = Qt::white; + } else { + fg = (bg.color() == Qt::white) ? Qt::black : Qt::white; + } + } + twi->setForeground(bg); + twi->setBackground(fg); + break; + } + case ATR_BLINK: + // not supported + break; + } /* switch */ + } /* if attr != ATR_NONE */ +} + +void NetHackQtMenuWindow::AddRow(int row, const MenuItem& mi) +{ + QFontMetrics fm(table->font()); + QTableWidgetItem *twi; + glyph_info gi; + + if (mi.Selectable() && how != PICK_NONE) { + // Count + twi = new QTableWidgetItem(""); + table->setItem(row, 0, twi); + twi->setFlags(Qt::ItemIsEnabled); +#if 0 // active count field now widened as needed rather than preset + WidenColumn(0, fm.QFM_WIDTH("999999") + MENU_WIDTH_SLOP); +#else + WidenColumn(0, MENU_WIDTH_SLOP); +#endif + + // Check box, set if pre-selected + QCheckBox *cb = new QCheckBox(); + cb->setChecked(mi.preselected); + cb->setFocusPolicy(Qt::NoFocus); + // CheckboxClicked() will call ToggleSelect() for item whose checkbox + // gets clicked upon + connect(cb, SIGNAL(clicked(bool)), this, SLOT(CheckboxClicked(bool))); + table->setCellWidget(row, 1, cb); + WidenColumn(1, cb->width()); + } + if (mi.glyph != NO_GLYPH) { + // Icon + map_glyphinfo(0, 0, mi.glyph, 0, &gi); + QPixmap pm(qt_settings->glyphs().glyph(mi.glyph, gi.gm.tileidx)); + twi = new QTableWidgetItem(QIcon(pm), ""); + table->setItem(row, 2, twi); + twi->setFlags(Qt::ItemIsEnabled); + WidenColumn(2, pm.width()); + } + + QString letter, text(mi.str); + if (mi.ch != 0) { + // Letter specified + letter = QString(mi.ch) + " - "; + } else { + // Letter is left blank, except for skills display when # and * are + // presented (note: they're just displayed, not become selectors) + if (text.startsWith(" ")) { + // If mi.str starts with " ", it's meant to line up with lines + // that have a letter; we don't want that here + text = text.mid(4); + } else if (text.startsWith(" #") || text.startsWith(" *")) { + // Put the * or # in the letter column + letter = text.left(4); + text = text.mid(4); + } + } + twi = new QTableWidgetItem(letter); + table->setItem(row, 3, twi); + table->item(row, 3)->setFlags(Qt::ItemIsEnabled); + // add extra padding because the measured width comes out too narrow; + // for the normal case of "a - ", the trailing space hid the fact that + // the column wasn't wide enough for four characters; for the " #" + // and " *" cases, the last character was replaced by very tiny "..." + int w = (int) fm.QFM_WIDTH(letter); + if (w) + w += MENU_WIDTH_SLOP / 2; + WidenColumn(3, w); + + twi = new QTableWidgetItem(text); + table->setItem(row, 4, twi); + table->item(row, 4)->setFlags(Qt::ItemIsEnabled); + WidenColumn(4, fm.QFM_WIDTH(text)); + + SetTwiAttr(twi, mi.color, mi.attr); +} + +void NetHackQtMenuWindow::WidenColumn(int column, int width) +{ + // need to add a bit so the whole column displays + width += 7; + if (table->columnWidth(column) < width) { + table->setColumnWidth(column, width); + } +} + +void NetHackQtMenuWindow::InputCount(char key) +{ + if (key == '\b' || key == '\177' || how == PICK_NONE) { + if (counting) { + if (countstr.isEmpty()) + ClearCount(); + else + countstr = countstr.mid(0, countstr.size() - 1); + } + } else { + counting = true; + // starting a count (enforced by caller) with '#' is optional; + // if used, show visible '0' + if (key == '#') + key = '0'; + // if we have non-zero digit and are currently showing visible '0', + // replace instead of append; doesn't attempt to handle multiple + // leading zeroes--they won't affect the outcome, just look odd + else if (key > '0' && countstr == "0") + countstr = ""; + countstr += QChar(key); + } + if (counting) + prompt.setText("Count: " + countstr); +} + +void NetHackQtMenuWindow::ClearCount(void) +{ + counting = false; + prompt.setText(promptstr); + countstr = ""; +} + +void NetHackQtMenuWindow::keyPressEvent(QKeyEvent *key_event) +{ + uchar key = keyValue(key_event); + if (!key) + return; + + // only one possible match for key==ch, and if one occurs it takes + // precedence over any other match (for instance, some menus might + // contain '-' to represent bare hands vs '-' for menu_unselect_page, + // or ':' to look into a container vs ':' for menu_search) + for (int row = 0; row < itemcount; ++row) + if (key == (uchar) itemlist[row].ch) { + ToggleSelect(row, false); + return; + } + + if (key == '\033') { + if (counting) + ClearCount(); + else if (searching) + ClearSearch(); + else + reject(); + } else if (key == '\r' || key == '\n' || key == ' ') { + accept(); + } else if ('0' <= key && key <= '9' && !counting) { + // check whether digit 'key' matches a group accelerator + int hits = 0; + for (int row = 0; row < itemcount; ++row) + if (key == (uchar) itemlist[row].gch) { + ToggleSelect(row, false); // matched so toggle this item + ++hits; + } + if (!hits) // didn't match any group accelerator; start a count + InputCount(key); + } else if (('0' <= key && key <= '9') + || (key == '#' && !counting) + || key == '\b' || key == '\177') { + InputCount(key); + } else if (key == MENU_SELECT_ALL || key == MENU_SELECT_PAGE) { + All(); + } else if (key == MENU_INVERT_ALL || key == MENU_INVERT_PAGE) { + Invert(); + } else if (key == MENU_UNSELECT_ALL || key == MENU_UNSELECT_PAGE) { + ChooseNone(); + } else if (key == MENU_SEARCH) { + Search(); + } else { + // multiple matches are possible with gch + for (int row = 0; row < itemcount; ++row) + if (key == (uchar) itemlist[row].gch) + ToggleSelect(row, false); + } +} + +void NetHackQtMenuWindow::All() +{ + if (how != PICK_ANY && (how != PICK_ONE || itemcount != 1)) + return; + + if (counting) + ClearCount(); // discard any pending count + for (int row = 0; row < itemcount; ++row) { + itemlist[row].preselected = false; // stale for all rows + // skip if not selectable or already selected or fails invert_test() + if (!itemlist[row].Selectable() + || itemlist[row].selected + || !menuitem_invert_test(1, itemlist[row].itemflags, FALSE)) + continue; + itemlist[row].selected = true; + + QTableWidgetItem *count = table->item(row, 0); + if (count != NULL) { + count->setText(""); + } + QCheckBox *cb = dynamic_cast (table->cellWidget(row, 1)); + if (cb != NULL) { + cb->setChecked(true); + } + } + if (biggestcount > 0L) { // had one or more counts + UpdateCountColumn(-1L); // all counts are now gone + } else { + table->repaint(); + } +} + +void NetHackQtMenuWindow::ChooseNone() +{ + if (how == PICK_NONE) + return; + + if (counting) + ClearCount(); // discard any pending count + for (int row = 0; row < itemcount; ++row) { + itemlist[row].preselected = false; // stale for all rows + // skip if not selectable or already unselected or fails invert_test() + if (!itemlist[row].Selectable() + || (!itemlist[row].selected && !isSelected(row)) + || !menuitem_invert_test(2, itemlist[row].itemflags, TRUE)) + continue; + itemlist[row].selected = false; + + QTableWidgetItem *count = table->item(row, 0); + if (count != NULL) { + count->setText(""); + } + QCheckBox *cb = dynamic_cast (table->cellWidget(row, 1)); + if (cb != NULL) { + cb->setChecked(Qt::Unchecked); + } + } + if (biggestcount > 0L) { // had one or more counts + UpdateCountColumn(-1L); // all counts are now gone + } else { + table->repaint(); + } +} + +void NetHackQtMenuWindow::Invert() +{ + if (how == PICK_NONE) + return; + + if (counting) + ClearCount(); // discard any pending count + for (int row = 0; row < itemcount; ++row) { + itemlist[row].preselected = false; // stale for all rows + if (!itemlist[row].Selectable() + || !menuitem_invert_test(0, itemlist[row].itemflags, + itemlist[row].selected)) + continue; + ToggleSelect(row, false); + } + if (biggestcount > 0L) { // had one or more counts + UpdateCountColumn(-1L); // all counts are now gone + } else { + table->repaint(); + } +} + +void NetHackQtMenuWindow::Search() +{ + if (how == PICK_NONE) + return; + + searching = true; + NetHackQtStringRequestor requestor(this, "Search for:"); + char line[BUFSZ]; + line[0] = '\0'; /* for EDIT_GETLIN */ + if (requestor.Get(line)) { + for (int i=0; i (table->cellWidget(row, 1)); + if (cb == NULL) + return; + + if (how == PICK_ONE) { + // explicitly picking a preselected item in a pick-one menu + // chooses that item rather than toggling preselection off; + // by clearing whole menu, the code below will select item #row + ChooseNone(); + already_toggled = false; + // FIXME? this won't handle a pending count properly; + // are there any pick-one menus with preselected choice + // where a count is useful? + } else { + itemlist[row].preselected = false; // flag is now out-of-date + } + + QTableWidgetItem *countfield = table->item(row, 0); + if (!counting) { + if (!already_toggled) + cb->setChecked((cb->checkState() == Qt::Unchecked)); // toggle + itemlist[row].selected = (cb->checkState() != Qt::Unchecked); + if (countfield != NULL) + countfield->setText(""); + } else { + long amt = 1L; + if (countfield != NULL) { + countfield->setText(countstr); // store in item(row,0) + amt = count(row); // fetch item(row,0) as a number + QString Amt = ""; + if (amt > 0L) + Amt = nh_qsprintf("%*ld", countdigits, amt); + countfield->setText(Amt); // store right-justified value + } + ClearCount(); // blank out 'countstr' and reset 'counting' + + // TODO: use a custom icon for check mark, like tty's '#' vs '+' + // [maybe not necessary since unlike tty menus, count is visible] + + // uncheck if count is explicitly 0, otherwise check + cb->setChecked((amt > 0L)); + itemlist[row].selected = (cb->checkState() != Qt::Unchecked); + + // if this count is larger than the biggest we've seen + // so far, it might need more digits to render; if so, + // all pending counts should be reformatted with new width + if (amt > biggestcount) + UpdateCountColumn(amt); + } + + if (how == PICK_ONE && isSelected(row)) + accept(); + else + table->repaint(); + } +} + +// table cell click handler for cells (*,col) where col != 1 +void NetHackQtMenuWindow::TableCellClicked(int row, int col UNUSED) +{ + ToggleSelect(row, false); +} + +// checkbox click handler for table cells (*,1); +// presence of a checkbox in the clicked cell prevents the table cell click +// handler above from being called even if this handler doesn't get set up +void NetHackQtMenuWindow::CheckboxClicked(bool on_off UNUSED) +{ + // find which checkbox just got toggled by looking for one whose + // check state doesn't match corresponding itemlist[].selected flag + // [there's got to be a more direct way of achieving this...] + for (int row = 0; row < itemcount; ++row) { + // for pick-one menu, ToggleSelect() will return to menu's caller + if (itemlist[row].Selectable()) { + if (!isSelected(row) ^ !itemlist[row].selected) { + // signal dispatcher has already checked or unchecked this box + ToggleSelect(row, true); + return; + } + } + } + // didn't find any changed checkbox; should never happen; what to do? +} + +bool NetHackQtMenuWindow::isSelected(int row) +{ + QCheckBox *cb = dynamic_cast (table->cellWidget(row, 1)); + return cb ? (cb->checkState() != Qt::Unchecked) : false; +} + +// convert text count to numeric for final result +long NetHackQtMenuWindow::count(int row) +{ + QTableWidgetItem *count = table->item(row, 0); + if (count == NULL) + return -1L; + QString cstr = count->text(); + return cstr.isEmpty() ? -1L : cstr.toLong(); +} + +// initialize a text window +NetHackQtTextWindow::NetHackQtTextWindow(QWidget *parent) : + QDialog(parent), + use_rip(false), + str_fixed(false), + textsearching(false), + ok("&Dismiss", this), + search("&Search", this), + lines(new NetHackQtTextListBox(this)), + target(""), + rip(this) +{ + // + // TODO? + // Searching would be far more convenient if the window contained + // the search string requestor widget instead of just a [Search] + // button to request a popup for that. + // Also, searching should probably be disabled if the entire text + // fits within the window so there's nothing to scroll through. + // + + ok.setDefault(true); + connect(&ok,SIGNAL(clicked()), this, SLOT(doDismiss())); + connect(&search, SIGNAL(clicked()), this, SLOT(Search())); + connect(qt_settings, SIGNAL(fontChanged()), this, SLOT(doUpdate())); + + QVBoxLayout* vb = new QVBoxLayout(this); + vb->addWidget(&rip); + QHBoxLayout* hb = new QHBoxLayout(); + vb->addLayout(hb); + hb->addWidget(&ok); + hb->addWidget(&search); + vb->addWidget(lines); + + // we don't want keystrokes being sent to the main window for use as + // commands while this text window is popped up + setFocusPolicy(Qt::StrongFocus); + // needed so that keystrokes get sent to our keyPressEvent() + lines->setFocusPolicy(Qt::NoFocus); + setModal(true); +} + +void NetHackQtTextWindow::doUpdate() +{ + update(); +} + + +NetHackQtTextWindow::~NetHackQtTextWindow() +{ +} + +QWidget* NetHackQtTextWindow::Widget() +{ + return this; +} + +bool NetHackQtTextWindow::Destroy() +{ + return true; /*!isVisible();*/ +} + +void NetHackQtTextWindow::doDismiss() +{ + // [Clear() was needed when the search target string was kept in + // a static buffer but is superfluous now that that's part of + // the TextWindow class and initialized in the constructor.] + Clear(); + accept(); +} + +void NetHackQtTextWindow::UseRIP(int how, time_t when) +{ +// Code from X11 windowport +#define STONE_LINE_LEN 16 /* # chars that fit on one line */ +#define NAME_LINE 0 /* line # for player name */ +#define GOLD_LINE 1 /* line # for amount of gold */ +#define DEATH_LINE 2 /* line # for death description */ +#define YEAR_LINE 6 /* line # for year */ + + static char **rip_line = 0; + if (!rip_line) { + rip_line=new char*[YEAR_LINE+1]; + for (int i=0; i 999999999L) + cash = 999999999L; + (void) snprintf(rip_line[GOLD_LINE], STONE_LINE_LEN + 1, "%ld Au", cash); + + /* Put together death description */ + formatkiller(buf, sizeof buf, how, FALSE); + //str_copy(buf, killer, SIZE(buf)); + + /* Put death type on stone */ + for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; ++line) { + char tmpchar; + int i, i0 = (int) strlen(dpx); + + if (i0 > STONE_LINE_LEN) { + for (i = STONE_LINE_LEN; (i > 0) && (i0 > STONE_LINE_LEN); --i) + if (dpx[i] == ' ') + i0 = i; + if (!i) + i0 = STONE_LINE_LEN; + } + tmpchar = dpx[i0]; + dpx[i0] = 0; + (void) str_copy(rip_line[line], dpx, STONE_LINE_LEN + 1); + if (tmpchar != ' ') { + dpx[i0] = tmpchar; + dpx= &dpx[i0]; + } else { + dpx= &dpx[i0 + 1]; + } + } + + /* Put year on stone; + 64 bit configuration with 64 bit int is capable of overflowing + STONE_LINE_LEN characters; a compiler might warn about that, + so force a value that it can recognize as fitting within buffer's + range ("%4d" imposes a minimum number of digits, not a maximum) */ + int year = (int) ((yyyymmdd(when) / 10000L) % 10000L); /* Y10K bug! */ + (void) snprintf(rip_line[YEAR_LINE], STONE_LINE_LEN + 1, "%4d", year); + + rip.setLines(rip_line, YEAR_LINE + 1); + use_rip = true; +} + +void NetHackQtTextWindow::Clear() +{ + lines->clear(); + target[0] = '\0'; // discard search target string + use_rip = false; + str_fixed = false; + textsearching = false; +} + +void NetHackQtTextWindow::Display(bool block UNUSED) +{ + // make sure window isn't completely empty + if (!lines->count()) + PutStr(ATR_NONE, ""); + + if (str_fixed) { + lines->setFont(qt_settings->normalFixedFont()); + } else { + lines->setFont(qt_settings->normalFont()); + } + + /* int h=0; */ + if (use_rip) { + /* h+=rip.height(); */ + (void) rip.height(); + ok.hide(); + search.hide(); + rip.show(); + } else { + /* h+=ok.height()*2 + 7; */ + (void) ok.height(); + ok.show(); + search.show(); + rip.hide(); + } +#if QT_VERSION < 0x060000 + QSize screensize = QApplication::desktop()->size(); +#else + QSize screensize = screen()->size(); +#endif + int mh = screensize.height()*3/5; + if ( (qt_compact_mode && lines->TotalHeight() > mh) || use_rip ) { + showNormal(); + } else { + move(0, 0); + adjustSize(); + centerOnMain(this); + show(); + } + + lines->clearSelection(); // affects [Search] + + exec(); + textsearching = false; +} + +// handle a line of text for a text window +void NetHackQtTextWindow::PutStr(int attr UNUSED, const QString& text) +{ +#if 1 + // 5.0: Always render text windows with fixed-width font. The majority + // of text files we'll ever display including ('license' and 'history') + // happen to have some lines with four spaces anyway and/or they have + // been pre-formatted to fit within less than 80 columns. For data.base + // entries, some do have four spaces (usually the final attribution) + // and some don't, resulting in inconsistent display from one entry to + // another if the default proportional font is ever used. + str_fixed = true; +#else + // if any line contains four consecutive spaces, render this text window + // using fixed-width font; skip substring lookup if flag is already set + str_fixed = str_fixed || text.contains(" "); +#endif + // instead of outputting the line directly, save it for future rendering + lines->addItem(text); +} + +// prompt for a target string and search current text window for it; +// if found, highlight the next line target occurs on; +// multiple searches with same or different search string are supported +void NetHackQtTextWindow::Search() +{ + textsearching = true; + NetHackQtStringRequestor requestor(this, "Search for:", "Done", "Find"); + requestor.SetDefault(target); + boolean get_a_line = requestor.Get(target, (int) sizeof target); + + // FIXME: + // Force text window to be on top. Without this, it moves behind + // the map after the string requestor completes. Then it can't + // be seen or accessed (unless the game window is minimized or + // dragged out of the way). Unfortunately the window noticeably + // vanishes and then immediately gets redrawn. + if (!this->isActiveWindow()) { + this->activateWindow(); + this->raise(); + } + + if (get_a_line && target[0]) { + int linecount = lines->count(); + int current = lines->currentRow(); + if (current == -1) + current = 0; + // when no row is highlighted (selected), start the search + // on the current row, otherwise start on the row after it + // [normally means that the very first row is a candidate + // for containing the target during the very first search] + int startln = lines->selectedItems().count(); + for (int i = startln; i < linecount; ++i) { + int lnum = (i + current) % linecount; + const QString &str = lines->item(lnum)->text(); + // Check whether target occurs on this line. If it does, + // the line is highlighted and this search finishes. + // When not currently within view, highlighting also + // scrolls the view to make it become the bottom line. + // A subsequent search will remember the target string + // and start searching on the line past the highlighted + // one (even if a new target is specified). + if (str.contains(target, Qt::CaseInsensitive)) { + lines->setCurrentRow(lnum); + return; + } + } + lines->setCurrentItem(NULL); + } else { + target[0] = '\0'; + } + textsearching = false; + return; +} + +void NetHackQtTextWindow::keyPressEvent(QKeyEvent *key_event) +{ + uchar key = keyValue(key_event); + + if (key == MENU_SEARCH) { + if (!use_rip) + Search(); + } else if (key == '\n' || key == '\r' || key == ' ') { + if (!textsearching) + accept(); + else + textsearching = FALSE; + } else if (key == '\033') { + reject(); + } else { + // ignore the current key instead of passing it along + //- QDialog::keyPressEvent(key_event); + } +} + +NetHackQtMenuOrTextWindow::NetHackQtMenuOrTextWindow(QWidget *parent_) : + actual(0), + parent(parent_) +{ +} + +// StartMenu() turns a MenuOrTextWindow into a MenuWindow, +// PutStr() turns one into a TextWindow; +// calling any other MenuOrTextWindow routine before either of those +// elicits a warning. (Should probably quit via panic() instead.) +void NetHackQtMenuOrTextWindow::MenuOrText_too_soon_warning(const char *which) +{ + impossible("'%s' called before we know whether window is Menu or Text.", + which); +} + +QWidget* NetHackQtMenuOrTextWindow::Widget() +{ + QWidget *result = NULL; + if (!actual) + MenuOrText_too_soon_warning("Widget"); + else + result = actual->Widget(); + return result; +} + +// Text +void NetHackQtMenuOrTextWindow::Clear() +{ + if (!actual) + MenuOrText_too_soon_warning("Clear"); + else + actual->Clear(); +} +void NetHackQtMenuOrTextWindow::Display(bool block) +{ + if (!actual) + MenuOrText_too_soon_warning("Display"); + else + actual->Display(block); +} +bool NetHackQtMenuOrTextWindow::Destroy() +{ + bool result = false; + if (!actual) + MenuOrText_too_soon_warning("Destroy"); + else + result = actual->Destroy(); + return result; +} +void NetHackQtMenuOrTextWindow::PutStr(int attr, const QString& text) +{ + if (!actual) + actual = new NetHackQtTextWindow(parent); + actual->PutStr(attr, text); +} + +// Menu +void NetHackQtMenuOrTextWindow::StartMenu(bool using_WIN_INVEN) +{ + if (!actual) + actual = new NetHackQtMenuWindow(parent); + actual->StartMenu(using_WIN_INVEN); +} +void NetHackQtMenuOrTextWindow::AddMenu( + int glyph, const ANY_P* identifier, + char ch, char gch, int attr, int clr, + const QString& str, unsigned itemflags) +{ + if (!actual) + MenuOrText_too_soon_warning("AddMenu"); + else + actual->AddMenu(glyph, identifier, ch, gch, attr, clr, str, itemflags); +} +void NetHackQtMenuOrTextWindow::EndMenu(const QString& prompt) +{ + if (!actual) + MenuOrText_too_soon_warning("EndMenu"); + else + actual->EndMenu(prompt); +} +int NetHackQtMenuOrTextWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) +{ + int result = -1; // cancelled + if (!actual) + MenuOrText_too_soon_warning("SelectMenu"); + else + result = actual->SelectMenu(how, menu_list); + return result; +} + +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4menu.h b/win/Qt/qt_menu.h similarity index 58% rename from win/Qt4/qt4menu.h rename to win/Qt/qt_menu.h index 5bc265920..844a470f4 100644 --- a/win/Qt4/qt4menu.h +++ b/win/Qt/qt_menu.h @@ -2,15 +2,18 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4menu.cpp -- a menu or text-list widget +// qt_menu.cpp -- a menu or text-list widget #ifndef QT4MENU_H #define QT4MENU_H -#include "qt4win.h" -#include "qt4rip.h" +#include "qt_win.h" +#include "qt_rip.h" -namespace nethack_qt4 { +// some menu fields aren't wide enough even though sized for measured text +#define MENU_WIDTH_SLOP 10 /* this should not be necessary */ + +namespace nethack_qt_ { class NetHackQtTextListBox : public QListWidget { public: @@ -21,7 +24,7 @@ class NetHackQtTextListBox : public QListWidget { int width = 0; QFontMetrics fm(font()); for (int i = 0; i < count(); i++) { - int lwidth = fm.width(item(i)->text()); + int lwidth = fm.QFM_WIDTH(item(i)->text()); width = std::max(width, lwidth); } return width; @@ -53,21 +56,24 @@ class NetHackQtMenuWindow : public QDialog, public NetHackQtWindow { virtual QWidget* Widget(); - virtual void StartMenu(); - virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const QString& str, bool presel); + virtual void StartMenu(bool using_WIN_INVEN = false); + virtual void AddMenu(int glyph, const ANY_P *identifier, + char ch, char gch, int attr, int clr, + const QString& str, unsigned itemflags); virtual void EndMenu(const QString& prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); + bool is_invent; // using core's WIN_INVEN + public slots: void All(); void ChooseNone(); void Invert(); void Search(); - void ToggleSelect(int); - void cellToggleSelect(int, int); - void DoSelection(bool); + void ToggleSelect(int row, bool alyready_checked); + void TableCellClicked(int row, int col); + void CheckboxClicked(bool on_off); protected: virtual void keyPressEvent(QKeyEvent*); @@ -81,10 +87,12 @@ public slots: ANY_P identifier; int attr; QString str; - int count; + long count; char ch; char gch; - bool selected; + bool selected; // True if checkbox is set + bool preselected; // True if caller told us to set checkbox + unsigned itemflags; unsigned color; bool Selectable() const { return identifier.a_void!=0; } @@ -107,19 +115,27 @@ public slots: // Count replaces prompt while it is being input QString promptstr; QString countstr; - bool counting; + long biggestcount; // determines width of field #0 + int countdigits; // number of digits to format biggestcount + bool counting; // in midst of entering a count + bool searching; // in midst of entering a search string void InputCount(char key); void ClearCount(void); - int how; - - bool has_glyphs; + int how; // pick-none, pick-one, pick-any + bool has_glyphs; // at least one item specified a glyph bool isSelected(int row); - int count(int row); + long count(int row); + void SetTwiAttr(QTableWidgetItem *twi, int color, int attr); void AddRow(int row, const MenuItem& mi); void WidenColumn(int column, int width); + void PadMenuColumns(bool split_descr); + void MenuResize(); + void UpdateCountColumn(long newcount); + + void ClearSearch(); }; class NetHackQtTextWindow : public QDialog, public NetHackQtWindow { @@ -140,15 +156,21 @@ public slots: void Search(); private slots: + void doDismiss(); void doUpdate(); +protected: + virtual void keyPressEvent(QKeyEvent *); + private: bool use_rip; bool str_fixed; + bool textsearching; QPushButton ok; QPushButton search; NetHackQtTextListBox* lines; + char target[BUFSZ]; NetHackQtRIP rip; }; @@ -156,7 +178,9 @@ private slots: class NetHackQtMenuOrTextWindow : public NetHackQtWindow { private: NetHackQtWindow* actual; - QWidget *parent; + QWidget *parent; + + static void MenuOrText_too_soon_warning(const char *); public: NetHackQtMenuOrTextWindow(QWidget *parent = NULL); @@ -170,14 +194,15 @@ class NetHackQtMenuOrTextWindow : public NetHackQtWindow { virtual void PutStr(int attr, const QString& text); // Menu - virtual void StartMenu(); - virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const QString& str, bool presel); + virtual void StartMenu(bool using_WIN_INVENT = false); + virtual void AddMenu(int glyph, const ANY_P *identifier, + char ch, char gch, int attr, int clr, + const QString& str, unsigned itemflags); virtual void EndMenu(const QString& prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_msg.cpp b/win/Qt/qt_msg.cpp new file mode 100644 index 000000000..f61549d81 --- /dev/null +++ b/win/Qt/qt_msg.cpp @@ -0,0 +1,230 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_msg.cpp -- a message window + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_msg.h" +#include "qt_msg.moc" +#include "qt_map.h" +#include "qt_set.h" +#include "qt_str.h" + +namespace nethack_qt_ { + +NetHackQtMessageWindow::NetHackQtMessageWindow() : + list(new QListWidget()), + scrollarea(new QScrollArea()) +{ + list->setFocusPolicy(Qt::NoFocus); + scrollarea->setFocusPolicy(Qt::NoFocus); + scrollarea->takeWidget(); + ::iflags.window_inited = 1; + map = 0; + currgetmsg = 0; + connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(updateFont())); + updateFont(); +} + +NetHackQtMessageWindow::~NetHackQtMessageWindow() +{ + ::iflags.window_inited = 0; + delete list; +} + +QWidget* NetHackQtMessageWindow::Widget() { + return list; +} + +void NetHackQtMessageWindow::setMap(NetHackQtMapWindow2* m) +{ + map = m; + updateFont(); +} + +void NetHackQtMessageWindow::updateFont() +{ + list->setFont(qt_settings->normalFont()); + if ( map ) + map->setFont(qt_settings->normalFont()); +} + +void NetHackQtMessageWindow::Scroll(int dx UNUSED, int dy UNUSED) +{ + //RLC Is this necessary? + //RLC list->Scroll(dx,dy); +} + +void NetHackQtMessageWindow::Clear() +{ + if (list) + NetHackQtMessageWindow::unhighlight_mesgs(); + + if (map) + map->clearMessages(); +} + +void NetHackQtMessageWindow::ClearMessages() +{ + if (list) + list->clear(); +} + +void NetHackQtMessageWindow::Display(bool block) +{ + if (changed) { + list->repaint(); + changed=false; + } + if (block) { + // we don't care what the response is here + (void) NetHackQtBind::qt_more(); + } +} + +const char * NetHackQtMessageWindow::GetStr(bool init) +{ + if (init) + currgetmsg = 0; + + QListWidgetItem *item = list->item(currgetmsg++); + if (item) { + QString str = item->text(); + if (str.toLatin1().length() < (int) sizeof historybuf) { + return strcpy(historybuf, str.toLatin1().constData()); + //raw_printf("getstr[%d]='%s'", currgetmsg, result); + } + } + return NULL; +} + +void NetHackQtMessageWindow::PutStr(int attr, const QString& text) +{ + changed=true; + + // If the line is output from the "/" command, map the first character + // as a symbol + QString text2; + if (text.mid(1, 3) == " ") { + text2 = QChar(cp437(text.at(0).unicode())) + text.mid(1); + } else { + text2 = text; + } + +#if 0 + if (attr != ATR_NONE) { + QListWidgetItem *item = new QListWidgetItem(text2); + if (attr != ATR_DIM && attr != ATR_INVERSE) { + QFont font = item->font(); + font.setUnderline(attr == ATR_ULINE); + font.setWeight((attr == ATR_BOLD) ? QFont::Bold : QFont::Normal); + item->setFont(font); + // ATR_BLINK not supported + } else { + // ATR_DIM or ATR_INVERSE + QBrush fg = item->foreground(); + QBrush bg = item->background(); + if (fg.color() == bg.color()) { // from menu coloring [AddRow()] + // default foreground and background come up the same for + // some unknown reason + //[pr: both are set to 'Qt::color1' which has same RGB + // value as 'Qt::black'; X11 on OSX behaves similarly] + if (fg.color() == Qt::color1) { + fg = Qt::black; + bg = Qt::white; + } else { + fg = (bg.color() == Qt::white) ? Qt::black : Qt::white; + } + } + if (attr == ATR_DIM) { + QColor fg_clr = fg.color(); + fg_clr.setAlpha(fg_clr.alpha() / 2); + item->setFlags(Qt::NoItemFlags); + } else if (attr == ATR_INVERSE) { + QBrush swapfb; + swapfb = fg; fg = bg; bg = swapfb; + } + item->setForeground(fg); + item->setBackground(bg); + } + } +#else + nhUse(attr); +#endif + + if (list->count() >= (int) ::iflags.msg_history) + delete list->item(0); + list->addItem(text2); + /* assert( list->count() > 0 ); */ + + // force scrollbar to bottom; + // selects most recent message, which causes it to be highlighted + list->setCurrentRow(list->count() - 1); + + // if message window has been scrolled right, force back to left edge + QScrollBar *sb = list->horizontalScrollBar(); + if (sb && sb->value() > 0) { + sb->setValue(0); + this->viewport()->update(); + } + + if (map) + map->putMessage(attr, text2); +} + +// append to the last message; usually the user's answer to a prompt +void NetHackQtMessageWindow::AddToStr(const char *answer) +{ + if (list) { + QListWidgetItem *item = list->currentItem(); + int ct = 0; + if (!item && (ct = list->count()) > 0) { + list->setCurrentRow(ct - 1); + item = list->currentItem(); + } + if (item) + item->setText(item->text() + QString(" %1").arg(answer)); + else // just in case... + NetHackQtMessageWindow::PutStr(ATR_NONE, answer); + } +} + +// used when yn_function() or more() rejects player's input and tries again +void NetHackQtMessageWindow::RehighlightPrompt() +{ + // selects most recent message, which causes it to be highlighted + if (list && list->count()) + list->setCurrentRow(list->count() - 1); +} + +// are there any highlighted messages? +bool NetHackQtMessageWindow::hilit_mesgs() +{ + // PutStr() uses setCurrentRow() to select the last message line; + // being selected causes that line to be highlighted. + // + // We could/should keep track of whether anything is currently + // highlighted instead of just assuming that last message still is. + if (list && list->count()) + return true; + return false; +} + +// unhighlight any highlighted messages +void NetHackQtMessageWindow::unhighlight_mesgs() +{ + if (list) + list->clearSelection(); +} + +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4msg.h b/win/Qt/qt_msg.h similarity index 58% rename from win/Qt4/qt4msg.h rename to win/Qt/qt_msg.h index f4091ad18..9c5624d8b 100644 --- a/win/Qt4/qt4msg.h +++ b/win/Qt/qt_msg.h @@ -2,18 +2,18 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4msg.h -- a message window +// qt_msg.h -- a message window #ifndef QT4MSG_H #define QT4MSG_H -#include "qt4win.h" +#include "qt_win.h" -namespace nethack_qt4 { +namespace nethack_qt_ { class NetHackQtMapWindow2; -class NetHackQtMessageWindow : QObject, public NetHackQtWindow { +class NetHackQtMessageWindow : QScrollArea, public NetHackQtWindow { Q_OBJECT public: NetHackQtMessageWindow(); @@ -30,16 +30,24 @@ class NetHackQtMessageWindow : QObject, public NetHackQtWindow { void setMap(NetHackQtMapWindow2*); + void RehighlightPrompt(); + bool hilit_mesgs(); + void unhighlight_mesgs(); + // for adding the answer for y_n() to its prompt string + void AddToStr(const char *answerbuf); + private: - QListWidget* list; - bool changed; + QListWidget *list; + QScrollArea *scrollarea; + bool changed; int currgetmsg; NetHackQtMapWindow2* map; + char historybuf[BUFSZ]; private slots: void updateFont(); }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_plsel.cpp b/win/Qt/qt_plsel.cpp new file mode 100644 index 000000000..a280f07fc --- /dev/null +++ b/win/Qt/qt_plsel.cpp @@ -0,0 +1,742 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_plsel.cpp -- player selector dialog + +// +// TODO: +// increase height so that no scrolling is needed for role list [needs +// to be done properly instead of forcing logo string to be taller] +// make race first vs role first dynamically selectable (tty allows +// gender first and alignment first too); +// maybe add a set of radio buttons for normal mode vs explore mode +// [vs wizard mode if eligible] +// gray out character name / disable name specification box if player +// shouldn't be allowed to change it ("wizard" for debug mode, use +// of some forced value for multi-user system). +// + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_plsel.h" +#include "qt_plsel.moc" +#include "qt_bind.h" +#include "qt_glyph.h" +#include "qt_set.h" +#include "qt_str.h" + +// Warwick prefers it this way... +#define QT_CHOOSE_RACE_FIRST + +/* check whether plname[] is among the list of generic user names */ +static bool generic_plname() +{ + if (*svp.plname) { + const char *sptr, *p; + const char *genericusers = sysopt.genericusers; + int ln = (int) strlen(svp.plname); + + if (!genericusers || !*genericusers) + genericusers = "player games"; + else if (!strcmp(genericusers, "*")) /* "*" => always ask for name */ + return true; + + while ((sptr = strstri(genericusers, svp.plname)) != NULL) { + /* check for full word: start of list or following a space */ + if ((sptr == genericusers || sptr[-1] == ' ') + /* and also preceding a space or at end of list */ + && (sptr[ln] == ' ' || sptr[ln] == '\0')) + return true; + /* doesn't match full word, but maybe we got a false hit when + looking for "play" in list "player play" so keep going */ + if ((p = strchr(sptr + 1, ' ')) == NULL) + break; + genericusers = p + 1; + } + } + return false; +} + +namespace nethack_qt_ { + +// temporary +void centerOnMain( QWidget* w ); +// end temporary + +// hack: padded with blank lines by inserting breaks above and below in +// order to force window to be tall enough to show all the roles at once +static const char nh_attribution[] = "
NetHack %1" + "
by the NetHack DevTeam

"; + +// +// None of these extra classes seem to be used except for NhPSListView. [pr] +// If NhPSListViewRole and NhPSListViewRace ever start being used, +// they'll need access to NetHackQtPlayerSelector::chosen_gend to use +// the correct tile for the icon. +// + +class NhPSListViewItem : public QTableWidgetItem { +public: + NhPSListViewItem( QTableWidget* parent UNUSED, const QString& name ) : + QTableWidgetItem(name) + { + } + + void setGlyph(int g, int tileidx) + { + NetHackQtGlyphs& glyphs = qt_settings->glyphs(); + int gw = glyphs.width(); + int gh = glyphs.height(); + QPixmap pm(gw,gh); + QPainter p(&pm); + glyphs.drawGlyph(p, g, tileidx, 0, 0, false); + p.end(); + setIcon(QIcon(pm)); + //RLC setHeight(std::max(pm.height()+1,height())); + } + +#if 0 //RLC + void paintCell( QPainter *p, const QColorGroup &cg, + int column, int width, int alignment ) + { + if ( isSelectable() ) { + QTableWidgetItem::paintCell( p, cg, column, width, alignment ); + } else { + QColorGroup disabled( + cg.foreground().light(), + cg.button().light(), + cg.light(), cg.dark(), cg.mid(), + Qt::gray, cg.base() ); + QTableWidgetItem::paintCell( p, disabled, column, width, alignment ); + } + } +#endif +}; + +class NhPSListViewRole : public NhPSListViewItem { +public: + NhPSListViewRole( QTableWidget* parent, int id ) : + NhPSListViewItem(parent, +#ifdef QT_CHOOSE_RACE_FIRST // Lowerize - looks better + QString(roles[id].name.m).toLower() +#else + roles[id].name.m +#endif + ) + { + glyph_info gi; + int glyph = monnum_to_glyph(roles[id].mnum, MALE); + map_glyphinfo(0, 0, glyph, 0, &gi); + setGlyph(glyph, gi.gm.tileidx); + } +}; + +class NhPSListViewRace : public NhPSListViewItem { +public: + NhPSListViewRace( QTableWidget* parent, int id ) : + NhPSListViewItem(parent, +#ifdef QT_CHOOSE_RACE_FIRST // Capitalize - looks better + str_titlecase(races[id].noun) +#else + races[id].noun +#endif + ) + { + glyph_info gi; + int glyph = monnum_to_glyph(races[id].mnum, MALE); + map_glyphinfo(0, 0, glyph, 0, &gi); + setGlyph(glyph, gi.gm.tileidx); + } +}; + +class NhPSListView : public QTableWidget { +public: + NhPSListView( QWidget* parent ) : + QTableWidget(parent) + { + setColumnCount(1); + verticalHeader()->hide(); +#if QT_VERSION >= 0x050000 + horizontalHeader()->setSectionsClickable(false); +#else + horizontalHeader()->setClickable(false); +#endif + } + + QSizePolicy sizePolicy() const + { + return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); + } + + QSize minimumSizeHint() const + { + return sizeHint(); + } + + QSize sizeHint() const + { + return QSize(columnWidth(0), QTableWidget::sizeHint().height()); + } +}; + +// constructor for player's name+role/race/gender/alignment selection +NetHackQtPlayerSelector::NetHackQtPlayerSelector( + NetHackQtKeyBuffer& ks UNUSED) : + QDialog(NetHackQtBind::mainWidget()), + fully_specified_role(true), + chosen_gend(ROLE_NONE), + chosen_align(ROLE_NONE), + cleric_role_row(0), + human_race_row(0), + rand_btn(new QPushButton("Random")), + play_btn(new QPushButton("Play")), + quit_btn(new QPushButton("Quit")) +{ + /* + 0 1 2 + + Name --------------------------------------+ + 0 | | + + -------------------------------------------+ + + Race ----+ + Role ----+ + Gender ------+ + | human | | Archeolog| | * Male | + 1 | elf | | Barbarian| | * Female | + | dwarf | | | +--------------+ + | gnome | | | + | orc | | | + Alignment ---+ + 2 | | | . | | * Lawful | + | | | . | | * Neutral | + | | | . | | * Chaotic | + | | | | +--------------+ + 3 | | | | ...stretch... + | | | | + 4 | | | Valkyrie | [ Random ] + 5 | | | Wizard | [ Play ] + 6 | | | | [ Quit ] + +----------+ +----------+ + * + * Both Race and Role entries are actually two-part: an icon (the map + * tile for the corresponding monster) and text (race or role name); + * Race column is as tall as role one but mostly blank; + * Role names aren't truncated in the actual display, just here; the + * race and role columns do have equal width; + * Roles with gender-specific names get changed to match chosen gender; + * Each of the four role/race/gender/alignment categories always has + * one entry checked; [Random] will change to a new set; + * [Play] is selected by default if [Name] is non-empty but grayed out + * if it is empty; + * [Quit] is selected by default when [Name] is empty; + * ...stretch... is "NetHack x.y.z" in large text over + * "by the NetHack DevTeam" is smaller text with blank space above + * and below the two lines of text. + * + * If currently selected race isn't allowed to be some roles, they'll + * be grayed out. To switch to one of those, first check "human" which + * offers access to all roles (except Valk which will be grayed out if + * "male" is checked), pick the role of interest, and then re-pick race + * (some of which will be grayed out if chosen role doesn't allow them). + * To pick alignment first, check "human" and "priest[ess]" to make + * all three alignments accessible, pick the one of interest, then pick + * among the races and roles that are acceptable for that alignment. + * Gender can be picked at any time, except for male when Valkyrie is + * selected. + */ + + QGridLayout *l = new QGridLayout(this); + l->setColumnStretch(2, 1); + sizePolicy().setHorizontalPolicy(QSizePolicy::Minimum); + + QGroupBox* namebox = new QGroupBox("Name", this); + QVBoxLayout *namelayout = new QVBoxLayout(namebox); + QLineEdit* name = new QLineEdit(namebox); + namelayout->addWidget(name); + name->setMaxLength(PL_NSIZ - 1); + name->setPlaceholderText(QString(" (required)")); // grayed out + + // if plname[] contains a generic user name, clear it + if (generic_plname()) + *svp.plname = '\0'; + name->setText(svp.plname); + connect(name, SIGNAL(textChanged(const QString&)), + this, SLOT(selectName(const QString&))); + name->setFocus(); + + // changed to move gender and alignment labels inside their boxes (below) + QGroupBox *genderbox = new QGroupBox(); + QButtonGroup *gendergroup = new QButtonGroup(this); + QGroupBox *alignbox = new QGroupBox(); + QButtonGroup *aligngroup = new QButtonGroup(this); + // these two QVBoxLayout pointers aren't used, the vertical box layouts + // being assigned to them are... + QVBoxLayout* vbgb UNUSED = new QVBoxLayout(genderbox); + QVBoxLayout* vbab UNUSED = new QVBoxLayout(alignbox); + char versionbuf[QBUFSZ]; + QLabel *logo = new QLabel(QString(nh_attribution).arg( + version_string(versionbuf, sizeof versionbuf)), this); + + l->addWidget( namebox, 0,0,1,3 ); + role = new NhPSListView(this); + race = new NhPSListView(this); +#ifdef QT_CHOOSE_RACE_FIRST + l->addWidget( race, 1,0,6,1 ); + l->addWidget( role, 1,1,6,1 ); +#else + l->addWidget( role, 1,0,6,1 ); + l->addWidget( race, 1,1,6,1 ); +#endif + + l->addWidget( genderbox, 1, 2 ); + l->addWidget( alignbox, 2, 2 ); + l->addWidget( logo, 3, 2, Qt::AlignCenter ); + l->setRowStretch( 3, 6 ); + + QTableWidgetItem *item; + int i, nrole, nrace; + + chosen_gend = flags.initgend; + chosen_align = flags.initalign; + + // XXX QListView unsorted goes in rev. + for (nrole=0; roles[nrole].name.m; nrole++) + ; + role->setRowCount(nrole); + for (i = 0; i < nrole; ++i) { + item = new QTableWidgetItem(); + role->setItem(i, 0, item); + + if (roles[i].mnum == PM_CLERIC) + cleric_role_row = i; // for populate_races() + } + + for (nrace=0; races[nrace].noun; nrace++) + ; + race->setRowCount(nrace); + for (i = 0; i < nrace; ++i) { + item = new QTableWidgetItem(); + race->setItem(i, 0, item); + + if (races[i].mnum == PM_HUMAN) + human_race_row = i; // (always i==0) for populate_roles() + } + +#ifdef QT_CHOOSE_RACE_FIRST + populate_races(); + populate_roles(); +#else + populate_roles(); + populate_races(); +#endif + + connect(role, SIGNAL(currentCellChanged(int, int, int, int)), + this, SLOT(selectRole(int, int, int, int))); + role->setHorizontalHeaderLabels(QStringList("Role")); + role->resizeColumnToContents(0); + + connect(race, SIGNAL(currentCellChanged(int, int, int, int)), + this, SLOT(selectRace(int, int, int, int))); + race->setHorizontalHeaderLabels(QStringList("Race")); + race->resizeColumnToContents(0); + + // TODO: + // Render the alignment and gender labels smaller to match the + // horizontal header labels for role and race. (Getting the font from + // race table above and setting it for labels below made no difference.) + + QLabel *gendlabel = new QLabel("Gender"); + genderbox->layout()->addWidget(gendlabel); + gender = new QRadioButton*[ROLE_GENDERS]; + for (i=0; ilayout()->addWidget(gender[i]); + gendergroup->addButton(gender[i], i); + } + connect(gendergroup, SIGNAL(buttonClicked(int)), + this, SLOT(selectGender(int))); + + QLabel *alignlabel = new QLabel("Alignment"); + alignbox->layout()->addWidget(alignlabel); + alignment = new QRadioButton*[ROLE_ALIGNS]; + for (i=0; ilayout()->addWidget(alignment[i]); + aligngroup->addButton(alignment[i], i); + } + connect(aligngroup, SIGNAL(buttonClicked(int)), + this, SLOT(selectAlignment(int))); + + l->addWidget(rand_btn, 4, 2); + connect(rand_btn, SIGNAL(clicked()), this, SLOT(Randomize())); + l->addWidget(play_btn, 5, 2); + connect(play_btn, SIGNAL(clicked()), this, SLOT(accept())); + l->addWidget(quit_btn, 6, 2); + connect(quit_btn, SIGNAL(clicked()), this, SLOT(reject())); + // if plname[] is non-empty, the Play button is enabled and the default; + // otherwise, Play is disabled and Quit is the default + plnamePlayVsQuit(); + + Randomize(); +} + +// update the role column in the PlayerSelector widget +void +NetHackQtPlayerSelector::populate_roles() +{ + // + // entry for each row in the role column shows a player-character tile + // (always gender-specific) and role's name (sometimes gender-specific) + // + QTableWidgetItem *item; + const char *rolename; + glyph_info gi; + int v, gf, gn = chosen_gend, al = chosen_align; + // if no race yet, we use human for gender check (gender doesn't affect + // race but we need a valid race when filtering Valkyrie out or back in) + int ra = race->currentRow(), hu = human_race_row; + bool is_f = (gn == 1); + NetHackQtGlyphs& glyphs = qt_settings->glyphs(); + for (int i = 0; roles[i].name.m; ++i) { + rolename = (is_f && roles[i].name.f) ? roles[i].name.f + : roles[i].name.m; + gf = monnum_to_glyph(roles[i].mnum, is_f ? FEMALE : MALE); + map_glyphinfo(0, 0, gf, 0, &gi); + v = ((ra < 0 || validrace(i, ra)) + && (gn < 0 || validgend(i, (ra >= 0) ? ra : hu, gn)) + && (al < 0 || validalign(i, (ra >= 0) ? ra : hu, al))); + item = role->item(i, 0); + item->setText(rolename); + item->setIcon(QIcon(glyphs.glyph(gf, gi.gm.tileidx))); + item->setFlags(v ? Qt::ItemIsEnabled | Qt::ItemIsSelectable + : Qt::NoItemFlags); + } + role->repaint(); // role->update() seems to be inadequate +} + +// update the race column in the PlayerSelector widget +void +NetHackQtPlayerSelector::populate_races() +{ + // + // entry for each row in race column shows race's generic monster tile + // (always gender-specific) and race's name (never gender-specific) + // + QTableWidgetItem *item; + glyph_info gi; + int v, gf, gn = chosen_gend, al = chosen_align; + // if no role yet, use cleric so that alignment won't rule anything out + int ro = role->currentRow(), cl = cleric_role_row; + bool is_f = (gn == 1); + NetHackQtGlyphs& glyphs = qt_settings->glyphs(); + for (int j = 0; races[j].noun; ++j) { + gf = monnum_to_glyph(races[j].mnum, is_f ? FEMALE : MALE); + map_glyphinfo(0, 0, gf, 0, &gi); + v = ((ro < 0 || validrace(ro, j)) + && (al < 0 || validalign((ro >= 0) ? ro : cl, j, al))); + item = race->item(j, 0); + item->setText(races[j].noun); + item->setIcon(QIcon(glyphs.glyph(gf, gi.gm.tileidx))); + item->setFlags(v ? Qt::ItemIsEnabled | Qt::ItemIsSelectable + : Qt::NoItemFlags); + } + race->repaint(); +} + +void NetHackQtPlayerSelector::Randomize() +{ + int nrole = role->rowCount(); + int nrace = race->rowCount(); + + boolean picksomething = (flags.initrole == ROLE_NONE + || flags.initrace == ROLE_NONE + || flags.initgend == ROLE_NONE + || flags.initalign == ROLE_NONE); + + if (flags.randomall && picksomething) { + if (flags.initrole == ROLE_NONE) + flags.initrole = ROLE_RANDOM; + if (flags.initrace == ROLE_NONE) + flags.initrace = ROLE_RANDOM; + if (flags.initgend == ROLE_NONE) + flags.initgend = ROLE_RANDOM; + if (flags.initalign == ROLE_NONE) + flags.initalign = ROLE_RANDOM; + } + + rigid_role_checks(); + + // Randomize race and role, unless specified in config + int ro = flags.initrole; + if (ro == ROLE_NONE || ro == ROLE_RANDOM) { + ro = rn2(nrole); + if (flags.initrole != ROLE_RANDOM) { + fully_specified_role = false; + } + } + int ra = flags.initrace; + if (ra == ROLE_NONE || ra == ROLE_RANDOM) { + ra = rn2(nrace); + if (flags.initrace != ROLE_RANDOM) { + fully_specified_role = false; + } + } + + // make sure we have a valid combination, honoring + // the user's request if possible. + bool choose_race_first; +#ifdef QT_CHOOSE_RACE_FIRST + choose_race_first = true; + if (flags.initrole >= 0 && flags.initrace < 0) { + choose_race_first = false; + } +#else + choose_race_first = false; + if (flags.initrace >= 0 && flags.initrole < 0) { + choose_race_first = true; + } +#endif + while (!validrace(ro,ra)) { + if (choose_race_first) { + ro = rn2(nrole); + if (flags.initrole != ROLE_RANDOM) { + fully_specified_role = false; + } + } else { + ra = rn2(nrace); + if (flags.initrace != ROLE_RANDOM) { + fully_specified_role = false; + } + } + } + + int g = flags.initgend; + if (g < 0) { + g = rn2(ROLE_GENDERS); + fully_specified_role = false; + } + while (!validgend(ro,ra,g)) { + g = rn2(ROLE_GENDERS); + } + gender[g]->setChecked(true); + selectGender(g); + + int a = flags.initalign; + if (a < 0) { + a = rn2(ROLE_ALIGNS); + fully_specified_role = false; + } + while (!validalign(ro,ra,a)) { + a = rn2(ROLE_ALIGNS); + } + alignment[a]->setChecked(true); + selectAlignment(a); + + role->setCurrentCell(ro, 0); + + race->setCurrentCell(ra, 0); +} + +// if plname[] is empty, disable [Play], otherwise [Play] is the default +void NetHackQtPlayerSelector::plnamePlayVsQuit() +{ + if (*svp.plname) { + play_btn->setEnabled(true); + play_btn->setDefault(true); + //quit_btn->setDefault(false); + } else { + play_btn->setEnabled(false); // [Play] still visible but grayed out + //play_btn->setDefault(false); + quit_btn->setDefault(true); + } +} + +// the line edit widget for the name field has received input +void NetHackQtPlayerSelector::selectName(const QString& n) +{ + const char *name_str = n.toLatin1().constData(); + // skip any leading spaces + // (it would be better to set up a validator that rejects leading spaces) + while (*name_str == ' ') + ++name_str; + str_copy(svp.plname, name_str, PL_NSIZ); + // possibly enable or disable the [Play] button + plnamePlayVsQuit(); +} + +void NetHackQtPlayerSelector::selectRole(int crow, int ccol, + int prow, int pcol) +{ + int ra = race->currentRow(); + int ro = role->currentRow(); + if (ra == -1 || ro == -1) + return; + QTableWidgetItem *item = role->item(prow, 0); + if (item != NULL) + item->setSelected(false); + +#ifdef QT_CHOOSE_RACE_FIRST + selectRace(crow, ccol, prow, pcol); +#else + QTableWidgetItem *i = role->currentItem(); + QTableWidgetItem *valid = 0; + for (int j = 0; roles[j].name.m; ++j) { + if (!valid && (ra < 0 || validrace(j, ra))) { + valid = role->item(j, 0); + break; + } + } + if (!validrace(role->currentRow(), ra)) + i = valid; + role->setCurrentItem(i, 0); + for (int j = 0; roles[j].name.m; ++j) { + item = role->item(j, 0); + item->setSelected(item == i); + /* used to call setFlags here, but setupOthers() -> selectGender() + (and selectAlignment()) -> populate_roles() takes care of that */ + } + nhUse(crow); + nhUse(ccol); + nhUse(pcol); +#endif + + //flags.initrole = role->currentRow(); + setupOthers(); +} + +void NetHackQtPlayerSelector::selectRace(int crow, int ccol, + int prow, int pcol) +{ + int ra = race->currentRow(); + int ro = role->currentRow(); + if (ra == -1 || ro == -1) + return; + QTableWidgetItem *item = race->item(prow, 0); + if (item != NULL) + item->setSelected(false); + +#ifndef QT_CHOOSE_RACE_FIRST + selectRole(crow, ccol, prow, pcol); +#else + QTableWidgetItem *i = race->currentItem(); + QTableWidgetItem *valid = 0; + for (int j = 0; races[j].noun; ++j) { + if (!valid && (ro < 0 || validrace(ro, j))) { + valid = race->item(j, 0); + break; + } + } + if (!validrace(ro, race->currentRow())) + i = valid; + for (int j = 0; races[j].noun; ++j) { + item = race->item(j, 0); + item->setSelected(item == i); + /* used to call setFlags here, but setupOthers() -> selectGender() + (and selectAlignment()) -> populate_races() takes care of that */ + } + nhUse(crow); + nhUse(ccol); + nhUse(pcol); +#endif + + //flags.initrace = race->currentRow(); + setupOthers(); +} + +void NetHackQtPlayerSelector::setupOthers() +{ + int ro = role->currentRow(); + int ra = race->currentRow(); + int valid=-1; + int c=0; + int j; + for (j=0; jisChecked() ) + c = j; + gender[j]->setEnabled(v); + if ( valid<0 && v ) valid = j; + } + if ( !validgend(ro,ra,c) ) + c = valid; + int k; + for (k=0; ksetChecked(c==k); + } + selectGender(c); + + valid=-1; + for (j=0; jisChecked() ) + c = j; + alignment[j]->setEnabled(v); + if ( valid<0 && v ) valid = j; + } + if ( !validalign(ro,ra,c) ) + c = valid; + for (k=0; ksetChecked(c==k); + } + selectAlignment(c); +} + +void NetHackQtPlayerSelector::selectGender(int i) +{ + chosen_gend = i; + // if gender has changed, tiles and some role titles will change + populate_roles(); + populate_races(); +} + +void NetHackQtPlayerSelector::selectAlignment(int i) +{ + chosen_align = i; + // if alignment has changed, some roles or races may no longer be + // available and some previously excluded ones might become available + populate_roles(); + populate_races(); +} + +void NetHackQtPlayerSelector::Quit() +{ + done(R_Quit); +} + +void NetHackQtPlayerSelector::Random() +{ + done(R_Rand); +} + +bool NetHackQtPlayerSelector::Choose() +{ + if (fully_specified_role) + return true; + +#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). + if ( qt_compact_mode ) { + showMaximized(); + } else +#endif + { + adjustSize(); + centerOnMain(this); + } + + if ( exec() ) { + flags.initrace = race->currentRow(); + flags.initrole = role->currentRow(); + flags.initgend = chosen_gend; + flags.initalign = chosen_align; + return true; + } else { + return false; + } +} + +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4plsel.h b/win/Qt/qt_plsel.h similarity index 72% rename from win/Qt4/qt4plsel.h rename to win/Qt/qt_plsel.h index de070d147..a30133711 100644 --- a/win/Qt4/qt4plsel.h +++ b/win/Qt/qt_plsel.h @@ -2,12 +2,12 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4plsel.h -- player selector dialog +// qt_plsel.h -- player selector dialog #ifndef QT4PLSEL_H #define QT4PLSEL_H -namespace nethack_qt4 { +namespace nethack_qt_ { class NetHackQtKeyBuffer; @@ -22,6 +22,10 @@ public slots: void Quit(); void Random(); void Randomize(); + void plnamePlayVsQuit(); + + void populate_roles(); + void populate_races(); void selectName(const QString& n); void selectRole(int current, int, int previous, int); @@ -38,11 +42,18 @@ public slots: QTableWidget* race; QRadioButton **gender; QRadioButton **alignment; + bool fully_specified_role; int chosen_gend; int chosen_align; + int cleric_role_row; + int human_race_row; + + QPushButton *rand_btn; + QPushButton *play_btn; + QPushButton *quit_btn; }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_post.h b/win/Qt/qt_post.h new file mode 100644 index 000000000..6c783cf00 --- /dev/null +++ b/win/Qt/qt_post.h @@ -0,0 +1,17 @@ +/* NetHack 5.0 qt_post.h $NHDT-Date: 1597276832 2020/08/13 00:00:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */ + +/* + * qt_post.h -- reverse part of qt_pre.h. + * + * #include after . + */ + +#if defined(__cplusplus) +#ifdef __clang__ +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif /* compiler-specific bits */ +#endif /* __cplusplus */ + +/*qt_post.h*/ diff --git a/win/Qt/qt_pre.h b/win/Qt/qt_pre.h new file mode 100644 index 000000000..1dddde25b --- /dev/null +++ b/win/Qt/qt_pre.h @@ -0,0 +1,76 @@ +/* NetHack 5.0 qt_pre.h $NHDT-Date: 1597276835 2020/08/13 00:00:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */ + +/* + * qt_pre.h -- undefine some nethack macros which conflict with Qt headers. + * + * #include after "hack.h", before . + */ + +#undef C // conflicts with Qt6 header +#undef Invisible +#undef Warning +#undef msleep +#undef wizard +#undef min +#undef max + +#ifdef NOT_C99 +#ifdef NEED_INDEX +#undef index +#endif +#ifdef NEED_RINDX +#undef rindex +#endif +#endif + +#if defined(__cplusplus) + +#ifdef __clang__ +#pragma clang diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic push +#endif +/* the diagnostic pop is in qt_post.h */ + +#ifdef __clang__ +/* disable warnings for shadowed names; some of the Qt prototypes use + placeholder argument names which conflict with nethack variables + ('u' and 'flags') */ +#pragma clang diagnostic ignored "-Wshadow" +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wshadow" +#endif + +#include + +/* QFontMetrics::width was deprecated in Qt 5.11 */ +#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) +#define QFM_WIDTH(foo) width(foo) +#else +#define QFM_WIDTH(foo) horizontalAdvance(foo) +#endif + +#if __cplusplus >= 202002L +/* c++20 or newer */ +#if QT_VERSION < 0x060000 +/* + * qt5/QtWidgets/qsizepolicy.h + * Qt5 header file issue under c++ 20 + * + * warning: bitwise operation between different enumeration types + * ‘QSizePolicy::Policy’ and ‘QSizePolicy::PolicyFlag’ + * is deprecated [-Wdeprecated-enum-enum-conversion] + */ +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" +#endif +#endif /* QT_VERSION < 0x060000 */ +#endif /* __cplusplus >= 202002L */ +#endif /* __cplusplus */ + +/*qt_pre.h*/ + diff --git a/win/Qt4/qt4rip.cpp b/win/Qt/qt_rip.cpp similarity index 70% rename from win/Qt4/qt4rip.cpp rename to win/Qt/qt_rip.cpp index d509f8895..cb2873dba 100644 --- a/win/Qt4/qt4rip.cpp +++ b/win/Qt/qt_rip.cpp @@ -2,28 +2,23 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4rip.cpp -- tombstone window +// qt_rip.cpp -- tombstone window +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif -#include "qt4rip.h" -#include "qt4bind.h" -#include "qt4str.h" +#include "qt_post.h" +#include "qt_rip.h" +#include "qt_bind.h" +#include "qt_str.h" -namespace nethack_qt4 { +namespace nethack_qt_ { QPixmap* NetHackQtRIP::pixmap=0; @@ -41,7 +36,7 @@ tryload(QPixmap& pm, const char* fn) { if (!pm.load(fn)) { QString msg; - msg.sprintf("Cannot load \"%s\"", fn); + msg = nh_qsprintf("Cannot load \"%s\"", fn); QMessageBox::warning(NetHackQtBind::mainWidget(), "IO Error", msg); } } @@ -69,7 +64,7 @@ QSize NetHackQtRIP::sizeHint() const return pixmap->size(); } -void NetHackQtRIP::paintEvent(QPaintEvent* event) +void NetHackQtRIP::paintEvent(QPaintEvent* event UNUSED) { if ( riplines ) { int pix_x=(width()-pixmap->width())/2; @@ -84,11 +79,17 @@ void NetHackQtRIP::paintEvent(QPaintEvent* event) painter.begin(this); painter.drawPixmap(pix_x,pix_y,*pixmap); for (int i=0; i= 202002L + static_cast(Qt::TextDontClip) + | static_cast(Qt::AlignHCenter), +#else + Qt::TextDontClip|Qt::AlignHCenter, +#endif + line[i]); } painter.end(); } } -} // namespace nethack_qt4 +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4rip.h b/win/Qt/qt_rip.h similarity index 84% rename from win/Qt4/qt4rip.h rename to win/Qt/qt_rip.h index 792a4e32f..97670f0d0 100644 --- a/win/Qt4/qt4rip.h +++ b/win/Qt/qt_rip.h @@ -2,12 +2,12 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4rip.h -- tombstone window +// qt_rip.h -- tombstone window #ifndef QT4RIP_H #define QT4RIP_H -namespace nethack_qt4 { +namespace nethack_qt_ { class NetHackQtRIP : public QWidget { private: @@ -25,6 +25,6 @@ class NetHackQtRIP : public QWidget { QSize sizeHint() const; }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_set.cpp b/win/Qt/qt_set.cpp new file mode 100644 index 000000000..2823e4dc0 --- /dev/null +++ b/win/Qt/qt_set.cpp @@ -0,0 +1,344 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_set.cpp -- Qt-specific settings, saved and restored by Qt so +// persist not just across save/restore but into new games. + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_set.h" +#include "qt_set.moc" +#include "qt_glyph.h" +#include "qt_main.h" +#include "qt_bind.h" +#include "qt_xcmd.h" +#include "qt_str.h" + +// Dialog box accessed via "Qt Settings..." in the games menu (non-OSX) +// or via "Preferences..." in the application menu (OSX): +//-- +// "Qt NetHack Settings" +// "Map:" [ ] Zoomed -- check box +// tilewidth -- number entry spinner +// tileheight -- ditto +// "Invent:" [ ] Shown -- check box +// dollwidth -- number entry spinner +// dollheight -- ditto +// "Font:" fontsize -- Huge:18pt, Large:14, Medium:12, Small:10, Tiny:8 +// [dismiss] -- button +//-- +// Map remembers 2 size pairs, one for Zoomed unchecked, another for checked. +// (Player controls whether the box is checked, using the dialog to manually +// switch back and forth if desired; nothing forces the Zoomed setting to +// specify larger tile size than not-Zoomed.) +// Paper doll inventory subset is shown or suppressed depending on check box. +// (It only remembers one tile size pair and that only matters when shown. +// The size could be different from both map settings but it is highly +// recommended that it match one of those unless Zoomed is never toggled.) +// Font size is used for message window and for text in the status window. +// (TODO: support separate font sizes for the two windows.) +// There's no way to undo or avoid saving any changes which player makes but +// all of the fields can be manually reversed. + +/* Used by tile/font-size patch below and in ../../src/files.c */ +char *qt_tilewidth=NULL; +char *qt_tileheight=NULL; +char *qt_fontsize=NULL; +#if defined(QWS) +int qt_compact_mode = 1; +#else +int qt_compact_mode = 0; +#endif + +namespace nethack_qt_ { + +#define TILEWMIN 6 +#define TILEHMIN 6 + +NetHackQtSettings::NetHackQtSettings() : + settings(), + whichsize("&Zoomed", this), + tilewidth(this), + tileheight(this), + widthlbl("Tile &width:", this), + heightlbl("Tile &height:", this), +#ifdef ENHANCED_PAPERDOLL + dollshown("&Shown", this), + dollwidth(this), + dollheight(this), + dollwidthlbl("&Doll width:", this), // should "Doll tile width"... + dollheightlbl("Doll height:", this), // ...but that's too verbose +#endif + fontsize(this), + normal("times"), +#ifdef WS_WIN + normalfixed("courier new"), +#else + normalfixed("courier"), +#endif + large("times"), + small("times"), + theglyphs(0) +{ + int default_fontsize; + + widthlbl.setBuddy(&tilewidth); + tilewidth.setRange(TILEWMIN, 128); + heightlbl.setBuddy(&tileheight); + tileheight.setRange(TILEHMIN, 128); + tilewidth.setValue(settings.value("tilewidth", 16).toInt()); + tileheight.setValue(settings.value("tileheight", 16).toInt()); +#ifdef ENHANCED_PAPERDOLL + dollwidthlbl.setBuddy(&dollwidth); + dollwidth.setRange(TILEWMIN, 48); + dollheightlbl.setBuddy(&dollheight); + dollheight.setRange(TILEHMIN, 48); + dollwidth.setValue(settings.value("dollwidth", 32).toInt()); + dollheight.setValue(settings.value("dollheight", 32).toInt()); + doll_is_shown = settings.value("dollShown", true).toBool(); + // needed the very first time + settings.setValue("dollShown", QVariant(doll_is_shown)); +#endif + default_fontsize = settings.value("fontsize", 2).toInt(); + + // these aren't currently part of the settings dialog; they're managed + // by the extended commands menu ('#' command) and updateXcmd() below + // but are included in qt_settings to be remembered across play sessions + xcmd_by_row = settings.value("xcmdByRow", false).toBool(); + xcmd_set = settings.value("xcmdSet", all_cmds).toInt(); + + // Tile/font sizes read from .nethackrc + if (qt_tilewidth != NULL) { + tilewidth.setValue(atoi(qt_tilewidth)); + free(qt_tilewidth); + qt_tilewidth = NULL; + } + if (qt_tileheight != NULL) { + tileheight.setValue(atoi(qt_tileheight)); + free(qt_tileheight); + qt_tileheight = NULL; + } + if (qt_fontsize != NULL) { + switch (tolower(qt_fontsize[0])) { + case 'h': default_fontsize = 0; break; + case 'l': default_fontsize = 1; break; + case 'm': default_fontsize = 2; break; + case 's': default_fontsize = 3; break; + case 't': default_fontsize = 4; break; + } + free(qt_fontsize); + qt_fontsize = NULL; + } + + theglyphs=new NetHackQtGlyphs(); + if (!theglyphs->no_tiles) { + resizeTiles(); + + connect(&whichsize, SIGNAL(toggled(bool)), this, + SLOT(setGlyphSize(bool))); + connect(&tilewidth, SIGNAL(valueChanged(int)), this, + SLOT(resizeTiles())); + connect(&tileheight, SIGNAL(valueChanged(int)), this, + SLOT(resizeTiles())); + +#ifdef ENHANCED_PAPERDOLL + connect(&dollshown, SIGNAL(toggled(bool)), this, + SLOT(setDollShown(bool))); + connect(&dollwidth, SIGNAL(valueChanged(int)), this, + SLOT(resizeDoll())); + connect(&dollheight, SIGNAL(valueChanged(int)), this, + SLOT(resizeDoll())); +#endif + } else { + // paper doll requires map tiles and those just failed to load + doll_is_shown = false; + } + + fontsize.setMinimumContentsLength((int) strlen("Medium")); + fontsize.addItem("Huge"); + fontsize.addItem("Large"); + fontsize.addItem("Medium"); + fontsize.addItem("Small"); + fontsize.addItem("Tiny"); + fontsize.setCurrentIndex(default_fontsize); + connect(&fontsize, SIGNAL(activated(int)), this, SLOT(changedFont())); + + int row = 0; // used like X11-style XtSetArg(), ++argc + QGridLayout *grid = new QGridLayout(this); + // dialog box label, spans first two rows and all three columns + QLabel *settings_label = new QLabel("Qt NetHack Settings\n", this); + grid->addWidget(settings_label, row, 0, 2, 3), row += 2; // uses extra row + settings_label->setAlignment(Qt::AlignHCenter | Qt::AlignTop); + + QLabel *map_label = new QLabel("&Map:", this); + map_label->setBuddy(&whichsize); + grid->addWidget(map_label, row, 0), // "Map: [ ]Zoomed" + grid->addWidget(&whichsize, row, 1), ++row; + grid->addWidget(&widthlbl, row, 1), + grid->addWidget(&tilewidth, row, 2), ++row; + grid->addWidget(&heightlbl, row, 1), + grid->addWidget(&tileheight, row, 2), ++row; + +#ifdef ENHANCED_PAPERDOLL + dollshown.QAbstractButton::setChecked(doll_is_shown); + QLabel *doll_label = new QLabel("&Invent:", this); + doll_label->setBuddy(&dollshown); + grid->addWidget(doll_label, row, 0), // "Invent: [ ]Shown" + grid->addWidget(&dollshown, row, 1), ++row; + grid->addWidget(&dollwidthlbl, row, 1), + grid->addWidget(&dollwidth, row, 2), ++row; + grid->addWidget(&dollheightlbl, row, 1), + grid->addWidget(&dollheight, row, 2), ++row; +#endif + + QLabel *flabel = new QLabel("&Font:", this); + flabel->setBuddy(&fontsize); + grid->addWidget(flabel, row, 0), + grid->addWidget(&fontsize, row, 1), ++row; + + QPushButton *dismiss = new QPushButton("Dismiss", this); + dismiss->setDefault(true); + grid->addWidget(dismiss, row, 0, 1, 3), ++row; + grid->setRowStretch(row - 1, 0); + grid->setColumnStretch(1, 1); + grid->setColumnStretch(2, 2); + grid->activate(); + + connect(dismiss, SIGNAL(clicked()), this, SLOT(accept())); + resize(150, 140); +} + +NetHackQtGlyphs& NetHackQtSettings::glyphs() +{ + // Caveat: + // 'theglyphs' will be Null if the tiles file couldn't be loaded; + // the game can still proceed with an ascii map in that situation. + return *theglyphs; +} + +void NetHackQtSettings::changedFont() +{ + settings.setValue("fontsize", fontsize.currentIndex()); + emit fontChanged(); +} + +void NetHackQtSettings::resizeTiles() +{ + tileWidth = tilewidth.value(); + tileHeight = tileheight.value(); + + settings.setValue("tilewidth", tileWidth); + settings.setValue("tileheight", tileHeight); + + if (theglyphs) { + theglyphs->setSize(tileWidth, tileHeight); + emit tilesChanged(); + } +} + +void NetHackQtSettings::toggleGlyphSize() +{ + whichsize.toggle(); +} + +void NetHackQtSettings::setGlyphSize(bool which UNUSED) +{ + QSize n = QSize(tilewidth.value(),tileheight.value()); + if ( othersize.isValid() ) { + tilewidth.blockSignals(true); + tileheight.blockSignals(true); + tilewidth.setValue(othersize.width()); + tileheight.setValue(othersize.height()); + tileheight.blockSignals(false); + tilewidth.blockSignals(false); + resizeTiles(); + } + othersize = n; +} + +#ifdef ENHANCED_PAPERDOLL +void NetHackQtSettings::resizeDoll() +{ + dollWidth = dollwidth.value(); + dollHeight = dollheight.value(); + + settings.setValue("dollwidth", dollWidth); + settings.setValue("dollheight", dollHeight); + settings.setValue("dollShown", doll_is_shown); + + //NetHackQtMainWindow::resizePaperDoll(doll_is_shown); + NetHackQtMainWindow *w = static_cast + (NetHackQtBind::mainWidget()); + w->resizePaperDoll(doll_is_shown); +} + +void NetHackQtSettings::toggleDollShown() +{ + dollshown.toggle(); +} + +void NetHackQtSettings::setDollShown(bool on_off) +{ + if (on_off != doll_is_shown) { + dollshown.QAbstractButton::setChecked(on_off); + doll_is_shown = on_off; + resizeDoll(); + } +} +#endif + +// called from NetHackQtExtCmdRequestor::Retry() +void NetHackQtSettings::updateXcmd(bool by_row, int which_set) +{ + // update 'settings' to have Qt store the revised values for next session + xcmd_by_row = by_row; + settings.setValue("xcmdByRow", QVariant(xcmd_by_row)); + xcmd_set = which_set; + settings.setValue("xcmdSet", xcmd_set); +} + +const QFont& NetHackQtSettings::normalFont() +{ + static int size[]={ 18, 14, 12, 10, 8 }; + normal.setPointSize(size[fontsize.currentIndex()]); + return normal; +} + +const QFont& NetHackQtSettings::normalFixedFont() +{ + static int size[]={ 18, 14, 13, 10, 8 }; + normalfixed.setPointSize(size[fontsize.currentIndex()]); + return normalfixed; +} + +const QFont& NetHackQtSettings::largeFont() +{ + static int size[]={ 24, 18, 14, 12, 10 }; + large.setPointSize(size[fontsize.currentIndex()]); + return large; +} + +const QFont& NetHackQtSettings::smallFont() +{ + static int size[]={ 14, 12, 10, 8, 8 }; + small.setPointSize(size[fontsize.currentIndex()]); + return small; +} + +bool NetHackQtSettings::ynInMessages() +{ + return !qt_compact_mode && !iflags.wc_popup_dialog; +} + +NetHackQtSettings* qt_settings; + +} // namespace nethack_qt_ diff --git a/win/Qt/qt_set.h b/win/Qt/qt_set.h new file mode 100644 index 000000000..99a2cf3cd --- /dev/null +++ b/win/Qt/qt_set.h @@ -0,0 +1,95 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_set.h -- the Qt settings + +#ifndef QT4SET_H +#define QT4SET_H + +#define ENHANCED_PAPERDOLL /* separate size from map tiles, can be hidden */ + +#include "qt_bind.h" // needed for mainWidget() for updateInventory() + +namespace nethack_qt_ { + +class NetHackQtGlyphs; +class NetHackQtMainWindow; + +class NetHackQtSettings : public QDialog { + Q_OBJECT +public: + int tileWidth = 16, tileHeight = 16; +#ifdef ENHANCED_PAPERDOLL + int dollWidth = 32, dollHeight = 32; + bool doll_is_shown = true; +#endif + bool xcmd_by_row = false; + int xcmd_set = 0; // all_cmds + + // dialog box for Qt-specific settings + NetHackQtSettings(); + + void updateXcmd(bool by_row, int which_set); + + NetHackQtGlyphs& glyphs(); + const QFont& normalFont(); + const QFont& normalFixedFont(); + const QFont& largeFont(); + const QFont& smallFont(); + + bool ynInMessages(); + +signals: + void fontChanged(); + void tilesChanged(); + +public slots: + void toggleGlyphSize(); + void setGlyphSize(bool); +#ifdef ENHANCED_PAPERDOLL + void toggleDollShown(); + void setDollShown(bool); + void resizeDoll(); +#endif + +private: + QSettings settings; + + QCheckBox whichsize; + QSpinBox tilewidth; + QSpinBox tileheight; + QLabel widthlbl; + QLabel heightlbl; + QSize othersize; +#ifdef ENHANCED_PAPERDOLL + QCheckBox dollshown; + QSpinBox dollwidth; + QSpinBox dollheight; + QLabel dollwidthlbl; + QLabel dollheightlbl; +#endif + + QComboBox fontsize; + + QFont normal, normalfixed, large, small; + + NetHackQtGlyphs* theglyphs; +#if 0 + void updateInventory() + { + static_cast (NetHackQtBind::mainWidget()) + ->updateInventory(); + } +#endif + +private slots: + void resizeTiles(); + void changedFont(); +}; + +extern NetHackQtSettings* qt_settings; + +} // namespace nethack_qt_ + +#endif diff --git a/win/Qt/qt_stat.cpp b/win/Qt/qt_stat.cpp new file mode 100644 index 000000000..13aae4108 --- /dev/null +++ b/win/Qt/qt_stat.cpp @@ -0,0 +1,1088 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_stat.cpp -- status window, upper right portion of the overall window +// +// The Qt status window consists of many lines: +// +// hitpoint bar (when enabled) +// Title (plname the Rank or plname the MonsterSpecies) +// Dungeon location (branch and level) +// separator line +// six icons (special 40x40 tiles, paired with...) +// six characteristic texts ("Str:18/03", "Dex:15", &c) +// separator line +// five status fields without icons (some containing two values: +// HP/HPmax, Energy/Enmax, AC, XpLevel/ExpPoints or HD, [blank], Gold) +// separator line +// line with two optional text fields (Time:1234, Score:89), maybe blank +// varying number of icons (one or more, each paired with...) +// corresponding text (Alignment plus zero or more status conditions +// including Hunger if not "normal" and encumbrance if not "normal") +// and version description (text only) right justified (when enabled) +// +// The hitpoint bar spans the width of the status window when enabled. +// Title and location are centered. +// The icons and text for the six characteristics are evenly spaced; +// this pair of lines is sometimes referred to as "row 1" below. +// The five main stats or slash-separated stat pairs are padded with an +// empty slot between Xp and Gold; adding the sixth makes that row +// line up with the characteristics; this line is sometimes referred +// to as "row 2". +// Time and Score are spaced as if each were three fields wide; their +// line is "row 3" relative to statuslines:2 vs statuslines:3. +// Icons and texts for alignment and conditions are left justified. +// The separator lines are thin and don't take up much vertical space. +// When enabled, the hitpoint bar bisects the margin above Title, +// increasing the overall status height by 9 pixels; when disabled, +// the status shifts up by those 9 pixels. +// When row 3 (Time, Score) is blank, it still takes up the vertical +// space that would be used to show those values. +// +// The above is for statuslines:3, which used to be the default. For +// statuslines:2, rows 1 and 2 are extended from six to seven fields +// and row 3 (optional Time, Score) is eliminated. Alignment is +// moved from the beginning of the Conditions pair (icon over text) +// of lines up to the end of row 1, the Characteristics pair of lines, +// with a separator between Cha:NN and it. Time, when active, is +// placed after Gold. Score, if enabled and active, is shown in the +// filler slot before Gold. When there are no Conditions to display, +// there is an invisible fake one (blank icon over blank text) +// rendered in order to preserve the vertical space they need. +// +// FIXME: +// When hitpoint bar is shown, attempting to resize horizontally won't +// do anything. Toggling it off, then resizing, and back On works. +// (Caused by specifying min-width and max-width constraints in the +// style sheets used to control color, but removing those constraints +// causes the bar display to get screwed up.) +// There are separate icons for Satiated and Hungry, but Weak, Fainting, +// and Fainted all share the Hungry one. Weak should have its own, +// Fainting+Fainted should have another. The current two depict +// plates with cutlery which is a bit of an anachronism. Satiated +// could be replaced by a figure in profile with a bulging belly, +// Hungry similar but with a slightly concave belly, Weak either a +// collapsing figure or a much larger concavity or both, Fainting/ +// Fainted a fully collapsed figure. +// If 'version' is being shown but gets squeezed by the cumulative width +// of conditions, the default clipping shows the center portion of the +// text string with beginning and end omitted. We want to force the +// end of the string to be shown with only the beginning omitted. +// +// TODO: +// If/when status conditions become too wide for the status window, scale +// down their icons and switch their text to a smaller font to match. +// Title and Location are explicitly rendered with a bigger font than +// the rest of status. That takes up more space, which is ok, but it +// also increases the vertical margin in between them by more than is +// necessary. Should squeeze some of that excess blank space out. +// + +extern "C" { +#include "hack.h" + +extern const char *const enc_stat[]; /* from botl.c */ +extern const char *const hu_stat[]; /* from eat.c */ +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_stat.h" +#include "qt_stat.moc" +#include "qt_set.h" +#include "qt_str.h" +#include "qt_xpms.h" + +extern int qt_compact_mode; + +namespace nethack_qt_ { + +NetHackQtStatusWindow::NetHackQtStatusWindow() : + /* first three rows: hitpoint bar, title (plname the Rank), location */ + hpbar_health(this), + hpbar_injury(this), + name(this,"(name)"), + dlevel(this,"(dlevel)"), + /* next two rows: icon over text label for the six characteristics */ + str(this, "Str"), + dex(this, "Dex"), + con(this, "Con"), + intel(this, "Int"), + wis(this, "Wis"), + cha(this, "Cha"), + /* sixth row, text only: some contain two slash-separated values */ + hp(this,"Hit Points"), + power(this,"Power"), + ac(this,"Armor Class"), + level(this,"Level"), // Xp level, with "/"+Exp points optionally appended + blank1(this, ""), // used for padding to align columns (was once 'exp') + gold(this,"Gold"), // gold used to be this row's first column, now last + /* seventh row: two optionally displayed values (just text, no icons) */ + time(this,"Time"), // if 'time' option On + score(this,"Score"), // if SCORE_ON_BOTL defined and 'showscore' option On + /* last two rows: alignment followed by conditions (icons over text) */ + align(this,"Alignment"), + blank2(this, " "), // used to prevent Conditions row from being empty + hunger(this,""), + encumber(this,""), + stoned(this,"Stone"), // major conditions + slimed(this,"Slime"), + strngld(this,"Strngl"), + sick_fp(this,"FoodPois"), + sick_il(this,"TermIll"), + stunned(this,"Stun"), // minor conditions + confused(this,"Conf"), + hallu(this,"Hallu"), + blind(this,"Blind"), + deaf(this,"Deaf"), + lev(this,"Lev"), // 'other' conditions + fly(this,"Fly"), + ride(this,"Ride"), + vers(this,""), // optional, right justified after 'conditions' + hline1(this), // separators + hline2(this), + hline3(this), + vline1(this), // vertical separator between Characteristics and Alignment + vline2(this), // padding for row 2 to match row 1's separator; not shown + /* miscellaneous; not display fields */ + cursy(0), + first_set(true), + alreadyfullhp(false), + was_polyd(false), + had_exp(false), + had_score(false), + prev_versinfo(0U) +{ + if (!qt_compact_mode) { + int w = NetHackQtBind::mainWidget()->width(); + setMaximumWidth(w / 2); + } + // for tool tips; they mostly work without this but sometimes changes + // to hunger or encumbrance seemed to cause tip display to stop + setMouseTracking(true); + + p_str = QPixmap(str_xpm); + p_str = QPixmap(str_xpm); + p_dex = QPixmap(dex_xpm); + p_con = QPixmap(cns_xpm); + p_int = QPixmap(int_xpm); + p_wis = QPixmap(wis_xpm); + p_cha = QPixmap(cha_xpm); + + p_chaotic = QPixmap(chaotic_xpm); + p_neutral = QPixmap(neutral_xpm); + p_lawful = QPixmap(lawful_xpm); + p_blank2 = QPixmap(blank_xpm); + + p_satiated = QPixmap(satiated_xpm); + p_hungry = QPixmap(hungry_xpm); + + p_encumber[0] = QPixmap(slt_enc_xpm); + p_encumber[1] = QPixmap(mod_enc_xpm); + p_encumber[2] = QPixmap(hvy_enc_xpm); + p_encumber[3] = QPixmap(ext_enc_xpm); + p_encumber[4] = QPixmap(ovr_enc_xpm); + + p_stoned = QPixmap(stone_xpm); + p_slimed = QPixmap(slime_xpm); + p_strngld = QPixmap(strngl_xpm); + p_sick_fp = QPixmap(sick_fp_xpm); + p_sick_il = QPixmap(sick_il_xpm); + p_stunned = QPixmap(stunned_xpm); + p_confused = QPixmap(confused_xpm); + p_hallu = QPixmap(hallu_xpm); + p_blind = QPixmap(blind_xpm); + p_deaf = QPixmap(deaf_xpm); + p_lev = QPixmap(lev_xpm); + p_fly = QPixmap(fly_xpm); + p_ride = QPixmap(ride_xpm); + + p_vers = QPixmap(blank_xpm); // same all-background pixmap as blank2 + + str.setIcon(p_str, "strength"); + dex.setIcon(p_dex, "dexterity"); + con.setIcon(p_con, "constitution"); + intel.setIcon(p_int, "intelligence"); + wis.setIcon(p_wis, "wisdom"); + cha.setIcon(p_cha, "charisma"); + + align.setIcon(p_neutral); + blank2.setIcon(p_blank2); // used for spacing when Conditions row is empty + hunger.setIcon(p_hungry); + encumber.setIcon(p_encumber[0]); + + stoned.setIcon(p_stoned, "turning to stone"); + slimed.setIcon(p_slimed, "turning into slime"); + strngld.setIcon(p_strngld, "being strangled"); + sick_fp.setIcon(p_sick_fp, "severe food poisoning"); + sick_il.setIcon(p_sick_il, "terminal illness"); + stunned.setIcon(p_stunned, "stunned"); + confused.setIcon(p_confused, "confused"); + hallu.setIcon(p_hallu, "hallucinating"); + blind.setIcon(p_blind, "cannot see"); + deaf.setIcon(p_deaf, "cannot hear"); + lev.setIcon(p_lev, "levitating"); + fly.setIcon(p_fly, "flying"); + ride.setIcon(p_ride, "riding"); + + vers.setIcon(p_vers); // used to align text-only version with conditions + + // separator lines +#if __cplusplus >= 202002L + hline1.setFrameStyle(static_cast(QFrame::HLine) + | static_cast(QFrame::Sunken)); + hline2.setFrameStyle(static_cast(QFrame::HLine) + | static_cast(QFrame::Sunken)); + hline3.setFrameStyle(static_cast(QFrame::HLine) + | static_cast(QFrame::Sunken)); +#else + hline1.setFrameStyle(QFrame::HLine | QFrame::Sunken); + hline2.setFrameStyle(QFrame::HLine | QFrame::Sunken); + hline3.setFrameStyle(QFrame::HLine | QFrame::Sunken); +#endif + hline1.setLineWidth(1); + hline2.setLineWidth(1); + hline3.setLineWidth(1); + // vertical separators for condensed layout (statuslines:2) +#if __cplusplus >= 202002L + vline1.setFrameStyle(static_cast(QFrame::VLine) + | static_cast(QFrame::Sunken)); + vline2.setFrameStyle(static_cast(QFrame::VLine) + | static_cast(QFrame::Sunken)); +#else + vline1.setFrameStyle(QFrame::VLine | QFrame::Sunken); + vline2.setFrameStyle(QFrame::VLine | QFrame::Sunken); +#endif + vline1.setLineWidth(1); // separates Alignment from Charisma + vline2.setLineWidth(1); + vline2.hide(); // padding to keep row 2 aligned with row 1, never shown + + // when 'hitpointbar' is On, the bar gets drawn above name/title + QHBoxLayout *hpbar = InitHitpointBar(); + + // 'statuslines' takes a value of 2 or 3; we use 3 as a request to put + // Alignment in front of status conditions so that line is never empty + // and to show Time and/or Score on their own line which might be empty + boolean spreadout = (::iflags.wc2_statuslines != 2); + +#if 1 //RLC + name.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + dlevel.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + QVBoxLayout *vbox = new QVBoxLayout(); + vbox->setSpacing(0); + vbox->addLayout(hpbar); // when 'hitpointbar' is enabled, it comes first + vbox->addWidget(&name); + vbox->addWidget(&dlevel); + vbox->addWidget(&hline1); + QHBoxLayout *charbox = new QHBoxLayout(); // Characteristics + charbox->addWidget(&str); + charbox->addWidget(&dex); + charbox->addWidget(&con); + charbox->addWidget(&intel); + charbox->addWidget(&wis); + charbox->addWidget(&cha); + if (!spreadout) { + // when condensed, include Alignment with Characteristics + charbox->addWidget(&vline1); // show a short vertical separator + charbox->addWidget(&align); + } + vbox->addLayout(charbox); + vbox->addWidget(&hline2); + QHBoxLayout *statbox = new QHBoxLayout(); // core status fields + statbox->addWidget(&hp); + statbox->addWidget(&power); + statbox->addWidget(&ac); + statbox->addWidget(&level); + if (spreadout) { + // when not condensed, put a blank field in front of Gold; + // Time and Score will be shown on their own separate line + statbox->addWidget(&blank1); // empty column #5 of 6 + statbox->addWidget(&gold); + } else { + // when condensed, display Time and Score on HP,...,Gold row +#ifndef SCORE_ON_BOTL + statbox->addWidget(&blank1); // empty column #5 of 7 +#else + statbox->addWidget(&score); // usually empty column #5 +#endif + statbox->addWidget(&gold); // columns 6 and maybe empty 7 + statbox->addWidget(&vline2); // padding between 6 and 7; not shown + statbox->addWidget(&time); + } + vbox->addLayout(statbox); + vbox->addWidget(&hline3); // separator before Time+Score or Conditions + if (spreadout) { + // when not condensed, put Time and Score on an extra row; since + // they're both optionally displayed, their row might be empty + // TODO? when neither will be shown, set their heights smaller + // and if either gets toggled On, set height back to normal + QHBoxLayout *timebox = new QHBoxLayout(); + timebox->addWidget(&time); + timebox->addWidget(&score); + vbox->addLayout(timebox); + } + QHBoxLayout *condbox = new QHBoxLayout(); // Conditions + if (spreadout) { + // when not condensed, include Alignment with Conditions to + // spread things out and also so that their row is never empty + condbox->addWidget(&align); + } else { + // otherwise place a padding widget on this row; it will be + // hidden if any Conditions are shown, or shown (with blank + // icon and empty text) when there aren't any, reserving + // space (the height of the row) for later conditions + condbox->addWidget(&blank2); + } + condbox->addWidget(&hunger); + condbox->addWidget(&encumber); + condbox->addWidget(&stoned); + condbox->addWidget(&slimed); + condbox->addWidget(&strngld); + condbox->addWidget(&sick_fp); + condbox->addWidget(&sick_il); + condbox->addWidget(&stunned); + condbox->addWidget(&confused); + condbox->addWidget(&hallu); + condbox->addWidget(&blind); + condbox->addWidget(&deaf); + condbox->addWidget(&lev); + condbox->addWidget(&fly); + condbox->addWidget(&ride); + condbox->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + // left justify conditions, whether 'vers' is present or absent + int stretch = 0; + condbox->addStretch(++stretch); // stretch==1 + // to right justify 'vers', use bigger stretch than condbox separator + condbox->addWidget(&vers, ++stretch, // stretch==2 + // text is below a blank icon, so bottom-aligned with the rest + // of the line with its text centered within that bottom area + Qt::AlignRight | Qt::AlignVCenter); + vbox->addLayout(condbox); + setLayout(vbox); +#endif + + connect(qt_settings, SIGNAL(fontChanged()), this, SLOT(doUpdate())); + doUpdate(); +} + +void NetHackQtStatusWindow::doUpdate() +{ + const QFont& large=qt_settings->largeFont(); + name.setFont(large); + dlevel.setFont(large); + + const QFont& normal=qt_settings->normalFont(); + str.setFont(normal); + dex.setFont(normal); + con.setFont(normal); + intel.setFont(normal); + wis.setFont(normal); + cha.setFont(normal); + hp.setFont(normal); + power.setFont(normal); + ac.setFont(normal); + level.setFont(normal); + blank1.setFont(normal); // padding + gold.setFont(normal); + time.setFont(normal); + score.setFont(normal); + align.setFont(normal); + // blank2 is used as a dummy condition when Alignment has been moved + // elsewhere (statuslines:2) and no other conditions currently apply; + // it has a blank icon with a label of a single space (if the label + // is completely empty, the rest of status shifts down a little when + // one or more real conditions replace it and shifts up again when + // all conditions are removed and this one is reinstated--as if "" is + // slightly taller than " ") + blank2.setFont(normal); + hunger.setFont(normal); + encumber.setFont(normal); + stoned.setFont(normal); + slimed.setFont(normal); + strngld.setFont(normal); + sick_fp.setFont(normal); + sick_il.setFont(normal); + stunned.setFont(normal); + confused.setFont(normal); + hallu.setFont(normal); + blind.setFont(normal); + deaf.setFont(normal); + lev.setFont(normal); + fly.setFont(normal); + ride.setFont(normal); + vers.setFont(normal); // shouldn't need small font + + updateStats(); +} + +QWidget* NetHackQtStatusWindow::Widget() { return this; } + +void NetHackQtStatusWindow::Clear() +{ +} +void NetHackQtStatusWindow::Display(bool block UNUSED) +{ +} +void NetHackQtStatusWindow::CursorTo(int,int y) +{ + cursy=y; +} +void NetHackQtStatusWindow::PutStr(int attr UNUSED, const QString& text UNUSED) +{ + // do a complete update when line 0 is done (as per X11 fancy status) + if (cursy==0) updateStats(); +} + +#if 0 // RLC +void NetHackQtStatusWindow::resizeEvent(QResizeEvent*) +{ +#if 0 + const float SP_name=0.13; // the (large) + const float SP_dlev=0.13; // Level 3 in The Dungeons of Doom (large) + const float SP_atr1=0.25; // STR DEX CON INT WIS CHA + const float SP_hln1=0.02; // --- + const float SP_atr2=0.09; // Au HP PW AC LVL EXP + const float SP_hln2=0.02; // --- + const float SP_time=0.09; // time score + const float SP_hln3=0.02; // --- + const float SP_stat=0.25; // Alignment, Poisoned, Hungry, Sick, etc. + + int h=height(); + int x=0,y=0; + + int iw; // Width of an item across line + int lh; // Height of a line of values + + lh=int(h*SP_name); + name.setGeometry(0,0,width(),lh); y+=lh; + lh=int(h*SP_dlev); + dlevel.setGeometry(0,y,width(),lh); y+=lh; + + lh=int(h*SP_hln1); + hline1.setGeometry(0,y,width(),lh); y+=lh; + + lh=int(h*SP_atr1); + iw=width()/6; + str.setGeometry(x,y,iw,lh); x+=iw; + dex.setGeometry(x,y,iw,lh); x+=iw; + con.setGeometry(x,y,iw,lh); x+=iw; + intel.setGeometry(x,y,iw,lh); x+=iw; + wis.setGeometry(x,y,iw,lh); x+=iw; + cha.setGeometry(x,y,iw,lh); x+=iw; + x=0; y+=lh; + + lh=int(h*SP_hln2); + hline2.setGeometry(0,y,width(),lh); y+=lh; + + lh=int(h*SP_atr2); + iw=width()/6; + gold.setGeometry(x,y,iw,lh); x+=iw; + hp.setGeometry(x,y,iw,lh); x+=iw; + power.setGeometry(x,y,iw,lh); x+=iw; + ac.setGeometry(x,y,iw,lh); x+=iw; + level.setGeometry(x,y,iw,lh); x+=iw; + //exp.setGeometry(x,y,iw,lh); x+=iw; + x=0; y+=lh; + + lh=int(h*SP_hln3); + hline3.setGeometry(0,y,width(),lh); y+=lh; + + lh=int(h*SP_time); + iw=width()/3; x+=iw/2; + time.setGeometry(x,y,iw,lh); x+=iw; + score.setGeometry(x,y,iw,lh); x+=iw; + x=0; y+=lh; + + lh=int(h*SP_stat); + iw=width()/9; + align.setGeometry(x,y,iw,lh); x+=iw; + hunger.setGeometry(x,y,iw,lh); x+=iw; + encumber.setGeometry(x,y,iw,lh); x+=iw; + stoned.setGeometry(x,y,iw,lh); x+=iw; + slimed.setGeometry(x,y,iw,lh); x+=iw; + strngld.setGeometry(x,y,iw,lh); x+=iw; + sick_fp.setGeometry(x,y,iw,lh); x+=iw; + sick_il.setGeometry(x,y,iw,lh); x+=iw; + stunned.setGeometry(x,y,iw,lh); x+=iw; + confused.setGeometry(x,y,iw,lh); x+=iw; + hallu.setGeometry(x,y,iw,lh); x+=iw; + blind.setGeometry(x,y,iw,lh); x+=iw; + deaf.setGeometry(x,y,iw,lh); x+=iw; + lev.setGeometry(x,y,iw,lh); x+=iw; + fly.setGeometry(x,y,iw,lh); x+=iw; + ride.setGeometry(x,y,iw,lh); x+=iw; +#if 0 + // [not fully implemented; this big chunk of code is no longer used] + //X = [get version, set font, measure width of version string] + vers.setGeometry(width() - X, y, width(), lh); x=width(); +#endif + x=0; y+=lh; +#else + // This is clumsy. But QLayout objects are proving balky. + + int row[10]; + + row[0] = name.sizeHint().height(); + row[1] = dlevel.sizeHint().height(); + row[2] = h.sizeHint().height(); +#endif +} +#endif + + +/* + * Set all widget values to a null string. This is used after all spacings + * have been calculated so that when the window is popped up we don't get all + * kinds of funny values being displayed. [Actually it isn't used at all.] + */ +void NetHackQtStatusWindow::nullOut() +{ +} + +void NetHackQtStatusWindow::fadeHighlighting() +{ + name.dissipateHighlight(); + dlevel.dissipateHighlight(); + + str.dissipateHighlight(); + dex.dissipateHighlight(); + con.dissipateHighlight(); + intel.dissipateHighlight(); + wis.dissipateHighlight(); + cha.dissipateHighlight(); + + gold.dissipateHighlight(); + hp.dissipateHighlight(); + power.dissipateHighlight(); + ac.dissipateHighlight(); + level.dissipateHighlight(); + align.dissipateHighlight(); + + //time.dissipateHighlight(); + score.dissipateHighlight(); + //vers.dissipateHighlight(); // never gets highlighted + + hunger.dissipateHighlight(); + encumber.dissipateHighlight(); + stoned.dissipateHighlight(); + slimed.dissipateHighlight(); + strngld.dissipateHighlight(); + sick_fp.dissipateHighlight(); + sick_il.dissipateHighlight(); + stunned.dissipateHighlight(); + confused.dissipateHighlight(); + hallu.dissipateHighlight(); + blind.dissipateHighlight(); + deaf.dissipateHighlight(); + lev.dissipateHighlight(); + fly.dissipateHighlight(); + ride.dissipateHighlight(); +} + +// hitpointbar: two panels: left==current health, right==missing max health +QHBoxLayout *NetHackQtStatusWindow::InitHitpointBar() +{ + hpbar_health.setFrameStyle(QFrame::NoFrame); + hpbar_health.setMaximumHeight(9); + hpbar_health.setAutoFillBackground(true); + if (!iflags.wc2_hitpointbar) + hpbar_health.hide(); + + hpbar_injury.setFrameStyle(QFrame::NoFrame); + /* health portion has thickness 9, injury portion just 3 */ + hpbar_injury.setMaximumHeight(3); + hpbar_injury.setContentsMargins(0, 3, 0, 3); // left,top,right,bottom + hpbar_injury.setAutoFillBackground(true); + hpbar_injury.hide(); // only shown when hitpointbar is On and uhp < uhpmax + + QHBoxLayout *hpbar = new QHBoxLayout; + hpbar->setSpacing(0); +#if QT_VERSION < 0x060000 + hpbar->setMargin(0); +#endif + hpbar->addWidget(&hpbar_health); + hpbar->setAlignment(&hpbar_health, Qt::AlignLeft); + hpbar->addWidget(&hpbar_injury); + hpbar->setAlignment(&hpbar_injury, Qt::AlignRight); + return hpbar; // caller will add our result to vbox layout +} + +DISABLE_WARNING_FORMAT_NONLITERAL + +// when hitpoint bar is enabled, calculate and draw it, otherwise remove it +void NetHackQtStatusWindow::HitpointBar() +{ + // a style sheet is used to specify color for otherwise blank labels; + // barcolors[][*]: column [0=left] is current health, [1=right] is injury + static const char + *styleformat = "QLabel { background-color : %s ; color : transparent ;" + " min-width : %d ; max-width %d }", + *barcolors[6][2] = { + { "black", "black" }, // 100% /* second black never shown */ + { "blue", "darkBlue" }, //75..99 + /* gray is darker than darkGray for some reason (at least on OSX); + default green is too dark compared to blue, yellow, orange, + and red so is changed here to green.lighter(150) */ + { "#00c000", "gray" }, //50..74 /* "green"=="#008000" */ + { "yellow", "darkGray" }, //25..49 + { "orange", "lightGray" }, //10..24 + { "red", "white" }, // 0..9 + }; + + /* + * tty and curses use inverse video characters in the left portion + * of the name+rank string to reflect hero's health. We draw a + * separate line above the name+rank field instead. The left side + * of the line indicates current health. The right side is only + * shown when injured and indicates missing amount of maximum health. + */ + if (iflags.wc2_hitpointbar) { + int colorindx, w, + ihp = Upolyd ? u.mh : u.uhp, + ihpmax = Upolyd ? u.mhmax : u.uhpmax; + ihp = std::max(std::min(ihp, ihpmax), 0); + int pct = 100 * ihp / ihpmax, + lox = hline1.x(), + hix = lox + hline1.width() - 1; + QRect geoH = hpbar_health.geometry(), + geoI = hpbar_injury.geometry(); + QString styleH, styleI; + + if (ihp < ihpmax) { + // health is less than full; + // use red for extreme low health even if the percentage is + // above the usual threshold (which will happen when maximum + // health is very low); do a similar threshold override for + // orange even though it can be distracting for low level hero + colorindx = (pct < 10 || ihp < 5) ? 5 // red | white + : (pct < 25 || ihp < 10 ) ? 4 // orange | lightGray + : (pct < 50) ? 3 // yellow | darkGray* + : (pct < 75) ? 2 // green | gray* + : 1; // blue | darkBlue + + int pxl_health = (hix - lox + 1) * ihp / ihpmax; + geoH.setRight(std::min(lox + pxl_health - 1, hix)); + hpbar_health.setGeometry(geoH); + w = geoH.right() - geoH.left() + 1; // might yield 0 (ie, if dead) + styleH = nh_qsprintf(styleformat, barcolors[colorindx][0], w, w); + hpbar_health.setStyleSheet(styleH); + // when healing, having the old injury-side shown while the new + // health-side expands pushes the injury farther right and it's + // momentarily visible there before it gets recalculated+redrawn + hpbar_injury.hide(); // will re-show below + hpbar_health.show(); // don't need to hide() if/when width is 0 + + int oldleft = geoI.left(); + geoI.setLeft(geoH.right() + 1); + geoI.setRight(hix); + hpbar_injury.setGeometry(geoI); + w = geoI.right() - geoI.left() + 1; + styleI = nh_qsprintf(styleformat, barcolors[colorindx][1], w, w); + hpbar_injury.setStyleSheet(styleI); + if (geoI.left() != oldleft) + hpbar_injury.move(geoI.left(), geoI.top()); + hpbar_injury.show(); + + alreadyfullhp = false; + } else if (!alreadyfullhp) { // skip if unchanged + // health is full + colorindx = 0; // black | (not used) + + hpbar_injury.hide(); + geoI.setLeft(hix); // hix + 1 + hpbar_injury.setGeometry(geoI); + + geoH.setRight(hix); + hpbar_health.setGeometry(geoH); + w = geoH.right() - geoH.left() + 1; + styleH = nh_qsprintf(styleformat, barcolors[colorindx][0], w, w); + hpbar_health.setStyleSheet(styleH); + hpbar_health.show(); + + alreadyfullhp = true; + } + } else { + // hitpoint bar is disabled + hpbar_health.hide(); + hpbar_injury.hide(); + alreadyfullhp = false; + } +} + +RESTORE_WARNING_FORMAT_NONLITERAL + +/* + * Update the displayed status. The current code in botl.c updates + * two lines of information. Both lines are always updated one after + * the other. So only do our update when we update the second line. + * + * Information on the first line: + * name, Str/Dex/&c characteristics, alignment, score + * + * Information on the second line: + * dlvl, gold, hp, power, ac, {level & exp or HD **} + * status (hunger, encumbrance, sick, stun, conf, halu, blind), time + * + * [**] HD is shown instead of level and exp when hero is polymorphed. + */ +void NetHackQtStatusWindow::updateStats() +{ + if (!parentWidget()) return; + if (cursy != 0) return; /* do a complete update when line 0 is done */ + + QString buf; + + if (first_set) { + // set toggle-detection flags for optional fields + was_polyd = Upolyd ? true : false; + had_exp = ::flags.showexp ? true : false; + // not conditionalized upon '#ifdef SCORE_ON_BOTL' here + had_score = ::flags.showscore ? true : false; // false when disabled + score.setLabel(""); // init if enabled, one-time set if disabled + } + // display hitpoint bar if it is active; it isn't subject to field + // highlighting so we don't track whether it has just been toggled On|Off + HitpointBar(); + + int st = ACURR(A_STR); + if (st > STR18(100)) { + buf = nh_qsprintf("Str:%d", st - 100); // 19..25 + } else if (st == STR18(100)) { + buf = nh_qsprintf("Str:18/**"); // 18/100 + } else if (st > 18) { + buf = nh_qsprintf("Str:18/%02d", st - 18); // 18/01..18/99 + } else { + buf = nh_qsprintf("Str:%d", st); // 3..18 + } + str.setLabel(buf, NetHackQtLabelledIcon::NoNum, (long) st); + dex.setLabel("Dex:", (long) ACURR(A_DEX)); + con.setLabel("Con:", (long) ACURR(A_CON)); + intel.setLabel("Int:", (long) ACURR(A_INT)); + wis.setLabel("Wis:", (long) ACURR(A_WIS)); + cha.setLabel("Cha:", (long) ACURR(A_CHA)); + + boolean spreadout = (::iflags.wc2_statuslines != 2); + int k = 0; // number of conditions shown + + long qt_uhs = 0L; + const char *hung = hu_stat[u.uhs]; + QString qhung = QString(hung).trimmed(); + if (hung[0]==' ') { + if (!hunger.isHidden()) { + hunger.setLabel("", NetHackQtLabelledIcon::NoNum, qt_uhs); + hunger.hide(); + } + } else { + // satiated is worse (due to risk of death from overeating) + // than not-hungry and we'll treat it as also worse than hungry, + // but better than weak or fainting; the u.uhs enum values + // order them differently so we jump through a hoop + switch (u.uhs) { + case NOT_HUNGRY: qt_uhs = 0L; break; + case HUNGRY: qt_uhs = 1L; break; + case SATIATED: qt_uhs = 2L; break; + case WEAK: qt_uhs = 3L; break; + case FAINTING: qt_uhs = 4L; break; + default: qt_uhs = 5L; break; // fainted, starved + } + hunger.setIcon(u.uhs ? p_hungry : p_satiated, qhung.toLower()); + hunger.setLabel(qhung, NetHackQtLabelledIcon::NoNum, qt_uhs); + hunger.ForceResize(); + ++k, hunger.show(); + } + long encindx = (long) near_capacity(); + const char *enc = enc_stat[encindx]; + if (enc[0]==' ' || !enc[0]) { + if (!encumber.isHidden()) { + encumber.setLabel("", NetHackQtLabelledIcon::NoNum, encindx); + encumber.hide(); + } + } else { + encumber.setIcon(p_encumber[encindx - 1], QString(enc).toLower()); + encumber.setLabel(enc, NetHackQtLabelledIcon::NoNum, encindx); + encumber.ForceResize(); + ++k, encumber.show(); + } + + if (Stoned) ++k, stoned.show(); else stoned.hide(); + if (Slimed) ++k, slimed.show(); else slimed.hide(); + if (Strangled) ++k, strngld.show(); else strngld.hide(); + if (Sick) { + /* FoodPois or TermIll or both */ + if (u.usick_type & SICK_VOMITABLE) { /* food poisoning */ + ++k, sick_fp.show(); + } else { + sick_fp.hide(); + } + if (u.usick_type & SICK_NONVOMITABLE) { /* terminally ill */ + ++k, sick_il.show(); + } else { + sick_il.hide(); + } + } else { + sick_fp.hide(); + sick_il.hide(); + } + if (Stunned) ++k, stunned.show(); else stunned.hide(); + if (Confusion) ++k, confused.show(); else confused.hide(); + if (Hallucination) ++k, hallu.show(); else hallu.hide(); + if (Blind) ++k, blind.show(); else blind.hide(); + if (Deaf) ++k, deaf.show(); else deaf.hide(); + + // flying is blocked when levitating, so Lev and Fly are mutually exclusive + if (Levitation) ++k, lev.show(); else lev.hide(); + if (Flying) ++k, fly.show(); else fly.hide(); + if (u.usteed) ++k, ride.show(); else ride.hide(); + + // version is optional; displayed to the right of conditions when present + if (::flags.showvers) { + // the value only changes if user modifies the 'versinfo' option + if (::flags.versinfo != prev_versinfo) { + char vbuf[80], *cvers = status_version(vbuf, sizeof vbuf, FALSE); + vers.setLabel(QString(cvers)); + // FIXME: this shouldn't be necessary but without hide() before + // forthcoming show(), the new value isn't appearing + if (!vers.isHidden()) vers.hide(); + prev_versinfo = ::flags.versinfo; + } + ++k, vers.show(); + } else + vers.hide(); + + if (Upolyd) { + buf = nh_capitalize_words(pmname(&mons[u.umonnum], + ::flags.female ? FEMALE : MALE)); + } else { + buf = rank_of(u.ulevel, svp.pl_character[0], ::flags.female); + } + QString buf2; + char buf3[BUFSZ]; + buf2 = nh_qsprintf("%s the %s", upstart(strcpy(buf3, svp.plname)), + buf.toLatin1().constData()); + name.setLabel(buf2, NetHackQtLabelledIcon::NoNum, u.ulevel); + + if (!describe_level(buf3, 0)) { + Sprintf(buf3, "%s, level %d", + svd.dungeons[u.uz.dnum].dname, ::depth(&u.uz)); + } + dlevel.setLabel(buf3); + + int poly_toggled = !was_polyd ^ !Upolyd; + int exp_toggled = !had_exp ^ !::flags.showexp; + if (poly_toggled) + // for this update, changed values aren't better|worse, just different + hp.setCompareMode(NeitherIsBetter); + if (poly_toggled || exp_toggled) + level.setCompareMode(NeitherIsBetter); + if (Upolyd) { + // You're a monster! + buf = nh_qsprintf("/%d", u.mhmax); + hp.setLabel("HP:", std::max((long) u.mh, 0L), buf); + level.setLabel("HD:", (long) mons[u.umonnum].mlevel); // hit dice + // Exp points are not shown when HD is displayed instead of Xp level + } else { + // You're normal. + buf = nh_qsprintf("/%d", u.uhpmax); + hp.setLabel("HP:", std::max((long) u.uhp, 0L), buf); + // if Exp points are to be displayed, append them to Xp level; + // up/down highlighting becomes tricky--don't try very hard; + // depending upon font size and status layout, "Level:NN/nnnnnnnn" + // might be too wide to fit + static const char *const lvllbl[3] = { "Level:", "Lvl:", "L:" }; + QFontMetrics fm(level.label->font()); + for (int i = ::flags.showexp ? 0 : 3; i < 4; ++i) { + // passes 0,1,2 are with Exp, 3 is without Exp and always fits + if (i < 3) { + buf = nh_qsprintf("%s%ld/%ld", lvllbl[i], (long) u.ulevel, + u.uexp); + } else { + buf = nh_qsprintf("%s%ld", lvllbl[i - 3], (long) u.ulevel); + } + // +2: allow a couple of pixels at either end to be clipped off + if (fm.size(0, buf).width() <= (2 + level.label->width() + 2)) + break; + } + level.setLabel(buf, NetHackQtLabelledIcon::NoNum, + // if we intended to show Exp but must settle + // for Xp due to width, we still want to use + // Exp for setLabel()'s Up|Down highlighting + ::flags.showexp ? u.uexp : (long) u.ulevel); + } + if (poly_toggled) + // for next update, changed values will be better|worse as usual + hp.setCompareMode(BiggerIsBetter); + if (poly_toggled || exp_toggled) + level.setCompareMode(BiggerIsBetter); + was_polyd = Upolyd ? true : false; + had_exp = (::flags.showexp && !was_polyd) ? true : false; + + buf = nh_qsprintf("/%d", u.uenmax); + power.setLabel("Pow:", (long) u.uen, buf); + ac.setLabel("AC:", (long) u.uac); + // gold prefix used to be "Au:", tty uses "$:"; never too wide to fit; + // practical limit due to carrying capacity limit is less than 300K + long goldamt = money_cnt(gi.invent); + goldamt = std::max(goldamt, 0L); // sanity; core's botl() does likewise + goldamt = std::min(goldamt, 99999999L); // ditto + gold.setLabel("Gold:", goldamt); + + const char *text; + QString qtext; + QPixmap *pxmp; + if (u.ualign.type == A_LAWFUL) { + pxmp = &p_lawful; + text = "Lawful"; + } else if (u.ualign.type == A_NEUTRAL) { + pxmp = &p_neutral; + text = "Neutral"; + } else { + pxmp = &p_chaotic; + // Unaligned should never happen + text = (u.ualign.type == A_CHAOTIC) ? "Chaotic" + : (u.ualign.type == A_NONE) ? "unaligned" + : "other?"; + } + qtext = nh_qsprintf("%sly aligned", text); + align.setIcon(*pxmp, qtext.toLower()); + align.setLabel(QString(text)); + // without this, the ankh pixmap shifts from centered to left + // justified relative to the label text for some unknown reason... + align.ForceResize(); + if (spreadout) + ++k; // when not condensed, Alignment is shown on the Conditions row + + if (!k) { + blank2.show(); // for vertical spacing: force the row to be non-empty + } else + blank2.hide(); + + // Time isn't highlighted (due to constantly changing) so we don't keep + // track of whether it has just been toggled On or Off + if (::flags.time) { + // hypothetically Time could grow to enough digits to have trouble + // fitting, but it's not worth worrying about + time.setLabel("Time:", (long) svm.moves); + } else { + time.setLabel(""); + } + +#ifdef SCORE_ON_BOTL + int score_toggled = !had_score ^ !::flags.showscore; + if (::flags.showscore) { + if (score_toggled) // toggled On + score.setCompareMode(NeitherIsBetter); + long pts = botl_score(); + if (spreadout) { + // plenty of room; Time and Score both have the width of 3 fields + score.setLabel("Score:", pts); + } else { + // depending upon font size and status layout, "Score:nnnnnnnn" + // might be too wide to fit (simpler version of Level:NN/nnnnnnnn) + static const char *const scrlbl[3] = { "Score:", "Scr:", "S:" }; + QFontMetrics fm(score.label->font()); + for (int i = 0; i < 3; ++i) { + buf = nh_qsprintf("%s%ld", scrlbl[i], pts); + // +2: allow couple of pixels at either end to be clipped off + if (fm.size(0, buf).width() <= (2 + score.width() + 2)) + break; + } + score.setLabel(buf, NetHackQtLabelledIcon::NoNum, pts); + // with Xp/Exp, we fallback to Xp if the shortest label prefix + // is still too long; here we just show a clipped value and + // let user either live with it or turn 'showscore' off (or + // set statuslines:3 to take advantage of the extra room that + // the spread out status layout provides) + } + } else { + if (score_toggled) { // toggled Off; if already Off, no need to set "" + score.setCompareMode(NoCompare); + score.setLabel(""); // blank when not active + } + } + if (score_toggled) + score.setCompareMode(BiggerIsBetter); + had_score = ::flags.showscore ? true : false; +#endif /* SCORE_ON_BOTL */ + + if (first_set) { + first_set=false; + + /* + * Default compareMode is BiggerIsBetter: an increased value + * is an improvement. + */ + name.highlightWhenChanging(); + dlevel.highlightWhenChanging(); + dlevel.setCompareMode(NeitherIsBetter); + + str.highlightWhenChanging(); + dex.highlightWhenChanging(); + con.highlightWhenChanging(); + intel.highlightWhenChanging(); + wis.highlightWhenChanging(); + cha.highlightWhenChanging(); + + hp.highlightWhenChanging(); + power.highlightWhenChanging(); + ac.highlightWhenChanging(); + ac.setCompareMode(SmallerIsBetter); + level.highlightWhenChanging(); + gold.highlightWhenChanging(); + + // don't highlight 'time' because it changes almost continuously + // [if we did highlight it, we wouldn't show increase as 'Better'] + //time.highlightWhenChanging(); time.setCompareMode(NeitherIsBetter); + score.highlightWhenChanging(); + + align.highlightWhenChanging(); + align.setCompareMode(NeitherIsBetter); + + hunger.highlightWhenChanging(); + hunger.setCompareMode(SmallerIsBetter); + encumber.highlightWhenChanging(); + encumber.setCompareMode(SmallerIsBetter); + stoned.highlightWhenChanging(); + slimed.highlightWhenChanging(); + strngld.highlightWhenChanging(); + sick_fp.highlightWhenChanging(); + sick_il.highlightWhenChanging(); + stunned.highlightWhenChanging(); + confused.highlightWhenChanging(); + hallu.highlightWhenChanging(); + blind.highlightWhenChanging(); + deaf.highlightWhenChanging(); + // the default behavior is to highlight a newly shown condition + // as "worse" but that isn't appropriate for 'other' conds; + // NetHackQtLabelledIcon::show() uses NeitherIsBetter to handle it + lev.highlightWhenChanging(); + lev.setCompareMode(NeitherIsBetter); + fly.highlightWhenChanging(); + fly.setCompareMode(NeitherIsBetter); + ride.highlightWhenChanging(); + ride.setCompareMode(NeitherIsBetter); + // not a true status condition; doesn't change (unless 'showvers' + // gets toggled or 'versinfo' is modified) so doesn't get highlighted + vers.setCompareMode(NoCompare); + } +} + +/* + * Turn off hilighted status values after a certain amount of turns. + */ +void NetHackQtStatusWindow::checkTurnEvents() +{ +} + +// clicking on status window runs #attributes (^X) +void NetHackQtStatusWindow::mousePressEvent(QMouseEvent *event UNUSED) +{ + QWidget *main = NetHackQtBind::mainWidget(); + (static_cast (main))->FuncAsCommand(doattributes); +} + +} // namespace nethack_qt_ diff --git a/win/Qt/qt_stat.h b/win/Qt/qt_stat.h new file mode 100644 index 000000000..43cf2f154 --- /dev/null +++ b/win/Qt/qt_stat.h @@ -0,0 +1,160 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_stat.h -- bindings between the Qt 4 interface and the main code + +#ifndef QT4STAT_H +#define QT4STAT_H + +#include "qt_win.h" +#include "qt_icon.h" + +namespace nethack_qt_ { + +class NetHackQtStatusWindow : QWidget, public NetHackQtWindow { + Q_OBJECT +public: + NetHackQtStatusWindow(); + + virtual QWidget* Widget(); + + virtual void Clear(); + virtual void Display(bool block); + virtual void CursorTo(int x,int y); + virtual void PutStr(int attr, const QString& text); + + void fadeHighlighting(); + +protected: + virtual void mousePressEvent(QMouseEvent *event); + //RLC void resizeEvent(QResizeEvent*); + +private slots: + void doUpdate(); + +private: + enum { hilight_time=1 }; + + QPixmap p_str; + QPixmap p_dex; + QPixmap p_con; + QPixmap p_int; + QPixmap p_wis; + QPixmap p_cha; + + QPixmap p_chaotic; + QPixmap p_neutral; + QPixmap p_lawful; + QPixmap p_blank2; // conditionally used for vertical spacing + + QPixmap p_satiated; + QPixmap p_hungry; + QPixmap p_encumber[5]; + + QPixmap p_stoned; + QPixmap p_slimed; + QPixmap p_strngld; + QPixmap p_sick_fp; + QPixmap p_sick_il; + QPixmap p_stunned; + QPixmap p_confused; + QPixmap p_hallu; + QPixmap p_blind; + QPixmap p_deaf; + QPixmap p_lev; + QPixmap p_fly; + QPixmap p_ride; + QPixmap p_vers; // version, when shown, is like a pseudo-condition + + /* + * Status fields, in display order (the three separator lines + * are exceptions). Hitpoint bar is optionally displayed and + * contains two side-by-side parts; neither part is labelled. + */ + QLabel hpbar_health; // hit point bar, left half + QLabel hpbar_injury; // hit point bar, right half + NetHackQtLabelledIcon name; // (aka title) centered on its own row + NetHackQtLabelledIcon dlevel; // (aka location) likewise + + /* the six characteristics; each is shown with a 40x40 icon above + and a text label below, so implicitly two rows */ + NetHackQtLabelledIcon str; + NetHackQtLabelledIcon dex; + NetHackQtLabelledIcon con; + NetHackQtLabelledIcon intel; + NetHackQtLabelledIcon wis; + NetHackQtLabelledIcon cha; + + /* five various status fields, some showing two values, shown as + a row of text only; 'exp' used to be a separate field but is + now displayed with 'level', with a blank field where it was so + that there continue to be six columns which line up beneath the + characteristics; gold used to be left-most but doesn't warrant + that position; Xp or Xp/Exp is replaced by HD when polymorphed */ + NetHackQtLabelledIcon hp; // current HP / maximum HP + NetHackQtLabelledIcon power; // current energy / maximum energy + NetHackQtLabelledIcon ac; // armor class + NetHackQtLabelledIcon level; // Xp level / Exp points (if 'showexp') + NetHackQtLabelledIcon blank1; // pads the line to six columns + NetHackQtLabelledIcon gold; // used to come before HP + + /* next row: two more fields, possibly blank; when present, each + is sized as if for three fields, so their centered values line + up with 2nd and 5th columns of the rows above */ + NetHackQtLabelledIcon time; // moves counter (if 'time' is set) + NetHackQtLabelledIcon score; // tentative score (if compiled with + // SCORE_ON_BOTL and 'showscore' is set) + + /* last rows: alignment and zero or more status conditions; + like the characteristics, they are shown as if in two rows with + a 40x40 icon above and text lebel below; blank values are omitted + and non-blank values are left justified */ + NetHackQtLabelledIcon align; // w/ alignment-specific ankh icon + NetHackQtLabelledIcon blank2; // used for spacing if Align is moved + NetHackQtLabelledIcon hunger; // blank if 'normal' + NetHackQtLabelledIcon encumber; // blank if 'unencumbered' ('normal') + /* zero or more status conditions; in major, minor, 'other' order */ + NetHackQtLabelledIcon stoned; + NetHackQtLabelledIcon slimed; + NetHackQtLabelledIcon strngld; + NetHackQtLabelledIcon sick_fp; + NetHackQtLabelledIcon sick_il; + NetHackQtLabelledIcon stunned; + NetHackQtLabelledIcon confused; + NetHackQtLabelledIcon hallu; + NetHackQtLabelledIcon blind; + NetHackQtLabelledIcon deaf; + NetHackQtLabelledIcon lev; + NetHackQtLabelledIcon fly; + NetHackQtLabelledIcon ride; + /* to right of conditions, right justified */ + NetHackQtLabelledIcon vers; // version + + QFrame hline1; // between dlevel and characteristics + QFrame hline2; // between characteristics and regular status fields + QFrame hline3; // between regular fields and time,score or conditions + QFrame vline1; // for statuslines:2, between Cha and Alignment + QFrame vline2; // for statuslines:2, padding between Gold and Time + + int cursy; + bool first_set; + bool alreadyfullhp; + + // for some fields, we need to know more than just "changed since + // last update"; there's no 'had_time' because Time isn't highlighted + bool was_polyd; + bool had_exp; + bool had_score; + unsigned prev_versinfo; + + QHBoxLayout *InitHitpointBar(); + void HitpointBar(); + void nullOut(); + void updateStats(); + void checkTurnEvents(); +}; + +} // namespace nethack_qt_ + +#endif diff --git a/win/Qt4/qt4str.cpp b/win/Qt/qt_str.cpp similarity index 84% rename from win/Qt4/qt4str.cpp rename to win/Qt/qt_str.cpp index b6b4440eb..764dd07bd 100644 --- a/win/Qt4/qt4str.cpp +++ b/win/Qt/qt_str.cpp @@ -2,25 +2,26 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4str.cpp -- some string functions +// qt_str.cpp -- some string functions #include #include -#include "qt4str.h" +#include +#include "qt_str.h" -namespace nethack_qt4 { +namespace nethack_qt_ { // Bounded string copy size_t str_copy(char *dest, const char *src, size_t max) { - size_t len = strlen(src); + size_t len = 0; if (max != 0) { - size_t csize = len; + len = strlen(src); if (len > max - 1) { len = max - 1; } - memcpy(dest, src, csize); - dest[csize] = '\0'; + memcpy(dest, src, len); + dest[len] = '\0'; } return len; } @@ -35,7 +36,7 @@ QString str_titlecase(const QString& str) QString nh_capitalize_words(const QString& str) { QStringList words = str.split(" "); - for (size_t i = 0; i < words.size(); ++i) { + for (size_t i = 0; i < (size_t) words.size(); ++i) { words[i] = str_titlecase(words[i]); } return words.join(" "); @@ -80,4 +81,20 @@ int cp437(int ch) return cp437table[(unsigned char)ch]; } -} // namespace nethack_qt4 +QString +nh_qsprintf(const char *format, ...) +{ + QString msg; + std::va_list args; + + va_start(args, format); +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + msg = QString::vasprintf(format, args); +#else + msg.vsprintf(format, args); +#endif + va_end(args); + return msg; +} + +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4str.h b/win/Qt/qt_str.h similarity index 65% rename from win/Qt4/qt4str.h rename to win/Qt/qt_str.h index 05f25f4c4..9bc8f66e0 100644 --- a/win/Qt4/qt4str.h +++ b/win/Qt/qt_str.h @@ -2,12 +2,12 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4str.h -- various string functions +// qt_str.h -- various string functions #ifndef QT4STR_H #define QT4STR_H -namespace nethack_qt4 { +namespace nethack_qt_ { // Bounded string copy extern size_t str_copy(char *dest, const char *src, size_t max); @@ -19,6 +19,13 @@ extern QString nh_capitalize_words(const QString& str); // Map symbol conversion extern int cp437(int ch); -} // namespace nethack_qt4 +// sprintf +extern QString nh_qsprintf(const char *format, ...) +#if defined(__GNUC__) && (__GNUC__ >= 2) + __attribute__((format(printf, 1, 2))) +#endif +; + +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_streq.cpp b/win/Qt/qt_streq.cpp new file mode 100644 index 000000000..dc6712a4d --- /dev/null +++ b/win/Qt/qt_streq.cpp @@ -0,0 +1,112 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_streq.cpp -- string requestor + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_streq.h" +#include "qt_str.h" +#include "qt_set.h" + +namespace nethack_qt_ { + +// temporary +void centerOnMain(QWidget *); +// end temporary + +NetHackQtStringRequestor::NetHackQtStringRequestor(QWidget *parent, + const char *p, const char *cancelstr, const char *okaystr) : + QDialog(parent), + prompt(QString::fromLatin1(p),this), + input(this,"input") +{ + if (qt_settings) + input.setFont(qt_settings->normalFixedFont()); + + cancel=new QPushButton(cancelstr,this); + connect(cancel,SIGNAL(clicked()),this,SLOT(reject())); + + okay = new QPushButton(okaystr, this); + connect(okay,SIGNAL(clicked()),this,SLOT(accept())); + connect(&input,SIGNAL(returnPressed()),this,SLOT(accept())); + okay->setDefault(true); + + setFocusPolicy(Qt::StrongFocus); +} + +void NetHackQtStringRequestor::resizeEvent(QResizeEvent*) +{ + const int margin=5; + const int gutter=5; + + int h = (height() - margin * 2 - gutter); + int w = (width() - margin * 2 - gutter); + int ifw = input.hasFrame() ? 3 : 0; // hack alert for input.frameWidth() + if (prompt.text().size() > 16) { + h /= 3; + prompt.setGeometry(margin + ifw * 2 + 1, margin, w + gutter, h); + input.setGeometry(width() * 1 / 5 - ifw, margin + h + gutter, + w * 4 / 5, h); + } else { + h /= 2; + prompt.setGeometry(margin + ifw * 2 + 1, margin, w * 2 / 5, h); + input.setGeometry(prompt.geometry().right() + gutter + - (ifw * 2 + 1) - ifw * 2, + margin, w * 3 / 5, h); + } + + cancel->setGeometry(margin, input.geometry().bottom() + gutter, w / 2, h); + okay->setGeometry(cancel->geometry().right() + gutter, + cancel->geometry().y(), w / 2, h); +} + +void NetHackQtStringRequestor::SetDefault(const char *d) +{ + input.setText(d); +} + +bool NetHackQtStringRequestor::Get(char *buffer, int maxchar, int minchar) +{ + input.setMaxLength(maxchar - 1); + + const QString &txt = prompt.text(); + int pw = fontMetrics().QFM_WIDTH(txt), + ww = minchar * input.fontMetrics().QFM_WIDTH(QChar('X')); + int heightfactor = ((txt.size() > 16) ? 3 : 2) * 2; // 2 or 3 lines high + int widthfudge = (((txt.size() > 16) ? 1 : 2) * 5) * 2; // 5: margn, guttr + resize(pw + ww + widthfudge, fontMetrics().height() * heightfactor); + +#ifdef EDIT_GETLIN + input.setText(buffer); +#endif + centerOnMain(this); + show(); + // Make sure that setFocus() really does change keyboard focus. + // This allows typing to go directly to the NetHackQtLineEdit + // widget without clicking on or in it first. Not needed for + // qt_getline() but is needed for menu Search to prevent typed + // characters being treated as making menu selections. + if (!input.isActiveWindow()) + input.activateWindow(); + input.setFocus(); + exec(); + + if (result()) { + str_copy(buffer, input.text().toLatin1().constData(), maxchar); + return true; + } else { + return false; + } +} + +} // namespace nethack_qt_ diff --git a/win/Qt/qt_streq.h b/win/Qt/qt_streq.h new file mode 100644 index 000000000..89894dc03 --- /dev/null +++ b/win/Qt/qt_streq.h @@ -0,0 +1,33 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_streq.h -- string requestor + +#ifndef QT4STREQ_H +#define QT4STREQ_H + +#include "qt_line.h" + +namespace nethack_qt_ { + +class NetHackQtStringRequestor : QDialog { +private: + QLabel prompt; + NetHackQtLineEdit input; + QPushButton* okay; + QPushButton* cancel; + +public: + NetHackQtStringRequestor(QWidget *parent, const char *p, + const char *cancelstr = "Cancel", + const char *okaystr = "Okay"); + void SetDefault(const char *); + // maxchar is size of buffer[], minchar is size of line edit widget + bool Get(char *buffer, int maxchar = 80, int minchar = 20); + virtual void resizeEvent(QResizeEvent *); +}; + +} // namespace nethack_qt_ + +#endif diff --git a/win/Qt/qt_svsel.cpp b/win/Qt/qt_svsel.cpp new file mode 100644 index 000000000..f08c0aa25 --- /dev/null +++ b/win/Qt/qt_svsel.cpp @@ -0,0 +1,121 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_svsel.cpp -- saved game selector +// +// Popup's layout: +//---- +// NetHack 5.0.x (literal text w/ dynamic version number) +// /----------------------\ (text to prevent multi-line comment warning) +// | | +// | | +// | splash image | nhsplash.xpm (red dragon w/ rider) +// | | +// | | +// \----------------------/ +// by the NetHack DevTeam (literal text) +// [ Quit ] [New-Game] side-by-side buttons +// Saved characters (literal text in small font) +// [ character one ] button with character name +// [ character two ] button with another character name +// [ character three ] button with yet another character name +// ... as many buttons as needed +//---- +// +// FIXME: +// If there are a lot of saved games available, the selection dialog +// needs vertical scrolling capability. +// +// Note: +// The code in this file is not used if the program is built without +// having SELECTSAVED defined or if the run-time option 'selectsaved' +// is False. SELECTSAVED used to be forced for Qt but isn't any more. +// However, we include this code unconditionally. +// + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_svsel.h" +#include "qt_bind.h" +#include "qt_str.h" + +namespace nethack_qt_ { + +// +// popup dialog at start of game to choose between a new game or which save +// file to load if user has at least one saved game and either hasn't supplied +// any character name or has supplied one which doesn't have a save file +// +NetHackQtSavedGameSelector::NetHackQtSavedGameSelector(const char** saved) : + QDialog(NetHackQtBind::mainWidget()) +{ + QVBoxLayout *vbl = new QVBoxLayout(this); + QHBoxLayout* hb; + + char cvers[BUFSZ]; + QString qvers = QString("NetHack ") + QString(version_string(cvers, sizeof cvers)); + QLabel *vers = new QLabel(qvers, this); + vers->setAlignment(Qt::AlignCenter); + vbl->addWidget(vers); + + QLabel *logo = new QLabel(this); + logo->setAlignment(Qt::AlignCenter); + logo->setPixmap(QPixmap("nhsplash.xpm")); + vbl->addWidget(logo); + + QLabel *attr = new QLabel("by the NetHack DevTeam", this); + attr->setAlignment(Qt::AlignCenter); + vbl->addWidget(attr); + vbl->addStretch(2); + + /* With Qt5, this next line triggers a complaint to stderr: +QLayout: Attempting to add QLayout "" to QDialog "", which already has a layout + hb = new QHBoxLayout(this); + */ + hb = new QHBoxLayout((QWidget *) NULL); + vbl->addLayout(hb, Qt::AlignCenter); + + QPushButton *q = new QPushButton("Quit", this); + hb->addWidget(q); + connect(q, SIGNAL(clicked()), this, SLOT(reject())); + QPushButton *c = new QPushButton("New Game", this); + hb->addWidget(c); + connect(c, SIGNAL(clicked()), this, SLOT(accept())); + c->setDefault(true); + + QGroupBox *box = new QGroupBox("Saved Characters", this); + QVBoxLayout *bgl = new QVBoxLayout(); + QButtonGroup *bg = new QButtonGroup(); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + connect(bg, SIGNAL(idPressed(int)), this, SLOT(done(int))); +#else + connect(bg, SIGNAL(buttonPressed(int)), this, SLOT(done(int))); +#endif + for (int i = 0; saved[i]; ++i) { + QPushButton *b = new QPushButton(saved[i]); + bgl->addWidget(b); + bg->addButton(b, i + 2); + } + box->setLayout(bgl); + vbl->addWidget(box); +} + +int NetHackQtSavedGameSelector::choose() +{ +#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). + if ( qt_compact_mode ) + showMaximized(); +#endif + return exec() - 2; +} + +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4svsel.h b/win/Qt/qt_svsel.h similarity index 79% rename from win/Qt4/qt4svsel.h rename to win/Qt/qt_svsel.h index 918e6f7e3..3a5498758 100644 --- a/win/Qt4/qt4svsel.h +++ b/win/Qt/qt_svsel.h @@ -2,12 +2,12 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4svsel.h -- saved game selector +// qt_svsel.h -- saved game selector #ifndef QT4SVSEL_H #define QT4SVSEL_H -namespace nethack_qt4 { +namespace nethack_qt_ { class NetHackQtSavedGameSelector : public QDialog { public: @@ -16,6 +16,6 @@ class NetHackQtSavedGameSelector : public QDialog { int choose(); }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_win.cpp b/win/Qt/qt_win.cpp index 6d560f1ce..db66579f6 100644 --- a/win/Qt/qt_win.cpp +++ b/win/Qt/qt_win.cpp @@ -1,8 +1,8 @@ -// NetHack 3.6 qt_win.cpp $NHDT-Date: 1524684508 2018/04/25 19:28:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.77 $ // Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// Qt Binding for NetHack 3.4 +// Qt Windowing interface for NetHack 5.0 // // Copyright (C) 1996-2001 by Warwick W. Allison (warwick@troll.no) // @@ -22,11 +22,11 @@ // and also because this is my first major application of Qt. // // The problem of NetHack's getkey requirement is solved by intercepting -// key events by overiding QApplicion::notify(...), and putting them in +// key events by overriding QApplication::notify(...), and putting them in // a buffer. Mouse clicks on the map window are treated with a similar // buffer. When the NetHack engine calls for a key, one is taken from -// the buffer, or if that is empty, QApplication::enter_loop() is called. -// Whenever keys or clicks go into the buffer, QApplication::exit_loop() +// the buffer, or if that is empty, QApplication::exec() is called. +// Whenever keys or clicks go into the buffer, QApplication::exit() // is called. // // Another problem is that some NetHack players are decade-long players who @@ -40,1400 +40,55 @@ // by the key event buffer. // -extern "C" { - // This includes all the definitions we need from the NetHack main // engine. We pretend MSC is a STDC compiler, because C++ is close // enough, and we undefine NetHack macros which conflict with Qt -// identifiers. - -#define alloc hide_alloc // avoid treading on STL symbol -#define lock hide_lock // avoid treading on STL symbol -#ifdef _MSC_VER -#define NHSTDC -#endif -#include "hack.h" -#include "func_tab.h" -#include "dlb.h" -#include "patchlevel.h" -#include "tile2x11.h" -#undef Invisible -#undef Warning -#undef red -#undef green -#undef blue -#undef Black -#undef curs -#undef TRUE -#undef FALSE -#undef min -#undef max -#undef alloc -#undef lock -#undef yn - -} - -#include "qt_win.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -//#include - -#include - -#include "qt_clust.h" -#include "qt_xpms.h" - -#include -#ifdef Q_WS_MACX -# include -#else -# include -#endif - -#ifdef _WS_X11_ -// For userid control -#include -#endif - -// Some distributors released Qt 2.1.0beta4 -#if QT_VERSION < 220 -# define nh_WX11BypassWM 0x01000000 -#else -# define nh_WX11BypassWM WX11BypassWM -#endif - -#ifdef USER_SOUNDS -# if QT_VERSION < 220 -# undef USER_SOUNDS -# else -# include -# endif -#endif - - -#ifdef USER_SOUNDS -extern "C" void play_sound_for_message(const char* str); -#endif - -#ifdef SAFERHANGUP -#include -#endif - -// Warwick prefers it this way... -#define QT_CHOOSE_RACE_FIRST - -static const char nh_attribution[] = "
NetHack" - "
by the NetHack DevTeam
"; - -static QString -aboutMsg() -{ - QString msg; - msg.sprintf( - "Qt NetHack is a version of NetHack built\n" -#ifdef KDE - "using KDE and the Qt GUI toolkit.\n" -#else - "using the Qt GUI toolkit.\n" -#endif - "This is version %d.%d.%d\n\n" - "Homepage:\n http://trolls.troll.no/warwick/nethack/\n\n" -#ifdef KDE - "KDE:\n http://www.kde.org\n" -#endif - "Qt:\n http://www.troll.no", - VERSION_MAJOR, - VERSION_MINOR, - PATCHLEVEL); - return msg; -} - -static void -centerOnMain( QWidget* w ) -{ - QWidget* m = qApp->mainWidget(); - if (!m) m = qApp->desktop(); - QPoint p = m->mapToGlobal(QPoint(0,0)); - w->move( p.x() + m->width()/2 - w->width()/2, - p.y() + m->height()/2 - w->height()/2 ); -} - -NetHackQtLineEdit::NetHackQtLineEdit() : - QLineEdit(0) -{ -} - -NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name) : - QLineEdit(parent,name) -{ -} - -void NetHackQtLineEdit::fakeEvent(int key, int ascii, int state) -{ - QKeyEvent fake(QEvent::KeyPress,key,ascii,state); - keyPressEvent(&fake); -} +// identifiers (now done in qt_pre.h). +#define QT_DEPRECATED_WARNINGS extern "C" { -/* Used by tile/font-size patch below and in ../../src/files.c */ -char *qt_tilewidth=NULL; -char *qt_tileheight=NULL; -char *qt_fontsize=NULL; -#if defined(QWS) -int qt_compact_mode = 1; -#else -int qt_compact_mode = 0; -#endif -extern const char *enc_stat[]; /* from botl.c */ -extern const char *hu_stat[]; /* from eat.c */ -extern int total_tiles_used; // from tile.c -extern short glyph2tile[]; // from tile.c -} - -static int tilefile_tile_W=16; -static int tilefile_tile_H=16; - -#define TILEWMIN 1 -#define TILEHMIN 1 - - -/* XPM */ -static const char * nh_icon[] = { -"40 40 6 1", -" s None c none", -". c #ffffff", -"X c #dadab6", -"o c #6c91b6", -"O c #476c6c", -"+ c #000000", -" ", -" ", -" ", -" . .X..XX.XX X ", -" .. .....X.XXXXXX XX ", -" ... ....X..XX.XXXXX XXX ", -" .. ..........X.XXXXXXXXXXX XX ", -" .... ........X..XX.XXXXXXXXX XXXX ", -" .... ..........X.XXXXXXXXXXX XXXX ", -" ooOOO..ooooooOooOOoOOOOOOOXX+++OO++ ", -" ooOOO..ooooooooOoOOOOOOOOOXX+++OO++ ", -" ....O..ooooooOooOOoOOOOOOOXX+XXXX++ ", -" ....O..ooooooooOoOOOOOOOOOXX+XXXX++ ", -" ..OOO..ooooooOooOOoOOOOOOOXX+++XX++ ", -" ++++..ooooooooOoOOOOOOOOOXX+++ +++ ", -" +++..ooooooOooOOoOOOOOOOXX+++ + ", -" ++..ooooooooOoOOOOOOOOOXX+++ ", -" ..ooooooOooOOoOOOOOOOXX+++ ", -" ..ooooooooOoOOOOOOOOOXX+++ ", -" ..ooooooOooOOoOOOOOOOXX+++ ", -" ..ooooooooOoOOOOOOOOOXX+++ ", -" ..oooooOooOOoOOOOOOXX+++ ", -" ..oooooooOoOOOOOOOOXX+++ ", -" ..ooooOooOOoOOOOOXX+++ ", -" ..ooooooOoOOOOOOOXX++++ ", -" ..o..oooOooOOoOOOOXX+XX+++ ", -" ...o..oooooOoOOOOOXX++XXX++ ", -" ....OO..ooOooOOoOOXX+++XXXX++ ", -" ...oo..+..oooOoOOOXX++XXooXXX++ ", -" ...ooo..++..OooOOoXX+++XXooOXXX+ ", -" ..oooOOXX+++....XXXX++++XXOOoOOXX+ ", -" ..oooOOXX+++ ...XXX+++++XXOOooOXX++ ", -" ..oooOXXX+++ ..XX+++ +XXOOooOXX++ ", -" .....XXX++++ XXXXXXX++ ", -" ....XX++++ XXXXXXX+ ", -" ...XX+++ XXXXX++ ", -" ", -" ", -" ", -" "}; -/* XPM */ -static const char * nh_icon_small[] = { -/* width height ncolors chars_per_pixel */ -"16 16 16 1", -/* colors */ -" c #587070", -". c #D1D5C9", -"X c #8B8C84", -"o c #2A2A28", -"O c #9AABA9", -"+ c #6A8FB2", -"@ c #C4CAC4", -"# c #B6BEB6", -"$ c None", -"% c #54564E", -"& c #476C6C", -"* c #ADB2AB", -"= c #ABABA2", -"- c #5E8295", -"; c #8B988F", -": c #E8EAE7", -/* pixels */ -"$$$$$$$$$$$$$$$$", -"$$$.$#::.#==*$$$", -"$.*:::::....#*=$", -"$@#:..@#*==#;XX;", -"$@O:+++- &&; X%X", -"$#%.+++- &&;% oX", -"$$o.++-- &&;%%X$", -"$$$:++-- &&;%%$$", -"$$$.O++- &&=o $$", -"$$$=:++- & XoX$$", -"$$*:@O-- ;%Xo$$", -"$*:O#$+--;oOOX $", -"$:+ =o::=oo=-;%X", -"$::.%o$*;X;##@%$", -"$$@# ;$$$$$=*;X$", -"$$$$$$$$$$$$$$$$" -}; - -/* XPM */ -static const char * map_xpm[] = { -"12 13 4 1", -". c None", -" c #000000000000", -"X c #0000B6DAFFFF", -"o c #69A69248B6DA", -" .", -" XXXXX ooo ", -" XoooX o ", -" XoooX o o ", -" XoooX ooo ", -" XXoXX o ", -" oooooXXX ", -" oo o oooX ", -" o XooX ", -" oooo XooX ", -" o o XXXX ", -" ", -". "}; -/* XPM */ -static const char * msg_xpm[] = { -"12 13 4 1", -". c None", -" c #FFFFFFFFFFFF", -"X c #69A69248B6DA", -"o c #000000000000", -" .", -" XXX XXX X o", -" o", -" XXXXX XX o", -" o", -" XX XXXXX o", -" o", -" XXXXXX o", -" o", -" XX XXX XX o", -" o", -" o", -".ooooooooooo"}; -/* XPM */ -static const char * stat_xpm[] = { -"12 13 5 1", -" c None", -". c #FFFF00000000", -"X c #000000000000", -"o c #FFFFFFFF0000", -"O c #69A6FFFF0000", -" ", -" ", -"... ", -"...X ", -"...X ... ", -"oooX oooX", -"oooXooo oooX", -"OOOXOOOXOOOX", -"OOOXOOOXOOOX", -"OOOXOOOXOOOX", -"OOOXOOOXOOOX", -"OOOXOOOXOOOX", -" XXXXXXXXXXX"}; -/* XPM */ -static const char * info_xpm[] = { -"12 13 4 1", -" c None", -". c #00000000FFFF", -"X c #FFFFFFFFFFFF", -"o c #000000000000", -" ... ", -" ....... ", -" ...XXX... ", -" .........o ", -"...XXXX.... ", -"....XXX....o", -"....XXX....o", -"....XXX....o", -" ...XXX...oo", -" ..XXXXX..o ", -" .......oo ", -" o...ooo ", -" ooo "}; - - -/* XPM */ -static const char * again_xpm[] = { -"12 13 2 1", -" c None", -". c #000000000000", -" .. ", -" .. ", -" ..... ", -" ....... ", -"... .. .. ", -".. .. .. ", -".. ..", -".. ..", -".. ..", -" .. .. ", -" .......... ", -" ...... ", -" "}; -/* XPM */ -static const char * kick_xpm[] = { -"12 13 3 1", -" c None", -". c #000000000000", -"X c #FFFF6DB60000", -" ", -" ", -" . . . ", -" ... . . ", -" ... . ", -" ... . ", -" ... ", -"XXX ... ", -"XXX. ... ", -"XXX. ... ", -"XXX. .. ", -" ... ", -" "}; -/* XPM */ -static const char * throw_xpm[] = { -"12 13 3 1", -" c None", -". c #FFFF6DB60000", -"X c #000000000000", -" ", -" ", -" ", -" ", -".... X ", -"....X X ", -"....X XXXXXX", -"....X X ", -" XXXX X ", -" ", -" ", -" ", -" "}; -/* XPM */ -static const char * fire_xpm[] = { -"12 13 5 1", -" c None", -". c #B6DA45140000", -"X c #FFFFB6DA9658", -"o c #000000000000", -"O c #FFFF6DB60000", -" . ", -" X. ", -" X . ", -" X .o ", -" X . o ", -" X .o o ", -"OOOOOOOOoooo", -" X .o o ", -" X . o o ", -" X .o ", -" X. o ", -" . o ", -" o "}; -/* XPM */ -static const char * get_xpm[] = { -"12 13 3 1", -" c None", -". c #000000000000", -"X c #FFFF6DB60000", -" ", -" . ", -" ... ", -" . . . ", -" . ", -" . ", -" ", -" XXXXX ", -" XXXXX. ", -" XXXXX. ", -" XXXXX. ", -" ..... ", -" "}; -/* XPM */ -static const char * drop_xpm[] = { -"12 13 3 1", -" c None", -". c #FFFF6DB60000", -"X c #000000000000", -" ", -" ..... ", -" .....X ", -" .....X ", -" .....X ", -" XXXXX ", -" ", -" X ", -" X ", -" X X X ", -" XXX ", -" X ", -" "}; -/* XPM */ -static const char * eat_xpm[] = { -"12 13 4 1", -" c None", -". c #000000000000", -"X c #FFFFB6DA9658", -"o c #FFFF6DB60000", -" .X. .. ", -" .X. .. ", -" .X. .. ", -" .X. .. ", -" ... .. ", -" .. .. ", -" .. .. ", -" oo oo ", -" oo oo ", -" oo oo ", -" oo oo ", -" oo oo ", -" oo oo "}; -/* XPM */ -static const char * rest_xpm[] = { -"12 13 2 1", -" c None", -". c #000000000000", -" ..... ", -" . ", -" . ", -" . ....", -" ..... . ", -" . ", -" ....", -" ", -" .... ", -" . ", -" . ", -" .... ", -" "}; -/* XPM */ -static const char * cast_a_xpm[] = { -"12 13 3 1", -" c None", -". c #FFFF6DB60000", -"X c #000000000000", -" . ", -" . ", -" .. ", -" .. ", -" .. . ", -" .. . ", -" ...... ", -" .. .. XX ", -" .. X X ", -" .. X X ", -" .. XXXX ", -" . X X ", -" . X X "}; -/* XPM */ -static const char * cast_b_xpm[] = { -"12 13 3 1", -" c None", -". c #FFFF6DB60000", -"X c #000000000000", -" . ", -" . ", -" .. ", -" .. ", -" .. . ", -" .. . ", -" ...... ", -" .. .. XXX ", -" .. X X ", -" .. XXX ", -" .. X X ", -" . X X ", -" . XXX "}; -/* XPM */ -static const char * cast_c_xpm[] = { -"12 13 3 1", -" c None", -". c #FFFF6DB60000", -"X c #000000000000", -" . ", -" . ", -" .. ", -" .. ", -" .. . ", -" .. . ", -" ...... ", -" .. .. XX ", -" .. X X ", -" .. X ", -" .. X ", -" . X X ", -" . XX "}; - -NetHackQtSettings::NetHackQtSettings(int w, int h) : - tilewidth(TILEWMIN,64,1,this), - tileheight(TILEHMIN,64,1,this), - widthlbl(&tilewidth,"&Width:",this), - heightlbl(&tileheight,"&Height:",this), - whichsize("&Zoomed",this), - fontsize(this), - normal("times"), -#ifdef WS_WIN - normalfixed("courier new"), -#else - normalfixed("fixed"), -#endif - large("times"), - theglyphs(0) - -{ - int default_fontsize; - - if (w<=300) { - // ~240x320 - default_fontsize=4; - tilewidth.setValue(8); - tileheight.setValue(12); - } else if (w<=700) { - // ~640x480 - default_fontsize=3; - tilewidth.setValue(8); - tileheight.setValue(14); - } else if (w<=900) { - // ~800x600 - default_fontsize=3; - tilewidth.setValue(10); - tileheight.setValue(17); - } else if (w<=1100) { - // ~1024x768 - default_fontsize=2; - tilewidth.setValue(12); - tileheight.setValue(22); - } else if (w<=1200) { - // ~1152x900 - default_fontsize=1; - tilewidth.setValue(14); - tileheight.setValue(26); - } else { - // ~1280x1024 and larger - default_fontsize=0; - tilewidth.setValue(16); - tileheight.setValue(30); - } - - // Tile/font sizes read from .nethackrc - if (qt_tilewidth != NULL) { - tilewidth.setValue(atoi(qt_tilewidth)); - free(qt_tilewidth); - } - if (qt_tileheight != NULL) { - tileheight.setValue(atoi(qt_tileheight)); - free(qt_tileheight); - } - if (qt_fontsize != NULL) { - switch (tolower(qt_fontsize[0])) { - case 'h': default_fontsize = 0; break; - case 'l': default_fontsize = 1; break; - case 'm': default_fontsize = 2; break; - case 's': default_fontsize = 3; break; - case 't': default_fontsize = 4; break; - } - free(qt_fontsize); - } - - theglyphs=new NetHackQtGlyphs(); - resizeTiles(); - - connect(&tilewidth,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles())); - connect(&tileheight,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles())); - connect(&whichsize,SIGNAL(toggled(bool)),this,SLOT(setGlyphSize(bool))); - - fontsize.insertItem("Huge"); - fontsize.insertItem("Large"); - fontsize.insertItem("Medium"); - fontsize.insertItem("Small"); - fontsize.insertItem("Tiny"); - fontsize.setCurrentItem(default_fontsize); - connect(&fontsize,SIGNAL(activated(int)),this,SIGNAL(fontChanged())); - - QGridLayout* grid = new QGridLayout(this, 5, 2, 8); - grid->addMultiCellWidget(&whichsize, 0, 0, 0, 1); - grid->addWidget(&tilewidth, 1, 1); grid->addWidget(&widthlbl, 1, 0); - grid->addWidget(&tileheight, 2, 1); grid->addWidget(&heightlbl, 2, 0); - QLabel* flabel=new QLabel(&fontsize, "&Font:",this); - grid->addWidget(flabel, 3, 0); grid->addWidget(&fontsize, 3, 1); - QPushButton* dismiss=new QPushButton("Dismiss",this); - dismiss->setDefault(TRUE); - grid->addMultiCellWidget(dismiss, 4, 4, 0, 1); - grid->setRowStretch(4,0); - grid->setColStretch(1,1); - grid->setColStretch(2,2); - grid->activate(); - - connect(dismiss,SIGNAL(clicked()),this,SLOT(accept())); - resize(150,140); -} - -NetHackQtGlyphs& NetHackQtSettings::glyphs() -{ - return *theglyphs; -} - -void NetHackQtSettings::resizeTiles() -{ - int w = tilewidth.value(); - int h = tileheight.value(); - - theglyphs->setSize(w,h); - emit tilesChanged(); -} - -void NetHackQtSettings::toggleGlyphSize() -{ - whichsize.toggle(); -} - -void NetHackQtSettings::setGlyphSize(bool which) -{ - QSize n = QSize(tilewidth.value(),tileheight.value()); - if ( othersize.isValid() ) { - tilewidth.blockSignals(TRUE); - tileheight.blockSignals(TRUE); - tilewidth.setValue(othersize.width()); - tileheight.setValue(othersize.height()); - tileheight.blockSignals(FALSE); - tilewidth.blockSignals(FALSE); - resizeTiles(); - } - othersize = n; -} - -const QFont& NetHackQtSettings::normalFont() -{ - static int size[]={ 18, 14, 12, 10, 8 }; - normal.setPointSize(size[fontsize.currentItem()]); - return normal; -} - -const QFont& NetHackQtSettings::normalFixedFont() -{ - static int size[]={ 18, 14, 13, 10, 8 }; - normalfixed.setPointSize(size[fontsize.currentItem()]); - return normalfixed; -} - -const QFont& NetHackQtSettings::largeFont() -{ - static int size[]={ 24, 18, 14, 12, 10 }; - large.setPointSize(size[fontsize.currentItem()]); - return large; -} - -bool NetHackQtSettings::ynInMessages() -{ - return !qt_compact_mode; -} - - -NetHackQtSettings* qt_settings; - - - -NetHackQtKeyBuffer::NetHackQtKeyBuffer() : - in(0), out(0) -{ -} - -bool NetHackQtKeyBuffer::Empty() const { return in==out; } -bool NetHackQtKeyBuffer::Full() const { return (in+1)%maxkey==out; } - -void NetHackQtKeyBuffer::Put(int k, int a, int state) -{ - if ( Full() ) return; // Safety - key[in]=k; - ascii[in]=a; - in=(in+1)%maxkey; -} - -void NetHackQtKeyBuffer::Put(char a) -{ - Put(0,a,0); -} - -void NetHackQtKeyBuffer::Put(const char* str) -{ - while (*str) Put(*str++); -} - -int NetHackQtKeyBuffer::GetKey() -{ - if ( Empty() ) return 0; - int r=TopKey(); - out=(out+1)%maxkey; - return r; -} - -int NetHackQtKeyBuffer::GetAscii() -{ - if ( Empty() ) return 0; // Safety - int r=TopAscii(); - out=(out+1)%maxkey; - return r; -} - -int NetHackQtKeyBuffer::GetState() -{ - if ( Empty() ) return 0; - int r=TopState(); - out=(out+1)%maxkey; - return r; -} - -int NetHackQtKeyBuffer::TopKey() const -{ - if ( Empty() ) return 0; - return key[out]; -} - -int NetHackQtKeyBuffer::TopAscii() const -{ - if ( Empty() ) return 0; - return ascii[out]; -} - -int NetHackQtKeyBuffer::TopState() const -{ - if ( Empty() ) return 0; - return state[out]; -} - - -NetHackQtClickBuffer::NetHackQtClickBuffer() : - in(0), out(0) -{ -} - -bool NetHackQtClickBuffer::Empty() const { return in==out; } -bool NetHackQtClickBuffer::Full() const { return (in+1)%maxclick==out; } - -void NetHackQtClickBuffer::Put(int x, int y, int mod) -{ - click[in].x=x; - click[in].y=y; - click[in].mod=mod; - in=(in+1)%maxclick; -} - -int NetHackQtClickBuffer::NextX() const { return click[out].x; } -int NetHackQtClickBuffer::NextY() const { return click[out].y; } -int NetHackQtClickBuffer::NextMod() const { return click[out].mod; } - -void NetHackQtClickBuffer::Get() -{ - out=(out+1)%maxclick; -} - -class NhPSListViewItem : public QListViewItem { -public: - NhPSListViewItem( QListView* parent, const QString& name ) : - QListViewItem(parent, name) - { - } - - void setGlyph(int g) - { - NetHackQtGlyphs& glyphs = qt_settings->glyphs(); - int gw = glyphs.width(); - int gh = glyphs.height(); - QPixmap pm(gw,gh); - QPainter p(&pm); - glyphs.drawGlyph(p, g, 0, 0); - p.end(); - setPixmap(0,pm); - setHeight(QMAX(pm.height()+1,height())); - } - - void paintCell( QPainter *p, const QColorGroup &cg, - int column, int width, int alignment ) - { - if ( isSelectable() ) { - QListViewItem::paintCell( p, cg, column, width, alignment ); - } else { - QColorGroup disabled( - cg.foreground().light(), - cg.button().light(), - cg.light(), cg.dark(), cg.mid(), - gray, cg.base() ); - QListViewItem::paintCell( p, disabled, column, width, alignment ); - } - } -}; - -class NhPSListViewRole : public NhPSListViewItem { -public: - NhPSListViewRole( QListView* parent, int id ) : - NhPSListViewItem(parent, -#ifdef QT_CHOOSE_RACE_FIRST // Lowerize - looks better - QString(QChar(roles[id].name.m[0])).lower()+QString(roles[id].name.m+1) -#else - roles[id].name.m -#endif - ) - { - setGlyph(monnum_to_glyph(roles[id].malenum)); - } -}; - -class NhPSListViewRace : public NhPSListViewItem { -public: - NhPSListViewRace( QListView* parent, int id ) : - NhPSListViewItem(parent, -#ifdef QT_CHOOSE_RACE_FIRST // Capitalize - looks better - QString(QChar(races[id].noun[0])).upper()+QString(races[id].noun+1) -#else - QString(QChar(races[id].noun[0])+QString(races[id].noun+1)) -#endif - ) - { - setGlyph(monnum_to_glyph(races[id].malenum)); - } -}; - -class NhPSListView : public QListView { -public: - NhPSListView( QWidget* parent ) : - QListView(parent) - { - setSorting(-1); // order is identity - header()->setClickEnabled(FALSE); - } - - QSizePolicy sizePolicy() const - { - return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); - } - - QSize minimumSizeHint() const - { - return sizeHint(); - } - - QSize sizeHint() const - { - QListView::sizeHint(); - QSize sz = header()->sizeHint(); - int h=0; - QListViewItem* c=firstChild(); - while (c) h+=c->height(),c = c->nextSibling(); - sz += QSize(frameWidth()*2, h+frameWidth()*2); - return sz; - } - - int selectedItemNumber() const - { - int i=0; - QListViewItem* c = firstChild(); - while (c) { - if (c == selectedItem()) { - return i; - } - i++; - c = c->nextSibling(); - } - return -1; - } - - void setSelectedItemNumber(int i) - { - QListViewItem* c=firstChild(); - while (i--) - c = c->nextSibling(); - c->setSelected(TRUE); - } -}; - -NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : - QDialog(qApp->mainWidget(),"plsel",TRUE), - keysource(ks), - fully_specified_role(TRUE) -{ - /* - 0 1 2 - + Name ------------------------------------+ - 0 | | - + ---- ------------------------------------+ - + Role ---+ + Race ---+ + Gender ------+ - | | | | | * Male | - 1 | | | | | * Female | - | | | | +--------------+ - | | | | - | | | | + Alignment ---+ - 2 | | | | | * Male | - | | | | | * Female | - | | | | +--------------+ - 3 | | | | ...stretch... - | | | | - 4 | | | | [ Play ] - 5 | | | | [ Quit ] - +---------+ +---------+ - */ - - int marg=4; - QGridLayout *l = new QGridLayout(this,6,3,marg,marg); - - QButtonGroup* namebox = new QButtonGroup(1,Horizontal,"Name",this); - QLineEdit* name = new QLineEdit(namebox); - name->setMaxLength(sizeof(plname)-1); - if ( strncmp(plname,"player",6) && strncmp(plname,"games",5) ) - name->setText(plname); - connect(name, SIGNAL(textChanged(const QString&)), - this, SLOT(selectName(const QString&)) ); - name->setFocus(); - QButtonGroup* genderbox = new QButtonGroup("Sex",this); - QButtonGroup* alignbox = new QButtonGroup("Alignment",this); - QVBoxLayout* vbgb = new QVBoxLayout(genderbox,3,1); - vbgb->setAutoAdd(TRUE); - vbgb->addSpacing(fontMetrics().height()*3/4); - QVBoxLayout* vbab = new QVBoxLayout(alignbox,3,1); - vbab->setAutoAdd(TRUE); - vbab->addSpacing(fontMetrics().height()); - QLabel* logo = new QLabel(nh_attribution, this); - - l->addMultiCellWidget( namebox, 0,0,0,2 ); -#ifdef QT_CHOOSE_RACE_FIRST - race = new NhPSListView(this); - role = new NhPSListView(this); - l->addMultiCellWidget( race, 1,5,0,0 ); - l->addMultiCellWidget( role, 1,5,1,1 ); -#else - role = new NhPSListView(this); - race = new NhPSListView(this); - l->addMultiCellWidget( role, 1,5,0,0 ); - l->addMultiCellWidget( race, 1,5,1,1 ); -#endif - role->addColumn("Role"); - race->addColumn("Race"); - - l->addWidget( genderbox, 1, 2 ); - l->addWidget( alignbox, 2, 2 ); - l->addWidget( logo, 3, 2, AlignCenter ); - l->setRowStretch( 3, 5 ); - - int i; - int nrole; - - for (nrole=0; roles[nrole].name.m; nrole++) - ; - for (i=nrole-1; i>=0; i--) { // XXX QListView unsorted goes in rev. - new NhPSListViewRole( role, i ); - } - connect( role, SIGNAL(selectionChanged()), this, SLOT(selectRole()) ); - - int nrace; - for (nrace=0; races[nrace].noun; nrace++) - ; - for (i=nrace-1; i>=0; i--) { - new NhPSListViewRace( race, i ); - } - connect( race, SIGNAL(selectionChanged()), this, SLOT(selectRace()) ); - - gender = new QRadioButton*[ROLE_GENDERS]; - for (i=0; iaddWidget( ok, 4, 2 ); - ok->setDefault(TRUE); - connect( ok, SIGNAL(clicked()), this, SLOT(accept()) ); - - QPushButton* cancel = new QPushButton("Quit",this); - l->addWidget( cancel, 5, 2 ); - connect( cancel, SIGNAL(clicked()), this, SLOT(reject()) ); - - // Randomize race and role, unless specified in config - int ro = flags.initrole; - if (ro == ROLE_NONE || ro == ROLE_RANDOM) { - ro = rn2(nrole); - if (flags.initrole != ROLE_RANDOM) { - fully_specified_role = FALSE; - } - } - int ra = flags.initrace; - if (ra == ROLE_NONE || ra == ROLE_RANDOM) { - ra = rn2(nrace); - if (flags.initrace != ROLE_RANDOM) { - fully_specified_role = FALSE; - } - } - - // make sure we have a valid combination, honoring - // the users request if possible. - bool choose_race_first; -#ifdef QT_CHOOSE_RACE_FIRST - choose_race_first = TRUE; - if (flags.initrole >= 0 && flags.initrace < 0) { - choose_race_first = FALSE; - } -#else - choose_race_first = FALSE; - if (flags.initrace >= 0 && flags.initrole < 0) { - choose_race_first = TRUE; - } -#endif - while (!validrace(ro,ra)) { - if (choose_race_first) { - ro = rn2(nrole); - if (flags.initrole != ROLE_RANDOM) { - fully_specified_role = FALSE; - } - } else { - ra = rn2(nrace); - if (flags.initrace != ROLE_RANDOM) { - fully_specified_role = FALSE; - } - } - } - - int g = flags.initgend; - if (g == -1) { - g = rn2(ROLE_GENDERS); - fully_specified_role = FALSE; - } - while (!validgend(ro,ra,g)) { - g = rn2(ROLE_GENDERS); - } - gender[g]->setChecked(TRUE); - selectGender(g); - - int a = flags.initalign; - if (a == -1) { - a = rn2(ROLE_ALIGNS); - fully_specified_role = FALSE; - } - while (!validalign(ro,ra,a)) { - a = rn2(ROLE_ALIGNS); - } - alignment[a]->setChecked(TRUE); - selectAlignment(a); - - QListViewItem* li; - - li = role->firstChild(); - while (ro--) li=li->nextSibling(); - role->setSelected(li,TRUE); - - li = race->firstChild(); - while (ra--) li=li->nextSibling(); - race->setSelected(li,TRUE); - - flags.initrace = race->selectedItemNumber(); - flags.initrole = role->selectedItemNumber(); -} - - -void NetHackQtPlayerSelector::selectName(const QString& n) -{ - strncpy(plname,n.latin1(),sizeof(plname)-1); -} - -void NetHackQtPlayerSelector::selectRole() -{ - int ra = race->selectedItemNumber(); - int ro = role->selectedItemNumber(); - if (ra == -1 || ro == -1) return; - -#ifdef QT_CHOOSE_RACE_FIRST - selectRace(); -#else - QListViewItem* i=role->currentItem(); - QListViewItem* valid=0; - int j; - NhPSListViewItem* item; - item = (NhPSListViewItem*)role->firstChild(); - for (j=0; roles[j].name.m; j++) { - bool v = validrace(j,ra); - item->setSelectable(TRUE); - if ( !valid && v ) valid = item; - item=(NhPSListViewItem*)item->nextSibling(); - } - if ( !validrace(role->selectedItemNumber(),ra) ) - i = valid; - role->setSelected(i,TRUE); - item = (NhPSListViewItem*)role->firstChild(); - for (j=0; roles[j].name.m; j++) { - bool v = validrace(j,ra); - item->setSelectable(v); - item->repaint(); - item=(NhPSListViewItem*)item->nextSibling(); - } -#endif - - flags.initrole = role->selectedItemNumber(); - setupOthers(); -} - -void NetHackQtPlayerSelector::selectRace() -{ - int ra = race->selectedItemNumber(); - int ro = role->selectedItemNumber(); - if (ra == -1 || ro == -1) return; - -#ifndef QT_CHOOSE_RACE_FIRST - selectRole(); -#else - QListViewItem* i=race->currentItem(); - QListViewItem* valid=0; - int j; - NhPSListViewItem* item; - item = (NhPSListViewItem*)race->firstChild(); - for (j=0; races[j].noun; j++) { - bool v = validrace(ro,j); - item->setSelectable(TRUE); - if ( !valid && v ) valid = item; - item=(NhPSListViewItem*)item->nextSibling(); - } - if ( !validrace(ro,race->selectedItemNumber()) ) - i = valid; - race->setSelected(i,TRUE); - item = (NhPSListViewItem*)race->firstChild(); - for (j=0; races[j].noun; j++) { - bool v = validrace(ro,j); - item->setSelectable(v); - item->repaint(); - item=(NhPSListViewItem*)item->nextSibling(); - } -#endif - - flags.initrace = race->selectedItemNumber(); - setupOthers(); -} - -void NetHackQtPlayerSelector::setupOthers() -{ - int ro = role->selectedItemNumber(); - int ra = race->selectedItemNumber(); - int valid=-1; - int c=0; - int j; - for (j=0; jisChecked() ) - c = j; - gender[j]->setEnabled(v); - if ( valid<0 && v ) valid = j; - } - if ( !validgend(ro,ra,c) ) - c = valid; - int k; - for (k=0; ksetChecked(c==k); - } - selectGender(c); - - valid=-1; - for (j=0; jisChecked() ) - c = j; - alignment[j]->setEnabled(v); - if ( valid<0 && v ) valid = j; - } - if ( !validalign(ro,ra,c) ) - c = valid; - for (k=0; ksetChecked(c==k); - } - selectAlignment(c); -} - -void NetHackQtPlayerSelector::selectGender(int i) -{ - flags.initgend = i; -} - -void NetHackQtPlayerSelector::selectAlignment(int i) -{ - flags.initalign = i; -} - - -void NetHackQtPlayerSelector::done(int i) -{ - setResult(i); - qApp->exit_loop(); -} - -void NetHackQtPlayerSelector::Quit() -{ - done(R_Quit); - qApp->exit_loop(); -} - -void NetHackQtPlayerSelector::Random() -{ - done(R_Rand); - qApp->exit_loop(); +#include "hack.h" } -bool NetHackQtPlayerSelector::Choose() -{ - if (fully_specified_role) return TRUE; - -#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). - if ( qt_compact_mode ) { - showMaximized(); - } else +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include #endif - { - adjustSize(); - centerOnMain(this); - } - - if ( exec() ) { - return TRUE; - } else { - return FALSE; - } -} - - -NetHackQtStringRequestor::NetHackQtStringRequestor(NetHackQtKeyBuffer& ks, const char* p, const char* cancelstr) : - QDialog(qApp->mainWidget(),"string",FALSE), - prompt(p,this,"prompt"), - input(this,"input"), - keysource(ks) -{ - cancel=new QPushButton(cancelstr,this); - connect(cancel,SIGNAL(clicked()),this,SLOT(reject())); - - okay=new QPushButton("Okay",this); - connect(okay,SIGNAL(clicked()),this,SLOT(accept())); - connect(&input,SIGNAL(returnPressed()),this,SLOT(accept())); - okay->setDefault(TRUE); - - setFocusPolicy(StrongFocus); -} - -void NetHackQtStringRequestor::resizeEvent(QResizeEvent*) -{ - const int margin=5; - const int gutter=5; - - int h=(height()-margin*2-gutter); - - if (strlen(prompt.text()) > 16) { - h/=3; - prompt.setGeometry(margin,margin,width()-margin*2,h); - input.setGeometry(width()*1/5,margin+h+gutter, - (width()-margin-2-gutter)*4/5,h); - } else { - h/=2; - prompt.setGeometry(margin,margin,(width()-margin*2-gutter)*2/5,h); - input.setGeometry(prompt.geometry().right()+gutter,margin, - (width()-margin-2-gutter)*3/5,h); - } +#include "qt_post.h" - cancel->setGeometry(margin,input.geometry().bottom()+gutter, - (width()-margin*2-gutter)/2,h); - okay->setGeometry(cancel->geometry().right()+gutter,cancel->geometry().y(), - cancel->width(),h); -} - -void NetHackQtStringRequestor::SetDefault(const char* d) -{ - input.setText(d); -} +// Many of these headers are not needed here. It's a holdover +// from when most of the Qt code was in one big file. +#include "qt_win.h" +#include "qt_bind.h" +#include "qt_click.h" +#include "qt_glyph.h" +#include "qt_inv.h" +#include "qt_key.h" +#include "qt_icon.h" +#include "qt_map.h" +#include "qt_menu.h" +#include "qt_msg.h" +#include "qt_set.h" -bool NetHackQtStringRequestor::Get(char* buffer, int maxchar) -{ - input.setMaxLength(maxchar); - if (strlen(prompt.text()) > 16) { - resize(fontMetrics().width(prompt.text())+50,fontMetrics().height()*6); - } else { - resize(fontMetrics().width(prompt.text())*2+50,fontMetrics().height()*4); - } +#include "qt_clust.h" - centerOnMain(this); - show(); - input.setFocus(); - setResult(-1); - while (result()==-1) { - // Put keys in buffer (eg. from macros, from out-of-focus input) - if (!keysource.Empty()) { - while (!keysource.Empty()) { - int key=keysource.TopKey(); - int ascii=keysource.TopAscii(); - int state=keysource.GetState(); - if (ascii=='\r' || ascii=='\n') { - // CR or LF in buffer causes confirmation - strcpy(buffer,input.text()); - return TRUE; - } else if (ascii=='\033') { - return FALSE; - } else { - input.fakeEvent(key,ascii,state); - } - } - } - qApp->enter_loop(); - } - // XXX Get rid of extra keys, since we couldn't get focus! - while (!keysource.Empty()) keysource.GetKey(); +namespace nethack_qt_ { - if (result()) { - strcpy(buffer,input.text()); - return TRUE; - } else { - return FALSE; - } -} -void NetHackQtStringRequestor::done(int i) +void +centerOnMain(QWidget *w) { - setResult(i); - qApp->exit_loop(); + QPoint p(0, 0); + QWidget *m = NetHackQtBind::mainWidget(); + if (m) + p = m->mapToGlobal(p); + w->move(p.x() + m->width() / 2 - w->width() / 2, + p.y() + m->height() / 2 - w->height() / 2); } - NetHackQtWindow::NetHackQtWindow() { } - NetHackQtWindow::~NetHackQtWindow() { } @@ -1441,3872 +96,22 @@ NetHackQtWindow::~NetHackQtWindow() // XXX Use "expected ..." for now, abort or default later. // void NetHackQtWindow::Clear() { puts("unexpected Clear"); } -void NetHackQtWindow::Display(bool block) { puts("unexpected Display"); } -bool NetHackQtWindow::Destroy() { return TRUE; } -void NetHackQtWindow::CursorTo(int x,int y) { puts("unexpected CursorTo"); } -void NetHackQtWindow::PutStr(int attr, const char* text) { puts("unexpected PutStr"); } -void NetHackQtWindow::StartMenu() { puts("unexpected StartMenu"); } -void NetHackQtWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const char* str, bool presel) { puts("unexpected AddMenu"); } -void NetHackQtWindow::EndMenu(const char* prompt) { puts("unexpected EndMenu"); } -int NetHackQtWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) { puts("unexpected SelectMenu"); return 0; } -void NetHackQtWindow::ClipAround(int x,int y) { puts("unexpected ClipAround"); } -void NetHackQtWindow::PrintGlyph(int x,int y,int glyph) { puts("unexpected PrintGlyph"); } +void NetHackQtWindow::Display(bool block UNUSED) { puts("unexpected Display"); } +bool NetHackQtWindow::Destroy() { return true; } +void NetHackQtWindow::CursorTo(int x UNUSED,int y UNUSED) { puts("unexpected CursorTo"); } +void NetHackQtWindow::PutStr(int attr UNUSED, const QString& text UNUSED) { puts("unexpected PutStr"); } +void NetHackQtWindow::StartMenu(bool using_WIN_INVEN UNUSED) + { puts("unexpected StartMenu"); } +void NetHackQtWindow::AddMenu(int glyph UNUSED, const ANY_P* identifier UNUSED, + char ch UNUSED, char gch UNUSED, int attr UNUSED, int clr UNUSED, + const QString& str UNUSED, unsigned itemflags UNUSED) + { puts("unexpected AddMenu"); } +void NetHackQtWindow::EndMenu(const QString& prompt UNUSED) { puts("unexpected EndMenu"); } +int NetHackQtWindow::SelectMenu(int how UNUSED, MENU_ITEM_P **menu_list UNUSED) + { puts("unexpected SelectMenu"); return 0; } +void NetHackQtWindow::ClipAround(int x UNUSED,int y UNUSED) { puts("unexpected ClipAround"); } +void NetHackQtWindow::PrintGlyph(int x UNUSED,int y UNUSED,const glyph_info *glyphinfo UNUSED,const glyph_info *bkglyphinfo UNUSED) { puts("unexpected PrintGlyph"); } //void NetHackQtWindow::PrintGlyphCompose(int x,int y,int,int) { puts("unexpected PrintGlyphCompose"); } -void NetHackQtWindow::UseRIP(int how, time_t when) { puts("unexpected UseRIP"); } - - - -// XXX Hmmm... crash after saving bones file if Map window is -// XXX deleted. Strange bug somewhere. -bool NetHackQtMapWindow::Destroy() { return FALSE; } - -NetHackQtMapWindow::NetHackQtMapWindow(NetHackQtClickBuffer& click_sink) : - clicksink(click_sink), - change(10), - rogue_font(0) -{ - viewport.addChild(this); - - setBackgroundColor(black); - viewport.setBackgroundColor(black); +void NetHackQtWindow::UseRIP(int how UNUSED, time_t when UNUSED) { puts("unexpected UseRIP"); } - pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_mark_xpm); - - cursor.setX(0); - cursor.setY(0); - Clear(); - - connect(qt_settings,SIGNAL(tilesChanged()),this,SLOT(updateTiles())); - connect(&viewport, SIGNAL(contentsMoving(int,int)), this, - SLOT(moveMessages(int,int))); - - updateTiles(); - //setFocusPolicy(StrongFocus); -#ifdef SAFERHANGUP - QTimer* deadman = new QTimer(this); - connect(deadman, SIGNAL(timeout()), SLOT(timeout())); - deadman->start(2000); // deadman timer every 2 seconds -#endif -} - -#ifdef SAFERHANGUP -// The "deadman" timer is received by this slot -void NetHackQtMapWindow::timeout() {} -#endif - -void NetHackQtMapWindow::moveMessages(int x, int y) -{ - QRect u = messages_rect; - messages_rect.moveTopLeft(QPoint(x,y)); - u |= messages_rect; - update(u); -} - -void NetHackQtMapWindow::clearMessages() -{ - messages = ""; - update(messages_rect); - messages_rect = QRect(); -} - -void NetHackQtMapWindow::putMessage(int attr, const char* text) -{ - if ( !messages.isEmpty() ) - messages += "\n"; - messages += text; - QFontMetrics fm = fontMetrics(); - messages_rect = fm.boundingRect(viewport.contentsX(), viewport.contentsY(), - viewport.width(), 0, - WordBreak|AlignTop|AlignLeft|DontClip, - messages); - update(messages_rect); -} - -void NetHackQtMapWindow::updateTiles() -{ - NetHackQtGlyphs& glyphs = qt_settings->glyphs(); - int gw = glyphs.width(); - int gh = glyphs.height(); - // Be exactly the size we want to be - full map... - resize(COLNO*gw,ROWNO*gh); - - viewport.verticalScrollBar()->setSteps(gh,gh); - viewport.horizontalScrollBar()->setSteps(gw,gw); - /* - viewport.setMaximumSize( - gw*COLNO + viewport.verticalScrollBar()->width(), - gh*ROWNO + viewport.horizontalScrollBar()->height() - ); - */ - viewport.updateScrollBars(); - - change.clear(); - change.add(0,0,COLNO,ROWNO); - delete rogue_font; rogue_font = 0; - Display(FALSE); - - emit resized(); -} - -NetHackQtMapWindow::~NetHackQtMapWindow() -{ - // Remove from viewport porthole, since that is a destructible member. - viewport.removeChild(this); - recreate(0,0,QPoint(0,0)); -} - -QWidget* NetHackQtMapWindow::Widget() -{ - return &viewport; -} - -void NetHackQtMapWindow::Scroll(int dx, int dy) -{ - if (viewport.horizontalScrollBar()->isVisible()) { - while (dx<0) { viewport.horizontalScrollBar()->subtractPage(); dx++; } - while (dx>0) { viewport.horizontalScrollBar()->addPage(); dx--; } - } - if (viewport.verticalScrollBar()->isVisible()) { - while (dy<0) { viewport.verticalScrollBar()->subtractPage(); dy++; } - while (dy>0) { viewport.verticalScrollBar()->addPage(); dy--; } - } -} - -void NetHackQtMapWindow::Clear() -{ - unsigned short stone=cmap_to_glyph(S_stone); - - for (int j=0; jexit_loop(); -} - -void NetHackQtMapWindow::mousePressEvent(QMouseEvent* event) -{ - clicksink.Put( - event->pos().x()/qt_settings->glyphs().width(), - event->pos().y()/qt_settings->glyphs().height(), - event->button()==LeftButton ? CLICK_1 : CLICK_2 - ); - qApp->exit_loop(); -} - -#ifdef TEXTCOLOR -static -const QPen& nhcolor_to_pen(int c) -{ - static QPen* pen=0; - if ( !pen ) { - pen = new QPen[17]; - pen[0] = QColor(24,24,24); // "black" on black - pen[1] = Qt::red; - pen[2] = QColor(0,191,0); - pen[3] = QColor(127,127,0); - pen[4] = Qt::blue; - pen[5] = Qt::magenta; - pen[6] = Qt::cyan; - pen[7] = Qt::gray; - pen[8] = Qt::white; // no color - pen[9] = QColor(255,127,0); - pen[10] = QColor(127,255,127); - pen[11] = Qt::yellow; - pen[12] = QColor(127,127,255); - pen[13] = QColor(255,127,255); - pen[14] = QColor(127,255,255); - pen[15] = Qt::white; - pen[16] = QColor(24,24,24); // "black" on black - } - - return pen[c]; -} -#endif - -void NetHackQtMapWindow::paintEvent(QPaintEvent* event) -{ - QRect area=event->rect(); - QRect garea; - garea.setCoords( - QMAX(0,area.left()/qt_settings->glyphs().width()), - QMAX(0,area.top()/qt_settings->glyphs().height()), - QMIN(COLNO-1,area.right()/qt_settings->glyphs().width()), - QMIN(ROWNO-1,area.bottom()/qt_settings->glyphs().height()) - ); - - QPainter painter; - - painter.begin(this); - - if (Is_rogue_level(&u.uz) || iflags.wc_ascii_map) - { - // You enter a VERY primitive world! - - painter.setClipRect( event->rect() ); // (normally we don't clip) - painter.fillRect( event->rect(), black ); - - if ( !rogue_font ) { - // Find font... - int pts = 5; - QString fontfamily = iflags.wc_font_map - ? iflags.wc_font_map : "Courier"; - bool bold = FALSE; - if ( fontfamily.right(5).lower() == "-bold" ) { - fontfamily.truncate(fontfamily.length()-5); - bold = TRUE; - } - while ( pts < 32 ) { - QFont f(fontfamily, pts, bold ? QFont::Bold : QFont::Normal); - painter.setFont(QFont(fontfamily, pts)); - QFontMetrics fm = painter.fontMetrics(); - if ( fm.width("M") > qt_settings->glyphs().width() ) - break; - if ( fm.height() > qt_settings->glyphs().height() ) - break; - pts++; - } - rogue_font = new QFont(fontfamily,pts-1); - } - painter.setFont(*rogue_font); - - for (int j=garea.top(); j<=garea.bottom(); j++) { - for (int i=garea.left(); i<=garea.right(); i++) { - unsigned short g=Glyph(i,j); - uchar ch; - int color, och; - unsigned special; - - painter.setPen( green ); - /* map glyph to character and color */ - (void)mapglyph(g, &och, &color, &special, i, j, 0); - ch = (uchar)och; -#ifdef TEXTCOLOR - painter.setPen( nhcolor_to_pen(color) ); -#endif - painter.drawText( - i*qt_settings->glyphs().width(), - j*qt_settings->glyphs().height(), - qt_settings->glyphs().width(), - qt_settings->glyphs().height(), - AlignCenter, - (const char*)&ch, 1 - ); - if (glyph_is_pet(g) -#ifdef TEXTCOLOR - && ::iflags.hilite_pet -#endif - ) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), - j*qt_settings->glyphs().height()), - pet_annotation); - } - } - } - - painter.setFont(font()); - } else { - for (int j=garea.top(); j<=garea.bottom(); j++) { - for (int i=garea.left(); i<=garea.right(); i++) { - unsigned short g=Glyph(i,j); - qt_settings->glyphs().drawCell(painter, g, i, j); - if (glyph_is_pet(g) -#ifdef TEXTCOLOR - && ::iflags.hilite_pet -#endif - ) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), - j*qt_settings->glyphs().height()), - pet_annotation); - } - } - } - } - - if (garea.contains(cursor)) { - if (Is_rogue_level(&u.uz)) { -#ifdef TEXTCOLOR - painter.setPen( white ); -#else - painter.setPen( green ); // REALLY primitive -#endif - } else - { - int hp100; - if (u.mtimedone) { - hp100=u.mhmax ? u.mh*100/u.mhmax : 100; - } else { - hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100; - } - - if (hp100 > 75) painter.setPen(white); - else if (hp100 > 50) painter.setPen(yellow); - else if (hp100 > 25) painter.setPen(QColor(0xff,0xbf,0x00)); // orange - else if (hp100 > 10) painter.setPen(red); - else painter.setPen(magenta); - } - - painter.drawRect( - cursor.x()*qt_settings->glyphs().width(),cursor.y()*qt_settings->glyphs().height(), - qt_settings->glyphs().width(),qt_settings->glyphs().height()); - } - - if (area.intersects(messages_rect)) { - painter.setPen(black); - painter.drawText(viewport.contentsX()+1,viewport.contentsY()+1, - viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages); - painter.setPen(white); - painter.drawText(viewport.contentsX(),viewport.contentsY(), - viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages); - } - - painter.end(); -} - -void NetHackQtMapWindow::Display(bool block) -{ - for (int i=0; iglyphs().width(), - ch.y()*qt_settings->glyphs().height(), - ch.width()*qt_settings->glyphs().width(), - ch.height()*qt_settings->glyphs().height(), - FALSE - ); - } - - change.clear(); - - if (block) { - yn_function("Press a key when done viewing",0,'\0'); - } -} - -void NetHackQtMapWindow::CursorTo(int x,int y) -{ - Changed(cursor.x(),cursor.y()); - cursor.setX(x); - cursor.setY(y); - Changed(cursor.x(),cursor.y()); -} - -void NetHackQtMapWindow::PutStr(int attr, const char* text) -{ - puts("unexpected PutStr in MapWindow"); -} - -void NetHackQtMapWindow::ClipAround(int x,int y) -{ - // Convert to pixel of center of tile - x=x*qt_settings->glyphs().width()+qt_settings->glyphs().width()/2; - y=y*qt_settings->glyphs().height()+qt_settings->glyphs().height()/2; - - // Then ensure that pixel is visible - viewport.center(x,y,0.45,0.45); -} - -void NetHackQtMapWindow::PrintGlyph(int x,int y,int glyph) -{ - Glyph(x,y)=glyph; - Changed(x,y); -} - -//void NetHackQtMapWindow::PrintGlyphCompose(int x,int y,int glyph1, int glyph2) -//{ - // TODO: composed graphics -//} - -void NetHackQtMapWindow::Changed(int x, int y) -{ - change.add(x,y); -} - - -class NetHackQtScrollText : public QTableView { - struct UData { - UData() : text(0), attr(0) { } - ~UData() { if (text) free(text); } - - char* text; - int attr; - }; -public: - int uncleared; - - NetHackQtScrollText(int maxlength) : - uncleared(0), - maxitems(maxlength), - first(0), - count(0), - item_cycle(maxlength) - { - setNumCols(1); - setCellWidth(200); - setCellHeight(fontMetrics().height()); - setBackgroundColor(white); - setTableFlags(Tbl_vScrollBar - |Tbl_autoHScrollBar - |Tbl_clipCellPainting - |Tbl_smoothScrolling); - } - - ~NetHackQtScrollText() - { - } - - void Scroll(int dx, int dy) - { - setXOffset(xOffset()+dx*viewWidth()); - setYOffset(yOffset()+dy*viewHeight()); - } - - void insertItem(int attr, const char* text) - { - setTopCell(count); - - setAutoUpdate(FALSE); - - int i; - if (count cellWidth()) { - // Get wider. - setCellWidth(w); - } - setTopCell(count); - - setAutoUpdate(TRUE); - - if (viewHeight() >= totalHeight()-cellHeight()) { - repaint(); - } else { - scroll(0,cellHeight()); - } - } - - virtual void setFont(const QFont& font) - { - QTableView::setFont(font); - setCellHeight(fontMetrics().height()); - } - -protected: - - UData& item(int i) - { - return item_cycle[(first+i)%maxitems]; - } - - const int maxitems; - int first, count; - QArray item_cycle; - - int datumWidth(const UData& uitem) - { - if (uitem.text) { - int width=fontMetrics().width(uitem.text)+3; - if (uitem.attr) { - // XXX Too expensive to do properly, because - // XXX we have to set the font of the widget - // XXX just to get the font metrics information! - // XXX Could hold a fake widget for that - // XXX purpose, but this hack is less ugly. - width+=width/10; - } - return width; - } else { - return 0; - } - } - - virtual void setupPainter(QPainter *p) - { - // XXX This shouldn't be needed - we set the bg in the constructor. - p->setBackgroundColor(white); - } - - virtual void paintCell(QPainter *p, int row, int col) - { - bool sel=FALSE; - UData& uitem=item(row); - - if (!sel && row < count-uncleared) { - p->setPen(darkGray); - } else { - p->setPen(black); - } - - if (uitem.attr) { - // XXX only bold - QFont bold(font().family(),font().pointSize(),QFont::Bold); - p->setFont(bold); - } - - p->drawText(3, 0, cellWidth(), cellHeight(), - AlignLeft|AlignVCenter, uitem.text); - - if (uitem.attr) { - p->setFont(font()); - } - } -}; - -NetHackQtMessageWindow::NetHackQtMessageWindow() : - list(new NetHackQtScrollText(::iflags.msg_history)) -{ - ::iflags.window_inited = 1; - map = 0; - connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(updateFont())); - updateFont(); -} - -NetHackQtMessageWindow::~NetHackQtMessageWindow() -{ - ::iflags.window_inited = 0; - delete list; -} - -QWidget* NetHackQtMessageWindow::Widget() { return list; } - -void NetHackQtMessageWindow::setMap(NetHackQtMapWindow* m) -{ - map = m; - updateFont(); -} - -void NetHackQtMessageWindow::updateFont() -{ - list->setFont(qt_settings->normalFont()); - if ( map ) - map->setFont(qt_settings->normalFont()); -} - -void NetHackQtMessageWindow::Scroll(int dx, int dy) -{ - list->Scroll(dx,dy); -} - -void NetHackQtMessageWindow::Clear() -{ - if ( map ) - map->clearMessages(); - if (list->uncleared) { - list->uncleared=0; - changed=TRUE; - Display(FALSE); - } -} - -void NetHackQtMessageWindow::Display(bool block) -{ - if (changed) { - list->repaint(); - changed=FALSE; - } -} - -void NetHackQtMessageWindow::PutStr(int attr, const char* text) -{ -#ifdef USER_SOUNDS - play_sound_for_message(text); -#endif - - changed=TRUE; - list->uncleared++; - list->insertItem(attr,text); - - // Force scrollbar to bottom - // XXX list->setTopItem(list->count()); - - if ( map ) - map->putMessage(attr, text); -} - - - -NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l) : - QWidget(parent), - low_is_good(FALSE), - prev_value(-123), - turn_count(-1), - label(new QLabel(l,this)), - icon(0) -{ - initHighlight(); -} -NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l, const QPixmap& i) : - QWidget(parent), - low_is_good(FALSE), - prev_value(-123), - turn_count(-1), - label(new QLabel(l,this)), - icon(new QLabel(this)) -{ - setIcon(i); - initHighlight(); -} -void NetHackQtLabelledIcon::initHighlight() -{ - const QPalette& pal=palette(); - const QColorGroup& pa=pal.normal(); - //QColorGroup good(white,darkGreen,pa.light(),pa.dark(),pa.mid(),white,pa.base()); - QColorGroup good(black,green,pa.light(),pa.dark(),pa.mid(),black,pa.base()); - QColorGroup bad(white,red,pa.light(),pa.dark(),pa.mid(),white,pa.base()); - hl_good=pal.copy(); - hl_good.setNormal(good); - hl_good.setActive(good); - hl_bad=pal.copy(); - hl_bad.setNormal(bad); - hl_bad.setActive(bad); -} - -void NetHackQtLabelledIcon::setLabel(const char* t, bool lower) -{ - if (!label) { - label=new QLabel(this); - label->setFont(font()); - resizeEvent(0); - } - if (0!=strcmp(label->text(),t)) { - label->setText(t); - highlight(lower==low_is_good ? hl_good : hl_bad); - } -} -void NetHackQtLabelledIcon::setLabel(const char* t, long v, long cv, const char* tail) -{ - char buf[BUFSZ]; - if (v==NoNum) { - Sprintf(buf,"%s%s",t,tail); - } else { - Sprintf(buf,"%s%ld%s",t,v,tail); - } - setLabel(buf,cvsetPixmap(i); - else { icon=new QLabel(this); icon->setPixmap(i); resizeEvent(0); } - icon->resize(i.width(),i.height()); -} -void NetHackQtLabelledIcon::setFont(const QFont& f) -{ - QWidget::setFont(f); - if (label) label->setFont(f); -} -void NetHackQtLabelledIcon::show() -{ -#if QT_VERSION >= 300 - if (isHidden()) -#else - if (!isVisible()) -#endif - highlight(hl_bad); - QWidget::show(); -} -void NetHackQtLabelledIcon::highlightWhenChanging() -{ - turn_count=0; -} -void NetHackQtLabelledIcon::lowIsGood() -{ - low_is_good=TRUE; -} -void NetHackQtLabelledIcon::dissipateHighlight() -{ - if (turn_count>0) { - turn_count--; - if (!turn_count) - unhighlight(); - } -} -void NetHackQtLabelledIcon::highlight(const QPalette& hl) -{ - if (label) { // Surely it is?! - if (turn_count>=0) { - label->setPalette(hl); - turn_count=4; - // `4' includes this turn, so dissipates after - // 3 more keypresses. - } else { - label->setPalette(palette()); - } - } -} -void NetHackQtLabelledIcon::unhighlight() -{ - if (label) { // Surely it is?! - label->setPalette(palette()); - } -} -void NetHackQtLabelledIcon::resizeEvent(QResizeEvent*) -{ - setAlignments(); - - //int labw=label ? label->fontMetrics().width(label->text()) : 0; - int labh=label ? label->fontMetrics().height() : 0; - int icoh=icon ? icon->height() : 0; - int h=icoh+labh; - int icoy=(h>height() ? height()-labh-icoh : height()/2-h/2); - int laby=icoy+icoh; - if (icon) { - icon->setGeometry(0,icoy,width(),icoh); - } - if (label) { - label->setGeometry(0,laby,width(),labh); - } -} - -void NetHackQtLabelledIcon::setAlignments() -{ - if (label) label->setAlignment(AlignHCenter|AlignVCenter); - if (icon) icon->setAlignment(AlignHCenter|AlignVCenter); -} - -static void -tryload(QPixmap& pm, const char* fn) -{ - if (!pm.load(fn)) { - QString msg; - msg.sprintf("Cannot load \"%s\"", fn); - QMessageBox::warning(0, "IO Error", msg); - } -} - -NetHackQtStatusWindow::NetHackQtStatusWindow() : - // Notes: - // Alignment needs -2 init value, because -1 is an alignment. - // Armor Class is an schar, so 256 is out of range. - // Blank value is 0 and should never change. - name(this,"(name)"), - dlevel(this,"(dlevel)"), - str(this,"STR"), - dex(this,"DEX"), - con(this,"CON"), - intel(this,"INT"), - wis(this,"WIS"), - cha(this,"CHA"), - gold(this,"Gold"), - hp(this,"Hit Points"), - power(this,"Power"), - ac(this,"Armour Class"), - level(this,"Level"), - exp(this,"Experience"), - align(this,"Alignment"), - time(this,"Time"), - score(this,"Score"), - hunger(this,""), - confused(this,"Confused"), - sick_fp(this,"Sick"), - sick_il(this,"Ill"), - blind(this,"Blind"), - stunned(this,"Stunned"), - hallu(this,"Hallu"), - encumber(this,""), - hline1(this), - hline2(this), - hline3(this), - first_set(TRUE) -{ - p_str = QPixmap(str_xpm); - p_str = QPixmap(str_xpm); - p_dex = QPixmap(dex_xpm); - p_con = QPixmap(cns_xpm); - p_int = QPixmap(int_xpm); - p_wis = QPixmap(wis_xpm); - p_cha = QPixmap(cha_xpm); - - p_chaotic = QPixmap(chaotic_xpm); - p_neutral = QPixmap(neutral_xpm); - p_lawful = QPixmap(lawful_xpm); - - p_satiated = QPixmap(satiated_xpm); - p_hungry = QPixmap(hungry_xpm); - - p_confused = QPixmap(confused_xpm); - p_sick_fp = QPixmap(sick_fp_xpm); - p_sick_il = QPixmap(sick_il_xpm); - p_blind = QPixmap(blind_xpm); - p_stunned = QPixmap(stunned_xpm); - p_hallu = QPixmap(hallu_xpm); - - p_encumber[0] = QPixmap(slt_enc_xpm); - p_encumber[1] = QPixmap(mod_enc_xpm); - p_encumber[2] = QPixmap(hvy_enc_xpm); - p_encumber[3] = QPixmap(ext_enc_xpm); - p_encumber[4] = QPixmap(ovr_enc_xpm); - - str.setIcon(p_str); - dex.setIcon(p_dex); - con.setIcon(p_con); - intel.setIcon(p_int); - wis.setIcon(p_wis); - cha.setIcon(p_cha); - - align.setIcon(p_neutral); - hunger.setIcon(p_hungry); - - confused.setIcon(p_confused); - sick_fp.setIcon(p_sick_fp); - sick_il.setIcon(p_sick_il); - blind.setIcon(p_blind); - stunned.setIcon(p_stunned); - hallu.setIcon(p_hallu); - - encumber.setIcon(p_encumber[0]); - - hline1.setFrameStyle(QFrame::HLine|QFrame::Sunken); - hline2.setFrameStyle(QFrame::HLine|QFrame::Sunken); - hline3.setFrameStyle(QFrame::HLine|QFrame::Sunken); - hline1.setLineWidth(1); - hline2.setLineWidth(1); - hline3.setLineWidth(1); - - connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate())); - doUpdate(); -} - -void NetHackQtStatusWindow::doUpdate() -{ - const QFont& large=qt_settings->largeFont(); - name.setFont(large); - dlevel.setFont(large); - - const QFont& normal=qt_settings->normalFont(); - str.setFont(normal); - dex.setFont(normal); - con.setFont(normal); - intel.setFont(normal); - wis.setFont(normal); - cha.setFont(normal); - gold.setFont(normal); - hp.setFont(normal); - power.setFont(normal); - ac.setFont(normal); - level.setFont(normal); - exp.setFont(normal); - align.setFont(normal); - time.setFont(normal); - score.setFont(normal); - hunger.setFont(normal); - confused.setFont(normal); - sick_fp.setFont(normal); - sick_il.setFont(normal); - blind.setFont(normal); - stunned.setFont(normal); - hallu.setFont(normal); - encumber.setFont(normal); - - updateStats(); -} - -QWidget* NetHackQtStatusWindow::Widget() { return this; } - -void NetHackQtStatusWindow::Clear() -{ -} -void NetHackQtStatusWindow::Display(bool block) -{ -} -void NetHackQtStatusWindow::CursorTo(int,int y) -{ - cursy=y; -} -void NetHackQtStatusWindow::PutStr(int attr, const char* text) -{ - // do a complete update when line 0 is done (as per X11 fancy status) - if (cursy==0) updateStats(); -} - -void NetHackQtStatusWindow::resizeEvent(QResizeEvent*) -{ - const float SP_name=0.13; // the (large) - const float SP_dlev=0.13; // Level 3 in The Dungeons of Doom (large) - const float SP_atr1=0.25; // STR DEX CON INT WIS CHA - const float SP_hln1=0.02; // --- - const float SP_atr2=0.09; // Au HP PW AC LVL EXP - const float SP_hln2=0.02; // --- - const float SP_time=0.09; // time score - const float SP_hln3=0.02; // --- - const float SP_stat=0.25; // Alignment, Poisoned, Hungry, Sick, etc. - - int h=height(); - int x=0,y=0; - - int iw; // Width of an item across line - int lh; // Height of a line of values - - lh=int(h*SP_name); - name.setGeometry(0,0,width(),lh); y+=lh; - lh=int(h*SP_dlev); - dlevel.setGeometry(0,y,width(),lh); y+=lh; - - lh=int(h*SP_hln1); - hline1.setGeometry(0,y,width(),lh); y+=lh; - - lh=int(h*SP_atr1); - iw=width()/6; - str.setGeometry(x,y,iw,lh); x+=iw; - dex.setGeometry(x,y,iw,lh); x+=iw; - con.setGeometry(x,y,iw,lh); x+=iw; - intel.setGeometry(x,y,iw,lh); x+=iw; - wis.setGeometry(x,y,iw,lh); x+=iw; - cha.setGeometry(x,y,iw,lh); x+=iw; - x=0; y+=lh; - - lh=int(h*SP_hln2); - hline2.setGeometry(0,y,width(),lh); y+=lh; - - lh=int(h*SP_atr2); - iw=width()/6; - gold.setGeometry(x,y,iw,lh); x+=iw; - hp.setGeometry(x,y,iw,lh); x+=iw; - power.setGeometry(x,y,iw,lh); x+=iw; - ac.setGeometry(x,y,iw,lh); x+=iw; - level.setGeometry(x,y,iw,lh); x+=iw; - exp.setGeometry(x,y,iw,lh); x+=iw; - x=0; y+=lh; - - lh=int(h*SP_hln3); - hline3.setGeometry(0,y,width(),lh); y+=lh; - - lh=int(h*SP_time); - iw=width()/3; x+=iw/2; - time.setGeometry(x,y,iw,lh); x+=iw; - score.setGeometry(x,y,iw,lh); x+=iw; - x=0; y+=lh; - - lh=int(h*SP_stat); - iw=width()/9; - align.setGeometry(x,y,iw,lh); x+=iw; - hunger.setGeometry(x,y,iw,lh); x+=iw; - confused.setGeometry(x,y,iw,lh); x+=iw; - sick_fp.setGeometry(x,y,iw,lh); x+=iw; - sick_il.setGeometry(x,y,iw,lh); x+=iw; - blind.setGeometry(x,y,iw,lh); x+=iw; - stunned.setGeometry(x,y,iw,lh); x+=iw; - hallu.setGeometry(x,y,iw,lh); x+=iw; - encumber.setGeometry(x,y,iw,lh); x+=iw; - x=0; y+=lh; -} - - -/* - * Set all widget values to a null string. This is used after all spacings - * have been calculated so that when the window is popped up we don't get all - * kinds of funny values being displayed. - */ -void NetHackQtStatusWindow::nullOut() -{ -} - -void NetHackQtStatusWindow::fadeHighlighting() -{ - name.dissipateHighlight(); - dlevel.dissipateHighlight(); - - str.dissipateHighlight(); - dex.dissipateHighlight(); - con.dissipateHighlight(); - intel.dissipateHighlight(); - wis.dissipateHighlight(); - cha.dissipateHighlight(); - - gold.dissipateHighlight(); - hp.dissipateHighlight(); - power.dissipateHighlight(); - ac.dissipateHighlight(); - level.dissipateHighlight(); - exp.dissipateHighlight(); - align.dissipateHighlight(); - - time.dissipateHighlight(); - score.dissipateHighlight(); - - hunger.dissipateHighlight(); - confused.dissipateHighlight(); - sick_fp.dissipateHighlight(); - sick_il.dissipateHighlight(); - blind.dissipateHighlight(); - stunned.dissipateHighlight(); - hallu.dissipateHighlight(); - encumber.dissipateHighlight(); -} - -/* - * Update the displayed status. The current code in botl.c updates - * two lines of information. Both lines are always updated one after - * the other. So only do our update when we update the second line. - * - * Information on the first line: - * name, attributes, alignment, score - * - * Information on the second line: - * dlvl, gold, hp, power, ac, {level & exp or HD **} - * status (hunger, conf, halu, stun, sick, blind), time, encumbrance - * - * [**] HD is shown instead of level and exp if mtimedone is non-zero. - */ -void NetHackQtStatusWindow::updateStats() -{ - if (!parentWidget()) return; - - char buf[BUFSZ]; - - if (cursy != 0) return; /* do a complete update when line 0 is done */ - - if (ACURR(A_STR) > 118) { - Sprintf(buf,"STR:%d",ACURR(A_STR)-100); - } else if (ACURR(A_STR)==118) { - Sprintf(buf,"STR:18/**"); - } else if(ACURR(A_STR) > 18) { - Sprintf(buf,"STR:18/%02d",ACURR(A_STR)-18); - } else { - Sprintf(buf,"STR:%d",ACURR(A_STR)); - } - str.setLabel(buf,NetHackQtLabelledIcon::NoNum,ACURR(A_STR)); - - dex.setLabel("DEX:",(long)ACURR(A_DEX)); - con.setLabel("CON:",(long)ACURR(A_CON)); - intel.setLabel("INT:",(long)ACURR(A_INT)); - wis.setLabel("WIS:",(long)ACURR(A_WIS)); - cha.setLabel("CHA:",(long)ACURR(A_CHA)); - const char* hung=hu_stat[u.uhs]; - if (hung[0]==' ') { - hunger.hide(); - } else { - hunger.setIcon(u.uhs ? p_hungry : p_satiated); - hunger.setLabel(hung); - hunger.show(); - } - if (Confusion) confused.show(); else confused.hide(); - if (Sick) { - if (u.usick_type & SICK_VOMITABLE) { - sick_fp.show(); - } else { - sick_fp.hide(); - } - if (u.usick_type & SICK_NONVOMITABLE) { - sick_il.show(); - } else { - sick_il.hide(); - } - } else { - sick_fp.hide(); - sick_il.hide(); - } - if (Blind) blind.show(); else blind.hide(); - if (Stunned) stunned.show(); else stunned.hide(); - if (Hallucination) hallu.show(); else hallu.hide(); - const char* enc=enc_stat[near_capacity()]; - if (enc[0]==' ' || !enc[0]) { - encumber.hide(); - } else { - encumber.setIcon(p_encumber[near_capacity()-1]); - encumber.setLabel(enc); - encumber.show(); - } - Strcpy(buf, plname); - if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a'; - Strcat(buf, " the "); - if (u.mtimedone) { - char mname[BUFSZ]; - int k = 0; - - Strcpy(mname, mons[u.umonnum].mname); - while(mname[k] != 0) { - if ((k == 0 || (k > 0 && mname[k-1] == ' ')) - && 'a' <= mname[k] && mname[k] <= 'z') - { - mname[k] += 'A' - 'a'; - } - k++; - } - Strcat(buf, mname); - } else { - Strcat(buf, rank_of(u.ulevel, pl_character[0], ::flags.female)); - } - name.setLabel(buf,NetHackQtLabelledIcon::NoNum,u.ulevel); - - if (describe_level(buf)) { - dlevel.setLabel(buf,(bool)TRUE); - } else { - Sprintf(buf, "%s, level ", dungeons[u.uz.dnum].dname); - dlevel.setLabel(buf,(long)depth(&u.uz)); - } - - gold.setLabel("Au:", money_cnt(invent)); - if (u.mtimedone) { - // You're a monster! - - Sprintf(buf, "/%d", u.mhmax); - hp.setLabel("HP:",u.mh > 0 ? u.mh : 0,buf); - level.setLabel("HD:",(long)mons[u.umonnum].mlevel); - } else { - // You're normal. - - Sprintf(buf, "/%d", u.uhpmax); - hp.setLabel("HP:",u.uhp > 0 ? u.uhp : 0,buf); - level.setLabel("Level:",(long)u.ulevel); - } - Sprintf(buf, "/%d", u.uenmax); - power.setLabel("Pow:",u.uen,buf); - ac.setLabel("AC:",(long)u.uac); - if (::flags.showexp) { - exp.setLabel("Exp:",(long)u.uexp); - } else - { - exp.setLabel(""); - } - if (u.ualign.type==A_CHAOTIC) { - align.setIcon(p_chaotic); - align.setLabel("Chaotic"); - } else if (u.ualign.type==A_NEUTRAL) { - align.setIcon(p_neutral); - align.setLabel("Neutral"); - } else { - align.setIcon(p_lawful); - align.setLabel("Lawful"); - } - - if (::flags.time) time.setLabel("Time:",(long)moves); - else time.setLabel(""); -#ifdef SCORE_ON_BOTL - if (::flags.showscore) { - score.setLabel("Score:",(long)botl_score()); - } else -#endif - { - score.setLabel(""); - } - - if (first_set) - { - first_set=FALSE; - - name.highlightWhenChanging(); - dlevel.highlightWhenChanging(); - - str.highlightWhenChanging(); - dex.highlightWhenChanging(); - con.highlightWhenChanging(); - intel.highlightWhenChanging(); - wis.highlightWhenChanging(); - cha.highlightWhenChanging(); - - gold.highlightWhenChanging(); - hp.highlightWhenChanging(); - power.highlightWhenChanging(); - ac.highlightWhenChanging(); ac.lowIsGood(); - level.highlightWhenChanging(); - exp.highlightWhenChanging(); - align.highlightWhenChanging(); - - //time.highlightWhenChanging(); - score.highlightWhenChanging(); - - hunger.highlightWhenChanging(); - confused.highlightWhenChanging(); - sick_fp.highlightWhenChanging(); - sick_il.highlightWhenChanging(); - blind.highlightWhenChanging(); - stunned.highlightWhenChanging(); - hallu.highlightWhenChanging(); - encumber.highlightWhenChanging(); - } -} - -/* - * Turn off hilighted status values after a certain amount of turns. - */ -void NetHackQtStatusWindow::checkTurnEvents() -{ -} - - - -NetHackQtMenuDialog::NetHackQtMenuDialog() : - QDialog(qApp->mainWidget(),0,FALSE) -{ -} - -void NetHackQtMenuDialog::resizeEvent(QResizeEvent*) -{ - emit Resized(); -} - -void NetHackQtMenuDialog::Accept() -{ - accept(); -} - -void NetHackQtMenuDialog::Reject() -{ - reject(); -} - -void NetHackQtMenuDialog::SetResult(int r) -{ - setResult(r); -} - -void NetHackQtMenuDialog::done(int i) -{ - setResult(i); - qApp->exit_loop(); -} - -// Table view columns: -// -// [pick-count] [accel] [glyph] [string] -// -// Maybe accel should be near string. We'll see. -// pick-count normally blank. -// double-clicking or click-on-count gives pop-up entry -// string is green when selected -// -NetHackQtMenuWindow::NetHackQtMenuWindow(NetHackQtKeyBuffer& ks) : - QTableView(), - keysource(ks), - dialog(new NetHackQtMenuDialog()), - prompt(0), - pressed(-1) -{ - setNumCols(4); - setCellHeight(QMAX(qt_settings->glyphs().height()+1,fontMetrics().height())); - setBackgroundColor(lightGray); - setFrameStyle(Panel|Sunken); - setLineWidth(2); - - ok=new QPushButton("Ok",dialog); - connect(ok,SIGNAL(clicked()),dialog,SLOT(accept())); - - cancel=new QPushButton("Cancel",dialog); - connect(cancel,SIGNAL(clicked()),dialog,SLOT(reject())); - - all=new QPushButton("All",dialog); - connect(all,SIGNAL(clicked()),this,SLOT(All())); - - none=new QPushButton("None",dialog); - connect(none,SIGNAL(clicked()),this,SLOT(ChooseNone())); - - invert=new QPushButton("Invert",dialog); - connect(invert,SIGNAL(clicked()),this,SLOT(Invert())); - - search=new QPushButton("Search",dialog); - connect(search,SIGNAL(clicked()),this,SLOT(Search())); - - QPoint pos(0,ok->height()); - recreate(dialog,0,pos); - prompt.recreate(dialog,0,pos); - - setBackgroundColor(lightGray); - - connect(dialog,SIGNAL(Resized()),this,SLOT(Layout())); - - setTableFlags(Tbl_autoHScrollBar|Tbl_autoVScrollBar - |Tbl_smoothScrolling|Tbl_clipCellPainting); - setFocusPolicy(StrongFocus); -} - -NetHackQtMenuWindow::~NetHackQtMenuWindow() -{ - // Remove from dialog before we destruct it - recreate(0,0,QPoint(0,0)); - delete dialog; -} - -void NetHackQtMenuWindow::focusInEvent(QFocusEvent *) -{ - // Don't repaint at all, since nothing is using the focus colour -} -void NetHackQtMenuWindow::focusOutEvent(QFocusEvent *) -{ - // Don't repaint at all, since nothing is using the focus colour -} - -int NetHackQtMenuWindow::cellWidth(int col) -{ - switch (col) { - case 0: - return fontMetrics().width("All "); - break; case 1: - return fontMetrics().width(" m "); - break; case 2: - return qt_settings->glyphs().width(); - break; case 3: - return str_width; - } - impossible("Extra column (#%d) in MenuWindow",col); - return 0; -} - -QWidget* NetHackQtMenuWindow::Widget() { return dialog; } - -void NetHackQtMenuWindow::StartMenu() -{ - setNumRows((itemcount=0)); - str_width=200; - str_fixed=FALSE; - next_accel=0; - has_glyphs=FALSE; -} - -NetHackQtMenuWindow::MenuItem::MenuItem() : - str(0) -{ -} - -NetHackQtMenuWindow::MenuItem::~MenuItem() -{ - if (str) free((void*)str); -} - -#define STR_MARGIN 4 - -void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P* identifier, - char ch, char gch, int attr, const char* str, bool presel) -{ - if (!ch && identifier->a_void!=0) { - // Supply a keyboard accelerator. Limited supply. - static char accel[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - if (accel[next_accel]) { - ch=accel[next_accel++]; - } - } - - if ((int)item.size() < itemcount+1) { - item.resize(itemcount*4+10); - } - item[itemcount].glyph=glyph; - item[itemcount].identifier=*identifier; - item[itemcount].ch=ch; - item[itemcount].attr=attr; - item[itemcount].str=strdup(str); - item[itemcount].selected=presel; - item[itemcount].count=-1; - ++itemcount; - - str_fixed=str_fixed || strstr(str," "); - if (glyph!=NO_GLYPH) has_glyphs=TRUE; -} -void NetHackQtMenuWindow::EndMenu(const char* p) -{ - prompt.setText(p ? p : ""); -} -void NetHackQtMenuWindow::Layout() -{ - int butw=totalWidth()/6; // 6 buttons - int buth=fontMetrics().height()+8; // 8 for spacing & mitres - int prompth=(prompt.text().isNull() ? 0 : buth); - - prompt.setGeometry(6,buth,dialog->width()-6,prompth); - int h=dialog->height()-buth-prompth; - setGeometry(0,buth+prompth, dialog->width(), h); - - // Below, we take care to use up full width - int x=0; - ok->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/5; - cancel->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/4; - all->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/3; - none->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/2; - invert->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/1; - search->setGeometry(x,0,butw,buth); -} - -int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list) -{ - setFont(str_fixed ? - qt_settings->normalFixedFont() : qt_settings->normalFont()); - - for (int i=0; iglyphs().height()+1,fontMetrics().height())); - setNumRows(itemcount); - - int buth=fontMetrics().height()+8; // 8 for spacing & mitres - - how=h; - - ok->setEnabled(how!=PICK_ONE);ok->setDefault(how!=PICK_ONE); - cancel->setEnabled(TRUE); - all->setEnabled(how==PICK_ANY); - none->setEnabled(how==PICK_ANY); - invert->setEnabled(how==PICK_ANY); - search->setEnabled(how!=PICK_NONE); - - dialog->SetResult(-1); - - // 20 allows for scrollbar or spacing - // 4 for frame borders - int mh = QApplication::desktop()->height()*3/5; - if ( qt_compact_mode && totalHeight() > mh ) { - // big, so make it fill - dialog->showMaximized(); - } else { - dialog->resize(totalWidth()+20, - QMIN(totalHeight(), mh)+buth+4+(prompt.text().isNull() ? 0 : buth)); - if ( dialog->width() > QApplication::desktop()->width() ) - dialog->resize(QApplication::desktop()->width(),dialog->height()+16); - centerOnMain(dialog); - dialog->show(); - } - - setFocus(); - while (dialog->result()<0) { - // changed the defaults below to the values in wintype.h 000119 - azy - if (!keysource.Empty()) { - char k=keysource.GetAscii(); - k=map_menu_cmd(k); /* added 000119 - azy */ - if (k=='\033') - dialog->Reject(); - else if (k=='\r' || k=='\n' || k==' ') - dialog->Accept(); - else if (k==MENU_SEARCH) - Search(); - else if (k==MENU_SELECT_ALL) - All(); - else if (k==MENU_INVERT_ALL) - Invert(); - else if (k==MENU_UNSELECT_ALL) - ChooseNone(); - else { - for (int i=0; iresult()<0) - qApp->enter_loop(); - } - //if ( (nhid != WIN_INVEN || !iflags.perm_invent) ) // doesn't work yet - { - dialog->hide(); - } - int result=dialog->result(); - - // Consume ^M (which QDialog steals for default button) - while (!keysource.Empty() && - (keysource.TopAscii()=='\n' || keysource.TopAscii()=='\r')) - keysource.GetAscii(); - - *menu_list=0; - if (how==PICK_NONE) - return result==0 ? -1 : 0; - - if (result>0) { - if (how==PICK_ONE) { - int i; - for (i=0; istate()&ShiftButton)) { - if (event->key()==Key_Prior) { - setYOffset(yOffset()-viewHeight()); - } else if (event->key()==Key_Next) { - setYOffset(yOffset()+viewHeight()); - } else { - event->ignore(); - } - } else { - event->ignore(); - } -} - -void NetHackQtMenuWindow::All() -{ - for (int i=0; iAccept(); - } - } -} - - -void NetHackQtMenuWindow::paintCell(QPainter* painter, int row, int col) -{ - // [pick-count] [accel] [glyph] [string] - - MenuItem& i = item[row]; - - painter->setPen(black); - painter->setFont(font()); - - if (i.selected) { - painter->setPen(darkGreen); - } - - switch (col) { - case 0: - if ( i.ch || i.attr!=ATR_INVERSE ) { - QString text; - if ( i.selected && i.count == -1 ) { - if ( i.str[0]>='0' && i.str[0]<='9' ) - text = "All"; - else - text = "*"; - } else if ( i.count<0 ) { - text = "-"; - } else { - text.sprintf("%d",i.count); - } - painter->drawText(0,0,cellWidth(col),cellHeight(), - AlignHCenter|AlignVCenter,text); - } - break; case 1: - if ((signed char)i.ch >= 0) { - char text[2]={i.ch,0}; - painter->drawText(0,0,cellWidth(col),cellHeight(), - AlignHCenter|AlignVCenter,text); - } - break; case 2: - if (i.glyph!=NO_GLYPH) { - // Centered in height - int y=(cellHeight()-qt_settings->glyphs().height())/2; - if (y<0) y=0; - qt_settings->glyphs().drawGlyph(*painter, i.glyph, 0, y); - } - break; case 3: - // XXX should qt_settings have ALL the various fonts - QFont newfont=font(); - - if (i.attr) { - switch(i.attr) { - case ATR_ULINE: - newfont.setUnderline(TRUE); - break; case ATR_BOLD: - painter->setPen(red); - break; case ATR_BLINK: - newfont.setItalic(TRUE); - break; case ATR_INVERSE: - newfont=qt_settings->largeFont(); - newfont.setWeight(QFont::Bold); - - if (i.selected) { - painter->setPen(blue); - } else { - painter->setPen(darkBlue); - } - } - } - painter->setFont(newfont); - - painter->drawText(STR_MARGIN,0,cellWidth(col),cellHeight(), - AlignLeft|AlignVCenter,i.str); - } -} - -void NetHackQtMenuWindow::mousePressEvent(QMouseEvent* event) -{ - int col=findCol(event->pos().x()); - int row=findRow(event->pos().y()); - - if (col<0 || row<0 || !item[row].Selectable()) return; - - if (how!=PICK_NONE) { - if (col==0) { - // Changing count. - NetHackQtStringRequestor requestor(keysource,"Count:"); - char buf[BUFSZ]; - - if (item[row].count>0) - Sprintf(buf,"%d", item[row].count); - else - Strcpy(buf, ""); - - requestor.SetDefault(buf); - if (requestor.Get(buf)) { - item[row].count=atoi(buf); - if (item[row].count==0) { - item[row].count=-1; - if (item[row].selected) ToggleSelect(row); - } else { - if (!item[row].selected) ToggleSelect(row); - } - updateCell(row,0); - } - } else { - pressed=row; - was_sel=item[row].selected; - ToggleSelect(row); - updateCell(row,0); - } - } -} - -void NetHackQtMenuWindow::mouseReleaseEvent(QMouseEvent* event) -{ - if (pressed>=0) { - int p=pressed; - pressed=-1; - updateCell(p,3); - } -} - -void NetHackQtMenuWindow::mouseMoveEvent(QMouseEvent* event) -{ - if (pressed>=0) { - int col=findCol(event->pos().x()); - int row=findRow(event->pos().y()); - - if (row>=0 && col>=0) { - if (pressed!=row) { - // reset to initial state - if (item[pressed].selected!=was_sel) - ToggleSelect(pressed); - } else { - // reset to new state - if (item[pressed].selected==was_sel) - ToggleSelect(pressed); - } - } - } -} - - -class NetHackQtTextListBox : public QListBox { -public: - NetHackQtTextListBox(QWidget* parent) : QListBox(parent) { } - - int TotalWidth() - { - doLayout(); - return contentsWidth(); - } - int TotalHeight() - { - doLayout(); - return contentsHeight(); - } - - virtual void setFont(const QFont &font) - { - QListBox::setFont(font); - } - void keyPressEvent(QKeyEvent* e) - { - QListBox::keyPressEvent(e); - } -}; - - -QPixmap* NetHackQtRIP::pixmap=0; - -NetHackQtRIP::NetHackQtRIP(QWidget* parent) : - QWidget(parent) -{ - if (!pixmap) { - pixmap=new QPixmap; - tryload(*pixmap, "rip.xpm"); - } - riplines=0; - resize(pixmap->width(),pixmap->height()); - setFont(QFont("times",12)); // XXX may need to be configurable -} - -void NetHackQtRIP::setLines(char** l, int n) -{ - line=l; - riplines=n; -} - -QSize NetHackQtRIP::sizeHint() const -{ - return pixmap->size(); -} - -void NetHackQtRIP::paintEvent(QPaintEvent* event) -{ - if ( riplines ) { - int pix_x=(width()-pixmap->width())/2; - int pix_y=(height()-pixmap->height())/2; - - // XXX positions based on RIP image - int rip_text_x=pix_x+156; - int rip_text_y=pix_y+67; - int rip_text_h=94/riplines; - - QPainter painter; - painter.begin(this); - painter.drawPixmap(pix_x,pix_y,*pixmap); - for (int i=0; imainWidget(),0,FALSE), - keysource(ks), - use_rip(FALSE), - str_fixed(FALSE), - ok("Dismiss",this), - search("Search",this), - lines(new NetHackQtTextListBox(this)), - rip(this) -{ - ok.setDefault(TRUE); - connect(&ok,SIGNAL(clicked()),this,SLOT(accept())); - connect(&search,SIGNAL(clicked()),this,SLOT(Search())); - connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate())); - - QVBoxLayout* vb = new QVBoxLayout(this); - vb->addWidget(&rip); - QHBoxLayout* hb = new QHBoxLayout(vb); - hb->addWidget(&ok); - hb->addWidget(&search); - vb->addWidget(lines); -} - -void NetHackQtTextWindow::doUpdate() -{ - update(); -} - - -NetHackQtTextWindow::~NetHackQtTextWindow() -{ - -} - -QWidget* NetHackQtTextWindow::Widget() -{ - return this; -} - -bool NetHackQtTextWindow::Destroy() -{ - return !isVisible(); -} - -void NetHackQtTextWindow::UseRIP(int how, time_t when) -{ -// Code from X11 windowport -#define STONE_LINE_LEN 16 /* # chars that fit on one line */ -#define NAME_LINE 0 /* line # for player name */ -#define GOLD_LINE 1 /* line # for amount of gold */ -#define DEATH_LINE 2 /* line # for death description */ -#define YEAR_LINE 6 /* line # for year */ - -static char** rip_line=0; - if (!rip_line) { - rip_line=new char*[YEAR_LINE+1]; - for (int i=0; i STONE_LINE_LEN) { - for(i = STONE_LINE_LEN; - ((i0 > STONE_LINE_LEN) && i); i--) - if(dpx[i] == ' ') i0 = i; - if(!i) i0 = STONE_LINE_LEN; - } - tmpchar = dpx[i0]; - dpx[i0] = 0; - strcpy(rip_line[line], dpx); - if (tmpchar != ' ') { - dpx[i0] = tmpchar; - dpx= &dpx[i0]; - } else dpx= &dpx[i0+1]; - } - - /* Put year on stone */ - year = yyyymmdd(when) / 10000L; - Sprintf(rip_line[YEAR_LINE], "%4ld", year); - - rip.setLines(rip_line,YEAR_LINE+1); - - use_rip=TRUE; -} - -void NetHackQtTextWindow::Clear() -{ - lines->clear(); - use_rip=FALSE; - str_fixed=FALSE; -} - -void NetHackQtTextWindow::Display(bool block) -{ - if (str_fixed) { - lines->setFont(qt_settings->normalFixedFont()); - } else { - lines->setFont(qt_settings->normalFont()); - } - - int h=0; - if (use_rip) { - h+=rip.height(); - ok.hide(); - search.hide(); - rip.show(); - } else { - h+=ok.height()*2; - ok.show(); - search.show(); - rip.hide(); - } - int mh = QApplication::desktop()->height()*3/5; - if ( qt_compact_mode && (lines->TotalHeight() > mh || use_rip) ) { - // big, so make it fill - showMaximized(); - } else { - resize(QMAX(use_rip ? rip.width() : 200, - lines->TotalWidth()+24), - QMIN(mh, lines->TotalHeight()+h)); - centerOnMain(this); - show(); - } - if (block) { - setResult(-1); - while (result()==-1) { - qApp->enter_loop(); - if (result()==-1 && !keysource.Empty()) { - char k=keysource.GetAscii(); - if (k=='\033' || k==' ' || k=='\r' || k=='\n') { - accept(); - } else if (k=='/') { - Search(); - } - } - } - } -} - -void NetHackQtTextWindow::PutStr(int attr, const char* text) -{ - str_fixed=str_fixed || strstr(text," "); - lines->insertItem(text); -} - -void NetHackQtTextWindow::done(int i) -{ - setResult(i+1000); - hide(); - qApp->exit_loop(); -} - -void NetHackQtTextWindow::keyPressEvent(QKeyEvent* e) -{ - if ( e->ascii() != '\r' && e->ascii() != '\n' && e->ascii() != '\033' ) - lines->keyPressEvent(e); - else - QDialog::keyPressEvent(e); -} - -void NetHackQtTextWindow::Search() -{ - NetHackQtStringRequestor requestor(keysource,"Search for:"); - static char line[256]=""; - requestor.SetDefault(line); - if (requestor.Get(line)) { - int current=lines->currentItem(); - for (uint i=1; icount(); i++) { - int lnum=(i+current)%lines->count(); - QString str=lines->text(lnum); - if (str.contains(line)) { - lines->setCurrentItem(lnum); - lines->centerCurrentItem(); - return; - } - } - lines->setCurrentItem(-1); - } -} - - -NetHackQtDelay::NetHackQtDelay(int ms) : - msec(ms) -{ -} - -void NetHackQtDelay::wait() -{ - startTimer(msec); - qApp->enter_loop(); -} - -void NetHackQtDelay::timerEvent(QTimerEvent* timer) -{ - qApp->exit_loop(); - killTimers(); -} - -NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget* parent) : - QWidget(parent) -{ -} - -void NetHackQtInvUsageWindow::drawWorn(QPainter& painter, obj* nhobj, int x, int y, bool canbe) -{ - short int glyph; - if (nhobj) - glyph=obj_to_glyph(nhobj, rn2_on_display_rng); - else if (canbe) - glyph=cmap_to_glyph(S_room); - else - glyph=cmap_to_glyph(S_stone); - - qt_settings->glyphs().drawCell(painter,glyph,x,y); -} - -void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*) -{ - // 012 - // - //0 WhB - //1 s"w - //2 gCg - //3 =A= - //4 T - //5 S - - QPainter painter; - painter.begin(this); - - // Blanks - drawWorn(painter,0,0,4,FALSE); - drawWorn(painter,0,0,5,FALSE); - drawWorn(painter,0,2,4,FALSE); - drawWorn(painter,0,2,5,FALSE); - - drawWorn(painter,uarm,1,3); // Armour - drawWorn(painter,uarmc,1,2); // Cloak - drawWorn(painter,uarmh,1,0); // Helmet - drawWorn(painter,uarms,0,1); // Shield - drawWorn(painter,uarmg,0,2); // Gloves - repeated - drawWorn(painter,uarmg,2,2); // Gloves - repeated - drawWorn(painter,uarmf,1,5); // Shoes (feet) - drawWorn(painter,uarmu,1,4); // Undershirt - drawWorn(painter,uleft,0,3); // RingL - drawWorn(painter,uright,2,3); // RingR - - drawWorn(painter,uwep,2,1); // Weapon - drawWorn(painter,uswapwep,0,0); // Secondary weapon - drawWorn(painter,uamul,1,1); // Amulet - drawWorn(painter,ublindf,2,0); // Blindfold - - painter.end(); -} - -class SmallToolButton : public QToolButton { -public: - SmallToolButton(const QPixmap & pm, const QString &textLabel, - const QString& grouptext, - QObject * receiver, const char* slot, - QToolBar * parent) : - QToolButton(pm, textLabel, -#if QT_VERSION < 210 - QString::null, -#else - grouptext, -#endif - receiver, slot, parent) - { - } - - QSize sizeHint() const - { - // get just a couple more pixels for the map - return QToolButton::sizeHint()-QSize(0,2); - } -}; - - -NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : - message(0), map(0), status(0), invusage(0), - keysink(ks), dirkey(0) -{ - QToolBar* toolbar = new QToolBar(this); -#if QT_VERSION >= 210 - setToolBarsMovable(FALSE); - toolbar->setHorizontalStretchable(TRUE); - toolbar->setVerticalStretchable(TRUE); -#endif - addToolBar(toolbar); - menubar = menuBar(); - - setCaption("Qt NetHack"); - if ( qt_compact_mode ) - setIcon(QPixmap(nh_icon_small)); - else - setIcon(QPixmap(nh_icon)); - - QPopupMenu* game=new QPopupMenu; - QPopupMenu* apparel=new QPopupMenu; - QPopupMenu* act1=new QPopupMenu; - QPopupMenu* act2 = qt_compact_mode ? new QPopupMenu : act1; - QPopupMenu* magic=new QPopupMenu; - QPopupMenu* info=new QPopupMenu; - - QPopupMenu *help; - -#ifdef KDE - help = kapp->getHelpMenu( TRUE, "" ); - help->insertSeparator(); -#else - help = qt_compact_mode ? info : new QPopupMenu; -#endif - - enum { OnDesktop=1, OnHandhelds=2 }; - struct Macro { - QPopupMenu* menu; - const char* name; - const char* action; - int flags; - } item[] = { - { game, 0, 0, 3}, - { game, "Version\tv", "v", 3}, - { game, "Compilation\tAlt+V", "\366", 3}, - { game, "History\tShift+V", "V", 3}, - { game, "Redraw\tCtrl+R", "\022", 0}, // useless - { game, "Options\tShift+O", "O", 3}, - { game, "Explore mode\tShift+X", "X", 3}, - { game, 0, 0, 3}, - { game, "Save\tSy", "Sy", 3}, - { game, "Quit\tAlt+Q", "\361", 3}, - - { apparel, "Apparel off\tShift+A", "A", 2}, - { apparel, "Remove many\tShift+A", "A", 1}, - { apparel, 0, 0, 3}, - { apparel, "Wield weapon\tw", "w", 3}, - { apparel, "Exchange weapons\tx", "x", 3}, - { apparel, "Two weapon combat\t#two", "#tw", 3}, - { apparel, "Load quiver\tShift+Q", "Q", 3}, - { apparel, 0, 0, 3}, - { apparel, "Wear armour\tShift+W", "W", 3}, - { apparel, "Take off armour\tShift+T", "T", 3}, - { apparel, 0, 0, 3}, - { apparel, "Put on non-armour\tShift+P", "P", 3}, - { apparel, "Remove non-armour\tShift+R", "R", 3}, - - { act1, "Again\tCtrl+A", "\001", 2}, - { act1, 0, 0, 3}, - { act1, "Apply\ta?", "a?", 3}, - { act1, "Chat\tAlt+C", "\343", 3}, - { act1, "Close door\tc", "c", 3}, - { act1, "Down\t>", ">", 3}, - { act1, "Drop many\tShift+D", "D", 2}, - { act1, "Drop\td?", "d?", 2}, - { act1, "Eat\te?", "e?", 2}, - { act1, "Engrave\tShift+E", "E", 3}, - { act1, "Fight\tShift+F", "F", 3}, - { act1, "Fire from quiver\tf", "f", 2}, - { act1, "Force\tAlt+F", "\346", 3}, - { act1, "Get\t,", ",", 2}, - { act1, "Jump\tAlt+J", "\352", 3}, - { act2, "Kick\tCtrl+D", "\004", 2}, - { act2, "Loot\tAlt+L", "\354", 3}, - { act2, "Open door\to", "o", 3}, - { act2, "Pay\tp", "p", 3}, - { act2, "Rest\t.", ".", 2}, - { act2, "Ride\t#ri", "#ri", 3}, - { act2, "Search\ts", "s", 3}, - { act2, "Sit\tAlt+S", "\363", 3}, - { act2, "Throw\tt", "t", 2}, - { act2, "Untrap\t#u", "#u", 3}, - { act2, "Up\t<", "<", 3}, - { act2, "Wipe face\tAlt+W", "\367", 3}, - - { magic, "Quaff potion\tq?", "q?", 3}, - { magic, "Read scroll/book\tr?", "r?", 3}, - { magic, "Zap wand\tz?", "z?", 3}, - { magic, "Zap spell\tShift+Z", "Z", 3}, - { magic, "Dip\tAlt+D", "\344", 3}, - { magic, "Rub\tAlt+R", "\362", 3}, - { magic, "Invoke\tAlt+I", "\351", 3}, - { magic, 0, 0, 3}, - { magic, "Offer\tAlt+O", "\357", 3}, - { magic, "Pray\tAlt+P", "\360", 3}, - { magic, 0, 0, 3}, - { magic, "Teleport\tCtrl+T", "\024", 3}, - { magic, "Monster action\tAlt+M", "\355", 3}, - { magic, "Turn undead\tAlt+T", "\364", 3}, - - { help, "Help\t?", "?", 3}, - { help, 0, 0, 3}, - { help, "What is here\t:", ":", 3}, - { help, "What is there\t;", ";", 3}, - { help, "What is...\t/y", "/y", 2}, - { help, 0, 0, 1}, - - { info, "Inventory\ti", "i", 3}, -#ifdef SLASHEM - { info, "Angbandish inventory\t*", "*", 3}, -#endif - { info, "Conduct\t#co", "#co", 3}, - { info, "Discoveries\t\\", "\\", 3}, - { info, "List/reorder spells\t+", "+", 3}, - { info, "Adjust letters\tAlt+A", "\341", 2}, - { info, 0, 0, 3}, - { info, "Name object\tAlt+N", "\356y?", 3}, - { info, "Name object type\tAlt+N", "\356n?", 3}, - { info, "Name creature\tShift+C", "C", 3}, - { info, 0, 0, 3}, - { info, "Qualifications\tAlt+E", "\345", 3}, - - { 0, 0, 0, 0 } - }; - - int i; - int count=0; - for (i=0; item[i].menu; i++) - if (item[i].name) count++; - - macro=new const char* [count]; - - game->insertItem("Qt settings...",1000); - help->insertItem("About Qt NetHack...",2000); - //help->insertItem("NetHack Guidebook...",3000); - help->insertSeparator(); - - count=0; - for (i=0; item[i].menu; i++) { - if ( item[i].flags & (qt_compact_mode ? 1 : 2) ) { - if (item[i].name) { - QString name = item[i].name; - if ( qt_compact_mode ) // accelerators aren't - name.replace(QRegExp("\t.*"),""); - item[i].menu->insertItem(name,count); - macro[count++]=item[i].action; - } else { - item[i].menu->insertSeparator(); - } - } - } - - menubar->insertItem("Game",game); - menubar->insertItem("Gear",apparel); - - if ( qt_compact_mode ) { - menubar->insertItem("A-J",act1); - menubar->insertItem("K-Z",act2); - menubar->insertItem("Magic",magic); - menubar->insertItem(QPixmap(info_xpm),info); - menubar->insertItem(QPixmap(map_xpm), this, SLOT(raiseMap())); - menubar->insertItem(QPixmap(msg_xpm), this, SLOT(raiseMessages())); - menubar->insertItem(QPixmap(stat_xpm), this, SLOT(raiseStatus())); - } else { - menubar->insertItem("Action",act1); - menubar->insertItem("Magic",magic); - menubar->insertItem("Info",info); - menubar->insertSeparator(); - menubar->insertItem("Help",help); - } - - QSignalMapper* sm = new QSignalMapper(this); - connect(sm, SIGNAL(mapped(const QString&)), this, SLOT(doKeys(const QString&))); - QToolButton* tb; - tb = new SmallToolButton( QPixmap(again_xpm),"Again","Action", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "\001" ); - tb = new SmallToolButton( QPixmap(get_xpm),"Get","Action", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "," ); - tb = new SmallToolButton( QPixmap(kick_xpm),"Kick","Action", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "\004" ); - tb = new SmallToolButton( QPixmap(throw_xpm),"Throw","Action", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "t" ); - tb = new SmallToolButton( QPixmap(fire_xpm),"Fire","Action", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "f" ); - tb = new SmallToolButton( QPixmap(drop_xpm),"Drop","Action", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "D" ); - tb = new SmallToolButton( QPixmap(eat_xpm),"Eat","Action", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "e" ); - tb = new SmallToolButton( QPixmap(rest_xpm),"Rest","Action", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "." ); - tb = new SmallToolButton( QPixmap(cast_a_xpm),"Cast A","Magic", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "Za" ); - tb = new SmallToolButton( QPixmap(cast_b_xpm),"Cast B","Magic", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "Zb" ); - tb = new SmallToolButton( QPixmap(cast_c_xpm),"Cast C","Magic", sm, SLOT(map()), toolbar ); - sm->setMapping(tb, "Zc" ); - if ( !qt_compact_mode ) { - QWidget* filler = new QWidget(toolbar); - filler->setBackgroundMode(PaletteButton); - toolbar->setStretchableWidget(filler); - } - - connect(menubar,SIGNAL(activated(int)),this,SLOT(doMenuItem(int))); - -#ifdef KDE - setMenu (menubar); -#endif - - int x=0,y=0; - int w=QApplication::desktop()->width()-10; // XXX arbitrary extra space for frame - int h=QApplication::desktop()->height()-50; - - int maxwn; - int maxhn; - if (qt_tilewidth != NULL) { - maxwn = atoi(qt_tilewidth) * COLNO + 10; - } else { - maxwn = 1400; - } - if (qt_tileheight != NULL) { - maxhn = atoi(qt_tileheight) * ROWNO * 6/4; - } else { - maxhn = 1024; - } - - // Be exactly the size we want to be - full map... - if (w>maxwn) { - x+=(w-maxwn)/2; - w=maxwn; // Doesn't need to be any wider - } - if (h>maxhn) { - y+=(h-maxhn)/2; - h=maxhn; // Doesn't need to be any taller - } - - setGeometry(x,y,w,h); - - if ( qt_compact_mode ) { - stack = new QWidgetStack(this); - setCentralWidget(stack); - } else { - setCentralWidget(new QWidget(this)); - invusage = new NetHackQtInvUsageWindow(centralWidget()); - } -} - -void NetHackQtMainWindow::zoomMap() -{ - qt_settings->toggleGlyphSize(); -} - -void NetHackQtMainWindow::raiseMap() -{ - if ( stack->id(stack->visibleWidget()) == 0 ) { - zoomMap(); - } else { - stack->raiseWidget(0); - } -} - -void NetHackQtMainWindow::raiseMessages() -{ - stack->raiseWidget(1); -} - -void NetHackQtMainWindow::raiseStatus() -{ - stack->raiseWidget(2); -} - -class NetHackMimeSourceFactory : public QMimeSourceFactory { -public: - const QMimeSource* data(const QString& abs_name) const - { - const QMimeSource* r = 0; - if ( (NetHackMimeSourceFactory*)this == QMimeSourceFactory::defaultFactory() ) - r = QMimeSourceFactory::data(abs_name); - else - r = QMimeSourceFactory::defaultFactory()->data(abs_name); - if ( !r ) { - int sl = abs_name.length(); - do { - sl = abs_name.findRev('/',sl-1); - QString name = sl>=0 ? abs_name.mid(sl+1) : abs_name; - int dot = name.findRev('.'); - if ( dot >= 0 ) - name = name.left(dot); - if ( name == "map" ) - r = new QImageDrag(QImage(map_xpm)); - else if ( name == "msg" ) - r = new QImageDrag(QImage(msg_xpm)); - else if ( name == "stat" ) - r = new QImageDrag(QImage(stat_xpm)); - } while (!r && sl>0); - } - return r; - } -}; - -void NetHackQtMainWindow::doMenuItem(int id) -{ - switch (id) { - case 1000: - centerOnMain(qt_settings); - qt_settings->show(); - break; - case 2000: - QMessageBox::about(this, "About Qt NetHack", aboutMsg()); - break; - case 3000: { - QDialog dlg(this,0,TRUE); - (new QVBoxLayout(&dlg))->setAutoAdd(TRUE); - QTextBrowser browser(&dlg); - NetHackMimeSourceFactory ms; - browser.setMimeSourceFactory(&ms); - browser.setSource(QDir::currentDirPath()+"/Guidebook.html"); - if ( qt_compact_mode ) - dlg.showMaximized(); - dlg.exec(); - } - break; - default: - if ( id >= 0 ) - doKeys(macro[id]); - } -} - -void NetHackQtMainWindow::doKeys(const QString& k) -{ - keysink.Put(k); - qApp->exit_loop(); -} - -void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window) -{ - message=window; - ShowIfReady(); -} - -void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow* window) -{ - map=window; - ShowIfReady(); - connect(map,SIGNAL(resized()),this,SLOT(layout())); -} - -void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window) -{ - status=window; - ShowIfReady(); -} - -void NetHackQtMainWindow::RemoveWindow(NetHackQtWindow* window) -{ - if (window==status) { - status=0; - ShowIfReady(); - } else if (window==map) { - map=0; - ShowIfReady(); - } else if (window==message) { - message=0; - ShowIfReady(); - } -} - -void NetHackQtMainWindow::updateInventory() -{ - if ( invusage ) - invusage->repaint(FALSE); -} - -void NetHackQtMainWindow::fadeHighlighting() -{ - if (status) { - status->fadeHighlighting(); - } -} - -void NetHackQtMainWindow::layout() -{ - if ( qt_compact_mode ) - return; - if (message && map && status) { - QSize maxs=map->Widget()->maximumSize(); - int maph=QMIN(height()*2/3,maxs.height()); - - QWidget* c = centralWidget(); - int h=c->height(); - int toph=h-maph; - int iuw=3*qt_settings->glyphs().width(); - int topw=(c->width()-iuw)/2; - - message->Widget()->setGeometry(0,0,topw,toph); - invusage->setGeometry(topw,0,iuw,toph); - status->Widget()->setGeometry(topw+iuw,0,topw,toph); - map->Widget()->setGeometry(QMAX(0,(c->width()-maxs.width())/2), - toph,c->width(),maph); - } -} - -void NetHackQtMainWindow::resizeEvent(QResizeEvent*) -{ - layout(); -#ifdef KDE - updateRects(); -#endif -} - -void NetHackQtMainWindow::keyReleaseEvent(QKeyEvent* event) -{ - if ( dirkey ) { - doKeys(QString(QChar(dirkey))); - if ( !event->isAutoRepeat() ) - dirkey = 0; - } -} - -void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event) -{ - // Global key controls - - // For desktop, arrow keys scroll map, since we don't want players - // to think that's the way to move. For handhelds, the normal way is to - // click-to-travel, so we allow the cursor keys for fine movements. - - // 321 - // 4 0 - // 567 - - if ( event->isAutoRepeat() && - event->key() >= Key_Left && event->key() <= Key_Down ) - return; - - const char* d = Cmd.dirchars; - switch (event->key()) { - case Key_Up: - if ( dirkey == d[0] ) - dirkey = d[1]; - else if ( dirkey == d[4] ) - dirkey = d[3]; - else - dirkey = d[2]; - break; case Key_Down: - if ( dirkey == d[0] ) - dirkey = d[7]; - else if ( dirkey == d[4] ) - dirkey = d[5]; - else - dirkey = d[6]; - break; case Key_Left: - if ( dirkey == d[2] ) - dirkey = d[1]; - else if ( dirkey == d[6] ) - dirkey = d[7]; - else - dirkey = d[0]; - break; case Key_Right: - if ( dirkey == d[2] ) - dirkey = d[3]; - else if ( dirkey == d[6] ) - dirkey = d[5]; - else - dirkey = d[4]; - break; case Key_Prior: - dirkey = 0; - if (message) message->Scroll(0,-1); - break; case Key_Next: - dirkey = 0; - if (message) message->Scroll(0,+1); - break; case Key_Space: - if ( flags.rest_on_space ) { - event->ignore(); - return; - } - case Key_Enter: - if ( map ) - map->clickCursor(); - break; default: - dirkey = 0; - event->ignore(); - } -} - -void NetHackQtMainWindow::closeEvent(QCloseEvent* e) -{ - if ( program_state.something_worth_saving ) { - switch ( QMessageBox::information( this, "NetHack", - "This will end your NetHack session", - "&Save", "&Cancel", 0, 1 ) ) - { - case 0: - // See dosave() function - if (dosave0()) { - u.uhp = -1; - NetHackQtBind::qt_exit_nhwindows(0); - nh_terminate(EXIT_SUCCESS); - } - break; - case 1: - break; // ignore the event - } - } else { - e->accept(); - } -} - -void NetHackQtMainWindow::ShowIfReady() -{ - if (message && map && status) { - QPoint pos(0,0); - QWidget* p = qt_compact_mode ? stack : centralWidget(); - message->Widget()->recreate(p,0,pos); - map->Widget()->recreate(p,0,pos); - status->Widget()->recreate(p,0,pos); - if ( qt_compact_mode ) { - message->setMap(map); - stack->addWidget(map->Widget(), 0); - stack->addWidget(message->Widget(), 1); - stack->addWidget(status->Widget(), 2); - raiseMap(); - } else { - layout(); - } - showMaximized(); - } else if (isVisible()) { - hide(); - } -} - - -NetHackQtYnDialog::NetHackQtYnDialog(NetHackQtKeyBuffer& keysrc,const char* q,const char* ch,char df) : - QDialog(qApp->mainWidget(),0,FALSE), - question(q), choices(ch), def(df), - keysource(keysrc) -{ - setCaption("NetHack: Question"); -} - -char NetHackQtYnDialog::Exec() -{ - QString ch(choices); - int ch_per_line=6; - QString qlabel; - QString enable; - if ( qt_compact_mode && !choices ) { - // expand choices from prompt - // ##### why isn't choices set properly??? - const char* c=question; - while ( *c && *c != '[' ) - c++; - qlabel = QString(question).left(c-question); - if ( *c ) { - c++; - if ( *c == '-' ) - ch.append(*c++); - char from=0; - while ( *c && *c != ']' && *c != ' ' ) { - if ( *c == '-' ) { - from = c[-1]; - } else if ( from ) { - for (char f=from+1; f<=*c; f++) - ch.append(f); - from = 0; - } else { - ch.append(*c); - from = 0; - } - c++; - } - if ( *c == ' ' ) { - while ( *c && *c != ']' ) { - if ( *c == '*' || *c == '?' ) - ch.append(*c); - c++; - } - } - } - if ( strstr(question, "what direction") ) { - // We replace this regardless, since sometimes you get choices. - const char* d = Cmd.dirchars; - enable=ch; - ch=""; - ch.append(d[1]); - ch.append(d[2]); - ch.append(d[3]); - ch.append(d[0]); - ch.append('.'); - ch.append(d[4]); - ch.append(d[7]); - ch.append(d[6]); - ch.append(d[5]); - ch.append(d[8]); - ch.append(d[9]); - ch_per_line = 3; - def = ' '; - } else { - // Hmm... they'll have to use a virtual keyboard - } - } else { - qlabel = question; - } - if (!ch.isNull()) { - QVBoxLayout vb(this); - vb.setAutoAdd(TRUE); - bool bigq = qlabel.length()>40; - if ( bigq ) { - QLabel* q = new QLabel(qlabel,this); - q->setAlignment(AlignLeft|WordBreak); - q->setMargin(4); - } - QButtonGroup group(ch_per_line, Horizontal, - bigq ? QString::null : qlabel, this); - - int nchoices=ch.length(); - - bool allow_count=ch.contains('#'); - - const int margin=8; - const int gutter=8; - const int extra=fontMetrics().height(); // Extra for group - int x=margin, y=extra+margin; - int butsize=fontMetrics().height()*2+5; - - QPushButton* button; - for (int i=0; isetEnabled(FALSE); - } - button->setFixedSize(butsize,butsize); // Square - if (ch[i]==def) button->setDefault(TRUE); - if (i%10==9) { - // last in row - x=margin; - y+=butsize+gutter; - } else { - x+=butsize+gutter; - } - } - - connect(&group,SIGNAL(clicked(int)),this,SLOT(doneItem(int))); - - QLabel* lb=0; - QLineEdit* le=0; - - if (allow_count) { - QHBox *hb = new QHBox(this); - lb=new QLabel("Count: ",hb); - le=new QLineEdit(hb); - } - - adjustSize(); - centerOnMain(this); - show(); - char choice=0; - char ch_esc=0; - for (uint i=0; i= 1000 ) { - choice = ch[result() - 1000].latin1(); - } - if ( !choice ) - qApp->enter_loop(); - } - hide(); - if (allow_count && !le->text().isEmpty()) { - yn_number=atoi(le->text()); - choice='#'; - } - return choice; - } else { - QLabel label(qlabel,this); - QPushButton cancel("Dismiss",this); - label.setFrameStyle(QFrame::Box|QFrame::Sunken); - label.setAlignment(AlignCenter); - label.resize(fontMetrics().width(qlabel)+60,30+fontMetrics().height()); - cancel.move(width()/2-cancel.width()/2,label.geometry().bottom()+8); - connect(&cancel,SIGNAL(clicked()),this,SLOT(reject())); - centerOnMain(this); - setResult(-1); - show(); - while (result()<0 && keysource.Empty()) { - qApp->enter_loop(); - } - hide(); - if (keysource.Empty()) { - return '\033'; - } else { - return keysource.GetAscii(); - } - } -} -void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event) -{ - // Don't want QDialog's Return/Esc behaviour - event->ignore(); -} - -void NetHackQtYnDialog::doneItem(int i) -{ - done(i+1000); -} - -void NetHackQtYnDialog::done(int i) -{ - setResult(i); - qApp->exit_loop(); -} - -NetHackQtGlyphs::NetHackQtGlyphs() -{ - const char* tile_file = "nhtiles.bmp"; - if ( iflags.wc_tile_file ) - tile_file = iflags.wc_tile_file; - - if (!img.load(tile_file)) { - tile_file = "x11tiles"; - if (!img.load(tile_file)) { - QString msg; - msg.sprintf("Cannot load x11tiles or nhtiles.bmp"); - QMessageBox::warning(0, "IO Error", msg); - } else { - tiles_per_row = TILES_PER_ROW; - if (img.width()%tiles_per_row) { - impossible( - "Tile file \"%s\" has %d columns, not multiple of row count (%d)", - tile_file, img.width(), tiles_per_row); - } - } - } else { - tiles_per_row = 40; - } - - if ( iflags.wc_tile_width ) - tilefile_tile_W = iflags.wc_tile_width; - else - tilefile_tile_W = img.width() / tiles_per_row; - if ( iflags.wc_tile_height ) - tilefile_tile_H = iflags.wc_tile_height; - else - tilefile_tile_H = tilefile_tile_W; - - setSize(tilefile_tile_W, tilefile_tile_H); -} - -void NetHackQtGlyphs::drawGlyph(QPainter& painter, int glyph, int x, int y) -{ - int tile = glyph2tile[glyph]; - int px = (tile%tiles_per_row)*width(); - int py = tile/tiles_per_row*height(); - - painter.drawPixmap( - x, - y, - pm, - px,py, - width(),height() - ); -} -void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, int cellx, int celly) -{ - drawGlyph(painter,glyph,cellx*width(),celly*height()); -} -void NetHackQtGlyphs::setSize(int w, int h) -{ - if ( size == QSize(w,h) ) - return; - - bool was1 = size == pm1.size(); - size = QSize(w,h); - if (!w || !h) - return; // Still not decided - - if ( size == pm1.size() ) { - pm = pm1; - return; - } - if ( size == pm2.size() ) { - pm = pm2; - return; - } - - if (w==tilefile_tile_W && h==tilefile_tile_H) { - pm.convertFromImage(img); - } else { - QApplication::setOverrideCursor( Qt::waitCursor ); - QImage scaled = img.smoothScale( - w*img.width()/tilefile_tile_W, - h*img.height()/tilefile_tile_H - ); - pm.convertFromImage(scaled,Qt::ThresholdDither|Qt::PreferDither); - QApplication::restoreOverrideCursor(); - } - (was1 ? pm2 : pm1) = pm; -} - - -////////////////////////////////////////////////////////////// -// -// The ugly C binding classes... -// -////////////////////////////////////////////////////////////// - - -NetHackQtMenuOrTextWindow::NetHackQtMenuOrTextWindow(NetHackQtKeyBuffer& ks) : - actual(0), - keysource(ks) -{ -} - -QWidget* NetHackQtMenuOrTextWindow::Widget() -{ - if (!actual) impossible("Widget called before we know if Menu or Text"); - return actual->Widget(); -} - -// Text -void NetHackQtMenuOrTextWindow::Clear() -{ - if (!actual) - impossible("Clear called before we know if Menu or Text"); - else - actual->Clear(); -} - -void NetHackQtMenuOrTextWindow::Display(bool block) -{ - if (!actual) - impossible("Display called before we know if Menu or Text"); - else - actual->Display(block); -} - -bool NetHackQtMenuOrTextWindow::Destroy() -{ - bool res = FALSE; - - if (!actual) - impossible("Destroy called before we know if Menu or Text"); - else - res = actual->Destroy(); - - return res; -} - -void NetHackQtMenuOrTextWindow::PutStr(int attr, const char* text) -{ - if (!actual) actual=new NetHackQtTextWindow(keysource); - actual->PutStr(attr,text); -} - -// Menu -void NetHackQtMenuOrTextWindow::StartMenu() -{ - if (!actual) actual=new NetHackQtMenuWindow(keysource); - actual->StartMenu(); -} - -void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const char* str, bool presel) -{ - if (!actual) impossible("AddMenu called before we know if Menu or Text"); - actual->AddMenu(glyph,identifier,ch,gch,attr,str,presel); -} - -void NetHackQtMenuOrTextWindow::EndMenu(const char* prompt) -{ - if (!actual) impossible("EndMenu called before we know if Menu or Text"); - actual->EndMenu(prompt); -} - -int NetHackQtMenuOrTextWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) -{ - if (!actual) impossible("SelectMenu called before we know if Menu or Text"); - return actual->SelectMenu(how,menu_list); -} - - -// XXX Should be from Options -// -// XXX Hmm. Tricky part is that perhaps some macros should only be active -// XXX when a key is about to be gotten. For example, the user could -// XXX define "-" to do "E-yyyyyyyy\r", but would still need "-" for -// XXX other purposes. Maybe just too bad. -// -struct { - int key; - int state; - const char* macro; -} key_macro[]={ - { Qt::Key_F1, 0, "n100." }, // Rest (x100) - { Qt::Key_F2, 0, "n20s" }, // Search (x20) - { Qt::Key_F3, 0, "o8o4o6o2o8o4o6o2o8o4o6o2" }, // Open all doors (x3) - { Qt::Key_Tab, 0, "\001" }, - { 0, 0, 0 } -}; - - -NetHackQtBind::NetHackQtBind(int& argc, char** argv) : -#ifdef KDE - KApplication(argc,argv) -#elif defined(QWS) // not quite the right condition - QPEApplication(argc,argv) -#else - QApplication(argc,argv) -#endif -{ - QPixmap pm("nhsplash.xpm"); - if ( iflags.wc_splash_screen && !pm.isNull() ) { - QVBox *vb = new QVBox(0,0, - WStyle_Customize | WStyle_NoBorder | nh_WX11BypassWM | WStyle_StaysOnTop ); - splash = vb; - QLabel *lsplash = new QLabel(vb); - lsplash->setAlignment(AlignCenter); - lsplash->setPixmap(pm); - QLabel* capt = new QLabel("Loading...",vb); - capt->setAlignment(AlignCenter); - if ( pm.mask() ) { - lsplash->setFixedSize(pm.size()); - lsplash->setMask(*pm.mask()); - } - splash->move((QApplication::desktop()->width()-pm.width())/2, - (QApplication::desktop()->height()-pm.height())/2); - //splash->setGeometry(0,0,100,100); - if ( qt_compact_mode ) { - splash->showMaximized(); - } else { - vb->setFrameStyle(QFrame::WinPanel|QFrame::Raised); - vb->setMargin(10); - splash->adjustSize(); - splash->show(); - } - - // force content refresh outside event loop - splash->repaint(FALSE); - lsplash->repaint(FALSE); - capt->repaint(FALSE); - qApp->flushX(); - - } else { - splash = 0; - } - main = new NetHackQtMainWindow(keybuffer); -#if defined(QWS) // not quite the right condition - showMainWidget(main); -#else - setMainWidget(main); -#endif - qt_settings=new NetHackQtSettings(main->width(),main->height()); -} - -void NetHackQtBind::qt_init_nhwindows(int* argc, char** argv) -{ -#ifdef UNIX -// Userid control -// -// Michael Hohmuth ... -// -// As the game runs setuid games, it must seteuid(getuid()) before -// calling XOpenDisplay(), and reset the euid afterwards. -// Otherwise, it can't read the $HOME/.Xauthority file and whines about -// not being able to open the X display (if a magic-cookie -// authorization mechanism is being used). - - uid_t gamesuid=geteuid(); - seteuid(getuid()); -#endif - - QApplication::setColorSpec(ManyColor); - instance=new NetHackQtBind(*argc,argv); - -#ifdef UNIX - seteuid(gamesuid); -#endif - -#ifdef _WS_WIN_ - // This nethack engine feature should be moved into windowport API - nt_kbhit = NetHackQtBind::qt_kbhit; -#endif -} - -int NetHackQtBind::qt_kbhit() -{ - return !keybuffer.Empty(); -} - -static bool have_asked = FALSE; - -void NetHackQtBind::qt_player_selection() -{ - if ( !have_asked ) - qt_askname(); -} - -NetHackQtSavedGameSelector::NetHackQtSavedGameSelector(const char** saved) : - QDialog(qApp->mainWidget(),"sgsel",TRUE) -{ - QVBoxLayout *vbl = new QVBoxLayout(this,6); - QHBox* hb; - - QLabel* logo = new QLabel(this); vbl->addWidget(logo); - logo->setAlignment(AlignCenter); - logo->setPixmap(QPixmap("nhsplash.xpm")); - QLabel* attr = new QLabel("by the NetHack DevTeam",this); - attr->setAlignment(AlignCenter); - vbl->addWidget(attr); - vbl->addStretch(2); - /* - QLabel* logo = new QLabel(hb); - hb = new QHBox(this); - vbl->addWidget(hb, AlignCenter); - logo->setPixmap(QPixmap(nh_icon)); - logo->setAlignment(AlignRight|AlignVCenter); - new QLabel(nh_attribution,hb); - */ - - hb = new QHBox(this); - vbl->addWidget(hb, AlignCenter); - QPushButton* q = new QPushButton("Quit",hb); - connect(q, SIGNAL(clicked()), this, SLOT(reject())); - QPushButton* c = new QPushButton("New Game",hb); - connect(c, SIGNAL(clicked()), this, SLOT(accept())); - c->setDefault(TRUE); - - QButtonGroup* bg = new QButtonGroup(3, Horizontal, "Saved Characters",this); - vbl->addWidget(bg); - connect(bg, SIGNAL(clicked(int)), this, SLOT(done(int))); - for (int i=0; saved[i]; i++) { - QPushButton* b = new QPushButton(saved[i],bg); - bg->insert(b, i+2); - } -} - -int NetHackQtSavedGameSelector::choose() -{ -#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). - if ( qt_compact_mode ) - showMaximized(); -#endif - return exec()-2; -} - -void NetHackQtBind::qt_askname() -{ - have_asked = TRUE; - - // We do it all here, and nothing in askname - - char** saved = get_saved_games(); - int ch = -1; - if ( saved && *saved ) { - if ( splash ) splash->hide(); - NetHackQtSavedGameSelector sgsel((const char**)saved); - ch = sgsel.choose(); - if ( ch >= 0 ) - strcpy(plname,saved[ch]); - } - free_saved_games(saved); - - switch (ch) { - case -1: - if ( splash ) splash->hide(); - if (NetHackQtPlayerSelector(keybuffer).Choose()) - return; - case -2: - break; - default: - return; - } - - // Quit - clearlocks(); - qt_exit_nhwindows(0); - nh_terminate(0); -} - -void NetHackQtBind::qt_get_nh_event() -{ -} - -#if defined(QWS) -// Kludge to access lastWindowClosed() signal. -class TApp : public QApplication { -public: - TApp(int& c, char**v) : QApplication(c,v) {} - void lwc() { emit lastWindowClosed(); } -}; -#endif - -void NetHackQtBind::qt_exit_nhwindows(const char *) -{ -#if defined(QWS) - // Avoids bug in SHARP SL5500 - ((TApp*)qApp)->lwc(); - qApp->quit(); -#endif - - delete instance; // ie. qApp -} - -void NetHackQtBind::qt_suspend_nhwindows(const char *) -{ -} - -void NetHackQtBind::qt_resume_nhwindows() -{ -} - -static QArray id_to_window; - -winid NetHackQtBind::qt_create_nhwindow(int type) -{ - winid id; - for (id = 0; id < (winid) id_to_window.size(); id++) { - if ( !id_to_window[id] ) - break; - } - if ( id == (winid) id_to_window.size() ) - id_to_window.resize(id+1); - - NetHackQtWindow* window=0; - - switch (type) { - case NHW_MAP: { - NetHackQtMapWindow* w=new NetHackQtMapWindow(clickbuffer); - main->AddMapWindow(w); - window=w; - } break; case NHW_MESSAGE: { - NetHackQtMessageWindow* w=new NetHackQtMessageWindow; - main->AddMessageWindow(w); - window=w; - } break; case NHW_STATUS: { - NetHackQtStatusWindow* w=new NetHackQtStatusWindow; - main->AddStatusWindow(w); - window=w; - } break; case NHW_MENU: - window=new NetHackQtMenuOrTextWindow(keybuffer); - break; case NHW_TEXT: - window=new NetHackQtTextWindow(keybuffer); - } - - window->nhid = id; - - // Note: use of isHidden does not work with Qt 2.1 - if ( splash -#if QT_VERSION >= 300 - && !main->isHidden() -#else - && main->isVisible() -#endif - ) - { - delete splash; - splash = 0; - } - - id_to_window[id] = window; - return id; -} - -void NetHackQtBind::qt_clear_nhwindow(winid wid) -{ - NetHackQtWindow* window=id_to_window[wid]; - window->Clear(); -} - -void NetHackQtBind::qt_display_nhwindow(winid wid, BOOLEAN_P block) -{ - NetHackQtWindow* window=id_to_window[wid]; - window->Display(block); -} - -void NetHackQtBind::qt_destroy_nhwindow(winid wid) -{ - NetHackQtWindow* window=id_to_window[wid]; - main->RemoveWindow(window); - if (window->Destroy()) - delete window; - id_to_window[wid] = 0; -} - -void NetHackQtBind::qt_curs(winid wid, int x, int y) -{ - NetHackQtWindow* window=id_to_window[wid]; - window->CursorTo(x,y); -} - -void NetHackQtBind::qt_putstr(winid wid, int attr, const char *text) -{ - NetHackQtWindow* window=id_to_window[wid]; - window->PutStr(attr,text); -} - -void NetHackQtBind::qt_display_file(const char *filename, BOOLEAN_P must_exist) -{ - NetHackQtTextWindow* window=new NetHackQtTextWindow(keybuffer); - bool complain = FALSE; - -#ifdef DLB - { - dlb *f; - char buf[BUFSZ]; - char *cr; - - window->Clear(); - f = dlb_fopen(filename, "r"); - if (!f) { - complain = must_exist; - } else { - while (dlb_fgets(buf, BUFSZ, f)) { - if ((cr = index(buf, '\n')) != 0) *cr = 0; -#ifdef MSDOS - if ((cr = index(buf, '\r')) != 0) *cr = 0; -#endif - if (index(buf, '\t') != 0) (void) tabexpand(buf); - window->PutStr(ATR_NONE, buf); - } - window->Display(FALSE); - (void) dlb_fclose(f); - } - } -#else - QFile file(filename); - - if (file.open(IO_ReadOnly)) { - char line[128]; - while (file.readLine(line,127) >= 0) { - line[strlen(line)-1]=0;// remove newline - window->PutStr(ATR_NONE,line); - } - window->Display(FALSE); - } else { - complain = must_exist; - } -#endif - - if (complain) { - QString message; - message.sprintf("File not found: %s\n",filename); - QMessageBox::message("File Error", (const char*)message, "Ignore"); - } -} - -void NetHackQtBind::qt_start_menu(winid wid) -{ - NetHackQtWindow* window=id_to_window[wid]; - window->StartMenu(); -} - -void NetHackQtBind::qt_add_menu(winid wid, int glyph, - const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr, - const char *str, BOOLEAN_P presel) -{ - NetHackQtWindow* window=id_to_window[wid]; - window->AddMenu(glyph, identifier, ch, gch, attr, str, presel); -} - -void NetHackQtBind::qt_end_menu(winid wid, const char *prompt) -{ - NetHackQtWindow* window=id_to_window[wid]; - window->EndMenu(prompt); -} - -int NetHackQtBind::qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list) -{ - NetHackQtWindow* window=id_to_window[wid]; - return window->SelectMenu(how,menu_list); -} - -void NetHackQtBind::qt_update_inventory() -{ - if (main) - main->updateInventory(); - /* doesn't work yet - if (program_state.something_worth_saving && iflags.perm_invent) - display_inventory(NULL, FALSE); - */ -} - -void NetHackQtBind::qt_mark_synch() -{ -} - -void NetHackQtBind::qt_wait_synch() -{ -} - -void NetHackQtBind::qt_cliparound(int x, int y) -{ - // XXXNH - winid should be a parameter! - qt_cliparound_window(WIN_MAP,x,y); -} - -void NetHackQtBind::qt_cliparound_window(winid wid, int x, int y) -{ - NetHackQtWindow* window=id_to_window[wid]; - window->ClipAround(x,y); -} -void NetHackQtBind::qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph, int bkglyph) -{ - NetHackQtWindow* window=id_to_window[wid]; - window->PrintGlyph(x,y,glyph); -} -//void NetHackQtBind::qt_print_glyph_compose(winid wid,XCHAR_P x,XCHAR_P y,int glyph1, int glyph2) -//{ - //NetHackQtWindow* window=id_to_window[wid]; - //window->PrintGlyphCompose(x,y,glyph1,glyph2); -//} - -void NetHackQtBind::qt_raw_print(const char *str) -{ - puts(str); -} - -void NetHackQtBind::qt_raw_print_bold(const char *str) -{ - puts(str); -} - -int NetHackQtBind::qt_nhgetch() -{ - if (main) - main->fadeHighlighting(); - - // Process events until a key arrives. - // - while (keybuffer.Empty() -#ifdef SAFERHANGUP - && !program_state.done_hup -#endif - ) { - qApp->enter_loop(); - } - -#ifdef SAFERHANGUP - if (program_state.done_hup && keybuffer.Empty()) return '\033'; -#endif - return keybuffer.GetAscii(); -} - -int NetHackQtBind::qt_nh_poskey(int *x, int *y, int *mod) -{ - if (main) - main->fadeHighlighting(); - - // Process events until a key or map-click arrives. - // - while (keybuffer.Empty() && clickbuffer.Empty() -#ifdef SAFERHANGUP - && !program_state.done_hup -#endif - ) { - qApp->enter_loop(); - } -#ifdef SAFERHANGUP - if (program_state.done_hup && keybuffer.Empty()) return '\033'; -#endif - if (!keybuffer.Empty()) { - return keybuffer.GetAscii(); - } else { - *x=clickbuffer.NextX(); - *y=clickbuffer.NextY(); - *mod=clickbuffer.NextMod(); - clickbuffer.Get(); - return 0; - } -} - -void NetHackQtBind::qt_nhbell() -{ - QApplication::beep(); -} - -int NetHackQtBind::qt_doprev_message() -{ - // Don't need it - uses scrollbar - // XXX but could make this a shortcut - return 0; -} - -char NetHackQtBind::qt_yn_function(const char *question, const char *choices, CHAR_P def) -{ - if (qt_settings->ynInMessages() && WIN_MESSAGE!=WIN_ERR) { - // Similar to X11 windowport `slow' feature. - - char message[BUFSZ]; - char yn_esc_map='\033'; - - if (choices) { - char *cb, choicebuf[QBUFSZ]; - Strcpy(choicebuf, choices); - if ((cb = index(choicebuf, '\033')) != 0) { - // anything beyond is hidden - *cb = '\0'; - } - (void)strncpy(message, question, QBUFSZ-1); - message[QBUFSZ-1] = '\0'; - Sprintf(eos(message), " [%s]", choicebuf); - if (def) Sprintf(eos(message), " (%c)", def); - Strcat(message, " "); - // escape maps to 'q' or 'n' or default, in that order - yn_esc_map = (index(choices, 'q') ? 'q' : - (index(choices, 'n') ? 'n' : def)); - } else { - Strcpy(message, question); - } - -#ifdef USE_POPUPS - // Improve some special-cases (DIRKS 08/02/23) - if (strcmp (choices,"ynq") == 0) { - switch (QMessageBox::information (qApp->mainWidget(),"NetHack",question,"&Yes","&No","&Quit",0,2)) - { - case 0: return 'y'; - case 1: return 'n'; - case 2: return 'q'; - } - } - - if (strcmp (choices,"yn") == 0) { - switch (QMessageBox::information(qApp->mainWidget(),"NetHack",question,"&Yes", "&No",0,1)) - { - case 0: return 'y'; - case 1: return 'n'; - } - } -#endif - - NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); - - int result=-1; - while (result<0) { - char ch=NetHackQtBind::qt_nhgetch(); - if (ch=='\033') { - result=yn_esc_map; - } else if (choices && !index(choices,ch)) { - if (def && (ch==' ' || ch=='\r' || ch=='\n')) { - result=def; - } else { - NetHackQtBind::qt_nhbell(); - // and try again... - } - } else { - result=ch; - } - } - - NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); - - return result; - } else { - NetHackQtYnDialog dialog(keybuffer,question,choices,def); - return dialog.Exec(); - } -} - -void NetHackQtBind::qt_getlin(const char *prompt, char *line) -{ - NetHackQtStringRequestor requestor(keybuffer,prompt); - if (!requestor.Get(line)) { - line[0]=0; - } -} - -NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(NetHackQtKeyBuffer& ks) : - QDialog(qApp->mainWidget(), "ext-cmd", FALSE), - keysource(ks) -{ - int marg=4; - QVBoxLayout *l = new QVBoxLayout(this,marg,marg); - - QPushButton* can = new QPushButton("Cancel", this); - can->setDefault(TRUE); - can->setMinimumSize(can->sizeHint()); - l->addWidget(can); - - QButtonGroup *group=new QButtonGroup("",0); - QGroupBox *grid=new QGroupBox("Extended commands",this); - l->addWidget(grid); - - int i; - int butw=50; - QFontMetrics fm = fontMetrics(); - for (i=0; extcmdlist[i].ef_txt; i++) { - butw = QMAX(butw,30+fm.width(extcmdlist[i].ef_txt)); - } - int ncols=4; - int nrows=(i+ncols-1)/ncols; - - QVBoxLayout* bl = new QVBoxLayout(grid,marg); - bl->addSpacing(fm.height()); - QGridLayout* gl = new QGridLayout(nrows,ncols,marg); - bl->addLayout(gl); - for (i=0; extcmdlist[i].ef_txt; i++) { - QPushButton* pb=new QPushButton(extcmdlist[i].ef_txt, grid); - pb->setMinimumSize(butw,pb->sizeHint().height()); - group->insert(pb); - gl->addWidget(pb,i/ncols,i%ncols); - } - connect(group,SIGNAL(clicked(int)),this,SLOT(done(int))); - - bl->activate(); - l->activate(); - resize(1,1); - - connect(can,SIGNAL(clicked()),this,SLOT(cancel())); -} - -void NetHackQtExtCmdRequestor::cancel() -{ - setResult(-1); - qApp->exit_loop(); -} - -void NetHackQtExtCmdRequestor::done(int i) -{ - setResult(i); - qApp->exit_loop(); -} - -int NetHackQtExtCmdRequestor::get() -{ - const int none = -10; - char str[32]; - int cursor=0; - resize(1,1); // pack - centerOnMain(this); - show(); - setResult(none); - while (result()==none) { - while (result()==none && !keysource.Empty()) { - char k=keysource.GetAscii(); - if (k=='\r' || k=='\n' || k==' ' || k=='\033') { - setResult(-1); - } else { - str[cursor++] = k; - int r=-1; - for (int i=0; extcmdlist[i].ef_txt; i++) { - if (qstrnicmp(str, extcmdlist[i].ef_txt, cursor)==0) { - if ( r == -1 ) - r = i; - else - r = -2; - } - } - if ( r == -1 ) { // no match! - QApplication::beep(); - cursor=0; - } else if ( r != -2 ) { // only one match - setResult(r); - } - } - } - if (result()==none) - qApp->enter_loop(); - } - hide(); - return result(); -} - - -int NetHackQtBind::qt_get_ext_cmd() -{ - NetHackQtExtCmdRequestor requestor(keybuffer); - return requestor.get(); -} - -void NetHackQtBind::qt_number_pad(int) -{ - // Ignore. -} - -void NetHackQtBind::qt_delay_output() -{ - NetHackQtDelay delay(15); - delay.wait(); -} - -void NetHackQtBind::qt_start_screen() -{ - // Ignore. -} - -void NetHackQtBind::qt_end_screen() -{ - // Ignore. -} - -void NetHackQtBind::qt_outrip(winid wid, int how, time_t when) -{ - NetHackQtWindow* window=id_to_window[wid]; - - window->UseRIP(how, when); -} - -bool NetHackQtBind::notify(QObject *receiver, QEvent *event) -{ - // Ignore Alt-key navigation to menubar, it's annoying when you - // use Alt-Direction to move around. - if ( main && event->type()==QEvent::KeyRelease && main==receiver - && ((QKeyEvent*)event)->key() == Key_Alt ) - return TRUE; - - bool result=QApplication::notify(receiver,event); -#ifdef SAFERHANGUP - if (program_state.done_hup) { - keybuffer.Put('\033'); - qApp->exit_loop(); - return TRUE; - } -#endif - if (event->type()==QEvent::KeyPress) { - QKeyEvent* key_event=(QKeyEvent*)event; - - if (!key_event->isAccepted()) { - const int k=key_event->key(); - bool macro=FALSE; - for (int i=0; !macro && key_macro[i].key; i++) { - if (key_macro[i].key==k - && ((key_macro[i].state&key_event->state())==key_macro[i].state)) - { - keybuffer.Put(key_macro[i].macro); - macro=TRUE; - } - } - char ch=key_event->ascii(); - if ( !ch && (key_event->state() & Qt::ControlButton) ) { - // On Mac, it aint-ncessarily-control - if ( k>=Qt::Key_A && k<=Qt::Key_Z ) - ch = k - Qt::Key_A + 1; - } - if (!macro && ch) { - bool alt = (key_event->state()&AltButton) || - (k >= Key_0 && k <= Key_9 && (key_event->state()&ControlButton)); - keybuffer.Put(key_event->key(),ch + (alt ? 128 : 0), - key_event->state()); - key_event->accept(); - result=TRUE; - } - - if (ch || macro) { - qApp->exit_loop(); - } - } - } - return result; -} - -NetHackQtBind* NetHackQtBind::instance=0; -NetHackQtKeyBuffer NetHackQtBind::keybuffer; -NetHackQtClickBuffer NetHackQtBind::clickbuffer; -NetHackQtMainWindow* NetHackQtBind::main=0; -QWidget* NetHackQtBind::splash=0; - - -extern "C" struct window_procs Qt_procs; - -struct window_procs Qt_procs = { - "Qt", - WC_COLOR|WC_HILITE_PET| - WC_ASCII_MAP|WC_TILED_MAP| - WC_FONT_MAP|WC_TILE_FILE|WC_TILE_WIDTH|WC_TILE_HEIGHT| - WC_PLAYER_SELECTION|WC_SPLASH_SCREEN, - 0L, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ - NetHackQtBind::qt_init_nhwindows, - NetHackQtBind::qt_player_selection, - NetHackQtBind::qt_askname, - NetHackQtBind::qt_get_nh_event, - NetHackQtBind::qt_exit_nhwindows, - NetHackQtBind::qt_suspend_nhwindows, - NetHackQtBind::qt_resume_nhwindows, - NetHackQtBind::qt_create_nhwindow, - NetHackQtBind::qt_clear_nhwindow, - NetHackQtBind::qt_display_nhwindow, - NetHackQtBind::qt_destroy_nhwindow, - NetHackQtBind::qt_curs, - NetHackQtBind::qt_putstr, - genl_putmixed, - NetHackQtBind::qt_display_file, - NetHackQtBind::qt_start_menu, - NetHackQtBind::qt_add_menu, - NetHackQtBind::qt_end_menu, - NetHackQtBind::qt_select_menu, - genl_message_menu, /* no need for X-specific handling */ - NetHackQtBind::qt_update_inventory, - NetHackQtBind::qt_mark_synch, - NetHackQtBind::qt_wait_synch, -#ifdef CLIPPING - NetHackQtBind::qt_cliparound, -#endif -#ifdef POSITIONBAR - donull, -#endif - NetHackQtBind::qt_print_glyph, - //NetHackQtBind::qt_print_glyph_compose, - NetHackQtBind::qt_raw_print, - NetHackQtBind::qt_raw_print_bold, - NetHackQtBind::qt_nhgetch, - NetHackQtBind::qt_nh_poskey, - NetHackQtBind::qt_nhbell, - NetHackQtBind::qt_doprev_message, - NetHackQtBind::qt_yn_function, - NetHackQtBind::qt_getlin, - NetHackQtBind::qt_get_ext_cmd, - NetHackQtBind::qt_number_pad, - NetHackQtBind::qt_delay_output, -#ifdef CHANGE_COLOR /* only a Mac option currently */ - donull, - donull, -#endif - /* other defs that really should go away (they're tty specific) */ - NetHackQtBind::qt_start_screen, - NetHackQtBind::qt_end_screen, -#ifdef GRAPHIC_TOMBSTONE - NetHackQtBind::qt_outrip, -#else - genl_outrip, -#endif - genl_preference_update, - genl_getmsghistory, - genl_putmsghistory, - genl_status_init, - genl_status_finish, - genl_status_enablefield, - genl_status_update, - genl_can_suspend_yes, -}; - -extern "C" void play_usersound(const char* filename, int volume) -{ -#ifdef USER_SOUNDS -#ifndef QT_NO_SOUND - QSound::play(filename); -#endif -#endif -} - -#include "qt_win.moc" -#ifndef KDE -#include "qt_kde0.moc" -#endif -#if QT_VERSION >= 300 -#include "qttableview.moc" -#endif +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4win.h b/win/Qt/qt_win.h similarity index 56% rename from win/Qt4/qt4win.h rename to win/Qt/qt_win.h index 02e96cd31..8edb91974 100644 --- a/win/Qt4/qt4win.h +++ b/win/Qt/qt_win.h @@ -2,8 +2,9 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// Qt Binding for NetHack 3.4 +// Qt Binding for NetHack 5.0 // +// [original comment from Warwick] // Unfortunately, this doesn't use Qt as well as I would like, // primarily because NetHack is fundamentally a getkey-type // program rather than being event driven (hence the ugly key @@ -11,39 +12,43 @@ // major application of Qt. // -#ifndef qt4win_h -#define qt4win_h +#ifndef qt_win_h +#define qt_win_h -namespace nethack_qt4 { +namespace nethack_qt_ { + +void centerOnMain(QWidget *); /* in the namespace but not in any class */ class NetHackQtWindow { public: NetHackQtWindow(); virtual ~NetHackQtWindow(); - virtual QWidget* Widget() =0; + virtual QWidget* Widget() = 0; virtual void Clear(); virtual void Display(bool block); virtual bool Destroy(); - virtual void CursorTo(int x,int y); + virtual void CursorTo(int x, int y); virtual void PutStr(int attr, const QString& text); void PutStr(int attr, const char *text) { PutStr(attr, QString::fromUtf8(text).replace(QChar(0x200B), "")); } - virtual void StartMenu(); - virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const QString& str, bool presel); + virtual void StartMenu(bool using_WIN_INVEN = false); + virtual void AddMenu(int glyph, const ANY_P* identifier, + char ch, char gch, int attr, int clr, + const QString& str, unsigned itemflags); virtual void EndMenu(const QString& prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); - virtual void ClipAround(int x,int y); - virtual void PrintGlyph(int x,int y,int glyph); + virtual void ClipAround(int x, int y); + virtual void PrintGlyph(int x, int y, const glyph_info *glyphinfo, + const glyph_info *bkglyphinfo); virtual void UseRIP(int how, time_t when); int nhid; }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qt_xcmd.cpp b/win/Qt/qt_xcmd.cpp new file mode 100644 index 000000000..505949398 --- /dev/null +++ b/win/Qt/qt_xcmd.cpp @@ -0,0 +1,613 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_xcmd.cpp -- extended command widget +// +// TODO: +// Either disable [Layout] when prompt has a partial response, or +// preserve that partial response across widget tear-down/rebuild. +// Maybe make the number of grid columns user settable? Or a way to +// specify a different font (smaller might be necessary for some folks; +// the font set up in "Qt settings" or "Preferences" applies to the +// message and status windows but not to extended command choosing). +// + +// +// Widget appearance (excluding window title bar): +// +----------------------------------------------------+ +// | [Cancel] [Filter] [Layout] [Reset] | control buttons +// |# Extended commands | text entry & title +// +----------------------------------------------------+ +// | [cmmnd_1] [cmnd_14] ... [cmnd_92] [cmd_105] | boxed grid of... +// | [cmmnd_2] [cmnd_15] ... [cmnd_93] [cmd_106] | ...command buttons +// ... +// | [cmnd_13] [cmnd_26] ... [cmd_104] blank | +// +----------------------------------------------------+ +// +// Typed input gets appended to "#". When enough to be unambiguous has +// accumulated, the matching command is immediately chosen (except for +// the prefix special case mentioned for [Cancel]); +// Title is centered and describes which [sub]set of commands are shown. +// It shares the prompt line to conserve vertical space. +// [Cancel] is highlighted as the default and applies if is typed, +// with special handling when player has typed up to the end of one +// command which is a prefix of another; there, or is +// used to select the shorter while still providing opportunity to type +// more of the longer command; (there are several such cases: +// "#drop[type]", "#known[class]", "#takeoff[all]", "#version[short]"); +// button is left justified (prior to addition of the filter/layout/reset +// buttons, [Cancel] stretched all the way across the top of the widget); +// [Filter] toggles between normal and autocomplete when playing in normal +// or explore mode, cycles through "all", "normal", "autocomplete", and +// "wizard mode extra commands only" when playing in wizard mode; that's +// kind of clumsy but probably not important enough to implement a more +// sophisticated interface; +// [Layout] toggles between displaying the command buttons down columns +// (as shown above) versus across rows ([cmd_1][cmd_2]...[cmd_9], &c); +// [Reset] clears typed partial response, if any, and sets filtering back +// to "all commands" and/or toggles layout back to by-column if either +// of those differ from their defaults; +// [cmd_N] are buttons labelled with command names; clicking returns the +// index for the name. +// +// Changing filter or layout returns xcmdNoMatch to qt_get_ext_cmd() which +// then calls us again (current filter and layout are kept in qt_settings +// so persist, not just through return and call back but across games); +// much simpler than reorganizing the button grid's contents on the fly. +// Current grid size with SHELL and SUSPEND enabled is 13x9 for all +// commands, 13x7 for normal mode commands, and 7x4 (when by-column) or +// 4x7 (if by-row) for wizard mode commands. Column counts are hardcoded +// and row counts are adjusted to fit (the command list, not the screen). +// Maybe move prompt and title above control buttons? However, menus have +// their count entry feedback positioned between control buttons and the +// rest of the information--current layout matches that. +// The popup is displayed as full-fledged window but the window title bar +// is blank (at least on OSX). +// If clicking on [Filter] or [Layout] (or [Reset], but there isn't any +// particular reason to try to run it twice in a row) places the pointer +// inside any button, clicking again won't do anything unless the pointer +// is moved (again, at least on OSX); a single pixel probably suffices. +// Possibly because despite not moving it has effectively gone into a +// whole new window since the old one gets torn down and is replaced by +// a new one that uses revised filter or layout settings. +// + +extern "C" { +#include "hack.h" +#include "func_tab.h" +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_xcmd.h" +#include "qt_xcmd.moc" +#include "qt_key.h" // for keyValue() +#include "qt_bind.h" +#include "qt_set.h" +#include "qt_str.h" + +// temporary +extern int qt_compact_mode; +// end temporary + +namespace nethack_qt_ { + +/* 'wizard' is #undef'd above (now in qt_pre.h) because a Qt header uses + that token, so create our own based on knowledge of 'wizard's internals */ +#define WizardMode (::flags.debug) + +extern uchar keyValue(QKeyEvent *key_event); // from qt_menu.cpp + +// temporary +void centerOnMain(QWidget *); +// end temporary + +static /*inline*/ bool +interesting_command(unsigned indx, int cmds) +{ + bool skip_wizard = !WizardMode || cmds == normal_cmds; + + // entry 0 is a no-op; don't bother displaying it in the command grid + if (indx == 0 && !strcmp("#", extcmdlist[indx].ef_txt)) + return false; + // treat '?' as both normal mode and debug mode + if (!strcmp("?", extcmdlist[indx].ef_txt)) + return true; + // some commands might have been compiled-out; don't show them + if ((extcmdlist[indx].flags & (CMD_NOT_AVAILABLE|INTERNALCMD)) != 0) + return false; + // if picking from normal mode-only don't show wizard mode commands + // or if picking from wizard mode-only don't show normal commands + if ((skip_wizard && (extcmdlist[indx].flags & WIZMODECMD) != 0) + || (cmds == wizard_cmds && (extcmdlist[indx].flags & WIZMODECMD) == 0)) + return false; + // autocomplete subset is essentially the traditional set of extended + // commands; many can be invoked by Alt+char but not by ordinary char + // or Ctrl+char; [X11's extended command selection uses this subset] + if (cmds == autocomplete_cmds + && (extcmdlist[indx].flags & AUTOCOMPLETE) == 0) + return false; + // if we've gotten here, this command isn't filtered away, so show it + return true; +} + +NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(QWidget *parent) : + QDialog(parent), + prompt(new QLabel("#", this)), + cancel_btn(new QPushButton("Cancel", this)), + byRow(qt_settings->xcmd_by_row), + set(qt_settings->xcmd_set), + butoffset(0), + exactmatchindx(xcmdNoMatch) +{ + if (!WizardMode && set != normal_cmds) + set = autocomplete_cmds; // {all,wizard}_cmds are wizard mode only + + QVBoxLayout *xl = new QVBoxLayout(this); // overall xcmd layout + int butw = 50; // initial button width; will be increased if too small + // should probably use the qt_settings font size as a spacing hint; + // tiny font, tiny internal margins; small font, small margins; + // medium or bigger, default margins (9 or 11?) + int spacing = qt_compact_mode ? 3 : -1; // 0 would abut; -1 gives default + + // first, the popup's controls: a row of buttons along the top; + // the two padding widgets make the control buttons line up better + // with the grid of xcmd choice buttons (closer but not exactly) + QHBoxLayout *ctrls = new QHBoxLayout(); + ctrls->setSpacing(spacing); // only seems to affect horizontal, not vert. + ctrls->addWidget(new QLabel(" ")); // padding + // Cancel, created during constructor setup (accessed in other routines) + DefaultActionIsCancel(true); /* cancel_btn->setDefault(true); */ + cancel_btn->setMinimumSize(cancel_btn->sizeHint()); + butw = std::max(butw, cancel_btn->width()); + ctrls->addWidget(cancel_btn); + ctrls->addStretch(0); // Cancel will be left justified, others far right + // Filter: change the [sub]set of commands that get shown; + // presently only useful when running in wizard mode + QPushButton *filter_btn = new QPushButton("Filter", this); +#if 0 /* [later] normal vs autocomplete matters regardless of wizard mode */ + if (!WizardMode) { // nothing to filter if not in wizard mode + filter_btn->setEnabled(false); // gray the [Filter] button out +#if 0 /* This works but makes [Reset] seem to be redundant. */ + // graying out may not be adequate; conceal [Filter] so that + // players without access to wizard mode won't become concerned + // about something that seems to them to always be disabled + filter_btn->hide(); +#endif + } +#endif + filter_btn->setMinimumSize(filter_btn->sizeHint()); + butw = std::max(butw, filter_btn->width()); + ctrls->addWidget(filter_btn); + // Layout: switch from by-column grid to by-row grid or vice versa + QPushButton *layout_btn = new QPushButton("Layout", this); + layout_btn->setMinimumSize(layout_btn->sizeHint()); + butw = std::max(butw, layout_btn->width()); + ctrls->addWidget(layout_btn); + // Reset: switch filter back to all commands and layout back to by-column + QPushButton *reset__btn = new QPushButton("Reset", this); + reset__btn->setMinimumSize(reset__btn->sizeHint()); + butw = std::max(butw, reset__btn->width()); + ctrls->addWidget(reset__btn); + ctrls->addWidget(new QLabel(" ")); // padding + xl->addLayout(ctrls); + + // text entry takes place below the row of control buttons and above + // the grid of command buttons; show typed text in fixed-width font + prompt->setFont(qt_settings->normalFixedFont()); + + // grid title rather than overall popup title + const char *ctitle = ((set == all_cmds) // implies wizard mode + ? "All commands" + : (set == normal_cmds) + ? (WizardMode ? "Normal mode commands" + : "Available commands") + : (set == autocomplete_cmds) + ? "Traditional extended commands" + : (set == wizard_cmds) + ? "Debug mode commands" + : "(unknown)"); // won't happen + const QString &qtitle = QString(ctitle); + // rectangular grid to hold a button for each extended command name + QGroupBox *grid = new QGroupBox(); /* new QGroupBox(title, this); */ + // used to connect the buttons with their click handling routine + QButtonGroup *group = new QButtonGroup(this); + + // put grid title on same line as prompt (the padding simplifies centering) + QHBoxLayout *pl = new QHBoxLayout(); // prompt line + pl->addWidget(prompt); + QLabel *tt = new QLabel(qtitle); + tt->setAlignment(Qt::AlignHCenter); // center title horizontally + pl->addWidget(tt); + pl->addWidget(new QLabel(" ")); // padding to balance prompt + xl->addLayout(pl); + xl->addWidget(grid); + + // having the controls in the same button group as the extended command + // choices means that they use the same click callback [a holdover from + // when Cancel was the only one; using a separate group and separate + // click callback would eliminate the need for butoffset in Button()] + group->addButton(cancel_btn, butoffset), ++butoffset; // (,0), 1 + group->addButton(filter_btn, butoffset), ++butoffset; // (,1), 2 + group->addButton(layout_btn, butoffset), ++butoffset; // (,2), 3 + group->addButton(reset__btn, butoffset), ++butoffset; // (,3), 4 + + unsigned i, j, ncmds = 0; + QFontMetrics fm = fontMetrics(); + // count the number of commands in current [sub]set and find the size of + // the widest choice button; starting size is from widest control button + for (i = 0; extcmdlist[i].ef_txt; ++i) { + if (interesting_command(i, set)) { + ++ncmds; + butw = std::max(butw, 30 + fm.QFM_WIDTH(extcmdlist[i].ef_txt)); + } + } + // if any of the choice buttons were bigger than the control buttons, + // make the control buttons bigger to match + if (cancel_btn->width() < butw) + cancel_btn->setMinimumWidth(butw); + if (filter_btn->width() < butw) + filter_btn->setMinimumWidth(butw); + if (layout_btn->width() < butw) + layout_btn->setMinimumWidth(butw); + if (reset__btn->width() < butw) + reset__btn->setMinimumWidth(butw); + + QVBoxLayout *bl = new QVBoxLayout(grid); + QGridLayout *gl = new QGridLayout(); + // for qt_compact_mode, put buttons closer together + gl->setSpacing(spacing); + bl->addLayout(gl); + // could grow the buttons[] vector one element at a time but since we + // know the ultimate size, grow to that in one operation + buttons.resize((int) ncmds); + + /* 'ncols' could be calculated to fit (or enable a vertical scrollbar + when resulting 'nrows' is too big, if GroupBox supports that); + it used to be hardcoded 4, but once every command became accessible + as an extended command, that resulted in so many rows that some of + the grid was chopped off at the bottom of the screen and the buttons + in that portion were out of reach */ + unsigned ncols = (set == all_cmds) ? 9 + : (set == normal_cmds) ? 8 + : (set == autocomplete_cmds) ? (WizardMode ? 6 : 5) + : (set == wizard_cmds) ? (byRow ? 6 : 5) + : 1; // can't happen + unsigned nrows = (ncmds + ncols - 1) / ncols; + /* + * Grid layout: by-column is the default. Can be toggled by clicking + * on the [Layout] control button. + * + * by-row vs by-column + * a b c a e i + * d e f b f j + * g h i c g - + * j - - d h - + */ + for (i = j = 0; extcmdlist[i].ef_txt; ++i) { + if (interesting_command(i, set)) { + QString btn_lbl = extcmdlist[i].ef_txt; + if (btn_lbl == "wait") + btn_lbl += " (rest)"; + QString btn_tip = nh_qsprintf(" %s ", extcmdlist[i].ef_desc); + QPushButton *pb = new QPushButton(btn_lbl, grid); + pb->setMinimumSize(butw, pb->sizeHint().height()); + // force the button to have fixed width or it can move around a + // pixel or two (tiny but visibly noticeable) when enableButtons() + // hides whole columns [see stretch comment below] + pb->setMaximumSize(pb->minimumSize()); + // i+butoffset is value that will be passed to the click handler + group->addButton(pb, i + butoffset); + // gray out "repeat" because picking it would just repeat the "#" + // that caused us to be called rather than whatever came before; + // it can still be chosen by typing "rep" but appears grayed out + // while in the process so having it not behave usefully shouldn't + // come as much of a surprise + if (btn_lbl == "repeat") + pb->setEnabled(false); + // show command description if mouse hovers over this button + pb->setToolTip(btn_tip); // extcmdlist[i].ef_desc + /* + * by column: xcmd_by_row==false, the default + * 0..R-1 down first column, R..2*R-1 down second column, ... + * otherwise: by row + * 0..C-1 across first row, C..2*C-1 across second row, ... + */ + unsigned row = !byRow ? j % nrows : j / ncols; + unsigned col = !byRow ? j / nrows : j % ncols; + gl->addWidget(pb, row, col); + // these stretch settings prevent the grid from becoming very + // ugly when enableButtons() disables whole rows and/or columns + // as typed characters reduce the pool of possible matches + if (row == 0) + gl->setColumnStretch(col, 1); + if (col == 0) + gl->setRowStretch(row, 1); + + // buttons[] vector is used by enableButtons() + buttons[j] = pb; // buttons.append(pb); + ++j; + } + } + +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + connect(group, SIGNAL(idPressed(int)), this, SLOT(Button(int))); +#else + connect(group, SIGNAL(buttonPressed(int)), this, SLOT(Button(int))); +#endif + + bl->activate(); + xl->activate(); + resize(1,1); +} + +// Click handler for the ExtCmdRequestor widget +int NetHackQtExtCmdRequestor::Button(int butnum) +{ + // 0..3 are control buttons, 4..N+3 are choice buttons. + // Widget return value is -1 for cancel (via reject), xcmdNoMatch + // for filter, layout, reset (via accept if circumstances warrant), + // 1..N for command choices (choice 0 is '#' and it isn't shown as + // a candidate since picking it is not useful). + switch (butnum) { + case 0: + Cancel(); + /*NOTREACHED*/ + break; + case 1: + Filter(); + break; + case 2: + Layout(); + break; + case 3: + Reset(); + break; + default: + // 4..N-3 are the extended commands + done(butnum - butoffset + 1); + /*NOTREACHED*/ + break; + } + return 0; +} + +// Respond to a click on the [Cancel] button +void NetHackQtExtCmdRequestor::Cancel() +{ + reject(); + /*NOTREACHED*/ +} + +// Respond to a click on the [Filter] button +void NetHackQtExtCmdRequestor::Filter() +{ + do { + if (++set > std::max(std::max(all_cmds, normal_cmds), + std::max(autocomplete_cmds, wizard_cmds))) + set = std::min(std::min(all_cmds, normal_cmds), + std::min(autocomplete_cmds, wizard_cmds)); + if (WizardMode) + break; + } while (set != normal_cmds && set != autocomplete_cmds); + + if (set != qt_settings->xcmd_set) { + Retry(); + /*NOTREACHED*/ + } + return; +} + +// Respond to a click on the [Layout] button +void NetHackQtExtCmdRequestor::Layout() +{ + byRow = !byRow; + Retry(); + /*NOTREACHED*/ +} + +// Respond to a click on the [Reset] button +void NetHackQtExtCmdRequestor::Reset() +{ + // clear any typed text first (in case future changes are made to + // remember it across accept (retry); that would be intended for the + // [Layout] case rather than for [Reset]) + bool clearprompt = (prompt->text() != "#"); + if (clearprompt) + prompt->setText("#"); + + int teardown = 0; + if (set != (WizardMode ? all_cmds : normal_cmds)) + set = all_cmds, ++teardown; + if (byRow) + byRow = false, ++teardown; + if (teardown) { + Retry(); + /*NOTREACHED*/ + } + + if (clearprompt) { // was a subset, now need to show full set + DefaultActionIsCancel(true); // in case keyPressEvent cleared it + enableButtons(); // redraws the grid after discarding typed text above + } +} + +// Return to ExtCmdRequestor::get()'s caller in order to be called back +void NetHackQtExtCmdRequestor::Retry() +{ + // remember the current settings; they'll persist until changed again + qt_settings->updateXcmd(byRow, set); + + // return to qt_get_ext_cmd() and have it run ExtCmdRequestor again; + // current selection grid will be torn down, then new one created; + setResult(xcmdNoMatch); + accept(); + /*NOTREACHED*/ +} + +#define Ctrl(c) (0x1f & (c)) /* ASCII */ +// Note: we don't necessarily have access to a terminal to query +// it for user's preferred kill character, so use hardcoded ^U. +// Player who prefers something else can cope by using ESC instead. +#define KILL_CHAR Ctrl('u') + +// used by keyPressEvent() and enableButtons() +static const QString &rest = "rest"; // informal synonym for "wait" + +// Receive the next character of typed input +void NetHackQtExtCmdRequestor::keyPressEvent(QKeyEvent *event) +{ + /* + * This will select a command outright--as soon as enough chars + * to not be ambiguous are entered--but also narrows down visible + * choices [via enableButtons()] in the grid of clickable command + * buttons as the text-so-far makes many become impossible to match. + * Use of backspace/delete or ESC/kill restores suppressed choices + * to the grid as they become matchable again. + */ + + unsigned saveexactmatchindx = exactmatchindx; + // if previous KeyPressEvent cleared default, restore it now + DefaultActionIsCancel(true); + QString promptstr = prompt->text(); + uchar uc = keyValue(event); + + if (!uc) { + // shift or control or meta, another character should be coming + QWidget::keyPressEvent(event); + } else if (uc == '\033' || uc == KILL_CHAR) { + // when partial response is present kills that text + // but keeps prompting; when response is empty cancels. + // Kill gets rid of pending text, if any, and always re-prompts. + if (uc == '\033' && promptstr == "#") + reject(); // cancel() if ESC used when string is empty + prompt->setText("#"); // reset to empty ('#' is always present) + enableButtons(); + } else if (uc == '\b' || uc == '\177') { + if (promptstr != "#") + prompt->setText(promptstr.left(promptstr.size() - 1)); + enableButtons(); + } else if ((uc < ' ' && !(uc == '\n' || uc == '\r')) + || uc > std::max('z', 'Z')) { + reject(); // done() + } else { + /* + * or is necessary if one command is a + * leading substring of another and superfluous otherwise. + * (When a command is not a prefix of another, it will have + * been selected before reaching its last letter.) + * + * If we got an exact match with the last key, we're expecting + * a or to explicitly choose it now but might + * get next letter of the longer command (or get a backspace). + * + * If we get an exact match this time, then stop showing + * [Cancel] as the default action for . + * (That's a visual cue for the player, not a requirement to + * prevent from triggering the default action.) + * If it's not the default action upon the next key press, + * we'll change that back (done above). + * + * TODO? + * Implement support: if promptstr matches multiple + * commands but they all have the next one or more letters in + * common, allow to add the common letters to promptstr. + */ + bool checkexact = (uc == '\n' || uc == '\r' || uc == ' '); + if (!checkexact) { + // force lower case instead of rejecting upper case + if (isupper(uc)) + uc = tolower(uc); + promptstr += QChar(uc); // add new char to typed text + } + QString typedstr = promptstr.mid(1); // skip the '#' + if (typedstr == rest) + typedstr = "wait"; + std::size_t len = typedstr.size(); + unsigned matches = 0; + unsigned matchindx = 0; + for (unsigned i = 0; extcmdlist[i].ef_txt; ++i) { + if (!interesting_command(i, set)) + continue; + const QString &cmdtxt = QString(extcmdlist[i].ef_txt); + if (cmdtxt.startsWith(typedstr)) { + bool is_exact = (cmdtxt == typedstr); + if (checkexact) { + if (is_exact) { + matchindx = i; + matches = 1; + break; + } + } else { + if (is_exact) + DefaultActionIsCancel(false, i); // clear default + if (++matches >= 2) + break; + matchindx = i; + } + } + } + if (matches == 1) { + done(matchindx + 1); + } else if (checkexact) { + // or without a pending exact match; cancel + reject(); + } else if (matches >= 2 + || promptstr.mid(1, len) == rest.left(len)) { + // update the text-so-far + prompt->setText(promptstr); + } else if (saveexactmatchindx != xcmdNoMatch) { + // had a pending exact match but typed something other than + // which didn't yield another match; prompt string + // hasn't been updated so still have a pending exact match + DefaultActionIsCancel(false, saveexactmatchindx); + } + enableButtons(); + } +} + +// Actual widget execution, used after calling NetHackQtExtCmdRequestor(). +int NetHackQtExtCmdRequestor::get() +{ + resize(1,1); // pack + centerOnMain(this); + // Add any keys presently buffered to the prompt + setResult(xcmdNone); + while (NetHackQtBind::qt_kbhit() && result() == xcmdNone) { + int ch = NetHackQtBind::qt_nhgetch(); + QKeyEvent event(QEvent::KeyPress, 0, Qt::NoModifier, QChar(ch)); + keyPressEvent(&event); + } + if (result() == xcmdNone) + exec(); + + int ret = result() - 1; + return ret; +} + +// Enable only buttons that match the current prompt string +void NetHackQtExtCmdRequestor::enableButtons() +{ + QString typedstr = prompt->text().mid(1); // skip the '#' + std::size_t len = typedstr.size(); + + // This used to look really bad when whole rows became empty: the + // grid shrank and the one line prompt area expanded to fill the + // vacated vertical space. Hiding whole columns looked bad too, + // remaining buttons were widened to take the space. Now the grid is + // forced to have fixed layout (via stretch settings in constructor). + for (auto b = buttons.begin(); b != buttons.end(); ++b) { + const QString &buttext = (*b)->text(); + bool showit = (buttext.left(len) == typedstr + || (buttext.contains("(rest)") + && typedstr == rest.left(len))); + (*b)->setVisible(showit); + } +} + +} // namespace nethack_qt_ diff --git a/win/Qt/qt_xcmd.h b/win/Qt/qt_xcmd.h new file mode 100644 index 000000000..4820d2d4d --- /dev/null +++ b/win/Qt/qt_xcmd.h @@ -0,0 +1,64 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_xcmd.h -- extended command widget + +#ifndef QT4XCMD_H +#define QT4XCMD_H + +namespace nethack_qt_ { + +// [Filter] setting; the X11 interface uses the autocomplete list +enum xcmdSets { + all_cmds = 0, // everything in extcmdlist[] + normal_cmds = 1, // all non-wizard mode commands + autocomplete_cmds = 2, // mostly commands which need Alt+char + wizard_cmds = 3 // commands only useable in wizard mode +}; +enum xcmdMisc { xcmdNone = -10, xcmdNoMatch = 9999 }; + +class NetHackQtExtCmdRequestor : public QDialog { + Q_OBJECT + +protected: + virtual void keyPressEvent(QKeyEvent *event); + +public: + NetHackQtExtCmdRequestor(QWidget *parent); + int get(); + +private: + QLabel *prompt; + QPushButton *cancel_btn; + QVector buttons; + bool byRow; // local copy of qt_settings->xcmd_by_row; + int set; // local copy of qt_settings->xcmd_set; + int butoffset; // number of control buttons (cancel, filter, &c) + unsigned exactmatchindx; + + void enableButtons(); + void Cancel(); // not selecting a command after all + void Filter(); // choose command set (all, normal mode, wizard mode) + void Layout(); // by-column vs by-row for button grid + void Reset(); // go back to default filter and layout + + void Retry(); // returns to caller in order to be called back... + // ...and restart with revised settings + + inline void DefaultActionIsCancel(bool make_it_so, + unsigned matchindx = xcmdNoMatch) + { + if (!make_it_so ^ !cancel_btn->isDefault()) { + cancel_btn->setDefault(make_it_so); + exactmatchindx = matchindx; + } + } + +private slots: + int Button(int); // click handler +}; + +} // namespace nethack_qt_ + +#endif diff --git a/win/gnome/gn_xpms.h b/win/Qt/qt_xpms.h similarity index 71% rename from win/gnome/gn_xpms.h rename to win/Qt/qt_xpms.h index 90bb7b3b1..7ea343590 100644 --- a/win/gnome/gn_xpms.h +++ b/win/Qt/qt_xpms.h @@ -1,18 +1,66 @@ -/* NetHack 3.6 gn_xpms.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ -/* These XPMs are the artwork of Warwick Allison - * . They have been borrowed from - * the most excellent NetHackQt, until such time as - * we can come up with something better. - * - * More information about NetHackQt can be had from: - * http://www.troll.no/~warwick/nethack/ - */ +// qt_xpms.h - static xpm arrays for use in status display +// +// In alphabetical order by array name. Probably not the best ordering... /* clang-format off */ + +// blank icon for use as placeholder /* XPM */ -static char *blind_xpm[] = { +static const char *blank_xpm[] = { +/* width height ncolors chars_per_pixel */ +"40 40 5 1", +/* colors */ +" c #000000", +". c None", +/* not used here */ +"X c #909090", +"o c #606060", +"O c #303030", +/* pixels */ +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................" +}; + +// Characteristics, Alignment, and Conditions +static const char *blind_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 5 1", /* colors */ @@ -64,7 +112,7 @@ static char *blind_xpm[] = { "........................................" }; /* XPM */ -static char *cha_xpm[] = { +static const char *cha_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 14 1", /* colors */ @@ -125,7 +173,7 @@ static char *cha_xpm[] = { "++++++++++++++++++++++++++++++++++++++++" }; /* XPM */ -static char *chaotic_xpm[] = { +static const char *chaotic_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 9 1", /* colors */ @@ -181,7 +229,7 @@ static char *chaotic_xpm[] = { "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }; /* XPM */ -static char *cns_xpm[] = { +static const char *cns_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 19 1", /* colors */ @@ -247,7 +295,7 @@ static char *cns_xpm[] = { "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" }; /* XPM */ -static char *confused_xpm[] = { +static const char *confused_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ @@ -265,6 +313,49 @@ static char *confused_xpm[] = { "* c #303030", "= c #6C91B6", /* pixels */ +#if 1 +/* mirror image of original; confused brain is facing the other way */ +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", +"OOOOOOO+.OO+O+OO.O+.=OO+.=.OOOOOOOOOOOOO", +"OOOOOO+O=++==+O=+=====O=====++OOOOOOOOOO", +"OOOOO+=O+==OO===++++=.=====.=+OOOOOOOOOO", +"OOOO======OoO&+===o==o=+.===+=OOOOOOOOOO", +"O.O.=+==+Oo&o==oO&&&&o=+OO====+O+OOOOOOO", +"O=+=O==Oooo&=ooo&o&oOooo=o&&+==O+=+.+OOO", +"O==++==+o&==o=oo&&o&=&oo=oo===O++OOOOOOO", +"OO=======oo&&o&oo&o&OO&o====O=.o=OOOOOOO", +"OOOO=====O&o=oOOoooo=Ooo=O=O=+===oOOOOOO", +"OOOO+===O=o=O====oo=O=======+==+OOOOOOOO", +"OOOOO======O========O====+=X=#=.OOOOOOOO", +"OOOO+==OO==========O====%#=.++oX#.OOOOOO", +"OOOO+==+=+=O====+====X==.=#.+#+#oX+OOOOO", +"OOOOO.OO+o===##Xo====.X=#.##===O+.+.OOOO", +"OOOO+=oOO=...+#O#X#==+#.o##O#O####+#OOOO", +"OOOOo=OO+==+X+#.X#+#.O#.#++++X+#+o#++OOO", +"OOOOOOO..+##+#XX+..#++#++X##.+X..+.+#OOO", +"OOOOOOO#+#+..X#+#+X+#++.+#++#+O....##OOO", +"OOOOOO$X.++#.##++.#XX#X#X+O#+#.+.+#++OOO", +"OOOOO**+##X+X+###X+##+++.++#+++.+#+#OOOO", +"OOOO@ *#+#+X#+.++..+.###o##.+#OO#..#OOOO", +"OOOO$ *#.+###++##+###.+++.O#+#+O#.#+OOOO", +"OOOO* ###+#.##..+#++##X..o#+#+#+XXOOOOO", +"OOOO %%XX%####+..+#.+#+#+#+X#.#XOOOOOO", +"OOOO* %.=++X.+#+#+#++.#+#+#.X%%.OOOOOOO", +"OOOO$ %#%%%%XX+.####O.+#+##* *.OOOOOOOO", +"OOOO$ X#+++.=XXX+++#.+.X% .OOOOOOOOOO", +"OOOO$ *X%####.=%X#..X%% *.OOOOOOOOOOO", +"OOOOO *=###%X#.=%%%XX* $.OOOOOOOOOOOOO", +"OOOOO@ *=#.+.#%%=%%%+OOOOOOOOOOOOOOOOO", +"OOOOOO *%X##X==%%%=oOOOOOOOOOOOOOOOOO", +"OOOOOO@ *%=X%%%%X+OOOOOOOOOOOOOOOOOO", +"OOOOOOO@* X%%%%XOOOOOOOOOOOOOOOOOOO", +"OOOOOOOOO$$* *X%%%=OOOOOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOO. =%%X+OOOOOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOOO %%%XOOOOOOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOOO$ *%%=OOOOOOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOOO$ %%%=OOOOOOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOOO$ %%%+OOOOOOOOOOOOOOOOOOOO" +#else "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO.=.+OO=.+O.OO+O+OO.+OOOOOO", "OOOOOOOOOOO++=====O=====+=O+==++=O+OOOOO", @@ -305,9 +396,59 @@ static char *confused_xpm[] = { "OOOOOOOOOOOOOOOOOOOOO=%%* $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO=%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO+%%% $OOOOOOOOOOOOO" +#endif }; /* XPM */ -static char *dex_xpm[] = { +static const char *deaf_xpm[] = { // placeholder for Deaf condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #dfdf40", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooXXXXooooooooooooooooooooooooooooX", +"XooooooXoooXoooooooooooooooooooooooooooX", +"XooooooXoooXoooooooooooooooooooooooooooX", +"XooooooXoooXoooooooooooooooooooooooooooX", +"XooooooXoooXoooooooooooooooooooooooooooX", +"XooooooXoooXooXXXXXooooooooooooooooooooX", +"XooooooXXXXoooXooooooooooooooooooooooooX", +"XoooooooooooooXooooooooooooooooooooooooX", +"XoooooooooooooXXXXoooooooooooooooooooooX", +"XoooooooooooooXooooooooooooooooooooooooX", +"XoooooooooooooXooooooooXoooooooooooooooX", +"XoooooooooooooXXXXXoooXoXooooooooooooooX", +"XooooooooooooooooooooXoooXoooooooooooooX", +"XooooooooooooooooooooXoooXoooooooooooooX", +"XooooooooooooooooooooXXXXXoooooooooooooX", +"XooooooooooooooooooooXoooXooXXXXXooooooX", +"XooooooooooooooooooooXoooXooXooooooooooX", +"XoooooooooooooooooooooooooooXooooooooooX", +"XoooooooooooooooooooooooooooXXXXoooooooX", +"XoooooooooooooooooooooooooooXooooooooooX", +"XoooooooooooooooooooooooooooXooooooooooX", +"XoooooooooooooooooooooooooooXooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ +static const char *dex_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 19 1", /* colors */ @@ -373,7 +514,7 @@ static char *dex_xpm[] = { "#################O######################" }; /* XPM */ -static char *ext_enc_xpm[] = { +static const char *ext_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ @@ -433,7 +574,105 @@ static char *ext_enc_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ -static char *hallu_xpm[] = { +static const char *fly_xpm[] = { // placeholder for Flying condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #7fefef", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooXoooXoooooooooooX", +"XooooooooooooooooooooooXoooXoooooooooooX", +"XoooooooooooooooooXoooooXoXooooooooooooX", +"XoooooooooooooooooXoooooXoXooooooooooooX", +"XooooooooooXXXXXooXooooooXoooooooooooooX", +"XooooooooooXooooooXooooooXoooooooooooooX", +"XooooooooooXooooooXooooooXoooooooooooooX", +"XooooooooooXXXXoooXooooooooooooooooooooX", +"XooooooooooXooooooXXXXoooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ +static const char *lev_xpm[] = { // placeholder for Levitating condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #df1010", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooXoooooXoooooooooX", +"XooooooooooooooooooooooXoooooXoooooooooX", +"XoooooooooooooooXXXXXoooXoooXooooooooooX", +"XoooooooooooooooXoooooooXoooXooooooooooX", +"XoooooooooXoooooXooooooooXoXoooooooooooX", +"XoooooooooXoooooXXXXoooooXoXoooooooooooX", +"XoooooooooXoooooXoooooooooXooooooooooooX", +"XoooooooooXoooooXooooooooooooooooooooooX", +"XoooooooooXoooooXXXXXooooooooooooooooooX", +"XoooooooooXooooooooooooooooooooooooooooX", +"XoooooooooXXXXoooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ +static const char *hallu_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 30 1", /* colors */ @@ -510,7 +749,7 @@ static char *hallu_xpm[] = { "$$$$$$$$$$$$$$$$$$$$$%$$+$$$$$$$$$$$$$$$" }; /* XPM */ -static char *hungry_xpm[] = { +static const char *hungry_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 15 1", /* colors */ @@ -572,7 +811,7 @@ static char *hungry_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ -static char *hvy_enc_xpm[] = { +static const char *hvy_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ @@ -632,7 +871,7 @@ static char *hvy_enc_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ -static char *int_xpm[] = { +static const char *int_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", /* colors */ @@ -691,7 +930,7 @@ static char *int_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOoOOOOOOOOOOOOOOOO" }; /* XPM */ -static char *lawful_xpm[] = { +static const char *lawful_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 10 1", /* colors */ @@ -748,7 +987,7 @@ static char *lawful_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ -static char *mod_enc_xpm[] = { +static const char *mod_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ @@ -808,7 +1047,7 @@ static char *mod_enc_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ -static char *neutral_xpm[] = { +static const char *neutral_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 14 1", /* colors */ @@ -869,7 +1108,7 @@ static char *neutral_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ -static char *ovr_enc_xpm[] = { +static const char *ovr_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ @@ -929,7 +1168,56 @@ static char *ovr_enc_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ -static char *satiated_xpm[] = { +static const char *ride_xpm[] = { // placeholder for Riding condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #df7f00", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XoooooooXXXXoooXXXooXXXXoooXXXXXoooooooX", +"XoooooooXoooXoooXoooXoooXooXoooooooooooX", +"XoooooooXoooXoooXoooXoooXooXoooooooooooX", +"XoooooooXXXXooooXoooXoooXooXXXXooooooooX", +"XoooooooXoXoooooXoooXoooXooXoooooooooooX", +"XoooooooXooXooooXoooXoooXooXoooooooooooX", +"XoooooooXoooXooXXXooXXXXoooXXXXXoooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ +static const char *satiated_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", /* colors */ @@ -999,7 +1287,7 @@ static char *satiated_xpm[] = { "########################################" }; /* XPM */ -static char *sick_fp_xpm[] = { +static const char *sick_fp_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 30 1", /* colors */ @@ -1076,7 +1364,7 @@ static char *sick_fp_xpm[] = { "*****************=*=********************" }; /* XPM */ -static char *sick_il_xpm[] = { +static const char *sick_il_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", /* colors */ @@ -1146,7 +1434,56 @@ static char *sick_il_xpm[] = { "#################$#$####################" }; /* XPM */ -static char *slt_enc_xpm[] = { +static const char *slime_xpm[] = { // placeholder for Slimed condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #40df40", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooXXXoooooooooooooooooooooooooooooooX", +"XoooXooooooooooooooooooooooooooooooooooX", +"XoooXooooooooooooooooooooooooooooooooooX", +"XooooXXXoooooooooooooooooooooooooooooooX", +"XoooooooXooooooooooooooooooooooooooooooX", +"XoooooooXooXoooooooooooooooooooooooooooX", +"XooooXXXoooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXooooooXXXooooooooooooooooooX", +"XooooooooooXoooooooXoooooooooooooooooooX", +"XooooooooooXXXXXoooXoooooooooooooooooooX", +"XooooooooooooooooooXoooooooooooooooooooX", +"XooooooooooooooooooXoooooooooooooooooooX", +"XooooooooooooooooooXoooXoooooXoooooooooX", +"XoooooooooooooooooXXXooXXoooXXoooooooooX", +"XooooooooooooooooooooooXXXoXXXoooooooooX", +"XooooooooooooooooooooooXoXXXoXoooooooooX", +"XooooooooooooooooooooooXooXooXoooooooooX", +"XooooooooooooooooooooooXoooooXooXXXXXooX", +"XooooooooooooooooooooooXoooooXooXooooooX", +"XoooooooooooooooooooooooooooooooXooooooX", +"XoooooooooooooooooooooooooooooooXXXXoooX", +"XoooooooooooooooooooooooooooooooXooooooX", +"XoooooooooooooooooooooooooooooooXooooooX", +"XoooooooooooooooooooooooooooooooXXXXXooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ +static const char *slt_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ @@ -1206,7 +1543,56 @@ static char *slt_enc_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ -static char *str_xpm[] = { +static const char *stone_xpm[] = { // placeholder for Stoned condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #6c91b6", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooXXXoooooooooooooooooooooooooooooooX", +"XoooXooooooooooooooooooooooooooooooooooX", +"XoooXooooooooooooooooooooooooooooooooooX", +"XooooXXXoooooooooooooooooooooooooooooooX", +"XoooooooXooooooooooooooooooooooooooooooX", +"XoooooooXooXXXXXoooooooooooooooooooooooX", +"XooooXXXoooooXoooooooooooooooooooooooooX", +"XooooooooooooXoooooooooooooooooooooooooX", +"XooooooooooooXoooooooooooooooooooooooooX", +"XooooooooooooXooooXXXooooooooooooooooooX", +"XooooooooooooXoooXoooXoooooooooooooooooX", +"XooooooooooooXoooXoooXoooooooooooooooooX", +"XooooooooooooooooXoooXoooooooooooooooooX", +"XooooooooooooooooXoooXoooooooooooooooooX", +"XooooooooooooooooXoooXooXoooXooooooooooX", +"XoooooooooooooooooXXXoooXXooXooooooooooX", +"XoooooooooooooooooooooooXXooXooooooooooX", +"XoooooooooooooooooooooooXoXoXooooooooooX", +"XoooooooooooooooooooooooXooXXooooooooooX", +"XoooooooooooooooooooooooXooXXooXXXXXoooX", +"XoooooooooooooooooooooooXoooXooXoooooooX", +"XooooooooooooooooooooooooooooooXoooooooX", +"XooooooooooooooooooooooooooooooXXXXooooX", +"XooooooooooooooooooooooooooooooXoooooooX", +"XooooooooooooooooooooooooooooooXoooooooX", +"XooooooooooooooooooooooooooooooXXXXXoooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ +static const char *str_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 17 1", /* colors */ @@ -1270,7 +1656,56 @@ static char *str_xpm[] = { "++++++++++++++++++++++++++++++++++++++++" }; /* XPM */ -static char *stunned_xpm[] = { +static const char *strngl_xpm[] = { // placeholder for Strangled condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #bf40ff", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooXXXoooooooooooooooooooooooooooooooooX", +"XoXooooooooooooooooooooooooooooooooooooX", +"XoXooooooooooooooooooooooooooooooooooooX", +"XoXXXXoooooooooooooooooooooooooooooooooX", +"XoooooXooooooooooooooooooooooooooooooooX", +"XoooooXooXXXXXoooooooooooooooooooooooooX", +"XooXXXoooooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXooXXXXoooooooooooooooooooooX", +"XooooooooooXooXoooXooooooooooooooooooooX", +"XoooooooooooooXoooXooooooooooooooooooooX", +"XoooooooooooooXXXXoooooooooooooooooooooX", +"XoooooooooooooXoXooooooooooooooooooooooX", +"XoooooooooooooXooXoooXoooXoooooooooooooX", +"XoooooooooooooXoooXooXXooXoooooooooooooX", +"XooooooooooooooooooooXXooXoooooooooooooX", +"XooooooooooooooooooooXoXoXoooooooooooooX", +"XooooooooooooooooooooXooXXoooooooooooooX", +"XooooooooooooooooooooXooXXoooXXXoooooooX", +"XooooooooooooooooooooXoooXooXooooooooooX", +"XoooooooooooooooooooooooooooXooooooooooX", +"XoooooooooooooooooooooooooooXoXXXooooooX", +"XoooooooooooooooooooooooooooXoooXooooooX", +"XoooooooooooooooooooooooooooXoooXooXoooX", +"XooooooooooooooooooooooooooooXXXoooXoooX", +"XooooooooooooooooooooooooooooooooooXoooX", +"XooooooooooooooooooooooooooooooooooXoooX", +"XooooooooooooooooooooooooooooooooooXoooX", +"XooooooooooooooooooooooooooooooooooXoooX", +"XooooooooooooooooooooooooooooooooooXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ +static const char *stunned_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", /* colors */ @@ -1329,7 +1764,7 @@ static char *stunned_xpm[] = { "OOOOOOOOOOOOOOOOOOOOO.X%& $OOOOOOOOOOOOO" }; /* XPM */ -static char *wis_xpm[] = { +static const char *wis_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ @@ -1359,12 +1794,6 @@ static char *wis_xpm[] = { "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooo+#& &#oooooooooooooooooooo", "oooooooooooo+& #oooooooooooooooooo", "ooooooooooo+ &====&& &ooooooooooooooooo", @@ -1386,60 +1815,6 @@ static char *wis_xpm[] = { "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo" -}; -/* XPM */ -static char *nothing_xpm[] = { -/* width height ncolors chars_per_pixel */ -"40 40 13 1", -/* colors */ -" c #000000", -". c #949E9E", -"X c #5C7A7A", -"o c None", -"O c #B0B0B0", -"+ c #909090", -"@ c #788C8C", -"# c #606060", -"$ c #406868", -"% c #FFFFFF", -"& c #303030", -"* c #6C91B6", -"= c #0000FF", -/* pixels */ -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", @@ -1448,4 +1823,5 @@ static char *nothing_xpm[] = { "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo" }; + /* clang-format on */ diff --git a/win/Qt/qt_yndlg.cpp b/win/Qt/qt_yndlg.cpp new file mode 100644 index 000000000..57e2f212f --- /dev/null +++ b/win/Qt/qt_yndlg.cpp @@ -0,0 +1,429 @@ +// Copyright (c) Warwick Allison, 1999. +// Qt4 conversion copyright (c) Ray Chason, 2012-2014. +// NetHack may be freely redistributed. See license for details. + +// qt_yndlg.cpp -- yes/no dialog + +extern "C" { +#include "hack.h" +} + +#include "qt_pre.h" +#include +#if QT_VERSION >= 0x050000 +#include +#endif +#include "qt_post.h" +#include "qt_yndlg.h" +#include "qt_yndlg.moc" +#include "qt_key.h" // for keyValue() +#include "qt_str.h" + +// temporary +extern int qt_compact_mode; +// end temporary + +namespace nethack_qt_ { + +static const char lrq[] = "lr\033LRq"; +char altchoices[BUFSZ + 12]; + +// temporary +void centerOnMain(QWidget *); +// end temporary + +NetHackQtYnDialog::NetHackQtYnDialog(QWidget *parent, const QString &q, + const char *ch, char df) : + QDialog(parent), + question(q), choices(ch), def(df), + keypress('\033'), + allow_count(false), + le((QLineEdit *) NULL), + y_btn((QPushButton *) NULL) +{ + setWindowTitle("NetHack: Question"); + + // plain prompt doesn't show any room for an answer (answer won't be + // echoed but the fact that a prompt is pending and accepts typed + // input as an alternative to mouse click seems clearer when there + // is some space available to accept it) + if (!question.endsWith(" ") && !question.endsWith("_")) + question += " _"; // an underlined space would be better + + if (choices) { + // special handling for wearing rings; prompt asks "right or left?" + // but side-by-side buttons look better with [left][right] instead + // (assumes that we're using left to right layout) + if (!strcmp(choices, "rl")) { + choices = lrq; + if (!def) + def = 'r'; + + // if count is allowed, explicitly add the digits as valid + } else if (!strncmp(choices, "yn#", (size_t) 3)) { + ::yn_number = 0L; + allow_count = true; + + if (!strchr(choices, '9')) { + copynchars(altchoices, choices, BUFSZ - 1); + // duplicate # is intentional; explicitly separates \... and 0 + choices = strcat(altchoices, "\033#0123456789"); + } + } + } + alt_answer[0] = alt_result[0] = '\0'; +} + +char NetHackQtYnDialog::Exec() +{ + QString ch(QString::fromLatin1(choices)); +// int ch_per_line=6; + QString qlabel; + QString enable; + if ( qt_compact_mode && !choices ) { + ch = ""; + // expand choices from prompt + // ##### why isn't choices set properly??? + int c = question.indexOf(QChar('[')); + qlabel = QString(question).left(c); + if ( c >= 0 ) { + c++; + if ( question[c] == '-' ) + ch.append(question[c++]); + unsigned from=0; + while (c < question.size() + && question[c] != ']' && question[c] != ' ') { + if ( question[c] == '-' ) { + from = question[c - 1].cell(); + } else if ( from != 0 ) { + for (unsigned f=from+1; QChar(f)<=question[c]; f++) + ch.append(QChar(f)); + from = 0; + } else { + ch.append(question[c]); + from = 0; + } + c++; + } + if ( question[c] == ' ' ) { + while ( c < question.size() && question[c] != ']' ) { + if ( question[c] == '*' || question[c] == '?' ) + ch.append(question[c]); + c++; + } + } + } + if ( question.indexOf("what direction") >= 0 ) { + // We replace this regardless, since sometimes you get choices. + const char* d = gc.Cmd.dirchars; + enable=ch; + ch=""; + ch.append(d[1]); + ch.append(d[2]); + ch.append(d[3]); + ch.append(d[0]); + ch.append('.'); + ch.append(d[4]); + ch.append(d[7]); + ch.append(d[6]); + ch.append(d[5]); + ch.append(d[8]); + ch.append(d[9]); +// ch_per_line = 3; + def = ' '; + } else { + // Hmm... they'll have to use a virtual keyboard + } + } else { + ch = QString::fromLatin1(choices); + qlabel = question.replace(QChar(0x200B), QString("")); + } + if (!ch.isNull()) { + QVBoxLayout *vb = new QVBoxLayout; + bool bigq = (qlabel.length() > (qt_compact_mode ? 40 : 60)); + if (bigq) { + QLabel *q = new QLabel(qlabel, this); + q->setAlignment(Qt::AlignLeft); + q->setWordWrap(true); + q->setMargin(4); + vb->addWidget(q); + } + QGroupBox *group = new QGroupBox(bigq ? QString() : qlabel, this); + vb->addWidget(group); + QHBoxLayout *groupbox = new QHBoxLayout(); + group->setLayout(groupbox); + QButtonGroup *bgroup = new QButtonGroup(group); + + int nchoices=ch.length(); + // note: is_ynaq covers nyaq too because the choices string is + // "ynaq" for both; only the default differs; likewise for nyNaq + bool is_ynaq = (ch == QString("ynaq") // [Yes ][ No ][All ][Stop] + || ch == QString("yn#aq") + || ch == altchoices), // alternate "yn#aq" + is_ynq = (ch == QString("ynq")), // [ Yes ][ No ][Cancel] + is_yn = (ch == QString("yn")), // [Yes ][ No ] + is_lr = (ch == QString(lrq)); // [ Left ][Right ] + +#if 0 + const int margin=8; + const int gutter=8; + const int extra=fontMetrics().height(); // Extra for group + int x=margin, y=extra+margin; +#endif + int butheight = fontMetrics().height() * 2 + 5, + butwidth = (butheight - 5) * ((is_ynq || is_lr) ? 3 + : (is_ynaq || is_yn) ? 2 : 1) + 5; + if (butwidth == butheight) { // square, enough room for C or ^C + // some characters will be labelled by name rather than by + // keystroke so will need wider buttons + for (int i = 0; i < nchoices; ++i) { + if (ch[i] == '\033') + break; // ESC and anything after are hidden + if (ch[i] == ' ' || ch[i] == '\n' || ch[i] == '\r') { + butwidth = (butheight - 5) * 2 + 5; + break; + } + } + } + + QPushButton *button; + for (int i = 0; i < nchoices; ++i) { + bool making_y = false; + if (ch[i] == '\033') + break; // ESC and anything after are hidden + if (ch[i] == '#' && allow_count) + continue; // don't show a button for '#'; has Count box instead + QString button_name = QString(visctrl((char) ch[i].cell())); + if (is_yn || is_ynq || is_ynaq || is_lr) { + // FIXME: a better way to recognize which labels should + // use alternate text is needed + switch (ch[i].cell()) { + case 'y': + button_name = "Yes"; + making_y = true; + break; + case 'n': + button_name = "No"; + break; + case 'a': + // the display of vanquished monsters uses "ynaq" for + // convenience, where 'a' requests a sort-by menu; + // show "sort" instead of "all" and allow player to + // type either 'a' or 's' when not clicking on button + if (question.contains(QString("vanquished?"))) + button_name = "Sort", AltChoice('s', 'a'); + else + button_name = "All"; + break; + case 'q': + // most 'q' replies are actually for "cancel" but + // for "ynaq" (where "all" is a choice) it's "stop" + // and for end of game disclosure it really is "quit" + if (question.left(10) == QString("Dump core?") + || (::program_state.gameover + && question.left(11) == QString("Do you want"))) + button_name = "Quit"; + else if (is_ynaq) + button_name = "Stop", AltChoice('s', 'q'); + else + button_name = "Cancel", AltChoice('c', 'q'); + break; + case 'l': + button_name = "Left"; + break; + case 'r': + button_name = "Right"; + break; + } + } else { + // special characters usually aren't listed among choices + // but if they are, label the buttons for them with sensible + // names; we want to avoid "^J" and "^M" for \n and \r; + // and are equivalent to each other but + // labelling \n as newline or line-feed seems confusing; + switch (ch[i].cell()) { + case ' ': + button_name = "Spc"; + break; + case '\n': + button_name = "Ent"; + break; + case '\r': + button_name = "Ret"; + break; + case '\033': // won't happen; ESC is hidden + button_name = "Esc"; + break; + case '&': + // ampersand is used as a hidden quote char to flag + // next character as a keyboard shortcut associated + // with the current action--that's inappropriate here; + // two consecutive ampersands are needed to display + // one in a button label; first check whether caller + // has already done that, skip this one if so + if (i > 0 && ch[i - 1].cell() == '&') + continue; // next i + button_name = "&&"; + break; + } + } + button=new QPushButton(button_name); + if (making_y && allow_count) + y_btn = button; // to change default in keyPressEvent() + if (!enable.isNull()) { + if (!enable.contains(ch[i])) + button->setEnabled(false); + } + button->setFixedSize(butwidth, butheight); + if (ch[i] == def) + button->setDefault(true); +#if 0 + // 'x' and 'y' don't seem to actually used anywhere + // and limit of 10 buttons per row isn't enforced + if (i % 10 == 9) { + // last in row + x = margin; + y += butheight + gutter; + } else { + x += butwidth + gutter; + } +#endif + groupbox->addWidget(button); + bgroup->addButton(button, i); + } + + connect(bgroup, SIGNAL(buttonClicked(int)), this, SLOT(doneItem(int))); + + QLabel *lb = 0; + if (allow_count) { + // insert Count widget in front of [n], between [y] and [n][a][q] + lb = new QLabel("Count:"); + groupbox->insertWidget(1, lb); // [y] button is item #0, [n] is #1 + le = new QLineEdit(); + groupbox->insertWidget(2, le); // [n] became #2, Count label is #1 + le->setPlaceholderText(QString("#")); // grayed out + } + // add an invisible right-most field to left justify the buttons + groupbox->addStretch(80); + + setLayout(vb); + adjustSize(); + centerOnMain(this); + show(); + char choice=0; + char ch_esc=0; + for (int i = 0; i < ch.length(); ++i) { + if (ch[i].cell() == 'q') + ch_esc = 'q'; + else if (!ch_esc && ch[i].cell() == 'n') + ch_esc = 'n'; + } + + // + // When a count is allowed, clicking on the count widget then + // typing in digits followed by is 'normal' operation. + // However, typing a digit without clicking first will set focus + // to the count widget with that typed digit preloaded. + // + exec(); + int res = result(); + if (res == 0) { + choice = is_lr ? '\033' : ch_esc ? ch_esc : def ? def : ' '; + } else if (res == 1) { + if (keypress) + choice = keypress; + else + choice = def ? def : ch_esc ? ch_esc : ' '; + } else if (res >= 1000) { + choice = (char) ch[res - 1000].cell(); + } + + // non-Null 'le' implies 'allow_count'; having a grayed-out '#' + // present in the QLineEdit widget doesn't affect its isEmpty() test + if (le && !le->text().isEmpty()) { + QString text(le->text()); + if (text.at(0) == QChar('#')) + text = text.mid(1); // rest of string past [0] + ::yn_number = text.toLong(); + choice = '#'; + } + keypress = choice; + + } else { + QLabel label(qlabel,this); + QPushButton cancel("Dismiss",this); +#if __cplusplus >= 202002L + label.setFrameStyle(static_cast(QFrame::Box) + | static_cast(QFrame::Sunken)); +#else + label.setFrameStyle(QFrame::Box|QFrame::Sunken); +#endif + label.setAlignment(Qt::AlignCenter); + label.resize(fontMetrics().QFM_WIDTH(qlabel)+60,30+fontMetrics().height()); + cancel.move(width()/2-cancel.width()/2,label.geometry().bottom()+8); + connect(&cancel,SIGNAL(clicked()),this,SLOT(reject())); + centerOnMain(this); + setResult(-1); + show(); + keypress = '\033'; + exec(); + } + return keypress; +} + +void NetHackQtYnDialog::AltChoice(char ans, char res) +{ + if (ans && !strchr(alt_answer, ans)) { + (void) strkitten(alt_answer, ans); + (void) strkitten(alt_result, res); + } +} + +void NetHackQtYnDialog::keyPressEvent(QKeyEvent *event) +{ + keypress = keyValue(event); + if (!keypress) + return; + + char *p = NULL; + if (*alt_answer && (p = strchr(alt_answer, keypress)) != 0) + keypress = alt_result[p - alt_answer]; + + if (!choices || !*choices || !keypress) { + this->done(1); + + } else { + int where = QString::fromLatin1(choices).indexOf(QChar(keypress)); + + if (allow_count && strchr("#0123456789", keypress)) { + if (keypress == '#') { + // 0 will be preselected; typing anything replaces it + le->setText(QString("0")); + le->home(true); + } else { + // digit will not be preselected; typing another appends + le->setText(QChar(keypress)); + le->end(false); + } + // (don't know whether this actually does anything useful) + le->setAttribute(Qt::WA_KeyboardFocusChange, true); + // this is definitely useful... + le->setFocus(Qt::ActiveWindowFocusReason); + // change default button from 'n' to 'y' + if (y_btn) + y_btn->setDefault(true); + } else if (where != -1) { + this->done(where + 1000); + + } else { + QDialog::keyPressEvent(event); + } + } +} + +void NetHackQtYnDialog::doneItem(int i) +{ + this->done(i + 1000); +} + +} // namespace nethack_qt_ diff --git a/win/Qt4/qt4yndlg.h b/win/Qt/qt_yndlg.h similarity index 60% rename from win/Qt4/qt4yndlg.h rename to win/Qt/qt_yndlg.h index d1474f541..0dd5d39e1 100644 --- a/win/Qt4/qt4yndlg.h +++ b/win/Qt/qt_yndlg.h @@ -2,12 +2,12 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt4yndlg.h -- yes/no dialog +// qt_yndlg.h -- yes/no dialog #ifndef QT4YNDLG_H #define QT4YNDLG_H -namespace nethack_qt4 { +namespace nethack_qt_ { class NetHackQtYnDialog : QDialog { Q_OBJECT @@ -16,9 +16,16 @@ class NetHackQtYnDialog : QDialog { const char* choices; char def; char keypress; + bool allow_count; + QLineEdit *le; + QPushButton *y_btn; + + // arbitrary size; might need to be more sophisticated someday + char alt_answer[26 + 1], alt_result[26 + 1]; protected: virtual void keyPressEvent(QKeyEvent*); + void AltChoice(char answer, char result); private slots: void doneItem(int); @@ -29,6 +36,6 @@ private slots: char Exec(); }; -} // namespace nethack_qt4 +} // namespace nethack_qt_ #endif diff --git a/win/Qt/qttableview.cpp b/win/Qt/qttableview.cpp deleted file mode 100644 index b53e8a415..000000000 --- a/win/Qt/qttableview.cpp +++ /dev/null @@ -1,2276 +0,0 @@ -/********************************************************************** -** $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.4 $ $NHDT-Date: 1524684508 2018/04/25 19:28:28 $ -** $Id: qttableview.cpp,v 1.2 2002/03/09 03:13:15 jwalz Exp $ -** -** Implementation of QtTableView class -** -** Created : 941115 -** -** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. -** -** This file contains a class moved out of the Qt GUI Toolkit API. It -** may be used, distributed and modified without limitation. -** -**********************************************************************/ - -#include "qttableview.h" -#if QT_VERSION >= 300 -#ifndef QT_NO_QTTABLEVIEW -#include -#include -#include -#include - -enum ScrollBarDirtyFlags { - verGeometry = 0x01, - verSteps = 0x02, - verRange = 0x04, - verValue = 0x08, - horGeometry = 0x10, - horSteps = 0x20, - horRange = 0x40, - horValue = 0x80, - verMask = 0x0F, - horMask = 0xF0 -}; - - -#define HSBEXT horizontalScrollBar()->sizeHint().height() -#define VSBEXT verticalScrollBar()->sizeHint().width() - - -class QCornerSquare : public QWidget // internal class -{ -public: - QCornerSquare( QWidget *, const char* = 0 ); - void paintEvent( QPaintEvent * ); -}; - -QCornerSquare::QCornerSquare( QWidget *parent, const char *name ) - : QWidget( parent, name ) -{ -} - -void QCornerSquare::paintEvent( QPaintEvent * ) -{ -} - - -// NOT REVISED -/*! - \class QtTableView qttableview.h - \brief The QtTableView class provides an abstract base for tables. - - \obsolete - - A table view consists of a number of abstract cells organized in rows - and columns, and a visible part called a view. The cells are identified - with a row index and a column index. The top-left cell is in row 0, - column 0. - - The behavior of the widget can be finely tuned using - setTableFlags(); a typical subclass will consist of little more than a - call to setTableFlags(), some table content manipulation and an - implementation of paintCell(). Subclasses that need cells with - variable width or height must reimplement cellHeight() and/or - cellWidth(). Use updateTableSize() to tell QtTableView when the - width or height has changed. - - When you read this documentation, it is important to understand the - distinctions among the four pixel coordinate systems involved. - - \list 1 - \i The \e cell coordinates. (0,0) is the top-left corner of a cell. - Cell coordinates are used by functions such as paintCell(). - - \i The \e table coordinates. (0,0) is the top-left corner of the cell at - row 0 and column 0. These coordinates are absolute; that is, they are - independent of what part of the table is visible at the moment. They are - used by functions such as setXOffset() or maxYOffset(). - - \i The \e widget coordinates. (0,0) is the top-left corner of the widget, - \e including the frame. They are used by functions such as repaint(). - - \i The \e view coordinates. (0,0) is the top-left corner of the view, \e - excluding the frame. This is the least-used coordinate system; it is used by - functions such as viewWidth(). \endlist - - It is rather unfortunate that we have to use four different - coordinate systems, but there was no alternative to provide a flexible and - powerful base class. - - Note: The row,column indices are always given in that order, - i.e., first the vertical (row), then the horizontal (column). This is - the opposite order of all pixel operations, which take first the - horizontal (x) and then the vertical (y). - - - - \warning the functions setNumRows(), setNumCols(), setCellHeight(), - setCellWidth(), setTableFlags() and clearTableFlags() may cause - virtual functions such as cellWidth() and cellHeight() to be called, - even if autoUpdate() is FALSE. This may cause errors if relevant - state variables are not initialized. - - \warning Experience has shown that use of this widget tends to cause - more bugs than expected and our analysis indicates that the widget's - very flexibility is the problem. If QScrollView or QListBox can - easily be made to do the job you need, we recommend subclassing - those widgets rather than QtTableView. In addition, QScrollView makes - it easy to have child widgets inside tables, which QtTableView - doesn't support at all. - - \sa QScrollView - \link guibooks.html#fowler GUI Design Handbook: Table\endlink -*/ - - -/*! - Constructs a table view. The \a parent, \a name and \f arguments - are passed to the QFrame constructor. - - The \link setTableFlags() table flags\endlink are all cleared (set to 0). - Set \c Tbl_autoVScrollBar or \c Tbl_autoHScrollBar to get automatic scroll - bars and \c Tbl_clipCellPainting to get safe clipping. - - The \link setCellHeight() cell height\endlink and \link setCellWidth() - cell width\endlink are set to 0. - - Frame line shapes (QFrame::HLink and QFrame::VLine) are disallowed; - see QFrame::setFrameStyle(). - - Note that the \a f argument is \e not \link setTableFlags() table - flags \endlink but rather \link QWidget::QWidget() widget - flags. \endlink - -*/ - -QtTableView::QtTableView( QWidget *parent, const char *name, WFlags f ) - : QFrame( parent, name, f ) -{ - nRows = nCols = 0; // zero rows/cols - xCellOffs = yCellOffs = 0; // zero offset - xCellDelta = yCellDelta = 0; // zero cell offset - xOffs = yOffs = 0; // zero total pixel offset - cellH = cellW = 0; // user defined cell size - tFlags = 0; - vScrollBar = hScrollBar = 0; // no scroll bars - cornerSquare = 0; - sbDirty = 0; - eraseInPaint = FALSE; - verSliding = FALSE; - verSnappingOff = FALSE; - horSliding = FALSE; - horSnappingOff = FALSE; - coveringCornerSquare = FALSE; - inSbUpdate = FALSE; -} - -/*! - Destroys the table view. -*/ - -QtTableView::~QtTableView() -{ - delete vScrollBar; - delete hScrollBar; - delete cornerSquare; -} - - -/*! - \internal - Reimplements QWidget::setBackgroundColor() for binary compatibility. - \sa setPalette() -*/ - -void QtTableView::setBackgroundColor( const QColor &c ) -{ - QWidget::setBackgroundColor( c ); -} - -/*!\reimp -*/ - -void QtTableView::setPalette( const QPalette &p ) -{ - QWidget::setPalette( p ); -} - -/*!\reimp -*/ - -void QtTableView::show() -{ - showOrHideScrollBars(); - QWidget::show(); -} - - -/*! - \overload void QtTableView::repaint( bool erase ) - Repaints the entire view. -*/ - -/*! - Repaints the table view directly by calling paintEvent() directly - unless updates are disabled. - - Erases the view area \a (x,y,w,h) if \a erase is TRUE. Parameters \a - (x,y) are in \e widget coordinates. - - If \a w is negative, it is replaced with width() - x. - If \a h is negative, it is replaced with height() - y. - - Doing a repaint() usually is faster than doing an update(), but - calling update() many times in a row will generate a single paint - event. - - At present, QtTableView is the only widget that reimplements \link - QWidget::repaint() repaint()\endlink. It does this because by - clearing and then repainting one cell at at time, it can make the - screen flicker less than it would otherwise. */ - -void QtTableView::repaint( int x, int y, int w, int h, bool erase ) -{ - if ( !isVisible() || testWState(WState_BlockUpdates) ) - return; - if ( w < 0 ) - w = width() - x; - if ( h < 0 ) - h = height() - y; - QRect r( x, y, w, h ); - if ( r.isEmpty() ) - return; // nothing to do - QPaintEvent e( r ); - if ( erase && backgroundMode() != NoBackground ) - eraseInPaint = TRUE; // erase when painting - paintEvent( &e ); - eraseInPaint = FALSE; -} - -/*! - \overload void QtTableView::repaint( const QRect &r, bool erase ) - Replaints rectangle \a r. If \a erase is TRUE draws the background - using the palette's background. -*/ - - -/*! - \fn int QtTableView::numRows() const - Returns the number of rows in the table. - \sa numCols(), setNumRows() -*/ - -/*! - Sets the number of rows of the table to \a rows (must be non-negative). - Does not change topCell(). - - The table repaints itself automatically if autoUpdate() is set. - - \sa numCols(), setNumCols(), numRows() -*/ - -void QtTableView::setNumRows( int rows ) -{ - if ( rows < 0 ) { -#if defined(QT_CHECK_RANGE) - qWarning( "QtTableView::setNumRows: (%s) Negative argument %d.", - name( "unnamed" ), rows ); -#endif - return; - } - if ( nRows == rows ) - return; - - if ( autoUpdate() && isVisible() ) { - int oldLastVisible = lastRowVisible(); - int oldTopCell = topCell(); - nRows = rows; - if ( autoUpdate() && isVisible() && - ( oldLastVisible != lastRowVisible() || oldTopCell != topCell() ) ) - repaint( oldTopCell != topCell() ); - } else { - // Be more careful - if destructing, bad things might happen. - nRows = rows; - } - updateScrollBars( verRange ); - updateFrameSize(); -} - -/*! - \fn int QtTableView::numCols() const - Returns the number of columns in the table. - \sa numRows(), setNumCols() -*/ - -/*! - Sets the number of columns of the table to \a cols (must be non-negative). - Does not change leftCell(). - - The table repaints itself automatically if autoUpdate() is set. - - \sa numCols(), numRows(), setNumRows() -*/ - -void QtTableView::setNumCols( int cols ) -{ - if ( cols < 0 ) { -#if defined(QT_CHECK_RANGE) - qWarning( "QtTableView::setNumCols: (%s) Negative argument %d.", - name( "unnamed" ), cols ); -#endif - return; - } - if ( nCols == cols ) - return; - int oldCols = nCols; - nCols = cols; - if ( autoUpdate() && isVisible() ) { - int maxCol = lastColVisible(); - if ( maxCol >= oldCols || maxCol >= nCols ) - repaint(); - } - updateScrollBars( horRange ); - updateFrameSize(); -} - - -/*! - \fn int QtTableView::topCell() const - Returns the index of the first row in the table that is visible in - the view. The index of the first row is 0. - \sa leftCell(), setTopCell() -*/ - -/*! - Scrolls the table so that \a row becomes the top row. - The index of the very first row is 0. - \sa setYOffset(), setTopLeftCell(), setLeftCell() -*/ - -void QtTableView::setTopCell( int row ) -{ - setTopLeftCell( row, -1 ); - return; -} - -/*! - \fn int QtTableView::leftCell() const - Returns the index of the first column in the table that is visible in - the view. The index of the very leftmost column is 0. - \sa topCell(), setLeftCell() -*/ - -/*! - Scrolls the table so that \a col becomes the leftmost - column. The index of the leftmost column is 0. - \sa setXOffset(), setTopLeftCell(), setTopCell() -*/ - -void QtTableView::setLeftCell( int col ) -{ - setTopLeftCell( -1, col ); - return; -} - -/*! - Scrolls the table so that the cell at row \a row and colum \a - col becomes the top-left cell in the view. The cell at the extreme - top left of the table is at position (0,0). - \sa setLeftCell(), setTopCell(), setOffset() -*/ - -void QtTableView::setTopLeftCell( int row, int col ) -{ - int newX = xOffs; - int newY = yOffs; - - if ( col >= 0 ) { - if ( cellW ) { - newX = col*cellW; - if ( newX > maxXOffset() ) - newX = maxXOffset(); - } else { - newX = 0; - while ( col ) - newX += cellWidth( --col ); // optimize using current! ### - } - } - if ( row >= 0 ) { - if ( cellH ) { - newY = row*cellH; - if ( newY > maxYOffset() ) - newY = maxYOffset(); - } else { - newY = 0; - while ( row ) - newY += cellHeight( --row ); // optimize using current! ### - } - } - setOffset( newX, newY ); -} - - -/*! - \fn int QtTableView::xOffset() const - - Returns the x coordinate in \e table coordinates of the pixel that is - currently on the left edge of the view. - - \sa setXOffset(), yOffset(), leftCell() */ - -/*! - Scrolls the table so that \a x becomes the leftmost pixel in the view. - The \a x parameter is in \e table coordinates. - - The interaction with \link setTableFlags() Tbl_snapToHGrid - \endlink is tricky. - - \sa xOffset(), setYOffset(), setOffset(), setLeftCell() -*/ - -void QtTableView::setXOffset( int x ) -{ - setOffset( x, yOffset() ); -} - -/*! - \fn int QtTableView::yOffset() const - - Returns the y coordinate in \e table coordinates of the pixel that is - currently on the top edge of the view. - - \sa setYOffset(), xOffset(), topCell() -*/ - - -/*! - Scrolls the table so that \a y becomes the top pixel in the view. - The \a y parameter is in \e table coordinates. - - The interaction with \link setTableFlags() Tbl_snapToVGrid - \endlink is tricky. - - \sa yOffset(), setXOffset(), setOffset(), setTopCell() -*/ - -void QtTableView::setYOffset( int y ) -{ - setOffset( xOffset(), y ); -} - -/*! - Scrolls the table so that \a (x,y) becomes the top-left pixel - in the view. Parameters \a (x,y) are in \e table coordinates. - - The interaction with \link setTableFlags() Tbl_snapTo*Grid \endlink - is tricky. If \a updateScrBars is TRUE, the scroll bars are - updated. - - \sa xOffset(), yOffset(), setXOffset(), setYOffset(), setTopLeftCell() -*/ - -void QtTableView::setOffset( int x, int y, bool updateScrBars ) -{ - if ( (!testTableFlags(Tbl_snapToHGrid) || xCellDelta == 0) && - (!testTableFlags(Tbl_snapToVGrid) || yCellDelta == 0) && - (x == xOffs && y == yOffs) ) - return; - - if ( x < 0 ) - x = 0; - if ( y < 0 ) - y = 0; - - if ( cellW ) { - if ( x > maxXOffset() ) - x = maxXOffset(); - xCellOffs = x / cellW; - if ( !testTableFlags(Tbl_snapToHGrid) ) { - xCellDelta = (short)(x % cellW); - } else { - x = xCellOffs*cellW; - xCellDelta = 0; - } - } else { - int xn=0, xcd=0, col = 0; - while ( col < nCols-1 && x >= xn+(xcd=cellWidth(col)) ) { - xn += xcd; - col++; - } - xCellOffs = col; - if ( testTableFlags(Tbl_snapToHGrid) ) { - xCellDelta = 0; - x = xn; - } else { - xCellDelta = (short)(x-xn); - } - } - if ( cellH ) { - if ( y > maxYOffset() ) - y = maxYOffset(); - yCellOffs = y / cellH; - if ( !testTableFlags(Tbl_snapToVGrid) ) { - yCellDelta = (short)(y % cellH); - } else { - y = yCellOffs*cellH; - yCellDelta = 0; - } - } else { - int yn=0, yrd=0, row=0; - while ( row < nRows-1 && y >= yn+(yrd=cellHeight(row)) ) { - yn += yrd; - row++; - } - yCellOffs = row; - if ( testTableFlags(Tbl_snapToVGrid) ) { - yCellDelta = 0; - y = yn; - } else { - yCellDelta = (short)(y-yn); - } - } - int dx = (x - xOffs); - int dy = (y - yOffs); - xOffs = x; - yOffs = y; - if ( autoUpdate() && isVisible() ) - scroll( dx, dy ); - if ( updateScrBars ) - updateScrollBars( verValue | horValue ); -} - - -/*! - \overload int QtTableView::cellWidth() const - - Returns the column width in pixels. Returns 0 if the columns have - variable widths. - - \sa setCellWidth(), cellHeight() -*/ - -/*! - Returns the width of column \a col in pixels. - - This function is virtual and must be reimplemented by subclasses that - have variable cell widths. Note that if the total table width - changes, updateTableSize() must be called. - - \sa setCellWidth(), cellHeight(), totalWidth(), updateTableSize() -*/ - -int QtTableView::cellWidth( int ) -{ - return cellW; -} - - -/*! - Sets the width in pixels of the table cells to \a cellWidth. - - Setting it to 0 means that the column width is variable. When - set to 0 (this is the default) QtTableView calls the virtual function - cellWidth() to get the width. - - \sa cellWidth(), setCellHeight(), totalWidth(), numCols() -*/ - -void QtTableView::setCellWidth( int cellWidth ) -{ - if ( cellW == cellWidth ) - return; -#if defined(QT_CHECK_RANGE) - if ( cellWidth < 0 || cellWidth > SHRT_MAX ) { - qWarning( "QtTableView::setCellWidth: (%s) Argument out of range (%d)", - name( "unnamed" ), cellWidth ); - return; - } -#endif - cellW = (short)cellWidth; - - updateScrollBars( horSteps | horRange ); - if ( autoUpdate() && isVisible() ) - repaint(); - -} - -/*! - \overload int QtTableView::cellHeight() const - - Returns the row height, in pixels. Returns 0 if the rows have - variable heights. - - \sa setCellHeight(), cellWidth() -*/ - - -/*! - Returns the height of row \a row in pixels. - - This function is virtual and must be reimplemented by subclasses that - have variable cell heights. Note that if the total table height - changes, updateTableSize() must be called. - - \sa setCellHeight(), cellWidth(), totalHeight() -*/ - -int QtTableView::cellHeight( int ) -{ - return cellH; -} - -/*! - Sets the height in pixels of the table cells to \a cellHeight. - - Setting it to 0 means that the row height is variable. When set - to 0 (this is the default), QtTableView calls the virtual function - cellHeight() to get the height. - - \sa cellHeight(), setCellWidth(), totalHeight(), numRows() -*/ - -void QtTableView::setCellHeight( int cellHeight ) -{ - if ( cellH == cellHeight ) - return; -#if defined(QT_CHECK_RANGE) - if ( cellHeight < 0 || cellHeight > SHRT_MAX ) { - qWarning( "QtTableView::setCellHeight: (%s) Argument out of range (%d)", - name( "unnamed" ), cellHeight ); - return; - } -#endif - cellH = (short)cellHeight; - if ( autoUpdate() && isVisible() ) - repaint(); - updateScrollBars( verSteps | verRange ); -} - - -/*! - Returns the total width of the table in pixels. - - This function is virtual and should be reimplemented by subclasses that - have variable cell widths and a non-trivial cellWidth() function, or a - large number of columns in the table. - - The default implementation may be slow for very wide tables. - - \sa cellWidth(), totalHeight() */ - -int QtTableView::totalWidth() -{ - if ( cellW ) { - return cellW*nCols; - } else { - int tw = 0; - for( int i = 0 ; i < nCols ; i++ ) - tw += cellWidth( i ); - return tw; - } -} - -/*! - Returns the total height of the table in pixels. - - This function is virtual and should be reimplemented by subclasses that - have variable cell heights and a non-trivial cellHeight() function, or a - large number of rows in the table. - - The default implementation may be slow for very tall tables. - - \sa cellHeight(), totalWidth() -*/ - -int QtTableView::totalHeight() -{ - if ( cellH ) { - return cellH*nRows; - } else { - int th = 0; - for( int i = 0 ; i < nRows ; i++ ) - th += cellHeight( i ); - return th; - } -} - - -/*! - \fn uint QtTableView::tableFlags() const - - Returns the union of the table flags that are currently set. - - \sa setTableFlags(), clearTableFlags(), testTableFlags() -*/ - -/*! - \fn bool QtTableView::testTableFlags( uint f ) const - - Returns TRUE if any of the table flags in \a f are currently set, - otherwise FALSE. - - \sa setTableFlags(), clearTableFlags(), tableFlags() -*/ - -/*! - Sets the table flags to \a f. - - If a flag setting changes the appearance of the table, the table is - repainted if - and only if - autoUpdate() is TRUE. - - The table flags are mostly single bits, though there are some multibit - flags for convenience. Here is a complete list: - -
-
Tbl_vScrollBar
- The table has a vertical scroll bar. -
Tbl_hScrollBar
- The table has a horizontal scroll bar. -
Tbl_autoVScrollBar
- The table has a vertical scroll bar if - - and only if - the table is taller than the view. -
Tbl_autoHScrollBar
The table has a horizontal scroll bar if - - and only if - the table is wider than the view. -
Tbl_autoScrollBars
- The union of the previous two flags. -
Tbl_clipCellPainting
- The table uses QPainter::setClipRect() to - make sure that paintCell() will not draw outside the cell - boundaries. -
Tbl_cutCellsV
- The table will never show part of a - cell at the bottom of the table; if there is not space for all of - a cell, the space is left blank. -
Tbl_cutCellsH
- The table will never show part of a - cell at the right side of the table; if there is not space for all of - a cell, the space is left blank. -
Tbl_cutCells
- The union of the previous two flags. -
Tbl_scrollLastHCell
- When the user scrolls horizontally, - let him/her scroll the last cell left until it is at the left - edge of the view. If this flag is not set, the user can only scroll - to the point where the last cell is completely visible. -
Tbl_scrollLastVCell
- When the user scrolls vertically, let - him/her scroll the last cell up until it is at the top edge of - the view. If this flag is not set, the user can only scroll to the - point where the last cell is completely visible. -
Tbl_scrollLastCell
- The union of the previous two flags. -
Tbl_smoothHScrolling
- The table scrolls as smoothly as - possible when the user scrolls horizontally. When this flag is not - set, scrolling is done one cell at a time. -
Tbl_smoothVScrolling
- The table scrolls as smoothly as - possible when scrolling vertically. When this flag is not set, - scrolling is done one cell at a time. -
Tbl_smoothScrolling
- The union of the previous two flags. -
Tbl_snapToHGrid
- Except when the user is actually scrolling, - the leftmost column shown snaps to the leftmost edge of the view. -
Tbl_snapToVGrid
- Except when the user is actually - scrolling, the top row snaps to the top edge of the view. -
Tbl_snapToGrid
- The union of the previous two flags. -
- - You can specify more than one flag at a time using bitwise OR. - - Example: - \code - setTableFlags( Tbl_smoothScrolling | Tbl_autoScrollBars ); - \endcode - - \warning The cutCells options (\c Tbl_cutCells, \c Tbl_cutCellsH and - Tbl_cutCellsV) may cause painting problems when scrollbars are - enabled. Do not combine cutCells and scrollbars. - - - \sa clearTableFlags(), testTableFlags(), tableFlags() -*/ - -void QtTableView::setTableFlags( uint f ) -{ - f = (f ^ tFlags) & f; // clear flags already set - tFlags |= f; - - bool updateOn = autoUpdate(); - setAutoUpdate( FALSE ); - - uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH; - - if ( f & Tbl_vScrollBar ) { - setVerScrollBar( TRUE ); - } - if ( f & Tbl_hScrollBar ) { - setHorScrollBar( TRUE ); - } - if ( f & Tbl_autoVScrollBar ) { - updateScrollBars( verRange ); - } - if ( f & Tbl_autoHScrollBar ) { - updateScrollBars( horRange ); - } - if ( f & Tbl_scrollLastHCell ) { - updateScrollBars( horRange ); - } - if ( f & Tbl_scrollLastVCell ) { - updateScrollBars( verRange ); - } - if ( f & Tbl_snapToHGrid ) { - updateScrollBars( horRange ); - } - if ( f & Tbl_snapToVGrid ) { - updateScrollBars( verRange ); - } - if ( f & Tbl_snapToGrid ) { // Note: checks for 2 flags - if ( (f & Tbl_snapToHGrid) != 0 && xCellDelta != 0 || //have to scroll? - (f & Tbl_snapToVGrid) != 0 && yCellDelta != 0 ) { - snapToGrid( (f & Tbl_snapToHGrid) != 0, // do snapping - (f & Tbl_snapToVGrid) != 0 ); - repaintMask |= Tbl_snapToGrid; // repaint table - } - } - - if ( updateOn ) { - setAutoUpdate( TRUE ); - updateScrollBars(); - if ( isVisible() && (f & repaintMask) ) - repaint(); - } - -} - -/*! - Clears the \link setTableFlags() table flags\endlink that are set - in \a f. - - Example (clears a single flag): - \code - clearTableFlags( Tbl_snapToGrid ); - \endcode - - The default argument clears all flags. - - \sa setTableFlags(), testTableFlags(), tableFlags() -*/ - -void QtTableView::clearTableFlags( uint f ) -{ - f = (f ^ ~tFlags) & f; // clear flags that are already 0 - tFlags &= ~f; - - bool updateOn = autoUpdate(); - setAutoUpdate( FALSE ); - - uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH; - - if ( f & Tbl_vScrollBar ) { - setVerScrollBar( FALSE ); - } - if ( f & Tbl_hScrollBar ) { - setHorScrollBar( FALSE ); - } - if ( f & Tbl_scrollLastHCell ) { - int maxX = maxXOffset(); - if ( xOffs > maxX ) { - setOffset( maxX, yOffs ); - repaintMask |= Tbl_scrollLastHCell; - } - updateScrollBars( horRange ); - } - if ( f & Tbl_scrollLastVCell ) { - int maxY = maxYOffset(); - if ( yOffs > maxY ) { - setOffset( xOffs, maxY ); - repaintMask |= Tbl_scrollLastVCell; - } - updateScrollBars( verRange ); - } - if ( f & Tbl_smoothScrolling ) { // Note: checks for 2 flags - if ((f & Tbl_smoothHScrolling) != 0 && xCellDelta != 0 ||//must scroll? - (f & Tbl_smoothVScrolling) != 0 && yCellDelta != 0 ) { - snapToGrid( (f & Tbl_smoothHScrolling) != 0, // do snapping - (f & Tbl_smoothVScrolling) != 0 ); - repaintMask |= Tbl_smoothScrolling; // repaint table - } - } - if ( f & Tbl_snapToHGrid ) { - updateScrollBars( horRange ); - } - if ( f & Tbl_snapToVGrid ) { - updateScrollBars( verRange ); - } - if ( updateOn ) { - setAutoUpdate( TRUE ); - updateScrollBars(); // returns immediately if nothing to do - if ( isVisible() && (f & repaintMask) ) - repaint(); - } - -} - - -/*! - \fn bool QtTableView::autoUpdate() const - - Returns TRUE if the view updates itself automatically whenever it - is changed in some way. - - \sa setAutoUpdate() -*/ - -/*! - Sets the auto-update option of the table view to \a enable. - - If \a enable is TRUE (this is the default), the view updates itself - automatically whenever it has changed in some way (for example, when a - \link setTableFlags() flag\endlink is changed). - - If \a enable is FALSE, the view does NOT repaint itself or update - its internal state variables when it is changed. This can be - useful to avoid flicker during large changes and is singularly - useless otherwise. Disable auto-update, do the changes, re-enable - auto-update and call repaint(). - - \warning Do not leave the view in this state for a long time - (i.e., between events). If, for example, the user interacts with the - view when auto-update is off, strange things can happen. - - Setting auto-update to TRUE does not repaint the view; you must call - repaint() to do this. - - \sa autoUpdate(), repaint() -*/ - -void QtTableView::setAutoUpdate( bool enable ) -{ - if ( isUpdatesEnabled() == enable ) - return; - setUpdatesEnabled( enable ); - if ( enable ) { - showOrHideScrollBars(); - updateScrollBars(); - } -} - - -/*! - Repaints the cell at row \a row, column \a col if it is inside the view. - - If \a erase is TRUE, the relevant part of the view is cleared to the - background color/pixmap before the contents are repainted. - - \sa isVisible() -*/ - -void QtTableView::updateCell( int row, int col, bool erase ) -{ - int xPos, yPos; - if ( !colXPos( col, &xPos ) ) - return; - if ( !rowYPos( row, &yPos ) ) - return; - QRect uR = QRect( xPos, yPos, - cellW ? cellW : cellWidth(col), - cellH ? cellH : cellHeight(row) ); - repaint( uR.intersect(viewRect()), erase ); -} - - -/*! - \fn QRect QtTableView::cellUpdateRect() const - - This function should be called only from the paintCell() function in - subclasses. It returns the portion of a cell that actually needs to be - updated in \e cell coordinates. This is useful only for non-trivial - paintCell(). - -*/ - -/*! - Returns the rectangle that is the actual table, excluding any - frame, in \e widget coordinates. -*/ - -QRect QtTableView::viewRect() const -{ - return QRect( frameWidth(), frameWidth(), viewWidth(), viewHeight() ); -} - - -/*! - Returns the index of the last (bottom) row in the view. - The index of the first row is 0. - - If no rows are visible it returns -1. This can happen if the - view is too small for the first row and Tbl_cutCellsV is set. - - \sa lastColVisible() -*/ - -int QtTableView::lastRowVisible() const -{ - int cellMaxY; - int row = findRawRow( maxViewY(), &cellMaxY ); - if ( row == -1 || row >= nRows ) { // maxViewY() past end? - row = nRows - 1; // yes: return last row - } else { - if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) { - if ( row == yCellOffs ) // cut by right margin? - return -1; // yes, nothing in the view - else - row = row - 1; // cut by margin, one back - } - } - return row; -} - -/*! - Returns the index of the last (right) column in the view. - The index of the first column is 0. - - If no columns are visible it returns -1. This can happen if the - view is too narrow for the first column and Tbl_cutCellsH is set. - - \sa lastRowVisible() -*/ - -int QtTableView::lastColVisible() const -{ - int cellMaxX; - int col = findRawCol( maxViewX(), &cellMaxX ); - if ( col == -1 || col >= nCols ) { // maxViewX() past end? - col = nCols - 1; // yes: return last col - } else { - if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) { - if ( col == xCellOffs ) // cut by bottom margin? - return -1; // yes, nothing in the view - else - col = col - 1; // cell by margin, one back - } - } - return col; -} - -/*! - Returns TRUE if \a row is at least partially visible. - \sa colIsVisible() -*/ - -bool QtTableView::rowIsVisible( int row ) const -{ - return rowYPos( row, 0 ); -} - -/*! - Returns TRUE if \a col is at least partially visible. - \sa rowIsVisible() -*/ - -bool QtTableView::colIsVisible( int col ) const -{ - return colXPos( col, 0 ); -} - - -/*! - \internal - Called when both scroll bars are active at the same time. Covers the - bottom left corner between the two scroll bars with an empty widget. -*/ - -void QtTableView::coverCornerSquare( bool enable ) -{ - coveringCornerSquare = enable; - if ( !cornerSquare && enable ) { - cornerSquare = new QCornerSquare( this ); - Q_CHECK_PTR( cornerSquare ); - cornerSquare->setGeometry( maxViewX() + frameWidth() + 1, - maxViewY() + frameWidth() + 1, - VSBEXT, - HSBEXT); - } - if ( autoUpdate() && cornerSquare ) { - if ( enable ) - cornerSquare->show(); - else - cornerSquare->hide(); - } -} - - -/*! - \internal - Scroll the view to a position such that: - - If \a horizontal is TRUE, the leftmost column shown fits snugly - with the left edge of the view. - - If \a vertical is TRUE, the top row shown fits snugly with the top - of the view. - - You can achieve the same effect automatically by setting any of the - \link setTableFlags() Tbl_snapTo*Grid \endlink table flags. -*/ - -void QtTableView::snapToGrid( bool horizontal, bool vertical ) -{ - int newXCell = -1; - int newYCell = -1; - if ( horizontal && xCellDelta != 0 ) { - int w = cellW ? cellW : cellWidth( xCellOffs ); - if ( xCellDelta >= w/2 ) - newXCell = xCellOffs + 1; - else - newXCell = xCellOffs; - } - if ( vertical && yCellDelta != 0 ) { - int h = cellH ? cellH : cellHeight( yCellOffs ); - if ( yCellDelta >= h/2 ) - newYCell = yCellOffs + 1; - else - newYCell = yCellOffs; - } - setTopLeftCell( newYCell, newXCell ); //row,column -} - -/*! - \internal - This internal slot is connected to the horizontal scroll bar's - QScrollBar::valueChanged() signal. - - Moves the table horizontally to offset \a val without updating the - scroll bar. -*/ - -void QtTableView::horSbValue( int val ) -{ - if ( horSliding ) { - horSliding = FALSE; - if ( horSnappingOff ) { - horSnappingOff = FALSE; - tFlags |= Tbl_snapToHGrid; - } - } - setOffset( val, yOffs, FALSE ); -} - -/*! - \internal - This internal slot is connected to the horizontal scroll bar's - QScrollBar::sliderMoved() signal. - - Scrolls the table smoothly horizontally even if \c Tbl_snapToHGrid is set. -*/ - -void QtTableView::horSbSliding( int val ) -{ - if ( testTableFlags(Tbl_snapToHGrid) && - testTableFlags(Tbl_smoothHScrolling) ) { - tFlags &= ~Tbl_snapToHGrid; // turn off snapping while sliding - setOffset( val, yOffs, FALSE ); - tFlags |= Tbl_snapToHGrid; // turn on snapping again - } else { - setOffset( val, yOffs, FALSE ); - } -} - -/*! - \internal - This internal slot is connected to the horizontal scroll bar's - QScrollBar::sliderReleased() signal. -*/ - -void QtTableView::horSbSlidingDone( ) -{ - if ( testTableFlags(Tbl_snapToHGrid) && - testTableFlags(Tbl_smoothHScrolling) ) - snapToGrid( TRUE, FALSE ); -} - -/*! - \internal - This internal slot is connected to the vertical scroll bar's - QScrollBar::valueChanged() signal. - - Moves the table vertically to offset \a val without updating the - scroll bar. -*/ - -void QtTableView::verSbValue( int val ) -{ - if ( verSliding ) { - verSliding = FALSE; - if ( verSnappingOff ) { - verSnappingOff = FALSE; - tFlags |= Tbl_snapToVGrid; - } - } - setOffset( xOffs, val, FALSE ); -} - -/*! - \internal - This internal slot is connected to the vertical scroll bar's - QScrollBar::sliderMoved() signal. - - Scrolls the table smoothly vertically even if \c Tbl_snapToVGrid is set. -*/ - -void QtTableView::verSbSliding( int val ) -{ - if ( testTableFlags(Tbl_snapToVGrid) && - testTableFlags(Tbl_smoothVScrolling) ) { - tFlags &= ~Tbl_snapToVGrid; // turn off snapping while sliding - setOffset( xOffs, val, FALSE ); - tFlags |= Tbl_snapToVGrid; // turn on snapping again - } else { - setOffset( xOffs, val, FALSE ); - } -} - -/*! - \internal - This internal slot is connected to the vertical scroll bar's - QScrollBar::sliderReleased() signal. -*/ - -void QtTableView::verSbSlidingDone( ) -{ - if ( testTableFlags(Tbl_snapToVGrid) && - testTableFlags(Tbl_smoothVScrolling) ) - snapToGrid( FALSE, TRUE ); -} - - -/*! - This virtual function is called before painting of table cells - is started. It can be reimplemented by subclasses that want to - to set up the painter in a special way and that do not want to - do so for each cell. -*/ - -void QtTableView::setupPainter( QPainter * ) -{ -} - -/*! - \fn void QtTableView::paintCell( QPainter *p, int row, int col ) - - This pure virtual function is called to paint the single cell at \a - (row,col) using \a p, which is open when paintCell() is called and - must remain open. - - The coordinate system is \link QPainter::translate() translated \endlink - so that the origin is at the top-left corner of the cell to be - painted, i.e. \e cell coordinates. Do not scale or shear the coordinate - system (or if you do, restore the transformation matrix before you - return). - - The painter is not clipped by default and for maximum efficiency. For safety, - call setTableFlags(Tbl_clipCellPainting) to enable clipping. - - \sa paintEvent(), setTableFlags() */ - - -/*! - Handles paint events, \a e, for the table view. - - Calls paintCell() for the cells that needs to be repainted. -*/ - -void QtTableView::paintEvent( QPaintEvent *e ) -{ - QRect updateR = e->rect(); // update rectangle - if ( sbDirty ) { - bool e = eraseInPaint; - updateScrollBars(); - eraseInPaint = e; - } - - QPainter paint( this ); - - if ( !contentsRect().contains( updateR, TRUE ) ) {// update frame ? - drawFrame( &paint ); - if ( updateR.left() < frameWidth() ) //### - updateR.setLeft( frameWidth() ); - if ( updateR.top() < frameWidth() ) - updateR.setTop( frameWidth() ); - } - - int maxWX = maxViewX(); - int maxWY = maxViewY(); - if ( updateR.right() > maxWX ) - updateR.setRight( maxWX ); - if ( updateR.bottom() > maxWY ) - updateR.setBottom( maxWY ); - - setupPainter( &paint ); // prepare for painting table - - int firstRow = findRow( updateR.y() ); - int firstCol = findCol( updateR.x() ); - int xStart, yStart; - if ( !colXPos( firstCol, &xStart ) || !rowYPos( firstRow, &yStart ) ) { - paint.eraseRect( updateR ); // erase area outside cells but in view - return; - } - int maxX = updateR.right(); - int maxY = updateR.bottom(); - int row = firstRow; - int col; - int yPos = yStart; - int xPos = maxX+1; // in case the while() is empty - int nextX; - int nextY; - QRect winR = viewRect(); - QRect cellR; - QRect cellUR; -#ifndef QT_NO_TRANSFORMATIONS - QWMatrix matrix; -#endif - - while ( yPos <= maxY && row < nRows ) { - nextY = yPos + (cellH ? cellH : cellHeight( row )); - if ( testTableFlags( Tbl_cutCellsV ) && nextY > ( maxWY + 1 ) ) - break; - col = firstCol; - xPos = xStart; - while ( xPos <= maxX && col < nCols ) { - nextX = xPos + (cellW ? cellW : cellWidth( col )); - if ( testTableFlags( Tbl_cutCellsH ) && nextX > ( maxWX + 1 ) ) - break; - - cellR.setRect( xPos, yPos, cellW ? cellW : cellWidth(col), - cellH ? cellH : cellHeight(row) ); - cellUR = cellR.intersect( updateR ); - if ( cellUR.isValid() ) { - cellUpdateR = cellUR; - cellUpdateR.moveBy( -xPos, -yPos ); // cell coordinates - if ( eraseInPaint ) - paint.eraseRect( cellUR ); - -#ifndef QT_NO_TRANSFORMATIONS - matrix.translate( xPos, yPos ); - paint.setWorldMatrix( matrix ); - if ( testTableFlags(Tbl_clipCellPainting) || - frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt - paint.setClipRect( cellUR ); - paintCell( &paint, row, col ); - paint.setClipping( FALSE ); - } else { - paintCell( &paint, row, col ); - } - matrix.reset(); - paint.setWorldMatrix( matrix ); -#else - paint.translate( xPos, yPos ); - if ( testTableFlags(Tbl_clipCellPainting) || - frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt - paint.setClipRect( cellUR ); - paintCell( &paint, row, col ); - paint.setClipping( FALSE ); - } else { - paintCell( &paint, row, col ); - } - paint.translate( -xPos, -yPos ); -#endif - } - col++; - xPos = nextX; - } - row++; - yPos = nextY; - } - - // while painting we have to erase any areas in the view that - // are not covered by cells but are covered by the paint event - // rectangle these must be erased. We know that xPos is the last - // x pixel updated + 1 and that yPos is the last y pixel updated + 1. - - // Note that this needs to be done regardless whether we do - // eraseInPaint or not. Reason: a subclass may implement - // flicker-freeness and encourage the use of repaint(FALSE). - // The subclass, however, cannot draw all pixels, just those - // inside the cells. So QtTableView is reponsible for all pixels - // outside the cells. - - QRect viewR = viewRect(); - const QColorGroup g = colorGroup(); - - if ( xPos <= maxX ) { - QRect r = viewR; - r.setLeft( xPos ); - r.setBottom( yPossetCursor( arrowCursor ); -#endif - sb->resize( sb->sizeHint() ); // height is irrelevant - Q_CHECK_PTR(sb); - sb->setTracking( FALSE ); - sb->setFocusPolicy( NoFocus ); - connect( sb, SIGNAL(valueChanged(int)), - SLOT(verSbValue(int))); - connect( sb, SIGNAL(sliderMoved(int)), - SLOT(verSbSliding(int))); - connect( sb, SIGNAL(sliderReleased()), - SLOT(verSbSlidingDone())); - sb->hide(); - that->vScrollBar = sb; - return sb; - } - return vScrollBar; -} - -/*! - Returns a pointer to the horizontal scroll bar mainly so you can - connect() to its signals. Note that the scroll bar works in pixel - values; use findCol() to translate to cell numbers. -*/ - -QScrollBar *QtTableView::horizontalScrollBar() const -{ - QtTableView *that = (QtTableView*)this; // semantic const - if ( !hScrollBar ) { - QScrollBar *sb = new QScrollBar( QScrollBar::Horizontal, that ); -#ifndef QT_NO_CURSOR - sb->setCursor( arrowCursor ); -#endif - sb->resize( sb->sizeHint() ); // width is irrelevant - sb->setFocusPolicy( NoFocus ); - Q_CHECK_PTR(sb); - sb->setTracking( FALSE ); - connect( sb, SIGNAL(valueChanged(int)), - SLOT(horSbValue(int))); - connect( sb, SIGNAL(sliderMoved(int)), - SLOT(horSbSliding(int))); - connect( sb, SIGNAL(sliderReleased()), - SLOT(horSbSlidingDone())); - sb->hide(); - that->hScrollBar = sb; - return sb; - } - return hScrollBar; -} - -/*! - Enables or disables the horizontal scroll bar, as required by - setAutoUpdate() and the \link setTableFlags() table flags\endlink. -*/ - -void QtTableView::setHorScrollBar( bool on, bool update ) -{ - if ( on ) { - tFlags |= Tbl_hScrollBar; - horizontalScrollBar(); // created - if ( update ) - updateScrollBars( horMask | verMask ); - else - sbDirty = sbDirty | (horMask | verMask); - if ( testTableFlags( Tbl_vScrollBar ) ) - coverCornerSquare( TRUE ); - if ( autoUpdate() ) - sbDirty = sbDirty | horMask; - } else { - tFlags &= ~Tbl_hScrollBar; - if ( !hScrollBar ) - return; - coverCornerSquare( FALSE ); - bool hideScrollBar = autoUpdate() && hScrollBar->isVisible(); - if ( hideScrollBar ) - hScrollBar->hide(); - if ( update ) - updateScrollBars( verMask ); - else - sbDirty = sbDirty | verMask; - if ( hideScrollBar && isVisible() ) - repaint( hScrollBar->x(), hScrollBar->y(), - width() - hScrollBar->x(), hScrollBar->height() ); - } - if ( update ) - updateFrameSize(); -} - - -/*! - Enables or disables the vertical scroll bar, as required by - setAutoUpdate() and the \link setTableFlags() table flags\endlink. -*/ - -void QtTableView::setVerScrollBar( bool on, bool update ) -{ - if ( on ) { - tFlags |= Tbl_vScrollBar; - verticalScrollBar(); // created - if ( update ) - updateScrollBars( verMask | horMask ); - else - sbDirty = sbDirty | (horMask | verMask); - if ( testTableFlags( Tbl_hScrollBar ) ) - coverCornerSquare( TRUE ); - if ( autoUpdate() ) - sbDirty = sbDirty | verMask; - } else { - tFlags &= ~Tbl_vScrollBar; - if ( !vScrollBar ) - return; - coverCornerSquare( FALSE ); - bool hideScrollBar = autoUpdate() && vScrollBar->isVisible(); - if ( hideScrollBar ) - vScrollBar->hide(); - if ( update ) - updateScrollBars( horMask ); - else - sbDirty = sbDirty | horMask; - if ( hideScrollBar && isVisible() ) - repaint( vScrollBar->x(), vScrollBar->y(), - vScrollBar->width(), height() - vScrollBar->y() ); - } - if ( update ) - updateFrameSize(); -} - - - - -int QtTableView::findRawRow( int yPos, int *cellMaxY, int *cellMinY, - bool goOutsideView ) const -{ - int r = -1; - if ( nRows == 0 ) - return r; - if ( goOutsideView || yPos >= minViewY() && yPos <= maxViewY() ) { - if ( yPos < minViewY() ) { -#if defined(QT_CHECK_RANGE) - qWarning( "QtTableView::findRawRow: (%s) internal error: " - "yPos < minViewY() && goOutsideView " - "not supported. (%d,%d)", - name( "unnamed" ), yPos, yOffs ); -#endif - return -1; - } - if ( cellH ) { // uniform cell height - r = (yPos - minViewY() + yCellDelta)/cellH; // cell offs from top - if ( cellMaxY ) - *cellMaxY = (r + 1)*cellH + minViewY() - yCellDelta - 1; - if ( cellMinY ) - *cellMinY = r*cellH + minViewY() - yCellDelta; - r += yCellOffs; // absolute cell index - } else { // variable cell height - QtTableView *tw = (QtTableView *)this; - r = yCellOffs; - int h = minViewY() - yCellDelta; //##arnt3 - int oldH = h; - Q_ASSERT( r < nRows ); - while ( r < nRows ) { - oldH = h; - h += tw->cellHeight( r ); // Start of next cell - if ( yPos < h ) - break; - r++; - } - if ( cellMaxY ) - *cellMaxY = h - 1; - if ( cellMinY ) - *cellMinY = oldH; - } - } - return r; - -} - - -int QtTableView::findRawCol( int xPos, int *cellMaxX, int *cellMinX , - bool goOutsideView ) const -{ - int c = -1; - if ( nCols == 0 ) - return c; - if ( goOutsideView || xPos >= minViewX() && xPos <= maxViewX() ) { - if ( xPos < minViewX() ) { -#if defined(QT_CHECK_RANGE) - qWarning( "QtTableView::findRawCol: (%s) internal error: " - "xPos < minViewX() && goOutsideView " - "not supported. (%d,%d)", - name( "unnamed" ), xPos, xOffs ); -#endif - return -1; - } - if ( cellW ) { // uniform cell width - c = (xPos - minViewX() + xCellDelta)/cellW; //cell offs from left - if ( cellMaxX ) - *cellMaxX = (c + 1)*cellW + minViewX() - xCellDelta - 1; - if ( cellMinX ) - *cellMinX = c*cellW + minViewX() - xCellDelta; - c += xCellOffs; // absolute cell index - } else { // variable cell width - QtTableView *tw = (QtTableView *)this; - c = xCellOffs; - int w = minViewX() - xCellDelta; //##arnt3 - int oldW = w; - Q_ASSERT( c < nCols ); - while ( c < nCols ) { - oldW = w; - w += tw->cellWidth( c ); // Start of next cell - if ( xPos < w ) - break; - c++; - } - if ( cellMaxX ) - *cellMaxX = w - 1; - if ( cellMinX ) - *cellMinX = oldW; - } - } - return c; -} - - -/*! - Returns the index of the row at position \a yPos, where \a yPos is in - \e widget coordinates. Returns -1 if \a yPos is outside the valid - range. - - \sa findCol(), rowYPos() -*/ - -int QtTableView::findRow( int yPos ) const -{ - int cellMaxY; - int row = findRawRow( yPos, &cellMaxY ); - if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) - row = - 1; // cell cut by bottom margin - if ( row >= nRows ) - row = -1; - return row; -} - - -/*! - Returns the index of the column at position \a xPos, where \a xPos is - in \e widget coordinates. Returns -1 if \a xPos is outside the valid - range. - - \sa findRow(), colXPos() -*/ - -int QtTableView::findCol( int xPos ) const -{ - int cellMaxX; - int col = findRawCol( xPos, &cellMaxX ); - if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) - col = - 1; // cell cut by right margin - if ( col >= nCols ) - col = -1; - return col; -} - - -/*! - Computes the position in the widget of row \a row. - - Returns TRUE and stores the result in \a *yPos (in \e widget - coordinates) if the row is visible. Returns FALSE and does not modify - \a *yPos if \a row is invisible or invalid. - - \sa colXPos(), findRow() -*/ - -bool QtTableView::rowYPos( int row, int *yPos ) const -{ - int y; - if ( row >= yCellOffs ) { - if ( cellH ) { - int lastVisible = lastRowVisible(); - if ( row > lastVisible || lastVisible == -1 ) - return FALSE; - y = (row - yCellOffs)*cellH + minViewY() - yCellDelta; - } else { - //##arnt3 - y = minViewY() - yCellDelta; // y of leftmost cell in view - int r = yCellOffs; - QtTableView *tw = (QtTableView *)this; - int maxY = maxViewY(); - while ( r < row && y <= maxY ) - y += tw->cellHeight( r++ ); - if ( y > maxY ) - return FALSE; - - } - } else { - return FALSE; - } - if ( yPos ) - *yPos = y; - return TRUE; -} - - -/*! - Computes the position in the widget of column \a col. - - Returns TRUE and stores the result in \a *xPos (in \e widget - coordinates) if the column is visible. Returns FALSE and does not - modify \a *xPos if \a col is invisible or invalid. - - \sa rowYPos(), findCol() -*/ - -bool QtTableView::colXPos( int col, int *xPos ) const -{ - int x; - if ( col >= xCellOffs ) { - if ( cellW ) { - int lastVisible = lastColVisible(); - if ( col > lastVisible || lastVisible == -1 ) - return FALSE; - x = (col - xCellOffs)*cellW + minViewX() - xCellDelta; - } else { - //##arnt3 - x = minViewX() - xCellDelta; // x of uppermost cell in view - int c = xCellOffs; - QtTableView *tw = (QtTableView *)this; - int maxX = maxViewX(); - while ( c < col && x <= maxX ) - x += tw->cellWidth( c++ ); - if ( x > maxX ) - return FALSE; - } - } else { - return FALSE; - } - if ( xPos ) - *xPos = x; - return TRUE; -} - - -/*! - Moves the visible area of the table right by \a xPixels and - down by \a yPixels pixels. Both may be negative. - - \warning You might find that QScrollView offers a higher-level of - functionality than using QtTableView and this function. - - This function is \e not the same as QWidget::scroll(); in particular, - the signs of \a xPixels and \a yPixels have the reverse semantics. - - \sa setXOffset(), setYOffset(), setOffset(), setTopCell(), - setLeftCell() -*/ - -void QtTableView::scroll( int xPixels, int yPixels ) -{ - QWidget::scroll( -xPixels, -yPixels, contentsRect() ); -} - - -/*! - Returns the leftmost pixel of the table view in \e view - coordinates. This excludes the frame and any header. - - \sa maxViewY(), viewWidth(), contentsRect() -*/ - -int QtTableView::minViewX() const -{ - return frameWidth(); -} - - -/*! - Returns the top pixel of the table view in \e view - coordinates. This excludes the frame and any header. - - \sa maxViewX(), viewHeight(), contentsRect() -*/ - -int QtTableView::minViewY() const -{ - return frameWidth(); -} - - -/*! - Returns the rightmost pixel of the table view in \e view - coordinates. This excludes the frame and any scroll bar, but - includes blank pixels to the right of the visible table data. - - \sa maxViewY(), viewWidth(), contentsRect() -*/ - -int QtTableView::maxViewX() const -{ - return width() - 1 - frameWidth() - - (tFlags & Tbl_vScrollBar ? VSBEXT - : 0); -} - - -/*! - Returns the bottom pixel of the table view in \e view - coordinates. This excludes the frame and any scroll bar, but - includes blank pixels below the visible table data. - - \sa maxViewX(), viewHeight(), contentsRect() -*/ - -int QtTableView::maxViewY() const -{ - return height() - 1 - frameWidth() - - (tFlags & Tbl_hScrollBar ? HSBEXT - : 0); -} - - -/*! - Returns the width of the table view, as such, in \e view - coordinates. This does not include any header, scroll bar or frame, - but it does include background pixels to the right of the table data. - - \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect() -*/ - -int QtTableView::viewWidth() const -{ - return maxViewX() - minViewX() + 1; -} - - -/*! - Returns the height of the table view, as such, in \e view - coordinates. This does not include any header, scroll bar or frame, - but it does include background pixels below the table data. - - \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect() -*/ - -int QtTableView::viewHeight() const -{ - return maxViewY() - minViewY() + 1; -} - - -void QtTableView::doAutoScrollBars() -{ - int viewW = width() - frameWidth() - minViewX(); - int viewH = height() - frameWidth() - minViewY(); - bool vScrollOn = testTableFlags(Tbl_vScrollBar); - bool hScrollOn = testTableFlags(Tbl_hScrollBar); - int w = 0; - int h = 0; - int i; - - if ( testTableFlags(Tbl_autoHScrollBar) ) { - if ( cellW ) { - w = cellW*nCols; - } else { - i = 0; - while ( i < nCols && w <= viewW ) - w += cellWidth( i++ ); - } - if ( w > viewW ) - hScrollOn = TRUE; - else - hScrollOn = FALSE; - } - - if ( testTableFlags(Tbl_autoVScrollBar) ) { - if ( cellH ) { - h = cellH*nRows; - } else { - i = 0; - while ( i < nRows && h <= viewH ) - h += cellHeight( i++ ); - } - - if ( h > viewH ) - vScrollOn = TRUE; - else - vScrollOn = FALSE; - } - - if ( testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn ) - if ( w > viewW - VSBEXT ) - hScrollOn = TRUE; - - if ( testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn ) - if ( h > viewH - HSBEXT ) - vScrollOn = TRUE; - - setHorScrollBar( hScrollOn, FALSE ); - setVerScrollBar( vScrollOn, FALSE ); - updateFrameSize(); -} - - -/*! - \fn void QtTableView::updateScrollBars() - - Updates the scroll bars' contents and presence to match the table's - state. Generally, you should not need to call this. - - \sa setTableFlags() -*/ - -/*! - Updates the scroll bars' contents and presence to match the table's - state \c or \a f. - - \sa setTableFlags() -*/ - -void QtTableView::updateScrollBars( uint f ) -{ - sbDirty = sbDirty | f; - if ( inSbUpdate ) - return; - inSbUpdate = TRUE; - - if ( testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) || - testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange) ) - // if range change and auto - doAutoScrollBars(); // turn scroll bars on/off if needed - - if ( !autoUpdate() ) { - inSbUpdate = FALSE; - return; - } - if ( yOffset() > 0 && testTableFlags( Tbl_autoVScrollBar ) && - !testTableFlags( Tbl_vScrollBar ) ) { - setYOffset( 0 ); - } - if ( xOffset() > 0 && testTableFlags( Tbl_autoHScrollBar ) && - !testTableFlags( Tbl_hScrollBar ) ) { - setXOffset( 0 ); - } - if ( !isVisible() ) { - inSbUpdate = FALSE; - return; - } - - if ( testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0 ) { - if ( sbDirty & horGeometry ) - hScrollBar->setGeometry( 0,height() - HSBEXT, - viewWidth() + frameWidth()*2, - HSBEXT); - - if ( sbDirty & horSteps ) { - if ( cellW ) - hScrollBar->setSteps( QMIN(cellW,viewWidth()/2), viewWidth() ); - else - hScrollBar->setSteps( 16, viewWidth() ); - } - - if ( sbDirty & horRange ) - hScrollBar->setRange( 0, maxXOffset() ); - - if ( sbDirty & horValue ) - hScrollBar->setValue( xOffs ); - - // show scrollbar only when it has a sane geometry - if ( !hScrollBar->isVisible() ) - hScrollBar->show(); - } - - if ( testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0 ) { - if ( sbDirty & verGeometry ) - vScrollBar->setGeometry( width() - VSBEXT, 0, - VSBEXT, - viewHeight() + frameWidth()*2 ); - - if ( sbDirty & verSteps ) { - if ( cellH ) - vScrollBar->setSteps( QMIN(cellH,viewHeight()/2), viewHeight() ); - else - vScrollBar->setSteps( 16, viewHeight() ); // fttb! ### - } - - if ( sbDirty & verRange ) - vScrollBar->setRange( 0, maxYOffset() ); - - if ( sbDirty & verValue ) - vScrollBar->setValue( yOffs ); - - // show scrollbar only when it has a sane geometry - if ( !vScrollBar->isVisible() ) - vScrollBar->show(); - } - if ( coveringCornerSquare && - ( (sbDirty & verGeometry ) || (sbDirty & horGeometry)) ) - cornerSquare->move( maxViewX() + frameWidth() + 1, - maxViewY() + frameWidth() + 1 ); - - sbDirty = 0; - inSbUpdate = FALSE; -} - - -void QtTableView::updateFrameSize() -{ - int rw = width() - ( testTableFlags(Tbl_vScrollBar) ? - VSBEXT : 0 ); - int rh = height() - ( testTableFlags(Tbl_hScrollBar) ? - HSBEXT : 0 ); - if ( rw < 0 ) - rw = 0; - if ( rh < 0 ) - rh = 0; - - if ( autoUpdate() ) { - int fh = frameRect().height(); - int fw = frameRect().width(); - setFrameRect( QRect(0,0,rw,rh) ); - - if ( rw != fw ) - update( QMIN(fw,rw) - frameWidth() - 2, 0, frameWidth()+4, rh ); - if ( rh != fh ) - update( 0, QMIN(fh,rh) - frameWidth() - 2, rw, frameWidth()+4 ); - } -} - - -/*! - Returns the maximum horizontal offset within the table of the - view's left edge in \e table coordinates. - - This is used mainly to set the horizontal scroll bar's range. - - \sa maxColOffset(), maxYOffset(), totalWidth() -*/ - -int QtTableView::maxXOffset() -{ - int tw = totalWidth(); - int maxOffs; - if ( testTableFlags(Tbl_scrollLastHCell) ) { - if ( nCols != 1) - maxOffs = tw - ( cellW ? cellW : cellWidth( nCols - 1 ) ); - else - maxOffs = tw - viewWidth(); - } else { - if ( testTableFlags(Tbl_snapToHGrid) ) { - if ( cellW ) { - maxOffs = tw - (viewWidth()/cellW)*cellW; - } else { - int goal = tw - viewWidth(); - int pos = tw; - int nextCol = nCols - 1; - int nextCellWidth = cellWidth( nextCol ); - while( nextCol > 0 && pos > goal + nextCellWidth ) { - pos -= nextCellWidth; - nextCellWidth = cellWidth( --nextCol ); - } - if ( goal + nextCellWidth == pos ) - maxOffs = goal; - else if ( goal < pos ) - maxOffs = pos; - else - maxOffs = 0; - } - } else { - maxOffs = tw - viewWidth(); - } - } - return maxOffs > 0 ? maxOffs : 0; -} - - -/*! - Returns the maximum vertical offset within the table of the - view's top edge in \e table coordinates. - - This is used mainly to set the vertical scroll bar's range. - - \sa maxRowOffset(), maxXOffset(), totalHeight() -*/ - -int QtTableView::maxYOffset() -{ - int th = totalHeight(); - int maxOffs; - if ( testTableFlags(Tbl_scrollLastVCell) ) { - if ( nRows != 1) - maxOffs = th - ( cellH ? cellH : cellHeight( nRows - 1 ) ); - else - maxOffs = th - viewHeight(); - } else { - if ( testTableFlags(Tbl_snapToVGrid) ) { - if ( cellH ) { - maxOffs = th - (viewHeight()/cellH)*cellH; - } else { - int goal = th - viewHeight(); - int pos = th; - int nextRow = nRows - 1; - int nextCellHeight = cellHeight( nextRow ); - while( nextRow > 0 && pos > goal + nextCellHeight ) { - pos -= nextCellHeight; - nextCellHeight = cellHeight( --nextRow ); - } - if ( goal + nextCellHeight == pos ) - maxOffs = goal; - else if ( goal < pos ) - maxOffs = pos; - else - maxOffs = 0; - } - } else { - maxOffs = th - viewHeight(); - } - } - return maxOffs > 0 ? maxOffs : 0; -} - - -/*! - Returns the index of the last column, which may be at the left edge - of the view. - - Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag, - this may or may not be the last column. - - \sa maxXOffset(), maxRowOffset() -*/ - -int QtTableView::maxColOffset() -{ - int mx = maxXOffset(); - if ( cellW ) - return mx/cellW; - else { - int xcd=0, col=0; - while ( col < nCols && mx > (xcd=cellWidth(col)) ) { - mx -= xcd; - col++; - } - return col; - } -} - - -/*! - Returns the index of the last row, which may be at the top edge of - the view. - - Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag, - this may or may not be the last row. - - \sa maxYOffset(), maxColOffset() -*/ - -int QtTableView::maxRowOffset() -{ - int my = maxYOffset(); - if ( cellH ) - return my/cellH; - else { - int ycd=0, row=0; - while ( row < nRows && my > (ycd=cellHeight(row)) ) { - my -= ycd; - row++; - } - return row; - } -} - - -void QtTableView::showOrHideScrollBars() -{ - if ( !autoUpdate() ) - return; - if ( vScrollBar ) { - if ( testTableFlags(Tbl_vScrollBar) ) { - if ( !vScrollBar->isVisible() ) - sbDirty = sbDirty | verMask; - } else { - if ( vScrollBar->isVisible() ) - vScrollBar->hide(); - } - } - if ( hScrollBar ) { - if ( testTableFlags(Tbl_hScrollBar) ) { - if ( !hScrollBar->isVisible() ) - sbDirty = sbDirty | horMask; - } else { - if ( hScrollBar->isVisible() ) - hScrollBar->hide(); - } - } - if ( cornerSquare ) { - if ( testTableFlags(Tbl_hScrollBar) && - testTableFlags(Tbl_vScrollBar) ) { - if ( !cornerSquare->isVisible() ) - cornerSquare->show(); - } else { - if ( cornerSquare->isVisible() ) - cornerSquare->hide(); - } - } -} - - -/*! - Updates the scroll bars and internal state. - - Call this function when the table view's total size is changed; - typically because the result of cellHeight() or cellWidth() have changed. - - This function does not repaint the widget. -*/ - -void QtTableView::updateTableSize() -{ - bool updateOn = autoUpdate(); - setAutoUpdate( FALSE ); - int xofs = xOffset(); - xOffs++; //so that setOffset will not return immediately - setOffset(xofs,yOffset(),FALSE); //to calculate internal state correctly - setAutoUpdate(updateOn); - - updateScrollBars( horSteps | horRange | - verSteps | verRange ); - showOrHideScrollBars(); -} - - -#endif -#endif diff --git a/win/Qt/tileedit.cpp b/win/Qt/tileedit.cpp deleted file mode 100644 index cbde51867..000000000 --- a/win/Qt/tileedit.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* NetHack 3.6 tileedit.cpp $NHDT-Date: 1524684508 2018/04/25 19:28:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ */ -/* Copyright (c) Warwick Allison, 1999. */ -/* NetHack may be freely redistributed. See license for details. */ -/* -Build this little utility program if you want to use it to edit the tile -files. Move tileedit.cpp and tileedit.h to ../../util, add the -3 lines below to the Makefile there and "make tileedit". - -tileedit: tileedit.cpp $(TEXT_IO) - moc -o tileedit.moc tileedit.h - $(CC) -o tileedit -I../include -I$(QTDIR)/include -L$(QTDIR)/lib tileedit.cpp $(TEXT_IO) -lqt -*/ - - -#include "tileedit.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern "C" { -#include "config.h" -#include "tile.h" -extern const char *FDECL(tilename, (int, int)); -} - -#define TILES_ACROSS 20 - -TilePickerTab::TilePickerTab(const char* basename, int i, QWidget* parent) : - QWidget(parent) -{ - id = i; - filename = basename; - filename += ".txt"; - num = 0; - int index = 0; - for (int real=0; real<2; real++) { - if ( real ) { - image.create( TILES_ACROSS*TILE_X, - ((num+TILES_ACROSS-1)/TILES_ACROSS)*TILE_Y, 32 ); - } - if ( !fopen_text_file(filename.latin1(), RDTMODE) ) { - // XXX handle better - exit(1); - } - pixel p[TILE_Y][TILE_X]; - while ( read_text_tile(p) ) { - if ( real ) { - int ox = (index%TILES_ACROSS)*TILE_X; - int oy = (index/TILES_ACROSS)*TILE_Y; - for ( int y=0; yx()-e->x()%TILE_X; - int oy = e->y()-e->y()%TILE_Y; - QImage subimage = image.copy(ox,oy,TILE_X,TILE_Y); - if ( e->button() == RightButton ) { - setCurrent(subimage); - } else { - last_pick = ox/TILE_X + oy/TILE_Y*TILES_ACROSS; - } - emit pick(subimage); - emit pickName(tilename(id, last_pick)); -} - -void TilePickerTab::setCurrent(const QImage& i) -{ - int ox = last_pick%TILES_ACROSS * TILE_X; - int oy = last_pick/TILES_ACROSS * TILE_Y; - bitBlt( &image, ox, oy, &i ); - bitBlt( &pixmap, ox, oy, &i ); - repaint( ox, oy, TILE_X, TILE_Y, FALSE ); -} - -QSize TilePickerTab::sizeHint() const -{ - return pixmap.size(); -} - -void TilePickerTab::paintEvent( QPaintEvent* ) -{ - QPainter p(this); - p.drawPixmap(0,0,pixmap); -} - -static struct { - const char* name; - TilePickerTab* tab; -} tileset[] = { - { "monsters", 0 }, - { "objects", 0 }, - { "other", 0 }, - { 0 } -}; - -TilePicker::TilePicker(QWidget* parent) : - QTabWidget(parent) -{ - for (int i=0; tileset[i].name; i++) { - QString tabname = tileset[i].name; - tabname[0] = tabname[0].upper(); - tileset[i].tab = new TilePickerTab(tileset[i].name,i+1,this); - addTab( tileset[i].tab, tabname ); - connect( tileset[i].tab, SIGNAL(pick(const QImage&)), - this, SIGNAL(pick(const QImage&)) ); - connect( tileset[i].tab, SIGNAL(pickName(const QString&)), - this, SIGNAL(pickName(const QString&)) ); - } -} - -void TilePicker::setCurrent(const QImage& i) -{ - ((TilePickerTab*)currentPage())->setCurrent(i); -} - -void TilePicker::save() -{ - for (int i=0; tileset[i].tab; i++) { - tileset[i].tab->save(); - } -} - -TrivialTileEditor::TrivialTileEditor( QWidget* parent ) : - QWidget(parent) -{ -} - -const QImage& TrivialTileEditor::image() const -{ - return img; -} - -void TrivialTileEditor::setColor( QRgb rgb ) -{ - pen = rgb; - for (penpixel = 0; - penpixelrect(); - QPoint tl = imagePoint(r.topLeft()); - QPoint br = imagePoint(r.bottomRight()); - r = QRect(tl,br).intersect(img.rect()); - QPainter painter(this); - for (int y=r.top(); y<=r.bottom(); y++) { - for (int x=r.left(); x<=r.right(); x++) { - paintPoint(painter,QPoint(x,y)); - } - } -} - -void TrivialTileEditor::paintPoint(QPainter& painter, QPoint p) -{ - QPoint p1 = screenPoint(p); - QPoint p2 = screenPoint(p+QPoint(1,1)); - QColor c = img.color(img.scanLine(p.y())[p.x()]); - painter.fillRect(QRect(p1,p2-QPoint(1,1)), c); -} - -void TrivialTileEditor::mousePressEvent(QMouseEvent* e) -{ - QPoint p = imagePoint(e->pos()); - if ( !img.rect().contains(p) ) - return; - uchar& pixel = img.scanLine(p.y())[p.x()]; - if ( e->button() == LeftButton ) { - pixel = penpixel; - QPainter painter(this); - paintPoint(painter,p); - } else if ( e->button() == RightButton ) { - emit pick( img.color(pixel) ); - } else if ( e->button() == MidButton ) { - QPainter painter(this); - if ( pixel != penpixel ) - fill(painter,p,pixel); - } -} - -void TrivialTileEditor::fill(QPainter& painter, QPoint p, uchar from) -{ - if ( img.rect().contains(p) ) { - uchar& pixel = img.scanLine(p.y())[p.x()]; - if ( pixel == from ) { - pixel = penpixel; - paintPoint(painter,p); - fill(painter, p+QPoint(-1,0), from); - fill(painter, p+QPoint(+1,0), from); - fill(painter, p+QPoint(0,-1), from); - fill(painter, p+QPoint(0,+1), from); - } - } -} - -void TrivialTileEditor::mouseReleaseEvent(QMouseEvent* e) -{ - emit edited(image()); -} - -void TrivialTileEditor::mouseMoveEvent(QMouseEvent* e) -{ - QPoint p = imagePoint(e->pos()); - if ( !img.rect().contains(p) ) - return; - uchar& pixel = img.scanLine(p.y())[p.x()]; - pixel = penpixel; - QPainter painter(this); - paintPoint(painter,p); -} - -QPoint TrivialTileEditor::imagePoint(QPoint p) const -{ - return QPoint(p.x()*TILE_X/width(), p.y()*TILE_Y/height()); -} - -QPoint TrivialTileEditor::screenPoint(QPoint p) const -{ - return QPoint(p.x()*width()/TILE_X, p.y()*height()/TILE_Y); -} - -QSizePolicy TrivialTileEditor::sizePolicy() const -{ - return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding, TRUE ); -} - -QSize TrivialTileEditor::sizeHint() const -{ - return sizeForWidth(-1); -} - -QSize TrivialTileEditor::sizeForWidth(int w) const -{ - if ( w < 0 ) - return QSize(TILE_X*32,TILE_Y*32); - else - return QSize(w,w*TILE_Y/TILE_X); -} - - -TilePalette::TilePalette( QWidget* parent ) : - QWidget(parent) -{ - num = 0; - rgb = 0; -} - -TilePalette::~TilePalette() -{ - delete rgb; -} - -void TilePalette::setFromImage( const QImage& i ) -{ - num = i.numColors(); - rgb = new QRgb[num]; - memcpy(rgb, i.colorTable(), num*sizeof(QRgb)); - repaint(FALSE); -} - -void TilePalette::setColor(QRgb c) -{ - for (int i=0; ix()*num/width(); - emit pick(rgb[c]); -} - -TileEditor::TileEditor(QWidget* parent) : - QVBox(parent), - editor(this), - palette(this) -{ - connect( &palette, SIGNAL(pick(QRgb)), - &editor, SLOT(setColor(QRgb)) ); - connect( &editor, SIGNAL(pick(QRgb)), - &palette, SLOT(setColor(QRgb)) ); - connect( &editor, SIGNAL(edited(const QImage&)), - this, SIGNAL(edited(const QImage&)) ); -} - -void TileEditor::edit(const QImage& i) -{ - editor.setImage(i); - palette.setFromImage(i); -} - -const QImage& TileEditor::image() const -{ - return editor.image(); -} - -class Main : public QMainWindow { -public: - Main() : - central(this), - editor(¢ral), - picker(¢ral) - { - QPopupMenu* file = new QPopupMenu(menuBar()); - file->insertItem("&Save", &picker, SLOT(save()), CTRL+Key_S); - file->insertSeparator(); - file->insertItem("&Exit", qApp, SLOT(quit()), CTRL+Key_Q); - menuBar()->insertItem("&File", file); - - connect( &picker, SIGNAL(pick(const QImage&)), - &editor, SLOT(edit(const QImage&)) ); - connect( &picker, SIGNAL(pickName(const QString&)), - statusBar(), SLOT(message(const QString&)) ); - connect( &editor, SIGNAL(edited(const QImage&)), - &picker, SLOT(setCurrent(const QImage&)) ); - - setCentralWidget(¢ral); - } - -private: - QHBox central; - TileEditor editor; - TilePicker picker; -}; - -main(int argc, char** argv) -{ - QApplication app(argc,argv); - Main m; - app.setMainWidget(&m); - m.show(); - return app.exec(); -} - -#include "tileedit.moc" diff --git a/win/Qt/tileedit.h b/win/Qt/tileedit.h deleted file mode 100644 index 550e65e03..000000000 --- a/win/Qt/tileedit.h +++ /dev/null @@ -1,135 +0,0 @@ -/* NetHack 3.6 tileedit.h $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (c) Warwick Allison, 1999. */ -/* NetHack may be freely redistributed. See license for details. */ -#ifndef QNHTILEEDIT_H -#define QNHTILEEDIT_H - -#include -#include -#include -#include - -class TilePickerTab : public QWidget -{ - Q_OBJECT - public: - TilePickerTab(const char *basename, int id, QWidget *parent); - - bool save(); - int numTiles(); - - signals: - void pick(const QImage &); - void pickName(const QString &); - - public slots: - void setCurrent(const QImage &); - - protected: - void paintEvent(QPaintEvent *); - QSize sizeHint() const; - void mousePressEvent(QMouseEvent *); - - private: - QString filename; - int id; - int last_pick; - int num; - QPixmap pixmap; - QImage image; -}; - -class TilePicker : public QTabWidget -{ - Q_OBJECT - public: - TilePicker(QWidget *parent); - - void setTile(int tilenum, const QImage &); - - signals: - void pick(const QImage &); - void pickName(const QString &); - - public slots: - void setCurrent(const QImage &); - void save(); -}; - -class TrivialTileEditor : public QWidget -{ - Q_OBJECT - public: - TrivialTileEditor(QWidget *parent); - const QImage &image() const; - - signals: - void edited(const QImage &); - void pick(QRgb); - - public slots: - void setColor(QRgb); - void setImage(const QImage &); - - protected: - void paintEvent(QPaintEvent *); - void mousePressEvent(QMouseEvent *); - void mouseReleaseEvent(QMouseEvent *); - void mouseMoveEvent(QMouseEvent *); - QSize sizeHint() const; - QSize sizeForWidth(int) const; - QSizePolicy sizePolicy() const; - - private: - void fill(QPainter &painter, QPoint p, uchar from); - QImage img; - QColor pen; - int penpixel; - void paintPoint(QPainter &painter, QPoint p); - QPoint screenPoint(QPoint) const; - QPoint imagePoint(QPoint) const; -}; - -class TilePalette : public QWidget -{ - Q_OBJECT - public: - TilePalette(QWidget *parent); - ~TilePalette(); - void setFromImage(const QImage &); - - protected: - void paintEvent(QPaintEvent *); - void mousePressEvent(QMouseEvent *); - QSize sizeHint() const; - QSizePolicy sizePolicy() const; - signals: - void pick(QRgb); - public slots: - void setColor(QRgb); - - private: - int num; - QRgb *rgb; -}; - -class TileEditor : public QVBox -{ - Q_OBJECT - public: - TileEditor(QWidget *parent); - - const QImage &image() const; - - signals: - void edited(const QImage &); - - public slots: - void edit(const QImage &); - - private: - TrivialTileEditor editor; - TilePalette palette; -}; - -#endif diff --git a/win/Qt4/.gitattributes b/win/Qt4/.gitattributes deleted file mode 100644 index 68792d904..000000000 --- a/win/Qt4/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* NH_filestag=(file%s_for_the_Qt_4_widget_library_-_X11,_Windows,_Mac_OS_X) diff --git a/win/Qt4/.gitignore b/win/Qt4/.gitignore deleted file mode 100644 index e978b1085..000000000 --- a/win/Qt4/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.moc diff --git a/win/Qt4/qt4bind.cpp b/win/Qt4/qt4bind.cpp deleted file mode 100644 index 5395787ec..000000000 --- a/win/Qt4/qt4bind.cpp +++ /dev/null @@ -1,831 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4bind.cpp -- bindings between the Qt 4 interface and the main code - -extern "C" { -#include "hack.h" -} -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#include -#if QT_VERSION >= 0x050000 -#include -#include -#else -#include -#endif -#include "qt4bind.h" -#include "qt4click.h" -#ifdef TIMED_DELAY -#include "qt4delay.h" -#endif -#include "qt4xcmd.h" -#include "qt4key.h" -#include "qt4map.h" -#include "qt4menu.h" -#include "qt4msg.h" -#include "qt4plsel.h" -#include "qt4svsel.h" -#include "qt4set.h" -#include "qt4stat.h" -#include "qt4streq.h" -#include "qt4yndlg.h" -#include "qt4str.h" - -extern "C" { -#include "dlb.h" -} - -// temporary -extern int qt_compact_mode; -// end temporary - -namespace nethack_qt4 { - -// XXX Should be from Options -// -// XXX Hmm. Tricky part is that perhaps some macros should only be active -// XXX when a key is about to be gotten. For example, the user could -// XXX define "-" to do "E-yyyyyyyy\r", but would still need "-" for -// XXX other purposes. Maybe just too bad. -// -static struct key_macro_rec { - int key; - int state; - const char* macro; -} key_macro[]={ - { Qt::Key_F1, 0, "n100." }, // Rest (x100) - { Qt::Key_F2, 0, "n20s" }, // Search (x20) - { Qt::Key_Tab, 0, "\001" }, - { 0, 0, 0 } -}; - -NetHackQtBind::NetHackQtBind(int& argc, char** argv) : -#ifdef KDE - KApplication(argc,argv) -#elif defined(QWS) // not quite the right condition - QPEApplication(argc,argv) -#else - QApplication(argc,argv) -#endif -{ - QPixmap pm("nhsplash.xpm"); - if ( iflags.wc_splash_screen && !pm.isNull() ) { - splash = new QFrame(NULL, - Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint ); - QVBoxLayout *vb = new QVBoxLayout(splash); - QLabel *lsplash = new QLabel(splash); - vb->addWidget(lsplash); - lsplash->setAlignment(Qt::AlignCenter); - lsplash->setPixmap(pm); - QLabel* capt = new QLabel("Loading...",splash); - vb->addWidget(capt); - capt->setAlignment(Qt::AlignCenter); - if ( !pm.isNull() ) { - lsplash->setFixedSize(pm.size()); - lsplash->setMask(pm); - } - splash->move((QApplication::desktop()->width()-pm.width())/2, - (QApplication::desktop()->height()-pm.height())/2); - //splash->setGeometry(0,0,100,100); - if ( qt_compact_mode ) { - splash->showMaximized(); - } else { - splash->setFrameStyle(QFrame::WinPanel|QFrame::Raised); - splash->setLineWidth(10); - splash->adjustSize(); - splash->show(); - } - - // force content refresh outside event loop - splash->repaint(); - lsplash->repaint(); - capt->repaint(); - qApp->flush(); - - } else { - splash = 0; - } - main = new NetHackQtMainWindow(keybuffer); - connect(qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit())); - qt_settings=new NetHackQtSettings(main->width(),main->height()); - msgs_strings = new QStringList(); - msgs_initd = false; - msgs_saved = false; -} - -void NetHackQtBind::qt_init_nhwindows(int* argc, char** argv) -{ - iflags.menu_tab_sep = true; - -#ifdef UNIX -// Userid control -// -// Michael Hohmuth ... -// -// As the game runs setuid games, it must seteuid(getuid()) before -// calling XOpenDisplay(), and reset the euid afterwards. -// Otherwise, it can't read the $HOME/.Xauthority file and whines about -// not being able to open the X display (if a magic-cookie -// authorization mechanism is being used). - - uid_t gamesuid=geteuid(); - seteuid(getuid()); -#endif - - QApplication::setColorSpec(ManyColor); - instance=new NetHackQtBind(*argc,argv); - -#ifdef UNIX - seteuid(gamesuid); -#endif - -#ifdef _WS_WIN_ - // This nethack engine feature should be moved into windowport API - nt_kbhit = NetHackQtBind::qt_kbhit; -#endif -} - -int NetHackQtBind::qt_kbhit() -{ - return !keybuffer.Empty(); -} - - -static bool have_asked = false; - -void NetHackQtBind::qt_player_selection() -{ - if ( !have_asked ) - qt_askname(); -} - -void NetHackQtBind::qt_askname() -{ - have_asked = true; - - // We do it all here, and nothing in askname - - char** saved = get_saved_games(); - int ch = -1; - if ( saved && *saved ) { - if ( splash ) splash->hide(); - NetHackQtSavedGameSelector sgsel((const char**)saved); - ch = sgsel.choose(); - if ( ch >= 0 ) - str_copy(plname, saved[ch], SIZE(plname)); - } - free_saved_games(saved); - - switch (ch) { - case -1: - if ( splash ) splash->hide(); - if (NetHackQtPlayerSelector(keybuffer).Choose()) - return; - case -2: - break; - default: - return; - } - - // Quit - clearlocks(); - qt_exit_nhwindows(0); - nh_terminate(0); -} - -void NetHackQtBind::qt_get_nh_event() -{ -} - -#if defined(QWS) -// Kludge to access lastWindowClosed() signal. -class TApp : public QApplication { -public: - TApp(int& c, char**v) : QApplication(c,v) {} - void lwc() { emit lastWindowClosed(); } -}; -#endif - -void NetHackQtBind::qt_exit_nhwindows(const char *) -{ -#if defined(QWS) - // Avoids bug in SHARP SL5500 - ((TApp*)qApp)->lwc(); - qApp->quit(); -#endif - - delete instance; // ie. qApp -} - -void NetHackQtBind::qt_suspend_nhwindows(const char *) -{ -} - -void NetHackQtBind::qt_resume_nhwindows() -{ -} - -static QVector id_to_window; - -winid NetHackQtBind::qt_create_nhwindow(int type) -{ - winid id; - for (id = 0; id < (winid) id_to_window.size(); id++) { - if ( !id_to_window[(int)id] ) - break; - } - if ( id == (winid) id_to_window.size() ) - id_to_window.resize(id+1); - - NetHackQtWindow* window=0; - - switch (type) { - case NHW_MAP: { - NetHackQtMapWindow2* w=new NetHackQtMapWindow2(clickbuffer); - main->AddMapWindow(w); - window=w; - } break; case NHW_MESSAGE: { - NetHackQtMessageWindow* w=new NetHackQtMessageWindow; - main->AddMessageWindow(w); - window=w; - } break; case NHW_STATUS: { - NetHackQtStatusWindow* w=new NetHackQtStatusWindow; - main->AddStatusWindow(w); - window=w; - } break; case NHW_MENU: - window=new NetHackQtMenuOrTextWindow(mainWidget()); - break; case NHW_TEXT: - window=new NetHackQtTextWindow(mainWidget()); - } - - window->nhid = id; - - // Note: use of isHidden does not work with Qt 2.1 - if ( splash -#if QT_VERSION >= 300 - && !main->isHidden() -#else - && main->isVisible() -#endif - ) - { - delete splash; - splash = 0; - } - - id_to_window[(int)id] = window; - return id; -} - -void NetHackQtBind::qt_clear_nhwindow(winid wid) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->Clear(); -} - -void NetHackQtBind::qt_display_nhwindow(winid wid, BOOLEAN_P block) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->Display(block); -} - -void NetHackQtBind::qt_destroy_nhwindow(winid wid) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - main->RemoveWindow(window); - if (window->Destroy()) - delete window; - id_to_window[(int)wid] = 0; -} - -void NetHackQtBind::qt_curs(winid wid, int x, int y) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->CursorTo(x,y); -} - -void NetHackQtBind::qt_putstr(winid wid, int attr, const char *text) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->PutStr(attr,QString::fromLatin1(text)); -} - -void NetHackQtBind::qt_putstr(winid wid, int attr, const std::string& text) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->PutStr(attr,QString::fromLatin1(text.c_str(), text.size())); -} - -void NetHackQtBind::qt_putstr(winid wid, int attr, const QString& text) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->PutStr(attr,text); -} - -void NetHackQtBind::qt_display_file(const char *filename, BOOLEAN_P must_exist) -{ - NetHackQtTextWindow* window=new NetHackQtTextWindow(mainWidget()); - bool complain = false; - - { - dlb *f; - char buf[BUFSZ]; - char *cr; - - window->Clear(); - f = dlb_fopen(filename, "r"); - if (!f) { - complain = must_exist; - } else { - while (dlb_fgets(buf, BUFSZ, f)) { - if ((cr = strchr(buf, '\n')) != 0) *cr = 0; -#ifdef MSDOS - if ((cr = strchr(buf, '\r')) != 0) *cr = 0; -#endif - window->PutStr(ATR_NONE, tabexpand(buf)); - } - window->Display(false); - (void) dlb_fclose(f); - } - } - - if (complain) { - QString message; - message.sprintf("File not found: %s\n",filename); - QMessageBox::warning(NULL, "File Error", message, QMessageBox::Ignore); - } -} - -void NetHackQtBind::qt_start_menu(winid wid) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->StartMenu(); -} - -void NetHackQtBind::qt_add_menu(winid wid, int glyph, - const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr, - const char *str, BOOLEAN_P presel) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->AddMenu(glyph, identifier, ch, gch, attr, - QString::fromLatin1(str), - presel); -} - -void NetHackQtBind::qt_end_menu(winid wid, const char *prompt) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->EndMenu(prompt); -} - -int NetHackQtBind::qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - return window->SelectMenu(how,menu_list); -} - -void NetHackQtBind::qt_update_inventory() -{ - if (main) - main->updateInventory(); - /* doesn't work yet - if (program_state.something_worth_saving && iflags.perm_invent) - display_inventory(NULL, false); - */ -} - -void NetHackQtBind::qt_mark_synch() -{ -} - -void NetHackQtBind::qt_wait_synch() -{ -} - -void NetHackQtBind::qt_cliparound(int x, int y) -{ - // XXXNH - winid should be a parameter! - qt_cliparound_window(WIN_MAP,x,y); -} - -void NetHackQtBind::qt_cliparound_window(winid wid, int x, int y) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->ClipAround(x,y); -} -void NetHackQtBind::qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph,int bkglyph) -{ - /* TODO: bkglyph */ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->PrintGlyph(x,y,glyph); -} -//void NetHackQtBind::qt_print_glyph_compose(winid wid,xchar x,xchar y,int glyph1, int glyph2) -//{ - //NetHackQtWindow* window=id_to_window[(int)wid]; - //window->PrintGlyphCompose(x,y,glyph1,glyph2); -//} - -void NetHackQtBind::qt_raw_print(const char *str) -{ - puts(str); -} - -void NetHackQtBind::qt_raw_print_bold(const char *str) -{ - puts(str); -} - -int NetHackQtBind::qt_nhgetch() -{ - if (main) - main->fadeHighlighting(); - - // Process events until a key arrives. - // - while (keybuffer.Empty()) { - int exc = qApp->exec(); - /* - * On OSX (possibly elsewhere), this prevents an infinite - * loop repeatedly issuing the complaint: -QCoreApplication::exec: The event loop is already running - * to stderr if you syncronously start nethack from a terminal - * then switch focus back to that terminal and type ^C. - * SIGINT -> done1() -> done2() -> yn_function("Really quit?") - * in the core asks for another keystroke. - * - * However, it still issues one such complaint, and whatever - * prompt wanted a response ("Really quit?") is shown in the - * message window but is auto-answered with ESC. - */ - if (exc == -1) - keybuffer.Put('\033'); - } - - return keybuffer.GetAscii(); -} - -int NetHackQtBind::qt_nh_poskey(int *x, int *y, int *mod) -{ - if (main) - main->fadeHighlighting(); - - // Process events until a key or map-click arrives. - // - while (keybuffer.Empty() && clickbuffer.Empty()) { - int exc = qApp->exec(); - // [see comment above in qt_nhgetch()] - if (exc == -1) - keybuffer.Put('\033'); - } - if (!keybuffer.Empty()) { - return keybuffer.GetAscii(); - } else { - *x=clickbuffer.NextX(); - *y=clickbuffer.NextY(); - *mod=clickbuffer.NextMod(); - clickbuffer.Get(); - return 0; - } -} - -void NetHackQtBind::qt_nhbell() -{ - QApplication::beep(); -} - -int NetHackQtBind::qt_doprev_message() -{ - // Don't need it - uses scrollbar - // XXX but could make this a shortcut - return 0; -} - -char NetHackQtBind::qt_yn_function(const char *question_, const char *choices, CHAR_P def) -{ - QString question(QString::fromLatin1(question_)); - QString message; - char yn_esc_map='\033'; - - if (choices) { - // anything beyond is hidden> - QString choicebuf = choices; - size_t cb = choicebuf.indexOf('\033'); - choicebuf = choicebuf.mid(0U, cb); - message = QString("%1 [%2] ").arg(question, choicebuf); - if (def) message += QString("(%1) ").arg(QChar(def)); - // escape maps to 'q' or 'n' or default, in that order - yn_esc_map = (strchr(choices, 'q') ? 'q' : - (strchr(choices, 'n') ? 'n' : def)); - } else { - message = question; - } - - if (qt_settings->ynInMessages() && WIN_MESSAGE!=WIN_ERR) { - // Similar to X11 windowport `slow' feature. - - int result = -1; - -#ifdef USE_POPUPS - if (choices) { - if (!strcmp(choices,"ynq")) - result = QMessageBox::information (NetHackQtBind::mainWidget(),"NetHack",question,"&Yes","&No","&Quit",0,2); - else if (!strcmp(choices,"yn")) - result = QMessageBox::information(NetHackQtBind::mainWidget(),"NetHack",question,"&Yes", "&No",0,1); - else if (!strcmp(choices, "rl")) - result = QMessageBox::information(NetHackQtBind::mainWidget(),"NetHack",question,"&Right", "&Left",0,1); - - if (result >= 0 && result < strlen(choices)) { - char yn_resp = choices[result]; - message += QString(" %1").arg(yn_resp); - result = yn_resp; - } - } -#endif - - NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); - - while (result < 0) { - char ch=NetHackQtBind::qt_nhgetch(); - if (ch=='\033') { - result=yn_esc_map; - } else if (choices && !strchr(choices,ch)) { - if (def && (ch==' ' || ch=='\r' || ch=='\n')) { - result=def; - } else { - NetHackQtBind::qt_nhbell(); - // and try again... - } - } else { - result=ch; - } - } - - NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); - - return result; - } else { - NetHackQtYnDialog dialog(mainWidget(),question,choices,def); - char ret = dialog.Exec(); - if (!(ret == '\0' || ret == '\033') && choices) - message += QString(" %1").arg(ret); - else if (def) - message += QString(" %1").arg(def); - NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); - - return ret; - } -} - -void NetHackQtBind::qt_getlin(const char *prompt, char *line) -{ - NetHackQtStringRequestor requestor(mainWidget(),prompt); - if (!requestor.Get(line)) { - line[0]=0; - } -} - -int NetHackQtBind::qt_get_ext_cmd() -{ - NetHackQtExtCmdRequestor requestor(mainWidget()); - return requestor.get(); -} - -void NetHackQtBind::qt_number_pad(int) -{ - // Ignore. -} - -void NetHackQtBind::qt_delay_output() -{ -#ifdef TIMED_DELAY - NetHackQtDelay delay(50); - delay.wait(); -#endif -} - -void NetHackQtBind::qt_start_screen() -{ - // Ignore. -} - -void NetHackQtBind::qt_end_screen() -{ - // Ignore. -} - -void NetHackQtBind::qt_outrip(winid wid, int how, time_t when) -{ - NetHackQtWindow* window=id_to_window[(int)wid]; - window->UseRIP(how, when); -} - -char * NetHackQtBind::qt_getmsghistory(BOOLEAN_P init) -{ - NetHackQtMessageWindow* window = main->GetMessageWindow(); - if (window) - return (char *)window->GetStr(init); - return NULL; -} - -void NetHackQtBind::qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring) -{ - NetHackQtMessageWindow* window = main->GetMessageWindow(); - if (!window) - return; - - if (is_restoring && !msgs_initd) { - /* we're restoring history from the previous session, but new - messages have already been issued this session */ - int i = 0; - const char *str; - - while ((str = window->GetStr((i == 0)))) { - msgs_strings->append(str); - i++; - } - msgs_initd = true; - msgs_saved = (i > 0); - window->ClearMessages(); - } - - if (msg) { - //raw_printf("msg='%s'", msg); - window->PutStr(ATR_NONE, QString::fromLatin1(msg)); -#ifdef DUMPLOG - dumplogmsg(msg); -#endif - } else if (msgs_saved) { - /* restore strings */ - int i; - for (i = 0; i < msgs_strings->size(); i++) { - window->PutStr(ATR_NONE, msgs_strings->at((i))); -#ifdef DUMPLOG - dumplogmsg(msgs_strings->at(i).toLatin1().constData()); -#endif - } - delete msgs_strings; - msgs_initd = false; - } -} - -bool NetHackQtBind::notify(QObject *receiver, QEvent *event) -{ - // Ignore Alt-key navigation to menubar, it's annoying when you - // use Alt-Direction to move around. - if ( main && event->type()==QEvent::KeyRelease && main==receiver - && ((QKeyEvent*)event)->key() == Qt::Key_Alt ) - return true; - - bool result=QApplication::notify(receiver,event); - if (event->type()==QEvent::KeyPress) { - QKeyEvent* key_event=(QKeyEvent*)event; - - if (!key_event->isAccepted()) { - const int k=key_event->key(); - bool macro=false; - for (int i=0; !macro && key_macro[i].key; i++) { - if (key_macro[i].key==k - && ((key_macro[i].state&key_event->modifiers())==key_macro[i].state)) - { - keybuffer.Put(key_macro[i].macro); - macro=true; - } - } - QString key=key_event->text(); - QChar ch = !key.isEmpty() ? key.at(0) : 0; - if (ch > 128) ch = 0; - if ( ch == 0 && (key_event->modifiers() & Qt::ControlModifier) ) { - // On Mac, ascii control codes are not sent, force them. - if ( k>=Qt::Key_A && k<=Qt::Key_Z ) - ch = k - Qt::Key_A + 1; - } - if (!macro && ch != 0) { - bool alt = (key_event->modifiers()&Qt::AltModifier) || - (k >= Qt::Key_0 && k <= Qt::Key_9 && (key_event->modifiers()&Qt::ControlModifier)); - keybuffer.Put(key_event->key(),ch.cell() + (alt ? 128 : 0), - key_event->modifiers()); - key_event->accept(); - result=true; - } - - if (ch != 0 || macro) { - qApp->exit(); - } - } - } - return result; -} - -NetHackQtBind* NetHackQtBind::instance=0; -NetHackQtKeyBuffer NetHackQtBind::keybuffer; -NetHackQtClickBuffer NetHackQtBind::clickbuffer; -NetHackQtMainWindow* NetHackQtBind::main=0; -QFrame* NetHackQtBind::splash=0; -QStringList *NetHackQtBind::msgs_strings; -boolean NetHackQtBind::msgs_saved = false; -boolean NetHackQtBind::msgs_initd = false; - -static void Qt_positionbar(char *) {} - -} // namespace nethack_qt4 - -struct window_procs Qt_procs = { - "Qt", - WC_COLOR | WC_HILITE_PET - | WC_ASCII_MAP | WC_TILED_MAP - | WC_FONT_MAP | WC_TILE_FILE | WC_TILE_WIDTH | WC_TILE_HEIGHT - | WC_PLAYER_SELECTION | WC_SPLASH_SCREEN, - 0L, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ - nethack_qt4::NetHackQtBind::qt_init_nhwindows, - nethack_qt4::NetHackQtBind::qt_player_selection, - nethack_qt4::NetHackQtBind::qt_askname, - nethack_qt4::NetHackQtBind::qt_get_nh_event, - nethack_qt4::NetHackQtBind::qt_exit_nhwindows, - nethack_qt4::NetHackQtBind::qt_suspend_nhwindows, - nethack_qt4::NetHackQtBind::qt_resume_nhwindows, - nethack_qt4::NetHackQtBind::qt_create_nhwindow, - nethack_qt4::NetHackQtBind::qt_clear_nhwindow, - nethack_qt4::NetHackQtBind::qt_display_nhwindow, - nethack_qt4::NetHackQtBind::qt_destroy_nhwindow, - nethack_qt4::NetHackQtBind::qt_curs, - nethack_qt4::NetHackQtBind::qt_putstr, - genl_putmixed, - nethack_qt4::NetHackQtBind::qt_display_file, - nethack_qt4::NetHackQtBind::qt_start_menu, - nethack_qt4::NetHackQtBind::qt_add_menu, - nethack_qt4::NetHackQtBind::qt_end_menu, - nethack_qt4::NetHackQtBind::qt_select_menu, - genl_message_menu, /* no need for X-specific handling */ - nethack_qt4::NetHackQtBind::qt_update_inventory, - nethack_qt4::NetHackQtBind::qt_mark_synch, - nethack_qt4::NetHackQtBind::qt_wait_synch, -#ifdef CLIPPING - nethack_qt4::NetHackQtBind::qt_cliparound, -#endif -#ifdef POSITIONBAR - nethack_qt4::Qt_positionbar, -#endif - nethack_qt4::NetHackQtBind::qt_print_glyph, - //NetHackQtBind::qt_print_glyph_compose, - nethack_qt4::NetHackQtBind::qt_raw_print, - nethack_qt4::NetHackQtBind::qt_raw_print_bold, - nethack_qt4::NetHackQtBind::qt_nhgetch, - nethack_qt4::NetHackQtBind::qt_nh_poskey, - nethack_qt4::NetHackQtBind::qt_nhbell, - nethack_qt4::NetHackQtBind::qt_doprev_message, - nethack_qt4::NetHackQtBind::qt_yn_function, - nethack_qt4::NetHackQtBind::qt_getlin, - nethack_qt4::NetHackQtBind::qt_get_ext_cmd, - nethack_qt4::NetHackQtBind::qt_number_pad, - nethack_qt4::NetHackQtBind::qt_delay_output, -#ifdef CHANGE_COLOR /* only a Mac option currently */ - donull, - donull, - donull, - donull, -#endif - /* other defs that really should go away (they're tty specific) */ - nethack_qt4::NetHackQtBind::qt_start_screen, - nethack_qt4::NetHackQtBind::qt_end_screen, -#ifdef GRAPHIC_TOMBSTONE - nethack_qt4::NetHackQtBind::qt_outrip, -#else - genl_outrip, -#endif - genl_preference_update, - - nethack_qt4::NetHackQtBind::qt_getmsghistory, - nethack_qt4::NetHackQtBind::qt_putmsghistory, - genl_status_init, - genl_status_finish, genl_status_enablefield, -#ifdef STATUS_HILITES - genl_status_update, -#else - genl_status_update, -#endif - genl_can_suspend_yes, -}; - -#ifndef WIN32 -extern "C" void play_usersound(const char* filename, int volume) -{ -#ifdef USER_SOUNDS -#ifndef QT_NO_SOUND - QSound::play(filename); -#endif -#endif -} -#endif diff --git a/win/Qt4/qt4bind.h b/win/Qt4/qt4bind.h deleted file mode 100644 index 820341cae..000000000 --- a/win/Qt4/qt4bind.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4bind.h -- bindings between the Qt 4 interface and the main code - -#ifndef QT4BIND_H -#define QT4BIND_H - -#include "qt4main.h" - -namespace nethack_qt4 { - -class NetHackQtClickBuffer; - -#ifdef KDE -#define NetHackQtBindBase KApplication -#elif defined(QWS) -#define NetHackQtBindBase QPEApplication -#else -#define NetHackQtBindBase QApplication -#endif - -class NetHackQtBind : NetHackQtBindBase { -private: - // Single-instance preservation... - NetHackQtBind(int& argc, char** argv); - - static NetHackQtBind* instance; - - static NetHackQtKeyBuffer keybuffer; - static NetHackQtClickBuffer clickbuffer; - - static QFrame* splash; - static NetHackQtMainWindow* main; - -public: - static void qt_init_nhwindows(int* argc, char** argv); - static void qt_player_selection(); - static void qt_askname(); - static void qt_get_nh_event(); - static void qt_exit_nhwindows(const char *); - static void qt_suspend_nhwindows(const char *); - static void qt_resume_nhwindows(); - static winid qt_create_nhwindow(int type); - static void qt_clear_nhwindow(winid wid); - static void qt_display_nhwindow(winid wid, BOOLEAN_P block); - static void qt_destroy_nhwindow(winid wid); - static void qt_curs(winid wid, int x, int y); - static void qt_putstr(winid wid, int attr, const char *text); - static void qt_putstr(winid wid, int attr, const std::string& text); - static void qt_putstr(winid wid, int attr, const QString& text); - static void qt_display_file(const char *filename, BOOLEAN_P must_exist); - static void qt_start_menu(winid wid); - static void qt_add_menu(winid wid, int glyph, - const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr, - const char *str, BOOLEAN_P presel); - static void qt_end_menu(winid wid, const char *prompt); - static int qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list); - static void qt_update_inventory(); - static void qt_mark_synch(); - static void qt_wait_synch(); - - static void qt_cliparound(int x, int y); - static void qt_cliparound_window(winid wid, int x, int y); - static void qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph,int bkglyph); - static void qt_raw_print(const char *str); - static void qt_raw_print_bold(const char *str); - static int qt_nhgetch(); - static int qt_nh_poskey(int *x, int *y, int *mod); - static void qt_nhbell(); - static int qt_doprev_message(); - static char qt_yn_function(const char *question, const char *choices, CHAR_P def); - static void qt_getlin(const char *prompt, char *line); - static int qt_get_ext_cmd(); - static void qt_number_pad(int); - static void qt_delay_output(); - static void qt_start_screen(); - static void qt_end_screen(); - - static char *qt_getmsghistory(BOOLEAN_P init); - static void qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring); - - static void qt_outrip(winid wid, int how, time_t when); - static int qt_kbhit(); - - static QWidget *mainWidget() { return main; } - -private: - virtual bool notify(QObject *receiver, QEvent *event); - - static QStringList *msgs_strings; - static boolean msgs_saved; - static boolean msgs_initd; -}; - -} // namespace nethack_qt4 - -#endif diff --git a/win/Qt4/qt4clust.cpp b/win/Qt4/qt4clust.cpp deleted file mode 100644 index 1cd080c11..000000000 --- a/win/Qt4/qt4clust.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* SCCS Id: @(#)qt_clust.cpp 3.4 1999/11/19 */ -/* Copyright (c) Warwick Allison, 1999. */ -/* NetHack may be freely redistributed. See license for details. */ -#include "qt4clust.h" - -static void include(QRect& r, const QRect& rect) -{ - if (rect.left()r.right()) { - r.setRight(rect.right()); - } - if (rect.top()r.bottom()) { - r.setBottom(rect.bottom()); - } -} - -/* -A Clusterizer groups rectangles (QRects) into non-overlapping rectangles -by a merging heuristic. -*/ -Clusterizer::Clusterizer(int maxclusters) : - cluster(new QRect[maxclusters]), - count(0), - max(maxclusters) -{ } - -Clusterizer::~Clusterizer() -{ - delete [] cluster; -} - -void Clusterizer::clear() -{ - count=0; -} - -void Clusterizer::add(int x, int y) -{ - add(QRect(x,y,1,1)); -} - -void Clusterizer::add(int x, int y, int w, int h) -{ - add(QRect(x,y,w,h)); -} - -void Clusterizer::add(const QRect& rect) -{ - QRect biggerrect(rect.x()-1,rect.y()-1,rect.width()+2,rect.height()+2); - - //assert(rect.width()>0 && rect.height()>0); - - int cursor; - - for (cursor=0; cursor=0) { - include(cluster[cheapest],rect); - return; - } - - if (count < max) { - cluster[count++]=rect; - return; - } - - // Do cheapest of: - // add to closest cluster - // do cheapest cluster merge, add to new cluster - - lowestcost=9999999; - cheapest=-1; - for (cursor=0; cursor=0) { - include(cluster[cheapestmerge1],cluster[cheapestmerge2]); - cluster[cheapestmerge2]=cluster[count--]; - } else { - // if (!cheapest) debugRectangles(rect); - include(cluster[cheapest],rect); - } - - // NB: clusters do not intersect (or intersection will - // overwrite). This is a result of the above algorithm, - // given the assumption that (x,y) are ordered topleft - // to bottomright. -} - -const QRect& Clusterizer::operator[](int i) -{ - return cluster[i]; -} diff --git a/win/Qt4/qt4glyph.cpp b/win/Qt4/qt4glyph.cpp deleted file mode 100644 index 942f3a1ab..000000000 --- a/win/Qt4/qt4glyph.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4glyph.cpp -- class to manage the glyphs in a tile set - -extern "C" { -#include "hack.h" -} -#include "tile2x11.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4glyph.h" -#include "qt4set.h" -#include "qt4str.h" - -extern short glyph2tile[]; // from tile.c - -namespace nethack_qt4 { - -static int tilefile_tile_W=16; -static int tilefile_tile_H=16; - -// Debian uses a separate PIXMAPDIR -#ifndef PIXMAPDIR -# ifdef HACKDIR -# define PIXMAPDIR HACKDIR -# else -# define PIXMAPDIR "." -# endif -#endif - -NetHackQtGlyphs::NetHackQtGlyphs() -{ - const char* tile_file = PIXMAPDIR "/nhtiles.bmp"; - if ( iflags.wc_tile_file ) - tile_file = iflags.wc_tile_file; - - if (!img.load(tile_file)) { - tile_file = PIXMAPDIR "/x11tiles"; - if (!img.load(tile_file)) { - QString msg; - msg.sprintf("Cannot load x11tiles or nhtiles.bmp"); - QMessageBox::warning(0, "IO Error", msg); - } else { - tiles_per_row = TILES_PER_ROW; - if (img.width()%tiles_per_row) { - impossible("Tile file \"%s\" has %d columns, not multiple of row count (%d)", - tile_file, img.width(), tiles_per_row); - } - } - } else { - tiles_per_row = 40; - } - - if ( iflags.wc_tile_width ) - tilefile_tile_W = iflags.wc_tile_width; - else - tilefile_tile_W = img.width() / tiles_per_row; - if ( iflags.wc_tile_height ) - tilefile_tile_H = iflags.wc_tile_height; - else - tilefile_tile_H = tilefile_tile_W; - - setSize(tilefile_tile_W, tilefile_tile_H); -} - -void NetHackQtGlyphs::drawGlyph(QPainter& painter, int glyph, int x, int y) -{ - int tile = glyph2tile[glyph]; - int px = (tile%tiles_per_row)*width(); - int py = tile/tiles_per_row*height(); - - painter.drawPixmap( - x, - y, - pm, - px,py, - width(),height() - ); -} -void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, int cellx, int celly) -{ - drawGlyph(painter,glyph,cellx*width(),celly*height()); -} -QPixmap NetHackQtGlyphs::glyph(int glyph) -{ - int tile = glyph2tile[glyph]; - int px = (tile%tiles_per_row)*tilefile_tile_W; - int py = tile/tiles_per_row*tilefile_tile_H; - - return QPixmap::fromImage(img.copy(px, py, tilefile_tile_W, tilefile_tile_H)); -} -void NetHackQtGlyphs::setSize(int w, int h) -{ - if ( size == QSize(w,h) ) - return; - - bool was1 = size == pm1.size(); - size = QSize(w,h); - if (!w || !h) - return; // Still not decided - - if ( size == pm1.size() ) { - pm = pm1; - return; - } - if ( size == pm2.size() ) { - pm = pm2; - return; - } - - if (w==tilefile_tile_W && h==tilefile_tile_H) { - pm.convertFromImage(img); - } else { - QApplication::setOverrideCursor( Qt::WaitCursor ); - QImage scaled = img.scaled( - w*img.width()/tilefile_tile_W, - h*img.height()/tilefile_tile_H, - Qt::IgnoreAspectRatio, - Qt::FastTransformation - ); - pm.convertFromImage(scaled,Qt::ThresholdDither|Qt::PreferDither); - QApplication::restoreOverrideCursor(); - } - (was1 ? pm2 : pm1) = pm; -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4glyph.h b/win/Qt4/qt4glyph.h deleted file mode 100644 index 12fd915fd..000000000 --- a/win/Qt4/qt4glyph.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4glyph.h -- class to manage the glyphs in a tile set - -#ifndef QT4GLYPH_H -#define QT4GLYPH_H - -namespace nethack_qt4 { - -class NetHackQtGlyphs { -public: - NetHackQtGlyphs(); - - int width() const { return size.width(); } - int height() const { return size.height(); } - void toggleSize(); - void setSize(int w, int h); - - void drawGlyph(QPainter&, int glyph, int pixelx, int pixely); - void drawCell(QPainter&, int glyph, int cellx, int celly); - QPixmap glyph(int glyph); - -private: - QImage img; - QPixmap pm,pm1, pm2; - QSize size; - int tiles_per_row; -}; - -} // namespace nethack_qt4 - -#endif diff --git a/win/Qt4/qt4icon.cpp b/win/Qt4/qt4icon.cpp deleted file mode 100644 index 0876cb59d..000000000 --- a/win/Qt4/qt4icon.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4icon.cpp -- a labelled icon - -#include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4icon.h" - -namespace nethack_qt4 { - -NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l) : - QWidget(parent), - low_is_good(false), - prev_value(-123), - turn_count(-1), - label(new QLabel(l,this)), - icon(0) -{ - initHighlight(); -} - -NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l, const QPixmap& i) : - QWidget(parent), - low_is_good(false), - prev_value(-123), - turn_count(-1), - label(new QLabel(l,this)), - icon(new QLabel(this)) -{ - setIcon(i); - initHighlight(); -} - -void NetHackQtLabelledIcon::initHighlight() -{ - hl_good = "QLabel { background-color : green; color : white }"; - hl_bad = "QLabel { background-color : red ; color : white }"; -} - -void NetHackQtLabelledIcon::setLabel(const QString& t, bool lower) -{ - if (!label) { - label=new QLabel(this); - label->setFont(font()); - resizeEvent(0); - } - if (label->text() != t) { - label->setText(t); - highlight(lower==low_is_good ? hl_good : hl_bad); - } -} - -void NetHackQtLabelledIcon::setLabel(const QString& t, long v, long cv, const QString& tail) -{ - QString buf; - if (v==NoNum) { - buf = ""; - } else { - buf.sprintf("%ld", v); - } - setLabel(t + buf + tail, cv < prev_value); - prev_value=cv; -} - -void NetHackQtLabelledIcon::setLabel(const QString& t, long v, const QString& tail) -{ - setLabel(t,v,v,tail); -} - -void NetHackQtLabelledIcon::setIcon(const QPixmap& i) -{ - if (icon) icon->setPixmap(i); - else { icon=new QLabel(this); icon->setPixmap(i); resizeEvent(0); } - icon->resize(i.width(),i.height()); -} - -void NetHackQtLabelledIcon::setFont(const QFont& f) -{ - QWidget::setFont(f); - if (label) label->setFont(f); -} - -void NetHackQtLabelledIcon::show() -{ -#if QT_VERSION >= 300 - if (isHidden()) -#else - if (!isVisible()) -#endif - highlight(hl_bad); - QWidget::show(); -} - -QSize NetHackQtLabelledIcon::sizeHint() const -{ - QSize iconsize, textsize; - - if (label && !icon) return label->sizeHint(); - if (icon && !label) return icon->sizeHint(); - if (!label && !icon) return QWidget::sizeHint(); - - iconsize = icon->sizeHint(); - textsize = label->sizeHint(); - return QSize( - std::max(iconsize.width(), textsize.width()), - iconsize.height() + textsize.height()); -} - -QSize NetHackQtLabelledIcon::minimumSizeHint() const -{ - QSize iconsize, textsize; - - if (label && !icon) return label->minimumSizeHint(); - if (icon && !label) return icon->minimumSizeHint(); - if (!label && !icon) return QWidget::minimumSizeHint(); - - iconsize = icon->minimumSizeHint(); - textsize = label->minimumSizeHint(); - return QSize( - std::max(iconsize.width(), textsize.width()), - iconsize.height() + textsize.height()); -} - -void NetHackQtLabelledIcon::highlightWhenChanging() -{ - turn_count=0; -} - -void NetHackQtLabelledIcon::lowIsGood() -{ - low_is_good=true; -} - -void NetHackQtLabelledIcon::dissipateHighlight() -{ - if (turn_count>0) { - turn_count--; - if (!turn_count) - unhighlight(); - } -} - -void NetHackQtLabelledIcon::highlight(const QString& hl) -{ - if (label) { // Surely it is?! - if (turn_count>=0) { - label->setStyleSheet(hl); - turn_count=4; - // `4' includes this turn, so dissipates after - // 3 more keypresses. - } else { - label->setStyleSheet(""); - } - } -} - -void NetHackQtLabelledIcon::unhighlight() -{ - if (label) { // Surely it is?! - label->setStyleSheet(""); - } -} - -void NetHackQtLabelledIcon::resizeEvent(QResizeEvent*) -{ - setAlignments(); - - //int labw=label ? label->fontMetrics().width(label->text()) : 0; - int labh=label ? label->fontMetrics().height() : 0; - int icoh=icon ? icon->height() : 0; - int h=icoh+labh; - int icoy=(h>height() ? height()-labh-icoh : height()/2-h/2); - int laby=icoy+icoh; - if (icon) { - icon->setGeometry(0,icoy,width(),icoh); - } - if (label) { - label->setGeometry(0,laby,width(),labh); - } -} - -void NetHackQtLabelledIcon::setAlignments() -{ - if (label) label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter); - if (icon) icon->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter); -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4icon.h b/win/Qt4/qt4icon.h deleted file mode 100644 index bdaf8183c..000000000 --- a/win/Qt4/qt4icon.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4icon.cpp -- a labelled icon - -#ifndef QT4ICON_H -#define QT4ICON_H - -namespace nethack_qt4 { - -class NetHackQtLabelledIcon : public QWidget { -public: - NetHackQtLabelledIcon(QWidget* parent, const char* label); - NetHackQtLabelledIcon(QWidget* parent, const char* label, const QPixmap& icon); - - enum { NoNum=-99999 }; - void setLabel(const QString&, bool lower=true); // a string - void setLabel(const QString&, long, const QString& tail=""); // a number - void setLabel(const QString&, long show_value, long comparative_value, const QString& tail=""); - void setIcon(const QPixmap&); - virtual void setFont(const QFont&); - - void highlightWhenChanging(); - void lowIsGood(); - void dissipateHighlight(); - - virtual void show(); - virtual QSize sizeHint() const; - virtual QSize minimumSizeHint() const; - -protected: - void resizeEvent(QResizeEvent*); - -private: - void initHighlight(); - void setAlignments(); - void highlight(const QString& highlight); - void unhighlight(); - - bool low_is_good; - int prev_value; - int turn_count; /* last time the value changed */ - QString hl_good; - QString hl_bad; - - QLabel* label; - QLabel* icon; -}; - -} // namespace nethack_qt4 - -#endif diff --git a/win/Qt4/qt4inv.cpp b/win/Qt4/qt4inv.cpp deleted file mode 100644 index 6d1a201b4..000000000 --- a/win/Qt4/qt4inv.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4inv.cpp -- inventory usage window -// This is at the top center of the main window - -extern "C" { -#include "hack.h" -} -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4inv.h" -#include "qt4glyph.h" -#include "qt4set.h" - -namespace nethack_qt4 { - -NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget* parent) : - QWidget(parent) -{ - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); -} - -void NetHackQtInvUsageWindow::drawWorn(QPainter& painter, obj* nhobj, int x, int y, bool canbe) -{ - short int glyph; - if (nhobj) - glyph=obj_to_glyph(nhobj, rn2_on_display_rng); - else if (canbe) - glyph=cmap_to_glyph(S_room); - else - glyph=cmap_to_glyph(S_stone); - - qt_settings->glyphs().drawCell(painter,glyph,x,y); -} - -void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*) -{ - // 012 - // - //0 WhB - //1 s"w - //2 gCg - //3 =A= - //4 T - //5 S - - QPainter painter; - painter.begin(this); - - // Blanks - drawWorn(painter,0,0,4,false); - drawWorn(painter,0,0,5,false); - drawWorn(painter,0,2,4,false); - drawWorn(painter,0,2,5,false); - - drawWorn(painter,uarm,1,3); // Armour - drawWorn(painter,uarmc,1,2); // Cloak - drawWorn(painter,uarmh,1,0); // Helmet - drawWorn(painter,uarms,0,1); // Shield - drawWorn(painter,uarmg,0,2); // Gloves - repeated - drawWorn(painter,uarmg,2,2); // Gloves - repeated - drawWorn(painter,uarmf,1,5); // Shoes (feet) - drawWorn(painter,uarmu,1,4); // Undershirt - drawWorn(painter,uleft,0,3); // RingL - drawWorn(painter,uright,2,3); // RingR - - drawWorn(painter,uwep,2,1); // Weapon - drawWorn(painter,uswapwep,0,0); // Secondary weapon - drawWorn(painter,uamul,1,1); // Amulet - drawWorn(painter,ublindf,2,0); // Blindfold - - painter.end(); -} - -QSize NetHackQtInvUsageWindow::sizeHint(void) const -{ - if (qt_settings) { - return QSize(qt_settings->glyphs().width()*3, - qt_settings->glyphs().height()*6); - } else { - return QWidget::sizeHint(); - } -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4inv.h b/win/Qt4/qt4inv.h deleted file mode 100644 index 51cdd4d0b..000000000 --- a/win/Qt4/qt4inv.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4inv.h -- inventory usage window -// This is at the top center of the main window - -#ifndef QT4INV_H -#define QT4INV_H - -namespace nethack_qt4 { - -class NetHackQtInvUsageWindow : public QWidget { -public: - NetHackQtInvUsageWindow(QWidget* parent); - virtual void paintEvent(QPaintEvent*); - virtual QSize sizeHint(void) const; - -private: - void drawWorn(QPainter& painter, obj*, int x, int y, bool canbe=true); -}; - -} // namespace nethack_qt4 - -#endif diff --git a/win/Qt4/qt4key.cpp b/win/Qt4/qt4key.cpp deleted file mode 100644 index ff16616fe..000000000 --- a/win/Qt4/qt4key.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4key.cpp -- a key buffer - -#include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#include "qt4key.h" - -namespace nethack_qt4 { - -NetHackQtKeyBuffer::NetHackQtKeyBuffer() : - in(0), out(0) -{ -} - -bool NetHackQtKeyBuffer::Empty() const { return in==out; } -bool NetHackQtKeyBuffer::Full() const { return (in+1)%maxkey==out; } - -void NetHackQtKeyBuffer::Put(int k, int a, int state) -{ - if ( Full() ) return; // Safety - key[in]=k; - ascii[in]=a; - in=(in+1)%maxkey; -} - -void NetHackQtKeyBuffer::Put(char a) -{ - Put(0,a,0); -} - -void NetHackQtKeyBuffer::Put(const char* str) -{ - while (*str) Put(*str++); -} - -int NetHackQtKeyBuffer::GetKey() -{ - if ( Empty() ) return 0; - int r=TopKey(); - out=(out+1)%maxkey; - return r; -} - -int NetHackQtKeyBuffer::GetAscii() -{ - if ( Empty() ) return 0; // Safety - int r=TopAscii(); - out=(out+1)%maxkey; - return r; -} - -Qt::KeyboardModifiers NetHackQtKeyBuffer::GetState() -{ - if ( Empty() ) return 0; - Qt::KeyboardModifiers r=TopState(); - out=(out+1)%maxkey; - return r; -} - -int NetHackQtKeyBuffer::TopKey() const -{ - if ( Empty() ) return 0; - return key[out]; -} - -int NetHackQtKeyBuffer::TopAscii() const -{ - if ( Empty() ) return 0; - return ascii[out]; -} - -Qt::KeyboardModifiers NetHackQtKeyBuffer::TopState() const -{ - if ( Empty() ) return 0; - return state[out]; -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4main.cpp b/win/Qt4/qt4main.cpp deleted file mode 100644 index 0a28399bb..000000000 --- a/win/Qt4/qt4main.cpp +++ /dev/null @@ -1,1076 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4main.cpp -- the main window - -extern "C" { -#include "hack.h" -} -#include "patchlevel.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4main.h" -#include "qt4main.moc" -#include "qt4bind.h" -#include "qt4glyph.h" -#include "qt4inv.h" -#include "qt4key.h" -#include "qt4map.h" -#include "qt4msg.h" -#include "qt4set.h" -#include "qt4stat.h" -#include "qt4str.h" - -#ifndef KDE -#include "qt4kde0.moc" -#endif - -// temporary -extern char *qt_tilewidth; -extern char *qt_tileheight; -extern int qt_compact_mode; -// end temporary - -namespace nethack_qt4 { - -// temporary -void centerOnMain( QWidget* w ); -// end temporary - -/* XPM */ -static const char * nh_icon[] = { -"40 40 6 1", -" s None c none", -". c #ffffff", -"X c #dadab6", -"o c #6c91b6", -"O c #476c6c", -"+ c #000000", -" ", -" ", -" ", -" . .X..XX.XX X ", -" .. .....X.XXXXXX XX ", -" ... ....X..XX.XXXXX XXX ", -" .. ..........X.XXXXXXXXXXX XX ", -" .... ........X..XX.XXXXXXXXX XXXX ", -" .... ..........X.XXXXXXXXXXX XXXX ", -" ooOOO..ooooooOooOOoOOOOOOOXX+++OO++ ", -" ooOOO..ooooooooOoOOOOOOOOOXX+++OO++ ", -" ....O..ooooooOooOOoOOOOOOOXX+XXXX++ ", -" ....O..ooooooooOoOOOOOOOOOXX+XXXX++ ", -" ..OOO..ooooooOooOOoOOOOOOOXX+++XX++ ", -" ++++..ooooooooOoOOOOOOOOOXX+++ +++ ", -" +++..ooooooOooOOoOOOOOOOXX+++ + ", -" ++..ooooooooOoOOOOOOOOOXX+++ ", -" ..ooooooOooOOoOOOOOOOXX+++ ", -" ..ooooooooOoOOOOOOOOOXX+++ ", -" ..ooooooOooOOoOOOOOOOXX+++ ", -" ..ooooooooOoOOOOOOOOOXX+++ ", -" ..oooooOooOOoOOOOOOXX+++ ", -" ..oooooooOoOOOOOOOOXX+++ ", -" ..ooooOooOOoOOOOOXX+++ ", -" ..ooooooOoOOOOOOOXX++++ ", -" ..o..oooOooOOoOOOOXX+XX+++ ", -" ...o..oooooOoOOOOOXX++XXX++ ", -" ....OO..ooOooOOoOOXX+++XXXX++ ", -" ...oo..+..oooOoOOOXX++XXooXXX++ ", -" ...ooo..++..OooOOoXX+++XXooOXXX+ ", -" ..oooOOXX+++....XXXX++++XXOOoOOXX+ ", -" ..oooOOXX+++ ...XXX+++++XXOOooOXX++ ", -" ..oooOXXX+++ ..XX+++ +XXOOooOXX++ ", -" .....XXX++++ XXXXXXX++ ", -" ....XX++++ XXXXXXX+ ", -" ...XX+++ XXXXX++ ", -" ", -" ", -" ", -" "}; -/* XPM */ -static const char * nh_icon_small[] = { -/* width height ncolors chars_per_pixel */ -"16 16 16 1", -/* colors */ -" c #587070", -". c #D1D5C9", -"X c #8B8C84", -"o c #2A2A28", -"O c #9AABA9", -"+ c #6A8FB2", -"@ c #C4CAC4", -"# c #B6BEB6", -"$ c None", -"% c #54564E", -"& c #476C6C", -"* c #ADB2AB", -"= c #ABABA2", -"- c #5E8295", -"; c #8B988F", -": c #E8EAE7", -/* pixels */ -"$$$$$$$$$$$$$$$$", -"$$$.$#::.#==*$$$", -"$.*:::::....#*=$", -"$@#:..@#*==#;XX;", -"$@O:+++- &&; X%X", -"$#%.+++- &&;% oX", -"$$o.++-- &&;%%X$", -"$$$:++-- &&;%%$$", -"$$$.O++- &&=o $$", -"$$$=:++- & XoX$$", -"$$*:@O-- ;%Xo$$", -"$*:O#$+--;oOOX $", -"$:+ =o::=oo=-;%X", -"$::.%o$*;X;##@%$", -"$$@# ;$$$$$=*;X$", -"$$$$$$$$$$$$$$$$" -}; - -#if 0 // RLC -/* XPM */ -static const char * map_xpm[] = { -"12 13 4 1", -". c None", -" c #000000000000", -"X c #0000B6DAFFFF", -"o c #69A69248B6DA", -" .", -" XXXXX ooo ", -" XoooX o ", -" XoooX o o ", -" XoooX ooo ", -" XXoXX o ", -" oooooXXX ", -" oo o oooX ", -" o XooX ", -" oooo XooX ", -" o o XXXX ", -" ", -". "}; -/* XPM */ -static const char * msg_xpm[] = { -"12 13 4 1", -". c None", -" c #FFFFFFFFFFFF", -"X c #69A69248B6DA", -"o c #000000000000", -" .", -" XXX XXX X o", -" o", -" XXXXX XX o", -" o", -" XX XXXXX o", -" o", -" XXXXXX o", -" o", -" XX XXX XX o", -" o", -" o", -".ooooooooooo"}; -/* XPM */ -static const char * stat_xpm[] = { -"12 13 5 1", -" c None", -". c #FFFF00000000", -"X c #000000000000", -"o c #FFFFFFFF0000", -"O c #69A6FFFF0000", -" ", -" ", -"... ", -"...X ", -"...X ... ", -"oooX oooX", -"oooXooo oooX", -"OOOXOOOXOOOX", -"OOOXOOOXOOOX", -"OOOXOOOXOOOX", -"OOOXOOOXOOOX", -"OOOXOOOXOOOX", -" XXXXXXXXXXX"}; -#endif -/* XPM */ -static const char * info_xpm[] = { -"12 13 4 1", -" c None", -". c #00000000FFFF", -"X c #FFFFFFFFFFFF", -"o c #000000000000", -" ... ", -" ....... ", -" ...XXX... ", -" .........o ", -"...XXXX.... ", -"....XXX....o", -"....XXX....o", -"....XXX....o", -" ...XXX...oo", -" ..XXXXX..o ", -" .......oo ", -" o...ooo ", -" ooo "}; - - -/* XPM */ -static const char * again_xpm[] = { -"12 13 2 1", -" c None", -". c #000000000000", -" .. ", -" .. ", -" ..... ", -" ....... ", -"... .. .. ", -".. .. .. ", -".. ..", -".. ..", -".. ..", -" .. .. ", -" .......... ", -" ...... ", -" "}; -/* XPM */ -static const char * kick_xpm[] = { -"12 13 3 1", -" c None", -". c #000000000000", -"X c #FFFF6DB60000", -" ", -" ", -" . . . ", -" ... . . ", -" ... . ", -" ... . ", -" ... ", -"XXX ... ", -"XXX. ... ", -"XXX. ... ", -"XXX. .. ", -" ... ", -" "}; -/* XPM */ -static const char * throw_xpm[] = { -"12 13 3 1", -" c None", -". c #FFFF6DB60000", -"X c #000000000000", -" ", -" ", -" ", -" ", -".... X ", -"....X X ", -"....X XXXXXX", -"....X X ", -" XXXX X ", -" ", -" ", -" ", -" "}; -/* XPM */ -static const char * fire_xpm[] = { -"12 13 5 1", -" c None", -". c #B6DA45140000", -"X c #FFFFB6DA9658", -"o c #000000000000", -"O c #FFFF6DB60000", -" . ", -" X. ", -" X . ", -" X .o ", -" X . o ", -" X .o o ", -"OOOOOOOOoooo", -" X .o o ", -" X . o o ", -" X .o ", -" X. o ", -" . o ", -" o "}; -/* XPM */ -static const char * get_xpm[] = { -"12 13 3 1", -" c None", -". c #000000000000", -"X c #FFFF6DB60000", -" ", -" . ", -" ... ", -" . . . ", -" . ", -" . ", -" ", -" XXXXX ", -" XXXXX. ", -" XXXXX. ", -" XXXXX. ", -" ..... ", -" "}; -/* XPM */ -static const char * drop_xpm[] = { -"12 13 3 1", -" c None", -". c #FFFF6DB60000", -"X c #000000000000", -" ", -" ..... ", -" .....X ", -" .....X ", -" .....X ", -" XXXXX ", -" ", -" X ", -" X ", -" X X X ", -" XXX ", -" X ", -" "}; -/* XPM */ -static const char * eat_xpm[] = { -"12 13 4 1", -" c None", -". c #000000000000", -"X c #FFFFB6DA9658", -"o c #FFFF6DB60000", -" .X. .. ", -" .X. .. ", -" .X. .. ", -" .X. .. ", -" ... .. ", -" .. .. ", -" .. .. ", -" oo oo ", -" oo oo ", -" oo oo ", -" oo oo ", -" oo oo ", -" oo oo "}; -/* XPM */ -static const char * rest_xpm[] = { -"12 13 2 1", -" c None", -". c #000000000000", -" ..... ", -" . ", -" . ", -" . ....", -" ..... . ", -" . ", -" ....", -" ", -" .... ", -" . ", -" . ", -" .... ", -" "}; -/* XPM */ -static const char * cast_a_xpm[] = { -"12 13 3 1", -" c None", -". c #FFFF6DB60000", -"X c #000000000000", -" . ", -" . ", -" .. ", -" .. ", -" .. . ", -" .. . ", -" ...... ", -" .. .. XX ", -" .. X X ", -" .. X X ", -" .. XXXX ", -" . X X ", -" . X X "}; -/* XPM */ -static const char * cast_b_xpm[] = { -"12 13 3 1", -" c None", -". c #FFFF6DB60000", -"X c #000000000000", -" . ", -" . ", -" .. ", -" .. ", -" .. . ", -" .. . ", -" ...... ", -" .. .. XXX ", -" .. X X ", -" .. XXX ", -" .. X X ", -" . X X ", -" . XXX "}; -/* XPM */ -static const char * cast_c_xpm[] = { -"12 13 3 1", -" c None", -". c #FFFF6DB60000", -"X c #000000000000", -" . ", -" . ", -" .. ", -" .. ", -" .. . ", -" .. . ", -" ...... ", -" .. .. XX ", -" .. X X ", -" .. X ", -" .. X ", -" . X X ", -" . XX "}; - -static QString -aboutMsg() -{ - QString msg; - msg.sprintf( - "Qt NetHack is a version of NetHack built\n" -#ifdef KDE - "using KDE and the Qt GUI toolkit.\n" -#else - "using the Qt GUI toolkit.\n" -#endif - "This is version %d.%d.%d\n\n" - "Homepage:\n http://trolls.troll.no/warwick/nethack/\n\n" -#ifdef KDE - "KDE:\n http://www.kde.org\n" -#endif - "Qt:\n http://www.troll.no", - VERSION_MAJOR, - VERSION_MINOR, - PATCHLEVEL); - return msg; -} - -class SmallToolButton : public QToolButton { -public: - SmallToolButton(const QPixmap & pm, const QString &textLabel, - const QString& grouptext, - QObject * receiver, const char* slot, - QWidget * parent) : - QToolButton(parent) - { - setIcon(QIcon(pm)); - setToolTip(textLabel); - setStatusTip(grouptext); - connect(this, SIGNAL(clicked(bool)), receiver, slot); - } - - QSize sizeHint() const - { - // get just a couple more pixels for the map - return QToolButton::sizeHint()-QSize(0,2); - } -}; - -NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : - message(0), map(0), status(0), invusage(0), - hsplitter(0), vsplitter(0), - keysink(ks), dirkey(0) -{ - QToolBar* toolbar = new QToolBar(this); - toolbar->setMovable(false); - toolbar->setFocusPolicy(Qt::NoFocus); - addToolBar(toolbar); - menubar = menuBar(); - - QCoreApplication::setOrganizationName("The NetHack DevTeam"); - QCoreApplication::setOrganizationDomain("nethack.org"); - QCoreApplication::setApplicationName("NetHack"); - - setWindowTitle("Qt NetHack"); - if ( qt_compact_mode ) - setWindowIcon(QIcon(QPixmap(nh_icon_small))); - else - setWindowIcon(QIcon(QPixmap(nh_icon))); - - QMenu* game=new QMenu; - QMenu* apparel=new QMenu; - QMenu* act1=new QMenu; - QMenu* act2 = qt_compact_mode ? new QMenu : act1; - QMenu* magic=new QMenu; - QMenu* info=new QMenu; - - QMenu *help; - -#ifdef KDE - help = kapp->getHelpMenu( true, "" ); - help->addSeparator(); -#else - help = qt_compact_mode ? info : new QMenu; -#endif - - enum { OnDesktop=1, OnHandhelds=2 }; - struct Macro { - QMenu* menu; - const char* name; - int flags; - int NDECL((*funct)); - } item[] = { - { game, 0, 3}, - { game, "Version", 3, doversion}, - { game, "Compilation", 3, doextversion}, - { game, "History", 3, dohistory}, - { game, "Redraw", 0, doredraw}, // useless - { game, "Options", 3, doset}, - { game, "Explore mode", 3, enter_explore_mode}, - { game, 0, 3}, - { game, "Save", 3, dosave}, - { game, "Quit", 3, done2}, - - { apparel, "Apparel off", 2, doddoremarm}, - { apparel, "Remove many", 1, doddoremarm}, - { apparel, 0, 3}, - { apparel, "Wield weapon", 3, dowield}, - { apparel, "Exchange weapons", 3, doswapweapon}, - { apparel, "Two weapon combat", 3, dotwoweapon}, - { apparel, "Load quiver", 3, dowieldquiver}, - { apparel, 0, 3}, - { apparel, "Wear armour", 3, dowear}, - { apparel, "Take off armour", 3, dotakeoff}, - { apparel, 0, 3}, - { apparel, "Put on non-armour", 3, doputon}, - { apparel, "Remove non-armour", 3, doremring}, - - /* { act1, "Again\tCtrl+A", "\001", 2}, - { act1, 0, 0, 3}, */ - { act1, "Apply", 3, doapply}, - { act1, "Chat", 3, dotalk}, - { act1, "Close door", 3, doclose}, - { act1, "Down", 3, dodown}, - { act1, "Drop many", 2, doddrop}, - { act1, "Drop", 2, dodrop}, - { act1, "Eat", 2, doeat}, - { act1, "Engrave", 3, doengrave}, - /* { act1, "Fight\tShift+F", "F", 3}, */ - { act1, "Fire from quiver", 2, dofire}, - { act1, "Force", 3, doforce}, - { act1, "Get", 2, dopickup}, - { act1, "Jump", 3, dojump}, - { act2, "Kick", 2, dokick}, - { act2, "Loot", 3, doloot}, - { act2, "Open door", 3, doopen}, - { act2, "Pay", 3, dopay}, - { act2, "Rest", 2, donull}, - { act2, "Ride", 3, doride}, - { act2, "Search", 3, dosearch}, - { act2, "Sit", 3, dosit}, - { act2, "Throw", 2, dothrow}, - { act2, "Untrap", 3, dountrap}, - { act2, "Up", 3, doup}, - { act2, "Wipe face", 3, dowipe}, - - { magic, "Quaff potion", 3, dodrink}, - { magic, "Read scroll/book", 3, doread}, - { magic, "Zap wand", 3, dozap}, - { magic, "Zap spell", 3, docast}, - { magic, "Dip", 3, dodip}, - { magic, "Rub", 3, dorub}, - { magic, "Invoke", 3, doinvoke}, - { magic, 0, 3}, - { magic, "Offer", 3, dosacrifice}, - { magic, "Pray", 3, dopray}, - { magic, 0, 3}, - { magic, "Teleport", 3, dotelecmd}, - { magic, "Monster action", 3, domonability}, - { magic, "Turn undead", 3, doturn}, - - { help, "Help", 3, dohelp}, - { help, 0, 3}, - { help, "What is here", 3, dolook}, - { help, "What is there", 3, doquickwhatis}, - { help, "What is...", 2, dowhatis}, - { help, 0, 1}, - - { info, "Inventory", 3, ddoinv}, - { info, "Conduct", 3, doconduct}, - { info, "Discoveries", 3, dodiscovered}, - { info, "List/reorder spells", 3, dovspell}, - { info, "Adjust letters", 2, doorganize}, - { info, 0, 3}, - { info, "Name object or creature", 3, docallcmd}, - { info, 0, 3}, - { info, "Skills", 3, enhance_weapon_skill}, - - { 0, 0, 0 } - }; - - int i; - - game->addAction("Qt settings...",this,SLOT(doQtSettings(bool))); - help->addAction("About Qt NetHack...",this,SLOT(doAbout(bool))); - //help->addAction("NetHack Guidebook...",this,SLOT(doGuidebook(bool))); - help->addSeparator(); - - for (i=0; item[i].menu; i++) { - if ( item[i].flags & (qt_compact_mode ? 1 : 2) ) { - if (item[i].name) { - char actchar[32]; - char menuitem[BUFSZ]; - actchar[0] = '\0'; - if (item[i].funct) { - actchar[0] = cmd_from_func(item[i].funct); - actchar[1] = '\0'; - } - if (actchar[0] && !qt_compact_mode) - Sprintf(menuitem, "%s\t%s", item[i].name, - visctrl(actchar[0])); - else - Sprintf(menuitem, "%s", item[i].name); - if (actchar[0]) { - QString name = menuitem; - QAction *action = item[i].menu->addAction(name); - action->setData(actchar); - } - } else { - item[i].menu->addSeparator(); - } - } - } - - game->setTitle("Game"); - menubar->addMenu(game); - apparel->setTitle("Gear"); - menubar->addMenu(apparel); - - if ( qt_compact_mode ) { - act1->setTitle("A-J"); - menubar->addMenu(act1); - act2->setTitle("K-Z"); - menubar->addMenu(act2); - magic->setTitle("Magic"); - menubar->addMenu(magic); - info->setIcon(QIcon(QPixmap(info_xpm))); - info->setTitle("Info"); - menubar->addMenu(info); - //menubar->insertItem(QPixmap(map_xpm), this, SLOT(raiseMap())); - //menubar->insertItem(QPixmap(msg_xpm), this, SLOT(raiseMessages())); - //menubar->insertItem(QPixmap(stat_xpm), this, SLOT(raiseStatus())); - info->addSeparator(); - info->addAction("Map", this, SLOT(raiseMap())); - info->addAction("Messages", this, SLOT(raiseMessages())); - info->addAction("Status", this, SLOT(raiseStatus())); - } else { - act1->setTitle("Action"); - menubar->addMenu(act1); - magic->setTitle("Magic"); - menubar->addMenu(magic); - info->setTitle("Info"); - menubar->addMenu(info); - menubar->addSeparator(); - help->setTitle("Help"); - menubar->addMenu(help); - } - - QSignalMapper* sm = new QSignalMapper(this); - connect(sm, SIGNAL(mapped(const QString&)), this, SLOT(doKeys(const QString&))); - QToolButton* tb; - char actchar[32]; - tb = new SmallToolButton( QPixmap(again_xpm),"Again","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", Cmd.spkeys[NHKF_DOAGAIN]); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(get_xpm),"Get","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(dopickup)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(kick_xpm),"Kick","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(dokick)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(throw_xpm),"Throw","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(dothrow)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(fire_xpm),"Fire","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(dofire)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(drop_xpm),"Drop","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(doddrop)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(eat_xpm),"Eat","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(doeat)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(rest_xpm),"Rest","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(donull)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - - connect(game,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - connect(apparel,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - connect(act1,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - if (act2 != act1) - connect(act2,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - connect(magic,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - connect(info,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - connect(help,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - -#ifdef KDE - setMenu (menubar); -#endif - - int x=0,y=0; - int w=QApplication::desktop()->width()-10; // XXX arbitrary extra space for frame - int h=QApplication::desktop()->height()-50; - - int maxwn; - int maxhn; - if (qt_tilewidth != NULL) { - maxwn = atoi(qt_tilewidth) * COLNO + 10; - } else { - maxwn = 1400; - } - if (qt_tileheight != NULL) { - maxhn = atoi(qt_tileheight) * ROWNO * 6/4; - } else { - maxhn = 1024; - } - - // Be exactly the size we want to be - full map... - if (w>maxwn) { - x+=(w-maxwn)/2; - w=maxwn; // Doesn't need to be any wider - } - if (h>maxhn) { - y+=(h-maxhn)/2; - h=maxhn; // Doesn't need to be any taller - } - - setGeometry(x,y,w,h); - - if ( qt_compact_mode ) { - stack = new QStackedWidget(this); - setCentralWidget(stack); - } else { - vsplitter = new QSplitter(Qt::Vertical); - setCentralWidget(vsplitter); - hsplitter = new QSplitter(Qt::Horizontal); - invusage = new NetHackQtInvUsageWindow(hsplitter); - vsplitter->insertWidget(0, hsplitter); - hsplitter->insertWidget(1, invusage); - } -} - -void NetHackQtMainWindow::zoomMap() -{ - qt_settings->toggleGlyphSize(); -} - -void NetHackQtMainWindow::raiseMap() -{ - if ( stack->currentWidget() == map->Widget() ) { - zoomMap(); - } else { - stack->setCurrentWidget(map->Widget()); - } -} - -void NetHackQtMainWindow::raiseMessages() -{ - stack->setCurrentWidget(message->Widget()); -} - -void NetHackQtMainWindow::raiseStatus() -{ - stack->setCurrentWidget(status->Widget()); -} - -#if 0 // RLC this isn't used -class NetHackMimeSourceFactory : public Q3MimeSourceFactory { -public: - const QMimeSource* data(const QString& abs_name) const - { - const QMimeSource* r = 0; - if ( (NetHackMimeSourceFactory*)this == Q3MimeSourceFactory::defaultFactory() ) - r = Q3MimeSourceFactory::data(abs_name); - else - r = Q3MimeSourceFactory::defaultFactory()->data(abs_name); - if ( !r ) { - int sl = abs_name.length(); - do { - sl = abs_name.lastIndexOf('/',sl-1); - QString name = sl>=0 ? abs_name.mid(sl+1) : abs_name; - int dot = name.lastIndexOf('.'); - if ( dot >= 0 ) - name = name.left(dot); - if ( name == "map" ) - r = new Q3ImageDrag(QImage(map_xpm)); - else if ( name == "msg" ) - r = new Q3ImageDrag(QImage(msg_xpm)); - else if ( name == "stat" ) - r = new Q3ImageDrag(QImage(stat_xpm)); - } while (!r && sl>0); - } - return r; - } -}; -#endif - -void NetHackQtMainWindow::doMenuItem(QAction *action) -{ - doKeys(action->data().toString()); -} - -void NetHackQtMainWindow::doQtSettings(bool) -{ - centerOnMain(qt_settings); - qt_settings->show(); -} - -void NetHackQtMainWindow::doAbout(bool) -{ - QMessageBox::about(this, "About Qt NetHack", aboutMsg()); -} - -#if 0 // RLC this isn't used -void NetHackQtMainWindow::doGuidebook(bool) -{ - QDialog dlg(this); - new QVBoxLayout(&dlg); - Q3TextBrowser browser(&dlg); - NetHackMimeSourceFactory ms; - browser.setMimeSourceFactory(&ms); - browser.setSource(QDir::currentPath()+"/Guidebook.html"); - if ( qt_compact_mode ) - dlg.showMaximized(); - dlg.exec(); -} -#endif - -void NetHackQtMainWindow::doKeys(const QString& k) -{ - keysink.Put(k.toLatin1().constData()); - qApp->exit(); -} - -void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window) -{ - message=window; - if (!qt_compact_mode) - hsplitter->insertWidget(0, message->Widget()); - ShowIfReady(); -} - -NetHackQtMessageWindow * NetHackQtMainWindow::GetMessageWindow() -{ - return message; -} - -void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow2* window) -{ - - map=window; - if (!qt_compact_mode) - vsplitter->insertWidget(1, map->Widget()); - ShowIfReady(); - connect(map,SIGNAL(resized()),this,SLOT(layout())); -} - -void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window) -{ - status=window; - if (!qt_compact_mode) - hsplitter->insertWidget(2, status->Widget()); - ShowIfReady(); -} - -void NetHackQtMainWindow::RemoveWindow(NetHackQtWindow* window) -{ - if (window==status) { - status=0; - ShowIfReady(); - } else if (window==map) { - map=0; - ShowIfReady(); - } else if (window==message) { - message=0; - ShowIfReady(); - } -} - -void NetHackQtMainWindow::updateInventory() -{ - if ( invusage ) - invusage->repaint(); -} - -void NetHackQtMainWindow::fadeHighlighting() -{ - if (status) { - status->fadeHighlighting(); - } -} - -void NetHackQtMainWindow::layout() -{ -#if 0 - if ( qt_compact_mode ) - return; - if (message && map && status) { - QSize maxs=map->Widget()->maximumSize(); - int maph=std::min(height()*2/3,maxs.height()); - - QWidget* c = centralWidget(); - int h=c->height(); - int toph=h-maph; - int iuw=3*qt_settings->glyphs().width(); - int topw=(c->width()-iuw)/2; - - message->Widget()->setGeometry(0,0,topw,toph); - invusage->setGeometry(topw,0,iuw,toph); - status->Widget()->setGeometry(topw+iuw,0,topw,toph); - map->Widget()->setGeometry(std::max(0,(c->width()-maxs.width())/2), - toph,c->width(),maph); - } -#endif -} - -void NetHackQtMainWindow::resizeEvent(QResizeEvent*) -{ - layout(); -#ifdef KDE - updateRects(); -#endif -} - -void NetHackQtMainWindow::keyReleaseEvent(QKeyEvent* event) -{ - if ( dirkey ) { - doKeys(QString(QChar(dirkey))); - if ( !event->isAutoRepeat() ) - dirkey = 0; - } -} - -void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event) -{ - // Global key controls - - // For desktop, arrow keys scroll map, since we don't want players - // to think that's the way to move. For handhelds, the normal way is to - // click-to-travel, so we allow the cursor keys for fine movements. - - // 321 - // 4 0 - // 567 - - if ( event->isAutoRepeat() && - event->key() >= Qt::Key_Left && event->key() <= Qt::Key_Down ) - return; - - const char* d = Cmd.dirchars; - switch (event->key()) { - case Qt::Key_Up: - if ( dirkey == d[0] ) - dirkey = d[1]; - else if ( dirkey == d[4] ) - dirkey = d[3]; - else - dirkey = d[2]; - break; case Qt::Key_Down: - if ( dirkey == d[0] ) - dirkey = d[7]; - else if ( dirkey == d[4] ) - dirkey = d[5]; - else - dirkey = d[6]; - break; case Qt::Key_Left: - if ( dirkey == d[2] ) - dirkey = d[1]; - else if ( dirkey == d[6] ) - dirkey = d[7]; - else - dirkey = d[0]; - break; case Qt::Key_Right: - if ( dirkey == d[2] ) - dirkey = d[3]; - else if ( dirkey == d[6] ) - dirkey = d[5]; - else - dirkey = d[4]; - break; case Qt::Key_PageUp: - dirkey = 0; - if (message) message->Scroll(0,-1); - break; case Qt::Key_PageDown: - dirkey = 0; - if (message) message->Scroll(0,+1); - break; case Qt::Key_Space: - if ( flags.rest_on_space ) { - event->ignore(); - return; - } - case Qt::Key_Enter: - if ( map ) - map->clickCursor(); - break; default: - dirkey = 0; - event->ignore(); - } -} - -void NetHackQtMainWindow::closeEvent(QCloseEvent* e) -{ - if ( program_state.something_worth_saving ) { - switch ( QMessageBox::information( this, "NetHack", - "This will end your NetHack session", - "&Save", "&Cancel", 0, 1 ) ) - { - case 0: - // See dosave() function - if (dosave0()) { - u.uhp = -1; - NetHackQtBind::qt_exit_nhwindows(0); - nh_terminate(EXIT_SUCCESS); - } - break; - case 1: - break; // ignore the event - } - } else { - e->accept(); - } -} - -void NetHackQtMainWindow::ShowIfReady() -{ - if (message && map && status) { - QWidget* hp = qt_compact_mode ? static_cast(stack) : static_cast(hsplitter); - QWidget* vp = qt_compact_mode ? static_cast(stack) : static_cast(vsplitter); - message->Widget()->setParent(hp); - map->Widget()->setParent(vp); - status->Widget()->setParent(hp); - if ( qt_compact_mode ) { - message->setMap(map); - stack->addWidget(map->Widget()); - stack->addWidget(message->Widget()); - stack->addWidget(status->Widget()); - raiseMap(); - } else { - layout(); - } - showMaximized(); - } else if (isVisible()) { - hide(); - } -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4map.cpp b/win/Qt4/qt4map.cpp deleted file mode 100644 index 00598e79b..000000000 --- a/win/Qt4/qt4map.cpp +++ /dev/null @@ -1,974 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4map.cpp -- the map window - -extern "C" { -#include "hack.h" -} -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4map.h" -#include "qt4map.moc" -#include "qt4click.h" -#include "qt4glyph.h" -#include "qt_xpms.h" -#include "qt4set.h" -#include "qt4str.h" - -// temporary -extern int qt_compact_mode; -// end temporary - -namespace nethack_qt4 { - -#ifdef TEXTCOLOR -static const QPen& nhcolor_to_pen(int c) -{ - static QPen* pen=0; - if ( !pen ) { - pen = new QPen[17]; - pen[0] = QColor(64,64,64); - pen[1] = QColor(Qt::red); - pen[2] = QColor(0,191,0); - pen[3] = QColor(127,127,0); - pen[4] = QColor(Qt::blue); - pen[5] = QColor(Qt::magenta); - pen[6] = QColor(Qt::cyan); - pen[7] = QColor(Qt::gray); - pen[8] = QColor(Qt::white); // no color - pen[9] = QColor(255,127,0); - pen[10] = QColor(127,255,127); - pen[11] = QColor(Qt::yellow); - pen[12] = QColor(127,127,255); - pen[13] = QColor(255,127,255); - pen[14] = QColor(127,255,255); - pen[15] = QColor(Qt::white); - pen[16] = QColor(Qt::black); - } - - return pen[c]; -} -#endif - -NetHackQtMapViewport::NetHackQtMapViewport(NetHackQtClickBuffer& click_sink) : - QWidget(NULL), - rogue_font(NULL), - clicksink(click_sink), - change(10) -{ - pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_mark_xpm); - pile_annotation = QPixmap(pile_mark_xpm); - - Clear(); - cursor.setX(0); - cursor.setY(0); -} - -NetHackQtMapViewport::~NetHackQtMapViewport(void) -{ - delete rogue_font; -} - -void NetHackQtMapViewport::paintEvent(QPaintEvent* event) -{ - QRect area=event->rect(); - QRect garea; - garea.setCoords( - std::max(0,area.left()/qt_settings->glyphs().width()), - std::max(0,area.top()/qt_settings->glyphs().height()), - std::min(COLNO-1,area.right()/qt_settings->glyphs().width()), - std::min(ROWNO-1,area.bottom()/qt_settings->glyphs().height()) - ); - - QPainter painter; - - painter.begin(this); - - if (Is_rogue_level(&u.uz) || iflags.wc_ascii_map) { - // You enter a VERY primitive world! - - painter.setClipRect( event->rect() ); // (normally we don't clip) - painter.fillRect( event->rect(), Qt::black ); - - if ( !rogue_font ) { - // Find font... - int pts = 5; - QString fontfamily = iflags.wc_font_map - ? iflags.wc_font_map : "Monospace"; - bool bold = false; - if ( fontfamily.right(5).toLower() == "-bold" ) { - fontfamily.truncate(fontfamily.length()-5); - bold = true; - } - while ( pts < 32 ) { - QFont f(fontfamily, pts, bold ? QFont::Bold : QFont::Normal); - painter.setFont(QFont(fontfamily, pts)); - QFontMetrics fm = painter.fontMetrics(); - if ( fm.width("M") > qt_settings->glyphs().width() ) - break; - if ( fm.height() > qt_settings->glyphs().height() ) - break; - pts++; - } - rogue_font = new QFont(fontfamily,pts-1); - } - painter.setFont(*rogue_font); - - for (int j=garea.top(); j<=garea.bottom(); j++) { - for (int i=garea.left(); i<=garea.right(); i++) { - unsigned short g=Glyph(i,j); - int color; - int ch; - unsigned special; - - painter.setPen( Qt::green ); - /* map glyph to character and color */ - mapglyph(g, &ch, &color, &special, i, j, 0); - ch = cp437(ch); -#ifdef TEXTCOLOR - painter.setPen( nhcolor_to_pen(color) ); -#endif - if (!DrawWalls( - painter, - i*qt_settings->glyphs().width(), - j*qt_settings->glyphs().height(), - qt_settings->glyphs().width(), - qt_settings->glyphs().height(), - ch)) { - painter.drawText( - i*qt_settings->glyphs().width(), - j*qt_settings->glyphs().height(), - qt_settings->glyphs().width(), - qt_settings->glyphs().height(), - Qt::AlignCenter, - QString(QChar(ch)).left(1) - ); - } -#ifdef TEXTCOLOR - if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); - } -#endif - } - } - - painter.setFont(font()); - } else { - for (int j=garea.top(); j<=garea.bottom(); j++) { - for (int i=garea.left(); i<=garea.right(); i++) { - unsigned short g=Glyph(i,j); - int color; - int ch; - unsigned special; - mapglyph(g, &ch, &color, &special, i, j, 0); - qt_settings->glyphs().drawCell(painter, g, i, j); -#ifdef TEXTCOLOR - if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); - } -#endif - } - } - } - - if (garea.contains(cursor)) { - if (Is_rogue_level(&u.uz)) { -#ifdef TEXTCOLOR - painter.setPen( Qt::white ); -#else - painter.setPen( Qt::green ); // REALLY primitive -#endif - } else - { - int hp100; - if (u.mtimedone) { - hp100=u.mhmax ? u.mh*100/u.mhmax : 100; - } else { - hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100; - } - - if (hp100 > 75) painter.setPen(Qt::white); - else if (hp100 > 50) painter.setPen(Qt::yellow); - else if (hp100 > 25) painter.setPen(QColor(0xff,0xbf,0x00)); // orange - else if (hp100 > 10) painter.setPen(Qt::red); - else painter.setPen(Qt::magenta); - } - - painter.drawRect( - cursor.x()*qt_settings->glyphs().width(),cursor.y()*qt_settings->glyphs().height(), - qt_settings->glyphs().width()-1,qt_settings->glyphs().height()-1); - } - -#if 0 - if (area.intersects(messages_rect)) { - painter.setPen(Qt::black); - painter.drawText(viewport.contentsX()+1,viewport.contentsY()+1, - viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); - painter.setPen(Qt::white); - painter.drawText(viewport.contentsX(),viewport.contentsY(), - viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); - } -#endif - - painter.end(); -} - -bool NetHackQtMapViewport::DrawWalls( - QPainter& painter, - int x, int y, int w, int h, - unsigned ch) -{ - enum - { - w_left = 0x01, - w_right = 0x02, - w_up = 0x04, - w_down = 0x08, - w_sq_top = 0x10, - w_sq_bottom = 0x20, - w_sq_left = 0x40, - w_sq_right = 0x80 - }; - unsigned linewidth; - unsigned walls; - int x1, y1, x2, y2, x3, y3; - - linewidth = ((w < h) ? w : h)/8; - if (linewidth == 0) linewidth = 1; - - // Single walls - walls = 0; - switch (ch) - { - case 0x2500: // BOX DRAWINGS LIGHT HORIZONTAL - walls = w_left | w_right; - break; - - case 0x2502: // BOX DRAWINGS LIGHT VERTICAL - walls = w_up | w_down; - break; - - case 0x250C: // BOX DRAWINGS LIGHT DOWN AND RIGHT - walls = w_down | w_right; - break; - - case 0x2510: // BOX DRAWINGS LIGHT DOWN AND LEFT - walls = w_down | w_left; - break; - - case 0x2514: // BOX DRAWINGS LIGHT UP AND RIGHT - walls = w_up | w_right; - break; - - case 0x2518: // BOX DRAWINGS LIGHT UP AND LEFT - walls = w_up | w_left; - break; - - case 0x251C: // BOX DRAWINGS LIGHT VERTICAL AND RIGHT - walls = w_up | w_down | w_right; - break; - - case 0x2524: // BOX DRAWINGS LIGHT VERTICAL AND LEFT - walls = w_up | w_down | w_left; - break; - - case 0x252C: // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - walls = w_down | w_left | w_right; - break; - - case 0x2534: // BOX DRAWINGS LIGHT UP AND HORIZONTAL - walls = w_up | w_left | w_right; - break; - - case 0x253C: // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - walls = w_up | w_down | w_left | w_right; - break; - } - - if (walls != 0) - { - x1 = x + w/2; - switch (walls & (w_up | w_down)) - { - case w_up: - painter.drawLine(x1, y, x1, y+h/2); - break; - - case w_down: - painter.drawLine(x1, y+h/2, x1, y+h-1); - break; - - case w_up | w_down: - painter.drawLine(x1, y, x1, y+h-1); - break; - } - - y1 = y + h/2; - switch (walls & (w_left | w_right)) - { - case w_left: - painter.drawLine(x, y1, x+w/2, y1); - break; - - case w_right: - painter.drawLine(x+w/2, y1, x+w-1, y1); - break; - - case w_left | w_right: - painter.drawLine(x, y1, x+w-1, y1); - break; - } - - return true; - } - - // Double walls - walls = 0; - switch (ch) - { - case 0x2550: // BOX DRAWINGS DOUBLE HORIZONTAL - walls = w_left | w_right | w_sq_top | w_sq_bottom; - break; - - case 0x2551: // BOX DRAWINGS DOUBLE VERTICAL - walls = w_up | w_down | w_sq_left | w_sq_right; - break; - - case 0x2554: // BOX DRAWINGS DOUBLE DOWN AND RIGHT - walls = w_down | w_right | w_sq_top | w_sq_left; - break; - - case 0x2557: // BOX DRAWINGS DOUBLE DOWN AND LEFT - walls = w_down | w_left | w_sq_top | w_sq_right; - break; - - case 0x255A: // BOX DRAWINGS DOUBLE UP AND RIGHT - walls = w_up | w_right | w_sq_bottom | w_sq_left; - break; - - case 0x255D: // BOX DRAWINGS DOUBLE UP AND LEFT - walls = w_up | w_left | w_sq_bottom | w_sq_right; - break; - - case 0x2560: // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT - walls = w_up | w_down | w_right | w_sq_left; - break; - - case 0x2563: // BOX DRAWINGS DOUBLE VERTICAL AND LEFT - walls = w_up | w_down | w_left | w_sq_right; - break; - - case 0x2566: // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL - walls = w_down | w_left | w_right | w_sq_top; - break; - - case 0x2569: // BOX DRAWINGS DOUBLE UP AND HORIZONTAL - walls = w_up | w_left | w_right | w_sq_bottom; - break; - - case 0x256C: // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL - walls = w_up | w_down | w_left | w_right; - break; - } - if (walls != 0) - { - x1 = x + w/2 - linewidth; - x2 = x + w/2 + linewidth; - x3 = x + w - 1; - y1 = y + h/2 - linewidth; - y2 = y + h/2 + linewidth; - y3 = y + h - 1; - if (walls & w_up) - { - painter.drawLine(x1, y, x1, y1); - painter.drawLine(x2, y, x2, y1); - } - if (walls & w_down) - { - painter.drawLine(x1, y2, x1, y3); - painter.drawLine(x2, y2, x2, y3); - } - if (walls & w_left) - { - painter.drawLine(x, y1, x1, y1); - painter.drawLine(x, y2, x1, y2); - } - if (walls & w_right) - { - painter.drawLine(x2, y1, x3, y1); - painter.drawLine(x2, y2, x3, y2); - } - if (walls & w_sq_top) - { - painter.drawLine(x1, y1, x2, y1); - } - if (walls & w_sq_bottom) - { - painter.drawLine(x1, y2, x2, y2); - } - if (walls & w_sq_left) - { - painter.drawLine(x1, y1, x1, y2); - } - if (walls & w_sq_right) - { - painter.drawLine(x2, y1, x2, y2); - } - return true; - } - - // Solid blocks - if (0x2591 <= ch && ch <= 0x2593) - { - unsigned shade = ch - 0x2590; - QColor rgb(painter.pen().color()); - QColor rgb2( - rgb.red()*shade/4, - rgb.green()*shade/4, - rgb.blue()*shade/4); - painter.fillRect(x, y, w, h, rgb2); - return true; - } - - return false; -} - -void NetHackQtMapViewport::mousePressEvent(QMouseEvent* event) -{ - clicksink.Put( - event->pos().x()/qt_settings->glyphs().width(), - event->pos().y()/qt_settings->glyphs().height(), - event->button()==Qt::LeftButton ? CLICK_1 : CLICK_2 - ); - qApp->exit(); -} - -void NetHackQtMapViewport::updateTiles() -{ - change.clear(); - change.add(0,0,COLNO,ROWNO); - delete rogue_font; rogue_font = NULL; -} - -QSize NetHackQtMapViewport::sizeHint() const -{ - return QSize( - qt_settings->glyphs().width() * COLNO, - qt_settings->glyphs().height() * ROWNO); -} - -QSize NetHackQtMapViewport::minimumSizeHint() const -{ - return sizeHint(); -} - -void NetHackQtMapViewport::clickCursor() -{ - clicksink.Put(cursor.x(),cursor.y(),CLICK_1); - qApp->exit(); -} - -void NetHackQtMapViewport::Clear() -{ - unsigned short stone=cmap_to_glyph(S_stone); - - for (int j=0; jglyphs().width(), - ch.y()*qt_settings->glyphs().height(), - ch.width()*qt_settings->glyphs().width(), - ch.height()*qt_settings->glyphs().height() - ); - } - - change.clear(); - - if (block) { - yn_function("Press a key when done viewing",0,'\0'); - } -} - -void NetHackQtMapViewport::CursorTo(int x,int y) -{ - Changed(cursor.x(),cursor.y()); - cursor.setX(x); - cursor.setY(y); - Changed(cursor.x(),cursor.y()); -} - -void NetHackQtMapViewport::PrintGlyph(int x,int y,int glyph) -{ - Glyph(x,y)=glyph; - Changed(x,y); -} - -void NetHackQtMapViewport::Changed(int x, int y) -{ - change.add(x,y); -} - -NetHackQtMapWindow2::NetHackQtMapWindow2(NetHackQtClickBuffer& click_sink) : - QScrollArea(NULL), - m_viewport(new NetHackQtMapViewport(click_sink)) -{ - QPalette palette; - palette.setColor(backgroundRole(), Qt::black); - setPalette(palette); - - setWidget(m_viewport); - - connect(qt_settings,SIGNAL(tilesChanged()),this,SLOT(updateTiles())); - updateTiles(); -} - -void NetHackQtMapWindow2::updateTiles() -{ - NetHackQtGlyphs& glyphs = qt_settings->glyphs(); - int gw = glyphs.width(); - int gh = glyphs.height(); - // Be exactly the size we want to be - full map... - m_viewport->resize(COLNO*gw,ROWNO*gh); - - verticalScrollBar()->setSingleStep(gh); - verticalScrollBar()->setPageStep(gh); - horizontalScrollBar()->setSingleStep(gw); - horizontalScrollBar()->setPageStep(gw); - - m_viewport->updateTiles(); - Display(false); - - emit resized(); -} - -void NetHackQtMapWindow2::clearMessages() -{ - messages = ""; - update(messages_rect); - messages_rect = QRect(); -} - -void NetHackQtMapWindow2::putMessage(int attr, const QString& text) -{ - if ( !messages.isEmpty() ) - messages += "\n"; - messages += QString(text).replace(QChar(0x200B), ""); - QFontMetrics fm = fontMetrics(); -#if 0 - messages_rect = fm.boundingRect(viewport.contentsX(),viewport.contentsY(),viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); - update(messages_rect); -#endif -} - -void NetHackQtMapWindow2::clickCursor() -{ - m_viewport->clickCursor(); -} - -QWidget *NetHackQtMapWindow2::Widget() -{ - return this; -} - -void NetHackQtMapWindow2::Clear() -{ - m_viewport->Clear(); -} - -void NetHackQtMapWindow2::Display(bool block) -{ - m_viewport->Display(block); -} - -void NetHackQtMapWindow2::CursorTo(int x,int y) -{ - m_viewport->CursorTo(x, y); -} - -void NetHackQtMapWindow2::PutStr(int attr, const QString& text) -{ - puts("unexpected PutStr in MapWindow"); -} - -void NetHackQtMapWindow2::ClipAround(int x,int y) -{ - // Convert to pixel of center of tile - x=x*qt_settings->glyphs().width()+qt_settings->glyphs().width()/2; - y=y*qt_settings->glyphs().height()+qt_settings->glyphs().height()/2; - - // Then ensure that pixel is visible - ensureVisible(x,y,width()*0.45,height()*0.45); -} - -void NetHackQtMapWindow2::PrintGlyph(int x,int y,int glyph) -{ - m_viewport->PrintGlyph(x, y, glyph); -} - -#if 0 //RLC -// XXX Hmmm... crash after saving bones file if Map window is -// XXX deleted. Strange bug somewhere. -bool NetHackQtMapWindow::Destroy() { return false; } - -NetHackQtMapWindow::NetHackQtMapWindow(NetHackQtClickBuffer& click_sink) : - clicksink(click_sink), - change(10), - rogue_font(0) -{ - viewport.addChild(this); - - QPalette palette; - palette.setColor(backgroundRole(), Qt::black); - setPalette(palette); - palette.setColor(viewport.backgroundRole(), Qt::black); - viewport.setPalette(palette); - - pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_mark_xpm); - pile_annotation = QPixmap(pile_mark_xpm); - - cursor.setX(0); - cursor.setY(0); - Clear(); - - connect(qt_settings,SIGNAL(tilesChanged()),this,SLOT(updateTiles())); - connect(&viewport, SIGNAL(contentsMoving(int,int)), this, - SLOT(moveMessages(int,int))); - - updateTiles(); - //setFocusPolicy(Qt::StrongFocus); -} - -void NetHackQtMapWindow::moveMessages(int x, int y) -{ - QRect u = messages_rect; - messages_rect.moveTopLeft(QPoint(x,y)); - u |= messages_rect; - update(u); -} - -void NetHackQtMapWindow::clearMessages() -{ - messages = ""; - update(messages_rect); - messages_rect = QRect(); -} - -void NetHackQtMapWindow::putMessage(int attr, const QString& text) -{ - if ( !messages.isEmpty() ) - messages += "\n"; - messages += QString(text).replace(QChar(0x200B), ""); - QFontMetrics fm = fontMetrics(); - messages_rect = fm.boundingRect(viewport.contentsX(),viewport.contentsY(),viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); - update(messages_rect); -} - -void NetHackQtMapWindow::updateTiles() -{ - NetHackQtGlyphs& glyphs = qt_settings->glyphs(); - int gw = glyphs.width(); - int gh = glyphs.height(); - // Be exactly the size we want to be - full map... - resize(COLNO*gw,ROWNO*gh); - - viewport.verticalScrollBar()->setSingleStep(gh); - viewport.verticalScrollBar()->setPageStep(gh); - viewport.horizontalScrollBar()->setSingleStep(gw); - viewport.horizontalScrollBar()->setPageStep(gw); - /* - viewport.setMaximumSize( - gw*COLNO + viewport.verticalScrollBar()->width(), - gh*ROWNO + viewport.horizontalScrollBar()->height() - ); - */ - viewport.updateScrollBars(); - - change.clear(); - change.add(0,0,COLNO,ROWNO); - delete rogue_font; rogue_font = 0; - Display(false); - - emit resized(); -} - -NetHackQtMapWindow::~NetHackQtMapWindow() -{ - // Remove from viewport porthole, since that is a destructible member. - viewport.removeChild(this); - setParent(0,0); -} - -QWidget* NetHackQtMapWindow::Widget() -{ - return &viewport; -} - -void NetHackQtMapWindow::Scroll(int dx, int dy) -{ - if (viewport.horizontalScrollBar()->isVisible()) { - while (dx<0) { viewport.horizontalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub); dx++; } - while (dx>0) { viewport.horizontalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd); dx--; } - } - if (viewport.verticalScrollBar()->isVisible()) { - while (dy<0) { viewport.verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepSub); dy++; } - while (dy>0) { viewport.verticalScrollBar()->triggerAction(QAbstractSlider::SliderPageStepAdd); dy--; } - } -} - -void NetHackQtMapWindow::Clear() -{ - unsigned short stone=cmap_to_glyph(S_stone); - - for (int j=0; jexit(); -} - -void NetHackQtMapWindow::mousePressEvent(QMouseEvent* event) -{ - clicksink.Put( - event->pos().x()/qt_settings->glyphs().width(), - event->pos().y()/qt_settings->glyphs().height(), - event->button()==Qt::LeftButton ? CLICK_1 : CLICK_2 - ); - qApp->exit(); -} - -void NetHackQtMapWindow::paintEvent(QPaintEvent* event) -{ - QRect area=event->rect(); - QRect garea; - garea.setCoords( - std::max(0,area.left()/qt_settings->glyphs().width()), - std::max(0,area.top()/qt_settings->glyphs().height()), - std::min(COLNO-1,area.right()/qt_settings->glyphs().width()), - std::min(ROWNO-1,area.bottom()/qt_settings->glyphs().height()) - ); - - QPainter painter; - - painter.begin(this); - - if (is_rogue_level(&u.uz) || iflags.wc_ascii_map) { - // You enter a VERY primitive world! - - painter.setClipRect( event->rect() ); // (normally we don't clip) - painter.fillRect( event->rect(), Qt::black ); - - if ( !rogue_font ) { - // Find font... - int pts = 5; - QString fontfamily = iflags.wc_font_map - ? iflags.wc_font_map : "Courier"; - bool bold = false; - if ( fontfamily.right(5).toLower() == "-bold" ) { - fontfamily.truncate(fontfamily.length()-5); - bold = true; - } - while ( pts < 32 ) { - QFont f(fontfamily, pts, bold ? QFont::Bold : QFont::Normal); - painter.setFont(QFont(fontfamily, pts)); - QFontMetrics fm = painter.fontMetrics(); - if ( fm.width("M") > qt_settings->glyphs().width() ) - break; - if ( fm.height() > qt_settings->glyphs().height() ) - break; - pts++; - } - rogue_font = new QFont(fontfamily,pts-1); - } - painter.setFont(*rogue_font); - - for (int j=garea.top(); j<=garea.bottom(); j++) { - for (int i=garea.left(); i<=garea.right(); i++) { - unsigned short g=Glyph(i,j); - int color; - char32_t ch; - unsigned special; - - painter.setPen( Qt::green ); - /* map glyph to character and color */ - mapglyph(g, &ch, &color, &special, i, j, 0); -#ifdef TEXTCOLOR - painter.setPen( nhcolor_to_pen(color) ); -#endif - painter.drawText( - i*qt_settings->glyphs().width(), - j*qt_settings->glyphs().height(), - qt_settings->glyphs().width(), - qt_settings->glyphs().height(), - Qt::AlignCenter, - QString(QChar(ch)).left(1) - ); -#ifdef TEXTCOLOR - if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); - } -#endif - } - } - - painter.setFont(font()); - } else { - for (int j=garea.top(); j<=garea.bottom(); j++) { - for (int i=garea.left(); i<=garea.right(); i++) { - unsigned short g=Glyph(i,j); - int color; - int ch; - unsigned special; - mapglyph(g, &ch, &color, &special, i, j, 0); - qt_settings->glyphs().drawCell(painter, g, i, j); -#ifdef TEXTCOLOR - if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); - } -#endif - } - } - } - - if (garea.contains(cursor)) { - if (Is_rogue_level(&u.uz)) { -#ifdef TEXTCOLOR - painter.setPen( Qt::white ); -#else - painter.setPen( Qt::green ); // REALLY primitive -#endif - } else - { - int hp100; - if (u.mtimedone) { - hp100=u.mhmax ? u.mh*100/u.mhmax : 100; - } else { - hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100; - } - - if (hp100 > 75) painter.setPen(Qt::white); - else if (hp100 > 50) painter.setPen(Qt::yellow); - else if (hp100 > 25) painter.setPen(QColor(0xff,0xbf,0x00)); // orange - else if (hp100 > 10) painter.setPen(Qt::red); - else painter.setPen(Qt::magenta); - } - - painter.drawRect( - cursor.x()*qt_settings->glyphs().width(),cursor.y()*qt_settings->glyphs().height(), - qt_settings->glyphs().width()-1,qt_settings->glyphs().height()-1); - } - - if (area.intersects(messages_rect)) { - painter.setPen(Qt::black); - painter.drawText(viewport.contentsX()+1,viewport.contentsY()+1, - viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); - painter.setPen(Qt::white); - painter.drawText(viewport.contentsX(),viewport.contentsY(), - viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); - } - - painter.end(); -} - -void NetHackQtMapWindow::Display(bool block) -{ - for (int i=0; iglyphs().width(), - ch.y()*qt_settings->glyphs().height(), - ch.width()*qt_settings->glyphs().width(), - ch.height()*qt_settings->glyphs().height() - ); - } - - change.clear(); - - if (block) { - yn_function("Press a key when done viewing",0,'\0'); - } -} - -void NetHackQtMapWindow::CursorTo(int x,int y) -{ - Changed(cursor.x(),cursor.y()); - cursor.setX(x); - cursor.setY(y); - Changed(cursor.x(),cursor.y()); -} - -void NetHackQtMapWindow::PutStr(int attr, const QString& text) -{ - puts("unexpected PutStr in MapWindow"); -} - -void NetHackQtMapWindow::ClipAround(int x,int y) -{ - // Convert to pixel of center of tile - x=x*qt_settings->glyphs().width()+qt_settings->glyphs().width()/2; - y=y*qt_settings->glyphs().height()+qt_settings->glyphs().height()/2; - - // Then ensure that pixel is visible - viewport.center(x,y,0.45,0.45); -} - -void NetHackQtMapWindow::PrintGlyph(int x,int y,int glyph) -{ - Glyph(x,y)=glyph; - Changed(x,y); -} - -//void NetHackQtMapWindow::PrintGlyphCompose(int x,int y,int glyph1, int glyph2) -//{ - // TODO: composed graphics -//} - -void NetHackQtMapWindow::Changed(int x, int y) -{ - change.add(x,y); -} -#endif - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4map.h b/win/Qt4/qt4map.h deleted file mode 100644 index 337a726aa..000000000 --- a/win/Qt4/qt4map.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4map.h -- the map window - -#ifndef QT4MAP_H -#define QT4MAP_H - -#include "qt4win.h" -#include "qt4clust.h" - -namespace nethack_qt4 { - -class NetHackQtClickBuffer; - -class NetHackQtMapViewport : public QWidget { - Q_OBJECT -public: - NetHackQtMapViewport(NetHackQtClickBuffer& click_sink); - ~NetHackQtMapViewport(void); - -protected: - virtual void paintEvent(QPaintEvent* event); - bool DrawWalls(QPainter& painter, int x, int y, int w, int h, unsigned ch); - virtual QSize sizeHint() const; - virtual QSize minimumSizeHint() const; - virtual void mousePressEvent(QMouseEvent* event); - -private: - QFont *rogue_font; - unsigned short glyph[ROWNO][COLNO]; - unsigned short& Glyph(int x, int y) { return glyph[y][x]; } - QPoint cursor; - QPixmap pet_annotation; - QPixmap pile_annotation; - NetHackQtClickBuffer& clicksink; - Clusterizer change; - - void clickCursor(); - void Clear(); - void Display(bool block); - void CursorTo(int x,int y); - void PrintGlyph(int x,int y,int glyph); - void Changed(int x, int y); - void updateTiles(); - - // NetHackQtMapWindow2 passes through many calls to the viewport - friend class NetHackQtMapWindow2; -}; - -class NetHackQtMapWindow2 : public QScrollArea, public NetHackQtWindow { - Q_OBJECT -public: - NetHackQtMapWindow2(NetHackQtClickBuffer& click_sink); - void clearMessages(); - void putMessage(int attr, const QString& text); - void clickCursor(); - virtual QWidget *Widget(); - - virtual void Clear(); - virtual void Display(bool block); - virtual void CursorTo(int x,int y); - virtual void PutStr(int attr, const QString& text); - virtual void ClipAround(int x,int y); - virtual void PrintGlyph(int x,int y,int glyph); - -signals: - void resized(); - -private slots: - void updateTiles(); - -private: - NetHackQtMapViewport *m_viewport; - QRect messages_rect; - QString messages; -}; - -} // namespace nethack_qt4 - -#endif diff --git a/win/Qt4/qt4menu.cpp b/win/Qt4/qt4menu.cpp deleted file mode 100644 index 5ab053891..000000000 --- a/win/Qt4/qt4menu.cpp +++ /dev/null @@ -1,830 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4menu.cpp -- a menu or text-list widget - -extern "C" { -#include "hack.h" -} -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4menu.h" -#include "qt4menu.moc" -#include "qt4glyph.h" -#include "qt4set.h" -#include "qt4streq.h" -#include "qt4str.h" - -// temporary -extern "C" int qt_compact_mode; -// end temporary - -extern "C" struct menucoloring *menu_colorings; - -namespace nethack_qt4 { - -// temporary -void centerOnMain( QWidget* w ); -// end temporary - -QSize NetHackQtTextListBox::sizeHint() const -{ - QScrollBar *hscroll = horizontalScrollBar(); - int hsize = hscroll ? hscroll->height() : 0; - return QSize(TotalWidth()+hsize, TotalHeight()+hsize); -} - -int NetHackQtMenuListBox::TotalWidth() const -{ - int width = 0; - - for (int col = 0; col < columnCount(); ++col) { - width += columnWidth(col); - } - return width; -} - -int NetHackQtMenuListBox::TotalHeight() const -{ - int height = 0; - - for (int row = 0; row < rowCount(); ++row) { - height += rowHeight(row); - } - return height; -} - -QSize NetHackQtMenuListBox::sizeHint() const -{ - QScrollBar *hscroll = horizontalScrollBar(); - int hsize = hscroll ? hscroll->height() : 0; - return QSize(TotalWidth()+hsize, TotalHeight()+hsize); -} - -// Table view columns: -// -// [pick-count] [accel] [glyph] [string] -// -// Maybe accel should be near string. We'll see. -// pick-count normally blank. -// double-clicking or click-on-count gives pop-up entry -// string is green when selected -// -NetHackQtMenuWindow::NetHackQtMenuWindow(QWidget *parent) : - QDialog(parent), - table(new NetHackQtMenuListBox()), - prompt(0), - counting(false) -{ - QGridLayout *grid = new QGridLayout(); - table->setColumnCount(5); - table->setFrameStyle(QFrame::Panel|QFrame::Sunken); - table->setLineWidth(2); - table->setShowGrid(false); - table->horizontalHeader()->hide(); - table->verticalHeader()->hide(); - - ok=new QPushButton("Ok"); - connect(ok,SIGNAL(clicked()),this,SLOT(accept())); - - cancel=new QPushButton("Cancel"); - connect(cancel,SIGNAL(clicked()),this,SLOT(reject())); - - all=new QPushButton("All"); - connect(all,SIGNAL(clicked()),this,SLOT(All())); - - none=new QPushButton("None"); - connect(none,SIGNAL(clicked()),this,SLOT(ChooseNone())); - - invert=new QPushButton("Invert"); - connect(invert,SIGNAL(clicked()),this,SLOT(Invert())); - - search=new QPushButton("Search"); - connect(search,SIGNAL(clicked()),this,SLOT(Search())); - - QPoint pos(0,ok->height()); - move(pos); - prompt.setParent(this,0); - prompt.move(pos); - - grid->addWidget(ok, 0, 0); - grid->addWidget(cancel, 0, 1); - grid->addWidget(all, 0, 2); - grid->addWidget(none, 0, 3); - grid->addWidget(invert, 0, 4); - grid->addWidget(search, 0, 5); - grid->addWidget(&prompt, 1, 0, 1, 7); - grid->addWidget(table, 2, 0, 1, 7); - grid->setColumnStretch(6, 1); - grid->setRowStretch(2, 1); - setFocusPolicy(Qt::StrongFocus); - table->setFocusPolicy(Qt::NoFocus); - connect(table, SIGNAL(cellClicked(int,int)), this, SLOT(cellToggleSelect(int,int))); - - setLayout(grid); -} - -NetHackQtMenuWindow::~NetHackQtMenuWindow() -{ -} - -QWidget* NetHackQtMenuWindow::Widget() { return this; } - -void NetHackQtMenuWindow::StartMenu() -{ - table->setRowCount((itemcount=0)); - next_accel=0; - has_glyphs=false; -} - -NetHackQtMenuWindow::MenuItem::MenuItem() : - str("") -{ -} - -NetHackQtMenuWindow::MenuItem::~MenuItem() -{ -} - -void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P* identifier, - char ch, char gch, int attr, const QString& str, bool presel) -{ - if (!ch && identifier->a_void!=0) { - // Supply a keyboard accelerator. Limited supply. - static char accel[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - if (accel[next_accel]) { - ch=accel[next_accel++]; - } - } - - if ((int)itemlist.size() < itemcount+1) { - itemlist.resize(itemcount*4+10); - } - itemlist[itemcount].glyph=glyph; - itemlist[itemcount].identifier=*identifier; - itemlist[itemcount].ch=ch; - itemlist[itemcount].gch=gch; - itemlist[itemcount].attr=attr; - itemlist[itemcount].str=str; - itemlist[itemcount].selected=presel; - itemlist[itemcount].count=-1; - itemlist[itemcount].color = -1; - // Display the boulder symbol correctly - if (str.left(8) == "boulder\t") { - int bracket = str.indexOf('['); - if (bracket != -1) { - itemlist[itemcount].str = str.left(bracket+1) - + QChar(cp437(str.at(bracket+1).unicode())) - + str.mid(bracket+2); - } - } - int mcolor, mattr; - if (attr == 0 - && get_menu_coloring(str.toLatin1().constData(), &mcolor, &mattr)) { - itemlist[itemcount].attr = mattr; - itemlist[itemcount].color = mcolor; - } - ++itemcount; - - if (glyph!=NO_GLYPH) has_glyphs=true; -} - -void NetHackQtMenuWindow::EndMenu(const QString& p) -{ - prompt.setText(p); - promptstr = p; -} - -int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list) -{ - QFont tablefont(qt_settings->normalFont()); - table->setFont(tablefont); - - table->setRowCount(itemcount); - - how=h; - - ok->setEnabled(how!=PICK_ONE);ok->setDefault(how!=PICK_ONE); - cancel->setEnabled(how!=PICK_NONE); - all->setEnabled(how==PICK_ANY); - none->setEnabled(how==PICK_ANY); - invert->setEnabled(how==PICK_ANY); - search->setEnabled(how!=PICK_NONE); - - setResult(-1); - - // Set contents of table - QFontMetrics fm(table->font()); - for (int i = 0; i < 5; i++) { - table->setColumnWidth(i, 0); - } - for (int i = 0; i < itemcount; i++) { - AddRow(i, itemlist[i]); - } - - // Determine column widths - std::vector col_widths; - for (std::size_t i = 0; i < itemlist.size(); ++i) { - QStringList columns = itemlist[i].str.split("\t"); - if (!itemlist[i].Selectable() && columns.size() == 1) - { - // Nonselectable line with no column dividers - // Assume this is a section header - continue; - } - for (std::size_t j = 0U; j < columns.size(); ++j) { - int w = fm.width(columns[j] + " \t"); - if (j >= col_widths.size()) { - col_widths.push_back(w); - } else if (col_widths[j] < w) { - col_widths[j] = w; - } - } - } - - // Pad each column to its column width - for (std::size_t i = 0U; i < itemlist.size(); ++i) { - QTableWidgetItem *twi = table->item(i, 4); - if (twi == NULL) { continue; } - QString text = twi->text(); - QStringList columns = text.split("\t"); - for (std::size_t j = 0U; j+1U < columns.size(); ++j) { - columns[j] += "\t"; - int width = col_widths[j]; - while (fm.width(columns[j]) < width) { - columns[j] += "\t"; - } - } - text = columns.join(""); - twi->setText(text); - WidenColumn(4, fm.width(text)); - } - - // FIXME: size for compact mode - //resize(this->width(), parent()->height()*7/8); - move(0, 0); - adjustSize(); - centerOnMain(this); - exec(); - int result=this->result(); - - *menu_list=0; - if (result>0 && how!=PICK_NONE) { - if (how==PICK_ONE) { - int i; - for (i=0; ifont()); - QTableWidgetItem *twi; - - if (mi.Selectable() && how != PICK_NONE) { - // Count - twi = new QTableWidgetItem(""); - table->setItem(row, 0, twi); - twi->setFlags(Qt::ItemIsEnabled); - WidenColumn(0, fm.width("999999")); - // Check box, set if selected - QCheckBox *cb = new QCheckBox(); - cb->setChecked(mi.selected); - cb->setFocusPolicy(Qt::NoFocus); - if (how == PICK_ONE) - connect(cb, SIGNAL(clicked(bool)), this, SLOT(DoSelection(bool))); - table->setCellWidget(row, 1, cb); - WidenColumn(1, cb->width()); - } - if (mi.glyph != NO_GLYPH) { - // Icon - QPixmap pm(qt_settings->glyphs().glyph(mi.glyph)); - twi = new QTableWidgetItem(QIcon(pm), ""); - table->setItem(row, 2, twi); - twi->setFlags(Qt::ItemIsEnabled); - WidenColumn(2, pm.width()); - } - QString letter, text(mi.str); - if (mi.ch != 0) { - // Letter specified - letter = QString(mi.ch) + " - "; - } - else { - // Letter is left blank, except for skills display when # and * are - // presented - if (text.startsWith(" ")) { - // If mi.str starts with " ", it's meant to line up with lines - // that have a letter; we don't want that here - text = text.mid(4); - } else if (text.startsWith(" #") || text.startsWith(" *")) { - // Put the * or # in the letter column - letter = text.left(4); - text = text.mid(4); - } - } - twi = new QTableWidgetItem(letter); - table->setItem(row, 3, twi); - table->item(row, 3)->setFlags(Qt::ItemIsEnabled); - WidenColumn(3, fm.width(letter)); - twi = new QTableWidgetItem(text); - table->setItem(row, 4, twi); - table->item(row, 4)->setFlags(Qt::ItemIsEnabled); - WidenColumn(4, fm.width(text)); - - if (mi.color != -1) { - twi->setForeground(colors[mi.color]); - } - - QFont itemfont(table->font()); - switch (mi.attr) { - case ATR_BOLD: - itemfont.setWeight(QFont::Bold); - twi->setFont(itemfont); - break; - - case ATR_DIM: - twi->setFlags(Qt::NoItemFlags); - break; - - case ATR_ULINE: - itemfont.setUnderline(true); - twi->setFont(itemfont); - break; - - case ATR_INVERSE: - { - QBrush fg = twi->foreground(); - QBrush bg = twi->background(); - if (fg == bg) { - // default foreground and background come up the same for - // some unknown reason - twi->setForeground(Qt::white); - twi->setBackground(Qt::black); - } else { - twi->setForeground(bg); - twi->setBackground(fg); - } - } - break; - } -} - -void NetHackQtMenuWindow::WidenColumn(int column, int width) -{ - // need to add a bit so the whole column displays - width += 7; - if (table->columnWidth(column) < width) { - table->setColumnWidth(column, width); - } -} - -void NetHackQtMenuWindow::InputCount(char key) -{ - if (key == '\b') - { - if (counting) - { - if (countstr.isEmpty()) - ClearCount(); - else - countstr = countstr.mid(0, countstr.size() - 1); - } - } - else - { - counting = true; - countstr += QChar(key); - } - if (counting) - prompt.setText("Count: " + countstr); -} - -void NetHackQtMenuWindow::ClearCount(void) -{ - counting = false; - prompt.setText(promptstr); - countstr = ""; -} - -void NetHackQtMenuWindow::keyPressEvent(QKeyEvent* event) -{ - QString text = event->text(); - - const QChar *uni = text.unicode(); - for (unsigned k = 0; uni[k] != 0; k++) { - unsigned key = uni[k].unicode(); - if (key=='\033') { - if (counting) - ClearCount(); - else - reject(); - } else if (key=='\r' || key=='\n' || key==' ') - accept(); - else if (key==MENU_SEARCH) - Search(); - else if (key==MENU_SELECT_ALL || key==MENU_SELECT_PAGE) - All(); - else if (key==MENU_INVERT_ALL || key==MENU_INVERT_PAGE) - Invert(); - else if (key==MENU_UNSELECT_ALL || key==MENU_UNSELECT_PAGE) - ChooseNone(); - else if (('0' <= key && key <= '9') || key == '\b') - InputCount(key); - else { - for (int i=0; iitem(i, 0); - if (count != NULL) count->setText(""); - - QCheckBox *cb = dynamic_cast(table->cellWidget(i, 1)); - if (cb != NULL) cb->setChecked(true); - } -} -void NetHackQtMenuWindow::ChooseNone() -{ - if (how != PICK_ANY) - return; - - for (int i=0; iitem(i, 0); - if (count != NULL) count->setText(""); - - QCheckBox *cb = dynamic_cast(table->cellWidget(i, 1)); - if (cb != NULL) cb->setChecked(false); - } -} -void NetHackQtMenuWindow::Invert() -{ - if (how != PICK_ANY) - return; - - for (int i=0; iitem(i, 0); - if (count != NULL) count->setText(""); - - QCheckBox *cb = dynamic_cast(table->cellWidget(i, 1)); - if (cb != NULL) cb->setChecked(cb->checkState() == Qt::Unchecked); - } -} -void NetHackQtMenuWindow::Search() -{ - if (how == PICK_NONE) - return; - - NetHackQtStringRequestor requestor(this, "Search for:"); - char line[256]; - if (requestor.Get(line)) { - for (int i=0; i(table->cellWidget(i, 1)); - if (cb == NULL) return; - - cb->setChecked((counting && !countstr.isEmpty()) - || cb->checkState() == Qt::Unchecked); - - QTableWidgetItem *count = table->item(i, 0); - if (count != NULL) count->setText(countstr); - - ClearCount(); - - if (how==PICK_ONE) { - accept(); - } - } -} - -void NetHackQtMenuWindow::cellToggleSelect(int i, int j) -{ - ToggleSelect(i); -} - -void NetHackQtMenuWindow::DoSelection(bool) -{ - if (how == PICK_ONE) { - accept(); - } -} - -bool NetHackQtMenuWindow::isSelected(int row) -{ - QCheckBox *cb = dynamic_cast(table->cellWidget(row, 1)); - return cb != NULL && cb->checkState() != Qt::Unchecked; -} - -int NetHackQtMenuWindow::count(int row) -{ - QTableWidgetItem *count = table->item(row, 0); - if (count == NULL) return -1; - QString cstr = count->text(); - return cstr.isEmpty() ? -1 : cstr.toInt(); -} - -NetHackQtTextWindow::NetHackQtTextWindow(QWidget *parent) : - QDialog(parent), - use_rip(false), - str_fixed(false), - ok("Dismiss",this), - search("Search",this), - lines(new NetHackQtTextListBox(this)), - rip(this) -{ - ok.setDefault(true); - connect(&ok,SIGNAL(clicked()),this,SLOT(accept())); - connect(&search,SIGNAL(clicked()),this,SLOT(Search())); - connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate())); - - QVBoxLayout* vb = new QVBoxLayout(this); - vb->addWidget(&rip); - QHBoxLayout* hb = new QHBoxLayout(); - vb->addLayout(hb); - hb->addWidget(&ok); - hb->addWidget(&search); - vb->addWidget(lines); -} - -void NetHackQtTextWindow::doUpdate() -{ - update(); -} - - -NetHackQtTextWindow::~NetHackQtTextWindow() -{ - -} - -QWidget* NetHackQtTextWindow::Widget() -{ - return this; -} - -bool NetHackQtTextWindow::Destroy() -{ - return !isVisible(); -} - -void NetHackQtTextWindow::UseRIP(int how, time_t when) -{ -// Code from X11 windowport -#define STONE_LINE_LEN 16 /* # chars that fit on one line */ -#define NAME_LINE 0 /* line # for player name */ -#define GOLD_LINE 1 /* line # for amount of gold */ -#define DEATH_LINE 2 /* line # for death description */ -#define YEAR_LINE 6 /* line # for year */ - -static char** rip_line=0; - if (!rip_line) { - rip_line=new char*[YEAR_LINE+1]; - for (int i=0; i STONE_LINE_LEN) { - for(i = STONE_LINE_LEN; - ((i0 > STONE_LINE_LEN) && i); i--) - if(dpx[i] == ' ') i0 = i; - if(!i) i0 = STONE_LINE_LEN; - } - tmpchar = dpx[i0]; - dpx[i0] = 0; - str_copy(rip_line[line], dpx, STONE_LINE_LEN+1); - if (tmpchar != ' ') { - dpx[i0] = tmpchar; - dpx= &dpx[i0]; - } else dpx= &dpx[i0+1]; - } - - /* Put year on stone */ - snprintf(rip_line[YEAR_LINE], STONE_LINE_LEN+1, "%4d", getyear()); - - rip.setLines(rip_line,YEAR_LINE+1); - - use_rip=true; -} - -void NetHackQtTextWindow::Clear() -{ - lines->clear(); - use_rip=false; - str_fixed=false; -} - -void NetHackQtTextWindow::Display(bool block) -{ - if (str_fixed) { - lines->setFont(qt_settings->normalFixedFont()); - } else { - lines->setFont(qt_settings->normalFont()); - } - - int h=0; - if (use_rip) { - h+=rip.height(); - ok.hide(); - search.hide(); - rip.show(); - } else { - h+=ok.height()*2 + 7; - ok.show(); - search.show(); - rip.hide(); - } - int mh = QApplication::desktop()->height()*3/5; - if ( (qt_compact_mode && lines->TotalHeight() > mh) || use_rip ) { - // big, so make it fill - showMaximized(); - } else { - move(0, 0); - adjustSize(); - centerOnMain(this); - show(); - } - exec(); -} - -void NetHackQtTextWindow::PutStr(int attr, const QString& text) -{ - str_fixed=str_fixed || text.contains(" "); - lines->addItem(text); -} - -void NetHackQtTextWindow::Search() -{ - NetHackQtStringRequestor requestor(this, "Search for:"); - static char line[256]=""; - requestor.SetDefault(line); - if (requestor.Get(line)) { - int current=lines->currentRow(); - for (int i=1; icount(); i++) { - int lnum=(i+current)%lines->count(); - QString str=lines->item(lnum)->text(); - if (str.contains(line)) { - lines->setCurrentRow(lnum); - return; - } - } - lines->setCurrentItem(NULL); - } -} - -NetHackQtMenuOrTextWindow::NetHackQtMenuOrTextWindow(QWidget *parent_) : - actual(0), - parent(parent_) -{ -} - -QWidget* NetHackQtMenuOrTextWindow::Widget() -{ - if (!actual) impossible("Widget called before we know if Menu or Text"); - return actual->Widget(); -} - -// Text -void NetHackQtMenuOrTextWindow::Clear() -{ - if (!actual) impossible("Clear called before we know if Menu or Text"); - actual->Clear(); -} -void NetHackQtMenuOrTextWindow::Display(bool block) -{ - if (!actual) impossible("Display called before we know if Menu or Text"); - actual->Display(block); -} -bool NetHackQtMenuOrTextWindow::Destroy() -{ - if (!actual) impossible("Destroy called before we know if Menu or Text"); - return actual->Destroy(); -} - -void NetHackQtMenuOrTextWindow::PutStr(int attr, const QString& text) -{ - if (!actual) actual=new NetHackQtTextWindow(parent); - actual->PutStr(attr,text); -} - -// Menu -void NetHackQtMenuOrTextWindow::StartMenu() -{ - if (!actual) actual=new NetHackQtMenuWindow(parent); - actual->StartMenu(); -} -void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const QString& str, bool presel) -{ - if (!actual) impossible("AddMenu called before we know if Menu or Text"); - actual->AddMenu(glyph,identifier,ch,gch,attr,str,presel); -} -void NetHackQtMenuOrTextWindow::EndMenu(const QString& prompt) -{ - if (!actual) impossible("EndMenu called before we know if Menu or Text"); - actual->EndMenu(prompt); -} -int NetHackQtMenuOrTextWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) -{ - if (!actual) impossible("SelectMenu called before we know if Menu or Text"); - return actual->SelectMenu(how,menu_list); -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4msg.cpp b/win/Qt4/qt4msg.cpp deleted file mode 100644 index d82e102fe..000000000 --- a/win/Qt4/qt4msg.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4msg.cpp -- a message window - -extern "C" { -#include "hack.h" -} -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4msg.h" -#include "qt4msg.moc" -#include "qt4map.h" -#include "qt4set.h" -#include "qt4str.h" - -namespace nethack_qt4 { - -NetHackQtMessageWindow::NetHackQtMessageWindow() : - list(new QListWidget()) -{ - list->setFocusPolicy(Qt::NoFocus); - ::iflags.window_inited = 1; - map = 0; - currgetmsg = 0; - connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(updateFont())); - updateFont(); -} - -NetHackQtMessageWindow::~NetHackQtMessageWindow() -{ - ::iflags.window_inited = 0; - delete list; -} - -QWidget* NetHackQtMessageWindow::Widget() { return list; } - -void NetHackQtMessageWindow::setMap(NetHackQtMapWindow2* m) -{ - map = m; - updateFont(); -} - -void NetHackQtMessageWindow::updateFont() -{ - list->setFont(qt_settings->normalFont()); - if ( map ) - map->setFont(qt_settings->normalFont()); -} - -void NetHackQtMessageWindow::Scroll(int dx, int dy) -{ - //RLC Is this necessary? - //RLC list->Scroll(dx,dy); -} - -void NetHackQtMessageWindow::Clear() -{ - if ( map ) - map->clearMessages(); -} - -void NetHackQtMessageWindow::ClearMessages() -{ - if (list) - list->clear(); -} - -void NetHackQtMessageWindow::Display(bool block) -{ - if (changed) { - list->repaint(); - changed=false; - } -} - -const char * NetHackQtMessageWindow::GetStr(bool init) -{ - if (init) - currgetmsg = 0; - - QListWidgetItem *item = list->item(currgetmsg++); - if (item) { - QString str = item->text(); - //raw_printf("getstr[%i]='%s'", currgetmsg, str.toLatin1().constData()); - return str.toLatin1().constData(); - } - return NULL; -} - -void NetHackQtMessageWindow::PutStr(int attr, const QString& text) -{ -#ifdef USER_SOUNDS - play_sound_for_message(text.toLatin1().constData()); -#endif - - changed=true; - - // If the line is output from the "/" command, map the first character - // as a symbol - QString text2; - if (text.mid(1, 3) == " ") { - text2 = QChar(cp437(text.at(0).unicode())) + text.mid(1); - } else { - text2 = text; - } -#if 0 - QListWidgetItem *item = new QListWidgetItem(text2); - - QFont font = item->font(); - font.setUnderline(attr == ATR_ULINE); - font.setWeight((attr == ATR_BOLD) ? QFont::Bold : QFont::Normal); - item->setFont(font); - - QColor fg = item->foreground().color(); - QColor bg = item->background().color(); - if (attr == ATR_DIM) - { - fg.setAlpha(fg.alpha() / 2); - } - if (attr == ATR_INVERSE) - { - QColor swap; - swap = fg; fg = bg; bg = swap; - } - item->setForeground(fg); - item->setBackground(bg); -#endif - - // ATR_BLINK not supported - if (list->count() >= ::iflags.msg_history) - delete list->item(0); - list->addItem(text2); - - // Force scrollbar to bottom - list->setCurrentRow(list->count()-1); - - if ( map ) - map->putMessage(attr, text2); -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4plsel.cpp b/win/Qt4/qt4plsel.cpp deleted file mode 100644 index 81bf5f023..000000000 --- a/win/Qt4/qt4plsel.cpp +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4plsel.cpp -- player selector dialog - -extern "C" { -#include "hack.h" -} -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4plsel.h" -#include "qt4plsel.moc" -#include "qt4bind.h" -#include "qt4glyph.h" -#include "qt4set.h" -#include "qt4str.h" - -// Warwick prefers it this way... -#define QT_CHOOSE_RACE_FIRST - -namespace nethack_qt4 { - -// temporary -void centerOnMain( QWidget* w ); -// end temporary - -static const char nh_attribution[] = "
NetHack %1" - "
by the NetHack DevTeam
"; - -class NhPSListViewItem : public QTableWidgetItem { -public: - NhPSListViewItem( QTableWidget* parent, const QString& name ) : - QTableWidgetItem(name) - { - } - - void setGlyph(int g) - { - NetHackQtGlyphs& glyphs = qt_settings->glyphs(); - int gw = glyphs.width(); - int gh = glyphs.height(); - QPixmap pm(gw,gh); - QPainter p(&pm); - glyphs.drawGlyph(p, g, 0, 0); - p.end(); - setIcon(QIcon(pm)); - //RLC setHeight(std::max(pm.height()+1,height())); - } - -#if 0 //RLC - void paintCell( QPainter *p, const QColorGroup &cg, - int column, int width, int alignment ) - { - if ( isSelectable() ) { - QTableWidgetItem::paintCell( p, cg, column, width, alignment ); - } else { - QColorGroup disabled( - cg.foreground().light(), - cg.button().light(), - cg.light(), cg.dark(), cg.mid(), - Qt::gray, cg.base() ); - QTableWidgetItem::paintCell( p, disabled, column, width, alignment ); - } - } -#endif -}; - -class NhPSListViewRole : public NhPSListViewItem { -public: - NhPSListViewRole( QTableWidget* parent, int id ) : - NhPSListViewItem(parent, -#ifdef QT_CHOOSE_RACE_FIRST // Lowerize - looks better - QString(roles[id].name.m).toLower() -#else - roles[id].name.m -#endif - ) - { - setGlyph(monnum_to_glyph(roles[id].malenum)); - } -}; - -class NhPSListViewRace : public NhPSListViewItem { -public: - NhPSListViewRace( QTableWidget* parent, int id ) : - NhPSListViewItem(parent, -#ifdef QT_CHOOSE_RACE_FIRST // Capitalize - looks better - str_titlecase(races[id].noun) -#else - races[id].noun -#endif - ) - { - setGlyph(monnum_to_glyph(races[id].malenum)); - } -}; - -class NhPSListView : public QTableWidget { -public: - NhPSListView( QWidget* parent ) : - QTableWidget(parent) - { - setColumnCount(1); - verticalHeader()->hide(); -#if QT_VERSION >= 0x050000 - horizontalHeader()->setSectionsClickable(false); -#else - horizontalHeader()->setClickable(false); -#endif - } - - QSizePolicy sizePolicy() const - { - return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); - } - - QSize minimumSizeHint() const - { - return sizeHint(); - } - - QSize sizeHint() const - { - return QSize(columnWidth(0), QTableWidget::sizeHint().height()); - } -}; - -NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : - QDialog(NetHackQtBind::mainWidget()), - fully_specified_role(true) -{ - /* - 0 1 2 - + Name ------------------------------------+ - 0 | | - + ---- ------------------------------------+ - + Role ---+ + Race ---+ + Gender ------+ - | | | | | * Male | - 1 | | | | | * Female | - | | | | +--------------+ - | | | | - | | | | + Alignment ---+ - 2 | | | | | * Male | - | | | | | * Female | - | | | | +--------------+ - 3 | | | | ...stretch... - | | | | - 4 | | | | [ Random ] - 5 | | | | [ Play ] - 6 | | | | [ Quit ] - +---------+ +---------+ - */ - - QGridLayout *l = new QGridLayout(this); - l->setColumnStretch(2, 1); - sizePolicy().setHorizontalPolicy(QSizePolicy::Minimum); - - QGroupBox* namebox = new QGroupBox("Name", this); - QVBoxLayout *namelayout = new QVBoxLayout(namebox); - QLineEdit* name = new QLineEdit(namebox); - namelayout->addWidget(name); - name->setMaxLength(sizeof(plname)-1); - if ( strncmp(plname,"player",6) && strncmp(plname,"games",5) ) - name->setText(plname); - connect(name, SIGNAL(textChanged(const QString&)), - this, SLOT(selectName(const QString&)) ); - name->setFocus(); - QGroupBox* genderbox = new QGroupBox("Gender",this); - QButtonGroup *gendergroup = new QButtonGroup(this); - QGroupBox* alignbox = new QGroupBox("Alignment",this); - QButtonGroup *aligngroup = new QButtonGroup(this); - QVBoxLayout* vbgb = new QVBoxLayout(genderbox); - QVBoxLayout* vbab = new QVBoxLayout(alignbox); - char versionbuf[QBUFSZ]; - QLabel* logo = new QLabel(QString(nh_attribution).arg(version_string(versionbuf)), this); - - l->addWidget( namebox, 0,0,1,3 ); -#ifdef QT_CHOOSE_RACE_FIRST - race = new NhPSListView(this); - role = new NhPSListView(this); - l->addWidget( race, 1,0,6,1 ); - l->addWidget( role, 1,1,6,1 ); -#else - role = new NhPSListView(this); - race = new NhPSListView(this); - l->addWidget( role, 1,0,6,1 ); - l->addWidget( race, 1,1,6,1 ); -#endif - - l->addWidget( genderbox, 1, 2 ); - l->addWidget( alignbox, 2, 2 ); - l->addWidget( logo, 3, 2, Qt::AlignCenter ); - l->setRowStretch( 3, 6 ); - - int i; - int nrole; - - chosen_gend = flags.initgend; - chosen_align = flags.initalign; - - // XXX QListView unsorted goes in rev. - for (nrole=0; roles[nrole].name.m; nrole++) - ; - role->setRowCount(nrole); - for (i=0; roles[i].name.m; i++) { - QTableWidgetItem *item = new QTableWidgetItem( - QIcon(qt_settings->glyphs().glyph(roles[i].malenum)), - roles[i].name.m); - item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); - role->setItem(i, 0, item); - } - connect( role, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(selectRole(int, int, int, int)) ); - role->setHorizontalHeaderLabels(QStringList("Role")); - role->resizeColumnToContents(0); - - int nrace; - for (nrace=0; races[nrace].noun; nrace++) - ; - race->setRowCount(nrace); - for (i=0; races[i].noun; i++) { - QTableWidgetItem *item = new QTableWidgetItem( - QIcon(qt_settings->glyphs().glyph(races[i].malenum)), - races[i].noun); - item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); - race->setItem(i, 0, item); - } - connect( race, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(selectRace(int, int, int, int)) ); - race->setHorizontalHeaderLabels(QStringList("Race")); - race->resizeColumnToContents(0); - - gender = new QRadioButton*[ROLE_GENDERS]; - for (i=0; ilayout()->addWidget(gender[i]); - gendergroup->addButton(gender[i], i); - } - connect( gendergroup, SIGNAL(buttonPressed(int)), this, SLOT(selectGender(int)) ); - - alignment = new QRadioButton*[ROLE_ALIGNS]; - for (i=0; ilayout()->addWidget(alignment[i]); - aligngroup->addButton(alignment[i], i); - } - connect( aligngroup, SIGNAL(buttonPressed(int)), this, SLOT(selectAlignment(int)) ); - - QPushButton* rnd = new QPushButton("Random",this); - l->addWidget( rnd, 4, 2 ); - rnd->setDefault(false); - connect( rnd, SIGNAL(clicked()), this, SLOT(Randomize()) ); - - QPushButton* ok = new QPushButton("Play",this); - l->addWidget( ok, 5, 2 ); - ok->setDefault(true); - connect( ok, SIGNAL(clicked()), this, SLOT(accept()) ); - - QPushButton* cancel = new QPushButton("Quit",this); - l->addWidget( cancel, 6, 2 ); - connect( cancel, SIGNAL(clicked()), this, SLOT(reject()) ); - - Randomize(); -} - -void NetHackQtPlayerSelector::Randomize() -{ - int nrole = role->rowCount(); - int nrace = race->rowCount(); - - boolean picksomething = (flags.initrole == ROLE_NONE - || flags.initrace == ROLE_NONE - || flags.initgend == ROLE_NONE - || flags.initalign == ROLE_NONE); - - if (flags.randomall && picksomething) { - if (flags.initrole == ROLE_NONE) - flags.initrole = ROLE_RANDOM; - if (flags.initrace == ROLE_NONE) - flags.initrace = ROLE_RANDOM; - if (flags.initgend == ROLE_NONE) - flags.initgend = ROLE_RANDOM; - if (flags.initalign == ROLE_NONE) - flags.initalign = ROLE_RANDOM; - } - - rigid_role_checks(); - - // Randomize race and role, unless specified in config - int ro = flags.initrole; - if (ro == ROLE_NONE || ro == ROLE_RANDOM) { - ro = rn2(nrole); - if (flags.initrole != ROLE_RANDOM) { - fully_specified_role = false; - } - } - int ra = flags.initrace; - if (ra == ROLE_NONE || ra == ROLE_RANDOM) { - ra = rn2(nrace); - if (flags.initrace != ROLE_RANDOM) { - fully_specified_role = false; - } - } - - // make sure we have a valid combination, honoring - // the users request if possible. - bool choose_race_first; -#ifdef QT_CHOOSE_RACE_FIRST - choose_race_first = true; - if (flags.initrole >= 0 && flags.initrace < 0) { - choose_race_first = false; - } -#else - choose_race_first = false; - if (flags.initrace >= 0 && flags.initrole < 0) { - choose_race_first = true; - } -#endif - while (!validrace(ro,ra)) { - if (choose_race_first) { - ro = rn2(nrole); - if (flags.initrole != ROLE_RANDOM) { - fully_specified_role = false; - } - } else { - ra = rn2(nrace); - if (flags.initrace != ROLE_RANDOM) { - fully_specified_role = false; - } - } - } - - int g = flags.initgend; - if (g == -1) { - g = rn2(ROLE_GENDERS); - fully_specified_role = false; - } - while (!validgend(ro,ra,g)) { - g = rn2(ROLE_GENDERS); - } - gender[g]->setChecked(true); - selectGender(g); - - int a = flags.initalign; - if (a == -1) { - a = rn2(ROLE_ALIGNS); - fully_specified_role = false; - } - while (!validalign(ro,ra,a)) { - a = rn2(ROLE_ALIGNS); - } - alignment[a]->setChecked(true); - selectAlignment(a); - - role->setCurrentCell(ro, 0); - - race->setCurrentCell(ra, 0); -} - -void NetHackQtPlayerSelector::selectName(const QString& n) -{ - str_copy(plname,n.toLatin1().constData(),SIZE(plname)); -} - -void NetHackQtPlayerSelector::selectRole(int crow, int ccol, int prow, int pcol) -{ - int ra = race->currentRow(); - int ro = role->currentRow(); - if (ra == -1 || ro == -1) return; - QTableWidgetItem* item; - item = role->item(prow, 0); - if (item != NULL) - item->setSelected(false); - -#ifdef QT_CHOOSE_RACE_FIRST - selectRace(crow, ccol, prow, pcol); -#else - QTableWidgetItem* i=role->currentItem(); - QTableWidgetItem* valid=0; - int j; - for (j=0; roles[j].name.m; j++) { - bool v = validrace(j,ra); - item = role->item(j, 0); - item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); - if ( !valid && v ) valid = item; - } - if ( !validrace(role->currentRow(),ra) ) - i = valid; - role->setCurrentItem(i, 0); - for (j=0; roles[j].name.m; j++) { - item = role->item(j, 0); - item->setSelected(item == i); - bool v = validrace(j,ra); - item->setFlags( - v ? Qt::ItemIsEnabled|Qt::ItemIsSelectable - : Qt::NoItemFlags); - } -#endif - - //flags.initrole = role->currentRow(); - setupOthers(); -} - -void NetHackQtPlayerSelector::selectRace(int crow, int ccol, int prow, int pcol) -{ - int ra = race->currentRow(); - int ro = role->currentRow(); - if (ra == -1 || ro == -1) return; - QTableWidgetItem* item; - item = race->item(prow, 0); - if (item != NULL) - item->setSelected(false); - -#ifndef QT_CHOOSE_RACE_FIRST - selectRole(crow, ccol, prow, pcol); -#else - QTableWidgetItem* i=race->currentItem(); - QTableWidgetItem* valid=0; - int j; - for (j=0; races[j].noun; j++) { - bool v = validrace(ro,j); - item = race->item(j, 0); - item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); - if ( !valid && v ) valid = item; - } - if ( !validrace(ro,race->currentRow()) ) - i = valid; - for (j=0; races[j].noun; j++) { - item = race->item(j, 0); - item->setSelected(item == i); - bool v = validrace(ro,j); - item->setFlags( - v ? Qt::ItemIsEnabled|Qt::ItemIsSelectable - : Qt::NoItemFlags); - } -#endif - - //flags.initrace = race->currentRow(); - setupOthers(); -} - -void NetHackQtPlayerSelector::setupOthers() -{ - int ro = role->currentRow(); - int ra = race->currentRow(); - int valid=-1; - int c=0; - int j; - for (j=0; jisChecked() ) - c = j; - gender[j]->setEnabled(v); - if ( valid<0 && v ) valid = j; - } - if ( !validgend(ro,ra,c) ) - c = valid; - int k; - for (k=0; ksetChecked(c==k); - } - selectGender(c); - - valid=-1; - for (j=0; jisChecked() ) - c = j; - alignment[j]->setEnabled(v); - if ( valid<0 && v ) valid = j; - } - if ( !validalign(ro,ra,c) ) - c = valid; - for (k=0; ksetChecked(c==k); - } - selectAlignment(c); -} - -void NetHackQtPlayerSelector::selectGender(int i) -{ - chosen_gend = i; -} - -void NetHackQtPlayerSelector::selectAlignment(int i) -{ - chosen_align = i; -} - -void NetHackQtPlayerSelector::Quit() -{ - done(R_Quit); -} - -void NetHackQtPlayerSelector::Random() -{ - done(R_Rand); -} - -bool NetHackQtPlayerSelector::Choose() -{ - if (fully_specified_role) return true; - -#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). - if ( qt_compact_mode ) { - showMaximized(); - } else -#endif - { - adjustSize(); - centerOnMain(this); - } - - if ( exec() ) { - flags.initrace = race->currentRow(); - flags.initrole = role->currentRow(); - flags.initgend = chosen_gend; - flags.initalign = chosen_align; - return true; - } else { - return false; - } -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4set.cpp b/win/Qt4/qt4set.cpp deleted file mode 100644 index f9bfa246e..000000000 --- a/win/Qt4/qt4set.cpp +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4set.cpp -- the Qt settings - -#include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4set.h" -#include "qt4set.moc" -#include "qt4glyph.h" -#include "qt4str.h" - -/* Used by tile/font-size patch below and in ../../src/files.c */ -char *qt_tilewidth=NULL; -char *qt_tileheight=NULL; -char *qt_fontsize=NULL; -#if defined(QWS) -int qt_compact_mode = 1; -#else -int qt_compact_mode = 0; -#endif - -namespace nethack_qt4 { - -#define TILEWMIN 6 -#define TILEHMIN 6 - -NetHackQtSettings::NetHackQtSettings(int w, int h) : - settings(), - tilewidth(this), - tileheight(this), - widthlbl("&Width:",this), - heightlbl("&Height:",this), - whichsize("&Zoomed",this), - fontsize(this), - normal("times"), -#ifdef WS_WIN - normalfixed("courier new"), -#else - normalfixed("courier"), -#endif - large("times"), - theglyphs(0) - -{ - int default_fontsize; - - widthlbl.setBuddy(&tilewidth); - tilewidth.setRange(TILEWMIN, 128); - heightlbl.setBuddy(&tileheight); - tileheight.setRange(TILEHMIN, 128); - - tilewidth.setValue(settings.value("tilewidth", 16).toInt()); - tileheight.setValue(settings.value("tileheight", 16).toInt()); - default_fontsize = settings.value("fontsize", 2).toInt(); - - // Tile/font sizes read from .nethackrc - if (qt_tilewidth != NULL) { - tilewidth.setValue(atoi(qt_tilewidth)); - delete[] qt_tilewidth; - } - if (qt_tileheight != NULL) { - tileheight.setValue(atoi(qt_tileheight)); - delete[] qt_tileheight; - } - if (qt_fontsize != NULL) { - switch (tolower(qt_fontsize[0])) { - case 'h': default_fontsize = 0; break; - case 'l': default_fontsize = 1; break; - case 'm': default_fontsize = 2; break; - case 's': default_fontsize = 3; break; - case 't': default_fontsize = 4; break; - } - delete[] qt_fontsize; - } - - theglyphs=new NetHackQtGlyphs(); - resizeTiles(); - - connect(&tilewidth,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles())); - connect(&tileheight,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles())); - connect(&whichsize,SIGNAL(toggled(bool)),this,SLOT(setGlyphSize(bool))); - - fontsize.addItem("Huge"); - fontsize.addItem("Large"); - fontsize.addItem("Medium"); - fontsize.addItem("Small"); - fontsize.addItem("Tiny"); - fontsize.setCurrentIndex(default_fontsize); - connect(&fontsize,SIGNAL(activated(int)),this,SLOT(changedFont())); - - QGridLayout* grid = new QGridLayout(this); - grid->addWidget(&whichsize, 0, 0, 1, 2); - grid->addWidget(&tilewidth, 1, 1); grid->addWidget(&widthlbl, 1, 0); - grid->addWidget(&tileheight, 2, 1); grid->addWidget(&heightlbl, 2, 0); - QLabel* flabel=new QLabel("&Font:",this); - flabel->setBuddy(&fontsize); - grid->addWidget(flabel, 3, 0); grid->addWidget(&fontsize, 3, 1); - QPushButton* dismiss=new QPushButton("Dismiss",this); - dismiss->setDefault(true); - grid->addWidget(dismiss, 4, 0, 1, 2); - grid->setRowStretch(4,0); - grid->setColumnStretch(1,1); - grid->setColumnStretch(2,2); - grid->activate(); - - connect(dismiss,SIGNAL(clicked()),this,SLOT(accept())); - resize(150,140); -} - -NetHackQtGlyphs& NetHackQtSettings::glyphs() -{ - return *theglyphs; -} - -void NetHackQtSettings::changedFont() -{ - settings.setValue("fontsize", fontsize.currentIndex()); - emit fontChanged(); -} - -void NetHackQtSettings::resizeTiles() -{ - int w = tilewidth.value(); - int h = tileheight.value(); - - settings.setValue("tilewidth", tilewidth.value()); - settings.setValue("tileheight", tileheight.value()); - theglyphs->setSize(w,h); - emit tilesChanged(); -} - -void NetHackQtSettings::toggleGlyphSize() -{ - whichsize.toggle(); -} - -void NetHackQtSettings::setGlyphSize(bool which) -{ - QSize n = QSize(tilewidth.value(),tileheight.value()); - if ( othersize.isValid() ) { - tilewidth.blockSignals(true); - tileheight.blockSignals(true); - tilewidth.setValue(othersize.width()); - tileheight.setValue(othersize.height()); - tileheight.blockSignals(false); - tilewidth.blockSignals(false); - resizeTiles(); - } - othersize = n; -} - -const QFont& NetHackQtSettings::normalFont() -{ - static int size[]={ 18, 14, 12, 10, 8 }; - normal.setPointSize(size[fontsize.currentIndex()]); - return normal; -} - -const QFont& NetHackQtSettings::normalFixedFont() -{ - static int size[]={ 18, 14, 13, 10, 8 }; - normalfixed.setPointSize(size[fontsize.currentIndex()]); - return normalfixed; -} - -const QFont& NetHackQtSettings::largeFont() -{ - static int size[]={ 24, 18, 14, 12, 10 }; - large.setPointSize(size[fontsize.currentIndex()]); - return large; -} - -bool NetHackQtSettings::ynInMessages() -{ - return !qt_compact_mode && !iflags.wc_popup_dialog; -} - -NetHackQtSettings* qt_settings; - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4set.h b/win/Qt4/qt4set.h deleted file mode 100644 index 48b90f306..000000000 --- a/win/Qt4/qt4set.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4set.h -- the Qt settings - -#ifndef QT4SET_H -#define QT4SET_H - -namespace nethack_qt4 { - -class NetHackQtGlyphs; - -class NetHackQtSettings : public QDialog { - Q_OBJECT -public: - // Size of window - used to decide default sizes - NetHackQtSettings(int width, int height); - - NetHackQtGlyphs& glyphs(); - const QFont& normalFont(); - const QFont& normalFixedFont(); - const QFont& largeFont(); - - bool ynInMessages(); - -signals: - void fontChanged(); - void tilesChanged(); - -public slots: - void toggleGlyphSize(); - void setGlyphSize(bool); - -private: - QSettings settings; - QSpinBox tilewidth; - QSpinBox tileheight; - QLabel widthlbl; - QLabel heightlbl; - QCheckBox whichsize; - QSize othersize; - - QComboBox fontsize; - - QFont normal, normalfixed, large; - - NetHackQtGlyphs* theglyphs; - -private slots: - void resizeTiles(); - void changedFont(); -}; - -extern NetHackQtSettings* qt_settings; - -} // namespace nethack_qt4 - -#endif diff --git a/win/Qt4/qt4stat.cpp b/win/Qt4/qt4stat.cpp deleted file mode 100644 index 3a15604e5..000000000 --- a/win/Qt4/qt4stat.cpp +++ /dev/null @@ -1,540 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4stat.cpp -- bindings between the Qt 4 interface and the main code - -extern "C" { -#include "hack.h" -} -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4stat.h" -#include "qt4stat.moc" -#include "qt4set.h" -#include "qt4str.h" -#include "qt_xpms.h" - -extern const char *enc_stat[]; /* from botl.c */ -extern const char *hu_stat[]; /* from eat.c */ - -namespace nethack_qt4 { - -NetHackQtStatusWindow::NetHackQtStatusWindow() : - // Notes: - // Alignment needs -2 init value, because -1 is an alignment. - // Armor Class is an schar, so 256 is out of range. - // Blank value is 0 and should never change. - name(this,"(name)"), - dlevel(this,"(dlevel)"), - str(this,"STR"), - dex(this,"DEX"), - con(this,"CON"), - intel(this,"INT"), - wis(this,"WIS"), - cha(this,"CHA"), - gold(this,"Gold"), - hp(this,"Hit Points"), - power(this,"Power"), - ac(this,"Armour Class"), - level(this,"Level"), - exp(this,"Experience"), - align(this,"Alignment"), - time(this,"Time"), - score(this,"Score"), - hunger(this,""), - confused(this,"Confused"), - sick_fp(this,"Sick"), - sick_il(this,"Ill"), - blind(this,""), - stunned(this,"Stunned"), - hallu(this,"Hallu"), - encumber(this,""), - hline1(this), - hline2(this), - hline3(this), - first_set(true) -{ - p_str = QPixmap(str_xpm); - p_str = QPixmap(str_xpm); - p_dex = QPixmap(dex_xpm); - p_con = QPixmap(cns_xpm); - p_int = QPixmap(int_xpm); - p_wis = QPixmap(wis_xpm); - p_cha = QPixmap(cha_xpm); - - p_chaotic = QPixmap(chaotic_xpm); - p_neutral = QPixmap(neutral_xpm); - p_lawful = QPixmap(lawful_xpm); - - p_satiated = QPixmap(satiated_xpm); - p_hungry = QPixmap(hungry_xpm); - - p_confused = QPixmap(confused_xpm); - p_sick_fp = QPixmap(sick_fp_xpm); - p_sick_il = QPixmap(sick_il_xpm); - p_blind = QPixmap(blind_xpm); - p_stunned = QPixmap(stunned_xpm); - p_hallu = QPixmap(hallu_xpm); - - p_encumber[0] = QPixmap(slt_enc_xpm); - p_encumber[1] = QPixmap(mod_enc_xpm); - p_encumber[2] = QPixmap(hvy_enc_xpm); - p_encumber[3] = QPixmap(ext_enc_xpm); - p_encumber[4] = QPixmap(ovr_enc_xpm); - - str.setIcon(p_str); - dex.setIcon(p_dex); - con.setIcon(p_con); - intel.setIcon(p_int); - wis.setIcon(p_wis); - cha.setIcon(p_cha); - - align.setIcon(p_neutral); - hunger.setIcon(p_hungry); - - confused.setIcon(p_confused); - sick_fp.setIcon(p_sick_fp); - sick_il.setIcon(p_sick_il); - blind.setIcon(p_blind); - stunned.setIcon(p_stunned); - hallu.setIcon(p_hallu); - - encumber.setIcon(p_encumber[0]); - - hline1.setFrameStyle(QFrame::HLine|QFrame::Sunken); - hline2.setFrameStyle(QFrame::HLine|QFrame::Sunken); - hline3.setFrameStyle(QFrame::HLine|QFrame::Sunken); - hline1.setLineWidth(1); - hline2.setLineWidth(1); - hline3.setLineWidth(1); - -#if 1 //RLC - name.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - dlevel.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - QVBoxLayout *vbox = new QVBoxLayout(); - vbox->setSpacing(0); - vbox->addWidget(&name); - vbox->addWidget(&dlevel); - vbox->addWidget(&hline1); - QHBoxLayout *atr1box = new QHBoxLayout(); - atr1box->addWidget(&str); - atr1box->addWidget(&dex); - atr1box->addWidget(&con); - atr1box->addWidget(&intel); - atr1box->addWidget(&wis); - atr1box->addWidget(&cha); - vbox->addLayout(atr1box); - vbox->addWidget(&hline2); - QHBoxLayout *atr2box = new QHBoxLayout(); - atr2box->addWidget(&gold); - atr2box->addWidget(&hp); - atr2box->addWidget(&power); - atr2box->addWidget(&ac); - atr2box->addWidget(&level); - atr2box->addWidget(&exp); - vbox->addLayout(atr2box); - vbox->addWidget(&hline3); - QHBoxLayout *timebox = new QHBoxLayout(); - timebox->addWidget(&time); - timebox->addWidget(&score); - vbox->addLayout(timebox); - QHBoxLayout *statbox = new QHBoxLayout(); - statbox->addWidget(&align); - statbox->addWidget(&hunger); - statbox->addWidget(&confused); - statbox->addWidget(&sick_fp); - statbox->addWidget(&sick_il); - statbox->addWidget(&blind); - statbox->addWidget(&stunned); - statbox->addWidget(&hallu); - statbox->addWidget(&encumber); - statbox->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); - vbox->addLayout(statbox); - setLayout(vbox); -#endif - - connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate())); - doUpdate(); -} - -void NetHackQtStatusWindow::doUpdate() -{ - const QFont& large=qt_settings->largeFont(); - name.setFont(large); - dlevel.setFont(large); - - const QFont& normal=qt_settings->normalFont(); - str.setFont(normal); - dex.setFont(normal); - con.setFont(normal); - intel.setFont(normal); - wis.setFont(normal); - cha.setFont(normal); - gold.setFont(normal); - hp.setFont(normal); - power.setFont(normal); - ac.setFont(normal); - level.setFont(normal); - exp.setFont(normal); - align.setFont(normal); - time.setFont(normal); - score.setFont(normal); - hunger.setFont(normal); - confused.setFont(normal); - sick_fp.setFont(normal); - sick_il.setFont(normal); - blind.setFont(normal); - stunned.setFont(normal); - hallu.setFont(normal); - encumber.setFont(normal); - - updateStats(); -} - -QWidget* NetHackQtStatusWindow::Widget() { return this; } - -void NetHackQtStatusWindow::Clear() -{ -} -void NetHackQtStatusWindow::Display(bool block) -{ -} -void NetHackQtStatusWindow::CursorTo(int,int y) -{ - cursy=y; -} -void NetHackQtStatusWindow::PutStr(int attr, const QString& text) -{ - // do a complete update when line 0 is done (as per X11 fancy status) - if (cursy==0) updateStats(); -} - -#if 0 // RLC -void NetHackQtStatusWindow::resizeEvent(QResizeEvent*) -{ -#if 0 - const float SP_name=0.13; // the (large) - const float SP_dlev=0.13; // Level 3 in The Dungeons of Doom (large) - const float SP_atr1=0.25; // STR DEX CON INT WIS CHA - const float SP_hln1=0.02; // --- - const float SP_atr2=0.09; // Au HP PW AC LVL EXP - const float SP_hln2=0.02; // --- - const float SP_time=0.09; // time score - const float SP_hln3=0.02; // --- - const float SP_stat=0.25; // Alignment, Poisoned, Hungry, Sick, etc. - - int h=height(); - int x=0,y=0; - - int iw; // Width of an item across line - int lh; // Height of a line of values - - lh=int(h*SP_name); - name.setGeometry(0,0,width(),lh); y+=lh; - lh=int(h*SP_dlev); - dlevel.setGeometry(0,y,width(),lh); y+=lh; - - lh=int(h*SP_hln1); - hline1.setGeometry(0,y,width(),lh); y+=lh; - - lh=int(h*SP_atr1); - iw=width()/6; - str.setGeometry(x,y,iw,lh); x+=iw; - dex.setGeometry(x,y,iw,lh); x+=iw; - con.setGeometry(x,y,iw,lh); x+=iw; - intel.setGeometry(x,y,iw,lh); x+=iw; - wis.setGeometry(x,y,iw,lh); x+=iw; - cha.setGeometry(x,y,iw,lh); x+=iw; - x=0; y+=lh; - - lh=int(h*SP_hln2); - hline2.setGeometry(0,y,width(),lh); y+=lh; - - lh=int(h*SP_atr2); - iw=width()/6; - gold.setGeometry(x,y,iw,lh); x+=iw; - hp.setGeometry(x,y,iw,lh); x+=iw; - power.setGeometry(x,y,iw,lh); x+=iw; - ac.setGeometry(x,y,iw,lh); x+=iw; - level.setGeometry(x,y,iw,lh); x+=iw; - exp.setGeometry(x,y,iw,lh); x+=iw; - x=0; y+=lh; - - lh=int(h*SP_hln3); - hline3.setGeometry(0,y,width(),lh); y+=lh; - - lh=int(h*SP_time); - iw=width()/3; x+=iw/2; - time.setGeometry(x,y,iw,lh); x+=iw; - score.setGeometry(x,y,iw,lh); x+=iw; - x=0; y+=lh; - - lh=int(h*SP_stat); - iw=width()/9; - align.setGeometry(x,y,iw,lh); x+=iw; - hunger.setGeometry(x,y,iw,lh); x+=iw; - confused.setGeometry(x,y,iw,lh); x+=iw; - sick_fp.setGeometry(x,y,iw,lh); x+=iw; - sick_il.setGeometry(x,y,iw,lh); x+=iw; - blind.setGeometry(x,y,iw,lh); x+=iw; - stunned.setGeometry(x,y,iw,lh); x+=iw; - hallu.setGeometry(x,y,iw,lh); x+=iw; - encumber.setGeometry(x,y,iw,lh); x+=iw; - x=0; y+=lh; -#else - // This is clumsy. But QLayout objects are proving balky. - - int row[10]; - - row[0] = name.sizeHint().height(); - row[1] = dlevel.sizeHint().height(); - row[2] = h.sizeHint().height(); -#endif -} -#endif - - -/* - * Set all widget values to a null string. This is used after all spacings - * have been calculated so that when the window is popped up we don't get all - * kinds of funny values being displayed. - */ -void NetHackQtStatusWindow::nullOut() -{ -} - -void NetHackQtStatusWindow::fadeHighlighting() -{ - name.dissipateHighlight(); - dlevel.dissipateHighlight(); - - str.dissipateHighlight(); - dex.dissipateHighlight(); - con.dissipateHighlight(); - intel.dissipateHighlight(); - wis.dissipateHighlight(); - cha.dissipateHighlight(); - - gold.dissipateHighlight(); - hp.dissipateHighlight(); - power.dissipateHighlight(); - ac.dissipateHighlight(); - level.dissipateHighlight(); - exp.dissipateHighlight(); - align.dissipateHighlight(); - - time.dissipateHighlight(); - score.dissipateHighlight(); - - hunger.dissipateHighlight(); - confused.dissipateHighlight(); - sick_fp.dissipateHighlight(); - sick_il.dissipateHighlight(); - blind.dissipateHighlight(); - stunned.dissipateHighlight(); - hallu.dissipateHighlight(); - encumber.dissipateHighlight(); -} - -/* - * Update the displayed status. The current code in botl.c updates - * two lines of information. Both lines are always updated one after - * the other. So only do our update when we update the second line. - * - * Information on the first line: - * name, attributes, alignment, score - * - * Information on the second line: - * dlvl, gold, hp, power, ac, {level & exp or HD **} - * status (hunger, conf, halu, stun, sick, blind), time, encumbrance - * - * [**] HD is shown instead of level and exp if mtimedone is non-zero. - */ -void NetHackQtStatusWindow::updateStats() -{ - if (!parentWidget()) return; - - QString buf; - const char *text; - - if (cursy != 0) return; /* do a complete update when line 0 is done */ - - if (ACURR(A_STR) > 118) { - buf.sprintf("STR:%d",ACURR(A_STR)-100); - } else if (ACURR(A_STR)==118) { - buf.sprintf("STR:18/**"); - } else if(ACURR(A_STR) > 18) { - buf.sprintf("STR:18/%02d",ACURR(A_STR)-18); - } else { - buf.sprintf("STR:%d",ACURR(A_STR)); - } - str.setLabel(buf,NetHackQtLabelledIcon::NoNum,ACURR(A_STR)); - - dex.setLabel("DEX:",(long)ACURR(A_DEX)); - con.setLabel("CON:",(long)ACURR(A_CON)); - intel.setLabel("INT:",(long)ACURR(A_INT)); - wis.setLabel("WIS:",(long)ACURR(A_WIS)); - cha.setLabel("CHA:",(long)ACURR(A_CHA)); - const char* hung=hu_stat[u.uhs]; - if (hung[0]==' ') { - hunger.hide(); - } else { - hunger.setIcon(u.uhs ? p_hungry : p_satiated); - hunger.setLabel(hung); - hunger.show(); - } - if (Confusion) confused.show(); else confused.hide(); - if (Sick) { - if (u.usick_type & SICK_VOMITABLE) { - sick_fp.show(); - } else { - sick_fp.hide(); - } - if (u.usick_type & SICK_NONVOMITABLE) { - sick_il.show(); - } else { - sick_il.hide(); - } - } else { - sick_fp.hide(); - sick_il.hide(); - } - if (Blind) { - blind.setLabel("Blind"); - blind.show(); - } else { - blind.hide(); - } - if (Stunned) stunned.show(); else stunned.hide(); - if (Hallucination) hallu.show(); else hallu.hide(); - const char* enc=enc_stat[near_capacity()]; - if (enc[0]==' ' || !enc[0]) { - encumber.hide(); - } else { - encumber.setIcon(p_encumber[near_capacity()-1]); - encumber.setLabel(enc); - encumber.show(); - } - if (u.mtimedone) { - buf = nh_capitalize_words(mons[u.umonnum].mname); - } else { - buf = rank_of(u.ulevel, pl_character[0], ::flags.female); - } - QString buf2; - buf2.sprintf("%s the %s", plname, buf.toLatin1().constData()); - name.setLabel(buf2, NetHackQtLabelledIcon::NoNum, u.ulevel); - - char buf3[BUFSZ]; - if (describe_level(buf3)) { - dlevel.setLabel(buf3,true); - } else { - buf.sprintf("%s, level ", dungeons[u.uz.dnum].dname); - dlevel.setLabel(buf,(long)::depth(&u.uz)); - } - - gold.setLabel("Au:", money_cnt(invent)); - - if (u.mtimedone) { - // You're a monster! - - buf.sprintf("/%d", u.mhmax); - hp.setLabel("HP:", u.mh > 0 ? u.mh : 0, buf); - level.setLabel("HD:",(long)mons[u.umonnum].mlevel); - } else { - // You're normal. - - buf.sprintf("/%d", u.uhpmax); - hp.setLabel("HP:", u.uhp > 0 ? u.uhp : 0, buf); - level.setLabel("Level:",(long)u.ulevel); - } - buf.sprintf("/%d", u.uenmax); - power.setLabel("Pow:", u.uen, buf); - ac.setLabel("AC:",(long)u.uac); -#ifdef EXP_ON_BOTL - if (::flags.showexp) { - exp.setLabel("Exp:",(long)u.uexp); - } else -#endif - { - exp.setLabel(""); - } - if (u.ualign.type==A_CHAOTIC) { - align.setIcon(p_chaotic); - text = "Chaotic"; - } else if (u.ualign.type==A_NEUTRAL) { - align.setIcon(p_neutral); - text = "Neutral"; - } else { - align.setIcon(p_lawful); - text = "Lawful"; - } - align.setLabel(text); - - if (::flags.time) time.setLabel("Time:",(long)moves); - else time.setLabel(""); -#ifdef SCORE_ON_BOTL - if (::flags.showscore) { - score.setLabel("Score:",(long)botl_score()); - } else -#endif - { - score.setLabel(""); - } - - if (first_set) - { - first_set=false; - - name.highlightWhenChanging(); - dlevel.highlightWhenChanging(); - - str.highlightWhenChanging(); - dex.highlightWhenChanging(); - con.highlightWhenChanging(); - intel.highlightWhenChanging(); - wis.highlightWhenChanging(); - cha.highlightWhenChanging(); - - gold.highlightWhenChanging(); - hp.highlightWhenChanging(); - power.highlightWhenChanging(); - ac.highlightWhenChanging(); ac.lowIsGood(); - level.highlightWhenChanging(); - exp.highlightWhenChanging(); - align.highlightWhenChanging(); - - //time.highlightWhenChanging(); - score.highlightWhenChanging(); - - hunger.highlightWhenChanging(); - confused.highlightWhenChanging(); - sick_fp.highlightWhenChanging(); - sick_il.highlightWhenChanging(); - blind.highlightWhenChanging(); - stunned.highlightWhenChanging(); - hallu.highlightWhenChanging(); - encumber.highlightWhenChanging(); - } -} - -/* - * Turn off hilighted status values after a certain amount of turns. - */ -void NetHackQtStatusWindow::checkTurnEvents() -{ -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4stat.h b/win/Qt4/qt4stat.h deleted file mode 100644 index a0a00a46f..000000000 --- a/win/Qt4/qt4stat.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4stat.h -- bindings between the Qt 4 interface and the main code - -#ifndef QT4STAT_H -#define QT4STAT_H - -#include "qt4win.h" -#include "qt4icon.h" - -namespace nethack_qt4 { - -class NetHackQtStatusWindow : QWidget, public NetHackQtWindow { - Q_OBJECT -public: - NetHackQtStatusWindow(); - - virtual QWidget* Widget(); - - virtual void Clear(); - virtual void Display(bool block); - virtual void CursorTo(int x,int y); - virtual void PutStr(int attr, const QString& text); - - void fadeHighlighting(); - -protected: - //RLC void resizeEvent(QResizeEvent*); - -private slots: - void doUpdate(); - -private: - enum { hilight_time=1 }; - - QPixmap p_str; - QPixmap p_dex; - QPixmap p_con; - QPixmap p_int; - QPixmap p_wis; - QPixmap p_cha; - - QPixmap p_chaotic; - QPixmap p_neutral; - QPixmap p_lawful; - - QPixmap p_satiated; - QPixmap p_hungry; - - QPixmap p_confused; - QPixmap p_sick_fp; - QPixmap p_sick_il; - QPixmap p_blind; - QPixmap p_stunned; - QPixmap p_hallu; - - QPixmap p_encumber[5]; - - NetHackQtLabelledIcon name; - NetHackQtLabelledIcon dlevel; - - NetHackQtLabelledIcon str; - NetHackQtLabelledIcon dex; - NetHackQtLabelledIcon con; - NetHackQtLabelledIcon intel; - NetHackQtLabelledIcon wis; - NetHackQtLabelledIcon cha; - - NetHackQtLabelledIcon gold; - NetHackQtLabelledIcon hp; - NetHackQtLabelledIcon power; - NetHackQtLabelledIcon ac; - NetHackQtLabelledIcon level; - NetHackQtLabelledIcon exp; - NetHackQtLabelledIcon align; - - NetHackQtLabelledIcon time; - NetHackQtLabelledIcon score; - - NetHackQtLabelledIcon hunger; - NetHackQtLabelledIcon confused; - NetHackQtLabelledIcon sick_fp; - NetHackQtLabelledIcon sick_il; - NetHackQtLabelledIcon blind; - NetHackQtLabelledIcon stunned; - NetHackQtLabelledIcon hallu; - NetHackQtLabelledIcon encumber; - - QFrame hline1; - QFrame hline2; - QFrame hline3; - - int cursy; - - bool first_set; - - void nullOut(); - void updateStats(); - void checkTurnEvents(); -}; - -} // namespace nethack_qt4 - -#endif diff --git a/win/Qt4/qt4streq.cpp b/win/Qt4/qt4streq.cpp deleted file mode 100644 index abe910ff7..000000000 --- a/win/Qt4/qt4streq.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4streq.cpp -- string requestor - -#include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4streq.h" -#include "qt4str.h" - -namespace nethack_qt4 { - -// temporary -void centerOnMain(QWidget *); -// end temporary - -NetHackQtStringRequestor::NetHackQtStringRequestor(QWidget *parent, const char* p, const char* cancelstr) : - QDialog(parent), - prompt(QString::fromLatin1(p),this), - input(this,"input") -{ - cancel=new QPushButton(cancelstr,this); - connect(cancel,SIGNAL(clicked()),this,SLOT(reject())); - - okay=new QPushButton("Okay",this); - connect(okay,SIGNAL(clicked()),this,SLOT(accept())); - connect(&input,SIGNAL(returnPressed()),this,SLOT(accept())); - okay->setDefault(true); - - setFocusPolicy(Qt::StrongFocus); -} - -void NetHackQtStringRequestor::resizeEvent(QResizeEvent*) -{ - const int margin=5; - const int gutter=5; - - int h=(height()-margin*2-gutter); - - if (prompt.text().size() > 16) { - h/=3; - prompt.setGeometry(margin,margin,width()-margin*2,h); - input.setGeometry(width()*1/5,margin+h+gutter, - (width()-margin-2-gutter)*4/5,h); - } else { - h/=2; - prompt.setGeometry(margin,margin,(width()-margin*2-gutter)*2/5,h); - input.setGeometry(prompt.geometry().right()+gutter,margin, - (width()-margin-2-gutter)*3/5,h); - } - - cancel->setGeometry(margin,input.geometry().bottom()+gutter, - (width()-margin*2-gutter)/2,h); - okay->setGeometry(cancel->geometry().right()+gutter,cancel->geometry().y(), - cancel->width(),h); -} - -void NetHackQtStringRequestor::SetDefault(const char* d) -{ - input.setText(d); -} - -bool NetHackQtStringRequestor::Get(char* buffer, int maxchar) -{ - input.setMaxLength(maxchar); - if (prompt.text().size() > 16) { - resize(fontMetrics().width(prompt.text())+50,fontMetrics().height()*6); - } else { - resize(fontMetrics().width(prompt.text())*2+50,fontMetrics().height()*4); - } - -#ifdef EDIT_GETLIN - input.setText(buffer); -#endif - centerOnMain(this); - show(); - input.setFocus(); - exec(); - - if (result()) { - str_copy(buffer,input.text().toLatin1().constData(),maxchar); - return true; - } else { - return false; - } -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4streq.h b/win/Qt4/qt4streq.h deleted file mode 100644 index a5f05d769..000000000 --- a/win/Qt4/qt4streq.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4streq.h -- string requestor - -#ifndef QT4STREQ_H -#define QT4STREQ_H - -#include "qt4line.h" - -namespace nethack_qt4 { - -class NetHackQtStringRequestor : QDialog { -private: - QLabel prompt; - NetHackQtLineEdit input; - QPushButton* okay; - QPushButton* cancel; - -public: - NetHackQtStringRequestor(QWidget *parent, const char* p,const char* cancelstr="Cancel"); - void SetDefault(const char*); - bool Get(char* buffer, int maxchar=80); - virtual void resizeEvent(QResizeEvent*); -}; - -} // namespace nethack_qt4 - -#endif diff --git a/win/Qt4/qt4svsel.cpp b/win/Qt4/qt4svsel.cpp deleted file mode 100644 index 0b5271588..000000000 --- a/win/Qt4/qt4svsel.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4svsel.cpp -- saved game selector - -#include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4svsel.h" -#include "qt4bind.h" -#include "qt4str.h" - -namespace nethack_qt4 { - -NetHackQtSavedGameSelector::NetHackQtSavedGameSelector(const char** saved) : - QDialog(NetHackQtBind::mainWidget()) -{ - QVBoxLayout *vbl = new QVBoxLayout(this); - QHBoxLayout* hb; - - QLabel* logo = new QLabel(this); vbl->addWidget(logo); - logo->setAlignment(Qt::AlignCenter); - logo->setPixmap(QPixmap("nhsplash.xpm")); - QLabel* attr = new QLabel("by the NetHack DevTeam",this); - attr->setAlignment(Qt::AlignCenter); - vbl->addWidget(attr); - vbl->addStretch(2); - /* - QLabel* logo = new QLabel(hb); - hb = new QHBox(this); - vbl->addWidget(hb, Qt::AlignCenter); - logo->setPixmap(QPixmap(nh_icon)); - logo->setAlignment(AlignRight|Qt::AlignVCenter); - new QLabel(nh_attribution,hb); - */ - - hb = new QHBoxLayout(this); - vbl->addLayout(hb, Qt::AlignCenter); - QPushButton* q = new QPushButton("Quit",this); - hb->addWidget(q); - connect(q, SIGNAL(clicked()), this, SLOT(reject())); - QPushButton* c = new QPushButton("New Game",this); - hb->addWidget(c); - connect(c, SIGNAL(clicked()), this, SLOT(accept())); - c->setDefault(true); - - QGroupBox* box = new QGroupBox("Saved Characters",this); - QButtonGroup *bg = new QButtonGroup(this); - vbl->addWidget(box); - QVBoxLayout *bgl = new QVBoxLayout(box); - connect(bg, SIGNAL(buttonPressed(int)), this, SLOT(done(int))); - for (int i=0; saved[i]; i++) { - QPushButton* b = new QPushButton(saved[i],box); - bg->addButton(b, i+2); - } -} - -int NetHackQtSavedGameSelector::choose() -{ -#if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). - if ( qt_compact_mode ) - showMaximized(); -#endif - return exec()-2; -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4win.cpp b/win/Qt4/qt4win.cpp deleted file mode 100644 index ca0abe57b..000000000 --- a/win/Qt4/qt4win.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// Qt Binding for NetHack 3.4 -// -// Copyright (C) 1996-2001 by Warwick W. Allison (warwick@troll.no) -// -// Contributors: -// Michael Hohmuth -// - Userid control -// Svante Gerhard -// - .nethackrc tile and font size settings -// Dirk Schoenberger -// - KDE support -// - SlashEm support -// and many others for bug reports. -// -// Unfortunately, this doesn't use Qt as well as I would like, -// primarily because NetHack is fundamentally a getkey-type program -// rather than being event driven (hence the ugly key and click buffer) -// and also because this is my first major application of Qt. -// -// The problem of NetHack's getkey requirement is solved by intercepting -// key events by overiding QApplicion::notify(...), and putting them in -// a buffer. Mouse clicks on the map window are treated with a similar -// buffer. When the NetHack engine calls for a key, one is taken from -// the buffer, or if that is empty, QApplication::exec() is called. -// Whenever keys or clicks go into the buffer, QApplication::exit() -// is called. -// -// Another problem is that some NetHack players are decade-long players who -// demand complete keyboard control (while Qt and X11 conspire to make this -// difficult by having widget-based focus rather than application based - -// a good thing in general). This problem is solved by again using the key -// event buffer. -// -// Out of all this hackery comes a silver lining however, as macros for -// the super-expert and menus for the ultra-newbie are also made possible -// by the key event buffer. -// - -// This includes all the definitions we need from the NetHack main -// engine. We pretend MSC is a STDC compiler, because C++ is close -// enough, and we undefine NetHack macros which conflict with Qt -// identifiers. - -#define QT_DEPRECATED_WARNINGS -#include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4win.h" -#include "qt4bind.h" -#include "qt4click.h" -#include "qt4glyph.h" -#include "qt4inv.h" -#include "qt4key.h" -#include "qt4icon.h" -#include "qt4map.h" -#include "qt4menu.h" -#include "qt4msg.h" -#include "qt4set.h" - -#include - -#include "qt4clust.h" - -#include - -#ifdef _WS_X11_ -// For userid control -#include -#endif - -#ifdef USER_SOUNDS -#if QT_VERSION >= 0x050000 -# include -# else -# include -# endif -#endif - - -#ifdef USER_SOUNDS -extern void play_sound_for_message(const std::string& str); -#endif - -namespace nethack_qt4 { - -void -centerOnMain( QWidget* w ) -{ - QWidget* m = NetHackQtBind::mainWidget(); - if (!m) m = qApp->desktop(); - QPoint p = m->mapToGlobal(QPoint(0,0)); - w->move( p.x() + m->width()/2 - w->width()/2, - p.y() + m->height()/2 - w->height()/2 ); -} - -NetHackQtWindow::NetHackQtWindow() -{ -} -NetHackQtWindow::~NetHackQtWindow() -{ -} - -// XXX Use "expected ..." for now, abort or default later. -// -void NetHackQtWindow::Clear() { puts("unexpected Clear"); } -void NetHackQtWindow::Display(bool block) { puts("unexpected Display"); } -bool NetHackQtWindow::Destroy() { return true; } -void NetHackQtWindow::CursorTo(int x,int y) { puts("unexpected CursorTo"); } -void NetHackQtWindow::PutStr(int attr, const QString& text) { puts("unexpected PutStr"); } -void NetHackQtWindow::StartMenu() { puts("unexpected StartMenu"); } -void NetHackQtWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const QString& str, bool presel) { puts("unexpected AddMenu"); } -void NetHackQtWindow::EndMenu(const QString& prompt) { puts("unexpected EndMenu"); } -int NetHackQtWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) { puts("unexpected SelectMenu"); return 0; } -void NetHackQtWindow::ClipAround(int x,int y) { puts("unexpected ClipAround"); } -void NetHackQtWindow::PrintGlyph(int x,int y,int glyph) { puts("unexpected PrintGlyph"); } -//void NetHackQtWindow::PrintGlyphCompose(int x,int y,int,int) { puts("unexpected PrintGlyphCompose"); } -void NetHackQtWindow::UseRIP(int how, time_t when) { puts("unexpected UseRIP"); } - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4xcmd.cpp b/win/Qt4/qt4xcmd.cpp deleted file mode 100644 index 7c078f640..000000000 --- a/win/Qt4/qt4xcmd.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4xcmd.cpp -- extended command widget - -#include "hack.h" -#include "func_tab.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4xcmd.h" -#include "qt4xcmd.moc" -#include "qt4bind.h" -#include "qt4set.h" -#include "qt4str.h" - -namespace nethack_qt4 { - -// temporary -void centerOnMain(QWidget *); -// end temporary - -NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(QWidget *parent) : - QDialog(parent) -{ - QVBoxLayout *l = new QVBoxLayout(this); - - QPushButton* can = new QPushButton("Cancel", this); - can->setDefault(true); - can->setMinimumSize(can->sizeHint()); - l->addWidget(can); - - prompt = new QLabel("#", this); - l->addWidget(prompt); - - QButtonGroup *group=new QButtonGroup(this); - QGroupBox *grid=new QGroupBox("Extended commands",this); - l->addWidget(grid); - - int i; - int butw=50; - QFontMetrics fm = fontMetrics(); - for (i=0; extcmdlist[i].ef_txt; i++) { - butw = std::max(butw,30+fm.width(extcmdlist[i].ef_txt)); - } - int ncols=4; - - QVBoxLayout* bl = new QVBoxLayout(grid); - bl->addSpacing(fm.height()); - QGridLayout* gl = new QGridLayout(); - bl->addLayout(gl); - for (i=0; extcmdlist[i].ef_txt; i++) { - QPushButton* pb=new QPushButton(extcmdlist[i].ef_txt, grid); - pb->setMinimumSize(butw,pb->sizeHint().height()); - group->addButton(pb, i+1); - gl->addWidget(pb,i/ncols,i%ncols); - buttons.append(pb); - } - group->addButton(can, 0); - connect(group,SIGNAL(buttonPressed(int)),this,SLOT(done(int))); - - bl->activate(); - l->activate(); - resize(1,1); -} - -void NetHackQtExtCmdRequestor::cancel() -{ - reject(); -} - -void NetHackQtExtCmdRequestor::keyPressEvent(QKeyEvent *event) -{ - QString text = event->text(); - if (text == "\r" || text == "\n" || text == " " || text == "\033") - { - reject(); - } - else if (text == "\b") - { - QString promptstr = prompt->text(); - if (promptstr != "#") - prompt->setText(promptstr.left(promptstr.size()-1)); - enableButtons(); - } - else - { - QString promptstr = prompt->text() + text; - QString typedstr = promptstr.mid(1); // skip the '#' - unsigned matches = 0; - unsigned match = 0; - for (unsigned i=0; extcmdlist[i].ef_txt; i++) { - if (QString(extcmdlist[i].ef_txt).startsWith(typedstr)) { - ++matches; - if (matches >= 2) - break; - match = i; - } - } - if (matches == 1) - done(match+1); - else if (matches >= 2) - prompt->setText(promptstr); - enableButtons(); - } -} - -int NetHackQtExtCmdRequestor::get() -{ - const int none = -10; - resize(1,1); // pack - centerOnMain(this); - // Add any keys presently buffered to the prompt - setResult(none); - while (NetHackQtBind::qt_kbhit() && result() == none) { - int ch = NetHackQtBind::qt_nhgetch(); - QKeyEvent event(QEvent::KeyPress, 0, Qt::NoModifier, QChar(ch)); - keyPressEvent(&event); - } - if (result() == none) - exec(); - return result()-1; -} - -// Enable only buttons that match the current prompt string -void NetHackQtExtCmdRequestor::enableButtons() -{ - QString typedstr = prompt->text().mid(1); // skip the '#' - std::size_t len = typedstr.size(); - - for (auto b = buttons.begin(); b != buttons.end(); ++b) { - (*b)->setVisible((*b)->text().left(len) == typedstr); - } -} - -} // namespace nethack_qt4 diff --git a/win/Qt4/qt4xcmd.h b/win/Qt4/qt4xcmd.h deleted file mode 100644 index 338ef3370..000000000 --- a/win/Qt4/qt4xcmd.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4xcmd.h -- extended command widget - -#ifndef QT4XCMD_H -#define QT4XCMD_H - -namespace nethack_qt4 { - -class NetHackQtExtCmdRequestor : public QDialog { - Q_OBJECT - -protected: - virtual void keyPressEvent(QKeyEvent *event); - -public: - NetHackQtExtCmdRequestor(QWidget *parent); - int get(); - -private: - QLabel *prompt; - QVector buttons; - void enableButtons(); - -private slots: - void cancel(); -}; - -} // namespace nethack_qt4 - -#endif diff --git a/win/Qt4/qt4yndlg.cpp b/win/Qt4/qt4yndlg.cpp deleted file mode 100644 index e315189de..000000000 --- a/win/Qt4/qt4yndlg.cpp +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) Warwick Allison, 1999. -// Qt4 conversion copyright (c) Ray Chason, 2012-2014. -// NetHack may be freely redistributed. See license for details. - -// qt4yndlg.cpp -- yes/no dialog - -#include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max - -#include -#if QT_VERSION >= 0x050000 -#include -#endif -#include "qt4yndlg.h" -#include "qt4yndlg.moc" -#include "qt4str.h" - -// temporary -extern int qt_compact_mode; -// end temporary - -namespace nethack_qt4 { - -// temporary -void centerOnMain(QWidget *); -// end temporary - -NetHackQtYnDialog::NetHackQtYnDialog(QWidget *parent,const QString& q,const char* ch,char df) : - QDialog(parent), - question(q), choices(ch), def(df), - keypress('\033') -{ - setWindowTitle("NetHack: Question"); -} - -char NetHackQtYnDialog::Exec() -{ - QString ch(QString::fromLatin1(choices)); - int ch_per_line=6; - QString qlabel; - QString enable; - if ( qt_compact_mode && !choices ) { - ch = ""; - // expand choices from prompt - // ##### why isn't choices set properly??? - int c = question.indexOf(QChar('[')); - qlabel = QString(question).left(c); - if ( c >= 0 ) { - c++; - if ( question[c] == '-' ) - ch.append(question[c++]); - unsigned from=0; - while ( c < question.size() && question[c] != ']' && question[c] != ' ' ) { - if ( question[c] == '-' ) { - from = question[c-1].unicode(); - } else if ( from != 0 ) { - for (unsigned f=from+1; f<=question[c]; f++) - ch.append(QChar(f)); - from = 0; - } else { - ch.append(question[c]); - from = 0; - } - c++; - } - if ( question[c] == ' ' ) { - while ( c < question.size() && question[c] != ']' ) { - if ( question[c] == '*' || question[c] == '?' ) - ch.append(question[c]); - c++; - } - } - } - if ( question.indexOf("what direction") >= 0 ) { - // We replace this regardless, since sometimes you get choices. - const char* d = Cmd.dirchars; - enable=ch; - ch=""; - ch.append(d[1]); - ch.append(d[2]); - ch.append(d[3]); - ch.append(d[0]); - ch.append('.'); - ch.append(d[4]); - ch.append(d[7]); - ch.append(d[6]); - ch.append(d[5]); - ch.append(d[8]); - ch.append(d[9]); - ch_per_line = 3; - def = ' '; - } else { - // Hmm... they'll have to use a virtual keyboard - } - } else { - ch = QString::fromLatin1(choices); - qlabel = question.replace(QChar(0x200B), QString("")); - } - if (!ch.isNull()) { - QVBoxLayout *vb = new QVBoxLayout; - bool bigq = qlabel.length()>40; - if ( bigq ) { - QLabel* q = new QLabel(qlabel,this); - q->setAlignment(Qt::AlignLeft); - q->setWordWrap(true); - q->setMargin(4); - vb->addWidget(q); - } - QGroupBox *group = new QGroupBox(bigq ? QString::null : qlabel, this); - vb->addWidget(group); - QHBoxLayout *groupbox = new QHBoxLayout(); - group->setLayout(groupbox); - QButtonGroup *bgroup = new QButtonGroup(group); - - int nchoices=ch.length(); - - bool allow_count=ch.contains('#'); - QString yn = "yn", ynq = "ynq"; - bool is_ynq = ch == yn || ch == ynq; - - const int margin=8; - const int gutter=8; - const int extra=fontMetrics().height(); // Extra for group - int x=margin, y=extra+margin; - int butsize=fontMetrics().height()*2+5; - - QPushButton* button; - for (int i=0; isetEnabled(false); - } - button->setFixedSize(butsize,butsize); // Square - if (ch[i]==def) button->setDefault(true); - if (i%10==9) { - // last in row - x=margin; - y+=butsize+gutter; - } else { - x+=butsize+gutter; - } - groupbox->addWidget(button); - bgroup->addButton(button, i); - } - - connect(bgroup,SIGNAL(buttonClicked(int)),this,SLOT(doneItem(int))); - - QLabel* lb=0; - QLineEdit* le=0; - - if (allow_count) { - QHBoxLayout *hb = new QHBoxLayout(this); - lb=new QLabel("Count: "); - hb->addWidget(lb); - le=new QLineEdit(); - hb->addWidget(le); - vb->addLayout(hb); - } - - setLayout(vb); - adjustSize(); - centerOnMain(this); - show(); - char choice=0; - char ch_esc=0; - for (uint i=0; i= 1000 ) { - choice = ch[result() - 1000].unicode(); - } - if (allow_count && !le->text().isEmpty()) { - yn_number=le->text().toInt(); - choice='#'; - } - return choice; - } else { - QLabel label(qlabel,this); - QPushButton cancel("Dismiss",this); - label.setFrameStyle(QFrame::Box|QFrame::Sunken); - label.setAlignment(Qt::AlignCenter); - label.resize(fontMetrics().width(qlabel)+60,30+fontMetrics().height()); - cancel.move(width()/2-cancel.width()/2,label.geometry().bottom()+8); - connect(&cancel,SIGNAL(clicked()),this,SLOT(reject())); - centerOnMain(this); - setResult(-1); - show(); - keypress = '\033'; - exec(); - return keypress; - } -} - -void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event) -{ - // Don't want QDialog's Return/Esc behaviour - //RLC ...or do we? - QString text(event->text()); - if (choices == NULL || choices[0] == 0) { - if (text != "") { - keypress = text.toUcs4()[0]; - done(1); - } - } else { - int where = QString::fromLatin1(choices).indexOf(text); - if (where != -1 && text != "#") { - done(where+1000); - } else { - QDialog::keyPressEvent(event); - } - } -} - -void NetHackQtYnDialog::doneItem(int i) -{ - done(i+1000); -} - -} // namespace nethack_qt4 diff --git a/win/X11/Install.X11 b/win/X11/Install.X11 index a3fe45831..0f822aeb7 100644 --- a/win/X11/Install.X11 +++ b/win/X11/Install.X11 @@ -96,7 +96,7 @@ aren't familiar, talk to your local X11 guru and read the man pages. nethack.sh automatically adds HACKDIR to your font search path. If you (assuming you are a system administrator) can install the fonts in your -standard X11 font directory the relevent lines in nethack.sh can be removed. +standard X11 font directory the relevant lines in nethack.sh can be removed. Alternatively, all persons playing nethack must add that "xset fp+" command to their .xinitrc file, or whatever file they execute when starting X11. See the note below for the alternative installation procedure @@ -128,39 +128,6 @@ support is only a small, optional, part of nethack, and the Makefile is needed for systems that don't use X11. -Notes for Sun's OpenWindows: - 1. For OpenWindows 3.0 (NOT 2.x), define OPENWINBUG in include/unixconf.h. - The library bug from SunOS 4.1.x is fixed in Solaris 2.x (or when - proper Sun patches have been applied to 4.1.x), so it is also - unnecessary there. (Defining it when unnecessary causes the same - problem being avoided when it is necessary. :-) - - 2. In addition to the changes suggested by the comments in src/Makefile, - - -- for OpenWindows 2.x and 3.0 (NOT 3.1) (i.e., versions for SunOS 4.x), - add -I/usr/openwin/include to CFLAGS, -L/usr/openwin/lib to LFLAGS, - and -lm to WINX11LIB in src/Makefile. - - -- for OpenWindows 3.1 (i.e., versions for Solaris 2.x), add - -I/usr/openwin/include to CFLAGS, -L/usr/openwin/lib -L/usr/ccs/lib - -R/usr/openwin/lib to LFLAGS, and -lsocket -lnsl -lm - to WINX11LIB in src/Makefile. - - (Naturally, if your OpenWindows is installed elsewhere, adapt the - openwin paths.) This will allow you to create a game executable. - - 3. Run the fonts through convertfont and run bldfamily on the directory. - Now you must let your X server know where to find the fonts. For a - personal installation, the simplest thing is to include the directory - of the fonts in the environment variable FONTPATH, as set in your - .profile or .login before starting the server. For a multi-user - installation, you have the various "xset fp+" options outlined - above for standard X. - - 4. Something must still be done with the NetHack.ad file -- all three - of the possibilities mentioned for standard X11 should work. - - Notes for AIX 3.2: 1. AIX 3.2 includes the Athena Widget Toolkit library (and other things) under the /usr/lpp/X11/Xamples tree, so you will have to add @@ -170,8 +137,7 @@ Notes for AIX 3.2: Notes for XFree86 - (on linux and BSD386 platforms) - 1. Edit src/Makefile for linux/BSD386. Even though you use the - Open Look Window manager, do not define OPENWINBUG. Use the + 1. Edit src/Makefile for linux/BSD386. Use the standard X11 object and library options. 2. Follow the standard installation directions defined above. diff --git a/win/X11/NetHack.ad b/win/X11/NetHack.ad index 755fa58a7..c10d1360f 100644 --- a/win/X11/NetHack.ad +++ b/win/X11/NetHack.ad @@ -1,4 +1,4 @@ -! $NHDT-Date: 1542244983 2018/11/15 01:23:03 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.20 $ +! $NHDT-Date: 1750598195 2025/06/22 05:16:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.27 $ ! Copyright (c) 2017 by Pasi Kallinen ! NetHack may be freely redistributed. See license for details. @@ -30,7 +30,9 @@ NetHack*text*borderWidth: 0 ! tile_file names a file containing full-color tiles for the map. ! If you use a 100dpi (or greater) monitor you may wish to double the ! tile size so you can see the figures. If NetHack was compiled to -! use XPM (USE_XPM in config.h), the tile_file is a standard XPM file. +! use XPM (via #define USE_XPM in config.h or via -DUSE_XPM in src/Makefile, +! which happens when using WANT_WIN_X11=1 or WANT_WIN_ALL=1 with setup.sh +! 'hints' that support such), the tile_file is a standard XPM file. ! Otherwise, it is a custom format. double_tile_size only applies to ! the custom format - to enlarge an XPM file, use processing tools ! such as XV or preferably PBMplus. @@ -54,7 +56,7 @@ NetHack.tile_file: x11tiles !NetHack.tombtext_y: 78 !NetHack.tombtext_dx: 0 !NetHack.tombtext_dy: 13 -! The color to use for the text on the hero's tombstone +! The color to use for the text on the tombstone of the hero (end of game). NetHack*rip*foreground: black ! The icon to use; supported values are nh72, nh56, and nh32; nh72 is the @@ -66,7 +68,7 @@ NetHack*rip*foreground: black ! questions is _not_ used. Single-character prompts appear in a fixed ! position between the top of the map and the bottom of the messages. ! If False, popups appear near where the pointer is positioned so tend to -! meander around the screen depending upon where the last click ocurred. +! meander around the screen depending upon where the last click occurred. ! (The name 'slow' is misleading; this feature was originally necessitated ! by window managers which were slow putting up popup windows, but the ! fixed-position prompting can be just as useful for quick popups.) @@ -78,7 +80,7 @@ NetHack*rip*foreground: black !NetHack*autofocus: True ! If 'slow' is True, setting 'highlight_prompt' to True will cause the line -! between map and message display that's used for prompting to be "hidden" +! between map and message display that is used for prompting to be "hidden" ! as part of the map when no prompt is active, then invert foreground and ! background to stand out when a prompt is issued and waiting for a response. ! If 'slow' is False, 'highlight_prompt' will have no effect. @@ -87,7 +89,7 @@ NetHack*highlight_prompt: False ! The number of lines the message window will show without scrolling. !NetHack*message_lines: 12 -! If True, the message window has a line that seperates old and new messages. +! If True, the message window has a line that separates old and new messages. !NetHack*message_line: True ! If True, the default, use a "fancy" style status area below the map. @@ -114,8 +116,8 @@ NetHack*message*translations: : input() ! !Down: input(j) ! Specify the number of rows and columns of the map window. The default -! is the standard 80x21 window. Note: this _does_not_ change nethack's -! level size, only what you see of it. +! is the standard 80x21 window. Note: this _does_not_ change the size of +! level maps, only what you see of them. !NetHack*map*rows: 21 !NetHack*map*columns: 80 @@ -321,7 +323,7 @@ NetHack*map*orange: orange NetHack*map*bright_green: green NetHack*map*yellow: yellow NetHack*map*bright_blue: Royal blue -NetHack*map*bright_magenta: Fuchsia +NetHack*map*bright_magenta: magenta NetHack*map*bright_cyan: cyan NetHack*map*white: white ! diff --git a/win/X11/Window.c b/win/X11/Window.c index 09c753f33..645193a77 100644 --- a/win/X11/Window.c +++ b/win/X11/Window.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 Window.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ -/* Copyright (c) Dean Luick, 1992 */ +/* NetHack 5.0 Window.c $NHDT-Date: 1596498371 2020/08/03 23:46:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ +/* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* @@ -31,8 +31,9 @@ #include "xwindowp.h" -#include "config.h" -#include "lint.h" +#include "config.h" /* #define for const for non __STDC__ compilers */ +#include "lint.h" /* for nethack's nhStr() macro */ +#include "winX.h" /* to make sure prototypes match corresponding functions */ static XtResource resources[] = { #define offset(field) XtOffset(WindowWidget, window.field) @@ -90,11 +91,10 @@ static XtResource resources[] = { /* ARGSUSED */ static void -no_op(w, event, params, num_params) -Widget w; /* unused */ -XEvent *event; /* unused */ -String *params; /* unused */ -Cardinal *num_params; /* unused */ +no_op(Widget w, /* unused */ + XEvent *event, /* unused */ + String *params, /* unused */ + Cardinal *num_params) /* unused */ { nhUse(w); nhUse(event); @@ -113,10 +113,7 @@ static char translations[] = ": input() \ /* ARGSUSED */ static void -Redisplay(w, event, region) -Widget w; -XEvent *event; -Region region; /* unused */ +Redisplay(Widget w, XEvent *event, Region region /* unused */) { nhUse(region); @@ -126,62 +123,59 @@ Region region; /* unused */ /* ARGSUSED */ static void -Resize(w) -Widget w; +Resize(Widget w) { XtCallCallbacks(w, XtNresizeCallback, (XtPointer) 0); } WindowClassRec windowClassRec = { { /* core fields */ - /* superclass */ (WidgetClass) &widgetClassRec, - /* class_name */ nhStr("Window"), - /* widget_size */ sizeof(WindowRec), - /* class_initialize */ 0, - /* class_part_initialize */ 0, - /* class_inited */ FALSE, - /* initialize */ 0, - /* initialize_hook */ 0, - /* realize */ XtInheritRealize, - /* actions */ actions, - /* num_actions */ XtNumber(actions), - /* resources */ resources, - /* num_resources */ XtNumber(resources), - /* xrm_class */ NULLQUARK, - /* compress_motion */ TRUE, - /* compress_exposure */ TRUE, - /* compress_enterleave */ TRUE, - /* visible_interest */ FALSE, - /* destroy */ 0, - /* resize */ Resize, - /* expose */ Redisplay, - /* set_values */ 0, - /* set_values_hook */ 0, - /* set_values_almost */ XtInheritSetValuesAlmost, - /* get_values_hook */ 0, - /* accept_focus */ 0, - /* version */ XtVersion, - /* callback_private */ 0, - /* tm_table */ translations, - /* query_geometry */ XtInheritQueryGeometry, - /* display_accelerator */ XtInheritDisplayAccelerator, - /* extension */ 0 }, + /* superclass */ (WidgetClass) &widgetClassRec, + /* class_name */ nhStr("Window"), + /* widget_size */ sizeof(WindowRec), + /* class_initialize */ 0, + /* class_part_initialize */ 0, + /* class_inited */ FALSE, + /* initialize */ 0, + /* initialize_hook */ 0, + /* realize */ XtInheritRealize, + /* actions */ actions, + /* num_actions */ XtNumber(actions), + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ TRUE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ TRUE, + /* visible_interest */ FALSE, + /* destroy */ 0, + /* resize */ Resize, + /* expose */ Redisplay, + /* set_values */ 0, + /* set_values_hook */ 0, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ 0, + /* accept_focus */ 0, + /* version */ XtVersion, + /* callback_private */ 0, + /* tm_table */ translations, + /* query_geometry */ XtInheritQueryGeometry, + /* display_accelerator */ XtInheritDisplayAccelerator, + /* extension */ 0 }, { /* window fields */ - /* empty */ 0 } + /* empty */ 0 } }; WidgetClass windowWidgetClass = (WidgetClass) &windowClassRec; Font -WindowFont(w) -Widget w; +WindowFont(Widget w) { return ((WindowWidget) w)->window.font->fid; } XFontStruct * -WindowFontStruct(w) -Widget w; +WindowFontStruct(Widget w) { return ((WindowWidget) w)->window.font; } diff --git a/win/X11/X11-issues.txt b/win/X11/X11-issues.txt new file mode 100644 index 000000000..82b72f6bf --- /dev/null +++ b/win/X11/X11-issues.txt @@ -0,0 +1,25 @@ +When persistent inventory window is first populated, focus is given to +its window (behavior might be window manager-specific; it happens with +default window manager on OSX). Focus should be explicitly directed +back to the main window. + +More focus: although the menu window gets focus, the menu inside that +window does not accept focus, so scrolling persistent inventory via +keyboard won't work. [Does not affect the new '|' command which takes +input via yn_function() rather than directly from the perm_invent menu.] + +When persistent inventory window is displayed, an update that ought to +make it grow won't do so even if there is room on the screen for that. +It will add scrollbar(s) when not already there, and it can be resized +manually. + +If the permsistent inventory window is manually made taller, it will +fill that space immediately. But if it is made wider, handling of the +extra space seems to be erratic and it is sometimes left blank until +window is dismissed and re-created via 'i' or toggling 'perm_invent'. + +Menus which have entries that are too wide to display have their wide +lines truncated rather than adding a horizontal scrollbar. Resizing +larger doesn't recover truncated text and resizing smaller truncates +even more. + diff --git a/win/X11/dialogs.c b/win/X11/dialogs.c index 988f6edbb..11664c198 100644 --- a/win/X11/dialogs.c +++ b/win/X11/dialogs.c @@ -44,7 +44,7 @@ * + 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 + * to suppress "warning: assignment discards qualifiers from pointer * target type" issued by 'gcc -Wwrite-strings' as used by nethack. * (For this file, always the second parameter to XtSetArg().) * @@ -77,8 +77,12 @@ #undef PRESERVE_NO_SYSV #endif +#define X11_BUILD #include "config.h" /* #define for const for non __STDC__ compilers */ +#undef X11_BUILD + #include "lint.h" /* for nethack's nhStr() macro */ +#include "winX.h" /* to make sure prototypes match corresponding functions */ /* ":" added to both translations below to allow limited redefining of * keysyms before testing for keysym values -- dlc */ @@ -96,11 +100,8 @@ static const char cancel_accelerators[] = "#override\n\ * an optional cancel button */ Widget -CreateDialog(parent, name, okay_callback, cancel_callback) -Widget parent; -String name; -XtCallbackProc okay_callback; -XtCallbackProc cancel_callback; +CreateDialog(Widget parent, String name, XtCallbackProc okay_callback, + XtCallbackProc cancel_callback) { Widget form, prompt, response, okay, cancel; Arg args[20]; @@ -217,8 +218,7 @@ XtCallbackProc cancel_callback; /* get the prompt from the dialog box. Used a startup time to * save away the initial prompt */ String -GetDialogPrompt(w) - Widget w; +GetDialogPrompt(Widget w) { Arg args[1]; Widget label; @@ -233,9 +233,7 @@ GetDialogPrompt(w) /* set the prompt. This is used to put error information in the prompt */ void -SetDialogPrompt(w, newprompt) -Widget w; -String newprompt; +SetDialogPrompt(Widget w, String newprompt) { Arg args[1]; Widget label; @@ -247,8 +245,7 @@ String newprompt; /* get what the user typed; caller must free the response */ String -GetDialogResponse(w) -Widget w; +GetDialogResponse(Widget w) { Arg args[1]; Widget response; @@ -260,12 +257,9 @@ Widget w; return XtNewString(s); } -/* set the default reponse */ +/* set the default response */ void -SetDialogResponse(w, s, ln) -Widget w; -String s; -unsigned ln; +SetDialogResponse(Widget w, String s, unsigned ln) { Arg args[4]; Widget response; @@ -295,8 +289,7 @@ unsigned ln; #if 0 /* clear the response */ void -ClearDialogResponse(w) - Widget w; +ClearDialogResponse(Widget w) { Arg args[2]; Widget response; @@ -312,9 +305,7 @@ ClearDialogResponse(w) /* position popup window under the cursor */ void -positionpopup(w, bottom) -Widget w; -boolean bottom; /* position y on bottom? */ +positionpopup(Widget w, boolean bottom) /* position y on bottom? */ { Arg args[3]; Cardinal num_args; diff --git a/win/X11/ibm.bdf b/win/X11/ibm.bdf index f2b77f31b..399d6dff5 100644 --- a/win/X11/ibm.bdf +++ b/win/X11/ibm.bdf @@ -3616,7 +3616,7 @@ fd00 3800 3600 ENDCHAR -STARTCHAR magic sheild 3 +STARTCHAR magic shield 3 ENCODING 171 SWIDTH 666 0 DWIDTH 8 0 diff --git a/win/X11/nethack.rc b/win/X11/nethack.rc index cc6a88277..417679492 100644 --- a/win/X11/nethack.rc +++ b/win/X11/nethack.rc @@ -84,3 +84,8 @@ OPTIONS=catname:Ghisteslwchlohm # 048 035 064 042 \ # 047 045 092 124 124 092 045 047 \ # 047 064 092 064 064 064 092 064 047 + +# CRASHREPORTURL must be set in syscf to enable these options. +# These identify you in crash reports +#OPTIONS=crash_name:Your Name +#OPTIONS=crash_email:user@example.com diff --git a/win/X11/nh32icon b/win/X11/nh32icon index 422ad63db..553ea2d92 100644 --- a/win/X11/nh32icon +++ b/win/X11/nh32icon @@ -1,4 +1,4 @@ -/* NetHack 3.6 nh32icon $NHDT-Date: 1446457887 2015/11/02 09:51:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 5.0 nh32icon $NHDT-Date: 1597001766 2020/08/09 19:36:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (C) 1993,1995,2015 by Robert Patrick Rankin */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,8 +10,8 @@ static unsigned char nh32icon_bits[] = { 0xff, 0x7f, 0xfe, 0xff, 0x01, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x40, 0x82, 0x21, 0x25, 0xc0, 0x83, 0x61, 0x25, 0x80, 0x81, 0xe1, 0x3d, 0x80, 0x81, 0xa1, 0x25, 0x80, 0x81, 0x21, 0x25, 0x80, 0x81, 0x01, 0x00, 0xe0, 0x87, - 0x71, 0x08, 0x90, 0x89, 0x81, 0x08, 0x80, 0x81, 0x61, 0x38, 0x80, 0x81, - 0x81, 0x48, 0x80, 0x81, 0x71, 0x32, 0x84, 0x81, 0x03, 0x00, 0x8a, 0xc1, + 0x71, 0x78, 0x90, 0x89, 0x81, 0x40, 0x80, 0x81, 0x61, 0x20, 0x80, 0x81, + 0x81, 0x10, 0x80, 0x81, 0x71, 0x12, 0x84, 0x81, 0x03, 0x00, 0x8a, 0xc1, 0x02, 0x00, 0x84, 0x41, 0x32, 0x67, 0x80, 0x41, 0xf3, 0x7f, 0x80, 0xc1, 0xf1, 0x7f, 0x84, 0x81, 0x71, 0x77, 0x8a, 0x81, 0xb1, 0x68, 0x84, 0x81, 0x71, 0x77, 0x80, 0x81, 0x71, 0x77, 0x80, 0x81, 0xb1, 0x68, 0x84, 0x81, diff --git a/win/X11/nh56icon b/win/X11/nh56icon index 69b4e8248..6d6156672 100644 --- a/win/X11/nh56icon +++ b/win/X11/nh56icon @@ -1,4 +1,4 @@ -/* NetHack 3.6 nh56icon $NHDT-Date: 1446457887 2015/11/02 09:51:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 5.0 nh56icon $NHDT-Date: 1597001767 2020/08/09 19:36:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) 1993,1995,2015 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ @@ -25,12 +25,12 @@ static unsigned char nh56icon_bits[] = { 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, - 0xc0, 0x43, 0x10, 0x21, 0x38, 0x70, 0x40, 0xc0, 0xc3, 0x10, 0x21, 0x38, - 0x88, 0x20, 0xc0, 0xc3, 0x10, 0x21, 0x38, 0x80, 0x20, 0xc0, 0x43, 0x11, - 0x21, 0x38, 0x80, 0x20, 0xc0, 0x43, 0x12, 0x3f, 0x38, 0x70, 0xe0, 0xc1, - 0x43, 0x12, 0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x14, 0x21, 0x38, 0x80, - 0x20, 0xc2, 0x43, 0x18, 0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x18, 0x21, - 0x38, 0x88, 0x2c, 0xc2, 0x43, 0x10, 0x21, 0x38, 0x70, 0xcc, 0xc1, 0x03, + 0xc0, 0x43, 0x10, 0x21, 0x38, 0x70, 0xe0, 0xc3, 0xc3, 0x10, 0x21, 0x38, + 0x88, 0x00, 0xc2, 0xc3, 0x10, 0x21, 0x38, 0x80, 0x00, 0xc2, 0x43, 0x11, + 0x21, 0x38, 0x80, 0x00, 0xc1, 0x43, 0x12, 0x3f, 0x38, 0x70, 0x00, 0xc1, + 0x43, 0x12, 0x21, 0x38, 0x80, 0x80, 0xc0, 0x43, 0x14, 0x21, 0x38, 0x80, + 0x80, 0xc0, 0x43, 0x18, 0x21, 0x38, 0x80, 0x40, 0xc0, 0x43, 0x18, 0x21, + 0x38, 0x88, 0x4c, 0xc0, 0x43, 0x10, 0x21, 0x38, 0x70, 0x4c, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0xfb, 0xff, 0xff, 0x39, 0xff, 0xff, 0xdf, 0x0b, 0x00, 0x80, 0x7c, 0x02, 0x00, 0xd0, 0x0b, 0x00, 0x80, 0xee, 0x02, 0x00, 0xd0, 0xfb, 0xff, diff --git a/win/X11/nh72icon b/win/X11/nh72icon index acc824d01..55ac15767 100644 --- a/win/X11/nh72icon +++ b/win/X11/nh72icon @@ -1,4 +1,4 @@ -/* NetHack 3.6 nh72icon $NHDT-Date: 1446457888 2015/11/02 09:51:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 5.0 nh72icon $NHDT-Date: 1596498370 2020/08/03 23:46:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) 1993 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/X11/tile2x11.c b/win/X11/tile2x11.c index 774b6e636..ce9726049 100644 --- a/win/X11/tile2x11.c +++ b/win/X11/tile2x11.c @@ -7,8 +7,8 @@ * by nethack. * * Assumptions: - * + Two dimensional byte arrays are in row order and are not padded - * between rows (x11_colormap[][]). + * + Two dimensional byte arrays are in row order and are not padded + * between rows (x11_colormap[][]). */ #include "hack.h" /* for MAX_GLYPH */ #include "tile.h" @@ -22,10 +22,12 @@ unsigned char tile_bytes[TILE_X * TILE_Y * (MAX_GLYPH + TILES_PER_ROW)]; unsigned char *curr_tb = tile_bytes; unsigned char x11_colormap[MAXCOLORMAPSIZE][3]; +extern void monst_globals_init(void); +extern void objects_globals_init(void); + /* Look up the given pixel and return its colormap index. */ static unsigned char -pix_to_colormap(pix) -pixel pix; +pix_to_colormap(pixel pix) { unsigned long i; @@ -46,9 +48,8 @@ pixel pix; /* Convert the tiles in the file to our format of bytes. */ static unsigned long -convert_tiles(tb_ptr, total) -unsigned char **tb_ptr; /* pointer to a tile byte pointer */ -unsigned long total; /* total tiles so far */ +convert_tiles(unsigned char **tb_ptr, /* pointer to a tile byte pointer */ + unsigned long total) /* total tiles so far */ { unsigned char *tb = *tb_ptr; unsigned long count = 0; @@ -76,7 +77,7 @@ unsigned long total; /* total tiles so far */ /* Merge the current text colormap (ColorMap) with ours (x11_colormap). */ static void -merge_text_colormap() +merge_text_colormap(void) { unsigned i, j; @@ -109,8 +110,7 @@ merge_text_colormap() /* Open the given file, read & merge the colormap, convert the tiles. */ static void -process_file(fname) -char *fname; +process_file(char *fname) { unsigned long count; @@ -127,8 +127,7 @@ char *fname; #ifdef USE_XPM static int -xpm_write(fp) -FILE *fp; +xpm_write(FILE *fp) { unsigned long i, j; unsigned n; @@ -140,7 +139,7 @@ FILE *fp; } Fprintf(fp, "/* XPM */\n"); - Fprintf(fp, "static char* nhtiles[] = {\n"); + Fprintf(fp, "static char *nhtiles[] = {\n"); Fprintf(fp, "\"%lu %lu %lu %d\",\n", header.tile_width * header.per_row, (header.tile_height * header.ntiles) / header.per_row, header.ncolors, 1 /* char per color */); @@ -166,9 +165,7 @@ FILE *fp; #endif /* USE_XPM */ int -main(argc, argv) -int argc; -char **argv; +main(int argc, char *argv[]) { FILE *fp; int i; @@ -187,6 +184,10 @@ char **argv; exit(1); } + /* without this, the comparisons check uninitialized data and won't pass */ + objects_globals_init(); + monst_globals_init(); + fp = fopen(OUTNAME, "w"); if (!fp) { Fprintf(stderr, "can't open output file\n"); @@ -239,3 +240,6 @@ char **argv; fclose(fp); return 0; } + +/*tile2X11.c*/ + diff --git a/win/X11/winX.c b/win/X11/winX.c index 961acd21b..24fb4fcff 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -1,10 +1,10 @@ -/* NetHack 3.6 winX.c $NHDT-Date: 1552441031 2019/03/13 01:37:11 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.73 $ */ +/* NetHack 5.0 winX.c $NHDT-Date: 1717967337 2024/06/09 21:08:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.136 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * "Main" file for the X window-port. This contains most of the interface - * routines. Please see doc/window.doc for an description of the window + * routines. Please see doc/window.txt for an description of the window * interface. */ @@ -16,6 +16,14 @@ #define SHORT_FILENAMES #endif +/* Can't use #ifdef LINUX because no header files have been processed yet. + * This is needed to ensure the prototype for seteuid() is picked up when + * the header files are processed. + */ +#ifdef __linux__ +#define _POSIX_C_SOURCE 200809 +#endif + #include #include #include @@ -46,7 +54,10 @@ #undef SHORT_FILENAMES /* hack.h will reset via global.h if necessary */ #endif +#define X11_BUILD #include "hack.h" +#undef X11_BUILD + #include "winX.h" #include "dlb.h" #include "xwindow.h" @@ -71,43 +82,61 @@ static struct icon_info { const char *name; unsigned char *bits; unsigned width, height; -} icon_data[] = { { "nh72", nh72icon_bits, nh72icon_width, nh72icon_height }, - { "nh56", nh56icon_bits, nh56icon_width, nh56icon_height }, - { "nh32", nh32icon_bits, nh32icon_width, nh32icon_height }, - { (const char *) 0, (unsigned char *) 0, 0, 0 } }; +} icon_data[] = { + { "nh72", nh72icon_bits, nh72icon_width, nh72icon_height }, + { "nh56", nh56icon_bits, nh56icon_width, nh56icon_height }, + { "nh32", nh32icon_bits, nh32icon_width, nh32icon_height }, + { (const char *) 0, (unsigned char *) 0, 0, 0 } +}; /* * Private global variables (shared among the window port files). */ struct xwindow window_list[MAX_WINDOWS]; AppResources appResources; -void FDECL((*input_func), (Widget, XEvent *, String *, Cardinal *)); +void (*input_func)(Widget, XEvent *, String *, Cardinal *); int click_x, click_y, click_button; /* Click position on a map window * (filled by set_button_values()). */ -int updated_inventory; +int updated_inventory; /* used to indicate perm_invent updating */ +color_attr X11_menu_promptstyle = { NO_COLOR, ATR_NONE }; -static void FDECL(X11_error_handler, (String)) NORETURN; -static int FDECL(X11_io_error_handler, (Display *)); +/* X11/Intrinsic.h prototype has an issue if [[NORETURN]] is used + * rather than the old __attribute((noreturn)) under c23 */ +#if defined(__GNUC__) || defined(__clang__) +#define USE_GNUC_PROTO +#endif -static int FDECL((*old_error_handler), (Display *, XErrorEvent *)); +#ifdef USE_GNUC_PROTO +static void X11_error_handler(String) __attribute__((noreturn)); +#else +ATTRNORETURN static XtErrorHandler X11_error_handler(String); +#endif +static int X11_io_error_handler(Display *); + +static int (*old_error_handler)(Display *, XErrorEvent *); + +#if defined(HANGUPHANDLING) #if !defined(NO_SIGNAL) && defined(SAFERHANGUP) #if XtSpecificationRelease >= 6 #define X11_HANGUP_SIGNAL static XtSignalId X11_sig_id; #endif #endif +#endif /* Interface definition, for windows.c */ struct window_procs X11_procs = { - "X11", - (WC_COLOR | WC_HILITE_PET | WC_ASCII_MAP | WC_TILED_MAP - | WC_PLAYER_SELECTION | WC_PERM_INVENT | WC_MOUSE_SUPPORT), -#if defined(STATUS_HILITES) - WC2_FLUSH_STATUS | WC2_RESET_STATUS | WC2_HILITE_STATUS | + WPID(X11), + ( WC_COLOR | WC_INVERSE | WC_HILITE_PET | WC_ASCII_MAP | WC_TILED_MAP + | WC_PLAYER_SELECTION | WC_PERM_INVENT | WC_MOUSE_SUPPORT ), + /* status requires VIA_WINDOWPORT(); WC2_FLUSH_STATUS ensures that */ + ( WC2_FLUSH_STATUS | WC2_SELECTSAVED +#ifdef STATUS_HILITES + | WC2_RESET_STATUS | WC2_HILITE_STATUS #endif - 0L, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ + | WC2_MENU_SHIFT ), + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ X11_init_nhwindows, X11_player_selection, X11_askname, X11_get_nh_event, X11_exit_nhwindows, X11_suspend_nhwindows, X11_resume_nhwindows, X11_create_nhwindow, @@ -115,7 +144,7 @@ struct window_procs X11_procs = { X11_putstr, genl_putmixed, X11_display_file, X11_start_menu, X11_add_menu, X11_end_menu, X11_select_menu, genl_message_menu, /* no need for X-specific handling */ - X11_update_inventory, X11_mark_synch, X11_wait_synch, + X11_mark_synch, X11_wait_synch, #ifdef CLIPPING X11_cliparound, #endif @@ -128,8 +157,6 @@ struct window_procs X11_procs = { #ifdef CHANGE_COLOR /* only a Mac option currently */ donull, donull, #endif - /* other defs that really should go away (they're tty specific) */ - X11_start_screen, X11_end_screen, #ifdef GRAPHIC_TOMBSTONE X11_outrip, #else @@ -139,38 +166,39 @@ struct window_procs X11_procs = { X11_status_init, X11_status_finish, X11_status_enablefield, X11_status_update, genl_can_suspend_no, /* XXX may not always be correct */ + X11_update_inventory, + X11_ctrl_nhwindow, }; /* * Local functions. */ -static winid NDECL(find_free_window); -#ifdef TEXTCOLOR -static void FDECL(nhFreePixel, (XtAppContext, XrmValuePtr, XtPointer, - XrmValuePtr, Cardinal *)); -#endif -static boolean FDECL(new_resource_macro, (String, unsigned)); -static void NDECL(load_default_resources); -static void NDECL(release_default_resources); -static int FDECL(panic_on_error, (Display *, XErrorEvent *)); +static winid find_free_window(void); +static void nhFreePixel(XtAppContext, XrmValuePtr, XtPointer, XrmValuePtr, + Cardinal *); +static boolean new_resource_macro(String, unsigned); +static void load_default_resources(void); +static void release_default_resources(void); +static int panic_on_error(Display *, XErrorEvent *); #ifdef X11_HANGUP_SIGNAL -static void FDECL(X11_sig, (int)); -static void FDECL(X11_sig_cb, (XtPointer, XtSignalId *)); +static void X11_sig(int); +static void X11_sig_cb(XtPointer, XtSignalId *); #endif -static void FDECL(d_timeout, (XtPointer, XtIntervalId *)); -static void FDECL(X11_hangup, (Widget, XEvent *, String *, Cardinal *)); -static void FDECL(askname_delete, (Widget, XEvent *, String *, Cardinal *)); -static void FDECL(askname_done, (Widget, XtPointer, XtPointer)); -static void FDECL(done_button, (Widget, XtPointer, XtPointer)); -static void FDECL(getline_delete, (Widget, XEvent *, String *, Cardinal *)); -static void FDECL(abort_button, (Widget, XtPointer, XtPointer)); -static void NDECL(release_getline_widgets); -static void FDECL(yn_delete, (Widget, XEvent *, String *, Cardinal *)); -static void FDECL(yn_key, (Widget, XEvent *, String *, Cardinal *)); -static void NDECL(release_yn_widgets); -static int FDECL(input_event, (int)); -static void FDECL(win_visible, (Widget, XtPointer, XEvent *, Boolean *)); -static void NDECL(init_standard_windows); +static void d_timeout(XtPointer, XtIntervalId *); +static void X11_hangup(Widget, XEvent *, String *, Cardinal *); +ATTRNORETURN static void X11_bail(const char *) NORETURN; +static void askname_delete(Widget, XEvent *, String *, Cardinal *); +static void askname_done(Widget, XtPointer, XtPointer); +static void done_button(Widget, XtPointer, XtPointer); +static void getline_delete(Widget, XEvent *, String *, Cardinal *); +static void abort_button(Widget, XtPointer, XtPointer); +static void release_getline_widgets(void); +static void yn_delete(Widget, XEvent *, String *, Cardinal *); +static void yn_key(Widget, XEvent *, String *, Cardinal *); +static void release_yn_widgets(void); +static int input_event(int); +static void win_visible(Widget, XtPointer, XEvent *, Boolean *); +static void init_standard_windows(void); /* * Local variables. @@ -182,9 +210,7 @@ static winid message_win = WIN_ERR, /* These are the winids of the message, */ static Pixmap icon_pixmap = None; /* Pixmap for icon. */ void -X11_putmsghistory(msg, is_restoring) -const char *msg; -boolean is_restoring; +X11_putmsghistory(const char *msg, boolean is_restoring) { if (WIN_MESSAGE != WIN_ERR) { struct xwindow *wp = &window_list[WIN_MESSAGE]; @@ -195,8 +221,7 @@ boolean is_restoring; } char * -X11_getmsghistory(init) -boolean init; +X11_getmsghistory(boolean init) { if (WIN_MESSAGE != WIN_ERR) { static struct line_element *curr = (struct line_element *) 0; @@ -226,8 +251,7 @@ boolean init; * that this is not the popup widget, nor the viewport, but the child. */ struct xwindow * -find_widget(w) -Widget w; +find_widget(Widget w) { int windex; struct xwindow *wp; @@ -251,7 +275,7 @@ Widget w; * Find a free window slot for use. */ static winid -find_free_window() +find_free_window(void) { int windex; struct xwindow *wp; @@ -268,9 +292,7 @@ find_free_window() XColor -get_nhcolor(wp, clr) -struct xwindow *wp; -int clr; +get_nhcolor(struct xwindow *wp, int clr) { init_menu_nhcolors(wp); /* FIXME: init_menu_nhcolors may fail */ @@ -282,8 +304,7 @@ int clr; } void -init_menu_nhcolors(wp) -struct xwindow *wp; +init_menu_nhcolors(struct xwindow *wp) { static const char *mapCLR_to_res[CLR_MAX] = { XtNblack, @@ -303,6 +324,9 @@ struct xwindow *wp; XtNbright_cyan, XtNwhite, }; + static const char *wintypenames[NHW_TEXT] = { + "message", "status", "map", "menu", "text" + }; Display *dpy; Colormap screen_colormap; XrmDatabase rDB; @@ -310,13 +334,8 @@ struct xwindow *wp; Status rc; int color; char *ret_type[32]; - char clr_name[BUFSZ]; - char clrclass[BUFSZ]; - const char *wintypenames[NHW_TEXT] = { - "message", "status", "map", "menu", "text" - }; + char wtn_up[20], clr_name[BUFSZ], clrclass[BUFSZ]; const char *wtn; - char wtn_up[BUFSZ]; if (wp->nh_colors_inited || !wp->type) return; @@ -402,18 +421,18 @@ XtConvertArgRec const nhcolorConvertArgs[] = { * Return True if something close was found. */ Boolean -nhApproxColor(screen, colormap, str, color) -Screen *screen; /* screen to use */ -Colormap colormap; /* the colormap to use */ -char *str; /* color name */ -XColor *color; /* the X color structure; changed only if successful */ +nhApproxColor( + Screen *screen, /* screen to use */ + Colormap colormap, /* the colormap to use */ + char *str, /* color name */ + XColor *color) /* the X color structure; changed only if successful */ { int ncells; long cdiff = 16777216; /* 2^24; hopefully our map is smaller */ XColor tmp; static XColor *table = 0; - register int i, j; - register long tdiff; + int i, j; + long tdiff; /* if the screen doesn't have a big colormap, don't waste our time or if it's huge, and _some_ match should have been possible */ @@ -435,10 +454,10 @@ XColor *color; /* the X color structure; changed only if successful */ XQueryColors(DisplayOfScreen(screen), colormap, table, ncells); } -/* go thru cells and look for the one with smallest diff */ -/* diff is calculated abs(reddiff)+abs(greendiff)+abs(bluediff) */ -/* a more knowledgeable color person might improve this -dlc */ -try_again: + /* go thru cells and look for the one with smallest diff; + diff is calculated abs(reddiff)+abs(greendiff)+abs(bluediff); + a more knowledgeable color person might improve this -dlc */ + try_again: for (i = 0; i < ncells; i++) { if (table[i].flags == tmp.flags) { j = (int) table[i].red - (int) tmp.red; @@ -478,13 +497,11 @@ XColor *color; /* the X color structure; changed only if successful */ } Boolean -nhCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret) -Display *dpy; -XrmValuePtr args; -Cardinal *num_args; -XrmValuePtr fromVal; -XrmValuePtr toVal; -XtPointer *closure_ret; +nhCvtStringToPixel( + Display *dpy, + XrmValuePtr args, Cardinal *num_args, + XrmValuePtr fromVal, XrmValuePtr toVal, + XtPointer *closure_ret) { String str = (String) fromVal->addr; XColor screenColor; @@ -573,9 +590,10 @@ XtPointer *closure_ret; /* Ask the WM for window frame size */ void -get_window_frame_extents(w, top, bottom, left, right) -Widget w; -long *top, *bottom, *left, *right; +get_window_frame_extents( + Widget w, + long *top, long *bottom, + long *left, long *right) { XEvent event; Display *dpy = XtDisplay(w); @@ -587,32 +605,56 @@ long *top, *bottom, *left, *right; unsigned char *data = 0; long *extents; + *top = *bottom = *left = *right = 0L; + prop = XInternAtom(dpy, "_NET_FRAME_EXTENTS", True); + if (prop == None) { + /* + * FIXME! + */ +#ifdef MACOS + /* + * Default window manager doesn't support _NET_FRAME_EXTENTS. + * Without this position tweak, the persistent inventory window + * creeps downward by approximately the height of its title bar + * and also a smaller amount to the left every time it gets + * updated. Caveat: amount determined by trial and error and + * could change depending upon monitor resolution.... + * + * This hack could be improved by implementing the anti-creep + * value as an X resource so that player can adjust it. + */ + *top = 22L; +#endif + return; + } while (XGetWindowProperty(dpy, win, prop, 0, 4, False, AnyPropertyType, &retprop, &retfmt, &nitems, &nbytes, &data) != Success - || nitems != 4 || nbytes != 0) - { - XNextEvent(dpy, &event); - } + || nitems != 4 || nbytes != 0) { + XNextEvent(dpy, &event); + } extents = (long *) data; - - *left = extents[0]; - *right = extents[1]; - *top = extents[2]; - *bottom = extents[3]; + if (extents) { + *left = extents[0]; + *right = extents[1]; + *top = extents[2]; + *bottom = extents[3]; + } } void -get_widget_window_geometry(w, x,y, width, height) -Widget w; -int *x, *y, *width, *height; +get_widget_window_geometry( + Widget w, + int *x, int *y, + int *width, int *height) { long top, bottom, left, right; Arg args[5]; + XtSetArg(args[0], nhStr(XtNx), x); XtSetArg(args[1], nhStr(XtNy), y); XtSetArg(args[2], nhStr(XtNwidth), width); @@ -625,8 +667,7 @@ int *x, *y, *width, *height; /* Change the full font name string so the weight is "bold" */ char * -fontname_boldify(fontname) -const char *fontname; +fontname_boldify(const char *fontname) { static char buf[BUFSZ]; char *bufp = buf; @@ -652,9 +693,7 @@ const char *fontname; } void -load_boldfont(wp, w) -struct xwindow *wp; -Widget w; +load_boldfont(struct xwindow *wp, Widget w) { Arg args[1]; XFontStruct *fs; @@ -676,15 +715,14 @@ Widget w; wp->boldfs = XLoadQueryFont(dpy, fontname); } -#ifdef TEXTCOLOR /* ARGSUSED */ static void -nhFreePixel(app, toVal, closure, args, num_args) -XtAppContext app; -XrmValuePtr toVal; -XtPointer closure; -XrmValuePtr args; -Cardinal *num_args; +nhFreePixel( + XtAppContext app, + XrmValuePtr toVal, + XtPointer closure, + XrmValuePtr args, + Cardinal *num_args) { Screen *screen; Colormap colormap; @@ -704,14 +742,12 @@ Cardinal *num_args; (unsigned long *) toVal->addr, 1, (unsigned long) 0); } } -#endif /*TEXTCOLOR*/ /* [ALI] Utility function to ask Xaw for font height, since the previous * assumption of ascent + descent is not always valid. */ Dimension -nhFontHeight(w) -Widget w; +nhFontHeight(Widget w) { #ifdef _XawTextSink_h Widget sink; @@ -742,9 +778,9 @@ static String *default_resource_data = 0, /* NULL-terminated arrays */ /* caller found "#define"; parse into macro name and its expansion value */ static boolean -new_resource_macro(inbuf, numdefs) -String inbuf; /* points past '#define' rather than to start of buffer */ -unsigned numdefs; /* array slot to fill */ +new_resource_macro( + String inbuf, /* points past '#define' rather than to start of buffer */ + unsigned numdefs) /* array slot to fill */ { String p, q; @@ -769,7 +805,7 @@ unsigned numdefs; /* array slot to fill */ ++q; /* skip whitespace between name and value */ for (p = eos(q); --p > q && (*p == ' ' || *p == '\t'); ) continue; /* discard trailing whitespace */ - *++p = '\0'; /* q..p containes macro value */ + *++p = '\0'; /* q..p contains macro value */ def_rsrc_valu[numdefs] = dupstr(q); return TRUE; } @@ -777,7 +813,7 @@ unsigned numdefs; /* array slot to fill */ /* read the template NetHack.ad into default_resource_data[] to supply fallback resources to XtAppInitialize() */ static void -load_default_resources() +load_default_resources(void) { FILE *fp; String inbuf; @@ -815,7 +851,7 @@ load_default_resources() ++numdefs; } linelen += strlen(inbuf); - if (!index(inbuf, '\n')) + if (!strchr(inbuf, '\n')) continue; if (linelen > longlen) longlen = linelen; @@ -886,7 +922,7 @@ load_default_resources() } static void -release_default_resources() +release_default_resources(void) { if (default_resource_data) { unsigned idx; @@ -900,23 +936,19 @@ release_default_resources() /* Global Functions ======================================================= */ void -X11_raw_print(str) -const char *str; +X11_raw_print(const char *str) { (void) puts(str); } void -X11_raw_print_bold(str) -const char *str; +X11_raw_print_bold(const char *str) { (void) puts(str); } void -X11_curs(window, x, y) -winid window; -int x, y; +X11_curs(winid window, int x, int y) { check_winid(window); @@ -934,10 +966,7 @@ int x, y; } void -X11_putstr(window, attr, str) -winid window; -int attr; -const char *str; +X11_putstr(winid window, int attr, const char *str) { winid new_win; struct xwindow *wp; @@ -947,8 +976,8 @@ const char *str; switch (wp->type) { case NHW_MESSAGE: - (void) strncpy(toplines, str, TBUFSZ); /* for Norep(). */ - toplines[TBUFSZ - 1] = 0; + (void) strncpy(gt.toplines, str, TBUFSZ); /* for Norep(). */ + gt.toplines[TBUFSZ - 1] = 0; append_message(wp, str); break; #ifndef STATUS_HILITES @@ -973,7 +1002,8 @@ const char *str; X11_destroy_nhwindow(window); *wp = window_list[new_win]; window_list[new_win].type = NHW_NONE; /* allow re-use */ - /* fall though to add text */ + FALLTHROUGH; + /*FALLTHRU*/ case NHW_TEXT: add_to_text_window(wp, attr, str); break; @@ -984,20 +1014,19 @@ const char *str; /* We do event processing as a callback, so this is a null routine. */ void -X11_get_nh_event() +X11_get_nh_event(void) { return; } int -X11_nhgetch() +X11_nhgetch(void) { return input_event(EXIT_ON_KEY_PRESS); } int -X11_nh_poskey(x, y, mod) -int *x, *y, *mod; +X11_nh_poskey(coordxy *x, coordxy *y, int *mod) { int val = input_event(EXIT_ON_KEY_OR_BUTTON_PRESS); @@ -1010,8 +1039,7 @@ int *x, *y, *mod; } winid -X11_create_nhwindow(type) -int type; +X11_create_nhwindow(int type) { winid window; struct xwindow *wp; @@ -1105,8 +1133,7 @@ int type; } void -X11_clear_nhwindow(window) -winid window; +X11_clear_nhwindow(winid window) { struct xwindow *wp; @@ -1132,9 +1159,7 @@ winid window; } void -X11_display_nhwindow(window, blocking) -winid window; -boolean blocking; +X11_display_nhwindow(winid window, boolean blocking) { struct xwindow *wp; @@ -1196,8 +1221,7 @@ boolean blocking; } void -X11_destroy_nhwindow(window) -winid window; +X11_destroy_nhwindow(winid window) { struct xwindow *wp; @@ -1257,34 +1281,82 @@ winid window; } } +/* display persistent inventory in its own window */ void -X11_update_inventory() +X11_update_inventory(int arg) { - if (x_inited && window_list[WIN_INVEN].menu_information->is_up) { - updated_inventory = 1; /* hack to avoid mapping&raising window */ - (void) display_inventory((char *) 0, FALSE); - updated_inventory = 0; + struct xwindow *wp = 0; + + if (!x_inited) + return; + + if (iflags.perm_invent) { + /* skip any calls to update_inventory() before in_moveloop starts */ + if (program_state.in_moveloop || program_state.gameover) { + updated_inventory = 1; /* hack to avoid mapping&raising window */ + if (!arg) { + repopulate_perminvent(); + } else { + x11_scroll_perminv(arg); + } + updated_inventory = 0; + } + } else if ((wp = &window_list[WIN_INVEN]) != 0 + && wp->type == NHW_MENU && wp->menu_information->is_up) { + /* persistent inventory is up but perm_invent is off, take it down */ + x11_no_perminv(wp); } + return; +} + +win_request_info * +X11_ctrl_nhwindow( + winid window UNUSED, + int request UNUSED, + win_request_info *wri UNUSED) +{ + if (!wri) + return (win_request_info *) 0; + + switch(request) { + case set_mode: + case request_settings: + break; + case set_menu_promptstyle: + X11_menu_promptstyle = wri->fromcore.menu_promptstyle; + break; + default: + break; + } + return wri; } /* The current implementation has all of the saved lines on the screen. */ int -X11_doprev_message() +X11_doprev_message(void) { return 0; } +/* issue a beep to alert the user about something */ void -X11_nhbell() +X11_nhbell(void) { - /* We can't use XBell until toplevel has been initialized. */ - if (x_inited) - XBell(XtDisplay(toplevel), 0); - /* else print ^G ?? */ + if (!flags.silent) { + /* We can't use XBell until toplevel has been initialized. */ + if (x_inited) { + XBell(XtDisplay(toplevel), 0); +#if 0 + } else { + /* raw_print() uses puts() so appends a newline */ + X11_raw_print("\a"); /* '\a' == '\007' (^G), ascii BEL */ +#endif + } + } } void -X11_mark_synch() +X11_mark_synch(void) { if (x_inited) { /* @@ -1301,22 +1373,23 @@ X11_mark_synch() } void -X11_wait_synch() +X11_wait_synch(void) { - if (x_inited) + if (x_inited) { + X11_mark_synch(); XFlush(XtDisplay(toplevel)); + } } /* Both resume_ and suspend_ are called from ioctl.c and unixunix.c. */ void -X11_resume_nhwindows() +X11_resume_nhwindows(void) { return; } /* ARGSUSED */ void -X11_suspend_nhwindows(str) -const char *str; +X11_suspend_nhwindows(const char *str) { nhUse(str); @@ -1326,34 +1399,16 @@ const char *str; /* Under X, we don't need to initialize the number pad. */ /* ARGSUSED */ void -X11_number_pad(state) /* called from options.c */ -int state; +X11_number_pad(int state) /* called from options.c */ { nhUse(state); return; } -/* called from setftty() in unixtty.c */ -void -X11_start_screen() -{ - return; -} - -/* called from settty() in unixtty.c */ -void -X11_end_screen() -{ - return; -} - #ifdef GRAPHIC_TOMBSTONE void -X11_outrip(window, how, when) -winid window; -int how; -time_t when; +X11_outrip(winid window, int how, time_t when) { struct xwindow *wp; FILE *rip_fp = 0; @@ -1417,7 +1472,8 @@ static XtActionsRec actions[] = { static XtResource resources[] = { { nhStr("slow"), nhStr("Slow"), XtRBoolean, sizeof(Boolean), XtOffset(AppResources *, slow), XtRString, nhStr("True") }, - { nhStr("fancy_status"), nhStr("Fancy_status"), XtRBoolean, sizeof(Boolean), + { nhStr("fancy_status"), nhStr("Fancy_status"), + XtRBoolean, sizeof(Boolean), XtOffset(AppResources *, fancy_status), XtRString, nhStr("True") }, { nhStr("autofocus"), nhStr("AutoFocus"), XtRBoolean, sizeof(Boolean), XtOffset(AppResources *, autofocus), XtRString, nhStr("False") }, @@ -1466,51 +1522,48 @@ static XtResource resources[] = { }; static int -panic_on_error(display, error) -Display *display; -XErrorEvent *error; +panic_on_error(Display *display, XErrorEvent *error) { char buf[BUFSZ]; XGetErrorText(display, error->error_code, buf, BUFSZ); - fprintf(stderr, "X Error: code %i (%s), request %i, minor %i, serial %lu\n", + fprintf(stderr, + "X Error: code %i (%s), request %i, minor %i, serial %lu\n", error->error_code, buf, - error->request_code, error->minor_code, - error->serial); + error->request_code, error->minor_code, error->serial); panic("X Error"); return 0; } static void -X11_error_handler(str) -String str; +X11_error_handler(String str) { nhUse(str); +#if defined(HANGUPHANDLING) hangup(1); #ifdef SAFERHANGUP /* keeps going after hangup() for '#if SAFERHANGUP' */ end_of_input(); +#endif #endif /*NOTREACHED*/ nh_terminate(EXIT_FAILURE); } static int -X11_io_error_handler(display) -Display *display; +X11_io_error_handler(Display *display) { nhUse(display); +#if defined(HANGUPHANDLING) hangup(1); #ifdef SAFERHANGUP /* keeps going after hangup() for '#if SAFERHANGUP' */ end_of_input(); +#endif #endif /*NOREACHED*/ /* but not declared NORETURN */ return 0; } - void -X11_init_nhwindows(argcp, argv) -int *argcp; -char **argv; +X11_init_nhwindows(int *argcp, char **argv) { int i; Cardinal num_args; @@ -1525,11 +1578,11 @@ char **argv; that to be toggled off via 'O' (note: 'nethack -s' won't reach here; its output goes to stdout and could be redirected into a file) */ iflags.toptenwin = TRUE; - set_option_mod_status("toptenwin", SET_IN_FILE); + set_option_mod_status("toptenwin", set_in_config); /* add another option that can be set */ - set_wc_option_mod_status(WC_TILED_MAP, SET_IN_GAME); - set_option_mod_status("mouse_support", SET_IN_GAME); + set_wc_option_mod_status(WC_TILED_MAP, set_in_game); + set_option_mod_status("mouse_support", set_in_game); load_default_resources(); /* create default_resource_data[] */ @@ -1538,12 +1591,12 @@ char **argv; * when opening X11 connections, in case the user is using xauth, since * the "games" or whatever user probably doesn't have permission to open * a window on the user's display. This code is harmless if the binary - * is not installed setuid. See include/system.h on compilation failures. + * is not installed setuid. */ savuid = geteuid(); (void) seteuid(getuid()); - XSetIOErrorHandler(X11_io_error_handler); + XSetIOErrorHandler((XIOErrorHandler) X11_io_error_handler); num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; @@ -1561,13 +1614,11 @@ char **argv; old_error_handler = XSetErrorHandler(panic_on_error); -#ifdef TEXTCOLOR /* add new color converter to deal with overused colormaps */ XtSetTypeConverter(XtRString, XtRPixel, nhCvtStringToPixel, (XtConvertArgList) nhcolorConvertArgs, XtNumber(nhcolorConvertArgs), XtCacheByDisplay, nhFreePixel); -#endif /* TEXTCOLOR */ /* Register the actions mentioned in "actions". */ XtAppAddActions(app_context, actions, XtNumber(actions)); @@ -1591,7 +1642,7 @@ char **argv; if (icon_pixmap != None) { XWMHints hints; - (void) memset((genericptr_t) &hints, 0, sizeof(XWMHints)); + (void) memset((genericptr_t) &hints, 0, sizeof hints); hints.flags = IconPixmapHint; hints.icon_pixmap = icon_pixmap; XSetWMHints(XtDisplay(toplevel), XtWindow(toplevel), @@ -1619,8 +1670,7 @@ char **argv; */ /* ARGSUSED */ void -X11_exit_nhwindows(dummy) -const char *dummy; +X11_exit_nhwindows(const char *dummy) { extern Pixmap tile_pixmap; /* from winmap.c */ @@ -1646,21 +1696,20 @@ const char *dummy; release_getline_widgets(); release_yn_widgets(); + + x_inited = FALSE; } #ifdef X11_HANGUP_SIGNAL static void -X11_sig(sig) /* Unix signal handler */ -int sig; +X11_sig(int sig) /* Unix signal handler */ { XtNoticeSignal(X11_sig_id); hangup(sig); } static void -X11_sig_cb(not_used, id) -XtPointer not_used; -XtSignalId *id; +X11_sig_cb(XtPointer not_used, XtSignalId *id) { XEvent event; XClientMessageEvent *mesg; @@ -1680,17 +1729,15 @@ XtSignalId *id; } #endif -/* delay_output ----------------------------------------------------------- */ +/* X11_delay_output ------------------------------------------------------- */ /* - * Timeout callback for delay_output(). Send a fake message to the map + * Timeout callback for X11_delay_output(). Send a fake message to the map * window. */ /* ARGSUSED */ static void -d_timeout(client_data, id) -XtPointer client_data; -XtIntervalId *id; +d_timeout(XtPointer client_data, XtIntervalId *id) { XEvent event; XClientMessageEvent *mesg; @@ -1715,7 +1762,7 @@ XtIntervalId *id; * for a sent event. */ void -X11_delay_output() +X11_delay_output(void) { if (!x_inited) return; @@ -1729,46 +1776,49 @@ X11_delay_output() /* X11_hangup ------------------------------------------------------------- */ /* ARGSUSED */ static void -X11_hangup(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +X11_hangup(Widget w, XEvent *event, String *params, Cardinal *num_params) { nhUse(w); nhUse(event); nhUse(params); nhUse(num_params); +#if defined(HANGUPHANDLING) hangup(1); /* 1 is commonly SIGHUP, but ignored anyway */ +#endif exit_x_event = TRUE; } +/* X11_bail --------------------------------------------------------------- */ +/* clean up and quit */ +static void +X11_bail(const char *mesg) +{ + program_state.something_worth_saving = 0; + clearlocks(); + X11_exit_nhwindows(mesg); + nh_terminate(EXIT_SUCCESS); + /*NOTREACHED*/ +} + /* askname ---------------------------------------------------------------- */ /* ARGSUSED */ static void -askname_delete(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +askname_delete(Widget w, XEvent *event, String *params, Cardinal *num_params) { nhUse(event); nhUse(params); nhUse(num_params); nh_XtPopdown(w); - (void) strcpy(plname, "Mumbles"); /* give them a name... ;-) */ + (void) strcpy(svp.plname, "Mumbles"); /* give them a name... ;-) */ exit_x_event = TRUE; } /* Callback for askname dialog widget. */ /* ARGSUSED */ static void -askname_done(w, client_data, call_data) -Widget w; -XtPointer client_data; -XtPointer call_data; +askname_done(Widget w, XtPointer client_data, XtPointer call_data) { unsigned len; char *s; @@ -1786,11 +1836,11 @@ XtPointer call_data; } /* Truncate name if necessary */ - if (len >= sizeof plname - 1) - len = sizeof plname - 1; + if (len >= sizeof svp.plname - 1) + len = sizeof svp.plname - 1; - (void) strncpy(plname, s, len); - plname[len] = '\0'; + (void) strncpy(svp.plname, s, len); + svp.plname[len] = '\0'; XtFree(s); nh_XtPopdown(XtParent(dialog)); @@ -1800,11 +1850,26 @@ XtPointer call_data; /* ask player for character's name to replace generic name "player" (or other values; see config.h) after 'nethack -u player' or OPTIONS=name:player */ void -X11_askname() +X11_askname(void) { Widget popup, dialog; Arg args[1]; +#ifdef SELECTSAVED + if (iflags.wc2_selectsaved && !iflags.renameinprogress) + switch (restore_menu(WIN_MAP)) { + case -1: /* quit */ + X11_bail("Until next time then..."); + /*NOTREACHED*/ + case 0: /* no game chosen; start new game */ + break; + case 1: /* save game selected, plname[] has been set */ + return; + } +#else + nhUse(X11_bail); +#endif /* SELECTSAVED */ + if (iflags.wc_player_selection == VIA_DIALOG) { /* X11_player_selection_dialog() handles name query */ plsel_ask_name = TRUE; @@ -1823,7 +1888,7 @@ X11_askname() (XtCallbackProc) 0); SetDialogPrompt(dialog, nhStr("What is your name?")); /* set prompt */ - SetDialogResponse(dialog, plname, PL_NSIZ); /* set default answer */ + SetDialogResponse(dialog, svp.plname, PL_NSIZ); /* set default answer */ XtRealizeWidget(popup); positionpopup(popup, TRUE); /* center,bottom */ @@ -1833,6 +1898,11 @@ X11_askname() /* The callback will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); + /* tty's character selection uses this; we might someday; + since we let user pick an arbitrary name now, he/she can + pick another one during role selection */ + iflags.renameallowed = TRUE; + XtDestroyWidget(dialog); XtDestroyWidget(popup); } @@ -1843,15 +1913,12 @@ X11_askname() static Widget getline_popup, getline_dialog; #define CANCEL_STR "\033" -static char *getline_input; +static char *getline_input; /* buffer to hold user input; getline's output */ /* Callback for getline dialog widget. */ /* ARGSUSED */ static void -done_button(w, client_data, call_data) -Widget w; -XtPointer client_data; -XtPointer call_data; +done_button(Widget w, XtPointer client_data, XtPointer call_data) { int len; char *s; @@ -1877,11 +1944,7 @@ XtPointer call_data; /* ARGSUSED */ static void -getline_delete(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +getline_delete(Widget w, XEvent *event, String *params, Cardinal *num_params) { nhUse(event); nhUse(params); @@ -1895,10 +1958,7 @@ Cardinal *num_params; /* Callback for getline dialog widget. */ /* ARGSUSED */ static void -abort_button(w, client_data, call_data) -Widget w; -XtPointer client_data; -XtPointer call_data; +abort_button(Widget w, XtPointer client_data, XtPointer call_data) { Widget dialog = (Widget) client_data; @@ -1911,7 +1971,7 @@ XtPointer call_data; } static void -release_getline_widgets() +release_getline_widgets(void) { if (getline_dialog) XtDestroyWidget(getline_dialog), getline_dialog = (Widget) 0; @@ -1919,14 +1979,17 @@ release_getline_widgets() XtDestroyWidget(getline_popup), getline_popup = (Widget) 0; } +/* ask user for a line of text */ void -X11_getlin(question, input) -const char *question; -char *input; +X11_getlin( + const char *question, /* prompt */ + char *input) /* user's input, getlin's _output_ buffer */ { - getline_input = input; + unsigned upromptlen; + + getline_input = input; /* used by popup actions */ - flush_screen(1); + flush_screen(1); /* tell core to make sure that map is up to date */ if (!getline_popup) { Arg args[1]; @@ -1946,24 +2009,58 @@ char *input; XSetWMProtocols(XtDisplay(getline_popup), XtWindow(getline_popup), &wm_delete_window, 1); } - SetDialogPrompt(getline_dialog, (String) question); /* set prompt */ - /* 60: make the answer widget be wide enough to hold 60 characters, + + /* 64: make the answer widget be wide enough to hold 64 characters, or the length of the prompt string, whichever is bigger. User's response can be longer--when limit is reached, value-so-far will slide left hiding some chars at the beginning of the response but making room to type more. [Prior to 3.6.1, width wasn't specifiable and answer box always got sized to match the width of the prompt.] */ + upromptlen = (unsigned) strlen(question); + if (upromptlen < 64) + upromptlen = 64; #ifdef EDIT_GETLIN - SetDialogResponse(getline_dialog, input, 60); /* set default answer */ + /* set default answer */ + SetDialogResponse(getline_dialog, input, upromptlen); #else - SetDialogResponse(getline_dialog, nhStr(""), 60); /* set default answer */ + /* no default answer */ + SetDialogResponse(getline_dialog, nhStr(""), upromptlen); #endif + SetDialogPrompt(getline_dialog, (String) question); /* set prompt */ positionpopup(getline_popup, TRUE); /* center,bottom */ nh_XtPopup(getline_popup, (int) XtGrabExclusive, getline_dialog); /* The callback will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); + + /* we get here after the popup has exited; + put prompt and response into the message window (and into + core's dumplog history) unless play hasn't started yet */ + if (program_state.in_moveloop || program_state.gameover) { + /* single space has meaning (to remove a previously applied name) so + show it clearly; don't care about legibility of multiple spaces */ + const char *visanswer = !input[0] ? "" + : (input[0] == ' ' && !input[1]) ? "" + : (input[0] == '\033') ? "" + : input; + int promptlen = (int) strlen(question), + answerlen = (int) strlen(visanswer); + + /* prompt should be limited to QBUFSZ-1 by caller; enforce that + here for the echoed value; answer could be up to BUFSZ-1 long; + pline() will truncate the whole message to that amount so we + truncate the answer for display; this only affects the echoed + response, not the actual response being returned to the core */ + if (promptlen >= QBUFSZ) + promptlen = QBUFSZ - 1; + if (answerlen + 1 + promptlen >= BUFSZ) /* +1: separating space */ + answerlen = BUFSZ - (1 + promptlen) - 1; + pline("%.*s %.*s", promptlen, question, answerlen, visanswer); + } + + /* clear static pointer that's about to go stale */ + getline_input = 0; } /* Display file ----------------------------------------------------------- */ @@ -1971,9 +2068,7 @@ char *input; /* uses a menu (with no selectors specified) rather than a text window to allow previous_page and first_menu actions to move backwards */ void -X11_display_file(str, complain) -const char *str; -boolean complain; +X11_display_file(const char *str, boolean complain) { dlb *fp; winid newwin; @@ -1982,6 +2077,7 @@ boolean complain; menu_item *menu_list; #define LLEN 128 char line[LLEN]; + int clr = 0; /* Use the port-independent file opener to see if the file exists. */ fp = dlb_fopen(str, RDTMODE); @@ -1993,12 +2089,12 @@ boolean complain; newwin = X11_create_nhwindow(NHW_MENU); wp = &window_list[newwin]; - X11_start_menu(newwin); + X11_start_menu(newwin, MENU_BEHAVE_STANDARD); - any = zeroany; + any = cg.zeroany; while (dlb_fgets(line, LLEN, fp)) { - X11_add_menu(newwin, NO_GLYPH, &any, 0, 0, ATR_NONE, - line, MENU_UNSELECTED); + X11_add_menu(newwin, &nul_glyphinfo, &any, 0, 0, ATR_NONE, + clr, line, MENU_ITEMFLAGS_NONE); } (void) dlb_fclose(fp); @@ -2020,10 +2116,11 @@ static const char *yn_choices; /* string of acceptable input */ static char yn_def; static char yn_return; /* return value */ static char yn_esc_map; /* ESC maps to this char. */ -static Widget yn_popup; /* popup for the yn fuction (created once) */ +static Widget yn_popup; /* popup for the yn function (created once) */ static Widget yn_label; /* label for yn function (created once) */ static boolean yn_getting_num; /* TRUE if accepting digits */ static boolean yn_preserve_case; /* default is to force yn to lower case */ +static boolean yn_no_default; /* don't convert ESC or quitchars to def */ static int yn_ndigits; /* digit count */ static long yn_val; /* accumulated value */ @@ -2036,8 +2133,7 @@ static const char yn_translations[] = "#override\n\ * no conversion (i.e. just the CTRL key hit) a NUL is returned. */ char -key_event_to_char(key) -XKeyEvent *key; +key_event_to_char(XKeyEvent *key) { char keystring[MAX_KEY_STRING]; int nbytes; @@ -2046,7 +2142,7 @@ XKeyEvent *key; nbytes = XLookupString(key, keystring, MAX_KEY_STRING, (KeySym *) 0, (XComposeStatus *) 0); - /* Modifier keys return a zero lengh string when pressed. */ + /* Modifier keys return a zero length string when pressed. */ if (nbytes == 0) return '\0'; @@ -2058,11 +2154,7 @@ XKeyEvent *key; */ /* ARGSUSED */ static void -yn_delete(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +yn_delete(Widget w, XEvent *event, String *params, Cardinal *num_params) { nhUse(w); nhUse(event); @@ -2080,11 +2172,7 @@ Cardinal *num_params; */ /* ARGSUSED */ static void -yn_key(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +yn_key(Widget w, XEvent *event, String *params, Cardinal *num_params) { char ch; @@ -2098,7 +2186,8 @@ Cardinal *num_params; return; } - if (!yn_choices) { /* accept any input */ + if (!yn_choices /* accept any input */ + || (yn_no_default && (ch == '\033' || strchr(yn_quitchars, ch)))) { yn_return = ch; } else { if (!yn_preserve_case) @@ -2107,9 +2196,9 @@ Cardinal *num_params; if (ch == '\033') { yn_getting_num = FALSE; yn_return = yn_esc_map; - } else if (index(yn_quitchars, ch)) { + } else if (strchr(yn_quitchars, ch)) { yn_return = yn_def; - } else if (index(yn_choices, ch)) { + } else if (strchr(yn_choices, ch)) { if (ch == '#') { if (yn_getting_num) { /* don't select again */ X11_nhbell(); @@ -2126,8 +2215,15 @@ Cardinal *num_params; } else { if (yn_getting_num) { if (digit(ch)) { + long dgt = (long) (ch - '0'); + yn_ndigits++; - yn_val = (yn_val * 10) + (long) (ch - '0'); + /* yn_val = (10 * yn_val) + (ch - '0'); */ + yn_val = AppendLongDigit(yn_val, dgt); + if (yn_val < 0L) { + yn_ndigits = 0; + yn_val = 0; + } return; /* wait for more input */ } if (yn_ndigits && (ch == '\b' || ch == 127 /*DEL*/)) { @@ -2152,7 +2248,7 @@ Cardinal *num_params; /* called at exit time */ static void -release_yn_widgets() +release_yn_widgets(void) { if (yn_label) XtDestroyWidget(yn_label), yn_label = (Widget) 0; @@ -2160,22 +2256,28 @@ release_yn_widgets() XtDestroyWidget(yn_popup), yn_popup = (Widget) 0; } -/* X11-specific edition of yn_function(), the routine called by the core - to show a prompt and get a single keystroke answer, often 'y' vs 'n' */ +/* guts of the X11_yn_function(), not to be confused with core code; + requires an extra argument: ynflags */ char -X11_yn_function(ques, choices, def) -const char *ques; -const char *choices; /* string of possible response chars; any char if Null */ -char def; /* default response if user hits or */ -{ - char buf[BUFSZ]; +X11_yn_function_core( + const char *ques, /* prompt text */ + const char *choices, /* allowed response chars; any char if Null */ + char def, /* default if user hits or */ + unsigned ynflags) /* flags; currently just log-it or not */ +{ + static XFontStruct *yn_font = 0; + static Dimension yn_minwidth = 0; + char buf[BUFSZ], buf2[BUFSZ]; Arg args[4]; Cardinal num_args; + boolean suppress_logging = (ynflags & YN_NO_LOGMESG) != 0U, + no_default_cnvrt = (ynflags & YN_NO_DEFAULT) != 0U; yn_choices = choices; /* set up globals for callback to use */ yn_def = def; + yn_no_default = no_default_cnvrt; yn_preserve_case = !choices; /* preserve case when an arbitrary - response is allowed */ + * response is allowed */ /* * This is sort of a kludge. There are quite a few places in the main @@ -2199,28 +2301,42 @@ char def; /* default response if user hits or */ yn_preserve_case = TRUE; break; } - if ((cb = index(choicebuf, '\033')) != 0) + if ((cb = strchr(choicebuf, '\033')) != 0) *cb = '\0'; /* ques [choices] (def) */ - if ((int) (1 + strlen(ques) + 2 + strlen(choicebuf) + 4) >= BUFSZ) - panic("X11_yn_function: question too long"); - (void) strncpy(buf, ques, QBUFSZ - 1); - buf[QBUFSZ - 1] = '\0'; - Sprintf(eos(buf), " [%s]", choicebuf); + int ln = ((int) strlen(ques) /* prompt text */ + + 3 /* " []" */ + + (int) strlen(choicebuf) /* choices within "[]" */ + + 4 /* " (c)" */ + + 1 /* a trailing space */ + + 1); /* \0 terminator */ + if (ln >= BUFSZ) + panic("X11_yn_function: question too long (%d)", ln); + Snprintf(buf, sizeof buf, "%.*s [%s]", QBUFSZ - 1, ques, choicebuf); if (def) Sprintf(eos(buf), " (%c)", def); Strcat(buf, " "); /* escape maps to 'q' or 'n' or default, in that order */ - yn_esc_map = (index(choices, 'q') ? 'q' - : index(choices, 'n') ? 'n' + yn_esc_map = (strchr(choices, 'q') ? 'q' + : strchr(choices, 'n') ? 'n' : def); } else { - if ((int) (1 + strlen(ques) + 1) >= BUFSZ) - panic("X11_yn_function: question too long"); + int ln = ((int) strlen(ques) /* prompt text */ + + 1 /* a trailing space */ + + 1); /* \0 terminator */ + if (ln >= BUFSZ) + panic("X11_yn_function: question too long (%d)", ln); Strcpy(buf, ques); Strcat(buf, " "); } + /* for popup-style, add some extra elbow room to the prompt to + enhance its visibility; there's no cursor shown, just the text */ + if (!appResources.slow) { + /* insert one leading space and two extra trailing spaces */ + Strcpy(buf2, buf); + Snprintf(buf, sizeof buf, " %s ", buf2); + } /* * The 'slow' resource is misleadingly named. When it is True, we @@ -2234,50 +2350,86 @@ char def; /* default response if user hits or */ if (appResources.slow) { /* - * 'slow': the yn_label widget was created when the map and - * status widgets were, and is positioned between them. It + * 'slow' is True: the yn_label widget was created when the map + * and status widgets were, and is positioned between them. It * will persist until end of game. All we need to do for * yn_function is direct keystroke input to the yn response * handler and reset its label to be the prompt text (below). */ input_func = yn_key; highlight_yn(FALSE); /* expose yn_label as separate from map */ - } else if (!yn_label) { + } else { /* - * Not 'slow'; create a persistent widget that will be popped up - * as needed, then down again, and last until end of game. The + * 'slow' is False; create a persistent widget that will be popped + * up as needed, then down again, and last until end of game. The * associated yn_label widget is used to track whether it exists. */ - XtSetArg(args[0], XtNallowShellResize, True); - yn_popup = XtCreatePopupShell("query", transientShellWidgetClass, - toplevel, args, ONE); - XtOverrideTranslations(yn_popup, + if (!yn_label) { + XtSetArg(args[0], XtNallowShellResize, True); + yn_popup = XtCreatePopupShell("query", transientShellWidgetClass, + toplevel, args, ONE); + XtOverrideTranslations(yn_popup, XtParseTranslationTable("WM_PROTOCOLS: yn_delete()")); - num_args = 0; - XtSetArg(args[num_args], XtNtranslations, - XtParseTranslationTable(yn_translations)); num_args++; - yn_label = XtCreateManagedWidget("yn_label", labelWidgetClass, - yn_popup, args, num_args); - - XtRealizeWidget(yn_popup); - XSetWMProtocols(XtDisplay(yn_popup), XtWindow(yn_popup), - &wm_delete_window, 1); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); + num_args++; + XtSetArg(args[num_args], XtNtranslations, + XtParseTranslationTable(yn_translations)); num_args++; + yn_label = XtCreateManagedWidget("yn_label", labelWidgetClass, + yn_popup, args, num_args); + + XtRealizeWidget(yn_popup); + XSetWMProtocols(XtDisplay(yn_popup), XtWindow(yn_popup), + &wm_delete_window, 1); + + /* get font that will be used; we'll need it to measure text */ + (void) memset((genericptr_t) args, 0, sizeof args); + XtSetArg(args[0], nhStr(XtNfont), &yn_font); + XtGetValues(yn_label, args, ONE); + + /* set up minimum yn_label width; we don't actually set + the XtNminWidth attribute */ + (void) memset(buf2, 'X', 25), buf2[25] = '\0'; /* 25 'X's */ + yn_minwidth = (Dimension) XTextWidth(yn_font, buf2, + (int) strlen(buf2)); + } } /* set the label of the yn widget to be the prompt text */ + (void) memset((genericptr_t) args, 0, sizeof args); num_args = 0; XtSetArg(args[num_args], XtNlabel, buf); num_args++; XtSetValues(yn_label, args, num_args); + /* for !slow, pop up the prompt+response widget */ if (!appResources.slow) { /* - * Due to some kind of weird bug in the X11R4 and X11R5 shell, we - * need to set the label twice to get the size to change. + * Setting the text doesn't always perform a resize when it + * should. We used to just set the text a second time, but that + * wasn't a reliable workaround, at least on OSX with XQuartz. + * This seems to work reliably. + * + * It also enforces a minimum prompt width, which wasn't being + * done before, so that really short prompts are more noticeable + * if they pop up where the pointer is parked and it happens to + * be sitting somewhere the player isn't looking. */ + Dimension promptwidth, labelwidth = 0; + + (void) memset((genericptr_t) args, 0, sizeof args); num_args = 0; - XtSetArg(args[num_args], XtNlabel, buf); num_args++; - XtSetValues(yn_label, args, num_args); + XtSetArg(args[num_args], XtNwidth, &labelwidth); num_args++; + XtGetValues(yn_label, args, num_args); + + promptwidth = (Dimension) XTextWidth(yn_font, buf, (int) strlen(buf)); + if (labelwidth != promptwidth || labelwidth < yn_minwidth) { + labelwidth = max(promptwidth, yn_minwidth); + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], XtNwidth, labelwidth); num_args++; + XtSetValues(yn_label, args, num_args); + } positionpopup(yn_popup, TRUE); nh_XtPopup(yn_popup, (int) XtGrabExclusive, yn_label); @@ -2286,32 +2438,51 @@ char def; /* default response if user hits or */ yn_getting_num = FALSE; (void) x_event(EXIT_ON_EXIT); /* get keystroke(s) */ + /* erase or remove the prompt */ if (appResources.slow) { - /* keystrokes now belong to the map */ - input_func = 0; - /* erase the prompt */ + (void) memset((genericptr_t) args, 0, sizeof args); num_args = 0; XtSetArg(args[num_args], XtNlabel, " "); num_args++; XtSetValues(yn_label, args, num_args); + + input_func = 0; /* keystrokes now belong to the map */ highlight_yn(FALSE); /* disguise yn_label as part of map */ } else { nh_XtPopdown(yn_popup); /* this removes the event grab */ } - pline("%s%c", buf, (yn_return != '\033') ? yn_return : '\0'); + if (!suppress_logging) { + char *p = trimspaces(buf); /* remove !slow's extra whitespace */ + + pline("%s %s", p, (yn_return == '\033') ? "ESC" : visctrl(yn_return)); + } return yn_return; } +/* X11-specific edition of yn_function(), the routine called by the core + to show a prompt and get a single key answer, often 'y' vs 'n' */ +char +X11_yn_function( + const char *ques, /* prompt text */ + const char *choices, /* allowed response chars; any char if Null */ + char def) /* default if user hits or */ +{ + char res = X11_yn_function_core(ques, choices, def, YN_NORMAL); + + return res; +} + /* used when processing window-capability-specific run-time options; we support toggling tiles on and off via iflags.wc_tiled_map */ void -X11_preference_update(pref) -const char *pref; +X11_preference_update(const char *pref) { if (!strcmp(pref, "tiled_map")) { if (WIN_MAP != WIN_ERR) display_map_window(&window_list[WIN_MAP]); + } else if (!strcmp(pref, "perm_invent")) { + ; /* TODO... */ } } @@ -2322,11 +2493,10 @@ const char *pref; * do some pre-processing. */ static int -input_event(exit_condition) -int exit_condition; +input_event(int exit_condition) { - if (appResources.fancy_status && WIN_STATUS != WIN_ERR) /* hilighting on the fancy status window */ - check_turn_events(); + if (appResources.fancy_status && WIN_STATUS != WIN_ERR) + check_turn_events(); /* hilighting on the fancy status window */ if (WIN_MAP != WIN_ERR) /* make sure cursor is not clipped */ check_cursor_visibility(&window_list[WIN_MAP]); if (WIN_MESSAGE != WIN_ERR) /* reset pause line */ @@ -2337,15 +2507,13 @@ int exit_condition; /*ARGSUSED*/ void -msgkey(w, data, event) -Widget w; -XtPointer data; -XEvent *event; +msgkey(Widget w, XtPointer data, XEvent *event, Boolean *continue_to_dispatch) { Cardinal num = 0; nhUse(w); nhUse(data); + nhUse(continue_to_dispatch); map_input(window_list[WIN_MAP].w, event, (String *) 0, &num); } @@ -2353,11 +2521,9 @@ XEvent *event; /* only called for autofocus */ /*ARGSUSED*/ static void -win_visible(w, data, event, flag) -Widget w; -XtPointer data; /* client_data not used */ -XEvent *event; -Boolean *flag; /* continue_to_dispatch flag not used */ +win_visible(Widget w, XtPointer data, /* client_data not used */ + XEvent *event, + Boolean *flag) /* continue_to_dispatch flag not used */ { XVisibilityEvent *vis_event = (XVisibilityEvent *) event; @@ -2377,15 +2543,14 @@ Boolean *flag; /* continue_to_dispatch flag not used */ part of the map when idle or to invert background and foreground when a prompt is active */ void -highlight_yn(init) -boolean init; +highlight_yn(boolean init) { struct xwindow *xmap; if (!appResources.slow || !appResources.highlight_prompt) return; - /* first time through, WIN_MAP isn't fully initiialized yet */ + /* first time through, WIN_MAP isn't fully initialized yet */ xmap = ((map_win != WIN_ERR) ? &window_list[map_win] : (WIN_MAP != WIN_ERR) ? &window_list[WIN_MAP] : 0); @@ -2393,12 +2558,12 @@ boolean init; Arg args[2]; XGCValues vals; unsigned long fg_bg = (GCForeground | GCBackground); - GC gc = (xmap->map_information->is_tile + GC ggc = (xmap->map_information->is_tile ? xmap->map_information->tile_map.white_gc : xmap->map_information->text_map.copy_gc); (void) memset((genericptr_t) &vals, 0, sizeof vals); - if (XGetGCValues(XtDisplay(xmap->w), gc, fg_bg, &vals)) { + if (XGetGCValues(XtDisplay(xmap->w), ggc, fg_bg, &vals)) { XtSetArg(args[0], XtNforeground, vals.foreground); XtSetArg(args[1], XtNbackground, vals.background); XtSetValues(yn_label, args, TWO); @@ -2417,7 +2582,7 @@ boolean init; * than using a popup. */ static void -init_standard_windows() +init_standard_windows(void) { Widget form, message_viewport, map_viewport, status; Arg args[8]; @@ -2493,7 +2658,7 @@ init_standard_windows() XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++; XtSetValues(map_viewport, args, num_args); - /* Create the status window, with the form as it's parent. */ + /* Create the status window, with the form as its parent. */ status_win = find_free_window(); wp = &window_list[status_win]; wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0; @@ -2517,7 +2682,7 @@ init_standard_windows() XtSetValues(status, args, num_args); /* - * Realize the popup so that the status widget knows it's size. + * Realize the popup so that the status widget knows its size. * * If we unset MappedWhenManaged then the DECwindow driver doesn't * attach the nethack toplevel to the highest virtual root window. @@ -2617,20 +2782,18 @@ init_standard_windows() } void -nh_XtPopup(w, g, childwid) -Widget w; /* widget */ -int g; /* type of grab */ -Widget childwid; /* child to receive focus (can be None) */ +nh_XtPopup(Widget w, /* widget */ + int grb, /* type of grab */ + Widget childwid) /* child to receive focus (can be None) */ { - XtPopup(w, (XtGrabKind) g); + XtPopup(w, (XtGrabKind) grb); XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1); if (appResources.autofocus) XtSetKeyboardFocus(toplevel, childwid); } void -nh_XtPopdown(w) -Widget w; +nh_XtPopdown(Widget w) { XtPopdown(w); if (appResources.autofocus) @@ -2638,39 +2801,33 @@ Widget w; } void -win_X11_init(dir) -int dir; +win_X11_init(int dir) { if (dir != WININIT) return; -#ifdef OPENWINBUG - /* With the OpenWindows 3.0 libraries and the SunOS 4.1.2 ld, these - * two routines will not be found when linking. An apparently correct - * executable is produced, along with nasty messages and a failure code - * returned to make. The routines are in the static libXmu.a and - * libXmu.sa.4.0, but not in libXmu.so.4.0. Rather than fiddle with - * static linking, we do this. - */ - if (rn2(2) > 2) { /* i.e., FALSE that an optimizer probably can't find */ - get_wmShellWidgetClass(); - get_applicationShellWidgetClass(); - } -#endif return; } void -find_scrollbars(w, horiz, vert) -Widget w; -Widget *horiz, *vert; -{ +find_scrollbars( + Widget w, /* widget of interest; scroll bars are probably attached + to its parent or grandparent */ + Widget last_w, /* if non-zero, don't search ancestry beyond this point */ + Widget *horiz, /* output: horizontal scrollbar */ + Widget *vert) /* output: vertical scrollbar */ +{ + *horiz = *vert = (Widget) 0; + /* for 3.6 this looked for an ancestor with both scrollbars but + menus might have only vertical */ if (w) { do { *horiz = XtNameToWidget(w, "*horizontal"); *vert = XtNameToWidget(w, "*vertical"); + if (*horiz || *vert) + break; w = XtParent(w); - } while (!*horiz && !*vert && w); + } while (w && (!last_w || w != last_w)); } } @@ -2679,11 +2836,8 @@ Widget *horiz, *vert; */ /*ARGSUSED*/ void -nh_keyscroll(viewport, event, params, num_params) -Widget viewport; -XEvent *event; -String *params; -Cardinal *num_params; +nh_keyscroll(Widget viewport, XEvent *event, String *params, + Cardinal *num_params) { Arg arg[2]; Widget horiz_sb = (Widget) 0, vert_sb = (Widget) 0; @@ -2699,7 +2853,7 @@ Cardinal *num_params; direction = atoi(params[0]); - find_scrollbars(viewport, &horiz_sb, &vert_sb); + find_scrollbars(viewport, (Widget) 0, &horiz_sb, &vert_sb); #define H_DELTA 0.25 /* distance of horiz shift */ /* vert shift is half of curr distance */ diff --git a/win/X11/winmap.c b/win/X11/winmap.c index b0eb620f8..7c2dbfcac 100644 --- a/win/X11/winmap.c +++ b/win/X11/winmap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winmap.c $NHDT-Date: 1455389908 2016/02/13 18:58:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.29 $ */ +/* NetHack 5.0 winmap.c $NHDT-Date: 1682206649 2023/04/22 23:37:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.59 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -45,8 +45,7 @@ #endif /* from tile.c */ -extern short glyph2tile[]; -extern int total_tiles_used; +extern int total_tiles_used, Tile_corr; /* Define these if you really want a lot of junk on your screen. */ /* #define VERBOSE */ /* print various info & events as they happen */ @@ -55,26 +54,45 @@ extern int total_tiles_used; #define USE_WHITE /* almost always use white as a tile cursor border */ -static boolean FDECL(init_tiles, (struct xwindow *)); -static void FDECL(set_button_values, (Widget, int, int, unsigned)); -static void FDECL(map_check_size_change, (struct xwindow *)); -static void FDECL(map_update, (struct xwindow *, int, int, int, int, - BOOLEAN_P)); -static void FDECL(init_text, (struct xwindow *)); -static void FDECL(map_exposed, (Widget, XtPointer, XtPointer)); -static void FDECL(set_gc, (Widget, Font, const char *, Pixel, GC *, GC *)); -static void FDECL(get_text_gc, (struct xwindow *, Font)); -static void FDECL(get_char_info, (struct xwindow *)); -static void FDECL(display_cursor, (struct xwindow *)); +#define COL0_OFFSET 1 /* change to 0 to revert to displaying unused column 0 */ + +#define NH_INVERSE_COLOR 0x40000000 +#define NH_ENHANCED_COLOR 0x80000000 + +static X11_map_symbol glyph_char(const glyph_info *glyphinfo); +static GC X11_make_gc(struct xwindow *wp, struct text_map_info_t *text_map, + X11_color color, boolean inverted); +#ifdef ENHANCED_SYMBOLS +static void X11_free_gc(struct xwindow *wp, GC gc, X11_color color); +#endif +#ifdef ENHANCED_SYMBOLS +static void X11_set_map_font(struct xwindow *wp); +#endif +static void X11_draw_image_string(Display *display, Drawable d, + GC ggc, int x, int y, + const X11_map_symbol *string, int length); +static Font X11_get_map_font(struct xwindow *wp); +static XFontStruct *X11_get_map_font_struct(struct xwindow *wp); +static boolean init_tiles(struct xwindow *); +static void set_button_values(Widget, int, int, unsigned); +static void map_check_size_change(struct xwindow *); +static void map_update(struct xwindow *, int, int, int, int, boolean); +static void init_text(struct xwindow *); +static void map_exposed(Widget, XtPointer, XtPointer); +static void set_gc(Widget, Font, const char *, Pixel, GC *, GC *); +static void get_text_gc(struct xwindow *, Font); +static void map_all_unexplored(struct map_info_t *); +static void get_char_info(struct xwindow *); +static void display_cursor(struct xwindow *); /* Global functions ======================================================= */ void -X11_print_glyph(window, x, y, glyph, bkglyph) -winid window; -xchar x, y; -int glyph; -int bkglyph UNUSED; +X11_print_glyph( + winid window, + coordxy x, coordxy y, + const glyph_info *glyphinfo, + const glyph_info *bkglyphinfo) { struct map_info_t *map_info; boolean update_bbox = FALSE; @@ -88,30 +106,54 @@ int bkglyph UNUSED; /* update both the tile and text backing stores */ { - unsigned short *t_ptr = &map_info->tile_map.glyphs[y][x].glyph; + unsigned short *g_ptr = &map_info->tile_map.glyphs[y][x].glyph, + *t_ptr = &map_info->tile_map.glyphs[y][x].tileidx; - if (*t_ptr != glyph) { - *t_ptr = glyph; + if (*g_ptr != glyphinfo->glyph) { + *g_ptr = glyphinfo->glyph; if (map_info->is_tile) update_bbox = TRUE; } + if (*t_ptr != glyphinfo->gm.tileidx) { + *t_ptr = glyphinfo->gm.tileidx; + if (map_info->is_tile) + update_bbox = TRUE; + } + + if (map_info->tile_map.glyphs[y][x].framecolor != bkglyphinfo->framecolor) { + map_info->tile_map.glyphs[y][x].framecolor = bkglyphinfo->framecolor; + update_bbox = TRUE; + } } { - uchar ch; - register unsigned char *ch_ptr; - int color, och; + X11_map_symbol ch; + X11_map_symbol *ch_ptr; + X11_color color; unsigned special; -#ifdef TEXTCOLOR + uint32 nhcolor = 0; int colordif; - register unsigned char *co_ptr; -#endif - - /* map glyph to character and color */ - (void) mapglyph(glyph, &och, &color, &special, x, y, 0); - ch = (uchar) och; - - if (special != map_info->tile_map.glyphs[y][x].special) { - map_info->tile_map.glyphs[y][x].special = special; + X11_color *co_ptr; + + color = glyphinfo->gm.sym.color; + special = glyphinfo->gm.glyphflags; + ch = glyph_char(glyphinfo); + + if (glyphinfo->gm.customcolor != 0) { + if ((glyphinfo->gm.customcolor & NH_BASIC_COLOR) != 0) { + /* NH_BASIC_COLOR */ + color = COLORVAL(glyphinfo->gm.customcolor); + } else if (iflags.colorcount == 256 + && (X11_procs.wincap2 & WC2_EXTRACOLORS) != 0 + && (glyphinfo->gm.customcolor & NH_BASIC_COLOR) == 0) { + uint32 closecolor = get_nhcolor_from_256_index(glyphinfo->gm.color256idx); + nhcolor = COLORVAL(closecolor); + } else { + /* 24-bit color, NH_BASIC_COLOR == 0 */ + nhcolor = COLORVAL(glyphinfo->gm.customcolor); + } + } + if (special != map_info->tile_map.glyphs[y][x].glyphflags) { + map_info->tile_map.glyphs[y][x].glyphflags = special; update_bbox = TRUE; } @@ -122,28 +164,115 @@ int bkglyph UNUSED; if (!map_info->is_tile) update_bbox = TRUE; } -#ifdef TEXTCOLOR co_ptr = &map_info->text_map.colors[y][x]; colordif = (((special & MG_PET) != 0 && iflags.hilite_pet) || ((special & MG_OBJPILE) != 0 && iflags.hilite_pile) - || ((special & (MG_DETECT | MG_BW_LAVA)) != 0)) + || ((special & (MG_DETECT | MG_BW_LAVA | MG_BW_ICE + | MG_BW_SINK | MG_BW_ENGR)) != 0 + && iflags.use_inverse)) ? CLR_MAX : 0; - if (*co_ptr != (uchar) (color + colordif)) { - *co_ptr = (uchar) (color + colordif); + color += colordif; + if (nhcolor != 0) + color = nhcolor | NH_ENHANCED_COLOR; + if (colordif != 0) + color |= NH_INVERSE_COLOR; + + if (*co_ptr != color) { + *co_ptr = color; if (!map_info->is_tile) update_bbox = TRUE; } -#endif + if (map_info->text_map.framecolors[y][x] != bkglyphinfo->framecolor) { + map_info->text_map.framecolors[y][x] = bkglyphinfo->framecolor; + update_bbox = TRUE; + } } if (update_bbox) { /* update row bbox */ - if ((uchar) x < map_info->t_start[y]) + if (x < map_info->t_start[y]) map_info->t_start[y] = x; - if ((uchar) x > map_info->t_stop[y]) + if (x > map_info->t_stop[y]) map_info->t_stop[y] = x; } } +static X11_map_symbol +glyph_char(const glyph_info *glyphinfo) +{ +#ifdef ENHANCED_SYMBOLS + /* CP437 to Unicode mapping according to the Unicode Consortium */ + static const uint16 cp437[256] = { + 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, + 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, + 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, + 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, + 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, + 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 + }; + /* Display DECgraphics as Unicode */ + static const uint16 decgraphics[128] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x2192, 0x2190, 0x2191, 0x2193, 0x002F, + 0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x2666, 0x2592, 0x0062, 0x0063, 0x0064, 0x0065, 0x00B0, 0x00B1, + 0x2591, 0x00A4, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x23BA, + 0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251C, 0x2524, 0x2534, 0x252C, + 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00B7, 0x007F + }; + X11_map_symbol och; + + if (SYMHANDLING(H_UTF8) && glyphinfo->gm.u != NULL && glyphinfo->gm.u->utf8str != NULL) { + och = glyphinfo->gm.u->utf32ch; + } else { + och = (uchar) glyphinfo->ttychar; + if (SYMHANDLING(H_IBM)) { + och = cp437[och]; + } else if ((SYMHANDLING(H_DEC) || SYMHANDLING(H_CURS)) && och >= 0x80) { + och = decgraphics[och & 0x7F]; + } + } + + return och; +#else + return (char) glyphinfo->ttychar; +#endif +} + #ifdef CLIPPING /* * The is the tty clip call. Since X can resize at any time, we can't depend @@ -151,9 +280,7 @@ int bkglyph UNUSED; */ /*ARGSUSED*/ void -X11_cliparound(x, y) -int x UNUSED; -int y UNUSED; +X11_cliparound(int x UNUSED, int y UNUSED) { return; } @@ -189,10 +316,10 @@ static struct tile_annotation pet_annotation; static struct tile_annotation pile_annotation; static void -init_annotation(annotation, filename, colorpixel) -struct tile_annotation *annotation; -char *filename; -Pixel colorpixel; +init_annotation( + struct tile_annotation *annotation, + char *filename, + Pixel colorpixel) { Display *dpy = XtDisplay(toplevel); @@ -219,7 +346,7 @@ Pixel colorpixel; * map viewport. */ void -post_process_tiles() +post_process_tiles(void) { Display *dpy = XtDisplay(toplevel); unsigned int width, height; @@ -256,8 +383,7 @@ post_process_tiles() * Return FALSE otherwise. */ static boolean -init_tiles(wp) -struct xwindow *wp; +init_tiles(struct xwindow *wp) { #ifdef USE_XPM XpmAttributes attributes; @@ -291,7 +417,7 @@ struct xwindow *wp; map_info = wp->map_information; tile_info = &map_info->tile_map; (void) memset((genericptr_t) tile_info, 0, - sizeof(struct tile_map_info_t)); + sizeof (struct tile_map_info_t)); /* no tile file name, no tile information */ if (!appResources.tile_file[0]) { @@ -401,7 +527,7 @@ ntiles %ld\n", goto tiledone; } - colors = (XColor *) alloc(sizeof(XColor) * (unsigned) header.ncolors); + colors = (XColor *) alloc(sizeof (XColor) * (unsigned) header.ncolors); for (i = 0; i < header.ncolors; i++) { cp = colormap + (3 * i); colors[i].red = cp[0] * 256; @@ -475,8 +601,12 @@ ntiles %ld\n", bitmap_pad, /* bit pad */ 0); /* bytes_per_line */ - if (!tile_image) + if (!tile_image) { impossible("init_tiles: insufficient memory to create image"); + X11_raw_print("Resorting to text map."); + result = FALSE; + goto tiledone; + } /* now we know the physical memory requirements, we can allocate space */ tile_image->data = @@ -484,7 +614,7 @@ ntiles %ld\n", if (appResources.double_tile_size) { unsigned long *expanded_row = - (unsigned long *) alloc(sizeof(unsigned long) * image_width); + (unsigned long *) alloc(sizeof (unsigned long) * image_width); tb = tile_bytes; for (y = 0; y < (int) image_height; y++) { @@ -531,7 +661,11 @@ ntiles %ld\n", values.foreground = WhitePixelOfScreen(screen) ^ XGetPixel(tile_image, 0, +#if 0 tile_height * glyph2tile[cmap_to_glyph(S_corr)]); +#else + tile_height * T_corr); +#endif values.function = GXxor; tile_info->white_gc = XtGetGC(wp->w, mask, &values); @@ -541,7 +675,7 @@ ntiles %ld\n", tile_info->black_gc = XtGetGC(wp->w, mask, &values); #endif /* USE_WHITE */ -tiledone: + tiledone: #ifndef USE_XPM if (fp) (void) fclose(fp); @@ -569,8 +703,7 @@ ntiles %ld\n", * Make sure the map's cursor is always visible. */ void -check_cursor_visibility(wp) -struct xwindow *wp; +check_cursor_visibility(struct xwindow *wp) { Arg arg[2]; Widget viewport, horiz_sb, vert_sb; @@ -587,7 +720,7 @@ struct xwindow *wp; /* All values are relative to currently visible area */ #define V_BORDER 0.25 /* if this far from vert edge, shift */ -#define H_BORDER 0.25 /* if this from from horiz edge, shift */ +#define H_BORDER 0.25 /* if this far from horiz edge, shift */ #define H_DELTA 0.25 /* distance of horiz shift */ #define V_DELTA 0.25 /* distance of vert shift */ @@ -721,8 +854,7 @@ struct xwindow *wp; * on the screen when the user resizes the nethack window. */ static void -map_check_size_change(wp) -struct xwindow *wp; +map_check_size_change(struct xwindow *wp) { struct map_info_t *map_info = wp->map_information; Arg arg[2]; @@ -739,7 +871,7 @@ struct xwindow *wp; if (new_width < map_info->viewport_width || new_height < map_info->viewport_height) { /* [ALI] If the viewport was larger than the map (and so the map - * widget was contrained to be larger than the actual map) then we + * widget was constrained to be larger than the actual map) then we * may be able to shrink the map widget as the viewport shrinks. */ if (map_info->is_tile) { @@ -772,16 +904,16 @@ struct xwindow *wp; /* * Fill in parameters "regular" and "inverse" with newly created GCs. - * Using the given background pixel and the foreground pixel optained + * Using the given background pixel and the foreground pixel obtained * by querying the widget with the resource name. */ static void -set_gc(w, font, resource_name, bgpixel, regular, inverse) -Widget w; -Font font; -const char *resource_name; -Pixel bgpixel; -GC *regular, *inverse; +set_gc( + Widget w, + Font font, + const char *resource_name, + Pixel bgpixel, + GC *regular, GC *inverse) { XGCValues values; XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont; @@ -811,9 +943,7 @@ GC *regular, *inverse; * background colors on the current GC as needed. */ static void -get_text_gc(wp, font) -struct xwindow *wp; -Font font; +get_text_gc(struct xwindow *wp, Font font) { struct map_info_t *map_info = wp->map_information; Pixel bgpixel; @@ -823,7 +953,6 @@ Font font; XtSetArg(arg[0], XtNbackground, &bgpixel); XtGetValues(wp->w, arg, ONE); -#ifdef TEXTCOLOR #define set_color_gc(nh_color, resource_name) \ set_gc(wp->w, font, resource_name, bgpixel, \ &map_info->text_map.color_gcs[nh_color], \ @@ -845,19 +974,13 @@ Font font; set_color_gc(CLR_BRIGHT_MAGENTA, XtNbright_magenta); set_color_gc(CLR_BRIGHT_CYAN, XtNbright_cyan); set_color_gc(CLR_WHITE, XtNwhite); -#else - set_gc(wp->w, font, XtNforeground, bgpixel, - &map_info->text_map.copy_gc, - &map_info->text_map.inv_copy_gc); -#endif } /* * Display the cursor on the map window. */ static void -display_cursor(wp) -struct xwindow *wp; +display_cursor(struct xwindow *wp) { /* Redisplay the cursor location inverted. */ map_update(wp, wp->cursy, wp->cursy, wp->cursx, wp->cursx, TRUE); @@ -868,27 +991,28 @@ struct xwindow *wp; * the screen. */ void -display_map_window(wp) -struct xwindow *wp; +display_map_window(struct xwindow *wp) { - register int row; + int row; struct map_info_t *map_info = wp->map_information; if ((Is_rogue_level(&u.uz) ? map_info->is_tile : (map_info->is_tile != iflags.wc_tiled_map)) && map_info->tile_map.image_width) { + int i; + /* changed map display mode, re-display the full map */ - (void) memset((genericptr_t) map_info->t_start, (char) 0, - sizeof(map_info->t_start)); - (void) memset((genericptr_t) map_info->t_stop, (char) (COLNO - 1), - sizeof(map_info->t_stop)); + for (i = 0; i < ROWNO; i++) { + map_info->t_start[i] = 0; + map_info->t_stop[i] = COLNO-1; + } map_info->is_tile = iflags.wc_tiled_map && !Is_rogue_level(&u.uz); XClearWindow(XtDisplay(wp->w), XtWindow(wp->w)); set_map_size(wp, COLNO, ROWNO); check_cursor_visibility(wp); highlight_yn(TRUE); /* change fg/bg to match map */ } else if (wp->prevx != wp->cursx || wp->prevy != wp->cursy) { - register unsigned int x = wp->prevx, y = wp->prevy; + coordxy x = wp->prevx, y = wp->prevy; /* * Previous cursor position is not the same as the current @@ -914,19 +1038,43 @@ struct xwindow *wp; } /* - * Set all map tiles to S_stone + * Set all map tiles and characters to S_unexplored (was S_stone). + * (Actually, column 0 is set to S_nothing and 1..COLNO-1 to S_unexplored.) */ static void -map_all_stone(map_info) -struct map_info_t *map_info; +map_all_unexplored(struct map_info_t *map_info) /* [was map_all_stone()] */ { int x, y; - unsigned short stone = cmap_to_glyph(S_stone); + glyph_info ginfo; + short unexp_idx, nothg_idx; + /* unsigned short g_stone = cmap_to_glyph(S_stone); */ + unsigned short g_unexp = GLYPH_UNEXPLORED, g_nothg = GLYPH_NOTHING; + int mgunexp = ' ', mgnothg = ' '; + struct tile_map_info_t *tile_map = &map_info->tile_map; + struct text_map_info_t *text_map = &map_info->text_map; + + mgunexp = glyph2ttychar(GLYPH_UNEXPLORED); + mgnothg = glyph2ttychar(GLYPH_NOTHING); + + map_glyphinfo(0, 0, g_unexp, 0, &ginfo); + unexp_idx = ginfo.gm.tileidx; + map_glyphinfo(0, 0, g_nothg, 0, &ginfo); + nothg_idx = ginfo.gm.tileidx; + /* + * Tiles map tracks glyphs. + * Text map tracks characters derived from glyphs. + */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { - map_info->tile_map.glyphs[y][x].glyph = stone; - map_info->tile_map.glyphs[y][x].special = 0; + tile_map->glyphs[y][x].glyph = !x ? g_nothg : g_unexp; + tile_map->glyphs[y][x].glyphflags = 0; + tile_map->glyphs[y][x].tileidx = !x ? nothg_idx : unexp_idx; + tile_map->glyphs[y][x].framecolor = NO_COLOR; + + text_map->text[y][x] = (uchar) (!x ? mgnothg : mgunexp); + text_map->colors[y][x] = NO_COLOR; + text_map->framecolors[y][x] = NO_COLOR; } } @@ -937,42 +1085,35 @@ struct map_info_t *map_info; * display_map_window(). */ void -clear_map_window(wp) -struct xwindow *wp; +clear_map_window(struct xwindow *wp) { struct map_info_t *map_info = wp->map_information; + int i; /* update both tile and text backing store, then update */ - - map_all_stone(map_info); - (void) memset((genericptr_t) map_info->text_map.text, ' ', - sizeof map_info->text_map.text); -#ifdef TEXTCOLOR - (void) memset((genericptr_t) map_info->text_map.colors, NO_COLOR, - sizeof map_info->text_map.colors); -#endif + map_all_unexplored(map_info); /* force a full update */ - (void) memset((genericptr_t) map_info->t_start, (char) 0, - sizeof map_info->t_start); - (void) memset((genericptr_t) map_info->t_stop, (char) COLNO - 1, - sizeof map_info->t_stop); + for (i = 0; i < ROWNO; i++) { + map_info->t_start[i] = 0; + map_info->t_stop[i] = COLNO-1; + } + display_map_window(wp); } /* - * Retreive the font associated with the map window and save attributes + * Retrieve the font associated with the map window and save attributes * that are used when updating it. */ static void -get_char_info(wp) -struct xwindow *wp; +get_char_info(struct xwindow *wp) { XFontStruct *fs; struct map_info_t *map_info = wp->map_information; struct text_map_info_t *text_map = &map_info->text_map; - fs = WindowFontStruct(wp->w); + fs = X11_get_map_font_struct(wp); text_map->square_width = fs->max_bounds.width; text_map->square_height = fs->max_bounds.ascent + fs->max_bounds.descent; text_map->square_ascent = fs->max_bounds.ascent; @@ -1013,11 +1154,7 @@ static int inptr = 0; /* points to valid data */ * Keyboard and button event handler for map window. */ void -map_input(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +map_input(Widget w, XEvent *event, String *params, Cardinal *num_params) { XKeyEvent *key; XButtonEvent *button; @@ -1074,7 +1211,7 @@ Cardinal *num_params; nbytes = XLookupString(key, keystring, MAX_KEY_STRING, (KeySym *) 0, (XComposeStatus *) 0); } - key_events: + key_events: /* Modifier keys return a zero length string when pressed. */ if (nbytes) { #ifdef VERBOSE_INPUT @@ -1113,11 +1250,7 @@ Cardinal *num_params; } static void -set_button_values(w, x, y, button) -Widget w; -int x; -int y; -unsigned int button; +set_button_values(Widget w, int x, int y, unsigned int button) { struct xwindow *wp; struct map_info_t *map_info; @@ -1132,6 +1265,7 @@ unsigned int button; click_x = x / map_info->text_map.square_width; click_y = y / map_info->text_map.square_height; } + click_x += COL0_OFFSET; /* note: reverse of usual adjustment */ /* The values can be out of range if the map window has been resized to be larger than the max size. */ @@ -1149,10 +1283,8 @@ unsigned int button; */ /*ARGSUSED*/ static void -map_exposed(w, client_data, widget_data) -Widget w; -XtPointer client_data; /* unused */ -XtPointer widget_data; /* expose event from Window widget */ +map_exposed(Widget w, XtPointer client_data, /* unused */ + XtPointer widget_data) /* expose event from Window widget */ { int x, y; struct xwindow *wp; @@ -1199,12 +1331,10 @@ XtPointer widget_data; /* expose event from Window widget */ t_width = map_info->text_map.square_width; } start_row = y / t_height; - stop_row = ((y + height) / t_height) - + ((((y + height) % t_height) == 0) ? 0 : 1) - 1; + stop_row = ((y + height) / t_height) + 1; start_col = x / t_width; - stop_col = ((x + width) / t_width) - + ((((x + width) % t_width) == 0) ? 0 : 1) - 1; + stop_col = ((x + width) / t_width) + 1; #ifdef VERBOSE printf("map_exposed: x = %d, y = %d, width = %d, height = %d\n", x, y, @@ -1235,15 +1365,11 @@ XtPointer widget_data; /* expose event from Window widget */ * The start and stop columns are *inclusive*. */ static void -map_update(wp, start_row, stop_row, start_col, stop_col, inverted) -struct xwindow *wp; -int start_row, stop_row, start_col, stop_col; -boolean inverted; +map_update(struct xwindow *wp, int start_row, int stop_row, int start_col, int stop_col, boolean inverted) { - int win_start_row, win_start_col; struct map_info_t *map_info = wp->map_information; int row; - register int count; + int count; if (start_row < 0 || stop_row >= ROWNO) { impossible("map_update: bad row range %d-%d\n", start_row, stop_row); @@ -1258,8 +1384,6 @@ boolean inverted; printf("update: [0x%x] %d %d %d %d\n", (int) wp->w, start_row, stop_row, start_col, stop_col); #endif - win_start_row = start_row; - win_start_col = start_col; if (map_info->is_tile) { struct tile_map_info_t *tile_map = &map_info->tile_map; @@ -1269,12 +1393,22 @@ boolean inverted; for (row = start_row; row <= stop_row; row++) { for (cur_col = start_col; cur_col <= stop_col; cur_col++) { +#if 0 int glyph = tile_map->glyphs[row][cur_col].glyph; int tile = glyph2tile[glyph]; +#else + int tile = tile_map->glyphs[row][cur_col].tileidx; +#endif int src_x, src_y; - int dest_x = cur_col * tile_map->square_width; + int dest_x = (cur_col - COL0_OFFSET) * tile_map->square_width; int dest_y = row * tile_map->square_height; + unsigned gflags = tile_map->glyphs[row][cur_col].glyphflags; +#if 0 + /* not required with the new glyph representations */ + if ((gflags & MG_FEMALE) != 0) + tile++; /* advance to the female tile variation */ +#endif src_x = (tile % TILES_PER_ROW) * tile_width; src_y = (tile / TILES_PER_ROW) * tile_height; XCopyArea(dpy, tile_pixmap, XtWindow(wp->w), @@ -1282,7 +1416,7 @@ boolean inverted; src_x, src_y, tile_width, tile_height, dest_x, dest_y); - if (glyph_is_pet(glyph) && iflags.hilite_pet) { + if ((gflags & MG_PET) != 0 && iflags.hilite_pet) { /* draw pet annotation (a heart) */ XSetForeground(dpy, tile_map->black_gc, pet_annotation.foreground); @@ -1296,8 +1430,7 @@ boolean inverted; XSetClipMask(dpy, tile_map->black_gc, None); XSetForeground(dpy, tile_map->black_gc, BlackPixelOfScreen(screen)); - } - if ((tile_map->glyphs[row][cur_col].special & MG_OBJPILE)) { + } else if ((gflags & MG_OBJPILE) != 0) { /* draw object pile annotation (a plus sign) */ XSetForeground(dpy, tile_map->black_gc, pile_annotation.foreground); @@ -1313,6 +1446,16 @@ boolean inverted; XSetForeground(dpy, tile_map->black_gc, BlackPixelOfScreen(screen)); } + { + uint32_t fc = COLORVAL(tile_map->glyphs[row][cur_col].framecolor); + + if (fc != NO_COLOR) + XDrawRectangle(dpy, XtWindow(wp->w), + map_info->text_map.color_gcs[fc], + dest_x, dest_y, + tile_map->square_width - 1 , + tile_map->square_height - 1); + } } } @@ -1327,7 +1470,7 @@ boolean inverted; #else tile_map->white_gc, #endif - start_col * tile_map->square_width, + (start_col - COL0_OFFSET) * tile_map->square_width, start_row * tile_map->square_height, tile_map->square_width - 1, tile_map->square_height - 1); @@ -1335,44 +1478,38 @@ boolean inverted; } else { struct text_map_info_t *text_map = &map_info->text_map; -#ifdef TEXTCOLOR { - register char *c_ptr; - char *t_ptr; - int cur_col, color, win_ystart; - boolean cur_inv; + X11_color *c_ptr; + X11_map_symbol *t_ptr; + int cur_col, win_ystart; + X11_color color; + GC ggc; for (row = start_row; row <= stop_row; row++) { win_ystart = text_map->square_ascent + (row * text_map->square_height); - t_ptr = (char *) &(text_map->text[row][start_col]); - c_ptr = (char *) &(text_map->colors[row][start_col]); + t_ptr = &(text_map->text[row][start_col]); + c_ptr = &(text_map->colors[row][start_col]); cur_col = start_col; while (cur_col <= stop_col) { color = *c_ptr++; - cur_inv = inverted; count = 1; while ((cur_col + count) <= stop_col && *c_ptr == color) { count++; c_ptr++; } - if (color >= CLR_MAX) { - color -= CLR_MAX; - cur_inv = !cur_inv; - } - XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w), - iflags.use_color - ? (cur_inv - ? text_map->inv_color_gcs[color] - : text_map->color_gcs[color]) - : (cur_inv - ? text_map->inv_copy_gc - : text_map->copy_gc), - text_map->square_lbearing - + (text_map->square_width * cur_col), - win_ystart, t_ptr, count); + ggc = X11_make_gc(wp, text_map, color, inverted); + X11_draw_image_string(XtDisplay(wp->w), XtWindow(wp->w), + ggc, + text_map->square_lbearing + + (text_map->square_width + * (cur_col - COL0_OFFSET)), + win_ystart, t_ptr, count); +#ifdef ENHANCED_SYMBOLS + X11_free_gc(wp, ggc, color); +#endif /* move text pointer and column count */ t_ptr += count; @@ -1380,41 +1517,121 @@ boolean inverted; } /* col loop */ } /* row loop */ } -#else /* !TEXTCOLOR */ - { - int win_row, win_xstart; - - /* We always start at the same x window position and have - the same character count. */ - win_xstart = text_map->square_lbearing - + (win_start_col * text_map->square_width); - count = stop_col - start_col + 1; - - for (row = start_row, win_row = win_start_row; row <= stop_row; - row++, win_row++) { - XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w), - inverted ? text_map->inv_copy_gc - : text_map->copy_gc, - win_xstart, - text_map->square_ascent - + (win_row * text_map->square_height), - (char *) &(text_map->text[row][start_col]), - count); + } +} + +static GC +X11_make_gc( + struct xwindow *wp UNUSED, + struct text_map_info_t *text_map, + X11_color color, + boolean inverted) +{ + boolean cur_inv = inverted; + GC ggc; + +#ifdef ENHANCED_SYMBOLS + if ((color & NH_ENHANCED_COLOR) != 0) { + /* We need a new GC */ + if ((color & NH_INVERSE_COLOR) != 0) { + cur_inv = !cur_inv; + } + if (iflags.use_color) { + Arg arg[1]; + XGCValues values; + Pixel fgpixel, bgpixel; + + /* FIXME: Does this still work when the display does not support + true color? */ + fgpixel = COLORVAL(color); + XtSetArg(arg[0], XtNbackground, &bgpixel); + XtGetValues(wp->w, arg, 1); + if (cur_inv) { + values.foreground = bgpixel; + values.background = fgpixel; + } else { + values.foreground = fgpixel; + values.background = bgpixel; } + values.function = GXcopy; + values.font = X11_get_map_font(wp); + ggc = XtGetGC(wp->w, + GCFunction | GCForeground | GCBackground | GCFont, + &values); + } else { + ggc = (cur_inv ? text_map->inv_copy_gc : text_map->copy_gc); + } + } else +#endif + { + uint32 nhcolor = COLORVAL(color); /* strip flag bits */ + + if (nhcolor >= CLR_MAX) { + nhcolor -= CLR_MAX; + cur_inv = !cur_inv; + } + ggc = (iflags.use_color + ? (cur_inv + ? text_map->inv_color_gcs[nhcolor] + : text_map->color_gcs[nhcolor]) + : (cur_inv + ? text_map->inv_copy_gc + : text_map->copy_gc)); + } + return ggc; +} + +#ifdef ENHANCED_SYMBOLS +static void +X11_free_gc(struct xwindow *wp, GC ggc, X11_color color) +{ + if ((color & NH_ENHANCED_COLOR) != 0 && iflags.use_color) { + /* X11_make_gc allocated a new GC */ + XtReleaseGC(wp->w, ggc); + } +} +#endif + +static void +X11_draw_image_string( + Display *display, + Drawable d, + GC ggc, + int x, int y, + const X11_map_symbol *string, int length) +{ +#ifdef ENHANCED_SYMBOLS + /* This doesn't support the supplementary planes. The basic Xlib seems + to load only PCF fonts, and these cannot contain characters encoded + above 0xFFFF. */ + XChar2b wstr[COLNO+1]; + int i; + + if (length > COLNO) { + length = COLNO; + } + for (i = 0; i < length; ++i) { + uint32 ch = string[i]; + if (ch > 0xFFFF || (0xD800 <= ch && ch <= 0xDFFF)) { + ch = 0xFFFD; } -#endif /* ?TEXTCOLOR */ + wstr[i].byte1 = ch >> 8; + wstr[i].byte2 = ch & 0xFF; } + XDrawImageString16(display, d, ggc, x, y, wstr, length); +#else /* !ENHANCED_SYMBOLS */ + XDrawImageString(display, d, ggc, x, y, (char *) string, length); +#endif /* ?ENHANCED_SYMBOLS */ } /* Adjust the number of rows and columns on the given map window */ void -set_map_size(wp, cols, rows) -struct xwindow *wp; -Dimension cols, rows; +set_map_size(struct xwindow *wp, Dimension cols, Dimension rows) { Arg args[4]; Cardinal num_args; + cols -= COL0_OFFSET; if (wp->map_information->is_tile) { wp->pixel_width = wp->map_information->tile_map.square_width * cols; wp->pixel_height = wp->map_information->tile_map.square_height * rows; @@ -1430,20 +1647,15 @@ Dimension cols, rows; } static void -init_text(wp) -struct xwindow *wp; +init_text(struct xwindow *wp) { struct map_info_t *map_info = wp->map_information; - struct text_map_info_t *text_map = &map_info->text_map; - (void) memset((genericptr_t) text_map->text, ' ', sizeof text_map->text); -#ifdef TEXTCOLOR - (void) memset((genericptr_t) text_map->colors, NO_COLOR, - sizeof text_map->colors); -#endif + /* set up map_info->text_map->text */ + map_all_unexplored(map_info); get_char_info(wp); - get_text_gc(wp, WindowFont(wp->w)); + get_text_gc(wp, X11_get_map_font(wp)); } static char map_translations[] = "#override\n\ @@ -1458,10 +1670,10 @@ static char map_translations[] = "#override\n\ * The map window creation routine. */ void -create_map_window(wp, create_popup, parent) -struct xwindow *wp; -boolean create_popup; /* parent is a popup shell that we create */ -Widget parent; +create_map_window( + struct xwindow *wp, + boolean create_popup, /* True: parent is a popup shell that we create */ + Widget parent) { struct map_info_t *map_info; /* map info pointer */ Widget map, viewport; @@ -1471,6 +1683,7 @@ Widget parent; #if 0 int screen_width, screen_height; #endif + int i; wp->type = NHW_MAP; @@ -1535,15 +1748,18 @@ Widget parent; XtAddCallback(map, XtNexposeCallback, map_exposed, (XtPointer) 0); map_info = wp->map_information = - (struct map_info_t *) alloc(sizeof(struct map_info_t)); + (struct map_info_t *) alloc(sizeof (struct map_info_t)); +#ifdef ENHANCED_SYMBOLS + X11_set_map_font(wp); +#endif map_info->viewport_width = map_info->viewport_height = 0; /* reset the "new entry" indicators */ - (void) memset((genericptr_t) map_info->t_start, (char) COLNO, - sizeof(map_info->t_start)); - (void) memset((genericptr_t) map_info->t_stop, (char) 0, - sizeof(map_info->t_stop)); + for (i = 0; i < ROWNO; i++) { + map_info->t_start[i] = COLNO; + map_info->t_stop[i] = 0; + } /* we probably want to restrict this to the 1st map window only */ map_info->is_tile = (init_tiles(wp) && iflags.wc_tiled_map); @@ -1581,15 +1797,92 @@ Widget parent; set_map_size(wp, COLNO, ROWNO); } - map_all_stone(map_info); + map_all_unexplored(map_info); +} + +#ifdef ENHANCED_SYMBOLS +static void +X11_set_map_font(struct xwindow *wp) +{ + struct map_info_t *map_info = wp->map_information; + XFontStruct *fs; + Atom font_atom; + const char *font_name; + unsigned dashes; + const char *p; + size_t len; + char unicode_font[BUFSZ]; + Font font_id; + + /* Query the configured font for the map */ + fs = WindowFontStruct(wp->w); + map_info->text_map.font = fs; + if (!XGetFontProperty(fs, XA_FONT, &font_atom)) { + return; + } + font_name = XGetAtomName(XtDisplay(wp->w), font_atom); + if (font_name == NULL) { + return; + } + + /* Proceed to the registry name */ + dashes = 13; + p = font_name; + while (dashes != 0) { + const char *q = strchr(p, '-'); + if (q == NULL) { + break; + } + p = q + 1; + --dashes; + } + + /* Substitute "iso10646-1" for the registry name and encoding */ + len = (size_t) (p - font_name); + if (dashes != 0 || len + 11 > sizeof(unicode_font)) { + return; + } + + memcpy(unicode_font, font_name, len); + strcpy(unicode_font + len, "iso10646-1"); + font_name = unicode_font; + + font_id = XLoadFont(XtDisplay(wp->w), font_name); + map_info->text_map.font = XQueryFont(XtDisplay(wp->w), font_id); + if (map_info->text_map.font == NULL) { + /* Fallback in case no iso10646 */ + map_info->text_map.font = fs; + } +} +#endif + +static Font +X11_get_map_font(struct xwindow *wp) +{ + return X11_get_map_font_struct(wp)->fid; +} + +static XFontStruct * +X11_get_map_font_struct(struct xwindow *wp) +{ +#ifdef ENHANCED_SYMBOLS + struct map_info_t *map_info = wp->map_information; + XFontStruct *fs = map_info->text_map.font; + + if (fs == NULL) { + fs = WindowFontStruct(wp->w); + } + return fs; +#else + return WindowFontStruct(wp->w); +#endif } /* * Destroy this map window. */ void -destroy_map_window(wp) -struct xwindow *wp; +destroy_map_window(struct xwindow *wp) { struct map_info_t *map_info = wp->map_information; @@ -1600,16 +1893,16 @@ struct xwindow *wp; struct text_map_info_t *text_map = &map_info->text_map; /* Free allocated GCs. */ -#ifdef TEXTCOLOR int i; for (i = 0; i < CLR_MAX; i++) { XtReleaseGC(wp->w, text_map->color_gcs[i]); XtReleaseGC(wp->w, text_map->inv_color_gcs[i]); } -#else - XtReleaseGC(wp->w, text_map->copy_gc); - XtReleaseGC(wp->w, text_map->inv_copy_gc); + + /* Free the font structure if we allocated one */ +#ifdef ENHANCED_SYMBOLS + XFreeFont(XtDisplay(wp->w), text_map->font); #endif /* Free malloc'ed space. */ @@ -1637,8 +1930,7 @@ boolean exit_x_event; /* exit condition for the event loop */ #if 0 /*******/ void -pkey(k) -int k; +pkey(int k) { printf("key = '%s%c'\n", (k < 32) ? "^" : "", (k < 32) ? '@' + k : k); } @@ -1649,8 +1941,7 @@ int k; * under certain circumstances. */ int -x_event(exit_condition) -int exit_condition; +x_event(int exit_condition) { XEvent event; int retval = 0; @@ -1675,7 +1966,7 @@ int exit_condition; XtDispatchEvent(&event); /* See if we can exit. */ - try_test: + try_test: switch (exit_condition) { case EXIT_ON_SENT_EVENT: { XAnyEvent *any = (XAnyEvent *) &event; @@ -1701,10 +1992,12 @@ int exit_condition; inptr = (inptr + 1) % INBUF_SIZE; /* pkey(retval); */ keep_going = FALSE; - } else if (program_state.done_hup) { +#if defined(HANGUPHANDLING) + } else if (program_state.done_hup) { retval = '\033'; inptr = (inptr + 1) % INBUF_SIZE; keep_going = FALSE; +#endif } break; case EXIT_ON_KEY_OR_BUTTON_PRESS: @@ -1720,10 +2013,12 @@ int exit_condition; /* pkey(retval); */ } keep_going = FALSE; +#if defined(HANGUPHANDLING) } else if (program_state.done_hup) { retval = '\033'; inptr = (inptr + 1) % INBUF_SIZE; keep_going = FALSE; +#endif } break; default: diff --git a/win/X11/winmenu.c b/win/X11/winmenu.c index 7ac8d2491..85deaf56f 100644 --- a/win/X11/winmenu.c +++ b/win/X11/winmenu.c @@ -1,17 +1,18 @@ -/* NetHack 3.6 winmenu.c $NHDT-Date: 1542245161 2018/11/15 01:26:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.33 $ */ -/* Copyright (c) Dean Luick, 1992 */ +/* NetHack 5.0 winmenu.c $NHDT-Date: 1644531504 2022/02/10 22:18:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.50 $ */ +/* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * File for creating menus. * - * + Global functions: start_menu, add_menu, end_menu, select_menu + * + Global functions: start_menu, add_menu, end_menu, select_menu */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif +#include #include #include #include @@ -32,37 +33,42 @@ #undef PRESERVE_NO_SYSV #endif +#define X11_BUILD #include "hack.h" +#undef X11_BUILD + #include "winX.h" -static void FDECL(menu_size_change_handler, (Widget, XtPointer, - XEvent *, Boolean *)); -static void FDECL(menu_select, (Widget, XtPointer, XtPointer)); -static void FDECL(invert_line, (struct xwindow *, x11_menu_item *, int, long)); -static void FDECL(menu_ok, (Widget, XtPointer, XtPointer)); -static void FDECL(menu_cancel, (Widget, XtPointer, XtPointer)); -static void FDECL(menu_all, (Widget, XtPointer, XtPointer)); -static void FDECL(menu_none, (Widget, XtPointer, XtPointer)); -static void FDECL(menu_invert, (Widget, XtPointer, XtPointer)); -static void FDECL(menu_search, (Widget, XtPointer, XtPointer)); -static void FDECL(search_menu, (struct xwindow *)); -static void FDECL(select_all, (struct xwindow *)); -static void FDECL(select_none, (struct xwindow *)); -static void FDECL(select_match, (struct xwindow *, char *)); -static void FDECL(invert_all, (struct xwindow *)); -static void FDECL(invert_match, (struct xwindow *, char *)); -static void FDECL(menu_popdown, (struct xwindow *)); -static Widget FDECL(menu_create_buttons, (struct xwindow *, Widget, Widget)); -static void FDECL(menu_create_entries, (struct xwindow *, struct menu *)); -static void FDECL(destroy_menu_entry_widgets, (struct xwindow *)); -static void NDECL(create_menu_translation_tables); - -static void FDECL(move_menu, (struct menu *, struct menu *)); -static void FDECL(free_menu_line_entries, (struct menu *)); -static void FDECL(free_menu, (struct menu *)); -static void FDECL(reset_menu_to_default, (struct menu *)); -static void FDECL(clear_old_menu, (struct xwindow *)); -static char *FDECL(copy_of, (const char *)); +static void menu_size_change_handler(Widget, XtPointer, XEvent *, + Boolean *); +static void menu_select(Widget, XtPointer, XtPointer); +static void invert_line(struct xwindow *, x11_menu_item *, int, long); +static void menu_ok(Widget, XtPointer, XtPointer); +static void menu_cancel(Widget, XtPointer, XtPointer); +static void menu_all(Widget, XtPointer, XtPointer); +static void menu_none(Widget, XtPointer, XtPointer); +static void menu_invert(Widget, XtPointer, XtPointer); +static void menu_search(Widget, XtPointer, XtPointer); +static void search_menu(struct xwindow *); +static void select_all(struct xwindow *); +static void select_none(struct xwindow *); +static void select_match(struct xwindow *, char *); +static void invert_all(struct xwindow *); +static void invert_match(struct xwindow *, char *); +static void menu_popdown(struct xwindow *); +static unsigned menu_scrollmask(struct xwindow *); +static void menu_unscroll(struct xwindow *); +static Widget menu_create_buttons(struct xwindow *, Widget, Widget); +static void menu_create_entries(struct xwindow *, struct menu *); +static void destroy_menu_entry_widgets(struct xwindow *); +static void create_menu_translation_tables(void); + +static void move_menu(struct menu *, struct menu *); +static void free_menu_line_entries(struct menu *); +static void free_menu(struct menu *); +static void reset_menu_to_default(struct menu *); +static void clear_old_menu(struct xwindow *); +static char *copy_of(const char *); #define reset_menu_count(mi) ((mi)->counting = FALSE, (mi)->menu_count = 0L) @@ -84,7 +90,7 @@ XtTranslations menu_translation_table = (XtTranslations) 0; XtTranslations menu_del_translation_table = (XtTranslations) 0; static void -create_menu_translation_tables() +create_menu_translation_tables(void) { if (!menu_translation_table) { menu_translation_table = XtParseTranslationTable(menu_translations); @@ -97,11 +103,7 @@ create_menu_translation_tables() /*ARGSUSED*/ static void -menu_size_change_handler(w, ptr, event, flag) -Widget w; -XtPointer ptr; -XEvent *event; -Boolean *flag; +menu_size_change_handler(Widget w, XtPointer ptr, XEvent *event, Boolean *flag) { struct xwindow *wp = (struct xwindow *) ptr; @@ -127,9 +129,7 @@ Boolean *flag; */ /* ARGSUSED */ static void -menu_select(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +menu_select(Widget w, XtPointer client_data, XtPointer call_data) { struct menu_info_t *menu_info; long how_many; @@ -178,11 +178,7 @@ XtPointer client_data, call_data; */ /* ARGSUSED */ void -menu_delete(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +menu_delete(Widget w, XEvent *event, String *params, Cardinal *num_params) { nhUse(event); nhUse(params); @@ -196,11 +192,7 @@ Cardinal *num_params; */ /*ARGSUSED*/ static void -invert_line(wp, curr, which, how_many) -struct xwindow *wp; -x11_menu_item *curr; -int which; -long how_many; +invert_line(struct xwindow *wp, x11_menu_item *curr, int which, long how_many) { Arg args[2]; @@ -224,23 +216,23 @@ long how_many; } } +static XEvent fake_perminv_event; + /* * Called when we get a key press event on a menu window. */ /* ARGSUSED */ void -menu_key(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +menu_key(Widget w, XEvent *event, String *params, Cardinal *num_params) { struct menu_info_t *menu_info; x11_menu_item *curr; struct xwindow *wp; + Widget hbar, vbar; char ch; int count; - boolean selected_something; + boolean selected_something, + perminv_scrolling = (event == &fake_perminv_event); nhUse(params); nhUse(num_params); @@ -248,7 +240,10 @@ Cardinal *num_params; wp = find_widget(w); menu_info = wp->menu_information; - ch = key_event_to_char((XKeyEvent *) event); + if (!perminv_scrolling) + ch = key_event_to_char((XKeyEvent *) event); + else + ch = (char) fake_perminv_event.type; if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ @@ -256,17 +251,19 @@ Cardinal *num_params; } /* don't exclude PICK_NONE menus; doing so disables scrolling via keys */ - if (menu_info->is_active) { /* waiting for input */ + if (menu_info->is_active || perminv_scrolling) { /* handle the input */ /* first check for an explicit selector match, so that it won't be overridden if it happens to duplicate a mapped menu command (':' - to look inside a container vs ':' to select via search string) */ + to look inside a container vs ':' to select via search string); + check for group accelerator match too */ for (curr = menu_info->curr_menu.base; curr; curr = curr->next) - if (curr->identifier.a_void != 0 && curr->selector == ch) + if (curr->identifier.a_void != 0 + && (curr->selector == ch || curr->gselector == ch)) goto make_selection; ch = map_menu_cmd(ch); if (ch == '\033') { /* quit */ - if (menu_info->counting) { + if (menu_info->counting || perminv_scrolling) { /* when there's a count in progress, ESC discards it rather than dismissing the whole menu */ reset_menu_count(menu_info); @@ -274,11 +271,17 @@ Cardinal *num_params; } select_none(wp); } else if (ch == '\n' || ch == '\r') { + if (perminv_scrolling) { + menu_unscroll(wp); + return; /* skip menu_popdown() */ + } ; /* accept */ } else if (digit(ch)) { - /* special case: '0' is also the default ball class */ - if (ch == '0' && !menu_info->counting - && index(menu_info->curr_menu.gacc, ch)) + /* special case: '0' is also the default ball class; + some menus use digits as potential group accelerators + but their entries don't rely on counts */ + if (!menu_info->counting + && strchr(menu_info->curr_menu.gacc, ch)) goto group_accel; menu_info->menu_count *= 10L; menu_info->menu_count += (long) (ch - '0'); @@ -308,30 +311,41 @@ Cardinal *num_params; X11_nhbell(); return; } else if (ch == MENU_FIRST_PAGE || ch == MENU_LAST_PAGE) { - Widget hbar = (Widget) 0, vbar = (Widget) 0; float top = (ch == MENU_FIRST_PAGE) ? 0.0 : 1.0; - find_scrollbars(wp->w, &hbar, &vbar); + find_scrollbars(wp->w, wp->popup, &hbar, &vbar); if (vbar) XtCallCallbacks(vbar, XtNjumpProc, &top); return; } else if (ch == MENU_NEXT_PAGE || ch == MENU_PREVIOUS_PAGE) { - Widget hbar = (Widget) 0, vbar = (Widget) 0; - - find_scrollbars(wp->w, &hbar, &vbar); + find_scrollbars(wp->w, wp->popup, &hbar, &vbar); if (vbar) { float shown, top; Arg arg[2]; + XtSetArg(arg[0], nhStr(XtNshown), &shown); XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top); XtGetValues(vbar, arg, TWO); top += ((ch == MENU_NEXT_PAGE) ? shown : -shown); - if (vbar) - XtCallCallbacks(vbar, XtNjumpProc, &top); + XtCallCallbacks(vbar, XtNjumpProc, &top); } return; - } else if (index(menu_info->curr_menu.gacc, ch)) { - group_accel: + } else if (ch == MENU_SHIFT_RIGHT || ch == MENU_SHIFT_LEFT) { + find_scrollbars(wp->w, wp->popup, &hbar, &vbar); + if (hbar) { + float shown, halfshown, left; + Arg arg[2]; + + XtSetArg(arg[0], nhStr(XtNshown), &shown); + XtSetArg(arg[1], nhStr(XtNtopOfThumb), &left); + XtGetValues(hbar, arg, TWO); + halfshown = shown * 0.5; + left += ((ch == MENU_SHIFT_RIGHT) ? halfshown : -halfshown); + XtCallCallbacks(hbar, XtNjumpProc, &left); + } + return; + } else if (strchr(menu_info->curr_menu.gacc, ch)) { + group_accel: /* matched a group accelerator */ if (menu_info->how == PICK_ANY || menu_info->how == PICK_ONE) { for (count = 0, curr = menu_info->curr_menu.base; curr; @@ -350,11 +364,12 @@ Cardinal *num_params; X11_nhbell(); return; } else { - make_selection: + make_selection: selected_something = FALSE; for (count = 0, curr = menu_info->curr_menu.base; curr; curr = curr->next, count++) - if (curr->identifier.a_void != 0 && curr->selector == ch) + if (curr->identifier.a_void != 0 + && (curr->selector == ch || curr->gselector == ch)) break; if (curr) { @@ -376,15 +391,13 @@ Cardinal *num_params; /* pop down on ESC */ } -menu_done: + menu_done: menu_popdown(wp); } /* ARGSUSED */ static void -menu_ok(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +menu_ok(Widget w, XtPointer client_data, XtPointer call_data) { struct xwindow *wp = (struct xwindow *) client_data; @@ -396,9 +409,8 @@ XtPointer client_data, call_data; /* ARGSUSED */ static void -menu_cancel(w, client_data, call_data) -Widget w; /* don't use - may be None */ -XtPointer client_data, call_data; +menu_cancel(Widget w, /* don't use - may be None */ + XtPointer client_data, XtPointer call_data) { struct xwindow *wp = (struct xwindow *) client_data; @@ -414,9 +426,7 @@ XtPointer client_data, call_data; /* ARGSUSED */ static void -menu_all(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +menu_all(Widget w, XtPointer client_data, XtPointer call_data) { nhUse(w); nhUse(call_data); @@ -426,9 +436,7 @@ XtPointer client_data, call_data; /* ARGSUSED */ static void -menu_none(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +menu_none(Widget w, XtPointer client_data, XtPointer call_data) { nhUse(w); nhUse(call_data); @@ -438,9 +446,7 @@ XtPointer client_data, call_data; /* ARGSUSED */ static void -menu_invert(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +menu_invert(Widget w, XtPointer client_data, XtPointer call_data) { nhUse(w); nhUse(call_data); @@ -450,9 +456,7 @@ XtPointer client_data, call_data; /* ARGSUSED */ static void -menu_search(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +menu_search(Widget w, XtPointer client_data, XtPointer call_data) { struct xwindow *wp = (struct xwindow *) client_data; struct menu_info_t *menu_info = wp->menu_information; @@ -467,8 +471,7 @@ XtPointer client_data, call_data; /* common to menu_search and menu_key */ static void -search_menu(wp) -struct xwindow *wp; +search_menu(struct xwindow *wp) { char *pat, buf[BUFSZ + 2]; /* room for '*' + BUFSZ-1 + '*' + '\0' */ struct menu_info_t *menu_info = wp->menu_information; @@ -500,58 +503,65 @@ struct xwindow *wp; } static void -select_all(wp) -struct xwindow *wp; +select_all(struct xwindow *wp) { x11_menu_item *curr; int count; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; - curr = curr->next, count++) - if (curr->identifier.a_void != 0) - if (!curr->selected) { - invert_line(wp, curr, count, -1L); - } - + curr = curr->next, count++) { + /* skip 'curr' if not selectable (header or such) or already + selected (no need to set) or rejected due to skip-invert test */ + if (!curr->identifier.a_void + || curr->selected + || !menuitem_invert_test(1, curr->itemflags, FALSE)) + continue; + invert_line(wp, curr, count, -1L); + } } static void -select_none(wp) -struct xwindow *wp; +select_none(struct xwindow *wp) { x11_menu_item *curr; int count; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; - curr = curr->next, count++) - if (curr->identifier.a_void != 0) - if (curr->selected) { - invert_line(wp, curr, count, -1L); - } + curr = curr->next, count++) { + /* skip 'curr' if not selectable (header or such) or already not + selected (no need to unset) or rejected due to skip-invert test */ + if (!curr->identifier.a_void + || !curr->selected + || !menuitem_invert_test(2, curr->itemflags, TRUE)) + continue; + invert_line(wp, curr, count, -1L); + } } static void -invert_all(wp) -struct xwindow *wp; +invert_all(struct xwindow *wp) { x11_menu_item *curr; int count; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; - curr = curr->next, count++) - if (curr->identifier.a_void != 0) - invert_line(wp, curr, count, -1L); - + curr = curr->next, count++) { + /* skip 'curr' if not selectable (header or such) + or rejected due to skip-invert test */ + if (!curr->identifier.a_void + || !menuitem_invert_test(0, curr->itemflags, curr->selected)) + continue; + invert_line(wp, curr, count, -1L); + } } static void -invert_match(wp, match) -struct xwindow *wp; -char *match; /* wildcard pattern for pmatch() */ +invert_match(struct xwindow *wp, + char *match) /* wildcard pattern for pmatch() */ { x11_menu_item *curr; int count; @@ -569,9 +579,8 @@ char *match; /* wildcard pattern for pmatch() */ } static void -select_match(wp, match) -struct xwindow *wp; -char *match; /* wildcard pattern for pmatch() */ +select_match(struct xwindow *wp, + char *match) /* wildcard pattern for pmatch() */ { x11_menu_item *curr, *found = 0; int count; @@ -596,8 +605,7 @@ char *match; /* wildcard pattern for pmatch() */ } static void -menu_popdown(wp) -struct xwindow *wp; +menu_popdown(struct xwindow *wp) { nh_XtPopdown(wp->popup); /* remove the event grab */ XtDestroyWidget(wp->popup); @@ -607,11 +615,163 @@ struct xwindow *wp; wp->menu_information->is_up = FALSE; /* menu is down */ } +/* construct a bit mask specifying which scrolling operations are allowed */ +static unsigned +menu_scrollmask(struct xwindow *wp) +{ + float shown, top; + Arg args[2]; + Widget hbar = (Widget) 0, vbar = (Widget) 0; + unsigned scrlmask = 0U; + + /* set up args once, then use twice (provided that both scrollbars are + present); 'top' is left for horizontal scrollbar */ + (void) memset(args, 0, sizeof args); + XtSetArg(args[0], nhStr(XtNshown), &shown); + XtSetArg(args[1], nhStr(XtNtopOfThumb), &top); + + find_scrollbars(wp->w, wp->popup, &hbar, &vbar); + if (vbar) { + XtGetValues(vbar, args, TWO); + if (top > 0.0) + scrlmask |= 1U; /* not at top; can scroll up */ + if (top + shown < 1.0) + scrlmask |= 2U; /* more beyond bottom; can scroll down */ + } + if (hbar) { + XtGetValues(hbar, args, TWO); + if (top > 0.0) + scrlmask |= 4U; /* not at left edge; can scroll to left */ + if (top + shown < 1.0) + scrlmask |= 8U; /* more beyond right side; can scroll to right */ + } + return scrlmask; +} + +/* if a menu is scrolled vertically and/horizontally, return it to the top + and far left */ +static void +menu_unscroll(struct xwindow *wp) +{ + float top, left, zero = 0.0; + Arg arg; + Widget hbar = (Widget) 0, vbar = (Widget) 0; + + find_scrollbars(wp->w, wp->popup, &hbar, &vbar); + if (hbar) { + XtSetArg(arg, nhStr(XtNtopOfThumb), &left); + XtGetValues(hbar, &arg, ONE); + if (left > 0.0) + XtCallCallbacks(hbar, XtNjumpProc, &zero); + } + if (vbar) { + XtSetArg(arg, nhStr(XtNtopOfThumb), &top); + XtGetValues(vbar, &arg, ONE); + if (top > 0.0) + XtCallCallbacks(vbar, XtNjumpProc, &zero); + } + return; +} + /* Global functions ======================================================= */ +/* called by X11_update_inventory() if persistent inventory is currently + displayed but the 'perm_invent' option is now Off */ +void +x11_no_perminv(struct xwindow *wp) +{ + if (wp && wp->type == NHW_MENU && wp->menu_information->is_up) { + destroy_menu_entry_widgets(wp); + menu_popdown(wp); + } +} + +/* called by X11_update_inventory() if user has executed #perminv command */ void -X11_start_menu(window) -winid window; +x11_scroll_perminv(int arg UNUSED) /* arg is always 1 */ +{ + static const char extrakeys[] = "\033 \n\r\003\177\b"; + char ch, menukeys[QBUFSZ]; + boolean save_is_active; + unsigned scrlmask; + Cardinal no_args = 0; + struct xwindow *wp = &window_list[WIN_INVEN]; + + /* caller has ensured that perm_invent is enabled, but the window + might not be displayed; if that's the case, display it */ + if (wp->type == NHW_MENU && !wp->menu_information->is_up) + X11_update_inventory(0); + /* if it's still not displayed for some reason, bail out now */ + if (wp->type != NHW_MENU || !wp->menu_information->is_up) { + X11_nhbell(); + return; + } + + do { + scrlmask = menu_scrollmask(wp); + (void) collect_menu_keys(menukeys, scrlmask, FALSE); + /* + * Add quitchars plus a few others to the player's scrolling keys. + * We accept some extra characters that menus usually ignore: + * ^C will be treated like , leaving menu positioned as-is + * and returning to play; or will be treated + * like and , resetting the menu to its top and + * returning to play; other characters will either be rejected by + * yn_function or stay here for scrolling. + */ + Strcat(menukeys, extrakeys); + /* append any scrolling keys excluded by scrlmask, after the \033 + added by extrakeys; they'll be acceptable but not shown */ + (void) collect_menu_keys(eos(menukeys), ~scrlmask, FALSE); + + /* normally the perm_invent menu is not flagged 'is_active' because + it doesn't accept input, so menu_popdown() doesn't set the flag + for the event loop to exit; force 'is_active' while this prompt + is in progress so that the prompt won't be left pending if + player closes the menu via mouse */ + save_is_active = wp->menu_information->is_active; + wp->menu_information->is_active = TRUE; + ch = X11_yn_function_core("Inventory scroll:", menukeys, + 0, (YN_NO_LOGMESG | YN_NO_DEFAULT)); + if (wp->menu_information->is_up) + wp->menu_information->is_active = save_is_active; + else + ch = 0; + + if (ch == C('c')) /* ^C */ + ch = '\033'; + else if (ch == '\177' || ch == '\b') /* or */ + ch = '\n'; + + if (ch && ch != '\033') { + /* in case persistent inventory window is covered, force it + to be on top; does not grab pointer or keyboard focus */ + XMapRaised(XtDisplay(wp->popup), XtWindow(wp->popup)); + + /* the fake event never goes onto X's event queue; it is only + examined by menu_key(), so we shortcut the messy details in + favor of easy to handle union type code; might conceivably + confuse a sophisticated debugger so we should possibly redo + this to set it up properly: event->keyevent->keycode */ + fake_perminv_event.type = ch; + menu_key(wp->w, &fake_perminv_event, (String *) 0, &no_args); + fake_perminv_event.type = 0; + } + + /* if yn_function() is using a popup (the 'slow=False' setting + in NetHack.ad) for its prompt+response and there is any + overlap between the persistent inventory and main windows, + perm_invent would be pushed behind the map every iteration of + this loop, so handle only one character at a time for !slow */ + if (!appResources.slow) + break; + } while (ch && !strchr(quitchars, ch)); + + return; +} + +void +X11_start_menu(winid window, unsigned long mbehavior UNUSED) { struct xwindow *wp; check_winid(window); @@ -619,7 +779,7 @@ winid window; wp = &window_list[window]; if (wp->menu_information->is_menu) { - /* make sure we'ere starting with a clean slate */ + /* make sure we're starting with a clean slate */ free_menu(&wp->menu_information->new_menu); } else { wp->menu_information->is_menu = TRUE; @@ -628,20 +788,19 @@ winid window; /*ARGSUSED*/ void -X11_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) -winid window; -int glyph; /* unused (for now) */ -const anything *identifier; -char ch; -char gch; /* group accelerator (0 = no group) */ -int attr; -const char *str; -boolean preselected; +X11_add_menu(winid window, + const glyph_info *glyphinfo UNUSED, + const anything *identifier, + char ch, /* selector letter; 0 if not selectable */ + char gch, /* group accelerator (0 = no group) */ + int attr, + int clr, + const char *str, + unsigned itemflags) { x11_menu_item *item; struct menu_info_t *menu_info; - - nhUse(glyph); + boolean preselected = (itemflags & MENU_ITEMFLAGS_SELECTED) != 0; check_winid(window); menu_info = window_list[window].menu_information; @@ -654,6 +813,8 @@ boolean preselected; item->next = (x11_menu_item *) 0; item->identifier = *identifier; item->attr = attr; + item->color = clr; + item->itemflags = itemflags; item->selected = item->preselected = preselected; item->pick_count = -1L; item->window = window; @@ -705,9 +866,7 @@ boolean preselected; } void -X11_end_menu(window, query) -winid window; -const char *query; +X11_end_menu(winid window, const char *query) { struct menu_info_t *menu_info; @@ -722,10 +881,7 @@ const char *query; } int -X11_select_menu(window, how, menu_list) -winid window; -int how; -menu_item **menu_list; +X11_select_menu(winid window, int how, menu_item **menu_list) { x11_menu_item *curr; struct xwindow *wp; @@ -759,7 +915,7 @@ menu_item **menu_list; winid newwin = X11_create_nhwindow(NHW_MENU); struct xwindow *nwp = &window_list[newwin]; - X11_start_menu(newwin); + X11_start_menu(newwin, MENU_BEHAVE_STANDARD); move_menu(&menu_info->new_menu, &nwp->menu_information->new_menu); for (curr = nwp->menu_information->new_menu.base; curr; curr = curr->next) @@ -792,11 +948,11 @@ menu_item **menu_list; if (n > 0) /* at least one group accelerator found */ for (ap = gacc, curr = menu_info->new_menu.base; curr; curr = curr->next) - if (curr->gselector && !index(gacc, curr->gselector) + if (curr->gselector && !strchr(gacc, curr->gselector) && (menu_info->how == PICK_ANY || gcnt[GSELIDX(curr->gselector)] == 1)) { *ap++ = curr->gselector; - *ap = '\0'; /* re-terminate for index() */ + *ap = '\0'; /* re-terminate for strchr() */ } } menu_info->new_menu.gacc = copy_of(gacc); @@ -808,14 +964,9 @@ menu_item **menu_list; permi = (window == WIN_INVEN && iflags.perm_invent && how == PICK_NONE); - if (menu_info->is_up) { - if (!menu_info->permi) { - destroy_menu_entry_widgets(wp); - nh_XtPopdown(wp->popup); - XtDestroyWidget(wp->popup); - wp->w = wp->popup = (Widget) 0; - menu_info->is_up = FALSE; - } + if (menu_info->is_up && !menu_info->permi) { + destroy_menu_entry_widgets(wp); + menu_popdown(wp); } if (!menu_info->is_up) { @@ -867,7 +1018,11 @@ menu_item **menu_list; num_args = 0; XtSetArg(args[num_args], nhStr(XtNallowVert), True); num_args++; - XtSetArg(args[num_args], nhStr(XtNallowHoriz), False); num_args++; + /* allow horizontal scroll bar for persistent inventory window; + it could be allowed for any menu, but when scrolled to the side + the selector letters aren't visible so we won't do that [yet?] */ + XtSetArg(args[num_args], nhStr(XtNallowHoriz), permi ? True : False); + num_args++; XtSetArg(args[num_args], nhStr(XtNuseBottom), True); num_args++; XtSetArg(args[num_args], nhStr(XtNuseRight), True); num_args++; #if 0 @@ -880,10 +1035,9 @@ menu_item **menu_list; XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++; XtSetArg(args[num_args], XtNtranslations, menu_translation_table); num_args++; - viewport_widget = XtCreateManagedWidget( - "menu_viewport", /* name */ - viewportWidgetClass, form, /* parent widget */ - args, num_args); /* values, and number of values */ + viewport_widget = XtCreateManagedWidget("menu_viewport", + viewportWidgetClass, form, + args, num_args); num_args = 0; XtSetArg(args[num_args], XtNwidth, 100); @@ -933,7 +1087,7 @@ menu_item **menu_list; menu_info->is_up = TRUE; if (permi) { - if (permi && menu_info->permi_x != -1) { + if (menu_info->permi_x != -1) { /* Cannot set window x,y at creation time, we must move the window now instead */ XMoveWindow(XtDisplay(wp->popup), XtWindow(wp->popup), @@ -941,7 +1095,7 @@ menu_item **menu_list; } /* cant use nh_XtPopup() because it may try to grab the focus */ XtPopup(wp->popup, (int) XtGrabNone); - if (permi && menu_info->permi_x == -1) { + if (menu_info->permi_x == -1) { /* remember perm_invent window geometry the first time */ get_widget_window_geometry(wp->popup, &menu_info->permi_x, @@ -998,8 +1152,7 @@ menu_item **menu_list; * zero length. */ static char * -copy_of(s) -const char *s; +copy_of(const char *s) { if (!s) s = ""; @@ -1010,9 +1163,7 @@ const char *s; * Create ok, cancel, all, none, invert, and search buttons. */ static Widget -menu_create_buttons(wp, form, under) -struct xwindow *wp; -Widget form,under; +menu_create_buttons(struct xwindow *wp, Widget form, Widget under) { Arg args[15]; Cardinal num_args; @@ -1107,7 +1258,8 @@ Widget form,under; num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), invert); num_args++; - XtSetArg(args[num_args], nhStr(XtNsensitive), how != PICK_NONE); num_args++; + XtSetArg(args[num_args], nhStr(XtNsensitive), how != PICK_NONE); + num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; @@ -1134,9 +1286,7 @@ Widget form,under; } static void -menu_create_entries(wp, curr_menu) -struct xwindow *wp; -struct menu *curr_menu; +menu_create_entries(struct xwindow *wp, struct menu *curr_menu) { x11_menu_item *curr; int menulineidx = 0; @@ -1144,6 +1294,7 @@ struct menu *curr_menu; int how = wp->menu_information->how; Arg args[15]; Cardinal num_args; + Dimension cwidth, maxwidth = 0; for (curr = curr_menu->base; curr; curr = curr->next) { char tmpbuf[BUFSZ]; @@ -1155,6 +1306,7 @@ struct menu *curr_menu; num_args = 0; XtSetArg(args[num_args], nhStr(XtNlabel), str); num_args++; + XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; @@ -1162,9 +1314,9 @@ struct menu *curr_menu; XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++; XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++; - if (!iflags.use_menu_color || wp->menu_information->disable_mcolors - || !get_menu_coloring(curr->str, &color, &attr)) - attr = curr->attr; + attr = curr->attr; + if (!wp->menu_information->disable_mcolors) + color = curr->color; if (color != NO_COLOR) { if (attr != ATR_INVERSE) @@ -1182,7 +1334,8 @@ struct menu *curr_menu; } if (menulineidx) { - XtSetArg(args[num_args], nhStr(XtNfromVert), prevlinewidget); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), prevlinewidget); + num_args++; } else { XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; } @@ -1210,12 +1363,27 @@ struct menu *curr_menu; XtAddCallback(linewidget, XtNcallback, menu_select, (XtPointer) curr); prevlinewidget = linewidget; + + if (canpick) { + /* get the current line width */ + XtSetArg(args[0], XtNwidth, &cwidth); + XtGetValues(curr->w, args, ONE); + if (maxwidth < cwidth) + maxwidth = cwidth; + } + } + + /* set all selectable menu entries to the maximum width */ + if (how != PICK_NONE) { + XtSetArg(args[0], XtNwidth, maxwidth); + for (curr = curr_menu->base; curr; curr = curr->next) + if (curr->identifier.a_void) + XtSetValues(curr->w, args, ONE); } } static void -destroy_menu_entry_widgets(wp) -struct xwindow *wp; +destroy_menu_entry_widgets(struct xwindow *wp) { WidgetList wlist; Cardinal numchild; @@ -1239,8 +1407,7 @@ struct xwindow *wp; } static void -move_menu(src_menu, dest_menu) -struct menu *src_menu, *dest_menu; +move_menu(struct menu *src_menu, struct menu *dest_menu) { free_menu(dest_menu); /* toss old menu */ *dest_menu = *src_menu; /* make new menu current */ @@ -1249,8 +1416,7 @@ struct menu *src_menu, *dest_menu; } static void -free_menu_line_entries(mp) -struct menu *mp; +free_menu_line_entries(struct menu *mp) { /* We're not freeing menu entry widgets here, but let XtDestroyWidget() on the parent widget take care of that */ @@ -1263,8 +1429,7 @@ struct menu *mp; } static void -free_menu(mp) -struct menu *mp; +free_menu(struct menu *mp) { free_menu_line_entries(mp); if (mp->query) @@ -1275,8 +1440,7 @@ struct menu *mp; } static void -reset_menu_to_default(mp) -struct menu *mp; +reset_menu_to_default(struct menu *mp) { mp->base = mp->last = (x11_menu_item *) 0; mp->query = (const char *) 0; @@ -1286,8 +1450,7 @@ struct menu *mp; } static void -clear_old_menu(wp) -struct xwindow *wp; +clear_old_menu(struct xwindow *wp) { struct menu_info_t *menu_info = wp->menu_information; @@ -1303,8 +1466,7 @@ struct xwindow *wp; } void -create_menu_window(wp) -struct xwindow *wp; +create_menu_window(struct xwindow *wp) { wp->type = NHW_MENU; wp->menu_information = @@ -1322,8 +1484,7 @@ struct xwindow *wp; } void -destroy_menu_window(wp) -struct xwindow *wp; +destroy_menu_window(struct xwindow *wp) { clear_old_menu(wp); /* this will also destroy the widgets */ free((genericptr_t) wp->menu_information); diff --git a/win/X11/winmesg.c b/win/X11/winmesg.c index 32f3909b2..107c37d58 100644 --- a/win/X11/winmesg.c +++ b/win/X11/winmesg.c @@ -1,15 +1,15 @@ -/* NetHack 3.6 winmesg.c $NHDT-Date: 1454811935 2016/02/07 02:25:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ */ -/* Copyright (c) Dean Luick, 1992 */ +/* NetHack 5.0 winmesg.c $NHDT-Date: 1596498373 2020/08/03 23:46:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ +/* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Message window routines. * * Global functions: - * create_message_window() - * destroy_message_window() - * display_message_window() - * append_message() + * create_message_window() + * destroy_message_window() + * display_message_window() + * append_message() */ #ifndef SYSV @@ -35,15 +35,15 @@ #include "hack.h" #include "winX.h" -static struct line_element *FDECL(get_previous, (struct line_element *)); -static void FDECL(set_circle_buf, (struct mesg_info_t *, int)); -static char *FDECL(split, (char *, XFontStruct *, DIMENSION_P)); -static void FDECL(add_line, (struct mesg_info_t *, const char *)); -static void FDECL(redraw_message_window, (struct xwindow *)); -static void FDECL(mesg_check_size_change, (struct xwindow *)); -static void FDECL(mesg_exposed, (Widget, XtPointer, XtPointer)); -static void FDECL(get_gc, (Widget, struct mesg_info_t *)); -static void FDECL(mesg_resized, (Widget, XtPointer, XtPointer)); +static struct line_element *get_previous(struct line_element *); +static void set_circle_buf(struct mesg_info_t *, int); +static char *split(char *, XFontStruct *, Dimension); +static void add_line(struct mesg_info_t *, const char *); +static void redraw_message_window(struct xwindow *); +static void mesg_check_size_change(struct xwindow *); +static void mesg_exposed(Widget, XtPointer, XtPointer); +static void get_gc(Widget, struct mesg_info_t *); +static void mesg_resized(Widget, XtPointer, XtPointer); static char mesg_translations[] = "#override\n\ Left: scroll(4)\n\ @@ -56,8 +56,7 @@ static char mesg_translations[] = "#override\n\ /* Move the message window's vertical scrollbar's slider to the bottom. */ void -set_message_slider(wp) -struct xwindow *wp; +set_message_slider(struct xwindow *wp) { Widget scrollbar; float top; @@ -71,10 +70,8 @@ struct xwindow *wp; } void -create_message_window(wp, create_popup, parent) -struct xwindow *wp; /* window pointer */ -boolean create_popup; -Widget parent; +create_message_window(struct xwindow *wp, /* window pointer */ + boolean create_popup, Widget parent) { Arg args[8]; Cardinal num_args; @@ -95,8 +92,8 @@ Widget parent; if (iflags.msg_history < (unsigned) appResources.message_lines) iflags.msg_history = (unsigned) appResources.message_lines; - if (iflags.msg_history > MAX_HISTORY) /* a sanity check */ - iflags.msg_history = MAX_HISTORY; + if (iflags.msg_history > MAX_MSG_HISTORY) /* a sanity check */ + iflags.msg_history = MAX_MSG_HISTORY; set_circle_buf(mesg_info, (int) iflags.msg_history); @@ -209,8 +206,7 @@ Widget parent; } void -destroy_message_window(wp) -struct xwindow *wp; +destroy_message_window(struct xwindow *wp) { if (wp->popup) { nh_XtPopdown(wp->popup); @@ -230,8 +226,7 @@ struct xwindow *wp; /* Redraw message window if new lines have been added. */ void -display_message_window(wp) -struct xwindow *wp; +display_message_window(struct xwindow *wp) { set_message_slider(wp); if (wp->mesg_information->dirty) @@ -243,9 +238,7 @@ struct xwindow *wp; * rendering of the text is too long for the window. */ void -append_message(wp, str) -struct xwindow *wp; -const char *str; +append_message(struct xwindow *wp, const char *str) { char *mark, *remainder, buf[BUFSZ]; @@ -270,8 +263,7 @@ const char *str; * element. */ static struct line_element * -get_previous(mark) -struct line_element *mark; +get_previous(struct line_element *mark) { struct line_element *curr; @@ -290,9 +282,7 @@ struct line_element *mark; * are no longer used. */ static void -set_circle_buf(mesg_info, count) -struct mesg_info_t *mesg_info; -int count; +set_circle_buf(struct mesg_info_t *mesg_info, int count) { int i; struct line_element *tail, *curr, *head; @@ -367,10 +357,9 @@ int count; * not, back up from the end by words until we find a place to split. */ static char * -split(s, fs, pixel_width) -char *s; -XFontStruct *fs; /* Font for the window. */ -Dimension pixel_width; +split(char *s, + XFontStruct *fs, /* Font for the window. */ + Dimension pixel_width) { char save, *end, *remainder; @@ -394,18 +383,16 @@ Dimension pixel_width; } /* - * Add a line of text to the window. The first line in the curcular list + * Add a line of text to the window. The first line in the circular list * becomes the last. So all we have to do is copy the new line over the * old one. If the line buffer is too small, then allocate a new, larger * one. */ static void -add_line(mesg_info, s) -struct mesg_info_t *mesg_info; -const char *s; +add_line(struct mesg_info_t *mesg_info, const char *s) { - register struct line_element *curr = mesg_info->head; - register int new_line_length = strlen(s); + struct line_element *curr = mesg_info->head; + int new_line_length = strlen(s); if (new_line_length + 1 > curr->buf_length) { if (curr->line) @@ -423,7 +410,7 @@ const char *s; } /* - * Save a position in the text buffer so we can draw a line to seperate + * Save a position in the text buffer so we can draw a line to separate * text from the last time this function was called. * * Save the head position, since it is the line "after" the last displayed @@ -431,10 +418,9 @@ const char *s; * line above this saved pointer. */ void -set_last_pause(wp) -struct xwindow *wp; +set_last_pause(struct xwindow *wp) { - register struct mesg_info_t *mesg_info = wp->mesg_information; + struct mesg_info_t *mesg_info = wp->mesg_information; #ifdef ERASE_LINE /* @@ -459,18 +445,17 @@ struct xwindow *wp; } static void -redraw_message_window(wp) -struct xwindow *wp; +redraw_message_window(struct xwindow *wp) { struct mesg_info_t *mesg_info = wp->mesg_information; - register struct line_element *curr; - register int row, y_base; + struct line_element *curr; + int row, y_base; /* * Do this the cheap and easy way. Clear the window and just redraw * the whole thing. * - * This could be done more effecently with one call to XDrawText() instead + * This could be done more efficiently with one call to XDrawText() instead * of many calls to XDrawString(). Maybe later. * * Only need to clear if window has new text. @@ -504,8 +489,7 @@ struct xwindow *wp; * move the vertical slider to the bottom. */ static void -mesg_check_size_change(wp) -struct xwindow *wp; +mesg_check_size_change(struct xwindow *wp) { struct mesg_info_t *mesg_info = wp->mesg_information; Arg arg[2]; @@ -531,10 +515,9 @@ struct xwindow *wp; /* Event handler for message window expose events. */ /*ARGSUSED*/ static void -mesg_exposed(w, client_data, widget_data) -Widget w; -XtPointer client_data; /* unused */ -XtPointer widget_data; /* expose event from Window widget */ +mesg_exposed(Widget w, + XtPointer client_data, /* unused */ + XtPointer widget_data) /* expose event from Window widget */ { XExposeEvent *event = (XExposeEvent *) widget_data; @@ -564,9 +547,7 @@ XtPointer widget_data; /* expose event from Window widget */ } static void -get_gc(w, mesg_info) -Widget w; -struct mesg_info_t *mesg_info; +get_gc(Widget w, struct mesg_info_t *mesg_info) { XGCValues values; XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont; @@ -586,7 +567,7 @@ struct mesg_info_t *mesg_info; /* * Handle resizes on a message window. Correct saved pixel height and width. - * Adjust circle buffer to accomidate the new size. + * Adjust circle buffer to accommodate the new size. * * Problem: If the resize decreases the width of the window such that * some lines are now longer than the window, they will be cut off by @@ -596,9 +577,7 @@ struct mesg_info_t *mesg_info; */ /* ARGSUSED */ static void -mesg_resized(w, client_data, call_data) -Widget w; -XtPointer call_data, client_data; +mesg_resized(Widget w, XtPointer call_data, XtPointer client_data) { Arg args[4]; Cardinal num_args; diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 04eb682c9..4baae3f49 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winmisc.c $NHDT-Date: 1554135506 2019/04/01 16:18:26 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.44 $ */ +/* NetHack 5.0 winmisc.c $NHDT-Date: 1596498374 2020/08/03 23:46:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.49 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -24,7 +24,7 @@ #include #include #include -#include /* for index() */ +#include /* for strchr() */ #include #ifdef PRESERVE_NO_SYSV @@ -34,7 +34,10 @@ #undef PRESERVE_NO_SYSV #endif +#define X11_BUILD #include "hack.h" +#undef X11_BUILD + #include "func_tab.h" #include "winX.h" @@ -91,35 +94,44 @@ static const char popup_entry_translations[] = "#override\n\ : scroll(8)\n\ : scroll(2)"; -static void FDECL(ps_quit, (Widget, XtPointer, XtPointer)); -static void FDECL(ps_random, (Widget, XtPointer, XtPointer)); -static void FDECL(ps_select, (Widget, XtPointer, XtPointer)); -static void FDECL(extend_select, (Widget, XtPointer, XtPointer)); -static void FDECL(extend_dismiss, (Widget, XtPointer, XtPointer)); -static void FDECL(extend_help, (Widget, XtPointer, XtPointer)); -static void FDECL(popup_delete, (Widget, XEvent *, String *, Cardinal *)); -static void NDECL(ec_dismiss); -static void FDECL(ec_scroll_to_view, (int)); -static void NDECL(init_extended_commands_popup); -static Widget FDECL(make_menu, (const char *, const char *, const char *, - const char *, XtCallbackProc, const char *, - XtCallbackProc, int, const char **, - Widget **, XtCallbackProc, Widget *)); - -void NDECL(X11_player_selection_setupOthers); -void NDECL(X11_player_selection_randomize); +static void plsel_dialog_acceptvalues(void); +static void plsel_set_play_button(boolean); +static void plsel_set_sensitivities(boolean); +static void X11_player_selection_randomize(void); +static void X11_player_selection_setupOthers(void); +static void racetoggleCallback(Widget, XtPointer, XtPointer); +static void roletoggleCallback(Widget, XtPointer, XtPointer); +static void gendertoggleCallback(Widget, XtPointer, XtPointer); +static void aligntoggleCallback(Widget, XtPointer, XtPointer); +static void plsel_random_btn_callback(Widget, XtPointer, XtPointer); +static void plsel_play_btn_callback(Widget, XtPointer, XtPointer); +static void plsel_quit_btn_callback(Widget, XtPointer, XtPointer); +static Widget X11_create_player_selection_name(Widget); +static void X11_player_selection_dialog(void); +static void X11_player_selection_prompts(void); +static void ps_quit(Widget, XtPointer, XtPointer); +static void ps_random(Widget, XtPointer, XtPointer); +static void ps_select(Widget, XtPointer, XtPointer); +static void extend_select(Widget, XtPointer, XtPointer); +static void extend_dismiss(Widget, XtPointer, XtPointer); +static void extend_help(Widget, XtPointer, XtPointer); +static void popup_delete(Widget, XEvent *, String *, Cardinal *); +static void ec_dismiss(void); +static void ec_scroll_to_view(int); +static void init_extended_commands_popup(void); +static Widget make_menu(const char *, const char *, const char *, const char *, + XtCallbackProc, const char *, XtCallbackProc, int, + const char **, Widget **, XtCallbackProc, Widget *); /* Bad Hack alert. Using integers instead of XtPointers */ XtPointer -i2xtp(i) -int i; +i2xtp(int i) { return (XtPointer) (ptrdiff_t) i; } int -xtp2i(x) -XtPointer x; +xtp2i(XtPointer x) { return (int) (ptrdiff_t) x; } @@ -127,9 +139,7 @@ XtPointer x; /* Player Selection ------------------------------------------------------- */ /* ARGSUSED */ static void -ps_quit(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +ps_quit(Widget w, XtPointer client_data, XtPointer call_data) { nhUse(w); nhUse(client_data); @@ -141,9 +151,7 @@ XtPointer client_data, call_data; /* ARGSUSED */ static void -ps_random(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +ps_random(Widget w, XtPointer client_data, XtPointer call_data) { nhUse(w); nhUse(client_data); @@ -155,9 +163,7 @@ XtPointer client_data, call_data; /* ARGSUSED */ static void -ps_select(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +ps_select(Widget w, XtPointer client_data, XtPointer call_data) { nhUse(w); nhUse(call_data); @@ -168,11 +174,7 @@ XtPointer client_data, call_data; /* ARGSUSED */ void -ps_key(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +ps_key(Widget w, XEvent *event, String *params, Cardinal *num_params) { char ch, *mark; char rolechars[QBUFSZ]; @@ -182,13 +184,13 @@ Cardinal *num_params; nhUse(params); nhUse(num_params); - (void) memset(rolechars, '\0', sizeof rolechars); /* for index() */ + (void) memset(rolechars, '\0', sizeof rolechars); /* for strchr() */ for (i = 0; roles[i].name.m; ++i) { ch = lowc(*roles[i].name.m); /* if (flags.female && roles[i].name.f) ch = lowc(*roles[i].name.f); */ /* this supports at most two roles with the same first letter */ - if (index(rolechars, ch)) + if (strchr(rolechars, ch)) ch = highc(ch); rolechars[i] = ch; } @@ -197,15 +199,15 @@ Cardinal *num_params; /* don't beep */ return; } - mark = index(rolechars, ch); + mark = strchr(rolechars, ch); if (!mark) - mark = index(rolechars, lowc(ch)); + mark = strchr(rolechars, lowc(ch)); if (!mark) - mark = index(rolechars, highc(ch)); + mark = strchr(rolechars, highc(ch)); if (!mark) { - if (index(ps_randchars, ch)) + if (strchr(ps_randchars, ch)) ps_selected = PS_RANDOM; - else if (index(ps_quitchars, ch)) + else if (strchr(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such class */ @@ -218,11 +220,7 @@ Cardinal *num_params; /* ARGSUSED */ void -race_key(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +race_key(Widget w, XEvent *event, String *params, Cardinal *num_params) { char ch, *mark; char racechars[QBUFSZ]; @@ -232,11 +230,11 @@ Cardinal *num_params; nhUse(params); nhUse(num_params); - (void) memset(racechars, '\0', sizeof racechars); /* for index() */ + (void) memset(racechars, '\0', sizeof racechars); /* for strchr() */ for (i = 0; races[i].noun; ++i) { ch = lowc(*races[i].noun); /* this supports at most two races with the same first letter */ - if (index(racechars, ch)) + if (strchr(racechars, ch)) ch = highc(ch); racechars[i] = ch; } @@ -245,15 +243,15 @@ Cardinal *num_params; /* don't beep */ return; } - mark = index(racechars, ch); + mark = strchr(racechars, ch); if (!mark) - mark = index(racechars, lowc(ch)); + mark = strchr(racechars, lowc(ch)); if (!mark) - mark = index(racechars, highc(ch)); + mark = strchr(racechars, highc(ch)); if (!mark) { - if (index(ps_randchars, ch)) + if (strchr(ps_randchars, ch)) ps_selected = PS_RANDOM; - else if (index(ps_quitchars, ch)) + else if (strchr(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such race */ @@ -266,11 +264,7 @@ Cardinal *num_params; /* ARGSUSED */ void -gend_key(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +gend_key(Widget w, XEvent *event, String *params, Cardinal *num_params) { char ch, *mark; static char gendchars[] = "mf"; @@ -284,13 +278,13 @@ Cardinal *num_params; /* don't beep */ return; } - mark = index(gendchars, ch); + mark = strchr(gendchars, ch); if (!mark) - mark = index(gendchars, lowc(ch)); + mark = strchr(gendchars, lowc(ch)); if (!mark) { - if (index(ps_randchars, ch)) + if (strchr(ps_randchars, ch)) ps_selected = PS_RANDOM; - else if (index(ps_quitchars, ch)) + else if (strchr(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such gender */ @@ -303,11 +297,7 @@ Cardinal *num_params; /* ARGSUSED */ void -algn_key(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +algn_key(Widget w, XEvent *event, String *params, Cardinal *num_params) { char ch, *mark; static char algnchars[] = "LNC"; @@ -321,13 +311,13 @@ Cardinal *num_params; /* don't beep */ return; } - mark = index(algnchars, ch); + mark = strchr(algnchars, ch); if (!mark) - mark = index(algnchars, highc(ch)); + mark = strchr(algnchars, highc(ch)); if (!mark) { - if (index(ps_randchars, ch)) + if (strchr(ps_randchars, ch)) ps_selected = PS_RANDOM; - else if (index(ps_quitchars, ch)) + else if (strchr(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such alignment */ @@ -348,8 +338,8 @@ Widget plsel_name_input; Widget plsel_btn_play; -void -plsel_dialog_acceptvalues() +static void +plsel_dialog_acceptvalues(void) { Arg args[2]; String s; @@ -362,21 +352,17 @@ plsel_dialog_acceptvalues() XtSetArg(args[0], nhStr(XtNstring), &s); XtGetValues(plsel_name_input, args, ONE); - (void) strncpy(plname, (char *) s, sizeof plname - 1); - plname[sizeof plname - 1] = '\0'; - (void) mungspaces(plname); - if (strlen(plname) < 1) - (void) strcpy(plname, "Mumbles"); + (void) strncpy(svp.plname, (char *) s, sizeof svp.plname - 1); + svp.plname[sizeof svp.plname - 1] = '\0'; + (void) mungspaces(svp.plname); + if (strlen(svp.plname) < 1) + (void) strcpy(svp.plname, "Mumbles"); iflags.renameinprogress = FALSE; } /* ARGSUSED */ void -plsel_quit(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +plsel_quit(Widget w, XEvent *event, String *params, Cardinal *num_params) { nhUse(w); nhUse(event); @@ -389,11 +375,7 @@ Cardinal *num_params; /* ARGSUSED */ void -plsel_play(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +plsel_play(Widget w, XEvent *event, String *params, Cardinal *num_params) { Arg args[2]; Boolean state; @@ -416,11 +398,7 @@ Cardinal *num_params; /* ARGSUSED */ void -plsel_randomize(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +plsel_randomize(Widget w, XEvent *event, String *params, Cardinal *num_params) { nhUse(w); nhUse(event); @@ -431,9 +409,8 @@ Cardinal *num_params; } /* enable or disable the Play button */ -void -plsel_set_play_button(state) -boolean state; +static void +plsel_set_play_button(boolean state) { Arg args[2]; @@ -441,9 +418,8 @@ boolean state; XtSetValues(plsel_btn_play, args, ONE); } -void -plsel_set_sensitivities(setcurr) -boolean setcurr; +static void +plsel_set_sensitivities(boolean setcurr) { Arg args[2]; int j, valid; @@ -495,13 +471,13 @@ boolean setcurr; X11_player_selection_setupOthers(); } -void -X11_player_selection_randomize() +static void +X11_player_selection_randomize(void) { int nrole = plsel_n_roles; int nrace = plsel_n_races; - int ro, ra, a, g; - boolean fully_specified_role, choose_race_first; + int ro, ra, al, gend; + boolean choose_race_first; boolean picksomething = (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE @@ -524,15 +500,11 @@ X11_player_selection_randomize() ro = flags.initrole; if (ro == ROLE_NONE || ro == ROLE_RANDOM) { ro = rn2(nrole); - if (flags.initrole != ROLE_RANDOM) { - fully_specified_role = FALSE; - } } ra = flags.initrace; if (ra == ROLE_NONE || ra == ROLE_RANDOM) { ra = rn2(nrace); if (flags.initrace != ROLE_RANDOM) { - fully_specified_role = FALSE; } } @@ -543,47 +515,39 @@ X11_player_selection_randomize() choose_race_first = TRUE; } - while (!validrace(ro,ra)) { + while (!validrace(ro, ra)) { if (choose_race_first) { ro = rn2(nrole); - if (flags.initrole != ROLE_RANDOM) { - fully_specified_role = FALSE; - } } else { ra = rn2(nrace); - if (flags.initrace != ROLE_RANDOM) { - fully_specified_role = FALSE; - } } } - g = flags.initgend; - if (g == ROLE_NONE) { - g = rn2(ROLE_GENDERS); - fully_specified_role = FALSE; + gend = flags.initgend; + if (gend == ROLE_NONE) { + gend = rn2(ROLE_GENDERS); } - while (!validgend(ro,ra,g)) { - g = rn2(ROLE_GENDERS); + while (!validgend(ro, ra, gend)) { + gend = rn2(ROLE_GENDERS); } - a = flags.initalign; - if (a == ROLE_NONE) { - a = rn2(ROLE_ALIGNS); - fully_specified_role = FALSE; + al = flags.initalign; + if (al == ROLE_NONE) { + al = rn2(ROLE_ALIGNS); } - while (!validalign(ro,ra,a)) { - a = rn2(ROLE_ALIGNS); + while (!validalign(ro, ra, al)) { + al = rn2(ROLE_ALIGNS); } - XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(g + 1)); - XawToggleSetCurrent(plsel_align_radios[0], i2xtp(a + 1)); + XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(gend + 1)); + XawToggleSetCurrent(plsel_align_radios[0], i2xtp(al + 1)); XawToggleSetCurrent(plsel_race_radios[0], i2xtp(ra + 1)); XawToggleSetCurrent(plsel_role_radios[0], i2xtp(ro + 1)); plsel_set_sensitivities(FALSE); } -void -X11_player_selection_setupOthers() +static void +X11_player_selection_setupOthers(void) { Arg args[2]; int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1; @@ -629,9 +593,7 @@ X11_player_selection_setupOthers() } static void -racetoggleCallback(w, client, call) -Widget w; -XtPointer client, call; +racetoggleCallback(Widget w, XtPointer client, XtPointer call) { Arg args[2]; int j, valid; @@ -670,9 +632,7 @@ XtPointer client, call; } static void -roletoggleCallback(w, client, call) -Widget w; -XtPointer client, call; +roletoggleCallback(Widget w, XtPointer client, XtPointer call) { Arg args[2]; int j, valid; @@ -711,9 +671,7 @@ XtPointer client, call; } static void -gendertoggleCallback(w, client, call) -Widget w; -XtPointer client, call; +gendertoggleCallback(Widget w, XtPointer client, XtPointer call) { int i, r = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1; @@ -735,9 +693,7 @@ XtPointer client, call; } static void -aligntoggleCallback(w, client, call) -Widget w; -XtPointer client, call; +aligntoggleCallback(Widget w, XtPointer client, XtPointer call) { int r = xtp2i(XawToggleGetCurrent(plsel_align_radios[0])) - 1; @@ -749,10 +705,7 @@ XtPointer client, call; } static void -plsel_random_btn_callback(w, client, call) -Widget w; -XtPointer client; -XtPointer call; +plsel_random_btn_callback(Widget w, XtPointer client, XtPointer call) { nhUse(w); nhUse(client); @@ -762,10 +715,7 @@ XtPointer call; } static void -plsel_play_btn_callback(w, client, call) -Widget w; -XtPointer client; -XtPointer call; +plsel_play_btn_callback(Widget w, XtPointer client, XtPointer call) { nhUse(w); nhUse(client); @@ -776,10 +726,7 @@ XtPointer call; } static void -plsel_quit_btn_callback(w, client, call) -Widget w; -XtPointer client; -XtPointer call; +plsel_quit_btn_callback(Widget w, XtPointer client, XtPointer call) { nhUse(w); nhUse(client); @@ -789,9 +736,8 @@ XtPointer call; exit_x_event = TRUE; /* leave event loop */ } -Widget -X11_create_player_selection_name(form) -Widget form; +static Widget +X11_create_player_selection_name(Widget form) { Widget namelabel, name_vp, name_form; Arg args[10]; @@ -833,8 +779,8 @@ Widget form; XtSetArg(args[num_args], nhStr(XtNeditType), !plsel_ask_name ? XawtextRead : XawtextEdit); num_args++; XtSetArg(args[num_args], nhStr(XtNresize), XawtextResizeWidth); num_args++; - XtSetArg(args[num_args], nhStr(XtNstring), plname); num_args++; - XtSetArg(args[num_args], XtNinsertPosition, strlen(plname)); num_args++; + XtSetArg(args[num_args], nhStr(XtNstring), svp.plname); num_args++; + XtSetArg(args[num_args], XtNinsertPosition, strlen(svp.plname)); num_args++; XtSetArg(args[num_args], nhStr(XtNaccelerators), XtParseAcceleratorTable(plsel_input_accelerators)); num_args++; plsel_name_input = XtCreateManagedWidget("name_input", @@ -852,8 +798,8 @@ Widget form; return name_vp; } -void -X11_player_selection_dialog() +static void +X11_player_selection_dialog(void) { Widget popup, popup_vp; Widget form; @@ -978,13 +924,15 @@ X11_player_selection_dialog() Widget racewidget; num_args = 0; - if (i > 0) + if (i > 0) { XtSetArg(args[num_args], nhStr(XtNfromVert), tmpwidget); num_args++; + } XtSetArg(args[num_args], XtNwidth, cwid); num_args++; - if (i > 0) + if (i > 0) { XtSetArg(args[num_args], nhStr(XtNradioGroup), plsel_race_radios[0]); num_args++; + } XtSetArg(args[num_args], nhStr(XtNradioData), (i + 1)); num_args++; racewidget = XtCreateManagedWidget(races[i].noun, @@ -1040,13 +988,15 @@ X11_player_selection_dialog() Widget rolewidget; num_args = 0; - if (i > 0) + if (i > 0) { XtSetArg(args[num_args], nhStr(XtNfromVert), tmpwidget); num_args++; + } XtSetArg(args[num_args], nhStr(XtNwidth), cwid); num_args++; - if (i > 0) + if (i > 0) { XtSetArg(args[num_args], nhStr(XtNradioGroup), plsel_role_radios[0]); num_args++; + } XtSetArg(args[num_args], nhStr(XtNradioData), (i + 1)); num_args++; rolewidget = XtCreateManagedWidget(roles[i].name.m, toggleWidgetClass, @@ -1270,16 +1220,19 @@ X11_player_selection_dialog() if (plsel_align_radios) free(plsel_align_radios); - if (ps_selected == PS_QUIT || program_state.done_hup) { + if (ps_selected == PS_QUIT +#if defined(HANGUPHANDLING) + || program_state.done_hup +#endif + ) { clearlocks(); X11_exit_nhwindows((char *) 0); nh_terminate(0); } } -/* Global functions ======================================================== */ -void -X11_player_selection_prompts() +static void +X11_player_selection_prompts(void) { int num_roles, num_races, num_gends, num_algns, i, availcount, availindex; Widget popup, player_form; @@ -1345,7 +1298,11 @@ X11_player_selection_prompts() XtDestroyWidget(popup); free((genericptr_t) choices), choices = 0; - if (ps_selected == PS_QUIT || program_state.done_hup) { + if (ps_selected == PS_QUIT +#if defined(HANGUPHANDLING) + || program_state.done_hup +#endif + ) { clearlocks(); X11_exit_nhwindows((char *) 0); nh_terminate(0); @@ -1414,7 +1371,11 @@ X11_player_selection_prompts() XtDestroyWidget(popup); free((genericptr_t) choices), choices = 0; - if (ps_selected == PS_QUIT || program_state.done_hup) { + if (ps_selected == PS_QUIT +#if defined(HANGUPHANDLING) + || program_state.done_hup +#endif + ) { clearlocks(); X11_exit_nhwindows((char *) 0); nh_terminate(0); @@ -1482,7 +1443,11 @@ X11_player_selection_prompts() XtDestroyWidget(popup); free((genericptr_t) choices), choices = 0; - if (ps_selected == PS_QUIT || program_state.done_hup) { + if (ps_selected == PS_QUIT +#if defined(HANGUPHANDLING) + || program_state.done_hup +#endif + ) { clearlocks(); X11_exit_nhwindows((char *) 0); nh_terminate(0); @@ -1548,7 +1513,11 @@ X11_player_selection_prompts() XtDestroyWidget(popup); free((genericptr_t) choices), choices = 0; - if (ps_selected == PS_QUIT || program_state.done_hup) { + if (ps_selected == PS_QUIT +#if defined(HANGUPHANDLING) + || program_state.done_hup +#endif + ) { clearlocks(); X11_exit_nhwindows((char *) 0); nh_terminate(0); @@ -1564,19 +1533,21 @@ X11_player_selection_prompts() } } +/* Global functions ======================================================== */ + void -X11_player_selection() +X11_player_selection(void) { if (iflags.wc_player_selection == VIA_DIALOG) { - if (!*plname) { + if (!*svp.plname) { #ifdef UNIX char *defplname = get_login_name(); #else char *defplname = (char *)0; #endif - (void) strncpy(plname, defplname ? defplname : "Mumbles", - sizeof plname - 1); - plname[sizeof plname - 1] = '\0'; + (void) strncpy(svp.plname, defplname ? defplname : "Mumbles", + sizeof svp.plname - 1); + svp.plname[sizeof svp.plname - 1] = '\0'; iflags.renameinprogress = TRUE; } X11_player_selection_dialog(); @@ -1587,7 +1558,7 @@ X11_player_selection() /* called by core to have the player pick an extended command */ int -X11_get_ext_cmd() +X11_get_ext_cmd(void) { if (iflags.extmenu != ec_full_list) { /* player has toggled the 'extmenu' option, toss the old widgets */ @@ -1608,13 +1579,14 @@ X11_get_ext_cmd() /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); - if (extended_cmd_selected < 0) + if (extended_cmd_selected < 0) { return -1; + } return command_indx[extended_cmd_selected]; } void -release_extended_cmds() +release_extended_cmds(void) { if (extended_commands) { XtDestroyWidget(extended_command_popup), extended_command_popup = 0; @@ -1629,9 +1601,7 @@ release_extended_cmds() /* Extended Command ------------------------------------------------------- */ /* ARGSUSED */ static void -extend_select(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +extend_select(Widget w, XtPointer client_data, XtPointer call_data) { int selected = (int) (ptrdiff_t) client_data; @@ -1657,9 +1627,7 @@ XtPointer client_data, call_data; /* ARGSUSED */ static void -extend_dismiss(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +extend_dismiss(Widget w, XtPointer client_data, XtPointer call_data) { nhUse(w); nhUse(client_data); @@ -1670,9 +1638,7 @@ XtPointer client_data, call_data; /* ARGSUSED */ static void -extend_help(w, client_data, call_data) -Widget w; -XtPointer client_data, call_data; +extend_help(Widget w, XtPointer client_data, XtPointer call_data) { nhUse(w); nhUse(client_data); @@ -1684,11 +1650,7 @@ XtPointer client_data, call_data; /* ARGSUSED */ void -ec_delete(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +ec_delete(Widget w, XEvent *event, String *params, Cardinal *num_params) { if (w == extended_command_popup) { ec_dismiss(); @@ -1699,11 +1661,7 @@ Cardinal *num_params; /* ARGSUSED */ static void -popup_delete(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +popup_delete(Widget w, XEvent *event, String *params, Cardinal *num_params) { nhUse(event); nhUse(params); @@ -1715,7 +1673,7 @@ Cardinal *num_params; } static void -ec_dismiss() +ec_dismiss(void) { /* unselect while still visible */ if (extended_cmd_selected >= 0) @@ -1729,8 +1687,7 @@ ec_dismiss() /* scroll the extended command menu if necessary so that choices extended_cmd_selected through ec_indx will be visible */ static void -ec_scroll_to_view(ec_indx) -int ec_indx; /* might be greater than extended_cmd_selected */ +ec_scroll_to_view(int ec_indx) /* might be greater than extended_cmd_selected */ { Widget viewport, scrollbar, tmpw; Arg args[5]; @@ -1747,7 +1704,7 @@ int ec_indx; /* might be greater than extended_cmd_selected */ * If the extended command menu needs to be scrolled in order to move * either the highlighted entry (extended_cmd_selected) or the target * entry (ec_indx) into view, we want to make both end up visible. - * [Highligthed one is the first matching entry when the user types + * [Highlighted one is the first matching entry when the user types * something, such as "adjust" after typing 'a', and will be chosen * by pressing . Target entry is one past the last matching * entry (or last matching entry itself if at end of command list), @@ -1831,29 +1788,9 @@ int ec_indx; /* might be greater than extended_cmd_selected */ } } -/* decide whether extcmdlist[idx] should be part of extended commands menu */ -static boolean -ignore_extcmd(idx) -int idx; -{ - /* #shell or #suspect might not be available; - 'extmenu' option controls whether we show full list - or just the traditional extended commands */ - if ((extcmdlist[idx].flags & CMD_NOT_AVAILABLE) != 0 - || ((extcmdlist[idx].flags & AUTOCOMPLETE) == 0 && !ec_full_list) - || strlen(extcmdlist[idx].ef_txt) < 2) /* ignore "#" and "?" */ - return TRUE; - - return FALSE; -} - /* ARGSUSED */ void -ec_key(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +ec_key(Widget w, XEvent *event, String *params, Cardinal *num_params) { char ch; int i, pass; @@ -1873,7 +1810,7 @@ Cardinal *num_params; } else if (ch == '?') { extend_help((Widget) 0, (XtPointer) 0, (XtPointer) 0); return; - } else if (index("\033\n\r", ch)) { + } else if (strchr("\033\n\r", ch)) { if (ch == '\033') { /* unselect while still visible */ if (extended_cmd_selected >= 0) @@ -1890,16 +1827,14 @@ Cardinal *num_params; ec_active = FALSE; return; } else if (ch == MENU_FIRST_PAGE || ch == MENU_LAST_PAGE) { - hbar = vbar = (Widget) 0; - find_scrollbars(w, &hbar, &vbar); + find_scrollbars(w, (Widget) 0, &hbar, &vbar); if (vbar) { top = (ch == MENU_FIRST_PAGE) ? 0.0 : 1.0; XtCallCallbacks(vbar, XtNjumpProc, &top); } return; } else if (ch == MENU_NEXT_PAGE || ch == MENU_PREVIOUS_PAGE) { - hbar = vbar = (Widget) 0; - find_scrollbars(w, &hbar, &vbar); + find_scrollbars(w, (Widget) 0, &hbar, &vbar); if (vbar) { XtSetArg(arg[0], nhStr(XtNshown), &shown); XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top); @@ -1951,7 +1886,7 @@ Cardinal *num_params; swap_fg_bg(extended_commands[extended_cmd_selected]); } /* advance to one past last matching entry, so that all - ambiguous choices, plus one to show thare aren't any + ambiguous choices, plus one to show there aren't any more such, will scroll into view */ do { if (!command_list[i + 1]) @@ -1971,28 +1906,29 @@ Cardinal *num_params; * be used from a menubox. */ static void -init_extended_commands_popup() +init_extended_commands_popup(void) { - int i, j, num_commands, ignore_cmds = 0; + int i, num_commands; + int *matches; + int ecmflags = ECM_NO1CHARCMD; - /* count commands */ - for (num_commands = 0; extcmdlist[num_commands].ef_txt; num_commands++) - if (ignore_extcmd(num_commands)) - ++ignore_cmds; + if (ec_full_list) + ecmflags |= ECM_IGNOREAC; - j = num_commands - ignore_cmds; - command_list = (const char **) alloc((unsigned) (j * sizeof (char *) + 1)); - command_indx = (short *) alloc((unsigned) (j * sizeof (short) + 1)); + num_commands = extcmds_match(NULL, ecmflags, &matches); - for (i = j = 0; i < num_commands; i++) { - if (ignore_extcmd(i)) - continue; - command_indx[j] = (short) i; - command_list[j++] = extcmdlist[i].ef_txt; + i = num_commands + 1; /* room for each extcmd, plus terminator */ + command_list = (const char **) alloc((unsigned) (i * sizeof(char *))); + command_indx = (short *) alloc((unsigned) (i * sizeof(short))); + + for (i = 0; i < num_commands; i++) { + struct ext_func_tab *ec = extcmds_getentry(matches[i]); + + command_indx[i] = matches[i]; + command_list[i] = ec->ef_txt; } - command_list[j] = (char *) 0; - command_indx[j] = -1; - num_commands = j; + command_list[i] = (char *) 0; + command_indx[i] = -1; extended_command_popup = make_menu("extended_commands", "Extended Commands", @@ -2023,21 +1959,13 @@ init_extended_commands_popup() * ------------------------ */ static Widget -make_menu(popup_name, popup_label, popup_translations, left_name, - left_callback, right_name, right_callback, num_names, widget_names, - command_widgets, name_callback, formp) -const char *popup_name; -const char *popup_label; -const char *popup_translations; -const char *left_name; -XtCallbackProc left_callback; -const char *right_name; -XtCallbackProc right_callback; -int num_names; -const char **widget_names; /* return array of command widgets */ -Widget **command_widgets; -XtCallbackProc name_callback; -Widget *formp; /* return */ +make_menu(const char *popup_name, const char *popup_label, + const char *popup_translations, const char *left_name, + XtCallbackProc left_callback, const char *right_name, + XtCallbackProc right_callback, int num_names, + const char **widget_names, /* return array of command widgets */ + Widget **command_widgets, + XtCallbackProc name_callback, Widget *formp) /* return */ { Widget popup, popform, form, label, above, left, right, view; Widget *commands, *curr; @@ -2286,7 +2214,7 @@ Widget *formp; /* return */ XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, 1); /* during role selection, highlight "random" as pre-selected choice */ - if (right_callback == ps_random && index(ps_randchars, '\n')) + if (right_callback == ps_random && strchr(ps_randchars, '\n')) swap_fg_bg(right); return popup; diff --git a/win/X11/winstat.c b/win/X11/winstat.c index 0aecdf1b6..0e6f79f94 100644 --- a/win/X11/winstat.c +++ b/win/X11/winstat.c @@ -1,11 +1,11 @@ -/* NetHack 3.6 winstat.c $NHDT-Date: 1543447325 2018/11/28 23:22:05 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.20 $ */ -/* Copyright (c) Dean Luick, 1992 */ +/* NetHack 5.0 winstat.c $NHDT-Date: 1649269127 2022/04/06 18:18:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.37 $ */ +/* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Status window routines. This file supports both the "traditional" * tty status display and a "fancy" status display. A tty status is - * made if a popup window is requested, otherewise a fancy status is + * made if a popup window is requested, otherwise a fancy status is * made. This code assumes that only one fancy status will ever be made. * Currently, only one status window (of any type) is _ever_ made. */ @@ -15,16 +15,16 @@ #endif #include -#include +#include /* for XtResizeWidget() and XtConfigureWidget() */ #include #include #include -#include +#include /* just for ONE, TWO */ #include #include #include #include -#include +/*#include */ #ifdef PRESERVE_NO_SYSV #ifdef SYSV @@ -48,83 +48,159 @@ #define F_WIS 5 #define F_CHA 6 -#define F_NAME 7 -#define F_DLEVEL 8 +#define F_NAME 7 /* title: "Name the Rank" where rank is role-specific */ +#define F_DLEVEL 8 /* location: dungeon branch and level */ #define F_GOLD 9 #define F_HP 10 #define F_MAXHP 11 #define F_POWER 12 #define F_MAXPOWER 13 #define F_AC 14 -#define F_LEVEL 15 -#define F_EXP 16 +#define F_XP_LEVL 15 +/*#define F_HD F_XP_LEVL*/ +#define F_EXP_PTS 16 #define F_ALIGN 17 #define F_TIME 18 #define F_SCORE 19 -/* status conditions grouped by columns; tty orders these differently */ -#define F_STONE 20 -#define F_SLIME 21 -#define F_STRNGL 22 -#define F_FOODPOIS 23 -#define F_TERMILL 24 - -#define F_HUNGER 25 -#define F_ENCUMBER 26 -#define F_LEV 27 -#define F_FLY 28 -#define F_RIDE 29 - -#define F_BLIND 30 -#define F_DEAF 31 -#define F_STUN 32 -#define F_CONF 33 -#define F_HALLU 34 - -#define NUM_STATS 35 - -static void FDECL(update_fancy_status, (struct xwindow *)); -static void FDECL(update_fancy_status_field, (int)); -static Widget FDECL(create_fancy_status, (Widget, Widget)); -static void FDECL(destroy_fancy_status, (struct xwindow *)); -static void FDECL(create_status_window_fancy, (struct xwindow *, BOOLEAN_P, Widget)); -static void FDECL(create_status_window_tty, (struct xwindow *, BOOLEAN_P, Widget)); -static void FDECL(destroy_status_window_fancy, (struct xwindow *)); -static void FDECL(destroy_status_window_tty, (struct xwindow *)); -static void FDECL(adjust_status_fancy, (struct xwindow *, const char *)); -static void FDECL(adjust_status_tty, (struct xwindow *, const char *)); +/* status conditions grouped by columns; tty orders these differently; + hunger/encumbrance/movement used to be in the middle with fatal + conditions on the left but those columns have been swapped and + renumbered to match new order (forcing shown_stats[] to be reordered); + some mutually exclusive conditions are overloaded during display-- + they're separate within shown_stats[] but share the same widget */ +#define F_HUNGER 20 +#define F_ENCUMBER 21 +#define F_TRAPPED 22 +#define F_TETHERED 23 /* overloads trapped rather than having its own slot */ +#define F_LEV 24 +#define F_FLY 25 +#define F_RIDE 26 + +#define F_GRABBED 27 +#define F_STONE 28 +#define F_SLIME 29 +#define F_STRNGL 30 +#define F_FOODPOIS 31 +#define F_TERMILL 32 +#define F_IN_LAVA 33 /* could overload trapped but severity differs a lot */ + +#define F_HELD 34 /* could overload grabbed but severity differs a lot */ +#define F_HOLDING 35 /* overloads held */ +#define F_BLIND 36 +#define F_DEAF 37 +#define F_STUN 38 +#define F_CONF 39 +#define F_HALLU 40 + +#define F_VERS 41 /* version info */ +#define NUM_STATS 42 + +static int condcolor(long, unsigned long *); +static int condattr(long, unsigned long *); +static void HiliteField(Widget, int, int, int, XFontStruct **); +static void PrepStatusField(int, Widget, const char *); +static void DisplayCond(int, unsigned long *); +static int render_conditions(int, int); +#ifdef STATUS_HILITES +static void tt_reset_color(int, int, unsigned long *); +#endif +static void tt_status_fixup(void); +static Widget create_tty_status_field(int, int, Widget, Widget); +static Widget create_tty_status(Widget, Widget); +static void stat_resized(Widget, XtPointer, XtPointer); +static void update_fancy_status_field(int, int, int); +static void update_fancy_status(boolean); +static Widget create_fancy_status(Widget, Widget); +static void destroy_fancy_status(struct xwindow *); +static void create_status_window_fancy(struct xwindow *, boolean, Widget); +static void create_status_window_tty(struct xwindow *, boolean, Widget); +static void destroy_status_window_fancy(struct xwindow *); +static void destroy_status_window_tty(struct xwindow *); +static void adjust_status_fancy(struct xwindow *, const char *); +static void adjust_status_tty(struct xwindow *, const char *); extern const char *status_fieldfmt[MAXBLSTATS]; extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; -static long X11_condition_bits; -static int X11_status_colors[MAXBLSTATS]; + +static unsigned long X11_condition_bits, old_condition_bits; +static int X11_status_colors[MAXBLSTATS], + old_field_colors[MAXBLSTATS], + old_cond_colors[32]; static int hpbar_percent, hpbar_color; +/* Number of conditions displayed during this update and last update. + When the last update had more, the excess need to be erased. */ +static int next_cond_indx = 0, prev_cond_indx = 0; +/* TODO: support statuslines:3 in addition to 2 for the tty-style status */ #define X11_NUM_STATUS_LINES 2 -#define X11_NUM_STATUS_FIELD 15 +#define X11_NUM_STATUS_FIELD 16 -static enum statusfields X11_fieldorder[X11_NUM_STATUS_LINES][X11_NUM_STATUS_FIELD] = { +static enum statusfields X11_fieldorder[][X11_NUM_STATUS_FIELD] = { { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, - BL_FLUSH }, + BL_FLUSH, BL_FLUSH }, { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, - BL_CAP, BL_CONDITION, BL_FLUSH } + BL_CAP, BL_CONDITION, BL_VERS, BL_FLUSH } +}; + +/* condition list for tty-style display, roughly in order of importance */ +static struct tt_condinfo { + unsigned long mask; + const char *text; +} tt_condorder[] = { + { BL_MASK_GRAB, "Grabbed!" }, + { BL_MASK_STONE, "Stone" }, + { BL_MASK_SLIME, "Slime" }, + { BL_MASK_STRNGL, "Strngl" }, + { BL_MASK_FOODPOIS, "FoodPois" }, + { BL_MASK_TERMILL, "TermIll" }, + { BL_MASK_INLAVA, "InLava" }, + { BL_MASK_HELD, "Held" }, + { BL_MASK_HOLDING, "Holding" }, + { BL_MASK_BLIND, "Blind" }, + { BL_MASK_DEAF, "Deaf" }, + { BL_MASK_STUN, "Stun" }, + { BL_MASK_CONF, "Conf" }, + { BL_MASK_HALLU, "Hallu" }, + { BL_MASK_TRAPPED, "Trapped" }, + { BL_MASK_TETHERED, "Tethered", }, + { BL_MASK_LEV, "Lev" }, + { BL_MASK_FLY, "Fly" }, + { BL_MASK_RIDE, "Ride" }, +}; + +static const char *const fancy_status_hilite_colors[] = { + "grey15", + "red3", + "dark green", + "saddle brown", + "blue", + "magenta3", + "dark cyan", + "web gray", + "", /* NO_COLOR */ + "orange", + "green3", + "goldenrod", + "royal blue", + "magenta", + "cyan", + "white", }; static Widget X11_status_widget; static Widget X11_status_labels[MAXBLSTATS]; static Widget X11_cond_labels[32]; /* Ugh */ +static XFontStruct *X11_status_font; +static Pixel X11_status_fg, X11_status_bg; struct xwindow *xw_status_win; -static Pixel X11_status_widget_fg, X11_status_widget_bg; - -int -condcolor(bm, bmarray) -long bm; -unsigned long *bmarray; +static int +condcolor(long bm, unsigned long *bmarray) { int i; @@ -136,33 +212,34 @@ unsigned long *bmarray; return NO_COLOR; } -int -condattr(bm, bmarray) -long bm; -unsigned long *bmarray; +static int +condattr(long bm, unsigned long *bmarray) { int attr = 0; int i; if (bm && bmarray) { - for (i = HL_ATTCLR_DIM; i < BL_ATTCLR_MAX; ++i) { + for (i = HL_ATTCLR_BOLD; i < BL_ATTCLR_MAX; ++i) { if (bmarray[i] && (bm & bmarray[i])) { switch(i) { + case HL_ATTCLR_BOLD: + attr |= HL_BOLD; + break; case HL_ATTCLR_DIM: attr |= HL_DIM; break; - case HL_ATTCLR_BLINK: - attr |= HL_BLINK; + case HL_ATTCLR_ITALIC: + attr |= HL_ITALIC; break; case HL_ATTCLR_ULINE: attr |= HL_ULINE; break; + case HL_ATTCLR_BLINK: + attr |= HL_BLINK; + break; case HL_ATTCLR_INVERSE: attr |= HL_INVERSE; break; - case HL_ATTCLR_BOLD: - attr |= HL_BOLD; - break; } } } @@ -171,348 +248,604 @@ unsigned long *bmarray; } void -X11_status_init() +X11_status_init(void) { -#ifdef STATUS_HILITES int i; + /* no color and no attributes */ for (i = 0; i < MAXBLSTATS; ++i) - X11_status_colors[i] = NO_COLOR; /* no color */ - X11_condition_bits = 0L; + X11_status_colors[i] = old_field_colors[i] = NO_COLOR; + for (i = 0; i < SIZE(old_cond_colors); ++i) + old_cond_colors[i] = NO_COLOR; hpbar_percent = 0, hpbar_color = NO_COLOR; -#endif /* STATUS_HILITES */ + X11_condition_bits = old_condition_bits = 0L; /* let genl_status_init do most of the initialization */ genl_status_init(); } void -X11_status_finish() +X11_status_finish(void) { /* nothing */ + return; } void -X11_status_enablefield(fieldidx, nm, fmt, enable) -int fieldidx; -const char *nm; -const char *fmt; -boolean enable; +X11_status_enablefield(int fieldidx, const char *nm, + const char *fmt, boolean enable) { genl_status_enablefield(fieldidx, nm, fmt, enable); } - +#if 0 int -cond_bm2idx(bm) -unsigned long bm; +cond_bm2idx(unsigned long bm) { int i; + for (i = 0; i < 32; i++) if ((1 << i) == bm) return i; return -1; } +#endif -void -MaybeDisplayCond(bm, colormasks, text) -unsigned long bm; -unsigned long *colormasks; -const char *text; +/* highlight a tty-style status field (or condition) */ +static void +HiliteField(Widget label, + int fld, int cond, int colrattr, + XFontStruct **font_p) +{ +#ifdef STATUS_HILITES + static Pixel grayPxl, blackPxl, whitePxl; + Arg args[6]; + Cardinal num_args; + XFontStruct *font = X11_status_font; + Pixel px, fg = X11_status_fg, bg = X11_status_bg; + struct xwindow *xw = xw_status_win; + int colr, attr; + + if ((colrattr & 0x00ff) >= CLR_MAX) + colrattr = (colrattr & ~0x00ff) | NO_COLOR; + colr = colrattr & 0x00ff; /* guaranteed to be >= 0 and < CLR_MAX */ + attr = (colrattr >> 8) & 0x00ff; + + if (!grayPxl) {/* one-time init */ + grayPxl = get_nhcolor(xw, CLR_GRAY).pixel; + blackPxl = get_nhcolor(xw, CLR_BLACK).pixel; + whitePxl = get_nhcolor(xw, CLR_WHITE).pixel; + } + /* [shouldn't be necessary; setting up gray will set up all colors] */ + if (colr != NO_COLOR && !xw->nh_colors[colr].pixel) + (void) get_nhcolor(xw, colr); + + /* handle highlighting if caller has specified that; set foreground, + background, and font even if not specified this time in case they + used modified values last time (which would stick if not reset) */ + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + if (colr != NO_COLOR) + fg = xw->nh_colors[colr].pixel; + if ((attr & HL_INVERSE) != 0) { + px = fg; + fg = bg; + bg = px; + } + /* foreground and background might both default to black, so we + need to force one to be different if/when they're the same + (actually, tt_status_fixup() takes care of that nowadays); + using gray to implement 'dim' only works for black and white + (or color+'inverse' when former background was black or white) */ + if (fg == bg + || ((attr & HL_DIM) != 0 && (fg == whitePxl || fg == blackPxl))) + fg = (fg != grayPxl) ? grayPxl + : (fg != blackPxl) ? blackPxl + : whitePxl; + XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; + XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; + if (attr & HL_BOLD) { + load_boldfont(xw_status_win, label); + if (xw_status_win->boldfs) + font = xw_status_win->boldfs; + } + XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++; + XtSetValues(label, args, num_args); + + /* return possibly modified font to caller so that text width + measurement can use it */ + if (font_p) + *font_p = font; +#else /*!STATUS_HILITES*/ + nhUse(label); + nhUse(font_p); +#endif /*?STATUS_HILITES*/ + if (fld != BL_CONDITION) + old_field_colors[fld] = colrattr; + else + old_cond_colors[cond] = colrattr; +} + +/* set up a specific field other than 'condition'; its general location + was specified during widget creation but it might need adjusting */ +static void +PrepStatusField(int fld, Widget label, const char *text) +{ + Arg args[6]; + Cardinal num_args; + Dimension lbl_wid; + XFontStruct *font = X11_status_font; + int colrattr = X11_status_colors[fld]; + struct status_info_t *si = xw_status_win->Win_info.Status_info; + + /* highlight if color and/or attribute(s) are different from last time */ + if (colrattr != old_field_colors[fld]) + HiliteField(label, fld, 0, colrattr, &font); + + num_args = 0; + (void) memset((genericptr_t) args, 0, sizeof args); + /* set up the current text to be displayed */ + if (text && *text) { + lbl_wid = 2 * si->in_wd + XTextWidth(font, text, (int) strlen(text)); + } else { + text = ""; + lbl_wid = 1; + } + XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++; + /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/ + XtSetValues(label, args, num_args); + XtResizeWidget(label, lbl_wid, si->ht, si->brd); +} + +/* set up one status condition for tty-style status display */ +static void +DisplayCond( + int c_idx, /* index into tt_condorder[] */ + unsigned long *colormasks) { - int idx = cond_bm2idx(bm); Widget label; - Arg args[10]; + Arg args[6]; Cardinal num_args; - Pixel fg = X11_status_widget_fg, bg = X11_status_widget_bg; Dimension lbl_wid; - Dimension lbl_hei; - Dimension lbl_border_wid; - Dimension lbl_iwidth; + XFontStruct *font = X11_status_font; + int coloridx, attrmask, colrattr, idx; + unsigned long bm = tt_condorder[c_idx].mask; + const char *text = tt_condorder[c_idx].text; + struct status_info_t *si = xw_status_win->Win_info.Status_info; - if (idx < 0) + if ((X11_condition_bits & bm) == 0) return; + /* widgets have been created for every condition; we allocate them + from left to right rather than keeping their original assignments */ + idx = next_cond_indx; label = X11_cond_labels[idx]; - if ((X11_condition_bits & bm) != 0) { - int attrmask, coloridx; - XFontStruct *font; - Position lbl_x; - Position lbl_y; - -#ifdef TEXTCOLOR - coloridx = condcolor(bm, colormasks); -#else - coloridx = NO_COLOR; -#endif - attrmask = condattr(bm, colormasks); - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNfont), &font); num_args++; - XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++; - XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; - XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++; - XtSetArg(args[num_args], nhStr(XtNinternalWidth), &lbl_iwidth); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), &lbl_border_wid); num_args++; - XtGetValues(label, args, num_args); - if (text && *text) - lbl_wid = lbl_iwidth + font->max_bounds.width * strlen(text); - else - lbl_wid = 1; + /* handle highlighting if caller requests it */ + coloridx = condcolor(bm, colormasks); + attrmask = condattr(bm, colormasks); + colrattr = (attrmask << 8) | coloridx; + if (colrattr != old_cond_colors[c_idx]) + HiliteField(label, BL_CONDITION, c_idx, colrattr, &font); - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNlabel), (text && *text) ? text : ""); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++; - - fg = (coloridx != NO_COLOR) ? get_nhcolor(xw_status_win, coloridx).pixel - : X11_status_widget_fg; - if (attrmask & HL_INVERSE) { - Pixel tmppx = fg; - fg = bg; - bg = tmppx; - } + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + /* set the condition text and its width; this widget might have + been displaying a different condition last time around */ + XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++; + /* measure width after maybe changing font [HiliteField()] */ + lbl_wid = 2 * si->in_wd + XTextWidth(font, text, (int) strlen(text)); + /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/ + + /* make this condition widget be ready for display */ + XtSetValues(label, args, num_args); + XtResizeWidget(label, lbl_wid, si->ht, si->brd); + + ++next_cond_indx; +} - if (attrmask & HL_BOLD) { - load_boldfont(xw_status_win, label); - XtSetArg(args[num_args], nhStr(XtNfont), - xw_status_win->boldfs); num_args++; - } +/* display the tty-style status conditions; the number shown varies and + we might be showing more, same, or fewer than during previous status */ +static int +render_conditions(int row, int dx) +{ + Widget label; + Arg args[6]; + Cardinal num_args; + Position lbl_x; + int i, gap = 5; + struct status_info_t *si = xw_status_win->Win_info.Status_info; + Dimension lbl_wid, brd_wid = si->brd; - if (fg == bg) - fg = get_nhcolor(xw_status_win, CLR_GRAY).pixel; + for (i = 0; i < next_cond_indx; i++) { + label = X11_cond_labels[i]; - XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; - XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; - XtSetValues(label, args, num_args); - XtResizeWidget(label, lbl_wid, lbl_hei, lbl_border_wid); - } else { + /* width of this widget was set in DisplayCond(); fetch it */ + (void) memset((genericptr_t) args, 0, sizeof args); num_args = 0; XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; - XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++; - XtSetArg(args[num_args], nhStr(XtNinternalWidth), &lbl_iwidth); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), &lbl_border_wid); num_args++; XtGetValues(label, args, num_args); - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), 1); num_args++; - XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; - XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; - XtSetValues(label, args, num_args); + /* figure out where to draw this widget and place it there */ + lbl_x = (Position) (dx + 1 + gap); + + XtConfigureWidget(label, lbl_x, si->y[row], lbl_wid, si->ht, brd_wid); - XtResizeWidget(label, lbl_wid, lbl_hei, lbl_border_wid); + /* keep track of where the end of our text appears */ + dx = (int) lbl_x + (int) (lbl_wid + 2 * brd_wid) - 1; + } + + /* if we have fewer conditions shown now than last time, set the + excess ones to blank; unlike the set drawn above, these haven't + been prepared in advance by DisplayCond because they aren't + being displayed; they might have been highlighted last time so + we need to specify more than just an empty text string */ + if (next_cond_indx < prev_cond_indx) { + XFontStruct *font = X11_status_font; + Pixel fg = X11_status_fg, bg = X11_status_bg; + + lbl_x = dx + 1; + lbl_wid = 1 + 2 * brd_wid; + for (i = next_cond_indx; i < prev_cond_indx; ++i) { + label = X11_cond_labels[i]; + + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++; + XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++; + XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; + XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; + /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/ + /*XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++;*/ + XtSetValues(label, args, num_args); + old_cond_colors[i] = NO_COLOR; /* fg, bg, font were just reset */ + XtConfigureWidget(label, lbl_x, si->y[row], lbl_wid, si->ht, 0); + /* don't advance 'dx' here */ + } } + + return dx; } +#ifdef STATUS_HILITES +/* reset status_hilite for BL_RESET; if highlighting has been disabled or + this field is disabled, clear highlighting for this field or condition */ +static void +tt_reset_color( + int fld, + int cond, + unsigned long *colormasks) +{ + Widget label; + int colrattr = NO_COLOR; -void -X11_status_update_tty(fld, ptr, chg, percent, color, colormasks) -int fld, chg UNUSED, percent, color; -genericptr_t ptr; -unsigned long *colormasks; + if (fld != BL_CONDITION) { + if (iflags.hilite_delta != 0L && status_activefields[fld]) + colrattr = X11_status_colors[fld]; + cond = 0; + label = X11_status_labels[fld]; + } else { + unsigned long bm = tt_condorder[cond].mask; + + if (iflags.hilite_delta != 0L && (X11_condition_bits & bm) != 0) { + /* BL_RESET before first BL_CONDITION will have colormasks==Null + but condcolor() and condattr() can cope with that */ + colrattr = condcolor(bm, colormasks); + colrattr |= (condattr(bm, colormasks) << 8); + } + label = X11_cond_labels[cond]; + } + HiliteField(label, fld, cond, colrattr, (XFontStruct **) 0); +} +#endif + +/* make sure foreground, background, and font have reasonable values, + then explicitly set them for all the status widgets; + also cache some geometry settings in (*xw_status_win).Status_info */ +static void +tt_status_fixup(void) { - static boolean oncearound = FALSE; /* prevent premature partial display */ - long *condptr = (long *) ptr; - int coloridx = NO_COLOR; - const char *text = (char *) ptr; - char tmpbuf[BUFSZ]; - int attridx = 0; - - XFontStruct *font; - Arg args[10]; + Arg args[6]; Cardinal num_args; - Position lbl_x; + Widget w; Position lbl_y; - Dimension lbl_wid; - Dimension lbl_hei; - Dimension lbl_border_wid; - Dimension lbl_iwidth; - Widget label; - Pixel fg = X11_status_widget_fg, bg = X11_status_widget_bg; + int x, y, ci, fld; + XFontStruct *font = 0; + Pixel fg = 0, bg = 0; + struct status_info_t *si = xw_status_win->Win_info.Status_info; -#ifndef TEXTCOLOR - color = NO_COLOR; -#endif + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfont), &font); num_args++; + XtSetArg(args[num_args], nhStr(XtNforeground), &fg); num_args++; + XtSetArg(args[num_args], nhStr(XtNbackground), &bg); num_args++; + XtGetValues(X11_status_widget, args, num_args); + if (fg == bg) { + XColor black = get_nhcolor(xw_status_win, CLR_BLACK), + white = get_nhcolor(xw_status_win, CLR_WHITE); - if (fld < BL_RESET || fld >= MAXBLSTATS) - return; + fg = (bg == white.pixel) ? black.pixel : white.pixel; + } + X11_status_fg = si->fg = fg, X11_status_bg = si->bg = bg; + + if (!font) { + w = X11_status_widget; + XtSetArg(args[0], nhStr(XtNfont), &font); + do { + XtGetValues(w, args, ONE); + } while (!font && (w = XtParent(w)) != 0); + + if (!font) { + /* trial and error time -- this is where we've actually + been obtaining the font even though we aren't setting + it for any of the field widgets (until for(y,x) below) */ + XtGetValues(X11_status_labels[0], args, ONE); + + if (!font) { /* this bit is untested... */ + /* write some text and hope Xaw sets up font for us */ + XtSetArg(args[0], nhStr(XtNlabel), "NetHack"); + XtSetValues(X11_status_labels[0], args, ONE); + (void) XFlush(XtDisplay(X11_status_labels[0])); + + XtSetArg(args[0], nhStr(XtNfont), &font); + XtGetValues(X11_status_labels[0], args, ONE); + + /* if still Null, XTextWidth() would crash so bail out */ + if (!font) + panic("X11 status can't determine font."); + } + } + } + X11_status_font = si->fs = font; - if ((fld >= 0 && fld < MAXBLSTATS) && !status_activefields[fld]) - return; + /* amount of space to advance a widget's location by one space; + increase width a tiny bit beyond the actual space */ + si->spacew = XTextWidth(X11_status_font, " ", 1) + (Dimension) 1; - if (fld != BL_FLUSH && fld != BL_RESET) { - if (!status_activefields[fld]) - return; - switch (fld) { - case BL_CONDITION: - X11_condition_bits = *condptr; - oncearound = TRUE; - break; - default: - Sprintf(status_vals[fld], - (fld == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30s" : - status_fieldfmt[fld] ? status_fieldfmt[fld] : "%s", - text); - X11_status_colors[fld] = color; - if (iflags.wc2_hitpointbar && fld == BL_HP) { - hpbar_percent = percent; - hpbar_color = color; - } - break; + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfont), font); num_args++; + XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; + XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; + XtSetValues(X11_status_widget, args, num_args); + + for (y = 0; y < X11_NUM_STATUS_LINES; y++) { + for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { + fld = X11_fieldorder[y][x]; /* next field to handle */ + if (fld <= BL_FLUSH) + continue; /* skip fieldorder[][] padding */ + + XtSetValues(X11_status_labels[fld], args, num_args); + old_field_colors[fld] = NO_COLOR; + + if (fld == BL_CONDITION) { + for (ci = 0; ci < SIZE(X11_cond_labels); ++ci) { /* 0..31 */ + XtSetValues(X11_cond_labels[ci], args, num_args); + old_cond_colors[ci] = NO_COLOR; + } + } } - if (fld == BL_CONDITION) { - MaybeDisplayCond(BL_MASK_STONE, colormasks, "Stone"); - MaybeDisplayCond(BL_MASK_SLIME, colormasks, "Slime"); - MaybeDisplayCond(BL_MASK_STRNGL, colormasks, "Strngl"); - MaybeDisplayCond(BL_MASK_FOODPOIS, colormasks, "FoodPois"); - MaybeDisplayCond(BL_MASK_TERMILL, colormasks, "TermIll"); - MaybeDisplayCond(BL_MASK_BLIND, colormasks, "Blind"); - MaybeDisplayCond(BL_MASK_DEAF, colormasks, "Deaf"); - MaybeDisplayCond(BL_MASK_STUN, colormasks, "Stun"); - MaybeDisplayCond(BL_MASK_CONF, colormasks, "Conf"); - MaybeDisplayCond(BL_MASK_HALLU, colormasks, "Hallu"); - MaybeDisplayCond(BL_MASK_LEV, colormasks, "Lev"); - MaybeDisplayCond(BL_MASK_FLY, colormasks, "Fly"); - MaybeDisplayCond(BL_MASK_RIDE, colormasks, "Ride"); - } else { - label = X11_status_labels[fld]; - text = status_vals[fld]; - if (fld == BL_GOLD) - text = decode_mixed(tmpbuf, text); -#ifdef TEXTCOLOR - coloridx = X11_status_colors[fld] & 0x00FF; -#endif - attridx = (X11_status_colors[fld] & 0xFF00) >> 8; + } - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNfont), &font); num_args++; - XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++; - XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; - XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++; - XtSetArg(args[num_args], nhStr(XtNinternalWidth), &lbl_iwidth); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), &lbl_border_wid); num_args++; - XtGetValues(label, args, num_args); + /* cache the y coordinate of each row for XtConfigureWidget() */ + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[0], nhStr(XtNy), &lbl_y); num_args++; + for (y = 0; y < X11_NUM_STATUS_LINES; y++) { + fld = X11_fieldorder[y][0]; + XtGetValues(X11_status_labels[fld], args, num_args); + si->y[y] = lbl_y; + } - /*raw_printf("font: %i-%i", - font->min_bounds.width, font->max_bounds.width);*/ + /* cache height, borderWidth, and internalWidth for XtResizeWidget() */ + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNheight), &si->ht); num_args++; + XtSetArg(args[num_args], nhStr(XtNborderWidth), &si->brd); num_args++; + XtSetArg(args[num_args], nhStr(XtNinternalWidth), &si->in_wd); num_args++; + XtGetValues(X11_status_labels[0], args, num_args); + + /* X11_status_update_tty() wants this in order to right justify 'vers' */ + if (!xw_status_win->pixel_width) { + XtSetArg(args[0], nhStr(XtNwidth), &xw_status_win->pixel_width); + XtGetValues(xw_status_win->w, args, ONE); + } +} - if (text && *text) - lbl_wid = lbl_iwidth + font->max_bounds.width * strlen(text); - else - lbl_wid = 1; +DISABLE_WARNING_FORMAT_NONLITERAL - /*raw_printf("1:lbl_wid=%i('%s')", lbl_wid, text);*/ +/* core requests updating one status field (or is indicating that it's time + to flush all updated fields); tty-style handling */ +static void +X11_status_update_tty( + int fld, + genericptr_t ptr, + int chg UNUSED, + int percent, + int color, + unsigned long *colormasks) /* bitmask of highlights for conditions */ +{ + static int xtra_space[MAXBLSTATS]; + static unsigned long *cond_colormasks = (unsigned long *) 0; - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNlabel), - (text && *text) ? text : ""); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++; + Arg args[6]; + Cardinal num_args; + Position lbl_x; + Dimension lbl_wid, brd_wid; + Widget label; - fg = (coloridx != NO_COLOR) ? get_nhcolor(xw_status_win, coloridx).pixel - : X11_status_widget_fg; - if (attridx & HL_INVERSE) { - Pixel tmppx = fg; + struct status_info_t *si; + char goldbuf[40]; + const char *fmt; + const char *text; + unsigned long *condptr; + int f, x, y, dx; - fg = bg; - bg = tmppx; - } + if (X11_status_fg == X11_status_bg || !X11_status_font) + tt_status_fixup(); - if (attridx & HL_BOLD) { - load_boldfont(xw_status_win, label); - XtSetArg(args[num_args], nhStr(XtNfont), - xw_status_win->boldfs); num_args++; + if (fld == BL_RESET) { +#ifdef STATUS_HILITES + for (y = 0; y < X11_NUM_STATUS_LINES; y++) { + for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { + f = X11_fieldorder[y][x]; + if (f <= BL_FLUSH) + continue; /* skip padding in the fieldorder[][] layout */ + if (f != BL_CONDITION) { + tt_reset_color(f, 0, (unsigned long *) 0); + } else { + int c_i; + + for (c_i = 0; c_i < SIZE(tt_condorder); ++c_i) + tt_reset_color(f, c_i, cond_colormasks); + } } + } +#endif + fld = BL_FLUSH; + } - if (fg == bg) - fg = get_nhcolor(xw_status_win, CLR_GRAY).pixel; + if (fld == BL_CONDITION) { + condptr = (unsigned long *) ptr; + X11_condition_bits = *condptr; + cond_colormasks = colormasks; /* expected to be non-Null */ + + prev_cond_indx = next_cond_indx; + next_cond_indx = 0; + /* if any conditions are active, set up their widgets */ + if (X11_condition_bits) + for (f = 0; f < SIZE(tt_condorder); ++f) + DisplayCond(f, cond_colormasks); + return; - XtSetArg(args[num_args], nhStr(XtNforeground), fg); num_args++; - XtSetArg(args[num_args], nhStr(XtNbackground), bg); num_args++; - XtSetValues(label, args, num_args); - XtResizeWidget(label, lbl_wid, lbl_hei, lbl_border_wid); + } else if (fld != BL_FLUSH) { + /* set up a specific field other than 'condition' */ + text = (char *) ptr; + if (fld == BL_GOLD) + text = decode_mixed(goldbuf, text); + xtra_space[fld] = 0; + if (status_activefields[fld]) { + fmt = (fld == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30s" + : status_fieldfmt[fld] ? status_fieldfmt[fld] : "%s"; + if (*fmt == ' ') { + ++xtra_space[fld]; + ++fmt; + } + Sprintf(status_vals[fld], fmt, text); + } else { + /* don't expect this since core won't call status_update() + for a field which isn't active */ + *status_vals[fld] = '\0'; + } +#ifdef STATUS_HILITES + if (!iflags.hilite_delta) + color = NO_COLOR; +#endif + X11_status_colors[fld] = color; + if (iflags.wc2_hitpointbar && fld == BL_HP) { + hpbar_percent = percent; + hpbar_color = color; } - } else { - int x, y; - - for (y = 0; y < X11_NUM_STATUS_LINES; y++) { - Cardinal dx = 0; - for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { - int f = X11_fieldorder[y][x]; + label = X11_status_labels[fld]; + text = status_vals[fld]; + PrepStatusField(fld, label, text); + return; + } - if (f <= BL_FLUSH) - continue; - if (!status_activefields[f]) - continue; + /* + * BL_FLUSH: draw all the status fields. + */ + si = xw_status_win->Win_info.Status_info; /* for cached geometry */ - if (f == BL_CONDITION) { - int i; + for (y = 0; y < X11_NUM_STATUS_LINES; y++) { /* row */ + dx = 0; /* no pixels written to this row yet */ - for (i = 0; i < 32; i++) { - label = X11_cond_labels[i]; + for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { /* 'column' */ + f = X11_fieldorder[y][x]; + if (f <= BL_FLUSH) + continue; /* skip padding in the fieldorder[][] layout */ - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++; - XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; - XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), - &lbl_border_wid); num_args++; - XtGetValues(label, args, num_args); + if (f == BL_CONDITION) { + if (next_cond_indx > 0 || prev_cond_indx > 0) + dx = render_conditions(y, dx); + continue; + } - lbl_x = dx; + label = X11_status_labels[f]; + text = status_vals[f]; - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++; - XtSetValues(label, args, num_args); - XtConfigureWidget(label, lbl_x, lbl_y, - lbl_wid, lbl_hei, lbl_border_wid); + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; + XtGetValues(label, args, num_args); + brd_wid = si->brd; - if (lbl_wid > 1) - dx += lbl_wid; - } + /* for a field which shouldn't be shown, we can't just skip + it because we might need to remove its previous content + if it has just been toggled off */ + if (!status_activefields[f]) { + if (lbl_wid <= 1) continue; - } - label = X11_status_labels[f]; - - text = status_vals[f]; - if (f == BL_GOLD) - text = decode_mixed(tmpbuf, text); - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNx), &lbl_x); num_args++; - XtSetArg(args[num_args], nhStr(XtNy), &lbl_y); num_args++; - XtSetArg(args[num_args], nhStr(XtNwidth), &lbl_wid); num_args++; - XtSetArg(args[num_args], nhStr(XtNheight), &lbl_hei); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), - &lbl_border_wid); num_args++; - XtGetValues(label, args, num_args); - - lbl_x = dx; - /*raw_printf("2:lbl_wid=%i('%s')", lbl_wid, text);*/ - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++; - XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++; - XtSetValues(label, args, num_args); - XtConfigureWidget(label, lbl_x, lbl_y, - lbl_wid, lbl_hei, lbl_border_wid); - - dx += lbl_wid; + text = ""; + lbl_wid = (Dimension) 1; + brd_wid = (Dimension) 0; + } else if (xtra_space[f]) { + /* if this field was to be formatted with a leading space + to separate it from the preceding field, we suppressed + that space during formatting; insert separation between + fields here; this prevents inverse video highlighting + from inverting the separating space along with the text */ + dx += xtra_space[f] * si->spacew; } - } - } + + /* where to display the current widget */ + lbl_x = (Position) (dx + 1); + if (f == BL_VERS) { + Dimension win_wid = xw_status_win->pixel_width, + fld_wid = lbl_wid + 2 * brd_wid; + + /* in case the doodad for resizing the window via click and + drag is in the lower right corner; justifying all the way + to the edge results in the last character being obscured; + avoid that by treating the 'vers' widget as one char + bigger than it actually is (an implicit trailing space) */ + fld_wid += si->spacew; + /* right justify if there's room */ + if (dx < win_wid - fld_wid) + lbl_x = win_wid - fld_wid; + } + + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNlabel), text); num_args++; + /*XtSetArg(args[num_args], nhStr(XtNwidth), lbl_wid); num_args++;*/ + /*XtSetArg(args[num_args], nhStr(XtNx), lbl_x); num_args++;*/ + XtSetValues(label, args, num_args); + XtConfigureWidget(label, lbl_x, si->y[y], + lbl_wid, si->ht, brd_wid); + + /* track the right-most pixel written so far */ + dx = (int) lbl_x + (int) (lbl_wid + 2 * brd_wid) - 1; + } /* [x] fields/columns in current row */ + } /* [y] rows */ + + /* this probably doesn't buy us anything but it isn't a sure thing + that nethack will immediately ask for input (triggering auto-flush) */ + (void) XFlush(XtDisplay(X11_status_labels[0])); } +RESTORE_WARNING_FORMAT_NONLITERAL + /*ARGSUSED*/ -void -X11_status_update_fancy(fld, ptr, chg, percent, color, colormasks) -int fld, chg UNUSED, percent UNUSED, color UNUSED; -genericptr_t ptr; -unsigned long *colormasks UNUSED; +static void +X11_status_update_fancy( + int fld, + genericptr_t ptr, + int chg UNUSED, int percent UNUSED, + int colrattr, + unsigned long *colormasks UNUSED) { - static const struct { + static const struct bl_to_ff { int bl, ff; } bl_to_fancyfield[] = { { BL_TITLE, F_NAME }, @@ -528,30 +861,36 @@ unsigned long *colormasks UNUSED; { BL_GOLD, F_GOLD }, { BL_ENE, F_POWER }, { BL_ENEMAX, F_MAXPOWER }, - { BL_XP, F_LEVEL }, + { BL_XP, F_XP_LEVL }, /* shares with BL_HD, depending upon Upolyd */ { BL_AC, F_AC }, - /*{ BL_HD, F_ },*/ { BL_TIME, F_TIME }, { BL_HUNGER, F_HUNGER }, { BL_HP, F_HP }, { BL_HPMAX, F_MAXHP }, { BL_LEVELDESC, F_DLEVEL }, - { BL_EXP, F_EXP } + { BL_VERS, F_VERS }, + { BL_EXP, F_EXP_PTS } }; - static const struct { + static const struct mask_to_ff { unsigned long mask; int ff; } mask_to_fancyfield[] = { + { BL_MASK_GRAB, F_GRABBED }, { BL_MASK_STONE, F_STONE }, { BL_MASK_SLIME, F_SLIME }, { BL_MASK_STRNGL, F_STRNGL }, { BL_MASK_FOODPOIS, F_FOODPOIS }, { BL_MASK_TERMILL, F_TERMILL }, + { BL_MASK_INLAVA, F_IN_LAVA }, + { BL_MASK_HELD, F_HELD }, + { BL_MASK_HOLDING, F_HOLDING }, { BL_MASK_BLIND, F_BLIND }, { BL_MASK_DEAF, F_DEAF }, { BL_MASK_STUN, F_STUN }, { BL_MASK_CONF, F_CONF }, { BL_MASK_HALLU, F_HALLU }, + { BL_MASK_TRAPPED, F_TRAPPED }, + { BL_MASK_TETHERED, F_TETHERED }, { BL_MASK_LEV, F_LEV }, { BL_MASK_FLY, F_FLY }, { BL_MASK_RIDE, F_RIDE } @@ -560,164 +899,168 @@ unsigned long *colormasks UNUSED; if (fld == BL_RESET || fld == BL_FLUSH) { if (WIN_STATUS != WIN_ERR) { - struct xwindow *wp = &window_list[WIN_STATUS]; - - update_fancy_status(wp); + update_fancy_status(FALSE); } return; } if (fld == BL_CONDITION) { - unsigned long mask = (unsigned long) ptr; - - for (i = 0; i < SIZE(mask_to_fancyfield); i++) - if (mask_to_fancyfield[i].mask == mask) - update_fancy_status_field(mask_to_fancyfield[i].ff); + unsigned long changed_bits, *condptr = (unsigned long *) ptr; + + X11_condition_bits = *condptr; + /* process the bits that are different from last time */ + changed_bits = (X11_condition_bits ^ old_condition_bits); + if (changed_bits) { + for (i = 0; i < SIZE(mask_to_fancyfield); i++) + if ((changed_bits & mask_to_fancyfield[i].mask) != 0L) + update_fancy_status_field(mask_to_fancyfield[i].ff, + condcolor(mask_to_fancyfield[i].mask, colormasks), + condattr(mask_to_fancyfield[i].mask, colormasks)); + old_condition_bits = X11_condition_bits; /* remember 'On' bits */ + } } else { + int colr, attr; + + if ((colrattr & 0x00ff) >= CLR_MAX) + colrattr = (colrattr & ~0x00ff) | NO_COLOR; + colr = colrattr & 0x00ff; /* guaranteed to be >= 0 and < CLR_MAX */ + attr = (colrattr >> 8) & 0x00ff; + for (i = 0; i < SIZE(bl_to_fancyfield); i++) - if (bl_to_fancyfield[i].bl == fld) - update_fancy_status_field(bl_to_fancyfield[i].ff); + if (bl_to_fancyfield[i].bl == fld) { + update_fancy_status_field(bl_to_fancyfield[i].ff, colr, attr); + break; + } } } void -X11_status_update(fld, ptr, chg, percent, color, colormasks) -int fld, chg UNUSED, percent UNUSED, color; -genericptr_t ptr; -unsigned long *colormasks; +X11_status_update( + int fld, + genericptr_t ptr, + int chg, int percent, + int color, + unsigned long *colormasks) { + if (fld < BL_RESET || fld >= MAXBLSTATS) + panic("X11_status_update(%d) -- invalid field", fld); + if (appResources.fancy_status) X11_status_update_fancy(fld, ptr, chg, percent, color, colormasks); else X11_status_update_tty(fld, ptr, chg, percent, color, colormasks); } -Widget -create_tty_status(parent, top) -Widget parent, top; +/* create a widget for a particular status field or potential condition */ +static Widget +create_tty_status_field(int fld, int condindx, Widget above, Widget left) { - Widget form; /* The form that surrounds everything. */ - Widget w; Arg args[16]; Cardinal num_args; - int i, x, y; + char labelname[40]; + int gap = condindx ? 5 : 0; + + if (!condindx) + Sprintf(labelname, "label_%s", bl_idx_to_fldname(fld)); + else + Sprintf(labelname, "cond_%02d", condindx); + /* set up widget attributes which (mostly) aren't going to be changing */ + (void) memset((genericptr_t) args, 0, sizeof args); num_args = 0; - if (top != (Widget) 0) { - XtSetArg(args[num_args], nhStr(XtNfromVert), top); - num_args++; + if (above) { + XtSetArg(args[num_args], nhStr(XtNfromVert), above); num_args++; + } + if (left) { + XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++; } - XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); - num_args++; - XtSetArg(args[num_args], XtNborderWidth, 0); - num_args++; + + XtSetArg(args[num_args], nhStr(XtNhorizDistance), gap); num_args++; + XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++; + + XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNbottomMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNleftMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; + /* internalWidth: default is 4; cut that it half and adjust regular + width to have it on both left and right instead of just on the left */ + XtSetArg(args[num_args], nhStr(XtNinternalWidth), 2); num_args++; + XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++; + return XtCreateManagedWidget(labelname, labelWidgetClass, + X11_status_widget, args, num_args); +} + +/* create an overall status widget (X11_status_widget) and also + separate widgets for all status fields and potential conditions */ +static Widget +create_tty_status(Widget parent, Widget top) +{ + Widget form; /* viewport that holds the form that surrounds everything */ + Widget w, over_w, prev_w; + Arg args[6]; + Cardinal num_args; + int x, y, i, fld; + + (void) memset((genericptr_t) args, 0, sizeof args); + num_args = 0; + if (top) { + XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++; + } + XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++; + XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNwidth, 400); num_args++; XtSetArg(args[num_args], XtNheight, 100); num_args++; form = XtCreateManagedWidget("status_viewport", viewportWidgetClass, parent, args, num_args); + (void) memset((genericptr_t) args, 0, sizeof args); num_args = 0; XtSetArg(args[num_args], XtNwidth, 400); num_args++; XtSetArg(args[num_args], XtNheight, 100); num_args++; - w = XtCreateManagedWidget("status_form", formWidgetClass, - form, args, num_args); + X11_status_widget = XtCreateManagedWidget("status_form", formWidgetClass, + form, args, num_args); + for (y = 0; y < X11_NUM_STATUS_LINES; y++) { + fld = (y > 0) ? X11_fieldorder[y - 1][0] : 0; /* temp, for over_w */ + /* for row(s) beyond the first, pick a widget in the previous + row to put this one underneath (in 'y' terms; 'x' is fluid) */ + over_w = (y > 0) ? X11_status_labels[fld] : (Widget) 0; + /* widget on current row to put the next one to the right of ('x') */ + prev_w = (Widget) 0; for (x = 0; x < X11_NUM_STATUS_FIELD; x++) { - int fld = X11_fieldorder[y][x]; - char labelname[BUFSZ]; - int prevfld; - + fld = X11_fieldorder[y][x]; /* next field to handle */ if (fld <= BL_FLUSH) - continue; - Sprintf(labelname, "label_%s", bl_idx_to_fldname(fld)); - num_args = 0; - if (y > 0) { - prevfld = X11_fieldorder[y-1][0]; - XtSetArg(args[num_args], nhStr(XtNfromVert), - X11_status_labels[prevfld]); num_args++; - } - if (x > 0) { - prevfld = X11_fieldorder[y][x-1]; - XtSetArg(args[num_args], nhStr(XtNfromHoriz), - X11_status_labels[prevfld]); num_args++; - } + continue; /* skip fieldorder[][] padding */ - XtSetArg(args[num_args], nhStr(XtNhorizDistance), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++; + w = create_tty_status_field(fld, 0, over_w, prev_w); + X11_status_labels[fld] = prev_w = w; - XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNbottomMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNleftMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++; - /* - XtSetArg(args[num_args], nhStr(XtNlabel), - bl_idx_to_fldname(fld)); num_args++; - */ - XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++; - X11_status_labels[fld] = XtCreateManagedWidget(labelname, - labelWidgetClass, w, - args, num_args); + if (fld == BL_CONDITION) { + for (i = 1; i <= SIZE(X11_cond_labels); ++i) { /* 1..32 */ + w = create_tty_status_field(fld, i, over_w, prev_w); + X11_cond_labels[i - 1] = prev_w = w; + } + } } - } - - for (i = 0; i < 32; i++) { - char condname[BUFSZ]; - int prevfld; - - Sprintf(condname, "cond_%i", i); - num_args = 0; - - prevfld = X11_fieldorder[0][0]; - XtSetArg(args[num_args], nhStr(XtNfromVert), - X11_status_labels[prevfld]); num_args++; - - XtSetArg(args[num_args], nhStr(XtNfromHoriz), - (i == 0) ? X11_status_labels[BL_CONDITION] - : X11_cond_labels[i-1]); num_args++; - - XtSetArg(args[num_args], nhStr(XtNhorizDistance), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNvertDistance), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNbottomMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNleftMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; - XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++; - XtSetArg(args[num_args], nhStr(XtNlabel), ""); num_args++; - X11_cond_labels[i] = XtCreateManagedWidget(condname, - labelWidgetClass, w, - args, num_args); } - - return w; + return X11_status_widget; } /*ARGSUSED*/ void -create_status_window_tty(wp, create_popup, parent) -struct xwindow *wp; /* window pointer */ -boolean create_popup UNUSED; -Widget parent; +create_status_window_tty(struct xwindow *wp, /* window pointer */ + boolean create_popup UNUSED, Widget parent) { - Arg args[10]; - Cardinal num_args; - wp->type = NHW_STATUS; - X11_status_widget = wp->w = create_tty_status(parent, (Widget) 0); - - num_args = 0; - XtSetArg(args[num_args], nhStr(XtNforeground), &X11_status_widget_fg); num_args++; - XtSetArg(args[num_args], nhStr(XtNbackground), &X11_status_widget_bg); num_args++; - XtGetValues(X11_status_widget, args, num_args); + wp->w = create_tty_status(parent, (Widget) 0); } void -destroy_status_window_tty(wp) -struct xwindow *wp; +destroy_status_window_tty(struct xwindow *wp) { - /* If status_information is defined, then it a "text" status window. */ + /* if status_information is defined, then it is a "text" status window */ if (wp->status_information) { if (wp->popup) { nh_XtPopdown(wp->popup); @@ -727,6 +1070,7 @@ struct xwindow *wp; free((genericptr_t) wp->status_information); wp->status_information = 0; } else { + ; } if (!wp->keep_window) wp->type = NHW_NONE; @@ -734,29 +1078,67 @@ struct xwindow *wp; /*ARGSUSED*/ void -adjust_status_tty(wp, str) -struct xwindow *wp UNUSED; -const char *str UNUSED; +adjust_status_tty(struct xwindow *wp UNUSED, const char *str UNUSED) { /* nothing */ + return; } void -create_status_window(wp, create_popup, parent) -struct xwindow *wp; /* window pointer */ -boolean create_popup; -Widget parent; +create_status_window( + struct xwindow *wp, /* window pointer */ + boolean create_popup, + Widget parent) { + struct status_info_t *si = (struct status_info_t *) alloc(sizeof *si); + xw_status_win = wp; - if (appResources.fancy_status) - create_status_window_fancy(wp, create_popup, parent); - else + if (wp->Win_info.Status_info) + free((genericptr_t) wp->Win_info.Status_info); + wp->Win_info.Status_info = si; + (void) memset((genericptr_t) si, 0, sizeof *si); + + if (!appResources.fancy_status) create_status_window_tty(wp, create_popup, parent); + else + create_status_window_fancy(wp, create_popup, parent); + +#if 0 /* + * this does not work as intended; it triggers + * "Warning: Cannot find callback list in XtAddCallback" + */ + XtAddCallback(wp->w, XtNresizeCallback, stat_resized, (XtPointer) 0); +#else + nhUse(stat_resized); +#endif +} + +/* callback to deal with the game window being resized */ +static void +stat_resized(Widget w, XtPointer call_data, XtPointer client_data) +{ + Arg args[4]; + Cardinal num_args; + struct xwindow *wp = xw_status_win; + + nhUse(call_data); + nhUse(client_data); + + if (w == wp->w) { + num_args = 0; + XtSetArg(args[num_args], XtNwidth, &wp->pixel_width); num_args++; + XtSetArg(args[num_args], XtNwidth, &wp->pixel_height); num_args++; + XtGetValues(w, args, num_args); + } else { + impossible("Status Window resized, but of what widget?"); + } + + /* tell core to call us back for a full status update */ + disp.botlx = TRUE; } void -destroy_status_window(wp) -struct xwindow *wp; +destroy_status_window(struct xwindow *wp) { if (appResources.fancy_status) destroy_status_window_fancy(wp); @@ -765,9 +1147,7 @@ struct xwindow *wp; } void -adjust_status(wp, str) -struct xwindow *wp; -const char *str; +adjust_status(struct xwindow *wp, const char *str) { if (appResources.fancy_status) adjust_status_fancy(wp, str); @@ -775,14 +1155,9 @@ const char *str; adjust_status_tty(wp, str); } -extern const char *hu_stat[]; /* from eat.c */ -extern const char *enc_stat[]; /* from botl.c */ - void -create_status_window_fancy(wp, create_popup, parent) -struct xwindow *wp; /* window pointer */ -boolean create_popup; -Widget parent; +create_status_window_fancy(struct xwindow *wp, /* window pointer */ + boolean create_popup, Widget parent) { XFontStruct *fs; Arg args[8]; @@ -804,32 +1179,28 @@ Widget parent; } wp->status_information = - (struct status_info_t *) alloc(sizeof(struct status_info_t)); + (struct status_info_t *) alloc(sizeof (struct status_info_t)); init_text_buffer(&wp->status_information->text); num_args = 0; - XtSetArg(args[num_args], XtNallowShellResize, False); - num_args++; - XtSetArg(args[num_args], XtNinput, False); - num_args++; + XtSetArg(args[num_args], XtNallowShellResize, False); num_args++; + XtSetArg(args[num_args], XtNinput, False); num_args++; - wp->popup = parent = XtCreatePopupShell( - "status_popup", topLevelShellWidgetClass, toplevel, args, num_args); + wp->popup = parent = XtCreatePopupShell("status_popup", + topLevelShellWidgetClass, + toplevel, args, num_args); /* * If we're here, then this is an auxiliary status window. If we're * cancelled via a delete window message, we should just pop down. */ num_args = 0; - XtSetArg(args[num_args], nhStr(XtNdisplayCaret), False); - num_args++; + XtSetArg(args[num_args], nhStr(XtNdisplayCaret), False); num_args++; XtSetArg(args[num_args], nhStr(XtNscrollHorizontal), - XawtextScrollWhenNeeded); - num_args++; + XawtextScrollWhenNeeded); num_args++; XtSetArg(args[num_args], nhStr(XtNscrollVertical), - XawtextScrollWhenNeeded); - num_args++; + XawtextScrollWhenNeeded); num_args++; wp->w = XtCreateManagedWidget("status", /* name */ asciiTextWidgetClass, @@ -844,34 +1215,28 @@ Widget parent; /* Get the font and margin information. */ num_args = 0; - XtSetArg(args[num_args], XtNfont, &fs); - num_args++; - XtSetArg(args[num_args], nhStr(XtNtopMargin), &top_margin); - num_args++; - XtSetArg(args[num_args], nhStr(XtNbottomMargin), &bottom_margin); - num_args++; - XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin); - num_args++; - XtSetArg(args[num_args], nhStr(XtNrightMargin), &right_margin); - num_args++; + XtSetArg(args[num_args], XtNfont, &fs); num_args++; + XtSetArg(args[num_args], nhStr(XtNtopMargin), &top_margin); num_args++; + XtSetArg(args[num_args], nhStr(XtNbottomMargin), + &bottom_margin); num_args++; + XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin); num_args++; + XtSetArg(args[num_args], nhStr(XtNrightMargin), + &right_margin); num_args++; XtGetValues(wp->w, args, num_args); wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin; - wp->pixel_width = - COLNO * fs->max_bounds.width + left_margin + right_margin; + wp->pixel_width = COLNO * fs->max_bounds.width + + left_margin + right_margin; /* Set the new width and height. */ num_args = 0; - XtSetArg(args[num_args], XtNwidth, wp->pixel_width); - num_args++; - XtSetArg(args[num_args], XtNheight, wp->pixel_height); - num_args++; + XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++; + XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++; XtSetValues(wp->w, args, num_args); } void -destroy_status_window_fancy(wp) -struct xwindow *wp; +destroy_status_window_fancy(struct xwindow *wp) { /* If status_information is defined, then it a "text" status window. */ if (wp->status_information) { @@ -891,20 +1256,18 @@ struct xwindow *wp; /* * This assumes several things: - * + Status has only 2 lines - * + That both lines are updated in succession in line order. - * + We didn't set stringInPlace on the widget. + * + Status has only 2 lines + * + That both lines are updated in succession in line order. + * + We didn't set stringInPlace on the widget. */ void -adjust_status_fancy(wp, str) -struct xwindow *wp; -const char *str; +adjust_status_fancy(struct xwindow *wp, const char *str) { Arg args[2]; Cardinal num_args; if (!wp->status_information) { - update_fancy_status(wp); + update_fancy_status(TRUE); return; } @@ -917,14 +1280,14 @@ const char *str; /* Set new buffer as text. */ num_args = 0; - XtSetArg(args[num_args], XtNstring, wp->status_information->text.text); - num_args++; + XtSetArg(args[num_args], XtNstring, + wp->status_information->text.text); num_args++; XtSetValues(wp->w, args, num_args); } -/* Fancy Status - * -------------------------------------------------------------*/ -static int hilight_time = 1; /* number of turns to hilight a changed value */ +/* Fancy ================================================================== */ +extern const char *const hu_stat[]; /* from eat.c */ +extern const char *const enc_stat[]; /* from botl.c */ struct X_status_value { /* we have to cast away 'const' when assigning new names */ @@ -935,80 +1298,195 @@ struct X_status_value { int turn_count; /* last time the value changed */ boolean set; /* if highlighted */ boolean after_init; /* don't highlight on first change (init) */ + boolean inverted_hilite; /* if highlit due to hilite_status inverse rule */ + Pixel default_fg; /* what FG color it initialized with */ + int colr, attr; /* color and attribute */ }; /* valid type values */ #define SV_VALUE 0 /* displays a label:value pair */ -#define SV_LABEL 1 /* displays a changable label */ -#define SV_NAME 2 /* displays an unchangeable name */ - -static void FDECL(hilight_label, (Widget)); -static void FDECL(update_val, (struct X_status_value *, long)); -static const char *FDECL(width_string, (int)); -static void FDECL(create_widget, (Widget, struct X_status_value *, int)); -static void FDECL(get_widths, (struct X_status_value *, int *, int *)); -static void FDECL(set_widths, (struct X_status_value *, int, int)); -static Widget FDECL(init_column, (const char *, Widget, Widget, Widget, - int *)); -static void NDECL(fixup_cond_widths); -static Widget FDECL(init_info_form, (Widget, Widget, Widget)); +#define SV_LABEL 1 /* displays a changeable label */ +#define SV_NAME 2 /* displays an unchangeable name */ + +/* for overloaded conditions */ +struct ovld_item { + unsigned long ovl_mask; + int ff; +}; +#define NUM_OVLD 4 /* peak number of overloads for a single field */ +struct f_overload { + unsigned long all_mask; + struct ovld_item conds[NUM_OVLD]; +}; +static const struct f_overload *ff_ovld_from_mask(unsigned long); +static const struct f_overload *ff_ovld_from_indx(int); +static void hilight_label(Widget); +static void update_val(struct X_status_value *, long); +static void skip_cond_val(struct X_status_value *); +static void update_color(struct X_status_value *, int); +static boolean name_widget_has_label(struct X_status_value *); +static void apply_hilite_attributes(struct X_status_value *, int); +static const char *width_string(int); +static void create_widget(Widget, struct X_status_value *, int); +static void get_widths(struct X_status_value *, int *, int *); +static void set_widths(struct X_status_value *, int, int); +static Widget init_column(const char *, Widget, Widget, Widget, int *, int); +static void fixup_cond_widths(void); +static Widget init_info_form(Widget, Widget, Widget); + +/* narrower values for the array initializer */ +#define W0 (Widget) 0 +#define P0 (Pixel) 0 /* * Notes: * + Alignment needs a different init value, because -1 is an alignment. * + Armor Class is an schar, so 256 is out of range. * + Blank value is 0 and should never change. + * + * - These must be in the same order as the F_foo numbers. */ static struct X_status_value shown_stats[NUM_STATS] = { - { "", SV_NAME, (Widget) 0, -1, 0, FALSE, FALSE }, /* 0*/ - - { "Strength", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Dexterity", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Constitution", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Intelligence", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Wisdom", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 5*/ - { "Charisma", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - - { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */ - { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */ - { "Gold", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Hit Points", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*10*/ - { "Max HP", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Max Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Armor Class", SV_VALUE, (Widget) 0, 256, 0, FALSE, FALSE }, - { "Level", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*15*/ - { "Experience", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Alignment", SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE }, - { "Time", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - { "Score", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, - - { "Petrifying", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*20*/ - { "Slimed", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Strangled", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Food Pois", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Term Ill", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - - { "", SV_NAME, (Widget) 0, -1, 0, FALSE, TRUE }, /*25*/ /* hunger */ - { "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*encumbr */ - { "Levitating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Flying", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Riding", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - - { "Blind", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*30*/ - { "Deaf", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Stunned", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Confused", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, - { "Hallucinating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, + /* 0 */ + { "", SV_NAME, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + /* 1 */ + { "Strength", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + { "Dexterity", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + { "Constitution", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + { "Intelligence", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + /* 5 */ + { "Wisdom", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + { "Charisma", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + /* F_NAME: 7 */ + { "", SV_LABEL, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + /* F_DLEVEL: 8 */ + { "", SV_LABEL, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + { "Gold", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + /* F_HP: 10 */ + { "Hit Points", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + { "Max HP", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + { "Power", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + { "Max Power", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + { "Armor Class", SV_VALUE, W0, 256L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + /* F_XP_LEVL: 15 */ + { "Xp Level", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + /* also 15 (overloaded field) */ + /*{ "Hit Dice", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },*/ + /* F_EXP_PTS: 16 (optionally displayed) */ + { "Exp Points", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + { "Alignment", SV_VALUE, W0, -2L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + /* 18, optionally displayed */ + { "Time", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + /* 19, conditionally present, optionally displayed when present */ + { "Score", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, + /* F_HUNGER: 20 (blank if 'normal') */ + { "", SV_NAME, W0, -1L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + /* F_ENCUMBER: 21 (blank if unencumbered) */ + { "", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Trapped", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Tethered", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Levitating", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + /* 25 */ + { "Flying", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Riding", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Grabbed!", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + /* F_STONE: 28 */ + { "Petrifying", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Slimed", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + /* 30 */ + { "Strangled", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Food Pois", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Term Ill", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + /* F_IN_LAVA: 33 */ + { "Sinking", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Held", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + /* 35 */ + { "Holding", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Blind", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Deaf", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Stunned", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + { "Confused", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + /* F_HALLU: 40 (full spelling truncated due to space limitations) */ + { "Hallucinat", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 }, + /* F_VERS; optionally shown, generally treated as a pseudo-condition */ + { "Version 1.2.3", SV_LABEL, W0, 0L, 0, FALSE, FALSE, FALSE, P0, 0, 0 }, +}; +#undef W0 +#undef P0 +/* + * The following are supported by the core but not yet handled here: + * bareh 'bare handed' (no weapon and no gloves) + * busy involved in some multi-turn activity, possibly involuntarily + * elf_iron elf being harmed by contact with iron (not implemented) + * glowhands 'glowing hands' (inflict confuse monster for next N melee hits) + * icy on or above ice terrain (temporary fumbling; might melt) + * parlyz paralyzed (can't move) + * sleeping asleep (can't move; might wake if attacked) + * slippery 'slippery hands' or gloves (will drop non-cursed weapons) + * submerged underwater (severely restricted vision, hampered movement) + * unconsc unconscious (can't move; includes fainted) + * woundedl 'wounded legs' (can't kick; temporary dex loss) + */ + +/* some conditions are mutually exclusive so we overload their fields in + order to share same display slot */ +static const struct f_overload cond_ovl[] = { + { (BL_MASK_TRAPPED | BL_MASK_TETHERED), + { { BL_MASK_TRAPPED, F_TRAPPED }, + { BL_MASK_TETHERED, F_TETHERED } }, + }, + { + /* BL_GRABBED is mutually exclusive with these but is more severe so + is shown separately rather than being overloaded with them */ + (BL_MASK_HELD | BL_MASK_HOLDING), + { { BL_MASK_HELD, F_HELD }, + { BL_MASK_HOLDING, F_HOLDING } }, + }, +#if 0 /* not yet implemented */ + { (BL_MASK_BUSY | BL_MASK_PARALYZ | BL_MASK_SLEEPING | BL_MASK_UNCONSC), + { { BL_MASK_BUSY, F_BUSY }, /* can't move but none of the below... */ + { BL_MASK_PARALYZ, F_PARALYZED } + { BL_MASK_SLEEPING, F_SLEEPING } + { BL_MASK_UNCONSC, F_UNCONSCIOUS } }, + }, +#endif }; +static const struct f_overload * +ff_ovld_from_mask(unsigned long mask) +{ + const struct f_overload *fo; + + for (fo = cond_ovl; fo < cond_ovl + SIZE(cond_ovl); ++fo) { + if ((fo->all_mask & mask) != 0L) + return fo; + } + return (struct f_overload *) 0; +} + +static const struct f_overload * +ff_ovld_from_indx(int indx) /* F_foo number, index into shown_stats[] */ +{ + const struct f_overload *fo; + int i, ff; + + if (indx > 0) { /* skip 0 (F_DUMMY) */ + for (fo = cond_ovl; fo < cond_ovl + SIZE(cond_ovl); ++fo) { + for (i = 0; i < NUM_OVLD && (ff = fo->conds[i].ff) > 0; ++i) + if (ff == indx) + return fo; + } + } + return (struct f_overload *) 0; +} + /* * Set all widget values to a null string. This is used after all spacings * have been calculated so that when the window is popped up we don't get all * kinds of funny values being displayed. */ void -null_out_status() +null_out_status(void) { int i; struct X_status_value *sv; @@ -1033,61 +1511,65 @@ null_out_status() } } -/* This is almost an exact duplicate of hilight_value() */ +/* this is almost an exact duplicate of hilight_value() */ static void -hilight_label(w) -Widget w; /* label widget */ +hilight_label(Widget w) /* label widget */ { - Arg args[2]; - Pixel fg, bg; - - XtSetArg(args[0], XtNforeground, &fg); - XtSetArg(args[1], XtNbackground, &bg); - XtGetValues(w, args, TWO); - - XtSetArg(args[0], XtNforeground, bg); - XtSetArg(args[1], XtNbackground, fg); - XtSetValues(w, args, TWO); + /* + * This predates STATUS_HILITES. + * It is used to show any changed item in inverse and gets + * reset on the next turn. + */ + swap_fg_bg(w); } +DISABLE_WARNING_FORMAT_NONLITERAL + static void -update_val(attr_rec, new_value) -struct X_status_value *attr_rec; -long new_value; +update_val(struct X_status_value *attr_rec, long new_value) { + static boolean Exp_shown = TRUE, time_shown = TRUE, score_shown = TRUE, + Xp_was_HD = FALSE; char buf[BUFSZ]; Arg args[4]; if (attr_rec->type == SV_LABEL) { if (attr_rec == &shown_stats[F_NAME]) { - Strcpy(buf, plname); + Strcpy(buf, svp.plname); buf[0] = highc(buf[0]); Strcat(buf, " the "); if (Upolyd) { - char mname[BUFSZ]; + char mnam[BUFSZ]; int k; - Strcpy(mname, mons[u.umonnum].mname); - for (k = 0; mname[k] != '\0'; k++) { - if (k == 0 || mname[k - 1] == ' ') - mname[k] = highc(mname[k]); + Strcpy(mnam, pmname(&mons[u.umonnum], Ugender)); + for (k = 0; mnam[k] != '\0'; k++) { + if (k == 0 || mnam[k - 1] == ' ') + mnam[k] = highc(mnam[k]); } - Strcat(buf, mname); - } else - Strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female)); + Strcat(buf, mnam); + } else { + Strcat(buf, + rank_of(u.ulevel, svp.pl_character[0], flags.female)); + } } else if (attr_rec == &shown_stats[F_DLEVEL]) { - if (!describe_level(buf)) { - Strcpy(buf, dungeons[u.uz.dnum].dname); + if (!describe_level(buf, 0)) { + Strcpy(buf, svd.dungeons[u.uz.dnum].dname); Sprintf(eos(buf), ", level %d", depth(&u.uz)); } + } else if (attr_rec == &shown_stats[F_VERS]) { + if (flags.showvers) + (void) status_version(buf, sizeof buf, FALSE); + else + buf[0] = '\0'; } else { impossible("update_val: unknown label type \"%s\"", attr_rec->name); return; } - if (strcmp(buf, attr_rec->name) == 0) + if (!strcmp(buf, attr_rec->name)) return; /* same */ /* Set the label. 'name' field is const for most entries; @@ -1102,16 +1584,19 @@ long new_value; attr_rec->last_value = new_value; - /* special cases: hunger, encumbrance, sickness */ + /* special cases: hunger and encumbrance */ if (attr_rec == &shown_stats[F_HUNGER]) { - XtSetArg(args[0], XtNlabel, hu_stat[new_value]); + Strcpy(buf, hu_stat[new_value]); + (void) mungspaces(buf); } else if (attr_rec == &shown_stats[F_ENCUMBER]) { - XtSetArg(args[0], XtNlabel, enc_stat[new_value]); + Strcpy(buf, enc_stat[new_value]); } else if (new_value) { - XtSetArg(args[0], XtNlabel, attr_rec->name); + Strcpy(buf, attr_rec->name); /* condition name On */ } else { - XtSetArg(args[0], XtNlabel, ""); + *buf = '\0'; /* condition name Off */ } + + XtSetArg(args[0], XtNlabel, buf); XtSetValues(attr_rec->w, args, ONE); } else { /* a value pair */ @@ -1119,92 +1604,66 @@ long new_value; /* special case: time can be enabled & disabled */ if (attr_rec == &shown_stats[F_TIME]) { - static boolean flagtime = TRUE; - - if (flags.time && !flagtime) { + if (flags.time && !time_shown) { set_name(attr_rec->w, shown_stats[F_TIME].name); force_update = TRUE; - flagtime = flags.time; - } else if (!flags.time && flagtime) { + time_shown = TRUE; + } else if (!flags.time && time_shown) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); - flagtime = flags.time; + time_shown = FALSE; } - if (!flagtime) + if (!time_shown) return; - } - /* special case: exp can be enabled & disabled */ - else if (attr_rec == &shown_stats[F_EXP]) { - static boolean flagexp = TRUE; + /* special case: experience points can be enabled & disabled */ + } else if (attr_rec == &shown_stats[F_EXP_PTS]) { + boolean showexp = flags.showexp && !Upolyd; - if (flags.showexp && !flagexp) { - set_name(attr_rec->w, shown_stats[F_EXP].name); + if (showexp && !Exp_shown) { + set_name(attr_rec->w, shown_stats[F_EXP_PTS].name); force_update = TRUE; - flagexp = flags.showexp; - } else if (!flags.showexp && flagexp) { + Exp_shown = TRUE; + } else if (!showexp && Exp_shown) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); - flagexp = flags.showexp; + Exp_shown = FALSE; } - if (!flagexp) + if (!Exp_shown) return; - } - /* special case: score can be enabled & disabled */ - else if (attr_rec == &shown_stats[F_SCORE]) { - static boolean flagscore = TRUE; + /* special case: when available, score can be enabled & disabled */ + } else if (attr_rec == &shown_stats[F_SCORE]) { #ifdef SCORE_ON_BOTL - - if (flags.showscore && !flagscore) { + if (flags.showscore && !score_shown) { set_name(attr_rec->w, shown_stats[F_SCORE].name); force_update = TRUE; - flagscore = flags.showscore; - } else if (!flags.showscore && flagscore) { + score_shown = TRUE; + } else +#endif + if (!flags.showscore && score_shown) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); - flagscore = flags.showscore; + score_shown = FALSE; } - if (!flagscore) + if (!score_shown) return; -#else - if (flagscore) { - set_name(attr_rec->w, ""); - set_value(attr_rec->w, ""); - flagscore = FALSE; - } - return; -#endif - } - - /* special case: when polymorphed, show "HD", disable exp */ - else if (attr_rec == &shown_stats[F_LEVEL]) { - static boolean lev_was_poly = FALSE; - if (Upolyd && !lev_was_poly) { + /* special case: when polymorphed, show "Hit Dice" and disable Exp */ + } else if (attr_rec == &shown_stats[F_XP_LEVL]) { + if (Upolyd && !Xp_was_HD) { force_update = TRUE; - set_name(attr_rec->w, "HD"); - lev_was_poly = TRUE; - } else if (Upolyd && lev_was_poly) { + set_name(attr_rec->w, "Hit Dice"); + Xp_was_HD = TRUE; + } else if (!Upolyd && Xp_was_HD) { force_update = TRUE; - set_name(attr_rec->w, shown_stats[F_LEVEL].name); - lev_was_poly = FALSE; + set_name(attr_rec->w, shown_stats[F_XP_LEVL].name); + Xp_was_HD = FALSE; } - } else if (attr_rec == &shown_stats[F_EXP]) { - static boolean exp_was_poly = FALSE; - - if (Upolyd && !exp_was_poly) { - force_update = TRUE; - set_name(attr_rec->w, ""); - set_value(attr_rec->w, ""); - exp_was_poly = TRUE; - } else if (Upolyd && exp_was_poly) { - force_update = TRUE; - set_name(attr_rec->w, shown_stats[F_EXP].name); - exp_was_poly = FALSE; - } - if (Upolyd) - return; /* no display for exp when poly */ + /* core won't call status_update() for Exp when it hasn't changed + so do so ourselves (to get Exp_shown flag to match display) */ + if (force_update) + update_fancy_status_field(F_EXP_PTS, NO_COLOR, HL_UNDEF); } if (attr_rec->last_value == new_value && !force_update) /* same */ @@ -1212,23 +1671,34 @@ long new_value; attr_rec->last_value = new_value; - /* Special cases: strength, alignment and "clear". */ - if (attr_rec == &shown_stats[F_STR]) { - if (new_value > 18) { - if (new_value > 118) - Sprintf(buf, "%ld", new_value - 100); - else if (new_value < 118) - Sprintf(buf, "18/%02ld", new_value - 18); + /* Special cases: strength and other characteristics, alignment + and "clear". */ + if (attr_rec >= &shown_stats[F_STR] + && attr_rec <= &shown_stats[F_CHA]) { + static const char fmt1[] = "%ld%s", fmt2[] = "%2ld%s"; + struct xwindow *wp; + const char *fmt = fmt1, *padding = ""; + + /* for full-fledged fancy status, force two digits for all + six characteristics, followed by three spaces of padding + to match "/xx" exceptional strength */ + wp = (WIN_STATUS != WIN_ERR) ? &window_list[WIN_STATUS] : 0; + if (wp && !wp->status_information) + fmt = fmt2, padding = " "; + + if (new_value > 18L && attr_rec == &shown_stats[F_STR]) { + if (new_value > 118L) /* 19..25 encoded as 119..125 */ + Sprintf(buf, fmt, new_value - 100L, padding); + else if (new_value < 118L) /* 18/01..18/99 as 19..117*/ + Sprintf(buf, "18/%02ld", new_value - 18L); else - Strcpy(buf, "18/**"); - } else { - Sprintf(buf, "%ld", new_value); + Strcpy(buf, "18/**"); /* 18/100 encoded as 118 */ + } else { /* non-strength or less than 18/01 strength (3..18) */ + Sprintf(buf, fmt, new_value, padding); /* 3..25 */ } } else if (attr_rec == &shown_stats[F_ALIGN]) { - Strcpy(buf, - (new_value == A_CHAOTIC) - ? "Chaotic" - : (new_value == A_NEUTRAL) ? "Neutral" : "Lawful"); + Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic" + : (new_value == A_NEUTRAL) ? "Neutral" : "Lawful"); } else { Sprintf(buf, "%ld", new_value); } @@ -1236,24 +1706,124 @@ long new_value; } /* - * Now hilight the changed information. Names, time and score don't - * hilight. If first time, don't hilight. If already lit, don't do - * it again. + * Now highlight the changed information. Don't highlight Time because + * it's continually changing. Don't highlight version because once set + * it only changes if player modifies 'versinfo' option. For others, + * don't highlight if this is the first update. + * If already highlighted, don't change it unless + * it's being set to blank (where that item should be reset now instead + * of showing highlighted blank until the next expiration check). + * + * 5.0: highlight non-labelled 'name' items (conditions plus hunger + * and encumbrance) when they come On. For all conditions going Off, + * or changing to not-hungry or not-encumbered, there's nothing to + * highlight because the field becomes blank. */ - if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) { - if (attr_rec->after_init) { - if (!attr_rec->set) { - if (attr_rec->type == SV_LABEL) - hilight_label(attr_rec->w); - else + if (attr_rec->after_init) { + /* toggle if not highlighted and being set to nonblank or if + already highlighted and being set to blank */ + if (attr_rec != &shown_stats[F_TIME] + && attr_rec != &shown_stats[F_VERS] + && !attr_rec->set ^ !*buf) { + /* But don't hilite if inverted from status_hilite since + it will already be hilited by apply_hilite_attributes(). */ + if (!attr_rec->inverted_hilite) { + if (attr_rec->type == SV_VALUE) hilight_value(attr_rec->w); - attr_rec->set = TRUE; + else + hilight_label(attr_rec->w); } - attr_rec->turn_count = 0; - } else { - attr_rec->after_init = TRUE; + attr_rec->set = !attr_rec->set; + } + attr_rec->turn_count = 0; + } else { + XtSetArg(args[0], XtNforeground, &attr_rec->default_fg); + XtGetValues(attr_rec->w, args, ONE); + attr_rec->after_init = TRUE; + } +} + +RESTORE_WARNING_FORMAT_NONLITERAL + +/* overloaded condition is being cleared without going through update_val() + so that an alternate can be shown; put this one back to default settings */ +static void +skip_cond_val(struct X_status_value *sv) +{ + sv->last_value = 0L; /* Off */ + if (sv->set) { + /* if condition was highlighted and the alternate value has + also requested to be highlighted, it used its own copy of + 'set' but the same widget so the highlighting got toggled + off; this will turn in back on in that exceptional case */ + hilight_label(sv->w); + sv->set = FALSE; + } +} + +static void +update_color(struct X_status_value *sv, int color) +{ + Pixel pixel = 0; + Arg args[1]; + XrmValue source; + XrmValue dest; + Widget w = (sv->type == SV_LABEL || sv->type == SV_NAME) ? sv->w + : get_value_widget(sv->w); + + if (color == NO_COLOR) { + if (sv->after_init) + pixel = sv->default_fg; + sv->colr = NO_COLOR; + } else { + source.addr = (XPointer) fancy_status_hilite_colors[color]; + source.size = (unsigned int) strlen((const char *) source.addr) + 1; + dest.size = (unsigned int) sizeof (Pixel); + dest.addr = (XPointer) &pixel; + if (XtConvertAndStore(w, XtRString, &source, XtRPixel, &dest)) + sv->colr = color; + } + if (pixel != 0) { + char *arg_name = (sv->set || sv->inverted_hilite) ? XtNbackground + : XtNforeground; + + XtSetArg(args[0], arg_name, pixel); + XtSetValues(w, args, ONE); + } +} + +static boolean +name_widget_has_label(struct X_status_value *sv) +{ + Arg args[1]; + const char *label; + + XtSetArg(args[0], XtNlabel, &label); + XtGetValues(sv->w, args, ONE); + return (*label != '\0'); +} + +static void +apply_hilite_attributes(struct X_status_value *sv, int attributes) +{ + boolean attr_inversion = ((HL_INVERSE & attributes) + && (sv->type != SV_NAME + || name_widget_has_label(sv))); + + if (sv->inverted_hilite != attr_inversion) { + sv->inverted_hilite = attr_inversion; + if (!sv->set) { + if (sv->type == SV_VALUE) + hilight_value(sv->w); + else + hilight_label(sv->w); } } + sv->attr = attributes; + /* Could possibly add more attributes here: HL_ATTCLR_DIM, + HL_ATTCLR_BLINK, HL_ATTCLR_ULINE, and HL_ATTCLR_BOLD. If so, + extract the above into its own function apply_hilite_inverse() + and each other attribute into its own to keep the code clean. */ } /* @@ -1262,23 +1832,24 @@ long new_value; * the other. So only do our update when we update the second line. * * Information on the first line: - * name, attributes, alignment, score + * name, characteristics, alignment, score * * Information on the second line: - * dlvl, gold, hp, power, ac, {level & exp or HD **}, time, - * status * (stone, slime, strngl, foodpois, termill, + * dlvl, gold, hp, power, ac, {level & exp or HD **}, time, + * status * (stone, slime, strngl, foodpois, termill, * hunger, encumbrance, lev, fly, ride, - * blind, deaf, stun, conf, hallu) + * blind, deaf, stun, conf, hallu, version ***) * - * [*] order of status fields is different on tty. - * [**] HD is shown instead of level and exp if Upolyd. + * [*] order of status fields is different on tty. + * [**] HD is shown instead of level and exp if Upolyd. + * [***] version is optional, right-justified after conditions */ static void -update_fancy_status_field(i) -int i; +update_fancy_status_field(int i, int color, int attributes) { struct X_status_value *sv = &shown_stats[i]; - long val; + unsigned long condmask = 0L; + long val = 0L; switch (i) { case F_DUMMY: @@ -1303,8 +1874,8 @@ int i; val = (long) ACURR(A_CHA); break; /* - * Label stats. With the exceptions of hunger, encumbrance, sick - * these are either on or off. Pleae leave the ternary operators + * Label stats. With the exceptions of hunger and encumbrance + * these are either on or off. Please leave the ternary operators * the way they are. I want to specify 0 or 1, not a boolean. */ case F_HUNGER: @@ -1313,56 +1884,80 @@ int i; case F_ENCUMBER: val = (long) near_capacity(); break; + + case F_TRAPPED: /* belongs with non-fatal but fits with 'other' */ + condmask = BL_MASK_TRAPPED; + break; + case F_TETHERED: /* overloaded with 'trapped' */ + condmask = BL_MASK_TETHERED; + break; + /* 'other' status conditions */ case F_LEV: - val = Levitation ? 1L : 0L; + condmask = BL_MASK_LEV; break; case F_FLY: - val = Flying ? 1L : 0L; + condmask = BL_MASK_FLY; break; case F_RIDE: - val = u.usteed ? 1L : 0L; + condmask = BL_MASK_RIDE; break; /* fatal status conditions */ + case F_GRABBED: + condmask = BL_MASK_GRAB; + break; case F_STONE: - val = Stoned ? 1L : 0L; + condmask = BL_MASK_STONE; break; case F_SLIME: - val = Slimed ? 1L : 0L; + condmask = BL_MASK_SLIME; break; case F_STRNGL: - val = Strangled ? 1L : 0L; + condmask = BL_MASK_STRNGL; break; case F_FOODPOIS: - val = (Sick && (u.usick_type & SICK_VOMITABLE)) ? 1L : 0L; + condmask = BL_MASK_FOODPOIS; break; case F_TERMILL: - val = (Sick && (u.usick_type & SICK_NONVOMITABLE)) ? 1L : 0L; + condmask = BL_MASK_TERMILL; + break; + case F_IN_LAVA: /* could overload with 'trapped' but is more severe */ + condmask = BL_MASK_INLAVA; break; /* non-fatal status conditions */ + case F_HELD: + condmask = BL_MASK_HELD; + break; + case F_HOLDING: /* belongs with 'other' but overloads 'held' */ + condmask = BL_MASK_HOLDING; + break; case F_BLIND: - val = Blind ? 1L : 0L; + condmask = BL_MASK_BLIND; break; case F_DEAF: - val = Deaf ? 1L : 0L; + condmask = BL_MASK_DEAF; break; case F_STUN: - val = Stunned ? 1L : 0L; + condmask = BL_MASK_STUN; break; case F_CONF: - val = Confusion ? 1L : 0L; + condmask = BL_MASK_CONF; break; case F_HALLU: - val = Hallucination ? 1L : 0L; + condmask = BL_MASK_HALLU; + break; + + /* pseudo-condition */ + case F_VERS: + val = (long) flags.versinfo; /* 1..7 */ break; case F_NAME: - val = (long) 0L; - break; /* special */ case F_DLEVEL: val = (long) 0L; break; /* special */ + case F_GOLD: - val = money_cnt(invent); + val = money_cnt(gi.invent); if (val < 0L) val = 0L; /* ought to issue impossible() and discard gold */ break; @@ -1382,17 +1977,17 @@ int i; case F_AC: val = (long) u.uac; break; - case F_LEVEL: + case F_XP_LEVL: val = (long) (Upolyd ? mons[u.umonnum].mlevel : u.ulevel); break; - case F_EXP: + case F_EXP_PTS: val = flags.showexp ? u.uexp : 0L; break; case F_ALIGN: val = (long) u.ualign.type; break; case F_TIME: - val = flags.time ? (long) moves : 0L; + val = flags.time ? (long) svm.moves : 0L; break; case F_SCORE: #ifdef SCORE_ON_BOTL @@ -1405,70 +2000,111 @@ int i; /* * There is a possible infinite loop that occurs with: * - * impossible->pline->flush_screen->bot->bot{1,2}-> - * putstr->adjust_status->update_other->impossible + * impossible->pline->flush_screen->bot->bot{1,2}-> + * putstr->adjust_status->update_other->impossible * * Break out with this. */ - static boolean active = FALSE; + static boolean isactive = FALSE; - if (!active) { - active = TRUE; + if (!isactive) { + isactive = TRUE; impossible("update_other: unknown shown value"); - active = FALSE; + isactive = FALSE; } val = 0L; break; } /* default */ } /* switch */ + + if (condmask) { + const struct f_overload *fo = ff_ovld_from_mask(condmask); + + val = ((X11_condition_bits & condmask) != 0L); + /* if we're turning an overloaded field Off, don't do it if any + of the other alternatives are being set On because we would + clobber that if the other one happens to be drawn first */ + if (!val && fo && (X11_condition_bits & fo->all_mask) != 0L) { + skip_cond_val(sv); + return; + } + } update_val(sv, val); + if (color != sv->colr) + update_color(sv, color); + if (attributes != sv->attr) + apply_hilite_attributes(sv, attributes); } -/*ARGUSED*/ +/* fully update status after bl_flush or window resize */ static void -update_fancy_status(wp) -struct xwindow *wp UNUSED; +update_fancy_status(boolean force_update) { + static boolean old_showtime, old_showexp, old_showscore, old_showvers; + static int old_upolyd = -1; /* -1: force first time update */ int i; - /*if (wp->cursy != 0) - return;*/ /* do a complete update when line 0 is done */ - - for (i = 0; i < NUM_STATS; i++) - update_fancy_status_field(i); + if (force_update + || Upolyd != old_upolyd /* Xp vs HD */ + || flags.time != old_showtime + || flags.showexp != old_showexp + || flags.showscore != old_showscore + || flags.showvers != old_showvers) { + /* update everything; usually only need this on the very first + time, then later if the window gets resized or if poly/unpoly + triggers Xp <-> HD switch or if an optional field gets + toggled off since there won't be a status_update() call for + the no longer displayed field; we're a bit more conservative + than that and do this when toggling on as well as off */ + for (i = 0; i < NUM_STATS; i++) + update_fancy_status_field(i, NO_COLOR, HL_UNDEF); + old_condition_bits = X11_condition_bits; + + old_upolyd = Upolyd; + old_showtime = flags.time; + old_showexp = flags.showexp; + old_showscore = flags.showscore; + old_showvers = flags.showvers; + } } - /* * Turn off hilighted status values after a certain amount of turns. */ void -check_turn_events() +check_turn_events(void) { int i; struct X_status_value *sv; + int hilight_time = 1; +#ifdef STATUS_HILITES + if (iflags.hilite_delta) + hilight_time = (int) iflags.hilite_delta; +#endif for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) { if (!sv->set) continue; if (sv->turn_count++ >= hilight_time) { - if (sv->type == SV_LABEL) - hilight_label(sv->w); - else - hilight_value(sv->w); + /* unhighlights by toggling a highlighted item back off again, + unless forced inverted by a status_hilite rule */ + if (!sv->inverted_hilite) { + if (sv->type == SV_VALUE) + hilight_value(sv->w); + else + hilight_label(sv->w); + } sv->set = FALSE; } } } -/* Initialize alternate status ============================================= - */ +/* Initialize alternate status ============================================ */ -/* Return a string for the initial width. */ +/* Return a string for the initial width, so use longest possible value. */ static const char * -width_string(sv_index) -int sv_index; +width_string(int sv_index) { switch (sv_index) { case F_DUMMY: @@ -1491,11 +2127,17 @@ int sv_index; case F_LEV: case F_FLY: case F_RIDE: + case F_TRAPPED: + case F_TETHERED: + case F_GRABBED: case F_STONE: case F_SLIME: case F_STRNGL: case F_FOODPOIS: case F_TERMILL: + case F_IN_LAVA: + case F_HELD: + case F_HOLDING: case F_BLIND: case F_DEAF: case F_STUN: @@ -1505,7 +2147,8 @@ int sv_index; case F_NAME: case F_DLEVEL: - return ""; + return ""; /* longest possible value not needed for these */ + case F_HP: case F_MAXHP: return "9999"; @@ -1514,12 +2157,12 @@ int sv_index; return "9999"; case F_AC: return "-127"; - case F_LEVEL: + case F_XP_LEVL: return "99"; case F_GOLD: /* strongest hero can pick up roughly 30% of this much */ return "999999"; /* same limit as tty */ - case F_EXP: + case F_EXP_PTS: case F_TIME: case F_SCORE: return "123456789"; /* a tenth digit will still fit legibly */ @@ -1531,10 +2174,7 @@ int sv_index; } static void -create_widget(parent, sv, sv_index) -Widget parent; -struct X_status_value *sv; -int sv_index; +create_widget(Widget parent, struct X_status_value *sv, int sv_index) { Arg args[4]; Cardinal num_args; @@ -1551,24 +2191,51 @@ int sv_index; *(char *) (sv->name) = '\0'; num_args = 0; - XtSetArg(args[num_args], XtNborderWidth, 0); - num_args++; - XtSetArg(args[num_args], XtNinternalHeight, 0); - num_args++; + XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; + XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++; sv->w = XtCreateManagedWidget((sv_index == F_NAME) ? "name" : "dlevel", labelWidgetClass, parent, args, num_args); break; - case SV_NAME: + case SV_NAME: { + char buf[BUFSZ]; + const char *txt; + const struct f_overload *fo = ff_ovld_from_indx(sv_index); + int baseindx = fo ? fo->conds[0].ff : sv_index; + + if (sv_index != baseindx) { + /* this code isn't actually executed; only the base condition + is in one of the fancy status columns and only the fields + in those columns are passed to this routine; the real + initialization--this same assignment--for overloaded + conditions takes place at the end of create_fancy_status() */ + sv->w = shown_stats[baseindx].w; + break; + } + txt = width_string(sv_index); /* for conditions, it's just sv->name */ + if (fo) { + int i, ff, altln, ln = (int) strlen(txt); + + /* make the initial value have the width of the longest of + these overloaded conditions; used for widget sizing, not for + display, and ultimately only matters if one of the overloads + happens to be the longest string in its whole column */ + for (i = 1; i < NUM_OVLD && (ff = fo->conds[i].ff) > 0; ++i) + if ((altln = (int) strlen(width_string(ff))) > ln) + ln = altln; + Sprintf(buf, "%*s", ln, txt); + txt = buf; + } num_args = 0; - XtSetArg(args[0], XtNlabel, width_string(sv_index)); num_args++; + XtSetArg(args[0], XtNlabel, txt); num_args++; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++; sv->w = XtCreateManagedWidget(sv->name, labelWidgetClass, parent, args, num_args); break; + } default: panic("create_widget: unknown type %d", sv->type); } @@ -1578,9 +2245,7 @@ int sv_index; * Get current width of value. width2p is only valid for SV_VALUE types. */ static void -get_widths(sv, width1p, width2p) -struct X_status_value *sv; -int *width1p, *width2p; +get_widths(struct X_status_value *sv, int *width1p, int *width2p) { Arg args[1]; Dimension width; @@ -1603,9 +2268,7 @@ int *width1p, *width2p; } static void -set_widths(sv, width1, width2) -struct X_status_value *sv; -int width1, width2; +set_widths(struct X_status_value *sv, int width1, int width2) { Arg args[1]; @@ -1625,10 +2288,10 @@ int width1, width2; } static Widget -init_column(name, parent, top, left, col_indices) -const char *name; -Widget parent, top, left; -int *col_indices; +init_column( + const char *name, + Widget parent, Widget top, Widget left, + int *col_indices, int xtrawidth) { Widget form; Arg args[4]; @@ -1639,15 +2302,13 @@ int *col_indices; num_args = 0; if (top != (Widget) 0) { - XtSetArg(args[num_args], nhStr(XtNfromVert), top); - num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++; } if (left != (Widget) 0) { - XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); - num_args++; + XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++; } - XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); - num_args++; + /* this was 0 but that resulted in the text being crammed together */ + XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++; form = XtCreateManagedWidget(name, formWidgetClass, parent, args, num_args); @@ -1658,8 +2319,7 @@ int *col_indices; if (ip != col_indices) { /* not first */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), - shown_stats[*(ip - 1)].w); - num_args++; + shown_stats[*(ip - 1)].w); num_args++; XtSetValues(sv->w, args, num_args); } get_widths(sv, &width1, &width2); @@ -1668,6 +2328,10 @@ int *col_indices; if (width2 > max_width2) max_width2 = width2; } + + /* insert some extra spacing between columns */ + max_width1 += xtrawidth; + for (ip = col_indices; *ip >= 0; ip++) { set_widths(&shown_stats[*ip], max_width1, max_width2); } @@ -1683,48 +2347,71 @@ int *col_indices; * These are the orders of the displayed columns. Change to suit. The -1 * indicates the end of the column. The two numbers after that are used * to store widths that are calculated at run-time. + * + * 5.0: changed so that all 6 columns have 8 rows, but a few entries + * are left blank <>. Exp-points, Score, and Time are optional depending + * on run-time settings; Xp-level is replaced by Hit-Dice (and Exp-points + * suppressed) when the hero is polymorphed. Title and Dungeon-Level span + * two columns and might expand to more if 'hitpointbar' is implemented. + * Version is optional, right justified, and much wider than the others. + * + Title ("Plname the Rank") <> <> <> <> + Dungeon-Branch-and-Level <> Hunger Grabbed Held + Hit-points Max-HP Strength Encumbrance Petrifying Blind + Power-points Max-Power Dexterity Trapped Slimed Deaf + Armor-class Alignment Constitution Levitation Strangled Stunned + Xp-level [Exp-points] Intelligence Flying Food-Pois Confused + Gold [Score] Wisdom Riding Term-Ill Hallucinat + <> [Time] Charisma <> Sinking Version + * + * A seventh column is going to be needed to fit in more conditions. */ -static int attrib_indices[] = { F_STR, F_DEX, F_CON, F_INT, F_WIS, F_CHA, - -1, 0, 0 }; + /* including F_DUMMY makes the three status condition columns evenly spaced with regard to the adjacent characteristics (Str,Dex,&c) column; - we lose track of the Widget pointer for them, each use clobbering the + we lose track of the Widget pointer for F_DUMMY, each use clobbering the one before, leaving the one from leftover_indices[]; since they're never updated, that shouldn't matter */ -static int status_indices[3][9] = { { F_STONE, F_SLIME, F_STRNGL, - F_FOODPOIS, F_TERMILL, F_DUMMY, - -1, 0, 0 }, - { F_HUNGER, F_ENCUMBER, - F_LEV, F_FLY, F_RIDE, F_DUMMY, - -1, 0, 0 }, - { F_BLIND, F_DEAF, F_STUN, - F_CONF, F_HALLU, F_DUMMY, - -1, 0, 0 } }; +static int status_indices[3][11] = { + { F_DUMMY, F_HUNGER, F_ENCUMBER, F_TRAPPED, + F_LEV, F_FLY, F_RIDE, F_DUMMY, -1, 0, 0 }, + { F_DUMMY, F_GRABBED, F_STONE, F_SLIME, F_STRNGL, + F_FOODPOIS, F_TERMILL, F_IN_LAVA, -1, 0, 0 }, + { F_DUMMY, F_HELD, F_BLIND, F_DEAF, F_STUN, + F_CONF, F_HALLU, F_VERS, -1, 0, 0 }, +}; /* used to fill up the empty space to right of 3rd status condition column */ static int leftover_indices[] = { F_DUMMY, -1, 0, 0 }; +/* -2: top two rows of these columns are reserved for title and location */ +static int col1_indices[11 - 2] = { + F_HP, F_POWER, F_AC, F_XP_LEVL, F_GOLD, F_DUMMY, -1, 0, 0 +}; +static int col2_indices[11 - 2] = { + F_MAXHP, F_MAXPOWER, F_ALIGN, F_EXP_PTS, F_SCORE, F_TIME, -1, 0, 0 +}; +static int characteristics_indices[11 - 2] = { + F_STR, F_DEX, F_CON, F_INT, F_WIS, F_CHA, -1, 0, 0 +}; -static int col1_indices[] = { F_HP, F_POWER, F_AC, F_LEVEL, F_GOLD, - F_SCORE, -1, 0, 0 }; -static int col2_indices[] = { F_MAXHP, F_MAXPOWER, F_ALIGN, F_EXP, F_TIME, - -1, 0, 0 }; /* * Produce a form that looks like the following: * - * name - * dlevel - * col1_indices[0] col2_indices[0] - * col1_indices[1] col2_indices[1] - * . . - * . . - * col1_indices[n] col2_indices[n] + * title + * location + * col1_indices[0] col2_indices[0] col3_indices[0] + * col1_indices[1] col2_indices[1] col3_indices[1] + * ... ... ... + * col1_indices[5] col2_indices[5] col3_indices[5] * - * TODO: increase the space between the two columns. + * The status conditions are managed separately and appear to the right + * of this form. + * + * TODO: widen title field and implement hitpoint bar on it. */ static Widget -init_info_form(parent, top, left) -Widget parent, top, left; +init_info_form(Widget parent, Widget top, Widget left) { - Widget form, col1; + Widget form, col1, col2; struct X_status_value *sv_name, *sv_dlevel; Arg args[6]; Cardinal num_args; @@ -1732,35 +2419,34 @@ Widget parent, top, left; num_args = 0; if (top != (Widget) 0) { - XtSetArg(args[num_args], nhStr(XtNfromVert), top); - num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++; } if (left != (Widget) 0) { - XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); - num_args++; + XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++; } - XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); - num_args++; - form = XtCreateManagedWidget("status_info", formWidgetClass, parent, args, - num_args); + XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++; + form = XtCreateManagedWidget("status_info", formWidgetClass, parent, + args, num_args); - /* top of form */ - sv_name = &shown_stats[F_NAME]; + /* top line/row of form */ + sv_name = &shown_stats[F_NAME]; /* title */ create_widget(form, sv_name, F_NAME); - /* second */ - sv_dlevel = &shown_stats[F_DLEVEL]; + /* second line/row */ + sv_dlevel = &shown_stats[F_DLEVEL]; /* location */ create_widget(form, sv_dlevel, F_DLEVEL); num_args = 0; - XtSetArg(args[num_args], nhStr(XtNfromVert), sv_name->w); - num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), sv_name->w); num_args++; XtSetValues(sv_dlevel->w, args, num_args); - /* two columns beneath */ + /* there are 3 columns beneath but top 2 rows are centered over first 2 */ col1 = init_column("name_col1", form, sv_dlevel->w, (Widget) 0, - col1_indices); - (void) init_column("name_col2", form, sv_dlevel->w, col1, col2_indices); + col1_indices, 0); + col2 = init_column("name_col2", form, sv_dlevel->w, col1, + col2_indices, 5); + (void) init_column("status_characteristics", form, sv_dlevel->w, col2, + characteristics_indices, 15); /* Add calculated widths. */ for (ip = col1_indices; *ip >= 0; ip++) @@ -1782,7 +2468,7 @@ Widget parent, top, left; /* give the three status condition columns the same width */ static void -fixup_cond_widths() +fixup_cond_widths(void) { int pass, i, *ip, w1, w2; @@ -1807,9 +2493,26 @@ fixup_cond_widths() } /* ascetics: expand the maximum width to make cond columns wider */ if (pass == 1) { - w1 += 20; + w1 += 15; if (w2 > 0) - w2 += 20; + w2 += 15; + } + } + + { + Arg args[3]; + Dimension vers_width = 0; + struct X_status_value *sv = &shown_stats[F_VERS]; + + if (sv) { + XtSetArg(args[0], XtNwidth, &vers_width); + XtGetValues(sv->w, args, ONE); + if (vers_width) { + vers_width *= 3; + XtSetArg(args[0], XtNwidth, vers_width); + XtSetArg(args[1], nhStr(XtNjustify), XtJustifyRight); + XtSetValues(sv->w, args, TWO); + } } } } @@ -1819,45 +2522,61 @@ fixup_cond_widths() * contains everything. */ static Widget -create_fancy_status(parent, top) -Widget parent, top; +create_fancy_status(Widget parent, Widget top) { Widget form; /* The form that surrounds everything. */ Widget w; Arg args[8]; Cardinal num_args; char buf[32]; - int i; + const struct f_overload *fo; + int i, ff; num_args = 0; if (top != (Widget) 0) { - XtSetArg(args[num_args], nhStr(XtNfromVert), top); - num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++; } - XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); - num_args++; - XtSetArg(args[num_args], XtNborderWidth, 0); - num_args++; - XtSetArg(args[num_args], XtNorientation, XtorientHorizontal); - num_args++; + XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 2); num_args++; + XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; + XtSetArg(args[num_args], XtNorientation, XtorientHorizontal); num_args++; form = XtCreateManagedWidget("fancy_status", panedWidgetClass, parent, args, num_args); w = init_info_form(form, (Widget) 0, (Widget) 0); - w = init_column("status_attributes", form, (Widget) 0, w, attrib_indices); +#if 0 /* moved to init_info_form() */ + w = init_column("status_characteristics", form, (Widget) 0, w, + characteristics_indices, 15); +#endif for (i = 0; i < 3; i++) { Sprintf(buf, "status_condition%d", i + 1); - w = init_column(buf, form, (Widget) 0, w, status_indices[i]); + w = init_column(buf, form, (Widget) 0, w, status_indices[i], 0); } - fixup_cond_widths(); /* make all 3 status_conditionN columns same width */ - w = init_column("status_leftover", form, (Widget) 0, w, leftover_indices); - nhUse(w); + fixup_cond_widths(); /* make all 3 status_conditionN columns same width + * (actually, the slot for F_VERS is much wider) */ + /* TODO: + * Calculate and set the width of the F_VERS widjet to be from the + * start of the third condition column through the right edge and + * get rid of the dummy column. + */ + + /* extra dummy 'column' to allocate any remaining space below the map */ + (void) init_column("status_leftover", form, (Widget) 0, w, + leftover_indices, 0); + + /* handle overloading; extra conditions don't start out in any column + so need to be initialized separately; the only initialization they + need is to share the widget of the base condition which is present + in one of the columns [could be deferred until first use] */ + for (fo = cond_ovl; fo < cond_ovl + SIZE(cond_ovl); ++fo) + for (i = 1; i < NUM_OVLD && (ff = fo->conds[i].ff) > 0; ++i) + if (!shown_stats[ff].w) + shown_stats[ff].w = shown_stats[fo->conds[0].ff].w; + return form; } static void -destroy_fancy_status(wp) -struct xwindow *wp; +destroy_fancy_status(struct xwindow *wp) { int i; struct X_status_value *sv; diff --git a/win/X11/wintext.c b/win/X11/wintext.c index 61615447c..cf2a1d7eb 100644 --- a/win/X11/wintext.c +++ b/win/X11/wintext.c @@ -1,11 +1,11 @@ -/* NetHack 3.6 wintext.c $NHDT-Date: 1552422654 2019/03/12 20:30:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.18 $ */ -/* Copyright (c) Dean Luick, 1992 */ +/* NetHack 5.0 wintext.c $NHDT-Date: 1597967808 2020/08/20 23:56:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.22 $ */ +/* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * File for dealing with text windows. * - * + No global functions. + * + No global functions. */ #ifndef SYSV @@ -28,7 +28,10 @@ #undef PRESERVE_NO_SYSV #endif +#define X11_BUILD #include "hack.h" +#undef X11_BUILD + #include "winX.h" #include "xwindow.h" @@ -48,16 +51,12 @@ static const char rip_translations[] = "#override\n\ : rip_dismiss_text()\n\ : rip_dismiss_text()"; -static Widget FDECL(create_ripout_widget, (Widget)); +static Widget create_ripout_widget(Widget); #endif /*ARGSUSED*/ void -delete_text(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +delete_text(Widget w, XEvent *event, String *params, Cardinal *num_params) { struct xwindow *wp; struct text_info_t *text_info; @@ -79,17 +78,13 @@ Cardinal *num_params; } /* - * Callback used for all text windows. The window is poped down on any key + * Callback used for all text windows. The window is popped down on any key * or button down event. It is destroyed if the main nethack code is done * with it. */ /*ARGSUSED*/ void -dismiss_text(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +dismiss_text(Widget w, XEvent *event, String *params, Cardinal *num_params) { struct xwindow *wp; struct text_info_t *text_info; @@ -112,11 +107,7 @@ Cardinal *num_params; /* Dismiss when a non-modifier key pressed. */ void -key_dismiss_text(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +key_dismiss_text(Widget w, XEvent *event, String *params, Cardinal *num_params) { char ch = key_event_to_char((XKeyEvent *) event); if (ch) @@ -126,11 +117,7 @@ Cardinal *num_params; #ifdef GRAPHIC_TOMBSTONE /* Dismiss from clicking on rip image. */ void -rip_dismiss_text(w, event, params, num_params) -Widget w; -XEvent *event; -String *params; -Cardinal *num_params; +rip_dismiss_text(Widget w, XEvent *event, String *params, Cardinal *num_params) { dismiss_text(XtParent(w), event, params, num_params); } @@ -138,10 +125,8 @@ Cardinal *num_params; /* ARGSUSED */ void -add_to_text_window(wp, attr, str) -struct xwindow *wp; -int attr; /* currently unused */ -const char *str; +add_to_text_window(struct xwindow *wp, int attr, /* currently unused */ + const char *str) { struct text_info_t *text_info = wp->text_information; int width; @@ -157,9 +142,7 @@ const char *str; } void -display_text_window(wp, blocking) -struct xwindow *wp; -boolean blocking; +display_text_window(struct xwindow *wp, boolean blocking) { struct text_info_t *text_info; Arg args[8]; @@ -214,7 +197,7 @@ boolean blocking; if (width > (Dimension) XtScreen(wp->w)->width) { /* too wide for screen */ /* Back off some amount - we really need to back off the scrollbar */ - /* width plus some extra. */ + /* width plus some extra. */ width = XtScreen(wp->w)->width - 20; } XtSetArg(args[num_args], XtNstring, text_info->text.text); @@ -250,7 +233,7 @@ boolean blocking; if (num_args) XtSetValues(wp->w, args, num_args); - /* We want the user to acknowlege. */ + /* We want the user to acknowledge. */ if (blocking) { (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(wp->popup); @@ -258,8 +241,7 @@ boolean blocking; } void -create_text_window(wp) -struct xwindow *wp; +create_text_window(struct xwindow *wp) { struct text_info_t *text_info; Arg args[8]; @@ -314,7 +296,7 @@ struct xwindow *wp; XtParseTranslationTable(text_translations)); num_args++; - wp->w = XtCreateManagedWidget(killer.name[0] && WIN_MAP == WIN_ERR + wp->w = XtCreateManagedWidget(svk.killer.name[0] && WIN_MAP == WIN_ERR ? "tombstone" : "text_text", /* name */ asciiTextWidgetClass, @@ -341,8 +323,7 @@ struct xwindow *wp; } void -destroy_text_window(wp) -struct xwindow *wp; +destroy_text_window(struct xwindow *wp) { /* Don't need to pop down, this only called from dismiss_text(). */ @@ -365,8 +346,7 @@ struct xwindow *wp; } void -clear_text_window(wp) -struct xwindow *wp; +clear_text_window(struct xwindow *wp) { clear_text_buffer(&wp->text_information->text); } @@ -376,10 +356,7 @@ struct xwindow *wp; /* Append a line to the text buffer. */ void -append_text_buffer(tb, str, concat) -struct text_buffer *tb; -const char *str; -boolean concat; +append_text_buffer(struct text_buffer *tb, const char *str, boolean concat) { char *copy; int length; @@ -410,7 +387,7 @@ boolean concat; if (tb->num_lines) { /* not first --- append a newline */ char appchar = '\n'; - if (concat && !index("!.?'\")", tb->text[tb->text_last - 1])) { + if (concat && !strchr("!.?'\")", tb->text[tb->text_last - 1])) { appchar = ' '; tb->num_lines--; /* offset increment at end of function */ } @@ -424,7 +401,7 @@ boolean concat; if (length) { /* Remove all newlines. Otherwise we have a confused line count. */ copy = (tb->text + tb->text_last); - while ((copy = index(copy, '\n')) != (char *) 0) + while ((copy = strchr(copy, '\n')) != (char *) 0) *copy = ' '; } @@ -436,8 +413,7 @@ boolean concat; /* Initialize text buffer. */ void -init_text_buffer(tb) -struct text_buffer *tb; +init_text_buffer(struct text_buffer *tb) { tb->text = (char *) alloc(START_SIZE); tb->text[0] = '\0'; @@ -448,8 +424,7 @@ struct text_buffer *tb; /* Empty the text buffer */ void -clear_text_buffer(tb) -struct text_buffer *tb; +clear_text_buffer(struct text_buffer *tb) { tb->text_last = 0; tb->text[0] = '\0'; @@ -458,8 +433,7 @@ struct text_buffer *tb; /* Free up allocated memory. */ void -free_text_buffer(tb) -struct text_buffer *tb; +free_text_buffer(struct text_buffer *tb) { free(tb->text); tb->text = (char *) 0; @@ -470,7 +444,7 @@ struct text_buffer *tb; #ifdef GRAPHIC_TOMBSTONE -static void FDECL(rip_exposed, (Widget, XtPointer, XtPointer)); +static void rip_exposed(Widget, XtPointer, XtPointer); static XImage *rip_image = 0; @@ -489,20 +463,26 @@ calculate_rip_text(int how, time_t when) char buf[BUFSZ]; char *dpx; - int line; - long year; + int line, year; + long cash; /* Put name on stone */ - Sprintf(rip_line[NAME_LINE], "%s", plname); + Sprintf(rip_line[NAME_LINE], "%.16s", svp.plname); /* STONE_LINE_LEN */ /* Put $ on stone */ - Sprintf(rip_line[GOLD_LINE], "%ld Au", done_money); + cash = max(gd.done_money, 0L); + /* arbitrary upper limit; practical upper limit is quite a bit less */ + if (cash > 999999999L) + cash = 999999999L; + Sprintf(buf, "%ld Au", cash); + Sprintf(rip_line[GOLD_LINE], "%ld Au", cash); + /* Put together death description */ formatkiller(buf, sizeof buf, how, FALSE); /* Put death type on stone */ for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; line++) { - register int i, i0; + int i, i0; char tmpchar; if ((i0 = strlen(dpx)) > STONE_LINE_LEN) { @@ -523,8 +503,8 @@ calculate_rip_text(int how, time_t when) } /* Put year on stone */ - year = yyyymmdd(when) / 10000L; - Sprintf(rip_line[YEAR_LINE], "%4ld", year); + year = (int) ((yyyymmdd(when) / 10000L) % 10000L); + Sprintf(rip_line[YEAR_LINE], "%4d", year); } /* @@ -532,17 +512,15 @@ calculate_rip_text(int how, time_t when) */ /*ARGSUSED*/ static void -rip_exposed(w, client_data, widget_data) -Widget w; -XtPointer client_data UNUSED; -XtPointer widget_data; /* expose event from Window widget */ +rip_exposed(Widget w, XtPointer client_data UNUSED, + XtPointer widget_data) /* expose event from Window widget */ { XExposeEvent *event = (XExposeEvent *) widget_data; Display *dpy = XtDisplay(w); Arg args[8]; XGCValues values; XtGCMask mask; - GC gc; + GC ggc; static Pixmap rip_pixmap = None; int i, x, y; @@ -565,10 +543,10 @@ XtPointer widget_data; /* expose event from Window widget */ XtGetValues(w, args, 1); values.function = GXcopy; values.font = WindowFont(w); - gc = XtGetGC(w, mask, &values); + ggc = XtGetGC(w, mask, &values); if (rip_pixmap != None) { - XCopyArea(dpy, rip_pixmap, XtWindow(w), gc, event->x, event->y, + XCopyArea(dpy, rip_pixmap, XtWindow(w), ggc, event->x, event->y, event->width, event->height, event->x, event->y); } @@ -579,12 +557,12 @@ XtPointer widget_data; /* expose event from Window widget */ XFontStruct *font = WindowFontStruct(w); int width = XTextWidth(font, rip_line[i], len); - XDrawString(dpy, XtWindow(w), gc, x - width / 2, y, rip_line[i], len); + XDrawString(dpy, XtWindow(w), ggc, x - width / 2, y, rip_line[i], len); x += appResources.tombtext_dx; y += appResources.tombtext_dy; } - XtReleaseGC(w, gc); + XtReleaseGC(w, ggc); } /* diff --git a/win/X11/winval.c b/win/X11/winval.c index 66de17926..62e3b9937 100644 --- a/win/X11/winval.c +++ b/win/X11/winval.c @@ -1,12 +1,12 @@ -/* NetHack 3.6 winval.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ -/* Copyright (c) Dean Luick, 1992 */ +/* NetHack 5.0 winval.c $NHDT-Date: 1611697183 2021/01/26 21:39:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ +/* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Routines that define a name-value label widget pair that fit inside a * form widget. */ -#include +/* #include */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ @@ -32,9 +32,7 @@ #define WVALUE "value" Widget -create_value(parent, name_value) -Widget parent; -const char *name_value; +create_value(Widget parent, const char *name_value) { Widget form, name; Arg args[8]; @@ -75,9 +73,7 @@ const char *name_value; } void -set_name(w, new_label) -Widget w; -const char *new_label; +set_name(Widget w, const char *new_label) { Arg args[1]; Widget name; @@ -88,9 +84,7 @@ const char *new_label; } void -set_name_width(w, new_width) -Widget w; -int new_width; +set_name_width(Widget w, int new_width) { Arg args[1]; Widget name; @@ -101,8 +95,7 @@ int new_width; } int -get_name_width(w) -Widget w; +get_name_width(Widget w) { Arg args[1]; Dimension width; @@ -114,59 +107,58 @@ Widget w; return (int) width; } +Widget +get_value_widget(Widget w) +{ + return XtNameToWidget(w, WVALUE); +} + void -set_value(w, new_value) -Widget w; -const char *new_value; +set_value(Widget w, const char *new_value) { Arg args[1]; Widget val; - val = XtNameToWidget(w, WVALUE); + val = get_value_widget(w); XtSetArg(args[0], XtNlabel, new_value); XtSetValues(val, args, ONE); } void -set_value_width(w, new_width) -Widget w; -int new_width; +set_value_width(Widget w, int new_width) { Arg args[1]; Widget val; - val = XtNameToWidget(w, WVALUE); + val = get_value_widget(w); XtSetArg(args[0], XtNwidth, new_width); XtSetValues(val, args, ONE); } int -get_value_width(w) -Widget w; +get_value_width(Widget w) { Arg args[1]; Widget val; Dimension width; - val = XtNameToWidget(w, WVALUE); + val = get_value_widget(w); XtSetArg(args[0], XtNwidth, &width); XtGetValues(val, args, ONE); return (int) width; } /* Swap foreground and background colors (this is the best I can do with */ -/* a label widget, unless I can get some init hook in there). */ +/* a label widget, unless I can get some init hook in there). */ void -hilight_value(w) -Widget w; +hilight_value(Widget w) { - swap_fg_bg(XtNameToWidget(w, WVALUE)); + swap_fg_bg(get_value_widget(w)); } /* Swap the foreground and background colors of the given widget */ void -swap_fg_bg(w) -Widget w; +swap_fg_bg(Widget w) { Arg args[2]; Pixel fg, bg; diff --git a/win/chain/wc_chainin.c b/win/chain/wc_chainin.c index 00cd7e75f..4e05d3933 100644 --- a/win/chain/wc_chainin.c +++ b/win/chain/wc_chainin.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 wc_chainin.c $NHDT-Date: 1433806610 2015/06/08 23:36:50 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ -/* Copyright (c) Kenneth Lorber, 2012 */ +/* NetHack 5.0 wc_chainin.c $NHDT-Date: 1596498323 2020/08/03 23:45:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ +/* Copyright (c) Kenneth Lorber, 2012 */ /* NetHack may be freely redistributed. See license for details. */ /* -chainin is an internal processor that changes the flow from window_procs @@ -7,6 +7,76 @@ #include "hack.h" +void chainin_init_nhwindows(int *, char **); +void chainin_player_selection(void); +void chainin_askname(void); +void chainin_get_nh_event(void); +void chainin_exit_nhwindows(const char *); +void chainin_suspend_nhwindows(const char *); +void chainin_resume_nhwindows(void); +winid chainin_create_nhwindow(int); +void chainin_clear_nhwindow(winid); +void chainin_display_nhwindow(winid, boolean); +void chainin_destroy_nhwindow(winid); +void chainin_curs(winid, int, int); +void chainin_putstr(winid, int, const char *); +void chainin_putmixed(winid, int, const char *); +void chainin_display_file(const char *, boolean); +void chainin_start_menu(winid, unsigned long); +void chainin_add_menu(winid, const glyph_info *, const ANY_P *, + char, char, int, int, + const char *, unsigned int); +void chainin_end_menu(winid, const char *); +int chainin_select_menu(winid, int, MENU_ITEM_P **); +char chainin_message_menu(char, int, const char *); +void chainin_mark_synch(void); +void chainin_wait_synch(void); +#ifdef CLIPPING +void chainin_cliparound(int, int); +#endif +#ifdef POSITIONBAR +void chainin_update_positionbar(char *); +#endif +void chainin_print_glyph(winid, coordxy, coordxy, + const glyph_info *, const glyph_info *); +void chainin_raw_print(const char *); +void chainin_raw_print_bold(const char *); +int chainin_nhgetch(void); +int chainin_nh_poskey(coordxy *, coordxy *, int *); +void chainin_nhbell(void); +int chainin_doprev_message(void); +char chainin_yn_function(const char *, const char *, char); +void chainin_getlin(const char *, char *); +int chainin_get_ext_cmd(void); +void chainin_number_pad(int); +void chainin_delay_output(void); +#ifdef CHANGE_COLOR +void chainin_change_color(int, long, int); +#ifdef MAC +void chainin_change_background(int); +short chainin_set_font_name(winid, char *); +#endif +char *chainin_get_color_string(void); +#endif + +void chainin_outrip(winid, int, time_t); +void chainin_preference_update(const char *); +char *chainin_getmsghistory(boolean); +void chainin_putmsghistory(const char *, boolean); +void chainin_status_init(void); +void chainin_status_finish(void); +void chainin_status_enablefield(int, const char *, const char *, + boolean); +void chainin_status_update(int, genericptr_t, int, int, int, + unsigned long *); + +boolean chainin_can_suspend(void); +void chainin_update_inventory(int); +win_request_info *chainin_ctrl_nhwindow(winid, int, win_request_info *); + +void *chainin_procs_chain(int cmd, int n, void *me, void *nextprocs, void *nextdata); +void chainin_procs_init(int dir); + struct chainin_data { struct chain_procs *nprocs; void *ndata; @@ -20,12 +90,12 @@ struct chainin_data { static struct chainin_data *cibase; void * -chainin_procs_chain(cmd, n, me, nextprocs, nextdata) -int cmd; -int n; -void *me; -void *nextprocs; -void *nextdata; +chainin_procs_chain( + int cmd, + int n, + void *me, + void *nextprocs, + void *nextdata) { struct chainin_data *tdp = 0; @@ -35,7 +105,7 @@ void *nextdata; tdp->nprocs = 0; tdp->ndata = 0; tdp->linknum = n; - cibase = 0; + cibase = tdp; break; case WINCHAIN_INIT: tdp = me; @@ -51,8 +121,8 @@ void *nextdata; /* XXX if we don't need this, take it out of the table */ void -chainin_procs_init(dir) -int dir UNUSED; +chainin_procs_init( + int dir UNUSED) { } @@ -61,54 +131,54 @@ int dir UNUSED; ***/ void -chainin_init_nhwindows(argcp, argv) -int *argcp; -char **argv; +chainin_init_nhwindows( + int *argcp, + char **argv) { (*cibase->nprocs->win_init_nhwindows)(cibase->ndata, argcp, argv); } void -chainin_player_selection() +chainin_player_selection(void) { (*cibase->nprocs->win_player_selection)(cibase->ndata); } void -chainin_askname() +chainin_askname(void) { (*cibase->nprocs->win_askname)(cibase->ndata); } void -chainin_get_nh_event() +chainin_get_nh_event(void) { (*cibase->nprocs->win_get_nh_event)(cibase->ndata); } void -chainin_exit_nhwindows(str) -const char *str; +chainin_exit_nhwindows( + const char *str) { (*cibase->nprocs->win_exit_nhwindows)(cibase->ndata, str); } void -chainin_suspend_nhwindows(str) -const char *str; +chainin_suspend_nhwindows( + const char *str) { (*cibase->nprocs->win_suspend_nhwindows)(cibase->ndata, str); } void -chainin_resume_nhwindows() +chainin_resume_nhwindows(void) { (*cibase->nprocs->win_resume_nhwindows)(cibase->ndata); } winid -chainin_create_nhwindow(type) -int type; +chainin_create_nhwindow( + int type) { winid rv; @@ -118,97 +188,100 @@ int type; } void -chainin_clear_nhwindow(window) -winid window; +chainin_clear_nhwindow( + winid window) { (*cibase->nprocs->win_clear_nhwindow)(cibase->ndata, window); } void -chainin_display_nhwindow(window, blocking) -winid window; -BOOLEAN_P blocking; +chainin_display_nhwindow( + winid window, + boolean blocking) { (*cibase->nprocs->win_display_nhwindow)(cibase->ndata, window, blocking); } void -chainin_destroy_nhwindow(window) -winid window; +chainin_destroy_nhwindow( + winid window) { (*cibase->nprocs->win_destroy_nhwindow)(cibase->ndata, window); } void -chainin_curs(window, x, y) -winid window; -int x; -int y; +chainin_curs( + winid window, + int x, + int y) { (*cibase->nprocs->win_curs)(cibase->ndata, window, x, y); } void -chainin_putstr(window, attr, str) -winid window; -int attr; -const char *str; +chainin_putstr( + winid window, + int attr, + const char *str) { (*cibase->nprocs->win_putstr)(cibase->ndata, window, attr, str); } void -chainin_putmixed(window, attr, str) -winid window; -int attr; -const char *str; +chainin_putmixed( + winid window, + int attr, + const char *str) { (*cibase->nprocs->win_putmixed)(cibase->ndata, window, attr, str); } void -chainin_display_file(fname, complain) -const char *fname; -boolean complain; +chainin_display_file( + const char *fname, + boolean complain) { (*cibase->nprocs->win_display_file)(cibase->ndata, fname, complain); } void -chainin_start_menu(window) -winid window; +chainin_start_menu( + winid window, + unsigned long mbehavior) { - (*cibase->nprocs->win_start_menu)(cibase->ndata, window); + (*cibase->nprocs->win_start_menu)(cibase->ndata, window, mbehavior); } void -chainin_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) -winid window; /* window to use, must be of type NHW_MENU */ -int glyph; /* glyph to display with item (unused) */ -const anything *identifier; /* what to return if selected */ -char ch; /* keyboard accelerator (0 = pick our own) */ -char gch; /* group accelerator (0 = no group) */ -int attr; /* attribute for string (like tty_putstr()) */ -const char *str; /* menu string */ -boolean preselected; /* item is marked as selected */ +chainin_add_menu( + winid window, /* window to use, must be of type NHW_MENU */ + const glyph_info *glyphinfo, /* glyph and other info to display with item */ + const anything *identifier, /* what to return if selected */ + char ch, /* keyboard accelerator (0 = pick our own) */ + char gch, /* group accelerator (0 = no group) */ + int attr, /* attribute for string (like tty_putstr()) */ + int clr, /* attribute for string (like tty_putstr()) */ + const char *str, /* menu string */ + unsigned int itemflags) /* flags such as item is marked as selected + MENU_ITEMFLAGS_SELECTED */ { - (*cibase->nprocs->win_add_menu)(cibase->ndata, window, glyph, identifier, - ch, gch, attr, str, preselected); + (*cibase->nprocs->win_add_menu)(cibase->ndata, window, glyphinfo, + identifier, ch, gch, attr, clr, str, itemflags); } void -chainin_end_menu(window, prompt) -winid window; -const char *prompt; +chainin_end_menu( + winid window, + const char *prompt) { (*cibase->nprocs->win_end_menu)(cibase->ndata, window, prompt); } int -chainin_select_menu(window, how, menu_list) -winid window; -int how; -menu_item **menu_list; +chainin_select_menu( + winid window, + int how, + menu_item **menu_list) { int rv; @@ -219,10 +292,10 @@ menu_item **menu_list; } char -chainin_message_menu(let, how, mesg) -char let; -int how; -const char *mesg; +chainin_message_menu( + char let, + int how, + const char *mesg) { char rv; @@ -232,28 +305,26 @@ const char *mesg; } void -chainin_update_inventory() +chainin_update_inventory(int arg) { - (*cibase->nprocs->win_update_inventory)(cibase->ndata); + (*cibase->nprocs->win_update_inventory)(cibase->ndata, arg); } void -chainin_mark_synch() +chainin_mark_synch(void) { (*cibase->nprocs->win_mark_synch)(cibase->ndata); } void -chainin_wait_synch() +chainin_wait_synch(void) { (*cibase->nprocs->win_wait_synch)(cibase->ndata); } #ifdef CLIPPING void -chainin_cliparound(x, y) -int x; -int y; +chainin_cliparound(int x, int y) { (*cibase->nprocs->win_cliparound)(cibase->ndata, x, y); } @@ -261,8 +332,7 @@ int y; #ifdef POSITIONBAR void -chainin_update_positionbar(posbar) -char *posbar; +chainin_update_positionbar(char *posbar) { (*cibase->nprocs->win_update_positionbar)(cibase->ndata, posbar); } @@ -270,30 +340,30 @@ char *posbar; /* XXX can we decode the glyph in a meaningful way? */ void -chainin_print_glyph(window, x, y, glyph, bkglyph) -winid window; -xchar x, y; -int glyph, bkglyph; +chainin_print_glyph( + winid window, + coordxy x, + coordxy y, + const glyph_info *glyphinfo, + const glyph_info *bkglyphinfo) { - (*cibase->nprocs->win_print_glyph)(cibase->ndata, window, x, y, glyph, bkglyph); + (*cibase->nprocs->win_print_glyph)(cibase->ndata, window, x, y, glyphinfo, bkglyphinfo); } void -chainin_raw_print(str) -const char *str; +chainin_raw_print(const char *str) { (*cibase->nprocs->win_raw_print)(cibase->ndata, str); } void -chainin_raw_print_bold(str) -const char *str; +chainin_raw_print_bold(const char *str) { (*cibase->nprocs->win_raw_print_bold)(cibase->ndata, str); } int -chainin_nhgetch() +chainin_nhgetch(void) { int rv; @@ -303,10 +373,10 @@ chainin_nhgetch() } int -chainin_nh_poskey(x, y, mod) -int *x; -int *y; -int *mod; +chainin_nh_poskey( + coordxy *x, + coordxy *y, + int *mod) { int rv; @@ -316,13 +386,13 @@ int *mod; } void -chainin_nhbell() +chainin_nhbell(void) { (*cibase->nprocs->win_nhbell)(cibase->ndata); } int -chainin_doprev_message() +chainin_doprev_message(void) { int rv; @@ -332,9 +402,10 @@ chainin_doprev_message() } char -chainin_yn_function(query, resp, def) -const char *query, *resp; -char def; +chainin_yn_function( + const char *query, + const char *resp, + char def) { int rv; @@ -344,15 +415,15 @@ char def; } void -chainin_getlin(query, bufp) -const char *query; -char *bufp; +chainin_getlin( + const char *query, + char *bufp) { (*cibase->nprocs->win_getlin)(cibase->ndata, query, bufp); } int -chainin_get_ext_cmd() +chainin_get_ext_cmd(void) { int rv; @@ -362,40 +433,38 @@ chainin_get_ext_cmd() } void -chainin_number_pad(state) -int state; +chainin_number_pad(int state) { (*cibase->nprocs->win_number_pad)(cibase->ndata, state); } void -chainin_delay_output() +chainin_delay_output(void) { (*cibase->nprocs->win_delay_output)(cibase->ndata); } #ifdef CHANGE_COLOR void -chainin_change_color(color, value, reverse) -int color; -long value; -int reverse; +chainin_change_color( + int color, + long value, + int reverse) { (*cibase->nprocs->win_change_color)(cibase->ndata, color, value, reverse); } #ifdef MAC void -chainin_change_background(bw) -int bw; +chainin_change_background(int bw) { (*cibase->nprocs->win_change_background)(cibase->ndata, bw); } short -chainin_set_font_name(window, font) -winid window; -char *font; +chainin_set_font_name( + winid window, + char *font) { short rv; @@ -406,7 +475,7 @@ char *font; #endif char * -trace_get_color_string() +trace_get_color_string(void) { char *rv; @@ -417,38 +486,23 @@ trace_get_color_string() #endif -/* other defs that really should go away (they're tty specific) */ void -chainin_start_screen() -{ - (*cibase->nprocs->win_start_screen)(cibase->ndata); -} - -void -chainin_end_screen() -{ - (*cibase->nprocs->win_end_screen)(cibase->ndata); -} - -void -chainin_outrip(tmpwin, how, when) -winid tmpwin; -int how; -time_t when; +chainin_outrip( + winid tmpwin, + int how, + time_t when) { (*cibase->nprocs->win_outrip)(cibase->ndata, tmpwin, how, when); } void -chainin_preference_update(pref) -const char *pref; +chainin_preference_update(const char *pref) { (*cibase->nprocs->win_preference_update)(cibase->ndata, pref); } char * -chainin_getmsghistory(init) -boolean init; +chainin_getmsghistory(boolean init) { char *rv; @@ -458,48 +512,48 @@ boolean init; } void -chainin_putmsghistory(msg, is_restoring) -const char *msg; -boolean is_restoring; +chainin_putmsghistory( + const char *msg, + boolean is_restoring) { (*cibase->nprocs->win_putmsghistory)(cibase->ndata, msg, is_restoring); } void -chainin_status_init() +chainin_status_init(void) { (*cibase->nprocs->win_status_init)(cibase->ndata); } void -chainin_status_finish() +chainin_status_finish(void) { (*cibase->nprocs->win_status_finish)(cibase->ndata); } void -chainin_status_enablefield(fieldidx, nm, fmt, enable) -int fieldidx; -const char *nm; -const char *fmt; -boolean enable; +chainin_status_enablefield( + int fieldidx, + const char *nm, + const char *fmt, + boolean enable) { (*cibase->nprocs->win_status_enablefield)(cibase->ndata, fieldidx, nm, fmt, enable); } -void -chainin_status_update(idx, ptr, chg, percent, color, colormasks) -int idx, chg, percent, color; -genericptr_t ptr; -unsigned long *colormasks; +void chainin_status_update( + int idx, + genericptr_t ptr, + int chg, int percent, int color, + unsigned long *colormasks) { (*cibase->nprocs->win_status_update)(cibase->ndata, idx, ptr, chg, percent, color, colormasks); } boolean -chainin_can_suspend() +chainin_can_suspend(void) { boolean rv; @@ -508,9 +562,23 @@ chainin_can_suspend() return rv; } +win_request_info * +chainin_ctrl_nhwindow( + winid window, + int request, + win_request_info *wri) +{ + win_request_info *rv; + + rv = (*cibase->nprocs->win_ctrl_nhwindow)(cibase->ndata, window, + request, wri); + return rv; +} + struct window_procs chainin_procs = { - "-chainin", 0, /* wincap */ + WPIDMINUS(chainin), 0, /* wincap */ 0, /* wincap2 */ + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ /* XXX problem - the above need to come from the real window port, possibly modified. May need to do something to call an additional init fn later @@ -525,7 +593,7 @@ struct window_procs chainin_procs = { chainin_display_nhwindow, chainin_destroy_nhwindow, chainin_curs, chainin_putstr, chainin_putmixed, chainin_display_file, chainin_start_menu, chainin_add_menu, chainin_end_menu, - chainin_select_menu, chainin_message_menu, chainin_update_inventory, + chainin_select_menu, chainin_message_menu, chainin_mark_synch, chainin_wait_synch, #ifdef CLIPPING chainin_cliparound, @@ -545,11 +613,11 @@ struct window_procs chainin_procs = { chainin_get_color_string, #endif - chainin_start_screen, chainin_end_screen, - chainin_outrip, chainin_preference_update, chainin_getmsghistory, chainin_putmsghistory, chainin_status_init, chainin_status_finish, chainin_status_enablefield, chainin_status_update, chainin_can_suspend, + chainin_update_inventory, + chainin_ctrl_nhwindow, }; diff --git a/win/chain/wc_chainout.c b/win/chain/wc_chainout.c index 18af49e17..a330e0efb 100644 --- a/win/chain/wc_chainout.c +++ b/win/chain/wc_chainout.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 wc_chainout.c $NHDT-Date: 1433806611 2015/06/08 23:36:51 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ -/* Copyright (c) Kenneth Lorber, 2012 */ +/* NetHack 5.0 wc_chainout.c $NHDT-Date: 1596498324 2020/08/03 23:45:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ +/* Copyright (c) Kenneth Lorber, 2012 */ /* NetHack may be freely redistributed. See license for details. */ /* -chainout is an internal processor that changes the flow from chain_procs @@ -7,6 +7,76 @@ #include "hack.h" +void chainout_init_nhwindows(void *,int *, char **); +void chainout_player_selection(void *); +void chainout_askname(void *); +void chainout_get_nh_event(void *); +void chainout_exit_nhwindows(void *,const char *); +void chainout_suspend_nhwindows(void *,const char *); +void chainout_resume_nhwindows(void *); +winid chainout_create_nhwindow(void *,int); +void chainout_clear_nhwindow(void *,winid); +void chainout_display_nhwindow(void *,winid, boolean); +void chainout_destroy_nhwindow(void *,winid); +void chainout_curs(void *,winid, int, int); +void chainout_putstr(void *,winid, int, const char *); +void chainout_putmixed(void *,winid, int, const char *); +void chainout_display_file(void *,const char *, boolean); +void chainout_start_menu(void *,winid, unsigned long); +void chainout_add_menu(void *,winid, const glyph_info *, const ANY_P *, + char, char, int, int, + const char *, unsigned int); +void chainout_end_menu(void *,winid, const char *); +int chainout_select_menu(void *,winid, int, MENU_ITEM_P **); +char chainout_message_menu(void *,char, int, const char *); +void chainout_mark_synch(void *); +void chainout_wait_synch(void *); +#ifdef CLIPPING +void chainout_cliparound(void *,int, int); +#endif +#ifdef POSITIONBAR +void chainout_update_positionbar(void *,char *); +#endif +void chainout_print_glyph(void *,winid, coordxy, coordxy, + const glyph_info *, const glyph_info *); +void chainout_raw_print(void *,const char *); +void chainout_raw_print_bold(void *,const char *); +int chainout_nhgetch(void *); +int chainout_nh_poskey(void *,coordxy *, coordxy *, int *); +void chainout_nhbell(void *); +int chainout_doprev_message(void *); +char chainout_yn_function(void *,const char *, const char *, char); +void chainout_getlin(void *,const char *, char *); +int chainout_get_ext_cmd(void *); +void chainout_number_pad(void *,int); +void chainout_delay_output(void *); +#ifdef CHANGE_COLOR +void chainout_change_color(void *,int, long, int); +#ifdef MAC +void chainout_change_background(void *,int); +short chainout_set_font_name(void *,winid, char *); +#endif +char *chainout_get_color_string(void *); +#endif + +void chainout_outrip(void *,winid, int, time_t); +void chainout_preference_update(void *,const char *); +char *chainout_getmsghistory(void *,boolean); +void chainout_putmsghistory(void *,const char *, boolean); +void chainout_status_init(void *); +void chainout_status_finish(void *); +void chainout_status_enablefield(void *,int, const char *, const char *, + boolean); +void chainout_status_update(void *,int, genericptr_t, int, int, int, + unsigned long *); + +boolean chainout_can_suspend(void *); +void chainout_update_inventory(void *, int); +win_request_info *chainout_ctrl_nhwindow(void *, winid, int, win_request_info *); + +void chainout_procs_init(int dir); +void *chainout_procs_chain(int cmd, int n, void *me, void *nextprocs, void *nextdata); + struct chainout_data { struct window_procs *nprocs; #if 0 @@ -17,12 +87,12 @@ struct chainout_data { }; void * -chainout_procs_chain(cmd, n, me, nextprocs, nextdata) -int cmd; -int n; -void *me; -void *nextprocs; -void *nextdata UNUSED; +chainout_procs_chain( + int cmd, + int n, + void *me, + void *nextprocs, + void *nextdata UNUSED) { struct chainout_data *tdp = 0; @@ -45,8 +115,7 @@ void *nextdata UNUSED; /* XXX if we don't need this, take it out of the table */ void -chainout_procs_init(dir) -int dir UNUSED; +chainout_procs_init(int dir UNUSED) { } @@ -55,10 +124,10 @@ int dir UNUSED; ***/ void -chainout_init_nhwindows(vp, argcp, argv) -void *vp; -int *argcp; -char **argv; +chainout_init_nhwindows( + void *vp, + int *argcp, + char **argv) { struct chainout_data *tdp = vp; @@ -66,8 +135,7 @@ char **argv; } void -chainout_player_selection(vp) -void *vp; +chainout_player_selection(void *vp) { struct chainout_data *tdp = vp; @@ -75,8 +143,7 @@ void *vp; } void -chainout_askname(vp) -void *vp; +chainout_askname(void *vp) { struct chainout_data *tdp = vp; @@ -84,8 +151,7 @@ void *vp; } void -chainout_get_nh_event(vp) -void *vp; +chainout_get_nh_event(void *vp) { struct chainout_data *tdp = vp; @@ -93,9 +159,9 @@ void *vp; } void -chainout_exit_nhwindows(vp, str) -void *vp; -const char *str; +chainout_exit_nhwindows( + void *vp, + const char *str) { struct chainout_data *tdp = vp; @@ -103,9 +169,9 @@ const char *str; } void -chainout_suspend_nhwindows(vp, str) -void *vp; -const char *str; +chainout_suspend_nhwindows( + void *vp, + const char *str) { struct chainout_data *tdp = vp; @@ -113,8 +179,7 @@ const char *str; } void -chainout_resume_nhwindows(vp) -void *vp; +chainout_resume_nhwindows(void *vp) { struct chainout_data *tdp = vp; @@ -122,9 +187,9 @@ void *vp; } winid -chainout_create_nhwindow(vp, type) -void *vp; -int type; +chainout_create_nhwindow( + void *vp, + int type) { struct chainout_data *tdp = vp; winid rv; @@ -135,9 +200,9 @@ int type; } void -chainout_clear_nhwindow(vp, window) -void *vp; -winid window; +chainout_clear_nhwindow( + void *vp, + winid window) { struct chainout_data *tdp = vp; @@ -145,10 +210,10 @@ winid window; } void -chainout_display_nhwindow(vp, window, blocking) -void *vp; -winid window; -BOOLEAN_P blocking; +chainout_display_nhwindow( + void *vp, + winid window, + boolean blocking) { struct chainout_data *tdp = vp; @@ -156,9 +221,9 @@ BOOLEAN_P blocking; } void -chainout_destroy_nhwindow(vp, window) -void *vp; -winid window; +chainout_destroy_nhwindow( + void *vp, + winid window) { struct chainout_data *tdp = vp; @@ -166,11 +231,11 @@ winid window; } void -chainout_curs(vp, window, x, y) -void *vp; -winid window; -int x; -int y; +chainout_curs( + void *vp, + winid window, + int x, + int y) { struct chainout_data *tdp = vp; @@ -178,11 +243,11 @@ int y; } void -chainout_putstr(vp, window, attr, str) -void *vp; -winid window; -int attr; -const char *str; +chainout_putstr( + void *vp, + winid window, + int attr, + const char *str) { struct chainout_data *tdp = vp; @@ -190,11 +255,11 @@ const char *str; } void -chainout_putmixed(vp, window, attr, str) -void *vp; -winid window; -int attr; -const char *str; +chainout_putmixed( + void *vp, + winid window, + int attr, + const char *str) { struct chainout_data *tdp = vp; @@ -202,10 +267,10 @@ const char *str; } void -chainout_display_file(vp, fname, complain) -void *vp; -const char *fname; -boolean complain; +chainout_display_file( + void *vp, + const char *fname, + boolean complain) { struct chainout_data *tdp = vp; @@ -213,39 +278,40 @@ boolean complain; } void -chainout_start_menu(vp, window) -void *vp; -winid window; +chainout_start_menu( + void *vp, + winid window, + unsigned long mbehavior) { struct chainout_data *tdp = vp; - (*tdp->nprocs->win_start_menu)(window); + (*tdp->nprocs->win_start_menu)(window, mbehavior); } void -chainout_add_menu(vp, window, glyph, identifier, ch, gch, attr, str, - preselected) -void *vp; -winid window; /* window to use, must be of type NHW_MENU */ -int glyph; /* glyph to display with item (unused) */ -const anything *identifier; /* what to return if selected */ -char ch; /* keyboard accelerator (0 = pick our own) */ -char gch; /* group accelerator (0 = no group) */ -int attr; /* attribute for string (like tty_putstr()) */ -const char *str; /* menu string */ -boolean preselected; /* item is marked as selected */ +chainout_add_menu( + void *vp, + winid window, /* window to use, must be of type NHW_MENU */ + const glyph_info *glyphinfo, /* glyph plus info to display with item */ + const anything *identifier, /* what to return if selected */ + char ch, /* keyboard accelerator (0 = pick our own) */ + char gch, /* group accelerator (0 = no group) */ + int attr, /* attribute for string (like tty_putstr()) */ + int clr, /* clr for string */ + const char *str, /* menu string */ + unsigned int itemflags) /* itemflags such as marked as selected */ { struct chainout_data *tdp = vp; - (*tdp->nprocs->win_add_menu)(window, glyph, identifier, ch, gch, attr, - str, preselected); + (*tdp->nprocs->win_add_menu)(window, glyphinfo, identifier, ch, gch, + attr, clr, str, itemflags); } void -chainout_end_menu(vp, window, prompt) -void *vp; -winid window; -const char *prompt; +chainout_end_menu( + void *vp, + winid window, + const char *prompt) { struct chainout_data *tdp = vp; @@ -253,11 +319,11 @@ const char *prompt; } int -chainout_select_menu(vp, window, how, menu_list) -void *vp; -winid window; -int how; -menu_item **menu_list; +chainout_select_menu( + void *vp, + winid window, + int how, + menu_item **menu_list) { struct chainout_data *tdp = vp; int rv; @@ -268,11 +334,11 @@ menu_item **menu_list; } char -chainout_message_menu(vp, let, how, mesg) -void *vp; -char let; -int how; -const char *mesg; +chainout_message_menu( + void *vp, + char let, + int how, + const char *mesg) { struct chainout_data *tdp = vp; char rv; @@ -283,17 +349,15 @@ const char *mesg; } void -chainout_update_inventory(vp) -void *vp; +chainout_update_inventory(void *vp, int arg) { struct chainout_data *tdp = vp; - (*tdp->nprocs->win_update_inventory)(); + (*tdp->nprocs->win_update_inventory)(arg); } void -chainout_mark_synch(vp) -void *vp; +chainout_mark_synch(void *vp) { struct chainout_data *tdp = vp; @@ -301,8 +365,7 @@ void *vp; } void -chainout_wait_synch(vp) -void *vp; +chainout_wait_synch(void *vp) { struct chainout_data *tdp = vp; @@ -311,10 +374,10 @@ void *vp; #ifdef CLIPPING void -chainout_cliparound(vp, x, y) -void *vp; -int x; -int y; +chainout_cliparound( + void *vp, + int x, + int y) { struct chainout_data *tdp = vp; @@ -324,9 +387,9 @@ int y; #ifdef POSITIONBAR void -chainout_update_positionbar(vp, posbar) -void *vp; -char *posbar; +chainout_update_positionbar( + void *vp, + char *posbar) { struct chainout_data *tdp = vp; @@ -335,21 +398,23 @@ char *posbar; #endif void -chainout_print_glyph(vp, window, x, y, glyph, bkglyph) -void *vp; -winid window; -xchar x, y; -int glyph, bkglyph; +chainout_print_glyph( + void *vp, + winid window, + coordxy x, + coordxy y, + const glyph_info *glyphinfo, + const glyph_info *bkglyphinfo) { struct chainout_data *tdp = vp; - (*tdp->nprocs->win_print_glyph)(window, x, y, glyph, bkglyph); + (*tdp->nprocs->win_print_glyph)(window, x, y, glyphinfo, bkglyphinfo); } void -chainout_raw_print(vp, str) -void *vp; -const char *str; +chainout_raw_print( + void *vp, + const char *str) { struct chainout_data *tdp = vp; @@ -357,9 +422,7 @@ const char *str; } void -chainout_raw_print_bold(vp, str) -void *vp; -const char *str; +chainout_raw_print_bold(void *vp, const char *str) { struct chainout_data *tdp = vp; @@ -367,8 +430,7 @@ const char *str; } int -chainout_nhgetch(vp) -void *vp; +chainout_nhgetch(void *vp) { struct chainout_data *tdp = vp; int rv; @@ -379,11 +441,11 @@ void *vp; } int -chainout_nh_poskey(vp, x, y, mod) -void *vp; -int *x; -int *y; -int *mod; +chainout_nh_poskey( + void *vp, + coordxy *x, + coordxy *y, + int *mod) { struct chainout_data *tdp = vp; int rv; @@ -394,8 +456,7 @@ int *mod; } void -chainout_nhbell(vp) -void *vp; +chainout_nhbell(void *vp) { struct chainout_data *tdp = vp; @@ -403,8 +464,7 @@ void *vp; } int -chainout_doprev_message(vp) -void *vp; +chainout_doprev_message(void *vp) { struct chainout_data *tdp = vp; int rv; @@ -415,10 +475,11 @@ void *vp; } char -chainout_yn_function(vp, query, resp, def) -void *vp; -const char *query, *resp; -char def; +chainout_yn_function( + void *vp, + const char *query, + const char *resp, + char def) { struct chainout_data *tdp = vp; int rv; @@ -429,10 +490,10 @@ char def; } void -chainout_getlin(vp, query, bufp) -void *vp; -const char *query; -char *bufp; +chainout_getlin( + void *vp, + const char *query, + char *bufp) { struct chainout_data *tdp = vp; @@ -440,8 +501,7 @@ char *bufp; } int -chainout_get_ext_cmd(vp) -void *vp; +chainout_get_ext_cmd(void *vp) { struct chainout_data *tdp = vp; int rv; @@ -452,9 +512,7 @@ void *vp; } void -chainout_number_pad(vp, state) -void *vp; -int state; +chainout_number_pad(void *vp, int state) { struct chainout_data *tdp = vp; @@ -462,8 +520,7 @@ int state; } void -chainout_delay_output(vp) -void *vp; +chainout_delay_output(void *vp) { struct chainout_data *tdp = vp; @@ -472,11 +529,11 @@ void *vp; #ifdef CHANGE_COLOR void -chainout_change_color(vp, color, value, reverse) -void *vp; -int color; -long value; -int reverse; +chainout_change_color( + void *vp, + int color, + long value, + int reverse) { struct chainout_data *tdp = vp; @@ -485,9 +542,9 @@ int reverse; #ifdef MAC void -chainout_change_background(vp, bw) -void *vp; -int bw; +chainout_change_background( + void *vp, + int bw) { struct chainout_data *tdp = vp; @@ -495,10 +552,10 @@ int bw; } short -chainout_set_font_name(vp, window, font) -void *vp; -winid window; -char *font; +chainout_set_font_name( + void *vp, + winid window, + char *font) { struct chainout_data *tdp = vp; short rv; @@ -510,8 +567,7 @@ char *font; #endif char * -trace_get_color_string(vp) -void *vp; +trace_get_color_string(void *vp) { struct chainout_data *tdp = vp; char *rv; @@ -523,31 +579,12 @@ void *vp; #endif -/* other defs that really should go away (they're tty specific) */ void -chainout_start_screen(vp) -void *vp; -{ - struct chainout_data *tdp = vp; - - (*tdp->nprocs->win_start_screen)(); -} - -void -chainout_end_screen(vp) -void *vp; -{ - struct chainout_data *tdp = vp; - - (*tdp->nprocs->win_end_screen)(); -} - -void -chainout_outrip(vp, tmpwin, how, when) -void *vp; -winid tmpwin; -int how; -time_t when; +chainout_outrip( + void *vp, + winid tmpwin, + int how, + time_t when) { struct chainout_data *tdp = vp; @@ -555,9 +592,9 @@ time_t when; } void -chainout_preference_update(vp, pref) -void *vp; -const char *pref; +chainout_preference_update( + void *vp, + const char *pref) { struct chainout_data *tdp = vp; @@ -565,9 +602,9 @@ const char *pref; } char * -chainout_getmsghistory(vp, init) -void *vp; -boolean init; +chainout_getmsghistory( + void *vp, + boolean init) { struct chainout_data *tdp = vp; char *rv; @@ -578,10 +615,10 @@ boolean init; } void -chainout_putmsghistory(vp, msg, is_restoring) -void *vp; -const char *msg; -boolean is_restoring; +chainout_putmsghistory( + void *vp, + const char *msg, + boolean is_restoring) { struct chainout_data *tdp = vp; @@ -589,8 +626,7 @@ boolean is_restoring; } void -chainout_status_init(vp) -void *vp; +chainout_status_init(void *vp) { struct chainout_data *tdp = vp; @@ -598,8 +634,7 @@ void *vp; } void -chainout_status_finish(vp) -void *vp; +chainout_status_finish(void *vp) { struct chainout_data *tdp = vp; @@ -607,12 +642,12 @@ void *vp; } void -chainout_status_enablefield(vp, fieldidx, nm, fmt, enable) -void *vp; -int fieldidx; -const char *nm; -const char *fmt; -boolean enable; +chainout_status_enablefield( + void *vp, + int fieldidx, + const char *nm, + const char *fmt, + boolean enable) { struct chainout_data *tdp = vp; @@ -620,11 +655,14 @@ boolean enable; } void -chainout_status_update(vp, idx, ptr, chg, percent, color, colormasks) -void *vp; -int idx, chg, percent, color; -genericptr_t ptr; -unsigned long *colormasks; +chainout_status_update( + void *vp, + int idx, + genericptr_t ptr, + int chg, + int percent, + int color, + unsigned long *colormasks) { struct chainout_data *tdp = vp; @@ -632,8 +670,7 @@ unsigned long *colormasks; } boolean -chainout_can_suspend(vp) -void *vp; +chainout_can_suspend(void *vp) { struct chainout_data *tdp = vp; boolean rv; @@ -643,9 +680,25 @@ void *vp; return rv; } +win_request_info * +chainout_ctrl_nhwindow( + void *vp, + winid window, + int request, + win_request_info *wri) +{ + struct chainout_data *tdp = vp; + win_request_info *rv; + + rv = (*tdp->nprocs->win_ctrl_nhwindow)(window, + request, wri); + return rv; +} + struct chain_procs chainout_procs = { - "-chainout", 0, /* wincap */ + WPIDMINUS(chainout), 0, /* wincap */ 0, /* wincap2 */ + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ /* XXX problem - the above need to come from the real window port, possibly modified. May need to do something to call an additional init fn later @@ -661,7 +714,8 @@ struct chain_procs chainout_procs = { chainout_destroy_nhwindow, chainout_curs, chainout_putstr, chainout_putmixed, chainout_display_file, chainout_start_menu, chainout_add_menu, chainout_end_menu, chainout_select_menu, - chainout_message_menu, chainout_update_inventory, chainout_mark_synch, + chainout_message_menu, + chainout_mark_synch, chainout_wait_synch, #ifdef CLIPPING chainout_cliparound, @@ -681,11 +735,11 @@ struct chain_procs chainout_procs = { chainout_get_color_string, #endif - chainout_start_screen, chainout_end_screen, - chainout_outrip, chainout_preference_update, chainout_getmsghistory, chainout_putmsghistory, chainout_status_init, chainout_status_finish, chainout_status_enablefield, chainout_status_update, chainout_can_suspend, + chainout_update_inventory, + chainout_ctrl_nhwindow, }; diff --git a/win/chain/wc_trace.c b/win/chain/wc_trace.c index 6da9a9b83..936bcf26f 100644 --- a/win/chain/wc_trace.c +++ b/win/chain/wc_trace.c @@ -1,16 +1,22 @@ -/* NetHack 3.6 wc_trace.c $NHDT-Date: 1501464799 2017/07/31 01:33:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.8 $ */ -/* Copyright (c) Kenneth Lorber, 2012 */ +/* NetHack 5.0 wc_trace.c $NHDT-Date: 1596498324 2020/08/03 23:45:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ +/* Copyright (c) Kenneth Lorber, 2012 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "wintty.h" #include "func_tab.h" -#include #include -FILE *wc_tracelogf; /* Should be static, but it's just too useful to have - * access to this logfile from arbitrary other files. */ +#ifdef WIN32 +long getpid(void); +long +getpid(){ + return 0; +} +#endif + +FILE *wc_tracelogf; static unsigned int indent_level; /* Some winfuncs call other winfuncs, so * we need to support nesting. */ @@ -33,6 +39,76 @@ static char indentdata[10] = " "; #define PRE indent_level++ #define POST indent_level-- +void trace_init_nhwindows(void *,int *, char **); +void trace_player_selection(void *); +void trace_askname(void *); +void trace_get_nh_event(void *); +void trace_exit_nhwindows(void *,const char *); +void trace_suspend_nhwindows(void *,const char *); +void trace_resume_nhwindows(void *); +winid trace_create_nhwindow(void *,int); +void trace_clear_nhwindow(void *,winid); +void trace_display_nhwindow(void *,winid, boolean); +void trace_destroy_nhwindow(void *,winid); +void trace_curs(void *,winid, int, int); +void trace_putstr(void *,winid, int, const char *); +void trace_putmixed(void *,winid, int, const char *); +void trace_display_file(void *,const char *, boolean); +void trace_start_menu(void *,winid, unsigned long); +void trace_add_menu(void *,winid, const glyph_info *, const ANY_P *, + char, char, int, int, + const char *, unsigned int); +void trace_end_menu(void *,winid, const char *); +int trace_select_menu(void *,winid, int, MENU_ITEM_P **); +char trace_message_menu(void *,char, int, const char *); +void trace_mark_synch(void *); +void trace_wait_synch(void *); +#ifdef CLIPPING +void trace_cliparound(void *,int, int); +#endif +#ifdef POSITIONBAR +void trace_update_positionbar(void *,char *); +#endif +void trace_print_glyph(void *,winid, coordxy, coordxy, + const glyph_info *, const glyph_info *); +void trace_raw_print(void *,const char *); +void trace_raw_print_bold(void *,const char *); +int trace_nhgetch(void *); +int trace_nh_poskey(void *,coordxy *, coordxy *, int *); +void trace_nhbell(void *); +int trace_doprev_message(void *); +char trace_yn_function(void *,const char *, const char *, char); +void trace_getlin(void *,const char *, char *); +int trace_get_ext_cmd(void *); +void trace_number_pad(void *,int); +void trace_delay_output(void *); +#ifdef CHANGE_COLOR +void trace_change_color(void *,int, long, int); +#ifdef MAC +void trace_change_background(void *,int); +short trace_set_font_name(void *,winid, char *); +#endif +char *trace_get_color_string(void *); +#endif + +void trace_outrip(void *,winid, int, time_t); +void trace_preference_update(void *,const char *); +char *trace_getmsghistory(void *,boolean); +void trace_putmsghistory(void *,const char *, boolean); +void trace_status_init(void *); +void trace_status_finish(void *); +void trace_status_enablefield(void *,int, const char *, const char *, + boolean); +void trace_status_update(void *,int, genericptr_t, int, int, int, + unsigned long *); + +boolean trace_can_suspend(void *); +void trace_update_inventory(void *,int); +win_request_info *trace_ctrl_nhwindow(void *, winid, int, win_request_info *); + +void trace_procs_init(int dir); +void *trace_procs_chain(int cmd, int n, void *me, void *nextprocs, void *nextdata); + struct trace_data { struct chain_procs *nprocs; void *ndata; @@ -41,12 +117,12 @@ struct trace_data { }; void * -trace_procs_chain(cmd, n, me, nextprocs, nextdata) -int cmd; -int n; -void *me; -void *nextprocs; -void *nextdata; +trace_procs_chain( + int cmd, + int n, + void *me, + void *nextprocs, + void *nextdata) { struct trace_data *tdp = 0; @@ -70,10 +146,9 @@ void *nextdata; } void -trace_procs_init(dir) -int dir; +trace_procs_init(int dir) { - char fname[200]; + char tfile[20]; long pid; /* processors shouldn't need this test, but just in case */ @@ -81,8 +156,14 @@ int dir; return; pid = (long) getpid(); - Sprintf(fname, "%s/tlog.%ld", HACKDIR, pid); + + Sprintf(tfile, "tlog.%ld", pid); +// XXX FQN_NUMBUF is private to files.c + const char *fname = fqname(tfile, TROUBLEPREFIX,7); + printf("TRACEFILE: %s\n",fname); + fflush(stdout); wc_tracelogf = fopen(fname, "w"); + (void)setvbuf(wc_tracelogf, NULL, _IONBF, 0); if (!wc_tracelogf) { fprintf(stderr, "Can't open trace log file %s: %s\n", fname, strerror(errno)); @@ -99,10 +180,10 @@ int dir; ***/ void -trace_init_nhwindows(vp, argcp, argv) -void *vp; -int *argcp; -char **argv; +trace_init_nhwindows( + void *vp, + int *argcp, + char **argv) { struct trace_data *tdp = vp; @@ -114,8 +195,7 @@ char **argv; } void -trace_player_selection(vp) -void *vp; +trace_player_selection(void *vp) { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%splayer_selection()\n", INDENT); @@ -126,8 +206,7 @@ void *vp; } void -trace_askname(vp) -void *vp; +trace_askname(void *vp) { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%saskname()\n", INDENT); @@ -138,8 +217,7 @@ void *vp; } void -trace_get_nh_event(vp) -void *vp; +trace_get_nh_event(void *vp) { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sget_nh_event()\n", INDENT); @@ -150,9 +228,9 @@ void *vp; } void -trace_exit_nhwindows(vp, str) -void *vp; -const char *str; +trace_exit_nhwindows( + void *vp, + const char *str) { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sexit_nhwindows(%s)\n", INDENT, str); @@ -163,9 +241,9 @@ const char *str; } void -trace_suspend_nhwindows(vp, str) -void *vp; -const char *str; +trace_suspend_nhwindows( + void *vp, + const char *str) { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%ssuspend_nhwindows(%s)\n", INDENT, str); @@ -176,8 +254,7 @@ const char *str; } void -trace_resume_nhwindows(vp) -void *vp; +trace_resume_nhwindows(void *vp) { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sresume_nhwindows()\n", INDENT); @@ -188,8 +265,7 @@ void *vp; } static const char * -NHWname(type) -int type; +NHWname(int type) { switch (type) { case NHW_MESSAGE: @@ -213,9 +289,9 @@ int type; } winid -trace_create_nhwindow(vp, type) -void *vp; -int type; +trace_create_nhwindow( + void *vp, + int type) { struct trace_data *tdp = vp; const char *typestring = NHWname(type); @@ -232,9 +308,9 @@ int type; } void -trace_clear_nhwindow(vp, window) -void *vp; -winid window; +trace_clear_nhwindow( + void *vp, + winid window) { struct trace_data *tdp = vp; @@ -246,10 +322,10 @@ winid window; } void -trace_display_nhwindow(vp, window, blocking) -void *vp; -winid window; -BOOLEAN_P blocking; +trace_display_nhwindow( + void *vp, + winid window, + boolean blocking) { struct trace_data *tdp = vp; @@ -262,9 +338,9 @@ BOOLEAN_P blocking; } void -trace_destroy_nhwindow(vp, window) -void *vp; -winid window; +trace_destroy_nhwindow( + void *vp, + winid window) { struct trace_data *tdp = vp; @@ -276,11 +352,11 @@ winid window; } void -trace_curs(vp, window, x, y) -void *vp; -winid window; -int x; -int y; +trace_curs( + void *vp, + winid window, + int x, + int y) { struct trace_data *tdp = vp; @@ -292,11 +368,11 @@ int y; } void -trace_putstr(vp, window, attr, str) -void *vp; -winid window; -int attr; -const char *str; +trace_putstr( + void *vp, + winid window, + int attr, + const char *str) { struct trace_data *tdp = vp; @@ -314,11 +390,11 @@ const char *str; } void -trace_putmixed(vp, window, attr, str) -void *vp; -winid window; -int attr; -const char *str; +trace_putmixed( + void *vp, + winid window, + int attr, + const char *str) { struct trace_data *tdp = vp; @@ -336,10 +412,10 @@ const char *str; } void -trace_display_file(vp, fname, complain) -void *vp; -const char *fname; -boolean complain; +trace_display_file( + void *vp, + const char *fname, + boolean complain) { struct trace_data *tdp = vp; @@ -356,30 +432,33 @@ boolean complain; } void -trace_start_menu(vp, window) -void *vp; -winid window; +trace_start_menu( + void *vp, + winid window, + unsigned long mbehavior) { struct trace_data *tdp = vp; - fprintf(wc_tracelogf, "%sstart_menu(%d)\n", INDENT, window); + fprintf(wc_tracelogf, "%sstart_menu(%d, %lu)\n", INDENT, + window, mbehavior); PRE; - (*tdp->nprocs->win_start_menu)(tdp->ndata, window); + (*tdp->nprocs->win_start_menu)(tdp->ndata, window, mbehavior); POST; } void -trace_add_menu(vp, window, glyph, identifier, ch, gch, attr, str, preselected) -void *vp; -winid window; /* window to use, must be of type NHW_MENU */ -int glyph; /* glyph to display with item (unused) */ -const anything *identifier; /* what to return if selected */ -char ch; /* keyboard accelerator (0 = pick our own) */ -char gch; /* group accelerator (0 = no group) */ -int attr; /* attribute for string (like tty_putstr()) */ -const char *str; /* menu string */ -boolean preselected; /* item is marked as selected */ +trace_add_menu( + void *vp, + winid window, /* window to use, must be of type NHW_MENU */ + const glyph_info *glyphinfo, /* glyph plus glyph info to display with item */ + const anything *identifier, /* what to return if selected */ + char ch, /* keyboard accelerator (0 = pick our own) */ + char gch, /* group accelerator (0 = no group) */ + int attr, /* attribute for string (like tty_putstr()) */ + int clr, /* color for string */ + const char *str, /* menu string */ + unsigned int itemflags) /* itemflags such as marked as selected */ { struct trace_data *tdp = vp; @@ -400,27 +479,27 @@ boolean preselected; /* item is marked as selected */ if (str) { fprintf(wc_tracelogf, - "%sadd_menu(%d, %d, %p, %s, %s, %d, '%s'(%d), %d)\n", INDENT, - window, glyph, (void *) identifier, buf_ch, buf_gch, attr, - str, (int) strlen(str), preselected); + "%sadd_menu(%d, %d, %u, %p, %s, %s, %d, '%s'(%d), %u)\n", INDENT, + window, glyphinfo->glyph, glyphinfo->gm.glyphflags, (void *) identifier, + buf_ch, buf_gch, attr, str, (int) strlen(str), itemflags); } else { fprintf(wc_tracelogf, - "%sadd_menu(%d, %d, %p, %s, %s, %d, NULL, %d)\n", INDENT, - window, glyph, (void *) identifier, buf_ch, buf_gch, attr, - preselected); + "%sadd_menu(%d, %d, %u, %p, %s, %s, %d, NULL, %u)\n", INDENT, + window, glyphinfo->glyph, glyphinfo->gm.glyphflags, (void *) identifier, + buf_ch, buf_gch, attr, itemflags); } PRE; - (*tdp->nprocs->win_add_menu)(tdp->ndata, window, glyph, identifier, ch, - gch, attr, str, preselected); + (*tdp->nprocs->win_add_menu)(tdp->ndata, window, glyphinfo, + identifier,ch, gch, attr, clr, str, itemflags); POST; } void -trace_end_menu(vp, window, prompt) -void *vp; -winid window; -const char *prompt; +trace_end_menu( + void *vp, + winid window, + const char *prompt) { struct trace_data *tdp = vp; @@ -437,11 +516,11 @@ const char *prompt; } int -trace_select_menu(vp, window, how, menu_list) -void *vp; -winid window; -int how; -menu_item **menu_list; +trace_select_menu( + void *vp, + winid window, + int how, + menu_item **menu_list) { struct trace_data *tdp = vp; int rv; @@ -459,11 +538,11 @@ menu_item **menu_list; } char -trace_message_menu(vp, let, how, mesg) -void *vp; -char let; -int how; -const char *mesg; +trace_message_menu( + void *vp, + char let, + int how, + const char *mesg) { struct trace_data *tdp = vp; char buf_let[10]; @@ -498,21 +577,29 @@ const char *mesg; } void -trace_update_inventory(vp) -void *vp; +trace_update_inventory(void *vp, int arg) { struct trace_data *tdp = vp; - fprintf(wc_tracelogf, "%supdate_inventory()\n", INDENT); + fprintf(wc_tracelogf, "%supdate_inventory(%d)\n", INDENT, arg); PRE; - (*tdp->nprocs->win_update_inventory)(tdp->ndata); + (*tdp->nprocs->win_update_inventory)(tdp->ndata, arg); + POST; +} + +win_request_info * +trace_ctrl_nhwindow(void *vp, winid w, int request, win_request_info *wri){ + struct trace_data *tdp = vp; + + fprintf(wc_tracelogf, "%sctrl_nhwindow(%d, %d, %p)\n", INDENT, w, request, wri); + PRE; + (*tdp->nprocs->win_ctrl_nhwindow)(tdp->ndata, w, request, wri); POST; } void -trace_mark_synch(vp) -void *vp; +trace_mark_synch(void *vp) { struct trace_data *tdp = vp; @@ -524,8 +611,7 @@ void *vp; } void -trace_wait_synch(vp) -void *vp; +trace_wait_synch(void *vp) { struct trace_data *tdp = vp; @@ -538,10 +624,10 @@ void *vp; #ifdef CLIPPING void -trace_cliparound(vp, x, y) -void *vp; -int x; -int y; +trace_cliparound( + void *vp, + int x, + int y) { struct trace_data *tdp = vp; @@ -555,9 +641,9 @@ int y; #ifdef POSITIONBAR void -trace_update_positionbar(vp, posbar) -void *vp; -char *posbar; +trace_update_positionbar( + void *vp, + char *posbar) { struct trace_data *tdp = vp; @@ -573,29 +659,31 @@ char *posbar; } #endif -/* XXX can we decode the glyph in a meaningful way? see mapglyph()? +/* XXX can we decode the glyph in a meaningful way? see map_glyphinfo()? genl_putmixed? */ void -trace_print_glyph(vp, window, x, y, glyph, bkglyph) -void *vp; -winid window; -xchar x, y; -int glyph, bkglyph; +trace_print_glyph( + void *vp, + winid window, + coordxy x, + coordxy y, + const glyph_info *glyphinfo, + const glyph_info *bkglyphinfo) { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sprint_glyph(%d, %d, %d, %d, %d)\n", INDENT, window, - x, y, glyph, bkglyph); + x, y, glyphinfo->glyph, bkglyphinfo->glyph); PRE; - (*tdp->nprocs->win_print_glyph)(tdp->ndata, window, x, y, glyph, bkglyph); + (*tdp->nprocs->win_print_glyph)(tdp->ndata, window, x, y, glyphinfo, bkglyphinfo); POST; } void -trace_raw_print(vp, str) -void *vp; -const char *str; +trace_raw_print( + void *vp, + const char *str) { struct trace_data *tdp = vp; @@ -612,9 +700,9 @@ const char *str; } void -trace_raw_print_bold(vp, str) -void *vp; -const char *str; +trace_raw_print_bold( + void *vp, + const char *str) { struct trace_data *tdp = vp; @@ -631,8 +719,7 @@ const char *str; } int -trace_nhgetch(vp) -void *vp; +trace_nhgetch(void *vp) { struct trace_data *tdp = vp; int rv; @@ -655,11 +742,11 @@ void *vp; } int -trace_nh_poskey(vp, x, y, mod) -void *vp; -int *x; -int *y; -int *mod; +trace_nh_poskey( + void *vp, + coordxy *x, + coordxy *y, + int *mod) { struct trace_data *tdp = vp; int rv; @@ -675,15 +762,15 @@ int *mod; } else { sprintf(buf, "(%d)", rv); } - fprintf(wc_tracelogf, "%s=> %s (%d, %d, %d)\n", INDENT, buf, *x, *y, + fprintf(wc_tracelogf, "%s=> %s (%d, %d, %d)\n", INDENT, buf, + (int) *x, (int) *y, *mod); return rv; } void -trace_nhbell(vp) -void *vp; +trace_nhbell(void *vp) { struct trace_data *tdp = vp; @@ -695,8 +782,7 @@ void *vp; } int -trace_doprev_message(vp) -void *vp; +trace_doprev_message(void *vp) { struct trace_data *tdp = vp; int rv; @@ -713,10 +799,11 @@ void *vp; } char -trace_yn_function(vp, query, resp, def) -void *vp; -const char *query, *resp; -char def; +trace_yn_function( + void *vp, + const char *query, + const char *resp, + char def) { struct trace_data *tdp = vp; char rv; @@ -759,10 +846,10 @@ char def; } void -trace_getlin(vp, query, bufp) -void *vp; -const char *query; -char *bufp; +trace_getlin( + void *vp, + const char *query, + char *bufp) { struct trace_data *tdp = vp; @@ -785,8 +872,7 @@ char *bufp; } int -trace_get_ext_cmd(vp) -void *vp; +trace_get_ext_cmd(void *vp) { struct trace_data *tdp = vp; int rv; @@ -814,9 +900,9 @@ void *vp; } void -trace_number_pad(vp, state) -void *vp; -int state; +trace_number_pad( + void *vp, + int state) { struct trace_data *tdp = vp; @@ -828,8 +914,7 @@ int state; } void -trace_delay_output(vp) -void *vp; +trace_delay_output(void *vp) { struct trace_data *tdp = vp; @@ -842,11 +927,11 @@ void *vp; #ifdef CHANGE_COLOR void -trace_change_color(vp, color, value, reverse) -void *vp; -int color; -long value; -int reverse; +trace_change_color( + void *vp, + int color, + long value, + int reverse) { struct trace_data *tdp = vp; @@ -860,9 +945,9 @@ int reverse; #ifdef MAC void -trace_change_background(vp, bw) -void *vp; -int bw; +trace_change_background( + void *vp, + int bw) { struct trace_data *tdp = vp; @@ -874,10 +959,10 @@ int bw; } short -trace_set_font_name(vp, window, font) -void *vp; -winid window; -char *font; +trace_set_font_name( + void *vp, + winid window, + char *font) { struct trace_data *tdp = vp; short rv; @@ -900,8 +985,7 @@ char *font; #endif char * -trace_get_color_string(vp) -void *vp; +trace_get_color_string(void *vp) { struct trace_data *tdp = vp; char *rv; @@ -924,39 +1008,12 @@ void *vp; #endif -/* other defs that really should go away (they're tty specific) */ -void -trace_start_screen(vp) -void *vp; -{ - struct trace_data *tdp = vp; - - fprintf(wc_tracelogf, "%sstart_screen()\n", INDENT); - - PRE; - (*tdp->nprocs->win_start_screen)(tdp->ndata); - POST; -} - void -trace_end_screen(vp) -void *vp; -{ - struct trace_data *tdp = vp; - - fprintf(wc_tracelogf, "%send_screen()\n", INDENT); - - PRE; - (*tdp->nprocs->win_end_screen)(tdp->ndata); - POST; -} - -void -trace_outrip(vp, tmpwin, how, when) -void *vp; -winid tmpwin; -int how; -time_t when; +trace_outrip( + void *vp, + winid tmpwin, + int how, + time_t when) { struct trace_data *tdp = vp; @@ -969,9 +1026,9 @@ time_t when; } void -trace_preference_update(vp, pref) -void *vp; -const char *pref; +trace_preference_update( + void *vp, + const char *pref) { struct trace_data *tdp = vp; @@ -988,9 +1045,9 @@ const char *pref; } char * -trace_getmsghistory(vp, init) -void *vp; -boolean init; +trace_getmsghistory( + void *vp, + boolean init) { struct trace_data *tdp = vp; char *rv; @@ -1012,10 +1069,10 @@ boolean init; } void -trace_putmsghistory(vp, msg, is_restoring) -void *vp; -const char *msg; -boolean is_restoring; +trace_putmsghistory( + void *vp, + const char *msg, + boolean is_restoring) { struct trace_data *tdp = vp; @@ -1033,8 +1090,7 @@ boolean is_restoring; } void -trace_status_init(vp) -void *vp; +trace_status_init(void *vp) { struct trace_data *tdp = vp; @@ -1046,8 +1102,7 @@ void *vp; } void -trace_status_finish(vp) -void *vp; +trace_status_finish(void *vp) { struct trace_data *tdp = vp; @@ -1059,12 +1114,12 @@ void *vp; } void -trace_status_enablefield(vp, fieldidx, nm, fmt, enable) -void *vp; -int fieldidx; -const char *nm; -const char *fmt; -boolean enable; +trace_status_enablefield( + void *vp, + int fieldidx, + const char *nm, + const char *fmt, + boolean enable) { struct trace_data *tdp = vp; @@ -1088,11 +1143,14 @@ boolean enable; } void -trace_status_update(vp, idx, ptr, chg, percent, color, colormasks) -void *vp; -int idx, chg, percent, color; -genericptr_t ptr; -unsigned long *colormasks; +trace_status_update( + void *vp, + int idx, + genericptr_t ptr, + int chg, + int percent, + int color, + unsigned long *colormasks) { struct trace_data *tdp = vp; @@ -1106,8 +1164,7 @@ unsigned long *colormasks; } boolean -trace_can_suspend(vp) -void *vp; +trace_can_suspend(void *vp) { struct trace_data *tdp = vp; boolean rv; @@ -1124,8 +1181,10 @@ void *vp; } struct chain_procs trace_procs = { - "+trace", 0, /* wincap */ + "+trace", wp_trace, + 0, /* wincap */ 0, /* wincap2 */ + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ /* XXX problem - the above need to come from the real window port, possibly modified. May need to do something to call an additional init fn later @@ -1139,7 +1198,7 @@ struct chain_procs trace_procs = { trace_create_nhwindow, trace_clear_nhwindow, trace_display_nhwindow, trace_destroy_nhwindow, trace_curs, trace_putstr, trace_putmixed, trace_display_file, trace_start_menu, trace_add_menu, trace_end_menu, - trace_select_menu, trace_message_menu, trace_update_inventory, + trace_select_menu, trace_message_menu, trace_mark_synch, trace_wait_synch, #ifdef CLIPPING trace_cliparound, @@ -1158,11 +1217,11 @@ struct chain_procs trace_procs = { trace_get_color_string, #endif - trace_start_screen, trace_end_screen, - trace_outrip, trace_preference_update, trace_getmsghistory, trace_putmsghistory, trace_status_init, trace_status_finish, trace_status_enablefield, trace_status_update, trace_can_suspend, + trace_update_inventory, + trace_ctrl_nhwindow }; diff --git a/win/curses/Readme.txt b/win/curses/Readme.txt index f9c95fdef..1cec52e6e 100644 --- a/win/curses/Readme.txt +++ b/win/curses/Readme.txt @@ -3,9 +3,9 @@ INTRO The "curses" windowport is a new text-based interface for NetHack, using high-level curses routines to control the display. Currently, it -has been compiled and tested on Linux and Windows, but it should also -be portable to a number of other systems, such as other forms of UNIX, -Mac OS X, MSDOS, and OS/2. +has been compiled and tested on Linux, macOS, Windows, and msdos, but it +should also be portable to a number of other systems, such as other +forms of UNIX and OS/2. Some features of this interface compared to the traditional tty interface include: @@ -22,26 +22,26 @@ interface include: BUILDING ======== -As of this writing code has been compiled on Linux and Windows. +UNIX/Linux/macOS build instructions: -UNIX/Linux build instructions: Follow the instructions in +Follow the instructions in sys/unix/Install.unx. By default, the Makefile is setup to compile against ncurses. Edit Makefile.src if you wish to compile against a different curses library, such as PDCurses for SDL. +See sys/unix/NewInstall.unx for more information about building +NetHack 5.0 and above. -Windows build instructions: If you are using Mingw32 as your compiler, -then follow the instructions in sys/winnt/Install.nt with the following -changes: +Windows build instructions: - * After running nhsetup, manually copy the file cursmake.gcc to the - src/ subdirectory - * Instead of typing "mingw32-make -f Makefile.gcc install" you will - type "mingw32-make -f cursmake.gcc install" +By default, the Makefile.nmake and GNUmakefile are set up to build +curses from the submodules/pdcurses submodules folder (assumes you +obtained your NetHack sources via cloning a git repository), +If you obtained your NetHack by another means, such as a zip download, +follow the instructions in sys/windows/Install.windows. If you are using a different compiler, you will have to manually modify the appropriate Makefile to include the curses windowport files. - GAMEPLAY ======== @@ -50,11 +50,11 @@ differences are primarily visual. This windowport supports dymanic resizing of the terminal window, so you can play with it to see how it looks best to you during a game. Also, the align_status and align_message options may be set during the game, so you can experiment -to see what arraingement looks best to you. +to see what arrangement looks best to you. For menus, in addition to the normal configurable keybindings for menu navigation descrived in the Guidebook, you can use the right and left -arrows to to forward or backward one page, respectively, and the home +arrows to forward or backward one page, respectively, and the home and end keys to go to the first and last pages, respectively. Some configuration options that are specific to or relevant to the @@ -105,7 +105,7 @@ CONTACT Please send any bug reports, suggestions, patches, or miscellaneous feedback to me (Karl Garrison) at: kgarrison@pobox.com. Note that as -of this writing, I only have sporatic Internet access, so I may not get +of this writing, I only have sporadic Internet access, so I may not get back to you right away. Happy Hacking! diff --git a/win/curses/Todo.txt b/win/curses/Todo.txt index b92327790..552ddbf57 100644 --- a/win/curses/Todo.txt +++ b/win/curses/Todo.txt @@ -8,7 +8,7 @@ NETHACK INTERFACE * Implement curses_rip for optional fancier color tombstone, as well as one that will display correctly on smaller terminals. - * I am confused as to how mark_synch, wait_synch, and delay_output + * I am confused as to how mark_synch, wait_synch, and nh_delay_output should work. Help, please? * Both PDCurses and Ncurses have mouse support, so the poskey function @@ -34,9 +34,9 @@ DISPLAY PDCurses, however. * Animation effects do not display properly - this could probably be - fixed with a correct implementation of the delay_output function. + fixed with a correct implementation of the curses_delay_output function. - * Support option to set forground and background colors for individual + * Support option to set foreground and background colors for individual windows @@ -45,7 +45,7 @@ MENUS (cursdial.c) - * Menus need to be able to accept a count as input, e.g. to specifiy + * Menus need to be able to accept a count as input, e.g. to specify how many items to drop. * Currently the "preselected" flag for an individual menu item is @@ -79,7 +79,7 @@ MAP WINDOW * The map window would probably benefit from a total redesign. Right now, it uses a pad instead of a regular curses window, which causes a - number of special cases in the code to account for it, and a seperate + number of special cases in the code to account for it, and a separate window behind it just to draw the border. It feels kludgy and annoying! @@ -95,7 +95,7 @@ STATUS WINDOW Gnomish Mines) and perhaps show thermometer bars for hit points and magical power. - * Conversely, if we have a narrower dislay, compress some of the + * Conversely, if we have a narrower display, compress some of the labels to save space, and do not display some items that never or rarely change (e.g. name, level and title, and alignment). Perhaps display changes to these fields in the message window if they do @@ -122,9 +122,8 @@ OTHER DIALOGS OTHER PLATFORMS =============== - * PDCurses also work on DOS and OS/2. PDCurses for SDL and ncurses - exist for Mac OS X. Porting the curses interface to these platforms - should not be too difficult. + * PDCurses also work on DOS and OS/2. Porting the curses interface to + these platforms should not be too difficult. MISC @@ -133,7 +132,7 @@ MISC * Update documentation and in-game help to describe the newly-added options: cursesgraphics, term_rows, term_cols, and windowborders. - * Recognize "Alt" key in a platform-independant way to allow its use + * Recognize "Alt" key in a platform-independent way to allow its use to select extended commands. Currently this works for PDCurses. For Ncurses, the Alt key works in an xterm or rxvt if the -meta8 flag is passed, but I'd like to see a general way of detecting it. diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 7858ee618..b317c8543 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -1,14 +1,16 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursdial.c */ +/* NetHack 5.0 cursdial.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ #include "curses.h" #include "hack.h" #include "wincurs.h" +#include "cursinit.h" +#include "curswins.h" +#include "cursmisc.h" #include "cursdial.h" #include "func_tab.h" -#include #if defined(FILENAME_CMP) && !defined(strcasecmp) #define strcasecmp FILENAME_CMP @@ -21,51 +23,24 @@ set up by curses_init_nhwindows() */ extern char erase_char, kill_char; -/* - * Note: - * - * Prototypes need to use the widened/unwidened type macros (CHAR_P, &c) - * in order to match fields of the window_procs struct (see winprocs.h). - * But for a standard-conforming compiler, we'll end up with the widened - * types necessary to match the mixed prototype/old-style function - * definition environment as used by nethack's core. Prototype -int func(CHAR_P); - * becomes -int func(int); - * after expansion, which matches the definition -int func(arg) char arg; { ... } - * according to the rules of the C standard. But the use of new-style - * definitions -int func(char arg) { ... } - * by the curses interface turns that into a conflict. No widening takes - * place so it ought to be 'int func(char);' instead. Unfortunately that - * would be incompatible for functions assigned to window_procs. - * - * So, the code here (also cursmain.c and cursinvt.c) is mis-using the - * widening macros for variable types -int func(CHAR_P arg) { ... } - * (no doubt modelling it after the C++ code in win/Qt where the option - * to switch the applicable definitions to old-style isn't available). - * Other alternatives aren't significantly better so just live with it. - * [Redoing the windowing interface to avoid narrow arguments would be - * better since that would fix Qt's usage too.] - */ - /* Dialog windows for curses interface */ +WINDOW *activemenu = NULL; /* for count_window refresh handling */ /* Private declarations */ typedef struct nhmi { winid wid; /* NetHack window id */ - int glyph; /* Menu glyphs */ + glyph_info glyphinfo; /* holds menu glyph and additional info */ anything identifier; /* Value returned if item selected */ - CHAR_P accelerator; /* Character used to select item from menu */ - CHAR_P group_accel; /* Group accelerator for menu item, if any */ + char accelerator; /* Character used to select item from menu */ + char group_accel; /* Group accelerator for menu item, if any */ int attr; /* Text attributes for item */ + int color; /* Color for item */ const char *str; /* Text of menu item */ - BOOLEAN_P presel; /* Whether menu item should be preselected */ + boolean presel; /* Whether menu item should be preselected */ boolean selected; /* Whether item is currently selected */ + unsigned itemflags; int page_num; /* Display page number for entry */ int line_num; /* Line number on page where entry begins */ int num_lines; /* Number of lines entry uses on page */ @@ -79,13 +54,15 @@ typedef struct nhm { const char *prompt; /* Menu prompt text */ nhmenu_item *entries; /* Menu entries */ int num_entries; /* Number of menu entries */ - int num_pages; /* Number of display pages for entry */ + int num_pages; /* Number of display pages for menu */ int height; /* Window height of menu */ int width; /* Window width of menu */ + unsigned long mbehavior; /* menu flags */ boolean reuse_accels; /* Non-unique accelerators per page */ boolean bottom_heavy; /* display multi-page menu starting at end */ - struct nhm *prev_menu; /* Pointer to previous entry */ - struct nhm *next_menu; /* Pointer to next entry */ + boolean show_obj_syms; /* handle iflags.menuobjsyms */ + struct nhm *prev_menu; /* Pointer to previous menu */ + struct nhm *next_menu; /* Pointer to next menu */ } nhmenu; typedef enum menu_op_type { @@ -94,21 +71,27 @@ typedef enum menu_op_type { INVERT } menu_op; -static nhmenu_item *curs_new_menu_item(winid, const char *); -static void curs_pad_menu(nhmenu *, boolean); -static nhmenu *get_menu(winid wid); +static nhmenu_item *curs_new_menu_item(winid, const char *) NONNULL; +static void curs_pad_menu(nhmenu *, boolean) NONNULLARG1; +static nhmenu *get_menu(winid wid); /* might return Null */ static char menu_get_accel(boolean first); -static void menu_determine_pages(nhmenu *menu); -static boolean menu_is_multipage(nhmenu *menu, int width, int height); -static void menu_win_size(nhmenu *menu); -static void menu_display_page(nhmenu *menu, WINDOW * win, int page_num, - char *); -static int menu_get_selections(WINDOW * win, nhmenu *menu, int how); -static void menu_select_deselect(WINDOW * win, nhmenu_item *item, - menu_op operation, int); -static int menu_operation(WINDOW * win, nhmenu *menu, menu_op operation, - int page_num); -static void menu_clear_selections(nhmenu *menu); +static void menu_determine_pages(nhmenu *menu) NONNULLARG1; +static boolean menu_is_multipage(nhmenu *menu, int width, + int height) NONNULLARG1; +static void menu_win_size(nhmenu *menu) NONNULLARG1; +#ifdef NCURSES_MOUSE_VERSION +static nhmenu_item *get_menuitem_y(WINDOW *win UNUSED, nhmenu *menu, + int page_num, int liney) NONNULLARG12; +#endif /*NCURSES_MOUSE_VERSION*/ +static void menu_display_page(WINDOW *win, nhmenu *menu, int page_num, + char *, char *) NONNULLARG12; +static int menu_get_selections(WINDOW *win, nhmenu *menu, + int how) NONNULLARG12; +static void menu_select_deselect(WINDOW *win, nhmenu_item *item, + menu_op operation, int) NONNULLARG12; +static int menu_operation(WINDOW *win, nhmenu *menu, menu_op operation, + int page_num) NONNULLARG12; +static void menu_clear_selections(nhmenu *menu) NONNULLARG1; static int menu_max_height(void); static nhmenu *nhmenus = NULL; /* NetHack menu array */ @@ -124,12 +107,16 @@ static nhmenu *nhmenus = NULL; /* NetHack menu array */ or a wish. Note: EDIT_GETLIN not supported for popup prompting. */ void -curses_line_input_dialog(const char *prompt, char *answer, int buffer) +curses_line_input_dialog( + const char *prompt, + char *answer, + int buffer) { int map_height, map_width, maxwidth, remaining_buf, winx, winy, count; WINDOW *askwin, *bwin; char *tmpstr; - int prompt_width, prompt_height = 1, height = prompt_height; + int prompt_width, prompt_height = 1, height = prompt_height, + answerx = 0, answery = 0, trylim; char input[BUFSZ]; /* if messages were being suppressed for the remainder of the turn, @@ -167,8 +154,9 @@ curses_line_input_dialog(const char *prompt, char *answer, int buffer) free(tmpstr); } - bwin = curses_create_window(prompt_width, height, + bwin = curses_create_window(TEXT_WIN, prompt_width, height, iflags.window_inited ? UP : CENTER); + curses_set_wid_colors(TEXT_WIN, bwin); wrefresh(bwin); getbegyx(bwin, winy, winx); askwin = newwin(height, prompt_width, winy + 1, winx + 1); @@ -183,11 +171,28 @@ curses_line_input_dialog(const char *prompt, char *answer, int buffer) wmove(askwin, count + 1, 0); } free(tmpstr); + /* remember where user's typed response will start, in case we + need to re-prompt */ + getyx(askwin, answery, answerx); } echo(); curs_set(1); - wgetnstr(askwin, input, buffer - 1); + trylim = 10; + do { + /* move and clear are only needed for 2nd and subsequent passes */ + wmove(askwin, answery, answerx); + wclrtoeol(askwin); + + wgetnstr(askwin, input, buffer - 1); + /* ESC after some input kills that input and tries again; + ESC at the start cancels, leaving ESC in the result buffer. + [Note: wgetnstr() treats as an ordinary character + so user has to type for it to behave the + way we want it to.] */ + if (input[0] != '\033' && strchr(input, '\033') != 0) + input[0] = '\0'; + } while (--trylim > 0 && !input[0]); curs_set(0); Strcpy(answer, input); werase(bwin); @@ -200,8 +205,10 @@ curses_line_input_dialog(const char *prompt, char *answer, int buffer) /* Get a single character response from the player, such as a y/n prompt */ int -curses_character_input_dialog(const char *prompt, const char *choices, - CHAR_P def) +curses_character_input_dialog( + const char *prompt, + const char *choices, + char def) { WINDOW *askwin = NULL; #ifdef PDCURSES @@ -220,7 +227,7 @@ curses_character_input_dialog(const char *prompt, const char *choices, re-activate them now that input is being requested */ curses_got_input(); - if (invent || (moves > 1)) { + if (svm.moves > 0) { curses_get_window_size(MAP_WIN, &map_height, &map_width); } else { map_height = term_rows; @@ -247,7 +254,7 @@ curses_character_input_dialog(const char *prompt, const char *choices, choicestr[count + 2] = choices[count]; } choicestr[count + 2] = ']'; - if (((def >= 'A') && (def <= 'Z')) || ((def >= 'a') && (def <= 'z'))) { + if ((def >= 'A' && def <= 'Z') || (def >= 'a' && def <= 'z')) { choicestr[count + 3] = ' '; choicestr[count + 4] = '('; choicestr[count + 5] = def; @@ -274,13 +281,16 @@ curses_character_input_dialog(const char *prompt, const char *choices, } if (iflags.wc_popup_dialog /*|| curses_stupid_hack*/) { - askwin = curses_create_window(prompt_width, prompt_height, UP); + askwin = curses_create_window(TEXT_WIN, prompt_width, prompt_height, UP); + activemenu = askwin; + for (count = 0; count < prompt_height; count++) { linestr = curses_break_str(askstr, maxwidth, count + 1); mvwaddstr(askwin, count + 1, 1, linestr); free(linestr); } + curses_set_wid_colors(TEXT_WIN, askwin); wrefresh(askwin); } else { /* TODO: add SUPPRESS_HISTORY flag, then after getting a response, @@ -295,9 +305,10 @@ curses_character_input_dialog(const char *prompt, const char *choices, #ifdef PDCURSES answer = wgetch(message_window); #else - answer = getch(); + answer = curses_read_char(); #endif if (answer == ERR) { + iflags.term_gone = 1; answer = def; break; } @@ -318,30 +329,32 @@ curses_character_input_dialog(const char *prompt, const char *choices, } break; } else if ((answer == '\n') || (answer == '\r') || (answer == ' ')) { - if ((choices != NULL) && (def != '\0')) { + if ((choices != NULL) + && ((def != '\0') || !strchr(choices, answer))) { answer = def; } break; } - if (digit(answer)) { - if (accept_count) { - if (answer != '0') { - yn_number = curses_get_count(answer - '0'); + if (digit(answer) && accept_count) { + if (answer != '0') { + yn_number = curses_get_count(answer); + + if (iflags.wc_popup_dialog) { + curses_count_window(NULL); touchwin(askwin); - refresh(); + wrefresh(askwin); } - - answer = '#'; - break; } + answer = '#'; + break; } if (any_choice) { break; } - if (choices != NULL && answer != '\0' && index(choices, answer)) + if (choices != NULL && answer != '\0' && strchr(choices, answer)) break; } curs_set(0); @@ -366,13 +379,14 @@ curses_character_input_dialog(const char *prompt, const char *choices, /* Return an extended command from the user */ int -curses_ext_cmd() +curses_ext_cmd(void) { - int count, letter, prompt_width, startx, starty, winx, winy; + int letter, prompt_width, startx, starty, winx, winy; int messageh, messagew, maxlen = BUFSZ - 1; int ret = -1; char cur_choice[BUFSZ]; int matches = 0; + int *ecmatches = NULL; WINDOW *extwin = NULL, *extwin2 = NULL; if (iflags.extmenu) { @@ -384,7 +398,8 @@ curses_ext_cmd() if (iflags.wc_popup_dialog) { /* Prompt in popup window */ int x0, y0, w, h; /* bounding coords of popup */ - extwin2 = curses_create_window(25, 1, UP); + extwin2 = curses_create_window(TEXT_WIN, 25, 1, UP); + curses_set_wid_colors(TEXT_WIN, extwin2); wrefresh(extwin2); /* create window inside window to prevent overwriting of border */ getbegyx(extwin2, y0, x0); @@ -413,41 +428,45 @@ curses_ext_cmd() while (1) { wmove(extwin, starty, startx); + wclrtoeol(extwin); waddstr(extwin, "# "); wmove(extwin, starty, startx + 2); waddstr(extwin, cur_choice); wmove(extwin, starty, (int) strlen(cur_choice) + startx + 2); - wclrtoeol(extwin); /* if we have an autocomplete command, AND it matches uniquely */ - if (matches == 1) { - curses_toggle_color_attr(extwin, NONE, A_UNDERLINE, ON); - wmove(extwin, starty, (int) strlen(cur_choice) + startx + 2); - wprintw(extwin, "%s", - extcmdlist[ret].ef_txt + (int) strlen(cur_choice)); - curses_toggle_color_attr(extwin, NONE, A_UNDERLINE, OFF); + if (matches == 1 && ecmatches) { + struct ext_func_tab *ec = extcmds_getentry(ecmatches[0]); + + if (ec) { + curses_toggle_color_attr(extwin, NONE, A_UNDERLINE, ON); + wmove(extwin, starty, (int) strlen(cur_choice) + startx + 2); + wprintw(extwin, "%s", ec->ef_txt + (int) strlen(cur_choice)); + curses_toggle_color_attr(extwin, NONE, A_UNDERLINE, OFF); + } } curs_set(1); wrefresh(extwin); - letter = getch(); + letter = pgetchar(); /* pgetchar(cmd.c) implements do-again */ curs_set(0); prompt_width = (int) strlen(cur_choice); - matches = 0; + if (letter == ERR) + iflags.term_gone = 1; if (letter == '\033' || letter == ERR) { ret = -1; break; } if (letter == '\r' || letter == '\n') { + (void) mungspaces(cur_choice); if (ret == -1) { - for (count = 0; extcmdlist[count].ef_txt; count++) { - if (!strcasecmp(cur_choice, extcmdlist[count].ef_txt)) { - ret = count; - break; - } - } + matches = extcmds_match(cur_choice, + (ECM_IGNOREAC | ECM_EXACTMATCH), + &ecmatches); + if (matches == 1 && ecmatches) + ret = ecmatches[0]; } break; } @@ -463,6 +482,7 @@ curses_ext_cmd() cur_choice[prompt_width - 1] = '\0'; letter = '*'; prompt_width--; + ret = -1; } /* honor kill_char if it's ^U or similar, but not if it's '@' */ @@ -478,30 +498,23 @@ curses_ext_cmd() cur_choice[prompt_width + 1] = '\0'; ret = -1; } - for (count = 0; extcmdlist[count].ef_txt; count++) { - if (!wizard && (extcmdlist[count].flags & WIZMODECMD)) - continue; - if (!(extcmdlist[count].flags & AUTOCOMPLETE)) - continue; - if ((int) strlen(extcmdlist[count].ef_txt) > prompt_width) { - if (strncasecmp(cur_choice, extcmdlist[count].ef_txt, - prompt_width) == 0) { - if ((extcmdlist[count].ef_txt[prompt_width] == - lowc(letter)) || letter == '*') { - if (matches == 0) { - ret = count; - } - - matches++; - } - } - } - } + matches = extcmds_match(cur_choice, ECM_NOFLAGS, &ecmatches); + if (matches == 1 && ecmatches) + ret = ecmatches[0]; } curses_destroy_win(extwin); if (extwin2) curses_destroy_win(extwin2); + + if (ret != -1) { + } else { + char extcmd_char = extcmd_initiator(); + + if (*cur_choice) + pline("%s%s: unknown extended command.", + visctrl(extcmd_char), cur_choice); + } return ret; } @@ -509,7 +522,7 @@ curses_ext_cmd() /* Initialize a menu from given NetHack winid */ void -curses_create_nhmenu(winid wid) +curses_create_nhmenu(winid wid, unsigned long mbehavior) { nhmenu *new_menu = NULL; nhmenu *menuptr = nhmenus; @@ -540,8 +553,10 @@ curses_create_nhmenu(winid wid) new_menu->num_pages = 0; new_menu->height = 0; new_menu->width = 0; + new_menu->mbehavior = mbehavior; new_menu->reuse_accels = FALSE; new_menu->bottom_heavy = FALSE; + new_menu->show_obj_syms = FALSE; return; } @@ -552,8 +567,10 @@ curses_create_nhmenu(winid wid) new_menu->num_pages = 0; new_menu->height = 0; new_menu->width = 0; + new_menu->mbehavior = mbehavior; new_menu->reuse_accels = FALSE; new_menu->bottom_heavy = FALSE; + new_menu->show_obj_syms = FALSE; new_menu->next_menu = NULL; if (nhmenus == NULL) { /* no menus in memory yet */ @@ -578,14 +595,16 @@ curs_new_menu_item(winid wid, const char *str) curses_rtrim(new_str); new_item = (nhmenu_item *) alloc((unsigned) sizeof (nhmenu_item)); new_item->wid = wid; - new_item->glyph = NO_GLYPH; - new_item->identifier = zeroany; + new_item->glyphinfo = nul_glyphinfo; + new_item->identifier = cg.zeroany; new_item->accelerator = '\0'; new_item->group_accel = '\0'; - new_item->attr = 0; + new_item->attr = ATR_NONE; + new_item->color = NO_COLOR; new_item->str = new_str; new_item->presel = FALSE; new_item->selected = FALSE; + new_item->itemflags = MENU_ITEMFLAGS_NONE; new_item->page_num = 0; new_item->line_num = 0; new_item->num_lines = 0; @@ -596,12 +615,20 @@ curs_new_menu_item(winid wid, const char *str) /* Add a menu item to the given menu window */ void -curses_add_nhmenu_item(winid wid, int glyph, const ANY_P *identifier, - CHAR_P accelerator, CHAR_P group_accel, int attr, - const char *str, BOOLEAN_P presel) +curses_add_nhmenu_item( + winid wid, + const glyph_info *glyphinfo, + const ANY_P *identifier, + char accelerator, + char group_accel, + int attr, + int clr, + const char *str, + unsigned itemflags) { nhmenu_item *new_item, *current_items, *menu_item_ptr; nhmenu *current_menu = get_menu(wid); + boolean presel = (itemflags & MENU_ITEMFLAGS_SELECTED) != 0; if (current_menu == NULL) { impossible( @@ -614,13 +641,14 @@ curses_add_nhmenu_item(winid wid, int glyph, const ANY_P *identifier, } new_item = curs_new_menu_item(wid, str); - new_item->glyph = glyph; + new_item->glyphinfo = *glyphinfo; new_item->identifier = *identifier; new_item->accelerator = accelerator; new_item->group_accel = group_accel; new_item->attr = attr; + new_item->color = clr; new_item->presel = presel; - + new_item->itemflags = itemflags; current_items = current_menu->entries; menu_item_ptr = current_items; @@ -639,10 +667,12 @@ curses_add_nhmenu_item(winid wid, int glyph, const ANY_P *identifier, /* for menu->bottom_heavy -- insert enough blank lines at top of first page to make the last page become a full one */ static void -curs_pad_menu(nhmenu *current_menu, boolean do_pad UNUSED) +curs_pad_menu( + nhmenu *current_menu, + boolean do_pad UNUSED) { nhmenu_item *menu_item_ptr; - int numpages = current_menu->num_pages; + int numpages; /* caller has already called menu_win_size() */ menu_determine_pages(current_menu); /* sets 'menu->num_pages' */ @@ -683,6 +713,7 @@ curs_menu_set_bottom_heavy(winid wid) { nhmenu *menu = get_menu(wid); + assert(menu != NULL); /* only called when 'wid' is a menu */ /* * Called after end_menu + finalize_nhmenu, * before select_menu + display_nhmenu. @@ -725,7 +756,10 @@ curses_finalize_nhmenu(winid wid, const char *prompt) /* Display a nethack menu, and return a selection, if applicable */ int -curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected) +curses_display_nhmenu( + winid wid, + int how, + MENU_ITEM_P **_selected) { nhmenu *current_menu = get_menu(wid); nhmenu_item *menu_item_ptr; @@ -738,14 +772,14 @@ curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected) if (current_menu == NULL) { impossible( "curses_display_nhmenu: attempt to display nonexistent menu"); - return '\033'; + return -1; /* not ESC which falsely claims 27 items were selected */ } menu_item_ptr = current_menu->entries; if (menu_item_ptr == NULL) { impossible("curses_display_nhmenu: attempt to display empty menu"); - return '\033'; + return -1; } /* Reset items to unselected to clear out selections from previous @@ -759,14 +793,15 @@ curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected) menu_determine_pages(current_menu); /* Display pre and post-game menus centered */ - if ((moves <= 1 && !invent) || program_state.gameover) { - win = curses_create_window(current_menu->width, + if (svm.moves == 0 || program_state.gameover) { + win = curses_create_window(wid, current_menu->width, current_menu->height, CENTER); } else { /* Display during-game menus on the right out of the way */ - win = curses_create_window(current_menu->width, + win = curses_create_window(wid, current_menu->width, current_menu->height, RIGHT); } + curses_set_wid_colors(wid, win); num_chosen = menu_get_selections(win, current_menu, how); curses_destroy_win(win); @@ -774,15 +809,14 @@ curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected) selected = (MENU_ITEM_P *) alloc((unsigned) (num_chosen * sizeof (MENU_ITEM_P))); count = 0; - menu_item_ptr = current_menu->entries; while (menu_item_ptr != NULL) { if (menu_item_ptr->selected) { if (count == num_chosen) { impossible("curses_display_nhmenu: Selected items " - "exceeds expected number"); - break; + "exceeds expected number"); + break; } selected[count].item = menu_item_ptr->identifier; selected[count].count = menu_item_ptr->count; @@ -794,6 +828,7 @@ curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected) if (count != num_chosen) { impossible( "curses_display_nhmenu: Selected items less than expected number"); + num_chosen = min(count, num_chosen); } } @@ -878,7 +913,6 @@ get_menu(winid wid) return NULL; /* Not found */ } - static char menu_get_accel(boolean first) { @@ -913,7 +947,7 @@ menu_is_multipage(nhmenu *menu, int width, int height) int curline = 0, accel_per_page = 0; nhmenu_item *menu_item_ptr = menu->entries; - if (*menu->prompt) { + if (menu->prompt && *menu->prompt) { curline += curses_num_lines(menu->prompt, width) + 1; } @@ -949,13 +983,12 @@ menu_determine_pages(nhmenu *menu) int tmpline, num_lines, accel_per_page; int curline = 0; int page_num = 1; - nhmenu_item *menu_item_ptr = menu->entries; + nhmenu_item *menu_item_ptr; int width = menu->width; int height = menu->height; int page_end = height; - - if (*menu->prompt) { + if (menu->prompt && *menu->prompt) { curline += curses_num_lines(menu->prompt, width) + 1; } tmpline = curline; @@ -1001,8 +1034,21 @@ menu_win_size(nhmenu *menu) int maxwidth, maxheight, curentrywidth, lastline; int maxentrywidth = 0; int maxheaderwidth = menu->prompt ? (int) strlen(menu->prompt) : 0; - nhmenu_item *menu_item_ptr; + nhmenu_item *menu_item_ptr, *last_item_ptr = NULL; + boolean only_if_no_headers = (iflags.menuobjsyms & 4) != 0; + + /* check entire menu rather than one page at a time */ + menu->show_obj_syms = iflags.use_menu_glyphs; + if (only_if_no_headers) { + for (menu_item_ptr = menu->entries; menu_item_ptr != NULL; + menu_item_ptr = menu_item_ptr->next_item) + if (menu_item_ptr->identifier.a_void == 0) { + menu->show_obj_syms = FALSE; + break; + } + } +#if 0 /* maxwidth is set below, so the value calculated here isn't used */ if (program_state.gameover) { /* for final inventory disclosure, use full width */ maxwidth = term_cols - 2; /* +2: borders assumed */ @@ -1017,9 +1063,11 @@ menu_win_size(nhmenu *menu) if ((term_cols / 2) > maxwidth) maxwidth = (term_cols / 2); /* Half the screen */ } +#endif maxheight = menu_max_height(); /* First, determine the width of the longest menu entry */ + assert(menu->entries != NULL); /* at least one iteration will occur */ for (menu_item_ptr = menu->entries; menu_item_ptr != NULL; menu_item_ptr = menu_item_ptr->next_item) { curentrywidth = (int) strlen(menu_item_ptr->str); @@ -1030,14 +1078,16 @@ menu_win_size(nhmenu *menu) } else { /* Add space for accelerator (selector letter) */ curentrywidth += 4; -#if 0 /* FIXME: menu glyphs */ - if (menu_item_ptr->glyph != NO_GLYPH && iflags.use_menu_glyphs) + if (menu_item_ptr->glyphinfo.glyph != NO_GLYPH + && menu->show_obj_syms) curentrywidth += 2; -#endif } if (curentrywidth > maxentrywidth) { maxentrywidth = curentrywidth; } + + /* might need this later */ + last_item_ptr = menu_item_ptr; } /* @@ -1056,15 +1106,12 @@ menu_win_size(nhmenu *menu) maxwidth = term_cols - 2; } - /* Possibly reduce height if only 1 page */ + /* Possibly reduce height if only 1 page. + Note: menu_is_multipage() populates entry->line_num and + entry->num_lines for all the menu's entries. */ if (!menu_is_multipage(menu, maxwidth, maxheight)) { - menu_item_ptr = menu->entries; - - while (menu_item_ptr->next_item != NULL) { - menu_item_ptr = menu_item_ptr->next_item; - } - - lastline = (menu_item_ptr->line_num) + menu_item_ptr->num_lines; + assert(last_item_ptr != NULL); + lastline = last_item_ptr->line_num + last_item_ptr->num_lines; if (lastline < maxheight) { maxheight = lastline; @@ -1072,7 +1119,7 @@ menu_win_size(nhmenu *menu) } /* avoid a tiny popup window; when it's shown over the endings of - old messsages rather than over the map, it is fairly easy for + old messages rather than over the map, it is fairly easy for the player to overlook it, particularly when walking around and stepping on a pile of 2 items; also, multi-page menus need enough room for "(Page M of N) => " even if all entries are narrower @@ -1081,22 +1128,91 @@ menu_win_size(nhmenu *menu) menu->height = max(maxheight, 5); } +#ifdef NCURSES_MOUSE_VERSION +static nhmenu_item * +get_menuitem_y( + WINDOW *win UNUSED, + nhmenu *menu, + int page_num, + int liney) +{ + nhmenu_item *menu_item_ptr; + int count, num_lines, entry_cols = menu->width; + char *tmpstr; + + menu_item_ptr = menu->entries; + + while (menu_item_ptr != NULL) { + if (menu_item_ptr->page_num == page_num) { + break; + } + menu_item_ptr = menu_item_ptr->next_item; + } + + if (menu_item_ptr == NULL) { /* Page not found */ + impossible("get_menuitem_y: attempt to display nonexistent page"); + return NULL; + } + + if (menu->prompt && *menu->prompt) { + num_lines = curses_num_lines(menu->prompt, menu->width); + + for (count = 0; count < num_lines; count++) { + tmpstr = curses_break_str(menu->prompt, menu->width, count + 1); + free(tmpstr); + } + } + + while (menu_item_ptr != NULL) { + if (menu_item_ptr->page_num != page_num) { + break; + } + if (menu_item_ptr->identifier.a_void != NULL) { + if (menu_item_ptr->line_num + 1 == liney) + return menu_item_ptr; + } + + num_lines = curses_num_lines(menu_item_ptr->str, entry_cols); + for (count = 0; count < num_lines; count++) { + if (menu_item_ptr->str && *menu_item_ptr->str) { + tmpstr = curses_break_str(menu_item_ptr->str, + entry_cols, count + 1); + free(tmpstr); + } + } + + menu_item_ptr = menu_item_ptr->next_item; + } + + return NULL; + +} +#endif /*NCURSES_MOUSE_VERSION*/ /* Displays menu selections in the given window */ +extern color_attr curses_menu_promptstyle; /*cursmain.c */ + static void -menu_display_page(nhmenu *menu, WINDOW * win, int page_num, char *selectors) +menu_display_page( + WINDOW *win, + nhmenu *menu, + int page_num, /* page number, 1..n rather than 0..n-1 */ + char *selectors, /* selection letters on current page */ + char *groupaccels) /* group accelerator characters on any page */ { nhmenu_item *menu_item_ptr; int count, curletter, entry_cols, start_col, num_lines; char *tmpstr; boolean first_accel = TRUE; - int color = NO_COLOR, attr = A_NORMAL; - boolean menu_color = FALSE; + int color = NO_COLOR, attr; /* letters assigned to entries on current page */ if (selectors) (void) memset((genericptr_t) selectors, 0, 256); + /* characters assigned to group accelerators on any page */ + if (groupaccels) + (void) memset((genericptr_t) groupaccels, 0, 256); /* Cycle through entries until we are on the correct page */ @@ -1121,7 +1237,11 @@ menu_display_page(nhmenu *menu, WINDOW * win, int page_num, char *selectors) for (count = 0; count < num_lines; count++) { tmpstr = curses_break_str(menu->prompt, menu->width, count + 1); + curses_menu_color_attr(win, curses_menu_promptstyle.color, + curses_menu_promptstyle.attr, ON); mvwprintw(win, count + 1, 1, "%s", tmpstr); + curses_menu_color_attr(win, curses_menu_promptstyle.color, + curses_menu_promptstyle.attr, OFF); free(tmpstr); } } @@ -1129,6 +1249,14 @@ menu_display_page(nhmenu *menu, WINDOW * win, int page_num, char *selectors) /* Display items for current page */ while (menu_item_ptr != NULL) { + /* collect group accelerators for every page */ + if (groupaccels && menu_item_ptr->identifier.a_void != NULL) { + unsigned gch = (unsigned) menu_item_ptr->group_accel; + + if (gch > 0 && gch <= 255) /* note: skip it if 0 */ + groupaccels[gch] = 1; + } + /* remaining processing applies to current page only */ if (menu_item_ptr->page_num != page_num) { break; } @@ -1171,32 +1299,24 @@ menu_display_page(nhmenu *menu, WINDOW * win, int page_num, char *selectors) entry_cols -= 4; start_col += 4; } -#if 0 - /* FIXME: menuglyphs not implemented yet */ - if (menu_item_ptr->glyph != NO_GLYPH && iflags.use_menu_glyphs) { - unsigned special; /*notused */ - - mapglyph(menu_item_ptr->glyph, &curletter, &color, &special, 0, 0, 0); + if (menu_item_ptr->glyphinfo.glyph != NO_GLYPH + && menu->show_obj_syms) { + color = menu_item_ptr->glyphinfo.gm.sym.color; curses_toggle_color_attr(win, color, NONE, ON); - mvwaddch(win, menu_item_ptr->line_num + 1, start_col, curletter); + mvwaddch(win, menu_item_ptr->line_num + 1, start_col, + menu_item_ptr->glyphinfo.ttychar); curses_toggle_color_attr(win, color, NONE, OFF); mvwaddch(win, menu_item_ptr->line_num + 1, start_col + 1, ' '); entry_cols -= 2; start_col += 2; } -#endif - color = NO_COLOR; - menu_color = iflags.use_menu_color - && get_menu_coloring(menu_item_ptr->str, &color, &attr); - if (menu_color) { - attr = curses_convert_attr(attr); - if (color != NO_COLOR || attr != A_NORMAL) - curses_menu_color_attr(win, color, attr, ON); - } else { - attr = menu_item_ptr->attr; - if (color != NO_COLOR || attr != A_NORMAL) - curses_toggle_color_attr(win, color, attr, ON); - } + color = menu_item_ptr->color; + if (color == NO_COLOR) + color = NONE; + attr = menu_item_ptr->attr; + /* attr is already a curses attr (A_ not ATR_) */ + if (color != NONE || attr != A_NORMAL) + curses_menu_color_attr(win, color, attr, ON); num_lines = curses_num_lines(menu_item_ptr->str, entry_cols); for (count = 0; count < num_lines; count++) { @@ -1208,13 +1328,9 @@ menu_display_page(nhmenu *menu, WINDOW * win, int page_num, char *selectors) free(tmpstr); } } - if (color != NO_COLOR || attr != A_NORMAL) { - if (menu_color) - curses_menu_color_attr(win, color, attr, OFF); - else - curses_toggle_color_attr(win, color, attr, OFF); + if (color != NONE || attr != A_NORMAL) { + curses_menu_color_attr(win, color, attr, OFF); } - menu_item_ptr = menu_item_ptr->next_item; } @@ -1241,31 +1357,171 @@ menu_display_page(nhmenu *menu, WINDOW * win, int page_num, char *selectors) curses_toggle_color_attr(win, HIGHLIGHT_COLOR, NONE, OFF); } } - curses_toggle_color_attr(win, DIALOG_BORDER_COLOR, NONE, ON); + if (curses_win_clr_inited(MENU_WIN) < 1) + curses_toggle_color_attr(win, DIALOG_BORDER_COLOR, NONE, ON); box(win, 0, 0); - curses_toggle_color_attr(win, DIALOG_BORDER_COLOR, NONE, OFF); + if (curses_win_clr_inited(MENU_WIN) < 1) + curses_toggle_color_attr(win, DIALOG_BORDER_COLOR, NONE, OFF); wrefresh(win); } +/* split out from menu_get_selections() so that perm_invent scrolling + can be controlled from outside the normal menu activity [groundwork; + ultimately not used that way, only from menu_get_seletions() itself] */ +boolean +curs_nonselect_menu_action( + WINDOW *win, + void *menu_v, /* generic pointer; caller might not know type 'nhmenu' */ + int how, + int curletter, + int *curpage_p, + char selectors[256], + int *num_selected_p) +{ + nhmenu_item *menu_item_ptr; + nhmenu *menu = (nhmenu *) menu_v; + boolean dismiss = FALSE; + int menucmd = (curletter <= 0 || curletter >= 255) ? curletter + : (int) (uchar) map_menu_cmd(curletter); + + switch (menucmd) { + case KEY_ESC: + *num_selected_p = -1; + dismiss = TRUE; + break; + case '\n': + case '\r': + dismiss = TRUE; + break; +#ifdef NCURSES_MOUSE_VERSION + case KEY_MOUSE: { + MEVENT mev; + + if (getmouse(&mev) == OK && how != PICK_NONE) { + if (wmouse_trafo(win, &mev.y, &mev.x, FALSE)) { + int y = mev.y; + + menu_item_ptr = get_menuitem_y(win, menu, *curpage_p, y); + + if (menu_item_ptr) { + if (how == PICK_ONE) { + menu_clear_selections(menu); + menu_select_deselect(win, menu_item_ptr, + SELECT, *curpage_p); + *num_selected_p = 1; + dismiss = TRUE; + } else { + menu_select_deselect(win, menu_item_ptr, + INVERT, *curpage_p); + } + } + } + } + break; + } /* case KEY_MOUSE */ +#endif /*NCURSES_MOUSE_VERSION*/ + case KEY_RIGHT: + case KEY_NPAGE: + case MENU_NEXT_PAGE: + case ' ': + if (*curpage_p < menu->num_pages) { + ++(*curpage_p); + menu_display_page(win, menu, *curpage_p, selectors, (char *) 0); + } else if (menucmd == ' ') { + dismiss = TRUE; + break; + } + break; + case KEY_LEFT: + case KEY_PPAGE: + case MENU_PREVIOUS_PAGE: + if (*curpage_p > 1) { + --(*curpage_p); + menu_display_page(win, menu, *curpage_p, selectors, (char *) 0); + } + break; + case KEY_END: + case MENU_LAST_PAGE: + if (*curpage_p != menu->num_pages) { + *curpage_p = menu->num_pages; + menu_display_page(win, menu, *curpage_p, selectors, (char *) 0); + } + break; + case KEY_HOME: + case MENU_FIRST_PAGE: + if (*curpage_p != 1) { + *curpage_p = 1; + menu_display_page(win, menu, *curpage_p, selectors, (char *) 0); + } + break; + case MENU_SEARCH: { + char search_key[BUFSZ]; + + if (how == PICK_NONE) + break; + + search_key[0] = '\0'; + curses_line_input_dialog("Search for:", search_key, BUFSZ); + + refresh(); + touchwin(win); + wrefresh(win); + + if (!*search_key) + break; + + menu_item_ptr = menu->entries; + + while (menu_item_ptr != NULL) { + if (menu_item_ptr->identifier.a_void != NULL + && strstri(menu_item_ptr->str, search_key)) { + if (how == PICK_ONE) { + menu_clear_selections(menu); + menu_select_deselect(win, menu_item_ptr, + SELECT, *curpage_p); + *num_selected_p = 1; + dismiss = TRUE; + break; + } else { + menu_select_deselect(win, menu_item_ptr, + INVERT, *curpage_p); + } + } + menu_item_ptr = menu_item_ptr->next_item; + } + break; + } /* case MENU_SEARCH */ + default: + if (how == PICK_NONE) { + *num_selected_p = 0; + dismiss = TRUE; + break; + } + } + + return dismiss; +} static int -menu_get_selections(WINDOW * win, nhmenu *menu, int how) +menu_get_selections(WINDOW *win, nhmenu *menu, int how) { - int curletter; - int count = -1; + int curletter, menucmd; + long count = -1L; int count_letter = '\0'; int curpage = !menu->bottom_heavy ? 1 : menu->num_pages; int num_selected = 0; boolean dismiss = FALSE; - char search_key[BUFSZ], selectors[256]; - nhmenu_item *menu_item_ptr = menu->entries; + char selectors[256], groupaccels[256]; + nhmenu_item *menu_item_ptr; - menu_display_page(menu, win, curpage, selectors); + activemenu = win; + menu_display_page(win, menu, curpage, selectors, groupaccels); while (!dismiss) { - curletter = getch(); + curletter = curses_getch(); if (curletter == ERR) { + iflags.term_gone = 1; num_selected = -1; dismiss = TRUE; } @@ -1287,8 +1543,11 @@ menu_get_selections(WINDOW * win, nhmenu *menu, int how) } break; case PICK_ANY: - if (curletter <= 0 || curletter >= 256 || !selectors[curletter]) { - switch (curletter) { + if (curletter <= 0 || curletter >= 256 + || (!selectors[curletter] && !groupaccels[curletter])) { + menucmd = (curletter <= 0 || curletter >= 255) ? curletter + : (int) (uchar) map_menu_cmd(curletter); + switch (menucmd) { case MENU_SELECT_PAGE: (void) menu_operation(win, menu, SELECT, curpage); break; @@ -1309,103 +1568,33 @@ menu_get_selections(WINDOW * win, nhmenu *menu, int how) break; } } + FALLTHROUGH; /*FALLTHRU*/ default: - if (isdigit(curletter)) { - count = curses_get_count(curletter - '0'); + if (curletter > 0 && curletter < 256 + && isdigit(curletter) && !selectors[curletter] + && !groupaccels[curletter]) { + count = curses_get_count(curletter); + /* after count, we know some non-digit is already pending */ + curletter = curses_getch(); + count_letter = (count > 0L) ? curletter : '\0'; + + /* remove the count wind (erases last line of message wind) */ + curses_count_window(NULL); + /* force redraw of the menu that is receiving the count */ touchwin(win); - refresh(); - curletter = getch(); - if (count > 0) { - count_letter = curletter; - } + wrefresh(win); } } - if (curletter <= 0 || curletter >= 256 || !selectors[curletter]) { - switch (curletter) { - case KEY_ESC: - num_selected = -1; - dismiss = TRUE; - break; - case '\n': - case '\r': - dismiss = TRUE; - break; - case KEY_RIGHT: - case KEY_NPAGE: - case MENU_NEXT_PAGE: - case ' ': - if (curpage < menu->num_pages) { - curpage++; - menu_display_page(menu, win, curpage, selectors); - } else if (curletter == ' ') { - dismiss = TRUE; - break; - } - break; - case KEY_LEFT: - case KEY_PPAGE: - case MENU_PREVIOUS_PAGE: - if (curpage > 1) { - curpage--; - menu_display_page(menu, win, curpage, selectors); - } - break; - case KEY_END: - case MENU_LAST_PAGE: - if (curpage != menu->num_pages) { - curpage = menu->num_pages; - menu_display_page(menu, win, curpage, selectors); - } - break; - case KEY_HOME: - case MENU_FIRST_PAGE: - if (curpage != 1) { - curpage = 1; - menu_display_page(menu, win, curpage, selectors); - } - break; - case MENU_SEARCH: - search_key[0] = '\0'; - curses_line_input_dialog("Search for:", search_key, BUFSZ); - - refresh(); - touchwin(win); - wrefresh(win); - - if (!*search_key) - break; - - menu_item_ptr = menu->entries; - - while (menu_item_ptr != NULL) { - if (menu_item_ptr->identifier.a_void != NULL - && strstri(menu_item_ptr->str, search_key)) { - if (how == PICK_ONE) { - menu_clear_selections(menu); - menu_select_deselect(win, menu_item_ptr, - SELECT, curpage); - num_selected = 1; - dismiss = TRUE; - break; - } else { - menu_select_deselect(win, menu_item_ptr, - INVERT, curpage); - } - } - - menu_item_ptr = menu_item_ptr->next_item; - } - - menu_item_ptr = menu->entries; - break; - default: - if (how == PICK_NONE) { - num_selected = 0; - dismiss = TRUE; - break; - } + if (curletter <= 0 || curletter >= 256 + || (!selectors[curletter] && !groupaccels[curletter])) { + dismiss = curs_nonselect_menu_action(win, (void *) menu, how, + curletter, &curpage, + selectors, &num_selected); + if (num_selected == -1) { + activemenu = NULL; + return -1; } } @@ -1419,7 +1608,8 @@ menu_get_selections(WINDOW * win, nhmenu *menu, int how) && curletter == menu_item_ptr->group_accel)) { if (curpage != menu_item_ptr->page_num) { curpage = menu_item_ptr->page_num; - menu_display_page(menu, win, curpage, selectors); + menu_display_page(win, menu, curpage, selectors, + (char *) 0); } if (how == PICK_ONE) { @@ -1461,23 +1651,27 @@ menu_get_selections(WINDOW * win, nhmenu *menu, int how) } } + activemenu = NULL; return num_selected; } - /* Select, deselect, or toggle selected for the given menu entry. For search operations, the toggled entry might be on a different page than the one currently shown. */ static void -menu_select_deselect(WINDOW *win, nhmenu_item *item, - menu_op operation, int current_page) +menu_select_deselect( + WINDOW *win, + nhmenu_item *item, + menu_op operation, + int current_page) { int curletter = item->accelerator; boolean visible = (item->page_num == current_page); if (operation == DESELECT || (item->selected && operation == INVERT)) { item->selected = FALSE; + item->count = -1L; if (visible) { mvwaddch(win, item->line_num + 1, 1, ' '); curses_toggle_color_attr(win, HIGHLIGHT_COLOR, NONE, ON); @@ -1501,12 +1695,15 @@ menu_select_deselect(WINDOW *win, nhmenu_item *item, /* Perform the selected operation (select, unselect, invert selection) -on the given menu page. If menu_page is 0, then perform opetation on +on the given menu page. If menu_page is 0, then perform operation on all pages in menu. Returns last page displayed. */ static int -menu_operation(WINDOW * win, nhmenu *menu, menu_op - operation, int page_num) +menu_operation( + WINDOW *win, + nhmenu *menu, + menu_op operation, + int page_num) { int first_page, last_page, current_page; nhmenu_item *menu_item_ptr = menu->entries; @@ -1530,7 +1727,7 @@ menu_operation(WINDOW * win, nhmenu *menu, menu_op current_page = first_page; if (page_num == 0) { - menu_display_page(menu, win, current_page, (char *) 0); + menu_display_page(win, menu, current_page, (char *) 0, (char *) 0); } if (menu_item_ptr == NULL) { /* Page not found */ @@ -1545,11 +1742,16 @@ menu_operation(WINDOW * win, nhmenu *menu, menu_op } current_page = menu_item_ptr->page_num; - menu_display_page(menu, win, current_page, (char *) 0); + menu_display_page(win, menu, current_page, (char *) 0, (char *) 0); } if (menu_item_ptr->identifier.a_void != NULL) { - menu_select_deselect(win, menu_item_ptr, operation, current_page); + if (menuitem_invert_test(((operation == INVERT) ? 0 + : (operation == SELECT) ? 1 : 2), + menu_item_ptr->itemflags, + menu_item_ptr->selected)) + menu_select_deselect(win, menu_item_ptr, + operation, current_page); } menu_item_ptr = menu_item_ptr->next_item; @@ -1580,3 +1782,5 @@ menu_max_height(void) { return term_rows - 2; } + +/*cursdial.c*/ diff --git a/win/curses/cursdial.h b/win/curses/cursdial.h index acc6f855b..de3d512fa 100644 --- a/win/curses/cursdial.h +++ b/win/curses/cursdial.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursdial.h */ +/* NetHack 5.0 cursdial.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -8,18 +8,24 @@ /* Global declarations */ -void curses_line_input_dialog(const char *prompt, char *answer, int buffer); +void curses_line_input_dialog(const char *prompt, char *answer, + int buffer) NONNULLPTRS; int curses_character_input_dialog(const char *prompt, const char *choices, - CHAR_P def); + char def) NONNULLARG1; int curses_ext_cmd(void); -void curses_create_nhmenu(winid wid); -void curses_add_nhmenu_item(winid wid, int glyph, const ANY_P *identifier, - CHAR_P accelerator, CHAR_P group_accel, int attr, - const char *str, BOOLEAN_P presel); +void curses_create_nhmenu(winid wid, unsigned long); +void curses_add_nhmenu_item(winid wid, const glyph_info *glyphinfo, + const ANY_P *identifier, char accelerator, + char group_accel, int attr, int clr, + const char *str, unsigned itemflags); void curs_menu_set_bottom_heavy(winid); void curses_finalize_nhmenu(winid wid, const char *prompt); int curses_display_nhmenu(winid wid, int how, MENU_ITEM_P **_selected); boolean curses_menu_exists(winid wid); void curses_del_menu(winid, boolean); +boolean curs_nonselect_menu_action(WINDOW *win, void *menu, int how, + int curletter, int *curpage_p, + char selectors[256], int *num_selected_p) + NONNULLPTRS; #endif /* CURSDIAL_H */ diff --git a/win/curses/cursinit.c b/win/curses/cursinit.c index 3d4f977d6..5ab7ea198 100644 --- a/win/curses/cursinit.c +++ b/win/curses/cursinit.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursinit.c */ +/* NetHack 5.0 cursinit.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -7,9 +7,6 @@ #include "hack.h" #include "wincurs.h" #include "cursinit.h" -/*#include "patchlevel.h"*/ - -#include /* Initialization and startup functions for curses interface */ @@ -19,24 +16,13 @@ static void set_window_position(int *, int *, int *, int *, int, int *, int *, int *, int *, int, int, int); -/* array to save initial terminal colors for later restoration */ - +#if 0 /* no longer used */ typedef struct nhrgb_type { short r; short g; short b; } nhrgb; - -nhrgb orig_yellow; -nhrgb orig_white; -nhrgb orig_darkgray; -nhrgb orig_hired; -nhrgb orig_higreen; -nhrgb orig_hiyellow; -nhrgb orig_hiblue; -nhrgb orig_himagenta; -nhrgb orig_hicyan; -nhrgb orig_hiwhite; +#endif /* Banners used for an optional ASCII splash screen */ @@ -109,27 +95,36 @@ set_window_position(int *winx, int *winy, int *winw, int *winh, /* Create the "main" nonvolatile windows used by nethack */ void -curses_create_main_windows() +curses_create_main_windows(void) { - int min_message_height = 1; + /* int min_message_height = 1; */ int message_orientation = 0; int status_orientation = 0; int border_space = 0; int hspace = term_cols - 80; - boolean borders = FALSE; + boolean borders = FALSE, noperminv_borders = FALSE; switch (iflags.wc2_windowborders) { + default: case 0: /* Off */ borders = FALSE; break; + + case 3: + noperminv_borders = TRUE; + FALLTHROUGH; + /*FALLTHRU*/ case 1: /* On */ borders = TRUE; break; + + case 4: + noperminv_borders = TRUE; + FALLTHROUGH; + /*FALLTHRU*/ case 2: /* Auto */ - borders = (term_cols > 81 && term_rows > 25); + borders = (term_cols >= 80 + 2 && term_rows >= 24 + 2); break; - default: - borders = FALSE; } if (borders) { @@ -138,7 +133,7 @@ curses_create_main_windows() } if ((term_cols - border_space) < COLNO) { - min_message_height++; + /* min_message_height++; */ } /* Determine status window orientation */ @@ -212,7 +207,7 @@ curses_create_main_windows() boolean msg_vertical = (message_orientation == ALIGN_LEFT || message_orientation == ALIGN_RIGHT); - /* Vertical windows have priority. Otherwise, priotity is: + /* Vertical windows have priority. Otherwise, priority is: status > inv > msg */ if (status_vertical) set_window_position(&status_x, &status_y, @@ -229,6 +224,9 @@ curses_create_main_windows() ALIGN_RIGHT, &map_x, &map_y, &map_width, &map_height, border_space, -1, width); + /* suppress borders on perm_invent window, part I */ + if (noperminv_borders) + inv_width += border_space, inv_height += border_space; /*+=2*/ } if (msg_vertical) @@ -277,7 +275,9 @@ curses_create_main_windows() if (iflags.perm_invent) curses_add_nhwin(INV_WIN, inv_height, inv_width, inv_y, inv_x, - ALIGN_RIGHT, borders); + ALIGN_RIGHT, + /* suppress perm_invent borders, part II */ + borders && !noperminv_borders); curses_add_nhwin(MAP_WIN, map_height, map_width, map_y, map_x, 0, borders); @@ -297,122 +297,84 @@ curses_create_main_windows() } } -/* Initialize curses colors to colors used by NetHack */ -void -curses_init_nhcolors() +static int pairs_used = 0; +static int colors_used = 0; + +/* create a new color */ +int +curses_init_rgb(int r, int g, int b) { -#ifdef TEXTCOLOR - if (has_colors()) { - use_default_colors(); - init_pair(1, COLOR_BLACK, -1); - init_pair(2, COLOR_RED, -1); - init_pair(3, COLOR_GREEN, -1); - init_pair(4, COLOR_YELLOW, -1); - init_pair(5, COLOR_BLUE, -1); - init_pair(6, COLOR_MAGENTA, -1); - init_pair(7, COLOR_CYAN, -1); - init_pair(8, -1, -1); - - { - int i; - boolean hicolor = FALSE; - - static const int clr_remap[16] = { - COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, - COLOR_BLUE, - COLOR_MAGENTA, COLOR_CYAN, -1, COLOR_WHITE, - COLOR_RED + 8, COLOR_GREEN + 8, COLOR_YELLOW + 8, - COLOR_BLUE + 8, - COLOR_MAGENTA + 8, COLOR_CYAN + 8, COLOR_WHITE + 8 - }; - - for (i = 0; i < (COLORS >= 16 ? 16 : 8); i++) { - init_pair(17 + (i * 2) + 0, clr_remap[i], COLOR_RED); - init_pair(17 + (i * 2) + 1, clr_remap[i], COLOR_BLUE); - } + if (!can_change_color()) + return 0; - if (COLORS >= 16) - hicolor = TRUE; - - /* Work around the crazy definitions above for more background - colors... */ - for (i = 0; i < (COLORS >= 16 ? 16 : 8); i++) { - init_pair((hicolor ? 49 : 9) + i, clr_remap[i], COLOR_GREEN); - init_pair((hicolor ? 65 : 33) + i, clr_remap[i], COLOR_YELLOW); - init_pair((hicolor ? 81 : 41) + i, clr_remap[i], COLOR_MAGENTA); - init_pair((hicolor ? 97 : 49) + i, clr_remap[i], COLOR_CYAN); - init_pair((hicolor ? 113 : 57) + i, clr_remap[i], COLOR_WHITE); - } - } + if (colors_used < COLORS - 1) { + colors_used++; + init_color(colors_used, r*4, g*4, b*4); + return colors_used; + } + return 0; +} +/* create a new foreground/background combination */ +int +curses_init_pair(int fg, int bg) +{ + if (pairs_used < COLOR_PAIRS - 1) { + pairs_used++; + init_pair(pairs_used, fg, bg); + return pairs_used; + } + return 0; +} - if (COLORS >= 16) { - init_pair(9, COLOR_WHITE, -1); - init_pair(10, COLOR_RED + 8, -1); - init_pair(11, COLOR_GREEN + 8, -1); - init_pair(12, COLOR_YELLOW + 8, -1); - init_pair(13, COLOR_BLUE + 8, -1); - init_pair(14, COLOR_MAGENTA + 8, -1); - init_pair(15, COLOR_CYAN + 8, -1); - init_pair(16, COLOR_WHITE + 8, -1); +/* Initialize curses colors to colors used by NetHack */ +void +curses_init_nhcolors(void) +{ + /* COLOR_foo + 8 means COLOR | A_BOLD when COLORS < 16 */ + /* otherwise assume the terminal has least 16 different colors */ + /* these map to the NetHack CLR_ defines */ + static const int fg_clr[16] = { + COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, + COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE, + -1, COLOR_RED + 8, COLOR_GREEN + 8, COLOR_YELLOW + 8, + COLOR_BLUE + 8, COLOR_MAGENTA + 8, COLOR_CYAN + 8, COLOR_WHITE + 8 + }; + static const int bg_clr[8] = { + -1, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, + COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE + }; + int bg, nhclr; + int maxc = (COLORS >= 16) ? 16 : 8; + + if (!has_colors()) + return; + + use_default_colors(); + + for (nhclr = CLR_BLACK; nhclr < maxc; nhclr++) { + for (bg = 0; bg < 8; bg++) { + init_pair((maxc * bg) + nhclr + 1, fg_clr[nhclr], bg_clr[bg]); } + } - if (can_change_color()) { - /* Preserve initial terminal colors */ - color_content(COLOR_YELLOW, &orig_yellow.r, &orig_yellow.g, - &orig_yellow.b); - color_content(COLOR_WHITE, &orig_white.r, &orig_white.g, - &orig_white.b); - - /* Set colors to appear as NetHack expects */ - init_color(COLOR_YELLOW, 500, 300, 0); - init_color(COLOR_WHITE, 600, 600, 600); - if (COLORS >= 16) { - /* Preserve initial terminal colors */ - color_content(COLOR_RED + 8, &orig_hired.r, - &orig_hired.g, &orig_hired.b); - color_content(COLOR_GREEN + 8, &orig_higreen.r, - &orig_higreen.g, &orig_higreen.b); - color_content(COLOR_YELLOW + 8, &orig_hiyellow.r, - &orig_hiyellow.g, &orig_hiyellow.b); - color_content(COLOR_BLUE + 8, &orig_hiblue.r, - &orig_hiblue.g, &orig_hiblue.b); - color_content(COLOR_MAGENTA + 8, &orig_himagenta.r, - &orig_himagenta.g, &orig_himagenta.b); - color_content(COLOR_CYAN + 8, &orig_hicyan.r, - &orig_hicyan.g, &orig_hicyan.b); - color_content(COLOR_WHITE + 8, &orig_hiwhite.r, - &orig_hiwhite.g, &orig_hiwhite.b); - - /* Set colors to appear as NetHack expects */ - init_color(COLOR_RED + 8, 1000, 500, 0); - init_color(COLOR_GREEN + 8, 0, 1000, 0); - init_color(COLOR_YELLOW + 8, 1000, 1000, 0); - init_color(COLOR_BLUE + 8, 0, 0, 1000); - init_color(COLOR_MAGENTA + 8, 1000, 0, 1000); - init_color(COLOR_CYAN + 8, 0, 1000, 1000); - init_color(COLOR_WHITE + 8, 1000, 1000, 1000); -# ifdef USE_DARKGRAY - if (COLORS > 16) { - color_content(CURSES_DARK_GRAY, &orig_darkgray.r, - &orig_darkgray.g, &orig_darkgray.b); - init_color(CURSES_DARK_GRAY, 300, 300, 300); - /* just override black colorpair entry here */ - init_pair(1, CURSES_DARK_GRAY, -1); - } -# endif - } else { - /* Set flag to use bold for bright colors */ - } +#ifdef USE_DARKGRAY + if (COLORS >= 16) { + if (iflags.wc2_darkgray) { + init_pair(CLR_BLACK + 1, COLOR_BLACK + 8, -1); } } #endif + colors_used = maxc; + pairs_used = (maxc * 8) + 16 + 1; } +#if 0 /* curses_choose_character + curses_character_dialog no longer used */ + /* Allow player to pick character's role, race, gender, and alignment. Borrowed from the Gnome window port. */ void -curses_choose_character() +curses_choose_character(void) { int n, i, sel, count_off, pick4u; int count = 0; @@ -452,7 +414,7 @@ curses_choose_character() } prompt[count_off] = '\0'; - sprintf(choice, "%s%c", tmpchoice, '\033'); + Snprintf(choice, sizeof(choice), "%s%c", tmpchoice, '\033'); if (strchr(tmpchoice, 't')) { /* Tutorial mode */ mvaddstr(0, 1, "New? Press t to enter a tutorial."); } @@ -719,6 +681,7 @@ curses_choose_character() flags.initalign = sel; } } + return; } /* Prompt user for character race, role, alignment, or gender */ @@ -726,13 +689,14 @@ int curses_character_dialog(const char **choices, const char *prompt) { int count, count2, ret, curletter; - char used_letters[52]; + char used_letters[invlet_basic]; /* a..zA..Z */ anything identifier; menu_item *selected = NULL; winid wid = curses_get_wid(NHW_MENU); + int clr = NO_COLOR; identifier.a_void = 0; - curses_start_menu(wid); + curses_start_menu(wid, MENU_BEHAVE_STANDARD); for (count = 0; choices[count]; count++) { curletter = tolower(choices[count][0]); @@ -743,20 +707,20 @@ curses_character_dialog(const char **choices, const char *prompt) } identifier.a_int = (count + 1); /* Must be non-zero */ - curses_add_menu(wid, NO_GLYPH, &identifier, curletter, 0, - A_NORMAL, choices[count], FALSE); + curses_add_menu(wid, &nul_glyphinfo, &identifier, curletter, 0, + A_NORMAL, clr, choices[count], MENU_ITEMFLAGS_NONE); used_letters[count] = curletter; } /* Random Selection */ identifier.a_int = ROLE_RANDOM; - curses_add_menu(wid, NO_GLYPH, &identifier, '*', 0, A_NORMAL, "Random", - FALSE); + curses_add_menu(wid, &nul_glyphinfo, &identifier, '*', 0, + A_NORMAL, clr, "Random", MENU_ITEMFLAGS_NONE); /* Quit prompt */ identifier.a_int = ROLE_NONE; - curses_add_menu(wid, NO_GLYPH, &identifier, 'q', 0, A_NORMAL, "Quit", - FALSE); + curses_add_menu(wid, &nul_glyphinfo, &identifier, 'q', 0, + A_NORMAL, clr, "Quit", MENU_ITEMFLAGS_NONE); curses_end_menu(wid, prompt); ret = curses_select_menu(wid, PICK_ONE, &selected); if (ret == 1) { @@ -774,25 +738,27 @@ curses_character_dialog(const char **choices, const char *prompt) return ret; } +#endif /* 0 */ + /* Initialize and display options appropriately */ void -curses_init_options() +curses_init_options(void) { - /* change these from DISP_IN_GAME to SET_IN_GAME */ - set_wc_option_mod_status(WC_ALIGN_MESSAGE | WC_ALIGN_STATUS, SET_IN_GAME); + /* change these from set_gameview to set_in_game */ + set_wc_option_mod_status(WC_ALIGN_MESSAGE | WC_ALIGN_STATUS, set_in_game); /* Remove a few options that are irrelevant to this windowport */ - set_option_mod_status("eight_bit_tty", SET_IN_FILE); + set_option_mod_status("eight_bit_tty", set_in_config); /* If we don't have a symset defined, load the curses symset by default */ - if (!symset[PRIMARY].explicitly) - load_symset("curses", PRIMARY); - if (!symset[ROGUESET].explicitly) + if (!gs.symset[PRIMARYSET].explicitly) + load_symset("curses", PRIMARYSET); + if (!gs.symset[ROGUESET].explicitly) load_symset("default", ROGUESET); #ifdef PDCURSES /* PDCurses for SDL, win32 and OS/2 has the ability to set the - terminal size programatically. If the user does not specify a + terminal size programmatically. If the user does not specify a size in the config file, we will set it to a nice big 32x110 to take advantage of some of the nice features of this windowport. */ if (iflags.wc2_term_cols == 0) @@ -819,17 +785,6 @@ curses_init_options() /* FIXME: this overrides explicit OPTIONS=!use_inverse */ iflags.wc_inverse = TRUE; /* aka iflags.use_inverse; default is False */ - /* fix up pet highlighting */ - if (iflags.wc2_petattr == -1) /* shouldn't happen */ - iflags.wc2_petattr = A_NORMAL; - if (iflags.wc2_petattr != A_NORMAL) { - /* Pet attribute specified, so hilite_pet should be true */ - iflags.hilite_pet = TRUE; - } else if (iflags.hilite_pet) { - /* pet highlighting specified, so don't leave petattr at A_NORMAL */ - iflags.wc2_petattr = A_REVERSE; - } - /* curses doesn't support 's' (single message at a time; successive ^P's go back to earlier messages) and 'c' (combination; single on first and second of consecutive ^P's, full on third) */ @@ -847,7 +802,7 @@ curses_init_options() /* Display an ASCII splash screen if the splash_screen option is set */ void -curses_display_splash_window() +curses_display_splash_window(void) { int i, x_start, y_start; @@ -879,36 +834,8 @@ curses_display_splash_window() refresh(); } -/* Resore colors and cursor state before exiting */ +/* Restore colors and cursor state before exiting */ void -curses_cleanup() +curses_cleanup(void) { -#ifdef TEXTCOLOR - if (has_colors() && can_change_color()) { - init_color(COLOR_YELLOW, orig_yellow.r, orig_yellow.g, orig_yellow.b); - init_color(COLOR_WHITE, orig_white.r, orig_white.g, orig_white.b); - - if (COLORS >= 16) { - init_color(COLOR_RED + 8, orig_hired.r, orig_hired.g, orig_hired.b); - init_color(COLOR_GREEN + 8, orig_higreen.r, orig_higreen.g, - orig_higreen.b); - init_color(COLOR_YELLOW + 8, orig_hiyellow.r, - orig_hiyellow.g, orig_hiyellow.b); - init_color(COLOR_BLUE + 8, orig_hiblue.r, orig_hiblue.g, - orig_hiblue.b); - init_color(COLOR_MAGENTA + 8, orig_himagenta.r, - orig_himagenta.g, orig_himagenta.b); - init_color(COLOR_CYAN + 8, orig_hicyan.r, orig_hicyan.g, - orig_hicyan.b); - init_color(COLOR_WHITE + 8, orig_hiwhite.r, orig_hiwhite.g, - orig_hiwhite.b); -# ifdef USE_DARKGRAY - if (COLORS > 16) { - init_color(CURSES_DARK_GRAY, orig_darkgray.r, - orig_darkgray.g, orig_darkgray.b); - } -# endif - } - } -#endif } diff --git a/win/curses/cursinit.h b/win/curses/cursinit.h index c611d59f6..f51f1a681 100644 --- a/win/curses/cursinit.h +++ b/win/curses/cursinit.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursinit.h */ +/* NetHack 5.0 cursinit.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,6 +9,8 @@ /* Global declarations */ void curses_create_main_windows(void); +int curses_init_rgb(int r, int g, int b); +int curses_init_pair(int fg, int bg); void curses_init_nhcolors(void); void curses_choose_character(void); int curses_character_dialog(const char **choices, const char *prompt); diff --git a/win/curses/cursinvt.c b/win/curses/cursinvt.c index 64fd0197d..3369b2d8c 100644 --- a/win/curses/cursinvt.c +++ b/win/curses/cursinvt.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursinvt.c */ +/* NetHack 5.0 cursinvt.c */ /* Copyright (c) Fredrik Ljungdahl, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -8,15 +8,63 @@ #include "wincurs.h" #include "cursinvt.h" -/* Permanent inventory for curses interface */ +static void curs_invt_updated(WINDOW *); +static unsigned pi_article_skip(const char *); +static int curs_scroll_invt(WINDOW *); +static void curs_show_invt(WINDOW *); + +/* + * Persistent inventory (perm_invent) for curses interface. + * It resembles a menu but does not function like one. + */ + +/* pseudo menu line data */ +struct pi_line { + char *invtxt; /* class header or inventory item without letter prefix */ + attr_t c_attr; /* attribute for class headers */ + int color; + char letter; /* inventory letter; accelerator if this was really a menu; + * used to distinguish item lines from header lines and for + * display (no selection possible) */ +}; +static struct pi_line zero_pi_line; + +/* full perm_invent data; added to array[] one line at a time */ +struct pi_data { + struct pi_line *array; /* one element for each line of perminv */ + unsigned allocsize, inuseindx; /* num elements allocated and populated */ + unsigned rowoffset, coloffset; /* for displaying a subset due to space */ + unsigned widest; /* longest array[].invtxt */ +}; +#define PERMINV_CHUNK 20 /* number of elements to grow array[] when needed */ + +/* current persistent inventory */ +static struct pi_data pi = { (struct pi_line *) 0, 0, 0, 0, 0, 0 }; + +/* discard saved persistent inventory data */ +void +curs_purge_perminv_data(boolean everything) +{ + if (pi.array) { + unsigned idx; + + for (idx = 0; idx < pi.inuseindx; ++idx) + free(pi.array[idx].invtxt), pi.array[idx].invtxt = 0; + + if (everything) + free(pi.array), pi.array = 0, pi.allocsize = 0; + } + + pi.inuseindx = 0; + pi.rowoffset = pi.coloffset = 0; + pi.widest = 0; +} /* Runs when the game indicates that the inventory has been updated */ void -curses_update_inv(void) +curs_update_invt(int arg) { WINDOW *win = curses_get_nhwin(INV_WIN); - boolean border; - int x = 0, y = 0; /* Check if the inventory window is enabled in first place */ if (!win) { @@ -34,115 +82,385 @@ curses_update_inv(void) return; } - border = curses_window_has_border(INV_WIN); + /* clear anything displayed from previous update */ + werase(win); - /* Figure out drawing area */ - if (border) { - x++; - y++; - } + if (!arg) { + /* + * 'arg'==0 means basic inventory_update(): [re-]populate and + * [re-]display the persistent inventory window. + */ + if (pi.array) /* previous data is obsolete */ + curs_purge_perminv_data(FALSE); - /* Clear the window as it is at the moment. */ - werase(win); + /* ask core to display full inventory in a PICK_NONE menu; + instead of setting up an ordinary menu, it will indirectly + call curs_add_invt() for each line (including class headers) */ + repopulate_perminvent(); + curs_invt_updated(win); - display_inventory(NULL, FALSE); + } else { + /* + * 'arg'!=0 means #perminv command is providing the player + * with opportunity to scroll the already displayed persistent + * inventory window. Aside from being non-zero, the value of + * 'arg' is ignored. + */ + int scrollingdone; - if (border) + /* previous data is still valid; let player interactively scroll it */ + do { + scrollingdone = curs_scroll_invt(win); + curs_invt_updated(win); + } while (!scrollingdone); + + } + return; +} + +/* persistent inventory has been updated or scrolled/panned; re-display it */ +static void +curs_invt_updated(WINDOW *win) +{ + /* display collected inventory data, probably clipped */ + curs_show_invt(win); + + if (curses_window_has_border(INV_WIN)) box(win, 0, 0); wnoutrefresh(win); } -/* Adds an inventory item. 'y' is 1 rather than 0 for the first item. */ -void -curses_add_inv(int y, - int glyph UNUSED, - CHAR_P accelerator, attr_t attr, const char *str) +/* scroll persistent inventory window forwards or backwards or side-to-side */ +static int +curs_scroll_invt(WINDOW *win UNUSED) { - WINDOW *win = curses_get_nhwin(INV_WIN); - int color = NO_COLOR; - int x = 0, width, height, available_width, stroffset = 0, - border = curses_window_has_border(INV_WIN) ? 1 : 0; - - /* Figure out where to draw the line */ - x += border; /* x starts at 0 and is incremented for border */ - y -= 1 - border; /* y starts at 1 and is decremented for non-border */ + char menukeys[QBUFSZ], qbuf[QBUFSZ]; + unsigned uheight, uwidth, uhalfwidth, scrlmask; + int ch, menucmd, height, width; + int res = 0; curses_get_window_size(INV_WIN, &height, &width); + uheight = (unsigned) height; + uwidth = (unsigned) width; + uhalfwidth = uwidth / 2; + + menukeys[0] = '\0'; + scrlmask = 0U; + if (pi.rowoffset > 0) + scrlmask |= 1U; /* include scroll backwards: ^ and < */ + if (pi.rowoffset + uheight <= pi.inuseindx) + scrlmask |= 2U; /* include scroll forwards: > and | */ + if (pi.coloffset > 0) + scrlmask |= 4U; /* include scroll left: { */ + if (pi.widest > pi.coloffset + uwidth) + scrlmask |= 8U; /* include scroll right: } */ + (void) collect_menu_keys(menukeys, scrlmask, TRUE); + + Snprintf(qbuf, sizeof qbuf, "Inventory scroll: [%s%s%s] ", + menukeys, *menukeys ? " " : "", "Ret Esc"); + + curses_count_window(qbuf); + ch = getch(); + curses_count_window((char *) 0); + curses_clear_unhighlight_message_window(); + + menucmd = (ch <= 0 || ch >= 255) ? ch : (int) (uchar) map_menu_cmd(ch); + switch (menucmd) { + case KEY_ESC: + case C('c'): /* ^C */ + /* for , leave window with scrolling as-is */ + res = -1; + break; + case '\n': + case '\r': + case '\b': + case '\177': + /* for , or when already on last page, + restore window to unscrolled */ + pi.rowoffset = pi.coloffset = 0; + res = 1; + break; + case ' ': + if (pi.rowoffset + uheight <= pi.inuseindx) { + pi.rowoffset = pi.coloffset = 0; + res = 1; + break; + } + FALLTHROUGH; + /*FALLTHRU*/ + case KEY_RIGHT: + case KEY_NPAGE: + case MENU_NEXT_PAGE: + if (pi.inuseindx <= uheight) + pi.rowoffset = 0; + else if (pi.rowoffset + 2 * uheight <= pi.inuseindx) + pi.rowoffset += uheight; + else + pi.rowoffset = pi.inuseindx - (uheight - 1); + break; + case KEY_LEFT: + case KEY_PPAGE: + case MENU_PREVIOUS_PAGE: + if (pi.rowoffset >= uheight) + pi.rowoffset -= uheight; + else + pi.rowoffset = 0; + break; + + case KEY_END: + case MENU_LAST_PAGE: + if (pi.inuseindx > uheight) + pi.rowoffset = pi.inuseindx - (uheight - 1); + else + pi.rowoffset = 0; + break; + case KEY_HOME: + case MENU_FIRST_PAGE: + pi.rowoffset = 0; + break; + + case KEY_DOWN: + if (pi.rowoffset + uheight <= pi.inuseindx) + pi.rowoffset += 1; + break; + case KEY_UP: + if (pi.rowoffset > 0) + pi.rowoffset -= 1; + else + pi.rowoffset = 0; + break; + + case MENU_SHIFT_RIGHT: + if (pi.widest <= uwidth) { + pi.coloffset = 0; + } else { + pi.coloffset += uhalfwidth; + if (pi.coloffset + uwidth > pi.widest) + pi.coloffset = pi.widest - uwidth; + } + break; + case MENU_SHIFT_LEFT: + if (pi.coloffset >= uhalfwidth) + pi.coloffset -= uhalfwidth; + else + pi.coloffset = 0; + break; + +#if 0 + case MENU_SEARCH: + break; +#endif + case '\0': + default: + curses_nhbell(); + break; + } + return res; +} + +/* check 'str' for an article prefix and return length of that */ +static unsigned +pi_article_skip(const char *str) +{ + unsigned skip = 0; /* number of chars to skip when displaying str */ + /* - * TODO: - * If border is On and 'y' is too big, turn border Off in order to - * get two more lines of perm_invent. - * - * And/or implement a way to switch focus from map to inventory - * so that the latter can be scrolled. Must not require use of a - * mouse. - * - * Also, when entries are omitted due to lack of space, mark the - * last line to indicate "there's more that you can't see" (like - * horizontal status window does for excess status conditions). - * Normal menu does this via 'page M of N'. + * if (!strncmp(str, "a ", 2)) + * skip = 2; + * else if (!strncmp(str, "an ", 3)) + * skip = 3; + * else if (!strncmp(str, "the ", 4)) + * skip = 4; */ - if (y - border >= height) /* 'height' is already -2 for Top+Btm borders */ - return; - available_width = width; /* 'width' also already -2 for Lft+Rgt borders */ + if (str[0] == 'a') { + if (str[1] == ' ') + skip = 2; + else if (str[1] == 'n' && str[2] == ' ') + skip = 3; + } else if (str[0] == 't') { + if (str[1] == 'h' && str[2] == 'e' && str[3] == ' ') + skip = 4; + } + + return skip; +} + +/* store an inventory item or class header but don't display anything yet */ +void +curs_add_invt( + int linenum, /* line index; 1..n rather than 0..n-1 */ + char accelerator, /* selector letter for items, 0 for class headers */ + attr_t attr, /* curses attribute for headers, 0 for items */ + int clr, /* NetHack color for headers, NO_COLOR for items */ + const char *str) /* formatted inventory item, without invlet prefix, + * or class header text */ +{ + unsigned idx, len; + struct pi_line newelement, *aptr = pi.array; + + if ((unsigned) linenum > pi.allocsize) { + pi.allocsize += PERMINV_CHUNK; + pi.array = (struct pi_line *) alloc(pi.allocsize * sizeof *aptr); + for (idx = 0; idx < pi.allocsize; ++idx) + pi.array[idx] = (idx < pi.inuseindx) ? aptr[idx] : zero_pi_line; + if (aptr) + free(aptr); + aptr = pi.array; + } + + newelement.invtxt = dupstr(str); + newelement.c_attr = attr; /* note: caller has already converted 'attr' + * from tty-style attribute to curses one */ + newelement.color = clr; + newelement.letter = accelerator; + aptr[pi.inuseindx++] = newelement; - wmove(win, y, x); + len = strlen(str); if (accelerator) { -#if 0 - attr_t bold = A_BOLD; - - wattron(win, bold); - waddch(win, accelerator); - wattroff(win, bold); - wprintw(win, ") "); -#else - /* despite being shown as a menu, nothing is selectable from the - persistent inventory window so don't highlight inventory letters */ - wprintw(win, "%c) ", accelerator); -#endif - available_width -= 3; /* letter+parenthesis+space */ - - /* narrow the entries to fit more of the interesting text; do so - unconditionally rather than trying to figure whether it's needed; - when 'sortpack' is enabled we could also strip out " of" - from " of but if that's to be done, - core ought to do it; - 'stroffset': defer skipping the article prefix until after menu - color pattern matching has taken place so that the persistent - inventory window always gets same coloring as regular inventory */ - if (!strncmpi(str, "a ", 2)) - stroffset = 2; - else if (!strncmpi(str, "an ", 3)) - stroffset = 3; - else if (!strncmpi(str, "the ", 4)) - stroffset = 4; + /* +4: " )c " inventory letter will be inserted before invtxt; + invtxt's "a "/"an "/"the " prefix, if any, will be skipped */ + len += 4; + if (len > pi.widest) + len -= pi_article_skip(str); } -#if 0 /* FIXME: MENU GLYPHS */ - if (accelerator && glyph != NO_GLYPH && iflags.use_menu_glyphs) { - unsigned dummy = 0; /* Not used */ - int color = 0; - int symbol = 0; - attr_t glyphclr; - - mapglyph(glyph, &symbol, &color, &dummy, u.ux, u.uy, 0); - glyphclr = curses_color_attr(color, 0); - wattron(win, glyphclr); - wprintw(win, "%c ", symbol); - wattroff(win, glyphclr); - available_width -= 2; + if (len > pi.widest) + pi.widest = len; +} + +/* display the inventory menu-like data collected in pi.array[] */ +static void +curs_show_invt(WINDOW *win) +{ + const char *str; + char accelerator, tmpbuf[BUFSZ]; + int attr, color; + unsigned lineno, stroffset, widest, left_col, right_col, + first_shown = 0, last_shown = 0, item_count = 0, xtra_line = 0; + int x, y, width, height, available_width, + border = curses_window_has_border(INV_WIN) ? 1 : 0, + /* we actually care about the topmost of message, map, or status + but either they all have borders or none do so just check map */ + otherborder = curses_window_has_border(MAP_WIN) ? 1 : 0; + + x = border; /* same for every line; 1 if border, 0 otherwise */ + + curses_get_window_size(INV_WIN, &height, &width); + widest = pi.widest; + left_col = pi.coloffset + 1; + right_col = left_col + (unsigned) width - 1; + + /* + * If there will be any blank lines left at the bottom, sometimes + * insert one blank line at the top. If the first line is an item + * (via !sortpack) which will be obscured by the column indicator, + * or there is only one line (such as "not carrying anything") if + * that line would be at the very top aligned with the top border + * of another window (windowborders=3,4) because that looks odd. + * This only handles the single page case [because scrolling always + * fills pages beyond the first rather than just continuing from + * last line of preceding page, hence no blank line(s) at bottom]. + */ + if ((pi.array[0].letter && pi.inuseindx < (unsigned) height + && widest > (unsigned) width) + || (pi.inuseindx == 1 && otherborder && !border)) { + wmove(win, 1, x); + wprintw(win, "%.*s", width - 2 * border, ""); + xtra_line = 1; } -#endif - if (accelerator /* Don't colorize categories */ - && iflags.use_menu_color) { - attr = 0; - get_menu_coloring(str, &color, (int *) &attr); - attr = curses_convert_attr(attr); + + for (lineno = 0; lineno < pi.rowoffset; ++lineno) + if (pi.array[lineno].letter) + ++item_count; + + for (lineno = pi.rowoffset; lineno < pi.inuseindx; ++lineno) { + str = pi.array[lineno].invtxt; + accelerator = pi.array[lineno].letter; + attr = pi.array[lineno].c_attr; /* already converted when stored */ + color = pi.array[lineno].color; + if (color == NO_COLOR) + color = NONE; + + if (accelerator) + ++item_count; + + /* Figure out where to draw the line */ + y = (int) (lineno + xtra_line - pi.rowoffset) + border; + if (y - border >= height) { /* height already -2 for Top+Btm border */ + /* 'y' has grown too big; there are too many lines to fit */ + continue; /* skip, but still loop to update 'item_count' */ + } + available_width = width; /* width is already -2 for Lft+Rgt borders */ + + wmove(win, y, x); + + stroffset = 0; + if (accelerator) { /* inventory item line */ + if (!first_shown) + first_shown = item_count; + last_shown = item_count; + /* despite being shown as a menu, nothing is selectable from the + persistent inventory window so avoid the usual highlighting + of inventory letters */ + wprintw(win, " %c) ", accelerator); + available_width -= 4; /* space+letter+parenthesis+space */ + + /* + * Narrow the entries to fit more of the interesting text, + * but defer the removal until after menu colors matching. + * Do so unconditionally rather than trying to figure whether + * it's needed. When 'sortpack' is enabled we could also strip + * out " of" from " of " + * but if that's to be done, the core ought to do it. + */ + stroffset = pi_article_skip(str); /* to skip "a "/"an "/"the " */ + /* if/when scrolled right, invtxt for item lines gets shifted */ + stroffset += pi.coloffset; + } + + if (stroffset < strlen(str)) { + curses_menu_color_attr(win, color, attr, ON); + wprintw(win, "%.*s", available_width, str + stroffset); + curses_menu_color_attr(win, color, attr, OFF); + } + + wclrtoeol(win); + } /* lineno loop */ + + if (pi.inuseindx > (unsigned) height) { + /* + * More lines than will fit at one time so some lines aren't shown. + * Overwrite the rightmost portion of last line with something + * like "[1-24 of 30>" or "<7-30 of 30]" if we've already scrolled + * forward. Right justified so that the line might still show + * something useful. It could be on a line of its own, in which + * case we need to erase that first. + */ + y = height - (1 - border); + if ((unsigned) y == pi.inuseindx - pi.rowoffset) { + wmove(win, y, x); + wclrtoeol(win); + } + Sprintf(tmpbuf, "%c%u-%u of %u%c", + (first_shown > 1) ? '<' : '[', + first_shown, last_shown, item_count, + (last_shown < item_count) ? '>' : ']'); + mvwaddstr(win, y, x + (width - (int) strlen(tmpbuf)), tmpbuf); + } + if (widest > (unsigned) width) { + /* + * More columns than the persistent inventory window can fit so + * some columns aren't shown. Overwrite the rightmost portion of + * first line with something like "[1-25 of 40}" or "{16-40 of 40]". + * For the usual case, that line will be an object class header + * so we won't be obscuring an item, but that might not be the + * situation on page 2 and definitely won't be if 'sortpack' is Off. + */ + Sprintf(tmpbuf, "%c%u-%u of %u%c", + (left_col > 1) ? '{' : '[', + left_col, right_col, widest, + (right_col < widest) ? '}' : ']'); + mvwaddstr(win, border, x + (width - (int) strlen(tmpbuf)), tmpbuf); } - if (color == NO_COLOR) - color = NONE; - curses_menu_color_attr(win, color, attr, ON); - wprintw(win, "%.*s", available_width, str + stroffset); - curses_menu_color_attr(win, color, attr, OFF); - wclrtoeol(win); + return; } diff --git a/win/curses/cursinvt.h b/win/curses/cursinvt.h index db2df6586..e644c193d 100644 --- a/win/curses/cursinvt.h +++ b/win/curses/cursinvt.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursinvt.h */ +/* NetHack 5.0 cursinvt.h */ /* Copyright (c) Fredrik Ljungdahl, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,6 +9,6 @@ /* Global declarations */ -void curses_update_inv(void); +void curses_update_inv(int); #endif /* CURSINVT_H */ diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index 673ad9ba2..23f5e90f2 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -1,17 +1,15 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursmain.c */ +/* NetHack 5.0 cursmain.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ #include "curses.h" #include "hack.h" -#ifdef SHORT_FILENAMES -#include "patchlev.h" -#else -#include "patchlevel.h" -#endif #include "color.h" #include "wincurs.h" +#ifdef CURSES_UNICODE +#include +#endif /* define this if not linking with tty.o|.obj for some reason */ #ifdef CURSES_DEFINE_ERASE_CHAR @@ -22,29 +20,50 @@ char erase_char, kill_char; extern char erase_char, kill_char; #endif -extern long curs_mesg_suppress_turn; /* from cursmesg.c */ +extern long curs_mesg_suppress_seq; /* from cursmesg.c */ +extern boolean curs_mesg_no_suppress; /* ditto */ +extern int mesg_mixed; +extern glyph_info mesg_gi; + +#ifndef CURSES_GENL_PUTMIXED +#if defined(PDC_WIDE) || defined(NCURSES_WIDECHAR) +#define USE_CURSES_PUTMIXED +#else /* WIDE */ +#ifdef NH_PRAGMA_MESSAGE +#ifdef _MSC_VER +#pragma message ("Curses wide support not defined so NetHack curses message window functionality reduced") +#else +#pragma message "Curses wide support not defined so NetHack curses message window functionality reduced" +#endif /* _MSC_VER */ +#endif /* NH_PRAGMA_MESSAGE */ +#endif /* WIDE */ +#endif /* CURSES_GENL_PUTMIXED */ /* stubs for curses_procs{} */ #ifdef POSITIONBAR static void dummy_update_position_bar(char *); #endif #ifdef CHANGE_COLOR -static void dummy_change_color(int, long, int); -static char *dummy_get_color_string(VOID_ARGS); +static void curses_change_color(int, long, int); +static char *curses_get_color_string(void); #endif /* Public functions for curses NetHack interface */ /* Interface definition, for windows.c */ struct window_procs curses_procs = { - "curses", + WPID(curses), (WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_COLOR | WC_INVERSE - | WC_HILITE_PET + | WC_HILITE_PET | WC_WINDOWCOLORS #ifdef NCURSES_MOUSE_VERSION /* (this macro name works for PDCURSES too) */ | WC_MOUSE_SUPPORT #endif | WC_PERM_INVENT | WC_POPUP_DIALOG | WC_SPLASH_SCREEN), (WC2_DARKGRAY | WC2_HITPOINTBAR +#ifdef CURSES_UNICODE + | WC2_U_UTF8STR +#endif + | WC2_EXTRACOLORS #ifdef SELECTSAVED | WC2_SELECTSAVED #endif @@ -53,7 +72,9 @@ struct window_procs curses_procs = { #endif | WC2_FLUSH_STATUS | WC2_TERM_SIZE | WC2_STATUSLINES | WC2_WINDOWBORDERS | WC2_PETATTR | WC2_GUICOLOR - | WC2_SUPPRESS_HIST), + | WC2_SUPPRESS_HIST | WC2_URGENT_MESG | WC2_MENU_SHIFT + | WC2_EXTRASTATUS + ), {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ curses_init_nhwindows, curses_player_selection, @@ -68,14 +89,17 @@ struct window_procs curses_procs = { curses_destroy_nhwindow, curses_curs, curses_putstr, +#ifdef USE_CURSES_PUTMIXED + curses_putmixed, +#else genl_putmixed, +#endif curses_display_file, curses_start_menu, curses_add_menu, curses_end_menu, curses_select_menu, genl_message_menu, - curses_update_inventory, curses_mark_synch, curses_wait_synch, #ifdef CLIPPING @@ -97,15 +121,13 @@ struct window_procs curses_procs = { curses_number_pad, curses_delay_output, #ifdef CHANGE_COLOR - dummy_change_color, -#ifdef MAC /* old OS 9, not OSX */ + curses_change_color, +#ifdef MACOS9 /* old OS 9, not OSX */ (void (*)(int)) 0, (short (*)(winid, char *)) 0, #endif - dummy_get_color_string, + curses_get_color_string, #endif - curses_start_screen, - curses_end_screen, genl_outrip, curses_preference_update, curses_getmsghistory, @@ -115,6 +137,8 @@ struct window_procs curses_procs = { genl_status_enablefield, curses_status_update, genl_can_suspend_yes, + curses_update_inventory, + curses_ctrl_nhwindow, }; /* @@ -126,6 +150,7 @@ int orig_cursor; /* Preserve initial cursor state */ WINDOW *base_term; /* underlying terminal window */ boolean counting; /* Count window is active */ WINDOW *mapwin, *statuswin, *messagewin; /* Main windows */ +color_attr curses_menu_promptstyle = { NO_COLOR, ATR_NONE }; /* Track if we're performing an update to the permanent window. Needed since we aren't using the normal menu functions to handle @@ -133,7 +158,7 @@ WINDOW *mapwin, *statuswin, *messagewin; /* Main windows */ static int inv_update = 0; /* -init_nhwindows(int* argcp, char** argv) +init_nhwindows(int *argcp, char **argv) -- Initialize the windows used by NetHack. This can also create the standard windows listed at the top, but does not display them. @@ -147,34 +172,61 @@ init_nhwindows(int* argcp, char** argv) ** windows? Or at least all but WIN_INFO? -dean */ void -curses_init_nhwindows(int *argcp UNUSED, - char **argv UNUSED) +curses_init_nhwindows( + int *argcp UNUSED, + char **argv UNUSED) { #ifdef PDCURSES char window_title[BUFSZ]; #endif +#ifdef CURSES_UNICODE +#ifdef PDCURSES + static char pdc_font[BUFSZ] = ""; +#endif +#endif + +#ifdef CURSES_UNICODE + setlocale(LC_CTYPE, ""); +#ifdef PDCURSES + /* Assume the DOSVGA port of PDCursesMod, or the SDL1 or SDL2 port of + either PDCurses or PDCursesMod. Honor the font_map option to set + a font. + On MS-DOS, if no font_map is set, use ter-u16v.psf if it is present. + PDC_FONT has no effect on other PDCurses or PDCursesMod ports. */ + if (iflags.wc_font_map && iflags.wc_font_map[0]) { + Snprintf(pdc_font, sizeof(pdc_font), "PDC_FONT=%s", + iflags.wc_font_map); +#ifdef MSDOS + } else if (access("ter-u16v.psf", R_OK) >= 0) { + Snprintf(pdc_font, sizeof(pdc_font), "PDC_FONT=ter-u16v.psf"); +#endif + } + if (pdc_font[0] != '\0') { + putenv(pdc_font); + } +#endif +#endif + + /* if anything has already been output by nethack (for instance, warnings + about RC file issues), let the player acknowlege it before initscr() + erases the screen */ + if (iflags.raw_printed) + curses_wait_synch(); #ifdef XCURSES base_term = Xinitscr(*argcp, argv); #else base_term = initscr(); #endif -#ifdef TEXTCOLOR if (has_colors()) { start_color(); curses_init_nhcolors(); } else { iflags.use_color = FALSE; - set_option_mod_status("color", SET_IN_FILE); + set_option_mod_status("color", set_in_config); iflags.wc2_guicolor = FALSE; - set_wc2_option_mod_status(WC2_GUICOLOR, SET_IN_FILE); + set_wc2_option_mod_status(WC2_GUICOLOR, set_in_config); } -#else - iflags.use_color = FALSE; - set_option_mod_status("color", SET_IN_FILE); - iflags.wc2_guicolor = FALSE; - set_wc2_option_mod_status(WC2_GUICOLOR, SET_IN_FILE); -#endif noecho(); raw(); nonl(); /* don't force ^M into newline (^J); input accepts them both @@ -192,21 +244,33 @@ curses_init_nhwindows(int *argcp UNUSED, #ifdef PDCURSES # ifdef DEF_GAME_NAME # ifdef VERSION_STRING - sprintf(window_title, "%s %s", DEF_GAME_NAME, VERSION_STRING); + Snprintf(window_title, sizeof window_title, "%s %s", + DEF_GAME_NAME, VERSION_STRING); # else - sprintf(window_title, "%s", DEF_GAME_NAME); + if (nomakedefs.version_string) + Snprintf(window_title, sizeof window_title, "%s %s", + DEF_GAME_NAME, nomakedefs.version_string); + else + Snprintf(window_title, sizeof window_title, "%s", DEF_GAME_NAME); # endif /* VERSION_STRING */ # else # ifdef VERSION_STRING - sprintf(window_title, "%s %s", "NetHack", VERSION_STRING); + Snprintf(window_title, sizeof window_title, "%s %s", + "NetHack", VERSION_STRING); # else - sprintf(window_title, "%s", "NetHack"); + if (nomakedefs.version_string) + Snprintf(window_title, sizeof window_title, "%s %s", + "NetHack", nomakedefs.version_string); + else + Snprintf(window_title, sizeof window_title, "%s", "NetHack"); # endif /* VERSION_STRING */ # endif/* DEF_GAME_NAME */ PDC_set_title(window_title); PDC_set_blink(TRUE); /* Only if the user asks for it! */ + /* disable the default paste function so control-V works as expected */ + PDC_set_function_key(FUNCTION_KEY_PASTE, 0); timeout(1); (void) getch(); timeout(-1); @@ -230,36 +294,52 @@ curses_init_nhwindows(int *argcp UNUSED, curses_display_splash_window(); } -/* Do a window-port specific player type selection. If player_selection() - offers a Quit option, it is its responsibility to clean up and terminate - the process. You need to fill in pl_character[0]. -*/ +/* Use the general role/race/&c selection originally implemented for tty. */ void -curses_player_selection() +curses_player_selection(void) { +#if 1 + if (genl_player_setup(0)) + return; /* success */ + + /* quit/cancel */ + curses_bail((const char *) NULL); + /*NOTREACHED*/ +#else + /* still present cursinit.c but no longer used */ curses_choose_character(); +#endif } /* Ask the user for a player name. */ void -curses_askname() +curses_askname(void) { #ifdef SELECTSAVED if (iflags.wc2_selectsaved && !iflags.renameinprogress) switch (restore_menu(MAP_WIN)) { - case -1: - curses_bail("Until next time then..."); /* quit */ - /*NOTREACHED*/ - case 0: - break; /* no game chosen; start new game */ - case 1: - return; /* plname[] has been set */ + case -1: /* quit */ + goto bail; + case 0: /* new game */ + break; + case 1: /* picked a save file to restore and set plname[] for it */ + return; } #endif /* SELECTSAVED */ - plname[0] = '\0'; - curses_line_input_dialog("Who are you?", plname, PL_NSIZ); + curses_line_input_dialog("Who are you?", svp.plname, PL_NSIZ); + (void) mungspaces(svp.plname); + if (!svp.plname[0] || svp.plname[0] == '\033') + goto bail; + + iflags.renameallowed = TRUE; /* tty uses this, we don't [yet?] */ + return; + + bail: + /* message is delivered via raw_print() */ + curses_bail("\nUntil next time then...\n"); + /*NOTREACHED*/ } @@ -267,7 +347,7 @@ curses_askname() A noop for the tty and X window-ports. */ void -curses_get_nh_event() +curses_get_nh_event(void) { boolean do_reset = FALSE; @@ -295,6 +375,19 @@ curses_get_nh_event() } } +/* restore terminal state; extracted from curses_exit_nhwindows() */ +void +curses_uncurse_terminal(void) +{ + /* also called by panictrace_handler(), a signal handler, so somewhat + iffy in that situation; but without this, newlines behave as raw + line feeds so subsequent backtrace gets scrawled all over the screen + and is nearly useless */ + curses_cleanup(); + curs_set(orig_cursor); + endwin(); +} + /* Exits the window system. This should dismiss all windows, except the "window" used for raw_print(). str is printed if possible. */ @@ -307,9 +400,8 @@ curses_exit_nhwindows(const char *str) curses_destroy_nhwindow(MESSAGE_WIN); curs_destroy_all_wins(); - curses_cleanup(); - curs_set(orig_cursor); - endwin(); + curses_uncurse_terminal(); + iflags.window_inited = 0; if (str != NULL) { raw_print(str); @@ -326,7 +418,7 @@ curses_suspend_nhwindows(const char *str UNUSED) /* Restore the windows after being suspended. */ void -curses_resume_nhwindows() +curses_resume_nhwindows(void) { curses_refresh_nethack_windows(); } @@ -343,8 +435,14 @@ curses_create_nhwindow(int type) { winid wid = curses_get_wid(type); + if (curses_is_menu(wid)) + curses_parse_wid_colors(MENU_WIN, iflags.wcolors[wcolor_menu].fg, + iflags.wcolors[wcolor_menu].bg); + else if (curses_is_text(wid)) + curses_parse_wid_colors(TEXT_WIN, iflags.wcolors[wcolor_text].fg, + iflags.wcolors[wcolor_text].bg); if (curses_is_menu(wid) || curses_is_text(wid)) { - curses_start_menu(wid); + curses_start_menu(wid, MENU_BEHAVE_STANDARD); curses_add_wid(wid); } @@ -376,13 +474,16 @@ curses_clear_nhwindow(winid wid) --more--, if necessary, in the tty window-port. */ void -curses_display_nhwindow(winid wid, BOOLEAN_P block) +curses_display_nhwindow(winid wid, boolean block) { menu_item *selected = NULL; + int border = curses_window_has_border(wid) ? 1 : 0; + if (wid == WIN_ERR) + return; if (curses_is_menu(wid) || curses_is_text(wid)) { curses_end_menu(wid, ""); - curses_select_menu(wid, PICK_NONE, &selected); + (void) curses_select_menu(wid, PICK_NONE, &selected); return; } @@ -390,8 +491,12 @@ curses_display_nhwindow(winid wid, BOOLEAN_P block) if (!iflags.window_inited && wid == MAP_WIN) { iflags.window_inited = TRUE; } else { + WINDOW *win = curses_get_nhwin(wid); + /* actually display the window */ - wnoutrefresh(curses_get_nhwin(wid)); + wnoutrefresh(win); + if (border) + box(win, 0, 0); /* flush pending writes from other windows too */ doupdate(); } @@ -420,6 +525,7 @@ curses_destroy_nhwindow(winid wid) curses_status_finish(); /* discard cached status data */ break; case INV_WIN: + curs_purge_perminv_data(TRUE); iflags.perm_invent = 0; /* avoid unexpected update_inventory() */ break; case MAP_WIN: @@ -471,6 +577,13 @@ curses_putstr(winid wid, int attr, const char *text) mesgflags = attr & (ATR_URGENT | ATR_NOHISTORY); attr &= ~mesgflags; + /* this is comparable to tty's cw->flags &= ~WIN_STOP; if messages are + being suppressed after >>ESC, override that and resume showing them */ + if ((mesgflags & ATR_URGENT) != 0) { + curs_mesg_suppress_seq = -1L; + curs_mesg_no_suppress = TRUE; + } + if (wid == WIN_MESSAGE && (mesgflags & ATR_NOHISTORY) != 0) { /* display message without saving it in recall history */ curses_count_window(text); @@ -479,13 +592,54 @@ curses_putstr(winid wid, int attr, const char *text) curses_attr = curses_convert_attr(attr); curses_puts(wid, curses_attr, text); } + + /* urgent message handling is a one-shot operation; we're done */ + curs_mesg_no_suppress = FALSE; +} + +void +curses_putmixed(winid window, int attr, const char *str) +{ + const char *substr = 0; + char buf[BUFSZ]; + boolean done_output = FALSE; +#ifdef ENHANCED_SYMBOLS + int utf8flag = 0; +#endif + + if (window == WIN_MESSAGE) { + str = mixed_to_glyphinfo(str, &mesg_gi); + mesg_mixed = 1; + } else { + if ((substr = strstri(str, "\\G")) != 0) { +#ifdef ENHANCED_SYMBOLS + if ((windowprocs.wincap2 & WC2_U_UTF8STR) && SYMHANDLING(H_UTF8)) { + mixed_to_utf8(buf, sizeof buf, str, &utf8flag); + } else { +#endif + decode_mixed(buf, str); +#ifdef ENHANCED_SYMBOLS + } +#endif + /* now send buf to the normal putstr */ + curses_putstr(window, attr, buf); + done_output = TRUE; + } + } + + if (!done_output) { + /* just send str to the normal putstr */ + curses_putstr(window, attr, str); + } + if (window == WIN_MESSAGE) + mesg_mixed = 0; } /* Display the file named str. Complain about missing files iff complain is TRUE. */ void -curses_display_file(const char *filename, BOOLEAN_P must_exist) +curses_display_file(const char *filename, boolean must_exist) { curses_view_file(filename, must_exist); } @@ -496,18 +650,20 @@ curses_display_file(const char *filename, BOOLEAN_P must_exist) be used for menus. */ void -curses_start_menu(winid wid) +curses_start_menu(winid wid, unsigned long mbehavior) { if (inv_update) return; - curses_create_nhmenu(wid); + curses_create_nhmenu(wid, mbehavior); } /* -add_menu(winid wid, int glyph, const anything identifier, +add_menu(winid wid, const glyph_info *glyphinfo, + const anything identifier, char accelerator, char groupacc, - int attr, char *str, boolean preselected) + int attr, int color, + char *str, unsigned int itemflags) -- Add a text line str to the given menu window. If identifier is 0, then the line cannot be selected (e.g. a title). Otherwise, identifier is the value returned if the line is @@ -517,7 +673,8 @@ add_menu(winid wid, int glyph, const anything identifier, accelerator. It is up to the window-port to make the accelerator visible to the user (e.g. put "a - " in front of str). The value attr is the same as in putstr(). - Glyph is an optional glyph to accompany the line. If + -- Glyph is an optional glyph to accompany the line and its + modifiers (if any) can be found in glyphinfo. If window port cannot or does not want to display it, this is OK. If there is no glyph applicable, then this value will be NO_GLYPH. @@ -533,26 +690,32 @@ add_menu(winid wid, int glyph, const anything identifier, The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the - menu is displayed, set preselected to TRUE. + menu is displayed, set bit MENU_ITEMFLAGS_SELECTED. */ void -curses_add_menu(winid wid, int glyph, const ANY_P * identifier, - CHAR_P accelerator, CHAR_P group_accel, int attr, - const char *str, BOOLEAN_P presel) +curses_add_menu(winid wid, const glyph_info *glyphinfo, + const ANY_P *identifier, + char accelerator, char group_accel, int attr, + int clr, const char *str, unsigned itemflags) { int curses_attr; attr &= ~(ATR_URGENT | ATR_NOHISTORY); curses_attr = curses_convert_attr(attr); + /* 'inv_update': 0 for normal menus, 1 and up for perminv window */ if (inv_update) { - curses_add_inv(inv_update, glyph, accelerator, curses_attr, str); + /* persistent inventory window; nothing is selectable; + omit glyphinfo because perm_invent is to the side of + the map so usually cramped for horizontal space */ + curs_add_invt(inv_update, accelerator, curses_attr, clr, str); inv_update++; return; } - curses_add_nhmenu_item(wid, glyph, identifier, accelerator, group_accel, - curses_attr, str, presel); + curses_add_nhmenu_item(wid, glyphinfo, identifier, + accelerator, group_accel, + curses_attr, clr, str, itemflags); } /* @@ -608,34 +771,85 @@ curses_select_menu(winid wid, int how, MENU_ITEM_P ** selected) } void -curses_update_inventory(void) +curses_update_inventory(int arg) { - /* Don't do anything if perm_invent is off unless we - changed the option. */ + /* Don't do anything if perm_invent is off unless it was on and + player just changed the option. */ if (!iflags.perm_invent) { if (curses_get_nhwin(INV_WIN)) { curs_reset_windows(TRUE, FALSE); + curs_purge_perminv_data(FALSE); } return; } - /* Update inventory sidebar. NetHack uses normal menu functions - when drawing the inventory, and we don't want to change the - underlying code. So instead, track if an inventory update is - being performed with a static variable. */ - inv_update = 1; - curses_update_inv(); - inv_update = 0; + /* skip inventory updating during character initialization */ + if (!program_state.in_moveloop && !program_state.gameover) + return; + + if (!arg) { + /* if perm_invent is just being toggled on, we need to run the + update twice; the first time creates the window and organizes + the screen to fit it in, the second time populates it; + needed if we're called from docrt() because the "organizes + the screen" part calls docrt() and that skips recursive calls */ + boolean no_inv_win_yet = !curses_get_nhwin(INV_WIN); + + /* Update inventory sidebar. NetHack uses normal menu functions + when gathering the inventory, and we don't want to change the + underlying code. So instead, track if an inventory update is + being performed with a static variable. */ + inv_update = 1; + curs_update_invt(0); + if (no_inv_win_yet) + curs_update_invt(0); + inv_update = 0; + } else { + /* perform scrolling operations on persistent inventory window */ + curs_update_invt(arg); + } +} + +win_request_info * +curses_ctrl_nhwindow( + winid window UNUSED, + int request, + win_request_info *wri) +{ + int attr; + + if (!wri) + return (win_request_info *) 0; + + switch (request) { + case set_mode: + case request_settings: + break; + case set_menu_promptstyle: + curses_menu_promptstyle.color = wri->fromcore.menu_promptstyle.color; + if (curses_menu_promptstyle.color == NO_COLOR) + curses_menu_promptstyle.color = NONE; + attr = wri->fromcore.menu_promptstyle.attr; + curses_menu_promptstyle.attr = curses_convert_attr(attr);; + break; + default: + break; + } + return wri; } /* mark_synch() -- Don't go beyond this point in I/O on any channel until - all channels are caught up to here. Can be an empty call - for the moment + all channels are caught up to here. */ void -curses_mark_synch() +curses_mark_synch(void) { + /* full refresh has unintended side-effect of making a menu window + that has called core's get_count() to vanish; do a basic screen + refresh instead */ + /*curses_refresh_nethack_windows();*/ + refresh(); } /* @@ -645,8 +859,32 @@ wait_synch() -- Wait until all pending output is complete (*flush*() for display is OK when return from wait_synch(). */ void -curses_wait_synch() +curses_wait_synch(void) { + if (iflags.raw_printed) { +#ifndef PDCURSES + int chr; + /* + * If any message has been issued via raw_print(), make the user + * acknowledge it. This might take place before initscr() so + * access to curses is limited. [Despite that, there's probably + * a more curses-specific way to handle this. FIXME?] + */ + + (void) fprintf(stdout, "\nPress to continue: "); + (void) fflush(stdout); + do { + chr = fgetc(stdin); + } while (chr > 0 && chr != C('j') && chr != C('m') && chr != '\033'); +#endif + iflags.raw_printed = 0; + } + + if (iflags.window_inited) { + if (curses_got_output()) + (void) curses_more(); + curses_mark_synch(); + } /* [do we need 'if (counting) curses_count_window((char *)0);' here?] */ } @@ -667,27 +905,67 @@ curses_cliparound(int x, int y) } /* -print_glyph(window, x, y, glyph, bkglyph) - -- Print the glyph at (x,y) on the given window. Glyphs are - integers at the interface, mapped to whatever the window- +print_glyph(window, x, y, glyphinfo, bkglyphinfo) + -- Print glyph at (x,y) on the given window. Glyphs are + integers within the glyph_info struct that is passed + at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). - bkglyph is to render the background behind the glyph. + bkglyphinfo is to render the background behind the glyph. It's not used here. + -- bkglyphinfo contains a background glyph for potential use + by some graphical or tiled environments to allow the + depiction to fall against a background consistent with + the grid around x,y. If bkglyphinfo->glyph is NO_GLYPH, + then the parameter should be ignored (do nothing with it). + -- glyph_info struct fields: + int glyph; the display entity + int color; color for window ports not using a tile + int ttychar; the character mapping for the original tty + interface. Most or all window ports wanted + and used this for various things so it is + provided in 5.0+ + short int symidx; offset into syms array + unsigned glyphflags; more detail about the entity + */ + void -curses_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, - int bkglyph UNUSED) +curses_print_glyph( + winid wid, + coordxy x, coordxy y, + const glyph_info *glyphinfo, + const glyph_info *bkglyphinfo) { + int glyph; int ch; int color; + int nhcolor = 0; unsigned int special; int attr = -1; - /* map glyph to character and color */ - mapglyph(glyph, &ch, &color, &special, x, y, 0); + glyph = glyphinfo->glyph; + special = glyphinfo->gm.glyphflags; + ch = glyphinfo->ttychar; + color = glyphinfo->gm.sym.color; + /* Extra color handling + * FIQ: The curses library does not support truecolor, only the more limited 256 + * color mode. On top of this, the windowport only supports 16 color mode. + * Thus, we only allow users to customize glyph colors to the basic NetHack + * colors. */ + if (glyphinfo->gm.customcolor != 0 + && (curses_procs.wincap2 & WC2_EXTRACOLORS) != 0) { + if ((glyphinfo->gm.customcolor & NH_BASIC_COLOR) != 0) { + color = COLORVAL(glyphinfo->gm.customcolor); +#if 0 + } else { + /* 24-bit color, NH_BASIC_COLOR == 0 */ + nhcolor = COLORVAL(glyphinfo->gm.customcolor); +#endif + } + } if ((special & MG_PET) && iflags.hilite_pet) { - attr = iflags.wc2_petattr; + attr = curses_convert_attr(iflags.wc2_petattr); } if ((special & MG_DETECT) && iflags.use_inverse) { attr = A_REVERSE; @@ -703,18 +981,34 @@ curses_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, */ if ((special & MG_OBJPILE) && iflags.hilite_pile) { if (iflags.wc_color) - color = 16 + (color * 2) + 1; - else + color = get_framecolor(color, CLR_BLUE); + else /* if (iflags.use_inverse) */ attr = A_REVERSE; } - /* water and lava look the same except for color; when color is off, - render lava in inverse video so that they look different */ - if ((special & MG_BW_LAVA) && iflags.use_inverse) { - attr = A_REVERSE; /* mapglyph() only sets this if color is off */ + /* water and lava look the same except for color; when color is off + (checked by core), render lava in inverse video so that it looks + different from water; similar for floor vs ice, fountain vs sink, + and corridor vs engranving-in-corridor */ + if ((special & (MG_BW_LAVA | MG_BW_ICE | MG_BW_SINK | MG_BW_ENGR)) + != 0 && iflags.use_inverse) { + /* reset_glyphmap() only sets MG_BW_foo if color is off */ + attr = A_REVERSE; + } + /* highlight female monsters (wizard mode option) */ + if ((special & MG_FEMALE) && wizard && iflags.wizmgender) { + attr = A_REVERSE; } } - curses_putch(wid, x, y, ch, color, attr); + curses_putch(wid, x, y, ch, +#ifdef ENHANCED_SYMBOLS + (SYMHANDLING(H_UTF8) + && glyphinfo->gm.u && glyphinfo->gm.u->utf8str) + ? glyphinfo->gm.u : NULL, +#endif + (nhcolor != 0) ? nhcolor : color, + bkglyphinfo->framecolor, attr); + } /* @@ -730,12 +1024,15 @@ void curses_raw_print(const char *str) { #ifdef PDCURSES - WINDOW *win = curses_get_nhwin(MESSAGE_WIN); + /* WINDOW *win = curses_get_nhwin(MESSAGE_WIN); */ - curses_message_win_puts(str, FALSE); -#else - puts(str); + if (iflags.window_inited) { + curses_message_win_puts(str, FALSE); + return; + } #endif + puts(str); + iflags.raw_printed++; } /* @@ -755,19 +1052,25 @@ int nhgetch() -- Returns a single character input from the user. Returned character _must_ be non-zero. */ int -curses_nhgetch() +curses_nhgetch(void) { int ch; - curses_prehousekeeping(); + /* curses_prehousekeeping() assumes that the map window is active; + avoid it when a menu is active */ + if (!activemenu) + curses_prehousekeeping(); + ch = curses_read_char(); - curses_posthousekeeping(); + + if (!activemenu) + curses_posthousekeeping(); return ch; } /* -int nh_poskey(int *x, int *y, int *mod) +int nh_poskey(coordxy *x, coordxy *y, int *mod) -- Returns a single character input from the user or a a positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, @@ -782,7 +1085,7 @@ int nh_poskey(int *x, int *y, int *mod) routine always returns a non-zero character. */ int -curses_nh_poskey(int *x, int *y, int *mod) +curses_nh_poskey(coordxy *x, coordxy *y, int *mod) { int key = curses_nhgetch(); @@ -791,6 +1094,10 @@ curses_nh_poskey(int *x, int *y, int *mod) if (key == KEY_MOUSE) { key = curses_get_mouse(x, y, mod); } +#else + nhUse(x); + nhUse(y); + nhUse(mod); #endif return key; @@ -801,9 +1108,10 @@ nhbell() -- Beep at user. [This will exist at least until sounds are redone, since sounds aren't attributable to windows anyway.] */ void -curses_nhbell() +curses_nhbell(void) { - beep(); + if (!flags.silent) + beep(); } /* @@ -812,7 +1120,7 @@ doprev_message() -- On the tty-port this scrolls WIN_MESSAGE back one line. */ int -curses_doprev_message() +curses_doprev_message(void) { curses_prev_mesg(); return 0; @@ -838,7 +1146,7 @@ char yn_function(const char *ques, const char *choices, char default) ports might use a popup. */ char -curses_yn_function(const char *question, const char *choices, CHAR_P def) +curses_yn_function(const char *question, const char *choices, char def) { return (char) curses_character_input_dialog(question, choices, def); } @@ -866,7 +1174,7 @@ int get_ext_cmd(void) selection, -1 otherwise. */ int -curses_get_ext_cmd() +curses_get_ext_cmd(void) { return curses_ext_cmd(); } @@ -888,43 +1196,28 @@ delay_output() -- Causes a visible delay of 50ms in the output. by a nap(50ms), but allows asynchronous operation. */ void -curses_delay_output() -{ - /* refreshing the whole display is a waste of time, - * but that's why we're here */ - refresh(); - napms(50); -} - -/* -start_screen() -- Only used on Unix tty ports, but must be declared for - completeness. Sets up the tty to work in full-screen - graphics mode. Look at win/tty/termcap.c for an - example. If your window-port does not need this function - just declare an empty function. -*/ -void -curses_start_screen() -{ -} - -/* -end_screen() -- Only used on Unix tty ports, but must be declared for - completeness. The complement of start_screen(). -*/ -void -curses_end_screen() +curses_delay_output(void) { +#ifdef TIMED_DELAY + if (flags.nap && !iflags.debug_fuzzer) { + /* refreshing the whole display is a waste of time, + * but that's why we're here */ + curses_update_stdscr_cursor(); + refresh(); + napms(50); + } +#endif } /* outrip(winid, int) - -- The tombstone code. If you want the traditional code use - genl_outrip for the value and check the #if in rip.c. + -- The tombstone code. We use genl_outrip() from rip.c + instead of rolling our own. */ void curses_outrip(winid wid UNUSED, - int how UNUSED) + int how UNUSED, + time_t when UNUSED) { return; } @@ -974,7 +1267,7 @@ curs_reset_windows(boolean redo_main, boolean redo_status) } if (need_redraw) { curses_last_messages(); - doredraw(); + docrt(); } } @@ -990,13 +1283,21 @@ dummy_update_position_bar(char *arg UNUSED) #ifdef CHANGE_COLOR static void -dummy_change_color(int a1 UNUSED, long a2 UNUSED, int a3 UNUSED) +curses_change_color(int color, long rgb, int reverse UNUSED) { - return; + short r, g, b; + + if (!can_change_color()) + return; + + r = (rgb >> 16) & 0xFF; + g = (rgb >> 8) & 0xFF; + b = rgb & 0xFF; + init_color(color % 16, r * 4, g * 4, b * 4); } static char * -dummy_get_color_string(VOID_ARGS) +curses_get_color_string(void) { return (char *) 0; } diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index f55085c8a..892369f63 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursmesg.c */ +/* NetHack 5.0 cursmesg.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -7,7 +7,7 @@ #include "hack.h" #include "wincurs.h" #include "cursmesg.h" -#include +#include "curswins.h" /* defined in sys//tty.c or cursmain.c as last resort; set up by curses_init_nhwindows() */ @@ -20,11 +20,33 @@ extern char erase_char, kill_char; /* player can type ESC at More>> prompt to avoid seeing more messages for the current move; but hero might get more than one move per turn, so the input routines need to be able to cancel this */ -long curs_mesg_suppress_turn = -1; +long curs_mesg_suppress_seq = -1L; +/* if a message is marked urgent, existing suppression will be overridden + so that messages resume being shown; this is used in case the urgent + message triggers More>> for the previous message and the player responds + with ESC; we need to avoid initiating suppression in that situation */ +boolean curs_mesg_no_suppress = FALSE; +/* curses_putmixed() will place information in these next two */ +int mesg_mixed = 0; +glyph_info mesg_gi; + +#ifndef CURSES_GENL_PUTMIXED +#if defined(PDC_WIDE) || defined(NCURSES_WIDECHAR) +#define USE_CURSES_PUTMIXED +#else /* WIDE */ +#ifdef NH_PRAGMA_MESSAGE +#ifdef _MSC_VER +#pragma message("Curses wide support not defined so NetHack curses message window functionality reduced") +#else +#pragma message "Curses wide support not defined so NetHack curses message window functionality reduced" +#endif /* _MSC_VER */ +#endif /* NH_PRAGMA_MESSAGE */ +#endif /* WIDE */ +#endif /* CURSES_GENL_PUTMIXED */ /* Message window routines for curses interface */ -/* Private declatations */ +/* Private declarations */ typedef struct nhpm { char *str; /* Message text */ @@ -38,6 +60,9 @@ static void unscroll_window(winid wid); static void directional_scroll(winid wid, int nlines); static void mesg_add_line(const char *mline); static nhprev_mesg *get_msg_line(boolean reverse, int mindex); +#ifdef USE_CURSES_PUTMIXED +static int curscolor(int nhcolor, boolean *boldon); +#endif static int turn_lines = 0; static int mx = 0; @@ -56,8 +81,13 @@ curses_message_win_puts(const char *message, boolean recursed) int height, width, border_space, linespace; char *tmpstr; WINDOW *win = curses_get_nhwin(MESSAGE_WIN); - boolean bold, border = curses_window_has_border(MESSAGE_WIN); + boolean bold, border = curses_window_has_border(MESSAGE_WIN), + adjustbold = FALSE; int message_length = (int) strlen(message); +#ifdef USE_CURSES_PUTMIXED + boolean have_mixed_leadin = FALSE; + cchar_t mixed_leadin_cchar[2]; +#endif #if 0 /* @@ -72,10 +102,11 @@ curses_message_win_puts(const char *message, boolean recursed) } #endif - if (curs_mesg_suppress_turn == moves) { + if (curs_mesg_suppress_seq == gh.hero_seq) { return; /* user has typed ESC to avoid seeing remaining messages. */ } + curses_set_wid_colors(MESSAGE_WIN, NULL); curses_get_window_size(MESSAGE_WIN, &height, &width); border_space = (border ? 1 : 0); if (mx < border_space) @@ -84,35 +115,70 @@ curses_message_win_puts(const char *message, boolean recursed) my = border_space; if (strcmp(message, "#") == 0) { /* Extended command or Count: */ - if ((strcmp(toplines, "#") != 0) + if ((strcmp(gt.toplines, "#") != 0) /* Bottom of message window */ && (my >= (height - 1 + border_space)) && (height != 1)) { scroll_window(MESSAGE_WIN); mx = width; my--; - Strcpy(toplines, message); + Strcpy(gt.toplines, message); } return; } if (!recursed) { - strcpy(toplines, message); + strcpy(gt.toplines, message); mesg_add_line(message); } - /* -2: room for trailing ">>" (if More>> is needed) or leading " " - (if combining this message with preceding one) */ - linespace = (width - 1) - 2 - (mx - border_space); + /* -3: room for trailing ">> " (in case More>> is needed) */ + linespace = width - 3 - (mx - border_space); + /* -2: for leading " " (if combining this message with preceding one) */ + if (mx > border_space) + linespace -= 2; + bold = (height > 1 && !last_messages); + +#ifdef USE_CURSES_PUTMIXED + if (mesg_mixed) { + wchar_t w[2]; + int leadin_color; + + leadin_color = curscolor(mesg_gi.gm.sym.color, &adjustbold); + /* + * curses_putmixed() skipped past the \GNNNNNNNN encoding + * in the string, and filled in the mesg_gi glyphinfo. It + * flagged that to us by setting mesg_mixed. + */ + + w[0] = (wchar_t) mesg_gi.ttychar; +#ifdef ENHANCED_SYMBOLS + if ((windowprocs.wincap2 & WC2_U_UTF8STR) && SYMHANDLING(H_UTF8) + && mesg_gi.gm.u) { + /* FIXME: this won't work with all unicode values (32 bits -> 16 + * bits on Windows) */ + w[0] = (wchar_t) mesg_gi.gm.u->utf32ch; + } +#endif + w[1] = L'\0'; + if (setcchar(mixed_leadin_cchar, w, + (bold || adjustbold) ? A_BOLD : A_NORMAL, + leadin_color, 0) == OK) { + have_mixed_leadin = TRUE; + message_length++; /* account for that additional column */ + } + } +#endif /* USE_CURSES_PUTMIXED */ if (linespace < message_length) { if (my - border_space >= height - 1) { /* bottom of message win */ if (++turn_lines > height || (turn_lines == height && mx > border_space)) { - /* Pause until key is hit - Esc suppresses any further - messages that turn */ - if (curses_more() == '\033') { - curs_mesg_suppress_turn = moves; + /* pause until key is hit - ESC suppresses further messages + this turn unless an urgent message is being delivered */ + if (curses_more() == '\033' + && !curs_mesg_no_suppress) { + curs_mesg_suppress_seq = gh.hero_seq; return; } /* turn_lines reset to 0 by more()->block()->got_input() */ @@ -135,38 +201,87 @@ curses_message_win_puts(const char *message, boolean recursed) } } - bold = (height > 1 && !last_messages); - if (bold) + if (bold || adjustbold) curses_toggle_color_attr(win, NONE, A_BOLD, ON); /* will this message fit as-is or do we need to split it? */ - if (mx == border_space && message_length > width - 2) { + if (mx == border_space && message_length > width - 3) { /* split needed */ - tmpstr = curses_break_str(message, (width - 2), 1); + tmpstr = curses_break_str(message, (width - 3), 1); +#ifdef USE_CURSES_PUTMIXED + if (have_mixed_leadin) { + mvwadd_wch(win, my, mx, mixed_leadin_cchar); + ++mx; + message_length--; + mesg_mixed = 0; + have_mixed_leadin = FALSE; + nhUse(have_mixed_leadin); + } +#endif mvwprintw(win, my, mx, "%s", tmpstr), mx += (int) strlen(tmpstr); /* one space to separate first part of message from rest [is this actually useful?] */ - if (mx < width - 2) + if (mx < width) ++mx; free(tmpstr); - if (bold) + if (bold || adjustbold) curses_toggle_color_attr(win, NONE, A_BOLD, OFF); - tmpstr = curses_str_remainder(message, (width - 2), 1); + tmpstr = curses_str_remainder(message, (width - 3), 1); curses_message_win_puts(tmpstr, TRUE); free(tmpstr); } else { +#ifdef USE_CURSES_PUTMIXED + if (have_mixed_leadin) { + mvwadd_wch(win, my, mx, mixed_leadin_cchar); + ++mx; + message_length--; + mesg_mixed = 0; + have_mixed_leadin = FALSE; + nhUse(have_mixed_leadin); + } +#endif mvwprintw(win, my, mx, "%s", message), mx += message_length; - if (bold) + if (bold || adjustbold) curses_toggle_color_attr(win, NONE, A_BOLD, OFF); } wrefresh(win); } +#ifdef USE_CURSES_PUTMIXED +static int +curscolor(int nhcolor, boolean *boldon) +{ + int curses_color; + + *boldon = FALSE; + if (nhcolor == 0) { /* make black fg visible */ +#ifdef USE_DARKGRAY + if (iflags.wc2_darkgray) { + if (COLORS > 16) { + /* colorpair for black is already darkgray */ + } else { /* Use bold for a bright black */ + *boldon = TRUE; + } + } else +#endif /* USE_DARKGRAY */ + nhcolor = CLR_BLUE; + } + curses_color = nhcolor + 1; + if (COLORS < 16) { + if (curses_color > 8 && curses_color < 17) + curses_color -= 8; + else if (curses_color > (17 + 16)) + curses_color -= 16; + } + return curses_color; +} +#endif + void curses_got_input(void) { /* if messages are being suppressed, reenable them */ - curs_mesg_suppress_turn = -1; + curs_mesg_suppress_seq = -1L; /* misleadingly named; represents number of lines delivered since player was sure to have had a chance to read them; if player @@ -176,9 +291,16 @@ curses_got_input(void) } int -curses_block(boolean noscroll) /* noscroll - blocking because of msgtype - * = stop/alert else blocking because - * window is full, so need to scroll after */ +curses_got_output(void) +{ + return turn_lines; +} + +int +curses_block( + boolean noscroll) /* noscroll - blocking because of MSGTYPE=STOP/ALERT + * else blocking because window is full, so need to + * scroll after */ { static const char resp[] = " \r\n\033"; /* space, enter, esc */ static int prev_x = -1, prev_y = -1, blink = 0; @@ -204,6 +326,7 @@ curses_block(boolean noscroll) /* noscroll - blocking because of msgtype } moreattr = !iflags.wc2_guicolor ? (int) A_REVERSE : NONE; curses_toggle_color_attr(win, MORECOLOR, moreattr, ON); + curses_set_wid_colors(MESSAGE_WIN, NULL); if (blink) { wattron(win, A_BLINK); mvwprintw(win, my, mx, ">"), mx += 1; @@ -213,6 +336,7 @@ curses_block(boolean noscroll) /* noscroll - blocking because of msgtype mvwprintw(win, my, mx, ">>"), mx += 2; } curses_toggle_color_attr(win, MORECOLOR, moreattr, OFF); + curses_set_wid_colors(MESSAGE_WIN, NULL); wrefresh(win); /* cancel mesg suppression; all messages will have had chance to be read */ @@ -220,12 +344,17 @@ curses_block(boolean noscroll) /* noscroll - blocking because of msgtype oldcrsr = curs_set(1); do { - ret = wgetch(win); + if (iflags.debug_fuzzer) + ret = '\n'; + else + ret = curses_read_char(); + if (ret == ERR) + iflags.term_gone = 1; if (ret == ERR || ret == '\0') ret = '\n'; /* msgtype=stop should require space/enter rather than any key, as we want to prevent YASD from direction keys. */ - } while (!index(resp, (char) ret)); + } while (!strchr(resp, (char) ret)); if (oldcrsr >= 0) (void) curs_set(oldcrsr); @@ -242,7 +371,7 @@ curses_block(boolean noscroll) /* noscroll - blocking because of msgtype } int -curses_more() +curses_more(void) { return curses_block(FALSE); } @@ -251,13 +380,14 @@ curses_more() /* Clear the message window if one line; otherwise unhighlight old messages */ void -curses_clear_unhighlight_message_window() +curses_clear_unhighlight_message_window(void) { - int mh, mw, count, + int mh, mw, rx, ry, brdroffset = curses_window_has_border(MESSAGE_WIN) ? 1 : 0; WINDOW *win = curses_get_nhwin(MESSAGE_WIN); turn_lines = 0; + curses_set_wid_colors(MESSAGE_WIN, NULL); curses_get_window_size(MESSAGE_WIN, &mh, &mw); if (mh == 1) { @@ -266,9 +396,14 @@ curses_clear_unhighlight_message_window() } else { mx = mw + brdroffset; /* Force new line on new turn */ - for (count = 0; count < mh; count++) - mvwchgat(win, count + brdroffset, brdroffset, - mw, COLOR_PAIR(8), A_NORMAL, NULL); + for (ry = brdroffset; ry < mh; ry++) { + for (rx = brdroffset; rx < mw; rx++) { + chtype cht = mvwinch(win, ry, rx); + + mvwchgat(win, ry, rx, 1, A_NORMAL, PAIR_NUMBER(cht), NULL); + } + } + wnoutrefresh(win); } wmove(win, my, mx); @@ -279,13 +414,14 @@ curses_clear_unhighlight_message_window() recent messages. */ void -curses_last_messages() +curses_last_messages(void) { nhprev_mesg *mesg; int i, height, width; int border = curses_window_has_border(MESSAGE_WIN) ? 1 : 0; WINDOW *win = curses_get_nhwin(MESSAGE_WIN); + curses_set_wid_colors(MESSAGE_WIN, NULL); curses_get_window_size(MESSAGE_WIN, &height, &width); werase(win); mx = my = border; @@ -312,7 +448,7 @@ curses_last_messages() if (mesg && mesg->str && *mesg->str) curses_message_win_puts(mesg->str, TRUE); } - curses_message_win_puts(toplines, TRUE); + curses_message_win_puts(gt.toplines, TRUE); --last_messages; if (border) @@ -324,7 +460,7 @@ curses_last_messages() /* Initialize list for message history */ void -curses_init_mesg_history() +curses_init_mesg_history(void) { max_messages = iflags.msg_history; @@ -332,8 +468,8 @@ curses_init_mesg_history() max_messages = 1; } - if (max_messages > MESG_HISTORY_MAX) { - max_messages = MESG_HISTORY_MAX; + if (max_messages > MAX_MSG_HISTORY) { + max_messages = MAX_MSG_HISTORY; } } @@ -356,7 +492,7 @@ curses_teardown_messages(void) /* Display previous messages in a popup (via menu so can scroll backwards) */ void -curses_prev_mesg() +curses_prev_mesg(void) { int count; winid wid; @@ -365,22 +501,47 @@ curses_prev_mesg() nhprev_mesg *mesg; menu_item *selected = NULL; boolean do_lifo = (iflags.prevmsg_window != 'f'); +#ifdef DEBUG + static int showturn = 0; /* 1: show hero_seq value in separators */ + int clr = NO_COLOR; + + /* + * Set DEBUGFILES=MesgTurn in environment or sysconf to decorate + * separator line between blocks of messages with the turn they + * were issued. + */ + if (!showturn) + showturn = (wizard && explicitdebug("MesgTurn")) ? 1 : -1; +#endif wid = curses_get_wid(NHW_MENU); - curses_create_nhmenu(wid); - Id = zeroany; + curses_create_nhmenu(wid, 0UL); + Id = cg.zeroany; for (count = 0; count < num_messages; ++count) { mesg = get_msg_line(do_lifo, count); - if (turn != mesg->turn && count != 0) { - curses_add_menu(wid, NO_GLYPH, &Id, 0, 0, A_NORMAL, "---", FALSE); + if (mesg->turn != turn) { + if (count > 0) { /* skip separator for first line */ + char sepbuf[50]; + + Strcpy(sepbuf, "---"); +#ifdef DEBUG + if (showturn == 1) + Sprintf(sepbuf, "- %ld+%ld", + (mesg->turn >> 3), (mesg->turn & 7L)); +#endif + curses_add_menu(wid, &nul_glyphinfo, &Id, 0, 0, + A_NORMAL, clr, sepbuf, MENU_ITEMFLAGS_NONE); + } + turn = mesg->turn; } - curses_add_menu(wid, NO_GLYPH, &Id, 0, 0, A_NORMAL, mesg->str, FALSE); - turn = mesg->turn; + curses_add_menu(wid, &nul_glyphinfo, &Id, 0, 0, + A_NORMAL, clr, mesg->str, MENU_ITEMFLAGS_NONE); } if (!count) - curses_add_menu(wid, NO_GLYPH, &Id, 0, 0, A_NORMAL, - "[No past messages available.]", FALSE); + curses_add_menu(wid, &nul_glyphinfo, &Id, 0, 0, + A_NORMAL, clr, "[No past messages available.]", + MENU_ITEMFLAGS_NONE); curses_end_menu(wid, ""); if (!do_lifo) @@ -453,10 +614,15 @@ curses_count_window(const char *count_text) but not for dolook's autodescribe when it refers to a named monster */ if (!countwin) countwin = newwin(1, messagew, winy, winx); + curses_set_wid_colors(MESSAGE_WIN, NULL); werase(countwin); mvwprintw(countwin, 0, 0, "%s", count_text); wrefresh(countwin); + if (activemenu) { + touchwin(activemenu); + wrefresh(activemenu); + } } /* Gets a "line" (buffer) of input. */ @@ -594,7 +760,7 @@ curses_message_win_getline(const char *prompt, char *answer, int buffer) #ifdef PDCURSES ch = wgetch(win); #else - ch = getch(); + ch = curses_read_char(); #endif curs_set(0); @@ -611,6 +777,7 @@ curses_message_win_getline(const char *prompt, char *answer, int buffer) switch (ch) { case ERR: /* should not happen */ + iflags.term_gone = 1; *answer = '\0'; goto alldone; case '\033': /* DOESCAPE */ @@ -643,7 +810,7 @@ curses_message_win_getline(const char *prompt, char *answer, int buffer) case '\n': (void) strncpy(answer, p_answer, buffer); answer[buffer - 1] = '\0'; - Strcpy(toplines, tmpbuf); + Strcpy(gt.toplines, tmpbuf); mesg_add_line(tmpbuf); #if 1 /* position at end of current line so next message will be @@ -724,6 +891,7 @@ directional_scroll(winid wid, int nlines) boolean border = curses_window_has_border(wid); WINDOW *win = curses_get_nhwin(wid); + curses_set_wid_colors(wid, NULL); curses_get_window_size(wid, &wh, &ww); if (wh == 1) { curses_clear_nhwin(wid); @@ -769,6 +937,8 @@ mesg_add_line(const char *mline) } else { /* instead of discarding list element being forced out, reuse it */ current_mesg = first_mesg; + assert(current_mesg != NULL); + assert(current_mesg->str != NULL); /* whenever new 'mline' is shorter, extra allocation size of the original element will be frittered away, until eventually we'll discard this 'str' and dupstr() a replacement; we could easily @@ -780,7 +950,7 @@ mesg_add_line(const char *mline) current_mesg->str = dupstr(mline); } } - current_mesg->turn = moves; + current_mesg->turn = gh.hero_seq; if (num_messages == 0) { /* very first message; set up head */ @@ -797,8 +967,8 @@ mesg_add_line(const char *mline) ++num_messages; } else { /* at capacity; old head is being removed */ - first_mesg = first_mesg->next_mesg; /* new head */ - first_mesg->prev_mesg = NULL; /* head has no prev_mesg */ + if ((first_mesg = first_mesg->next_mesg) != 0) /* new head */ + first_mesg->prev_mesg = NULL; /* head has no prev_mesg */ } /* since 'current_mesg' might be reusing 'first_mesg' and has now become 'last_mesg', this update must be after head replacement */ @@ -836,8 +1006,7 @@ get_msg_line(boolean reverse, int mindex) puts it into save file; if any new messages are added to the list while that is taking place, the results are likely to be scrambled */ char * -curses_getmsghistory(init) -boolean init; +curses_getmsghistory(boolean init) { static int nxtidx; nhprev_mesg *mesg; @@ -880,16 +1049,12 @@ boolean init; * into message history for ^P recall without having displayed it. */ void -curses_putmsghistory(msg, restoring_msghist) -const char *msg; -boolean restoring_msghist; +curses_putmsghistory(const char *msg, boolean restoring_msghist) { + /* FIXME: these should be moved to struct instance_globals g */ static boolean initd = FALSE; static int stash_count; static nhprev_mesg *stash_head = 0; -#ifdef DUMPLOG - extern unsigned saved_pline_index; /* pline.c */ -#endif if (restoring_msghist && !initd) { /* hide any messages we've gathered since starting current session @@ -899,19 +1064,24 @@ boolean restoring_msghist; stash_head = first_mesg, first_mesg = (nhprev_mesg *) 0; last_mesg = (nhprev_mesg *) 0; /* no need to remember the tail */ initd = TRUE; -#ifdef DUMPLOG - /* this suffices; there's no need to scrub saved_pline[] pointers */ - saved_pline_index = 0; +#ifdef DUMPLOG_CORE + /* this suffices; there's no need to scrub g.saved_pline[] pointers */ + gs.saved_pline_index = 0; #endif } if (msg) { mesg_add_line(msg); - /* treat all saved and restored messages as turn #1 */ - last_mesg->turn = 1L; -#ifdef DUMPLOG - dumplogmsg(last_mesg->str); + /* treat all saved and restored messages as turn #1; + however, we aren't only called when restoring history; + core uses putmsghistory() for other stuff during play + and those messages should have a normal turn value */ + if (last_mesg) { /* appease static analyzer */ + last_mesg->turn = restoring_msghist ? (1L << 3) : gh.hero_seq; +#ifdef DUMPLOG_CORE + dumplogmsg(last_mesg->str); #endif + } } else if (stash_count) { nhprev_mesg *mesg; long mesg_turn; @@ -924,21 +1094,32 @@ boolean restoring_msghist; stashed messages as newly occurring ones is much simpler; we ignore the backlinks because the list is destroyed as it gets processed hence there can't be any other traversals */ - mesg = stash_head; - stash_head = mesg->next_mesg; - --stash_count; - mesg_turn = mesg->turn; - mesg_add_line(mesg->str); - /* added line became new tail */ - last_mesg->turn = mesg_turn; -#ifdef DUMPLOG - dumplogmsg(mesg->str); + if ((mesg = stash_head) != 0) { + stash_head = mesg->next_mesg; + --stash_count; + mesg_turn = mesg->turn; + mesg_add_line(mesg->str); + /* added line became new tail */ + if (last_mesg) /* appease static analyzer */ + last_mesg->turn = mesg_turn; +#ifdef DUMPLOG_CORE + dumplogmsg(mesg->str); #endif - free((genericptr_t) mesg->str); - free((genericptr_t) mesg); + free((genericptr_t) mesg->str); + free((genericptr_t) mesg); + } } initd = FALSE; /* reset */ } + + /* + * Restoring a game with window borders on and align_status:left + * (which pushes the starting column of the message window to the + * right) brings up an initial display where the border around + * the message window is missing. This draws it. + */ + if (restoring_msghist && !msg) + curses_last_messages(); } /*cursmesg.c*/ diff --git a/win/curses/cursmesg.h b/win/curses/cursmesg.h index ca0752eea..897170b4f 100644 --- a/win/curses/cursmesg.h +++ b/win/curses/cursmesg.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursmesg.h */ +/* NetHack 5.0 cursmesg.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -11,6 +11,7 @@ void curses_message_win_puts(const char *message, boolean recursed); void curses_got_input(void); +int curses_got_output(void); int curses_block(boolean require_tab); int curses_more(void); void curses_clear_unhighlight_message_window(void); @@ -19,7 +20,7 @@ void curses_last_messages(void); void curses_init_mesg_history(void); void curses_prev_mesg(void); void curses_count_window(const char *count_text); -char *curses_getmsghistory(BOOLEAN_P); -void curses_putmsghistory(const char *, BOOLEAN_P); +char *curses_getmsghistory(boolean); +void curses_putmsghistory(const char *, boolean); #endif /* CURSMESG_H */ diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index 0d813cfcf..3084d193a 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursmisc.c */ +/* NetHack 5.0 cursmisc.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,8 +10,6 @@ #include "func_tab.h" #include "dlb.h" -#include - /* Misc. curses interface functions */ /* Private declarations */ @@ -19,66 +17,49 @@ static int curs_x = -1; static int curs_y = -1; -static int parse_escape_sequence(void); +#if defined(PDCURSES) && defined(PDC_KEY_MODIFIER_ALT) +static unsigned long last_getch_modifiers = 0L; +static boolean modifiers_available = TRUE; +#else +static boolean modifiers_available = FALSE; +#endif -/* Macros for Control and Alt keys */ +static int modified(int ch); +static void update_modifiers(void); +static int parse_escape_sequence(int, boolean *); -#ifndef M -# ifndef NHSTDC -# define M(c) (0x80 | (c)) -# else -# define M(c) ((c) - 128) -# endif/* NHSTDC */ -#endif -#ifndef C -# define C(c) (0x1f & (c)) -#endif +#define SS3 M(C('O')) /* 8-bit escape sequence initiator for VT number pad */ +int +curses_getch(void) +{ + int ch; + + if (iflags.debug_fuzzer) + ch = randomkey(); + else + ch = getch(); + return ch; +} /* Read a character of input from the user */ int -curses_read_char() +curses_read_char(void) { int ch; -#if defined(ALT_0) || defined(ALT_9) || defined(ALT_A) || defined(ALT_Z) - int tmpch; -#endif /* cancel message suppression; all messages have had a chance to be read */ curses_got_input(); - ch = getch(); -#if defined(ALT_0) || defined(ALT_9) || defined(ALT_A) || defined(ALT_Z) - tmpch = ch; -#endif + ch = curses_getch(); ch = curses_convert_keys(ch); if (ch == 0) { ch = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ } -#if defined(ALT_0) && defined(ALT_9) /* PDCurses, maybe others */ - if ((ch >= ALT_0) && (ch <= ALT_9)) { - tmpch = (ch - ALT_0) + '0'; - ch = M(tmpch); - } -#endif - -#if defined(ALT_A) && defined(ALT_Z) /* PDCurses, maybe others */ - if ((ch >= ALT_A) && (ch <= ALT_Z)) { - tmpch = (ch - ALT_A) + 'a'; - ch = M(tmpch); - } -#endif -#ifdef KEY_RESIZE - /* Handle resize events via get_nh_event, not this code */ - if (ch == KEY_RESIZE) { - ch = C('r'); /* NetHack doesn't know what to do with KEY_RESIZE */ - } -#endif - - if (counting && !isdigit(ch)) { /* Dismiss count window if necissary */ + if (counting && !isdigit(ch)) { /* dismiss count window if necessary */ curses_count_window(NULL); curses_refresh_nethack_windows(); } @@ -91,15 +72,17 @@ curses_read_char() void curses_toggle_color_attr(WINDOW *win, int color, int attr, int onoff) { -#ifdef TEXTCOLOR + if (color == NO_COLOR) + color = NONE; + int curses_color; + boolean use_bold = FALSE; /* if color is disabled, just show attribute */ if ((win == mapwin) ? !iflags.wc_color /* statuswin is for #if STATUS_HILITES but doesn't need to be conditional */ : !(iflags.wc2_guicolor || win == statuswin)) { -#endif if (attr != NONE) { if (onoff == ON) wattron(win, attr); @@ -107,13 +90,12 @@ curses_toggle_color_attr(WINDOW *win, int color, int attr, int onoff) wattroff(win, attr); } return; -#ifdef TEXTCOLOR } - if (color == 0) { /* make black fg visible */ + if (color == CLR_BLACK) { /* make black fg visible */ # ifdef USE_DARKGRAY if (iflags.wc2_darkgray) { - if (can_change_color() && (COLORS > 16)) { + if (COLORS > 16) { /* colorpair for black is already darkgray */ } else { /* Use bold for a bright black */ wattron(win, A_BOLD); @@ -122,17 +104,23 @@ curses_toggle_color_attr(WINDOW *win, int color, int attr, int onoff) # endif/* USE_DARKGRAY */ color = CLR_BLUE; } - curses_color = color + 1; + if (COLORS < 16) { - if (curses_color > 8 && curses_color < 17) - curses_color -= 8; - else if (curses_color > (17 + 16)) - curses_color -= 16; + /* convert NetHack's 16 colors to 8 colors + BOLD */ + int fg = color % 16; + int bg = color / 16; + + if (fg > 7) + use_bold = TRUE; + + curses_color = (8 * (bg % 8)) + (fg % 8) + 1; + } else { + curses_color = color + 1; } + if (onoff == ON) { /* Turn on color/attributes */ if (color != NONE) { - if ((((color > 7) && (color < 17)) || - (color > 17 + 17)) && (COLORS < 16)) { + if (use_bold) { wattron(win, A_BOLD); } wattron(win, COLOR_PAIR(curses_color)); @@ -144,11 +132,11 @@ curses_toggle_color_attr(WINDOW *win, int color, int attr, int onoff) } else { /* Turn off color/attributes */ if (color != NONE) { - if ((color > 7) && (COLORS < 16)) { + if (use_bold) { wattroff(win, A_BOLD); } # ifdef USE_DARKGRAY - if ((color == 0) && (!can_change_color() || (COLORS <= 16))) { + if ((color == 0) && (COLORS <= 16)) { wattroff(win, A_BOLD); } # else @@ -163,9 +151,6 @@ curses_toggle_color_attr(WINDOW *win, int color, int attr, int onoff) wattroff(win, attr); } } -#else - nhUse(color); -#endif /* TEXTCOLOR */ } /* call curses_toggle_color_attr() with 'menucolors' instead of 'guicolor' @@ -179,7 +164,8 @@ curses_menu_color_attr(WINDOW *win, int color, int attr, int onoff) /* curses_toggle_color_attr() uses 'guicolor' to decide whether to honor specified color, but menu windows have their own more-specific control, 'menucolors', so override with that here */ - iflags.wc2_guicolor = iflags.use_menu_color; +/* iflags.wc2_guicolor = iflags.use_menu_color; */ + iflags.wc2_guicolor = (color != NONE); curses_toggle_color_attr(win, color, attr, onoff); iflags.wc2_guicolor = save_guicolor; } @@ -303,7 +289,7 @@ curses_break_str(const char *str, int width, int line_num) char *retstr; int curline = 0; int strsize = (int) strlen(str) + 1; -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) && !defined(_MSC_VER) char substr[strsize]; char curstr[strsize]; char tmpstr[strsize]; @@ -357,7 +343,12 @@ curses_break_str(const char *str, int width, int line_num) } if (curline < line_num) { +#if 0 return NULL; +#else + /* callers aren't prepared to handle NULL return */ + Strcpy(curstr, ""); +#endif } retstr = curses_copy_of(curstr); @@ -375,7 +366,7 @@ curses_str_remainder(const char *str, int width, int line_num) char *retstr; int curline = 0; int strsize = strlen(str) + 1; -#if __STDC_VERSION__ >= 199901L +#if (__STDC_VERSION__ >= 199901L) && !defined(_MSC_VER) char substr[strsize]; char tmpstr[strsize]; @@ -412,6 +403,7 @@ curses_str_remainder(const char *str, int width, int line_num) if (last_space == 0) { /* No spaces found */ last_space = count - 1; } + assert(IndexOk(last_space, substr)); if (substr[last_space] == '\0') { break; } @@ -620,11 +612,22 @@ curses_move_cursor(winid wid, int x, int y) } } +/* update the ncurses stdscr cursor to where the cursor in our map is */ +void +curses_update_stdscr_cursor(void) +{ +#ifndef PDCURSES + int xadj = 0, yadj = 0; + + curses_get_window_xy(MAP_WIN, &xadj, &yadj); + move(curs_y + yadj, curs_x + xadj); +#endif +} /* Perform actions that should be done every turn before nhgetch() */ void -curses_prehousekeeping() +curses_prehousekeeping(void) { #ifndef PDCURSES WINDOW *win = curses_get_nhwin(MAP_WIN); @@ -647,7 +650,7 @@ curses_prehousekeeping() /* Perform actions that should be done every turn after nhgetch() */ void -curses_posthousekeeping() +curses_posthousekeeping(void) { curs_set(0); /* curses_decrement_highlights(FALSE); */ @@ -663,6 +666,7 @@ curses_view_file(const char *filename, boolean must_exist) char buf[BUFSZ]; menu_item *selected = NULL; dlb *fp = dlb_fopen(filename, "r"); + int clr = NO_COLOR; if (fp == NULL) { if (must_exist) @@ -671,11 +675,12 @@ curses_view_file(const char *filename, boolean must_exist) } wid = curses_get_wid(NHW_MENU); - curses_create_nhmenu(wid); - Id = zeroany; + curses_create_nhmenu(wid, 0UL); + Id = cg.zeroany; while (dlb_fgets(buf, BUFSZ, fp) != NULL) { - curses_add_menu(wid, NO_GLYPH, &Id, 0, 0, A_NORMAL, buf, FALSE); + curses_add_menu(wid, &nul_glyphinfo, &Id, 0, 0, + A_NORMAL, clr, buf, FALSE); } dlb_fclose(fp); @@ -691,7 +696,8 @@ curses_rtrim(char *str) char *s; for (s = str; *s != '\0'; ++s); - for (--s; isspace(*s) && s > str; --s); + if (s > str) + for (--s; isspace(*s) && s > str; --s); if (s == str) *s = '\0'; else @@ -702,30 +708,27 @@ curses_rtrim(char *str) /* Read numbers until non-digit is encountered, and return number in int form. */ -int +long curses_get_count(int first_digit) { - long current_count = first_digit; int current_char; - - current_char = curses_read_char(); - - while (isdigit(current_char)) { - current_count = (current_count * 10) + (current_char - '0'); - if (current_count > LARGEST_INT) { - current_count = LARGEST_INT; - } - - custompline(SUPPRESS_HISTORY, "Count: %ld", current_count); - current_char = curses_read_char(); - } + long current_count = 0L; + + /* use core's count routine; we have the first digit; if any more + are typed, get_count() will send "Count:123" to the message window; + curses's message window will display that in count window instead */ + current_char = get_count(NULL, (char) first_digit, + /* 0L => no limit on value unless it wraps + * to negative */ + 0L, ¤t_count, + /* don't put into message history, echo full + * number rather than waiting until 2nd digit */ + GC_ECHOFIRST); ungetch(current_char); - if (current_char == '\033') { /* Cancelled with escape */ current_count = -1; } - return current_count; } @@ -733,10 +736,10 @@ curses_get_count(int first_digit) /* Convert the given NetHack text attributes into the format curses understands, and return that format mask. */ -int +attr_t curses_convert_attr(int attr) { - int curses_attr; + attr_t curses_attr; /* first, strip off control flags masked onto the display attributes (caller should have already done this...) */ @@ -761,6 +764,9 @@ curses_convert_attr(int attr) case ATR_INVERSE: curses_attr = A_REVERSE; break; + case ATR_ITALIC: + curses_attr = A_ITALIC; + break; default: curses_attr = A_NORMAL; } @@ -768,200 +774,138 @@ curses_convert_attr(int attr) return curses_attr; } - -/* Map letter attributes from a string to bitmask. Return mask on - success (might be 0), or -1 if not found. */ - -int -curses_read_attrs(const char *attrs) -{ - int retattr = 0; - - if (!attrs || !*attrs) - return A_NORMAL; - - if (strchr(attrs, 'b') || strchr(attrs, 'B')) - retattr |= A_BOLD; - if (strchr(attrs, 'i') || strchr(attrs, 'I')) /* inverse */ - retattr |= A_REVERSE; - if (strchr(attrs, 'u') || strchr(attrs, 'U')) - retattr |= A_UNDERLINE; - if (strchr(attrs, 'k') || strchr(attrs, 'K')) - retattr |= A_BLINK; - if (strchr(attrs, 'd') || strchr(attrs, 'D')) - retattr |= A_DIM; -#ifdef A_ITALIC - if (strchr(attrs, 't') || strchr(attrs, 'T')) - retattr |= A_ITALIC; -#endif -#ifdef A_LEFTLINE - if (strchr(attrs, 'l') || strchr(attrs, 'L')) - retattr |= A_LEFTLINE; -#endif -#ifdef A_RIGHTLINE - if (strchr(attrs, 'r') || strchr(attrs, 'R')) - retattr |= A_RIGHTLINE; -#endif - if (retattr == 0) { - /* still default; check for none/normal */ - if (strchr(attrs, 'n') || strchr(attrs, 'N')) - retattr = A_NORMAL; - else - retattr = -1; /* error */ - } - return retattr; -} - -/* format iflags.wc2_petattr into "+a+b..." for set bits a, b, ... - (used by core's 'O' command; return value points past leading '+') */ -char * -curses_fmt_attrs(outbuf) -char *outbuf; -{ - int attr = iflags.wc2_petattr; - - outbuf[0] = '\0'; - if (attr == A_NORMAL) { - Strcpy(outbuf, "+N(None)"); - } else { - if (attr & A_BOLD) - Strcat(outbuf, "+B(Bold)"); - if (attr & A_REVERSE) - Strcat(outbuf, "+I(Inverse)"); - if (attr & A_UNDERLINE) - Strcat(outbuf, "+U(Underline)"); - if (attr & A_BLINK) - Strcat(outbuf, "+K(blinK)"); - if (attr & A_DIM) - Strcat(outbuf, "+D(Dim)"); -#ifdef A_ITALIC - if (attr & A_ITALIC) - Strcat(outbuf, "+T(iTalic)"); -#endif -#ifdef A_LEFTLINE - if (attr & A_LEFTLINE) - Strcat(outbuf, "+L(Left line)"); -#endif -#ifdef A_RIGHTLINE - if (attr & A_RIGHTLINE) - Strcat(outbuf, "+R(Right line)"); -#endif - } - if (!*outbuf) - Sprintf(outbuf, "+unknown [%d]", attr); - return &outbuf[1]; -} - /* Convert special keys into values that NetHack can understand. Currently this is limited to arrow keys, but this may be expanded. */ - int curses_convert_keys(int key) { + boolean reject = (program_state.input_state == otherInp), + as_is = FALSE, numpad_esc = FALSE; int ret = key; - if (ret == '\033') { - ret = parse_escape_sequence(); - } + if (modifiers_available) + update_modifiers(); - /* Handle arrow keys */ + /* Handle arrow and keypad keys, but only when getting a command + (or a command-like keystroke for getpos() or getdir()). */ switch (key) { + case SS3: /* M-^O, 8-bit version of ESC 'O' c for keypad key */ + case '\033': /* ESC or ^[ */ + /* changes ESC c to M-c or number pad key to corresponding digit + (but we only get here via key==ESC if curses' getch() didn't + change the latter to KEY_xyz) */ + ret = parse_escape_sequence(key, &numpad_esc); + reject = ((uchar) ret < 1 || ret > 255); + as_is = !numpad_esc; /* don't perform phonepad inversion */ + break; case KEY_BACKSPACE: /* we can't distinguish between a separate backspace key and explicit Ctrl+H intended to rush to the left; without this, a value for ^H greater than 255 is passed back to core's readchar() and stripping the value down to 0..255 yields ^G! */ ret = C('H'); + FALLTHROUGH; + /*FALLTHRU*/ + default: + if (modifiers_available) + ret = modified(ret); +#if defined(ALT_A) && defined(ALT_Z) + /* for PDcurses, but doesn't handle Alt+X for upper case X; + ncurses doesn't have ALT_x definitions so we achieve a similar + effect via parse_escape_sequence(), and that works for upper + case and other non-letter, non-digit keys */ + if (ret >= ALT_A && ret <= ALT_Z) { + ret = (ret - ALT_A) + 'a'; + ret = M(ret); + } +#endif +#if defined(ALT_0) && defined(ALT_9) + if (ret >= ALT_0 && ret <= ALT_9) { + ret = (ret - ALT_0) + '0'; + ret = M(ret); + } +#endif + /* use key as-is unless it's out of normal char range */ + reject = ((uchar) ret < 1 || ret > 255); + as_is = TRUE; break; #ifdef KEY_B1 case KEY_B1: #endif case KEY_LEFT: - if (iflags.num_pad) { - ret = '4'; - } else { - ret = 'h'; - } + ret = iflags.num_pad ? '4' : 'h'; break; #ifdef KEY_B3 case KEY_B3: #endif case KEY_RIGHT: - if (iflags.num_pad) { - ret = '6'; - } else { - ret = 'l'; - } + ret = iflags.num_pad ? '6' : 'l'; break; #ifdef KEY_A2 case KEY_A2: #endif case KEY_UP: - if (iflags.num_pad) { - ret = '8'; - } else { - ret = 'k'; - } + ret = iflags.num_pad ? '8' : 'k'; break; #ifdef KEY_C2 case KEY_C2: #endif case KEY_DOWN: - if (iflags.num_pad) { - ret = '2'; - } else { - ret = 'j'; - } + ret = iflags.num_pad ? '2' : 'j'; break; #ifdef KEY_A1 case KEY_A1: #endif case KEY_HOME: - if (iflags.num_pad) { - ret = '7'; - } else { - ret = !Cmd.swap_yz ? 'y' : 'z'; - } + ret = iflags.num_pad ? '7' : (!gc.Cmd.swap_yz ? 'y' : 'z'); break; #ifdef KEY_A3 case KEY_A3: #endif case KEY_PPAGE: - if (iflags.num_pad) { - ret = '9'; - } else { - ret = 'u'; - } + ret = iflags.num_pad ? '9' : 'u'; break; #ifdef KEY_C1 case KEY_C1: #endif case KEY_END: - if (iflags.num_pad) { - ret = '1'; - } else { - ret = 'b'; - } + ret = iflags.num_pad ? '1' : 'b'; break; #ifdef KEY_C3 case KEY_C3: #endif case KEY_NPAGE: - if (iflags.num_pad) { - ret = '3'; - } else { - ret = 'n'; - } + ret = iflags.num_pad ? '3' : 'n'; break; #ifdef KEY_B2 case KEY_B2: - if (iflags.num_pad) { - ret = '5'; - } else { - ret = 'g'; - } + ret = iflags.num_pad ? '5' : 'g'; break; #endif /* KEY_B2 */ +#ifdef KEY_RESIZE + case KEY_RESIZE: + /* actual resize is handled elsewhere; just avoid beep/bell here */ + ret = '\033'; /* was C('R'); -- nethack's redraw command */ + reject = FALSE; + break; +#endif + } + + /* phone layout is inverted, 123 on top and 789 on bottom; if player has + set num_pad to deal with that, we need to invert here too but only + when some key has been converted into a digit, not for actual digit */ + if (iflags.num_pad && (iflags.num_pad_mode & 2) != 0 && !as_is) { + if (ret >= '1' && ret <= '3') + ret += 6; /* 1,2,3 -> 7,8,9 */ + else if (ret >= '7' && ret <= '9') + ret -= 6; /* 7,8,9 -> 1,2,3 */ + } + + if (reject) { + /* an arrow or function key has been pressed during text entry */ + curses_nhbell(); /* calls beep() which might cause unwanted screen + * refresh if terminal is set for 'visible bell' */ + ret = '\033'; /* ESC */ } return ret; @@ -988,7 +932,7 @@ event, or the first non-mouse key event in the case of mouse movement. */ int -curses_get_mouse(int *mousex, int *mousey, int *mod) +curses_get_mouse(coordxy *mousex, coordxy *mousey, int *mod) { int key = '\033'; @@ -1022,14 +966,17 @@ curses_get_mouse(int *mousex, int *mousey, int *mod) } } } +#else + nhUse(mousex); + nhUse(mousey); + nhUse(mod); #endif /* NCURSES_MOUSE_VERSION */ return key; } void -curses_mouse_support(mode) -int mode; /* 0: off, 1: on, 2: alternate on */ +curses_mouse_support(int mode) /* 0: off, 1: on, 2: alternate on */ { #ifdef NCURSES_MOUSE_VERSION mmask_t result, oldmask, newmask; @@ -1046,36 +993,114 @@ int mode; /* 0: off, 1: on, 2: alternate on */ #endif } +/* caller just got an input character of ESC or M-^O; + note: curses converts a lot of escape sequences to single values greater + than 255 and those won't look like ESC to caller so won't get here */ static int -parse_escape_sequence(void) +parse_escape_sequence(int key, boolean *keypadnum) { #ifndef PDCURSES - int ret; + int ret, keypadother = 0; - timeout(10); + *keypadnum = FALSE; + timeout(10); ret = getch(); - if (ret != ERR) { /* Likely an escape sequence */ - if (((ret >= 'a') && (ret <= 'z')) || ((ret >= '0') && (ret <= '9'))) { - ret |= 0x80; /* Meta key support for most terminals */ - } else if (ret == 'O') { /* Numeric keypad */ + if (ret == 'O' || key == SS3) { /* handle numeric keypad */ + /* + * ESC O or M-^O . + * + * For the former, we don't have the next char yet so get it now. + * If there isn't one, treat ESC O as if user typed M-O (which + * is probably the case, via alt+shift+O combo sending two char + * "ESC O"). + * + * For the latter, it there wasn't another char then 'ret' will + * be ERR and we'll treat the result as M-^O. However, if there + * is another char and it is O meant as two characters "M-^O O" + * we'll be fooled, but that's not a valid escape sequence so + * don't worry about those two characters arriving together. + */ + if (key == '\033') ret = getch(); - if ((ret != ERR) && (ret >= 112) && (ret <= 121)) { - ret = ret - 112 + '0'; /* Convert to number */ - } else { - ret = '\033'; /* Escape */ - } + + if (ret == ERR) { + iflags.term_gone = 1; + /* there was no additional char; treat as M-O or M-^O below */ + ret = (key == '\033') ? 'O' : C('O'); + } else if (ret >= 112 && ret <= 121) { /* 'p'..'y' */ + *keypadnum = TRUE; /* convert 'p'..'y' to '0'..'9' below */ + } else if (ret >= 108 && ret <= 110) { /* 'l'..'n' */ + keypadother = 1; /* convert 'l','m','n' to ',','.','-' below */ + } else if (ret == 'M') { + keypadother = 2; /* convert "ESC O M" or "SS3 M" to ^M */ } - } else { - ret = '\033'; /* Just an escape character */ } - timeout(-1); + timeout(-1); /* reset to 'wait unlimited time for next input' */ + + if (*keypadnum) { + /* 'p' -> '0', ..., 'y' -> '9' */ + ret -= ('p' - '0'); /* Convert c from 'ESC O c' to digit */ + } else if (keypadother > 0) { + /* conversion for VT keypad keys (no plus; ignore PF1 through PF4) + [typical PC keyboard has period and plus, no comma or minus] */ + if (keypadother == 1) + ret -= ('l' - ','); /* keypad comma, period, or minus */ + else + ret = C('M'); /* keypad */ + } else if (ret != ERR && ret <= 255) { + /* ESC ; effectively 'altmeta' behind player's back */ + ret = M(ret); /* Meta key support for most terminals */ + } else { + ret = '\033'; /* Just an escape character */ + } return ret; #else + nhUse(key); + nhUse(keypadnum); return '\033'; #endif /* !PDCURSES */ } +#undef SS3 + +/* update_modifiers() and modified() will never be + called if modifiers_available is FALSE */ + +static void +update_modifiers(void) +{ +#if defined(PDCURSES) && defined(PDC_KEY_MODIFIER_ALT) + last_getch_modifiers = PDC_get_key_modifiers(); +#endif +} + +static int +modified(int ch) +{ + int ret_ch = ch; + +#if defined(PDCURSES) && defined(PDC_KEY_MODIFIER_ALT) + /* PDCurses key modifier masks: + * PDC_KEY_MODIFIER_SHIFT = 1 + * PDC_KEY_MODIFIER_CONTROL = 2 + * PDC_KEY_MODIFIER_ALT = 4 + * PDC_KEY_MODIFIER_NUMLOCK = 8 + * PDC_KEY_MODIFIER_REPEAT = 16 + * ALT + 'a' through ALT + 'z' returns ALT_A through ALT_Z + * and those are out of the normal character range and + * code in curses_convert_keys() handles those. + * ALT + 'A' through ALT + 'Z' return normal 'A' through 'Z' + * so we check the modifier here. + */ + if (((last_getch_modifiers & PDC_KEY_MODIFIER_ALT) == PDC_KEY_MODIFIER_ALT) + && (ch >= 'A' && ch <= 'Z')) + ret_ch = M(ch); +#endif + return ret_ch; +} + +/*cursmisc.c*/ diff --git a/win/curses/cursmisc.h b/win/curses/cursmisc.h index d76346184..dc79ebfbe 100644 --- a/win/curses/cursmisc.h +++ b/win/curses/cursmisc.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursmisc.h */ +/* NetHack 5.0 cursmisc.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -8,6 +8,7 @@ /* Global declarations */ +int curses_getch(void); int curses_read_char(void); void curses_toggle_color_attr(WINDOW *win, int color, int attr, int onoff); void curses_menu_color_attr(WINDOW *win, int color, int attr, int onoff); @@ -21,16 +22,15 @@ boolean curses_is_menu(winid wid); boolean curses_is_text(winid wid); int curses_convert_glyph(int ch, int glyph); void curses_move_cursor(winid wid, int x, int y); +void curses_update_stdscr_cursor(void); void curses_prehousekeeping(void); void curses_posthousekeeping(void); void curses_view_file(const char *filename, boolean must_exist); void curses_rtrim(char *str); -int curses_get_count(int first_digit); -int curses_convert_attr(int attr); -int curses_read_attrs(const char *attrs); -char *curses_fmt_attrs(char *); +long curses_get_count(int first_digit); +attr_t curses_convert_attr(int attr); int curses_convert_keys(int key); -int curses_get_mouse(int *mousex, int *mousey, int *mod); +int curses_get_mouse(coordxy *mousex, coordxy *mousey, int *mod); void curses_mouse_support(int); #endif /* CURSMISC_H */ diff --git a/win/curses/cursstat.c b/win/curses/cursstat.c index a2b83d861..0abcecdc7 100644 --- a/win/curses/cursstat.c +++ b/win/curses/cursstat.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursstat.c */ +/* NetHack 5.0 cursstat.c */ /* Copyright (c) Andy Thomson, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -27,21 +27,19 @@ static char *status_vals_long[MAXBLSTATS]; static unsigned long *curses_colormasks; static long curses_condition_bits; static int curses_status_colors[MAXBLSTATS]; -static int hpbar_percent, hpbar_color; +static int hpbar_percent, hpbar_crit_hp, hpbar_color; static int vert_status_dirty; -static void NDECL(draw_status); -static void FDECL(draw_vertical, (BOOLEAN_P)); -static void FDECL(draw_horizontal, (BOOLEAN_P)); +static void draw_status(void); +static void draw_vertical(boolean); +static void draw_horizontal(boolean); static void curs_HPbar(char *, int); -static void curs_stat_conds(int, int *, int *, char *, boolean *); +static void curs_stat_conds(int, int, int *, int *, char *, boolean *); static void curs_vert_status_vals(int); #ifdef STATUS_HILITES -#ifdef TEXTCOLOR -static int FDECL(condcolor, (long, unsigned long *)); -#endif -static int FDECL(condattr, (long, unsigned long *)); -static int FDECL(nhattr2curses, (int)); +static int condcolor(long, unsigned long *); +static int condattr(long, unsigned long *); +static int nhattr2curses(int); #endif /* STATUS_HILITES */ /* width of a single line in vertical status orientation (one field per line; @@ -49,7 +47,7 @@ static int FDECL(nhattr2curses, (int)); #define STATVAL_WIDTH 60 /* overkill; was MAXCO (200), massive overkill */ void -curses_status_init() +curses_status_init(void) { int i; @@ -59,7 +57,7 @@ curses_status_init() *status_vals_long[i] = '\0'; } curses_condition_bits = 0L; - hpbar_percent = 0, hpbar_color = NO_COLOR; + hpbar_percent = hpbar_crit_hp = 0, hpbar_color = NO_COLOR; vert_status_dirty = 1; /* let genl_status_init do most of the initialization */ @@ -68,7 +66,7 @@ curses_status_init() } void -curses_status_finish() +curses_status_finish(void) { int i; @@ -131,24 +129,28 @@ curses_status_finish() * Each condition bit must only ever appear in one of the * CLR_ array members, but can appear in multiple HL_ATTCLR_ * offsets (because more than one attribute can co-exist). - * See doc/window.doc for more details. + * See doc/window.txt for more details. */ static int changed_fields = 0; +DISABLE_WARNING_FORMAT_NONLITERAL + void -curses_status_update(fldidx, ptr, chg, percent, color_and_attr, colormasks) -int fldidx, chg UNUSED, - percent, color_and_attr; -genericptr_t ptr; -unsigned long *colormasks; +curses_status_update( + int fldidx, + genericptr_t ptr, + int chg UNUSED, + int percent, + int color_and_attr, + unsigned long *colormasks) { long *condptr = (long *) ptr; char *text = (char *) ptr; if (fldidx != BL_FLUSH) { if (fldidx < 0 || fldidx >= MAXBLSTATS) { - context.botlx = context.botl = FALSE; /* avoid another bot() */ + /* panic immediately sets gb.bot_disabled to avoid bot() */ panic("curses_status_update(%d)", fldidx); } changed_fields |= (1 << fldidx); @@ -159,9 +161,6 @@ unsigned long *colormasks; curses_condition_bits = *condptr; curses_colormasks = colormasks; } else { -#ifndef TEXTCOLOR - color_and_attr = (color_and_attr & ~0x00FF) | NO_COLOR; -#endif /* * status_vals[] are used for horizontal orientation * (wide lines of multiple short values). @@ -174,6 +173,7 @@ unsigned long *colormasks; /* decode once instead of every time it's displayed */ status_vals[BL_GOLD][0] = ' '; text = decode_mixed(&status_vals[BL_GOLD][1], text); + nhUse(text); } else if ((fldidx == BL_HUNGER || fldidx == BL_CAP) && (!*text || !strcmp(text, " "))) { /* fieldfmt[] is " %s"; avoid lone space when empty */ @@ -181,8 +181,8 @@ unsigned long *colormasks; } else { Sprintf(status_vals[fldidx], (fldidx == BL_TITLE && iflags.wc2_hitpointbar) - ? "%-30s" : status_fieldfmt[fldidx] - ? status_fieldfmt[fldidx] : "%s", + ? "%-30.30s" : status_fieldfmt[fldidx] + ? status_fieldfmt[fldidx] : "%s", text); /* strip trailing spaces; core ought to do this for us */ if (fldidx == BL_HUNGER || fldidx == BL_LEVELDESC) @@ -196,7 +196,9 @@ unsigned long *colormasks; curses_status_colors[fldidx] = color_and_attr; if (iflags.wc2_hitpointbar && fldidx == BL_HP) { hpbar_percent = percent; - hpbar_color = color_and_attr; + hpbar_crit_hp = critically_low_hp(TRUE) ? 1 : 0; + hpbar_color = ((color_and_attr & 0x00ff) | (HL_INVERSE << 8) + | (hpbar_crit_hp ? (HL_BLINK << 8) : 0)); } } } else { /* BL_FLUSH */ @@ -205,8 +207,10 @@ unsigned long *colormasks; } } +RESTORE_WARNING_FORMAT_NONLITERAL + static void -draw_status() +draw_status(void) { WINDOW *win = curses_get_nhwin(STATUS_WIN); orient statorient = (orient) curses_get_window_orientation(STATUS_WIN); @@ -244,19 +248,19 @@ draw_status() /* horizontal layout on 2 or 3 lines */ static void -draw_horizontal(border) -boolean border; +draw_horizontal(boolean border) { #define blPAD BL_FLUSH /* almost all fields already come with a leading space; "xspace" indicates places where we'll generate an extra one */ static const enum statusfields - twolineorder[3][15] = { + twolineorder[3][19] = { { BL_TITLE, /*xspace*/ BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, /*xspace*/ BL_ALIGN, /*xspace*/ BL_SCORE, - BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD }, + BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, + blPAD, blPAD, blPAD }, { BL_LEVELDESC, /*xspace*/ BL_GOLD, /*xspace*/ BL_HP, BL_HPMAX, @@ -264,32 +268,36 @@ boolean border; /*xspace*/ BL_AC, /*xspace*/ BL_XP, BL_EXP, BL_HD, /*xspace*/ BL_TIME, - /*xspace*/ BL_HUNGER, BL_CAP, BL_CONDITION, + /*xspace*/ BL_HUNGER, BL_CAP, + BL_WEAPON, BL_ARMOR, BL_TERRAIN, BL_CONDITION, BL_VERS, BL_FLUSH }, { BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, - blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } + blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, + blPAD, blPAD, blPAD } }, - threelineorder[3][15] = { /* moves align to line 2, leveldesc+ to 3 */ + threelineorder[3][19] = { /* moves align to line 2, leveldesc+ to 3 */ { BL_TITLE, /*xspace*/ BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, /*xspace*/ BL_SCORE, - BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }, + BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, + blPAD, blPAD, blPAD }, { BL_ALIGN, /*xspace*/ BL_GOLD, /*xspace*/ BL_HP, BL_HPMAX, /*xspace*/ BL_ENE, BL_ENEMAX, /*xspace*/ BL_AC, /*xspace*/ BL_XP, BL_EXP, BL_HD, - /*xspace*/ BL_HUNGER, BL_CAP, - BL_FLUSH, blPAD, blPAD }, + /*xspace*/ BL_HUNGER, BL_CAP, BL_WEAPON, BL_ARMOR, BL_TERRAIN, + BL_FLUSH, blPAD, blPAD, blPAD }, { BL_LEVELDESC, /*xspace*/ BL_TIME, /*xspecial*/ BL_CONDITION, + /*xspecial*/ BL_VERS, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, - blPAD, blPAD, blPAD, blPAD } + blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } }; - const enum statusfields (*fieldorder)[15]; - xchar spacing[MAXBLSTATS], valline[MAXBLSTATS]; + const enum statusfields (*fieldorder)[19]; + coordxy spacing[MAXBLSTATS], valline[MAXBLSTATS]; enum statusfields fld, prev_fld; char *text, *p, cbuf[BUFSZ], ebuf[STATVAL_WIDTH]; #ifdef SCORE_ON_BOTL @@ -297,9 +305,11 @@ boolean border; char sbuf[STATVAL_WIDTH]; #endif int i, j, number_of_lines, - cap_and_hunger, exp_points, sho_score, + cap_and_hunger, exp_points, sho_score, sho_vers, + /* both height and width get their values set, + * but only width gets used in this function */ height, width, w, xtra, clen, x, y, t, ex, ey, - condstart = 0, conddummy = 0; + condstart = 0, conddummy = 0, versstart = 0; #ifdef STATUS_HILITES int coloridx = NO_COLOR, attrmask = 0; #endif /* STATUS_HILITES */ @@ -319,12 +329,21 @@ boolean border; * for gold so would recover only 2 columns. n >>= 10 might have * greater geek appeal but could lead to bug reports and couldn't * be accomplished via simple string truncation.) + * * For experience point and score suppression, might try that first * (better chance for column recovery, with "/nM" freeing 5 out of * 7+ digits; in rare instances, "/nG" could free 8 out of 10+ digits) * before deciding to remove them altogether. * tty's shorter condition designations combined with comparable * trimming of hunger and encumbrance would be better overall. + * + * For first line when hitpointbar is off, treat trailing spaces + * on Title as discardable leading spaces on Str. (Enabling + * perm_invent without having a wide terminal size results in status + * being narrower than usual and possibly truncating by omitting + * right hand fields, emphasizing the wasted space devoted to + * title's trailing spaces. Same issue without perm_invent if main + * window gets clipped to fit a narrow terminal.) */ number_of_lines = (iflags.wc2_statuslines < 3) ? 2 : 3; @@ -335,7 +354,7 @@ boolean border; /* collect active conditions in cbuf[], space separated, suitable for direct output if no highlighting is requested ('asis') but primarily used to measure the length */ - curs_stat_conds(0, &x, &y, cbuf, &asis); + curs_stat_conds(0, 0, &x, &y, cbuf, &asis); clen = (int) strlen(cbuf); cap_and_hunger = 0; @@ -346,6 +365,10 @@ boolean border; exp_points = (flags.showexp ? 1 : 0); /* don't bother conditionalizing this; always 0 for !SCORE_ON_BOTL */ sho_score = (status_activefields[BL_SCORE] != 0); + sho_vers = (status_activefields[BL_VERS] != 0); + versstart = sho_vers ? (width - (int) strlen(status_vals[BL_VERS]) + + (border ? 1 : 0)) + : 0; /* simplify testing which fields reside on which lines; assume line #0 */ (void) memset((genericptr_t) valline, 0, sizeof valline); @@ -382,6 +405,9 @@ boolean border; case BL_ENEMAX: spacing[fld] = 0; /* no leading or extra space */ break; + case BL_WEAPON: + case BL_ARMOR: + case BL_TERRAIN: case BL_DX: case BL_CO: case BL_IN: @@ -397,6 +423,7 @@ boolean border; w -= (t - 30); /* '+= strlen()' below will add 't'; * functional result being 'w += 30' */ } + FALLTHROUGH; /*FALLTHRU*/ case BL_ALIGN: case BL_LEVELDESC: @@ -412,6 +439,7 @@ boolean border; text = cbuf; /* for 'w += strlen(text)' below */ spacing[fld] = (cap_and_hunger == 0); break; + case BL_VERS: case BL_STR: case BL_HP: case BL_ENE: @@ -541,7 +569,7 @@ boolean border; case BL_SCORE: #ifdef SCORE_ON_BOTL if ((sho_score & 2) != 0) { /* strip "S:" prefix */ - if ((colon = index(text, ':')) != 0) + if ((colon = strchr(text, ':')) != 0) text = strcat(strcpy(sbuf, " "), colon + 1); else sho_score = 0; @@ -562,6 +590,11 @@ boolean border; } else if (fld != BL_CONDITION) { /* regular field, including title if no hitpointbar */ + if (fld == BL_VERS) { + getyx(win, y, x); + if (x < versstart) + wmove(win, y, versstart); /* right justify */ + } #ifdef STATUS_HILITES coloridx = curses_status_colors[fld]; /* includes attribute */ if (iflags.hilite_delta && coloridx != NO_COLOR) { @@ -575,11 +608,9 @@ boolean border; attrmask = nhattr2curses(attrmask); wattron(win, attrmask); } -#ifdef TEXTCOLOR coloridx &= 0x00FF; if (coloridx != NO_COLOR && coloridx != CLR_MAX) curses_toggle_color_attr(win, coloridx, NONE, ON); -#endif } #endif /* STATUS_HILITES */ @@ -587,10 +618,8 @@ boolean border; #ifdef STATUS_HILITES if (iflags.hilite_delta) { -#ifdef TEXTCOLOR if (coloridx != NO_COLOR) curses_toggle_color_attr(win, coloridx, NONE, OFF); -#endif if (attrmask) wattroff(win, attrmask); } @@ -608,6 +637,14 @@ boolean border; y = j + (border ? 1 : 0); /* cbuf[] was populated above; clen is its length */ if (number_of_lines == 3) { + int vlen = (sho_vers + && fieldorder[j][i + 1] == BL_VERS) + ? ((int) strlen(status_vals[BL_VERS]) + + spacing[BL_VERS]) + : 0; + + clen += vlen; /* when aligning conditions, treat + * version as if an added condition */ /* * For 3-line status, align conditions with hunger * (or where it would have been, when not shown), @@ -625,6 +662,7 @@ boolean border; else wmove(win, y, width + (border ? 1 : 0) - clen); } + clen -= vlen; } /* 'asis' was set up by first curs_stat_conds() call above; True means that none of the conditions @@ -638,49 +676,55 @@ boolean border; if (asis) waddstr(win, cbuf); else /* cond by cond if any cond specifies highlighting */ - curs_stat_conds(0, &x, &y, (char *) 0, (boolean *) 0); + curs_stat_conds(0, 0, &x, &y, + (char *) 0, (boolean *) 0); } /* curses_condition_bits */ } /* hitpointbar vs regular field vs conditions */ } /* i (fld) */ wclrtoeol(win); /* [superfluous? draw_status() calls werase()] */ } /* j (line) */ + nhUse(height); return; } /* vertical layout, to left or right of map */ static void -draw_vertical(border) -boolean border; +draw_vertical(boolean border) { /* for blank lines, the digit prefix is the order in which they get removed if we need to shrink to fit within height limit (very rare) */ static const enum statusfields fieldorder[] = { BL_TITLE, /* might be overlaid by hitpoint bar */ - /* 4:blank */ + /* 5:blank */ BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC, - /* 3:blank */ + /* 4:blank */ BL_LEVELDESC, BL_ALIGN, BL_XP, BL_EXP, BL_HD, BL_GOLD, - /* 2:blank (but only if time or score or both enabled) */ + /* 3:blank (but only if time or score or both enabled) */ BL_TIME, BL_SCORE, - /* 1:blank */ + /* 2:blank */ BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, - /* 5:blank (if any of hunger, encumbrance, or conditions appear) */ + /* 6:blank (if any of hunger, encumbrance, or conditions appear) */ BL_HUNGER, BL_CAP, /* these two are shown on same line */ BL_CONDITION, /* shown three per line so may take up to four lines */ + BL_WEAPON, BL_ARMOR, BL_TERRAIN, /* same line if 2, two lines if 3 */ + /* 1:blank (bottom justified) */ + BL_VERS, BL_FLUSH }; static const enum statusfields shrinkorder[] = { - BL_STR, BL_SCORE, BL_TIME, BL_LEVELDESC, BL_HP, - BL_CONDITION, BL_CAP, BL_HUNGER + BL_VERS, BL_STR, BL_SCORE, BL_TIME, BL_LEVELDESC, BL_HP, + BL_TERRAIN, BL_ARMOR, BL_WEAPON, + BL_CONDITION, BL_CAP, BL_HUNGER }; - xchar spacing[MAXBLSTATS]; - int i, fld, cap_and_hunger, time_and_score, cond_count; + coordxy spacing[MAXBLSTATS]; + int i, fld, cap_and_hunger, time_and_score, cond_count, wep_arm_ter, + sho_vers, per_line; char *text; #ifdef STATUS_HILITES char *p = 0, savedch = '\0'; @@ -703,10 +747,6 @@ boolean border; * truncate the two portions separately. ( is already being * truncated to 10 chars by the botl.c code, so we don't really * need to do anything further unless we want to override that.) - * Format hunger, encumbrance, and conditions in columns: 12+1+12 - * for first two and for 2 conditions, 8+1+8+1+8 for 3+ conditions. - * (Would probably only look good enough to matter when 6 or more - * conditions are present, so not worth bothering with.) */ cap_and_hunger = 0; @@ -721,10 +761,19 @@ boolean border; time_and_score |= 2; cond_count = 0; if (curses_condition_bits) { - for (i = 0; i < BL_MASK_BITS; ++i) + for (i = 0; i < CONDITION_COUNT; ++i) if (curses_condition_bits & (1 << i)) ++cond_count; } + per_line = 2; /* will be changed to 3 if status becomes too tall */ + sho_vers = (status_activefields[BL_VERS] ? 1 : 0); + wep_arm_ter = 0; + if (status_activefields[BL_WEAPON] && *status_vals_long[BL_WEAPON]) + wep_arm_ter |= 1; + if (status_activefields[BL_ARMOR] && *status_vals_long[BL_ARMOR]) + wep_arm_ter |= 2; + if (status_activefields[BL_TERRAIN] && *status_vals_long[BL_TERRAIN]) + wep_arm_ter |= 4; /* count how many lines we'll need; we normally space several groups of fields with blank lines but might need to compress some of those out */ @@ -749,7 +798,7 @@ boolean border; /* unlike hunger+cap, score is shown on separate line from time; needs time+score separator if time is inactive */ spacing[fld] = (time_and_score == 2) ? 2 - : (time_and_score & 1) ? 1 : 0; + : (time_and_score == 3) ? 1 : 0; break; case BL_HUNGER: /* separated from characteristics unless blank */ @@ -765,8 +814,38 @@ boolean border; otherwise just start on next line; if more than 3 conditions are present, this will consume multiple lines from height */ spacing[fld] = cond_count ? (!cap_and_hunger ? 2 : 1) : 0; - if (cond_count > 3) /* first 3 handled via '+= spacing[]' below */ - height_needed += (cond_count - 1) / 3; /* three per line */ + /* first line handled via '+= spacing[]' below */ + if (cond_count > per_line) + height_needed += (cond_count - 1) / per_line; + break; + case BL_WEAPON: + /* two lines if no hunger or encumbrance and no conditions, + otherwise one line if weapon status being is shown */ + spacing[fld] = ((wep_arm_ter & 1) == 1) /* show wep */ + ? ((!cond_count && !cap_and_hunger) ? 2 : 1) + : 0; /* no wep */ + break; + case BL_ARMOR: + /* two lines if no hunger or encumbrance and no conditions + and no weapon status, otherwise one line if no weapon + status, else same line as weapon status */ + spacing[fld] = ((wep_arm_ter & 3) == 2) /* show arm, no wep */ + ? ((!cond_count && !cap_and_hunger) ? 2 : 1) + : 0; /* wep and arm (on same line) or no arm */ + break; + case BL_TERRAIN: + /* two lines if no hunger or encumbrance and no conditions + and no weapon status and no armor status, otherwise one + line if both weapon status and armor status or neither of + them and terrain status is being shown */ + spacing[fld] = ((wep_arm_ter & 7) == 4) /* show ter, no wep|arm */ + ? ((!cond_count && !cap_and_hunger) ? 2 : 1) + /* if all three, put terrain on next line; else + same line for wep+ter or arm+ter or no ter */ + : (((wep_arm_ter & 7) == 7) ? 1 : 0); + break; + case BL_VERS: + spacing[fld] = sho_vers ? 2 : 0; break; case BL_XP: case BL_HD: @@ -778,18 +857,26 @@ boolean border; height_needed += spacing[fld]; } if (height_needed > height) { - for (i = 0; i < SIZE(shrinkorder); ++i) { - fld = shrinkorder[i]; - if (spacing[fld] == 2) { - spacing[fld] = 1; /* suppress planned blank line */ - if (--height_needed <= height) - break; + /* if there are a lot of status conditions, compress them first */ + if (per_line == 2 && cond_count > per_line) { + height_needed -= (cond_count - 1) / per_line; + per_line = 3; + height_needed += (cond_count - 1) / per_line; + } + if (height_needed > height) { + for (i = 0; i < SIZE(shrinkorder); ++i) { + fld = shrinkorder[i]; + if (spacing[fld] == 2) { + spacing[fld] = 1; /* suppress planned blank line */ + if (--height_needed <= height) + break; + } } } #ifdef SCORE_ON_BOTL /* with all optional fields and every status condition (12 out of the 13 since two are mutually exclusive) active, we need - 21 non-blank lines; curses_create_main_windows() used to + 22 non-blank lines; curses_create_main_windows() used to require 24 lines or more in order to enable vertical status, but that has been relaxed to 20 so height_needed might still be too high after suppressing all the blank lines */ @@ -797,11 +884,18 @@ boolean border; height_needed -= spacing[BL_SCORE]; spacing[BL_SCORE] = 0; time_and_score &= ~2; - /* height_needed isn't used beyond here but we keep it accurate */ - nhUse(height_needed); } #endif + } else if (height_needed < height) { + if (sho_vers) { + /* bottom justify 'version' */ + spacing[BL_VERS] += height - height_needed; /* 2 + (h - h') */ + height_needed = height; + } } + /* height_needed isn't used beyond here but was updated (for BL_SCORE + or BL_VERS) to keep it accurate in case that changes someday */ + nhUse(height_needed); if (border) x++, y++; @@ -815,9 +909,8 @@ boolean border; continue; if (spacing[fld]) { - wmove(win, y++, x); /* move to next line */ - if (spacing[fld] == 2) - wmove(win, y++, x); /* skip a line */ + y += spacing[fld]; + wmove(win, y - 1, x); /* move to next (or further) line */ } if (fld == BL_TITLE && iflags.wc2_hitpointbar) { @@ -832,7 +925,11 @@ boolean border; the first (or only) and keep it for the second (if both) */ if (*text == ' ' && (fld == BL_HUNGER - || (fld == BL_CAP && cap_and_hunger != 3))) + || (fld == BL_CAP && cap_and_hunger != 3) + || fld == BL_WEAPON + || (fld == BL_ARMOR && (wep_arm_ter & 3) == 2) + || (fld == BL_TERRAIN && ((wep_arm_ter & 7) == 4 + || (wep_arm_ter & 7) == 7)))) ++text; #ifdef STATUS_HILITES coloridx = curses_status_colors[fld]; /* includes attributes */ @@ -840,7 +937,7 @@ boolean border; /* most status_vals_long[] are "long-text : value" and unlike horizontal status's abbreviated "ab:value", we highlight just the value portion */ - p = (fld != BL_TITLE) ? index(text, ':') : 0; + p = (fld != BL_TITLE) ? strchr(text, ':') : 0; p = !p ? text : p + 1; while (*p == ' ') ++p; @@ -855,7 +952,7 @@ boolean border; *p = savedch; text = p; /* rest of field */ if ((fld == BL_HPMAX || fld == BL_ENEMAX) - && (p = index(text, ')')) != 0) { + && (p = strchr(text, ')')) != 0) { savedch = *p; *p = '\0'; } else @@ -866,11 +963,9 @@ boolean border; attrmask = nhattr2curses(attrmask); wattron(win, attrmask); } -#ifdef TEXTCOLOR coloridx &= 0x00FF; if (coloridx != NO_COLOR && coloridx != CLR_MAX) curses_toggle_color_attr(win, coloridx, NONE, ON); -#endif } /* highlighting active */ #endif /* STATUS_HILITES */ @@ -878,10 +973,8 @@ boolean border; #ifdef STATUS_HILITES if (iflags.hilite_delta) { -#ifdef TEXTCOLOR if (coloridx != NO_COLOR) curses_toggle_color_attr(win, coloridx, NONE, OFF); -#endif if (attrmask) wattroff(win, attrmask); } /* resume normal rendition */ @@ -894,9 +987,11 @@ boolean border; } else { /* status conditions */ if (cond_count) { - /* output active conditions, three per line; + /* output active conditions; usually two per line, but if + window isn't tall enough, it's increased to three per line; cursor is already positioned where they should start */ - curs_stat_conds(1, &x, &y, (char *) 0, (boolean *) 0); + curs_stat_conds(1, per_line, &x, &y, + (char *) 0, (boolean *) 0); } } /* hitpointbar vs regular field vs conditions */ } /* fld loop */ @@ -905,13 +1000,12 @@ boolean border; /* hitpointbar using hp percent calculation */ static void -curs_HPbar(char *text, /* pre-padded with trailing spaces if short */ - int bar_len) /* width of space within the brackets */ +curs_HPbar( + char *text, /* pre-padded with trailing spaces if short */ + int bar_len) /* width of space within the brackets */ { #ifdef STATUS_HILITES -#ifdef TEXTCOLOR int coloridx = 0; -#endif #endif /* STATUS_HILITES */ int k, bar_pos; char bar[STATVAL_WIDTH], *bar2 = (char *) 0, savedch = '\0'; @@ -924,6 +1018,8 @@ curs_HPbar(char *text, /* pre-padded with trailing spaces if short */ bar_len = k; (void) strncpy(bar, text, bar_len); bar[bar_len] = '\0'; + if (hpbar_crit_hp) + repad_with_dashes(bar); bar_pos = (bar_len * hpbar_percent) / 100; if (bar_pos < 1 && hpbar_percent > 0) @@ -937,29 +1033,27 @@ curs_HPbar(char *text, /* pre-padded with trailing spaces if short */ } waddch(win, '['); + if (hpbar_crit_hp) + wattron(win, A_BLINK); if (*bar) { /* True unless dead (0 HP => bar_pos == 0) */ /* fixed attribute, not nhattr2curses((hpbar_color >> 8) & 0x00FF) */ wattron(win, A_REVERSE); /* do this even if hilite_delta is 0 */ #ifdef STATUS_HILITES -#ifdef TEXTCOLOR if (iflags.hilite_delta) { coloridx = hpbar_color & 0x00FF; if (coloridx != NO_COLOR) curses_toggle_color_attr(win, coloridx, NONE, ON); } -#endif #endif /* STATUS_HILITES */ /* portion of title corresponding to current hit points */ waddstr(win, bar); #ifdef STATUS_HILITES -#ifdef TEXTCOLOR if (iflags.hilite_delta) { if (coloridx != NO_COLOR) curses_toggle_color_attr(win, coloridx, NONE, OFF); } -#endif #endif /* STATUS_HILITES */ wattroff(win, A_REVERSE); /* do this even if hilite_delta is 0 */ } /* *bar (current HP > 0) */ @@ -969,21 +1063,28 @@ curs_HPbar(char *text, /* pre-padded with trailing spaces if short */ *bar2 = savedch; waddstr(win, bar2); } + if (hpbar_crit_hp) + wattroff(win, A_BLINK); waddch(win, ']'); } -/* valid_conditions[] is used primarily for parsing hilite_status rules, but +/* conditions[] is used primarily for parsing hilite_status rules, but we can use it for condition names and mask bits, avoiding duplication */ -extern const struct condmap valid_conditions[]; /* botl.c */ +extern const struct conditions_t conditions[]; /* botl.c */ +extern int cond_idx[CONDITION_COUNT]; + +DISABLE_WARNING_FORMAT_NONLITERAL static void -curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */ - int *x, int *y, /* real for vertical, ignored otherwise */ - char *condbuf, /* optional output; collect string of conds */ - boolean *nohilite) /* optional output; indicates whether -*/ -{ /*+ condbuf[] could be used as-is */ +curs_stat_conds( + int vert_cond, /* 0 => horizontal, 1 => vertical */ + int per_line, /* for vertical, number of conditions per line */ + int *x, int *y, /* real for vertical, ignored otherwise */ + char *condbuf, /* optional output; collect string of conds */ + boolean *nohilite) /* optional output; indicates whether -*/ +{ /*+ condbuf[] could be used as-is */ char condnam[20]; - int i; + int i, ci; long bitmsk; if (condbuf) { @@ -995,10 +1096,11 @@ curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */ condbuf[0] = '\0'; if (nohilite) *nohilite = TRUE; /* assume ok */ - for (i = 0; i < BL_MASK_BITS; ++i) { - bitmsk = valid_conditions[i].bitmask; + for (i = 0; i < CONDITION_COUNT; ++i) { + ci = cond_idx[i]; + bitmsk = conditions[ci].mask; if (curses_condition_bits & bitmsk) { - Strcpy(condnam, valid_conditions[i].id); + Strcpy(condnam, conditions[ci].text[0]); Strcat(strcat(condbuf, " "), upstart(condnam)); #ifdef STATUS_HILITES if (nohilite && *nohilite @@ -1010,6 +1112,7 @@ curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */ } } else if (curses_condition_bits) { unsigned long cond_bits; + const char *vert_fmt = 0; int height = 0, width, cx, cy, cy0, cndlen; #ifdef STATUS_HILITES int attrmask = 0, color = NO_COLOR; @@ -1020,13 +1123,19 @@ curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */ getmaxyx(win, height, width); border = curses_window_has_border(STATUS_WIN); cy0 = height - (border ? 2 : 1); + if (vert_cond) + vert_fmt = (per_line == 2) ? "%-12.12s" : "%-8.8s"; cond_bits = curses_condition_bits; - /* show active conditions directly; for vertical, three per line */ - for (i = 0; i < BL_MASK_BITS; ++i) { - bitmsk = valid_conditions[i].bitmask; + /* show active conditions directly; for vertical, 2 or 3 per line */ + for (i = 0; i < CONDITION_COUNT; ++i) { + ci = cond_idx[i]; + bitmsk = conditions[ci].mask; if (cond_bits & bitmsk) { - Strcpy(condnam, valid_conditions[i].id); + if (!vert_fmt) + Strcpy(condnam, conditions[ci].text[0]); + else + Sprintf(condnam, vert_fmt, conditions[ci].text[0]); cndlen = 1 + (int) strlen(condnam); /* count leading space */ if (!do_vert) { getyx(win, cy, cx); @@ -1042,7 +1151,7 @@ curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */ } cond_bits &= ~bitmsk; /* nonzero if another cond after this */ /* output unhighlighted leading space unless at #1 of 3 */ - if (!do_vert || (vert_cond % 3) != 1) + if (!do_vert || (vert_cond % per_line) != 1) waddch(win, ' '); #ifdef STATUS_HILITES if (iflags.hilite_delta) { @@ -1051,11 +1160,9 @@ curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */ attrmask = nhattr2curses(attrmask); wattron(win, attrmask); } -#ifdef TEXTCOLOR if ((color = condcolor(bitmsk, curses_colormasks)) != NO_COLOR) curses_toggle_color_attr(win, color, NONE, ON); -#endif } #endif /* STATUS_HILITES */ @@ -1064,16 +1171,14 @@ curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */ #ifdef STATUS_HILITES if (iflags.hilite_delta) { -#ifdef TEXTCOLOR if (color != NO_COLOR) curses_toggle_color_attr(win, color, NONE, OFF); -#endif if (attrmask) wattroff(win, attrmask); } #endif /* STATUS_HILITES */ /* if that was #3 of 3 advance to next line */ - if (do_vert && (++vert_cond % 3) == 1) + if (do_vert && cond_bits && (++vert_cond % per_line) == 1) wmove(win, (*y)++, *x); } /* if cond_bits & bitmask */ } /* for i */ @@ -1089,6 +1194,8 @@ curs_stat_conds(int vert_cond, /* 0 => horizontal, 1 => vertical */ return; } +RESTORE_WARNING_FORMAT_NONLITERAL + /* status_update() sets up values for horizontal status; do vertical */ void curs_vert_status_vals(int win_width) @@ -1118,7 +1225,7 @@ curs_vert_status_vals(int win_width) } else { text = status_vals[fldidx]; if (fldidx != BL_TITLE && fldidx != BL_LEVELDESC) { - if ((colon = index(text, ':')) != 0) + if ((colon = strchr(text, ':')) != 0) text = colon + 1; } lbl = status_fieldnm[fldidx]; @@ -1172,10 +1279,15 @@ curs_vert_status_vals(int win_width) if (fld_width < hp_width + 3) /* +3: " " gap and "("...")" */ Sprintf(leadingspace, "%*s", (hp_width + 3) - fld_width, " "); + FALLTHROUGH; /*FALLTHRU*/ + case BL_VERS: case BL_EXP: case BL_HUNGER: case BL_CAP: + case BL_WEAPON: + case BL_ARMOR: + case BL_TERRAIN: case BL_TITLE: use_name = FALSE; break; @@ -1186,6 +1298,24 @@ curs_vert_status_vals(int win_width) Sprintf(status_vals_long[fldidx], "%*.*s: %s%s", -lbl_width, lbl_width, lbl, leadingspace, text); *status_vals_long[fldidx] = highc(*status_vals_long[fldidx]); + } else if (fldidx == BL_VERS && *text) { + int txtlen = (int) strlen(text); + + /* right justify without "Version :" prefix; if longer than + width, keep only the *end* of the value */ + if (txtlen >= win_width) + Strcpy(status_vals_long[BL_VERS], + eos((char *) text) - win_width); + else + Sprintf(status_vals_long[BL_VERS], + "%*s%s", win_width - txtlen, " ", text); + } else if ((fldidx == BL_HUNGER || fldidx == BL_CAP) && *text) { + /* hunger and encumbrance are shown side-by-side in + a 26 character or wider window; if leading space is + present, get rid of it, then add one we're sure about */ + if (*text == ' ') + ++text; + Sprintf(status_vals_long[fldidx], " %-12.12s", text); } else { /* unlabeled: title, hp-max, en-max, exp-points, hunger+cap */ Sprintf(status_vals_long[fldidx], "%s%s", leadingspace, text); @@ -1225,15 +1355,12 @@ curs_vert_status_vals(int win_width) } #ifdef STATUS_HILITES -#ifdef TEXTCOLOR /* * Return what color this condition should * be displayed in based on user settings. */ static int -condcolor(bm, bmarray) -long bm; -unsigned long *bmarray; +condcolor(long bm, unsigned long *bmarray) { int i; @@ -1244,36 +1371,34 @@ unsigned long *bmarray; } return NO_COLOR; } -#endif /* TEXTCOLOR */ static int -condattr(bm, bmarray) -long bm; -unsigned long *bmarray; +condattr(long bm, unsigned long *bmarray) { int i, attr = 0; if (bm && bmarray) { - for (i = HL_ATTCLR_DIM; i < BL_ATTCLR_MAX; ++i) { + for (i = HL_ATTCLR_BOLD; i < BL_ATTCLR_MAX; ++i) { if ((bmarray[i] & bm) != 0) { - switch (i) { + switch(i) { + case HL_ATTCLR_BOLD: + attr |= HL_BOLD; + break; case HL_ATTCLR_DIM: attr |= HL_DIM; break; - case HL_ATTCLR_BLINK: - attr |= HL_BLINK; + case HL_ATTCLR_ITALIC: + attr |= HL_ITALIC; break; case HL_ATTCLR_ULINE: attr |= HL_ULINE; break; + case HL_ATTCLR_BLINK: + attr |= HL_BLINK; + break; case HL_ATTCLR_INVERSE: attr |= HL_INVERSE; break; - case HL_ATTCLR_BOLD: - attr |= HL_BOLD; - break; - default: - break; } } } @@ -1283,965 +1408,25 @@ unsigned long *bmarray; /* convert tty attributes to curses attributes; despite similar names, the mask fields have different values */ static int -nhattr2curses(attrmask) -int attrmask; +nhattr2curses(int attrmask) { int result = 0; if (attrmask & HL_BOLD) result |= A_BOLD; - if (attrmask & HL_INVERSE) - result |= A_REVERSE; + if (attrmask & HL_DIM) + result |= A_DIM; + if (attrmask & HL_ITALIC) + result |= A_ITALIC; if (attrmask & HL_ULINE) result |= A_UNDERLINE; if (attrmask & HL_BLINK) result |= A_BLINK; - if (attrmask & HL_DIM) - result |= A_DIM; + if (attrmask & HL_INVERSE) + result |= A_REVERSE; return result; } #endif /* STATUS_HILITES */ -/* ======================================================================== */ - - -#if 0 /* old stuff; some may be re-incorporated, most should be discarded */ -/* Private declarations */ - -/* Used to track previous value of things, to highlight changes. */ -typedef struct nhs { - long value; - int highlight_turns; - int highlight_color; -} nhstat; - -static attr_t get_trouble_color(const char *); -static void draw_trouble_str(const char *); -static void print_statdiff(const char *append, nhstat *, long, int); -static void get_playerrank(char *); -static int hpen_color(boolean, int, int); -static void draw_bar(boolean, int, int, const char *); -static void draw_horizontal(int, int, int, int); -static void draw_horizontal_new(int, int, int, int); -static void draw_vertical(int, int, int, int); -static void curses_add_statuses(WINDOW *, boolean, boolean, int *, int *); -static void curses_add_status(WINDOW *, boolean, boolean, int *, int *, - const char *, int); -static int decrement_highlight(nhstat *, boolean); - -#ifdef STATUS_COLORS -static attr_t hpen_color_attr(boolean, int, int); -extern struct color_option text_color_of(const char *text, - const struct text_color_option *color_options); -struct color_option percentage_color_of(int value, int max, - const struct percent_color_option *color_options); - -extern const struct text_color_option *text_colors; -extern const struct percent_color_option *hp_colors; -extern const struct percent_color_option *pw_colors; -#endif - -/* Whether or not we have printed status window content at least once. - Used to ensure that prev* doesn't end up highlighted on game start. */ -static boolean first = TRUE; -static nhstat prevdepth; -static nhstat prevstr; -static nhstat prevint; -static nhstat prevwis; -static nhstat prevdex; -static nhstat prevcon; -static nhstat prevcha; -static nhstat prevau; -static nhstat prevlevel; -static nhstat prevac; -static nhstat prevexp; -static nhstat prevtime; - -#ifdef SCORE_ON_BOTL -static nhstat prevscore; -#endif - -extern const char *hu_stat[]; /* from eat.c */ -extern const char *enc_stat[]; /* from botl.c */ - -/* If the statuscolors patch isn't enabled, have some default colors for status problems - anyway */ - -struct statcolor { - const char *txt; /* For status problems */ - int color; /* Default color assuming STATUS_COLORS isn't enabled */ -}; - -static const struct statcolor default_colors[] = { - {"Satiated", CLR_YELLOW}, - {"Hungry", CLR_YELLOW}, - {"Weak", CLR_ORANGE}, - {"Fainted", CLR_BRIGHT_MAGENTA}, - {"Fainting", CLR_BRIGHT_MAGENTA}, - {"Burdened", CLR_RED}, - {"Stressed", CLR_RED}, - {"Strained", CLR_ORANGE}, - {"Overtaxed", CLR_ORANGE}, - {"Overloaded", CLR_BRIGHT_MAGENTA}, - {"Conf", CLR_BRIGHT_BLUE}, - {"Blind", CLR_BRIGHT_BLUE}, - {"Stun", CLR_BRIGHT_BLUE}, - {"Hallu", CLR_BRIGHT_BLUE}, - {"Ill", CLR_BRIGHT_MAGENTA}, - {"FoodPois", CLR_BRIGHT_MAGENTA}, - {"Slime", CLR_BRIGHT_MAGENTA}, - {NULL, NULL, NO_COLOR}, -}; - -static attr_t -get_trouble_color(const char *stat) -{ - attr_t res = curses_color_attr(CLR_GRAY, 0); - const struct statcolor *clr; - for (clr = default_colors; clr->txt; clr++) { - if (stat && !strcmp(clr->txt, stat)) { -#ifdef STATUS_COLORS - /* Check if we have a color enabled with statuscolors */ - if (!iflags.use_status_colors) - return curses_color_attr(CLR_GRAY, 0); /* no color configured */ - - struct color_option stat_color; - - stat_color = text_color_of(clr->txt, text_colors); - if (stat_color.color == NO_COLOR && !stat_color.attr_bits) - return curses_color_attr(CLR_GRAY, 0); - - if (stat_color.color != NO_COLOR) - res = curses_color_attr(stat_color.color, 0); - - res = curses_color_attr(stat_color.color, 0); - int count; - for (count = 0; (1 << count) <= stat_color.attr_bits; count++) { - if (count != ATR_NONE && - (stat_color.attr_bits & (1 << count))) - res |= curses_convert_attr(count); - } - - return res; -#else - return curses_color_attr(clr->color, 0); -#endif - } - } - - return res; -} - -/* TODO: This is in the wrong place. */ -void -get_playerrank(char *rank) -{ - char buf[BUFSZ]; - if (Upolyd) { - int k = 0; - - Strcpy(buf, mons[u.umonnum].mname); - while(buf[k] != 0) { - if ((k == 0 || (k > 0 && buf[k-1] == ' ')) && - 'a' <= buf[k] && buf[k] <= 'z') - buf[k] += 'A' - 'a'; - k++; - } - Strcpy(rank, buf); - } else - Strcpy(rank, rank_of(u.ulevel, Role_switch, flags.female)); -} - -/* Handles numerical stat changes of various kinds. - type is generally STAT_OTHER (generic "do nothing special"), - but is used if the stat needs to be handled in a special way. */ -static void -print_statdiff(const char *append, nhstat *stat, long new, int type) -{ - char buf[BUFSZ]; - WINDOW *win = curses_get_nhwin(STATUS_WIN); - - int color = CLR_GRAY; - - /* Turncount isn't highlighted, or it would be highlighted constantly. */ - if (type != STAT_TIME && new != stat->value) { - /* Less AC is better */ - if ((type == STAT_AC && new < stat->value) || - (type != STAT_AC && new > stat->value)) { - color = STAT_UP_COLOR; - if (type == STAT_GOLD) - color = HI_GOLD; - } else - color = STAT_DOWN_COLOR; - - stat->value = new; - stat->highlight_color = color; - stat->highlight_turns = 5; - } else if (stat->highlight_turns) - color = stat->highlight_color; - - attr_t attr = curses_color_attr(color, 0); - wattron(win, attr); - wprintw(win, "%s", append); - if (type == STAT_STR && new > 18) { - if (new > 118) - wprintw(win, "%d", new - 100); - else if (new == 118) - wprintw(win, "18/**"); - else - wprintw(win, "18/%02d", new - 18); - } else - wprintw(win, "%d", new); - - wattroff(win, attr); -} - -static void -draw_trouble_str(const char *str) -{ - WINDOW *win = curses_get_nhwin(STATUS_WIN); - - attr_t attr = get_trouble_color(str); - wattron(win, attr); - wprintw(win, "%s", str); - wattroff(win, attr); -} - -/* Returns a ncurses attribute for foreground and background. - This should probably be in cursinit.c or something. */ -attr_t -curses_color_attr(int nh_color, int bg_color) -{ - int color = nh_color + 1; - attr_t cattr = A_NORMAL; - - if (!nh_color) { -#ifdef USE_DARKGRAY - if (iflags.wc2_darkgray) { - if (!can_change_color() || COLORS <= 16) - cattr |= A_BOLD; - } else -#endif - color = COLOR_BLUE; - } - - if (COLORS < 16 && color > 8) { - color -= 8; - cattr = A_BOLD; - } - - /* Can we do background colors? We can if we have more than - 16*7 colors (more than 8*7 for terminals with bold) */ - if (COLOR_PAIRS > (COLORS >= 16 ? 16 : 8) * 7) { - /* NH3 has a rather overcomplicated way of defining - its colors past the first 16: - Pair Foreground Background - 17 Black Red - 18 Black Blue - 19 Red Red - 20 Red Blue - 21 Green Red - ... - (Foreground order: Black, Red, Green, Yellow, Blue, - Magenta, Cyan, Gray/White) - - To work around these oddities, we define backgrounds - by the following pairs: - - 16 COLORS - 49-64: Green - 65-80: Yellow - 81-96: Magenta - 97-112: Cyan - 113-128: Gray/White - - 8 COLORS - 9-16: Green - 33-40: Yellow - 41-48: Magenta - 49-56: Cyan - 57-64: Gray/White */ - - if (bg_color == nh_color) - color = 1; /* Make foreground black if fg==bg */ - - if (bg_color == CLR_RED || bg_color == CLR_BLUE) { - /* already defined before extension */ - color *= 2; - color += 16; - if (bg_color == CLR_RED) - color--; - } else { - boolean hicolor = FALSE; - if (COLORS >= 16) - hicolor = TRUE; - - switch (bg_color) { - case CLR_GREEN: - color = (hicolor ? 48 : 8) + color; - break; - case CLR_BROWN: - color = (hicolor ? 64 : 32) + color; - break; - case CLR_MAGENTA: - color = (hicolor ? 80 : 40) + color; - break; - case CLR_CYAN: - color = (hicolor ? 96 : 48) + color; - break; - case CLR_GRAY: - color = (hicolor ? 112 : 56) + color; - break; - default: - break; - } - } - } - cattr |= COLOR_PAIR(color); - - return cattr; -} - -/* Returns a complete curses attribute. Used to possibly bold/underline/etc HP/Pw. */ -#ifdef STATUS_COLORS -static attr_t -hpen_color_attr(boolean is_hp, int cur, int max) -{ - struct color_option stat_color; - int count; - attr_t attr = 0; - if (!iflags.use_status_colors) - return curses_color_attr(CLR_GRAY, 0); - - stat_color = percentage_color_of(cur, max, is_hp ? hp_colors : pw_colors); - - if (stat_color.color != NO_COLOR) - attr |= curses_color_attr(stat_color.color, 0); - - for (count = 0; (1 << count) <= stat_color.attr_bits; count++) { - if (count != ATR_NONE && (stat_color.attr_bits & (1 << count))) - attr |= curses_convert_attr(count); - } - - return attr; -} -#endif - -/* Return color for the HP bar. - With status colors ON, this respect its configuration (defaulting to gray), but - only obeys the color (no weird attributes for the HP bar). - With status colors OFF, this returns reasonable defaults which are also used - for the HP/Pw text itself. */ -static int -hpen_color(boolean is_hp, int cur, int max) -{ -#ifdef STATUS_COLORS - if (iflags.use_status_colors) { - struct color_option stat_color; - stat_color = percentage_color_of(cur, max, is_hp ? hp_colors : pw_colors); - - if (stat_color.color == NO_COLOR) - return CLR_GRAY; - else - return stat_color.color; - } else - return CLR_GRAY; -#endif - - int color = CLR_GRAY; - if (cur == max) - color = CLR_GRAY; - else if (cur * 3 > max * 2) /* >2/3 */ - color = is_hp ? CLR_GREEN : CLR_CYAN; - else if (cur * 3 > max) /* >1/3 */ - color = is_hp ? CLR_YELLOW : CLR_BLUE; - else if (cur * 7 > max) /* >1/7 */ - color = is_hp ? CLR_RED : CLR_MAGENTA; - else - color = is_hp ? CLR_ORANGE : CLR_BRIGHT_MAGENTA; - - return color; -} - -/* Draws a bar - is_hp: TRUE if we're drawing HP, Pw otherwise (determines colors) - cur/max: Current/max HP/Pw - title: Not NULL if we are drawing as part of an existing title. - Otherwise, the format is as follows: [ 11 / 11 ] */ -static void -draw_bar(boolean is_hp, int cur, int max, const char *title) -{ - WINDOW *win = curses_get_nhwin(STATUS_WIN); - -#ifdef STATUS_COLORS - if (!iflags.hitpointbar) { - wprintw(win, "%s", !title ? "---" : title); - return; - } -#endif - - char buf[BUFSZ]; - if (title) - Strcpy(buf, title); - else { - int len = 5; - sprintf(buf, "%*d / %-*d", len, cur, len, max); - } - - /* Colors */ - attr_t fillattr, attr; - int color = hpen_color(is_hp, cur, max); - int invcolor = color & 7; - - fillattr = curses_color_attr(color, invcolor); - attr = curses_color_attr(color, 0); - - /* Figure out how much of the bar to fill */ - int fill = 0; - int len = strlen(buf); - if (cur > 0 && max > 0) - fill = len * cur / max; - if (fill > len) - fill = len; - - waddch(win, '['); - wattron(win, fillattr); - wprintw(win, "%.*s", fill, buf); - wattroff(win, fillattr); - wattron(win, attr); - wprintw(win, "%.*s", len - fill, &buf[fill]); - wattroff(win, attr); - waddch(win, ']'); -} - -/* Update the status win - this is called when NetHack would normally - write to the status window, so we know somwthing has changed. We - override the write and update what needs to be updated ourselves. */ -void -curses_update_stats(void) -{ - WINDOW *win = curses_get_nhwin(STATUS_WIN); - orient statorient = (orient) curses_get_window_orientation(STATUS_WIN); - boolean horiz = (statorient != ALIGN_RIGHT && statorient != ALIGN_LEFT); - boolean border = curses_window_has_border(STATUS_WIN); - - /* Clear the window */ - werase(win); - - /* Figure out if we have proper window dimensions for horizontal status */ - if (horiz) { - /* correct y */ - int cy = 3; - if (iflags.statuslines < 3) - cy = 2; - - /* actual y (and x) */ - int ax = 0; - int ay = 0; - getmaxyx(win, ay, ax); - if (border) - ay -= 2; - - if (cy != ay) { - curses_create_main_windows(); - curses_last_messages(); - doredraw(); - - /* Reset XP highlight (since classic_status and new show - different numbers) */ - prevexp.highlight_turns = 0; - curses_update_stats(); - return; - } - } - - /* Starting x/y. Passed to draw_horizontal/draw_vertical to keep track of - window positioning. */ - int x = 0; - int y = 0; - - /* Don't start at border position if applicable */ - if (border) { - x++; - y++; - } - - /* Get HP values. */ - int hp = u.uhp; - int hpmax = u.uhpmax; - if (Upolyd) { - hp = u.mh; - hpmax = u.mhmax; - } - - if (horiz) - draw_horizontal(x, y, hp, hpmax); - else - draw_vertical(x, y, hp, hpmax); - - if (border) - box(win, 0, 0); - - wnoutrefresh(win); - - if (first) { - first = FALSE; - - /* Zero highlight timers. This will call curses_update_status again - if needed */ - curses_decrement_highlights(TRUE); - } -} - -static void -draw_horizontal(int x, int y, int hp, int hpmax) -{ - if (iflags.statuslines >= 3) { - /* Draw new-style statusbar */ - draw_horizontal_new(x, y, hp, hpmax); - return; - } - char buf[BUFSZ]; - char rank[BUFSZ]; - WINDOW *win = curses_get_nhwin(STATUS_WIN); - - /* Line 1 */ - wmove(win, y, x); - - get_playerrank(rank); - sprintf(buf, "%s the %s", plname, rank); - - /* Use the title as HP bar (similar to hitpointbar) */ - draw_bar(TRUE, hp, hpmax, buf); - - /* Attributes */ - print_statdiff(" St:", &prevstr, ACURR(A_STR), STAT_STR); - print_statdiff(" Dx:", &prevdex, ACURR(A_DEX), STAT_OTHER); - print_statdiff(" Co:", &prevcon, ACURR(A_CON), STAT_OTHER); - print_statdiff(" In:", &prevint, ACURR(A_INT), STAT_OTHER); - print_statdiff(" Wi:", &prevwis, ACURR(A_WIS), STAT_OTHER); - print_statdiff(" Ch:", &prevcha, ACURR(A_CHA), STAT_OTHER); - - wprintw(win, (u.ualign.type == A_CHAOTIC ? " Chaotic" : - u.ualign.type == A_NEUTRAL ? " Neutral" : " Lawful")); - -#ifdef SCORE_ON_BOTL - if (flags.showscore) - print_statdiff(" S:", &prevscore, botl_score(), STAT_OTHER); -#endif /* SCORE_ON_BOTL */ - - - /* Line 2 */ - y++; - wmove(win, y, x); - - describe_level(buf); - - wprintw(win, "%s", buf); - - print_statdiff("$", &prevau, money_cnt(invent), STAT_GOLD); - - /* HP/Pw use special coloring rules */ - attr_t hpattr, pwattr; -#ifdef STATUS_COLORS - hpattr = hpen_color_attr(TRUE, hp, hpmax); - pwattr = hpen_color_attr(FALSE, u.uen, u.uenmax); -#else - int hpcolor, pwcolor; - hpcolor = hpen_color(TRUE, hp, hpmax); - pwcolor = hpen_color(FALSE, u.uen, u.uenmax); - hpattr = curses_color_attr(hpcolor, 0); - pwattr = curses_color_attr(pwcolor, 0); -#endif - wprintw(win, " HP:"); - wattron(win, hpattr); - wprintw(win, "%d(%d)", (hp < 0) ? 0 : hp, hpmax); - wattroff(win, hpattr); - - wprintw(win, " Pw:"); - wattron(win, pwattr); - wprintw(win, "%d(%d)", u.uen, u.uenmax); - wattroff(win, pwattr); - - print_statdiff(" AC:", &prevac, u.uac, STAT_AC); - - if (Upolyd) - print_statdiff(" HD:", &prevlevel, mons[u.umonnum].mlevel, STAT_OTHER); - else if (flags.showexp) { - print_statdiff(" Xp:", &prevlevel, u.ulevel, STAT_OTHER); - /* use waddch, we don't want to highlight the '/' */ - waddch(win, '/'); - print_statdiff("", &prevexp, u.uexp, STAT_OTHER); - } - else - print_statdiff(" Exp:", &prevlevel, u.ulevel, STAT_OTHER); - - if (flags.time) - print_statdiff(" T:", &prevtime, moves, STAT_TIME); - - curses_add_statuses(win, FALSE, FALSE, NULL, NULL); -} - -static void -draw_horizontal_new(int x, int y, int hp, int hpmax) -{ - char buf[BUFSZ]; - char rank[BUFSZ]; - WINDOW *win = curses_get_nhwin(STATUS_WIN); - - /* Line 1 */ - wmove(win, y, x); - - get_playerrank(rank); - char race[BUFSZ]; - Strcpy(race, urace.adj); - race[0] = highc(race[0]); - wprintw(win, "%s the %s %s%s%s", plname, - (u.ualign.type == A_CHAOTIC ? "Chaotic" : - u.ualign.type == A_NEUTRAL ? "Neutral" : "Lawful"), - Upolyd ? "" : race, Upolyd ? "" : " ", - rank); - - /* Line 2 */ - y++; - wmove(win, y, x); - wprintw(win, "HP:"); - draw_bar(TRUE, hp, hpmax, NULL); - print_statdiff(" AC:", &prevac, u.uac, STAT_AC); - if (Upolyd) - print_statdiff(" HD:", &prevlevel, mons[u.umonnum].mlevel, STAT_OTHER); - else if (flags.showexp) { - /* Ensure that Xp have proper highlight on level change. */ - int levelchange = 0; - if (prevlevel.value != u.ulevel) { - if (prevlevel.value < u.ulevel) - levelchange = 1; - else - levelchange = 2; - } - print_statdiff(" Xp:", &prevlevel, u.ulevel, STAT_OTHER); - /* use waddch, we don't want to highlight the '/' */ - waddch(win, '('); - - /* Figure out amount of Xp needed to next level */ - int xp_left = 0; - if (u.ulevel < 30) - xp_left = (newuexp(u.ulevel) - u.uexp); - - if (levelchange) { - prevexp.value = (xp_left + 1); - if (levelchange == 2) - prevexp.value = (xp_left - 1); - } - print_statdiff("", &prevexp, xp_left, STAT_AC); - waddch(win, ')'); - } - else - print_statdiff(" Exp:", &prevlevel, u.ulevel, STAT_OTHER); - - waddch(win, ' '); - describe_level(buf); - - wprintw(win, "%s", buf); - - /* Line 3 */ - y++; - wmove(win, y, x); - wprintw(win, "Pw:"); - draw_bar(FALSE, u.uen, u.uenmax, NULL); - - print_statdiff(" $", &prevau, money_cnt(invent), STAT_GOLD); - -#ifdef SCORE_ON_BOTL - if (flags.showscore) - print_statdiff(" S:", &prevscore, botl_score(), STAT_OTHER); -#endif /* SCORE_ON_BOTL */ - - if (flags.time) - print_statdiff(" T:", &prevtime, moves, STAT_TIME); - - curses_add_statuses(win, TRUE, FALSE, &x, &y); - - /* Right-aligned attributes */ - int stat_length = 6; /* " Dx:xx" */ - int str_length = 6; - if (ACURR(A_STR) > 18 && ACURR(A_STR) < 119) - str_length = 9; - - getmaxyx(win, y, x); - - /* We want to deal with top line of y. getmaxx would do what we want, but it only - exist for compatibility reasons and might not exist at all in some versions. */ - y = 0; - if (curses_window_has_border(STATUS_WIN)) { - x--; - y++; - } - - x -= stat_length; - int orig_x = x; - wmove(win, y, x); - print_statdiff(" Co:", &prevcon, ACURR(A_CON), STAT_OTHER); - x -= stat_length; - wmove(win, y, x); - print_statdiff(" Dx:", &prevdex, ACURR(A_DEX), STAT_OTHER); - x -= str_length; - wmove(win, y, x); - print_statdiff(" St:", &prevstr, ACURR(A_STR), STAT_STR); - - x = orig_x; - y++; - wmove(win, y, x); - print_statdiff(" Ch:", &prevcha, ACURR(A_CHA), STAT_OTHER); - x -= stat_length; - wmove(win, y, x); - print_statdiff(" Wi:", &prevwis, ACURR(A_WIS), STAT_OTHER); - x -= str_length; - wmove(win, y, x); - print_statdiff(" In:", &prevint, ACURR(A_INT), STAT_OTHER); -} - -/* Personally I never understood the point of a vertical status bar. But removing the - option would be silly, so keep the functionality. */ -static void -draw_vertical(int x, int y, int hp, int hpmax) -{ - char buf[BUFSZ]; - char rank[BUFSZ]; - WINDOW *win = curses_get_nhwin(STATUS_WIN); - - /* Print title and dungeon branch */ - wmove(win, y++, x); - - get_playerrank(rank); - int ranklen = strlen(rank); - int namelen = strlen(plname); - int maxlen = 19; -#ifdef STATUS_COLORS - if (!iflags.hitpointbar) - maxlen += 2; /* With no hitpointbar, we can fit more since there's no "[]" */ -#endif - - if ((ranklen + namelen) > maxlen) { - /* The result doesn't fit. Strip name if >10 characters, then strip title */ - if (namelen > 10) { - while (namelen > 10 && (ranklen + namelen) > maxlen) - namelen--; - } - - while ((ranklen + namelen) > maxlen) - ranklen--; /* Still doesn't fit, strip rank */ - } - sprintf(buf, "%-*s the %-*s", namelen, plname, ranklen, rank); - draw_bar(TRUE, hp, hpmax, buf); - wmove(win, y++, x); - wprintw(win, "%s", dungeons[u.uz.dnum].dname); - - y++; /* Blank line inbetween */ - wmove(win, y++, x); - - /* Attributes. Old vertical order is preserved */ - print_statdiff("Strength: ", &prevstr, ACURR(A_STR), STAT_STR); - wmove(win, y++, x); - print_statdiff("Intelligence: ", &prevint, ACURR(A_INT), STAT_OTHER); - wmove(win, y++, x); - print_statdiff("Wisdom: ", &prevwis, ACURR(A_WIS), STAT_OTHER); - wmove(win, y++, x); - print_statdiff("Dexterity: ", &prevdex, ACURR(A_DEX), STAT_OTHER); - wmove(win, y++, x); - print_statdiff("Constitution: ", &prevcon, ACURR(A_CON), STAT_OTHER); - wmove(win, y++, x); - print_statdiff("Charisma: ", &prevcha, ACURR(A_CHA), STAT_OTHER); - wmove(win, y++, x); - wprintw(win, "Alignment: "); - wprintw(win, (u.ualign.type == A_CHAOTIC ? "Chaotic" : - u.ualign.type == A_NEUTRAL ? "Neutral" : "Lawful")); - wmove(win, y++, x); - wprintw(win, "Dungeon Level: "); - - /* Astral Plane doesn't fit */ - if (In_endgame(&u.uz)) - wprintw(win, "%s", Is_astralevel(&u.uz) ? "Astral" : "End Game"); - else - wprintw(win, "%d", depth(&u.uz)); - wmove(win, y++, x); - - print_statdiff("Gold: ", &prevau, money_cnt(invent), STAT_GOLD); - wmove(win, y++, x); - - /* HP/Pw use special coloring rules */ - attr_t hpattr, pwattr; -#ifdef STATUS_COLORS - hpattr = hpen_color_attr(TRUE, hp, hpmax); - pwattr = hpen_color_attr(FALSE, u.uen, u.uenmax); -#else - int hpcolor, pwcolor; - hpcolor = hpen_color(TRUE, hp, hpmax); - pwcolor = hpen_color(FALSE, u.uen, u.uenmax); - hpattr = curses_color_attr(hpcolor, 0); - pwattr = curses_color_attr(pwcolor, 0); -#endif - - wprintw(win, "Hit Points: "); - wattron(win, hpattr); - wprintw(win, "%d/%d", (hp < 0) ? 0 : hp, hpmax); - wattroff(win, hpattr); - wmove(win, y++, x); - - wprintw(win, "Magic Power: "); - wattron(win, pwattr); - wprintw(win, "%d/%d", u.uen, u.uenmax); - wattroff(win, pwattr); - wmove(win, y++, x); - - print_statdiff("Armor Class: ", &prevac, u.uac, STAT_AC); - wmove(win, y++, x); - - if (Upolyd) - print_statdiff("Hit Dice: ", &prevlevel, mons[u.umonnum].mlevel, STAT_OTHER); - else if (flags.showexp) { - print_statdiff("Experience: ", &prevlevel, u.ulevel, STAT_OTHER); - /* use waddch, we don't want to highlight the '/' */ - waddch(win, '/'); - print_statdiff("", &prevexp, u.uexp, STAT_OTHER); - } - else - print_statdiff("Level: ", &prevlevel, u.ulevel, STAT_OTHER); - wmove(win, y++, x); - - if (flags.time) { - print_statdiff("Time: ", &prevtime, moves, STAT_TIME); - wmove(win, y++, x); - } - -#ifdef SCORE_ON_BOTL - if (flags.showscore) { - print_statdiff("Score: ", &prevscore, botl_score(), STAT_OTHER); - wmove(win, y++, x); - } -#endif /* SCORE_ON_BOTL */ - - curses_add_statuses(win, FALSE, TRUE, &x, &y); -} - -static void -curses_add_statuses(WINDOW *win, boolean align_right, - boolean vertical, int *x, int *y) -{ - if (align_right) { - /* Right-aligned statuses. Since add_status decrease one x more - (to separate them with spaces), add 1 to x unless we have borders - (which would offset what add_status does) */ - int mx = *x; - int my = *y; - getmaxyx(win, my, mx); - if (!curses_window_has_border(STATUS_WIN)) - mx++; - - *x = mx; - } - -#define statprob(str, trouble) \ - curses_add_status(win, align_right, vertical, x, y, str, trouble) - - /* Hunger */ - statprob(hu_stat[u.uhs], u.uhs != 1); /* 1 is NOT_HUNGRY (not defined here) */ - - /* General troubles */ - statprob("Conf", Confusion); - statprob("Blind", Blind); - statprob("Stun", Stunned); - statprob("Hallu", Hallucination); - statprob("Ill", (u.usick_type & SICK_NONVOMITABLE)); - statprob("FoodPois", (u.usick_type & SICK_VOMITABLE)); - statprob("Slime", Slimed); - - /* Encumbrance */ - int enc = near_capacity(); - statprob(enc_stat[enc], enc > UNENCUMBERED); -#undef statprob -} - -static void -curses_add_status(WINDOW *win, boolean align_right, boolean vertical, - int *x, int *y, const char *str, int trouble) -{ - /* If vertical is TRUE here with no x/y, that's an error. But handle - it gracefully since NH3 doesn't recover well in crashes. */ - if (!x || !y) - vertical = FALSE; - - if (!trouble) - return; - - if (!vertical && !align_right) - waddch(win, ' '); - - /* For whatever reason, hunger states have trailing spaces. Get rid of them. */ - char buf[BUFSZ]; - Strcpy(buf, str); - int i; - for (i = 0; (buf[i] != ' ' && buf[i] != '\0'); i++) ; - - buf[i] = '\0'; - if (align_right) { - *x -= (strlen(buf) + 1); /* add spacing */ - wmove(win, *y, *x); - } - - draw_trouble_str(buf); - - if (vertical) { - wmove(win, *y, *x); - *y += 1; /* ++ advances the pointer addr */ - } -} - -/* Decrement a single highlight, return 1 if decremented to zero. zero is TRUE if we're - zeroing the highlight. */ -static int -decrement_highlight(nhstat *stat, boolean zero) -{ - if (stat->highlight_turns > 0) { - if (zero) { - stat->highlight_turns = 0; - return 1; - } - - stat->highlight_turns--; - if (stat->highlight_turns == 0) - return 1; - } - return 0; -} - -/* Decrement the highlight_turns for all stats. Call curses_update_stats - if needed to unhighlight a stat */ -void -curses_decrement_highlights(boolean zero) -{ - int unhighlight = 0; - - unhighlight |= decrement_highlight(&prevdepth, zero); - unhighlight |= decrement_highlight(&prevstr, zero); - unhighlight |= decrement_highlight(&prevdex, zero); - unhighlight |= decrement_highlight(&prevcon, zero); - unhighlight |= decrement_highlight(&prevint, zero); - unhighlight |= decrement_highlight(&prevwis, zero); - unhighlight |= decrement_highlight(&prevcha, zero); - unhighlight |= decrement_highlight(&prevau, zero); - unhighlight |= decrement_highlight(&prevlevel, zero); - unhighlight |= decrement_highlight(&prevac, zero); - unhighlight |= decrement_highlight(&prevexp, zero); - unhighlight |= decrement_highlight(&prevtime, zero); -#ifdef SCORE_ON_BOTL - unhighlight |= decrement_highlight(&prevscore, zero); -#endif - - if (unhighlight) - curses_update_stats(); -} -#endif /*0*/ - /*cursstat.c*/ diff --git a/win/curses/cursstat.h b/win/curses/cursstat.h index e10977bb2..4d4ce2ac5 100644 --- a/win/curses/cursstat.h +++ b/win/curses/cursstat.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursstat.h */ +/* NetHack 5.0 cursstat.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -17,7 +17,7 @@ /* Global declarations */ -void curses_update_stats(); +void curses_update_stats(void); void curses_decrement_highlights(boolean); attr_t curses_color_attr(int nh_color, int bg_color); diff --git a/win/curses/curswins.c b/win/curses/curswins.c index bd2f505e8..21e1bae09 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -1,12 +1,18 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 curswins.c */ +/* NetHack 5.0 curswins.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ +#if defined(CURSES_UNICODE) && !defined(_XOPEN_SOURCE_EXTENDED) +#define _XOPEN_SOURCE_EXTENDED 1 +#endif #include "curses.h" #include "hack.h" #include "wincurs.h" +#include "cursinit.h" +#include "cursmisc.h" #include "curswins.h" +#include "cursstat.h" /* Window handling for curses interface */ @@ -18,8 +24,11 @@ typedef struct nhw { int width; /* Usable width not counting border */ int height; /* Usable height not counting border */ int x; /* start of window on terminal (left) */ - int y; /* start of window on termial (top) */ + int y; /* start of window on terminal (top) */ int orientation; /* Placement of window relative to map */ + boolean clr_inited; /* fg/bg/colorpair inited? */ + int fg, bg; /* foreground, background color index */ + int colorpair; /* color pair of fg, bg */ boolean border; /* Whether window has a visible border */ } nethack_window; @@ -32,7 +41,9 @@ typedef struct nhwd { typedef struct nhchar { int ch; /* character */ int color; /* color info for character */ + int framecolor; /* background color info for character */ int attr; /* attributes of character */ + struct unicode_representation *unicode_representation; } nethack_char; static boolean map_clipped; /* Map window smaller than 80x21 */ @@ -47,7 +58,7 @@ static void clear_map(void); /* Create a window with the specified size and orientation */ WINDOW * -curses_create_window(int width, int height, orient orientation) +curses_create_window(int wid, int width, int height, orient orientation) { int mapx = 0, mapy = 0, maph = 0, mapw = 0; int startx = 0; @@ -58,7 +69,7 @@ curses_create_window(int width, int height, orient orientation) if ((orientation == UP) || (orientation == DOWN) || (orientation == LEFT) || (orientation == RIGHT)) { - if (invent || (moves > 1)) { + if (svm.moves > 0) { map_border = curses_window_has_border(MAP_WIN); curses_get_window_xy(MAP_WIN, &mapx, &mapy); curses_get_window_size(MAP_WIN, &maph, &mapw); @@ -87,13 +98,14 @@ curses_create_window(int width, int height, orient orientation) switch (orientation) { default: impossible("curses_create_window: Bad orientation"); + FALLTHROUGH; /*FALLTHRU*/ case CENTER: startx = (term_cols / 2) - (width / 2); starty = (term_rows / 2) - (height / 2); break; case UP: - if (invent || (moves > 1)) { + if (svm.moves > 0) { startx = (mapw / 2) - (width / 2) + mapx + mapb_offset; } else { startx = 0; @@ -102,7 +114,7 @@ curses_create_window(int width, int height, orient orientation) starty = mapy + mapb_offset; break; case DOWN: - if (invent || (moves > 1)) { + if (svm.moves > 0) { startx = (mapw / 2) - (width / 2) + mapx + mapb_offset; } else { startx = 0; @@ -118,7 +130,7 @@ curses_create_window(int width, int height, orient orientation) starty = term_rows - height; break; case RIGHT: - if (invent || (moves > 1)) { + if (svm.moves > 0) { startx = (mapw + mapx + (mapb_offset * 2)) - width; } else { startx = term_cols - width; @@ -137,29 +149,94 @@ curses_create_window(int width, int height, orient orientation) } win = newwin(height, width, starty, startx); - curses_toggle_color_attr(win, DIALOG_BORDER_COLOR, NONE, ON); + + if (curses_is_text(wid)) + wid = TEXT_WIN; + else if (curses_is_menu(wid)) + wid = MENU_WIN; + + if (nhwins[wid].clr_inited < 1) + curses_toggle_color_attr(win, DIALOG_BORDER_COLOR, NONE, ON); box(win, 0, 0); - curses_toggle_color_attr(win, DIALOG_BORDER_COLOR, NONE, OFF); + if (nhwins[wid].clr_inited < 1) + curses_toggle_color_attr(win, DIALOG_BORDER_COLOR, NONE, OFF); return win; } +int +curses_win_clr_inited(int wid) +{ + if (curses_is_text(wid)) { + wid = TEXT_WIN; + } else if (curses_is_menu(wid)) { + wid = MENU_WIN; + } + return nhwins[wid].clr_inited; +} + +void +curses_set_wid_colors(int wid, WINDOW *win) +{ + if (wid == TEXT_WIN || curses_is_text(wid)) { + wid = TEXT_WIN; + if (!nhwins[wid].clr_inited) + curses_parse_wid_colors(wid, iflags.wcolors[wcolor_text].fg, + iflags.wcolors[wcolor_text].bg); + } else if (wid == MENU_WIN || curses_is_menu(wid)) { + wid = MENU_WIN; + if (!nhwins[wid].clr_inited) + curses_parse_wid_colors(wid, iflags.wcolors[wcolor_menu].fg, + iflags.wcolors[wcolor_menu].bg); + } + /* FIXME: colors and nhwins[] entry for perm invent window */ + if (nhwins[wid].clr_inited > 0) { + wbkgd(win ? win : nhwins[wid].curwin, + COLOR_PAIR(nhwins[wid].colorpair)); + } +} /* Erase and delete curses window, and refresh standard windows */ void curses_destroy_win(WINDOW *win) { - werase(win); - wrefresh(win); + int mapwidth = 0, winwidth, dummyht; + + /* + * In case map is narrower than the space alloted for it, if we + * are destroying a popup window and it is wider than the map, + * erase the popup first. It probably has overwritten some of + * the next-to-map empty space. If we don't clear that now, the + * base window will remember it and redisplay it during refreshes. + * + * Note: since we almost never destroy non-popups, we don't really + * need to determine whether 'win' is one. Overhead for unnecessary + * erasure is negligible. + */ + getmaxyx(win, dummyht, winwidth); /* macro, assigns to its args */ + if (mapwin) + getmaxyx(mapwin, dummyht, mapwidth); + if (winwidth > mapwidth) { + werase(win); + wnoutrefresh(win); + } + delwin(win); + if (win == activemenu) + activemenu = NULL; + /* during shutdown, RIP window could still be active after mapwin goes + away; so, avoid 'if (mapwin)' above when deleting RIP window later */ + if (win == mapwin) + win = mapwin = NULL; curses_refresh_nethack_windows(); + nhUse(dummyht); } /* Refresh nethack windows if they exist, or base window if not */ void -curses_refresh_nethack_windows() +curses_refresh_nethack_windows(void) { WINDOW *status_window, *message_window, *map_window, *inv_window; @@ -168,17 +245,29 @@ curses_refresh_nethack_windows() map_window = curses_get_nhwin(MAP_WIN); inv_window = curses_get_nhwin(INV_WIN); - if ((moves <= 1) && !invent) { + if (!iflags.window_inited) { + return; + } + + if (svm.moves == 0) { /* Main windows not yet displayed; refresh base window instead */ touchwin(stdscr); refresh(); } else { - touchwin(status_window); - wnoutrefresh(status_window); - touchwin(map_window); - wnoutrefresh(map_window); - touchwin(message_window); - wnoutrefresh(message_window); + if (status_window != NULL) { + curses_set_wid_colors(STATUS_WIN, NULL); + touchwin(status_window); + wnoutrefresh(status_window); + } + if (map_window != NULL) { + touchwin(map_window); + wnoutrefresh(map_window); + } + if (message_window != NULL) { + curses_set_wid_colors(MESSAGE_WIN, NULL); + touchwin(message_window); + wnoutrefresh(message_window); + } if (inv_window) { touchwin(inv_window); wnoutrefresh(inv_window); @@ -202,12 +291,74 @@ curses_get_nhwin(winid wid) return nhwins[wid].curwin; } +boolean +parse_hexstr(char *colorbuf, int *red, int *green, int *blue) +{ + int len = colorbuf ? strlen(colorbuf) : 0; + + if (len == 7 && colorbuf[0] == '#') { + char tmpbuf[16]; + + Sprintf(tmpbuf, "0x%c%c", colorbuf[1], colorbuf[2]); + *red = strtol(tmpbuf, NULL, 0); + Sprintf(tmpbuf, "0x%c%c", colorbuf[3], colorbuf[4]); + *green = strtol(tmpbuf, NULL, 0); + Sprintf(tmpbuf, "0x%c%c", colorbuf[5], colorbuf[6]); + *blue = strtol(tmpbuf, NULL, 0); + return TRUE; + } + return FALSE; +} + +void +curses_parse_wid_colors(int wid, char *fg, char *bg) +{ + + if (curses_is_text(wid)) { + wid = TEXT_WIN; + } else if (curses_is_menu(wid)) { + wid = MENU_WIN; + } + + if (nhwins[wid].clr_inited) + return; + + int nh_fg = fg ? match_str2clr(fg, TRUE) : CLR_MAX; + int nh_bg = bg ? match_str2clr(bg, TRUE) : CLR_MAX; + int r, g, b; + + if (nh_fg == CLR_MAX) { + if (fg && parse_hexstr(fg, &r, &g, &b)) { + nh_fg = curses_init_rgb(r, g, b); + } else { + nh_fg = -1; + } + } + if (nh_bg == CLR_MAX) { + if (bg && parse_hexstr(bg, &r, &g, &b)) { + nh_bg = curses_init_rgb(r, g, b); + } else { + nh_bg = -1; + } + } + + nhwins[wid].fg = nh_fg; + nhwins[wid].bg = nh_bg; + if (nh_fg == -1 || nh_bg == -1) { + nhwins[wid].clr_inited = -1; + } else { + nhwins[wid].colorpair = curses_init_pair(nh_fg, nh_bg); + nhwins[wid].clr_inited = 1; + } +} + /* Add curses window pointer and window info to list for given NetHack winid */ void -curses_add_nhwin(winid wid, int height, int width, int y, int x, - orient orientation, boolean border) +curses_add_nhwin( + winid wid, int height, int width, int y, int x, + orient orientation, boolean border) { WINDOW *win; int real_width = width; @@ -226,6 +377,9 @@ curses_add_nhwin(winid wid, int height, int width, int y, int x, nhwins[wid].x = x; nhwins[wid].y = y; nhwins[wid].orientation = orientation; + nhwins[wid].fg = nhwins[wid].bg = 0; + nhwins[wid].colorpair = -1; + nhwins[wid].clr_inited = 0; if (border) { real_width += 2; /* leave room for bounding box */ @@ -233,23 +387,24 @@ curses_add_nhwin(winid wid, int height, int width, int y, int x, } win = newwin(real_height, real_width, y, x); + nhwins[wid].curwin = win; switch (wid) { case MESSAGE_WIN: messagewin = win; + curses_parse_wid_colors(wid, iflags.wcolors[wcolor_message].fg, + iflags.wcolors[wcolor_message].bg); + curses_set_wid_colors(wid, NULL); break; case STATUS_WIN: statuswin = win; + curses_parse_wid_colors(wid, iflags.wcolors[wcolor_status].fg, + iflags.wcolors[wcolor_status].bg); + curses_set_wid_colors(wid, NULL); break; case MAP_WIN: mapwin = win; - - if ((width < COLNO) || (height < ROWNO)) { - map_clipped = TRUE; - } else { - map_clipped = FALSE; - } - + map_clipped = (width < COLNO || height < ROWNO); break; } @@ -257,7 +412,6 @@ curses_add_nhwin(winid wid, int height, int width, int y, int x, box(win, 0, 0); } - nhwins[wid].curwin = win; } @@ -292,6 +446,7 @@ curses_add_wid(winid wid) void curses_refresh_nhwin(winid wid) { + curses_set_wid_colors(wid, NULL); wnoutrefresh(curses_get_nhwin(wid)); doupdate(); } @@ -315,7 +470,10 @@ curses_del_nhwin(winid wid) wid); return; } - nhwins[wid].curwin = NULL; + if (nhwins[wid].curwin != NULL) { + delwin(nhwins[wid].curwin); + nhwins[wid].curwin = NULL; + } nhwins[wid].nhwin = -1; } @@ -350,18 +508,31 @@ curses_del_wid(winid wid) /* called by destroy_nhwindows() prior to exit */ void -curs_destroy_all_wins() +curs_destroy_all_wins(void) { curses_count_window((char *) 0); /* clean up orphan */ +#if 0 /* this works but confuses the static analyzer (from llvm-19, + * which reports "warning: Use of memory after it is freed") */ while (nhwids) curses_del_wid(nhwids->nhwid); +#else + while (nhwids) { + nethack_wid *tmpptr = nhwids; + + curses_del_wid(tmpptr->nhwid); + } +#endif } /* Print a single character in the given window at the given coordinates */ void -curses_putch(winid wid, int x, int y, int ch, int color, int attr) +curses_putch(winid wid, int x, int y, int ch, +#ifdef ENHANCED_SYMBOLS + struct unicode_representation *unicode_representation, +#endif + int color, int framecolor, int attr) { static boolean map_initted = FALSE; int sx, sy, ex, ey; @@ -384,7 +555,11 @@ curses_putch(winid wid, int x, int y, int ch, int color, int attr) --x; /* map column [0] is not used; draw column [1] in first screen col */ map[y][x].ch = ch; map[y][x].color = color; + map[y][x].framecolor = framecolor; map[y][x].attr = attr; +#ifdef ENHANCED_SYMBOLS + map[y][x].unicode_representation = unicode_representation; +#endif nch = map[y][x]; (void) curses_map_borders(&sx, &sy, &ex, &ey, -1, -1); @@ -437,6 +612,10 @@ curses_get_window_size(winid wid, int *height, int *width) boolean curses_window_has_border(winid wid) { + if (curses_is_menu(wid)) + wid = MENU_WIN; + else if (curses_is_text(wid)) + wid = TEXT_WIN; return nhwins[wid].border; } @@ -508,9 +687,11 @@ curses_puts(winid wid, int attr, const char *text) wid); return; } - Id = zeroany; - curses_add_nhmenu_item(wid, NO_GLYPH, &Id, 0, 0, attr, text, FALSE); + Id = cg.zeroany; + curses_add_nhmenu_item(wid, &nul_glyphinfo, &Id, 0, 0, + attr, NO_COLOR, text, MENU_ITEMFLAGS_NONE); } else { + curses_set_wid_colors(wid, NULL); waddstr(win, text); wnoutrefresh(win); } @@ -530,6 +711,7 @@ curses_clear_nhwin(winid wid) clear_map(); } + curses_set_wid_colors(wid, NULL); werase(win); if (border) { @@ -545,6 +727,7 @@ curses_alert_win_border(winid wid, boolean onoff) if (!win || !curses_window_has_border(wid)) return; + curses_set_wid_colors(wid, NULL); if (onoff) curses_toggle_color_attr(win, ALERT_BORDER_COLOR, NONE, ON); box(win, 0, 0); @@ -579,16 +762,97 @@ is_main_window(winid wid) /* Unconditionally write a single character to a window at the given coordinates without a refresh. Currently only used for the map. */ +/* convert nhcolor (fg) and framecolor (bg) to curses colorpair */ +int +get_framecolor(int nhcolor, int framecolor) +{ + /* curses_toggle_color_attr() adds the +1 and takes care of COLORS < 16 */ + return (16 * (framecolor % 8)) + (nhcolor % 16); +} + static void write_char(WINDOW * win, int x, int y, nethack_char nch) { - curses_toggle_color_attr(win, nch.color, nch.attr, ON); + int curscolor = nch.color, cursattr = nch.attr; + + if (nch.framecolor != NO_COLOR) { + curscolor = get_framecolor(nch.color, nch.framecolor); + if (nch.attr == A_REVERSE) + cursattr = A_NORMAL; /* hilited pet looks odd otherwise */ + } + curses_toggle_color_attr(win, curscolor, cursattr, ON); +#if defined(CURSES_UNICODE) && defined(ENHANCED_SYMBOLS) + if ((nch.unicode_representation && nch.unicode_representation->utf8str) + || SYMHANDLING(H_IBM)) { + /* CP437 to Unicode mapping according to the Unicode Consortium */ + static const uint16 cp437[256] = { + 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, + 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, + 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, + 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, + 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, + 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 + }; + attr_t attr; + short pair; + wchar_t wch[3]; + uint32 utf32ch; + cchar_t cch; + + if (SYMHANDLING(H_UTF8)) { + utf32ch = nch.unicode_representation->utf32ch; + } else if (SYMHANDLING(H_IBM)) { + utf32ch = cp437[(uint8)nch.ch]; + } else { + utf32ch = (uint8)nch.ch; + } + if (sizeof(wchar_t) == 2 && utf32ch >= 0x10000) { + /* UTF-16 surrogate pair */ + wch[0] = (wchar_t)((utf32ch >> 10) + 0xD7C0); + wch[1] = (wchar_t)((utf32ch & 0x3FF) + 0xDC00); + wch[2] = L'\0'; + } else { + wch[0] = (wchar_t)utf32ch; + wch[1] = L'\0'; + } + wmove(win, y, x); + wattr_get(win, &attr, &pair, NULL); + setcchar(&cch, wch, attr, pair, NULL); + mvwadd_wch(win, y, x, &cch); + } else +#endif #ifdef PDCURSES - mvwaddrawch(win, y, x, nch.ch); + mvwaddrawch(win, y, x, nch.ch); #else - mvwaddch(win, y, x, nch.ch); + mvwaddch(win, y, x, nch.ch); #endif - curses_toggle_color_attr(win, nch.color, nch.attr, OFF); + curses_toggle_color_attr(win, curscolor, cursattr, OFF); } @@ -612,16 +876,24 @@ curses_draw_map(int sx, int sy, int ex, int ey) #ifdef MAP_SCROLLBARS hsb_back.ch = '-'; hsb_back.color = SCROLLBAR_BACK_COLOR; + hsb_back.framecolor = NO_COLOR; hsb_back.attr = A_NORMAL; + hsb_back.unicode_representation = NULL; hsb_bar.ch = '*'; hsb_bar.color = SCROLLBAR_COLOR; + hsb_bar.framecolor = NO_COLOR; hsb_bar.attr = A_NORMAL; + hsb_bar.unicode_representation = NULL; vsb_back.ch = '|'; vsb_back.color = SCROLLBAR_BACK_COLOR; + vsb_back.framecolor = NO_COLOR; vsb_back.attr = A_NORMAL; + vsb_back.unicode_representation = NULL; vsb_bar.ch = '*'; vsb_bar.color = SCROLLBAR_COLOR; + vsb_bar.framecolor = NO_COLOR; vsb_bar.attr = A_NORMAL; + vsb_bar.unicode_representation = NULL; /* Horizontal scrollbar */ if (sx > 0 || ex < (COLNO - 1)) { @@ -630,17 +902,15 @@ curses_draw_map(int sx, int sy, int ex, int ey) if (sx > 0 && sbsx == 0) ++sbsx; - if (ex < ROWNO - 1 && sbex == ROWNO - 1) + if (ex < COLNO - 1 && sbex == COLNO - 1) --sbex; for (count = 0; count < sbsx; count++) { write_char(mapwin, count + bspace, ey - sy + 1 + bspace, hsb_back); } - for (count = sbsx; count <= sbex; count++) { write_char(mapwin, count + bspace, ey - sy + 1 + bspace, hsb_bar); } - for (count = sbex + 1; count <= (ex - sx); count++) { write_char(mapwin, count + bspace, ey - sy + 1 + bspace, hsb_back); } @@ -659,11 +929,9 @@ curses_draw_map(int sx, int sy, int ex, int ey) for (count = 0; count < sbsy; count++) { write_char(mapwin, ex - sx + 1 + bspace, count + bspace, vsb_back); } - for (count = sbsy; count <= sbey; count++) { write_char(mapwin, ex - sx + 1 + bspace, count + bspace, vsb_bar); } - for (count = sbey + 1; count <= (ey - sy); count++) { write_char(mapwin, ex - sx + 1 + bspace, count + bspace, vsb_back); } @@ -682,7 +950,7 @@ curses_draw_map(int sx, int sy, int ex, int ey) /* Init map array to blanks */ static void -clear_map() +clear_map(void) { int x, y; @@ -691,6 +959,7 @@ clear_map() map[y][x].ch = ' '; map[y][x].color = NO_COLOR; map[y][x].attr = A_NORMAL; + map[y][x].unicode_representation = NULL; } } } diff --git a/win/curses/curswins.h b/win/curses/curswins.h index ad2e5902f..ebf4c9bb5 100644 --- a/win/curses/curswins.h +++ b/win/curses/curswins.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 curswins.h */ +/* NetHack 5.0 curswins.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,11 +9,15 @@ /* Global declarations */ -WINDOW *curses_create_window(int width, int height, orient orientation); +WINDOW *curses_create_window(int wid, int width, int height, orient orientation); +int curses_win_clr_inited(int wid); +void curses_set_wid_colors(int wid, WINDOW *win); void curses_destroy_win(WINDOW * win); void curses_refresh_nethack_windows(void); WINDOW *curses_get_nhwin(winid wid); +void curses_parse_wid_colors(int wid, char *fg, char *bg); +boolean parse_hexstr(char *colorbuf, int *red, int *green, int *blue); void curses_add_nhwin(winid wid, int height, int width, int y, int x, orient orientation, boolean border); void curses_add_wid(winid wid); @@ -21,7 +25,14 @@ void curses_refresh_nhwin(winid wid); void curses_del_nhwin(winid wid); void curses_del_wid(winid wid); void curs_destroy_all_wins(void); -void curses_putch(winid wid, int x, int y, int ch, int color, int attrs); +#ifdef ENHANCED_SYMBOLS +void curses_putch(winid wid, int x, int y, int ch, + struct unicode_representation *ur, int color, + int framecolor, int attrs); +#else +void curses_putch(winid wid, int x, int y, int ch, int color, + int framecolor, int attrs); +#endif void curses_get_window_xy(winid wid, int *x, int *y); boolean curses_window_has_border(winid wid); boolean curses_window_exists(winid wid); diff --git a/win/gem/.gitattributes b/win/gem/.gitattributes deleted file mode 100644 index 6833fbaf2..000000000 --- a/win/gem/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* NH_filestag=(file%s_for_GEM_versions_-_untested_for_3.6.6) diff --git a/win/gem/Install.gem b/win/gem/Install.gem deleted file mode 100644 index c3742dee2..000000000 --- a/win/gem/Install.gem +++ /dev/null @@ -1,40 +0,0 @@ -$NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ - -Hi, - -This is nethack3.5.0 for Atari Gem and tty -Windowing System. - -It is by far not complete or perfect. -(My english too :-)) - -You need at least 2Meg free RAM, 16 colors and -3 Meg free Disk space. -In fact it works also with monochrome, but you -have to create a nh2.img (and title2.img) on your own. - -Atari windowport changes from 3.3.0: -added a ASCII-Mode in GEM -> F2 -the cursor is switchable -> F3 -added inventory/menu search -> : -removed the redraw problem -removed almost all flicker (except with NOVA-Card :-() -placed the GEM-dialogues more pleasent -tty corner windows (i.e. inv) display now correct in a vt52-win -greyed out old messages -placed the GEM-windows more convient -... - -Feel free to contact me about Issues and Errors. -e-mail: gaston@cs.tu-berlin.de - -You use this program at your own risk, I can't -guarantee it will work or do you no harm. - -Look at the nethack licence too. - -As you may have noticed the look and feel is from -Warwick Allisons nethack3.1.3d Gem Version -and I have used E_Gem2.2.0 from Christian Grunenberg. - -Marvin diff --git a/win/gem/bitmfile.c b/win/gem/bitmfile.c deleted file mode 100644 index d0b402ca1..000000000 --- a/win/gem/bitmfile.c +++ /dev/null @@ -1,338 +0,0 @@ -/****************************\ -* Bitmap mit Farbtabelle als * -* Graphik-Datei speichern * -* Autor: Gabriel Schmidt * -* (c) 1992 by MAXON-Computer * -* Modifiziert von Sebastian * -* Bieber, Dez. 1994 * -* -> Programmcode * -\****************************/ -/* - * $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.4 $ - */ - -#include -#include -#include -#include -#include - -#include "bitmfile.h" - -/* --- (X) IMG-Implementation ----------------- */ - -#define IMG_COMPRESSED - -typedef struct { - UWORD img_version; - UWORD img_headlen; - UWORD img_nplanes; - UWORD img_patlen; - UWORD img_pixw; - UWORD img_pixh; - UWORD img_w; - UWORD img_h; -} IMG_HEADER; - -typedef enum { NONE, SOLID0, SOLID1, PATRUN, BITSTR } IMG_MODE; - -typedef UBYTE IMG_SOLID; - -typedef enum { RGB = 0, CMY = 1, Pantone = 2 } XIMG_COLMODEL; - -typedef struct { - ULONG img_ximg; - XIMG_COLMODEL img_colmodel; -} XIMG_HEADER; - -typedef struct RGB XIMG_RGB; - -int -bitmap_to_img(FILE_TYP typ, int ww, int wh, unsigned int pixw, - unsigned int pixh, unsigned int planes, unsigned int colors, - const char *filename, - void (*get_color)(unsigned int colind, struct RGB *rgb), - void (*get_pixel)(int x, int y, unsigned int *colind)) -{ - int file, error, cnt; - IMG_HEADER header; - XIMG_HEADER xheader; - XIMG_RGB xrgb; - IMG_MODE mode; - UBYTE *line_buf, *write_buf; - register UBYTE *startpnt, *bufpnt; - unsigned int colind, line_len, line, bit; - register unsigned int byte; - register UBYTE count; - - /* fill in (X) IMG-Header */ - - header.img_version = 1; - header.img_headlen = (UWORD) sizeof(header) / 2; - if (typ == XIMG) - header.img_headlen += - (UWORD)(sizeof(xheader) + colors * sizeof(xrgb)) / 2; - - header.img_nplanes = planes; - header.img_patlen = 2; - header.img_pixw = pixw; - header.img_pixh = pixh; - header.img_w = ww; - header.img_h = wh; - - xheader.img_ximg = XIMG_MAGIC; - xheader.img_colmodel = RGB; - - /* calculate linelength, allocate buffer. */ - - line_len = (ww + 7) / 8; - - line_buf = malloc((size_t) planes * line_len); - if (line_buf == NULL) - return (ENOMEM); - - /* Worst case: the bufferd line could grow to max. 3 times the length */ - /* of the original! - */ - - write_buf = malloc((size_t) 3 * line_len); - if (write_buf == NULL) { - free(line_buf); - return (ENOMEM); - }; - - /* open file */ - - file = open(filename, O_WRONLY | O_CREAT | O_TRUNC); - if (file < 0) { - error = errno; - free(line_buf); - free(write_buf); - return (error); - }; - - /* write Header */ - - if (write(file, &header, sizeof(header)) != sizeof(header) - || (typ == XIMG - && write(file, &xheader, sizeof(xheader)) != sizeof(xheader))) { - error = errno; - close(file); - free(line_buf); - free(write_buf); - return (error); - }; - - /* save the colortable if possible */ - - if (typ == XIMG) - for (cnt = 0; cnt < colors; cnt++) { - get_color(cnt, &xrgb); - if (write(file, &xrgb, sizeof(xrgb)) != sizeof(xrgb)) { - error = errno; - close(file); - free(line_buf); - free(write_buf); - return (error); - }; - }; - - /* And now line by line ... */ - - for (line = 0; line < wh; line++) { - /* get pixel, split it up and */ - /* store it as planes in buffer */ - - for (byte = 0; byte < line_len; byte++) { - for (cnt = 0; cnt < planes; cnt++) - line_buf[cnt * line_len + byte] = 0x00; - - for (bit = 0; bit < 8; bit++) { - if (8 * byte + bit < ww) - get_pixel(8 * byte + bit, line, &colind); - - for (cnt = 0; cnt < planes; cnt++) { - line_buf[cnt * line_len + byte] <<= 1; - line_buf[cnt * line_len + byte] |= colind & 0x01; - colind >>= 1; - }; - }; - }; - - /* compress bitstrings in buffer */ - /* and write it to file */ - - for (cnt = 0; cnt < planes; cnt++) { - /* Bitstringpointer to start of plane */ - - startpnt = &line_buf[cnt * line_len]; - bufpnt = write_buf; - - while (startpnt < &line_buf[(cnt + 1) * line_len]) { - /*********************************************/ - /* Which _new_ compression-mode "fits" the */ - /* the current byte? - */ - /* Note: the compressing modes get choosen */ - /* "positive". The non compressing BITSTR- */ - /* mode is choosen only if nothing else */ - /* "fits" ... - */ - /*********************************************/ - - switch (*startpnt) { - case 0x00: - mode = SOLID0; - break; - case 0xFF: - mode = SOLID1; - break; - default: - if (startpnt < &line_buf[(cnt + 1) * line_len - 3] - && *(startpnt) == *(startpnt + 2) - && *(startpnt + 1) == *(startpnt + 3)) - mode = PATRUN; - else - mode = BITSTR; - }; - - /************************************************/ - /* The mode is choosen, now work with it. - */ - /* The compressing modi stay current as long as */ - /* possible. - */ - /************************************************/ - - count = 0; - - switch (mode) { - case SOLID0: - while ((startpnt < &line_buf[(cnt + 1) * line_len]) - && (*(startpnt) == 0x00) && (count < 0x7F)) { - startpnt++; - count++; - }; - *(bufpnt++) = count; - break; - - case SOLID1: - while ((startpnt < &line_buf[(cnt + 1) * line_len]) - && (*(startpnt) == 0xFF) && (count < 0x7F)) { - startpnt++; - count++; - }; - *(bufpnt++) = 0x80 | count; - break; - - case PATRUN: - *(bufpnt++) = 0x00; - startpnt += 2; - count = 1; - while (startpnt < &line_buf[(cnt + 1) * line_len - 1] - && *(startpnt) == *(startpnt - 2) - && *(startpnt + 1) == *(startpnt - 1) - && (count < 0xFF)) { - count++; - startpnt += 2; - }; - *(bufpnt++) = count; - *(bufpnt++) = *(startpnt - 2); - *(bufpnt++) = *(startpnt - 1); - break; - - /************************************************/ - /* The while Condition is ment as follows: */ - /* */ - /* while ( NOT(2-Byte-Solidrun possible) && - */ - /* NOT(6-Byte-Patternrun possible) && - */ - /* count < 0xFF - * && */ - /* still Bytes remaining ) - */ - /* */ - /* As soon as a _compressing_ alternative shows */ - /* up, BITSTR gets cancelled! - */ - /************************************************/ - - case BITSTR: - *(bufpnt++) = 0x80; - while (!(((startpnt + count) - < &line_buf[(cnt + 1) * line_len - 1]) - && (((*(startpnt + count) == 0xFF) - && (*(startpnt + count + 1) == 0xFF)) - || ((*(startpnt + count) == 0x00) - && (*(startpnt + count + 1) == 0x00)))) - && !(((startpnt + count) - < &line_buf[(cnt + 1) * line_len - 5]) - && (*(startpnt + count) - == *(startpnt + count + 2)) - && (*(startpnt + count + 1) - == *(startpnt + count + 3)) - && (*(startpnt + count) - == *(startpnt + count + 4)) - && (*(startpnt + count + 1) - == *(startpnt + count + 5))) - && (count < 0xFF) - && ((startpnt + count) - < &line_buf[(cnt + 1) * line_len])) - count++; - *(bufpnt++) = count; - for (; count > 0; count--) - *(bufpnt++) = *(startpnt++); - break; - }; - }; - - if (write(file, write_buf, bufpnt - write_buf) - != (bufpnt - write_buf)) { - error = errno; - close(file); - free(line_buf); - free(write_buf); - return (error); - }; - }; - }; - - /*close file, free buffer. */ - - close(file); - free(line_buf); - free(write_buf); - return (0); -} - -/*---filetype-dispatcher--------------------*/ - -const char * -get_file_ext(FILE_TYP typ) -{ - switch (typ) { - case IMG: - case XIMG: - return ("IMG"); - default: - return (""); - }; -} - -int -bitmap_to_file(FILE_TYP typ, int ww, int wh, unsigned int pwx, - unsigned int pwy, unsigned int planes, unsigned int colors, - const char *filename, - void (*get_color)(unsigned int colind, struct RGB *rgb), - void (*get_pixel)(int x, int y, unsigned int *colind)) -{ - switch (typ) { - case IMG: - case XIMG: - return (bitmap_to_img(typ, ww, wh, pwx, pwy, planes, colors, filename, - get_color, get_pixel)); - default: - return (-1); - }; -} diff --git a/win/gem/gem_rsc.uu b/win/gem/gem_rsc.uu deleted file mode 100644 index 32b3900ea..000000000 --- a/win/gem/gem_rsc.uu +++ /dev/null @@ -1,230 +0,0 @@ -begin 777 GEM_RSC.RSC -M $29@^Z$B(/N@^Z #0)&@^Z)]X Y0 , !8 @ "@. -M "!.151(04-+ "!'86UE "!(97)E "!4:&5R90 @271E;0 @07!P -M87)E; @36%G:6, ("!!8F]U="!.971H86-K+BXN "TM+2TM+2TM+2TM+2TM -M+2TM+2TM+2T ("!$97-K($%C8V5S2 Q(" ("!$97-K($%C8V5S2 R(" ("!$97-K($%C8V5S2 S(" ("!$97-K($%C8V5S2 T -M(" ("!$97-K($%C8V5S2 U(" ("!$97-K($%C8V5S2 V(" -M("!(96QP+BXN(" @(" @(" @/P @(%=H870@:7,N+BX@(" @(" O " @0V]M -M;6%N9"!H96QP+BXN("8 +2TM+2TM+2TM+2TM+2TM+2TM+2TM " @3W!T:6]N -M" @ -M(" @( 5L " @16YG00 M+2TM -M+2TM+2TM+2TM+2TM " @3&]O:R!A=" @(" [ " @4V5A " @2G5M<" @(" @( 5J " @ -M0VAA=" @(" @( 5C " @1FEG:'0@(" @("!& " @4VAO=R!A;&P@(" @("!I -M " @4VAO=R!K:6YD(" @("!) " @1&ES8V]V97)I97,@("!< "TM+2TM+2TM -M+2TM+2TM+2TM+2T ("!%870@(" @(" @(" @(&4 ("!$2 @(" @(" @(&$ ("!5 @($9I;&P@<75I=F5R(" @ -M(" @40 @($9I2 @(% ("!296UO -M=F4@86-C97-S;W)Y(%( ("!7;W)N(')I;F=S(" @(" @(#T ("!7;W)N(&%M -M=6QE=" @(" @("( ("!,:7-T('-P96QL@ @($-A'#P)'$< X#@0/YS^"!P' . X$#_=_@@?GF @ !@)__^8"0 F D 59@) "8"0!5F D )@) 168"0 -MF D%!9@$@ $X!($5, 2 3 "0%9P D "8 $@5. D G $A3@ D)P $DX -M F< $. G ' #SP\\ \\//@/ -M___X#___^ ____@/ #X#U55^ \ /@/557X#P ^ ]55?@/ #X#U55^ > -M ?@'U57P!X !\ /55_ #P /@ ?47X #P#\ ?5^ #P_ ??@ #_P ?X -M #\ < '0 !V\ =P 4 !@ "$8 /__ -M "\ 0 !W$ >1 'D@ % 8 A& #__P @ $ >: 'HP !Z0 -M P & 0 __\ "0 ! 'V0 !]L ?E , !@ "$8 /__ ( "@ -M!^H ?O '^P # 8 A& #__P % P @ ("0 " H P & 0 -M __\ "0 ! ("P "$$ AW , !@ "$8 /__ #8 -@ "(, B% -M (A@ # 8 A$ #__@ " $ B' (B0 "(H P & (1 __X -M @ ! (BP "(T B. , !@ "$0 /_^ ( 0 "(\ B1 (D@ # -M 8 A$ #__@ " $ B3 (E0 ")8 P & (1 __X @ ! ( -MEP ")D B: , !@ "$0 /_^ ( 0 ")L B= (G@ # 8 A$ -M #__@ " $ B? (H0 "*( P & (1 __X @ ! (HP "*4 -M BF , !@ "$0 /_^ ( 0 "*< BN (KP % 8 A& #__P ' -M $ BP (M0 "+8 !0 & (1@ __\ !0 ! (MP "- C1 , -M!@ "$P, /__ !D 0 "-( C= (Z # 8 I!Y #__P + L CJ -M ([0 ".X P & (0> $ P ! ([P "0H D+ , !@ "$0$ -M /__ !L 0 "^H D: &URD 4 !( @ \Z -M .N@ "1$0 !P " ( ! " +0 (__\ 0 * !D -M : 9 H @ " !0 1 : ,! $ P ) !D -M " ,@,! 3_____ " - "0,! 7_____ " -M /0 ) !@,! ;_____ " 0P / !@,! ?_____ -M " 20 5 !P,! C_____ " 4 < !@,! G_ -M____ " 5@ B "0,! +_____ " 7P K !P,! -M "P!< !D P$ 40 3 !0 # 3 !0 /\1 " -M%@ ( W_____ !P 9@ %@ ! [_____ !P ( >0 -M $ %@ ! ______ !P D ( %@ ! !#_____ !P -MI0 , %@ ! !'_____ !P N@ 0 %@ ! !+_____ !P -M SP 4 %@ ! !/_____ !P Y 8 %@ ! O_____ !P -M ^0 < %@ ! !\ %0 > !0 /\1 + %0 * !;_____ -M !P !#@ %0 ! !?_____ !P !(@ $ %0 ! !C_ -M____ !P !-@ ( %0 ! !G_____ !P ( !2@ , %0 ! -M !K_____ !P !8 0 %0 ! !O_____ !P != 4 -M%0 ! !S_____ !P ( !B 8 %0 ! !W_____ !P !G@ -M < %0 ! ![_____ !P ( !L@ @ %0 ! !3_____ !P ! -MR D %0 ! "X ( M !0 /\1 1 % . "'_____ !P -M !W % ! "+_____ !P ![P $ % ! "/_____ !P -M " @ ( % ! "3_____ !P "%0 , % ! "7_____ -M !P "* 0 % ! ";_____ !P ".P 4 % ! "?_ -M____ !P "3@ 8 % ! "C_____ !P ( "80 < % ! -M "G_____ !P "=@ @ % ! "K_____ !P "B0 D -M% ! "O_____ !P ( "G H % ! "S_____ !P "L0 -M L % ! "W_____ !P "Q P % ! !______ !P " -MUP T % ! #L +P Z !0 /\1 7 $ , ##_____ !P -M "Z@ $ ! #'_____ !P ( "^0 $ $ ! #+_____ !P -M #"@ ( $ ! #/_____ !P #&0 , $ ! #3_____ -M !P #* 0 $ ! #7_____ !P #-P 4 $ ! #;_ -M____ !P #1@ 8 $ ! #?_____ !P #50 < $ ! -M #C_____ !P #9 @ $ ! #G_____ !P #

$P / #W_____ !P # -MH $P ! #[_____ !P #L@ $ $P ! #______ !P -M #Q ( $P ! $#_____ !P ( #U@ , $P ! $'_____ !P -M #Z@ 0 $P ! $+_____ !P #_ 4 $P ! $/_____ -M !P $#@ 8 $P ! $3_____ !P $( < $P ! $7_ -M____ !P $,@ @ $P ! $;_____ !P $1 D $P ! -M $?_____ !P $5@ H $P ! $C_____ !P $: L -M$P ! $G_____ !P ( $>@ P $P ! $K_____ !P $C@ -M T $P ! #O_____ !P $H X $P ! %P 3 !; !0 /\1 -M D %@ 0 $W_____ !P $L@ %@ ! $[_____ !P -M $QP $ %@ ! $______ !P $W ( %@ ! %#_____ !P -M $\0 , %@ ! %'_____ !P %!@ 0 %@ ! %+_____ -M !P %&P 4 %@ ! %/_____ !P ( %, 8 %@ ! %3_ -M____ !P %1P < %@ ! %7_____ !P %7 @ %@ ! -M %;_____ !P %<0 D %@ ! %?_____ !P %A@ H -M%@ ! %C_____ !P ( %FP L %@ ! %G_____ !P %L@ -M P %@ ! %K_____ !P %QP T %@ ! %O_____ !P % -MW X %@ ! $O_____ !P %\0 \ %@ ! H 70!H !0 -M /\1 M $@ , %[_____ !P &!@ $@ ! %______ !P -M ( &%P $ $@ ! &#_____ !P &*@ ( $@ ! &'_____ -M !P &.P , $@ ! &+_____ !P &3 0 $@ ! &/_ -M____ !P &70 4 $@ ! &3_____ !P &;@ 8 $@ ! -M &7_____ !P &?P < $@ ! &;_____ !P &D @ -M$@ ! &?_____ !P &H0 D $@ ! &C_____ !P &L@ -M H $@ ! %S_____ !P ( &PP L $@ !__\ 0 ! !0 1 -M 4 3P " #_____"Q0 8 $1>0 @ "__\ 0 ! !0 -M $1 " $ H 5 #_____ !D ( $A 1 , @ !__\ 0 *"Q0 -M 0 (1 # $ +@ * +_____ !H,!P &U I @$ P8! 4 P $ -M !0 /\1 0 !" #0 ' 3_____ !\ 2(@ "" !0 % +_ -M____ !P &V #" 4 !P ! ;_____ !P( &X / $ %0 ! -M ?_____ !P &]@ / , '@ ! C_____ !P '%0 / 0 -M$0 ! G_____ !P ')P / 8 & ! K_____ !4 /N@ ! -M# <$(@ ! #_____ !4 ( /U@ !" @ (0 !__\ 0 ""Q0 0 /X1 -M> ! ( 3P@6 +_____$QH,!P 'DP " !4 " ! #_____ !@ ( -M ) ( @ &3@ 4__\ 0 ["Q0 0 (1> ! $ + ) +_____ !4( -M /\@ " $ " ! #< P U !0 $1>0 " , * @# 4 ! $ -M !H,!0 'I0 !" @ ! /_____!1D $1 0 ! < -M!@ & !H,!0 'IP $" @ ! 7_____!1D $1 0 ! -M D " ( !H,!0 'J0 '" @ ! ?_____!1D $1 -M 0 ! L "@ * !H,!0 'JP *" @ ! G_____!1D $1 -M 0 ! T # , !H,!0 'K0 -" @ ! O_____!1D $1 -M 0 ! \ #@ . !H,!0 'KP 0" @ ! W_____!1D -M $1 0 ! !$ $ 0 !H,!0 'L0 3" @ ! ______!1D -M $1 0 ! !, $@ 2 !H,!0 'LP 6" @ ! !'_____ -M!1D $1 0 ! !4 % 4 !H,!0 'M0 9" @ ! !/_ -M____!1D $1 0 ! !< %@ 6 !H,!0 'MP <" @ ! -M !7_____!1D $1 0 ! !D & 8 !H,!0 'N0 ?" -M @ ! !?_____!1D $1 0 ! !L &@ : !H,!0 'NP B -M" @ ! !G_____!1D $1 0 ! !T ' < !H,!0 ' -MO0 E" @ ! !O_____!1D $1 0 ! !\ '@ > !H,!0 -M 'OP ! ( @ ! !W_____!1D $1 0 ! "$ ( @ !H, -M!0 'P0 $ ( @ ! !______!1D $1 0 ! ", (@ B -M !H,!0 'PP ' ( @ ! "'_____!1D $1 0 ! "4 -M) D !H,!0 'Q0 * ( @ ! "/_____!1D $1 0 ! -M "< )@ F !H,!0 'QP - ( @ ! "7_____!1D $1 -M 0 ! "D * H !H,!0 'R0 0 ( @ ! "?_____!1D $1 -M 0 ! "L *@ J !H,!0 'RP 3 ( @ ! "G_____!1D $1 -M 0 ! "T + L !H,!0 'S0 6 ( @ ! "O_____!1D -M $1 0 ! "\ +@ N !H,!0 'SP 9 ( @ ! "W_____!1D -M $1 0 ! #$ , P !H,!0 'T0 < ( @ ! "______ -M!1D $1 0 ! #, ,@ R !H,!0 'TP ? ( @ ! #'_ -M____!1D $1 0 ! #4 - T !H,!0 'U0 B ( @ ! -M #/_____!1D $1 0 ! ( -@ V !H,!0 'UP E ( -M @ ! #7_____!1D $1 0 ! #H . Y !0 $1>0 # -M , %@ # #G_____ !X(" 0#@ ! $ "P ! #?_____ !H,!P ' -MYP - $ !P ! #O_____ !X(" 0*@ # < # ! #_____ !H,)0 -M '_0 1 < !@ !__\ 0 $"Q0( 0 (1> ! $ .P ' +_____ !4( -M 01@ " $ -P ! /_____ !X(" 08@ " , -P ! 3_____ -M$QH$!0 (>0 # 4 " ! #_____ !H,)P (@ P 4 " !__\ -M 0 9"Q0 0 1> ( 0 # & +_____ !L 0 6> % @ ! -M /_____ !L ! 6> " ( @ ! 3_____ !L P 6> *" ( -M @ ! 7_____ !L @ 6> % 4 @ ! < !@ & !8,!0 0?@ " -M 0 @ ! 7_____!1D $1 0 ! D " ( !8,!0 0 -MF@ % 0 @ ! ?_____!1D $1 0 ! L "@ * !8,!0 -M 0M@ ( 0 @ ! G_____!1D $1 0 ! T # , !8, -M!0 0T@ "" ( @ ! O_____!1D $1 0 ! \ #@ . -M !8,!0 0[@ %" ( @ ! W_____!1D $1 0 ! !$ -M$ 0 !8,!0 1"@ (" ( @ ! ______!1D $1 0 ! -M !, $@ 2 !8,!0 1)@ " $ @ ! !'_____!1D $1 -M 0 ! !4 % 4 !8,!0 10@ % $ @ ! !/_____!1D $1 -M 0 ! !< %@ 6 !8,!0 17@ ( $ @ ! !7_____!1D $1 -M 0 ! !D & 8 !8,!0 1>@ '! 4 !0P !?_____!1D -M $1 ! 0P &@ : !8,!0 1E@ ' !0P !G_____!1D -M( $1 ! 0P __\ 0 $ !0 1 ! 4 3P # +_____ -M !L, 0 0 6>0 @ ! /_____"Q0( $1>0 $ @ ! 3_ -M____ !L, 0 @ 6>0 ( @ ! #_____ !@ ( + " 30 # -M__\ 0 $"Q0 0 (1>0 ! $ + @4 +_____ !4( 1L@ ! -M+ ! /_____"AX " 1S@ . !( $ ! 3_____ !8,!P 1Z@ A -M !( "0@! #_____ !8 ( 2!@ " $ * @,__\ 0 !"Q0 $1 -M<@ # , " " #_____ !H,)P )# !" !@ !__\ 0 ! !0 0 @ -M /\1>0 " , !@ # #_____ !\ ( 21 P # 29@ '#X -G !QN N -end diff --git a/win/gem/gem_rso.uu b/win/gem/gem_rso.uu deleted file mode 100644 index cd555da9d..000000000 --- a/win/gem/gem_rso.uu +++ /dev/null @@ -1,22 +0,0 @@ -begin 777 GEM_RSC.RSO -M4E-/2 1( @ " ! !#__P __\ -M -M '___^!____@ -M #__P #__P -M -M /_ '___^!____@ :1F]1)Y2KX@ -M (\TJP "!$U%3E4 P'1$]!0D]55 '@9$3U%5250 __\ 0 #"E-4 -M05154TQ)3D4 $*1U)!0E-405154P#__P " ,&34%05TE. !DU!4$)/ -M6 0E-05!#55)33U( __\ P #!4%"3U54 "$9,64%"3U54 !!T]+ -M04)/550 ,+3D542$%#2TE-1S __\ ! #!4Q)3D53 "$9,64Q)3D53 -M !!5%,24Y% ""4Q)3D533$E35 #__P % ,(64Y#2$])0T4 +1DQ9 -M64Y#2$])0T4 $(64Y04D]-4%0 ()4T]-14-(05)3 # UE.,0 -0-9 -M3DX #<'04Y90TA!4@ . A#2$]314Y#2 .@5#3U5.5 .P193D]+ /__ -M 8 P=,24Y%1T54 "D9,64Q)3D5'150 $(3$=04D]-4%0 ('3$=2 -M15!,60 P-13$< 0$3$=/2P#__P ' ,)1$E214-424]. #$9,641) -M4D5#5$E/3@ !01$25(Q 5!$1)4CD !<'1$E21$]73@ &05$25)54 #_ -M_P ( ,&35-'5TE. !!55035-' ""D=204)-4T=724X ,%1$Y-4T< -M 0(35-'3$E.15, __\ "0 #!TY!345'150 *1DQ93D%-14=%5 @90 -M3$Y!344 0.3D542$%#2U!)0U154D4 __\ "@ #!5!!1T52 "$9,65!! -@1T52 !!E%004=%4@#__P + ,&3DA)0T]. /____\ -end diff --git a/win/gem/gr_rect.c b/win/gem/gr_rect.c deleted file mode 100644 index ecd689093..000000000 --- a/win/gem/gr_rect.c +++ /dev/null @@ -1,204 +0,0 @@ -/* NetHack 3.6 gr_rect.c $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ - */ -/* Copyright (c) Christian Bressler, 2001 */ -/* NetHack may be freely redistributed. See license for details. */ -/* This is an almost exact copy of qt_clust.cpp */ -/* gr_rect.c */ -#include -#include -#include -#include "gr_rect.h" -dirty_rect * -new_dirty_rect(int size) -{ - dirty_rect *new = NULL; - if (size > 0) { - new = (dirty_rect *) calloc(1L, sizeof(dirty_rect)); - if (new) { - new->rects = (GRECT *) calloc((long) size, sizeof(GRECT)); - if (new->rects == NULL) { - free(new); - return (NULL); - } - new->max = size; - } - } - return (new); -} -void -delete_dirty_rect(dirty_rect *this) -{ - if (this == NULL) - return; - if (this->rects) - free(this->rects); - /* In case the Pointer is reused wrongly */ - this->rects = NULL; - this->max = 0; - this->used = 0; - free(this); -} -static int gc_inside(GRECT *frame, GRECT *test); -static int gc_touch(GRECT *frame, GRECT *test); -static void gc_combine(GRECT *frame, GRECT *test); -static long gc_area(GRECT *area); -int -add_dirty_rect(dirty_rect *dr, GRECT *area) -{ - int cursor; - long lowestcost = 9999999L; - int cheapest = -1; - int cheapestmerge1 = -1; - int cheapestmerge2 = -1; - int merge1; - int merge2; - for (cursor = 0; cursor < dr->used; cursor++) { - if (gc_inside(&dr->rects[cursor], area)) { - /* Wholly contained already. */ - return (TRUE); - } - } - for (cursor = 0; cursor < dr->used; cursor++) { - if (gc_touch(&dr->rects[cursor], area)) { - GRECT larger = dr->rects[cursor]; - long cost; - gc_combine(&larger, area); - cost = gc_area(&larger) - gc_area(&dr->rects[cursor]); - if (cost < lowestcost) { - int bad = FALSE, c; - for (c = 0; c < dr->used && !bad; c++) { - bad = gc_touch(&dr->rects[c], &larger) && c != cursor; - } - if (!bad) { - cheapest = cursor; - lowestcost = cost; - } - } - } - } - if (cheapest >= 0) { - gc_combine(&dr->rects[cheapest], area); - return (TRUE); - } - if (dr->used < dr->max) { - dr->rects[dr->used++] = *area; - return (TRUE); - } - // Do cheapest of: - // add to closest cluster - // do cheapest cluster merge, add to new cluster - lowestcost = 9999999L; - cheapest = -1; - for (cursor = 0; cursor < dr->used; cursor++) { - GRECT larger = dr->rects[cursor]; - long cost; - gc_combine(&larger, area); - cost = gc_area(&larger) - gc_area(&dr->rects[cursor]); - if (cost < lowestcost) { - int bad = FALSE, c; - for (c = 0; c < dr->used && !bad; c++) { - bad = gc_touch(&dr->rects[c], &larger) && c != cursor; - } - if (!bad) { - cheapest = cursor; - lowestcost = cost; - } - } - } - // XXX could make an heuristic guess as to whether we - // XXX need to bother looking for a cheap merge. - for (merge1 = 0; merge1 < dr->used; merge1++) { - for (merge2 = 0; merge2 < dr->used; merge2++) { - if (merge1 != merge2) { - GRECT larger = dr->rects[merge1]; - long cost; - gc_combine(&larger, &dr->rects[merge2]); - cost = gc_area(&larger) - gc_area(&dr->rects[merge1]) - - gc_area(&dr->rects[merge2]); - if (cost < lowestcost) { - int bad = FALSE, c; - for (c = 0; c < dr->used && !bad; c++) { - bad = gc_touch(&dr->rects[c], &larger) && c != cursor; - } - if (!bad) { - cheapestmerge1 = merge1; - cheapestmerge2 = merge2; - lowestcost = cost; - } - } - } - } - } - if (cheapestmerge1 >= 0) { - gc_combine(&dr->rects[cheapestmerge1], &dr->rects[cheapestmerge2]); - dr->rects[cheapestmerge2] = dr->rects[dr->used - 1]; - dr->rects[dr->used - 1] = *area; - } else { - gc_combine(&dr->rects[cheapest], area); - } - // NB: clusters do not intersect (or intersection will - // overwrite). This is a result of the above algorithm, - // given the assumption that (x,y) are ordered topleft - // to bottomright. - return (TRUE); -} -int -get_dirty_rect(dirty_rect *dr, GRECT *area) -{ - if (dr == NULL || area == NULL || dr->rects == NULL || dr->used <= 0 - || dr->max <= 0) - return (FALSE); - *area = dr->rects[--dr->used]; - return (TRUE); -} -int -clear_dirty_rect(dirty_rect *dr) -{ - if (dr) - dr->used = 0; - return (TRUE); -} -int -resize_dirty_rect(dirty_rect *dr, int new_size) -{ - return (FALSE); -} -static int -gc_inside(GRECT *frame, GRECT *test) -{ - if (frame && test && frame->g_x <= test->g_x && frame->g_y <= test->g_y - && frame->g_x + frame->g_w >= test->g_x + test->g_w - && frame->g_y + frame->g_h >= test->g_y + test->g_h) - return (TRUE); - return (FALSE); -} -static int -gc_touch(GRECT *frame, GRECT *test) -{ - GRECT tmp = { test->g_x - 1, test->g_y - 1, test->g_w + 2, - test->g_h + 2 }; - return (rc_intersect(frame, &tmp)); -} -static void -gc_combine(GRECT *frame, GRECT *test) -{ - if (!frame || !test) - return; - if (frame->g_x > test->g_x) { - frame->g_w += frame->g_x - test->g_x; - frame->g_x = test->g_x; - } - if (frame->g_y > test->g_y) { - frame->g_h += frame->g_y - test->g_y; - frame->g_y = test->g_y; - } - if (frame->g_x + frame->g_w < test->g_x + test->g_w) - frame->g_w = test->g_x + test->g_w - frame->g_x; - if (frame->g_y + frame->g_h < test->g_y + test->g_h) - frame->g_h = test->g_y + test->g_h - frame->g_y; -} -static long -gc_area(GRECT *area) -{ - return ((long) area->g_h * (long) area->g_w); -} diff --git a/win/gem/gr_rect.h b/win/gem/gr_rect.h deleted file mode 100644 index 3d81f25e0..000000000 --- a/win/gem/gr_rect.h +++ /dev/null @@ -1,17 +0,0 @@ -/* gr_rect.h */ -/* - * $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.4 $ - */ -#include -/********** structs **********/ -typedef struct { - GRECT *rects; - int max, used; -} dirty_rect; -/********* functions ************/ -dirty_rect *new_dirty_rect(int size); -void delete_dirty_rect(dirty_rect *this); -int add_dirty_rect(dirty_rect *dr, GRECT *area); -int get_dirty_rect(dirty_rect *dr, GRECT *area); -int clear_dirty_rect(dirty_rect *dr); -int resize_dirty_rect(dirty_rect *dr, int new_size); diff --git a/win/gem/load_img.c b/win/gem/load_img.c deleted file mode 100644 index cfa2195e9..000000000 --- a/win/gem/load_img.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $ - */ -#define __TCC_COMPAT__ -#include -#include -#include -#include -#include -#include -#include -#include -#include "load_img.h" - -#ifndef FALSE -#define FALSE 0 -#define TRUE !FALSE -#endif - -/* VDI <-> Device palette order conversion matrixes: */ -/* Four-plane vdi-device */ -int vdi2dev4[] = { 0, 15, 1, 2, 4, 6, 3, 5, 7, 8, 9, 10, 12, 14, 11, 13 }; -/* Two-plane vdi-device */ -int vdi2dev2[] = { 0, 3, 1, 2 }; - -void -get_colors(int handle, short *palette, int col) -{ - int i, idx; - - /* get current color palette */ - for (i = 0; i < col; i++) { - /* device->vdi->device palette order */ - switch (planes) { - case 1: - idx = i; - break; - case 2: - idx = vdi2dev2[i]; - break; - case 4: - idx = vdi2dev4[i]; - break; - default: - if (i < 16) - idx = vdi2dev4[i]; - else - idx = i == 255 ? 1 : i; - } - vq_color(handle, i, 0, (int *) palette + idx * 3); - } -} - -void -img_set_colors(int handle, short *palette, int col) -{ - int i, idx, end; - - /* set color palette */ - end = min(1 << col, 1 << planes); - for (i = 0; i < end; i++) { - switch (planes) { /* MAR -- war col 10.01.2001 */ - case 1: - idx = i; - break; - case 2: - idx = vdi2dev2[i]; - break; - case 4: - idx = vdi2dev4[i]; - break; - default: - if (i < 16) - idx = vdi2dev4[i]; - else - idx = i == 255 ? 1 : i; - } - vs_color(handle, i, (int *) palette + idx * 3); - } -} - -int -convert(MFDB *image, long size) -{ - int plane, mplanes; - char *line_addr, *buf_addr, *new_addr, *new1_addr, *image_addr, - *screen_addr; - MFDB dev_form, tmp; - long new_size; - - /* convert size from words to bytes */ - size <<= 1; - - /* memory for the device raster */ - new_size = size * (long) planes; - if ((new_addr = (char *) calloc(1, new_size)) == NULL) - return (FALSE); - - /* initialize MFDBs */ - tmp = *image; - tmp.fd_nplanes = planes; - tmp.fd_addr = new_addr; - tmp.fd_stand = 1; /* standard format */ - dev_form = tmp; - screen_addr = new_addr; - dev_form.fd_stand = 0; /* device format */ - image_addr = (char *) image->fd_addr; - - /* initialize some variables and zero temp. line buffer */ - mplanes = min(image->fd_nplanes, planes); - /* convert image */ - line_addr = image_addr; - buf_addr = screen_addr; - if (mplanes > 1) { - /* cut/pad color planes into temp buf */ - for (plane = 0; plane < mplanes; plane++) { - memcpy(buf_addr, line_addr, size); - line_addr += size; - buf_addr += size; - } - } else { - /* fill temp line bitplanes with a b&w line */ - for (plane = 0; plane < planes; plane++) { - memcpy(buf_addr, line_addr, size); - buf_addr += size; - } - } - free(image->fd_addr); - /* convert image line in temp into current device raster format */ - if ((new1_addr = (char *) calloc(1, new_size)) == NULL) - return (FALSE); - dev_form.fd_addr = new1_addr; - vr_trnfm(x_handle, &tmp, &dev_form); - free(new_addr); - - /* change image description */ - image->fd_stand = 0; /* device format */ - image->fd_addr = new1_addr; - image->fd_nplanes = planes; - return (TRUE); -} - -int -transform_img(MFDB *image) -{ /* return FALSE if transform_img fails */ - int success; - long size; - - if (!image->fd_addr) - return (FALSE); - - size = (long) ((long) image->fd_wdwidth * (long) image->fd_h); - success = convert( - image, size); /* Use vr_trfm(), which needs quite a lot memory. */ - if (success) - return (TRUE); - /* else show_error(ERR_ALLOC); */ - return (FALSE); -} - -/* Loads & depacks IMG (0 if succeded, else error). */ -/* Bitplanes are one after another in address IMG_HEADER.addr. */ -int -depack_img(char *name, IMG_header *pic) -{ - int b, line, plane, width, word_aligned, opcode, patt_len, pal_size, - byte_repeat, patt_repeat, scan_repeat, error = FALSE; - char *pattern, *to, *endline, *puffer, sol_pat; - long size; - FILE *fp; - - if ((fp = fopen(name, "rb")) == NULL) - return (ERR_FILE); - - setvbuf(fp, NULL, _IOLBF, BUFSIZ); - - /* read header info (bw & ximg) into image structure */ - fread((char *) &(pic->version), 2, 8 + 3, fp); - - /* only 2-256 color imgs */ - if (pic->planes < 1 || pic->planes > 8) { - error = ERR_COLOR; - goto end_depack; - } - - /* if XIMG, read info */ - if (pic->magic == XIMG && pic->paltype == 0) { - pal_size = (1 << pic->planes) * 3 * 2; - if ((pic->palette = (short *) calloc(1, pal_size))) { - fread((char *) pic->palette, 1, pal_size, fp); - } - } else { - pic->palette = NULL; - } - - /* width in bytes word aliged */ - word_aligned = (pic->img_w + 15) >> 4; - word_aligned <<= 1; - - /* width byte aligned */ - width = (pic->img_w + 7) >> 3; - - /* allocate memory for the picture */ - free(pic->addr); - size = (long) ((long) word_aligned * (long) pic->img_h - * (long) pic->planes); /*MAR*/ - - /* check for header validity & malloc long... */ - if (pic->length > 7 && pic->planes < 33 && pic->img_w > 0 - && pic->img_h > 0) { - if (!(pic->addr = (char *) calloc(1, size))) { - error = ERR_ALLOC; - goto end_depack; - } - } else { - error = ERR_HEADER; - goto end_depack; - } - - patt_len = pic->pat_len; - - /* jump over the header and possible (XIMG) info */ - fseek(fp, (long) pic->length * 2L, SEEK_SET); - - for (line = 0, to = pic->addr; line < pic->img_h; - line += scan_repeat) { /* depack whole img */ - for (plane = 0, scan_repeat = 1; plane < pic->planes; - plane++) { /* depack one scan line */ - puffer = to = - pic->addr - + (long) (line + plane * pic->img_h) * (long) word_aligned; - endline = puffer + width; - do { /* depack one line in one bitplane */ - switch ((opcode = fgetc(fp))) { - case 0: /* pattern or scan repeat */ - if ((patt_repeat = fgetc(fp))) { /* repeat a pattern */ - fread(to, patt_len, 1, fp); - pattern = to; - to += patt_len; - while (--patt_repeat) { /* copy pattern */ - memcpy(to, pattern, patt_len); - to += patt_len; - } - } else { /* repeat a line */ - if (fgetc(fp) == 0xFF) - scan_repeat = fgetc(fp); - else { - error = ERR_DEPACK; - goto end_depack; - } - } - break; - case 0x80: /* Literal */ - byte_repeat = fgetc(fp); - fread(to, byte_repeat, 1, fp); - to += byte_repeat; - break; - default: /* Solid run */ - byte_repeat = opcode & 0x7F; - sol_pat = opcode & 0x80 ? 0xFF : 0x00; - while (byte_repeat--) - *to++ = sol_pat; - } - } while (to < endline); - - if (to == endline) { - /* ensure that lines aren't repeated past the end of the img - */ - if (line + scan_repeat > pic->img_h) - scan_repeat = pic->img_h - line; - /* copy line to image buffer */ - if (scan_repeat > 1) { - /* calculate address of a current line in a current - * bitplane */ - /* to=pic->addr+(long)(line+1+plane*pic->img_h)*(long)word_aligned;*/ - for (b = scan_repeat - 1; b; --b) { - memcpy(to, puffer, width); - to += word_aligned; - } - } - } else { - error = ERR_DEPACK; - goto end_depack; - } - } - } - -end_depack: - fclose(fp); - return (error); -} - -int -half_img(MFDB *s, MFDB *d) -{ - int pxy[8], i, j; - MFDB tmp; - - mfdb(&tmp, NULL, s->fd_w / 2, s->fd_h, s->fd_stand, s->fd_nplanes); - tmp.fd_w = s->fd_w / 2; - tmp.fd_addr = calloc(1, mfdb_size(&tmp)); - if (!tmp.fd_addr) - return (FALSE); - - pxy[1] = pxy[5] = 0; - pxy[3] = pxy[7] = s->fd_h - 1; - for (i = 0; i < s->fd_w / 2; i++) { - pxy[0] = pxy[2] = 2 * i; - pxy[4] = pxy[6] = i; - vro_cpyfm(x_handle, S_ONLY, pxy, s, &tmp); - } - pxy[0] = pxy[4] = 0; - pxy[2] = pxy[6] = s->fd_w / 2 - 1; - for (j = 0; j < s->fd_h / 2; j++) { - pxy[1] = pxy[3] = 2 * j; - pxy[5] = pxy[7] = j; - vro_cpyfm(x_handle, S_ONLY, pxy, &tmp, d); - } - free(tmp.fd_addr); - return (TRUE); -} diff --git a/win/gem/tile2img.c b/win/gem/tile2img.c deleted file mode 100644 index 765b4a7c1..000000000 --- a/win/gem/tile2img.c +++ /dev/null @@ -1,159 +0,0 @@ -/* NetHack 3.6 tile2img.c $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */ -/* Copyright (c) NetHack PC Development Team 1995 */ -/* NetHack may be freely redistributed. See license for details. */ - -/* - * Edit History: - * - * Initial Creation M.Allison 94/01/11 - * Marvin was here Marvin 97/01/11 - * - */ - -/* #include */ -#include "hack.h" -#include "tile.h" -#include "bitmfile.h" - -/* #define COLORS_IN_USE MAXCOLORMAPSIZE /* 256 colors */ -#define COLORS_IN_USE 16 /* 16 colors */ - -extern char *FDECL(tilename, (int, int)); -static void FDECL(build_ximgtile, (pixel(*) [TILE_X])); -void get_color(unsigned int colind, struct RGB *rgb); -void get_pixel(int x, int y, unsigned int *colind); - -#if COLORS_IN_USE == 16 -#define MAX_X 320 /* 2 per byte, 4 bits per pixel */ -#else -#define MAX_X 640 -#endif -#define MAX_Y 1200 - -FILE *tibfile2; - -pixel tilepixels[TILE_Y][TILE_X]; - -char *tilefiles[] = { "..\\win\\share\\monsters.txt", - "..\\win\\share\\objects.txt", - "..\\win\\share\\other.txt" }; - -unsigned int **Bild_daten; -int num_colors = 0; -int tilecount; -int max_tiles_in_row = 40; -int tiles_in_row; -int filenum; -int initflag; -int yoffset, xoffset; -char bmpname[128]; -FILE *fp; - -int -main(argc, argv) -int argc; -char *argv[]; -{ - int i; - - if (argc != 2) { - Fprintf(stderr, "usage: tile2img outfile.img\n"); - exit(EXIT_FAILURE); - } else - strcpy(bmpname, argv[1]); - -#ifdef OBSOLETE - bmpfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE); - if (bmpfile2 == (FILE *) 0) { - Fprintf(stderr, "Unable to open output file %s\n", - NETHACK_PACKED_TILEFILE); - exit(EXIT_FAILURE); - } -#endif - - tilecount = 0; - xoffset = yoffset = 0; - initflag = 0; - filenum = 0; - fp = fopen(bmpname, "wb"); - if (!fp) { - printf("Error creating tile file %s, aborting.\n", bmpname); - exit(1); - } - fclose(fp); - - Bild_daten = (unsigned int **) malloc(MAX_Y * sizeof(unsigned int *)); - for (i = 0; i < MAX_Y; i++) - Bild_daten[i] = (unsigned int *) malloc(MAX_X * sizeof(unsigned int)); - - while (filenum < 3) { - if (!fopen_text_file(tilefiles[filenum], RDTMODE)) { - Fprintf(stderr, "usage: tile2img (from the util directory)\n"); - exit(EXIT_FAILURE); - } - num_colors = colorsinmap; - if (num_colors > 62) { - Fprintf(stderr, "too many colors (%d)\n", num_colors); - exit(EXIT_FAILURE); - } - while (read_text_tile(tilepixels)) { - build_ximgtile(tilepixels); - tilecount++; - xoffset += TILE_X; - if (xoffset >= MAX_X) { - yoffset += TILE_Y; - xoffset = 0; - } - } - (void) fclose_text_file(); - ++filenum; - } - Fprintf(stderr, "Total of %d tiles in memory.\n", tilecount); - - bitmap_to_file(XIMG, MAX_X, (tilecount / 20 + 1) * 16, 372, 372, 4, 16, - bmpname, get_color, get_pixel); - - Fprintf(stderr, "Total of %d tiles written to %s.\n", tilecount, bmpname); - - exit(EXIT_SUCCESS); - /*NOTREACHED*/ - return 0; -} - -void -get_color(unsigned int colind, struct RGB *rgb) -{ - rgb->r = (1000L * (long) ColorMap[CM_RED][colind]) / 0xFF; - rgb->g = (1000L * (long) ColorMap[CM_GREEN][colind]) / 0xFF; - rgb->b = (1000L * (long) ColorMap[CM_BLUE][colind]) / 0xFF; -} - -void -get_pixel(int x, int y, unsigned int *colind) -{ - *colind = Bild_daten[y][x]; -} - -static void -build_ximgtile(pixels) -pixel (*pixels)[TILE_X]; -{ - int cur_x, cur_y, cur_color; - int x, y; - - for (cur_y = 0; cur_y < TILE_Y; cur_y++) { - for (cur_x = 0; cur_x < TILE_X; cur_x++) { - for (cur_color = 0; cur_color < num_colors; cur_color++) { - if (ColorMap[CM_RED][cur_color] == pixels[cur_y][cur_x].r - && ColorMap[CM_GREEN][cur_color] == pixels[cur_y][cur_x].g - && ColorMap[CM_BLUE][cur_color] == pixels[cur_y][cur_x].b) - break; - } - if (cur_color >= num_colors) - Fprintf(stderr, "color not in colormap!\n"); - y = cur_y + yoffset; - x = cur_x + xoffset; - Bild_daten[y][x] = cur_color; - } - } -} diff --git a/win/gem/title.uu b/win/gem/title.uu deleted file mode 100644 index 9fda441bd..000000000 --- a/win/gem/title.uu +++ /dev/null @@ -1,426 +0,0 @@ -begin 777 title.img -M $ .P $ $!= %T 4 R%A)34< /H ^@#Z /H &K ^@ /H ^@ -M #Z /H #Z LH#Z &K CT"R@$: :L!JP+* 1H CT /H -M :L (] 1H -; UL"R@/H LH"/0 _PDH*"BH!H ) ?_@'_^_ -M___'A( /_#_\!__X _P#__P?__P!B@HAH )_@ ?X ! X!( / \ #^ ' -M__ /\ /@ /A@>!@ ?@#_^____'@X 0W_@?^ /_\ __ ?_X!__P 8H!X ( -M?\ '_Q___X.#@ ^/\ _P ?_@ ?P ?_ #_\'AX (?]_W_U___[N#@!"O]^_W -M_?_O_\?S^?_?[_\_A@> "& P!@,8 #& X !V( .&!@8 8 P '@.$8# # ,' -M* > "#_@ _X/__^#@X /C_ /\ #_X ?_ #_@ ?^!X> "* O^@+H "Z X / -MJ!?H%_Z +_^8#>Z O_0"AP> "& P P8, #& X /S# ,, & 8 #@ Q&!P P& -M!R@'@ @_X '\!___@X. #X?@!^ _\ ?_X _X '_ >'@ B@+_T%] N@. -M#[0O]"_^@%__8 +N@;_T!8<'@ @P, &&# Q@. #\PP## !@& !P &Q@X , -M# "- O_H7T "Z X /M"_T+_Z 7_Z (Z" -M_^@7AP6 "O@ ,!X!A_P /X#@!#\/XP_@8!_ P \8/^&#_\!@B !P8 ? -M #@#@ !N@O_07X<%@!U\ # ? 8?L/_S^ -M?P'X_#\,/P, /@<'_#&#_&!_X 8%@ H0 ' '@ X X ', \ #P #@6 -M!/P '^ &!8 *' ?]P#]Y___NX. $+?O!^\!_^X!_A_@_OP_W^ &A8 <[__0 -M%_Z%]#_\NG\!^+0O]"_] "_Y!APN@O^@7X<%@!T\ # / 8?L?__^_X/__#\, -M/P, /@8/_CN#^&#_P 8%@ H0 # '@ X X 0, \ #P #@ !X H ^ _ -MP 8%@!T< !_[ /WGP .[@/X'M^\'[P'_[@/YX^K^^#^_P :%@!SO_] +_H7T -M0 .Z@(('M"_T+_T +_H)XBZ"_Z"_AP6 "#P , \!A^Q_@X 2@__\/PP_ P ^ -M!A__/X/PP/^ !@6 '1@ , > ?_#A^ /@P#P / . ?X#@#P #^ !@6 -M'1P '_L _>??_+M^_OBW[P?O ?_N _?Y[O[P?[^ !H6 '.?_T O^A?1?_+M^ -M@OBT+_0O_0 O^A?Y+H+_0+^'!8 ??_SI^_O\W[P?O ?_N ^_^[O[P_W\'A8 ?_[A^ /^P#P / ' !__#@#P /X'!8 <'X ?^X#]Y]__N'[^ -M_[?O!^\!^_<'W_]N_O#^_@>%@!OG_] +_H7T7_^Y_H+_M"_T+_T*%_1?_VZ" -M_H*(!8 ??__A^_O_W[P?O _OW -M!]__KO[Q_OX'A8 ;Y__0!?Z%]%__^?Z"__0O]"_Z"A?T7_^N@OT"B 6 '#_ -M, ?!A^Q___Q_@__\/PP_!@X?#/_A_X/V!_P'!8 <&\ < !X!__^'X __ / -M \ < /^'. / !_ <%@!P?P!_]P/WGW__X?O[_]^\'[P/[]P>_X<[^\_W\ -M!X6 &^?_T 7^A?1?__O^@O_T+_0O^@H7]+__SH+Z!8@%@!P_P# 'P8?L?@ \ -M>8/P?#\,/P8>'QS_@'^#_ _\!P6 '!O ' > > #QX /!P#P / ' #^ -M;@#P _P'!8 <'\ ?_<#]Y]X /'C^\'?O!^\#\_<'OX!N_O?[_ >%@!OG_] % -M_H7T7____H+_]"_T+_H2%^2__^Z"] N(!8 ?> QP_O '[P?O _7W#W\ 'O[W^_@'A8 ;Y__0 OZ%]%____Z" -M__0O]"_Z%1?I?__^@O0+B 6 '#_ , /!A^Q^ 1AH_ ,/_P_!A\?F?X #X/X -M'_ '!8 -&\ , !X!X !& \ . # \ ! > ?@ . . '\ <%@!P?P!_^P/WG -MW@ $8-[P!^ '[P/U]X]^ [^[_?P!X6 &^?_T +^A?1?___^@O_T( 0O^A47 -MZ7___H+H%X@%@!P_P# #X8?L?@ 88/P#!_X/PP?#YG^ >#\#_P!P6 #1O -M #@ > > !@ / #@ P/ 0#@'X !@# #_ '!8 <'\ ?_N#]Y]X &#^\ ?_ -M_^\']?N/?@ &_M_O\ >%@!OG_] "_H7T7____H+_]!_X+_05"^E___Z"T"^( -M!8 ?> ! GO '___O!_7[CWP -M O[?[^ 'A8 ;Y__0 OZ%]%____Z"__0 "_T%0OI?__^@M OB 6 '#_ , 'A -MA^Q^ !Z_ , _##\/F?P 8/@?\ '!8 (&\ & !X!X$@ 'P X &#P , -M X!\!( "'\ '!8 ('\ ?_V#]Y]X#@!&6\ ?__^\'[?N/? _C_?P >%@!OG -M_] !?H7T7____H+_] +_0M"^E___Z"(%^(!8 >!( !\ . !@\ #@. > 2 C^ !P6 "!_ 'O]P_>?> -M X 1_O '___O!^[[GW@ /__OX 'A8 ;Y__2@7Z%]%____Z"__0 "_T+HO1 -M?__^@ "_B 6 &W_ ,X#QA^Q^! !F_ , !_##^'\?@ 8 !_P@%@ @[P -M, '@'@2 ? #@ 8/ X!P'@$@ %_" 6 "#_ 'O^P_>?> X 0YO '__^O!^[] -MWW@ /__?PB%@!O'_]* OH7T7_O__H+_] +_0NA=%___Z 7^(@ $.!(& -M&L S@/&'['X, '#\ P #\8/X?S^ !@ '_"( !#@2 "#O P > >!( ! -M\ . !@\ #@' ^ 2 7\(!8 (/\ >_[#]Y]X#@!"^\ ?__^\/[OW>^ __]_ -M"(6 &\?_TH"^A?1?\__^@O_T OZ"Z%TO___H !?XB (!^ !_\ SP/F' -M['X\ &+\ P?^'\8?X?S^ !@ /^"( "'X #@ A[P . '@'@2 ? #@ 8/ -M !X!P/@$@ '^" 6 &W_ 'G^X_>?>" ]O '__^O#][]WO@ /_^_@B%@!J' -M_]) OH7T7\O__H+_]!_X+^A>A=+___Z HF 3.$@!O\ #/ P88,8?P << -M#+_\,!AAAC, & 8 #@ )Y7@. 3^$@ 'X'8 "!_X#@ $,!( 5_ >?X#\ -M!\ X "Z =@!^ /P/P> X($@ )__@.%@!4$ !) @(0$0#@ (( !" $( A -MA!(#@ * 02 G@!@X @;X . #-@888,?\P ;\ ## ,,!AAAC, &! -M@8 %@ -UP " 7^$@ & 'X ##\ @!H0?____? 'C_ _ ? ^ P@ 'X ?@ -M#\#\'@."!H #?\ A( 6_G $B! A 1 R @@ $( 0@"$"$$@. H&!!H # -M<#__@ %?A * &3-@888,/PP 8, #K ,82 -M 7 @@ (# ( !( . %@.( !X_P/P'__@ /X !6 'H _ ?AX#@ /^?X &@ (/ -M (2 %OSX !(@0(0$/P@ (( !" $( A 0A(#@ ."0( &@ (,_X2 '/X #,P -M888, P ?, #+ -L!A@PS, &#X, '@ ' @ '@@ 55555^^"& 4 $@!8' -M! >'\#\!__X ". =@!F /P'X> X #_C^ !X !P(2 %OF, !(00(0$ @ -M (( !" $( A 0A(#@ ."(( '@ &_A( <_ ,S QA@P C !XP ,, SP-,## -M,P 8-@P > 3" < #@ (=O"& 1 $@!8& @ >'^#\!_]X "> ?@!R ; -M@'X> X #_C^ !X !,(2 %OL& !(0((0$ @ (( !" $(!" 0A(#@ ."(( ' -M@ $OA( 6_ '_\_@_A_P)#___T__\/_T_\O_#\X. X/P?X> ?" < #@ (- -M_"($@!P& __>[^[]]_;[__ZN__?O]N_=OW[>___^_M_?AX !\(2 '/L'_]+H -M+H7T O__H+_]"_T+]"_0M+___Z"T%^(A( 6Z '_\_@_A_P'[___@__\?_R_ -M^?_#\X. X/P?X> >" 8 #@!P)_?_ X X!\ #__X __ /\ _ /P# ___^ -M , ?AX !X 2 '!(#_][O[OWW__O__O[_]Z_W;]:_?M[___[^W]^'@ '@A8 5 -M!@ 2"""$! ?H "" 0@!" 0@$(2 X #@A! !X !'X& #*JJJH !__/X/Z?\ -M/X. "L?__'_\__?_P_.#@ .#\'^'@ $P@ & !( ;^?_ X X!\ #__X __ / -M\ _ /P# ___^ , ?AX !, & 'U5557D%_][O[MWW^!O__KK_]Z_W+]B_?M[_ -M__[^W]^'@ $PA8 5C@ 2"""$!#@8 "" 0@!" 0@$(2 X #@A! !X& 5\$ -M@ <#__/\/[?\A( *@__]/_X_\/_!\X. X/X/X: L7\!8 ;<__ \ 8!\ ?C -M__X __ /\ _ !P! ___^ . /AH "Q?R 2"#@!S\B__>]];-]T?C__[^__;O -M]>_?AW]>___^_N_OAH "Q?R%@ C\ !($$(0$0 . "H( !" $(!" 01(#@ ." -M"" &@ (__X !! 2 " ?_]_R?C_Q_@X *@__]O_T_X7_A\X. \/X/X2 !/P) -M__X%@!L'_\#P!@'P'_O__@#_\ _P#X $#___X X ^$@ 3\"?_^@ %[@X < -M_G?_VO=V]???^__^_O_V;_;OOOA?7O___K[O[X2 !/P)__Z%@ CX !($$(0$ -M0 . "H( !" $("!X01(#@ .""" $@ $#@P6 "(__^_X_E_Q_@X *S___/_^_ -MZQ_I]X. YOX/X. H"?@P6 &XO_P/@& ? ?___^ /_P#_ /@ 0/___@#@ -M#X. H"?@X !/X2 &X__UOO6[???___^LO_T[_1OM.>76O___N;O[X. H"? -M@X6 "'0 $@(0A 1 X *@@ $( 0@( >!$@. X((( . 7^$ 8 !?X6 !?/_ -M#^?]A( *Q__\/_T_?VS1\X. \/\'X> ?X!@!5____^>__ ^ (!\!____X -M__ /\ \#@ = ___^ / 'AX !_H !'X. '/Y__][Z^IWV7____KK_]^_V[R"3 -M+U[___Z^]_>'@ '^A8 ;A__2^@J%]%____Z"__0O]"^@ %2___^@O07B( ! -M 8: !O/_G__\?X. "OO__+__?W:.>_.#@ .C_!^'@ 'X@ $!A( 1.__ _ (! -M\!____X __ /\ \#@ = ___^ / 'AX !^( !#X2 &S__WOUJA???___^AO_W -M;_2O*7&%7O___M[W]X> ?B%@!O'_]+]"H7T7____H+_]"_T+Z 5+___Z" -M]!>(@ $'AH %\_\OK_R'@ 5__/]]](6 X/^'X> :" 0>$@!&[_\#\ @'P -M'____@#_\ _P#P2"@ 3^ /@'AX !H( !!X2 &[__WOW:U?=?___^@O_TK_ :"%@!O'_]+]"H7T7____H+_]"_T+Z( )+___Z"^A>( -M@ $'B( #G\_]A( *B___/_]_>?WW]X. ^?^#X: F@ @ $'A( 1F__ _@(! -M\!____X __ /\ \$@H $_@#X X: F@ @ $'A( ;G__2_NJU]E____[V__3O -M]*\G_@B:___^FOO[AH ": "%@!OG_]+^BH7T7____H+_]"_TKZ/\ )K___Z" -M^@N(@ $#AH &]_^7__Q_@X %V___?_Z#@ +L]X2 OX/A( $[4 ( ! X2 -M$=O_P/X! ? ?___^ /_P#_ /!( &?__^ /@#A( $[4 ( ! X2 &]__VO[M -MA???___^IO_TK_4O0@/SF7___H+[^X2 !.U "%@!OG_]+^A87T7____H;_ -M]"_U+T(#X)E___Z"^@N(@ (!^ . '#_ ,_'GU^_^ !O_ -?PW_[__^_? -M ?_S3X '@ (!^ . "!O / > >!( *\ / \ _ @< . _ #@ > @'X -M X ('\ >\)LMY%X#@!'"\ :O!B]2_!&K< @O&[@ >%@!OG_]+^@P7T7___ -M_L+_]"_T+T+\$*E___Z"_0N( 8 !X . '#_ /_#5G^]^ !@_ ,/P[_U__Z -M__ ??S3X ' 8 !X . "!O / > >!( *\ / \ _\ @< . _ !@ %@!OG_]+_0 7T -M7____M[_]*_T+V+_T*E___Z"_06(!8 %@!OG_]+_0 7T7__]_NK_]"_T -M;T+_TDE___Z"_06(!8 %@!OG_]+_H 7T7__]_IK_]&_U;T+_T4M___Z" -M_H6(!8 @O""P >%@!OG_]+_H 7U7__Y_J;_]._U+M7_ZDE___Z"_H*(!8 % -M@!OG_]+_T 7W7__Y_H[_]B_V+L7_[%:___Z2_H*(!8 %@!SG_]+_T 7T -M7__U_O;_]:_U;HW_[-2___:2_T%_AP6 '#_ -_ V[^[^ XAB_ /OPS_K_ 8 -M?O@ ">_P]> '!8 6&\ \ !X!X " \ / X!\ 0. . _ 8 <%@!P? -MP!KP&17E7@ $(/;P!&\'+M7P#]6X "2\$M@!X6 '.?_TO_0%?1?__7^]O_T -M;_4NU?_N5;__]H+_07^'!8 9S_#[ -MX <%@!8;P #P '@'@ ( #P \ #@'P 8 X #\ !@!P6 '!_ $O +5>1> -M P@MO 'KP?N[? *IM@ ++P16 'A8 O]^[E_^JF -MW__FDO]!?X<%@!P_P#?P'=?O_@ V89/P##\,/R_@&O_X !G'\'7P!P6 %AO -M / > > !@ / #P , ^ "!@#@ /P # '!8 <'\ :\ HMY%X '&#N\ ?O -M!^W;X TJ6 NO JL >%@!SG_]+_Z@WT7__=_N[_]^_W[=O_[2I?_^::_ZB_ -MAP6 '#_ /_ /M^U^ .9AP_ ,/PP^#^ ,?WP .?_P?_ '!8 6&\ \ !X!X -M & \ / @#X (' . _ , <%@!P?P!+P!$WFW@ \8+[P!^\'Z_O@!ZK< -M !""\""P!X6 '.?_TO_T3?;?_SW^OO_W[_?K^__WJM__UH+_H+^'!8 => /S@_W /]P_W^^ 'Z^P ,.+P(+@' -MA8 <[__6__5=]U_\_?[_?^_W[_?[__ > #@ ' P > # 0# -M@ /P !@'!8 <'\ 2\ *EY]X#_.#_< _[#__]X ?M] !@WO 96 >%@!SO_]+_ -M^J7WWP/]_O]_[_OO__W_]^WW_V[>_]!?AP6 '/O /_ &!^S__ ?C ? __S__ -M_^ , ! !X $!( #\ 8!P6 -M'+O $O #_>=0__WA_[ < 0 /> 'U?@ X/[P$=@'A8 '@ X$!@0& \ !@2 _ ' <%@!S[P!KP ?WG -MS__]X?X /\ _P# #_;^ <#N\!3 #-K__?WWS__]_?X/@X. "\#_[_;^ -M =[N_]1?AP6 ' / ,_ #!^PP ?G__ _P#_?\ __\'^8Z/P'_P'!8 < \ -M\ !X > !\ #_ /]_P ' " / # <%@!P#P![P ?WG___]X@'P /\ -M_W_ ?=__\+>\ @L!X> "MK__?WW___]^@&'@ G!]W__WM[_Z"^'!8 < \ _ -M\ ,'[ #__\?^ '_@?__P '_< #'@_ ;/ <%@!P#P #P '@ !X!_X ?^! -M___ , 8 \ ,!P6 ' / $O !_>?___G@'_@!_X'__\ &S__AO[P#.P' -MAX )TO_]_??___G@B( )_AN__[[^_^QOAP6 ' ? ,_ !A^P ?__@'_@!_\'_ -M_^ _SX#CX/P#_X'!8 "-[__OWW__P'BH ( -MX<__?O[_]"^'!8 <#X _\ &'[ ___^ __ /_X___X '_O_\?@_ .W@<%@!P/ -M@ #P '@ /_X#_\ __C___@ ?^P !X \ &!P6 ' ^ $O _>?_@__@/_P# -M_^/__^ !_['\'O[P!38'AX 'TO_^_??_@XR !_'\_O[_]#>'!8 &#X S\ #' -MA( 2X#__!\ /P ?^?__\#\ Q^!P6 ' ^ / > ?__@/_\'P _ ! -M_YX#^ #P 8'!8 <#X >\ !][_!__^ __P? #\ '_G@/Y_O 'E@>'@ ?6 -M__]][_!_C( '_@/Y_O_WEX<'@ 0W\ #'A( #X'_@!H ) _^/__\!\ 9?!PB -M"O > /___@?^ &@ D#_X__\ !P <'!X +&O ?>P/___@?^ &@ D#_X__ -M]_]P [<'AX &VO__?>P/CX %]_]_^[>'!X %,_ 9_R#@ +A\ B "!_'___! -M\ :O!PB !/ <"#@ +A\ B "!_'_^ < #!P> !1[P #W @X "X? (@ @? -MQ__@_W #6P>'@ 7>__^]PY" !>#_?_M;AP> !3/P '_@@X !@ F " 'C__CY -M\ 8/!PB !/ <"#@ & "8 ( >/_^ P ,'!X %'O .<"#@ & "8 ( >/_ -M^ >P _L'AX %WO__N=^1@ 0'O_O[AP> "#/P #_@___ #(& !O ?\ 8O@ 8( -M@ ?P ?@___ #(& !O 0$ #@ 8'@ @>\ 'X/__P R!@ ;P$% #VX &AX $ -MWO__QY* !/!?^]N'!X '8? #^'_^ V !Q_ ?_ &!X &"( &< /X?_X#8 ' -M'\!_@ !@ 8'@ <_< /X?_X#8 ''\!_@ /]@ :'@ *_?Y6 X_[_8<'@ 9@ -M\ /X?\0@8 $^ P'@ 8(@ 40 _A_Q"!@ 3X & !@> !C^0 _A_Q"!@ 3X -M!_V !H> K^?EH "]_V'!X &8'@ !^/ #X & ?_X?P? !@J P?CP ^ !@'_ -M^ !P 8'@ 8_X 'X\ /@ 8!__@/_< &AX "O^>6@ */_8<'@ 7!_ 'XA& -M!0_\#\/ !@J @?B$8 %#_P , &!X %?^ !^(1@ 4/_ #^P :'@ )_XY: -M O#^AP> !<_P . $H $_@#[P 8(@ 00 . $H $_@ P 8'@ 5^$ #@!* -M!/X /L &AX "?A^7@ $^AP: P&_^!6 ! < ?^ &!X " ?@5@ 0' $!@!@> -M O'X%8 $!P!'8 :&@ +^\9B L=_A@: P/W_A>!@ '@!@> @?^%X "^" & -M!H # P?_@!6 -M @?^!P: ! ('_X 5@ ('_@>&@ +Z/YB OX?A@: ! X/_\ 6@8 !\ 8'@ ,/ -M_\ 6@8 !P 8'@ ,/_\ 6@8 !P :&@ 'QFH !SX8'@ (/_A> @_P!@> @_^ -M%X "#_ &!X "#_X7@ (/\ :H!X "'^ 7@ (#^ 8'@ (?X!> @/X!@> A_@ -M%X " _@&J > 3\9@ %\!@> 3\9@ %\!@> 3\9@ %\!J@'@ %\&8 !'@8' -M@ %\&8 !'@8'@ %\&8 !'@:H!X !X!F 0,&!X !X!F 0,&!X !X!F 0,& -MJ"@H'8 !. JH*"@<@ (!_@JH"X "'X #@ (#P!8+@ '\!( " \ %@ '\$ N -M > $@ (#P 6 ?P$@ (#_PJ+@ +\?X. OP_E@N A^ X "#/ 6"H " _P$ -M@ (/\ 2 @'^$ J @/@!( "#_ $@ (#_P2 P/_@ F+@ +\?X. O /E@N -M A_ X "&?@6"H "!_P$@ (?^ 6 ?P0"H "!^ $@ (?^ 2 P?_@ . P?_ -M@ F+@ +\/X. N 'E@J P?^0 . A/X%@J @_@!( "'_@%@ '\!8 !_ H* -M@ $(!8 "'_@$@ ,'_X #@ ,'_X )BX "X;^#@ +@!Y8*@ ('_@2 B?\%@J -M A_@!( "/_P$@ (!_@6 ?P*"H !& 6 C_\!( #!_^ X #!_^ "8N >&$ -M@ + Y8*@ (/_ 2 B_\%@J A_P!( "/_P$@ (!_@2 @'^"@J 1 %@ (_ -M_ 2 P?_@ . P?_@ F+@ 'SA( "P .%@ $SA8 !,XH*@ (/_ 2 C_\!8 ! -M9 6 :@*"H "/_@$@ (__ 2 P??@ . @'>"@J C?@!( "/_P$@ ,'WX # -M@ ,'WX )BX !^X2 L #A8 !=X6 ;N*"H "'_P$@ (YG 6 2 %@ $@"@J -M C_X!( ".9P$@ (#WP2 @'>"@J B?P!( "/_P$@ ,#WX #@ ,'WX )BX ! -M^X2 L #E@J AZ\!( "/_P%@ $@!8 !( H*@ (^N 2 C_\!( " ]\$@ (! -MW@H*@ (O\ 2 C_\!( " ]\$@ ,'WX )BX !^X2 L9CE@J AUO 2 AB(!8 !> 6 7@*"H "/K@$@ (?^ 2 @&&!( " -M 88*"H "+_ $@ (7> 2 @&'!( #/X?@"8N ?N$@ +O]X6 8>%@ &'B@J -M A_\!( "*!06"H "/_@$@ (O] 6 ?P%@ '\"@J BO0!( "+_0%@ '^!( # -M/__P"8N ?N$@ +7ZY8*@ ([W 2 @O0!( # P. X $ 08 < @*@ (_^ 2 -M @PP!( # P. !( #? !P" J @PP!( "## %@ '\!( $/OWP< B+@ '[A( " -M_#^*@ /X_'^)"H ".]P$@ (($ 2 ! >'P#@#@ -^#_@("H "/#@$@ (/\ 2 -M! >'@#@#@ -\#_@("H "## $@ (/\ 6 "7@ . /_W_^ B*@ +\.XR ;^# -M@ /X_'^)"H "/#P$@ (,, 2 "@__X/P 0$#_X("H "/_ $@ (/\ 2 ! O_ -M@/P$@ (/_@@*@ (+T 2 @_P!X '_ ._O__@B+@ 'SBH #^_^?@X "^'B* -M"H 6/_\/_ !^ !^ '__]_@ '@#__@@*@!8_\P_\ '__X'X 8 W^ -M 8 _^" J "@PS#_P ?__@?@$@ @-_@ ?\/_@B+@ 'S@X $_@?@?X. -M _@ #X. _@!#XD*@ T__[_^ #__X?\ _@P* !#\!__\("H 6/^.__@ ' -M___G_ ,_\'_P . /_P@*@ H'X[_^ ?__^?\!( "!_\#@ /^#_\(BX ! -MXX. !/@'X!^#@ /S_P>#@ /X @^)"H !/X,!@ @"__]O_ ?X,"@ 1_P___ -M" J %C@'__\ !O__;_P &/_!_\ & !_\("X ) ___ ;__V_\!( "!_\# -M@ ,\!_\(BX !YX. !/D#P)^#@ /C_P>#@ /@ >)"H !#X. "8 #?_[__ -M^X,"A @)@!__?_\ #Z___^ #_\___" F %P/_^#__@ ^__?_\ #8_@'^ #/X /_ -M" F $0,8 #__@ ^__?_\ # '^ X #% /_"(N "/@____P0 (/@X #V_X! -M@X #S_0#B0F %P'G'__[@ ??^__\ 'Z___X '_\__^" F %P?_X!_[@ _? -M^__\ ' _$'X '/X '^" F $088X!_[@ _?^__\ # $'X X #% '^"(N -M". ?___P( 0/@X #P_Q!@X #S_0!B0F %P/P'__Q@ >O=?_X '#/^/@ ![ -M]_G\" F %P__X _Q@ ^O]?_X ' ''W@ '; .?\" F %PP/X _Q@ ^O]?_X -M # 'W@ &8]^?\"(N #N /___QT N/___YPQQ]@X #W_?GB0F %P_\/__@ -M _7<__X 8_W_'X C /'\" F %P__P _@ _7\__X ' #'_X 'C /_\ -M" J %@/ #^ #]?S__@ !__@?_@ > __P(BX (P ____'H#X^$@ +L?X0! -MB@F 0^#@!/ _7\__P "'_/\ #D//\" F %P__^@_ _7\__P #@ -M#'_\ ##@/_\" J %D "#\ #]?S__ ./@?_P ,!W__P(BX (^@____'H -M#X^#@ +[[(6 ?>*"8 7",?_'^ , ##\ +___P 'R__P("8 +#__[ -M[^ #\ #_\ #@ D(?_P '@__P("8 7!_@#[^ #\ #_\ , ?_P (5 -M__P(BX "^^^)@ /[SW^$@ 'UB@J %L__#^ "/'#^ +___@ (1__@( -M"8 +#__C_^ #R/'_^ $@ A_^ @'_^ @)@! #3@ __ -MG^/ ?O_^ #@H '^ _/_^ @'@!H@ 8_Z__CP 7[__@ #_'_X # -MX/_X' <'@!,&' 8P __@ 7[__@ # '_X X #%/_X"(N !^O__#__Z!>% -M@ +\?X2 !/3___>'!X -. '___[_ ]__X ."@ ?X #\__X" > &B -M #_C_^_P #O?_^ /\/_@ /@?_C\!P> $P<\ " #_^ #O?_^ , -M/_@#@ ,4?_@(BX 'X__QC__$(X6 OP_A( $]'__(X<'@ 0X /@X &^ , -M/__ X* !_@ 'S__@(!X :( ?^O___@ /#__P !_P_^ _!_^_P' -M!X 9!_P < /_X /#__P !P _^ @Q_^ B+@ ?K_^!'_\/#A8 "_#^$ -M@ 3\?_PGAP> &3 #__\]_X !O[^\ '__[@ '__S@(!X :( ?^/S -MW_@ ._O[P #_X?N _P_/_P'!X 9#_P 0 /SP ._O[P\ #@ ?O^ -M @ _. B+@ ?C_^!'_\6'A8 "_A^$@ 3\/_@?AP> &3 #__\]WX ?[^\ -M ?__S@( '__B (!X :( __WSW_@ )_O[P #_\/. @ !_X>/_ '!X 9 -M#_P P 'SP@ )_O[S_ " //_@ !@ >( B+@ ?]_^H7_]F'AH !#X2 !/X? -MX!^'!X 9, ?__YV)@ '[?YQ40 "__^)P0 __^( @'@!H@ '_\?G?^ _ -MM_G ! ?_PX@! /_PX__ <&@!H(#_P1@ 'YQV /[?YVKP % ../P # . -M( B+@ ?Q_^=G_\/+AH !#X6 P_@/X<&@ !_X /^_\"PN " !#'^ !@ !@F+@ +Z?X. @/ AH !AX6 X?!^X<&@!D/ -M__P#___X 0 _[_P#!$ +__\& $ #___"0: &P& ___+@?_ '_O_ 0!_ -M_\0 0!__\$__ <(@!<#_ .!F< ?^_\'/O % !&?_ ' 0F+@ C\O_N_ -M_@/ ?X6 <>%@ /!P:.'!H 9!\ !?__\ -$ ?\_\$ %___ @#___PD& -M@ T!P ?__T0'_P!_S_P X +?__H " ___PO_T'!X :/__Z 0&MP!_S_P -M/_\ ( __^ P @ $'BX (_1____X#P'^%@ 'KA8 #\, #AP> "#?\!___ -M ")$!( %0 " !_\$@ 4/_^" 0<'@ @P ?__P ?^ 2 #A_X@ ?_ !_X __ -MX/__!P> 7@%@ (]N 2 ";__@ ?__@ . L [!Y^ D ZAP> DSD!( " -M 8(&@ & !8 &0 /@ "$!P> 4 %@ (^?@2 S_\@ . "#_\0 /@'_^!P: -M P'S& 2 CY^!( )\\^ !\\_ X "7WH'AX "_.>6@ +1QX<'@ *Q* 6 -M 0($@ ,-,( #@ ,-,$ #@ (@0 <'@ *MS 2 C_^!( #/_R X #/_Q X " -M<<8'!X "[]P$@ (__@2 ">RW@ >RWP . ENN!X> OWOEH "\<>'!X " -M4" $@ (GY 2 P(@@ . T(@0 2 40'!X "3]P$@ (X' 2 S_<@ . S_< -M0 . G_^!P> N_-@ +X'YD'@ &P -M!8 ", P$@ ."@( #@ /"@$ #@ )@!@<'@ *O_ 2 B_T!( #/_R X #/_Q -M X "?_X'!H # >_\!( "+_0$@ E__X $__\ #@ )__@>?@ *__8<'@ ,1 -M! P#@ 0,, #@!( '@ L 0 . !# D X%!X ##O@, X )>]X X '_B -M X #/_Q X $/]P #@4'@ ,N^ P#@ ][W@#@ #__X $__\ #@ 0OW . -M!8> ?Z8@ '?AP> "ACP#A@ &?D _@#@ P /@4'@ H' -M" X8 &?^X/X X " 8 #@ )\/@2 !!X< #X%!X 5!P@.& !__^#^ ?_^ -M !?#_P X $'A0 /@6(@ $/D( "_#^$@ +^'X<'@!0, ]\ &#R ?X !# -MR8'\ +'X@2 !!@,!'X%!X * _ /? "?_?G^ . !P&!_ >!X$@ 0?_ 1^ -M!0> %0/P#WP ___Y_@ #PW@?P 7@?\ . !!?\!'X%DX "_#^$@ +X'XT' -M@!P&( ?^ (!D _\ "@P/\ +%8@/P ,/ S^!0> ' ' !_X !?_O[_P -M :C _P 'U^ _ _\#/X%!X < < '_@ '___O_ /K\#_ !?7_S\ -M"]P,_@63@ +^OX2 OU_C0: !0'__ __ X 5@ _\ @0 !_^ +CQ _X . -M< _\!0: !P'V( __ ^#@!/\ _!P__^ #\/$_X __ _\!0> ' 8CC_\ -M#_]___P !^__[_X #?P___@ 6@#_P%F8 "_#^$@ +'XX<&@!T#__P?_P " -M !/^ $ 0'_@ D P'_ #_ /_ 4&@ <##R ?_P /@X 3^ ?X ?__@ ( -M'_Q/_ __\/_ 4'@!P&(]__ W__[_X !_O__O^ ]____\ #'XP_\!9^ -M L?CAP: '0?__!__ $ @(?X 0# /^ "8& /\ #P!_\!0: !P8#P!__ -M !^#@!/X #_P#__^ #P?^._\ '__Y_\!0> # /#__\ 'O]_?_@ /X. #?X -M/W____P !A_@ #^ !_ 2 C_X!0: !PP __@!^#@ /P '^#@ G^ 'X/X'_\ -M .#@ 'X!0> 0>#@!B '_Z___ ?W__G_X ?_?___P \ #__@%GX "P!^' -M!H =#_P"#__@$>(G#\ !X P?P C_@0?P % */_H%!H '"$ "#__@'X. -M#\ ?7____P ?C@ ?_P X. ?H%!X !0X. &. .W=OWP !X?_\__ !]P!^_ -M_ #T O_^@6?@ +0'X<&@!T/]@,/^> 3\ ^?X #@ '!_ #_^'!_ \ \? -M_@4'@ ;P P_YX!^#@ /@ '^#@ G\ '_X ?_\ >#@ '^!0> ',G___G@#>_W -M;^ ??__O_P ?< ?O_P !_ /__X%GX "\#^'!H =#_,#C_@ ?"/W^ > # -M@?P !__CX?P / /'_X%!H ' ? #C_@ #X. #^ ?_OO__P ?_@#__P !X. -M ?X%!H = < ?G_P !_ /__X%GX "\#^'!H = -M#_&#C_@ ? /C_ &? #D_@ 0?_C@_@ _ /W_@%!H ' ? #C_@ #X. #_ -M/^____@ ?_@#__@ !X. ?@%!H ' /\ 0__D/^ !_^.#^ T \?X 4& -M@!T/L /_\ /X ?_\ ?X '_^ _^ /_^ 'W___X 4&@!T/CS__\ /_Q__ -M\ /@ ?W^ _P!__^ 'T __X 6?@ +P?X<'@!8P&(!X 6,#^/ -M\ !P..'\ __,/^ !_^./^ . P,_P 4&@!T., /_\ ?X ?_\ /\ /_ -M^ /^ /_^ #/___P 4&@!T.#\/_\ ?_Q__\ /P __^ /P!__^ # /_ -MP 6?@ '#B > !# ?__ #@ \#A^ #_CG^ #_C_^ #@ .#_< %!X <, /_ -M\ >, __X #. /_X . /_X /__]P 4'@! /X__P !X____@ , '__@ -M X #'__@ X #@_W !9^ <>(!X $, /]\ . %0./P /^/_X /^/_X -M "@___? -M#C___\ #@ ,?_^ #@ D?_^ '#^< %GX !QX@'@ 00!_G X 5!__ ? -MX__ _X__ !P_' !0> '! '^< #Y__\ #@'_\ #@#_\ #__ -M\< %!X 0#__YP /_O_P (!__P . "1__P '!_[ -M\< "&'\\ /#\< /#_< '#\\ %!X <'_OQP /__SP /__Q -MP /__]P /__SP 4'@!P/__' ?^_/ ___' ___W !P_/ -M!9^ <>(!X <$<)QP (8?SP \/QP \/YP ' __\< !_[\\ #__\< -M #__^< '#\\ %GX !QX@'@!SYP!A #P_' #P_# #P_# ! -MP_& !0> ' ' &$ #__\< #__\, #__\, #__\8 %!X &!H 6 8$ " ?\?\ _]_^ _]_ -M^ . U\:X 8'@!5_/'@ '?&_ -7:O@ -7:O@#@ -;"N &J : ! &! -M!^ #@ .G!7 #@ .I%3 #@ .I%3 #@ ,& . &!H " 8$$@! !_Q_P #_W_P -M #_W_P X #_A_@!@> %7\X$ 5\:\ U=J\ U=J\ . _X?X :H -M #_ B@H**@/@ '@#H " > (#X !X Z @_@" ^ > .@ (/^ B>@ +P!X@. -M@ (!\ . 3X*@ (#P @.@ (!\ Z C_ " Z @'P X " ? )@ (_\ B>@ + -M#X@.@ (!\ . 7 *@ (/P @.@ (!\ Z G_ " Z @'P X "#_@)@ )_X B> -M@ * 'X@.@ ("X . 6 *@ %_"0Z @+@#H$)#H " ^ #@ (?^ F!@ '@")X! -M@ $?B B R 0 . C^@ X !8 6 ?P$@ %^"0Z C^@"8 !_ . @'^"0B -M R 0 . C_@ X "'_@(@ ,!_^ (F8 ! X. _X 'X@(@ -@ & #@8 !P . -M 6 $@ ,'_X #@0D.@8 !P B !P?_@ ?\)"( #8 !@ X& < #@ (?^ B -M P'_P B8@ CX '____X /X@(@ AP & '_P . 6 $@ ,.+\ #@8 !@ @- -M@ ,!_\ (@ @.+\ /_@ @(@ AP & '_P . A_X"( # __ "(J 7^- -M@ CP #____Q^/X@(@ H__N /_X !@X +_@ $/_@ !_X (#8 # __@ -M"( ($/_@ #_X ("( (/X;@ #_^ -@ ,#_\ (B( "O@:.@ C@ !____Q_ -M/X@(@ A__^ ?_\ B "!?NX >N " J !B ?_\ B "!?NX ^N -M" B "G\#X !__P .$!X # __ "(B _P#WXV ". '____/\_B B "#__ -MP !__P"( (/__P !U8 ("H &0 !__P"( (/__P #U8 ("( */@' -M '__ 8. ?X'@ ,#_\ (B( #^ &_C8 (P /___\_S^("( "#_\#@ @. -M ' '__P. ""@ \ >N " V P__\ . A;1 X (+__P #ZX ("( ! -M# 2 P__\ 2 0$#@ ('_P. P/_P B(@ +P (B _X6T8. ",?_#____/\_ -MB B @__ X (# P !XQX#@ AQ2G '_@ @-@ ,/__ #@ )_^@. "'XQ -M\ _^ " B 0@$@ ,/__ #@ ( #O< /_ :8@ @'_X____S_/X@(@ (((0. P0 ( . #PA$ -M8 N !P #_[#__@8(@ (&<@. P?_X . #W>\8 O__P #_[#__@8( -M@ ('W@. P?_X . #W>\8 !_^ #P_#__@:(@ +^_@X (!_^/ -M___\_S^("( ""#$#@ ,"'$ #@ ]'B?P8 ;1X\ _\[__X&"( "!_X#@ ,# -MX\ #@ ]X>?P8 ;>'\ _\[__X&"( "!\X#@ ,#X\ #@ =X>?P8 .' X % -M __[__X&CH !XX2 #?A____^ X ( -M 'X /X #@X ,_@ ( !@X .OX #\#__@#'_G__ -M #^#@ ' !HF #Q____X ?@!___P/P/__^(6 \ X@(@ 4&9@& (2 $=@% -MG_G__@XX_X'_ !Y\ ?^ !@B "P>> 8 #P _]@'@X ,_@X _ '_ '[^ ?^ -M!@B !0>> 8 A( -V /P'_^ # 8 $ ___P84#B F &/ _^ ?__C_P #_-!_^>@// -M ?^ __X _ <(@ L____X .0 )__ 'X. "_Y[X ?_X#__@#\!PB %3____@ -MY__G_\ ? /__@'\,/__@(. ?P'B( (P/ ____D "># 8 $ ___@84#B B -M&7 '__PG! Y_\ #Y_\?_]X;SV'_@!_^,/X'"( %0_P?__"$@ + 'X2 "M_X -M '__@/_^-_X'"( !#X. $?!O__;_P!\ ___@>PP__^ @X !_@>(@ +P (. -M _P /X,!@ 0#__^AA8 #^ WB B &? #__@GBBY_\ #YO\?_\X;CF'_@!/\ -M./X'"( %@?@/_^"$@ + 'X2 "L_X '__@//\/_X'"( !#X. %>!O__;_P!\ -M ___@>1Q__^ \____@>(@ +P (. _P /X,!@ 4#__^Q]X2 _P /X@'@!H! -M\ G_P ,1##_@ .?SQ__GCP \?^ _YX_P<)@ 3P!_\ A( "@!^$@ J?_ #_ -M_X#C_G__!PB !0__W_\ A( (@!\ ___@<>#@ * XX,'B( "\ "#@ /\ #^# -M 8 % ___X>>$@ /\ '^(!X : _@!V_\ #((P_X !FX!__^ P8,'B( "^ &#@ /\ #^# 8 % ___^>^$@ /^ '^(!X : _P#^_X -M#1%P_X #^?\?\8P^ ?'_ #^?_X'"( %? /C_@"$@ * 'X. "_&-_@'__P ! -M_G_^!PB !7__Y_X A( (@!\ __Q@<># 8 $ ?___@>(@ +\ X. _P /X,! -M@ 4#___SYX2 _X ?X@'@!H#_ /__@ . +#_@ /_]Q_P #ZD\?P 'P_[@<( -M@ 5\ ^/^ (2 H ?@X +\ '^ /_\ '\/^X'"( %?__C_@"$@!" 'X '__ ! -M]UO__ !___N!XB OP#@X #_ _@X "@ >#@ 'WA( #_@ _B B !@__P_X -M X,"@ Y@!__@ #7^__@ /Z_[@<'@ 4#R!'__@. C__ X -!__@ #0 __@ -M _Z_[@<'@!H#R '__@ #@#__ ?___@ 8!__@ ___[@>)@ 'O@X #_ _ -MB( !SX2 _P /X@)@!@XP_P ____@ 8 ?_X '___X '^/\P'!X % \ X -M__P#@ (__@. #0?_X $ /_X /^/\P'!X : \_'__P X(__@ '___X $ -M /_X /__\P'B8 !QX. _P /XV _P /X@)@!@8X_@ ]___@ 8 ?_P # -MMW_X #^O\ '!X % X 8__@#@ (__@. #0?_P ,'_X ?^O\ '!X : X_G -M__@ Z(__@ '___P $>/_X ?__\ 'B8 !YX. _P@/XV _@ /X@(@!@/ -MQ__P /?_YP #,'YX ![-^. #_C\("( 8" #_\ '#^< !##^> P -M?C@ !_X_" F %SC_\ #OC^< !/_^> !\_C@ !___"(V _P\/XV _@ -M/X@(@!@/S__P /__YP ,'YX ![M^> #_]\("( 8" #_\ '#^< !_ -M_^> X?G@ #__?" F %S#_\ #GC^< !__^> !\_G@ #___"(V _P< -M/XV _ 'X@(@!D/___ /__YP ,'XX !7A^> '_Q^ !PF &&#_P -M'#^< !__^. +Y?G@ '_\?@ <)@!A@_\ YX_G ?__C@ "__YX !__ -M_X 'C8 #_!P_C8 #X ?B B "#___P '___ X # P#@ X (<'XP !?_I\ ' -M"8 "\#\#@!,\!P ___X !W/^, !__Z? !PF &/ _ ?__\ /__^ -M ?W_C ?___P >-@ /@/ >-@ . >("( (?\_\ ?\_\#@ ,# . #@ A@ -M'@ /__+P <)@ + ' . $S ' #___@ ?Y_X /__R\ '"8 4P!P !_S -M_P ___X '^?^ "#@ ' !XV ^ \!XT"@ $#B B "'_'_ '_'_ X # -M#@#@ X '8 X %__T0@(@ ,!P!P#@!)P!P _X_X /^?^ /__]$("( 5 -M < < ?\?\ /^/^ #_G_@ #@PB-@ /@?@>,@ 3\ !B!V W__\ @= -4@ -___ ('8 #?__P")V X #X@ -end diff --git a/win/gem/wingem.c b/win/gem/wingem.c deleted file mode 100644 index ddd5f813c..000000000 --- a/win/gem/wingem.c +++ /dev/null @@ -1,1234 +0,0 @@ -/* NetHack 3.6 wingem.c $NHDT-Date: 1450453304 2015/12/18 15:41:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.26 $ */ -/* Copyright (c) Christian Bressler, 1999 */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "hack.h" -#include "func_tab.h" -#include "dlb.h" -#include -#ifdef SHORT_FILENAMES -#include "patchlev.h" -#else -#include "patchlevel.h" -#endif - -#ifdef GEM_GRAPHICS -#include "wingem.h" - -static char nullstr[] = "", winpanicstr[] = "Bad window id %d"; -static int curr_status_line; - -static char *FDECL(copy_of, (const char *)); -static void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */ - -extern int mar_set_tile_mode(int); -extern void mar_set_font(int, const char *, int); -extern void mar_set_margin(int); -extern void mar_set_msg_visible(int); -extern void mar_set_status_align(int); -extern void mar_set_msg_align(int); -extern void mar_set_tilefile(char *); -extern void mar_set_tilex(int); -extern void mar_set_tiley(int); -extern short glyph2tile[MAX_GLYPH]; /* from tile.c */ -extern void mar_display_nhwindow(winid); /* from wingem1.c */ - -void Gem_outrip(winid, int, time_t); -void Gem_preference_update(const char *); -/* Interface definition, for windows.c */ -struct window_procs Gem_procs = { - "Gem", - WC_COLOR | WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_INVERSE - | WC_SCROLL_MARGIN | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU - | WC_FONT_TEXT | WC_FONT_MAP | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS - | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_FONTSIZ_MAP | WC_TILE_WIDTH - | WC_TILE_HEIGHT | WC_TILE_FILE | WC_VARY_MSGCOUNT | WC_ASCII_MAP, - 0L, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ - Gem_init_nhwindows, Gem_player_selection, Gem_askname, - Gem_get_nh_event, Gem_exit_nhwindows, Gem_suspend_nhwindows, - Gem_resume_nhwindows, Gem_create_nhwindow, Gem_clear_nhwindow, - Gem_display_nhwindow, Gem_destroy_nhwindow, Gem_curs, Gem_putstr, - genl_putmixed, Gem_display_file, Gem_start_menu, Gem_add_menu, - Gem_end_menu, Gem_select_menu, genl_message_menu, Gem_update_inventory, - Gem_mark_synch, Gem_wait_synch, -#ifdef CLIPPING - Gem_cliparound, -#endif -#ifdef POSITIONBAR - Gem_update_positionbar, -#endif - Gem_print_glyph, Gem_raw_print, Gem_raw_print_bold, Gem_nhgetch, - Gem_nh_poskey, Gem_nhbell, Gem_doprev_message, Gem_yn_function, - Gem_getlin, Gem_get_ext_cmd, Gem_number_pad, Gem_delay_output, -#ifdef CHANGE_COLOR /* the Mac uses a palette device */ - Gem_change_color, -#ifdef MAC - Gem_change_background, Gem_set_font_name, -#endif - Gem_get_color_string, -#endif - - /* other defs that really should go away (they're tty specific) */ - Gem_start_screen, Gem_end_screen, Gem_outrip, Gem_preference_update, - genl_getmsghistory, genl_putmsghistory - genl_status_init, - genl_status_finish, genl_status_enablefield, genl_status_update, - genl_can_suspend_no, -}; - -#ifdef MAC -void * -Gem_change_background(dummy) -int dummy; -{ -} - -short * -Gem_set_font_name(foo, bar) -winid foo; -char *bar; -{ -} -#endif - -/*************************** Proceduren *************************************/ - -int -mar_hp_query(void) -{ - if (Upolyd) - return (u.mh ? u.mhmax / u.mh : -1); - return (u.uhp ? u.uhpmax / u.uhp : -1); -} - -int -mar_iflags_numpad() -{ - return (iflags.num_pad ? 1 : 0); -} - -int -mar_get_msg_history() -{ - return (iflags.msg_history); -} - -int -mar_get_msg_visible() -{ - return (iflags.wc_vary_msgcount); -} -/* clean up and quit */ -static void -bail(mesg) -const char *mesg; -{ - clearlocks(); - Gem_exit_nhwindows(mesg); - nh_terminate(EXIT_SUCCESS); - /*NOTREACHED*/ -} - -/*$$$*/ -#define DEF_CLIPAROUND_MARGIN -1 -#ifndef TILE_X -#define TILE_X 16 -#endif -#define TILE_Y 16 -#define TILES_PER_LINE 20 -#define NHFONT_DEFAULT_SIZE 10 -#define NHFONT_SIZE_MIN 3 -#define NHFONT_SIZE_MAX 20 -/*$$$*/ -/*ARGSUSED*/ -void -Gem_init_nhwindows(argcp, argv) -int *argcp; -char **argv; -{ - argv = argv, argcp = argcp; - colors_changed = TRUE; - - set_wc_option_mod_status(WC_ALIGN_MESSAGE | WC_ALIGN_STATUS - | WC_TILE_WIDTH | WC_TILE_HEIGHT - | WC_TILE_FILE, - DISP_IN_GAME); - set_wc_option_mod_status( - WC_HILITE_PET | WC_SCROLL_MARGIN | WC_FONT_MESSAGE | WC_FONT_MAP - | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT - | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_MAP | WC_FONTSIZ_STATUS - | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT, - SET_IN_GAME); - if (iflags.wc_align_message == 0) - iflags.wc_align_message = ALIGN_TOP; - if (iflags.wc_align_status == 0) - iflags.wc_align_status = ALIGN_BOTTOM; - if (iflags.wc_scroll_margin == 0) - iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN; - if (iflags.wc_tile_width == 0) - iflags.wc_tile_width = TILE_X; - if (iflags.wc_tile_height == 0) - iflags.wc_tile_height = TILE_Y; - if (iflags.wc_tile_file && *iflags.wc_tile_file) - mar_set_tilefile(iflags.wc_tile_file); - if (iflags.wc_vary_msgcount == 0) - iflags.wc_vary_msgcount = 3; - mar_set_tile_mode( - !iflags.wc_ascii_map); /* MAR -- 17.Mar 2002 True is tiles */ - mar_set_tilex(iflags.wc_tile_width); - mar_set_tiley(iflags.wc_tile_height); - mar_set_msg_align(iflags.wc_align_message - ALIGN_BOTTOM); - mar_set_status_align(iflags.wc_align_status - ALIGN_BOTTOM); - if (mar_gem_init() == 0) { - bail((char *) 0); - /*NOTREACHED*/ - } - iflags.window_inited = TRUE; - - CO = 80; /* MAR -- whatsoever */ - LI = 25; - - add_menu_cmd_alias(' ', MENU_NEXT_PAGE); - mar_set_no_glyph(NO_GLYPH); -} - -void -Gem_player_selection() -{ - int i, k, n; - char pick4u = 'n', pbuf[QBUFSZ], lastch = 0, currch; - winid win; - anything any; - menu_item *selected = NULL; - - /* avoid unnecessary prompts further down */ - rigid_role_checks(); - - /* Should we randomly pick for the player? */ - if (!flags.randomall - && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE - || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) { - /* pick4u = yn_function("Shall I pick a character for you? - * [ynq]",ynqchars,'n');*/ - pick4u = yn_function(build_plselection_prompt( - pbuf, QBUFSZ, flags.initrole, flags.initrace, - flags.initgend, flags.initalign), - ynqchars, 'n'); - if (pick4u == 'q') { - give_up: /* Just quit */ - if (selected) - free((genericptr_t) selected); - bail((char *) 0); - /*NOTREACHED*/ - return; - } - } - - /* Select a role, if necessary */ - if (flags.initrole < 0) { - /* Process the choice */ - if (pick4u == 'y' || flags.initrole == ROLE_RANDOM - || flags.randomall) { - /* Pick a random role */ - flags.initrole = pick_role(flags.initrace, flags.initgend, - flags.initalign, PICK_RANDOM); - if (flags.initrole < 0) { - mar_add_message("Incompatible role!"); - mar_display_nhwindow(WIN_MESSAGE); - flags.initrole = randrole(FALSE); - } - } else { - /* Prompt for a role */ - win = create_nhwindow(NHW_MENU); - start_menu(win); - any.a_void = 0; /* zero out all bits */ - for (i = 0; roles[i].name.m; i++) { - if (ok_role(i, flags.initrace, flags.initgend, - flags.initalign)) { - any.a_int = i + 1; /* must be non-zero */ - currch = lowc(roles[i].name.m[0]); - if (currch == lastch) - currch = highc(currch); - add_menu(win, roles[i].malenum, &any, currch, 0, ATR_NONE, - an(roles[i].name.m), MENU_UNSELECTED); - lastch = currch; - } - } - any.a_int = pick_role(flags.initrace, flags.initgend, - flags.initalign, PICK_RANDOM) + 1; - if (any.a_int == 0) /* must be non-zero */ - any.a_int = randrole(FALSE) + 1; - add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", - MENU_UNSELECTED); - any.a_int = i + 1; /* must be non-zero */ - add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", - MENU_UNSELECTED); - end_menu(win, "Pick a role"); - n = select_menu(win, PICK_ONE, &selected); - destroy_nhwindow(win); - - /* Process the choice */ - if (n != 1 || selected[0].item.a_int == any.a_int) - goto give_up; /* Selected quit */ - - flags.initrole = selected[0].item.a_int - 1; - free((genericptr_t) selected), selected = 0; - } - } - - /* Select a race, if necessary */ - /* force compatibility with role, try for compatibility with - * pre-selected gender/alignment */ - if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { - /* pre-selected race not valid */ - if (pick4u == 'y' || flags.initrace == ROLE_RANDOM - || flags.randomall) { - flags.initrace = pick_race(flags.initrole, flags.initgend, - flags.initalign, PICK_RANDOM); - if (flags.initrace < 0) { - mar_add_message("Incompatible race!"); - mar_display_nhwindow(WIN_MESSAGE); - flags.initrace = randrace(flags.initrole); - } - } else { /* pick4u == 'n' */ - /* Count the number of valid races */ - n = 0; /* number valid */ - k = 0; /* valid race */ - for (i = 0; races[i].noun; i++) { - if (ok_race(flags.initrole, i, flags.initgend, - flags.initalign)) { - n++; - k = i; - } - } - if (n == 0) { - for (i = 0; races[i].noun; i++) { - if (validrace(flags.initrole, i)) { - n++; - k = i; - } - } - } - /* Permit the user to pick, if there is more than one */ - if (n > 1) { - win = create_nhwindow(NHW_MENU); - start_menu(win); - any.a_void = 0; /* zero out all bits */ - for (i = 0; races[i].noun; i++) - if (ok_race(flags.initrole, i, flags.initgend, - flags.initalign)) { - any.a_int = i + 1; /* must be non-zero */ - add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, - ATR_NONE, races[i].noun, MENU_UNSELECTED); - } - any.a_int = pick_race(flags.initrole, flags.initgend, - flags.initalign, PICK_RANDOM) + 1; - if (any.a_int == 0) /* must be non-zero */ - any.a_int = randrace(flags.initrole) + 1; - add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", - MENU_UNSELECTED); - any.a_int = i + 1; /* must be non-zero */ - add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", - MENU_UNSELECTED); - Sprintf(pbuf, "Pick the race of your %s", - roles[flags.initrole].name.m); - end_menu(win, pbuf); - n = select_menu(win, PICK_ONE, &selected); - destroy_nhwindow(win); - if (n != 1 || selected[0].item.a_int == any.a_int) - goto give_up; /* Selected quit */ - k = selected[0].item.a_int - 1; - free((genericptr_t) selected), selected = 0; - } - flags.initrace = k; - } - } - - /* Select a gender, if necessary */ - /* force compatibility with role/race, try for compatibility with - * pre-selected alignment */ - if (flags.initgend < 0 - || !validgend(flags.initrole, flags.initrace, flags.initgend)) { - /* pre-selected gender not valid */ - if (pick4u == 'y' || flags.initgend == ROLE_RANDOM - || flags.randomall) { - flags.initgend = pick_gend(flags.initrole, flags.initrace, - flags.initalign, PICK_RANDOM); - if (flags.initgend < 0) { - mar_add_message("Incompatible gender!"); - mar_display_nhwindow(WIN_MESSAGE); - flags.initgend = randgend(flags.initrole, flags.initrace); - } - } else { /* pick4u == 'n' */ - /* Count the number of valid genders */ - n = 0; /* number valid */ - k = 0; /* valid gender */ - for (i = 0; i < ROLE_GENDERS; i++) { - if (ok_gend(flags.initrole, flags.initrace, i, - flags.initalign)) { - n++; - k = i; - } - } - if (n == 0) { - for (i = 0; i < ROLE_GENDERS; i++) { - if (validgend(flags.initrole, flags.initrace, i)) { - n++; - k = i; - } - } - } - /* Permit the user to pick, if there is more than one */ - if (n > 1) { - win = create_nhwindow(NHW_MENU); - start_menu(win); - any.a_void = 0; /* zero out all bits */ - for (i = 0; i < ROLE_GENDERS; i++) - if (ok_gend(flags.initrole, flags.initrace, i, - flags.initalign)) { - any.a_int = i + 1; - add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, - ATR_NONE, genders[i].adj, MENU_UNSELECTED); - } - any.a_int = pick_gend(flags.initrole, flags.initrace, - flags.initalign, PICK_RANDOM) + 1; - if (any.a_int == 0) /* must be non-zero */ - any.a_int = randgend(flags.initrole, flags.initrace) + 1; - add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", - MENU_UNSELECTED); - any.a_int = i + 1; /* must be non-zero */ - add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", - MENU_UNSELECTED); - Sprintf(pbuf, "Pick the gender of your %s %s", - races[flags.initrace].adj, - roles[flags.initrole].name.m); - end_menu(win, pbuf); - n = select_menu(win, PICK_ONE, &selected); - destroy_nhwindow(win); - if (n != 1 || selected[0].item.a_int == any.a_int) - goto give_up; /* Selected quit */ - k = selected[0].item.a_int - 1; - free((genericptr_t) selected), selected = 0; - } - flags.initgend = k; - } - } - - /* Select an alignment, if necessary */ - /* force compatibility with role/race/gender */ - if (flags.initalign < 0 - || !validalign(flags.initrole, flags.initrace, flags.initalign)) { - /* pre-selected alignment not valid */ - if (pick4u == 'y' || flags.initalign == ROLE_RANDOM - || flags.randomall) { - flags.initalign = pick_align(flags.initrole, flags.initrace, - flags.initgend, PICK_RANDOM); - if (flags.initalign < 0) { - mar_add_message("Incompatible alignment!"); - mar_display_nhwindow(WIN_MESSAGE); - flags.initalign = randalign(flags.initrole, flags.initrace); - } - } else { /* pick4u == 'n' */ - /* Count the number of valid alignments */ - n = 0; /* number valid */ - k = 0; /* valid alignment */ - for (i = 0; i < ROLE_ALIGNS; i++) { - if (ok_align(flags.initrole, flags.initrace, flags.initgend, - i)) { - n++; - k = i; - } - } - if (n == 0) { - for (i = 0; i < ROLE_ALIGNS; i++) { - if (validalign(flags.initrole, flags.initrace, i)) { - n++; - k = i; - } - } - } - /* Permit the user to pick, if there is more than one */ - if (n > 1) { - win = create_nhwindow(NHW_MENU); - start_menu(win); - any.a_void = 0; /* zero out all bits */ - for (i = 0; i < ROLE_ALIGNS; i++) - if (ok_align(flags.initrole, flags.initrace, - flags.initgend, i)) { - any.a_int = i + 1; - add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, - ATR_NONE, aligns[i].adj, MENU_UNSELECTED); - } - any.a_int = pick_align(flags.initrole, flags.initrace, - flags.initgend, PICK_RANDOM) + 1; - if (any.a_int == 0) /* must be non-zero */ - any.a_int = randalign(flags.initrole, flags.initrace) + 1; - add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", - MENU_UNSELECTED); - any.a_int = i + 1; /* must be non-zero */ - add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", - MENU_UNSELECTED); - Sprintf(pbuf, "Pick the alignment of your %s %s %s", - genders[flags.initgend].adj, - races[flags.initrace].adj, - (flags.initgend && roles[flags.initrole].name.f) - ? roles[flags.initrole].name.f - : roles[flags.initrole].name.m); - end_menu(win, pbuf); - n = select_menu(win, PICK_ONE, &selected); - destroy_nhwindow(win); - if (n != 1 || selected[0].item.a_int == any.a_int) - goto give_up; /* Selected quit */ - k = selected[0].item.a_int - 1; - free((genericptr_t) selected), selected = 0; - } - flags.initalign = k; - } - } - - /* Success! */ - return; -} - -/* - * plname is filled either by an option (-u Player or -uPlayer) or - * explicitly (by being the wizard) or by askname. - * It may still contain a suffix denoting pl_character. - * Always called after init_nhwindows() and before display_gamewindows(). - */ - -void -Gem_askname() -{ - strncpy(plname, mar_ask_name(), PL_NSIZ); -} - -void -Gem_get_nh_event() -{ -} - -void -Gem_suspend_nhwindows(str) -const char *str; -{ - const char *foo; - - foo = str; /* MAR -- And the compiler whines no more ... */ -} - -void -Gem_resume_nhwindows() -{ -} - -void -Gem_end_screen() -{ -} - -void -Gem_start_screen() -{ -} - -extern void mar_exit_nhwindows(void); -extern boolean run_from_desktop; - -void -Gem_exit_nhwindows(str) -const char *str; -{ - if (str) - Gem_raw_print(str); - mar_exit_nhwindows(); - if (iflags.toptenwin) - run_from_desktop = FALSE; - iflags.window_inited = 0; -} - -winid -Gem_create_nhwindow(type) -int type; -{ - winid newid; - - switch (type) { - case NHW_MESSAGE: - if (iflags.msg_history < 20) - iflags.msg_history = 20; - else if (iflags.msg_history > 60) - iflags.msg_history = 60; - break; - case NHW_STATUS: - case NHW_MAP: - case NHW_MENU: - case NHW_TEXT: - break; - default: - panic("Tried to create window type %d\n", (int) type); - return WIN_ERR; - } - - newid = mar_create_window(type); - - if (newid == MAXWIN) { - panic("No window slots!"); - /* NOTREACHED */ - } - - return newid; -} - -void -Gem_nhbell() -{ - if (flags.silent) - return; - putchar('\007'); - fflush(stdout); -} - -extern void mar_clear_map(void); - -void -Gem_clear_nhwindow(window) -winid window; -{ - if (window == WIN_ERR) - panic(winpanicstr, window); - - switch (mar_hol_win_type(window)) { - case NHW_MESSAGE: - mar_clear_messagewin(); - break; - case NHW_MAP: - mar_clear_map(); - break; - case NHW_STATUS: - case NHW_MENU: - case NHW_TEXT: - break; - } -} - -extern void mar_more(void); - -/*ARGSUSED*/ -void -Gem_display_nhwindow(window, blocking) -winid window; -boolean blocking; -{ - if (window == WIN_ERR) - panic(winpanicstr, window); - - mar_display_nhwindow(window); - - switch (mar_hol_win_type(window)) { - case NHW_MESSAGE: - if (blocking) - mar_more(); - break; - case NHW_MAP: - if (blocking) - Gem_display_nhwindow(WIN_MESSAGE, TRUE); - break; - case NHW_STATUS: - case NHW_TEXT: - case NHW_MENU: - default: - break; - } -} - -void -Gem_destroy_nhwindow(window) -winid window; -{ - if (window == WIN_ERR) /* MAR -- test existence */ - panic(winpanicstr, window); - - mar_destroy_nhwindow(window); -} - -extern void mar_curs(int, int); /* mar_curs is only for map */ - -void -Gem_curs(window, x, y) -winid window; -register int x, y; -{ - if (window == WIN_ERR) /* MAR -- test existence */ - panic(winpanicstr, window); - - if (window == WIN_MAP) - mar_curs(x - 1, y); /*$$$*/ - else if (window == WIN_STATUS) - curr_status_line = y; -} - -extern void mar_add_status_str(const char *, int); -extern void mar_putstr_text(winid, int, const char *); - -void -Gem_putstr(window, attr, str) -winid window; -int attr; -const char *str; -{ - int win_type; - - if (window == WIN_ERR) { - Gem_raw_print(str); - return; - } - - if (str == (const char *) 0) - return; - - switch ((win_type = mar_hol_win_type(window))) { - case NHW_MESSAGE: - mar_add_message(str); - break; - - case NHW_STATUS: - mar_status_dirty(); - mar_add_status_str(str, curr_status_line); - if (curr_status_line) - mar_display_nhwindow(WIN_STATUS); - break; - - case NHW_MAP: - if (strcmp(str, ".")) - Gem_putstr(WIN_MESSAGE, 0, str); - else - mar_map_curs_weiter(); - mar_display_nhwindow(WIN_MESSAGE); - mar_display_nhwindow(WIN_STATUS); - break; - - case NHW_MENU: - mar_change_menu_2_text(window); - /* Fallthru */ - case NHW_TEXT: - mar_putstr_text(window, attr, str); - break; - } /* endswitch win_type */ -} - -void -Gem_display_file(fname, complain) -const char *fname; -boolean complain; -{ - dlb *f; - char buf[BUFSZ]; - char *cr; - - f = dlb_fopen(fname, "r"); - if (!f) { - if (complain) - pline("Cannot open \"%s\".", fname); - } else { - winid datawin; - - datawin = Gem_create_nhwindow(NHW_TEXT); - while (dlb_fgets(buf, BUFSZ, f)) { - if ((cr = index(buf, '\n')) != 0) - *cr = 0; - if (index(buf, '\t') != 0) - (void) tabexpand(buf); - Gem_putstr(datawin, 0, buf); - } - (void) dlb_fclose(f); - Gem_display_nhwindow(datawin, FALSE); - Gem_destroy_nhwindow(datawin); - } -} - -/*ARGSUSED*/ -/* - * Add a menu item to the beginning of the menu list. This list is reversed - * later. - */ -void -Gem_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) -winid window; /* window to use, must be of type NHW_MENU */ -int glyph; /* glyph to display with item (unused) */ -const anything *identifier; /* what to return if selected */ -char ch; /* keyboard accelerator (0 = pick our own) */ -char gch; /* group accelerator (0 = no group) */ -int attr; /* attribute for string (like Gem_putstr()) */ -const char *str; /* menu string */ -boolean preselected; /* item is marked as selected */ -{ - Gem_menu_item *G_item; - const char *newstr; - char buf[QBUFSZ]; - - if (str == (const char *) 0) - return; - - if (window == WIN_ERR) /* MAR -- test existence */ - panic(winpanicstr, window); - - if (identifier->a_void) - Sprintf(buf, "%c - %s", ch ? ch : '?', str); - else - Sprintf(buf, "%s", str); - newstr = buf; - - G_item = (Gem_menu_item *) alloc(sizeof(Gem_menu_item)); - G_item->Gmi_identifier = (long) identifier->a_void; - G_item->Gmi_glyph = glyph != NO_GLYPH ? glyph2tile[glyph] : NO_GLYPH; - G_item->Gmi_count = -1L; - G_item->Gmi_selected = preselected ? 1 : 0; - G_item->Gmi_accelerator = ch; - G_item->Gmi_groupacc = gch; - G_item->Gmi_attr = attr; - G_item->Gmi_str = copy_of(newstr); - mar_add_menu(window, G_item); -} - -/* - * End a menu in this window, window must a type NHW_MENU. - * We assign the keyboard accelerators as needed. - */ -void -Gem_end_menu(window, prompt) -winid window; /* menu to use */ -const char *prompt; /* prompt to for menu */ -{ - if (window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU) - panic(winpanicstr, window); - - /* Reverse the list so that items are in correct order. */ - mar_reverse_menu(); - - /* Put the prompt at the beginning of the menu. */ - mar_set_menu_title(prompt); - - mar_set_accelerators(); -} - -int -Gem_select_menu(window, how, menu_list) -winid window; -int how; -menu_item **menu_list; -{ - Gem_menu_item *Gmit; - menu_item *mi; - int n; - - if (window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU) - panic(winpanicstr, window); - - *menu_list = (menu_item *) 0; - mar_set_menu_type(how); - Gem_display_nhwindow(window, TRUE); - - for (n = 0, Gmit = mar_hol_inv(); Gmit; Gmit = Gmit->Gmi_next) - if (Gmit->Gmi_selected) - n++; - - if (n > 0) { - *menu_list = (menu_item *) alloc(n * sizeof(menu_item)); - for (mi = *menu_list, Gmit = mar_hol_inv(); Gmit; - Gmit = Gmit->Gmi_next) - if (Gmit->Gmi_selected) { - mi->item = (anything)(genericptr_t) Gmit->Gmi_identifier; - mi->count = Gmit->Gmi_count; - mi++; - } - } - - return n; -} - -void -Gem_update_inventory() -{ -} - -void -Gem_mark_synch() -{ - mar_display_nhwindow(WIN_MESSAGE); - mar_display_nhwindow(WIN_MAP); - mar_display_nhwindow(WIN_STATUS); -} - -void -Gem_wait_synch() -{ - mar_display_nhwindow(WIN_MESSAGE); - mar_display_nhwindow(WIN_MAP); - mar_display_nhwindow(WIN_STATUS); -} - -#ifdef CLIPPING -extern void mar_cliparound(void); -void -Gem_cliparound(x, y) -int x, y; -{ - mar_curs(x - 1, y); - mar_cliparound(); -} -#endif /* CLIPPING */ - -/* - * Gem_print_glyph - * - * Print the glyph to the output device. Don't flush the output device. - * - * Since this is only called from show_glyph(), it is assumed that the - * position and glyph are always correct (checked there)! - */ - -void mar_print_gl_char(winid, xchar, xchar, int); - -extern int mar_set_rogue(int); - -extern void mar_add_pet_sign(winid, int, int); - -void -Gem_print_glyph(window, x, y, glyph, bkglyph) -winid window; -xchar x, y; -int glyph, bkglyph; -{ - /* Move the cursor. */ - Gem_curs(window, x, y); - - mar_set_rogue(Is_rogue_level(&u.uz) ? TRUE : FALSE); - - x--; /* MAR -- because x ranges from 1 to COLNO */ - if (mar_set_tile_mode(-1)) { - mar_print_glyph(window, x, y, glyph2tile[glyph], glyph2tile[bkglyph]); - if ( -#ifdef TEXTCOLOR - iflags.hilite_pet && -#endif - glyph_is_pet(glyph)) - mar_add_pet_sign(window, x, y); - } else - mar_print_gl_char(window, x, y, glyph); -} - -void mar_print_char(winid, xchar, xchar, char, int); - -void -mar_print_gl_char(window, x, y, glyph) -winid window; -xchar x, y; -int glyph; -{ - int ch; - int color; - unsigned special; - - /* map glyph to character and color */ - (void) mapglyph(glyph, &ch, &color, &special, x, y, 0); - -#ifdef TEXTCOLOR - /* Turn off color if rogue level. */ - if (Is_rogue_level(&u.uz)) - color = NO_COLOR; -#endif /* TEXTCOLOR */ - - mar_print_char(window, x, y, ch, color); -} - -extern void mar_raw_print(const char *); -extern void mar_raw_print_bold(const char *); - -void -Gem_raw_print(str) -const char *str; -{ - if (str && *str) { - if (iflags.window_inited) - mar_raw_print(str); - else - printf("%s\n", str); - } -} - -void -Gem_raw_print_bold(str) -const char *str; -{ - if (str && *str) { - if (iflags.window_inited) - mar_raw_print_bold(str); - else - printf("%s\n", str); - } -} - -extern void mar_update_value(void); /* wingem1.c */ - -int -Gem_nhgetch() -{ - int i; - - mar_update_value(); - i = tgetch(); - if (!i) - i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ - - return i; -} - -/* Get a extended command in windowport specific way. - returns index of the ext_cmd or -1. - called after '#'. - It's a menu with all the possibilities. */ -int -Gem_get_ext_cmd() -{ - winid wind; - int i, count, what, too_much = FALSE; - menu_item *selected = NULL; - anything any; - char accelerator = 0, tmp_acc = 0; - const char *ptr; - - wind = Gem_create_nhwindow(NHW_MENU); - Gem_start_menu(wind); - for (i = 0; (ptr = extcmdlist[i].ef_txt); i++) { - any.a_int = i; - accelerator = *ptr; - if (tmp_acc == accelerator) { - if (too_much) - accelerator = '&'; /* MAR -- poor choice, anyone? */ - else - accelerator += 'A' - 'a'; - too_much = TRUE; - } else - too_much = FALSE; - tmp_acc = *ptr; - Gem_add_menu(wind, NO_GLYPH, &any, accelerator, 0, ATR_NONE, ptr, - FALSE); - } - Gem_end_menu(wind, "What extended command?"); - count = Gem_select_menu(wind, PICK_ONE, &selected); - what = count ? selected->item.a_int : -1; - if (selected) - free(selected); - Gem_destroy_nhwindow(wind); - return (what); -} - -void -Gem_number_pad(state) -int state; -{ - state = state; -} - -void -win_Gem_init() -{ -} - -#ifdef POSITIONBAR -void -Gem_update_positionbar(posbar) -char *posbar; -{ -} -#endif - -/** Gem_outrip **/ -void mar_set_text_to_rip(winid); -char **rip_line = 0; - -void -Gem_outrip(w, how, when) -winid w; -int how; -time_t when; -{ -/* Code from X11 windowport */ -#define STONE_LINE_LEN 15 /* # chars that fit on one line */ -#define NAME_LINE 0 /* line # for player name */ -#define GOLD_LINE 1 /* line # for amount of gold */ -#define DEATH_LINE 2 /* line # for death description */ -#define YEAR_LINE 6 /* line # for year */ - char buf[BUFSZ]; - char *dpx; - int line; - long year; - - if (!rip_line) { - int i; - rip_line = (char **) malloc((YEAR_LINE + 1) * sizeof(char *)); - for (i = 0; i < YEAR_LINE + 1; i++) { - rip_line[i] = - (char *) malloc((STONE_LINE_LEN + 1) * sizeof(char)); - } - } - /* Follows same algorithm as genl_outrip() */ - /* Put name on stone */ - Sprintf(rip_line[NAME_LINE], "%s", plname); - /* Put $ on stone */ - Sprintf(rip_line[GOLD_LINE], "%ld Au", done_money); - /* Put together death description */ - formatkiller(buf, sizeof buf, how, FALSE); - - /* Put death type on stone */ - for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; line++) { - register int i, i0; - char tmpchar; - if ((i0 = strlen(dpx)) > STONE_LINE_LEN) { - for (i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) - if (dpx[i] == ' ') - i0 = i; - if (!i) - i0 = STONE_LINE_LEN; - } - tmpchar = dpx[i0]; - dpx[i0] = 0; - strcpy(rip_line[line], dpx); - if (tmpchar != ' ') { - dpx[i0] = tmpchar; - dpx = &dpx[i0]; - } else - dpx = &dpx[i0 + 1]; - } - /* Put year on stone */ - year = yyyymmdd(when) / 10000L; - Sprintf(rip_line[YEAR_LINE], "%4ld", year); - - mar_set_text_to_rip(w); - for (line = 0; line < 13; line++) - putstr(w, 0, ""); -} -void -mar_get_font(type, p_fname, psize) -int type; -char **p_fname; -int *psize; -{ - switch (type) { - case NHW_MESSAGE: - *p_fname = iflags.wc_font_message; - *psize = iflags.wc_fontsiz_message; - break; - case NHW_MAP: - *p_fname = iflags.wc_font_map; - *psize = iflags.wc_fontsiz_map; - break; - case NHW_STATUS: - *p_fname = iflags.wc_font_status; - *psize = iflags.wc_fontsiz_status; - break; - case NHW_MENU: - *p_fname = iflags.wc_font_menu; - *psize = iflags.wc_fontsiz_menu; - break; - case NHW_TEXT: - *p_fname = iflags.wc_font_text; - *psize = iflags.wc_fontsiz_text; - break; - default: - break; - } -} -void -Gem_preference_update(pref) -const char *pref; -{ - if (stricmp(pref, "font_message") == 0 - || stricmp(pref, "font_size_message") == 0) { - if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN - || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX) - iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; - mar_set_font(NHW_MESSAGE, iflags.wc_font_message, - iflags.wc_fontsiz_message); - return; - } - if (stricmp(pref, "font_map") == 0 - || stricmp(pref, "font_size_map") == 0) { - if (iflags.wc_fontsiz_map < NHFONT_SIZE_MIN - || iflags.wc_fontsiz_map > NHFONT_SIZE_MAX) - iflags.wc_fontsiz_map = NHFONT_DEFAULT_SIZE; - mar_set_font(NHW_MAP, iflags.wc_font_map, iflags.wc_fontsiz_map); - return; - } - if (stricmp(pref, "font_status") == 0 - || stricmp(pref, "font_size_status") == 0) { - if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN - || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX) - iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE; - mar_set_font(NHW_STATUS, iflags.wc_font_status, - iflags.wc_fontsiz_status); - return; - } - if (stricmp(pref, "font_menu") == 0 - || stricmp(pref, "font_size_menu") == 0) { - if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN - || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX) - iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; - mar_set_font(NHW_MENU, iflags.wc_font_menu, iflags.wc_fontsiz_menu); - return; - } - if (stricmp(pref, "font_text") == 0 - || stricmp(pref, "font_size_text") == 0) { - if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN - || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX) - iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; - mar_set_font(NHW_TEXT, iflags.wc_font_text, iflags.wc_fontsiz_text); - return; - } - if (stricmp(pref, "scroll_margin") == 0) { - mar_set_margin(iflags.wc_scroll_margin); - Gem_cliparound(u.ux, u.uy); - return; - } - if (stricmp(pref, "ascii_map") == 0) { - mar_set_tile_mode(!iflags.wc_ascii_map); - doredraw(); - return; - } - if (stricmp(pref, "hilite_pet") == 0) { - /* MAR -- works without doing something here. */ - return; - } - if (stricmp(pref, "align_message") == 0) { - mar_set_msg_align(iflags.wc_align_message - ALIGN_BOTTOM); - return; - } - if (stricmp(pref, "align_status") == 0) { - mar_set_status_align(iflags.wc_align_status - ALIGN_BOTTOM); - return; - } - if (stricmp(pref, "vary_msgcount") == 0) { - mar_set_msg_visible(iflags.wc_vary_msgcount); - return; - } -} -/* - * Allocate a copy of the given string. If null, return a string of - * zero length. - * - * This is an exact duplicate of copy_of() in X11/winmenu.c. - */ -static char * -copy_of(s) -const char *s; -{ - if (!s) - s = nullstr; - return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s); -} - -#endif /* GEM_GRAPHICS \ - \ -/*wingem.c*/ diff --git a/win/gem/wingem1.c b/win/gem/wingem1.c deleted file mode 100644 index 368aff27e..000000000 --- a/win/gem/wingem1.c +++ /dev/null @@ -1,3290 +0,0 @@ -/* NetHack 3.6 wingem1.c $NHDT-Date: 1433806613 2015/06/08 23:36:53 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ */ -/* Copyright (c) Christian Bressler 1999 */ -/* NetHack may be freely redistributed. See license for details. */ - -#define __TCC_COMPAT__ - -#include -#include -#include -#include -#include -#include -#include - -#include "gem_rsc.h" -#include "load_img.h" -#include "gr_rect.h" - -#define genericptr_t void * -typedef signed char schar; -#include "wintype.h" -#undef genericptr_t - -#define NDECL(f) f(void) -#define FDECL(f, p) f p -#define CHAR_P char -#define SCHAR_P schar -#define UCHAR_P uchar -#define XCHAR_P xchar -#define SHORT_P short -#define BOOLEAN_P boolean -#define ALIGNTYP_P aligntyp -typedef signed char xchar; -#include "wingem.h" -#undef CHAR_P -#undef SCHAR_P -#undef UCHAR_P -#undef XCHAR_P -#undef SHORT_P -#undef BOOLEAN_P -#undef ALIGNTYP_P -#undef NDECL -#undef FDECL - -static char nullstr[] = "", md[] = "NetHack 3.6.0", strCancel[] = "Cancel", - strOk[] = "Ok", strText[] = "Text"; - -extern winid WIN_MESSAGE, WIN_MAP, WIN_STATUS, WIN_INVEN; - -#define MAXWIN 20 -#define ROWNO 21 -#define COLNO 80 -#define MSGLEN 100 - -#define MAP_GADGETS \ - NAME | MOVER | CLOSER | FULLER | LFARROW | RTARROW | UPARROW | DNARROW \ - | VSLIDE | HSLIDE | SIZER | SMALLER -#define DIALOG_MODE AUTO_DIAL | MODAL | NO_ICONIFY - -/* - * Keyboard translation tables. - */ -#define C(c) (0x1f & (c)) -#define M(c) (0x80 | (c)) - -#define KEYPADLO 0x61 -#define KEYPADHI 0x71 - -#define PADKEYS (KEYPADHI - KEYPADLO + 1) -#define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) - -/* - * Keypad keys are translated to the normal values below. - * When iflags.BIOS is active, shifted keypad keys are translated to the - * shift values below. - */ -static const struct pad { - char normal, shift, cntrl; -} keypad[PADKEYS] = - { - { C('['), 'Q', C('[') }, /* UNDO */ - { '?', '/', '?' }, /* HELP */ - { '(', 'a', '(' }, /* ( */ - { ')', 'w', ')' }, /* ) */ - { '/', '/', '/' }, /* / */ - { C('p'), '$', C('p') }, /* * */ - { 'y', 'Y', C('y') }, /* 7 */ - { 'k', 'K', C('k') }, /* 8 */ - { 'u', 'U', C('u') }, /* 9 */ - { 'h', 'H', C('h') }, /* 4 */ - { '.', '.', '.' }, - { 'l', 'L', C('l') }, /* 6 */ - { 'b', 'B', C('b') }, /* 1 */ - { 'j', 'J', C('j') }, /* 2 */ - { 'n', 'N', C('n') }, /* 3 */ - { 'i', 'I', C('i') }, /* Ins */ - { '.', ':', ':' } /* Del */ - }, - numpad[PADKEYS] = { - { C('['), 'Q', C('[') }, /* UNDO */ - { '?', '/', '?' }, /* HELP */ - { '(', 'a', '(' }, /* ( */ - { ')', 'w', ')' }, /* ) */ - { '/', '/', '/' }, /* / */ - { C('p'), '$', C('p') }, /* * */ - { '7', M('7'), '7' }, /* 7 */ - { '8', M('8'), '8' }, /* 8 */ - { '9', M('9'), '9' }, /* 9 */ - { '4', M('4'), '4' }, /* 4 */ - { '.', '.', '.' }, /* 5 */ - { '6', M('6'), '6' }, /* 6 */ - { '1', M('1'), '1' }, /* 1 */ - { '2', M('2'), '2' }, /* 2 */ - { '3', M('3'), '3' }, /* 3 */ - { 'i', 'I', C('i') }, /* Ins */ - { '.', ':', ':' } /* Del */ - }; - -#define TBUFSZ 300 -#define BUFSZ 256 -extern int yn_number; /* from decl.c */ -extern char toplines[TBUFSZ]; /* from decl.c */ -extern char mapped_menu_cmds[]; /* from options.c */ -extern int mar_iflags_numpad(void); /* from wingem.c */ -extern void Gem_raw_print(const char *); /* from wingem.c */ -extern int mar_hp_query(void); /* from wingem.c */ -extern int mar_get_msg_history(void); /* from wingem.c */ -extern int mar_get_msg_visible(void); /* from wingem.c */ -extern void mar_get_font(int, char **, int *); /* from wingem.c */ -extern int vdi2dev4[]; /* from load_img.c */ - -void recalc_msg_win(GRECT *); -void recalc_status_win(GRECT *); -void calc_std_winplace(int, GRECT *); -int (*v_mtext)(int, int, int, char *); -static int no_glyph; /* the int indicating there is no glyph */ -IMG_header tile_image, titel_image, rip_image; -MFDB Tile_bilder, Map_bild, Titel_bild, Rip_bild, Black_bild, Pet_Mark, - FontCol_Bild; -static int Tile_width = 16, Tile_heigth = 16, Tiles_per_line = 20; -char *Tilefile = NULL; -/* pet_mark Design by Warwick Allison warwick@troll.no */ -static int pet_mark_data[] = { 0x0000, 0x3600, 0x7F00, 0x7F00, - 0x3E00, 0x1C00, 0x0800 }; -static short *normal_palette = NULL; - -static struct gw { - WIN *gw_window; - int gw_type, gw_dirty; - GRECT gw_place; -} Gem_nhwindow[MAXWIN]; - -typedef struct { - int id; - int size; - int cw, ch; - int prop; -} NHGEM_FONT; - -/*struct gemmapdata {*/ -GRECT dirty_map_area = { COLNO - 1, ROWNO, 0, 0 }; -int map_cursx = 0, map_cursy = 0, curs_col = WHITE; -int draw_cursor = TRUE, scroll_margin = -1; -NHGEM_FONT map_font; -SCROLL scroll_map; -char **map_glyphs = NULL; -dirty_rect *dr_map; -/*};*/ - -/*struct gemstatusdata{*/ -char **status_line; -int Anz_status_lines, status_w, status_align = FALSE; -NHGEM_FONT status_font; -dirty_rect *dr_stat; -/*};*/ - -/*struct gemmessagedata{*/ -int mar_message_pause = TRUE; -int mar_esc_pressed = FALSE; -int messages_pro_zug = 0; -char **message_line; -int *message_age; -int msg_pos = 0, msg_max = 0, msg_anz = 0, msg_width = 0, msg_vis = 3, - msg_align = TRUE; -NHGEM_FONT msg_font; -dirty_rect *dr_msg; -/*};*/ - -/*struct geminvdata {*/ -SCROLL scroll_menu; -Gem_menu_item *invent_list; -int Anz_inv_lines = 0, Inv_breite = 16; -NHGEM_FONT menu_font; -int Inv_how; -/*};*/ - -/*struct gemtextdata{*/ -char **text_lines; -int Anz_text_lines = 0, text_width; -NHGEM_FONT text_font; -int use_rip = FALSE; -extern char **rip_line; -/*};*/ - -static OBJECT *zz_oblist[NHICON + 1]; - -MITEM scroll_keys[] = { - /* menu, key, state, mode, msg */ - { FAIL, key(CTRLLEFT, 0), K_CTRL, PAGE_LEFT, FAIL }, - { FAIL, key(CTRLRIGHT, 0), K_CTRL, PAGE_RIGHT, FAIL }, - { FAIL, key(SCANUP, 0), K_SHIFT, PAGE_UP, FAIL }, - { FAIL, key(SCANDOWN, 0), K_SHIFT, PAGE_DOWN, FAIL }, - { FAIL, key(SCANLEFT, 0), 0, LINE_LEFT, FAIL }, - { FAIL, key(SCANRIGHT, 0), 0, LINE_RIGHT, FAIL }, - { FAIL, key(SCANUP, 0), 0, LINE_UP, FAIL }, - { FAIL, key(SCANDOWN, 0), 0, LINE_DOWN, FAIL }, - { FAIL, key(SCANLEFT, 0), K_SHIFT, LINE_START, FAIL }, - { FAIL, key(SCANRIGHT, 0), K_SHIFT, LINE_END, FAIL }, - { FAIL, key(SCANUP, 0), K_CTRL, WIN_START, FAIL }, - { FAIL, key(SCANDOWN, 0), K_CTRL, WIN_END, FAIL }, - { FAIL, key(SCANHOME, 0), K_SHIFT, WIN_END, FAIL }, - { FAIL, key(SCANHOME, 0), 0, WIN_START, FAIL } -}; -#define SCROLL_KEYS 14 - -static DIAINFO *Inv_dialog; - -#define null_free(ptr) free(ptr), (ptr) = NULL -#define test_free(ptr) \ - if (ptr) \ - null_free(ptr) - -static char *Menu_title = NULL; - -void mar_display_nhwindow(winid); -void -mar_check_hilight_status(void) -{ -} /* to be filled :-) */ -static char *mar_copy_of(const char *); - -extern void panic(const char *, ...); -void * -m_alloc(size_t amt) -{ - void *ptr; - - ptr = malloc(amt); - if (!ptr) - panic("Memory allocation failure; cannot get %lu bytes", amt); - return (ptr); -} - -void -mar_clear_messagewin(void) -{ - int i, *ptr = message_age; - - if (WIN_MESSAGE == WIN_ERR) - return; - for (i = msg_anz; --i >= 0; ptr++) { - if (*ptr) - Gem_nhwindow[WIN_MESSAGE].gw_dirty = TRUE; - *ptr = FALSE; - } - mar_message_pause = FALSE; - - mar_display_nhwindow(WIN_MESSAGE); -} - -void -clipbrd_save(void *data, int cnt, boolean append, boolean is_inv) -{ - char path[MAX_PATH], *text, *crlf = "\r\n"; - long handle; - int i; - - if (data && cnt > 0 && scrp_path(path, "scrap.txt") - && (handle = append ? Fopen(path, 1) : Fcreate(path, 0)) > 0) { - if (append) - Fseek(0L, (int) handle, SEEK_END); - if (is_inv) { - Gem_menu_item *it = (Gem_menu_item *) data; - - for (; it; it = it->Gmi_next) { - text = it->Gmi_str; - Fwrite((int) handle, strlen(text), text); - Fwrite((int) handle, 2L, crlf); - } - } else { - for (i = 0; i < cnt; i++) { - text = ((char **) data)[i] + 1; - Fwrite((int) handle, strlen(text), text); - Fwrite((int) handle, 2L, crlf); - } - } - Fclose((int) handle); - - scrp_changed(SCF_TEXT, 0x2e545854l); /* .TXT */ - } -} - -void -move_win(WIN *z_win) -{ - GRECT frame = desk; - - v_set_mode(MD_XOR); - v_set_line(BLACK, 1, 1, 0, 0); - frame.g_w <<= 1, frame.g_h <<= 1; - if (graf_rt_dragbox(FALSE, &z_win->curr, &frame, &z_win->curr.g_x, - &z_win->curr.g_y, NULL)) - window_size(z_win, &z_win->curr); - else - window_top(z_win); -} - -void -message_handler(int x, int y) -{ - switch (objc_find(zz_oblist[MSGWIN], ROOT, MAX_DEPTH, x, y)) { - case UPMSG: - if (msg_pos > msg_vis - 1) { - msg_pos--; - Gem_nhwindow[WIN_MESSAGE].gw_dirty = TRUE; - mar_display_nhwindow(WIN_MESSAGE); - } - Event_Timer(50, 0, TRUE); - break; - case DNMSG: - if (msg_pos < msg_max) { - msg_pos++; - Gem_nhwindow[WIN_MESSAGE].gw_dirty = TRUE; - mar_display_nhwindow(WIN_MESSAGE); - } - Event_Timer(50, 0, TRUE); - break; - case GRABMSGWIN: - default: - move_win(Gem_nhwindow[WIN_MESSAGE].gw_window); - break; - case -1: - break; - } -} - -int -mar_ob_mapcenter(OBJECT *p_obj) -{ - WIN *p_w = WIN_MAP != WIN_ERR ? Gem_nhwindow[WIN_MAP].gw_window : NULL; - - if (p_obj && p_w) { - p_obj->ob_x = p_w->work.g_x + p_w->work.g_w / 2 - p_obj->ob_width / 2; - p_obj->ob_y = - p_w->work.g_y + p_w->work.g_h / 2 - p_obj->ob_height / 2; - return (DIA_LASTPOS); - } - return (DIA_CENTERED); -} - -/****************************** set_no_glyph - * *************************************/ - -void -mar_set_no_glyph(ng) -int ng; -{ - no_glyph = ng; -} - -void -mar_set_tilefile(name) -char *name; -{ - Tilefile = name; -} -void -mar_set_tilex(value) -int value; -{ - Min(&value, 32); - Max(&value, 1); - Tile_width = value; -} -void -mar_set_tiley(value) -int value; -{ - Min(&value, 32); - Max(&value, 1); - Tile_heigth = value; -} -/****************************** userdef_draw - * *************************************/ - -void rearrange_windows(void); -void -mar_set_status_align(int sa) -{ - if (status_align != sa) { - status_align = sa; - rearrange_windows(); - } -} -void -mar_set_msg_align(int ma) -{ - if (msg_align != ma) { - msg_align = ma; - rearrange_windows(); - } -} -void -mar_set_msg_visible(int mv) -{ - if (mv != msg_vis) { - Max(&mv, 1); - Min(&mv, min(msg_anz, 20)); - Min(&mv, desk.g_h / msg_font.ch / 2); - msg_vis = mv; - rearrange_windows(); - } -} -/* size<0 cellheight; size>0 points */ -void -mar_set_fontbyid(int type, int id, int size) -{ - int chardim[4]; - if (id <= 0) - id = ibm_font_id; - if ((size > -3 && size < 3) || size < -20 || size > 20) - size = -ibm_font; - /* MAR -- 17.Mar 2002 For now allow FNT_PROP only with NHW_TEXT */ - if (type != NHW_TEXT && (FontInfo(id)->type & (FNT_PROP | FNT_ASCII))) - id = ibm_font_id; - switch (type) { - case NHW_MESSAGE: - if (msg_font.size == -size && msg_font.id == id) - break; - msg_font.size = -size; - msg_font.id = id; - msg_font.prop = FontInfo(id)->type & (FNT_PROP | FNT_ASCII); - v_set_text(msg_font.id, msg_font.size, BLACK, 0, 0, chardim); - msg_font.ch = chardim[3] ? chardim[3] : 1; - msg_font.cw = chardim[2] ? chardim[2] : 1; - msg_width = min(max_w / msg_font.cw - 3, MSGLEN); - rearrange_windows(); - break; - case NHW_MAP: - if (map_font.size != -size || map_font.id != id) { - MFDB mtmp; - map_font.size = -size; - map_font.id = id; - map_font.prop = FontInfo(id)->type & (FNT_PROP | FNT_ASCII); - v_set_text(map_font.id, map_font.size, BLACK, 0, 0, chardim); - map_font.ch = chardim[3] ? chardim[3] : 1; - map_font.cw = chardim[2] ? chardim[2] : 1; - mfdb(&mtmp, NULL, (COLNO - 1) * map_font.cw, ROWNO * map_font.ch, - 0, planes); - if (mfdb_size(&mtmp) > mfdb_size(&FontCol_Bild) - && mfdb_size(&mtmp) > mfdb_size(&Map_bild)) { - FontCol_Bild.fd_addr = Map_bild.fd_addr = - (int *) realloc(Map_bild.fd_addr, mfdb_size(&mtmp)); - if (!Map_bild.fd_addr) /* FIXME -- Not really neccessary since - the former space is still valid */ - panic("Not enough Space for the map."); - } - mfdb(&FontCol_Bild, FontCol_Bild.fd_addr, - (COLNO - 1) * map_font.cw, ROWNO * map_font.ch, 0, planes); - rearrange_windows(); - } - break; - case NHW_STATUS: - if (status_font.size == -size && status_font.id == id) - break; - status_font.size = -size; - status_font.id = id; - status_font.prop = FontInfo(id)->type & (FNT_PROP | FNT_ASCII); - v_set_text(status_font.id, status_font.size, BLACK, 0, 0, chardim); - status_font.ch = chardim[3] ? chardim[3] : 1; - status_font.cw = chardim[2] ? chardim[2] : 1; - rearrange_windows(); - break; - case NHW_MENU: - if (menu_font.size == -size && menu_font.id == id) - break; - menu_font.size = -size; - menu_font.id = id; - menu_font.prop = FontInfo(id)->type & (FNT_PROP | FNT_ASCII); - v_set_text(menu_font.id, menu_font.size, BLACK, 0, 0, chardim); - menu_font.ch = chardim[3] ? chardim[3] : 1; - menu_font.cw = chardim[2] ? chardim[2] : 1; - break; - case NHW_TEXT: - if (text_font.size == -size && text_font.id == id) - break; - text_font.size = -size; - text_font.id = id; - text_font.prop = FontInfo(id)->type & (FNT_PROP | FNT_ASCII); - v_set_text(text_font.id, text_font.size, BLACK, 0, 0, chardim); - text_font.ch = chardim[3] ? chardim[3] : 1; - text_font.cw = chardim[2] ? chardim[2] : 1; - break; - default: - break; - } -} -void -mar_set_font(int type, const char *font_name, int size) -{ - int id = 0; - /* MAR -- 17.Mar 2002 usual Gem behavior, use the Font-ID */ - if (font_name && *font_name) { - id = atoi(font_name); - if (id <= 0) { - int i, tid; - char name[32]; - for (i = fonts_loaded; --i >= 0;) { - tid = vqt_name(x_handle, i, name); - if (!stricmp(name, font_name)) { - id = tid; - break; - } - } - } - } - mar_set_fontbyid(type, id, size); -} -void -rearrange_windows(void) -{ - GRECT area; - int todo = TRUE; - if (WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window) { - scroll_map.px_hline = - mar_set_tile_mode(FAIL) ? Tile_width : map_font.cw; - scroll_map.px_vline = - mar_set_tile_mode(FAIL) ? Tile_heigth : map_font.ch; - if (todo) { - calc_std_winplace(FAIL, &area); - todo = FALSE; - } - calc_std_winplace(NHW_MAP, &area); - Gem_nhwindow[WIN_MAP].gw_window->max.g_w = area.g_w; - Gem_nhwindow[WIN_MAP].gw_window->max.g_h = area.g_h; - Gem_nhwindow[WIN_MAP].gw_window->max.g_w = area.g_w; - window_reinit(Gem_nhwindow[WIN_MAP].gw_window, md, md, NULL, FALSE, - FALSE); - { - int buf[8]; - buf[3] = K_CTRL; - buf[4] = C('L'); - AvSendMsg(ap_id, AV_SENDKEY, buf); - } - } - if (WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) { - if (todo) { - calc_std_winplace(FAIL, &area); - todo = FALSE; - } - calc_std_winplace(NHW_MESSAGE, &area); - Gem_nhwindow[WIN_MESSAGE].gw_window->min_h = area.g_h; - window_size(Gem_nhwindow[WIN_MESSAGE].gw_window, &area); - redraw_window(Gem_nhwindow[WIN_MESSAGE].gw_window, NULL); - } - if (WIN_STATUS != WIN_ERR && Gem_nhwindow[WIN_STATUS].gw_window) { - if (todo) { - calc_std_winplace(FAIL, &area); - todo = FALSE; - } - calc_std_winplace(NHW_STATUS, &area); - Gem_nhwindow[WIN_STATUS].gw_window->min_h = area.g_h; - window_size(Gem_nhwindow[WIN_STATUS].gw_window, &area); - redraw_window(Gem_nhwindow[WIN_STATUS].gw_window, NULL); - } -} -void -my_color_area(GRECT *area, int col) -{ - int pxy[4]; - - v_set_fill(col, 1, IP_SOLID, 0); - rc_grect_to_array(area, pxy); - v_bar(x_handle, pxy); -} - -void -my_clear_area(GRECT *area) -{ - my_color_area(area, WHITE); -} - -int mar_set_tile_mode(int); - -static void -win_draw_map(int first, WIN *win, GRECT *area) -{ - int pla[8], w = area->g_w - 1, h = area->g_h - 1; - int i, x, y; - GRECT back = *area; - - first = first; - - if (!mar_set_tile_mode(FAIL)) { - int start = - (area->g_x - win->work.g_x) / map_font.cw + scroll_map.hpos; - int stop = (area->g_x + area->g_w + map_font.cw - 1 - win->work.g_x) - / map_font.cw - + scroll_map.hpos; - int starty = - (area->g_y - win->work.g_y) / map_font.ch + scroll_map.vpos; - int stopy = min((area->g_y + area->g_h + map_font.ch - 1 - - win->work.g_y) / map_font.ch - + scroll_map.vpos, - ROWNO); - char tmp; - v_set_text(map_font.id, map_font.size, WHITE, 0, 0, NULL); - v_set_mode(MD_TRANS); - - x = win->work.g_x - scroll_map.px_hpos + start * map_font.cw; - y = win->work.g_y - scroll_map.px_vpos + starty * map_font.ch; - pla[2] = pla[0] = scroll_map.px_hpos + area->g_x - win->work.g_x; - pla[3] = pla[1] = starty * map_font.ch; - pla[2] += w; - pla[3] += map_font.ch - 1; - pla[6] = pla[4] = area->g_x; /* x_wert to */ - pla[7] = pla[5] = y; /* y_wert to */ - pla[6] += w; - pla[7] += map_font.ch - 1; - back.g_h = map_font.ch; - for (i = starty; i < stopy; i++, y += map_font.ch, - pla[1] += map_font.ch, pla[3] += map_font.ch, - pla[5] += map_font.ch, pla[7] += map_font.ch) { - back.g_y = y; - my_color_area(&back, BLACK); - tmp = map_glyphs[i][stop]; - map_glyphs[i][stop] = 0; - (*v_mtext)(x_handle, x, y, &map_glyphs[i][start]); - map_glyphs[i][stop] = tmp; - vro_cpyfm(x_handle, S_OR_D, pla, &FontCol_Bild, screen); - } - } else { - v_set_mode(MD_REPLACE); - pla[2] = pla[0] = scroll_map.px_hpos + area->g_x - win->work.g_x; - pla[3] = pla[1] = scroll_map.px_vpos + area->g_y - win->work.g_y; - pla[2] += w; - pla[3] += h; - pla[6] = pla[4] = area->g_x; /* x_wert to */ - pla[7] = pla[5] = area->g_y; /* y_wert to */ - pla[6] += w; - pla[7] += h; - vro_cpyfm(x_handle, S_ONLY, pla, &Map_bild, screen); - } - - if (draw_cursor) { - v_set_line(curs_col, 1, 1, 0, 0); - pla[0] = pla[2] = - win->work.g_x - + scroll_map.px_hline * (map_cursx - scroll_map.hpos); - pla[1] = pla[3] = - win->work.g_y - + scroll_map.px_vline * (map_cursy - scroll_map.vpos); - pla[2] += scroll_map.px_hline - 1; - pla[3] += scroll_map.px_vline - 1; - v_rect(pla[0], pla[1], pla[2], pla[3]); - } -} - -static int -draw_titel(PARMBLK *pb) -{ - static int pla[8]; - GRECT work = *(GRECT *) &pb->pb_x; - - if (rc_intersect((GRECT *) &pb->pb_xc, &work)) { - pla[0] = pla[1] = 0; - pla[2] = pb->pb_w - 1; - pla[3] = pb->pb_h - 1; - pla[6] = pla[4] = pb->pb_x; /* x_wert to */ - pla[7] = pla[5] = pb->pb_y; /* y_wert to */ - pla[6] += pb->pb_w - 1; - pla[7] += pb->pb_h - 1; - - vro_cpyfm(x_handle, S_ONLY, pla, &Titel_bild, screen); - } - - return (0); -} - -static int -draw_lines(PARMBLK *pb) -{ - GRECT area = *(GRECT *) &pb->pb_x; - - if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { - char **ptr; - int x = pb->pb_x, y = pb->pb_y, start_line = (area.g_y - y); - - v_set_mode((text_font.cw & 7) == 0 && text_font.prop == 0 ? MD_REPLACE - : MD_TRANS); - - /* void v_set_text(int font,int height,int color,int effect,int - * rotate,int out[4]) */ - v_set_text(text_font.id, text_font.size, BLACK, 0, 0, NULL); - start_line /= text_font.ch; - y += start_line * text_font.ch; - x -= (int) scroll_menu.px_hpos; - ptr = &text_lines[start_line += scroll_menu.vpos]; - start_line = - min((area.g_y - y + area.g_h + text_font.ch - 1) / text_font.ch, - Anz_text_lines - start_line); - area.g_h = text_font.ch; - Vsync(); - /* x=(x+7) & ~7;*/ - for (; --start_line >= 0; y += text_font.ch) { - area.g_y = y; - my_clear_area(&area); - if (**ptr - 1) { - v_set_text(FAIL, 0, BLUE, 0x01, 0, NULL); - (*v_mtext)(x_handle, x, y, (*ptr++) + 1); - v_set_text(FAIL, 0, BLACK, 0x00, 0, NULL); - } else - (*v_mtext)(x_handle, x, y, (*ptr++) + 1); - } - } - return (0); -} - -static int -draw_rip(PARMBLK *pb) -{ - GRECT area = *(GRECT *) &pb->pb_x; - if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { - char **ptr; - int x = pb->pb_x, y = pb->pb_y, start_line = (area.g_y - y), - chardim[4], pla[8], i; - v_set_mode(MD_REPLACE); - /* void v_set_text(int font,int height,int color,int effect,int - * rotate,int out[4]) */ - v_set_text(text_font.id, text_font.size, BLACK, 0, 0, chardim); - start_line /= text_font.ch; - y += start_line * text_font.ch; - x -= scroll_menu.px_hpos; - ptr = &text_lines[start_line += scroll_menu.vpos]; - start_line = - min((area.g_y - y + area.g_h + text_font.ch - 1) / text_font.ch, - Anz_text_lines - start_line); - area.g_h = text_font.ch; - Vsync(); - x = (x + 7) & ~7; - for (; --start_line >= 0; y += text_font.ch) { - area.g_y = y; - my_clear_area(&area); - if (**ptr - 1) { - v_set_text(FAIL, 0, BLUE, 0x01, 0, NULL); - (*v_mtext)(x_handle, x, y, (*ptr++) + 1); - v_set_text(FAIL, 0, BLACK, 0x00, 0, NULL); - } else - (*v_mtext)(x_handle, x, y, (*ptr++) + 1); - } - pla[0] = pla[1] = 0; - pla[2] = min(pb->pb_w - 1, Rip_bild.fd_w - 1); - pla[3] = min(pb->pb_h - 1, Rip_bild.fd_h - 1); - pla[6] = pla[4] = - pb->pb_x + (pb->pb_w - Rip_bild.fd_w) / 2; /* x_wert to */ - pla[7] = pla[5] = pb->pb_y; /* y_wert to */ - pla[6] += pla[2]; - pla[7] += pla[3]; - vro_cpyfm(x_handle, S_ONLY, pla, &Rip_bild, screen); - v_set_mode(MD_TRANS); - vst_alignment(x_handle, 1, 5, &i, &i); - pla[5] += 64; - for (i = 0; i < 7; i++, pla[5] += chardim[3]) { - v_set_text(text_font.id, (i == 0 || i == 6) ? text_font.size : 12, - WHITE, 1, 0, chardim); - (*v_mtext)(x_handle, pla[4] + 157, pla[5], rip_line[i]); - v_set_text(text_font.id, (i == 0 || i == 6) ? text_font.size : 12, - BLACK, 0, 0, chardim); - (*v_mtext)(x_handle, pla[4] + 157, pla[5], rip_line[i]); - } - vst_alignment(x_handle, 0, 5, &i, &i); - } - return (0); -} - -static int -draw_msgline(PARMBLK *pb) -{ - GRECT area = *(GRECT *) &pb->pb_x; - - if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { - int x = pb->pb_x, y = pb->pb_y + (msg_vis - 1) * msg_font.ch, foo, i; - char **ptr = &message_line[msg_pos], tmp; - int startx, stopx, starty, stopy; - - x = (x + 7) & ~7; /* Byte alignment speeds output up */ - - v_set_mode(MD_REPLACE); - - /* void v_set_text(int font,int height,int color,int effect,int - * rotate,int out[4]) */ - v_set_text(msg_font.id, msg_font.size, FAIL, FAIL, 0, NULL); - vst_alignment(x_handle, 0, 5, &foo, &foo); - stopy = min(msg_pos, msg_vis); - /* Vsync();*/ - startx = - (area.g_x - x) / msg_font.cw - - 1; /* MAR 06.02.2001 -- because italic covers the next char */ - Max(&startx, 0); - stopx = (area.g_x + area.g_w + msg_font.cw - x - 1) / msg_font.cw; - x += startx * msg_font.cw; - for (i = 0; i < stopy; i++, y -= msg_font.ch, ptr--) { - if (message_age[msg_pos - i]) - v_set_text(FAIL, 0, BLACK, 0, 0, NULL); - else - v_set_text(FAIL, 0, LBLACK, 4, 0, NULL); - tmp = (*ptr)[stopx]; - (*ptr)[stopx] = 0; - (*v_mtext)(x_handle, x, y, &(*ptr)[startx]); - (*ptr)[stopx] = tmp; - } - } - return (0); -} - -static int -draw_status(PARMBLK *pb) -{ - GRECT area = *(GRECT *) &pb->pb_x; - - area.g_x += 2 * status_font.cw - 2; - area.g_w -= 2 * status_font.cw - 2; - if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { - int x = pb->pb_x, y = pb->pb_y, startx, stopx, starty, stopy, i; - char tmp; - - /* void v_set_text(int font,int height,int color,int effect,int - * rotate,int out[4]) */ - v_set_mode(MD_REPLACE); - v_set_text(status_font.id, status_font.size, BLACK, 0, 0, NULL); - x = (x + 2 * status_font.cw + 6) & ~7; - - startx = (area.g_x - x) / status_font.cw; - starty = (area.g_y - y) / status_font.ch; - stopx = - (area.g_x + area.g_w + status_font.ch - 1 - x) / status_font.cw; - stopy = - (area.g_y + area.g_h + status_font.ch - 1 - y) / status_font.ch; - Max(&startx, 0); /* MAR -- Hmm, area.g_x could end up 1 below x */ - Max(&stopx, 0); - x += startx * status_font.cw; - y += starty * status_font.ch; - /* Vsync();*/ - area.g_h = status_font.ch; - for (i = starty; i < min(2, stopy); - i++, area.g_y += status_font.ch, y += status_font.ch) { - my_clear_area(&area); - tmp = status_line[i][stopx]; - status_line[i][stopx] = 0; - (*v_mtext)(x_handle, x, y, &status_line[i][startx]); - status_line[i][stopx] = tmp; - } - } - return (0); -} - -static int -draw_inventory(PARMBLK *pb) -{ - GRECT area = *(GRECT *) &pb->pb_x; - - if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { - int gl, i, x = pb->pb_x, y = pb->pb_y, start_line = area.g_y - y; - Gem_menu_item *it; - - v_set_mode(MD_REPLACE); - v_set_text(menu_font.id, menu_font.size, BLACK, 0, 0, NULL); - - start_line /= menu_font.ch; - y += start_line * menu_font.ch; - x -= scroll_menu.px_hpos; - start_line += scroll_menu.vpos; - - for (it = invent_list, i = start_line; --i >= 0 && it; - it = it->Gmi_next) - ; - - i = min((area.g_y - y + area.g_h + menu_font.ch - 1) / menu_font.ch, - Anz_inv_lines - start_line); - - Vsync(); - area.g_h = menu_font.ch; - - for (; (--i >= 0) && it; it = it->Gmi_next, y += menu_font.ch) { - if (it->Gmi_attr) - v_set_text(FAIL, FALSE, BLUE, 1, FAIL, NULL); /* Bold */ - else - v_set_text(FAIL, FALSE, BLACK, 0, FAIL, NULL); - - area.g_y = y; - my_clear_area(&area); - if ((gl = it->Gmi_glyph) != no_glyph) { - int pla[8], h = min(menu_font.ch, Tile_heigth) - 1; - - pla[0] = pla[2] = - (gl % Tiles_per_line) * Tile_width; /* x_wert from */ - pla[1] = pla[3] = - (gl / Tiles_per_line) * Tile_heigth; /* y_wert from */ - pla[4] = pla[6] = x; /* x_wert to */ - pla[5] = pla[7] = y; /* y_wert to */ - pla[2] += Tile_width - 1; - pla[3] += h; - pla[6] += Tile_heigth - 1; - pla[7] += h; - - vro_cpyfm(x_handle, S_ONLY, pla, &Tile_bilder, screen); - } - if (it->Gmi_identifier) - it->Gmi_str[2] = it->Gmi_selected - ? (it->Gmi_count == -1L ? '+' : '#') - : '-'; - (*v_mtext)(x_handle, (x + 23) & ~7, y, it->Gmi_str); - } - } - return (0); -} - -static int -draw_prompt(PARMBLK *pb) -{ - GRECT area = *(GRECT *) &pb->pb_x; - - if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { - char **ptr = (char **) pb->pb_parm; - int x = pb->pb_x, y = pb->pb_y, chardim[4]; - - /* void v_set_text(int font,int height,int color,int effect,int - * rotate,int out[4]) */ - v_set_mode(MD_TRANS); - v_set_text(ibm_font_id, ibm_font, WHITE, 0, 0, chardim); - Vsync(); - if (planes < 4) { - int pxy[4]; - v_set_fill(BLACK, 2, 4, 0); - rc_grect_to_array(&area, pxy); - v_bar(x_handle, pxy); - } else - my_color_area(&area, LWHITE); - (*v_mtext)(x_handle, x, y, *(ptr++)); - if (*ptr) - (*v_mtext)(x_handle, x, y + chardim[3], *ptr); - } - return (0); -} - -static USERBLK ub_lines = { draw_lines, 0L }, ub_msg = { draw_msgline, 0L }, - ub_inventory = { draw_inventory, 0L }, - ub_titel = { draw_titel, 0L }, ub_status = { draw_status, 0L }, - ub_prompt = { draw_prompt, 0L }; - -/**************************** rsc_funktionen *****************************/ - -void -my_close_dialog(DIAINFO *dialog, boolean shrink_box) -{ - close_dialog(dialog, shrink_box); - Event_Timer(0, 0, TRUE); -} - -void -mar_get_rsc_tree(obj_number, z_ob_obj) -int obj_number; -OBJECT **z_ob_obj; -{ - rsrc_gaddr(R_TREE, obj_number, z_ob_obj); - fix_objects(*z_ob_obj, SCALING, 0, 0); -} - -void mar_clear_map(void); - -void -img_error(errnumber) -int errnumber; -{ - char buf[BUFSZ]; - - switch (errnumber) { - case ERR_HEADER: - sprintf(buf, "%s", "[1][ Image Header | corrupt. ][ Oops ]"); - break; - case ERR_ALLOC: - sprintf(buf, "%s", - "[1][ Not enough | memory for | an image. ][ Oops ]"); - break; - case ERR_FILE: - sprintf(buf, "%s", - "[1][ The Image-file | is not available ][ Oops ]"); - break; - case ERR_DEPACK: - sprintf(buf, "%s", "[1][ The Image-file | is corrupt ][ Oops ]"); - break; - case ERR_COLOR: - sprintf(buf, "%s", "[1][ Number of colors | not supported ][ Oops ]"); - break; - default: - sprintf(buf, "[1][ img_error | strange error | number: %i ][ Hmm ]", - errnumber); - break; - } - form_alert(1, buf); -} - -void -mar_change_button_char(OBJECT *z_ob, int nr, char ch) -{ - *ob_get_text(z_ob, nr, 0) = ch; - ob_set_hotkey(z_ob, nr, ch); -} - -void -mar_set_dir_keys() -{ - static int mi_numpad = FAIL; - char mcmd[] = "bjnh.lyku", npcmd[] = "123456789", *p_cmd; - - if (mi_numpad != mar_iflags_numpad()) { - OBJECT *z_ob = zz_oblist[DIRECTION]; - int i; - mi_numpad = mar_iflags_numpad(); - ob_set_hotkey(z_ob, DIRDOWN, '>'); - ob_set_hotkey(z_ob, DIRUP, '<'); - p_cmd = mi_numpad ? npcmd : mcmd; - for (i = 0; i < 9; i++) - mar_change_button_char(z_ob, DIR1 + 2 * i, p_cmd[i]); - } -} - -extern int total_tiles_used; /* tile.c */ - -int -mar_gem_init() -{ - int i, bild_fehler = FALSE, fsize; - char *fname; - static MITEM wish_workaround = { FAIL, key(0, 'J'), K_CTRL, W_CYCLE, - FAIL }; - OBJECT *z_ob; - - if ((i = open_rsc("gem_rsc.rsc", NULL, md, md, md, 0, 0, 0)) <= 0) { - graf_mouse(M_OFF, NULL); - if (i < 0) - form_alert(1, "[3][| Fatal Error | File: GEM_RSC.RSC | not " - "found. ][ grumble ]"); - else - form_alert(1, "[3][| Fatal Error | GEM initialisation | failed. " - "][ a pity ]"); - return (0); - } - if (planes < 1 || planes > 8) { - form_alert( - 1, - "[3][ Color-depth | not supported, | try 2-256 colors. ][ Ok ]"); - return (0); - } - MouseBee(); - - /* MAR -- 17.Mar 2002 NVDI 3.0 or better uses v_ftext */ - v_mtext = speedo == 3 ? &v_ftext : &v_gtext; - for (i = 0; i < NHICON; i++) - mar_get_rsc_tree(i, &zz_oblist[i]); - - z_ob = zz_oblist[ABOUT]; - ob_hide(z_ob, OKABOUT, TRUE); - ob_draw_dialog(z_ob, 0, 0, 0, 0); - - mar_get_font(NHW_MESSAGE, &fname, &fsize); - mar_set_font(NHW_MESSAGE, fname, fsize); - mar_get_font(NHW_MAP, &fname, &fsize); - mar_set_font(NHW_MAP, fname, fsize); - mar_get_font(NHW_STATUS, &fname, &fsize); - mar_set_font(NHW_STATUS, fname, fsize); - mar_get_font(NHW_MENU, &fname, &fsize); - mar_set_font(NHW_MENU, fname, fsize); - mar_get_font(NHW_TEXT, &fname, &fsize); - mar_set_font(NHW_TEXT, fname, fsize); - msg_anz = mar_get_msg_history(); - mar_set_msg_visible(mar_get_msg_visible()); - msg_width = min(max_w / msg_font.cw - 3, MSGLEN); - - if (max_w / status_font.cw < COLNO - 1) - mar_set_fontbyid(NHW_STATUS, small_font_id, -small_font); - status_w = min(max_w / status_font.cw - 3, MSGLEN); - - if (planes > 0 && planes < 9) { - normal_palette = (short *) m_alloc(3 * colors * sizeof(short)); - get_colors(x_handle, normal_palette, colors); - } - -loadimg: - bild_fehler = depack_img(Tilefile ? Tilefile : (planes >= 4) ? "NH16.IMG" - : "NH2.IMG", - &tile_image); - if (bild_fehler) { - z_ob = zz_oblist[ABOUT]; - ob_undraw_dialog(z_ob, 0, 0, 0, 0); - ob_hide(z_ob, OKABOUT, FALSE); - img_error(bild_fehler); - return (0); - } - if (tile_image.img_w % Tile_width || tile_image.img_h % Tile_heigth) { - Tilefile = NULL; - Tile_width = Tile_heigth = 16; - printf("size didn't match.\n"); - goto loadimg; - } - if ((tile_image.img_w / Tile_width) * (tile_image.img_h / Tile_heigth) - < total_tiles_used) { - Tilefile = NULL; - Tile_width = Tile_heigth = 16; - printf("Too few Tiles in Image.\n"); - goto loadimg; - } - Tiles_per_line = tile_image.img_w / Tile_width; - - if (planes >= 4) { - if (tile_image.planes > 1) - img_set_colors(x_handle, tile_image.palette, tile_image.planes); -#if 0 - else{ - int mypalette[]={}; - img_set_colors(x_handle, mypalette, 4); - } -#endif - } - - mfdb(&Tile_bilder, (int *) tile_image.addr, tile_image.img_w, - tile_image.img_h, 1, tile_image.planes); - transform_img(&Tile_bilder); - - mfdb(&Map_bild, NULL, (COLNO - 1) * Tile_width, ROWNO * Tile_heigth, 0, - planes); - mfdb(&FontCol_Bild, NULL, (COLNO - 1) * map_font.cw, ROWNO * map_font.ch, - 0, planes); - Map_bild.fd_addr = - (int *) m_alloc(mfdb_size(&Map_bild) > mfdb_size(&FontCol_Bild) - ? mfdb_size(&Map_bild) - : mfdb_size(&FontCol_Bild)); - FontCol_Bild.fd_addr = Map_bild.fd_addr; - - mfdb(&Pet_Mark, pet_mark_data, 8, 7, 1, 1); - vr_trnfm(x_handle, &Pet_Mark, &Pet_Mark); - - mfdb(&Black_bild, NULL, 16, 32, 1, - 1); /* MAR -- 17.Mar 2002 that should cover the biggest map-font */ - Black_bild.fd_addr = (int *) m_alloc(mfdb_size(&Black_bild)); - memset(Black_bild.fd_addr, 255, mfdb_size(&Black_bild)); - vr_trnfm(x_handle, &Black_bild, &Black_bild); - - for (i = 0; i < MAXWIN; i++) { - Gem_nhwindow[i].gw_window = NULL; - Gem_nhwindow[i].gw_type = 0; - Gem_nhwindow[i].gw_dirty = TRUE; - } - - memset(&scroll_menu, 0, sizeof(scroll_menu)); - scroll_menu.scroll = AUTO_SCROLL; - scroll_menu.obj = LINESLIST; - scroll_menu.px_hline = menu_font.cw; - scroll_menu.px_vline = menu_font.ch; - scroll_menu.hscroll = scroll_menu.vscroll = 1; - scroll_menu.tbar_d = 2 * gr_ch - 2; - - mar_set_dir_keys(); - - memset(&scroll_map, 0, sizeof(scroll_map)); - scroll_map.scroll = AUTO_SCROLL; - scroll_map.obj = ROOT; - scroll_map.px_hline = mar_set_tile_mode(FAIL) ? Tile_width : map_font.cw; - scroll_map.px_vline = mar_set_tile_mode(FAIL) ? Tile_heigth : map_font.ch; - scroll_map.hsize = COLNO - 1; - scroll_map.vsize = ROWNO; - scroll_map.hpage = 8; - scroll_map.vpage = 8; - scroll_map.hscroll = 1; - scroll_map.vscroll = 1; - - /* dial_options( round, niceline, standard, return_default, background, - nonselectable, - always_keys, toMouse, clipboard, hz); */ - dial_options(TRUE, TRUE, FALSE, RETURN_DEFAULT, AES_BACK, TRUE, - KEY_ALWAYS, FALSE, TRUE, 3); - /* dial_colors( dial_pattern, dial_color, dial_frame, hotkey, alert, - cycle_button, - check_box, radio_button, arrow, cycle_backgrnd, check_backgrnd, - radio_backgrnd, - arrow_backgrnd, edit_3d, draw_3d) */ - if (planes < 4) - dial_colors(4, BLACK, WHITE, RED, RED, WHITE, BLACK, BLACK, BLACK, - FAIL, FAIL, FAIL, FAIL, TRUE, TRUE); - else - dial_colors(7, LWHITE, BLACK, RED, RED, BLACK, BLACK, BLACK, BLACK, - WHITE, WHITE, WHITE, WHITE, TRUE, TRUE); - - /* void MenuItems(MITEM *close,MITEM *closeall,MITEM *cycle,MITEM - *invcycle, - MITEM *globcycle,MITEM *full,MITEM *bottom,MITEM *iconify,MITEM - *iconify_all, - MITEM *menu,int menu_cnt) */ - /* Ctrl-W ist normaly bound to cycle */ - MenuItems(NULL, NULL, &wish_workaround, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, 0); - - menu_install(zz_oblist[MENU], TRUE); - - z_ob = zz_oblist[ABOUT]; - ob_undraw_dialog(z_ob, 0, 0, 0, 0); - ob_hide(z_ob, OKABOUT, FALSE); - - return (1); -} - -/************************* mar_exit_nhwindows *******************************/ - -void -mar_exit_nhwindows() -{ - int i; - - for (i = MAXWIN; --i >= 0;) - if (Gem_nhwindow[i].gw_type) - mar_destroy_nhwindow(i); - - if (normal_palette) { - img_set_colors(x_handle, normal_palette, tile_image.planes); - null_free(normal_palette); - } - test_free(tile_image.palette); - test_free(tile_image.addr); - test_free(titel_image.palette); - test_free(titel_image.addr); -} - -/************************* mar_curs *******************************/ - -void -mar_curs(x, y) -int x, y; -{ - Min(&dirty_map_area.g_x, x); - Min(&dirty_map_area.g_y, y); - Max(&dirty_map_area.g_w, x); - Max(&dirty_map_area.g_h, y); - Min(&dirty_map_area.g_x, map_cursx); - Min(&dirty_map_area.g_y, map_cursy); - Max(&dirty_map_area.g_w, map_cursx); - Max(&dirty_map_area.g_h, map_cursy); - - map_cursx = x; - map_cursy = y; - - if (WIN_MAP != WIN_ERR) - Gem_nhwindow[WIN_MAP].gw_dirty = TRUE; -} - -void mar_cliparound(void); -void -mar_map_curs_weiter(void) -{ - static int once = TRUE; - - if (once) { - redraw_window(Gem_nhwindow[WIN_STATUS].gw_window, NULL); - redraw_window(Gem_nhwindow[WIN_MESSAGE].gw_window, NULL); - once = FALSE; - } - mar_curs(map_cursx + 1, map_cursy); - mar_cliparound(); -} - -/************************* about *******************************/ - -void -mar_about() -{ - xdialog(zz_oblist[ABOUT], md, NULL, NULL, DIA_CENTERED, FALSE, - DIALOG_MODE); - Event_Timer(0, 0, TRUE); -} - -/************************* ask_name *******************************/ - -char * -mar_ask_name() -{ - OBJECT *z_ob = zz_oblist[NAMEGET]; - int bild_fehler; - char who_are_you[] = "Who are you? "; - - bild_fehler = - depack_img(planes < 4 ? "TITLE2.IMG" : "TITLE.IMG", &titel_image); - if (bild_fehler) { /* MAR -- this isn't lethal */ - ob_set_text(z_ob, NETHACKPICTURE, "missing title.img."); - } else { - mfdb(&Titel_bild, (int *) titel_image.addr, titel_image.img_w, - titel_image.img_h, 1, titel_image.planes); - transform_img(&Titel_bild); - z_ob[NETHACKPICTURE].ob_type = G_USERDEF; - z_ob[NETHACKPICTURE].ob_spec.userblk = &ub_titel; - } - - ob_clear_edit(z_ob); - xdialog(z_ob, who_are_you, NULL, NULL, DIA_CENTERED, FALSE, DIALOG_MODE); - Event_Timer(0, 0, TRUE); - - test_free(titel_image.palette); - test_free(titel_image.addr); - test_free(Titel_bild.fd_addr); - return (ob_get_text(z_ob, PLNAME, 0)); -} - -/************************* more *******************************/ - -void -send_key(int key) -{ - int buf[8]; - - buf[3] = 0; /* No Shift/Ctrl/Alt */ - buf[4] = key; - AvSendMsg(ap_id, AV_SENDKEY, buf); -} - -void -send_return() -{ - send_key(key(SCANRET, 0)); -} - -int -K_Init(xev, availiable) -XEVENT *xev; -int availiable; -{ - xev = xev; - return (MU_KEYBD & availiable); -} - -int -KM_Init(xev, availiable) -XEVENT *xev; -int availiable; -{ - xev = xev; - return ((MU_KEYBD | MU_MESAG) & availiable); -} - -int -M_Init(xev, availiable) -XEVENT *xev; -int availiable; -{ - xev = xev; - return (MU_MESAG & availiable); -} - -#define More_Init K_Init - -int -More_Handler(xev) -XEVENT *xev; -{ - int ev = xev->ev_mwich; - - if (ev & MU_KEYBD) { - char ch = (char) (xev->ev_mkreturn & 0x00FF); - DIAINFO *dinf; - WIN *w; - - switch (ch) { - case '\033': /* no more more more */ - case ' ': - if ((w = get_top_window()) && (dinf = (DIAINFO *) w->dialog) - && dinf->di_tree == zz_oblist[PAGER]) { - if (ch == '\033') - mar_esc_pressed = TRUE; - send_return(); - break; - } - /* Fall thru */ - default: - ev &= ~MU_KEYBD; /* unknown key */ - break; - } - } - return (ev); -} - -void -mar_more() -{ - if (!mar_esc_pressed) { - OBJECT *z_ob = zz_oblist[PAGER]; - WIN *p_w; - - Event_Handler(More_Init, More_Handler); - dial_colors(7, RED, BLACK, RED, RED, BLACK, BLACK, BLACK, BLACK, - WHITE, WHITE, WHITE, WHITE, TRUE, TRUE); - if (WIN_MESSAGE != WIN_ERR - && (p_w = Gem_nhwindow[WIN_MESSAGE].gw_window)) { - z_ob->ob_x = p_w->work.g_x; - z_ob->ob_y = p_w->curr.g_y + p_w->curr.g_h + gr_ch; - } - xdialog(z_ob, NULL, NULL, NULL, DIA_LASTPOS, FALSE, DIALOG_MODE); - Event_Timer(0, 0, TRUE); - Event_Handler(NULL, NULL); - - if (planes < 4) - dial_colors(4, BLACK, WHITE, RED, RED, WHITE, BLACK, BLACK, BLACK, - FAIL, FAIL, FAIL, FAIL, TRUE, TRUE); - else - dial_colors(7, LWHITE, BLACK, RED, RED, BLACK, BLACK, BLACK, - BLACK, WHITE, WHITE, WHITE, WHITE, TRUE, TRUE); - } -} - -/************************* Gem_start_menu *******************************/ -void -Gem_start_menu(win) -winid win; -{ - win = win; - if (invent_list) { - Gem_menu_item *curr, *next; - - for (curr = invent_list; curr; curr = next) { - next = curr->Gmi_next; - free(curr->Gmi_str); - free(curr); - } - } - invent_list = NULL; - Anz_inv_lines = 0; - Inv_breite = 16; -} - -/************************* mar_add_menu *******************************/ - -void -mar_add_menu(win, item) -winid win; -Gem_menu_item *item; -{ - win = win; - item->Gmi_next = invent_list; - invent_list = item; - Anz_inv_lines++; -} - -void -mar_reverse_menu() -{ - Gem_menu_item *next, *head = 0, *curr = invent_list; - - while (curr) { - next = curr->Gmi_next; - curr->Gmi_next = head; - head = curr; - curr = next; - } - invent_list = head; -} - -void -mar_set_accelerators() -{ - char ch = 'a'; - Gem_menu_item *curr; - - for (curr = invent_list; curr; curr = curr->Gmi_next) { - int extent[8]; - v_set_text(menu_font.id, menu_font.size, BLACK, 0, 0, NULL); - vqt_extent(x_handle, curr->Gmi_str, extent); - Max(&Inv_breite, extent[4] + Tile_width + menu_font.cw); - if (ch && curr->Gmi_accelerator == 0 && curr->Gmi_identifier) { - curr->Gmi_accelerator = ch; - curr->Gmi_str[0] = ch; - if (ch == 'z') - ch = 'A'; - else if (ch == 'Z') - ch = 0; - else - ch++; - } - } -} - -Gem_menu_item * -mar_hol_inv() -{ - return (invent_list); -} - -/************************* mar_putstr_text *********************/ - -void mar_raw_print(const char *); - -void -mar_set_text_to_rip(winid w) -{ - use_rip = TRUE; -} -void -mar_putstr_text(winid window, int attr, const char *str) -{ - static int zeilen_frei = 0; - int breite; - char *ptr; - - window = window; - if (!text_lines) { - text_lines = (char **) m_alloc(12 * sizeof(char *)); - zeilen_frei = 12; - } - if (!zeilen_frei) { - text_lines = (char **) realloc(text_lines, (Anz_text_lines + 12) - * sizeof(char *)); - zeilen_frei = 12; - } - if (!text_lines) { - mar_raw_print("No room for Text"); - return; - } - - if (str) - breite = strlen(str); - Min(&breite, 80); - ptr = text_lines[Anz_text_lines] = - (char *) m_alloc(breite * sizeof(char) + 2); - *ptr = (char) (attr + 1); /* avoid 0 */ - strncpy(ptr + 1, str, breite); - ptr[breite + 1] = 0; - Anz_text_lines++; - zeilen_frei--; -} - -int -mar_set_inv_win(Anzahl, Breite) -int Anzahl, Breite; -{ - OBJECT *z_ob = zz_oblist[LINES]; - int retval = WIN_DIAL | MODAL | NO_ICONIFY; - - scroll_menu.hsize = 0; - scroll_menu.vpage = (desk.g_h - 3 * gr_ch) / scroll_menu.px_vline; - if (Anzahl > scroll_menu.vpage) { - retval |= WD_VSLIDER; - if (Breite > max_w - 3 * scroll_menu.px_hline) { - retval |= WD_HSLIDER; - scroll_menu.hpage = - (max_w - 3 * scroll_menu.px_hline) / scroll_menu.px_hline; - scroll_menu.hpos = 0; - scroll_menu.hsize = Breite / scroll_menu.px_hline; - scroll_menu.vpage = - (desk.g_h - 4 * gr_ch - 1) / scroll_menu.px_vline; - } - Anzahl = scroll_menu.vpage; - } else { - if (Breite > max_w - scroll_menu.px_hline) { - retval |= WD_HSLIDER; - scroll_menu.hpage = - (max_w - scroll_menu.px_hline) / scroll_menu.px_hline; - scroll_menu.hpos = 0; - scroll_menu.hsize = Breite / scroll_menu.px_hline; - scroll_menu.vpage = - (desk.g_h - 4 * gr_ch - 1) / scroll_menu.px_vline; - if (Anzahl > scroll_menu.vpage) { - retval |= WD_VSLIDER; - Anzahl = scroll_menu.vpage; - } - } - scroll_menu.vpage = Anzahl; - } - if ((scroll_menu.hmax = scroll_menu.hsize - scroll_menu.hpage) < 0) - scroll_menu.hmax = 0; - if ((scroll_menu.vmax = scroll_menu.vsize - scroll_menu.vpage) < 0) - scroll_menu.vmax = 0; - - /* left/right/up 2 pixel border down 2gr_ch toolbar */ - z_ob[ROOT].ob_width = z_ob[LINESLIST].ob_width = Breite; - z_ob[ROOT].ob_height = z_ob[QLINE].ob_y = z_ob[LINESLIST].ob_height = - scroll_menu.px_vline * Anzahl; - z_ob[QLINE].ob_y += gr_ch / 2; - z_ob[ROOT].ob_width += 4; - z_ob[ROOT].ob_height += 2 * gr_ch + 2; - - return (retval); -} - -/************************* mar_status_dirty *******************************/ - -void -mar_status_dirty() -{ - int ccol; - - ccol = mar_hp_query(); - - if (ccol < 2) - curs_col = WHITE; /* 50-100% : 0 */ - else if (ccol < 3) - curs_col = YELLOW; /* 33-50% : 6 */ - else if (ccol < 5) - curs_col = LYELLOW; /* 20-33% : 14*/ - else if (ccol < 10) - curs_col = RED; /* 10-20% : 2 */ - else - curs_col = MAGENTA; /* <10% : 7*/ -} - -/************************* mar_add_message *******************************/ - -void -mar_add_message(str) -const char *str; -{ - int i, mesg_hist = mar_get_msg_history(); - char *tmp, *rest, buf[TBUFSZ]; - - if (WIN_MESSAGE == WIN_ERR) - return; - - if (!mar_message_pause) { - mar_message_pause = TRUE; - messages_pro_zug = 0; - msg_pos = msg_max; - } - - if (msg_max > mesg_hist - 2) { - msg_max = mesg_hist - 2; - msg_pos--; - if (msg_pos < 0) - msg_pos = 0; - tmp = message_line[0]; - for (i = 0; i < mesg_hist - 1; i++) { - message_line[i] = message_line[i + 1]; - message_age[i] = message_age[i + 1]; - } - message_line[mesg_hist - 1] = tmp; - } - strcpy(toplines, str); - messages_pro_zug++; - msg_max++; - - if ((int) strlen(toplines) >= msg_width) { - int pos = msg_width; - tmp = toplines + msg_width; - while (*tmp != ' ' && pos >= 0) { - tmp--; - pos--; - } - if (pos <= 0) - pos = msg_width; /* Mar -- Oops, what a word :-) */ - message_age[msg_max] = TRUE; - strncpy(message_line[msg_max], toplines, pos); - message_line[msg_max][pos] = 0; - rest = strcpy(buf, toplines + pos); - } else { - message_age[msg_max] = TRUE; - strncpy(message_line[msg_max], toplines, msg_width); - rest = 0; - } - - Gem_nhwindow[WIN_MESSAGE].gw_dirty = TRUE; - if (messages_pro_zug - >= mesg_hist) { /* MAR -- Greater then should never happen */ - messages_pro_zug = mesg_hist; - mar_display_nhwindow(WIN_MESSAGE); - } - - if (rest) - mar_add_message(rest); -} - -/************************* mar_add_status_str *******************************/ - -void -mar_add_status_str(str, line) -const char *str; -int line; -{ - int i, last_diff = -1; - GRECT area = { 0, line * status_font.ch, status_font.cw, status_font.ch }; - for (i = 0; (i < status_w - 2) && str[i]; i++) - if (str[i] != status_line[line][i]) { - if (last_diff == -1) - area.g_x = i * status_font.cw; - else - area.g_w += status_font.cw; - last_diff = i; - status_line[line][i] = str[i]; - } else if (last_diff >= 0) { - add_dirty_rect(dr_stat, &area); - last_diff = -1; - area.g_w = status_font.cw; - } - for (; i < status_w - 1; i++) { - if (status_line[line][i]) { - if (last_diff == -1) - area.g_x = i * status_font.cw; - else - area.g_w += status_font.cw; - last_diff = i; - } - status_line[line][i] = 0; - } - if (last_diff >= 0) - add_dirty_rect(dr_stat, &area); -} - -/************************* mar_set_menu_title *******************************/ - -void -mar_set_menu_title(str) -const char *str; -{ - test_free(Menu_title); /* just in case */ - Menu_title = mar_copy_of(str ? str : nullstr); -} - -/************************* mar_set_menu_type *******************************/ - -void -mar_set_menu_type(how) -int how; -{ - Inv_how = how; -} - -/************************* Inventory Utils *******************************/ - -void -set_all_on_page(start, page) -int start, page; -{ - Gem_menu_item *curr; - - if (start < 0 || page < 0) - return; - - for (curr = invent_list; start-- && curr; curr = curr->Gmi_next) - ; - for (; page-- && curr; curr = curr->Gmi_next) - if (curr->Gmi_identifier && !curr->Gmi_selected) - curr->Gmi_selected = TRUE; -} - -void -unset_all_on_page(start, page) -int start, page; -{ - Gem_menu_item *curr; - - if (start < 0 || page < 0) - return; - - for (curr = invent_list; start-- && curr; curr = curr->Gmi_next) - ; - for (; page-- && curr; curr = curr->Gmi_next) - if (curr->Gmi_identifier && curr->Gmi_selected) { - curr->Gmi_selected = FALSE; - curr->Gmi_count = -1L; - } -} - -void -invert_all_on_page(start, page, acc) -int start, page; -char acc; -{ - Gem_menu_item *curr; - - if (start < 0 || page < 0) - return; - - for (curr = invent_list; start-- && curr; curr = curr->Gmi_next) - ; - for (; page-- && curr; curr = curr->Gmi_next) - if (curr->Gmi_identifier && (acc == 0 || curr->Gmi_groupacc == acc)) { - if (curr->Gmi_selected) { - curr->Gmi_selected = FALSE; - curr->Gmi_count = -1L; - } else - curr->Gmi_selected = TRUE; - } -} - -/************************* Inv_Handler and Inv_Init - * *******************************/ - -int -scroll_top_dialog(char ch) -{ - WIN *w; - DIAINFO *dinf; - - if ((w = get_top_window()) && (dinf = (DIAINFO *) w->dialog) - && dinf->di_tree == zz_oblist[LINES]) { - switch (ch) { - case ' ': - if (scroll_menu.vpos == scroll_menu.vmax) { - send_return(); - break; - } - /* Fall thru */ - case MENU_NEXT_PAGE: - scroll_window(w, PAGE_DOWN, NULL); - break; - case MENU_PREVIOUS_PAGE: - scroll_window(w, PAGE_UP, NULL); - break; - case MENU_FIRST_PAGE: - scroll_window(w, WIN_START, NULL); - break; - case MENU_LAST_PAGE: - scroll_window(w, WIN_END, NULL); - break; - default: - return (FALSE); - } - return (TRUE); - } - return (FALSE); -} - -#define Text_Init KM_Init - -int -Text_Handler(xev) -XEVENT *xev; -{ - int ev = xev->ev_mwich; - - if (ev & MU_MESAG) { - int *buf = xev->ev_mmgpbuf, y_wo, i; - if (*buf == FONT_CHANGED) { - if (buf[3] >= 0) { - mar_set_fontbyid(NHW_TEXT, buf[4], buf[5]); - FontAck(buf[1], 1); - } - } - } - if (ev & MU_KEYBD) { - char ch = (char) (xev->ev_mkreturn & 0x00FF); - - if (!scroll_top_dialog(ch)) - switch (ch) { - case '\033': - send_return(); /* just closes the textwin */ - break; - case C('c'): - clipbrd_save(text_lines, Anz_text_lines, - xev->ev_mmokstate & K_SHIFT, FALSE); - break; - default: - ev &= ~MU_KEYBD; /* unknown key */ - break; - } - } - return (ev); -} - -#define Inv_Init KM_Init - -static long count = 0; -int -Inv_Handler(xev) -XEVENT *xev; -{ - int ev = xev->ev_mwich; - Gem_menu_item *it; - GRECT area; - OBJECT *z_ob = zz_oblist[LINES]; - - ob_pos(z_ob, LINESLIST, &area); - if (ev & MU_MESAG) { - int *buf = xev->ev_mmgpbuf, y_wo, i; - - if (*buf == FONT_CHANGED) { - if (buf[3] >= 0) { - mar_set_fontbyid(NHW_MENU, buf[4], buf[5]); - FontAck(buf[1], 1); - } - } else if (*buf == OBJC_CHANGED && buf[3] == LINESLIST) { - ob_undostate(z_ob, LINESLIST, SELECTED); - mouse(NULL, &y_wo); - y_wo = (y_wo - area.g_y) / menu_font.ch + scroll_menu.vpos; - for (it = invent_list, i = 0; i < y_wo && it; - it = it->Gmi_next, i++) - ; - if (it->Gmi_identifier) { - it->Gmi_selected = !it->Gmi_selected; - it->Gmi_count = count == 0L ? -1L : count; - count = 0L; - if (Inv_how != PICK_ANY) { - /*my_close_dialog(Inv_dialog,TRUE);*/ - send_return(); - } else { - area.g_x = (area.g_x + 23 + 2 * menu_font.cw) & ~7; - area.g_w = menu_font.cw; - area.g_h = menu_font.ch; - area.g_y += (y_wo - scroll_menu.vpos) * menu_font.ch; - ob_draw_chg(Inv_dialog, LINESLIST, &area, FAIL); - } /* how != PICK_ANY */ - } /* identifier */ - } else /* LINESLIST changed */ - ev &= ~MU_MESAG; /* unknown message not used */ - } /* MU_MESAG */ - - if (ev & MU_KEYBD) { - char ch = (char) (xev->ev_mkreturn & 0x00FF); - - if (!scroll_top_dialog(ch)) { - switch (ch) { - case '0': /* special 0 is also groupaccelerator for balls */ - if (count <= 0) - goto find_acc; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (Inv_how == PICK_NONE) - goto find_acc; - count = (count * 10L) + (long) (ch - '0'); - break; - case '\033': /* cancel - from counting or loop */ - if (count > 0L) - count = 0L; - else { - unset_all_on_page(0, (int) scroll_menu.vsize); - my_close_dialog(Inv_dialog, TRUE); - return (ev); - } - break; - case '\0': /* finished (commit) */ - case '\n': - case '\r': - break; - case MENU_SELECT_PAGE: - if (Inv_how == PICK_NONE) - goto find_acc; - if (Inv_how == PICK_ANY) - set_all_on_page((int) scroll_menu.vpos, - scroll_menu.vpage); - break; - case MENU_SELECT_ALL: - if (Inv_how == PICK_NONE) - goto find_acc; - if (Inv_how == PICK_ANY) - set_all_on_page(0, (int) scroll_menu.vsize); - break; - case MENU_UNSELECT_PAGE: - unset_all_on_page((int) scroll_menu.vpos, scroll_menu.vpage); - break; - case MENU_UNSELECT_ALL: - unset_all_on_page(0, (int) scroll_menu.vsize); - break; - case MENU_INVERT_PAGE: - if (Inv_how == PICK_NONE) - goto find_acc; - if (Inv_how == PICK_ANY) - invert_all_on_page((int) scroll_menu.vpos, - scroll_menu.vpage, 0); - break; - case MENU_INVERT_ALL: - if (Inv_how == PICK_NONE) - goto find_acc; - if (Inv_how == PICK_ANY) - invert_all_on_page(0, (int) scroll_menu.vsize, 0); - break; - case MENU_SEARCH: - if (Inv_how != PICK_NONE) { - char buf[BUFSZ]; - Gem_getlin("Search for:", buf); - if (!*buf || buf[0] == '\033') - break; - for (it = invent_list; it; it = it->Gmi_next) { - if (it->Gmi_identifier && strstr(it->Gmi_str, buf)) { - it->Gmi_selected = TRUE; - if (Inv_how != PICK_ANY) { - my_close_dialog(Inv_dialog, FALSE); - break; - } - } - } - } - break; - case C('c'): - clipbrd_save(invent_list, Anz_inv_lines, - xev->ev_mmokstate & K_SHIFT, TRUE); - break; - default: - find_acc: - if (Inv_how == PICK_NONE) - my_close_dialog(Inv_dialog, TRUE); - else - for (it = invent_list; it; it = it->Gmi_next) { - if (it->Gmi_identifier - && (it->Gmi_accelerator == ch - || it->Gmi_groupacc == ch)) { - it->Gmi_selected = !it->Gmi_selected; - it->Gmi_count = count == 0L ? -1L : count; - count = 0L; - if (Inv_how != PICK_ANY) - my_close_dialog(Inv_dialog, TRUE); - } - } - break; - } /* end switch(ch) */ - if (Inv_how == PICK_ANY) { - area.g_x = (area.g_x + 23 + 2 * menu_font.cw) & ~7; - area.g_w = menu_font.cw; - ob_draw_chg(Inv_dialog, LINESLIST, &area, FAIL); - } - } /* !scroll_Inv_dialog */ - } /* MU_KEYBD */ - - if (Inv_how == PICK_ANY) { - ob_set_text(Inv_dialog->di_tree, QLINE, strCancel); - for (it = invent_list; it; it = it->Gmi_next) - if (it->Gmi_identifier && it->Gmi_selected) { - ob_set_text(Inv_dialog->di_tree, QLINE, strOk); - break; - } - ob_draw_chg(Inv_dialog, QLINE, NULL, FAIL); - } - return (ev); -} - -/************************* draw_window *******************************/ - -static void -mar_draw_window(first, win, area) -int first; -WIN *win; -GRECT *area; -{ - OBJECT *obj = (OBJECT *) win->para; - - if (obj) { - if (first) { - obj->ob_x = win->work.g_x; - obj->ob_y = win->work.g_y; - } - if (area == NULL) - area = &(win->work); - objc_draw(obj, ROOT, MAX_DEPTH, area->g_x, area->g_y, area->g_w, - area->g_h); - } -} - -/************************* mar_display_nhwindow - * *******************************/ - -void -redraw_winwork(WIN *w, GRECT *area) -{ - area->g_x += w->work.g_x; - area->g_y += w->work.g_y; - redraw_window(w, area); -} -void -mar_menu_set_slider(WIN *p_win) -{ - if (p_win) { - SCROLL *sc = p_win->scroll; - - if (!sc) - return; - - if (p_win->gadgets & HSLIDE) { - long hsize = 1000l; - - if (sc->hsize > 0 && sc->hpage > 0) { - hsize *= sc->hpage; - hsize /= sc->hsize; - } - window_slider(p_win, HOR_SLIDER, 0, (int) hsize); - } - if (p_win->gadgets & VSLIDE) { - long vsize = 1000l; - - if (sc->vsize > 0 && sc->vpage > 0) { - vsize *= sc->vpage; - vsize /= sc->vsize; - } - window_slider(p_win, VERT_SLIDER, 0, (int) vsize); - } - } -} - -void -recalc_msg_win(GRECT *area) -{ - OBJECT *z_ob; - z_ob = zz_oblist[MSGWIN]; - z_ob[MSGLINES].ob_spec.userblk = &ub_msg; - z_ob[MSGLINES].ob_width = z_ob[ROOT].ob_width = - (msg_width + 3) * msg_font.cw; - z_ob[MSGLINES].ob_width -= z_ob[UPMSG].ob_width; - z_ob[ROOT].ob_height = z_ob[GRABMSGWIN].ob_height = - z_ob[MSGLINES].ob_height = msg_vis * msg_font.ch; - z_ob[DNMSG].ob_y = z_ob[GRABMSGWIN].ob_height - z_ob[DNMSG].ob_height; - window_border(0, 0, 0, z_ob->ob_width, z_ob->ob_height, area); -} -void -recalc_status_win(GRECT *area) -{ - OBJECT *z_ob; - z_ob = zz_oblist[STATUSLINE]; - z_ob[ROOT].ob_type = G_USERDEF; - z_ob[ROOT].ob_spec.userblk = &ub_status; - z_ob[ROOT].ob_width = (status_w + 2) * status_font.cw; - z_ob[ROOT].ob_height = z_ob[GRABSTATUS].ob_height = 2 * status_font.ch; - z_ob[GRABSTATUS].ob_width = 2 * status_font.cw - 2; - window_border(0, 0, 0, z_ob->ob_width, z_ob->ob_height, area); -} -void -calc_std_winplace(int which, GRECT *place) -{ - static int todo = TRUE; - static GRECT me, ma, st; - - if (todo || which < 0) { - OBJECT *z_ob; - int map_h_off, foo; - - /* First the messagewin */ - recalc_msg_win(&me); - - /* Now the map */ - wind_calc(WC_BORDER, MAP_GADGETS, 0, 0, - scroll_map.px_hline * (COLNO - 1), - scroll_map.px_vline * ROWNO, &foo, &foo, &foo, &map_h_off); - map_h_off -= scroll_map.px_vline * ROWNO; - window_border(MAP_GADGETS, 0, 0, scroll_map.px_hline * (COLNO - 1), - scroll_map.px_vline * ROWNO, &ma); - - /* Next the statuswin */ - recalc_status_win(&st); - - /* And last but not least a final test */ - ma.g_h = map_h_off + scroll_map.px_vline * ROWNO; - while (me.g_h + ma.g_h + st.g_h >= desk.g_h) - ma.g_h -= scroll_map.px_vline; - /* stack the windows */ - ma.g_y = me.g_y = st.g_y = desk.g_y; - if (status_align) { - ma.g_y += st.g_h; - if (msg_align) { - st.g_y += me.g_h; - ma.g_y += me.g_h; - } else { - me.g_y += st.g_h + ma.g_h; - } - } else { - if (msg_align) { - ma.g_y += me.g_h; - } else { - me.g_y += ma.g_h; - } - st.g_y += me.g_h + ma.g_h; - } - - if (which) - todo = FALSE; - } - switch (which) { - case NHW_MESSAGE: - *place = me; - break; - case NHW_MAP: - *place = ma; - break; - case NHW_STATUS: - *place = st; - break; - default: - break; - } -} - -void -mar_display_nhwindow(wind) -winid wind; -{ - DIAINFO *dlg_info; - OBJECT *z_ob; - int d_exit = W_ABANDON, i, breite, mar_di_mode, tmp_magx = magx; - GRECT g_mapmax, area; - char *tmp_button; - struct gw *p_Gw; - - if (wind == WIN_ERR) - return; - - p_Gw = &Gem_nhwindow[wind]; - switch (p_Gw->gw_type) { - case NHW_TEXT: - if (WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) - mar_display_nhwindow(WIN_MESSAGE); - z_ob = zz_oblist[LINES]; - scroll_menu.vsize = Anz_text_lines; - scroll_menu.vpos = 0; - if (use_rip) { - if (!depack_img(planes < 4 ? "RIP2.IMG" : "RIP.IMG", - &rip_image)) { - mfdb(&Rip_bild, (int *) rip_image.addr, rip_image.img_w, - rip_image.img_h, 1, rip_image.planes); - transform_img(&Rip_bild); - } - ub_lines.ub_code = draw_rip; - } else - ub_lines.ub_code = draw_lines; - z_ob[LINESLIST].ob_spec.userblk = &ub_lines; - breite = 16; - v_set_text(text_font.id, text_font.size, BLACK, 0, 0, NULL); - for (i = 0; i < Anz_text_lines; i++) { - int eout[8]; - vqt_extent(x_handle, text_lines[i], eout); - Max(&breite, eout[4]); - } - scroll_menu.px_vline = text_font.ch; - scroll_menu.px_hline = text_font.cw; - mar_di_mode = mar_set_inv_win(Anz_text_lines, breite); - tmp_button = ob_get_text(z_ob, QLINE, 0); - ob_set_text(z_ob, QLINE, strOk); - ob_undoflag(z_ob, LINESLIST, TOUCHEXIT); - Event_Handler(Text_Init, Text_Handler); - if ((dlg_info = open_dialog(z_ob, strText, NULL, NULL, - mar_ob_mapcenter(z_ob), FALSE, - mar_di_mode, FAIL, NULL, NULL)) != NULL) { - WIN *ptr_win = dlg_info->di_win; - - ptr_win->scroll = &scroll_menu; - mar_menu_set_slider(ptr_win); - WindowItems(ptr_win, SCROLL_KEYS, scroll_keys); - if ((d_exit = X_Form_Do(NULL)) != W_ABANDON) { - my_close_dialog(dlg_info, FALSE); - if (d_exit != W_CLOSED) - ob_undostate(z_ob, d_exit & NO_CLICK, SELECTED); - } - } - Event_Handler(NULL, NULL); - ob_set_text(z_ob, QLINE, tmp_button); - break; - case NHW_MENU: - if (WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) - mar_display_nhwindow(WIN_MESSAGE); - z_ob = zz_oblist[LINES]; - scroll_menu.vsize = Anz_inv_lines; - scroll_menu.vpos = 0; - z_ob[LINESLIST].ob_spec.userblk = &ub_inventory; - if ((Menu_title) - && (wind != WIN_INVEN)) /* because I sets no Menu_title */ - Max(&Inv_breite, gr_cw * strlen(Menu_title) + 16); - scroll_menu.px_vline = menu_font.ch; - scroll_menu.px_hline = menu_font.cw; - mar_di_mode = mar_set_inv_win(Anz_inv_lines, Inv_breite, NHW_MENU); - tmp_button = ob_get_text(z_ob, QLINE, 0); - ob_set_text(z_ob, QLINE, Inv_how != PICK_NONE ? strCancel : strOk); - ob_doflag(z_ob, LINESLIST, TOUCHEXIT); - Event_Handler(Inv_Init, Inv_Handler); - if ((Inv_dialog = - open_dialog(z_ob, (wind == WIN_INVEN) - ? "Inventory" - : (Menu_title ? Menu_title : "Staun"), - NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, - mar_di_mode, FAIL, NULL, NULL)) != NULL) { - WIN *ptr_win = Inv_dialog->di_win; - - ptr_win->scroll = &scroll_menu; - mar_menu_set_slider(ptr_win); - WindowItems(ptr_win, SCROLL_KEYS, scroll_keys); - do { - int y_wo, x_wo, ru_w = 1, ru_h = 1; - GRECT oarea; - Gem_menu_item *it; - d_exit = X_Form_Do(NULL); - if ((d_exit & NO_CLICK) == LINESLIST) { - ob_pos(z_ob, LINESLIST, &oarea); - if (mouse(&x_wo, &y_wo) && Inv_how == PICK_ANY) { - graf_rt_rubberbox(FALSE, x_wo, y_wo, FAIL, FAIL, - &oarea, &ru_w, &ru_h, NULL); - invert_all_on_page( - (int) ((y_wo - oarea.g_y) / menu_font.ch - + scroll_menu.vpos), - (ru_h + menu_font.ch - 1) / menu_font.ch, 0); - } else { - for (it = invent_list, i = 0; - i < ((y_wo - oarea.g_y) / menu_font.ch - + scroll_menu.vpos) - && it; - it = it->Gmi_next, i++) - ; - if (it && it->Gmi_identifier) { - it->Gmi_selected = !it->Gmi_selected; - it->Gmi_count = count == 0L ? -1L : count; - count = 0L; - if (Inv_how != PICK_ANY) - break; - } /* identifier */ - } - oarea.g_x = (oarea.g_x + 23 + 2 * menu_font.cw) & ~7; - oarea.g_y = y_wo - (y_wo - oarea.g_y) % menu_font.ch; - oarea.g_w = menu_font.cw; - oarea.g_h = ((ru_h + menu_font.ch - 1) / menu_font.ch) - * menu_font.ch; - ob_draw_chg(Inv_dialog, LINESLIST, &oarea, FAIL); - } - if (Inv_how == PICK_ANY) { - ob_set_text(Inv_dialog->di_tree, QLINE, strCancel); - for (it = invent_list; it; it = it->Gmi_next) - if (it->Gmi_identifier && it->Gmi_selected) { - ob_set_text(Inv_dialog->di_tree, QLINE, strOk); - break; - } - ob_draw_chg(Inv_dialog, QLINE, NULL, FAIL); - } - } while ((d_exit & NO_CLICK) == LINESLIST); - if (d_exit != W_ABANDON) { - my_close_dialog(Inv_dialog, FALSE); - if (d_exit != W_CLOSED) - ob_undostate(z_ob, d_exit & NO_CLICK, SELECTED); - } - } - Event_Handler(NULL, NULL); - ob_set_text(z_ob, QLINE, tmp_button); - break; - case NHW_MAP: - if (p_Gw->gw_window == NULL) { - calc_std_winplace(NHW_MAP, &p_Gw->gw_place); - window_border(MAP_GADGETS, 0, 0, Tile_width * (COLNO - 1), - Tile_heigth * ROWNO, &g_mapmax); - p_Gw->gw_window = open_window( - md, md, NULL, zz_oblist[NHICON], MAP_GADGETS, TRUE, 128, 128, - &g_mapmax, &p_Gw->gw_place, &scroll_map, win_draw_map, NULL, - XM_TOP | XM_BOTTOM | XM_SIZE); - WindowItems(p_Gw->gw_window, SCROLL_KEYS - 1, - scroll_keys); /* ClrHome centers on u */ - mar_clear_map(); - } - if (p_Gw->gw_dirty) { - area.g_x = p_Gw->gw_window->work.g_x - + scroll_map.px_hline - * (dirty_map_area.g_x - scroll_map.hpos); - area.g_y = p_Gw->gw_window->work.g_y - + scroll_map.px_vline - * (dirty_map_area.g_y - scroll_map.vpos); - area.g_w = (dirty_map_area.g_w - dirty_map_area.g_x + 1) - * scroll_map.px_hline; - area.g_h = (dirty_map_area.g_h - dirty_map_area.g_y + 1) - * scroll_map.px_vline; - - redraw_window(p_Gw->gw_window, &area); - - dirty_map_area.g_x = COLNO - 1; - dirty_map_area.g_y = ROWNO; - dirty_map_area.g_w = dirty_map_area.g_h = 0; - } - break; - case NHW_MESSAGE: - if (p_Gw->gw_window == NULL) { - calc_std_winplace(NHW_MESSAGE, &p_Gw->gw_place); - z_ob = zz_oblist[MSGWIN]; - magx = 0; /* MAR -- Fake E_GEM to remove Backdropper */ - p_Gw->gw_window = open_window( - NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, &p_Gw->gw_place, - NULL, mar_draw_window, z_ob, XM_TOP | XM_BOTTOM | XM_SIZE); - magx = tmp_magx; - window_size(p_Gw->gw_window, &p_Gw->gw_window->curr); - p_Gw->gw_dirty = TRUE; - } - - if (p_Gw->gw_dirty) { - ob_pos(zz_oblist[MSGWIN], MSGLINES, &area); - while (messages_pro_zug > 3) { - messages_pro_zug -= 3; - msg_pos += 3; - redraw_window(p_Gw->gw_window, &area); - mar_more(); - } - msg_pos += messages_pro_zug; - messages_pro_zug = 0; - if (msg_pos > msg_max) - msg_pos = msg_max; - redraw_window(p_Gw->gw_window, &area); - mar_message_pause = FALSE; - } - break; - case NHW_STATUS: - if (p_Gw->gw_window == NULL) { - z_ob = zz_oblist[STATUSLINE]; - calc_std_winplace(NHW_STATUS, &p_Gw->gw_place); - magx = 0; /* MAR -- Fake E_GEM to remove Backdropper */ - p_Gw->gw_window = open_window( - NULL, NULL, NULL, NULL, 0, FALSE, 0, 0, NULL, &p_Gw->gw_place, - NULL, mar_draw_window, z_ob, XM_TOP | XM_BOTTOM | XM_SIZE); - magx = tmp_magx; - /* Because 2*status_font.ch is smaller then e_gem expects the - * minimum win_height */ - p_Gw->gw_window->min_h = z_ob[ROOT].ob_height; - window_size(p_Gw->gw_window, &p_Gw->gw_place); - p_Gw->gw_dirty = TRUE; - add_dirty_rect(dr_stat, &p_Gw->gw_place); - } - while (get_dirty_rect(dr_stat, &area)) { - area.g_x = (area.g_x + p_Gw->gw_window->work.g_x - + 2 * status_font.cw + 6) & ~7; - area.g_y += p_Gw->gw_window->work.g_y; - redraw_window(p_Gw->gw_window, &area); - } - break; - default: - if (p_Gw->gw_dirty) - redraw_window(p_Gw->gw_window, NULL); - } - p_Gw->gw_dirty = FALSE; -} - -/************************* create_window *******************************/ - -int -mar_hol_win_type(window) -winid window; -{ - return (Gem_nhwindow[window].gw_type); -} - -winid -mar_create_window(type) -int type; -{ - winid newid; - static char name[] = "Gem"; - int i; - struct gw *p_Gw = &Gem_nhwindow[0]; - - for (newid = 0; p_Gw->gw_type && newid < MAXWIN; newid++, p_Gw++) - ; - - switch (type) { - case NHW_MESSAGE: - message_line = (char **) m_alloc(msg_anz * sizeof(char *)); - message_age = (int *) m_alloc(msg_anz * sizeof(int)); - for (i = 0; i < msg_anz; i++) { - message_age[i] = FALSE; - message_line[i] = (char *) m_alloc((MSGLEN + 1) * sizeof(char)); - *message_line[i] = 0; - } - dr_msg = new_dirty_rect(10); - if (!dr_msg) - panic("Memory allocation failure (dr_msg)"); - break; - case NHW_STATUS: - status_line = (char **) m_alloc(2 * sizeof(char *)); - for (i = 0; i < 2; i++) { - status_line[i] = (char *) m_alloc(status_w * sizeof(char)); - memset(status_line[i], 0, status_w); - } - dr_stat = new_dirty_rect(10); - if (!dr_stat) - panic("Memory allocation failure (dr_stat)"); - break; - case NHW_MAP: - map_glyphs = (char **) m_alloc((long) ROWNO * sizeof(char *)); - for (i = 0; i < ROWNO; i++) { - map_glyphs[i] = (char *) m_alloc((long) COLNO * sizeof(char)); - *map_glyphs[i] = map_glyphs[i][COLNO - 1] = 0; - } - dr_map = new_dirty_rect(10); - if (!dr_map) - panic("Memory allocation failure (dr_map)"); - - mar_clear_map(); - break; - case NHW_MENU: - case NHW_TEXT: /* They are no more treated as dialog */ - break; - default: - p_Gw->gw_window = open_window( - "Sonst", name, NULL, NULL, NAME | MOVER | CLOSER, 0, 0, 0, NULL, - &p_Gw->gw_place, NULL, NULL, NULL, XM_TOP | XM_BOTTOM | XM_SIZE); - break; - } - - p_Gw->gw_type = type; - - return (newid); -} - -void -mar_change_menu_2_text(win) -winid win; -{ - Gem_nhwindow[win].gw_type = NHW_TEXT; -} - -/************************* mar_clear_map *******************************/ - -void -mar_clear_map() -{ - int pla[8]; - int x, y; - - pla[0] = pla[1] = pla[4] = pla[5] = 0; - pla[2] = pla[6] = scroll_map.px_hline * (COLNO - 1) - 1; - pla[3] = pla[7] = scroll_map.px_vline * ROWNO - 1; - for (y = 0; y < ROWNO; y++) - for (x = 0; x < COLNO - 1; x++) - map_glyphs[y][x] = ' '; - vro_cpyfm(x_handle, ALL_BLACK, pla, &Tile_bilder, - &Map_bild); /* MAR -- 17.Mar 2002 Hmm, what if FontCol_Bild is - bigger? */ - if (WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window) - redraw_window(Gem_nhwindow[WIN_MAP].gw_window, NULL); -} - -/************************* destroy_window *******************************/ - -void -mar_destroy_nhwindow(window) -winid window; -{ - int i; - - switch (Gem_nhwindow[window].gw_type) { - case NHW_TEXT: - for (i = 0; i < Anz_text_lines; i++) - free(text_lines[i]); - null_free(text_lines); - Anz_text_lines = 0; - use_rip = FALSE; - break; - case NHW_MENU: - Gem_start_menu(window); /* delete invent_list */ - test_free(Menu_title); - break; - case 0: /* No window available, probably an error message? */ - break; - default: - close_window(Gem_nhwindow[window].gw_window, 0); - break; - } - Gem_nhwindow[window].gw_window = NULL; - Gem_nhwindow[window].gw_type = 0; - Gem_nhwindow[window].gw_dirty = FALSE; - - if (window == WIN_MAP) { - for (i = 0; i < ROWNO; i++) { - free(map_glyphs[i]); - } - null_free(map_glyphs); - WIN_MAP = WIN_ERR; - } - if (window == WIN_STATUS) { - for (i = 0; i < 2; i++) - free(status_line[i]); - null_free(status_line); - WIN_STATUS = WIN_ERR; - } - if (window == WIN_MESSAGE) { - for (i = 0; i < msg_anz; i++) - free(message_line[i]); - null_free(message_line); - null_free(message_age); - WIN_MESSAGE = WIN_ERR; - } - if (window == WIN_INVEN) - WIN_INVEN = WIN_ERR; -} - -/************************* nh_poskey *******************************/ - -void -mar_set_margin(int m) -{ - Max(&m, 0); - Min(&m, - min(ROWNO, COLNO)); /* MAR 16.Mar 2002 -- the larger the less sense */ - scroll_margin = m; -} -void -mar_cliparound() -{ - if (WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window) { - int breite = scroll_margin > 0 ? scroll_margin - : max(scroll_map.hpage / 4, 1), - hoehe = scroll_margin > 0 ? scroll_margin - : max(scroll_map.vpage / 4, 1), - adjust_needed; - adjust_needed = FALSE; - if ((map_cursx < scroll_map.hpos + breite) - || (map_cursx >= scroll_map.hpos + scroll_map.hpage - breite)) { - scroll_map.hpos = map_cursx - scroll_map.hpage / 2; - adjust_needed = TRUE; - } - if ((map_cursy < scroll_map.vpos + hoehe) - || (map_cursy >= scroll_map.vpos + scroll_map.vpage - hoehe)) { - scroll_map.vpos = map_cursy - scroll_map.vpage / 2; - adjust_needed = TRUE; - } - if (adjust_needed) - scroll_window(Gem_nhwindow[WIN_MAP].gw_window, WIN_SCROLL, NULL); - } -} - -void -mar_update_value() -{ - if (WIN_MESSAGE != WIN_ERR) { - mar_message_pause = FALSE; - mar_esc_pressed = FALSE; - mar_display_nhwindow(WIN_MESSAGE); - } - - if (WIN_MAP != WIN_ERR) - mar_cliparound(); - - if (WIN_STATUS != WIN_ERR) { - mar_check_hilight_status(); - mar_display_nhwindow(WIN_STATUS); - } -} - -int -Main_Init(xev, availiable) -XEVENT *xev; -int availiable; -{ - xev->ev_mb1mask = xev->ev_mb1state = 1; - xev->ev_mb1clicks = xev->ev_mb2clicks = xev->ev_mb2mask = - xev->ev_mb2state = 2; - return ((MU_KEYBD | MU_BUTTON1 | MU_BUTTON2 | MU_MESAG) & availiable); -} - -/* - * return a key, or 0, in which case a mouse button was pressed - * mouse events should be returned as character postitions in the map window. - */ -/*ARGSUSED*/ -int -mar_nh_poskey(x, y, mod) -int *x, *y, *mod; -{ - static XEVENT xev; - int retval, ev; - - xev.ev_mflags = Main_Init(&xev, 0xFFFF); - ev = Event_Multi(&xev); - - retval = FAIL; - - if (ev & MU_KEYBD) { - char ch = xev.ev_mkreturn & 0x00FF; - char scan = (xev.ev_mkreturn & 0xff00) >> 8; - int shift = xev.ev_mmokstate; - const struct pad *kpad; - - /* Translate keypad keys */ - if (iskeypad(scan)) { - kpad = mar_iflags_numpad() == 1 ? numpad : keypad; - if (shift & K_SHIFT) - ch = kpad[scan - KEYPADLO].shift; - else if (shift & K_CTRL) { - if (scan >= 0x67 && scan <= 0x6f && scan != 0x6b) { - send_key(kpad[scan - KEYPADLO].normal); - ch = 'g'; - } else { - ch = kpad[scan - KEYPADLO].cntrl; - } - } else - ch = kpad[scan - KEYPADLO].normal; - } - if (scan == SCANHOME) - mar_cliparound(); - else if (scan == SCANF1) - retval = 'h'; - else if (scan == SCANF2) { - mar_set_tile_mode(!mar_set_tile_mode(FAIL)); - retval = C('l'); /* trigger full-redraw */ - } else if (scan == SCANF3) { - draw_cursor = !draw_cursor; - mar_curs(map_cursx, map_cursy); - mar_display_nhwindow(WIN_MAP); - } else if (scan == SCANF4) { /* Font-Selector */ - if (!CallFontSelector(0, FAIL, FAIL, FAIL, FAIL)) { - xalert(1, 1, X_ICN_ALERT, NULL, SYS_MODAL, BUTTONS_RIGHT, - TRUE, "Hello", "Fontselector not available!", NULL); - } - } else if (!ch && shift & K_CTRL && scan == -57) { - /* MAR -- nothing ignore Ctrl-Alt-Clr/Home == MagiC's restore - * screen */ - } else { - if (!ch) - ch = (char) M(tolower(scan_2_ascii(xev.ev_mkreturn, shift))); - if (((int) ch) == -128) - ch = '\033'; - retval = ch; - } - } - - if (ev & MU_BUTTON1 || ev & MU_BUTTON2) { - int ex = xev.ev_mmox, ey = xev.ev_mmoy; - WIN *akt_win = window_find(ex, ey); - - if (WIN_MAP != WIN_ERR - && akt_win == Gem_nhwindow[WIN_MAP].gw_window) { - *x = max(min((ex - akt_win->work.g_x) / scroll_map.px_hline - + scroll_map.hpos, - COLNO - 1), - 0) + 1; - *y = max(min((ey - akt_win->work.g_y) / scroll_map.px_vline - + scroll_map.vpos, - ROWNO), - 0); - *mod = xev.ev_mmobutton; - retval = 0; - } else if (WIN_STATUS != WIN_ERR - && akt_win == Gem_nhwindow[WIN_STATUS].gw_window) { - move_win(akt_win); - } else if (WIN_MESSAGE != WIN_ERR - && akt_win == Gem_nhwindow[WIN_MESSAGE].gw_window) { - message_handler(ex, ey); - } - } - - if (ev & MU_MESAG) { - int *buf = xev.ev_mmgpbuf; - char *str; - OBJECT *z_ob = zz_oblist[MENU]; - - switch (*buf) { - case MN_SELECTED: - menu_tnormal(z_ob, buf[3], TRUE); /* unselect menu header */ - str = ob_get_text(z_ob, buf[4], 0); - str += strlen(str) - 2; - switch (*str) { - case ' ': /* just that command */ - retval = str[1]; - break; - case '\005': /* Alt command */ - case '\007': - retval = M(str[1]); - break; - case '^': /* Ctrl command */ - retval = C(str[1]); - break; - case 'f': /* Func Key */ - switch (str[1]) { - case '1': - retval = 'h'; - break; - case '2': - mar_set_tile_mode(!mar_set_tile_mode(FAIL)); - retval = C('l'); /* trigger full-redraw */ - break; - case '3': - draw_cursor = !draw_cursor; - mar_curs(map_cursx, map_cursy); - mar_display_nhwindow(WIN_MAP); - break; - default: - } - break; - default: - mar_about(); - break; - } - break; /* MN_SELECTED */ - case WM_CLOSED: - WindowHandler(W_ICONIFYALL, NULL, NULL); - break; - case AP_TERM: - retval = 'S'; - break; - case FONT_CHANGED: - if (buf[3] >= 0) { - if (buf[3] == Gem_nhwindow[WIN_MESSAGE].gw_window->handle) { - mar_set_fontbyid(NHW_MESSAGE, buf[4], buf[5]); - mar_display_nhwindow(WIN_MESSAGE); - } else if (buf[3] - == Gem_nhwindow[WIN_MAP].gw_window->handle) { - mar_set_fontbyid(NHW_MAP, buf[4], buf[5]); - mar_display_nhwindow(WIN_MAP); - } else if (buf[3] - == Gem_nhwindow[WIN_STATUS].gw_window->handle) { - mar_set_fontbyid(NHW_STATUS, buf[4], buf[5]); - mar_display_nhwindow(WIN_STATUS); - } - FontAck(buf[1], 1); - } - break; - default: - break; - } - } /* MU_MESAG */ - - if (retval == FAIL) - retval = mar_nh_poskey(x, y, mod); - - return (retval); -} - -int -Gem_nh_poskey(x, y, mod) -int *x, *y, *mod; -{ - mar_update_value(); - return (mar_nh_poskey(x, y, mod)); -} - -void -Gem_delay_output() -{ - Event_Timer(50, 0, FALSE); /* wait 50ms */ -} - -int -Gem_doprev_message() -{ - if (msg_pos > 2) { - msg_pos--; - if (WIN_MESSAGE != WIN_ERR) - Gem_nhwindow[WIN_MESSAGE].gw_dirty = TRUE; - mar_display_nhwindow(WIN_MESSAGE); - } - return (0); -} - -/************************* print_glyph *******************************/ - -int mar_set_rogue(int); - -int -mar_set_tile_mode(tiles) -int tiles; -{ - static int tile_mode = TRUE; - static GRECT prev; - WIN *z_w = WIN_MAP != WIN_ERR ? Gem_nhwindow[WIN_MAP].gw_window : NULL; - - if (tiles < 0) - return (tile_mode); - else if (!z_w) - tile_mode = tiles; - else if (tile_mode == tiles || (mar_set_rogue(FAIL) && tiles)) - return (FAIL); - else { - GRECT tmp; - - tile_mode = tiles; - scroll_map.px_hline = tiles ? Tile_width : map_font.cw; - scroll_map.px_vline = tiles ? Tile_heigth : map_font.ch; - window_border(MAP_GADGETS, 0, 0, scroll_map.px_hline * (COLNO - 1), - scroll_map.px_vline * ROWNO, &tmp); - z_w->max.g_w = tmp.g_w; - z_w->max.g_h = tmp.g_h; - if (tiles) - z_w->curr = prev; - else - prev = z_w->curr; - - window_reinit(z_w, md, md, NULL, FALSE, FALSE); - } - return (FAIL); -} - -int -mar_set_rogue(what) -int what; -{ - static int rogue = FALSE, prev_mode = TRUE; - - if (what < 0) - return (rogue); - if (what != rogue) { - rogue = what; - if (rogue) { - prev_mode = mar_set_tile_mode(FAIL); - mar_set_tile_mode(FALSE); - } else - mar_set_tile_mode(prev_mode); - } - return (FAIL); -} - -void -mar_add_pet_sign(window, x, y) -winid window; -int x, y; -{ - if (window != WIN_ERR && window == WIN_MAP) { - static int pla[8] = { 0, 0, 7, 7, 0, 0, 0, 0 }, - colindex[2] = { RED, WHITE }; - - pla[4] = pla[6] = scroll_map.px_hline * x; - pla[5] = pla[7] = scroll_map.px_vline * y; - pla[6] += 7; - pla[7] += 6; - vrt_cpyfm(x_handle, MD_TRANS, pla, &Pet_Mark, &Map_bild, colindex); - } -} - -void -mar_print_glyph(window, x, y, gl, bkgl) -winid window; -int x, y, gl, bkgl; -{ - if (window != WIN_ERR && window == WIN_MAP) { - static int pla[8]; - - pla[2] = pla[0] = (gl % Tiles_per_line) * Tile_width; - pla[3] = pla[1] = (gl / Tiles_per_line) * Tile_heigth; - pla[2] += Tile_width - 1; - pla[3] += Tile_heigth - 1; - pla[6] = pla[4] = Tile_width * x; /* x_wert to */ - pla[7] = pla[5] = Tile_heigth * y; /* y_wert to */ - pla[6] += Tile_width - 1; - pla[7] += Tile_heigth - 1; - - vro_cpyfm(x_handle, gl != -1 ? S_ONLY : ALL_BLACK, pla, &Tile_bilder, - &Map_bild); - } -} - -void -mar_print_char(window, x, y, ch, col) -winid window; -int x, y; -char ch; -int col; -{ - if (window != WIN_ERR && window == WIN_MAP) { - static int gem_color[16] = { 9, 2, 11, 10, 4, 7, 8, 15, - 0, 14, 3, 6, 5, 13, 15, 0 }; - int pla[8], colindex[2]; - - map_glyphs[y][x] = ch; - - pla[0] = pla[1] = 0; - pla[2] = map_font.cw - 1; - pla[3] = map_font.ch - 1; - pla[6] = pla[4] = map_font.cw * x; - pla[7] = pla[5] = map_font.ch * y; - pla[6] += map_font.cw - 1; - pla[7] += map_font.ch - 1; - colindex[0] = gem_color[col]; - colindex[1] = WHITE; - vrt_cpyfm(x_handle, MD_REPLACE, pla, &Black_bild, &FontCol_Bild, - colindex); - } -} - -/************************* getlin *******************************/ - -void -Gem_getlin(ques, input) -const char *ques; -char *input; -{ - OBJECT *z_ob = zz_oblist[LINEGET]; - int d_exit, length; - char *pr[2], *tmp; - - if (WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) - mar_display_nhwindow(WIN_MESSAGE); - - z_ob[LGPROMPT].ob_type = G_USERDEF; - z_ob[LGPROMPT].ob_spec.userblk = &ub_prompt; - z_ob[LGPROMPT].ob_height = 2 * gr_ch; - - length = z_ob[LGPROMPT].ob_width / gr_cw; - if (strlen(ques) > length) { - tmp = ques + length; - while (*tmp != ' ' && tmp >= ques) { - tmp--; - } - if (tmp <= ques) - tmp = ques + length; /* Mar -- Oops, what a word :-) */ - pr[0] = ques; - *tmp = 0; - pr[1] = ++tmp; - } else { - pr[0] = ques; - pr[1] = NULL; - } - ub_prompt.ub_parm = (long) pr; - - ob_clear_edit(z_ob); - d_exit = xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, - DIALOG_MODE); - Event_Timer(0, 0, TRUE); - - if (d_exit == W_CLOSED || d_exit == W_ABANDON - || (d_exit & NO_CLICK) == QLG) { - *input = '\033'; - input[1] = 0; - } else - strncpy(input, ob_get_text(z_ob, LGREPLY, 0), length); -} - -/************************* ask_direction *******************************/ - -#define Dia_Init K_Init - -int -Dia_Handler(xev) -XEVENT *xev; -{ - int ev = xev->ev_mwich; - char ch = (char) (xev->ev_mkreturn & 0x00FF); - - if (ev & MU_KEYBD) { - WIN *w; - DIAINFO *dinf; - - switch (ch) { - case 's': - send_key((int) (mar_iflags_numpad() ? '5' : '.')); - break; - case '.': - send_key('5'); /* MAR -- '.' is a button if numpad isn't set */ - break; - case '\033': /*ESC*/ - if ((w = get_top_window()) && (dinf = (DIAINFO *) w->dialog) - && dinf->di_tree == zz_oblist[DIRECTION]) { - my_close_dialog(dinf, FALSE); - break; - } - /* Fall thru */ - default: - ev &= ~MU_KEYBD; /* let the dialog handle it */ - break; - } - } - return (ev); -} - -int -mar_ask_direction() -{ - int d_exit; - OBJECT *z_ob = zz_oblist[DIRECTION]; - - Event_Handler(Dia_Init, Dia_Handler); - mar_set_dir_keys(); - d_exit = xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, - DIALOG_MODE); - Event_Timer(0, 0, TRUE); - Event_Handler(NULL, NULL); - - if (d_exit == W_CLOSED || d_exit == W_ABANDON) - return ('\033'); - if ((d_exit & NO_CLICK) == DIRDOWN) - return ('>'); - if ((d_exit & NO_CLICK) == DIRUP) - return ('<'); - if ((d_exit & NO_CLICK) == (DIR1 + 8)) /* 5 or . */ - return ('.'); - return (*ob_get_text(z_ob, d_exit & NO_CLICK, 0)); -} - -/************************* yn_function *******************************/ - -#define any_init M_Init - -static int -any_handler(xev) -XEVENT *xev; -{ - int ev = xev->ev_mwich; - - if (ev & MU_MESAG) { - int *buf = xev->ev_mmgpbuf; - - if (*buf == OBJC_EDITED) - my_close_dialog(*(DIAINFO **) &buf[4], FALSE); - else - ev &= ~MU_MESAG; - } - return (ev); -} - -int -send_yn_esc(char ch) -{ - static char esc_char = 0; - - if (ch < 0) { - if (esc_char) { - send_key((int) esc_char); - return (TRUE); - } - return (FALSE); - } else - esc_char = ch; - return (TRUE); -} - -#define single_init K_Init - -static int -single_handler(xev) -XEVENT *xev; -{ - int ev = xev->ev_mwich; - - if (ev & MU_KEYBD) { - char ch = (char) xev->ev_mkreturn & 0x00FF; - WIN *w; - DIAINFO *dinf; - - switch (ch) { - case ' ': - send_return(); - break; - case '\033': - if ((w = get_top_window()) && (dinf = (DIAINFO *) w->dialog) - && dinf->di_tree == zz_oblist[YNCHOICE]) { - if (!send_yn_esc(FAIL)) - my_close_dialog(dinf, FALSE); - break; - } - /* Fall thru */ - default: - ev &= ~MU_MESAG; - } - } - return (ev); -} - -char -Gem_yn_function(query, resp, def) -const char *query, *resp; -char def; -{ - OBJECT *z_ob = zz_oblist[YNCHOICE]; - int d_exit, i, len; - long anzahl; - char *tmp; - const char *ptr; - - if (WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) - mar_display_nhwindow(WIN_MESSAGE); - - /* if query for direction the special dialog */ - if (strstr(query, "irect")) - return (mar_ask_direction()); - - len = min(strlen(query), (max_w - 8 * gr_cw) / gr_cw); - z_ob[ROOT].ob_width = (len + 8) * gr_cw; - z_ob[YNPROMPT].ob_width = gr_cw * len + 8; - tmp = ob_get_text(z_ob, YNPROMPT, 0); - ob_set_text(z_ob, YNPROMPT, mar_copy_of(query)); - - if (resp) { /* single inputs */ - ob_hide(z_ob, SOMECHARS, FALSE); - ob_hide(z_ob, ANYCHAR, TRUE); - - if (strchr(resp, 'q')) - send_yn_esc('q'); - else if (strchr(resp, 'n')) - send_yn_esc('n'); - else - send_yn_esc( - def); /* strictly def should be returned, but in trad. I it's - 0 */ - - if (strchr(resp, '#')) { /* count possible */ - ob_hide(z_ob, YNOK, FALSE); - ob_hide(z_ob, COUNT, FALSE); - } else { /* no count */ - ob_hide(z_ob, YNOK, TRUE); - ob_hide(z_ob, COUNT, TRUE); - } - - if ((anzahl = (long) strchr(resp, '\033'))) { - anzahl -= (long) resp; - } else { - anzahl = strlen(resp); - } - for (i = 0, ptr = resp; i < 2 * anzahl; i += 2, ptr++) { - ob_hide(z_ob, YN1 + i, FALSE); - mar_change_button_char(z_ob, YN1 + i, *ptr); - ob_undoflag(z_ob, YN1 + i, DEFAULT); - if (*ptr == def) - ob_doflag(z_ob, YN1 + i, DEFAULT); - } - - z_ob[SOMECHARS].ob_width = z_ob[YN1 + i].ob_x + 8; - z_ob[SOMECHARS].ob_height = z_ob[YN1 + i].ob_y + gr_ch + gr_ch / 2; - Max((int *) &z_ob[ROOT].ob_width, - z_ob[SOMECHARS].ob_width + 4 * gr_cw); - z_ob[ROOT].ob_height = z_ob[SOMECHARS].ob_height + 4 * gr_ch; - if (strchr(resp, '#')) - z_ob[ROOT].ob_height = z_ob[YNOK].ob_y + 2 * gr_ch; - - for (i += YN1; i < (YNN + 1); i += 2) { - ob_hide(z_ob, i, TRUE); - } - Event_Handler(single_init, single_handler); - } else { /* any input */ - ob_hide(z_ob, SOMECHARS, TRUE); - ob_hide(z_ob, ANYCHAR, FALSE); - ob_hide(z_ob, YNOK, TRUE); - ob_hide(z_ob, COUNT, TRUE); - z_ob[ANYCHAR].ob_height = 2 * gr_ch; - z_ob[CHOSENCH].ob_y = z_ob[CHOSENCH + 1].ob_y = gr_ch / 2; - z_ob[ROOT].ob_width = - max(z_ob[YNPROMPT].ob_width + z_ob[YNPROMPT].ob_x, - z_ob[ANYCHAR].ob_width + z_ob[ANYCHAR].ob_x) + 2 * gr_cw; - z_ob[ROOT].ob_height = - z_ob[ANYCHAR].ob_height + z_ob[ANYCHAR].ob_y + gr_ch / 2; - *ob_get_text(z_ob, CHOSENCH, 0) = '?'; - Event_Handler(any_init, any_handler); - } - - d_exit = xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, - DIALOG_MODE); - Event_Timer(0, 0, TRUE); - Event_Handler(NULL, NULL); - /* display of count is missing (through the core too) */ - - free(ob_get_text(z_ob, YNPROMPT, 0)); - ob_set_text(z_ob, YNPROMPT, tmp); - - if (resp && (d_exit == W_CLOSED || d_exit == W_ABANDON)) - return ('\033'); - if ((d_exit & NO_CLICK) == YNOK) { - yn_number = atol(ob_get_text(z_ob, COUNT, 0)); - return ('#'); - } - if (!resp) - return (*ob_get_text(z_ob, CHOSENCH, 0)); - return (*ob_get_text(z_ob, d_exit & NO_CLICK, 0)); -} - -/* - * Allocate a copy of the given string. If null, return a string of - * zero length. - * - * This is an exact duplicate of copy_of() in X11/winmenu.c. - */ -static char * -mar_copy_of(s) -const char *s; -{ - if (!s) - s = nullstr; - return strcpy((char *) m_alloc((unsigned) (strlen(s) + 1)), s); -} - -const char *strRP = "raw_print", *strRPB = "raw_print_bold"; - -void -mar_raw_print(str) -const char *str; -{ - xalert(1, FAIL, X_ICN_INFO, NULL, APPL_MODAL, BUTTONS_CENTERED, TRUE, - strRP, str, NULL); -} - -void -mar_raw_print_bold(str) -const char *str; -{ - char buf[BUFSZ]; - - sprintf(buf, "!%s", str); - xalert(1, FAIL, X_ICN_INFO, NULL, APPL_MODAL, BUTTONS_CENTERED, TRUE, - strRPB, buf, NULL); -} - -/*wingem1.c*/ diff --git a/win/gem/xpm2img.c b/win/gem/xpm2img.c deleted file mode 100644 index fed4ac08f..000000000 --- a/win/gem/xpm2img.c +++ /dev/null @@ -1,184 +0,0 @@ -/* NetHack 3.6 xpm2img.c $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ -/* Copyright (c) Christian Bressler 2002 */ -/* NetHack may be freely redistributed. See license for details. */ -/* This is mainly a reworked tile2bmp.c + xpm2iff.c -- Marvin */ -#include -#include -#include -#include "bitmfile.h" -#define TRUE 1 -#define FALSE 0 -void get_color(unsigned int colind, struct RGB *rgb); -void get_pixel(int x, int y, unsigned int *colind); -char *xpmgetline(); -unsigned int **Bild_daten; -/* translation table from xpm characters to RGB and colormap slots */ -struct Ttable { - char flag; - struct RGB col; - int slot; /* output colortable index */ -} ttable[256]; -struct RGB *ColorMap; -int num_colors = 0; -int width = 0, height = 0; -int initflag; -FILE *fp; -int -main(argc, argv) -int argc; -char *argv[]; -{ - int i; - int row, col, planeno; - int farben, planes; - if (argc != 3) { - fprintf(stderr, "usage: tile2img infile.xpm outfile.img\n"); - exit(EXIT_FAILURE); - } - initflag = 0; - fp = fopen(argv[2], "wb"); - if (!fp) { - printf("Error creating IMG-file %s, aborting.\n", argv[2]); - exit(EXIT_FAILURE); - } - fclose(fp); - if (fopen_xpm_file(argv[1], "r") != TRUE) { - printf("Error reading xpm-file %s, aborting.\n", argv[1]); - exit(EXIT_FAILURE); - } - Bild_daten = - (unsigned int **) malloc((long) height * sizeof(unsigned int *)); - for (i = 0; i < height; i++) - Bild_daten[i] = - (unsigned int *) malloc((long) width * sizeof(unsigned int)); - for (row = 0; row < height; row++) { - char *xb = xpmgetline(); - int plane_offset; - if (xb == 0) { - printf("Error to few lines in xpm-file %s, aborting.\n", argv[1]); - exit(EXIT_FAILURE); - } - for (col = 0; col < width; col++) { - int color = xb[col]; - if (!ttable[color].flag) - fprintf(stderr, "Bad image data\n"); - Bild_daten[row][col] = ttable[color].slot; - } - } - if (num_colors > 256) { - fprintf(stderr, "ERROR: zuviele Farben\n"); - exit(EXIT_FAILURE); - } else if (num_colors > 16) { - farben = 256; - planes = 8; - } else if (num_colors > 2) { - farben = 16; - planes = 4; - } else { - farben = 2; - planes = 1; - } - bitmap_to_file(XIMG, width, height, 372, 372, planes, farben, argv[2], - get_color, get_pixel); - exit(EXIT_SUCCESS); - /*NOTREACHED*/ - return 0; -} -void -get_color(unsigned int colind, struct RGB *rgb) -{ - rgb->r = (1000L * (long) ColorMap[colind].r) / 0xFF; - rgb->g = (1000L * (long) ColorMap[colind].g) / 0xFF; - rgb->b = (1000L * (long) ColorMap[colind].b) / 0xFF; -} -void -get_pixel(int x, int y, unsigned int *colind) -{ - *colind = Bild_daten[y][x]; -} -FILE *xpmfh = 0; -char initbuf[200]; -char *xpmbuf = initbuf; -/* version 1. Reads the raw xpm file, NOT the compiled version. This is - * not a particularly good idea but I don't have time to do the right thing - * at this point, even if I was absolutely sure what that was. */ -fopen_xpm_file(const char *fn, const char *mode) -{ - int temp; - char *xb; - if (strcmp(mode, "r")) - return FALSE; /* no choice now */ - if (xpmfh) - return FALSE; /* one file at a time */ - xpmfh = fopen(fn, mode); - if (!xpmfh) - return FALSE; /* I'm hard to please */ - /* read the header */ - xb = xpmgetline(); - if (xb == 0) - return FALSE; - if (4 != sscanf(xb, "%d %d %d %d", &width, &height, &num_colors, &temp)) - return FALSE; /* bad header */ - /* replace the original buffer with one big enough for - * the real data - */ - /* XXX */ - xpmbuf = malloc(width * 2); - if (!xpmbuf) { - fprintf(stderr, "ERROR: Can't allocate line buffer\n"); - exit(1); - } - if (temp != 1) - return FALSE; /* limitation of this code */ - { - /* read the colormap and translation table */ - int ccount = -1; - ColorMap = - (struct RGB *) malloc((long) num_colors * sizeof(struct RGB)); - while (ccount++ < (num_colors - 1)) { - char index; - int r, g, b; - xb = xpmgetline(); - if (xb == 0) - return FALSE; - if (4 != sscanf(xb, "%c c #%2x%2x%2x", &index, &r, &g, &b)) { - fprintf(stderr, "Bad color entry: %s\n", xb); - return FALSE; - } - ttable[index].flag = 1; /* this color is valid */ - ttable[index].col.r = r; - ttable[index].col.g = g; - ttable[index].col.b = b; - ttable[index].slot = ccount; - ColorMap[ccount].r = r; - ColorMap[ccount].g = g; - ColorMap[ccount].b = b; - } - } - return TRUE; -} -/* This deserves better. Don't read it too closely - you'll get ill. */ -#define bufsz 2048 -char buf[bufsz]; -char * -xpmgetline() -{ - char *bp; - do { - if (fgets(buf, bufsz, xpmfh) == 0) - return 0; - } while (buf[0] != '"'); - /* strip off the trailing <",> if any */ - for (bp = buf; *bp; bp++) - ; - bp--; - while (isspace(*bp)) - bp--; - if (*bp == ',') - bp--; - if (*bp == '"') - bp--; - bp++; - *bp = '\0'; - return &buf[1]; -} diff --git a/win/gnome/.gitattributes b/win/gnome/.gitattributes deleted file mode 100644 index a1f2b4604..000000000 --- a/win/gnome/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* NH_filestag=(file%s_for_GNOME_versions_-_untested_for_3.6.6) diff --git a/win/gnome/README b/win/gnome/README deleted file mode 100644 index 3f7ec2017..000000000 --- a/win/gnome/README +++ /dev/null @@ -1,53 +0,0 @@ -This directory contains the windowing code written for GnomeHack. The NetHack -devteam is in the process of making it part of the normal distribution. -It should be noted that this is still work in progress and that there are -still problems with this code. So use at your own risk. Of course any -contributions, especially bug fixes, are more than welcome! - -These files are based on the files from GnomeHack 1.0.5 by Erik Andersen. -Some files have been renamed to fit into 8.3 name constraints (yuk!). -These are: - - GnomeHack.h gnomeprv.h - GnomeHackAskStringDialog.c gnaskstr.c - GnomeHackAskStringDialog.h gnaskstr.h - GnomeHackBind.c gnbind.c - GnomeHackBind.h gnbind.h - GnomeHackGlyph.c gnglyph.c - GnomeHackGlyph.h gnglyph.h - GnomeHackMainWindow.c gnmain.c - GnomeHackMainWindow.h gnmain.h - GnomeHackMapWindow.c gnmap.c - GnomeHackMapWindow.h gnmap.h - GnomeHackMenuWindow.c gnmenu.c - GnomeHackMenuWindow.h gnmenu.h - GnomeHackMessageWindow.c gnmesg.c - GnomeHackMessageWindow.h gnmesg.h - GnomeHackPlayerSelDialog.c gnplayer.c - GnomeHackPlayerSelDialog.h gnplayer.h - GnomeHackSettings.c gnopts.c - GnomeHackSettings.h gnopts.h - GnomeHackSignals.c gnsignal.c - GnomeHackSignals.h gnsignal.h - GnomeHackStatusWindow.c gnstatus.c - GnomeHackStatusWindow.h gnstatus.h - GnomeHackTextWindow.c gntext.c - GnomeHackTextWindow.h gntext.h - GnomeHackYesNoDialog.c gnyesno.c - GnomeHackYesNoDialog.h gnyesno.h - -Other files have been removed because we don't or can't use them (yet). - - Makefile.am - Makefile.in - gnomehack.desktop - gnomehack.desktop.in - -NetHack currently doesn't use autoconf, so the setup for that has not -made the translation. - -Note: All loss in style, elegance, and readability is entirely our fault -and not Erik's. - - - diff --git a/win/gnome/gnaskstr.c b/win/gnome/gnaskstr.c deleted file mode 100644 index be56ecea5..000000000 --- a/win/gnome/gnaskstr.c +++ /dev/null @@ -1,57 +0,0 @@ -/* NetHack 3.6 gnaskstr.c $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gnaskstr.h" -#include "gnmain.h" -#include - -static void -ghack_ask_string_callback(gchar *string, gpointer data) -{ - char **user_text = (char **) data; - - g_assert(user_text != NULL); - - *user_text = string; /* note - value must be g_free'd */ -} - -int -ghack_ask_string_dialog(const char *szMessageStr, const char *szDefaultStr, - const char *szTitleStr, char *buffer) -{ - int i; - GtkWidget *dialog; - gchar *user_text = NULL; - - dialog = - gnome_request_dialog(FALSE, szMessageStr, szDefaultStr, 0, - ghack_ask_string_callback, &user_text, NULL); - g_assert(dialog != NULL); - - gtk_window_set_title(GTK_WINDOW(dialog), szTitleStr); - - gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gnome_dialog_set_parent(GNOME_DIALOG(dialog), - GTK_WINDOW(ghack_get_main_window())); - - i = gnome_dialog_run_and_close(GNOME_DIALOG(dialog)); - - /* Quit */ - if (i != 0 || user_text == NULL) { - if (user_text) - g_free(user_text); - return -1; - } - - if (*user_text == 0) { - g_free(user_text); - return -1; - } - - g_assert(strlen(user_text) > 0); - strcpy(buffer, user_text); - g_free(user_text); - return 0; -} diff --git a/win/gnome/gnaskstr.h b/win/gnome/gnaskstr.h deleted file mode 100644 index 2fe57e78e..000000000 --- a/win/gnome/gnaskstr.h +++ /dev/null @@ -1,12 +0,0 @@ -/* NetHack 3.6 gnaskstr.h $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackAskStringDialog_h -#define GnomeHackAskStringDialog_h - -int ghack_ask_string_dialog(const char *szMessageStr, - const char *szDefaultStr, const char *szTitleStr, - char *buffer); - -#endif /* GnomeHackAskStringDialog_h */ diff --git a/win/gnome/gnbind.c b/win/gnome/gnbind.c deleted file mode 100644 index 53dee7232..000000000 --- a/win/gnome/gnbind.c +++ /dev/null @@ -1,1191 +0,0 @@ -/* NetHack 3.6 gnbind.c $NHDT-Date: 1450453305 2015/12/18 15:41:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.33 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -/* - * This file implements the interface between the window port specific - * code in the Gnome port and the rest of the nethack game engine. -*/ - -#include "gnbind.h" -#include "gnmain.h" -#include "gnmenu.h" -#include "gnaskstr.h" -#include "gnyesno.h" - -GNHWinData gnome_windowlist[MAXWINDOWS]; -winid WIN_WORN = WIN_ERR; - -extern void tty_raw_print(const char *); -extern void tty_raw_print_bold(const char *); - -/* Interface definition, for windows.c */ -struct window_procs Gnome_procs = { - "Gnome", WC_COLOR | WC_HILITE_PET | WC_INVERSE, 0L, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ - gnome_init_nhwindows, - gnome_player_selection, gnome_askname, gnome_get_nh_event, - gnome_exit_nhwindows, gnome_suspend_nhwindows, gnome_resume_nhwindows, - gnome_create_nhwindow, gnome_clear_nhwindow, gnome_display_nhwindow, - gnome_destroy_nhwindow, gnome_curs, gnome_putstr, genl_putmixed, - gnome_display_file, gnome_start_menu, gnome_add_menu, gnome_end_menu, - gnome_select_menu, - genl_message_menu, /* no need for X-specific handling */ - gnome_update_inventory, gnome_mark_synch, gnome_wait_synch, -#ifdef CLIPPING - gnome_cliparound, -#endif -#ifdef POSITIONBAR - donull, -#endif - gnome_print_glyph, gnome_raw_print, gnome_raw_print_bold, gnome_nhgetch, - gnome_nh_poskey, gnome_nhbell, gnome_doprev_message, gnome_yn_function, - gnome_getlin, gnome_get_ext_cmd, gnome_number_pad, gnome_delay_output, -#ifdef CHANGE_COLOR /* only a Mac option currently */ - donull, donull, -#endif - /* other defs that really should go away (they're tty specific) */ - gnome_start_screen, gnome_end_screen, gnome_outrip, - genl_preference_update, genl_getmsghistory, genl_putmsghistory, - genl_status_init, genl_status_finish, genl_status_enablefield, - genl_status_update, - genl_can_suspend_yes, -}; - -/* -init_nhwindows(int* argcp, char** argv) - -- Initialize the windows used by NetHack. This can also - create the standard windows listed at the top, but does - not display them. - -- Any commandline arguments relevant to the windowport - should be interpreted, and *argcp and *argv should - be changed to remove those arguments. - -- When the message window is created, the variable - iflags.window_inited needs to be set to TRUE. Otherwise - all plines() will be done via raw_print(). - ** Why not have init_nhwindows() create all of the "standard" - ** windows? Or at least all but WIN_INFO? -dean -*/ -void -gnome_init_nhwindows(int *argc, char **argv) -{ - /* Main window */ - ghack_init_main_window(*argc, argv); - ghack_init_signals(); - -#ifdef HACKDIR - // if (ghack_init_glyphs(HACKDIR "/t32-1024.xpm")) - if (ghack_init_glyphs(HACKDIR "/x11tiles")) - g_error("ERROR: Could not initialize glyphs.\n"); -#else -#error HACKDIR is not defined! -#endif - - // gnome/gtk is not reentrant - set_option_mod_status("ignintr", DISP_IN_GAME); - flags.ignintr = TRUE; - - iflags.window_inited = TRUE; - - /* gnome-specific window creation */ - WIN_WORN = gnome_create_nhwindow(NHW_WORN); -} - -/* Do a window-port specific player type selection. If player_selection() - offers a Quit option, it is its responsibility to clean up and terminate - the process. You need to fill in pl_character[0]. -*/ -void -gnome_player_selection() -{ - int n, i, sel; - const char **choices; - int *pickmap; - - /* prevent an unnecessary prompt */ - rigid_role_checks(); - - if (!flags.randomall && flags.initrole < 0) { - /* select a role */ - for (n = 0; roles[n].name.m; n++) - continue; - choices = (const char **) alloc(sizeof(char *) * (n + 1)); - pickmap = (int *) alloc(sizeof(int) * (n + 1)); - for (;;) { - for (n = 0, i = 0; roles[i].name.m; i++) { - if (ok_role(i, flags.initrace, flags.initgend, - flags.initalign)) { - if (flags.initgend >= 0 && flags.female - && roles[i].name.f) - choices[n] = roles[i].name.f; - else - choices[n] = roles[i].name.m; - pickmap[n++] = i; - } - } - if (n > 0) - break; - else if (flags.initalign >= 0) - flags.initalign = -1; /* reset */ - else if (flags.initgend >= 0) - flags.initgend = -1; - else if (flags.initrace >= 0) - flags.initrace = -1; - else - panic("no available ROLE+race+gender+alignment combinations"); - } - choices[n] = (const char *) 0; - if (n > 1) - sel = ghack_player_sel_dialog( - choices, _("Player selection"), - _("Choose one of the following roles:")); - else - sel = 0; - if (sel >= 0) - sel = pickmap[sel]; - else if (sel == ROLE_NONE) { /* Quit */ - clearlocks(); - gtk_exit(0); - } - free(choices); - free(pickmap); - } else if (flags.initrole < 0) - sel = ROLE_RANDOM; - else - sel = flags.initrole; - - if (sel == ROLE_RANDOM) { /* Random role */ - sel = pick_role(flags.initrace, flags.initgend, flags.initalign, - PICK_RANDOM); - if (sel < 0) - sel = randrole(FALSE); - } - - flags.initrole = sel; - - /* Select a race, if necessary */ - /* force compatibility with role, try for compatibility with - * pre-selected gender/alignment */ - if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { - if (flags.initrace == ROLE_RANDOM || flags.randomall) { - flags.initrace = pick_race(flags.initrole, flags.initgend, - flags.initalign, PICK_RANDOM); - if (flags.initrace < 0) - flags.initrace = randrace(flags.initrole); - } else { - /* Count the number of valid races */ - n = 0; /* number valid */ - for (i = 0; races[i].noun; i++) { - if (ok_race(flags.initrole, i, flags.initgend, - flags.initalign)) - n++; - } - if (n == 0) { - for (i = 0; races[i].noun; i++) { - if (validrace(flags.initrole, i)) - n++; - } - } - - choices = (const char **) alloc(sizeof(char *) * (n + 1)); - pickmap = (int *) alloc(sizeof(int) * (n + 1)); - for (n = 0, i = 0; races[i].noun; i++) { - if (ok_race(flags.initrole, i, flags.initgend, - flags.initalign)) { - choices[n] = races[i].noun; - pickmap[n++] = i; - } - } - choices[n] = (const char *) 0; - /* Permit the user to pick, if there is more than one */ - if (n > 1) - sel = ghack_player_sel_dialog( - choices, _("Race selection"), - _("Choose one of the following races:")); - else - sel = 0; - if (sel >= 0) - sel = pickmap[sel]; - else if (sel == ROLE_NONE) { /* Quit */ - clearlocks(); - gtk_exit(0); - } - flags.initrace = sel; - free(choices); - free(pickmap); - } - if (flags.initrace == ROLE_RANDOM) { /* Random role */ - sel = pick_race(flags.initrole, flags.initgend, flags.initalign, - PICK_RANDOM); - if (sel < 0) - sel = randrace(flags.initrole); - flags.initrace = sel; - } - } - - /* Select a gender, if necessary */ - /* force compatibility with role/race, try for compatibility with - * pre-selected alignment */ - if (flags.initgend < 0 - || !validgend(flags.initrole, flags.initrace, flags.initgend)) { - if (flags.initgend == ROLE_RANDOM || flags.randomall) { - flags.initgend = pick_gend(flags.initrole, flags.initrace, - flags.initalign, PICK_RANDOM); - if (flags.initgend < 0) - flags.initgend = randgend(flags.initrole, flags.initrace); - } else { - /* Count the number of valid genders */ - n = 0; /* number valid */ - for (i = 0; i < ROLE_GENDERS; i++) { - if (ok_gend(flags.initrole, flags.initrace, i, - flags.initalign)) - n++; - } - if (n == 0) { - for (i = 0; i < ROLE_GENDERS; i++) { - if (validgend(flags.initrole, flags.initrace, i)) - n++; - } - } - - choices = (const char **) alloc(sizeof(char *) * (n + 1)); - pickmap = (int *) alloc(sizeof(int) * (n + 1)); - for (n = 0, i = 0; i < ROLE_GENDERS; i++) { - if (ok_gend(flags.initrole, flags.initrace, i, - flags.initalign)) { - choices[n] = genders[i].adj; - pickmap[n++] = i; - } - } - choices[n] = (const char *) 0; - /* Permit the user to pick, if there is more than one */ - if (n > 1) - sel = ghack_player_sel_dialog( - choices, _("Gender selection"), - _("Choose one of the following genders:")); - else - sel = 0; - if (sel >= 0) - sel = pickmap[sel]; - else if (sel == ROLE_NONE) { /* Quit */ - clearlocks(); - gtk_exit(0); - } - flags.initgend = sel; - free(choices); - free(pickmap); - } - if (flags.initgend == ROLE_RANDOM) { /* Random gender */ - sel = pick_gend(flags.initrole, flags.initrace, flags.initalign, - PICK_RANDOM); - if (sel < 0) - sel = randgend(flags.initrole, flags.initrace); - flags.initgend = sel; - } - } - - /* Select an alignment, if necessary */ - /* force compatibility with role/race/gender */ - if (flags.initalign < 0 - || !validalign(flags.initrole, flags.initrace, flags.initalign)) { - if (flags.initalign == ROLE_RANDOM || flags.randomall) { - flags.initalign = pick_align(flags.initrole, flags.initrace, - flags.initgend, PICK_RANDOM); - if (flags.initalign < 0) - flags.initalign = randalign(flags.initrole, flags.initrace); - } else { - /* Count the number of valid alignments */ - n = 0; /* number valid */ - for (i = 0; i < ROLE_ALIGNS; i++) { - if (ok_align(flags.initrole, flags.initrace, flags.initgend, - i)) - n++; - } - if (n == 0) { - for (i = 0; i < ROLE_ALIGNS; i++) - if (validalign(flags.initrole, flags.initrace, i)) - n++; - } - - choices = (const char **) alloc(sizeof(char *) * (n + 1)); - pickmap = (int *) alloc(sizeof(int) * (n + 1)); - for (n = 0, i = 0; i < ROLE_ALIGNS; i++) { - if (ok_align(flags.initrole, flags.initrace, flags.initgend, - i)) { - choices[n] = aligns[i].adj; - pickmap[n++] = i; - } - } - choices[n] = (const char *) 0; - /* Permit the user to pick, if there is more than one */ - if (n > 1) - sel = ghack_player_sel_dialog( - choices, _("Alignment selection"), - _("Choose one of the following alignments:")); - else - sel = 0; - if (sel >= 0) - sel = pickmap[sel]; - else if (sel == ROLE_NONE) { /* Quit */ - clearlocks(); - gtk_exit(0); - } - flags.initalign = sel; - free(choices); - free(pickmap); - } - if (flags.initalign == ROLE_RANDOM) { - sel = pick_align(flags.initrole, flags.initrace, flags.initgend, - PICK_RANDOM); - if (sel < 0) - sel = randalign(flags.initrole, flags.initrace); - flags.initalign = sel; - } - } -} - -/* Ask the user for a player name. */ -void -gnome_askname() -{ - int ret; - - g_message("Asking name...."); - - /* Ask for a name and stuff the response into plname, a nethack global */ - ret = ghack_ask_string_dialog("What is your name?", "gandalf", - "GnomeHack", plname); - - /* Quit if they want to quit... */ - if (ret == -1) { - clearlocks(); - gtk_exit(0); - } -} - -/* Does window event processing (e.g. exposure events). - A noop for the tty and X window-ports. -*/ -void -gnome_get_nh_event() -{ - /* We handle our own events. */ - return; -} - -/* Exits the window system. This should dismiss all windows, - except the "window" used for raw_print(). str is printed if possible. -*/ -void -gnome_exit_nhwindows(const char *str) -{ - /* gtk cannot do this without exiting the program, do nothing */ -} - -/* Prepare the window to be suspended. */ -void -gnome_suspend_nhwindows(const char *str) -{ - /* I don't think we need to do anything here... */ - return; -} - -/* Restore the windows after being suspended. */ -void -gnome_resume_nhwindows() -{ - /* Do Nothing. Un-necessary since the GUI will refresh itself. */ - return; -} - -/* Create a window of type "type" which can be - NHW_MESSAGE (top line) - NHW_STATUS (bottom lines) - NHW_MAP (main dungeon) - NHW_MENU (inventory or other "corner" windows) - NHW_TEXT (help/text, full screen paged window) -*/ -winid -gnome_create_nhwindow(int type) -{ - winid i = 0; - - /* Return the next available winid */ - - for (i = 0; i < MAXWINDOWS; i++) - if (gnome_windowlist[i].win == NULL) - break; - if (i == MAXWINDOWS) - g_error("ERROR: No windows available...\n"); - gnome_create_nhwindow_by_id(type, i); - return i; -} - -void -gnome_create_nhwindow_by_id(int type, winid i) -{ - switch (type) { - case NHW_MAP: { - gnome_windowlist[i].win = ghack_init_map_window(); - gnome_windowlist[i].type = NHW_MAP; - ghack_main_window_add_map_window(gnome_windowlist[i].win); - break; - } - case NHW_MESSAGE: { - gnome_windowlist[i].win = ghack_init_message_window(); - gnome_windowlist[i].type = NHW_MESSAGE; - ghack_main_window_add_message_window(gnome_windowlist[i].win); - break; - } - case NHW_STATUS: { - gnome_windowlist[i].win = ghack_init_status_window(); - gnome_windowlist[i].type = NHW_STATUS; - ghack_main_window_add_status_window(gnome_windowlist[i].win); - break; - } - case NHW_WORN: { - gnome_windowlist[i].win = ghack_init_worn_window(); - gnome_windowlist[i].type = NHW_WORN; - ghack_main_window_add_worn_window(gnome_windowlist[i].win); - break; - } - case NHW_MENU: { - gnome_windowlist[i].type = NHW_MENU; - gnome_windowlist[i].win = ghack_init_menu_window(); - break; - } - case NHW_TEXT: { - gnome_windowlist[i].win = ghack_init_text_window(); - gnome_windowlist[i].type = NHW_TEXT; - break; - } - } -} - -/* This widget is being destroyed before its time-- - * clear its entry from the windowlist. -*/ -void -gnome_delete_nhwindow_by_reference(GtkWidget *menuWin) -{ - int i; - - for (i = 0; i < MAXWINDOWS; i++) { - if (gnome_windowlist[i].win == menuWin) { - gnome_windowlist[i].win = NULL; - gnome_windowlist[i].type = 0; - break; - } - } -} - -/* Clear the given window, when asked to. */ -void -gnome_clear_nhwindow(winid wid) -{ - if (gnome_windowlist[wid].win != NULL) { - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), - ghack_signals[GHSIG_CLEAR]); - } -} - -/* -- Display the window on the screen. If there is data - pending for output in that window, it should be sent. - If blocking is TRUE, display_nhwindow() will not - return until the data has been displayed on the screen, - and acknowledged by the user where appropriate. - -- All calls are blocking in the tty window-port. - -- Calling display_nhwindow(WIN_MESSAGE,???) will do a - --more--, if necessary, in the tty window-port. -*/ -void -gnome_display_nhwindow(winid wid, BOOLEAN_P block) -{ - if (gnome_windowlist[wid].win != NULL) { - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), - ghack_signals[GHSIG_DISPLAY], block); - if (block && (gnome_windowlist[wid].type == NHW_MAP)) - (void) gnome_nhgetch(); - } -} - -/* Destroy will dismiss the window if the window has not - * already been dismissed. -*/ -void -gnome_destroy_nhwindow(winid wid) -{ - if ((wid == WIN_MAP) || (wid == WIN_MESSAGE) || (wid == WIN_STATUS)) { - /* no thanks, I'll do these myself */ - return; - } - if (wid != -1 && gnome_windowlist[wid].win != NULL) { - gtk_widget_destroy(gnome_windowlist[wid].win); - gnome_windowlist[wid].win = NULL; - gnome_windowlist[wid].type = 0; - } -} - -/* Next output to window will start at (x,y), also moves - displayable cursor to (x,y). For backward compatibility, - 1 <= x < cols, 0 <= y < rows, where cols and rows are - the size of window. -*/ -void -gnome_curs(winid wid, int x, int y) -{ - if (wid != -1 && gnome_windowlist[wid].win != NULL) { - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), - ghack_signals[GHSIG_CURS], x, y); - } -} - -/* -putstr(window, attr, str) - -- Print str on the window with the given attribute. Only - printable ASCII characters (040-0126) must be supported. - Multiple putstr()s are output on separate lines. -Attributes - can be one of - ATR_NONE (or 0) - ATR_ULINE - ATR_BOLD - ATR_BLINK - ATR_INVERSE - If a window-port does not support all of these, it may map - unsupported attributes to a supported one (e.g. map them - all to ATR_INVERSE). putstr() may compress spaces out of - str, break str, or truncate str, if necessary for the - display. Where putstr() breaks a line, it has to clear - to end-of-line. - -- putstr should be implemented such that if two putstr()s - are done consecutively the user will see the first and - then the second. In the tty port, pline() achieves this - by calling more() or displaying both on the same line. -*/ -void -gnome_putstr(winid wid, int attr, const char *text) -{ - if ((wid >= 0) && (wid < MAXWINDOWS) - && (gnome_windowlist[wid].win != NULL)) { - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), - ghack_signals[GHSIG_PUTSTR], (guint) attr, text); - } -} - -/* Display the file named str. Complain about missing files - iff complain is TRUE. -*/ -void -gnome_display_file(const char *filename, BOOLEAN_P must_exist) -{ - /* Strange -- for some reason it makes us create a new text window - * instead of reusing any existing ones -- perhaps we can work out - * some way to reuse stuff -- but for now just make and destroy new - * ones each time */ - - dlb *f; - - f = dlb_fopen(filename, "r"); - if (!f) { - if (must_exist) { - GtkWidget *box; - char message[90]; - sprintf(message, "Warning! Could not find file: %s\n", filename); - - box = gnome_message_box_new(_(message), GNOME_MESSAGE_BOX_ERROR, - GNOME_STOCK_BUTTON_OK, NULL); - gnome_dialog_set_default(GNOME_DIALOG(box), 0); - gnome_dialog_set_parent(GNOME_DIALOG(box), - GTK_WINDOW(ghack_get_main_window())); - gtk_window_set_modal(GTK_WINDOW(box), TRUE); - gtk_widget_show(box); - } - } else { - GtkWidget *txtwin, *gless, *frametxt; -#define LLEN 128 - char line[LLEN], *textlines; - int num_lines, charcount; - - txtwin = gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK, NULL); - gtk_widget_set_usize(GTK_WIDGET(txtwin), 500, 400); - gtk_window_set_policy(GTK_WINDOW(txtwin), TRUE, TRUE, FALSE); - gtk_window_set_title(GTK_WINDOW(txtwin), "Text Window"); - gnome_dialog_set_default(GNOME_DIALOG(txtwin), 0); - gtk_window_set_modal(GTK_WINDOW(txtwin), TRUE); - frametxt = gtk_frame_new(""); - gtk_widget_show(frametxt); - - /* - * Count the number of lines and characters in the file. - */ - num_lines = 0; - charcount = 1; - while (dlb_fgets(line, LLEN, f)) { - num_lines++; - charcount += strlen(line); - } - (void) dlb_fclose(f); - - /* Ignore empty files */ - if (num_lines == 0) - return; - - /* - * Re-open the file and read the data into a buffer. - */ - textlines = (char *) alloc((unsigned int) charcount); - textlines[0] = '\0'; - f = dlb_fopen(filename, RDTMODE); - - while (dlb_fgets(line, LLEN, f)) { - (void) strcat(textlines, line); - } - (void) dlb_fclose(f); - - gless = gnome_less_new(); - gnome_less_show_string(GNOME_LESS(gless), textlines); - gtk_container_add(GTK_CONTAINER(frametxt), gless); - gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(txtwin)->vbox), frametxt, - TRUE, TRUE, 0); - gtk_widget_show_all(txtwin); - gtk_window_set_modal(GTK_WINDOW(txtwin), TRUE); - gnome_dialog_set_parent(GNOME_DIALOG(txtwin), - GTK_WINDOW(ghack_get_main_window())); - gnome_dialog_run_and_close(GNOME_DIALOG(txtwin)); - free(textlines); - } -} - -/* Start using window as a menu. You must call start_menu() - before add_menu(). After calling start_menu() you may not - putstr() to the window. Only windows of type NHW_MENU may - be used for menus. -*/ -void -gnome_start_menu(winid wid) -{ - if (wid != -1) { - if (gnome_windowlist[wid].win == NULL - && gnome_windowlist[wid].type != 0) { - gnome_create_nhwindow_by_id(gnome_windowlist[wid].type, wid); - } - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), - ghack_signals[GHSIG_START_MENU]); - } -} - -/* -add_menu(windid window, int glyph, const anything identifier, - char accelerator, char groupacc, - int attr, char *str, boolean preselected) - -- Add a text line str to the given menu window. If -identifier - is 0, then the line cannot be selected (e.g. a title). - Otherwise, identifier is the value returned if the line is - selected. Accelerator is a keyboard key that can be used - to select the line. If the accelerator of a selectable - item is 0, the window system is free to select its own - accelerator. It is up to the window-port to make the - accelerator visible to the user (e.g. put "a - " in front - of str). The value attr is the same as in putstr(). - Glyph is an optional glyph to accompany the line. If - window port cannot or does not want to display it, this - is OK. If there is no glyph applicable, then this - value will be NO_GLYPH. - -- All accelerators should be in the range [A-Za-z]. - -- It is expected that callers do not mix accelerator - choices. Either all selectable items have an accelerator - or let the window system pick them. Don't do both. - -- Groupacc is a group accelerator. It may be any character - outside of the standard accelerator (see above) or a - number. If 0, the item is unaffected by any group - accelerator. If this accelerator conflicts with - the menu command (or their user defined aliases), it loses. - The menu commands and aliases take care not to interfere - with the default object class symbols. - -- If you want this choice to be preselected when the - menu is displayed, set preselected to TRUE. -*/ -void -gnome_add_menu(winid wid, int glyph, const ANY_P *identifier, - CHAR_P accelerator, CHAR_P group_accel, int attr, - const char *str, BOOLEAN_P presel) -{ - GHackMenuItem item; - item.glyph = glyph; - item.identifier = identifier; - item.accelerator = accelerator; - item.group_accel = group_accel; - item.attr = attr; - item.str = str; - item.presel = presel; - - if (wid != -1 && gnome_windowlist[wid].win != NULL) { - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), - ghack_signals[GHSIG_ADD_MENU], &item); - } -} - -/* -end_menu(window, prompt) - -- Stop adding entries to the menu and flushes the window - to the screen (brings to front?). Prompt is a prompt - to give the user. If prompt is NULL, no prompt will - be printed. - ** This probably shouldn't flush the window any more (if - ** it ever did). That should be select_menu's job. -dean -*/ -void -gnome_end_menu(winid wid, const char *prompt) -{ - if (wid != -1 && gnome_windowlist[wid].win != NULL) { - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), - ghack_signals[GHSIG_END_MENU], prompt); - } -} - -/* -int select_menu(windid window, int how, menu_item **selected) - -- Return the number of items selected; 0 if none were chosen, - -1 when explicitly cancelled. If items were selected, then - selected is filled in with an allocated array of menu_item - structures, one for each selected line. The caller must - free this array when done with it. The "count" field - of selected is a user supplied count. If the user did - not supply a count, then the count field is filled with - -1 (meaning all). A count of zero is equivalent to not - being selected and should not be in the list. If no items - were selected, then selected is NULL'ed out. How is the - mode of the menu. Three valid values are PICK_NONE, - PICK_ONE, and PICK_N, meaning: nothing is selectable, - only one thing is selectable, and any number valid items - may selected. If how is PICK_NONE, this function should - never return anything but 0 or -1. - -- You may call select_menu() on a window multiple times -- - the menu is saved until start_menu() or destroy_nhwindow() - is called on the window. - -- Note that NHW_MENU windows need not have select_menu() - called for them. There is no way of knowing whether - select_menu() will be called for the window at - create_nhwindow() time. -*/ -int -gnome_select_menu(winid wid, int how, MENU_ITEM_P **selected) -{ - int nReturned = -1; - - if (wid != -1 && gnome_windowlist[wid].win != NULL - && gnome_windowlist[wid].type == NHW_MENU) { - nReturned = ghack_menu_window_select_menu(gnome_windowlist[wid].win, - selected, how); - } - - return nReturned; -} - -/* - -- Indicate to the window port that the inventory has been changed. - -- Merely calls display_inventory() for window-ports that leave the - window up, otherwise empty. -*/ -void -gnome_update_inventory() -{ - ghack_main_window_update_inventory(); -} - -/* -mark_synch() -- Don't go beyond this point in I/O on any channel until - all channels are caught up to here. Can be an empty call - for the moment -*/ -void -gnome_mark_synch() -{ - /* Do nothing */ -} - -/* -wait_synch() -- Wait until all pending output is complete (*flush*() for - streams goes here). - -- May also deal with exposure events etc. so that the - display is OK when return from wait_synch(). -*/ -void -gnome_wait_synch() -{ - /* Do nothing */ -} - -/* -cliparound(x, y)-- Make sure that the user is more-or-less centered on the - screen if the playing area is larger than the screen. - -- This function is only defined if CLIPPING is defined. -*/ -void -gnome_cliparound(int x, int y) -{ - /* FIXME!!! winid should be a parameter!!! - * Call a function that Does The Right Thing(tm). - */ - gnome_cliparound_proper(WIN_MAP, x, y); -} - -void -gnome_cliparound_proper(winid wid, int x, int y) -{ - if (wid != -1 && gnome_windowlist[wid].win != NULL) { - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), - ghack_signals[GHSIG_CLIPAROUND], (guint) x, - (guint) y); - } -} - -/* -print_glyph(window, x, y, glyph, bkglyph) - -- Print the glyph at (x,y) on the given window. Glyphs are - integers at the interface, mapped to whatever the window- - port wants (symbol, font, color, attributes, ...there's - a 1-1 map between glyphs and distinct things on the map). -*/ -void -gnome_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) -{ - if (wid != -1 && gnome_windowlist[wid].win != NULL) { - GdkImlibImage *im; - - im = ghack_image_from_glyph(glyph, FALSE); - - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), - ghack_signals[GHSIG_PRINT_GLYPH], (guint) x, - (guint) y, im, NULL); - } -} - -/* -raw_print(str) -- Print directly to a screen, or otherwise guarantee that - the user sees str. raw_print() appends a newline to str. - It need not recognize ASCII control characters. This is - used during startup (before windowing system initialization - -- maybe this means only error startup messages are raw), - for error messages, and maybe other "msg" uses. E.g. - updating status for micros (i.e, "saving"). -*/ -void -gnome_raw_print(const char *str) -{ - tty_raw_print(str); -} - -/* -raw_print_bold(str) - -- Like raw_print(), but prints in bold/standout (if -possible). -*/ -void -gnome_raw_print_bold(const char *str) -{ - tty_raw_print_bold(str); -} - -/* -int nhgetch() -- Returns a single character input from the user. - -- In the tty window-port, nhgetch() assumes that tgetch() - will be the routine the OS provides to read a character. - Returned character _must_ be non-zero. -*/ -int -gnome_nhgetch() -{ - int key; - GList *theFirst; - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[WIN_STATUS].win), - ghack_signals[GHSIG_FADE_HIGHLIGHT]); - - g_askingQuestion = 1; - /* Process events until a key press event arrives. */ - while (g_numKeys == 0) { - if (program_state.done_hup) - return '\033'; - gtk_main_iteration(); - } - - theFirst = g_list_first(g_keyBuffer); - g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst); - key = GPOINTER_TO_INT(theFirst->data); - g_list_free_1(theFirst); - g_numKeys--; - g_askingQuestion = 0; - return (key); -} - -/* -int nh_poskey(int *x, int *y, int *mod) - -- Returns a single character input from the user or a - a positioning event (perhaps from a mouse). If the - return value is non-zero, a character was typed, else, - a position in the MAP window is returned in x, y and mod. - mod may be one of - - CLICK_1 -- mouse click type 1 - CLICK_2 -- mouse click type 2 - - The different click types can map to whatever the - hardware supports. If no mouse is supported, this - routine always returns a non-zero character. -*/ -int -gnome_nh_poskey(int *x, int *y, int *mod) -{ - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[WIN_STATUS].win), - ghack_signals[GHSIG_FADE_HIGHLIGHT]); - - g_askingQuestion = 0; - /* Process events until a key or map-click arrives. */ - while (g_numKeys == 0 && g_numClicks == 0) { - if (program_state.done_hup) - return '\033'; - gtk_main_iteration(); - } - - if (g_numKeys > 0) { - int key; - GList *theFirst; - - theFirst = g_list_first(g_keyBuffer); - g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst); - key = GPOINTER_TO_INT(theFirst->data); - g_list_free_1(theFirst); - g_numKeys--; - return (key); - } else { - GHClick *click; - GList *theFirst; - - theFirst = g_list_first(g_clickBuffer); - g_clickBuffer = g_list_remove_link(g_clickBuffer, theFirst); - click = (GHClick *) theFirst->data; - *x = click->x; - *y = click->y; - *mod = click->mod; - g_free(click); - g_list_free_1(theFirst); - g_numClicks--; - return (0); - } -} - -/* -nhbell() -- Beep at user. [This will exist at least until sounds are - redone, since sounds aren't attributable to windows -anyway.] -*/ -void -gnome_nhbell() -{ - /* FIXME!!! Play a cool GNOME sound instead */ - gdk_beep(); -} - -/* -doprev_message() - -- Display previous messages. Used by the ^P command. - -- On the tty-port this scrolls WIN_MESSAGE back one line. -*/ -int -gnome_doprev_message() -{ - /* Do Nothing. They can read old messages using the scrollbar. */ - return 0; -} - -/* -char yn_function(const char *ques, const char *choices, char default) - -- Print a prompt made up of ques, choices and default. - Read a single character response that is contained in - choices or default. If choices is NULL, all possible - inputs are accepted and returned. This overrides - everything else. The choices are expected to be in - lower case. Entering ESC always maps to 'q', or 'n', - in that order, if present in choices, otherwise it maps - to default. Entering any other quit character (SPACE, - RETURN, NEWLINE) maps to default. - -- If the choices string contains ESC, then anything after - it is an acceptable response, but the ESC and whatever - follows is not included in the prompt. - -- If the choices string contains a '#' then accept a count. - Place this value in the global "yn_number" and return '#'. - -- This uses the top line in the tty window-port, other - ports might use a popup. -*/ -char -gnome_yn_function(const char *question, const char *choices, CHAR_P def) -{ - int ch; - int result = -1; - char message[BUFSZ]; - char yn_esc_map = '\033'; - GtkWidget *mainWnd = ghack_get_main_window(); - - if (choices) { - char *cb, choicebuf[QBUFSZ]; - Strcpy(choicebuf, choices); - if ((cb = index(choicebuf, '\033')) != 0) { - /* anything beyond is hidden */ - *cb = '\0'; - } - (void) strncpy(message, question, QBUFSZ - 1); - message[QBUFSZ - 1] = '\0'; - sprintf(eos(message), " [%s]", choicebuf); - if (def) - sprintf(eos(message), " (%c)", def); - Strcat(message, " "); - /* escape maps to 'q' or 'n' or default, in that order */ - yn_esc_map = - (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); - } else { - Strcpy(message, question); - } - - gnome_putstr(WIN_MESSAGE, ATR_BOLD, message); - if (mainWnd != NULL && choices && !index(choices, ch)) { - return (ghack_yes_no_dialog(question, choices, def)); - } - - /* Only here if main window is not present */ - while (result < 0) { - ch = gnome_nhgetch(); - if (ch == '\033') { - result = yn_esc_map; - } else if (choices && !index(choices, ch)) { - /* FYI: ch==-115 is for KP_ENTER */ - if (def - && (ch == ' ' || ch == '\r' || ch == '\n' || ch == -115)) { - result = def; - } else { - gnome_nhbell(); - /* and try again... */ - } - } else { - result = ch; - } - } - return result; -} - -/* -getlin(const char *ques, char *input) - -- Prints ques as a prompt and reads a single line of text, - up to a newline. The string entered is returned without the - newline. ESC is used to cancel, in which case the string - "\033\000" is returned. - -- getlin() must call flush_screen(1) before doing anything. - -- This uses the top line in the tty window-port, other - ports might use a popup. -*/ -void -gnome_getlin(const char *question, char *input) -{ - int ret; - - ret = ghack_ask_string_dialog(question, "", "nethack", input); - - if (ret == -1) - input[0] = 0; -} - -/* -int get_ext_cmd(void) - -- Get an extended command in a window-port specific way. - An index into extcmdlist[] is returned on a successful - selection, -1 otherwise. -*/ -int -gnome_get_ext_cmd() -{ - return ghack_menu_ext_cmd(); -} - -/* -number_pad(state) - -- Initialize the number pad to the given state. -*/ -void -gnome_number_pad(int state) -{ - /* Do Nothing */ -} - -/* -delay_output() -- Causes a visible delay of 50ms in the output. - Conceptually, this is similar to wait_synch() followed - by a nap(50ms), but allows asynchronous operation. -*/ -void -gnome_delay_output() -{ - if (gnome_windowlist[WIN_MESSAGE].win != NULL) { - gtk_signal_emit(GTK_OBJECT(gnome_windowlist[WIN_MESSAGE].win), - ghack_signals[GHSIG_DELAY], (guint) 50); - } -} - -/* -start_screen() -- Only used on Unix tty ports, but must be declared for - completeness. Sets up the tty to work in full-screen - graphics mode. Look at win/tty/termcap.c for an - example. If your window-port does not need this function - just declare an empty function. -*/ -void -gnome_start_screen() -{ - /* Do Nothing */ -} - -/* -end_screen() -- Only used on Unix tty ports, but must be declared for - completeness. The complement of start_screen(). -*/ -void -gnome_end_screen() -{ - /* Do Nothing */ -} - -/* -outrip(winid, int, when) - -- The tombstone code. If you want the traditional code use - genl_outrip for the value and check the #if in rip.c. -*/ -void -gnome_outrip(winid wid, int how, time_t when) -{ - /* Follows roughly the same algorithm as genl_outrip() */ - char buf[BUFSZ]; - char ripString[BUFSZ] = "\0"; - long year; - - /* Put name on stone */ - Sprintf(buf, "%s\n", plname); - Strcat(ripString, buf); - - /* Put $ on stone */ - Sprintf(buf, "%ld Au\n", done_money); - Strcat(ripString, buf); - - /* Put together death description */ - formatkiller(buf, sizeof buf, how, FALSE); - - /* Put death type on stone */ - Strcat(ripString, buf); - Strcat(ripString, "\n"); - - /* Put year on stone */ - year = yyyymmdd(when) / 10000L; - Sprintf(buf, "%4ld\n", year); - Strcat(ripString, buf); - - ghack_text_window_rip_string(ripString); -} diff --git a/win/gnome/gnbind.h b/win/gnome/gnbind.h deleted file mode 100644 index a4e6b9139..000000000 --- a/win/gnome/gnbind.h +++ /dev/null @@ -1,88 +0,0 @@ -/* NetHack 3.6 gnbind.h $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackBind_h -#define GnomeHackBind_h - -/* - * This header files defines the interface between the window port specific - * code in the Gnome port and the rest of the nethack game engine. -*/ - -#include -#include - -#include "gnomeprv.h" -#include "gnmain.h" -#include "gnmap.h" -#include "gnmenu.h" -#include "gnplayer.h" -#include "gnsignal.h" -#include "gnstatus.h" -#include "gntext.h" -#include "gnmesg.h" -#include "gnyesno.h" -#include "gnglyph.h" -#include "gnworn.h" - -/* Create an array to keep track of the various windows */ - -#ifndef MAXWINDOWS -#define MAXWINDOWS 15 -#endif - -typedef struct gnome_nhwindow_data { - GtkWidget *win; - int type; -} GNHWinData; - -/* Some prototypes */ -void gnome_init_nhwindows(int *argc, char **argv); -void gnome_player_selection(void); -void gnome_askname(void); -void gnome_get_nh_event(void); -void gnome_exit_nhwindows(const char *); -void gnome_suspend_nhwindows(const char *); -void gnome_resume_nhwindows(void); -winid gnome_create_nhwindow(int type); -void gnome_create_nhwindow_by_id(int type, winid i); -void gnome_clear_nhwindow(winid wid); -void gnome_display_nhwindow(winid wid, BOOLEAN_P block); -void gnome_destroy_nhwindow(winid wid); -void gnome_curs(winid wid, int x, int y); -void gnome_putstr(winid wid, int attr, const char *text); -void gnome_display_file(const char *filename, BOOLEAN_P must_exist); -void gnome_start_menu(winid wid); -void gnome_add_menu(winid wid, int glyph, const ANY_P *identifier, - CHAR_P accelerator, CHAR_P group_accel, int attr, - const char *str, BOOLEAN_P presel); -void gnome_end_menu(winid wid, const char *prompt); -int gnome_select_menu(winid wid, int how, MENU_ITEM_P **selected); -/* No need for message_menu -- we'll use genl_message_menu instead */ -void gnome_update_inventory(void); -void gnome_mark_synch(void); -void gnome_wait_synch(void); -void gnome_cliparound(int x, int y); -/* The following function does the right thing. The nethack - * gnome_cliparound (which lacks the winid) simply calls this function. -*/ -void gnome_cliparound_proper(winid wid, int x, int y); -void gnome_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph); -void gnome_raw_print(const char *str); -void gnome_raw_print_bold(const char *str); -int gnome_nhgetch(void); -int gnome_nh_poskey(int *x, int *y, int *mod); -void gnome_nhbell(void); -int gnome_doprev_message(void); -char gnome_yn_function(const char *question, const char *choices, CHAR_P def); -void gnome_getlin(const char *question, char *input); -int gnome_get_ext_cmd(void); -void gnome_number_pad(int state); -void gnome_delay_output(void); -void gnome_start_screen(void); -void gnome_end_screen(void); -void gnome_outrip(winid wid, int how, time_t when); -void gnome_delete_nhwindow_by_reference(GtkWidget *menuWin); - -#endif /* GnomeHackBind_h */ diff --git a/win/gnome/gnglyph.c b/win/gnome/gnglyph.c deleted file mode 100644 index 9072dc9c6..000000000 --- a/win/gnome/gnglyph.c +++ /dev/null @@ -1,221 +0,0 @@ -/* NetHack 3.6 gnglyph.c $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gnglyph.h" -#include "tile2x11.h" - -/* from tile.c */ -extern int total_tiles_used; - -static GHackGlyphs ghack_glyphs; -static GdkImlibImage **ghack_tiles = NULL; - -/* NAME: - * ghack_init_glyphs(char* xpm_file) - * - * ARGUMENTS: - * char *xpm_file -- The name of the image file. - * May be any image format imlib recognizes. - * Does not have to be XPM. - * - * RETURNS: - * TRUE upon successful loading of the glyphs. - * FALSE upon failure. - * - * PURPOSE: - * Constructor for the Glyph object. Well, really each glyph - * object is a collection of glyphs, or tiles. This constructor - * takes a single argument: the name of the image file that contains - * the tile images. - * - * NOTES: - * The glyphs (tiles) must be in the image in a certain way: the - * glyphs must be stacked such that the resultant image is - * TILE_X * TILES_PER_ROW wide, and - * TILE_Y * (number of glyphs) / TILES_PER_ROW high (rounded up). - * In this sense, TILE_X == TILE_Y, and can be any reasonable integer - * say, 16 <= TILE_X <= 64. Because the glyph number is tightly - * coupled to the Nethack object it represents, the order of the - * glyphs in the image is imporant: Glyph 1 is at the top of the - * image, while Glyph N (the last glyph) is at the bottom. - * - * What's the difference between a glyph and a tile? Well, a - * tile is just an image. A glyph is a tile that knows its - * place in line. - * - * This initializer relies heavily on gdk_imlib. Thanks, Rasterman. - */ - -int -ghack_init_glyphs(const char *xpmFile) -{ - ghack_glyphs.im = gdk_imlib_load_image((char *) xpmFile); - if (!ghack_glyphs.im) { - g_error("Couldn't load required xpmFile!"); - return -1; - } - - gdk_imlib_render(ghack_glyphs.im, ghack_glyphs.im->rgb_width, - ghack_glyphs.im->rgb_height); - - if ((ghack_glyphs.im->rgb_width % TILES_PER_ROW) != 0 - || ghack_glyphs.im->rgb_width <= TILES_PER_ROW) { - g_error( - "%s is not a multiple of %d (number of tiles/row) pixels wide", - xpmFile, TILES_PER_ROW); - return -1; - } - ghack_glyphs.count = total_tiles_used; - if ((ghack_glyphs.count % TILES_PER_ROW) != 0) { - ghack_glyphs.count += - TILES_PER_ROW - (ghack_glyphs.count % TILES_PER_ROW); - } - ghack_glyphs.width = ghack_glyphs.im->rgb_width / TILES_PER_ROW; - ghack_glyphs.height = - ghack_glyphs.im->rgb_height / (ghack_glyphs.count / TILES_PER_ROW); - - /* Assume the tiles are organized in rows of TILES_PER_ROW */ - ghack_tiles = g_new0(GdkImlibImage *, ghack_glyphs.count); - return (ghack_tiles == NULL) ? -1 : 0; -} - -void -ghack_free_glyphs() -{ - int i; - for (i = 0; i < ghack_glyphs.count; i++) - gdk_imlib_destroy_image(ghack_tiles[i]); - g_free(ghack_tiles); - gdk_imlib_destroy_image(ghack_glyphs.im); - ghack_glyphs.im = NULL; -} - -/* NAME: - * ghack_glyph_count( ) - * - * ARGUMENTS: - * None. - * - * RETURNS: - * int -- The number of glyphs in this object. - * - * PURPOSE: - * Simply reports the number of glyphs in this object. - */ - -int -ghack_glyph_count() -{ - return ghack_glyphs.count; -} - -/* NAME: - * ghack_glyph_height() - * - * ARGUMENTS: - * None - * - * RETURNS: - * int -- The glyph height. - * - * PURPOSE: - * Returns the standard glyph height. - */ - -int -ghack_glyph_height() -{ - return ghack_glyphs.height; -} - -/* NAME: - * ghack_glyph_width() - * - * ARGUMENTS: - * None - * - * RETURNS: - * int -- The glyph width. - * - * PURPOSE: - * Returns the standard glyph width. - */ - -int -ghack_glyph_width() -{ - return ghack_glyphs.width; -} - -/* NAME: - * ghack_image_from_glyph( int glyph, gboolean force) - * - * ARGUMENTS: - * int glyph -- The glyph number. - * gboolean force -- force it to re-render. - * - * RETURNS: - * GdkImlibImage* -- The glyph image, as a GdkImlibImage. - * - * PURPOSE: - * Decodes the glyph into an image suitable for manipulation - */ - -GdkImlibImage * -ghack_image_from_glyph(int glyph, gboolean force) -{ - int tile = glyph2tile[glyph]; - - if (tile >= ghack_glyphs.count || tile < 0) { - g_warning( - "Aiiee! I've was asked for a tile outside the allowed range!\n" - "Email this to other-gnomehack@lists.debian.org"); - g_warning("Max tile: %d Tile asked for: %d", ghack_glyphs.count, - tile); - return NULL; - } - - if (ghack_glyphs.im == NULL) { - g_warning("Aiiee! I've been asked to clone from a null image.\n" - "Email this to other-gnomehack@lists.debian.org"); - g_warning("making image from tile %d, force=%s\n", tile, - (force == TRUE) ? "TRUE" : "FALSE"); - } - - if (force == TRUE) { - g_warning("Aiiee! I've been asked to force rendering.\n" - "Email this to other-gnomehack@lists.debian.org"); - g_warning("making image from tile %d, force=%s\n", tile, - (force == TRUE) ? "TRUE" : "FALSE"); - } - - if (!ghack_tiles[tile] || force) { - int src_x, src_y; -#if 0 - fprintf( stderr, "crop_and_clone: glyph=%d, tile=%d, ptr=%p, x=%d, y=%d, w=%d, h=%d\n", glyph, tile, - (void*)&(ghack_tiles[tile]), 0, - tile * ghack_glyphs.width, - ghack_glyphs.height, - ghack_glyphs.width); -#endif - if (ghack_glyphs.im->pixmap == NULL) - g_warning("Aiiee! ghack_glyphs.im->pixmap==NULL!!!!\n"); - src_x = (tile % TILES_PER_ROW) * ghack_glyphs.width; - src_y = (tile / TILES_PER_ROW) * ghack_glyphs.height; - ghack_tiles[tile] = gdk_imlib_crop_and_clone_image( - ghack_glyphs.im, src_x, src_y, ghack_glyphs.width, - ghack_glyphs.height); - } - - if (ghack_tiles[tile] && (!ghack_tiles[tile]->pixmap || force)) { - if (gdk_imlib_render(ghack_tiles[tile], ghack_tiles[tile]->rgb_width, - ghack_tiles[tile]->rgb_height) == 0) { - g_error("GLYPH: couldn't create tile # %d", tile); - } - if (!ghack_tiles[tile]->pixmap) - g_error("Strange, tile # %d didn't get rendered???", tile); - } - - return ghack_tiles[tile]; -} diff --git a/win/gnome/gnglyph.h b/win/gnome/gnglyph.h deleted file mode 100644 index 66d2e27bf..000000000 --- a/win/gnome/gnglyph.h +++ /dev/null @@ -1,41 +0,0 @@ -/* NetHack 3.6 gnglyph.h $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackGlyph_h -#define GnomeHackGlyph_h - -#include "config.h" -#include "global.h" - -/* the prototypes in system headers contain useless argument names - that trigger spurious warnings if gcc's `-Wshadow' option is used */ -#undef index -#define index _hide_index_ -#define time _hide_time_ - -#include -#include - -#undef index -#define index strchr -#undef time - -extern short glyph2tile[]; /* From tile.c */ - -typedef struct { - GdkImlibImage *im; - int count; - int width; - int height; -} GHackGlyphs; - -extern int ghack_init_glyphs(const char *); -extern void ghack_free_glyphs(void); -extern void ghack_dispose_glyphs(void); -extern int ghack_glyph_count(void); -extern GdkImlibImage *ghack_image_from_glyph(int, gboolean); -extern int ghack_glyph_height(void); -extern int ghack_glyph_width(void); - -#endif /* GnomeHackGlyph_h */ diff --git a/win/gnome/gnmain.c b/win/gnome/gnmain.c deleted file mode 100644 index 1a16cc9fe..000000000 --- a/win/gnome/gnmain.c +++ /dev/null @@ -1,706 +0,0 @@ -/* NetHack 3.6 gnmain.c $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gnmain.h" -#include "gnsignal.h" -#include "gnbind.h" -#include "gnopts.h" -#include -#include -#include -#include -#include -#include -#include "hack.h" -#include "date.h" - -static GtkWidget *mainWindow = NULL; -static GtkWidget *about = NULL; -static GtkWidget *hBoxFirstRow; -static GtkWidget *vBoxMain; - -int restarted = 0; -int os_x = 0, os_y = 0, os_w = 0, os_h = 0; - -static GnomeClient *session_id; - -static void -ghack_quit_game(GtkWidget *widget, int button) -{ - gtk_widget_hide(widget); - if (button == 0) { - gnome_exit_nhwindows(0); - gtk_object_unref(GTK_OBJECT(session_id)); - clearlocks(); - gtk_exit(0); - } -} - -static void -ghack_quit_game_cb(GtkWidget *widget, gpointer data) -{ - GtkWidget *box; - box = gnome_message_box_new( - _("Do you really want to quit?"), GNOME_MESSAGE_BOX_QUESTION, - GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL); - gnome_dialog_set_default(GNOME_DIALOG(box), 1); - gnome_dialog_set_parent(GNOME_DIALOG(box), - GTK_WINDOW(ghack_get_main_window())); - gnome_dialog_set_accelerator(GNOME_DIALOG(box), 1, 'n', 0); - gnome_dialog_set_accelerator(GNOME_DIALOG(box), 0, 'y', 0); - - gtk_window_set_modal(GTK_WINDOW(box), TRUE); - gtk_signal_connect(GTK_OBJECT(box), "clicked", - (GtkSignalFunc) ghack_quit_game, NULL); - gtk_widget_show(box); -} - -static void -ghack_save_game(GtkWidget *widget, int button) -{ - gtk_widget_hide(widget); - if (button == 0) { - if (dosave0()) { - /* make sure they see the Saving message */ - display_nhwindow(WIN_MESSAGE, TRUE); - gnome_exit_nhwindows("Be seeing you..."); - clearlocks(); - gtk_exit(0); - } else - (void) doredraw(); - } -} - -void -ghack_save_game_cb(GtkWidget *widget, gpointer data) -{ - GtkWidget *box; - box = gnome_message_box_new( - _("Quit and save the current game?"), GNOME_MESSAGE_BOX_QUESTION, - GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL); - gnome_dialog_set_default(GNOME_DIALOG(box), 1); - gnome_dialog_set_parent(GNOME_DIALOG(box), - GTK_WINDOW(ghack_get_main_window())); - gnome_dialog_set_accelerator(GNOME_DIALOG(box), 1, 'n', 0); - gnome_dialog_set_accelerator(GNOME_DIALOG(box), 0, 'y', 0); - - gtk_window_set_modal(GTK_WINDOW(box), TRUE); - gtk_signal_connect(GTK_OBJECT(box), "clicked", - (GtkSignalFunc) ghack_save_game, NULL); - gtk_widget_show(box); -} - -static void -ghack_new_game(GtkWidget *widget, int button) -{ - if (button == 0) { - g_message("This feature is not yet implemented. Sorry."); - } -} - -static void -ghack_new_game_cb(GtkWidget *widget, gpointer data) -{ - GtkWidget *box; - box = gnome_message_box_new( - _("Start a new game?"), GNOME_MESSAGE_BOX_QUESTION, - GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL); - gnome_dialog_set_default(GNOME_DIALOG(box), 1); - gnome_dialog_set_parent(GNOME_DIALOG(box), - GTK_WINDOW(ghack_get_main_window())); - gnome_dialog_set_accelerator(GNOME_DIALOG(box), 1, 'n', 0); - gnome_dialog_set_accelerator(GNOME_DIALOG(box), 0, 'y', 0); - - gtk_window_set_modal(GTK_WINDOW(box), TRUE); - gtk_signal_connect(GTK_OBJECT(box), "clicked", - (GtkSignalFunc) ghack_new_game, NULL); - gtk_widget_show(box); -} - -static void -about_destroy_callback(void) -{ - about = NULL; -} - -static void -ghack_about_cb(GtkWidget *widget, gpointer data) -{ - char buf[BUFSZ] = "\0"; - char buf1[BUFSZ] = "\0"; - const gchar *authors[] = { "Erik Andersen", "Anthony Taylor", - "Jeff Garzik", "The Nethack Dev Team", NULL }; - - if (about) { - gdk_window_raise(about->window); - return; - } - - getversionstring(buf); -#if 0 -/* XXX this needs further re-write to use DEVTEAM_EMAIL, DEVTEAM_URL, - * sysopt.support, etc. I'm not doing it now because I can't test - * it yet. (keni) - */ -/* out of date first cut: */ -! len = strlen(buf); -! char *str1 = _("\nSend comments and bug reports to:\n"); -! len += strlen(str1); -! len += sysopt.email; -! char *str2 = _("\nThis game is free software. See License for details."); -! len += strlen(str2); -! str = (char*)alloc(len+1); -! strcat(buf, str1); -! strcat(buf, sysopt.email); -! strcat(buf, str2); -free(str) below -#else - strcat(buf1, VERSION_STRING); - strcat(buf, - _("\nSend comments and bug reports to: nethack-bugs@nethack.org\n" - "This game is free software. See License for details.")); -#endif - about = gnome_about_new(_("Nethack"), buf1, - "Copyright (C) 1985-2002 Mike Stephenson", - (const char **) authors, buf, NULL); - - gtk_signal_connect(GTK_OBJECT(about), "destroy", - (GtkSignalFunc) about_destroy_callback, NULL); - - gtk_widget_show(about); -} - -static void -ghack_settings_cb(GtkWidget *widget, gpointer data) -{ - ghack_settings_dialog(); -} - -static void -ghack_accelerator_selected(GtkWidget *widget, gpointer data) -{ - GdkEventKey event; - int key = GPOINTER_TO_INT(data); - /* g_message("An accelerator for \"%c\" was selected", key); */ - /* stuff a key directly into the keybuffer */ - event.state = 0; - event.keyval = key; - ghack_handle_key_press(NULL, &event, NULL); -} - -#ifndef M -#ifndef NHSTDC -#define M(c) (0x80 | (c)) -#else -#define M(c) ((c) -128) -#endif /* NHSTDC */ -#endif -#ifndef C -#define C(c) (0x1f & (c)) -#endif - -GnomeUIInfo game_tree[] = { - { GNOME_APP_UI_ITEM, N_("_Change Settings..."), - N_("Change Game Settings"), ghack_settings_cb, NULL, NULL, - GNOME_APP_PIXMAP_NONE, NULL, 0, 0, NULL }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Version"), NULL, ghack_accelerator_selected, - GINT_TO_POINTER('v'), NULL, GNOME_APP_PIXMAP_STOCK, - GNOME_STOCK_MENU_ABOUT, 'v', 0 }, - { GNOME_APP_UI_ITEM, N_("History..."), NULL, ghack_accelerator_selected, - GINT_TO_POINTER('V'), NULL, GNOME_APP_PIXMAP_STOCK, - GNOME_STOCK_MENU_ABOUT, 'V', GDK_SHIFT_MASK }, - { GNOME_APP_UI_ITEM, N_("Compilation..."), NULL, - ghack_accelerator_selected, GINT_TO_POINTER(M('v')), NULL, - GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'v', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Options..."), NULL, ghack_accelerator_selected, - GINT_TO_POINTER('O'), NULL, GNOME_APP_PIXMAP_STOCK, - GNOME_STOCK_MENU_PREF, 'O', GDK_SHIFT_MASK }, - { GNOME_APP_UI_ITEM, N_("Explore Mode..."), NULL, - ghack_accelerator_selected, GINT_TO_POINTER('X'), NULL, - GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_QUIT, 'X', GDK_SHIFT_MASK }, - GNOMEUIINFO_SEPARATOR, - GNOMEUIINFO_MENU_NEW_GAME_ITEM(ghack_new_game_cb, NULL), - GNOMEUIINFO_MENU_SAVE_ITEM(ghack_save_game_cb, NULL), - { GNOME_APP_UI_ITEM, N_("Exit"), NULL, ghack_quit_game_cb, - GINT_TO_POINTER(M('Q')), NULL, GNOME_APP_PIXMAP_STOCK, - GNOME_STOCK_MENU_ABOUT, 'Q', GDK_MOD1_MASK }, - GNOMEUIINFO_END -}; - -GnomeUIInfo edit_menu[] = { - { GNOME_APP_UI_ITEM, N_("Inventory"), N_("Edit/View your Inventory"), - ghack_accelerator_selected, GINT_TO_POINTER('i'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'i', 0 }, - { GNOME_APP_UI_ITEM, N_("Discoveries"), N_("Edit/View your Discoveries"), - ghack_accelerator_selected, GINT_TO_POINTER('\\'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, '\\', 0 }, - { GNOME_APP_UI_ITEM, N_("List/reorder your spells"), - N_("List/reorder your spells"), ghack_accelerator_selected, - GINT_TO_POINTER('x'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'x', 0 }, - { GNOME_APP_UI_ITEM, N_("Adjust letters"), - N_("Adjust letter for items in your Inventory"), - ghack_accelerator_selected, GINT_TO_POINTER(M('a')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'a', GDK_MOD1_MASK }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Name object"), N_("Assign a name to an object"), - ghack_accelerator_selected, GINT_TO_POINTER(M('n')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'n', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Name creature"), - N_("Assign a name to a creature"), ghack_accelerator_selected, - GINT_TO_POINTER('C'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'C', - GDK_SHIFT_MASK }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Qualifications"), N_("Edit your Qualifications"), - ghack_accelerator_selected, GINT_TO_POINTER(M('e')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'e', GDK_MOD1_MASK }, - GNOMEUIINFO_END -}; - -GnomeUIInfo apparel_menu[] = { - { GNOME_APP_UI_ITEM, N_("Wield Weapon"), - N_("Select a weapon to fight with"), ghack_accelerator_selected, - GINT_TO_POINTER('w'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'w', 0 }, - { GNOME_APP_UI_ITEM, N_("Remove Apparel..."), - N_("Remove apparel dialog bog"), ghack_accelerator_selected, - GINT_TO_POINTER('A'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'A', - GDK_SHIFT_MASK }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Wear Armor"), N_("Put on armor"), - ghack_accelerator_selected, GINT_TO_POINTER('W'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'W', GDK_SHIFT_MASK }, - { GNOME_APP_UI_ITEM, N_("Take off Armor"), - N_("Take off armor you are wearing"), ghack_accelerator_selected, - GINT_TO_POINTER('T'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'T', - GDK_SHIFT_MASK }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Put on non-armor"), - N_("Put on non-armor apparel"), ghack_accelerator_selected, - GINT_TO_POINTER('P'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'P', - GDK_SHIFT_MASK }, - { GNOME_APP_UI_ITEM, N_("Remove non-armor"), - N_("Remove non-armor apparel you are wearing"), - ghack_accelerator_selected, GINT_TO_POINTER('R'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'R', GDK_SHIFT_MASK }, - GNOMEUIINFO_END -}; - -GnomeUIInfo action_menu[] = { - { GNOME_APP_UI_ITEM, N_("Get"), - N_("Pick up things at the current location"), - ghack_accelerator_selected, GINT_TO_POINTER(','), NULL, - GNOME_APP_PIXMAP_NONE, NULL, ',', 0 }, - { GNOME_APP_UI_ITEM, N_("Loot"), N_("loot a box on the floor"), - ghack_accelerator_selected, GINT_TO_POINTER(M('l')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'l', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Sit"), N_("sit down"), - ghack_accelerator_selected, GINT_TO_POINTER(M('s')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 's', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Force"), N_("force a lock"), - ghack_accelerator_selected, GINT_TO_POINTER(M('f')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'f', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Kick"), N_("kick something (usually a door)"), - ghack_accelerator_selected, GINT_TO_POINTER(C('d')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'd', GDK_CONTROL_MASK }, - { GNOME_APP_UI_ITEM, N_("Jump"), N_("jump to another location"), - ghack_accelerator_selected, GINT_TO_POINTER(M('j')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'j', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Ride"), N_("Ride (or stop riding) a monster"), - doride, GINT_TO_POINTER(M('r')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'R', - GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Wipe face"), N_("wipe off your face"), - ghack_accelerator_selected, GINT_TO_POINTER(M('w')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'w', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Throw/Shoot"), N_("throw or shoot a weapon"), - ghack_accelerator_selected, GINT_TO_POINTER('t'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 't', 0 }, - { - GNOME_APP_UI_ITEM, N_("Quiver/Ready"), - N_("ready or quiver some ammunition"), ghack_accelerator_selected, - GINT_TO_POINTER('Q'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'Q', - GDK_SHIFT_MASK, - }, - { GNOME_APP_UI_ITEM, N_("Open Door"), N_("open a door"), - ghack_accelerator_selected, GINT_TO_POINTER('o'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'o', 0 }, - { GNOME_APP_UI_ITEM, N_("Close Door"), N_("open a door"), - ghack_accelerator_selected, GINT_TO_POINTER('c'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'c', 0 }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Drop"), N_("drop an object"), - ghack_accelerator_selected, GINT_TO_POINTER('d'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'd', 0 }, - { GNOME_APP_UI_ITEM, N_("Drop Many"), - N_("drop selected types of objects"), ghack_accelerator_selected, - GINT_TO_POINTER('D'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'D', - GDK_SHIFT_MASK }, - { GNOME_APP_UI_ITEM, N_("Eat"), N_("eat something"), - ghack_accelerator_selected, GINT_TO_POINTER('e'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'e', 0 }, - { GNOME_APP_UI_ITEM, N_("Engrave"), - N_("write a message in the dust on the floor"), - ghack_accelerator_selected, GINT_TO_POINTER('E'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'E', GDK_SHIFT_MASK }, - { GNOME_APP_UI_ITEM, N_("Apply"), - N_("apply or use a tool (pick-axe, key, camera, etc.)"), - ghack_accelerator_selected, GINT_TO_POINTER('a'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'a', 0 }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Up"), N_("go up the stairs"), - ghack_accelerator_selected, GINT_TO_POINTER('<'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, '<', 0 }, - { GNOME_APP_UI_ITEM, N_("Down"), N_("go down the stairs"), - ghack_accelerator_selected, GINT_TO_POINTER('>'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, '>', 0 }, - { GNOME_APP_UI_ITEM, N_("Rest"), N_("wait for a moment"), - ghack_accelerator_selected, GINT_TO_POINTER('.'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, '.', 0 }, - { GNOME_APP_UI_ITEM, N_("Search"), - N_("search for secret doors, hidden traps and monsters"), - ghack_accelerator_selected, GINT_TO_POINTER('s'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 's', 0 }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Chat"), N_("talk to someone"), - ghack_accelerator_selected, GINT_TO_POINTER(M('c')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'c', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Pay"), N_("pay your bill to the shopkeeper"), - ghack_accelerator_selected, GINT_TO_POINTER('p'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'p', 0 }, - GNOMEUIINFO_END -}; - -GnomeUIInfo magic_menu[] = { - { GNOME_APP_UI_ITEM, N_("Quaff potion"), N_("drink a potion"), - ghack_accelerator_selected, GINT_TO_POINTER('q'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'q', 0 }, - { GNOME_APP_UI_ITEM, N_("Read Book/Scroll"), - N_("read a spell book or a scroll"), ghack_accelerator_selected, - GINT_TO_POINTER('r'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'r', 0 }, - { GNOME_APP_UI_ITEM, N_("Zap Wand"), N_("zap a wand"), - ghack_accelerator_selected, GINT_TO_POINTER('z'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'z', 0 }, - { GNOME_APP_UI_ITEM, N_("Zap Spell"), N_("cast a spell"), - ghack_accelerator_selected, GINT_TO_POINTER('Z'), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'Z', GDK_SHIFT_MASK }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Dip"), N_("dip an object into something"), - ghack_accelerator_selected, GINT_TO_POINTER(M('d')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'd', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Rub"), N_("Rub something (i.e. a lamp)"), - ghack_accelerator_selected, GINT_TO_POINTER(M('r')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'r', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Invoke"), - N_("invoke an object's special powers"), ghack_accelerator_selected, - GINT_TO_POINTER(M('i')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'i', - GDK_MOD1_MASK }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Offer"), N_("offer a sacrifice to the gods"), - ghack_accelerator_selected, GINT_TO_POINTER(M('o')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'o', GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Pray"), N_("pray to the gods for help"), - ghack_accelerator_selected, GINT_TO_POINTER(M('p')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 'p', GDK_MOD1_MASK }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("Teleport"), N_("teleport (if you can)"), - ghack_accelerator_selected, GINT_TO_POINTER(C('t')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 't', GDK_CONTROL_MASK }, - { GNOME_APP_UI_ITEM, N_("Monster Action"), - N_("use a monster's special ability"), ghack_accelerator_selected, - GINT_TO_POINTER(M('m')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'm', - GDK_MOD1_MASK }, - { GNOME_APP_UI_ITEM, N_("Turn Undead"), N_("turn undead"), - ghack_accelerator_selected, GINT_TO_POINTER(M('t')), NULL, - GNOME_APP_PIXMAP_NONE, NULL, 't', GDK_MOD1_MASK }, - GNOMEUIINFO_END -}; - -GnomeUIInfo help_menu[] = { - { GNOME_APP_UI_ITEM, N_("About..."), N_("About GnomeHack"), - ghack_about_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK, - GNOME_STOCK_MENU_ABOUT, 0, 0, NULL }, - { GNOME_APP_UI_ITEM, N_("Help"), NULL, ghack_accelerator_selected, - GINT_TO_POINTER('?'), NULL, GNOME_APP_PIXMAP_STOCK, - GNOME_STOCK_MENU_ABOUT, '?', 0 }, - GNOMEUIINFO_SEPARATOR, - { GNOME_APP_UI_ITEM, N_("What is here"), - N_("Check what items occupy the current location"), - ghack_accelerator_selected, GINT_TO_POINTER(':'), NULL, - GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, ':', 0 }, - { GNOME_APP_UI_ITEM, N_("What is that"), N_("Identify an object"), - ghack_accelerator_selected, GINT_TO_POINTER(';'), NULL, - GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, ';', 0 }, - { GNOME_APP_UI_ITEM, N_("Identify a map symbol"), - N_("Identify a map symbol"), ghack_accelerator_selected, - GINT_TO_POINTER('/'), NULL, GNOME_APP_PIXMAP_STOCK, - GNOME_STOCK_MENU_ABOUT, '/', 0 }, - GNOMEUIINFO_END -}; - -GnomeUIInfo mainmenu[] = { GNOMEUIINFO_MENU_GAME_TREE(game_tree), - GNOMEUIINFO_MENU_EDIT_TREE(edit_menu), - { GNOME_APP_UI_SUBTREE, N_("Apparel"), NULL, - apparel_menu, NULL, NULL, 0, NULL, 0, 0, NULL }, - { GNOME_APP_UI_SUBTREE, N_("Action"), NULL, - action_menu, NULL, NULL, 0, NULL, 0, 0, NULL }, - { GNOME_APP_UI_SUBTREE, N_("Magic"), NULL, - magic_menu, NULL, NULL, 0, NULL, 0, 0, NULL }, - GNOMEUIINFO_MENU_HELP_TREE(help_menu), - GNOMEUIINFO_END }; - -static void -ghack_main_window_key_press(GtkWidget *widget, GdkEventKey *event, - gpointer data) -{ - /* First, turn off the key press propogation. We've got the - * key, but we don't wan't the underlying Gtk widgets to get it, - * since they do the wrong thing with the arrow keys (shift focus)... */ - gtk_signal_emit_stop_by_name(GTK_OBJECT(mainWindow), "key_press_event"); - - /* stuff the key event into the keybuffer */ - ghack_handle_key_press(widget, event, data); -} - -/* parsing args */ -void -parse_args(int argc, char *argv[]) -{ - gint ch; - - struct option options[] = { /* Default args */ - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'v' }, - - { NULL, 0, NULL, 0 } - }; - - gchar *id = NULL; - - /* initialize getopt */ - optarg = NULL; - optind = 0; - optopt = 0; - - while ((ch = getopt_long(argc, argv, "hv", options, NULL)) != EOF) { - switch (ch) { - case 'h': - g_print( - _("%s: A gnomified 'Hello World' program\n\n" - "Usage: %s [--help] [--version]\n\n" - "Options:\n" - " --help display this help and exit\n" - " --version output version information and exit\n"), - argv[0], argv[0]); - exit(0); - break; - case 'v': - g_print(_("NetHack %s.\n"), VERSION_STRING); - exit(0); - break; - case ':': - case '?': - g_print(_("Options error\n")); - exit(0); - break; - } - } - - /* SM stuff */ - session_id = gnome_client_new(); -#if 0 - session_id = gnome_client_new ( - /* callback to save the state and parameter for it */ - save_state, argv[0], - /* callback to die and parameter for it */ - NULL, NULL, - /* id from the previous session if restarted, NULL otherwise */ - id); -#endif - /* set the program name */ - gnome_client_set_program(session_id, argv[0]); - g_free(id); - - return; -} - -/* - * [ALI] Gnome installs its own handler(s) for SIGBUS, SIGFPE and SIGSEGV. - * These handlers will fork and exec a helper program. When that helper - * comes to initialize GTK+, it may fail if setuid/setgid. We solve this - * by dropping privileges before passing the signal along the chain. - * Note: We don't need to either drop or mask the saved ID since this - * will be reset when the child process performs the execve() anyway. - */ - -static struct { - int signum; - void (*handler)(int); -} ghack_chain[] = { - { SIGBUS }, - { SIGFPE }, - { SIGSEGV }, - { SIGILL } /* Not currently handled by Gnome */ -}; - -static void -ghack_sig_handler(int signum) -{ - int i; - uid_t uid, euid; - gid_t gid, egid; - uid = getuid(); - euid = geteuid(); - gid = getgid(); - egid = getegid(); - if (gid != egid) - setgid(gid); - if (uid != euid) - setuid(uid); - for (i = SIZE(ghack_chain) - 1; i >= 0; i--) - if (ghack_chain[i].signum == signum) { - ghack_chain[i].handler(signum); - break; - } - if (i < 0) - impossible("Unhandled ghack signal"); - if (uid != euid) - setuid(euid); - if (gid != egid) - setgid(egid); -} - -/* initialize gnome and fir up the main window */ -void -ghack_init_main_window(int argc, char **argv) -{ - int i; - struct timeval tv; - uid_t uid, euid; - - /* It seems that the authors of gnome_score_init() drop group - * priveledges. We need group priveledges, so until we change the - * way we save games to do things the gnome way(???), this stays - * commented out. (after hours of frusteration...) - * -Erik - */ - /* gnome_score_init("gnomehack"); */ - - gettimeofday(&tv, NULL); - srand(tv.tv_usec); - - uid = getuid(); - euid = geteuid(); - if (uid != euid) - setuid(uid); - hide_privileges(TRUE); - /* XXX gnome_init must print nethack options for --help, but does not */ - gnome_init("nethack", VERSION_STRING, argc, argv); - hide_privileges(FALSE); - parse_args(argc, argv); - -/* Initialize the i18n stuff (not that gnomehack supperts it yet...) */ -#if 0 - textdomain (PACKAGE); -#endif - gdk_imlib_init(); - - /* Main window */ - mainWindow = - gnome_app_new((char *) "nethack", (char *) N_("Nethack for Gnome")); - gtk_widget_realize(mainWindow); - if (restarted) { - gtk_widget_set_uposition(mainWindow, os_x, os_y); - gtk_widget_set_usize(mainWindow, os_w, os_h); - } - gtk_window_set_default_size(GTK_WINDOW(mainWindow), 800, 600); - gtk_window_set_policy(GTK_WINDOW(mainWindow), FALSE, TRUE, TRUE); - gnome_app_create_menus(GNOME_APP(mainWindow), mainmenu); - gtk_signal_connect(GTK_OBJECT(mainWindow), "key_press_event", - GTK_SIGNAL_FUNC(ghack_main_window_key_press), NULL); - gtk_signal_connect(GTK_OBJECT(mainWindow), "delete_event", - GTK_SIGNAL_FUNC(ghack_quit_game_cb), NULL); - - /* Put some stuff into our main window */ - vBoxMain = gtk_vbox_new(FALSE, 0); - hBoxFirstRow = gtk_hbox_new(FALSE, 0); - - /* pack Boxes into other boxes to produce the right structure */ - gtk_box_pack_start(GTK_BOX(vBoxMain), hBoxFirstRow, FALSE, TRUE, 0); - - /* pack vBoxMain which contains all our widgets into the main window. */ - gnome_app_set_contents(GNOME_APP(mainWindow), vBoxMain); - - /* DONT show the main window yet, due to a Gtk bug that causes it - * to not refresh the window when adding widgets after the window - * has already been shown */ - if (uid != euid) - setuid(euid); - for (i = 0; i < SIZE(ghack_chain); i++) - ghack_chain[i].handler = - signal(ghack_chain[i].signum, ghack_sig_handler); -} - -void -ghack_main_window_add_map_window(GtkWidget *win) -{ - GtkWidget *vBox; - - vBox = gtk_vbox_new(TRUE, 0); - gtk_box_pack_start(GTK_BOX(vBox), win, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(vBoxMain), vBox, TRUE, TRUE, 2); - gtk_widget_show_all(vBox); - /* Ok, now show the main window -- now that we have added in - * all the windows (relys on nethack displaying the map window last - * (This is an ugly kludge, BTW) - */ - gtk_widget_show_all(mainWindow); -} - -void -ghack_main_window_add_message_window(GtkWidget *win) -{ - gtk_box_pack_start(GTK_BOX(hBoxFirstRow), win, TRUE, TRUE, 2); - gtk_widget_show_all(win); -} - -void -ghack_main_window_add_status_window(GtkWidget *win) -{ - gtk_box_pack_start(GTK_BOX(hBoxFirstRow), win, FALSE, TRUE, 2); - gtk_widget_show_all(win); -} - -void -ghack_main_window_add_worn_window(GtkWidget *win) -{ - gtk_box_pack_end(GTK_BOX(hBoxFirstRow), win, FALSE, TRUE, 2); - gtk_widget_show_all(win); -} - -void -ghack_main_window_add_text_window(GtkWidget *win) -{ - g_warning("Fixme!!! AddTextWindow is not yet implemented"); -} - -void -ghack_main_window_remove_window(GtkWidget *win) -{ - g_warning("Fixme!!! RemoveWindow is not yet implemented"); -} - -void -ghack_main_window_update_inventory() -{ - /* For now, do very little. Eventually we may allow the inv. window - to stay active. When we do this, we'll need to implement this... - g_warning("Fixme!!! updateInventory is not yet implemented"); - */ - gnome_display_nhwindow(WIN_WORN, FALSE); -} - -GtkWidget * -ghack_get_main_window() -{ - return (GTK_WIDGET(mainWindow)); -} diff --git a/win/gnome/gnmain.h b/win/gnome/gnmain.h deleted file mode 100644 index 7b49438f0..000000000 --- a/win/gnome/gnmain.h +++ /dev/null @@ -1,22 +0,0 @@ -/* NetHack 3.6 gnmain.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackMainWindow_h -#define GnomeHackMainWindow_h - -#include -#include - -void ghack_init_main_window(int argc, char **argv); -void ghack_main_window_add_map_window(GtkWidget *win); -void ghack_main_window_add_message_window(GtkWidget *win); -void ghack_main_window_add_status_window(GtkWidget *win); -void ghack_main_window_add_text_window(GtkWidget *); -void ghack_main_window_add_worn_window(GtkWidget *win); -void ghack_main_window_remove_window(GtkWidget *); -void ghack_main_window_update_inventory(); -void ghack_save_game_cb(GtkWidget *widget, gpointer data); -GtkWidget *ghack_get_main_window(); - -#endif /* GnomeHackMainWindow_h */ diff --git a/win/gnome/gnmap.c b/win/gnome/gnmap.c deleted file mode 100644 index 98e80b485..000000000 --- a/win/gnome/gnmap.c +++ /dev/null @@ -1,529 +0,0 @@ -/* NetHack 3.6 gnmap.c $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* Copyright (C) 1998 by Anthony Taylor */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gnmap.h" -#include "gnglyph.h" -#include "gnsignal.h" -#include "hack.h" - -#ifndef ROWNO -#define ROWNO 21 -#define COLNO 80 -#endif - -/* globals static to this file go here */ -struct { - GnomeCanvas *canvas; - GnomeCanvasImage *map[(ROWNO + 1) * COLNO]; - GnomeCanvasImage *overlay[(ROWNO + 1) * COLNO]; - double zoom; - GtkWidget *frame; -} ghack_map; - -static GdkImlibImage *background; -static GdkImlibImage *petmark; -static GnomeCanvasGroup *myCanvasGroup; - -/* static function declarations -- local to this file go here */ -void ghack_map_cursor_to(GtkWidget *win, int x, int y, gpointer data); -void ghack_map_putstr(GtkWidget *win, int attr, const char *text, - gpointer data); -void ghack_map_print_glyph(GtkObject *win, guint x, guint y, - GdkImlibImage *im, gpointer data); -void ghack_map_clear(GtkWidget *win, gpointer data); -static void ghack_map_display(GtkWidget *win, boolean block, gpointer data); -static void ghack_map_cliparound(GtkWidget *win, int x, int y, gpointer data); -static void ghack_map_window_zoom(GtkAdjustment *adj, gpointer data); - -/* The following XPM is the artwork of Warwick Allison - * . It has been borrowed from - * the most excellent NetHackQt, until such time as - * we can come up with something better. - * - * More information about NetHackQt can be had from: - * http://www.troll.no/~warwick/nethack/ - */ - -/* XPM */ -static char *pet_mark_xpm[] = { - /* width height ncolors chars_per_pixel */ - "8 7 2 1", - /* colors */ - ". c None", " c #FF0000", - /* pixels */ - "........", ".. . .", ". ", ". ", - ".. .", "... ..", ".... ..." -}; - -/* NAME: - * ghack_init_map_window( ) - * - * ARGUMENTS: - * NONE - * - * RETURNS: - * GtkWidget* - * - * PURPOSE: - * Create the basic map necessities. Create a canvas; - * give it a background. Attach all the right signals - * to all the right places. Generally prepare the map - * to behave properly. -*/ - -GtkWidget * -ghack_init_map_window() -{ - GtkWidget *vbox; - GtkWidget *hbox; - GtkWidget *table; - GtkWidget *frame; - GtkWidget *w; - GtkWidget *hSeparator; - GtkAdjustment *adj; - GnomeCanvasImage *bg; - double width, height, x, y; - int i; - - width = COLNO * ghack_glyph_width(); - height = ROWNO * ghack_glyph_height(); - - vbox = gtk_vbox_new(FALSE, 4); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); - gtk_widget_show(vbox); - - /* Add in a horiz seperator */ - hSeparator = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox), hSeparator, FALSE, FALSE, 2); - gtk_widget_show(hSeparator); - - hbox = gtk_hbox_new(FALSE, 4); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - gtk_widget_show(hbox); - - /* Create the Zoom spinbutton. - */ - ghack_map.zoom = 1.0; - w = gtk_label_new("Zoom:"); - gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 0); - gtk_widget_show(w); - adj = - GTK_ADJUSTMENT(gtk_adjustment_new(1.00, 0.5, 3.00, 0.05, 0.50, 0.50)); - w = gtk_spin_button_new(adj, 0.5, 2); - gtk_widget_set_usize(w, 50, 0); - gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 0); - gtk_widget_show(w); - - /* Canvas and scrollbars - */ - gtk_widget_push_visual(gdk_imlib_get_visual()); - gtk_widget_push_colormap(gdk_imlib_get_colormap()); - ghack_map.canvas = GNOME_CANVAS(gnome_canvas_new()); - // gtk_widget_push_visual(gdk_rgb_get_visual()); - // gtk_widget_push_colormap(gdk_rgb_get_cmap()); - // ghack_map.canvas = GNOME_CANVAS (gnome_canvas_new_aa()); - - gtk_widget_pop_colormap(); - gtk_widget_pop_visual(); - gtk_widget_show(GTK_WIDGET(ghack_map.canvas)); - - table = gtk_table_new(2, 2, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(table), 4); - gtk_table_set_col_spacings(GTK_TABLE(table), 4); - gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); - gtk_widget_show(table); - - frame = gtk_frame_new(NULL); - ghack_map.frame = frame; - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); - gtk_table_attach(GTK_TABLE(table), frame, 0, 1, 0, 1, - GTK_EXPAND | GTK_FILL | GTK_SHRINK, - GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0); - gtk_widget_show(frame); - - gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(ghack_map.canvas)); - gnome_canvas_set_scroll_region(GNOME_CANVAS(ghack_map.canvas), 0, 0, - width + 2 * ghack_glyph_width(), - height + 2 * ghack_glyph_height()); - - gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(ghack_map.canvas), 1.0); - - w = gtk_hscrollbar_new(GTK_LAYOUT(ghack_map.canvas)->hadjustment); - gtk_table_attach(GTK_TABLE(table), w, 0, 1, 1, 2, - GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, 0, 0); - gtk_widget_show(w); - - w = gtk_vscrollbar_new(GTK_LAYOUT(ghack_map.canvas)->vadjustment); - gtk_table_attach(GTK_TABLE(table), w, 1, 2, 0, 1, GTK_FILL, - GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0); - gtk_widget_show(w); - - myCanvasGroup = GNOME_CANVAS_GROUP(gnome_canvas_item_new( - gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)), - gnome_canvas_group_get_type(), "x", 0.0, "y", 0.0, NULL)); - - /* Tile the map background with a pretty image */ - background = gdk_imlib_load_image((char *) "mapbg.xpm"); - if (background == NULL) { - g_warning( - "Bummer! Failed to load the map background image (mapbg.xpm)!"); - } else { - gdk_imlib_render(background, background->rgb_width, - background->rgb_height); - - /* Tile the map background */ - for (y = 0; y < height + background->rgb_height; - y += background->rgb_height) { - for (x = 0; x < width + background->rgb_width; - x += background->rgb_width) { - bg = GNOME_CANVAS_IMAGE(gnome_canvas_item_new( - myCanvasGroup, gnome_canvas_image_get_type(), "x", - (double) x, "y", (double) y, "width", - (double) background->rgb_width, "height", - (double) background->rgb_height, "image", background, - "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER, NULL)); - gnome_canvas_item_lower_to_bottom(GNOME_CANVAS_ITEM(bg)); - } - } - } - - /* ghack_map.map is an array of canvas images. Each cell of - * the array will contain one tile. Here, we create the - * space for the cells and then create the cells for easy - * access later. - */ - for (i = 0, y = 0; y < height; y += ghack_glyph_height()) { - for (x = 0; x < width; x += ghack_glyph_width()) { - ghack_map.map[i++] = GNOME_CANVAS_IMAGE(gnome_canvas_item_new( - myCanvasGroup, gnome_canvas_image_get_type(), "x", (double) x, - "y", (double) y, "width", (double) ghack_glyph_width(), - "height", (double) ghack_glyph_height(), "anchor", - GTK_ANCHOR_NORTH_WEST, NULL)); - } - } - - /* Set up the pet mark image */ - petmark = gdk_imlib_create_image_from_xpm_data(pet_mark_xpm); - if (petmark == NULL) { - g_warning("Bummer! Failed to load the pet_mark image!"); - } else { - gdk_imlib_render(petmark, petmark->rgb_width, petmark->rgb_height); - - /* ghack_map.overlay is an array of canvas images used to - * overlay tile images... - */ - for (i = 0, y = 0; y < height; y += ghack_glyph_height()) { - for (x = 0; x < width; x += ghack_glyph_width()) { - ghack_map.overlay[i] = - GNOME_CANVAS_IMAGE(gnome_canvas_item_new( - myCanvasGroup, gnome_canvas_image_get_type(), "x", - (double) x, "y", (double) y, "width", - (double) petmark->rgb_width, "height", - (double) petmark->rgb_height, "image", petmark, - "anchor", GTK_ANCHOR_NORTH_WEST, NULL)); - gnome_canvas_item_lower_to_bottom( - GNOME_CANVAS_ITEM(ghack_map.overlay[i++])); - } - } - } - - /* Resize the canvas when the spinbutton changes - */ - gtk_signal_connect(GTK_OBJECT(adj), "value_changed", - (GtkSignalFunc) ghack_map_window_zoom, - ghack_map.canvas); - - /* Game signals - */ - gtk_signal_connect(GTK_OBJECT(vbox), "ghack_curs", - GTK_SIGNAL_FUNC(ghack_map_cursor_to), NULL); - gtk_signal_connect(GTK_OBJECT(vbox), "ghack_putstr", - GTK_SIGNAL_FUNC(ghack_map_putstr), NULL); - gtk_signal_connect(GTK_OBJECT(vbox), "ghack_print_glyph", - GTK_SIGNAL_FUNC(ghack_map_print_glyph), NULL); - gtk_signal_connect(GTK_OBJECT(vbox), "ghack_clear", - GTK_SIGNAL_FUNC(ghack_map_clear), NULL); - gtk_signal_connect(GTK_OBJECT(vbox), "ghack_display", - GTK_SIGNAL_FUNC(ghack_map_display), NULL); - gtk_signal_connect(GTK_OBJECT(vbox), "ghack_cliparound", - GTK_SIGNAL_FUNC(ghack_map_cliparound), NULL); - gtk_signal_connect(GTK_OBJECT(ghack_map.canvas), "button_press_event", - GTK_SIGNAL_FUNC(ghack_handle_button_press), NULL); - gtk_signal_connect(GTK_OBJECT(ghack_map.canvas), "gnome_delay_output", - GTK_SIGNAL_FUNC(ghack_delay), NULL); - - return GTK_WIDGET(vbox); -} - -/* NAME: - * ghack_map_window_zoom - * - * ARGUMENTS: - * double zoom -- The zoom factor - * - * RETURNS: - * Nothing. - * - * PURPOSE: - * Zoom the map image in and out. This should allow the user to - * dynamically scale the map. Ideally, the background should - * *NOT* scale, but this may be impractical. -*/ - -static void -ghack_map_window_zoom(GtkAdjustment *adj, gpointer data) -{ - if (adj->value > 3.0) - adj->value = 3.0; - if (adj->value < 0.5) - adj->value = 0.5; - ghack_map.zoom = adj->value; - gnome_canvas_set_pixels_per_unit(data, adj->value); -} - -void -ghack_map_cursor_to(GtkWidget *win, int x, int y, gpointer data) -{ - GnomeCanvasGroup *group; - static GnomeCanvasRE *cursor = NULL; - - double x1, y1, x2, y2; - float hp; - guint r, g, b; - - x1 = x * ghack_glyph_width() - 1; - y1 = y * ghack_glyph_height() - 1; - x2 = x1 + ghack_glyph_width() + 2; - y2 = y1 + ghack_glyph_height() + 2; - hp = u.mtimedone ? (u.mhmax ? (float) u.mh / u.mhmax : 1) - : (u.uhpmax ? (float) u.uhp / u.uhpmax : 1); - - r = 255; - g = (hp >= 0.75) ? 255 : (hp >= 0.25 ? 255 * 2 * (hp - 0.25) : 0); - b = (hp >= 0.75) ? 255 * 4 * (hp - 0.75) - : (hp >= 0.25 ? 0 : 255 * 4 * (0.25 - hp)); - - group = gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)); - - if (!cursor) { - cursor = GNOME_CANVAS_RE(gnome_canvas_item_new( - group, gnome_canvas_rect_get_type(), "width_units", 1.0, NULL)); - } - gnome_canvas_item_set(GNOME_CANVAS_ITEM(cursor), "outline_color_rgba", - GNOME_CANVAS_COLOR(r, g, b), "x1", x1, "y1", y1, - "x2", x2, "y2", y2, NULL); - - gnome_canvas_item_raise_to_top(GNOME_CANVAS_ITEM(cursor)); - gnome_canvas_item_show(GNOME_CANVAS_ITEM(cursor)); -} - -void -ghack_map_putstr(GtkWidget *win, int attr, const char *text, gpointer data) -{ - g_warning("Fixme!!! ghack_map_putstr is not implemented"); -} - -/* NAME: - * ghack_map_print_glyph( ) - * - * ARGUMENTS: - * XCHAR_P x, y -- The coordinates where which to print the glyph - * GdkImlibImage* glyph -- The glyph image to print - * - * RETURNS: - * Nothing. - * - * PURPOSE: - * Draw the glyph-tile at the specified coordinates. -*/ - -void -ghack_map_print_glyph(GtkObject *win, guint x, guint y, GdkImlibImage *im, - gpointer data) -{ - GnomeCanvasGroup *group; - int i = y * COLNO + x; - int glyph = glyph_at(x, y); - GnomeCanvasImage *canvas_image = GNOME_CANVAS_IMAGE(ghack_map.map[i]); - - group = gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)); - - gnome_canvas_item_set(GNOME_CANVAS_ITEM(canvas_image), "image", im, NULL); - gnome_canvas_item_show(GNOME_CANVAS_ITEM(canvas_image)); - - canvas_image = GNOME_CANVAS_IMAGE(ghack_map.overlay[i]); - - if (x == u.ux && y == u.uy) - ghack_map_cliparound(NULL, x, y, NULL); - - if (glyph_is_pet(glyph) -#ifdef TEXTCOLOR - && iflags.hilite_pet -#endif - ) { - gnome_canvas_item_raise_to_top(GNOME_CANVAS_ITEM(canvas_image)); - gnome_canvas_item_show(GNOME_CANVAS_ITEM(canvas_image)); - } else { - gnome_canvas_item_hide(GNOME_CANVAS_ITEM(canvas_image)); - } -} - -/* NAME: - * ghack_map_clear( ) - * - * ARGUMENTS: - * NONE - * - * RETURNS: - * Nothing. - * - * PURPOSE: - * Clear the map by hiding all the map tiles. -*/ - -void -ghack_map_clear(GtkWidget *win, gpointer data) -{ - int i; - - for (i = 0; i < ROWNO * COLNO; i++) { - if (GNOME_IS_CANVAS_IMAGE(ghack_map.map[i])) { - gnome_canvas_item_hide(GNOME_CANVAS_ITEM(ghack_map.map[i])); - } - if (GNOME_IS_CANVAS_IMAGE(ghack_map.overlay[i])) { - gnome_canvas_item_hide(GNOME_CANVAS_ITEM(ghack_map.overlay[i])); - } - } - gnome_canvas_update_now(GNOME_CANVAS(ghack_map.canvas)); -} - -void -ghack_map_display(GtkWidget *win, boolean block, gpointer data) -{ - gtk_widget_show_all(GTK_WIDGET(win)); -} - -void -ghack_map_cliparound(GtkWidget *win, int x, int y, gpointer data) -{ - int map_width, map_height; - int to_x, to_y; - int cur_x, cur_y; - int width, height, half_width, half_height; - - x *= ghack_glyph_width() * ghack_map.zoom; - y *= ghack_glyph_height() * ghack_map.zoom; - map_width = COLNO * ghack_glyph_width() * ghack_map.zoom; - map_height = ROWNO * ghack_glyph_height() * ghack_map.zoom; - - gdk_window_get_size(GTK_LAYOUT(ghack_map.canvas)->bin_window, &width, - &height); - gnome_canvas_get_scroll_offsets(ghack_map.canvas, &cur_x, &cur_y); - - half_width = width * 0.5; - half_height = height * 0.5; - - if (((x - cur_x) < (width * 0.25)) || ((x - cur_x) > (width * 0.75))) { - to_x = ((x - half_width) > 0) ? x - half_width : 0; - to_x = ((x + half_width) > map_width) ? map_width - 2 * half_width - : to_x; - } else { - to_x = cur_x; - } - - if (((y - cur_y) < (height * 0.25)) || ((y - cur_y) > (height * 0.75))) { - to_y = ((y - half_height) > 0) ? y - half_height : 0; - to_y = ((y + half_height) > map_height) ? map_height - 2 * half_height - : to_y; - } else { - to_y = cur_y; - } - - if (to_x != cur_x || to_y != cur_y) - gnome_canvas_scroll_to(ghack_map.canvas, to_x, to_y); - // gnome_canvas_update_now ( ghack_map.canvas); -} - -void -ghack_reinit_map_window() -{ - GnomeCanvasImage *bg; - double width, height, x, y; - int i; - - /* ghack_map_clear(NULL, NULL); */ - - width = COLNO * ghack_glyph_width(); - height = ROWNO * ghack_glyph_height(); - - gnome_canvas_set_scroll_region(GNOME_CANVAS(ghack_map.canvas), 0, 0, - width + 2 * ghack_glyph_width(), - height + 2 * ghack_glyph_height()); - - /* remove everything currently in the canvas map */ - gtk_object_destroy(GTK_OBJECT(myCanvasGroup)); - - /* Put some groups back */ - myCanvasGroup = GNOME_CANVAS_GROUP(gnome_canvas_item_new( - gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)), - gnome_canvas_group_get_type(), "x", 0.0, "y", 0.0, NULL)); - - /* Tile the map background with a pretty image */ - if (background != NULL) { - /* Tile the map background */ - for (y = 0; y < height + background->rgb_height; - y += background->rgb_height) { - for (x = 0; x < width + background->rgb_width; - x += background->rgb_width) { - bg = GNOME_CANVAS_IMAGE(gnome_canvas_item_new( - myCanvasGroup, gnome_canvas_image_get_type(), "x", - (double) x, "y", (double) y, "width", - (double) background->rgb_width, "height", - (double) background->rgb_height, "image", background, - "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER, NULL)); - gnome_canvas_item_lower_to_bottom(GNOME_CANVAS_ITEM(bg)); - } - } - } - - /* ghack_map.map is an array of canvas images. Each cell of - * the array will contain one tile. Here, we create the - * space for the cells and then create the cells for easy - * access later. - */ - for (i = 0, y = 0; y < height; y += ghack_glyph_height()) { - for (x = 0; x < width; x += ghack_glyph_width()) { - ghack_map.map[i++] = GNOME_CANVAS_IMAGE(gnome_canvas_item_new( - myCanvasGroup, gnome_canvas_image_get_type(), "x", (double) x, - "y", (double) y, "width", (double) ghack_glyph_width(), - "height", (double) ghack_glyph_height(), "anchor", - GTK_ANCHOR_NORTH_WEST, NULL)); - } - } - - if (petmark != NULL) { - /* ghack_map.overlay is an array of canvas images used to - * overlay tile images... - */ - for (i = 0, y = 0; y < height; y += ghack_glyph_height()) { - for (x = 0; x < width; x += ghack_glyph_width()) { - ghack_map.overlay[i] = - GNOME_CANVAS_IMAGE(gnome_canvas_item_new( - myCanvasGroup, gnome_canvas_image_get_type(), "x", - (double) x, "y", (double) y, "width", - (double) petmark->rgb_width, "height", - (double) petmark->rgb_height, "image", petmark, - "anchor", GTK_ANCHOR_NORTH_WEST, NULL)); - gnome_canvas_item_lower_to_bottom( - GNOME_CANVAS_ITEM(ghack_map.overlay[i++])); - } - } - } - - ghack_map_cliparound(NULL, u.ux, u.uy, NULL); - ghack_map_cursor_to(NULL, u.ux, u.uy, NULL); - gnome_canvas_update_now(ghack_map.canvas); - doredraw(); -} diff --git a/win/gnome/gnmap.h b/win/gnome/gnmap.h deleted file mode 100644 index 6031a9983..000000000 --- a/win/gnome/gnmap.h +++ /dev/null @@ -1,16 +0,0 @@ -/* NetHack 3.6 gnmap.h $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackMapWindow_h -#define GnomeHackMapWindow_h - -#include -#include -#include "config.h" -#include "global.h" - -GtkWidget *ghack_init_map_window(void); -void ghack_reinit_map_window(void); - -#endif /* GnomeHackMapWindow_h */ diff --git a/win/gnome/gnmenu.c b/win/gnome/gnmenu.c deleted file mode 100644 index adcae2f2f..000000000 --- a/win/gnome/gnmenu.c +++ /dev/null @@ -1,741 +0,0 @@ -/* NetHack 3.6 gnmenu.c $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#include -#include -#include -#include "gnmenu.h" -#include "gnmain.h" -#include "gnbind.h" -#include "func_tab.h" - -typedef enum { MenuUnknown = 0, MenuText, MenuMenu } MenuWinType; - -typedef struct { - ANY_P identifier; - gchar accelerator[BUFSZ]; - int itemNumber; - int selected; -} menuItem; - -typedef struct { - int curItem; - int numRows; - int charIdx; - guint32 lastTime; -} extMenu; - -static GdkColor color_blue = { 0, 0, 0, 0xffff }; - -static void -ghack_menu_window_key(GtkWidget *menuWin, GdkEventKey *event, gpointer data) -{ - int i, numRows; - menuItem *item; - MenuWinType isMenu; - - isMenu = (MenuWinType) GPOINTER_TO_INT( - gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu")); - - if (isMenu == MenuMenu) { - GtkWidget *clist; - gint selection_mode; - - clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); - g_assert(clist != NULL); - numRows = GPOINTER_TO_INT( - gtk_object_get_data(GTK_OBJECT(clist), "numRows")); - selection_mode = GPOINTER_TO_INT( - gtk_object_get_data(GTK_OBJECT(clist), "selection_mode")); - for (i = 0; i <= numRows; ++i) { - item = (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), i); - if (item == NULL) - continue; - if (!strcmp(item->accelerator, "")) - continue; - - if ((!strcmp(item->accelerator, event->string)) - || ((selection_mode == GTK_SELECTION_MULTIPLE) - && (event->keyval == ','))) { - if (item->selected) { - gtk_clist_unselect_row(GTK_CLIST(clist), item->itemNumber, - 0); - item->selected = FALSE; - } else { - gtk_clist_select_row(GTK_CLIST(clist), item->itemNumber, - 0); - if (gtk_clist_row_is_visible(GTK_CLIST(clist), - item->itemNumber) - != GTK_VISIBILITY_FULL) - gtk_clist_moveto(GTK_CLIST(clist), item->itemNumber, - 0, 0.5, 0); - item->selected = TRUE; - } - } - } - } -} - -static void -ghack_menu_row_selected(GtkCList *clist, int row, int col, GdkEvent *event) -{ - /* FIXME: Do something */ -} - -void -ghack_menu_window_clear(GtkWidget *menuWin, gpointer data) -{ - MenuWinType isMenu; - int i, numRows; - menuItem *item; - - isMenu = (MenuWinType) GPOINTER_TO_INT( - gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu")); - - if (isMenu == MenuMenu) { - GtkWidget *clist; - - clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); - g_assert(clist != NULL); - - /* destroy existing menu data, if any */ - if (clist) { - /* destroy all the row_data we stored in the clist */ - numRows = GPOINTER_TO_INT( - gtk_object_get_data(GTK_OBJECT(clist), "numRows")); - for (i = 0; i < numRows; i++) { - item = - (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), i); - if (item != NULL) { - g_free(item); - gtk_clist_set_row_data(GTK_CLIST(clist), i, - (gpointer) NULL); - } - } - gtk_object_set_data(GTK_OBJECT(clist), "numItems", - GINT_TO_POINTER(-1)); - gtk_clist_clear(GTK_CLIST(clist)); - } - } - - else if (isMenu == MenuText) { - GnomeLess *gless; - - gless = GNOME_LESS(gtk_object_get_data(GTK_OBJECT(menuWin), "gless")); - g_assert(gless != NULL); - - gtk_editable_delete_text(GTK_EDITABLE(gless->text), 0, 0); - } -} - -void -ghack_menu_window_display(GtkWidget *menuWin, gboolean blocking, - gpointer data) -{ - // if(blocking) { - gnome_dialog_close_hides(GNOME_DIALOG(menuWin), TRUE); - gnome_dialog_set_close(GNOME_DIALOG(menuWin), TRUE); - gnome_dialog_run_and_close(GNOME_DIALOG(menuWin)); - //} - // else { - // gtk_widget_show(menuWin); - //} -} - -gint -ghack_menu_hide(GtkWidget *menuWin, GdkEvent *event, gpointer data) -{ - gtk_widget_hide(menuWin); - return FALSE; /* FIXME: what is correct result here? */ -} - -void -ghack_menu_window_start_menu(GtkWidget *menuWin, gpointer data) -{ - GtkWidget *frame1, *swin, *clist; - MenuWinType isMenu; - - g_assert(menuWin != NULL); - g_assert(data == NULL); - - /* destroy existing menu data, if any */ - frame1 = gtk_object_get_data(GTK_OBJECT(menuWin), "frame1"); - if (frame1) - gtk_widget_destroy(frame1); - - isMenu = MenuMenu; - gtk_object_set_data(GTK_OBJECT(menuWin), "isMenu", - GINT_TO_POINTER(isMenu)); - - gtk_widget_set_usize(GTK_WIDGET(menuWin), 500, 400); - gtk_window_set_policy(GTK_WINDOW(menuWin), TRUE, TRUE, FALSE); - - frame1 = gtk_frame_new("Make your selection"); - g_assert(frame1 != NULL); - gtk_object_set_data(GTK_OBJECT(menuWin), "frame1", frame1); - gtk_widget_show(GTK_WIDGET(frame1)); - gtk_container_set_border_width(GTK_CONTAINER(frame1), 5); - gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(menuWin)->vbox), frame1, TRUE, - TRUE, 0); - - swin = gtk_scrolled_window_new(NULL, NULL); - g_assert(swin != NULL); - gtk_object_set_data(GTK_OBJECT(menuWin), "swin", swin); - gtk_widget_show(GTK_WIDGET(swin)); - gtk_container_add(GTK_CONTAINER(frame1), swin); - - clist = gtk_clist_new(4); - g_assert(clist != NULL); - gtk_object_set_data(GTK_OBJECT(menuWin), "clist", clist); - gtk_widget_show(GTK_WIDGET(clist)); - gtk_container_add(GTK_CONTAINER(swin), clist); - - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - gtk_signal_connect(GTK_OBJECT(clist), "select_row", - GTK_SIGNAL_FUNC(ghack_menu_row_selected), NULL); - gtk_object_set_data(GTK_OBJECT(clist), "numItems", GINT_TO_POINTER(-1)); -} - -int -ghack_menu_window_select_menu(GtkWidget *menuWin, MENU_ITEM_P **_selected, - gint how) -{ - gint rc; - guint num_sel, i, idx; - GtkWidget *clist; - GList *cur; - MENU_ITEM_P *selected = NULL; - menuItem *item; - - g_assert(_selected != NULL); - *_selected = NULL; - - if (how == PICK_NONE) { - gnome_dialog_close_hides(GNOME_DIALOG(menuWin), TRUE); - rc = gnome_dialog_run_and_close(GNOME_DIALOG(menuWin)); - return (rc == 1 ? -1 : 0); - } - - clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); - g_assert(clist != NULL); - - gtk_object_set_data(GTK_OBJECT(clist), "selection_mode", - GINT_TO_POINTER((how == PICK_ANY) - ? GTK_SELECTION_MULTIPLE - : GTK_SELECTION_SINGLE)); - gtk_clist_set_selection_mode(GTK_CLIST(clist), - (how == PICK_ANY) ? GTK_SELECTION_MULTIPLE - : GTK_SELECTION_SINGLE); - gnome_dialog_close_hides(GNOME_DIALOG(menuWin), TRUE); - rc = gnome_dialog_run_and_close(GNOME_DIALOG(menuWin)); - if ((rc == 1) || (GTK_CLIST(clist)->selection == NULL)) { - return (-1); - } - - num_sel = g_list_length(GTK_CLIST(clist)->selection); - if (num_sel < 1) { - return (-1); - } - - /* fill in array with selections from clist */ - selected = g_new0(MENU_ITEM_P, num_sel); - g_assert(selected != NULL); - cur = GTK_CLIST(clist)->selection; - i = 0; - while (cur) { - g_assert(i < num_sel); - - /* grab row number from clist selection list */ - idx = GPOINTER_TO_INT(cur->data); - - item = (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), idx); - selected[i].item = item->identifier; - selected[i].count = -1; - cur = g_list_next(cur); - i++; - } - - *_selected = selected; - - return ((int) num_sel); -} - -void -ghack_menu_window_add_menu(GtkWidget *menuWin, gpointer menu_item, - gpointer data) -{ - GHackMenuItem *item; - GtkWidget *clist; - gchar buf[BUFSZ] = "", accelBuf[BUFSZ] = ""; - gchar *pbuf; - char *text[4] = { buf, NULL, NULL, NULL }; - gint nCurrentRow = -1, numItems = -1; - MenuWinType isMenu; - GtkStyle *bigStyle = NULL; - gboolean item_selectable; - GdkImlibImage *image; - static gboolean special; - - g_assert(menu_item != NULL); - item = (GHackMenuItem *) menu_item; - item_selectable = (item->identifier->a_int == 0) ? FALSE : TRUE; - isMenu = (MenuWinType) GPOINTER_TO_INT( - gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu")); - - clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); - g_assert(clist != NULL); - /* This is a special kludge to make the special hidden help menu item work - * as designed */ - if (special == TRUE) { - special = FALSE; - item_selectable = TRUE; - } - if (!strcmp(item->str, "The NetHack license.")) { - special = TRUE; - } - - if (item->str) { - /* First, make a new blank entry in the clist */ - nCurrentRow = gtk_clist_append(GTK_CLIST(clist), text); - - if (item->glyph != NO_GLYPH) { - image = ghack_image_from_glyph(item->glyph, FALSE); - if (image == NULL || image->pixmap == NULL) { - g_warning("Bummer -- having to force rendering for glyph %d!", - item->glyph); - /* wierd -- pixmap is NULL so retry rendering it */ - image = ghack_image_from_glyph(item->glyph, TRUE); - } - if (image == NULL || image->pixmap == NULL) { - g_error("Aiiee! glyph is still NULL for item\n\"%s\"", - item->str); - } else - gtk_clist_set_pixmap(GTK_CLIST(clist), nCurrentRow, 1, - gdk_imlib_move_image(image), - gdk_imlib_move_mask(image)); - } - if (item->accelerator) { - /* FIXME: handle accelerator, */ - g_snprintf(accelBuf, sizeof(accelBuf), "%c ", item->accelerator); - gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf); - g_snprintf(buf, sizeof(buf), "%s", item->str); - gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 2, buf); - } else { - if (item->group_accel) { - /* FIXME: maybe some day I should try to handle - * group accelerators... */ - } - if (((item->attr == 0) && (item->identifier->a_int != 0)) - || (special == TRUE)) { - numItems = GPOINTER_TO_INT(gtk_object_get_data( - GTK_OBJECT(clist), "numItems")) + 1; - - /* Ok, now invent a unique accelerator */ - if (('a' + numItems) <= 'z') { - g_snprintf(accelBuf, sizeof(accelBuf), "%c ", - 'a' + numItems); - gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, - accelBuf); - } else if (('A' + numItems - 26) <= 'Z') { - g_snprintf(accelBuf, sizeof(accelBuf), "%c ", - 'A' + numItems - 26); - gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, - accelBuf); - } else { - accelBuf[0] = buf[0] = 0; - } - g_snprintf(buf, sizeof(buf), "%s", item->str); - gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 2, buf); - gtk_object_set_data(GTK_OBJECT(clist), "numItems", - GINT_TO_POINTER(numItems)); - - /* This junk is to specially handle the options menu */ - pbuf = strstr(buf, " ["); - if (pbuf == NULL) { - pbuf = strstr(buf, "\t["); - } - if (pbuf != NULL) { - *pbuf = 0; - pbuf++; - gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 3, - pbuf); - } - } - /* FIXME: handle more than 26*2 accelerators (but how? - * since I only have so many keys to work with???) - else - { - foo(); - } - */ - else { - g_snprintf(buf, sizeof(buf), "%s", item->str); - pbuf = strstr(buf, " ["); - if (pbuf == NULL) { - pbuf = strstr(buf, "\t["); - } - if (pbuf != NULL) { - *pbuf = 0; - pbuf++; - gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 3, - pbuf); - } - gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 2, buf); - } - } - - if (item->attr) { - switch (item->attr) { - case ATR_ULINE: - case ATR_BOLD: - case ATR_BLINK: - case ATR_INVERSE: - bigStyle = gtk_style_copy(GTK_WIDGET(clist)->style); - g_assert(bigStyle != NULL); - gdk_font_unref(bigStyle->font); - bigStyle->font = - gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); - bigStyle->fg[GTK_STATE_NORMAL] = color_blue; - gtk_clist_set_cell_style(GTK_CLIST(clist), nCurrentRow, 2, - bigStyle); - item_selectable = FALSE; - } - } - - g_assert(nCurrentRow >= 0); - gtk_clist_set_selectable(GTK_CLIST(clist), nCurrentRow, - item_selectable); - - if (item_selectable == TRUE && item->presel == TRUE) { - /* pre-select this item */ - gtk_clist_select_row(GTK_CLIST(clist), nCurrentRow, 0); - } - - gtk_object_set_data(GTK_OBJECT(clist), "numRows", - GINT_TO_POINTER(nCurrentRow)); - - /* We have to allocate memory here, since the menu_item currently - * lives on the stack, and will otherwise go to the great bit bucket - * in the sky as soon as this function exits, which would leave a - * pointer to crap in the row_data. Use g_memdup to make a private, - * persistant copy of the item identifier. - * - * We need to arrange to blow away this memory somewhere (like - * ghack_menu_destroy and ghack_menu_window_clear for example). - * - * -Erik - */ - { - menuItem newItem; - menuItem *pNewItem; - - newItem.identifier = *item->identifier; - newItem.itemNumber = nCurrentRow; - newItem.selected = FALSE; - newItem.accelerator[0] = 0; - /* only copy 1 char, since accel keys are by definition 1 char */ - if (accelBuf[0]) { - strncpy(newItem.accelerator, accelBuf, 1); - } - newItem.accelerator[1] = 0; - - pNewItem = g_memdup(&newItem, sizeof(menuItem)); - gtk_clist_set_row_data(GTK_CLIST(clist), nCurrentRow, - (gpointer) pNewItem); - } - } - /* Now adjust the column widths to match the contents */ - gtk_clist_columns_autosize(GTK_CLIST(clist)); -} - -void -ghack_menu_window_end_menu(GtkWidget *menuWin, gpointer data) -{ - const char *p = (const char *) data; - - if ((p) && (*p)) { - GtkWidget *frame1 = - gtk_object_get_data(GTK_OBJECT(menuWin), "frame1"); - g_assert(frame1 != NULL); - - gtk_frame_set_label(GTK_FRAME(frame1), p); - } -} - -void -ghack_menu_window_put_string(GtkWidget *menuWin, int attr, const char *text, - gpointer data) -{ - GnomeLess *gless; - MenuWinType isMenu; - - if (text == NULL) - return; - - isMenu = (MenuWinType) GPOINTER_TO_INT( - gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu")); - - if (isMenu == MenuText) { - gless = GNOME_LESS(gtk_object_get_data(GTK_OBJECT(menuWin), "gless")); - g_assert(gless != NULL); - g_assert(gless->text != NULL); - g_assert(GTK_IS_TEXT(gless->text)); - - /* Don't bother with attributes yet */ - gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, text, -1); - gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, "\n", -1); - - } - - else if (isMenu == MenuUnknown) { - isMenu = MenuText; - gtk_object_set_data(GTK_OBJECT(menuWin), "isMenu", - GINT_TO_POINTER(isMenu)); - - gtk_widget_set_usize(GTK_WIDGET(menuWin), 500, 400); - gtk_window_set_policy(GTK_WINDOW(menuWin), TRUE, TRUE, FALSE); - - gless = GNOME_LESS(gnome_less_new()); - g_assert(gless != NULL); - gtk_object_set_data(GTK_OBJECT(menuWin), "gless", gless); - gtk_widget_show(GTK_WIDGET(gless)); - - gnome_less_show_string(gless, text); - gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, "\n", -1); - - gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(menuWin)->vbox), - GTK_WIDGET(gless), TRUE, TRUE, 0); - } -} - -void -ghack_menu_destroy(GtkWidget *menuWin, gpointer data) -{ - MenuWinType isMenu; - - isMenu = (MenuWinType) GPOINTER_TO_INT( - gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu")); - - if (isMenu == MenuText) { - GnomeLess *gless; - - gless = GNOME_LESS(gtk_object_get_data(GTK_OBJECT(menuWin), "gless")); - g_assert(gless != NULL); - g_assert(gless->text != NULL); - g_assert(GTK_IS_TEXT(gless->text)); - gtk_widget_destroy(GTK_WIDGET(gless)); - } - - else if (isMenu == MenuMenu) { - GtkWidget *frame1, *swin, *clist; - - /* destroy existing menu data, if any */ - clist = gtk_object_get_data(GTK_OBJECT(menuWin), "clist"); - if (clist) { - /* destroy all the row_data we stored in the clist */ - int i, numRows; - menuItem *item; - numRows = GPOINTER_TO_INT( - gtk_object_get_data(GTK_OBJECT(clist), "numRows")); - for (i = 0; i < numRows; i++) { - item = - (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), i); - if (item != NULL) { - g_free(item); - gtk_clist_set_row_data(GTK_CLIST(clist), i, - (gpointer) NULL); - } - } - - gtk_object_set_data(GTK_OBJECT(clist), "numItems", - GINT_TO_POINTER(-1)); - gtk_widget_destroy(clist); - } - swin = gtk_object_get_data(GTK_OBJECT(menuWin), "swin"); - if (swin) { - gtk_widget_destroy(swin); - } - frame1 = gtk_object_get_data(GTK_OBJECT(menuWin), "frame1"); - if (frame1) { - gtk_widget_destroy(frame1); - } - } - gnome_delete_nhwindow_by_reference(menuWin); -} - -GtkWidget * -ghack_init_menu_window(void) -{ - GtkWidget *menuWin = NULL; - GtkWidget *parent = ghack_get_main_window(); - - menuWin = gnome_dialog_new("GnomeHack", GNOME_STOCK_BUTTON_OK, - GNOME_STOCK_BUTTON_CANCEL, NULL); - - gnome_dialog_set_default(GNOME_DIALOG(menuWin), 0); - gtk_signal_connect(GTK_OBJECT(menuWin), "destroy", - GTK_SIGNAL_FUNC(ghack_menu_destroy), NULL); - - gtk_signal_connect(GTK_OBJECT(menuWin), "delete_event", - GTK_SIGNAL_FUNC(ghack_menu_hide), NULL); - - gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_clear", - GTK_SIGNAL_FUNC(ghack_menu_window_clear), NULL); - - gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_display", - GTK_SIGNAL_FUNC(ghack_menu_window_display), NULL); - - gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_start_menu", - GTK_SIGNAL_FUNC(ghack_menu_window_start_menu), NULL); - - gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_add_menu", - GTK_SIGNAL_FUNC(ghack_menu_window_add_menu), NULL); - - gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_end_menu", - GTK_SIGNAL_FUNC(ghack_menu_window_end_menu), NULL); - - gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_select_menu", - GTK_SIGNAL_FUNC(ghack_menu_window_select_menu), NULL); - - gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_putstr", - GTK_SIGNAL_FUNC(ghack_menu_window_put_string), NULL); - - gtk_signal_connect(GTK_OBJECT(menuWin), "key_press_event", - GTK_SIGNAL_FUNC(ghack_menu_window_key), NULL); - - /* Center the dialog over parent */ - g_assert(parent != NULL); - g_assert(menuWin != NULL); - g_assert(GTK_IS_WINDOW(parent)); - g_assert(GNOME_IS_DIALOG(menuWin)); - gnome_dialog_set_parent(GNOME_DIALOG(menuWin), GTK_WINDOW(parent)); - - return menuWin; -} - -static void -ghack_ext_key_hit(GtkWidget *menuWin, GdkEventKey *event, gpointer data) -{ - GtkWidget *clist; - extMenu *info = (extMenu *) data; - int i; - char c = event->string[0]; - - clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); - g_assert(clist != NULL); - - /* if too long between keystrokes, reset to initial state */ - if (event->time - info->lastTime > 500) - goto init_state; - - /* see if current item continue to match */ - if (info->charIdx > 0) { - if (extcmdlist[info->curItem].ef_txt[info->charIdx] == c) { - ++info->charIdx; - goto found; - } - } - - /* see if the prefix matches a later command in the list */ - if (info->curItem >= 0) { - for (i = info->curItem + 1; i < info->numRows; ++i) { - if (!strncmp(extcmdlist[info->curItem].ef_txt, - extcmdlist[i].ef_txt, info->charIdx)) { - if (extcmdlist[i].ef_txt[info->charIdx] == c) { - ++info->charIdx; - info->curItem = i; - goto found; - } - } - } - } - -init_state: - /* reset to initial state, look for matching 1st character */ - for (i = 0; i < info->numRows; ++i) { - if (extcmdlist[i].ef_txt[0] == c) { - info->charIdx = 1; - info->curItem = i; - goto found; - } - } - - /* no match: leave prior, if any selection in place */ - return; - -found: - info->lastTime = event->time; - gtk_clist_select_row(GTK_CLIST(clist), info->curItem, 0); - if (gtk_clist_row_is_visible(GTK_CLIST(clist), info->curItem) - != GTK_VISIBILITY_FULL) - gtk_clist_moveto(GTK_CLIST(clist), info->curItem, 0, 0.5, 0); -} - -int -ghack_menu_ext_cmd(void) -{ - int n; - GtkWidget *dialog; - GtkWidget *swin; - GtkWidget *frame1; - GtkWidget *clist; - extMenu info; - - dialog = gnome_dialog_new("Extended Commands", GNOME_STOCK_BUTTON_OK, - GNOME_STOCK_BUTTON_CANCEL, NULL); - gnome_dialog_close_hides(GNOME_DIALOG(dialog), FALSE); - gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event", - GTK_SIGNAL_FUNC(ghack_ext_key_hit), &info); - - frame1 = gtk_frame_new("Make your selection"); - gtk_object_set_data(GTK_OBJECT(dialog), "frame1", frame1); - gtk_widget_show(frame1); - gtk_container_border_width(GTK_CONTAINER(frame1), 3); - - swin = gtk_scrolled_window_new(NULL, NULL); - clist = gtk_clist_new(2); - gtk_object_set_data(GTK_OBJECT(dialog), "clist", clist); - gtk_widget_set_usize(clist, 500, 400); - gtk_container_add(GTK_CONTAINER(swin), clist); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - gtk_signal_connect(GTK_OBJECT(clist), "select_row", - GTK_SIGNAL_FUNC(ghack_menu_row_selected), NULL); - - gtk_container_add(GTK_CONTAINER(frame1), swin); - gtk_box_pack_start_defaults(GTK_BOX(GNOME_DIALOG(dialog)->vbox), frame1); - - /* Add the extended commands into the list here... */ - for (n = 0; extcmdlist[n].ef_txt; ++n) { - const char *text[3] = { extcmdlist[n].ef_txt, extcmdlist[n].ef_desc, - NULL }; - gtk_clist_insert(GTK_CLIST(clist), n, (char **) text); - } - - /* fill in starting info fields */ - info.curItem = -1; - info.numRows = n; - info.charIdx = 0; - info.lastTime = 0; - - gtk_clist_columns_autosize(GTK_CLIST(clist)); - gtk_widget_show_all(swin); - - /* Center the dialog over over parent */ - gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gnome_dialog_set_parent(GNOME_DIALOG(dialog), - GTK_WINDOW(ghack_get_main_window())); - - /* Run the dialog -- returning whichever button was pressed */ - n = gnome_dialog_run_and_close(GNOME_DIALOG(dialog)); - - /* Quit on button 2 or error */ - return (n != 0) ? -1 : info.curItem; -} diff --git a/win/gnome/gnmenu.h b/win/gnome/gnmenu.h deleted file mode 100644 index f6ba3231d..000000000 --- a/win/gnome/gnmenu.h +++ /dev/null @@ -1,31 +0,0 @@ -/* NetHack 3.6 gnmenu.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackMenuWindow_h -#define GnomeHackMenuWindow_h - -#include -#include "config.h" -#include "global.h" -#include "gnomeprv.h" - -GtkWidget *ghack_init_menu_window(void); - -struct _GHackMenuItem { - int glyph; - const ANY_P *identifier; - CHAR_P accelerator; - CHAR_P group_accel; - int attr; - const char *str; - BOOLEAN_P presel; -}; - -typedef struct _GHackMenuItem GHackMenuItem; - -int ghack_menu_window_select_menu(GtkWidget *menuWin, MENU_ITEM_P **_selected, - gint how); -int ghack_menu_ext_cmd(void); - -#endif /* GnomeHackMenuWindow_h */ diff --git a/win/gnome/gnmesg.c b/win/gnome/gnmesg.c deleted file mode 100644 index 652e17456..000000000 --- a/win/gnome/gnmesg.c +++ /dev/null @@ -1,99 +0,0 @@ -/* NetHack 3.6 gnmesg.c $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gnmesg.h" -#include "gnsignal.h" - -/* Pick an arbitrary number of chars such as 80 col X 40 rows text = 3200 - * chars */ -#define nCharsBeforeDeletingStuff 3200 - -/* Message Window widgets */ -GtkWidget *MW_table; -GtkWidget *MW_text; -GtkWidget *MW_scrollbar; - -void -ghack_message_window_clear(GtkWidget *widget, gpointer data) -{ - /* Seems nethack calls this after every move -- we don't want - * to really clear the window at all though. Ignore the request */ - gint len; - - len = gtk_text_get_length(GTK_TEXT(MW_text)); - - if (len < nCharsBeforeDeletingStuff) - return; - - gtk_text_freeze(GTK_TEXT(MW_text)); - gtk_text_set_point(GTK_TEXT(MW_text), 0); - gtk_text_forward_delete(GTK_TEXT(MW_text), - len - ((guint)(nCharsBeforeDeletingStuff * 0.5))); - gtk_text_set_point(GTK_TEXT(MW_text), - (guint)(nCharsBeforeDeletingStuff * 0.5)); - gtk_text_thaw(GTK_TEXT(MW_text)); -} - -void -ghack_message_window_destroy(GtkWidget *win, gpointer data) -{ -} - -void -ghack_message_window_display(GtkWidget *widget, boolean block, gpointer data) -{ -} - -void -ghack_message_window_put_string(GtkWidget *widget, int attr, const char *text, - gpointer data) -{ - if (text == NULL) - return; - - /* Don't bother with attributes yet */ - gtk_text_insert(GTK_TEXT(MW_text), NULL, NULL, NULL, text, -1); - gtk_text_insert(GTK_TEXT(MW_text), NULL, NULL, NULL, "\n", -1); -} - -void -ghack_message_window_use_RIP(int how) -{ -} - -void -ghack_message_window_scroll(int dx, int dy) -{ -} - -GtkWidget * -ghack_init_message_window(void) -{ - MW_table = gtk_table_new(2, 1, FALSE); - gtk_table_set_row_spacing(GTK_TABLE(MW_table), 0, 2); - - MW_text = gtk_text_new(NULL, NULL); - gtk_text_set_editable(GTK_TEXT(MW_text), FALSE); - gtk_text_set_word_wrap(GTK_TEXT(MW_text), TRUE); - gtk_table_attach(GTK_TABLE(MW_table), MW_text, 0, 1, 0, 1, - (GTK_EXPAND | GTK_FILL), (GTK_EXPAND | GTK_FILL), 0, 0); - - MW_scrollbar = gtk_vscrollbar_new(GTK_TEXT(MW_text)->vadj); - gtk_table_attach(GTK_TABLE(MW_table), MW_scrollbar, 1, 2, 0, 1, GTK_FILL, - (GTK_EXPAND | GTK_FILL), 0, 0); - - gtk_signal_connect(GTK_OBJECT(MW_table), "ghack_putstr", - GTK_SIGNAL_FUNC(ghack_message_window_put_string), - NULL); - - gtk_signal_connect(GTK_OBJECT(MW_table), "ghack_clear", - GTK_SIGNAL_FUNC(ghack_message_window_clear), NULL); - - gtk_signal_connect(GTK_OBJECT(MW_table), "gnome_delay_output", - GTK_SIGNAL_FUNC(ghack_delay), NULL); - - gtk_widget_show_all(MW_table); - - return GTK_WIDGET(MW_table); -} diff --git a/win/gnome/gnmesg.h b/win/gnome/gnmesg.h deleted file mode 100644 index 8608216a7..000000000 --- a/win/gnome/gnmesg.h +++ /dev/null @@ -1,22 +0,0 @@ -/* NetHack 3.6 gnmesg.h $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackMessageWindow_h -#define GnomeHackMessageWindow_h - -#include -#include "config.h" - -GtkWidget *ghack_init_message_window(/* GnomeHackKeyBuffer g_keybuffer, - GnomeHackClickBuffer g_clickbuffer */); -void ghack_message_window_clear(GtkWidget *widget, gpointer data); -void ghack_message_window_destroy(); -void ghack_message_window_display(GtkWidget *widget, boolean block, - gpointer data); -void ghack_message_window_put_string(GtkWidget *widget, int attr, - const char *text, gpointer data); -void ghack_message_window_use_RIP(int how); -void ghack_message_window_scroll(int dx, int dy); - -#endif /* GnomeHackMessageWindow_h */ diff --git a/win/gnome/gnomeprv.h b/win/gnome/gnomeprv.h deleted file mode 100644 index d6ecbbb87..000000000 --- a/win/gnome/gnomeprv.h +++ /dev/null @@ -1,15 +0,0 @@ -/* NetHack 3.6 gnomeprv.h $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHack_h -#define GnomeHack_h - -/* These are the base nethack include files */ -#include "hack.h" -#include "dlb.h" -#include "patchlevel.h" - -#include "winGnome.h" - -#endif /* GnomeHack_h */ diff --git a/win/gnome/gnopts.c b/win/gnome/gnopts.c deleted file mode 100644 index 8cae327e1..000000000 --- a/win/gnome/gnopts.c +++ /dev/null @@ -1,114 +0,0 @@ -/* NetHack 3.6 gnopts.c $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gnopts.h" -#include "gnglyph.h" -#include "gnmain.h" -#include "gnmap.h" -#include -#include -#include "hack.h" - -static gint tileset; -static GtkWidget *clist; -const char *tilesets[] = { "Traditional (16x16)", "Big (32x32)", 0 }; - -static void -opt_sel_key_hit(GtkWidget *widget, GdkEventKey *event, gpointer data) -{ - int i; - for (i = 0; tilesets[i] != 0; ++i) { - if (tilesets[i][0] == toupper(event->keyval)) { - tileset = i; - gtk_clist_select_row(GTK_CLIST(clist), i, 0); - } - } -} - -static void -opt_sel_row_selected(GtkCList *cList, int row, int col, GdkEvent *event) -{ - tileset = row; -} - -void -ghack_settings_dialog() -{ - int i; - static GtkWidget *dialog; - static GtkWidget *swin; - static GtkWidget *frame1; - - dialog = gnome_dialog_new(_("GnomeHack Settings"), GNOME_STOCK_BUTTON_OK, - GNOME_STOCK_BUTTON_CANCEL, NULL); - gnome_dialog_close_hides(GNOME_DIALOG(dialog), FALSE); - gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event", - GTK_SIGNAL_FUNC(opt_sel_key_hit), tilesets); - - frame1 = gtk_frame_new(_("Choose one of the following tilesets:")); - gtk_object_set_data(GTK_OBJECT(dialog), "frame1", frame1); - gtk_widget_show(frame1); - gtk_container_border_width(GTK_CONTAINER(frame1), 3); - - swin = gtk_scrolled_window_new(NULL, NULL); - clist = gtk_clist_new(2); - gtk_clist_column_titles_hide(GTK_CLIST(clist)); - gtk_widget_set_usize(GTK_WIDGET(clist), 100, 180); - gtk_container_add(GTK_CONTAINER(swin), clist); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - gtk_signal_connect(GTK_OBJECT(clist), "select_row", - GTK_SIGNAL_FUNC(opt_sel_row_selected), NULL); - - gtk_container_add(GTK_CONTAINER(frame1), swin); - gtk_box_pack_start_defaults(GTK_BOX(GNOME_DIALOG(dialog)->vbox), frame1); - - /* Add the tilesets into the list here... */ - for (i = 0; tilesets[i]; i++) { - gchar accelBuf[BUFSZ]; - const char *text[3] = { accelBuf, tilesets[i], NULL }; - sprintf(accelBuf, "%c ", tolower(tilesets[i][0])); - gtk_clist_insert(GTK_CLIST(clist), i, (char **) text); - } - - gtk_clist_columns_autosize(GTK_CLIST(clist)); - gtk_widget_show_all(swin); - - /* Center the dialog over over parent */ - gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gnome_dialog_set_parent(GNOME_DIALOG(dialog), - GTK_WINDOW(ghack_get_main_window())); - - /* Run the dialog -- returning whichever button was pressed */ - i = gnome_dialog_run(GNOME_DIALOG(dialog)); - gnome_dialog_close(GNOME_DIALOG(dialog)); - - /* They hit Quit or error */ - if (i != 0) { - return; - } - switch (tileset) { - case 0: - /* They selected traditional */ - ghack_free_glyphs(); - if (ghack_init_glyphs(HACKDIR "/x11tiles")) - g_error("ERROR: Could not initialize glyphs.\n"); - ghack_reinit_map_window(); - break; - case 1: - ghack_free_glyphs(); - if (ghack_init_glyphs(HACKDIR "/t32-1024.xpm")) - g_error("ERROR: Could not initialize glyphs.\n"); - ghack_reinit_map_window(); - - /* They selected big */ - break; - default: - /* This shouldn't happen */ - g_warning("This shouldn't happen\n"); - } -} diff --git a/win/gnome/gnopts.h b/win/gnome/gnopts.h deleted file mode 100644 index e6fec0c77..000000000 --- a/win/gnome/gnopts.h +++ /dev/null @@ -1,10 +0,0 @@ -/* NetHack 3.6 gnopts.h $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackSettings_h -#define GnomeHackSettings_h - -void ghack_settings_dialog(void); - -#endif /* GnomeHackSettings.h */ diff --git a/win/gnome/gnplayer.c b/win/gnome/gnplayer.c deleted file mode 100644 index d14fa4bec..000000000 --- a/win/gnome/gnplayer.c +++ /dev/null @@ -1,100 +0,0 @@ -/* NetHack 3.6 gnplayer.c $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#include -#include -#include "gnplayer.h" -#include "gnmain.h" -#include "hack.h" - -static gint role_number; -static GtkWidget *clist; - -static void -player_sel_key_hit(GtkWidget *widget, GdkEventKey *event, gpointer data) -{ - const char **roles = data; - int i; - for (i = 0; roles[i] != 0; ++i) { - if (tolower(roles[i][0]) == tolower(event->keyval)) { - role_number = i; - gtk_clist_select_row(GTK_CLIST(clist), i, 0); - if (gtk_clist_row_is_visible(GTK_CLIST(clist), i) - != GTK_VISIBILITY_FULL) - gtk_clist_moveto(GTK_CLIST(clist), i, 0, 0.5, 0); - } - } -} - -static void -player_sel_row_selected(GtkCList *clist, int row, int col, GdkEvent *event) -{ - role_number = row; -} - -int -ghack_player_sel_dialog(const char **choices, const gchar *title, - const gchar *prompt) -{ - int i; - static GtkWidget *dialog; - static GtkWidget *swin; - static GtkWidget *frame1; - - dialog = gnome_dialog_new(title, GNOME_STOCK_BUTTON_OK, _("Random"), - GNOME_STOCK_BUTTON_CANCEL, NULL); - gnome_dialog_close_hides(GNOME_DIALOG(dialog), FALSE); - gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event", - GTK_SIGNAL_FUNC(player_sel_key_hit), choices); - - frame1 = gtk_frame_new(prompt); - gtk_object_set_data(GTK_OBJECT(dialog), "frame1", frame1); - gtk_widget_show(frame1); - gtk_container_border_width(GTK_CONTAINER(frame1), 3); - - swin = gtk_scrolled_window_new(NULL, NULL); - clist = gtk_clist_new(2); - gtk_clist_column_titles_hide(GTK_CLIST(clist)); - gtk_widget_set_usize(GTK_WIDGET(clist), 100, 180); - gtk_container_add(GTK_CONTAINER(swin), clist); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - gtk_signal_connect(GTK_OBJECT(clist), "select_row", - GTK_SIGNAL_FUNC(player_sel_row_selected), NULL); - - gtk_container_add(GTK_CONTAINER(frame1), swin); - gtk_box_pack_start_defaults(GTK_BOX(GNOME_DIALOG(dialog)->vbox), frame1); - - /* Add the roles into the list here... */ - for (i = 0; choices[i]; i++) { - gchar accelBuf[BUFSZ]; - const char *text[3] = { accelBuf, choices[i], NULL }; - sprintf(accelBuf, "%c ", tolower(choices[i][0])); - gtk_clist_insert(GTK_CLIST(clist), i, (char **) text); - } - - gtk_clist_columns_autosize(GTK_CLIST(clist)); - gtk_widget_show_all(swin); - - /* Center the dialog over over parent */ - gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); - gnome_dialog_set_parent(GNOME_DIALOG(dialog), - GTK_WINDOW(ghack_get_main_window())); - - /* Run the dialog -- returning whichever button was pressed */ - i = gnome_dialog_run_and_close(GNOME_DIALOG(dialog)); - - /* Quit on button 2 or error */ - if (i < 0 || i > 1) { - return (ROLE_NONE); - } - /* Random is button 1*/ - if (i == 1) { - return (ROLE_RANDOM); - } - return (role_number); -} diff --git a/win/gnome/gnplayer.h b/win/gnome/gnplayer.h deleted file mode 100644 index d004f190b..000000000 --- a/win/gnome/gnplayer.h +++ /dev/null @@ -1,10 +0,0 @@ -/* NetHack 3.6 gnplayer.h $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackPlayerSelDialog_h -#define GnomeHackPlayerSelDialog_h - -int ghack_player_sel_dialog(const char **, const gchar *, const gchar *); - -#endif /* GnomeHackPlayerSelDialog_h */ diff --git a/win/gnome/gnsignal.c b/win/gnome/gnsignal.c deleted file mode 100644 index d9accadc3..000000000 --- a/win/gnome/gnsignal.c +++ /dev/null @@ -1,399 +0,0 @@ -/* NetHack 3.6 gnsignal.c $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ -/* Copyright (C) 1998 by Anthony Taylor */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gnsignal.h" -#include "gnmain.h" -#include - -GList *g_keyBuffer; -GList *g_clickBuffer; -int g_numKeys = 0; -int g_numClicks = 0; -int g_askingQuestion = 0; -static int s_done = FALSE; - -/* - * ghack_init_signals - * - * Create some signals and attach them to the GtkWidget class. - * These are the signals: - * - * ghack_curs : NONE:INT,INT - * INT 1 = x - * INT 2 = y - * - * ghack_putstr : NONE:INT,POINTER - * INT = attribute - * POINTER = char* string to print - * - * ghack_print_glyph : NONE:INT,INT,POINTER - * INT 1 = x - * INT 2 = y - * INT 3 = GtkPixmap* to rendered glyph - * - * ghack_clear : NONE:NONE - * - * ghack_display : NONE:BOOL - * BOOL = blocking flag - * - * ghack_start_menu : NONE:NONE - * - * ghack_add_menu : NONE:POINTER - * POINTER = GHackMenuItem* - * - * ghack_end_menu : NONE:POINTER - * POINTER = char* to closing string - * - * ghack_select_menu : NONE:POINTER,INT,POINTER - * POINTER = int pointer-- filled with number - * of selected items on return - * INT = number of items selected - * POINTER = structure to fill - * - * ghack_cliparound : NONE:INT,INT - * INT 1 = x - * INT 2 = y -*/ - -void -ghack_init_signals(void) -{ - ghack_signals[GHSIG_CURS] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_curs", GTK_RUN_FIRST, - gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2, GTK_TYPE_INT, - GTK_TYPE_INT); - - ghack_signals[GHSIG_PUTSTR] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_putstr", GTK_RUN_FIRST, - gtk_marshal_NONE__INT_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_INT, - GTK_TYPE_POINTER); - - ghack_signals[GHSIG_PRINT_GLYPH] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_print_glyph", - GTK_RUN_FIRST, gtk_marshal_NONE__INT_INT_POINTER, GTK_TYPE_NONE, 3, - GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER); - - ghack_signals[GHSIG_CLEAR] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_clear", GTK_RUN_FIRST, - gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); - - ghack_signals[GHSIG_DISPLAY] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_display", GTK_RUN_FIRST, - gtk_marshal_NONE__BOOL, GTK_TYPE_NONE, 1, GTK_TYPE_BOOL); - - ghack_signals[GHSIG_START_MENU] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_start_menu", - GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); - - ghack_signals[GHSIG_ADD_MENU] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_add_menu", - GTK_RUN_FIRST, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, - GTK_TYPE_POINTER); - - ghack_signals[GHSIG_END_MENU] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_end_menu", - GTK_RUN_FIRST, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, - GTK_TYPE_POINTER); - - ghack_signals[GHSIG_SELECT_MENU] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_select_menu", - GTK_RUN_FIRST, gtk_marshal_NONE__POINTER_INT_POINTER, GTK_TYPE_NONE, - 3, GTK_TYPE_POINTER, GTK_TYPE_INT, GTK_TYPE_POINTER); - - ghack_signals[GHSIG_CLIPAROUND] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_cliparound", - GTK_RUN_FIRST, gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2, - GTK_TYPE_INT, GTK_TYPE_INT); - - ghack_signals[GHSIG_FADE_HIGHLIGHT] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "ghack_fade_highlight", - GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); - - ghack_signals[GHSIG_DELAY] = gtk_object_class_user_signal_new( - gtk_type_class(gtk_widget_get_type()), "gnome_delay_output", - GTK_RUN_FIRST, gtk_marshal_NONE__INT, GTK_TYPE_NONE, 1, GTK_TYPE_INT); -} - -/* For want of a better place, I'm putting the delay output stuff here - * -Erik - */ -static gint -timeout_callback(gpointer data) -{ - s_done = TRUE; - return FALSE; -} - -void -ghack_delay(GtkWidget *win, int numMillisecs, gpointer data) -{ - s_done = FALSE; - gtk_timeout_add((unsigned int) numMillisecs, timeout_callback, NULL); - while (s_done == FALSE) - gtk_main_iteration(); -} - -void -ghack_handle_button_press(GtkWidget *widget, GdkEventButton *event, - gpointer data) -{ - GHClick *click; - double x1, y1; - - if (event->type != GDK_BUTTON_PRESS) - return; - - gnome_canvas_window_to_world(GNOME_CANVAS(widget), event->x, event->y, - &x1, &y1); - /* - g_message("I got a click at %f,%f with button %d \n", - x1, y1, event->button); - */ - - /* We allocate storage here, so we need to remember if (g_numClicks>0) - * to blow this away when closing the app using something like - * while (g_clickBuffer) - * { - * g_free((GHClick)g_clickBuffer->data); - * g_clickBuffer = g_clickBuffer->next; - * } - * g_list_free( g_clickBuffer ); - * - */ - click = g_new(GHClick, 1); - - click->x = (int) x1 / ghack_glyph_width(); - click->y = (int) y1 / ghack_glyph_height(); - click->mod = (event->button == 1) ? CLICK_1 : CLICK_2; - - g_clickBuffer = g_list_prepend(g_clickBuffer, click); - /* Could use g_list_length(), but it is stupid and just - * traverses the list while counting, so we'll just do - * the counting ourselves in advance. */ - g_numClicks++; -} - -#ifndef M -#ifndef NHSTDC -#define M(c) (0x80 | (c)) -#else -#define M(c) ((c) -128) -#endif /* NHSTDC */ -#endif -#ifndef C -#define C(c) (0x1f & (c)) -#endif - -void -ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) -{ - static int was_pound = 0; - int key = 0; - int ctl = GDK_CONTROL_MASK; - int alt = GDK_MOD1_MASK; - -/* Turn this on to debug key events */ -#if 0 - g_message("I got a \"%s\" key (%d) %s%s", - gdk_keyval_name (event->keyval), event->keyval, - (event->state&ctl)? "+CONTROL":"", (event->state&alt)? "+ALT":""); -#endif - - switch (event->keyval) { - /* special keys to do stuff with */ - - /* Set up the direction keys */ - - /* First handle the arrow keys -- these always mean move */ - case GDK_Right: - case GDK_rightarrow: - key = Cmd.move_E; - break; - case GDK_Left: - case GDK_leftarrow: - key = Cmd.move_W; - break; - case GDK_Up: - case GDK_uparrow: - key = Cmd.move_N; - break; - case GDK_Down: - case GDK_downarrow: - key = Cmd.move_S; - break; - case GDK_Home: - key = Cmd.move_NW; - break; - case GDK_End: - key = Cmd.move_SW; - break; - case GDK_Page_Down: - key = Cmd.move_SE; - break; - case GDK_Page_Up: - key = Cmd.move_NE; - break; - case ' ': - key = '.'; - break; - - /* Now, handle the numberpad (move or numbers) */ - case GDK_KP_Right: - case GDK_KP_6: - if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) - && iflags.num_pad) - key = GDK_KP_6; - else - key = '6'; - break; - - case GDK_KP_Left: - case GDK_KP_4: - if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) - && iflags.num_pad) - key = GDK_KP_4; - else - key = '4'; - break; - - case GDK_KP_Up: - case GDK_KP_8: - if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) - && iflags.num_pad) - key = GDK_KP_8; - else - key = '8'; - break; - - case GDK_KP_Down: - case GDK_KP_2: - if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) - && iflags.num_pad) - key = GDK_KP_2; - else - key = '2'; - break; - - /* Move Top-Left */ - case GDK_KP_Home: - case GDK_KP_7: - if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) - && iflags.num_pad) - key = GDK_KP_7; - else - key = '7'; - break; - - case GDK_KP_Page_Up: - case GDK_KP_9: - if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) - && iflags.num_pad) - key = GDK_KP_9; - else - key = '9'; - break; - - case GDK_KP_End: - case GDK_KP_1: - if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) - && iflags.num_pad) - key = GDK_KP_1; - else - key = '1'; - break; - - case GDK_KP_Page_Down: - case GDK_KP_3: - if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) - && iflags.num_pad) - key = GDK_KP_3; - else - key = '3'; - break; - - case GDK_KP_5: - if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) - && iflags.num_pad) - key = GDK_KP_5; - else - key = '5'; - break; - - case GDK_KP_Delete: - case GDK_KP_Decimal: - key = '.'; - break; - - /* can't just ignore "#", it's a core feature */ - case GDK_numbersign: - key = '#'; - break; - - /* We will probably want to do something with these later... */ - case GDK_KP_Begin: - case GDK_KP_F1: - case GDK_F1: - case GDK_KP_F2: - case GDK_F2: - case GDK_KP_F3: - case GDK_F3: - case GDK_KP_F4: - case GDK_F4: - case GDK_F5: - case GDK_F6: - case GDK_F7: - case GDK_F8: - case GDK_F9: - case GDK_F10: - case GDK_F11: - case GDK_F12: - break; - /* various keys to ignore */ - case GDK_KP_Insert: - case GDK_Insert: - case GDK_Delete: - case GDK_Print: - case GDK_BackSpace: - case GDK_Pause: - case GDK_Scroll_Lock: - case GDK_Shift_Lock: - case GDK_Num_Lock: - case GDK_Caps_Lock: - case GDK_Control_L: - case GDK_Control_R: - case GDK_Shift_L: - case GDK_Shift_R: - case GDK_Alt_L: - case GDK_Alt_R: - case GDK_Meta_L: - case GDK_Meta_R: - case GDK_Mode_switch: - case GDK_Multi_key: - return; - - default: - key = event->keyval; - break; - } - - if ((event->state & alt) || was_pound) { - key = M(event->keyval); - } else if (event->state & ctl) { - key = C(event->keyval); - } - if (was_pound) { - was_pound = 0; - } - - /* Ok, here is where we do clever stuff to overide the default - * game behavior */ - if (g_askingQuestion == 0) { - if (key == 'S' || key == M('S') || key == C('S')) { - ghack_save_game_cb(NULL, NULL); - return; - } - } - g_keyBuffer = g_list_prepend(g_keyBuffer, GINT_TO_POINTER(key)); - g_numKeys++; -} diff --git a/win/gnome/gnsignal.h b/win/gnome/gnsignal.h deleted file mode 100644 index 9e65b5d3a..000000000 --- a/win/gnome/gnsignal.h +++ /dev/null @@ -1,53 +0,0 @@ -/* NetHack 3.6 gnsignal.h $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Anthony Taylor */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackSignals_h -#define GnomeHackSignals_h - -#include -#include -#include "gnomeprv.h" -#include "gnglyph.h" - -/* The list of custom signals */ - -enum { - GHSIG_CURS, - GHSIG_PUTSTR, - GHSIG_PRINT_GLYPH, - GHSIG_CLEAR, - GHSIG_DISPLAY, - GHSIG_START_MENU, - GHSIG_ADD_MENU, - GHSIG_END_MENU, - GHSIG_SELECT_MENU, - GHSIG_CLIPAROUND, - GHSIG_FADE_HIGHLIGHT, - GHSIG_DELAY, - GHSIG_LAST_SIG -}; - -guint ghack_signals[GHSIG_LAST_SIG]; - -extern void ghack_init_signals(void); - -void ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, - gpointer data); -void ghack_handle_button_press(GtkWidget *widget, GdkEventButton *event, - gpointer data); - -typedef struct { - int x, y, mod; -} GHClick; - -extern GList *g_keyBuffer; -extern GList *g_clickBuffer; -extern int g_numKeys; -extern int g_numClicks; - -extern int g_askingQuestion; - -void ghack_delay(GtkWidget *win, int numMillisecs, gpointer data); - -#endif /* GnomeHackSignals_h */ diff --git a/win/gnome/gnstatus.c b/win/gnome/gnstatus.c deleted file mode 100644 index 6cde95bac..000000000 --- a/win/gnome/gnstatus.c +++ /dev/null @@ -1,908 +0,0 @@ -/* NetHack 3.6 gnstatus.c $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gnstatus.h" -#include "gnsignal.h" -#include "gn_xpms.h" -#include "gnomeprv.h" - -extern const char *hu_stat[]; /* from eat.c */ -extern const char *enc_stat[]; /* from botl.c */ - -void ghack_status_window_update_stats(); -void ghack_status_window_clear(GtkWidget *win, gpointer data); -void ghack_status_window_destroy(GtkWidget *win, gpointer data); -void ghack_status_window_display(GtkWidget *win, boolean block, - gpointer data); -void ghack_status_window_cursor_to(GtkWidget *win, int x, int y, - gpointer data); -void ghack_status_window_put_string(GtkWidget *win, int attr, - const char *text, gpointer data); - -static void ghack_fade_highlighting(); -static void ghack_highlight_widget(GtkWidget *widget, GtkStyle *oldStyle, - GtkStyle *newStyle); - -/* some junk to handle when to fade the highlighting */ -#define NUM_TURNS_HIGHLIGHTED 3 - -static GList *s_HighLightList; - -typedef struct { - GtkWidget *widget; - GtkStyle *oldStyle; - int nTurnsLeft; -} Highlight; - -/* Ok, now for a LONG list of widgets... */ -static GtkWidget *statTable = NULL; -static GtkWidget *titleLabel = NULL; -static GtkWidget *dgnLevelLabel = NULL; -static GtkWidget *strPix = NULL; -static GtkWidget *strLabel = NULL; -static GtkWidget *dexPix = NULL; -static GtkWidget *dexLabel = NULL; -static GtkWidget *intPix = NULL; -static GtkWidget *intLabel = NULL; -static GtkWidget *wisPix = NULL; -static GtkWidget *wisLabel = NULL; -static GtkWidget *conPix = NULL; -static GtkWidget *conLabel = NULL; -static GtkWidget *chaPix = NULL; -static GtkWidget *chaLabel = NULL; -static GtkWidget *goldLabel = NULL; -static GtkWidget *hpLabel = NULL; -static GtkWidget *powLabel = NULL; -static GtkWidget *acLabel = NULL; -static GtkWidget *levlLabel = NULL; -static GtkWidget *expLabel = NULL; -static GtkWidget *timeLabel = NULL; -static GtkWidget *scoreLabel = NULL; -static GtkWidget *alignPix = NULL; -static GtkWidget *alignLabel = NULL; -static GtkWidget *hungerPix = NULL; -static GtkWidget *hungerLabel = NULL; -static GtkWidget *sickPix = NULL; -static GtkWidget *sickLabel = NULL; -static GtkWidget *blindPix = NULL; -static GtkWidget *blindLabel = NULL; -static GtkWidget *stunPix = NULL; -static GtkWidget *stunLabel = NULL; -static GtkWidget *halluPix = NULL; -static GtkWidget *halluLabel = NULL; -static GtkWidget *confuPix = NULL; -static GtkWidget *confuLabel = NULL; -static GtkWidget *encumbPix = NULL; -static GtkWidget *encumbLabel = NULL; - -static GtkStyle *normalStyle = NULL; -static GtkStyle *bigStyle = NULL; -static GtkStyle *redStyle = NULL; -static GtkStyle *greenStyle = NULL; -static GtkStyle *bigRedStyle = NULL; -static GtkStyle *bigGreenStyle = NULL; - -/* Pure red */ -static GdkColor color_red = { 0, 0xff00, 0, 0 }; -/* ForestGreen (looks better than just pure green) */ -static GdkColor color_green = { 0, 0x2200, 0x8b00, 0x2200 }; - -static int lastDepth; -static int lastStr; -static int lastInt; -static int lastWis; -static int lastDex; -static int lastCon; -static int lastCha; -static long lastAu; -static int lastHP; -static int lastMHP; -static int lastLevel; -static int lastPOW; -static int lastMPOW; -static int lastAC; -static int lastExp; -static aligntyp lastAlignment; -static unsigned lastHungr; -static long lastConf; -static long lastBlind; -static long lastStun; -static long lastHalu; -static long lastSick; -static int lastEncumb; - -void -ghack_status_window_clear(GtkWidget *win, gpointer data) -{ - /* Don't think we need this at all */ -} - -void -ghack_status_window_destroy(GtkWidget *win, gpointer data) -{ - while (s_HighLightList) { - g_free((Highlight *) s_HighLightList->data); - s_HighLightList = s_HighLightList->next; - } - g_list_free(s_HighLightList); -} - -void -ghack_status_window_display(GtkWidget *win, boolean block, gpointer data) -{ - gtk_widget_show_all(GTK_WIDGET(win)); -} - -void -ghack_status_window_cursor_to(GtkWidget *win, int x, int y, gpointer data) -{ - /* Don't think we need this at all */ -} - -void -ghack_status_window_put_string(GtkWidget *win, int attr, const char *text, - gpointer data) -{ - ghack_status_window_update_stats(); -} - -GtkWidget * -ghack_init_status_window() -{ - GtkWidget *horizSep0, *horizSep1, *horizSep2, *horizSep3; - GtkWidget *statsHBox, *strVBox, *dexVBox, *intVBox, *statHBox; - GtkWidget *wisVBox, *conVBox, *chaVBox; - GtkWidget *alignVBox, *hungerVBox, *sickVBox, *blindVBox; - GtkWidget *stunVBox, *halluVBox, *confuVBox, *encumbVBox; - - /* Set up a (ridiculous) initial state */ - lastDepth = 9999; - lastStr = 9999; - lastInt = 9999; - lastWis = 9999; - lastDex = 9999; - lastCon = 9999; - lastCha = 9999; - lastAu = 9999; - lastHP = 9999; - lastMHP = 9999; - lastLevel = 9999; - lastPOW = 9999; - lastMPOW = 9999; - lastAC = 9999; - lastExp = 9999; - lastAlignment = A_NEUTRAL; /* start off guessing neutral */ - lastHungr = 9999; - lastConf = 9999; - lastBlind = 9999; - lastStun = 9999; - lastHalu = 9999; - lastSick = 9999; - lastEncumb = 9999; - - statTable = gtk_table_new(10, 8, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(statTable), 1); - gtk_table_set_col_spacings(GTK_TABLE(statTable), 1); - - /* Begin the first row of the table -- the title */ - titleLabel = gtk_label_new(_("GnomeHack!")); - gtk_table_attach(GTK_TABLE(statTable), titleLabel, 0, 8, 0, 1, GTK_FILL, - 0, 0, 0); - if (!normalStyle) - normalStyle = - gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(titleLabel))); - - /* Set up some styles to draw stuff with */ - if (!redStyle) { - g_assert(greenStyle == NULL); - g_assert(bigStyle == NULL); - g_assert(bigRedStyle == NULL); - g_assert(bigGreenStyle == NULL); - - greenStyle = gtk_style_copy(normalStyle); - redStyle = gtk_style_copy(normalStyle); - bigRedStyle = gtk_style_copy(normalStyle); - bigGreenStyle = gtk_style_copy(normalStyle); - bigStyle = gtk_style_copy(normalStyle); - - greenStyle->fg[GTK_STATE_NORMAL] = color_green; - redStyle->fg[GTK_STATE_NORMAL] = color_red; - bigRedStyle->fg[GTK_STATE_NORMAL] = color_red; - bigGreenStyle->fg[GTK_STATE_NORMAL] = color_green; - - gdk_font_unref(bigRedStyle->font); - gdk_font_unref(bigGreenStyle->font); - bigRedStyle->font = - gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); - bigGreenStyle->font = - gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); - - gdk_font_unref(bigStyle->font); - bigStyle->font = - gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); - } - gtk_widget_set_style(GTK_WIDGET(titleLabel), bigStyle); - - /* Begin the second row */ - dgnLevelLabel = gtk_label_new(_("Nethack for Gnome")); - gtk_table_attach(GTK_TABLE(statTable), dgnLevelLabel, 0, 8, 1, 2, - GTK_FILL, 0, 0, 0); - gtk_widget_set_style(GTK_WIDGET(dgnLevelLabel), bigStyle); - - /* Begin the third row */ - horizSep0 = gtk_hseparator_new(); - gtk_table_attach(GTK_TABLE(statTable), horizSep0, 0, 8, 2, 3, GTK_FILL, - GTK_FILL, 0, 0); - - /* Begin the fourth row */ - statsHBox = gtk_hbox_new(TRUE, 0); - - strVBox = gtk_vbox_new(FALSE, 0); - strPix = gnome_pixmap_new_from_xpm_d(str_xpm); - strLabel = gtk_label_new("STR: "); - gtk_box_pack_start(GTK_BOX(strVBox), strPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(strVBox), strLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(strVBox), TRUE, TRUE, - 2); - - dexVBox = gtk_vbox_new(FALSE, 0); - dexPix = gnome_pixmap_new_from_xpm_d(dex_xpm); - dexLabel = gtk_label_new("DEX: "); - gtk_box_pack_start(GTK_BOX(dexVBox), dexPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(dexVBox), dexLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(dexVBox), TRUE, TRUE, - 2); - - conVBox = gtk_vbox_new(FALSE, 0); - conPix = gnome_pixmap_new_from_xpm_d(cns_xpm); - conLabel = gtk_label_new("CON: "); - gtk_box_pack_start(GTK_BOX(conVBox), conPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(conVBox), conLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(conVBox), TRUE, TRUE, - 2); - - intVBox = gtk_vbox_new(FALSE, 0); - intPix = gnome_pixmap_new_from_xpm_d(int_xpm); - intLabel = gtk_label_new("INT: "); - gtk_box_pack_start(GTK_BOX(intVBox), intPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(intVBox), intLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(intVBox), TRUE, TRUE, - 2); - - wisVBox = gtk_vbox_new(FALSE, 0); - wisPix = gnome_pixmap_new_from_xpm_d(wis_xpm); - wisLabel = gtk_label_new("WIS: "); - gtk_box_pack_start(GTK_BOX(wisVBox), wisPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(wisVBox), wisLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(wisVBox), TRUE, TRUE, - 2); - - chaVBox = gtk_vbox_new(FALSE, 0); - chaPix = gnome_pixmap_new_from_xpm_d(cha_xpm); - chaLabel = gtk_label_new("CHA: "); - gtk_box_pack_start(GTK_BOX(chaVBox), chaPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(chaVBox), chaLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(chaVBox), TRUE, TRUE, - 2); - - gtk_table_attach(GTK_TABLE(statTable), GTK_WIDGET(statsHBox), 0, 8, 3, 4, - GTK_FILL, 0, 0, 0); - - /* Begin the fifth row */ - horizSep1 = gtk_hseparator_new(); - gtk_table_attach(GTK_TABLE(statTable), horizSep1, 0, 8, 4, 5, GTK_FILL, - GTK_FILL, 0, 0); - - /* Begin the sixth row */ - hpLabel = gtk_label_new("HP: "); - gtk_table_attach(GTK_TABLE(statTable), hpLabel, 0, 1, 5, 6, GTK_FILL, 0, - 0, 0); - - acLabel = gtk_label_new("AC: "); - gtk_table_attach(GTK_TABLE(statTable), acLabel, 2, 3, 5, 6, GTK_FILL, 0, - 0, 0); - - powLabel = gtk_label_new("Power: "); - gtk_table_attach(GTK_TABLE(statTable), powLabel, 4, 5, 5, 6, GTK_FILL, 0, - 0, 0); - - goldLabel = gtk_label_new("Au: "); - gtk_table_attach(GTK_TABLE(statTable), goldLabel, 6, 7, 5, 6, GTK_FILL, 0, - 0, 0); - - /* Begin the seventh row */ - horizSep2 = gtk_hseparator_new(); - gtk_table_attach(GTK_TABLE(statTable), horizSep2, 0, 8, 6, 7, GTK_FILL, - GTK_FILL, 0, 0); - - /* Begin the eigth row */ - levlLabel = gtk_label_new("Level: "); - gtk_table_attach(GTK_TABLE(statTable), levlLabel, 0, 1, 7, 8, GTK_FILL, 0, - 0, 0); - - expLabel = gtk_label_new("Exp: "); - gtk_table_attach(GTK_TABLE(statTable), expLabel, 2, 3, 7, 8, GTK_FILL, 0, - 0, 0); - - timeLabel = gtk_label_new("Time: "); - gtk_table_attach(GTK_TABLE(statTable), timeLabel, 4, 5, 7, 8, GTK_FILL, 0, - 0, 0); - - scoreLabel = gtk_label_new("Score: "); - gtk_table_attach(GTK_TABLE(statTable), scoreLabel, 6, 7, 7, 8, GTK_FILL, - 0, 0, 0); - - /* Begin the ninth row */ - horizSep3 = gtk_hseparator_new(); - gtk_table_attach(GTK_TABLE(statTable), horizSep3, 0, 8, 8, 9, GTK_FILL, - GTK_FILL, 0, 0); - - /* Begin the tenth and last row */ - statHBox = gtk_hbox_new(FALSE, 0); - - alignVBox = gtk_vbox_new(FALSE, 0); - alignPix = gnome_pixmap_new_from_xpm_d(neutral_xpm); - alignLabel = gtk_label_new("Neutral"); - gtk_box_pack_start(GTK_BOX(alignVBox), alignPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(alignVBox), alignLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(alignVBox), TRUE, FALSE, - 2); - - hungerVBox = gtk_vbox_new(FALSE, 0); - hungerPix = gnome_pixmap_new_from_xpm_d(hungry_xpm); - hungerLabel = gtk_label_new("Hungry"); - gtk_box_pack_start(GTK_BOX(hungerVBox), hungerPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(hungerVBox), hungerLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(hungerVBox), TRUE, FALSE, - 2); - - sickVBox = gtk_vbox_new(FALSE, 0); - sickPix = gnome_pixmap_new_from_xpm_d(sick_fp_xpm); - sickLabel = gtk_label_new("FoodPois"); - gtk_box_pack_start(GTK_BOX(sickVBox), sickPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(sickVBox), sickLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(sickVBox), TRUE, FALSE, - 2); - - blindVBox = gtk_vbox_new(FALSE, 0); - blindPix = gnome_pixmap_new_from_xpm_d(blind_xpm); - blindLabel = gtk_label_new("Blind"); - gtk_box_pack_start(GTK_BOX(blindVBox), blindPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(blindVBox), blindLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(blindVBox), TRUE, FALSE, - 2); - - stunVBox = gtk_vbox_new(FALSE, 0); - stunPix = gnome_pixmap_new_from_xpm_d(stunned_xpm); - stunLabel = gtk_label_new("Stun"); - gtk_box_pack_start(GTK_BOX(stunVBox), stunPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(stunVBox), stunLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(stunVBox), TRUE, FALSE, - 2); - - confuVBox = gtk_vbox_new(FALSE, 0); - confuPix = gnome_pixmap_new_from_xpm_d(confused_xpm); - confuLabel = gtk_label_new("Confused"); - gtk_box_pack_start(GTK_BOX(confuVBox), confuPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(confuVBox), confuLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(confuVBox), TRUE, FALSE, - 2); - - halluVBox = gtk_vbox_new(FALSE, 0); - halluPix = gnome_pixmap_new_from_xpm_d(hallu_xpm); - halluLabel = gtk_label_new("Hallu"); - gtk_box_pack_start(GTK_BOX(halluVBox), halluPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(halluVBox), halluLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(halluVBox), TRUE, FALSE, - 2); - - encumbVBox = gtk_vbox_new(FALSE, 0); - encumbPix = gnome_pixmap_new_from_xpm_d(slt_enc_xpm); - encumbLabel = gtk_label_new("Burdened"); - gtk_box_pack_start(GTK_BOX(encumbVBox), encumbPix, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(encumbVBox), encumbLabel, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(encumbVBox), TRUE, FALSE, - 2); - - gtk_table_attach(GTK_TABLE(statTable), GTK_WIDGET(statHBox), 0, 8, 9, 10, - GTK_FILL, GTK_FILL, 0, 0); - - /* Set up the necessary signals */ - gtk_signal_connect(GTK_OBJECT(statTable), "ghack_fade_highlight", - GTK_SIGNAL_FUNC(ghack_fade_highlighting), NULL); - - gtk_signal_connect(GTK_OBJECT(statTable), "ghack_putstr", - GTK_SIGNAL_FUNC(ghack_status_window_put_string), NULL); - - gtk_signal_connect(GTK_OBJECT(statTable), "ghack_clear", - GTK_SIGNAL_FUNC(ghack_status_window_clear), NULL); - - gtk_signal_connect(GTK_OBJECT(statTable), "ghack_curs", - GTK_SIGNAL_FUNC(ghack_status_window_cursor_to), NULL); - gtk_signal_connect(GTK_OBJECT(statTable), "gnome_delay_output", - GTK_SIGNAL_FUNC(ghack_delay), NULL); - - /* Lastly, show the status window and everything in it */ - gtk_widget_show_all(statTable); - - return GTK_WIDGET(statTable); -} - -void -ghack_status_window_update_stats() -{ - char buf[BUFSZ]; - gchar *buf1; - const char *hung; - const char *enc; - static int firstTime = TRUE; - long umoney; - - /* First, fill in the player name and the dungeon level */ - strcpy(buf, plname); - if ('a' <= buf[0] && buf[0] <= 'z') - buf[0] += 'A' - 'a'; - strcat(buf, " the "); - if (u.mtimedone) { - char mname[BUFSZ]; - int k = 0; - - strcpy(mname, mons[u.umonnum].mname); - while (mname[k] != 0) { - if ((k == 0 || (k > 0 && mname[k - 1] == ' ')) && 'a' <= mname[k] - && mname[k] <= 'z') { - mname[k] += 'A' - 'a'; - } - k++; - } - strcat(buf, mname); - } else { - strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female)); - } - gtk_label_get(GTK_LABEL(titleLabel), &buf1); - if (strcmp(buf1, buf) != 0 && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(titleLabel, bigStyle, bigGreenStyle); - } - gtk_label_set(GTK_LABEL(titleLabel), buf); - - if (In_endgame(&u.uz)) { - strcpy(buf, (Is_astralevel(&u.uz) ? "Astral Plane" : "End Game")); - } else { - sprintf(buf, "%s, level %d", dungeons[u.uz.dnum].dname, depth(&u.uz)); - } - if (lastDepth > depth(&u.uz) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(dgnLevelLabel, bigStyle, bigRedStyle); - } else if (lastDepth < depth(&u.uz) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(dgnLevelLabel, bigStyle, bigGreenStyle); - } - lastDepth = depth(&u.uz); - gtk_label_set(GTK_LABEL(dgnLevelLabel), buf); - - /* Next, fill in the player's stats */ - if (ACURR(A_STR) > 118) { - sprintf(buf, "STR:%d", ACURR(A_STR) - 100); - } else if (ACURR(A_STR) == 118) { - sprintf(buf, "STR:18/**"); - } else if (ACURR(A_STR) > 18) { - sprintf(buf, "STR:18/%02d", ACURR(A_STR) - 18); - } else { - sprintf(buf, "STR:%d", ACURR(A_STR)); - } - if (lastStr < ACURR(A_STR) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(strLabel, normalStyle, greenStyle); - } else if (lastStr > ACURR(A_STR) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(strLabel, normalStyle, redStyle); - } - lastStr = ACURR(A_STR); - gtk_label_set(GTK_LABEL(strLabel), buf); - - sprintf(buf, "INT:%d", ACURR(A_INT)); - if (lastInt < ACURR(A_INT) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(intLabel, normalStyle, greenStyle); - } else if (lastInt > ACURR(A_INT) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(intLabel, normalStyle, redStyle); - } - lastInt = ACURR(A_INT); - gtk_label_set(GTK_LABEL(intLabel), buf); - - sprintf(buf, "WIS:%d", ACURR(A_WIS)); - if (lastWis < ACURR(A_WIS) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(wisLabel, normalStyle, greenStyle); - } else if (lastWis > ACURR(A_WIS) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(wisLabel, normalStyle, redStyle); - } - lastWis = ACURR(A_WIS); - gtk_label_set(GTK_LABEL(wisLabel), buf); - - sprintf(buf, "DEX:%d", ACURR(A_DEX)); - if (lastDex < ACURR(A_DEX) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(dexLabel, normalStyle, greenStyle); - } else if (lastDex > ACURR(A_DEX) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(dexLabel, normalStyle, redStyle); - } - lastDex = ACURR(A_DEX); - gtk_label_set(GTK_LABEL(dexLabel), buf); - - sprintf(buf, "CON:%d", ACURR(A_CON)); - if (lastCon < ACURR(A_CON) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(conLabel, normalStyle, greenStyle); - } else if (lastCon > ACURR(A_CON) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(conLabel, normalStyle, redStyle); - } - lastCon = ACURR(A_CON); - gtk_label_set(GTK_LABEL(conLabel), buf); - - sprintf(buf, "CHA:%d", ACURR(A_CHA)); - if (lastCha < ACURR(A_CHA) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(chaLabel, normalStyle, greenStyle); - } else if (lastCha > ACURR(A_CHA) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(chaLabel, normalStyle, redStyle); - } - lastCha = ACURR(A_CHA); - gtk_label_set(GTK_LABEL(chaLabel), buf); - - /* Now do the non-pixmaped stats (gold and such) */ - umoney = money_cnt(invent); - sprintf(buf, "Au:%ld", umoney); - if (lastAu < umoney && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(goldLabel, normalStyle, greenStyle); - } else if (lastAu > umoney && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(goldLabel, normalStyle, redStyle); - } - lastAu = umoney; - gtk_label_set(GTK_LABEL(goldLabel), buf); - - if (u.mtimedone) { - /* special case: when polymorphed, show "HD", disable exp */ - sprintf(buf, "HP:%d/%d", ((u.mh > 0) ? u.mh : 0), u.mhmax); - if ((lastHP < u.mh || lastMHP < u.mhmax) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(hpLabel, normalStyle, greenStyle); - } else if ((lastHP > u.mh || lastMHP > u.mhmax) - && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(hpLabel, normalStyle, redStyle); - } - lastHP = u.mh; - lastMHP = u.mhmax; - } else { - sprintf(buf, "HP:%d/%d", ((u.uhp > 0) ? u.uhp : 0), u.uhpmax); - if ((lastHP < u.uhp || lastMHP < u.uhpmax) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(hpLabel, normalStyle, greenStyle); - } else if ((lastHP > u.uhp || lastMHP > u.uhpmax) - && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(hpLabel, normalStyle, redStyle); - } - lastHP = u.uhp; - lastMHP = u.uhpmax; - } - gtk_label_set(GTK_LABEL(hpLabel), buf); - - if (u.mtimedone) { - /* special case: when polymorphed, show "HD", disable exp */ - sprintf(buf, "HD:%d", mons[u.umonnum].mlevel); - if (lastLevel < mons[u.umonnum].mlevel && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(levlLabel, normalStyle, greenStyle); - } else if (lastLevel > mons[u.umonnum].mlevel && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(levlLabel, normalStyle, redStyle); - } - lastLevel = mons[u.umonnum].mlevel; - } else { - sprintf(buf, "Level:%d", u.ulevel); - if (lastLevel < u.ulevel && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(levlLabel, normalStyle, greenStyle); - } else if (lastLevel > u.ulevel && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(levlLabel, normalStyle, redStyle); - } - lastLevel = u.ulevel; - } - gtk_label_set(GTK_LABEL(levlLabel), buf); - - sprintf(buf, "Power:%d/%d", u.uen, u.uenmax); - if ((lastPOW < u.uen || lastMPOW < u.uenmax) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(powLabel, normalStyle, greenStyle); - } - if ((lastPOW > u.uen || lastMPOW > u.uenmax) && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(powLabel, normalStyle, redStyle); - } - lastPOW = u.uen; - lastMPOW = u.uenmax; - gtk_label_set(GTK_LABEL(powLabel), buf); - - sprintf(buf, "AC:%d", u.uac); - if (lastAC > u.uac && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(acLabel, normalStyle, greenStyle); - } else if (lastAC < u.uac && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(acLabel, normalStyle, redStyle); - } - lastAC = u.uac; - gtk_label_set(GTK_LABEL(acLabel), buf); - - if (flags.showexp) { - sprintf(buf, "Exp:%ld", u.uexp); - if (lastExp < u.uexp && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(expLabel, normalStyle, greenStyle); - } else if (lastExp > u.uexp && firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(expLabel, normalStyle, redStyle); - } - lastExp = u.uexp; - gtk_label_set(GTK_LABEL(expLabel), buf); - } else { - gtk_label_set(GTK_LABEL(expLabel), ""); - } - - if (flags.time) { - sprintf(buf, "Time:%ld", moves); - gtk_label_set(GTK_LABEL(timeLabel), buf); - } else - gtk_label_set(GTK_LABEL(timeLabel), ""); -#ifdef SCORE_ON_BOTL - if (flags.showscore) { - sprintf(buf, "Score:%ld", botl_score()); - gtk_label_set(GTK_LABEL(scoreLabel), buf); - } else - gtk_label_set(GTK_LABEL(scoreLabel), ""); -#else - { - gtk_label_set(GTK_LABEL(scoreLabel), ""); - } -#endif - - /* See if their alignment has changed */ - if (lastAlignment != u.ualign.type) { - if (firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(alignLabel, normalStyle, redStyle); - } - - lastAlignment = u.ualign.type; - /* looks like their alignment has changed -- change out the icon */ - if (u.ualign.type == A_CHAOTIC) { - gtk_label_set(GTK_LABEL(alignLabel), "Chaotic"); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(alignPix), chaotic_xpm); - } else if (u.ualign.type == A_NEUTRAL) { - gtk_label_set(GTK_LABEL(alignLabel), "Neutral"); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(alignPix), neutral_xpm); - } else { - gtk_label_set(GTK_LABEL(alignLabel), "Lawful"); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(alignPix), lawful_xpm); - } - } - - hung = hu_stat[u.uhs]; - if (lastHungr != u.uhs) { - if (firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(hungerLabel, normalStyle, redStyle); - } - - lastHungr = u.uhs; - if (hung[0] == ' ') { - gtk_label_set(GTK_LABEL(hungerLabel), " "); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(hungerPix), nothing_xpm); - } else if (u.uhs == 0 /* SATIATED */) { - gtk_label_set(GTK_LABEL(hungerLabel), hung); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(hungerPix), satiated_xpm); - } else { - gtk_label_set(GTK_LABEL(hungerLabel), hung); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(hungerPix), hungry_xpm); - } - } - - if (lastConf != Confusion) { - if (firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(confuLabel, normalStyle, redStyle); - } - - lastConf = Confusion; - if (Confusion) { - gtk_label_set(GTK_LABEL(confuLabel), "Confused"); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(confuPix), confused_xpm); - } else { - gtk_label_set(GTK_LABEL(confuLabel), " "); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(confuPix), nothing_xpm); - } - } - - if (lastBlind != Blind) { - if (firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(blindLabel, normalStyle, redStyle); - } - - lastBlind = Blind; - if (Blind) { - gtk_label_set(GTK_LABEL(blindLabel), "Blind"); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(blindPix), blind_xpm); - } else { - gtk_label_set(GTK_LABEL(blindLabel), " "); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(blindPix), nothing_xpm); - } - } - if (lastStun != Stunned) { - if (firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(stunLabel, normalStyle, redStyle); - } - - lastStun = Stunned; - if (Stunned) { - gtk_label_set(GTK_LABEL(stunLabel), "Stun"); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(stunPix), stunned_xpm); - } else { - gtk_label_set(GTK_LABEL(stunLabel), " "); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(stunPix), nothing_xpm); - } - } - - if (lastHalu != Hallucination) { - if (firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(halluLabel, normalStyle, redStyle); - } - - lastHalu = Hallucination; - if (Hallucination) { - gtk_label_set(GTK_LABEL(halluLabel), "Hallu"); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(halluPix), hallu_xpm); - } else { - gtk_label_set(GTK_LABEL(halluLabel), " "); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(halluPix), nothing_xpm); - } - } - - if (lastSick != Sick) { - if (firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(sickLabel, normalStyle, redStyle); - } - - lastSick = Sick; - if (Sick) { - if (u.usick_type & SICK_VOMITABLE) { - gtk_label_set(GTK_LABEL(sickLabel), "FoodPois"); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), sick_fp_xpm); - } else if (u.usick_type & SICK_NONVOMITABLE) { - gtk_label_set(GTK_LABEL(sickLabel), "Ill"); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), sick_il_xpm); - } else { - gtk_label_set(GTK_LABEL(sickLabel), "FoodPois"); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), sick_fp_xpm); - } - } else { - gtk_label_set(GTK_LABEL(sickLabel), " "); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), nothing_xpm); - } - } - - enc = enc_stat[near_capacity()]; - if (lastEncumb != near_capacity()) { - if (firstTime == FALSE) { - /* Ok, this changed so add it to the highlighing list */ - ghack_highlight_widget(encumbLabel, normalStyle, redStyle); - } - - lastEncumb = near_capacity(); - switch (lastEncumb) { - case 0: - gtk_label_set(GTK_LABEL(encumbLabel), " "); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), nothing_xpm); - break; - case 1: - gtk_label_set(GTK_LABEL(encumbLabel), enc); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), slt_enc_xpm); - break; - case 2: - gtk_label_set(GTK_LABEL(encumbLabel), enc); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), mod_enc_xpm); - break; - case 3: - gtk_label_set(GTK_LABEL(encumbLabel), enc); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), hvy_enc_xpm); - break; - case 4: - gtk_label_set(GTK_LABEL(encumbLabel), enc); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), ext_enc_xpm); - break; - case 5: - gtk_label_set(GTK_LABEL(encumbLabel), enc); - gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), ovr_enc_xpm); - } - } - firstTime = FALSE; -} - -static void -ghack_fade_highlighting() -{ - GList *item; - Highlight *highlt; - - /* Remove any items from the queue if their time is up */ - for (item = g_list_first(s_HighLightList); item;) { - highlt = (Highlight *) item->data; - if (highlt) { - if (highlt->nTurnsLeft <= 0) { - gtk_widget_set_style(GTK_WIDGET(highlt->widget), - highlt->oldStyle); - s_HighLightList = g_list_remove_link(s_HighLightList, item); - g_free(highlt); - g_list_free_1(item); - item = g_list_first(s_HighLightList); - continue; - } else - (highlt->nTurnsLeft)--; - } - if (item) - item = item->next; - else - break; - } -} - -/* Widget changed, so add it to the highlighing list */ -static void -ghack_highlight_widget(GtkWidget *widget, GtkStyle *oldStyle, - GtkStyle *newStyle) -{ - Highlight *highlt; - GList *item; - - /* Check if this widget is already in the queue. If so then - * remove it, so we will only have the new entry in the queue */ - for (item = g_list_first(s_HighLightList); item;) { - highlt = (Highlight *) item->data; - if (highlt) { - if (highlt->widget == widget) { - s_HighLightList = g_list_remove_link(s_HighLightList, item); - g_free(highlt); - g_list_free_1(item); - break; - } - } - if (item) - item = item->next; - else - break; - } - - /* Ok, now highlight this widget and add it into the fade - * highlighting queue */ - highlt = g_new(Highlight, 1); - highlt->nTurnsLeft = NUM_TURNS_HIGHLIGHTED; - highlt->oldStyle = oldStyle; - highlt->widget = widget; - s_HighLightList = g_list_prepend(s_HighLightList, highlt); - gtk_widget_set_style(GTK_WIDGET(widget), newStyle); -} diff --git a/win/gnome/gnstatus.h b/win/gnome/gnstatus.h deleted file mode 100644 index f2aa0445b..000000000 --- a/win/gnome/gnstatus.h +++ /dev/null @@ -1,14 +0,0 @@ -/* NetHack 3.6 gnstatus.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackStatusWindow_h -#define GnomeHackStatusWindow_h - -#include -#include "config.h" -#include "global.h" - -GtkWidget *ghack_init_status_window(); - -#endif /* GnomeHackStatusWindow_h */ diff --git a/win/gnome/gntext.c b/win/gnome/gntext.c deleted file mode 100644 index 9f3ee0e65..000000000 --- a/win/gnome/gntext.c +++ /dev/null @@ -1,151 +0,0 @@ -/* NetHack 3.6 gntext.c $NHDT-Date: 1432512804 2015/05/25 00:13:24 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gntext.h" -#include "gnmain.h" -#include - -/* include the standard RIP window (win/X11/rip.xpm) */ -#include "gn_rip.h" - -/* dimensions of the pixmap */ -#define RIP_IMAGE_WIDTH 400 -#define RIP_IMAGE_HEIGHT 200 - -/* dimensions and location of area where we can draw text on the pixmap */ -#define RIP_DRAW_WIDTH 84 -#define RIP_DRAW_HEIGHT 89 -#define RIP_DRAW_X 114 -#define RIP_DRAW_Y 69 - -/* Text Window widgets */ -GtkWidget *RIP = NULL; -GtkWidget *RIPlabel = NULL; -GtkWidget *TW_window = NULL; -GnomeLess *gless; - -static int showRIP = 0; - -void -ghack_text_window_clear(GtkWidget *widget, gpointer data) -{ - g_assert(gless != NULL); - gtk_editable_delete_text(GTK_EDITABLE(gless->text), 0, 0); -} - -void -ghack_text_window_destroy() -{ - TW_window = NULL; -} - -void -ghack_text_window_display(GtkWidget *widget, boolean block, gpointer data) -{ - if (showRIP == 1) { - gtk_widget_show(GTK_WIDGET(RIP)); - gtk_window_set_title(GTK_WINDOW(TW_window), "Rest In Peace"); - } - - gtk_signal_connect(GTK_OBJECT(TW_window), "destroy", - (GtkSignalFunc) ghack_text_window_destroy, NULL); - if (block) - gnome_dialog_run(GNOME_DIALOG(TW_window)); - else - gnome_dialog_run_and_close(GNOME_DIALOG(TW_window)); - - if (showRIP == 1) { - showRIP = 0; - gtk_widget_hide(GTK_WIDGET(RIP)); - gtk_window_set_title(GTK_WINDOW(TW_window), "Text Window"); - } -} - -void -ghack_text_window_put_string(GtkWidget *widget, int attr, const char *text, - gpointer data) -{ - if (text == NULL) - return; - - /* Don't bother with attributes yet */ - gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, text, -1); - gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, "\n", -1); -} - -GtkWidget * -ghack_init_text_window() -{ - GtkWidget *pixmap; - if (TW_window) - return (GTK_WIDGET(TW_window)); - - TW_window = gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK, NULL); - gtk_window_set_default_size(GTK_WINDOW(TW_window), 500, 400); - gtk_window_set_policy(GTK_WINDOW(TW_window), TRUE, TRUE, FALSE); - gtk_window_set_title(GTK_WINDOW(TW_window), "Text Window"); - - /* create GNOME pixmap object */ - pixmap = gnome_pixmap_new_from_xpm_d(rip_xpm); - g_assert(pixmap != NULL); - gtk_widget_show(GTK_WIDGET(pixmap)); - - /* create label with our "death message", sized to fit into the - * tombstone */ - RIPlabel = gtk_label_new("RIP"); - g_assert(RIPlabel != NULL); - /* gtk_label_set_justify is broken? */ - gtk_label_set_justify(GTK_LABEL(RIPlabel), GTK_JUSTIFY_CENTER); - gtk_label_set_line_wrap(GTK_LABEL(RIPlabel), TRUE); - gtk_widget_set_usize(RIPlabel, RIP_DRAW_WIDTH, RIP_DRAW_HEIGHT); - gtk_widget_show(RIPlabel); - - /* create a fixed sized widget for the RIP pixmap */ - RIP = gtk_fixed_new(); - g_assert(RIP != NULL); - gtk_widget_set_usize(RIP, RIP_IMAGE_WIDTH, RIP_IMAGE_HEIGHT); - gtk_fixed_put(GTK_FIXED(RIP), pixmap, 0, 0); - gtk_fixed_put(GTK_FIXED(RIP), RIPlabel, RIP_DRAW_X, RIP_DRAW_Y); - gtk_widget_show(RIP); - gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(TW_window)->vbox), RIP, TRUE, - TRUE, 0); - - /* create a gnome Less widget for the text stuff */ - gless = GNOME_LESS(gnome_less_new()); - g_assert(gless != NULL); - gtk_widget_show(GTK_WIDGET(gless)); - gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(TW_window)->vbox), - GTK_WIDGET(gless), TRUE, TRUE, 0); - - /* Hook up some signals */ - gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_putstr", - GTK_SIGNAL_FUNC(ghack_text_window_put_string), NULL); - - gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_clear", - GTK_SIGNAL_FUNC(ghack_text_window_clear), NULL); - - gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_display", - GTK_SIGNAL_FUNC(ghack_text_window_display), NULL); - - /* Center the dialog over over parent */ - gnome_dialog_set_parent(GNOME_DIALOG(TW_window), - GTK_WINDOW(ghack_get_main_window())); - - gtk_window_set_modal(GTK_WINDOW(TW_window), TRUE); - gtk_widget_show_all(TW_window); - gtk_widget_hide(GTK_WIDGET(RIP)); - gnome_dialog_close_hides(GNOME_DIALOG(TW_window), TRUE); - - return GTK_WIDGET(TW_window); -} - -void -ghack_text_window_rip_string(const char *string) -{ - /* This is called to specify that the next message window will - * be a RIP window, which will include this text */ - - showRIP = 1; - gtk_label_set(GTK_LABEL(RIPlabel), string); -} diff --git a/win/gnome/gntext.h b/win/gnome/gntext.h deleted file mode 100644 index 1ff9ebfb6..000000000 --- a/win/gnome/gntext.h +++ /dev/null @@ -1,21 +0,0 @@ -/* NetHack 3.6 gntext.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackTextWindow_h -#define GnomeHackTextWindow_h - -#include -#include "config.h" -#include "global.h" - -GtkWidget *ghack_init_text_window(); -void ghack_text_window_clear(GtkWidget *widget, gpointer data); -void ghack_text_window_destroy(); -void ghack_text_window_display(GtkWidget *widget, boolean block, - gpointer data); -void ghack_text_window_put_string(GtkWidget *widget, int attr, - const char *text, gpointer data); -void ghack_text_window_rip_string(const char *ripString); - -#endif /* GnomeHackTextWindow_h */ diff --git a/win/gnome/gnworn.c b/win/gnome/gnworn.c deleted file mode 100644 index 4d7303d15..000000000 --- a/win/gnome/gnworn.c +++ /dev/null @@ -1,103 +0,0 @@ -/* NetHack 3.6 gnworn.c 2009/05/06 10:58:06 1.3 */ -/* - * $NHDT-Date: 1432512804 2015/05/25 00:13:24 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ - */ -/* Copyright (C) 2002, Dylan Alex Simon */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gnworn.h" -#include "gnglyph.h" -#include "gnsignal.h" -#include "gnomeprv.h" - -#define WORN_WIDTH 3 -#define WORN_HEIGHT 6 - -#define WORN_OBJECT_LIST /* struct obj *[WORN_HEIGHT][WORN_WIDTH] = */ \ - { \ - { \ - uquiver, uarmh, u.twoweap ? NULL : uswapwep \ - } \ - , { u.twoweap ? uswapwep : NULL, ublindf, uwep }, \ - { uleft, uamul, uright }, { uarms, uarmc, uarmg }, \ - { uarmu, uarm, uskin }, \ - { \ - uball, uarmf, uchain \ - } \ - } - -static GtkWidget *worn_contents[WORN_HEIGHT][WORN_WIDTH]; -static struct obj *last_worn_objects[WORN_HEIGHT][WORN_WIDTH]; - -GdkImlibImage *image_of_worn_object(struct obj *o); -void ghack_worn_display(GtkWidget *win, boolean block, gpointer data); - -GtkWidget * -ghack_init_worn_window() -{ - GtkWidget *top; - GtkWidget *table; - GtkWidget *tablealign; - GtkWidget *label; - int i, j; - - top = gtk_vbox_new(FALSE, 2); - - table = gtk_table_new(WORN_HEIGHT, WORN_WIDTH, TRUE); - for (i = 0; i < WORN_HEIGHT; i++) { - for (j = 0; j < WORN_WIDTH; j++) { - worn_contents[i][j] = - gnome_pixmap_new_from_imlib(image_of_worn_object(NULL)); - last_worn_objects[i][j] = NULL; /* a pointer that will never be */ - gtk_table_attach(GTK_TABLE(table), - GTK_WIDGET(worn_contents[i][j]), j, j + 1, i, - i + 1, 0, 0, 0, 0); - } - } - tablealign = gtk_alignment_new(0.5, 0.0, 0.0, 1.0); - gtk_box_pack_start(GTK_BOX(top), tablealign, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(tablealign), table); - - label = gtk_label_new("Equipment"); - gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); - gtk_box_pack_start(GTK_BOX(top), label, FALSE, FALSE, 0); - - gtk_signal_connect(GTK_OBJECT(top), "ghack_display", - GTK_SIGNAL_FUNC(ghack_worn_display), NULL); - - return top; -} - -GdkImlibImage * -image_of_worn_object(struct obj *o) -{ - int glyph; - GdkImlibImage *im; - - if (o) - glyph = obj_to_glyph(o, rn2_on_display_rng); - else - glyph = cmap_to_glyph(S_stone); - - im = ghack_image_from_glyph(glyph, FALSE); - - return im; -} - -void -ghack_worn_display(GtkWidget *win, boolean block, gpointer data) -{ - int i, j; - struct obj *worn_objects[WORN_HEIGHT][WORN_WIDTH] = WORN_OBJECT_LIST; - - for (i = 0; i < WORN_HEIGHT; i++) { - for (j = 0; j < WORN_WIDTH; j++) { - if (worn_objects[i][j] != last_worn_objects[i][j]) { - last_worn_objects[i][j] = worn_objects[i][j]; - gnome_pixmap_load_imlib( - GNOME_PIXMAP(worn_contents[i][j]), - image_of_worn_object(worn_objects[i][j])); - } - } - } -} diff --git a/win/gnome/gnworn.h b/win/gnome/gnworn.h deleted file mode 100644 index 113c65b8c..000000000 --- a/win/gnome/gnworn.h +++ /dev/null @@ -1,17 +0,0 @@ -/* NetHack 3.6 gnworn.h 2009/05/06 10:58:06 1.3 */ -/* - * $NHDT-Date: 1432512804 2015/05/25 00:13:24 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ - */ -/* Copyright (C) 2002 by Dylan Alex Simon */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackWornWindow_h -#define GnomeHackWornWindow_h - -#include -#include "config.h" -#include "global.h" - -GtkWidget *ghack_init_worn_window(); - -#endif /* GnomeHackWornWindow_h */ diff --git a/win/gnome/gnyesno.c b/win/gnome/gnyesno.c deleted file mode 100644 index 4efa5b58e..000000000 --- a/win/gnome/gnyesno.c +++ /dev/null @@ -1,70 +0,0 @@ -/* NetHack 3.6 gnyesno.c $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "gnbind.h" -#include "gnyesno.h" - -int -ghack_yes_no_dialog(const char *question, const char *choices, int def) -{ - int i = 0, ret; - gchar button_name[BUFSZ]; - GtkWidget *box; - GtkWidget *mainWnd = NULL; - - box = gnome_message_box_new(question, GNOME_MESSAGE_BOX_QUESTION, NULL); - /* add buttons for each choice */ - if (!strcmp(GNOME_STOCK_BUTTON_OK, choices)) { - gnome_dialog_append_button(GNOME_DIALOG(box), GNOME_STOCK_BUTTON_OK); - gnome_dialog_set_default(GNOME_DIALOG(box), 0); - gnome_dialog_set_accelerator(GNOME_DIALOG(box), 0, 'o', 0); -#if 0 - g_print("Setting accelerator '%c' for button %d\n", 'o', 0); -#endif - } else { - for (; choices[i] != '\0'; i++) { - if (choices[i] == 'y') { - sprintf(button_name, GNOME_STOCK_BUTTON_YES); - } else if (choices[i] == 'n') { - sprintf(button_name, GNOME_STOCK_BUTTON_NO); - } else if (choices[i] == 'q') { - sprintf(button_name, "Quit"); - } else { - sprintf(button_name, "%c", choices[i]); - } - if (def == choices[i]) - gnome_dialog_set_default(GNOME_DIALOG(box), i); - gnome_dialog_append_button(GNOME_DIALOG(box), button_name); - gnome_dialog_set_accelerator(GNOME_DIALOG(box), i, choices[i], 0); -#if 0 - g_print("Setting accelerator '%c' for button %d\n", choices[i], i); -#endif - } - } -#if 0 - /* Perhaps add in a quit game button, like this... */ - gnome_dialog_append_button ( GNOME_DIALOG(box), GNOME_STOCK_BUTTON_CLOSE); - gnome_dialog_set_accelerator( GNOME_DIALOG(box), i, choices[i], 0); - g_print("Setting accelerator '%c' for button %d\n", 'Q', i); -#endif - - gnome_dialog_set_close(GNOME_DIALOG(box), TRUE); - mainWnd = ghack_get_main_window(); - gtk_window_set_modal(GTK_WINDOW(box), TRUE); - gtk_window_set_title(GTK_WINDOW(box), "GnomeHack"); - if (mainWnd != NULL) { - gnome_dialog_set_parent(GNOME_DIALOG(box), GTK_WINDOW(mainWnd)); - } - - ret = gnome_dialog_run_and_close(GNOME_DIALOG(box)); - -#if 0 - g_print("You selected button %d\n", ret); -#endif - - if (ret == -1) - return ('\033'); - else - return (choices[ret]); -} diff --git a/win/gnome/gnyesno.h b/win/gnome/gnyesno.h deleted file mode 100644 index 89ac86da5..000000000 --- a/win/gnome/gnyesno.h +++ /dev/null @@ -1,11 +0,0 @@ -/* NetHack 3.6 gnyesno.h $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 1998 by Erik Andersen */ -/* NetHack may be freely redistributed. See license for details. */ - -#ifndef GnomeHackYesNoDialog_h -#define GnomeHackYesNoDialog_h - -int ghack_yes_no_dialog(const char *szQuestionStr, const char *szChoicesStr, - int nDefault); - -#endif diff --git a/win/gnome/mapbg.xpm b/win/gnome/mapbg.xpm deleted file mode 100644 index 09759b449..000000000 --- a/win/gnome/mapbg.xpm +++ /dev/null @@ -1,353 +0,0 @@ -/* XPM */ -static char * mapbg_xpm[] = { -"96 96 254 2", -" c None", -". c #BC6C33", -"+ c #AC6324", -"@ c #B46B2B", -"# c #B47734", -"$ c #AC6B2C", -"% c #B46C3D", -"& c #BC7945", -"* c #A4774B", -"= c #B48643", -"- c #AC7F40", -"; c #AC773A", -"> c #C49054", -", c #C48044", -"' c #B4642C", -") c #B45E21", -"! c #BC642B", -"~ c #BD723E", -"{ c #C4884E", -"] c #C48F4B", -"^ c #C49753", -"/ c #CC9052", -"( c #CC7234", -"_ c #B4804F", -": c #C4985D", -"< c #946232", -"[ c #AC6431", -"} c #C46637", -"| c #945222", -"1 c #8C5435", -"2 c #844C29", -"3 c #945836", -"4 c #AC653D", -"5 c #A45E2B", -"6 c #AC5E2A", -"7 c #A44D21", -"8 c #A45823", -"9 c #A4592C", -"0 c #B46C34", -"a c #B46536", -"b c #AC7240", -"c c #AC7231", -"d c #944C1B", -"e c #8C5223", -"f c #945722", -"g c #AC6B34", -"h c #944C24", -"i c #9C5222", -"j c #B47234", -"k c #C4783B", -"l c #BC7833", -"m c #BC7F3B", -"n c #BC8044", -"o c #BC783C", -"p c #A46332", -"q c #9C6331", -"r c #B4773C", -"s c #B4723D", -"t c #A46B33", -"u c #B48043", -"v c #CC814C", -"w c #B46422", -"x c #C47946", -"y c #C48743", -"z c #BC6D3D", -"A c #BC6536", -"B c #94522E", -"C c #A4643E", -"D c #B45E2F", -"E c #A45223", -"F c #9C4C1B", -"G c #B47845", -"H c #C4804D", -"I c #9C5723", -"J c #AC5E35", -"K c #A45935", -"L c #9B5E29", -"M c #BE7234", -"N c #BC8744", -"O c #AC5924", -"P c #A45E35", -"Q c #9C582C", -"R c #AC501F", -"S c #9C5935", -"T c #8C4D28", -"U c #643D21", -"V c #845437", -"W c #B47E31", -"X c #844126", -"Y c #B45823", -"Z c #954627", -"` c #9C4C24", -" . c #7C4124", -".. c #B4592D", -"+. c #9C5E37", -"@. c #945644", -"#. c #AC6C3E", -"$. c #8C4627", -"%. c #9C643E", -"&. c #744021", -"*. c #A4723C", -"=. c #844628", -"-. c #743819", -";. c #844019", -">. c #944D2D", -",. c #A4512C", -"'. c #B45227", -"). c #C4622A", -"!. c #9C522E", -"~. c #7C3A1A", -"{. c #BC5E24", -"]. c #CC8243", -"^. c #9C664C", -"/. c #AC5934", -"(. c #9C4E2E", -"_. c #7C4B29", -":. c #8C532C", -"<. c #A46423", -"[. c #7C422C", -"}. c #743214", -"|. c #AC592C", -"1. c #8C4224", -"2. c #C47F3C", -"3. c #8C421C", -"4. c #8C410F", -"5. c #8C5D3E", -"6. c #8C5B32", -"7. c #88461A", -"8. c #663626", -"9. c #AC6B4C", -"0. c #94411A", -"a. c #845C30", -"b. c #744B20", -"c. c #7C4D34", -"d. c #CC874A", -"e. c #D49053", -"f. c #C46C32", -"g. c #BC814D", -"h. c #CC7842", -"i. c #A45A44", -"j. c #8C4B1A", -"k. c #843204", -"l. c #945E37", -"m. c #7C564C", -"n. c #74422C", -"o. c #95461B", -"p. c #AC7747", -"q. c #745634", -"r. c #94572C", -"s. c #7C4621", -"t. c #CC7A54", -"u. c #B47654", -"v. c #BC5E2C", -"w. c #B49056", -"x. c #C4915C", -"y. c #B4874E", -"z. c #BC884D", -"A. c #A46C45", -"B. c #D48749", -"C. c #BC5A30", -"D. c #CCA06C", -"E. c #BCA26C", -"F. c #BC8F54", -"G. c #BC895C", -"H. c #BC8F4C", -"I. c #BC995E", -"J. c #C46D3D", -"K. c #D4985A", -"L. c #C4562C", -"M. c #843A16", -"N. c #C49F63", -"O. c #BC9652", -"P. c #B48F4C", -"Q. c #CC915C", -"R. c #BC5824", -"S. c #B49A60", -"T. c #CC9F60", -"U. c #DC995F", -"V. c #AC8A54", -"W. c #B4875F", -"X. c #C4885C", -"Y. c #BC905E", -"Z. c #CC975B", -"`. c #D4A167", -" + c #7C5334", -".+ c #9C6B39", -"++ c #845323", -"@+ c #B46D4C", -"#+ c #A46B3C", -"$+ c #CC9864", -"%+ c #8C4E34", -"&+ c #743A24", -"*+ c #6C3D2E", -"=+ c #C45E30", -"-+ c #AC7E52", -";+ c #9C6C47", -">+ c #6C3C1B", -",+ c #CC8954", -"'+ c #542810", -")+ c #7C5E3C", -"!+ c #84532C", -"~+ c #946C45", -"{+ c #946340", -"]+ c #BCA870", -"^+ c #B49E5C", -"/+ c #C47E5C", -"(+ c #AC8E44", -"_+ c #8C633A", -":+ c #C4A86C", -"<+ c #CCA76E", -"[+ c #CCA961", -"}+ c #7A462D", -"|+ c #8C6644", -"1+ c #744623", -"2+ c #A47248", -"3+ c #94624C", -"4+ c #845E3C", -"5+ c #7C5329", -"6+ c #9C7249", -"7+ c #844D34", -"8+ c #6C4C30", -"9+ c #A46E54", -"0+ c #A4624C", -"a+ c #6C3E24", -"b+ c #5C3224", -"c+ c #D4A66C", -"d+ c #744B30", -"e+ c #BC926C", -"f+ c #AC7954", -"g+ c #AC522C", -"h+ c #6C4526", -"i+ c #A47A54", -"j+ c #BC6644", -"k+ c #BC6E4C", -"l+ c #A48650", -"m+ c #AC825C", -"n+ c #CC6A34", -"o+ c #9C7E5C", -"p+ c #7C623C", -"q+ c #5C3A2C", -"r+ c #644A34", -"s+ c #4C3624", -"t+ c #844B1B", -"u+ c #7C4018", -"v+ c #D49A68", -"w+ c #7C4B1C", -"x+ c #742E04", -"y+ c #CC8157", -"z+ c #745A44", -"A+ c #B46644", -"B+ c #643614", -"C+ c #C4A65C", -"D+ c #843A04", -"E+ c #6C2E14", -". + @ # @ $ % & * = - ; > , ' . ) ! ~ { ] ^ ] / ( ' , _ : < [ } [ | 1 2 3 4 5 ! 6 7 8 ' 8 9 0 a b c d | [ 0 % e 8 f 5 ~ g h i % & % 5 a ' 8 ' a < j k l m { n o . ! 6 . 0 % p p q g r s 0 @ 0 . ", -"j + $ # @ t g s u > u c { v @ ! w ' ~ x y y m u . ) z r > f 5 A [ B 3 2 B C 6 @ D E E 8 F i 6 0 g G 0 o H , j d I I [ & % i f [ . @ . 6 J K 2 3 L $ . M o N # j D ' O % [ 0 p P L g & l 0 0 . % ", -"4 Q 5 % j $ @ g u / G t M k ' R 9 9 J A . M p 3 . O ! M { L 3 4 [ Q S T B Q 6 ' 6 6 J a a 9 9 a c & 0 ~ ~ z 0 L 5 8 5 [ [ d 8 & M . x i B 3 U V 3 4 . l & N m W 6 6 8 % [ g 8 5 q % & o j [ [ 0 ", -"3 X h [ 0 0 0 0 ~ n j p 0 z Y 7 T Z ` Y ! ' Q .a ..! . , t +.@.#.[ C S S 9 [ . D a J a z J 8 % , o + 8 8 [ @ ' J 9 Q 6 5 5 [ x P [ 4 $.1 %.&.V S p ~ o b *.; c 9 6 5 % [ [ 5 p p b & o 0 $ [ 6 ", -"=.-.;.9 a . j j . 0 [ @ z . Y O >.h ,.'.).! !.~.P D {.! ].& ^.T & & s % 4 [ A . 4 /.` Z (.d Q , H #.8 E 8 [ [ [ a 9 /.% z 0 . ~ _.1 :.T S C S | < <.M 0 | 2 T >.Q Q | [ 5 [ p 0 0 % # s j % 5 !.", -"[.}.~.!.' 0 @ @ . 6 O 0 ~ a D Y P K |.... . K 1.8 D {.! 2.y b Q o x % % a 6 . A ,.` 3.1.1.4.i ~ & 5 i d 8 J 9 [ A J |.D a D a a 5.3 .;.h 8 a I 6.f $ g 7.}.1.$.T T T +.Q 0 g 0 % % 0 0 0 % 5 h ", -"_.8.;.E 6 ' ' @ ' O 8 ' @ . a ..+ D 9 9 0 o ~ p 6 ' ! . , n 0 . 0 o [ A a |.a 6 ` 3.Z (.>.$.I 0 #.e h d !.J I C a D E F F 7 |.D 9.>.>.Z 0.9 a 8 a.b.Q [ =.;.!.K 2 T 7.S 5 #.[ 0 g [ g g % g J Q ", -"c.-.;.8 D ) @ w . ' w [ a ~ ~ Y O O 9 S c d.e.d.f.A . H g.# @ h.$ ~ [ % z |.. 6 /.Z ` i.Z d [ o %.j.S P 4 % Q p E 8 O 7 F Z E /.O k.a a 9 & #.l.m.n.B C j.T 5 ) :.:.2 q p % [ [ [ [ [ [ [ 4 p Q ", -"o.F i I 9 [ 0 0 ' 6 8 6 # n o 0 @ ) L W d.].0 [ + @ M k m ; $ @ $ 0 j 0 0 0 0 a c g G p.q f p s ' 0 d !.Q h & M Y '.7 E 7 7 7 R [ @ ) |.[ 4 3 b.q.b.2 L % g P r.j.I 6 a a 6 + [ [ p [ [ g & & I ", -"I d d E 0 ~ 0 6 ' O E 8 j n m . ( j # N 2.@ O !.@ @ ! M r # # M # m n , & r % s m r & o p I [ [ $ @ 7.Q P Q o j f.. O 8 F 7 O ..6 ' ' ..a a q 2 _.s.;.j.F o.o.j.I 5 p O 8 O @ M [ 0 0 g 0 o ~ L ", -"[ 9 F 9 z t.. O ' ) O w r n , ~ A % u.n o w |.|.a ' D ' o o n ~ j l , N n r G _ u 0 #.a |.[ 0 # n r | 9 P 8 0 [ l o o % g [ D 6 7 O ..Y a A 4 p C #.s ' O 6 D a g % 0 a [ 6 [ 0 @ , k o o n o c ", -"[ [ [ ' a . a |.8 O Y 0 o ~ . v./.r.S #.z . D D 5 6 ..! s & o ~ # o m r u _ w.x.y.p.[ J 6 % y z.] n p g a 6 @ [ # m y { m ~ @ @ 9 |.D ' A ~ % [ A.G x ~ ' ! 0 z 0 0 0 % . 0 [ [ [ o o $ M # 0 o ", -"g s ~ 0 0 a ' ' O ' ~ B.{ o ' C./.$.;.B ' A R ` Z ,...A . o & ~ y m N N ] : : D.E.F.G.g.G _ H.I.y N s % 0 a z M r u m & o o m m & & ~ ~ l j 0 <.t s G j $ 0 # j % [ 8 [ 0 % . ~ @ o o 0 r j # y ", -"o o l s o & , x 0 J.B.e.K., . L.a >.M.d 6 ! E 3.M.o...! . & n r 2.y n { > : : F.I.I.N.: y.F.O.P.n o a ' D 6 ' 0 $ c % o & o o m & G # j # r c [ q p L I I L <.p . ' [ 0 o % 0 % o k o o o o o , ", -"k n o o & { / Q., l ~ , { m ! R.D !.h 6 . . ) P 7.i ..w M m { n m n N z.z.z.y.= y.z.I.S.w.I.x.g.o ' 6 Y R O 8 [ [ a [ a z o r # s j j j @ 0 . 0 ~ . 0 0 0 0 0 o ! . o H o [ [ a g 6 [ s 0 g g g ", -"@ o o r c u > T.U.H # n ] n J.).D 6 0 k ( M ~ & +.[ D w l y / g.{ { { { N z.] > y z.w.w.V.W.X.& ~ 6 Y R Y ! ' 0 ~ a E 7 9 0 m n o k k k . ' D } D D A z z ' [ A 6 ' 0 0 p L [ x a I [ & & & s g ", -"I E D ! 0 s z.F.T.H.o o h.d., c j m / Y.Z.`.n t ' ' $ , y y N m m y y ] { z.n N n { ; > H.r / z.~ p E O D 6 ' . @ 5 i d F 5 g r [ j o 0 g % 0 [ ' 6 5 p I 4.4.o.o.d e U +c.6..+[ i j d.# m { p ", -"0 5 i O a g.Q.F.T.^ N o & ].n @ # m { b p.Q.N c ! a M , / { m m W m N z.z.n N y n { ; z.] u ] r 0 + 8 ..a D w @ @ ' 8 d T r.g r @ 0 g [ <.[ [ p 5 5 [ p Q Q 5 z 6 p :.b.V _.l.p s 5 0 m @ # { G ", -"H ~ [ a & H g._ > Z.: ] z.] , o . o ~ f Q H H j . . x y d., 2.o y N z.z.z.N n & { { ; z.> u { s 0 a D 6 v.a ' w Y O >. .&.2 q $ g 0 [ 5 5 [ [ [ 0 [ | 7.>.Q 9 h !.P ++2 5.=.4 @ C | Q P Q 5 0 k ", -"H , s % @+#.#+#+#.z.$+N.: Z.H k 0 a a E 9 & x ~ z k x , , l M k y ] > ^ > G.n m { N u ] ^ { y s k . a |.6 ! ' + {.|.%+&+*+V p l [ $ @ [ $ 0 0 p % S 7.$.B C Q T ;.3 T 2 @.%+a @ +.T $.>.K 9 [ k ", -"n & q B +.+.S p :.#+y.Y.w.H.{ , J.a a /.a z a o x k , o ~ . . f.# n ] : Z.: > { o n u > ^ { n o ~ J.a 9 6 0 . @ =+O T 8.8.1 [ 0 $ 0 s j % % g 0 +.Q S !.B h h f ~.4 t %.3 3 4 6 r.T X $.i.J a k ", -"~ % B e ^.%.e T 3 q * -+_ u H / x a a a A 0 [ & , { , n l M f.. . o z.> : : ] H o n N F.z.n o J.~ a [ [ 0 % M M w |.Z }.-.T L O j ~ o 0 $ [ [ % p 5 9 K i j.j.| 4.% G p 1 S B r.| T X Z K a [ . ", -"' % +.l.* ;+2 2 ;+%.q s b b u x.x % 0 . 0 M j n N z.y n o o f.! ).. & z.F.> z.n n n z.H.z.n 0 . a [ [ b & r g j @ 0 [ >.` K a ' 0 r o % [ 5 5 g $ p 8 9 a ~ o # D @ o #+T @.>+1 K 5 5 [ % ~ z J ", -"E a +.1 ;+;+6.A.* %.+.@+% p #+= #.g 0 0 M , r y u N N n o k . {.R.v.0 u G.F.{ z.,+y > H.H.G ' ' @ [ g n z.# $ <.<.0 a |.E a A 0 <.0 x o g L 8 [ <.% 0 8 8 @ k m B.M o g V 1 '+)+h Q @ j M 0 J o.", -"_..+^.!+6.l.l.l.~+;+6.V {+:.:.A.r.e q G F.N.]+]+^+I.^ K.d.' 6 z @ M % a /+{ y.H.(+T.^ u ,+2.a ' [ <.t y.x.y.b t L $ @ ' [ 0 # g j j r % [ I p g [ 0 O Y ) w 2.y l j $ @ 5 I P i I <.0 0 0 0 5 e ", -":.%.< :.1 {+l.3 ~+;+_+6.l.!+s.5.3 T q g.> > :+<+:+: H.y ].. ) A + ' 6 9 [ G z.> P.[+^ N { d.0 . . @ s g.z.n 0 @ j o o 0 @ M r # $ j o #.[ <.g #.j . 6 . . 0 , y j l k , g 8 p 5 [ g a z % a 5 i ", -"A.%.%.+.l.C #+%.{+~+{+{+5.}+n.}+3 6.#.H { z.> T.<+Z.n o , ~ ! a w ' D 9 !.[ n ] O.<+N.= ] y o l M . o o & s 0 . n n o 0 $ j r # $ j s 0 #.s s # g [ 9 0 z 5 g #+2.o , ,+d.H & 0 s % a a a [ J 5 ", -"b S %.C +.^.9.A.5.{+~+^.|+1+*+n.c.1 #.H x o H ,+> { n s x k . . . ! A A O a v y I.[+N.N H.y m 2.h.l l & o r ~ o & m r g g s o G j g b G G r r & r #.[ % 4 | S q o 5 <.~ , d.o $ z a 6 a a /.4 a ", -"#.3 +.%.r.+.2+b 5.5.3+;+5.c.n.n.8.T #.~ 0 z x & % & & o x M . z ! D A A D o d.d.: T.: H.z.] y ] 2.m n n z.N N n m G r # r r m r n g c g.{ G j o H r [ #.9 7.e q [ | [ $ g o o o % a [ J [ [ a a ", -"C p %.C {+l.;+;+{+4+3+;+l.%+2 .2 Q @+z J 6 K Q [ M & & , s 0 l ~ ' a ' ' o , n F.F.> H.m N N m N N u y.z.H.z.N n n n n z.n G o , s r G.F.r # & o & [ g L j.Q p o 5 0 [ 0 , o x M . s g % % % a ", -"C A.#+A.A.;+5.1 ~+5.{+;+^.S +.Q #.g ~ x 6 h $.=.. [ [ r g.o # , , H o 0 j o m N = N { N u u m r N N N n _ u = = & u u _ N _ n r & & n z.z.n o # x x j o o $ o r ].L + [ 0 d.g g 0 n , n u n % p ", -"q p.2+A.* ;+5+1+6+a.< A.#+#+~ g v ' . h.a $. .7+. + I #.{ { m / H e.{ k d.y N ] N N ] / n n y m N { { { G G u _ r b r u = u G r ~ g.{ u y.z.n @ 0 0 0 o 2.y ].m , + , o s , 0 & @ , { N , y o 5 ", -"k @ j j . H & 6.a.6+a.6+;+s ~ [ 2.j C C !.j.b.8+[ K j.l r H.N.P.= z.K.N Z.; N > r z.H.N ] r t o u u n n u u u V.<.G I p ;.g g u = V.H.u { # o g $ g G z.z.m m , N = = ] # y m # W <.o ~ ; t r t ", -". + $ [ ' ~ & .+l.;+l.2+9+#.~ a n q 1 2 T &.1+q.C [ % { y T.^ I.> z./ o e.r n z.# u N N { u # l u u m r r r p.u s % [ J I 5 r { z.u > u { r r 0 j ~ b g t #.o d.H.y N K.y { o r n g k o g.N { j ", -"D 9 + + O ' % b S 0+@.9+C C 4 z A.}+a+b+V &._.7+e p { { { c+F.<+Z.N n $ y 0 ~ % j $ r y n # ~ 0 u m n G r s G n & $ % 5 4 j.t n F.G.] g.{ r n 0 d.n p $.X I # 2.y n u y g 0 0 , 2.' . % & { e.. ", -"..|.6 a D D a j S @.2 3+1 5.S #.S [.d+U l.T +.B e b X.g.> D.F.N.x.z.r 6 M D ' |.0 [ o , r j ~ $ r n g.& & r r & s p % P % j.<.p.> z.z._ / n n o y & S ~.~.Q j m / H H v 5 I |.x M ' A /.5 s x a ", -"C./.9 9 D v.' . %.7+a+c.d+c.2 q !.1 3+2 #+9 % S u.Z.G.y.e+x.z.f+> { & [ . ....... 0 , v % . ~ ' [ b & n & s ~ s t #.& G & b _ g.z._ z.g./ g.{ H m g Q X >.s { y 5 L p , [ a [ x . ! A |.4.Q z {.", -"..g+d 0.7 ..' z %.c.U }+h+5+s.l.$.%+3 h ' ' z g G.$+-+_ Y.* f+r._ H & w D O ..D A z ~ o j % 0 a I [ s G r s b s G x.H X.G X.G.z.G.= G.z.x.z.> > z.u #.C b H > N <.| d % % h.~ ~ . } v./.~.d D v.", -"..|.d ;.F ..D . C T _.c.[.B $.P }+ .%+K z ' s _ z.i+-+i+_ 2+;+e t r z [ 6 |.|.A 6 a D [ 0 ~ 0 [ E [ s g.G G r u > : z._ p.G.F.P.Y.F.F.F.: y.> Z.Z.> g.n g.> ] > U.,+o , [ ~ a ! f.{...J 3.| D ! ", -"v.J.p h /.A A J.i.B B @.=.i.(.j+a.c.@.k+t.~ A.l+F..+e+m+W.f+;+:.P s % ' D a a z ..D 8 I ~ & 0 a /.@+x z.z.= y.z.x.y.p.A.b y.I.N.: Y.N.: : y.F.N.x.F.N y ] ] : T.r n n , 5 5 [ ' M ! /.k+B 4 . n+", -"] u 6 R ! A z g.I #.=.%+l.%+J a B T p [ & C k+g.u ; g.e+o+p+ +3 {+q #.[ 6 . o g [ H [ n { > N j D 6 a & { : I.w._ _ !+_.+.9.Y.N.]+S.I.F.Z.u n n u u - H.Z.N # y I l o u j j m l l l + $ K.] u : ", -"z.m @ ' f.~ ~ g.& & :.1 @.S % a %.+.C % @+[ u.& u b _ m+~+)+_+^.#+#.% @ [ . & c s d.g.> ] { z.N ~ z s u G.x.O.F.G -+c.&.1 ^.y.I.]+S.N.G.> n n N ] = ; W Z.] u n @ n o m n m , $ l 2.j k e.{ N Z.", -"n , j . k o n > { G e T 3 C H a P 0+J % [ [ % & n G _ f+|+4+2+f+p 4 % a ' ~ , s & % { { F.N z.z., n & n z.z.F.y.s 9+b.U c.@._ O.S.I.N.G.H.n { { N ] H.= H.y m y , , s j g j & . j M . M & [ 5 r ", -"n o j . o y z.T.,+_ r.:.:.#.,+a 3 K !.4 8 a % x u G u.A._+|+9+#.4 #.z a [ ~ x % G f u u > ^ z.N N u u g.z.z.g.G p 3 8+q+*+V p.] w.I.T.z.G.z.{ { u ] Z.> z.= r #.~ ].r g <.<.~ o ~ x k z A O i a ", -"& o j @ , N ] : K.{ p.#+p #.H g Q P Q a 6 ~ ~ H _ g.& _ p.-+p.#+% % @+0 0 % & #.& | G y.Z.> H.y.> z.u u g.g.G b i 2 r+s+8.7+#+r -+F.T.F.> g.{ g.> ] = u y.g.t t++ & & , r g j 0 o ~ z z z J D z ", -"0 o o o n & _ G.x.> { _ G g.H & #.s % s z H H & W.u.g.X.G.e+g.A.i.3 p % % 0 ~ z ~ #.g.> > y.u n Z.> u G r r s #.S 2 +}+n.3 C c u z.Z.> > g.{ & > N y.u p.u #.| g ~ r n H & & 0 r b g a a 6 ' a ", -"g o x o @+p +.@+= G.> { ,+{ g.{ g.g., o H v H #.6.1 %.u.-+i+2+l.:.u+!+#.s g M x % & G g.g.G ; u { z.{ n s % g 0 S 2 %.l.Q @+r G G u { G.> _ n G N u > > u p.u.g & G ; r u r u s F.= n & 0 . a a ", -"g o n % 9 $.>.0+z.> Z.Q.v+,+n ,+z.n n 0 , & u.I 8+&.1 A.* i+;++.5.&.++b r [ @ ~ % /+5 G g.g.n G c r { H & [ [ p 3 2 C t a ].{ u g.G z.z.: r _ & > u G.x.z._ b r.b n z.> N b G r P.- u n o ~ M 0 ", -";.P 9 ~ #.u+7.6.t u F.y.g.o k m . . a ~ I ~ j p ++s.w+;+{+< _ ;+7+l.2 _ 4 s ' M c c # & s g 0 k @ o u u r g 8 |.2 &.t+b P.w.y.r ; { z.H.; z.o s t ; z.: F.z.n ; # m r t #.c r & u H.; y o ~ ~ Q ", -"h T x+K & | r.r.% & y.u s s z s a 9 p [ g & n <.l.>+&.b 2+%.p.f+V 1 3 #.% g % o m u n & & % $ [ p 0 r r n g 9 6 +.e Q u F.P.N r n n ; = u { r s ; r y.x.y.N u # u N o c s s G g.] Z.= ] % a J T ", -"X S 3.j.9 K 4 Q A s s % % a 4 +.+.e Q r.G & d.g b 7.:.p.G p.b p.6.6.4 [ x % > z.z.{ { { y n o % $ j r u g.r [ a 3 Q 4 & _ y.n % p.n u g.; ; s H , n z.{ z.g.n o o , n s r & G H = F.= H 9 7 (.T ", -"~.P S 3.0.i a K J.~ & & u.@+^.l.l.1 3 e #.G { & u.r.C #.p.H G c .+t % J y+u.T.y.G.g.F.] { r & H ~ o G , ,+& [ [ T K % G ; - & g #.#.s g.s #.s ,+y 2.{ H r b & r #.& o s r o & n z.] z.{ 9 /.,.(.", -"S 1.M.,.|./.a a a u.n g.@++.c.8+V {+6.l.< G { / G +.p q #.{ r s u m % % x g.Y.l+X.#.#.u n g [ k+o ~ g & { & [ [ S a k+x p.G & 4 #.r.3 #.& & @+s r s & r 5 | Q p 9 #.s s o n G H H.F.z.n E ,.Z Z ", -"4 ` ` |.A ~ z J P #.s r t e q+s+c.~+5.q l.g.g.K.{ % t % s b 4 s r , 0 n H : : w./+r.7.+.; #.[ . s [ I [ & G p 4 S 4 k+n G u g.% 3 t+T Q u.#.#.t C p g % | 4.7.T >.C s r n N n z.F.z.z.G 7 ..Z >.", -"J a J.D |.J.~ E 4 C #.o z +.d+r+!+;+%.%.p.g.g.Q.K.X.r G s +.Q %.a o b > : T.T.: ~ Q u+=.P @+~ f.s [ i <.& & @+r | !.[ s G u & @+2 s.:.B #.p #+t 3 !.C a S h B :.$.P G n ] z.N F.Z.x.^ { [ } ..a ", -"D R D D O a 6 h (.h i ' a 4 5.z+6.%.A..+G.z.g.u z.K.G #.%.r.r.T 6 ~ n Z.N.F.> { . [ >.X T J . f.H g 8 #.y+H g.H 3 i 9 % ; p.b [ 6.s.=.T #.#.#+l.=.X 3 4 [ +.Q 3 $.C g.{ ^ ^ H.F.x.F.: 2.8 v.R [ ", -"E a D 8 8 6 5 I 5+5+!+B [ ~ C 5+#+* L u.#.s p #.0 [ #.3 +.1 1 =.p u.r Z./ n G H % 5 B 2 T L 0 ! $ l W m { n s o p.b g G ~ #.P +.l.w+w+f .+G r L 1+s.f K [ 6 9 o a P g & m m g.z.u m { , 0 O D ..", -"R |.O E 8 ' [ [ ++!+1 Q ..a [ {+G -+r.#+4 #+p g 8 5 C e 1 2 2 =.q r #.Q.{ r #.z.% p q L +.#.~ . j 2.m 2.{ { n l b p.n H g 5 +.#.b T j.+.% 0 0 @ 2 T S 5 [ 6 I 4 a 6 0 x & r n g.m u m G @ [ a |.", -"D D O O D 0 z ~ Q S K /...D % & _ f+f +.p #.p +.| +.C 2 2 2 5.2 p s g e.{ # c H & % #.b t #.4 ` K % m o g.H g.# p.s s % #.p S S K S J 4 x a [ D r.r.q [ % a i 5 a 6 0 o g [ #.#.o # 0 0 0 z . 6 ", -"A ..J D J J z ~ J P J a A ! z g.2+A.e P % @+C r.T l.A.7+2 7++.:.p G g / , n & H /+& u ] / Q.@+1.9 ~ ,+g.G z.,+y & p.#.g g 4 9 T 1.P @+/.~ 4 D 9 +.r.P [ o ~ I 8 a [ a 0 [ 5 P [ 0 g 0 g z , , [ ", -"v.O D 4 (.` /.a [ S 3 J . a #.A.l.C Q 5 k+s A.:.=.3 ^.s._.2 3 r.I ~ 0 m o , o s +.B e t z.Q.u.$.1.[ & <.j.r.G # s g.g.r #.[ P !.2 %.#.B C S P 4 P 9 p [ , & 5 8 [ p [ 0 [ [ a a ~ ' [ @ ~ v x 0 ", -"v./.D P Z h K 7 P r.T p s ~ q :.6.#+C 9 z C C :._.1 l.s.2 :.q !.Q ~ [ o k , ~ [ C B e L g.`.v+G @+H / #.t+Q & , s & n o r s [ d !+!+1 < 3 7.j.C [ /.[ g H , [ I S I p [ [ % z z % [ 0 z ~ k k 0 ", -"! |.P S X B J ` /.K S C z & q _.:.#+% |.4 Q +.V T 7+1 2 3 S [ 5 9 [ Q ~ H v % [ +.r.3 r.+._ : z.g.n y u I p ~ ' g o o r n , a d 2 s.2 b 3 T ;.C D J [ g H H [ 9 T T f [ g . % [ [ 5 ' o . 0 . . ", -"' E !.T u+S 4 h g+/.K J z z S . .C & D a >.S 7+%+2 1 2 +.p [ 5 i (.4.~ v x [ 0 +.C 9.+.3 b H.H.,+N ] / G x x 8 8 l Z./ m o ~ 6 :.T T 9.$.+.K A+/.|.[ g , ,+g 5 2 2 +.g % o 0 8 I | [ k % ) A k ", -"O O 8 Z h K p p <.+.r.B Q q :.&.&+S @+#.9 B S {+I f r.T 2 l.l.e ;.q 9 x x k ~ 9 q.B+1 0+S C s / 2.N ^ C+O.; [ v.Y 0 M ,+m n [ ' I I 5 % 4 t r r [ [ 0 0 , n { ; R O @ p.; #.p 9 7.Q #.% a O O z ", -"i 9 9 i !.L S r.< 3 >.:.Q +.:. .}+3 4 4 6 Q Q +.$ Q L 3 1 :.r.e | p 5 ~ 0 s [ 5 5.s.c.^.0+r.p n H m u H.z.j @ J.+ [ t r r n o k [ i S 4 #.s r # j 0 o 0 , o n n . ' <.p p r.!.Q Q P [ 4 % [ !.9 ", -"2 B P J 9 S :.c._.2 =.%+P #.4 @.T >.P 4 J 5 P %.[ % C 3 2 B l.T 9 [ [ . 6 z [ #._.>+'+c.{+_.Q #.,+# j m N r o , e./ ] u = n n s [ 3.3.P u.g.n N o c o 0 ~ g n { , 0 [ a [ B $.2 d Q Q Q C C B T ", -"&.1 P [ 6 3 2 1+c.V %+3 4 @+P >.%+%+B J [ K 9 P a P +.B 2 :.%.%.a [ z . 9 % r.C i.@.>+ +|+2 >.6 r M j ~ x d.z.N > Z.T.z.^ > / n J ;.u+Q u.{ { N G 0 % 0 0 5 0 n m j . a ..!.T u+7.5 4 r.>.1 2 =.", -"h+7++.J +.r.c.d+_.!+1 C #.o % S T =.>.S K Q Q J 4 7.X 1 1 2 C H ~ % x z 5 [ T B 0+3 V 1+4+l.B a <.0 z ' . , y r - N Z.= H.z./ z.& S | #.G n z.u N j o 0 o O [ [ N , % E ` !.S :.I % @+Q 2 _.n.n.", -"n.7+3 3 r.B !+V b.++3 +.j o 0 S =.2 T B >.>.(.K $.T _.&._.A.& ~ b s % & g #.L q d 2 1 a+u+%.I % 6 M ~ w [ o , r n { > n u u N z.,+G s G g.y.z.z.n r r 0 . 8 8 I o d.& |.i J 4 S 6 g p B 1 2 n.a+", -"=.=.7+V 6.1 1 r.l.{+S +.5 p r.;.c.7+7+2 T >.>.(. .1 +U _._ ,+6 l.C L s s & g.X.s #.#.C Q p g $ . J.. @ [ . ~ . 0 o o n n z.z.> > , n z.n z.> z.n r r [ 0 O 6 E + o , G & n % I [ [ !.T :.7+}+}+", -"$.=._. +V 6.3 9 !+1 %+%+r.C S %+_.7+7+[.=.B (.T 1 n.h+5+|+p.o @ ++l.s.t #.& X.Q.N g.x y+k+0 ,+W A ' @ 0 0 + D ) O [ [ x 0 u ; u y N N u - z.F._ u r o [ ' ' . . E [ r N { y 0 R % 4 p r.B =. .7+", -"2 s.7+1 &+1 .:._.1+1+2 1 %+7+1.5+2 X $.[.n._.3 >.Q i [ M g #.p 2 e :.l.f #.[ a g p #.% 0 % z . $ m 8 x |.v.' w *.$ # @ j l p f + , k s d f z.n u ; o # $ o l 2.m $ <.j x o [ L @ j % [ h $.P 1.", -"1 2 2 %+ .S T :._._._.2 7+2 %+@.6.T %+X [.n. .T B K 8 6 [ 0 #.p 2 2 !+e T #+Q 9 t p g % [ ' a 5 r.<.I . /.a 6 w p #.~ M z ~ [ 9 $ r g.g f t n z., u m , c , # 2.2.l j s s [ <.[ $ j s % | >.K >.", -"S T T T $.%.3 T c.c.2 _.}+=.1 +.+.S B }+n.h+s.1.!.Q 6 |.' o #.p 2 1 :.2 2 #.3 | r.p #.a 9 [ [ I &.2 <.' a A J [ d Q J z z z A+a g s { #.C _ b G.m & r { $ y g 0 j o o g <.[ s o $ & r & 4 L p S ", -"p Q S >.>.C P | 2 2 V 2 2 2 3 C P 4 S 2 h+1+7+Z 3 ` |.D J.~ [ p 1 3 :.5+2 2++.T :.p @+[ 9 J [ f 8.>+t + . a 9 P 0.` F |.a D a D I #.& A.G _ *.n n s s n 0 , g @ t s s #.p g r o s & s o & g [ g ", -"a [ J K S S 4 r.%+1 3 3 3 S %.C 9 a J %+&.2 S /.+.>.E D } z K S B 3 :._._.A.1 2 3 #.& a 9 9 C r.b+>+#.5 0 J Q B 0 a 8 a z . . a 4.P L #+f+b G g.x g x % & & , m 0 o s [ p #.t <.#.G $ s m % g p ", -"5 P 4 P Q T +.Q S P P 4 4 #.p 9 B K D i T S J A+#.0+E D A ..4 q S S 3 2 s.%.7+2 1 +.@+a /.[ #.l.8.1+#.8 6 !.>.2 6 i D+| I F + 8 E #.L #.p.t n & & P & 5 o s H n o s % C p q q f @+#.g r r s b p ", -"8 9 P J S M.+.S P [ % 4 [ 4 J Q j.Q ..'.|.D a j+l.u.9 D D E s +.J C p 3 2 3 2 %+2 >.K a a #.4 l.>+1 P O ,.Z r.w+S Q -.r.p L & . z a [ G G ; o j a i a Q 5 p o G M j $ p S r.3 %.t #.s m s b & S ", -"9 i 4 4 0+u+%.%.' % . [ 6 |.9 Q w+(.7 L.=+A A ) >+p.J D |.` G T 4 % 4 +.2 1 [.1 3 :.!.a % 4 l.s.&.q 9 /.,.$.r.++T =.E+2 @.T #.% } F % G & { s @ P ` K I d p [ % l M g q | 2 r.A.+.t G n t #.u.B ", -"t r.J @+P B 9 ' a [ J |.J p B ;.T Q [ D v.. . + ; l w . 4 T #+e t #+6.!+!+:.f P K S r.S 0 % S &+s.f P Q ` Q 5 Q <.+ | <.0 5 7.l.P I 8 ' . @ 0 % a Q i i ` [ % I 6 & P #.| >+3 S !+p q c b - C C ", -"t r.P A+q p % A % [ [ 9 6 P S =.T Q a D A M k m m 2.@ f.P T #+q 4 [ r.T 3 S P [ K S S #.% 4 B }+e L +.Q ` 9 P 6 # l j k o g t+| P !.8 D ' 6 J [ [ 8 9 5 5 5 6 I i 0 g r q u+r.@.6.p p 0 b & #.a ", -"#+q J 4 P #+% a [ J O 8 9 !.>.2 ` 9 /...! k ].].y / M M 5 T #.[ z |.K =.C K A+z P S +.4 [ !.>.7+3 3 | ` ` 8 6 a j o l l 0 s p C 9 ` 7 ,.|.8 9 |.K 9 5 a @+6 i 9 i @ j o t j.:.e ++S 9 P p g [ A ", -"q C J P p % % |.' [ 6 9 !.| >.T ,.9 |.|.' . k 2.N 2.k k P T 4 g z J p ;.C B 4 A+[ 5 +.P 8 ` >.V T T h (.8 |.D z y 2.o k $ o g I ,.` 7 ,.9 g+9 |.|.[ [ a z [ i 9 I [ [ 0 L T r.:.1 +.S Q +.q P A+", -":.+.J P #.g.% a a a [ P 9 Q !.S |./.|.|.D z M ~ r o h.k [ Q C [ s p #+s.3 s.3 +.5 #.4 9 O 6 3 7+[.T Q |.6 a A A #.o 2.B., d.~ L ,.,.,.K /.K g+/.8 a 6 9 4 4 Q Q Q 9 d h h T 1 V 5+6.1 2 _._.++3 ", -":.C A+4 s & ~ a a p P P K K 9 |.,.,.,.|.D a ' a [ @ f.k #.C [ [ s #+%.b.c.h+_.:.| C 4 6 J a !.&.X T K 5 6 a [ 9 f p [ ~ k y+o a 9 K K K K 9 9 |.6 a |.i 9 [ 9 | Z $.0.0.Z >.%+s.b.++e &.h+U h+_.", -"1 #.k+#.s r #.z Q Q B r.K 9 O ..8 !.E 9 O |.Y Y a O . . b b b g #.#+l._.d+&.&.2 | 9 4 J ..D B &.$.B I i 5 g p T Q 4 8 [ 8 [ I [ 9 K 9 Q Q Q 9 [ ' [ [ 6 9 S Q h h !.(.` h >.=.s.++l.+.s.c.U 8+c.", -"_.4 @+[ s b a x S T :.S P 6 D v.J K |.|.|...g+'.A O v.. #._ G r a C B }+[.}+ .7+I +.p D D |.3 V B S I d 5 G 4 2 7.C 5 a a ' i % 8 9 Q :.| I p ' . 6 A ~ P I Q B p 6 [ E F d t+w+t+h K .1+b+*+}+", -"r.q S f q r z.- !.i Q L g ' ! ).O A O z [ 4.+ ' #.I z ..a K r.#+| T 2 i.[ i [ L h i 7 J I f | Q ` 5 + 0 @ c b f e $ c m j H r #.Q I f [ Q Q 0+T r.q t % [ 6 |...p t m y r L T ;.t+:.r.p u+&.h+q.", -"< A.b p g u _ - #.p 5 6 0 . . ! 6 |.d 6 % 6 . O 5 d 9 9 J Q Q q [ S %+C P E [ f T P 9 9 h p +.S 6 6 5 j j j & g o , j $ I g G v #+#.f 5 [ #.g u+f p n r @ [ a a g 0 r o c [ Q T 7.T K a Q | e 6.", -"#+G g._ p.u N u f+#.p 6 A . . @ @ [ g % % a A A [ K Q r.r.;.p @+~ C r.S K 8 9 B u+Q ,.` ;.l.I h 8 6 6 2.v # o s . z 0 o o & p | f G & s s s G [ r # 2.<.l l , 0 & n o j c #.p h $.3.` /.a 4 a C ", -"f+g.z.n u u y.z.u r a v.A M o # o o , & a . a } z x G p.< u+4 t.~ p r.S 9 ,.Q T ;.P /.8 7.q +.B 8 ' ' , ,+o z g D 8 E 0 x o 5 T D+u.,+].o 0 l { ,+0 @ I k o n p g & o g j ~ #.5 3 1.h F /.J x ~ ", -"n u G G u n z.] y.n o . f.k 2.m o j s 0 a % ....a x x.x.G.f % j+0 Q r.S 9 6 9 h T P /.J Q q Q K ' J.[ [ o ~ . ' ,.,.|.6 a 6 4 z r.[ % 0 o l $ n s 5 0 8 o I Q e d [ #.g o n & ~ 2+Q q h p [ & o ", -"& r b c u n N n N , x M ~ k 2.m j M ~ s [ ` 8 |.z % & z.Z.% z /.0 I S S /.z a Q B 9 g+a Q 5 B K D z I I g #.5 F d (.a [ % [ a a #.Q I 5 z o j y & p [ 6 ~ !.B T j.[ 0 g x & ~ , g.p.G #.g c o j ", -"~ @ j r m G o o m m # j 2.d.2.@ @ 2.& v % 7.6 ~ x + 0 s v & a a a Q +.P J ~ ' g J J '.A 6 % [ z 9 [ h T #.P F 4.K S 9 d 6 J % D C Q % 0 [ M & { / & 0 0 ~ 0 [ +.9 @+[ g x o $ o r & G g.#.o o c ", -". @ j n , r 0 0 x l # # y K.].. M ~ <.y+H 5 & x 2.0 ].x ].z O ' a B P S O ~ . g 5 ..R ..O % a A z 4 u+7.A.+.` E :.p u.9 P 8 A+a 9 9 v ~ [ s % % N ] B.B.k z g g 4 s J [ & M [ o + 0 0 & 0 & l @ "}; diff --git a/win/macosx/NetHackGuidebook.applescript b/win/macosx/NetHackGuidebook.applescript index 977d4d713..81281a397 100644 --- a/win/macosx/NetHackGuidebook.applescript +++ b/win/macosx/NetHackGuidebook.applescript @@ -1,5 +1,5 @@ #!/usr/bin/osascript -# NetHack 3.6 NetHackGuidebook.applescript $NHDT-Date: 1575245175 2019/12/02 00:06:15 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.10 $ +# NetHack 5.0 NetHackGuidebook.applescript $NHDT-Date: 1596498328 2020/08/03 23:45:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2011 # NetHack may be freely redistributed. See license for details. diff --git a/win/macosx/NetHackRecover.applescript b/win/macosx/NetHackRecover.applescript index c1db10171..c6e81ae0a 100644 --- a/win/macosx/NetHackRecover.applescript +++ b/win/macosx/NetHackRecover.applescript @@ -1,5 +1,5 @@ #!/usr/bin/osascript -# NetHack 3.6 NetHackRecover.applescript $NHDT-Date: 1524684596 2018/04/25 19:29:56 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.9 $ +# NetHack 5.0 NetHackRecover.applescript $NHDT-Date: 1596498329 2020/08/03 23:45:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009 # NetHack may be freely redistributed. See license for details. diff --git a/win/macosx/NetHackTerm.applescript b/win/macosx/NetHackTerm.applescript index 7c31b1610..dfeee0053 100644 --- a/win/macosx/NetHackTerm.applescript +++ b/win/macosx/NetHackTerm.applescript @@ -13,6 +13,11 @@ set debug to false set needshutdown to false + +tell application "Finder" + set bundleAppPath to POSIX path of (application file id "org.nethack.macos" as text) +end tell + tell application "Terminal" # see if we're going to have to shut it down at the end because we started it up if it is not running then @@ -21,7 +26,7 @@ tell application "Terminal" activate #open new window and run NetHack in it - do script with command "clear;sleep 1;/usr/local/bin/nethack;echo '(press RETURN to exit)';awk '{exit}';exit" + do script with command "clear;sleep 1;pwd;" & bundleAppPath & "/Contents/MacOS/nethack;echo '(press RETURN to exit)';awk '{exit}';exit" set nhresult to result -- class is tab set nhresrec to result as record set nhreslist to result as list diff --git a/win/macosx/recover.pl b/win/macosx/recover.pl index bb66c8d89..7fb9411aa 100755 --- a/win/macosx/recover.pl +++ b/win/macosx/recover.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl -# NetHack 3.6 recover.pl $NHDT-Date: 1524684612 2018/04/25 19:30:12 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ +# NetHack 5.0 recover.pl $NHDT-Date: 1596498329 2020/08/03 23:45:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009 # NetHack may be freely redistributed. See license for details. diff --git a/win/share/bmptiles.c b/win/share/bmptiles.c index 641415915..5c6bd09c8 100644 --- a/win/share/bmptiles.c +++ b/win/share/bmptiles.c @@ -1,9 +1,8 @@ -/* NetHack 3.6 bmptiles.c $NHDT-Date: 1457207054 2016/03/05 19:44:14 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.0 $ */ +/* NetHack 5.0 bmptiles.c $NHDT-Date: 1596498334 2020/08/03 23:45:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ */ /* Copyright (c) Ray Chason, 2016. */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" -#include "integer.h" #include "tileset.h" /* First BMP file header */ @@ -61,23 +60,21 @@ struct BitmapInfoHeader { #define BI_JPEG 4 #define BI_PNG 5 -static uint16 FDECL(read_u16, (const unsigned char buf[2])); -static uint32 FDECL(read_u32, (const unsigned char buf[4])); -static int32 FDECL(read_s32, (const unsigned char buf[4])); -static struct Pixel FDECL(build_pixel, (const struct BitmapInfoHeader *, uint32)); -static unsigned char FDECL(pixel_element, (uint32, uint32)); -static boolean FDECL(read_header, (FILE *, struct BitmapHeader *)); -static boolean FDECL(read_info_header, (FILE *, struct BitmapInfoHeader *)); -static boolean FDECL(check_info_header, (const struct BitmapInfoHeader *)); -static unsigned FDECL(get_palette_size, (const struct BitmapInfoHeader *)); -static boolean FDECL(read_palette, (FILE *, struct Pixel *, unsigned)); +static uint16 read_u16(const unsigned char buf[2]); +static uint32 read_u32(const unsigned char buf[4]); +static int32 read_s32(const unsigned char buf[4]); +static struct Pixel build_pixel(const struct BitmapInfoHeader *, uint32); +static unsigned char pixel_element(uint32, uint32); +static boolean read_header(FILE *, struct BitmapHeader *); +static boolean read_info_header(FILE *, struct BitmapInfoHeader *); +static boolean check_info_header(const struct BitmapInfoHeader *); +static unsigned get_palette_size(const struct BitmapInfoHeader *); +static boolean read_palette(FILE *, struct Pixel *, unsigned); /* Read a .BMP file into the image structure */ /* Return TRUE if successful, FALSE on any error */ boolean -read_bmp_tiles(filename, image) -const char *filename; -struct TileSetImage *image; +read_bmp_tiles(const char *filename, struct TileSetImage *image) { struct BitmapHeader header1; struct BitmapInfoHeader header2; @@ -107,15 +104,6 @@ struct TileSetImage *image; if (!read_info_header(fp, &header2)) goto error; if (!check_info_header(&header2)) goto error; -#if 0 /* TODO */ - if (header2.Compression == BI_PNG) { - /* Image data is an embedded PNG bit stream */ - boolean ok = do_read_png_tiles(fp, image)); - fclose(fp); - return ok; - } -#endif - /* header2.Height < 0 means the Y coordinate is reversed; the origin is * top left rather than bottom left */ image->width = header2.Width; @@ -300,7 +288,7 @@ struct TileSetImage *image; break; case 32: for (x = 0; x < image->width; ++x) { - uint32 color = read_u32(row_bytes + x * 2); + uint32 color = read_u32(row_bytes + x * 4); row[x] = build_pixel(&header2, color); } break; @@ -334,9 +322,7 @@ struct TileSetImage *image; /* Read and decode the first header */ static boolean -read_header(fp, header) -FILE *fp; -struct BitmapHeader *header; +read_header(FILE *fp, struct BitmapHeader *header) { unsigned char buf[14]; size_t size; @@ -353,9 +339,7 @@ struct BitmapHeader *header; /* Read and decode the second header */ static boolean -read_info_header(fp, header) -FILE *fp; -struct BitmapInfoHeader *header; +read_info_header(FILE *fp, struct BitmapInfoHeader *header) { unsigned char buf[124]; /* maximum size */ size_t size; @@ -450,8 +434,7 @@ struct BitmapInfoHeader *header; /* Check the second header for consistency and unsupported features */ static boolean -check_info_header(header) -const struct BitmapInfoHeader *header; +check_info_header(const struct BitmapInfoHeader *header) { if (header->NumPlanes != 1) return FALSE; switch (header->BitsPerPixel) { @@ -501,8 +484,7 @@ const struct BitmapInfoHeader *header; /* Return the number of palette entries to read from the file */ static unsigned -get_palette_size(header) -const struct BitmapInfoHeader *header; +get_palette_size(const struct BitmapInfoHeader *header) { switch (header->BitsPerPixel) { case 1: @@ -526,10 +508,7 @@ const struct BitmapInfoHeader *header; * Return TRUE if successful, FALSE on any error */ static boolean -read_palette(fp, palette, palette_size) -FILE *fp; -struct Pixel *palette; -unsigned palette_size; +read_palette(FILE *fp, struct Pixel *palette, unsigned palette_size) { unsigned i; unsigned char buf[4]; @@ -556,8 +535,7 @@ unsigned palette_size; /* Decode an unsigned 16 bit quantity */ static uint16 -read_u16(buf) -const unsigned char buf[2]; +read_u16(const unsigned char buf[2]) { return ((uint16)buf[0] << 0) | ((uint16)buf[1] << 8); @@ -565,8 +543,7 @@ const unsigned char buf[2]; /* Decode an unsigned 32 bit quantity */ static uint32 -read_u32(buf) -const unsigned char buf[4]; +read_u32(const unsigned char buf[4]) { return ((uint32)buf[0] << 0) | ((uint32)buf[1] << 8) @@ -576,8 +553,7 @@ const unsigned char buf[4]; /* Decode a signed 32 bit quantity */ static int32 -read_s32(buf) -const unsigned char buf[4]; +read_s32(const unsigned char buf[4]) { return (int32)((read_u32(buf) ^ 0x80000000) - 0x80000000); } @@ -585,9 +561,7 @@ const unsigned char buf[4]; /* Build a pixel structure, given the mask words in the second header and * a packed 16 or 32 bit pixel */ static struct Pixel -build_pixel(header, color) -const struct BitmapInfoHeader *header; -uint32 color; +build_pixel(const struct BitmapInfoHeader *header, uint32 color) { struct Pixel pixel; @@ -600,16 +574,14 @@ uint32 color; /* Extract one element (red, green, blue or alpha) from a pixel */ static unsigned char -pixel_element(mask, color) -uint32 mask; -uint32 color; +pixel_element(uint32 mask, uint32 color) { uint32 bits, shift; if (mask == 0) return 0; bits = 0xFFFF; /* 0xFF, 0xF, 0x3, 0x1 */ shift = 16; /* 8, 4, 2, 1 */ - while (bits != 0) { + while (shift != 0) { if ((mask & bits) == 0) { mask >>= shift; color >>= shift; diff --git a/win/share/gifread.c b/win/share/gifread.c index 28c5215e1..18c0dd5de 100644 --- a/win/share/gifread.c +++ b/win/share/gifread.c @@ -20,7 +20,7 @@ #include "tile.h" #ifndef MONITOR_HEAP -extern long *FDECL(alloc, (unsigned int)); +extern long *alloc(unsigned int); #endif #define PPM_ASSIGN(p, red, grn, blu) \ @@ -65,24 +65,22 @@ static int tiles_across, tiles_down, curr_tiles_across, curr_tiles_down; static pixel **image; static unsigned char input_code_size; -static int FDECL(GetDataBlock, (FILE * fd, unsigned char *buf)); -static void FDECL(DoExtension, (FILE * fd, int label)); -static boolean FDECL(ReadColorMap, (FILE * fd, int number)); -static void FDECL(read_header, (FILE * fd)); -static int FDECL(GetCode, (FILE * fd, int code_size, int flag)); -static int FDECL(LWZReadByte, (FILE * fd, int flag, int input_code_size)); -static void FDECL(ReadInterleavedImage, (FILE * fd, int len, int height)); -static void FDECL(ReadTileStrip, (FILE * fd, int len)); +static int GetDataBlock(FILE * fd, unsigned char *buf); +static void DoExtension(FILE * fd, int label); +static boolean ReadColorMap(FILE * fd, int number); +static void read_header(FILE * fd); +static int GetCode(FILE * fd, int code_size, int flag); +static int LWZReadByte(FILE * fd, int flag); /*, int input_code_size);*/ +static void ReadInterleavedImage(FILE * fd, int len, int height); +static void ReadTileStrip(FILE * fd, int len); /* These should be in gif.h, but there isn't one. */ -boolean FDECL(fopen_gif_file, (const char *, const char *)); -boolean FDECL(read_gif_tile, (pixel(*) [TILE_X])); -int NDECL(fclose_gif_file); +boolean fopen_gif_file(const char *, const char *); +boolean read_gif_tile(pixel(*) [TILE_X]); +int fclose_gif_file(void); static int -GetDataBlock(fd, buf) -FILE *fd; -unsigned char *buf; +GetDataBlock(FILE *fd, unsigned char *buf) { unsigned char count; @@ -102,12 +100,10 @@ unsigned char *buf; } static void -DoExtension(fd, label) -FILE *fd; -int label; +DoExtension(FILE *fd, int label) { static char buf[256]; - char *str; + const char *str; switch (label) { case 0x01: /* Plain Text Extension */ @@ -169,9 +165,7 @@ int label; } static boolean -ReadColorMap(fd, number) -FILE *fd; -int number; +ReadColorMap(FILE *fd, int number) { int i; unsigned char rgb[3]; @@ -194,8 +188,7 @@ int number; * file, so if that image has a local colormap, overwrite the global one. */ static void -read_header(fd) -FILE *fd; +read_header(FILE *fd) { unsigned char buf[16]; unsigned char c; @@ -294,10 +287,7 @@ FILE *fd; } static int -GetCode(fd, code_size, flag) -FILE *fd; -int code_size; -int flag; +GetCode(FILE *fd, int code_size, int flag) { static unsigned char buf[280]; static int curbit, lastbit, done, last_byte; @@ -338,10 +328,7 @@ int flag; } static int -LWZReadByte(fd, flag, input_code_size) -FILE *fd; -int flag; -int input_code_size; +LWZReadByte(FILE *fd, int flag) /*, int input_code_size)*/ { static int fresh = FALSE; int code, incode; @@ -351,7 +338,7 @@ int input_code_size; static int clear_code, end_code; static int table[2][(1 << MAX_LWZ_BITS)]; static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp; - register int i; + int i; if (flag) { set_code_size = input_code_size; @@ -454,14 +441,12 @@ int input_code_size; } static void -ReadInterleavedImage(fd, len, height) -FILE *fd; -int len, height; +ReadInterleavedImage(FILE *fd, int len, int height) { int v; int xpos = 0, ypos = 0, pass = 0; - while ((v = LWZReadByte(fd, FALSE, (int) input_code_size)) >= 0) { + while ((v = LWZReadByte(fd, FALSE /*, (int) input_code_size*/ )) >= 0) { PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v], ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]); @@ -502,20 +487,18 @@ int len, height; break; } -fini: - if (LWZReadByte(fd, FALSE, (int) input_code_size) >= 0) + fini: + if (LWZReadByte(fd, FALSE /*, (int) input_code_size*/ ) >= 0) Fprintf(stderr, "too much input data, ignoring extra...\n"); } static void -ReadTileStrip(fd, len) -FILE *fd; -int len; +ReadTileStrip(FILE *fd, int len) { int v; int xpos = 0, ypos = 0; - while ((v = LWZReadByte(fd, FALSE, (int) input_code_size)) >= 0) { + while ((v = LWZReadByte(fd, FALSE /*, (int) input_code_size*/ )) >= 0) { PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v], ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]); @@ -530,9 +513,7 @@ int len; } boolean -fopen_gif_file(filename, type) -const char *filename; -const char *type; +fopen_gif_file(const char *filename, const char *type) { int i; @@ -583,7 +564,7 @@ const char *type; exit(EXIT_FAILURE); } - if (LWZReadByte(gif_file, TRUE, (int) input_code_size) < 0) { + if (LWZReadByte(gif_file, TRUE /*, (int) input_code_size*/ ) < 0) { Fprintf(stderr, "error reading image\n"); exit(EXIT_FAILURE); } @@ -599,8 +580,7 @@ const char *type; /* Read a tile. Returns FALSE when there are no more tiles */ boolean -read_gif_tile(pixels) -pixel (*pixels)[TILE_X]; +read_gif_tile(pixel (*pixels)[TILE_X]) { int i, j; @@ -646,7 +626,7 @@ pixel (*pixels)[TILE_X]; } int -fclose_gif_file() +fclose_gif_file(void) { int i; @@ -665,20 +645,21 @@ fclose_gif_file() } #ifndef AMIGA -static char *std_args[] = { "tilemap", /* dummy argv[0] */ - "monsters.gif", "monsters.txt", "objects.gif", - "objects.txt", "other.gif", "other.txt" }; +static const char *const std_args[] = { + "tilemap", /* dummy argv[0] */ + "monsters.gif", "monsters.txt", + "objects.gif", "objects.txt", + "other.gif", "other.txt", +}; int -main(argc, argv) -int argc; -char *argv[]; +main(int argc, char *argv[]) { pixel pixels[TILE_Y][TILE_X]; if (argc == 1) { argc = SIZE(std_args); - argv = std_args; + argv = (char **) std_args; } else if (argc != 3) { Fprintf(stderr, "usage: gif2txt giffile txtfile\n"); exit(EXIT_FAILURE); diff --git a/win/share/giftiles.c b/win/share/giftiles.c index 911ea3c21..1fdf1a0bc 100644 --- a/win/share/giftiles.c +++ b/win/share/giftiles.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 giftiles.c $NHDT-Date: 1457358406 2016/03/07 13:46:46 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.0 $ */ +/* NetHack 5.0 giftiles.c $NHDT-Date: 1596498335 2020/08/03 23:45:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ */ /* Copyright (c) Ray Chason, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -45,14 +45,15 @@ struct DataBlock { unsigned char *data; }; -static boolean FDECL(read_data_block, (struct Bitstream *gif, struct DataBlock *block)); -static void FDECL(free_data_block, (struct DataBlock *block)); -static unsigned short FDECL(read_u16, (const unsigned char buf[2])); -static void FDECL(init_decoder, (struct Bitstream *gif, unsigned bit_width)); -static void FDECL(reset_decoder, (struct Bitstream *gif)); -static int FDECL(decode, (struct Bitstream *gif, struct DataBlock *block)); -static int FDECL(get_code, (struct Bitstream *gif, struct DataBlock *block)); -static unsigned FDECL(interlace_incr, (unsigned y, unsigned height)); +static boolean read_data_block(struct Bitstream *gif, + struct DataBlock *block); +static void free_data_block(struct DataBlock *block); +static unsigned short read_u16(const unsigned char buf[2]); +static void init_decoder(struct Bitstream *gif, unsigned bit_width); +static void reset_decoder(struct Bitstream *gif); +static int decode(struct Bitstream *gif, struct DataBlock *block); +static int get_code(struct Bitstream *gif, struct DataBlock *block); +static unsigned interlace_incr(unsigned y, unsigned height); /* * GIF specifies a canvas, which may have a palette (the "global color table") @@ -64,9 +65,7 @@ static unsigned FDECL(interlace_incr, (unsigned y, unsigned height)); */ boolean -read_gif_tiles(filename, image) -const char *filename; -struct TileSetImage *image; +read_gif_tiles(const char *filename, struct TileSetImage *image) { struct Bitstream gif; struct DataBlock block; @@ -158,7 +157,7 @@ struct TileSetImage *image; boolean have_lct, interlace; unsigned lct_start, lct_size; struct Pixel lct[256]; - int b; + int new_b; unsigned x, y, x2, y2; size = fread(buf, 1, 9, gif.fp); @@ -203,23 +202,23 @@ struct TileSetImage *image; } } /* 22. Table based image data */ - b = fgetc(gif.fp); - if (b == EOF) goto error; - if (b < MIN_LZW_BITS - 1 || MAX_LZW_BITS - 1 < b) goto error; - init_decoder(&gif, b); + new_b = fgetc(gif.fp); + if (new_b == EOF) goto error; + if (new_b < MIN_LZW_BITS - 1 || MAX_LZW_BITS - 1 < new_b) goto error; + init_decoder(&gif, new_b); x = 0; y = 0; if (!read_data_block(&gif, &block)) goto error; while (TRUE) { - b = decode(&gif, &block); - if (b == EOF) goto error; - if (b == END_OF_DATA) break; + new_b = decode(&gif, &block); + if (new_b == EOF) goto error; + if (new_b == END_OF_DATA) break; if (y >= img_height) goto error; x2 = img_left + x; y2 = img_top + y; if (x2 < image->width && y2 < image->height) { - image->pixels[y2 * image->width + x2] = lct[b]; - image->indexes[y2 * image->width + x2] = b + lct_start; + image->pixels[y2 * image->width + x2] = lct[new_b]; + image->indexes[y2 * image->width + x2] = new_b + lct_start; } ++x; if (x >= img_width) { @@ -310,9 +309,7 @@ struct TileSetImage *image; } static void -init_decoder(gif, bit_width) -struct Bitstream *gif; -unsigned bit_width; +init_decoder(struct Bitstream *gif, unsigned bit_width) { unsigned i; unsigned clear; @@ -335,8 +332,7 @@ unsigned bit_width; } static void -reset_decoder(gif) -struct Bitstream *gif; +reset_decoder(struct Bitstream *gif) { /* Set the bit width */ gif->bit_width = gif->initial_bit_width + 1; @@ -349,9 +345,7 @@ struct Bitstream *gif; } static int -decode(gif, block) -struct Bitstream *gif; -struct DataBlock *block; +decode(struct Bitstream *gif, struct DataBlock *block) { int code; unsigned clear = 1 << gif->initial_bit_width; @@ -364,12 +358,12 @@ struct DataBlock *block; /* Get the next code, until code other than clear */ while (TRUE) { code = get_code(gif, block); - if (code != clear) break; + if ((unsigned) code != clear) break; reset_decoder(gif); } if (code == EOF) return EOF; - if (code == clear + 1) return END_OF_DATA; + if ((unsigned) code == clear + 1) return END_OF_DATA; if (code > gif->dict_size) return EOF; /* Add a new string to the dictionary */ @@ -396,7 +390,7 @@ struct DataBlock *block; /* code is less than gif->dict_size and not equal to clear or clear + 1 */ /* Prepare the decoded string for return; note that it is stored in * reverse order */ - while (code >= clear) { + while ((unsigned) code >= clear) { gif->string[gif->str_size++] = gif->dictionary[code].byte; code = gif->dictionary[code].next; } @@ -405,9 +399,7 @@ struct DataBlock *block; } static int -get_code(gif, block) -struct Bitstream *gif; -struct DataBlock *block; +get_code(struct Bitstream *gif, struct DataBlock *block) { int code; @@ -426,9 +418,7 @@ struct DataBlock *block; } static unsigned -interlace_incr(y, height) -unsigned y; -unsigned height; +interlace_incr(unsigned y, unsigned height) { static const unsigned char incr[] = { 8, 2, 4, 2 }; @@ -457,17 +447,14 @@ unsigned height; /* Decode an unsigned 16 bit quantity */ static unsigned short -read_u16(buf) -const unsigned char buf[2]; +read_u16(const unsigned char buf[2]) { return ((unsigned short)buf[0] << 0) | ((unsigned short)buf[1] << 8); } static boolean -read_data_block(gif, block) -struct Bitstream *gif; -struct DataBlock *block; +read_data_block(struct Bitstream *gif, struct DataBlock *block) { long pos = ftell(gif->fp); int b; @@ -494,7 +481,8 @@ struct DataBlock *block; b = fgetc(gif->fp); if (b == EOF) return FALSE; if (b == 0) break; - if (fread(block->data + i, 1, b, gif->fp) != b) return FALSE; + if (fread(block->data + i, 1, b, gif->fp) != (unsigned) b) + return FALSE; i += b; } @@ -503,8 +491,7 @@ struct DataBlock *block; } static void -free_data_block(block) -struct DataBlock *block; +free_data_block(struct DataBlock *block) { free(block->data); block->size = 0; diff --git a/win/share/monsters.txt b/win/share/monsters.txt index f2b81fc6e..acc435a2f 100644 --- a/win/share/monsters.txt +++ b/win/share/monsters.txt @@ -1,3 +1,6 @@ +# monsters.txt - tile definitions for monsters +# Note: lines beginning with '# tile ' are not comments; other +# lines beginning with '#' are. . = (71, 108, 108) A = (0, 0, 0) B = (0, 182, 255) @@ -27,7 +30,7 @@ Y = (149, 149, 149) Z = (195, 195, 195) 0 = (100, 100, 100) 1 = (72, 108, 108) -# tile 0 (giant ant) +# tile 0 (giant ant,male) { ................ ................ @@ -46,7 +49,51 @@ Z = (195, 195, 195) ......JA.JA..... ................ } -# tile 1 (killer bee) +# +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female ants are slightly larger than male ants, just like in real +# life. I could have added wings to the male ants, but I felt that +# doing so would lead to some confusion. +# +# tile 1 (giant ant,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ......J......... + ......AJAJKKA... + ....JJAAAKJJJA.. + ....AAKJJAJJAA.. + ...KKAJJJAAA.... + ..BJJAAAAAJJ.... + ..JBJAJAJAAAJ... + .....AJA.JA..... + ......JA.JA..... + ................ +} +# tile 2 (killer bee,male) +{ + ................ + ................ + .PPP.....PP..... + PPPPP...PBPP.... + PBPPP..PBPPP.... + .PPBP.PPLPLL.... + ...PP.PLLALHAH.. + ...AKKKLAHAAHH.. + BBJJJJJJJAHHAA.. + ABJBBJJJJAHAHH.. + .JJABJAJ.J.HH... + .......J.J...... + ................ + ...AAAAAAAAAAA.. + .....AAAAAA..... + ................ +} +# tile 3 (killer bee,female) { ................ ................ @@ -65,7 +112,7 @@ Z = (195, 195, 195) .....AAAAAA..... ................ } -# tile 2 (soldier ant) +# tile 4 (soldier ant,male) { ................ ................ @@ -84,7 +131,26 @@ Z = (195, 195, 195) ..JJAAJA.JA..... ................ } -# tile 3 (fire ant) +# tile 5 (soldier ant,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ......JJAJKKA... + ....JJAAAKJJJA.. + ....AAKJJAJJAA.. + .JJKKAJJJAAA.... + JBJJJAAAAAJJ.... + JJJBJAJAJAAAJ... + JAAJJAJA.JA..... + ..JJAAJA.JA..... + ................ +} +# tile 6 (fire ant,male) { ................ ................ @@ -103,7 +169,45 @@ Z = (195, 195, 195) ......DA.DA..... ................ } -# tile 4 (giant beetle) +# tile 7 (fire ant,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ......D......... + ......ADACCCA... + ....DDAAACDDDA.. + ....AACDDADDAA.. + ...CCADDDAAA.... + ..GDDAAAAADD.... + ..DGDADADAAAD... + .....ADA.DA..... + ......DA.DA..... + ................ +} +# tile 8 (giant beetle,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ......KKDKK..... + ....KACLCJJD.... + ...KCLCJJDDDK... + ...DCCJDADDAD... + ...ADJDDDDDDD... + ...BAKDDAADKAA.. + ...ABAKDDK...... + ......AA.AA..... + ................ + ................ +} +# tile 9 (giant beetle,female) { ................ ................ @@ -122,7 +226,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 5 (queen bee) +# tile 10 (queen bee,male) +{ + ................ + .PPP.....PP..... + PPPPP...PPPP.... + PPPPP..PPBPP.... + PBPPP..PBPPP.... + .PPBP.PPLPLL.... + ...PP.PLLALHAH.. + ...AKKKLAHAAHH.. + BBJJJJJJJAHHAAH. + ABJBBJJJJAHAHHH. + .JJABJAJ.JHHHAA. + ...J...J.JAAAHH. + ..JJ..JJ.J.HHAH. + ..JAAAJAAJ..HH.. + .....AAAAAA..... + ................ +} +# tile 11 (queen bee,female) { ................ .PPP.....PP..... @@ -141,7 +264,26 @@ Z = (195, 195, 195) .....AAAAAA..... ................ } -# tile 6 (acid blob) +# tile 12 (acid blob,male) +{ + ................ + ................ + ................ + .....KDDA....... + ...DDKDDKA...... + .DDDIIIDJDA..... + D.IIOOIIDAIA.... + .DKNNNODIDA..IA. + IDJNANOJDDJA.... + ADIDNOIDIDDDA... + ...JDIKIADKIA... + .IA.IDID.JDA.... + ...I.DDA....DA.. + .........IA..... + ..IA............ + ................ +} +# tile 13 (acid blob,female) { ................ ................ @@ -160,7 +302,26 @@ Z = (195, 195, 195) ..IA............ ................ } -# tile 7 (quivering blob) +# tile 14 (quivering blob,male) +{ + ................ + ................ + .....PPPP....... + .........P...... + .P.OOOPPE..AAA.. + P.OPBBBPOEAEAA.. + P.PBNNNP.OEAAEA. + P.PNNNNNPOEEAEA. + POPNAANNEO.OAEA. + .OPNAANNE..OAAA. + .OPBNNNEPP.OEAA. + BPOPEEEBBPO.EEA. + BBBPBBBBBBPPPPA. + ..BBBBBBBBBBPA.. + ................ + ................ +} +# tile 15 (quivering blob,female) { ................ ................ @@ -179,7 +340,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 8 (gelatinous cube) +# tile 16 (gelatinous cube,male) { ................ ................ @@ -198,7 +359,45 @@ Z = (195, 195, 195) ................ ................ } -# tile 9 (chickatrice) +# tile 17 (gelatinous cube,female) +{ + ................ + ................ + ................ + ................ + ................ + .......LLL...... + .....LLLLLLLL... + ...LLLLLLLLLD... + ...CLLLLLLLDDA.. + ...CGGCLLLDDDAA. + ...CAGCGGDDDDAAA + ...CCCCAGDDDAAAA + .....CCCCDDAAAA. + .......CCDAAA... + ................ + ................ +} +# tile 18 (chickatrice,male) +{ + ................ + ................ + ................ + ................ + .......OO....... + ......HAOO...... + .....HHOOH.HHA.. + ........OOHOA... + ........OOFA.... + ........FGGFA... + ........AGFGAA.. + ...........GA... + .......F..FFA... + .......AFFAA.... + ........AA...... + ................ +} +# tile 19 (chickatrice,female) { ................ ................ @@ -217,7 +416,26 @@ Z = (195, 195, 195) ........AA...... ................ } -# tile 10 (cockatrice) +# tile 20 (cockatrice,male) +{ + ................ + ...D.DD......... + ....DD.......... + ....NL..AA...... + ..HHAN.AAA...... + .HH.NO..AAAA.... + ...AOOLFFFAA.... + ...OOLKGGFFAA... + ...AOAGGFGFFAA.. + .......GFFGFAA.. + .........FGGAA.. + .....FA...FFA... + ....FA....FFA... + ....FA..FFFA.... + .....FFFFA...... + ................ +} +# tile 21 (cockatrice,female) { ................ ...D.DD......... @@ -236,7 +454,26 @@ Z = (195, 195, 195) .....FFFFA...... ................ } -# tile 11 (pyrolisk) +# tile 22 (pyrolisk,male) +{ + ................ + ...D.DD......... + ....DD.......... + ....NB..AA...... + ..HHAN.AAA...... + .HH.NB..AAAA.... + ...APBBJJJAA.... + ...PPPKDDKJAA... + ...APADDKDKJAA.. + .......DJKDJAA.. + .........JDDAA.. + .....JA...JJA... + ....JA....JJA... + ....KA..KKKA.... + .....JKKKA...... + ................ +} +# tile 23 (pyrolisk,female) { ................ ...D.DD......... @@ -255,7 +492,26 @@ Z = (195, 195, 195) .....JKKKA...... ................ } -# tile 12 (jackal) +# tile 24 (jackal,male) +{ + ................ + ................ + ................ + ................ + ...O..O......... + ...O.OO...O..... + ..OOOO.....O.... + ..IOIOO....O.A.. + .OLLOOOL...O.A.. + DOOOAOOOOOOOAA.. + ..AAOOOOOOOOAA.. + ....OJOOOOOLAA.. + ....OJOLKALKAA.. + ...OOAOAAAOAA... + .....OO..OOA.... + ................ +} +# tile 25 (jackal,female) { ................ ................ @@ -274,7 +530,26 @@ Z = (195, 195, 195) .....OO..OOA.... ................ } -# tile 13 (fox) +# tile 26 (fox,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ....C........... + ....C........... + ..CCAC...CCC.... + ..ACCCCCCACCC... + ...AACCCC.ACC... + ....ACAAC..AA... + ...AC.ACA....... + ................ +} +# tile 27 (fox,female) { ................ ................ @@ -293,7 +568,26 @@ Z = (195, 195, 195) ...AC.ACA....... ................ } -# tile 14 (coyote) +# tile 28 (coyote,male) +{ + ................ + ................ + ................ + ...K..K......... + ...K.KK......KKK + ..KKKK......KKKA + ..NCNK.KKKKKAAA. + .KCCKKKKKKKKK... + KKCKAKKKKKKKK... + DKKKAKAKKKKAK... + ..AAKAAKAAAAK... + ....AKAKAAAAK... + ...AKKAKA.AKK... + .....AKK........ + ................ + ................ +} +# tile 29 (coyote,female) { ................ ................ @@ -312,7 +606,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 15 (werejackal) +# tile 30 (werejackal,male) { ................ ................ @@ -331,14 +625,52 @@ Z = (195, 195, 195) ...L.LL..OOA.... ......L......... } -# tile 16 (little dog) +# tile 31 (werejackal,female) { ................ ................ ................ ................ - ...J..J......... - ...J.JJ...K..... + ...O..O......... + ...O.OO...O..... + ..OOOO.....O.... + ..IOIOO....O.A.. + .OLLOOOL...O.A.. + DOOOALLOOOOOAA.. + ..AALLLLOOOOAA.. + ....LJLLLOOLAA.. + ....LJLLKALKAA.. + ..LLLALAAAOAA... + ...L.LL..OOA.... + ......L......... +} +# tile 32 (little dog,male) +{ + ................ + ................ + ................ + ................ + ...J..J......... + ...J.JJ...K..... + ..JJJJ.....K.... + ..NJNKK....K.A.. + .JJJCKK....K.A.. + .PJJAKCKKCKKAA.. + .DDAACKKCKKKAA.. + ....KJKJCJKJAA.. + ....KJKJJAJJAA.. + ...KKAKAAAKAA... + .....KK...KA.... + ................ +} +# tile 33 (little dog,female) +{ + ................ + ................ + ................ + ................ + ...J..J......... + ...J.JJ...K..... ..JJJJ.....K.... ..NJNKK....K.A.. .JJJCKK....K.A.. @@ -350,7 +682,26 @@ Z = (195, 195, 195) .....KK...KA.... ................ } -# tile 17 (dingo) +# tile 34 (dingo,male) +{ + ................ + ................ + ................ + .............C.. + ...C..C.......C. + ...C.CC.......CA + ..CCCCK.......CA + ..ACACCKCCCCCCAA + ..LLCCCKCCCLCCCA + .KCCACKCLLLLACCA + ..AACAACLLAAACCA + ....ACACAAAAAACA + ....CCACAAA..CCA + .....ACCA....... + ................ + ................ +} +# tile 35 (dingo,female) { ................ ................ @@ -369,7 +720,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 18 (dog) +# tile 36 (dog,male) +{ + ................ + ................ + ................ + ...J..J.....K... + ...J.JJ......K.. + ..JJJJ.......K.. + ..NJNKK......K.A + .JJJCKKKK....K.A + .PJCAKCKKKKCKKAA + .DDAACKKKKCKKKAA + ..AAKJKKJJCJKJAA + ....KJKKJJJAJJAA + ....KAKJAAAAKJA. + ...KKAKAAAAAKAA. + .....KKAA...KA.. + ................ +} +# tile 37 (dog,female) { ................ ................ @@ -388,7 +758,26 @@ Z = (195, 195, 195) .....KKAA...KA.. ................ } -# tile 19 (large dog) +# tile 38 (large dog,male) +{ + ................ + ................ + ...J..J.....K... + ...J.JJ......K.. + ..JJJJ.......K.. + ..NJNKKK.....K.A + .JJJCKKKKK..JK.A + .PJCAKCKKKKCKKAA + .DDAACKKKKCKKKAA + ..AAKJKKJJCJKJAA + ...JKJKKJJJAJJAA + ....KAKJAAAAKJA. + ....KAKJAAAAKJA. + ...KKAKAAAAAKAA. + .....KKAA...KA.. + ................ +} +# tile 39 (large dog,female) { ................ ................ @@ -407,7 +796,7 @@ Z = (195, 195, 195) .....KKAA...KA.. ................ } -# tile 20 (wolf) +# tile 40 (wolf,male) { ................ ................ @@ -426,7 +815,33 @@ Z = (195, 195, 195) .....PPAA..PPA.. ................ } -# tile 21 (werewolf) +# +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female wolves are slightly smaller than male wolves. +# There wasn't a great way to show this without making winter wolves +# look very similar to winter wolf cubs, so I just made the female +# wolves tails slightly shorter. +# +# tile 41 (wolf,female) +{ + ................ + ................ + ................ + ...P..P......... + ...P.PP......P.. + ..PPPP.......P.. + ..N.NPP......P.A + .P..PPPPP....P.A + PP.PAPPPPPPPPPAA + DPPPAPPPPPPPPPAA + ..AAP.PP..P.P.AA + ....P.PP...A.PAA + ....PAP.AAAAP.A. + ...PPAPAAAAAPAA. + .....PPAA..PPA.. + ................ +} +# tile 42 (werewolf,male) { ................ ................ @@ -445,7 +860,29 @@ Z = (195, 195, 195) ...L.LLAA..PP... .....LL......... } -# tile 22 (winter wolf cub) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female werewolves wear slightly different clothing. +# +# tile 43 (werewolf,female) +{ + ................ + ................ + ................ + ...P..P......... + ...P.PP......P.. + ..PPPP.......P.. + ..N.NPP......P.A + .P..PPPPP....P.A + PP.PAPPPPPPPPPAA + DPPPALPPPPPPPPAA + ..AALLPL..P.P.AA + ....L.LL...A.PAA + ....LAL.AAAAP.A. + ..LLLALAAAAAPPA. + ...L.LLAA..PP... + .....LL......... +} +# tile 44 (winter wolf cub,male) { ................ ................ @@ -464,26 +901,64 @@ Z = (195, 195, 195) .....NB..NBA.... ................ } -# tile 23 (warg) +# tile 45 (winter wolf cub,female) { ................ - ...P..P....PP... - ...P.PP......P.. - ..PPPP.......P.A - ..N.NPP......P.A - .P..PPPPP....P.A - PPPPDPPPPPPPPPAA - DPPNDPPPPPPPPPAA - ..DDDPPPPPPPPPAA - PNDNP.PPPPPPPPAA - .PPPPAPPPPAPP.A. - ...PAAPPAAAAPPAA - ...PAAP.AAAAP.A. - .PPPAAPAAAAAPAA. - ....PPPAA.PPPA.. + ................ + ................ + ................ + ...N..N......... + ...N.NB......... + ..NNNN.....N.... + ..DNDNB....N.A.. + ..NNNNB....N.A.. + .NNNNNNNNNNNAA.. + .DNBBNNNNNNBAA.. + ....NNNNNNNBAA.. + ....NNNBBANBAA.. + ...NBANAAANAA... + .....NB..NBA.... + ................ +} +# tile 46 (warg,male) +{ + ................ + ...P..0....P0... + ...0.0P......0.. + ..0P0P.......P.A + ..N.N0P......0.A + .P..0P0P0....P.A + P0P0D0P0P0P0P0AA + DP0NDP0P0P0P0PAA + ..DDD0P0P0P0P0AA + 0NDN0.0P0P0P0PAA + .0P0PAP0P0A0P.A. + ...PAA0PAAAA0PAA + ...0AAP.AAAAP.A. + .P0PAA0AAAAA0AA. + ....P0PAA.P0PA.. + ................ +} +# tile 47 (warg,female) +{ + ................ + ...P..0.....P... + ...0.0P......0.. + ..0P0P.......P.A + ..N.N0P......0.A + .P..0P0P0....P.A + P0P0D0P0P0P0P0AA + DP0NDP0P0P0P0PAA + ..DDD0P0P0P0P0AA + 0NDN0.0P0P0P0PAA + .0P0PAP0P0A0P.A. + ...PAA0PAAAA0PAA + ...0AAP.AAAAP.A. + .P0PAA0AAAAA0AA. + ....P0PAA.P0PA.. ................ } -# tile 24 (winter wolf) +# tile 48 (winter wolf,male) { ................ ................ @@ -502,7 +977,45 @@ Z = (195, 195, 195) .....NNAA..NNA.. ................ } -# tile 25 (hell hound pup) +# tile 49 (winter wolf,female) +{ + ................ + ................ + ................ + ...N..N......... + ...N.NN......N.. + ..NNNN.......N.. + ..DODNN......N.A + .NOONNNNN....N.A + NNONANNNNNNNNNAA + DNNBANNNNNNNNNAA + ..AANNNNNNNBNNAA + ....NBNNNBBANNAA + ....NANBAAAANBA. + ...NNANAAAAANAA. + .....NNAA..NNA.. + ................ +} +# tile 50 (hell hound pup,male) +{ + ................ + ................ + ................ + ................ + ...C..C......... + ...C.CC...C..... + ..CCCC.....C.... + ..DCDCC....C.A.. + .CCCCCC....C.A.. + .PCCACCCCCCCAA.. + .CHAACCCCCCCAA.. + CHC.CCCCCCCCAA.. + .D..CCCCCACCAA.. + ...CCACAAACAA... + .....CC...CA.... + ................ +} +# tile 51 (hell hound pup,female) { ................ ................ @@ -521,7 +1034,26 @@ Z = (195, 195, 195) .....CC...CA.... ................ } -# tile 26 (hell hound) +# tile 52 (hell hound,male) +{ + ................ + ...C..C....CC... + ...C.CC......C.. + ..CCCC.......C.A + ..DJDCC......C.A + .CCCCCCCC....C.A + CCCCDCCCCCCCCCAA + .CHC.CCCCCCCCCAA + CHC..CCCCCCCCCAA + .D..CCCCCCCCCCAA + ...CCACCCCACC.A. + ...CAACCAAAACCAA + ...CAAC.AAAAC.A. + .CCCAACAAAAACAA. + ....CCCAA.CCCA.. + ................ +} +# tile 53 (hell hound,female) { ................ ...C..C....CC... @@ -540,7 +1072,26 @@ Z = (195, 195, 195) ....CCCAA.CCCA.. ................ } -# tile 27 (Cerberus) +# tile 54 (Cerberus,male) +{ + ................ + ..J..J.......... + ..JJJJ.J..J..... + .NJNJ..J.JJ..... + JJJJKAJJJJ....J. + PJJJJANJNKK...J. + DJKJAJJJKJJK..J. + ..AAJPJKAJKJKJJ. + ..JJJDDAJKJJJJJA + ..JJJAAJJJJJJJJA + .JKKKJJJKJJKJJAA + .JJAAKJJKJJJKJAA + JJAAAAJJAAAAJJA. + JAAAAAJAAAAAJAA. + .....JJAA...JA.. + ................ +} +# tile 55 (Cerberus,female) { ................ ..J..J.......... @@ -559,7 +1110,26 @@ Z = (195, 195, 195) .....JJAA...JA.. ................ } -# tile 28 (gas spore) +# tile 56 (gas spore,male) +{ + ................ + ................ + ................ + .....PFGGFP..... + ....PGFFFFFP.... + ...PFFFFFGGFP... + ...FFGGFFGGFF... + ...GFGGFFFFFG... + ...GFFFFFFFFG... + ...FFFFGGFFFF... + ...PGGFGGFGGP... + ....PGFFFFGP.... + .....PFGGFP..... + ................ + ................ + ................ +} +# tile 57 (gas spore,female) { ................ ................ @@ -578,7 +1148,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 29 (floating eye) +# tile 58 (floating eye,male) { ................ ................ @@ -597,27 +1167,84 @@ Z = (195, 195, 195) ................ ................ } -# tile 30 (freezing sphere) +# tile 59 (floating eye,female) { ................ ................ - ......PBBBP..... - ....PBBBBBBBP... - ....BBBBBBBBB... - ...PBPPPBBBBBP.. - ...BBNNBBPPPBB.. - ...BBANPBNNBBB.. - ...PBBPPBANPBP.. - ....BBBBBBPPB... - ....PBBBBBBBPAA. - ......PBBBPAAAA. - ......AAAAAAAAA. - .......AAAAAAA.. - ................ - ................ -} -# tile 31 (flaming sphere) -{ + ......ONNNO..... + ....PNNNNNNNP... + ....NNNNNNNNN... + ...ONNBBBBNNNO.. + ...NNBBEEBBNNN.. + ...NNBEAAEBNNN.. + ...ONBEAAEBNNO.. + ....NBBEEBBNN... + ....PNBBBBNNPAA. + ......ONNNOAAAA. + ......AAAAAAAAA. + .......AAAAAAA.. + ................ + ................ +} +# tile 60 (freezing sphere,male) +{ + ................ + ................ + ......PBBBP..... + ....PBBBBBBBP... + ....BBBBBBBBB... + ...PBPPPBBBBBP.. + ...BBNNBBPPPBB.. + ...BBANPBNNBBB.. + ...PBBPPBANPBP.. + ....BBBBBBPPB... + ....PBBBBBBBPAA. + ......PBBBPAAAA. + ......AAAAAAAAA. + .......AAAAAAA.. + ................ + ................ +} +# tile 61 (freezing sphere,female) +{ + ................ + ................ + ......PBBBP..... + ....PBBBBBBBP... + ....BBBBBBBBB... + ...PBPPPBBBBBP.. + ...BBNNBBPPPBB.. + ...BBANPBNNBBB.. + ...PBBPPBANPBP.. + ....BBBBBBPPB... + ....PBBBBBBBPAA. + ......PBBBPAAAA. + ......AAAAAAAAA. + .......AAAAAAA.. + ................ + ................ +} +# tile 62 (flaming sphere,male) +{ + ................ + ....C...H....... + ....C....O...C.. + ...C..H.CC...C.. + ...C..C.CC..CC.. + ...DCA.DDC.ACC.. + .AHCDCADDCAADC.. + .AACDCDDDDDADD.. + ..ACDDDJJJDDDD.. + ..ADDCAKDDACDD.. + ...ADAKDDCDAD... + ...ADADHCHCAD... + ....DADDDCDAD... + .....DADDDAD.... + ......JJJJJ..... + ................ +} +# tile 63 (flaming sphere,female) +{ ................ ....C...H....... ....C....O...C.. @@ -635,7 +1262,26 @@ Z = (195, 195, 195) ......JJJJJ..... ................ } -# tile 32 (shocking sphere) +# tile 64 (shocking sphere,male) +{ + ................ + .....PPPPPP..... + ...PPIAAADAPP... + ..PAAAIAAADDAP.. + ..PHAAAPBOAAAP.. + .PAHHAPBBBOAAAP. + .PHAAAPBBBBAHHP. + .PAAAAPPBBBAAAP. + .PAAAIAPPPAAAIP. + .PIIIAAAAAAIIAP. + ..PIAANAAPAAAIP. + ..PIAANAAAPAAP.. + ...PANANAPAPAP.. + ....PPAIAPAPP... + ......PPPPP..... + ................ +} +# tile 65 (shocking sphere,female) { ................ .....PPPPPP..... @@ -654,7 +1300,26 @@ Z = (195, 195, 195) ......PPPPP..... ................ } -# tile 33 (beholder) +# tile 66 (beholder,male) +{ + ....OA..OA...... + ..OA.DADA.OA.OA. + ...DA.DADADADD.. + ..OADDOOOODDADO. + ...DDHOAAOHDDA.. + ...JDHOAAOHDDJ.. + ...DDDOOOODDDD.. + ...DDDDDDDDDDD.. + ...JDAOAAAOADJ.. + ....DDAAOAADD... + ....PDDDDDDDPAA. + ......JDDDJAAAA. + ......AAAAAAAAA. + .......AAAAAAA.. + ................ + ................ +} +# tile 67 (beholder,female) { ....OA..OA...... ..OA.DADA.OA.OA. @@ -673,7 +1338,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 34 (kitten) +# tile 68 (kitten,male) { ................ ................ @@ -692,7 +1357,26 @@ Z = (195, 195, 195) ......CCA..CA... ................ } -# tile 35 (housecat) +# tile 69 (kitten,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ...........N.... + ............N... + ....N.N.....C.A. + ...NNNNC....C.A. + ...ENENNNJJNC.A. + ...NNNNNJJJNNAA. + ....IANNJJNNNAA. + .....NANNWNNWA.. + ......NNA..NA... + ................ +} +# tile 70 (housecat,male) { ................ ................ @@ -711,7 +1395,51 @@ Z = (195, 195, 195) .....CCA...CA... ................ } -# tile 36 (jaguar) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Calico cats are almost exclusively female, so I turned the female cats +# into calico cats. The other piece of logic behind this choice was that +# players will probably really enjoy seeing different variants of their +# pets. +# +# tile 71 (housecat,female) +{ + ................ + ................ + ................ + ................ + ................ + ...........N.... + ............N... + ...N.N......C.A. + ..NNNNC.....C.A. + .NANANCNJJJNN.A. + .NNNNNNNJJNNNAA. + ..NINWNJJJNNNAA. + ...AANNNNNNNNAA. + ...NNANNWWNNWA.. + .....NNA...NA... + ................ +} +# tile 72 (jaguar,male) +{ + ................ + ................ + ................ + ................ + ..C..C......C... + ..CC.CJ......C.A + .CCCCCJ......C.A + .GCGCCJCAACCJC.A + .CCCCCJCCCCCCCAA + .CDDDJCAACCAJCAA + ..CCACCAJCCAACAA + ....CACCJJJCCJA. + ....CACAAAAACJA. + ...CKACAAAAACAA. + .....CCAA...CA.. + ................ +} +# tile 73 (jaguar,female) { ................ ................ @@ -730,7 +1458,26 @@ Z = (195, 195, 195) .....CCAA...CA.. ................ } -# tile 37 (lynx) +# tile 74 (lynx,male) +{ + ................ + ................ + ................ + ................ + O....O.......... + AC.CCA.......... + .CCCA........CA. + .GCGCOAKKKKK.LA. + .CKCCAJCCCCCKA.. + LLDDLLACLLLCCAA. + ..CC.AACLLLCCAA. + .......CAAAACAA. + ....CACAAAACCA.. + ................ + ................ + ................ +} +# tile 75 (lynx,female) { ................ ................ @@ -749,7 +1496,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 38 (panther) +# tile 76 (panther,male) +{ + ................ + ................ + ............AA.. + ..............A. + ..............A. + .A...A........A. + .EA.AE........A. + .AAAAAEAAAAAAA.. + .AAAAAEAAAAAAA.. + .HAHAA.AAAAAAAA. + .AAAA.AAAAAEAAA. + .AAA..AAAAAEAAA. + .....AA....AAA.. + ..AAAA..AAAA.... + ................ + ................ +} +# tile 77 (panther,female) { ................ ................ @@ -768,7 +1534,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 39 (large cat) +# tile 78 (large cat,male) { ................ ................ @@ -787,7 +1553,45 @@ Z = (195, 195, 195) .....CCAA...CA.. ................ } -# tile 40 (tiger) +# tile 79 (large cat,female) +{ + ................ + ................ + ................ + ................ + ............N... + .............N.. + ...N.N.......C.A + ..NNNNC......C.A + .NANANCNJJJJNN.A + .NNNNNNNJJJNNNAA + ..NDNWNJJJNNNNAA + ...AANNNNNNNNNAA + ....NANNWWWNNWA. + ...NJANAAAAANAA. + .....NNAA...NA.. + ................ +} +# tile 80 (tiger,male) +{ + ................ + ................ + ................ + ................ + ..C..C......C... + .CCJCC.......C.A + .CAACCJ......A.A + .GAGCCJACACAJC.A + .CCCCCACACACACAA + .ODOCACCACACACAA + .OCOACCJACACACAA + ....CACJAJAJCAA. + ....AACAAAAAAJA. + ...CKACAAAAACAA. + .....CCAA..CCA.. + ................ +} +# tile 81 (tiger,female) { ................ ................ @@ -806,7 +1610,64 @@ Z = (195, 195, 195) .....CCAA..CCA.. ................ } -# tile 41 (gremlin) +# tile 82 (displacer beast,male) +{ + ................ + ........E....... + .......E.E..AA.. + DEEEA..A.E....A. + ....EA.E.D....A. + .A...A.E......A. + .EA.AEAAA.....A. + .AAAAAAAAAA..A.. + .AAAAEAAAAAAAA.. + .HAHAEAAAAAAAAA. + .AAAAEAAAAAAAAA. + .AAA.AAAAAAAAAA. + .....AE.AEEA.EA. + ....AE.AE.EA.EA. + ...AE.AE.EA.EA.. + ................ +} +# tile 83 (displacer beast,female) +{ + ................ + ........E....... + .......E.E..AA.. + DEEEA..A.E....A. + ....EA.E.D....A. + .A...A.E......A. + .EA.AEAAA.....A. + .AAAAAAAAAA..A.. + .AAAAEAAAAAAAA.. + .HAHAEAAAAAAAAA. + .AAAAEAAAAAAAAA. + .AAA.AAAAAAAAAA. + .....AE.AEEA.EA. + ....AE.AE.EA.EA. + ...AE.AE.EA.EA.. + ................ +} +# tile 84 (gremlin,male) +{ + ................ + ................ + ................ + GGGA....AGGG.... + .GGGFAAAGGG..... + ..FFFFFFFF...... + ...NDFFDNA...... + ...GNFFNGA...... + ...GFFFFGA..AA.. + ...AGFFFAFAAAAA. + ..GFAGFAFFFAAAA. + .GFGFAAFFAFAAAA. + .GF.GFAGAAFAAAA. + ....FFAGFAA.AA.. + ...GFA.FGA...... + ................ +} +# tile 85 (gremlin,female) { ................ ................ @@ -825,7 +1686,26 @@ Z = (195, 195, 195) ...GFA.FGA...... ................ } -# tile 42 (gargoyle) +# tile 86 (gargoyle,male) +{ + ................ + ................ + ...PAPPPPAP..... + ..PA......AP.... + ..P.DD..DDAP.... + ....PD..DPA..... + ....P....PA..AA. + ....AP...A.AAAAA + ...P.AP.A...AAAA + ..P.P.AA..A.AAAA + ..PA.P.APAA.AAAA + ..PA.P....A.AA.. + .....P....AAAA.. + .....P.AP.AA.... + ....PFA.FPA..... + ................ +} +# tile 87 (gargoyle,female) { ................ ................ @@ -844,7 +1724,7 @@ Z = (195, 195, 195) ....PFA.FPA..... ................ } -# tile 43 (winged gargoyle) +# tile 88 (winged gargoyle,male) { ...K......K..... ...KJ....KJ..... @@ -863,18 +1743,37 @@ Z = (195, 195, 195) ....PFA.FPA..... ................ } -# tile 44 (hobbit) +# tile 89 (winged gargoyle,female) { - ................ - ................ - ................ - ................ - ......JJA....... - .....JJJJA...... - ....JLFLFJ...... - ....JLLLLJ...... - ....JKLLKJJ.AA.. - ...CLLLLLLCAAA.. + ...K......K..... + ...KJ....KJ..... + ..KJAPPPPAJJ.... + ..KJ......AJ.... + ..KJDD..DDAJ.... + .KJAPD..DPAJJ... + .KJAP....PAAJAA. + KJA.AP...A.AJJAA + J..P.AP.A...AJAA + ..P.P.AA..A.AAAA + ..PA.P.APAA.AAAA + ..PA.P....A.AA.. + .....P....AAAA.. + .....P.AP.AA.... + ....PFA.FPA..... + ................ +} +# tile 90 (hobbit,male) +{ + ................ + ................ + ................ + ................ + ......JJA....... + .....JJJJA...... + ....JLFLFJ...... + ....JLLLLJ...... + ....JKLLKJJ.AA.. + ...CLLLLLLCAAA.. ..CLALLLLALCA... ..LLAJJKJALLA... ...L.LKJLALAA... @@ -882,7 +1781,55 @@ Z = (195, 195, 195) ....LLL.LLL..... ................ } -# tile 45 (dwarf) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female hobbits wear slightly different clothing. +# +# tile 91 (hobbit,female) +{ + ................ + ................ + ................ + ................ + ......JJA....... + .....JJJJA...... + ....JLFLFJ...... + ....JLLLLJ...... + ....JKLLKJJ.AA.. + ...CLLLLLLCAAA.. + ..CLALJKJALCA... + ..LLAJJKJALLA... + ...L.LKJLALAA... + .....LLALLA.A... + ....LLL.LLL..... + ................ +} +# Note from contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Male and female dwarfs are not differentiated in any way whatsoever. +# According to Terry Pratchett (in Unseen Academicals, if I remember +# correctly) it is almost impossible to tell what gender a dwarf is, +# even for fellow dwarfs. I strongly believe that NetHack should follow +# this tradition. +# +# tile 92 (dwarf,male) +{ + ................ + ................ + ................ + ................ + ......B......... + .....BEE........ + ....BBEEE....... + ....BLLLE....... + .....OLO...AAA.. + ...BBOOOEEAAAA.. + ...BABOEAEAAAA.. + ....LBBELAAAA... + ....EBAEEAA..... + ....BEAEB.A..... + ................ + ................ +} +# tile 93 (dwarf,female) { ................ ................ @@ -901,7 +1848,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 46 (bugbear) +# tile 94 (bugbear,male) +{ + ................ + ................ + ......K......... + .K..KKK......... + .KKKKKK......... + KADKADKKK....... + KKKKKKKJKK...... + KAPAPAKJJKJ..... + KAAAAAKKJKJJ.... + .KKKKKJKAKKJ.... + ..KAJJCAKKKJ.AA. + ..KK.KKKKKJJAA.. + ...C..KJAKJAA... + .....CCAAKJA.... + ........CCA..... + ................ +} +# tile 95 (bugbear,female) { ................ ................ @@ -920,7 +1886,26 @@ Z = (195, 195, 195) ........CCA..... ................ } -# tile 47 (dwarf lord) +# tile 96 (dwarf leader,male) +{ + ................ + ................ + ................ + ................ + ......B......... + .....BEE........ + ....HHHHH....... + ....BLLLE....... + ....BOLOE..AAA.. + ...BBOOOEEAAAA.. + ...BABOEAEAAAA.. + ....LBBELAAAA... + ....EBAEEAA..... + ....BEAEB.A..... + ................ + ................ +} +# tile 97 (dwarf leader,female) { ................ ................ @@ -939,7 +1924,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 48 (dwarf king) +# tile 98 (dwarf ruler,male) +{ + ................ + ................ + ................ + ................ + ....H.C.H....... + ....HCHCH....... + ....HHHHH....... + ....BLLLE...A... + .....OLO...AAAA. + ...EBOOOEEAAAA.. + ...BABOEAEAAAA.. + ....LBBELAAAA... + ....EBAEEAA..... + ....BEAEB.A..... + ................ + ................ +} +# tile 99 (dwarf ruler,female) { ................ ................ @@ -958,7 +1962,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 49 (mind flayer) +# tile 100 (mind flayer,male) +{ + ................ + .......IIIIC.... + .....IIIIIIC.... + ....IIIIIIIC.... + ...IGIIIIGC..... + ...IIGINGIC..... + ....IIIIIC...... + ....IAIAIF...... + ....IAIAIF...... + ....IAIAIFI..... + .....FIFIFIC.AA. + ....CBIBBF.CAAA. + ...IIIBBFFACAAA. + ......BBFCAAAA.. + ......CFFCAA.... + ....IIC.IIA..... +} +# tile 101 (mind flayer,female) { ................ .......IIIIC.... @@ -977,7 +2000,26 @@ Z = (195, 195, 195) ......CFFCAA.... ....IIC.IIA..... } -# tile 50 (master mind flayer) +# tile 102 (master mind flayer,male) +{ + ................ + .......IIIIC.... + .....IIIIIIC.... + ....IIIIIIIC.... + ...IGIIIIGC..... + ...IIGINGIC..... + .EEEIIIIICEEEE.. + ..EEIAIAIEEEE... + ...EIAIAIEEE.... + ....IAIAIEEE.... + ....EFIFIEEE.AA. + ....CBIBBEEEAAA. + ...IIIBBEEEEAAA. + ....EEBEEEEAAA.. + ...EEECEEEAA.... + ....IIC.IIA..... +} +# tile 103 (master mind flayer,female) { ................ .......IIIIC.... @@ -996,7 +2038,26 @@ Z = (195, 195, 195) ...EEECEEEAA.... ....IIC.IIA..... } -# tile 51 (manes) +# tile 104 (manes,male) +{ + ................ + ................ + ....PP.......... + ...PPPP......... + ..PAPAP......... + ..PPPPP.PPP.P... + ..P..PPPP....... + ..P..PPPPP...P.. + ..PPPPP.PPP..... + ..P.P.P.PP.P.... + .P...P.PPPP..... + .P....PPP.PP.... + ..P....P.P.P.P.. + ........P....... + ................ + ................ +} +# tile 105 (manes,female) { ................ ................ @@ -1015,7 +2076,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 52 (homunculus) +# tile 106 (homunculus,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ......JJJ....... + ......LLC....... + ......LLC....... + .....BBPPPAA.... + ....L.BPPACAA... + ......BAPAAAA... + .....LLALCA..... + ................ + ................ +} +# tile 107 (homunculus,female) { ................ ................ @@ -1034,7 +2114,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 53 (imp) +# tile 108 (imp,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + .....O.D.O...... + .....OCDDO...... + ......CDD....... + .....GGFFFAA.... + ....C.GFFADAA... + ......GAFAAAA... + .....CDADDA..... + ................ + ................ +} +# tile 109 (imp,female) { ................ ................ @@ -1053,7 +2152,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 54 (lemure) +# tile 110 (lemure,male) +{ + ................ + ................ + ....PP.......... + ...PPPP......... + ..PAPAP....P.... + ..PPPPP..PP.P... + ..P..PPPPPPPP... + ..P..PPPPPPP.... + ..PPPPPPPPP..... + ....PPPPPPPP.... + ..PPPPPPPPPP.... + ...PPPPPPPPPP... + ..P.P..PPPP.PP.. + ........P.PP.... + ................ + ................ +} +# tile 111 (lemure,female) { ................ ................ @@ -1072,7 +2190,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 55 (quasit) +# tile 112 (quasit,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + .....O.D.O...... + .....OCDDOD..... + ......CDD.D..... + .....GGFFFAA.... + ....C.GFFAAADA.. + ....C.GFFJJDA... + ......GAFAAAA... + .....CDADDA..... + ................ + ................ +} +# tile 113 (quasit,female) { ................ ................ @@ -1091,7 +2228,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 56 (tengu) +# tile 114 (tengu,male) { ................ .......PP....... @@ -1110,26 +2247,83 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 57 (blue jelly) +# tile 115 (tengu,female) { ................ - ................ - ................ - .......E........ - ......OBE....... - ...BE.OBEBOE.... - ..OBEOBBEOBBE... - ..OBEOBBEOBBE... - ..BBBGGBGGBEEE.. - ..BBBAGBAGEEEEA. - ..BBBBBBEBEEEEAA - ...BBBBBBBEEEAAA - ....BBBBBEEEAAA. - ......BBBEEAA... + .......PP....... + ......PPPP...... + .....DPPNP...... + ....DDDPPP...... + ....DDPPPP...... + ....D..PPA...... + .....PIAAIP.AAA. + ....PPPIIPPPAAA. + ....PAPPPPAPAAA. + ....PAHHHHAPAAA. + ....LAPPPPALAAA. + ......PPPPAAAA.. + ......PPPPAA.A.. + .....LLA.LLA.... + ................ +} +# tile 116 (blue jelly,male) +{ + ................ + ................ + ................ + .......E........ + ......OBE....... + ...BE.OBEBOE.... + ..OBEOBBEOBBE... + ..OBEOBBEOBBE... + ..BBBGGBGGBEEE.. + ..BBBAGBAGEEEEA. + ..BBBBBBEBEEEEAA + ...BBBBBBBEEEAAA + ....BBBBBEEEAAA. + ......BBBEEAA... + ................ + ................ +} +# tile 117 (blue jelly,female) +{ + ................ + ................ + ................ + .......E........ + ......OBE....... + ...BE.OBEBOE.... + ..OBEOBBEOBBE... + ..OBEOBBEOBBE... + ..BBBGGBGGBEEE.. + ..BBBAGBAGEEEEA. + ..BBBBBBEBEEEEAA + ...BBBBBBBEEEAAA + ....BBBBBEEEAAA. + ......BBBEEAA... + ................ + ................ +} +# tile 118 (spotted jelly,male) +{ + ................ + ................ + ................ + .......E........ + ......OBE....... + ...BE.OCEBOE.... + ..OCEOCCEOBCE... + ..OCEOBCEOCBD... + ..BBBHHBHHBEDD.. + ..CCBAHBAHEEEEA. + ..BBCBBBEBEEDEAA + ...BBBCBBBEEDAAA + ....BCCCBEEDAAA. + ......CCBEEAA... ................ ................ } -# tile 58 (spotted jelly) +# tile 119 (spotted jelly,female) { ................ ................ @@ -1148,7 +2342,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 59 (ochre jelly) +# tile 120 (ochre jelly,male) +{ + ................ + ................ + ................ + .......D........ + ......LCD....... + ...CD.LCDCLD.... + ..LCDLCCDLCCD... + ..LCDLCCDLCCD... + ..CCCGGCGGCDDD.. + ..CCCAGCAGDDDDA. + ..CCCCCCDCDDDDAA + ...CCCCCCCDDDAAA + ....CCCCCDDDAAA. + ......CCCDDAA... + ................ + ................ +} +# tile 121 (ochre jelly,female) { ................ ................ @@ -1167,7 +2380,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 60 (kobold) +# tile 122 (kobold,male) +{ + ................ + ................ + ................ + ................ + ...N...N........ + ...NBPBN........ + ...BABAB........ + ....BBPA..A..... + ...BBABPA.AA.A.. + ..BPBBBBPAAAAA.. + ..BAPBPAPAAAAA.. + ....PBPAAAAAA... + ....BABAAAA..... + ...BBABBA....... + ................ + ................ +} +# tile 123 (kobold,female) { ................ ................ @@ -1186,7 +2418,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 61 (large kobold) +# tile 124 (large kobold,male) +{ + ................ + ................ + ................ + ...N...N........ + ...NBPBN........ + ...BABAB........ + ....BBPA..A..... + ...BBABPA.AA.... + ..BPBBBBPAAA.A.. + ..BAPBPAPAAAAA.. + ..BAPBPAPAAAAA.. + ....PBPAAAAAA... + ....BABAAAA..... + ...BBABBA....... + ................ + ................ +} +# tile 125 (large kobold,female) { ................ ................ @@ -1205,7 +2456,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 62 (kobold lord) +# tile 126 (kobold leader,male) +{ + ................ + ................ + ................ + ...N...N........ + ...NCCCN........ + ...CABAC........ + ...CBBPC..A..... + ..CCBABCC.AA.... + ..CCBBBCCAAA.A.. + ..BCCBCCPAAAAA.. + ..BACBCAPAAAAA.. + ....BBBAAAAAA... + ....BABAAAA..... + ...BBABBA....... + ................ + ................ +} +# tile 127 (kobold leader,female) { ................ ................ @@ -1224,7 +2494,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 63 (kobold shaman) +# tile 128 (kobold shaman,male) +{ + ................ + ................ + ................ + ...N...N........ + ...NHHHN........ + ...HABAH........ + ...HBBPH..A..... + ..HHBABHH.AA.... + .HHHBBBHHHAA.A.. + .HBHHBHHPHAAAA.. + ..BAHBHAPAAAAA.. + ....BBBAAAAAA... + ....BABAAAA..... + ...BBABBA....... + ................ + ................ +} +# tile 129 (kobold shaman,female) { ................ ................ @@ -1243,7 +2532,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 64 (leprechaun) +# tile 130 (leprechaun,male) { ................ ................ @@ -1262,7 +2551,49 @@ Z = (195, 195, 195) ................ ................ } -# tile 65 (small mimic) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female leprechauns are clean-shaven. Although of course not one +# hundred percent accurate, it's convenient visual shorthand. +# +# tile 131 (leprechaun,female) +{ + ................ + ................ + ................ + ................ + ......G......... + ......F....K.... + .....GFF..KLK... + ....GFFFF..K.... + .....KLKA.GLAA.. + ...FGFLFFFAKA.A. + ...GAGFFAAAK.AA. + ....LKHKKJAKAA.. + ....GFAGKJAKA... + ...GFAA.GFAK.... + ................ + ................ +} +# tile 132 (small mimic,male) +{ + ................ + ................ + ................ + ................ + ......POP....... + ......NNO....... + ......NNO....... + .......OA....... + .....NNNNN..AA.. + ....OONNNOO.AA.. + ....NANOOANAAA.. + ......NAOAAAA... + ......NAOAA.A... + .....NN.OOA..... + ................ + ................ +} +# tile 133 (small mimic,female) { ................ ................ @@ -1281,7 +2612,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 66 (large mimic) +# tile 134 (large mimic,male) { ................ ................ @@ -1300,7 +2631,45 @@ Z = (195, 195, 195) ................ ................ } -# tile 67 (giant mimic) +# tile 135 (large mimic,female) +{ + ................ + ................ + ................ + ......LLOA...... + ......NNOA...... + ......NNOA...... + ......ONOA...... + .....NNNNO..AAA. + ....OONNNOO.AAA. + ...NOANNNAOOAAA. + ...NAONONOANAAA. + .....NO.NOAAAA.. + .....NO.NOAA.A.. + ....NNO.NOOA.... + ................ + ................ +} +# tile 136 (giant mimic,male) +{ + ................ + ......NNO....... + .....NNNNOA..... + .....NNNNOA..... + .....NNNNOA..... + .....ONNNOA..... + ..PONNOOONOOPAAA + .PONONNNNOONOPAA + .ONOANNNNOAONOAA + .NNOANNNNOAOOOAA + ...AANNONNAAAAAA + ....PNO.NNPAAAAA + ....ONO.NNOAA..A + ....NNO.NNOAA..A + ...NNNO.NNOOA... + ................ +} +# tile 137 (giant mimic,female) { ................ ......NNO....... @@ -1319,7 +2688,26 @@ Z = (195, 195, 195) ...NNNO.NNOOA... ................ } -# tile 68 (wood nymph) +# tile 138 (wood nymph,male) +{ + ................ + ................ + ...OH........... + ..OHHL.......... + ..OHLL.......... + ..HHLA.......... + .OHLLFKKKKLA.... + .HKFLFKKKKA..... + OHKJFKKJJK.A.... + HKKLJJGKAAAAAAA. + .JJAJGDKJAAAAA.. + ..JA.KKJJAAAA... + ...J.KKKKJAA.... + ....JKKKKKJA.... + ....KJKJKJKJ.... + ................ +} +# tile 139 (wood nymph,female) { ................ ................ @@ -1338,7 +2726,7 @@ Z = (195, 195, 195) ....KJKJKJKJ.... ................ } -# tile 69 (water nymph) +# tile 140 (water nymph,male) { ................ ................ @@ -1357,7 +2745,7 @@ Z = (195, 195, 195) ....BPBPBPBP.... ................ } -# tile 70 (mountain nymph) +# tile 141 (water nymph,female) { ................ ................ @@ -1365,18 +2753,75 @@ Z = (195, 195, 195) ..OHHL.......... ..OHLL.......... ..HHLA.......... - .OHLLCOOOOLA.... - .HOCLCOOOOA..... - OHOLCOOLLO.A.... - HOOKLLIOAAAAAAA. - .LLALIBOKAAAAA.. - ..LA.OOLLAAAA... - ...L.OOOOLAA.... - ....LOOOOOLA.... - ....OLOLOLOL.... - ................ + .OHLLJBBBBLA.... + .HBJLJBBBBA..... + OHBPJBBPPB.A.... + HBBLPPNBAAAAAAA. + .PPAPNDB.AAAAA.. + ..PA.BBPPAAAA... + ...P.BBBBPAA.... + ....PBBBBBPA.... + ....BPBPBPBP.... + ................ +} +# tile 142 (mountain nymph,male) +{ + ................ + ................ + ...OH........... + ..OHHL.......... + ..OHLL.......... + ..HHLA.......... + .OHLLCOOOOLA.... + .HOCLCOOOOA..... + OHOLCOOLLO.A.... + HOOKLLIOAAAAAAA. + .LLALIBOKAAAAA.. + ..LA.OOLLAAAA... + ...L.OOOOLAA.... + ....LOOOOOLA.... + ....OLOLOLOL.... + ................ +} +# tile 143 (mountain nymph,female) +{ + ................ + ................ + ...OH........... + ..OHHL.......... + ..OHLL.......... + ..HHLA.......... + .OHLLCOOOOLA.... + .HOCLCOOOOA..... + OHOLCOOLLO.A.... + HOOKLLIOAAAAAAA. + .LLALIBOKAAAAA.. + ..LA.OOLLAAAA... + ...L.OOOOLAA.... + ....LOOOOOLA.... + ....OLOLOLOL.... + ................ +} +# tile 144 (goblin,male) +{ + ................ + ................ + ................ + ....LK.......... + ...CJA.......... + ..KJA........... + .JJA.IIK...AA... + .IK.IGIGIJAA.... + J.ICKIIIJK...... + ...IIJJJK.A..... + ....KICJAAAAA... + ....ICKKJA...... + ....IKAIJA...... + ...IKAA.IK...... + ................ + ................ } -# tile 71 (goblin) +# tile 145 (goblin,female) { ................ ................ @@ -1395,7 +2840,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 72 (hobgoblin) +# tile 146 (hobgoblin,male) +{ + ................ + .....LK......... + ....CKA......... + ...CJA.......... + ..KJA........... + .JJA.IIK...AA... + .IK.IHIHIJAA.... + J.ICKIIIJK...... + ...IIJJJK.A..... + ....KICCAAAAA... + ....IIIIJA...... + ....ICKKJA...... + ....IKAIJA...... + ...IKAA.IK...... + ................ + ................ +} +# tile 147 (hobgoblin,female) { ................ .....LK......... @@ -1414,7 +2878,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 73 (orc) +# tile 148 (orc,male) +{ + ................ + ................ + ................ + .....OA......... + ....NOPA........ + ....LPLA........ + .....P.A........ + ..KCCAKKKA.AA... + ..BPCKJ.P.AAA... + ..BAGGFAAPNO.... + ..BAJJPNOAAA.... + ....BNOJAAAAAA.. + ...BJACPAAAA.... + ..BPPABPPA...... + ................ + ................ +} +# tile 149 (orc,female) { ................ ................ @@ -1433,7 +2916,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 74 (hill orc) +# tile 150 (hill orc,male) +{ + ................ + ................ + ................ + .....OA......... + ....NOPA........ + ....LKLA........ + .....K.A........ + ..KGGAFFKA.AA... + ..JKGFF.K.AAA... + ..JAHHFAAKNO.... + ..JAGFFNOAAA.... + ....GNNFAAAAAA.. + ...GGAGFAAAA.... + ..KJJAKJJA...... + ................ + ................ +} +# tile 151 (hill orc,female) { ................ ................ @@ -1452,7 +2954,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 75 (Mordor orc) +# tile 152 (Mordor orc,male) +{ + ................ + ................ + ................ + .....OA......... + ....NOPA........ + ....LPLA........ + .....P.A........ + ..KIIAIIKA.AA... + ..BPIDD.P.AAA... + ..BAGGFAAP.O.... + ..BAIDDNOAAA.... + ....BNOJAAAAAA.. + ...BIAIPAAAA.... + ..BPPABPPA...... + ................ + ................ +} +# tile 153 (Mordor orc,female) { ................ ................ @@ -1471,7 +2992,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 76 (Uruk-hai) +# tile 154 (Uruk-hai,male) +{ + ................ + ................ + .....OA......... + ....NOPA........ + ....LPLA........ + .....P.A........ + ..IIIAIIIA...... + ..BPIKI.BAAAA... + ..BIG.PPPPAAA... + .NBAD.PDDPAA.... + ..BNNJPDDPAA.... + ....INPPPPAAAA.. + ...BIAK.AAAA.... + ..BPPABPPA...... + ................ + ................ +} +# tile 155 (Uruk-hai,female) { ................ ................ @@ -1490,7 +3030,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 77 (orc shaman) +# tile 156 (orc shaman,male) { ................ ................ @@ -1509,7 +3049,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 78 (orc-captain) +# tile 157 (orc shaman,female) +{ + ................ + ................ + .....OA......... + ....NOPA........ + ....LPLA........ + .....P.A........ + ..CCCACCCA...... + ..BPCKC.BAAAA... + ..BCGGFJBAAAA... + ..BAJJCJBAAA.... + ..BAJJCJBAAA.... + ....CACJAAAAAA.. + ...BCACPAAAA.... + ..BPPABPPA...... + ................ + ................ +} +# tile 158 (orc-captain,male) { ................ ................ @@ -1528,7 +3087,45 @@ Z = (195, 195, 195) ................ ................ } -# tile 79 (rock piercer) +# tile 159 (orc-captain,female) +{ + ................ + ................ + .....OA......... + ...NNOOPA....... + ....LPLA........ + ...IPPPA........ + ..DIIPADDA.AA... + ..BPIAD.P.AAA... + ..BAGGFAAP.O.... + ..BAGGFAAP.O.... + ..BAJJPNOAAA.... + ....BNOJAAAAAA.. + ...BDAIPAAAA.... + ..BPPABPPA...... + ................ + ................ +} +# tile 160 (rock piercer,male) +{ + .JKKKKKKKKJAAA.. + ..JJGKGKJJAAAA.. + ...JKKKJJAAAA... + ...JJKKJJAAAA... + ....JKKJAAAA.... + ....JJKJ.AAA.... + ....JJKJ.AAA.... + ....JJJJ..A..... + .....JJ...A..... + .....JJ...A..... + .....JJ......... + .....JJ......... + .....J.......... + .....J.......... + ................ + ................ +} +# tile 161 (rock piercer,female) { .JKKKKKKKKJAAA.. ..JJGKGKJJAAAA.. @@ -1547,7 +3144,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 80 (iron piercer) +# tile 162 (iron piercer,male) +{ + .BPPPPPPPP.AAA.. + ..BBDPDP..AAAA.. + ...BPPP..AAAA... + ...PBPP..AAAA... + ....BPP.AAAA.... + ....BBP.AAAA.... + ....PBP.AAAA.... + ....PBP...A..... + .....BP...A..... + .....BP...A..... + .....BP......... + .....BP......... + .....B.......... + .....P.......... + ................ + ................ +} +# tile 163 (iron piercer,female) { .BPPPPPPPP.AAA.. ..BBDPDP..AAAA.. @@ -1566,7 +3182,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 81 (glass piercer) +# tile 164 (glass piercer,male) +{ + .NBBBBBBBBPAAA.. + ..NNDBDBPPAAAA.. + ...NBBBPPAAAA... + ...PNBBPPAAAA... + ....NBBPAAAA.... + ....NNBPAAAA.... + ....PNBPAAAA.... + ....PNBP..A..... + .....NB...A..... + .....NB...A..... + .....NB......... + .....NB......... + .....N.......... + .....P.......... + ................ + ................ +} +# tile 165 (glass piercer,female) { .NBBBBBBBBPAAA.. ..NNDBDBPPAAAA.. @@ -1585,7 +3220,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 82 (rothe) +# tile 166 (rothe,male) +{ + ................ + ...........K.... + ............K... + ............K... + .......JJJKKJ... + .....JKKKKKKK... + ..AAAKKKKKKKK... + .AAAAAKKKKKKKA.. + AAKKAAKKKKKAKA.. + .KEKKAKKKJAAKA.. + .KKKJAKKAJAAK... + ..KJAAAKAAA..... + ..AAKA.KA....... + ..A..A.K........ + ................ + ................ +} +# tile 167 (rothe,female) { ................ ...........K.... @@ -1604,7 +3258,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 83 (mumak) +# tile 168 (mumak,male) { ................ ...........P.... @@ -1623,7 +3277,45 @@ Z = (195, 195, 195) PPPA............ .AA............. } -# tile 84 (leocrotta) +# tile 169 (mumak,female) +{ + ................ + ...........P.... + .PP.........P... + PPP...PPPPP.P... + PPPPPPPPP.PP.... + PPPPBPPBBP.PP... + PPPBPPPPPP.PP... + .PDPPDDPP.PPP... + ..BPPDDP.PPPPA.. + ..PPPPPPPPPPPA.. + ..PPPPO..PAPPA.. + .OOPPOOAPPAPPA.. + OOPPOOAAPPA..... + .PPPAPA.PP...... + PPPA............ + .AA............. +} +# tile 170 (leocrotta,male) +{ + ................ + ..A..A.......... + ..AOOA....J..... + ..AOOAA....J.... + .APOAFA....J.... + .APOAAA.JJJJ.... + .AOPAAJKKKKKJ... + .AOAAKJJKKJKJA.. + ...JKKKKKJAKKA.. + ...JKJKKJAAKKA.. + ..JKJAKKAAPAPA.. + ..KKAAKKAAPAPA.. + .PAPAAPAPA...... + .PAPA.PAPA...... + ................ + ................ +} +# tile 171 (leocrotta,female) { ................ ..A..A.......... @@ -1642,7 +3334,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 85 (wumpus) +# tile 172 (wumpus,male) { ................ ............B... @@ -1661,7 +3353,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 86 (titanothere) +# tile 173 (wumpus,female) +{ + ................ + ............B... + .............B.. + .......BBBBB.B.. + ....BBBPPBBBB... + ...BOOBBBPBBBB.. + ...OOBBBBBPBBB.. + ..DABBAABBPBBBA. + .BOOBBDABEBBEBAA + .BOBBBBBBEBEBBAA + .BBBBBBBEBBABBAA + .EBBBBBEABBABBAA + ..EEEEEAABBA.... + .....BBA.BB..... + ................ + ................ +} +# tile 174 (titanothere,male) { ................ ................ @@ -1680,7 +3391,45 @@ Z = (195, 195, 195) ................ ................ } -# tile 87 (baluchitherium) +# tile 175 (titanothere,female) +{ + ................ + ................ + ................ + ..........PPP.P. + .......PPPPPPPAP + .....PPPPPPPPP.A + ..P.P.PPPPPPPP.A + ..PPP.PPPPPPPPPA + ..PPPP.PPPPPPPPA + .PPPPP.PPPPPPP.. + .PPEPP.PPPP.PPA. + PBPPP.PPP.AAPPA. + PPPP.AAPPAA..... + .PP.PPAPPA...... + ................ + ................ +} +# tile 176 (baluchitherium,male) +{ + ................ + ................ + ................ + ..........PPP.P. + .......PPPPPPPAP + .....PPPPPPPPP.A + ..P.P.PPPPPPPP.A + ..PPP.PPPPPPPPPA + ..PPPP.PPPPPPPPA + BPPPPP.PPPPPPP.. + B.PEPP.PPPP.PPA. + PB.PP.PPP.AAPPA. + PPPP.AAPPAA..... + .PP.PPAPPA...... + ................ + ................ +} +# tile 177 (baluchitherium,female) { ................ ................ @@ -1699,7 +3448,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 88 (mastodon) +# tile 178 (mastodon,male) +{ + ................ + ................ + ................ + ................ + ................ + ..O...O......... + .N..POP.P....... + N..PNPPPPP...... + O.PNPPPPPP.PP... + O.POPEPPP.PPPPP. + .OPOPOP..PPPPPAP + ..PPOPP.PPPPPPAA + ..PPAAAPPPPAPPA. + ..P...APPAAAPPA. + .......PPA...... + ................ +} +# tile 179 (mastodon,female) { ................ ................ @@ -1718,7 +3486,26 @@ Z = (195, 195, 195) .......PPA...... ................ } -# tile 89 (sewer rat) +# tile 180 (sewer rat,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ..K..K.JKKKK.... + ..KKKKJKKJKKK... + ..JAKAKJJJKKKJ.. + ..GKGKJKAKKAKKA. + .KKJJJJKAKAAKKA. + .PJJAAKKAJAJKA.. + ..AA.KKA..JKA... + .........JJA.... + ................ +} +# tile 181 (sewer rat,female) { ................ ................ @@ -1737,7 +3524,26 @@ Z = (195, 195, 195) .........JJA.... ................ } -# tile 90 (giant rat) +# tile 182 (giant rat,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ..K..K.JKKKKK... + ..KKKKJKKKJKKK.. + ..JAKAKJKJJKKKJ. + ..GAGAKJKJJKKKK. + ..AKAKJKKAKKAKKA + .KKJJJJKAJKAAKKA + .PJJAAKKAJJAJKA. + ..AA.KKAA..JKA.. + ..........JJA... + ................ +} +# tile 183 (giant rat,female) { ................ ................ @@ -1756,7 +3562,26 @@ Z = (195, 195, 195) ..........JJA... ................ } -# tile 91 (rabid rat) +# tile 184 (rabid rat,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ..K..K.JKKKKK... + ..KKKKJKKKJKKK.. + ..JAKAKJKJJKKKJ. + ..GAGAKJKJJKKKK. + ..AKAKJKKAKKAKKA + .KKJOOOKAJKAAKKA + .PJOOAKKAJJAJKA. + ..AOOOKAA..JKA.. + .OOOOOOOO.JJA... + ................ +} +# tile 185 (rabid rat,female) { ................ ................ @@ -1775,7 +3600,26 @@ Z = (195, 195, 195) .OOOOOOOO.JJA... ................ } -# tile 92 (wererat) +# tile 186 (wererat,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ..K..K.JKKKKK... + ..KKKKJKKKJKKK.. + ..LLLLKJKJJKKKJ. + ..FLFLLJKJJKKKK. + ..LLLLJKKAKKAKKA + .KKJJJJKAJKAAKKA + .PJJAAKKAJJAJKA. + ..AA.KKAA..JKA.. + ..........JJA... + ................ +} +# tile 187 (wererat,female) { ................ ................ @@ -1794,7 +3638,26 @@ Z = (195, 195, 195) ..........JJA... ................ } -# tile 93 (rock mole) +# tile 188 (rock mole,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + .......AAAAA.... + ...AAAAAAAAAA... + ..AAAAAAAAAAAA.. + ..JAJAAAAAAAAAA. + .AAAAAAAAAAAAAA. + AN.NAAAAAAAAAAA. + A...AAAA...AAA.. + AN.NAA.AA...AA.. + .AAAA........... +} +# tile 189 (rock mole,female) { ................ ................ @@ -1813,7 +3676,26 @@ Z = (195, 195, 195) AN.NAA.AA...AA.. .AAAA........... } -# tile 94 (woodchuck) +# tile 190 (woodchuck,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + .......KJA...... + ......NKKNA..... + ......KNOJA..... + ......KNOJA..... + .....KKKKKJA.... + ....JJKLLJJJAA.. + ......KLLJAAAAA. + ......KJJJAAAA.. + .....JJAAJJAA... + ................ +} +# tile 191 (woodchuck,female) { ................ ................ @@ -1832,7 +3714,26 @@ Z = (195, 195, 195) .....JJAAJJAA... ................ } -# tile 95 (cave spider) +# tile 192 (cave spider,male) +{ + ................ + ................ + ................ + ................ + ................ + ........PA...... + .......PA....... + ......PAPBBA.... + ...PA.APBPPPA... + ...ABBPPAPPAA.PA + ...GPPPPAAAPPPAA + ...PPGPAAPPAAAA. + ..D.PAPAPAAPPA.. + ....D.PAAPA.APA. + .....PAA.APA.... + ................ +} +# tile 193 (cave spider,female) { ................ ................ @@ -1851,7 +3752,26 @@ Z = (195, 195, 195) .....PAA.APA.... ................ } -# tile 96 (centipede) +# tile 194 (centipede,male) +{ + ................ + ................ + ......PBPP...... + ....BBPAAA...... + ..PPBAAA........ + .PAPBBBPPPP..... + ..PAAPPBBBA..... + ....PAAPAPBPP... + ......AABBPP.... + ......BB.PPAP... + ....PBBPPAP.A... + ...GPPPAP.AP.... + ...PPGPAAP...... + ..B.PAA......... + ...B............ + ................ +} +# tile 195 (centipede,female) { ................ ................ @@ -1870,7 +3790,26 @@ Z = (195, 195, 195) ...B............ ................ } -# tile 97 (giant spider) +# tile 196 (giant spider,male) +{ + ................ + ................ + ................ + ................ + ................ + ........JA...... + .......JA....... + ......JAJKKA.... + ...JA.AJKJJJA... + ...AKKJJAJJAA.JA + ...GJJJJAAAJJJAA + ...JJGJAAJJAAAA. + ..D.JAJAJAAJJA.. + ....D.JAAJA.AJA. + .....JAA.AJA.... + ................ +} +# tile 197 (giant spider,female) { ................ ................ @@ -1889,7 +3828,26 @@ Z = (195, 195, 195) .....JAA.AJA.... ................ } -# tile 98 (scorpion) +# tile 198 (scorpion,male) +{ + ................ + ................ + .......JKJKJAA.. + ......JA.JKJKKA. + .......KA...JJJA + ......JA....KKJA + ...........JJJKA + .......AJKKAJJA. + .....AAJKJJJAA.. + ...AKKJJAJJAA... + ...GJJJJAAAJJJA. + ...JJGJAAJJAAAJ. + ..D.JAJAJAAJJA.. + ....D.JAAJA.JAA. + .......JAAJA.... + ................ +} +# tile 199 (scorpion,female) { ................ ................ @@ -1908,7 +3866,26 @@ Z = (195, 195, 195) .......JAAJA.... ................ } -# tile 99 (lurker above) +# tile 200 (lurker above,male) +{ + .AAAAAAAAAAAAAAA + ...AAGFAAGFAAA.. + ...AAAAAAAAAAA.. + ....AODODODOA... + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ +} +# tile 201 (lurker above,female) { .AAAAAAAAAAAAAAA ...AAGFAAGFAAA.. @@ -1927,7 +3904,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 100 (trapper) +# tile 202 (trapper,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ....AODODODOA... + ...AAAAAAAAAAA.. + ...AAGFAAGFAAA.. + .AAAAAAAAAAAAAAA +} +# tile 203 (trapper,female) { ................ ................ @@ -1946,7 +3942,26 @@ Z = (195, 195, 195) ...AAGFAAGFAAA.. .AAAAAAAAAAAAAAA } -# tile 101 (pony) +# tile 204 (pony,male) +{ + ................ + ................ + .....JJ......... + ....KKKJ........ + ...KKEKJ........ + ..KKJKKJ........ + ..JJAKKJAA...... + ...AKKKJA....... + ...KKKKKKKJ..... + ...KKKKKKKJJAAA. + ...KJKJJJJJAJA.. + ...JAJAAAAJAA... + ...JAJAAJAJA.... + ...L.JAALAJ..... + .....LA...L..... + ................ +} +# tile 205 (pony,female) { ................ ................ @@ -1965,7 +3980,26 @@ Z = (195, 195, 195) .....LA...L..... ................ } -# tile 102 (white unicorn) +# tile 206 (white unicorn,male) +{ + ................ + ..HP............ + ..PHO.NN........ + ...PHNNB........ + ...ONENB........ + ..ONNNNB........ + ..NOANNBAA...... + ...AONNBA....... + ...ONNNONNN..... + ..NONNNNONNOAAA. + ..N.ONONNONAOA.. + ..OAANAAAAOAA... + ...LAOAAOAOA.... + .....OAALAO..... + .....LA...L..... + ................ +} +# tile 207 (white unicorn,female) { ................ ..HP............ @@ -1984,7 +4018,26 @@ Z = (195, 195, 195) .....LA...L..... ................ } -# tile 103 (gray unicorn) +# tile 208 (gray unicorn,male) +{ + ................ + ..HP............ + ..PHO.PP........ + ...PHPPN........ + ....PGPN........ + ...PPPPN........ + ..PPAPPNAA...... + ...APPPNA....... + ....PPP.PPP..... + ..P.PPPP.PP.AAA. + ..P..P.PP.PA.A.. + ..PAAPAAAA.AA... + ...LA.AA.A.A.... + ......AALA...... + .....LA...L..... + ................ +} +# tile 209 (gray unicorn,female) { ................ ..HP............ @@ -2003,7 +4056,26 @@ Z = (195, 195, 195) .....LA...L..... ................ } -# tile 104 (black unicorn) +# tile 210 (black unicorn,male) +{ + ................ + ..HP............ + ..PHO.AA........ + ...PHAAJ........ + ...AADAJ........ + ..AAAAAJ........ + ..AAPAAJPP...... + ...PAAAJP....... + ...AAAAAAAA..... + ..AAAAAAAAAAPPP. + ..A.AAAAAAAPAP.. + ..APPAPPAPAPP... + ...LPAPPAPAP.... + .....APPLPA..... + .....LP...L..... + ................ +} +# tile 211 (black unicorn,female) { ................ ..HP............ @@ -2022,7 +4094,26 @@ Z = (195, 195, 195) .....LP...L..... ................ } -# tile 105 (horse) +# tile 212 (horse,male) +{ + ................ + ................ + .....JJ......... + ....KKKJ........ + ..KKKEKJ........ + .KKKJKKJAA...... + .JJJAKKJAA...... + ...AKKKJA....... + ...KKKKKKKKJA... + ..KKKKKKKKKKJA.. + ..KJJKJJJJJKAJA. + ..JAAJAAAAAJAJA. + ..JAAJAAAJAJAA.. + ..LA.JAA.L.JA... + .....LA....L.... + ................ +} +# tile 213 (horse,female) { ................ ................ @@ -2041,7 +4132,26 @@ Z = (195, 195, 195) .....LA....L.... ................ } -# tile 106 (warhorse) +# tile 214 (warhorse,male) +{ + ................ + .....JJJ........ + ...KKKKJJ....... + .KKKKEKJJ....... + KKKKKKKJJAA..... + JKKKJKKJJAA..... + .JJJAKKJJAA..... + ...AKKKJJA...... + ...KKKKKKKKKJA.. + ..KKKKKKKKKKKJA. + ..KKJKKJKKJKKJJA + ..KJAKJAKJAKJAJA + ..KJAKJAKJAKJA.. + ..LC.KJALC.KJ... + .....LC....LC... + ................ +} +# tile 215 (warhorse,female) { ................ .....JJJ........ @@ -2060,7 +4170,26 @@ Z = (195, 195, 195) .....LC....LC... ................ } -# tile 107 (fog cloud) +# tile 216 (fog cloud,male) +{ + .......P........ + ....P..P........ + .....P.P...P.... + ...P.......P.... + ..P..P.P.P...... + ....PP.PP.P.P... + .P..APAPPP..P... + ...P.PPPP.PP.... + ......PPPPP.P.P. + ...P.PPPPP..P... + ....P..P.PP.P... + .P...P.P...PPP.. + ..P.P....PP..... + .......P....P... + ..P..P.P..P..... + ................ +} +# tile 217 (fog cloud,female) { .......P........ ....P..P........ @@ -2079,7 +4208,26 @@ Z = (195, 195, 195) ..P..P.P..P..... ................ } -# tile 108 (dust vortex) +# tile 218 (dust vortex,male) +{ + ................ + ................ + ....K..KKKK..... + ...K..KKJJJK.... + ..K..KJJJJ..K... + .KJ.KJJ.JKK..K.. + .KJJKJ.JJJJK.... + .KJJJJ....JJK... + .KKJ.J...J.JKK.. + ..KJJ....JJJJK.. + ...KJJJJ.JKJJK.. + .K..KKJ.JJK.JK.. + ..K..JJJJK..K... + ...KJJJKK..K.... + ....KKKK..K..... + ................ +} +# tile 219 (dust vortex,female) { ................ ................ @@ -2098,7 +4246,26 @@ Z = (195, 195, 195) ....KKKK..K..... ................ } -# tile 109 (ice vortex) +# tile 220 (ice vortex,male) +{ + ................ + ................ + ....N..NNNN..... + ...N..NNOOON.... + ..N..NOOOO..N... + .NO.NOO.ONN..N.. + .NOONO.OOOON.... + .NOOOO....OON... + .NNO.O...O.ONN.. + ..NOO....OOOON.. + ...NOOOO.ONOON.. + .N..NNO.OON.ON.. + ..N..OOOON..N... + ...NOOONN..N.... + ....NNNN..N..... + ................ +} +# tile 221 (ice vortex,female) { ................ ................ @@ -2117,7 +4284,26 @@ Z = (195, 195, 195) ....NNNN..N..... ................ } -# tile 110 (energy vortex) +# tile 222 (energy vortex,male) +{ + ................ + ................ + ....E..EEEE..... + ...E..EEAAAE.... + ..E..EAAAA..E... + .EA.EAAAAIE..E.. + .EAAIAAAAAAE.... + .EAAAAAAAAAAE... + .EEAAAAAAAAAEE.. + ..EAAAAAAAAAAE.. + ...EAAAAAAIAAE.. + .E..EIAAAAE.AE.. + ..E..AAAAE..E... + ...EAAAEE..E.... + ....EEEE..E..... + ................ +} +# tile 223 (energy vortex,female) { ................ ................ @@ -2136,7 +4322,26 @@ Z = (195, 195, 195) ....EEEE..E..... ................ } -# tile 111 (steam vortex) +# tile 224 (steam vortex,male) +{ + ................ + ................ + ....P..PPPP..... + ...P..PPBBBP.... + ..P..PBBBB..P... + .PB.PBBPBPP..P.. + .PBBPBPBBBBP.... + .PBBBBP.PPBBP... + .PPBPB...BPBPP.. + ..PBBPP.PBBBBP.. + ...PBBBBPBPBBP.. + .P..PPBPBBP.BP.. + ..P..BBBBP..P... + ...PBBBPP..P.... + ....PPPP..P..... + ................ +} +# tile 225 (steam vortex,female) { ................ ................ @@ -2155,7 +4360,26 @@ Z = (195, 195, 195) ....PPPP..P..... ................ } -# tile 112 (fire vortex) +# tile 226 (fire vortex,male) +{ + ................ + ................ + ....D..DDDD..... + ...D..DDCCCD.... + ..D..DCCCC..D... + .DC.DCCHCDD..D.. + .DCCDCHCCCCD.... + .DCCCCHHHHCCD... + .DDCHCHHHCHCDD.. + ..DCCHHHHCCCCD.. + ...DCCCCHCDCCD.. + .D..DDCHCCD.CD.. + ..D..CCCCD..D... + ...DCCCDD..D.... + ....DDDD..D..... + ................ +} +# tile 227 (fire vortex,female) { ................ ................ @@ -2174,7 +4398,26 @@ Z = (195, 195, 195) ....DDDD..D..... ................ } -# tile 113 (baby long worm) +# tile 228 (baby long worm,male) +{ + ................ + ................ + ................ + ................ + ......CLC....... + ......LLL....... + .....GGAGG.A.... + .....GGAGGAAA... + ......LLLAAA.C.. + ......LLLAA.CC.. + ......CLLCCCCA.. + .......LLLCCA... + ........CLL..... + ................ + ................ + ................ +} +# tile 229 (baby long worm,female) { ................ ................ @@ -2193,7 +4436,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 114 (baby purple worm) +# tile 230 (baby purple worm,male) +{ + ................ + ................ + ................ + .......I........ + ......III....... + ......III....... + .....GGAGG.A.... + .....GGAGGAAA... + ......IIIAAA.D.. + ......IIIAA.DD.. + ......IIIDDDDA.. + .......IIIDDA... + ........III..... + ................ + ................ + ................ +} +# tile 231 (baby purple worm,female) { ................ ................ @@ -2212,7 +4474,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 115 (long worm) +# tile 232 (long worm,male) +{ + ................ + ................ + .....CLC........ + ....CLLLC....... + ....LLLLL....... + ...GGGLGGGAA.... + ...GAGLGAGAAA... + ...GGGLGGGAAA... + ....LLLLLAAACC.. + ....LLLLLAACCC.. + ....CLLLLCCCCA.. + .....LLLLLCCA... + ......CLLLL..... + ................ + ................ + ................ +} +# tile 233 (long worm,female) { ................ ................ @@ -2231,7 +4512,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 116 (purple worm) +# tile 234 (purple worm,male) +{ + ................ + ................ + .....DID........ + ....DIIID....... + ....IIIII....... + ...GGGIGGGAA.... + ...GAGIGAGAAA... + ...GGGIGGGAAA... + ....IIIIIAAADD.. + ....IIIIIAADDD.. + ....DIIIIDDDDA.. + .....IIIIIDDA... + ......DIIII..... + ................ + ................ + ................ +} +# tile 235 (purple worm,female) { ................ ................ @@ -2250,7 +4550,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 117 (grid bug) +# tile 236 (grid bug,male) +{ + ................ + ................ + ................ + ................ + ..D....NHCN..D.. + .D.D..NHDNCNDED. + D.D.D.NNHCND.DED + .D...D.NNHDND... + .DDD..ENNG.D.DE. + ..DDDDEEEEGD..DE + D.....DEHEE.D... + .D.......H...... + ................ + ................ + ................ + ................ +} +# tile 237 (grid bug,female) { ................ ................ @@ -2269,7 +4588,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 118 (xan) +# tile 238 (xan,male) +{ + ................ + ................ + ..........GG.... + ...HHH...GOGG... + .....HH..GGGG... + ...HHHHH.GGG.... + .......GG...AAA. + .....GOGGHHAAAA. + ....GOGG..HHAAA. + NNNGOGG.AAHHHA.. + NANGGGG.AAHAH... + NNNGGNNNAAAAAA.. + ..GGGNANAA.AAA.. + .GGGANNNAA.A.A.. + ..G..AAAAAA..... + ......AA.AA..... +} +# tile 239 (xan,female) { ................ ................ @@ -2288,7 +4626,26 @@ Z = (195, 195, 195) ..G..AAAAAA..... ......AA.AA..... } -# tile 119 (yellow light) +# tile 240 (yellow light,male) +{ + ................ + ......NA........ + ......HA........ + ..NA.NHNA.NA.... + ...LALHLALA..... + ....NHHHNA...... + ..NLHHHHHLNA.... + NHHHHHHHHHHHNA.. + ..NLHHHHHLNA.... + ....NHHHNA...... + ...LALHLALA..... + ..NA.NNNA.NA.... + ......HA........ + ......NA........ + ................ + ................ +} +# tile 241 (yellow light,female) { ................ ......NA........ @@ -2307,7 +4664,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 120 (black light) +# tile 242 (black light,male) +{ + ................ + ......AA........ + ......AA........ + ..AA.AAAA.AA.... + ...AAAAAAAA..... + ....AAAAAA...... + ..AAAAAAAAAA.... + AAAAAAAAAAAAAA.. + ..AAAAAAAAAA.... + ....AAAAAA...... + ...AAAAAAAA..... + ..AA.AAAA.AA.... + ......AA........ + ......AA........ + ................ + ................ +} +# tile 243 (black light,female) { ................ ......AA........ @@ -2326,7 +4702,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 121 (zruty) +# tile 244 (zruty,male) +{ + ................ + ......FFGF...... + ....OOFGFFFF.... + ...AOFGFOOKFF... + ...FFGFAOAJKKF.. + ..FFFFFFJAAJKK.. + ..ODOFFJAJJKKJA. + ..DDDDJAJJKJJAA. + ..JODOAJJJAJJAAA + .KKJAJJJKJAJJAAA + .KKAAJKKKKJAAAAA + ...AJJKKKKJJAAAA + ...KJJAAAAKJAAA. + ..JKJJJAAJJJJ... + ................ + ................ +} +# tile 245 (zruty,female) { ................ ......FFGF...... @@ -2345,7 +4740,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 122 (couatl) +# tile 246 (couatl,male) +{ + ................ + ................ + ........I....I.. + ....KKAIII..III. + ...NAOJAKI.IIIII + ...KKJAJJKKK..II + ...KKAAIJJJJJ..I + ...FAA.I...KJ..I + ..FAFA..AAAKJAA. + .......AAAJJAAA. + ......AKKJJAAA.. + ......KJAAAAAJA. + .....JJAA...JA.. + ......JJJJJJA... + ................ + ................ +} +# tile 247 (couatl,female) { ................ ................ @@ -2364,7 +4778,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 123 (Aleax) +# tile 248 (Aleax,male) { ................ ......BBBB..I... @@ -2383,7 +4797,48 @@ Z = (195, 195, 195) ..BF.LLAALLAFB.. ................ } -# tile 124 (Angel) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female Aleax wears slightly different clothing. +# +# tile 249 (Aleax,female) +{ + ................ + ......BBBB..I... + ..I..BF...B..... + ....BF.HHA.B.... + ...BF.HHHHA.B.I. + ...BF.LFLFA.FB.. + .I.BF.LLLLA.FB.. + ...BF.ALLA.FB... + ..BF.LJAAJL.ABA. + .BF.LLJJJJLLAFB. + .BF.LAJKJJALAFB. + .BF.LAJJKJALAFB. + ..BF..LJJLAAABA. + ...BF.LLALAABA.. + ..BF.LLAALLAFB.. + ................ +} +# tile 250 (Angel,male) +{ + ................ + ................ + ......HHHH...... + ................ + .......CC....... + ......CLLC..AA.. + ......PLLP....A. + ......NPPPA.A... + .....BBLLPPAAA.. + .....NNLLPPAAA.. + ......BNNPAAAA.. + ......BNNPAAAA.. + .....BNNNPAA.A.. + .....BNNNNPA.... + ....BNNNNNNP.... + ................ +} +# tile 251 (Angel,female) { ................ ................ @@ -2402,7 +4857,26 @@ Z = (195, 195, 195) ....BNNNNNNP.... ................ } -# tile 125 (ki-rin) +# tile 252 (ki-rin,male) +{ + ................ + ................ + ..LP............ + ..PLO.C.C....... + ...PLCCD........ + ...KCIKD........ + ..KCCCCD........ + ..CKACCDA....... + ...ACCCCCC...A.. + ...KCCCKCCKAA... + ..CAKCKCKCAKA... + ..CAAKAKAKA..... + ...L.KALAK...... + .....LA..L...... + ................ + ................ +} +# tile 253 (ki-rin,female) { ................ ................ @@ -2421,7 +4895,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 126 (Archon) +# tile 254 (Archon,male) { ................ ......OOOO...... @@ -2440,7 +4914,49 @@ Z = (195, 195, 195) ................ ................ } -# tile 127 (bat) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female archons are clean-shaven. Although of course not one +# hundred percent accurate, it's convenient visual shorthand. +# +# tile 255 (Archon,female) +{ + ................ + ......OOOO...... + .....OOOOOO..... + .....OJLLJO..... + .....OLLLLO..... + ....OOKLLKOO.... + ......AKKA...... + .....AAAAAAA.... + ....AAAAAAAAA... + ...OAAOAAAJLJ... + ..OOAOAAAACJC... + ....LAAAACCJCC.. + .....AAAAAJJJ... + ....AAAAAAAA.... + ................ + ................ +} +# tile 256 (bat,male) +{ + ................ + ................ + ................ + ................ + ...JJJCACJJJ.... + ..JJAAHJHAAJJ... + ..JA...JA..AJ... + ................ + ................ + ......AAAA...... + ....AAAAAAAA.... + ...AAA.AA.AAA... + .......AA....... + ................ + ................ + ................ +} +# tile 257 (bat,female) { ................ ................ @@ -2459,7 +4975,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 128 (giant bat) +# tile 258 (giant bat,male) +{ + ................ + ................ + ................ + ...JK.J.J.JK.... + ..KJJJCACJJKJ... + .JJJAAHJHAAJJK.. + .KJA...JA..AJJ.. + ..JA.......AJ... + ................ + .....AAAAAA..... + ...AAAAAAAAAA... + ..AAAA.AA.AAAA.. + .......AA....... + ................ + ................ + ................ +} +# tile 259 (giant bat,female) { ................ ................ @@ -2478,7 +5013,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 129 (raven) +# tile 260 (raven,male) +{ + ..AAAA...AAA.... + .AAAAAA.AAA..... + AAAAAAAAAAA.AA.. + A...AAAAAAAAAAA. + ......AAAAAAAAA. + .....AAAA.....AA + .....ADA.......A + .....PA......... + .....P.......... + .........P.P.P.. + ........P.P.P.P. + .......P.P.P.... + ........P.P.P... + ...........P.... + ................ + ................ +} +# tile 261 (raven,female) { ..AAAA...AAA.... .AAAAAA.AAA..... @@ -2497,7 +5051,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 130 (vampire bat) +# tile 262 (vampire bat,male) +{ + ................ + ................ + ................ + ...AA.A.A.AA.... + ..AAAAAAAAAAA... + .AAAA.DAD.AAAA.. + .AAA...A...AAA.. + ..A.........A... + ................ + .....AAAAAA..... + ...AAAAAAAAAA... + ..AAAA.AA.AAAA.. + .......AA....... + ................ + ................ + ................ +} +# tile 263 (vampire bat,female) { ................ ................ @@ -2516,7 +5089,30 @@ Z = (195, 195, 195) ................ ................ } -# tile 131 (plains centaur) +# tile 264 (plains centaur,male) +{ + ................ + ...KKA.......... + ...LLAA......... + .AAKKAA......... + .LLAALLA........ + LALLLLALA....... + LALLLKALA.A..... + ..LKLKAAAAA..... + ..KLKJKJJKAA.... + .KJKJKJKJAKAAAA. + .KAKJJJJKJAAA.A. + .KAAKAAAAKAA.... + ..CAKAAJAKA..... + ....KAAKAK...... + ....CA...C...... + ................ +} +# Note from contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Centaur tiles have no differentiation because the different types of +# centaurs are already extremely difficult to tell apart from one another. +# +# tile 265 (plains centaur,female) { ................ ...KKA.......... @@ -2535,7 +5131,26 @@ Z = (195, 195, 195) ....CA...C...... ................ } -# tile 132 (forest centaur) +# tile 266 (forest centaur,male) +{ + ................ + ................ + ................ + ...KKA.......... + LA.LLAALA....... + LAALLAALA....... + .LLAALLA........ + ..LLLLA.A....... + ..LKLKAAAAA..... + ..KLKJKJJKAA.... + .KJKJKJKJAKA.A.. + .KAKJJJJKJAAAA.. + .KAAKAAJAKA..... + ..C.KAAKAK...... + ....CA...C...... + ................ +} +# tile 267 (forest centaur,female) { ................ ................ @@ -2554,7 +5169,26 @@ Z = (195, 195, 195) ....CA...C...... ................ } -# tile 133 (mountain centaur) +# tile 268 (mountain centaur,male) +{ + ................ + ................ + ...KKA.......... + ...LLAA......... + ..AKKAA......... + .LJJJJLA........ + LAJKKJALA.A..... + LAKKKKALAAA..... + ..JJJJKJJKAA.... + .KJJJKJKJAKAAAA. + .KAKJJJJKJAAA.A. + .KAAKAAAAKAA.... + ..CAKAAJAKA..... + ....KAAKAK...... + ....CA...C...... + ................ +} +# tile 269 (mountain centaur,female) { ................ ................ @@ -2573,7 +5207,26 @@ Z = (195, 195, 195) ....CA...C...... ................ } -# tile 134 (baby gray dragon) +# tile 270 (baby gray dragon,male) +{ + ................ + ................ + ................ + .....BBBA....... + ....NPNPPA...... + ...BPPPPPA...... + ..CHHPABPA.AAA.. + .CHCDA.BPAAAAAA. + ..D..BPPAAAAAAA. + ....BBPPPPPAAAA. + ...BOOPPPPPPAAA. + ..BPOBPPPPPPPAA. + ..BPPBPPOBPAPPA. + ..BPABP.ABPAPPA. + .....BPAA..PPAA. + ...........PAA.. +} +# tile 271 (baby gray dragon,female) { ................ ................ @@ -2592,7 +5245,64 @@ Z = (195, 195, 195) .....BPAA..PPAA. ...........PAA.. } -# tile 135 (baby silver dragon) +# tile 272 (baby gold dragon,male) +{ + ................ + ................ + ................ + .....HHHA....... + ....ODODDA...... + ...PDDDDDA...... + ..CHHHAPDA.AAA.. + .CHCDA.PDAAAAAA. + ..D..PHDAAAAAAA. + ....PPHHDDDAAAA. + ...PNNHHHDDDAAA. + ..PHNPHHDHHDDAA. + ..PHDPHHNPDADDA. + ..PHAPH.APDADDA. + .....PHAA..DDAA. + ...........DAA.. +} +# tile 273 (baby gold dragon,female) +{ + ................ + ................ + ................ + .....HHHA....... + ....ODODDA...... + ...PDDDDDA...... + ..CHHHAPDA.AAA.. + .CHCDA.PDAAAAAA. + ..D..PHDAAAAAAA. + ....PPHHDDDAAAA. + ...PNNHHHDDDAAA. + ..PHNPHHDHHDDAA. + ..PHDPHHNPDADDA. + ..PHAPH.APDADDA. + .....PHAA..DDAA. + ...........DAA.. +} +# tile 274 (baby silver dragon,male) +{ + ................ + ................ + ................ + .....PPPA....... + ....OBOBBA...... + ...PBBBBBA...... + ..CHHBAPBA.AAA.. + .CHCDA.PBAAAAAA. + ..D..PBBAAAAAAA. + ....PPBBBBBAAAA. + ...PNNBBBBBBAAA. + ..PBNPBBBBBBBAA. + ..PBBPBBNPBABBA. + ..PBAPB.APBABBA. + .....PBAA..BBAA. + ...........BAA.. +} +# tile 275 (baby silver dragon,female) { ................ ................ @@ -2611,7 +5321,26 @@ Z = (195, 195, 195) .....PBAA..BBAA. ...........BAA.. } -# tile 136 (baby shimmering dragon) +# tile 276 (baby shimmering dragon,male) +{ + .I.............. + ...BBBBBBB.I.... + ..BF.FFF.FB...I. + .BF..BBBA.FB.... + BF..NPNPPAFB.I.. + BF.BPPPPPA.B.... + B.CHHPABPAFBAAI. + BCHCDA.BPAAFBAA. + B.D..BPPAAAAFBA. + B...BBPPPPPAAFB. + BF.BOOPPPPPPAAAB + BFBPOBPPPPPPPAFB + BFBPPBPPOBPAPPFB + B.BPABP.ABPAPPFB + B....BPAA..PPAAB + .B.........PAAB. +} +# tile 277 (baby shimmering dragon,female) { .I.............. ...BBBBBBB.I.... @@ -2630,7 +5359,26 @@ Z = (195, 195, 195) B....BPAA..PPAAB .B.........PAAB. } -# tile 137 (baby red dragon) +# tile 278 (baby red dragon,male) +{ + ................ + ................ + ................ + .....IIIA....... + ....NDNDDA...... + ...IDDDDDA...... + ..CHHDAIDA.AAA.. + .CHCDA.IDAAAAAA. + ..D..IDDAAAAAAA. + ....IIDDDDDAAAA. + ...IHHDDDDDDAAA. + ..IDHIDDDDDDDAA. + ..IDDIDDHIDADDA. + ..IDAID.AIDADDA. + .....IDAA..DDAA. + ...........DAA.. +} +# tile 279 (baby red dragon,female) { ................ ................ @@ -2649,7 +5397,26 @@ Z = (195, 195, 195) .....IDAA..DDAA. ...........DAA.. } -# tile 138 (baby white dragon) +# tile 280 (baby white dragon,male) +{ + ................ + ................ + ................ + .....NNNA....... + ....IOIOOA...... + ...NOOOOOA...... + ..CHHOANOA.AAA.. + .CHCDA.NOAAAAAA. + ..D..NOOAAAAAAA. + ....NNOOOOOAAAA. + ...NOOOOOOOOAAA. + ..NOONOOOOOOOAA. + ..NOONOOONOAOOA. + ..NOANO.ANOAOOA. + .....NOAA..OOAA. + ...........OAA.. +} +# tile 281 (baby white dragon,female) { ................ ................ @@ -2668,7 +5435,26 @@ Z = (195, 195, 195) .....NOAA..OOAA. ...........OAA.. } -# tile 139 (baby orange dragon) +# tile 282 (baby orange dragon,male) +{ + ................ + ................ + ................ + .....LLLA....... + ....NCNCCA...... + ...LCCCCCA...... + ..CHHCALCA.AAA.. + .CHCDA.LCAAAAAA. + ..D..LCCAAAAAAA. + ....LLCCCCCAAAA. + ...LOOCCCCCCAAA. + ..LCOLCCCCCCCAA. + ..LCCLCCOLCACCA. + ..LCALC.ALCACCA. + .....LCAA..CCAA. + ...........CAA.. +} +# tile 283 (baby orange dragon,female) { ................ ................ @@ -2687,7 +5473,26 @@ Z = (195, 195, 195) .....LCAA..CCAA. ...........CAA.. } -# tile 140 (baby black dragon) +# tile 284 (baby black dragon,male) +{ + ................ + ................ + ................ + .....AAA........ + ....NANAA....... + ...AAAAAA....... + ..CHHA.AA..PPP.. + .CHCD..AA.PPPPP. + ..D..AAAPPP.PPP. + ....AAAAAAAPPPP. + ...AAAAAAAAAPPP. + ..AAAAAAAAAAAPP. + ..AAAAAAAAAPAAP. + ..AAPAA.PAAPAAP. + .....AAP...AAPP. + ...........APP.. +} +# tile 285 (baby black dragon,female) { ................ ................ @@ -2706,7 +5511,26 @@ Z = (195, 195, 195) .....AAP...AAPP. ...........APP.. } -# tile 141 (baby blue dragon) +# tile 286 (baby blue dragon,male) +{ + ................ + ................ + ................ + .....BBBA....... + ....NENEEA...... + ...BEEEEEA...... + ..CHHEABEA.AAA.. + CCHCDA.BEAAAAAA. + ..D..BEEAAAAAAA. + ....BBEEEEEAAAA. + ...BOOEEEEEEAAA. + ..BEOBEEEEEEEAA. + ..BEEBEEOBEAEEA. + ..BEABE.ABEAEEA. + .....BEAA..EEAA. + ...........EAA.. +} +# tile 287 (baby blue dragon,female) { ................ ................ @@ -2725,7 +5549,26 @@ Z = (195, 195, 195) .....BEAA..EEAA. ...........EAA.. } -# tile 142 (baby green dragon) +# tile 288 (baby green dragon,male) +{ + ................ + ................ + ................ + .....GGGA....... + ....NFNFFA...... + ...GFFFFFA...... + ..CHHFAGFA.AAA.. + .CHCDA.GFAAAAAA. + ..D..GFFAAAAAAA. + ....GGFFFFFAAAA. + ...GOOFFFFFFAAA. + ..GFOGFFFFFFFAA. + ..GFFGFFOGFAFFA. + ..GFAGF.AGFAFFA. + .....GFAA..FFAA. + ...........FAA.. +} +# tile 289 (baby green dragon,female) { ................ ................ @@ -2744,7 +5587,26 @@ Z = (195, 195, 195) .....GFAA..FFAA. ...........FAA.. } -# tile 143 (baby yellow dragon) +# tile 290 (baby yellow dragon,male) +{ + ................ + ................ + ................ + .....NNNA....... + ....DHDHHA...... + ...NHHHHHA...... + ..CHHHANHA.AAA.. + .CHCDA.NHAAAAAA. + ..D..NHHAAAAAAA. + ....NNHHHHHAAAA. + ...NOOHHHHHHAAA. + ..NHONHHHHHHHAA. + ..NHHNHHONHAHHA. + ..NHANH.ANHAHHA. + .....NHAA..HHAA. + ...........HAA.. +} +# tile 291 (baby yellow dragon,female) { ................ ................ @@ -2763,7 +5625,26 @@ Z = (195, 195, 195) .....NHAA..HHAA. ...........HAA.. } -# tile 144 (gray dragon) +# tile 292 (gray dragon,male) +{ + ......BBBPA..... + .....NPNPPPA.... + ....BPPPPPPA.... + ..DCHHP..PPA.... + CHCHCD..BPPA.... + HD.D...BPPA..... + ......OBPAAAAAA. + ....BOBPAAAAAAAA + ..BOOBPA.PP.AAA. + .BOOOBPPPPPP.AA. + .BOOOBPPPPPPPAA. + PPOOBBPPPPPPPPA. + BP.OBPPOOPP.P.A. + BPAABP.AAPPAPPA. + ....BPAA...PP.A. + ........PPPP.A.. +} +# tile 293 (gray dragon,female) { ......BBBPA..... .....NPNPPPA.... @@ -2782,7 +5663,64 @@ Z = (195, 195, 195) ....BPAA...PP.A. ........PPPP.A.. } -# tile 145 (silver dragon) +# tile 294 (gold dragon,male) +{ + ......HHHDA..... + .....OHOHHDA.... + ....PHHHHDDA.... + ..DCHHD..HDA.... + CHCHCD..PHDA.... + HD.D...PHDA..... + ......HPDAAAAAA. + ....PHPDAAAAAAAA + ..PHHPDA.HH.AAA. + .PHHHPDHHDHH.AA. + .PHHHPDDHHDHHAA. + DDHHPPDHHDHHDHA. + PD.HPDDHHDD.D.A. + PDAAPD.AADHADHA. + ....PDAA...HD.A. + ........DDHD.A.. +} +# tile 295 (gold dragon,female) +{ + ......HHHDA..... + .....OHOHHDA.... + ....PHHHHDDA.... + ..DCHHD..HDA.... + CHCHCD..PHDA.... + HD.D...PHDA..... + ......HPDAAAAAA. + ....PHPDAAAAAAAA + ..PHHPDA.HH.AAA. + .PHHHPDHHDHH.AA. + .PHHHPDDHHDHHAA. + DDHHPPDHHDHHDHA. + PD.HPDDHHDD.D.A. + PDAAPD.AADHADHA. + ....PDAA...HD.A. + ........DDHD.A.. +} +# tile 296 (silver dragon,male) +{ + ......PPPBA..... + .....OBOBBBA.... + ....PBBBBBBA.... + ..DCHHB..BBA.... + CHCHCD..PBBA.... + HD.D...PBBA..... + ......NPBAAAAAA. + ....PNPBAAAAAAAA + ..PNNPBA.BB.AAA. + .PNNNPBBBBBB.AA. + .PNNNPBBBBBBBAA. + BBNNPPBBBBBBBBA. + PB.NPBBNNBB.B.A. + PBAAPB.AABBABBA. + ....PBAA...BB.A. + ........BBBB.A.. +} +# tile 297 (silver dragon,female) { ......PPPBA..... .....OBOBBBA.... @@ -2801,7 +5739,26 @@ Z = (195, 195, 195) ....PBAA...BB.A. ........BBBB.A.. } -# tile 146 (shimmering dragon) +# tile 298 (shimmering dragon,male) +{ + .I.BF.BBBPAFB... + ..BF.NPNPPPAFB.I + .BF.BPPPPPPAFB.. + .BDCHHP..PPAFBI. + CBCHCD..BPPAFB.. + HDBB...BPPA.B..I + ..BF..OBPAAAABA. + .BF.BOBPAAAAAFBA + BFBOOBPA.PP.AAFB + .BOOOBPPPPPP.AFB + .BOOOBPPPPPPPAFB + PPOOBBPPPPPPPPFB + BP.OBPPOOPP.P.FB + BPAABP.AAPPAPPFB + ....BPAA...PP.AB + ........PPPP.AB. +} +# tile 299 (shimmering dragon,female) { .I.BF.BBBPAFB... ..BF.NPNPPPAFB.I @@ -2820,7 +5777,26 @@ Z = (195, 195, 195) ....BPAA...PP.AB ........PPPP.AB. } -# tile 147 (red dragon) +# tile 300 (red dragon,male) +{ + ......IIIDA..... + .....NDNDDDA.... + ....IDDDDDDA.... + ..DCHHD..DDA.... + CHCHCD..IDDA.... + HD.D...IDDA..... + ......HIDAAAAAA. + ....IHIDAAAAAAAA + ..IHHIDAJDDJAAA. + .IHHHIDDDDDDJAA. + .IHHHIDDDDDDDAA. + DDHHIIDDDDDDDDA. + ID.HIDDHHDDJDJA. + IDAAID.AADDADDA. + ....IDAAJJJDDJA. + ........DDDDJA.. +} +# tile 301 (red dragon,female) { ......IIIDA..... .....NDNDDDA.... @@ -2839,7 +5815,7 @@ Z = (195, 195, 195) ....IDAAJJJDDJA. ........DDDDJA.. } -# tile 148 (white dragon) +# tile 302 (white dragon,male) { ......NNNOA..... .....IOIOOOA.... @@ -2858,7 +5834,45 @@ Z = (195, 195, 195) ....NOAA...OOJA. ........OOOOJA.. } -# tile 149 (orange dragon) +# tile 303 (white dragon,female) +{ + ......NNNOA..... + .....IOIOOOA.... + ....NOOOOOOA.... + ..DCHHO..OOA.... + CHCHCD..NOOA.... + HD.D...NOOA..... + ......ONOAAAAAA. + ....NONOAAAAAAAA + ..NOONOA.OO.AAA. + .NOOONOOOOOOJAA. + .NOOONOOOOOOOAA. + OOOONNOOOOOOOOA. + NO.ONOOOOOO.OJA. + NOAANO.AAOOAOOA. + ....NOAA...OOJA. + ........OOOOJA.. +} +# tile 304 (orange dragon,male) +{ + ......LLLCA..... + .....NCNCCCA.... + ....LCCCCCCA.... + ..DCHHC..CCA.... + CHCHCD..LCCA.... + HD.D...LCCA..... + ......OLCAAAAAA. + ....LOLCAAAAAAAA + ..LOOLCA.CCKAAA. + .LOOOLCCCCCCJAA. + .LOOOLCCCCCCCAA. + CCOOLLCCCCCCCCA. + LC.OLCCOOCCKCJA. + LCAALC.AACCACCA. + ....LCAA.KKCCJA. + ........CCCCJA.. +} +# tile 305 (orange dragon,female) { ......LLLCA..... .....NCNCCCA.... @@ -2877,7 +5891,26 @@ Z = (195, 195, 195) ....LCAA.KKCCJA. ........CCCCJA.. } -# tile 150 (black dragon) +# tile 306 (black dragon,male) +{ + ......AAAA...... + .....NANAAA..... + ....AAAAAAA..... + ..DCHHA..AA..... + CHCHCD..AAA..... + HD.D...AAA...... + ......AAA..PPPP. + ....AAAAPPPPPPPP + ..AAAAAAAAA.PPP. + .AAAAAAAAAAAAPP. + .AAAAAAAAAAAAPP. + AAAAAAAAAAAAAAP. + AA.AAAAAAAA.AAP. + AAPPAA.PPAAPAAP. + ....AAPP...AAAP. + ........AAAAA... +} +# tile 307 (black dragon,female) { ......AAAA...... .....NANAAA..... @@ -2896,7 +5929,26 @@ Z = (195, 195, 195) ....AAPP...AAAP. ........AAAAA... } -# tile 151 (blue dragon) +# tile 308 (blue dragon,male) +{ + ......BBBEA..... + .....NENEEEA.... + ....BEEEEEEA.... + ..DCHHE..EEA.... + CHCHCD..BEEA.... + HD.D...BEEA..... + ......OBEAAAAAA. + ....BOBEAAAAAAAA + ..BOOBEA.EE.AAA. + .BOOOBEEEEEEJAA. + .BOOOBEEEEEEEAA. + EEOOBBEEEEEEEEA. + BE.OBEEOOEE.EJA. + BEAABE.AAEEAEEA. + ....BEAA...EEJA. + ...P....EEEEJA.. +} +# tile 309 (blue dragon,female) { ......BBBEA..... .....NENEEEA.... @@ -2915,7 +5967,26 @@ Z = (195, 195, 195) ....BEAA...EEJA. ...P....EEEEJA.. } -# tile 152 (green dragon) +# tile 310 (green dragon,male) +{ + ......GGGFA..... + .....NFNFFFA.... + ....GFFFFFFA.... + ..DCHHF..FFA.... + CHCHCD..GFFA.... + HD.D...GFFA..... + ......OGFAAAAAA. + ....GOGFAAAAAAAA + ..GOOGFA.FF.AAA. + .GOOOGFFFFFFJAA. + .GOOOGFFFFFFFAA. + FFOOGGFFFFFFFFA. + GF.OGFFOOFF.FJA. + GFAAGF.AAFFAFFA. + ....GFAA...FFJA. + ........FFFFJA.. +} +# tile 311 (green dragon,female) { ......GGGFA..... .....NFNFFFA.... @@ -2934,7 +6005,26 @@ Z = (195, 195, 195) ....GFAA...FFJA. ........FFFFJA.. } -# tile 153 (yellow dragon) +# tile 312 (yellow dragon,male) +{ + ......NNNHA..... + .....DHDHHHA.... + ....NHHHHHHA.... + ..DCHHH..HHA.... + CHCHCD..NHHA.... + HD.D...NHHA..... + ......ONHAAAAAA. + ....NONHAAAAAAAA + ..NOONHAJHHJAAA. + .NOOONHHHHHHJAA. + .NOOONHHHHHHHAA. + HHOONNHHHHHHHHA. + NH.ONHHOOHHJHJA. + NHAANH.AAHHAHHA. + ....NHAAJJJHHJA. + ........HHHHJA.. +} +# tile 313 (yellow dragon,female) { ......NNNHA..... .....DHDHHHA.... @@ -2953,7 +6043,26 @@ Z = (195, 195, 195) ....NHAAJJJHHJA. ........HHHHJA.. } -# tile 154 (stalker) +# tile 314 (stalker,male) +{ + ................ + .......PPP...... + ......P.P.P..... + .....PPPPPP..... + .....PP..PPP.... + ....PPPPPP.P.... + ....P.PPPP.P.... + ....P.PPP..P.... + ....P..PP..P.... + ....P.PPPP.P.... + ....P.P..P.P.... + ....P.P..P.P.... + ......P..P...... + ......P..P...... + .....PP..PP..... + ................ +} +# tile 315 (stalker,female) { ................ .......PPP...... @@ -2972,7 +6081,26 @@ Z = (195, 195, 195) .....PP..PP..... ................ } -# tile 155 (air elemental) +# tile 316 (air elemental,male) +{ + ................ + ...P.PPP..P..... + ..P.PAPA.P...... + P..PPPPPP..P.... + .P.PPAAPPP...P.. + ..PPPAAP.P.P.... + ..PAPAAPAP...... + P.PAPPP.AP.P.AA. + ..PA.PP.AP.AAAA. + ..PAPPPPAPAAAA.. + ..PAP.APAPAAAA.. + ..PAP.APAPAAAAA. + ....P.APAAAAAAA. + ..P.P.APPAAAAAA. + ...PP.APPPA..... + ................ +} +# tile 317 (air elemental,female) { ................ ...P.PPP..P..... @@ -2991,7 +6119,26 @@ Z = (195, 195, 195) ...PP.APPPA..... ................ } -# tile 156 (fire elemental) +# tile 318 (fire elemental,male) +{ + ................ + .H..LDDD........ + ...LDADAC.H..... + H..DDDDDD..H.H.. + ..LDDAADDD...... + ..DDDAADCD.H.... + ..DADAACAD...... + H.DADDDCAD...AA. + ..DACDDCAD.AAAA. + ..DADDDDADAAAA.. + ..DADCADADAAAA.. + H.DADCADADAAAAA. + ....DCADAAAAAAA. + .H.LDCADDAAAAAA. + ..LDDCADDDA..... + ................ +} +# tile 319 (fire elemental,female) { ................ .H..LDDD........ @@ -3010,7 +6157,26 @@ Z = (195, 195, 195) ..LDDCADDDA..... ................ } -# tile 157 (earth elemental) +# tile 320 (earth elemental,male) +{ + ..F............. + ....CKKK..F..... + ...CKAKAJ....F.. + ...KKKKKK....... + ..CKKAAKKK.F..F. + .FKKKAAKJK...... + ..KAKAAJAK..F... + ..KAKJJJAK...AA. + F.KAJKKJAK.AAAA. + ..KAKKKKAKAAAA.. + ..KAKJAKAKAAAA.. + ..KAKJAKAKAAAAA. + ....KJAKAAAAAAA. + .F.CKJAKKAAAAAA. + ..CKKJAKKKA..... + ................ +} +# tile 321 (earth elemental,female) { ..F............. ....CKKK..F..... @@ -3029,7 +6195,26 @@ Z = (195, 195, 195) ..CKKJAKKKA..... ................ } -# tile 158 (water elemental) +# tile 322 (water elemental,male) +{ + ................ + ....PBBB..E..... + .E.PBABAE...E... + ...BBBBBB....... + ..PBBAABBB.E..E. + E.BBBAABEB...... + ..BABAABEB.E.... + ..BABBBBEB...AA. + ..BAPBBEAB.AAAA. + E.BABBBBABAAAA.. + ..BABEABABAAAA.. + ..BABEABABAAAAA. + ....BEABAAAAAAA. + .E.PBEABBAAAAAA. + ..PBBEABBBA..... + ................ +} +# tile 323 (water elemental,female) { ................ ....PBBB..E..... @@ -3048,7 +6233,26 @@ Z = (195, 195, 195) ..PBBEABBBA..... ................ } -# tile 159 (lichen) +# tile 324 (lichen,male) +{ + ................ + ................ + ...FFF...FFF.... + ..FCFFFFFCCFA... + .FCOOFFFCOFFFA.. + .FCOOFFFCFFFFA.. + ..FFFFFFFFFFA... + ...AFFFCCFFFA... + ...FFFFCOFFAA... + ..FCCFFCOFCFA... + ..FCOFFCFFOCFA.. + ..FFCFFFCFFFFA.. + ...FFFAAFFFFFA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 325 (lichen,female) { ................ ................ @@ -3067,7 +6271,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 160 (brown mold) +# tile 326 (brown mold,male) +{ + ................ + ................ + ...JJJ...JJJ.... + ..JKJJJJJKKJA... + .JKCCJJJKCJJJA.. + .JKCCJJJKJJJJA.. + ..JJJJJJJJJJA... + ...AJJJKKJJJA... + ...JJJJKCJJAA... + ..JKKJJKCJKJA... + ..JKCJJKJJCKJA.. + ..JJKJJJKJJJJA.. + ...JJJAAJJJJJA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 327 (brown mold,female) { ................ ................ @@ -3086,7 +6309,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 161 (yellow mold) +# tile 328 (yellow mold,male) +{ + ................ + ................ + ...HHH...HHH.... + ..HHHHHHHNHHA... + .HHNNOHHNNOHHA.. + .HHNNOOHHOOHHA.. + ..HHOOHHHHHHA... + ...AHHHHHHHHA... + ...HHHHNNOHAA... + ..HHHHHNNOHHA... + ..HNNOHHHONOHA.. + ..HHOHHHHHOOHA.. + ...HHHAAHHHHHA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 329 (yellow mold,female) { ................ ................ @@ -3105,7 +6347,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 162 (green mold) +# tile 330 (green mold,male) +{ + ................ + ................ + ...FFF...FFF.... + ..FGFFFFFGGFA... + .FGOOFFFGOFFFA.. + .FGOOFFFGFFFFA.. + ..FFFFFFFFFFA... + ...AFFFGGFFFA... + ...FFFFGOFFAA... + ..FGGFFGOFGFA... + ..FGOFFGFFOGFA.. + ..FFGFFFGFFFFA.. + ...FFFAAFFFFFA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 331 (green mold,female) { ................ ................ @@ -3124,7 +6385,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 163 (red mold) +# tile 332 (red mold,male) +{ + ................ + ................ + ...DDD...DDD.... + ..DCDDDDDCCDA... + .DLLCDDDCLDDDA.. + .DCCCDDDCDDDDA.. + ..DDDDDDDDDDA... + ...ADDDCCDDDA... + ...DDDDCLDDAA... + ..DCCDDCLDCDA... + ..DCLDDCDDLCDA.. + ..DDCDDDCDDDDA.. + ...DDDAADDDDDA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 333 (red mold,female) { ................ ................ @@ -3143,7 +6423,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 164 (shrieker) +# tile 334 (shrieker,male) { ................ ................ @@ -3162,7 +6442,45 @@ Z = (195, 195, 195) ...AAAAAAAAAA... ................ } -# tile 165 (violet fungus) +# tile 335 (shrieker,female) +{ + ................ + ................ + ................ + ................ + .....GGGGFF..... + ...GGGGIGIDFF... + .GGGIIGGGIIFFFF. + GIIGIIGGGGGGGDDF + GIIGGGGIIGIIGIDF + GGGGIGGIIGIIGGFF + ..GGGGGGGGGGG... + ......FFF..AAAAA + ....AGGGFFAAAAAA + ...AGGGGGGFAAAA. + ...AAAAAAAAAA... + ................ +} +# tile 336 (violet fungus,male) +{ + ................ + ................ + ...III...III.... + ..ILIIIIILLIA... + .IOOLIIILOIIIA.. + .ILLLIIILIIIIA.. + ..IIIIIIIIIIA... + ...AIIILLIIIA... + ...IIIILOIIAA... + ..ILLIILOILIA... + ..ILOIILIIOLIA.. + ..IILIIILIIIIA.. + ...IIIAAIIIIIA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 337 (violet fungus,female) { ................ ................ @@ -3181,7 +6499,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 166 (gnome) +# tile 338 (gnome,male) { ................ ................ @@ -3200,7 +6518,30 @@ Z = (195, 195, 195) ................ ................ } -# tile 167 (gnome lord) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female gnomes are clean-shaven. Although of course not one +# hundred percent accurate, it's convenient visual shorthand. +# +# tile 339 (gnome,female) +{ + ................ + ................ + ................ + .....DF......... + ......G......... + .....GFF........ + ....GGFFF....... + ....GLLLF....... + .....LLL...AAA.. + ...FGGGGFFAAAA.. + ...GAGFFAFAAAA.. + ....LKNKFAAAA... + ....FGAFFAA..... + ....GFAFG.A..... + ................ + ................ +} +# tile 340 (gnome leader,male) { ................ ................ @@ -3219,7 +6560,30 @@ Z = (195, 195, 195) ................ ................ } -# tile 168 (gnomish wizard) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female gnome leaders are clean-shaven. Although of course not one +# hundred percent accurate, it's convenient visual shorthand. +# +# tile 341 (gnome leader,female) +{ + ................ + ................ + ......D......... + ......G......... + ......G......... + .....GFF........ + ....HHHHH....... + ....GLLLF.....A. + .....LLL...AAA.. + ...FGGGGFFAAAA.. + ...GAGGFAFAAAA.. + ....LKNKFAAAA... + ....FGAFFAA..... + ....GFAFG.A..... + ................ + ................ +} +# tile 342 (gnomish wizard,male) { ................ ................ @@ -3238,7 +6602,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 169 (gnome king) +# tile 343 (gnomish wizard,female) +{ + ................ + ................ + ................ + ................ + ......G......... + .....GFF........ + ....GGFFF....... + ....GLLLF....... + ...FFLLLFF.AAA.. + ...GFGFGFFAAAA.. + ...FAGGFAFAAAA.. + ...GLKNKFFAAA... + ...FFGFFFFA..... + ...GFFFFGFA..... + ................ + ................ +} +# tile 344 (gnome ruler,male) { ................ ................ @@ -3257,7 +6640,30 @@ Z = (195, 195, 195) ................ ................ } -# tile 170 (giant) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female gnome rulers are clean-shaven. Although of course not one +# hundred percent accurate, it's convenient visual shorthand. +# +# tile 345 (gnome ruler,female) +{ + ................ + ................ + ................ + ................ + ....H.C.H....... + ....HCHCH....... + ....HHHHH....... + ....GLLLF...A... + .....LLL...AAAA. + ...FGGGGFFAAAA.. + ...GAGFFAFAAAA.. + ....LKNKFAAAA... + ....FGAFFAA..... + ....GFAFG.A..... + ................ + ................ +} +# tile 346 (giant,male) { ......JJJJAA.... ....JJJJJJJJA... @@ -3276,7 +6682,45 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.CLLLKAA } -# tile 171 (stone giant) +# tile 347 (giant,female) +{ + ......JJJJAA.... + ....JJJJJJJJA... + ....JJLLLLJJA... + ....JFFLLFFJA... + ....JLLLLLLJA... + ....ALLAALLAAA.. + .....ALLLLJAAAA. + ..CCLLJJJJLLCCAA + .CLLLCCKCKCLLLCA + .LLLKLKCKCLKLLLA + .LLAALLCCLLAALLA + .LLAAJJJKKJAALLA + .CLC.JJJJJKKCLAA + ..LL.CLJACLJLLAA + .....CLJACLJAAAA + ...LLLLJ.CLLLKAA +} +# tile 348 (stone giant,male) +{ + ......JJJJAA.... + ....JJJJJJJJA... + ....JJLLLLJJA... + ....JFFLLFFJA... + ....JLLLLLLJA... + ....ALLAALLAAA.. + .....ALLLLJAAAA. + ..CCLLJJJJLLCCAA + .CLLLCCKCKCLLLCA + .LLLAAKCKCLKLLLA + .LLPPPACCLLAALLA + .LLPPPPAKKJAALLA + .CLCPPPAJJKKCLAA + ..LLPPALACLJLLAA + .....ALJACLJAAAA + ...LLLLJ.CLLLKAA +} +# tile 349 (stone giant,female) { ......JJJJAA.... ....JJJJJJJJA... @@ -3295,7 +6739,26 @@ Z = (195, 195, 195) .....ALJACLJAAAA ...LLLLJ.CLLLKAA } -# tile 172 (hill giant) +# tile 350 (hill giant,male) +{ + ......JJJJAA.... + ....JJJJJJJJA... + ....JJLLLLJJA... + ....JFFLLFFJA... + ....JLLLLLLJA... + ....ALLAALLAAA.. + .....ALLLLJAAAA. + ...JJKJJJJJJJAA. + ..LJJCCKCKCJJLA. + ..JLKKKCKCKKLJA. + ..LAAKKCCKJAALAA + ..LAAJJJKKJAALAA + ..LC.JJJJJKKCLAA + ..LL.CLJACLJLLAA + .....CLJACLJAAAA + ...LLLLJ.LLLLKAA +} +# tile 351 (hill giant,female) { ......JJJJAA.... ....JJJJJJJJA... @@ -3314,7 +6777,26 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.LLLLKAA } -# tile 173 (fire giant) +# tile 352 (fire giant,male) +{ + ....PPDDDDAA.... + ....PDDDDDDDA... + ...PPDLLLLDDA... + ...PDPFLLFFDA... + ...PPPLLLLLDA... + ....PLLAALLAAA.. + ...PPALLLLJAAAA. + ...JPDJJJJJJJAA. + ..LDDHDKCKCJJLA. + ..JLHDDCKCKKLJA. + ..LAHDHCCKJAALAA + JLAADDHJKKJAALAA + JJLJDHHJJJKKCLAA + ..LLJJJJACLJLLAA + .....CLJACLJAAAA + ...LLLLJ.LLLLKAA +} +# tile 353 (fire giant,female) { ....PPDDDDAA.... ....PDDDDDDDA... @@ -3333,7 +6815,7 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.LLLLKAA } -# tile 174 (frost giant) +# tile 354 (frost giant,male) { .....KJJJJAA.... ....KJJJJJJJA... @@ -3352,7 +6834,49 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.CLLLKAA } -# tile 175 (ettin) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female frost giants are clean-shaven. Although of course not one +# hundred percent accurate, it's convenient visual shorthand. +# +# tile 355 (frost giant,female) +{ + .....KJJJJAA.... + ....KJJJJJJJA... + ....JJLLLLJJA... + ....JEELLEEJA... + ....JLLLLLLJA... + ....ALLLLLLAAA.. + .....LLAALLAAAA. + ....KKLLLLKKAAAA + ...KJKKKKKKJJAAA + ..KJKKJJJJKKJJAA + ..KAAJKJJKJAAJAA + ..JAAJKKKKJAAJAA + ..LC.JJJJJKKCLAA + ..LL.CJJAJLJLLAA + .....CLJACLJAAAA + ...LLLLJ.CLLLKAA +} +# tile 356 (ettin,male) +{ + ....NN..ONOP.... + ..NNOOPNNOOPP... + ..NPP..NPP..P... + ..ALPPLALPPLA... + ..APPPPAPPPPA... + ..APAAPAPAAPAA.. + ..APPPPAPPPPAAA. + ..BIIIIJJJIIIBAA + .BPPPIIIIIIPPPBA + .PPPFPIIIIPFPPPA + .PPAAPIIIIPAAPPA + .PPAAIIIIIIAAPPA + .BPB.IIFFIIABPAA + ..PP.BPAABPAPPAA + .....BPAABPAAAAA + ...PPPPA.BPPPFAA +} +# tile 357 (ettin,female) { ....NN..ONOP.... ..NNOOPNNOOPP... @@ -3371,7 +6895,26 @@ Z = (195, 195, 195) .....BPAABPAAAAA ...PPPPA.BPPPFAA } -# tile 176 (storm giant) +# tile 358 (storm giant,male) +{ + ......JJJJAA.... + ....JJJJJJJJA... + ....JJLLLLJJA... + ....JFFLLFFJA... + ....JLLLLLLJA... + ....ALLAALLAAH.. + .....ALLLLJAHAA. + ...JJKJJJJJHHAA. + ..LJJCCKCKHHLAA. + ..JLKKKCKHHHHHH. + ..LAAKKCCKJAHHAA + ..LAAJJJKKJHHALA + ..LC.JJJJJKHAAAA + ..LL.CLJACHAAAAA + .....CLJACCJAAAA + ...LLLLJ.LLLLKAA +} +# tile 359 (storm giant,female) { ......JJJJAA.... ....JJJJJJJJA... @@ -3390,7 +6933,26 @@ Z = (195, 195, 195) .....CLJACCJAAAA ...LLLLJ.LLLLKAA } -# tile 177 (titan) +# tile 360 (titan,male) +{ + .....AAAAAAA.... + ....AALLLLAAA... + ....A..LL..AA... + ....ALLLLLLAA... + ....ALLAALLAAA.. + .....ALLLLJAAAA. + ..CCJJJJJJJJCCA. + .CLLLCCKCKCLLLCA + .LLLKJKCKCJKLLLA + .LLAAJJCCJJAALLA + .LLAAJJCCJJAALLA + .LLAAJJJKKJAALLA + .CLC.JJJJJKKCLAA + ..LL.CLJACLJLLAA + .....CLJACLJAAAA + ...LLLLJ.CLLLKAA +} +# tile 361 (titan,female) { .....AAAAAAA.... ....AALLLLAAA... @@ -3409,7 +6971,7 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.CLLLKAA } -# tile 178 (minotaur) +# tile 362 (minotaur,male) { ................ .O..........O... @@ -3428,7 +6990,48 @@ Z = (195, 195, 195) ....CLCACLCAAAAA ..LLLLL.LLLLLAA. } -# tile 179 (jabberwock) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female minotaurs wear slightly different clothing. +# +# tile 363 (minotaur,female) +{ + ................ + .O..........O... + .OOOJJJJJJOOO... + ..OOJJKJJJOO.... + ...JGAKJGAJA.... + ...JJJKJJJJA.... + ....JJKJJJAAA... + ....JKKKJAAAA... + ..CLJAJAKALCAA.A + .CLLJJJJJALLCAAA + .LLCLAAAALCLLAA. + .LAAJLLLLJAALAA. + .LL.JJJJJJJLLAAA + .LL.JJJJJJJLLAAA + ....CLCACLCAAAAA + ..LLLLL.LLLLLAA. +} +# tile 364 (jabberwock,male) +{ + ................ + ...DP........... + ....DP.ADOO..... + ..DAIDADIPAD.... + ...DIAPIPA...... + ...DBDDDA....... + ..IBBDADDA..AA.. + .DDDDAODDIAAAA.. + ..OAOA.DDAIAAA.. + ..IOAODDAAADDAA. + ..DDDADDDDAIDA.. + ...AAADDIDIDDD.. + ....IDDAIDDDDA.. + ....IDAAIDAA.... + ...IDAA..ID..... + ................ +} +# tile 365 (jabberwock,female) { ................ ...DP........... @@ -3447,7 +7050,26 @@ Z = (195, 195, 195) ...IDAA..ID..... ................ } -# tile 180 (vorpal jabberwock) +# tile 366 (vorpal jabberwock,male) +{ + ................ + ...GP........... + ....GP.AGOO..... + ..GAFGAGFPAG.... + ...GFAPFPA...... + ...GHGGGA....... + ..FHHGAGGA..AA.. + .GGGGAOGGFAAAA.. + ..OAOA.GGAFAAA.. + ..FOAOGGAAAGGAA. + ..GGGAGGGGAFGA.. + ...AAAGGFGFGGG.. + ....FGGAFGGGGA.. + ....FGAAFGAA.... + ...FGAA..FG..... + ................ +} +# tile 367 (vorpal jabberwock,female) { ................ ...GP........... @@ -3466,7 +7088,26 @@ Z = (195, 195, 195) ...FGAA..FG..... ................ } -# tile 181 (Keystone Kop) +# tile 368 (Keystone Kop,male) +{ + ................ + ....AA.......... + ...AAAA......... + ...AOAA...C..... + ..AAAAAA..C..... + ...LLLL...C..... + ....LL....C..... + ...AAAA.AAA..... + ..AAAAAAAAC.P... + .AA.AAAAA.PPPP.. + ..AAAAAA.PPPPPP. + ....AAAAPPPAPP.. + .A.AAAAAAPAAA... + AAAAA.PAAAAA.... + ..AA....AA...... + ................ +} +# tile 369 (Keystone Kop,female) { ................ ....AA.......... @@ -3485,7 +7126,26 @@ Z = (195, 195, 195) ..AA....AA...... ................ } -# tile 182 (Kop Sergeant) +# tile 370 (Kop Sergeant,male) +{ + ................ + ....AA.......... + ...AOOA......... + ...AOOA...C..... + ..AAAAAA..C..... + ...LLLL...C..... + ....LL....C..... + ...AAAA.AAA..... + ..AAAAAAAAC.P... + .AA.AAAAA.CPPP.. + ..AAAAAA.PPPPPP. + ....AAAAPPPAPP.. + .A.AAAAAAPAAA... + AAAAA.PAAAAA.... + ..AA....AA...... + ................ +} +# tile 371 (Kop Sergeant,female) { ................ ....AA.......... @@ -3504,7 +7164,26 @@ Z = (195, 195, 195) ..AA....AA...... ................ } -# tile 183 (Kop Lieutenant) +# tile 372 (Kop Lieutenant,male) +{ + ................ + ....AA.......... + ...AOOA...C..... + ...AOOA...C..... + ..AAAAAA..C..... + ...LLLL...C..... + ....LL....C..... + ..OAAAO.AAA..... + .OAAAAA.AAC.P... + .AA.AAAAA.CPPP.. + ..AAAAAA.PPPPPP. + ....AAAAPPPAPP.. + .A.AAAAAAPAAA... + AAAAA.PAAAAA.... + ..AA....AA...... + ................ +} +# tile 373 (Kop Lieutenant,female) { ................ ....AA.......... @@ -3523,7 +7202,26 @@ Z = (195, 195, 195) ..AA....AA...... ................ } -# tile 184 (Kop Kaptain) +# tile 374 (Kop Kaptain,male) +{ + ................ + ....AA....C..... + ...AHHA...C..... + ...AHHA...C..... + ..AAAAAA..C..... + ...LLLL...C..... + ....LL....C..... + .HHAAAAHHAA..... + .AAAAHAAAACCC... + .AA.AHAAA.CPPP.. + ..AAAHAA.PCPPPP. + ....AAAAPPPAPP.. + .A.AAAAAAPAAA... + AAAAA.PAAAAA.... + ..AA....AA...... + ................ +} +# tile 375 (Kop Kaptain,female) { ................ ....AA....C..... @@ -3542,7 +7240,26 @@ Z = (195, 195, 195) ..AA....AA...... ................ } -# tile 185 (lich) +# tile 376 (lich,male) +{ + ................ + ................ + ...OOO.......... + ..AOAOO......... + ..OOOOO......... + ..OO.O.......... + .....PPP........ + ...OOPPP....AAA. + ..O.PPPPPA..AAA. + .O...PPPP.AAAAA. + ....O.PPPAAAA.A. + ......PPPAAA.A.. + .....OPAP.A..... + ...OOOA.OA...... + ......OOO....... + ................ +} +# tile 377 (lich,female) { ................ ................ @@ -3561,7 +7278,26 @@ Z = (195, 195, 195) ......OOO....... ................ } -# tile 186 (demilich) +# tile 378 (demilich,male) +{ + ................ + ................ + ...OOO.......... + ..AOAOO......... + ..OOOOO......... + ..OO.O.......... + .....PPP........ + ...OOPPP....AAA. + ..O.PPPPPA..AAA. + .O...PPPP.AAAAA. + ....L.PPPAAAA.A. + ......LPPAAA.A.. + .....LLAL.A..... + ...LLLA.LA...... + ......LLL....... + ................ +} +# tile 379 (demilich,female) { ................ ................ @@ -3580,7 +7316,26 @@ Z = (195, 195, 195) ......LLL....... ................ } -# tile 187 (master lich) +# tile 380 (master lich,male) +{ + ...H............ + ...HCH.H........ + ...HHHCH........ + ..AOAOHH........ + ..OOOOO......... + ..OO.O.......... + .....PPP........ + ...PPPPP....AAA. + ..PPPPPPPA..AAA. + .O..PPPPP.AAAAA. + ....OPPPPAAAA.A. + ......PPPAAA.A.. + .....OPAP.A..... + ...OOOA.OA...... + ......OOO....... + ................ +} +# tile 381 (master lich,female) { ...H............ ...HCH.H........ @@ -3599,7 +7354,26 @@ Z = (195, 195, 195) ......OOO....... ................ } -# tile 188 (arch-lich) +# tile 382 (arch-lich,male) +{ + ................ + ................ + ...OOO.......... + ..DODOO......... + ..OOOOO......... + H.OO.O.......... + A....PPP........ + A..OOPPP....AAA. + .AO.PPPPPA..AAA. + .O...PPPP.AAAAA. + .A..O.PPPAAAA.A. + ..A...PPPAAA.A.. + ..A..OPAP.A..... + ..AOOOA.OA...... + ......OOO....... + ................ +} +# tile 383 (arch-lich,female) { ................ ................ @@ -3618,7 +7392,26 @@ Z = (195, 195, 195) ......OOO....... ................ } -# tile 189 (kobold mummy) +# tile 384 (kobold mummy,male) +{ + ................ + ................ + ................ + ...N...N........ + ...NONONO....... + ...OAOAO.OP..... + ....ONN...A..... + ...ONODNA.AA.... + ..OLONNONAAA.A.. + ..NALONANAAAAA.. + ..NAOLOAOAAAAA.. + ....NOLAAAAAA... + ....NANAAAA..... + ...OOANOA....... + ................ + ................ +} +# tile 385 (kobold mummy,female) { ................ ................ @@ -3637,7 +7430,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 190 (gnome mummy) +# tile 386 (gnome mummy,male) { ................ ................ @@ -3656,7 +7449,49 @@ Z = (195, 195, 195) ................ ................ } -# tile 191 (orc mummy) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female gnome mummies are clean-shaven. Although of course not one +# hundred percent accurate, it's convenient visual shorthand. +# +# tile 387 (gnome mummy,female) +{ + ................ + ................ + ................ + ................ + ......G......... + .....GGFO....... + ....GGFFOOP..... + ....GDODF....... + .....ONO...AAA.. + ...NONOONOAAAA.. + ...OANLOAOAAAA.. + ....NNOLOAAAA... + ....NOANDAA..... + ....NOAOO.A..... + ................ + ................ +} +# tile 388 (orc mummy,male) +{ + ................ + ................ + ................ + .....OA......... + ....NOOP........ + ....DODPOP...... + ....OOOA........ + ..OOOOOOOA.AA... + ..OOOOOOO.AAA... + ..OAOOOAACCC.... + ..OAOOOCCAAA.... + ....OCCOAAAAAA.. + ...CCAOOAAAA.... + ..OOOAOOOA...... + ................ + ................ +} +# tile 389 (orc mummy,female) { ................ ................ @@ -3675,7 +7510,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 192 (dwarf mummy) +# tile 390 (dwarf mummy,male) +{ + ................ + ................ + ................ + ................ + ......B......... + .....BBEO....... + ....BBEEEOP..... + ....BDODE....... + .....ONO...AAA.. + ...NONOONOAAAA.. + ...OANLOAOAAAA.. + ....NNOLOAAAA... + ....NOANDAA..... + ....NOAOO.A..... + ................ + ................ +} +# tile 391 (dwarf mummy,female) { ................ ................ @@ -3694,7 +7548,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 193 (elf mummy) +# tile 392 (elf mummy,male) +{ + ................ + ................ + .........O...... + .......OOOP..... + ......OOOOP..... + ......OEOEAP.... + ......OOOOA..... + ......AOOA....A. + ......OAAO..AAA. + .....OOOOOOAAAA. + ....OALOOLAOAAA. + ....OADOOOAOAA.. + ......OOAOAA.A.. + .....OOA.OOA.... + ................ + ................ +} +# tile 393 (elf mummy,female) { ................ ................ @@ -3713,7 +7586,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 194 (human mummy) +# tile 394 (human mummy,male) +{ + ................ + ................ + ...ONNO......... + ...NNNNOP....... + ..PANAN.OPP..... + ..PNNNN......... + ..ONOONNP....... + .ONLNNOOO....... + .NJNOOOOO..AAA.. + .OJOOOODN.AAAA.. + .NJOLNOAOAAAAAA. + .OCNO.NKNAAAAA.. + .N.OO.OLAAAAAAA. + ...OOAOOAAA..... + ..NNN.NNNA...... + ................ +} +# tile 395 (human mummy,female) { ................ ................ @@ -3732,7 +7624,26 @@ Z = (195, 195, 195) ..NNN.NNNA...... ................ } -# tile 195 (ettin mummy) +# tile 396 (ettin mummy,male) +{ + .....NN..ONOO... + ...NNOOONNOOOO.. + ...NOOOONOOOOOO. + ...OFOFOLOFOFO.O + ...OOOOOLOOOOO.P + ...NOOOOLNNOOOA. + ...ONOOOLOOOOAAA + ..OOOONNNNNNNOAA + .ONNNNNNOONOOOOA + .ONODNNOOOOOOOOA + .NNAAONNONOAAOOA + .NOAAONOONLAAOOA + .OOO.ONOONOOOOAA + ..OO.NNOANOLOOAA + .....NOOANOOAAAA + ...OOOOO.OOOOKAA +} +# tile 397 (ettin mummy,female) { .....NN..ONOO... ...NNOOONNOOOO.. @@ -3751,7 +7662,26 @@ Z = (195, 195, 195) .....NOOANOOAAAA ...OOOOO.OOOOKAA } -# tile 196 (giant mummy) +# tile 398 (giant mummy,male) +{ + ......ONOOAA.... + ....ONNNOOOOA... + ....NNOOOOOOO... + ....NFFOOFFOOP.. + ....NONOOOOOAOP. + ....AONOOOOAAAP. + .....ANOOODAAAA. + ..OOOONOOONNNOAA + .ONNNNNOOOOOOOOA + .ONODNNLOOOOOOOA + .NNAAONOLNOAAOOA + .NOAAONOONLAAOOA + .OOO.ONOONOOOOAA + ..OO.NNOANOLOOAA + .....NOOANOOAAAA + ...OOOOO.OOOOKAA +} +# tile 399 (giant mummy,female) { ......ONOOAA.... ....ONNNOOOOA... @@ -3770,7 +7700,26 @@ Z = (195, 195, 195) .....NOOANOOAAAA ...OOOOO.OOOOKAA } -# tile 197 (red naga hatchling) +# tile 400 (red naga hatchling,male) +{ + ................ + ................ + ................ + ................ + ....K........... + ...KLK.......... + ...LLLA......... + ...ALAA......... + ...LALA......... + ...LLLA......... + ...LLLAA........ + ...LDLAA........ + ...IDDAAAAADA... + ...IDDDAAADDA... + ....IIDDDDDA.... + ................ +} +# tile 401 (red naga hatchling,female) { ................ ................ @@ -3789,7 +7738,26 @@ Z = (195, 195, 195) ....IIDDDDDA.... ................ } -# tile 198 (black naga hatchling) +# tile 402 (black naga hatchling,male) +{ + ................ + ................ + ................ + ................ + ....K........... + ...KLK.......... + ...LLLA......... + ...ALAA......... + ...LALA......... + ...LLLA......... + ...LLLA......... + ...LALAA........ + ...AAAPA..PAA... + ...AAAAPPPAAA... + ....AAAAAAAA.... + ................ +} +# tile 403 (black naga hatchling,female) { ................ ................ @@ -3808,7 +7776,26 @@ Z = (195, 195, 195) ....AAAAAAAA.... ................ } -# tile 199 (golden naga hatchling) +# tile 404 (golden naga hatchling,male) +{ + ................ + ................ + ................ + ................ + ....K........... + ...KLK.......... + ...LLLA......... + ...ALAA......... + ...LALA......... + ...LLLA......... + ...LLLAA........ + ...LHLAA........ + ...NHHAAAAAHA... + ...NHHHAAAHHA... + ....NNHHHHHA.... + ................ +} +# tile 405 (golden naga hatchling,female) { ................ ................ @@ -3827,7 +7814,26 @@ Z = (195, 195, 195) ....NNHHHHHA.... ................ } -# tile 200 (guardian naga hatchling) +# tile 406 (guardian naga hatchling,male) +{ + ................ + ................ + ................ + ................ + ....K........... + ...KLK.......... + ...LLLA......... + ...ALAA......... + ...LALA......... + ...LLLA......... + ...LLLAA........ + ...LFLAA........ + ...GFFAAAAAFA... + ...GFFFAAAFFA... + ....GGFFFFFA.... + ................ +} +# tile 407 (guardian naga hatchling,female) { ................ ................ @@ -3846,7 +7852,26 @@ Z = (195, 195, 195) ....GGFFFFFA.... ................ } -# tile 201 (red naga) +# tile 408 (red naga,male) +{ + ................ + ....KK.......... + ...KLLK......... + ...LLLLA........ + ...ALLAA........ + ...LAALA........ + ...LLLLA........ + ...LLLDA..AA.... + ...LDLDA.AAAA... + ...IDDDAAAIIA... + ...IDDDAIDDDIDA. + ...IDDDIDDDDDDDA + ...IDDDDDDAA.DDA + ....DDDDDA..DDA. + .....DDAA..DDA.. + ..........DA.... +} +# tile 409 (red naga,female) { ................ ....KK.......... @@ -3865,7 +7890,26 @@ Z = (195, 195, 195) .....DDAA..DDA.. ..........DA.... } -# tile 202 (black naga) +# tile 410 (black naga,male) +{ + ................ + ....KK.......... + ...KLLK......... + ...LLLLA........ + ...ALLAA........ + ...LAALA........ + ...LLLLA........ + ...LLLAA........ + ...LALAA..PPP... + ...AAAAPPPAAP... + ...AAAAPAAAAAAP. + ...AAAAAAAAAAAAP + ...AAAAAAAPP.AAP + ....AAAAAP..AAP. + .....AAPP..AAP.. + ..........AP.... +} +# tile 411 (black naga,female) { ................ ....KK.......... @@ -3884,7 +7928,26 @@ Z = (195, 195, 195) .....AAPP..AAP.. ..........AP.... } -# tile 203 (golden naga) +# tile 412 (golden naga,male) +{ + ................ + ....KK.......... + ...KLLK......... + ...LLLLA........ + ...ALLAA........ + ...LAALA........ + ...LLLLA........ + ...LLLHA..AA.... + ...LHLHA.AAAA... + ...NHHHAAANNA... + ...NHHHANHHHNHA. + ...NHHHNHHHHHHHA + ...NHHHHHHAA.HHA + ....HHHHHA..HHA. + .....HHAA..HHA.. + ..........HA.... +} +# tile 413 (golden naga,female) { ................ ....KK.......... @@ -3903,7 +7966,26 @@ Z = (195, 195, 195) .....HHAA..HHA.. ..........HA.... } -# tile 204 (guardian naga) +# tile 414 (guardian naga,male) +{ + ................ + ....KK.......... + ...KLLK......... + ...LLLLA........ + ...ALLAA........ + ..CLAALC........ + ..LLLLLL........ + ..CLLCLC..AA.... + ...CLLCA.AAAA... + ...GLFCAAAGGA... + ...GFFFAAFFFGFA. + ...GFFFGFFFFFFFA + ...GFFFFFFAA.FFA + ....FFFFFA..FFA. + .....FFAA..FFA.. + ..........FA.... +} +# tile 415 (guardian naga,female) { ................ ....KK.......... @@ -3922,7 +8004,26 @@ Z = (195, 195, 195) .....FFAA..FFA.. ..........FA.... } -# tile 205 (ogre) +# tile 416 (ogre,male) +{ + ................ + ................ + ....CLLLC....... + ..LCKKLKKCL..... + ...LAALAALJA.... + ...CLLLLLCJA.... + ....CAAACJAAA... + ....LDDDLAAAA... + ..CLJLLLKALCAA.A + .CLLAJJJJALLCAAA + .LLCLAAAALCLLAA. + .LAACLLLLCAALAA. + .LC.HHHBHHACLAAA + .LL.JJJJJJALLAAA + ....CJJJCLAAAAAA + ..LLLLL.LLLLLAA. +} +# tile 417 (ogre,female) { ................ ................ @@ -3941,7 +8042,7 @@ Z = (195, 195, 195) ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } -# tile 206 (ogre lord) +# tile 418 (ogre leader,male) { ................ ................ @@ -3960,7 +8061,26 @@ Z = (195, 195, 195) ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } -# tile 207 (ogre king) +# tile 419 (ogre leader,female) +{ + ................ + ................ + ....CLLLC....... + ..LCKKLKKCL..... + ...LAALAALJA.... + ...CLLLLLCJA.... + ....CLLLCJAAA... + ....LAAALAAAA... + ..JKJLLLKAKJAA.A + .CLKAJJJJAKLCAAA + .LLJKAAAAKJLLAA. + .LAAJKKKKJAALAA. + .LC.HHHBHHACLAAA + .LL.JJJJJJALLAAA + ....CJJJCLAAAAAA + ..LLLLL.LLLLLAA. +} +# tile 420 (ogre tyrant,male) { ...H..C..H...... ...HDCHCDH...... @@ -3979,7 +8099,48 @@ Z = (195, 195, 195) ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } -# tile 208 (gray ooze) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female ogre tyrants have slightly different crowns. +# +# tile 421 (ogre tyrant,female) +{ + ...HH.C.HH...... + ...HDCHCDH...... + ...HHHHHHH...... + ..LCKKLKKCL..... + ...LAALAALJA.... + ...CLLLLLCJA.... + ....CLLLCJAAA... + ....LAAALAAAA... + ..JKJLLLKAKJAA.A + .CJKAJJJJAKJCAAA + .LJJKAAAAKJJLAA. + .LAAJKKKKJAALAA. + .LC.HHHBHHACLAAA + .LL.JJJJJJALLAAA + ....CJJJCLAAAAAA + ..LLLLL.LLLLLAA. +} +# tile 422 (gray ooze,male) +{ + ................ + ................ + ................ + .....PBPA....... + ...PBBBPBA...... + ..BBNNBPPBAA.... + .BBNNPPPBBPAAA.. + PBBBPPPBPBBAAA.. + BBBPBPPPPPBPAAA. + BBPBPPPPPPPBAAA. + PBPPBPPPBBPPAAA. + .PBBPPPBAAPPPAA. + ...PBBBAAAKPPJ.. + ........ACPPAK.. + .........KCCCJ.. + ................ +} +# tile 423 (gray ooze,female) { ................ ................ @@ -3998,7 +8159,26 @@ Z = (195, 195, 195) .........KCCCJ.. ................ } -# tile 209 (brown pudding) +# tile 424 (brown pudding,male) +{ + ................ + ................ + ................ + ................ + ............J... + ....JKKJJJ..JJ.. + ...KKKCJJJJJ.... + ..KKNNJNNJJJ.... + ..KJANJANJJJA... + ..KKJJJJJCJJAA.. + ..JKJJCJJJJJAA.. + ...JJJJJJJJAAA.. + ....JJJJJJAAA... + .....AAAAAAA.... + ................ + ................ +} +# tile 425 (brown pudding,female) { ................ ................ @@ -4017,7 +8197,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 210 (green slime) +# tile 426 (green slime,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ............G... + .....G......G..G + .G....G..G.NGN.G + ..NG.NGGNGGGGGGG + ..GGNGGNGGGFGGF. + GGNGGGGGGGGGFF.G + .NGGGGGFGFG..... + NGGGGFGGFG.G..GF + NGGFGGF..GF..... + ..GGF..GGF..G... +} +# tile 427 (green slime,female) { ................ ................ @@ -4036,7 +8235,26 @@ Z = (195, 195, 195) NGGFGGF..GF..... ..GGF..GGF..G... } -# tile 211 (black pudding) +# tile 428 (black pudding,male) +{ + ........A....... + ........AA...... + .....AAA........ + ....AAAAA....... + ....CACAA....... + ....DADAA....... + ....AAAAA....... + ....AAAAA....... + ....AAAAA....... + .....AAAAA...... + .....AAAAA...... + ......AAAAA..... + ......AAAAAA.... + .......AAAAAA.A. + ........AAAAAAAA + ..........AAAA.. +} +# tile 429 (black pudding,female) { ........A....... ........AA...... @@ -4055,7 +8273,7 @@ Z = (195, 195, 195) ........AAAAAAAA ..........AAAA.. } -# tile 212 (quantum mechanic) +# tile 430 (quantum mechanic,male) { ................ ......LLLL...... @@ -4074,7 +8292,90 @@ Z = (195, 195, 195) ....NAAEBAANN... ................ } -# tile 213 (rust monster) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female quantum mechanics have a different hairstyle and no beard. +# +# tile 431 (quantum mechanic,female) +{ + ................ + ......JJJJJ..... + ...FGGCLCGGF.... + ...GNNGLGNNGJ... + B.BGANGGGANGL... + B.BFGGCLCGGFLJ.. + BIB.JCLLLCCLJJ.. + BILN.LLAALLAAAA. + BILNN.LLLLCAAAA. + BIB.NNCCCCNAAA.. + BIB.BNNNONNNAA.. + .B...NNNONNLAA.. + .....NBEBENA.A.. + .....NBEBENN.... + ....NAAEBAANN... + ................ +} +# Note from contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Male and female genetic engineers look the same, because the genetic +# engineer tile is perfect. +# +# tile 432 (genetic engineer,male) +{ + ................ + ......LLLL...... + ...LAALLLAAL.... + ...LNNLLLNNLL... + ...LANLLLANLL... + ...LLLLLLLLLL... + .....CLLLCCL.... + ..LN.LLAALL..... + ..LNN.LLLLJ..... + ..A.NNLLLLN..... + .A.ABNNNONNN.... + .AA..NNNONNL.... + .A.A.NPEPENA.... + .AA..NPEPENN.... + ..AANAAEPAANN... + ................ +} +# tile 433 (genetic engineer,female) +{ + ................ + ......LLLL...... + ...LAALLLAAL.... + ...LNNLLLNNLL... + ...LANLLLANLL... + ...LLLLLLLLLL... + .....CLLLCCL.... + ..LN.LLAALL..... + ..LNN.LLLLJ..... + ..A.NNLLLLN..... + .A.ABNNNONNN.... + .AA..NNNONNL.... + .A.A.NPEPENA.... + .AA..NPEPENN.... + ..AANAAEPAANN... + ................ +} +# tile 434 (rust monster,male) +{ + ................ + ....EEEE........ + ...EEHEHE....... + ...EEEAEE....... + ...EEPAPE....... + ...EPEAEP...E... + ....EEEE.AAEE... + ....EEEEEAAEEE.. + ...EEEEEEEAEAEE. + ..EEEEEEAAAAE... + ..EEAEEEEAEEEA.. + ..AAEEEEEEEEEAA. + ....AEEEEEEEAAA. + .....EEEEEAA..A. + ......AAAA...... + ................ +} +# tile 435 (rust monster,female) { ................ ....EEEE........ @@ -4093,7 +8394,26 @@ Z = (195, 195, 195) ......AAAA...... ................ } -# tile 214 (disenchanter) +# tile 436 (disenchanter,male) +{ + ................ + ....PPPP........ + ...PPDPDP....... + ...PPPAPP....... + ...PPOAOP....... + ...POPAPO...P... + ....PPPP.AAPP... + ....PPPPPAAPPP.. + ...PPPPPPPAPAPP. + ..PPPPPPAAAAP... + ..PPAPPPPAPPPA.. + ..AAPPPPPPPPPAA. + ....APPPPPPPAAA. + .....PPPPPAA..A. + ......AAAA...... + ................ +} +# tile 437 (disenchanter,female) { ................ ....PPPP........ @@ -4112,7 +8432,26 @@ Z = (195, 195, 195) ......AAAA...... ................ } -# tile 215 (garter snake) +# tile 438 (garter snake,male) +{ + ................ + ................ + ................ + ....KKA......... + ...NAOKA........ + ...KKAKA........ + ...KKAKA....KA.. + ....APKAP..KAPP. + .....PKAPP.KAP.. + .....KAAP..KAP.. + ....KAAP..KAAP.. + ....KAAPPKAAP... + ....KAAKKAAP.... + .....KAAAAP..... + ................ + ................ +} +# tile 439 (garter snake,female) { ................ ................ @@ -4131,7 +8470,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 216 (snake) +# tile 440 (snake,male) +{ + ................ + ................ + ................ + ....KKA......... + ...NAOJA........ + ...KKJAJ........ + ...KKAAJ....KK.. + ...FAAKJ...KJAA. + ..FAFAKJAA.KJA.. + .....KJAA..KJA.. + ....KJAA..KJJA.. + ....KJAAAKJJA... + ....KJJJJJJA.... + .....KJJJJA..... + ................ + ................ +} +# tile 441 (snake,female) { ................ ................ @@ -4150,7 +8508,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 217 (water moccasin) +# tile 442 (water moccasin,male) +{ + ................ + ................ + ................ + ....AAA......... + ...AAAAA...AA... + ...OAOAAA.AA.... + ...AAA.AA.AA.... + ...DA..AA.AA.... + ..D.D.AAA..AA... + .....AAA...AA... + .....AAA...AA... + ....AAA...AAA... + ....AAAAAAAA.... + ....AAAAAAA..... + .....AAAAA...... + ................ +} +# tile 443 (water moccasin,female) { ................ ................ @@ -4169,7 +8546,26 @@ Z = (195, 195, 195) .....AAAAA...... ................ } -# tile 218 (python) +# tile 444 (python,male) +{ + ................ + ................ + ................ + ...KKKA.....JJ.. + ...GAGJA...JJJ.. + ..JKKJAJ..KJJ... + ..KKKAJJ..KJJ.AA + ..KKAAKJA.KKJAA. + .....AKJAA.KJAA. + ....JKJAA..KJJA. + ...JJJAA..KJJJA. + ...JJJAAAKJJJA.. + ...JJJJJJJJJAA.. + ....JJJJJJJAA... + .....JJJJJAA.... + ................ +} +# tile 445 (python,female) { ................ ................ @@ -4188,7 +8584,26 @@ Z = (195, 195, 195) .....JJJJJAA.... ................ } -# tile 219 (pit viper) +# tile 446 (pit viper,male) +{ + ................ + ................ + ................ + ....AAA......... + ...AAAAA...AAA.. + ...OAAAAA.AA.AA. + ...AA..AA.AA.AA. + ...D...AA.AA..A. + ......AAA..AA.A. + ......AA...AA... + .....AAA...AA... + .....AA...AAA... + .....AA..AAA.... + .....AAAAAA..... + ......AAAA...... + ................ +} +# tile 447 (pit viper,female) { ................ ................ @@ -4207,7 +8622,7 @@ Z = (195, 195, 195) ......AAAA...... ................ } -# tile 220 (cobra) +# tile 448 (cobra,male) { ................ ................ @@ -4226,7 +8641,45 @@ Z = (195, 195, 195) .....AAAAAAAAA.. ................ } -# tile 221 (troll) +# tile 449 (cobra,female) +{ + ................ + ................ + ................ + ....AAA......... + ...AAAAAA....... + ..PA..AAAA...... + ..A..AAAAA..AA.. + ..D..AAAAA....A. + ......AAA.....A. + ......AA..AAAA.. + .....AA..AA..... + ....AA...AA..... + ....AA....AAAA.. + ....AAA......AA. + .....AAAAAAAAA.. + ................ +} +# tile 450 (troll,male) +{ + ................ + ..AAAAAA........ + AAAANANA........ + .AAKKKJJA....... + AAAKAAAKA....... + AKAKAAAKAA...... + KJJAKKKAJKA..... + KJAJAAAJJJA..... + KJAJKKJJKJA..... + .KJJAFGFJJAAAA.. + ..KJA.PFJAAAA... + ...AFAGFAAAAAA.. + ...GFAGP.AA.AA.. + ..KJJAKJAA.AA... + ..KJA..KA....... + ................ +} +# tile 451 (troll,female) { ................ ..AAAAAA........ @@ -4245,7 +8698,26 @@ Z = (195, 195, 195) ..KJA..KA....... ................ } -# tile 222 (ice troll) +# tile 452 (ice troll,male) +{ + ................ + ..OONOOO........ + NONOAOAOO....... + .NOKKKJJO....... + NOJKAAAKOO...... + OKJKAAAKAO...... + KJJAKKKAJKA..... + KJAJAAAJJJA..... + KJAJKKJJKJA..... + .KJJAEBEJJAAAA.. + ..KJA.PEJAAAA... + ...AEABEAAAAAA.. + ...BEABP.AA.AA.. + ..KJJAKJAA.AA... + ..KJA..KA....... + ................ +} +# tile 453 (ice troll,female) { ................ ..OONOOO........ @@ -4264,7 +8736,26 @@ Z = (195, 195, 195) ..KJA..KA....... ................ } -# tile 223 (rock troll) +# tile 454 (rock troll,male) +{ + ................ + ...AAAAA........ + .AAANANAAAA..... + .AAKKKJJAA...... + AAAKAAAKAAAA.... + AKAKAAAKAAA..... + KJJAKKKAJKAA.... + KJAJAAAJJJA..... + KJAPAKJJKJA..... + PKJPPAGFJJAAAA.. + PPPPPAFFJAAAA... + .PPPAAGFAAAAAA.. + ...AFAGF.AA.AA.. + ..KJJAKJAA.AA... + ..KJA..KA....... + ................ +} +# tile 455 (rock troll,female) { ................ ...AAAAA........ @@ -4283,7 +8774,26 @@ Z = (195, 195, 195) ..KJA..KA....... ................ } -# tile 224 (water troll) +# tile 456 (water troll,male) +{ + ................ + ...AAAAA........ + ..AANANAA....... + .AAKKKJJAA...... + .AAKAAAKAA...... + .KAKAAAKAA...... + KJJAKKKAJKA..... + KJAJAAAJJJA..... + KJAJKKJJKJA..... + .KJJAEBEJJAAAA.. + ..KJA.PEJAAAA... + ...AEABEAAAAAA.. + ...BEABP.AA.AA.. + ..KJJAKJAA.AA... + ..KJA..KA....... + ................ +} +# tile 457 (water troll,female) { ................ ...AAAAA........ @@ -4302,7 +8812,26 @@ Z = (195, 195, 195) ..KJA..KA....... ................ } -# tile 225 (Olog-hai) +# tile 458 (Olog-hai,male) +{ + ...PPPPP........ + ..PPAAAPP....... + ..PANANAP....... + ..PAAAAAP....... + .PPAAAAAPP...... + PPPAAAAAPPP..... + AAPPAAAPPAA..... + AAAPPPPPAAA..... + AAAPPPPPAAA..... + .AAAAPPPAAAPPP.. + PONNNNNNAACPP... + ...APAPPAPPPPP.. + ...PPAPP.PP.PP.. + ..AAAAAAAP.PP... + ..AAA.AAA....... + ................ +} +# tile 459 (Olog-hai,female) { ...PPPPP........ ..PPAAAPP....... @@ -4321,7 +8850,26 @@ Z = (195, 195, 195) ..AAA.AAA....... ................ } -# tile 226 (umber hulk) +# tile 460 (umber hulk,male) +{ + ................ + ...AAAAA........ + ..AAAAAAA....... + .ADADADADA...... + .AAAAAAAAA.A.... + .AAAOAOAAA.AA... + .A.AOAOA.AAA.... + .A.AAAAAPAA..... + .AAAAAAAP....... + .A.AAAAA.PPPPPP. + ...AA.AA.PPPPP.. + ...AA.AAPPPPPPP. + ...AAPAAPPPP.... + ..AAAPAAAPP..... + .AAAP..AAP...... + ................ +} +# tile 461 (umber hulk,female) { ................ ...AAAAA........ @@ -4340,7 +8888,26 @@ Z = (195, 195, 195) .AAAP..AAP...... ................ } -# tile 227 (vampire) +# tile 462 (vampire,male) +{ + ................ + ................ + .....AAA........ + ....AAOAA....... + .ADDAGAGADA..... + ..ADALLOAD...... + .AAAAAAAAA...... + ..AAAAAAAA...... + ...AAAAAAA...... + ..ADAAAAAAPPPPP. + ..ADDAAAAAPPPP.. + ..AAAAAAAAPPP... + .....AAPAAPP.... + ....AAP..AP..... + ................ + ................ +} +# tile 463 (vampire,female) { ................ ................ @@ -4359,26 +8926,64 @@ Z = (195, 195, 195) ................ ................ } -# tile 228 (vampire lord) +# tile 464 (vampire leader,male) +{ + ................ + .....AAAA....... + .N..AAOOAA...... + .NDDAGAAGADA.... + .NADALLLOAD..... + AAAAAAAAAAA..... + AAAAAAAAAAA..... + .AAAAAAAAAA..... + .NAAAAAAAAA..... + .N.AAAAAAAAPPPPP + .NADAAAAAAAPPPPP + .NADDAAAAAAPPPP. + .NAAAAAAAAAPPP.. + .N...AAAPAAPP... + .N..AAPP..AP.... + ................ +} +# tile 465 (vampire leader,female) +{ + ................ + .....AAAA....... + .N..AAOOAA...... + .NDDAGAAGADA.... + .NADALLLOAD..... + AAAAAAAAAAA..... + AAAAAAAAAAA..... + .AAAAAAAAAA..... + .NAAAAAAAAA..... + .N.AAAAAAAAPPPPP + .NADAAAAAAAPPPPP + .NADDAAAAAAPPPP. + .NAAAAAAAAAPPP.. + .N...AAAPAAPP... + .N..AAPP..AP.... + ................ +} +# tile 466 (vampire mage,male) { ................ - .....AAAA....... - .N..AAOOAA...... - .NDDAGAAGADA.... - .NADALLLOAD..... - AAAAAAAAAAA..... - AAAAAAAAAAA..... - .AAAAAAAAAA..... - .NAAAAAAAAA..... - .N.AAAAAAAAPPPPP - .NADAAAAAAAPPPPP - .NADDAAAAAAPPPP. - .NAAAAAAAAAPPP.. - .N...AAAPAAPP... - .N..AAPP..AP.... + ................ + .....AAA........ + ....AAOAA....... + .ADDAGAGADA..... + ..ADALLOAD...... + .AAAA.A.AA...... + ..AAAACAAA...... + ...AAADAAA...... + ..ADAAAAAAPPPPP. + ..ADDAAAAAPPPP.. + ..AAAAAAAAPPP... + .....AAPAAPP.... + ....AAP..AP..... + ................ ................ } -# tile 229 (vampire mage) +# tile 467 (vampire mage,female) { ................ ................ @@ -4397,7 +9002,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 230 (Vlad the Impaler) +# tile 468 (Vlad the Impaler,male) +{ + ................ + ..N..AAAA....... + ADNDAAOOAADDDA.. + .ANDAGAAGADDA... + ..NDALLLOADA.... + ..NAAAAAAAAAAAAA + .HHHDAAAAADDDDDA + HEHEHJAAAADDDAA. + LLLLLJAAAADDAAPP + .LLLJAAAAADDAPPP + ..NJDAAAAADAPPPP + .ANDDAAAAAAAPPPP + .ANAAAAAAAAPPPP. + ..N..AAAPAAPPP.. + ..N.AAPP..AP.... + ................ +} +# tile 469 (Vlad the Impaler,female) { ................ ..N..AAAA....... @@ -4416,7 +9040,7 @@ Z = (195, 195, 195) ..N.AAPP..AP.... ................ } -# tile 231 (barrow wight) +# tile 470 (barrow wight,male) { ................ ................ @@ -4435,7 +9059,51 @@ Z = (195, 195, 195) .J.....LLAA..... ................ } -# tile 232 (wraith) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female barrow wights look like old grandmothers with flyaway hair. I +# kept the hair color the same and used a similar quantity of pixels so +# that they look similar enough to the males that you can tell they are +# barrow wights. +# +# tile 471 (barrow wight,female) +{ + ................ + .......OOOOO.... + ..OOOOOOO....... + .ODLDLOO.OOO.... + .OLLLLOOOOOOO... + .OLJLLOPOO...... + .OPLLL.POOOAAAA. + ..PPP.PP.AAAAAA. + .LPPPPPP.PAAAA.. + .JJ.PPPP.PAAAA.. + .J...PPL.PPAAA.. + .J...PPPPPPAAA.. + .J...PPPPPPPAA.. + .J..LLPPPPPPA... + .J.....LLAA..... + ................ +} +# tile 472 (wraith,male) +{ + ................ + ................ + ...PPPPP........ + ...PAAPPP....... + ....PAAPP....... + ....PAAPP....... + ..PP.PPP.P...... + .OLAPPP.PP...... + ..AAPPPPAP..AAA. + ..PPPPPOLPAAAAA. + ...A.PPAAAAPPA.. + .....PPAPPPPA... + ......PPPPA..... + ................ + ................ + ................ +} +# tile 473 (wraith,female) { ................ ................ @@ -4454,7 +9122,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 233 (Nazgul) +# tile 474 (Nazgul,male) +{ + ................ + ................ + ...PPPPP........ + ...PAAPPP....... + ....PAAPP....... + ....PAAPP....... + ..PP.PPP.P...... + .OLAPPP.PP...... + .OPAPPPPAP..AAA. + ..PAPPPPAP..AAA. + ..PA.PPPLP..AAA. + ..PP.PPOLPAAAAA. + ...AAPPOAAAPPA.. + .....PPAPPPPA... + ......PPPPA..... + ................ +} +# tile 475 (Nazgul,female) { ................ ................ @@ -4473,7 +9160,26 @@ Z = (195, 195, 195) ......PPPPA..... ................ } -# tile 234 (xorn) +# tile 476 (xorn,male) +{ + ................ + ................ + ................ + ...OB.OP.BP..... + ...BBBBPPPP..... + ...B............ + ...DDBB.BDDA.A.. + ...DDBB.PDDAAAA. + ...B.......AAAA. + ...BOB.BPP.AAAA. + ...BBB.PPP.AAAA. + ...B.......AAA.. + ...BOBBPPBPAA... + ...BO.BP.PPA.... + ................ + ................ +} +# tile 477 (xorn,female) { ................ ................ @@ -4492,7 +9198,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 235 (monkey) +# tile 478 (monkey,male) +{ + ................ + ................ + ................ + ................ + ................ + .......KKA...... + ......KLLJA..... + ......KLLJA..... + .......KJA...... + .....KKKKKJAA... + ....KJKLLJJJAA.. + ....LAKLLJALAA.. + ......KJJJAAAA.. + ......JAAJAAA... + .....JJA.JJA.... + ................ +} +# tile 479 (monkey,female) { ................ ................ @@ -4511,7 +9236,26 @@ Z = (195, 195, 195) .....JJA.JJA.... ................ } -# tile 236 (ape) +# tile 480 (ape,male) +{ + ................ + ................ + ......KKKJ...... + .....JJJJJJ..... + ....KCELECJJ.AA. + ....KLLLLCAJAAAA + ...KKCLACCAJJAAA + ..KKKKCCCAJKJJAA + ..KKAKJAAJJAJJAA + ..KAAKJJJJJAAJAA + ..LC.KJJJJJKCLAA + ..LL.CJJAKLJLLAA + .....CLJACLJAAAA + ...LLLLJACLLLKA. + ................ + ................ +} +# tile 481 (ape,female) { ................ ................ @@ -4530,7 +9274,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 237 (owlbear) +# tile 482 (owlbear,male) +{ + ................ + ....K.....K..... + ....CK...KK..... + ....CKKKKKK..... + ...KOOOKOOOK.... + ...KOOOKOOOKA..A + ...KOOAJAOOKAAAA + ..CKCJJHJJKAKAAA + .CKKKCKLKKAJJKAA + .KJJJJCKKJJJJJAA + .KJJJPAKJPJJJJAA + ..KJJJAKJJJJJAAA + ...JJPAKJPJJAAA. + ...JAAJAJAAJAA.. + ...PJPJAJPJPA... + ................ +} +# tile 483 (owlbear,female) { ................ ....K.....K..... @@ -4549,7 +9312,26 @@ Z = (195, 195, 195) ...PJPJAJPJPA... ................ } -# tile 238 (yeti) +# tile 484 (yeti,male) +{ + ................ + ....BNNN........ + ...BNANAP....... + ..BNNNNNNP...... + ..NNNADANN...... + ..NNNNNNPN...... + ..N.NNBPPNP..... + ..N.NNNNANP..AA. + ..NNBNNNPN.AAAA. + ....NNNNP.KAAA.. + ....NN.NPAKKAA.. + ....NB.NPAACKAA. + ....NNANPAAKKJA. + ...BNNANNPAACKA. + ..BNNA..NNA..... + ................ +} +# tile 485 (yeti,female) { ................ ....BNNN........ @@ -4568,7 +9350,26 @@ Z = (195, 195, 195) ..BNNA..NNA..... ................ } -# tile 239 (carnivorous ape) +# tile 486 (carnivorous ape,male) +{ + ................ + ................ + ......KKKJ...... + .....JJJJJJ..... + ....KCELECJJ.AA. + ....KLLLLCAJAAAA + ...KKCAAACAJJAAA + ..KKKCDDDCAKJJAA + ..KKAKCCCAJAJJAA + ..KAAKJAAJJAAJAA + ..LC.AJJJJJKCLAA + ..LLDDAJAKLJLLAA + ...DDALJACLJAAAA + ..DDALLJACLLLKA. + ................ + ................ +} +# tile 487 (carnivorous ape,female) { ................ ................ @@ -4587,7 +9388,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 240 (sasquatch) +# tile 488 (sasquatch,male) +{ + ................ + ....CCCCC....... + ...CGAJGAJ...... + ..CKKKKJJJ...... + ..CKKAAAKJJ..... + .CKKKAAAKKJ..... + .CKJKKKKKKKJ.... + .CKAJJJJJAKJ.... + .CKAJKKKJAKJ.AA. + .CKJAJKJACKJAAAA + .CKJAJJJACKJAAA. + ..J.AJAKKAJAAAAA + ...CKJAKKJAAAAA. + .KCKJJACKJKJAA.. + .CJJJKACKJJKA... + ................ +} +# tile 489 (sasquatch,female) { ................ ....CCCCC....... @@ -4606,7 +9426,26 @@ Z = (195, 195, 195) .CJJJKACKJJKA... ................ } -# tile 241 (kobold zombie) +# tile 490 (kobold zombie,male) +{ + ................ + ................ + ................ + ...N...N........ + ...NGFBN........ + ...GABAB........ + ....GBFA..A..... + ...GBABFA.AA.... + ..GFBBBIKAAA.A.. + ..BAFBFFEAAAAA.. + ..BAFBFFAAAAAA.. + ....FBFAAAAAA... + ....BABAAAA..... + ...BBABBA....... + ................ + ................ +} +# tile 491 (kobold zombie,female) { ................ ................ @@ -4625,7 +9464,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 242 (gnome zombie) +# tile 492 (gnome zombie,male) { ................ ................ @@ -4644,7 +9483,45 @@ Z = (195, 195, 195) ................ ................ } -# tile 243 (orc zombie) +# tile 493 (gnome zombie,female) +{ + ................ + ................ + ................ + ................ + ......G......... + .....GFF........ + ....GGFFF....... + ....GDFDF....... + .....GFF...AAA.. + ...FGFFFEGAAAA.. + ..GAAGFFFAGAAA.. + ....AKNKFAAAA... + ....FGAFFAA..... + ....GFAFG.A..... + ................ + ................ +} +# tile 494 (orc zombie,male) +{ + ................ + ................ + ................ + .....OA......... + ....NOPA........ + ....GPGA........ + .....PFA........ + ..KCCAKKKA.AA... + .BBPCKJ.BBAAA... + BB.AGGFAABBA.... + B..AJJPAAABA.... + ....BAPPPAAAAA.. + ...BJAAEPAAA.... + ..BPPAAAPP...... + ................ + ................ +} +# tile 495 (orc zombie,female) { ................ ................ @@ -4663,7 +9540,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 244 (dwarf zombie) +# tile 496 (dwarf zombie,male) +{ + ................ + ................ + ................ + ................ + ......B......... + .....BEE........ + ....BBEEE....... + ....BFFFE....... + .....PFP...AAA.. + ...BBPPPEEAAAA.. + ..FBABPEAEAAAA.. + ..F.EBBEFAAAA... + ....EBAEEAA..... + ....BEAEB.A..... + ................ + ................ +} +# tile 497 (dwarf zombie,female) { ................ ................ @@ -4682,7 +9578,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 245 (elf zombie) +# tile 498 (elf zombie,male) +{ + ................ + ................ + .........G...... + .......GGF...... + ......GGGGA..... + ......FEFEA..... + ......FFFFA..... + ......AFDA....A. + ......GAAG..AAA. + ....FFGGGFFFAAA. + ...FAAAGFAAAFAA. + .....AGGGFAAAA.. + ......GFAFAA.A.. + .....KDA.FKA.... + ................ + ................ +} +# tile 499 (elf zombie,female) { ................ ................ @@ -4701,7 +9616,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 246 (human zombie) +# tile 500 (human zombie,male) +{ + ......AAA....... + .....FFGAA...... + .....AGAFA...... + .....FFGFA...... + ....FKF..JJ..... + ....JJJFJKJ..... + ...FJ.KJJAKJ.... + ..FK..KFJFFJ.... + ..G...KKJG...... + .....BP.BPAAAAA. + .....FPAPFAAAA.. + .....BFABFAAAA.. + .....PFABPAA.... + .....BFABFA..... + ....GGAGGA...... + ................ +} +# tile 501 (human zombie,female) { ......AAA....... .....FFGAA...... @@ -4720,7 +9654,26 @@ Z = (195, 195, 195) ....GGAGGA...... ................ } -# tile 247 (ettin zombie) +# tile 502 (ettin zombie,male) +{ + ....NN..ONOP.... + ..NNOOPNNOOPP... + ..NFF..NFF..P... + ..ADFFDADFFDA... + ..AFFFFAFFFFA... + ..AFAAFAFAAFAA.. + ..AFFFFAFFFFAAA. + ..GIIIIJJJIIIGAA + .GFFFIIIIIIFFFGA + .GFFFFIIIIFFFFFA + .FFAAFIIIIFAAFFA + .FFAAIIIIIIAAFFA + .FFF.IIFFIIAGFAA + ..FF.GFAAGFAFFAA + .....GFAAGFAAAAA + ...FFFFA.GFFFFAA +} +# tile 503 (ettin zombie,female) { ....NN..ONOP.... ..NNOOPNNOOPP... @@ -4739,7 +9692,26 @@ Z = (195, 195, 195) .....GFAAGFAAAAA ...FFFFA.GFFFFAA } -# tile 248 (ghoul) +# tile 504 (ghoul,male) +{ + ......AAA....... + .....OOOAA...... + .....DODOA...... + .....OOOOA...... + ....PPOOOPP..... + ....PPPPPPP..... + ...PP.PPPAPP.... + ..PP..PPPOOP.... + ..O...PPPO...... + .....PP.PPAAAAA. + .....PPAPPAAAA.. + .....PPAPPAAAA.. + .....PPAPPAA.... + .....PPAPPA..... + ....OOAOOA...... + ................ +} +# tile 505 (ghoul,female) { ......AAA....... .....OOOAA...... @@ -4758,7 +9730,26 @@ Z = (195, 195, 195) ....OOAOOA...... ................ } -# tile 249 (giant zombie) +# tile 506 (giant zombie,male) +{ + ......JJJJAA.... + ....JJJJJJJJA... + ....JJFFFFJJA... + ....JDDFFDDJA... + ....JFFFFFFJA... + ....AFFAAFFAAA.. + .....AFFFFJAAAA. + ..GGFFJJJJFFGGAA + .GFFFGGFFFFFFFCA + .FFFKFFFFFFKFFFA + FFFAAFFFFFFAAFFA + FFAA.JJJKKJAAFFA + FFA..JJJJJKAGFAA + .....GFAGFFAFFAA + ....GFFAGFFAAAAA + ...GFFAAGFFFAAAA +} +# tile 507 (giant zombie,female) { ......JJJJAA.... ....JJJJJJJJA... @@ -4777,7 +9768,26 @@ Z = (195, 195, 195) ....GFFAGFFAAAAA ...GFFAAGFFFAAAA } -# tile 250 (skeleton) +# tile 508 (skeleton,male) +{ + ................ + ................ + ...OOO.......... + ..AOAOO......... + ..OOOOO......... + ..OO.O.......... + ......O......... + ....OOOOO...AAA. + ...OA.OOOA..AAA. + ..OA.OAAO.AAAAA. + ....OA.OOOAAA.A. + ......OOOAAA.A.. + .....O.AO.A..... + ...OOOA.OA...... + ......OOO....... + ................ +} +# tile 509 (skeleton,female) { ................ ................ @@ -4796,7 +9806,26 @@ Z = (195, 195, 195) ......OOO....... ................ } -# tile 251 (straw golem) +# tile 510 (straw golem,male) +{ + ......LJ........ + ......LJHJ...... + ....HJLJH...A... + ....AAAAAL.....A + ....DAADAL.A.AA. + ....LJHJL..AAAA. + ....LLHJLHHCHHL. + ...HHLJL.AJLJL.A + .HHJJLLLLAAA.AA. + ..JL..LALHAAAAAA + .LL..CJLHJHAAAAA + .....HJLAHJHAAA. + .....HJAACALHAAA + ....CJLAAJHALHA. + ....HALA.AHAAL.. + ..........L..... +} +# tile 511 (straw golem,female) { ......LJ........ ......LJHJ...... @@ -4815,7 +9844,26 @@ Z = (195, 195, 195) ....HALA.AHAAL.. ..........L..... } -# tile 252 (paper golem) +# tile 512 (paper golem,male) +{ + ................ + .......OA....... + .....NNNOA...... + .....ONNNOA..... + ......ONNOA..... + .......NOA...... + ..NNOA.NOA...... + ..NONOAOAONNOA.. + ..OAOANNOAOOOA.. + ......NNNOAAAAA. + ......ONOAAAAAA. + .......OOAAAAAA. + .....NOAAOAAAAA. + .....NOA..NOAA.. + ....OOA...OOA... + ................ +} +# tile 513 (paper golem,female) { ................ .......OA....... @@ -4834,7 +9882,26 @@ Z = (195, 195, 195) ....OOA...OOA... ................ } -# tile 253 (rope golem) +# tile 514 (rope golem,male) +{ + ................ + ................ + ......OOO....... + .....O...O...... + .....O...O...AA. + .OO...O..O..A..A + O..O...LL..OO..A + ...O...LOOO.AOA. + ....OOOOOAAAAO.. + .......OO..AA.A. + .......LO.AA...A + ......O..OOAA..A + ....OO..A..O.A.. + ...O..AA...O.A.. + ...O.A....OAA... + ....OA.......... +} +# tile 515 (rope golem,female) { ................ ................ @@ -4853,7 +9920,26 @@ Z = (195, 195, 195) ...O.A....OAA... ....OA.......... } -# tile 254 (gold golem) +# tile 516 (gold golem,male) +{ + ................ + ......HNH....... + ......DND...N... + ......HNH...JC.. + ......HNH...NC.. + ...HHHAAAAHANC.. + ..HNJNHNHNJNAC.A + ..HHHHHHHHHHHA.A + .NCACCCCCCCCA..A + .HH.AAAAAAAAA.AA + .NH.ANC.AHNC.AAA + .NJ.AHC.AHHC.AAA + ..H.ANC.AHNC.AAA + ....HJC.AHJC.AA. + H...HNC.AHNC.A.H + ..H............. +} +# tile 517 (gold golem,female) { ................ ......HNH....... @@ -4872,7 +9958,26 @@ Z = (195, 195, 195) H...HNC.AHNC.A.H ..H............. } -# tile 255 (leather golem) +# tile 518 (leather golem,male) +{ + ......KKKK...... + .....KHKHJ...... + ....KAKKJJA..... + ...KKAJJJJAJ.... + ..KKJJAJAAKJJ... + .KKKJJAAKKKJJJ.. + ..KKJJJAKKJJJJ.. + ...KKJJJA.AAA.A. + ....AAAA.KJAAAA. + ....KJAAAKKAAAAA + ...KJJAA.KJJAAA. + ...KKJA..KKJAAA. + ..KKJJJAKKJJJAA. + ..KKKJJAKKKJJA.. + ...KJJA..KJJA... + ....KA....KA.... +} +# tile 519 (leather golem,female) { ......KKKK...... .....KHKHJ...... @@ -4891,7 +9996,26 @@ Z = (195, 195, 195) ...KJJA..KJJA... ....KA....KA.... } -# tile 256 (wood golem) +# tile 520 (wood golem,male) +{ + ................ + ......KCKJ...... + ......HCHJ..C... + ......KCKJ..CK.. + ......KCKJ..CKJ. + ...KKKAAAAKACKJ. + ..KCCCCCCCCCAKJA + ..KKKKKKKKKKKAJA + .CJAJJJJJJJJA..A + .CKJAAAAAAAAA.AA + .CKJACKJAKCKJAAA + .CKJACKJAKCKJAAA + ..KJACKJAKCKJAAA + ....KCKJAKCKJAA. + ....KCKJAKCKJA.. + ................ +} +# tile 521 (wood golem,female) { ................ ......KCKJ...... @@ -4910,7 +10034,26 @@ Z = (195, 195, 195) ....KCKJAKCKJA.. ................ } -# tile 257 (flesh golem) +# tile 522 (flesh golem,male) +{ + ................ + ................ + ...D..DDC....... + .....DLDDL...... + ..DD..LLLLC.D... + ...CDL.LLLLADL.. + ..CLDLA.CLLA.LL. + ..LLLAA.LLCA..L. + .CLLAA.CLLAA..CA + .LLA..CLLALLAAAA + ..LA.CLCAALCAAAA + ...A..LLCACLCAAA + ....LLALLAALLAAA + ..CLLLAAAADLLA.. + ..LLDDD..DDDDD.. + ................ +} +# tile 523 (flesh golem,female) { ................ ................ @@ -4929,7 +10072,26 @@ Z = (195, 195, 195) ..LLDDD..DDDDD.. ................ } -# tile 258 (clay golem) +# tile 524 (clay golem,male) +{ + ................ + ................ + ................ + ....LCCCCK...... + ...LKKKKKKK..... + ...CKAKKAKK..... + ...CKAKKAKK..... + .LCKKKKKKKKLC... + CKKJKKKKKKCKKJ.. + KKKJKKJJKKJKKJAA + .JJAKKJAKKAJJAAA + ..AKKKJAKKKAAAAA + ..CKKKKKKKKKAAAA + ..CKKKAACKKKAA.. + ..CKKKA.CKKKAA.. + ................ +} +# tile 525 (clay golem,female) { ................ ................ @@ -4948,7 +10110,26 @@ Z = (195, 195, 195) ..CKKKA.CKKKAA.. ................ } -# tile 259 (stone golem) +# tile 526 (stone golem,male) +{ + ................ + ................ + ................ + ....BBBPP....... + ...BBPPPPP...... + ...BHAPHAP...... + ...PPPPPPP...... + .BBPPPPPP.BPA... + BPPPP....PPPPAA. + BPP.BPPPP.PPPAAA + .PP.BP.PP.PPPAAA + ...BPP.PPPAAAAAA + ..BPPPAPPPAAAAA. + ..PPPPAPPPPAAA.. + ...PPAA.PPPA.... + ................ +} +# tile 527 (stone golem,female) { ................ ................ @@ -4967,7 +10148,26 @@ Z = (195, 195, 195) ...PPAA.PPPA.... ................ } -# tile 260 (glass golem) +# tile 528 (glass golem,male) +{ + ................ + .....BBBBBBA.... + .....BPNPPPA.... + .....BNPPPNA.... + .....NPPPNPA.... + .....BPPNPPA.... + .......BA...BA.. + .BNBBABPBA.BPNA. + .NPPNABPNBBANPBA + .....BPNPPPAABAA + .....BNPPPAAAAAA + ......BPPNAAAAAA + ....BNABNABPAAA. + ...BNPA...BNAAA. + ..BNPA....NPAA.. + ...BA.....BPA... +} +# tile 529 (glass golem,female) { ................ .....BBBBBBA.... @@ -4986,7 +10186,26 @@ Z = (195, 195, 195) ..BNPA....NPAA.. ...BA.....BPA... } -# tile 261 (iron golem) +# tile 530 (iron golem,male) +{ + ................ + ......PBP....... + ......HBH...B... + ......PBP...JP.. + ......PBP...BP.. + ...PPPAAAAPABP.. + ..PBJBBBBBJBAP.A + ..PPPPPPPPPPPA.A + .B.A........A..A + .BP.AAAAAAAAA.AA + .BP.ABP.APBP.AAA + .BJ.ABP.APBP.AAA + ..P.ABP.APBP.AAA + ....PJP.APJP.AA. + ....PBP.APBP.A.. + ................ +} +# tile 531 (iron golem,female) { ................ ......PBP....... @@ -5005,7 +10224,7 @@ Z = (195, 195, 195) ....PBP.APBP.A.. ................ } -# tile 262 (human) +# tile 532 (human,male) { ................ ................ @@ -5024,7 +10243,29 @@ Z = (195, 195, 195) ................ ................ } -# tile 263 (wererat) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female humans wear slightly different clothing. +# +# tile 533 (human,female) +{ + ................ + ................ + .......JJA...... + ......JJJJA..... + ......ELELA..... + ......LLLLA..... + ......ALLA...... + .....CJAAJC.AAA. + ....CLJLLJLCAAA. + ....LAKJJJALAAA. + ....LAJJKJALAAA. + ......JJJKAAAA.. + ......JJAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 534 (wererat,male) { ................ ................ @@ -5043,7 +10284,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 264 (werejackal) +# tile 535 (wererat,female) +{ + ................ + ................ + .......JJA...... + ......JJJJA..... + ......GJGJA..... + ......LLLLA..... + ......ALLA...... + .....CJAAJC.AAA. + ....CLJLLJLCAAA. + ....LAKJJJALAAA. + ....LAJJKJALAAA. + ......JJJKAAAA.. + ......JJAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 536 (werejackal,male) { ................ ................ @@ -5062,7 +10322,29 @@ Z = (195, 195, 195) ................ ................ } -# tile 265 (werewolf) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female werejackals wear slightly different clothing. +# +# tile 537 (werejackal,female) +{ + ................ + ................ + .......JJA...... + ......JJJJA..... + ......IPIPA..... + ......LLLLA..... + ......ALLA...... + .....CJAAJC.AAA. + ....CLJLLJLCAAA. + ....LAKJJJALAAA. + ....LAJJKJALAAA. + ......JJJKAAAA.. + ......JJAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 538 (werewolf,male) { ................ ................ @@ -5081,7 +10363,48 @@ Z = (195, 195, 195) ................ ................ } -# tile 266 (elf) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female werewolves wear slightly different clothing. +# +# tile 539 (werewolf,female) +{ + ................ + ................ + ......JJA....... + .....JJJJA...... + .....NJNJA...... + .....LLLLA...... + .....ALLA....... + ....CJAAJC.AAA.. + ...CLJLLJLCAAA.. + ...LAKJJJALAAA.. + ...LAJJKJALAAA.. + .....JJJKAAAA... + .....JJAJAA.A... + ....KLA.LKA..... + ................ + ................ +} +# tile 540 (elf,male) +{ + ................ + .........G...... + .......GGF...... + ......GGGGA..... + ......LELEA..... + ......LLLLA..... + ......ALLA....A. + ......GAAG..AAA. + .....LGGGFLAAAA. + ....LAAGFAALAAA. + ....LAGGGFALAA.. + ......GFAFAA.A.. + ......GFAFAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 541 (elf,female) { ................ .........G...... @@ -5100,7 +10423,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 267 (Woodland-elf) +# tile 542 (Woodland-elf,male) +{ + ................ + ................ + .........K...... + .......KKJ...... + ......KKKKA..... + ......LELEA..... + ......LLLLA..... + ......ALLA....A. + ......KAAK..AAA. + .....LKKKJLAAAA. + ....LAPPJAALAAA. + ..KKLKKKKJALAA.. + ......PPAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 543 (Woodland-elf,female) { ................ ................ @@ -5119,7 +10461,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 268 (Green-elf) +# tile 544 (Green-elf,male) +{ + ................ + ................ + .........G...... + .......GGF...... + ......GGGGA..... + ......LELEA..... + ......LLLLA..... + ......ALLA....A. + ......GAAG..AAA. + .....LGGGFLAAAA. + ....LAAGFAALAAA. + ....LAGGGFALAA.. + ......GFAFAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 545 (Green-elf,female) { ................ ................ @@ -5138,7 +10499,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 269 (Grey-elf) +# tile 546 (Grey-elf,male) +{ + ................ + ................ + .........P...... + .......PP....... + ......PPPPA..... + ......LELEA..... + ......LLLLA..... + ......ALLA....A. + ......PAAP..AAA. + .....LPPP.LAAAA. + ....LAAP.AALAAA. + ....LAPPP.ALAA.. + ......P.A.AA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 547 (Grey-elf,female) { ................ ................ @@ -5157,7 +10537,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 270 (elf-lord) +# tile 548 (elf-noble,male) +{ + ................ + ................ + ........II...... + .......HGF...... + ......HGGGA..... + ......LELEA..... + ......LLLLA..... + ......ALLA....A. + ......HAAH..AAA. + .....LHHHFLAAAA. + ....LAAIIAALAAA. + ....LAHGGFALAA.. + ......HFAFAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 549 (elf-noble,female) { ................ ................ @@ -5176,7 +10575,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 271 (Elvenking) +# tile 550 (elven monarch,male) { ................ ................ @@ -5195,7 +10594,48 @@ Z = (195, 195, 195) ................ ................ } -# tile 272 (doppelganger) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female elven monarchs have slightly different crowns. +# +# tile 551 (elven monarch,female) +{ + ................ + ......H..H...... + ......H..H...... + ......HCHH...... + ......HHHHA..... + ......LELEA..... + ......LLLLA..... + .....IALLAI...A. + ....IIIAAIDIAAA. + .....LIIGDLAAAAA + ....LADIFDALAAAA + ....LAIIGDALAAA. + .....IIFAFDAAA.. + ...IIKLAILKDI... + ................ + ................ +} +# tile 552 (doppelganger,male) +{ + ................ + ......CCCC..I... + ..I..CD...C..... + ....CD.HHA.C.... + ...CD.HHHHA.C.I. + ...CD.LFLFA.DC.. + .I.CD.LLLLA.DC.. + ...CD.ALLA.DC... + ..CD.LLAALL.ACA. + .CD.LLLLLLLLADC. + .CD.LALLLLALADC. + .CD.LAJJKJALADC. + ..CD..LJJLAAACA. + ...CD.LLALAACA.. + ..CD.LLAALLADC.. + ................ +} +# tile 553 (doppelganger,female) { ................ ......CCCC..I... @@ -5214,7 +10654,26 @@ Z = (195, 195, 195) ..CD.LLAALLADC.. ................ } -# tile 273 (shopkeeper) +# tile 554 (shopkeeper,male) +{ + ................ + ................ + ......AAAA...... + .....AAAAAA..... + ......JLJL...... + ......LLLL...... + ......ALLA...... + .....EBAABEA.AA. + ....EBBBBBBEAAA. + ....BAEBBEABAAA. + ....LAGFFFALAAA. + ......GFAFAAAA.. + ......GFAFAA.A.. + .....JJA.JJA.... + ................ + ................ +} +# tile 555 (shopkeeper,female) { ................ ................ @@ -5233,7 +10692,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 274 (guard) +# tile 556 (guard,male) { ................ .....BBPPPAA.... @@ -5252,7 +10711,49 @@ Z = (195, 195, 195) .....BPPABPPAAAA ....BPPP.BPPPAAA } -# tile 275 (prisoner) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female guards are clean-shaven. Although of course not one +# hundred percent accurate, it's convenient visual shorthand. +# +# tile 557 (guard,female) +{ + ................ + .....BBPPPAA.... + ....BNPPPPPPA... + ....BPPBPPPPA... + ....BAABPAAPA... + ....BCLBPCLPA... + ....JCLPPCLJAA.. + ....BPLLLLAPAAAA + ...BPPLAALAPPAAA + ..BPPPPLLPPPPPAA + ..PPABPPPPPPAPPA + ..PPABPPPPPPAPPA + ..LC.BPPPPPPCLAA + ..LL.BPPABPPLLAA + .....BPPABPPAAAA + ....BPPP.BPPPAAA +} +# tile 558 (prisoner,male) +{ + ................ + ................ + .......NOA...... + .......LLA...... + .......LLA...... + .......NOA...... + ......NOONA..... + .....NOOOONA.... + ....NANOOOANAA.. + ....PANOOOAPAAA. + ....LANOOOALAAA. + ......NOOOAAAA.. + ......NAANAAA... + ......PAAPAA.... + .....LLA.LLA.... + ................ +} +# tile 559 (prisoner,female) { ................ ................ @@ -5271,7 +10772,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 276 (Oracle) +# tile 560 (Oracle,male) +{ + ................ + ................ + .......NN....... + LLL...GLLG...LLL + ..L..NLLLLN..L.. + ...L.NLAALN.L... + ....LNLLLLNL.... + .....LNLLNL..AA. + .....NBBEEN.AAAA + ......BBEEAAAAAA + .LLA..BBBEAAALL. + .LLLLBBBEBELLLLA + ..LLCLBLLELLCLAA + ...CLLLLLLLCLAA. + ....LELLLLELAA.. + ................ +} +# tile 561 (Oracle,female) { ................ ................ @@ -5290,7 +10810,26 @@ Z = (195, 195, 195) ....LELLLLELAA.. ................ } -# tile 277 (aligned priest) +# tile 562 (aligned cleric,male) +{ + ................ + INI............. + III..KCCK....... + .J..KCCCCK...... + .J..CAAKCC...... + .LC.CAAACC...... + CLLC.CAACJKC.... + CJLACCCCJKCCC... + .JAACCJJCKCCCK.. + .JKCCCJCCJCCK.AA + .J..CCJCCLJCAAAA + .J..CCJCLLCAAAA. + .J..KCJCCCJAAAA. + .J.ACCJCCCJAAA.. + .JACCCJJCCCAA... + ................ +} +# tile 563 (aligned cleric,female) { ................ INI............. @@ -5309,7 +10848,26 @@ Z = (195, 195, 195) .JACCCJJCCCAA... ................ } -# tile 278 (high priest) +# tile 564 (high cleric,male) +{ + .INI............ + IIIII.KCCK...... + .IHI.KCAACK..... + ..H..CGAGAC..... + ..LC.CAAAAC..... + .CLLC.CAACJCK... + .CHLACCCCJCCCK.. + ..HAACCJJCCCCCK. + ..HCCCCJCCJCCC.A + ..H..CCJCCLJCAAA + ..H..CCJCLLCAAAA + ..H..KCJCCCJAAAA + ..H..KCJCCCJAAAA + ..H.ACCJCCCJAAA. + ..HACCCJJCCCAA.. + ................ +} +# tile 565 (high cleric,female) { .INI............ IIIII.KCCK...... @@ -5328,7 +10886,26 @@ Z = (195, 195, 195) ..HACCCJJCCCAA.. ................ } -# tile 279 (soldier) +# tile 566 (soldier,male) +{ + .....J.......... + .....JAAA....... + .....ALLLA...... + .....LLLLC...... + .....JLLC....... + .....JF..F...... + ....FJFFFFF..A.. + ....FJFFFAF.A... + ....FLFFFFFAAA.. + ....FJFFAAAAAAA. + .....LFAFFAAAA.. + .....FFAF.AAAA.. + ......FAF.AA.... + .....FFAFFA..... + .....JJ.JJ...... + ................ +} +# tile 567 (soldier,female) { .....J.......... .....JAAA....... @@ -5347,7 +10924,26 @@ Z = (195, 195, 195) .....JJ.JJ...... ................ } -# tile 280 (sergeant) +# tile 568 (sergeant,male) +{ + .....J.......... + .....JFFF....... + ....FFFFFF...... + .....LLLLC...... + .....JLLC....... + .....JF..G...... + ....FJFFFFF..A.. + ....FJFFFAF.A... + ....FLFFFFFAAA.. + ....FJFFAAAAAAA. + .....LFAFFAAAA.. + .....FFAF.AAAA.. + ......FAF.AA.... + .....FFAFFA..... + .....AA.AA...... + ................ +} +# tile 569 (sergeant,female) { .....J.......... .....JFFF....... @@ -5366,7 +10962,26 @@ Z = (195, 195, 195) .....AA.AA...... ................ } -# tile 281 (nurse) +# tile 570 (nurse,male) +{ + ................ + .......NO....... + ......NDDO...... + ......NNOOA..... + .....DBLBLD..... + .....CLLLLDC.... + .....DALLACD.... + .....CNAAODCAAA. + .....NNNOOLAAAA. + ....LANNDOALAAA. + ....LANNOOALAAA. + ......NNOOAAAA.. + ......NNAOAA.A.. + .....LLA.LLA.... + ................ + ................ +} +# tile 571 (nurse,female) { ................ .......NO....... @@ -5385,7 +11000,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 282 (lieutenant) +# tile 572 (lieutenant,male) +{ + ................ + .......FFF...... + .....FFFFFF..... + ......LLLL...... + .......LLCA..... + .....GF.FGA..... + ....FFFFFFFF.... + ....FAFFFFAFAAA. + ....FAFFFFAFAAAA + ....FAFFFFAFAAA. + ....LFFAFFJLJA.. + .....FFAFFJJJA.. + ......FAF.AA.... + .....FFAFFA..... + .....AA.AA...... + ................ +} +# tile 573 (lieutenant,female) { ................ .......FFF...... @@ -5404,7 +11038,26 @@ Z = (195, 195, 195) .....AA.AA...... ................ } -# tile 283 (captain) +# tile 574 (captain,male) +{ + ................ + ......FHHF...... + .....FFFFFF..... + ......LLLL...... + .......LLCA..... + .....HF.FHF..... + ....FFFFFFFFAA.. + ....FAFFIFAFAAAA + ....FAFFFFAFAAA. + ....FAFFFFAFAAA. + ....LFFAFFJLJA.. + .....FFAFFJJJA.. + ......FAF.JJJA.. + .....FFAFFJJJA.. + .....AA.AAAAA... + ................ +} +# tile 575 (captain,female) { ................ ......FHHF...... @@ -5423,7 +11076,26 @@ Z = (195, 195, 195) .....AA.AAAAA... ................ } -# tile 284 (watchman) +# tile 576 (watchman,male) +{ + ................ + ......PPP....... + ....PPPPPP...... + .....LLLLC...... + ......LLC....... + .....PP..P...... + ....PPPPPPP..... + ....PAPPHAPPA... + ....PAPPPANNAAA. + ....PJPPAPNNAAA. + ....JLPAPPAAAA.. + .....JPAP.AAAA.. + ......PAP.AA.... + .....PPAPPA..... + ....JJJ.JJJ..... + ................ +} +# tile 577 (watchman,female) { ................ ......PPP....... @@ -5442,7 +11114,26 @@ Z = (195, 195, 195) ....JJJ.JJJ..... ................ } -# tile 285 (watch captain) +# tile 578 (watch captain,male) +{ + ......PPP....... + .....PHHHP...... + ....PPPPPPP..... + .....LLLLC...... + ......LLC....... + .....HP..H...... + ....PPPPPPP..... + ....PAPPHAPPA... + ....PAPPPANNAAA. + ....PJPPAPNNAAA. + ....JLPAPPAAAA.. + .....JPAP.AAAA.. + .....JPAP.AA.... + .....PPAPPA..... + ....JJJ.JJJ..... + ................ +} +# tile 579 (watch captain,female) { ......PPP....... .....PHHHP...... @@ -5461,7 +11152,26 @@ Z = (195, 195, 195) ....JJJ.JJJ..... ................ } -# tile 286 (Medusa) +# tile 580 (Medusa,male) +{ + ................ + ..GA...GA....... + ...FA.FA..GA.... + ....FJFFFF...... + ..FAFLLFA....A.. + .GAFLLLLA..A..A. + ....JLLKA.A.A.A. + ...KBLLBKAAAAA.. + ..KIIBBIIIAAA.A. + ..IIIKKILLIAAA.. + ..KIILLIALIAA... + ...KIALKAAIAA... + ...IKAAKIIAAA... + ...IIKKIIIAA.... + ..IIKIKIKIA..... + ................ +} +# tile 581 (Medusa,female) { ................ ..GA...GA....... @@ -5480,7 +11190,26 @@ Z = (195, 195, 195) ..IIKIKIKIA..... ................ } -# tile 287 (Wizard of Yendor) +# tile 582 (Wizard of Yendor,male) +{ + .EEE.......EEE.. + EFFAE..E..EAFFE. + EAAAE.EEE.EAAAE. + EAAAEEEAEEEAAAE. + EEAAEEDADEEAAEE. + .EEEEAAAAAEEEE.. + ..EEEEAAAEEEE... + ..EEEEEEEEEE.... + ...EEEEEEEE..... + ...EEEEEEEE....A + ....EEEEEE...AAA + ....EEEEEEAAAAAA + ...EEEEEEEEAAAAA + ..EEEEEEEEEAAAAA + .EEEEEEEEEEEAAA. + EEEEEEEEEEEEEEA. +} +# tile 583 (Wizard of Yendor,female) { .EEE.......EEE.. EFFAE..E..EAFFE. @@ -5499,7 +11228,26 @@ Z = (195, 195, 195) .EEEEEEEEEEEAAA. EEEEEEEEEEEEEEA. } -# tile 288 (Croesus) +# tile 584 (Croesus,male) +{ + ....H..H..H..... + ....HCHEHCH..... + ....HHHHHHH..... + ....ALLLLLA..... + ....LLALALL..... + .....LLLLL...... + ....HLLDLLH..... + ...HIALLLAIH.A.A + ...HIHAAAHIHAAAA + ..IIIEHHHIIIIAAA + ..IIIIEHIIIIIAA. + ..ILLIHHHILLIAAA + ...LIIKHIIILAAAA + ..GIIIKJIIIIGAA. + .GIIIKJJKKIIIGG. + ................ +} +# tile 585 (Croesus,female) { ....H..H..H..... ....HCHEHCH..... @@ -5518,7 +11266,26 @@ Z = (195, 195, 195) .GIIIKJJKKIIIGG. ................ } -# tile 289 (Charon) +# tile 586 (Charon,male) +{ + ................ + .......J........ + ......JJJ....... + ....JJJAJJJ..... + ....JJDADJJ..... + ...JJAAAAAJJ.... + ...JJJAAAJJJ.... + ..JJJJJJJJJJ.... + .JJJJJJJJJJJJ... + JJJJJJJJJJJJJJ.A + .OO.JJJJJJ.OOAAA + ....JJJJJJAAAAAA + ...JJJJJJJJAAAAA + ..JJJJJJJJJAAAAA + .JJJJJJJJJJJAAA. + JJJJJJJJJJJJJJA. +} +# tile 587 (Charon,female) { ................ .......J........ @@ -5537,7 +11304,26 @@ Z = (195, 195, 195) .JJJJJJJJJJJAAA. JJJJJJJJJJJJJJA. } -# tile 290 (ghost) +# tile 588 (ghost,male) +{ + ................ + ................ + ...NNN.......... + ..NANANN........ + .NNNNNNNNN...... + .NNPAAPNNNNN.... + .NNAAAANNNOONO.. + .NNAAAANONNNPNNO + .NNPAAPNONNOOOP. + .NNNNNNONOPNPPO. + .NNONNOPNNOPOOP. + .NOPNNOOOPPOOP.. + .OOOPOPPOPPP.PP. + .PP.PPOPPP...P.. + .O...P....P..... + ........P....... +} +# tile 589 (ghost,female) { ................ ................ @@ -5556,7 +11342,26 @@ Z = (195, 195, 195) .O...P....P..... ........P....... } -# tile 291 (shade) +# tile 590 (shade,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ........AAAAAAA. + ....AAAAAAAA.... + ..AAAAAAAAAAAA.. + AAAAAAAAAAAAAAA. + ..AAAAAAAAAAAAAA + .AAAAAAAAAAAAA.. + AAAA.AAAAJA..... + ................ +} +# tile 591 (shade,female) { ................ ................ @@ -5575,7 +11380,26 @@ Z = (195, 195, 195) AAAA.AAAAJA..... ................ } -# tile 292 (water demon) +# tile 592 (water demon,male) +{ + ................ + ................ + ................ + ................ + ..EE.....EE..... + .E.EE...EE.E.... + ....EEEEE....... + ....EBEBE..A.... + ...EEEEEEEAAAA.. + ..EEE...EEEAA.A. + ..EEEEEEEEEAAA.. + ..EEAEEEAEEAAA.. + ...AAEEEAAAAA... + ....EEAEEAA..... + ....EEAEEA...... + ................ +} +# tile 593 (water demon,female) { ................ ................ @@ -5594,7 +11418,26 @@ Z = (195, 195, 195) ....EEAEEA...... ................ } -# tile 293 (succubus) +# tile 594 (amorous demon,male) +{ + DD.OHHD......... + DDOHHDGD........ + DDOHDDDDD....... + DDHHDDDA........ + DDDHDJADDDD..... + DDDJDDDDDDDD.... + .DDDDDCDD.DDD... + .DDCDDDKK..DD... + ..DDKKDDDAADDA.. + ...DDDDDDAAAAA.. + ....DDDDDDDDDA.. + ....DDJDJJAAAAAA + ....JDJJADKAA... + ....DDKAADDKA... + ...DDKAA..DDAA.. + ..DDKAA...DDDA.. +} +# tile 595 (amorous demon,female) { DD.OHHD......... DDOHHDGD........ @@ -5613,7 +11456,7 @@ Z = (195, 195, 195) ....DDAA..DDAA.. ...DDJA...DDDA.. } -# tile 294 (horned devil) +# tile 596 (horned devil,male) { ................ ................ @@ -5632,26 +11475,45 @@ Z = (195, 195, 195) ..CDDAA.DDK..... ................ } -# tile 295 (incubus) +# tile 597 (horned devil,female) { - DD.OHHD......... - DDOHHDGD........ - DDOHDDDDD....... - DDHHDDDA........ - DDDHDJADDDD..... - DDDJDDDDDDDD.... - .DDDDDCDD.DDD... - .DDCDDDKK..DD... - ..DDKKDDDAADDA.. - ...DDDDDDAAAAA.. - ....DDDDDDDDDA.. - ....DDJDJJAAAAAA - ....JDJJADKAA... - ....DDKAADDKA... - ...DDKAA..DDAA.. - ..DDKAA...DDDA.. + ................ + ................ + ..O.......O..... + ..OO.....OO..... + ...LOCDCOL...... + ...CDDDDDC...... + ...DAADAADA..D.. + ...DDDDDDDA.D... + ..CCDDFDDCCAD.A. + ..CDKDDDKCDADA.. + ..CDAKKKACDAAAA. + ..DDADDDADDAAAA. + ....CDDDKAAAAA.. + ...CDDADDKAA.... + ..CDDAA.DDK..... + ................ +} +# tile 598 (erinys,male) +{ + ..GA...GA....... + ...FA.FA..GA.... + ....FJFFFF...... + ..FAFLLFA....... + .GAFDLDLA..A.A.. + ....LLLEA.A.A.A. + ...EBLLBEAAAA.A. + ..EBBBBBBBAAAA.. + ..BBBEBBLLBAA.A. + ..EBBLLBALBAAA.. + ...EBALBAABAA... + ...BEAABBBAAA... + ...BBBBBBBAAA... + ...BBBBBBBAA.... + ..BBEBEBEBA..... + ................ } -# tile 296 (erinys) +# tile 599 (erinys,female) { ..GA...GA....... ...FA.FA..GA.... @@ -5670,7 +11532,26 @@ Z = (195, 195, 195) ..BBEBEBEBA..... ................ } -# tile 297 (barbed devil) +# tile 600 (barbed devil,male) +{ + ................ + ................ + ..O.......O..... + ..OO.....OO..... + .O.LOCDCOL.O.... + ...CDDDDDC....DD + ...DAADAADA..D.D + ...DDDDDDDA.D... + ..CCDDFDDCCAD.A. + ..CDKDDDKCDADA.. + .C.DAKKKACDKAAA. + ..DDADDDADDAAAA. + ....CDDDKAAAAA.. + .K.CDDADDKAAK... + .CCDDAA.DDKK.... + ................ +} +# tile 601 (barbed devil,female) { ................ ................ @@ -5689,7 +11570,26 @@ Z = (195, 195, 195) .CCDDAA.DDKK.... ................ } -# tile 298 (marilith) +# tile 602 (marilith,male) +{ + .D..HHH.....D... + DD.HHHHHA...DD.. + .DCHDDDHHAAD..A. + ..HDBDBDHDDAAAA. + .CHKDDDKHAAADD.. + CDDDKKKDHDDDDFF. + D..CDDCDKAAFFFAA + D.KDDKDDDDDDFAA. + D.DKDDKDKAFDFAA. + ..D.GDDFAAFDFFAA + .D.GGFFFAAAFFFFA + ...GFFFFFAAAFFFA + ..FGFFFFFFAFFFFA + ..FGFFFFFFFFFFA. + ..FGFFFFFFFFFA.. + ....GFFFFFFAA... +} +# tile 603 (marilith,female) { .D..HHH.....D... DD.HHHHHA...DD.. @@ -5708,26 +11608,64 @@ Z = (195, 195, 195) ..FGFFFFFFFFFA.. ....GFFFFFFAA... } -# tile 299 (vrock) +# tile 604 (vrock,male) +{ + ................ + ......OPP.O..... + ......PPPP...... + .....KPPDP...... + ....KJJPPP...... + ....KJPPPP...... + ....K..PPA...... + .....GGAAGG.AAA. + ....FDFDFDFDAAA. + ..G.GADGDFAGAGA. + ....GAFGFGAGAAA. + ..G.DADFDGAFAAA. + ......GAADAAAG.. + .F.G..GAAFAA.A.. + .....DFA.GGA..F. + ................ +} +# tile 605 (vrock,female) { ................ ......OPP.O..... ......PPPP...... - .....CPPDP...... - ....CCCPPP...... - ....CCPPPP...... - ....C..PPA...... - .....DDAADD.AAA. - ....DDDDDDDDAAA. - ....DADDDDADAAA. - ....DADDDDADAAA. - ....DADDDDADAAA. - ......DAADAAAA.. - ......DAADAA.A.. - .....DDA.DDA.... + .....LPPGP...... + ....LCCPPP...... + ....LCPPPP...... + ....L..PPA...... + .....GGAAGG.AAA. + ....FDFDFDFDAAA. + ..G.GADGDFAGAGA. + ....GAFGFGAGAAA. + ..G.DADFDGAFAAA. + ......GAADAAAG.. + .F.G..GAAFAA.A.. + .....DFA.GGA..F. + ................ +} +# tile 606 (hezrou,male) +{ + ................ + ................ + ....GGGFF....... + ..NGFFNNFFF..... + .DFFFDDNFF.F.... + .GFFFDNFF.FFFAA. + .AFAFFFFFFFFFFAA + .GFFFF.FFF.FGFAA + .GAAAFF..LFGFFAA + ..FFFF.FFLFGFFFA + ..LLA.FLLLJJG.FA + .LLAFFLLFJJGFFFA + ..LAFLLLAAGF.FAA + .....L.LAGFFFFAA + ...........FFFA. ................ } -# tile 300 (hezrou) +# tile 607 (hezrou,female) { ................ ................ @@ -5746,7 +11684,26 @@ Z = (195, 195, 195) ...........FFFA. ................ } -# tile 301 (bone devil) +# tile 608 (bone devil,male) +{ + ................ + ................ + ..O.......O..... + ..OO.....OO..O.. + ...LNLOLOL....O. + ...LOOOOOL....O. + ...NAAOAAOA..O.. + ...NOOOOOOA.O... + ..NOOOFOOOOAO.A. + ..OOKNOOKOOALA.. + ..OOANOOAOOAKAA. + ..LLANOOALLAAAA. + ....NOOOLAAAAA.. + ...NOOAOOLAA.... + ..NOOAA.OOL..... + ................ +} +# tile 609 (bone devil,female) { ................ ................ @@ -5765,7 +11722,26 @@ Z = (195, 195, 195) ..NOOAA.OOL..... ................ } -# tile 302 (ice devil) +# tile 610 (ice devil,male) +{ + ................ + ................ + ..N.......N..... + ..NN.....NN..... + ...PBPNPNP..BNB. + ...PNNNNNP..N.N. + ...BAANAANA...N. + ...BNNNNNNA.BNB. + ..BNNNFNNNNAN.A. + ..NNKBNNKNNABA.. + ..NNABNNANNA.AA. + ..PPABNNAPPAAAA. + ....BNNNPAAAAA.. + ...BNNANNPAA.... + ..BNNAA.NNP..... + ................ +} +# tile 611 (ice devil,female) { ................ ................ @@ -5784,7 +11760,26 @@ Z = (195, 195, 195) ..BNNAA.NNP..... ................ } -# tile 303 (nalfeshnee) +# tile 612 (nalfeshnee,male) +{ + ................ + ................ + ......BB...BB... + ..KKKKKBB.BB.... + .KADKADKKKB..... + .KKKKKKKDKK..... + .OKDKOKKDDKD.... + .OKDKOKKKDKDD... + .KAAAKKDKAKKD... + ..KKKDDLAKKKD.A. + ...KK.KKKKKDDA.. + ....L..KDAKDAA.. + ......LLAAKDA... + .........LLA.... + ................ + ................ +} +# tile 613 (nalfeshnee,female) { ................ ................ @@ -5803,7 +11798,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 304 (pit fiend) +# tile 614 (pit fiend,male) +{ + ................ + .K.O.......O.K.. + .K.OO.....OO.KJ. + KJJ.LOCDCOL.KJJ. + KJJJKDDDDDKKJJJ. + KJJCKDNDNDKCJJJA + JJCCKDDDDDJCCJJA + JJCCCKDIDJDCCJJA + JACCDDKJJDDCDAJA + JACCKDDDDDKCDAJA + ...CDKDDDKCDDAAA + ....DKDDDKCDAAAA + .....CDDDKAAAA.. + ....CDDADDKA.... + ...CDDAA.DDK.... + ................ +} +# tile 615 (pit fiend,female) { ................ .K.O.......O.K.. @@ -5822,7 +11836,26 @@ Z = (195, 195, 195) ...CDDAA.DDK.... ................ } -# tile 305 (sandestin) +# tile 616 (sandestin,male) +{ + .....CCCCC..I... + .I..CD....C..... + ...CD.DDD..C..I. + ..CD.DDDDD..C... + ..CD.DNDNDA.DC.. + I.CD.DDDDDA.DC.. + ..CD.ADDDA.DC..A + .CD.DDAAADD.DCAA + CD.DDDDDDDDDADCA + CD.DADDDDDADADCA + CD.DADDDDDADADCA + CD.DADDDDDADADC. + .CD..DDJDDAADCA. + ..CD.DDADDADCA.. + .CD.DDAADDDADC.. + ................ +} +# tile 617 (sandestin,female) { .....CCCCC..I... .I..CD....C..... @@ -5841,7 +11874,26 @@ Z = (195, 195, 195) .CD.DDAADDDADC.. ................ } -# tile 306 (balrog) +# tile 618 (balrog,male) +{ + ................ + .K..O.....O..K.. + .KJ.O.....O.KJ.. + KJJLOOCDCOOLJJJ. + JJJDDDDDDDDDDKJ. + JCCDDDNDNDDDCCJA + CCDKDDDDDDDJCCCA + CDDKKKDIDJJDCCDA + CDDKDDKJJDDDCDDA + CCDKDDDDDDDKCDDA + JCCDKKDDDKKCDDDA + JJCDKKDDDKKCDDJA + JJ..CCDDDKKAAJJA + J..CDDDADDDKAAJA + ..CDDDAA.DDDK.AA + ................ +} +# tile 619 (balrog,female) { ................ .K..O.....O..K.. @@ -5860,7 +11912,26 @@ Z = (195, 195, 195) ..CDDDAA.DDDK.AA ................ } -# tile 307 (Juiblex) +# tile 620 (Juiblex,male) +{ + ................ + DD.........DD... + NDC.KKKKJ.CND... + .CCKCCCKKCCAA... + ..KCCCCKCCJAA... + ..KCCCCCK.JJAA.. + ..KCCFCCK..JAA.. + ..FKCFCCKK.JAAA. + .FKKFCCKFK..JAA. + .FKCFCCFKFK.JAA. + .FCFCCKFCFK.JAA. + FKCFCFCFCKK.JAA. + CKFCCFCCKKFKJJA. + CCKKCFCKFFKKKKA. + .CCCCCCCCCCCKA.. + ................ +} +# tile 621 (Juiblex,female) { ................ DD.........DD... @@ -5879,7 +11950,26 @@ Z = (195, 195, 195) .CCCCCCCCCCCKA.. ................ } -# tile 308 (Yeenoghu) +# tile 622 (Yeenoghu,male) +{ + ....B.HHP....... + ....BPPPP....... + ...BPLCPPH...... + .KBPPCCPPH...... + .PPPPPPP.H...... + .PP...P.PH...... + ....BPPPPPAAA... + ..BPPPPPPPPAAAA. + .BP.PPPPPAPPAAAA + .B...BPP.AAPAAAA + .B...BPP.AAPAAA. + .....BPPAAAAA.A. + ....BP.PPAA...A. + ...BP.AAPPA..A.. + ...BPAA.PPA..... + ................ +} +# tile 623 (Yeenoghu,female) { ....B.HHP....... ....BPPPP....... @@ -5898,7 +11988,26 @@ Z = (195, 195, 195) ...BPAA.PPA..... ................ } -# tile 309 (Orcus) +# tile 624 (Orcus,male) +{ + ................ + .K..O.....O..K.. + KJJO..BBB..O.KJ. + KJJLOBPPPPOLKJJ. + JKJJ.PGPGP.JJKJA + JJKJKPPPPPJJKJJJ + JBPPB.BPPABBPPJJ + PJJPP.BPPAPPJJPA + PJBPPP.AAPPPPJPA + .JBP.PPPP.P.PJAA + .JBPPPP.PPPPPJAA + ..PPP.PPP.PPPAAA + ...P.PPPPPPP.P.A + ...BPPPAPPPPAAPA + ...OOPPAOOPPAGA. + ................ +} +# tile 625 (Orcus,female) { ................ .K..O.....O..K.. @@ -5917,7 +12026,26 @@ Z = (195, 195, 195) ...OOPPAOOPPAGA. ................ } -# tile 310 (Geryon) +# tile 626 (Geryon,male) +{ + .K...........K.. + .K....JJJ....KJ. + KJJ..JJJJJ..KJJ. + KJJJKLLLLLKKJJJ. + KJJJKLBLBLKJJJJA + JJJJKLLLLLJJJJJA + JJALLKLLLJLLAJJA + JA.LLLKJJLLLAAJA + ...LJLLLLLKLAAAA + ...LCKLLLKCLAFGF + ...LLGLLFALLFFFA + .....GFFFAAAFFAA + ....GGGGFFAAFFAA + ....GFFFFFAAFGFA + ....FGGGFFFFFFFA + .....FFFFFFFFFA. +} +# tile 627 (Geryon,female) { .K...........K.. .K....JJJ....KJ. @@ -5936,7 +12064,26 @@ Z = (195, 195, 195) ....FGGGFFFFFFFA .....FFFFFFFFFA. } -# tile 311 (Dispater) +# tile 628 (Dispater,male) +{ + ................ + ......OJJO...... + ......JJJJA..... + ......BLBLA..... + ......LLLLA..... + ......ALLA...... + .....CKAAKK.AAA. + ....CKKKKKKKAAA. + ....KACKKJAKAAA. + ....KACKKJAKAAJA + ....KACKKJAKAAJA + ....LACKKJJLAJA. + ......CKAJAJJA.. + ......CKAPAAAA.. + .....PPA.PPA.... + ................ +} +# tile 629 (Dispater,female) { ................ ......OJJO...... @@ -5955,7 +12102,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 312 (Baalzebub) +# tile 630 (Baalzebub,male) +{ + ......F...F..... + .......F.F...... + ......BFFFB..... + .....BPPFBPP.... + .....PPPFPPP.... + ......PPFPP..... + .....CAFFFAK.... + ....CKKAFAKKKAA. + ....CAKJFAKAKAA. + ....FACJDAJAFAA. + ....FACKJJJAFAA. + ....FACKKKJAFAA. + ......CKKKJAAA.. + ......CKAKJA.A.. + .....FFA..FF.... + ................ +} +# tile 631 (Baalzebub,female) { ......F...F..... .......F.F...... @@ -5974,7 +12140,26 @@ Z = (195, 195, 195) .....FFA..FF.... ................ } -# tile 313 (Asmodeus) +# tile 632 (Asmodeus,male) +{ + ................ + ......OJJO...... + ......JJJJA..... + ......BLBLA..... + ......LLLLA..... + ......ALLA...... + .....CKAAKK.AAA. + ....CKKKKKKKAAA. + ...KKCKKKKJKKAA. + ...KKAKKKJAKKAJA + ...KA.CKKJAAKAJA + ...LA.CKKJJALJA. + ......CKAJAJJA.. + ......CKAPAAAA.. + .....PPA.PPA.... + ................ +} +# tile 633 (Asmodeus,female) { ................ ......OJJO...... @@ -5993,7 +12178,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 314 (Demogorgon) +# tile 634 (Demogorgon,male) +{ + ...KKK..KKK..... + ..KBKBK.BKBK.... + ..KDKKK.KKDK.... + ..DKKFA.GKKD.... + ....GFAAGFAAA... + ...GFFFJFFFA.AAA + ..GFAGFFFAFFAAAA + .GJFAGJFJAFFFAA. + .GFAAGFFFAAFJA.. + .GJA.GFJFAAFFAA. + .GFA.GFFFA.FJAA. + .GJA.GJFJA.FFAA. + .GFAGFAAFFAFFA.. + ..GAGJAAJFAFAA.. + ..GAGFAFFFAFA... + ................ +} +# tile 635 (Demogorgon,female) { ...KKK..KKK..... ..KBKBK.BKBK.... @@ -6012,7 +12216,26 @@ Z = (195, 195, 195) ..GAGFAFFFAFA... ................ } -# tile 315 (Death) +# tile 636 (Death,male) +{ + .BBBB....JJJ.... + .BPPPP.JJJJ..... + .C....JJJJJ..... + .C....JAAAJ..... + .C...JADADAJ.AAA + OOJ..JAAAAAJAAA. + OOOJJJAAAAAJJJA. + OOJJJJAAAAJOOJJA + .CJJJJAAAJOOOOJA + .C.JJAAAAJAOAAJA + .C..JAAAAJAOAAJA + .C..JAAAAAJOAJAA + .C..JAAAAAJJJAAA + .C.JAAAAAAAJJAA. + .CJJAAAAAAAAJJA. + ACJAAAAAAAAAAAJ. +} +# tile 637 (Death,female) { .BBBB....JJJ.... .BPPPP.JJJJ..... @@ -6031,7 +12254,26 @@ Z = (195, 195, 195) .CJJAAAAAAAAJJA. ACJAAAAAAAAAAAJ. } -# tile 316 (Pestilence) +# tile 638 (Pestilence,male) +{ + F........JJJ.... + ..F....JJJJ..... + B...F.JJJJJ..... + ...B..JAAAJ..... + .F...JADADAJ.... + ...F.JAAAAAJ.AA. + .B..JFAAAAFJAA.. + ...FJJAFABJJAA.. + ..F.JFFBAJJJAAA. + ....FAFFJJJJAAA. + ....JABAJJJJAAA. + ...FJFFJJJJJJAA. + ...JJBFJJJJJJAA. + ...JAABFBJJJJAA. + ..JJFBFAFFAJJJA. + .JJAAFAFAAAAAAJ. +} +# tile 639 (Pestilence,female) { F........JJJ.... ..F....JJJJ..... @@ -6050,7 +12292,26 @@ Z = (195, 195, 195) ..JJFBFAFFAJJJA. .JJAAFAFAAAAAAJ. } -# tile 317 (Famine) +# tile 640 (Famine,male) +{ + .........JJJ.... + .......JJJ...... + K.....JJJJJ..... + K.....JAAAJ..... + K....JADADAJ.... + K....JAAAAAJ...A + K.....JAAAJJ..AA + OOJJJJJJAAJAJ.AA + K...JJJAAJJAJAAA + K.....JAJJJOJAA. + K.....JAOOOAAA.. + K.....JAJJAAA... + K.....JAJJAA.... + K.....JAAJAA.... + K...JJAAAJJAA... + K..JJAAAAAJJJA.. +} +# tile 641 (Famine,female) { .........JJJ.... .......JJJ...... @@ -6069,7 +12330,26 @@ Z = (195, 195, 195) K...JJAAAJJAA... K..JJAAAAAJJJA.. } -# tile 318 (mail daemon) +# tile 642 (mail daemon,male) +{ + ...OP.BEEE.PO... + ...OOEBEEEEOOD.. + ..DLOBEEEEOOLDD. + .DDDLDDDDDDLDDD. + .CCDDDNDDNDDDCC. + CCDKDDDDDDDDJCCC + CDDKKDDIIDDJJCCD + CDDK.KDAADJJECDD + CCDKEEKKKJEEKCDD + .CCDK.EEEE..CDDD + .CCDAE.EENNNCDD. + .DDDAEEEENDNDDD. + ....BBEEENNNNN.. + ...BEEEAANNNNNA. + ..CDDDAAA.DDDK.. + ................ +} +# tile 643 (mail daemon,female) { ...OP.BEEE.PO... ...OOEBEEEEOOD.. @@ -6088,7 +12368,26 @@ Z = (195, 195, 195) ..CDDDAAA.DDDK.. ................ } -# tile 319 (djinni) +# tile 644 (djinni,male) +{ + .LL..NNN..LL.... + ..L..NGNA.L..... + ..LAALLLAALA.... + ..LAAKKKAALA.... + ...LCKKKCLA..... + ....LCKCLA...... + ....LICLIA..A... + ....IIIIEA.AA..A + ....EIEEIA.AAAAA + ....IEFEAAAAAAAA + .....DEAIAAAAA.. + .....IGIFAAAA... + .......FEDAAA... + .......I.GEA.A.. + .........IFED... + ................ +} +# tile 645 (djinni,female) { .LL..NNN..LL.... ..L..NGNA.L..... @@ -6107,7 +12406,26 @@ Z = (195, 195, 195) .........IFED... ................ } -# tile 320 (jellyfish) +# tile 646 (jellyfish,male) +{ + ................ + .....PBPA....... + ...PBBBPBA...... + ..BBNNBPPBAA.... + .BBNNPPPBBPAA... + PBBBPPPBPBBAAA.. + BBBPBPPPPPBPAAA. + BBPBPPPPPPPBAAA. + PBPPBPPPPEPEEE.. + .PBBPPPEPEPPEE.. + .PEPBBEEPEEPEE.. + .PEEEPEEPEEPE... + ..PEEPE..PE.P... + ..P.EP.EEP..P... + ..PEE.P.E..E.... + .P..E.P..E...... +} +# tile 647 (jellyfish,female) { ................ .....PBPA....... @@ -6126,7 +12444,26 @@ Z = (195, 195, 195) ..PEE.P.E..E.... .P..E.P..E...... } -# tile 321 (piranha) +# tile 648 (piranha,male) +{ + ................ + ................ + ................ + ................ + ................ + ....OPP......... + .....OPP........ + ..O..PPAP.....E. + ..POPPPPPA...EEE + ..PPPPP.PPA.E... + ...PP..PPPAAAEE. + ..E.PPPPPPPPPE.. + ..E...PPPPPAA.E. + .....E..PPAE.... + .....E..P....... + ....E..E...E.... +} +# tile 649 (piranha,female) { ................ ................ @@ -6145,7 +12482,26 @@ Z = (195, 195, 195) .....E..P....... ....E..E...E.... } -# tile 322 (shark) +# tile 650 (shark,male) +{ + ................ + ................ + ................ + ...............P + ........P.....PP + ....E..PP....PP. + ...E...PPA..PPP. + ..EEEEPPPA.PPPPP + .E.EEPPP.PPPPPPE + ...EP.P.PPPPPEEE + ..PPPPPPPPPPEEE. + .APPPPPPPPEEEE.E + PPPPPPP..EE..... + NDPPAPEPPP.E..EE + PDNPPEE..EE..... + .PPPE..EEE..E... +} +# tile 651 (shark,female) { ................ ................ @@ -6164,7 +12520,26 @@ Z = (195, 195, 195) PDNPPEE..EE..... .PPPE..EEE..E... } -# tile 323 (giant eel) +# tile 652 (giant eel,male) +{ + ................ + ................ + ................ + ....AAA......... + ...AAOAA...AAA.. + ..AAAAAAA.AA.AA. + ..AAAA.AA.AA.AA. + ...AA..AA.AA..A. + ......AAA..AA.A. + ......AA...AA... + .....AAA.E.AA.E. + ...E.AAEE.AAAE.. + ...E.AAEEAAAEE.. + ..E..AAAAAAE.E.. + ...EE.AAAAE.E... + ..E...EE.E...E.. +} +# tile 653 (giant eel,female) { ................ ................ @@ -6183,7 +12558,26 @@ Z = (195, 195, 195) ...EE.AAAAE.E... ..E...EE.E...E.. } -# tile 324 (electric eel) +# tile 654 (electric eel,male) +{ + ................ + ................ + ................ + ....AAA......... + ...AAOAA........ + ..AAAAAAA....... + ..AAAA.AA....... + ...AA..AA...DD.. + ......AAA..DD... + ......AA...DD... + .....AAA.E.DD.E. + ...E.AAEE.DD.E.. + ...E.AAEEDD.EE.. + ..E..AAADDDE.E.. + ...EE.AAADE.E... + ..E...EE.E...E.. +} +# tile 655 (electric eel,female) { ................ ................ @@ -6202,7 +12596,26 @@ Z = (195, 195, 195) ...EE.AAADE.E... ..E...EE.E...E.. } -# tile 325 (kraken) +# tile 656 (kraken,male) +{ + ................ + ................ + ..FF..FF........ + ..DDFDDF........ + ..FFFFF.....GG.. + ..NCNFF......GFA + ..CC.FF.....EGFA + ....GFAA.GFAEGFE + ...GFFAGFFFFAGFE + ...GFAAFFAGFAEEE + ..GFFAGFFAGFEEE. + EEGFFAGFFAEEEE.E + .EGFFAGFFEE..... + EEGFFEEEEE.E..EE + EEEEEEE..EE..... + ..EEE..EEE..E... +} +# tile 657 (kraken,female) { ................ ................ @@ -6221,7 +12634,26 @@ Z = (195, 195, 195) EEEEEEE..EE..... ..EEE..EEE..E... } -# tile 326 (newt) +# tile 658 (newt,male) +{ + ................ + ................ + ................ + ................ + ................ + ......JKKJ...... + .....CLCCLLC.... + ....LAAAACCLCA.. + .......LCCLLLCA. + ....LCCCLLLAALA. + ....CALLLLAAAA.. + ...LLLLCLAAA.... + ...LLAAALLA..... + ................ + ................ + ................ +} +# tile 659 (newt,female) { ................ ................ @@ -6240,7 +12672,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 327 (gecko) +# tile 660 (gecko,male) +{ + ................ + ................ + ...........LLP.. + ..........LLOOA. + ......PO.LLOOOA. + ......OOALOOOA.. + .......LLOOOA... + ...POALOOOAA.... + ...OOLOOOOOOA... + ....ALOOOAOPA... + ...DOOOOA.AA.... + ...OOOAOOA...... + ...OODAOPA...... + ..F.AA.AA....... + ................ + ................ +} +# tile 661 (gecko,female) { ................ ................ @@ -6259,7 +12710,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 328 (iguana) +# tile 662 (iguana,male) +{ + ................ + ................ + ................ + ................ + ................ + ....GPGPGGPF.... + ..GPAAAAFFGPF... + .GPAA.PFFGPPPAA. + ......FGGPPFPPAA + .PFGGGGPPPFAAPPA + .FGPAPPPPFAAAAA. + .GPPPPFPFAAA.A.. + .PPFFAFPPAA..... + D.AAAAAAPPA..... + ................ + ................ +} +# tile 663 (iguana,female) { ................ ................ @@ -6278,7 +12748,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 329 (baby crocodile) +# tile 664 (baby crocodile,male) +{ + ................ + ................ + ................ + ................ + ................ + .....FFOFOFA.... + ....FOGFGGOFF... + ....GAAAAFOGFA.. + ...FAA.GFOGGGFA. + ...GFOOOGGGFAGA. + ...FGAGGGGFAAA.. + ..FGGGGFGFAA.... + ..GGDFAFGGA..... + ...D............ + ................ + ................ +} +# tile 665 (baby crocodile,female) { ................ ................ @@ -6297,7 +12786,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 330 (lizard) +# tile 666 (lizard,male) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ....FFFFGFJ..... + ..FFAAAJJGFJ.... + ......JGFFJFAA.. + ...JGGGFFJAAFA.. + ..JFAFFFJAAAA... + ..FFFFJJAAA..... + .JFAAAAFAA...... + .D.............. + ................ + ................ +} +# tile 667 (lizard,female) { ................ ................ @@ -6316,7 +12824,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 331 (chameleon) +# tile 668 (chameleon,male) +{ + ................ + ................ + ................ + .....GGGG....... + ...GGGGGGGG..... + ...GGFFFFGGFA... + ..GPAAAGFFGGFA.. + .GPAA.PFFGGGGAA. + ...GGGGGGGGFGGAA + .PGGBBGGGGFAAGGA + .FGGABGGGFAAAAA. + .GGGGGFGFAAA.A.. + .DGFFAFGGAA..... + D.AAAAAAGGA..... + .DD............. + ................ +} +# tile 669 (chameleon,female) { ................ ................ @@ -6335,7 +12862,26 @@ Z = (195, 195, 195) .DD............. ................ } -# tile 332 (crocodile) +# tile 670 (crocodile,male) +{ + ................ + ................ + ................ + ................ + ....FFOFOOFA.... + ...FOGFGFGOFFA.. + ..FGAAAAFFOGFFA. + .FFAA.GFFOGGGGFA + ......FOOGGGGGGA + .G.OOOOGGGGFAGGA + .FOGAGGGGGFAAAA. + FGGGGGFGGFAA.... + GGDDFAFGGGA..... + GDDFAAAAGGA..... + .DF............. + ................ +} +# tile 671 (crocodile,female) { ................ ................ @@ -6354,7 +12900,26 @@ Z = (195, 195, 195) .DF............. ................ } -# tile 333 (salamander) +# tile 672 (salamander,male) +{ + ................ + ................ + ................ + ......CCC....... + ....CCCCCCC..... + ...CCDDDDCCDA... + ....AAAADDCCDA.. + ......KDDCCCCAA. + ..LLLCCCCCCDCCAA + .KLCCCLLLCDAACCA + .DCEECLKKDAAAAA. + DCCAECDKDAAA.A.. + CCCCCCDCCAA..... + .DAADAAACCA..... + ..ACCA.......... + ...AAA.......... +} +# tile 673 (salamander,female) { ................ ................ @@ -6373,7 +12938,26 @@ Z = (195, 195, 195) ..ACCA.......... ...AAA.......... } -# tile 334 (long worm tail) +# tile 674 (long worm tail,male) +{ + ........ILLLL... + ......IILLAA.... + .....ILLAA...... + .....ILA........ + .....ILA........ + ......LLA...II.. + .......LLIIILLLL + ........ILLAAA.L + ...IIIILLALL.... + .ILLLLLAA..LL... + ILLAAAA.....LA.. + ILA.........LA.. + LLA........LLA.. + LILA......LLA... + .LLLIIIILLLA.... + ...LLLLLAAA..... +} +# tile 675 (long worm tail,female) { ........ILLLL... ......IILLAA.... @@ -6392,7 +12976,7 @@ Z = (195, 195, 195) .LLLIIIILLLA.... ...LLLLLAAA..... } -# tile 335 (archeologist) +# tile 676 (archeologist,male) { ................ ................ @@ -6411,7 +12995,49 @@ Z = (195, 195, 195) .....CJJ.JKJ.... ................ } -# tile 336 (barbarian) +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 +# Female archeologist tile is a reference to a certain archeologist +# known for raiding tombs. +# +# tile 677 (archeologist,female) +{ + ................ + ................ + ................ + ......KJJJ...... + ......KKLJ...... + .....KLELE...... + ....KJLLLL...... + ....JJALLA...... + ...JJLBAAPL.AAA. + ...JLLBBBPLLAAA. + ....LABPPPALAAA. + ....LALLLLALAAA. + .....AOJJOAAAA.. + .....KCJAJJA.A.. + .....CJJ.JKJ.... + ................ +} +# tile 678 (barbarian,male) +{ + ................ + ................ + .......HHA...... + ......HHHHA..... + ......LFLFA..... + ......LLLLA..... + ......ALLA...... + .....LLAALL.AAA. + ....LLLLLLLLAAA. + ....LALLLLALAAA. + ....LAALLAALAAA. + ....LAJJKJALAAA. + ......LJJLAAAA.. + ......LLALAA.A.. + .....LLA.LLA.... + ................ +} +# tile 679 (barbarian,female) { ................ ................ @@ -6430,7 +13056,7 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 337 (caveman) +# tile 680 (cave dweller,male) { ................ ................ @@ -6449,7 +13075,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 338 (cavewoman) +# tile 681 (cave dweller,female) { ................ ................ @@ -6468,7 +13094,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 339 (healer) +# tile 682 (healer,male) +{ + ................ + .......NN....... + ......NDDO...... + ......NNNN...... + ......ELEP...... + ......LLLP...... + .......LLP...... + ......O..PA.AAA. + .....NNOOPPAAAA. + ....OOONOPPPAA.. + ....LANOOPALAA.. + ......NOOPAAAA.. + .....NOOOPAA.A.. + ....NOOOOOPA.... + ................ + ................ +} +# tile 683 (healer,female) { ................ .......NN....... @@ -6487,7 +13132,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 340 (knight) +# tile 684 (knight,male) +{ + ................ + ................ + .......BPA...... + ......BPPPA..... + ......PEEPA..... + ......PLLPA..... + ......ALLAA..... + .....BBAABB.AAA. + ....BPPPPPPPAAA. + ....PABPPPAPAAA. + ....LA.PP.ALAAA. + ......BP.PAAAA.. + ......BPAPAA.A.. + .....PPA.PPA.... + ................ + ................ +} +# tile 685 (knight,female) { ................ ................ @@ -6506,7 +13170,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 341 (monk) +# tile 686 (monk,male) +{ + ................ + ................ + .......CCC...... + ......JCJJJA.... + ......CAAAJA.... + ......CAAAJA.... + ......CKLKCAAAA. + .....CDDDDDDAAAA + ....CDDLALDDDAAA + ....DALLALLADAA. + ....DDDDCDDDDAA. + .....AACCCDAAAA. + .....CDCCCDDA.A. + ....CCCCCCCDD... + ................ + ................ +} +# tile 687 (monk,female) { ................ ................ @@ -6525,7 +13208,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 342 (priest) +# tile 688 (cleric,male) { ................ ................ @@ -6535,16 +13218,16 @@ Z = (195, 195, 195) ......ALLJA..... ......IJJIAAAA.. .....ODDDDDAAAA. - ....IDNDDDDDAAA. - ...NLNNNDDALAA.. - ......NDDDAAAA.. + ....INNDDDDDAAA. + ...NLNNDDDALAA.. + ......DDDDAAAA.. ......DIIDAAAA.. .....DDIIDDA.A.. ....DIIIIIDD.... ................ ................ } -# tile 343 (priestess) +# tile 689 (cleric,female) { ................ .......JJ....... @@ -6554,16 +13237,35 @@ Z = (195, 195, 195) .....JJLLJJ..... .....JEJJEJAAA.. .....ODEEDDAAAA. - ....IDINDDDDAAA. - ....L.NNNDALAA.. - ......INDDAAAA.. - ......INDDAAAA.. + ....IDINNDDDAAA. + ....L.DNNDALAA.. + ......IDDDAAAA.. + ......IDDDAAAA.. .....DDIIDDA.A.. ....DIIIIIDD.... ................ ................ } -# tile 344 (ranger) +# tile 690 (ranger,male) +{ + ................ + ................ + ........CJA..... + .......CJJJA.... + .......JEEJA.... + .......JLLJA.... + .......ALLAA.... + ......GGAAGG.AAA + .....BPFFFFPPAAA + .....PAGFFFAPAAA + .....LA.FF.ALAAA + .......BP.PAAAA. + .......BPAPAA.A. + ......PPA.PPA... + ................ + ................ +} +# tile 691 (ranger,female) { ................ ................ @@ -6582,7 +13284,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 345 (rogue) +# tile 692 (rogue,male) +{ + ................ + ................ + ................ + .....OA...OA.... + .....OOIDPPA.... + ......IDDDA..... + ......LKLKA..... + ......LLLLA..... + ......ALLA...... + ......BAABAA..A. + .....KEBBEJAAAA. + ....KAAEEAAKAA.. + ....LAJJHJALAA.. + ......KKJKAAAA.. + .....KKA.KKA.... + ................ +} +# tile 693 (rogue,female) { ................ ................ @@ -6601,7 +13322,26 @@ Z = (195, 195, 195) .....KKA.KKA.... ................ } -# tile 346 (samurai) +# tile 694 (samurai,male) +{ + ................ + ................ + .........AA..... + .......AAA...... + ......AAAAA..... + .....ALFLFA..... + .....ALLLLA..... + ......ALLA...... + ....IIIAAIIIAAA. + ....LDIIIIDLAAA. + ....LABBBBALAAA. + ....LABBBBALAAA. + ......IDDDAAAA.. + ......IDADAA.A.. + .....IIA.IIA.... + ................ +} +# tile 695 (samurai,female) { ................ ................ @@ -6620,7 +13360,26 @@ Z = (195, 195, 195) .....IIA.IIA.... ................ } -# tile 347 (tourist) +# tile 696 (tourist,male) +{ + ................ + ................ + ......JKJJA..... + ......KJJJA..... + ...JJJJJJJJJJ... + ......LFLFAA.... + ......LLLLA..... + ......ALLA...... + .....HGAAGH.AAA. + ....LLGHHGLLAAA. + ....LAHGHGALAAA. + ....LAHHGHALAAA. + ......JJJKAAAA.. + ......LLALAA.A.. + .....LLA.LLA.... + ................ +} +# tile 697 (tourist,female) { ................ ................ @@ -6639,7 +13398,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 348 (valkyrie) +# tile 698 (valkyrie,male) +{ + ................ + ................ + ......LHHL...... + .....HHHHHL..... + ....LHELELH..... + ....HHLLLLH..... + ...HH.AHHA...... + ....JKJHAKJJAAA. + ....LJJKKJJLAAA. + ....LACKJCALAAA. + ....LAAKKAALAAA. + ......KKJKAAAA.. + ......KJAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 699 (valkyrie,female) { ................ ................ @@ -6658,7 +13436,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 349 (wizard) +# tile 700 (wizard,male) +{ + ................ + .........BP..... + .......BBPE..... + ......BPPEA..... + ......BAAEA..... + ......BAAEA..... + ......PLLE...... + ......PAAEA.AAA. + .....BBPBEEAAAA. + ....PPPBEEEEAA.. + ....LABPPEALAA.. + ......BPPEAAAA.. + .....BPPPEAA.A.. + .....BPPPPEA.... + ....BPPPPPPE.... + ................ +} +# tile 701 (wizard,female) { ................ .........BP..... @@ -6677,7 +13474,26 @@ Z = (195, 195, 195) ....BPPPPPPE.... ................ } -# tile 350 (Lord Carnarvon) +# tile 702 (Lord Carnarvon,male) +{ + .......JJ....... + ......KJJJ...... + ....KCKKKJJJ.... + ......LELEA..... + ......LLLLA..... + ......ALLA...... + .....CIAAIK.AAA. + ....CKKIIKKKAAA. + ...KKCKKHKJKKAA. + ...KKAKHKJAKKAA. + ...KAIHKKJIAKA.. + ...LAICKKJIALA.. + .....ICKAJIAAA.. + ......CKAPAAAA.. + .....PPA.PPA.... + ................ +} +# tile 703 (Lord Carnarvon,female) { .......JJ....... ......KJJJ...... @@ -6696,7 +13512,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 351 (Pelias) +# tile 704 (Pelias,male) +{ + ................ + .......JJ....... + ......KKKJ...... + ......LELEA..... + ......LLLLA..... + ......ALLA...... + .....CKAAKK.AAA. + ....CKKKKKKKAAA. + ...KKCKKKKJKKAA. + ...KKAKKKKAKKAA. + ...KA.CKKJAAKA.. + ...LA.CKAJAALA.. + ......CKAJAAAA.. + ......CKAPAAAA.. + .....PPA.PPA.... + ................ +} +# tile 705 (Pelias,female) { ................ .......JJ....... @@ -6715,7 +13550,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 352 (Shaman Karnov) +# tile 706 (Shaman Karnov,male) +{ + ................ + .......JJA...... + ......JJJJA..... + .....JFLFLJ..... + .....JLLLLJ..... + .....JJDDJA..... + ....LHAJJAHLAA.. + ...LLLHAAHLLLAA. + ...LLLLHHLLLLAA. + ...LLALHHLALLAA. + ...LLALLLLALLAA. + ....LACKKJALAAA. + ......CKKJAAAA.. + ......LA.LAA.A.. + .....LLA.LLA.... + ................ +} +# tile 707 (Shaman Karnov,female) { ................ .......JJA...... @@ -6734,7 +13588,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 353 (Earendil) +# tile 708 (Earendil,male) +{ + .........G...... + ....B..GGF..B... + ...BB.GGGGABB... + ..BPBPLELEABPB.. + ..BBBPLLLLABBB.. + ..PBPPALLAPPP... + ...PPBGAAGBBB... + ...BBLGGGFLBBB.. + ..BBLAAGFAALBB.. + ...BLAGGGFALB... + ......GFAF...... + ......L..L.AAA.. + ......AAAAAAAA.. + ....AAAAAAAA.... + .....AAAAAA..... + ................ +} +# tile 709 (Earendil,female) { .........G...... ....B..GGF..B... @@ -6753,7 +13626,26 @@ Z = (195, 195, 195) .....AAAAAA..... ................ } -# tile 354 (Elwing) +# tile 710 (Elwing,male) +{ + .........G...... + ....B..GGF..B... + ...BB.GGGGABB... + ..BPBHLELEHBPB.. + ..BBBHLLLLHBBB.. + ..PBHHALLAHHP... + ...PHHGAAGHHB... + ...BBLGGGFLBBB.. + ..BBLAAGFAALBB.. + ...BLAGGGFALB... + ......GFAF...... + ......L..L.AAA.. + ......AAAAAAAA.. + ....AAAAAAAA.... + .....AAAAAA..... + ................ +} +# tile 711 (Elwing,female) { .........G...... ....B..GGF..B... @@ -6772,7 +13664,26 @@ Z = (195, 195, 195) .....AAAAAA..... ................ } -# tile 355 (Hippocrates) +# tile 712 (Hippocrates,male) +{ + ................ + ....LLLCCD...... + ...LLCCDDA...... + ...LAAAADA...... + ...LBABADA...... + ...LAAAADA...... + ...CCLLDD.B..... + ....CKKDDFBFAAA. + ..LLLCLDDDBFAAA. + .CCCCLDDDFBAAA.. + .LALLCCDDFBDAA.. + ...LCCCCDABFAA.. + ...LCCCCDABAAA.. + ..LLCCCCDAA.AA.. + .LCCCCCCCDA..... + ................ +} +# tile 713 (Hippocrates,female) { ................ ....LLLCCD...... @@ -6791,7 +13702,26 @@ Z = (195, 195, 195) .LCCCCCCCDA..... ................ } -# tile 356 (King Arthur) +# tile 714 (King Arthur,male) +{ + ................ + ................ + ......OHHA...... + .....OHHHHA..... + .....HBLBHA..... + .....HLLLHA..... + .....ALLLAA..... + ....BBAAABB.AAA. + ...BPPPPPPPPAAA. + ...PABPPPPACPAA. + ..NNNNNNNNNCLCA. + .....BPP.PACAA.. + .....BPAPPAA.A.. + .....BPAPPAA.A.. + ....PPAA.PPA.... + ................ +} +# tile 715 (King Arthur,female) { ................ ................ @@ -6810,7 +13740,26 @@ Z = (195, 195, 195) ....PPAA.PPA.... ................ } -# tile 357 (Grand Master) +# tile 716 (Grand Master,male) +{ + ................ + .......LL....... + ......LLLL...... + ......LLLL...... + ..LC.CALLAC..... + .CLLC.CAACCCC... + .CJLACCCCCCCCC.. + ..JAACCCCCCCCCC. + ..JCCCCCCCCCCC.A + ..J..PPPPPLCCAAA + ..J..CCCCLLCAAAA + ..J..CCCCCCCAAAA + ..J..CCCCCCCAAAA + ..J.ACCCCCCCAAA. + ..JACCCCCCCCAA.. + ................ +} +# tile 717 (Grand Master,female) { ................ .......LL....... @@ -6829,7 +13778,26 @@ Z = (195, 195, 195) ..JACCCCCCCCAA.. ................ } -# tile 358 (Arch Priest) +# tile 718 (Arch Priest,male) +{ + ..N............. + .NNN..JLLJ...... + ..N...JLLJ...... + ..N...LLLL...... + ..LC.CALLAC..... + .CLLC.CAACJDK... + .CHLACCCCJCCDK.. + ..HAACCJJCCCCDK. + ..HCCCCJCCJCCC.A + ..H..DCJCCLJCAAA + ..H..DCJCLLCAAAA + ..H..KCJCCDJAAAA + ..H..KCJCCDJAAAA + ..H.ACCJCCDJAAA. + ..HACCCJJCCCAA.. + ................ +} +# tile 719 (Arch Priest,female) { ..N............. .NNN..JLLJ...... @@ -6848,7 +13816,26 @@ Z = (195, 195, 195) ..HACCCJJCCCAA.. ................ } -# tile 359 (Orion) +# tile 720 (Orion,male) +{ + ................ + ................ + .......CJA...... + ......CJJJA..... + ......JEEJA..... + ......JLLJA..... + ......ALLAA..... + .....GGAAGG..... + ....BGFFFFFP.... + ....BPFFFFPPAAA. + ....PAGFFFAPAAA. + ....LANNNNALAAA. + ......BP.PAAAAA. + ......BP.PAAAA.. + ......BPAPAA.A.. + .....PPA.PPA.... +} +# tile 721 (Orion,female) { ................ ................ @@ -6867,7 +13854,26 @@ Z = (195, 195, 195) ......BPAPAA.A.. .....PPA.PPA.... } -# tile 360 (Master of Thieves) +# tile 722 (Master of Thieves,male) +{ + ................ + ...H.....H...... + ...HHIDKHH...... + ....IDDDD....... + ....LLLLLA...... + ....LBLBLA...... + ....LLLLLA...... + .....LLLA....... + ....B.AABAA..... + ...KEBBBEJAAA... + ..KAEEEEEAJAAA.. + ..LAJJHHJALAAA.. + ....JKKKJAAAAA.. + ....KJAJKAAAA... + ...JJA..JJA..... + ................ +} +# tile 723 (Master of Thieves,female) { ................ ...H.....H...... @@ -6886,7 +13892,26 @@ Z = (195, 195, 195) ...JJA..JJA..... ................ } -# tile 361 (Lord Sato) +# tile 724 (Lord Sato,male) +{ + .....AAA........ + .....AAA........ + ...AAAAAAA...... + ..AALLLLLAA..... + ..ALFFLFFLA..... + ..ALLLLLLLA..... + ...AALLLA....... + IIIIIAAAIIIIAAA. + LLDIIIIIIDLLAAA. + LLABBBBBBALLAAA. + LLABBBBBBALLAAA. + LLABBBBBBALLAAA. + ...IIDDDDAAAAAA. + ...IIAAIDAAA..A. + ..IIIA.IIIAA.... + ................ +} +# tile 725 (Lord Sato,female) { .....AAA........ .....AAA........ @@ -6905,7 +13930,26 @@ Z = (195, 195, 195) ..IIIA.IIIAA.... ................ } -# tile 362 (Twoflower) +# tile 726 (Twoflower,male) +{ + ................ + ................ + ......JKJJA..... + ......KJJJA..... + ....JJJJJJJJ.... + .....NNLNNA..... + ....NALNALNA.... + .....NNANNAA.... + .....AAAAAA.AAA. + ....LLHGHGLLAAA. + ....LAGGGGALAAA. + ....LAHGHGALAAA. + ......JJJKAAAA.. + ......JJAKAA.A.. + .....LLA.LLA.... + ................ +} +# tile 727 (Twoflower,female) { ................ ................ @@ -6924,7 +13968,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 363 (Norn) +# tile 728 (Norn,male) +{ + ................ + ................ + ......NNN....... + .....NNNNN...... + .....NELELN..... + ....NNLLLLN..... + ...NNNALLA...... + ...NJKJAAKJJAAA. + ..NNLJJKKJJLAAA. + ..N.LACKJCALAAA. + ....LAKKKKALAAA. + ......KKJKAAAA.. + ......KJAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 729 (Norn,female) { ................ ................ @@ -6943,7 +14006,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 364 (Neferet the Green) +# tile 730 (Neferet the Green,male) +{ + ................ + ................ + ......GGG....... + .....GFFFG...... + ....GFEFEG...... + ....GFFFFEG..... + .N.GPEFFFEE..... + .I..BBEAAEA.AA.. + .I.BBPPBBEEAAAA. + .IGBPPPPPEEEAA.. + .I.PP.EPEAAGAA.. + .I...BPPPAAAAA.. + .N...BPPPEAA.A.. + ....BPPPPPEA.... + ...BPPPPPPPE.... + ................ +} +# tile 731 (Neferet the Green,female) { ................ ................ @@ -6962,7 +14044,26 @@ Z = (195, 195, 195) ...BPPPPPPPE.... ................ } -# tile 365 (Minion of Huhetotl) +# tile 732 (Minion of Huhetotl,male) +{ + ...OP......PO... + ...OODDDDDDOOD.. + ..DLOOCDDCOOLDD. + .DDDLDDDDDDLDDD. + .CCDDDNDDNDDDCC. + CCDKDDDDDDDDJCCC + CDDKKDDIIDDJJCCD + CDDKKKDAADJJDCDD + CCDKDDKKKJDDKCDD + .CCDKKDDDDKKCDDD + .CCDADKDDKDACDD. + .DDDADDDDDDADDD. + ....CCDDDDKKAA.. + ...CDDDAADDDKAA. + ..CDDDAAA.DDDK.. + ................ +} +# tile 733 (Minion of Huhetotl,female) { ...OP......PO... ...OODDDDDDOOD.. @@ -6981,7 +14082,26 @@ Z = (195, 195, 195) ..CDDDAAA.DDDK.. ................ } -# tile 366 (Thoth Amon) +# tile 734 (Thoth Amon,male) +{ + ................ + ......OJJO...... + ......JJJJA..... + ......BLBLA..... + ......LLLLA..... + ......ALLA...... + .....BPAAPP.AAA. + ....BPPPPPPPAAA. + ...PPBPPPPJPPAA. + ...PPAPPP.APPA.A + ...PA.BPP.AAPA.A + ...LA.BPP..AL.A. + ......BPA.A..A.. + ......BPAPAAAA.. + .....PPA.PPA.... + ................ +} +# tile 735 (Thoth Amon,female) { ................ ......OJJO...... @@ -7000,7 +14120,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 367 (Chromatic Dragon) +# tile 736 (Chromatic Dragon,male) +{ + ......GGGFA..... + .....NFNFEEA.... + ....GFFFEECA.... + ..DCHHF..CCA.... + CHCHCD..BCCA.... + HD.D...BFFA..... + ......OBFAAAAAA. + ....HOGFAAAAAAAA + ..HOOIEA.EF.AAA. + .HOOOIEEEEFFJAA. + .HOOOIEEFFFDDAA. + HBOOIIEFFFDDCCA. + HB.OIEFOODD.CJA. + HBAAGE.AADDACCA. + ....GFAA...CCJA. + ........FFFFJA.. +} +# tile 737 (Chromatic Dragon,female) { ......GGGFA..... .....NFNFEEA.... @@ -7019,7 +14158,26 @@ Z = (195, 195, 195) ....GFAA...CCJA. ........FFFFJA.. } -# tile 368 (Goblin King) +# tile 738 (Goblin King,male) +{ + ................ + ................ + .H..H...H....... + CLC.HCHCH....... + CLC.HHHHH....... + .H..IIIII....... + .HK.IHIHI.I..... + .HICKIIIJKK..... + .H.IIJJJK.AA.... + .H..JICJJAAAAA.. + .H..IIIIJAAAAA.. + ....JIIJJAA..... + ....IJKJJA...... + ...IKAA.IK...... + ................ + ................ +} +# tile 739 (Goblin King,female) { ................ ................ @@ -7038,7 +14196,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 369 (Cyclops) +# tile 740 (Cyclops,male) { ................ ....LLLLL....... @@ -7057,26 +14215,85 @@ Z = (195, 195, 195) ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } -# tile 370 (Ixoth) +# tile 741 (Cyclops,female) { - ....O......O.... - ....O......O.... - ...LOOCDDCOOL... - ...DDDDDDDDDDD.. - .CCDDDGDDGDDDCC. - CCDKDDDDDDDDJCCC - CDDKKKDIIDJJDCCD - CDDKDDKJJJDDDCDD - CCDKDDDDDDDDKCDD - .CCDKKDDDDKKCDDD - .CCDADKDDKDACDD. - .DDDADDDDDDADDD. - ....CCDDDDKKAA.. - ...CDDDAADDDKAA. - ..CDDDAAA.DDDK.. + ................ + ....LLLLL....... + ...CLLLLLC...... + ...LBABNNL...... + ...LBBBNNLJA.... + ...CLNNNLCJA.... + ....LLLLLJAAA... + ....LAALLAAAA... + ..JKJLLLKAKJAA.A + .CLKAJJJJAKLCAAA + .LLJKAAAAKJLLAA. + .LAAJKKKKJAALAA. + .LC.GGGHGGACLAAA + .LL.JJJJJJALLAAA + ....CJJJCLAAAAAA + ..LLLLL.LLLLLAA. +} +#: Ixoth is a male red dragon +#: [for many years his tile erroneously depicted a demon] +# tile 742 (Ixoth,male) +{ + ......O......... + ...KJ.DDD.O..... + ..KJODDDKKDD..O. + .KJCDIDKJJJDDDDD + .KJDDDKJJJJJAAA. + .KJDDKJJKJDAAA.. + .CJODCJKJDDDA... + .CJIDCKJDADDA... + .ACDOCKDAAAD.... + .AADDDCDAAAA.... + ..DDDOICOAAA.... + .DDDOODIODA..... + .DDADDDDCDA..... + DDAADGDDGDD..... + DDDAADDDDADD.... + ADD.AADD..AD.... +} +# tile 743 (Ixoth,female) +{ + ......O......... + ...KJ.DDD.O..... + ..KJODDDKKDD..O. + .KJCDIDKJJJDDDDD + .KJDDDKJJJJJAAA. + .KJDDKJJKJDAAA.. + .CJODCJKJDDDA... + .CJIDCKJDADDA... + .ACDOCKDAAAD.... + .AADDDCDAAAA.... + ..DDDOICOAAA.... + .DDDOODIODA..... + .DDADDDDCDA..... + DDAADGDDGDD..... + DDDAADDDDADD.... + ADD.AADD..AD.... +} +# tile 744 (Master Kaen,male) +{ + ................ + .......KKA...... + ......KJJKA..... + ..KKA.KAAKA.KKA. + .KAAKAKDDKAKAAKA + .KOOJKKOOKKKOOJA + .KJJJJJJJJJKJJJA + ..KJJJJJJJJJJJA. + ....KJJJJJJJA... + ......KJJJAAAAAA + .....KJJJJKAAAAA + .....KJJJJJAAAAA + ....KJJJJJJKAAA. + ...KJJJJJJJJKAA. + ...KJJJJJJJJJA.. ................ } -# tile 371 (Master Kaen) +# tile 745 (Master Kaen,female) { ................ .......KKA...... @@ -7095,7 +14312,26 @@ Z = (195, 195, 195) ...KJJJJJJJJJA.. ................ } -# tile 372 (Nalzok) +# tile 746 (Nalzok,male) +{ + ....O......O.... + ....O......O.... + ...LOOCDDCOOL... + ...DDDDDDDDDDD.. + .CCDDDBDDBDDDCC. + CCDKDDDDDDDDJCCC + CDDKKKDIIDJJDCCD + CDDKDDKJJJDDDCDD + CCDKDDDDDDDDKCDD + .CCDKKDDDDKKCDDD + .CCDADKDDKDACDD. + .DDDADDDDDDADDD. + ....CCDDDDKKAA.. + ...CDDDAADDDKAA. + ..CDDDAAA.DDDK.. + ................ +} +# tile 747 (Nalzok,female) { ....O......O.... ....O......O.... @@ -7114,7 +14350,26 @@ Z = (195, 195, 195) ..CDDDAAA.DDDK.. ................ } -# tile 373 (Scorpius) +# tile 748 (Scorpius,male) +{ + .....JLJLJAA.... + ....JA.JCJCKAA.. + ....AJ.....JJJA. + ....LA......LCKA + .JAKJA......JJJA + ..JJA......ALCJA + .......ALLAJCJKA + ....JJALCCAAJJA. + .JJALLAJCJJJAA.. + JA.LCCAJAJJAAAA. + ..JACJJJAAACCJAA + GGJJJJJAACCAAAJA + .JJGGAJACAAJJAAA + D.JJAAJAACA.JAA. + ...D...JAAJA.JJ. + ........JA.JA... +} +# tile 749 (Scorpius,female) { .....JLJLJAA.... ....JA.JCJCKAA.. @@ -7133,7 +14388,26 @@ Z = (195, 195, 195) ...D...JAAJA.JJ. ........JA.JA... } -# tile 374 (Master Assassin) +# tile 750 (Master Assassin,male) +{ + ................ + ................ + ................ + .......AA....... + ......AAAA...... + .....ABLBLA..... + .....AAAAAA..... + ......AAAA...... + .....AAAAAA..PP. + ....AAAAAAAAPPP. + ....AAAAAAAAPPP. + ....LAAAAAALPPP. + ......AAAAAPPP.. + ......AAAAAP.P.. + .....AAA.AAA.... + ................ +} +# tile 751 (Master Assassin,female) { ................ ................ @@ -7152,7 +14426,26 @@ Z = (195, 195, 195) .....AAA.AAA.... ................ } -# tile 375 (Ashikaga Takauji) +# tile 752 (Ashikaga Takauji,male) +{ + ................ + ................ + ......AA........ + .......AAA...... + ......AAAAA..... + .....ALFLFA..... + .....ALLLLA..... + ......ALLA...... + ....IIIAAIIIAAA. + ....LDIIIIDLAAA. + ....LAIIIIALAAA. + ....LALHHLALAAA. + ......IIIIAAAA.. + ......IIAIAA.A.. + .....IIA.IIA.... + ................ +} +# tile 753 (Ashikaga Takauji,female) { ................ ................ @@ -7171,7 +14464,26 @@ Z = (195, 195, 195) .....IIA.IIA.... ................ } -# tile 376 (Lord Surtur) +# tile 754 (Lord Surtur,male) +{ + ....PPDDDDAA.... + ....PDDDDDDDA... + ...PPDLLLLDDA... + ...PDPFLLFFDA... + ...PPPLLLLLDA... + ....PLLAALLAAA.. + ...PPALLLLBAAAA. + ...PPDBBBBBBBAA. + ..BDDHDPBPPPPPA. + ..PPHDDPBPPPPPA. + ..LAHDHPBPPAALAA + JLAADDHBBBBAALAA + JJLJDHHPBPPPCLAA + ..LLJBPPABPPLLAA + .....BPPABPPAAAA + ...LLLLJ.BLLLKAA +} +# tile 755 (Lord Surtur,female) { ....PPDDDDAA.... ....PDDDDDDDA... @@ -7190,7 +14502,7 @@ Z = (195, 195, 195) .....BPPABPPAAAA ...LLLLJ.BLLLKAA } -# tile 377 (Dark One) +# tile 756 (Dark One,male) { ................ ......AAA....... @@ -7209,7 +14521,45 @@ Z = (195, 195, 195) AAAAAAAAAAAAAAAA ................ } -# tile 378 (student) +# tile 757 (Dark One,female) +{ + ................ + ......AAA....... + .....AAAAA...... + .....ADADA...... + .....AAAAA...... + ....AAAAAAA..... + ....AAAAAAA..... + ...AAAAAAAAA.... + ...AAAAAAAAA.... + ..AAAAAAAAAAA... + ..AAAAAAAAAAA... + ...AAAAAAAAA.... + ...AAAAAAAAAA... + ..AAAAAAAAAAAA.. + AAAAAAAAAAAAAAAA + ................ +} +# tile 758 (student,male) +{ + ................ + ................ + .....GGFGG...... + .......G........ + ......NDND...... + ...DDDDDDDD..... + ......LELEA..... + ......LLLLA..... + ......ALLA...... + .....CKAAKJ.AAA. + ....CKKKJJJJAAA. + ....KACKJJAJAAA. + ....LACJKJALAAA. + .....KCJAJJA.A.. + .....CJJ.JKJ.... + ................ +} +# tile 759 (student,female) { ................ ................ @@ -7228,7 +14578,26 @@ Z = (195, 195, 195) .....CJJ.JKJ.... ................ } -# tile 379 (chieftain) +# tile 760 (chieftain,male) +{ + ................ + ................ + .......HHA...... + ......HHHHA..... + ......LFLFA..... + ......LLLLA..... + .....HALLAH..... + ....LLHAAHLLAAA. + ....LLLIILLLAAA. + ....LALIILALAAA. + ....LAALLAALAAA. + ....LAJJKJALAAA. + ......LJJLAAAA.. + ......LLALAA.A.. + .....LLA.LLA.... + ................ +} +# tile 761 (chieftain,female) { ................ ................ @@ -7247,7 +14616,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 380 (neanderthal) +# tile 762 (neanderthal,male) +{ + ................ + ................ + ................ + ......JJJJ...... + .....JJJJJJ..... + .....JFLFLJ..... + .....JLLLLJ..... + .....JJDDJA..... + ....JJAJJAJJ.AA. + ...JLLJAAJLLJAA. + ...LLALJJLALLAA. + ....LALCCLALAAA. + ......LA.LAA.A.. + .....LLA.LLA.... + ................ + ................ +} +# tile 763 (neanderthal,female) { ................ ................ @@ -7266,7 +14654,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 381 (High-elf) +# tile 764 (High-elf,male) +{ + .........G...... + .......GGF...... + ......GGGGA..... + ......LILIA..... + ......LLLLA..... + ......ALLA...... + ......GAAG..AA.. + .....LGGGFLAAAA. + ....LAAGFAALAAA. + ....LA.GFAALAA.. + ....LA.GFAALAA.. + ....LAGGGFAL.A.. + ......GFAFAA.A.. + ......GFAFAA.... + ......GFAFAA.... + .....KLA.LKA.... +} +# tile 765 (High-elf,female) { .........G...... .......GGF...... @@ -7285,7 +14692,26 @@ Z = (195, 195, 195) ......GFAFAA.... .....KLA.LKA.... } -# tile 382 (attendant) +# tile 766 (attendant,male) +{ + ................ + ................ + ................ + ......JJJ....... + .....JLLLJ...... + ......BLB....... + .....CLLLD...... + .....CCKKDA.AAA. + .....LLCLDDAAAA. + ....CCCLDDDDAA.. + ....LALCCDALAA.. + ......LCCDAAAA.. + .....LCCCDAA.A.. + ....LCCCCCDA.... + ................ + ................ +} +# tile 767 (attendant,female) { ................ ................ @@ -7304,7 +14730,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 383 (page) +# tile 768 (page,male) +{ + ................ + ................ + .......BPA...... + ......BPPPA..... + ......PEEPA..... + ......PLLPA..... + .......LLAA..... + ......BAABA.AAA. + .....BPPPPPAAAA. + ....PABPPPAPAAA. + ....LA.PP.ALAAA. + ......BP.PAAAA.. + ......LLALAA.A.. + .....LLA.LLA.... + ................ + ................ +} +# tile 769 (page,female) { ................ ................ @@ -7323,7 +14768,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 384 (abbot) +# tile 770 (abbot,male) +{ + ................ + ................ + ................ + ................ + ................ + ......KLK....... + ......LLL....... + ....CCLLLJJ..... + ....KCKLKKJAAA.. + ....CDDDDDDAAAA. + ...CDDLALDDDAAA. + ...DALLALLADAA.. + ...DDDDCDDDDAA.. + ....AACCCDAAAA.. + ....CDCCCDDA.A.. + ...CCCCCCCDD.... +} +# tile 771 (abbot,female) { ................ ................ @@ -7342,7 +14806,26 @@ Z = (195, 195, 195) ....CDCCCDDA.A.. ...CCCCCCCDD.... } -# tile 385 (acolyte) +# tile 772 (acolyte,male) +{ + ................ + ................ + ................ + ......JJJJ...... + ......JLLJA..... + ......LLLLA..... + ......ALLJA..... + ......CJJCAAAA.. + .....LDDDDDAAAA. + ....CDCCDDDDAAA. + ....L.LCCDALAA.. + ......LCCDAAAA.. + ......LCCDAAAA.. + .....LDCCDDA.A.. + ....LCCCCCDD.... + ................ +} +# tile 773 (acolyte,female) { ................ ................ @@ -7361,7 +14844,26 @@ Z = (195, 195, 195) ....LCCCCCDD.... ................ } -# tile 386 (hunter) +# tile 774 (hunter,male) +{ + ................ + ................ + ................ + ....J..CJA...... + ...J..CJJJA..... + ...J..JEEJA..... + ..J...JLLJA..... + ..J...ALLAA..... + ..J..GGAAGG.AAA. + ..LPBPFFFFPPAAA. + ..J..AGFFFAPAAA. + ..J....FF.ALAAA. + ...J..BP.PAAAA.. + ...J..BPAPAA.A.. + ....JPPA.PPA.... + ................ +} +# tile 775 (hunter,female) { ................ ................ @@ -7380,7 +14882,26 @@ Z = (195, 195, 195) ....JPPA.PPA.... ................ } -# tile 387 (thug) +# tile 776 (thug,male) +{ + ................ + ................ + ................ + .......ID....... + ......IDDDA..... + ......LKLKA..... + ......LLLLA..... + ......ALLA...... + .....KKAAKKA..A. + ....KKJKKJJKAAA. + ....KAAJJAAKAA.. + ....LAJJJJALAA.. + ......KKJKAAAA.. + ......KAAKAAAA.. + .....KKA.KKA.... + ................ +} +# tile 777 (thug,female) { ................ ................ @@ -7399,7 +14920,26 @@ Z = (195, 195, 195) .....KKA.KKA.... ................ } -# tile 388 (ninja) +# tile 778 (ninja,male) +{ + ................ + ................ + .........AA..... + .......AAA...... + ......AAAAA..... + .....AFLFLA..... + .....AAAAAA..... + ......AAAA...... + ....AAAAAAAA.PP. + ....AAAAAAAAPPP. + ....AAAAAAAAPPP. + ....LAAAAAALPPP. + ......AAAAAPPP.. + ......AAAAAP.P.. + .....AAA.AAA.... + ................ +} +# tile 779 (ninja,female) { ................ ................ @@ -7418,7 +14958,26 @@ Z = (195, 195, 195) .....AAA.AAA.... ................ } -# tile 389 (roshi) +# tile 780 (roshi,male) +{ + ................ + ................ + ................ + .......AAAAA.... + ......AAAAA..... + .....ALFLFA..... + .....ALLLLA..... + ......ALLA...... + ....PPPAAPPPAAA. + ....L.PPPP.LAAA. + ....LAOOOOALAAA. + ....LAOOOOALAAA. + ......P...AAAA.. + ......P.A.AA.A.. + .....PPA.PPA.... + ................ +} +# tile 781 (roshi,female) { ................ ................ @@ -7437,7 +14996,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 390 (guide) +# tile 782 (guide,male) +{ + ................ + ................ + ......JKJJA..... + ......KJJJA..... + ....JJJJJJJJ.... + ......LFLFAA.... + ......LLLLA..... + ......ALLA...... + .....HHAAHH.AAA. + ....LLHHHHLLAAA. + ....LAHHHHALAAA. + ....LAHHHHALAAA. + ......JJJKAAAA.. + ......JJAKAA.A.. + .....LLA.LLA.... + ................ +} +# tile 783 (guide,female) { ................ ................ @@ -7456,7 +15034,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 391 (warrior) +# tile 784 (warrior,male) +{ + .....O....O..... + .....NO..ON..... + ......NPPN...... + .....PPPPPP..... + .....PELELP..... + ....HHLLLLH..... + ...HHHALLA...... + ...HJKJAAKJJAAA. + ..HHLJJKKJJLAAA. + ..H.LACKJCALAAA. + ....LAAKKAALAAA. + ......KKJKAAAA.. + ......KJAJAA.A.. + ......KJAJAA.A.. + .....KLA.LKA.... + ................ +} +# tile 785 (warrior,female) { .....O....O..... .....NO..ON..... @@ -7475,7 +15072,26 @@ Z = (195, 195, 195) .....KLA.LKA.... ................ } -# tile 392 (apprentice) +# tile 786 (apprentice,male) +{ + ................ + ................ + ................ + ......JJJ....... + .....JLLLJ...... + ......GLG....... + .....BLLLE...... + .....BBEEEA.AAA. + .....BBPBEEAAAA. + ....PPPBEEEEAA.. + ....LABPPEALAA.. + ......BPPEAAAA.. + .....BPPPEAA.A.. + .....BPPPPEA.... + ....BPPPPPPE.... + ................ +} +# tile 787 (apprentice,female) { ................ ................ @@ -7494,7 +15110,7 @@ Z = (195, 195, 195) ....BPPPPPPE.... ................ } -# tile 393 (invisible monster) +# tile 788 (invisible monster, nogender) { ................ ................ diff --git a/win/Qt/nhicns.uu b/win/share/nhicns.uu similarity index 100% rename from win/Qt/nhicns.uu rename to win/share/nhicns.uu diff --git a/win/Qt/nhsplash.xpm b/win/share/nhsplash.xpm similarity index 100% rename from win/Qt/nhsplash.xpm rename to win/share/nhsplash.xpm diff --git a/win/share/objects.txt b/win/share/objects.txt index 15c6181e8..53ebdcf13 100644 --- a/win/share/objects.txt +++ b/win/share/objects.txt @@ -1,3 +1,6 @@ +# objects.txt - tile definitions for objects +# Note: lines beginning with '# tile ' are not comments; other +# lines beginning with '#' are. . = (71, 108, 108) A = (0, 0, 0) B = (0, 182, 255) @@ -46,7 +49,350 @@ Z = (195, 195, 195) CKKKKKKKKKKJAA.. .AAAAAAAAAAAA... } -# tile 1 (arrow) +#_ after "strange object" come 17 generic objects, one for each object class +# tile 1 (strange / generic strange) +#_ right/close square bracket +{ + ................ + ................ + ................ + ......OOOO...... + .......SSOS..... + .........OS..... + .........OS..... + .........OS..... + .........OS..... + .........OS..... + .........OS..... + ......OOOOS..... + .......SSSS..... + ................ + ................ + ................ +} +# tile 2 (weapon / generic weapon) +#_ right/close parenthesis +{ + ................ + ................ + ................ + ......OO........ + .......SO....... + .........O...... + .........OS..... + .........OS..... + .........OS..... + .........OS..... + ........O.S..... + ......OO.S...... + .......SS....... + ................ + ................ + ................ +} +# tile 3 (armor / generic armor) +#_ left/open square bracket +{ + ................ + ................ + ................ + ......OOOO...... + ......ORRRR..... + ......OR........ + ......OR........ + ......OR........ + ......OR........ + ......OR........ + ......OR........ + ......OOOO...... + .......RRRR..... + ................ + ................ + ................ +} +# tile 4 (ring / generic ring) +#_ circle rather than equal sign +{ + ................ + ................ + ................ + ................ + .......OOO...... + ......O.RRO..... + .....O.R...O.... + .....OR....OR... + .....OR....OR... + ......O...O.R... + .......OOO.R.... + ........RRR..... + ................ + ................ + ................ + ................ +} +# tile 5 (amulet / generic amulet) +#_ double quote +{ + ................ + ................ + ................ + ................ + ......O..O...... + ......OS.OS..... + .....O.SO.S..... + .....OS.OS...... + ....O.SO.S...... + ....OS.OS....... + .....S..S....... + ................ + ................ + ................ + ................ + ................ +} +# tile 6 (tool / generic tool) +#_ left/open parenthesis +{ + ................ + ................ + ................ + ........OO...... + .......O.RR..... + ......O.R....... + ......OR........ + ......OR........ + ......OR........ + ......OR........ + .......O........ + ........OO...... + .........RR..... + ................ + ................ + ................ +} +# tile 7 (food / generic food) +#_ percent sign (almost) +{ + ................ + ................ + ................ + ................ + .....OO.....O... + ....O.SO...O.S.. + ....OS.OS.O.S... + .....OO.SO.S.... + ......SSO.S..... + .......O.SOO.... + ......O.SO.SO... + .....O.S.OS.OS.. + ....O.S...OO.S.. + .....S.....SS... + ................ + ................ +} +# tile 8 (potion / generic potion) +#_ exclamation point +{ + ................ + ................ + ................ + .......O........ + .......OS....... + .......OS....... + .......OS....... + .......OS....... + .......OS....... + .......OS....... + ........S....... + ................ + .......O........ + ........S....... + ................ + ................ +} +# tile 9 (scroll / generic scroll) +#_ question mark (almost) +{ + ................ + ................ + ................ + ......OOO....... + .....O.SSO...... + ......S..OS..... + .........OS..... + ........O.S..... + .......O.S...... + .......OS....... + .......OS....... + ........S....... + .......O........ + ........S....... + ................ + ................ +} +# tile 10 (spellbook / generic spellbook) +#_ plus sign +{ + ................ + ................ + ................ + ................ + ................ + .......O........ + .......OS....... + .......OS....... + ....OOOOOOO..... + .....SSOSSSS.... + .......OS....... + .......OS....... + ........S....... + ................ + ................ + ................ +} +# tile 11 (wand / generic wand) +#_ slash +{ + ................ + ................ + ................ + ...........O.... + ..........O.S... + .........O.S.... + ........O.S..... + .......O.S...... + ......O.S....... + .....O.S........ + ....O.S......... + ...O.S.......... + ....S........... + ................ + ................ + ................ +} +# tile 12 (coin / generic coin) +#_ dollar sign +{ + ................ + ................ + ................ + ........H....... + .......OOO...... + ......O.HSS..... + ......OSH....... + .......OOO...... + ........HSO..... + ........H.OS.... + .......OOO.S.... + ........HSS..... + ................ + ................ + ................ + ................ +} +# tile 13 (gem / generic gem) +#_ asterisk +{ + ................ + ................ + ................ + .......O........ + ....O..OS.O..... + .....O.OSO.S.... + ......O.O.S..... + .......O.S...... + ......O.O....... + .....O.O.O...... + ....O.SOS.O..... + .....S.OS..S.... + ........S....... + ................ + ................ + ................ +} +# tile 14 (large rock / generic large rock) +#_ backtick/grave accent [boulder and statue] +{ + ................ + ................ + ................ + ................ + ................ + .....O.......... + .....OS......... + ......OO........ + .......SO....... + .........S...... + ................ + ................ + ................ + ................ + ................ + ................ +} +# tile 15 (iron ball / generic iron ball) +#_ zero +{ + ................ + ................ + ................ + ................ + ......OOO....... + .....O.SSO...... + .....OS..OS..... + .....OS..OS..... + .....OS..OS..... + .....OS..OS..... + .....OS..OS..... + ......OOO.S..... + .......SSS...... + ................ + ................ + ................ +} +# tile 16 (iron chain / generic iron chain) +#_ underscore (ugh) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ...OOOOOOOOO.... + ....SSSSSSSSS... + ................ + ................ + ................ + ................ +} +# tile 17 (venom / generic venom) +#_ period +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + .......OO....... + .......OOR...... + ........RR...... + ................ + ................ + ................ + ................ +} +#_ end of generic object tiles +#_ start of regular object tiles +# tile 18 (arrow) { ................ ..........PP.... @@ -65,7 +411,7 @@ Z = (195, 195, 195) ..AAA........... ................ } -# tile 2 (runed arrow / elven arrow) +# tile 19 (runed arrow / elven arrow) { ................ ..........FF.... @@ -84,7 +430,7 @@ Z = (195, 195, 195) ..AAA........... ................ } -# tile 3 (crude arrow / orcish arrow) +# tile 20 (crude arrow / orcish arrow) { ................ ..........PP.... @@ -103,7 +449,7 @@ Z = (195, 195, 195) ..AAA........... ................ } -# tile 4 (silver arrow) +# tile 21 (silver arrow) { ................ ..........DP.... @@ -122,7 +468,7 @@ Z = (195, 195, 195) ..AAA........... ................ } -# tile 5 (bamboo arrow / ya) +# tile 22 (bamboo arrow / ya) { ................ ..........BP.... @@ -141,7 +487,7 @@ Z = (195, 195, 195) NNPA............ .AA............. } -# tile 6 (crossbow bolt) +# tile 23 (crossbow bolt) { ................ ................ @@ -160,7 +506,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 7 (dart) +# tile 24 (dart) { ................ ................ @@ -179,7 +525,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 8 (throwing star / shuriken) +# tile 25 (throwing star / shuriken) { ................ ................ @@ -198,7 +544,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 9 (boomerang) +# tile 26 (boomerang) { ................ ................ @@ -217,7 +563,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 10 (spear) +# tile 27 (spear) { ................ ..............N. @@ -236,7 +582,7 @@ Z = (195, 195, 195) ..JAA........... ................ } -# tile 11 (runed spear / elven spear) +# tile 28 (runed spear / elven spear) { ................ ..............N. @@ -255,7 +601,7 @@ Z = (195, 195, 195) ..JAA........... ................ } -# tile 12 (crude spear / orcish spear) +# tile 29 (crude spear / orcish spear) { ................ ..............N. @@ -274,7 +620,7 @@ Z = (195, 195, 195) ..JAA........... ................ } -# tile 13 (stout spear / dwarvish spear) +# tile 30 (stout spear / dwarvish spear) { ................ ................ @@ -293,7 +639,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 14 (silver spear) +# tile 31 (silver spear) { ................ ..............OA @@ -312,7 +658,7 @@ Z = (195, 195, 195) .OA............. ................ } -# tile 15 (throwing spear / javelin) +# tile 32 (throwing spear / javelin) { ................ ..............OA @@ -331,7 +677,7 @@ Z = (195, 195, 195) .OA............. ................ } -# tile 16 (trident) +# tile 33 (trident) { ................ ...PA........... @@ -350,7 +696,7 @@ Z = (195, 195, 195) ............JA.. ................ } -# tile 17 (dagger) +# tile 34 (dagger) { ................ ................ @@ -369,7 +715,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 18 (runed dagger / elven dagger) +# tile 35 (runed dagger / elven dagger) { ................ ................ @@ -388,7 +734,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 19 (crude dagger / orcish dagger) +# tile 36 (crude dagger / orcish dagger) { ................ ................ @@ -407,7 +753,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 20 (silver dagger) +# tile 37 (silver dagger) { ................ ................ @@ -426,7 +772,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 21 (athame) +# tile 38 (athame) { ................ ................ @@ -445,7 +791,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 22 (scalpel) +# tile 39 (scalpel) { ................ ................ @@ -464,7 +810,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 23 (knife) +# tile 40 (knife) { ................ ................ @@ -483,7 +829,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 24 (stiletto) +# tile 41 (stiletto) { ................ ................ @@ -502,7 +848,7 @@ Z = (195, 195, 195) ..AAA........... ................ } -# tile 25 (worm tooth) +# tile 42 (worm tooth) { ................ ................ @@ -521,7 +867,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 26 (crysknife) +# tile 43 (crysknife) { ................ ................ @@ -540,7 +886,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 27 (axe) +# tile 44 (axe) { ................ .....OPA........ @@ -559,7 +905,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 28 (double-headed axe / battle-axe) +# tile 45 (double-headed axe / battle-axe) { ................ ................ @@ -578,7 +924,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 29 (short sword) +# tile 46 (short sword) { ................ ................ @@ -597,7 +943,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 30 (runed short sword / elven short sword) +# tile 47 (runed short sword / elven short sword) { ................ ................ @@ -616,7 +962,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 31 (crude short sword / orcish short sword) +# tile 48 (crude short sword / orcish short sword) { ................ ................ @@ -635,7 +981,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 32 (broad short sword / dwarvish short sword) +# tile 49 (broad short sword / dwarvish short sword) { ................ ................ @@ -654,7 +1000,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 33 (curved sword / scimitar) +# tile 50 (curved sword / scimitar) { ................ ................ @@ -673,7 +1019,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 34 (silver saber) +# tile 51 (silver saber) { ................ ................ @@ -692,7 +1038,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 35 (broadsword) +# tile 52 (broadsword) { ................ ................ @@ -711,7 +1057,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 36 (runed broadsword / elven broadsword) +# tile 53 (runed broadsword / elven broadsword) { ................ ................ @@ -730,7 +1076,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 37 (long sword) +# tile 54 (long sword) { ................ .............O.. @@ -749,7 +1095,7 @@ Z = (195, 195, 195) .AAA............ ................ } -# tile 38 (two-handed sword) +# tile 55 (two-handed sword) { ..............N. .............NO. @@ -768,7 +1114,7 @@ Z = (195, 195, 195) .AAA............ ................ } -# tile 39 (samurai sword / katana) +# tile 56 (samurai sword / katana) { ................ ..............N. @@ -787,7 +1133,7 @@ Z = (195, 195, 195) ..AA............ ................ } -# tile 40 (long samurai sword / tsurugi) +# tile 57 (long samurai sword / tsurugi) { ................ ................ @@ -806,7 +1152,7 @@ Z = (195, 195, 195) ..AA............ ................ } -# tile 41 (runed broadsword / runesword) +# tile 58 (runed broadsword / runesword) { ................ .............A.. @@ -825,7 +1171,7 @@ Z = (195, 195, 195) .PPP............ ................ } -# tile 42 (vulgar polearm / partisan) +# tile 59 (vulgar polearm / partisan) { ................ .............PO. @@ -844,7 +1190,7 @@ Z = (195, 195, 195) .JJAA........... JJAA............ } -# tile 43 (hilted polearm / ranseur) +# tile 60 (hilted polearm / ranseur) { ................ .............PN. @@ -863,7 +1209,7 @@ Z = (195, 195, 195) .JJAA........... JJAA............ } -# tile 44 (forked polearm / spetum) +# tile 61 (forked polearm / spetum) { ................ .............PN. @@ -882,7 +1228,7 @@ Z = (195, 195, 195) .JJAA........... JJAA............ } -# tile 45 (single-edged polearm / glaive) +# tile 62 (single-edged polearm / glaive) { .............KA. ............KNOA @@ -901,26 +1247,7 @@ Z = (195, 195, 195) JAA............. AA.............. } -# tile 46 (lance) -{ - PA.............. - .PA............. - ..BA............ - ...OA........... - ....OA.......... - .....NA......... - ......NA........ - ......PNA....... - .......PNA...... - ........BNA..... - .........ONA.... - ..........NNOOOA - ..........OONOA. - ..........OOONOA - ..........OA.ONO - ..............ON -} -# tile 47 (angled poleaxe / halberd) +# tile 63 (angled poleaxe / halberd) { ................ .........OOOA... @@ -939,7 +1266,7 @@ Z = (195, 195, 195) JJAA............ JAA............. } -# tile 48 (long poleaxe / bardiche) +# tile 64 (long poleaxe / bardiche) { .............NA. ............POPA @@ -958,7 +1285,7 @@ Z = (195, 195, 195) JAA............. ................ } -# tile 49 (pole cleaver / voulge) +# tile 65 (pole cleaver / voulge) { .............NA. ............NNOA @@ -977,26 +1304,7 @@ Z = (195, 195, 195) JAA............. AA.............. } -# tile 50 (broad pick / dwarvish mattock) -{ - ................ - ................ - ......ONOA...... - ........PNOA.... - .........NONA... - ........KJAANA.. - .......KJA...NA. - ......KJA....... - .....KJA........ - ....KJA......... - ...KJA.......... - ..KJA........... - .KJA............ - ................ - ................ - ................ -} -# tile 51 (pole sickle / fauchard) +# tile 66 (pole sickle / fauchard) { ..........NNN... .........NPPPN.. @@ -1015,7 +1323,7 @@ Z = (195, 195, 195) KJA............. .A.............. } -# tile 52 (pruning hook / guisarme) +# tile 67 (pruning hook / guisarme) { .............NA. ............POPA @@ -1034,7 +1342,7 @@ Z = (195, 195, 195) JAA............. AA.............. } -# tile 53 (hooked polearm / bill-guisarme) +# tile 68 (hooked polearm / bill-guisarme) { .............PN. ............PNA. @@ -1053,7 +1361,7 @@ Z = (195, 195, 195) PNPAA........... OPAA............ } -# tile 54 (pronged polearm / lucern hammer) +# tile 69 (pronged polearm / lucern hammer) { .........NP..... .........PNP.... @@ -1072,7 +1380,7 @@ Z = (195, 195, 195) .JJAA........... JJAA............ } -# tile 55 (beaked polearm / bec de corbin) +# tile 70 (beaked polearm / bec de corbin) { ................ ................ @@ -1091,7 +1399,45 @@ Z = (195, 195, 195) ................ ................ } -# tile 56 (mace) +# tile 71 (broad pick / dwarvish mattock) +{ + ................ + ................ + ......ONOA...... + ........PNOA.... + .........NONA... + ........KJAANA.. + .......KJA...NA. + ......KJA....... + .....KJA........ + ....KJA......... + ...KJA.......... + ..KJA........... + .KJA............ + ................ + ................ + ................ +} +# tile 72 (lance) +{ + PA.............. + .PA............. + ..BA............ + ...OA........... + ....OA.......... + .....NA......... + ......NA........ + ......PNA....... + .......PNA...... + ........BNA..... + .........ONA.... + ..........NNOOOA + ..........OONOA. + ..........OOONOA + ..........OA.ONO + ..............ON +} +# tile 73 (mace) { ................ ................ @@ -1110,7 +1456,26 @@ Z = (195, 195, 195) ...A............ ................ } -# tile 57 (morning star) +# tile 74 (silver mace) +{ + ................ + ................ + ................ + .........BPB.... + ........B.N.BP.. + ........PN.N.P.. + ........B.N.BP.. + ........PB.BPP.. + .......KJQPPP... + ......KJA....... + .....KJA........ + ....KJA......... + ...KJA.......... + ..KJA........... + ...A............ + ................ +} +# tile 75 (morning star) { ................ ................ @@ -1129,7 +1494,7 @@ Z = (195, 195, 195) ......KA........ ................ } -# tile 58 (war hammer) +# tile 76 (war hammer) { ..........O..... .........PPOA... @@ -1148,7 +1513,7 @@ Z = (195, 195, 195) .JA............. ................ } -# tile 59 (club) +# tile 77 (club) { ................ ................ @@ -1167,7 +1532,7 @@ Z = (195, 195, 195) .JA............. ................ } -# tile 60 (rubber hose) +# tile 78 (rubber hose) { ................ ................ @@ -1186,7 +1551,7 @@ Z = (195, 195, 195) ....AAA......... ................ } -# tile 61 (staff / quarterstaff) +# tile 79 (staff / quarterstaff) { ................ .............JK. @@ -1205,7 +1570,7 @@ Z = (195, 195, 195) .JJAA........... ..A............. } -# tile 62 (thonged club / aklys) +# tile 80 (thonged club / aklys) { ................ ................ @@ -1220,11 +1585,11 @@ Z = (195, 195, 195) .....KJAA....... .....KAA........ ....KAA......... - .....A.......... - ................ - ................ + .....AOOOOO..... + ......OA.OA..... + .......OOA...... } -# tile 63 (flail) +# tile 81 (flail) { ................ ............KJ.. @@ -1243,7 +1608,7 @@ Z = (195, 195, 195) ..JA............ ................ } -# tile 64 (bullwhip) +# tile 82 (bullwhip) { ................ ................ @@ -1262,7 +1627,7 @@ Z = (195, 195, 195) ......AAA....... ................ } -# tile 65 (bow) +# tile 83 (bow) { ................ .....K.......... @@ -1281,7 +1646,7 @@ Z = (195, 195, 195) .....KAA........ ................ } -# tile 66 (runed bow / elven bow) +# tile 84 (runed bow / elven bow) { .....K.......... .....KP......... @@ -1300,7 +1665,7 @@ Z = (195, 195, 195) .....KPAAA...... .....KAA........ } -# tile 67 (crude bow / orcish bow) +# tile 85 (crude bow / orcish bow) { ................ ................ @@ -1319,7 +1684,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 68 (long bow / yumi) +# tile 86 (long bow / yumi) { .....L.......... .....LP......... @@ -1338,7 +1703,7 @@ Z = (195, 195, 195) .....LPAAA...... .....LAA........ } -# tile 69 (sling) +# tile 87 (sling) { ................ ................ @@ -1357,7 +1722,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 70 (crossbow) +# tile 88 (crossbow) { ................ ................ @@ -1376,7 +1741,7 @@ Z = (195, 195, 195) ........OA...... ................ } -# tile 71 (leather hat / elven leather helm) +# tile 89 (leather hat / elven leather helm) { ................ ................ @@ -1395,7 +1760,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 72 (iron skull cap / orcish helm) +# tile 90 (iron skull cap / orcish helm) { ................ ................ @@ -1414,7 +1779,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 73 (hard hat / dwarvish iron helm) +# tile 91 (hard hat / dwarvish iron helm) { ................ ................ @@ -1433,7 +1798,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 74 (fedora) +# tile 92 (fedora) { ................ ................ @@ -1452,7 +1817,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 75 (conical hat / cornuthaum) +# tile 93 (conical hat / cornuthaum) { ................ .......E........ @@ -1471,7 +1836,7 @@ Z = (195, 195, 195) ....EEEEEEE..... ................ } -# tile 76 (conical hat / dunce cap) +# tile 94 (conical hat / dunce cap) { ................ .......E........ @@ -1490,7 +1855,7 @@ Z = (195, 195, 195) ....EEEEEEE..... ................ } -# tile 77 (dented pot) +# tile 95 (dented pot) { ................ ................ @@ -1509,7 +1874,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 78 (plumed helmet / helmet) +# tile 96 (crystal helmet / helm of brilliance) +{ + ................ + ................ + ................ + ................ + .......N........ + ......NNN....... + .....NIBINA..... + .....IBIBI.A.... + ....N.N.N.NA.... + ....NNNNNNNA.... + ....NANNAANA.... + ....BANNA.BA.... + .......AA..A.... + ................ + ................ + ................ +} +# tile 97 (plumed helmet / helmet) { .......DID...... ......DIBI...... @@ -1528,7 +1912,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 79 (etched helmet / helm of brilliance) +# tile 98 (etched helmet / helm of caution) { ................ ................ @@ -1547,7 +1931,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 80 (crested helmet / helm of opposite alignment) +# tile 99 (crested helmet / helm of opposite alignment) { ................ ................ @@ -1566,7 +1950,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 81 (visored helmet / helm of telepathy) +# tile 100 (visored helmet / helm of telepathy) { ................ ................ @@ -1585,7 +1969,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 82 (gray dragon scale mail) +# tile 101 (gray dragon scale mail) { ................ ................ @@ -1604,7 +1988,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 83 (silver dragon scale mail) +# tile 102 (gold dragon scale mail) +{ + ................ + ................ + ...H.HHHOOO.O... + .H.HHHHHOODOO.O. + .H.HODHOODHODAOA + .H.HDHOODHODDAOA + ..AHHOODHODDDA.A + ...HOODHODDHDA.. + ...HODHODDHDDA.. + ....HHODDHDDAA.. + ...H.HDDHDDAOA.. + ..HHHAHHDDAOOOA. + .HHHDA.HDAAOOOOA + ..HDAA......OOA. + ................ + ................ +} +# tile 103 (silver dragon scale mail) { ................ ................ @@ -1623,7 +2026,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 84 (shimmering dragon scale mail) +# tile 104 (shimmering dragon scale mail) { ................ ................ @@ -1642,7 +2045,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 85 (red dragon scale mail) +# tile 105 (red dragon scale mail) { ................ ................ @@ -1661,7 +2064,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 86 (white dragon scale mail) +# tile 106 (white dragon scale mail) { ................ ................ @@ -1680,7 +2083,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 87 (orange dragon scale mail) +# tile 107 (orange dragon scale mail) { ................ ................ @@ -1699,7 +2102,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 88 (black dragon scale mail) +# tile 108 (black dragon scale mail) { ................ ................ @@ -1718,7 +2121,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 89 (blue dragon scale mail) +# tile 109 (blue dragon scale mail) { ................ ................ @@ -1737,7 +2140,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 90 (green dragon scale mail) +# tile 110 (green dragon scale mail) { ................ ................ @@ -1756,7 +2159,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 91 (yellow dragon scale mail) +# tile 111 (yellow dragon scale mail) { ................ ................ @@ -1775,7 +2178,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 92 (gray dragon scales) +# tile 112 (gray dragon scales) { ................ ................ @@ -1794,7 +2197,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 93 (silver dragon scales) +# tile 113 (gold dragon scales) +{ + ................ + ................ + ................ + ........H....... + .......HDH...... + ....H.HDHDA..... + ...HDH.DHAAD.... + ..HDHHAHAADHA... + ...HDAADHAHAA... + ....AADHAAAA.... + .......AAHA..... + .......HDAA..... + ........AA...... + ................ + ................ + ................ +} +# tile 114 (silver dragon scales) { ................ ................ @@ -1813,7 +2235,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 94 (shimmering dragon scales) +# tile 115 (shimmering dragon scales) { ................ ................ @@ -1832,7 +2254,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 95 (red dragon scales) +# tile 116 (red dragon scales) { ................ ................ @@ -1851,7 +2273,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 96 (white dragon scales) +# tile 117 (white dragon scales) { ................ ................ @@ -1870,7 +2292,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 97 (orange dragon scales) +# tile 118 (orange dragon scales) { ................ ................ @@ -1889,7 +2311,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 98 (black dragon scales) +# tile 119 (black dragon scales) { ................ ................ @@ -1908,7 +2330,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 99 (blue dragon scales) +# tile 120 (blue dragon scales) { ................ ................ @@ -1927,7 +2349,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 100 (green dragon scales) +# tile 121 (green dragon scales) { ................ ................ @@ -1946,7 +2368,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 101 (yellow dragon scales) +# tile 122 (yellow dragon scales) { ................ ................ @@ -1965,7 +2387,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 102 (plate mail) +# tile 123 (plate mail) { ................ ................ @@ -1984,7 +2406,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 103 (crystal plate mail) +# tile 124 (crystal plate mail) { ................ ................ @@ -2003,7 +2425,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 104 (bronze plate mail) +# tile 125 (bronze plate mail) { ................ ................ @@ -2022,7 +2444,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 105 (splint mail) +# tile 126 (splint mail) { ................ ................ @@ -2041,7 +2463,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 106 (banded mail) +# tile 127 (banded mail) { ................ ................ @@ -2060,7 +2482,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 107 (dwarvish mithril-coat) +# tile 128 (dwarvish mithril-coat) { ................ ................ @@ -2079,7 +2501,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 108 (elven mithril-coat) +# tile 129 (elven mithril-coat) { ................ ...N.N.NO.O.O... @@ -2098,7 +2520,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 109 (chain mail) +# tile 130 (chain mail) { ................ ................ @@ -2117,7 +2539,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 110 (crude chain mail / orcish chain mail) +# tile 131 (crude chain mail / orcish chain mail) { ................ ................ @@ -2136,7 +2558,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 111 (scale mail) +# tile 132 (scale mail) { ................ ................ @@ -2155,7 +2577,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 112 (studded leather armor) +# tile 133 (studded leather armor) { ................ ................ @@ -2174,7 +2596,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 113 (ring mail) +# tile 134 (ring mail) { ................ ................ @@ -2193,7 +2615,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 114 (crude ring mail / orcish ring mail) +# tile 135 (crude ring mail / orcish ring mail) { ................ ................ @@ -2212,7 +2634,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 115 (leather armor) +# tile 136 (leather armor) { ................ ................ @@ -2231,7 +2653,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 116 (leather jacket) +# tile 137 (leather jacket) { ................ ................ @@ -2250,7 +2672,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 117 (Hawaiian shirt) +# tile 138 (Hawaiian shirt) { ................ ................ @@ -2269,7 +2691,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 118 (T-shirt) +# tile 139 (T-shirt) { ................ ................ @@ -2288,7 +2710,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 119 (mummy wrapping) +# tile 140 (mummy wrapping) { ................ ................ @@ -2307,7 +2729,7 @@ Z = (195, 195, 195) ..N.AAN.NA.OO... ................ } -# tile 120 (faded pall / elven cloak) +# tile 141 (faded pall / elven cloak) { ................ ................ @@ -2326,7 +2748,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 121 (coarse mantelet / orcish cloak) +# tile 142 (coarse mantelet / orcish cloak) { ................ ................ @@ -2345,7 +2767,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 122 (hooded cloak / dwarvish cloak) +# tile 143 (hooded cloak / dwarvish cloak) { ................ ................ @@ -2364,7 +2786,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 123 (slippery cloak / oilskin cloak) +# tile 144 (slippery cloak / oilskin cloak) { ................ ................ @@ -2383,7 +2805,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 124 (robe) +# tile 145 (robe) { ................ ......CCC....... @@ -2402,7 +2824,7 @@ Z = (195, 195, 195) ...ACCCCCCAAA... ....AAAAAAAA.... } -# tile 125 (apron / alchemy smock) +# tile 146 (apron / alchemy smock) { ................ ................ @@ -2421,7 +2843,7 @@ Z = (195, 195, 195) .....NNNNNAA.... ......AAAAA..... } -# tile 126 (leather cloak) +# tile 147 (leather cloak) { ................ ................ @@ -2440,7 +2862,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 127 (tattered cape / cloak of protection) +# tile 148 (tattered cape / cloak of protection) { ................ ................ @@ -2459,7 +2881,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 128 (opera cloak / cloak of invisibility) +# tile 149 (opera cloak / cloak of invisibility) { ................ ......NNN....... @@ -2478,7 +2900,7 @@ Z = (195, 195, 195) ..AANNNNNNAOOAA. ....AAAAAAAAAA.. } -# tile 129 (ornamental cope / cloak of magic resistance) +# tile 150 (ornamental cope / cloak of magic resistance) { ................ ................ @@ -2497,7 +2919,7 @@ Z = (195, 195, 195) ..AAAAAAAAAAAP.. ...PPPPPPPPPPP.. } -# tile 130 (piece of cloth / cloak of displacement) +# tile 151 (piece of cloth / cloak of displacement) { ................ ................ @@ -2516,7 +2938,26 @@ Z = (195, 195, 195) .....PPPPPAA.... .......PPAA..... } -# tile 131 (small shield) +# tile 152 (wooden shield / small shield) +{ + ................ + ................ + ................ + ................ + ................ + ...C.CJJ.J...... + ...CCKKJJJA..... + ...CKKKJJJA..... + ...CKKJJJJA..... + ...CKKJJJJA..... + ....CKKJJAA..... + .....CKJAA...... + ......CAA....... + .......A........ + ................ + ................ +} +# tile 153 (wooden shield / shield of drain resistance) { ................ ................ @@ -2535,7 +2976,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 132 (blue and green shield / elven shield) +# tile 154 (wooden shield / shield of shock resistance) +{ + ................ + ................ + ................ + ................ + ................ + ...C.CJJ.J...... + ...CCKKJJJA..... + ...CKKKJJJA..... + ...CKKJJJJA..... + ...CKKJJJJA..... + ....CKKJJAA..... + .....CKJAA...... + ......CAA....... + .......A........ + ................ + ................ +} +# tile 155 (blue and green shield / elven shield) { ................ ................ @@ -2554,7 +3014,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 133 (white-handed shield / Uruk-hai shield) +# tile 156 (white-handed shield / Uruk-hai shield) { ................ ...K.KKKJJJ.J... @@ -2573,7 +3033,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 134 (red-eyed shield / orcish shield) +# tile 157 (red-eyed shield / orcish shield) { ................ ................ @@ -2592,7 +3052,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 135 (large shield) +# tile 158 (large shield) { ................ ...N.NNNOOO.O... @@ -2611,7 +3071,7 @@ Z = (195, 195, 195) ........AA...... ................ } -# tile 136 (large round shield / dwarvish roundshield) +# tile 159 (large round shield / dwarvish roundshield) { ................ ................ @@ -2630,7 +3090,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 137 (polished silver shield / shield of reflection) +# tile 160 (polished silver shield / shield of reflection) { ................ ................ @@ -2649,7 +3109,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 138 (old gloves / leather gloves) +# tile 161 (old gloves / leather gloves) { ................ ................ @@ -2668,7 +3128,7 @@ Z = (195, 195, 195) .........AAA.... ................ } -# tile 139 (padded gloves / gauntlets of fumbling) +# tile 162 (padded gloves / gauntlets of fumbling) { ................ ................ @@ -2687,7 +3147,7 @@ Z = (195, 195, 195) .........AAA.... ................ } -# tile 140 (riding gloves / gauntlets of power) +# tile 163 (riding gloves / gauntlets of power) { ................ ................ @@ -2706,7 +3166,7 @@ Z = (195, 195, 195) .........AAA.... ................ } -# tile 141 (fencing gloves / gauntlets of dexterity) +# tile 164 (fencing gloves / gauntlets of dexterity) { ................ ................ @@ -2725,7 +3185,7 @@ Z = (195, 195, 195) .........AAA.... ................ } -# tile 142 (walking shoes / low boots) +# tile 165 (walking shoes / low boots) { ................ ................ @@ -2744,7 +3204,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 143 (hard shoes / iron shoes) +# tile 166 (hard shoes / iron shoes) { ................ ................ @@ -2763,7 +3223,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 144 (jackboots / high boots) +# tile 167 (jackboots / high boots) { .......CCKKKK... ......CKAAAAJJ.. @@ -2782,7 +3242,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 145 (combat boots / speed boots) +# tile 168 (combat boots / speed boots) { ................ ................ @@ -2801,7 +3261,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 146 (jungle boots / water walking boots) +# tile 169 (jungle boots / water walking boots) { ................ ................ @@ -2820,7 +3280,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 147 (hiking boots / jumping boots) +# tile 170 (hiking boots / jumping boots) { ................ ................ @@ -2839,7 +3299,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 148 (mud boots / elven boots) +# tile 171 (mud boots / elven boots) { ................ ................ @@ -2858,7 +3318,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 149 (buckled boots / kicking boots) +# tile 172 (buckled boots / kicking boots) { ................ ................ @@ -2877,7 +3337,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 150 (riding boots / fumble boots) +# tile 173 (riding boots / fumble boots) { ................ ................ @@ -2896,7 +3356,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 151 (snow boots / levitation boots) +# tile 174 (snow boots / levitation boots) { ................ ................ @@ -2915,7 +3375,7 @@ Z = (195, 195, 195) ...A.A.A.A.A.A.. ................ } -# tile 152 (wooden / adornment) +# tile 175 (wooden / adornment) { ................ ................ @@ -2934,7 +3394,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 153 (granite / gain strength) +# tile 176 (granite / gain strength) { ................ ................ @@ -2953,7 +3413,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 154 (opal / gain constitution) +# tile 177 (opal / gain constitution) { ................ ................ @@ -2972,7 +3432,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 155 (clay / increase accuracy) +# tile 178 (clay / increase accuracy) { ................ ................ @@ -2991,7 +3451,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 156 (coral / increase damage) +# tile 179 (coral / increase damage) { ................ ................ @@ -3010,7 +3470,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 157 (black onyx / protection) +# tile 180 (black onyx / protection) { ................ ................ @@ -3029,7 +3489,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 158 (moonstone / regeneration) +# tile 181 (moonstone / regeneration) { ................ ................ @@ -3048,7 +3508,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 159 (tiger eye / searching) +# tile 182 (tiger eye / searching) { ................ ................ @@ -3067,7 +3527,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 160 (jade / stealth) +# tile 183 (jade / stealth) { ................ ................ @@ -3086,7 +3546,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 161 (bronze / sustain ability) +# tile 184 (bronze / sustain ability) { ................ ................ @@ -3105,7 +3565,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 162 (agate / levitation) +# tile 185 (agate / levitation) { ................ ................ @@ -3124,7 +3584,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 163 (topaz / hunger) +# tile 186 (topaz / hunger) { ................ ................ @@ -3143,7 +3603,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 164 (sapphire / aggravate monster) +# tile 187 (sapphire / aggravate monster) { ................ ................ @@ -3162,7 +3622,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 165 (ruby / conflict) +# tile 188 (ruby / conflict) { ................ ................ @@ -3181,7 +3641,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 166 (diamond / warning) +# tile 189 (diamond / warning) { ................ ................ @@ -3200,7 +3660,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 167 (pearl / poison resistance) +# tile 190 (pearl / poison resistance) { ................ ................ @@ -3219,7 +3679,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 168 (iron / fire resistance) +# tile 191 (iron / fire resistance) { ................ ................ @@ -3238,7 +3698,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 169 (brass / cold resistance) +# tile 192 (brass / cold resistance) { ................ ................ @@ -3257,7 +3717,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 170 (copper / shock resistance) +# tile 193 (copper / shock resistance) { ................ ................ @@ -3276,7 +3736,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 171 (twisted / free action) +# tile 194 (twisted / free action) { ................ ................ @@ -3295,7 +3755,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 172 (steel / slow digestion) +# tile 195 (steel / slow digestion) { ................ ................ @@ -3314,7 +3774,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 173 (silver / teleportation) +# tile 196 (silver / teleportation) { ................ ................ @@ -3333,7 +3793,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 174 (gold / teleport control) +# tile 197 (gold / teleport control) { ................ ................ @@ -3352,7 +3812,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 175 (ivory / polymorph) +# tile 198 (ivory / polymorph) { ................ ................ @@ -3371,7 +3831,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 176 (emerald / polymorph control) +# tile 199 (emerald / polymorph control) { ................ ................ @@ -3390,7 +3850,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 177 (wire / invisibility) +# tile 200 (wire / invisibility) { ................ ................ @@ -3409,7 +3869,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 178 (engagement / see invisible) +# tile 201 (engagement / see invisible) { ................ ................ @@ -3428,7 +3888,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 179 (shiny / protection from shape changers) +# tile 202 (shiny / protection from shape changers) { ................ ................ @@ -3447,7 +3907,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 180 (circular / amulet of ESP) +# tile 203 (circular / amulet of ESP) { ................ ......LLLLLAA... @@ -3466,7 +3926,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 181 (spherical / amulet of life saving) +# tile 204 (spherical / amulet of life saving) { ................ ......LLLLLAA... @@ -3485,7 +3945,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 182 (oval / amulet of strangulation) +# tile 205 (oval / amulet of strangulation) { ................ ......LLLLLLAA.. @@ -3504,7 +3964,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 183 (triangular / amulet of restful sleep) +# tile 206 (triangular / amulet of restful sleep) { ................ ......LLLLLAA... @@ -3523,7 +3983,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 184 (pyramidal / amulet versus poison) +# tile 207 (pyramidal / amulet versus poison) { ................ ......LLLLLAA... @@ -3542,7 +4002,7 @@ Z = (195, 195, 195) ....KJJJJJJJJA.. .......AAAAAAA.. } -# tile 185 (square / amulet of change) +# tile 208 (square / amulet of change) { ................ ......LLLLLAA... @@ -3561,7 +4021,7 @@ Z = (195, 195, 195) .......AAAAA.... ................ } -# tile 186 (concave / amulet of unchanging) +# tile 209 (concave / amulet of unchanging) { ................ ......LLLLLAA... @@ -3580,7 +4040,7 @@ Z = (195, 195, 195) .......KCCAA.... ........AAA..... } -# tile 187 (hexagonal / amulet of reflection) +# tile 210 (hexagonal / amulet of reflection) { ................ ......LLLLLAA... @@ -3599,7 +4059,7 @@ Z = (195, 195, 195) ........AAA..... ................ } -# tile 188 (octagonal / amulet of magical breathing) +# tile 211 (octagonal / amulet of magical breathing) { ................ ......LLLLLAA... @@ -3618,7 +4078,45 @@ Z = (195, 195, 195) .......KKKAA.... ........AAA..... } -# tile 189 (Amulet of Yendor / cheap plastic imitation of the Amulet of Yendor) +# tile 212 (perforated / amulet of guarding) +{ + ................ + ......LLLLLAA... + .....LAA...LAA.. + ....LAA.....LAA. + ....LAA.....LAA. + ....LAA.....LAA. + ....LAA.....LAA. + .....LAA...LAA.. + ......LAA.LAA... + ......ACCCAA.... + ......CKKKKAA... + .....CKAKAKKA... + .....CKKAKAKA... + ......KAKAKAA... + .......KKKAA.... + ........AAA..... +} +# tile 213 (cubical / amulet of flying) +{ + ................ + ......LLLLLAA... + .....LAA...LAA.. + ....LAA.....LAA. + ....LAA.....LAA. + ....LAA.....LAA. + ....LAA.....LAA. + .....LAA...LAA.. + ......LAA.LAA... + .......LAL...... + .....KKLKL...... + .....KCCCCCA.... + .....KCKKKKA.... + .....KCKKKKA.... + ......CKKKKA.... + .......AAAAA.... +} +# tile 214 (Amulet of Yendor / cheap plastic imitation of the Amulet of Yendor) { ................ ......HHHHHAA... @@ -3637,7 +4135,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 190 (Amulet of Yendor / Amulet of Yendor) +# tile 215 (Amulet of Yendor / Amulet of Yendor) { ................ ......HHHHHAA... @@ -3656,7 +4154,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 191 (large box) +# tile 216 (large box) { ................ ................ @@ -3675,7 +4173,7 @@ Z = (195, 195, 195) CKKKKKKKKKKJAA.. .AAAAAAAAAAAA... } -# tile 192 (chest) +# tile 217 (chest) { ................ ................ @@ -3694,7 +4192,7 @@ Z = (195, 195, 195) CKKKKKKKKKKJAA.. .AAAAAAAAAAAA... } -# tile 193 (ice box) +# tile 218 (ice box) { ................ ................ @@ -3713,7 +4211,7 @@ Z = (195, 195, 195) NBBBBBBBBBBPAA.. .AAAAAAAAAAAA... } -# tile 194 (bag / sack) +# tile 219 (bag / sack) { ................ ................ @@ -3732,7 +4230,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 195 (bag / oilskin sack) +# tile 220 (bag / oilskin sack) { ................ ................ @@ -3751,7 +4249,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 196 (bag / bag of holding) +# tile 221 (bag / bag of holding) { ................ ................ @@ -3770,7 +4268,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 197 (bag / bag of tricks) +# tile 222 (bag / bag of tricks) { ................ ................ @@ -3789,7 +4287,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 198 (key / skeleton key) +# tile 223 (key / skeleton key) { ................ ................ @@ -3808,7 +4306,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 199 (lock pick) +# tile 224 (lock pick) { ................ ................ @@ -3827,7 +4325,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 200 (credit card) +# tile 225 (credit card) { ................ ................ @@ -3846,7 +4344,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 201 (candle / tallow candle) +# tile 226 (candle / tallow candle) { ................ ................ @@ -3865,7 +4363,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 202 (candle / wax candle) +# tile 227 (candle / wax candle) { ................ ................ @@ -3884,7 +4382,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 203 (brass lantern) +# tile 228 (brass lantern) { ................ ................ @@ -3903,7 +4401,7 @@ Z = (195, 195, 195) .....AAAAAAA.... ................ } -# tile 204 (lamp / oil lamp) +# tile 229 (lamp / oil lamp) { ................ ................ @@ -3922,7 +4420,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 205 (lamp / magic lamp) +# tile 230 (lamp / magic lamp) { ................ ................ @@ -3941,7 +4439,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 206 (expensive camera) +# tile 231 (expensive camera) { ................ ................ @@ -3960,7 +4458,7 @@ Z = (195, 195, 195) ...PPPPPPPPPPPP. ................ } -# tile 207 (looking glass / mirror) +# tile 232 (looking glass / mirror) { ................ ................ @@ -3979,7 +4477,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 208 (glass orb / crystal ball) +# tile 233 (glass orb / crystal ball) { ................ ................ @@ -3998,7 +4496,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 209 (lenses) +# tile 234 (lenses) { ................ ................ @@ -4017,7 +4515,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 210 (blindfold) +# tile 235 (blindfold) { ................ ................ @@ -4036,7 +4534,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 211 (towel) +# tile 236 (towel) { ................ ................ @@ -4055,7 +4553,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 212 (saddle) +# tile 237 (saddle) { ................ ................ @@ -4074,7 +4572,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 213 (leash) +# tile 238 (leash) { ................ ................ @@ -4093,7 +4591,7 @@ Z = (195, 195, 195) .....AAAA....... ................ } -# tile 214 (stethoscope) +# tile 239 (stethoscope) { ................ ................ @@ -4112,7 +4610,7 @@ Z = (195, 195, 195) ........AAA..... ................ } -# tile 215 (tinning kit) +# tile 240 (tinning kit) { ................ ................ @@ -4131,7 +4629,7 @@ Z = (195, 195, 195) ......AAA....... ................ } -# tile 216 (tin opener) +# tile 241 (tin opener) { ................ ................ @@ -4150,7 +4648,7 @@ Z = (195, 195, 195) ........AA...... ................ } -# tile 217 (can of grease) +# tile 242 (can of grease) { ................ ................ @@ -4169,7 +4667,7 @@ Z = (195, 195, 195) .......AAAA..... ................ } -# tile 218 (figurine) +# tile 243 (figurine) { ................ ................ @@ -4188,7 +4686,7 @@ Z = (195, 195, 195) .....JJJJJAA.... ................ } -# tile 219 (magic marker) +# tile 244 (magic marker) { ................ ................ @@ -4207,7 +4705,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 220 (land mine) +# tile 245 (land mine) { ................ ................ @@ -4226,7 +4724,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 221 (beartrap) +# tile 246 (beartrap) { ................ ................ @@ -4245,7 +4743,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 222 (whistle / tin whistle) +# tile 247 (whistle / tin whistle) { ................ ................ @@ -4264,7 +4762,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 223 (whistle / magic whistle) +# tile 248 (whistle / magic whistle) { ................ ................ @@ -4283,7 +4781,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 224 (flute / wooden flute) +# tile 249 (flute / wooden flute) { ................ ................ @@ -4302,7 +4800,7 @@ Z = (195, 195, 195) ..A............. ................ } -# tile 225 (flute / magic flute) +# tile 250 (flute / magic flute) { ................ ................ @@ -4321,7 +4819,7 @@ Z = (195, 195, 195) ..A............. ................ } -# tile 226 (horn / tooled horn) +# tile 251 (horn / tooled horn) { ................ ................ @@ -4340,7 +4838,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 227 (horn / frost horn) +# tile 252 (horn / frost horn) { ................ ................ @@ -4359,7 +4857,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 228 (horn / fire horn) +# tile 253 (horn / fire horn) { ................ ................ @@ -4378,7 +4876,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 229 (horn / horn of plenty) +# tile 254 (horn / horn of plenty) { ................ ................ @@ -4397,7 +4895,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 230 (harp / wooden harp) +# tile 255 (harp / wooden harp) { ................ ................ @@ -4416,7 +4914,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 231 (harp / magic harp) +# tile 256 (harp / magic harp) { ................ ................ @@ -4435,7 +4933,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 232 (bell) +# tile 257 (bell) { ................ .......KA....... @@ -4454,7 +4952,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 233 (bugle) +# tile 258 (bugle) { ................ ................ @@ -4473,7 +4971,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 234 (drum / leather drum) +# tile 259 (drum / leather drum) { ................ ................ @@ -4492,7 +4990,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 235 (drum / drum of earthquake) +# tile 260 (drum / drum of earthquake) { ................ ................ @@ -4511,7 +5009,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 236 (pick-axe) +# tile 261 (pick-axe) { ................ ................ @@ -4530,7 +5028,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 237 (iron hook / grappling hook) +# tile 262 (grappling hook) { .............N.. ..............P. @@ -4549,7 +5047,7 @@ Z = (195, 195, 195) ..OOA..OOOA..... ....OOOAA....... } -# tile 238 (unicorn horn) +# tile 263 (unicorn horn) { ................ ................ @@ -4568,7 +5066,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 239 (candelabrum / Candelabrum of Invocation) +# tile 264 (candelabrum / Candelabrum of Invocation) { .......N........ .......D........ @@ -4587,7 +5085,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 240 (silver bell / Bell of Opening) +# tile 265 (silver bell / Bell of Opening) { ................ .......OA....... @@ -4606,7 +5104,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 241 (tripe ration) +# tile 266 (tripe ration) { ................ ................ @@ -4625,7 +5123,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 242 (corpse) +# tile 267 (corpse) { ................ .....D.DPLN..... @@ -4644,7 +5142,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 243 (egg) +# tile 268 (egg) { ................ ................ @@ -4663,7 +5161,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 244 (meatball) +# tile 269 (meatball) { ................ ................ @@ -4682,7 +5180,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 245 (meat stick) +# tile 270 (meat stick) { ................ ................ @@ -4701,7 +5199,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 246 (huge chunk of meat) +# tile 271 (enormous meatball) { ................ ................ @@ -4720,7 +5218,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 247 (meat ring) +# tile 272 (meat ring) { ................ ................ @@ -4739,7 +5237,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 248 (glob of gray ooze) +# tile 273 (glob of gray ooze) { ................ ................ @@ -4758,7 +5256,7 @@ Z = (195, 195, 195) ...AAA.AAAAA.... ................ } -# tile 249 (glob of brown pudding) +# tile 274 (glob of brown pudding) { ................ ................ @@ -4777,7 +5275,7 @@ Z = (195, 195, 195) ...AAA.AAAAA.... ................ } -# tile 250 (glob of green slime) +# tile 275 (glob of green slime) { ................ ................ @@ -4796,7 +5294,7 @@ Z = (195, 195, 195) ...AAA.AAAAA.... ................ } -# tile 251 (glob of black pudding) +# tile 276 (glob of black pudding) { ................ ................ @@ -4815,7 +5313,7 @@ Z = (195, 195, 195) ...AAA.AAAAA.... ................ } -# tile 252 (kelp frond) +# tile 277 (kelp frond) { ....FA.......... ....FFA......... @@ -4834,7 +5332,7 @@ Z = (195, 195, 195) .....FFFFA...... ......FFFFA..... } -# tile 253 (eucalyptus leaf) +# tile 278 (eucalyptus leaf) { ................ ................ @@ -4853,7 +5351,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 254 (apple) +# tile 279 (apple) { ................ ................ @@ -4872,7 +5370,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 255 (orange) +# tile 280 (orange) { ................ ................ @@ -4891,7 +5389,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 256 (pear) +# tile 281 (pear) { ................ ................ @@ -4910,7 +5408,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 257 (melon) +# tile 282 (melon) { ................ ................ @@ -4929,7 +5427,7 @@ Z = (195, 195, 195) ......AAA....... ................ } -# tile 258 (banana) +# tile 283 (banana) { ................ ................ @@ -4948,7 +5446,7 @@ Z = (195, 195, 195) .....AAAAA...... ................ } -# tile 259 (carrot) +# tile 284 (carrot) { ................ ..........F..F.. @@ -4967,7 +5465,7 @@ Z = (195, 195, 195) ...A............ ................ } -# tile 260 (sprig of wolfsbane) +# tile 285 (sprig of wolfsbane) { ................ ................ @@ -4986,7 +5484,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 261 (clove of garlic) +# tile 286 (clove of garlic) { ................ ................ @@ -5005,7 +5503,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 262 (slime mold) +# tile 287 (slime mold) { ................ ................ @@ -5024,7 +5522,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 263 (lump of royal jelly) +# tile 288 (lump of royal jelly) { ................ ................ @@ -5043,7 +5541,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 264 (cream pie) +# tile 289 (cream pie) { ................ ................ @@ -5062,7 +5560,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 265 (candy bar) +# tile 290 (candy bar) { ................ ................ @@ -5081,7 +5579,7 @@ Z = (195, 195, 195) ....A........... ................ } -# tile 266 (fortune cookie) +# tile 291 (fortune cookie) { ................ ................ @@ -5100,7 +5598,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 267 (pancake) +# tile 292 (pancake) { ................ ................ @@ -5119,7 +5617,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 268 (lembas wafer) +# tile 293 (lembas wafer) { ................ ................ @@ -5138,7 +5636,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 269 (cram ration) +# tile 294 (cram ration) { ................ ...JKA.......... @@ -5157,7 +5655,7 @@ Z = (195, 195, 195) .....AAAAAA..... ................ } -# tile 270 (food ration) +# tile 295 (food ration) { ...JJA.......... ...BPA.......... @@ -5176,7 +5674,7 @@ Z = (195, 195, 195) ....KKKKKKKKKA.. .....AAAAAAAA... } -# tile 271 (K-ration) +# tile 296 (K-ration) { ................ ................ @@ -5195,7 +5693,7 @@ Z = (195, 195, 195) ....KKKKKKKKKA.. .....AAAAAAAA... } -# tile 272 (C-ration) +# tile 297 (C-ration) { ................ ................ @@ -5214,7 +5712,7 @@ Z = (195, 195, 195) ....KKKKKKKKKA.. .....AAAAAAAA... } -# tile 273 (tin) +# tile 298 (tin) { ................ ................ @@ -5233,7 +5731,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 274 (ruby / gain ability) +# tile 299 (ruby / gain ability) { ................ ................ @@ -5252,7 +5750,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 275 (pink / restore ability) +# tile 300 (pink / restore ability) { ................ ................ @@ -5271,7 +5769,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 276 (orange / confusion) +# tile 301 (orange / confusion) { ................ ................ @@ -5290,7 +5788,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 277 (yellow / blindness) +# tile 302 (yellow / blindness) { ................ ................ @@ -5309,7 +5807,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 278 (emerald / paralysis) +# tile 303 (emerald / paralysis) { ................ ................ @@ -5328,7 +5826,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 279 (dark green / speed) +# tile 304 (dark green / speed) { ................ ................ @@ -5347,7 +5845,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 280 (cyan / levitation) +# tile 305 (cyan / levitation) { ................ ................ @@ -5366,7 +5864,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 281 (sky blue / hallucination) +# tile 306 (sky blue / hallucination) { ................ ................ @@ -5385,7 +5883,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 282 (brilliant blue / invisibility) +# tile 307 (brilliant blue / invisibility) { ................ ................ @@ -5404,7 +5902,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 283 (magenta / see invisible) +# tile 308 (magenta / see invisible) { ................ ................ @@ -5423,7 +5921,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 284 (purple-red / healing) +# tile 309 (purple-red / healing) { ................ ................ @@ -5442,7 +5940,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 285 (puce / extra healing) +# tile 310 (puce / extra healing) { ................ ................ @@ -5461,7 +5959,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 286 (milky / gain level) +# tile 311 (milky / gain level) { ................ ................ @@ -5480,7 +5978,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 287 (swirly / enlightenment) +# tile 312 (swirly / enlightenment) { ................ ................ @@ -5499,7 +5997,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 288 (bubbly / monster detection) +# tile 313 (bubbly / monster detection) { ................ ................ @@ -5518,7 +6016,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 289 (smoky / object detection) +# tile 314 (smoky / object detection) { ................ ................ @@ -5537,7 +6035,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 290 (cloudy / gain energy) +# tile 315 (cloudy / gain energy) { ................ ................ @@ -5556,7 +6054,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 291 (effervescent / sleeping) +# tile 316 (effervescent / sleeping) { ................ ................ @@ -5575,7 +6073,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 292 (black / full healing) +# tile 317 (black / full healing) { ................ ................ @@ -5594,7 +6092,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 293 (golden / polymorph) +# tile 318 (golden / polymorph) { ................ ................ @@ -5613,7 +6111,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 294 (brown / booze) +# tile 319 (brown / booze) { ................ ................ @@ -5632,7 +6130,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 295 (fizzy / sickness) +# tile 320 (fizzy / sickness) { ................ ................ @@ -5651,7 +6149,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 296 (dark / fruit juice) +# tile 321 (dark / fruit juice) { ................ ................ @@ -5670,7 +6168,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 297 (white / acid) +# tile 322 (white / acid) { ................ ................ @@ -5689,7 +6187,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 298 (murky / oil) +# tile 323 (murky / oil) { ................ ................ @@ -5708,7 +6206,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 299 (clear / water) +# tile 324 (clear / water) { ................ ................ @@ -5727,7 +6225,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 300 (ZELGO MER / enchant armor) +# tile 325 (ZELGO MER / enchant armor) { ................ ................ @@ -5746,7 +6244,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 301 (JUYED AWK YACC / destroy armor) +# tile 326 (JUYED AWK YACC / destroy armor) { ................ ................ @@ -5765,7 +6263,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 302 (NR 9 / confuse monster) +# tile 327 (NR 9 / confuse monster) { ................ ................ @@ -5784,7 +6282,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 303 (XIXAXA XOXAXA XUXAXA / scare monster) +# tile 328 (XIXAXA XOXAXA XUXAXA / scare monster) { ................ ................ @@ -5803,7 +6301,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 304 (PRATYAVAYAH / remove curse) +# tile 329 (PRATYAVAYAH / remove curse) { ................ ................ @@ -5822,7 +6320,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 305 (DAIYEN FOOELS / enchant weapon) +# tile 330 (DAIYEN FOOELS / enchant weapon) { ................ ................ @@ -5841,7 +6339,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 306 (LEP GEX VEN ZEA / create monster) +# tile 331 (LEP GEX VEN ZEA / create monster) { ................ ................ @@ -5860,7 +6358,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 307 (PRIRUTSENIE / taming) +# tile 332 (PRIRUTSENIE / taming) { ................ ................ @@ -5879,7 +6377,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 308 (ELBIB YLOH / genocide) +# tile 333 (ELBIB YLOH / genocide) { ................ ................ @@ -5898,7 +6396,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 309 (VERR YED HORRE / light) +# tile 334 (VERR YED HORRE / light) { ................ ................ @@ -5917,7 +6415,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 310 (VENZAR BORGAVVE / teleportation) +# tile 335 (VENZAR BORGAVVE / teleportation) { ................ ................ @@ -5936,7 +6434,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 311 (THARR / gold detection) +# tile 336 (THARR / gold detection) { ................ ................ @@ -5955,7 +6453,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 312 (YUM YUM / food detection) +# tile 337 (YUM YUM / food detection) { ................ ................ @@ -5974,7 +6472,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 313 (KERNOD WEL / identify) +# tile 338 (KERNOD WEL / identify) { ................ ................ @@ -5993,7 +6491,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 314 (ELAM EBOW / magic mapping) +# tile 339 (ELAM EBOW / magic mapping) { ................ ................ @@ -6012,7 +6510,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 315 (DUAM XNAHT / amnesia) +# tile 340 (DUAM XNAHT / amnesia) { ................ ................ @@ -6031,7 +6529,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 316 (ANDOVA BEGARIN / fire) +# tile 341 (ANDOVA BEGARIN / fire) { ................ ................ @@ -6050,7 +6548,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 317 (KIRJE / earth) +# tile 342 (KIRJE / earth) { ................ ................ @@ -6069,7 +6567,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 318 (VE FORBRYDERNE / punishment) +# tile 343 (VE FORBRYDERNE / punishment) { ................ ................ @@ -6088,7 +6586,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 319 (HACKEM MUCHE / charging) +# tile 344 (HACKEM MUCHE / charging) { ................ ................ @@ -6107,7 +6605,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 320 (VELOX NEB / stinking cloud) +# tile 345 (VELOX NEB / stinking cloud) { ................ ................ @@ -6126,7 +6624,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 321 (FOOBIE BLETCH) +# tile 346 (FOOBIE BLETCH) { ................ ................ @@ -6145,7 +6643,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 322 (TEMOV) +# tile 347 (TEMOV) { ................ ................ @@ -6164,7 +6662,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 323 (GARVEN DEH) +# tile 348 (GARVEN DEH) { ................ ................ @@ -6183,7 +6681,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 324 (READ ME) +# tile 349 (READ ME) { ................ ................ @@ -6202,7 +6700,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 325 (ETAOIN SHRDLU) +# tile 350 (ETAOIN SHRDLU) { ................ ................ @@ -6221,7 +6719,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 326 (LOREM IPSUM) +# tile 351 (LOREM IPSUM) { ................ ................ @@ -6240,7 +6738,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 327 (FNORD) +# tile 352 (FNORD) { ................ ................ @@ -6259,7 +6757,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 328 (KO BATE) +# tile 353 (KO BATE) { ................ ................ @@ -6278,7 +6776,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 329 (ABRA KA DABRA) +# tile 354 (ABRA KA DABRA) { ................ ................ @@ -6297,7 +6795,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 330 (ASHPD SODALG) +# tile 355 (ASHPD SODALG) { ................ ................ @@ -6316,7 +6814,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 331 (ZLORFIK) +# tile 356 (ZLORFIK) { ................ ................ @@ -6335,7 +6833,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 332 (GNIK SISI VLE) +# tile 357 (GNIK SISI VLE) { ................ ................ @@ -6354,7 +6852,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 333 (HAPAX LEGOMENON) +# tile 358 (HAPAX LEGOMENON) { ................ ................ @@ -6373,7 +6871,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 334 (EIRIS SAZUN IDISI) +# tile 359 (EIRIS SAZUN IDISI) { ................ ................ @@ -6392,7 +6890,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 335 (PHOL ENDE WODAN) +# tile 360 (PHOL ENDE WODAN) { ................ ................ @@ -6411,7 +6909,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 336 (GHOTI) +# tile 361 (GHOTI) { ................ ................ @@ -6430,7 +6928,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 337 (MAPIRO MAHAMA DIROMAT) +# tile 362 (MAPIRO MAHAMA DIROMAT) { ................ ................ @@ -6449,7 +6947,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 338 (VAS CORP BET MANI) +# tile 363 (VAS CORP BET MANI) { ................ ................ @@ -6468,7 +6966,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 339 (XOR OTA) +# tile 364 (XOR OTA) { ................ ................ @@ -6487,7 +6985,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 340 (STRC PRST SKRZ KRK) +# tile 365 (STRC PRST SKRZ KRK) { ................ ................ @@ -6506,7 +7004,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 341 (stamped / mail) +# tile 366 (stamped / mail) { ................ ................ @@ -6525,7 +7023,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 342 (unlabeled / blank paper) +# tile 367 (unlabeled / blank paper) { ................ ................ @@ -6544,7 +7042,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 343 (parchment / dig) +# tile 368 (parchment / dig) { ................ ................ @@ -6563,7 +7061,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 344 (vellum / magic missile) +# tile 369 (vellum / magic missile) { ................ ................ @@ -6582,7 +7080,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 345 (ragged / fireball) +# tile 370 (ragged / fireball) { ................ ................ @@ -6601,7 +7099,7 @@ Z = (195, 195, 195) ......OOJJAA.... ................ } -# tile 346 (dog eared / cone of cold) +# tile 371 (dog eared / cone of cold) { ................ ................ @@ -6620,7 +7118,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 347 (mottled / sleep) +# tile 372 (mottled / sleep) { ................ ................ @@ -6639,7 +7137,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 348 (stained / finger of death) +# tile 373 (stained / finger of death) { ................ ................ @@ -6658,7 +7156,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 349 (cloth / light) +# tile 374 (cloth / light) { ................ ................ @@ -6677,7 +7175,7 @@ Z = (195, 195, 195) .......PPPAA.... ................ } -# tile 350 (leathery / detect monsters) +# tile 375 (leathery / detect monsters) { ................ ................ @@ -6696,7 +7194,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 351 (white / healing) +# tile 376 (white / healing) { ................ ................ @@ -6715,7 +7213,7 @@ Z = (195, 195, 195) .......PNNAA.... ................ } -# tile 352 (pink / knock) +# tile 377 (pink / knock) { ................ ................ @@ -6734,7 +7232,7 @@ Z = (195, 195, 195) .......IIIAA.... ................ } -# tile 353 (red / force bolt) +# tile 378 (red / force bolt) { ................ ................ @@ -6753,7 +7251,7 @@ Z = (195, 195, 195) .......DDDAA.... ................ } -# tile 354 (orange / confuse monster) +# tile 379 (orange / confuse monster) { ................ ................ @@ -6772,7 +7270,7 @@ Z = (195, 195, 195) .......CCCAA.... ................ } -# tile 355 (yellow / cure blindness) +# tile 380 (yellow / cure blindness) { ................ ................ @@ -6791,7 +7289,7 @@ Z = (195, 195, 195) .......HHHAA.... ................ } -# tile 356 (velvet / drain life) +# tile 381 (velvet / drain life) { ................ ................ @@ -6810,7 +7308,7 @@ Z = (195, 195, 195) .......EEEAA.... ................ } -# tile 357 (light green / slow monster) +# tile 382 (light green / slow monster) { ................ ................ @@ -6829,7 +7327,7 @@ Z = (195, 195, 195) .......GGGAA.... ................ } -# tile 358 (dark green / wizard lock) +# tile 383 (dark green / wizard lock) { ................ ................ @@ -6848,7 +7346,7 @@ Z = (195, 195, 195) .......FFFAA.... ................ } -# tile 359 (turquoise / create monster) +# tile 384 (turquoise / create monster) { ................ ................ @@ -6867,7 +7365,7 @@ Z = (195, 195, 195) .......FBBAA.... ................ } -# tile 360 (cyan / detect food) +# tile 385 (cyan / detect food) { ................ ................ @@ -6886,7 +7384,7 @@ Z = (195, 195, 195) .......BBBAA.... ................ } -# tile 361 (light blue / cause fear) +# tile 386 (light blue / cause fear) { ................ ................ @@ -6905,7 +7403,7 @@ Z = (195, 195, 195) .......BBBAA.... ................ } -# tile 362 (dark blue / clairvoyance) +# tile 387 (dark blue / clairvoyance) { ................ ................ @@ -6924,7 +7422,7 @@ Z = (195, 195, 195) .......EEEAA.... ................ } -# tile 363 (indigo / cure sickness) +# tile 388 (indigo / cure sickness) { ................ ................ @@ -6943,7 +7441,7 @@ Z = (195, 195, 195) .......EEEAA.... ................ } -# tile 364 (magenta / charm monster) +# tile 389 (magenta / charm monster) { ................ ................ @@ -6962,7 +7460,7 @@ Z = (195, 195, 195) .......IIIAA.... ................ } -# tile 365 (purple / haste self) +# tile 390 (purple / haste self) { ................ ................ @@ -6981,7 +7479,7 @@ Z = (195, 195, 195) .......IIIAA.... ................ } -# tile 366 (violet / detect unseen) +# tile 391 (violet / detect unseen) { ................ ................ @@ -7000,7 +7498,7 @@ Z = (195, 195, 195) .......IIIAA.... ................ } -# tile 367 (tan / levitation) +# tile 392 (tan / levitation) { ................ ................ @@ -7019,7 +7517,7 @@ Z = (195, 195, 195) .......KKKAA.... ................ } -# tile 368 (plaid / extra healing) +# tile 393 (plaid / extra healing) { ................ ................ @@ -7038,7 +7536,7 @@ Z = (195, 195, 195) .......EFDAA.... ................ } -# tile 369 (light brown / restore ability) +# tile 394 (light brown / restore ability) { ................ ................ @@ -7057,7 +7555,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 370 (dark brown / invisibility) +# tile 395 (dark brown / invisibility) { ................ ................ @@ -7076,7 +7574,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 371 (gray / detect treasure) +# tile 396 (gray / detect treasure) { ................ ................ @@ -7095,7 +7593,7 @@ Z = (195, 195, 195) .......PPPAA.... ................ } -# tile 372 (wrinkled / remove curse) +# tile 397 (wrinkled / remove curse) { ................ ................ @@ -7114,7 +7612,7 @@ Z = (195, 195, 195) ......JJKKAA.... ................ } -# tile 373 (dusty / magic mapping) +# tile 398 (dusty / magic mapping) { ................ ................ @@ -7133,7 +7631,7 @@ Z = (195, 195, 195) .KAKA..JJJAA.... ................ } -# tile 374 (bronze / identify) +# tile 399 (bronze / identify) { ................ ................ @@ -7152,7 +7650,7 @@ Z = (195, 195, 195) .......CCCAA.... ................ } -# tile 375 (copper / turn undead) +# tile 400 (copper / turn undead) { ................ ................ @@ -7171,7 +7669,7 @@ Z = (195, 195, 195) .......JCJAA.... ................ } -# tile 376 (silver / polymorph) +# tile 401 (silver / polymorph) { ................ ................ @@ -7190,7 +7688,7 @@ Z = (195, 195, 195) .......PPPAA.... ................ } -# tile 377 (gold / teleport away) +# tile 402 (gold / teleport away) { ................ ................ @@ -7209,7 +7707,7 @@ Z = (195, 195, 195) .......HHHAA.... ................ } -# tile 378 (glittering / create familiar) +# tile 403 (glittering / create familiar) { ................ ................ @@ -7228,7 +7726,7 @@ Z = (195, 195, 195) .......PPPAN.... .......N........ } -# tile 379 (shining / cancellation) +# tile 404 (shining / cancellation) { ....N........... .......N........ @@ -7247,7 +7745,7 @@ Z = (195, 195, 195) .......PPPAA.... ................ } -# tile 380 (dull / protection) +# tile 405 (dull / protection) { ................ ................ @@ -7266,7 +7764,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 381 (thin / jumping) +# tile 406 (thin / jumping) { ................ ................ @@ -7285,7 +7783,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 382 (thick / stone to flesh) +# tile 407 (thick / stone to flesh) { ................ ................ @@ -7304,7 +7802,26 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 383 (plain / blank paper) +# tile 408 (checkered / chain lightning) +{ + ................ + ................ + ................ + ....AAAA........ + ....AAAAAA...... + ...AAADDDANNP... + ...AADDAADNNN... + ..PNAADDNNNNOA.. + ..NNDNADDNNNOAA. + .PNNNDDDAAAONA.. + .NNNNNNAAAAAAA.. + .NOONNAAAAAOA... + ..PNOOOAAAOA.... + ....PAAOOOA..... + .......AAA...... + ................ +} +# tile 409 (plain / blank paper) { ................ ................ @@ -7323,7 +7840,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 384 (paperback / novel) +# tile 410 (paperback / novel) { ................ ................ @@ -7342,7 +7859,7 @@ Z = (195, 195, 195) .......EEEAA.... ................ } -# tile 385 (papyrus / Book of the Dead) +# tile 411 (papyrus / Book of the Dead) { ................ ................ @@ -7361,7 +7878,7 @@ Z = (195, 195, 195) .......AAA...... ................ } -# tile 386 (glass / light) +# tile 412 (glass / light) { ................ ................ @@ -7380,7 +7897,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 387 (balsa / secret door detection) +# tile 413 (balsa / secret door detection) { ................ ................ @@ -7399,7 +7916,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 388 (crystal / enlightenment) +# tile 414 (crystal / enlightenment) { ................ ................ @@ -7418,7 +7935,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 389 (maple / create monster) +# tile 415 (maple / create monster) { ................ ................ @@ -7437,7 +7954,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 390 (pine / wishing) +# tile 416 (pine / wishing) { ................ ................ @@ -7456,7 +7973,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 391 (oak / nothing) +# tile 417 (redwood / stasis) +{ + ................ + ................ + ................ + ...........NO... + ..........DDAA.. + .........DDAA... + ........DDAA.... + .......DDAA..... + ......DDAA...... + .....DDAA....... + ....DDAA........ + ...NOAA......... + ....AA.......... + ................ + ................ + ................ +} +# tile 418 (oak / nothing) { ................ ................ @@ -7475,7 +8011,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 392 (ebony / striking) +# tile 419 (ebony / striking) { ................ ................ @@ -7494,7 +8030,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 393 (marble / make invisible) +# tile 420 (marble / make invisible) { ................ ................ @@ -7513,7 +8049,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 394 (tin / slow monster) +# tile 421 (tin / slow monster) { ................ ................ @@ -7532,7 +8068,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 395 (brass / speed monster) +# tile 422 (brass / speed monster) { ................ ................ @@ -7551,7 +8087,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 396 (copper / undead turning) +# tile 423 (copper / undead turning) { ................ ................ @@ -7570,7 +8106,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 397 (silver / polymorph) +# tile 424 (silver / polymorph) { ................ ................ @@ -7589,7 +8125,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 398 (platinum / cancellation) +# tile 425 (platinum / cancellation) { ................ ................ @@ -7608,7 +8144,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 399 (iridium / teleportation) +# tile 426 (iridium / teleportation) { ................ ................ @@ -7627,7 +8163,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 400 (zinc / opening) +# tile 427 (zinc / opening) { ................ ................ @@ -7646,7 +8182,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 401 (aluminum / locking) +# tile 428 (aluminum / locking) { ................ ................ @@ -7665,7 +8201,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 402 (uranium / probing) +# tile 429 (uranium / probing) { ................ ................ @@ -7684,7 +8220,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 403 (iron / digging) +# tile 430 (iron / digging) { ................ ................ @@ -7703,7 +8239,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 404 (steel / magic missile) +# tile 431 (steel / magic missile) { ................ ................ @@ -7722,7 +8258,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 405 (hexagonal / fire) +# tile 432 (hexagonal / fire) { ................ ................ @@ -7741,7 +8277,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 406 (short / cold) +# tile 433 (short / cold) { ................ ................ @@ -7760,7 +8296,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 407 (runed / sleep) +# tile 434 (runed / sleep) { ................ ................ @@ -7779,7 +8315,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 408 (long / death) +# tile 435 (long / death) { ................ .............NO. @@ -7798,7 +8334,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 409 (curved / lightning) +# tile 436 (curved / lightning) { ................ .......NO....... @@ -7817,7 +8353,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 410 (forked) +# tile 437 (forked) { ................ ................ @@ -7836,7 +8372,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 411 (spiked) +# tile 438 (spiked) { ................ ................ @@ -7855,7 +8391,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 412 (jeweled) +# tile 439 (jeweled) { ................ ................ @@ -7874,7 +8410,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 413 (gold piece) +# tile 440 (gold piece) { ................ ................ @@ -7893,7 +8429,7 @@ Z = (195, 195, 195) .........HA..... ...........HA... } -# tile 414 (white / dilithium crystal) +# tile 441 (white / dilithium crystal) { ................ ................ @@ -7912,7 +8448,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 415 (white / diamond) +# tile 442 (white / diamond) { ................ ................ @@ -7931,7 +8467,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 416 (red / ruby) +# tile 443 (red / ruby) { ................ ................ @@ -7950,7 +8486,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 417 (orange / jacinth) +# tile 444 (orange / jacinth) { ................ ................ @@ -7969,7 +8505,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 418 (blue / sapphire) +# tile 445 (blue / sapphire) { ................ ................ @@ -7988,7 +8524,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 419 (black / black opal) +# tile 446 (black / black opal) { ................ ................ @@ -8007,7 +8543,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 420 (green / emerald) +# tile 447 (green / emerald) { ................ ................ @@ -8026,7 +8562,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 421 (green / turquoise) +# tile 448 (green / turquoise) { ................ ................ @@ -8045,7 +8581,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 422 (yellow / citrine) +# tile 449 (yellow / citrine) { ................ ................ @@ -8064,7 +8600,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 423 (green / aquamarine) +# tile 450 (green / aquamarine) { ................ ................ @@ -8083,7 +8619,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 424 (yellowish brown / amber) +# tile 451 (yellowish brown / amber) { ................ ................ @@ -8102,7 +8638,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 425 (yellowish brown / topaz) +# tile 452 (yellowish brown / topaz) { ................ ................ @@ -8121,7 +8657,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 426 (black / jet) +# tile 453 (black / jet) { ................ ................ @@ -8140,7 +8676,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 427 (white / opal) +# tile 454 (white / opal) { ................ ................ @@ -8159,7 +8695,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 428 (yellow / chrysoberyl) +# tile 455 (yellow / chrysoberyl) { ................ ................ @@ -8178,7 +8714,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 429 (red / garnet) +# tile 456 (red / garnet) { ................ ................ @@ -8197,7 +8733,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 430 (violet / amethyst) +# tile 457 (violet / amethyst) { ................ ................ @@ -8216,7 +8752,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 431 (red / jasper) +# tile 458 (red / jasper) { ................ ................ @@ -8235,7 +8771,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 432 (violet / fluorite) +# tile 459 (violet / fluorite) { ................ ................ @@ -8254,7 +8790,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 433 (black / obsidian) +# tile 460 (black / obsidian) { ................ ................ @@ -8273,7 +8809,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 434 (orange / agate) +# tile 461 (orange / agate) { ................ ................ @@ -8292,7 +8828,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 435 (green / jade) +# tile 462 (green / jade) { ................ ................ @@ -8311,7 +8847,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 436 (white / worthless piece of white glass) +# tile 463 (white / worthless piece of white glass) { ................ ................ @@ -8330,7 +8866,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 437 (blue / worthless piece of blue glass) +# tile 464 (blue / worthless piece of blue glass) { ................ ................ @@ -8349,7 +8885,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 438 (red / worthless piece of red glass) +# tile 465 (red / worthless piece of red glass) { ................ ................ @@ -8368,7 +8904,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 439 (yellowish brown / worthless piece of yellowish brown glass) +# tile 466 (yellowish brown / worthless piece of yellowish brown glass) { ................ ................ @@ -8387,7 +8923,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 440 (orange / worthless piece of orange glass) +# tile 467 (orange / worthless piece of orange glass) { ................ ................ @@ -8406,7 +8942,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 441 (yellow / worthless piece of yellow glass) +# tile 468 (yellow / worthless piece of yellow glass) { ................ ................ @@ -8425,7 +8961,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 442 (black / worthless piece of black glass) +# tile 469 (black / worthless piece of black glass) { ................ ................ @@ -8444,7 +8980,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 443 (green / worthless piece of green glass) +# tile 470 (green / worthless piece of green glass) { ................ ................ @@ -8463,7 +8999,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 444 (violet / worthless piece of violet glass) +# tile 471 (violet / worthless piece of violet glass) { ................ ................ @@ -8482,7 +9018,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 445 (gray / luckstone) +# tile 472 (gray / luckstone) { ................ ................ @@ -8501,7 +9037,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 446 (gray / loadstone) +# tile 473 (gray / loadstone) { ................ ................ @@ -8520,7 +9056,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 447 (gray / touchstone) +# tile 474 (gray / touchstone) { ................ ................ @@ -8539,7 +9075,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 448 (gray / flint) +# tile 475 (gray / flint) { ................ ................ @@ -8558,7 +9094,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 449 (rock) +# tile 476 (rock) { ................ ................ @@ -8577,7 +9113,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 450 (boulder) +# tile 477 (boulder) { ................ ................ @@ -8596,7 +9132,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 451 (statue) +# tile 478 (statue) { ................ ........JJ...... @@ -8615,7 +9151,7 @@ Z = (195, 195, 195) .....JJJJJJAA... ................ } -# tile 452 (heavy iron ball) +# tile 479 (heavy iron ball) { ................ ................ @@ -8634,7 +9170,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 453 (iron chain) +# tile 480 (iron chain) { ................ ................ @@ -8653,7 +9189,7 @@ Z = (195, 195, 195) ...........PP.PA ............AA.. } -# tile 454 (splash of venom / blinding venom) +# tile 481 (splash of venom / splash of blinding venom) { ................ ................ @@ -8672,7 +9208,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 455 (splash of venom / acid venom) +# tile 482 (splash of venom / splash of acid venom) { ................ ................ diff --git a/win/share/other.txt b/win/share/other.txt index b13d334e9..fb875b809 100644 --- a/win/share/other.txt +++ b/win/share/other.txt @@ -1,3 +1,6 @@ +# other.txt - tile definitions for 'other' (walls, furniture, explosions) +# Note: lines beginning with '# tile ' are not comments; other +# lines beginning with '#' are. . = (71, 108, 108) A = (0, 0, 0) B = (0, 182, 255) @@ -27,26 +30,26 @@ Y = (149, 149, 149) Z = (195, 195, 195) 0 = (100, 100, 100) 1 = (72, 108, 108) -# tile 0 (dark part of a room) -{ - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA -} -# tile 1 (vertical wall) +# tile 0 (stone) +{ + PPPPPPPPPPPPJPPP + PAPPPJPPAPPPPPPP + PPPPPPPPPPPPPPPP + PPJPPPPPPPJPPPAP + PPPPPAPPPPPPPPPP + PPPPPPPPPPPPPPPP + PAPPPPPPPAPPPJPP + PPPPPPPPPPPPPPPP + JPPPAPPJPPPPPPPP + PPPPPPPPPPJPPPPP + PPPPPPPPPPPPPAPP + PPPJPPPPAPPPPPPP + PPPPPPPPPPPPPPPP + PPPPPJPPPPPPAPPJ + PPAPPPPPPJPPPPPP + PPPPPPPPPPPPPPPP +} +# tile 1 (main walls vertical) { ANNOA1PPPPP1NNOA AOOOA1P1PP11OOOA @@ -65,7 +68,7 @@ Z = (195, 195, 195) A111A11PPPP1111A AOPPA11PPPP1OP1A } -# tile 2 (horizontal wall) +# tile 2 (main walls horizontal) { AAANOOAAAAANOOAA OOONOOA1OOONOOA1 @@ -84,7 +87,7 @@ Z = (195, 195, 195) 1111111111111111 AAAAAAAAAAAAAAAA } -# tile 3 (top left corner wall) +# tile 3 (main walls tlcorn) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 @@ -103,7 +106,7 @@ Z = (195, 195, 195) A111A11PPPP1111A AOPPA11PPPP1OP1A } -# tile 4 (top right corner wall) +# tile 4 (main walls trcorn) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 @@ -122,7 +125,7 @@ Z = (195, 195, 195) A111A11PPPP1111A AOPPA11PPPP1OP1A } -# tile 5 (bottom left corner wall) +# tile 5 (main walls blcorn) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 @@ -141,7 +144,7 @@ Z = (195, 195, 195) 1111111111111111 AAAAAAAAAAAAAAAA } -# tile 6 (bottom right corner wall) +# tile 6 (main walls brcorn) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 @@ -160,7 +163,7 @@ Z = (195, 195, 195) 1111111111111111 AAAAAAAAAAAAAAAA } -# tile 7 (cross wall) +# tile 7 (main walls cross wall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 @@ -179,7 +182,7 @@ Z = (195, 195, 195) A111A11PPPP1111A AOPPA11PPPP1OP1A } -# tile 8 (tuwall) +# tile 8 (main walls tuwall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 @@ -198,7 +201,7 @@ Z = (195, 195, 195) 1111111111111111 AAAAAAAAAAAAAAAA } -# tile 9 (tdwall) +# tile 9 (main walls tdwall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 @@ -217,7 +220,7 @@ Z = (195, 195, 195) A111A11PPPP1111A AOPPA11PPPP1OP1A } -# tile 10 (tlwall) +# tile 10 (main walls tlwall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 @@ -236,7 +239,7 @@ Z = (195, 195, 195) A111A11PPPP1111A AOPPA11PPPP1OP1A } -# tile 11 (trwall) +# tile 11 (main walls trwall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 @@ -426,7 +429,26 @@ Z = (195, 195, 195) .A.A.A.A.A.A.A.A A.A.A.A.A.A.A.A. } -# tile 21 (corridor) +# tile 21 (engraving in a room) +{ + ................ + ................ + ...H...H........ + ....H...H....... + .........H..H... + ..........H..... + ................ + .......PP....... + .......PP....... + ................ + ................ + ................ + ................ + ................ + ................ + ................ +} +# tile 22 (corridor) { ................ ................ @@ -445,7 +467,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 22 (lit corridor) +# tile 23 (lit corridor) { ................ ................ @@ -464,7 +486,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 23 (staircase up) +# tile 24 (engraving in a corridor) +{ + ................ + ...H...H........ + ....H...H....... + .........H..H... + ..........H..... + ................ + .......PP....... + ......P.PP...... + ......PP.P...... + .......PP....... + ................ + ................ + ................ + ................ + ................ + ................ +} +# tile 25 (staircase up) { AAAAAAAAAAAAAA.A AADJJJJJJJJJDA.A @@ -483,7 +524,7 @@ Z = (195, 195, 195) AAAAAAAAAAAAAA.A AAAAAAAAAAAAAAAA } -# tile 24 (staircase down) +# tile 26 (staircase down) { AAAAAAAAAAAAAA.A AADJJJJJJJJJDA.A @@ -502,7 +543,7 @@ Z = (195, 195, 195) AAAAAAAAAAAAAA.A AAAAAAAAAAAAAAAA } -# tile 25 (ladder up) +# tile 27 (ladder up) { ADAAAAAAAAAAAD.A AADAAAANAAAADA.A @@ -521,7 +562,7 @@ Z = (195, 195, 195) AAAAAAAAAAAAAA.A AAAAAAAAAAAAAAAA } -# tile 26 (ladder down) +# tile 28 (ladder down) { ADAAAAAAAAAAAD.A AADAAAANAAAADA.A @@ -540,7 +581,121 @@ Z = (195, 195, 195) AAAAAAAAAAAAAA.A AAAAAAAAAAAAAAAA } -# tile 27 (altar) +# tile 29 (branch staircase up) +{ + AAAAAAAAAAAAAA.A + AADJJJJJJJJJDA.A + AACDDJKHKKDDCA.A + AAAAAAHHHAAAA..A + AAADJHHHHHJDA..A + AAACHGGHGHHCA..A + AAAAAAGGHAAA...A + AAAAKDGGGKJA...A + AAAACKFGHKCA...A + AAAAAAGFGAA....A + AAAAAKFFFJA....A + AAAAACKJJKA....A + AAAAAAAAAAAA...A + AAAAAAAAAAAAA..A + AAAAAAAAAAAAAA.A + AAAAAAAAAAAAAAAA +} +# tile 30 (branch staircase down) +{ + AAAAAAAAAAAAAA.A + AADJJJJJJJJJDA.A + AACDDJHHHKDDCA.A + AAAAAAHHHAAAA..A + AAADJJHGHJJDA..A + AAACDDGHHKDCA..A + AAAAAAGHGAAA...A + AAAAFGGGHGHA...A + AAAACFGGGFCA...A + AAAAAAHFHAA....A + AAAAAKKGJJA....A + AAAAACKJJKA....A + AAAAAAAAAAAA...A + AAAAAAAAAAAAA..A + AAAAAAAAAAAAAA.A + AAAAAAAAAAAAAAAA +} +# tile 31 (branch ladder up) +{ + ADAAAAAAAAAAAD.A + AADAAAAHAAAADA.A + AACCCCHHHCCCCA.A + AADAAHAHAHAAD..A + AAADAAAHAAADA..A + AAACDDDHDDDCA..A + AAADAAAGAAAD...A + AAAAKAAGAAJA...A + AAAACKKGKKCA...A + AAAADAAFAAD....A + AAAAAKJFJJA....A + AAAAADAAAKA....A + AAAAAAAAAAAA...A + AAAAAAAAAAAAA..A + AAAAAAAAAAAAAA.A + AAAAAAAAAAAAAAAA +} +# tile 32 (branch ladder down) +{ + ADAAAAAAAAAAAD.A + AADAAAAHAAAADA.A + AACCCCCHCCCCCA.A + AADAAAAHAAAAD..A + AAADAAAHAAADA..A + AAACDDDHDDDCA..A + AAADAAAGAAAD...A + AAAAKAAGAAJA...A + AAAACGKGKGCA...A + AAAADAGGGAD....A + AAAAAKJGJJA....A + AAAAADAAAKA....A + AAAAAAAAAAAA...A + AAAAAAAAAAAAA..A + AAAAAAAAAAAAAA.A + AAAAAAAAAAAAAAAA +} +# tile 33 (unaligned altar) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ...QDDQDDDDQ.... + ..QQQDDQDDQDQ... + ...RRDQDQDQQAA.. + ...RQDQQQQQQA... + ..QQQQQQDQQQQ... + ...AAAAAAAAAAA.. + ................ +} +# tile 34 (chaotic altar) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ...SDDDDDSDS.... + ..SSSDSDDSSSS... + ...TTSDSDSSRQQ.. + ...TSSSSSSRRQ... + ..SSRRRRRRRSS... + ...AAAAAAAAAAA.. + ................ +} +# tile 35 (neutral altar) { ................ ................ @@ -559,7 +714,45 @@ Z = (195, 195, 195) ...AAAAAAAAAAA.. ................ } -# tile 28 (grave) +# tile 36 (lawful altar) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ...MMMDMDMDM.... + ..MMMDMMMDMMM... + ...NNMMMMMMZAA.. + ...NMMMMMMZZA... + ..MMZZZZZZZMM... + ...AAAAAAAAAAA.. + ................ +} +# tile 37 (other altar) +{ + ................ + ................ + ................ + ................ + ......N.N....... + ...N..N.N..N.... + .N..N.....N..N.. + ..N.........N... + ................ + NN.IIIIIIIII.NN. + ..IIIIIIIIIII... + ...LLIIIIIIKAA.. + ...LIIIIIIKKQ... + ..IIKKKKKKKII... + ...AAAAAAAAAAA.. + ................ +} +# tile 38 (grave) { ................ ................ @@ -578,7 +771,7 @@ Z = (195, 195, 195) FFFFFFFFFFFFFFF. ................ } -# tile 29 (throne) +# tile 39 (throne) { ................ .....HHHHH...... @@ -597,7 +790,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 30 (sink) +# tile 40 (sink) { ................ ................ @@ -616,7 +809,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 31 (fountain) +# tile 41 (fountain) { ....E....E...... ..EEEE..EEE..... @@ -635,7 +828,7 @@ Z = (195, 195, 195) ....AAAAAAAAA... ................ } -# tile 32 (pool) +# tile 42 (pool) { ..........NNN... .EEEE....NE.EN.. @@ -654,7 +847,7 @@ Z = (195, 195, 195) .E..EE...E..EEE. EE....EEE.....EE } -# tile 33 (ice) +# tile 43 (ice) { NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN @@ -673,7 +866,7 @@ Z = (195, 195, 195) NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN } -# tile 34 (molten lava) +# tile 44 (molten lava) { DDDDDDCDDDDDDDDD DDDDDCDKDDDDDDDD @@ -692,7 +885,26 @@ Z = (195, 195, 195) DDDDKKDDDDCDDDDD DDDDDDDDDDDKDDDD } -# tile 35 (vertical open drawbridge) +# tile 45 (wall of lava) +{ + DDDDDDCDDDDDDDDD + DDDDDCHKDDCDDDDD + DDCCDAKDHADCHCDD + DCHJADAADJAAJHKD + DCJAAJAAJAJAADKD + DDKKAAAAAAAJKHKD + DDAAAAAAAAAAJKDD + DHDJAAAAAAAJKADD + DCJAJAAAAAAAAKHD + DDKAAAAAAAAAKCDD + DHDJAAAAAAKAKHDC + DDAAKAKAKAAJADDD + DCDCAAJAAJKAKCDD + CDHAJAKJKAJADJDD + DDDDHKDHCDCDHDDD + DDDDDDDDDDDKDDDD +} +# tile 46 (vertical open drawbridge) { EKKAKKKKKKKAKKAE EJKKKKKKKKKKKJAA @@ -711,7 +923,7 @@ Z = (195, 195, 195) EEJJJJJJJJJJJAAA EJKKKKKKKKKKKJAA } -# tile 36 (horizontal open drawbridge) +# tile 47 (horizontal open drawbridge) { EEEEEEEEEEEEEEEE JEJKJEJKJEJKJEJK @@ -730,7 +942,7 @@ Z = (195, 195, 195) AAAAAAAAAAAAAAAA AAAEAAAEAAAEAAAE } -# tile 37 (vertical closed drawbridge) +# tile 48 (vertical closed drawbridge) { ................ ..JKJ.JKJ.JKJ... @@ -749,7 +961,7 @@ Z = (195, 195, 195) ...AAA.AAA.AAA.. ................ } -# tile 38 (horizontal closed drawbridge) +# tile 49 (horizontal closed drawbridge) { ................ ..JJJJJJJJJJJ... @@ -768,7 +980,7 @@ Z = (195, 195, 195) ...AAAAAAAAAAA.. ................ } -# tile 39 (air) +# tile 50 (air) { BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB @@ -787,7 +999,7 @@ Z = (195, 195, 195) BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB } -# tile 40 (cloud) +# tile 51 (cloud) { BBBBBBBBBBBBBBBB BBBBBNNNNNNNBBBB @@ -806,7 +1018,7 @@ Z = (195, 195, 195) BBBBBBOOOOBBBBBB BBBBBBBBBBBBBBBB } -# tile 41 (water) +# tile 52 (water) { EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE @@ -825,7 +1037,7 @@ Z = (195, 195, 195) EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE } -# tile 42 (arrow trap) +# tile 53 (arrow trap) { ................ .....DDDDD...... @@ -844,7 +1056,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 43 (dart trap) +# tile 54 (dart trap) { ................ .....DDDDD...... @@ -863,7 +1075,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 44 (falling rock trap) +# tile 55 (falling rock trap) { ................ .....DDDDD...... @@ -882,7 +1094,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 45 (squeaky board) +# tile 56 (squeaky board) { ................ .....DDDDD...... @@ -901,7 +1113,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 46 (bear trap) +# tile 57 (bear trap) { ................ .....DDDDD...... @@ -920,7 +1132,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 47 (land mine) +# tile 58 (land mine) { ................ .....DDDDD...... @@ -939,7 +1151,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 48 (rolling boulder trap) +# tile 59 (rolling boulder trap) { ................ .....DDDDD...... @@ -958,7 +1170,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 49 (sleeping gas trap) +# tile 60 (sleeping gas trap) { ................ .....DDDDD...... @@ -977,7 +1189,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 50 (rust trap) +# tile 61 (rust trap) { ................ .....DDDDD...... @@ -996,7 +1208,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 51 (fire trap) +# tile 62 (fire trap) { ................ .....DDDDD...... @@ -1015,7 +1227,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 52 (pit) +# tile 63 (pit) { AAAAAAAAAAAAAAAA A.AAAAAAAAAAAABA @@ -1034,7 +1246,7 @@ Z = (195, 195, 195) A.PPPPPPPPPPPPPA AAAAAAAAAAAAAAAA } -# tile 53 (spiked pit) +# tile 64 (spiked pit) { AAAAAAAAAAAAAAAA A.AAAAAAAAAAAABA @@ -1053,7 +1265,7 @@ Z = (195, 195, 195) A.PPPPPPPPPPPPPA AAAAAAAAAAAAAAAA } -# tile 54 (hole) +# tile 65 (hole) { ................ ......AAAA...... @@ -1072,7 +1284,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 55 (trap door) +# tile 66 (trap door) { AAAAAAAAAAAAAAAA A.AAAAAAAAAAAABA @@ -1091,7 +1303,7 @@ Z = (195, 195, 195) A.PPPPPPPPPPPPPA AAAAAAAAAAAAAAAA } -# tile 56 (teleportation trap) +# tile 67 (teleportation trap) { ................ .....DDDDD...... @@ -1110,7 +1322,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 57 (level teleporter) +# tile 68 (level teleporter) { ................ .....DDADD...... @@ -1129,7 +1341,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 58 (magic portal) +# tile 69 (magic portal) { ................ .....DDDDD...... @@ -1148,7 +1360,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 59 (web) +# tile 70 (web) { OAOA.OA...O....O .O.NNNN.NOA..OOA @@ -1167,7 +1379,7 @@ Z = (195, 195, 195) .OA............. OA.............. } -# tile 60 (statue trap) +# tile 71 (statue trap) { ................ .....DDDDD...... @@ -1186,7 +1398,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 61 (magic trap) +# tile 72 (magic trap) { ................ .....DDDDD...... @@ -1205,7 +1417,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 62 (anti-magic field) +# tile 73 (anti-magic field) { ................ ......DDDDD..... @@ -1224,7 +1436,7 @@ Z = (195, 195, 195) .....AAAAA...... ................ } -# tile 63 (polymorph trap) +# tile 74 (polymorph trap) { ................ .....DDDDD...... @@ -1243,7 +1455,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 64 (vibrating square) +# tile 75 (vibrating square) { ................ ................ @@ -1262,2230 +1474,2193 @@ Z = (195, 195, 195) ................ ................ } -# tile 65 (vertical beam) +# tile 76 (trapped door) { - .......NN....... - ......NN........ - .....NN......... - ......NN........ - .......NN....... - ........NN...... - .........NN..... - ........NN...... - .......NN....... - ......NN........ - .....NN......... - ......NN........ - .......NN....... - ........NN...... - .........NN..... - ........NN...... + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AACCKKKKKKKKJJAA + ACKJJJJJJJJJJKJA + APJJPKJJKJJJJJJA + A.PP.PPPPP.BPPJA + A.........BPP.JA + A.JJ.JJJJJDAPADA + AJJJJKJJJJ.D.DJA + APKJPKJJJJJADAJA + A.PP.PPPPPPD.DJA + A.........D...DA + A.JJ.JJJJJJJJJJA + AJKJJKJJKJJJNJNA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA } -# tile 66 (horizontal beam) +# tile 77 (trapped chest) { ................ ................ ................ - ................ - ................ - ..N.......N..... - .NNN.....NNN.... - NN.NN...NN.NN... - N...NN.NN...NN.N - .....NNN.....NNN - ......N.......N. - ................ - ................ - ................ - ................ - ................ -} -# tile 67 (left slant beam) -{ - NNNNN........... - ....N........... - ....N........... - ....N........... - ....N........... - ....N........... - ....N........... - ....N........... - ....NNNNNNNNN... - ............N... - ............N... - ............N... - ............N... - ............N... - ............N... - ............NNNN + ...CJKKKCJKKKC.. + .CKJKKCKJKKCJJK. + .KJKKKKJKKKKJJJ. + CJKDKCJKDKCJJJJ. + CJKKDCJDKKCJJJJ. + CCCCCDHCCCCJJJJ. + CJJJHQQHJJJJJJJ. + CJKKDHHDKKCJJJJN + CJKDKHHKDKCJJJJA + CJKKKCJKKKCJJJAA + CJCCCCJCCCCJJAA. + CKKKKKKKKKKJAA.. + .NAAAAAAAAAAA... } -# tile 68 (right slant beam) -{ - ............NNNN - ............N... - ............N... - ............N... - ............N... - ............N... - ............N... - ....NNNNNNNNN... - ....N........... - ....N........... - ....N........... - ....N........... - ....N........... - ....N........... - ....N........... - NNNNN........... -} -# tile 69 (dig beam) +# tile 78 (missile zap 1 0) { - ....AAAA........ - ..A....AA..AA... - .AA.AAA......AA. - .AA.A....A..AA.. - ..A....A.A.A.AA. - .A..AAA.A....AA. - .A.AA.....A.AA.. - ...AA....AA..... - .A.A...A...A.A.. - ...A......AA.AA. - .A.AAA.AAAA.A.A. - .AA..AA.......A. - ..A...AA..A..AA. - ..AAAAA..AAAAA.. - ....AA....AAA... - ................ + .......II....... + ......IIII...... + ......IIII...... + .......II....... + .......II....... + ......IIII...... + ......IIII...... + .......II....... + .......II....... + ......IIII...... + ......IIII...... + .......II....... + .......II....... + ......IIII...... + ......IIII...... + .......II....... } -# tile 70 (flash beam) +# tile 79 (missile zap 1 1) { ................ - .....NNNNNN..... - ...NNNNNNNNNN... - ..NNNNNNNNNNNN.. - ..NNNNNNNNNNNN.. - .NNNNNNNNNNNNNN. - .NNNNNNNNNNNNNN. - .NNNNNNNNNNNNNN. - .NNNNNNNNNNNNNN. - .NNNNNNNNNNNNNN. - .NNNNNNNNNNNNNN. - ..NNNNNNNNNNNN.. - ..NNNNNNNNNNNN.. - ...NNNNNNNNNN... - .....NNNNNN..... ................ -} -# tile 71 (boom left) -{ ................ ................ - ....KK.......... - ....KHKA........ - .....KHKA....... - ......KKKA...... - .......KKKA..... - ........KDKA.... - ........JDKA.... - .......JKDJA.... - ......JKDJA..... - .....JHDJA...... - ....JHDJA....... - .....KJA........ ................ ................ -} -# tile 72 (boom right) -{ + .II..II..II..II. + IIIIIIIIIIIIIIII + IIIIIIIIIIIIIIII + .II..II..II..II. ................ ................ - .........JK..... - ........JDHJ.... - .......JDHJA.... - ......JDKJA..... - .....JDKJA...... - .....KDJA....... - .....KDKA....... - ......KKKA...... - .......KKKA..... - ........KHKA.... - .........KHKA... - ..........KKA... ................ ................ -} -# tile 73 (shield1) -{ ................ - .....I....I..... - ....I......I.... - ...I........I... - ..I...IIII...I.. - .I............I. - ....I..II..I.... - ....I.IIII.I.... - ....I.IIII.I.... - ....I..II..I.... - .I............I. - ..I...IIII...I.. - ...I........I... - ....I......I.... - .....I....I..... ................ } -# tile 74 (shield2) +# tile 80 (missile zap 1 2) { - ................ - .CCCCCCCCCCCCCCC - .C.............. - .C.CCCCCCCCCCCC. - .C.C..........C. - .C.C.CCCCCCCC.C. - .C.C.C......C.C. - .C.C.C.CCCC.C.C. - .C.C.C.CC.C.C.C. - .C.C.C....C.C.C. - .C.C.CCCCCC.C.C. - .C.C........C.C. - .C.CCCCCCCCCC.C. - .C............C. - .CCCCCCCCCCCCCC. - ................ + III............. + IIII............ + IIII............ + .IIII........... + ...IIII......... + ....IIII........ + ....IIII........ + .....IIII....... + .......IIII..... + ........IIII.... + ........IIII.... + .........IIII... + ...........IIII. + ............IIII + ............IIII + .............III } -# tile 75 (shield3) +# tile 81 (missile zap 1 3) { - .......HH....... - .......HH....... - ....HH.HH.HH.... - ...H...HH...H... - ..H.H......H.H.. - ..H..H....H..H.. - ......H..H...... - HHHH...HH...HHHH - HHHH...HH...HHHH - ......H..H...... - ..H..H....H..H.. - ..H.H......H.H.. - ...H...HH...H... - ....HH.HH.HH.... - .......HH....... - .......HH....... + .............III + ............IIII + ............IIII + ...........IIII. + .........IIII... + ........IIII.... + ........IIII.... + .......IIII..... + .....IIII....... + ....IIII........ + ....IIII........ + ...IIII......... + .IIII........... + IIII............ + IIII............ + III............. +} +# tile 82 (fire zap 2 0) +{ + .......CC....... + ......CCCC...... + ......CCCC...... + .......CC....... + .......CC....... + ......CCCC...... + ......CCCC...... + .......CC....... + .......CC....... + ......CCCC...... + ......CCCC...... + .......CC....... + .......CC....... + ......CCCC...... + ......CCCC...... + .......CC....... } -# tile 76 (shield4) +# tile 83 (fire zap 2 1) { ................ - ......NNNNN..... - ........N....... - ...NNNN.N.NNN... - ...N..N.N.N.N... - .N.NNNN.N.N.N... - .N......N.NNN.N. - .NNNNNNNN.....N. - .N.....NNNNNNNN. - .N.NNN.N......N. - ...N.N.N.NNNN.N. - ...N.N.N.N..N... - ...NNN.N.NNNN... - .......N........ - .....NNNNN...... + ................ + ................ + ................ + ................ + ................ + .CC..CC..CC..CC. + CCCCCCCCCCCCCCCC + CCCCCCCCCCCCCCCC + .CC..CC..CC..CC. + ................ + ................ + ................ + ................ + ................ ................ } -# tile 77 (poison cloud) +# tile 84 (fire zap 2 2) { - BBBBBBBBBBBBBBBB - BBBBBFFFFFFFBBBB - BBBFFFFFFFFFFBBB - BBFFFFFFFFFGFFBB - BBFFFFFFFFFFFFFB - BFFFFFFFFFFFFGFB - FFFGFFFFFFFFGFFF - FFFFFFFFFFGGFFFF - FFFFFFFFFFFFFGFF - FFGGFFFFFFFGGFFG - FFFFFGGGGGFFFFGG - BGFFFFFFFFFFGGGB - BBGGGFFFFGGGGGGB - BBBGGGGGGGGGGBBB - BBBBBBGGGGBBBBBB - BBBBBBBBBBBBBBBB + CCC............. + CCCC............ + CCCC............ + .CCCC........... + ...CCCC......... + ....CCCC........ + ....CCCC........ + .....CCCC....... + .......CCCC..... + ........CCCC.... + ........CCCC.... + .........CCCC... + ...........CCCC. + ............CCCC + ............CCCC + .............CCC } -# tile 78 (valid position) +# tile 85 (fire zap 2 3) { - ................ - ................ - .....GGGG....... - ....GGGGGG...... - ...GGFFFFGG..... - ...GGF...GGF.... - ....FF...GGF.... - ........GGFF.... - .......GGFF..... - ......GGFF...... - ......GGF....... - .......FF....... - ......GG........ - ......GGF....... - .......FF....... - ................ + .............CCC + ............CCCC + ............CCCC + ...........CCCC. + .........CCCC... + ........CCCC.... + ........CCCC.... + .......CCCC..... + .....CCCC....... + ....CCCC........ + ....CCCC........ + ...CCCC......... + .CCCC........... + CCCC............ + CCCC............ + CCC............. } -# tile 79 (swallow top left) +# tile 86 (frost zap 3 0) { - AAAAAAADDDDDDAAA - AAAAADDDDDDDDDDD - AAAADDDDDDDDDDDD - AAADDDDDDCCDDDDD - AAADDDCCCCCCDDDD - AADDDDCCCCCDDDDD - AADDDCCCCCDDDDDD - AADDDCCCCDDDDD.. - AADDDCCCDDDD.... - AADDDCCCDDDD.... - AADDDDDDDDD..... - AAADDDDDDD...... - AAADDDDDDD...... - AAAADDDDDD...... - AAAADDDDDD...... - AAAADDDDDD...... + .......NN....... + ......NNNN...... + ......NNNN...... + .......NN....... + .......NN....... + ......NNNN...... + ......NNNN...... + .......NN....... + .......NN....... + ......NNNN...... + ......NNNN...... + .......NN....... + .......NN....... + ......NNNN...... + ......NNNN...... + .......NN....... } -# tile 80 (swallow top center) +# tile 87 (frost zap 3 1) { - AAAAAAAAAAAAAAAA - DDAAAAAAAAAAAAAA - DDDDAAAAAAAAAADD - DDDDDDDDDDDDDDDD - DDDDDDDDDDDDDDDD - DDDDDDDDDDDDDDDD - DDDDDDDCCCCCCDDD - .DDDDDDDDCCCCCDD - ...DDDDDDDDDDDDD - ....DDDDDDDDDDDD - ......DDDDDDDD.. - .......DDDD..... + ................ + ................ + ................ + ................ + ................ + ................ + .NN..NN..NN..NN. + NNNNNNNNNNNNNNNN + NNNNNNNNNNNNNNNN + .NN..NN..NN..NN. + ................ + ................ ................ ................ ................ ................ } -# tile 81 (swallow top right) +# tile 88 (frost zap 3 2) { - AAAAAAAAAAAAAAAA - AAADDDDDAAAAAAAA - DDDDDDDDDDDAAAAA - DDDDDDDDDDDDAAAA - DDDDDCCCDDDDDAAA - DDDDDCCCCDDDDDAA - DDDDDCCCCDDDDDDA - DDDDDCCCCCDDDDDD - DDDDDDCCCCCDDDDD - DDDDDDDCCCCDDDDD - ...DDDDDCCCDDDDD - ...DDDDDDCCDDDDD - ....DDDDDDDDDDDD - ....DDDDDDDDDDDD - ....DDDDDDDDDDDD - ....DDDDDDDDDDDA + NNN............. + NNNN............ + NNNN............ + .NNNN........... + ...NNNN......... + ....NNNN........ + ....NNNN........ + .....NNNN....... + .......NNNN..... + ........NNNN.... + ........NNNN.... + .........NNNN... + ...........NNNN. + ............NNNN + ............NNNN + .............NNN } -# tile 82 (swallow middle left) +# tile 89 (frost zap 3 3) { - AAAADDDDDD...... - AAAADDDDDDD..... - AAAADDDDDDD..... - AAAADDDDDDDD.... - AAAADDCCCDDD.... - AAADDDDCCDDD.... - AADDDDCCCDDD.... - AADDDDCCCDDD.... - AADDDDCDDDDD.... - ADDDDDDDDDD..... - ADDDDDDDDD...... - DDDDDDDDD....... - DDDDDDDD........ - DDDDDDD......... - DDDDDDD......... - DDCCDDD......... -} -# tile 83 (swallow middle right) -{ - ....DDDDDDDDDDDA - ....DDDDDDDDDDDA - ....DDDDDDDDDDAA - ....DDDDDDDDDDAA - ...DDDDDDDDDDDAA - ..DDDCCDDDDDDAAA - ..DDDCCDDDDDDAAA - ..DDDCCDDDDDAAAA - ..DDDCCDDDDDAAAA - ..DDDDDDDDDDAAAA - ...DDDDDDDDDAAAA - ...DDDDDDDDDAAAA - ....DDDDDDDDDAAA - .....DDDDDDDDAAA - ......DDDDDDDDAA - .......DDDDDDDAA -} -# tile 84 (swallow bottom left ) -{ - DDDCDDD......... - DDDCDDD......... - ADDCDDD......... - ADDDDDDD........ - ADDDDDDDDDDDD... - AADDDDDDDDDDDDDD - AADDDDDDDDDDDDDD - AAADDDDDDDDCDDDD - AAAAADDDDDDCCCCD - AAAAAAADDDDDCCCD - AAAAAAAAADDDDCCC - AAAAAAAAAADDDDCC - AAAAAAAAAAADDDDD - AAAAAAAAAAADDDDD - AAAAAAAAAAAADDDD - AAAAAAAAAAAAAADD -} -# tile 85 (swallow bottom center) -{ - ................ - ................ - ................ - ................ - .............DDD - ............DDDD - D...........DDDD - DD..........DDDC - DDD.........DDDC - DDDD........DDDC - DDDDDD....DDDDDC - DDDDDDDDDDDDDDDC - DDDDDDDDDDDDDDDC - DDDDDDDDDDDDDDDD - DDDDDDDDDDDDDDDD - DDDDDDDDDDDDDDAA -} -# tile 86 (swallow bottom right) -{ - ......DDDDDDDDAA - ......DDDDDDDDDA - .....DDDDDDDDDDA - ....DDDDDDDDDDDA - DDDDDDDDDDDDDDDA - DDDDDDDDDDDDDDDA - CCCDDDDDDDDDDDAA - CCCCDDDDDDDDDDAA - CCCDDDDDDDDDDDAA - CCDDDDDDDDDDDAAA - CCDDDDDDAAAAAAAA - CDDDDDAAAAAAAAAA - CDDDDAAAAAAAAAAA - DDDDAAAAAAAAAAAA - DDAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA -} -# tile 87 (explosion top left) -{ - ................ - ................ - .............AAA - ......A...AAAAAA - .........AAAAAAA - .........AAAAAA. - ........AAAA...A - ...AAA.AAAA...AA - .A...AAAAAA.AAAA - .....AAAAAA.AAAA - ....AAAAAAA.AAAA - ........AA..AA.. - ....AAAAAAAAAA.. - ...AAAA..AAA.... - ..AAAA..AAAA.... - ..AAA..AAAAA.... -} -# tile 88 (explosion top centre) -{ - ................ - ................ - A........AAAAAA. - AAAAAA.AAAAAAAA. - AAAAAA.....AAAAA - ...AAA.AAAAAAAAA - AAAAAA.AAAAAAAAA - AAAAAA.AAAAAAAA. - AA...........A.. - ..AAA.A.....AAAA - .A.A.A...A...AAA - .PPA...AA.....AA - .A.....A....AAAA - .....A..A...PAAA - ........A.A.APAA - .PA...APAAAAAAAA -} -# tile 89 (explosion top right) -{ - ................ - ................ - ................ - ........A...A... - AAAAA........... - AAAAAA...A..A... - AAAAAAA......... - ......AAAA...... - AAAAA..AAAA..... - ..AAAAAAAAAA.... - AA.AA....AAA.... - AA.AAAAA.AAA.... - AAPAA.AAAAAA.A.. - AAA.....AAAA.... - AA.A..A.AAAA.... - A.AA..A.AAAAA... -} -# tile 90 (explosion middle left) -{ - ..AAA.A.AAA..... - ..AAA.AAAAA.AP.. - ...AA.AA.......A - ...AAAAAA....PP. - ..AAA.AA..A..PAP - .AAA...A....P.AP - .AAA.AAA.A..P..P - .AAA.AAA...AAAAP - .AAA.AAA....PAAA - .AAA..AA....PPAA - ..AAA..AA...PAAP - ...AAA...AP.PPPP - ....AAA...P..P.A - .....AA.....AAA. - ..A.A...AAP...PA - ....A.........PA -} -# tile 91 (explosion middle center) -{ - APAAA..PPAPAAAAA - .APA..A.AAAPAAA. - AAP.PAA..AAAAAA. - PAPPPAAA..AAPA.. - AAAPPAAAAPAAP..A - AAPP.PPPAAAAA..A - AAPAAAAAAAAAAA.. - APPAAAAAAAAAAA.. - AAAAAAAAAAAAPAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAA.AA - AAAAAAAAAAA.HH.. -} -# tile 92 (explosion middle right) -{ - ..AAA.A.A.AAAA.. - ..AAAAA.A.AAAA.. - ..AAAAA.A.AAAA.. - P.AAAAA...AAAA.. - P.AAPAPAA.AAAA.. - P...P..A..AAA... - ...AP..AAAAAA... - .PAAPAAAAAAAA... - AAP...PAAAAA.... - ..AA.PPAA.A...A. - A...PP.......... - .AAAAPPAA...A... - ..AA.PP.AAA..... - A......AAAAA.... - AAA...AAAAAAA... - ....PPAAAAAAAA.. -} -# tile 93 (explosion bottom left) -{ - ....A.......A..P - ....A.......AA.. - .A..AA...P..A.A. - ...AAA.A..P..AAP - ...AAAA..AAP..A. - ...AAAA....P...A - ...AAAA..A..A..A - ...AAAAA.AAA.... - ...AAAAA..AA.... - ....AAAAAAAAA... - .....AAAAAAAAAAA - ...A..AAAAAAAAAA - ........AA.AAAAA - ...A........AAAA - ................ - ................ -} -# tile 94 (explosion bottom center) -{ - PPPAAAAAPAAA.A.. - AAPPAAPPPPA.A... - PPPPPPPPPPA..APP - .PPAA.AA.APAA... - ..AAAA.A..AAAPAA - APPAPAP.A.A.PAA. - A..PPAAA.......P - AA.......A...... - PAPA.AAAAAAAAAAP - AA.APAAAA......A - AAA.A.PP...AAAAA - AAAAAA.A..AAAAAA - AAAAAAAAAAAAAAAA - AAAA..........AA - ................ - ................ -} -# tile 95 (explosion bottom right) -{ - ....P..AAAAAAA.. - ..A..A.AA.A.AA.. - PP..A..AA.A.AA.. - ...AAA.AA.A.AA.. - .AAAAA.AAA..AA.. - ..PAA..AAA.AAA.. - .AAA..AAA..AAA.. - .A.AA.AAAAAAAA.. - AA.AAAAAA.AAAA.. - ...AAAAAAAAAAA.. - .AAAAAAAA.AAA... - AAAAAAAA........ - AAAAAA....A..... - AAA...A......... - ................ - ................ + .............NNN + ............NNNN + ............NNNN + ...........NNNN. + .........NNNN... + ........NNNN.... + ........NNNN.... + .......NNNN..... + .....NNNN....... + ....NNNN........ + ....NNNN........ + ...NNNN......... + .NNNN........... + NNNN............ + NNNN............ + NNN............. } -# tile 96 (explosion noxious 0) +# tile 90 (sleep zap 4 0) { - ................ - ................ - .............FFF - ......F...FFFFFF - .........FFFFFFF - .........FFFFFF. - ........FFFF...F - ...FFF.FFFF...FF - .F...FFFFFF.FFFF - .....FFFFFF.FFFF - ....FFFFFFF.FFFF - ........FF..FF.. - ....FFFFFFFFFF.. - ...FFFF..FFF.... - ..FFFF..FFFF.... - ..FFF..FFFFF.... + .......BB....... + ......BBBB...... + ......BBBB...... + .......BB....... + .......BB....... + ......BBBB...... + ......BBBB...... + .......BB....... + .......BB....... + ......BBBB...... + ......BBBB...... + .......BB....... + .......BB....... + ......BBBB...... + ......BBBB...... + .......BB....... } -# tile 97 (explosion noxious 1) +# tile 91 (sleep zap 4 1) { ................ ................ - F........FFFFFF. - FFFFFF.FFFFFFFF. - FFFFFF.....FFFFF - ...FFF.FFFFFFFFF - FFFFFF.FFFFFFFFF - FFFFFF.FFFFFFFF. - FF...........F.. - ..FFF.F.....FFFF - .H.F.F...F...FFF - .GGF...FF.....FF - .H.....F....FFFF - .....F..F...GFFF - ........F.F.FGFF - .GH...HGHHFFFFFF -} -# tile 98 (explosion noxious 2) -{ ................ ................ ................ - ........F...F... - FFFFF........... - FFFFFF...F..F... - FFFFFFF......... - ......FFFF...... - FFFFF..FFFF..... - ..FFFFFFFFFF.... - FF.FF....FFF.... - FF.FFFFF.FFF.... - FFGFF.FFFFFF.F.. - FFF.....FFFF.... - FF.F..F.FFFF.... - F.FF..F.FFFFF... + ................ + .BB..BB..BB..BB. + BBBBBBBBBBBBBBBB + BBBBBBBBBBBBBBBB + .BB..BB..BB..BB. + ................ + ................ + ................ + ................ + ................ + ................ } -# tile 99 (explosion noxious 3) +# tile 92 (sleep zap 4 2) { - ..FFF.F.FFF..... - ..FFF.FFFFF.FG.. - ...FF.FF.......F - ...FFFFFF....GG. - ..FFF.FF..F..GFG - .FFF...F....G.FG - .FFF.FFF.H..G..G - .FFF.FFF...FFFFG - .FFF.FFF....GFHH - .FFF..FF....GGHH - ..FFF..FF...GHHG - ...FFF...FG.GGGG - ....FFF...G..G.H - .....FF.....HHF. - ..F.F...FHG...GH - ....F.........GH + BBB............. + BBBB............ + BBBB............ + .BBBB........... + ...BBBB......... + ....BBBB........ + ....BBBB........ + .....BBBB....... + .......BBBB..... + ........BBBB.... + ........BBBB.... + .........BBBB... + ...........BBBB. + ............BBBB + ............BBBB + .............BBB } -# tile 100 (explosion noxious 4) +# tile 93 (sleep zap 4 3) { - FGHFF..GGFGHFFFF - .HGH..F.FFHGFHF. - HFG.GHF..HHHFFH. - GFGGGHHH..HHGF.. - HHHGGHHHHGHHG..F - HHGG.GGGHHHHF..F - HHGHHHHHHHHHHF.. - HGGHHHHHHHHHHH.. - HHHHHHNNNNHHGHNH - GHHHHHHHNHHHHHNH - GHHGHGNNNNHHHHGF - GGNHNHNNNNHHHGGF - HHHHNHNNNHHHGGGG - HGGNGHNNNHHHGGGF - HHHHNHNHN.GGG.GF - GGGGNHHHGGG.HH.. + .............BBB + ............BBBB + ............BBBB + ...........BBBB. + .........BBBB... + ........BBBB.... + ........BBBB.... + .......BBBB..... + .....BBBB....... + ....BBBB........ + ....BBBB........ + ...BBBB......... + .BBBB........... + BBBB............ + BBBB............ + BBB............. } -# tile 101 (explosion noxious 5) +# tile 94 (death zap 5 0) { - ..FFF.F.F.FFFF.. - ..FFFFF.F.FFFF.. - ..FFFFF.F.FFFF.. - G.FFFFF...FFFF.. - G.FFGFGFF.FFFF.. - G...G.GF..FFF... - ...FG..FFFFFF... - .GFFFFFFFFFFF... - FFG...GFFFFF.... - ..FF.GGFF.F...F. - F...GG.......... - .FFFFGGFF...F... - ..HF.GG.FFF..... - H......FFFFF.... - HFH...FFFFFFF... - ....GGFFFFFFFF.. + .......AA....... + ......AAAA...... + ......AAAA...... + .......AA....... + .......AA....... + ......AAAA...... + ......AAAA...... + .......AA....... + .......AA....... + ......AAAA...... + ......AAAA...... + .......AA....... + .......AA....... + ......AAAA...... + ......AAAA...... + .......AA....... } -# tile 102 (explosion noxious 6) +# tile 95 (death zap 5 1) { - ....F.......H..G - ....F.......FH.. - .F..FF...G..F.H. - ...FFF.F..G..FFG - ...FFFF..FFG..F. - ...FFFF....G...F - ...FFFF..F..H..F - ...FFFFF.FFF.... - ...FFFFF..FF.... - ....FFFFFFFFF... - .....FFFHFFFFFFF - ...F..FFFFFFFFFF - ........FF.FFFFF - ...F........FFFF ................ ................ -} -# tile 103 (explosion noxious 7) -{ - GGGHHHHHGHHH.H.. - HHGGHHGGGGH.F... - GGGGGGGGGGF..FGG - .GGHF.FF.HGFF... - ..HHHH.F..FFHGHF - HGGFGFG.H.H.GFF. - F..GGFFH.......G - HF.......F...... - GHGF.FFFFFFFFFFG - HF.HGHFFF......F - FFF.F.GG...FFFFF - FFFFFF.F..FFFFFF - FFFFFFFFFFFFFFFF - FFFF..........FF ................ ................ -} -# tile 104 (explosion noxious 8) -{ - ....G..FFFFFFF.. - ..F..F.FF.F.FF.. - GG..F..FF.F.FF.. - ...FFF.FF.F.FF.. - .FFFFF.FFF..FF.. - ..GFF..FFF.FFF.. - .FFF..FFF..FFF.. - .F.FF.FFFFFFFF.. - FF.FFFFFF.FFFF.. - ...FFFFFFFFFFF.. - .FFFFFFFF.FFF... - FFFFFFFF........ - FFFFFF....F..... - FFF...F......... ................ ................ -} -# tile 105 (explosion muddy 0) -{ + .AA..AA..AA..AA. + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + .AA..AA..AA..AA. ................ ................ - .............JJJ - ......J...JJJJJJ - .........JJJJJJJ - .........JJJJJJK - ........JJJJKKKJ - ...JJJ.JJJJKKKJJ - .J...JJJJJJKJJJJ - .....JJJJJJKJJJJ - ....JJJJJJJKJJJJ - .......KJJKKJJKK - ....JJJJJJJJJJKK - ...JJJJKKJJJKKKK - ..JJJJKKJJJJKKKK - ..JJJKKJJJJJKKKK + ................ + ................ + ................ + ................ +} +# tile 96 (death zap 5 2) +{ + AAA............. + AAAA............ + AAAA............ + .AAAA........... + ...AAAA......... + ....AAAA........ + ....AAAA........ + .....AAAA....... + .......AAAA..... + ........AAAA.... + ........AAAA.... + .........AAAA... + ...........AAAA. + ............AAAA + ............AAAA + .............AAA +} +# tile 97 (death zap 5 3) +{ + .............AAA + ............AAAA + ............AAAA + ...........AAAA. + .........AAAA... + ........AAAA.... + ........AAAA.... + .......AAAA..... + .....AAAA....... + ....AAAA........ + ....AAAA........ + ...AAAA......... + .AAAA........... + AAAA............ + AAAA............ + AAA............. +} +# tile 98 (lightning zap 6 0) +{ + .......NN....... + ......NNNN...... + ......NNNN...... + .......NN....... + .......NN....... + ......NNNN...... + ......NNNN...... + .......NN....... + .......NN....... + ......NNNN...... + ......NNNN...... + .......NN....... + .......NN....... + ......NNNN...... + ......NNNN...... + .......NN....... } -# tile 106 (explosion muddy 1) +# tile 99 (lightning zap 6 1) { ................ ................ - J........JJJJJJ. - JJJJJJKJJJJJJJJ. - JJJJJJKKKKKJJJJJ - KKKJJJKJJJJJJJJJ - JJJJJJKJJJJJJJJJ - JJJJJJKJJJJJJJJK - JJKKKKKKKKKKKJKK - KKJJJKJKKKKKJJJJ - KLKJKJKKKJKKKJJJ - KCCJKKKJJKKKKKJJ - KLKKKKKJKKKKJJJJ - KKKKKJKKJKKKCJJJ - KKKKKKKKJKJKJCJJ - KCLKKKLCLLJJJJJJ -} -# tile 107 (explosion muddy 2) -{ ................ ................ ................ - ........J...J... - JJJJJ........... - JJJJJJ...J..J... - JJJJJJJ......... - KKKKKKJJJJ...... - JJJJJKKJJJJ..... - KKJJJJJJJJJJ.... - JJKJJKKKKJJJ.... - JJKJJJJJKJJJ.... - JJCJJKJJJJJJ.J.. - JJJKKKKKJJJJ.... - JJKJKKJKJJJJ.... - JKJJKKJKJJJJJ... + ................ + .NN..NN..NN..NN. + NNNNNNNNNNNNNNNN + NNNNNNNNNNNNNNNN + .NN..NN..NN..NN. + ................ + ................ + ................ + ................ + ................ + ................ } -# tile 108 (explosion muddy 3) +# tile 100 (lightning zap 6 2) { - ..JJJKJKJJJKKKKK - ..JJJKJJJJJKJCKK - ...JJKJJKKKKKKKJ - ...JJJJJJKKKKCCK - ..JJJKJJKKJKKCJC - .JJJKKKJKKKKCKJC - .JJJKJJJKLKKCKKC - .JJJKJJJKKKJJJJC - .JJJKJJJKKKKCJLL - .JJJKKJJKKKKCCLL - ..JJJKKJJKKKCLLC - ...JJJKKKJCKCCCC - ....JJJKKKCKKCKL - .....JJKKKKKLLJK - ..J.JKKKJLCKKKCL - ....JKKKKKKKKKCL + NNN............. + NNNN............ + NNNN............ + .NNNN........... + ...NNNN......... + ....NNNN........ + ....NNNN........ + .....NNNN....... + .......NNNN..... + ........NNNN.... + ........NNNN.... + .........NNNN... + ...........NNNN. + ............NNNN + ............NNNN + .............NNN } -# tile 109 (explosion muddy 4) +# tile 101 (lightning zap 6 3) { - JCLJJKKCCJCLJJJJ - KLCLKKJKJJLCJLJK - LJCKCLJKKLLLJJLK - CJCCCLLLKKLLCJKK - LLLCCLLLLCLLCKKJ - LLCCKCCCLLLLJKKJ - LLCLLLLLLLLLLJKK - LCCLLLLLLLLLLLKK - LLLLLLCCCCLLCLCL - CLLLLLLLCLLLLLCL - CLLCLCCCCCLLLLCJ - CCCLCLCCCCLLLCCJ - LLLLCLCCCLLLCCCC - LCCCCLCCCLLLCCCJ - LLLLCLCLCKCCCKCJ - CCCCCLLLCCCKLLKK + .............NNN + ............NNNN + ............NNNN + ...........NNNN. + .........NNNN... + ........NNNN.... + ........NNNN.... + .......NNNN..... + .....NNNN....... + ....NNNN........ + ....NNNN........ + ...NNNN......... + .NNNN........... + NNNN............ + NNNN............ + NNN............. } -# tile 110 (explosion muddy 5) +# tile 102 (poison gas zap 7 0) { - KKJJJKJKJKJJJJ.. - KKJJJJJKJKJJJJ.. - KKJJJJJKJKJJJJ.. - CKJJJJJKKKJJJJ.. - CKJJCJCJJKJJJJ.. - CKKKCKKJKKJJJ... - KKKJCKKJJJJJJ... - KCJJCJJJJJJJJ... - JJCKKKCJJJJJ.... - KKJJKCCJJKJ...J. - JKKKCCKKKK...... - KJJJJCCJJK..J... - KKLJKCCKJJJ..... - LKKKKKKJJJJJ.... - LJLKKKJJJJJJJ... - KKKKCCJJJJJJJJ.. + .......FF....... + ......FFFF...... + ......FFFF...... + .......FF....... + .......FF....... + ......FFFF...... + ......FFFF...... + .......FF....... + .......FF....... + ......FFFF...... + ......FFFF...... + .......FF....... + .......FF....... + ......FFFF...... + ......FFFF...... + .......FF....... } -# tile 111 (explosion muddy 6) +# tile 103 (poison gas zap 7 1) { - ....JKKKKKKKLKKC - ....JKKKKKKKJLKK - .J..JJKKKCKKJKLK - ...JJJKJKKCKKJJC - ...JJJJKKJJCKKJK - ...JJJJKKKKCKKKJ - ...JJJJKKJKKLKKJ - ...JJJJJKJJJKKKK - ...JJJJJKKJJKKKK - ....JJJJJJJJJKKK - .....JJJLJJJJJJJ - ...J..JJJJJJJJJJ - ........JJ.JJJJJ - ...J........JJJJ - ................ ................ -} -# tile 112 (explosion muddy 7) -{ - CCCLLLLLCLLLKLKK - LLCCLLCCCCLKJKKK - CCCCCCCCCCJKKJCC - KCCLJKJJKLCJJKKK - KKLLLLKJKKJJLCLJ - LCCJCJCKLKLKCJJK - JKKCCJJLKKKKKKKC - LJKKKKKKKJKKKKKK - CLCJKJJJJJJJJJJC - LJKLCLJJJKKKKKKJ - JJJKJKCCKKKJJJJJ - JJJJJJKJKKJJJJJJ - JJJJJJJJJJJJJJJJ - JJJJ..........JJ ................ ................ -} -# tile 113 (explosion muddy 8) -{ - KKKKCKKJJJJJJJ.. - KKJKKJKJJKJKJJ.. - CCKKJKKJJKJKJJ.. - KKKJJJKJJKJKJJ.. - KJJJJJKJJJKKJJ.. - KKCJJKKJJJKJJJ.. - KJJJKKJJJKKJJJ.. - KJKJJKJJJJJJJJ.. - JJKJJJJJJKJJJJ.. - KKKJJJJJJJJJJJ.. - KJJJJJJJJ.JJJ... - JJJJJJJJ........ - JJJJJJ....J..... - JJJ...J......... ................ ................ -} -# tile 114 (explosion wet 0) -{ ................ + .FF..FF..FF..FF. + FFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFF + .FF..FF..FF..FF. ................ - .............EEE - ......E...EEEEEE - .........EEEEEEE - .........EEEEEEP - ........EEEEPPPE - ...EEE.EEEEPPPEE - .E...EEEEEEPEEEE - .....EEEEEEPEEEE - ....EEEEEEEPEEEE - .......PEEPPEEPP - ....EEEEEEEEEEPP - ...EEEEPPEEEPPPP - ..EEEEPPEEEEPPPP - ..EEEPPEEEEEPPPP -} -# tile 115 (explosion wet 1) -{ ................ ................ - E........EEEEEE. - EEEEEEPEEEEEEEE. - EEEEEEPPPPPEEEEE - PPPEEEPEEEEEEEEE - EEEEEEPEEEEEEEEE - EEEEEEPEEEEEEEEP - EEPPPPPPPPPPPEPP - PPEEEPEPPPPPEEEE - PNPEPEPPPEPPPEEE - PBBEPPPEEPPPPPEE - PNPPPPPEPPPPEEEE - PPPPPEPPEPPPBEEE - PPPPPPPPEPEPEBEE - PBNPPPNBEEEEEEEE -} -# tile 116 (explosion wet 2) -{ ................ ................ ................ - ........E...E... - EEEEE........... - EEEEEE...E..E... - EEEEEEE......... - PPPPPPEEEE...... - EEEEEPPEEEE..... - PPEEEEEEEEEE.... - EEPEEPPPPEEE.... - EEPEEEEEPEEE.... - EEBEEPEEEEEE.E.. - EEEPPPPPEEEE.... - EEPEPPEPEEEE.... - EPEEPPEPEEEEE... } -# tile 117 (explosion wet 3) +# tile 104 (poison gas zap 7 2) { - ..EEEPEPEEEPPPPP - ..EEEPEEEEEPEBPP - ...EEPEEPPPPPPPE - ...EEEEEEPPPPBBP - ..EEEPEEPPEPPBEB - .EEEPPPEPPPPBPEB - .EEEPEEEPNPPBPPB - .EEEPEEEPPPEEEEB - .EEEPEEEPPPPBEEE - .EEEPPEEPPPPBBEE - ..EEEPPEEPPPBEEB - ...EEEPPPEBPBBBB - ....EEEPPPBPPBPN - .....EEPPPPPNNEP - ..E.EPPPENBPPPBE - ....EPPPPPPPPPBE + FFF............. + FFFF............ + FFFF............ + .FFFF........... + ...FFFF......... + ....FFFF........ + ....FFFF........ + .....FFFF....... + .......FFFF..... + ........FFFF.... + ........FFFF.... + .........FFFF... + ...........FFFF. + ............FFFF + ............FFFF + .............FFF } -# tile 118 (explosion wet 4) +# tile 105 (poison gas zap 7 3) { - EBNEEPPBBEBNEEEE - PNBNPPEPEEEBENEP - NEBPBEEPPEEEEENP - BEBBBEEEPPEEBEPP - EEEBBEEEEBEEBPPE - EEBBPBBBEEEEEPPE - EEBEEEEEEEEEEEPP - EBBEEEEEEEEEEEPP - EEEEEEEEEEEEBEEE - BEEEEEEEEEEEEEEE - BEEBEBEEEEEEEEBE - BBEEEEEEEEEEEBBE - EEEEEEEEEEEEBBBB - EBBEBEEEEEEEBBBE - EEEEEEEEEPBBBPBE - BBBBEEEEBBBPNNPP + .............FFF + ............FFFF + ............FFFF + ...........FFFF. + .........FFFF... + ........FFFF.... + ........FFFF.... + .......FFFF..... + .....FFFF....... + ....FFFF........ + ....FFFF........ + ...FFFF......... + .FFFF........... + FFFF............ + FFFF............ + FFF............. } -# tile 119 (explosion wet 5) +# tile 106 (acid zap 8 0) { - PPEEEPEPEPEEEE.. - PPEEEEEPEPEEEE.. - PPEEEEEPEPEEEE.. - BPEEEEEPPPEEEE.. - BPEEBEBEEPEEEE.. - BPPPBPPEPPEEE... - PPPEBPPEEEEEE... - PBEEBEEEEEEEE... - EEBPPPBEEEEE.... - PPEEPBBEEPE...E. - EPPPBBPPPP...... - PEEEEBBEEP..E... - PPNEPBBPEEE..... - NPPPPPPEEEEE.... - NENPPPEEEEEEE... - PPPPBBEEEEEEEE.. + .......GG....... + ......GGGG...... + ......GGGG...... + .......GG....... + .......GG....... + ......GGGG...... + ......GGGG...... + .......GG....... + .......GG....... + ......GGGG...... + ......GGGG...... + .......GG....... + .......GG....... + ......GGGG...... + ......GGGG...... + .......GG....... } -# tile 120 (explosion wet 6) +# tile 107 (acid zap 8 1) { - ....EPPPPPPPNPPB - ....EPPPPPPPENPP - .E..EEPPPBPPEPNP - ...EEEPEPPBPPEEB - ...EEEEPPEEBPPEP - ...EEEEPPPPBPPPE - ...EEEEPPEPPNPPE - ...EEEEEPEEEPPPP - ...EEEEEPPEEPPPP - ....EEEEEEEEEPPP - .....EEENEEEEEEE - ...E..EEEEEEEEEE - ........EE.EEEEE - ...E........EEEE - ................ ................ -} -# tile 121 (explosion wet 7) -{ - BBBEEEEEBEEEPEPP - EEBBEEBBBBEPEPPP - BBBBBBBBBBEPPEBB - PBBEEPEEPNBEEPPP - PPEEEEPEPPEENBNE - NBBEBEBPNPNPBEEP - EPPBBEENPPPPPPPB - NEPPPPPPPEPPPPPP - BNBEPEEEEEEEEEEB - NEPNBNEEEPPPPPPE - EEEPEPBBPPPEEEEE - EEEEEEPEPPEEEEEE - EEEEEEEEEEEEEEEE - EEEE..........EE ................ ................ -} -# tile 122 (explosion wet 8) -{ - PPPPBPPEEEEEEE.. - PPEPPEPEEPEPEE.. - BBPPEPPEEPEPEE.. - PPPEEEPEEPEPEE.. - PEEEEEPEEEPPEE.. - PPBEEPPEEEPEEE.. - PEEEPPEEEPPEEE.. - PEPEEPEEEEEEEE.. - EEPEEEEEEPEEEE.. - PPPEEEEEEEEEEE.. - PEEEEEEEE.EEE... - EEEEEEEE........ - EEEEEE....E..... - EEE...E......... ................ ................ -} -# tile 123 (explosion magical 0) -{ ................ + .GG..GG..GG..GG. + GGGGGGGGGGGGGGGG + GGGGGGGGGGGGGGGG + .GG..GG..GG..GG. ................ - .............EEE - ......E...EEEEEE - .........EEEEEEE - .........EEEEEEC - ........EEEEIIIE - ...EEE.EEEEIIIEE - .E...EEEEEEIEEEE - .....EEEEEEIEEEE - ....EEEEEEEIEEEE - .......IEEIIEEII - ....EEEEEEEEEEII - ...EEEEIIEEEIIII - ..EEEEIIEEEEIIII - ..EEEIIEEEEEIIII -} -# tile 124 (explosion magical 1) -{ ................ ................ - E........EEEEEE. - EEEEEEIEEEEEEEE. - EEEEEEIIIIIEEEEE - IIIEEEIEEEEEEEEE - EEEEEEIEEEEEEEEE - EEEEEEIEEEEEEEEI - EEIIIIIIIIIIIEII - IIEEEIEIIIIIEEEE - IHIEIEIIIEIIIEEE - ILLEIIIEEIIIIIEE - IHIIIIIEIIIIEEEE - IIIIIEIIEIIILEEE - IIIIIIIIEIEIELEE - ILHIIIHLHHEEEEEE -} -# tile 125 (explosion magical 2) -{ ................ ................ ................ - ........E...E... - EEEEE........... - EEEEEE...E..E... - EEEEEEE......... - IIIIIIEEEE...... - EEEEEIIEEEE..... - IIEEEEEEEEEE.... - EEIEEIIIIEEE.... - EEIEEEEEIEEE.... - EELEEIEEEEEE.E.. - EEEIIIIIEEEE.... - EEIEIIEIEEEE.... - EIEEIIEIEEEEE... -} -# tile 126 (explosion magical 3) -{ - ..EEEIEIEEEIIIII - ..EEEIEEEEEIEIII - ...EEIEEIIIIIIIE - ...EEEEEEIIIIIII - ..EEEIEEIIEIIIEI - .EEEIIIEIIIIIIEI - .EEEIEEEINIIIIII - .EEEIEEEIIIEEEEI - .EEEIEEEIIIIIENN - .EEEIIEEIIIIIINN - ..EEEIIEEIIIINNI - ...EEEIIIEIIIIII - ....EEEIIIIIIIIN - .....EEIIIIINNEI - ..E.EIIIENIIIIIN - ....EIIIIIIIIIIN } -# tile 127 (explosion magical 4) +# tile 108 (acid zap 8 2) { - EINEEIIIIEINEEEE - ININIIEIEENIENEI - NEIIINEIINNNEENI - IEIIINNNIINNIEII - NNNIINNNNINNIIIE - NNIIIIIINNNNEIIE - NNINNNNNNNNNNEII - NIINNNNNNNNNNNII - NNNNNNNNNNNNINNN - INNNNNNNNNNNNNNN - INNININNNNNNNNIE - IINNNNNNNNNNNIIE - NNNNNNNNNNNNIIII - NIININNNNNNNIIIE - NNNNNNNNNIIIIIIE - IIIINNNNIIIINNII + GGG............. + GGGG............ + GGGG............ + .GGGG........... + ...GGGG......... + ....GGGG........ + ....GGGG........ + .....GGGG....... + .......GGGG..... + ........GGGG.... + ........GGGG.... + .........GGGG... + ...........GGGG. + ............GGGG + ............GGGG + .............GGG } -# tile 128 (explosion magical 5) +# tile 109 (acid zap 8 3) { - IIEEEIEIEIEEEE.. - IIEEEEEIEIEEEE.. - IIEEEEEIEIEEEE.. - IIEEEEEIIIEEEE.. - IIEEIEIEEIEEEE.. - IIIIIIIEIIEEE... - IIIEIIIEEEEEE... - IIEEIEEEEEEEE... - EEIIIIIEEEEE.... - IIEEIIIEEIE...E. - EIIIIIIIII...... - IEEEEIIEEI..E... - IINEIIIIEEE..... - NIIIIIIEEEEE.... - NENIIIEEEEEEE... - IIIIIIEEEEEEEE.. + .............GGG + ............GGGG + ............GGGG + ...........GGGG. + .........GGGG... + ........GGGG.... + ........GGGG.... + .......GGGG..... + .....GGGG....... + ....GGGG........ + ....GGGG........ + ...GGGG......... + .GGGG........... + GGGG............ + GGGG............ + GGG............. } -# tile 129 (explosion magical 6) +# tile 110 (dig beam) { - ....EIIIIIIIHIII - ....EIIIIIIIEHII - .E..EEIIIIIIEIHI - ...EEEIEIIIIIEEI - ...EEEEIIEEIIIEI - ...EEEEIIIIIIIIE - ...EEEEIIEIIHIIE - ...EEEEEIEEEIIII - ...EEEEEIIEEIIII - ....EEEEEEEEEIII - .....EEEHEEEEEEE - ...E..EEEEEEEEEE - ........EE.EEEEE - ...E........EEEE - ................ + ....AAAA........ + ..A....AA..AA... + .AA.AAA......AA. + .AA.A....A..AA.. + ..A....A.A.A.AA. + .A..AAA.A....AA. + .A.AA.....A.AA.. + ...AA....AA..... + .A.A...A...A.A.. + ...A......AA.AA. + .A.AAA.AAAA.A.A. + .AA..AA.......A. + ..A...AA..A..AA. + ..AAAAA..AAAAA.. + ....AA....AAA... ................ } -# tile 130 (explosion magical 7) +# tile 111 (flash beam) { - IIINNNNNINNNINII - NNIINNIIIINIEIII - IIIIIIIIIIEIIEII - IIINEIEEINIEEIII - IINNNNIEIIEENINE - NIIEIEIININIIEEI - EIIIIEENIIIIIIII - NEIIIIIIIEIIIIII - INIEIEEEEEEEEEEI - NEININEEEIIIIIIE - EEEIEIIIIIIEEEEE - EEEEEEIEIIEEEEEE - EEEEEEEEEEEEEEEE - EEEE..........EE ................ + .....NNNNNN..... + ...NNNNNNNNNN... + ..NNNNNNNNNNNN.. + ..NNNNNNNNNNNN.. + .NNNNNNNNNNNNNN. + .NNNNNNNNNNNNNN. + .NNNNNNNNNNNNNN. + .NNNNNNNNNNNNNN. + .NNNNNNNNNNNNNN. + .NNNNNNNNNNNNNN. + ..NNNNNNNNNNNN.. + ..NNNNNNNNNNNN.. + ...NNNNNNNNNN... + .....NNNNNN..... ................ } -# tile 131 (explosion magical 8) +# tile 112 (boom left) { - IIIIIIIEEEEEEE.. - IIEIIEIEEIEIEE.. - IIIIEIIEEIEIEE.. - IIIEEEIEEIEIEE.. - IEEEEEIEEEIIEE.. - IIIEEIIEEEIEEE.. - IEEEIIEEEIIEEE.. - IEIEEIEEEEEEEE.. - EEIEEEEEEIEEEE.. - IIIEEEEEEEEEEE.. - IEEEEEEEE.EEE... - EEEEEEEE........ - EEEEEE....E..... - EEE...E......... ................ ................ -} -# tile 132 (explosion fiery 0) -{ + ....KK.......... + ....KHKA........ + .....KHKA....... + ......KKKA...... + .......KKKA..... + ........KDKA.... + ........JDKA.... + .......JKDJA.... + ......JKDJA..... + .....JHDJA...... + ....JHDJA....... + .....KJA........ ................ ................ - .............DDD - ......D...DDDDDD - .........DDDDDDD - .........DDDDDDC - ........DDDDCCCD - ...DDD.DDDDCCCDD - .D...DDDDDDCDDDD - .....DDDDDDCDDDD - ....DDDDDDDCDDDD - .......CDDCCDDCC - ....DDDDDDDDDDCC - ...DDDDCCDDDCCCC - ..DDDDCCDDDDCCCC - ..DDDCCDDDDDCCCC } -# tile 133 (explosion fiery 1) +# tile 113 (boom right) { ................ ................ - D........DDDDDD. - DDDDDDCDDDDDDDD. - DDDDDDCCCCCDDDDD - CCCDDDCDDDDDDDDD - DDDDDDCDDDDDDDDD - DDDDDDCDDDDDDDDC - DDCCCCCCCCCCCDCC - CCDDDCDCCCCCDDDD - CHCDCDCCCDCCCDDD - CLLDCCCDDCCCCCDD - CHCCCCCDCCCCDDDD - CCCCCDCCDCCCLDDD - CCCCCCCCDCDCDLDD - CLHCCCHLHHDDDDDD -} -# tile 134 (explosion fiery 2) -{ - ................ + .........JK..... + ........JDHJ.... + .......JDHJA.... + ......JDKJA..... + .....JDKJA...... + .....KDJA....... + .....KDKA....... + ......KKKA...... + .......KKKA..... + ........KHKA.... + .........KHKA... + ..........KKA... ................ ................ - ........D...D... - DDDDD........... - DDDDDD...D..D... - DDDDDDD......... - CCCCCCDDDD...... - DDDDDCCDDDD..... - CCDDDDDDDDDD.... - DDCDDCCCCDDD.... - DDCDDDDDCDDD.... - DDLDDCDDDDDD.D.. - DDDCCCCCDDDD.... - DDCDCCDCDDDD.... - DCDDCCDCDDDDD... -} -# tile 135 (explosion fiery 3) -{ - ..DDDCDCDDDCCCCC - ..DDDCDDDDDCDLCC - ...DDCDDCCCCCCCD - ...DDDDDDCCCCLLC - ..DDDCDDCCDCCLDL - .DDDCCCDCCCCLCDL - .DDDCDDDCHCCLCCL - .DDDCDDDCCCDDDDL - .DDDCDDDCCCCLDHH - .DDDCCDDCCCCLLHH - ..DDDCCDDCCCLHHL - ...DDDCCCDLCLLLL - ....DDDCCCLCCLCH - .....DDCCCCCHHDC - ..D.DCCCDHLCCCLH - ....DCCCCCCCCCLH -} -# tile 136 (explosion fiery 4) -{ - DLHDDCCLLDLHDDDD - CHLHCCDCDDHLDHDC - HDLCLHDCCHHHDDHC - LDLLLHHHCCHHLDCC - HHHLLHHHHLHHLCCD - HHLLCLLLHHHHDCCD - HHLHHHHHHHHHHDCC - HLLHHHHHHHHHHHCC - HHHHHHNNNNHHLHNH - LHHHHHHHNHHHHHNH - LHHLHLNNNNHHHHLD - LLNHNHNNNNHHHLLD - HHHHNHNNNHHHLLLL - HLLNLHNNNHHHLLLD - HHHHNHNHNCLLLCLD - LLLLNHHHLLLCHHCC } -# tile 137 (explosion fiery 5) +# tile 114 (shield1) { - CCDDDCDCDCDDDD.. - CCDDDDDCDCDDDD.. - CCDDDDDCDCDDDD.. - LCDDDDDCCCDDDD.. - LCDDLDLDDCDDDD.. - LCCCLCCDCCDDD... - CCCDLCCDDDDDD... - CLDDLDDDDDDDD... - DDLCCCLDDDDD.... - CCDDCLLDDCD...D. - DCCCLLCCCC...... - CDDDDLLDDC..D... - CCHDCLLCDDD..... - HCCCCCCDDDDD.... - HDHCCCDDDDDDD... - CCCCLLDDDDDDDD.. + ................ + .....I....I..... + ....I......I.... + ...I........I... + ..I...IIII...I.. + .I............I. + ....I..II..I.... + ....I.IIII.I.... + ....I.IIII.I.... + ....I..II..I.... + .I............I. + ..I...IIII...I.. + ...I........I... + ....I......I.... + .....I....I..... + ................ } -# tile 138 (explosion fiery 6) +# tile 115 (shield2) { - ....DCCCCCCCHCCL - ....DCCCCCCCDHCC - .D..DDCCCLCCDCHC - ...DDDCDCCLCCDDL - ...DDDDCCDDLCCDC - ...DDDDCCCCLCCCD - ...DDDDCCDCCHCCD - ...DDDDDCDDDCCCC - ...DDDDDCCDDCCCC - ....DDDDDDDDDCCC - .....DDDHDDDDDDD - ...D..DDDDDDDDDD - ........DD.DDDDD - ...D........DDDD ................ + .CCCCCCCCCCCCCCC + .C.............. + .C.CCCCCCCCCCCC. + .C.C..........C. + .C.C.CCCCCCCC.C. + .C.C.C......C.C. + .C.C.C.CCCC.C.C. + .C.C.C.CC.C.C.C. + .C.C.C....C.C.C. + .C.C.CCCCCC.C.C. + .C.C........C.C. + .C.CCCCCCCCCC.C. + .C............C. + .CCCCCCCCCCCCCC. ................ } -# tile 139 (explosion fiery 7) +# tile 116 (shield3) +{ + .......HH....... + .......HH....... + ....HH.HH.HH.... + ...H...HH...H... + ..H.H......H.H.. + ..H..H....H..H.. + ......H..H...... + HHHH...HH...HHHH + HHHH...HH...HHHH + ......H..H...... + ..H..H....H..H.. + ..H.H......H.H.. + ...H...HH...H... + ....HH.HH.HH.... + .......HH....... + .......HH....... +} +# tile 117 (shield4) { - LLLHHHHHLHHHCHCC - HHLLHHLLLLHCDCCC - LLLLLLLLLLDCCDLL - CLLHDCDDCHLDDCCC - CCHHHHCDCCDDHLHD - HLLDLDLCHCHCLDDC - DCCLLDDHCCCCCCCL - HDCCCCCCCDCCCCCC - LHLDCDDDDDDDDDDL - HDCHLHDDDCCCCCCD - DDDCDCLLCCCDDDDD - DDDDDDCDCCDDDDDD - DDDDDDDDDDDDDDDD - DDDD..........DD ................ + ......NNNNN..... + ........N....... + ...NNNN.N.NNN... + ...N..N.N.N.N... + .N.NNNN.N.N.N... + .N......N.NNN.N. + .NNNNNNNN.....N. + .N.....NNNNNNNN. + .N.NNN.N......N. + ...N.N.N.NNNN.N. + ...N.N.N.N..N... + ...NNN.N.NNNN... + .......N........ + .....NNNNN...... ................ } -# tile 140 (explosion fiery 8) +# tile 118 (poison cloud) { - CCCCLCCDDDDDDD.. - CCDCCDCDDCDCDD.. - LLCCDCCDDCDCDD.. - CCCDDDCDDCDCDD.. - CDDDDDCDDDCCDD.. - CCLDDCCDDDCDDD.. - CDDDCCDDDCCDDD.. - CDCDDCDDDDDDDD.. - DDCDDDDDDCDDDD.. - CCCDDDDDDDDDDD.. - CDDDDDDDD.DDD... - DDDDDDDD........ - DDDDDD....D..... - DDD...D......... - ................ - ................ + BBBBBBBBBBBBBBBB + BBBBBFFFFFFFBBBB + BBBFFFFFFFFFFBBB + BBFFFFFFFFFGFFBB + BBFFFFFFFFFFFFFB + BFFFFFFFFFFFFGFB + FFFGFFFFFFFFGFFF + FFFFFFFFFFGGFFFF + FFFFFFFFFFFFFGFF + FFGGFFFFFFFGGFFG + FFFFFGGGGGFFFFGG + BGFFFFFFFFFFGGGB + BBGGGFFFFGGGGGGB + BBBGGGGGGGGGGBBB + BBBBBBGGGGBBBBBB + BBBBBBBBBBBBBBBB } -# tile 141 (explosion frosty 0) +# S_goodpos (dollar sign from generic coin tile) +# tile 119 (valid position) { ................ ................ - .............EEE - .....NE...EEEEEE - ..N...N..ENBEEEE - .N.N.N...EEEEEEP - ....N...EEEEPPPE - ...NEN.NEEEPPPEE - .EN..ENEEEEPNBEE - ...N.EEEEEEPEEEE - ....EENBEEEPEEEE - .......PEEPPEEPP - ....EEEEEEEEEEPP - ...EEEEPPEEEPPPP - ..EEEEPPNBEEPPPP - ..EEEPPEEEEEPPPP -} -# tile 142 (explosion frosty 1) -{ + ................ + ........B....... + .......OOO...... + ......O.BSS..... + ......OSB....... + .......OOO...... + ........BSO..... + ........B.OS.... + .......OOO.S.... + ........BSS..... + ................ + ................ ................ ................ - E........EEEEEE. - ENBEENPEEEENBEE. - EEEEEENPNPNEEEEE - PPBEEEPENEEEEEEE - EEEEEENNNNNEEEEE - EEEEEEPENEEENBEP - EEPPPPNPNPNPPPPP - PPEEENEPPPPNEEEE - PNPEPEPPPEPPPEEE - PBBEPPPEEPPNBPEE - PNPPPPPEPPPPEEEE - PPPPPEPPEPPPBEEE - PPPPPPPPEPEPEBEE - PBNPPPNBNNEEEEEE } -# tile 143 (explosion frosty 2) +# tile 120 (swallow top left) { + AAAAAAADDDDDDAAA + AAAAADDDDDDDDDDD + AAAADDDDDDDDDDDD + AAADDDDDDCCDDDDD + AAADDDCCCCCCDDDD + AADDDDCCCCCDDDDD + AADDDCCCCCDDDDDD + AADDDCCCCDDDDD.. + AADDDCCCDDDD.... + AADDDCCCDDDD.... + AADDDDDDDDD..... + AAADDDDDDD...... + AAADDDDDDD...... + AAAADDDDDD...... + AAAADDDDDD...... + AAAADDDDDD...... +} +# tile 121 (swallow top center) +{ + AAAAAAAAAAAAAAAA + DDAAAAAAAAAAAAAA + DDDDAAAAAAAAAADD + DDDDDDDDDDDDDDDD + DDDDDDDDDDDDDDDD + DDDDDDDDDDDDDDDD + DDDDDDDCCCCCCDDD + .DDDDDDDDCCCCCDD + ...DDDDDDDDDDDDD + ....DDDDDDDDDDDD + ......DDDDDDDD.. + .......DDDD..... + ................ ................ ................ ................ - ........E...E... - EEEEE........... - EEEEEE...E..N... - EEEEEEEN..NN.... - PPPPPPENEN...... - EEEEEPPENEN.N... - PPEEEEEEEEEN.N.. - EEPEEPPPPNNE.N.. - EEPEEEEENEEE.... - EEBEEPEEEEEE.E.. - EEEPPPPPEEEE.... - EEPEPPEPEEEE.... - EPEEPPEPEEEEE... } -# tile 144 (explosion frosty 3) +# tile 122 (swallow top right) { - ..EEEPEPEEEPPPPP - ..EEEPEEEEEPEBPP - ...EEPEEPPPPPPPE - ...ENENEEPPPPBBP - ..EEENEEPPEPPBEB - .EEENENEPPPPBPEB - .EEEPEEEPNPPBPPB - .EEEPEEEPPPEEEEB - .EEEPEEEPPPPBENN - .EEEPPEEPPPPBBNN - ..EEEPNEEPPPBNNB - ...EENNNPEBPBBBB - ....EENPPPBPPBPN - .....EEPPPPPNNEP - ..E.EPPPENBPPPBN - ....EPPPPPPPPPBN + AAAAAAAAAAAAAAAA + AAADDDDDAAAAAAAA + DDDDDDDDDDDAAAAA + DDDDDDDDDDDDAAAA + DDDDDCCCDDDDDAAA + DDDDDCCCCDDDDDAA + DDDDDCCCCDDDDDDA + DDDDDCCCCCDDDDDD + DDDDDDCCCCCDDDDD + DDDDDDDCCCCDDDDD + ...DDDDDCCCDDDDD + ...DDDDDDCCDDDDD + ....DDDDDDDDDDDD + ....DDDDDDDDDDDD + ....DDDDDDDDDDDD + ....DDDDDDDDDDDA } -# tile 145 (explosion frosty 4) +# tile 123 (swallow middle left) { - EBNEEPPBBEBNEEEE - PNBNPPEPEENBENEP - NEBPBNEPPNNNEENP - BEBBBNNNPPNNBEPP - NNNBBNNNNBNNBPPE - NNBBPBBBNNNNEPPE - NNBNNNNNNNNNNEPP - NBBNNNNNNNNNNNPP - NNNNNNNNNNNNBNNN - BNNNNNNNNNNNNNNN - BNNBNBNNNNNNNNBE - BBNNNNNNNNNNNBBE - NNNNNNNNNNNNBBBB - NBBNBNNNNNNNBBBE - NNNNNNNNNPBBBPBE - BBBBNNNNBBBPNNPP + AAAADDDDDD...... + AAAADDDDDDD..... + AAAADDDDDDD..... + AAAADDDDDDDD.... + AAAADDCCCDDD.... + AAADDDDCCDDD.... + AADDDDCCCDDD.... + AADDDDCCCDDD.... + AADDDDCDDDDD.... + ADDDDDDDDDD..... + ADDDDDDDDD...... + DDDDDDDDD....... + DDDDDDDD........ + DDDDDDD......... + DDDDDDD......... + DDCCDDD......... } -# tile 146 (explosion frosty 5) +# tile 124 (swallow middle right) { - PPEEEPEPEPEEEE.. - PPEEEEEPEPEEEE.. - PPEEEEEPEPEEEE.. - BPEEEEEPPPEEEE.. - BPEEBEBEEPEEEE.. - BPPPBPPEPPEEE... - PPPEBPPENEEEN... - PBEEBEEEENENE... - EEBPPPBNNNNNNN.. - PPEEPBBEENEN..E. - EPPPBBPPNP..N... - PEEEEBBEEP..E... - PPNEPBBPEEE..... - NPPPPPPEEEEE.... - NENPPPEEEEEEE... - PPPPBBEEEEEEEE.. + ....DDDDDDDDDDDA + ....DDDDDDDDDDDA + ....DDDDDDDDDDAA + ....DDDDDDDDDDAA + ...DDDDDDDDDDDAA + ..DDDCCDDDDDDAAA + ..DDDCCDDDDDDAAA + ..DDDCCDDDDDAAAA + ..DDDCCDDDDDAAAA + ..DDDDDDDDDDAAAA + ...DDDDDDDDDAAAA + ...DDDDDDDDDAAAA + ....DDDDDDDDDAAA + .....DDDDDDDDAAA + ......DDDDDDDDAA + .......DDDDDDDAA } -# tile 147 (explosion frosty 6) +# tile 125 (swallow bottom left) { - ....EPPPPPPPNPPB - ....EPPPPPPPENPP - .E..EEPPPBPPEPNP - ...EEEPEPPBPPEEB - ...EENEPPEEBPPEP - ...NEEENPPPBPPPE - ..NENPNPNEPPNPPE - ...NNENNPEEEPPPP - .N.PEEEPPNEEPPPP - ...NNENNEEEEEPPP - ..N.NPNENEEEEEEE - ...N..ENEEEEEEEE - .....N..EE.EEEEE - ...E........EEEE - ................ - ................ + DDDCDDD......... + DDDCDDD......... + ADDCDDD......... + ADDDDDDD........ + ADDDDDDDDDDDD... + AADDDDDDDDDDDDDD + AADDDDDDDDDDDDDD + AAADDDDDDDDCDDDD + AAAAADDDDDDCCCCD + AAAAAAADDDDDCCCD + AAAAAAAAADDDDCCC + AAAAAAAAAADDDDCC + AAAAAAAAAAADDDDD + AAAAAAAAAAADDDDD + AAAAAAAAAAAADDDD + AAAAAAAAAAAAAADD } -# tile 148 (explosion frosty 7) +# tile 126 (swallow bottom center) { - BBBNNNNNBNNNPNPP - NNBBNNBBBBNPEPPP - BBBBBBBBBBEPPEBB - PBBNEPEEPNBEEPPP - PPNNNNPEPPEENBNE - NBBEBEBPNPNPBEEP - EPPBBEENPPPPPPPB - NEPPPPPPPEPPPPPP - BNBEPEEEEEEEEEEB - NEPNBNEEEPNENPPE - EEEPEPBBPPPNEEEE - EEEEEEPEPNNNNNEE - EEEEEEEEEEENEEEE - EEEE......N.N.EE ................ ................ -} -# tile 149 (explosion frosty 8) -{ - PPPPBPPEEEEEEE.. - PPEPPEPEEPEPEE.. - BBPPEPPEEPEPNEN. - PPPEEEPEEPEPEN.. - PEEEEEPEEEPPNEN. - PPBEEPNENEPEEE.. - PEEEPPENEPPEEE.. - PEPEENNNNNEEEE.. - EEPEEEENEPEEEE.. - PPPEEENENEEEEE.. - PEEEEEEEE.EEE... - EEEEEEEE........ - EEEEEE....EN.... - EEE...E...N.N... - ...........N.... ................ + ................ + .............DDD + ............DDDD + D...........DDDD + DD..........DDDC + DDD.........DDDC + DDDD........DDDC + DDDDDD....DDDDDC + DDDDDDDDDDDDDDDC + DDDDDDDDDDDDDDDC + DDDDDDDDDDDDDDDD + DDDDDDDDDDDDDDDD + DDDDDDDDDDDDDDAA } -# tile 150 (zap 0 0) +# tile 127 (swallow bottom right) { - .......II....... - ......IIII...... - ......IIII...... - .......II....... - .......II....... - ......IIII...... - ......IIII...... - .......II....... - .......II....... - ......IIII...... - ......IIII...... - .......II....... - .......II....... - ......IIII...... - ......IIII...... - .......II....... + ......DDDDDDDDAA + ......DDDDDDDDDA + .....DDDDDDDDDDA + ....DDDDDDDDDDDA + DDDDDDDDDDDDDDDA + DDDDDDDDDDDDDDDA + CCCDDDDDDDDDDDAA + CCCCDDDDDDDDDDAA + CCCDDDDDDDDDDDAA + CCDDDDDDDDDDDAAA + CCDDDDDDAAAAAAAA + CDDDDDAAAAAAAAAA + CDDDDAAAAAAAAAAA + DDDDAAAAAAAAAAAA + DDAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA } -# tile 151 (zap 0 1) +# tile 128 (explosion dark top left) { ................ ................ + .............AAA + ......A...AAAAAA + .........AAAAAAA + .........AAAAAA. + ........AAAA...A + ...AAA.AAAA...AA + .A...AAAAAA.AAAA + .....AAAAAA.AAAA + ....AAAAAAA.AAAA + ........AA..AA.. + ....AAAAAAAAAA.. + ...AAAA..AAA.... + ..AAAA..AAAA.... + ..AAA..AAAAA.... +} +# tile 129 (explosion dark top center) +{ ................ ................ - ................ - ................ - .II..II..II..II. - IIIIIIIIIIIIIIII - IIIIIIIIIIIIIIII - .II..II..II..II. - ................ - ................ - ................ + A........AAAAAA. + AAAAAA.AAAAAAAA. + AAAAAA.....AAAAA + ...AAA.AAAAAAAAA + AAAAAA.AAAAAAAAA + AAAAAA.AAAAAAAA. + AA...........A.. + ..AAA.A.....AAAA + .A.A.A...A...AAA + .PPA...AA.....AA + .A.....A....AAAA + .....A..A...PAAA + ........A.A.APAA + .PA...APAAAAAAAA +} +# tile 130 (explosion dark top right) +{ ................ ................ ................ + ........A...A... + AAAAA........... + AAAAAA...A..A... + AAAAAAA......... + ......AAAA...... + AAAAA..AAAA..... + ..AAAAAAAAAA.... + AA.AA....AAA.... + AA.AAAAA.AAA.... + AAPAA.AAAAAA.A.. + AAA.....AAAA.... + AA.A..A.AAAA.... + A.AA..A.AAAAA... } -# tile 152 (zap 0 2) +# tile 131 (explosion dark middle left) { - III............. - IIII............ - IIII............ - .IIII........... - ...IIII......... - ....IIII........ - ....IIII........ - .....IIII....... - .......IIII..... - ........IIII.... - ........IIII.... - .........IIII... - ...........IIII. - ............IIII - ............IIII - .............III + ..AAA.A.AAA..... + ..AAA.AAAAA.AP.. + ...AA.AA.......A + ...AAAAAA....PP. + ..AAA.AA..A..PAP + .AAA...A....P.AP + .AAA.AAA.A..P..P + .AAA.AAA...AAAAP + .AAA.AAA....PAAA + .AAA..AA....PPAA + ..AAA..AA...PAAP + ...AAA...AP.PPPP + ....AAA...P..P.A + .....AA.....AAA. + ..A.A...AAP...PA + ....A.........PA } -# tile 153 (zap 0 3) +# tile 132 (explosion dark middle center) { - .............III - ............IIII - ............IIII - ...........IIII. - .........IIII... - ........IIII.... - ........IIII.... - .......IIII..... - .....IIII....... - ....IIII........ - ....IIII........ - ...IIII......... - .IIII........... - IIII............ - IIII............ - III............. + APAAA..PPAPAAAAA + .APA..A.AAAPAAA. + AAP.PAA..AAAAAA. + PAPPPAAA..AAPA.. + AAAPPAAAAPAAP..A + AAPP.PPPAAAAA..A + AAPAAAAAAAAAAA.. + APPAAAAAAAAAAA.. + AAAAAAAAAAAAPAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAA.AA + AAAAAAAAAAA.HH.. } -# tile 154 (zap 1 0) +# tile 133 (explosion dark middle right) { - .......CC....... - ......CCCC...... - ......CCCC...... - .......CC....... - .......CC....... - ......CCCC...... - ......CCCC...... - .......CC....... - .......CC....... - ......CCCC...... - ......CCCC...... - .......CC....... - .......CC....... - ......CCCC...... - ......CCCC...... - .......CC....... + ..AAA.A.A.AAAA.. + ..AAAAA.A.AAAA.. + ..AAAAA.A.AAAA.. + P.AAAAA...AAAA.. + P.AAPAPAA.AAAA.. + P...P..A..AAA... + ...AP..AAAAAA... + .PAAPAAAAAAAA... + AAP...PAAAAA.... + ..AA.PPAA.A...A. + A...PP.......... + .AAAAPPAA...A... + ..AA.PP.AAA..... + A......AAAAA.... + AAA...AAAAAAA... + ....PPAAAAAAAA.. +} +# tile 134 (explosion dark bottom left) +{ + ....A.......A..P + ....A.......AA.. + .A..AA...P..A.A. + ...AAA.A..P..AAP + ...AAAA..AAP..A. + ...AAAA....P...A + ...AAAA..A..A..A + ...AAAAA.AAA.... + ...AAAAA..AA.... + ....AAAAAAAAA... + .....AAAAAAAAAAA + ...A..AAAAAAAAAA + ........AA.AAAAA + ...A........AAAA + ................ + ................ } -# tile 155 (zap 1 1) +# tile 135 (explosion dark bottom center) { + PPPAAAAAPAAA.A.. + AAPPAAPPPPA.A... + PPPPPPPPPPA..APP + .PPAA.AA.APAA... + ..AAAA.A..AAAPAA + APPAPAP.A.A.PAA. + A..PPAAA.......P + AA.......A...... + PAPA.AAAAAAAAAAP + AA.APAAAA......A + AAA.A.PP...AAAAA + AAAAAA.A..AAAAAA + AAAAAAAAAAAAAAAA + AAAA..........AA ................ ................ +} +# tile 136 (explosion dark bottom right) +{ + ....P..AAAAAAA.. + ..A..A.AA.A.AA.. + PP..A..AA.A.AA.. + ...AAA.AA.A.AA.. + .AAAAA.AAA..AA.. + ..PAA..AAA.AAA.. + .AAA..AAA..AAA.. + .A.AA.AAAAAAAA.. + AA.AAAAAA.AAAA.. + ...AAAAAAAAAAA.. + .AAAAAAAA.AAA... + AAAAAAAA........ + AAAAAA....A..... + AAA...A......... ................ ................ +} +# tile 137 (explosion noxious top left) +{ ................ ................ - .CC..CC..CC..CC. - CCCCCCCCCCCCCCCC - CCCCCCCCCCCCCCCC - .CC..CC..CC..CC. - ................ + .............FFF + ......F...FFFFFF + .........FFFFFFF + .........FFFFFF. + ........FFFF...F + ...FFF.FFFF...FF + .F...FFFFFF.FFFF + .....FFFFFF.FFFF + ....FFFFFFF.FFFF + ........FF..FF.. + ....FFFFFFFFFF.. + ...FFFF..FFF.... + ..FFFF..FFFF.... + ..FFF..FFFFF.... +} +# tile 138 (explosion noxious top center) +{ ................ ................ + F........FFFFFF. + FFFFFF.FFFFFFFF. + FFFFFF.....FFFFF + ...FFF.FFFFFFFFF + FFFFFF.FFFFFFFFF + FFFFFF.FFFFFFFF. + FF...........F.. + ..FFF.F.....FFFF + .H.F.F...F...FFF + .GGF...FF.....FF + .H.....F....FFFF + .....F..F...GFFF + ........F.F.FGFF + .GH...HGHHFFFFFF +} +# tile 139 (explosion noxious top right) +{ ................ ................ ................ + ........F...F... + FFFFF........... + FFFFFF...F..F... + FFFFFFF......... + ......FFFF...... + FFFFF..FFFF..... + ..FFFFFFFFFF.... + FF.FF....FFF.... + FF.FFFFF.FFF.... + FFGFF.FFFFFF.F.. + FFF.....FFFF.... + FF.F..F.FFFF.... + F.FF..F.FFFFF... } -# tile 156 (zap 1 2) +# tile 140 (explosion noxious middle left) { - CCC............. - CCCC............ - CCCC............ - .CCCC........... - ...CCCC......... - ....CCCC........ - ....CCCC........ - .....CCCC....... - .......CCCC..... - ........CCCC.... - ........CCCC.... - .........CCCC... - ...........CCCC. - ............CCCC - ............CCCC - .............CCC + ..FFF.F.FFF..... + ..FFF.FFFFF.FG.. + ...FF.FF.......F + ...FFFFFF....GG. + ..FFF.FF..F..GFG + .FFF...F....G.FG + .FFF.FFF.H..G..G + .FFF.FFF...FFFFG + .FFF.FFF....GFHH + .FFF..FF....GGHH + ..FFF..FF...GHHG + ...FFF...FG.GGGG + ....FFF...G..G.H + .....FF.....HHF. + ..F.F...FHG...GH + ....F.........GH } -# tile 157 (zap 1 3) +# tile 141 (explosion noxious middle center) { - .............CCC - ............CCCC - ............CCCC - ...........CCCC. - .........CCCC... - ........CCCC.... - ........CCCC.... - .......CCCC..... - .....CCCC....... - ....CCCC........ - ....CCCC........ - ...CCCC......... - .CCCC........... - CCCC............ - CCCC............ - CCC............. + FGHFF..GGFGHFFFF + .HGH..F.FFHGFHF. + HFG.GHF..HHHFFH. + GFGGGHHH..HHGF.. + HHHGGHHHHGHHG..F + HHGG.GGGHHHHF..F + HHGHHHHHHHHHHF.. + HGGHHHHHHHHHHH.. + HHHHHHNNNNHHGHNH + GHHHHHHHNHHHHHNH + GHHGHGNNNNHHHHGF + GGNHNHNNNNHHHGGF + HHHHNHNNNHHHGGGG + HGGNGHNNNHHHGGGF + HHHHNHNHN.GGG.GF + GGGGNHHHGGG.HH.. } -# tile 158 (zap 2 0) +# tile 142 (explosion noxious middle right) { - .......NN....... - ......NNNN...... - ......NNNN...... - .......NN....... - .......NN....... - ......NNNN...... - ......NNNN...... - .......NN....... - .......NN....... - ......NNNN...... - ......NNNN...... - .......NN....... - .......NN....... - ......NNNN...... - ......NNNN...... - .......NN....... + ..FFF.F.F.FFFF.. + ..FFFFF.F.FFFF.. + ..FFFFF.F.FFFF.. + G.FFFFF...FFFF.. + G.FFGFGFF.FFFF.. + G...G.GF..FFF... + ...FG..FFFFFF... + .GFFFFFFFFFFF... + FFG...GFFFFF.... + ..FF.GGFF.F...F. + F...GG.......... + .FFFFGGFF...F... + ..HF.GG.FFF..... + H......FFFFF.... + HFH...FFFFFFF... + ....GGFFFFFFFF.. } -# tile 159 (zap 2 1) +# tile 143 (explosion noxious bottom left) { + ....F.......H..G + ....F.......FH.. + .F..FF...G..F.H. + ...FFF.F..G..FFG + ...FFFF..FFG..F. + ...FFFF....G...F + ...FFFF..F..H..F + ...FFFFF.FFF.... + ...FFFFF..FF.... + ....FFFFFFFFF... + .....FFFHFFFFFFF + ...F..FFFFFFFFFF + ........FF.FFFFF + ...F........FFFF ................ ................ +} +# tile 144 (explosion noxious bottom center) +{ + GGGHHHHHGHHH.H.. + HHGGHHGGGGH.F... + GGGGGGGGGGF..FGG + .GGHF.FF.HGFF... + ..HHHH.F..FFHGHF + HGGFGFG.H.H.GFF. + F..GGFFH.......G + HF.......F...... + GHGF.FFFFFFFFFFG + HF.HGHFFF......F + FFF.F.GG...FFFFF + FFFFFF.F..FFFFFF + FFFFFFFFFFFFFFFF + FFFF..........FF ................ ................ +} +# tile 145 (explosion noxious bottom right) +{ + ....G..FFFFFFF.. + ..F..F.FF.F.FF.. + GG..F..FF.F.FF.. + ...FFF.FF.F.FF.. + .FFFFF.FFF..FF.. + ..GFF..FFF.FFF.. + .FFF..FFF..FFF.. + .F.FF.FFFFFFFF.. + FF.FFFFFF.FFFF.. + ...FFFFFFFFFFF.. + .FFFFFFFF.FFF... + FFFFFFFF........ + FFFFFF....F..... + FFF...F......... + ................ ................ +} +# tile 146 (explosion muddy top left) +{ ................ - .NN..NN..NN..NN. - NNNNNNNNNNNNNNNN - NNNNNNNNNNNNNNNN - .NN..NN..NN..NN. ................ + .............JJJ + ......J...JJJJJJ + .........JJJJJJJ + .........JJJJJJK + ........JJJJKKKJ + ...JJJ.JJJJKKKJJ + .J...JJJJJJKJJJJ + .....JJJJJJKJJJJ + ....JJJJJJJKJJJJ + .......KJJKKJJKK + ....JJJJJJJJJJKK + ...JJJJKKJJJKKKK + ..JJJJKKJJJJKKKK + ..JJJKKJJJJJKKKK +} +# tile 147 (explosion muddy top center) +{ ................ ................ + J........JJJJJJ. + JJJJJJKJJJJJJJJ. + JJJJJJKKKKKJJJJJ + KKKJJJKJJJJJJJJJ + JJJJJJKJJJJJJJJJ + JJJJJJKJJJJJJJJK + JJKKKKKKKKKKKJKK + KKJJJKJKKKKKJJJJ + KLKJKJKKKJKKKJJJ + KCCJKKKJJKKKKKJJ + KLKKKKKJKKKKJJJJ + KKKKKJKKJKKKCJJJ + KKKKKKKKJKJKJCJJ + KCLKKKLCLLJJJJJJ +} +# tile 148 (explosion muddy top right) +{ ................ ................ ................ + ........J...J... + JJJJJ........... + JJJJJJ...J..J... + JJJJJJJ......... + KKKKKKJJJJ...... + JJJJJKKJJJJ..... + KKJJJJJJJJJJ.... + JJKJJKKKKJJJ.... + JJKJJJJJKJJJ.... + JJCJJKJJJJJJ.J.. + JJJKKKKKJJJJ.... + JJKJKKJKJJJJ.... + JKJJKKJKJJJJJ... } -# tile 160 (zap 2 2) +# tile 149 (explosion muddy middle left) { - NNN............. - NNNN............ - NNNN............ - .NNNN........... - ...NNNN......... - ....NNNN........ - ....NNNN........ - .....NNNN....... - .......NNNN..... - ........NNNN.... - ........NNNN.... - .........NNNN... - ...........NNNN. - ............NNNN - ............NNNN - .............NNN + ..JJJKJKJJJKKKKK + ..JJJKJJJJJKJCKK + ...JJKJJKKKKKKKJ + ...JJJJJJKKKKCCK + ..JJJKJJKKJKKCJC + .JJJKKKJKKKKCKJC + .JJJKJJJKLKKCKKC + .JJJKJJJKKKJJJJC + .JJJKJJJKKKKCJLL + .JJJKKJJKKKKCCLL + ..JJJKKJJKKKCLLC + ...JJJKKKJCKCCCC + ....JJJKKKCKKCKL + .....JJKKKKKLLJK + ..J.JKKKJLCKKKCL + ....JKKKKKKKKKCL } -# tile 161 (zap 2 3) +# tile 150 (explosion muddy middle center) { - .............NNN - ............NNNN - ............NNNN - ...........NNNN. - .........NNNN... - ........NNNN.... - ........NNNN.... - .......NNNN..... - .....NNNN....... - ....NNNN........ - ....NNNN........ - ...NNNN......... - .NNNN........... - NNNN............ - NNNN............ - NNN............. + JCLJJKKCCJCLJJJJ + KLCLKKJKJJLCJLJK + LJCKCLJKKLLLJJLK + CJCCCLLLKKLLCJKK + LLLCCLLLLCLLCKKJ + LLCCKCCCLLLLJKKJ + LLCLLLLLLLLLLJKK + LCCLLLLLLLLLLLKK + LLLLLLCCCCLLCLCL + CLLLLLLLCLLLLLCL + CLLCLCCCCCLLLLCJ + CCCLCLCCCCLLLCCJ + LLLLCLCCCLLLCCCC + LCCCCLCCCLLLCCCJ + LLLLCLCLCKCCCKCJ + CCCCCLLLCCCKLLKK } -# tile 162 (zap 3 0) +# tile 151 (explosion muddy middle right) { - .......BB....... - ......BBBB...... - ......BBBB...... - .......BB....... - .......BB....... - ......BBBB...... - ......BBBB...... - .......BB....... - .......BB....... - ......BBBB...... - ......BBBB...... - .......BB....... - .......BB....... - ......BBBB...... - ......BBBB...... - .......BB....... + KKJJJKJKJKJJJJ.. + KKJJJJJKJKJJJJ.. + KKJJJJJKJKJJJJ.. + CKJJJJJKKKJJJJ.. + CKJJCJCJJKJJJJ.. + CKKKCKKJKKJJJ... + KKKJCKKJJJJJJ... + KCJJCJJJJJJJJ... + JJCKKKCJJJJJ.... + KKJJKCCJJKJ...J. + JKKKCCKKKK...... + KJJJJCCJJK..J... + KKLJKCCKJJJ..... + LKKKKKKJJJJJ.... + LJLKKKJJJJJJJ... + KKKKCCJJJJJJJJ.. } -# tile 163 (zap 3 1) +# tile 152 (explosion muddy bottom left) { + ....JKKKKKKKLKKC + ....JKKKKKKKJLKK + .J..JJKKKCKKJKLK + ...JJJKJKKCKKJJC + ...JJJJKKJJCKKJK + ...JJJJKKKKCKKKJ + ...JJJJKKJKKLKKJ + ...JJJJJKJJJKKKK + ...JJJJJKKJJKKKK + ....JJJJJJJJJKKK + .....JJJLJJJJJJJ + ...J..JJJJJJJJJJ + ........JJ.JJJJJ + ...J........JJJJ ................ ................ +} +# tile 153 (explosion muddy bottom center) +{ + CCCLLLLLCLLLKLKK + LLCCLLCCCCLKJKKK + CCCCCCCCCCJKKJCC + KCCLJKJJKLCJJKKK + KKLLLLKJKKJJLCLJ + LCCJCJCKLKLKCJJK + JKKCCJJLKKKKKKKC + LJKKKKKKKJKKKKKK + CLCJKJJJJJJJJJJC + LJKLCLJJJKKKKKKJ + JJJKJKCCKKKJJJJJ + JJJJJJKJKKJJJJJJ + JJJJJJJJJJJJJJJJ + JJJJ..........JJ + ................ ................ +} +# tile 154 (explosion muddy bottom right) +{ + KKKKCKKJJJJJJJ.. + KKJKKJKJJKJKJJ.. + CCKKJKKJJKJKJJ.. + KKKJJJKJJKJKJJ.. + KJJJJJKJJJKKJJ.. + KKCJJKKJJJKJJJ.. + KJJJKKJJJKKJJJ.. + KJKJJKJJJJJJJJ.. + JJKJJJJJJKJJJJ.. + KKKJJJJJJJJJJJ.. + KJJJJJJJJ.JJJ... + JJJJJJJJ........ + JJJJJJ....J..... + JJJ...J......... ................ ................ +} +# tile 155 (explosion wet top left) +{ ................ - .BB..BB..BB..BB. - BBBBBBBBBBBBBBBB - BBBBBBBBBBBBBBBB - .BB..BB..BB..BB. ................ + .............EEE + ......E...EEEEEE + .........EEEEEEE + .........EEEEEEP + ........EEEEPPPE + ...EEE.EEEEPPPEE + .E...EEEEEEPEEEE + .....EEEEEEPEEEE + ....EEEEEEEPEEEE + .......PEEPPEEPP + ....EEEEEEEEEEPP + ...EEEEPPEEEPPPP + ..EEEEPPEEEEPPPP + ..EEEPPEEEEEPPPP +} +# tile 156 (explosion wet top center) +{ ................ ................ + E........EEEEEE. + EEEEEEPEEEEEEEE. + EEEEEEPPPPPEEEEE + PPPEEEPEEEEEEEEE + EEEEEEPEEEEEEEEE + EEEEEEPEEEEEEEEP + EEPPPPPPPPPPPEPP + PPEEEPEPPPPPEEEE + PNPEPEPPPEPPPEEE + PBBEPPPEEPPPPPEE + PNPPPPPEPPPPEEEE + PPPPPEPPEPPPBEEE + PPPPPPPPEPEPEBEE + PBNPPPNBEEEEEEEE +} +# tile 157 (explosion wet top right) +{ ................ ................ ................ + ........E...E... + EEEEE........... + EEEEEE...E..E... + EEEEEEE......... + PPPPPPEEEE...... + EEEEEPPEEEE..... + PPEEEEEEEEEE.... + EEPEEPPPPEEE.... + EEPEEEEEPEEE.... + EEBEEPEEEEEE.E.. + EEEPPPPPEEEE.... + EEPEPPEPEEEE.... + EPEEPPEPEEEEE... } -# tile 164 (zap 3 2) +# tile 158 (explosion wet middle left) { - BBB............. - BBBB............ - BBBB............ - .BBBB........... - ...BBBB......... - ....BBBB........ - ....BBBB........ - .....BBBB....... - .......BBBB..... - ........BBBB.... - ........BBBB.... - .........BBBB... - ...........BBBB. - ............BBBB - ............BBBB - .............BBB + ..EEEPEPEEEPPPPP + ..EEEPEEEEEPEBPP + ...EEPEEPPPPPPPE + ...EEEEEEPPPPBBP + ..EEEPEEPPEPPBEB + .EEEPPPEPPPPBPEB + .EEEPEEEPNPPBPPB + .EEEPEEEPPPEEEEB + .EEEPEEEPPPPBEEE + .EEEPPEEPPPPBBEE + ..EEEPPEEPPPBEEB + ...EEEPPPEBPBBBB + ....EEEPPPBPPBPN + .....EEPPPPPNNEP + ..E.EPPPENBPPPBE + ....EPPPPPPPPPBE +} +# tile 159 (explosion wet middle center) +{ + EBNEEPPBBEBNEEEE + PNBNPPEPEEEBENEP + NEBPBEEPPEEEEENP + BEBBBEEEPPEEBEPP + EEEBBEEEEBEEBPPE + EEBBPBBBEEEEEPPE + EEBEEEEEEEEEEEPP + EBBEEEEEEEEEEEPP + EEEEEEEEEEEEBEEE + BEEEEEEEEEEEEEEE + BEEBEBEEEEEEEEBE + BBEEEEEEEEEEEBBE + EEEEEEEEEEEEBBBB + EBBEBEEEEEEEBBBE + EEEEEEEEEPBBBPBE + BBBBEEEEBBBPNNPP } -# tile 165 (zap 3 3) +# tile 160 (explosion wet middle right) { - .............BBB - ............BBBB - ............BBBB - ...........BBBB. - .........BBBB... - ........BBBB.... - ........BBBB.... - .......BBBB..... - .....BBBB....... - ....BBBB........ - ....BBBB........ - ...BBBB......... - .BBBB........... - BBBB............ - BBBB............ - BBB............. + PPEEEPEPEPEEEE.. + PPEEEEEPEPEEEE.. + PPEEEEEPEPEEEE.. + BPEEEEEPPPEEEE.. + BPEEBEBEEPEEEE.. + BPPPBPPEPPEEE... + PPPEBPPEEEEEE... + PBEEBEEEEEEEE... + EEBPPPBEEEEE.... + PPEEPBBEEPE...E. + EPPPBBPPPP...... + PEEEEBBEEP..E... + PPNEPBBPEEE..... + NPPPPPPEEEEE.... + NENPPPEEEEEEE... + PPPPBBEEEEEEEE.. } -# tile 166 (zap 4 0) +# tile 161 (explosion wet bottom left) { - .......AA....... - ......AAAA...... - ......AAAA...... - .......AA....... - .......AA....... - ......AAAA...... - ......AAAA...... - .......AA....... - .......AA....... - ......AAAA...... - ......AAAA...... - .......AA....... - .......AA....... - ......AAAA...... - ......AAAA...... - .......AA....... + ....EPPPPPPPNPPB + ....EPPPPPPPENPP + .E..EEPPPBPPEPNP + ...EEEPEPPBPPEEB + ...EEEEPPEEBPPEP + ...EEEEPPPPBPPPE + ...EEEEPPEPPNPPE + ...EEEEEPEEEPPPP + ...EEEEEPPEEPPPP + ....EEEEEEEEEPPP + .....EEENEEEEEEE + ...E..EEEEEEEEEE + ........EE.EEEEE + ...E........EEEE + ................ + ................ } -# tile 167 (zap 4 1) +# tile 162 (explosion wet bottom center) { + BBBEEEEEBEEEPEPP + EEBBEEBBBBEPEPPP + BBBBBBBBBBEPPEBB + PBBEEPEEPNBEEPPP + PPEEEEPEPPEENBNE + NBBEBEBPNPNPBEEP + EPPBBEENPPPPPPPB + NEPPPPPPPEPPPPPP + BNBEPEEEEEEEEEEB + NEPNBNEEEPPPPPPE + EEEPEPBBPPPEEEEE + EEEEEEPEPPEEEEEE + EEEEEEEEEEEEEEEE + EEEE..........EE ................ ................ +} +# tile 163 (explosion wet bottom right) +{ + PPPPBPPEEEEEEE.. + PPEPPEPEEPEPEE.. + BBPPEPPEEPEPEE.. + PPPEEEPEEPEPEE.. + PEEEEEPEEEPPEE.. + PPBEEPPEEEPEEE.. + PEEEPPEEEPPEEE.. + PEPEEPEEEEEEEE.. + EEPEEEEEEPEEEE.. + PPPEEEEEEEEEEE.. + PEEEEEEEE.EEE... + EEEEEEEE........ + EEEEEE....E..... + EEE...E......... ................ ................ +} +# tile 164 (explosion magical top left) +{ ................ ................ - .AA..AA..AA..AA. - AAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAA - .AA..AA..AA..AA. - ................ + .............EEE + ......E...EEEEEE + .........EEEEEEE + .........EEEEEEC + ........EEEEIIIE + ...EEE.EEEEIIIEE + .E...EEEEEEIEEEE + .....EEEEEEIEEEE + ....EEEEEEEIEEEE + .......IEEIIEEII + ....EEEEEEEEEEII + ...EEEEIIEEEIIII + ..EEEEIIEEEEIIII + ..EEEIIEEEEEIIII +} +# tile 165 (explosion magical top center) +{ ................ ................ + E........EEEEEE. + EEEEEEIEEEEEEEE. + EEEEEEIIIIIEEEEE + IIIEEEIEEEEEEEEE + EEEEEEIEEEEEEEEE + EEEEEEIEEEEEEEEI + EEIIIIIIIIIIIEII + IIEEEIEIIIIIEEEE + IHIEIEIIIEIIIEEE + ILLEIIIEEIIIIIEE + IHIIIIIEIIIIEEEE + IIIIIEIIEIIILEEE + IIIIIIIIEIEIELEE + ILHIIIHLHHEEEEEE +} +# tile 166 (explosion magical top right) +{ ................ ................ ................ + ........E...E... + EEEEE........... + EEEEEE...E..E... + EEEEEEE......... + IIIIIIEEEE...... + EEEEEIIEEEE..... + IIEEEEEEEEEE.... + EEIEEIIIIEEE.... + EEIEEEEEIEEE.... + EELEEIEEEEEE.E.. + EEEIIIIIEEEE.... + EEIEIIEIEEEE.... + EIEEIIEIEEEEE... } -# tile 168 (zap 4 2) +# tile 167 (explosion magical middle left) { - AAA............. - AAAA............ - AAAA............ - .AAAA........... - ...AAAA......... - ....AAAA........ - ....AAAA........ - .....AAAA....... - .......AAAA..... - ........AAAA.... - ........AAAA.... - .........AAAA... - ...........AAAA. - ............AAAA - ............AAAA - .............AAA + ..EEEIEIEEEIIIII + ..EEEIEEEEEIEIII + ...EEIEEIIIIIIIE + ...EEEEEEIIIIIII + ..EEEIEEIIEIIIEI + .EEEIIIEIIIIIIEI + .EEEIEEEINIIIIII + .EEEIEEEIIIEEEEI + .EEEIEEEIIIIIENN + .EEEIIEEIIIIIINN + ..EEEIIEEIIIINNI + ...EEEIIIEIIIIII + ....EEEIIIIIIIIN + .....EEIIIIINNEI + ..E.EIIIENIIIIIN + ....EIIIIIIIIIIN } -# tile 169 (zap 4 3) +# tile 168 (explosion magical middle center) { - .............AAA - ............AAAA - ............AAAA - ...........AAAA. - .........AAAA... - ........AAAA.... - ........AAAA.... - .......AAAA..... - .....AAAA....... - ....AAAA........ - ....AAAA........ - ...AAAA......... - .AAAA........... - AAAA............ - AAAA............ - AAA............. + EINEEIIIIEINEEEE + ININIIEIEENIENEI + NEIIINEIINNNEENI + IEIIINNNIINNIEII + NNNIINNNNINNIIIE + NNIIIIIINNNNEIIE + NNINNNNNNNNNNEII + NIINNNNNNNNNNNII + NNNNNNNNNNNNINNN + INNNNNNNNNNNNNNN + INNININNNNNNNNIE + IINNNNNNNNNNNIIE + NNNNNNNNNNNNIIII + NIININNNNNNNIIIE + NNNNNNNNNIIIIIIE + IIIINNNNIIIINNII } -# tile 170 (zap 5 0) +# tile 169 (explosion magical middle right) { - .......NN....... - ......NNNN...... - ......NNNN...... - .......NN....... - .......NN....... - ......NNNN...... - ......NNNN...... - .......NN....... - .......NN....... - ......NNNN...... - ......NNNN...... - .......NN....... - .......NN....... - ......NNNN...... - ......NNNN...... - .......NN....... + IIEEEIEIEIEEEE.. + IIEEEEEIEIEEEE.. + IIEEEEEIEIEEEE.. + IIEEEEEIIIEEEE.. + IIEEIEIEEIEEEE.. + IIIIIIIEIIEEE... + IIIEIIIEEEEEE... + IIEEIEEEEEEEE... + EEIIIIIEEEEE.... + IIEEIIIEEIE...E. + EIIIIIIIII...... + IEEEEIIEEI..E... + IINEIIIIEEE..... + NIIIIIIEEEEE.... + NENIIIEEEEEEE... + IIIIIIEEEEEEEE.. +} +# tile 170 (explosion magical bottom left) +{ + ....EIIIIIIIHIII + ....EIIIIIIIEHII + .E..EEIIIIIIEIHI + ...EEEIEIIIIIEEI + ...EEEEIIEEIIIEI + ...EEEEIIIIIIIIE + ...EEEEIIEIIHIIE + ...EEEEEIEEEIIII + ...EEEEEIIEEIIII + ....EEEEEEEEEIII + .....EEEHEEEEEEE + ...E..EEEEEEEEEE + ........EE.EEEEE + ...E........EEEE + ................ + ................ } -# tile 171 (zap 5 1) +# tile 171 (explosion magical bottom center) { + IIINNNNNINNNINII + NNIINNIIIINIEIII + IIIIIIIIIIEIIEII + IIINEIEEINIEEIII + IINNNNIEIIEENINE + NIIEIEIININIIEEI + EIIIIEENIIIIIIII + NEIIIIIIIEIIIIII + INIEIEEEEEEEEEEI + NEININEEEIIIIIIE + EEEIEIIIIIIEEEEE + EEEEEEIEIIEEEEEE + EEEEEEEEEEEEEEEE + EEEE..........EE ................ ................ +} +# tile 172 (explosion magical bottom right) +{ + IIIIIIIEEEEEEE.. + IIEIIEIEEIEIEE.. + IIIIEIIEEIEIEE.. + IIIEEEIEEIEIEE.. + IEEEEEIEEEIIEE.. + IIIEEIIEEEIEEE.. + IEEEIIEEEIIEEE.. + IEIEEIEEEEEEEE.. + EEIEEEEEEIEEEE.. + IIIEEEEEEEEEEE.. + IEEEEEEEE.EEE... + EEEEEEEE........ + EEEEEE....E..... + EEE...E......... ................ ................ +} +# tile 173 (explosion fiery top left) +{ ................ ................ - .NN..NN..NN..NN. - NNNNNNNNNNNNNNNN - NNNNNNNNNNNNNNNN - .NN..NN..NN..NN. - ................ + .............DDD + ......D...DDDDDD + .........DDDDDDD + .........DDDDDDC + ........DDDDCCCD + ...DDD.DDDDCCCDD + .D...DDDDDDCDDDD + .....DDDDDDCDDDD + ....DDDDDDDCDDDD + .......CDDCCDDCC + ....DDDDDDDDDDCC + ...DDDDCCDDDCCCC + ..DDDDCCDDDDCCCC + ..DDDCCDDDDDCCCC +} +# tile 174 (explosion fiery top center) +{ ................ ................ + D........DDDDDD. + DDDDDDCDDDDDDDD. + DDDDDDCCCCCDDDDD + CCCDDDCDDDDDDDDD + DDDDDDCDDDDDDDDD + DDDDDDCDDDDDDDDC + DDCCCCCCCCCCCDCC + CCDDDCDCCCCCDDDD + CHCDCDCCCDCCCDDD + CLLDCCCDDCCCCCDD + CHCCCCCDCCCCDDDD + CCCCCDCCDCCCLDDD + CCCCCCCCDCDCDLDD + CLHCCCHLHHDDDDDD +} +# tile 175 (explosion fiery top right) +{ ................ ................ ................ + ........D...D... + DDDDD........... + DDDDDD...D..D... + DDDDDDD......... + CCCCCCDDDD...... + DDDDDCCDDDD..... + CCDDDDDDDDDD.... + DDCDDCCCCDDD.... + DDCDDDDDCDDD.... + DDLDDCDDDDDD.D.. + DDDCCCCCDDDD.... + DDCDCCDCDDDD.... + DCDDCCDCDDDDD... } -# tile 172 (zap 5 2) +# tile 176 (explosion fiery middle left) { - NNN............. - NNNN............ - NNNN............ - .NNNN........... - ...NNNN......... - ....NNNN........ - ....NNNN........ - .....NNNN....... - .......NNNN..... - ........NNNN.... - ........NNNN.... - .........NNNN... - ...........NNNN. - ............NNNN - ............NNNN - .............NNN + ..DDDCDCDDDCCCCC + ..DDDCDDDDDCDLCC + ...DDCDDCCCCCCCD + ...DDDDDDCCCCLLC + ..DDDCDDCCDCCLDL + .DDDCCCDCCCCLCDL + .DDDCDDDCHCCLCCL + .DDDCDDDCCCDDDDL + .DDDCDDDCCCCLDHH + .DDDCCDDCCCCLLHH + ..DDDCCDDCCCLHHL + ...DDDCCCDLCLLLL + ....DDDCCCLCCLCH + .....DDCCCCCHHDC + ..D.DCCCDHLCCCLH + ....DCCCCCCCCCLH } -# tile 173 (zap 5 3) +# tile 177 (explosion fiery middle center) { - .............NNN - ............NNNN - ............NNNN - ...........NNNN. - .........NNNN... - ........NNNN.... - ........NNNN.... - .......NNNN..... - .....NNNN....... - ....NNNN........ - ....NNNN........ - ...NNNN......... - .NNNN........... - NNNN............ - NNNN............ - NNN............. + DLHDDCCLLDLHDDDD + CHLHCCDCDDHLDHDC + HDLCLHDCCHHHDDHC + LDLLLHHHCCHHLDCC + HHHLLHHHHLHHLCCD + HHLLCLLLHHHHDCCD + HHLHHHHHHHHHHDCC + HLLHHHHHHHHHHHCC + HHHHHHNNNNHHLHNH + LHHHHHHHNHHHHHNH + LHHLHLNNNNHHHHLD + LLNHNHNNNNHHHLLD + HHHHNHNNNHHHLLLL + HLLNLHNNNHHHLLLD + HHHHNHNHNCLLLCLD + LLLLNHHHLLLCHHCC } -# tile 174 (zap 6 0) +# tile 178 (explosion fiery middle right) { - .......FF....... - ......FFFF...... - ......FFFF...... - .......FF....... - .......FF....... - ......FFFF...... - ......FFFF...... - .......FF....... - .......FF....... - ......FFFF...... - ......FFFF...... - .......FF....... - .......FF....... - ......FFFF...... - ......FFFF...... - .......FF....... + CCDDDCDCDCDDDD.. + CCDDDDDCDCDDDD.. + CCDDDDDCDCDDDD.. + LCDDDDDCCCDDDD.. + LCDDLDLDDCDDDD.. + LCCCLCCDCCDDD... + CCCDLCCDDDDDD... + CLDDLDDDDDDDD... + DDLCCCLDDDDD.... + CCDDCLLDDCD...D. + DCCCLLCCCC...... + CDDDDLLDDC..D... + CCHDCLLCDDD..... + HCCCCCCDDDDD.... + HDHCCCDDDDDDD... + CCCCLLDDDDDDDD.. } -# tile 175 (zap 6 1) +# tile 179 (explosion fiery bottom left) { + ....DCCCCCCCHCCL + ....DCCCCCCCDHCC + .D..DDCCCLCCDCHC + ...DDDCDCCLCCDDL + ...DDDDCCDDLCCDC + ...DDDDCCCCLCCCD + ...DDDDCCDCCHCCD + ...DDDDDCDDDCCCC + ...DDDDDCCDDCCCC + ....DDDDDDDDDCCC + .....DDDHDDDDDDD + ...D..DDDDDDDDDD + ........DD.DDDDD + ...D........DDDD ................ ................ +} +# tile 180 (explosion fiery bottom center) +{ + LLLHHHHHLHHHCHCC + HHLLHHLLLLHCDCCC + LLLLLLLLLLDCCDLL + CLLHDCDDCHLDDCCC + CCHHHHCDCCDDHLHD + HLLDLDLCHCHCLDDC + DCCLLDDHCCCCCCCL + HDCCCCCCCDCCCCCC + LHLDCDDDDDDDDDDL + HDCHLHDDDCCCCCCD + DDDCDCLLCCCDDDDD + DDDDDDCDCCDDDDDD + DDDDDDDDDDDDDDDD + DDDD..........DD + ................ ................ +} +# tile 181 (explosion fiery bottom right) +{ + CCCCLCCDDDDDDD.. + CCDCCDCDDCDCDD.. + LLCCDCCDDCDCDD.. + CCCDDDCDDCDCDD.. + CDDDDDCDDDCCDD.. + CCLDDCCDDDCDDD.. + CDDDCCDDDCCDDD.. + CDCDDCDDDDDDDD.. + DDCDDDDDDCDDDD.. + CCCDDDDDDDDDDD.. + CDDDDDDDD.DDD... + DDDDDDDD........ + DDDDDD....D..... + DDD...D......... ................ ................ +} +# tile 182 (explosion frosty top left) +{ ................ - .FF..FF..FF..FF. - FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFF - .FF..FF..FF..FF. ................ + .............EEE + .....NE...EEEEEE + ..N...N..ENBEEEE + .N.N.N...EEEEEEP + ....N...EEEEPPPE + ...NEN.NEEEPPPEE + .EN..ENEEEEPNBEE + ...N.EEEEEEPEEEE + ....EENBEEEPEEEE + .......PEEPPEEPP + ....EEEEEEEEEEPP + ...EEEEPPEEEPPPP + ..EEEEPPNBEEPPPP + ..EEEPPEEEEEPPPP +} +# tile 183 (explosion frosty top center) +{ ................ ................ + E........EEEEEE. + ENBEENPEEEENBEE. + EEEEEENPNPNEEEEE + PPBEEEPENEEEEEEE + EEEEEENNNNNEEEEE + EEEEEEPENEEENBEP + EEPPPPNPNPNPPPPP + PPEEENEPPPPNEEEE + PNPEPEPPPEPPPEEE + PBBEPPPEEPPNBPEE + PNPPPPPEPPPPEEEE + PPPPPEPPEPPPBEEE + PPPPPPPPEPEPEBEE + PBNPPPNBNNEEEEEE +} +# tile 184 (explosion frosty top right) +{ ................ ................ ................ + ........E...E... + EEEEE........... + EEEEEE...E..N... + EEEEEEEN..NN.... + PPPPPPENEN...... + EEEEEPPENEN.N... + PPEEEEEEEEEN.N.. + EEPEEPPPPNNE.N.. + EEPEEEEENEEE.... + EEBEEPEEEEEE.E.. + EEEPPPPPEEEE.... + EEPEPPEPEEEE.... + EPEEPPEPEEEEE... } -# tile 176 (zap 6 2) +# tile 185 (explosion frosty middle left) { - FFF............. - FFFF............ - FFFF............ - .FFFF........... - ...FFFF......... - ....FFFF........ - ....FFFF........ - .....FFFF....... - .......FFFF..... - ........FFFF.... - ........FFFF.... - .........FFFF... - ...........FFFF. - ............FFFF - ............FFFF - .............FFF + ..EEEPEPEEEPPPPP + ..EEEPEEEEEPEBPP + ...EEPEEPPPPPPPE + ...ENENEEPPPPBBP + ..EEENEEPPEPPBEB + .EEENENEPPPPBPEB + .EEEPEEEPNPPBPPB + .EEEPEEEPPPEEEEB + .EEEPEEEPPPPBENN + .EEEPPEEPPPPBBNN + ..EEEPNEEPPPBNNB + ...EENNNPEBPBBBB + ....EENPPPBPPBPN + .....EEPPPPPNNEP + ..E.EPPPENBPPPBN + ....EPPPPPPPPPBN } -# tile 177 (zap 6 3) +# tile 186 (explosion frosty middle center) { - .............FFF - ............FFFF - ............FFFF - ...........FFFF. - .........FFFF... - ........FFFF.... - ........FFFF.... - .......FFFF..... - .....FFFF....... - ....FFFF........ - ....FFFF........ - ...FFFF......... - .FFFF........... - FFFF............ - FFFF............ - FFF............. + EBNEEPPBBEBNEEEE + PNBNPPEPEENBENEP + NEBPBNEPPNNNEENP + BEBBBNNNPPNNBEPP + NNNBBNNNNBNNBPPE + NNBBPBBBNNNNEPPE + NNBNNNNNNNNNNEPP + NBBNNNNNNNNNNNPP + NNNNNNNNNNNNBNNN + BNNNNNNNNNNNNNNN + BNNBNBNNNNNNNNBE + BBNNNNNNNNNNNBBE + NNNNNNNNNNNNBBBB + NBBNBNNNNNNNBBBE + NNNNNNNNNPBBBPBE + BBBBNNNNBBBPNNPP } -# tile 178 (zap 7 0) +# tile 187 (explosion frosty middle right) { - .......GG....... - ......GGGG...... - ......GGGG...... - .......GG....... - .......GG....... - ......GGGG...... - ......GGGG...... - .......GG....... - .......GG....... - ......GGGG...... - ......GGGG...... - .......GG....... - .......GG....... - ......GGGG...... - ......GGGG...... - .......GG....... + PPEEEPEPEPEEEE.. + PPEEEEEPEPEEEE.. + PPEEEEEPEPEEEE.. + BPEEEEEPPPEEEE.. + BPEEBEBEEPEEEE.. + BPPPBPPEPPEEE... + PPPEBPPENEEEN... + PBEEBEEEENENE... + EEBPPPBNNNNNNN.. + PPEEPBBEENEN..E. + EPPPBBPPNP..N... + PEEEEBBEEP..E... + PPNEPBBPEEE..... + NPPPPPPEEEEE.... + NENPPPEEEEEEE... + PPPPBBEEEEEEEE.. } -# tile 179 (zap 7 1) +# tile 188 (explosion frosty bottom left) { - ................ - ................ - ................ - ................ - ................ - ................ - .GG..GG..GG..GG. - GGGGGGGGGGGGGGGG - GGGGGGGGGGGGGGGG - .GG..GG..GG..GG. - ................ - ................ - ................ - ................ + ....EPPPPPPPNPPB + ....EPPPPPPPENPP + .E..EEPPPBPPEPNP + ...EEEPEPPBPPEEB + ...EENEPPEEBPPEP + ...NEEENPPPBPPPE + ..NENPNPNEPPNPPE + ...NNENNPEEEPPPP + .N.PEEEPPNEEPPPP + ...NNENNEEEEEPPP + ..N.NPNENEEEEEEE + ...N..ENEEEEEEEE + .....N..EE.EEEEE + ...E........EEEE ................ ................ } -# tile 180 (zap 7 2) +# tile 189 (explosion frosty bottom center) { - GGG............. - GGGG............ - GGGG............ - .GGGG........... - ...GGGG......... - ....GGGG........ - ....GGGG........ - .....GGGG....... - .......GGGG..... - ........GGGG.... - ........GGGG.... - .........GGGG... - ...........GGGG. - ............GGGG - ............GGGG - .............GGG + BBBNNNNNBNNNPNPP + NNBBNNBBBBNPEPPP + BBBBBBBBBBEPPEBB + PBBNEPEEPNBEEPPP + PPNNNNPEPPEENBNE + NBBEBEBPNPNPBEEP + EPPBBEENPPPPPPPB + NEPPPPPPPEPPPPPP + BNBEPEEEEEEEEEEB + NEPNBNEEEPNENPPE + EEEPEPBBPPPNEEEE + EEEEEEPEPNNNNNEE + EEEEEEEEEEENEEEE + EEEE......N.N.EE + ................ + ................ } -# tile 181 (zap 7 3) +# tile 190 (explosion frosty bottom right) { - .............GGG - ............GGGG - ............GGGG - ...........GGGG. - .........GGGG... - ........GGGG.... - ........GGGG.... - .......GGGG..... - .....GGGG....... - ....GGGG........ - ....GGGG........ - ...GGGG......... - .GGGG........... - GGGG............ - GGGG............ - GGG............. + PPPPBPPEEEEEEE.. + PPEPPEPEEPEPEE.. + BBPPEPPEEPEPNEN. + PPPEEEPEEPEPEN.. + PEEEEEPEEEPPNEN. + PPBEEPNENEPEEE.. + PEEEPPENEPPEEE.. + PEPEENNNNNEEEE.. + EEPEEEENEPEEEE.. + PPPEEENENEEEEE.. + PEEEEEEEE.EEE... + EEEEEEEE........ + EEEEEE....EN.... + EEE...E...N.N... + ...........N.... + ................ } -# tile 182 (warning 0) +# tile 191 (warning 0) { ................ ................ @@ -3504,7 +3679,7 @@ Z = (195, 195, 195) .......AA....... ................ } -# tile 183 (warning 1) +# tile 192 (warning 1) { ................ ................ @@ -3523,7 +3698,7 @@ Z = (195, 195, 195) .......AA....... ................ } -# tile 184 (warning 2) +# tile 193 (warning 2) { ................ ................ @@ -3542,7 +3717,7 @@ Z = (195, 195, 195) .......AA....... ................ } -# tile 185 (warning 3) +# tile 194 (warning 3) { ................ ................ @@ -3561,7 +3736,7 @@ Z = (195, 195, 195) .......AA....... ................ } -# tile 186 (warning 4) +# tile 195 (warning 4) { ................ ................ @@ -3580,7 +3755,7 @@ Z = (195, 195, 195) .......AA....... ................ } -# tile 187 (warning 5) +# tile 196 (warning 5) { ................ ................ @@ -3599,7 +3774,45 @@ Z = (195, 195, 195) .......AA....... ................ } -# tile 188 (sub mine walls 0) +# tile 197 (unexplored) +{ + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA +} +# tile 198 (nothing) +{ + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAA +} +# tile 199 (mines walls vertical) { AJJKKKACJAAJJJAA AJKKKACLJJAJJJJA @@ -3618,7 +3831,7 @@ Z = (195, 195, 195) AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } -# tile 189 (sub mine walls 1) +# tile 200 (mines walls horizontal) { AJAAAAAAJJAAAJAA JJJAAAJJJJJAAAAJ @@ -3637,7 +3850,7 @@ Z = (195, 195, 195) JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } -# tile 190 (sub mine walls 2) +# tile 201 (mines walls tlcorn) { AAAAAAKCCKKJAAAA AAAAKKCLCJKJJAAA @@ -3656,7 +3869,7 @@ Z = (195, 195, 195) AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } -# tile 191 (sub mine walls 3) +# tile 202 (mines walls trcorn) { AAAAAAKCCKKJAAAA AAAAKKCLCJKJJAAA @@ -3675,7 +3888,7 @@ Z = (195, 195, 195) AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } -# tile 192 (sub mine walls 4) +# tile 203 (mines walls blcorn) { AKKKAAKKKKAAJJJA AKKAAKCCCJJJAAJA @@ -3694,7 +3907,7 @@ Z = (195, 195, 195) AJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } -# tile 193 (sub mine walls 5) +# tile 204 (mines walls brcorn) { AKKAAAKKAAAAJJJA AKAAKKLCKAAAAAJA @@ -3713,7 +3926,7 @@ Z = (195, 195, 195) JJJJJJJJJJJJJJJA AAAAAAAAAAAAAAAA } -# tile 194 (sub mine walls 6) +# tile 205 (mines walls cross wall) { AAAAAAKCCKKJAAAA AAAAKCCLCJKJJAAA @@ -3732,7 +3945,7 @@ Z = (195, 195, 195) AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } -# tile 195 (sub mine walls 7) +# tile 206 (mines walls tuwall) { AKKAAAKKKKAAJJJA AKAAKKLCCJJJAAJA @@ -3751,7 +3964,7 @@ Z = (195, 195, 195) JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } -# tile 196 (sub mine walls 8) +# tile 207 (mines walls tdwall) { AAAAAAKCCKKJAAAA AAAAKCCLCJKJJAAA @@ -3770,7 +3983,7 @@ Z = (195, 195, 195) AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } -# tile 197 (sub mine walls 9) +# tile 208 (mines walls tlwall) { AKKAACKCCKKJAJJA AKACKKKLLJKJJAJA @@ -3789,7 +4002,7 @@ Z = (195, 195, 195) AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } -# tile 198 (sub mine walls 10) +# tile 209 (mines walls trwall) { AKKAACKCCKKJAJJA AKACKKCLCJKJJAJA @@ -3808,7 +4021,7 @@ Z = (195, 195, 195) AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } -# tile 199 (sub gehennom walls 0) +# tile 210 (gehennom walls vertical) { ALLDAJ11111JLLDA ADDDAJ1J11JJDDDA @@ -3827,7 +4040,7 @@ Z = (195, 195, 195) AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } -# tile 200 (sub gehennom walls 1) +# tile 211 (gehennom walls horizontal) { AAALDDAAAAALDDAA DDDLDDAJDDDLDDAJ @@ -3846,7 +4059,7 @@ Z = (195, 195, 195) JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } -# tile 201 (sub gehennom walls 2) +# tile 212 (gehennom walls tlcorn) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ @@ -3865,7 +4078,7 @@ Z = (195, 195, 195) AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } -# tile 202 (sub gehennom walls 3) +# tile 213 (gehennom walls trcorn) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ @@ -3884,7 +4097,7 @@ Z = (195, 195, 195) AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } -# tile 203 (sub gehennom walls 4) +# tile 214 (gehennom walls blcorn) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ @@ -3903,7 +4116,7 @@ Z = (195, 195, 195) JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } -# tile 204 (sub gehennom walls 5) +# tile 215 (gehennom walls brcorn) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ @@ -3922,7 +4135,7 @@ Z = (195, 195, 195) JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } -# tile 205 (sub gehennom walls 6) +# tile 216 (gehennom walls cross wall) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ @@ -3941,7 +4154,7 @@ Z = (195, 195, 195) AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } -# tile 206 (sub gehennom walls 7) +# tile 217 (gehennom walls tuwall) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ @@ -3960,7 +4173,7 @@ Z = (195, 195, 195) JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } -# tile 207 (sub gehennom walls 8) +# tile 218 (gehennom walls tdwall) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ @@ -3979,7 +4192,7 @@ Z = (195, 195, 195) AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } -# tile 208 (sub gehennom walls 9) +# tile 219 (gehennom walls tlwall) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ @@ -3998,7 +4211,7 @@ Z = (195, 195, 195) AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } -# tile 209 (sub gehennom walls 10) +# tile 220 (gehennom walls trwall) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ @@ -4017,7 +4230,7 @@ Z = (195, 195, 195) AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } -# tile 210 (sub knox walls 0) +# tile 221 (knox walls vertical) { AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA @@ -4036,7 +4249,7 @@ Z = (195, 195, 195) AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } -# tile 211 (sub knox walls 1) +# tile 222 (knox walls horizontal) { AJAAAJAAAJAAAJAA JJJAAAJAJJJAAAJA @@ -4055,7 +4268,7 @@ Z = (195, 195, 195) KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } -# tile 212 (sub knox walls 2) +# tile 223 (knox walls tlcorn) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA @@ -4074,7 +4287,7 @@ Z = (195, 195, 195) AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } -# tile 213 (sub knox walls 3) +# tile 224 (knox walls trcorn) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA @@ -4093,7 +4306,7 @@ Z = (195, 195, 195) AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } -# tile 214 (sub knox walls 4) +# tile 225 (knox walls blcorn) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA @@ -4112,7 +4325,7 @@ Z = (195, 195, 195) KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } -# tile 215 (sub knox walls 5) +# tile 226 (knox walls brcorn) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA @@ -4131,7 +4344,7 @@ Z = (195, 195, 195) KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } -# tile 216 (sub knox walls 6) +# tile 227 (knox walls cross wall) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA @@ -4150,7 +4363,7 @@ Z = (195, 195, 195) AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } -# tile 217 (sub knox walls 7) +# tile 228 (knox walls tuwall) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA @@ -4169,7 +4382,7 @@ Z = (195, 195, 195) KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } -# tile 218 (sub knox walls 8) +# tile 229 (knox walls tdwall) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA @@ -4188,7 +4401,7 @@ Z = (195, 195, 195) AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } -# tile 219 (sub knox walls 9) +# tile 230 (knox walls tlwall) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA @@ -4207,7 +4420,7 @@ Z = (195, 195, 195) AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } -# tile 220 (sub knox walls 10) +# tile 231 (knox walls trwall) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA @@ -4226,7 +4439,7 @@ Z = (195, 195, 195) AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } -# tile 221 (sub sokoban walls 0) +# tile 232 (sokoban walls vertical) { ANNBA1EEEEE1NNBA ABBBA1E1EE11BBBA @@ -4245,7 +4458,7 @@ Z = (195, 195, 195) A111A11EEEE1111A ABEEA11EEEE1BE1A } -# tile 222 (sub sokoban walls 1) +# tile 233 (sokoban walls horizontal) { AAANBBAAAAANBBAA BBBNBBA1BBBNBBA1 @@ -4264,7 +4477,7 @@ Z = (195, 195, 195) 1111111111111111 AAAAAAAAAAAAAAAA } -# tile 223 (sub sokoban walls 2) +# tile 234 (sokoban walls tlcorn) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 @@ -4283,7 +4496,7 @@ Z = (195, 195, 195) A111A11EEEE1111A ABEEA11EEEE1BE1A } -# tile 224 (sub sokoban walls 3) +# tile 235 (sokoban walls trcorn) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 @@ -4302,7 +4515,7 @@ Z = (195, 195, 195) A111A11EEEE1111A ABEEA11EEEE1BE1A } -# tile 225 (sub sokoban walls 4) +# tile 236 (sokoban walls blcorn) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 @@ -4321,7 +4534,7 @@ Z = (195, 195, 195) 1111111111111111 AAAAAAAAAAAAAAAA } -# tile 226 (sub sokoban walls 5) +# tile 237 (sokoban walls brcorn) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 @@ -4340,7 +4553,7 @@ Z = (195, 195, 195) 1111111111111111 AAAAAAAAAAAAAAAA } -# tile 227 (sub sokoban walls 6) +# tile 238 (sokoban walls cross wall) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 @@ -4359,7 +4572,7 @@ Z = (195, 195, 195) A111A11EEEE1111A ABEEA11EEEE1BE1A } -# tile 228 (sub sokoban walls 7) +# tile 239 (sokoban walls tuwall) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 @@ -4378,7 +4591,7 @@ Z = (195, 195, 195) 1111111111111111 AAAAAAAAAAAAAAAA } -# tile 229 (sub sokoban walls 8) +# tile 240 (sokoban walls tdwall) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 @@ -4397,7 +4610,7 @@ Z = (195, 195, 195) A111A11EEEE1111A ABEEA11EEEE1BE1A } -# tile 230 (sub sokoban walls 9) +# tile 241 (sokoban walls tlwall) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 @@ -4416,7 +4629,7 @@ Z = (195, 195, 195) A111A11EEEE1111A ABEEA11EEEE1BE1A } -# tile 231 (sub sokoban walls 10) +# tile 242 (sokoban walls trwall) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 diff --git a/win/share/ppmwrite.c b/win/share/ppmwrite.c index 9fd052c6e..b9f5848e3 100644 --- a/win/share/ppmwrite.c +++ b/win/share/ppmwrite.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 ppmwrite.c $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */ +/* NetHack 5.0 ppmwrite.c $NHDT-Date: 1596498336 2020/08/03 23:45:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.7 $ */ /* this produces a raw ppm file, with a 15-character header of * "P6 3-digit-width 3-digit-height 255\n" */ @@ -7,7 +7,7 @@ #include "tile.h" #ifndef MONITOR_HEAP -extern long *FDECL(alloc, (unsigned int)); +extern long *alloc(unsigned int); #endif FILE *ppm_file; @@ -20,18 +20,18 @@ struct ppmscreen { static int tiles_across, tiles_down, curr_tiles_across; static pixel **image; -static void NDECL(write_header); -static void NDECL(WriteTileStrip); +static void write_header(void); +static void WriteTileStrip(void); static void -write_header() +write_header(void) { (void) fprintf(ppm_file, "P6 %03d %03d 255\n", PpmScreen.Width, PpmScreen.Height); } static void -WriteTileStrip() +WriteTileStrip(void) { int i, j; @@ -45,9 +45,7 @@ WriteTileStrip() } boolean -fopen_ppm_file(filename, type) -const char *filename; -const char *type; +fopen_ppm_file(const char *filename, const char *type) { int i; @@ -84,8 +82,7 @@ const char *type; } boolean -write_ppm_tile(pixels) -pixel (*pixels)[TILE_X]; +write_ppm_tile(pixel (*pixels)[TILE_X]) { int i, j; @@ -104,7 +101,7 @@ pixel (*pixels)[TILE_X]; } int -fclose_ppm_file() +fclose_ppm_file(void) { int i, j; @@ -139,9 +136,7 @@ fclose_ppm_file() } int -main(argc, argv) -int argc; -char *argv[]; +main(int argc, char *argv[]) { pixel pixels[TILE_Y][TILE_X]; diff --git a/win/share/safeproc.c b/win/share/safeproc.c deleted file mode 100644 index 927744c4e..000000000 --- a/win/share/safeproc.c +++ /dev/null @@ -1,575 +0,0 @@ -/* NetHack 3.6 safeproc.c */ -/* Copyright (c) Michael Allison, 2018 */ -/* NetHack may be freely redistributed. See license for details. */ - -#include "hack.h" -#include - -/* - * *********************************************************** - * This is a complete WindowPort implementation that can be - * assigned to the windowproc function pointers very early - * in the startup initialization, perhaps immediately even. - * It requires only the following call: - * windowprocs = *get_safe_procs(0); - * - * The game startup can trigger functions in other modules - * that make assumptions on a WindowPort being available - * and bad things can happen if any function pointers are - * null at that time. - * - * Some ports prior to 3.6.2 made attempts to early init - * various pieces of one of their WindowPorts, but that - * caused conflicts if that particular WindowPort wasn't - * the one that the user ended up selecting in their - * config file later. The WindowPort interfaced was designed - * to allow multiple WindowPorts to be linked into the same - * game binary. - * - * The base functions established by a call to get_safe_procs() - * accomplish the goal of preventing crashes, but not much - * else. - * - * There are also a few additional functions provided in here - * that can be selected optionally to provide some startup - * functionality for getting messages out to the user about - * issues that are being experienced during startup in - * general or during options parsing. The ones in here are - * deliberately free from any platforms or OS specific code. - * Please leave them using stdio C routines as much as - * possible. That isn't to say you can't do fancier functions - * prior to initialization of the primary WindowPort, but you - * can provide those platform-specific functions elsewhere, - * and assign them the same way that these more generic versions - * are assigned. - * - * The additional platform-independent, but more functional - * routines provided in here should be assigned after the - * windowprocs = *get_safe_procs(n) - * call. - * - * Usage: - * - * windowprocs = *get_safe_procs(0); - * initializes a set of winprocs function pointers that ensure - * none of the function pointers are left null, but that's all - * it does. - * - * windowprocs = *get_safe_procs(1); - * initializes a set of winprocs functions pointers that ensure - * none of the function pointers are left null, but also - * provides some basic output and input functionality using - * nothing other than C stdio routines (no platform-specific - * or OS-specific code). - * - * *********************************************************** - */ - -struct window_procs safe_procs = { - "safe-startup", 0L, 0L, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ - safe_init_nhwindows, safe_player_selection, safe_askname, safe_get_nh_event, - safe_exit_nhwindows, safe_suspend_nhwindows, safe_resume_nhwindows, - safe_create_nhwindow, safe_clear_nhwindow, safe_display_nhwindow, - safe_destroy_nhwindow, safe_curs, safe_putstr, genl_putmixed, - safe_display_file, safe_start_menu, safe_add_menu, safe_end_menu, - safe_select_menu, safe_message_menu, safe_update_inventory, safe_mark_synch, - safe_wait_synch, -#ifdef CLIPPING - safe_cliparound, -#endif -#ifdef POSITIONBAR - safe_update_positionbar, -#endif - safe_print_glyph, safe_raw_print, safe_raw_print_bold, safe_nhgetch, - safe_nh_poskey, safe_nhbell, safe_doprev_message, safe_yn_function, - safe_getlin, safe_get_ext_cmd, safe_number_pad, safe_delay_output, -#ifdef CHANGE_COLOR /* the Mac uses a palette device */ - safe_change_color, -#ifdef MAC - safe_change_background, set_safe_font_name, -#endif - safe_get_color_string, -#endif - safe_start_screen, safe_end_screen, genl_outrip, - safe_preference_update, - safe_getmsghistory, safe_putmsghistory, - safe_status_init, - safe_status_finish, safe_status_enablefield, -#ifdef STATUS_HILITES - safe_status_update, -#else - safe_status_update, -#endif - safe_can_suspend, -}; - -struct window_procs * -get_safe_procs(optn) -int optn; -{ - if (optn) { - /* include the slightly more functional stdc versions */ - safe_procs.win_raw_print = stdio_raw_print; - safe_procs.win_raw_print_bold = stdio_raw_print_bold; - safe_procs.win_nhgetch = stdio_nhgetch; - safe_procs.win_wait_synch = stdio_wait_synch; - if (optn == 2) - safe_procs.win_raw_print = stdio_nonl_raw_print; - } - return &safe_procs; -} - -/*ARGSUSED*/ -void -safe_init_nhwindows(argcp, argv) -int *argcp UNUSED; -char **argv UNUSED; -{ - return; -} - -void -safe_player_selection() -{ - return; -} - -void -safe_askname() -{ - return; -} - -void -safe_get_nh_event() -{ - return; -} - -void -safe_suspend_nhwindows(str) -const char *str; -{ - return; -} - -void -safe_resume_nhwindows() -{ - return; -} - -void -safe_exit_nhwindows(str) -const char *str; -{ - return; -} - -winid -safe_create_nhwindow(type) -int type; -{ - return WIN_ERR; -} - -void -safe_clear_nhwindow(window) -winid window; -{ - return; -} - -/*ARGSUSED*/ -void -safe_display_nhwindow(window, blocking) -winid window; -boolean blocking; -{ - return; -} - -void -safe_dismiss_nhwindow(window) -winid window; -{ - return; -} - -void -safe_destroy_nhwindow(window) -winid window; -{ - return; -} - -void -safe_curs(window, x, y) -winid window; -int x, y; -{ - return; -} - -void -safe_putstr(window, attr, str) -winid window; -int attr; -const char *str; -{ - return; -} - -void -safe_display_file(fname, complain) -const char *fname; -boolean complain; -{ - return; -} - -void -safe_start_menu(window) -winid window; -{ - return; -} - -/*ARGSUSED*/ -/* - * Add a menu item to the beginning of the menu list. This list is reversed - * later. - */ -void -safe_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) -winid window; /* window to use, must be of type NHW_MENU */ -int glyph UNUSED; /* glyph to display with item (not used) */ -const anything *identifier; /* what to return if selected */ -char ch; /* keyboard accelerator (0 = pick our own) */ -char gch; /* group accelerator (0 = no group) */ -int attr; /* attribute for string (like safe_putstr()) */ -const char *str; /* menu string */ -boolean preselected; /* item is marked as selected */ -{ - return; -} - -/* - * End a menu in this window, window must a type NHW_MENU. - */ -void -safe_end_menu(window, prompt) -winid window; /* menu to use */ -const char *prompt; /* prompt to for menu */ -{ - return; -} - -int -safe_select_menu(window, how, menu_list) -winid window; -int how; -menu_item **menu_list; -{ - return 0; -} - -/* special hack for treating top line --More-- as a one item menu */ -char -safe_message_menu(let, how, mesg) -char let; -int how; -const char *mesg; -{ - return '\033'; -} - -void -safe_update_inventory() -{ - return; -} - -void -safe_mark_synch() -{ -} - -void -safe_wait_synch() -{ -} - -#ifdef CLIPPING -void -safe_cliparound(x, y) -int x, y; -{ -} -#endif /* CLIPPING */ - -/* - * safe_print_glyph - * - * Print the glyph to the output device. Don't flush the output device. - */ -void -safe_print_glyph(window, x, y, glyph, bkglyph) -winid window; -xchar x, y; -int glyph; -int bkglyph UNUSED; -{ - return; -} - -void -safe_raw_print(str) -const char *str; -{ - return; -} - -void -safe_raw_print_bold(str) -const char *str; -{ - return; -} - -int -safe_nhgetch() -{ - return '\033'; -} - -/* - * return a key, or 0, in which case a mouse button was pressed - * mouse events should be returned as character postitions in the map window. - * Since normal tty's don't have mice, just return a key. - */ -/*ARGSUSED*/ -int -safe_nh_poskey(x, y, mod) -int *x, *y, *mod; -{ - return '\033'; -} - -void -win_safe_init(dir) -int dir; -{ - return; -} - -#ifdef POSITIONBAR -void -safe_update_positionbar(posbar) -char *posbar; -{ - return; -} -#endif /* POSITIONBAR */ - -/* - * safe_status_init() - * -- initialize the port-specific data structures. - */ -void -safe_status_init() -{ - return; -} - -boolean -safe_can_suspend() -{ - return FALSE; -} - -void -safe_nhbell() -{ - return; -} - -int -safe_doprev_message() -{ - return 0; -} - -char -safe_yn_function(query, resp, def) -const char *query; -const char *resp; -char def; -{ - return '\033'; -} - -/*ARGSUSED*/ -void -safe_getlin(prompt, outbuf) -const char *prompt UNUSED; -char *outbuf; -{ - Strcpy(outbuf, "\033"); -} - -int -safe_get_ext_cmd() -{ - return '\033'; -} - -void -safe_number_pad(mode) -int mode; -{ - return; -} - -void -safe_delay_output() -{ - return; -} - -void -safe_start_screen() -{ - return; -} - -void -safe_end_screen() -{ - return; -} - -void -safe_outrip(tmpwin, how, when) -winid tmpwin; -int how; -time_t when; -{ - return; -} - -/*ARGSUSED*/ -void -safe_preference_update(pref) -const char *pref UNUSED; -{ - return; -} - -char * -safe_getmsghistory(init) -boolean init UNUSED; -{ - return (char *) 0; -} - -void -safe_putmsghistory(msg, is_restoring) -const char *msg; -boolean is_restoring; -{ -} - -void -safe_status_finish() -{ -} - -void -safe_status_enablefield(fieldidx, nm, fmt, enable) -int fieldidx; -const char *nm; -const char *fmt; -boolean enable; -{ -} - -#ifdef STATUS_HILITES -/* call once for each field, then call with BL_FLUSH to output the result */ -void -safe_status_update(idx, ptr, chg, percent, color, colormasks) -int idx; -genericptr_t ptr; -int chg UNUSED, percent UNUSED, color UNUSED; -unsigned long *colormasks UNUSED; -{ -} -#endif /* STATUS_HILITES */ - -/************************************************************** - * These are some optionally selectable routines that add - * some base functionality over the safe_* versions above. - * The safe_* versions are primarily designed to ensure that - * there are no null function pointers remaining at early - * game startup/initialization time. - * - * The slightly more functional versions in here should be kept - * free of platform-specific code or OS-specific code. If you - * want to use versions that involve platform-specific or - * OS-specific code, go right ahead but use your own replacement - * version of the functions in a platform-specific or - * OS-specific source file, not in here. - ***************************************************************/ - -/* Add to your code: windowprocs.win_raw_print = stdio_wait_synch; */ -void -stdio_wait_synch() -{ - char valid[] = {' ', '\n', '\r', '\033', '\0'}; - - fprintf(stdout, "--More--"); - (void) fflush(stdout); - while (!index(valid, nhgetch())) - ; -} - -/* Add to your code: windowprocs.win_raw_print = stdio_raw_print; */ -void -stdio_raw_print(str) -const char *str; -{ - if (str) - fprintf(stdout, "%s\n", str); - return; -} - -/* no newline variation, add to your code: - windowprocs.win_raw_print = stdio_nonl_raw_print; */ -void -stdio_nonl_raw_print(str) -const char *str; -{ - if (str) - fprintf(stdout, "%s", str); - return; -} - -/* Add to your code: windowprocs.win_raw_print_bold = stdio_raw_print_bold; */ -void -stdio_raw_print_bold(str) -const char *str; -{ - stdio_raw_print(str); - return; -} - -/* Add to your code: windowprocs.win_nhgetch = stdio_nhgetch; */ -int -stdio_nhgetch() -{ - return getchar(); -} - - -/* safeprocs.c */ diff --git a/win/share/thintile.c b/win/share/thintile.c index 4d6793c46..b975c37cf 100644 --- a/win/share/thintile.c +++ b/win/share/thintile.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 thintile.c $NHDT-Date: 1457207049 2016/03/05 19:44:09 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.10 $ */ +/* NetHack 5.0 thintile.c $NHDT-Date: 1596498337 2020/08/03 23:45:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) NetHack Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/share/tile.doc b/win/share/tile.doc index baa7bd266..d701d33df 100644 --- a/win/share/tile.doc +++ b/win/share/tile.doc @@ -1,4 +1,4 @@ -NetHack 3.6 tile.doc $NHDT-Date: 1524684654 2018/04/25 19:30:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.7 $ +NetHack 5.0 tile.doc $NHDT-Date: 1596498338 2020/08/03 23:45:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.8 $ Window ports can optionally make use of the tiles (pictures for NetHack symbols) found in this directory. They are distributed in a text format @@ -120,10 +120,10 @@ boolean read_gif_tile(pixel[TILE_Y][TILE_X]); Array provided by shared code for NetHack use, by compiling and running tilemap.c to form tile.c: -short glyph2tile[MAXGLYPH]; - maps glyph number to tile number for display purposes, assuming - (non-blank) tiles are numbered sequentially through - monsters/objects/other +glyph_map glyphmap[MAXGLYPH]; + maps glyph number to tile number, ( and later to ttychar, symidx, + glyphflags) for display purposes, assuming (non-blank) tiles are + numbered sequentially through monsters/objects/other tilemap.c (shudder) accounts for things disappearing due to compilation options -- there should be a tile for everything appearing under any diff --git a/win/share/tile.h b/win/share/tile.h index 0313ac07c..fcb01ece0 100644 --- a/win/share/tile.h +++ b/win/share/tile.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 tile.h $NHDT-Date: 1524689272 2018/04/25 20:47:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.13 $ */ +/* NetHack 5.0 tile.h $NHDT-Date: 1596498339 2020/08/03 23:45:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) 2016 by Michael Allison */ /* NetHack may be freely redistributed. See license for details. */ @@ -33,18 +33,18 @@ extern int colorsinmainmap; #define Fprintf (void) fprintf -extern boolean FDECL(fopen_text_file, (const char *, const char *)); -extern boolean FDECL(read_text_tile, (pixel(*) [TILE_X])); -extern boolean FDECL(write_text_tile, (pixel(*) [TILE_X])); -extern int NDECL(fclose_text_file); +extern boolean fopen_text_file(const char *, const char *); +extern boolean read_text_tile(pixel(*) [TILE_X]); +extern boolean write_text_tile(pixel(*) [TILE_X]); +extern int fclose_text_file(void); -extern void FDECL(set_grayscale, (int)); -extern void NDECL(init_colormap); -extern void NDECL(merge_colormap); +extern void set_grayscale(int); +extern void init_colormap(void); +extern void merge_colormap(void); #if defined(MICRO) || defined(WIN32) #undef exit #if !defined(MSDOS) && !defined(WIN32) -extern void FDECL(exit, (int)); +extern void exit(int); #endif #endif diff --git a/win/share/tile2bmp.c b/win/share/tile2bmp.c index ca2c7dd73..e875763f9 100644 --- a/win/share/tile2bmp.c +++ b/win/share/tile2bmp.c @@ -1,65 +1,37 @@ -/* NetHack 3.6 tile2bmp.c $NHDT-Date: 1451442061 2015/12/30 02:21:01 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $ */ +/* NetHack 5.0 tile2bmp.c $NHDT-Date: 1737281026 2025/01/19 02:03:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.51 $ */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* * Edit History: * - * Initial Creation M.Allison 1994/01/11 - * 256 colour bmp and statue support M.Allison 2015/04/19 + * Initial Creation M.Allison 1994/01/11 + * 256 colour bmp and statue support M.Allison 2015/04/19 * */ -/* #pragma warning(4103:disable) */ - #ifndef __GNUC__ #include "win32api.h" #endif -#include "hack.h" +#include "config.h" +#include "hacklib.h" + #include "tile.h" +extern void monst_globals_init(void); +extern void objects_globals_init(void); +static int examine_tilefiles(void); +static int set_tilefile_path(const char *, const char *, char *, size_t); -#include -#if defined(UINT32_MAX) && defined(INT32_MAX) && defined(UINT16_MAX) -#define UINT8 uint8_t -#define UINT16 uint16_t -#define UINT32 uint32_t -#define INT32 int32_t +#if defined(_MSC_VER) && defined(_WIN64) +#define UNALIGNED_POINTER __unaligned #else -# ifdef _MSC_VER -#define UINT8 unsigned char -#define UINT16 unsigned short -#define UINT32 unsigned long -#define INT32 long -# endif +#define UNALIGNED_POINTER #endif -#if (TILE_X == 32) #define COLORS_IN_USE 256 -#else -/*#define COLORS_IN_USE 16 */ /* 16 colors */ -#define COLORS_IN_USE 256 /* 256 colors */ -#endif - #define BITCOUNT 8 -extern char *FDECL(tilename, (int, int)); - -#define MAGICTILENO (340 + 440 + 231 + 340) - -#if BITCOUNT == 4 -#define MAX_X 320 /* 2 per byte, 4 bits per pixel */ -#define MAX_Y 480 -#else -#if (TILE_X == 32) -#define MAX_X (32 * 40) -#define MAX_Y ((MAGICTILENO * 32) / 40) * 2 -#else -#define MAX_X (16 * 40) -#define MAX_Y ((MAGICTILENO * 16) / 40) * 2 -#endif -#endif - /* GCC fix by Paolo Bonzini 1999/03/28 */ #ifdef __GNUC__ #define PACK __attribute__((packed)) @@ -77,8 +49,8 @@ leshort(short x) #endif } -static INT32 -lelong(INT32 x) +static int32_t +lelong(int32_t x) { #ifdef __BIG_ENDIAN__ return ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) @@ -90,88 +62,72 @@ lelong(INT32 x) #ifdef __GNUC__ typedef struct tagBMIH { - UINT32 biSize; - INT32 biWidth; - INT32 biHeight; - UINT16 biPlanes; - UINT16 biBitCount; - UINT32 biCompression; - UINT32 biSizeImage; - INT32 biXPelsPerMeter; - INT32 biYPelsPerMeter; - UINT32 biClrUsed; - UINT32 biClrImportant; + uint32_t biSize; + int32_t biWidth; + int32_t biHeight; + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + int32_t biXPelsPerMeter; + int32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; } PACK BITMAPINFOHEADER; typedef struct tagBMFH { - UINT16 bfType; - UINT32 bfSize; - UINT16 bfReserved1; - UINT16 bfReserved2; - UINT32 bfOffBits; + uint16_t bfType; + uint32_t bfSize; + uint16_t bfReserved1; + uint16_t bfReserved2; + uint32_t bfOffBits; } PACK BITMAPFILEHEADER; typedef struct tagRGBQ { - UINT8 rgbBlue; - UINT8 rgbGreen; - UINT8 rgbRed; - UINT8 rgbReserved; + uint8_t rgbBlue; + uint8_t rgbGreen; + uint8_t rgbRed; + uint8_t rgbReserved; } PACK RGBQUAD; -#define DWORD UINT32 -#define WORD UINT16 -#define BI_RGB 0L -#define BI_RLE8 1L -#define BI_RLE4 2L +#define BI_RGB 0L +#define BI_RLE8 1L +#define BI_RLE4 2L #define BI_BITFIELDS 3L #endif /* __GNUC__ */ +#define RGBQUAD_COUNT 256 #pragma pack(1) struct tagBMP { BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; -#if BITCOUNT == 4 -#define RGBQUAD_COUNT 16 RGBQUAD bmaColors[RGBQUAD_COUNT]; -#else -#if (TILE_X == 32) -#define RGBQUAD_COUNT 256 -#else -/*#define RGBQUAD_COUNT 16 */ -#define RGBQUAD_COUNT 256 -#endif - RGBQUAD bmaColors[RGBQUAD_COUNT]; -#endif -#if (COLORS_IN_USE == 16) - uchar packtile[MAX_Y][MAX_X]; -#else - uchar packtile[MAX_Y][MAX_X]; -/* uchar packtile[TILE_Y][TILE_X]; */ -#endif -} PACK bmp; + uchar packtile; /* start */ +} PACK bmp, *newbmp; #pragma pack() -#define BMPFILESIZE (sizeof(struct tagBMP)) - FILE *tibfile2; - pixel tilepixels[TILE_Y][TILE_X]; - -static void FDECL(build_bmfh, (BITMAPFILEHEADER *)); -static void FDECL(build_bmih, (BITMAPINFOHEADER *)); -static void FDECL(build_bmptile, (pixel(*) [TILE_X])); - -char *tilefiles[] = { -#if (TILE_X == 32) - "../win/share/mon32.txt", "../win/share/obj32.txt", - "../win/share/oth32.txt", -#else - "../win/share/monsters.txt", "../win/share/objects.txt", - "../win/share/other.txt", +static void build_bmfh(BITMAPFILEHEADER *); +static void build_bmih(UNALIGNED_POINTER BITMAPINFOHEADER *); +static void build_bmptile(pixel(*) [TILE_X]); + +#define TILESETS 1 +static const char *const relative_tiledir = "../win/share/"; +/* monsters must be first because main uses it twice */ +const char *const tilefilenames[TILESETS][3] = { + {"monsters.txt", "objects.txt", "other.txt"}, +#if 0 + {"mon32.txt", "obj32.txt", "oth32.txt"}, + {"mon64.txt", "obj64.txt", "oth64.txt"}, #endif }; +int tilecnt[SIZE(tilefilenames[0])]; +int tilefileset = 0; +int tiles_counted; +int max_x, max_y; +int magictileno = 0, bmpsize; int num_colors = 0; -int tilecount; int max_tiles_in_row = 40; int tiles_in_row; int filenum; @@ -181,29 +137,51 @@ int yoffset, xoffset; char bmpname[128]; FILE *fp; +DISABLE_WARNING_UNREACHABLE_CODE + int -main(argc, argv) -int argc; -char *argv[]; +main(int argc, char *argv[]) { - int i, j; + int i, j, number_of_rows, number_in_final_row; + uchar *c; + char tilefile_full_path[256] = { 0 }; if (argc != 2) { Fprintf(stderr, "usage: %s outfile.bmp\n", argv[0]); exit(EXIT_FAILURE); - } else + } else if (argv[1] == 0 || strlen(argv[1]) >= sizeof bmpname - 1) { + Fprintf(stderr, "invalid output bmp file name %s, aborting.\n", + argv[0]); + exit(EXIT_FAILURE); + } else { strcpy(bmpname, argv[1]); + } + + objects_globals_init(); + monst_globals_init(); -#ifdef OBSOLETE - bmpfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE); - if (bmpfile2 == (FILE *) 0) { - Fprintf(stderr, "Unable to open output file %s\n", - NETHACK_PACKED_TILEFILE); +/* tilefileset = (TILE_X == 64) ? 2 : (TILE_X == 32) ? 1 : 0; */ + tilefileset = 0; + if (!examine_tilefiles()) { + Fprintf(stderr, "unable to open all of the tile files, aborting.\n"); exit(EXIT_FAILURE); } -#endif - - tilecount = 0; + for (i = 0; i < SIZE(tilecnt); ++i) + magictileno += tilecnt[i]; + /* count monsters twice for grayscale variation */ + magictileno += tilecnt[0]; + + max_x = TILE_X * max_tiles_in_row; + max_y = ((TILE_Y * magictileno) / max_tiles_in_row) + TILE_Y; + bmpsize = (sizeof bmp - sizeof bmp.packtile) + + (max_y * (max_x * sizeof(uchar))); + newbmp = malloc(bmpsize); + if (!newbmp) { + printf("memory allocation failure, %d %d, aborting.\n", + bmpsize, magictileno); + exit(EXIT_FAILURE); + } + tiles_counted = 0; xoffset = yoffset = 0; initflag = 0; filenum = 0; @@ -211,44 +189,59 @@ char *argv[]; fp = fopen(bmpname, "wb"); if (!fp) { printf("Error creating tile file %s, aborting.\n", bmpname); - exit(1); + exit(EXIT_FAILURE); } while (pass < 4) { - filenum = pass % (sizeof(tilefiles) / sizeof(char *)); - if (!fopen_text_file(tilefiles[filenum], RDTMODE)) { + filenum = pass % SIZE(tilefilenames[tilefileset]); + if (!set_tilefile_path(relative_tiledir, + tilefilenames[tilefileset][filenum], + tilefile_full_path, sizeof tilefile_full_path)) { + Fprintf(stderr, "tile2bmp path issue %s %s %d\n", + relative_tiledir, tilefilenames[tilefileset][filenum], + (int) sizeof tilefile_full_path); + exit(EXIT_FAILURE); + } + if (!fopen_text_file(tilefile_full_path, RDTMODE)) { Fprintf(stderr, "usage: tile2bmp (from the util directory)\n"); exit(EXIT_FAILURE); } num_colors = colorsinmap; if (num_colors > 62) { - Fprintf(stderr, "too many colors (%d)\n", num_colors); + Fprintf(stderr, "too many colors (%d), aborting.\n", num_colors); exit(EXIT_FAILURE); } if (!initflag) { + UNALIGNED_POINTER BITMAPINFOHEADER *bmih; + build_bmfh(&bmp.bmfh); - build_bmih(&bmp.bmih); - for (i = 0; i < MAX_Y; ++i) - for (j = 0; j < MAX_X; ++j) - bmp.packtile[i][j] = (uchar) 0; + bmih = &bmp.bmih; + build_bmih(bmih); for (i = 0; i < num_colors; i++) { bmp.bmaColors[i].rgbRed = ColorMap[CM_RED][i]; bmp.bmaColors[i].rgbGreen = ColorMap[CM_GREEN][i]; bmp.bmaColors[i].rgbBlue = ColorMap[CM_BLUE][i]; bmp.bmaColors[i].rgbReserved = 0; } + *newbmp = bmp; + for (i = 0; i < max_y; ++i) + for (j = 0; j < max_x; ++j) { + c = &newbmp->packtile + ((i * max_x) + j); + *c = (uchar) 0; + } initflag = 1; } set_grayscale(pass == 3); - /* printf("Colormap initialized\n"); */ + /* printf("Colormap initialized\n"); */ while (read_text_tile(tilepixels)) { + if (tiles_counted >= magictileno) { + Fprintf(stderr, "tile2bmp: more than %d tiles!\n", + magictileno); + exit(EXIT_FAILURE); + } build_bmptile(tilepixels); - tilecount++; -#if BITCOUNT == 4 - xoffset += (TILE_X / 2); -#else + tiles_counted++; xoffset += TILE_X; -#endif - if (xoffset >= MAX_X) { + if (xoffset >= max_x) { yoffset += TILE_Y; xoffset = 0; } @@ -256,48 +249,52 @@ char *argv[]; (void) fclose_text_file(); ++pass; } - fwrite(&bmp, sizeof(bmp), 1, fp); + fwrite(newbmp, bmpsize, 1, fp); fclose(fp); - Fprintf(stderr, "Total of %d tiles written to %s.\n", tilecount, bmpname); + number_of_rows = tiles_counted / max_tiles_in_row; + number_in_final_row = tiles_counted % max_tiles_in_row; + + Fprintf(stderr, "Total of %d tiles written to %s, " + "%d full rows of %d tiles", + tiles_counted, bmpname, + number_of_rows, max_tiles_in_row); + if (number_in_final_row != 0) { + Fprintf(stderr, ", final row %d has %d tile%s", + number_of_rows + 1, number_in_final_row, + number_in_final_row > 1 ? "s" : ""); + } + (void) fputs(".\n\n", stderr); + free((genericptr_t) newbmp); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } +RESTORE_WARNINGS + static void -build_bmfh(pbmfh) -BITMAPFILEHEADER *pbmfh; +build_bmfh(BITMAPFILEHEADER* pbmfh) { pbmfh->bfType = leshort(0x4D42); - pbmfh->bfSize = lelong(BMPFILESIZE); - pbmfh->bfReserved1 = (UINT32) 0; - pbmfh->bfReserved2 = (UINT32) 0; - pbmfh->bfOffBits = lelong(sizeof(bmp.bmfh) + sizeof(bmp.bmih) + pbmfh->bfSize = lelong(bmpsize); + pbmfh->bfReserved1 = (uint32_t) 0; + pbmfh->bfReserved2 = (uint32_t) 0; + pbmfh->bfOffBits = lelong(sizeof bmp.bmfh + sizeof bmp.bmih + (RGBQUAD_COUNT * sizeof(RGBQUAD))); } static void -build_bmih(pbmih) -BITMAPINFOHEADER *pbmih; +build_bmih(UNALIGNED_POINTER BITMAPINFOHEADER* pbmih) { - WORD cClrBits; + uint16_t cClrBits; int w, h; pbmih->biSize = lelong(sizeof(bmp.bmih)); -#if BITCOUNT == 4 - pbmih->biWidth = lelong(w = MAX_X * 2); -#else - pbmih->biWidth = lelong(w = MAX_X); -#endif - pbmih->biHeight = lelong(h = MAX_Y); + pbmih->biWidth = lelong(w = max_x); + pbmih->biHeight = lelong(h = max_y); pbmih->biPlanes = leshort(1); -#if BITCOUNT == 4 - pbmih->biBitCount = leshort(4); - cClrBits = 4; -#else pbmih->biBitCount = leshort(8); cClrBits = 8; -#endif if (cClrBits == 1) cClrBits = 1; else if (cClrBits <= 4) @@ -319,22 +316,16 @@ BITMAPINFOHEADER *pbmih; #else pbmih->biClrUsed = lelong(RGBQUAD_COUNT); #endif - -#if (TILE_X == 16) - /* pbmih->biSizeImage = lelong(0); */ pbmih->biSizeImage = lelong(((w * cClrBits + 31) & ~31) / 8 * h); -#else - pbmih->biSizeImage = lelong(((w * cClrBits + 31) & ~31) / 8 * h); -#endif - pbmih->biClrImportant = (DWORD) 0; + pbmih->biClrImportant = (uint32_t) 0; } static void -build_bmptile(pixels) -pixel (*pixels)[TILE_X]; +build_bmptile(pixel(*pixels)[TILE_X]) { int cur_x, cur_y, cur_color, apply_color; int x, y; + uchar *c; for (cur_y = 0; cur_y < TILE_Y; cur_y++) { for (cur_x = 0; cur_x < TILE_X; cur_x++) { @@ -345,18 +336,62 @@ pixel (*pixels)[TILE_X]; break; } if (cur_color >= num_colors) - Fprintf(stderr, "color not in colormap!\n"); - y = (MAX_Y - 1) - (cur_y + yoffset); + Fprintf(stderr, "color not in colormap! (tile #%d)\n", + tiles_counted); + y = (max_y - 1) - (cur_y + yoffset); apply_color = cur_color; -#if BITCOUNT == 4 - x = (cur_x / 2) + xoffset; - bmp.packtile[y][x] = cur_x % 2 - ? (uchar)(bmp.packtile[y][x] | cur_color) - : (uchar)(cur_color << 4); -#else x = cur_x + xoffset; - bmp.packtile[y][x] = (uchar) apply_color; -#endif + c = &newbmp->packtile + ((y * max_x) + x); + *c = (uchar) apply_color; } } } + +static int +set_tilefile_path(const char *fdir, const char *fname, char *buf, size_t sz) +{ + size_t consuming = 0; + + *buf = '\0'; + consuming = strlen(fdir) + strlen(fname) + 1; + if (consuming > sz) + return 0; + Strcpy(buf, fdir); + Strcat(buf, fname); + return 1; +} + +static int +examine_tilefiles(void) +{ + FILE *fp2; + int i, tiles_in_file; + char tilefile_full_path[256]; + + for (i = 0; i < SIZE(tilefilenames[0]); ++i) { + tiles_in_file = 0; + if (!set_tilefile_path(relative_tiledir, + tilefilenames[tilefileset][i], + tilefile_full_path, + sizeof tilefile_full_path)) { + Fprintf(stderr, "tile2bmp path issue %s/%s %d\n", + relative_tiledir, tilefilenames[tilefileset][i], + (int) sizeof tilefile_full_path); + return 0; + } + fp2 = fopen(tilefile_full_path, "r"); + if (fp2) { + char line[256]; + + while (fgets(line, sizeof line, fp2)) { + if (!strncmp(line, "# tile ", 7)) + tiles_in_file++; + } + (void) fclose(fp2); + tilecnt[i] = tiles_in_file; + } + } + return 1; +} + +/*tile2bmp.c*/ diff --git a/win/share/tilemap.c b/win/share/tilemap.c index f859f44e8..302372c4a 100644 --- a/win/share/tilemap.c +++ b/win/share/tilemap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 tilemap.c $NHDT-Date: 1542501042 2018/11/18 00:30:42 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.35 $ */ +/* NetHack 5.0 tilemap.c $NHDT-Date: 1737720923 2025/01/24 04:15:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.87 $ */ /* Copyright (c) 2016 by Michael Allison */ /* NetHack may be freely redistributed. See license for details. */ @@ -8,37 +8,147 @@ * then again with it defined to produce tiletxt.{o,obj}. */ +#if 0 +#include "config.h" +/* #include "onames.h" */ +#include "permonst.h" +#include "objclass.h" +/* #include "pm.h" */ +#include "sym.h" +#include "rm.h" +#else #include "hack.h" +#endif + +#ifdef Snprintf +#undef Snprintf +#endif +#define Snprintf(str, size, ...) \ + nh_snprintf(__func__, __LINE__, str, size, __VA_ARGS__) + +#ifdef MONITOR_HEAP +/* with heap monitoring enabled, free(ptr) is a macro which expands to + nhfree(ptr,__FILE__,__LINE__); since tilemap doesn't link with + src/alloc.o it doesn't have access to nhfree(); use actual free */ +#undef free +#endif #define Fprintf (void) fprintf -const char *FDECL(tilename, (int, int)); -void NDECL(init_tilemap); -void FDECL(process_substitutions, (FILE *)); -boolean FDECL(acceptable_tilename, (int, const char *, const char *)); +/* + * Defining OBTAIN_TILEMAP to get a listing of the tile-mappings + * for debugging purposes requires that your link to produce + * the tilemap utility must also include: + * objects.o, monst.o drawing.o + */ +#define OBTAIN_TILEMAP + +#if defined(OBTAIN_TILEMAP) && !defined(TILETEXT) +FILE *tilemap_file; +#endif #if defined(MICRO) || defined(WIN32) #undef exit #if !defined(MSDOS) && !defined(WIN32) -extern void FDECL(exit, (int)); -#endif +extern void exit(int); #endif - -#if defined(MSDOS) || defined(WIN32) || defined(X11_GRAPHICS) -#define STATUES_LOOK_LIKE_MONSTERS #endif -#define MON_GLYPH 1 -#define OBJ_GLYPH 2 -#define OTH_GLYPH 3 /* fortunately unnecessary */ +struct { + int idx; + const char *tilelabel; + const char *expectedlabel; +} altlabels[MAXPCHARS + 1] = { +#define PCHAR_TILES +#include "defsym.h" +#undef PCHAR_TILES + { 0, 0, 0 } +}; +enum {MON_GLYPH, OBJ_GLYPH, OTH_GLYPH, TERMINATOR = -1}; #define EXTRA_SCROLL_DESCR_COUNT ((SCR_BLANK_PAPER - SCR_STINKING_CLOUD) - 1) +const char *altar_text[] = { + "unaligned", "chaotic", "neutral", "lawful", "other altar", +}; +enum wall_levels { main_dungeon, mines, gehennom, knox, sokoban }; -/* note that the ifdefs here should be the opposite sense from monst.c/ +int wall_offsets[] = { + GLYPH_CMAP_MAIN_OFF, GLYPH_CMAP_MINES_OFF, + GLYPH_CMAP_GEH_OFF, GLYPH_CMAP_KNOX_OFF, + GLYPH_CMAP_SOKO_OFF, +}; +const char *wall_texts[] = { + "main walls", "mines walls", "gehennom walls", + "knox walls", "sokoban walls", +}; +const char *walldesc[] = { + "vertical", "horizontal", "tlcorn", "trcorn", "blcorn", "brcorn", + "cross wall", "tuwall", "tdwall", "tlwall", "trwall", +}; + +int expl_offsets[] = { + GLYPH_EXPLODE_DARK_OFF, GLYPH_EXPLODE_NOXIOUS_OFF, + GLYPH_EXPLODE_MUDDY_OFF, GLYPH_EXPLODE_WET_OFF, + GLYPH_EXPLODE_MAGICAL_OFF, GLYPH_EXPLODE_FIERY_OFF, + GLYPH_EXPLODE_FROSTY_OFF, +}; +const char *expl_texts[] = { + "dark", "noxious", "muddy", "wet", "magical", "fiery", "frosty", +}; + +const char *zap_texts[] = { + "missile", "fire", "frost", "sleep", + "death", "lightning", "poison gas", "acid", +}; + +enum tilesrc { monsters_file, objects_file, other_file, generated }; +const char *tilesrc_texts[] = { + "monsters.txt", "objects.txt", "other.txt", "generated", +}; + +struct tilemap_t { + short tilenum; +#if defined(OBTAIN_TILEMAP) + char name[127]; + int glyph; +#endif +} tilemap[MAX_GLYPH]; + +#define MAX_TILENAM 256 + /* List of tiles encountered and their usage */ +struct tiles_used { + int tilenum; + enum tilesrc src; + int file_entry; + char tilenam[MAX_TILENAM]; + char references[1024]; +}; +struct tiles_used *tilelist[2500] = { 0 }; + +/* Some special tiles used for init of some things */ +int TILE_stone = 0, /* will get set to correct tile later */ + TILE_unexplored = 0, /* will get set to correct tile later */ + TILE_nothing = 0, /* will get set to correct tile later */ + TILE_corr = 0; /* will get set to correct tile later; X11 uses it */ + +/* prototypes for functions in this file */ +const char *tilename(int, const int, int); +void init_tilemap(void); +void process_substitutions(FILE *); +boolean acceptable_tilename(int, int, const char *, const char *); +#if defined(OBTAIN_TILEMAP) +void precheck(int offset, const char *glyphtype); +void add_tileref(int n, int glyphref, enum tilesrc src, int tile_file_entry, + const char *nam, const char *prefix); +void dump_tilerefs(FILE *fp); +void free_tilerefs(void); +#endif + + /* note that the ifdefs here should be the opposite sense from monst.c/ * objects.c/rm.h */ -struct conditionals { +struct conditionals_t { int sequence, predecessor; const char *name; } conditionals[] = { @@ -50,11 +160,11 @@ struct conditionals { { MON_GLYPH, PM_BABY_SILVER_DRAGON, "baby shimmering dragon" }, { MON_GLYPH, PM_SILVER_DRAGON, "shimmering dragon" }, { MON_GLYPH, PM_JABBERWOCK, "vorpal jabberwock" }, - { MON_GLYPH, PM_VAMPIRE_LORD, "vampire mage" }, + { MON_GLYPH, PM_VAMPIRE_LEADER, "vampire mage" }, #ifndef CHARON /* not supported yet */ { MON_GLYPH, PM_CROESUS, "Charon" }, #endif -#ifndef MAIL +#ifndef MAIL_STRUCTURES { MON_GLYPH, PM_FAMINE, "mail daemon" }, #endif /* commented out in monst.c at present */ @@ -69,181 +179,378 @@ struct conditionals { /* allow slime mold to look like slice of pizza, since we * don't know what a slime mold should look like when renamed anyway */ -#ifndef MAIL +#ifndef MAIL_STRUCTURES { OBJ_GLYPH, SCR_STINKING_CLOUD + EXTRA_SCROLL_DESCR_COUNT, "stamped / mail" }, #endif - { 0, 0, 0 } + { TERMINATOR, 0, 0 } }; +#if defined(TILETEXT) || defined(OBTAIN_TILEMAP) /* - * Some entries in glyph2tile[] should be substituted for on various levels. - * The tiles used for the substitute entries will follow the usual ones in - * other.til in the order given here, which should have every substitution - * for the same set of tiles grouped together. You will have to change - * more code in process_substitutions()/substitute_tiles() if the sets - * overlap in the future. - */ -struct substitute { - int first_glyph, last_glyph; - const char *sub_name; /* for explanations */ - const char *level_test; -} substitutes[] = { { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, - "mine walls", "In_mines(plev)" }, - { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, - "gehennom walls", "In_hell(plev)" }, - { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, - "knox walls", "Is_knox(plev)" }, - { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, - "sokoban walls", "In_sokoban(plev)" } }; - -#ifdef TILETEXT - -/* - * entry is the position of the tile within the monsters/objects/other set + * file_entry is the position of the tile within the monsters/objects/other set */ const char * -tilename(set, entry) -int set, entry; +tilename(int set, const int file_entry, int gend UNUSED) { - int i, j, condnum, tilenum; + int i, k, cmap, condnum, tilenum; static char buf[BUFSZ]; - - /* Note: these initializers don't do anything except guarantee that - we're linked properly. - */ - monst_init(); - objects_init(); +#if 0 + int offset, gendnum; +#endif (void) def_char_to_objclass(']'); - condnum = tilenum = 0; - - for (i = 0; i < NUMMONS; i++) { - if (set == MON_GLYPH && tilenum == entry) - return mons[i].mname; - tilenum++; - while (conditionals[condnum].sequence == MON_GLYPH - && conditionals[condnum].predecessor == i) { - if (set == MON_GLYPH && tilenum == entry) - return conditionals[condnum].name; - condnum++; + tilenum = 0; + + buf[0] = '\0'; + if (set == MON_GLYPH) { + for (i = 0; i < NUMMONS; i++) { + if (tilenum == file_entry) { + if (mons[i].pmnames[MALE]) + Snprintf(buf, sizeof buf, "%s {%s}", + mons[i].pmnames[NEUTRAL], mons[i].pmnames[MALE]); + else + Snprintf(buf, sizeof buf, "%s", mons[i].pmnames[NEUTRAL]); + return buf; + } + tilenum++; + if (tilenum == file_entry) { + if (mons[i].pmnames[FEMALE]) + Snprintf(buf, sizeof buf, "%s {%s}", + mons[i].pmnames[NEUTRAL], + mons[i].pmnames[FEMALE]); + else + Snprintf(buf, sizeof buf, "%s", mons[i].pmnames[NEUTRAL]); + return buf; + } + for (condnum = 0; conditionals[condnum].sequence != -1; + ++condnum) { + if (conditionals[condnum].sequence == MON_GLYPH + && conditionals[condnum].predecessor == i) { + for (k = 0; k < 2; k++) { /* male and female */ + tilenum++; + if (tilenum == file_entry) + return conditionals[condnum].name; + } + } + } + tilenum++; + } + if (tilenum == file_entry) + return "invisible monster"; + } /* MON_GLYPH */ + + if (set == OBJ_GLYPH) { + tilenum = 0; /* set-relative number */ + for (i = 0; i < NUM_OBJECTS; i++) { + /* prefer to give the description - that's all the tile's + * appearance should reveal */ + if (tilenum == file_entry) { + if (!obj_descr[i].oc_descr) + return obj_descr[i].oc_name; + if (!obj_descr[i].oc_name) + return obj_descr[i].oc_descr; + + Sprintf(buf, "%s / %s", obj_descr[i].oc_descr, + obj_descr[i].oc_name); + return buf; + } + for (condnum = 0; conditionals[condnum].sequence != -1; + ++condnum) { + if (conditionals[condnum].sequence == OBJ_GLYPH + && conditionals[condnum].predecessor == i) { + tilenum++; + if (tilenum == file_entry) + return conditionals[condnum].name; + } + } + tilenum++; + } + } /* OBJ_GLYPH */ + + if (set == OTH_GLYPH) { + tilenum = 0; /* set-relative number */ + + /* S_stone */ + for (cmap = S_stone; cmap <= S_stone; cmap++) { + if (tilenum == file_entry) { + if (*defsyms[cmap].explanation) { + return defsyms[cmap].explanation; + } else if (altlabels[cmap].tilelabel + && *altlabels[cmap].tilelabel) { + Sprintf(buf, "%s", altlabels[cmap].tilelabel); + return buf; + } else { + Sprintf(buf, "cmap %d %d", cmap, tilenum); + return buf; + } + } + for (condnum = 0; conditionals[condnum].sequence != -1; + condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + } + } tilenum++; } - } - if (set == MON_GLYPH && tilenum == entry) - return "invisible monster"; - tilenum = 0; /* set-relative number */ - for (i = 0; i < NUM_OBJECTS; i++) { - /* prefer to give the description - that's all the tile's - * appearance should reveal */ - if (set == OBJ_GLYPH && tilenum == entry) { - if (!obj_descr[i].oc_descr) - return obj_descr[i].oc_name; - if (!obj_descr[i].oc_name) - return obj_descr[i].oc_descr; - - Sprintf(buf, "%s / %s", obj_descr[i].oc_descr, - obj_descr[i].oc_name); - return buf; + /* walls - level specific */ + for (k = main_walls; k < mines_walls; k++) { + for (cmap = S_vwall; cmap <= S_trwall; cmap++) { + i = cmap - S_vwall; + if (tilenum == file_entry) { + Sprintf(buf, "%s %s", wall_texts[k], walldesc[i]); + return buf; + } + for (condnum = 0; conditionals[condnum].sequence != -1; + condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + } + } + tilenum++; + } } - tilenum++; - while (conditionals[condnum].sequence == OBJ_GLYPH - && conditionals[condnum].predecessor == i) { - if (set == OBJ_GLYPH && tilenum == entry) - return conditionals[condnum].name; - condnum++; + /* cmap A */ + for (cmap = S_ndoor; cmap <= S_brdnladder; cmap++) { + i = cmap - S_ndoor; nhUse(i); + if (tilenum == file_entry) { + if (*defsyms[cmap].explanation) { + return defsyms[cmap].explanation; + } else if (altlabels[cmap].tilelabel + && *altlabels[cmap].tilelabel) { + Sprintf(buf, "%s", altlabels[cmap].tilelabel); + return buf; + } else { + Sprintf(buf, "cmap %d %d", cmap, tilenum); + return buf; + } + } + for (condnum = 0; conditionals[condnum].sequence != -1; + ++condnum) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + if (tilenum == file_entry) + return conditionals[condnum].name; + } + } tilenum++; } - } - tilenum = 0; /* set-relative number */ - for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) { - if (set == OTH_GLYPH && tilenum == entry) { - if (*defsyms[i].explanation) { - return defsyms[i].explanation; - } else { - Sprintf(buf, "cmap %d", tilenum); + /* Altars */ + cmap = S_altar; + for (k = altar_unaligned; k <= altar_other; k++) { + /* Since defsyms only has one altar symbol, + it isn't much help in identifying details + these. Roll our own name. */ + if (tilenum == file_entry) { + Sprintf(buf, "%s altar", altar_text[k]); return buf; } + tilenum++; } - tilenum++; - while (conditionals[condnum].sequence == OTH_GLYPH - && conditionals[condnum].predecessor == i) { - if (set == OTH_GLYPH && tilenum == entry) - return conditionals[condnum].name; - condnum++; + for (condnum = 0; conditionals[condnum].sequence != -1; ++condnum) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + if (tilenum == file_entry) + return conditionals[condnum].name; + } + } + + /* cmap B */ + for (cmap = S_grave; cmap < S_arrow_trap + MAXTCHARS; cmap++) { + i = cmap - S_grave; nhUse(i); + if (tilenum == file_entry) { + if (*defsyms[cmap].explanation) { + return defsyms[cmap].explanation; + } else if (altlabels[cmap].tilelabel + && *altlabels[cmap].tilelabel) { + Sprintf(buf, "%s", altlabels[cmap].tilelabel); + return buf; + } else { + Sprintf(buf, "cmap %d %d", cmap, tilenum); + return buf; + } + } + + for (condnum = 0; conditionals[condnum].sequence != -1; + ++condnum) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + if (tilenum == file_entry) + return conditionals[condnum].name; + } + } tilenum++; } - } - /* explosions */ - tilenum = MAXPCHARS - MAXEXPCHARS; - i = entry - tilenum; - if (i < (MAXEXPCHARS * EXPL_MAX)) { - if (set == OTH_GLYPH) { - static const char *explosion_types[] = { - /* hack.h */ - "dark", "noxious", "muddy", "wet", "magical", "fiery", - "frosty" - }; - Sprintf(buf, "explosion %s %d", explosion_types[i / MAXEXPCHARS], - i % MAXEXPCHARS); + +#if 0 + /* zaps */ + for (k = 0; k < NUM_ZAP; k++) { + offset = GLYPH_ZAP_OFF + (k * ((S_rslant - S_vbeam) + 1)); + for (cmap = S_vbeam; cmap <= S_rslant; cmap++) { + i = cmap - S_vbeam; + if (tilenum == file_entry) { + Sprintf(buf, "%s zap %d %d", zap_texts[k], k + 1, i % 4); + return buf; + } + for (condnum = 0; conditionals[condnum].sequence != -1; + condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + } + } + tilenum++; + } + } +#else + i = file_entry - tilenum; + if (i < (NUM_ZAP << 2)) { + Sprintf(buf, "%s zap %d %d", zap_texts[i / 4], (i / 4) + 1, i % 4); return buf; } - } - tilenum += (MAXEXPCHARS * EXPL_MAX); + tilenum += (NUM_ZAP << 2); +#endif - i = entry - tilenum; - if (i < (NUM_ZAP << 2)) { - if (set == OTH_GLYPH) { - Sprintf(buf, "zap %d %d", i / 4, i % 4); - return buf; + /* cmap C */ + for (cmap = S_digbeam; cmap <= S_goodpos; cmap++) { + i = cmap - S_digbeam; nhUse(i); + if (tilenum == file_entry) { + if (*defsyms[cmap].explanation) { + return defsyms[cmap].explanation; + } else if (altlabels[cmap].tilelabel + && *altlabels[cmap].tilelabel) { + Sprintf(buf, "%s", altlabels[cmap].tilelabel); + return buf; + } else { + Sprintf(buf, "cmap %d %d", cmap, tilenum); + return buf; + } + } + for (condnum = 0; conditionals[condnum].sequence != -1; + ++condnum) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + if (tilenum == file_entry) + return conditionals[condnum].name; + } + } + tilenum++; + } + + /* swallow */ + for (cmap = S_sw_tl; cmap <= S_sw_br; cmap++) { + i = cmap - S_sw_tl; + if (tilenum + i == file_entry) { + if (*defsyms[cmap].explanation) { + return defsyms[cmap].explanation; + } else if (altlabels[cmap].tilelabel + && *altlabels[cmap].tilelabel) { + Sprintf(buf, "%s", altlabels[cmap].tilelabel); + return buf; + } else { + Sprintf(buf, "cmap swallow %d", cmap); + return buf; + } + } + } + tilenum += ((S_sw_br - S_sw_tl) + 1); + + /* explosions */ + for (k = expl_dark; k <= expl_frosty; k++) { + for (cmap = S_expl_tl; cmap <= S_expl_br; cmap++) { + i = cmap - S_expl_tl; nhUse(i); + if (tilenum == file_entry) { + /* substitute "explosion " in the tilelabel + with "explosion dark " etc */ + Sprintf(buf, "explosion %s %s", expl_texts[k], + &altlabels[cmap].tilelabel[10]); + return buf; + } + for (condnum = 0; conditionals[condnum].sequence != -1; + ++condnum) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + if (tilenum == file_entry) + return conditionals[condnum].name; + } + } + tilenum++; + } } - } - tilenum += (NUM_ZAP << 2); - i = entry - tilenum; - if (i < WARNCOUNT) { - if (set == OTH_GLYPH) { + /* warnings */ + i = file_entry - tilenum; + if (i < WARNCOUNT) { Sprintf(buf, "warning %d", i); return buf; } - } - tilenum += WARNCOUNT; + tilenum += WARNCOUNT; - for (i = 0; i < SIZE(substitutes); i++) { - j = entry - tilenum; - if (j <= substitutes[i].last_glyph - substitutes[i].first_glyph) { - if (set == OTH_GLYPH) { - Sprintf(buf, "sub %s %d", substitutes[i].sub_name, j); - return buf; - } + i = file_entry - tilenum; + if (i < 1) { + Sprintf(buf, "unexplored"); + return buf; } - tilenum += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; - } + tilenum += 1; + + i = file_entry - tilenum; + if (i < 1) { + Sprintf(buf, "nothing"); + return buf; + } + tilenum++; - Sprintf(buf, "unknown %d %d", set, entry); + /* other level walls */ + /* this batch starts at mines(1), not main(0) */ + for (k = mines_walls; k <= sokoban_walls; k++) { + for (cmap = S_vwall; cmap <= S_trwall; cmap++) { + i = cmap - S_vwall; + if (tilenum == file_entry) { + Sprintf(buf, "%s %s", wall_texts[k], walldesc[i]); + return buf; + } + for (condnum = 0; conditionals[condnum].sequence != -1; + condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + } + } + tilenum++; + } + } + } /* OTH_GLYPH */ + Sprintf(buf, "unknown %d %d", set, file_entry); return buf; } +#endif /* TILETEXT || OBTAIN_TILEMAP */ -#else /* TILETEXT */ - +#ifndef TILETEXT #define TILE_FILE "tile.c" - #ifdef AMIGA #define SOURCE_TEMPLATE "NH:src/%s" +#define INCLUDE_TEMPLATE "NH:include/t.%s" #else -#ifdef MAC +#ifdef MACOS9 #define SOURCE_TEMPLATE ":src:%s" +#define INCLUDE_TEMPLATE ":include:%s" #else #define SOURCE_TEMPLATE "../src/%s" +#define INCLUDE_TEMPLATE "../include/%s" #endif #endif -short tilemap[MAX_GLYPH]; - -#ifdef STATUES_LOOK_LIKE_MONSTERS +#ifndef STATUES_DONT_LOOK_LIKE_MONSTERS int lastmontile, lastobjtile, lastothtile, laststatuetile; #else int lastmontile, lastobjtile, lastothtile; @@ -256,31 +563,121 @@ int lastmontile, lastobjtile, lastothtile; * set up array to map glyph numbers to tile numbers * * assumes tiles are numbered sequentially through monsters/objects/other, - * with entries for all supported compilation options + * with entries for all supported compilation options. monsters have two + * tiles for each (male + female). * * "other" contains cmap and zaps (the swallow sets are a repeated portion * of cmap), as well as the "flash" glyphs for the new warning system * introduced in 3.3.1. */ void -init_tilemap() +init_tilemap(void) { - int i, j, condnum, tilenum; + int i, j, k, cmap, condnum, tilenum, offset; int corpsetile, swallowbase; + int file_entry = 0; + +#if defined(OBTAIN_TILEMAP) + tilemap_file = fopen("tilemappings.lst", "w"); + Fprintf(tilemap_file, "NUMMONS = %d\n", NUMMONS); + Fprintf(tilemap_file, "NUM_OBJECTS = %d\n", NUM_OBJECTS); + Fprintf(tilemap_file, "MAXEXPCHARS = %d\n", MAXEXPCHARS); + Fprintf(tilemap_file, "MAXPCHARS = %d\n", MAXPCHARS); + Fprintf(tilemap_file, "MAX_GLYPH = %d\n", MAX_GLYPH); + Fprintf(tilemap_file, "GLYPH_MON_OFF = %d\n", GLYPH_MON_OFF); + Fprintf(tilemap_file, "GLYPH_MON_MALE_OFF = %d\n", GLYPH_MON_MALE_OFF); + Fprintf(tilemap_file, "GLYPH_MON_FEM_OFF = %d\n", GLYPH_MON_FEM_OFF); + Fprintf(tilemap_file, "GLYPH_PET_OFF = %d\n", GLYPH_PET_OFF); + Fprintf(tilemap_file, "GLYPH_PET_MALE_OFF = %d\n", GLYPH_PET_MALE_OFF); + Fprintf(tilemap_file, "GLYPH_PET_FEM_OFF = %d\n", GLYPH_PET_FEM_OFF); + Fprintf(tilemap_file, "GLYPH_INVIS_OFF = %d\n", GLYPH_INVIS_OFF); + Fprintf(tilemap_file, "GLYPH_DETECT_OFF = %d\n", GLYPH_DETECT_OFF); + Fprintf(tilemap_file, "GLYPH_DETECT_MALE_OFF = %d\n", + GLYPH_DETECT_MALE_OFF); + Fprintf(tilemap_file, "GLYPH_DETECT_FEM_OFF = %d\n", + GLYPH_DETECT_FEM_OFF); + Fprintf(tilemap_file, "GLYPH_BODY_OFF = %d\n", GLYPH_BODY_OFF); + Fprintf(tilemap_file, "GLYPH_RIDDEN_OFF = %d\n", GLYPH_RIDDEN_OFF); + Fprintf(tilemap_file, "GLYPH_RIDDEN_MALE_OFF = %d\n", + GLYPH_RIDDEN_MALE_OFF); + Fprintf(tilemap_file, "GLYPH_RIDDEN_FEM_OFF = %d\n", + GLYPH_RIDDEN_FEM_OFF); + Fprintf(tilemap_file, "GLYPH_OBJ_OFF = %d\n", GLYPH_OBJ_OFF); + Fprintf(tilemap_file, "GLYPH_CMAP_OFF = %d\n", GLYPH_CMAP_OFF); + Fprintf(tilemap_file, "GLYPH_CMAP_STONE_OFF = %d\n", GLYPH_CMAP_STONE_OFF); + Fprintf(tilemap_file, "GLYPH_CMAP_MAIN_OFF = %d\n", GLYPH_CMAP_MAIN_OFF); + Fprintf(tilemap_file, "GLYPH_CMAP_MINES_OFF = %d\n", + GLYPH_CMAP_MINES_OFF); + Fprintf(tilemap_file, "GLYPH_CMAP_GEH_OFF = %d\n", GLYPH_CMAP_GEH_OFF); + Fprintf(tilemap_file, "GLYPH_CMAP_KNOX_OFF = %d\n", GLYPH_CMAP_KNOX_OFF); + Fprintf(tilemap_file, "GLYPH_CMAP_SOKO_OFF = %d\n", GLYPH_CMAP_SOKO_OFF); + Fprintf(tilemap_file, "GLYPH_CMAP_A_OFF = %d\n", GLYPH_CMAP_A_OFF); + Fprintf(tilemap_file, "GLYPH_ALTAR_OFF = %d\n", GLYPH_ALTAR_OFF); + Fprintf(tilemap_file, "GLYPH_CMAP_B_OFF = %d\n", GLYPH_CMAP_B_OFF); + Fprintf(tilemap_file, "GLYPH_ZAP_OFF = %d\n", GLYPH_ZAP_OFF); + Fprintf(tilemap_file, "GLYPH_CMAP_C_OFF = %d\n", GLYPH_CMAP_C_OFF); + Fprintf(tilemap_file, "GLYPH_SWALLOW_OFF = %d\n", GLYPH_SWALLOW_OFF); + Fprintf(tilemap_file, "GLYPH_EXPLODE_OFF = %d\n", GLYPH_EXPLODE_OFF); + Fprintf(tilemap_file, "GLYPH_EXPLODE_DARK_OFF = %d\n", + GLYPH_EXPLODE_DARK_OFF); + Fprintf(tilemap_file, "GLYPH_EXPLODE_NOXIOUS_OFF = %d\n", + GLYPH_EXPLODE_NOXIOUS_OFF); + Fprintf(tilemap_file, "GLYPH_EXPLODE_MUDDY_OFF = %d\n", + GLYPH_EXPLODE_MUDDY_OFF); + Fprintf(tilemap_file, "GLYPH_EXPLODE_WET_OFF = %d\n", + GLYPH_EXPLODE_WET_OFF); + Fprintf(tilemap_file, "GLYPH_EXPLODE_MAGICAL_OFF = %d\n", + GLYPH_EXPLODE_MAGICAL_OFF); + Fprintf(tilemap_file, "GLYPH_EXPLODE_FIERY_OFF = %d\n", + GLYPH_EXPLODE_FIERY_OFF); + Fprintf(tilemap_file, "GLYPH_EXPLODE_FROSTY_OFF = %d\n", + GLYPH_EXPLODE_FROSTY_OFF); + Fprintf(tilemap_file, "GLYPH_WARNING_OFF = %d\n", GLYPH_WARNING_OFF); + Fprintf(tilemap_file, "GLYPH_STATUE_OFF = %d\n", GLYPH_STATUE_OFF); + Fprintf(tilemap_file, "GLYPH_STATUE_MALE_OFF = %d\n", + GLYPH_STATUE_MALE_OFF); + Fprintf(tilemap_file, "GLYPH_STATUE_FEM_OFF = %d\n", + GLYPH_STATUE_FEM_OFF); + Fprintf(tilemap_file, "GLYPH_OBJ_PILETOP_OFF = %d\n", + GLYPH_OBJ_PILETOP_OFF); + Fprintf(tilemap_file, "GLYPH_BODY_PILETOP_OFF = %d\n", + GLYPH_BODY_PILETOP_OFF); + Fprintf(tilemap_file, "GLYPH_STATUE_MALE_PILETOP_OFF = %d\n", + GLYPH_STATUE_MALE_PILETOP_OFF); + Fprintf(tilemap_file, "GLYPH_STATUE_FEM_PILETOP_OFF = %d\n", + GLYPH_STATUE_FEM_PILETOP_OFF); + Fprintf(tilemap_file, "GLYPH_UNEXPLORED_OFF = %d\n", + GLYPH_UNEXPLORED_OFF); + Fprintf(tilemap_file, "GLYPH_NOTHING_OFF = %d\n", GLYPH_NOTHING_OFF); +#endif for (i = 0; i < MAX_GLYPH; i++) { - tilemap[i] = -1; + tilemap[i].tilenum = -1; } - corpsetile = NUMMONS + NUM_INVIS_TILES + CORPSE; - swallowbase = NUMMONS + NUM_INVIS_TILES + NUM_OBJECTS + S_sw_tl; + corpsetile = NUMMONS /* MON_MALE */ + + NUMMONS /* MON_FEM */ + + NUM_INVIS_TILES /* INVIS */ + + CORPSE; /* within OBJ */ + + swallowbase = NUMMONS /* MON_MALE */ + + NUMMONS /* MON_FEM */ + + NUM_INVIS_TILES /* INVIS */ + + NUM_OBJECTS /* Objects */ + + 1 /* Stone */ + + ((S_trwall - S_vwall) + 1) /* main walls */ + + ((S_brdnladder - S_ndoor) + 1) /* cmap A */ + + (4 + 1) /* 5 altar tiles */ + + (S_arrow_trap + MAXTCHARS - S_grave) /* cmap B */ + + (NUM_ZAP << 2) /* zaps */ + + ((S_goodpos - S_digbeam) + 1); /* cmap C */ /* add number compiled out */ - for (i = 0; conditionals[i].sequence; i++) { + for (i = 0; conditionals[i].sequence != TERMINATOR; i++) { switch (conditionals[i].sequence) { case MON_GLYPH: - corpsetile++; - swallowbase++; + corpsetile += 2; + swallowbase += 2; break; case OBJ_GLYPH: if (conditionals[i].predecessor < CORPSE) @@ -294,199 +691,650 @@ init_tilemap() } } - condnum = tilenum = 0; + tilenum = 0; for (i = 0; i < NUMMONS; i++) { - tilemap[GLYPH_MON_OFF + i] = tilenum; - tilemap[GLYPH_PET_OFF + i] = tilenum; - tilemap[GLYPH_DETECT_OFF + i] = tilenum; - tilemap[GLYPH_RIDDEN_OFF + i] = tilenum; - tilemap[GLYPH_BODY_OFF + i] = corpsetile; - j = GLYPH_SWALLOW_OFF + 8 * i; - tilemap[j] = swallowbase; - tilemap[j + 1] = swallowbase + 1; - tilemap[j + 2] = swallowbase + 2; - tilemap[j + 3] = swallowbase + 3; - tilemap[j + 4] = swallowbase + 4; - tilemap[j + 5] = swallowbase + 5; - tilemap[j + 6] = swallowbase + 6; - tilemap[j + 7] = swallowbase + 7; +#if defined(OBTAIN_TILEMAP) + char buf[256]; +#endif + + tilemap[GLYPH_MON_MALE_OFF + i].tilenum = tilenum; + tilemap[GLYPH_PET_MALE_OFF + i].tilenum = tilenum; + tilemap[GLYPH_DETECT_MALE_OFF + i].tilenum = tilenum; + tilemap[GLYPH_RIDDEN_MALE_OFF + i].tilenum = tilenum; + tilemap[GLYPH_BODY_OFF + i].tilenum = corpsetile; + tilemap[GLYPH_BODY_PILETOP_OFF + i].tilenum = corpsetile; +#if defined(OBTAIN_TILEMAP) + Sprintf(buf, "%s (mnum=%d)", tilename(MON_GLYPH, file_entry, 0), i); + Snprintf(tilemap[GLYPH_MON_MALE_OFF + i].name, + sizeof tilemap[0].name,"male %s", buf); + Snprintf(tilemap[GLYPH_PET_MALE_OFF + i].name, + sizeof tilemap[0].name, "%s male %s", "pet", buf); + Snprintf(tilemap[GLYPH_DETECT_MALE_OFF + i].name, + sizeof tilemap[0].name, "%s male %s", "detected", buf); + Snprintf(tilemap[GLYPH_RIDDEN_MALE_OFF + i].name, + sizeof tilemap[0].name, "%s male %s", "ridden", buf); + Snprintf(tilemap[GLYPH_BODY_OFF + i].name, + sizeof tilemap[0].name, "%s %s", "body of", buf); + Snprintf(tilemap[GLYPH_BODY_PILETOP_OFF + i].name, + sizeof tilemap[0].name, "%s %s", "piletop body of", buf); + add_tileref(tilenum, GLYPH_MON_MALE_OFF + i, monsters_file, + file_entry, tilemap[GLYPH_MON_MALE_OFF + i].name, ""); + add_tileref(tilenum, GLYPH_PET_MALE_OFF + i, monsters_file, + file_entry, tilemap[GLYPH_PET_MALE_OFF + i].name, ""); + add_tileref(tilenum, GLYPH_DETECT_MALE_OFF + i, monsters_file, + file_entry, tilemap[GLYPH_DETECT_MALE_OFF + i].name,""); + add_tileref(tilenum, GLYPH_RIDDEN_MALE_OFF + i, monsters_file, + file_entry, tilemap[GLYPH_RIDDEN_MALE_OFF + i].name, ""); + add_tileref(corpsetile, GLYPH_BODY_OFF + i, objects_file, CORPSE, + tilemap[GLYPH_BODY_OFF + i].name, ""); + add_tileref(corpsetile, GLYPH_BODY_PILETOP_OFF + i, objects_file, + CORPSE, tilemap[GLYPH_BODY_PILETOP_OFF + i].name, ""); +#endif tilenum++; - while (conditionals[condnum].sequence == MON_GLYPH - && conditionals[condnum].predecessor == i) { - condnum++; - tilenum++; + file_entry++; + tilemap[GLYPH_MON_FEM_OFF + i].tilenum = tilenum; + tilemap[GLYPH_PET_FEM_OFF + i].tilenum = tilenum; + tilemap[GLYPH_DETECT_FEM_OFF + i].tilenum = tilenum; + tilemap[GLYPH_RIDDEN_FEM_OFF + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Sprintf(buf, "%s (mnum=%d)", tilename(MON_GLYPH, file_entry, 0), i); + Snprintf(tilemap[GLYPH_MON_FEM_OFF + i].name, + sizeof tilemap[0].name, "female %s", buf); + Snprintf(tilemap[GLYPH_PET_FEM_OFF + i].name, + sizeof tilemap[0].name, "%s female %s", "pet", + buf); + Snprintf(tilemap[GLYPH_DETECT_FEM_OFF + i].name, + sizeof tilemap[0].name, "%s female %s", + "detected", buf); + Snprintf(tilemap[GLYPH_RIDDEN_FEM_OFF + i].name, + sizeof tilemap[0].name, "%s female %s", + "ridden", buf); + Snprintf(tilemap[GLYPH_BODY_OFF + i].name, + sizeof tilemap[0].name, "%s %s", "body of", buf); + Snprintf(tilemap[GLYPH_BODY_PILETOP_OFF + i].name, + sizeof tilemap[0].name, "%s %s", + "piletop body of", buf); + add_tileref(tilenum, GLYPH_MON_FEM_OFF + i, monsters_file, + file_entry, tilemap[GLYPH_MON_FEM_OFF + i].name, ""); + add_tileref(tilenum, GLYPH_PET_FEM_OFF + i, monsters_file, + file_entry, tilemap[GLYPH_PET_FEM_OFF + i].name, ""); + add_tileref(tilenum, GLYPH_DETECT_FEM_OFF + i, monsters_file, + file_entry, tilemap[GLYPH_DETECT_FEM_OFF + i].name, ""); + add_tileref(tilenum, GLYPH_RIDDEN_FEM_OFF + i, monsters_file, + file_entry, tilemap[GLYPH_RIDDEN_FEM_OFF + i].name, ""); + add_tileref(corpsetile, GLYPH_BODY_OFF + i, objects_file, CORPSE, + tilemap[GLYPH_BODY_OFF + i].name, ""); + add_tileref(corpsetile, GLYPH_BODY_PILETOP_OFF + i, objects_file, + corpsetile, tilemap[GLYPH_BODY_PILETOP_OFF + i].name, ""); +#endif + + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == MON_GLYPH + && conditionals[condnum].predecessor == i) { + tilenum += 2; /* male and female */ + file_entry += 2; +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping monst %s (%d)\n", + tilename(MON_GLYPH, file_entry, 0), file_entry); +#endif + } } + tilenum++; /* male + female tiles for each */ + file_entry++; } - tilemap[GLYPH_INVISIBLE] = tilenum++; - lastmontile = tilenum - 1; + tilemap[GLYPH_INVISIBLE].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Sprintf(tilemap[GLYPH_INVISIBLE].name, "%s (mnum=%d)", "invisible mon", + file_entry); + add_tileref(tilenum, GLYPH_INVISIBLE, monsters_file, + file_entry, tilemap[GLYPH_INVISIBLE].name, "invisible "); +#endif + lastmontile = tilenum; + tilenum++; + file_entry++; /* non-productive, but in case something ever gets + inserted right below here ahead of objects */ + /* start of objects */ + file_entry = 0; for (i = 0; i < NUM_OBJECTS; i++) { - tilemap[GLYPH_OBJ_OFF + i] = tilenum; + tilemap[GLYPH_OBJ_OFF + i].tilenum = tilenum; + tilemap[GLYPH_OBJ_PILETOP_OFF + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_OBJ_OFF + i].name, + sizeof tilemap[GLYPH_OBJ_OFF + i].name, + "%s (onum=%d)", + tilename(OBJ_GLYPH, file_entry, 0), i); + Snprintf(tilemap[GLYPH_OBJ_PILETOP_OFF + i].name, + sizeof tilemap[GLYPH_OBJ_PILETOP_OFF + i].name, + "%s %s (onum=%d)", + "piletop", tilename(OBJ_GLYPH, file_entry, 0), i); + add_tileref(tilenum, GLYPH_OBJ_OFF + i, + objects_file, file_entry, + tilemap[GLYPH_OBJ_OFF + i].name, ""); + add_tileref(tilenum, GLYPH_OBJ_PILETOP_OFF + i, + objects_file, file_entry, + tilemap[GLYPH_OBJ_PILETOP_OFF + i].name, ""); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OBJ_GLYPH + && conditionals[condnum].predecessor == i) { + tilenum++; + file_entry++; +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping obj %s (%d)\n", + tilename(OBJ_GLYPH, file_entry, 0), file_entry); +#endif + } + } tilenum++; - while (conditionals[condnum].sequence == OBJ_GLYPH - && conditionals[condnum].predecessor == i) { - condnum++; + file_entry++; + } + lastobjtile = tilenum - 1; + + file_entry = 0; + /* S_stone */ + cmap = S_stone; + precheck((GLYPH_CMAP_STONE_OFF), "stone"); + tilemap[GLYPH_CMAP_STONE_OFF].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_CMAP_STONE_OFF].name, + sizeof tilemap[0].name, + "%s (cmap=%d)", + tilename(OTH_GLYPH, file_entry, 0), + cmap); + add_tileref(tilenum, GLYPH_CMAP_STONE_OFF, + other_file, file_entry, + tilemap[GLYPH_CMAP_STONE_OFF].name, ""); +#endif + TILE_stone = tilenum; /* Used to init nul_glyphinfo tileidx entry */ + tilenum++; + file_entry++; + + /* walls in the main dungeon */ + for (k = main_walls; k < mines_walls; k++) { + offset = wall_offsets[k]; + for (cmap = S_vwall; cmap <= S_trwall; cmap++) { + i = cmap - S_vwall; + precheck(offset + i, "walls"); + tilemap[offset + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[offset + i].name, + sizeof tilemap[0].name, + "%s (cmap=%d)", + tilename(OTH_GLYPH, file_entry, 0), + cmap); + add_tileref(tilenum, offset + i, other_file, file_entry, + tilemap[offset + i].name, ""); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; + condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + file_entry++; +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping cmap %s (%d) (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), file_entry, + cmap); +#endif + } + } tilenum++; + file_entry++; } } - lastobjtile = tilenum - 1; - for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) { - tilemap[GLYPH_CMAP_OFF + i] = tilenum; + /* cmap A */ + for (cmap = S_ndoor; cmap <= S_brdnladder; cmap++) { + i = cmap - S_ndoor; + precheck((GLYPH_CMAP_A_OFF + i), "cmap A"); + tilemap[GLYPH_CMAP_A_OFF + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_CMAP_A_OFF + i].name, + sizeof tilemap[0].name, + "cmap A %s (cmap=%d)", + tilename(OTH_GLYPH, file_entry, 0), cmap); + add_tileref(tilenum, GLYPH_CMAP_A_OFF + i, other_file, file_entry, + tilemap[GLYPH_CMAP_A_OFF + i].name, ""); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + file_entry++; +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping cmap A %s (%d) (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), file_entry, cmap); +#endif + } + } + if (cmap == S_corr) + TILE_corr = tilenum; /* X11 references this tile during tile init */ tilenum++; - while (conditionals[condnum].sequence == OTH_GLYPH - && conditionals[condnum].predecessor == i) { - condnum++; - tilenum++; + file_entry++; + } + + /* Altars */ + cmap = S_altar; + j = 0; + for (k = altar_unaligned; k <= altar_other; k++) { + offset = GLYPH_ALTAR_OFF + j; + precheck((offset), "altar"); + tilemap[offset].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[offset].name, + sizeof tilemap[0].name, + "%s %s (cmap=%d)", + altar_text[j], tilename(OTH_GLYPH, file_entry, 0), cmap); + add_tileref(tilenum, offset, other_file, file_entry, + tilemap[offset].name, ""); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping %s %s (%d)\n", + altar_text[j], + tilename(OTH_GLYPH, file_entry, 0), cmap); +#endif + tilenum++; + file_entry++; + } } + j++; + tilenum++; + file_entry++; } - for (i = 0; i < (MAXEXPCHARS * EXPL_MAX); i++) { - tilemap[GLYPH_EXPLODE_OFF + i] = tilenum; + /* cmap B */ + for (cmap = S_grave; cmap < S_arrow_trap + MAXTCHARS; cmap++) { + i = cmap - S_grave; + precheck((GLYPH_CMAP_B_OFF + i), "cmap B"); + tilemap[GLYPH_CMAP_B_OFF + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_CMAP_B_OFF + i].name, + sizeof tilemap[0].name, + "%s (cmap=%d)", + tilename(OTH_GLYPH, file_entry, 0), cmap); + add_tileref(tilenum, GLYPH_CMAP_B_OFF + i, other_file, file_entry, + tilemap[GLYPH_CMAP_B_OFF + i].name, ""); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + file_entry++; +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping cmap %s (%d) (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), file_entry, cmap); +#endif + } + } tilenum++; - while (conditionals[condnum].sequence == OTH_GLYPH - && conditionals[condnum].predecessor == (i + MAXPCHARS)) { - condnum++; + file_entry++; + } + + /* zaps */ +#if 0 + for (k = 0; k < NUM_ZAP; k++) { + offset = GLYPH_ZAP_OFF + (k * ((S_rslant - S_vbeam) + 1)); + for (cmap = S_vbeam; cmap <= S_rslant; cmap++) { + i = cmap - S_vbeam; + precheck((offset + i), "zaps"); + tilemap[offset + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[offset + i].name, + sizeof tilemap[0].name, + "%s (%d) (%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry, cmap); + add_tileref(tilenum, offset + i, other_file, file_entry, + tilemap[offset + i].name, ""); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; + condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping zap %s (%d) (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), file_entry, + cmap); +#endif + file_entry++; + tilenum++; + } + + } tilenum++; + file_entry++; } } - +#else for (i = 0; i < NUM_ZAP << 2; i++) { - tilemap[GLYPH_ZAP_OFF + i] = tilenum; + tilemap[GLYPH_ZAP_OFF + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_ZAP_OFF + i].name, + sizeof tilemap[0].name, + "zap %s (cmap=%d)", + tilename(OTH_GLYPH, file_entry, 0), (i >> 2)); + add_tileref(tilenum, GLYPH_ZAP_OFF + i, other_file, file_entry, + tilemap[GLYPH_ZAP_OFF + i].name, ""); +#endif tilenum++; - while (conditionals[condnum].sequence == OTH_GLYPH + file_entry++; + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == (i + MAXEXPCHARS)) { - condnum++; - tilenum++; +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping zap %s (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif + file_entry++; + tilenum++; + } } } +#endif - for (i = 0; i < WARNCOUNT; i++) { - tilemap[GLYPH_WARNING_OFF + i] = tilenum; + /* cmap C */ + for (cmap = S_digbeam; cmap <= S_goodpos; cmap++) { + i = cmap - S_digbeam; + precheck((GLYPH_CMAP_C_OFF + i), "cmap C"); + tilemap[GLYPH_CMAP_C_OFF + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_CMAP_C_OFF + i].name, + sizeof tilemap[0].name, + "%s (cmap=%d)", + tilename(OTH_GLYPH, file_entry, 0), cmap); + add_tileref(tilenum, GLYPH_CMAP_C_OFF + i, other_file, file_entry, + tilemap[GLYPH_CMAP_C_OFF + i].name, ""); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + file_entry++; +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping cmap %s (%d) (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), file_entry, cmap); +#endif + } + } tilenum++; + file_entry++; + } + /* swallow */ + const char *swallow_text[] = { + "swallow top left", "swallow top center", + "swallow top right", "swallow middle left", + "swallow middle right", "swallow bottom left", + "swallow bottom center", "swallow bottom right", + }; + + offset = GLYPH_SWALLOW_OFF; + for (k = 0; k < NUMMONS; k++) { +// if (k == 0) { +// swallowbase = tilenum; +// } + for (cmap = S_sw_tl; cmap <= S_sw_br; cmap++) { + i = cmap - S_sw_tl; + precheck((offset + i), "swallows"); + tilemap[offset + i].tilenum = swallowbase + i; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[offset + i].name, + sizeof tilemap[0].name, + "%s %s (cmap=%d)", + swallow_text[i], + mons[k].pmnames[NEUTRAL], cmap); + add_tileref(swallowbase + i, offset + i, + other_file, file_entry + i, + tilemap[offset + i].name, ""); +#endif + } + offset += ((S_sw_br - S_sw_tl) + 1); } + tilenum += ((S_sw_br - S_sw_tl) + 1); + file_entry += ((S_sw_br - S_sw_tl) + 1); -#ifndef STATUES_LOOK_LIKE_MONSTERS - /* statue patch: statues still use the same glyph as in vanilla */ + /* explosions */ + for (k = expl_dark; k <= expl_frosty; k++) { + offset = expl_offsets[k]; + for (cmap = S_expl_tl; cmap <= S_expl_br; cmap++) { + i = cmap - S_expl_tl; + precheck((offset + i), "explosions"); + tilemap[offset + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[offset + i].name, + sizeof tilemap[0].name, + "%s (cmap=%d)", + tilename(OTH_GLYPH, file_entry, 0), cmap); + add_tileref(tilenum, offset + i, other_file, file_entry, + tilemap[offset + i].name, ""); +#endif - for (i = 0; i < NUMMONS; i++) { - tilemap[GLYPH_STATUE_OFF + i] = tilemap[GLYPH_OBJ_OFF + STATUE]; - } + for (condnum = 0; conditionals[condnum].sequence != -1; + condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping cmap %s (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), cmap); #endif + tilenum++; + file_entry++; + } + } + tilenum++; + file_entry++; + } + } - lastothtile = tilenum - 1; + for (i = 0; i < WARNCOUNT; i++) { + precheck((GLYPH_WARNING_OFF + i), "warnings"); + tilemap[GLYPH_WARNING_OFF + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_WARNING_OFF + i].name, + sizeof tilemap[0].name, + "%s (warn=%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry); + add_tileref(tilenum, GLYPH_WARNING_OFF + i, other_file, file_entry, + tilemap[GLYPH_WARNING_OFF + i].name, ""); +#endif + tilenum++; + file_entry++; + } -#ifdef STATUES_LOOK_LIKE_MONSTERS - /* skip over the substitutes to get to the grayscale statues */ - for (i = 0; i < SIZE(substitutes); i++) { - tilenum += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; + for (i = 0; i < 1; i++) { + precheck((GLYPH_UNEXPLORED_OFF + i), "unexplored"); + tilemap[GLYPH_UNEXPLORED_OFF + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_UNEXPLORED_OFF + i].name, + sizeof tilemap[0].name, + "unexplored %s (%d)", + tilemap[GLYPH_UNEXPLORED_OFF + i].name, file_entry); + add_tileref(tilenum, GLYPH_UNEXPLORED_OFF + i, other_file, file_entry, + tilemap[GLYPH_UNEXPLORED_OFF + i].name, ""); +#endif + TILE_unexplored = tilenum; /* for writing into tiledef.h */ + tilenum++; + file_entry++; } - /* statue patch: statues look more like the monster */ - condnum = 0; /* doing monsters again, so reset */ - for (i = 0; i < NUMMONS; i++) { - tilemap[GLYPH_STATUE_OFF + i] = tilenum; + for (i = 0; i < 1; i++) { + precheck(GLYPH_NOTHING + i, "nothing"); + tilemap[GLYPH_NOTHING + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_NOTHING + i].name, + sizeof tilemap[0].name, + " nothing %s (%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry); + add_tileref(tilenum, GLYPH_NOTHING + i, other_file, file_entry, + tilemap[GLYPH_NOTHING + i].name, ""); +#endif + TILE_nothing = tilenum; /* for writing into tiledef.h */ tilenum++; - while (conditionals[condnum].sequence == MON_GLYPH - && conditionals[condnum].predecessor == i) { - condnum++; + file_entry++; + } + /* other walls beyond the main walls */ + for (k = mines_walls; k <= sokoban_walls; k++) { + offset = wall_offsets[k]; + for (cmap = S_vwall; cmap <= S_trwall; cmap++) { + i = cmap - S_vwall; + precheck(offset + i, "walls"); + tilemap[offset + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[offset + i].name, + sizeof tilemap[0].name, + "%s (cmap=%d)", + tilename(OTH_GLYPH, file_entry, 0), + cmap); + add_tileref(tilenum, offset + i, other_file, file_entry, + tilemap[offset + i].name, ""); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == cmap) { + tilenum++; + file_entry++; +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping cmap %s (%d) (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), file_entry, cmap); +#endif + } + } tilenum++; + file_entry++; } } - laststatuetile = tilenum - 1; -#endif -} -const char *prolog[] = { "", "void", "substitute_tiles(plev)", - "d_level *plev;", "{", " int i;", "" }; +#ifdef STATUES_DONT_LOOK_LIKE_MONSTERS + /* statue patch: statues still use the same glyph as in 3.4.x */ -const char *epilog[] = { " return;", "}" }; + for (i = 0; i < NUMMONS; i++) { + tilemap[GLYPH_STATUE_OFF + i].tilenum = + tilemap[GLYPH_OBJ_OFF + STATUE].tilenum; +#ifdef OBTAIN_TILEMAP + Snprintf(tilemap[GLYPH_STATUE_OFF + i].name, + sizeof tilemap[0].name, + "%s (%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif + } +#endif + lastothtile = tilenum - 1; -/* write out the substitutions in an easily-used form. */ -void -process_substitutions(ofp) -FILE *ofp; -{ - static const char Dent[] = " "; /* 4 space indentation */ - int i, j, k, span, start; - - Fprintf(ofp, "\n"); - - j = 0; /* unnecessary */ - span = -1; - for (i = 0; i < SIZE(substitutes); i++) { - if (i == 0 || substitutes[i].first_glyph != substitutes[j].first_glyph - || substitutes[i].last_glyph != substitutes[j].last_glyph) { - j = i; - span++; - Fprintf(ofp, "short std_tiles%d[] = { ", span); - for (k = substitutes[i].first_glyph; - k < substitutes[i].last_glyph; k++) - Fprintf(ofp, "%d, ", tilemap[k]); - Fprintf(ofp, "%d };\n", tilemap[substitutes[i].last_glyph]); +#ifndef STATUES_DONT_LOOK_LIKE_MONSTERS + /* STATUES _DO_ LOOK LIKE MONSTERS */ + file_entry = 0; + /* statue patch: statues look more like the monster */ + for (i = 0; i < NUMMONS; i++) { + precheck(GLYPH_STATUE_MALE_OFF + i, "male statues"); + tilemap[GLYPH_STATUE_MALE_OFF + i].tilenum = tilenum; + precheck(GLYPH_STATUE_MALE_PILETOP_OFF + i, "male statue piletop"); + tilemap[GLYPH_STATUE_MALE_PILETOP_OFF + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_STATUE_MALE_OFF + i].name, + sizeof tilemap[0].name, + "statue of male %s (mnum=%d)", + tilename(MON_GLYPH, file_entry, 0), i); + Snprintf(tilemap[GLYPH_STATUE_MALE_PILETOP_OFF + i].name, + sizeof tilemap[0].name, + "piletop statue of male %s (mnum=%d)", + tilename(MON_GLYPH, file_entry, 0), i); + add_tileref(tilenum, GLYPH_STATUE_MALE_OFF + i, generated, file_entry, + tilemap[GLYPH_STATUE_MALE_OFF + i].name, + ""); + add_tileref(tilenum, GLYPH_STATUE_MALE_PILETOP_OFF + i, generated, + file_entry, + tilemap[GLYPH_STATUE_MALE_PILETOP_OFF + i].name, + ""); +#endif + tilenum++; + file_entry++; + precheck(GLYPH_STATUE_FEM_OFF + i, "female statues"); + tilemap[GLYPH_STATUE_FEM_OFF + i].tilenum = tilenum; + precheck(GLYPH_STATUE_FEM_PILETOP_OFF + i, "female statue piletop"); + tilemap[GLYPH_STATUE_FEM_PILETOP_OFF + i].tilenum = tilenum; +#if defined(OBTAIN_TILEMAP) + Snprintf(tilemap[GLYPH_STATUE_FEM_OFF + i].name, + sizeof tilemap[0].name, + "statue of female %s (mnum=%d)", + tilename(MON_GLYPH, file_entry, 0), i); + Sprintf(tilemap[GLYPH_STATUE_FEM_PILETOP_OFF + i].name, + "piletop statue of female %s (mnum=%d)", + tilename(MON_GLYPH, file_entry, 0), i); + add_tileref(tilenum, GLYPH_STATUE_FEM_OFF + i, generated, file_entry, + tilemap[GLYPH_STATUE_FEM_OFF + i].name, ""); + add_tileref(tilenum, GLYPH_STATUE_FEM_PILETOP_OFF + i, generated, + file_entry, + tilemap[GLYPH_STATUE_FEM_PILETOP_OFF + i].name, ""); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == MON_GLYPH + && conditionals[condnum].predecessor == i) { + file_entry += 2; /* skip female tile too */ + tilenum += 2; +#if defined(OBTAIN_TILEMAP) + Fprintf(tilemap_file, "skipping statue of %s (%d)\n", + tilename(MON_GLYPH, file_entry, 0), file_entry); +#endif + } } + tilenum++; + file_entry++; } + /* go beyond NUMMONS to cover off the invisible tile at the + end of monsters.txt so that the tile mapping matches things + in the .bmp file (for example) */ + file_entry = 0; +#if defined(OBTAIN_TILEMAP) + add_tileref(tilenum, NO_GLYPH, monsters_file, file_entry, + "invisible statue", ""); +#endif + laststatuetile = tilenum - 1; +#endif /* STATUES_DONT_LOOK_LIKE_MONSTERS */ - for (i = 0; i < SIZE(prolog); i++) { - Fprintf(ofp, "%s\n", prolog[i]); - } - j = -1; - span = -1; - start = lastothtile + 1; - for (i = 0; i < SIZE(substitutes); i++) { - if (i == 0 || substitutes[i].first_glyph != substitutes[j].first_glyph - || substitutes[i].last_glyph != substitutes[j].last_glyph) { - if (i != 0) { /* finish previous span */ - Fprintf(ofp, "%s} else {\n", Dent); - Fprintf(ofp, "%s%sfor (i = %d; i <= %d; i++)\n", Dent, Dent, - substitutes[j].first_glyph, substitutes[j].last_glyph); - Fprintf(ofp, "%s%s%sglyph2tile[i] = std_tiles%d[i - %d];\n", - Dent, Dent, Dent, span, substitutes[j].first_glyph); - Fprintf(ofp, "%s}\n\n", Dent); - } - j = i; - span++; - } - Fprintf(ofp, "%s%sif (%s) {\n", Dent, (i == j) ? "" : "} else ", - substitutes[i].level_test); - Fprintf(ofp, "%s%sfor (i = %d; i <= %d; i++)\n", Dent, Dent, - substitutes[i].first_glyph, substitutes[i].last_glyph); - Fprintf(ofp, "%s%s%sglyph2tile[i] = %d + i - %d;\n", - Dent, Dent, Dent, start, substitutes[i].first_glyph); - start += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; - } - /* finish last span */ - Fprintf(ofp, "%s} else {\n", Dent); - Fprintf(ofp, "%s%sfor (i = %d; i <= %d; i++)\n", Dent, Dent, - substitutes[j].first_glyph, substitutes[j].last_glyph); - Fprintf(ofp, "%s%s%sglyph2tile[i] = std_tiles%d[i - %d];\n", - Dent, Dent, Dent, span, substitutes[j].first_glyph); - Fprintf(ofp, "%s}\n", Dent); - - for (i = 0; i < SIZE(epilog); i++) { - Fprintf(ofp, "%s\n", epilog[i]); +#if defined(OBTAIN_TILEMAP) + for (i = 0; i < MAX_GLYPH; ++i) { + Fprintf(tilemap_file, "glyph[%04d] [%04d] %-80s\n", + i, tilemap[i].tilenum, tilemap[i].name); } - - lastothtile = start - 1; -#ifdef STATUES_LOOK_LIKE_MONSTERS - start = laststatuetile + 1; + dump_tilerefs(tilemap_file); + fclose(tilemap_file); #endif - Fprintf(ofp, "\nint total_tiles_used = %d;\n", start); } +#if defined(OBTAIN_TILEMAP) +extern void monst_globals_init(void); +extern void objects_globals_init(void); +#endif + +DISABLE_WARNING_UNREACHABLE_CODE + int -main() +main(int argc, char *argv[]) { - register int i; + int i, tilenum; char filename[30]; FILE *ofp; + const char *enhanced; + const char indent[] = " "; + +#if defined(OBTAIN_TILEMAP) + objects_globals_init(); + monst_globals_init(); +#endif init_tilemap(); +#ifdef ENHANCED_SYMBOLS + enhanced = ", utf8rep"; +#else + enhanced = ""; +#endif /* * create the source file, "tile.c" */ - Sprintf(filename, SOURCE_TEMPLATE, TILE_FILE); + Snprintf(filename, sizeof filename, SOURCE_TEMPLATE, TILE_FILE); if (!(ofp = fopen(filename, "w"))) { perror(filename); exit(EXIT_FAILURE); @@ -494,148 +1342,216 @@ main() Fprintf(ofp, "/* This file is automatically generated. Do not edit. */\n"); Fprintf(ofp, "\n#include \"hack.h\"\n"); - Fprintf(ofp, "\nshort glyph2tile[MAX_GLYPH] = {\n"); + Fprintf(ofp, "\n#ifndef TILES_IN_GLYPHMAP\n"); + Fprintf(ofp, "\n#else /* ?TILES_IN_GLYPHMAP */\n"); + Fprintf(ofp, "\nenum special_tiles {\n"); + Fprintf(ofp, " TILE_CORR = %d,\n", TILE_corr); + Fprintf(ofp, " TILE_STONE = %d,\n", TILE_stone); + Fprintf(ofp, " TILE_UNEXPLORED = %d\n", TILE_unexplored); + Fprintf(ofp, "};\n"); + Fprintf(ofp, "\nint total_tiles_used = %d,\n", laststatuetile + 1); + Fprintf(ofp, "%sTile_corr = TILE_CORR,\n", indent); /* X11 uses it */ + Fprintf(ofp, "%sTile_stone = TILE_STONE,\n", indent); + Fprintf(ofp, "%sTile_unexplored = TILE_UNEXPLORED,\n", indent); + Fprintf(ofp, "%smaxmontile = %d,\n", indent, lastmontile); + Fprintf(ofp, "%smaxobjtile = %d,\n", indent, lastobjtile); + Fprintf(ofp, "%smaxothtile = %d;\n\n", indent, lastothtile); + Fprintf(ofp, "#define NO_CUSTOMCOLOR (0U)\n\n"); + Fprintf(ofp, "/* glyph, ttychar, { %s%s } */\n", + "glyphflags, { NO_COLOR, symidx }, NO_CUSTOMCOLOR, NO_CUSTOMCOLOR, ovidx, tileidx", enhanced); +#ifdef ENHANCED_SYMBOLS + enhanced = ", 0"; /* replace ", utf8rep" since we're done with that */ +#endif + Fprintf(ofp, "const glyph_info nul_glyphinfo = {\n"); + Fprintf(ofp, "%sNO_GLYPH, ' ', NO_COLOR,\n", indent); + Fprintf(ofp, "%s%s/* glyph_map */\n", indent, indent); + Fprintf(ofp, "%s%s{ %s, TILE_UNEXPLORED%s }\n", indent, indent, + "MG_UNEXPL, { NO_COLOR, SYM_UNEXPLORED + SYM_OFF_X }, NO_CUSTOMCOLOR, NO_CUSTOMCOLOR", + enhanced); + Fprintf(ofp, "};\n"); + Fprintf(ofp, "\nglyph_map glyphmap[MAX_GLYPH] = {\n"); for (i = 0; i < MAX_GLYPH; i++) { - Fprintf(ofp, " %4d,", tilemap[i]); - if ((i % 12) == 11 || i == MAX_GLYPH - 1) - Fprintf(ofp, "\n"); + tilenum = tilemap[i].tilenum; + if (tilenum < 0) { /* will be -1 if not assigned a real value */ + Fprintf(stderr, "ERROR: glyph %d maps to tile %d.\n", i, tilenum); + (void) fclose(ofp); + unlink(filename); + exit(EXIT_FAILURE); + /*NOTREACHED*/ + } + Fprintf(ofp, + " { 0U, { NO_COLOR, 0 }, NO_CUSTOMCOLOR, NO_CUSTOMCOLOR, %4d%s }, /* [%04d] %s:%03d %s */\n", + tilenum, enhanced, i, + tilesrc_texts[tilelist[tilenum]->src], + tilelist[tilenum]->file_entry, + tilemap[i].name); } Fprintf(ofp, "};\n"); - - process_substitutions(ofp); - - Fprintf(ofp, "\n#define MAXMONTILE %d\n", lastmontile); - Fprintf(ofp, "#define MAXOBJTILE %d\n", lastobjtile); - Fprintf(ofp, "#define MAXOTHTILE %d\n", lastothtile); -#ifdef STATUES_LOOK_LIKE_MONSTERS - Fprintf(ofp, "/* #define MAXSTATUETILE %d */\n", laststatuetile); -#endif + Fprintf(ofp, "\n#endif /* TILES_IN_GLYPHMAP */\n"); Fprintf(ofp, "\n/*tile.c*/\n"); (void) fclose(ofp); + free_tilerefs(); exit(EXIT_SUCCESS); /*NOTREACHED*/ + nhUse(argc); + nhUse(argv); return 0; } -#endif /* TILETEXT */ +RESTORE_WARNINGS -struct { - int idx; - const char *betterlabel; - const char *expectedlabel; -} altlabels[] = { -{S_stone, "dark part of a room", "dark part of a room"}, -{S_vwall, "vertical wall", "wall"}, -{S_hwall, "horizontal wall", "wall"}, -{S_tlcorn, "top left corner wall", "wall"}, -{S_trcorn, "top right corner wall", "wall"}, -{S_blcorn, "bottom left corner wall", "wall"}, -{S_brcorn, "bottom right corner wall", "wall"}, -{S_crwall, "cross wall", "wall"}, -{S_tuwall, "tuwall", "wall"}, -{S_tdwall, "tdwall", "wall"}, -{S_tlwall, "tlwall", "wall"}, -{S_trwall, "trwall", "wall"}, -{S_ndoor, "no door", "doorway"}, -{S_vodoor, "vertical open door", "open door"}, -{S_hodoor, "horizontal open door", "open door"}, -{S_vcdoor, "vertical closed door", "closed door"}, -{S_hcdoor, "horizontal closed door", "closed door"}, -{S_bars, "iron bars", "iron bars"}, -{S_tree, "tree", "tree"}, -{S_room, "room", "floor of a room"}, -{S_darkroom, "darkroom", "dark part of a room"}, -{S_corr, "corridor", "corridor"}, -{S_litcorr, "lit corridor", "lit corridor"}, -{S_upstair, "up stairs", "staircase up"}, -{S_dnstair, "down stairs", "staircase down"}, -{S_upladder, "up ladder", "ladder up"}, -{S_dnladder, "down ladder", "ladder down"}, -{S_altar, "altar", "altar"}, -{S_grave, "grave", "grave"}, -{S_throne, "throne", "opulent throne"}, -{S_sink, "sink", "sink"}, -{S_fountain, "fountain", "fountain"}, -{S_pool, "pool", "water"}, -{S_ice, "ice", "ice"}, -{S_lava, "lava", "molten lava"}, -{S_vodbridge, "vertical open drawbridge", "lowered drawbridge"}, -{S_hodbridge, "horizontal open drawbridge", "lowered drawbridge"}, -{S_vcdbridge, "vertical closed drawbridge", "raised drawbridge"}, -{S_hcdbridge, "horizontal closed drawbridge", "raised drawbridge"}, -{S_air, "air", "air"}, -{S_cloud, "cloud", "cloud"}, -{S_water, "water", "water"}, -{S_arrow_trap, "arrow trap", "arrow trap"}, -{S_dart_trap, "dart trap", "dart trap"}, -{S_falling_rock_trap, "falling rock trap", "falling rock trap"}, -{S_squeaky_board, "squeaky board", "squeaky board"}, -{S_bear_trap, "bear trap", "bear trap"}, -{S_land_mine, "land mine", "land mine"}, -{S_rolling_boulder_trap, "rolling boulder trap", "rolling boulder trap"}, -{S_sleeping_gas_trap, "sleeping gas trap", "sleeping gas trap"}, -{S_rust_trap, "rust trap", "rust trap"}, -{S_fire_trap, "fire trap", "fire trap"}, -{S_pit, "pit", "pit"}, -{S_spiked_pit, "spiked pit", "spiked pit"}, -{S_hole, "hole", "hole"}, -{S_trap_door, "trap door", "trap door"}, -{S_teleportation_trap, "teleportation trap", "teleportation trap"}, -{S_level_teleporter, "level teleporter", "level teleporter"}, -{S_magic_portal, "magic portal", "magic portal"}, -{S_web, "web", "web"}, -{S_statue_trap, "statue trap", "statue trap"}, -{S_magic_trap, "magic trap", "magic trap"}, -{S_anti_magic_trap, "anti magic trap", "anti-magic field"}, -{S_polymorph_trap, "polymorph trap", "polymorph trap"}, -{S_vibrating_square, "vibrating square", "vibrating square"}, -{S_vbeam, "vertical beam", "cmap 65"}, -{S_hbeam, "horizontal beam", "cmap 66"}, -{S_lslant, "left slant beam", "cmap 67"}, -{S_rslant, "right slant beam", "cmap 68"}, -{S_digbeam, "dig beam", "cmap 69"}, -{S_flashbeam, "flash beam", "cmap 70"}, -{S_boomleft, "boom left", "cmap 71"}, -{S_boomright, "boom right", "cmap 72"}, -{S_ss1, "shield1", "cmap 73"}, -{S_ss2, "shield2", "cmap 74"}, -{S_ss3, "shield3", "cmap 75"}, -{S_ss4, "shield4", "cmap 76"}, -{S_poisoncloud, "poison cloud", "poison cloud"}, -{S_goodpos, "valid position", "valid position"}, -{S_sw_tl, "swallow top left", "cmap 79"}, -{S_sw_tc, "swallow top center", "cmap 80"}, -{S_sw_tr, "swallow top right", "cmap 81"}, -{S_sw_ml, "swallow middle left", "cmap 82"}, -{S_sw_mr, "swallow middle right", "cmap 83"}, -{S_sw_bl, "swallow bottom left ", "cmap 84"}, -{S_sw_bc, "swallow bottom center", "cmap 85"}, -{S_sw_br, "swallow bottom right", "cmap 86"}, -{S_explode1, "explosion top left", "explosion dark 0"}, -{S_explode2, "explosion top centre", "explosion dark 1"}, -{S_explode3, "explosion top right", "explosion dark 2"}, -{S_explode4, "explosion middle left", "explosion dark 3"}, -{S_explode5, "explosion middle center", "explosion dark 4"}, -{S_explode6, "explosion middle right", "explosion dark 5"}, -{S_explode7, "explosion bottom left", "explosion dark 6"}, -{S_explode8, "explosion bottom center", "explosion dark 7"}, -{S_explode9, "explosion bottom right", "explosion dark 8"}, -}; +#endif /* TILETEXT */ boolean -acceptable_tilename(idx, encountered, expected) -int idx; -const char *encountered, *expected; +acceptable_tilename( + int glyph_set, + int idx, + const char *encountered, + const char *expected) { - if (idx >= 0 && idx < SIZE(altlabels)) { - if (!strcmp(altlabels[idx].expectedlabel, expected)) { - if (!strcmp(altlabels[idx].betterlabel, encountered)) + int i; + size_t a, b; + char buf[BUFSZ]; + const char *pastprefix = encountered; + struct aliaslist { + const char *original; + const char *alias; + }; + struct aliaslist aliases[] = { + { "wall", "vertical wall" }, + { "wall", "horizontal wall" }, + { "wall", "top left corner wall" }, + { "wall", "top right corner wall" }, + { "wall", "bottom left corner wall" }, + { "wall", "bottom right corner wall" }, + { "open door", "vertical open door" }, + { "open door", "horizontal open door" }, + { "open door", "no door" }, + { "altar", "chaotic altar" }, + { "altar", "neutral altar" }, + { "altar", "lawful altar" }, + { "opulent throne", "throne" }, + { "water", "pool" }, + { "lowered drawbridge", "vertical open drawbridge" }, + { "lowered drawbridge", "horizontal open drawbridge" }, + { "raised drawbridge", "vertical closed drawbridge" }, + { "raised drawbridge", "horizontal closed drawbridge" }, + { "altar", "unaligned altar" }, + { "altar", "other altar" }, +#if 0 + { "dark part of a room", "stone" }, +#endif + }; + + if (glyph_set == OTH_GLYPH) { + if (idx >= 0 && idx < (SIZE(altlabels) - 1)) { + if (!strcmp(altlabels[idx].tilelabel, encountered)) + return TRUE; + } + a = strlen(encountered); + for (i = 0; i < SIZE(aliases); i++) { + if (!strcmp(pastprefix, aliases[i].alias)) + return TRUE; + pastprefix = encountered; + b = strlen(aliases[i].alias); + if (a > b) { + pastprefix = encountered + (a - b); + if (!strcmp(pastprefix, aliases[i].alias)) + return TRUE; + } + if (!strcmp(encountered, aliases[i].alias) + && !strcmp(expected, aliases[i].original)) { return TRUE; + } + } + Snprintf(buf, sizeof buf, "cmap tile %d", idx); + if (!strcmp(expected, buf)) + return TRUE; + return FALSE; + } + return TRUE; +} + +#if defined(OBTAIN_TILEMAP) +void +precheck(int offset, const char *glyphtype) +{ + if (tilemap[offset].tilenum != -1) + Fprintf(stderr, "unexpected re-write of tile mapping [%s]\n", + glyphtype); +} + +void +add_tileref( + int n, + int glyphref, + enum tilesrc src, + int entrynum, + const char *nam, + const char *prefix) +{ + struct tiles_used temp = { 0 }; + static const char ellipsis[] = "..."; + char buf[BUFSZ]; + + if (!tilelist[n]) { + if ((tilelist[n] = malloc(sizeof temp)) != 0) { + tilelist[n]->tilenum = n; + tilelist[n]->src = src; + tilelist[n]->file_entry = entrynum; + /* leave room for trailing "...nnnn" */ + Snprintf(tilelist[n]->tilenam, sizeof tilelist[n]->tilenam - 7, + "%s%s", prefix, nam); + tilelist[n]->references[0] = '\0'; + } else { + Fprintf(stderr, "tilemap malloc failure %zu bytes\n", + sizeof temp); + exit(EXIT_FAILURE); + } + } + Snprintf(temp.references, + sizeof temp.references - 7, /* room for "...nnnn" */ + "%s%s%d", tilelist[n]->references, + (tilelist[n]->references[0] != '\0') ? ", " : "", glyphref); + Snprintf(buf, sizeof buf, "...%4d", glyphref); + Snprintf(tilelist[n]->references, sizeof tilelist[n]->references, "%s%s", + temp.references, + (strlen(temp.references) >= (sizeof temp.references - 7) - 1) + ? buf + : ""); + nhUse(ellipsis); +} + +void +dump_tilerefs(FILE * fp) +{ + int i; + + Fprintf(fp, "\n"); + for (i = 0; i < SIZE(tilelist); i++) { + if (tilelist[i]) { + Fprintf(fp, "tile[%04d] %s[%04d] %-25s: %s\n", i, + tilesrc_texts[tilelist[i]->src], + tilelist[i]->file_entry, + tilelist[i]->tilenam, + tilelist[i]->references); } } - return FALSE; } +void +free_tilerefs(void) +{ + int i; + + for (i = 0; i < SIZE(tilelist); i++) { + if (tilelist[i]) + free((genericptr_t) tilelist[i]), tilelist[i] = 0; + } +} + +#endif + /*tilemap.c*/ diff --git a/win/share/tileset.c b/win/share/tileset.c index d37b91281..6a1280fb4 100644 --- a/win/share/tileset.c +++ b/win/share/tileset.c @@ -1,13 +1,16 @@ -/* NetHack 3.6 tileset.c $NHDT-Date: 1501463811 2017/07/31 01:16:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.0 $ */ +/* NetHack 5.0 tileset.c $NHDT-Date: 1596498341 2020/08/03 23:45:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.3 $ */ /* Copyright (c) Ray Chason, 2016. */ /* NetHack may be freely redistributed. See license for details. */ -#include "hack.h" +#include "config.h" +#include "objclass.h" +#include "flag.h" #include "tileset.h" -static void FDECL(get_tile_map, (const char *)); -static void FDECL(split_tiles, (const struct TileSetImage *)); -static void FDECL(free_image, (struct TileSetImage *)); +static void get_tile_map(const char *); +static unsigned gcd(unsigned, unsigned); +static void split_tiles(const struct TileSetImage *); +static void free_image(struct TileSetImage *); static struct TileImage *tiles; static unsigned num_tiles; @@ -17,9 +20,7 @@ static boolean have_palette; static struct Pixel palette[256]; boolean -read_tiles(filename, true_color) -const char *filename; -boolean true_color; +read_tiles(const char *filename, boolean true_color) { static const unsigned char png_sig[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A @@ -100,22 +101,43 @@ boolean true_color; return FALSE; } +/* Free tile memory not required by the chosen display mode */ +void +set_tile_type(boolean true_color) +{ + unsigned i; + + if (tiles) { + if (true_color) { + for (i = 0; i < num_tiles; ++i) { + free((genericptr_t) tiles[i].indexes); + tiles[i].indexes = NULL; + } + have_palette = FALSE; + } else { + for (i = 0; i < num_tiles; ++i) { + free((genericptr_t) tiles[i].pixels); + tiles[i].pixels = NULL; + } + } + } +} + const struct Pixel * -get_palette() +get_palette(void) { return have_palette ? palette : NULL; } /* TODO: derive tile_map from image_desc */ static void -get_tile_map(image_desc) -const char *image_desc; +get_tile_map(const char *image_desc UNUSED) { return; } void -free_tiles() +free_tiles(void) { unsigned i; @@ -135,8 +157,7 @@ free_tiles() } static void -free_image(image) -struct TileSetImage *image; +free_image(struct TileSetImage *image) { if (image->pixels) free((genericptr_t) image->pixels), image->pixels = NULL; @@ -147,17 +168,118 @@ struct TileSetImage *image; } const struct TileImage * -get_tile(tile_index) -unsigned tile_index; +get_tile(unsigned tile_index) { if (tile_index >= num_tiles) return &blank_tile; return &tiles[tile_index]; } +/* Note that any tile returned by this function must be freed */ +struct TileImage * +stretch_tile(const struct TileImage *inp_tile, + unsigned out_width, unsigned out_height) +{ + unsigned x_scale_inp, x_scale_out, y_scale_inp, y_scale_out; + unsigned divisor; + unsigned size; + struct TileImage *out_tile; + unsigned x_inp, y_inp, x2, y2, x_out, y_out; + unsigned pos; + + /* Derive the scale factors */ + divisor = gcd(out_width, inp_tile->width); + x_scale_inp = inp_tile->width / divisor; + x_scale_out = out_width / divisor; + divisor = gcd(out_height, inp_tile->height); + y_scale_inp = inp_tile->height / divisor; + y_scale_out = out_height / divisor; + + /* Derive the stretched tile */ + out_tile = (struct TileImage *) alloc(sizeof(struct TileImage)); + out_tile->width = out_width; + out_tile->height = out_height; + size = out_width * out_height; + if (inp_tile->pixels != NULL) { + out_tile->pixels = (struct Pixel *) alloc(size * sizeof(struct Pixel)); + divisor = x_scale_inp * y_scale_inp; + for (y_out = 0; y_out < out_height; ++y_out) { + for (x_out = 0; x_out < out_width; ++x_out) { + unsigned r, g, b, a; + + /* Derive output pixels by blending input pixels */ + r = 0; + g = 0; + b = 0; + a = 0; + for (y2 = 0; y2 < y_scale_inp; ++y2) { + y_inp = (y_out * y_scale_inp + y2) / y_scale_out; + for (x2 = 0; x2 < x_scale_inp; ++x2) { + x_inp = (x_out * x_scale_inp + x2) / x_scale_out; + pos = y_inp * inp_tile->width + x_inp; + r += inp_tile->pixels[pos].r; + g += inp_tile->pixels[pos].g; + b += inp_tile->pixels[pos].b; + a += inp_tile->pixels[pos].a; + } + } + + pos = y_out * out_width + x_out; + out_tile->pixels[pos].r = r / divisor; + out_tile->pixels[pos].g = g / divisor; + out_tile->pixels[pos].b = b / divisor; + out_tile->pixels[pos].a = a / divisor; + } + } + } else { + out_tile->pixels = NULL; + } + + /* If the output device uses a palette, we can't blend; just pick + a subset of the pixels */ + if (inp_tile->indexes != NULL) { + out_tile->indexes = (unsigned char *) alloc(size); + for (y_out = 0; y_out < out_height; ++y_out) { + for (x_out = 0; x_out < out_width; ++x_out) { + pos = y_out * out_width + x_out; + x_inp = x_out * x_scale_inp / x_scale_out; + y_inp = y_out * y_scale_inp / y_scale_out; + out_tile->indexes[pos] = + inp_tile->indexes[y_inp * inp_tile->width + x_inp]; + } + } + } else { + out_tile->indexes = NULL; + } + return out_tile; +} + +/* Free a tile returned by stretch_tile */ +/* Do NOT use this with tiles returned by get_tile */ +void +free_tile(struct TileImage *tile) +{ + if (tile != NULL) { + free(tile->indexes); + free(tile->pixels); + free(tile); + } +} + +/* Return the greatest common divisor */ +static unsigned +gcd(unsigned a, unsigned b) +{ + while (TRUE) { + if (b == 0) return a; + a %= b; + if (a == 0) return b; + b %= a; + } +} + static void -split_tiles(image) -const struct TileSetImage *image; +split_tiles(const struct TileSetImage *image) { unsigned tile_rows, tile_cols; size_t tile_size, i, j; @@ -185,8 +307,8 @@ const struct TileSetImage *image; if (image->indexes != NULL) { tile->indexes = (unsigned char *) alloc(tile_size); } - for (y2 = 0; y2 < iflags.wc_tile_height; ++y2) { - for (x2 = 0; x2 < iflags.wc_tile_width; ++x2) { + for (y2 = 0; y2 < (unsigned) iflags.wc_tile_height; ++y2) { + for (x2 = 0; x2 < (unsigned) iflags.wc_tile_width; ++x2) { unsigned x = x1 * iflags.wc_tile_width + x2; unsigned y = y1 * iflags.wc_tile_height + y2; @@ -219,9 +341,7 @@ const struct TileSetImage *image; } boolean -read_png_tiles(filename, image) -const char *filename; -struct TileSetImage *image; +read_png_tiles(const char *filename UNUSED, struct TileSetImage *image UNUSED) { /* stub */ return FALSE; diff --git a/win/share/tiletext.c b/win/share/tiletext.c index 480698c01..80f630f94 100644 --- a/win/share/tiletext.c +++ b/win/share/tiletext.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 tiletext.c $NHDT-Date: 1524689272 2018/04/25 20:47:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.16 $ */ +/* NetHack 5.0 tiletext.c $NHDT-Date: 1596498342 2020/08/03 23:45:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.17 $ */ /* Copyright (c) 2016 by Pasi Kallinen */ /* NetHack may be freely redistributed. See license for details. */ @@ -18,43 +18,114 @@ static int placeholder_init = 0; static pixel placeholder[TILE_Y][TILE_X]; static FILE *tile_file; static int tile_set, tile_set_indx; +static const char *const text_sets[] = { #if (TILE_X == 8) -static const char *text_sets[] = { "monthin.txt", "objthin.txt", - "oththin.txt" }; + "monthin.txt", "objthin.txt", "oththin.txt" #else -static const char *text_sets[] = { "monsters.txt", "objects.txt", - "other.txt" }; + "monsters.txt", "objects.txt", "other.txt" #endif +}; + +static char inbuf[BUFSZ]; + +extern const char *tilename(int, int, int); +extern boolean acceptable_tilename(int, int, const char *, const char *); +static int get_next_line(FILE *, boolean); +static void read_text_colormap(FILE *); +static boolean write_text_colormap(FILE *); +static boolean read_txttile(FILE *, pixel (*)[TILE_X]); +static void write_txttile(FILE *, pixel (*)[TILE_X]); -extern const char *FDECL(tilename, (int, int)); -extern boolean FDECL(acceptable_tilename, (int, const char *, const char *)); -static void FDECL(read_text_colormap, (FILE *)); -static boolean FDECL(write_text_colormap, (FILE *)); -static boolean FDECL(read_txttile, (FILE *, pixel (*)[TILE_X])); -static void FDECL(write_txttile, (FILE *, pixel (*)[TILE_X])); +enum { MONSTER_SET, OBJECT_SET, OTHER_SET}; /* Ugh. DICE doesn't like %[A-Z], so we have to spell it out... */ -#define FORMAT_STRING \ - "%[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.] = " \ +#define FORMAT_STRING \ + "%1[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.] = " \ "(%d, %d, %d) " +/* +----------------------------------------------------------------------------- + Tile palette Feb 9, 2022 + + [0] . = (71, 108, 108) + [1] A = (0, 0, 0) grayshade maps to [1] itself + [2] B = (0, 182, 255) maps to [17] or Q for shade of gray + [3] C = (255, 108, 0) maps to [18] or R for shade of gray + [4] D = (255, 0, 0) maps to [19] or S for shade of gray + [5] E = (0, 0, 255) maps to [20] or T for shade of gray + [6] F = (0, 145, 0) maps to [27] or 0 for shade of gray + [7] G = (108, 255, 0) maps to [22] or V for shade of gray + [8] H = (255, 255, 0) maps to [23] or W for shade of gray + [9] I = (255, 0, 255) maps to [24] or X for shade of gray + [10] J = (145, 71, 0) maps to [25] or Y for shade of gray + [11] K = (204, 79, 0) maps to [26] or Z for shade of gray + [12] L = (255, 182, 145) maps to [21] or U for shade of gray + [13] M = (237, 237, 237) grayshade maps to [15] or O for shade of gray + [14] N = (255, 255, 255) grayshade maps to [13] or M for shade of gray + [15] O = (215, 215, 215) grayshade maps to [14] or N for shade of gray + [16] P = (108, 145, 182) maps to [14] or N for shade of gray + [17] Q = (18, 18, 18) grayshade maps to [1] or A for shade of gray + [18] R = (54, 54, 54) grayshade maps to [17] or Q for shade of gray + [19] S = (73, 73, 73) grayshade maps to [18] or R for shade of gray + [20] T = (82, 82, 82) grayshade maps to [19] or S for shade of gray + [21] U = (205,205,205) grayshade maps to [20] or T for shade of gray + [22] V = (104, 104, 104) grayshade maps to [27] or 0 for shade of gray + [23] W = (131, 131, 131) grayshade maps to [22] or V for shade of gray + [24] X = (140, 140, 140) grayshade maps to [23] or W for shade of gray + [25] Y = (149, 149, 149) grayshade maps to [24] or X for shade of gray + [26] Z = (195, 195, 195) grayshade maps to [25] or Y for shade of gray + [27] 0 = (100, 100, 100) grayshade maps to [20] or T for shade of gray + [28] 1 = (72, 108, 108) not mapped in graymappings +----------------------------------------------------------------------------- +*/ + static int grayscale = 0; /* grayscale color mapping */ static const int graymappings[] = { /* . A B C D E F G H I J K L M N O P */ - 0, 1, 17, 18, 19, 20, 27, 22, 23, 24, 25, 26, 21, 15, 13, 14, 14 + 0, 1, 17, 18, 19, 20, 27, 22, 23, 24, 25, 26, 21, 15, 13, 14, 14, + /* Q R S T U V W X Y Z 0 */ + 1, 17, 18, 19, 20, 27, 22, 23, 24, 25, 20 }; void -set_grayscale(g) -int g; +set_grayscale(int gs) { - grayscale = g; + grayscale = gs; +} + +/* read next line; repeat until it's a non-comment; populates 'inbuf[]'; + the buffer might already have data (first line after colormap) */ +static int +get_next_line(FILE *txtfile, boolean force) +{ + int ch; + + for (;;) { + if (force || !inbuf[0]) { + /* skip leading whitespace */ + do { + ch = fgetc(txtfile); + } while (ch == ' '); + ungetc(ch, txtfile); + /* get rest of line */ + if (!fgets(inbuf, BUFSZ, txtfile)) + break; + force = TRUE; + /* ignore blank lines; + the old fscanf() processing did that, possibly by accident */ + if (!inbuf[0] || (inbuf[0] == '\n' && !inbuf[1])) + continue; + } + if (inbuf[0] != '#' || !strncmp(inbuf, "# tile ", 7)) + return 1; + } + inbuf[0] = '\0'; + return 0; } static void -read_text_colormap(txtfile) -FILE *txtfile; +read_text_colormap(FILE *txtfile) { int i, r, g, b; char c[2]; @@ -63,7 +134,9 @@ FILE *txtfile; color_index[i] = -1; num_colors = 0; - while (fscanf(txtfile, FORMAT_STRING, c, &r, &g, &b) == 4) { + while (get_next_line(txtfile, TRUE)) { + if (sscanf(inbuf, FORMAT_STRING, c, &r, &g, &b) != 4) + break; color_index[(int) c[0]] = num_colors; ColorMap[CM_RED][num_colors] = r; ColorMap[CM_GREEN][num_colors] = g; @@ -76,8 +149,7 @@ FILE *txtfile; #undef FORMAT_STRING static boolean -write_text_colormap(txtfile) -FILE *txtfile; +write_text_colormap(FILE *txtfile) { int i; char c; @@ -103,114 +175,148 @@ FILE *txtfile; return TRUE; } +/* read one tile from win/share/{monsters,objects,other}.txt */ static boolean -read_txttile(txtfile, pixels) -FILE *txtfile; -pixel (*pixels)[TILE_X]; +read_txttile(FILE *txtfile, pixel (*pixels)[TILE_X]) { - int ph, i, j, k; - char buf[BUFSZ], ttype[BUFSZ]; + static int gidx = 0; + int ph, i = 0, j, k, reslt; + char buf[BUFSZ], ttype[BUFSZ], gend[BUFSZ]; const char *p; - char c[2]; + char *q; + boolean res = FALSE; + + gend[0] = '\0'; + reslt = 0; + if (get_next_line(txtfile, FALSE)) { + if (tile_set == MONSTER_SET) + reslt = sscanf(inbuf, "# %255s %d (%255[^,],%255[^)])", + ttype, &i, buf, gend); + else + reslt = sscanf(inbuf, "# %255s %d (%255[^)])", + ttype, &i, buf); + } + if (reslt <= 0) + goto done; - if (fscanf(txtfile, "# %s %d (%[^)])", ttype, &i, buf) <= 0) - return FALSE; + ttype[sizeof ttype - 1] = '\0'; + buf[sizeof buf - 1] = '\0'; + + if (tile_set == MONSTER_SET && gend[0] == 'f') + gidx = 1; ph = strcmp(ttype, "placeholder") == 0; if (!ph && strcmp(ttype, "tile") != 0) Fprintf(stderr, "Keyword \"%s\" unexpected for entry %d\n", ttype, i); - if (tile_set != 0) { - /* check tile name, but not relative number, which will - * change when tiles are added - */ - p = tilename(tile_set, tile_set_indx); - if (p && strcmp(p, buf) && !acceptable_tilename(tile_set_indx,buf,p)) { + /* check tile name, but not relative number, which will + * change when tiles are added + */ + p = tilename(tile_set, tile_set_indx, gidx); + if (p && (q = strstr(p, " {")) != 0) { + *q = '\0'; + } + if (p && strcmp(p, buf)) { + boolean other_mismatch = + (tile_set == OTHER_SET + && !acceptable_tilename(tile_set, tile_set_indx, buf, p)); + + if (tile_set != OTHER_SET || other_mismatch) { Fprintf(stderr, "warning: for tile %d (numbered %d) of %s,\n", - tile_set_indx, i, text_sets[tile_set - 1]); + tile_set_indx, i, text_sets[tile_set]); Fprintf(stderr, "\tfound '%s' while expecting '%s'\n", buf, p); } } tile_set_indx++; /* look for non-whitespace at each stage */ - if (fscanf(txtfile, "%1s", c) < 0) { + if (!get_next_line(txtfile, TRUE)) { Fprintf(stderr, "unexpected EOF\n"); - return FALSE; + goto done; } - if (c[0] != '{') { + if (inbuf[0] != '{') { Fprintf(stderr, "didn't find expected '{'\n"); - return FALSE; + goto done; } + for (j = 0; j < TILE_Y; j++) { + /* read next line of color indices */ + if (!get_next_line(txtfile, TRUE)) { + Fprintf(stderr, "unexpected EOF\n"); + goto done; + } + if ((q = strchr(inbuf, '\n')) == 0) + q = &inbuf[strlen(inbuf)]; /* eos(inbuf) */ + while (q < &inbuf[TILE_X]) + *q++ = '.'; + *q = '\0'; + for (i = 0; i < TILE_X; i++) { - if (fscanf(txtfile, "%1s", c) < 0) { - Fprintf(stderr, "unexpected EOF\n"); - return FALSE; - } - k = color_index[(int) c[0]]; - if (grayscale) { + k = color_index[(unsigned char) inbuf[i]]; + if (grayscale && k >= 0) { if (k > (SIZE(graymappings) - 1)) Fprintf(stderr, "Gray mapping issue %d > %d.\n", k, SIZE(graymappings) - 1); else k = graymappings[k]; } - if (k == -1) - Fprintf(stderr, "color %c not in colormap!\n", c[0]); - else { + if (k == -1) { + Fprintf(stderr, "color %c not in colormap!\n", inbuf[i]); + } else if (k >= 0 && k < MAXCOLORMAPSIZE) { pixels[j][i].r = ColorMap[CM_RED][k]; pixels[j][i].g = ColorMap[CM_GREEN][k]; pixels[j][i].b = ColorMap[CM_BLUE][k]; + } else { + Fprintf(stderr, + "%d exceeds array boundary for ColorMap[][%d]!\n", + k, MAXCOLORMAPSIZE); } } } if (ph) { /* remember it for later */ - memcpy(placeholder, pixels, sizeof(placeholder)); + memcpy(placeholder, pixels, sizeof placeholder); } - if (fscanf(txtfile, "%1s ", c) < 0) { + if (!get_next_line(txtfile, TRUE)) { Fprintf(stderr, "unexpected EOF\n"); - return FALSE; + goto done; } - if (c[0] != '}') { + if (inbuf[0] != '}') { Fprintf(stderr, "didn't find expected '}'\n"); - return FALSE; + goto done; } -#ifdef _DCC - /* DICE again... it doesn't seem to eat whitespace after the } like - * it should, so we have to do so manually. - */ - while ((*c = fgetc(txtfile)) != EOF && isspace((uchar) *c)) - ; - ungetc(*c, txtfile); -#endif - return TRUE; + res = TRUE; + done: + inbuf[0] = '\0'; + return res; } static void -write_txttile(txtfile, pixels) -FILE *txtfile; -pixel (*pixels)[TILE_X]; +write_txttile(FILE *txtfile, pixel (*pixels)[TILE_X]) { const char *p; const char *type; - int i, j, k; + int i = 0, j, k; if (memcmp(placeholder, pixels, sizeof(placeholder)) == 0) type = "placeholder"; else type = "tile"; - if (tile_set == 0) - Fprintf(txtfile, "# %s %d (unknown)\n", type, tile_set_indx); - else { - p = tilename(tile_set, tile_set_indx); - if (p) - Fprintf(txtfile, "# %s %d (%s)\n", type, tile_set_indx, p); - else - Fprintf(txtfile, "# %s %d (null)\n", type, tile_set_indx); + if (tile_set == MONSTER_SET) { + for (i = 0; i < 2; ++i) { + Fprintf(txtfile, "# %s %d (unknown,%s)\n", type, tile_set_indx, + i ? "female" : "male"); + if (i == 0) + tile_set_indx++; + } + } else { + p = tilename(tile_set, tile_set_indx, i); + if (p) + Fprintf(txtfile, "# %s %d (%s)\n", type, tile_set_indx, p); + else + Fprintf(txtfile, "# %s %d (null)\n", type, tile_set_indx); } tile_set_indx++; @@ -235,7 +341,7 @@ pixel (*pixels)[TILE_X]; /* initialize main colormap from globally accessed ColorMap */ void -init_colormap() +init_colormap(void) { int i; @@ -249,7 +355,7 @@ init_colormap() /* merge new colors from ColorMap into MainColorMap */ void -merge_colormap() +merge_colormap(void) { int i, j; @@ -275,15 +381,13 @@ merge_colormap() } boolean -fopen_text_file(filename, type) -const char *filename; -const char *type; +fopen_text_file(const char *filename, const char *type) { const char *p; int i; if (tile_file != (FILE *) 0) { - Fprintf(stderr, "can only open one text file at at time\n"); + Fprintf(stderr, "can only open one text file at a time\n"); return FALSE; } @@ -293,7 +397,7 @@ const char *type; return FALSE; } - p = rindex(filename, '/'); + p = strrchr(filename, '/'); if (p) p++; else @@ -302,7 +406,7 @@ const char *type; tile_set = 0; for (i = 0; i < SIZE(text_sets); i++) { if (!strcmp(p, text_sets[i])) - tile_set = i + 1; + tile_set = i; } tile_set_indx = 0; @@ -333,22 +437,20 @@ const char *type; } boolean -read_text_tile(pixels) -pixel (*pixels)[TILE_X]; +read_text_tile(pixel (*pixels)[TILE_X]) { - return (read_txttile(tile_file, pixels)); + return read_txttile(tile_file, pixels); } boolean -write_text_tile(pixels) -pixel (*pixels)[TILE_X]; +write_text_tile(pixel (*pixels)[TILE_X]) { write_txttile(tile_file, pixels); return TRUE; } int -fclose_text_file() +fclose_text_file(void) { int ret; diff --git a/win/shim/winshim.c b/win/shim/winshim.c new file mode 100644 index 000000000..a18534d35 --- /dev/null +++ b/win/shim/winshim.c @@ -0,0 +1,325 @@ +/* NetHack 5.0 winshim.c $NHDT-Date: 1596498345 2020/08/03 23:45:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.259 $ */ +/* Copyright (c) Adam Powers, 2020 */ +/* NetHack may be freely redistributed. See license for details. */ + +/* not an actual windowing port, but a fake win port for libnethack */ + +#include "hack.h" +#include + +#ifdef SHIM_GRAPHICS +#include +/* for cross-compiling to WebAssembly (WASM) */ +#ifdef __EMSCRIPTEN__ +#include +#endif + +#undef SHIM_DEBUG + +#ifdef SHIM_DEBUG +#define debugf printf +#else /* !SHIM_DEBUG */ +#define debugf(...) +#endif /* SHIM_DEBUG */ + + +/* shim_graphics_callback is the primary interface to shim graphics, + * call this function with your declared callback function + * and you will receive all the windowing calls + */ +#ifdef __EMSCRIPTEN__ +/************ + * WASM interface + ************/ +EMSCRIPTEN_KEEPALIVE +static char *shim_callback_name = NULL; +void shim_graphics_set_callback(char *cbName); + +void shim_graphics_set_callback(char *cbName) { + if (shim_callback_name != NULL) free(shim_callback_name); + if(cbName && strlen(cbName) > 0) { + debugf("setting shim_callback_name: %s\n", cbName); + shim_callback_name = strdup(cbName); + } else { + debugf("un-setting shim_callback_name\n"); + shim_callback_name = NULL; + } + /* TODO: free(shim_callback_name) during shutdown? */ +} +void local_callback (const char *cb_name, const char *shim_name, void *ret_ptr, const char *fmt_str, void *args); + +/* A2P = Argument to Pointer */ +#define A2P & +/* P2V = Pointer to Void */ +#define P2V (void *) +#define DECLCB(ret_type, name, fn_args, fmt, ...) \ +ret_type name fn_args; \ +\ +ret_type name fn_args { \ + void *args[] = { __VA_ARGS__ }; \ + ret_type ret = (ret_type) 0; \ + debugf("SHIM GRAPHICS: " #name "\n"); \ + if (!shim_callback_name) return ret; \ + local_callback(shim_callback_name, #name, (void *)&ret, fmt, args); \ + debugf("SHIM GRAPHICS: " #name " done.\n"); \ + return ret; \ +} + +#define VDECLCB(name, fn_args, fmt, ...) \ +void name fn_args; \ +\ +void name fn_args { \ + void *args[] = { __VA_ARGS__ }; \ + debugf("SHIM GRAPHICS: " #name "\n"); \ + if (!shim_callback_name) return; \ + local_callback(shim_callback_name, #name, NULL, fmt, args); \ + debugf("SHIM GRAPHICS: " #name " done.\n"); \ +} + +#else /* !__EMSCRIPTEN__ */ + +/************ + * libnethack.a interface + ************/ +typedef void(*shim_callback_t)(const char *name, void *ret_ptr, const char *fmt, ...); +static shim_callback_t shim_graphics_callback = NULL; +void shim_graphics_set_callback(shim_callback_t cb); + +void shim_graphics_set_callback(shim_callback_t cb) { + shim_graphics_callback = cb; +} + +#define A2P +#define P2V +#define DECLCB(ret_type, name, fn_args, fmt, ...) \ +ret_type name fn_args;\ +\ +ret_type name fn_args { \ + ret_type ret = (ret_type) 0; \ + debugf("SHIM GRAPHICS: " #name "\n"); \ + if (!shim_graphics_callback) return ret; \ + shim_graphics_callback(#name, (void *)&ret, fmt, ## __VA_ARGS__); \ + debugf("SHIM GRAPHICS: " #name " done.\n"); \ + return ret; \ +} + +#define VDECLCB(name, fn_args, fmt, ...) \ +void name fn_args;\ +\ +void name fn_args { \ + debugf("SHIM GRAPHICS: " #name "\n"); \ + if (!shim_graphics_callback) return; \ + shim_graphics_callback(#name, NULL, fmt, ## __VA_ARGS__); \ + debugf("SHIM GRAPHICS: " #name " done.\n"); \ +} +#endif /* __EMSCRIPTEN__ */ + +VDECLCB(shim_init_nhwindows,(int *argcp, char **argv), "vpp", P2V argcp, P2V argv) +DECLCB(boolean, shim_player_selection_or_tty,(void), "b") +VDECLCB(shim_askname,(void), "v") +VDECLCB(shim_get_nh_event,(void), "v") +VDECLCB(shim_exit_nhwindows,(const char *str), "vs", P2V str) +VDECLCB(shim_suspend_nhwindows,(const char *str), "vs", P2V str) +VDECLCB(shim_resume_nhwindows,(void), "v") +DECLCB(winid, shim_create_nhwindow, (int type), "ii", A2P type) +VDECLCB(shim_clear_nhwindow,(winid window), "vi", A2P window) +VDECLCB(shim_display_nhwindow,(winid window, boolean blocking), "vib", A2P window, A2P blocking) +VDECLCB(shim_destroy_nhwindow,(winid window), "vi", A2P window) +VDECLCB(shim_curs,(winid a, int x, int y), "viii", A2P a, A2P x, A2P y) +VDECLCB(shim_putstr,(winid w, int attr, const char *str), "viis", A2P w, A2P attr, P2V str) +VDECLCB(shim_display_file,(const char *name, boolean complain), "vsb", P2V name, A2P complain) +VDECLCB(shim_start_menu,(winid window, unsigned long mbehavior), "vii", A2P window, A2P mbehavior) +VDECLCB(shim_add_menu, + (winid window, const glyph_info *glyphinfo, const ANY_P *identifier, char ch, char gch, int attr, int clr, const char *str, unsigned int itemflags), + "vipi00iisi", + A2P window, P2V glyphinfo, P2V identifier, A2P ch, A2P gch, A2P attr, A2P clr, P2V str, A2P itemflags) +VDECLCB(shim_end_menu,(winid window, const char *prompt), "vis", A2P window, P2V prompt) +/* XXX: shim_select_menu menu_list is an output */ +DECLCB(int, shim_select_menu,(winid window, int how, MENU_ITEM_P **menu_list), "iiip", A2P window, A2P how, P2V menu_list) +DECLCB(char, shim_message_menu,(char let, int how, const char *mesg), "ciis", A2P let, A2P how, P2V mesg) +VDECLCB(shim_mark_synch,(void), "v") +VDECLCB(shim_wait_synch,(void), "v") +VDECLCB(shim_cliparound,(int x, int y), "vii", A2P x, A2P y) +VDECLCB(shim_update_positionbar,(char *posbar), "vs", P2V posbar) +VDECLCB(shim_print_glyph,(winid w, coordxy x, coordxy y, const glyph_info *glyphinfo, const glyph_info *bkglyphinfo), "vi11pp", A2P w, A2P x, A2P y, P2V glyphinfo, P2V bkglyphinfo) +VDECLCB(shim_raw_print,(const char *str), "vs", P2V str) +VDECLCB(shim_raw_print_bold,(const char *str), "vs", P2V str) +DECLCB(int, shim_nhgetch,(void), "i") +DECLCB(int, shim_nh_poskey,(coordxy *x, coordxy *y, int *mod), "ippp", P2V x, P2V y, P2V mod) +VDECLCB(shim_nhbell,(void), "v") +DECLCB(int, shim_doprev_message,(void),"iv") +DECLCB(char, shim_yn_function,(const char *query, const char *resp, char def), "css0", P2V query, P2V resp, A2P def) +VDECLCB(shim_getlin,(const char *query, char *bufp), "vsp", P2V query, P2V bufp) +DECLCB(int,shim_get_ext_cmd,(void),"iv") +VDECLCB(shim_number_pad,(int state), "vi", A2P state) +VDECLCB(shim_delay_output,(void), "v") +VDECLCB(shim_change_color,(int color, long rgb, int reverse), "viii", A2P color, A2P rgb, A2P reverse) +VDECLCB(shim_change_background,(int white_or_black), "vi", A2P white_or_black) +DECLCB(short, set_shim_font_name,(winid window_type, char *font_name),"2is", A2P window_type, P2V font_name) +DECLCB(char *,shim_get_color_string,(void),"sv") + +VDECLCB(shim_preference_update, (const char *pref), "vp", P2V pref) +DECLCB(char *,shim_getmsghistory, (boolean init), "sb", A2P init) +VDECLCB(shim_putmsghistory, (const char *msg, boolean restoring_msghist), "vsb", P2V msg, A2P restoring_msghist) +VDECLCB(shim_status_init, (void), "v") +VDECLCB(shim_status_enablefield, + (int fieldidx, const char *nm, const char *fmt, boolean enable), + "vippb", + A2P fieldidx, P2V nm, P2V fmt, A2P enable) +/* XXX: the second argument to shim_status_update is sometimes an integer and sometimes a pointer */ +VDECLCB(shim_status_update, + (int fldidx, genericptr_t ptr, int chg, int percent, int color, unsigned long *colormasks), + "vipiiip", + A2P fldidx, P2V ptr, A2P chg, A2P percent, A2P color, P2V colormasks) +#ifdef __EMSCRIPTEN__ +/* XXX: calling repopulate_perminvent() from shim_update_inventory() causes reentrancy that breaks emscripten Asyncify */ +/* this should be fine since according to windows.doc, the only purpose of shim_update_inventory() is to call repopulate_perminvent() */ +void shim_update_inventory(int a1 UNUSED) { + if(iflags.perm_invent) { + repopulate_perminvent(); + } +} + +void shim_player_selection() { + boolean do_genl_player_setup = shim_player_selection_or_tty(); + if (do_genl_player_setup) { + genl_player_setup(80); + } +} + +win_request_info * +shim_ctrl_nhwindow( + winid window UNUSED, + int request UNUSED, + win_request_info *wri UNUSED) { + return (win_request_info *) 0; +} +#else /* !__EMSCRIPTEN__ */ +VDECLCB(shim_player_selection, (void), "v") +VDECLCB(shim_update_inventory,(int a1 UNUSED), "vi", A2P a1) +DECLCB(win_request_info *, shim_ctrl_nhwindow, + (winid window, int request, win_request_info *wri), + "viip", + A2P window, A2P request, P2V wri) +#endif + +/* Interface definition used in windows.c */ +struct window_procs shim_procs = { + WPID(shim), + (0 + | WC_ASCII_MAP + | WC_MOUSE_SUPPORT + | WC_COLOR | WC_HILITE_PET | WC_INVERSE | WC_EIGHT_BIT_IN), + (0 +#if defined(SELECTSAVED) + | WC2_SELECTSAVED +#endif +#if defined(STATUS_HILITES) + | WC2_HILITE_STATUS | WC2_HITPOINTBAR | WC2_FLUSH_STATUS + | WC2_RESET_STATUS +#endif + | WC2_DARKGRAY | WC2_SUPPRESS_HIST | WC2_STATUSLINES), + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ + shim_init_nhwindows, shim_player_selection, shim_askname, shim_get_nh_event, + shim_exit_nhwindows, shim_suspend_nhwindows, shim_resume_nhwindows, + shim_create_nhwindow, shim_clear_nhwindow, shim_display_nhwindow, + shim_destroy_nhwindow, shim_curs, shim_putstr, genl_putmixed, + shim_display_file, shim_start_menu, shim_add_menu, shim_end_menu, + shim_select_menu, shim_message_menu, shim_mark_synch, + shim_wait_synch, +#ifdef CLIPPING + shim_cliparound, +#endif +#ifdef POSITIONBAR + shim_update_positionbar, +#endif + shim_print_glyph, shim_raw_print, shim_raw_print_bold, shim_nhgetch, + shim_nh_poskey, shim_nhbell, shim_doprev_message, shim_yn_function, + shim_getlin, shim_get_ext_cmd, shim_number_pad, shim_delay_output, +#ifdef CHANGE_COLOR /* the Mac uses a palette device */ + shim_change_color, +#ifdef MAC + shim_change_background, set_shim_font_name, +#endif + shim_get_color_string, +#endif + + genl_outrip, + shim_preference_update, + shim_getmsghistory, shim_putmsghistory, + shim_status_init, + genl_status_finish, genl_status_enablefield, +#ifdef STATUS_HILITES + shim_status_update, +#else + genl_status_update, +#endif + genl_can_suspend_yes, + shim_update_inventory, + shim_ctrl_nhwindow, +}; + +#ifdef __EMSCRIPTEN__ +/* convert the C callback to a JavaScript callback */ +EM_JS(void, local_callback, (const char *cb_name, const char *shim_name, void *ret_ptr, const char *fmt_str, void *args), { + // Asyncify.handleAsync() is the more logical choice here; however, the stack unrolling in Asyncify is performed by + // function call analysis during compilation. Since we are using an indirect callback (cb_name), it can't predict the stack + // unrolling and it crashes. Thus we use Asyncify.handleSleep() and wakeUp() to make sure that async doesn't break + // Asyncify. For details, see: https://emscripten.org/docs/porting/asyncify.html#optimizing + Asyncify.handleSleep(wakeUp => { + // convert callback arguments to proper JavaScript variadic arguments + let name = UTF8ToString(shim_name); + let fmt = UTF8ToString(fmt_str); + let cbName = UTF8ToString(cb_name); + // console.log("local_callback:", cbName, fmt, name); + + // get pointer / type conversion helpers + let getPointerValue = globalThis.nethackGlobal.helpers.getPointerValue; + let setPointerValue = globalThis.nethackGlobal.helpers.setPointerValue; + + reentryMutexLock(name); + + let argTypes = fmt.split(""); + let retType = argTypes.shift(); + + // build array of JavaScript args from WASM parameters + let jsArgs = []; + for (let i = 0; i < argTypes.length; i++) { + let ptr = args + (4*i); + let val = getArg(name, ptr, argTypes[i]); + jsArgs.push(val); + } + + // do the callback + let userCallback = globalThis[cbName]; + userCallback.call(this, name, ... jsArgs).then((retVal) => { + // save the return value + setPointerValue(name, ret_ptr, retType, retVal); + reentryMutexUnlock(); + try { + wakeUp(); + } catch (e) { + + } + }); + + function getArg(name, ptr, type) { + return (type === "p") ? getValue(ptr, "*") : getPointerValue(name, getValue(ptr, "*"), type); + } + + function reentryMutexLock(name) { + globalThis.nethackGlobal = globalThis.nethackGlobal || {}; + if(globalThis.nethackGlobal.shimFunctionRunning) { + console.error(`'${name}' attempting second call to 'local_callback' before '${globalThis.nethackGlobal.shimFunctionRunning}' has finished, will crash emscripten Asyncify. For details see: emscripten.org/docs/porting/asyncify.html#reentrancy`); + } + globalThis.nethackGlobal.shimFunctionRunning = name; + } + + function reentryMutexUnlock() { + globalThis.nethackGlobal.shimFunctionRunning = null; + } + }); +}) +#endif /* __EMSCRIPTEN__ */ + +#endif /* SHIM_GRAPHICS */ diff --git a/win/tty/getline.c b/win/tty/getline.c index b6a0b9af0..0cd1a4605 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -1,14 +1,13 @@ -/* NetHack 3.6 getline.c $NHDT-Date: 1543830347 2018/12/03 09:45:47 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.37 $ */ +/* NetHack 5.0 getline.c $NHDT-Date: 1701285885 2023/11/29 19:24:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.59 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ -/* Copyright (c) Michael Allison, 2006. */ -/* Copyright (c) Facebook, Inc. and its affiliates. */ +/*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef TTY_GRAPHICS -#if !defined(MAC) +#if !defined(MACOS9) #define NEWAUTOCOMP #endif @@ -16,51 +15,57 @@ #include "func_tab.h" char morc = 0; /* tell the outside world what char you chose */ -STATIC_VAR boolean suppress_history; -STATIC_DCL boolean FDECL(ext_cmd_getlin_hook, (char *)); +static boolean suppress_history; +static boolean ext_cmd_getlin_hook(char *); -typedef boolean FDECL((*getlin_hook_proc), (char *)); +typedef boolean (*getlin_hook_proc)(char *); -STATIC_DCL void FDECL(hooked_tty_getlin, - (const char *, char *, getlin_hook_proc)); -extern int NDECL(extcmd_via_menu); /* cmd.c */ +static void hooked_tty_getlin(const char *, char *, getlin_hook_proc); +extern int extcmd_via_menu(void); /* cmd.c */ extern char erase_char, kill_char; /* from appropriate tty.c file */ /* * Read a line closed with '\n' into the array char bufp[BUFSZ]. * (The '\n' is not stored. The string is closed with a '\0'.) - * Reading can be interrupted by an escape ('\033') - now the - * resulting string is "\033". + * Reading can be interrupted by an escape ('\033'). If there is already + * some text, it is removed and prompting continues as if from the start. + * However, if there is no text yet (or anymore) then "\033" is returned. */ void -tty_getlin(query, bufp) -const char *query; -register char *bufp; +tty_getlin(const char *query, char *bufp) { suppress_history = FALSE; hooked_tty_getlin(query, bufp, (getlin_hook_proc) 0); } -STATIC_OVL void -hooked_tty_getlin(query, bufp, hook) -const char *query; -register char *bufp; -getlin_hook_proc hook; +static void +hooked_tty_getlin( + const char *query, + char *bufp, + getlin_hook_proc hook) { - register char *obufp = bufp; - register int c; + char *obufp = bufp; + int c; struct WinDesc *cw = wins[WIN_MESSAGE]; - boolean doprev = 0; + boolean doprev = FALSE; - if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) + if (ttyDisplay->toplin == TOPLINE_NEED_MORE && !(cw->flags & WIN_STOP)) more(); cw->flags &= ~WIN_STOP; - ttyDisplay->toplin = 3; /* special prompt state */ + ttyDisplay->toplin = TOPLINE_SPECIAL_PROMPT; ttyDisplay->inread++; - /* issue the prompt */ + /* + * Issue the prompt. + * + * custompline() will call vpline() which calls flush_screen() which + * calls bot(). The core now disables bot() processing while inside + * getlin, so the screen won't be modified during whatever this prompt + * is for. + */ custompline(OVERRIDE_MSGTYPE | SUPPRESS_HISTORY, "%s ", query); + #ifdef EDIT_GETLIN /* bufp is input/output; treat current contents (presumed to be from previous getlin()) as default input */ @@ -73,9 +78,13 @@ getlin_hook_proc hook; for (;;) { (void) fflush(stdout); - Strcat(strcat(strcpy(toplines, query), " "), obufp); + Strcat(strcat(strcpy(gt.toplines, query), " "), obufp); + term_curs_set(1); c = pgetchar(); + term_curs_set(0); if (c == '\033' || c == EOF) { + if (c == EOF) + iflags.term_gone = 1; if (c == '\033' && obufp[0] != '\0') { obufp[0] = '\0'; bufp = obufp; @@ -94,30 +103,37 @@ getlin_hook_proc hook; ttyDisplay->intr--; *bufp = 0; } - if (c == '\020') { /* ctrl-P */ - if (iflags.prevmsg_window != 's') { - int sav = ttyDisplay->inread; - - ttyDisplay->inread = 0; + if (c == C('p')) { /* ctrl-P, doesn't honor rebinding #prevmsg cmd */ + int sav = ttyDisplay->inread; + + ttyDisplay->inread = 0; + if (iflags.prevmsg_window == 's' + || (iflags.prevmsg_window == 'c' && !doprev)) { + /* msg_window:single, or msg_window:combination while it's + behaving like msg_window:single */ + if (!doprev) + (void) tty_doprev_message(); /* need two initially */ + (void) tty_doprev_message(); + ttyDisplay->inread = sav; + doprev = TRUE; + continue; + } else { + /* msg_window:full or reverse, or msg_window:combination while + it's behaving like msg_window:full */ (void) tty_doprev_message(); ttyDisplay->inread = sav; + doprev = FALSE; tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; addtopl(query); addtopl(" "); *bufp = 0; addtopl(obufp); - } else { - if (!doprev) - (void) tty_doprev_message(); /* need two initially */ - (void) tty_doprev_message(); - doprev = 1; - continue; } - } else if (doprev && iflags.prevmsg_window == 's') { + } else if (doprev) { tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; - doprev = 0; + doprev = FALSE; addtopl(query); addtopl(" "); *bufp = 0; @@ -194,32 +210,31 @@ getlin_hook_proc hook; } else tty_nhbell(); } - ttyDisplay->toplin = 2; /* nonempty, no --More-- required */ + ttyDisplay->toplin = TOPLINE_NON_EMPTY; ttyDisplay->inread--; clear_nhwindow(WIN_MESSAGE); /* clean up after ourselves */ if (suppress_history) { /* prevent next message from pushing current query+answer into tty message history */ - *toplines = '\0'; -#ifdef DUMPLOG + *gt.toplines = '\0'; +#ifdef DUMPLOG_CORE } else { /* needed because we've bypassed pline() */ - dumplogmsg(toplines); + dumplogmsg(gt.toplines); #endif } } /* - * Hack for RL window proc: register if we are in xwaitforspace context. + * NLE: Hack for RL window proc: register if we are in xwaitforspace context. */ boolean xwaitingforspace; void -xwaitforspace(s) -register const char *s; /* chars allowed besides return */ +xwaitforspace(const char *s) /* chars allowed besides return */ { - register int c, x = ttyDisplay ? (int) ttyDisplay->dismiss_more : '\n'; + int c, x = ttyDisplay ? (int) ttyDisplay->dismiss_more : '\n'; xwaitingforspace = TRUE; morc = 0; @@ -227,6 +242,7 @@ register const char *s; /* chars allowed besides return */ #ifdef HANGUPHANDLING !program_state.done_hup && #endif + /* NLE: use NetHack function here */ (c = nhgetch()) != EOF) { if (c == '\n' || c == '\r') break; @@ -238,13 +254,14 @@ register const char *s; /* chars allowed besides return */ morc = '\033'; break; } - if ((s && index(s, c)) || c == x || (x == '\n' && c == '\r')) { + if ((s && strchr(s, c)) || c == x || (x == '\n' && c == '\r')) { morc = (char) c; break; } tty_nhbell(); } } + /* NLE: reset xwaitingforspace flag */ xwaitingforspace = FALSE; } @@ -257,30 +274,19 @@ register const char *s; /* chars allowed besides return */ * Return TRUE if we've extended the string at base. Otherwise return FALSE. * Assumptions: * - * + we don't change the characters that are already in base - * + base has enough room to hold our string + * + we don't change the characters that are already in base + * + base has enough room to hold our string */ -STATIC_OVL boolean -ext_cmd_getlin_hook(base) -char *base; +static boolean +ext_cmd_getlin_hook(char *base) { - int oindex, com_index; - - com_index = -1; - for (oindex = 0; extcmdlist[oindex].ef_txt != (char *) 0; oindex++) { - if (extcmdlist[oindex].flags & CMD_NOT_AVAILABLE) - continue; - if ((extcmdlist[oindex].flags & AUTOCOMPLETE) - && !(!wizard && (extcmdlist[oindex].flags & WIZMODECMD)) - && !strncmpi(base, extcmdlist[oindex].ef_txt, strlen(base))) { - if (com_index == -1) /* no matches yet */ - com_index = oindex; - else /* more than 1 match */ - return FALSE; - } - } - if (com_index >= 0) { - Strcpy(base, extcmdlist[com_index].ef_txt); + int *ecmatches; + int nmatches = extcmds_match(base, ECM_NOFLAGS, &ecmatches); + + if (nmatches == 1) { + struct ext_func_tab *ec = extcmds_getentry(ecmatches[0]); + + Strcpy(base, ec->ef_txt); return TRUE; } @@ -292,10 +298,13 @@ char *base; * stop when we have found enough characters to make a unique command. */ int -tty_get_ext_cmd() +tty_get_ext_cmd(void) { - int i; char buf[BUFSZ]; + int nmatches; + int *ecmatches = 0; + boolean (*no_hook)(char *base) = (boolean (*)(char *)) 0; + char extcmd_char[2]; if (iflags.extmenu) return extcmd_via_menu(); @@ -303,34 +312,26 @@ tty_get_ext_cmd() suppress_history = TRUE; /* maybe a runtime option? * hooked_tty_getlin("#", buf, - * (flags.cmd_comp && !in_doagain) + * (flags.cmd_comp && !gi.in_doagain) * ? ext_cmd_getlin_hook * : (getlin_hook_proc) 0); */ + extcmd_char[0] = extcmd_initiator(), extcmd_char[1] = '\0'; buf[0] = '\0'; - hooked_tty_getlin("#", buf, in_doagain ? (getlin_hook_proc) 0 - : ext_cmd_getlin_hook); + hooked_tty_getlin(extcmd_char, buf, + !gi.in_doagain ? ext_cmd_getlin_hook : no_hook); (void) mungspaces(buf); - if (buf[0] == 0 || buf[0] == '\033') - return -1; - - for (i = 0; extcmdlist[i].ef_txt != (char *) 0; i++) - if (!strcmpi(buf, extcmdlist[i].ef_txt)) - break; - if (!in_doagain) { - int j; - for (j = 0; buf[j]; j++) - savech(buf[j]); - savech('\n'); - } - - if (extcmdlist[i].ef_txt == (char *) 0) { - pline("%s: unknown extended command.", buf); - i = -1; + nmatches = (buf[0] == '\0' || buf[0] == '\033') ? -1 + : extcmds_match(buf, ECM_IGNOREAC | ECM_EXACTMATCH, &ecmatches); + if (nmatches != 1) { + if (nmatches != -1) + pline("%s%.60s: unknown extended command.", + visctrl(extcmd_char[0]), buf); + return -1; } - return i; + return ecmatches[0]; } #endif /* TTY_GRAPHICS */ diff --git a/win/tty/termcap.c b/win/tty/termcap.c index f325a689a..fb5397438 100644 --- a/win/tty/termcap.c +++ b/win/tty/termcap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 termcap.c $NHDT-Date: 1609454952 2020/12/31 22:49:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.40 $ */ +/* NetHack 5.0 termcap.c $NHDT-Date: 1701946349 2023/12/07 10:52:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.60 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -7,93 +7,101 @@ #if defined(TTY_GRAPHICS) && !defined(NO_TERMS) +/* leave this undefined; it produces bad screen output with rxvt-unicode */ +/*#define DECgraphicsOptimization*/ + #include "wintty.h" #include "tcap.h" -#ifdef MICROPORT_286_BUG -#define Tgetstr(key) (tgetstr(key, tbuf)) -#else /* MICROPORT_286_BUG */ #define Tgetstr(key) (tgetstr(key, &tbufptr)) -#endif /* MICROPORT_286_BUG **/ -static char *FDECL(s_atr2str, (int)); -static char *FDECL(e_atr2str, (int)); +static char *s_atr2str(int); +static char *e_atr2str(int); + +void cmov(int, int); +void nocmov(int, int); +void term_start_extracolor(uint32, uint16); +void term_end_extracolor(void); -void FDECL(cmov, (int, int)); -void FDECL(nocmov, (int, int)); -#if defined(TEXTCOLOR) && defined(TERMLIB) +#if defined(TERMLIB) #if (!defined(UNIX) || !defined(TERMINFO)) && !defined(TOS) -static void FDECL(analyze_seq, (char *, int *, int *)); +static void analyze_seq(char *, int *, int *); +#endif #endif +#if (defined(TERMLIB) || defined(ANSI_DEFAULT)) +static void init_hilite(void); +static void kill_hilite(void); #endif -#if defined(TEXTCOLOR) && (defined(TERMLIB) || defined(ANSI_DEFAULT)) -static void NDECL(init_hilite); -static void NDECL(kill_hilite); -#endif /* defined(TEXTCOLOR) && defined(TERMLIB) */ /* (see tcap.h) -- nh_CM, nh_ND, nh_CD, nh_HI,nh_HE, nh_US,nh_UE, ul_hack */ struct tc_lcl_data tc_lcl_data = { 0, 0, 0, 0, 0, 0, 0, FALSE }; -STATIC_VAR char *HO, *CL, *CE, *UP, *XD, *BC, *SO, *SE, *TI, *TE; -STATIC_VAR char *VS, *VE; -STATIC_VAR char *ME, *MR, *MB, *MH, *MD; +static char *nh_VI = (char *) 0; /* cursor_invisible */ +static char *nh_VE = (char *) 0; /* cursor_normal */ +/*static char *nh_VS = (char *) 0;*/ /* cursor_visible (highlighted cursor) */ +static char *nh_Ic = (char *) 0; /* initialize_color */ + +static char *HO, *CL, *CE, *UP, *XD, *BC, *SO, *SE, *TI, *TE; +static char *VS, *VE; +static char *ME, *MR, *MB, *MH, *MD; +static char *ZH, *ZR; #ifdef TERMLIB boolean dynamic_HIHE = FALSE; -STATIC_VAR int SG; -STATIC_OVL char PC = '\0'; -STATIC_VAR char tbuf[512]; +static int SG; +static char PC = '\0'; +static char tbuf[512]; #endif /*TERMLIB*/ -#ifdef TEXTCOLOR #ifdef TOS const char *hilites[CLR_MAX]; /* terminal escapes for the various colors */ -#else /* TOS */ +#else char NEARDATA *hilites[CLR_MAX]; /* terminal escapes for the various colors */ -#endif /* TOS */ -#endif /* TEXTCOLOR */ +#endif static char *KS = (char *) 0, *KE = (char *) 0; /* keypad sequences */ static char nullstr[] = ""; #if defined(ASCIIGRAPH) && !defined(NO_TERMS) extern boolean HE_resets_AS; -#endif /* defined(ASCIIGRAPH) && !defined(NO_TERMS) */ +#endif #ifndef TERMLIB -STATIC_VAR char tgotobuf[20]; +static char tgotobuf[20]; #ifdef TOS #define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y + ' ', x + ' '), tgotobuf) -#else /* TOS */ +#else #define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y + 1, x + 1), tgotobuf) -#endif /* TOS */ +#endif #endif /* TERMLIB */ +/* these don't need to be part of 'struct instance_globals g' */ +static char tty_standout_on[16], tty_standout_off[16]; + void -tty_startup(wid, hgt) -int *wid, *hgt; +term_startup(int *wid, int *hgt) { #ifdef TERMLIB - register const char *term; - register char *tptr; + const char *term; + char *tptr; char *tbufptr, *pc; int i; #ifdef VMS term = verify_termcap(); if (!term) -#endif /* VMS */ +#endif term = getenv("TERM"); #if defined(TOS) && defined(__GNUC__) if (!term) term = "builtin"; /* library has a default */ -#endif /* defined(TOS) && defined(__GNUC__) */ +#endif if (!term) #endif /* TERMLIB */ #ifndef ANSI_DEFAULT error("Can't get TERM."); -#else /* ANSI_DEFAULT */ +#else #ifdef TOS { CO = 80; @@ -158,9 +166,7 @@ int *wid, *hgt; AE = nhStr("\017"); #endif TE = VS = VE = nullstr; -#ifdef TEXTCOLOR init_hilite(); -#endif /* TEXTCOLOR */ *wid = CO; *hgt = LI; CL = nhStr("\033[2J"); /* last thing set */ @@ -170,6 +176,8 @@ int *wid, *hgt; #endif /* ANSI_DEFAULT */ #ifdef TERMLIB + tptr = (char *) alloc(1024); + tbufptr = tbuf; if (!strncmp(term, "5620", 4)) flags.null = FALSE; /* this should be a termcap flag */ @@ -178,31 +186,44 @@ int *wid, *hgt; * NLE: Removed call to tgetent: nlecl.c calls tgetent once on startup. * The call leaks if we dlclose libnethack, which dlcloses ncurses as well. */ - if ((pc = Tgetstr("pc")) != 0) { + /* + if (tgetent(tptr, term) < 1) { + char buf[BUFSZ]; + (void) strncpy(buf, term, + (BUFSZ - 1) - (sizeof("Unknown terminal type: . "))); + buf[BUFSZ - 1] = '\0'; + error("Unknown terminal type: %s.", term); + } + + if ((pc = Tgetstr(nhStr("pc"))) != 0) + PC = *pc; + */ + if ((pc = Tgetstr(nhStr("pc"))) != 0) { PC = *pc; free(pc); } - if (!(BC = Tgetstr("le"))) /* both termcap and terminfo use le */ + if (!(BC = Tgetstr(nhStr("le")))) { /* both termcap and terminfo use le */ #ifdef TERMINFO error("Terminal must backspace."); -#else /* TERMINFO */ - if (!(BC = Tgetstr("bc"))) { /* termcap also uses bc/bs */ +#else + if (!(BC = Tgetstr(nhStr("bc")))) { /* termcap also uses bc/bs */ #ifndef MINIMAL_TERM - if (!tgetflag("bs")) + if (!tgetflag(nhStr("bs"))) error("Terminal must backspace."); -#endif /* MINIMAL_TERM */ +#endif BC = tbufptr; tbufptr += 2; *BC = '\b'; } -#endif /* TERMINFO */ +#endif + } #ifdef MINIMAL_TERM HO = (char *) 0; -#else /* MINIMAL_TERM */ - HO = Tgetstr("ho"); -#endif /* MINIMAL_TERM */ +#else + HO = Tgetstr(nhStr("ho")); +#endif /* * LI and CO are set in ioctl.c via a TIOCGWINSZ if available. If * the kernel has values for either we should use them rather than @@ -210,18 +231,18 @@ int *wid, *hgt; */ #ifndef MICRO if (!CO) - CO = tgetnum("co"); + CO = tgetnum(nhStr("co")); if (!LI) - LI = tgetnum("li"); -#else /* MICRO */ + LI = tgetnum(nhStr("li")); +#else #if defined(TOS) && defined(__GNUC__) if (!strcmp(term, "builtin")) { get_scr_size(); } else -#endif /* defined(TOS) && defined(__GNUC__) */ +#endif { - CO = tgetnum("co"); - LI = tgetnum("li"); + CO = tgetnum(nhStr("co")); + LI = tgetnum(nhStr("li")); if (!LI || !CO) /* if we don't override it */ get_scr_size(); } @@ -229,49 +250,61 @@ int *wid, *hgt; #ifdef CLIPPING if (CO < COLNO || LI < ROWNO + 3) setclipped(); -#endif /* CLIPPING */ - nh_ND = Tgetstr("nd"); - if (tgetflag("os")) +#endif + nh_ND = Tgetstr(nhStr("nd")); /* move cursor right 1 column */ + if (tgetflag(nhStr("os"))) /* term can overstrike */ error("NetHack can't have OS."); - if (tgetflag("ul")) + if (tgetflag(nhStr("ul"))) /* underline by overstrike w/ underscore */ ul_hack = TRUE; - CE = Tgetstr("ce"); - UP = Tgetstr("up"); + CE = Tgetstr(nhStr("ce")); /* clear line from cursor to eol */ + UP = Tgetstr(nhStr("up")); /* move cursor up 1 line */ /* It seems that xd is no longer supported, and we should use a linefeed instead; unfortunately this requires resetting CRMOD, and many output routines will have to be modified slightly. Let's leave that till the next release. */ - XD = Tgetstr("xd"); + XD = Tgetstr(nhStr("xd")); /* not: XD = Tgetstr("do"); */ - if (!(nh_CM = Tgetstr("cm"))) { + if (!(nh_CM = Tgetstr(nhStr("cm")))) { /* cm: move cursor */ if (!UP && !HO) error("NetHack needs CM or UP or HO."); tty_raw_print("Playing NetHack on terminals without CM is suspect."); tty_wait_synch(); } - SO = Tgetstr("so"); - SE = Tgetstr("se"); - nh_US = Tgetstr("us"); - nh_UE = Tgetstr("ue"); - SG = tgetnum("sg"); /* -1: not fnd; else # of spaces left by so */ + SO = Tgetstr(nhStr("so")); /* standout start */ + SE = Tgetstr(nhStr("se")); /* standout end */ + nh_US = Tgetstr(nhStr("us")); /* underline start */ + nh_UE = Tgetstr(nhStr("ue")); /* underline end */ + ZH = Tgetstr(nhStr("ZH")); /* italic start */ + ZR = Tgetstr(nhStr("ZR")); /* italic end */ + SG = tgetnum(nhStr("sg")); /* -1: not fnd; else # of spaces left by so */ if (!SO || !SE || (SG > 0)) SO = SE = nh_US = nh_UE = nullstr; - TI = Tgetstr("ti"); - TE = Tgetstr("te"); + TI = Tgetstr(nhStr("ti")); /* nonconsequential cursor movement start */ + TE = Tgetstr(nhStr("te")); /* nonconsequential cursor movement end */ VS = VE = nullstr; #ifdef TERMINFO - VS = Tgetstr("eA"); /* enable graphics */ -#endif /* TERMINFO */ - KS = Tgetstr("ks"); /* keypad start (special mode) */ - KE = Tgetstr("ke"); /* keypad end (ordinary mode [ie, digits]) */ - MR = Tgetstr("mr"); /* reverse */ - MB = Tgetstr("mb"); /* blink */ - MD = Tgetstr("md"); /* boldface */ - MH = Tgetstr("mh"); /* dim */ - ME = Tgetstr("me"); /* turn off all attributes */ + VS = Tgetstr(nhStr("eA")); /* enable graphics */ +#endif + KS = Tgetstr(nhStr("ks")); /* keypad start (special mode) */ + KE = Tgetstr(nhStr("ke")); /* keypad end (ordinary mode [ie, digits]) */ + MR = Tgetstr(nhStr("mr")); /* reverse */ + MB = Tgetstr(nhStr("mb")); /* blink */ + MD = Tgetstr(nhStr("md")); /* boldface */ + if (!SO) + SO = MD; + MH = Tgetstr(nhStr("mh")); /* dim */ + ME = Tgetstr(nhStr("me")); /* turn off all attributes */ if (!ME) ME = SE ? SE : nullstr; /* default to SE value */ + nh_VI = Tgetstr(nhStr("vi")); + nh_VE = Tgetstr(nhStr("ve")); + /*nh_VS = Tgetstr(nhStr("vs"));*/ + if (!nh_VI || !nh_VE /*|| !nh_VS*/ ) + nh_VI = nh_VE = /*nh_VS =*/ (char *) 0; + + nh_Ic = Tgetstr(nhStr("Ic")); + /* Get rid of padding numbers for nh_HI and nh_HE. Hope they * aren't really needed!!! nh_HI and nh_HE are outputted to the * pager as a string - so how can you send it NULs??? @@ -285,36 +318,44 @@ int *wid, *hgt; nh_HE = dupstr(&ME[i]); dynamic_HIHE = TRUE; - AS = Tgetstr("as"); - AE = Tgetstr("ae"); - nh_CD = Tgetstr("cd"); -#ifdef TEXTCOLOR + AS = Tgetstr(nhStr("as")); /* alt charset start */ + AE = Tgetstr(nhStr("ae")); /* alt charset end */ + nh_CD = Tgetstr(nhStr("cd")); /* clear lines from cursor and down */ #if defined(TOS) && defined(__GNUC__) if (!strcmp(term, "builtin") || !strcmp(term, "tw52") || !strcmp(term, "st52")) { init_hilite(); } -#else /* defined(TOS) && defined(__GNUC__) */ +#else init_hilite(); -#endif /* defined(TOS) && defined(__GNUC__) */ -#endif /* TEXTCOLOR */ +#endif *wid = CO; *hgt = LI; - if (!(CL = Tgetstr("cl"))) /* last thing set */ + /* cl: clear screen, set cursor to upper left */ + if (!(CL = Tgetstr(nhStr("cl")))) /* last thing set */ error("NetHack needs CL."); if ((int) (tbufptr - tbuf) > (int) (sizeof tbuf)) error("TERMCAP entry too big...\n"); + /* NLE: Disable freeing of termcap buffer */ + /* free((genericptr_t) tptr); */ #endif /* TERMLIB */ + /* keep static copies of these so that raw_print_bold() will work + after exit_nhwindows(); if the sequences are too long, then bold + won't work after that--it will be rendered as ordinary text */ + if (nh_HI && strlen(nh_HI) < sizeof tty_standout_on) + Strcpy(tty_standout_on, nh_HI); + if (nh_HE && strlen(nh_HE) < sizeof tty_standout_off) + Strcpy(tty_standout_off, nh_HE); } /* note: at present, this routine is not part of the formal window interface */ /* deallocate resources prior to final termination */ void -tty_shutdown() +term_shutdown(void) { /* we only attempt to clean up a few individual termcap variables */ -#if defined(TEXTCOLOR) && (defined(TERMLIB) || defined(ANSI_DEFAULT)) +#if defined(TERMLIB) || defined(ANSI_DEFAULT) kill_hilite(); #endif #ifdef TERMLIB @@ -328,8 +369,7 @@ tty_shutdown() } void -tty_number_pad(state) -int state; +tty_number_pad(int state) { switch (state) { case -1: /* activate keypad mode (escape sequences) */ @@ -347,8 +387,8 @@ int state; } #ifdef TERMLIB -extern void NDECL((*decgraphics_mode_callback)); /* defined in drawing.c */ -static void NDECL(tty_decgraphics_termcap_fixup); +extern void (*decgraphics_mode_callback)(void); /* defined in symbols.c */ +static void tty_decgraphics_termcap_fixup(void); /* We call this routine whenever DECgraphics mode is enabled, even if it @@ -358,7 +398,7 @@ static void NDECL(tty_decgraphics_termcap_fixup); so this is a convenient hook. */ static void -tty_decgraphics_termcap_fixup() +tty_decgraphics_termcap_fixup(void) { static char ctrlN[] = "\016"; static char ctrlO[] = "\017"; @@ -379,65 +419,101 @@ tty_decgraphics_termcap_fixup() * Do not select NA ASCII as the primary font since people may * reasonably be using the UK character set. */ - if (SYMHANDLING(H_DEC)) - xputs("\033)0"); + if (SYMHANDLING(H_DEC)) { + xputs("\033)0"); /* "\e)0" load line drawing chars as secondary set */ + /* TI doesn't necessarily do this; explicitly switch to primary + font in case previous program (either before starting nethack + or during a shell escape) left the alternate font active */ + xputs(AE); + } + #ifdef PC9800 init_hilite(); -#endif /* PC9800 */ +#endif #if defined(ASCIIGRAPH) && !defined(NO_TERMS) +#if DECgraphicsOptimization /* some termcaps suffer from the bizarre notion that resetting video attributes should also reset the chosen character set */ - { - const char *nh_he = nh_HE, *ae = AE; - int he_limit, ae_length; + if (dynamic_HIHE) { + assert(nh_HE != NULL); + xputs(nh_HE); /* turn off any active highlighting (before maybe + * changing HE or AE) */ + (void) strsubst(nh_HE, AE, ""); + (void) strsubst(nh_HE, ctrlO, ""); + /* if AE has prefixing, substituting an empty string for it in HE + would only work if it is a leading prefix of HE; remove the + magic sequences that loads US set ("\e(B") or UK set ("\e(A") + into the primary character set since we don't want HE to do that */ + (void) strsubst(nh_HE, "\033(B", ""); + (void) strsubst(nh_HE, "\033(A", ""); + } +#endif - if (digit(*ae)) { /* skip over delay prefix, if any */ - do - ++ae; - while (digit(*ae)); - if (*ae == '.') { - ++ae; - if (digit(*ae)) - ++ae; - } - if (*ae == '*') + /* if AE is still present in HE, set a flag so that glyph writing + code will know that AS needs to be refreshed for consecutive + line drawing characters */ + const char *ae = AE; + + if (digit(*ae)) { /* skip over delay prefix, if any */ + do + ++ae; + while (digit(*ae)); + if (*ae == '.') { + ++ae; + if (digit(*ae)) ++ae; } - /* can't use nethack's case-insensitive strstri() here, and some old - systems don't have strstr(), so use brute force substring search */ - ae_length = strlen(ae), he_limit = strlen(nh_he); - while (he_limit >= ae_length) { - if (strncmp(nh_he, ae, ae_length) == 0) { - HE_resets_AS = TRUE; - break; - } - ++nh_he, --he_limit; - } + if (*ae == '*') + ++ae; } -#endif /* defined(ASCIIGRAPH) && !defined(NO_TERMS) */ + /* stdc strstr(), not nethack's strstri(); HE ends color, ME ends + inverse video; they might have the same value; sequences to end + other attributes aren't known to sometimes contain AE */ + if ((nh_HE && strstr(nh_HE, ae)) || (ME && strstr(ME, ae))) + HE_resets_AS = TRUE; + +#ifdef DECgraphicsOptimization + /* some termcaps have AS load the line-drawing character set as + primary instead of having initialization load it as secondary + (we've already done that init) and then having AS simply switch + to secondary (change to do that now); they also have AE load + the US character set, which we avoid by not touching primary; + if HE_resets_AS, we can't simplify AS/AE due to the risk that + HE is changing the primary set rather than just toggling to it */ + if (!HE_resets_AS && !strcmp(AS, "\033(0") && !strcmp(AE, "\033(B")) { + /* first output old AE to make sure we aren't about to leave + primary set with line drawing chars */ + xputs(AE); + AS = ctrlN; + AE = ctrlO; + } +#endif /* DECgraphicsOptimization */ + xputs(AE); +#endif /* ASCIIGRAPH && !NO_TERMS */ } #endif /* TERMLIB */ #if defined(ASCIIGRAPH) && defined(PC9800) -extern void NDECL((*ibmgraphics_mode_callback)); /* defined in drawing.c */ -#endif /* defined(ASCIIGRAPH) && defined(PC9800) */ +extern void (*ibmgraphics_mode_callback)(void); /* defined in symbols.c */ +#endif +extern void (*utf8graphics_mode_callback)(void); /* defined in symbols.c */ #ifdef PC9800 -extern void NDECL((*ascgraphics_mode_callback)); /* defined in drawing.c */ -static void NDECL(tty_ascgraphics_hilite_fixup); +extern void (*ascgraphics_mode_callback)(void); /* defined in symbols.c */ +static void tty_ascgraphics_hilite_fixup(void); static void -tty_ascgraphics_hilite_fixup() +tty_ascgraphics_hilite_fixup(void) { - register int c; + int c; for (c = 0; c < CLR_MAX / 2; c++) if (c != CLR_BLACK) { - hilites[c | BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm")); + hilites[c | BRIGHT] = (char *) alloc(sizeof "\033[1;3%dm"); Sprintf(hilites[c | BRIGHT], "\033[1;3%dm", c); if (c != CLR_GRAY) { - hilites[c] = (char *) alloc(sizeof("\033[0;3%dm")); + hilites[c] = (char *) alloc(sizeof "\033[0;3%dm"); Sprintf(hilites[c], "\033[0;3%dm", c); } } @@ -445,7 +521,7 @@ tty_ascgraphics_hilite_fixup() #endif /* PC9800 */ void -tty_start_screen() +term_start_screen(void) { xputs(TI); xputs(VS); @@ -459,7 +535,7 @@ tty_start_screen() init_hilite(); /* set up callback in case option is not set yet but toggled later */ ibmgraphics_mode_callback = init_hilite; -#endif /* ASCIIGRAPH */ +#endif #endif /* PC9800 */ #ifdef TERMLIB @@ -467,15 +543,19 @@ tty_start_screen() tty_decgraphics_termcap_fixup(); /* set up callback in case option is not set yet but toggled later */ decgraphics_mode_callback = tty_decgraphics_termcap_fixup; -#endif /* TERMLIB */ - if (Cmd.num_pad) +#endif +#ifdef ENHANCED_SYMBOLS + utf8graphics_mode_callback = tty_utf8graphics_fixup; +#endif + + if (gc.Cmd.num_pad) tty_number_pad(1); /* make keypad send digits */ } void -tty_end_screen() +term_end_screen(void) { - clear_screen(); + term_clear_screen(); xputs(VE); xputs(TE); } @@ -489,8 +569,7 @@ tty_end_screen() then action must be taken in trampoli.[ch]. */ void -nocmov(x, y) -int x, y; +nocmov(int x, int y) { if ((int) ttyDisplay->cury > y) { if (UP) { @@ -539,8 +618,7 @@ int x, y; } void -cmov(x, y) -register int x, y; +cmov(int x, int y) { xputs(tgoto(nh_CM, x, y)); ttyDisplay->cury = y; @@ -549,8 +627,7 @@ register int x, y; /* See note above. xputc() is a special function for overlays. */ int -xputc(c) -int c; /* actually char, but explicitly specify its widened type */ +xputc(int c) /* actually char, but explicitly specify its widened type */ { /* * Note: xputc() as a direct all to putchar() doesn't make any @@ -562,7 +639,7 @@ int c; /* actually char, but explicitly specify its widened type */ * * xputc() used to be declared as 'void xputc(c) char c; {}' but * avoiding the proper type 'int' just to avoid (void) casts when - * ignoring the result can't have been sufficent reason to add it. + * ignoring the result can't have been sufficient reason to add it. * It also had '#if apollo' conditional to have the arg be int. * Matching putchar()'s declaration and using explicit casts where * warranted is more robust, so we're just a jacket around that. @@ -571,27 +648,27 @@ int c; /* actually char, but explicitly specify its widened type */ } void -xputs(s) -const char *s; +xputs(const char *s) { + /* NLE: Use NLE xputs function */ #ifdef RL_GRAPHICS nle_xputs(s); #else /* RL_GRAPHICS */ #ifndef TERMLIB (void) fputs(s, stdout); -#else /* TERMLIB */ +#else tputs(s, 1, xputc); -#endif /* TERMLIB */ -#endif /*RL_GRAPHICS*/ +#endif +#endif /* RL_GRAPHICS */ } void -cl_end() +cl_end(void) { if (CE) { xputs(CE); } else { /* no-CE fix - free after Harold Rynes */ - register int cx = ttyDisplay->curx + 1; + int cx = ttyDisplay->curx + 1; /* this looks terrible, especially on a slow terminal but is better than nothing */ @@ -605,19 +682,21 @@ cl_end() } void -clear_screen() +term_clear_screen(void) { /* note: if CL is null, then termcap initialization failed, - so don't attempt screen-oriented I/O during final cleanup. + * so don't attempt screen-oriented I/O during final cleanup. */ if (CL) { xputs(CL); home(); + /* set remembered data to all spaces */ + erase_tty_screen(); } } void -home() +home(void) { if (HO) xputs(HO); @@ -629,14 +708,14 @@ home() } void -standoutbeg() +standoutbeg(void) { if (SO) xputs(SO); } void -standoutend() +standoutend(void) { if (SE) xputs(SE); @@ -644,28 +723,28 @@ standoutend() #if 0 /* if you need one of these, uncomment it (here and in extern.h) */ void -revbeg() +revbeg(void) { if (MR) xputs(MR); } void -boldbeg() +boldbeg(void) { if (MD) xputs(MD); } void -blinkbeg() +blinkbeg(void) { if (MB) xputs(MB); } void -dimbeg() +dimbeg(void) { /* not in most termcap entries */ if (MH) @@ -673,7 +752,7 @@ dimbeg() } void -m_end() +m_end(void) { if (ME) xputs(ME); @@ -681,13 +760,13 @@ m_end() #endif /*0*/ void -backsp() +backsp(void) { xputs(BC); } void -tty_nhbell() +tty_nhbell(void) { if (flags.silent) return; @@ -697,19 +776,19 @@ tty_nhbell() #ifdef ASCIIGRAPH void -graph_on() +graph_on(void) { if (AS) xputs(AS); } void -graph_off() +graph_off(void) { if (AE) xputs(AE); } -#endif /* ASCIIGRAPH */ +#endif #if !defined(MICRO) #ifdef VMS @@ -717,28 +796,73 @@ static const short tmspc10[] = { /* from termcap */ 0, 2000, 1333, 909, 743, 666, 333, 166, 83, 55, 50, 41, 27, 20, 13, 10, 5 }; -#else /* VMS */ +#else static const short tmspc10[] = { /* from termcap */ 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5 }; -#endif /* VMS */ -#endif /* !defined(MICRO) */ +#endif +#endif -/* NLE: Don't delay ever. */ +/* delay 50 ms */ void -tty_delay_output() +tty_delay_output(void) { +/* NLE: Nope. Don't delay ever. */ +#ifndef RL_GRAPHICS +#if defined(MICRO) + int i; +#endif + if (iflags.debug_fuzzer) + return; +#ifdef TIMED_DELAY + if (flags.nap) { + (void) fflush(stdout); + msleep(50); /* sleep for 50 milliseconds */ + return; + } +#endif +#if defined(MICRO) + /* simulate the delay with "cursor here" */ + for (i = 0; i < 3; i++) { + cmov(ttyDisplay->curx, ttyDisplay->cury); + (void) fflush(stdout); + } +#else /* MICRO */ + /* BUG: if the padding character is visible, as it is on the 5620 + then this looks terrible. */ + if (flags.null) { + tputs( +#ifdef TERMINFO + "$<50>", +#else + "50", +#endif + 1, xputc); + + } else if (ospeed > 0 && ospeed < SIZE(tmspc10) && nh_CM) { + /* delay by sending cm(here) an appropriate number of times */ + int cmlen = + (int) strlen(tgoto(nh_CM, ttyDisplay->curx, ttyDisplay->cury)); + int i = 500 + tmspc10[ospeed] / 2; + + while (i > 0) { + cmov((int) ttyDisplay->curx, (int) ttyDisplay->cury); + i -= cmlen * tmspc10[ospeed]; + } + } +#endif /* MICRO */ +#endif /* RL_GRAPHICS */ } /* must only be called with curx = 1 */ void -cl_eos() /* free after Robert Viduya */ +cl_eos(void) /* free after Robert Viduya */ { if (nh_CD) { xputs(nh_CD); } else { - register int cy = ttyDisplay->cury + 1; + int cy = ttyDisplay->cury + 1; while (cy <= LI - 2) { cl_end(); @@ -751,7 +875,7 @@ cl_eos() /* free after Robert Viduya */ } } -#if defined(TEXTCOLOR) && defined(TERMLIB) +#if defined(TERMLIB) #if defined(UNIX) && defined(TERMINFO) /* * Sets up color highlighting, using terminfo(4) escape sequences. @@ -781,16 +905,15 @@ cl_eos() /* free after Robert Viduya */ macros used elsewhere within nethack; fortunately they're not needed beyond this point, so we don't need to worry about reconstructing them after the header file inclusion. */ -#undef delay_output #undef TRUE #undef FALSE -#define m_move curses_m_move /* Some curses.h decl m_move(), not used here */ +#define m_move curses_m_move /* some curses.h decl m_move(), not used here */ #include #if !defined(LINUX) && !defined(__FreeBSD__) && !defined(NOTPARMDECL) extern char *tparm(); -#endif /* !defined(LINUX) && !defined(__FreeBSD__) && !defined(NOTPARMDECL) */ +#endif #ifndef COLOR_BLACK /* trust include file */ #ifndef _M_UNIX /* guess BGR */ @@ -811,8 +934,8 @@ extern char *tparm(); #define COLOR_MAGENTA 5 #define COLOR_CYAN 6 #define COLOR_WHITE 7 -#endif /* _M_UNIX */ -#endif /* COLOR_BLACK */ +#endif +#endif /* Mapping data for the six terminfo colors that resolve to pairs of nethack * colors. Black and white are handled specially. @@ -826,18 +949,25 @@ const struct { { COLOR_MAGENTA, CLR_MAGENTA, CLR_BRIGHT_MAGENTA }, { COLOR_CYAN, CLR_CYAN, CLR_BRIGHT_CYAN } }; +typedef struct { + unsigned char r, g, b; +} RGB; + static char nilstring[] = ""; static void -init_hilite() +init_hilite(void) { - register int c; + int c, colors; char *setf, *scratch; - int md_len; - if (tgetnum("Co") < 8 || (MD == NULL) || (strlen(MD) == 0) - || ((setf = tgetstr("AF", (char **) 0)) == (char *) 0 - && (setf = tgetstr("Sf", (char **) 0)) == (char *) 0)) { + colors = tgetnum(nhStr("Co")); + iflags.colorcount = colors; + int md_len = 0; + + if (colors < 8 || !MD || !*MD + || ((setf = tgetstr(nhStr("AF"), (char **) 0)) == (char *) 0 + && (setf = tgetstr(nhStr("Sf"), (char **) 0)) == (char *) 0)) { /* Fallback when colors not available * It's arbitrary to collapse all colors except gray * together, but that's what the previous code did. @@ -861,41 +991,63 @@ init_hilite() return; } - md_len = strlen(MD); - - c = 6; - while (c--) { - char *work; - - scratch = tparm(setf, ti_map[c].ti_color); - work = (char *) alloc(strlen(scratch) + md_len + 1); - Strcpy(work, MD); - hilites[ti_map[c].nh_bright_color] = work; - work += md_len; - Strcpy(work, scratch); - hilites[ti_map[c].nh_color] = work; + if (colors >= 16) { + for (c = 0; c < SIZE(ti_map); c++) { + /* system colors */ + scratch = tparm(setf, ti_map[c].nh_color); + hilites[ti_map[c].nh_color] = dupstr(scratch); + /* bright colors */ + scratch = tparm(setf, ti_map[c].nh_bright_color); + hilites[ti_map[c].nh_bright_color] = dupstr(scratch); + } + } else { + /* 8 system colors */ + md_len = (int) strlen(MD); + + c = 6; + while (c--) { + char *work; + + scratch = tparm(setf, ti_map[c].ti_color); + work = (char *) alloc(strlen(scratch) + md_len + 1); + Strcpy(work, MD); + hilites[ti_map[c].nh_bright_color] = work; + work += md_len; + Strcpy(work, scratch); + hilites[ti_map[c].nh_color] = work; + } } - scratch = tparm(setf, COLOR_WHITE); - hilites[CLR_WHITE] = (char *) alloc(strlen(scratch) + md_len + 1); - Strcpy(hilites[CLR_WHITE], MD); - Strcat(hilites[CLR_WHITE], scratch); + if (colors >= 16) { + scratch = tparm(setf, COLOR_WHITE | BRIGHT); + hilites[CLR_WHITE] = dupstr(scratch); + } else { + scratch = tparm(setf, COLOR_WHITE); + hilites[CLR_WHITE] = (char *) alloc(strlen(scratch) + md_len + 1); + Strcpy(hilites[CLR_WHITE], MD); + Strcat(hilites[CLR_WHITE], scratch); + } hilites[CLR_GRAY] = nilstring; hilites[NO_COLOR] = nilstring; if (iflags.wc2_darkgray) { - /* On many terminals, esp. those using classic PC CGA/EGA/VGA - * textmode, specifying "hilight" and "black" simultaneously - * produces a dark shade of gray that is visible against a - * black background. We can use it to represent black objects. - */ - scratch = tparm(setf, COLOR_BLACK); - hilites[CLR_BLACK] = (char *) alloc(strlen(scratch) + md_len + 1); - Strcpy(hilites[CLR_BLACK], MD); - Strcat(hilites[CLR_BLACK], scratch); + if (colors >= 16) { + scratch = tparm(setf, COLOR_BLACK|BRIGHT); + hilites[CLR_BLACK] = dupstr(scratch); + } else { + /* On many terminals, esp. those using classic PC CGA/EGA/VGA + * textmode, specifying "hilight" and "black" simultaneously + * produces a dark shade of gray that is visible against a + * black background. We can use it to represent black objects. + */ + scratch = tparm(setf, COLOR_BLACK); + hilites[CLR_BLACK] = (char *) alloc(strlen(scratch) + md_len + 1); + Strcpy(hilites[CLR_BLACK], MD); + Strcat(hilites[CLR_BLACK], scratch); + } } else { - /* But it's concievable that hilighted black-on-black could + /* But it's conceivable that hilighted black-on-black could * still be invisible on many others. We substitute blue for * black. */ @@ -904,46 +1056,60 @@ init_hilite() } static void -kill_hilite() +kill_hilite(void) { + int c; + /* if colors weren't available, no freeing needed */ if (hilites[CLR_BLACK] == nh_HI) return; + /* hilites[] will be set to NULL below, whether freed here or not */ + if (hilites[CLR_BLACK]) { if (hilites[CLR_BLACK] != hilites[CLR_BLUE]) - free(hilites[CLR_BLACK]); - hilites[CLR_BLACK] = 0; + free(hilites[CLR_BLACK]), hilites[CLR_BLACK] = NULL; + } + if (tgetnum(nhStr("Co")) >= 16) { + if (hilites[CLR_BLUE]) + free(hilites[CLR_BLUE]); + if (hilites[CLR_GREEN]) + free(hilites[CLR_GREEN]); + if (hilites[CLR_CYAN]) + free(hilites[CLR_CYAN]); + if (hilites[CLR_MAGENTA]) + free(hilites[CLR_MAGENTA]); + if (hilites[CLR_RED]) + free(hilites[CLR_RED]); + if (hilites[CLR_BROWN]) + free(hilites[CLR_BROWN]); + } else { + /* CLR_BLUE overlaps CLR_BRIGHT_BLUE, do not free */ + /* CLR_GREEN overlaps CLR_BRIGHT_GREEN, do not free */ + /* CLR_CYAN overlaps CLR_BRIGHT_CYAN, do not free */ + /* CLR_MAGENTA overlaps CLR_BRIGHT_MAGENTA, do not free */ + /* CLR_RED overlaps CLR_ORANGE, do not free */ + /* CLR_BROWN overlaps CLR_YELLOW, do not free */ } - /* CLR_BLUE overlaps CLR_BRIGHT_BLUE, do not free */ - /* CLR_GREEN overlaps CLR_BRIGHT_GREEN, do not free */ - /* CLR_CYAN overlaps CLR_BRIGHT_CYAN, do not free */ - /* CLR_MAGENTA overlaps CLR_BRIGHT_MAGENTA, do not free */ - /* CLR_RED overlaps CLR_ORANGE, do not free */ - /* CLR_BROWN overlaps CLR_YELLOW, do not free */ /* CLR_GRAY is static 'nilstring', do not free */ /* NO_COLOR is static 'nilstring', do not free */ if (hilites[CLR_BRIGHT_BLUE]) - free(hilites[CLR_BRIGHT_BLUE]), - hilites[CLR_BRIGHT_BLUE] = hilites[CLR_BLUE] = 0; + free(hilites[CLR_BRIGHT_BLUE]); if (hilites[CLR_BRIGHT_GREEN]) - free(hilites[CLR_BRIGHT_GREEN]), - hilites[CLR_BRIGHT_GREEN] = hilites[CLR_GREEN] = 0; + free(hilites[CLR_BRIGHT_GREEN]); if (hilites[CLR_BRIGHT_CYAN]) - free(hilites[CLR_BRIGHT_CYAN]), - hilites[CLR_BRIGHT_CYAN] = hilites[CLR_CYAN] = 0; + free(hilites[CLR_BRIGHT_CYAN]); if (hilites[CLR_BRIGHT_MAGENTA]) - free(hilites[CLR_BRIGHT_MAGENTA]), - hilites[CLR_BRIGHT_MAGENTA] = hilites[CLR_MAGENTA] = 0; + free(hilites[CLR_BRIGHT_MAGENTA]); if (hilites[CLR_ORANGE]) - free(hilites[CLR_ORANGE]), - hilites[CLR_ORANGE] = hilites[CLR_RED] = 0; + free(hilites[CLR_ORANGE]); if (hilites[CLR_YELLOW]) - free(hilites[CLR_YELLOW]), - hilites[CLR_YELLOW] = hilites[CLR_BROWN] = 0; + free(hilites[CLR_YELLOW]); if (hilites[CLR_WHITE]) - free(hilites[CLR_WHITE]), hilites[CLR_WHITE] = 0; - hilites[CLR_GRAY] = hilites[NO_COLOR] = 0; + free(hilites[CLR_WHITE]); + + for (c = 0; c < CLR_MAX; c++) + hilites[c] = NULL; } #else /* UNIX && TERMINFO */ @@ -951,19 +1117,17 @@ kill_hilite() #ifndef TOS /* find the foreground and background colors set by nh_HI or nh_HE */ static void -analyze_seq(str, fg, bg) -char *str; -int *fg, *bg; +analyze_seq(char *str, int *fg, int *bg) { - register int c, code; + int c, code; int len; #ifdef MICRO *fg = CLR_GRAY; *bg = CLR_BLACK; -#else /* MICRO */ +#else *fg = *bg = NO_COLOR; -#endif /* MICRO */ +#endif c = (str[0] == '\233') ? 1 : 2; /* index of char beyond esc prefix */ len = strlen(str) - 1; /* length excluding attrib suffix */ @@ -977,9 +1141,9 @@ int *fg, *bg; #ifdef MICRO *fg = CLR_GRAY; *bg = CLR_BLACK; -#else /* MICRO */ +#else *fg = *bg = NO_COLOR; -#endif /* MICRO */ +#endif } else if (code == 1) { /* bold */ *fg |= BRIGHT; #if 0 @@ -990,7 +1154,7 @@ int *fg, *bg; *fg |= BLINK; } else if (code == 25) { /* stop blinking */ *fg &= ~BLINK; -#endif /* 0 */ +#endif } else if (code == 7 || code == 27) { /* reverse */ code = *fg & ~BRIGHT; *fg = *bg | (*fg & BRIGHT); @@ -1005,18 +1169,18 @@ int *fg, *bg; c++; } } -#endif /* TOS */ +#endif /* * Sets up highlighting sequences, using ANSI escape sequences (highlight code - * found in print.c). The nh_HI and nh_HE sequences (usually from SO) are + * found in wintty.c). The nh_HI and nh_HE sequences (usually from SO) are * scanned to find foreground and background colors. */ static void -init_hilite() +init_hilite(void) { - register int c; + int c; #ifdef TOS extern unsigned long tos_numcolors; /* in tos.c */ static char NOCOL[] = "\033b0", COLHE[] = "\033q\033b0"; @@ -1032,7 +1196,8 @@ init_hilite() hilites[0] = NOCOL; for (c = 1; c < SIZE(hilites); c++) { char *foo; - foo = (char *) alloc(sizeof("\033b0")); + + foo = (char *) alloc(sizeof "\033b0"); if (tos_numcolors > 4) Sprintf(foo, "\033b%c", (c & ~BRIGHT) + '0'); else @@ -1074,11 +1239,11 @@ init_hilite() #ifdef MICRO if (c == CLR_BLUE) continue; -#endif /* MICRO */ - if (c == foreg) +#endif + if (c == foreg) { hilites[c] = (char *) 0; - else if (c != hi_foreg || backg != hi_backg) { - hilites[c] = (char *) alloc(sizeof("\033[%d;3%d;4%dm")); + } else if (c != hi_foreg || backg != hi_backg) { + hilites[c] = (char *) alloc(sizeof "\033[%d;3%d;4%dm"); Sprintf(hilites[c], "\033[%d", !!(c & BRIGHT)); if ((c | BRIGHT) != (foreg | BRIGHT)) Sprintf(eos(hilites[c]), ";3%d", c & ~BRIGHT); @@ -1091,15 +1256,15 @@ init_hilite() #ifdef MICRO /* brighten low-visibility colors */ hilites[CLR_BLUE] = hilites[CLR_BLUE | BRIGHT]; -#endif /* MICRO */ +#endif #endif /* TOS */ } static void -kill_hilite() +kill_hilite(void) { #ifndef TOS - register int c; + int c; for (c = 0; c < CLR_MAX / 2; c++) { if (hilites[c | BRIGHT] == hilites[c]) @@ -1109,19 +1274,24 @@ kill_hilite() if (hilites[c | BRIGHT] && hilites[c | BRIGHT] != nh_HI) free((genericptr_t) hilites[c | BRIGHT]), hilites[c | BRIGHT] = 0; } -#endif /* TOS */ +#endif return; } #endif /* UNIX && TERMINFO */ -#endif /* TEXTCOLOR && TERMLIB */ +#endif /* TERMLIB */ -#if defined(TEXTCOLOR) && !defined(TERMLIB) && defined(ANSI_DEFAULT) +#if !defined(TERMLIB) && defined(ANSI_DEFAULT) static char adef_nilstring[] = ""; static void -init_hilite() +init_hilite(void) { - register int c; + int c; + + if (!hilites[CLR_BLACK]) + hilites[CLR_BLACK] = adef_nilstring; + if (!hilites[CLR_BLACK | BRIGHT]) + hilites[CLR_BLACK | BRIGHT] = hilites[CLR_BLACK]; if (!hilites[CLR_GRAY]) hilites[CLR_GRAY] = adef_nilstring; @@ -1146,7 +1316,7 @@ init_hilite() } } - /* See TEXTCOLOR && TERMLIB && UNIX && TERMINFO code above. */ + /* See TERMLIB && UNIX && TERMINFO code above. */ if (iflags.wc2_darkgray) { /* Bright black is dark gray. */ hilites[CLR_BLACK] = (char *) alloc(sizeof "\033[1;30m"); @@ -1158,17 +1328,17 @@ init_hilite() } static void -kill_hilite() +kill_hilite(void) { - register int c; + int c; for (c = 0; c < CLR_MAX / 2; c++) { - if (c == CLR_BLACK) - continue; if (c == CLR_GRAY || hilites[c] == adef_nilstring) hilites[c] = 0; if (hilites[c | BRIGHT] == adef_nilstring) hilites[c] = 0; + if (c == CLR_BLACK) + continue; if (hilites[c | BRIGHT] == hilites[c]) /* for blue */ hilites[c | BRIGHT] = 0; if (hilites[c] && hilites[c] != nh_HI) @@ -1183,15 +1353,20 @@ kill_hilite() hilites[CLR_BLACK] = 0; } } -#endif /* TEXTCOLOR && !TERMLIB && ANSI_DEFAULT */ +#endif /* !TERMLIB && ANSI_DEFAULT */ static char nulstr[] = ""; static char * -s_atr2str(n) -int n; +s_atr2str(int n) { switch (n) { + case ATR_ITALIC: + /* if italic isn't available, fall through to underline */ + if (ZH && *ZH) + return ZH; + FALLTHROUGH; + /*FALLTHRU*/ case ATR_BLINK: case ATR_ULINE: if (n == ATR_BLINK) { @@ -1201,6 +1376,7 @@ int n; if (nh_US && *nh_US) return nh_US; } + FALLTHROUGH; /*FALLTHRU*/ case ATR_BOLD: if (MD && *MD) @@ -1221,18 +1397,25 @@ int n; } static char * -e_atr2str(n) -int n; +e_atr2str(int n) { switch (n) { + case ATR_ITALIC: + /* send ZR unless we didn't have ZH and substituted US */ + if (ZR && *ZR && ZH && *ZH) + return ZR; + FALLTHROUGH; + /*FALLTHRU*/ case ATR_ULINE: if (nh_UE && *nh_UE) return nh_UE; + FALLTHROUGH; /*FALLTHRU*/ case ATR_BOLD: case ATR_BLINK: if (nh_HE && *nh_HE) return nh_HE; + FALLTHROUGH; /*FALLTHRU*/ case ATR_DIM: case ATR_INVERSE: @@ -1246,8 +1429,7 @@ int n; /* suppress nonfunctional highlights so render_status() might be able to optimize more; keep this in sync with s_atr2str() */ int -term_attr_fixup(msk) -int msk; +term_attr_fixup(int msk) { /* underline is converted to bold if its start sequence isn't available */ if ((msk & HL_ULINE) && (!nh_US || !*nh_US)) { @@ -1267,8 +1449,7 @@ int msk; } void -term_start_attr(attr) -int attr; +term_start_attr(int attr) { if (attr) { const char *astr = s_atr2str(attr); @@ -1279,8 +1460,7 @@ int attr; } void -term_end_attr(attr) -int attr; +term_end_attr(int attr) { if (attr) { const char *astr = e_atr2str(attr); @@ -1290,36 +1470,156 @@ int attr; } } +/* this is called 'start bold' but HI is derived from SO (standout) rather + than from MD (start bold attribute) */ void -term_start_raw_bold() +term_start_raw_bold(void) { - xputs(nh_HI); + const char *soOn = nh_HI ? nh_HI : tty_standout_on; + + if (*soOn) + xputs(soOn); } +/* this is called 'end bold' but HE is derived from ME (end all attributes) */ void -term_end_raw_bold() +term_end_raw_bold(void) { - xputs(nh_HE); -} + const char *soOff = nh_HE ? nh_HE : tty_standout_off; -#ifdef TEXTCOLOR + if (*soOff) + xputs(soOff); +} void -term_end_color() +term_end_color(void) { xputs(nh_HE); } void -term_start_color(color) -int color; +term_start_color(int color) { - if (color < CLR_MAX) + if (color == NO_COLOR) + xputs(nh_HE); /* inline term_end_color() */ + else if (color < CLR_MAX && hilites[color] && *hilites[color]) xputs(hilites[color]); } -#endif /* TEXTCOLOR */ +void +term_start_bgcolor(int color) +{ + char tmp[8]; + Sprintf(tmp, "\033[%dm", ((color % 8) + 40)); + xputs(tmp); +} + +/* hide or show cursor */ +void +term_curs_set(int visibility) +{ + static int vis = -1; + + if (vis == visibility) + return; + + if (!visibility && nh_VI) + xputs(nh_VI); + else if (visibility && nh_VE) + xputs(nh_VE); + vis = visibility; +} + +#ifdef CHANGE_COLOR +void +tty_change_color(int color, long rgb, int reverse UNUSED) +{ + char buf[BUFSZ]; + int i; + char *c, *fmt; + + /* FIXME: colors are not reset back when exiting NetHack */ + if (nh_Ic && *nh_Ic) { + long clr = color, r, g, b; + + /* color * 3 seems to work correctly? */ + /* this probably depends on the termcap definition */ + r = ((rgb >> 16) & 0xFF) * 3; + g = ((rgb >> 8) & 0xFF) * 3; + b = (rgb & 0xFF) * 3; + + + fmt = tparm(nh_Ic, clr, r, g, b); + + c = fmt; + + i = 0; + while (*c) { + if (*c == '\033') { + buf[i++] = '\\'; + buf[i++] = 'E'; + } else { + buf[i++] = *c; + } + c++; + } + buf[i++] = '\0'; + xputs(fmt); + } +} +#endif /* CHANGE_COLOR */ -#endif /* TTY_GRAPHICS && !NO_TERMS */ + +#ifndef SEP2 +#define tcfmtstr "\033[38;2;%ld;%ld;%ldm" +#ifdef UNIX +#define tcfmtstr24bit "\033[38;2;%u;%u;%um" +#define tcfmtstr256 "\033[38;5;%dm" +#else +#define tcfmtstr24bit "\033[38;2;%lu;%lu;%lum" +#define tcfmtstr256 "\033[38:5:%lum" +#endif +#endif + +static void emit24bit(long mcolor); +static void emit256(int u256coloridx); + +static void emit24bit(long mcolor) +{ + static char tcolorbuf[QBUFSZ]; + + Snprintf(tcolorbuf, sizeof tcolorbuf, tcfmtstr, + ((mcolor >> 16) & 0xFF), /* red */ + ((mcolor >> 8) & 0xFF), /* green */ + ((mcolor >> 0) & 0xFF)); /* blue */ + xputs(tcolorbuf); +} + +static void emit256(int color256idx) +{ + static char tcolorbuf[QBUFSZ]; + + Snprintf(tcolorbuf, sizeof tcolorbuf, tcfmtstr256, + color256idx); + xputs(tcolorbuf); +} + +void +term_start_extracolor(uint32 customcolor, uint16 color256idx) +{ + /* color 0 has bit 0x1000000 set */ + long mcolor = (customcolor & 0xFFFFFF); + if (iflags.colorcount == 256) + emit256(color256idx); + else + emit24bit(mcolor); +} + +void +term_end_extracolor(void) +{ + xputs("\033[0m"); +} +#endif /* TTY_GRAPHICS && !NO_TERMS */ /*termcap.c*/ diff --git a/win/tty/topl.c b/win/tty/topl.c index 67ff59fcb..b87a6ac67 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 topl.c $NHDT-Date: 1560608320 2019/06/15 14:18:40 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.47 $ */ +/* NetHack 5.0 topl.c $NHDT-Date: 1717967339 2024/06/09 21:08:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.89 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,20 +10,16 @@ #include "tcap.h" #include "wintty.h" -#ifndef C /* this matches src/cmd.c */ -#define C(c) (0x1f & (c)) -#endif - -STATIC_DCL void FDECL(redotoplin, (const char *)); -STATIC_DCL void FDECL(topl_putsym, (CHAR_P)); -STATIC_DCL void FDECL(removetopl, (int)); -STATIC_DCL void FDECL(msghistory_snapshot, (BOOLEAN_P)); -STATIC_DCL void FDECL(free_msghistory_snapshot, (BOOLEAN_P)); +static void redotoplin(const char *); +static void topl_putsym(char); +static void removetopl(int); +static void msghistory_snapshot(boolean); +static void free_msghistory_snapshot(boolean); int -tty_doprev_message() +tty_doprev_message(void) { - register struct WinDesc *cw = wins[WIN_MESSAGE]; + struct WinDesc *cw = wins[WIN_MESSAGE]; winid prevmsg_win; int i; @@ -40,7 +36,7 @@ tty_doprev_message() putstr(prevmsg_win, 0, cw->data[i]); i = (i + 1) % cw->rows; } while (i != cw->maxcol); - putstr(prevmsg_win, 0, toplines); + putstr(prevmsg_win, 0, gt.toplines); display_nhwindow(prevmsg_win, TRUE); destroy_nhwindow(prevmsg_win); } else if (iflags.prevmsg_window == 'c') { /* combination */ @@ -48,7 +44,7 @@ tty_doprev_message() morc = 0; if (cw->maxcol == cw->maxrow) { ttyDisplay->dismiss_more = C('p'); /* ^P ok at --More-- */ - redotoplin(toplines); + redotoplin(gt.toplines); cw->maxcol--; if (cw->maxcol < 0) cw->maxcol = cw->rows - 1; @@ -73,7 +69,7 @@ tty_doprev_message() putstr(prevmsg_win, 0, cw->data[i]); i = (i + 1) % cw->rows; } while (i != cw->maxcol); - putstr(prevmsg_win, 0, toplines); + putstr(prevmsg_win, 0, gt.toplines); display_nhwindow(prevmsg_win, TRUE); destroy_nhwindow(prevmsg_win); } @@ -85,7 +81,7 @@ tty_doprev_message() prevmsg_win = create_nhwindow(NHW_MENU); putstr(prevmsg_win, 0, "Message History"); putstr(prevmsg_win, 0, ""); - putstr(prevmsg_win, 0, toplines); + putstr(prevmsg_win, 0, gt.toplines); cw->maxcol = cw->maxrow - 1; if (cw->maxcol < 0) cw->maxcol = cw->rows - 1; @@ -108,7 +104,7 @@ tty_doprev_message() do { morc = 0; if (cw->maxcol == cw->maxrow) - redotoplin(toplines); + redotoplin(gt.toplines); else if (cw->data[cw->maxcol]) redotoplin(cw->data[cw->maxcol]); cw->maxcol--; @@ -122,36 +118,42 @@ tty_doprev_message() return 0; } -STATIC_OVL void -redotoplin(str) -const char *str; +static void +redotoplin(const char *str) { int otoplin = ttyDisplay->toplin; home(); - if (*str & 0x80) { - /* kludge for the / command, the only time we ever want a */ - /* graphics character on the top line */ - g_putch((int) *str++); - ttyDisplay->curx++; + if (!ttyDisplay->topl_utf8) { + if (ttyDisplay->mixed && (*str & 0x80)) { + /* kludge for the / command, the only time we ever want a */ + /* graphics character on the top line */ + g_putch((int) *str++); + ttyDisplay->curx++; + } + end_glyphout(); /* in case message printed during graphics output */ } - end_glyphout(); /* in case message printed during graphics output */ putsyms(str); cl_end(); - ttyDisplay->toplin = 1; - if (ttyDisplay->cury && otoplin != 3) + ttyDisplay->toplin = TOPLINE_NEED_MORE; + if (ttyDisplay->cury && otoplin != TOPLINE_SPECIAL_PROMPT) more(); } /* for use by tty_putstr() */ void -show_topl(str) -const char *str; +show_topl(const char *str) { struct WinDesc *cw = wins[WIN_MESSAGE]; - if (!(cw->flags & WIN_STOP)) { - if (ttyDisplay->cury && ttyDisplay->toplin == 2) + /* show if either STOP isn't set or current message specifies NOSTOP */ + if ((cw->flags & (WIN_STOP | WIN_NOSTOP)) != WIN_STOP) { + /* NOSTOP cancels persistent STOP and is a one-shot operation; + force both to be cleared (no-op for either bit that isn't set) */ + cw->flags &= ~(WIN_STOP | WIN_NOSTOP); + + if (ttyDisplay->cury && ttyDisplay->toplin == TOPLINE_NON_EMPTY) + /* NLE: use NetHack function here */ clear_nhwindow(WIN_MESSAGE); cw->curx = cw->cury = 0; @@ -159,20 +161,20 @@ const char *str; cl_end(); addtopl(str); - if (ttyDisplay->cury && ttyDisplay->toplin != 3) - ttyDisplay->toplin = 2; + if (ttyDisplay->cury && ttyDisplay->toplin != TOPLINE_SPECIAL_PROMPT) + ttyDisplay->toplin = TOPLINE_NON_EMPTY; } } /* used by update_topl(); also by tty_putstr() */ void -remember_topl() +remember_topl(void) { - register struct WinDesc *cw = wins[WIN_MESSAGE]; + struct WinDesc *cw = wins[WIN_MESSAGE]; int idx = cw->maxrow; - unsigned len = strlen(toplines) + 1; + unsigned len = strlen(gt.toplines) + 1; - if ((cw->flags & WIN_LOCKHISTORY) || !*toplines) + if ((cw->flags & WIN_LOCKHISTORY) || !*gt.toplines) return; if (len > (unsigned) cw->datlen[idx]) { @@ -182,34 +184,38 @@ remember_topl() cw->data[idx] = (char *) alloc(len); cw->datlen[idx] = (short) len; } - Strcpy(cw->data[idx], toplines); - *toplines = '\0'; - cw->maxcol = cw->maxrow = (idx + 1) % cw->rows; + Strcpy(cw->data[idx], gt.toplines); + if (!program_state.in_checkpoint) { + *gt.toplines = '\0'; + cw->maxcol = cw->maxrow = (idx + 1) % cw->rows; + } } void -addtopl(s) -const char *s; +addtopl(const char *s) { - register struct WinDesc *cw = wins[WIN_MESSAGE]; + struct WinDesc *cw = wins[WIN_MESSAGE]; tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury); putsyms(s); cl_end(); - ttyDisplay->toplin = 1; + ttyDisplay->toplin = TOPLINE_NEED_MORE; } void -more() +more(void) { struct WinDesc *cw = wins[WIN_MESSAGE]; - /* avoid recursion -- only happens from interrupts */ - if (ttyDisplay->inmore++) - return; if (iflags.debug_fuzzer) return; + /* avoid recursion -- only happens from interrupts */ + if (ttyDisplay->inmore) + return; + + ttyDisplay->inmore++; + if (ttyDisplay->toplin) { tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury); if (cw->curx >= CO - 8) @@ -224,11 +230,13 @@ more() xwaitforspace("\033 "); - if (morc == '\033') - cw->flags |= WIN_STOP; + if (morc == '\033') { + if (!(cw->flags & WIN_NOSTOP)) + cw->flags |= WIN_STOP; + } if (ttyDisplay->toplin && cw->cury) { - docorner(1, cw->cury + 1); + docorner(1, cw->cury + 1, 0); cw->curx = cw->cury = 0; home(); } else if (morc == '\033') { @@ -236,70 +244,68 @@ more() home(); cl_end(); } - ttyDisplay->toplin = 0; + ttyDisplay->toplin = TOPLINE_EMPTY; ttyDisplay->inmore = 0; } void -update_topl(bp) -register const char *bp; +update_topl(const char *bp) { - register char *tl, *otl; - register int n0; + char *tl, *otl; + int n0; int notdied = 1; struct WinDesc *cw = wins[WIN_MESSAGE]; + boolean skip = (cw->flags & (WIN_STOP | WIN_NOSTOP)) == WIN_STOP; /* If there is room on the line, print message on same line */ /* But messages like "You die..." deserve their own line */ n0 = strlen(bp); - if ((ttyDisplay->toplin == 1 || (cw->flags & WIN_STOP)) + if ((ttyDisplay->toplin == TOPLINE_NEED_MORE || skip) && cw->cury == 0 - && n0 + (int) strlen(toplines) + 3 < CO - 8 /* room for --More-- */ + && n0 + (int) strlen(gt.toplines) + 3 < CO - 8 /* room for --More-- */ && (notdied = strncmp(bp, "You die", 7)) != 0) { - Strcat(toplines, " "); - Strcat(toplines, bp); + Strcat(gt.toplines, " "); + Strcat(gt.toplines, bp); cw->curx += 2; - if (!(cw->flags & WIN_STOP)) + if (!skip) addtopl(bp); return; - } else if (!(cw->flags & WIN_STOP)) { - if (ttyDisplay->toplin == 1) { + } else if (!skip) { + if (ttyDisplay->toplin == TOPLINE_NEED_MORE) { more(); - } else if (cw->cury) { /* for when flags.toplin == 2 && cury > 1 */ - docorner(1, cw->cury + 1); /* reset cury = 0 if redraw screen */ - cw->curx = cw->cury = 0; /* from home--cls() & docorner(1,n) */ + } else if (cw->cury) { /* for toplin==TOPLINE_NON_EMPTY && cury > 1 */ + docorner(1, cw->cury + 1, 0); /* reset cury = 0 if redraw screen */ + cw->curx = cw->cury = 0; /* from home--cls() & docorner(1,n,0) */ } } remember_topl(); - (void) strncpy(toplines, bp, TBUFSZ); - toplines[TBUFSZ - 1] = 0; + (void) strncpy(gt.toplines, bp, TBUFSZ); + gt.toplines[TBUFSZ - 1] = 0; - for (tl = toplines; n0 >= CO; ) { + for (tl = gt.toplines; n0 >= CO; ) { otl = tl; for (tl += CO - 1; tl != otl; --tl) if (*tl == ' ') break; if (tl == otl) { /* Eek! A huge token. Try splitting after it. */ - tl = index(otl, ' '); + tl = strchr(otl, ' '); if (!tl) break; /* No choice but to spit it out whole. */ } *tl++ = '\n'; n0 = strlen(tl); } - if (!notdied) - cw->flags &= ~WIN_STOP; - if (!(cw->flags & WIN_STOP)) - redotoplin(toplines); + if (!notdied) /* double negative => "You die"; avoid suppressing mesg */ + cw->flags &= ~WIN_STOP, skip = FALSE; + if (!skip) + redotoplin(gt.toplines); } -STATIC_OVL -void -topl_putsym(c) -char c; +static void +topl_putsym(char c) { - register struct WinDesc *cw = wins[WIN_MESSAGE]; + struct WinDesc *cw = wins[WIN_MESSAGE]; if (cw == (struct WinDesc *) 0) panic("Putsym window MESSAGE nonexistent"); @@ -309,6 +315,7 @@ char c; if (ttyDisplay->curx == 0 && ttyDisplay->cury > 0) tty_curs(BASE_WINDOW, CO, (int) ttyDisplay->cury - 1); backsp(); + nhassert(ttyDisplay->curx > 0); ttyDisplay->curx--; cw->curx = ttyDisplay->curx; return; @@ -338,16 +345,14 @@ char c; } void -putsyms(str) -const char *str; +putsyms(const char *str) { while (*str) topl_putsym(*str++); } -STATIC_OVL void -removetopl(n) -register int n; +static void +removetopl(int n) { /* assume addtopl() has been done, so ttyDisplay->toplin is already set */ while (n-- > 0) @@ -358,22 +363,24 @@ extern char erase_char; /* from xxxtty.c; don't need kill_char */ /* returns a single keystroke; also sets 'yn_number' */ char -tty_yn_function(query, resp, def) -const char *query, *resp; -char def; -/* - * Generic yes/no function. 'def' is the default (returned by space or - * return; 'esc' returns 'q', or 'n', or the default, depending on - * what's in the string. The 'query' string is printed before the user - * is asked about the string. - * If resp is NULL, any single character is accepted and returned. - * If not-NULL, only characters in it are allowed (exceptions: the - * quitchars are always allowed, and if it contains '#' then digits - * are allowed); if it includes an , anything beyond that won't - * be shown in the prompt to the user but will be acceptable as input. - */ +tty_yn_function( + const char *query, + const char *resp, + char def) { - register char q; + /* + * Generic yes/no function. 'def' is the default (returned by space + * or return; 'esc' returns 'q', or 'n', or the default, depending on + * what's in the expected-response string. The 'query' string is + * printed before the user is asked about the string. + * + * If resp is NULL, any single character is accepted and returned. + * If not-NULL, only characters in it are allowed (exceptions: the + * quitchars are always allowed, and if it contains '#' then digits + * are allowed). If it includes an , anything beyond that won't + * be shown in the prompt to the user but will be acceptable as input. + */ + char q; char rtmp[40]; boolean digit_ok, allow_num, preserve_case = FALSE; struct WinDesc *cw = wins[WIN_MESSAGE]; @@ -381,15 +388,16 @@ char def; char prompt[BUFSZ]; yn_number = 0L; - if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) + if (ttyDisplay->toplin == TOPLINE_NEED_MORE + && (cw->flags & (WIN_STOP | WIN_NOSTOP)) != WIN_STOP) more(); - cw->flags &= ~WIN_STOP; - ttyDisplay->toplin = 3; /* special prompt state */ + cw->flags &= ~(WIN_STOP | WIN_NOSTOP); + ttyDisplay->toplin = TOPLINE_SPECIAL_PROMPT; ttyDisplay->inread++; if (resp) { char *rb, respbuf[QBUFSZ]; - allow_num = (index(resp, '#') != 0); + allow_num = (strchr(resp, '#') != 0); Strcpy(respbuf, resp); /* normally we force lowercase, but if any uppercase letters are present in the allowed response, preserve case; @@ -400,7 +408,7 @@ char def; break; } /* any acceptable responses that follow aren't displayed */ - if ((rb = index(respbuf, '\033')) != 0) + if ((rb = strchr(respbuf, '\033')) != 0) *rb = '\0'; (void) strncpy(prompt, query, QBUFSZ - 1); prompt[QBUFSZ - 1] = '\0'; @@ -430,6 +438,7 @@ char def; ttyDisplay->inread = 0; (void) tty_doprev_message(); ttyDisplay->inread = sav; + /* NLE: use NetHack function here */ clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; addtopl(prompt); @@ -454,18 +463,18 @@ char def; } digit_ok = allow_num && digit(q); if (q == '\033') { - if (index(resp, 'q')) + if (strchr(resp, 'q')) q = 'q'; - else if (index(resp, 'n')) + else if (strchr(resp, 'n')) q = 'n'; else q = def; break; - } else if (index(quitchars, q)) { + } else if (strchr(quitchars, q)) { q = def; break; } - if (!index(resp, q) && !digit_ok) { + if (!strchr(resp, q) && !digit_ok) { tty_nhbell(); q = (char) 0; } else if (q == '#' || digit_ok) { @@ -486,12 +495,15 @@ char def; if (!preserve_case) z = lowc(z); if (digit(z)) { - value = (10 * value) + (z - '0'); + long dgt = (long) (z - '0'); + + /* value = (10 * value) + (z - '0'); */ + value = AppendLongDigit(value, dgt); if (value < 0) break; /* overflow: try again */ digit_string[0] = z; addtopl(digit_string), n_len++; - } else if (z == 'y' || index(quitchars, z)) { + } else if (z == 'y' || strchr(quitchars, z)) { if (z == '\033') value = -1; /* abort */ z = '\n'; /* break */ @@ -525,16 +537,17 @@ char def; Sprintf(rtmp, "#%ld", yn_number); else (void) key2txt(q, rtmp); - /* addtopl(rtmp); -- rewrite toplines instead */ - Sprintf(toplines, "%s%s", prompt, rtmp); -#ifdef DUMPLOG - dumplogmsg(toplines); + /* addtopl(rtmp); -- rewrite gt.toplines instead */ + Sprintf(gt.toplines, "%s%s", prompt, rtmp); +#ifdef DUMPLOG_CORE + dumplogmsg(gt.toplines); #endif ttyDisplay->inread--; - ttyDisplay->toplin = 2; + ttyDisplay->toplin = TOPLINE_NON_EMPTY; if (ttyDisplay->intr) ttyDisplay->intr--; if (wins[WIN_MESSAGE]->cury) + /* NLE: use NetHack function here */ clear_nhwindow(WIN_MESSAGE); return q; @@ -545,9 +558,9 @@ static char **snapshot_mesgs = 0; /* collect currently available message history data into a sequential array; optionally, purge that data from the active circular buffer set as we go */ -STATIC_OVL void -msghistory_snapshot(purge) -boolean purge; /* clear message history buffer as we copy it */ +static void +msghistory_snapshot( + boolean purge) /* clear message history buffer as we copy it */ { char *mesg; int i, inidx, outidx; @@ -558,7 +571,7 @@ boolean purge; /* clear message history buffer as we copy it */ return; cw = wins[WIN_MESSAGE]; - /* flush toplines[], moving most recent message to history */ + /* flush gt.toplines[], moving most recent message to history */ remember_topl(); /* for a passive snapshot, we just copy pointers, so can't allow further @@ -575,7 +588,7 @@ boolean purge; /* clear message history buffer as we copy it */ if (mesg && *mesg) { snapshot_mesgs[outidx++] = mesg; if (purge) { - /* we're taking this pointer away; subsequest history + /* we're taking this pointer away; subsequent history updates will eventually allocate a new one to replace it */ cw->data[inidx] = (char *) 0; cw->datlen[inidx] = 0; @@ -591,9 +604,10 @@ boolean purge; /* clear message history buffer as we copy it */ } /* release memory allocated to message history snapshot */ -STATIC_OVL void -free_msghistory_snapshot(purged) -boolean purged; /* True: took history's pointers, False: just cloned them */ +static void +free_msghistory_snapshot( + boolean purged) /* True: took history's pointers, + * False: just cloned them */ { if (snapshot_mesgs) { /* snapshot pointers are no longer in use */ @@ -623,8 +637,7 @@ boolean purged; /* True: took history's pointers, False: just cloned them */ * included among the output of the subsequent calls. */ char * -tty_getmsghistory(init) -boolean init; +tty_getmsghistory(boolean init) { static int nxtidx; char *nextmesg; @@ -664,15 +677,10 @@ boolean init; * into message history for ^P recall without having displayed it. */ void -tty_putmsghistory(msg, restoring_msghist) -const char *msg; -boolean restoring_msghist; +tty_putmsghistory(const char *msg, boolean restoring_msghist) { static boolean initd = FALSE; int idx; -#ifdef DUMPLOG - extern unsigned saved_pline_index; /* pline.c */ -#endif if (restoring_msghist && !initd) { /* we're restoring history from the previous session, but new @@ -682,26 +690,36 @@ boolean restoring_msghist; restored ones are being put into place */ msghistory_snapshot(TRUE); initd = TRUE; -#ifdef DUMPLOG +#ifdef DUMPLOG_CORE /* this suffices; there's no need to scrub saved_pline[] pointers */ - saved_pline_index = 0; + gs.saved_pline_index = 0; #endif } if (msg) { + /* Caller is asking us to remember a top line that needed more. + Should we call more? This can happen when the player has set + iflags.force_invmenu and they attempt to shoot with nothing in + the quiver. */ + if (ttyDisplay && ttyDisplay->toplin == TOPLINE_NEED_MORE) + ttyDisplay->toplin = TOPLINE_NON_EMPTY; + /* move most recent message to history, make this become most recent */ remember_topl(); - Strcpy(toplines, msg); -#ifdef DUMPLOG - dumplogmsg(toplines); + Strcpy(gt.toplines, msg); +#ifdef DUMPLOG_CORE + dumplogmsg(gt.toplines); #endif } else if (snapshot_mesgs) { + nhassert(ttyDisplay == NULL || + ttyDisplay->toplin != TOPLINE_NEED_MORE); + /* done putting arbitrary messages in; put the snapshot ones back */ for (idx = 0; snapshot_mesgs[idx]; ++idx) { remember_topl(); - Strcpy(toplines, snapshot_mesgs[idx]); -#ifdef DUMPLOG - dumplogmsg(toplines); + Strcpy(gt.toplines, snapshot_mesgs[idx]); +#ifdef DUMPLOG_CORE + dumplogmsg(gt.toplines); #endif } /* now release the snapshot */ diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 5e9c547b9..3930d0343 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintty.c $NHDT-Date: 1575245194 2019/12/02 00:06:34 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.227 $ */ +/* NetHack 5.0 wintty.c $NHDT-Date: 1737691300 2025/01/23 20:01:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.420 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -17,7 +17,10 @@ #ifdef TTY_GRAPHICS #include "dlb.h" -#ifdef MAC +/* leave this undefined; it produces bad screen output with rxvt-unicode */ +/*#define DECgraphicsOptimization*/ + +#ifdef MACOS9 #define MICRO /* The Mac is a MICRO only for this file, not in general! */ #ifdef THINK_C extern void msmsg(const char *, ...); @@ -30,22 +33,41 @@ extern void msmsg(const char *, ...); #include "wintty.h" -#ifdef CLIPPING /* might want SIGWINCH */ -#if defined(BSD) || defined(ULTRIX) || defined(AIX_31) || defined(_BULL_SOURCE) +#if defined(CLIPPING) && !defined(NO_SIGNAL) #include +#ifdef SIGWINCH +#define RESIZABLE +#endif #endif + +#ifdef DEF_PAGER + /* DEF_PAGER implies UNIX; when dlb is in use, the only file accessible + to an external pager is 'license'; override 'DEF_PAGER' for that + situation rather than using code to fallback to DLB plus internal + pager after open() failure */ +#ifdef DLB +#undef DEF_PAGER +#else +#ifndef O_RDONLY /* (same logic as unixmain.c) */ +#include #endif +#endif /* DLB */ +#endif /* DEF_PAGER */ +#if defined(TTY_TILES_ESCCODES) || defined(TTY_SOUND_ESCCODES) +#define VT_ANSI_COMMAND 'z' +#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 +#ifdef TTY_SOUND_ESCCODES +#define AVTC_SOUND_PLAY 4 +#endif -#ifdef HANGUP_HANDLING +#ifdef HANGUPHANDLING /* * NetHack's core switches to a dummy windowing interface when it * detects SIGHUP, but that's no help for any interface routine which @@ -56,7 +78,7 @@ extern short glyph2tile[]; */ #define HUPSKIP() \ do { \ - if (program_state.done_hup) { \ + if (program_state.done_hup) { \ morc = '\033'; \ return; \ } \ @@ -64,20 +86,21 @@ extern short glyph2tile[]; /* morc=ESC - in case we bypass xwaitforspace() which sets that */ #define HUPSKIP_RESULT(RES) \ do { \ - if (program_state.done_hup) \ + if (program_state.done_hup) \ return (RES); \ } while (0) -#else /* !HANGUP_HANDLING */ +#else /* !HANGUPHANDLING */ #define HUPSKIP() /*empty*/ #define HUPSKIP_RESULT(RES) /*empty*/ -#endif /* ?HANGUP_HANDLING */ - -extern char mapped_menu_cmds[]; /* from options.c */ +#endif /* ?HANGUPHANDLING */ /* Interface definition, for windows.c */ struct window_procs tty_procs = { - "tty", + WPID(tty), (0 +#ifdef TTY_PERM_INVENT + | WC_PERM_INVENT +#endif #ifdef MSDOS | WC_TILED_MAP | WC_ASCII_MAP #endif @@ -93,18 +116,21 @@ struct window_procs tty_procs = { | WC2_HILITE_STATUS | WC2_HITPOINTBAR | WC2_FLUSH_STATUS | WC2_RESET_STATUS #endif - | WC2_DARKGRAY | WC2_SUPPRESS_HIST | WC2_STATUSLINES), -#ifdef TEXTCOLOR - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ -#else - {1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1}, + | WC2_DARKGRAY | WC2_SUPPRESS_HIST | WC2_URGENT_MESG | WC2_STATUSLINES + | WC2_U_UTF8STR | WC2_PETATTR +#if !defined(NO_TERMS) || defined(WIN32CON) + | WC2_EXTRACOLORS #endif + | WC2_EXTRASTATUS + ), + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ tty_init_nhwindows, tty_player_selection, tty_askname, tty_get_nh_event, tty_exit_nhwindows, tty_suspend_nhwindows, tty_resume_nhwindows, tty_create_nhwindow, tty_clear_nhwindow, tty_display_nhwindow, - tty_destroy_nhwindow, tty_curs, tty_putstr, genl_putmixed, + tty_destroy_nhwindow, tty_curs, tty_putstr, + tty_putmixed, tty_display_file, tty_start_menu, tty_add_menu, tty_end_menu, - tty_select_menu, tty_message_menu, tty_update_inventory, tty_mark_synch, + tty_select_menu, tty_message_menu, tty_mark_synch, tty_wait_synch, #ifdef CLIPPING tty_cliparound, @@ -117,14 +143,13 @@ struct window_procs tty_procs = { tty_getlin, tty_get_ext_cmd, tty_number_pad, tty_delay_output, #ifdef CHANGE_COLOR /* the Mac uses a palette device */ tty_change_color, -#ifdef MAC +#ifdef MACOS9 tty_change_background, set_tty_font_name, #endif tty_get_color_string, #endif - /* other defs that really should go away (they're tty specific) */ - tty_start_screen, tty_end_screen, genl_outrip, + genl_outrip, tty_preference_update, tty_getmsghistory, tty_putmsghistory, tty_status_init, @@ -135,88 +160,125 @@ struct window_procs tty_procs = { genl_status_update, #endif genl_can_suspend_yes, + tty_update_inventory, + tty_ctrl_nhwindow, }; winid BASE_WINDOW; struct WinDesc *wins[MAXWIN]; struct DisplayDesc *ttyDisplay; /* the tty display descriptor */ -extern void FDECL(cmov, (int, int)); /* from termcap.c */ -extern void FDECL(nocmov, (int, int)); /* from termcap.c */ +extern void cmov(int, int); /* from termcap.c */ +extern void nocmov(int, int); /* from termcap.c */ + +static volatile int erasing_tty_screen; /* volatile: SIGWINCH */ + #if defined(UNIX) || defined(VMS) -#ifndef RL_GRAPHICS static char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */ #endif -#endif -static char winpanicstr[] = "Bad window id %d"; +static const char winpanicstr[] = "Bad window Id %d (%s)"; +#define ttywindowpanic() panic(winpanicstr, window, __func__) char defmorestr[] = "--More--"; #ifdef CLIPPING -#if defined(USE_TILES) && defined(MSDOS) +#if defined(TILES_IN_GLYPHMAP) && defined(MSDOS) boolean clipping = FALSE; /* clipping on? */ int clipx = 0, clipxmax = 0; +int clipy = 0, clipymax = 0; #else static boolean clipping = FALSE; /* clipping on? */ static int clipx = 0, clipxmax = 0; -#endif static int clipy = 0, clipymax = 0; +#endif #endif /* CLIPPING */ -#if defined(USE_TILES) && defined(MSDOS) -extern void FDECL(adjust_cursor_flags, (struct WinDesc *)); +#if defined(TILES_IN_GLYPHMAP) && defined(MSDOS) +extern void adjust_cursor_flags(struct WinDesc *); #endif -#if defined(ASCIIGRAPH) && !defined(NO_TERMS) +#if defined(ASCIIGRAPH) boolean GFlag = FALSE; boolean HE_resets_AS; /* see termcap.c */ #endif -#if defined(MICRO) || defined(WIN32CON) -static const char to_continue[] = "to continue"; -#define getret() getreturn(to_continue) -#else -STATIC_DCL void NDECL(getret); +static void bail(const char *); /* __attribute__((noreturn)) */ +static void newclipping(coordxy, coordxy); +static void new_status_window(void); +static void getret(void); +static void erase_menu_or_text(winid, struct WinDesc *, boolean); +static void free_window_info(struct WinDesc *, boolean); +static boolean toggle_menu_curr(winid, tty_menu_item *, int, boolean, + boolean, long); +static void dmore(struct WinDesc *, const char *); +static void set_item_state(winid, int, tty_menu_item *); +static void set_all_on_page(winid, tty_menu_item *, tty_menu_item *); +static void unset_all_on_page(winid, tty_menu_item *, tty_menu_item *); +static void invert_all_on_page(winid, tty_menu_item *, tty_menu_item *, + char, long); +static void invert_all(winid, tty_menu_item *, tty_menu_item *, char, long); +static void toggle_menu_attr(boolean, int, int); +static void process_menu_window(winid, struct WinDesc *); +static void process_text_window(winid, struct WinDesc *); +static tty_menu_item *reverse(tty_menu_item *); +static const char *compress_str(const char *); +#ifndef STATUS_HILITES +static void tty_putsym(winid, int, int, char); #endif -STATIC_DCL void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */ -STATIC_DCL void NDECL(new_status_window); -STATIC_DCL void FDECL(erase_menu_or_text, (winid, struct WinDesc *, - BOOLEAN_P)); -STATIC_DCL void FDECL(free_window_info, (struct WinDesc *, BOOLEAN_P)); -STATIC_DCL void FDECL(dmore, (struct WinDesc *, const char *)); -STATIC_DCL void FDECL(set_item_state, (winid, int, tty_menu_item *)); -STATIC_DCL void FDECL(set_all_on_page, (winid, tty_menu_item *, - tty_menu_item *)); -STATIC_DCL void FDECL(unset_all_on_page, (winid, tty_menu_item *, - tty_menu_item *)); -STATIC_DCL void FDECL(invert_all_on_page, (winid, tty_menu_item *, - tty_menu_item *, CHAR_P)); -STATIC_DCL void FDECL(invert_all, (winid, tty_menu_item *, - tty_menu_item *, CHAR_P)); -STATIC_DCL void FDECL(toggle_menu_attr, (BOOLEAN_P, int, int)); -STATIC_DCL void FDECL(process_menu_window, (winid, struct WinDesc *)); -STATIC_DCL void FDECL(process_text_window, (winid, struct WinDesc *)); -STATIC_DCL tty_menu_item *FDECL(reverse, (tty_menu_item *)); -STATIC_DCL const char *FDECL(compress_str, (const char *)); -STATIC_DCL void FDECL(tty_putsym, (winid, int, int, CHAR_P)); -STATIC_DCL void FDECL(setup_rolemenu, (winid, BOOLEAN_P, int, int, int)); -STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); -STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); -STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); -STATIC_DCL boolean NDECL(reset_role_filtering); +#define MAX_STATUS_ROWS 3 +#define StatusRows() ((iflags.wc2_statuslines <= 2) ? 2 : MAX_STATUS_ROWS) #ifdef STATUS_HILITES -STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P, int *)); -STATIC_DCL void NDECL(render_status); -STATIC_DCL void FDECL(tty_putstatusfield, (const char *, int, int)); -STATIC_DCL boolean NDECL(check_windowdata); -STATIC_DCL void NDECL(set_condition_length); -STATIC_DCL int FDECL(make_things_fit, (BOOLEAN_P)); -STATIC_DCL void FDECL(shrink_enc, (int)); -STATIC_DCL void FDECL(shrink_dlvl, (int)); +static boolean check_fields(boolean forcefields, int sz[MAX_STATUS_ROWS]); +static void render_status(void); +static void tty_putstatusfield(const char *, int, int); +static boolean check_windowdata(void); +static void set_condition_length(void); +static int make_things_fit(boolean); +static void shrink_enc(int); +static void shrink_dlvl(int); #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) -STATIC_DCL void NDECL(status_sanity_check); +static void status_sanity_check(void); #endif /* NH_DEVEL_STATUS */ #endif +#ifdef ENHANCED_SYMBOLS +void g_pututf8(uint8 *utf8str); +#endif + +static boolean calling_from_update_inventory = FALSE; +#ifdef TTY_PERM_INVENT +static struct tty_perminvent_cell emptyttycell = { + 0, 0, 0, { 0 }, NO_COLOR + 1 +}; +static glyph_info zerogi = { 0 }; +static struct to_core zero_tocore = { 0 }; +enum { border_left, border_middle, border_right, border_elements }; +static int bordercol[border_elements] = { 0, 0, 0 }; /* left, middle, right */ +static int ttyinvmode = InvNormal; /* enum is in wintype.h */ +static int inuse_only_start = 0; /* next slot to use for in-use-only mode */ +static boolean done_tty_perm_invent_init = FALSE; +enum { tty_slots = invlet_basic + invlet_gold + invlet_overflow }; /* 54 */ +static boolean slot_tracker[tty_slots]; +static int ttyinv_slots_used = 0; /* 1-based, slot_trackter[0..slots-1] */ +static long last_glyph_reset_when; +#ifndef NOINVSYM /* invent.c */ +#define NOINVSYM '#' +#endif +static int ttyinv_create_window(int, struct WinDesc *); +static void ttyinv_remove_data(struct WinDesc *, boolean); +static void ttyinv_add_menu(winid, struct WinDesc *, char ch, int attr, + int clr, const char *str); +static int selector_to_slot(char ch, const int invflags, boolean *ignore); +static char slot_to_invlet(int, boolean); +static void ttyinv_inuse_fulllines(struct WinDesc *, int); +static void ttyinv_inuse_twosides(struct WinDesc *, int); +static void ttyinv_end_menu(int, struct WinDesc *); +static void ttyinv_render(winid window, struct WinDesc *cw); +static void tty_invent_box_glyph_init(struct WinDesc *cw); +static boolean assesstty(enum inv_modes, short *, short *, + long *, long *, long *, long *, long *); +static void ttyinv_populate_slot(struct WinDesc *, int, int, + const char *, uint32, int); +#endif /* TTY_PERM_INVENT */ /* * A string containing all the default commands -- to add to a list @@ -232,9 +294,8 @@ static const char default_menu_cmds[] = { #ifdef TTY_TILES_ESCCODES static int vt_tile_current_window = -2; -void -print_vt_code(i, c, d) -int i, c, d; +static void +print_vt_code(int i, int c, int d) { HUPSKIP(); if (iflags.vt_tiledata) { @@ -245,26 +306,42 @@ int i, c, d; vt_tile_current_window = c; } if (d >= 0) - printf("\033[1;%d;%d;%d%c", i, c, d, TILE_ANSI_COMMAND); + printf("\033[1;%d;%d;%d%c", i, c, d, VT_ANSI_COMMAND); else - printf("\033[1;%d;%d%c", i, c, TILE_ANSI_COMMAND); + printf("\033[1;%d;%d%c", i, c, VT_ANSI_COMMAND); } else { - printf("\033[1;%d%c", i, TILE_ANSI_COMMAND); + printf("\033[1;%d%c", i, VT_ANSI_COMMAND); } } } #else -# define print_vt_code(i, c, d) ; +#define print_vt_code(i, c, d) /*empty*/ #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)) +#if defined(USER_SOUNDS) && defined(TTY_SOUND_ESCCODES) +static void +print_vt_soundcode_idx(int idx, int v) +{ + HUPSKIP(); + if (iflags.vt_sounddata) { + if (v >= 0) + printf("\033[1;%d;%d;%d%c", AVTC_SOUND_PLAY, + idx, v, VT_ANSI_COMMAND); + else + printf("\033[1;%d;%d%c", AVTC_SOUND_PLAY, + idx, VT_ANSI_COMMAND); + } +} +#else /* !(USER_SOUNDS && TTY_SOUND_ESCCODES) */ +#define print_vt_soundcode_idx(idx, v) ; +#endif /* ?(USER_SOUNDS && TTY_SOUND_ESCCODES) */ /* clean up and quit */ -STATIC_OVL void -bail(mesg) -const char *mesg; +static void +bail(const char *mesg) { clearlocks(); tty_exit_nhwindows(mesg); @@ -272,94 +349,151 @@ const char *mesg; /*NOTREACHED*/ } -#if defined(SIGWINCH) && defined(CLIPPING) -STATIC_DCL void FDECL(winch_handler, (int)); +#ifdef RESIZABLE +static void winch_handler(int); +static void resize_tty(void); - /* - * This really ought to just set a flag like the hangup handler does, - * then check the flag at "safe" times, in case the signal arrives - * while something fragile is executing. Better to have a brief period - * where display updates don't fit the new size than for tty internals - * to become corrupted. - * - * 'winch_seen' has been "notyet" for a long time.... - */ +static volatile int resize_mesg = 0; + +/* signal handler is called with at least 1 arg */ /*ARGUSED*/ -STATIC_OVL void -winch_handler(sig_unused) /* signal handler is called with at least 1 arg */ -int sig_unused UNUSED; +static void +winch_handler(int sig_unused UNUSED) { - int oldLI = LI, oldCO = CO, i; - register struct WinDesc *cw; - #ifdef WINCHAIN { #define WINCH_MESSAGE "(SIGWINCH)" if (wc_tracelogf) (void) write(fileno(wc_tracelogf), WINCH_MESSAGE, - strlen(WINCH_MESSAGE)); + sizeof WINCH_MESSAGE - sizeof ""); #undef WINCH_MESSAGE } #endif - getwindowsz(); - /* For long running events such as multi-page menus and - * display_file(), we note the signal's occurance and - * hope the code there decides to handle the situation - * and reset the flag. There will be race conditions - * when handling this - code handlers so it doesn't matter. - */ -#ifdef notyet - winch_seen = TRUE; + + program_state.resize_pending++; /* resize_tty() will reset it */ + /* if nethack is waiting for input, which is the most likely scenario, + we will go ahead and respond to the resize immediately; otherwise, + tty_nhgetch() will do so the next time it's called */ + if (program_state.getting_char) { + resize_tty(); +#if 0 /* [this doesn't work as intended and seems to be unnecessary] */ + if (resize_mesg) { + /* resize_tty() put "Press a key to continue: " on top line */ + (void) tty_nhgetch(); /* recursion... */ + } #endif - if ((oldLI != LI || oldCO != CO) && ttyDisplay) { - ttyDisplay->rows = LI; - ttyDisplay->cols = CO; + } + return; +} - cw = wins[BASE_WINDOW]; - cw->rows = ttyDisplay->rows; - cw->cols = ttyDisplay->cols; +/* query the system for tty size (vis getwindowsz()), and adapt the game's + windows to match */ +static void +resize_tty(void) +{ + int oldLI = LI, oldCO = CO, mapx, mapy, oldtoplin, i; + boolean map_active; + struct WinDesc *cw; - if (iflags.window_inited) { - cw = wins[WIN_MESSAGE]; - cw->curx = cw->cury = 0; + /* reset to 0 rather than just decrement */ + program_state.resize_pending = 0; + resize_mesg = 0; - new_status_window(); - if (u.ux) { - i = ttyDisplay->toplin; - ttyDisplay->toplin = 0; - docrt(); - bot(); - ttyDisplay->toplin = i; - flush_screen(1); - if (i) { - addtopl(toplines); - } else - for (i = WIN_INVEN; i < MAXWIN; i++) - if (wins[i] && wins[i]->active) { - /* cop-out */ - addtopl("Press Return to continue: "); - break; - } - (void) fflush(stdout); - if (i < 2) - flush_screen(1); + getwindowsz(); /* update LI and CO */ + if (!ttyDisplay || (LI == oldLI && CO == oldCO)) + return; + + ttyDisplay->rows = LI; + ttyDisplay->cols = CO; + + cw = wins[BASE_WINDOW]; + cw->rows = ttyDisplay->rows; + cw->cols = ttyDisplay->cols; + + if (!iflags.window_inited) + return; + + /* try to figure out where we'll want to leave the cursor */ + cw = (WIN_MAP != WIN_ERR) ? wins[WIN_MAP] : NULL; + map_active = (cw && cw->active); + if (!map_active) + mapx = 1, mapy = 0; + else if (gg.getposx < 1) + mapx = u.ux, mapy = u.uy; + else + mapx = gg.getposx, mapy = gg.getposy; + + oldtoplin = ttyDisplay->toplin; + ttyDisplay->toplin = TOPLINE_EMPTY; /* (before term_clear_screen()) */ + /* whatever used to be on the screen has become suspect; + blank it all out, then redo the display */ + term_clear_screen(); + new_status_window(); + + /* if the map window is shown, redisplay it (also status, perminv) */ + if (map_active) { + docrt_flags(docrtRefresh); + bot(); /* context.botlx=1 gets set by docrt() */ + for (i = 0; i < MAXWIN; ++i) { + if (i == BASE_WINDOW + || i == WIN_MAP /* docrt() updates it */ + || i == WIN_STATUS /* docrt()+bot() updates it */ +#ifdef TTY_PERM_INVENT + || i == WIN_INVEN /* docrt() again */ +#endif + || i == WIN_MESSAGE) /* we fake it here */ + continue; + if (wins[i] && wins[i]->active) { + /* cop-out */ + oldtoplin = TOPLINE_EMPTY; /* don't restore it below */ + ttyDisplay->toplin = TOPLINE_NON_EMPTY; + addtopl("Press a key to continue: "); + resize_mesg++; + break; } } + } /* wins[WIN_MAP].active */ + + if (oldtoplin != TOPLINE_EMPTY) { + ttyDisplay->toplin = oldtoplin; + addtopl(gt.toplines); + } + if (map_active) { + newclipping(mapx, mapy); + tty_curs(WIN_MAP, mapx, mapy); + tty_display_nhwindow(WIN_MAP, FALSE); /*fflush(stdout)*/ } + return; } +#endif /* RESIZABLE */ + +static void +newclipping(coordxy x, coordxy y) +{ +#ifdef CLIPPING + if (CO < COLNO || LI < 1 + ROWNO + iflags.wc2_statuslines) { + setclipped(); /* sets clipping=TRUE */ + if (x) + tty_cliparound(x, y); + } else { + clipping = FALSE; + clipx = clipy = 0; + } +#else + nhUse(x + y); #endif + return; +} /* destroy and recreate status window; extracted from winch_handler() and augmented for use by tty_preference_update() */ -STATIC_OVL void -new_status_window() +static void +new_status_window(void) { if (WIN_STATUS != WIN_ERR) { - /* if it's shrinking, clear it before destroying so that + /* in case it's shrinking, clear it before destroying so that dropped portion won't show anything that's now becoming stale */ - if (wins[WIN_STATUS]->maxrow > iflags.wc2_statuslines) - tty_clear_nhwindow(WIN_STATUS); - + tty_clear_nhwindow(WIN_STATUS); tty_destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR; } /* frees some status tracking data */ @@ -370,62 +504,48 @@ new_status_window() #ifdef STATUS_HILITES status_initialize(REASSESS_ONLY); #endif - -#ifdef CLIPPING - if (u.ux) { - if (LI < 1 + ROWNO + iflags.wc2_statuslines) { - setclipped(); - tty_cliparound(u.ux, u.uy); - } else { - clipping = FALSE; - clipx = clipy = 0; - } - } -#endif } /*ARGSUSED*/ void -tty_init_nhwindows(argcp, argv) -int *argcp UNUSED; -char **argv UNUSED; +tty_init_nhwindows(int *argcp UNUSED, char **argv UNUSED) { int wid, hgt, i; /* options aren't processed yet so wc2_statuslines might be 0; make sure that it has a reasonable value during tty setup */ - iflags.wc2_statuslines = (iflags.wc2_statuslines < 3) ? 2 : 3; + iflags.wc2_statuslines = StatusRows(); /* 2 or 3; 0 => 2 */ /* * Remember tty modes, to be restored on exit. * - * gettty() must be called before tty_startup() + * gettty() must be called before term_startup() * due to ordering of LI/CO settings - * tty_startup() must be called before initoptions() + * term_startup() must be called before initoptions() * due to ordering of graphics settings */ #if defined(UNIX) || defined(VMS) -#ifndef RL_GRAPHICS setbuf(stdout, obuf); -#endif #endif gettty(); /* to port dependant tty setup */ - tty_startup(&wid, &hgt); - setftty(); /* calls start_screen */ + term_startup(&wid, &hgt); + setftty(); /* calls term_start_screen */ + term_curs_set(0); /* set up tty descriptor */ ttyDisplay = (struct DisplayDesc *) alloc(sizeof (struct DisplayDesc)); - ttyDisplay->toplin = 0; + ttyDisplay->toplin = TOPLINE_EMPTY; + ttyDisplay->topl_utf8 = 0; /* putmixed may set this */ ttyDisplay->rows = hgt; ttyDisplay->cols = wid; ttyDisplay->curx = ttyDisplay->cury = 0; ttyDisplay->inmore = ttyDisplay->inread = ttyDisplay->intr = 0; ttyDisplay->dismiss_more = 0; -#ifdef TEXTCOLOR ttyDisplay->color = NO_COLOR; -#endif ttyDisplay->attrs = 0; + ttyDisplay->topl_utf8 = 0; + ttyDisplay->mixed = 0; /* set up the default windows */ BASE_WINDOW = tty_create_nhwindow(NHW_BASE); @@ -433,805 +553,105 @@ char **argv UNUSED; ttyDisplay->lastwin = WIN_ERR; -#if defined(SIGWINCH) && defined(CLIPPING) && !defined(NO_SIGNAL) +#ifdef RESIZABLE (void) signal(SIGWINCH, (SIG_RET_TYPE) winch_handler); #endif tty_clear_nhwindow(BASE_WINDOW); - tty_putstr(BASE_WINDOW, 0, ""); + /* Once pline() is functional, error-related prompts such as + * those relating to save files etc. can intrude on the + * copyright information display because their prompts are + * up at the very top in the message window. + * Move the copyright information a little further down to + * row 3, out of the way. */ + + tty_curs(BASE_WINDOW, 1, 4); for (i = 1; i <= 4; ++i) tty_putstr(BASE_WINDOW, 0, copyright_banner_line(i)); tty_putstr(BASE_WINDOW, 0, ""); tty_display_nhwindow(BASE_WINDOW, FALSE); - /* 'statuslines' defaults to SET_IN_FILE, allowed but invisible; + /* Move to a default location for the "Shall I pick .." player + * selection prompts, which also use the BASE_WINDOW. Leave + * room for as many as 3 unexpected raw_prints early startup + * messages above that. + * If there is a topline message prompt, before the + * "Shall I pick ..." prompt, the latter will end up appearing + * immediately after the topline message prompt. There should + * now be room. */ + tty_curs(BASE_WINDOW, 1, 11); + + /* 'statuslines' defaults to set_in_config, allowed but invisible; make it dynamically settable if feasible, otherwise visible */ - if (tty_procs.wincap2 & WC2_STATUSLINES) + if ((tty_procs.wincap2 & WC2_STATUSLINES) != 0) set_wc2_option_mod_status(WC2_STATUSLINES, #ifndef CLIPPING - (LI < 1 + ROWNO + 2) ? DISP_IN_GAME : + (LI <= 1 + ROWNO + 2) ? set_gameview : #endif - SET_IN_GAME); + set_in_game); } void -tty_preference_update(pref) -const char *pref; +tty_preference_update(const char *pref) { - if (!strcmp(pref, "statuslines") && iflags.window_inited) { + boolean newstatuslines = (!strcmp(pref, "statuslines") + && iflags.window_inited); + + if (newstatuslines) { new_status_window(); + newclipping(u.ux, u.uy); } -#if defined(WIN32) - nttty_preference_update(pref); +#if defined(WIN32CON) + consoletty_preference_update(pref); #else genl_preference_update(pref); +#endif +#ifdef TTY_PERM_INVENT + /* the boundary box around persistent inventory is drawn with wall + symbols, so if player changes to a different symbol set (other + than temporary switch to the rogue one), redraw perm_invent; not + only might individual symbols change (punctuation vs line drawing), + the way to render them might change too (Handling: DEC/UTF8/&c) */ + if ((!strcmp(pref, "symset") || !strcmp(pref, "perm_invent")) + && iflags.window_inited) { + if (WIN_INVEN != WIN_ERR) + tty_invent_box_glyph_init(wins[WIN_INVEN]); + } + /* if newstatuslines has been toggled between 2 and 3 or vice versa + then we want to reposition the perm_invent window to match */ + if (newstatuslines && WIN_INVEN != WIN_ERR) { + perm_invent_toggled(TRUE); /*TEMP?*/ + tty_destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR; + perm_invent_toggled(FALSE); /*TEMP?*/ + } #endif return; } -/* try to reduce clutter in the code below... */ -#define ROLE flags.initrole -#define RACE flags.initrace -#define GEND flags.initgend -#define ALGN flags.initalign - void -tty_player_selection() +tty_player_selection(void) { - int i, k, n, choice, nextpick; - boolean getconfirmation, picksomething; - char pick4u = 'n'; - char pbuf[QBUFSZ], plbuf[QBUFSZ]; - winid win; - anything any; - menu_item *selected = 0; - - /* Used to avoid "Is this ok?" if player has already specified all - * four facets of role. - * Note that rigid_role_checks might force any unspecified facets to - * have a specific value, but that will still require confirmation; - * player can specify the forced ones if avoiding that is demanded. - */ - picksomething = (ROLE == ROLE_NONE || RACE == ROLE_NONE - || GEND == ROLE_NONE || ALGN == ROLE_NONE); - /* Used for '-@'; - * choose randomly without asking for all unspecified facets. - */ - if (flags.randomall && picksomething) { - if (ROLE == ROLE_NONE) - ROLE = ROLE_RANDOM; - if (RACE == ROLE_NONE) - RACE = ROLE_RANDOM; - if (GEND == ROLE_NONE) - GEND = ROLE_RANDOM; - if (ALGN == ROLE_NONE) - ALGN = ROLE_RANDOM; - } - - /* prevent unnecessary prompting if role forces race (samurai) or gender - (valkyrie) or alignment (rogue), or race forces alignment (orc), &c */ - rigid_role_checks(); - - /* Should we randomly pick for the player? */ - if (ROLE == ROLE_NONE || RACE == ROLE_NONE || GEND == ROLE_NONE - || ALGN == ROLE_NONE) { - int echoline; - char *prompt = build_plselection_prompt(pbuf, QBUFSZ, - ROLE, RACE, GEND, ALGN); - - /* this prompt string ends in "[ynaq]?": - y - game picks role,&c then asks player to confirm; - n - player manually chooses via menu selections; - a - like 'y', but skips confirmation and starts game; - q - quit - */ - tty_putstr(BASE_WINDOW, 0, ""); - echoline = wins[BASE_WINDOW]->cury; - tty_putstr(BASE_WINDOW, 0, prompt); - do { - pick4u = lowc(readchar()); - if (index(quitchars, pick4u)) - pick4u = 'y'; - } while (!index(ynaqchars, pick4u)); - if ((int) strlen(prompt) + 1 < CO) { - /* Echo choice and move back down line */ - tty_putsym(BASE_WINDOW, (int) strlen(prompt) + 1, echoline, - pick4u); - tty_putstr(BASE_WINDOW, 0, ""); - } else - /* Otherwise it's hard to tell where to echo, and things are - * wrapping a bit messily anyway, so (try to) make sure the next - * question shows up well and doesn't get wrapped at the - * bottom of the window. - */ - tty_clear_nhwindow(BASE_WINDOW); - - if (pick4u != 'y' && pick4u != 'a' && pick4u != 'n') - goto give_up; - } - - makepicks: - nextpick = RS_ROLE; - do { - if (nextpick == RS_ROLE) { - nextpick = RS_RACE; - /* Select a role, if necessary; - we'll try to be compatible with pre-selected - race/gender/alignment, but may not succeed. */ - if (ROLE < 0) { - /* Process the choice */ - if (pick4u == 'y' || pick4u == 'a' || ROLE == ROLE_RANDOM) { - /* Pick a random role */ - k = pick_role(RACE, GEND, ALGN, PICK_RANDOM); - if (k < 0) { - tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); - k = randrole(FALSE); - } - } else { - /* Prompt for a role */ - tty_clear_nhwindow(BASE_WINDOW); - role_selection_prolog(RS_ROLE, BASE_WINDOW); - win = create_nhwindow(NHW_MENU); - start_menu(win); - /* populate the menu with role choices */ - setup_rolemenu(win, TRUE, RACE, GEND, ALGN); - /* add miscellaneous menu entries */ - role_menu_extra(ROLE_RANDOM, win, TRUE); - any = zeroany; /* separator, not a choice */ - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", - MENU_UNSELECTED); - role_menu_extra(RS_RACE, win, FALSE); - role_menu_extra(RS_GENDER, win, FALSE); - role_menu_extra(RS_ALGNMNT, win, FALSE); - if (gotrolefilter()) - role_menu_extra(RS_filter, win, FALSE); - role_menu_extra(ROLE_NONE, win, FALSE); /* quit */ - Strcpy(pbuf, "Pick a role or profession"); - end_menu(win, pbuf); - n = select_menu(win, PICK_ONE, &selected); - /* - * PICK_ONE with preselected choice behaves strangely: - * n == -1 -- , so use quit choice; - * n == 0 -- explicitly chose preselected entry, - * toggling it off, so use it; - * n == 1 -- implicitly chose preselected entry - * with or ; - * n == 2 -- explicitly chose a different entry, so - * both it and preselected one are in list. - */ - if (n > 0) { - choice = selected[0].item.a_int; - if (n > 1 && choice == ROLE_RANDOM) - choice = selected[1].item.a_int; - } else - choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE; - if (selected) - free((genericptr_t) selected), selected = 0; - destroy_nhwindow(win); - - if (choice == ROLE_NONE) { - goto give_up; /* Selected quit */ - } else if (choice == RS_menu_arg(RS_ALGNMNT)) { - ALGN = k = ROLE_NONE; - nextpick = RS_ALGNMNT; - } else if (choice == RS_menu_arg(RS_GENDER)) { - GEND = k = ROLE_NONE; - nextpick = RS_GENDER; - } else if (choice == RS_menu_arg(RS_RACE)) { - RACE = k = ROLE_NONE; - nextpick = RS_RACE; - } else if (choice == RS_menu_arg(RS_filter)) { - ROLE = k = ROLE_NONE; - (void) reset_role_filtering(); - nextpick = RS_ROLE; - } else if (choice == ROLE_RANDOM) { - k = pick_role(RACE, GEND, ALGN, PICK_RANDOM); - if (k < 0) - k = randrole(FALSE); - } else { - k = choice - 1; - } - } - ROLE = k; - } /* needed role */ - } /* picking role */ - - if (nextpick == RS_RACE) { - nextpick = (ROLE < 0) ? RS_ROLE : RS_GENDER; - /* Select a race, if necessary; - force compatibility with role, try for compatibility - with pre-selected gender/alignment. */ - if (RACE < 0 || !validrace(ROLE, RACE)) { - /* no race yet, or pre-selected race not valid */ - if (pick4u == 'y' || pick4u == 'a' || RACE == ROLE_RANDOM) { - k = pick_race(ROLE, GEND, ALGN, PICK_RANDOM); - if (k < 0) { - tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); - k = randrace(ROLE); - } - } else { /* pick4u == 'n' */ - /* Count the number of valid races */ - n = 0; /* number valid */ - k = 0; /* valid race */ - for (i = 0; races[i].noun; i++) - if (ok_race(ROLE, i, GEND, ALGN)) { - n++; - k = i; - } - if (n == 0) { - for (i = 0; races[i].noun; i++) - if (validrace(ROLE, i)) { - n++; - k = i; - } - } - /* Permit the user to pick, if there is more than one */ - if (n > 1) { - tty_clear_nhwindow(BASE_WINDOW); - role_selection_prolog(RS_RACE, BASE_WINDOW); - win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ - /* populate the menu with role choices */ - setup_racemenu(win, TRUE, ROLE, GEND, ALGN); - /* add miscellaneous menu entries */ - role_menu_extra(ROLE_RANDOM, win, TRUE); - any.a_int = 0; /* separator, not a choice */ - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", - MENU_UNSELECTED); - role_menu_extra(RS_ROLE, win, FALSE); - role_menu_extra(RS_GENDER, win, FALSE); - role_menu_extra(RS_ALGNMNT, win, FALSE); - if (gotrolefilter()) - role_menu_extra(RS_filter, win, FALSE); - role_menu_extra(ROLE_NONE, win, FALSE); /* quit */ - Strcpy(pbuf, "Pick a race or species"); - end_menu(win, pbuf); - n = select_menu(win, PICK_ONE, &selected); - if (n > 0) { - choice = selected[0].item.a_int; - if (n > 1 && choice == ROLE_RANDOM) - choice = selected[1].item.a_int; - } else - choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE; - if (selected) - free((genericptr_t) selected), selected = 0; - destroy_nhwindow(win); - - if (choice == ROLE_NONE) { - goto give_up; /* Selected quit */ - } else if (choice == RS_menu_arg(RS_ALGNMNT)) { - ALGN = k = ROLE_NONE; - nextpick = RS_ALGNMNT; - } else if (choice == RS_menu_arg(RS_GENDER)) { - GEND = k = ROLE_NONE; - nextpick = RS_GENDER; - } else if (choice == RS_menu_arg(RS_ROLE)) { - ROLE = k = ROLE_NONE; - nextpick = RS_ROLE; - } else if (choice == RS_menu_arg(RS_filter)) { - RACE = k = ROLE_NONE; - if (reset_role_filtering()) - nextpick = RS_ROLE; - else - nextpick = RS_RACE; - } else if (choice == ROLE_RANDOM) { - k = pick_race(ROLE, GEND, ALGN, PICK_RANDOM); - if (k < 0) - k = randrace(ROLE); - } else { - k = choice - 1; - } - } - } - RACE = k; - } /* needed race */ - } /* picking race */ - - if (nextpick == RS_GENDER) { - nextpick = (ROLE < 0) ? RS_ROLE : (RACE < 0) ? RS_RACE - : RS_ALGNMNT; - /* Select a gender, if necessary; - force compatibility with role/race, try for compatibility - with pre-selected alignment. */ - if (GEND < 0 || !validgend(ROLE, RACE, GEND)) { - /* no gender yet, or pre-selected gender not valid */ - if (pick4u == 'y' || pick4u == 'a' || GEND == ROLE_RANDOM) { - k = pick_gend(ROLE, RACE, ALGN, PICK_RANDOM); - if (k < 0) { - tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); - k = randgend(ROLE, RACE); - } - } else { /* pick4u == 'n' */ - /* Count the number of valid genders */ - n = 0; /* number valid */ - k = 0; /* valid gender */ - for (i = 0; i < ROLE_GENDERS; i++) - if (ok_gend(ROLE, RACE, i, ALGN)) { - n++; - k = i; - } - if (n == 0) { - for (i = 0; i < ROLE_GENDERS; i++) - if (validgend(ROLE, RACE, i)) { - n++; - k = i; - } - } - /* Permit the user to pick, if there is more than one */ - if (n > 1) { - tty_clear_nhwindow(BASE_WINDOW); - role_selection_prolog(RS_GENDER, BASE_WINDOW); - win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ - /* populate the menu with gender choices */ - setup_gendmenu(win, TRUE, ROLE, RACE, ALGN); - /* add miscellaneous menu entries */ - role_menu_extra(ROLE_RANDOM, win, TRUE); - any.a_int = 0; /* separator, not a choice */ - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", - MENU_UNSELECTED); - role_menu_extra(RS_ROLE, win, FALSE); - role_menu_extra(RS_RACE, win, FALSE); - role_menu_extra(RS_ALGNMNT, win, FALSE); - if (gotrolefilter()) - role_menu_extra(RS_filter, win, FALSE); - role_menu_extra(ROLE_NONE, win, FALSE); /* quit */ - Strcpy(pbuf, "Pick a gender or sex"); - end_menu(win, pbuf); - n = select_menu(win, PICK_ONE, &selected); - if (n > 0) { - choice = selected[0].item.a_int; - if (n > 1 && choice == ROLE_RANDOM) - choice = selected[1].item.a_int; - } else - choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE; - if (selected) - free((genericptr_t) selected), selected = 0; - destroy_nhwindow(win); - - if (choice == ROLE_NONE) { - goto give_up; /* Selected quit */ - } else if (choice == RS_menu_arg(RS_ALGNMNT)) { - ALGN = k = ROLE_NONE; - nextpick = RS_ALGNMNT; - } else if (choice == RS_menu_arg(RS_RACE)) { - RACE = k = ROLE_NONE; - nextpick = RS_RACE; - } else if (choice == RS_menu_arg(RS_ROLE)) { - ROLE = k = ROLE_NONE; - nextpick = RS_ROLE; - } else if (choice == RS_menu_arg(RS_filter)) { - GEND = k = ROLE_NONE; - if (reset_role_filtering()) - nextpick = RS_ROLE; - else - nextpick = RS_GENDER; - } else if (choice == ROLE_RANDOM) { - k = pick_gend(ROLE, RACE, ALGN, PICK_RANDOM); - if (k < 0) - k = randgend(ROLE, RACE); - } else { - k = choice - 1; - } - } - } - GEND = k; - } /* needed gender */ - } /* picking gender */ - - if (nextpick == RS_ALGNMNT) { - nextpick = (ROLE < 0) ? RS_ROLE : (RACE < 0) ? RS_RACE : RS_GENDER; - /* Select an alignment, if necessary; - force compatibility with role/race/gender. */ - if (ALGN < 0 || !validalign(ROLE, RACE, ALGN)) { - /* no alignment yet, or pre-selected alignment not valid */ - if (pick4u == 'y' || pick4u == 'a' || ALGN == ROLE_RANDOM) { - k = pick_align(ROLE, RACE, GEND, PICK_RANDOM); - if (k < 0) { - tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); - k = randalign(ROLE, RACE); - } - } else { /* pick4u == 'n' */ - /* Count the number of valid alignments */ - n = 0; /* number valid */ - k = 0; /* valid alignment */ - for (i = 0; i < ROLE_ALIGNS; i++) - if (ok_align(ROLE, RACE, GEND, i)) { - n++; - k = i; - } - if (n == 0) { - for (i = 0; i < ROLE_ALIGNS; i++) - if (validalign(ROLE, RACE, i)) { - n++; - k = i; - } - } - /* Permit the user to pick, if there is more than one */ - if (n > 1) { - tty_clear_nhwindow(BASE_WINDOW); - role_selection_prolog(RS_ALGNMNT, BASE_WINDOW); - win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ - setup_algnmenu(win, TRUE, ROLE, RACE, GEND); - role_menu_extra(ROLE_RANDOM, win, TRUE); - any.a_int = 0; /* separator, not a choice */ - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", - MENU_UNSELECTED); - role_menu_extra(RS_ROLE, win, FALSE); - role_menu_extra(RS_RACE, win, FALSE); - role_menu_extra(RS_GENDER, win, FALSE); - if (gotrolefilter()) - role_menu_extra(RS_filter, win, FALSE); - role_menu_extra(ROLE_NONE, win, FALSE); /* quit */ - Strcpy(pbuf, "Pick an alignment or creed"); - end_menu(win, pbuf); - n = select_menu(win, PICK_ONE, &selected); - if (n > 0) { - choice = selected[0].item.a_int; - if (n > 1 && choice == ROLE_RANDOM) - choice = selected[1].item.a_int; - } else - choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE; - if (selected) - free((genericptr_t) selected), selected = 0; - destroy_nhwindow(win); - - if (choice == ROLE_NONE) { - goto give_up; /* Selected quit */ - } else if (choice == RS_menu_arg(RS_GENDER)) { - GEND = k = ROLE_NONE; - nextpick = RS_GENDER; - } else if (choice == RS_menu_arg(RS_RACE)) { - RACE = k = ROLE_NONE; - nextpick = RS_RACE; - } else if (choice == RS_menu_arg(RS_ROLE)) { - ROLE = k = ROLE_NONE; - nextpick = RS_ROLE; - } else if (choice == RS_menu_arg(RS_filter)) { - ALGN = k = ROLE_NONE; - if (reset_role_filtering()) - nextpick = RS_ROLE; - else - nextpick = RS_ALGNMNT; - } else if (choice == ROLE_RANDOM) { - k = pick_align(ROLE, RACE, GEND, PICK_RANDOM); - if (k < 0) - k = randalign(ROLE, RACE); - } else { - k = choice - 1; - } - } - } - ALGN = k; - } /* needed alignment */ - } /* picking alignment */ - - } while (ROLE < 0 || RACE < 0 || GEND < 0 || ALGN < 0); - - /* - * Role, race, &c have now been determined; - * ask for confirmation and maybe go back to choose all over again. - * - * Uses ynaq for familiarity, although 'a' is usually a - * superset of 'y' but here is an alternate form of 'n'. - * Menu layout: - * title: Is this ok? [ynaq] - * blank: - * text: $name, $alignment $gender $race $role - * blank: - * menu: y + yes; play - * n - no; pick again - * maybe: a - no; rename hero - * q - quit - * (end) - */ - getconfirmation = (picksomething && pick4u != 'a' && !flags.randomall); - while (getconfirmation) { - tty_clear_nhwindow(BASE_WINDOW); - role_selection_prolog(ROLE_NONE, BASE_WINDOW); - win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ - any.a_int = 0; - if (!roles[ROLE].name.f - && (roles[ROLE].allow & ROLE_GENDMASK) - == (ROLE_MALE | ROLE_FEMALE)) - Sprintf(plbuf, " %s", genders[GEND].adj); - else - *plbuf = '\0'; /* omit redundant gender */ - Sprintf(pbuf, "%s, %s%s %s %s", plname, aligns[ALGN].adj, plbuf, - races[RACE].adj, - (GEND == 1 && roles[ROLE].name.f) ? roles[ROLE].name.f - : roles[ROLE].name.m); - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, pbuf, - MENU_UNSELECTED); - /* blank separator */ - any.a_int = 0; - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); - /* [ynaq] menu choices */ - any.a_int = 1; - add_menu(win, NO_GLYPH, &any, 'y', 0, ATR_NONE, "Yes; start game", - MENU_SELECTED); - any.a_int = 2; - add_menu(win, NO_GLYPH, &any, 'n', 0, ATR_NONE, - "No; choose role again", MENU_UNSELECTED); - if (iflags.renameallowed) { - any.a_int = 3; - add_menu(win, NO_GLYPH, &any, 'a', 0, ATR_NONE, - "Not yet; choose another name", MENU_UNSELECTED); - } - any.a_int = -1; - add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", - MENU_UNSELECTED); - Sprintf(pbuf, "Is this ok? [yn%sq]", iflags.renameallowed ? "a" : ""); - end_menu(win, pbuf); - n = select_menu(win, PICK_ONE, &selected); - /* [pick-one menus with a preselected entry behave oddly...] */ - choice = (n > 0) ? selected[n - 1].item.a_int : (n == 0) ? 1 : -1; - if (selected) - free((genericptr_t) selected), selected = 0; - destroy_nhwindow(win); - - switch (choice) { - default: /* 'q' or ESC */ - goto give_up; /* quit */ - break; - case 3: { /* 'a' */ - /* - * TODO: what, if anything, should be done if the name is - * changed to or from "wizard" after port-specific startup - * code has set flags.debug based on the original name? - */ - int saveROLE, saveRACE, saveGEND, saveALGN; - - iflags.renameinprogress = TRUE; - /* plnamesuffix() can change any or all of ROLE, RACE, - GEND, ALGN; we'll override that and honor only the name */ - saveROLE = ROLE, saveRACE = RACE, saveGEND = GEND, - saveALGN = ALGN; - *plname = '\0'; - plnamesuffix(); /* calls askname() when plname[] is empty */ - ROLE = saveROLE, RACE = saveRACE, GEND = saveGEND, - ALGN = saveALGN; - break; /* getconfirmation is still True */ - } - case 2: /* 'n' */ - /* start fresh, but bypass "shall I pick everything for you?" - step; any partial role selection via config file, command - line, or name suffix is discarded this time */ - pick4u = 'n'; - ROLE = RACE = GEND = ALGN = ROLE_NONE; - goto makepicks; - break; - case 1: /* 'y' or Space or Return/Enter */ - /* success; drop out through end of function */ - getconfirmation = FALSE; - break; - } - } - - /* Success! */ - tty_display_nhwindow(BASE_WINDOW, FALSE); - return; + if (genl_player_setup(ttyDisplay->rows)) + return; - give_up: - /* Quit */ - if (selected) - free((genericptr_t) selected); /* [obsolete] */ bail((char *) 0); /*NOTREACHED*/ - return; -} - -STATIC_OVL boolean -reset_role_filtering() -{ - winid win; - anything any; - int i, n; - menu_item *selected = 0; - - win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; - - /* no extra blank line preceding this entry; end_menu supplies one */ - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, - "Unacceptable roles", MENU_UNSELECTED); - setup_rolemenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE); - - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, - "Unacceptable races", MENU_UNSELECTED); - setup_racemenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE); - - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, - "Unacceptable genders", MENU_UNSELECTED); - setup_gendmenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE); - - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, - "Unacceptable alignments", MENU_UNSELECTED); - setup_algnmenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE); - - end_menu(win, "Pick all that apply"); - n = select_menu(win, PICK_ANY, &selected); - - if (n > 0) { - clearrolefilter(); - for (i = 0; i < n; i++) - setrolefilter(selected[i].item.a_string); - - ROLE = RACE = GEND = ALGN = ROLE_NONE; - } - if (selected) - free((genericptr_t) selected), selected = 0; - destroy_nhwindow(win); - return (n > 0) ? TRUE : FALSE; -} - -#undef ROLE -#undef RACE -#undef GEND -#undef ALGN - -/* add entries a-Archeologist, b-Barbarian, &c to menu being built in 'win' */ -STATIC_OVL void -setup_rolemenu(win, filtering, race, gend, algn) -winid win; -boolean filtering; /* True => exclude filtered roles; False => filter reset */ -int race, gend, algn; /* all ROLE_NONE for !filtering case */ -{ - anything any; - int i; - boolean role_ok; - char thisch, lastch = '\0', rolenamebuf[50]; - - any = zeroany; /* zero out all bits */ - for (i = 0; roles[i].name.m; i++) { - role_ok = ok_role(i, race, gend, algn); - if (filtering && !role_ok) - continue; - if (filtering) - any.a_int = i + 1; - else - any.a_string = roles[i].name.m; - thisch = lowc(*roles[i].name.m); - if (thisch == lastch) - thisch = highc(thisch); - Strcpy(rolenamebuf, roles[i].name.m); - if (roles[i].name.f) { - /* role has distinct name for female (C,P) */ - if (gend == 1) { - /* female already chosen; replace male name */ - Strcpy(rolenamebuf, roles[i].name.f); - } else if (gend < 0) { - /* not chosen yet; append slash+female name */ - Strcat(rolenamebuf, "/"); - Strcat(rolenamebuf, roles[i].name.f); - } - } - /* !filtering implies reset_role_filtering() where we want to - mark this role as preseleted if current filter excludes it */ - add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE, an(rolenamebuf), - (!filtering && !role_ok) ? MENU_SELECTED : MENU_UNSELECTED); - lastch = thisch; - } -} - -STATIC_OVL void -setup_racemenu(win, filtering, role, gend, algn) -winid win; -boolean filtering; -int role, gend, algn; -{ - anything any; - boolean race_ok; - int i; - char this_ch; - - any = zeroany; - for (i = 0; races[i].noun; i++) { - race_ok = ok_race(role, i, gend, algn); - if (filtering && !race_ok) - continue; - if (filtering) - any.a_int = i + 1; - else - any.a_string = races[i].noun; - this_ch = *races[i].noun; - /* filtering: picking race, so choose by first letter, with - capital letter as unseen accelerator; - !filtering: resetting filter rather than picking, choose by - capital letter since lowercase role letters will be present */ - add_menu(win, NO_GLYPH, &any, - filtering ? this_ch : highc(this_ch), - filtering ? highc(this_ch) : 0, - ATR_NONE, races[i].noun, - (!filtering && !race_ok) ? MENU_SELECTED : MENU_UNSELECTED); - } -} - -STATIC_DCL void -setup_gendmenu(win, filtering, role, race, algn) -winid win; -boolean filtering; -int role, race, algn; -{ - anything any; - boolean gend_ok; - int i; - char this_ch; - - any = zeroany; - for (i = 0; i < ROLE_GENDERS; i++) { - gend_ok = ok_gend(role, race, i, algn); - if (filtering && !gend_ok) - continue; - if (filtering) - any.a_int = i + 1; - else - any.a_string = genders[i].adj; - this_ch = *genders[i].adj; - /* (see setup_racemenu for explanation of selector letters - and setup_rolemenu for preselection) */ - add_menu(win, NO_GLYPH, &any, - filtering ? this_ch : highc(this_ch), - filtering ? highc(this_ch) : 0, - ATR_NONE, genders[i].adj, - (!filtering && !gend_ok) ? MENU_SELECTED : MENU_UNSELECTED); - } -} - -STATIC_DCL void -setup_algnmenu(win, filtering, role, race, gend) -winid win; -boolean filtering; -int role, race, gend; -{ - anything any; - boolean algn_ok; - int i; - char this_ch; - - any = zeroany; - for (i = 0; i < ROLE_ALIGNS; i++) { - algn_ok = ok_align(role, race, gend, i); - if (filtering && !algn_ok) - continue; - if (filtering) - any.a_int = i + 1; - else - any.a_string = aligns[i].adj; - this_ch = *aligns[i].adj; - /* (see setup_racemenu for explanation of selector letters - and setup_rolemenu for preselection) */ - add_menu(win, NO_GLYPH, &any, - filtering ? this_ch : highc(this_ch), - filtering ? highc(this_ch) : 0, - ATR_NONE, aligns[i].adj, - (!filtering && !algn_ok) ? MENU_SELECTED : MENU_UNSELECTED); - } } /* - * plname is filled either by an option (-u Player or -uPlayer) or + * svp.plname is filled either by an option (-u Player or -uPlayer) or * explicitly (by being the wizard) or by askname. * It may still contain a suffix denoting the role, etc. - * Always called after init_nhwindows() and before display_gamewindows(). + * Always called after init_nhwindows() and before + * init_sound_disp_gamewindows(). */ void -tty_askname() +tty_askname(void) { static const char who_are_you[] = "Who are you? "; - register int c, ct, tryct = 0; + int c, ct, tryct = 0; #ifdef SELECTSAVED if (iflags.wc2_selectsaved && !iflags.renameinprogress) @@ -1239,10 +659,11 @@ tty_askname() case -1: bail("Until next time then..."); /* quit */ /*NOTREACHED*/ + break; case 0: break; /* no game chosen; start new game */ case 1: - return; /* plname[] has been set */ + return; /* svp.plname[] has been set */ } #endif /* SELECTSAVED */ @@ -1260,6 +681,7 @@ tty_askname() tty_curs(BASE_WINDOW, (int) (sizeof who_are_you), wins[BASE_WINDOW]->cury - 1); ct = 0; + /* NLE: use NetHack function here */ while ((c = nhgetch()) != '\n') { if (c == EOF) c = '\033'; @@ -1305,7 +727,7 @@ tty_askname() && !(c >= '0' && c <= '9' && ct > 0)) c = '_'; #endif - if (ct < (int) (sizeof plname) - 1) { + if (ct < (int) (sizeof svp.plname) - 1) { #if defined(MICRO) #if defined(MSDOS) if (iflags.grmode) { @@ -1316,13 +738,13 @@ tty_askname() #else (void) putchar(c); #endif - plname[ct++] = c; + svp.plname[ct++] = c; #ifdef WIN32CON ttyDisplay->curx++; #endif } } - plname[ct] = 0; + svp.plname[ct] = 0; } while (ct == 0); /* move to next line to simulate echo of user's */ @@ -1334,15 +756,19 @@ tty_askname() } void -tty_get_nh_event() +tty_get_nh_event(void) { return; } -#if !defined(MICRO) && !defined(WIN32CON) -STATIC_OVL void -getret() +static void +getret(void) { +#if defined(MICRO) || defined(WIN32CON) + getreturn("to continue"); +#else + if (!isatty(STDIN_FILENO) || program_state.early_options) + return; HUPSKIP(); xputs("\n"); if (flags.standout) @@ -1353,29 +779,38 @@ getret() if (flags.standout) standoutend(); xwaitforspace(" "); -} #endif + iflags.raw_printed = 0; +} void -tty_suspend_nhwindows(str) -const char *str; +tty_suspend_nhwindows(const char *str) { + term_curs_set(1); settty(str); /* calls end_screen, perhaps raw_print */ if (!str) tty_raw_print(""); /* calls fflush(stdout) */ } void -tty_resume_nhwindows() +tty_resume_nhwindows(void) { gettty(); - setftty(); /* calls start_screen */ + setftty(); /* calls term_start_screen */ + term_curs_set(0); docrt(); } +#ifdef CHANGE_COLOR +char * +tty_get_color_string(void) +{ + return (char *) 0; +} +#endif /* CHANGE_COLOR */ + void -tty_exit_nhwindows(str) -const char *str; +tty_exit_nhwindows(const char *str) { winid i; @@ -1408,18 +843,14 @@ const char *str; ttyDisplay = (struct DisplayDesc *) 0; #endif -#ifndef NO_TERMS /*(until this gets added to the window interface)*/ - tty_shutdown(); /* cleanup termcap/terminfo/whatever */ -#endif -#ifdef WIN32 - nttty_exit(); -#endif + term_shutdown(); /* cleanup termcap/terminfo/whatever */ iflags.window_inited = 0; } +DISABLE_WARNING_UNREACHABLE_CODE + winid -tty_create_nhwindow(type) -int type; +tty_create_nhwindow(int type) { struct WinDesc *newwin; int i, rowoffset; @@ -1445,6 +876,7 @@ int type; newwin->mlist = (tty_menu_item *) 0; newwin->plist = (tty_menu_item **) 0; newwin->npages = newwin->plist_size = newwin->nitems = newwin->how = 0; + newwin->mbehavior = 0U; switch (type) { case NHW_BASE: /* base window, used for absolute movement on the screen */ @@ -1459,8 +891,8 @@ int type; /* sanity check */ if (iflags.msg_history < 20) iflags.msg_history = 20; - else if (iflags.msg_history > 60) - iflags.msg_history = 60; + else if (iflags.msg_history > MAX_MSG_HISTORY) + iflags.msg_history = MAX_MSG_HISTORY; newwin->maxrow = newwin->rows = iflags.msg_history; newwin->maxcol = newwin->cols = 0; break; @@ -1474,7 +906,7 @@ int type; iflags.wc2_statuslines = 2; newwin->offx = 0; rowoffset = ttyDisplay->rows - iflags.wc2_statuslines; -#if defined(USE_TILES) && defined(MSDOS) +#if defined(TILES_IN_GLYPHMAP) && defined(MSDOS) if (iflags.grmode) { newwin->offy = rowoffset; } else @@ -1531,30 +963,31 @@ int type; return newid; } -STATIC_OVL void -erase_menu_or_text(window, cw, clear) -winid window; -struct WinDesc *cw; -boolean clear; +RESTORE_WARNING_UNREACHABLE_CODE + +static void +erase_menu_or_text( + winid window, + struct WinDesc *cw, + boolean clear) { if (cw->offx == 0) { if (cw->offy) { tty_curs(window, 1, 0); cl_eos(); } else if (clear) { - clear_screen(); + term_clear_screen(); } else { docrt(); + flush_screen(1); } } else { - docorner((int) cw->offx, cw->maxrow + 1); + docorner((int) cw->offx, cw->maxrow + 1, 0); } } -STATIC_OVL void -free_window_info(cw, free_data) -struct WinDesc *cw; -boolean free_data; +static void +free_window_info(struct WinDesc *cw, boolean free_data) { int i; @@ -1601,69 +1034,93 @@ boolean free_data; } void -tty_clear_nhwindow(window) -winid window; +tty_clear_nhwindow(winid window) { int i, j, m, n; - register struct WinDesc *cw = 0; + struct WinDesc *cw = 0; HUPSKIP(); if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) - panic(winpanicstr, window); + ttywindowpanic(); ttyDisplay->lastwin = window; print_vt_code2(AVTC_SELECT_WINDOW, window); switch (cw->type) { case NHW_MESSAGE: - if (ttyDisplay->toplin) { - home(); - cl_end(); - if (cw->cury) - docorner(1, cw->cury + 1); - ttyDisplay->toplin = 0; + if (ttyDisplay->toplin != TOPLINE_EMPTY) { + if (!erasing_tty_screen) { + home(); + cl_end(); + if (cw->cury) + docorner(1, cw->cury + 1, 0); + } + cw->curx = cw->cury = 0; + ttyDisplay->toplin = TOPLINE_EMPTY; } break; case NHW_STATUS: m = cw->maxrow; n = cw->cols; for (i = 0; i < m; ++i) { - tty_curs(window, 1, i); - cl_end(); - + if (!erasing_tty_screen) { + tty_curs(window, 1, i); + cl_end(); + } for (j = 0; j < n - 1; ++j) cw->data[i][j] = ' '; cw->data[i][n - 1] = '\0'; /*finalx[i][NOW] = finalx[i][BEFORE] = 0;*/ } - context.botlx = 1; + disp.botlx = TRUE; break; case NHW_MAP: /* cheap -- clear the whole thing and tell nethack to redraw botl */ - context.botlx = 1; + disp.botlx = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case NHW_BASE: - clear_screen(); - /*for (i = 0; i < cw->maxrow; ++i) */ - /* finalx[i][NOW] = finalx[i][BEFORE] = 0;*/ + /* if erasing_tty_screen is True, calling sequence is + term_clear_screen -> erase_tty_screen -> tty_clear_nhwindow + so we don't call term_clear_screen again */ + if (!erasing_tty_screen) { + term_clear_screen(); + } + /* + * Neither map nor base window tracks what is currently shown so + * there's no stale data that would need to be changed to spaces. + */ break; case NHW_MENU: case NHW_TEXT: - if (cw->active) - erase_menu_or_text(window, cw, TRUE); - free_window_info(cw, FALSE); +#ifdef TTY_PERM_INVENT + case NHW_PERMINVENT: +#endif + if (!erasing_tty_screen) { + if (cw->active) + erase_menu_or_text(window, cw, TRUE); +#ifdef TTY_PERM_INVENT + if (cw->type == NHW_MENU && cw->mbehavior == MENU_BEHAVE_PERMINV) + ttyinv_remove_data(cw, FALSE); + else +#endif + free_window_info(cw, FALSE); + } break; } cw->curx = cw->cury = 0; + /* cw->blanked = TRUE; -- this isn't used */ } -boolean -toggle_menu_curr(window, curr, lineno, in_view, counting, count) -winid window; -tty_menu_item *curr; -int lineno; -boolean in_view, counting; -long count; +/* toggle a specific entry */ +static boolean +toggle_menu_curr( + winid window, + tty_menu_item *curr, + int lineno, + boolean in_view, + boolean counting, + long count) { if (curr->selected) { if (counting && count > 0) { @@ -1696,10 +1153,10 @@ long count; return FALSE; } -STATIC_OVL void -dmore(cw, s) -register struct WinDesc *cw; -const char *s; /* valid responses */ +static void +dmore( + struct WinDesc *cw, + const char *s) /* valid responses */ { const char *prompt = cw->morestr ? cw->morestr : defmorestr; int offset = (cw->type == NHW_TEXT) ? 1 : 2; @@ -1717,140 +1174,168 @@ const char *s; /* valid responses */ xwaitforspace(s); } -STATIC_OVL void -set_item_state(window, lineno, item) -winid window; -int lineno; -tty_menu_item *item; +/* change screen display for selection state of an item; + not used or wanted for items that aren't shown by the current page */ +static void +set_item_state( + winid window, + int lineno, + tty_menu_item *item) { char ch = item->selected ? (item->count == -1L ? '+' : '#') : '-'; HUPSKIP(); tty_curs(window, 4, lineno); term_start_attr(item->attr); + if (item->color != NO_COLOR) + term_start_color(item->color); (void) putchar(ch); ttyDisplay->curx++; + if (item->color != NO_COLOR) + term_end_color(); term_end_attr(item->attr); } -STATIC_OVL void -set_all_on_page(window, page_start, page_end) -winid window; -tty_menu_item *page_start, *page_end; +/* select all [ignores pending count, if any] */ +static void +set_all_on_page( + winid window, + tty_menu_item *page_start, + tty_menu_item *page_end) { tty_menu_item *curr; int n; - for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) - if (curr->identifier.a_void && !curr->selected) { - curr->selected = TRUE; - set_item_state(window, n, curr); - } + for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) { + if (!curr->identifier.a_void /* not selectable */ + || curr->selected /* already selected */ + || !menuitem_invert_test(1, curr->itemflags, FALSE)) + continue; + curr->selected = TRUE; + set_item_state(window, n, curr); + } } -STATIC_OVL void -unset_all_on_page(window, page_start, page_end) -winid window; -tty_menu_item *page_start, *page_end; +/* unselect all */ +static void +unset_all_on_page( + winid window, + tty_menu_item *page_start, + tty_menu_item *page_end) { tty_menu_item *curr; int n; - for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) - if (curr->identifier.a_void && curr->selected) { - curr->selected = FALSE; - curr->count = -1L; - set_item_state(window, n, curr); - } + for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) { + if (!curr->identifier.a_void /* skip if not selectable */ + || !curr->selected /* skip if already de-selected */ + || !menuitem_invert_test(2, curr->itemflags, TRUE)) + continue; + curr->selected = FALSE; + curr->count = -1L; + set_item_state(window, n, curr); + } } -STATIC_OVL void -invert_all_on_page(window, page_start, page_end, acc) -winid window; -tty_menu_item *page_start, *page_end; -char acc; /* group accelerator, 0 => all */ +/* invert current page */ +static void +invert_all_on_page( + winid window, + tty_menu_item *page_start, + tty_menu_item *page_end, + char acc, /* group accelerator, 0 => all */ + long count) /* pending count; -1L for non-group toggling */ { tty_menu_item *curr; int n; - for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) - if (curr->identifier.a_void && (acc == 0 || curr->gselector == acc)) { - if (curr->selected) { - curr->selected = FALSE; - curr->count = -1L; - } else - curr->selected = TRUE; - set_item_state(window, n, curr); + for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) { + if (!curr->identifier.a_void /* not selectable */ + || (acc ? curr->gselector != acc /* skip if not group 'acc' */ + /* inverting all rather than a group; skip if flagged */ + : !menuitem_invert_test(0, curr->itemflags, curr->selected))) + continue; + + if (curr->selected) { + curr->selected = FALSE; + curr->count = -1L; + } else { + curr->selected = TRUE; + if (count > 0) + curr->count = count; } + set_item_state(window, n, curr); + } } -/* - * Invert all entries that match the give group accelerator (or all if zero). - */ -STATIC_OVL void -invert_all(window, page_start, page_end, acc) -winid window; -tty_menu_item *page_start, *page_end; -char acc; /* group accelerator, 0 => all */ +/* invert all entries that match given group accelerator (or all if zero) */ +static void +invert_all( + winid window, + tty_menu_item *page_start, + tty_menu_item *page_end, + char acc, /* group accelerator, 0 => all */ + long count) /* pending count; -1L for non-group toggling */ { tty_menu_item *curr; boolean on_curr_page; struct WinDesc *cw = wins[window]; - invert_all_on_page(window, page_start, page_end, acc); + /* handle current page separately (it will need screen updating) */ + invert_all_on_page(window, page_start, page_end, acc, count); - /* invert the rest */ + /* invert the rest (no screen updating for them) */ for (on_curr_page = FALSE, curr = cw->mlist; curr; curr = curr->next) { if (curr == page_start) on_curr_page = TRUE; else if (curr == page_end) on_curr_page = FALSE; - if (!on_curr_page && curr->identifier.a_void - && (acc == 0 || curr->gselector == acc)) { - if (curr->selected) { - curr->selected = FALSE; - curr->count = -1; - } else - curr->selected = TRUE; + /* skip if on current page (already handled above) or not + selectable (header line or similar) or if group toggling + is taking place and this item isn't in specified group or + group toggling is not taking place and this item is off + limits to bulk toggling (assumes that an item won't be + both in a group and also subject to bulk restrictions) */ + if (on_curr_page || !curr->identifier.a_void + || (acc ? curr->gselector != acc + : !menuitem_invert_test(0, curr->itemflags, curr->selected))) + continue; + + if (curr->selected) { + curr->selected = FALSE; + curr->count = -1; + } else { + curr->selected = TRUE; + if (count > 0) + curr->count = count; } } } /* support menucolor in addition to caller-supplied attribute */ -STATIC_OVL void -toggle_menu_attr(on, color, attr) -boolean on; -int color, attr; +static void +toggle_menu_attr(boolean on, int color, int attr) { if (on) { term_start_attr(attr); -#ifdef TEXTCOLOR if (color != NO_COLOR) term_start_color(color); -#endif } else { -#ifdef TEXTCOLOR if (color != NO_COLOR) term_end_color(); -#endif term_end_attr(attr); } - -#ifndef TEXTCOLOR - nhUse(color); -#endif } -STATIC_OVL void -process_menu_window(window, cw) -winid window; -struct WinDesc *cw; +static void +process_menu_window(winid window, struct WinDesc *cw) { tty_menu_item *page_start, *page_end, *curr; long count; - int n, attr_n, curr_page, page_lines, resp_len; - boolean finished, counting, reset_count; + int n, attr_n, curr_page, page_lines, resp_len, previous_page_lines; + boolean finished, counting, reset_count, show_obj_syms, + only_if_no_headers = (iflags.menuobjsyms & 4) != 0; char *cp, *rp, resp[QBUFSZ], gacc[QBUFSZ], *msave, *morestr, really_morc; #define MENU_EXPLICIT_CHOICE 0x7f /* pseudo menu manipulation char */ @@ -1862,6 +1347,7 @@ struct WinDesc *cw; count = 0L; reset_count = TRUE; finished = FALSE; + previous_page_lines = 0; /* collect group accelerators; for PICK_NONE, they're ignored; for PICK_ONE, only those which match exactly one entry will be @@ -1869,7 +1355,7 @@ struct WinDesc *cw; gacc[0] = '\0'; if (cw->how != PICK_NONE) { int i, gcnt[128]; -#define GSELIDX(c) (c & 127) /* guard against `signed char' */ +#define GSELIDX(c) ((c) & 127) /* guard against `signed char' */ for (i = 0; i < SIZE(gcnt); i++) gcnt[i] = 0; @@ -1881,22 +1367,37 @@ struct WinDesc *cw; if (n > 0) /* at least one group accelerator found */ for (rp = gacc, curr = cw->mlist; curr; curr = curr->next) - if (curr->gselector && curr->gselector != curr->selector - && !index(gacc, curr->gselector) + if (curr->gselector + && (curr->gselector != curr->selector + /* '$' is both a selector "letter" and a group + accelerator; including it in gacc allows gold to + be selected via group when not on current page */ + || curr->gselector == GOLD_SYM) + && !strchr(gacc, curr->gselector) && (cw->how == PICK_ANY || gcnt[GSELIDX(curr->gselector)] == 1)) { *rp++ = curr->gselector; - *rp = '\0'; /* re-terminate for index() */ + *rp = '\0'; /* re-terminate for strchr() */ } +#undef GSELIDX } resp_len = 0; /* lint suppression */ + show_obj_syms = iflags.use_menu_glyphs; + if (only_if_no_headers) { + for (curr = cw->mlist; curr; curr = curr->next) + if (curr->identifier.a_void == 0) { + show_obj_syms = FALSE; + break; + } + } + /* loop until finished */ while (!finished) { HUPSKIP(); if (reset_count) { counting = FALSE; - count = 0; + count = 0L; } else reset_count = TRUE; @@ -1911,7 +1412,7 @@ struct WinDesc *cw; tty_curs(window, 1, 0); cl_eos(); } else - clear_screen(); + term_clear_screen(); } rp = resp; @@ -1933,9 +1434,8 @@ struct WinDesc *cw; (void) putchar(' '); ++ttyDisplay->curx; - if (!iflags.use_menu_color - || !get_menu_coloring(curr->str, &color, &attr)) - attr = curr->attr; + attr = curr->attr; + color = curr->color; /* which character to start attribute highlighting; whole line for headers and such, after the selector @@ -1944,9 +1444,9 @@ struct WinDesc *cw; entries, so we don't rely on curr->identifier here) */ attr_n = 0; /* whole line */ if (curr->str[0] && curr->str[1] == ' ' - && curr->str[2] && index("-+#", curr->str[2]) + && curr->str[2] && strchr("-+#", curr->str[2]) && curr->str[3] == ' ') - /* [0]=letter, [1]==space, [2]=[-+#], [3]=space */ + /* [0]=letter, [1]=space, [2]=[-+#], [3]=space */ attr_n = 4; /* [4:N]=entry description */ /* @@ -1968,15 +1468,25 @@ struct WinDesc *cw; if (n == attr_n && (color != NO_COLOR || attr != ATR_NONE)) toggle_menu_attr(TRUE, color, attr); - if (n == 2 - && curr->identifier.a_void != 0 + if (n == 2 && curr->identifier.a_void != 0 && curr->selected) { - if (curr->count == -1L) - (void) putchar('+'); /* all selected */ - else - (void) putchar('#'); /* count selected */ - } else + char c = (curr->count == -1L) ? '*' : '#'; + + /* all selected: '*' vs count selected: '#' */ + (void) putchar(c); + } else if (n == 2 && curr->identifier.a_void != 0 + && show_obj_syms + && curr->glyphinfo.glyph != NO_GLYPH) { + int gcolor = curr->glyphinfo.gm.sym.color; + + /* tty_print_glyph could be used, but is overkill + and requires referencing the cursor location */ + toggle_menu_attr(TRUE, gcolor, ATR_NONE); + (void) putchar(curr->glyphinfo.ttychar); + toggle_menu_attr(FALSE, gcolor, ATR_NONE); + } else { (void) putchar(*cp); + } } /* for *cp */ if (n > attr_n && (color != NO_COLOR || attr != ATR_NONE)) toggle_menu_attr(FALSE, color, attr); @@ -1996,14 +1506,36 @@ struct WinDesc *cw; tty_curs(window, 1, n); cl_end(); } - } + /* + * If this corner menu was big, there are likely large + * portions of the map, status window, and tty perm_invent + * window (is there is one), that are all missing a lot of + * information. Let's repair the blacked-out rows now + * because it looks better. + */ + if (previous_page_lines != 0 + && page_lines < previous_page_lines) { + /* + * +3 to leave a couple of blank rows + * under the menu to make it contrast well. + */ + int row_startoffset = page_lines + 3; + if (row_startoffset > cw->maxrow - 1) + row_startoffset = cw->maxrow - 1; + docorner((int) cw->offx, cw->maxrow + 1, row_startoffset); + } + } /* set extra chars.. */ - Strcat(resp, default_menu_cmds); + if (*gacc) { + Strcat(resp, gacc); /* group accelerators */ + if (cw->how == PICK_ONE) + resp_len = (int) strlen(resp); + } Strcat(resp, " "); /* next page or end */ Strcat(resp, "0123456789\033\n\r"); /* counts, quit */ - Strcat(resp, gacc); /* group accelerators */ - Strcat(resp, mapped_menu_cmds); + Strcat(resp, gm.mapped_menu_cmds); + Strcat(resp, default_menu_cmds); if (cw->npages > 1) Sprintf(cw->morestr, "(%d of %d)", curr_page + 1, @@ -2022,8 +1554,8 @@ struct WinDesc *cw; xwaitforspace(resp); } - really_morc = morc; /* (only used with MENU_EXPLICIT_CHOICE */ - if ((rp = index(resp, morc)) != 0 && rp < resp + resp_len) + really_morc = morc; /* (only used with MENU_EXPLICIT_CHOICE) */ + if ((rp = strchr(resp, morc)) != 0 && rp < resp + resp_len) /* explicit menu selection; don't override it if it also happens to match a mapped menu command (such as ':' to look inside a container vs ':' to search) */ @@ -2033,11 +1565,6 @@ struct WinDesc *cw; switch (morc) { case '0': - /* special case: '0' is also the default ball class */ - if (!counting && index(gacc, morc)) - goto group_accel; - /* fall through to count the zero */ - /*FALLTHRU*/ case '1': case '2': case '3': @@ -2047,7 +1574,20 @@ struct WinDesc *cw; case '7': case '8': case '9': - count = (count * 10L) + (long) (morc - '0'); + /* special case: '0' is also the default ball class; + some menus use digits as potential group accelerators + but their entries don't rely on counts */ + if (!counting && strchr(gacc, morc)) + goto group_accel; + + { + long dgt = (long) (morc - '0'); + + /* count = (10 * count) + (morc - '0'); */ + count = AppendLongDigit(count, dgt); + if (count < 0L) /* overflow */ + continue; /* reset_count is True */ + } /* * It is debatable whether we should allow 0 to * start a count. There is no difference if the @@ -2079,15 +1619,12 @@ struct WinDesc *cw; case '\0': /* finished (commit) */ case '\n': case '\r': - /* only finished if we are actually picking something */ - if (cw->how != PICK_NONE) { - finished = TRUE; - break; - } - /* else fall through */ + finished = TRUE; + break; case ' ': case MENU_NEXT_PAGE: if (cw->npages > 0 && curr_page != cw->npages - 1) { + previous_page_lines = page_lines; curr_page++; page_start = 0; } else if (morc == ' ') { @@ -2122,29 +1659,46 @@ struct WinDesc *cw; break; case MENU_INVERT_PAGE: if (cw->how == PICK_ANY) - invert_all_on_page(window, page_start, page_end, 0); + invert_all_on_page(window, page_start, page_end, 0, -1L); break; case MENU_SELECT_ALL: if (cw->how == PICK_ANY) { + /* entries on the current page need screen updating */ set_all_on_page(window, page_start, page_end); - /* set the rest */ - for (curr = cw->mlist; curr; curr = curr->next) - if (curr->identifier.a_void && !curr->selected) - curr->selected = TRUE; - } + /* set the rest; entries on current page will be skipped + because all of those will be 'already selected' now + (some won't be if they failed menuitem_invert_test() + in set_all_on_page() but those will fail it again here) */ + for (curr = cw->mlist; curr; curr = curr->next) { + if (!curr->identifier.a_void /* not selectable */ + || curr->selected /* already selected */ + /* FALSE: not currently selected */ + || !menuitem_invert_test(1, curr->itemflags, FALSE)) + continue; + curr->selected = TRUE; + } + } /* if PICK_ANY */ break; case MENU_UNSELECT_ALL: + /* entries on the current page need screen updating */ unset_all_on_page(window, page_start, page_end); - /* unset the rest */ - for (curr = cw->mlist; curr; curr = curr->next) - if (curr->identifier.a_void && curr->selected) { - curr->selected = FALSE; - curr->count = -1; - } + /* unset the rest; entries on current page will be skipped + because none of those will still be in 'selected' state + (unless they failed the menuitem_invert_test() in + unset_all_on_page() but those will fail it again here) */ + for (curr = cw->mlist; curr; curr = curr->next) { + if (!curr->identifier.a_void /* not selectable */ + || !curr->selected /* already de-selected */ + /* TRUE: currently selected */ + || !menuitem_invert_test(2, curr->itemflags, TRUE)) + continue; + curr->selected = FALSE; + curr->count = -1; + } break; case MENU_INVERT_ALL: if (cw->how == PICK_ANY) - invert_all(window, page_start, page_end, 0); + invert_all(window, page_start, page_end, 0, -1L); break; case MENU_SEARCH: if (cw->how == PICK_NONE) { @@ -2181,17 +1735,19 @@ struct WinDesc *cw; break; case MENU_EXPLICIT_CHOICE: morc = really_morc; + FALLTHROUGH; /*FALLTHRU*/ default: - if (cw->how == PICK_NONE || !index(resp, morc)) { + if (cw->how == PICK_NONE || !strchr(resp, morc)) { /* unacceptable input received */ tty_nhbell(); break; - } else if (index(gacc, morc)) { + } else if (strchr(gacc, morc)) { group_accel: /* group accelerator; for the PICK_ONE case, we know that it matches exactly one item in order to be in gacc[] */ - invert_all(window, page_start, page_end, morc); + invert_all(window, page_start, page_end, morc, + counting ? count : -1L); if (cw->how == PICK_ONE) finished = TRUE; break; @@ -2211,16 +1767,15 @@ struct WinDesc *cw; } /* while */ cw->morestr = msave; free((genericptr_t) morestr); +#undef MENU_EXPLICIT_CHOICE } -STATIC_OVL void -process_text_window(window, cw) -winid window; -struct WinDesc *cw; +static void +process_text_window(winid window, struct WinDesc *cw) { int i, n, attr; boolean linestart; - register char *cp; + char *cp; for (n = 0, i = 0; i < cw->maxrow; i++) { HUPSKIP(); @@ -2236,7 +1791,7 @@ struct WinDesc *cw; tty_curs(window, 1, 0); cl_eos(); } else - clear_screen(); + term_clear_screen(); n = 0; } tty_curs(window, 1, n++); @@ -2264,9 +1819,16 @@ struct WinDesc *cw; ) { /* message recall for msg_window:full/combination/reverse might have output from '/' in it (see redotoplin()) */ - if (linestart && (*cp & 0x80) != 0) { - g_putch(*cp); - end_glyphout(); + if (linestart) { + if (SYMHANDLING(H_UTF8)) { + /* FIXME: what is actually in that line? is it the \GNNNNNNNN or UTF-8? */ + g_putch(*cp); + } else if ((*cp & 0x80) != 0) { + g_putch(*cp); + end_glyphout(); + } else { + (void) putchar(*cp); + } linestart = FALSE; } else { (void) putchar(*cp); @@ -2293,16 +1855,16 @@ struct WinDesc *cw; /*ARGSUSED*/ void -tty_display_nhwindow(window, blocking) -winid window; -boolean blocking; /* with ttys, all windows are blocking */ +tty_display_nhwindow( + winid window, + boolean blocking) /* with ttys, all windows are blocking */ { - register struct WinDesc *cw = 0; + struct WinDesc *cw = 0; short s_maxcol; HUPSKIP(); if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) - panic(winpanicstr, window); + ttywindowpanic(); if (cw->flags & WIN_CANCELLED) return; ttyDisplay->lastwin = window; @@ -2312,12 +1874,13 @@ boolean blocking; /* with ttys, all windows are blocking */ switch (cw->type) { case NHW_MESSAGE: - if (ttyDisplay->toplin == 1) { + if (ttyDisplay->toplin == TOPLINE_NEED_MORE) { more(); - ttyDisplay->toplin = 1; /* more resets this */ + ttyDisplay->toplin = TOPLINE_NEED_MORE; /* more resets this */ tty_clear_nhwindow(window); + nhassert(ttyDisplay->toplin == TOPLINE_EMPTY); } else - ttyDisplay->toplin = 0; + ttyDisplay->toplin = TOPLINE_EMPTY; cw->curx = cw->cury = 0; if (!cw->active) iflags.window_inited = TRUE; @@ -2325,17 +1888,19 @@ boolean blocking; /* with ttys, all windows are blocking */ case NHW_MAP: end_glyphout(); if (blocking) { - if (!ttyDisplay->toplin) - ttyDisplay->toplin = 1; + if (ttyDisplay->toplin != TOPLINE_EMPTY) + ttyDisplay->toplin = TOPLINE_NEED_MORE; tty_display_nhwindow(WIN_MESSAGE, TRUE); return; } + FALLTHROUGH; /*FALLTHRU*/ case NHW_BASE: (void) fflush(stdout); break; case NHW_TEXT: cw->maxcol = ttyDisplay->cols; /* force full-screen mode */ + FALLTHROUGH; /*FALLTHRU*/ case NHW_MENU: cw->active = 1; @@ -2356,7 +1921,7 @@ boolean blocking; /* with ttys, all windows are blocking */ cw->offx = 0; if (cw->type == NHW_MENU) cw->offy = 0; - if (ttyDisplay->toplin == 1) + if (ttyDisplay->toplin == TOPLINE_NEED_MORE) tty_display_nhwindow(WIN_MESSAGE, TRUE); #ifdef H2344_BROKEN if (cw->maxrow >= (int) ttyDisplay->rows @@ -2371,8 +1936,8 @@ boolean blocking; /* with ttys, all windows are blocking */ tty_curs(window, 1, 0); cl_eos(); } else - clear_screen(); - ttyDisplay->toplin = 0; + term_clear_screen(); + ttyDisplay->toplin = TOPLINE_EMPTY; } else { if (WIN_MESSAGE != WIN_ERR) tty_clear_nhwindow(WIN_MESSAGE); @@ -2388,21 +1953,22 @@ boolean blocking; /* with ttys, all windows are blocking */ } void -tty_dismiss_nhwindow(window) -winid window; +tty_dismiss_nhwindow(winid window) { - register struct WinDesc *cw = 0; + struct WinDesc *cw = 0; HUPSKIP(); if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) - panic(winpanicstr, window); + ttywindowpanic(); print_vt_code2(AVTC_SELECT_WINDOW, window); switch (cw->type) { case NHW_MESSAGE: - if (ttyDisplay->toplin) + if (ttyDisplay->toplin != TOPLINE_EMPTY) tty_display_nhwindow(WIN_MESSAGE, TRUE); + nhassert(ttyDisplay->toplin == TOPLINE_EMPTY); + FALLTHROUGH; /*FALLTHRU*/ case NHW_STATUS: case NHW_BASE: @@ -2416,15 +1982,24 @@ winid window; break; case NHW_MENU: case NHW_TEXT: + case NHW_PERMINVENT: if (cw->active) { - if (iflags.window_inited) { - /* otherwise dismissing the text endwin after other windows - * are dismissed tries to redraw the map and panics. since - * the whole reason for dismissing the other windows was to - * leave the ending window on the screen, we don't want to - * erase it anyway. - */ - erase_menu_or_text(window, cw, FALSE); + /* skip erasure if window_inited has been reset to 0 during + final run-down in case this is the end-of-game window; + the contents of that window should remain shown even when + the window itself has gone away */ + if (iflags.window_inited && !erasing_tty_screen) { + boolean clearscreen = FALSE; /* just erase the menu */ + + /* during role/race/&c selection, menus are put up on top + of the base window; we don't track what was there so + can't refresh--force the screen to be cleared instead + (affects dismissal of 'reset role filtering' menu if + screen height forces that to need a second page) */ + if (program_state.in_role_selection) + clearscreen = TRUE; + + erase_menu_or_text(window, cw, clearscreen); } cw->active = 0; } @@ -2434,31 +2009,58 @@ winid window; } void -tty_destroy_nhwindow(window) -winid window; +tty_destroy_nhwindow(winid window) { - register struct WinDesc *cw = 0; + struct WinDesc *cw = 0; - if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) - panic(winpanicstr, window); + if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) { + if (window == WIN_INVEN) /* Null wins[WIN_INVEN] is tolerated */ + return; + ttywindowpanic(); + } if (cw->active) tty_dismiss_nhwindow(window); if (cw->type == NHW_MESSAGE) iflags.window_inited = 0; if (cw->type == NHW_MAP) - clear_screen(); - + term_clear_screen(); +#ifdef TTY_PERM_INVENT + if (cw->type == NHW_MENU && cw->mbehavior == MENU_BEHAVE_PERMINV) + ttyinv_remove_data(cw, TRUE); +#endif free_window_info(cw, TRUE); free((genericptr_t) cw); wins[window] = 0; /* available for re-use */ } +/* when screen is cleared, reset stored data to spaces */ void -tty_curs(window, x, y) -winid window; -register int x, y; /* not xchar: perhaps xchar is unsigned and - curx-x would be unsigned as well */ +erase_tty_screen(void) +{ + struct WinDesc *cw; + int i; + + HUPSKIP(); + if (erasing_tty_screen++) + return; +#if 0 /* originally we called term_clear_screen() but now it calls us */ + term_clear_screen(); /* erase the screen */ +#endif + /* update window data to reflect that each active window is all blanks */ + for (i = 0; i < MAXWIN; ++i) { + cw = wins[i]; + if (cw && cw->active) + tty_clear_nhwindow(i); + } + tty_curs(BASE_WINDOW, 1, 0); + erasing_tty_screen = 0; +} + +void +tty_curs( + winid window, + int x, int y) /* coordinates (and curx-x) must be signed */ { struct WinDesc *cw = 0; int cx = ttyDisplay->curx; @@ -2466,18 +2068,17 @@ register int x, y; /* not xchar: perhaps xchar is unsigned and HUPSKIP(); if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) - panic(winpanicstr, window); + ttywindowpanic(); ttyDisplay->lastwin = window; print_vt_code2(AVTC_SELECT_WINDOW, window); -#if defined(USE_TILES) && defined(MSDOS) +#if defined(TILES_IN_GLYPHMAP) && defined(MSDOS) adjust_cursor_flags(cw); #endif - cw->curx = --x; /* column 0 is never used */ - cw->cury = y; + #ifdef DEBUG - if (x < 0 || y < 0 || y >= cw->rows || x > cw->cols) { + if (x < 1 || y < 0 || y >= cw->rows || x > cw->cols) { const char *s = "[unknown type]"; switch (cw->type) { @@ -2500,17 +2101,21 @@ register int x, y; /* not xchar: perhaps xchar is unsigned and s = "[base window]"; break; } - debugpline4("bad curs positioning win %d %s (%d,%d)", window, s, x, y); - /* This return statement caused a functional difference between - DEBUG and non-DEBUG operation, so it is being commented - out. It caused tty_curs() to fail to move the cursor to the - location it needed to be if the x,y range checks failed, - leaving the next piece of output to be displayed at whatever - random location the cursor happened to be at prior. */ - - /* return; */ + /* avoid sending a line to the message window if we're complaining + about cursor positioning in message window; perhaps raw_printf? + this ought to be using impossible() so that someone might + actually see it */ + if (cw->type != NHW_MESSAGE) + debugpline4("tty_curs: bad positioning win %d %s <%d,%d>", + window, s, x, y); + /* don't try to fix up x,y here because then tty_curs() would + behave differently depending on whether DEBUG is defined; + garbage in, garbage out is the order of the day... */ } -#endif +#endif /* DEBUG */ + cw->curx = --x; /* column 0 is not used */ + cw->cury = y; + x += cw->offx; y += cw->offy; @@ -2555,23 +2160,24 @@ register int x, y; /* not xchar: perhaps xchar is unsigned and ttyDisplay->cury = y; } -STATIC_OVL void -tty_putsym(window, x, y, ch) -winid window; -int x, y; -char ch; +#ifndef STATUS_HILITES +static void +tty_putsym(winid window, int x, int y, char ch) { - register struct WinDesc *cw = 0; + struct WinDesc *cw = 0; HUPSKIP(); if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) - panic(winpanicstr, window); + ttywindowpanic(); print_vt_code2(AVTC_SELECT_WINDOW, window); switch (cw->type) { #ifndef STATUS_HILITES case NHW_STATUS: +#endif +#ifdef TTY_PERM_INVENT + case NHW_PERMINVENT: #endif case NHW_MAP: case NHW_BASE: @@ -2587,17 +2193,17 @@ char ch; break; } } +#endif -STATIC_OVL const char * -compress_str(str) -const char *str; +static const char * +compress_str(const char *str) { static char cbuf[BUFSZ]; /* compress out consecutive spaces if line is too long; topline wrapping converts space at wrap point into newline, we reverse that here */ - if ((int) strlen(str) >= CO || index(str, '\n')) { + if ((int) strlen(str) >= CO || strchr(str, '\n')) { const char *in_str = str; char c, *outstr = cbuf, *outend = &cbuf[sizeof cbuf - 1]; boolean was_space = TRUE; /* True discards all leading spaces; @@ -2620,17 +2226,14 @@ const char *str; } void -tty_putstr(window, attr, str) -winid window; -int attr; -const char *str; +tty_putstr(winid window, int attr, const char *str) { - register struct WinDesc *cw = 0; - register char *ob; - register long i, n0; + struct WinDesc *cw = 0; + char *ob; + long i, n0; #ifndef STATUS_HILITES - register const char *nb; - register long j; + const char *nb; + long j; #endif HUPSKIP(); @@ -2645,7 +2248,11 @@ const char *str; if (str == (const char *) 0 || ((cw->flags & WIN_CANCELLED) && (cw->type != NHW_MESSAGE))) return; - if (cw->type != NHW_MESSAGE) + if (cw->type != NHW_MESSAGE +#ifdef TTY_PERM_INVENT + && window != WIN_INVEN +#endif + ) str = compress_str(str); ttyDisplay->lastwin = window; @@ -2654,16 +2261,34 @@ const char *str; switch (cw->type) { case NHW_MESSAGE: { - int suppress_history = (attr & ATR_NOHISTORY); + int suppress_history = (attr & ATR_NOHISTORY), + urgent_message = (attr & ATR_URGENT); + +#if defined(ASCIIGRAPH) && !defined(NO_TERMS) + /* if ^C occurs, player is prompted with "Really quit?" and that + prompt is issued via tty_putstr(WIN_MESSAGE); if ^C happens + while writing DECgraphics chars, the prompt text would be + rendered as VT line-drawing characters unless we do this; + also, if color was in progress it wouldn't be switched off */ + end_glyphout(); +#endif + /* if message is designated 'urgent' don't suppress it if user has + typed ESC at --More-- prompt when dismissing an earlier message; + besides turning off WIN_STOP, we need to prevent current message + from provoking --More-- and giving the user another chance at + using ESC to suppress, otherwise this message wouldn't get shown */ + if (urgent_message) { + if ((cw->flags & WIN_STOP) != 0) { + tty_clear_nhwindow(WIN_MESSAGE); + cw->flags &= ~WIN_STOP; + } + cw->flags |= WIN_NOSTOP; + } /* in case we ever support display attributes for topline messages, clear flag mask leaving only display attr */ /*attr &= ~(ATR_URGENT | ATR_NOHISTORY);*/ - /* really do this later */ -#if defined(USER_SOUNDS) && defined(WIN32CON) - play_sound_for_message(str); -#endif if (!suppress_history) { /* normal output; add to current top line if room, else flush whatever is there to history and then write this */ @@ -2674,23 +2299,25 @@ const char *str; /* write to top line without remembering what we're writing */ show_topl(str); } + + cw->flags &= ~WIN_NOSTOP; /* NOSTOP is a one-shot operation */ break; } #ifndef STATUS_HILITES case NHW_STATUS: ob = &cw->data[cw->cury][j = cw->curx]; - if (context.botlx) + if (disp.botlx) *ob = '\0'; if (!cw->cury && (int) strlen(str) >= CO) { /* the characters before "St:" are unnecessary */ - nb = index(str, ':'); + nb = strchr(str, ':'); if (nb && nb > str + 2) str = nb - 2; } nb = str; for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { if (!*nb) { - if (*ob || context.botlx) { + if (*ob || disp.botlx) { /* last char printed may be in middle of line */ tty_curs(WIN_STATUS, i, cw->cury); cl_end(); @@ -2794,22 +2421,24 @@ const char *str; } break; } + return; } void -tty_display_file(fname, complain) -const char *fname; -boolean complain; +tty_display_file( + const char *fname, /* name of file to display */ + boolean complain) /* whether to report problem if file can't be opened */ { #ifdef DEF_PAGER /* this implies that UNIX is defined */ + /* FIXME: this won't work if fname is inside a dlb container */ { /* use external pager; this may give security problems */ - register int fd = open(fname, 0); + int fd = open(fname, O_RDONLY); if (fd < 0) { if (complain) pline("Cannot open %s.", fname); - else + else /* [is this refresh actually necessary?] */ docrt(); return; } @@ -2822,18 +2451,15 @@ boolean complain; if (complain) raw_printf("Cannot open %s as stdin.", fname); } else { - (void) execlp(catmore, "page", (char *) 0); + (void) execlp(gc.catmore, "page", (char *) 0); if (complain) - raw_printf("Cannot exec %s.", catmore); + raw_printf("Cannot exec %s.", gc.catmore); } if (complain) sleep(10); /* want to wait_synch() but stdin is gone */ nh_terminate(EXIT_FAILURE); } (void) close(fd); -#ifdef notyet - winch_seen = 0; -#endif } #else /* DEF_PAGER */ { @@ -2849,10 +2475,11 @@ boolean complain; tty_mark_synch(); tty_raw_print(""); perror(fname); - tty_wait_synch(); + tty_wait_synch(); /* "Hit to continue: " */ + if (u.ux) /* if hero is on map, refresh the screen */ + docrt(); pline("Cannot open \"%s\".", fname); - } else if (u.ux) - docrt(); + } } else { winid datawin = tty_create_nhwindow(NHW_TEXT); boolean empty = TRUE; @@ -2863,18 +2490,18 @@ boolean complain; #endif ) { /* attempt to scroll text below map window if there's room */ - wins[datawin]->offy = wins[WIN_STATUS]->offy + 3; + wins[datawin]->offy = wins[WIN_STATUS]->offy + StatusRows(); if ((int) wins[datawin]->offy + 12 > (int) ttyDisplay->rows) wins[datawin]->offy = 0; } while (dlb_fgets(buf, BUFSZ, f)) { - if ((cr = index(buf, '\n')) != 0) + if ((cr = strchr(buf, '\n')) != 0) *cr = 0; #ifdef MSDOS - if ((cr = index(buf, '\r')) != 0) + if ((cr = strchr(buf, '\r')) != 0) *cr = 0; #endif - if (index(buf, '\t') != 0) + if (strchr(buf, '\t') != 0) (void) tabexpand(buf); empty = FALSE; tty_putstr(datawin, 0, buf); @@ -2888,33 +2515,64 @@ boolean complain; } } #endif /* DEF_PAGER */ + return; } void -tty_start_menu(window) -winid window; +tty_start_menu(winid window, unsigned long mbehavior) { + struct WinDesc *cw = 0; + + if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) + ttywindowpanic(); + +#ifdef TTY_PERM_INVENT + if (cw->mbehavior == MENU_BEHAVE_PERMINV) { + /* PERMINV is ready to go already; not much to do here */ + inuse_only_start = 0; + return; + } + if (mbehavior == MENU_BEHAVE_PERMINV + && (iflags.perm_invent + || gp.perm_invent_toggling_direction == toggling_on)) { + winid w = ttyinv_create_window(window, wins[window]); + + if (w == WIN_ERR) { + ; /* something went wrong, so add clean up code here */ + } else { + cw->mbehavior = mbehavior; + WIN_INVEN = w; + } + return; + } +#else + nhUse(mbehavior); +#endif + tty_clear_nhwindow(window); return; } -/*ARGSUSED*/ + /*ARGSUSED*/ /* * Add a menu item to the beginning of the menu list. This list is reversed * later. */ void -tty_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) -winid window; /* window to use, must be of type NHW_MENU */ -int glyph UNUSED; /* glyph to display with item (not used) */ -const anything *identifier; /* what to return if selected */ -char ch; /* keyboard accelerator (0 = pick our own) */ -char gch; /* group accelerator (0 = no group) */ -int attr; /* attribute for string (like tty_putstr()) */ -const char *str; /* menu string */ -boolean preselected; /* item is marked as selected */ +tty_add_menu( + winid window, /* window to use, must be of type NHW_MENU */ + const glyph_info *glyphinfo, /* glyph info with glyph to + * display with item */ + const anything *identifier, /* what to return if selected */ + char ch, /* selector letter (0 = pick our own) */ + char gch, /* group accelerator (0 = no group) */ + int attr, /* attribute for string (like tty_putstr()) */ + int clr, /* color for string */ + const char *str, /* menu string */ + unsigned int itemflags) /* itemflags such as MENU_ITEMFLAGS_SELECTED */ { - register struct WinDesc *cw = 0; + boolean preselected = ((itemflags & MENU_ITEMFLAGS_SELECTED) != 0); + struct WinDesc *cw = 0; tty_menu_item *item; const char *newstr; char buf[4 + BUFSZ]; @@ -2926,7 +2584,14 @@ boolean preselected; /* item is marked as selected */ if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 || cw->type != NHW_MENU) - panic(winpanicstr, window); + ttywindowpanic(); + +#ifdef TTY_PERM_INVENT + if (cw->mbehavior == MENU_BEHAVE_PERMINV) { + ttyinv_add_menu(window, cw, ch, attr, clr, str); + return; + } +#endif cw->nitems++; if (identifier->a_void) { @@ -2948,19 +2613,21 @@ boolean preselected; /* item is marked as selected */ item->identifier = *identifier; item->count = -1L; item->selected = preselected; + item->itemflags = itemflags; item->selector = ch; item->gselector = gch; item->attr = attr; - item->str = dupstr(newstr ? newstr : ""); + item->color = clr; + item->str = dupstr(newstr); + item->glyphinfo = *glyphinfo; item->next = cw->mlist; cw->mlist = item; } /* Invert the given list, can handle NULL as an input. */ -STATIC_OVL tty_menu_item * -reverse(curr) -tty_menu_item *curr; +static tty_menu_item * +reverse(tty_menu_item *curr) { tty_menu_item *next, *head = 0; @@ -2973,6 +2640,8 @@ tty_menu_item *curr; return head; } +static color_attr tty_menu_promptstyle = { NO_COLOR, ATR_NONE }; + /* * End a menu in this window, window must a type NHW_MENU. This routine * processes the string list. We calculate the # of pages, then assign @@ -2980,19 +2649,33 @@ tty_menu_item *curr; * height of the window. */ void -tty_end_menu(window, prompt) -winid window; /* menu to use */ -const char *prompt; /* prompt to for menu */ +tty_end_menu( + winid window, /* menu to use */ + const char *prompt) /* prompt to for menu */ { struct WinDesc *cw = 0; tty_menu_item *curr; short len; int lmax, n; char menu_ch; + int clr = NO_COLOR; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 - || cw->type != NHW_MENU) - panic(winpanicstr, window); + || cw->type != NHW_MENU) { + /* this can happen if start_menu failed due to size requirements + for the tty perm inventory window. It isn't a situation that + requires a panic, just an early return. */ + if (window == WIN_INVEN && !cw) + return; + ttywindowpanic(); + } +#ifdef TTY_PERM_INVENT + /* (probably don't need to check both of these conditions) */ + if (cw->mbehavior == MENU_BEHAVE_PERMINV && window == WIN_INVEN) { + ttyinv_end_menu(window, cw); + return; + } +#endif /* Reverse the list so that items are in correct order. */ cw->mlist = reverse(cw->mlist); @@ -3001,11 +2684,12 @@ const char *prompt; /* prompt to for menu */ if (prompt) { anything any; - any = zeroany; /* not selectable */ - tty_add_menu(window, NO_GLYPH, &any, 0, 0, ATR_NONE, "", - MENU_UNSELECTED); - tty_add_menu(window, NO_GLYPH, &any, 0, 0, ATR_NONE, prompt, - MENU_UNSELECTED); + any = cg.zeroany; /* not selectable */ + tty_add_menu(window, &nul_glyphinfo, &any, 0, 0, + ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE); + tty_add_menu(window, &nul_glyphinfo, &any, 0, 0, + tty_menu_promptstyle.attr, tty_menu_promptstyle.color, + prompt, MENU_ITEMFLAGS_NONE); } /* 52: 'a'..'z' and 'A'..'Z'; avoids selector duplication within a page */ @@ -3069,123 +2753,882 @@ const char *prompt; /* prompt to for menu */ len = strlen(cw->morestr); } - if (len > (int) ttyDisplay->cols) { - /* truncate the prompt if it's too long for the screen */ - if (cw->npages <= 1) /* only str in single page case */ - cw->morestr[ttyDisplay->cols] = 0; - len = ttyDisplay->cols; - } - if (len > cw->cols) - cw->cols = len; + if (len > (int) ttyDisplay->cols) { + /* truncate the prompt if it's too long for the screen */ + if (cw->npages <= 1) /* only str in single page case */ + cw->morestr[ttyDisplay->cols] = 0; + len = ttyDisplay->cols; + } + if (len > cw->cols) + cw->cols = len; + + cw->maxcol = cw->cols; + + /* + * The number of lines in the first page plus the morestr will be the + * maximum size of the window. + */ + if (cw->npages > 1) + cw->maxrow = cw->rows = lmax + 1; + else + cw->maxrow = cw->rows = cw->nitems + 1; +} + +int +tty_select_menu(winid window, int how, menu_item **menu_list) +{ + struct WinDesc *cw = 0; + tty_menu_item *curr; + menu_item *mi; + int n, cancelled; + + if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 + || cw->type != NHW_MENU) + ttywindowpanic(); + + if (cw->mbehavior == MENU_BEHAVE_PERMINV) { + return 0; + } + *menu_list = (menu_item *) 0; + cw->how = (short) how; + morc = 0; + tty_display_nhwindow(window, TRUE); + cancelled = !!(cw->flags & WIN_CANCELLED); + tty_dismiss_nhwindow(window); /* does not destroy window data */ + + if (cancelled) { + n = -1; + } else { + for (n = 0, curr = cw->mlist; curr; curr = curr->next) + if (curr->selected) + n++; + } + + if (n > 0) { + *menu_list = (menu_item *) alloc(n * sizeof(menu_item)); + for (mi = *menu_list, curr = cw->mlist; curr; curr = curr->next) + if (curr->selected) { + mi->item = curr->identifier; + mi->count = curr->count; + mi++; + } + } + + return n; +} + +/* special hack for treating top line --More-- as a one item menu */ +char +tty_message_menu(char let, int how, const char *mesg) +{ + HUPSKIP_RESULT('\033'); + /* "menu" without selection; use ordinary pline, no more() */ + if (how == PICK_NONE) { + pline("%s", mesg); + return 0; + } + + ttyDisplay->dismiss_more = let; + morc = 0; + /* barebones pline(); since we're only supposed to be called after + response to a prompt, we'll assume that the display is up to date */ + tty_putstr(WIN_MESSAGE, 0, mesg); + /* if `mesg' didn't wrap (triggering --More--), force --More-- now */ + if (ttyDisplay->toplin == TOPLINE_NEED_MORE) { + more(); + ttyDisplay->toplin = TOPLINE_NEED_MORE; /* more resets this */ + tty_clear_nhwindow(WIN_MESSAGE); + nhassert(ttyDisplay->toplin == TOPLINE_EMPTY); + } + /* normally means skip further messages, but in this case + it means cancel the current prompt; any other messages should + continue to be output normally */ + wins[WIN_MESSAGE]->flags &= ~WIN_CANCELLED; + ttyDisplay->dismiss_more = 0; + + return ((how == PICK_ONE && morc == let) || morc == '\033') ? morc : '\0'; +} + +win_request_info * +tty_ctrl_nhwindow( + winid window UNUSED, + int request, + win_request_info *wri) +{ +#if defined(TTY_PERM_INVENT) + boolean tty_ok /*, show_gold */, inuse_only; + int maxslot; + /* these types are set match the wintty.h field declarations */ + long minrow; /* long to match maxrow declaration in wintty.h */ + short offx, offy; + long rows, cols, maxrow, maxcol; +#endif + + if (!wri) + return (win_request_info *) 0; + + switch (request) { + case set_mode: + case request_settings: +#if defined(TTY_PERM_INVENT) + ttyinvmode = wri->fromcore.invmode; + if (request == set_mode) + break; + /* show_gold = (ttyinvmode & InvShowGold) != 0; */ + inuse_only = ((ttyinvmode & InvInUse) != 0); + wri->tocore = zero_tocore; + tty_ok = assesstty(ttyinvmode, &offx, &offy, &rows, &cols, &maxcol, + &minrow, &maxrow); + if (!tty_ok && rows == 0 && cols == 0) { + /* something is terribly wrong, possibly too early in startup */ + wri->tocore.tocore_flags |= too_early; + } else { + wri->tocore.needrows = (int) (minrow + 1 + ROWNO + StatusRows()); + wri->tocore.needcols = (int) tty_perminv_mincol; + wri->tocore.haverows = (int) ttyDisplay->rows; + wri->tocore.havecols = (int) ttyDisplay->cols; + if (!tty_ok) { +#ifdef RESIZABLE + /* terminal isn't big enough right now but player might + * resize it and then use 'm O' to try to set 'perm_invent' + * again + */ + wri->tocore.tocore_flags |= too_small; +#else + wri->tocore.tocore_flags |= prohibited; +#endif + } else { + maxslot = (maxrow - 2) * (!inuse_only ? 2 : 1); + wri->tocore.maxslot = maxslot; + } + } +#endif /* TTY_PERM_INVENT */ + break; + case set_menu_promptstyle: + tty_menu_promptstyle = wri->fromcore.menu_promptstyle; + break; + default: + break; + } + return wri; +} + +#ifdef TTY_PERM_INVENT + +static int +ttyinv_create_window(int newid, struct WinDesc *newwin) +{ + int r, c; + long minrow; /* long to match maxrow declaration */ + unsigned n; + + /* Is there enough real estate to do this beyond the status line? + * Rows: + * Top border line (1) + * 26 inventory rows (26) + * [should be 27 to have room for '$' and '#'] + * Bottom border line (1) + * 1 + 26 + 1 = 28 + * + * Cols: + * Left border (1) + * Left inventory items (38) + * Middle separation (1) + * Right inventory items (38) + * Right border (1) + * 1 + 38 + 1 + 38 + 1 = 79 + * + * The topline + map rows + status lines require: + * 1 + 21 + 2 (or 3) = 24 (or 25 depending on status line count). + * So we can only present a full inventory on tty if there are + * 28 + 24 (or 25) available (52 or 53 rows on the terminal). + * Correspondingly ttyDisplay->rows has to be at least 52 (or 53). + * [The top and bottom borderlines aren't necessary. Suppressing + * them would reduce the number of rows needed by 2.] + * + */ + + /* preliminary init in case tty_destroy_nhwindow() gets called */ + newwin->data = (char **) 0; + newwin->datlen = (short *) 0; + newwin->cells = (struct tty_perminvent_cell **) 0; + + if (!assesstty(ttyinvmode, &newwin->offx, &newwin->offy, &newwin->rows, + &newwin->cols, &newwin->maxcol, &minrow, + &newwin->maxrow)) { + tty_destroy_nhwindow(newid); + WIN_INVEN = WIN_ERR; + pline("%s.", "tty perm_invent could not be enabled"); + pline("tty perm_invent needs a terminal that is at least %dx%d, " + "yours is %dx%d.", + (int) (minrow + 1 + ROWNO + StatusRows()), tty_perminv_mincol, + ttyDisplay->rows, ttyDisplay->cols); + tty_wait_synch(); +#ifndef RESIZABLE + set_option_mod_status("perm_invent", set_gameview); +#endif + iflags.perm_invent = FALSE; + return WIN_ERR; + } + + /* + * Terminal/window/screen is big enough. + */ + /*newwin->maxrow = minrow;*/ + newwin->maxcol = newwin->cols; + /* establish the borders */ + bordercol[border_left] = 0; + bordercol[border_middle] = (newwin->maxcol + 1) / 2; + bordercol[border_right] = newwin->maxcol - 1; + /* for in-use mode, use full lines; it will switch to two panels if + there are more items than the number of full lines */ + if ((ttyinvmode & InvInUse) != 0) + bordercol[border_middle] = bordercol[border_right]; + ttyinv_slots_used = 0; + + n = (unsigned) (newwin->maxrow * sizeof (struct tty_perminvent_cell *)); + newwin->cells = (struct tty_perminvent_cell **) alloc(n); + + n = (unsigned) (newwin->maxcol * sizeof (struct tty_perminvent_cell)); + for (r = 0; r < newwin->maxrow; r++) { + newwin->cells[r] = (struct tty_perminvent_cell *) alloc(n); + for (c = 0; c < newwin->maxcol; c++) + newwin->cells[r][c] = emptyttycell; + } + newwin->active = 1; + tty_invent_box_glyph_init(newwin); + + return newid; +} + +/* discard perminvent window or erase it and set remembered data to spaces */ +static void +ttyinv_remove_data(struct WinDesc *cw, boolean destroy) +{ + if (!cw) { + impossible("Removing ttyinv data for nonexistent perm invent window?"); + return; + } + + if (cw->cells) { + int r, c; + + for (r = 0; r < cw->maxrow; r++) { + if (cw->cells[r]) { + for (c = 0; c < cw->maxcol; c++) { + struct tty_perminvent_cell *invcell = &cw->cells[r][c]; + + /* glyph is a flag indicating whether content union + contains a glyph_info structure or just a char */ + if (invcell->glyph) + free((genericptr_t) invcell->content.gi); + *invcell = emptyttycell; /* sets glyph flag to 0 */ + if (!destroy) { /* erasing */ + invcell->content.ttychar = ' '; + invcell->text = 1; + invcell->refresh = 1; /* full redraw wanted */ + } + } + if (destroy) + free((genericptr_t) cw->cells[r]), + cw->cells[r] = (struct tty_perminvent_cell *) 0; + } + } + if (destroy) { + free((genericptr_t) cw->cells), + cw->cells = (struct tty_perminvent_cell **) 0; + cw->rows = cw->cols = 0; + } + } + if (destroy) { + cw->maxrow = cw->maxcol = 0; + /*WIN_INVEN = WIN_ERR;*/ /* caller's responsibility */ + done_tty_perm_invent_init = FALSE; + } + ttyinv_slots_used = 0; /* reset: inuse_only isn't using any slots */ +} + +static void +ttyinv_add_menu( + winid window UNUSED, + struct WinDesc *cw, + char ch, + int attr UNUSED, int clr, + const char *str) +{ + char invbuf[BUFSZ]; + const char *text; + boolean show_gold = (ttyinvmode & InvShowGold) != 0, + inuse_only = (ttyinvmode & InvInUse) != 0, + ignore = FALSE; + int row, side, slot, startcolor_at = 0, + rows_per_side = (inuse_only ? (cw->maxrow - 2) + : !show_gold ? 26 + : 27); + + if (!program_state.in_moveloop) + return; + slot = selector_to_slot(ch, ttyinvmode, &ignore); + if (inuse_only && slot > 2 * rows_per_side) + ignore = TRUE; /* left & right sides full; no 3rd 'side' available */ + if (!ignore) { + slot_tracker[slot] = TRUE; + /* if we need to expand inuse_only from one side to two, do so now; + entries are shown in row 1 thru rows_per_side (with rows 0 and + rows_per_side+1 containing boundary lines) but stored in + slots 0 thru rows_per_side-1, so zero-based slot==rows_per_side + is the entry that will be shown on first row of the second side + (and one-base ttyinv_slots_used==rows_per_side means that on the + previous inventory_update(), full lines filled all the rows; + ttyinv_slots_used==0 means that we've just enabled perm_invent) */ + if (inuse_only && slot == rows_per_side + && ttyinv_slots_used % rows_per_side == 0) + ttyinv_inuse_twosides(cw, rows_per_side); + + text = str; /* 'text' will switch to invbuf[] below */ + /* strip away "a"/"an"/"the" prefix to show a bit more of + the interesting part of the object's description; this + is inline version of pi_article_skip() from cursinvt.c; + should move that to hacklib.c and use it here */ + if (text[0] == 'a') { + if (text[1] == ' ') + text += 2; + else if (text[1] == 'n' && text[2] == ' ') + text += 3; + } else if (text[0] == 't') { + if (text[1] == 'h' && text[2] == 'e' && text[3] == ' ') + text += 4; + } + /* + * TODO? + * Replace "c - " prefix with "c: " or just "c " to have a bit more + * room for 'text' (the item description). If this prefix gets + * changed, the indentation for empty inventory in ttyinv_render() + * should be changed to match. + */ + Snprintf(invbuf, sizeof invbuf, "%c - %s", ch, text); + text = invbuf; + startcolor_at = (int) (sizeof "a - " - sizeof ""); /* 4 */ + row = (slot % rows_per_side) + 1; /* +1: top border */ + /* side: left side panel or right side panel, not a window column */ + side = slot / rows_per_side; + ttyinv_populate_slot(cw, row, side, text, + (uint32) clr, startcolor_at); + } + return; +} + +/* convert a..zA..Z to 0..51 or for 'show_gold' $a..zA..Z# to 0..53 */ +static int +selector_to_slot( + char ch, + const int invflags, + boolean *ignore) +{ + int slot = 0; + boolean show_gold = (invflags & InvShowGold) != 0, + inuse_only = (invflags & InvInUse) != 0; + + *ignore = FALSE; + if (inuse_only) { + /* + * Inuse_only uses slots 0 to N-1 instead of fixed positions. + * Caller--or caller's caller's ... caller--only passes us + * relevant items so no filtering is necessary here. + * '!show_gold' gets ignored here since gold might be quivered + * and become an in-use item. + * Inuse_only items might include one (or more than one) with + * invlet '#' but it isn't special for Inuse_only. + * When nothing is in use, the core sends a menu header line to + * to indicate such in order to avoid having an empty menu; we + * ignore that and reconstruct one in ttyinv_render(). + */ + if (!ch) + *ignore = TRUE; + else + slot = inuse_only_start++; + } else { + /* normal perminv */ + switch (ch) { + case '$': + if (!show_gold) + *ignore = TRUE; + else + slot = 0; + break; + case '#': + /* overflow item won't be gold but there is only room allocated + for it when gold is also eligible to be shown (hero doesn't + have to be carrying any, we just need the extra row it gets) */ + if (!show_gold) + *ignore = TRUE; + else + /* fixed location, bottom of right-hand panel; if there is + more than 1 overflow item, we are only able to show 1 */ + slot = 0 + 52 + 1; /* 0 for gold, 2 * 26 letters, then '#' */ + break; + case '\0': + *ignore = TRUE; + break; + default: + if (ch >= 'a' && ch <= 'z') + slot = (ch - 'a') + (show_gold ? 1 : 0); + else if (ch >= 'A' && ch <= 'Z') + slot = (ch - 'A') + (show_gold ? 1 : 0) + 26; + break; + } + } /* normal vs inuse_only */ + return slot; +} + +static char +slot_to_invlet(int slot, boolean incl_gold) +{ + char res = '\0'; + + switch (slot) { + case 0: + res = incl_gold ? '$' : 'a'; + break; + case 53: + /* if (!incl_gold) impossible("ttyinv_render: slot %d?", slot); */ + res = '#'; + break; + default: + if (incl_gold) + --slot; /* simplify 1..52 (0 and 53 won't get here) to 0..51 */ + res = (slot < 26) ? ('a' + slot) + : (slot < 52) ? ('A' + slot - 26) + : '?'; /* won't happen */ + break; + } + return res; +} + +/* called if inuse_only contracts from two sides to one; there won't be + full lines shown until the next inventory update because the data past + the middle boundary was clipped rather than saved; caller or caller's + caller or somewhere up the call chain will call update_inventory() to + redraw it all and rectify that */ +static void +ttyinv_inuse_fulllines( + struct WinDesc *cw, + int rows_per_side UNUSED) +{ + bordercol[border_middle] = bordercol[border_right]; + tty_invent_box_glyph_init(cw); +} + +/* called when inuse_only expands from full lines (one side) to two sides */ +static void +ttyinv_inuse_twosides( + struct WinDesc *cw, + int rows_per_side) +{ + int row, col; + + bordercol[border_middle] = (cw->maxcol + 1) / 2; + tty_invent_box_glyph_init(cw); + /* draw the middle boundary */ + col = bordercol[border_middle]; + for (row = 0; row <= rows_per_side; ++row) + tty_refresh_inventory(col, col, row); +} + +/* split out of tty_end_menu(); persistent inventory is ready to display */ +static void +ttyinv_end_menu(int window, struct WinDesc *cw) +{ + if (iflags.perm_invent + || gp.perm_invent_toggling_direction == toggling_on) { + if (program_state.in_moveloop) { + boolean inuse_only = ((ttyinvmode & InvInUse) != 0); + int rows_per_side = inuse_only ? cw->maxrow - 2 : 0; + int old_slots_used = ttyinv_slots_used; /* value before render */ + + ttyinv_render(window, cw); + + /* if inuse_only was using two sides and has just shrunk to one, + it will switch to full rows instead of side-by-side panels + but current data only holds the left-hand panel's portion; + rerun the whole thing to regenerate previously clipped data; + fortunately this should be a fairly rare occurrence */ + if (inuse_only && old_slots_used > rows_per_side + /* 'ttyinv_slots_used' was just updated by ttyinv_render() + to the number of entries currently shown */ + && ttyinv_slots_used <= rows_per_side) + tty_update_inventory(0); /* will call back to core for data */ + } + } +} + +/* display persistent inventory from data collected by add_menu() */ +static void +ttyinv_render(winid window, struct WinDesc *cw) +{ + int row, col, slot, side, filled_count = 0, slot_limit; + uint32 current_row_color = NO_COLOR; + struct tty_perminvent_cell *cell; + char invbuf[BUFSZ]; + boolean force_redraw = program_state.in_docrt ? TRUE : FALSE, + inuse_only = (ttyinvmode & InvInUse) != 0, + show_gold = (ttyinvmode & InvShowGold) != 0 && !inuse_only, + sparse = (ttyinvmode & InvSparse) != 0 && !inuse_only; + int rows_per_side = (inuse_only ? (cw->maxrow - 2) + : !show_gold ? 26 + : 27); + + slot_limit = SIZE(slot_tracker); + if (inuse_only) { + slot_limit = rows_per_side; /* assume one side */ + if (ttyinv_slots_used == 0 || ttyinv_slots_used >= rows_per_side) + slot_limit *= 2; /* second side is populated */ + } else if (!show_gold) { + slot_limit -= 2; /* there are two extra slots for gold and overflow; + * blanking them for !show_gold would wrap back to + * rows 1 and 2 and need non-existent third side */ + } + + for (slot = 0; slot < slot_limit; ++slot) + if (slot_tracker[slot]) + filled_count++; + /* clear unused slots */ + for (slot = 0; slot < slot_limit; ++slot) { + if (slot_tracker[slot]) + continue; + if (slot == 0 && !filled_count) { + Sprintf(invbuf, "%-4s[%s]", "", + inuse_only ? "no items are in use" + : (!show_gold && money_cnt(gi.invent)) ? "only gold" + : "empty"); + } else if (sparse && filled_count) { + Sprintf(invbuf, "%c", slot_to_invlet(slot, show_gold)); + } else { + invbuf[0] = '\0'; /* "" => fill slot with spaces */ + } + row = (slot % rows_per_side) + 1; /* +1: top border */ + /* side: left side panel or right side panel, not a window column */ + side = slot / rows_per_side; + ttyinv_populate_slot(cw, row, side, invbuf, NO_COLOR, 0); + } + + /* inuse_only might switch from one panel to two or vice versa */ + if (inuse_only && filled_count != ttyinv_slots_used) { + if (filled_count > rows_per_side + && ttyinv_slots_used <= rows_per_side) { + /* need second side; set up the middle border */ + /* done earlier, in add_menu(): + ttyinv_inuse_twosides(cw, rows_per_side); + */ + } else if (filled_count <= rows_per_side + && ttyinv_slots_used > rows_per_side) { + /* have second side but don't need/want it anymore */ + ttyinv_inuse_fulllines(cw, rows_per_side); + } + ttyinv_slots_used = filled_count; + } + + /* has there been a glyph reset since we last got here? */ + if (gg.glyph_reset_timestamp > last_glyph_reset_when) { + /* // tty_invent_box_glyph_init(wins[WIN_INVEN]); */ + last_glyph_reset_when = gg.glyph_reset_timestamp; + force_redraw = TRUE; + } + /* render to the display */ + calling_from_update_inventory = TRUE; + for (row = 0; row < cw->maxrow; ++row) { + for (col = 0; col < cw->maxcol; ++col) { + cell = &cw->cells[row][col]; + if (cell->refresh || force_redraw) { + if (cell->color && (current_row_color != cell->color - 1)) { + current_row_color = cell->color - 1; +#if 0 + if (current_row_color == NO_COLOR) + term_end_color(); + else +#endif + term_start_color(current_row_color); + } + if (cell->glyph) { + tty_print_glyph(window, col + 1, row, cell->content.gi, + &nul_glyphinfo); + end_glyphout(); + } else { + if (col != cw->curx || row != cw->cury) + tty_curs(window, col + 1, row); + (void) putchar(cell->content.ttychar); + ttyDisplay->curx++; + cw->curx++; + } + cell->refresh = 0; + } + } + if (current_row_color != NO_COLOR) + term_end_color(); + } + tty_curs(window, 1, 0); + for (slot = 0; slot < SIZE(slot_tracker); ++slot) + slot_tracker[slot] = FALSE; + calling_from_update_inventory = FALSE; + return; +} + +/* put the formatted object description for one item into a particular row + and left/right panel, truncating if long or padding with spaces if short */ +static void +ttyinv_populate_slot( + struct WinDesc *cw, + int row, /* 'row' within the window, not within screen */ + int side, /* 'side'==0 is left panel or ==1 is right panel */ + const char *text, + uint32 color, + int clroffset) +{ + struct tty_perminvent_cell *cell; + char c; + int ccnt, col, endcol; + boolean oops, inuse_only = (ttyinvmode & InvInUse) != 0; + + oops = (row < 0 || (long) row >= cw->maxrow || side < 0); + if (inuse_only && side > 1 && !oops) + return; /* there might be more in-use than fits; ignore excess */ + if (oops || side > 1) + panic("ttyinv_populate_slot row=%d, side=%d", row, side); + + col = bordercol[side] + 1; + endcol = bordercol[side + 1] - 1; + cell = &cw->cells[row][col]; + for (ccnt = col; ccnt <= endcol; ++ccnt, ++cell) { + /* [don't expect this to happen] if there was a glyph here, release + memory allocated for it; gi pointer and ttychar character overlay + each other in a union, so clear gi before assigning ttychar */ + if (cell->glyph) { + free((genericptr_t) cell->content.gi); + *cell = emptyttycell; /* clears cell->glyph and cell->content */ + } - cw->maxcol = cw->cols; + if ((c = *text) != '\0') + ++text; + else + c = ' '; - /* - * The number of lines in the first page plus the morestr will be the - * maximum size of the window. - */ - if (cw->npages > 1) - cw->maxrow = cw->rows = lmax + 1; - else - cw->maxrow = cw->rows = cw->nitems + 1; + if (cell->content.ttychar != c) { + cell->content.ttychar = c; + cell->refresh = 1; + } + if (cell->color != color + 1) { + /* offset color by 1 so 0 is not valid */ + if (ccnt >= (col + clroffset)) + cell->color = color + 1; + else + cell->color = NO_COLOR + 1; + cell->refresh = 1; + } + cell->text = 1; /* cell->content.ttychar is current */ + } } -int -tty_select_menu(window, how, menu_list) -winid window; -int how; -menu_item **menu_list; +void +tty_refresh_inventory(int start, int stop, int y) { - register struct WinDesc *cw = 0; - tty_menu_item *curr; - menu_item *mi; - int n, cancelled; + int row = y, col, col_limit = stop; + struct WinDesc *cw = 0; + winid window = WIN_INVEN; + struct tty_perminvent_cell *cell; + boolean printing_glyphs; - if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 - || cw->type != NHW_MENU) - panic(winpanicstr, window); + if (window == WIN_ERR || !iflags.perm_invent + || gp.perm_invent_toggling_direction == toggling_off) + return; - *menu_list = (menu_item *) 0; - cw->how = (short) how; - morc = 0; - tty_display_nhwindow(window, TRUE); - cancelled = !!(cw->flags & WIN_CANCELLED); - tty_dismiss_nhwindow(window); /* does not destroy window data */ + if ((cw = wins[window]) == (struct WinDesc *) 0) + ttywindowpanic(); - if (cancelled) { - n = -1; - } else { - for (n = 0, curr = cw->mlist; curr; curr = curr->next) - if (curr->selected) - n++; + if (col_limit > cw->maxcol) + col_limit = cw->maxcol; + + /* we've been asked to redisplay a portion of the screen, one row */ + printing_glyphs = FALSE; + for (col = start - 1; col < col_limit; ++col) { + cell = &cw->cells[row][col]; + if (cell->color != ttyDisplay->color + 1) { + term_start_color(cell->color - 1); + ttyDisplay->color = cell->color - 1; + } + if (cell->glyph) { + tty_print_glyph(window, col + 1, row, cell->content.gi, + &nul_glyphinfo); + printing_glyphs = TRUE; + } else { + if (printing_glyphs) + end_glyphout(); + if (col != cw->curx || row != cw->cury) + tty_curs(window, col + 1, row); + (void) putchar(cell->content.ttychar); + ttyDisplay->curx++; + cw->curx++; + } + cell->refresh = 0; + } + if (printing_glyphs) + end_glyphout(); + if (ttyDisplay->color != NO_COLOR) { + term_end_color(); + ttyDisplay->color = NO_COLOR; } +} - if (n > 0) { - *menu_list = (menu_item *) alloc(n * sizeof(menu_item)); - for (mi = *menu_list, curr = cw->mlist; curr; curr = curr->next) - if (curr->selected) { - mi->item = curr->identifier; - mi->count = curr->count; - mi++; +static void +tty_invent_box_glyph_init(struct WinDesc *cw) +{ + int row, col, glyph, bordercolor = NO_COLOR; + uchar sym; + struct tty_perminvent_cell *cell; + boolean inuse_only = (ttyinvmode & InvInUse) != 0, + show_gold = (ttyinvmode & InvShowGold) != 0 && !inuse_only; + int rows_per_side = (inuse_only ? (cw->maxrow - 2) + : !show_gold ? 26 + : 27), + bottomrow = rows_per_side + 1; + + if (cw == 0 || !cw->active) + return; + + for (row = 0; row < cw->maxrow; ++row) + for (col = 0; col < cw->maxcol; ++col) { + cell = &cw->cells[row][col]; + sym = S_crwall; /* placeholder */ + /* note: for top and bottom, check [border_right] before + [border_middle] because they could be the same column (for + InvInUse) and if so we want corner rather than tee there */ + if (row == 0) { + sym = (col == bordercol[border_left]) ? S_tlcorn + : (col == bordercol[border_right]) ? S_trcorn + : (col == bordercol[border_middle]) ? S_tdwall + : S_hwall; + } else if (row < bottomrow) { + if (col == bordercol[border_left] + || col == bordercol[border_middle] + || col == bordercol[border_right]) + sym = S_vwall; + /* else sym keeps placeholder value */ + } else if (row == bottomrow) { + sym = (col == bordercol[border_left]) ? S_blcorn + : (col == bordercol[border_right]) ? S_brcorn + : (col == bordercol[border_middle]) ? S_tuwall + : S_hwall; } - } - return n; + if (sym == S_crwall) { /* not a boundary (but might have been) */ + if (cell->glyph) { + /* presumably is no longer wanted middle vertical line */ + free((genericptr_t) cell->content.gi); + *cell = emptyttycell; /* clears cell->glyph */ + cell->content.ttychar = ' '; + cell->text = 1; + cell->refresh = 1; + } + continue; + } + /* a boundary; if it doesn't hold a glyph yet, allocate one */ + if (!cell->glyph) { + cell->content.gi = (glyph_info *) alloc(sizeof (glyph_info)); + *(cell->content.gi) = zerogi; + cell->glyph = 1, cell->text = 0; + } + + /* to get here, cell->glyph is 1 and cell->content union has gi */ + glyph = cmap_D0walls_to_glyph(sym); + map_glyphinfo(0, 0, glyph, 0, cell->content.gi); + cell->glyph = 1; /* (redundant) */ + cell->text = 0; + /* originally this conditionally set refresh depending upon + whether the glyph was already shown, but that optimization + is for something that rarely happens (boundary lines aren't + redrawn very often, and most of the time when they are it's + because they were erased or overwritten by something so + won't match the prior value anymore) so skip it */ + cell->refresh = 1; + cell->color = bordercolor + 1; + } + done_tty_perm_invent_init = TRUE; } -/* special hack for treating top line --More-- as a one item menu */ -char -tty_message_menu(let, how, mesg) -char let; -int how; -const char *mesg; +/* + * returns TRUE if things are ok + */ +static boolean +assesstty( + enum inv_modes invmode, + short *offx, short *offy, long *rows, long *cols, + long *maxcol, long *minrow, long *maxrow) { - HUPSKIP(); - /* "menu" without selection; use ordinary pline, no more() */ - if (how == PICK_NONE) { - pline("%s", mesg); - return 0; - } - - ttyDisplay->dismiss_more = let; - morc = 0; - /* barebones pline(); since we're only supposed to be called after - response to a prompt, we'll assume that the display is up to date */ - tty_putstr(WIN_MESSAGE, 0, mesg); - /* if `mesg' didn't wrap (triggering --More--), force --More-- now */ - if (ttyDisplay->toplin == 1) { - more(); - ttyDisplay->toplin = 1; /* more resets this */ - tty_clear_nhwindow(WIN_MESSAGE); + boolean inuse_only = ((int) invmode & (int) InvInUse) != 0, + show_gold = ((int) invmode & (int) InvShowGold) != 0 + && !inuse_only; + int perminv_minrow = tty_perminv_minrow + (show_gold ? 1 : 0); + + if (!ttyDisplay) { + /* too early */ + *offx = *offy = *rows = *cols = 0; + *maxcol = 0; + *minrow = *maxrow = 0; + return !(*rows < perminv_minrow || *cols < tty_perminv_mincol); } - /* normally means skip further messages, but in this case - it means cancel the current prompt; any other messages should - continue to be output normally */ - wins[WIN_MESSAGE]->flags &= ~WIN_CANCELLED; - ttyDisplay->dismiss_more = 0; - return ((how == PICK_ONE && morc == let) || morc == '\033') ? morc : '\0'; + *offx = 0; + /* topline + map rows + status lines */ + *offy = 1 + ROWNO + StatusRows(); /* 1 + 21 + (2 or 3) */ + *rows = (ttyDisplay->rows - *offy); + *cols = ttyDisplay->cols; + *minrow = perminv_minrow; +#define SMALL_INUSE_WINDOW +#ifdef SMALL_INUSE_WINDOW +#undef SMALL_INUSE_WINDOW + /* simplify testing by not requiring a small font to have enough room */ + if (inuse_only) + *minrow = 1 + 8 + 1; +#else + /* "normal" max for items in use would be 3 weapon + 7 armor + 4 + accessories == 14, but lit lamps/candles and attached leashes are + also included; if hero ends up with more than 15 in-use items, + some will be left out */ + if (inuse_only) + *minrow = 1 + 15 + 1; /* top border + 15 lines + bottom border */ +#endif + *maxrow = min(*rows, perminv_minrow); + *maxcol = *cols; + return !(*rows < *minrow || *cols < tty_perminv_mincol); } + +#endif /* TTY_PERM_INVENT */ + +/* update persistent inventory window */ void -tty_update_inventory() +tty_update_inventory(int arg UNUSED) { +#ifdef TTY_PERM_INVENT + sync_perminvent(); /* call back to core */ +#else + /* do nothing */ +#endif return; } void -tty_mark_synch() +tty_mark_synch(void) { HUPSKIP(); (void) fflush(stdout); } void -tty_wait_synch() +tty_wait_synch(void) { HUPSKIP(); /* we just need to make sure all windows are synch'd */ - if (!ttyDisplay || ttyDisplay->rawprint) { + if (WIN_MAP == WIN_ERR || !ttyDisplay || ttyDisplay->rawprint) { getret(); if (ttyDisplay) ttyDisplay->rawprint = 0; @@ -3196,7 +3639,7 @@ tty_wait_synch() (void) fflush(stdout); } else if (ttyDisplay->inread > program_state.gameover) { /* this can only happen if we were reading and got interrupted */ - ttyDisplay->toplin = 3; + ttyDisplay->toplin = TOPLINE_SPECIAL_PROMPT; /* do this twice; 1st time gets the Quit? message again */ (void) tty_doprev_message(); (void) tty_doprev_message(); @@ -3207,15 +3650,23 @@ tty_wait_synch() } void -docorner(xmin, ymax) -register int xmin, ymax; +docorner( + int xmin, int ymax, + int ystart_between_menu_pages) { - register int y; - register struct WinDesc *cw = wins[WIN_MAP]; + int y; + struct WinDesc *cw = wins[WIN_MAP]; + int ystart = 0; +#ifdef TTY_PERM_INVENT + struct WinDesc *icw = 0; + + if (WIN_INVEN != WIN_ERR && iflags.perm_invent) + icw = wins[WIN_INVEN]; +#endif HUPSKIP(); #if 0 /* this optimization is not valuable enough to justify - abusing core internals... */ + * abusing core internals... */ if (u.uswallow) { /* Can be done more efficiently */ swallowed(1); /* without this flush, if we happen to follow --More-- displayed in @@ -3226,17 +3677,28 @@ register int xmin, ymax; } #endif /*0*/ -#if defined(SIGWINCH) && defined(CLIPPING) +#ifdef RESIZABLE if (ymax > LI) ymax = LI; /* can happen if window gets smaller */ #endif - for (y = 0; y < ymax; y++) { + if (ystart_between_menu_pages) + ystart = ystart_between_menu_pages; + + for (y = ystart; y < ymax; y++) { tty_curs(BASE_WINDOW, xmin, y); /* move cursor */ - cl_end(); /* clear to end of line */ + if (!ystart_between_menu_pages) + cl_end(); /* clear to end of line */ +#ifdef TTY_PERM_INVENT + /* the whole thing is beyond the board but not necessarily all the + way to the bottom of the screen */ + if (icw && y >= (int) icw->offy && y < icw->offy + icw->maxrow) + tty_refresh_inventory(xmin - (int) icw->offx, icw->maxcol, + y - (int) icw->offy); +#endif #ifdef CLIPPING if (y < (int) cw->offy || y + clipy > ROWNO) continue; /* only refresh board */ -#if defined(USE_TILES) && defined(MSDOS) +#if defined(TILES_IN_GLYPHMAP) && defined(MSDOS) if (iflags.tile_view) row_refresh((xmin / 2) + clipx - ((int) cw->offx / 2), COLNO - 1, y + clipy - (int) cw->offy); @@ -3249,18 +3711,20 @@ register int xmin, ymax; continue; /* only refresh board */ row_refresh(xmin - (int) cw->offx, COLNO - 1, y - (int) cw->offy); #endif + } end_glyphout(); - if (ymax >= (int) wins[WIN_STATUS]->offy) { + if (ymax >= (int) wins[WIN_STATUS]->offy + && !ystart_between_menu_pages) { /* we have wrecked the bottom line */ - context.botlx = 1; + disp.botlx = TRUE; bot(); } } void -end_glyphout() +end_glyphout(void) { HUPSKIP(); #if defined(ASCIIGRAPH) && !defined(NO_TERMS) @@ -3269,24 +3733,24 @@ end_glyphout() graph_off(); } #endif -#ifdef TEXTCOLOR if (ttyDisplay->color != NO_COLOR) { term_end_color(); ttyDisplay->color = NO_COLOR; } -#endif } -#ifndef WIN32 void -g_putch(in_ch) -int in_ch; +g_putch(int in_ch) { - register char ch = (char) in_ch; + char ch = (char) in_ch; +#ifndef WIN32CON HUPSKIP(); -#if defined(ASCIIGRAPH) && !defined(NO_TERMS) - if (SYMHANDLING(H_IBM) + +#if defined(ASCIIGRAPH) + if (SYMHANDLING(H_UTF8)) { + (void) putchar(ch); + } else if (SYMHANDLING(H_IBM) /* for DECgraphics, lower-case letters with high bit set mean switch character set and render with high bit clear; user might want 8-bits for other characters */ @@ -3301,25 +3765,51 @@ int in_ch; } (void) putchar((ch ^ 0x80)); /* Strip 8th bit */ } else { - if (GFlag) { + if (GFlag +#ifdef DECgraphicsOptimization + /* for DECgraphics, we only need to switch back from the line + drawing character set to the normal one if 'ch' is a lowercase + letter or one of a handful of punctuation characters (the + range is contiguous but somewhat odd); deferring graph_off() + now might allow skipping both it and next potential graph_on() */ + && ch >= 0x5f && ch <= 0x7e +#endif + ) { graph_off(); GFlag = FALSE; } (void) putchar(ch); } -#else +#else /* ?ASCIIGRAPH */ (void) putchar(ch); -#endif /* ASCIIGRAPH && !NO_TERMS */ +#endif /* ASCIIGRAPH */ +#else /* WIN32CON */ + console_g_putch(in_ch); + nhUse(ch); +#endif /* WIN32CON */ + return; +} +#if defined(UNIX) || defined(VMS) +#if defined(ENHANCED_SYMBOLS) +void +g_pututf8(uint8 *utf8str) +{ + HUPSKIP(); + while (*utf8str) { + (void) putchar(*utf8str); + utf8str++; + } return; } -#endif /* !WIN32 */ +#endif /* ENHANCED_SYMBOLS */ +#endif /* UNIX || VMS */ #ifdef CLIPPING void -setclipped() +setclipped(void) { clipping = TRUE; clipx = clipy = 0; @@ -3328,8 +3818,7 @@ setclipped() } void -tty_cliparound(x, y) -int x, y; +tty_cliparound(int x, int y) { int oldx = clipx, oldy = clipy; @@ -3351,7 +3840,7 @@ int x, y; clipy = clipymax - (LI - 1 - iflags.wc2_statuslines); } if (clipx != oldx || clipy != oldy) { - redraw_map(); /* ask the core to resend the map window's data */ + redraw_map(TRUE); /* ask the core to resend the map window's data */ } } #endif /* CLIPPING */ @@ -3366,15 +3855,16 @@ int x, y; */ void -tty_print_glyph(window, x, y, glyph, bkglyph) -winid window; -xchar x, y; -int glyph; -int bkglyph UNUSED; +tty_print_glyph( + winid window, + coordxy x, coordxy y, + const glyph_info *glyphinfo, + const glyph_info *bkglyphinfo) { + boolean inverse_on = FALSE, colordone = FALSE, glyphdone = FALSE; + boolean petattr = FALSE; int ch; - boolean reverse_on = FALSE; - int color; + uint32 color; unsigned special; HUPSKIP(); @@ -3384,15 +3874,17 @@ int bkglyph UNUSED; return; } #endif - /* map glyph to character and color */ - (void) mapglyph(glyph, &ch, &color, &special, x, y, 0); + /* get glyph ttychar, color, and special flags */ + ch = glyphinfo->ttychar; + color = glyphinfo->gm.sym.color; + special = glyphinfo->gm.glyphflags; print_vt_code2(AVTC_SELECT_WINDOW, window); /* Move the cursor. */ tty_curs(window, x, y); - print_vt_code3(AVTC_GLYPH_START, glyph2tile[glyph], special); + print_vt_code3(AVTC_GLYPH_START, glyphinfo->gm.tileidx, special); #ifndef NO_TERMS if (ul_hack && ch == '_') { /* non-destructive underscore */ @@ -3400,57 +3892,125 @@ int bkglyph UNUSED; backsp(); } #endif - -#ifdef TEXTCOLOR - if (color != ttyDisplay->color) { - if (ttyDisplay->color != NO_COLOR) - term_end_color(); - ttyDisplay->color = color; - if (color != NO_COLOR) - term_start_color(color); - } -#endif /* TEXTCOLOR */ - - /* must be after color check; term_end_color may turn off inverse too */ - if (((special & MG_PET) && iflags.hilite_pet) - || ((special & MG_OBJPILE) && iflags.hilite_pile) - || ((special & MG_DETECT) && iflags.use_inverse) - || ((special & MG_BW_LAVA) && iflags.use_inverse)) { + if (iflags.use_color) { + ttyDisplay->colorflags = NH_BASIC_COLOR; + if (color != ttyDisplay->color) { + if (ttyDisplay->color != NO_COLOR) + term_end_color(); + } + /* we don't link with termcap.o if NO_TERMS is defined */ + if ((tty_procs.wincap2 & WC2_EXTRACOLORS) + && glyphinfo->gm.customcolor != 0 + && iflags.colorcount >= 256 + && !calling_from_update_inventory) { + if ((glyphinfo->gm.customcolor & NH_BASIC_COLOR) == 0) { + term_start_extracolor(glyphinfo->gm.customcolor, + glyphinfo->gm.color256idx); + ttyDisplay->colorflags = 0; + colordone = TRUE; + } else { + color = COLORVAL(glyphinfo->gm.customcolor); + } + } + if (!colordone) { + ttyDisplay->color = color; + if (color != NO_COLOR) + term_start_color(color); + } + } /* iflags.use_color aka iflags.wc_color */ + + /* must be after color check; term_end_color may turn off inverse too; + BW_LAVA, BW_ICE, BW_SINK, BW_ENGR won't ever be set when color is on; + (tried bold for ice but it didn't look very good; inverse is easier + to see although the Valkyrie quest ends up being hard on the eyes) */ + if (iflags.use_color + && bkglyphinfo && bkglyphinfo->framecolor != NO_COLOR) { + ttyDisplay->framecolor = bkglyphinfo->framecolor; + term_start_bgcolor(bkglyphinfo->framecolor); + } else if ((special & MG_PET) != 0 && iflags.hilite_pet) { + term_start_attr(iflags.wc2_petattr); + petattr = TRUE; + } else if ((((special & MG_OBJPILE) != 0 && iflags.hilite_pile) + || ((special & MG_FEMALE) != 0 && wizard && iflags.wizmgender) + || ((special & (MG_DETECT | MG_BW_LAVA | MG_BW_ICE + | MG_BW_SINK | MG_BW_ENGR)) != 0)) + && iflags.use_inverse) { term_start_attr(ATR_INVERSE); - reverse_on = TRUE; + inverse_on = TRUE; } -#if defined(USE_TILES) && defined(MSDOS) - if (iflags.grmode && iflags.tile_view) - xputg(glyph, ch, special); - else +#if defined(TILES_IN_GLYPHMAP) && defined(MSDOS) + if (iflags.grmode && iflags.tile_view) { + xputg(glyphinfo, bkglyphinfo); + glyphdone = TRUE; + } +#endif +#ifdef ENHANCED_SYMBOLS + if (!glyphdone + && (tty_procs.wincap2 & WC2_U_UTF8STR) && SYMHANDLING(H_UTF8) + && glyphinfo->gm.u && glyphinfo->gm.u->utf8str) { + /* we have a sequence to do */ + g_pututf8(glyphinfo->gm.u->utf8str); + glyphdone = TRUE; + } #endif + if (!glyphdone) g_putch(ch); /* print the character */ - if (reverse_on) { + if (inverse_on) term_end_attr(ATR_INVERSE); -#ifdef TEXTCOLOR - /* turn off color as well, ATR_INVERSE may have done this already */ - if (ttyDisplay->color != NO_COLOR) { + else if (petattr) + term_end_attr(iflags.wc2_petattr); + if (iflags.use_color) { + /* turn off color as well, turning off ATR_INVERSE may have done + this already and if so, we won't know the current state unless + we do it explicitly */ + if (ttyDisplay->color != NO_COLOR + || ttyDisplay->framecolor != NO_COLOR) { term_end_color(); - ttyDisplay->color = NO_COLOR; + ttyDisplay->color = ttyDisplay->framecolor = NO_COLOR; } -#endif + if (ttyDisplay->colorflags != NH_BASIC_COLOR) + term_end_extracolor(); } - print_vt_code1(AVTC_GLYPH_END); wins[window]->curx++; /* one character over */ ttyDisplay->curx++; /* the real cursor moved too */ } +#ifdef NO_TERMS /* termcap.o isn't linked in */ +#if !defined(MSDOS) && !defined(WIN32) +void +term_start_bgcolor(int color) +{ + /* placeholder for now */ +} +void +term_curs_set(int visibility UNUSED) +{ + /* nothing */ +} +#endif + +#ifdef CHANGE_COLOR +void +tty_change_color(int color UNUSED, long rgb UNUSED, int reverse UNUSED) +{ + /* nothing */ +} +#endif /* CHANGE_COLOR */ + +#endif /* NO_TERMS */ + void -tty_raw_print(str) -const char *str; +tty_raw_print(const char *str) { HUPSKIP(); if (ttyDisplay) ttyDisplay->rawprint++; + else if (*str) + iflags.raw_printed++; print_vt_code2(AVTC_SELECT_WINDOW, NHW_BASE); #if defined(MICRO) || defined(WIN32CON) msmsg("%s\n", str); @@ -3461,12 +4021,13 @@ const char *str; } void -tty_raw_print_bold(str) -const char *str; +tty_raw_print_bold(const char *str) { HUPSKIP(); if (ttyDisplay) ttyDisplay->rawprint++; + else if (*str) + iflags.raw_printed++; print_vt_code2(AVTC_SELECT_WINDOW, NHW_BASE); term_start_raw_bold(); #if defined(MICRO) || defined(WIN32CON) @@ -3484,21 +4045,20 @@ const char *str; } int -tty_nhgetch() +tty_nhgetch(void) { int i; #ifdef UNIX - /* kludge alert: Some Unix variants return funny values if getc() - * is called, interrupted, and then called again. There - * is non-reentrant code in the internal _filbuf() routine, called by - * getc(). + /* kludge alert: Some Unix variants return funny values if getc() is + * called, interrupted, and then called again. There is non-reentrant + * code in the internal _filbuf() routine, called by getc(). */ - static volatile int nesting = 0; char nestbuf; #endif HUPSKIP_RESULT('\033'); print_vt_code1(AVTC_INLINE_SYNC); + term_curs_set(1); (void) fflush(stdout); /* Note: if raw_print() and wait_synch() get called to report terminal * initialization problems, then wins[] and ttyDisplay might not be @@ -3510,22 +4070,38 @@ tty_nhgetch() if (iflags.debug_fuzzer) { i = randomkey(); } else { +#ifdef RESIZABLE + if (program_state.resize_pending) + resize_tty(); +#endif + program_state.getting_char++; #ifdef UNIX - i = (++nesting == 1) + i = (program_state.getting_char == 1) ? tgetch() - : (read(fileno(stdin), (genericptr_t) &nestbuf, 1) == 1) - ? (int) nestbuf : EOF; - --nesting; + : ((read(fileno(stdin), (genericptr_t) &nestbuf, 1) == 1) + ? (int) nestbuf : EOF); #else i = tgetch(); +#endif + program_state.getting_char--; +#ifdef RESIZABLE + if (resize_mesg) { + resize_mesg = 0; + tty_clear_nhwindow(WIN_MESSAGE); + i = '\033'; + } #endif } + term_curs_set(0); if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ - else if (i == EOF) + else if (i == EOF) { + iflags.term_gone = 1; i = '\033'; /* same for EOF */ - if (ttyDisplay && ttyDisplay->toplin == 1) - ttyDisplay->toplin = 2; + } + /* topline has been seen - we can clear the need for --More-- */ + if (ttyDisplay && ttyDisplay->toplin == TOPLINE_NEED_MORE) + ttyDisplay->toplin = TOPLINE_NON_EMPTY; #ifdef TTY_TILES_ESCCODES { /* hack to force output of the window select code */ @@ -3545,8 +4121,11 @@ tty_nhgetch() */ /*ARGSUSED*/ int -tty_nh_poskey(x, y, mod) -int *x, *y, *mod; +#if defined(WIN32CON) +tty_nh_poskey(coordxy *x, coordxy *y, int *mod) +#else +tty_nh_poskey(coordxy *x UNUSED, coordxy *y UNUSED, int *mod UNUSED) +#endif { int i; @@ -3560,24 +4139,20 @@ int *x, *y, *mod; */ if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE]) wins[WIN_MESSAGE]->flags &= ~WIN_STOP; - i = ntposkey(x, y, mod); + i = console_poskey(x, y, mod); if (!i && mod && (*mod == 0 || *mod == EOF)) i = '\033'; /* map NUL or EOF to ESC, nethack doesn't expect either */ - if (ttyDisplay && ttyDisplay->toplin == 1) - ttyDisplay->toplin = 2; + /* topline has been seen - we can clear the need for --More-- */ + if (ttyDisplay && ttyDisplay->toplin == TOPLINE_NEED_MORE) + ttyDisplay->toplin = TOPLINE_NON_EMPTY; #else /* !WIN32CON */ - nhUse(x); - nhUse(y); - nhUse(mod); - i = tty_nhgetch(); #endif /* ?WIN32CON */ return i; } void -win_tty_init(dir) -int dir; +win_tty_init(int dir) { if (dir != WININIT) return; @@ -3586,8 +4161,7 @@ int dir; #ifdef POSITIONBAR void -tty_update_positionbar(posbar) -char *posbar; +tty_update_positionbar(char *posbar) { #ifdef MSDOS video_update_positionbar(posbar); @@ -3595,6 +4169,33 @@ char *posbar; } #endif /* POSITIONBAR */ +void +tty_putmixed(winid window, int attr, const char *str) +{ + struct WinDesc *cw; + char buf[BUFSZ]; +#ifdef ENHANCED_SYMBOLS + int utf8flag = 0; +#endif + + if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) { + tty_raw_print(str); + return; + } + ttyDisplay->mixed = 1; +#ifdef ENHANCED_SYMBOLS + if ((windowprocs.wincap2 & WC2_U_UTF8STR) && SYMHANDLING(H_UTF8)) { + mixed_to_utf8(buf, sizeof buf, str, &utf8flag); + if (cw->type == NHW_MESSAGE) + ttyDisplay->topl_utf8 = utf8flag; + } else +#endif + decode_mixed(buf, str); + /* now send it to the normal tty_putstr */ + tty_putstr(window, attr, buf); + ttyDisplay->topl_utf8 = 0; + ttyDisplay->mixed = 0; +} /* * +------------------+ @@ -3660,63 +4261,48 @@ extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; #ifdef STATUS_HILITES -#ifdef TEXTCOLOR -STATIC_DCL int FDECL(condcolor, (long, unsigned long *)); -#endif -STATIC_DCL int FDECL(condattr, (long, unsigned long *)); +static int condcolor(long, unsigned long *); +static int condattr(long, unsigned long *); static unsigned long *tty_colormasks; static long tty_condition_bits; static struct tty_status_fields tty_status[2][MAXBLSTATS]; /* 2: NOW,BEFORE */ -static int hpbar_percent, hpbar_color; -static struct condition_t { - long mask; - const char *text[3]; /* 3: potential display vals, progressively shorter */ -} conditions[] = { - /* The sequence order of these matters */ - { BL_MASK_STONE, { "Stone", "Ston", "Sto" } }, - { BL_MASK_SLIME, { "Slime", "Slim", "Slm" } }, - { BL_MASK_STRNGL, { "Strngl", "Stngl", "Str" } }, - { BL_MASK_FOODPOIS, { "FoodPois", "Fpois", "Poi" } }, - { BL_MASK_TERMILL, { "TermIll" , "Ill", "Ill" } }, - { BL_MASK_BLIND, { "Blind", "Blnd", "Bl" } }, - { BL_MASK_DEAF, { "Deaf", "Def", "Df" } }, - { BL_MASK_STUN, { "Stun", "Stun", "St" } }, - { BL_MASK_CONF, { "Conf", "Cnf", "Cf" } }, - { BL_MASK_HALLU, { "Hallu", "Hal", "Hl" } }, - { BL_MASK_LEV, { "Lev", "Lev", "Lv" } }, - { BL_MASK_FLY, { "Fly", "Fly", "Fl" } }, - { BL_MASK_RIDE, { "Ride", "Rid", "Rd" } }, -}; -static const char *encvals[3][6] = { +static int hpbar_percent, hpbar_crit_hp; +extern const struct conditions_t conditions[CONDITION_COUNT]; + +static const char *const encvals[3][6] = { { "", "Burdened", "Stressed", "Strained", "Overtaxed", "Overloaded" }, { "", "Burden", "Stress", "Strain", "Overtax", "Overload" }, { "", "Brd", "Strs", "Strn", "Ovtx", "Ovld" } }; #define blPAD BL_FLUSH -#define MAX_PER_ROW 15 +#define MAX_PER_ROW 19 /* 2 or 3 status lines */ static const enum statusfields twolineorder[3][MAX_PER_ROW] = { { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, - BL_SCORE, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD }, + BL_SCORE, BL_FLUSH, + blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }, { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, - BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, - BL_CAP, BL_CONDITION, BL_FLUSH }, + BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, + BL_CONDITION, BL_WEAPON, BL_ARMOR, BL_TERRAIN, BL_VERS, BL_FLUSH }, /* third row of array isn't used for twolineorder */ { BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, - blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } + blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } }, - /* Align moved from 1 to 2, Leveldesc+Time+Condition moved from 2 to 3 */ + /* Align moved from 1 to 2, Leveldesc+Time+Cond+Vers moved from 2 to 3 */ threelineorder[3][MAX_PER_ROW] = { - { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, - BL_SCORE, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }, + { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_SCORE, BL_FLUSH, + blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }, { BL_ALIGN, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, - BL_AC, BL_XP, BL_EXP, BL_HD, BL_HUNGER, - BL_CAP, BL_FLUSH, blPAD, blPAD }, - { BL_LEVELDESC, BL_TIME, BL_CONDITION, BL_FLUSH, blPAD, blPAD, - blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } + BL_AC, BL_XP, BL_EXP, BL_HD, BL_HUNGER, BL_CAP, + BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }, + { BL_LEVELDESC, BL_TIME, BL_CONDITION, BL_WEAPON, BL_ARMOR, BL_TERRAIN, + BL_VERS, BL_FLUSH, blPAD, + blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } }; static const enum statusfields (*fieldorder)[MAX_PER_ROW]; +#undef MAX_PER_ROW +#undef blPAD static int finalx[3][2]; /* [rows][NOW or BEFORE] */ static boolean windowdata_init = FALSE; @@ -3750,12 +4336,12 @@ static int do_field_opt = * -- call genl_status_init() to initialize the general data. */ void -tty_status_init() +tty_status_init(void) { #ifdef STATUS_HILITES int i, num_rows; - num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3; + num_rows = StatusRows(); /* 2 or 3 */ fieldorder = (num_rows != 3) ? twolineorder : threelineorder; for (i = 0; i < MAXBLSTATS; ++i) { @@ -3770,7 +4356,7 @@ tty_status_init() tty_status[BEFORE][i] = tty_status[NOW][i]; } tty_condition_bits = 0L; - hpbar_percent = 0, hpbar_color = NO_COLOR; + hpbar_percent = hpbar_crit_hp = 0; #endif /* STATUS_HILITES */ /* let genl_status_init do most of the initialization */ @@ -3778,11 +4364,11 @@ tty_status_init() } void -tty_status_enablefield(fieldidx, nm, fmt, enable) -int fieldidx; -const char *nm; -const char *fmt; -boolean enable; +tty_status_enablefield( + int fieldidx, + const char *nm, + const char *fmt, + boolean enable) { genl_status_enablefield(fieldidx, nm, fmt, enable); } @@ -3798,31 +4384,50 @@ boolean enable; * BL_TITLE, 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 + * BL_LEVELDESC, BL_EXP, BL_CONDITION, + * BL_WEAPON, BL_ARMOR, BL_TERRAIN, BL_VERS * -- fldindex could also be BL_FLUSH (-1), which is not really * a field index, but is a special trigger to tell the * windowport that it should output all changes received * to this point. It marks the end of a bot() cycle. * -- fldindex could also be BL_RESET (-3), which is not really - * a field index, but is a special advisory to to tell the + * a field index, but is a special advisory to tell the * windowport that it should redisplay all its status fields, * even if no changes have been presented to it. * -- 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_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 + * BL_MASK_BAREH 0x00000001L + * BL_MASK_BLIND 0x00000002L + * BL_MASK_BUSY 0x00000004L + * BL_MASK_CONF 0x00000008L + * BL_MASK_DEAF 0x00000010L + * BL_MASK_ELF_IRON 0x00000020L + * BL_MASK_FLY 0x00000040L + * BL_MASK_FOODPOIS 0x00000080L + * BL_MASK_GLOWHANDS 0x00000100L + * BL_MASK_GRAB 0x00000200L + * BL_MASK_HALLU 0x00000400L + * BL_MASK_HELD 0x00000800L + * BL_MASK_ICY 0x00001000L + * BL_MASK_INLAVA 0x00002000L + * BL_MASK_LEV 0x00004000L + * BL_MASK_PARLYZ 0x00008000L + * BL_MASK_RIDE 0x00010000L + * BL_MASK_SLEEPING 0x00020000L + * BL_MASK_SLIME 0x00040000L + * BL_MASK_SLIPPERY 0x00080000L + * BL_MASK_STONE 0x00100000L + * BL_MASK_STRNGL 0x00200000L + * BL_MASK_STUN 0x00400000L + * BL_MASK_SUBMERGED 0x00800000L + * BL_MASK_TERMILL 0x01000000L + * BL_MASK_TETHERED 0x02000000L + * BL_MASK_TRAPPED 0x04000000L + * BL_MASK_UNCONSC 0x08000000L + * BL_MASK_WOUNDEDL 0x10000000L + * BL_MASK_HOLDING 0x20000000L + * * -- The value passed for BL_GOLD usually 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 @@ -3843,14 +4448,19 @@ boolean enable; * Each condition bit must only ever appear in one of the * CLR_ array members, but can appear in multiple HL_ATTCLR_ * offsets (because more than one attribute can co-exist). - * See doc/window.doc for more details. + * See doc/window.txt for more details. */ +DISABLE_WARNING_FORMAT_NONLITERAL + void -tty_status_update(fldidx, ptr, chg, percent, color, colormasks) -int fldidx, chg UNUSED, percent, color; -genericptr_t ptr; -unsigned long *colormasks; +tty_status_update( + int fldidx, + genericptr_t ptr, + int chg UNUSED, + int percent, + int color, + unsigned long *colormasks) { int attrmask; long *condptr = (long *) ptr; @@ -3868,6 +4478,7 @@ unsigned long *colormasks; switch (fldidx) { case BL_RESET: reset_state = FORCE_RESET; + FALLTHROUGH; /*FALLTHRU*/ case BL_FLUSH: if (make_things_fit(reset_state) || truncation_expected) { @@ -3888,12 +4499,10 @@ unsigned long *colormasks; break; case BL_GOLD: text = decode_mixed(goldbuf, text); + FALLTHROUGH; /*FALLTHRU*/ default: attrmask = (color >> 8) & 0x00FF; -#ifndef TEXTCOLOR - color = NO_COLOR; -#endif fmt = status_fieldfmt[fldidx]; if (!fmt) fmt = "%s"; @@ -3916,7 +4525,7 @@ unsigned long *colormasks; } /* The core botl engine sends a single blank to the window port - for carrying-capacity when its unused. Let's suppress that */ + for carrying-capacity when it's unused. Let's suppress that */ if (fldidx >= 0 && fldidx < MAXBLSTATS && tty_status[NOW][fldidx].lth == 1 && status_vals[fldidx][0] == ' ') { @@ -3930,13 +4539,16 @@ unsigned long *colormasks; if (iflags.wc2_hitpointbar) { /* Special additional processing for hitpointbar */ hpbar_percent = percent; - hpbar_color = (color & 0x00FF); - tty_status[NOW][BL_TITLE].color = hpbar_color; + hpbar_crit_hp = critically_low_hp(TRUE) ? 1 : 0; + tty_status[NOW][BL_TITLE].color = (color & 0x00FF); + attrmask = HL_INVERSE | (hpbar_crit_hp ? HL_BLINK : 0); + tty_status[NOW][BL_TITLE].attr = term_attr_fixup(attrmask); tty_status[NOW][BL_TITLE].dirty = TRUE; } break; case BL_LEVELDESC: dlvl_shrinklvl = 0; /* caller is passing full length string */ + FALLTHROUGH; /*FALLTHRU*/ case BL_HUNGER: /* The core sends trailing blanks for some fields. @@ -3957,7 +4569,7 @@ unsigned long *colormasks; break; case BL_GOLD: /* \GXXXXNNNN counts as 1 [moot since we use decode_mixed() above] */ - if ((p = index(status_vals[fldidx], '\\')) != 0 && p[1] == 'G') + if ((p = strchr(status_vals[fldidx], '\\')) != 0 && p[1] == 'G') tty_status[NOW][fldidx].lth -= (10 - 1); break; case BL_CAP: @@ -3969,14 +4581,15 @@ unsigned long *colormasks; return; } -STATIC_OVL int -make_things_fit(force_update) -boolean force_update; +RESTORE_WARNING_FORMAT_NONLITERAL + +static int +make_things_fit(boolean force_update) { int trycnt, fitting = 0, requirement; - int rowsz[3], num_rows, condrow, otheroptions = 0; + int rowsz[MAX_STATUS_ROWS], num_rows, condrow, otheroptions = 0; - num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3; + num_rows = StatusRows(); condrow = num_rows - 1; /* always last row, 1 for 0..1 or 2 for 0..2 */ cond_shrinklvl = 0; if (enc_shrinklvl > 0 && num_rows == 2) @@ -4033,10 +4646,8 @@ boolean force_update; * must be updated because they need to change. * This is now done at an individual field case-by-case level. */ -STATIC_OVL boolean -check_fields(forcefields, sz) -boolean forcefields; -int sz[3]; +static boolean +check_fields(boolean forcefields, int sz[MAX_STATUS_ROWS]) { int c, i, row, col, num_rows, idx; boolean valid = TRUE, matchprev, update_right; @@ -4044,8 +4655,7 @@ int sz[3]; if (!windowdata_init && !check_windowdata()) return FALSE; - num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3; - + num_rows = StatusRows(); /* 2 or 3 */ for (row = 0; row < num_rows; ++row) { sz[row] = 0; col = 1; @@ -4136,18 +4746,20 @@ int sz[3]; } #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) -STATIC_OVL void -status_sanity_check(VOID_ARGS) +static void +status_sanity_check(void) { - int i; - static boolean in_sanity_check = FALSE; static const char *const idxtext[] = { - "BL_TITLE", "BL_STR", "BL_DX", "BL_CO", "BL_IN", "BL_WI", /* 0.. 5 */ - "BL_CH","BL_ALIGN", "BL_SCORE", "BL_CAP", "BL_GOLD", /* 6.. 10 */ - "BL_ENE", "BL_ENEMAX", "BL_XP", "BL_AC", "BL_HD", /* 11.. 15 */ - "BL_TIME", "BL_HUNGER", "BL_HP", "BL_HPMAX", /* 16.. 19 */ - "BL_LEVELDESC", "BL_EXP", "BL_CONDITION" /* 20.. 22 */ + "BL_TITLE", "BL_STR", "BL_DX", "BL_CO", "BL_IN", "BL_WI", /* 0.. 5 */ + "BL_CH","BL_ALIGN", "BL_SCORE", "BL_CAP", "BL_GOLD", /* 6..10 */ + "BL_ENE", "BL_ENEMAX", "BL_XP", "BL_AC", "BL_HD", /* 11..15 */ + "BL_TIME", "BL_HUNGER", "BL_HP", "BL_HPMAX", /* 16..19 */ + "BL_LEVELDESC", "BL_EXP", "BL_CONDITION", /* 20..22 */ + "BL_WEAPON", "BL_ARMOR", "BL_TERRAIN", /* 23..25 */ + "BL_VERS", /* 26 */ }; + static boolean in_sanity_check = FALSE; + int i; if (in_sanity_check) return; @@ -4158,9 +4770,15 @@ status_sanity_check(VOID_ARGS) */ for (i = 0; i < MAXBLSTATS; ++i) { if (tty_status[NOW][i].sanitycheck) { - char panicmsg[BUFSZ]; - - Sprintf(panicmsg, "failed on tty_status[NOW][%s].", idxtext[i]); + char panicmsg[BUFSZ], indxtxt[40]; + + /* guard against an increase in MAXBLSTATS in botl.h without + a corresponding expansion of idxtext[] here */ + if (i < SIZE(idxtext)) + Strcpy(indxtxt, idxtext[i]); + else /* blstats[] increased without doing same for idxtext[] */ + Sprintf(indxtxt, "#%d", i); + Sprintf(panicmsg, "failed on tty_status[NOW][%s].", indxtxt); paniclog("status_sanity_check", panicmsg); tty_status[NOW][i].sanitycheck = FALSE; /* @@ -4184,10 +4802,8 @@ status_sanity_check(VOID_ARGS) /* * This is what places a field on the tty display. */ -STATIC_OVL void -tty_putstatusfield(text, x, y) -const char *text; -int x, y; +static void +tty_putstatusfield(const char *text, int x, int y) { int i, n, ncols, nrows, lth = 0; struct WinDesc *cw = 0; @@ -4227,8 +4843,8 @@ int x, y; } /* caller must set cond_shrinklvl (0..2) before calling us */ -STATIC_OVL void -set_condition_length() +static void +set_condition_length(void) { long mask; int c, lth = 0; @@ -4243,9 +4859,8 @@ set_condition_length() tty_status[NOW][BL_CONDITION].lth = lth; } -STATIC_OVL void -shrink_enc(lvl) -int lvl; +static void +shrink_enc(int lvl) { /* shrink or restore the encumbrance word */ if (lvl <= 2) { @@ -4255,13 +4870,12 @@ int lvl; tty_status[NOW][BL_CAP].lth = strlen(status_vals[BL_CAP]); } -STATIC_OVL void -shrink_dlvl(lvl) -int lvl; +static void +shrink_dlvl(int lvl) { /* try changing Dlvl: to Dl: */ char buf[BUFSZ]; - char *levval = index(status_vals[BL_LEVELDESC], ':'); + char *levval = strchr(status_vals[BL_LEVELDESC], ':'); if (levval) { dlvl_shrinklvl = lvl; @@ -4276,8 +4890,8 @@ int lvl; * Ensure the underlying status window data start out * blank and null-terminated. */ -STATIC_OVL boolean -check_windowdata(VOID_ARGS) +static boolean +check_windowdata(void) { if (WIN_STATUS == WIN_ERR || wins[WIN_STATUS] == (struct WinDesc *) 0) { paniclog("check_windowdata", " null status window."); @@ -4289,15 +4903,12 @@ check_windowdata(VOID_ARGS) return TRUE; } -#ifdef TEXTCOLOR /* * Return what color this condition should * be displayed in based on user settings. */ -STATIC_OVL int -condcolor(bm, bmarray) -long bm; -unsigned long *bmarray; +static int +condcolor(long bm, unsigned long *bmarray) { int i; @@ -4308,41 +4919,35 @@ unsigned long *bmarray; } return NO_COLOR; } -#else -/* might need something more elaborate if some compiler complains that - the condition where this gets used always has the same value */ -#define condcolor(bm,bmarray) NO_COLOR -#define term_start_color(color) /*empty*/ -#define term_end_color() /*empty*/ -#endif /* TEXTCOLOR */ - -STATIC_OVL int -condattr(bm, bmarray) -long bm; -unsigned long *bmarray; + +static int +condattr(long bm, unsigned long *bmarray) { int attr = 0; int i; if (bm && bmarray) { - for (i = HL_ATTCLR_DIM; i < BL_ATTCLR_MAX; ++i) { + for (i = HL_ATTCLR_BOLD; i < BL_ATTCLR_MAX; ++i) { if ((bm & bmarray[i]) != 0) { switch (i) { + case HL_ATTCLR_BOLD: + attr |= HL_BOLD; + break; case HL_ATTCLR_DIM: attr |= HL_DIM; break; - case HL_ATTCLR_BLINK: - attr |= HL_BLINK; + case HL_ATTCLR_ITALIC: + attr |= HL_ITALIC; break; case HL_ATTCLR_ULINE: attr |= HL_ULINE; break; + case HL_ATTCLR_BLINK: + attr |= HL_BLINK; + break; case HL_ATTCLR_INVERSE: attr |= HL_INVERSE; break; - case HL_ATTCLR_BOLD: - attr |= HL_BOLD; - break; } } } @@ -4355,38 +4960,43 @@ unsigned long *bmarray; if (m) { \ if ((m) & HL_BOLD) \ term_start_attr(ATR_BOLD); \ - if ((m) & HL_INVERSE) \ - term_start_attr(ATR_INVERSE); \ + if ((m) & HL_DIM) \ + term_start_attr(ATR_DIM); \ + if ((m) & HL_ITALIC) \ + term_start_attr(ATR_ITALIC); \ if ((m) & HL_ULINE) \ term_start_attr(ATR_ULINE); \ if ((m) & HL_BLINK) \ term_start_attr(ATR_BLINK); \ - if ((m) & HL_DIM) \ - term_start_attr(ATR_DIM); \ + if ((m) & HL_INVERSE) \ + term_start_attr(ATR_INVERSE); \ } \ } while (0) #define End_Attr(m) \ do { \ if (m) { \ - if ((m) & HL_DIM) \ - term_end_attr(ATR_DIM); \ + if ((m) & HL_INVERSE) \ + term_end_attr(ATR_INVERSE); \ if ((m) & HL_BLINK) \ term_end_attr(ATR_BLINK); \ if ((m) & HL_ULINE) \ term_end_attr(ATR_ULINE); \ - if ((m) & HL_INVERSE) \ - term_end_attr(ATR_INVERSE); \ + if ((m) & HL_ITALIC) \ + term_end_attr(ATR_ITALIC); \ + if ((m) & HL_DIM) \ + term_end_attr(ATR_DIM); \ if ((m) & HL_BOLD) \ term_end_attr(ATR_BOLD); \ } \ } while (0) -STATIC_OVL void -render_status(VOID_ARGS) +static void +render_status(void) { long mask, bits; - int i, x, y, idx, c, row, tlth, num_rows, coloridx = 0, attrmask = 0; + int i, x, y, idx, c, ci, row, tlth, num_rows, + coloridx = 0, attrmask = 0; char *text; struct WinDesc *cw = 0; @@ -4396,7 +5006,7 @@ render_status(VOID_ARGS) return; } - num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3; + num_rows = StatusRows(); /* 2 or 3 */ for (row = 0; row < num_rows; ++row) { HUPSKIP(); y = row; @@ -4419,13 +5029,24 @@ render_status(VOID_ARGS) * +-----------------+ */ bits = tty_condition_bits; - /* if no bits are set, we can fall through condition - rendering code to finalx[] handling (and subsequent - rest-of-line erasure if line is shorter than before) */ - if (num_rows == 3 && bits != 0L) { - int k; + /* + * If no bits are set, we can fall through condition + * rendering code to finalx[] handling (and subsequent + * rest-of-line erasure if line is shorter than before). + * + * First, when conditions are on 3rd row, they might + * be indented to line up with a position on 2nd row. + */ + if (row == MAX_STATUS_ROWS - 1 && bits != 0L) { + int cstart, last_col = cw->cols; char *dat = &cw->data[y][0]; + /* 'version' might follow conditions; if so, adjust + expectations for where conditions should end; + only matters when conditions are being indented */ + if (status_activefields[BL_VERS] + && fieldorder[row][i + 1] == BL_VERS) + last_col -= (int) tty_status[NOW][BL_VERS].lth; /* line up with hunger (or where it would have been when currently omitted); if there isn't enough room for that, right justify; or place @@ -4435,22 +5056,26 @@ render_status(VOID_ARGS) if (tty_status[BEFORE][BL_HUNGER].y < row && x < tty_status[BEFORE][BL_HUNGER].x && (tty_status[BEFORE][BL_HUNGER].x + tlth - < cw->cols - 1)) - k = tty_status[BEFORE][BL_HUNGER].x; + < last_col - 1)) + cstart = tty_status[BEFORE][BL_HUNGER].x; else if (x + tlth < cw->cols - 1) - k = cw->cols - tlth; + cstart = last_col - tlth; else - k = x; - while (x < k) { - if (dat[x - 1] != ' ') - tty_putstatusfield(" ", x, y); - ++x; + cstart = x; + /* indent conditions to line them up with 2nd row */ + if (x < cstart) { + do { + if (dat[x - 1] != ' ') + tty_putstatusfield(" ", x, y); + } while (++x < cstart); + tty_status[NOW][BL_CONDITION].x = x; + tty_curs(WIN_STATUS, x, y); } - tty_status[NOW][BL_CONDITION].x = x; - tty_curs(WIN_STATUS, x, y); } + /* actually draw condition words */ for (c = 0; c < SIZE(conditions) && bits != 0L; ++c) { - mask = conditions[c].mask; + ci = cond_idx[c]; + mask = conditions[ci].mask; if (bits & mask) { const char *condtext; @@ -4462,7 +5087,7 @@ render_status(VOID_ARGS) if (coloridx != NO_COLOR) term_start_color(coloridx); } - condtext = conditions[c].text[cond_shrinklvl]; + condtext = conditions[ci].text[cond_shrinklvl]; if (x >= cw->cols && !truncation_expected) { impossible( "Unexpected condition placement overflow for \"%s\"", @@ -4500,7 +5125,7 @@ render_status(VOID_ARGS) */ /* hitpointbar using hp percent calculation */ int bar_len, bar_pos = 0; - char bar[MAXCO], *bar2 = (char *) 0, savedch = '\0'; + char bar[30 + 1], *bar2 = (char *) 0, savedch = '\0'; boolean twoparts = (hpbar_percent < 100); /* force exactly 30 characters, padded with spaces @@ -4508,10 +5133,14 @@ render_status(VOID_ARGS) if (strlen(text) != 30) { Sprintf(bar, "%-30.30s", text); Strcpy(status_vals[BL_TITLE], bar); - } else + } else { Strcpy(bar, text); + } + if (hpbar_crit_hp) + repad_with_dashes(bar); bar_len = (int) strlen(bar); /* always 30 */ - tlth = bar_len + 2; + /*tlth = bar_len + 2; // not needed within this 'if'*/ + attrmask = 0; /* for the second part only case: dead */ /* when at full HP, the whole title will be highlighted; when injured or dead, there will be a second portion which is not highlighted */ @@ -4528,19 +5157,25 @@ render_status(VOID_ARGS) } tty_putstatusfield("[", x++, y); if (*bar) { /* always True, unless twoparts+dead (0 HP) */ - term_start_attr(ATR_INVERSE); - if (iflags.hilite_delta && hpbar_color != NO_COLOR) - term_start_color(hpbar_color); + coloridx = tty_status[NOW][BL_TITLE].color; + attrmask = tty_status[NOW][BL_TITLE].attr; + Begin_Attr(attrmask); + if (iflags.hilite_delta && coloridx != NO_COLOR) + term_start_color(coloridx); tty_putstatusfield(bar, x, y); x += (int) strlen(bar); - if (iflags.hilite_delta && hpbar_color != NO_COLOR) + if (iflags.hilite_delta && coloridx != NO_COLOR) term_end_color(); - term_end_attr(ATR_INVERSE); + End_Attr(attrmask); } - if (twoparts) { /* no highlighting for second part */ + if (twoparts) { + if ((attrmask & HL_BLINK) != 0) + term_start_attr(ATR_BLINK); *bar2 = savedch; tty_putstatusfield(bar2, x, y); x += (int) strlen(bar2); + if ((attrmask & HL_BLINK) != 0) + term_end_attr(ATR_BLINK); } tty_putstatusfield("]", x++, y); } else { @@ -4550,6 +5185,34 @@ render_status(VOID_ARGS) * | in a special case above | * +-----------------------------+ */ + if (idx == BL_VERS + /* if 'version' is the last field in its row, right + justify it (otherwise just treat it as ordinary) */ + && fieldorder[row][i + 1] == BL_FLUSH) { + int vstart; + char *dat = &cw->data[y][0]; + /* FIXME: there's something fishy going on here; + 'x' ends up out of synch when conditions have + 3rd row indentation and the indenting of version + overwrites them with spaces; this hides that */ + int vx = tty_status[BEFORE][BL_CONDITION].x + + tty_status[BEFORE][BL_CONDITION].lth; + + if (i > 0 && fieldorder[row][i - 1] == BL_CONDITION + && x != vx) { + x = vx; + tty_curs(WIN_STATUS, x, y); + } + /* indent version to right justify it */ + vstart = cw->cols - (int) tty_status[NOW][idx].lth; + if (x < vstart) { + do { + if (dat[x - 1] != ' ') + tty_putstatusfield(" ", x, y); + } while (++x < vstart); + tty_status[NOW][BL_VERS].x = x; + } + } if (iflags.hilite_delta) { while (*text == ' ') { tty_putstatusfield(" ", x++, y); @@ -4587,7 +5250,7 @@ render_status(VOID_ARGS) * - Copy the entire tty_status struct. */ tty_status[BEFORE][idx] = tty_status[NOW][idx]; - } + } /* for i=..., idx=fieldorder[][i] */ x = finalx[row][NOW]; if ((x < finalx[row][BEFORE] || !finalx[row][BEFORE]) && x + 1 < cw->cols) { @@ -4599,12 +5262,64 @@ render_status(VOID_ARGS) * - Copy the last written column number on the row. */ finalx[row][BEFORE] = finalx[row][NOW]; - } + } /* for row=... */ return; } +#undef Begin_Attr +#undef End_Attr +#ifdef condcolor +#undef condcolor +#endif +#ifdef term_start_color +#undef term_start_color +#undef term_end_color +#endif +#undef FORCE_RESET +#undef NO_RESET +#undef MAX_STATUS_ROWS +#undef StatusRows + #endif /* STATUS_HILITES */ +#if defined(USER_SOUNDS) && defined(TTY_SOUND_ESCCODES) +void +play_usersound_via_idx(int idx, int volume) +{ + print_vt_soundcode_idx(idx, volume); +} +#endif /* USER_SOUNDS && TTY_SOUND_ESCCODES */ + +#ifdef VT_ANSI_COMMAND +#undef VT_ANSI_COMMAND +#endif +#ifdef AVTC_GLYPH_START /* TTY_TILES_ESCCODES */ +#undef AVTC_GLYPH_START +#undef AVTC_GLYPH_END +#undef AVTC_SELECT_WINDOW +#undef AVTC_INLINE_SYNC +#endif +#ifdef AVTC_SOUND_PLAY /* TTY_SOUND_ESCCODES */ +#undef AVTC_SOUND_PLAY +#endif + +#ifdef print_vt_code +#undef print_vt_code +#endif +#undef print_vt_code1 +#undef print_vt_code2 +#undef print_vt_code3 +#ifdef print_vt_soundcode_idx +#undef print_vt_soundcode_idx +#endif + +#undef RESIZABLE +#undef HUPSKIP +#undef HUPSKIP_RESULT +#undef ttypanic + #endif /* TTY_GRAPHICS */ +#undef H2344_BROKEN + /*wintty.c*/ diff --git a/win/win32/NetHackW.c b/win/win32/NetHackW.c index c6941d7c0..bee362598 100644 --- a/win/win32/NetHackW.c +++ b/win/win32/NetHackW.c @@ -1,8 +1,8 @@ -/* NetHack 3.6 winhack.c $NHDT-Date: 1449488876 2015/12/07 11:47:56 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.44 $ */ +/* NetHack 5.0 NetHackW.c $NHDT-Date: 1693359674 2023/08/30 01:41:14 $ $NHDT-Branch: keni-crashweb2 $:$NHDT-Revision: 1.79 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ -// winhack.cpp : Defines the entry point for the application. +// NetHackW.cpp : Defines the entry point for the application. // #include "win10.h" @@ -15,10 +15,6 @@ #include "mhmain.h" #include "mhmap.h" -#if !defined(SAFEPROCS) -#error You must #define SAFEPROCS to build winhack.c -#endif - /* Borland and MinGW redefine "boolean" in shlwapi.h, so just use the little bit we need */ typedef struct _DLLVERSIONINFO { @@ -53,7 +49,6 @@ Version _WIN_32IE Platform/IE /*#define COMCTL_URL * "http://www.microsoft.com/msdownload/ieplatform/ie/comctrlx86.asp"*/ -extern void FDECL(nethack_exit, (int)); static TCHAR *_get_cmd_arg(TCHAR *pCmdLine); static HRESULT GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor); BOOL WINAPI @@ -63,7 +58,7 @@ _nhapply_image_transparent(HDC hDC, int x, int y, int width, int height, // Global Variables: NHWinApp _nethack_app; -extern int GUILaunched; /* We tell shared startup code in windmain.c +int GUILaunched = TRUE; /* We tell shared startup code in windmain.c that the GUI was launched via this */ #ifdef __BORLANDC__ @@ -71,19 +66,23 @@ extern int GUILaunched; /* We tell shared startup code in windmain.c #define _strdup(s1) strdup(s1) #endif -// Foward declarations of functions included in this code module: -extern boolean FDECL(main, (int, char **)); -static void __cdecl mswin_moveloop(void *); - #define MAX_CMDLINE_PARAM 255 +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 28251) +#endif + +extern int nethackw_main(int argc, char *argv[]); + +static char *argv[MAX_CMDLINE_PARAM]; + int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { INITCOMMONCONTROLSEX InitCtrls; int argc; - char *argv[MAX_CMDLINE_PARAM]; size_t len; TCHAR *p; TCHAR wbuf[BUFSZ]; @@ -96,34 +95,8 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmdShow); - /* - * Get a set of valid safe windowport function - * pointers during early startup initialization. - * - * When get_safe_procs is called with 0 as the param, - * non-functional, but safe function pointers are set - * for all windowport routines. - * - * When get_safe_procs is called with 1 as the param, - * raw_print, raw_print_bold, and wait_synch, and nhgetch - * are set to use C stdio routines via stdio_raw_print, - * stdio_raw_print_bold, stdio_wait_synch, and - * stdio_nhgetch. - */ - windowprocs = *get_safe_procs(0); - - /* - * Now we are going to override a couple - * of the windowprocs functions so that - * error messages are handled in a suitable - * way for the graphical version. - */ - windowprocs.win_raw_print = mswin_raw_print; - windowprocs.win_raw_print_bold = mswin_raw_print_bold; - windowprocs.win_wait_synch = mswin_wait_synch; - win10_init(); - sys_early_init(); + early_init(0, NULL); /* Change as needed to support CRASHREPORT */ /* init application structure */ _nethack_app.hApp = hInstance; @@ -158,6 +131,8 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, _nethack_app.bNoHScroll = FALSE; _nethack_app.bNoVScroll = FALSE; + if (_nethack_app.saved_text) + free(_nethack_app.saved_text), _nethack_app.saved_text = 0; _nethack_app.saved_text = strdup(""); _nethack_app.bAutoLayout = TRUE; @@ -165,7 +140,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, _nethack_app.bNoSounds = FALSE; -#if 0 /* GdiTransparentBlt does not render spash bitmap for whatever reason */ +#if 0 /* GdiTransparentBlt does not render splash bitmap for whatever reason */ /* use system-provided TransparentBlt for Win2k+ */ ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); @@ -178,21 +153,21 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, // init controls if (FAILED(GetComCtlVersion(&major, &minor))) { - char buf[TBUFSZ]; - Sprintf(buf, "Cannot load common control library.\n%s\n%s", + char buf2[TBUFSZ]; + Sprintf(buf2, "Cannot load common control library.\n%s\n%s", "For further information, refer to the installation notes at", INSTALL_NOTES); - panic(buf); + panic("%s", buf2); } if (major < MIN_COMCTLMAJOR || (major == MIN_COMCTLMAJOR && minor < MIN_COMCTLMINOR)) { - char buf[TBUFSZ]; - Sprintf(buf, "Common control library is outdated.\n%s %d.%d\n%s\n%s", + char buf2[TBUFSZ]; + Sprintf(buf2, "Common control library is outdated.\n%s %d.%d\n%s\n%s", "NetHack requires at least version ", MIN_COMCTLMAJOR, MIN_COMCTLMINOR, "For further information, refer to the installation notes at", INSTALL_NOTES); - panic(buf); + panic("%s", buf2); } ZeroMemory(&InitCtrls, sizeof(InitCtrls)); InitCtrls.dwSize = sizeof(InitCtrls); @@ -201,34 +176,34 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, /* get command line parameters */ p = _get_cmd_arg(GetCommandLine()); - p = _get_cmd_arg(NULL); /* skip first paramter - command name */ + p = _get_cmd_arg(NULL); /* skip first parameter - command name */ for (argc = 1; p && argc < MAX_CMDLINE_PARAM; argc++) { len = _tcslen(p); if (len > 0) { - argv[argc] = _strdup(NH_W2A(p, buf, BUFSZ)); + argv[argc] = strdup(NH_W2A(p, buf, BUFSZ)); } else { - argv[argc] = ""; + argv[argc] = strdup(""); } p = _get_cmd_arg(NULL); } GetModuleFileName(NULL, wbuf, BUFSZ); - argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ)); + argv[0] = strdup(NH_W2A(wbuf, buf, BUFSZ)); if (argc == 2) { TCHAR *savefile = strdup(argv[1]); - TCHAR *plname; + TCHAR *name; for (p = savefile; *p && *p != '-'; p++) ; if (*p) { /* we found a '-' */ - plname = p + 1; - for (p = plname; *p && *p != '.'; p++) + name = p + 1; + for (p = name; *p && *p != '.'; p++) ; if (*p) { if (strcmp(p + 1, "NetHack-saved-game") == 0) { *p = '\0'; - argv[1] = "-u"; - argv[2] = _strdup(plname); + argv[1] = strdup("-u"); + argv[2] = strdup(name); argc = 3; } } @@ -236,13 +211,48 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, free(savefile); } GUILaunched = 1; - /* let main do the argument processing */ - (void) main(argc, argv); + /* emergency IO */ + windowprocs.win_raw_print = mswin_raw_print; + windowprocs.win_raw_print_bold = mswin_raw_print_bold; + windowprocs.win_nhgetch = mswin_nhgetch; + windowprocs.win_wait_synch = mswin_wait_synch; + + /* let nethackw_main do the argument processing */ + nethackw_main(argc, argv); + /* not reached */ return 0; } +extern void free_menu_data(void); + +void +free_winmain_stuff(void) +{ + int cnt; + + for (cnt = 0; cnt < MAX_CMDLINE_PARAM; ++cnt) { + if (argv[cnt]) + free((genericptr_t) argv[cnt]), argv[cnt] = 0; + } + if (_nethack_app.saved_text) + free((genericptr_t) _nethack_app.saved_text), + _nethack_app.saved_text = 0; + for (cnt = 0; cnt < MAXWINDOWS; ++cnt) { + if (windowdata[cnt].address) { + if (!windowdata[cnt].isstatic) + free(windowdata[cnt].address); + windowdata[cnt].address = 0; + } + } + free_menu_data(); +} + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + PNHWinApp -GetNHApp() +GetNHApp(void) { return &_nethack_app; } @@ -288,7 +298,7 @@ _get_cmd_arg(TCHAR *pCmdLine) } else { pArgs = NULL; } - + nhUse(bQuoted); return pRetArg; } @@ -406,7 +416,7 @@ _nhapply_image_transparent(HDC hDC, int x, int y, int width, int height, /* Mask out the transparent colored pixels on the source image. */ BitBlt(hdcSave, 0, 0, width, height, hdcBack, 0, 0, SRCAND); - /* XOR the source image with the beckground. */ + /* XOR the source image with the background. */ BitBlt(hdcMem, 0, 0, width, height, hdcSave, 0, 0, SRCPAINT); /* blt resulting image to the screen */ diff --git a/win/win32/NetHackW.rc b/win/win32/NetHackW.rc index 095c8f07e..0a555c803 100644 --- a/win/win32/NetHackW.rc +++ b/win/win32/NetHackW.rc @@ -34,7 +34,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // remains consistent on all systems. IDI_NETHACKW ICON "NETHACK.ICO" - ///////////////////////////////////////////////////////////////////////////// // // Menu @@ -76,18 +75,33 @@ BEGIN MENUITEM "&Lock Windows", IDM_SETTING_LOCKWINDOWS END POPUP "&Help" + // 5.0: HELP_LONG and HELP_OPTIONS_LONG both used to specify &L as their + // accelator. Typing 'L' or 'l' highlighted one of the two, then + // would execute it or typing another 'l' or 'L' would unhighlight the + // currently highlit one and highlight the other. All other accelerators + // just run the relevant entry without needing . HELP_LONG has + // finally been changed to &g for "game". + // + // "// {...}" lines are placeholders for missing entries that are more + // recent than this resource file. The wizard mode one may need to + // stay suppressed since it is conditional. BEGIN MENUITEM "&About ...", IDM_ABOUT - MENUITEM "&Long description of the game", IDM_HELP_LONG + MENUITEM "Long description of the &game", IDM_HELP_LONG MENUITEM "List of &commands", IDM_HELP_COMMANDS MENUITEM "&History of NetHack", IDM_HELP_HISTORY - MENUITEM "&Info on a character", IDM_HELP_INFO_CHAR + MENUITEM "&Info on a display character", IDM_HELP_INFO_CHAR MENUITEM "Info on what a given &key does", IDM_HELP_INFO_KEY MENUITEM "List of game &options", IDM_HELP_OPTIONS MENUITEM "&Longer list of game options", IDM_HELP_OPTIONS_LONG + // { dispfile_optmenu, "Using the %s command to set options." } //"'O'" + // { dokeylist, "Full list of keyboard commands." } MENUITEM "List of e&xtended commands", IDM_HELP_EXTCMD + // { domenucontrols, "List menu control keys." } MENUITEM "The &NetHack license", IDM_HELP_LICENSE + // { docontact, "Support information." } MENUITEM "NetHack for &Windows help", IDM_HELP_PORTHELP + // { dispfile_debughelp, "List of wizard-mode commands." } END END @@ -320,8 +334,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,6,7,0 - PRODUCTVERSION 3,6,7,0 + FILEVERSION 5,0,0,0 + PRODUCTVERSION 5,0,0,0 FILEFLAGSMASK 0x1fL #ifdef _DEBUG FILEFLAGS 0x9L @@ -337,13 +351,13 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "NetHack for Windows - Graphical Interface" - VALUE "FileVersion", "3.6.7" + VALUE "FileVersion", "5.0.0" VALUE "InternalName", "NetHackW" - VALUE "LegalCopyright", "Copyright (C) 1985 - 2023. By Stichting Mathematisch Centrum and M. Stephenson. See license for details." + VALUE "LegalCopyright", "Copyright (C) 1985 - 2026. By Stichting Mathematisch Centrum and M. Stephenson. See license for details." VALUE "OriginalFilename", "NetHackW.exe" VALUE "PrivateBuild", "140606" VALUE "ProductName", "NetHack" - VALUE "ProductVersion", "3.6.7" + VALUE "ProductVersion", "5.0.0" END END BLOCK "VarFileInfo" @@ -376,6 +390,81 @@ BEGIN IDS_APP_TITLE_SHORT "NetHack for Windows" END +#ifdef RCWAV +se_squeak_A WAVE "se_squeak_A.wav" +se_squeak_B WAVE "se_squeak_B.wav" +se_squeak_B_flat WAVE "se_squeak_B_flat.wav" +se_squeak_C WAVE "se_squeak_C.wav" +se_squeak_D WAVE "se_squeak_D.wav" +se_squeak_D_flat WAVE "se_squeak_D_flat.wav" +se_squeak_E WAVE "se_squeak_E.wav" +se_squeak_E_flat WAVE "se_squeak_E_flat.wav" +se_squeak_F WAVE "se_squeak_F.wav" +se_squeak_F_sharp WAVE "se_squeak_F_sharp.wav" +se_squeak_G WAVE "se_squeak_G.wav" +se_squeak_G_share WAVE "se_squeak_G_sharp.wav" + +sound_Bell WAVE "sound_Bell.wav" +sound_Bugle_A WAVE "sound_Bugle_A.wav" +sound_Bugle_B WAVE "sound_Bugle_B.wav" +sound_Bugle_C WAVE "sound_Bugle_C.wav" +sound_Bugle_D WAVE "sound_Bugle_D.wav" +sound_Bugle_E WAVE "sound_Bugle_E.wav" +sound_Bugle_F WAVE "sound_Bugle_F.wav" +sound_Bugle_G WAVE "sound_Bugle_G.wav" +sound_Drum_Of_Earthquake WAVE "sound_Drum_Of_Earthquake.wav" +sound_Fire_Horn WAVE "sound_Fire_Horn.wav" +sound_Frost_Horn WAVE "sound_Frost_Horn.wav" +sound_Leather_Drum WAVE "sound_Leather_Drum.wav" +sound_Magic_Harp_A WAVE "sound_Magic_Harp_A.wav" +sound_Magic_Harp_B WAVE "sound_Magic_Harp_B.wav" +sound_Magic_Harp_C WAVE "sound_Magic_Harp_C.wav" +sound_Magic_Harp_D WAVE "sound_Magic_Harp_D.wav" +sound_Magic_Harp_E WAVE "sound_Magic_Harp_E.wav" +sound_Magic_Harp_F WAVE "sound_Magic_Harp_F.wav" +sound_Magic_Harp_G WAVE "sound_Magic_Harp_G.wav" +sound_Magic_Flute_A WAVE "sound_Magic_Flute_A.wav" +sound_Magic_Flute_B WAVE "sound_Magic_Flute_B.wav" +sound_Magic_Flute_C WAVE "sound_Magic_Flute_C.wav" +sound_Magic_Flute_D WAVE "sound_Magic_Flute_D.wav" +sound_Magic_Flute_E WAVE "sound_Magic_Flute_E.wav" +sound_Magic_Flute_F WAVE "sound_Magic_Flute_F.wav" +sound_Magic_Flute_G WAVE "sound_Magic_Flute_G.wav" +sound_Tooled_Horn_A WAVE "sound_Tooled_Horn_A.wav" +sound_Tooled_Horn_B WAVE "sound_Tooled_Horn_B.wav" +sound_Tooled_Horn_C WAVE "sound_Tooled_Horn_C.wav" +sound_Tooled_Horn_D WAVE "sound_Tooled_Horn_D.wav" +sound_Tooled_Horn_E WAVE "sound_Tooled_Horn_E.wav" +sound_Tooled_Horn_F WAVE "sound_Tooled_Horn_F.wav" +sound_Tooled_Horn_G WAVE "sound_Tooled_Horn_G.wav" +sound_Wooden_Flute_A WAVE "sound_Wooden_Flute_A.wav" +sound_Wooden_Flute_B WAVE "sound_Wooden_Flute_B.wav" +sound_Wooden_Flute_C WAVE "sound_Wooden_Flute_C.wav" +sound_Wooden_Flute_D WAVE "sound_Wooden_Flute_D.wav" +sound_Wooden_Flute_E WAVE "sound_Wooden_Flute_E.wav" +sound_Wooden_Flute_F WAVE "sound_Wooden_Flute_F.wav" +sound_Wooden_Flute_G WAVE "sound_Wooden_Flute_G.wav" +sound_Wooden_Harp_A WAVE "sound_Wooden_Harp_A.wav" +sound_Wooden_Harp_B WAVE "sound_Wooden_Harp_B.wav" +sound_Wooden_Harp_C WAVE "sound_Wooden_Harp_C.wav" +sound_Wooden_Harp_D WAVE "sound_Wooden_Harp_D.wav" +sound_Wooden_Harp_E WAVE "sound_Wooden_Harp_E.wav" +sound_Wooden_Harp_F WAVE "sound_Wooden_Harp_F.wav" +sound_Wooden_Harp_G WAVE "sound_Wooden_Harp_G.wav" +sa2_xpleveldown WAVE "sa2_xpleveldown.wav" +sa2_xplevelup WAVE "sa2_xplevelup.wav" +#endif + +#ifdef VIA_MAKE +#ifndef ID_MANIFEST +#define ID_MANIFEST 1 +#endif +#ifndef RT_MANIFEST +#define RT_MANIFEST MAKEINTRESOURCE(24) +#endif +ID_MANIFEST RT_MANIFEST "NetHackW.exe.manifest" +#endif + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/win/win32/dgnstuff-mingw32.mak b/win/win32/dgnstuff-mingw32.mak deleted file mode 100644 index d81c95795..000000000 --- a/win/win32/dgnstuff-mingw32.mak +++ /dev/null @@ -1,93 +0,0 @@ -# $NHDT-Date: 1524689255 2018/04/25 20:47:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ -# Copyright (c) 2018 by Michael Allison -# NetHack may be freely redistributed. See license for details. - -# Set all of these or none of them. -# -# bison and flex are the ones found in GnuWin32, which -# is probably the easiest set of these tools to find -# on Windows. -# -#YACC = bison.exe -y -#LEX = flex.exe -#YTABC = y.tab.c -#YTABH = y.tab.h -#LEXYYC = lex.yy.c -SHELL=cmd.exe - -default: all - -all: tools ../util/dgn_yacc.c ../util/dgn_lex.c - -rebuild: clean all - -clean: - -del ..\util\dgn_lex.c - -del ..\util\dgn_yacc.c - -del ..\include\dgn_comp.h - -tools: -ifneq "$(YACC)" "" - @echo Yacc-alike set to $(YACC) - @echo YTABC set to $(YTABC) - @echo YTABH set to $(YTABH) -endif - -ifneq "$(LEX)" "" - @echo Lex-alike set to $(LEX) - @echo LEXYYC set to $(LEXYYC) -endif - -#========================================== -# Dungeon Compiler Stuff -#========================================== - -../include/dgn_comp.h : ../util/dgn_comp.y -ifeq "$(YACC)" "" - @echo Using pre-built dgn_comp.h - chdir ..\include - copy /y ..\sys\share\dgn_comp.h - copy /b dgn_comp.h+,, - chdir ..\src -else - chdir ..\util - $(YACC) -d dgn_comp.y - copy $(YTABC) $@ - copy $(YTABH) ..\include\dgn_comp.h - @del $(YTABC) - @del $(YTABH) - chdir ..\build -endif - -../util/dgn_yacc.c : ../util/dgn_comp.y -ifeq "$(YACC)" "" - @echo Using pre-built dgn_yacc.c - chdir ..\util - copy /y ..\sys\share\dgn_yacc.c - copy /b dgn_yacc.c+,, - chdir ..\src -else - chdir ..\util - $(YACC) -d dgn_comp.y - copy $(YTABC) $@ - copy $(YTABH) ..\include\dgn_comp.h - @del $(YTABC) - @del $(YTABH) - chdir ..\build -endif - -../util/dgn_lex.c: ../util/dgn_comp.l -ifeq "$(LEX)" "" - @echo Using pre-built dgn_lex.c - chdir ..\util - copy /y ..\sys\share\dgn_lex.c - copy /b dgn_lex.c+,, - chdir ..\src -else - chdir ..\util - $(LEX) dgn_comp.l - copy $(LEXYYC) $@ - @del $(LEXYYC) - chdir ..\build -endif - diff --git a/win/win32/dgnstuff.mak b/win/win32/dgnstuff.mak deleted file mode 100644 index d32dec0ce..000000000 --- a/win/win32/dgnstuff.mak +++ /dev/null @@ -1,93 +0,0 @@ -# $NHDT-Date: 1524689255 2018/04/25 20:47:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ -# Copyright (c) 2018 by Michael Allison -# NetHack may be freely redistributed. See license for details. - -# Set all of these or none of them. -# -# bison and flex are the ones found in GnuWin32, which -# is probably the easiest set of these tools to find -# on Windows. -# -#YACC = bison.exe -y -#LEX = flex.exe -#YTABC = y.tab.c -#YTABH = y.tab.h -#LEXYYC = lex.yy.c - - -default: all - -all: tools ..\util\dgn_yacc.c ..\util\dgn_lex.c - -rebuild: clean all - -clean: - -del ..\util\dgn_lex.c - -del ..\util\dgn_yacc.c - -del ..\include\dgn_comp.h - -tools: -!IFDEF YACC - @echo Yacc-alike set to $(YACC) - @echo YTABC set to $(YTABC) - @echo YTABH set to $(YTABH) -!ENDIF - -!IFDEF LEX - @echo Lex-alike set to $(LEX) - @echo LEXYYC set to $(LEXYYC) -!ENDIF - - -#========================================== -# Dungeon Compiler Stuff -#========================================== - -..\include\dgn_comp.h : ..\util\dgn_comp.y -!IF "$(YACC)"=="" - @echo Using pre-built dgn_comp.h - chdir ..\include - copy /y ..\sys\share\dgn_comp.h - copy /b dgn_comp.h+,, - chdir ..\src -!ELSE - chdir ..\util - $(YACC) -d dgn_comp.y - copy $(YTABC) $@ - copy $(YTABH) ..\include\dgn_comp.h - @del $(YTABC) - @del $(YTABH) - chdir ..\src -!ENDIF - -..\util\dgn_yacc.c : ..\util\dgn_comp.y -!IF "$(YACC)"=="" - @echo Using pre-built dgn_yacc.c - chdir ..\util - copy /y ..\sys\share\dgn_yacc.c - copy /b dgn_yacc.c+,, - chdir ..\src -!ELSE - chdir ..\util - $(YACC) -d dgn_comp.y - copy $(YTABC) $@ - copy $(YTABH) ..\include\dgn_comp.h - @del $(YTABC) - @del $(YTABH) - chdir ..\src -!ENDIF - -..\util\dgn_lex.c: ..\util\dgn_comp.l -!IF "$(LEX)"=="" - @echo Using pre-built dgn_lex.c - chdir ..\util - copy /y ..\sys\share\dgn_lex.c - copy /b dgn_lex.c+,, - chdir ..\src -!ELSE - chdir ..\util - $(LEX) dgn_comp.l - copy $(LEXYYC) $@ - @del $(LEXYYC) - chdir ..\src -!ENDIF diff --git a/win/win32/levstuff-mingw32.mak b/win/win32/levstuff-mingw32.mak deleted file mode 100644 index 524755c1f..000000000 --- a/win/win32/levstuff-mingw32.mak +++ /dev/null @@ -1,100 +0,0 @@ -# $NHDT-Date: 1524689255 2018/04/25 20:47:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ -# Copyright (c) 2018 by Michael Allison -# NetHack may be freely redistributed. See license for details. - -# Set all of these or none of them. -# -# bison and flex are the ones found in GnuWin32, which -# is probably the easiest set of these tools to find -# on Windows. -# -#YACC = bison.exe -y -#LEX = flex.exe -#YTABC = y.tab.c -#YTABH = y.tab.h -#LEXYYC = lex.yy.c -SHELL = cmd.exe - -default: all - -all: tools ../util/lev_yacc.c ../util/lev_lex.c - -rebuild: clean all - -clean: - -del ..\util\lev_lex.c - -del ..\util\lev_yacc.c - -del ..\include\lev_comp.h - -tools: -ifneq "$(YACC)" "" - @echo Yacc-alike set to "$(YACC)" - @echo YTABC set to $(YTABC) - @echo YTABH set to $(YTABH) -endif - -ifneq "$(LEX)" "" - @echo Lex-alike set to "$(LEX)" - @echo LEXYYC set to $(LEXYYC) -endif - -#========================================== -# Level Compiler Stuff -#========================================== - -../include/lev_comp.h: ../util/lev_comp.y - @echo Yacc-alike set to "$(YACC)" -ifeq "$(YACC)" "" - @echo Using pre-built lev_comp.h - chdir ..\include - copy /y ..\sys\share\lev_comp.h - copy /b lev_comp.h+,, - chdir ..\src -else - @echo Generating lev_yacc.c and lev_comp.h - chdir ..\util - $(YACC) -d lev_comp.y - copy $(YTABC) $@ - copy $(YTABH) ..\include\lev_comp.h - @del $(YTABC) - @del $(YTABH) - chdir ..\src -endif - -../util/lev_yacc.c: ../util/lev_comp.y - @echo Yacc-alike set to "$(YACC)" -ifeq "$(YACC)" "" - @echo Using pre-built lev_yacc.c - chdir ..\util - copy /y ..\sys\share\lev_yacc.c - copy /b lev_yacc.c+,, - chdir ..\src -else - @echo Generating lev_yacc.c and lev_comp.h - chdir ..\util - $(YACC) -d lev_comp.y - copy $(YTABC) $@ - copy $(YTABH) ..\include\lev_comp.h - @del $(YTABC) - @del $(YTABH) - chdir ..\src -endif - -../util/lev_lex.c: ../util/lev_comp.l - @echo Lex-alike set to "$(LEX)" -ifeq "$(LEX)" "" - @echo Using pre-built lev_lex.c - chdir ..\util - copy /y ..\sys\share\lev_lex.c - copy /b lev_lex.c+,, - chdir ..\src -else - @echo Generating lev_lex.c - chdir ..\util - $(LEX) lev_comp.l - copy $(LEXYYC) $@ - @del $(LEXYYC) - chdir ..\src -endif - - diff --git a/win/win32/levstuff.mak b/win/win32/levstuff.mak deleted file mode 100644 index 0a38390d1..000000000 --- a/win/win32/levstuff.mak +++ /dev/null @@ -1,96 +0,0 @@ -# $NHDT-Date: 1524689255 2018/04/25 20:47:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ -# Copyright (c) 2018 by Michael Allison -# NetHack may be freely redistributed. See license for details. - -# Set all of these or none of them. -# -# bison and flex are the ones found in GnuWin32, which -# is probably the easiest set of these tools to find -# on Windows. -# -#YACC = bison.exe -y -#LEX = flex.exe -#YTABC = y.tab.c -#YTABH = y.tab.h -#LEXYYC = lex.yy.c - - -default: all - -all: tools ..\util\lev_yacc.c ..\util\lev_lex.c - -rebuild: clean all - -clean: - -del ..\util\lev_lex.c - -del ..\util\lev_yacc.c - -del ..\include\lev_comp.h - -tools: -!IFDEF YACC - @echo Yacc-alike set to $(YACC) - @echo YTABC set to $(YTABC) - @echo YTABH set to $(YTABH) -!ENDIF - -!IFDEF LEX - @echo Lex-alike set to $(LEX) - @echo LEXYYC set to $(LEXYYC) -!ENDIF - -#========================================== -# Level Compiler Stuff -#========================================== - -..\include\lev_comp.h: ..\util\lev_comp.y -!IFNDEF YACC - @echo Using pre-built lev_comp.h - chdir ..\include - copy /y ..\sys\share\lev_comp.h - copy /b lev_comp.h+,, - chdir ..\src -!ELSE - @echo Generating lev_yacc.c and lev_comp.h - chdir ..\util - $(YACC) -d lev_comp.y - copy $(YTABC) $@ - copy $(YTABH) ..\include\lev_comp.h - @del $(YTABC) - @del $(YTABH) - chdir ..\src -!ENDIF - -..\util\lev_yacc.c: ..\util\lev_comp.y -!IFNDEF YACC - @echo Using pre-built lev_yacc.c - chdir ..\util - copy /y ..\sys\share\lev_yacc.c - copy /b lev_yacc.c+,, - chdir ..\src -!ELSE - @echo Generating lev_yacc.c and lev_comp.h - chdir ..\util - $(YACC) -d lev_comp.y - copy $(YTABC) $@ - copy $(YTABH) ..\include\lev_comp.h - @del $(YTABC) - @del $(YTABH) - chdir ..\src -!ENDIF - -..\util\lev_lex.c: ..\util\lev_comp.l -!IFNDEF LEX - @echo Using pre-built lev_lex.c - chdir ..\util - copy /y ..\sys\share\lev_lex.c - copy /b lev_lex.c+,, - chdir ..\src -!ELSE - @echo Generating lev_lex.c - chdir ..\util - $(LEX) lev_comp.l - copy $(LEXYYC) $@ - @del $(LEXYYC) - chdir ..\src -!ENDIF - diff --git a/win/win32/mhaskyn.c b/win/win32/mhaskyn.c index 396025fb0..9ed889b9a 100644 --- a/win/win32/mhaskyn.c +++ b/win/win32/mhaskyn.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 mhaskyn.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mhaskyn.c $NHDT-Date: 1596498346 2020/08/03 23:45:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include diff --git a/win/win32/mhaskyn.h b/win/win32/mhaskyn.h index 700107a41..d81a33698 100644 --- a/win/win32/mhaskyn.h +++ b/win/win32/mhaskyn.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhaskyn.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 5.0 mhaskyn.h $NHDT-Date: 1596498347 2020/08/03 23:45:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhdlg.c b/win/win32/mhdlg.c index cb76c9a18..0d48f2531 100644 --- a/win/win32/mhdlg.c +++ b/win/win32/mhdlg.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 mhdlg.c $NHDT-Date: 1544695946 2018/12/13 10:12:26 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mhdlg.c $NHDT-Date: 1596498347 2020/08/03 23:45:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.36 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* various dialog boxes are defined here */ @@ -12,7 +12,10 @@ #include "mhdlg.h" #include - +int list_view_height(HWND hWnd, int count); +void get_rect_size(RECT *rect, SIZE *size); +void center_dialog(HWND dialog); +void size_dialog(HWND dialog, SIZE new_client_size); /*---------------------------------------------------------------*/ /* data for getlin dialog */ @@ -38,7 +41,7 @@ mswin_getlin_window(const char *question, char *result, size_t result_size) INT_PTR ret; struct getlin_data data; - /* initilize dialog data */ + /* initialize dialog data */ ZeroMemory(&data, sizeof(data)); data.question = question; data.result = result; @@ -134,18 +137,20 @@ GetlinDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_COMMAND: { - TCHAR wbuf[BUFSZ]; + TCHAR wbuf2[BUFSZ]; + wbuf2[BUFSZ - 1] = '\0'; switch (LOWORD(wParam)) { /* OK button was pressed */ case IDOK: data = (struct getlin_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA); SendDlgItemMessage(hWnd, IDC_GETLIN_EDIT, WM_GETTEXT, - (WPARAM) sizeof(wbuf), (LPARAM) wbuf); - NH_W2A(wbuf, data->result, data->result_size); + (WPARAM) sizeof(wbuf2), (LPARAM) wbuf2); + NH_W2A(wbuf2, data->result, data->result_size); - /* Fall through. */ + FALLTHROUGH; + /* FALLTHRU */ /* cancel button was pressed */ case IDCANCEL: @@ -245,7 +250,8 @@ ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) hWnd, IDC_EXTCMD_LIST, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0); if (*data->selection == LB_ERR) *data->selection = -1; - /* Fall through. */ + FALLTHROUGH; + /* FALLTHRU */ /* CANCEL button ws clicked */ case IDCANCEL: @@ -300,7 +306,7 @@ enum player_selector_control { psc_control_count }; -static const s_psc_id[psc_control_count] = { +static const int s_psc_id[psc_control_count] = { IDC_PLSEL_NAME_GROUP, IDC_PLSEL_ROLE_GROUP, IDC_PLSEL_RACE_GROUP, @@ -343,9 +349,14 @@ INT_PTR CALLBACK PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM); static void plselAdjustSelections(HWND hWnd); static boolean plselRandomize(plsel_data_t * data); static BOOL plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam); +void calculate_player_selector_layout(plsel_data_t * data); +void move_controls(control_t * controls, int count); +void do_player_selector_layout(plsel_data_t * data); +void plselInitDialog(struct plsel_data * data); +int plselFinalSelection(HWND hWnd); boolean -mswin_player_selection_window() +mswin_player_selection_window(void) { INT_PTR ret; plsel_data_t data; @@ -401,7 +412,7 @@ calculate_player_selector_layout(plsel_data_t * data) name_box->size.cy = (int) (24 * scale); control_t * role_list = &data->controls[psc_role_list]; - /* NOTE: we dont' scale the list view reported height as it appears these + /* NOTE: we don't scale the list view reported height as it appears these values are the actual size the control will be drawn at using the existing DPI value */ role_list->size.cy = list_view_height(role_list->hWnd, data->role_count); @@ -574,6 +585,7 @@ plselInitDialog(struct plsel_data * data) { TCHAR wbuf[BUFSZ]; LVCOLUMN lvcol; + control_t *control; SetWindowLongPtr(data->dialog, GWLP_USERDATA, (LONG_PTR) data); @@ -646,7 +658,7 @@ plselInitDialog(struct plsel_data * data) /* set player name */ control_t * name_box = &data->controls[psc_name_box]; - SetDlgItemText(data->dialog, name_box->id, NH_A2W(plname, wbuf, sizeof(wbuf))); + SetDlgItemText(data->dialog, name_box->id, NH_A2W(svp.plname, wbuf, sizeof(wbuf))); plselRandomize(data); @@ -654,10 +666,12 @@ plselInitDialog(struct plsel_data * data) plselAdjustSelections(data->dialog); /* set tab order */ - control_t * control = &data->controls[psc_quit_button]; - for(int i = psc_quit_button; i >= psc_name_box; i--, control++) - SetWindowPos(control->hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + for (int i = psc_quit_button; i >= psc_name_box; i--) { + control = &data->controls[i]; + SetWindowPos(control->hWnd, NULL, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE); + } do_player_selector_layout(data); center_dialog(data->dialog); @@ -868,13 +882,18 @@ plselAdjustSelections(HWND hWnd) /* player made up his mind - get final selection here */ int -plselFinalSelection(HWND hWnd) +plselFinalSelection(HWND hWnd UNUSED) { - int role = flags.initrole; - int race = flags.initrace; - int gender = flags.initgend; - int alignment = flags.initalign; + int role, race, gender, alignment; + nhUse(role); + nhUse(race); + nhUse(gender); + nhUse(alignment); + role = flags.initrole; + race = flags.initrace; + gender = flags.initgend; + alignment = flags.initalign; assert(role != ROLE_RANDOM && role != ROLE_NONE); assert(race != ROLE_RANDOM && race != ROLE_NONE); assert(gender != ROLE_RANDOM && gender != ROLE_NONE); @@ -889,6 +908,7 @@ plselFinalSelection(HWND hWnd) static boolean plselRandomize(plsel_data_t * data) { + int role, race, gender, alignment; boolean fully_specified = TRUE; // restore back to configuration settings @@ -914,10 +934,10 @@ static boolean plselRandomize(plsel_data_t * data) rigid_role_checks(); - int role = flags.initrole; - int race = flags.initrace; - int gender = flags.initgend; - int alignment = flags.initalign; + role = flags.initrole; + race = flags.initrace; + gender = flags.initgend; + alignment = flags.initalign; assert(role != ROLE_RANDOM && role != ROLE_NONE); assert(race != ROLE_RANDOM && race != ROLE_NONE); @@ -972,7 +992,7 @@ plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA); /* If there are no list box items, skip this message. */ - if (lpdis->itemID < 0) + if (lpdis->itemID == (UINT) -1) return FALSE; HWND control = GetDlgItem(hWnd, (int) wParam); diff --git a/win/win32/mhdlg.h b/win/win32/mhdlg.h index c028fc82b..9c3414da4 100644 --- a/win/win32/mhdlg.h +++ b/win/win32/mhdlg.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhdlg.h $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 5.0 mhdlg.h $NHDT-Date: 1596498348 2020/08/03 23:45:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -12,6 +12,6 @@ int mswin_getlin_window(const char *question, char *result, size_t result_size); int mswin_ext_cmd_window(int *selection); -boolean mswin_player_selection_window(); +boolean mswin_player_selection_window(void); #endif /* MSWINDlgWindow_h */ diff --git a/win/win32/mhfont.c b/win/win32/mhfont.c index 18e09082e..5b39bcbf0 100644 --- a/win/win32/mhfont.c +++ b/win/win32/mhfont.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 mhfont.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.23 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mhfont.c $NHDT-Date: 1596498349 2020/08/03 23:45:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.29 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* font management and such */ @@ -55,7 +55,7 @@ mswin_font_supports_unicode(HFONT hFont) return FALSE; } -/* create font based on window type, charater attributes and +/* create font based on window type, character attributes and window device context */ cached_font * mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace) @@ -217,7 +217,7 @@ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace) } UINT -mswin_charset() +mswin_charset(void) { CHARSETINFO cis; if (SYMHANDLING(H_IBM)) diff --git a/win/win32/mhfont.h b/win/win32/mhfont.h index 9402d54a9..c4f10826f 100644 --- a/win/win32/mhfont.h +++ b/win/win32/mhfont.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhfont.h $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ +/* NetHack 5.0 mhfont.h $NHDT-Date: 1596498350 2020/08/03 23:45:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.17 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhinput.c b/win/win32/mhinput.c index d0e3c7076..7f209ea20 100644 --- a/win/win32/mhinput.c +++ b/win/win32/mhinput.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 mhinput.c $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mhinput.c $NHDT-Date: 1596498350 2020/08/03 23:45:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include @@ -34,7 +34,7 @@ mswin_nh_input_init(void) /* check for input */ int -mswin_have_input() +mswin_have_input(void) { return #ifdef SAFERHANGUP @@ -63,7 +63,7 @@ mswin_input_push(PMSNHEvent event) /* get event from the queue and delete it */ PMSNHEvent -mswin_input_pop() +mswin_input_pop(void) { PMSNHEvent retval; @@ -72,7 +72,7 @@ mswin_input_pop() if (program_state.done_hup) { static MSNHEvent hangup_event; hangup_event.type = NHEVENT_CHAR; - hangup_event.kbd.ch = '\033'; + hangup_event.ei.kbd.ch = '\033'; return &hangup_event; } #endif @@ -92,7 +92,7 @@ mswin_input_pop() /* get event from the queue but leave it there */ PMSNHEvent -mswin_input_peek() +mswin_input_peek(void) { PMSNHEvent retval; @@ -101,7 +101,7 @@ mswin_input_peek() if (program_state.done_hup) { static MSNHEvent hangup_event; hangup_event.type = NHEVENT_CHAR; - hangup_event.kbd.ch = '\033'; + hangup_event.ei.kbd.ch = '\033'; return &hangup_event; } #endif diff --git a/win/win32/mhinput.h b/win/win32/mhinput.h index f8e58f054..20c7af695 100644 --- a/win/win32/mhinput.h +++ b/win/win32/mhinput.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhinput.h $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 5.0 mhinput.h $NHDT-Date: 1596498351 2020/08/03 23:45:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,34 +10,37 @@ #define NHEVENT_CHAR 1 #define NHEVENT_MOUSE 2 + +union event_innards { + struct { + int ch; + } kbd; + + struct { + int mod; + int x, y; + } ms; +}; + typedef struct mswin_event { int type; - union { - struct { - int ch; - } kbd; - - struct { - int mod; - int x, y; - } ms; - }; + union event_innards ei; } MSNHEvent, *PMSNHEvent; #define NHEVENT_KBD(c) \ { \ MSNHEvent e; \ e.type = NHEVENT_CHAR; \ - e.kbd.ch = (c); \ + e.ei.kbd.ch = (c); \ mswin_input_push(&e); \ } #define NHEVENT_MS(_mod, _x, _y) \ { \ MSNHEvent e; \ e.type = NHEVENT_MOUSE; \ - e.ms.mod = (_mod); \ - e.ms.x = (_x); \ - e.ms.y = (_y); \ + e.ei.ms.mod = (_mod); \ + e.ei.ms.x = (_x); \ + e.ei.ms.y = (_y); \ mswin_input_push(&e); \ } diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index e775f12a7..94f2249bc 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -1,11 +1,13 @@ -/* NetHack 3.6 mhmain.c $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.62 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mhmain.c $NHDT-Date: 1596498352 2020/08/03 23:45:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.76 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include -#include "date.h" +#include "config.h" +#if !defined(PATCHLEVEL_H) #include "patchlevel.h" +#endif #include "resource.h" #include "mhmsg.h" #include "mhinput.h" @@ -23,8 +25,9 @@ extern winid WIN_STATUS; static TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass"); static TCHAR szTitle[MAX_LOADSTRING]; +struct window_tracking_data windowdata[MAXWINDOWS]; extern void mswin_display_splash_window(BOOL); - +extern void free_menu_data(void); /* mhmenu.c */ LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); static LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); @@ -33,12 +36,15 @@ static void register_main_window_class(void); static int menuid2mapmode(int menuid); static int mapmode2menuid(int map_mode); static void nhlock_windows(BOOL lock); -static char *nh_compose_ascii_screenshot(); -static void mswin_apply_window_style_all(); +static char *nh_compose_ascii_screenshot(void); +#ifdef ENHANCED_SYMBOLS +static WCHAR *nh_compose_unicode_screenshot(void); +#endif +static void mswin_apply_window_style_all(void); // returns strdup() created pointer - callee assumes the ownership HWND -mswin_init_main_window() +mswin_init_main_window(void) { static int run_once = 0; HWND ret; @@ -92,7 +98,7 @@ mswin_init_main_window() } void -register_main_window_class() +register_main_window_class(void) { WNDCLASS wcex; @@ -185,7 +191,7 @@ static const char scanmap[] = { 'b', 'n', 'm', ',', '.', '?' /* ... */ }; -#define IDT_FUZZ_TIMER 100 +#define IDT_FUZZ_TIMER 100 /* // FUNCTION: WndProc(HWND, unsigned, WORD, LONG) @@ -203,9 +209,11 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) data = (PNHMainWindow) malloc(sizeof(NHMainWindow)); if (!data) panic("out of memory"); + ZeroMemory(data, sizeof(NHMainWindow)); data->mapAcsiiModeSave = MAP_MODE_ASCII12x16; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + windowdata[NHW_MAIN].address = (genericptr_t) data; /* update menu items */ CheckMenuItem( @@ -378,7 +386,7 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) c = 0; ZeroMemory(kbd_state, sizeof(kbd_state)); - GetKeyboardState(kbd_state); + (void) GetKeyboardState(kbd_state); if (ToAscii((UINT) wParam, (lParam >> 16) & 0xFF, kbd_state, &c, 0)) { NHEVENT_KBD(c & 0xFF); @@ -400,7 +408,7 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if (GetNHApp()->regNetHackMode && ((lParam & 1 << 29) != 0)) { unsigned char c = (unsigned char) (wParam & 0xFF); unsigned char scancode = (lParam >> 16) & 0xFF; - if (index(extendedlist, tolower(c)) != 0) { + if (strchr(extendedlist, tolower(c)) != 0) { NHEVENT_KBD(M(tolower(c))); } else if (scancode == (SCANLO + SIZE(scanmap)) - 1) { NHEVENT_KBD(M('?')); @@ -504,7 +512,7 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /* clean up */ free((PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA)); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); - + windowdata[NHW_MAIN].address = 0; // PostQuitMessage(0); exit(1); break; @@ -536,6 +544,7 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) mswin_select_map_mode(iflags.wc_map_mode); child = GetNHApp()->windowlist[msg_param->wid].win; + nhUse(child); } break; case MSNH_MSG_RANDOM_INPUT: { @@ -745,62 +754,66 @@ mswin_layout_main_window(HWND changed_child) } if (IsWindow(changed_child)) SetForegroundWindow(changed_child); + nhUse(data); } +VOID CALLBACK FuzzTimerProc( _In_ HWND hwnd, + _In_ UINT uMsg, _In_ UINT_PTR idEvent, + _In_ DWORD dwTime); + VOID CALLBACK FuzzTimerProc( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ UINT_PTR idEvent, - _In_ DWORD dwTime - ) + _In_ HWND hwnd, + _In_ UINT uMsg UNUSED, + _In_ UINT_PTR idEvent UNUSED, + _In_ DWORD dwTime UNUSED) { - INPUT input[16]; - int i_pos = 0; - int c = randomkey(); - SHORT k = VkKeyScanA(c); - BOOL gen_alt = (rn2(50) == 0) && isalpha(c); - - if (!iflags.debug_fuzzer) { - KillTimer(hwnd, IDT_FUZZ_TIMER); - return; - } - - if (!GetFocus()) + INPUT input[16]; + int i_pos = 0; + int c = randomkey(); + SHORT k = VkKeyScanA(c); + BOOL gen_alt = (rn2(50) == 0) && isalpha(c); + + if (!iflags.debug_fuzzer) { + KillTimer(hwnd, IDT_FUZZ_TIMER); + return; + } + + if (!GetFocus()) return; - ZeroMemory(input, sizeof(input)); - if (gen_alt) { - input[i_pos].type = INPUT_KEYBOARD; - input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE; - input[i_pos].ki.wScan = MapVirtualKey(VK_MENU, 0); - i_pos++; - } - - if (HIBYTE(k) & 1) { - input[i_pos].type = INPUT_KEYBOARD; - input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE; - input[i_pos].ki.wScan = MapVirtualKey(VK_LSHIFT, 0); - i_pos++; - } - - input[i_pos].type = INPUT_KEYBOARD; - input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE; - input[i_pos].ki.wScan = MapVirtualKey(LOBYTE(k), 0); - i_pos++; - - if (HIBYTE(k) & 1) { - input[i_pos].type = INPUT_KEYBOARD; - input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; - input[i_pos].ki.wScan = MapVirtualKey(VK_LSHIFT, 0); - i_pos++; - } - if (gen_alt) { - input[i_pos].type = INPUT_KEYBOARD; - input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; - input[i_pos].ki.wScan = MapVirtualKey(VK_MENU, 0); - i_pos++; - } - SendInput(i_pos, input, sizeof(input[0])); + ZeroMemory(input, sizeof(input)); + if (gen_alt) { + input[i_pos].type = INPUT_KEYBOARD; + input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE; + input[i_pos].ki.wScan = MapVirtualKey(VK_MENU, 0); + i_pos++; + } + + if (HIBYTE(k) & 1) { + input[i_pos].type = INPUT_KEYBOARD; + input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE; + input[i_pos].ki.wScan = MapVirtualKey(VK_LSHIFT, 0); + i_pos++; + } + + input[i_pos].type = INPUT_KEYBOARD; + input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE; + input[i_pos].ki.wScan = MapVirtualKey(LOBYTE(k), 0); + i_pos++; + + if (HIBYTE(k) & 1) { + input[i_pos].type = INPUT_KEYBOARD; + input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; + input[i_pos].ki.wScan = MapVirtualKey(VK_LSHIFT, 0); + i_pos++; + } + if (gen_alt) { + input[i_pos].type = INPUT_KEYBOARD; + input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; + input[i_pos].ki.wScan = MapVirtualKey(VK_MENU, 0); + i_pos++; + } + SendInput(i_pos, input, sizeof(input[0])); } LRESULT @@ -869,42 +882,86 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) break; case IDM_SETTING_SCREEN_TO_CLIPBOARD: { - char *p; + char *p = NULL; +#ifdef ENHANCED_SYMBOLS + WCHAR *wp = NULL; +#endif + unsigned chr_size = 1; size_t len; HANDLE hglbCopy; - char *p_copy; - p = nh_compose_ascii_screenshot(); - if (!p) - return 0; - len = strlen(p); +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8)) { + wp = nh_compose_unicode_screenshot(); + if (!wp) + return 0; + len = wcslen(wp); + chr_size = sizeof(WCHAR); + } else +#endif + { + p = nh_compose_ascii_screenshot(); + if (!p) + return 0; + len = strlen(p); + } if (!OpenClipboard(hWnd)) { NHMessageBox(hWnd, TEXT("Cannot open clipboard"), MB_OK | MB_ICONERROR); free(p); +#ifdef ENHANCED_SYMBOLS + free(wp); +#endif return 0; } EmptyClipboard(); - hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * sizeof(char)); + hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * chr_size); if (hglbCopy == NULL) { CloseClipboard(); free(p); +#ifdef ENHANCED_SYMBOLS + free(wp); +#endif return FALSE; } - p_copy = (char *) GlobalLock(hglbCopy); - strncpy(p_copy, p, len); - p_copy[len] = 0; // null character +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8)) { + WCHAR *p_copy; + + if ((p_copy = (WCHAR *) GlobalLock(hglbCopy)) != 0) { + wcsncpy(p_copy, wp, len); + p_copy[len] = 0; // null character + } + } else { +#endif + char *p_copy; + + if ((p_copy = (char *) GlobalLock(hglbCopy)) != 0) { + strncpy(p_copy, p, len); + p_copy[len] = 0; // null character + } +#ifdef ENHANCED_SYMBOLS + } +#endif GlobalUnlock(hglbCopy); - SetClipboardData(SYMHANDLING(H_IBM) ? CF_OEMTEXT : CF_TEXT, hglbCopy); +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8)) + SetClipboardData(CF_UNICODETEXT, hglbCopy); + else +#endif + SetClipboardData(SYMHANDLING(H_IBM) ? CF_OEMTEXT : CF_TEXT, hglbCopy); CloseClipboard(); free(p); +#ifdef ENHANCED_SYMBOLS + free(wp); +#endif } break; case IDM_SETTING_SCREEN_TO_FILE: { @@ -933,7 +990,7 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) ofn.nMaxFile = SIZE(filename); ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NH_A2W(hackdir, whackdir, MAX_PATH); + ofn.lpstrInitialDir = NH_A2W(gh.hackdir, whackdir, MAX_PATH); ofn.lpstrTitle = NULL; ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; ofn.nFileOffset = 0; @@ -946,28 +1003,47 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) if (!GetSaveFileName(&ofn)) return FALSE; - text = nh_compose_ascii_screenshot(); - if (!text) - return FALSE; +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8)) { + text = NULL; + wtext = nh_compose_unicode_screenshot(); + if (!wtext) + return FALSE; + tlen = wcslen(wtext); + } else +#endif + { + text = nh_compose_ascii_screenshot(); + if (!text) + return FALSE; + tlen = strlen(text); + wtext = (wchar_t *) malloc(tlen * sizeof(wchar_t)); + if (wtext) { + MultiByteToWideChar(NH_CODEPAGE, 0, text, -1, wtext, tlen); + } + } + filename[SIZE(filename) - 1] = '\0'; pFile = _tfopen(filename, TEXT("wt+,ccs=UTF-8")); if (!pFile) { TCHAR buf[4096]; - _stprintf(buf, TEXT("Cannot open %s for writing!"), filename); + nh_stprintf(buf, sizeof buf, + TEXT("Cannot open %s for writing!"), filename); NHMessageBox(hWnd, buf, MB_OK | MB_ICONERROR); - free(text); + if (text) + free(text); + if (wtext) + free(wtext); return FALSE; } - tlen = strlen(text); - wtext = (wchar_t *) malloc(tlen * sizeof(wchar_t)); - if (!wtext) - panic("out of memory"); - MultiByteToWideChar(NH_CODEPAGE, 0, text, -1, wtext, tlen); - fwrite(wtext, tlen * sizeof(wchar_t), 1, pFile); - fclose(pFile); - free(text); - free(wtext); + if (wtext) { + fwrite(wtext, tlen * sizeof(wchar_t), 1, pFile); + fclose(pFile); + free(wtext); + } + if (text) + free(text); } break; case IDM_NHMODE: { @@ -1043,10 +1119,11 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) default: return 1; } + nhUse(wmEvent); return 0; } -// Mesage handler for about box. +// Message handler for about box. LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { @@ -1059,15 +1136,15 @@ About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: - getversionstring(buf); + getversionstring(buf, sizeof buf); SetDlgItemText(hDlg, IDC_ABOUT_VERSION, NH_A2W(buf, wbuf, sizeof(wbuf))); + Sprintf(buf, "%s\n%s\n%s\n%s", + COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B, + nomakedefs.copyright_banner_c, COPYRIGHT_BANNER_D); SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT, - NH_A2W(COPYRIGHT_BANNER_A "\n" COPYRIGHT_BANNER_B - "\n" COPYRIGHT_BANNER_C - "\n" COPYRIGHT_BANNER_D, - wbuf, BUFSZ)); + NH_A2W(buf, wbuf, sizeof(wbuf))); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); @@ -1096,7 +1173,7 @@ About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) } void -mswin_menu_check_intf_mode() +mswin_menu_check_intf_mode(void) { HMENU hMenu = GetMenu(GetNHApp()->hMainWnd); @@ -1146,7 +1223,7 @@ mswin_select_map_mode(int mode) iflags.wc_map_mode = mode; /* - ** first, check if WIN_MAP has been inialized. + ** first, check if WIN_MAP has been initialized. ** If not - attempt to retrieve it by type, then check it again */ if (map_id == WIN_ERR) @@ -1229,7 +1306,8 @@ mswin_apply_window_style(HWND hwnd) { } void -mswin_apply_window_style_all() { +mswin_apply_window_style_all(void) +{ int i; for (i = 0; i < MAXWINDOWS; i++) { if (IsWindow(GetNHApp()->windowlist[i].win) @@ -1241,9 +1319,8 @@ mswin_apply_window_style_all() { } // returns strdup() created pointer - callee assumes the ownership -#define TEXT_BUFFER_SIZE 4096 char * -nh_compose_ascii_screenshot() +nh_compose_ascii_screenshot(void) { char *retval; PMSNHMsgGetText text; @@ -1252,25 +1329,83 @@ nh_compose_ascii_screenshot() text = (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE); - text->max_size = - TEXT_BUFFER_SIZE - - 1; /* make sure we always have 0 at the end of the buffer */ - - ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); - SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, - (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); - strcpy(retval, text->buffer); - - ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); - SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_MSNH_COMMAND, - (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); - strcat(retval, text->buffer); - - ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); - SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND, - (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); - strcat(retval, text->buffer); - - free(text); + if (text && retval) { + text->max_size = + TEXT_BUFFER_SIZE + - 1; /* make sure we always have 0 at the end of the buffer */ + + ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); + SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, + (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); + strcpy(retval, text->buffer); + + ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); + SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_MSNH_COMMAND, + (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); + strcat(retval, text->buffer); + + ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); + SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND, + (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); + strcat(retval, text->buffer); + + free(text); + } + return retval; +} + +#ifdef ENHANCED_SYMBOLS +// returns malloc() created pointer - callee assumes the ownership +static WCHAR * +nh_compose_unicode_screenshot(void) +{ + WCHAR *retval; + PMSNHMsgGetText text; + PMSNHMsgGetWideText wtext; + size_t retsize; + const size_t max_size = 3 * TEXT_BUFFER_SIZE; + + retval = (WCHAR *) malloc(max_size * sizeof(WCHAR)); + retsize = 0; + + text = + (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE); + if (text && retval) { + text->max_size = + TEXT_BUFFER_SIZE + - 1; /* make sure we always have 0 at the end of the buffer */ + + wtext = (PMSNHMsgGetWideText) malloc( + sizeof(MSNHMsgGetWideText) + TEXT_BUFFER_SIZE * sizeof(WCHAR)); + if (wtext) { + wtext->max_size = + TEXT_BUFFER_SIZE + - 1; /* make sure we always have 0 at the end of the buffer */ + + ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); + SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, + (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); + retsize += MultiByteToWideChar( + CP_ACP, 0, text->buffer, strlen(text->buffer), + retval + retsize, max_size - retsize); + + ZeroMemory(wtext->buffer, TEXT_BUFFER_SIZE * sizeof(WCHAR)); + SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_MSNH_COMMAND, + (WPARAM) MSNH_MSG_GETWIDETEXT, (LPARAM) wtext); + wcsncpy(retval + retsize, wtext->buffer, max_size - retsize - 1); + retsize += wcslen(retval + retsize); + + ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); + SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND, + (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); + retsize += MultiByteToWideChar( + CP_ACP, 0, text->buffer, strlen(text->buffer), + retval + retsize, max_size - retsize); + retval[retsize] = L'\0'; + free(wtext); + } + free(text); + } return retval; } +#endif diff --git a/win/win32/mhmain.h b/win/win32/mhmain.h index 9ace851ea..89c0724b3 100644 --- a/win/win32/mhmain.h +++ b/win/win32/mhmain.h @@ -1,11 +1,11 @@ -/* NetHack 3.6 mhmain.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ +/* NetHack 5.0 mhmain.h $NHDT-Date: 1596498352 2020/08/03 23:45:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMainWindow_h #define MSWINMainWindow_h -/* this is a main appliation window */ +/* this is a main application window */ #include "winMS.h" diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 9b5e02cf4..a24e99f0e 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmap.c $NHDT-Date: 1435002695 2015/06/22 19:51:35 $ $NHDT-Branch: master $:$NHDT-Revision: 1.56 $ */ +/* NetHack 5.0 mhmap.c $NHDT-Date: 1596498353 2020/08/03 23:45:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.85 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -13,7 +13,9 @@ #include "resource.h" #include "color.h" +#if !defined(PATCHLEVEL_H) #include "patchlevel.h" +#endif #define NHMAP_FONT_NAME TEXT("Terminal") #define NHMAP_TTFONT_NAME TEXT("Consolas") @@ -22,8 +24,6 @@ #define CURSOR_BLINK_INTERVAL 1000 // milliseconds #define CURSOR_HEIGHT 2 // pixels -extern short glyph2tile[]; - #define TILEBMP_X(ntile) \ ((ntile % GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_X) #define TILEBMP_Y(ntile) \ @@ -33,8 +33,8 @@ extern short glyph2tile[]; typedef struct mswin_nethack_map_window { HWND hWnd; /* window */ - int map[COLNO][ROWNO]; /* glyph map */ - int bkmap[COLNO][ROWNO]; /* backround glyph map */ + glyph_info map[COLNO][ROWNO]; + glyph_info bkmap[COLNO][ROWNO]; boolean locDirty[COLNO][ROWNO]; /* dirty flag for map location */ boolean mapDirty; /* one or more map locations are dirty */ int mapMode; /* current map mode */ @@ -49,6 +49,7 @@ typedef struct mswin_nethack_map_window { POINT map_orig; /* map origin point */ HFONT hMapFont; /* font for ASCII mode */ + HFONT hMapFontUnicode; /* font for Unicode mode */ boolean bUnicodeFont; /* font supports unicode page 437 */ int tileWidth; /* width of tile in pixels at 96 dpi */ @@ -56,7 +57,7 @@ typedef struct mswin_nethack_map_window { double backScale; /* scaling from source to back buffer */ double frontScale; /* scaling from back to front */ double monitorScale; /* from 96dpi to monitor dpi*/ - + boolean cursorOn; int yNoBlinkCursor; /* non-blinking cursor height inback buffer in pixels */ @@ -84,16 +85,17 @@ static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut); static void paint(PNHMapWindow data, int i, int j); static void dirtyAll(PNHMapWindow data); static void dirty(PNHMapWindow data, int i, int j); -static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg); +static void setGlyph(PNHMapWindow data, int i, int j, + const glyph_info *fg, const glyph_info *bg); static void clearAll(PNHMapWindow data); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) static void nhglyph2charcolor(short glyph, uchar *ch, int *color); #endif -extern boolean win32_cursorblink; /* from sys\winnt\winnt.c */ +extern boolean win32_cursorblink; /* from sys\windows\windsys.c */ HWND -mswin_init_map_window() +mswin_init_map_window(void) { static int run_once = 0; HWND hWnd; @@ -251,6 +253,12 @@ mswin_map_layout(HWND hWnd, LPSIZE map_size) data->bUnicodeFont = winos_font_support_cp437(data->hMapFont); + // Same as above, but with ANSI_CHARSET for IBM and Unicode modes + lgfnt.lfCharSet = ANSI_CHARSET; + if (data->hMapFontUnicode) + DeleteObject(data->hMapFontUnicode); + data->hMapFontUnicode = CreateFontIndirect(&lgfnt); + // set tile size to match font metrics data->xBackTile = textMetrics.tmAveCharWidth; @@ -268,7 +276,7 @@ mswin_map_layout(HWND hWnd, LPSIZE map_size) HDC frontBufferDC = GetDC(hWnd); HBITMAP hBackBuffer = CreateCompatibleBitmap(frontBufferDC, backWidth, backHeight); ReleaseDC(hWnd, frontBufferDC); - + if (data->hBackBuffer != NULL) { SelectBitmap(data->backBufferDC, hBackBuffer); DeleteObject(data->hBackBuffer); @@ -287,7 +295,7 @@ mswin_map_layout(HWND hWnd, LPSIZE map_size) double windowAspectRatio = (double) wnd_size.cx / (double) wnd_size.cy; - double backAspectRatio = + double backAspectRatio = (double) data->backWidth / (double) data->backHeight; if (windowAspectRatio > backAspectRatio) @@ -313,7 +321,11 @@ mswin_map_layout(HWND hWnd, LPSIZE map_size) if (data->xFrontTile < 1) data->xFrontTile = 1; if (data->yFrontTile < 1) data->yFrontTile = 1; - /* calcuate ASCII cursor height */ + /* ensure front tile is non-zero in size */ + data->xFrontTile = max(data->xFrontTile, 1); + data->yFrontTile = max(data->yFrontTile, 1); + + /* calculate ASCII cursor height */ data->yBlinkCursor = (int) ((double) CURSOR_HEIGHT * data->backScale); data->yNoBlinkCursor = data->yBackTile; @@ -478,7 +490,7 @@ mswin_map_mode(HWND hWnd, int mode) mswin_map_layout(hWnd, &mapSize); - mswin_update_inventory(); /* for perm_invent to hide/show tiles */ + mswin_update_inventory(0); /* for perm_invent to hide/show tiles */ return oldMode; } @@ -510,7 +522,7 @@ void mswin_map_update(HWND hWnd) /* register window class for map window */ void -register_map_window_class() +register_map_window_class(void) { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); @@ -574,7 +586,7 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) size.cx = LOWORD(lParam); size.cy = HIWORD(lParam); } else { - /* mapping factor is unchaged we just need to adjust scroll bars + /* mapping factor is unchanged we just need to adjust scroll bars */ size.cx = data->xFrontTile * COLNO; size.cy = data->yFrontTile * ROWNO; @@ -621,12 +633,15 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: if (data->hMapFont) DeleteObject(data->hMapFont); + if (data->hMapFontUnicode) + DeleteObject(data->hMapFontUnicode); if (data->hBackBuffer) DeleteBitmap(data->hBackBuffer); if (data->backBufferDC) DeleteDC(data->backBufferDC); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_MAP].address = 0; break; case WM_TIMER: @@ -658,8 +673,8 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) switch (wParam) { case MSNH_MSG_PRINT_GLYPH: { PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph) lParam; - setGlyph(data, msg_data->x, msg_data->y, - msg_data->glyph, msg_data->bkglyph); + setGlyph(data, msg_data->x, msg_data->y, + &msg_data->glyphinfo, &msg_data->bkglyphinfo); } break; case MSNH_MSG_CLIPAROUND: { @@ -721,15 +736,17 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) data->xCur = msg_data->x; data->yCur = msg_data->y; } - + } break; case MSNH_MSG_GETTEXT: { PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam; size_t index; int col, row; +#if 0 int color; - unsigned special; + unsigned special = 0U; +#endif int mgch; index = 0; @@ -737,14 +754,40 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) for (col = 0; col < COLNO; col++) { if (index >= msg_data->max_size) break; - if (data->map[col][row] == NO_GLYPH) { + if (data->map[col][row].glyph == NO_GLYPH) mgch = ' '; + msg_data->buffer[index] = data->map[col][row].ttychar; + index++; + } + if (index >= msg_data->max_size - 1) + break; + msg_data->buffer[index++] = '\r'; + msg_data->buffer[index++] = '\n'; + } + nhUse(mgch); + } break; + +#ifdef ENHANCED_SYMBOLS + case MSNH_MSG_GETWIDETEXT: { + PMSNHMsgGetWideText msg_data = (PMSNHMsgGetWideText) lParam; + size_t index; + int col, row; + + index = 0; + for (row = 0; row < ROWNO; row++) { + for (col = 0; col < COLNO; col++) { + glyph_info *glyphinfo; + uint32 ch; + if (index >= msg_data->max_size) + break; + glyphinfo = &data->map[col][row]; + if (glyphinfo->gm.u && glyphinfo->gm.u->utf8str) { + ch = glyphinfo->gm.u->utf32ch; } else { - (void) mapglyph(data->map[col][row], &mgch, &color, - &special, col, row, 0); + ch = glyphinfo->ttychar; } - msg_data->buffer[index] = mgch; - index++; + winos_ascii_to_wide(msg_data->buffer + index, ch); + index += wcslen(msg_data->buffer + index); } if (index >= msg_data->max_size - 1) break; @@ -752,12 +795,13 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) msg_data->buffer[index++] = '\n'; } } break; +#endif - case MSNH_MSG_RANDOM_INPUT: - nhassert(0); // unexpected - break; + case MSNH_MSG_RANDOM_INPUT: + nhassert(0); // unexpected + break; - } /* end switch(wParam) */ + } /* end switch(wParam) */ } /* on WM_CREATE */ @@ -792,6 +836,7 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) ReleaseDC(hWnd, hDC); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + windowdata[NHW_MAP].address = (genericptr_t) data; clearAll(data); @@ -805,13 +850,13 @@ paintTile(PNHMapWindow data, int i, int j, RECT * rect) int glyph, bkglyph; int layer; #ifdef USE_PILEMARK - int color; - unsigned special; - int mgch; +// int color; +// unsigned special = 0U; +// int mgch; #endif layer = 0; - glyph = data->map[i][j]; - bkglyph = data->bkmap[i][j]; + glyph = data->map[i][j].glyph; + bkglyph = data->bkmap[i][j].glyph; if (glyph == NO_GLYPH && bkglyph == NO_GLYPH) { HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0)); @@ -819,87 +864,87 @@ paintTile(PNHMapWindow data, int i, int j, RECT * rect) DeleteObject(blackBrush); } - if (bkglyph != NO_GLYPH) { - ntile = glyph2tile[bkglyph]; - t_x = TILEBMP_X(ntile); - t_y = TILEBMP_Y(ntile); - - StretchBlt(data->backBufferDC, rect->left, rect->top, - data->xBackTile, data->yBackTile, data->tileDC, - t_x, t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, SRCCOPY); - layer++; - } - if ((glyph != NO_GLYPH) && (glyph != bkglyph)) { - ntile = glyph2tile[glyph]; - t_x = TILEBMP_X(ntile); - t_y = TILEBMP_Y(ntile); + if (glyph != NO_GLYPH) { + if (bkglyph != NO_GLYPH) { + ntile = data->bkmap[i][j].gm.tileidx; + t_x = TILEBMP_X(ntile); + t_y = TILEBMP_Y(ntile); - if (layer > 0) { - (*GetNHApp()->lpfnTransparentBlt)( - data->backBufferDC, rect->left, rect->top, - data->xBackTile, data->yBackTile, data->tileDC, t_x, - t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, TILE_BK_COLOR); - } else { StretchBlt(data->backBufferDC, rect->left, rect->top, - data->xBackTile, data->yBackTile, data->tileDC, - t_x, t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, SRCCOPY); + data->xBackTile, data->yBackTile, data->tileDC, t_x, + t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, + SRCCOPY); + layer++; + } + if (glyph != bkglyph) { + /* rely on tileidx provided by NetHack core */ + ntile = data->map[i][j].gm.tileidx; + t_x = TILEBMP_X(ntile); + t_y = TILEBMP_Y(ntile); + + /* Don't use all black GLYPH_UNEXPLORED tile as a background */ + if (layer > 0 && bkglyph != GLYPH_UNEXPLORED) { + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, t_x, + t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, TILE_BK_COLOR); + } else { + StretchBlt(data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, + t_x, t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, SRCCOPY); + } + layer++; } - - layer++; - } #ifdef USE_PILEMARK - /* rely on NetHack core helper routine */ - (void) mapglyph(data->map[i][j], &mgch, &color, &special, - i, j, 0); - if ((glyph != NO_GLYPH) && (special & MG_PET) + if ((data->map[i][j].gm.glyphflags & MG_PET) != 0 #else - if ((glyph != NO_GLYPH) && glyph_is_pet(glyph) + if (glyph_is_pet(glyph) #endif - && iflags.wc_hilite_pet) { - /* apply pet mark transparently over - pet image */ - HDC hdcPetMark; - HBITMAP bmPetMarkOld; - - /* this is DC for petmark bitmap */ - hdcPetMark = CreateCompatibleDC(data->backBufferDC); - bmPetMarkOld = - SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); - - (*GetNHApp()->lpfnTransparentBlt)( - data->backBufferDC, rect->left, rect->top, - data->xBackTile, data->yBackTile, hdcPetMark, 0, 0, - TILE_X, TILE_Y, TILE_BK_COLOR); - SelectObject(hdcPetMark, bmPetMarkOld); - DeleteDC(hdcPetMark); - } + && iflags.wc_hilite_pet) { + /* apply pet mark transparently over + pet image */ + HDC hdcPetMark; + HBITMAP bmPetMarkOld; + + /* this is DC for petmark bitmap */ + hdcPetMark = CreateCompatibleDC(data->backBufferDC); + bmPetMarkOld = + SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); + + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, hdcPetMark, 0, 0, + TILE_X, TILE_Y, TILE_BK_COLOR); + SelectObject(hdcPetMark, bmPetMarkOld); + DeleteDC(hdcPetMark); + } #ifdef USE_PILEMARK - if ((glyph != NO_GLYPH) && (special & MG_OBJPILE) - && iflags.hilite_pile) { - /* apply pilemark transparently over other image */ - HDC hdcPileMark; - HBITMAP bmPileMarkOld; - - /* this is DC for pilemark bitmap */ - hdcPileMark = CreateCompatibleDC(data->backBufferDC); - bmPileMarkOld = SelectObject(hdcPileMark, - GetNHApp()->bmpPileMark); - - (*GetNHApp()->lpfnTransparentBlt)( - data->backBufferDC, rect->left, rect->top, - data->xBackTile, data->yBackTile, hdcPileMark, 0, 0, - TILE_X, TILE_Y, TILE_BK_COLOR); - SelectObject(hdcPileMark, bmPileMarkOld); - DeleteDC(hdcPileMark); - } + if ((data->map[i][j].gm.glyphflags & MG_OBJPILE) != 0 + && iflags.hilite_pile) { + /* apply pilemark transparently over other image */ + HDC hdcPileMark; + HBITMAP bmPileMarkOld; + + /* this is DC for pilemark bitmap */ + hdcPileMark = CreateCompatibleDC(data->backBufferDC); + bmPileMarkOld = SelectObject(hdcPileMark, + GetNHApp()->bmpPileMark); + + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, hdcPileMark, 0, 0, + TILE_X, TILE_Y, TILE_BK_COLOR); + SelectObject(hdcPileMark, bmPileMarkOld); + DeleteDC(hdcPileMark); + } #endif + } /* glyph != NO_GLYPH */ - if (i == data->xCur && j == data->yCur && + if (i == data->xCur && j == data->yCur && (data->cursorOn || !win32_cursorblink)) DrawFocusRect(data->backBufferDC, rect); } @@ -908,13 +953,15 @@ paintTile(PNHMapWindow data, int i, int j, RECT * rect) static void paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) { - if (data->map[i][j] >= 0) { + if (data->map[i][j].glyph >= 0) { - char ch; - WCHAR wch; + glyph_info *glyphinfo; + uint32 ch; + WCHAR wch[3]; int color; - unsigned special; - int mgch; + uint32 rgbcolor; +// unsigned special; +// int mgch; HBRUSH back_brush; COLORREF OldFg; @@ -924,17 +971,28 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) FillRect(data->backBufferDC, rect, blackBrush); DeleteObject(blackBrush); - #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) - nhglyph2charcolor(data->map[i][j], &ch, &color); - OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); - #else - /* rely on NetHack core helper routine */ - (void) mapglyph(data->map[i][j], &mgch, &color, - &special, i, j, 0); - ch = (char) mgch; - if (((special & MG_PET) && iflags.hilite_pet) - || ((special & (MG_DETECT | MG_BW_LAVA)) - && iflags.use_inverse)) { + glyphinfo = &data->map[i][j]; + ch = glyphinfo->ttychar; + color = (int) glyphinfo->gm.sym.color; + rgbcolor = nhcolor_to_RGB(color); +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8) + && glyphinfo->gm.u + && glyphinfo->gm.u->utf8str) { + ch = glyphinfo->gm.u->utf32ch; + } +#endif + if (glyphinfo->gm.customcolor != 0 + && (mswin_procs.wincap2 & WC2_EXTRACOLORS) != 0) { + if ((glyphinfo->gm.customcolor & NH_BASIC_COLOR) != 0) { + color = (int) COLORVAL(glyphinfo->gm.customcolor); + rgbcolor = nhcolor_to_RGB(color); + } + } + if (((data->map[i][j].gm.glyphflags & MG_PET) && iflags.hilite_pet) + || ((data->map[i][j].gm.glyphflags & (MG_DETECT | MG_BW_LAVA + | MG_BW_ICE | MG_BW_SINK + | MG_BW_ENGR)) != 0)) { back_brush = CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); FillRect(data->backBufferDC, rect, back_brush); @@ -947,32 +1005,40 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) break; default: OldFg = - SetTextColor(data->backBufferDC, nhcolor_to_RGB(color)); + SetTextColor(data->backBufferDC, rgbcolor); } } else { - OldFg = SetTextColor(data->backBufferDC, nhcolor_to_RGB(color)); + OldFg = SetTextColor(data->backBufferDC, rgbcolor); } - #endif - if (data->bUnicodeFont) { - wch = winos_ascii_to_wide(ch); - if (wch == 0x2591 || wch == 0x2592) { - int level = 80; - HBRUSH brush = CreateSolidBrush(RGB(level, level, level)); + if (data->bUnicodeFont || SYMHANDLING(H_UTF8)) { + winos_ascii_to_wide(wch, ch); + if (wch[0] == 0x2591 || wch[0] == 0x2592) { + int intensity = 80; + HBRUSH brush = CreateSolidBrush(RGB(intensity, intensity, intensity)); FillRect(data->backBufferDC, rect, brush); DeleteObject(brush); - level = (wch == 0x2591 ? 100 : 200); - brush = CreateSolidBrush(RGB(level, level, level)); - RECT smallRect = { rect->left + 1, rect->top + 1, - rect->right - 1, rect->bottom - 1 }; + intensity = (wch[0] == 0x2591 ? 1 : 2); + brush = CreateSolidBrush(RGB( + GetRValue(rgbcolor)*intensity/2, + GetGValue(rgbcolor)*intensity/2, + GetBValue(rgbcolor)*intensity/2)); + RECT smallRect = {0}; + smallRect.left = rect->left + 1; + smallRect.top = rect->top + 1; + smallRect.right = rect->right - 1; + smallRect.bottom = rect->bottom - 1; FillRect(data->backBufferDC, &smallRect, brush); DeleteObject(brush); } else { - DrawTextW(data->backBufferDC, &wch, 1, rect, + SelectObject(data->backBufferDC, data->hMapFontUnicode); + DrawTextW(data->backBufferDC, wch, -1, rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE); } } else { - DrawTextA(data->backBufferDC, &ch, 1, rect, + char ch8 = (char) ch; + SelectObject(data->backBufferDC, data->hMapFont); + DrawTextA(data->backBufferDC, &ch8, 1, rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE); } @@ -984,7 +1050,7 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) (data->cursorOn || !win32_cursorblink)) { int yCursor = (win32_cursorblink ? data->yBlinkCursor : data->yNoBlinkCursor); - PatBlt(data->backBufferDC, + PatBlt(data->backBufferDC, rect->left, rect->bottom - yCursor, rect->right - rect->left, yCursor, @@ -992,11 +1058,18 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) } } -static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg) +static void setGlyph(PNHMapWindow data, int i, int j, + const glyph_info *fg, const glyph_info *bg) { - if ((data->map[i][j] != fg) || (data->bkmap[i][j] != bg)) { - data->map[i][j] = fg; - data->bkmap[i][j] = bg; + if ((data->map[i][j].glyph != fg->glyph) + || (data->bkmap[i][j].glyph != bg->glyph) + || data->map[i][j].ttychar != fg->ttychar + || data->map[i][j].gm.sym.color != fg->gm.sym.color + || data->map[i][j].gm.customcolor != fg->gm.customcolor + || data->map[i][j].gm.glyphflags != fg->gm.glyphflags + || data->map[i][j].gm.tileidx != fg->gm.tileidx) { + data->map[i][j] = *fg; + data->bkmap[i][j] = *bg; data->locDirty[i][j] = TRUE; data->mapDirty = TRUE; } @@ -1006,8 +1079,8 @@ static void clearAll(PNHMapWindow data) { for (int x = 0; x < COLNO; x++) for (int y = 0; y < ROWNO; y++) { - data->map[x][y] = NO_GLYPH; - data->bkmap[x][y] = NO_GLYPH; + data->map[x][y] = nul_glyphinfo; + data->bkmap[x][y] = nul_glyphinfo; data->locDirty[x][y] = TRUE; } data->mapDirty = TRUE; @@ -1206,7 +1279,6 @@ void nhglyph2charcolor(short g, uchar *ch, int *color) { int offset; -#ifdef TEXTCOLOR #define zap_color(n) *color = iflags.use_color ? zapcolors[n] : NO_COLOR #define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR @@ -1217,17 +1289,6 @@ nhglyph2charcolor(short g, uchar *ch, int *color) #define warn_color(n) \ *color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR -#else /* no text color */ - -#define zap_color(n) -#define cmap_color(n) -#define obj_color(n) -#define mon_color(n) -#define pet_color(c) -#define warn_color(c) - *color = CLR_WHITE; -#endif - if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */ *ch = showsyms[offset + SYM_OFF_W]; warn_color(offset); diff --git a/win/win32/mhmap.h b/win/win32/mhmap.h index d6e6c7d1d..a66041fd1 100644 --- a/win/win32/mhmap.h +++ b/win/win32/mhmap.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmap.h $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ +/* NetHack 5.0 mhmap.h $NHDT-Date: 1596498354 2020/08/03 23:45:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.17 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 62e78480f..3f9b7dfe8 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmenu.c $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.48 $ */ +/* NetHack 5.0 mhmenu.c $NHDT-Date: 1596498354 2020/08/03 23:45:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.74 $ */ /* Copyright (c) Alex Kompel, 2002 */ /* NetHack may be freely redistributed. See license for details. */ @@ -27,38 +27,42 @@ #define CHECK_HEIGHT 16 typedef struct mswin_menu_item { - int glyph; + glyph_info glyphinfo; ANY_P identifier; - CHAR_P accelerator; - CHAR_P group_accel; + char accelerator; + char group_accel; int attr; + int color; char str[NHMENU_STR_SIZE]; - BOOLEAN_P presel; + boolean presel; + unsigned int itemflags; int count; BOOL has_focus; } NHMenuItem, *PNHMenuItem; +union menu_innards { + struct menu_list { + int size; /* number of items in items[] */ + int allocated; /* number of allocated slots in items[] */ + PNHMenuItem items; /* menu items */ + char gacc[QBUFSZ]; /* group accelerators */ + BOOL counting; /* counting flag */ + char prompt[QBUFSZ]; /* menu prompt */ + int tab_stop_size[NUMTABS]; /* tabstops to align option values */ + int menu_cx; /* menu width */ + } menu; + + struct menu_text { + TCHAR *text; + SIZE text_box_size; + } text; +}; + typedef struct mswin_nethack_menu_window { int type; /* MENU_TYPE_TEXT or MENU_TYPE_MENU */ int how; /* for menus: PICK_NONE, PICK_ONE, PICK_ANY */ - union { - struct menu_list { - int size; /* number of items in items[] */ - int allocated; /* number of allocated slots in items[] */ - PNHMenuItem items; /* menu items */ - char gacc[QBUFSZ]; /* group accelerators */ - BOOL counting; /* counting flag */ - char prompt[QBUFSZ]; /* menu prompt */ - int tab_stop_size[NUMTABS]; /* tabstops to align option values */ - int menu_cx; /* menu width */ - } menu; - - struct menu_text { - TCHAR *text; - SIZE text_box_size; - } text; - }; + union menu_innards menui; int result; int done; @@ -70,14 +74,12 @@ typedef struct mswin_nethack_menu_window { BOOL is_active; } NHMenuWindow, *PNHMenuWindow; -extern short glyph2tile[]; - static WNDPROC wndProcListViewOrig = NULL; static WNDPROC editControlWndProc = NULL; #define NHMENU_IS_SELECTABLE(item) ((item).identifier.a_obj != NULL) #define NHMENU_IS_SELECTED(item) ((item).count != 0) -#define NHMENU_HAS_GLYPH(item) ((item).glyph != NO_GLYPH) +#define NHMENU_HAS_GLYPH(item) ((item).glyphinfo.glyph != NO_GLYPH) INT_PTR CALLBACK MenuWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHMenuListWndProc(HWND, UINT, WPARAM, LPARAM); @@ -93,6 +95,8 @@ static void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count); static void reset_menu_count(HWND hwndList, PNHMenuWindow data); static BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch); +static genericptr_t menu_data_to_free; +void free_menu_data(void); /*-----------------------------------------------------------------------------*/ HWND @@ -161,23 +165,23 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, if (data->type == MENU_TYPE_MENU) { char next_char = 'a'; - data->menu.gacc[0] = '\0'; - ap = data->menu.gacc; - for (i = 0; i < data->menu.size; i++) { - if (data->menu.items[i].accelerator != 0) { - if (isalpha(data->menu.items[i].accelerator)) { - next_char = (char)(data->menu.items[i].accelerator + 1); + data->menui.menu.gacc[0] = '\0'; + ap = data->menui.menu.gacc; + for (i = 0; i < data->menui.menu.size; i++) { + if (data->menui.menu.items[i].accelerator != 0) { + if (isalpha(data->menui.menu.items[i].accelerator)) { + next_char = (char)(data->menui.menu.items[i].accelerator + 1); } - } else if (NHMENU_IS_SELECTABLE(data->menu.items[i])) { + } else if (NHMENU_IS_SELECTABLE(data->menui.menu.items[i])) { if (isalpha(next_char)) { - data->menu.items[i].accelerator = next_char; + data->menui.menu.items[i].accelerator = next_char; } else { if (next_char > 'z') next_char = 'A'; else if (next_char > 'Z') next_char = 'a'; - data->menu.items[i].accelerator = next_char; + data->menui.menu.items[i].accelerator = next_char; } next_char++; @@ -185,12 +189,12 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, } /* collect group accelerators */ - for (i = 0; i < data->menu.size; i++) { + for (i = 0; i < data->menui.menu.size; i++) { if (data->how != PICK_NONE) { - if (data->menu.items[i].group_accel - && !strchr(data->menu.gacc, - data->menu.items[i].group_accel)) { - *ap++ = data->menu.items[i].group_accel; + if (data->menui.menu.items[i].group_accel + && !strchr(data->menui.menu.gacc, + data->menui.menu.items[i].group_accel)) { + *ap++ = data->menui.menu.items[i].group_accel; *ap = '\x0'; } } @@ -218,9 +222,9 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, } else if (how == PICK_ONE || how == PICK_ANY) { /* count selected items */ ret_val = 0; - for (i = 0; i < data->menu.size; i++) { - if (NHMENU_IS_SELECTABLE(data->menu.items[i]) - && NHMENU_IS_SELECTED(data->menu.items[i])) { + for (i = 0; i < data->menui.menu.size; i++) { + if (NHMENU_IS_SELECTABLE(data->menui.menu.items[i]) + && NHMENU_IS_SELECTED(data->menui.menu.items[i])) { ret_val++; } } @@ -233,12 +237,12 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, panic("out of memory"); sel_ind = 0; - for (i = 0; i < data->menu.size; i++) { - if (NHMENU_IS_SELECTABLE(data->menu.items[i]) - && NHMENU_IS_SELECTED(data->menu.items[i])) { + for (i = 0; i < data->menui.menu.size; i++) { + if (NHMENU_IS_SELECTABLE(data->menui.menu.items[i]) + && NHMENU_IS_SELECTED(data->menui.menu.items[i])) { selected[sel_ind].item = - data->menu.items[i].identifier; - selected[sel_ind].count = data->menu.items[i].count; + data->menui.menu.items[i].identifier; + selected[sel_ind].count = data->menui.menu.items[i].count; sel_ind++; } } @@ -258,10 +262,10 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, */ if (iflags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN && how != PICK_NONE) { - data->menu.prompt[0] = '\0'; + data->menui.menu.prompt[0] = '\0'; SetMenuListType(hWnd, PICK_NONE); - for (i = 0; i < data->menu.size; i++) - data->menu.items[i].count = 0; + for (i = 0; i < data->menui.menu.size; i++) + data->menui.menu.items[i].count = 0; LayoutMenu(hWnd); } } @@ -281,22 +285,24 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) HDC hdc = GetDC(control); data = (PNHMenuWindow) malloc(sizeof(NHMenuWindow)); - ZeroMemory(data, sizeof(NHMenuWindow)); - data->type = MENU_TYPE_TEXT; - data->how = PICK_NONE; - data->result = 0; - data->done = 0; - data->bmpChecked = - LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL)); - data->bmpCheckedCount = - LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT)); - data->bmpNotChecked = - LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL)); - data->bmpDC = CreateCompatibleDC(hdc); - data->is_active = FALSE; - SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); - - /* set font for the text cotrol */ + if (data) { + ZeroMemory(data, sizeof(NHMenuWindow)); + data->type = MENU_TYPE_TEXT; + data->how = PICK_NONE; + data->result = 0; + data->done = 0; + data->bmpChecked = + LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL)); + data->bmpCheckedCount = LoadBitmap( + GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT)); + data->bmpNotChecked = + LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL)); + data->bmpDC = CreateCompatibleDC(hdc); + data->is_active = FALSE; + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + windowdata[NHW_MENU].address = (genericptr_t) data; + } + /* set font for the text control */ cached_font * font = mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE); SendMessage(control, WM_SETFONT, (WPARAM) font->hFont, @@ -361,7 +367,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case IDCANCEL: if (data->type == MENU_TYPE_MENU && (data->how == PICK_ONE || data->how == PICK_ANY) - && data->menu.counting) { + && data->menui.menu.counting) { HWND list; int i; @@ -396,9 +402,9 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case LVN_ITEMACTIVATE: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam; if (data->how == PICK_ONE) { - if (lpnmlv->iItem >= 0 && lpnmlv->iItem < data->menu.size + if (lpnmlv->iItem >= 0 && lpnmlv->iItem < data->menui.menu.size && NHMENU_IS_SELECTABLE( - data->menu.items[lpnmlv->iItem])) { + data->menui.menu.items[lpnmlv->iItem])) { SelectMenuItem(lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, -1); data->done = 1; @@ -415,7 +421,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if (data->how == PICK_ANY) { SelectMenuItem( lpnmitem->hdr.hwndFrom, data, lpnmitem->iItem, - NHMENU_IS_SELECTED(data->menu.items[lpnmitem->iItem]) + NHMENU_IS_SELECTED(data->menui.menu.items[lpnmitem->iItem]) ? 0 : -1); } @@ -429,7 +435,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) return 0; if (data->how == PICK_ONE || data->how == PICK_ANY) { - data->menu.items[lpnmlv->iItem].has_focus = + data->menui.menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED); ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem); @@ -446,7 +452,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /* check item focus */ if (data->how == PICK_ONE || data->how == PICK_ANY) { - data->menu.items[lpnmlv->iItem].has_focus = + data->menui.menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED); ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem); @@ -511,11 +517,12 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) DeleteObject(data->bmpCheckedCount); DeleteObject(data->bmpNotChecked); if (data->type == MENU_TYPE_TEXT) { - if (data->text.text) - free(data->text.text); + if (data->menui.text.text) + free(data->menui.text.text); } free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_MENU].address = 0; } return TRUE; } @@ -537,31 +544,37 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) RECT text_rt; HGDIOBJ saveFont; HDC hdc; + TCHAR *was; if (data->type != MENU_TYPE_TEXT) SetMenuType(hWnd, MENU_TYPE_TEXT); - if (!data->text.text) { + if (!data->menui.text.text) { text_size = strlen(msg_data->text) + 4; - data->text.text = - (TCHAR *) malloc(text_size * sizeof(data->text.text[0])); - ZeroMemory(data->text.text, - text_size * sizeof(data->text.text[0])); + data->menui.text.text = + (TCHAR *) malloc(text_size * sizeof(data->menui.text.text[0])); + if (data->menui.text.text) + ZeroMemory(data->menui.text.text, + text_size * sizeof(data->menui.text.text[0])); } else { - text_size = _tcslen(data->text.text) + strlen(msg_data->text) + 4; - data->text.text = (TCHAR *) realloc( - data->text.text, text_size * sizeof(data->text.text[0])); + was = data->menui.text.text; + + text_size = _tcslen(data->menui.text.text) + strlen(msg_data->text) + 4; + data->menui.text.text = (TCHAR *) realloc( + data->menui.text.text, text_size * sizeof(data->menui.text.text[0])); + if (!data->menui.text.text) + free(was); /* this is not a good situation, but not a leak either */ } - if (!data->text.text) + if (!data->menui.text.text) break; - _tcscat(data->text.text, NH_A2W(msg_data->text, wbuf, BUFSZ)); - _tcscat(data->text.text, TEXT("\r\n")); + _tcscat(data->menui.text.text, NH_A2W(msg_data->text, wbuf, BUFSZ)); + _tcscat(data->menui.text.text, TEXT("\r\n")); text_view = GetDlgItem(hWnd, IDC_MENU_TEXT); if (!text_view) panic("cannot get text view window"); - SetWindowText(text_view, data->text.text); + SetWindowText(text_view, data->menui.text.text); /* calculate dimensions of the added line of text */ hdc = GetDC(text_view); @@ -571,9 +584,9 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) DrawTextA(hdc, msg_data->text, strlen(msg_data->text), &text_rt, DT_CALCRECT | DT_TOP | DT_LEFT | DT_NOPREFIX | DT_SINGLELINE); - data->text.text_box_size.cx = - max(text_rt.right - text_rt.left, data->text.text_box_size.cx); - data->text.text_box_size.cy += text_rt.bottom - text_rt.top; + data->menui.text.text_box_size.cx = + max(text_rt.right - text_rt.left, data->menui.text.text_box_size.cx); + data->menui.text.text_box_size.cy += text_rt.bottom - text_rt.top; SelectObject(hdc, saveFont); ReleaseDC(text_view, hdc); } break; @@ -583,16 +596,16 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) if (data->type != MENU_TYPE_MENU) SetMenuType(hWnd, MENU_TYPE_MENU); - if (data->menu.items) - free(data->menu.items); + if (data->menui.menu.items) + free(data->menui.menu.items); data->how = PICK_NONE; - data->menu.items = NULL; - data->menu.size = 0; - data->menu.allocated = 0; + data->menui.menu.items = NULL; + data->menui.menu.size = 0; + data->menui.menu.allocated = 0; data->done = 0; data->result = 0; for (i = 0; i < NUMTABS; ++i) - data->menu.tab_stop_size[i] = MIN_TABSTOP_SIZE; + data->menui.menu.tab_stop_size[i] = MIN_TABSTOP_SIZE; } break; case MSNH_MSG_ADDMENU: { @@ -608,93 +621,116 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) if (data->type != MENU_TYPE_MENU) break; - if (data->menu.size == data->menu.allocated) { - data->menu.allocated += 10; - data->menu.items = (PNHMenuItem) realloc( - data->menu.items, data->menu.allocated * sizeof(NHMenuItem)); - } + if (data->menui.menu.size == data->menui.menu.allocated) { + PNHMenuItem was = data->menui.menu.items; - new_item = data->menu.size; - ZeroMemory(&data->menu.items[new_item], - sizeof(data->menu.items[new_item])); - data->menu.items[new_item].glyph = msg_data->glyph; - data->menu.items[new_item].identifier = *msg_data->identifier; - data->menu.items[new_item].accelerator = msg_data->accelerator; - data->menu.items[new_item].group_accel = msg_data->group_accel; - data->menu.items[new_item].attr = msg_data->attr; - strncpy(data->menu.items[new_item].str, msg_data->str, - NHMENU_STR_SIZE); - /* prevent & being interpreted as a mnemonic start */ - strNsubst(data->menu.items[new_item].str, "&", "&&", 0); - data->menu.items[new_item].presel = msg_data->presel; - - /* calculate tabstop size */ - hDC = GetDC(hWnd); - cached_font * font = mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE); - saveFont = SelectObject(hDC, font->hFont); - GetTextMetrics(hDC, &tm); - p1 = data->menu.items[new_item].str; - p = strchr(data->menu.items[new_item].str, '\t'); - column = 0; - for (;;) { - TCHAR wbuf[BUFSZ]; - RECT drawRect; - SetRect(&drawRect, 0, 0, 1, 1); - if (p != NULL) - *p = '\0'; /* for time being, view tab field as zstring */ - DrawText(hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, - DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_EXPANDTABS - | DT_SINGLELINE); - data->menu.tab_stop_size[column] = - max(data->menu.tab_stop_size[column], - drawRect.right - drawRect.left); - - menuitemwidth += data->menu.tab_stop_size[column]; - - if (p != NULL) - *p = '\t'; - else /* last string so, */ - break; + data->menui.menu.allocated += 10; + data->menui.menu.items = (PNHMenuItem) realloc( + data->menui.menu.items, data->menui.menu.allocated * sizeof(NHMenuItem)); + if (!data->menui.menu.items) + free(was); + else + menu_data_to_free = (genericptr_t) data->menui.menu.items; + } - /* add the separation only when not the last item */ - /* in the last item, we break out of the loop, in the statement - * just above */ - menuitemwidth += TAB_SEPARATION; + if (data->menui.menu.items) { + new_item = data->menui.menu.size; + ZeroMemory(&data->menui.menu.items[new_item], + sizeof(data->menui.menu.items[new_item])); + data->menui.menu.items[new_item].glyphinfo = msg_data->glyphinfo; + data->menui.menu.items[new_item].identifier = + *msg_data->identifier; + data->menui.menu.items[new_item].accelerator = + msg_data->accelerator; + data->menui.menu.items[new_item].group_accel = + msg_data->group_accel; + data->menui.menu.items[new_item].attr = msg_data->attr; + data->menui.menu.items[new_item].color = msg_data->color; + strncpy(data->menui.menu.items[new_item].str, msg_data->str, + NHMENU_STR_SIZE); + /* prevent & being interpreted as a mnemonic start */ + strNsubst(data->menui.menu.items[new_item].str, "&", "&&", 0); + data->menui.menu.items[new_item].presel = msg_data->presel; + data->menui.menu.items[new_item].itemflags = msg_data->itemflags; + + /* calculate tabstop size */ + hDC = GetDC(hWnd); + cached_font *font = + mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE); + saveFont = SelectObject(hDC, font->hFont); + GetTextMetrics(hDC, &tm); + p1 = data->menui.menu.items[new_item].str; + p = strchr(data->menui.menu.items[new_item].str, '\t'); + column = 0; + for (;;) { + TCHAR wbuf[BUFSZ]; + RECT drawRect; + SetRect(&drawRect, 0, 0, 1, 1); + if (p != NULL) + *p = '\0'; /* for time being, view tab field as zstring */ + DrawText(hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, + DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_EXPANDTABS + | DT_SINGLELINE); + data->menui.menu.tab_stop_size[column] = + max(data->menui.menu.tab_stop_size[column], + drawRect.right - drawRect.left); + + menuitemwidth += data->menui.menu.tab_stop_size[column]; + + if (p != NULL) + *p = '\t'; + else /* last string so, */ + break; + + /* add the separation only when not the last item */ + /* in the last item, we break out of the loop, in the + * statement just above */ + menuitemwidth += TAB_SEPARATION; + + ++column; + p1 = p + 1; + p = strchr(p1, '\t'); + } - ++column; - p1 = p + 1; - p = strchr(p1, '\t'); - } - SelectObject(hDC, saveFont); - ReleaseDC(hWnd, hDC); + SelectObject(hDC, saveFont); + ReleaseDC(hWnd, hDC); - /* calculate new menu width */ - data->menu.menu_cx = - max(data->menu.menu_cx, - 2 * TILE_X + menuitemwidth - + (tm.tmAveCharWidth + tm.tmOverhang) * 12); + /* calculate new menu width */ + data->menui.menu.menu_cx = + max(data->menui.menu.menu_cx, + 2 * TILE_X + menuitemwidth + + (tm.tmAveCharWidth + tm.tmOverhang) * 12); - /* increment size */ - data->menu.size++; + /* increment size */ + data->menui.menu.size++; + } } break; case MSNH_MSG_ENDMENU: { PMSNHMsgEndMenu msg_data = (PMSNHMsgEndMenu) lParam; if (msg_data->text) { - strncpy(data->menu.prompt, msg_data->text, - sizeof(data->menu.prompt) - 1); + strncpy(data->menui.menu.prompt, msg_data->text, + sizeof(data->menui.menu.prompt) - 1); } else { - ZeroMemory(data->menu.prompt, sizeof(data->menu.prompt)); + ZeroMemory(data->menui.menu.prompt, sizeof(data->menui.menu.prompt)); } } break; - case MSNH_MSG_RANDOM_INPUT: { - PostMessage(GetMenuControl(hWnd), - WM_MSNH_COMMAND, MSNH_MSG_RANDOM_INPUT, 0); - } break; + case MSNH_MSG_RANDOM_INPUT: { + PostMessage(GetMenuControl(hWnd), + WM_MSNH_COMMAND, MSNH_MSG_RANDOM_INPUT, 0); + } break; } } + +void +free_menu_data(void) +{ + if (menu_data_to_free != 0) + free(menu_data_to_free), menu_data_to_free = 0; +} + /*-----------------------------------------------------------------------------*/ void LayoutMenu(HWND hWnd) @@ -766,7 +802,7 @@ LayoutMenu(HWND hWnd) ListView_SetColumnWidth( GetMenuControl(hWnd), 0, max(clrt.right - clrt.left - GetSystemMetrics(SM_CXVSCROLL), - data->menu.menu_cx)); + data->menui.menu.menu_cx)); } MoveWindow(GetMenuControl(hWnd), pt_elem.x, pt_elem.y, sz_elem.cx, @@ -843,7 +879,7 @@ SetMenuListType(HWND hWnd, int how) panic("how should be one of PICK_NONE, PICK_ONE or PICK_ANY"); }; - if (strlen(data->menu.prompt) == 0) { + if (strlen(data->menui.menu.prompt) == 0) { dwStyles |= LVS_NOCOLUMNHEADER; } @@ -880,22 +916,22 @@ SetMenuListType(HWND hWnd, int how) ZeroMemory(&lvcol, sizeof(lvcol)); lvcol.mask = LVCF_WIDTH | LVCF_TEXT; lvcol.cx = monitorInfo.width; - lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ); + lvcol.pszText = NH_A2W(data->menui.menu.prompt, wbuf, BUFSZ); ListView_InsertColumn(control, 0, &lvcol); /* add items to the list view */ - for (i = 0; i < data->menu.size; i++) { + for (i = 0; i < data->menui.menu.size; i++) { LVITEM lvitem; ZeroMemory(&lvitem, sizeof(lvitem)); - sprintf(buf, "%c - %s", max(data->menu.items[i].accelerator, ' '), - data->menu.items[i].str); + Snprintf(buf, sizeof buf, "%c - %s", max(data->menui.menu.items[i].accelerator, ' '), + data->menui.menu.items[i].str); lvitem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; lvitem.iItem = i; lvitem.iSubItem = 0; - lvitem.state = data->menu.items[i].presel ? LVIS_SELECTED : 0; + lvitem.state = data->menui.menu.items[i].presel ? LVIS_SELECTED : 0; lvitem.pszText = NH_A2W(buf, wbuf, BUFSZ); - lvitem.lParam = (LPARAM) &data->menu.items[i]; + lvitem.lParam = (LPARAM) &data->menui.menu.items[i]; nItem = (int) SendMessage(control, LB_ADDSTRING, (WPARAM) 0, (LPARAM) buf); if (ListView_InsertItem(control, &lvitem) == -1) { @@ -904,6 +940,7 @@ SetMenuListType(HWND hWnd, int how) } if (data->is_active) SetFocus(control); + nhUse(nItem); } /*-----------------------------------------------------------------------------*/ HWND @@ -913,10 +950,10 @@ GetMenuControl(HWND hWnd) data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); - /* We may continue getting window messages after a window's WM_DESTROY is - called. We need to handle the case that USERDATA has been freed. */ - if (data == NULL) - return NULL; + /* We may continue getting window messages after a window's WM_DESTROY is + called. We need to handle the case that USERDATA has been freed. */ + if (data == NULL) + return NULL; if (data->type == MENU_TYPE_TEXT) { return GetDlgItem(hWnd, IDC_MENU_TEXT); @@ -949,15 +986,19 @@ onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam) /* Set the height of the list box items to max height of the individual * items */ - for (i = 0; i < data->menu.size; i++) { - if (NHMENU_HAS_GLYPH(data->menu.items[i]) + for (i = 0; i < data->menui.menu.size; i++) { +/* int map_y = GetNHApp()->mapTile_Y; */ + int map_y = 16; /* leave it at the default size, unless + * we are actually showing the larger + * icons in the menu */ + if (NHMENU_HAS_GLYPH(data->menui.menu.items[i]) && !IS_MAP_ASCII(iflags.wc_map_mode)) { lpmis->itemHeight = max(lpmis->itemHeight, - (UINT) max(tm.tmHeight, GetNHApp()->mapTile_Y) + 2); + (UINT) max(tm.tmHeight, map_y) + 2); } else { lpmis->itemHeight = - max(lpmis->itemHeight, (UINT) max(tm.tmHeight, TILE_Y) + 2); + max(lpmis->itemHeight, (UINT) max(tm.tmHeight, map_y) + 2); } } @@ -987,9 +1028,6 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) char *p, *p1; int column; int spacing = 0; - - int color = NO_COLOR, attr; - boolean menucolr = FALSE; double monitorScale = win10_monitor_scale(hWnd); int tileXScaled = (int) (TILE_X * monitorScale); int tileYScaled = (int) (TILE_Y * monitorScale); @@ -999,12 +1037,12 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) lpdis = (LPDRAWITEMSTRUCT) lParam; /* If there are no list box items, skip this message. */ - if (lpdis->itemID == -1) + if (lpdis->itemID == (UINT) -1) return FALSE; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); - item = &data->menu.items[lpdis->itemID]; + item = &data->menui.menu.items[lpdis->itemID]; tileDC = CreateCompatibleDC(lpdis->hDC); cached_font * font = mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE); @@ -1017,6 +1055,9 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) ? menu_fg_color : (COLORREF) GetSysColor(DEFAULT_COLOR_FG_MENU)); + if (item->color != NO_COLOR) + (void) SetTextColor(lpdis->hDC, nhcolor_to_RGB(item->color)); + GetTextMetrics(lpdis->hDC, &tm); spacing = tm.tmAveCharWidth; @@ -1044,7 +1085,7 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tileYScaled) / 2; bmpSaved = SelectBitmap(data->bmpDC, bmpCheck); - StretchBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, + StretchBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, data->bmpDC, 0, 0, CHECK_WIDTH, CHECK_HEIGHT, SRCCOPY); SelectObject(data->bmpDC, bmpSaved); } @@ -1054,15 +1095,6 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) if (item->accelerator != 0) { buf[0] = item->accelerator; buf[1] = '\x0'; - - if (iflags.use_menu_color - && (menucolr = get_menu_coloring(item->str, &color, &attr))) { - cached_font * menu_font = mswin_get_font(NHW_MENU, attr, lpdis->hDC, FALSE); - SelectObject(lpdis->hDC, menu_font->hFont); - if (color != NO_COLOR) - SetTextColor(lpdis->hDC, nhcolor_to_RGB(color)); - } - SetRect(&drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom); DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect, @@ -1077,10 +1109,13 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) if (NHMENU_HAS_GLYPH(*item)) { if (!IS_MAP_ASCII(iflags.wc_map_mode)) { HGDIOBJ saveBmp; - double monitorScale = win10_monitor_scale(hWnd); + double monitorScale2; + + nhUse(monitorScale2); + monitorScale2 = win10_monitor_scale(hWnd); saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); - ntile = glyph2tile[item->glyph]; + ntile = item->glyphinfo.gm.tileidx; t_x = (ntile % GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_X; t_y = @@ -1090,13 +1125,13 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) if (GetNHApp()->bmpMapTiles == GetNHApp()->bmpTiles) { /* using original nethack tiles - apply image transparently */ - (*GetNHApp()->lpfnTransparentBlt)(lpdis->hDC, x, y, + (*GetNHApp()->lpfnTransparentBlt)(lpdis->hDC, x, y, tileXScaled, tileYScaled, tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR); } else { /* using custom tiles - simple blt */ - StretchBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, + StretchBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, SRCCOPY); } SelectObject(tileDC, saveBmp); @@ -1134,13 +1169,13 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) p = strchr(item->str, '\t'); column = 0; SetRect(&drawRect, x, lpdis->rcItem.top, - min(x + data->menu.tab_stop_size[0], lpdis->rcItem.right), + min(x + data->menui.menu.tab_stop_size[0], lpdis->rcItem.right), lpdis->rcItem.bottom); for (;;) { - TCHAR wbuf[BUFSZ]; + TCHAR wbuf2[BUFSZ]; if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ - DrawText(lpdis->hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, + DrawText(lpdis->hDC, NH_A2W(p1, wbuf2, BUFSZ), strlen(p1), &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); if (p != NULL) *p = '\t'; @@ -1151,28 +1186,30 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) p = strchr(p1, '\t'); drawRect.left = drawRect.right + TAB_SEPARATION; ++column; - drawRect.right = min(drawRect.left + data->menu.tab_stop_size[column], + drawRect.right = min(drawRect.left + data->menui.menu.tab_stop_size[column], lpdis->rcItem.right); } /* draw focused item */ if (item->has_focus || (NHMENU_IS_SELECTABLE(*item) - && data->menu.items[lpdis->itemID].count != -1)) { + && data->menui.menu.items[lpdis->itemID].count != -1)) { RECT client_rt; GetClientRect(lpdis->hwndItem, &client_rt); client_rt.right = min(client_rt.right, lpdis->rcItem.right); if (NHMENU_IS_SELECTABLE(*item) - && data->menu.items[lpdis->itemID].count != 0 - && item->glyph != NO_GLYPH) { - if (data->menu.items[lpdis->itemID].count == -1) { - _stprintf(wbuf, TEXT("Count: All")); + && data->menui.menu.items[lpdis->itemID].count != 0 + && item->glyphinfo.glyph != NO_GLYPH) { + if (data->menui.menu.items[lpdis->itemID].count == -1) { + nh_stprintf(wbuf, sizeof wbuf, + TEXT("Count: All")); } else { - _stprintf(wbuf, TEXT("Count: %d"), - data->menu.items[lpdis->itemID].count); + nh_stprintf(wbuf, sizeof wbuf, + TEXT("Count: %d"), + data->menui.menu.items[lpdis->itemID].count); } - /* TOOD: add blinking for blink text */ + /* TODO: add blinking for blink text */ cached_font * blink_font = mswin_get_font(NHW_MENU, ATR_BLINK, lpdis->hDC, FALSE); SelectObject(lpdis->hDC, blink_font->hFont); @@ -1229,8 +1266,8 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); is_accelerator = FALSE; - for (i = 0; i < data->menu.size; i++) { - if (data->menu.items[i].accelerator == ch) { + for (i = 0; i < data->menui.menu.size; i++) { + if (data->menui.menu.items[i].accelerator == ch) { is_accelerator = TRUE; break; } @@ -1251,7 +1288,7 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) return -2; case MENU_LAST_PAGE: - i = max(0, data->menu.size - 1); + i = max(0, data->menui.menu.size - 1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; @@ -1261,10 +1298,10 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) pageSize = ListView_GetCountPerPage(hwndList); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus down one page */ - i = min(curIndex + pageSize, data->menu.size - 1); + i = min(curIndex + pageSize, data->menui.menu.size - 1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos down one page */ - i = min(topIndex + (2 * pageSize - 1), data->menu.size - 1); + i = min(topIndex + (2 * pageSize - 1), data->menui.menu.size - 1); ListView_EnsureVisible(hwndList, i, FALSE); return -2; @@ -1283,7 +1320,10 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) case MENU_SELECT_ALL: if (data->how == PICK_ANY) { reset_menu_count(hwndList, data); - for (i = 0; i < data->menu.size; i++) { + for (i = 0; i < data->menui.menu.size; i++) { + if (!menuitem_invert_test(1, data->menui.menu.items[i].itemflags, + NHMENU_IS_SELECTED(data->menui.menu.items[i]))) + continue; SelectMenuItem(hwndList, data, i, -1); } return -2; @@ -1293,7 +1333,10 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) case MENU_UNSELECT_ALL: if (data->how == PICK_ANY) { reset_menu_count(hwndList, data); - for (i = 0; i < data->menu.size; i++) { + for (i = 0; i < data->menui.menu.size; i++) { + if (!menuitem_invert_test(2, data->menui.menu.items[i].itemflags, + NHMENU_IS_SELECTED(data->menui.menu.items[i]))) + continue; SelectMenuItem(hwndList, data, i, 0); } return -2; @@ -1303,9 +1346,12 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) case MENU_INVERT_ALL: if (data->how == PICK_ANY) { reset_menu_count(hwndList, data); - for (i = 0; i < data->menu.size; i++) { + for (i = 0; i < data->menui.menu.size; i++) { + if (!menuitem_invert_test(0, data->menui.menu.items[i].itemflags, + NHMENU_IS_SELECTED(data->menui.menu.items[i]))) + continue; SelectMenuItem(hwndList, data, i, - NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 + NHMENU_IS_SELECTED(data->menui.menu.items[i]) ? 0 : -1); } return -2; @@ -1319,8 +1365,11 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); from = max(0, topIndex); - to = min(data->menu.size, from + pageSize); + to = min(data->menui.menu.size, from + pageSize); for (i = from; i < to; i++) { + if (!menuitem_invert_test(1, data->menui.menu.items[i].itemflags, + NHMENU_IS_SELECTED(data->menui.menu.items[i]))) + continue; SelectMenuItem(hwndList, data, i, -1); } return -2; @@ -1334,8 +1383,11 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); from = max(0, topIndex); - to = min(data->menu.size, from + pageSize); + to = min(data->menui.menu.size, from + pageSize); for (i = from; i < to; i++) { + if (!menuitem_invert_test(2, data->menui.menu.items[i].itemflags, + NHMENU_IS_SELECTED(data->menui.menu.items[i]))) + continue; SelectMenuItem(hwndList, data, i, 0); } return -2; @@ -1349,10 +1401,13 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); from = max(0, topIndex); - to = min(data->menu.size, from + pageSize); + to = min(data->menui.menu.size, from + pageSize); for (i = from; i < to; i++) { + if (!menuitem_invert_test(0, data->menui.menu.items[i].itemflags, + NHMENU_IS_SELECTED(data->menui.menu.items[i]))) + continue; SelectMenuItem(hwndList, data, i, - NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 + NHMENU_IS_SELECTED(data->menui.menu.items[i]) ? 0 : -1); } return -2; @@ -1371,13 +1426,13 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) SetFocus(hwndList); // set focus back to the list control if (!*buf || *buf == '\033') return -2; - for (i = 0; i < data->menu.size; i++) { - if (NHMENU_IS_SELECTABLE(data->menu.items[i]) - && strstr(data->menu.items[i].str, buf)) { + for (i = 0; i < data->menui.menu.size; i++) { + if (NHMENU_IS_SELECTABLE(data->menui.menu.items[i]) + && strstr(data->menui.menu.items[i].str, buf)) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, - NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); + NHMENU_IS_SELECTED(data->menui.menu.items[i]) ? 0 : -1); } else if (data->how == PICK_ONE) { SelectMenuItem(hwndList, data, i, -1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, @@ -1412,10 +1467,10 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) pageSize = ListView_GetCountPerPage(hwndList); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus down one page */ - i = min(curIndex + pageSize, data->menu.size - 1); + i = min(curIndex + pageSize, data->menui.menu.size - 1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos down one page */ - i = min(topIndex + (2 * pageSize - 1), data->menu.size - 1); + i = min(topIndex + (2 * pageSize - 1), data->menui.menu.size - 1); ListView_EnsureVisible(hwndList, i, FALSE); return -2; @@ -1431,7 +1486,7 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) if (i >= 0) { SelectMenuItem( hwndList, data, i, - NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); + NHMENU_IS_SELECTED(data->menui.menu.items[i]) ? 0 : -1); } } } @@ -1439,18 +1494,18 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) accelerator: default: - if (strchr(data->menu.gacc, ch) - && !(ch == '0' && data->menu.counting)) { + if (strchr(data->menui.menu.gacc, ch) + && !(ch == '0' && data->menui.menu.counting)) { /* matched a group accelerator */ if (data->how == PICK_ANY || data->how == PICK_ONE) { reset_menu_count(hwndList, data); - for (i = 0; i < data->menu.size; i++) { - if (NHMENU_IS_SELECTABLE(data->menu.items[i]) - && data->menu.items[i].group_accel == ch) { + for (i = 0; i < data->menui.menu.size; i++) { + if (NHMENU_IS_SELECTABLE(data->menui.menu.items[i]) + && data->menui.menu.items[i].group_accel == ch) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, - NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 + NHMENU_IS_SELECTED(data->menui.menu.items[i]) ? 0 : -1); } else if (data->how == PICK_ONE) { SelectMenuItem(hwndList, data, i, -1); @@ -1471,14 +1526,14 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) int count; i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); if (i >= 0) { - count = data->menu.items[i].count; + count = data->menui.menu.items[i].count; if (count == -1) count = 0; count *= 10L; count += (int) (ch - '0'); if (count != 0) /* ignore leading zeros */ { - data->menu.counting = TRUE; - data->menu.items[i].count = min(100000, count); + data->menui.menu.counting = TRUE; + data->menui.menu.items[i].count = min(100000, count); ListView_RedrawItems(hwndList, i, i); /* update count mark */ } @@ -1490,15 +1545,17 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) || is_accelerator) { if (data->how == PICK_ANY || data->how == PICK_ONE) { topIndex = ListView_GetTopIndex(hwndList); - if( topIndex < 0 || topIndex > data->menu.size ) break; // impossible? + if( topIndex < 0 || topIndex > data->menui.menu.size ) break; // impossible? int iter = topIndex; do { - i = iter % data->menu.size; - if (data->menu.items[i].accelerator == ch) { + i = iter % data->menui.menu.size; + if (iflags.debug_fuzzer && iter > 1000000) + ch = data->menui.menu.items[i].accelerator; + if (data->menui.menu.items[i].accelerator == ch) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, - NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 + NHMENU_IS_SELECTED(data->menui.menu.items[i]) ? 0 : -1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); @@ -1511,7 +1568,7 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) return -2; } } - } while( (++iter % data->menu.size) != topIndex ); + } while( (++iter % data->menui.menu.size) != topIndex ); } } break; @@ -1543,10 +1600,10 @@ mswin_menu_window_size(HWND hWnd, LPSIZE sz) extra_cx = (wrt.right - wrt.left) - sz->cx; if (data->type == MENU_TYPE_MENU) { - sz->cx = data->menu.menu_cx + GetSystemMetrics(SM_CXVSCROLL); + sz->cx = data->menui.menu.menu_cx + GetSystemMetrics(SM_CXVSCROLL); } else { /* Use the width of the text box */ - sz->cx = data->text.text_box_size.cx + sz->cx = data->menui.text.text_box_size.cx + 2 * GetSystemMetrics(SM_CXVSCROLL); } sz->cx += extra_cx; @@ -1563,18 +1620,18 @@ SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count) { int i; - if (item < 0 || item >= data->menu.size) + if (item < 0 || item >= data->menui.menu.size) return; if (data->how == PICK_ONE && count != 0) { - for (i = 0; i < data->menu.size; i++) - if (item != i && data->menu.items[i].count != 0) { - data->menu.items[i].count = 0; + for (i = 0; i < data->menui.menu.size; i++) + if (item != i && data->menui.menu.items[i].count != 0) { + data->menui.menu.items[i].count = 0; ListView_RedrawItems(hwndList, i, i); }; } - data->menu.items[item].count = count; + data->menui.menu.items[item].count = count; ListView_RedrawItems(hwndList, item, item); reset_menu_count(hwndList, data); } @@ -1583,7 +1640,7 @@ void reset_menu_count(HWND hwndList, PNHMenuWindow data) { int i; - data->menu.counting = FALSE; + data->menui.menu.counting = FALSE; if (IsWindow(hwndList)) { i = ListView_GetNextItem((hwndList), -1, LVNI_FOCUSED); if (i >= 0) diff --git a/win/win32/mhmenu.h b/win/win32/mhmenu.h index 200dc3e15..a2ca7a8c4 100644 --- a/win/win32/mhmenu.h +++ b/win/win32/mhmenu.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmenu.h $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 5.0 mhmenu.h $NHDT-Date: 1596498355 2020/08/03 23:45:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhmsg.h b/win/win32/mhmsg.h index 4fd04af01..2f7eff193 100644 --- a/win/win32/mhmsg.h +++ b/win/win32/mhmsg.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmsg.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ +/* NetHack 5.0 mhmsg.h $NHDT-Date: 1596498356 2020/08/03 23:45:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -22,6 +22,9 @@ #define MSNH_MSG_GETTEXT 111 #define MSNH_MSG_UPDATE_STATUS 112 #define MSNH_MSG_RANDOM_INPUT 113 +#ifdef ENHANCED_SYMBOLS +#define MSNH_MSG_GETWIDETEXT 114 +#endif typedef struct mswin_nhmsg_add_wnd { winid wid; @@ -34,10 +37,10 @@ typedef struct mswin_nhmsg_putstr { } MSNHMsgPutstr, *PMSNHMsgPutstr; typedef struct mswin_nhmsg_print_glyph { - XCHAR_P x; - XCHAR_P y; - int glyph; - int bkglyph; + coordxy x; + coordxy y; + glyph_info glyphinfo; + glyph_info bkglyphinfo; } MSNHMsgPrintGlyph, *PMSNHMsgPrintGlyph; typedef struct mswin_nhmsg_cliparound { @@ -46,13 +49,15 @@ typedef struct mswin_nhmsg_cliparound { } MSNHMsgClipAround, *PMSNHMsgClipAround; typedef struct mswin_nhmsg_add_menu { - int glyph; + glyph_info glyphinfo; const ANY_P *identifier; - CHAR_P accelerator; - CHAR_P group_accel; + char accelerator; + char group_accel; int attr; + int color; const char *str; - BOOLEAN_P presel; + boolean presel; + unsigned int itemflags; } MSNHMsgAddMenu, *PMSNHMsgAddMenu; typedef struct mswin_nhmsg_cursor { @@ -66,9 +71,16 @@ typedef struct mswin_nhmsg_end_menu { typedef struct mswin_nhmsg_get_text { size_t max_size; - char buffer[]; + char buffer[TEXT_BUFFER_SIZE]; } MSNHMsgGetText, *PMSNHMsgGetText; +#ifdef ENHANCED_SYMBOLS +typedef struct mswin_nhmsg_get_wide_text { + size_t max_size; + WCHAR buffer[TEXT_BUFFER_SIZE]; +} MSNHMsgGetWideText, *PMSNHMsgGetWideText; +#endif + typedef struct mswin_nhmsg_update_status { struct mswin_status_lines * status_lines; } MSNHMsgUpdateStatus, *PMSNHMsgUpdateStatus; diff --git a/win/win32/mhmsgwnd.c b/win/win32/mhmsgwnd.c index 58df28c63..8dc795fba 100644 --- a/win/win32/mhmsgwnd.c +++ b/win/win32/mhmsgwnd.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 mhmsgwnd.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.32 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mhmsgwnd.c $NHDT-Date: 1596498357 2020/08/03 23:45:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.40 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" @@ -10,8 +10,7 @@ #define MSG_WRAP_TEXT #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 1) -#define MAX_MSG_LINES 128 -#define MSG_LINES (int) min(iflags.msg_history, MAX_MSG_LINES) +#define MSG_LINES (int) min(iflags.msg_history, MAX_MSG_HISTORY) #define MAXWINDOWTEXT TBUFSZ #define DEFAULT_COLOR_BG_MSG COLOR_WINDOW @@ -26,7 +25,7 @@ struct window_line { typedef struct mswin_nethack_message_window { size_t max_text; - struct window_line window_text[MAX_MSG_LINES]; + struct window_line window_text[MAX_MSG_HISTORY]; int lines_last_turn; /* lines added during the last turn */ int lines_not_seen; /* lines not yet seen by user after last turn or --More-- */ @@ -66,7 +65,7 @@ extern void play_sound_for_message(const char *str); #endif HWND -mswin_init_message_window() +mswin_init_message_window(void) { static int run_once = 0; HWND ret; @@ -116,7 +115,7 @@ mswin_init_message_window() } void -register_message_window_class() +register_message_window_class(void) { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); @@ -172,6 +171,7 @@ NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_MESSAGE].address = 0; } break; case WM_SIZE: { @@ -294,7 +294,7 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) int okkey = 0; char tmptext[MAXWINDOWTEXT + 1]; - // @@@ Ok respnses + // @@@ Ok responses /* save original text */ strcpy(tmptext, data->window_text[MSG_LINES - 1].text); @@ -416,9 +416,9 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) } } break; - case MSNH_MSG_RANDOM_INPUT: - nhassert(0); // unexpected - break; + case MSNH_MSG_RANDOM_INPUT: + nhassert(0); // unexpected + break; } /* switch( wParam ) */ } @@ -481,8 +481,8 @@ onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) // of the scroll box, and update the window. UpdateWindow // sends the WM_PAINT message. - if (yInc = max(MSG_VISIBLE_LINES - data->yPos, - min(yInc, data->yMax - data->yPos))) { + if ((yInc = max(MSG_VISIBLE_LINES - data->yPos, + min(yInc, data->yMax - data->yPos)))) { data->yPos += yInc; /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc, (CONST RECT *) NULL, (CONST RECT *) NULL, @@ -647,6 +647,7 @@ onPaint(HWND hWnd) strcpy(tmptext, data->window_text[i].text); strip_newline(tmptext); NH_A2W(tmptext, wbuf, sizeof(wbuf)); + wbuf[SIZE(wbuf) - 1] = '\0'; wlen = _tcslen(wbuf); setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn)); #ifdef MSG_WRAP_TEXT @@ -664,7 +665,7 @@ onPaint(HWND hWnd) /* Find out the cursor (caret) position */ if (i == MSG_LINES - 1) { int nnum, numfit; - SIZE size; + SIZE size = {0}; TCHAR *nbuf; int nlen; @@ -729,6 +730,7 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) ZeroMemory(data, sizeof(NHMessageWindow)); data->max_text = MAXWINDOWTEXT; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + windowdata[NHW_MESSAGE].address = (genericptr_t) data; // for cleanup at the end /* re-calculate window size (+ font size) */ mswin_message_window_size(hWnd, &dummy); @@ -769,7 +771,7 @@ mswin_message_window_size(HWND hWnd, LPSIZE sz) sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; - /* set size to accomodate MSG_VISIBLE_LINES and + /* set size to accommodate MSG_VISIBLE_LINES and horizontal scroll bar (difference between window rect and client rect */ GetClientRect(hWnd, &client_rt); @@ -794,7 +796,7 @@ can_append_text(HWND hWnd, int attr, const char *text) if (data->lines_not_seen == 0) return FALSE; - /* cannot append text with different attrbutes */ + /* cannot append text with different attributes */ if (data->window_text[MSG_LINES - 1].attr != attr) return FALSE; @@ -802,7 +804,7 @@ can_append_text(HWND hWnd, int attr, const char *text) if (str_end_is(data->window_text[MSG_LINES - 1].text, "\n")) return FALSE; - /* check if the maximum string langth will be exceeded */ + /* check if the maximum string length will be exceeded */ if (strlen(data->window_text[MSG_LINES - 1].text) + 2 + /* space characters */ strlen(text) + strlen(MORE) diff --git a/win/win32/mhmsgwnd.h b/win/win32/mhmsgwnd.h index ac780b5eb..614e0e8a2 100644 --- a/win/win32/mhmsgwnd.h +++ b/win/win32/mhmsgwnd.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmsgwnd.h $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 5.0 mhmsgwnd.h $NHDT-Date: 1596498358 2020/08/03 23:45:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhrip.c b/win/win32/mhrip.c index f00004f09..45188ac31 100644 --- a/win/win32/mhrip.c +++ b/win/win32/mhrip.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 mhrip.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.19 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mhrip.c $NHDT-Date: 1596498358 2020/08/03 23:45:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.24 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "win10.h" @@ -40,7 +40,7 @@ INT_PTR CALLBACK NHRIPWndProc(HWND, UINT, WPARAM, LPARAM); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); HWND -mswin_init_RIP_window() +mswin_init_RIP_window(void) { HWND ret; PNHRIPWindow data; @@ -56,6 +56,7 @@ mswin_init_RIP_window() ZeroMemory(data, sizeof(NHRIPWindow)); SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR) data); + windowdata[NHW_RIP].address = (genericptr_t) data; return ret; } @@ -240,6 +241,7 @@ NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) DeleteObject(data->rip_bmp); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_RIP].address = 0; } break; } @@ -262,13 +264,20 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) text_size = strlen(msg_data->text) + 4; data->window_text = (TCHAR *) malloc(text_size * sizeof(data->window_text[0])); - ZeroMemory(data->window_text, - text_size * sizeof(data->window_text[0])); + if (data->window_text) { + ZeroMemory(data->window_text, + text_size * sizeof(data->window_text[0])); + } } else { + TCHAR *was = data->window_text; + text_size = _tcslen(data->window_text) + strlen(msg_data->text) + 4; data->window_text = (TCHAR *) realloc( data->window_text, text_size * sizeof(data->window_text[0])); + if (!data->window_text) { + free(was); + } } if (!data->window_text) break; @@ -283,11 +292,12 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) break; } - case MSNH_MSG_RANDOM_INPUT: - nhassert(0); // unexpected - break; + case MSNH_MSG_RANDOM_INPUT: + nhassert(0); // unexpected + break; } + nhUse(InRipText); } void diff --git a/win/win32/mhrip.h b/win/win32/mhrip.h index f463d0c85..7435294ef 100644 --- a/win/win32/mhrip.h +++ b/win/win32/mhrip.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhrip.h $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 5.0 mhrip.h $NHDT-Date: 1596498359 2020/08/03 23:45:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index dcb698450..da5897978 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 mhsplash.c $NHDT-Date: 1449751714 2015/12/10 12:48:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.27 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mhsplash.c $NHDT-Date: 1596498360 2020/08/03 23:46:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.36 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "win10.h" @@ -8,8 +8,10 @@ #include "mhsplash.h" #include "mhmsg.h" #include "mhfont.h" -#include "date.h" +#include "config.h" +#if !defined(VERSION_MAJOR) #include "patchlevel.h" +#endif #include "dlb.h" #define LLEN 128 @@ -133,6 +135,8 @@ mswin_display_splash_window(BOOL show_ver) mswin_set_splash_data(hWnd, &splashData, monitorInfo.scale); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) &splashData); + windowdata[NHW_SPLASH].address = (genericptr_t) &splashData; + windowdata[NHW_SPLASH].isstatic = 1; GetNHApp()->hPopupWnd = hWnd; @@ -143,15 +147,15 @@ mswin_display_splash_window(BOOL show_ver) /* Fill the text control */ strbuf_reserve(&strbuf, BUFSIZ); Sprintf(strbuf.str, "%s\n%s\n%s\n%s\n\n", COPYRIGHT_BANNER_A, - COPYRIGHT_BANNER_B, COPYRIGHT_BANNER_C, COPYRIGHT_BANNER_D); + COPYRIGHT_BANNER_B, nomakedefs.copyright_banner_c, COPYRIGHT_BANNER_D); if (show_ver) { /* Show complete version information */ dlb *f; char verbuf[BUFSZ]; - int verstrsize = 0; - - getversionstring(verbuf); + /* int verstrsize = 0; */ + + getversionstring(verbuf, sizeof verbuf); strbuf_append(&strbuf, verbuf); strbuf_append(&strbuf, "\n\n"); @@ -255,6 +259,7 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) DrawText(hdc, VersionString, strlen(VersionString), &rt, DT_LEFT | DT_NOPREFIX); EndPaint(hWnd, &ps); + nhUse(OldFont); } break; case WM_COMMAND: diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index 20b09f094..d7e66505d 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 mhstatus.c $NHDT-Date: 1536411224 2018/09/08 12:53:44 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.29 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mhstatus.c $NHDT-Date: 1596498360 2020/08/03 23:46:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.35 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include @@ -19,7 +19,6 @@ extern COLORREF nhcolor_to_RGB(int c); /* from mhmap */ - typedef struct back_buffer { HWND hWnd; HDC hdc; @@ -29,6 +28,11 @@ typedef struct back_buffer { int height; } back_buffer_t; +void back_buffer_free(back_buffer_t * back_buffer); +void back_buffer_allocate(back_buffer_t * back_buffer, int width, int height); +void back_buffer_size(back_buffer_t * back_buffer, int width, int height); +void back_buffer_init(back_buffer_t * back_buffer, HWND hWnd, int width, int height); + void back_buffer_free(back_buffer_t * back_buffer) { if (back_buffer->bm != NULL) { @@ -73,7 +77,7 @@ typedef struct mswin_nethack_status_window { mswin_status_lines * status_lines; back_buffer_t back_buffer; boolean blink_state; /* true = invert blink text */ - boolean has_blink_fields; /* true if one or more has blink attriubte */ + boolean has_blink_fields; /* true if one or more has blink attribute */ } NHStatusWindow, *PNHStatusWindow; @@ -86,7 +90,7 @@ static LRESULT onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam); #define DEFAULT_COLOR_FG_STATUS COLOR_WINDOWTEXT HWND -mswin_init_status_window() +mswin_init_status_window(void) { static int run_once = 0; HWND ret; @@ -127,6 +131,7 @@ mswin_init_status_window() if (!data) panic("out of memory"); + windowdata[NHW_STATUS].address = (genericptr_t) data; ZeroMemory(data, sizeof(NHStatusWindow)); SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR) data); @@ -151,7 +156,7 @@ mswin_init_status_window() } void -register_status_window_class() +register_status_window_class(void) { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); @@ -199,15 +204,17 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) size_t space_remaining = msg_data->max_size; for (int line = 0; line < NHSW_LINES; line++) { - mswin_status_line *status_line = data->status_lines[line].lines; + mswin_status_line *status_line = &data->status_lines->lines[line]; for (int i = 0; i < status_line->status_strings.count; i++) { mswin_status_string * status_string = status_line->status_strings.status_strings[i]; - if (status_string->space_in_front) { - strncat(msg_data->buffer, " ", space_remaining); + if (status_string->str != NULL) { + if (status_string->space_in_front) { + strncat(msg_data->buffer, " ", space_remaining); + space_remaining = msg_data->max_size - strlen(msg_data->buffer); + } + strncat(msg_data->buffer, status_string->str, space_remaining); space_remaining = msg_data->max_size - strlen(msg_data->buffer); } - strncat(msg_data->buffer, status_string->str, space_remaining); - space_remaining = msg_data->max_size - strlen(msg_data->buffer); } strncat(msg_data->buffer, "\r\n", space_remaining); space_remaining = msg_data->max_size - strlen(msg_data->buffer); @@ -220,9 +227,9 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) InvalidateRect(hWnd, NULL, TRUE); } break; - case MSNH_MSG_RANDOM_INPUT: - nhassert(0); // unexpected - break; + case MSNH_MSG_RANDOM_INPUT: + nhassert(0); // unexpected + break; } /* end switch( wParam ) { */ } break; @@ -251,6 +258,7 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_STATUS].address = 0; break; case WM_SETFOCUS: @@ -270,7 +278,7 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } static LRESULT -onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) +onWMPaint(HWND hWnd, WPARAM wParam UNUSED, LPARAM lParam UNUSED) { SIZE sz; WCHAR wbuf[BUFSZ]; @@ -350,7 +358,7 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) BOOL useUnicode = fnt->supportsUnicode; - winos_ascii_to_wide_str(str, wbuf, SIZE(wbuf)); + winos_ascii_to_wide_str((const unsigned char *) str, wbuf, SIZE(wbuf)); nFg = (clr == NO_COLOR ? status_fg_color : ((clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr) diff --git a/win/win32/mhstatus.h b/win/win32/mhstatus.h index 4d5d93753..f4b3d844e 100644 --- a/win/win32/mhstatus.h +++ b/win/win32/mhstatus.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhstatus.h $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 5.0 mhstatus.h $NHDT-Date: 1596498361 2020/08/03 23:46:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -17,11 +17,13 @@ static const int fieldorder2[] = { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX BL_ENE, BL_ENEMAX, BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, -1 }; +#ifdef MSWPROC_C static const int *fieldorders[] = { fieldorder1, fieldorder2, NULL }; +#endif static const int fieldcounts[NHSW_LINES] = { SIZE(fieldorder1) - 1, SIZE(fieldorder2) - 1}; #define MSWIN_MAX_LINE1_STRINGS (SIZE(fieldorder1) - 1) -#define MSWIN_MAX_LINE2_STRINGS (SIZE(fieldorder2) - 1 + BL_MASK_BITS) +#define MSWIN_MAX_LINE2_STRINGS (SIZE(fieldorder2) - 1 + CONDITION_COUNT) #define MSWIN_MAX_LINE_STRINGS (MSWIN_MAX_LINE1_STRINGS > MSWIN_MAX_LINE2_STRINGS ? \ MSWIN_MAX_LINE1_STRINGS : MSWIN_MAX_LINE2_STRINGS) diff --git a/win/win32/mhtext.c b/win/win32/mhtext.c index 0ff816f8a..72ab526e6 100644 --- a/win/win32/mhtext.c +++ b/win/win32/mhtext.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 mhtext.c $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mhtext.c $NHDT-Date: 1596498362 2020/08/03 23:46:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.31 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" @@ -24,7 +24,7 @@ static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void LayoutText(HWND hwnd); HWND -mswin_init_text_window() +mswin_init_text_window(void) { HWND ret; RECT rt; @@ -36,7 +36,7 @@ mswin_init_text_window() mswin_get_window_placement(NHW_TEXT, &rt); } - /* create text widnow object */ + /* create text window object */ ret = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_NHTEXT), GetNHApp()->hMainWnd, NHTextWndProc); if (!ret) @@ -83,8 +83,10 @@ NHTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) data = (PNHTextWindow)malloc(sizeof(NHTextWindow)); if (!data) panic("out of memory"); + ZeroMemory(data, sizeof(NHTextWindow)); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)data); + windowdata[NHW_TEXT].address = (genericptr_t) data; // for cleanup at the end HWND control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); HDC hdc = GetDC(control); @@ -173,6 +175,7 @@ NHTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) free(data->window_text); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_TEXT].address = 0; } break; @@ -198,13 +201,20 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) text_size = strlen(msg_data->text) + 4; data->window_text = (TCHAR *) malloc(text_size * sizeof(data->window_text[0])); - ZeroMemory(data->window_text, - text_size * sizeof(data->window_text[0])); + if (data->window_text) { + ZeroMemory(data->window_text, + text_size * sizeof(data->window_text[0])); + } } else { + TCHAR *was = data->window_text; + text_size = _tcslen(data->window_text) + strlen(msg_data->text) + 4; data->window_text = (TCHAR *) realloc( data->window_text, text_size * sizeof(data->window_text[0])); + if (!data->window_text) { + free(was); + } } if (!data->window_text) break; @@ -214,11 +224,11 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) break; } - case MSNH_MSG_RANDOM_INPUT: { - PostMessage(GetDlgItem(hWnd, IDC_TEXT_CONTROL), + case MSNH_MSG_RANDOM_INPUT: { + PostMessage(GetDlgItem(hWnd, IDC_TEXT_CONTROL), WM_MSNH_COMMAND, MSNH_MSG_RANDOM_INPUT, 0); - } - break; + } + break; } } diff --git a/win/win32/mhtext.h b/win/win32/mhtext.h index edcea4be8..eee831041 100644 --- a/win/win32/mhtext.h +++ b/win/win32/mhtext.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhtext.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 5.0 mhtext.h $NHDT-Date: 1596498363 2020/08/03 23:46:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index e54292728..8a46c375b 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -1,5 +1,5 @@ -/* NetHack 3.6 mswproc.c $NHDT-Date: 1575245201 2019/12/02 00:06:41 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.137 $ */ -/* Copyright (C) 2001 by Alex Kompel */ +/* NetHack 5.0 mswproc.c $NHDT-Date: 1717967341 2024/06/09 21:09:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.193 $ */ +/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* @@ -7,12 +7,13 @@ * code in the mswin port and the rest of the nethack game engine. */ +#define MSWPROC_C #include "hack.h" #include "color.h" #include "dlb.h" #include "func_tab.h" /* for extended commands */ #include "winMS.h" -#include + #include #include "mhmap.h" #include "mhstatus.h" @@ -28,6 +29,7 @@ #include "mhmain.h" #include "mhfont.h" #include "resource.h" +#undef MSWPROC_C #define LLEN 128 @@ -35,7 +37,7 @@ #ifdef DEBUG # ifdef _DEBUG -static FILE* _s_debugfp = NULL; +static FILE *_s_debugfp = NULL; extern void logDebug(const char *fmt, ...); # endif #endif @@ -76,19 +78,24 @@ COLORREF message_bg_color = RGB(0, 0, 0); COLORREF message_fg_color = RGB(0xFF, 0xFF, 0xFF); strbuf_t raw_print_strbuf = { 0 }; +color_attr mswin_menu_promptstyle = { NO_COLOR, ATR_NONE }; /* Interface definition, for windows.c */ struct window_procs mswin_procs = { - "MSWIN", + WPID(mswin), WC_COLOR | WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_INVERSE | WC_SCROLL_AMOUNT | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONT_MAP | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE | WC_VARY_MSGCOUNT | WC_WINDOWCOLORS | WC_PLAYER_SELECTION + | WC_PERM_INVENT | WC_SPLASH_SCREEN | WC_POPUP_DIALOG | WC_MOUSE_SUPPORT, #ifdef STATUS_HILITES WC2_HITPOINTBAR | WC2_FLUSH_STATUS | WC2_RESET_STATUS | WC2_HILITE_STATUS | +#endif +#ifdef ENHANCED_SYMBOLS + WC2_U_UTF8STR | WC2_EXTRACOLORS | #endif 0L, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ @@ -99,7 +106,7 @@ struct window_procs mswin_procs = { genl_putmixed, mswin_display_file, mswin_start_menu, mswin_add_menu, mswin_end_menu, mswin_select_menu, genl_message_menu, /* no need for X-specific handling */ - mswin_update_inventory, mswin_mark_synch, mswin_wait_synch, + mswin_mark_synch, mswin_wait_synch, #ifdef CLIPPING mswin_cliparound, #endif @@ -110,18 +117,19 @@ struct window_procs mswin_procs = { mswin_nh_poskey, mswin_nhbell, mswin_doprev_message, mswin_yn_function, mswin_getlin, mswin_get_ext_cmd, mswin_number_pad, mswin_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ - mswin, mswin_change_background, + mswin_change_color, mswin_get_color_string, #endif - /* other defs that really should go away (they're tty specific) */ - mswin_start_screen, mswin_end_screen, mswin_outrip, + mswin_outrip, mswin_preference_update, mswin_getmsghistory, mswin_putmsghistory, mswin_status_init, mswin_status_finish, mswin_status_enablefield, mswin_status_update, genl_can_suspend_yes, + mswin_update_inventory, + mswin_ctrl_nhwindow, }; /* -init_nhwindows(int* argcp, char** argv) +init_nhwindows(int *argcp, char **argv) -- Initialize the windows used by NetHack. This can also create the standard windows listed at the top, but does not display them. @@ -154,10 +162,10 @@ mswin_init_nhwindows(int *argc, char **argv) mswin_nh_input_init(); /* set it to WIN_ERR so we can detect attempts to - use this ID before it is inialized */ + use this ID before it is initialized */ WIN_MAP = WIN_ERR; - /* Read Windows settings from the reqistry */ + /* Read Windows settings from the registry */ /* First set safe defaults */ GetNHApp()->regMainMinX = CW_USEDEFAULT; mswin_read_reg(); @@ -213,16 +221,16 @@ mswin_init_nhwindows(int *argc, char **argv) * non-console applications */ iflags.toptenwin = 1; - set_option_mod_status("toptenwin", SET_IN_FILE); - //set_option_mod_status("perm_invent", SET_IN_FILE); - set_option_mod_status("mouse_support", SET_IN_GAME); + set_option_mod_status("toptenwin", set_in_config); + //set_option_mod_status("perm_invent", set_in_config); + set_option_mod_status("mouse_support", set_in_game); /* initialize map tiles bitmap */ initMapTiles(); /* set tile-related options to readonly */ set_wc_option_mod_status(WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE, - DISP_IN_GAME); + set_gameview); /* set font-related options to change in the game */ set_wc_option_mod_status( @@ -231,24 +239,24 @@ mswin_init_nhwindows(int *argc, char **argv) | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT, - SET_IN_GAME); - - mswin_color_from_string(iflags.wc_foregrnd_menu, &menu_fg_brush, - &menu_fg_color); - mswin_color_from_string(iflags.wc_foregrnd_message, &message_fg_brush, - &message_fg_color); - mswin_color_from_string(iflags.wc_foregrnd_status, &status_fg_brush, - &status_fg_color); - mswin_color_from_string(iflags.wc_foregrnd_text, &text_fg_brush, - &text_fg_color); - mswin_color_from_string(iflags.wc_backgrnd_menu, &menu_bg_brush, - &menu_bg_color); - mswin_color_from_string(iflags.wc_backgrnd_message, &message_bg_brush, - &message_bg_color); - mswin_color_from_string(iflags.wc_backgrnd_status, &status_bg_brush, - &status_bg_color); - mswin_color_from_string(iflags.wc_backgrnd_text, &text_bg_brush, - &text_bg_color); + set_in_game); + + mswin_color_from_string(iflags.wcolors[wcolor_menu].fg, + &menu_fg_brush, &menu_fg_color); + mswin_color_from_string(iflags.wcolors[wcolor_message].fg, + &message_fg_brush, &message_fg_color); + mswin_color_from_string(iflags.wcolors[wcolor_status].fg, + &status_fg_brush, &status_fg_color); + mswin_color_from_string(iflags.wcolors[wcolor_text].fg, + &text_fg_brush, &text_fg_color); + mswin_color_from_string(iflags.wcolors[wcolor_menu].bg, + &menu_bg_brush, &menu_bg_color); + mswin_color_from_string(iflags.wcolors[wcolor_message].bg, + &message_bg_brush, &message_bg_color); + mswin_color_from_string(iflags.wcolors[wcolor_status].bg, + &status_bg_brush, &status_bg_color); + mswin_color_from_string(iflags.wcolors[wcolor_text].bg, + &text_bg_brush, &text_bg_color); if (iflags.wc_splash_screen) mswin_display_splash_window(FALSE); @@ -331,6 +339,7 @@ prompt_for_player_selection(void) anything any; menu_item *selected = 0; DWORD box_result; + int clr = NO_COLOR; logDebug("prompt_for_player_selection()\n"); @@ -355,22 +364,23 @@ prompt_for_player_selection(void) /* tty_putstr(BASE_WINDOW, 0, prompt); */ do { /* pick4u = lowc(readchar()); */ - if (index(quitchars, pick4u)) + if (strchr(quitchars, pick4u)) pick4u = 'y'; - } while (!index(ynqchars, pick4u)); + } while (!strchr(ynqchars, pick4u)); if ((int) strlen(prompt) + 1 < CO) { /* Echo choice and move back down line */ /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, * pick4u); */ /* tty_putstr(BASE_WINDOW, 0, ""); */ - } else + } else { /* Otherwise it's hard to tell where to echo, and things are * wrapping a bit messily anyway, so (try to) make sure the next * question shows up well and doesn't get wrapped at the * bottom of the window. */ - /* tty_clear_nhwindow(BASE_WINDOW) */; - + /* tty_clear_nhwindow(BASE_WINDOW) */ + ; + } if (pick4u != 'y' && pick4u != 'n') { give_up: /* Quit */ if (selected) @@ -405,8 +415,8 @@ prompt_for_player_selection(void) /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */ /* Prompt for a role */ win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ + start_menu(win, MENU_BEHAVE_STANDARD); + any = cg.zeroany; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { @@ -428,8 +438,8 @@ prompt_for_player_selection(void) } else Strcpy(rolenamebuf, roles[i].name.m); } - add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE, - an(rolenamebuf), MENU_UNSELECTED); + add_menu(win, &nul_glyphinfo, &any, thisch, 0, ATR_NONE, + clr, an(rolenamebuf), MENU_ITEMFLAGS_NONE); lastch = thisch; } } @@ -437,12 +447,12 @@ prompt_for_player_selection(void) flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrole(FALSE) + 1; - add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", - MENU_UNSELECTED); + add_menu(win, &nul_glyphinfo, &any, '*', 0, + ATR_NONE, clr, "Random", MENU_ITEMFLAGS_NONE); any.a_int = i + 1; /* must be non-zero */ - add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", - MENU_UNSELECTED); - Sprintf(pbuf, "Pick a role for your %s", plbuf); + add_menu(win, &nul_glyphinfo, &any, 'q', 0, + ATR_NONE, clr, "Quit", MENU_ITEMFLAGS_NONE); + Snprintf(pbuf, sizeof pbuf, "Pick a role for your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); @@ -497,25 +507,26 @@ prompt_for_player_selection(void) /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */ win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ + start_menu(win, MENU_BEHAVE_STANDARD); + any = cg.zeroany; /* zero out all bits */ for (i = 0; races[i].noun; i++) if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { any.a_int = i + 1; /* must be non-zero */ - add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, - ATR_NONE, races[i].noun, MENU_UNSELECTED); + add_menu(win, &nul_glyphinfo, &any, + races[i].noun[0], 0, ATR_NONE, clr, + races[i].noun, MENU_ITEMFLAGS_NONE); } any.a_int = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrace(flags.initrole) + 1; - add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", - MENU_UNSELECTED); + add_menu(win, &nul_glyphinfo, &any, '*', 0, + ATR_NONE, clr, "Random", MENU_ITEMFLAGS_NONE); any.a_int = i + 1; /* must be non-zero */ - add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", - MENU_UNSELECTED); - Sprintf(pbuf, "Pick the race of your %s", plbuf); + add_menu(win, &nul_glyphinfo, &any, 'q', 0, + ATR_NONE, clr, "Quit", MENU_ITEMFLAGS_NONE); + Snprintf(pbuf, sizeof pbuf, "Pick the race of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); @@ -571,25 +582,26 @@ prompt_for_player_selection(void) /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */ win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ + start_menu(win, MENU_BEHAVE_STANDARD); + any = cg.zeroany; /* zero out all bits */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { any.a_int = i + 1; - add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, - ATR_NONE, genders[i].adj, MENU_UNSELECTED); + add_menu(win, &nul_glyphinfo, &any, + genders[i].adj[0], 0, ATR_NONE, clr, + genders[i].adj, MENU_ITEMFLAGS_NONE); } any.a_int = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randgend(flags.initrole, flags.initrace) + 1; - add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", - MENU_UNSELECTED); + add_menu(win, &nul_glyphinfo, &any, '*', 0, + ATR_NONE, clr, "Random", MENU_ITEMFLAGS_NONE); any.a_int = i + 1; /* must be non-zero */ - add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", - MENU_UNSELECTED); - Sprintf(pbuf, "Pick the gender of your %s", plbuf); + add_menu(win, &nul_glyphinfo, &any, 'q', 0, + ATR_NONE, clr, "Quit", MENU_ITEMFLAGS_NONE); + Snprintf(pbuf, sizeof pbuf, "Pick the gender of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); @@ -644,25 +656,26 @@ prompt_for_player_selection(void) /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */ win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ + start_menu(win, MENU_BEHAVE_STANDARD); + any = cg.zeroany; /* zero out all bits */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { any.a_int = i + 1; - add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, - ATR_NONE, aligns[i].adj, MENU_UNSELECTED); + add_menu(win, &nul_glyphinfo, &any, + aligns[i].adj[0], 0, ATR_NONE, clr, + aligns[i].adj, MENU_ITEMFLAGS_NONE); } any.a_int = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randalign(flags.initrole, flags.initrace) + 1; - add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", - MENU_UNSELECTED); + add_menu(win, &nul_glyphinfo, &any, '*', 0, + ATR_NONE, clr, "Random", MENU_ITEMFLAGS_NONE); any.a_int = i + 1; /* must be non-zero */ - add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", - MENU_UNSELECTED); - Sprintf(pbuf, "Pick the alignment of your %s", plbuf); + add_menu(win, &nul_glyphinfo, &any, 'q', 0, + ATR_NONE, clr, "Quit", MENU_ITEMFLAGS_NONE); + Snprintf(pbuf, sizeof pbuf, "Pick the alignment of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); @@ -685,7 +698,7 @@ mswin_askname(void) { logDebug("mswin_askname()\n"); - if (mswin_getlin_window("Who are you?", plname, PL_NSIZ) == IDCANCEL) { + if (mswin_getlin_window("Who are you?", svp.plname, PL_NSIZ) == IDCANCEL) { bail("bye-bye"); /* not reached */ } @@ -721,9 +734,6 @@ mswin_exit_nhwindows(const char *str) /* Write Window settings to the registry */ mswin_write_reg(); - /* set things back to failsafes */ - windowprocs = *get_safe_procs(0); - /* and make sure there is still a way to communicate something */ windowprocs.win_raw_print = mswin_raw_print; windowprocs.win_raw_print_bold = mswin_raw_print_bold; @@ -741,7 +751,7 @@ mswin_suspend_nhwindows(const char *str) /* Restore the windows after being suspended. */ void -mswin_resume_nhwindows() +mswin_resume_nhwindows(void) { logDebug("mswin_resume_nhwindows()\n"); @@ -851,7 +861,7 @@ mswin_clear_nhwindow(winid wid) --more--, if necessary, in the tty window-port. */ void -mswin_display_nhwindow(winid wid, BOOLEAN_P block) +mswin_display_nhwindow(winid wid, boolean block) { logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block); if (GetNHApp()->windowlist[wid].win != NULL) { @@ -871,7 +881,8 @@ mswin_display_nhwindow(winid wid, BOOLEAN_P block) if (!block) { UpdateWindow(GetNHApp()->windowlist[wid].win); } else { - if (GetNHApp()->windowlist[wid].type == NHW_MAP) { + if ((GetNHApp()->windowlist[wid].type == NHW_MAP) + || (GetNHApp()->windowlist[wid].type == NHW_MESSAGE)) { (void) mswin_nhgetch(); } } @@ -1010,6 +1021,7 @@ mswin_putstr_ex(winid wid, int attr, const char *text, int app) if (GetNHApp()->windowlist[wid].win != NULL) { MSNHMsgPutstr data; + ZeroMemory(&data, sizeof(data)); data.attr = attr; data.text = text; @@ -1020,11 +1032,17 @@ mswin_putstr_ex(winid wid, int attr, const char *text, int app) /* yield a bit so it gets done immediately */ mswin_get_nh_event(); } else { + char *was = GetNHApp()->saved_text; + // build text to display later in message box GetNHApp()->saved_text = realloc(GetNHApp()->saved_text, strlen(text) + strlen(GetNHApp()->saved_text) + 1); - strcat(GetNHApp()->saved_text, text); + if (!GetNHApp()->saved_text) { + free(was); + } else { + strcat(GetNHApp()->saved_text, text); + } } } @@ -1032,7 +1050,7 @@ mswin_putstr_ex(winid wid, int attr, const char *text, int app) iff complain is TRUE. */ void -mswin_display_file(const char *filename, BOOLEAN_P must_exist) +mswin_display_file(const char *filename, boolean must_exist) { dlb *f; TCHAR wbuf[BUFSZ]; @@ -1043,8 +1061,9 @@ mswin_display_file(const char *filename, BOOLEAN_P must_exist) if (!f) { if (must_exist) { TCHAR message[90]; - _stprintf(message, TEXT("Warning! Could not find file: %s\n"), - NH_A2W(filename, wbuf, sizeof(wbuf))); + nh_stprintf(message, sizeof message, + TEXT("Warning! Could not find file: %s\n"), + NH_A2W(filename, wbuf, sizeof(wbuf))); NHMessageBox(GetNHApp()->hMainWnd, message, MB_OK | MB_ICONEXCLAMATION); } @@ -1074,9 +1093,9 @@ mswin_display_file(const char *filename, BOOLEAN_P must_exist) be used for menus. */ void -mswin_start_menu(winid wid) +mswin_start_menu(winid wid, unsigned long mbehavior) { - logDebug("mswin_start_menu(%d)\n", wid); + logDebug("mswin_start_menu(%d, %lu)\n", wid, mbehavior); if ((wid >= 0) && (wid < MAXWINDOWS)) { if (GetNHApp()->windowlist[wid].win == NULL && GetNHApp()->windowlist[wid].type == NHW_MENU) { @@ -1093,12 +1112,13 @@ mswin_start_menu(winid wid) } /* -add_menu(windid window, int glyph, const anything identifier, +add_menu(windid window, const glyph_info *glyphinfo, + const anything identifier, char accelerator, char groupacc, - int attr, char *str, boolean preselected) + int attr, int clr, + char *str, unsigned int itemflags) -- Add a text line str to the given menu window. If -identifier - is 0, then the line cannot be selected (e.g. a title). + identifier is 0, then the line cannot be selected (e.g. a title). Otherwise, identifier is the value returned if the line is selected. Accelerator is a keyboard key that can be used to select the line. If the accelerator of a selectable @@ -1106,8 +1126,8 @@ identifier accelerator. It is up to the window-port to make the accelerator visible to the user (e.g. put "a - " in front of str). The value attr is the same as in putstr(). - Glyph is an optional glyph to accompany the line. If - window port cannot or does not want to display it, this + Glyphinfo->glyph is an optional glyph to accompany the line. + If window port cannot or does not want to display it, this is OK. If there is no glyph applicable, then this value will be NO_GLYPH. -- All accelerators should be in the range [A-Za-z]. @@ -1125,24 +1145,30 @@ identifier menu is displayed, set preselected to TRUE. */ void -mswin_add_menu(winid wid, int glyph, const ANY_P *identifier, - CHAR_P accelerator, CHAR_P group_accel, int attr, - const char *str, BOOLEAN_P presel) -{ - logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n", wid, glyph, - identifier, (char) accelerator, (char) group_accel, attr, str, - presel); +mswin_add_menu(winid wid, const glyph_info *glyphinfo, + const ANY_P *identifier, + char accelerator, char group_accel, int attr, int clr, + const char *str, unsigned int itemflags) +{ + boolean presel = ((itemflags & MENU_ITEMFLAGS_SELECTED) != 0); + logDebug("mswin_add_menu(%d, %d, %u, %p, %c, %c, %d, %d, %s, %u)\n", wid, + glyphinfo->glyph, glyphinfo->gm.glyphflags, + identifier, (char) accelerator, (char) group_accel, attr, clr, str, + itemflags); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgAddMenu data; ZeroMemory(&data, sizeof(data)); - data.glyph = glyph; + if (glyphinfo) + data.glyphinfo = *glyphinfo; data.identifier = identifier; data.accelerator = accelerator; data.group_accel = group_accel; data.attr = attr; + data.color = clr; data.str = str; data.presel = presel; + data.itemflags = itemflags; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_ADDMENU, (LPARAM) &data); @@ -1220,16 +1246,38 @@ mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected) /* -- Indicate to the window port that the inventory has been changed. - -- Merely calls display_inventory() for window-ports that leave the + -- Merely calls repopulate_perminvent() for window-ports that leave the window up, otherwise empty. */ void -mswin_update_inventory() +mswin_update_inventory(int arg) { - logDebug("mswin_update_inventory()\n"); + logDebug("mswin_update_inventory(%d)\n", arg); if (iflags.perm_invent && program_state.something_worth_saving && iflags.window_inited && WIN_INVEN != WIN_ERR) - display_inventory(NULL, FALSE); + repopulate_perminvent(); +} + +win_request_info * +mswin_ctrl_nhwindow( + winid window UNUSED, + int request, + win_request_info *wri) +{ + if (!wri) + return (win_request_info *) 0; + + switch(request) { + case set_mode: + case request_settings: + break; + case set_menu_promptstyle: + mswin_menu_promptstyle = wri->fromcore.menu_promptstyle; + break; + default: + break; + } + return wri; } /* @@ -1238,7 +1286,7 @@ mark_synch() -- Don't go beyond this point in I/O on any channel until for the moment */ void -mswin_mark_synch() +mswin_mark_synch(void) { logDebug("mswin_mark_synch()\n"); } @@ -1250,7 +1298,7 @@ wait_synch() -- Wait until all pending output is complete (*flush*() for display is OK when return from wait_synch(). */ void -mswin_wait_synch() +mswin_wait_synch(void) { logDebug("mswin_wait_synch()\n"); mswin_raw_print_flush(); @@ -1279,21 +1327,23 @@ mswin_cliparound(int x, int y) } /* -print_glyph(window, x, y, glyph, bkglyph) - -- Print the glyph at (x,y) on the given window. Glyphs are - integers at the interface, mapped to whatever the window- +print_glyph(window, x, y, glyphinfo, bkglyphinfo) + -- Print a glyph (glyphinfo->glyph) at (x,y) on the given + window. Glyphs are integers mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). - -- bkglyph is a background glyph for potential use by some - graphical or tiled environments to allow the depiction - to fall against a background consistent with the grid - around x,y. + -- bkglyphinfo contains a background glyph for potential use + by some graphical or tiled environments to allow the depiction + to fall against a background consistent with the grid + around x,y. */ void -mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) +mswin_print_glyph(winid wid, coordxy x, coordxy y, + const glyph_info *glyphinfo, const glyph_info *bkglyphinfo) { - logDebug("mswin_print_glyph(%d, %d, %d, %d, %d)\n", wid, x, y, glyph, bkglyph); + logDebug("mswin_print_glyph(%d, %d, %d, %d, %d, %lu)\n", + wid, x, y, glyphinfo->glyph, bkglyphinfo->glyph); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { @@ -1302,8 +1352,10 @@ mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) ZeroMemory(&data, sizeof(data)); data.x = x; data.y = y; - data.glyph = glyph; - data.bkglyph = bkglyph; + if (glyphinfo) + data.glyphinfo = *glyphinfo; + if (bkglyphinfo) + data.bkglyphinfo = *bkglyphinfo; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_PRINT_GLYPH, (LPARAM) &data); } @@ -1313,10 +1365,12 @@ mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) * mswin_raw_print_accumulate() accumulate the given text into * raw_print_strbuf. */ +void mswin_raw_print_accumulate(const char * str, boolean bold); + void mswin_raw_print_accumulate(const char * str, boolean bold) { - bold; // ignored for now + nhUse(bold); // ignored for now if (raw_print_strbuf.str != NULL) strbuf_append(&raw_print_strbuf, "\n"); strbuf_append(&raw_print_strbuf, str); @@ -1327,16 +1381,22 @@ mswin_raw_print_accumulate(const char * str, boolean bold) * dialog box and clear raw_print_strbuf. */ void -mswin_raw_print_flush() +mswin_raw_print_flush(void) { if (raw_print_strbuf.str != NULL) { int wlen = strlen(raw_print_strbuf.str) + 1; - TCHAR * wbuf = (TCHAR *) alloc(wlen * sizeof(TCHAR)); - if (wbuf != NULL) { - NHMessageBox(GetNHApp()->hMainWnd, + if (strcmp(raw_print_strbuf.str, "\n") != 0 +#ifdef _MSC_VER + || IsDebuggerPresent() +#endif + ) { + TCHAR * wbuf = (TCHAR *) alloc(wlen * sizeof(TCHAR)); + if (wbuf != NULL) { + NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(raw_print_strbuf.str, wbuf, wlen), MB_ICONINFORMATION | MB_OK); - free(wbuf); + free(wbuf); + } } strbuf_empty(&raw_print_strbuf); } @@ -1391,7 +1451,7 @@ int nhgetch() -- Returns a single character input from the user. Returned character _must_ be non-zero. */ int -mswin_nhgetch() +mswin_nhgetch(void) { PMSNHEvent event; int key = 0; @@ -1401,12 +1461,12 @@ mswin_nhgetch() while ((event = mswin_input_pop()) == NULL || event->type != NHEVENT_CHAR) mswin_main_loop(); - key = event->kbd.ch; + key = event->ei.kbd.ch; return (key); } /* -int nh_poskey(int *x, int *y, int *mod) +int nh_poskey(coordxy *x, coordxy *y, int *mod) -- Returns a single character input from the user or a a positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, @@ -1421,7 +1481,7 @@ int nh_poskey(int *x, int *y, int *mod) routine always returns a non-zero character. */ int -mswin_nh_poskey(int *x, int *y, int *mod) +mswin_nh_poskey(coordxy *x, coordxy *y, int *mod) { PMSNHEvent event; int key; @@ -1432,26 +1492,27 @@ mswin_nh_poskey(int *x, int *y, int *mod) mswin_main_loop(); if (event->type == NHEVENT_MOUSE) { - if (iflags.wc_mouse_support) { - *mod = event->ms.mod; - *x = event->ms.x; - *y = event->ms.y; + if (iflags.wc_mouse_support) { + *mod = event->ei.ms.mod; + *x = (coordxy) event->ei.ms.x; + *y = (coordxy) event->ei.ms.y; } key = 0; } else { - key = event->kbd.ch; + key = event->ei.kbd.ch; } return (key); } /* nhbell() -- Beep at user. [This will exist at least until sounds are - redone, since sounds aren't attributable to windows -anyway.] + redone, since sounds aren't attributable to windows anyway.] */ void -mswin_nhbell() +mswin_nhbell(void) { + /* this currently does nothing, but if that ever changes, the setting + of flags.silent should be respected */ logDebug("mswin_nhbell()\n"); } @@ -1461,7 +1522,7 @@ doprev_message() -- On the tty-port this scrolls WIN_MESSAGE back one line. */ int -mswin_doprev_message() +mswin_doprev_message(void) { logDebug("mswin_doprev_message()\n"); SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, @@ -1489,14 +1550,14 @@ char yn_function(const char *ques, const char *choices, char default) ports might use a popup. */ char -mswin_yn_function(const char *question, const char *choices, CHAR_P def) +mswin_yn_function(const char *question, const char *choices, char def) { char ch; char yn_esc_map = '\033'; char message[BUFSZ]; char res_ch[2]; int createcaret; - boolean digit_ok, allow_num; + boolean digit_ok, allow_num = FALSE; logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def); @@ -1520,10 +1581,10 @@ mswin_yn_function(const char *question, const char *choices, CHAR_P def) if (choices) { char *cb, choicebuf[QBUFSZ]; - allow_num = (index(choices, '#') != 0); + allow_num = (strchr(choices, '#') != 0); Strcpy(choicebuf, choices); - if ((cb = index(choicebuf, '\033')) != 0) { + if ((cb = strchr(choicebuf, '\033')) != 0) { /* anything beyond is hidden */ *cb = '\0'; } @@ -1535,7 +1596,7 @@ mswin_yn_function(const char *question, const char *choices, CHAR_P def) Strcat(message, " "); /* escape maps to 'q' or 'n' or default, in that order */ yn_esc_map = - (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); + (strchr(choices, 'q') ? 'q' : (strchr(choices, 'n') ? 'n' : def)); } else { Strcpy(message, question); Strcat(message, " "); @@ -1562,17 +1623,17 @@ mswin_yn_function(const char *question, const char *choices, CHAR_P def) digit_ok = allow_num && digit(ch); if (ch == '\033') { - if (index(choices, 'q')) + if (strchr(choices, 'q')) ch = 'q'; - else if (index(choices, 'n')) + else if (strchr(choices, 'n')) ch = 'n'; else ch = def; break; - } else if (index(quitchars, ch)) { + } else if (strchr(quitchars, ch)) { ch = def; break; - } else if (!index(choices, ch) && !digit_ok) { + } else if (!strchr(choices, ch) && !digit_ok) { mswin_nhbell(); ch = (char) 0; /* and try again... */ @@ -1580,6 +1641,7 @@ mswin_yn_function(const char *question, const char *choices, CHAR_P def) char z, digit_string[2]; int n_len = 0; long value = 0; + mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, ("#"), 1); n_len++; digit_string[1] = '\0'; @@ -1593,13 +1655,16 @@ mswin_yn_function(const char *question, const char *choices, CHAR_P def) do { /* loop until we get a non-digit */ z = lowc(readchar()); if (digit(z)) { - value = (10 * value) + (z - '0'); + long dgt = (long) (z - '0'); + + /* value = (10 * value) + (z - '0'); */ + value = AppendLongDigit(value, dgt); if (value < 0) break; /* overflow: try again */ digit_string[0] = z; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1); n_len++; - } else if (z == 'y' || index(quitchars, z)) { + } else if (z == 'y' || strchr(quitchars, z)) { if (z == '\033') value = -1; /* abort */ z = '\n'; /* break */ @@ -1641,7 +1706,7 @@ mswin_yn_function(const char *question, const char *choices, CHAR_P def) res_ch[1] = '\x0'; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1); } - + nhUse(yn_esc_map); return ch; } @@ -1729,14 +1794,14 @@ int get_ext_cmd(void) selection, -1 otherwise. */ int -mswin_get_ext_cmd() +mswin_get_ext_cmd(void) { + char cmd[BUFSZ]; int ret; logDebug("mswin_get_ext_cmd()\n"); if (!iflags.wc_popup_dialog) { char c; - char cmd[BUFSZ]; int i, len; int createcaret; @@ -1765,7 +1830,8 @@ mswin_get_ext_cmd() break; if (extcmdlist[i].ef_txt == (char *) 0) { - pline("%s: unknown extended command.", cmd); + pline("%s%s: unknown extended command.", + visctrl(extcmd_initiator()), cmd); i = -1; } break; @@ -1806,13 +1872,16 @@ mswin_get_ext_cmd() createcaret = 0; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret); - return i; + ret = i; } else { - if (mswin_ext_cmd_window(&ret) == IDCANCEL) - return -1; + cmd[0] = '\0'; + if (mswin_ext_cmd_window(&ret) != IDCANCEL) + Strcpy(cmd, extcmdlist[ret].ef_txt); else - return ret; + ret = -1; } + + return ret; } /* @@ -1832,7 +1901,7 @@ delay_output() -- Causes a visible delay of 50ms in the output. by a nap(50ms), but allows asynchronous operation. */ void -mswin_delay_output() +mswin_delay_output(void) { logDebug("mswin_delay_output()\n"); mswin_map_update(mswin_hwnd_from_winid(WIN_MAP)); @@ -1840,41 +1909,16 @@ mswin_delay_output() } void -mswin_change_color() +mswin_change_color(int color, long rgb, int reverse) { - logDebug("mswin_change_color()\n"); + logDebug("mswin_change_color(%d, %ld, %d)\n", color, rgb, reverse); } char * -mswin_get_color_string() +mswin_get_color_string(void) { logDebug("mswin_get_color_string()\n"); - return (""); -} - -/* -start_screen() -- Only used on Unix tty ports, but must be declared for - completeness. Sets up the tty to work in full-screen - graphics mode. Look at win/tty/termcap.c for an - example. If your window-port does not need this function - just declare an empty function. -*/ -void -mswin_start_screen() -{ - /* Do Nothing */ - logDebug("mswin_start_screen()\n"); -} - -/* -end_screen() -- Only used on Unix tty ports, but must be declared for - completeness. The complement of start_screen(). -*/ -void -mswin_end_screen() -{ - /* Do Nothing */ - logDebug("mswin_end_screen()\n"); + return (char *) ""; } /* @@ -1898,12 +1942,12 @@ mswin_outrip(winid wid, int how, time_t when) } /* Put name on stone */ - Sprintf(buf, "%s", plname); + Sprintf(buf, "%s", svp.plname); buf[STONE_LINE_LEN] = 0; putstr(wid, 0, buf); /* Put $ on stone */ - Sprintf(buf, "%ld Au", done_money); + Sprintf(buf, "%ld Au", gd.done_money); buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */ putstr(wid, 0, buf); @@ -2040,34 +2084,37 @@ mswin_preference_update(const char *pref) } if (stricmp(pref, "perm_invent") == 0) { - mswin_update_inventory(); + mswin_update_inventory(0); return; } } -#define TEXT_BUFFER_SIZE 4096 +static PMSNHMsgGetText history_text = 0; +static char *next_message = 0; + char * -mswin_getmsghistory(BOOLEAN_P init) +mswin_getmsghistory(boolean init) { - static PMSNHMsgGetText text = 0; - static char *next_message = 0; - if (init) { - text = (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + if (history_text) + free((genericptr_t) history_text), history_text = 0; + history_text = (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE); - text->max_size = - TEXT_BUFFER_SIZE - - 1; /* make sure we always have 0 at the end of the buffer */ + if (history_text) { + history_text->max_size = + TEXT_BUFFER_SIZE + - 1; /* make sure we always have 0 at the end of the buffer */ - ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); - SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, - (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); + ZeroMemory(history_text->buffer, TEXT_BUFFER_SIZE); + SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, + (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) history_text); - next_message = text->buffer; + next_message = history_text->buffer; + } } if (!(next_message && next_message[0])) { - free(text); + free(history_text), history_text = 0; next_message = 0; return (char *) 0; } else { @@ -2084,7 +2131,7 @@ mswin_getmsghistory(BOOLEAN_P init) } void -mswin_putmsghistory(const char *msg, BOOLEAN_P restoring) +mswin_putmsghistory(const char *msg, boolean restoring) { BOOL save_sound_opt; @@ -2102,7 +2149,7 @@ mswin_putmsghistory(const char *msg, BOOLEAN_P restoring) } void -mswin_main_loop() +mswin_main_loop(void) { while (!mswin_have_input()) { MSG msg; @@ -2162,7 +2209,7 @@ initMapTiles(void) char errmsg[BUFSZ]; errcode = GetLastError(); - Sprintf(errmsg, "%s (0x%x).", + Sprintf(errmsg, "%s (0x%lx).", "Cannot load tiles from the file. Reverting back to default", errcode); raw_print(errmsg); @@ -2319,7 +2366,7 @@ logDebug(const char *fmt, ...) /* Reading and writing settings from the registry. */ #define CATEGORYKEY "Software" #define COMPANYKEY "NetHack" -#define PRODUCTKEY "NetHack 3.6.6" +#define PRODUCTKEY "NetHack 5.0.0" #define SETTINGSKEY "Settings" #define MAINSHOWSTATEKEY "MainShowState" #define MAINMINXKEY "MainMinX" @@ -2360,7 +2407,7 @@ logDebug(const char *fmt, ...) #define INTFKEY "Interface" void -mswin_read_reg() +mswin_read_reg(void) { HKEY key; DWORD size; @@ -2368,22 +2415,22 @@ mswin_read_reg() char keystring[MAX_PATH]; int i; COLORREF default_mapcolors[CLR_MAX] = { - RGB(0x55, 0x55, 0x55), /* CLR_BLACK */ - RGB(0xFF, 0x00, 0x00), /* CLR_RED */ - RGB(0x00, 0x80, 0x00), /* CLR_GREEN */ - RGB(0xA5, 0x2A, 0x2A), /* CLR_BROWN */ - RGB(0x00, 0x00, 0xFF), /* CLR_BLUE */ - RGB(0xFF, 0x00, 0xFF), /* CLR_MAGENTA */ - RGB(0x00, 0xFF, 0xFF), /* CLR_CYAN */ - RGB(0xC0, 0xC0, 0xC0), /* CLR_GRAY */ - RGB(0xFF, 0xFF, 0xFF), /* NO_COLOR */ - RGB(0xFF, 0xA5, 0x00), /* CLR_ORANGE */ - RGB(0x00, 0xFF, 0x00), /* CLR_BRIGHT_GREEN */ - RGB(0xFF, 0xFF, 0x00), /* CLR_YELLOW */ - RGB(0x00, 0xC0, 0xFF), /* CLR_BRIGHT_BLUE */ - RGB(0xFF, 0x80, 0xFF), /* CLR_BRIGHT_MAGENTA */ - RGB(0x80, 0xFF, 0xFF), /* CLR_BRIGHT_CYAN */ - RGB(0xFF, 0xFF, 0xFF) /* CLR_WHITE */ + RGB(0x55, 0x55, 0x55), /* CLR_BLACK */ + RGB(0xFF, 0x00, 0x00), /* CLR_RED */ + RGB(0x00, 0x80, 0x00), /* CLR_GREEN */ + RGB(0xA5, 0x2A, 0x2A), /* CLR_BROWN */ + RGB(0x00, 0x00, 0xFF), /* CLR_BLUE */ + RGB(0xFF, 0x00, 0xFF), /* CLR_MAGENTA */ + RGB(0x00, 0xFF, 0xFF), /* CLR_CYAN */ + RGB(0xC0, 0xC0, 0xC0), /* CLR_GRAY */ + RGB(0xFF, 0xFF, 0xFF), /* NO_COLOR */ + RGB(0xFF, 0xA5, 0x00), /* CLR_ORANGE */ + RGB(0x00, 0xFF, 0x00), /* CLR_BRIGHT_GREEN */ + RGB(0xFF, 0xFF, 0x00), /* CLR_YELLOW */ + RGB(0x00, 0xC0, 0xFF), /* CLR_BRIGHT_BLUE */ + RGB(0xFF, 0x80, 0xFF), /* CLR_BRIGHT_MAGENTA */ + RGB(0x80, 0xFF, 0xFF), /* CLR_BRIGHT_CYAN */ + RGB(0xFF, 0xFF, 0xFF) /* CLR_WHITE */ }; sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY, @@ -2472,7 +2519,7 @@ mswin_read_reg() } void -mswin_write_reg() +mswin_write_reg(void) { HKEY key; DWORD disposition; @@ -2487,7 +2534,7 @@ mswin_write_reg() if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_WRITE, &key) != ERROR_SUCCESS) { - RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, "", + RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &disposition); } @@ -2550,7 +2597,7 @@ mswin_write_reg() } void -mswin_destroy_reg() +mswin_destroy_reg(void) { char keystring[MAX_PATH]; HKEY key; @@ -2624,7 +2671,7 @@ static color_table_value color_table[] = { }; typedef struct ctbv { - char *colorstring; + const char *colorstring; int syscolorvalue; } color_table_brush_value; @@ -2659,7 +2706,7 @@ mswin_color_from_string(char *colorstring, HBRUSH *brushptr, color_table_value *ctv_ptr = color_table; color_table_brush_value *ctbv_ptr = color_table_brush; int red_value, blue_value, green_value; - static char *hexadecimals = "0123456789abcdef"; + static const char *hexadecimals = "0123456789abcdef"; if (colorstring == NULL) return; @@ -2667,31 +2714,33 @@ mswin_color_from_string(char *colorstring, HBRUSH *brushptr, if (strlen(++colorstring) != 6) return; - red_value = (int) (index(hexadecimals, tolower((uchar) *colorstring)) + red_value = (int) (strchr(hexadecimals, tolower((uchar) *colorstring)) - hexadecimals); ++colorstring; red_value *= 16; - red_value += (int) (index(hexadecimals, tolower((uchar) *colorstring)) - - hexadecimals); + red_value += + (int) (strchr(hexadecimals, tolower((uchar) *colorstring)) + - hexadecimals); ++colorstring; - green_value = (int) (index(hexadecimals, - tolower((uchar) *colorstring)) - - hexadecimals); + green_value = + (int) (strchr(hexadecimals, tolower((uchar) *colorstring)) + - hexadecimals); ++colorstring; green_value *= 16; - green_value += (int) (index(hexadecimals, - tolower((uchar) *colorstring)) - - hexadecimals); + green_value += + (int) (strchr(hexadecimals, tolower((uchar) *colorstring)) + - hexadecimals); ++colorstring; - blue_value = (int) (index(hexadecimals, tolower((uchar) *colorstring)) - - hexadecimals); + blue_value = + (int) (strchr(hexadecimals, tolower((uchar) *colorstring)) + - hexadecimals); ++colorstring; blue_value *= 16; - blue_value += (int) (index(hexadecimals, - tolower((uchar) *colorstring)) - - hexadecimals); + blue_value += + (int) (strchr(hexadecimals, tolower((uchar) *colorstring)) + - hexadecimals); ++colorstring; *colorptr = RGB(red_value, green_value, blue_value); @@ -2714,7 +2763,10 @@ mswin_color_from_string(char *colorstring, HBRUSH *brushptr, if (max_brush > TOTAL_BRUSHES) panic("Too many colors!"); *brushptr = CreateSolidBrush(*colorptr); - brush_table[max_brush++] = *brushptr; + if (IndexOk(max_brush, brush_table)) { + brush_table[max_brush] = *brushptr; + max_brush++; + } } void @@ -2791,6 +2843,8 @@ int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type) { TCHAR title[MAX_LOADSTRING]; + if (program_state.exiting && !strcmp(text, "\n")) + text = "Press Enter to exit"; LoadString(GetNHApp()->hApp, IDS_APP_TITLE_SHORT, title, MAX_LOADSTRING); @@ -2799,26 +2853,42 @@ NHMessageBox(HWND hWnd, LPCTSTR text, UINT type) static mswin_status_lines _status_lines; static mswin_status_string _status_strings[MAXBLSTATS]; -static mswin_status_string _condition_strings[BL_MASK_BITS]; +static mswin_status_string _condition_strings[CONDITION_COUNT]; static mswin_status_field _status_fields[MAXBLSTATS]; -static mswin_condition_field _condition_fields[BL_MASK_BITS] = { - { BL_MASK_STONE, "Stone" }, - { BL_MASK_SLIME, "Slime" }, - { BL_MASK_STRNGL, "Strngl" }, - { BL_MASK_FOODPOIS, "FoodPois" }, - { BL_MASK_TERMILL, "TermIll" }, - { BL_MASK_BLIND, "Blind" }, - { BL_MASK_DEAF, "Deaf" }, - { BL_MASK_STUN, "Stun" }, - { BL_MASK_CONF, "Conf" }, - { BL_MASK_HALLU, "Hallu" }, - { BL_MASK_LEV, "Lev" }, - { BL_MASK_FLY, "Fly" }, - { BL_MASK_RIDE, "Ride" } +static mswin_condition_field _condition_fields[CONDITION_COUNT] = { + { BL_MASK_BAREH, "Bare", 0}, + { BL_MASK_BLIND, "Blind", 0 }, + { BL_MASK_BUSY, "Busy", 0 }, + { BL_MASK_CONF, "Conf", 0 }, + { BL_MASK_DEAF, "Deaf", 0 }, + { BL_MASK_ELF_IRON, "Iron", 0 }, + { BL_MASK_FLY, "Fly", 0 }, + { BL_MASK_FOODPOIS, "FoodPois", 0 }, + { BL_MASK_GLOWHANDS, "Glow", 0 }, + { BL_MASK_GRAB, "Grab", 0 }, + { BL_MASK_HALLU, "Hallu", 0 }, + { BL_MASK_HELD, "Held", 0 }, + { BL_MASK_ICY, "Icy", 0 }, + { BL_MASK_INLAVA, "Lava", 0 }, + { BL_MASK_LEV, "Lev", 0 }, + { BL_MASK_PARLYZ, "Parlyz", 0 }, + { BL_MASK_RIDE, "Ride", 0 }, + { BL_MASK_SLEEPING, "Zzz", 0 }, + { BL_MASK_SLIME, "Slime", 0 }, + { BL_MASK_SLIPPERY, "Slip", 0 }, + { BL_MASK_STONE, "Stone", 0 }, + { BL_MASK_STRNGL, "Strngl", 0 }, + { BL_MASK_STUN, "Stun", 0 }, + { BL_MASK_SUBMERGED, "Sub", 0 }, + { BL_MASK_TERMILL, "TermIll", 0 }, + { BL_MASK_TETHERED, "Teth", 0 }, + { BL_MASK_TRAPPED, "Trap", 0 }, + { BL_MASK_UNCONSC, "Out", 0 }, + { BL_MASK_WOUNDEDL, "Legs", 0 }, + { BL_MASK_HOLDING, "Uhold", 0 }, }; - extern winid WIN_STATUS; #ifdef STATUS_HILITES @@ -2840,6 +2910,7 @@ void mswin_status_init(void) { logDebug("mswin_status_init()\n"); + int ci; for (int i = 0; i < SIZE(_status_fields); i++) { mswin_status_field * status_field = &_status_fields[i]; @@ -2848,9 +2919,10 @@ mswin_status_init(void) } for (int i = 0; i < SIZE(_condition_fields); i++) { - mswin_condition_field * condition_field = &_condition_fields[i]; - nhassert(condition_field->mask == (1 << i)); - condition_field->bit_position = i; + ci = cond_idx[i]; + mswin_condition_field * condition_field = &_condition_fields[ci]; + nhassert(condition_field->mask == (1 << ci)); + condition_field->bit_position = ci; } for (int i = 0; i < SIZE(_status_strings); i++) { @@ -2859,7 +2931,8 @@ mswin_status_init(void) } for (int i = 0; i < SIZE(_condition_strings); i++) { - mswin_status_string * status_string = &_condition_strings[i]; + ci = cond_idx[i]; + mswin_status_string * status_string = &_condition_strings[ci]; status_string->str = NULL; } @@ -2884,10 +2957,11 @@ mswin_status_init(void) &_status_strings[field_index]; if (field_index == BL_CONDITION) { - for (int j = 0; j < BL_MASK_BITS; j++) { + for (int j = 0; j < CONDITION_COUNT; j++) { + ci = cond_idx[j]; nhassert(status_strings->count <= SIZE(status_strings->status_strings)); status_strings->status_strings[status_strings->count++] = - &_condition_strings[j]; + &_condition_strings[ci]; } } } @@ -2961,11 +3035,9 @@ mswin_status_enablefield(int fieldidx, const char *nm, const char *fmt, } } -/* TODO: turn this into a commmon helper; multiple identical implementations */ +/* TODO: turn this into a common helper; multiple identical implementations */ static int -mswin_condcolor(bm, bmarray) -long bm; -unsigned long *bmarray; +mswin_condcolor(long bm, unsigned long *bmarray) { int i; @@ -2978,16 +3050,15 @@ unsigned long *bmarray; } static int -mswin_condattr(bm, bmarray) -long bm; -unsigned long *bmarray; +mswin_condattr(long bm, unsigned long *bmarray) { if (bm && bmarray) { - if (bm & bmarray[HL_ATTCLR_DIM]) return HL_DIM; - if (bm & bmarray[HL_ATTCLR_BLINK]) return HL_BLINK; - if (bm & bmarray[HL_ATTCLR_ULINE]) return HL_ULINE; + if (bm & bmarray[HL_ATTCLR_BOLD]) return HL_BOLD; + if (bm & bmarray[HL_ATTCLR_DIM]) return HL_DIM; + if (bm & bmarray[HL_ATTCLR_ITALIC]) return HL_ITALIC; + if (bm & bmarray[HL_ATTCLR_ULINE]) return HL_ULINE; + if (bm & bmarray[HL_ATTCLR_BLINK]) return HL_BLINK; if (bm & bmarray[HL_ATTCLR_INVERSE]) return HL_INVERSE; - if (bm & bmarray[HL_ATTCLR_BOLD]) return HL_BOLD; } return HL_NONE; @@ -3004,14 +3075,14 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percent, int color, u 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 - -- fldindex could also be BL_FLUSH, which is not really - a field index, but is a special trigger to tell the - windowport that it should output all changes received + -- fldindex could also be BL_FLUSH, which is not really + a field index, but is a special trigger to tell the + windowport that it should output all changes received to this point. It marks the end of a bot() cycle. - -- fldindex could also be BL_RESET, which is not really - a field index, but is a special advisory to to tell the - windowport that it should redisplay all its status fields, - even if no changes have been presented to it. + -- fldindex could also be BL_RESET, which is not really + a field index, but is a special advisory to tell the + windowport that it should redisplay all its status fields, + even if no changes have been presented to it. -- 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): @@ -3036,18 +3107,22 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percent, int color, u use to display the text. -- condmasks is a pointer to a set of BL_ATTCLR_MAX unsigned longs telling which conditions should be displayed in each - color and attriubte. + color and attribute. */ + +DISABLE_WARNING_FORMAT_NONLITERAL + void -mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, unsigned long *condmasks) +mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, + int color, unsigned long *condmasks) { long cond, *condptr = (long *) ptr; char *text = (char *) ptr; MSNHMsgUpdateStatus update_cmd_data; - int ocolor, ochar; - unsigned ospecial; + int ochar, ci; - logDebug("mswin_status_update(%d, %p, %d, %d, %x, %p)\n", idx, ptr, chg, percent, color, condmasks); + logDebug("mswin_status_update(%d, %p, %d, %d, %x, %p)\n", + idx, ptr, chg, percent, color, condmasks); if (idx >= 0) { @@ -3068,14 +3143,16 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, switch (idx) { case BL_CONDITION: { - mswin_condition_field * condition_field = _condition_fields; + mswin_condition_field * condition_field; nhassert(status_string->str == NULL); cond = *condptr; - for (int i = 0; i < BL_MASK_BITS; i++, condition_field++) { - status_string = &_condition_strings[i]; + for (int i = 0; i < CONDITION_COUNT; i++) { + ci = cond_idx[i]; + condition_field = &_condition_fields[ci]; + status_string = &_condition_strings[ci]; if (condition_field->mask & cond) { status_string->str = condition_field->name; @@ -3095,8 +3172,7 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, if (iflags.invis_goldsym) ochar = GOLD_SYM; else - mapglyph(objnum_to_glyph(GOLD_PIECE), - &ochar, &ocolor, &ospecial, 0, 0, 0); + ochar = glyph2ttychar(objnum_to_glyph(GOLD_PIECE)); buf[0] = ochar; p = strchr(text, ':'); if (p) { @@ -3139,3 +3215,5 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, } } +RESTORE_WARNING_FORMAT_NONLITERAL + diff --git a/win/win32/nethack.rc b/win/win32/nethack.rc index 95e8d0cdb..4c167d047 100644 --- a/win/win32/nethack.rc +++ b/win/win32/nethack.rc @@ -60,8 +60,8 @@ IDI_ICON1 ICON "nethack.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,6,7,0 - PRODUCTVERSION 3,6,7,0 + FILEVERSION 5,0,0,0 + PRODUCTVERSION 5,0,0,0 FILEFLAGSMASK 0x1fL #ifdef _DEBUG FILEFLAGS 0x9L @@ -77,12 +77,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "NetHack for Windows - TTY Interface" - VALUE "FileVersion", "3.6.7" + VALUE "FileVersion", "5.0.0" VALUE "InternalName", "NetHack" - VALUE "LegalCopyright", "Copyright (C) 1985 - 2023. By Stichting Mathematisch Centrum and M. Stephenson. See license for details." + VALUE "LegalCopyright", "Copyright (C) 1985 - 2026. By Stichting Mathematisch Centrum and M. Stephenson. See license for details." VALUE "OriginalFilename", "NetHack.exe" VALUE "ProductName", "NetHack" - VALUE "ProductVersion", "3.6.7" + VALUE "ProductVersion", "5.0.0" END END BLOCK "VarFileInfo" diff --git a/win/win32/vs2017/.gitattributes b/win/win32/vs2017/.gitattributes deleted file mode 100644 index 041653ea8..000000000 --- a/win/win32/vs2017/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* NH_filestag=(file%s_for_Visual_Studio_2017_Community_Edition_builds) diff --git a/win/win32/vs2017/.gitignore b/win/win32/vs2017/.gitignore deleted file mode 100644 index c4775b3c5..000000000 --- a/win/win32/vs2017/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -!NetHack.sln -*.db-shm -*.db-wal -paniclog -_pkginfo.txt -AppPackages -BundleArtifacts -report.xml -*.cer -*.appxbundle -NetHackPackage_StoreKey.pfx -NetHackPackage_TemporaryKey.pfx diff --git a/win/win32/vs2017/Images/BadgeLogo.scale-100.png b/win/win32/vs2017/Images/BadgeLogo.scale-100.png deleted file mode 100644 index 0c1dff1b4..000000000 Binary files a/win/win32/vs2017/Images/BadgeLogo.scale-100.png and /dev/null differ diff --git a/win/win32/vs2017/Images/BadgeLogo.scale-125.png b/win/win32/vs2017/Images/BadgeLogo.scale-125.png deleted file mode 100644 index 45aa7773c..000000000 Binary files a/win/win32/vs2017/Images/BadgeLogo.scale-125.png and /dev/null differ diff --git a/win/win32/vs2017/Images/BadgeLogo.scale-150.png b/win/win32/vs2017/Images/BadgeLogo.scale-150.png deleted file mode 100644 index 6a911cb2a..000000000 Binary files a/win/win32/vs2017/Images/BadgeLogo.scale-150.png and /dev/null differ diff --git a/win/win32/vs2017/Images/BadgeLogo.scale-200.png b/win/win32/vs2017/Images/BadgeLogo.scale-200.png deleted file mode 100644 index 21e20fb67..000000000 Binary files a/win/win32/vs2017/Images/BadgeLogo.scale-200.png and /dev/null differ diff --git a/win/win32/vs2017/Images/BadgeLogo.scale-400.png b/win/win32/vs2017/Images/BadgeLogo.scale-400.png deleted file mode 100644 index 10fdb8f1e..000000000 Binary files a/win/win32/vs2017/Images/BadgeLogo.scale-400.png and /dev/null differ diff --git a/win/win32/vs2017/Images/LargeTile.scale-100.png b/win/win32/vs2017/Images/LargeTile.scale-100.png deleted file mode 100644 index 2c00fc94e..000000000 Binary files a/win/win32/vs2017/Images/LargeTile.scale-100.png and /dev/null differ diff --git a/win/win32/vs2017/Images/LargeTile.scale-125.png b/win/win32/vs2017/Images/LargeTile.scale-125.png deleted file mode 100644 index fb1ba8d8e..000000000 Binary files a/win/win32/vs2017/Images/LargeTile.scale-125.png and /dev/null differ diff --git a/win/win32/vs2017/Images/LargeTile.scale-150.png b/win/win32/vs2017/Images/LargeTile.scale-150.png deleted file mode 100644 index f3ccd1107..000000000 Binary files a/win/win32/vs2017/Images/LargeTile.scale-150.png and /dev/null differ diff --git a/win/win32/vs2017/Images/LargeTile.scale-200.png b/win/win32/vs2017/Images/LargeTile.scale-200.png deleted file mode 100644 index 0c40a8a72..000000000 Binary files a/win/win32/vs2017/Images/LargeTile.scale-200.png and /dev/null differ diff --git a/win/win32/vs2017/Images/LargeTile.scale-400.png b/win/win32/vs2017/Images/LargeTile.scale-400.png deleted file mode 100644 index 5c11c508b..000000000 Binary files a/win/win32/vs2017/Images/LargeTile.scale-400.png and /dev/null differ diff --git a/win/win32/vs2017/Images/LockScreenLogo.scale-200.png b/win/win32/vs2017/Images/LockScreenLogo.scale-200.png deleted file mode 100644 index 735f57adb..000000000 Binary files a/win/win32/vs2017/Images/LockScreenLogo.scale-200.png and /dev/null differ diff --git a/win/win32/vs2017/Images/SmallTile.scale-100.png b/win/win32/vs2017/Images/SmallTile.scale-100.png deleted file mode 100644 index f7e719d06..000000000 Binary files a/win/win32/vs2017/Images/SmallTile.scale-100.png and /dev/null differ diff --git a/win/win32/vs2017/Images/SmallTile.scale-125.png b/win/win32/vs2017/Images/SmallTile.scale-125.png deleted file mode 100644 index e5aa2ea1b..000000000 Binary files a/win/win32/vs2017/Images/SmallTile.scale-125.png and /dev/null differ diff --git a/win/win32/vs2017/Images/SmallTile.scale-150.png b/win/win32/vs2017/Images/SmallTile.scale-150.png deleted file mode 100644 index 57d16d648..000000000 Binary files a/win/win32/vs2017/Images/SmallTile.scale-150.png and /dev/null differ diff --git a/win/win32/vs2017/Images/SmallTile.scale-200.png b/win/win32/vs2017/Images/SmallTile.scale-200.png deleted file mode 100644 index 5e5e0ece8..000000000 Binary files a/win/win32/vs2017/Images/SmallTile.scale-200.png and /dev/null differ diff --git a/win/win32/vs2017/Images/SmallTile.scale-400.png b/win/win32/vs2017/Images/SmallTile.scale-400.png deleted file mode 100644 index 3ed4e6994..000000000 Binary files a/win/win32/vs2017/Images/SmallTile.scale-400.png and /dev/null differ diff --git a/win/win32/vs2017/Images/SplashScreen.scale-100.png b/win/win32/vs2017/Images/SplashScreen.scale-100.png deleted file mode 100644 index d4bab84e3..000000000 Binary files a/win/win32/vs2017/Images/SplashScreen.scale-100.png and /dev/null differ diff --git a/win/win32/vs2017/Images/SplashScreen.scale-125.png b/win/win32/vs2017/Images/SplashScreen.scale-125.png deleted file mode 100644 index d97a15fc2..000000000 Binary files a/win/win32/vs2017/Images/SplashScreen.scale-125.png and /dev/null differ diff --git a/win/win32/vs2017/Images/SplashScreen.scale-150.png b/win/win32/vs2017/Images/SplashScreen.scale-150.png deleted file mode 100644 index 2ce132a50..000000000 Binary files a/win/win32/vs2017/Images/SplashScreen.scale-150.png and /dev/null differ diff --git a/win/win32/vs2017/Images/SplashScreen.scale-200.png b/win/win32/vs2017/Images/SplashScreen.scale-200.png deleted file mode 100644 index cbffd4a6a..000000000 Binary files a/win/win32/vs2017/Images/SplashScreen.scale-200.png and /dev/null differ diff --git a/win/win32/vs2017/Images/SplashScreen.scale-400.png b/win/win32/vs2017/Images/SplashScreen.scale-400.png deleted file mode 100644 index 05424b307..000000000 Binary files a/win/win32/vs2017/Images/SplashScreen.scale-400.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square150x150Logo.scale-100.png b/win/win32/vs2017/Images/Square150x150Logo.scale-100.png deleted file mode 100644 index 778506203..000000000 Binary files a/win/win32/vs2017/Images/Square150x150Logo.scale-100.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square150x150Logo.scale-125.png b/win/win32/vs2017/Images/Square150x150Logo.scale-125.png deleted file mode 100644 index 6c625595e..000000000 Binary files a/win/win32/vs2017/Images/Square150x150Logo.scale-125.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square150x150Logo.scale-150.png b/win/win32/vs2017/Images/Square150x150Logo.scale-150.png deleted file mode 100644 index d0471de30..000000000 Binary files a/win/win32/vs2017/Images/Square150x150Logo.scale-150.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square150x150Logo.scale-200.png b/win/win32/vs2017/Images/Square150x150Logo.scale-200.png deleted file mode 100644 index 105037a99..000000000 Binary files a/win/win32/vs2017/Images/Square150x150Logo.scale-200.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square150x150Logo.scale-400.png b/win/win32/vs2017/Images/Square150x150Logo.scale-400.png deleted file mode 100644 index 3b5c7146b..000000000 Binary files a/win/win32/vs2017/Images/Square150x150Logo.scale-400.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-16.png b/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-16.png deleted file mode 100644 index c37bb5650..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-16.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-256.png b/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-256.png deleted file mode 100644 index c5a031ec3..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-256.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-32.png b/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-32.png deleted file mode 100644 index 33651c0e2..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-32.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-48.png b/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-48.png deleted file mode 100644 index 3be7763d0..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-48.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.scale-100.png b/win/win32/vs2017/Images/Square44x44Logo.scale-100.png deleted file mode 100644 index b0b2e6cfd..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.scale-100.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.scale-125.png b/win/win32/vs2017/Images/Square44x44Logo.scale-125.png deleted file mode 100644 index 7497e6315..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.scale-125.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.scale-150.png b/win/win32/vs2017/Images/Square44x44Logo.scale-150.png deleted file mode 100644 index d8291fea8..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.scale-150.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.scale-200.png b/win/win32/vs2017/Images/Square44x44Logo.scale-200.png deleted file mode 100644 index aa5dce320..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.scale-200.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.scale-400.png b/win/win32/vs2017/Images/Square44x44Logo.scale-400.png deleted file mode 100644 index ec0fa86b7..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.scale-400.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-16.png b/win/win32/vs2017/Images/Square44x44Logo.targetsize-16.png deleted file mode 100644 index c2f20ed08..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.targetsize-16.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-24.png b/win/win32/vs2017/Images/Square44x44Logo.targetsize-24.png deleted file mode 100644 index 87a34d0aa..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.targetsize-24.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-24_altform-unplated.png b/win/win32/vs2017/Images/Square44x44Logo.targetsize-24_altform-unplated.png deleted file mode 100644 index 1e2c78548..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.targetsize-24_altform-unplated.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-256.png b/win/win32/vs2017/Images/Square44x44Logo.targetsize-256.png deleted file mode 100644 index d7793c819..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.targetsize-256.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-32.png b/win/win32/vs2017/Images/Square44x44Logo.targetsize-32.png deleted file mode 100644 index 089f3635f..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.targetsize-32.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-48.png b/win/win32/vs2017/Images/Square44x44Logo.targetsize-48.png deleted file mode 100644 index fcd6b9b25..000000000 Binary files a/win/win32/vs2017/Images/Square44x44Logo.targetsize-48.png and /dev/null differ diff --git a/win/win32/vs2017/Images/StoreLogo.backup.png b/win/win32/vs2017/Images/StoreLogo.backup.png deleted file mode 100644 index a90d0b6cd..000000000 Binary files a/win/win32/vs2017/Images/StoreLogo.backup.png and /dev/null differ diff --git a/win/win32/vs2017/Images/StoreLogo.scale-100.png b/win/win32/vs2017/Images/StoreLogo.scale-100.png deleted file mode 100644 index 7eda4fa47..000000000 Binary files a/win/win32/vs2017/Images/StoreLogo.scale-100.png and /dev/null differ diff --git a/win/win32/vs2017/Images/StoreLogo.scale-125.png b/win/win32/vs2017/Images/StoreLogo.scale-125.png deleted file mode 100644 index c1a3b87e2..000000000 Binary files a/win/win32/vs2017/Images/StoreLogo.scale-125.png and /dev/null differ diff --git a/win/win32/vs2017/Images/StoreLogo.scale-150.png b/win/win32/vs2017/Images/StoreLogo.scale-150.png deleted file mode 100644 index 09163a158..000000000 Binary files a/win/win32/vs2017/Images/StoreLogo.scale-150.png and /dev/null differ diff --git a/win/win32/vs2017/Images/StoreLogo.scale-200.png b/win/win32/vs2017/Images/StoreLogo.scale-200.png deleted file mode 100644 index 854fafb9b..000000000 Binary files a/win/win32/vs2017/Images/StoreLogo.scale-200.png and /dev/null differ diff --git a/win/win32/vs2017/Images/StoreLogo.scale-400.png b/win/win32/vs2017/Images/StoreLogo.scale-400.png deleted file mode 100644 index 9d4176160..000000000 Binary files a/win/win32/vs2017/Images/StoreLogo.scale-400.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Wide310x150Logo.scale-100.png b/win/win32/vs2017/Images/Wide310x150Logo.scale-100.png deleted file mode 100644 index 3a29f0911..000000000 Binary files a/win/win32/vs2017/Images/Wide310x150Logo.scale-100.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Wide310x150Logo.scale-125.png b/win/win32/vs2017/Images/Wide310x150Logo.scale-125.png deleted file mode 100644 index 5bde11842..000000000 Binary files a/win/win32/vs2017/Images/Wide310x150Logo.scale-125.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Wide310x150Logo.scale-150.png b/win/win32/vs2017/Images/Wide310x150Logo.scale-150.png deleted file mode 100644 index 8f35b96b8..000000000 Binary files a/win/win32/vs2017/Images/Wide310x150Logo.scale-150.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Wide310x150Logo.scale-200.png b/win/win32/vs2017/Images/Wide310x150Logo.scale-200.png deleted file mode 100644 index a0be94e1a..000000000 Binary files a/win/win32/vs2017/Images/Wide310x150Logo.scale-200.png and /dev/null differ diff --git a/win/win32/vs2017/Images/Wide310x150Logo.scale-400.png b/win/win32/vs2017/Images/Wide310x150Logo.scale-400.png deleted file mode 100644 index cbffd4a6a..000000000 Binary files a/win/win32/vs2017/Images/Wide310x150Logo.scale-400.png and /dev/null differ diff --git a/win/win32/vs2017/NetHack.sln b/win/win32/vs2017/NetHack.sln deleted file mode 100644 index aa2bb7562..000000000 --- a/win/win32/vs2017/NetHack.sln +++ /dev/null @@ -1,189 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26730.12 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetHackW", "NetHackW.vcxproj", "{CEC5D360-8804-454F-8591-002184C23499}" - ProjectSection(ProjectDependencies) = postProject - {93F10526-209E-41D7-BBEA-775787876895} = {93F10526-209E-41D7-BBEA-775787876895} - {63F9B82B-F589-4082-ABE5-D4F0682050AB} = {63F9B82B-F589-4082-ABE5-D4F0682050AB} - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} = {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} - {BA3DD34C-04B7-40D0-B373-9329AA9E8945} = {BA3DD34C-04B7-40D0-B373-9329AA9E8945} - {642BC75D-ABAF-403E-8224-7C725FD4CB42} = {642BC75D-ABAF-403E-8224-7C725FD4CB42} - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC} = {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC} - {8A3F81C7-2968-49A8-86BF-2669412AD7DE} = {8A3F81C7-2968-49A8-86BF-2669412AD7DE} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dgncomp", "dgncomp.vcxproj", "{8A3F81C7-2968-49A8-86BF-2669412AD7DE}" - ProjectSection(ProjectDependencies) = postProject - {642BC75D-ABAF-403E-8224-7C725FD4CB42} = {642BC75D-ABAF-403E-8224-7C725FD4CB42} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dlb", "dlb.vcxproj", "{0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}" - ProjectSection(ProjectDependencies) = postProject - {63F9B82B-F589-4082-ABE5-D4F0682050AB} = {63F9B82B-F589-4082-ABE5-D4F0682050AB} - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} = {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} - {BA3DD34C-04B7-40D0-B373-9329AA9E8945} = {BA3DD34C-04B7-40D0-B373-9329AA9E8945} - {8A3F81C7-2968-49A8-86BF-2669412AD7DE} = {8A3F81C7-2968-49A8-86BF-2669412AD7DE} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "levcomp", "levcomp.vcxproj", "{9DD9C52E-E8C9-4533-BD22-83C055C0AABA}" - ProjectSection(ProjectDependencies) = postProject - {BA3DD34C-04B7-40D0-B373-9329AA9E8945} = {BA3DD34C-04B7-40D0-B373-9329AA9E8945} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "makedefs", "makedefs.vcxproj", "{BA3DD34C-04B7-40D0-B373-9329AA9E8945}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "recover", "recover.vcxproj", "{2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tile2bmp", "tile2bmp.vcxproj", "{642BC75D-ABAF-403E-8224-7C725FD4CB42}" - ProjectSection(ProjectDependencies) = postProject - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} = {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} - {BA3DD34C-04B7-40D0-B373-9329AA9E8945} = {BA3DD34C-04B7-40D0-B373-9329AA9E8945} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tilemap", "tilemap.vcxproj", "{93F10526-209E-41D7-BBEA-775787876895}" - ProjectSection(ProjectDependencies) = postProject - {8A3F81C7-2968-49A8-86BF-2669412AD7DE} = {8A3F81C7-2968-49A8-86BF-2669412AD7DE} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uudecode", "uudecode.vcxproj", "{63F9B82B-F589-4082-ABE5-D4F0682050AB}" - ProjectSection(ProjectDependencies) = postProject - {BA3DD34C-04B7-40D0-B373-9329AA9E8945} = {BA3DD34C-04B7-40D0-B373-9329AA9E8945} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetHack", "NetHack.vcxproj", "{609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}" - ProjectSection(ProjectDependencies) = postProject - {93F10526-209E-41D7-BBEA-775787876895} = {93F10526-209E-41D7-BBEA-775787876895} - {63F9B82B-F589-4082-ABE5-D4F0682050AB} = {63F9B82B-F589-4082-ABE5-D4F0682050AB} - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} = {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} - {BA3DD34C-04B7-40D0-B373-9329AA9E8945} = {BA3DD34C-04B7-40D0-B373-9329AA9E8945} - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC} = {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC} - {8A3F81C7-2968-49A8-86BF-2669412AD7DE} = {8A3F81C7-2968-49A8-86BF-2669412AD7DE} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDCurses", "PDCurses.vcxproj", "{BAA70D0F-3EC7-4D10-91F0-974F1F49308B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{477BF231-48E0-4312-AA12-9D8576215489}" - ProjectSection(SolutionItems) = preProject - NetHackProperties.props = NetHackProperties.props - EndProjectSection -EndProject -Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "NetHackPackage", "NetHackPackage.wapproj", "{6838EC9D-F25D-4779-9CD7-2EDB61E49429}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CEC5D360-8804-454F-8591-002184C23499}.Debug|Win32.ActiveCfg = Debug|Win32 - {CEC5D360-8804-454F-8591-002184C23499}.Debug|Win32.Build.0 = Debug|Win32 - {CEC5D360-8804-454F-8591-002184C23499}.Debug|x64.ActiveCfg = Debug|x64 - {CEC5D360-8804-454F-8591-002184C23499}.Debug|x64.Build.0 = Debug|x64 - {CEC5D360-8804-454F-8591-002184C23499}.Release|Win32.ActiveCfg = Release|Win32 - {CEC5D360-8804-454F-8591-002184C23499}.Release|Win32.Build.0 = Release|Win32 - {CEC5D360-8804-454F-8591-002184C23499}.Release|x64.ActiveCfg = Release|x64 - {CEC5D360-8804-454F-8591-002184C23499}.Release|x64.Build.0 = Release|x64 - {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Debug|Win32.ActiveCfg = Debug|Win32 - {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Debug|Win32.Build.0 = Debug|Win32 - {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Debug|x64.ActiveCfg = Debug|x64 - {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Debug|x64.Build.0 = Debug|x64 - {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Release|Win32.ActiveCfg = Release|Win32 - {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Release|Win32.Build.0 = Release|Win32 - {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Release|x64.ActiveCfg = Release|x64 - {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Release|x64.Build.0 = Release|x64 - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Debug|Win32.ActiveCfg = Debug|Win32 - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Debug|Win32.Build.0 = Debug|Win32 - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Debug|x64.ActiveCfg = Debug|x64 - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Debug|x64.Build.0 = Debug|x64 - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Release|Win32.ActiveCfg = Release|Win32 - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Release|Win32.Build.0 = Release|Win32 - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Release|x64.ActiveCfg = Release|x64 - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Release|x64.Build.0 = Release|x64 - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Debug|Win32.ActiveCfg = Debug|Win32 - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Debug|Win32.Build.0 = Debug|Win32 - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Debug|x64.ActiveCfg = Debug|x64 - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Debug|x64.Build.0 = Debug|x64 - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Release|Win32.ActiveCfg = Release|Win32 - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Release|Win32.Build.0 = Release|Win32 - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Release|x64.ActiveCfg = Release|x64 - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Release|x64.Build.0 = Release|x64 - {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Debug|Win32.ActiveCfg = Debug|Win32 - {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Debug|Win32.Build.0 = Debug|Win32 - {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Debug|x64.ActiveCfg = Debug|x64 - {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Debug|x64.Build.0 = Debug|x64 - {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Release|Win32.ActiveCfg = Release|Win32 - {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Release|Win32.Build.0 = Release|Win32 - {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Release|x64.ActiveCfg = Release|x64 - {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Release|x64.Build.0 = Release|x64 - {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Debug|Win32.ActiveCfg = Debug|Win32 - {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Debug|Win32.Build.0 = Debug|Win32 - {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Debug|x64.ActiveCfg = Debug|x64 - {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Debug|x64.Build.0 = Debug|x64 - {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Release|Win32.ActiveCfg = Release|Win32 - {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Release|Win32.Build.0 = Release|Win32 - {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Release|x64.ActiveCfg = Release|x64 - {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Release|x64.Build.0 = Release|x64 - {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Debug|Win32.ActiveCfg = Debug|Win32 - {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Debug|Win32.Build.0 = Debug|Win32 - {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Debug|x64.ActiveCfg = Debug|x64 - {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Debug|x64.Build.0 = Debug|x64 - {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Release|Win32.ActiveCfg = Release|Win32 - {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Release|Win32.Build.0 = Release|Win32 - {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Release|x64.ActiveCfg = Release|x64 - {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Release|x64.Build.0 = Release|x64 - {93F10526-209E-41D7-BBEA-775787876895}.Debug|Win32.ActiveCfg = Debug|Win32 - {93F10526-209E-41D7-BBEA-775787876895}.Debug|Win32.Build.0 = Debug|Win32 - {93F10526-209E-41D7-BBEA-775787876895}.Debug|x64.ActiveCfg = Debug|x64 - {93F10526-209E-41D7-BBEA-775787876895}.Debug|x64.Build.0 = Debug|x64 - {93F10526-209E-41D7-BBEA-775787876895}.Release|Win32.ActiveCfg = Release|Win32 - {93F10526-209E-41D7-BBEA-775787876895}.Release|Win32.Build.0 = Release|Win32 - {93F10526-209E-41D7-BBEA-775787876895}.Release|x64.ActiveCfg = Release|x64 - {93F10526-209E-41D7-BBEA-775787876895}.Release|x64.Build.0 = Release|x64 - {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Debug|Win32.ActiveCfg = Debug|Win32 - {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Debug|Win32.Build.0 = Debug|Win32 - {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Debug|x64.ActiveCfg = Debug|x64 - {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Debug|x64.Build.0 = Debug|x64 - {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Release|Win32.ActiveCfg = Release|Win32 - {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Release|Win32.Build.0 = Release|Win32 - {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Release|x64.ActiveCfg = Release|x64 - {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Release|x64.Build.0 = Release|x64 - {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Debug|Win32.ActiveCfg = Debug|Win32 - {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Debug|Win32.Build.0 = Debug|Win32 - {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Debug|x64.ActiveCfg = Debug|x64 - {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Debug|x64.Build.0 = Debug|x64 - {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Release|Win32.ActiveCfg = Release|Win32 - {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Release|Win32.Build.0 = Release|Win32 - {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Release|x64.ActiveCfg = Release|x64 - {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Release|x64.Build.0 = Release|x64 - {BAA70D0F-3EC7-4D10-91F0-974F1F49308B}.Debug|Win32.ActiveCfg = Debug|Win32 - {BAA70D0F-3EC7-4D10-91F0-974F1F49308B}.Debug|Win32.Build.0 = Debug|Win32 - {BAA70D0F-3EC7-4D10-91F0-974F1F49308B}.Debug|x64.ActiveCfg = Debug|x64 - {BAA70D0F-3EC7-4D10-91F0-974F1F49308B}.Debug|x64.Build.0 = Debug|x64 - {BAA70D0F-3EC7-4D10-91F0-974F1F49308B}.Release|Win32.ActiveCfg = Release|Win32 - {BAA70D0F-3EC7-4D10-91F0-974F1F49308B}.Release|Win32.Build.0 = Release|Win32 - {BAA70D0F-3EC7-4D10-91F0-974F1F49308B}.Release|x64.ActiveCfg = Release|x64 - {BAA70D0F-3EC7-4D10-91F0-974F1F49308B}.Release|x64.Build.0 = Release|x64 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Debug|Win32.ActiveCfg = Debug|Win32 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Debug|Win32.Build.0 = Debug|Win32 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Debug|Win32.Deploy.0 = Debug|Win32 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Debug|x64.ActiveCfg = Debug|x64 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Debug|x64.Build.0 = Debug|x64 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Debug|x64.Deploy.0 = Debug|x64 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Release|Win32.ActiveCfg = Release|Win32 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Release|Win32.Build.0 = Release|Win32 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Release|Win32.Deploy.0 = Release|Win32 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Release|x64.ActiveCfg = Release|x64 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Release|x64.Build.0 = Release|x64 - {6838EC9D-F25D-4779-9CD7-2EDB61E49429}.Release|x64.Deploy.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6DF8F690-552A-4329-8FAB-DD447071A473} - EndGlobalSection -EndGlobal diff --git a/win/win32/vs2017/NetHack.vcxproj b/win/win32/vs2017/NetHack.vcxproj deleted file mode 100644 index bc49f9efc..000000000 --- a/win/win32/vs2017/NetHack.vcxproj +++ /dev/null @@ -1,270 +0,0 @@ - - - - - {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751} - Win32Proj - NetHack - - - - - - - - - - - - - - - - - - - - - - $(BinDir) - - - - $(PDCURSES);%(AdditionalIncludeDirectories) - CURSES_GRAPHICS;CHTYPE_32;PDC_NCMOUSE;%(PreprocessorDefinitions) - - - $(ToolsDir) - PDCurses.lib;%(AdditionalDependencies) - - - - - /Gs /Oi- %(AdditionalOptions) - Disabled - Default - Speed - true - $(WinWin32Dir);$(IncDir);$(SysWinntDir);$(SysShareDir);$(WinShareDir);%(AdditionalIncludeDirectories) - TILES;WIN32CON;DLB;MSWIN_GRAPHICS;SAFEPROCS;_LIB;%(PreprocessorDefinitions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;bcrypt.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUISTUB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/win/win32/vs2017/NetHackPackage.appxmanifest b/win/win32/vs2017/NetHackPackage.appxmanifest deleted file mode 100644 index c97a4fff1..000000000 --- a/win/win32/vs2017/NetHackPackage.appxmanifest +++ /dev/null @@ -1,29 +0,0 @@ - - - - - NetHack 3.6 - NetHack DevTeam - Images\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/win/win32/vs2017/NetHackPackage.wapproj b/win/win32/vs2017/NetHackPackage.wapproj deleted file mode 100644 index 514baa251..000000000 --- a/win/win32/vs2017/NetHackPackage.wapproj +++ /dev/null @@ -1,145 +0,0 @@ - - - - 15.0 - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ - - - - - - $(BinDir) - - - 6838ec9d-f25d-4779-9cd7-2edb61e49429 - 10.0.17763.0 - 10.0.15063.0 - en-US - NetHackPackage_StoreKey.pfx - NetHackW.vcxproj - 19591BE8832D6EFED75019EACE7C4CA42ABC90D4 - False - True - x86 - 1 - OnApplicationRun - - - Always - - - Always - - - Always - - - Always - - - - Designer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NetHackW\.nethackrc.template - - - NetHackW\Guidebook.txt - - - NetHackW\license - - - NetHackW\nhdat$(VERSION_MAJOR)$(VERSION_MINOR)$(PATCHLEVEL) - - - NetHackW\opthelp - - - NetHackW\symbols.template - - - NetHackW\sysconf.template - - - - - - - - - - \ No newline at end of file diff --git a/win/win32/vs2017/NetHackProperties.props b/win/win32/vs2017/NetHackProperties.props deleted file mode 100644 index f9c3ea4e8..000000000 --- a/win/win32/vs2017/NetHackProperties.props +++ /dev/null @@ -1,25 +0,0 @@ - - - - - 3 - 6 - 7 - - - - - - $(VERSION_MAJOR) - true - - - $(VERSION_MINOR) - true - - - $(PATCHLEVEL) - true - - - diff --git a/win/win32/vs2017/NetHackW.vcxproj b/win/win32/vs2017/NetHackW.vcxproj deleted file mode 100644 index 4369b4485..000000000 --- a/win/win32/vs2017/NetHackW.vcxproj +++ /dev/null @@ -1,227 +0,0 @@ - - - - - {CEC5D360-8804-454F-8591-002184C23499} - NetHackW - - - - - - - - - - - - - - - - - - - - - $(BinDir) - - - - /Gs /Oi- %(AdditionalOptions) - Disabled - true - $(WinWin32Dir);$(IncDir);$(SysWinntDir);$(SysShareDir);$(WinShareDir);%(AdditionalIncludeDirectories) - TILES;_WINDOWS;DLB;MSWIN_GRAPHICS;SAFEPROCS;NOTTYGRAPHICS;%(PreprocessorDefinitions) - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - Windows - comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies) - - - $(WinWin32Dir)NethackW.exe.manifest;%(AdditionalManifestFiles) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TTYSTUB; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/win/win32/vs2017/PDCurses.vcxproj b/win/win32/vs2017/PDCurses.vcxproj deleted file mode 100644 index 1365917ca..000000000 --- a/win/win32/vs2017/PDCurses.vcxproj +++ /dev/null @@ -1,118 +0,0 @@ - - - - - {BAA70D0F-3EC7-4D10-91F0-974F1F49308B} - Win32Proj - PDCurses - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - $(PDCURSES);$(IncludePath) - - - - NotUsing - Level3 - true - true - 4996;4244;%(DisableSpecificWarnings) - MultiThreadedDebug - true - - - Windows - true - - - - - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - MultiThreadedDebug - - - - - Disabled - _DEBUG;_LIB;%(PreprocessorDefinitions) - - - - - MaxSpeed - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - - - true - true - - - - - MaxSpeed - true - true - NDEBUG;_LIB;%(PreprocessorDefinitions) - - - true - true - - - - \ No newline at end of file diff --git a/win/win32/vs2017/Package.StoreAssociation.xml b/win/win32/vs2017/Package.StoreAssociation.xml deleted file mode 100644 index 1200895f3..000000000 --- a/win/win32/vs2017/Package.StoreAssociation.xml +++ /dev/null @@ -1,373 +0,0 @@ - - - CN=8BDC628A-FAAA-4EBA-8B5B-EB61BA93BA1F - NetHack DevTeam - AAD - http://www.w3.org/2001/04/xmlenc#sha256 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 30485NetHackDevTeam.NetHack3.6 - - NetHack 3.6 - - - - 30485NetHackDevTeam.NetHackBeta - - - \ No newline at end of file diff --git a/win/win32/vs2017/ScreenShot.PNG b/win/win32/vs2017/ScreenShot.PNG deleted file mode 100644 index 36d9f9876..000000000 Binary files a/win/win32/vs2017/ScreenShot.PNG and /dev/null differ diff --git a/win/win32/vs2017/afterdgncomp.proj b/win/win32/vs2017/afterdgncomp.proj deleted file mode 100644 index 90a8aea1c..000000000 --- a/win/win32/vs2017/afterdgncomp.proj +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/win/win32/vs2017/afterdlb.proj b/win/win32/vs2017/afterdlb.proj deleted file mode 100644 index 807fdf7c7..000000000 --- a/win/win32/vs2017/afterdlb.proj +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/win/win32/vs2017/afterlevcomp.proj b/win/win32/vs2017/afterlevcomp.proj deleted file mode 100644 index a167c0061..000000000 --- a/win/win32/vs2017/afterlevcomp.proj +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/win/win32/vs2017/aftermakedefs.proj b/win/win32/vs2017/aftermakedefs.proj deleted file mode 100644 index 845817c46..000000000 --- a/win/win32/vs2017/aftermakedefs.proj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/win/win32/vs2017/afternethack.proj b/win/win32/vs2017/afternethack.proj deleted file mode 100644 index ca39fddfc..000000000 --- a/win/win32/vs2017/afternethack.proj +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - diff --git a/win/win32/vs2017/afterrecover.proj b/win/win32/vs2017/afterrecover.proj deleted file mode 100644 index 46ab13a55..000000000 --- a/win/win32/vs2017/afterrecover.proj +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/win/win32/vs2017/aftertile2bmp.proj b/win/win32/vs2017/aftertile2bmp.proj deleted file mode 100644 index 5fd6d13b0..000000000 --- a/win/win32/vs2017/aftertile2bmp.proj +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - diff --git a/win/win32/vs2017/aftertilemap.proj b/win/win32/vs2017/aftertilemap.proj deleted file mode 100644 index e576f8b89..000000000 --- a/win/win32/vs2017/aftertilemap.proj +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/win/win32/vs2017/afteruudecode.proj b/win/win32/vs2017/afteruudecode.proj deleted file mode 100644 index 7f81188ae..000000000 --- a/win/win32/vs2017/afteruudecode.proj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/win/win32/vs2017/build.bat b/win/win32/vs2017/build.bat deleted file mode 100644 index 2a10d6239..000000000 --- a/win/win32/vs2017/build.bat +++ /dev/null @@ -1,44 +0,0 @@ -@echo off - -if "%VSCMD_VER%"=="" ( - echo MSBuild environment not set ... attempting to setup build environment. - call :setup_environment -) - -if "%VSCMD_VER%"=="" ( - echo Unable to setup build environment. Exiting. - goto :EOF -) - -msbuild NetHack.sln /t:Clean;Build /p:Configuration=Debug;Platform=Win32 -msbuild NetHack.sln /t:Clean;Build /p:Configuration=Debug;Platform=x64 -msbuild NetHack.sln /t:Clean;Build /p:Configuration=Release;Platform=Win32 -msbuild NetHack.sln /t:Clean;Build /p:Configuration=Release;Platform=x64 - -goto :EOF - -:setup_environment - - -if "%VS150COMNTOOLS%"=="" ( - call :set_vs15comntools -) - -if "%VS150COMNTOOLS%"=="" ( - echo Can not find Visual Studio 2017 Common Tools path. - echo Set VS150COMNTOOLS appropriately. - goto :EOF -) - -call "%VS150COMNTOOLS%VsMSBuildCmd.bat" -cd %~dp0 - -goto :EOF - -:set_vs15comntools - -if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Professional\Common7\Tools" ( - set "VS150COMNTOOLS=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Professional\Common7\Tools\" -) - -goto :EOF diff --git a/win/win32/vs2017/common.props b/win/win32/vs2017/common.props deleted file mode 100644 index ee802873c..000000000 --- a/win/win32/vs2017/common.props +++ /dev/null @@ -1,41 +0,0 @@ - - - - true - - - false - - - - Level3 - WIN32;CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WINVER=0x0601;_WIN32_WINNT=0x0601;%(PreprocessorDefinitions) - - - Console - $(SymbolsDir)$(TargetName).pdb - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebug - - - true - - - - - MaxSpeed - OnlyExplicitInline - NDEBUG;%(PreprocessorDefinitions) - MultiThreaded - - - UseLinkTimeCodeGeneration - - - diff --git a/win/win32/vs2017/config.props b/win/win32/vs2017/config.props deleted file mode 100644 index 3d435b54b..000000000 --- a/win/win32/vs2017/config.props +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - - - $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) - $(LatestTargetPlatformVersion) - - diff --git a/win/win32/vs2017/console.props b/win/win32/vs2017/console.props deleted file mode 100644 index f91d9dad4..000000000 --- a/win/win32/vs2017/console.props +++ /dev/null @@ -1,11 +0,0 @@ - - - - - _CONSOLE;%(PreprocessorDefinitions) - - - Console - - - diff --git a/win/win32/vs2017/default.props b/win/win32/vs2017/default.props deleted file mode 100644 index e0bc58136..000000000 --- a/win/win32/vs2017/default.props +++ /dev/null @@ -1,18 +0,0 @@ - - - - Application - false - MultiByte - v141 - $(BinDir) - - - true - - - false - true - - - diff --git a/win/win32/vs2017/default_dll.props b/win/win32/vs2017/default_dll.props deleted file mode 100644 index 51d90a3ee..000000000 --- a/win/win32/vs2017/default_dll.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - DynamicLibrary - false - MultiByte - v141 - - - true - - - false - true - - - diff --git a/win/win32/vs2017/default_lib.props b/win/win32/vs2017/default_lib.props deleted file mode 100644 index 61bf2ecaa..000000000 --- a/win/win32/vs2017/default_lib.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - StaticLibrary - false - MultiByte - v141 - - - true - - - false - true - - - diff --git a/win/win32/vs2017/dgncomp.vcxproj b/win/win32/vs2017/dgncomp.vcxproj deleted file mode 100644 index cb2fc0375..000000000 --- a/win/win32/vs2017/dgncomp.vcxproj +++ /dev/null @@ -1,132 +0,0 @@ - - - - - {8A3F81C7-2968-49A8-86BF-2669412AD7DE} - - - - - - - - - - - - - - - - - - - - - - - $(IncDir);$(SysWinntDir);$(SysShareDir);%(AdditionalIncludeDirectories) - WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Lex; - Yacc; - $(BuildDependsOn); - - - - - - - NoLex; - NoYacc; - $(BuildDependsOn); - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/win/win32/vs2017/dirs.props b/win/win32/vs2017/dirs.props deleted file mode 100644 index 0ebb31a25..000000000 --- a/win/win32/vs2017/dirs.props +++ /dev/null @@ -1,28 +0,0 @@ - - - - $(MSBuildProjectDirectory)\..\..\..\ - $(RootDir)bin\$(Configuration)\$(Platform)\ - $(ProjectDir)obj\$(Configuration)\$(Platform)\$(TargetName)\ - $(ProjectDir)symbols\$(Configuration)\$(Platform)\$(TargetName)\ - $(RootDir)tools\$(Configuration)\$(Platform)\ - $(RootDir)util\ - $(RootDir)dat\ - $(RootDir)doc\ - $(RootDir)include\ - $(RootDir)src\ - $(RootDir)sys\ - $(RootDir)util\ - $(RootDir)sys\share\ - $(RootDir)sys\winnt\ - $(RootDir)win\share\ - $(RootDir)win\tty\ - $(RootDir)win\win32\ - $(ToolsDir) - $(ObjDir) - $(RootDir)win\curses\ - - - $(RootDir)..\PDCurses\ - - diff --git a/win/win32/vs2017/dlb.vcxproj b/win/win32/vs2017/dlb.vcxproj deleted file mode 100644 index d189827b5..000000000 --- a/win/win32/vs2017/dlb.vcxproj +++ /dev/null @@ -1,51 +0,0 @@ - - - - - {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC} - - - - - - - - - - - - - - - - - - - - - - - $(IncDir);$(SysWinntDir);$(SysShareDir);%(AdditionalIncludeDirectories) - WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/win/win32/vs2017/dll.props b/win/win32/vs2017/dll.props deleted file mode 100644 index bd90844f1..000000000 --- a/win/win32/vs2017/dll.props +++ /dev/null @@ -1,11 +0,0 @@ - - - - - WIN32CON;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - - - diff --git a/win/win32/vs2017/files.props b/win/win32/vs2017/files.props deleted file mode 100644 index 483ec1eb1..000000000 --- a/win/win32/vs2017/files.props +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/win/win32/vs2017/levcomp.vcxproj b/win/win32/vs2017/levcomp.vcxproj deleted file mode 100644 index 8cb2fb75d..000000000 --- a/win/win32/vs2017/levcomp.vcxproj +++ /dev/null @@ -1,95 +0,0 @@ - - - - - {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} - - - - - - - - - - - - - - - - - - - - - - - $(IncDir);$(SysWinntDir);$(SysShareDir);%(AdditionalIncludeDirectories) - WIN32CON;DLB;MSWIN_GRAPHICS;YY_NO_UNISTD_H;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - Lex; - Yacc; - $(BuildDependsOn); - - - - - - - NoLex; - NoYacc; - $(BuildDependsOn); - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/win/win32/vs2017/makedefs.vcxproj b/win/win32/vs2017/makedefs.vcxproj deleted file mode 100644 index 1f6c1c49f..000000000 --- a/win/win32/vs2017/makedefs.vcxproj +++ /dev/null @@ -1,62 +0,0 @@ - - - - - {BA3DD34C-04B7-40D0-B373-9329AA9E8945} - - - - - - - - - - - - - - - - - - - - - - - $(IncDir);$(SysWinntDir);%(AdditionalIncludeDirectories) - WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/win/win32/vs2017/recover.vcxproj b/win/win32/vs2017/recover.vcxproj deleted file mode 100644 index f9cc6de8a..000000000 --- a/win/win32/vs2017/recover.vcxproj +++ /dev/null @@ -1,57 +0,0 @@ - - - - - {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E} - - - - - - - - - - - - - - - - - - - - - - $(BinDir) - - - - $(IncDir);$(SysWinntDir);%(AdditionalIncludeDirectories) - WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/win/win32/vs2017/tile2bmp.vcxproj b/win/win32/vs2017/tile2bmp.vcxproj deleted file mode 100644 index ab1145c70..000000000 --- a/win/win32/vs2017/tile2bmp.vcxproj +++ /dev/null @@ -1,53 +0,0 @@ - - - - - {642BC75D-ABAF-403E-8224-7C725FD4CB42} - - - - - - - - - - - - - - - - - - - - - - - $(IncDir);$(SysWinntDir);$(SysShareDir);%(AdditionalIncludeDirectories) - WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) - - - - - - - - - - - TILETEXT;%(PreprocessorDefinitions) - - - - - - - - - - - - - \ No newline at end of file diff --git a/win/win32/vs2017/tilemap.vcxproj b/win/win32/vs2017/tilemap.vcxproj deleted file mode 100644 index cb0ba0bd4..000000000 --- a/win/win32/vs2017/tilemap.vcxproj +++ /dev/null @@ -1,89 +0,0 @@ - - - - - {93F10526-209E-41D7-BBEA-775787876895} - - - - - - - - - - - - - - - - - - - - - - - $(IncDir);$(SysWinntDir);$(SysShareDir);%(AdditionalIncludeDirectories) - WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/win/win32/vs2017/tiles.vcxproj b/win/win32/vs2017/tiles.vcxproj deleted file mode 100644 index f17bd023f..000000000 --- a/win/win32/vs2017/tiles.vcxproj +++ /dev/null @@ -1,124 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {55946465-FC65-47B3-BB48-742C7694C0D6} - MakeFileProj - - - - Makefile - false - v120 - - - Makefile - false - v120 - - - Makefile - false - v120 - - - Makefile - false - v120 - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - .\..\util\ - .\..\util\ - .\Debug\ - .\Debug\ - nmake /f "tiles.mak" - nmake /f "tiles.mak" - nmake /f "tiles.mak" /a - nmake /f "tiles.mak" /a - - - ..\win\win32\tiles.bmp - ..\win\win32\tiles.bmp - $(NMakePreprocessorDefinitions) - $(NMakePreprocessorDefinitions) - $(NMakeIncludeSearchPath) - $(NMakeIncludeSearchPath) - $(NMakeForcedIncludes) - $(NMakeForcedIncludes) - $(NMakeAssemblySearchPath) - $(NMakeAssemblySearchPath) - $(NMakeForcedUsingAssemblies) - $(NMakeForcedUsingAssemblies) - .\..\util\ - .\..\util\ - .\Release\ - .\Release\ - nmake /f "tiles.mak" - nmake /f "tiles.mak" - nmake /f "tiles.mak" /a - nmake /f "tiles.mak" /a - - - ..\win\win32\tiles.bmp - ..\win\win32\tiles.bmp - $(NMakePreprocessorDefinitions) - $(NMakePreprocessorDefinitions) - $(NMakeIncludeSearchPath) - $(NMakeIncludeSearchPath) - $(NMakeForcedIncludes) - $(NMakeForcedIncludes) - $(NMakeAssemblySearchPath) - $(NMakeAssemblySearchPath) - $(NMakeForcedUsingAssemblies) - $(NMakeForcedUsingAssemblies) - - - - - - {642bc75d-abaf-403e-8224-7c725fd4cb42} - false - - - - - - diff --git a/win/win32/vs2017/travisci.sh b/win/win32/vs2017/travisci.sh deleted file mode 100644 index f9fd227b6..000000000 --- a/win/win32/vs2017/travisci.sh +++ /dev/null @@ -1,41 +0,0 @@ -set -x -export VSVER=2017 -export MSVER=14.16.27023 -export SDKVER=10.0.17763.0 -export FRAMEVER=4.0.30319 -export NETFXVER=4.6.1 -export WKITVER=10.0.17134.0 -#export TOOLSVER=Enterprise -export TOOLSVER=BuildTools -export PATH=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER/Common7/IDE/VC/VCPackages:$PATH -export PATH=/c/Program\ Files\ \(x86\)/Windows\ Kits/10/bin/$WKITVER/x64:$PATH -export PATH=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER/VC/Tools/MSVC/$MSVER/bin/HostX64/x64:$PATH -export PATH=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER/VC/Tools/MSVC/$MSVER/bin/HostX64/x86:$PATH -export PATH=$PATH:/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER/Common7/IDE/CommonExtensions/Microsoft/TestWindow -export PATH=$PATH:/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER/MSBuild/Current/bin/Roslyn -export PATH=$PATH:/c/ProgramData/chocolatey/lib/winflexbison/tools -export INCLUDE=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/2017/$TOOLSVER/VC/Tools/MSVC/$MSVER/include -export INCLUDE=$INCLUDE:/c/Program\ Files\ \(x86\)/Windows\ Kits/10/Include/$WKITVER/ucrt -export INCLUDE=$INCLUDE:/c/Program\ Files\ \(x86\)/Windows\ Kits/10/include/$WKITVER/ucrt -export INCLUDE=$INCLUDE:/c/Program\ Files\ \(x86\)/Windows\ Kits/10/include/$WKITVER/shared -export INCLUDE=$INCLUDE:/c/Program\ Files\ \(x86\)/Windows\ Kits/10/include/$WKITVER/um -export INCLUDE=$INCLUDE:/c/Program\ Files\ \(x86\)/Windows\ Kits/10/include/$WKITVER/winrt -export INCLUDE=$INCLUDE:/c/Program\ Files\ \(x86\)/Windows\ Kits/10/include/$WKITVER/cppwinrt -export LIB=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER/VC/Tools/MSVC/$MSVER/ATLMFC/lib/x86 -export LIB=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER/VC/Tools/MSVC/$MSVER/lib/x86:$LIB -export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/10/lib/$WKITVER/ucrt/x86:$LIB -export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/10/lib/$WKITVER/um/x86:$LIB -git clone --depth 1 https://github.com/wmcbrine/PDCurses.git ../pdcurses -export ADD_CURSES=Y -export PDCURSES_TOP=../../pdcurses -export YACC="win_bison -y" -export LEX=win_flex.exe -export YTABC=y.tab.c -export YTABH=y.tab.h -export LEXYYC=lex.yy.cexport -cd src -mkdir ../binary -cp ../sys/winnt/Makefile.msc ./Makefile -nmake install -cd .. -powershell -Command "Compress-Archive -U -Path binary/* -DestinationPath $TRAVIS_TAG.x86.zip" diff --git a/win/win32/vs2017/uudecode.vcxproj b/win/win32/vs2017/uudecode.vcxproj deleted file mode 100644 index ce602e1f2..000000000 --- a/win/win32/vs2017/uudecode.vcxproj +++ /dev/null @@ -1,39 +0,0 @@ - - - - - {63F9B82B-F589-4082-ABE5-D4F0682050AB} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/win/win32/winMS.h b/win/win32/winMS.h index c5ee77368..2d4deb058 100644 --- a/win/win32/winMS.h +++ b/win/win32/winMS.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 winMS.h $NHDT-Date: 1434804346 2015/06/20 12:45:46 $ $NHDT-Branch: win32-x64-working $:$NHDT-Revision: 1.41 $ */ +/* NetHack 5.0 winMS.h $NHDT-Date: 1596498367 2020/08/03 23:46:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.53 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -35,14 +35,27 @@ #include "hack.h" #include "color.h" +#define TEXT_BUFFER_SIZE 4096 + /* Create an array to keep track of the various windows */ #ifndef MAXWINDOWS #define MAXWINDOWS 15 #endif -#define NHW_RIP 32 -#define NHW_INVEN 33 +struct window_tracking_data { + genericptr_t address; + int isstatic; +}; + +/* these are only in MSWIN_GRAPHICS, not the core */ +enum mswin_window_types { + NHW_MAIN = (NHW_LAST_TYPE + 1), + NHW_INVEN, + NHW_RIP, + NHW_SPLASH +}; +extern struct window_tracking_data windowdata[MAXWINDOWS]; #ifndef TILE_X #define TILE_X 16 @@ -129,12 +142,9 @@ typedef struct mswin_nhwindow_app { LPTRANSPARENTBLT lpfnTransparentBlt; /* transparent blt function */ } NHWinApp, *PNHWinApp; -#define E extern - -E PNHWinApp GetNHApp(void); -E struct window_procs mswin_procs; - -#undef E +extern PNHWinApp GetNHApp(void); +extern struct window_procs mswin_procs; +extern void free_winmain_stuff(void); /* Some prototypes */ void mswin_init_nhwindows(int *argc, char **argv); @@ -146,49 +156,50 @@ void mswin_suspend_nhwindows(const char *); void mswin_resume_nhwindows(void); winid mswin_create_nhwindow(int type); void mswin_clear_nhwindow(winid wid); -void mswin_display_nhwindow(winid wid, BOOLEAN_P block); +void mswin_display_nhwindow(winid wid, boolean block); void mswin_destroy_nhwindow(winid wid); void mswin_curs(winid wid, int x, int y); void mswin_putstr(winid wid, int attr, const char *text); void mswin_putstr_ex(winid wid, int attr, const char *text, int); -void mswin_display_file(const char *filename, BOOLEAN_P must_exist); -void mswin_start_menu(winid wid); -void mswin_add_menu(winid wid, int glyph, const ANY_P *identifier, - CHAR_P accelerator, CHAR_P group_accel, int attr, - const char *str, BOOLEAN_P presel); +void mswin_display_file(const char *filename, boolean must_exist); +void mswin_start_menu(winid wid, unsigned long mbehavior); +void mswin_add_menu(winid wid, const glyph_info *glyphinfo, + const ANY_P *identifier, + char accelerator, char group_accel, int attr, + int clr, const char *str, unsigned int itemflags); void mswin_end_menu(winid wid, const char *prompt); int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected); -void mswin_update_inventory(void); void mswin_mark_synch(void); void mswin_wait_synch(void); void mswin_cliparound(int x, int y); -void mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph); +void mswin_print_glyph(winid wid, coordxy x, coordxy y, + const glyph_info *glyph, const glyph_info *bkglyph); void mswin_raw_print(const char *str); void mswin_raw_print_bold(const char *str); -void mswin_raw_print_flush(); +void mswin_raw_print_flush(void); int mswin_nhgetch(void); -int mswin_nh_poskey(int *x, int *y, int *mod); +int mswin_nh_poskey(coordxy *x, coordxy *y, int *mod); void mswin_nhbell(void); int mswin_doprev_message(void); -char mswin_yn_function(const char *question, const char *choices, CHAR_P def); +char mswin_yn_function(const char *question, const char *choices, char def); void mswin_getlin(const char *question, char *input); int mswin_get_ext_cmd(void); void mswin_number_pad(int state); void mswin_delay_output(void); -void mswin_change_color(void); +void mswin_change_color(int color, long rgb, int reverse); char *mswin_get_color_string(void); -void mswin_start_screen(void); -void mswin_end_screen(void); void mswin_outrip(winid wid, int how, time_t when); void mswin_preference_update(const char *pref); -char *mswin_getmsghistory(BOOLEAN_P init); -void mswin_putmsghistory(const char *msg, BOOLEAN_P); +char *mswin_getmsghistory(boolean init); +void mswin_putmsghistory(const char *msg, boolean); void mswin_status_init(void); void mswin_status_finish(void); void mswin_status_enablefield(int fieldidx, const char *nm, const char *fmt, boolean enable); void mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, unsigned long *colormasks); +void mswin_update_inventory(int); +win_request_info *mswin_ctrl_nhwindow(winid, int, win_request_info *); /* helper function */ HWND mswin_hwnd_from_winid(winid wid); @@ -208,6 +219,8 @@ void mswin_get_window_placement(int type, LPRECT rt); void mswin_update_window_placement(int type, LPRECT rt); void mswin_apply_window_style(HWND hwnd); +//boolean mswin_player_selection_window(void); + int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type); extern HBRUSH menu_bg_brush; @@ -233,12 +246,14 @@ extern COLORREF message_fg_color; /* unicode stuff */ #define NH_CODEPAGE (SYMHANDLING(H_IBM) ? GetOEMCP() : GetACP()) #ifdef _UNICODE +#define nh_stprintf swprintf #define NH_W2A(w, a, cb) \ (WideCharToMultiByte(NH_CODEPAGE, 0, (w), -1, (a), (cb), NULL, NULL), (a)) #define NH_A2W(a, w, cb) \ (MultiByteToWideChar(NH_CODEPAGE, 0, (a), -1, (w), (cb)), (w)) #else +#define nh_stprintf snprintf #define NH_W2A(w, a, cb) (strncpy((a), (w), (cb))) #define NH_A2W(a, w, cb) (strncpy((w), (a), (cb)))