1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: st_stuff.c 1452 2019-08-03 07:03:27Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2000 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: st_stuff.c,v $
21 // Revision 1.22 2003/08/11 13:50:00 hurdler
22 // go final + translucent HUD + fix spawn in net game
23 //
24 // Revision 1.21 2001/08/20 21:37:35 hurdler
25 // fix palette in splitscreen + hardware mode
26 //
27 // Revision 1.20 2001/08/20 20:40:39 metzgermeister
28 //
29 // Revision 1.19 2001/08/08 20:34:43 hurdler
30 // Big TANDL update
31 //
32 // Revision 1.18 2001/05/16 21:21:14 bpereira
33 // Revision 1.17 2001/04/01 17:35:07 bpereira
34 // Revision 1.16 2001/03/03 06:17:34 bpereira
35 // Revision 1.15 2001/02/24 13:35:21 bpereira
36 // Revision 1.14 2001/02/10 13:05:45 hurdler
37 //
38 // Revision 1.13 2001/01/31 17:14:07 hurdler
39 // Add cv_scalestatusbar in hardware mode
40 //
41 // Revision 1.12 2001/01/25 22:15:44 bpereira
42 // added heretic support
43 //
44 // Revision 1.11 2000/11/02 19:49:37 bpereira
45 //
46 // Revision 1.10 2000/10/04 16:34:51 hurdler
47 // Change a little the presentation of monsters/secrets numbers
48 //
49 // Revision 1.9 2000/10/02 18:25:45 bpereira
50 // Revision 1.8 2000/10/01 10:18:19 bpereira
51 //
52 // Revision 1.7 2000/10/01 01:12:00 hurdler
53 // Add number of monsters and secrets in overlay
54 //
55 // Revision 1.6 2000/09/28 20:57:18 bpereira
56 //
57 // Revision 1.5 2000/09/25 19:28:15 hurdler
58 // Enable Direct3D support as OpenGL
59 //
60 // Revision 1.4 2000/09/21 16:45:09 bpereira
61 // Revision 1.3 2000/08/31 14:30:56 bpereira
62 // Revision 1.2 2000/02/27 00:42:11 hurdler
63 // Revision 1.1.1.1 2000/02/22 20:32:33 hurdler
64 // Initial import into CVS (v1.29 pr3)
65 //
66 //
67 // DESCRIPTION:
68 // Status bar code.
69 // Does the face/direction indicator animatin.
70 // Does palette indicators as well (red pain/berserk, bright pickup)
71 //
72 //-----------------------------------------------------------------------------
73
74 #include "doomincl.h"
75
76 #include "am_map.h"
77
78 #include "g_game.h"
79 #include "m_cheat.h"
80
81 #include "screen.h"
82 #include "r_local.h"
83 #include "p_local.h"
84 #include "p_inter.h"
85 #include "m_random.h"
86
87 #include "st_stuff.h"
88 #include "st_lib.h"
89 #include "i_video.h"
90 #include "v_video.h"
91
92 #include "keys.h"
93
94 #include "z_zone.h"
95 #include "hu_stuff.h"
96 #include "d_main.h"
97
98 #ifdef HWRENDER
99 #include "hardware/hw_drv.h"
100 #include "hardware/hw_main.h"
101 #endif
102
103 // Doom and Heretic use ST_Drawer.
104 // Almost everything else that is ST_ is Doom Only.
105 // Heretic has its own status bar drawer that uses SB_ functions in sb_bar.c.
106 // There is very little shared code, but some sharing attempts are being made.
107
108 //protos
109 static void ST_Create_Widgets(void);
110
111
112 #define FLASH_COLOR 0x72
113
114 //
115 // STATUS BAR DATA
116 //
117
118 // Palette indices.
119 // For damage/bonus red-/gold-shifts
120 #define STARTREDPALS 1
121 #define STARTBONUSPALS 9
122 #define NUMREDPALS 8
123 #define NUMBONUSPALS 4
124 // Radiation suit, green shift.
125 #define RADIATIONPAL 13
126
127 // N/256*100% probability
128 // that the normal face state will change
129 #define ST_FACEPROBABILITY 96
130
131 // For Responder
132 #define ST_TOGGLECHAT KEY_ENTER
133
134 // Location of status bar
135 //added:08-01-98:status bar position changes according to resolution.
136 #define ST_FX 143
137 // This is now dynamic
138 // #define ST_Y stbar_y
139
140 // Number of status faces.
141 #define ST_NUMPAINFACES 5
142 #define ST_NUMSTRAIGHTFACES 3
143 #define ST_NUMTURNFACES 2
144 #define ST_NUMSPECIALFACES 3
145
146 #define ST_FACESTRIDE \
147 (ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES)
148
149 #define ST_NUMEXTRAFACES 2
150
151 #define ST_NUMFACES \
152 (ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES)
153
154 #define ST_TURNOFFSET (ST_NUMSTRAIGHTFACES)
155 #define ST_OUCHOFFSET (ST_TURNOFFSET + ST_NUMTURNFACES)
156 #define ST_EVILGRINOFFSET (ST_OUCHOFFSET + 1)
157 #define ST_RAMPAGEOFFSET (ST_EVILGRINOFFSET + 1)
158 #define ST_GODFACE (ST_NUMPAINFACES*ST_FACESTRIDE)
159 #define ST_DEADFACE (ST_GODFACE+1)
160
161 #define ST_FACESX 143
162 #define ST_FACESY 0
163
164 #define ST_EVILGRINCOUNT (2*TICRATE)
165 #define ST_STRAIGHTFACECOUNT (TICRATE/2)
166 #define ST_TURNCOUNT (1*TICRATE)
167 #define ST_OUCHCOUNT (1*TICRATE)
168 #define ST_RAMPAGEDELAY (2*TICRATE)
169
170 #define ST_MUCHPAIN 20
171
172
173 // Location and size of statistics,
174 // justified according to widget type.
175 // Problem is, within which space? STbar? Screen?
176 // Note: this could be read in by a lump.
177 // Problem is, is the stuff rendered
178 // into a buffer,
179 // or into the frame buffer?
180
181 // AMMO number pos.
182 #define ST_AMMOWIDTH 3
183 #define ST_AMMOX 44
184 #define ST_AMMOY 3
185
186 // HEALTH number pos.
187 #define ST_HEALTHWIDTH 3
188 #define ST_HEALTHX 90
189 #define ST_HEALTHY 3
190
191 // Weapon pos.
192 #define ST_ARMSX 111
193 #define ST_ARMSY 4
194 #define ST_ARMSBGX 104
195 #define ST_ARMSBGY 0
196 #define ST_ARMSXSPACE 12
197 #define ST_ARMSYSPACE 10
198
199 // Frags pos.
200 #define ST_FRAGSX 138
201 #define ST_FRAGSY 3
202 #define ST_FRAGSWIDTH 2
203
204 // ARMOR number pos.
205 #define ST_ARMORWIDTH 3
206 #define ST_ARMORX 221
207 #define ST_ARMORY 3
208
209 // Key icon positions.
210 #define ST_KEYSBOX_X 236
211 #define ST_KEYSBOX_Y 2
212 #define ST_KEYSBOX_W 13
213 #define ST_KEYSBOX_H 30
214 // They appear in a vertical column, so share x positions.
215 #define ST_KEY_WIDTH 6
216 #define ST_KEY_HEIGHT 5
217 #define ST_KEYX 239
218 #define ST_KEYDX 2
219 #define ST_KEYDY 2
220 static uint8_t keybox_y[6] = { 3, 13, 23, 3, 13, 23 };
221 static uint8_t keybox_dual_x[6] =
222 { ST_KEYX-ST_KEYDX, ST_KEYX-ST_KEYDX, ST_KEYX-ST_KEYDX,
223 ST_KEYX+ST_KEYDX, ST_KEYX+ST_KEYDX, ST_KEYX+ST_KEYDX };
224 static uint8_t keybox_dual_y[6] =
225 { 3-ST_KEYDY, 13-ST_KEYDY, 23-ST_KEYDY,
226 3+ST_KEYDY, 13+ST_KEYDY, 23+ST_KEYDY };
227
228 // Ammunition counter, and max ammo, in two columns in status bar.
229 // Max ammo changes when backpack aquired.
230 #define ST_AMMOS_WIDTH 3
231 #define ST_MAXAMMOS_WIDTH 3
232 #define ST_AMMOSX 288
233 #define ST_MAXAMMOSX 314
234 static uint8_t ammobox_y[4] = { 5, 11, 23, 17 };
235
236
237 //faB: unused stuff from the Doom alpha version ?
238 // pistol
239 //#define ST_WEAPON0X 110
240 //#define ST_WEAPON0Y 4
241 // shotgun
242 //#define ST_WEAPON1X 122
243 //#define ST_WEAPON1Y 4
244 // chain gun
245 //#define ST_WEAPON2X 134
246 //#define ST_WEAPON2Y 4
247 // missile launcher
248 //#define ST_WEAPON3X 110
249 //#define ST_WEAPON3Y 13
250 // plasma gun
251 //#define ST_WEAPON4X 122
252 //#define ST_WEAPON4Y 13
253 // bfg
254 //#define ST_WEAPON5X 134
255 //#define ST_WEAPON5Y 13
256
257 // WPNS title
258 //#define ST_WPNSX 109
259 //#define ST_WPNSY 23
260
261 // DETH title
262 //#define ST_DETHX 109
263 //#define ST_DETHY 23
264
265 //Incoming messages window location
266 // #define ST_MSGTEXTX (viewwindowx)
267 // #define ST_MSGTEXTY (viewwindowy+viewheight-18)
268 //#define ST_MSGTEXTX 0
269 //#define ST_MSGTEXTY 0 //added:08-01-98:unused
270 // Dimensions given in characters.
271 #define ST_MSGWIDTH 52
272 // Or shall I say, in lines?
273 #define ST_MSGHEIGHT 1
274
275 #define ST_OUTTEXTX 0
276 #define ST_OUTTEXTY 6
277
278 // Width, in characters again.
279 #define ST_OUTWIDTH 52
280 // Height, in lines.
281 #define ST_OUTHEIGHT 1
282
283 #if 0
284 // UNUSED
285 #define ST_MAPWIDTH \
286 (strlen(mapnames[(gameepisode-1)*9+(gamemap-1)]))
287
288 //added:24-01-98:unused ?
289 //#define ST_MAPTITLEX (vid.width - ST_MAPWIDTH * ST_CHATFONTWIDTH)
290 #endif
291
292 #define ST_MAPTITLEY 0
293 #define ST_MAPHEIGHT 1
294
295
296 int stbar_height = ST_HEIGHT;
297 int stbar_y = BASEVIDHEIGHT - ST_HEIGHT;
298 int stbar_x = 0;
299 int stbar_scalex, stbar_scaley;
300 int stbar_fg = FG | V_TRANSLUCENTPATCH;
301
302
303 //added:02-02-98: set true if widgets coords need to be recalculated
304 // Set by functions that change the window or status bar size.
305 boolean stbar_recalc;
306
307 // ST_Start() has just been called
308 boolean st_force_refresh;
309
310 // facegraphics loaded
311 static byte facegraphics_loaded = false;
312
313 // used for timing
314 static unsigned int st_clock;
315
316 // used for making messages go away
317 static int st_msgcounter=0;
318
319 // used when in chat
320 static st_chatstateenum_t st_chatstate;
321
322 // whether left-side main status bar is active
323 boolean stbar_on;
324
325 // whether status bar chat is active
326 static boolean st_chat;
327
328 // value of st_chat before message popped up
329 static boolean st_oldchat;
330
331 // whether chat window has the cursor on
332 static boolean st_cursor_on;
333
334 // !deathmatch
335 static boolean st_not_deathmatch;
336
337 // main bar left
338 static patch_t* sbar = NULL;
339
340 // 0-9, tall numbers, minus at [10], percent at [11].
341 static patch_t* tallnum[12];
342
343 // 0-9, short, yellow (,different!) numbers
344 static patch_t* shortnum[12];
345
346 // 3 key-cards, 3 skulls
347 static patch_t* keys[NUMCARDS];
348
349 // face status patches
350 static patch_t* faces[ST_NUMFACES];
351
352 // face background
353 static patch_t* faceback;
354
355 // main bar right
356 static patch_t* armsbg;
357
358 // weapon ownership patches
359 static patch_t* arms[6][2];
360
361 // ready-weapon widget
362 static st_number_t w_ready;
363
364 // in deathmatch only, summary of frags stats
365 static st_number_t w_frags;
366
367 // health widget
368 static st_number_t w_health;
369
370 // arms background
371 static st_binicon_t w_armsbg;
372
373 // weapon ownership widgets
374 static st_multicon_t w_arms[6];
375
376 // face status widget
377 static st_multicon_t w_faces;
378
379 // keycard widgets
380 static st_multicon_t w_keyboxes[6];
381
382 // armor widget
383 static st_number_t w_armor;
384
385 // ammo widgets
386 static st_number_t w_ammo[4];
387
388 // max ammo widgets
389 static st_number_t w_maxammo[4];
390
391
392 // ------------------------------------------
393 // Status bar state.
394 // Doom only.
395 // Single player only (can handle only one status bar).
396 // Splitscreen must use status overlay, which does not have state.
397
398 // Status bar player, also used by Heretic status display
399 player_t* st_plyr = NULL;
400
401 // number of frags so far in deathmatch
402 static int st_fragscount;
403
404 // used to use appopriately pained face
405 static int st_oldhealth = -1;
406
407 // Doom only, but has room for Heretic weapons.
408 // used for evil grin
409 static boolean oldweaponsowned[NUMWEAPONS];
410
411 // count until face changes
412 static int st_facecount = 0;
413
414 // current face index, used by w_faces
415 static int st_faceindex = 0;
416
417 // holds key-type for each key box on bar
418 byte st_card; // card state displayed (Doom, Heretic)
419 static byte st_num_keyboxes;
420 static int keyboxes[6]; // 0..3 keycards skulls, 4..6 dual display
421
422 // a random number per tick
423 static int st_randomnumber;
424
425
426 // ------------------------------------------
427 // Doom status overlay variables
428 // ------------------------------------------
429
430 // Doom only.
431 // Icons for status bar.
432 static lumpnum_t sbo_health, sbo_frags, sbo_armor;
433 static lumpnum_t sbo_ammo[NUMWEAPONS];
434
435
436 // ------------------------------------------
437 // Doom status bar
438 // ------------------------------------------
439
440 //
441 // STATUS BAR CODE
442 //
443
444
445 // Single player only, when stbar_on.
446 // Global : st_plyr
ST_Refresh_Background(void)447 static void ST_Refresh_Background( void )
448 {
449 byte * colormap;
450
451 // Draw background, with status bar flag settings
452 V_SetupDraw( BG | (stbar_fg & ~V_SCREENMASK) );
453
454 // software mode copies patch to BG buffer,
455 // hardware modes directly draw the statusbar to the screen
456 V_DrawScaledPatch(stbar_x, stbar_y, sbar);
457
458 // draw the faceback for the statusbarplayer
459 colormap = (st_plyr->skincolor) ?
460 SKIN_TO_SKINMAP( st_plyr->skincolor )
461 : & reg_colormaps[0]; // default green skin
462
463 V_DrawMappedPatch (stbar_x+ST_FX, stbar_y, faceback, colormap);
464
465 // copy the statusbar buffer to the screen
466 if( rendermode == render_soft )
467 V_CopyRect(0, vid.height-stbar_height, BG, vid.width, stbar_height, 0, vid.height-stbar_height, FG);
468 }
469
470
471 // Respond to keyboard input events,
472 // intercept cheats.
ST_Responder(event_t * ev)473 boolean ST_Responder (event_t* ev)
474 {
475
476 if (ev->type == ev_keyup)
477 {
478 // Filter automap on/off : activates the statusbar while automap is active
479 if( (ev->data1 & 0xffff0000) == AM_MSGHEADER )
480 {
481 switch(ev->data1)
482 {
483 case AM_MSGENTERED:
484 st_force_refresh = true; // force refresh of status bar
485 break;
486
487 case AM_MSGEXITED:
488 break;
489 }
490 }
491
492 }
493 return false;
494 }
495
496 // Global : st_plyr
ST_calcPainOffset(void)497 static int ST_calcPainOffset(void)
498 {
499 // [WDJ] FIXME : This thrashes when splitplayer, but it is correct.
500 static int st_pain;
501 static int oldhealth = -1;
502
503 int health = st_plyr->health > 100 ? 100 : st_plyr->health;
504 if (health != oldhealth)
505 {
506 st_pain = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101);
507 oldhealth = health;
508 }
509 return st_pain;
510 }
511
512
513 //
514 // This is a not-very-pretty routine which handles
515 // the face states and their timing.
516 // the precedence of expressions is:
517 // dead > evil grin > turned head > straight ahead
518 //
519 // Doom only.
520 // Single Player status only.
521 // Global : st_plyr
ST_updateFaceWidget(void)522 static void ST_updateFaceWidget(void)
523 {
524 static int fw_last_attackdown_cnt = -1;
525 static int fw_priority = 0; // priority of face effects
526
527 player_t * plyr = st_plyr;
528 int i;
529 angle_t badguyangle;
530 angle_t diffang;
531 boolean doevilgrin;
532
533 // Highest priority first
534 if (fw_priority < 10)
535 {
536 if (!plyr->health)
537 {
538 // dead
539 fw_priority = 9;
540 st_faceindex = ST_DEADFACE;
541 st_facecount = 1;
542 }
543 }
544
545 if (fw_priority < 9)
546 {
547 if (plyr->bonuscount)
548 {
549 // picking up bonus
550 doevilgrin = false;
551
552 // Doom only.
553 for (i=0;i<NUMWEAPONS;i++)
554 {
555 if (oldweaponsowned[i] != plyr->weaponowned[i])
556 {
557 doevilgrin = true;
558 oldweaponsowned[i] = plyr->weaponowned[i];
559 }
560 }
561 if (doevilgrin)
562 {
563 // evil grin if just picked up weapon
564 fw_priority = 8; // allow retrigger evil grin
565 st_facecount = ST_EVILGRINCOUNT;
566 st_faceindex = ST_calcPainOffset() + ST_EVILGRINOFFSET;
567 }
568 }
569
570 }
571
572 if (fw_priority < 8)
573 {
574 if (plyr->damagecount
575 && plyr->attacker
576 && plyr->attacker != plyr->mo)
577 {
578 // being attacked
579 fw_priority = 7; // allow attack test retrigger
580
581 // [WDJ] Ouch-face when damage>20, fix from DoomWiki, same as prboom
582 // if (plyr->health - st_oldhealth > ST_MUCHPAIN) // orig bug
583 if (st_oldhealth - plyr->health > ST_MUCHPAIN)
584 {
585 st_facecount = ST_TURNCOUNT;
586 st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET;
587 fw_priority = 8; // [WDJ] Necessary to keep ouchface visible
588 }
589 else
590 {
591 badguyangle = R_PointToAngle2(plyr->mo->x,
592 plyr->mo->y,
593 plyr->attacker->x,
594 plyr->attacker->y);
595
596 if (badguyangle > plyr->mo->angle)
597 {
598 // whether right or left
599 diffang = badguyangle - plyr->mo->angle;
600 i = diffang > ANG180;
601 }
602 else
603 {
604 // whether left or right
605 diffang = plyr->mo->angle - badguyangle;
606 i = diffang <= ANG180;
607 } // confusing, aint it?
608
609
610 st_facecount = ST_TURNCOUNT;
611 st_faceindex = ST_calcPainOffset();
612
613 if (diffang < ANG45)
614 {
615 // head-on
616 st_faceindex += ST_RAMPAGEOFFSET;
617 }
618 else if (i)
619 {
620 // turn face right
621 st_faceindex += ST_TURNOFFSET;
622 }
623 else
624 {
625 // turn face left
626 st_faceindex += ST_TURNOFFSET+1;
627 }
628 }
629 }
630 }
631
632 if (fw_priority < 7)
633 {
634 // getting hurt because of your own damn stupidity
635 if (plyr->damagecount)
636 {
637 // [WDJ] Ouch-face when damage>20, fix from DoomWiki, same as prboom
638 // if (plyr->health - st_oldhealth > ST_MUCHPAIN)
639 if (st_oldhealth - plyr->health > ST_MUCHPAIN)
640 {
641 fw_priority = 7; // no pain retrigger
642 st_facecount = ST_TURNCOUNT;
643 st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET;
644 }
645 else
646 {
647 fw_priority = 6; // allow pain test retrigger
648 st_facecount = ST_TURNCOUNT;
649 st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET;
650 }
651 }
652 }
653
654 if (fw_priority < 6)
655 {
656 // rapid firing
657 if (plyr->attackdown)
658 {
659 if (fw_last_attackdown_cnt < 0)
660 fw_last_attackdown_cnt = ST_RAMPAGEDELAY;
661 else if (--fw_last_attackdown_cnt == 0)
662 {
663 fw_last_attackdown_cnt = 1;
664 fw_priority = 5; // continual retrigger, no timer
665 st_facecount = 1;
666 st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET;
667 }
668 }
669 else
670 fw_last_attackdown_cnt = -1;
671 }
672
673 if (fw_priority < 5)
674 {
675 // invulnerability
676 if ((plyr->cheats & CF_GODMODE)
677 || plyr->powers[pw_invulnerability])
678 {
679 fw_priority = 4; // continual retrigger, no timer
680 st_facecount = 1;
681 st_faceindex = ST_GODFACE;
682 }
683 }
684
685 // look left or look right if the facecount has timed out
686 if (st_facecount == 0)
687 {
688 fw_priority = 0; // clear
689 st_faceindex = ST_calcPainOffset() + (st_randomnumber % 3);
690 st_facecount = ST_STRAIGHTFACECOUNT;
691 }
692
693 st_facecount--;
694 }
695
ST_SameTeam(player_t * a,player_t * b)696 boolean ST_SameTeam(player_t *a,player_t *b)
697 {
698 switch( cv_teamplay.EV ) {
699 case 0 : return false;
700 case 1 : return (a->skincolor == b->skincolor);
701 case 2 : return (a->skin == b->skin);
702 }
703 return false;
704 }
705
706 // count the frags of the playernum player
707 //Fab: made as a tiny routine so ST_overlayDrawer() can use it
708 //Boris: rename ST_countFrags in to ST_PlayerFrags for use anytime
709 // when we need the frags
ST_PlayerFrags(int playernum)710 int ST_PlayerFrags (int playernum)
711 {
712 player_t * player = &players[playernum];
713 int i,frags;
714
715 frags = player->addfrags;
716 for (i=0 ; i<MAXPLAYERS ; i++)
717 {
718 if( ((cv_teamplay.EV == 0) && i != playernum)
719 || (cv_teamplay.EV && !ST_SameTeam(&players[i], player)) )
720 frags += player->frags[i];
721 else
722 frags -= player->frags[i];
723 }
724
725 return frags;
726 }
727
728
729 // Doom only.
730 // Single player status bar only.
731 // Global : st_plyr
732 // Called by: ST_Ticker
ST_updateWidgets(void)733 static void ST_updateWidgets(void)
734 {
735 static int largeammo = NON_NUMBER; // means "n/a"
736
737 int i;
738 player_t * plyr = st_plyr;
739
740 #ifdef PARANOIA
741 if(!plyr) return; // not likely, but have soft fail
742 #endif
743 // must redirect the pointer if the ready weapon has changed.
744 // if (w_ready.data != plyr->readyweapon)
745 // {
746 if (plyr->weaponinfo[plyr->readyweapon].ammo == am_noammo)
747 w_ready.num = &largeammo;
748 else
749 w_ready.num = &plyr->ammo[plyr->weaponinfo[plyr->readyweapon].ammo];
750 //{
751 // static int tic=0;
752 // static int dir=-1;
753 // if (!(tic&15))
754 // plyr->ammo[weaponinfo[plyr->readyweapon].ammo]+=dir;
755 // if (plyr->ammo[weaponinfo[plyr->readyweapon].ammo] == -100)
756 // dir = 1;
757 // tic++;
758 // }
759 // w_ready.data = plyr->readyweapon;
760
761 // if (*w_ready.on)
762 // STlib_updateNum(&w_ready, true);
763 // refresh weapon change
764 // }
765
766 // update keycard multiple widgets
767 if( plyr->cards != st_card )
768 {
769 // fraggle script can take a key, so keyboxes must not be sticky.
770 if( ~plyr->cards & st_card )
771 {
772 st_force_refresh = true; // a card was taken
773 st_card = 0;
774 }
775 if( (plyr->cards & 0x07) && (plyr->cards & 0x38) )
776 {
777 // Have both keycards and skulls.
778 if(((st_card & 0x07) == 0) || ((st_card & 0x38) == 0))
779 {
780 // Enable display of both skulls and keycards.
781 st_num_keyboxes = 6;
782 // Shift keybox[ 0..6 ] positions, into two vertical columns
783 // Skulls will now be in [3..6]
784 for( i=0; i<6; i++ )
785 {
786 keyboxes[i] = -1; // clear previous recorded skulls
787 w_keyboxes[i].x = stbar_x + keybox_dual_x[i],
788 w_keyboxes[i].y = stbar_y + keybox_dual_y[i],
789 w_keyboxes[i].command = STLIB_REFRESH; // to clear old card positions
790 }
791 }
792 }
793 st_card = plyr->cards;
794
795 for (i=0;i<3;i++)
796 {
797 // keycards
798 keyboxes[i] = ((st_card >> i) & 0x01) ? i : -1;
799
800 // skull keys
801 if ((st_card >> i) & 0x08)
802 {
803 keyboxes[i+3] = i+3; // dual display
804 if( st_num_keyboxes == 3 )
805 keyboxes[i] = i+3; // only skull display
806 }
807 else
808 {
809 keyboxes[i+3] = -1; // skull off in dual display
810 }
811 }
812 }
813
814 // refresh everything if this is him coming back to life
815 ST_updateFaceWidget();
816 st_oldhealth = plyr->health;
817
818 // used by the w_armsbg widget
819 st_not_deathmatch = ! deathmatch;
820
821 st_fragscount = ST_PlayerFrags(statusbarplayer);
822
823 // get rid of chat window if up because of message
824 if (!--st_msgcounter)
825 st_chat = st_oldchat;
826 }
827
828 static boolean st_stopped = true;
829
830 // Global : st_plyr
ST_Ticker(void)831 void ST_Ticker (void)
832 {
833 if( st_stopped )
834 return;
835
836 if( EN_heretic )
837 {
838 SB_Heretic_Ticker();
839 return;
840 }
841
842 // Doom only.
843 st_clock++;
844 st_randomnumber = M_Random();
845
846 // Update immediately upon display changes.
847 if((cv_viewsize.value<11) || automapactive )
848 ST_updateWidgets();
849 }
850
851 // These are used by Heretic too.
852 int st_palette = 0;
853 byte pickupflash_table[ 4 ] = { 6, 5, 4, 3 }; // Vanilla=[3]=3
854
855 // Single and SplitPlayer, Software and Hardware Render.
856 // Called by: R_SetupFrame, from R_RenderPlayerView, HWR_RenderPlayerView
ST_doPaletteStuff(player_t * plyr)857 void ST_doPaletteStuff( player_t * plyr )
858 {
859 int palette;
860 int red_cnt;
861
862 red_cnt = plyr->damagecount;
863
864 if (plyr->powers[pw_strength])
865 {
866 // slowly fade the berzerk out
867 int bzc = 12 - (plyr->powers[pw_strength]>>6);
868
869 if (bzc > red_cnt)
870 red_cnt = bzc;
871 }
872
873 if (red_cnt)
874 {
875 palette = STARTREDPALS + ((red_cnt+7)>>3);
876
877 if (palette >= (STARTREDPALS+NUMREDPALS))
878 palette = STARTREDPALS+NUMREDPALS-1;
879 }
880 else
881 if (plyr->bonuscount && (cv_pickupflash.EV>=2))
882 {
883 // Pickup object palette flash.
884 palette = STARTBONUSPALS
885 + ((plyr->bonuscount+7)>>(pickupflash_table[cv_pickupflash.EV]));
886
887 if (palette >= (STARTBONUSPALS+NUMBONUSPALS))
888 palette = STARTBONUSPALS+NUMBONUSPALS-1;
889 }
890 else
891 if ( plyr->powers[pw_ironfeet] > BLINKTHRESHOLD
892 || plyr->powers[pw_ironfeet]&0x08) // blink rate
893 palette = RADIATIONPAL;
894 else
895 palette = 0;
896
897
898 //added:28-02-98:quick hack underwater palette
899 /*if (plyr->mo &&
900 (plyr->mo->z + (((unsigned int)cv_viewheight.EV)<<FRACBITS) < plyr->mo->waterz) )
901 palette = RADIATIONPAL;*/
902
903 if (palette != st_palette)
904 {
905 st_palette = palette;
906
907 #ifdef HWRENDER
908 if( EN_HWR_flashpalette ) // some hardware draw can flash palette
909 {
910 // Imitate the palette flash
911 //debug_Printf("palette: %d\n", palette);
912 HWR_SetFlashPalette( palette );
913 }
914 else
915 #endif
916 {
917 // Splitscreen cannot use palette effects when 8bit palette draw,
918 // but other draw modes can.
919 if( ((cv_splitscreen.EV == 0) || (vid.drawmode != DRAW8PAL))
920 || !palette )
921 V_SetPalette (palette);
922 }
923 }
924 }
925
926 // Set status palette 0 for camera.
ST_Palette0(void)927 void ST_Palette0( void )
928 {
929 if (st_palette)
930 {
931 #ifdef HWRENDER
932 if ( EN_HWR_flashpalette )
933 {
934 // Imitate the palette flash
935 HWR_SetFlashPalette( 0 );
936 }
937 else
938 #endif
939 {
940 V_SetPalette(0);
941 }
942
943 // Record it as the status palette.
944 st_palette = 0;
945 }
946 }
947
948
949 // Single player only, when stbar_on.
950 // Called by: ST_Drawer, when stbar_on.
951 // STlib refresh enable is now setup by caller.
952 // Only called when stbar_on == true, so more tests are pointless.
ST_Draw_Widgets(void)953 static void ST_Draw_Widgets( void )
954 {
955 int i;
956 player_t * plyr;
957
958 // Draw stbar_fg, screen0 status bar
959 V_SetupDraw( stbar_fg ); // for all STlib
960
961 if( cv_pickupflash.EV == 1 )
962 {
963 plyr = st_plyr;
964 // Pickup flash on the status bar.
965 if( plyr->ammo_pickup )
966 {
967 w_ready.command = STLIB_FLASH;
968 }
969 if( plyr->armor_pickup )
970 {
971 w_armor.command = STLIB_FLASH;
972 }
973 if( plyr->health_pickup )
974 {
975 w_health.command = STLIB_FLASH;
976 }
977
978 if( plyr->key_pickup )
979 {
980 // Flash entire box.
981 // Do not know which one was picked up.
982 V_DrawScaledFill(stbar_x + ST_KEYSBOX_X, stbar_y + ST_KEYSBOX_Y,
983 ST_KEYSBOX_W, ST_KEYSBOX_H, FLASH_COLOR);
984 // Prevent the key icons from performing background refresh.
985 for (i=0;i<st_num_keyboxes;i++)
986 w_keyboxes[i].command = STLIB_FLASH;
987 }
988 else if( w_keyboxes[0].command == STLIB_FLASH_CLEAR
989 && ( rendermode == render_soft ) )
990 {
991 // Restore the background
992 V_CopyRect(stbar_x + ST_KEYSBOX_X, stbar_y + ST_KEYSBOX_Y, BG,
993 ST_KEYSBOX_W, ST_KEYSBOX_H,
994 stbar_x + ST_KEYSBOX_X, stbar_y + ST_KEYSBOX_Y, stbar_fg);
995 // Refresh the key icons.
996 for (i=0;i<st_num_keyboxes;i++)
997 w_keyboxes[i].command = STLIB_REFRESH;
998 }
999 }
1000
1001 STlib_updateNum(&w_ready); // current weapon ammo
1002
1003 for (i=0;i<4;i++)
1004 {
1005 STlib_updateNum(&w_ammo[i]);
1006 STlib_updateNum(&w_maxammo[i]);
1007 }
1008
1009 STlib_updatePercent(&w_health);
1010 STlib_updatePercent(&w_armor);
1011
1012 STlib_updateBinIcon(&w_armsbg);
1013
1014 if( deathmatch )
1015 {
1016 // frags on
1017 STlib_updateNum(&w_frags);
1018 }
1019 else
1020 {
1021 // arms on
1022 for (i=0;i<6;i++)
1023 STlib_updateMultIcon(&w_arms[i]);
1024 }
1025
1026 STlib_updateMultIcon(&w_faces);
1027
1028 for (i=0;i<st_num_keyboxes;i++)
1029 STlib_updateMultIcon(&w_keyboxes[i]);
1030 }
1031
1032
ST_Invalidate(void)1033 void ST_Invalidate(void)
1034 {
1035 st_force_refresh = true;
1036 st_card = 0;
1037 }
1038
1039 static void ST_overlayDrawer ( byte status_position, player_t * plyr );
1040
1041 // Doom and Heretic.
1042 // For player, and both splitscreen players.
1043 // Called by D_Display
ST_Drawer(boolean refresh)1044 void ST_Drawer ( boolean refresh )
1045 {
1046 // Respond to these changes immediately, so cannot be in any setup.
1047 stbar_on = (cv_viewsize.value<11) || automapactive;
1048
1049 if( EN_heretic )
1050 {
1051 SB_Heretic_Drawer( refresh );
1052 return;
1053 }
1054
1055 // Doom Only.
1056 //added:30-01-98:force a set of the palette by doPaletteStuff()
1057 if (vid.recalc)
1058 st_palette = -1;
1059
1060 // Player status palette interactions moved to R_SetupFrame
1061 // so that Splitplayer can be handled.
1062
1063 // Splitplayer restricted to overlay or status bar off.
1064 if( stbar_on )
1065 {
1066 // Single player only (st_plyr), keeping state.
1067 if (st_force_refresh || refresh || stbar_recalc )
1068 {
1069 // after ST_Start(), screen refresh needed, or vid mode change
1070 if (stbar_recalc) //recalc widget coords after vid mode change
1071 {
1072 ST_Create_Widgets ();
1073 stbar_recalc = false;
1074 }
1075 st_force_refresh = false;
1076 st_card = 0;
1077
1078 // This is not executed as frequently as drawing, so it is more
1079 // complicated, in order to keep ST_Draw_Widgets simpler.
1080
1081 // Draw status bar background to BG buffer
1082 ST_Refresh_Background(); // st_plyr
1083
1084 stlib_enable_erase = (rendermode == render_soft);
1085 stlib_force_refresh = true; // stlib refreshes from BG buffer.
1086 }
1087 else
1088 {
1089 // Otherwise, update as little as possible
1090 stlib_force_refresh = false;
1091 }
1092 // Update all widgets using stlib.
1093 ST_Draw_Widgets();
1094 }
1095 else if( st_overlay_on )
1096 {
1097 // Overlay status over screen.
1098 // Any minimal state kept, must be per splitscreen (see hardware).
1099 // Does not use stlib.
1100 if( cv_splitscreen.EV )
1101 {
1102 if((vid.drawmode != DRAW8PAL) && st_palette != 0 )
1103 ST_Palette0();
1104
1105 // player 1 is upper
1106 ST_overlayDrawer ( 1, displayplayer_ptr );
1107 if( displayplayer2_ptr )
1108 {
1109 // player 2 is lower
1110 ST_overlayDrawer( 0, displayplayer2_ptr );
1111 }
1112 }
1113 else if( !playerdeadview )
1114 {
1115 ST_overlayDrawer( 0, displayplayer_ptr );
1116 }
1117 }
1118 }
1119
1120
1121 byte st_patches_loaded = 0;
1122 load_patch_t st_patches[13] =
1123 {
1124 { &armsbg, "STARMS" }, // arms background
1125 { &sbar, "STBAR" }, // status bar background bits
1126 { NULL, NULL }
1127 };
1128
1129
1130 // Called by ST_Init, SCR_SetMode
ST_Load_Graphics(void)1131 void ST_Load_Graphics(void)
1132 {
1133 int i;
1134 // [Stylinski] Compiler complains of possible buffer overrun, requires [10].
1135 char namebuf[12];
1136 // [WDJ] all ST graphics are loaded endian fixed
1137 // [WDJ] Lock the status bar graphics against other texture users.
1138
1139 if( EN_heretic )
1140 {
1141 SB_Heretic_Load_Graphics();
1142 return;
1143 }
1144
1145 st_patches_loaded = 1;
1146 load_patch_list( st_patches );
1147
1148 // Load the numbers, tall and short
1149 for (i=0;i<10;i++)
1150 {
1151 sprintf(namebuf, "STTNUM%d", i);
1152 tallnum[i] = W_CachePatchName(namebuf, PU_LOCK_SB);
1153
1154 sprintf(namebuf, "STYSNUM%d", i);
1155 shortnum[i] = W_CachePatchName(namebuf, PU_LOCK_SB);
1156 }
1157 tallnum[10] = W_CachePatchName("STTMINUS", PU_LOCK_SB);
1158 tallnum[11] = W_CachePatchName("STTPRCNT", PU_LOCK_SB);
1159 shortnum[10] = NULL; // has no minus
1160 shortnum[11] = NULL; // has no percent
1161
1162
1163 // key cards
1164 // FreeDoom and DoomII have STKEYS 0..5.
1165 for (i=0;i<NUMCARDS;i++)
1166 {
1167 sprintf(namebuf, "STKEYS%d", i);
1168 keys[i] = W_CachePatchName(namebuf, PU_LOCK_SB);
1169 }
1170
1171 // arms ownership widgets
1172 for (i=0;i<6;i++)
1173 {
1174 sprintf(namebuf, "STGNUM%d", i+2);
1175
1176 // gray #
1177 arms[i][0] = W_CachePatchName(namebuf, PU_LOCK_SB);
1178
1179 // yellow #
1180 arms[i][1] = shortnum[i+2]; // shared patch
1181 }
1182
1183 // the original Doom uses 'STF' as base name for all face graphics
1184 ST_Load_FaceGraphics ("STF");
1185 }
1186
1187
1188 // made separate so that skins code can reload custom face graphics
ST_Load_FaceGraphics(const char * facestr)1189 void ST_Load_FaceGraphics (const char *facestr)
1190 {
1191 lumpnum_t ln;
1192 int i,j;
1193 int facenum;
1194 char namelump[9];
1195 char* namebuf;
1196 // [WDJ] all ST graphics are loaded endian fixed
1197
1198 //hack: make sure base face name is no more than 3 chars
1199 // bug: core dump fixed 19990220 by Kin
1200 // [WDJ] Cannot modify facestr.
1201 strncpy (namelump, facestr, 3); // copy base name
1202 namelump[3] = '\0';
1203 // namebuf points after base face name, for appending to base name
1204 namebuf = namelump;
1205 while (*namebuf>' ') namebuf++;
1206
1207 // face states
1208 facenum = 0;
1209 for (i=0;i<ST_NUMPAINFACES;i++)
1210 {
1211 for (j=0;j<ST_NUMSTRAIGHTFACES;j++)
1212 {
1213 sprintf(namebuf, "ST%d%d", i, j);
1214 faces[facenum++] = W_CachePatchName(namelump, PU_LOCK_SB);
1215 }
1216 sprintf(namebuf, "TR%d0", i); // turn right
1217 faces[facenum++] = W_CachePatchName(namelump, PU_LOCK_SB);
1218 sprintf(namebuf, "TL%d0", i); // turn left
1219 faces[facenum++] = W_CachePatchName(namelump, PU_LOCK_SB);
1220 sprintf(namebuf, "OUCH%d", i); // ouch!
1221 faces[facenum++] = W_CachePatchName(namelump, PU_LOCK_SB);
1222 sprintf(namebuf, "EVL%d", i); // evil grin ;)
1223 faces[facenum++] = W_CachePatchName(namelump, PU_LOCK_SB);
1224 sprintf(namebuf, "KILL%d", i); // pissed off
1225 faces[facenum++] = W_CachePatchName(namelump, PU_LOCK_SB);
1226 }
1227 strcpy (namebuf, "GOD0");
1228 faces[facenum++] = W_CachePatchName(namelump, PU_LOCK_SB);
1229 strcpy (namebuf, "DEAD0");
1230 faces[facenum++] = W_CachePatchName(namelump, PU_LOCK_SB);
1231
1232 // face backgrounds for different player colors
1233 //added:08-02-98: uses only STFB0, which is remapped to the right
1234 // colors using the player translation tables, so if
1235 // you add new player colors, it is automatically
1236 // used for the statusbar.
1237 strcpy (namebuf, "B0");
1238 ln = W_CheckNumForName(namelump);
1239 if( VALID_LUMP( ln ) )
1240 faceback = W_CachePatchNum( ln, PU_LOCK_SB );
1241 else
1242 faceback = W_CachePatchName("STFB0", PU_LOCK_SB);
1243
1244 ST_Invalidate();
1245 facegraphics_loaded = true;
1246 }
1247
1248
ST_Release_Graphics(void)1249 void ST_Release_Graphics(void)
1250 {
1251 int i;
1252
1253 if( EN_heretic )
1254 {
1255 SB_Heretic_Release_Graphics();
1256 return;
1257 }
1258
1259 //faB: GlidePatch_t are always purgeable
1260 if( st_patches_loaded )
1261 {
1262 st_patches_loaded = 0;
1263 release_patch_list( st_patches );
1264
1265 // unload the numbers, tall and short
1266 release_patch_array( tallnum, 12 );
1267 release_patch_array( shortnum, 10 );
1268
1269 // unload gray #'s
1270 for (i=0;i<6;i++)
1271 W_release_patch( arms[i][0] );
1272
1273 // unload the key cards
1274 release_patch_array( keys, NUMCARDS );
1275 }
1276
1277 ST_Release_FaceGraphics ();
1278 }
1279
1280 // made separate so that skins code can reload custom face graphics
1281 // Called by SetPlayerSkin, ST_Release_Graphics
ST_Release_FaceGraphics(void)1282 void ST_Release_FaceGraphics (void)
1283 {
1284 //faB: MipPatch_t are always purgeable
1285 if( facegraphics_loaded )
1286 {
1287 facegraphics_loaded = false;
1288 release_patch_array( faces, ST_NUMFACES );
1289
1290 // face background
1291 W_release_patch( faceback );
1292 }
1293 }
1294
1295
1296
1297 // Doom only.
ST_init_stbar(void)1298 static void ST_init_stbar(void)
1299 {
1300
1301 int i;
1302
1303 st_force_refresh = true;
1304
1305 //added:16-01-98:'link' the statusbar display to a player, which could be
1306 // another player than consoleplayer, for example, when you
1307 // change the view in a multiplayer demo with F12.
1308 if (singledemo)
1309 statusbarplayer = displayplayer;
1310 else
1311 statusbarplayer = consoleplayer;
1312
1313 // Single player status state init.
1314 st_plyr = &players[statusbarplayer];
1315
1316 st_clock = 0;
1317 st_chatstate = StartChatState;
1318
1319 stbar_on = true; // ST_Drawer clears it for Splitscreen
1320 st_oldchat = st_chat = false;
1321 st_cursor_on = false;
1322
1323 st_faceindex = 0;
1324 st_palette = -1;
1325
1326 st_oldhealth = -1;
1327
1328 // Doom only.
1329 for (i=0;i<NUMWEAPONS;i++)
1330 oldweaponsowned[i] = st_plyr->weaponowned[i];
1331
1332 st_card = 0; // no keys
1333 st_num_keyboxes = 3;
1334 for (i=0;i<6;i++)
1335 keyboxes[i] = -1;
1336
1337 }
1338
1339
ST_CalcPos(void)1340 void ST_CalcPos(void)
1341 {
1342 if( cv_scalestatusbar.EV || cv_viewsize.value>=11 )
1343 {
1344 // large scaled status bar
1345 stbar_fg = FG | V_SCALEPATCH | V_SCALESTART | V_TRANSLUCENTPATCH;
1346 stbar_scalex = vid.dupx;
1347 stbar_scaley = vid.dupy;
1348
1349 #ifdef HWRENDER
1350 if( rendermode != render_soft )
1351 {
1352 stbar_x = 0;
1353 stbar_y = BASEVIDHEIGHT - stbar_height/vid.fdupy;
1354 }
1355 else
1356 #endif
1357
1358 {
1359 stbar_x = ((vid.width - ST_WIDTH*vid.dupx)>>1)/vid.dupx;
1360 stbar_y = (vid.height - stbar_height)/vid.dupy;
1361 }
1362 }
1363 else
1364 {
1365 // smaller unscaled status bar in center
1366 stbar_fg = FG | V_NOSCALE | V_TRANSLUCENTPATCH;
1367 stbar_scalex = stbar_scaley = 1;
1368 stbar_x = (vid.width - ST_WIDTH)>>1; // center
1369 stbar_y = vid.height - stbar_height;
1370 }
1371 }
1372
1373 // Single player init.
1374 // Also can be called at init of Splitscreen game.
1375 //added:30-01-98: NOTE: this is called at any level start, view change,
1376 // and after vid mode change.
1377 static
ST_Create_Widgets(void)1378 void ST_Create_Widgets(void)
1379 {
1380 int i;
1381
1382 ST_CalcPos();
1383
1384 // ready weapon ammo
1385 STlib_initNum(&w_ready,
1386 stbar_x + ST_AMMOX,
1387 stbar_y + ST_AMMOY,
1388 tallnum,
1389 &st_plyr->ammo[st_plyr->weaponinfo[st_plyr->readyweapon].ammo],
1390 ST_AMMOWIDTH );
1391
1392 // the last weapon type
1393 // w_ready.data = st_plyr->readyweapon;
1394
1395 // health percentage
1396 STlib_initNum(&w_health,
1397 stbar_x + ST_HEALTHX,
1398 stbar_y + ST_HEALTHY,
1399 tallnum,
1400 &st_plyr->health,
1401 3 );
1402
1403 // arms background
1404 STlib_initBinIcon(&w_armsbg,
1405 stbar_x + ST_ARMSBGX,
1406 stbar_y + ST_ARMSBGY,
1407 armsbg,
1408 &st_not_deathmatch );
1409
1410 // weapons owned, draw enabled by ! deathmatch
1411 for(i=0;i<6;i++)
1412 {
1413 STlib_initMultIcon(&w_arms[i],
1414 stbar_x + ST_ARMSX + (i%3)*ST_ARMSXSPACE,
1415 stbar_y + ST_ARMSY + (i/3)*ST_ARMSYSPACE,
1416 arms[i], (int *) &st_plyr->weaponowned[i+1] );
1417 }
1418
1419 // frags sum, draw enabled by deathmatch
1420 STlib_initNum(&w_frags,
1421 stbar_x + ST_FRAGSX,
1422 stbar_y + ST_FRAGSY,
1423 tallnum,
1424 &st_fragscount,
1425 ST_FRAGSWIDTH);
1426
1427 // faces
1428 STlib_initMultIcon(&w_faces,
1429 stbar_x + ST_FACESX,
1430 stbar_y + ST_FACESY,
1431 faces,
1432 &st_faceindex );
1433
1434 // armor percentage - should be colored later
1435 STlib_initNum(&w_armor,
1436 stbar_x + ST_ARMORX,
1437 stbar_y + ST_ARMORY,
1438 tallnum,
1439 &st_plyr->armorpoints,
1440 3 );
1441
1442 // keyboxes 0-6, in vertical column
1443 for( i=0; i<6; i++ )
1444 {
1445 STlib_initMultIcon(&w_keyboxes[i],
1446 stbar_x + ST_KEYX,
1447 stbar_y + keybox_y[i],
1448 keys, // patches
1449 &keyboxes[i] );
1450 }
1451
1452 for( i=0; i<4; i++ )
1453 {
1454 // In vertical column.
1455 // ammo count (all four kinds)
1456 STlib_initNum(&w_ammo[i],
1457 stbar_x + ST_AMMOSX,
1458 stbar_y + ammobox_y[i],
1459 shortnum,
1460 &st_plyr->ammo[i],
1461 ST_AMMOS_WIDTH);
1462 // max ammo count (all four kinds)
1463 STlib_initNum(&w_maxammo[i],
1464 stbar_x + ST_MAXAMMOSX,
1465 stbar_y + ammobox_y[i],
1466 shortnum,
1467 &st_plyr->maxammo[i],
1468 ST_MAXAMMOS_WIDTH);
1469 }
1470 }
1471
ST_Stop(void)1472 static void ST_Stop (void)
1473 {
1474 if (st_stopped)
1475 return;
1476
1477 // V_SetPalette (0);
1478 ST_Palette0();
1479
1480 st_stopped = true;
1481 }
1482
1483 // Doom or Heretic.
1484 // Single and SplitPlayer.
1485 // Called by G_DoLoadLevel, P_SpawnPlayer, P_AddWadFile
1486 // Called by ST_Change_DemoView
ST_Start(void)1487 void ST_Start (void)
1488 {
1489 // Doom and Heretic common.
1490 st_plyr = &players[statusbarplayer];
1491
1492 if( EN_heretic )
1493 {
1494 st_stopped = false;
1495 return;
1496 }
1497
1498 // Doom only.
1499 if (!st_stopped)
1500 ST_Stop();
1501
1502 // Init as if Single player.
1503 // When AutoMap displayed, shows Status bar for player1.
1504 ST_init_stbar();
1505 ST_Create_Widgets();
1506 st_stopped = false;
1507 stbar_recalc = false; //added:02-02-98: widgets coords have been setup
1508 // see ST_drawer()
1509 }
1510
1511 //
1512 // Initializes the status bar,
1513 // sets the defaults border patch for the window borders.
1514 //
1515
1516 //faB: used by Glide mode, holds lumpnum of flat used to fill space around the viewwindow
1517 lumpnum_t st_borderflat_num; // extern in r_draw.h
1518
ST_Init(void)1519 void ST_Init (void)
1520 {
1521 int i;
1522
1523 if(dedicated)
1524 return;
1525
1526 //added:26-01-98:screens[4] is allocated at videomode setup, and
1527 // set at V_Init(), the first time being at SCR_Recalc()
1528
1529 // choose and cache the default border patch
1530 switch(gamemode) {
1531 case doom2_commercial :
1532 // DOOM II border patch, original was GRNROCK
1533 st_borderflat_num = W_GetNumForName ("GRNROCK");
1534 break;
1535 case heretic :
1536 if( ! VALID_LUMP( W_CheckNumForName("e2m1") ) )
1537 {
1538 // GDESC_heretic_shareware
1539 st_borderflat_num = W_GetNumForName ("FLOOR04");
1540 }
1541 else
1542 st_borderflat_num = W_GetNumForName ("FLAT513");
1543 break;
1544 case hexen :
1545 st_borderflat_num = W_GetNumForName ("F_022");
1546 break;
1547 default :
1548 // DOOM border patch.
1549 st_borderflat_num = W_GetNumForName ("FLOOR7_2");
1550 }
1551 // [WDJ] Lock against other users of same patch releasing it!.
1552 scr_borderflat = W_CacheLumpNum (st_borderflat_num, PU_LOCK_SB);
1553
1554 ST_Load_Graphics(); // Doom and Heretic
1555
1556 if( EN_heretic )
1557 return;
1558
1559 // Doom only
1560 //
1561 // cache the status bar overlay icons (fullscreen mode)
1562 //
1563 sbo_health = W_GetNumForName ("SBOHEALT");
1564 sbo_frags = W_GetNumForName ("SBOFRAGS");
1565 sbo_armor = W_GetNumForName ("SBOARMOR");
1566
1567 // With Heretic, NUMWEAPONS = 18.
1568 // Doom weapons are 0..8, chainsaw = 7.
1569 for (i=0;i<NUMWEAPONS;i++)
1570 {
1571 sbo_ammo[i] = (i>0 && i!=7 && i<=8)?
1572 W_GetNumForName (va("SBOAMMO%c",'0'+i))
1573 : 0;
1574 }
1575 }
1576
1577 //added:16-01-98: change the status bar too, when pressing F12 while viewing
1578 // a demo.
ST_Change_DemoView(void)1579 void ST_Change_DemoView (void)
1580 {
1581 //the same routine is called at multiplayer deathmatch spawn
1582 // so it can be called multiple times
1583 ST_Start();
1584 }
1585
1586
1587 // =========================================================================
1588 // STATUS BAR OVERLAY
1589 // =========================================================================
1590
1591 consvar_t cv_stbaroverlay = {"overlay","kahmf",CV_SAVE,NULL};
1592
1593 boolean st_overlay_on; // status overlay for Doom and Heretic
1594
1595
ST_Register_Commands(void)1596 void ST_Register_Commands (void)
1597 {
1598 CV_RegisterVar (&cv_stbaroverlay);
1599 }
1600
1601
1602 // Draw a number, scaled, over the view
1603 // Always draw the number completely since it's overlay
1604 //
1605 // x, y: scaled position, right border!
1606 static
ST_drawOverlayNum(int x,int y,int num,patch_t ** numpat,patch_t * percent,byte pickup_flash)1607 void ST_drawOverlayNum (int x, int y,
1608 int num,
1609 patch_t** numpat,
1610 patch_t* percent,
1611 byte pickup_flash )
1612 {
1613 // Hardware or software draw.
1614 patch_t * pf = V_patch( numpat[0] );
1615 int hf = pf->height;
1616 int wf = pf->width;
1617 int wfv = wf * vid.dupx;
1618 boolean neg;
1619
1620 V_SetupDraw( FG | V_NOSCALE | V_SCALEPATCH | V_TRANSLUCENTPATCH );
1621
1622 if( pickup_flash && (cv_pickupflash.EV == 1))
1623 {
1624 // Assume 3 digits 0..200
1625 V_DrawVidFill(x - (wfv*3), y, wfv*3, hf*vid.dupy, FLASH_COLOR);
1626 }
1627
1628 // in the special case of 0, you draw 0
1629 if (num == 0)
1630 {
1631 V_DrawScaledPatch(x - wfv, y, numpat[ 0 ]);
1632 return;
1633 }
1634
1635 neg = num < 0;
1636
1637 if (neg)
1638 num = -num;
1639
1640 // draw the number
1641 while (num)
1642 {
1643 x -= wfv;
1644 V_DrawScaledPatch(x, y, numpat[ num % 10 ]);
1645 num /= 10;
1646 }
1647
1648 // draw a minus sign if necessary, minus is at [10] in the number font
1649 if (neg && numpat[10])
1650 V_DrawScaledPatch(x - (8*vid.dupx), y, numpat[10]);
1651 }
1652
1653 // y : status position normally
1654 // y0 : status base position as modified for splitscreen
SCY(int y,int y0)1655 static inline int SCY( int y, int y0 )
1656 {
1657 //31/10/99: fixed by Hurdler so it _works_ also in hardware mode
1658 // do not scale to resolution for hardware accelerated
1659 // because these modes always scale by default
1660 y = (int)( y * vid.fdupy ); // scale to resolution
1661 if( cv_splitscreen.EV ) {
1662 y >>= 1; // half sized screens
1663 y += y0; // base position of upper or lower screen
1664 }
1665 return y;
1666 }
1667
1668
SCX(int x)1669 static inline int SCX( int x )
1670 {
1671 return x * vid.fdupx;
1672 }
1673
1674 static
ST_drawOverlayKeys(int x,int y,player_t * plyr)1675 void ST_drawOverlayKeys( int x, int y, player_t * plyr )
1676 {
1677 int i, yh, xinc, yinc;
1678 byte cards = plyr->cards;
1679
1680 xinc = (int)((ST_KEY_WIDTH + 1) * vid.fdupx);
1681 yinc = (int)((ST_KEY_HEIGHT + 1) * vid.fdupy);
1682 yh = y; // upper row is same as lower row when no skull keys
1683 // if both skull and cards, then move cards up a row
1684 if( cards & 0x38 )
1685 yh -= yinc;
1686
1687 if( plyr->key_pickup && (cv_pickupflash.EV == 1))
1688 {
1689 V_DrawVidFill(x - (xinc*3), yh, (xinc*3), y - yh + yinc, FLASH_COLOR);
1690 }
1691
1692 for (i=0;i<3;i++)
1693 {
1694 x -= xinc;
1695 if( (cards >> i) & 0x08 ) // skull
1696 {
1697 V_DrawScaledPatch(x, y, keys[i+3]); // skull graphic lower row
1698 }
1699 if( (cards >> i) & 0x01 ) // card
1700 {
1701 V_DrawScaledPatch(x, yh, keys[i]); // keycard graphic upper row
1702 }
1703 }
1704 }
1705
1706
1707 // Draw the status bar overlay, customisable : the user choose which
1708 // kind of information to overlay
1709 //
1710 // status_position : 0=lower, 1=upper
1711 static
ST_overlayDrawer(byte status_position,player_t * plyr)1712 void ST_overlayDrawer ( byte status_position, player_t * plyr )
1713 {
1714 const char * cmds;
1715 char c;
1716 int i;
1717 // [WDJ] 8/2012 fix opengl overlay position to use fdupy
1718 float sf_dupy = (rendermode == render_soft)? vid.dupy : vid.fdupy ;
1719 int y0 = status_position ? 0 : vid.height / 2;
1720 int lowerbar_y = SCY(198,y0) - (int)( 16 * sf_dupy );
1721
1722 // Draw screen0, scaled, abs position
1723 V_SetupDraw( FG | V_NOSCALE | V_SCALEPATCH );
1724 // x, y are already scaled.
1725
1726 cmds = cv_stbaroverlay.string;
1727
1728 while ((c=*cmds++))
1729 {
1730 if (c>='A' && c<='Z')
1731 c = c + 'a' - 'A';
1732 switch (c)
1733 {
1734 case 'h': // draw health
1735 ST_drawOverlayNum(SCX(50), lowerbar_y,
1736 plyr->health,
1737 tallnum, NULL, plyr->health_pickup);
1738
1739 V_DrawScalePic_Num (SCX(52), lowerbar_y, sbo_health);
1740 break;
1741
1742 case 'f': // draw frags
1743 st_fragscount = ST_PlayerFrags(plyr-players);
1744
1745 if( deathmatch )
1746 {
1747 ST_drawOverlayNum(SCX(300), SCY(2,y0),
1748 st_fragscount,
1749 tallnum, NULL, 0);
1750
1751 V_DrawScalePic_Num (SCX(302), SCY(2,y0), sbo_frags);
1752 }
1753 break;
1754
1755 case 'a': // draw ammo
1756 i = sbo_ammo[plyr->readyweapon];
1757 if (i)
1758 {
1759 ST_drawOverlayNum(SCX(234), lowerbar_y,
1760 plyr->ammo[plyr->weaponinfo[plyr->readyweapon].ammo],
1761 tallnum, NULL, plyr->ammo_pickup);
1762
1763 V_DrawScalePic_Num (SCX(236), lowerbar_y, i);
1764 }
1765 break;
1766
1767 case 'k': // draw keys
1768 ST_drawOverlayKeys( SCX(318), lowerbar_y - (8 * sf_dupy), plyr );
1769 break;
1770
1771 case 'm': // draw armor
1772 ST_drawOverlayNum(SCX(300), lowerbar_y,
1773 plyr->armorpoints,
1774 tallnum, NULL, plyr->armor_pickup);
1775
1776 V_DrawScalePic_Num (SCX(302), lowerbar_y, sbo_armor);
1777 break;
1778
1779 // added by Hurdler for single player only (or coop netplay)
1780 case 'e': // number of monster killed
1781 if( (! deathmatch) && (!cv_splitscreen.EV) )
1782 {
1783 char buf[16];
1784 sprintf(buf, "%d/%d", plyr->killcount, totalkills);
1785 V_DrawString(SCX(318-V_StringWidth(buf)), SCY(1,y0), 0, buf);
1786 }
1787 break;
1788
1789 case 's': // number of secrets found
1790 if( (! deathmatch) && (!cv_splitscreen.EV) )
1791 {
1792 char buf[16];
1793 sprintf(buf, "%d/%d", plyr->secretcount, totalsecret);
1794 V_DrawString(SCX(318-V_StringWidth(buf)), SCY(11,y0), 0, buf);
1795 }
1796 break;
1797
1798 /* //TODO
1799 case 'r': // current frame rate
1800 {
1801 char buf[8];
1802 int framerate = 35;
1803 sprintf(buf, "%d FPS", framerate);
1804 V_DrawString(SCX(2), SCY(4,y0), 0, buf);
1805 }
1806 break;
1807 */
1808 }
1809 }
1810 }
1811