1 /*
2 ** shared_sbar.cpp
3 ** Base status bar implementation
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2006 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34
35 #include <assert.h>
36
37 #include "templates.h"
38 #include "sbar.h"
39 #include "c_cvars.h"
40 #include "c_dispatch.h"
41 #include "c_console.h"
42 #include "v_video.h"
43 #include "m_swap.h"
44 #include "w_wad.h"
45 #include "v_text.h"
46 #include "s_sound.h"
47 #include "gi.h"
48 #include "doomstat.h"
49 #include "g_level.h"
50 #include "d_net.h"
51 #include "colormatcher.h"
52 #include "v_palette.h"
53 #include "d_player.h"
54 #include "farchive.h"
55 #include "a_hexenglobal.h"
56 #include "gstrings.h"
57
58 #include "../version.h"
59
60 #define XHAIRSHRINKSIZE (FRACUNIT/18)
61 #define XHAIRPICKUPSIZE (FRACUNIT*2+XHAIRSHRINKSIZE)
62 #define POWERUPICONSIZE 32
63
64 IMPLEMENT_POINTY_CLASS(DBaseStatusBar)
65 DECLARE_POINTER(Messages[0])
66 DECLARE_POINTER(Messages[1])
67 DECLARE_POINTER(Messages[2])
68 END_POINTERS
69
70 EXTERN_CVAR (Bool, am_showmonsters)
71 EXTERN_CVAR (Bool, am_showsecrets)
72 EXTERN_CVAR (Bool, am_showitems)
73 EXTERN_CVAR (Bool, am_showtime)
74 EXTERN_CVAR (Bool, am_showtotaltime)
75 EXTERN_CVAR (Bool, noisedebug)
76 EXTERN_CVAR (Int, con_scaletext)
77
78 DBaseStatusBar *StatusBar;
79
80 extern int setblocks;
81
82 int ST_X, ST_Y;
83 int SB_state = 3;
84
85 FTexture *CrosshairImage;
86 static int CrosshairNum;
87
88 // [RH] Base blending values (for e.g. underwater)
89 int BaseBlendR, BaseBlendG, BaseBlendB;
90 float BaseBlendA;
91
92 CVAR (Int, paletteflash, 0, CVAR_ARCHIVE)
CVAR(Flag,pf_hexenweaps,paletteflash,PF_HEXENWEAPONS)93 CVAR (Flag, pf_hexenweaps, paletteflash, PF_HEXENWEAPONS)
94 CVAR (Flag, pf_poison, paletteflash, PF_POISON)
95 CVAR (Flag, pf_ice, paletteflash, PF_ICE)
96 CVAR (Flag, pf_hazard, paletteflash, PF_HAZARD)
97
98 // Stretch status bar to full screen width?
99 CUSTOM_CVAR (Bool, st_scale, true, CVAR_ARCHIVE)
100 {
101 if (StatusBar)
102 {
103 StatusBar->SetScaled (self);
104 setsizeneeded = true;
105 }
106 }
107
108 CVAR (Int, crosshair, 0, CVAR_ARCHIVE)
109 CVAR (Bool, crosshairforce, false, CVAR_ARCHIVE)
110 CVAR (Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE);
111 CVAR (Bool, crosshairhealth, true, CVAR_ARCHIVE);
112 CVAR (Bool, crosshairscale, false, CVAR_ARCHIVE);
113 CVAR (Bool, crosshairgrow, false, CVAR_ARCHIVE);
114 CUSTOM_CVAR(Int, am_showmaplabel, 2, CVAR_ARCHIVE)
115 {
116 if (self < 0 || self > 2) self = 2;
117 }
118
119 CVAR (Bool, idmypos, false, 0);
120
121 //---------------------------------------------------------------------------
122 //
123 // Format the map name, include the map label if wanted
124 //
125 //---------------------------------------------------------------------------
126
ST_FormatMapName(FString & mapname,const char * mapnamecolor)127 void ST_FormatMapName(FString &mapname, const char *mapnamecolor)
128 {
129 cluster_info_t *cluster = FindClusterInfo (level.cluster);
130 bool ishub = (cluster != NULL && (cluster->flags & CLUSTER_HUB));
131
132 if (am_showmaplabel == 1 || (am_showmaplabel == 2 && !ishub))
133 {
134 mapname << level.MapName << ": ";
135 }
136 mapname << mapnamecolor << level.LevelName;
137 }
138
139 //---------------------------------------------------------------------------
140 //
141 // Load crosshair definitions
142 //
143 //---------------------------------------------------------------------------
144
ST_LoadCrosshair(bool alwaysload)145 void ST_LoadCrosshair(bool alwaysload)
146 {
147 int num = 0;
148 char name[16], size;
149
150 if (!crosshairforce &&
151 players[consoleplayer].camera != NULL &&
152 players[consoleplayer].camera->player != NULL &&
153 players[consoleplayer].camera->player->ReadyWeapon != NULL)
154 {
155 num = players[consoleplayer].camera->player->ReadyWeapon->Crosshair;
156 }
157 if (num == 0)
158 {
159 num = crosshair;
160 }
161 if (!alwaysload && CrosshairNum == num && CrosshairImage != NULL)
162 { // No change.
163 return;
164 }
165
166 if (CrosshairImage != NULL)
167 {
168 CrosshairImage->Unload ();
169 }
170 if (num == 0)
171 {
172 CrosshairNum = 0;
173 CrosshairImage = NULL;
174 return;
175 }
176 if (num < 0)
177 {
178 num = -num;
179 }
180 size = (SCREENWIDTH < 640) ? 'S' : 'B';
181
182 mysnprintf (name, countof(name), "XHAIR%c%d", size, num);
183 FTextureID texid = TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly);
184 if (!texid.isValid())
185 {
186 mysnprintf (name, countof(name), "XHAIR%c1", size);
187 texid = TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly);
188 if (!texid.isValid())
189 {
190 texid = TexMan.CheckForTexture("XHAIRS1", FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ShortNameOnly);
191 }
192 }
193 CrosshairNum = num;
194 CrosshairImage = TexMan[texid];
195 }
196
197 //---------------------------------------------------------------------------
198 //
199 // ST_Clear
200 //
201 //---------------------------------------------------------------------------
202
ST_Clear()203 void ST_Clear()
204 {
205 if (StatusBar != NULL)
206 {
207 StatusBar->Destroy();
208 StatusBar = NULL;
209 }
210 CrosshairImage = NULL;
211 CrosshairNum = 0;
212 }
213
214 //---------------------------------------------------------------------------
215 //
216 // ST_SetNeedRefresh
217 //
218 //---------------------------------------------------------------------------
219
ST_SetNeedRefresh()220 void ST_SetNeedRefresh()
221 {
222 SB_state = (StatusBar == NULL || screen == NULL) ? 0 : screen->GetPageCount();
223 }
224
225 //---------------------------------------------------------------------------
226 //
227 // Constructor
228 //
229 //---------------------------------------------------------------------------
230
DBaseStatusBar(int reltop,int hres,int vres)231 DBaseStatusBar::DBaseStatusBar (int reltop, int hres, int vres)
232 {
233 CompleteBorder = false;
234 Centering = false;
235 FixedOrigin = false;
236 CrosshairSize = FRACUNIT;
237 RelTop = reltop;
238 memset(Messages, 0, sizeof(Messages));
239 Displacement = 0;
240 CPlayer = NULL;
241 ShowLog = false;
242 HorizontalResolution = hres;
243 VirticalResolution = vres;
244
245 SetScaled (st_scale);
246 }
247
248 //---------------------------------------------------------------------------
249 //
250 // PROP Destroy
251 //
252 //---------------------------------------------------------------------------
253
Destroy()254 void DBaseStatusBar::Destroy ()
255 {
256 for (unsigned int i = 0; i < countof(Messages); ++i)
257 {
258 DHUDMessage *msg = Messages[i];
259 while (msg)
260 {
261 DHUDMessage *next = msg->Next;
262 msg->Destroy();
263 msg = next;
264 }
265 Messages[i] = NULL;
266 }
267 Super::Destroy();
268 }
269
270 //---------------------------------------------------------------------------
271 //
272 // PROC SetScaled
273 //
274 //---------------------------------------------------------------------------
275
276 //[BL] Added force argument to have forcescaled mean forcescaled.
277 // - Also, if the VirticalResolution is something other than the default (200)
278 // We should always obey the value of scale.
SetScaled(bool scale,bool force)279 void DBaseStatusBar::SetScaled (bool scale, bool force)
280 {
281 Scaled = (RelTop != 0 || force) && ((SCREENWIDTH != 320 || HorizontalResolution != 320) && scale);
282
283 if (!Scaled)
284 {
285 ST_X = (SCREENWIDTH - HorizontalResolution) / 2;
286 ST_Y = SCREENHEIGHT - RelTop;
287 ::ST_Y = ST_Y;
288 if (RelTop > 0)
289 {
290 Displacement = ((ST_Y * VirticalResolution / SCREENHEIGHT) - (VirticalResolution - RelTop))*FRACUNIT/RelTop;
291 }
292 else
293 {
294 Displacement = 0;
295 }
296 }
297 else
298 {
299 ST_X = 0;
300 ST_Y = VirticalResolution - RelTop;
301 if (CheckRatio(SCREENWIDTH, SCREENHEIGHT) != 4)
302 { // Normal resolution
303 ::ST_Y = Scale (ST_Y, SCREENHEIGHT, VirticalResolution);
304 }
305 else
306 { // 5:4 resolution
307 ::ST_Y = Scale(ST_Y - VirticalResolution/2, SCREENHEIGHT*3, Scale(VirticalResolution, BaseRatioSizes[4][1], 200)) + SCREENHEIGHT/2
308 + (SCREENHEIGHT - SCREENHEIGHT * BaseRatioSizes[4][3] / 48) / 2;
309 }
310 Displacement = 0;
311 }
312 ::ST_X = ST_X;
313 ST_SetNeedRefresh();
314 }
315
316 //---------------------------------------------------------------------------
317 //
318 // PROC AttachToPlayer
319 //
320 //---------------------------------------------------------------------------
321
AttachToPlayer(player_t * player)322 void DBaseStatusBar::AttachToPlayer (player_t *player)
323 {
324 CPlayer = player;
325 ST_SetNeedRefresh();
326 }
327
328 //---------------------------------------------------------------------------
329 //
330 // PROC GetPlayer
331 //
332 //---------------------------------------------------------------------------
333
GetPlayer()334 int DBaseStatusBar::GetPlayer ()
335 {
336 return int(CPlayer - players);
337 }
338
339 //---------------------------------------------------------------------------
340 //
341 // PROC MultiplayerChanged
342 //
343 //---------------------------------------------------------------------------
344
MultiplayerChanged()345 void DBaseStatusBar::MultiplayerChanged ()
346 {
347 ST_SetNeedRefresh();
348 }
349
350 //---------------------------------------------------------------------------
351 //
352 // PROC Tick
353 //
354 //---------------------------------------------------------------------------
355
Tick()356 void DBaseStatusBar::Tick ()
357 {
358 for (unsigned int i = 0; i < countof(Messages); ++i)
359 {
360 DHUDMessage *msg = Messages[i];
361 DHUDMessage **prev = &Messages[i];
362
363 while (msg)
364 {
365 DHUDMessage *next = msg->Next;
366
367 if (msg->Tick ())
368 {
369 *prev = next;
370 msg->Destroy();
371 }
372 else
373 {
374 prev = &msg->Next;
375 }
376 msg = next;
377 }
378
379 // If the crosshair has been enlarged, shrink it.
380 if (CrosshairSize > FRACUNIT)
381 {
382 CrosshairSize -= XHAIRSHRINKSIZE;
383 if (CrosshairSize < FRACUNIT)
384 {
385 CrosshairSize = FRACUNIT;
386 }
387 }
388 }
389 }
390
391 //---------------------------------------------------------------------------
392 //
393 // PROC AttachMessage
394 //
395 //---------------------------------------------------------------------------
396
AttachMessage(DHUDMessage * msg,DWORD id,int layer)397 void DBaseStatusBar::AttachMessage (DHUDMessage *msg, DWORD id, int layer)
398 {
399 DHUDMessage *old = NULL;
400 DHUDMessage **prev;
401 DObject *container = this;
402
403 old = (id == 0 || id == 0xFFFFFFFF) ? NULL : DetachMessage (id);
404 if (old != NULL)
405 {
406 old->Destroy();
407 }
408
409 // Merge unknown layers into the default layer.
410 if ((size_t)layer >= countof(Messages))
411 {
412 layer = HUDMSGLayer_Default;
413 }
414
415 prev = &Messages[layer];
416
417 // The ID serves as a priority, where lower numbers appear in front of
418 // higher numbers. (i.e. The list is sorted in descending order, since
419 // it gets drawn back to front.)
420 while (*prev != NULL && (*prev)->SBarID > id)
421 {
422 container = *prev;
423 prev = &(*prev)->Next;
424 }
425
426 msg->Next = *prev;
427 msg->SBarID = id;
428 *prev = msg;
429 GC::WriteBarrier(container, msg);
430 }
431
432 //---------------------------------------------------------------------------
433 //
434 // PROC DetachMessage
435 //
436 //---------------------------------------------------------------------------
437
DetachMessage(DHUDMessage * msg)438 DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg)
439 {
440 for (unsigned int i = 0; i < countof(Messages); ++i)
441 {
442 DHUDMessage *probe = Messages[i];
443 DHUDMessage **prev = &Messages[i];
444
445 while (probe && probe != msg)
446 {
447 prev = &probe->Next;
448 probe = probe->Next;
449 }
450 if (probe != NULL)
451 {
452 *prev = probe->Next;
453 probe->Next = NULL;
454 // Redraw the status bar in case it was covered
455 if (screen != NULL)
456 {
457 ST_SetNeedRefresh();
458 }
459 return probe;
460 }
461 }
462 return NULL;
463 }
464
DetachMessage(DWORD id)465 DHUDMessage *DBaseStatusBar::DetachMessage (DWORD id)
466 {
467 for (unsigned int i = 0; i < countof(Messages); ++i)
468 {
469 DHUDMessage *probe = Messages[i];
470 DHUDMessage **prev = &Messages[i];
471
472 while (probe && probe->SBarID != id)
473 {
474 prev = &probe->Next;
475 probe = probe->Next;
476 }
477 if (probe != NULL)
478 {
479 *prev = probe->Next;
480 probe->Next = NULL;
481 // Redraw the status bar in case it was covered
482 if (screen != NULL)
483 {
484 ST_SetNeedRefresh();
485 }
486 return probe;
487 }
488 }
489 return NULL;
490 }
491
492 //---------------------------------------------------------------------------
493 //
494 // PROC DetachAllMessages
495 //
496 //---------------------------------------------------------------------------
497
DetachAllMessages()498 void DBaseStatusBar::DetachAllMessages ()
499 {
500 for (unsigned int i = 0; i < countof(Messages); ++i)
501 {
502 DHUDMessage *probe = Messages[i];
503
504 Messages[i] = NULL;
505 while (probe != NULL)
506 {
507 DHUDMessage *next = probe->Next;
508 probe->Destroy();
509 probe = next;
510 }
511 }
512 }
513
514 //---------------------------------------------------------------------------
515 //
516 // PROC ShowPlayerName
517 //
518 //---------------------------------------------------------------------------
519
ShowPlayerName()520 void DBaseStatusBar::ShowPlayerName ()
521 {
522 EColorRange color;
523
524 color = (CPlayer == &players[consoleplayer]) ? CR_GOLD : CR_GREEN;
525 AttachMessage (new DHUDMessageFadeOut (SmallFont, CPlayer->userinfo.GetName(),
526 1.5f, 0.92f, 0, 0, color, 2.f, 0.35f), MAKE_ID('P','N','A','M'));
527 }
528
529 //---------------------------------------------------------------------------
530 //
531 // PROC DrawImage
532 //
533 // Draws an image with the status bar's upper-left corner as the origin.
534 //
535 //---------------------------------------------------------------------------
536
DrawImage(FTexture * img,int x,int y,FRemapTable * translation) const537 void DBaseStatusBar::DrawImage (FTexture *img,
538 int x, int y, FRemapTable *translation) const
539 {
540 if (img != NULL)
541 {
542 screen->DrawTexture (img, x + ST_X, y + ST_Y,
543 DTA_Translation, translation,
544 DTA_Bottom320x200, Scaled,
545 TAG_DONE);
546 }
547 }
548
549 //---------------------------------------------------------------------------
550 //
551 // PROC DrawImage
552 //
553 // Draws an optionally dimmed image with the status bar's upper-left corner
554 // as the origin.
555 //
556 //---------------------------------------------------------------------------
557
DrawDimImage(FTexture * img,int x,int y,bool dimmed) const558 void DBaseStatusBar::DrawDimImage (FTexture *img,
559 int x, int y, bool dimmed) const
560 {
561 if (img != NULL)
562 {
563 screen->DrawTexture (img, x + ST_X, y + ST_Y,
564 DTA_ColorOverlay, dimmed ? DIM_OVERLAY : 0,
565 DTA_Bottom320x200, Scaled,
566 TAG_DONE);
567 }
568 }
569
570 //---------------------------------------------------------------------------
571 //
572 // PROC DrawImage
573 //
574 // Draws a translucent image with the status bar's upper-left corner as the
575 // origin.
576 //
577 //---------------------------------------------------------------------------
578
DrawFadedImage(FTexture * img,int x,int y,fixed_t shade) const579 void DBaseStatusBar::DrawFadedImage (FTexture *img,
580 int x, int y, fixed_t shade) const
581 {
582 if (img != NULL)
583 {
584 screen->DrawTexture (img, x + ST_X, y + ST_Y,
585 DTA_Alpha, shade,
586 DTA_Bottom320x200, Scaled,
587 TAG_DONE);
588 }
589 }
590
591 //---------------------------------------------------------------------------
592 //
593 // PROC DrawPartialImage
594 //
595 // Draws a portion of an image with the status bar's upper-left corner as
596 // the origin. The image should be the same size as the status bar.
597 // Used for Doom's status bar.
598 //
599 //---------------------------------------------------------------------------
600
DrawPartialImage(FTexture * img,int wx,int ww) const601 void DBaseStatusBar::DrawPartialImage (FTexture *img, int wx, int ww) const
602 {
603 if (img != NULL)
604 {
605 screen->DrawTexture (img, ST_X, ST_Y,
606 DTA_WindowLeft, wx,
607 DTA_WindowRight, wx + ww,
608 DTA_Bottom320x200, Scaled,
609 TAG_DONE);
610 }
611 }
612
613 //---------------------------------------------------------------------------
614 //
615 // PROC DrINumber
616 //
617 // Draws a three digit number.
618 //
619 //---------------------------------------------------------------------------
620
DrINumber(signed int val,int x,int y,int imgBase) const621 void DBaseStatusBar::DrINumber (signed int val, int x, int y, int imgBase) const
622 {
623 int oldval;
624
625 if (val > 999)
626 val = 999;
627 oldval = val;
628 if (val < 0)
629 {
630 if (val < -9)
631 {
632 DrawImage (Images[imgLAME], x+1, y+1);
633 return;
634 }
635 val = -val;
636 DrawImage (Images[imgBase+val], x+18, y);
637 DrawImage (Images[imgNEGATIVE], x+9, y);
638 return;
639 }
640 if (val > 99)
641 {
642 DrawImage (Images[imgBase+val/100], x, y);
643 }
644 val = val % 100;
645 if (val > 9 || oldval > 99)
646 {
647 DrawImage (Images[imgBase+val/10], x+9, y);
648 }
649 val = val % 10;
650 DrawImage (Images[imgBase+val], x+18, y);
651 }
652
653 //---------------------------------------------------------------------------
654 //
655 // PROC DrBNumber
656 //
657 // Draws an x digit number using the big font.
658 //
659 //---------------------------------------------------------------------------
660
DrBNumber(signed int val,int x,int y,int size) const661 void DBaseStatusBar::DrBNumber (signed int val, int x, int y, int size) const
662 {
663 bool neg;
664 int i, w;
665 int power;
666 FTexture *pic;
667
668 pic = Images[imgBNumbers];
669 w = (pic != NULL) ? pic->GetWidth() : 0;
670
671 if (val == 0)
672 {
673 if (pic != NULL)
674 {
675 DrawImage (pic, x - w, y);
676 }
677 return;
678 }
679
680 if ( (neg = val < 0) )
681 {
682 val = -val;
683 size--;
684 }
685 for (i = size-1, power = 10; i > 0; i--)
686 {
687 power *= 10;
688 }
689 if (val >= power)
690 {
691 val = power - 1;
692 }
693 while (val != 0 && size--)
694 {
695 x -= w;
696 pic = Images[imgBNumbers + val % 10];
697 val /= 10;
698 if (pic != NULL)
699 {
700 DrawImage (pic, x, y);
701 }
702 }
703 if (neg)
704 {
705 pic = Images[imgBNEGATIVE];
706 if (pic != NULL)
707 {
708 DrawImage (pic, x - w, y);
709 }
710 }
711 }
712
713 //---------------------------------------------------------------------------
714 //
715 // PROC DrSmallNumber
716 //
717 // Draws a small three digit number.
718 //
719 //---------------------------------------------------------------------------
720
DrSmallNumber(int val,int x,int y) const721 void DBaseStatusBar::DrSmallNumber (int val, int x, int y) const
722 {
723 int digit = 0;
724
725 if (val > 999)
726 {
727 val = 999;
728 }
729 if (val > 99)
730 {
731 digit = val / 100;
732 DrawImage (Images[imgSmNumbers + digit], x, y);
733 val -= digit * 100;
734 }
735 if (val > 9 || digit)
736 {
737 digit = val / 10;
738 DrawImage (Images[imgSmNumbers + digit], x+4, y);
739 val -= digit * 10;
740 }
741 DrawImage (Images[imgSmNumbers + val], x+8, y);
742 }
743
744 //---------------------------------------------------------------------------
745 //
746 // PROC DrINumberOuter
747 //
748 // Draws a number outside the status bar, possibly scaled.
749 //
750 //---------------------------------------------------------------------------
751
DrINumberOuter(signed int val,int x,int y,bool center,int w) const752 void DBaseStatusBar::DrINumberOuter (signed int val, int x, int y, bool center, int w) const
753 {
754 bool negative = false;
755
756 x += w*2;
757 if (val < 0)
758 {
759 negative = true;
760 val = -val;
761 }
762 else if (val == 0)
763 {
764 screen->DrawTexture (Images[imgINumbers], x + 1, y + 1,
765 DTA_FillColor, 0, DTA_Alpha, HR_SHADOW,
766 DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
767 screen->DrawTexture (Images[imgINumbers], x, y,
768 DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
769 return;
770 }
771
772 int oval = val;
773 int ox = x;
774
775 // First the shadow
776 while (val != 0)
777 {
778 screen->DrawTexture (Images[imgINumbers + val % 10], x + 1, y + 1,
779 DTA_FillColor, 0, DTA_Alpha, HR_SHADOW,
780 DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
781 x -= w;
782 val /= 10;
783 }
784 if (negative)
785 {
786 screen->DrawTexture (Images[imgNEGATIVE], x + 1, y + 1,
787 DTA_FillColor, 0, DTA_Alpha, HR_SHADOW,
788 DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
789 }
790
791 // Then the real deal
792 val = oval;
793 x = ox;
794 while (val != 0)
795 {
796 screen->DrawTexture (Images[imgINumbers + val % 10], x, y,
797 DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
798 x -= w;
799 val /= 10;
800 }
801 if (negative)
802 {
803 screen->DrawTexture (Images[imgNEGATIVE], x, y,
804 DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
805 }
806 }
807
808 //---------------------------------------------------------------------------
809 //
810 // PROC DrBNumberOuter
811 //
812 // Draws a three digit number using the big font outside the status bar.
813 //
814 //---------------------------------------------------------------------------
815
DrBNumberOuter(signed int val,int x,int y,int size) const816 void DBaseStatusBar::DrBNumberOuter (signed int val, int x, int y, int size) const
817 {
818 int xpos;
819 int w;
820 bool negative = false;
821 FTexture *pic;
822
823 pic = Images[imgBNumbers+3];
824 if (pic != NULL)
825 {
826 w = pic->GetWidth();
827 }
828 else
829 {
830 w = 0;
831 }
832
833 xpos = x + w/2 + (size-1)*w;
834
835 if (val == 0)
836 {
837 pic = Images[imgBNumbers];
838 if (pic != NULL)
839 {
840 screen->DrawTexture (pic, xpos - pic->GetWidth()/2 + 2, y + 2,
841 DTA_HUDRules, HUD_Normal,
842 DTA_Alpha, HR_SHADOW,
843 DTA_FillColor, 0,
844 TAG_DONE);
845 screen->DrawTexture (pic, xpos - pic->GetWidth()/2, y,
846 DTA_HUDRules, HUD_Normal,
847 TAG_DONE);
848 }
849 return;
850 }
851 else if (val < 0)
852 {
853 negative = true;
854 val = -val;
855 }
856
857 int oval = val;
858 int oxpos = xpos;
859
860 // Draw shadow first
861 while (val != 0)
862 {
863 pic = Images[val % 10 + imgBNumbers];
864 if (pic != NULL)
865 {
866 screen->DrawTexture (pic, xpos - pic->GetWidth()/2 + 2, y + 2,
867 DTA_HUDRules, HUD_Normal,
868 DTA_Alpha, HR_SHADOW,
869 DTA_FillColor, 0,
870 TAG_DONE);
871 }
872 val /= 10;
873 xpos -= w;
874 }
875 if (negative)
876 {
877 pic = Images[imgBNEGATIVE];
878 if (pic != NULL)
879 {
880 screen->DrawTexture (pic, xpos - pic->GetWidth()/2 + 2, y + 2,
881 DTA_HUDRules, HUD_Normal,
882 DTA_Alpha, HR_SHADOW,
883 DTA_FillColor, 0,
884 TAG_DONE);
885 }
886 }
887
888 // Then draw the real thing
889 val = oval;
890 xpos = oxpos;
891 while (val != 0)
892 {
893 pic = Images[val % 10 + imgBNumbers];
894 if (pic != NULL)
895 {
896 screen->DrawTexture (pic, xpos - pic->GetWidth()/2, y,
897 DTA_HUDRules, HUD_Normal,
898 TAG_DONE);
899 }
900 val /= 10;
901 xpos -= w;
902 }
903 if (negative)
904 {
905 pic = Images[imgBNEGATIVE];
906 if (pic != NULL)
907 {
908 screen->DrawTexture (pic, xpos - pic->GetWidth()/2, y,
909 DTA_HUDRules, HUD_Normal,
910 TAG_DONE);
911 }
912 }
913 }
914
915 //---------------------------------------------------------------------------
916 //
917 // PROC DrBNumberOuter
918 //
919 // Draws a three digit number using the real big font outside the status bar.
920 //
921 //---------------------------------------------------------------------------
922
DrBNumberOuterFont(signed int val,int x,int y,int size) const923 void DBaseStatusBar::DrBNumberOuterFont (signed int val, int x, int y, int size) const
924 {
925 int xpos;
926 int w, v;
927 bool negative = false;
928 FTexture *pic;
929
930 w = 0;
931 BigFont->GetChar ('0', &w);
932
933 if (w > 1)
934 {
935 w--;
936 }
937 xpos = x + w/2 + (size-1)*w;
938
939 if (val == 0)
940 {
941 pic = BigFont->GetChar ('0', &v);
942 screen->DrawTexture (pic, xpos - v/2 + 2, y + 2,
943 DTA_HUDRules, HUD_Normal,
944 DTA_Alpha, HR_SHADOW,
945 DTA_FillColor, 0,
946 DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
947 TAG_DONE);
948 screen->DrawTexture (pic, xpos - v/2, y,
949 DTA_HUDRules, HUD_Normal,
950 DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
951 TAG_DONE);
952 return;
953 }
954 else if (val < 0)
955 {
956 negative = true;
957 val = -val;
958 }
959
960 int oval = val;
961 int oxpos = xpos;
962
963 // First the shadow
964 while (val != 0)
965 {
966 pic = BigFont->GetChar ('0' + val % 10, &v);
967 screen->DrawTexture (pic, xpos - v/2 + 2, y + 2,
968 DTA_HUDRules, HUD_Normal,
969 DTA_Alpha, HR_SHADOW,
970 DTA_FillColor, 0,
971 DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
972 TAG_DONE);
973 val /= 10;
974 xpos -= w;
975 }
976 if (negative)
977 {
978 pic = BigFont->GetChar ('-', &v);
979 if (pic != NULL)
980 {
981 screen->DrawTexture (pic, xpos - v/2 + 2, y + 2,
982 DTA_HUDRules, HUD_Normal,
983 DTA_Alpha, HR_SHADOW,
984 DTA_FillColor, 0,
985 DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
986 TAG_DONE);
987 }
988 }
989
990 // Then the foreground number
991 val = oval;
992 xpos = oxpos;
993 while (val != 0)
994 {
995 pic = BigFont->GetChar ('0' + val % 10, &v);
996 screen->DrawTexture (pic, xpos - v/2, y,
997 DTA_HUDRules, HUD_Normal,
998 DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
999 TAG_DONE);
1000 val /= 10;
1001 xpos -= w;
1002 }
1003 if (negative)
1004 {
1005 pic = BigFont->GetChar ('-', &v);
1006 if (pic != NULL)
1007 {
1008 screen->DrawTexture (pic, xpos - v/2, y,
1009 DTA_HUDRules, HUD_Normal,
1010 DTA_Translation, BigFont->GetColorTranslation (CR_UNTRANSLATED),
1011 TAG_DONE);
1012 }
1013 }
1014 }
1015
1016 //---------------------------------------------------------------------------
1017 //
1018 // PROC DrSmallNumberOuter
1019 //
1020 // Draws a small three digit number outside the status bar.
1021 //
1022 //---------------------------------------------------------------------------
1023
DrSmallNumberOuter(int val,int x,int y,bool center) const1024 void DBaseStatusBar::DrSmallNumberOuter (int val, int x, int y, bool center) const
1025 {
1026 int digit = 0;
1027
1028 if (val > 999)
1029 {
1030 val = 999;
1031 }
1032 if (val > 99)
1033 {
1034 digit = val / 100;
1035 screen->DrawTexture (Images[imgSmNumbers + digit], x, y,
1036 DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
1037 val -= digit * 100;
1038 }
1039 if (val > 9 || digit)
1040 {
1041 digit = val / 10;
1042 screen->DrawTexture (Images[imgSmNumbers + digit], x+4, y,
1043 DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
1044 val -= digit * 10;
1045 }
1046 screen->DrawTexture (Images[imgSmNumbers + val], x+8, y,
1047 DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal, TAG_DONE);
1048 }
1049
1050 //---------------------------------------------------------------------------
1051 //
1052 // RefreshBackground
1053 //
1054 //---------------------------------------------------------------------------
1055
RefreshBackground() const1056 void DBaseStatusBar::RefreshBackground () const
1057 {
1058 int x, x2, y, ratio;
1059
1060 ratio = CheckRatio (SCREENWIDTH, SCREENHEIGHT);
1061 x = (!(ratio & 3) || !Scaled) ? ST_X : SCREENWIDTH*(48-BaseRatioSizes[ratio][3])/(48*2);
1062 y = x == ST_X && x > 0 ? ST_Y : ::ST_Y;
1063
1064 if(!CompleteBorder)
1065 {
1066 if(y < SCREENHEIGHT)
1067 {
1068 V_DrawBorder (x+1, y, SCREENWIDTH, y+1);
1069 V_DrawBorder (x+1, SCREENHEIGHT-1, SCREENWIDTH, SCREENHEIGHT);
1070 }
1071 }
1072 else
1073 {
1074 x = SCREENWIDTH;
1075 }
1076
1077 if (x > 0)
1078 {
1079 if(!CompleteBorder)
1080 {
1081 x2 = !(ratio & 3) || !Scaled ? ST_X+HorizontalResolution :
1082 SCREENWIDTH - (SCREENWIDTH*(48-BaseRatioSizes[ratio][3])+48*2-1)/(48*2);
1083 }
1084 else
1085 {
1086 x2 = SCREENWIDTH;
1087 }
1088
1089 V_DrawBorder (0, y, x+1, SCREENHEIGHT);
1090 V_DrawBorder (x2-1, y, SCREENWIDTH, SCREENHEIGHT);
1091
1092 if (setblocks >= 10)
1093 {
1094 FTexture *p = TexMan[gameinfo.Border.b];
1095 if (p != NULL)
1096 {
1097 screen->FlatFill(0, y, x, y + p->GetHeight(), p, true);
1098 screen->FlatFill(x2, y, SCREENWIDTH, y + p->GetHeight(), p, true);
1099 }
1100 }
1101 }
1102 }
1103
1104 //---------------------------------------------------------------------------
1105 //
1106 // DrawCrosshair
1107 //
1108 //---------------------------------------------------------------------------
1109
DrawCrosshair()1110 void DBaseStatusBar::DrawCrosshair ()
1111 {
1112 static DWORD prevcolor = 0xffffffff;
1113 static int palettecolor = 0;
1114
1115 DWORD color;
1116 fixed_t size;
1117 int w, h;
1118
1119 // Don't draw the crosshair in chasecam mode
1120 if (players[consoleplayer].cheats & CF_CHASECAM)
1121 return;
1122
1123 ST_LoadCrosshair();
1124
1125 // Don't draw the crosshair if there is none
1126 if (CrosshairImage == NULL || gamestate == GS_TITLELEVEL || camera->health <= 0)
1127 {
1128 return;
1129 }
1130
1131 if (crosshairscale)
1132 {
1133 size = SCREENHEIGHT * FRACUNIT / 200;
1134 }
1135 else
1136 {
1137 size = FRACUNIT;
1138 }
1139
1140 if (crosshairgrow)
1141 {
1142 size = FixedMul (size, CrosshairSize);
1143 }
1144 w = (CrosshairImage->GetWidth() * size) >> FRACBITS;
1145 h = (CrosshairImage->GetHeight() * size) >> FRACBITS;
1146
1147 if (crosshairhealth)
1148 {
1149 int health = Scale(CPlayer->health, 100, CPlayer->mo->GetDefault()->health);
1150
1151 if (health >= 85)
1152 {
1153 color = 0x00ff00;
1154 }
1155 else
1156 {
1157 int red, green;
1158 health -= 25;
1159 if (health < 0)
1160 {
1161 health = 0;
1162 }
1163 if (health < 30)
1164 {
1165 red = 255;
1166 green = health * 255 / 30;
1167 }
1168 else
1169 {
1170 red = (60 - health) * 255 / 30;
1171 green = 255;
1172 }
1173 color = (red<<16) | (green<<8);
1174 }
1175 }
1176 else
1177 {
1178 color = crosshaircolor;
1179 }
1180
1181 if (color != prevcolor)
1182 {
1183 prevcolor = color;
1184 palettecolor = ColorMatcher.Pick (RPART(color), GPART(color), BPART(color));
1185 }
1186
1187 screen->DrawTexture (CrosshairImage,
1188 viewwidth / 2 + viewwindowx,
1189 viewheight / 2 + viewwindowy,
1190 DTA_DestWidth, w,
1191 DTA_DestHeight, h,
1192 DTA_AlphaChannel, true,
1193 DTA_FillColor, (palettecolor << 24) | (color & 0xFFFFFF),
1194 TAG_DONE);
1195 }
1196
1197 //---------------------------------------------------------------------------
1198 //
1199 // FlashCrosshair
1200 //
1201 //---------------------------------------------------------------------------
1202
FlashCrosshair()1203 void DBaseStatusBar::FlashCrosshair ()
1204 {
1205 CrosshairSize = XHAIRPICKUPSIZE;
1206 }
1207
1208 //---------------------------------------------------------------------------
1209 //
1210 // DrawMessages
1211 //
1212 //---------------------------------------------------------------------------
1213
DrawMessages(int layer,int bottom)1214 void DBaseStatusBar::DrawMessages (int layer, int bottom)
1215 {
1216 DHUDMessage *msg = Messages[layer];
1217 int visibility = 0;
1218
1219 if (viewactive)
1220 {
1221 visibility |= HUDMSG_NotWith3DView;
1222 }
1223 if (automapactive)
1224 {
1225 visibility |= viewactive ? HUDMSG_NotWithOverlayMap : HUDMSG_NotWithFullMap;
1226 }
1227 while (msg)
1228 {
1229 DHUDMessage *next = msg->Next;
1230 msg->Draw (bottom, visibility);
1231 msg = next;
1232 }
1233 }
1234
1235 //---------------------------------------------------------------------------
1236 //
1237 // Draw
1238 //
1239 //---------------------------------------------------------------------------
1240
Draw(EHudState state)1241 void DBaseStatusBar::Draw (EHudState state)
1242 {
1243 // HUD_AltHud state is for popups only
1244 if (state == HUD_AltHud)
1245 return;
1246
1247 char line[64+10];
1248
1249 if ((SB_state != 0 || BorderNeedRefresh) && state == HUD_StatusBar)
1250 {
1251 RefreshBackground ();
1252 }
1253
1254 if (idmypos)
1255 { // Draw current coordinates
1256 int height = SmallFont->GetHeight();
1257 char labels[3] = { 'X', 'Y', 'Z' };
1258 fixed_t *value;
1259 int i;
1260
1261 int vwidth;
1262 int vheight;
1263 int xpos;
1264 int y;
1265
1266 if (con_scaletext == 0)
1267 {
1268 vwidth = SCREENWIDTH;
1269 vheight = SCREENHEIGHT;
1270 xpos = vwidth - 80;
1271 y = ::ST_Y - height;
1272 }
1273 else
1274 {
1275 vwidth = SCREENWIDTH/2;
1276 vheight = SCREENHEIGHT/2;
1277 xpos = vwidth - SmallFont->StringWidth("X: -00000")-6;
1278 y = ::ST_Y/2 - height;
1279 }
1280
1281 if (gameinfo.gametype == GAME_Strife)
1282 {
1283 if (con_scaletext == 0)
1284 y -= height * 4;
1285 else
1286 y -= height * 2;
1287 }
1288
1289 fixedvec3 pos = CPlayer->mo->Pos();
1290 for (i = 2, value = &pos.z; i >= 0; y -= height, --value, --i)
1291 {
1292 mysnprintf (line, countof(line), "%c: %d", labels[i], *value >> FRACBITS);
1293 screen->DrawText (SmallFont, CR_GREEN, xpos, y, line,
1294 DTA_KeepRatio, true,
1295 DTA_VirtualWidth, vwidth, DTA_VirtualHeight, vheight,
1296 TAG_DONE);
1297 V_SetBorderNeedRefresh();
1298 }
1299 }
1300
1301 if (viewactive)
1302 {
1303 if (CPlayer && CPlayer->camera && CPlayer->camera->player)
1304 {
1305 DrawCrosshair ();
1306 }
1307 }
1308 else if (automapactive)
1309 {
1310 int y, time = Tics2Seconds(level.time), height;
1311 int totaltime = Tics2Seconds(level.totaltime);
1312 EColorRange highlight = (gameinfo.gametype & GAME_DoomChex) ?
1313 CR_UNTRANSLATED : CR_YELLOW;
1314
1315 height = SmallFont->GetHeight () * CleanYfac;
1316
1317 // Draw timer
1318 y = 8;
1319 if (am_showtime)
1320 {
1321 mysnprintf (line, countof(line), "%02d:%02d:%02d", time/3600, (time%3600)/60, time%60); // Time
1322 screen->DrawText (SmallFont, CR_GREY, SCREENWIDTH - 80*CleanXfac, y, line, DTA_CleanNoMove, true, TAG_DONE);
1323 y+=8*CleanYfac;
1324 }
1325 if (am_showtotaltime)
1326 {
1327 mysnprintf (line, countof(line), "%02d:%02d:%02d", totaltime/3600, (totaltime%3600)/60, totaltime%60); // Total time
1328 screen->DrawText (SmallFont, CR_GREY, SCREENWIDTH - 80*CleanXfac, y, line, DTA_CleanNoMove, true, TAG_DONE);
1329 }
1330
1331 // Draw map name
1332 y = ::ST_Y - height;
1333 if (gameinfo.gametype == GAME_Heretic && SCREENWIDTH > 320 && !Scaled)
1334 {
1335 y -= 8;
1336 }
1337 else if (gameinfo.gametype == GAME_Hexen)
1338 {
1339 if (Scaled)
1340 {
1341 y -= Scale (11, SCREENHEIGHT, 200);
1342 }
1343 else
1344 {
1345 if (SCREENWIDTH < 640)
1346 {
1347 y -= 12;
1348 }
1349 else
1350 { // Get past the tops of the gargoyles' wings
1351 y -= 28;
1352 }
1353 }
1354 }
1355 else if (gameinfo.gametype == GAME_Strife)
1356 {
1357 if (Scaled)
1358 {
1359 y -= Scale (8, SCREENHEIGHT, 200);
1360 }
1361 else
1362 {
1363 y -= 8;
1364 }
1365 }
1366 FString mapname;
1367
1368 ST_FormatMapName(mapname, TEXTCOLOR_GREY);
1369 screen->DrawText (SmallFont, highlight,
1370 (SCREENWIDTH - SmallFont->StringWidth (mapname)*CleanXfac)/2, y, mapname,
1371 DTA_CleanNoMove, true, TAG_DONE);
1372
1373 if (!deathmatch)
1374 {
1375 int y = 8;
1376
1377 // Draw monster count
1378 if (am_showmonsters)
1379 {
1380 mysnprintf (line, countof(line), "%s" TEXTCOLOR_GREY " %d/%d",
1381 GStrings("AM_MONSTERS"), level.killed_monsters, level.total_monsters);
1382 screen->DrawText (SmallFont, highlight, 8, y, line,
1383 DTA_CleanNoMove, true, TAG_DONE);
1384 y += height;
1385 }
1386
1387 // Draw secret count
1388 if (am_showsecrets)
1389 {
1390 mysnprintf (line, countof(line), "%s" TEXTCOLOR_GREY " %d/%d",
1391 GStrings("AM_SECRETS"), level.found_secrets, level.total_secrets);
1392 screen->DrawText (SmallFont, highlight, 8, y, line,
1393 DTA_CleanNoMove, true, TAG_DONE);
1394 y += height;
1395 }
1396
1397 // Draw item count
1398 if (am_showitems)
1399 {
1400 mysnprintf (line, countof(line), "%s" TEXTCOLOR_GREY " %d/%d",
1401 GStrings("AM_ITEMS"), level.found_items, level.total_items);
1402 screen->DrawText (SmallFont, highlight, 8, y, line,
1403 DTA_CleanNoMove, true, TAG_DONE);
1404 }
1405 }
1406 }
1407 }
1408
1409
DrawLog()1410 void DBaseStatusBar::DrawLog ()
1411 {
1412 int hudwidth, hudheight;
1413
1414 if (CPlayer->LogText && *CPlayer->LogText)
1415 {
1416 // This uses the same scaling as regular HUD messages
1417 switch (con_scaletext)
1418 {
1419 default:
1420 hudwidth = SCREENWIDTH;
1421 hudheight = SCREENHEIGHT;
1422 break;
1423
1424 case 1:
1425 hudwidth = SCREENWIDTH / CleanXfac;
1426 hudheight = SCREENHEIGHT / CleanYfac;
1427 break;
1428
1429 case 2:
1430 hudwidth = SCREENWIDTH / 2;
1431 hudheight = SCREENHEIGHT / 2;
1432 break;
1433 }
1434
1435 int linelen = hudwidth<640? Scale(hudwidth,9,10)-40 : 560;
1436 FBrokenLines *lines = V_BreakLines (SmallFont, linelen, CPlayer->LogText);
1437 int height = 20;
1438
1439 for (int i = 0; lines[i].Width != -1; i++) height += SmallFont->GetHeight () + 1;
1440
1441 int x,y,w;
1442
1443 if (linelen<560)
1444 {
1445 x=hudwidth/20;
1446 y=hudheight/8;
1447 w=hudwidth-2*x;
1448 }
1449 else
1450 {
1451 x=(hudwidth>>1)-300;
1452 y=hudheight*3/10-(height>>1);
1453 if (y<0) y=0;
1454 w=600;
1455 }
1456 screen->Dim(0, 0.5f, Scale(x, SCREENWIDTH, hudwidth), Scale(y, SCREENHEIGHT, hudheight),
1457 Scale(w, SCREENWIDTH, hudwidth), Scale(height, SCREENHEIGHT, hudheight));
1458 x+=20;
1459 y+=10;
1460 for (int i = 0; lines[i].Width != -1; i++)
1461 {
1462
1463 screen->DrawText (SmallFont, CR_UNTRANSLATED, x, y, lines[i].Text,
1464 DTA_KeepRatio, true,
1465 DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, TAG_DONE);
1466 y += SmallFont->GetHeight ()+1;
1467 }
1468
1469 V_FreeBrokenLines (lines);
1470 }
1471 }
1472
MustDrawLog(EHudState)1473 bool DBaseStatusBar::MustDrawLog(EHudState)
1474 {
1475 return true;
1476 }
1477
SetMugShotState(const char * stateName,bool waitTillDone,bool reset)1478 void DBaseStatusBar::SetMugShotState(const char *stateName, bool waitTillDone, bool reset)
1479 {
1480 }
1481
1482 //---------------------------------------------------------------------------
1483 //
1484 // DrawBottomStuff
1485 //
1486 //---------------------------------------------------------------------------
1487
DrawBottomStuff(EHudState state)1488 void DBaseStatusBar::DrawBottomStuff (EHudState state)
1489 {
1490 DrawMessages (HUDMSGLayer_UnderHUD, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT);
1491 }
1492
1493 //---------------------------------------------------------------------------
1494 //
1495 // DrawTopStuff
1496 //
1497 //---------------------------------------------------------------------------
1498
DrawTopStuff(EHudState state)1499 void DBaseStatusBar::DrawTopStuff (EHudState state)
1500 {
1501 if (demoplayback && demover != DEMOGAMEVERSION)
1502 {
1503 screen->DrawText (SmallFont, CR_TAN, 0, ST_Y - 40 * CleanYfac,
1504 "Demo was recorded with a different version\n"
1505 "of " GAMENAME ". Expect it to go out of sync.",
1506 DTA_CleanNoMove, true, TAG_DONE);
1507 }
1508
1509 DrawPowerups ();
1510 if (automapactive && !viewactive)
1511 {
1512 DrawMessages (HUDMSGLayer_OverMap, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT);
1513 }
1514 DrawMessages (HUDMSGLayer_OverHUD, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT);
1515 DrawConsistancy ();
1516 DrawWaiting ();
1517 if (ShowLog && MustDrawLog(state)) DrawLog ();
1518
1519 if (noisedebug)
1520 {
1521 S_NoiseDebug ();
1522 }
1523 }
1524
1525 //---------------------------------------------------------------------------
1526 //
1527 // DrawPowerups
1528 //
1529 //---------------------------------------------------------------------------
1530
DrawPowerups()1531 void DBaseStatusBar::DrawPowerups ()
1532 {
1533 // Each icon gets a 32x32 block to draw itself in.
1534 int x, y;
1535 AInventory *item;
1536 const int yshift = SmallFont->GetHeight();
1537
1538 x = -20;
1539 y = 17
1540 + (ST_IsTimeVisible() ? yshift : 0)
1541 + (ST_IsLatencyVisible() ? yshift : 0);
1542 for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory)
1543 {
1544 if (item->DrawPowerup (x, y))
1545 {
1546 x -= POWERUPICONSIZE;
1547 if (x < -POWERUPICONSIZE*5)
1548 {
1549 x = -20;
1550 y += POWERUPICONSIZE*2;
1551 }
1552 }
1553 }
1554 }
1555
1556 //---------------------------------------------------------------------------
1557 //
1558 // BlendView
1559 //
1560 //---------------------------------------------------------------------------
1561
BlendView(float blend[4])1562 void DBaseStatusBar::BlendView (float blend[4])
1563 {
1564 V_AddBlend (BaseBlendR / 255.f, BaseBlendG / 255.f, BaseBlendB / 255.f, BaseBlendA, blend);
1565 V_AddPlayerBlend(CPlayer, blend, 1.0f, 228);
1566
1567 if (screen->Accel2D || (CPlayer->camera != NULL && menuactive == MENU_Off && ConsoleState == c_up))
1568 {
1569 player_t *player = (CPlayer->camera != NULL && CPlayer->camera->player != NULL) ? CPlayer->camera->player : CPlayer;
1570 V_AddBlend (player->BlendR, player->BlendG, player->BlendB, player->BlendA, blend);
1571 }
1572
1573 V_SetBlend ((int)(blend[0] * 255.0f), (int)(blend[1] * 255.0f),
1574 (int)(blend[2] * 255.0f), (int)(blend[3] * 256.0f));
1575 }
1576
DrawConsistancy() const1577 void DBaseStatusBar::DrawConsistancy () const
1578 {
1579 static bool firsttime = true;
1580 int i;
1581 char conbuff[64], *buff_p;
1582
1583 if (!netgame)
1584 return;
1585
1586 buff_p = NULL;
1587 for (i = 0; i < MAXPLAYERS; i++)
1588 {
1589 if (playeringame[i] && players[i].inconsistant)
1590 {
1591 if (buff_p == NULL)
1592 {
1593 strcpy (conbuff, "Out of sync with:");
1594 buff_p = conbuff + 17;
1595 }
1596 *buff_p++ = ' ';
1597 *buff_p++ = '1' + i;
1598 *buff_p = 0;
1599 }
1600 }
1601
1602 if (buff_p != NULL)
1603 {
1604 if (firsttime)
1605 {
1606 firsttime = false;
1607 if (debugfile)
1608 {
1609 fprintf (debugfile, "%s as of tic %d (%d)\n", conbuff,
1610 players[1-consoleplayer].inconsistant,
1611 players[1-consoleplayer].inconsistant/ticdup);
1612 }
1613 }
1614 screen->DrawText (SmallFont, CR_GREEN,
1615 (screen->GetWidth() - SmallFont->StringWidth (conbuff)*CleanXfac) / 2,
1616 0, conbuff, DTA_CleanNoMove, true, TAG_DONE);
1617 BorderTopRefresh = screen->GetPageCount ();
1618 }
1619 }
1620
DrawWaiting() const1621 void DBaseStatusBar::DrawWaiting () const
1622 {
1623 int i;
1624 char conbuff[64], *buff_p;
1625
1626 if (!netgame)
1627 return;
1628
1629 buff_p = NULL;
1630 for (i = 0; i < MAXPLAYERS; i++)
1631 {
1632 if (playeringame[i] && players[i].waiting)
1633 {
1634 if (buff_p == NULL)
1635 {
1636 strcpy (conbuff, "Waiting for:");
1637 buff_p = conbuff + 12;
1638 }
1639 *buff_p++ = ' ';
1640 *buff_p++ = '1' + i;
1641 *buff_p = 0;
1642 }
1643 }
1644
1645 if (buff_p != NULL)
1646 {
1647 screen->DrawText (SmallFont, CR_ORANGE,
1648 (screen->GetWidth() - SmallFont->StringWidth (conbuff)*CleanXfac) / 2,
1649 SmallFont->GetHeight()*CleanYfac, conbuff, DTA_CleanNoMove, true, TAG_DONE);
1650 BorderTopRefresh = screen->GetPageCount ();
1651 }
1652 }
1653
FlashItem(const PClass * itemtype)1654 void DBaseStatusBar::FlashItem (const PClass *itemtype)
1655 {
1656 }
1657
NewGame()1658 void DBaseStatusBar::NewGame ()
1659 {
1660 }
1661
SetInteger(int pname,int param)1662 void DBaseStatusBar::SetInteger (int pname, int param)
1663 {
1664 }
1665
ShowPop(int popnum)1666 void DBaseStatusBar::ShowPop (int popnum)
1667 {
1668 ShowLog = (popnum == POP_Log && !ShowLog);
1669 }
1670
ReceivedWeapon(AWeapon * weapon)1671 void DBaseStatusBar::ReceivedWeapon (AWeapon *weapon)
1672 {
1673 }
1674
Serialize(FArchive & arc)1675 void DBaseStatusBar::Serialize (FArchive &arc)
1676 {
1677 if (SaveVersion < 3821)
1678 {
1679 memset(Messages, 0, sizeof(Messages));
1680 arc << Messages[HUDMSGLayer_Default];
1681 }
1682 else
1683 {
1684 for (unsigned int i = 0; i < countof(Messages); ++i)
1685 {
1686 arc << Messages[i];
1687 }
1688 }
1689 }
1690
ScreenSizeChanged()1691 void DBaseStatusBar::ScreenSizeChanged ()
1692 {
1693 st_scale.Callback ();
1694 ST_SetNeedRefresh();
1695
1696 for (unsigned int i = 0; i < countof(Messages); ++i)
1697 {
1698 DHUDMessage *message = Messages[i];
1699 while (message != NULL)
1700 {
1701 message->ScreenSizeChanged ();
1702 message = message->Next;
1703 }
1704 }
1705 }
1706
1707 //---------------------------------------------------------------------------
1708 //
1709 // ValidateInvFirst
1710 //
1711 // Returns an inventory item that, when drawn as the first item, is sure to
1712 // include the selected item in the inventory bar.
1713 //
1714 //---------------------------------------------------------------------------
1715
ValidateInvFirst(int numVisible) const1716 AInventory *DBaseStatusBar::ValidateInvFirst (int numVisible) const
1717 {
1718 AInventory *item;
1719 int i;
1720
1721 if (CPlayer->mo->InvFirst == NULL)
1722 {
1723 CPlayer->mo->InvFirst = CPlayer->mo->FirstInv();
1724 if (CPlayer->mo->InvFirst == NULL)
1725 { // Nothing to show
1726 return NULL;
1727 }
1728 }
1729
1730 assert (CPlayer->mo->InvFirst->Owner == CPlayer->mo);
1731
1732 // If there are fewer than numVisible items shown, see if we can shift the
1733 // view left to show more.
1734 for (i = 0, item = CPlayer->mo->InvFirst; item != NULL && i < numVisible; ++i, item = item->NextInv())
1735 { }
1736
1737 while (i < numVisible)
1738 {
1739 item = CPlayer->mo->InvFirst->PrevInv ();
1740 if (item == NULL)
1741 {
1742 break;
1743 }
1744 else
1745 {
1746 CPlayer->mo->InvFirst = item;
1747 ++i;
1748 }
1749 }
1750
1751 if (CPlayer->mo->InvSel == NULL)
1752 {
1753 // Nothing selected, so don't move the view.
1754 return CPlayer->mo->InvFirst == NULL ? CPlayer->mo->Inventory : CPlayer->mo->InvFirst;
1755 }
1756 else
1757 {
1758 // Check if InvSel is already visible
1759 for (item = CPlayer->mo->InvFirst, i = numVisible;
1760 item != NULL && i != 0;
1761 item = item->NextInv(), --i)
1762 {
1763 if (item == CPlayer->mo->InvSel)
1764 {
1765 return CPlayer->mo->InvFirst;
1766 }
1767 }
1768 // Check if InvSel is to the right of the visible range
1769 for (i = 1; item != NULL; item = item->NextInv(), ++i)
1770 {
1771 if (item == CPlayer->mo->InvSel)
1772 {
1773 // Found it. Now advance InvFirst
1774 for (item = CPlayer->mo->InvFirst; i != 0; --i)
1775 {
1776 item = item->NextInv();
1777 }
1778 return item;
1779 }
1780 }
1781 // Check if InvSel is to the left of the visible range
1782 for (item = CPlayer->mo->Inventory;
1783 item != CPlayer->mo->InvSel;
1784 item = item->NextInv())
1785 { }
1786 if (item != NULL)
1787 {
1788 // Found it, so let it become the first item shown
1789 return item;
1790 }
1791 // Didn't find the selected item, so don't move the view.
1792 // This should never happen, so let debug builds assert.
1793 assert (item != NULL);
1794 return CPlayer->mo->InvFirst;
1795 }
1796 }
1797
1798 //============================================================================
1799 //
1800 // DBaseStatusBar :: GetCurrentAmmo
1801 //
1802 // Returns the types and amounts of ammo used by the current weapon. If the
1803 // weapon only uses one type of ammo, it is always returned as ammo1.
1804 //
1805 //============================================================================
1806
GetCurrentAmmo(AAmmo * & ammo1,AAmmo * & ammo2,int & ammocount1,int & ammocount2) const1807 void DBaseStatusBar::GetCurrentAmmo (AAmmo *&ammo1, AAmmo *&ammo2, int &ammocount1, int &ammocount2) const
1808 {
1809 if (CPlayer->ReadyWeapon != NULL)
1810 {
1811 ammo1 = CPlayer->ReadyWeapon->Ammo1;
1812 ammo2 = CPlayer->ReadyWeapon->Ammo2;
1813 if (ammo1 == NULL)
1814 {
1815 ammo1 = ammo2;
1816 ammo2 = NULL;
1817 }
1818 }
1819 else
1820 {
1821 ammo1 = ammo2 = NULL;
1822 }
1823 ammocount1 = ammo1 != NULL ? ammo1->Amount : 0;
1824 ammocount2 = ammo2 != NULL ? ammo2->Amount : 0;
1825 }
1826
1827 //============================================================================
1828 //
1829 // CCMD showpop
1830 //
1831 // Asks the status bar to show a pop screen.
1832 //
1833 //============================================================================
1834
CCMD(showpop)1835 CCMD (showpop)
1836 {
1837 if (argv.argc() != 2)
1838 {
1839 Printf ("Usage: showpop <popnumber>\n");
1840 }
1841 else if (StatusBar != NULL)
1842 {
1843 int popnum = atoi (argv[1]);
1844 if (popnum < 0)
1845 {
1846 popnum = 0;
1847 }
1848 StatusBar->ShowPop (popnum);
1849 }
1850 }
1851