The consolidation of global variables from scattered source
files into decl.c and declared in decl.h was begun in 3.7.0.
Their placement in common files was done for centralized
initialization and potential re-initialization during a
"play again" scenario.
It wasn't really necessary for all of them to be housed in a
single huge structure to meet the "play again" requirement,
and the single huge structure has been a little unwieldy when
it comes to maintenance.
Following this commit, instead of one single extremely large structure
named 'g' to house all of the relocated global variables, they
are distributed into several ga through gz.
To make things easy for the developer, each variable is placed
into the struct corresponding to the starting letter of the variable.
That way, no lookup is required in order to know which struct houses
a particular variable, it is a simple match to the starting letter
for all the centralized global variables.
A global variable named 'amulets', would be found in ga.
ga.amulets
^ ^
A global varable named 'move', would be found in gm.
gm.moves
^ ^
A global variable named 'val_for_n_or_more' would be found in gv.
gv.val_for_n_or_more
^ ^
A global variable named 'youmonst' would be found in gy.
gy.youmonst
^ ^
335 lines
13 KiB
C++
335 lines
13 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 = 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);
|
|
|
|
// 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
|
|
//
|
|
// 3.7: 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 <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_
|