1 // Copyright (c) Warwick Allison, 1999.
2 // Qt4 conversion copyright (c) Ray Chason, 2012-2014.
3 // NetHack may be freely redistributed. See license for details.
4
5 // qt4stat.cpp -- bindings between the Qt 4 interface and the main code
6
7 extern "C" {
8 #include "hack.h"
9 }
10 #undef Invisible
11 #undef Warning
12 #undef index
13 #undef msleep
14 #undef rindex
15 #undef wizard
16 #undef yn
17 #undef min
18 #undef max
19
20 #include <QtGui/QtGui>
21 #if QT_VERSION >= 0x050000
22 #include <QtWidgets/QtWidgets>
23 #endif
24 #include "qt4stat.h"
25 #include "qt4stat.moc"
26 #include "qt4set.h"
27 #include "qt4str.h"
28 #include "qt_xpms.h"
29
30 extern const char *enc_stat[]; /* from botl.c */
31 extern const char *hu_stat[]; /* from eat.c */
32
33 namespace nethack_qt4 {
34
NetHackQtStatusWindow()35 NetHackQtStatusWindow::NetHackQtStatusWindow() :
36 // Notes:
37 // Alignment needs -2 init value, because -1 is an alignment.
38 // Armor Class is an schar, so 256 is out of range.
39 // Blank value is 0 and should never change.
40 name(this,"(name)"),
41 dlevel(this,"(dlevel)"),
42 str(this,"STR"),
43 dex(this,"DEX"),
44 con(this,"CON"),
45 intel(this,"INT"),
46 wis(this,"WIS"),
47 cha(this,"CHA"),
48 gold(this,"Gold"),
49 hp(this,"Hit Points"),
50 power(this,"Power"),
51 ac(this,"Armour Class"),
52 level(this,"Level"),
53 exp(this,"Experience"),
54 align(this,"Alignment"),
55 time(this,"Time"),
56 score(this,"Score"),
57 hunger(this,""),
58 confused(this,"Confused"),
59 sick_fp(this,"Sick"),
60 sick_il(this,"Ill"),
61 blind(this,""),
62 stunned(this,"Stunned"),
63 hallu(this,"Hallu"),
64 encumber(this,""),
65 hline1(this),
66 hline2(this),
67 hline3(this),
68 first_set(true)
69 {
70 p_str = QPixmap(str_xpm);
71 p_str = QPixmap(str_xpm);
72 p_dex = QPixmap(dex_xpm);
73 p_con = QPixmap(cns_xpm);
74 p_int = QPixmap(int_xpm);
75 p_wis = QPixmap(wis_xpm);
76 p_cha = QPixmap(cha_xpm);
77
78 p_chaotic = QPixmap(chaotic_xpm);
79 p_neutral = QPixmap(neutral_xpm);
80 p_lawful = QPixmap(lawful_xpm);
81
82 p_satiated = QPixmap(satiated_xpm);
83 p_hungry = QPixmap(hungry_xpm);
84
85 p_confused = QPixmap(confused_xpm);
86 p_sick_fp = QPixmap(sick_fp_xpm);
87 p_sick_il = QPixmap(sick_il_xpm);
88 p_blind = QPixmap(blind_xpm);
89 p_stunned = QPixmap(stunned_xpm);
90 p_hallu = QPixmap(hallu_xpm);
91
92 p_encumber[0] = QPixmap(slt_enc_xpm);
93 p_encumber[1] = QPixmap(mod_enc_xpm);
94 p_encumber[2] = QPixmap(hvy_enc_xpm);
95 p_encumber[3] = QPixmap(ext_enc_xpm);
96 p_encumber[4] = QPixmap(ovr_enc_xpm);
97
98 str.setIcon(p_str);
99 dex.setIcon(p_dex);
100 con.setIcon(p_con);
101 intel.setIcon(p_int);
102 wis.setIcon(p_wis);
103 cha.setIcon(p_cha);
104
105 align.setIcon(p_neutral);
106 hunger.setIcon(p_hungry);
107
108 confused.setIcon(p_confused);
109 sick_fp.setIcon(p_sick_fp);
110 sick_il.setIcon(p_sick_il);
111 blind.setIcon(p_blind);
112 stunned.setIcon(p_stunned);
113 hallu.setIcon(p_hallu);
114
115 encumber.setIcon(p_encumber[0]);
116
117 hline1.setFrameStyle(QFrame::HLine|QFrame::Sunken);
118 hline2.setFrameStyle(QFrame::HLine|QFrame::Sunken);
119 hline3.setFrameStyle(QFrame::HLine|QFrame::Sunken);
120 hline1.setLineWidth(1);
121 hline2.setLineWidth(1);
122 hline3.setLineWidth(1);
123
124 #if 1 //RLC
125 name.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
126 dlevel.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
127 QVBoxLayout *vbox = new QVBoxLayout();
128 vbox->setSpacing(0);
129 vbox->addWidget(&name);
130 vbox->addWidget(&dlevel);
131 vbox->addWidget(&hline1);
132 QHBoxLayout *atr1box = new QHBoxLayout();
133 atr1box->addWidget(&str);
134 atr1box->addWidget(&dex);
135 atr1box->addWidget(&con);
136 atr1box->addWidget(&intel);
137 atr1box->addWidget(&wis);
138 atr1box->addWidget(&cha);
139 vbox->addLayout(atr1box);
140 vbox->addWidget(&hline2);
141 QHBoxLayout *atr2box = new QHBoxLayout();
142 atr2box->addWidget(&gold);
143 atr2box->addWidget(&hp);
144 atr2box->addWidget(&power);
145 atr2box->addWidget(&ac);
146 atr2box->addWidget(&level);
147 atr2box->addWidget(&exp);
148 vbox->addLayout(atr2box);
149 vbox->addWidget(&hline3);
150 QHBoxLayout *timebox = new QHBoxLayout();
151 timebox->addWidget(&time);
152 timebox->addWidget(&score);
153 vbox->addLayout(timebox);
154 QHBoxLayout *statbox = new QHBoxLayout();
155 statbox->addWidget(&align);
156 statbox->addWidget(&hunger);
157 statbox->addWidget(&confused);
158 statbox->addWidget(&sick_fp);
159 statbox->addWidget(&sick_il);
160 statbox->addWidget(&blind);
161 statbox->addWidget(&stunned);
162 statbox->addWidget(&hallu);
163 statbox->addWidget(&encumber);
164 statbox->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
165 vbox->addLayout(statbox);
166 setLayout(vbox);
167 #endif
168
169 connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate()));
170 doUpdate();
171 }
172
doUpdate()173 void NetHackQtStatusWindow::doUpdate()
174 {
175 const QFont& large=qt_settings->largeFont();
176 name.setFont(large);
177 dlevel.setFont(large);
178
179 const QFont& normal=qt_settings->normalFont();
180 str.setFont(normal);
181 dex.setFont(normal);
182 con.setFont(normal);
183 intel.setFont(normal);
184 wis.setFont(normal);
185 cha.setFont(normal);
186 gold.setFont(normal);
187 hp.setFont(normal);
188 power.setFont(normal);
189 ac.setFont(normal);
190 level.setFont(normal);
191 exp.setFont(normal);
192 align.setFont(normal);
193 time.setFont(normal);
194 score.setFont(normal);
195 hunger.setFont(normal);
196 confused.setFont(normal);
197 sick_fp.setFont(normal);
198 sick_il.setFont(normal);
199 blind.setFont(normal);
200 stunned.setFont(normal);
201 hallu.setFont(normal);
202 encumber.setFont(normal);
203
204 updateStats();
205 }
206
Widget()207 QWidget* NetHackQtStatusWindow::Widget() { return this; }
208
Clear()209 void NetHackQtStatusWindow::Clear()
210 {
211 }
Display(bool block)212 void NetHackQtStatusWindow::Display(bool block)
213 {
214 }
CursorTo(int,int y)215 void NetHackQtStatusWindow::CursorTo(int,int y)
216 {
217 cursy=y;
218 }
PutStr(int attr,const QString & text)219 void NetHackQtStatusWindow::PutStr(int attr, const QString& text)
220 {
221 // do a complete update when line 0 is done (as per X11 fancy status)
222 if (cursy==0) updateStats();
223 }
224
225 #if 0 // RLC
226 void NetHackQtStatusWindow::resizeEvent(QResizeEvent*)
227 {
228 #if 0
229 const float SP_name=0.13; // <Name> the <Class> (large)
230 const float SP_dlev=0.13; // Level 3 in The Dungeons of Doom (large)
231 const float SP_atr1=0.25; // STR DEX CON INT WIS CHA
232 const float SP_hln1=0.02; // ---
233 const float SP_atr2=0.09; // Au HP PW AC LVL EXP
234 const float SP_hln2=0.02; // ---
235 const float SP_time=0.09; // time score
236 const float SP_hln3=0.02; // ---
237 const float SP_stat=0.25; // Alignment, Poisoned, Hungry, Sick, etc.
238
239 int h=height();
240 int x=0,y=0;
241
242 int iw; // Width of an item across line
243 int lh; // Height of a line of values
244
245 lh=int(h*SP_name);
246 name.setGeometry(0,0,width(),lh); y+=lh;
247 lh=int(h*SP_dlev);
248 dlevel.setGeometry(0,y,width(),lh); y+=lh;
249
250 lh=int(h*SP_hln1);
251 hline1.setGeometry(0,y,width(),lh); y+=lh;
252
253 lh=int(h*SP_atr1);
254 iw=width()/6;
255 str.setGeometry(x,y,iw,lh); x+=iw;
256 dex.setGeometry(x,y,iw,lh); x+=iw;
257 con.setGeometry(x,y,iw,lh); x+=iw;
258 intel.setGeometry(x,y,iw,lh); x+=iw;
259 wis.setGeometry(x,y,iw,lh); x+=iw;
260 cha.setGeometry(x,y,iw,lh); x+=iw;
261 x=0; y+=lh;
262
263 lh=int(h*SP_hln2);
264 hline2.setGeometry(0,y,width(),lh); y+=lh;
265
266 lh=int(h*SP_atr2);
267 iw=width()/6;
268 gold.setGeometry(x,y,iw,lh); x+=iw;
269 hp.setGeometry(x,y,iw,lh); x+=iw;
270 power.setGeometry(x,y,iw,lh); x+=iw;
271 ac.setGeometry(x,y,iw,lh); x+=iw;
272 level.setGeometry(x,y,iw,lh); x+=iw;
273 exp.setGeometry(x,y,iw,lh); x+=iw;
274 x=0; y+=lh;
275
276 lh=int(h*SP_hln3);
277 hline3.setGeometry(0,y,width(),lh); y+=lh;
278
279 lh=int(h*SP_time);
280 iw=width()/3; x+=iw/2;
281 time.setGeometry(x,y,iw,lh); x+=iw;
282 score.setGeometry(x,y,iw,lh); x+=iw;
283 x=0; y+=lh;
284
285 lh=int(h*SP_stat);
286 iw=width()/9;
287 align.setGeometry(x,y,iw,lh); x+=iw;
288 hunger.setGeometry(x,y,iw,lh); x+=iw;
289 confused.setGeometry(x,y,iw,lh); x+=iw;
290 sick_fp.setGeometry(x,y,iw,lh); x+=iw;
291 sick_il.setGeometry(x,y,iw,lh); x+=iw;
292 blind.setGeometry(x,y,iw,lh); x+=iw;
293 stunned.setGeometry(x,y,iw,lh); x+=iw;
294 hallu.setGeometry(x,y,iw,lh); x+=iw;
295 encumber.setGeometry(x,y,iw,lh); x+=iw;
296 x=0; y+=lh;
297 #else
298 // This is clumsy. But QLayout objects are proving balky.
299
300 int row[10];
301
302 row[0] = name.sizeHint().height();
303 row[1] = dlevel.sizeHint().height();
304 row[2] = h.sizeHint().height();
305 #endif
306 }
307 #endif
308
309
310 /*
311 * Set all widget values to a null string. This is used after all spacings
312 * have been calculated so that when the window is popped up we don't get all
313 * kinds of funny values being displayed.
314 */
nullOut()315 void NetHackQtStatusWindow::nullOut()
316 {
317 }
318
fadeHighlighting()319 void NetHackQtStatusWindow::fadeHighlighting()
320 {
321 name.dissipateHighlight();
322 dlevel.dissipateHighlight();
323
324 str.dissipateHighlight();
325 dex.dissipateHighlight();
326 con.dissipateHighlight();
327 intel.dissipateHighlight();
328 wis.dissipateHighlight();
329 cha.dissipateHighlight();
330
331 gold.dissipateHighlight();
332 hp.dissipateHighlight();
333 power.dissipateHighlight();
334 ac.dissipateHighlight();
335 level.dissipateHighlight();
336 exp.dissipateHighlight();
337 align.dissipateHighlight();
338
339 time.dissipateHighlight();
340 score.dissipateHighlight();
341
342 hunger.dissipateHighlight();
343 confused.dissipateHighlight();
344 sick_fp.dissipateHighlight();
345 sick_il.dissipateHighlight();
346 blind.dissipateHighlight();
347 stunned.dissipateHighlight();
348 hallu.dissipateHighlight();
349 encumber.dissipateHighlight();
350 }
351
352 /*
353 * Update the displayed status. The current code in botl.c updates
354 * two lines of information. Both lines are always updated one after
355 * the other. So only do our update when we update the second line.
356 *
357 * Information on the first line:
358 * name, attributes, alignment, score
359 *
360 * Information on the second line:
361 * dlvl, gold, hp, power, ac, {level & exp or HD **}
362 * status (hunger, conf, halu, stun, sick, blind), time, encumbrance
363 *
364 * [**] HD is shown instead of level and exp if mtimedone is non-zero.
365 */
updateStats()366 void NetHackQtStatusWindow::updateStats()
367 {
368 if (!parentWidget()) return;
369
370 QString buf;
371 const char *text;
372
373 if (cursy != 0) return; /* do a complete update when line 0 is done */
374
375 if (ACURR(A_STR) > 118) {
376 buf.sprintf("STR:%d",ACURR(A_STR)-100);
377 } else if (ACURR(A_STR)==118) {
378 buf.sprintf("STR:18/**");
379 } else if(ACURR(A_STR) > 18) {
380 buf.sprintf("STR:18/%02d",ACURR(A_STR)-18);
381 } else {
382 buf.sprintf("STR:%d",ACURR(A_STR));
383 }
384 str.setLabel(buf,NetHackQtLabelledIcon::NoNum,ACURR(A_STR));
385
386 dex.setLabel("DEX:",(long)ACURR(A_DEX));
387 con.setLabel("CON:",(long)ACURR(A_CON));
388 intel.setLabel("INT:",(long)ACURR(A_INT));
389 wis.setLabel("WIS:",(long)ACURR(A_WIS));
390 cha.setLabel("CHA:",(long)ACURR(A_CHA));
391 const char* hung=hu_stat[u.uhs];
392 if (hung[0]==' ') {
393 hunger.hide();
394 } else {
395 hunger.setIcon(u.uhs ? p_hungry : p_satiated);
396 hunger.setLabel(hung);
397 hunger.show();
398 }
399 if (Confusion) confused.show(); else confused.hide();
400 if (Sick) {
401 if (u.usick_type & SICK_VOMITABLE) {
402 sick_fp.show();
403 } else {
404 sick_fp.hide();
405 }
406 if (u.usick_type & SICK_NONVOMITABLE) {
407 sick_il.show();
408 } else {
409 sick_il.hide();
410 }
411 } else {
412 sick_fp.hide();
413 sick_il.hide();
414 }
415 if (Blind) {
416 blind.setLabel("Blind");
417 blind.show();
418 } else {
419 blind.hide();
420 }
421 if (Stunned) stunned.show(); else stunned.hide();
422 if (Hallucination) hallu.show(); else hallu.hide();
423 const char* enc=enc_stat[near_capacity()];
424 if (enc[0]==' ' || !enc[0]) {
425 encumber.hide();
426 } else {
427 encumber.setIcon(p_encumber[near_capacity()-1]);
428 encumber.setLabel(enc);
429 encumber.show();
430 }
431 if (u.mtimedone) {
432 buf = nh_capitalize_words(mons[u.umonnum].mname);
433 } else {
434 buf = rank_of(u.ulevel, pl_character[0], ::flags.female);
435 }
436 QString buf2;
437 buf2.sprintf("%s the %s", plname, buf.toLatin1().constData());
438 name.setLabel(buf2, NetHackQtLabelledIcon::NoNum, u.ulevel);
439
440 char buf3[BUFSZ];
441 if (describe_level(buf3)) {
442 dlevel.setLabel(buf3,true);
443 } else {
444 buf.sprintf("%s, level ", dungeons[u.uz.dnum].dname);
445 dlevel.setLabel(buf,(long)::depth(&u.uz));
446 }
447
448 gold.setLabel("Au:", money_cnt(invent));
449
450 if (u.mtimedone) {
451 // You're a monster!
452
453 buf.sprintf("/%d", u.mhmax);
454 hp.setLabel("HP:", u.mh > 0 ? u.mh : 0, buf);
455 level.setLabel("HD:",(long)mons[u.umonnum].mlevel);
456 } else {
457 // You're normal.
458
459 buf.sprintf("/%d", u.uhpmax);
460 hp.setLabel("HP:", u.uhp > 0 ? u.uhp : 0, buf);
461 level.setLabel("Level:",(long)u.ulevel);
462 }
463 buf.sprintf("/%d", u.uenmax);
464 power.setLabel("Pow:", u.uen, buf);
465 ac.setLabel("AC:",(long)u.uac);
466 #ifdef EXP_ON_BOTL
467 if (::flags.showexp) {
468 exp.setLabel("Exp:",(long)u.uexp);
469 } else
470 #endif
471 {
472 exp.setLabel("");
473 }
474 if (u.ualign.type==A_CHAOTIC) {
475 align.setIcon(p_chaotic);
476 text = "Chaotic";
477 } else if (u.ualign.type==A_NEUTRAL) {
478 align.setIcon(p_neutral);
479 text = "Neutral";
480 } else {
481 align.setIcon(p_lawful);
482 text = "Lawful";
483 }
484 align.setLabel(text);
485
486 if (::flags.time) time.setLabel("Time:",(long)moves);
487 else time.setLabel("");
488 #ifdef SCORE_ON_BOTL
489 if (::flags.showscore) {
490 score.setLabel("Score:",(long)botl_score());
491 } else
492 #endif
493 {
494 score.setLabel("");
495 }
496
497 if (first_set)
498 {
499 first_set=false;
500
501 name.highlightWhenChanging();
502 dlevel.highlightWhenChanging();
503
504 str.highlightWhenChanging();
505 dex.highlightWhenChanging();
506 con.highlightWhenChanging();
507 intel.highlightWhenChanging();
508 wis.highlightWhenChanging();
509 cha.highlightWhenChanging();
510
511 gold.highlightWhenChanging();
512 hp.highlightWhenChanging();
513 power.highlightWhenChanging();
514 ac.highlightWhenChanging(); ac.lowIsGood();
515 level.highlightWhenChanging();
516 exp.highlightWhenChanging();
517 align.highlightWhenChanging();
518
519 //time.highlightWhenChanging();
520 score.highlightWhenChanging();
521
522 hunger.highlightWhenChanging();
523 confused.highlightWhenChanging();
524 sick_fp.highlightWhenChanging();
525 sick_il.highlightWhenChanging();
526 blind.highlightWhenChanging();
527 stunned.highlightWhenChanging();
528 hallu.highlightWhenChanging();
529 encumber.highlightWhenChanging();
530 }
531 }
532
533 /*
534 * Turn off hilighted status values after a certain amount of turns.
535 */
checkTurnEvents()536 void NetHackQtStatusWindow::checkTurnEvents()
537 {
538 }
539
540 } // namespace nethack_qt4
541