The walls for the mines, gehennom, knox, and sokoban had been changed at the "tile"-level, with no awareness of the core game, or non-tile interfaces. - Expand the glyphs to include a set of walls for the main level as well as each of those mentioned above. Altars had been adjusted at the map_glyphinfo() level to substitute some color variations on-the-fly for unaligned, chaotic, neutral, lawful altars, and shrines. The tile interface had no awareness of the feature. - Expand the glyphs to include each of the altar variations that had been implemented in the display code for tty-only. This required the addition of four placeholder tiles in other.txt. Someone with artistic skill will hopefully alter the additional tiles to better reflect their intended purpose. Explosions had unique tiles in the tile window port, and the display code for tty tinkered with the colors, but the game had very little awareness of the different types of explosions. - Expand the glyphs to include each of the explosion types: dark, noxious, muddy, wet, magical, fiery and frosty. Pile-markers to represent a pile had been introduced at the display-level, without little to no awareness by the core game. - Expand the glyphs to include piletops, including objects, bodys, and statues. Recently male and female variations of tiles and monsters had been had been introduced, but the mechanics had been mostly done at the display-level through a marker flag. The window port interface then had to increment the tile mapped to the glyph to get the female version of the tile. - Expand the glyphs to include the male and female versions of the monsters, and their corresponding pet versions, ridden, detected versions and statues of them. Direct references to GLYPH_BODY_OFF and GLYPH_STATUE_OFF in object_from_map() in pager.c were getting incomplete results. - Add macros glyph_to_body_corpsenm(glyph) and glyph_to_statue_corpsenm(glyph) macros for obtaining the corpsenm value after passing the glyph_is_body() or glyph_is_statue() test. Other relevant notes: - The tile ordering in the win/share/*.txt tile files has been altered, other.txt in particular. - tilemap.c has had a lot of alterations to accommodate the expanded glyphs. Output that is useful for troubleshooting will end up in tilemappings.lst if OBTAIN_TILEMAP is defined during build. It lists all of the glyphs and which tile it gets mapped to, and also lists each tile and some of the references to it by various glyphs. - An array glyphmap[MAXGLYPH] is now used. It has an entry for each glyph, ordered by glyph, and once reset_glyphs(glyph) has been run, it contains the mapped symindex, default color, glyphflags, and tile index. If USE_TILES is defined during build, the tile.c produced from the tilemap utility populates the tileidx field of each array element with a glyph-to-tile mapping for the glyph. Later on, when reset_glyphmap() is run, the other fields of each element will get populated. - The glyph-to-tile mapping is an added field available to a window port via the glyphinfo struct passed in the documented interface. The old glyph2tile[] array is gone. The various active window ports that had been using glyph2tile[] have been updated to use the new interface mechanism. Disclaimer: There may be some bug fixing or tidying required in the window port code. - reset_glyphmap() is called after config file options parsing has finished, because some config file settings can impact the results produced by reset_glyphmap(). - Everything that passes the glyph_is_cmap(glyph) test must return a valid cmap value from glyph_to_cmap(glyph). - An 'extern glyph_info glyphmap[MAX_GLYPH];' is inserted into the top of only the files which need awareness of it, not inserted into display.h. Presently, the only files that actually need to directly reference the glyphmap[] array are display.c, o_init.c (for shuffling the tiles), and the generated tile.c (if USE_TILES is defined). - Added an MG_MALE glyphflag to complement the MG_FEMALE glyphflag. - Provide an array for wall colorizations. reset_glyphmap() will draw the colors from this array: int array wallcolors[sokoban_walls + 1]; The indices of the wallcolors array are main_walls (0), mines_walls (1), gehennom_walls (2), knox_walls (3), and sokoban_walls (4). In future, a config file option for adjusting the wall colors and/or an 'O' option menu to do the same could be added. Right now, the initializaton of the wallcolors[] array entries in display.c leaves the walls at CLR_GRAY, matching the defsym color. - Most of the display-level kludges for some of the on-the-fly interface features have been removed from map_glyphinfo() as they aren't needed any longer. These glyph expansions adhere more closely to the original glyph mechanics of the game. - Because the glyphs are re-ordered and expanded, an update to editlevel will be required upon merge of these changes.
327 lines
12 KiB
C++
327 lines
12 KiB
C++
// 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 <QtGui/QtGui>
|
|
#if QT_VERSION >= 0x050000
|
|
#include <QtWidgets/QtWidgets>
|
|
#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 = g.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);
|
|
|
|
// 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;
|
|
#ifdef ENHANCED_PAPERDOLL
|
|
// color margin around cell containing item whose BUC state is known
|
|
if (Role_if('P') && !Blind)
|
|
nhobj->bknown = 1;
|
|
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);
|
|
map_glyphinfo(0, 0, glyph, 0, &gi); /* this skirts the defined
|
|
interface unfortunately */
|
|
} 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 ? cmap_to_glyph(S_room) : GLYPH_UNEXPLORED;
|
|
}
|
|
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] b H q b H q b H q b eyewear H helmet q quiver
|
|
// 1 [S " w] S " w W " W X " w S shield " amulet w weapon
|
|
// 2 [G C G] G C x G C x G C . G gloves C cloak x alt-weap
|
|
// 3 [= A =] = A = = A = = A = = left rg A suit = right ring
|
|
// 4 [. U .] l U L l U L l U L l leash U shirt L light
|
|
// 5 [. F .] . F . . F . . F . . blank F boots . blank
|
|
// W wielded two-handed weapon
|
|
// X wielded secondary weapon
|
|
//
|
|
// 3.7: use a different layout (also different legend for it, above):
|
|
// 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 right side;
|
|
// add leash-in-use on lower left side
|
|
//
|
|
// Actually indexed by grid[column][row].
|
|
|
|
#ifdef ENHANCED_PAPERDOLL
|
|
if (iflags.wc_ascii_map)
|
|
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 column
|
|
drawWorn(painter, ublindf, 0, 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, 0, 1, NULL); // secondary weapon, in use
|
|
else if (uwep && bimanual(uwep)) // show two-handed uwep twice
|
|
drawWorn(painter, uwep, 0, 1, NULL, dollReverse); // uwep on left
|
|
else
|
|
drawWorn(painter, uarms, 0, 1, "no shield");
|
|
drawWorn(painter, uarmg, 0, 2, "no gloves");
|
|
drawWorn(painter, uleft, 0, 3, "no left ring");
|
|
/* light source and leash aren't unique and don't have pointers defined */
|
|
drawWorn(painter, find_tool(LEASH), 0, 4, "no leashes in use");
|
|
drawWorn(painter, NULL, 0, 5, NULL, dollUnused); // always blank
|
|
|
|
// middle 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 column
|
|
drawWorn(painter, uquiver, 2, 0, "nothing readied for firing"); // quiver
|
|
drawWorn(painter, uwep, 2, 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, 2, 2, "no alternate weapon");
|
|
else
|
|
drawWorn(painter, NULL, 2, 2, "secondary weapon is wielded");
|
|
drawWorn(painter, uright, 2, 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), 2, 4, "no active light sources");
|
|
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 <QHelpEvent *> (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 <NetHackQtMainWindow *> (main))->FuncAsCommand(doprinuse);
|
|
#endif
|
|
}
|
|
|
|
} // namespace nethack_qt_
|