This is a fork of Zandronum used on servers hosted by The Sentinels Playground (TSPG), Euroboros (EB), and Down Under Doomers (DUD).
Révision | b16e174e1c9b8f26b6658673370d040c821bd103 (tree) |
---|---|
l'heure | 2023-04-23 12:07:25 |
Auteur | Adam Kaminski <kaminskiadam9@gmai...> |
Commiter | Adam Kaminski |
Added the ScoreMargin class, and a base class for all margin SCORINFO commands.
@@ -1089,6 +1089,10 @@ | ||
1089 | 1089 | > |
1090 | 1090 | </File> |
1091 | 1091 | <File |
1092 | + RelativePath=".\src\scoreboard_margin.cpp" | |
1093 | + > | |
1094 | + </File> | |
1095 | + <File | |
1092 | 1096 | RelativePath=".\src\sectinfo.cpp" |
1093 | 1097 | > |
1094 | 1098 | </File> |
@@ -1218,6 +1218,7 @@ | ||
1218 | 1218 | s_sound.cpp |
1219 | 1219 | sc_man.cpp |
1220 | 1220 | scoreboard.cpp #ST |
1221 | + scoreboard_margin.cpp #ZA | |
1221 | 1222 | sectinfo.cpp #ST |
1222 | 1223 | st_stuff.cpp |
1223 | 1224 | statistics.cpp |
@@ -2247,7 +2247,11 @@ | ||
2247 | 2247 | ulGapBetweenColumns( 0 ), |
2248 | 2248 | ulGapBetweenRows( 0 ), |
2249 | 2249 | lHeaderHeight( 0 ), |
2250 | - lRowHeight( 0 ) { } | |
2250 | + lRowHeight( 0 ), | |
2251 | + MainHeader( MARGINTYPE_HEADER_OR_FOOTER, "MainHeader" ), | |
2252 | + TeamHeader( MARGINTYPE_TEAM, "TeamHeader" ), | |
2253 | + SpectatorHeader( MARGINTYPE_SPECTATOR, "SpectatorHeader" ), | |
2254 | + Footer( MARGINTYPE_HEADER_OR_FOOTER, "Footer" ) { } | |
2251 | 2255 | |
2252 | 2256 | //***************************************************************************** |
2253 | 2257 | // |
@@ -2772,7 +2776,7 @@ | ||
2772 | 2776 | if ( ulWidth == 0 ) |
2773 | 2777 | return; |
2774 | 2778 | |
2775 | - UpdateHeight( ); | |
2779 | + UpdateHeight( ulDisplayPlayer ); | |
2776 | 2780 | |
2777 | 2781 | // [AK] Reset the player list then sort players based on the scoreboard's rank order. |
2778 | 2782 | for ( ULONG ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) |
@@ -2839,14 +2843,18 @@ | ||
2839 | 2843 | // |
2840 | 2844 | //***************************************************************************** |
2841 | 2845 | |
2842 | -void Scoreboard::UpdateHeight( void ) | |
2846 | +void Scoreboard::UpdateHeight( const ULONG ulDisplayPlayer ) | |
2843 | 2847 | { |
2844 | 2848 | const ULONG ulRowYOffset = lRowHeight + ulGapBetweenRows; |
2845 | 2849 | const ULONG ulNumActivePlayers = HUD_GetNumPlayers( ); |
2846 | 2850 | const ULONG ulNumSpectators = HUD_GetNumSpectators( ); |
2851 | + const ULONG ulWidthWithoutBorder = ulWidth - 2 * ulBackgroundBorderSize; | |
2847 | 2852 | |
2848 | 2853 | ulHeight = 2 * ulBackgroundBorderSize + lHeaderHeight + ulGapBetweenHeaderAndRows; |
2849 | 2854 | |
2855 | + MainHeader.Refresh( ulDisplayPlayer, ulWidthWithoutBorder ); | |
2856 | + ulHeight += MainHeader.GetHeight( ); | |
2857 | + | |
2850 | 2858 | if (( ulFlags & SCOREBOARDFLAG_DONTDRAWBORDERS ) == false ) |
2851 | 2859 | { |
2852 | 2860 | // [AK] The borders are drawn in three places: above and below the column headers, and |
@@ -2869,7 +2877,16 @@ | ||
2869 | 2877 | const ULONG ulNumTeamsWithPlayers = TEAM_TeamsWithPlayersOn( ); |
2870 | 2878 | |
2871 | 2879 | if ( ulNumTeamsWithPlayers > 0 ) |
2880 | + { | |
2881 | + // [AK] Refresh and add the heights of all team headers too, if allowed. | |
2882 | + if (( ulFlags & SCOREBOARDFLAG_DONTSHOWTEAMHEADERS ) == false ) | |
2883 | + { | |
2884 | + TeamHeader.Refresh( ulDisplayPlayer, ulWidthWithoutBorder ); | |
2885 | + ulHeight += TeamHeader.GetHeight( ) * ulNumTeamsWithPlayers; | |
2886 | + } | |
2887 | + | |
2872 | 2888 | ulHeight += lRowHeight * ( ulNumTeamsWithPlayers - 1 ); |
2889 | + } | |
2873 | 2890 | } |
2874 | 2891 | } |
2875 | 2892 |
@@ -2879,9 +2896,19 @@ | ||
2879 | 2896 | if ( ulNumActivePlayers > 0 ) |
2880 | 2897 | ulHeight += lRowHeight; |
2881 | 2898 | |
2899 | + // [AK] Refresh and add the height of the spectator header too, if allowed. | |
2900 | + if (( ulFlags & SCOREBOARDFLAG_DONTSHOWTEAMHEADERS ) == false ) | |
2901 | + { | |
2902 | + SpectatorHeader.Refresh( ulDisplayPlayer, ulWidthWithoutBorder ); | |
2903 | + ulHeight += SpectatorHeader.GetHeight( ); | |
2904 | + } | |
2905 | + | |
2882 | 2906 | ulHeight += ulNumSpectators * ulRowYOffset; |
2883 | 2907 | } |
2884 | 2908 | |
2909 | + Footer.Refresh( ulDisplayPlayer, ulWidthWithoutBorder ); | |
2910 | + ulHeight += Footer.GetHeight( ); | |
2911 | + | |
2885 | 2912 | lRelY = ( HUD_GetHeight( ) - ulHeight ) / 2; |
2886 | 2913 | } |
2887 | 2914 |
@@ -2915,6 +2942,9 @@ | ||
2915 | 2942 | LONG lYPos = lRelY + ulBackgroundBorderSize; |
2916 | 2943 | bool bUseLightBackground = true; |
2917 | 2944 | |
2945 | + // [AK] Draw the main header first. | |
2946 | + MainHeader.Render( ulDisplayPlayer, ScoreMargin::NO_TEAM, lYPos, fAlpha ); | |
2947 | + | |
2918 | 2948 | // [AK] Draw a border above the column headers. |
2919 | 2949 | DrawBorder( HeaderColor, lYPos, fAlpha, false ); |
2920 | 2950 |
@@ -2932,13 +2962,21 @@ | ||
2932 | 2962 | for ( ULONG ulIdx = 0; ulIdx < ulNumActivePlayers; ulIdx++ ) |
2933 | 2963 | { |
2934 | 2964 | const ULONG ulPlayer = ulPlayerList[ulIdx]; |
2965 | + const ULONG ulTeam = players[ulPlayer].Team; | |
2935 | 2966 | |
2936 | 2967 | // [AK] In team-based game modes, if the previous player is on a different team than |
2937 | 2968 | // the current player, leave a gap between both teams and make the row background light. |
2938 | - if (( ShouldSeparateTeams( )) && ( ulIdx > 0 ) && ( players[ulPlayer].Team != players[ulPlayerList[ulIdx - 1]].Team )) | |
2969 | + if (( ShouldSeparateTeams( )) && (( ulIdx == 0 ) || ( ulTeam != players[ulPlayerList[ulIdx - 1]].Team ))) | |
2939 | 2970 | { |
2940 | - lYPos += lRowHeight; | |
2941 | - bUseLightBackground = true; | |
2971 | + if ( ulIdx > 0 ) | |
2972 | + { | |
2973 | + lYPos += lRowHeight; | |
2974 | + bUseLightBackground = true; | |
2975 | + } | |
2976 | + | |
2977 | + // [AK] Draw the header for this team, if allowed. | |
2978 | + if (( ulFlags & SCOREBOARDFLAG_DONTSHOWTEAMHEADERS ) == false ) | |
2979 | + TeamHeader.Render( ulDisplayPlayer, ulTeam, lYPos, fAlpha ); | |
2942 | 2980 | } |
2943 | 2981 | |
2944 | 2982 | DrawRow( ulPlayer, ulDisplayPlayer, lYPos, fAlpha, bUseLightBackground ); |
@@ -2957,16 +2995,23 @@ | ||
2957 | 2995 | bUseLightBackground = true; |
2958 | 2996 | } |
2959 | 2997 | |
2998 | + // [AK] Draw the header for spectators, if allowed. | |
2999 | + if (( ulFlags & SCOREBOARDFLAG_DONTSHOWTEAMHEADERS ) == false ) | |
3000 | + SpectatorHeader.Render( ulDisplayPlayer, ScoreMargin::NO_TEAM, lYPos, fAlpha ); | |
3001 | + | |
2960 | 3002 | // [AK] The index of the first true spectator should be the same as the number of active |
2961 | 3003 | // players. The list is organized such that all active players come before any true spectators. |
2962 | 3004 | for ( ULONG ulIdx = ulNumActivePlayers; ulIdx < ulTotalPlayers; ulIdx++ ) |
2963 | 3005 | DrawRow( ulPlayerList[ulIdx], ulDisplayPlayer, lYPos, fAlpha, bUseLightBackground ); |
2964 | 3006 | } |
2965 | 3007 | |
2966 | - // [AK] Finally, draw a border at the bottom of the scoreboard. We must subtract ulGapBetweenRows here (a bit hacky) | |
3008 | + // [AK] Draw a border at the bottom of the scoreboard. We must subtract ulGapBetweenRows here (a bit hacky) | |
2967 | 3009 | // because SCOREBOARD_s::DrawPlayerRow adds it every time a row is drawn. This isn't necessary for the last row. |
2968 | 3010 | lYPos += ulGapBetweenHeaderAndRows - ulGapBetweenRows; |
2969 | 3011 | DrawBorder( HeaderColor, lYPos, fAlpha, false ); |
3012 | + | |
3013 | + // [AK] Finally, draw the footer. | |
3014 | + Footer.Render( ulDisplayPlayer, ScoreMargin::NO_TEAM, lYPos, fAlpha ); | |
2970 | 3015 | } |
2971 | 3016 | |
2972 | 3017 | //***************************************************************************** |
@@ -88,6 +88,17 @@ | ||
88 | 88 | }; |
89 | 89 | |
90 | 90 | //***************************************************************************** |
91 | +// | |
92 | +// [AK] Margin types, either a header/footer, or a team or spectator header. | |
93 | +// | |
94 | +enum MARGINTYPE_e | |
95 | +{ | |
96 | + MARGINTYPE_HEADER_OR_FOOTER, | |
97 | + MARGINTYPE_TEAM, | |
98 | + MARGINTYPE_SPECTATOR, | |
99 | +}; | |
100 | + | |
101 | +//***************************************************************************** | |
91 | 102 | enum |
92 | 103 | { |
93 | 104 | COLUMN_EMPTY, |
@@ -402,6 +413,56 @@ | ||
402 | 413 | |
403 | 414 | //***************************************************************************** |
404 | 415 | // |
416 | +// [AK] ScoreMargin | |
417 | +// | |
418 | +// Draws the main header, footer, and all of the team/spectator headers using | |
419 | +// a variety of commands that are parsed from the SCORINFO lumps. | |
420 | +// | |
421 | +//***************************************************************************** | |
422 | + | |
423 | +class ScoreMargin | |
424 | +{ | |
425 | +public: | |
426 | + // [AK] A base class for all boundary commands in SCORINFO. | |
427 | + class BaseCommand | |
428 | + { | |
429 | + public: | |
430 | + BaseCommand( ScoreMargin *pMargin ); | |
431 | + | |
432 | + virtual void Parse( FScanner &sc ) = 0; | |
433 | + virtual void Refresh( const ULONG ulDisplayPlayer ) = 0; | |
434 | + virtual void Draw( const ULONG ulDisplayPlayer, const ULONG ulTeam, const LONG lYPos, const float fAlpha ) const = 0; | |
435 | + | |
436 | + protected: | |
437 | + ScoreMargin *const pParentMargin; | |
438 | + }; | |
439 | + | |
440 | + ScoreMargin( MARGINTYPE_e MarginType, const char *pszName ); | |
441 | + ~ScoreMargin( void ) { ClearCommands( ); } | |
442 | + | |
443 | + MARGINTYPE_e GetType( void ) const { return Type; } | |
444 | + const char *GetName( void ) const { return Name.GetChars( ); } | |
445 | + ULONG GetWidth( void ) const { return ulWidth; } | |
446 | + ULONG GetHeight( void ) const { return ulHeight; } | |
447 | + void IncreaseHeight( ULONG ulExtraHeight ) { ulHeight += ulExtraHeight; } | |
448 | + void Refresh( const ULONG ulDisplayPlayer, const ULONG ulNewWidth ); | |
449 | + void Render( const ULONG ulDisplayPlayer, const ULONG ulTeam, LONG &lYPos, const float fAlpha ) const; | |
450 | + | |
451 | + // [AK] Indicates that this margin is drawing for no team. | |
452 | + const static unsigned int NO_TEAM = UCHAR_MAX; | |
453 | + | |
454 | +private: | |
455 | + void ClearCommands( void ); | |
456 | + | |
457 | + TArray<BaseCommand *> Commands; | |
458 | + const MARGINTYPE_e Type; | |
459 | + const FName Name; | |
460 | + ULONG ulWidth; | |
461 | + ULONG ulHeight; | |
462 | +}; | |
463 | + | |
464 | +//***************************************************************************** | |
465 | +// | |
405 | 466 | // [AK] Scoreboard |
406 | 467 | // |
407 | 468 | // Contains all properties and columns on the scoreboard. The scoreboard is |
@@ -487,11 +548,15 @@ | ||
487 | 548 | ULONG ulPlayerList[MAXPLAYERS]; |
488 | 549 | TArray<ScoreColumn *> ColumnOrder; |
489 | 550 | TArray<DataScoreColumn *> RankOrder; |
551 | + ScoreMargin MainHeader; | |
552 | + ScoreMargin TeamHeader; | |
553 | + ScoreMargin SpectatorHeader; | |
554 | + ScoreMargin Footer; | |
490 | 555 | |
491 | 556 | void AddColumnToList( FScanner &sc, const bool bAddToRankOrder ); |
492 | 557 | void RemoveColumnFromList( FScanner &sc, const bool bRemoveFromRankOrder ); |
493 | 558 | void UpdateWidth( void ); |
494 | - void UpdateHeight( void ); | |
559 | + void UpdateHeight( const ULONG ulDisplayPlayer ); | |
495 | 560 | void DrawRow( const ULONG ulPlayer, const ULONG ulDisplayPlayer, LONG &lYPos, const float fAlpha, bool &bUseLightBackground ) const; |
496 | 561 | }; |
497 | 562 |
@@ -230,6 +230,8 @@ | ||
230 | 230 | ENUM_ELEMENT2( SCOREBOARDFLAG_DONTSEPARATETEAMS, 0x20 ), |
231 | 231 | // The local row background color is never used. |
232 | 232 | ENUM_ELEMENT2( SCOREBOARDFLAG_DONTUSELOCALROWBACKGROUNDCOLOR, 0x40 ), |
233 | + // Prevents any of the team headers from being shown. | |
234 | + ENUM_ELEMENT2( SCOREBOARDFLAG_DONTSHOWTEAMHEADERS, 0x80 ), | |
233 | 235 | } |
234 | 236 | END_ENUM( SCOREBOARDFLAG_e ) |
235 | 237 |
@@ -0,0 +1,159 @@ | ||
1 | +//----------------------------------------------------------------------------- | |
2 | +// | |
3 | +// Zandronum Source | |
4 | +// Copyright (C) 2021-2023 Adam Kaminski | |
5 | +// Copyright (C) 2021-2023 Zandronum Development Team | |
6 | +// All rights reserved. | |
7 | +// | |
8 | +// Redistribution and use in source and binary forms, with or without | |
9 | +// modification, are permitted provided that the following conditions are met: | |
10 | +// | |
11 | +// 1. Redistributions of source code must retain the above copyright notice, | |
12 | +// this list of conditions and the following disclaimer. | |
13 | +// 2. Redistributions in binary form must reproduce the above copyright notice, | |
14 | +// this list of conditions and the following disclaimer in the documentation | |
15 | +// and/or other materials provided with the distribution. | |
16 | +// 3. Neither the name of the Zandronum Development Team nor the names of its | |
17 | +// contributors may be used to endorse or promote products derived from this | |
18 | +// software without specific prior written permission. | |
19 | +// 4. Redistributions in any form must be accompanied by information on how to | |
20 | +// obtain complete source code for the software and any accompanying | |
21 | +// software that uses the software. The source code must either be included | |
22 | +// in the distribution or be available for no more than the cost of | |
23 | +// distribution plus a nominal fee, and must be freely redistributable | |
24 | +// under reasonable conditions. For an executable file, complete source | |
25 | +// code means the source code for all modules it contains. It does not | |
26 | +// include source code for modules or files that typically accompany the | |
27 | +// major components of the operating system on which the executable file | |
28 | +// runs. | |
29 | +// | |
30 | +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
31 | +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
32 | +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
33 | +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
34 | +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
35 | +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
36 | +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
37 | +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
38 | +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
39 | +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
40 | +// POSSIBILITY OF SUCH DAMAGE. | |
41 | +// | |
42 | +// | |
43 | +// | |
44 | +// Filename: scoreboard_margin.cpp | |
45 | +// | |
46 | +// Description: Contains everything that controls the scoreboard's margins | |
47 | +// (i.e. the main header, team/spectator headers, and the footer). | |
48 | +// | |
49 | +//----------------------------------------------------------------------------- | |
50 | + | |
51 | +#include "scoreboard.h" | |
52 | + | |
53 | +//***************************************************************************** | |
54 | +// FUNCTIONS | |
55 | + | |
56 | +//***************************************************************************** | |
57 | +// | |
58 | +// [AK] ScoreMargin::BaseCommand::BaseCommand | |
59 | +// | |
60 | +// Initializes a margin command. | |
61 | +// | |
62 | +//***************************************************************************** | |
63 | + | |
64 | +ScoreMargin::BaseCommand::BaseCommand( ScoreMargin *pMargin ) : pParentMargin( pMargin ) | |
65 | +{ | |
66 | + // [AK] This should never happen, but throw a fatal error if it does. | |
67 | + if ( pParentMargin == NULL ) | |
68 | + I_Error( "ScoreMargin::BaseCommand: parent margin is NULL." ); | |
69 | +} | |
70 | + | |
71 | +//***************************************************************************** | |
72 | +// | |
73 | +// [AK] ScoreMargin::ScoreMargin | |
74 | +// | |
75 | +// Initializes a margin's members to their default values. | |
76 | +// | |
77 | +//***************************************************************************** | |
78 | + | |
79 | +ScoreMargin::ScoreMargin( MARGINTYPE_e MarginType, const char *pszName ) : | |
80 | + Type( MarginType ), | |
81 | + Name( pszName ), | |
82 | + ulWidth( 0 ), | |
83 | + ulHeight( 0 ) { } | |
84 | + | |
85 | +//***************************************************************************** | |
86 | +// | |
87 | +// [AK] ScoreMargin::Refresh | |
88 | +// | |
89 | +// Updates the margin's width and height, then refreshes its command list. | |
90 | +// | |
91 | +//***************************************************************************** | |
92 | + | |
93 | +void ScoreMargin::Refresh( const ULONG ulDisplayPlayer, const ULONG ulNewWidth ) | |
94 | +{ | |
95 | + // [AK] If there's no commands, then don't do anything. | |
96 | + if ( Commands.Size( ) == 0 ) | |
97 | + return; | |
98 | + | |
99 | + // [AK] Never accept a width of zero, throw a fatal error if this happens. | |
100 | + if ( ulNewWidth == 0 ) | |
101 | + I_Error( "ScoreMargin::Refresh: tried assigning a width of zero to '%s'.", GetName( )); | |
102 | + | |
103 | + ulWidth = ulNewWidth; | |
104 | + ulHeight = 0; | |
105 | + | |
106 | + for ( unsigned int i = 0; i < Commands.Size( ); i++ ) | |
107 | + Commands[i]->Refresh( ulDisplayPlayer ); | |
108 | +} | |
109 | + | |
110 | +//***************************************************************************** | |
111 | +// | |
112 | +// [AK] ScoreMargin::Render | |
113 | +// | |
114 | +// Draws all commands that are defined inside the margin. | |
115 | +// | |
116 | +//***************************************************************************** | |
117 | + | |
118 | +void ScoreMargin::Render( const ULONG ulDisplayPlayer, const ULONG ulTeam, LONG &lYPos, const float fAlpha ) const | |
119 | +{ | |
120 | + // [AK] If this is supposed to be a team header, then we can't draw for invalid teams! | |
121 | + if ( Type == MARGINTYPE_TEAM ) | |
122 | + { | |
123 | + if (( ulTeam == NO_TEAM ) || ( ulTeam >= teams.Size( ))) | |
124 | + I_Error( "ScoreMargin::Render: '%s' can't be drawn for invalid teams.", GetName( )); | |
125 | + } | |
126 | + // [AK] Otherwise, if this is a non-team header, then we can't draw for any specific team! | |
127 | + else if ( ulTeam != NO_TEAM ) | |
128 | + { | |
129 | + I_Error( "ScoreMargin::Render: '%s' must not be drawn for any specific team.", GetName( )); | |
130 | + } | |
131 | + | |
132 | + // [AK] If there's no commands, or the width or height are zero, then we can't draw anything. | |
133 | + if (( Commands.Size( ) == 0 ) || ( ulWidth == 0 ) || ( ulHeight == 0 )) | |
134 | + return; | |
135 | + | |
136 | + for ( unsigned int i = 0; i < Commands.Size( ); i++ ) | |
137 | + Commands[i]->Draw( ulDisplayPlayer, ulTeam, lYPos, fAlpha ); | |
138 | + | |
139 | + lYPos += ulHeight; | |
140 | +} | |
141 | + | |
142 | +//***************************************************************************** | |
143 | +// | |
144 | +// [AK] ScoreMargin::ClearCommands | |
145 | +// | |
146 | +// Deletes all of the margin's commands from memory. | |
147 | +// | |
148 | +//***************************************************************************** | |
149 | + | |
150 | +void ScoreMargin::ClearCommands( void ) | |
151 | +{ | |
152 | + for ( unsigned int i = 0; i < Commands.Size( ); i++ ) | |
153 | + { | |
154 | + delete Commands[i]; | |
155 | + Commands[i] = NULL; | |
156 | + } | |
157 | + | |
158 | + Commands.Clear( ); | |
159 | +} |