1 (* Copyright (C) Doom 2D: Forever Developers
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 {$INCLUDE ../../shared/a_modes.inc}
20 procedure r_Game_Load
;
21 procedure r_Game_Free
;
23 procedure r_Game_LoadTextures
;
24 procedure r_Game_FreeTextures
;
26 procedure r_Game_Draw
;
27 procedure r_Game_DrawLoadingStat
;
28 procedure r_Game_DrawMenuBackground (tex
: AnsiString);
30 procedure r_Game_SetupScreenSize
;
35 gMenuSmallFont
: DWORD
;
40 {$INCLUDE ../nogl/noGLuses.inc}
41 {$IFDEF ENABLE_HOLMES}
50 {$IFDEF ENABLE_CORPSES}
53 {$IFDEF ENABLE_SYSTEM}
56 SysUtils
, Classes
, Math
,
57 g_base
, g_basic
, r_graphics
,
58 MAPDEF
, xprofiler
, utils
, wadreader
, CONFIG
,
60 g_language
, g_console
, g_triggers
, g_player
, g_options
, g_monsters
, g_map
, g_panel
,
61 g_items
, g_weapons
, g_phys
, g_net
, g_netmaster
,
62 g_game
, r_console
, r_items
, r_map
, r_monsters
, r_weapons
, r_netmaster
, r_player
, r_textures
,
67 profileFrameDraw
: TProfiler
= nil;
74 BackID
: DWORD
= DWORD(-1);
77 procedure LoadStdFont(cfgres
, texture
: string; var FontID
: DWORD
);
89 wad
:= TWADFile
.Create
;
90 if wad
.ReadFile(GameWAD
) then
91 wad
.GetResource('FONTS/'+cfgres
, cfgdata
, cfglen
);
96 g_Texture_CreateWADEx('FONT_STD', GameWAD
+':FONTS\'+texture
);
98 config
:= TConfig
.CreateMem(cfgdata
, cfglen
);
99 cwdt
:= Min(Max(config
.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
100 chgt
:= Min(Max(config
.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
101 spc
:= Min(Max(config
.ReadInt('FontMap', 'Kerning', 0), -128), 127);
103 if g_Texture_Get('FONT_STD', ID
) then
104 e_TextureFontBuild(ID
, FontID
, cwdt
, chgt
, spc
);
109 if cfglen
<> 0 then FreeMem(cfgdata
);
112 procedure LoadFont(txtres
, fntres
: string; var FontID
: DWORD
);
118 cfgdata
, fntdata
: Pointer;
119 cfglen
, fntlen
: Integer;
127 wad
:= TWADFile
.Create
;
128 if wad
.ReadFile(GameWAD
) then
130 wad
.GetResource('FONTS/'+txtres
, cfgdata
, cfglen
);
131 wad
.GetResource('FONTS/'+fntres
, fntdata
, fntlen
);
137 config
:= TConfig
.CreateMem(cfgdata
, cfglen
);
138 cwdt
:= Min(Max(config
.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
139 chgt
:= Min(Max(config
.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
141 spc
:= Min(Max(config
.ReadInt('FontMap', 'Kerning', 0), -128), 127);
142 FontID
:= e_CharFont_Create(spc
);
146 chrwidth
:= config
.ReadInt(IntToStr(a
), 'Width', 0);
147 if chrwidth
= 0 then Continue
;
149 if e_CreateTextureMemEx(fntdata
, fntlen
, CharID
, cwdt
*(a
mod 16), chgt
*(a
div 16),
151 e_CharFont_AddChar(FontID
, CharID
, Chr(a
), chrwidth
);
157 if cfglen
<> 0 then FreeMem(cfgdata
);
158 if fntlen
<> 0 then FreeMem(fntdata
);
161 procedure r_Game_Load
;
169 g_Texture_CreateWADEx('MENU_BACKGROUND', GameWAD
+ ':TEXTURES\TITLE', gTextureFilter
);
170 g_Texture_CreateWADEx('INTER', GameWAD
+ ':TEXTURES\INTER', gTextureFilter
);
171 g_Texture_CreateWADEx('ENDGAME_EN', GameWAD
+ ':TEXTURES\ENDGAME_EN', gTextureFilter
);
172 g_Texture_CreateWADEx('ENDGAME_RU', GameWAD
+ ':TEXTURES\ENDGAME_RU', gTextureFilter
);
173 LoadStdFont('STDTXT', 'STDFONT', gStdFont
);
174 LoadFont('MENUTXT', 'MENUFONT', gMenuFont
);
175 LoadFont('SMALLTXT', 'SMALLFONT', gMenuSmallFont
);
177 g_Texture_CreateWADEx('NOTEXTURE', GameWAD
+ ':TEXTURES\NOTEXTURE');
178 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUD', GameWAD
+ ':TEXTURES\HUD');
179 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDAIR', GameWAD
+ ':TEXTURES\AIRBAR');
180 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDJET', GameWAD
+ ':TEXTURES\JETBAR');
181 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDBG', GameWAD
+ ':TEXTURES\HUDBG');
182 g_Texture_CreateWADEx('TEXTURE_PLAYER_ARMORHUD', GameWAD
+ ':TEXTURES\ARMORHUD');
183 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG', GameWAD
+ ':TEXTURES\FLAGHUD_R_BASE');
184 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_S', GameWAD
+ ':TEXTURES\FLAGHUD_R_STOLEN');
185 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_D', GameWAD
+ ':TEXTURES\FLAGHUD_R_DROP');
186 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG', GameWAD
+ ':TEXTURES\FLAGHUD_B_BASE');
187 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_S', GameWAD
+ ':TEXTURES\FLAGHUD_B_STOLEN');
188 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_D', GameWAD
+ ':TEXTURES\FLAGHUD_B_DROP');
189 g_Texture_CreateWADEx('TEXTURE_PLAYER_TALKBUBBLE', GameWAD
+ ':TEXTURES\TALKBUBBLE');
190 g_Texture_CreateWADEx('TEXTURE_PLAYER_INVULPENTA', GameWAD
+ ':TEXTURES\PENTA');
191 g_Texture_CreateWADEx('TEXTURE_PLAYER_INDICATOR', GameWAD
+ ':TEXTURES\PLRIND');
194 if not g_Texture_CreateWADEx('UI_GFX_PBAR_LEFT', GameWAD
+':TEXTURES\LLEFT') then hasPBarGfx
:= false;
195 if not g_Texture_CreateWADEx('UI_GFX_PBAR_MARKER', GameWAD
+':TEXTURES\LMARKER') then hasPBarGfx
:= false;
196 if not g_Texture_CreateWADEx('UI_GFX_PBAR_MIDDLE', GameWAD
+':TEXTURES\LMIDDLE') then hasPBarGfx
:= false;
197 if not g_Texture_CreateWADEx('UI_GFX_PBAR_RIGHT', GameWAD
+':TEXTURES\LRIGHT') then hasPBarGfx
:= false;
200 g_Texture_GetSize('UI_GFX_PBAR_LEFT', wl
, hl
);
201 g_Texture_GetSize('UI_GFX_PBAR_RIGHT', wr
, hr
);
202 g_Texture_GetSize('UI_GFX_PBAR_MIDDLE', wb
, hb
);
203 g_Texture_GetSize('UI_GFX_PBAR_MARKER', wm
, hm
);
204 if (wl
> 0) and (hl
> 0) and (wr
> 0) and (hr
= hl
) and (wb
> 0) and (hb
= hl
) and (wm
> 0) and (hm
> 0) and (hm
<= hl
) then
213 procedure r_Game_Free
;
215 e_CharFont_Remove(gMenuFont
);
216 e_CharFont_Remove(gMenuSmallFont
);
217 g_Texture_Delete('NOTEXTURE');
218 g_Texture_Delete('TEXTURE_PLAYER_HUD');
219 g_Texture_Delete('TEXTURE_PLAYER_HUDBG');
220 g_Texture_Delete('TEXTURE_PLAYER_ARMORHUD');
221 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG');
222 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_S');
223 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_D');
224 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG');
225 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_S');
226 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_D');
227 g_Texture_Delete('TEXTURE_PLAYER_TALKBUBBLE');
228 g_Texture_Delete('TEXTURE_PLAYER_INVULPENTA');
231 procedure r_Game_SetupScreenSize
;
233 RES_FACTOR
= 4.0 / 3.0;
239 // Размер экранов игроков:
240 gPlayerScreenSize
.X
:= gScreenWidth
-196;
241 if (gPlayer1
<> nil) and (gPlayer2
<> nil) then
242 gPlayerScreenSize
.Y
:= gScreenHeight
div 2
244 gPlayerScreenSize
.Y
:= gScreenHeight
;
246 // Размер заднего плана:
247 if BackID
<> DWORD(-1) then
250 if (gScreenWidth
*s
> gMapInfo
.Width
) or
251 (gScreenHeight
*s
> gMapInfo
.Height
) then
253 gBackSize
.X
:= gScreenWidth
;
254 gBackSize
.Y
:= gScreenHeight
;
258 e_GetTextureSize(BackID
, @bw
, @bh
);
259 rf
:= Single(bw
) / Single(bh
);
260 if (rf
> RES_FACTOR
) then bw
:= Round(Single(bh
) * RES_FACTOR
)
261 else if (rf
< RES_FACTOR
) then bh
:= Round(Single(bw
) / RES_FACTOR
);
262 s
:= Max(gScreenWidth
/ bw
, gScreenHeight
/ bh
);
263 if (s
< 1.0) then s
:= 1.0;
264 gBackSize
.X
:= Round(bw
*s
);
265 gBackSize
.Y
:= Round(bh
*s
);
270 procedure r_Game_LoadTextures
;
272 g_Texture_CreateWADEx('TEXTURE_endpic', EndPicPath
, gTextureFilter
);
273 if gMapInfo
.SkyFullName
<> '' then
274 g_Texture_CreateWAD(BackID
, gMapInfo
.SkyFullName
, gTextureFilter
);
275 r_Game_SetupScreenSize
;
278 procedure r_Game_FreeTextures
;
280 g_Texture_Delete('TEXTURE_endpic');
281 if BackID
<> DWORD(-1) then
285 e_DeleteTexture(BackID
);
290 procedure r_Map_DrawBack(dx
, dy
: Integer);
292 if gDrawBackGround
and (BackID
<> DWORD(-1)) then
293 e_DrawSize(BackID
, dx
, dy
, 0, False, False, gBackSize
.X
, gBackSize
.Y
)
295 e_Clear(GL_COLOR_BUFFER_BIT
, 0, 0, 0);
298 function GetActivePlayer_ByID(ID
: Integer): TPlayer
;
305 if gPlayers
= nil then
307 for a
:= Low(gPlayers
) to High(gPlayers
) do
308 if IsActivePlayer(gPlayers
[a
]) then
310 if gPlayers
[a
].UID
<> ID
then
312 Result
:= gPlayers
[a
];
317 function calcProfilesHeight (prof
: TProfiler
): Integer;
320 if (prof
= nil) then exit
;
321 if (length(prof
.bars
) = 0) then exit
;
322 result
:= length(prof
.bars
)*(16+2);
326 function drawProfiles (x
, y
: Integer; prof
: TProfiler
): Integer;
333 if (prof
= nil) then exit
;
335 if (length(prof
.bars
) = 0) then exit
;
337 hgt
:= calcProfilesHeight(prof
);
338 if (x
< 0) then x
:= gScreenWidth
-(wdt
-1)+x
;
339 if (y
< 0) then y
:= gScreenHeight
-(hgt
-1)+y
;
341 //e_DrawFillQuad(x, y, x+wdt-1, y+hgt-1, 255, 255, 255, 200, B_BLEND);
342 //e_DrawFillQuad(x, y, x+wdt-1, y+hgt-1, 20, 20, 20, 0, B_NONE);
343 e_DarkenQuadWH(x
, y
, wdt
, hgt
, 150);
346 for ii
:= 0 to High(prof
.bars
) do
348 e_TextureFontPrintEx(x
+2+4*prof
.bars
[ii
].level
, yy
, Format('%s: %d', [prof
.bars
[ii
].name
, prof
.bars
[ii
].value
]), gStdFont
, 255, 255, 0, 1, false);
354 procedure drawTime(X
, Y
: Integer); inline;
356 e_TextureFontPrint(x
, y
, Format('%d:%.2d:%.2d', [gTime
div 1000 div 3600, (gTime
div 1000 div 60) mod 60, gTime
div 1000 mod 60]), gStdFont
);
359 procedure DrawStat();
361 pc
, x
, y
, w
, h
: Integer;
362 w1
, w2
, w3
, w4
: Integer;
364 cw
, ch
, r
, g
, b
, rr
, gg
, bb
: Byte;
367 stat
: TPlayerStatArray
;
375 pc
:= g_Player_GetCount
;
376 e_TextureFontGetSize(gStdFont
, cw
, ch
);
378 w
:= gScreenWidth
-(gScreenWidth
div 5);
379 if gGameSettings
.GameMode
in [GM_TDM
, GM_CTF
] then
382 h
:= 40+ch
*5+(ch
+8)*pc
;
383 x
:= (gScreenWidth
div 2)-(w
div 2);
384 y
:= (gScreenHeight
div 2)-(h
div 2);
386 e_DrawFillQuad(x
, y
, x
+w
-1, y
+h
-1, 64, 64, 64, 32);
387 e_DrawQuad(x
, y
, x
+w
-1, y
+h
-1, 255, 127, 0);
389 drawTime(x
+w
-78, y
+8);
391 wad
:= g_ExtractWadNameNoPath(gMapInfo
.Map
);
392 map
:= g_ExtractFileName(gMapInfo
.Map
);
393 mapstr
:= wad
+ ':\' + map
+ ' - ' + gMapInfo
.Name
;
395 case gGameSettings
.GameMode
of
398 if gGameSettings
.MaxLives
= 0 then
401 s1
:= _lc
[I_GAME_LMS
];
402 s2
:= Format(_lc
[I_GAME_FRAG_LIMIT
], [gGameSettings
.ScoreLimit
]);
403 s3
:= Format(_lc
[I_GAME_TIME_LIMIT
], [gGameSettings
.TimeLimit
div 3600, (gGameSettings
.TimeLimit
div 60) mod 60, gGameSettings
.TimeLimit
mod 60]);
408 if gGameSettings
.MaxLives
= 0 then
409 s1
:= _lc
[I_GAME_TDM
]
411 s1
:= _lc
[I_GAME_TLMS
];
412 s2
:= Format(_lc
[I_GAME_FRAG_LIMIT
], [gGameSettings
.ScoreLimit
]);
413 s3
:= Format(_lc
[I_GAME_TIME_LIMIT
], [gGameSettings
.TimeLimit
div 3600, (gGameSettings
.TimeLimit
div 60) mod 60, gGameSettings
.TimeLimit
mod 60]);
418 s1
:= _lc
[I_GAME_CTF
];
419 s2
:= Format(_lc
[I_GAME_SCORE_LIMIT
], [gGameSettings
.ScoreLimit
]);
420 s3
:= Format(_lc
[I_GAME_TIME_LIMIT
], [gGameSettings
.TimeLimit
div 3600, (gGameSettings
.TimeLimit
div 60) mod 60, gGameSettings
.TimeLimit
mod 60]);
425 if gGameSettings
.MaxLives
= 0 then
426 s1
:= _lc
[I_GAME_COOP
]
428 s1
:= _lc
[I_GAME_SURV
];
429 s2
:= _lc
[I_GAME_MONSTERS
] + ' ' + IntToStr(gCoopMonstersKilled
) + '/' + IntToStr(gTotalMonsters
);
430 s3
:= _lc
[I_GAME_SECRETS
] + ' ' + IntToStr(gCoopSecretsFound
) + '/' + IntToStr(gSecretsCount
);
440 e_TextureFontPrintEx(x
+(w
div 2)-(Length(s1
)*cw
div 2), _y
, s1
, gStdFont
, 255, 255, 255, 1);
442 e_TextureFontPrintEx(x
+(w
div 2)-(Length(mapstr
)*cw
div 2), _y
, mapstr
, gStdFont
, 200, 200, 200, 1);
444 e_TextureFontPrintEx(x
+16, _y
, s2
, gStdFont
, 200, 200, 200, 1);
446 e_TextureFontPrintEx(x
+w
-16-(Length(s3
))*cw
, _y
, s3
,
447 gStdFont
, 200, 200, 200, 1);
449 if NetMode
= NET_SERVER
then
450 e_TextureFontPrintEx(x
+8, y
+ 8, _lc
[I_NET_SERVER
], gStdFont
, 255, 255, 255, 1)
452 if NetMode
= NET_CLIENT
then
453 e_TextureFontPrintEx(x
+8, y
+ 8,
454 NetClientIP
+ ':' + IntToStr(NetClientPort
), gStdFont
, 255, 255, 255, 1);
458 stat
:= g_Player_GetStats();
461 w2
:= (w
-16) div 6 + 48; // ширина 2 столбца
462 w3
:= (w
-16) div 6; // ширина 3 и 4 столбцов
464 w1
:= w
-16-w2
-w3
-w4
; // оставшееся пространство - для цвета и имени игрока
466 if gGameSettings
.GameMode
in [GM_TDM
, GM_CTF
] then
470 for a
:= TEAM_RED
to TEAM_BLUE
do
474 s1
:= _lc
[I_GAME_TEAM_RED
];
481 s1
:= _lc
[I_GAME_TEAM_BLUE
];
487 e_TextureFontPrintEx(x
+16, _y
, s1
, gStdFont
, r
, g
, b
, 1);
488 e_TextureFontPrintEx(x
+w1
+16, _y
, IntToStr(gTeamStat
[a
].Score
),
489 gStdFont
, r
, g
, b
, 1);
491 _y
:= _y
+ch
+(ch
div 4);
492 e_DrawLine(1, x
+16, _y
, x
+w
-16, _y
, r
, g
, b
);
495 for aa
:= 0 to High(stat
) do
496 if stat
[aa
].Team
= a
then
512 namestr
:= Format('[%5d] %s', [UID
, Name
])
516 e_TextureFontPrintEx(x
+16, _y
, namestr
, gStdFont
, rr
, gg
, bb
, 1);
518 e_TextureFontPrintEx(x
+w1
+16, _y
, Format(_lc
[I_GAME_PING_MS
], [Ping
, Loss
]), gStdFont
, rr
, gg
, bb
, 1);
520 e_TextureFontPrintEx(x
+w1
+w2
+16, _y
, IntToStr(Frags
), gStdFont
, rr
, gg
, bb
, 1);
522 e_TextureFontPrintEx(x
+w1
+w2
+w3
+16, _y
, IntToStr(Deaths
), gStdFont
, rr
, gg
, bb
, 1);
529 else if gGameSettings
.GameMode
in [GM_DM
, GM_COOP
] then
532 e_TextureFontPrintEx(x
+16, _y
, _lc
[I_GAME_PLAYER_NAME
], gStdFont
, 255, 127, 0, 1);
533 e_TextureFontPrintEx(x
+16+w1
, _y
, _lc
[I_GAME_PING
], gStdFont
, 255, 127, 0, 1);
534 e_TextureFontPrintEx(x
+16+w1
+w2
, _y
, _lc
[I_GAME_FRAGS
], gStdFont
, 255, 127, 0, 1);
535 e_TextureFontPrintEx(x
+16+w1
+w2
+w3
, _y
, _lc
[I_GAME_DEATHS
], gStdFont
, 255, 127, 0, 1);
538 for aa
:= 0 to High(stat
) do
552 namestr
:= Format('[%5d] %s', [UID
, Name
])
556 e_DrawFillQuad(x
+16, _y
+4, x
+32-1, _y
+16+4-1, Color
.R
, Color
.G
, Color
.B
, 0);
557 e_DrawQuad(x
+16, _y
+4, x
+32-1, _y
+16+4-1, 192, 192, 192);
559 e_TextureFontPrintEx(x
+16+16+8, _y
+4, namestr
, gStdFont
, r
, g
, 0, 1);
561 e_TextureFontPrintEx(x
+w1
+16, _y
+4, Format(_lc
[I_GAME_PING_MS
], [Ping
, Loss
]), gStdFont
, r
, g
, 0, 1);
563 e_TextureFontPrintEx(x
+w1
+w2
+16, _y
+4, IntToStr(Frags
), gStdFont
, r
, g
, 0, 1);
565 e_TextureFontPrintEx(x
+w1
+w2
+w3
+16, _y
+4, IntToStr(Deaths
), gStdFont
, r
, g
, 0, 1);
571 procedure DrawCustomStat();
577 ww2
, hh2
, r
, g
, b
, rr
, gg
, bb
: Byte;
578 s1
, s2
, topstr
: String;
580 e_TextureFontGetSize(gStdFont
, ww2
, hh2
);
582 {$IFDEF ENABLE_SYSTEM}
586 if g_Console_Action(ACTION_SCORES
) then
588 if not gStatsPressed
then
590 gStatsOff
:= not gStatsOff
;
591 gStatsPressed
:= True;
595 gStatsPressed
:= False;
599 s1
:= _lc
[I_MENU_INTER_NOTICE_TAB
];
600 w
:= (Length(s1
) * ww2
) div 2;
601 x
:= gScreenWidth
div 2 - w
;
603 e_TextureFontPrint(x
, y
, s1
, gStdFont
);
607 if (gGameSettings
.GameMode
= GM_COOP
) then
609 if gMissionFailed
then
610 topstr
:= _lc
[I_MENU_INTER_MISSION_FAIL
]
612 topstr
:= _lc
[I_MENU_INTER_LEVEL_COMPLETE
];
615 topstr
:= _lc
[I_MENU_INTER_ROUND_OVER
];
617 e_CharFont_GetSize(gMenuFont
, topstr
, ww1
, hh1
);
618 e_CharFont_Print(gMenuFont
, (gScreenWidth
div 2)-(ww1
div 2), 16, topstr
);
622 topstr
:= Format(_lc
[I_MENU_INTER_NOTICE_TIME
], [gServInterTime
]);
623 if not gChatShow
then
624 e_TextureFontPrintEx((gScreenWidth
div 2)-(Length(topstr
)*ww2
div 2),
625 gScreenHeight
-(hh2
+4)*2, topstr
, gStdFont
, 255, 255, 255, 1);
628 if g_Game_IsClient
then
629 topstr
:= _lc
[I_MENU_INTER_NOTICE_MAP
]
631 topstr
:= _lc
[I_MENU_INTER_NOTICE_SPACE
];
632 if not gChatShow
then
633 e_TextureFontPrintEx((gScreenWidth
div 2)-(Length(topstr
)*ww2
div 2),
634 gScreenHeight
-(hh2
+4), topstr
, gStdFont
, 255, 255, 255, 1);
639 w
:= gScreenWidth
-x
*2;
645 e_DrawFillQuad(x
, y
, gScreenWidth
-x
-1, gScreenHeight
-y
-1, 64, 64, 64, 32);
646 e_DrawQuad(x
, y
, gScreenWidth
-x
-1, gScreenHeight
-y
-1, 255, 127, 0);
648 m
:= Max(Length(_lc
[I_MENU_MAP
])+1, Length(_lc
[I_GAME_GAME_TIME
])+1)*ww2
;
650 case CustomStat
.GameMode
of
653 if gGameSettings
.MaxLives
= 0 then
656 s1
:= _lc
[I_GAME_LMS
];
660 if gGameSettings
.MaxLives
= 0 then
661 s1
:= _lc
[I_GAME_TDM
]
663 s1
:= _lc
[I_GAME_TLMS
];
665 GM_CTF
: s1
:= _lc
[I_GAME_CTF
];
668 if gGameSettings
.MaxLives
= 0 then
669 s1
:= _lc
[I_GAME_COOP
]
671 s1
:= _lc
[I_GAME_SURV
];
677 e_TextureFontPrintEx(x
+(w
div 2)-(Length(s1
)*ww2
div 2), _y
, s1
, gStdFont
, 255, 255, 255, 1);
681 e_TextureFontPrintEx(x
+8, _y
, _lc
[I_MENU_MAP
], gStdFont
, 255, 127, 0, 1);
682 e_TextureFontPrint(x
+8+m
, _y
, Format('%s - %s', [CustomStat
.Map
, CustomStat
.MapName
]), gStdFont
);
685 e_TextureFontPrintEx(x
+8, _y
, _lc
[I_GAME_GAME_TIME
], gStdFont
, 255, 127, 0, 1);
686 e_TextureFontPrint(x
+8+m
, _y
, Format('%d:%.2d:%.2d', [CustomStat
.GameTime
div 1000 div 3600,
687 (CustomStat
.GameTime
div 1000 div 60) mod 60,
688 CustomStat
.GameTime
div 1000 mod 60]), gStdFont
);
690 pc
:= Length(CustomStat
.PlayerStat
);
693 if CustomStat
.GameMode
= GM_COOP
then
695 m
:= Max(Length(_lc
[I_GAME_MONSTERS
])+1, Length(_lc
[I_GAME_SECRETS
])+1)*ww2
;
697 s2
:= _lc
[I_GAME_MONSTERS
];
698 e_TextureFontPrintEx(x
+8, _y
, s2
, gStdFont
, 255, 127, 0, 1);
699 e_TextureFontPrintEx(x
+8+m
, _y
, IntToStr(gCoopMonstersKilled
) + '/' + IntToStr(gTotalMonsters
), gStdFont
, 255, 255, 255, 1);
701 s2
:= _lc
[I_GAME_SECRETS
];
702 e_TextureFontPrintEx(x
+8, _y
, s2
, gStdFont
, 255, 127, 0, 1);
703 e_TextureFontPrintEx(x
+8+m
, _y
, IntToStr(gCoopSecretsFound
) + '/' + IntToStr(gSecretsCount
), gStdFont
, 255, 255, 255, 1);
706 m
:= Max(Length(_lc
[I_GAME_MONSTERS_TOTAL
])+1, Length(_lc
[I_GAME_SECRETS_TOTAL
])+1)*ww2
;
708 s2
:= _lc
[I_GAME_MONSTERS_TOTAL
];
709 e_TextureFontPrintEx(x
+250, _y
, s2
, gStdFont
, 255, 127, 0, 1);
710 e_TextureFontPrintEx(x
+250+m
, _y
, IntToStr(gCoopTotalMonstersKilled
) + '/' + IntToStr(gCoopTotalMonsters
), gStdFont
, 255, 255, 255, 1);
712 s2
:= _lc
[I_GAME_SECRETS_TOTAL
];
713 e_TextureFontPrintEx(x
+250, _y
, s2
, gStdFont
, 255, 127, 0, 1);
714 e_TextureFontPrintEx(x
+250+m
, _y
, IntToStr(gCoopTotalSecretsFound
) + '/' + IntToStr(gCoopTotalSecrets
), gStdFont
, 255, 255, 255, 1);
718 if CustomStat
.GameMode
in [GM_TDM
, GM_CTF
] then
723 if TeamStat
[TEAM_RED
].Score
> TeamStat
[TEAM_BLUE
].Score
then s1
:= _lc
[I_GAME_WIN_RED
]
724 else if TeamStat
[TEAM_BLUE
].Score
> TeamStat
[TEAM_RED
].Score
then s1
:= _lc
[I_GAME_WIN_BLUE
]
725 else s1
:= _lc
[I_GAME_WIN_DRAW
];
727 e_TextureFontPrintEx(x
+8+(w
div 2)-(Length(s1
)*ww2
div 2), _y
, s1
, gStdFont
, 255, 255, 255, 1);
730 for t
:= TEAM_RED
to TEAM_BLUE
do
734 e_TextureFontPrintEx(x
+8, _y
, _lc
[I_GAME_TEAM_RED
],
735 gStdFont
, 255, 0, 0, 1);
736 e_TextureFontPrintEx(x
+w1
+8, _y
, IntToStr(CustomStat
.TeamStat
[TEAM_RED
].Score
),
737 gStdFont
, 255, 0, 0, 1);
744 e_TextureFontPrintEx(x
+8, _y
, _lc
[I_GAME_TEAM_BLUE
],
745 gStdFont
, 0, 0, 255, 1);
746 e_TextureFontPrintEx(x
+w1
+8, _y
, IntToStr(CustomStat
.TeamStat
[TEAM_BLUE
].Score
),
747 gStdFont
, 0, 0, 255, 1);
753 e_DrawLine(1, x
+8, _y
+20, x
-8+w
, _y
+20, r
, g
, b
);
756 for p
:= 0 to High(CustomStat
.PlayerStat
) do
757 if CustomStat
.PlayerStat
[p
].Team
= t
then
758 with CustomStat
.PlayerStat
[p
] do
772 if (gPlayers
[Num
] <> nil) and (gPlayers
[Num
].FReady
) then
773 e_TextureFontPrintEx(x
+16, _y
, Name
+ ' *', gStdFont
, rr
, gg
, bb
, 1)
775 e_TextureFontPrintEx(x
+16, _y
, Name
, gStdFont
, rr
, gg
, bb
, 1);
776 e_TextureFontPrintEx(x
+w1
+16, _y
, IntToStr(Frags
), gStdFont
, rr
, gg
, bb
, 1);
777 e_TextureFontPrintEx(x
+w1
+w2
+16, _y
, IntToStr(Deaths
), gStdFont
, rr
, gg
, bb
, 1);
784 else if CustomStat
.GameMode
in [GM_DM
, GM_COOP
] then
787 e_TextureFontPrintEx(x
+8, _y
, _lc
[I_GAME_PLAYER_NAME
], gStdFont
, 255, 127, 0, 1);
788 e_TextureFontPrintEx(x
+8+w1
, _y
, _lc
[I_GAME_FRAGS
], gStdFont
, 255, 127, 0, 1);
789 e_TextureFontPrintEx(x
+8+w1
+w2
, _y
, _lc
[I_GAME_DEATHS
], gStdFont
, 255, 127, 0, 1);
792 for p
:= 0 to High(CustomStat
.PlayerStat
) do
793 with CustomStat
.PlayerStat
[p
] do
795 e_DrawFillQuad(x
+8, _y
+4, x
+24-1, _y
+16+4-1, Color
.R
, Color
.G
, Color
.B
, 0);
802 if (gPlayers
[Num
] <> nil) and (gPlayers
[Num
].FReady
) then
803 e_TextureFontPrintEx(x
+8+16+8, _y
+4, Name
+ ' *', gStdFont
, r
, r
, r
, 1, True)
805 e_TextureFontPrintEx(x
+8+16+8, _y
+4, Name
, gStdFont
, r
, r
, r
, 1, True);
806 e_TextureFontPrintEx(x
+w1
+8+16+8, _y
+4, IntToStr(Frags
), gStdFont
, r
, r
, r
, 1, True);
807 e_TextureFontPrintEx(x
+w1
+w2
+8+16+8, _y
+4, IntToStr(Deaths
), gStdFont
, r
, r
, r
, 1, True);
812 // HACK: take stats screenshot immediately after the first frame of the stats showing
813 if gScreenshotStats
and (not StatShotDone
) and (Length(CustomStat
.PlayerStat
) > 1) then
815 g_TakeScreenShot('stats/' + StatFilename
);
816 StatShotDone
:= True;
820 procedure DrawSingleStat();
822 tm
, key_x
, val_x
, y
: Integer;
826 procedure player_stat(n
: Integer);
832 s1
:= Format(' %d ', [SingleStat
.PlayerStat
[n
].Kills
]);
833 s2
:= Format(' %d', [gTotalMonsters
]);
835 e_CharFont_Print(gMenuFont
, key_x
, y
, _lc
[I_MENU_INTER_KILLS
]);
836 e_CharFont_PrintEx(gMenuFont
, val_x
, y
, s1
, _RGB(255, 0, 0));
837 e_CharFont_GetSize(gMenuFont
, s1
, w1
, h
);
838 e_CharFont_Print(gMenuFont
, val_x
+w1
, y
, '/');
840 e_CharFont_GetSize(gMenuFont
, s1
, w1
, h
);
841 e_CharFont_PrintEx(gMenuFont
, val_x
+w1
, y
, s2
, _RGB(255, 0, 0));
843 // "Kills-per-minute: ##.#":
844 s1
:= _lc
[I_MENU_INTER_KPM
];
846 kpm
:= (SingleStat
.PlayerStat
[n
].Kills
/ tm
) * 60
848 kpm
:= SingleStat
.PlayerStat
[n
].Kills
;
849 s2
:= Format(' %.1f', [kpm
]);
851 e_CharFont_Print(gMenuFont
, key_x
, y
+32, s1
);
852 e_CharFont_PrintEx(gMenuFont
, val_x
, y
+32, s2
, _RGB(255, 0, 0));
854 // "Secrets found: # / #":
855 s1
:= Format(' %d ', [SingleStat
.PlayerStat
[n
].Secrets
]);
856 s2
:= Format(' %d', [SingleStat
.TotalSecrets
]);
858 e_CharFont_Print(gMenuFont
, key_x
, y
+64, _lc
[I_MENU_INTER_SECRETS
]);
859 e_CharFont_PrintEx(gMenuFont
, val_x
, y
+64, s1
, _RGB(255, 0, 0));
860 e_CharFont_GetSize(gMenuFont
, s1
, w1
, h
);
861 e_CharFont_Print(gMenuFont
, val_x
+w1
, y
+64, '/');
863 e_CharFont_GetSize(gMenuFont
, s1
, w1
, h
);
864 e_CharFont_PrintEx(gMenuFont
, val_x
+w1
, y
+64, s2
, _RGB(255, 0, 0));
869 e_CharFont_GetSize(gMenuFont
, _lc
[I_MENU_INTER_LEVEL_COMPLETE
], w1
, h
);
870 e_CharFont_Print(gMenuFont
, (gScreenWidth
-w1
) div 2, 32, _lc
[I_MENU_INTER_LEVEL_COMPLETE
]);
872 // Определяем координаты выравнивания по самой длинной строке:
873 s1
:= _lc
[I_MENU_INTER_KPM
];
874 e_CharFont_GetSize(gMenuFont
, s1
, w1
, h
);
877 e_CharFont_GetSize(gMenuFont
, s1
, w2
, h
);
879 key_x
:= (gScreenWidth
-w1
-w2
) div 2;
883 tm
:= SingleStat
.GameTime
div 1000;
884 s1
:= _lc
[I_MENU_INTER_TIME
];
885 s2
:= Format(' %d:%.2d:%.2d', [tm
div (60*60), (tm
mod (60*60)) div 60, tm
mod 60]);
887 e_CharFont_Print(gMenuFont
, key_x
, 80, s1
);
888 e_CharFont_PrintEx(gMenuFont
, val_x
, 80, s2
, _RGB(255, 0, 0));
890 if SingleStat
.TwoPlayers
then
893 s1
:= _lc
[I_MENU_PLAYER_1
];
894 e_CharFont_GetSize(gMenuFont
, s1
, w1
, h
);
895 e_CharFont_Print(gMenuFont
, (gScreenWidth
-w1
) div 2, 128, s1
);
897 // Статистика первого игрока:
902 s1
:= _lc
[I_MENU_PLAYER_2
];
903 e_CharFont_GetSize(gMenuFont
, s1
, w1
, h
);
904 e_CharFont_Print(gMenuFont
, (gScreenWidth
-w1
) div 2, 288, s1
);
906 // Статистика второго игрока:
912 // Статистика первого игрока:
918 procedure r_Game_DrawLoadingStat
;
919 procedure drawRect (x
, y
, w
, h
: Integer);
921 if (w
< 1) or (h
< 1) then exit
;
923 glVertex2f(x
+0.375, y
+0.375);
924 glVertex2f(x
+w
+0.375, y
+0.375);
925 glVertex2f(x
+w
+0.375, y
+h
+0.375);
926 glVertex2f(x
+0.375, y
+h
+0.375);
930 function drawPBar (cur
, total
: Integer; washere
: Boolean): Boolean;
932 rectW
, rectH
: Integer;
939 idl
, idr
, idb
, idm
: LongWord;
943 if (total
< 1) then exit
;
944 if (cur
< 1) then exit
; // don't blink
945 if (not washere
) and (cur
>= total
) then exit
; // don't blink
946 //if (cur < 0) then cur := 0;
947 //if (cur > total) then cur := total;
952 g_Texture_Get('UI_GFX_PBAR_LEFT', idl
);
953 g_Texture_GetSize('UI_GFX_PBAR_LEFT', wl
, hl
);
954 g_Texture_Get('UI_GFX_PBAR_RIGHT', idr
);
955 g_Texture_GetSize('UI_GFX_PBAR_RIGHT', wr
, hr
);
956 g_Texture_Get('UI_GFX_PBAR_MIDDLE', idb
);
957 g_Texture_GetSize('UI_GFX_PBAR_MIDDLE', wb
, hb
);
958 g_Texture_Get('UI_GFX_PBAR_MARKER', idm
);
959 g_Texture_GetSize('UI_GFX_PBAR_MARKER', wm
, hm
);
961 //rectW := gScreenWidth-360;
962 rectW
:= trunc(624.0*gScreenWidth
/1024.0);
965 x0
:= (gScreenWidth
-rectW
) div 2;
966 y0
:= gScreenHeight
-rectH
-64;
967 if (y0
< 2) then y0
:= 2;
969 glEnable(GL_SCISSOR_TEST
);
972 glScissor(x0
, gScreenHeight
-y0
-rectH
, rectW
, rectH
);
973 e_DrawSize(idl
, x0
, y0
, 0, true, false, wl
, hl
);
974 e_DrawSize(idr
, x0
+rectW
-wr
, y0
, 0, true, false, wr
, hr
);
977 glScissor(x0
+wl
, gScreenHeight
-y0
-rectH
, rectW
-wl
-wr
, rectH
);
979 while (f
< x0
+rectW
) do
981 e_DrawSize(idb
, f
, y0
, 0, true, false, wb
, hb
);
986 wdt
:= (rectW
-wl
-wr
)*cur
div total
;
987 if (wdt
> rectW
-wl
-wr
) then wdt
:= rectW
-wr
-wr
;
990 my
:= y0
; // don't be so smart, ketmar: +(rectH-wm) div 2;
991 glScissor(x0
+wl
, gScreenHeight
-my
-rectH
, wdt
, hm
);
995 e_DrawSize(idm
, f
, y0
, 0, true, false, wm
, hm
);
1001 glScissor(0, 0, gScreenWidth
, gScreenHeight
);
1005 rectW
:= gScreenWidth
-64;
1008 x0
:= (gScreenWidth
-rectW
) div 2;
1009 y0
:= gScreenHeight
-rectH
-64;
1010 if (y0
< 2) then y0
:= 2;
1012 glDisable(GL_BLEND
);
1013 glDisable(GL_TEXTURE_2D
);
1015 //glClearColor(0, 0, 0, 0);
1016 //glClear(GL_COLOR_BUFFER_BIT);
1018 glColor4ub(127, 127, 127, 255);
1019 drawRect(x0
-2, y0
-2, rectW
+4, rectH
+4);
1021 glColor4ub(0, 0, 0, 255);
1022 drawRect(x0
-1, y0
-1, rectW
+2, rectH
+2);
1024 glColor4ub(127, 127, 127, 255);
1025 wdt
:= rectW
*cur
div total
;
1026 if (wdt
> rectW
) then wdt
:= rectW
;
1027 drawRect(x0
, y0
, wdt
, rectH
);
1036 if (Length(LoadingStat
.Msgs
) = 0) then exit
;
1038 e_CharFont_GetSize(gMenuFont
, _lc
[I_MENU_LOADING
], ww
, hh
);
1039 yy
:= (gScreenHeight
div 3);
1040 e_CharFont_Print(gMenuFont
, (gScreenWidth
div 2)-(ww
div 2), yy
-2*hh
, _lc
[I_MENU_LOADING
]);
1041 xx
:= (gScreenWidth
div 3);
1045 for i
:= 0 to NextMsg
-1 do
1047 if (i
= (NextMsg
-1)) and (MaxValue
> 0) then
1048 s
:= Format('%s: %d/%d', [Msgs
[i
], CurValue
, MaxValue
])
1052 e_CharFont_PrintEx(gMenuSmallFont
, xx
, yy
, s
, _RGB(255, 0, 0));
1053 yy
:= yy
+ LOADING_INTERLINE
;
1054 PBarWasHere
:= drawPBar(CurValue
, MaxValue
, PBarWasHere
);
1059 procedure r_Game_DrawMenuBackground (tex
: AnsiString);
1065 if g_Texture_Get(tex
, ID
) then
1067 e_Clear(GL_COLOR_BUFFER_BIT
, 0, 0, 0);
1068 e_GetTextureSize(ID
, @w
, @h
);
1070 w
:= round(w
* 1.333 * (gScreenHeight
/ h
))
1072 w
:= trunc(w
* (gScreenHeight
/ h
));
1073 e_DrawSize(ID
, (gScreenWidth
- w
) div 2, 0, 0, False, False, w
, gScreenHeight
);
1075 else e_Clear(GL_COLOR_BUFFER_BIT
, 0, 0, 0);
1078 procedure DrawMinimap(p
: TPlayer
; RenderRect
: TRect
);
1080 a
, aX
, aY
, aX2
, aY2
, Scale
, ScaleSz
: Integer;
1082 function monDraw (mon
: TMonster
): Boolean;
1084 result
:= false; // don't stop
1089 // Левый верхний угол
1090 aX
:= Obj
.X
div ScaleSz
+ 1;
1091 aY
:= Obj
.Y
div ScaleSz
+ 1;
1093 aX2
:= max(Obj
.Rect
.Width
div ScaleSz
, 1);
1094 aY2
:= max(Obj
.Rect
.Height
div ScaleSz
, 1);
1095 // Правый нижний угол
1096 aX2
:= aX
+ aX2
- 1;
1097 aY2
:= aY
+ aY2
- 1;
1098 e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 255, 255, 0, 0);
1104 if (gMapInfo
.Width
> RenderRect
.Right
- RenderRect
.Left
) or
1105 (gMapInfo
.Height
> RenderRect
.Bottom
- RenderRect
.Top
) then
1108 // Сколько пикселов карты в 1 пикселе мини-карты:
1109 ScaleSz
:= 16 div Scale
;
1110 // Размеры мини-карты:
1111 aX
:= max(gMapInfo
.Width
div ScaleSz
, 1);
1112 aY
:= max(gMapInfo
.Height
div ScaleSz
, 1);
1114 e_DrawFillQuad(0, 0, aX
-1, aY
-1, 0, 0, 0, 0);
1116 if gWalls
<> nil then
1119 for a
:= 0 to High(gWalls
) do
1121 if PanelType
<> 0 then
1123 // Левый верхний угол:
1124 aX
:= X
div ScaleSz
;
1125 aY
:= Y
div ScaleSz
;
1127 aX2
:= max(Width
div ScaleSz
, 1);
1128 aY2
:= max(Height
div ScaleSz
, 1);
1129 // Правый нижний угол:
1130 aX2
:= aX
+ aX2
- 1;
1131 aY2
:= aY
+ aY2
- 1;
1134 PANEL_WALL
: e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 208, 208, 208, 0);
1135 PANEL_OPENDOOR
, PANEL_CLOSEDOOR
:
1136 if Enabled
then e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 160, 160, 160, 0);
1140 if gSteps
<> nil then
1143 for a
:= 0 to High(gSteps
) do
1145 if PanelType
<> 0 then
1147 // Левый верхний угол:
1148 aX
:= X
div ScaleSz
;
1149 aY
:= Y
div ScaleSz
;
1151 aX2
:= max(Width
div ScaleSz
, 1);
1152 aY2
:= max(Height
div ScaleSz
, 1);
1153 // Правый нижний угол:
1154 aX2
:= aX
+ aX2
- 1;
1155 aY2
:= aY
+ aY2
- 1;
1157 e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 128, 128, 128, 0);
1160 if gLifts
<> nil then
1163 for a
:= 0 to High(gLifts
) do
1165 if PanelType
<> 0 then
1167 // Левый верхний угол:
1168 aX
:= X
div ScaleSz
;
1169 aY
:= Y
div ScaleSz
;
1171 aX2
:= max(Width
div ScaleSz
, 1);
1172 aY2
:= max(Height
div ScaleSz
, 1);
1173 // Правый нижний угол:
1174 aX2
:= aX
+ aX2
- 1;
1175 aY2
:= aY
+ aY2
- 1;
1178 LIFTTYPE_UP
: e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 116, 72, 36, 0);
1179 LIFTTYPE_DOWN
: e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 116, 124, 96, 0);
1180 LIFTTYPE_LEFT
: e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 200, 80, 4, 0);
1181 LIFTTYPE_RIGHT
: e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 252, 140, 56, 0);
1185 if gWater
<> nil then
1188 for a
:= 0 to High(gWater
) do
1190 if PanelType
<> 0 then
1192 // Левый верхний угол:
1193 aX
:= X
div ScaleSz
;
1194 aY
:= Y
div ScaleSz
;
1196 aX2
:= max(Width
div ScaleSz
, 1);
1197 aY2
:= max(Height
div ScaleSz
, 1);
1198 // Правый нижний угол:
1199 aX2
:= aX
+ aX2
- 1;
1200 aY2
:= aY
+ aY2
- 1;
1202 e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 0, 0, 192, 0);
1205 if gAcid1
<> nil then
1207 // Рисуем кислоту 1:
1208 for a
:= 0 to High(gAcid1
) do
1210 if PanelType
<> 0 then
1212 // Левый верхний угол:
1213 aX
:= X
div ScaleSz
;
1214 aY
:= Y
div ScaleSz
;
1216 aX2
:= max(Width
div ScaleSz
, 1);
1217 aY2
:= max(Height
div ScaleSz
, 1);
1218 // Правый нижний угол:
1219 aX2
:= aX
+ aX2
- 1;
1220 aY2
:= aY
+ aY2
- 1;
1222 e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 0, 176, 0, 0);
1225 if gAcid2
<> nil then
1227 // Рисуем кислоту 2:
1228 for a
:= 0 to High(gAcid2
) do
1230 if PanelType
<> 0 then
1232 // Левый верхний угол:
1233 aX
:= X
div ScaleSz
;
1234 aY
:= Y
div ScaleSz
;
1236 aX2
:= max(Width
div ScaleSz
, 1);
1237 aY2
:= max(Height
div ScaleSz
, 1);
1238 // Правый нижний угол:
1239 aX2
:= aX
+ aX2
- 1;
1240 aY2
:= aY
+ aY2
- 1;
1242 e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 176, 0, 0, 0);
1245 if gPlayers
<> nil then
1248 for a
:= 0 to High(gPlayers
) do
1249 if gPlayers
[a
] <> nil then with gPlayers
[a
] do
1251 // Левый верхний угол:
1252 aX
:= Obj
.X
div ScaleSz
+ 1;
1253 aY
:= Obj
.Y
div ScaleSz
+ 1;
1255 aX2
:= max(Obj
.Rect
.Width
div ScaleSz
, 1);
1256 aY2
:= max(Obj
.Rect
.Height
div ScaleSz
, 1);
1257 // Правый нижний угол:
1258 aX2
:= aX
+ aX2
- 1;
1259 aY2
:= aY
+ aY2
- 1;
1261 if gPlayers
[a
] = p
then
1262 e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 0, 255, 0, 0)
1265 TEAM_RED
: e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 255, 0, 0, 0);
1266 TEAM_BLUE
: e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 0, 0, 255, 0);
1267 else e_DrawFillQuad(aX
, aY
, aX2
, aY2
, 255, 128, 0, 0);
1272 g_Mons_ForEach(monDraw
);
1277 procedure renderAmbientQuad (hasAmbient
: Boolean; constref ambColor
: TDFColor
);
1279 if not hasAmbient
then exit
;
1280 e_AmbientQuad(sX
, sY
, sWidth
, sHeight
, ambColor
.r
, ambColor
.g
, ambColor
.b
, ambColor
.a
);
1283 // ////////////////////////////////////////////////////////////////////////// //
1287 function g_Texture_Light (): Integer;
1289 Radius
: Integer = 128;
1297 GetMem(tex
, (Radius
*2)*(Radius
*2)*4);
1299 for y
:= 0 to Radius
*2-1 do
1301 for x
:= 0 to Radius
*2-1 do
1303 dist
:= 1.0-sqrt((x
-Radius
)*(x
-Radius
)+(y
-Radius
)*(y
-Radius
))/Radius
;
1306 tpp
^ := 0; Inc(tpp
);
1307 tpp
^ := 0; Inc(tpp
);
1308 tpp
^ := 0; Inc(tpp
);
1309 tpp
^ := 0; Inc(tpp
);
1313 //tc.setPixel(x, y, Color(cast(int)(dist*255), cast(int)(dist*255), cast(int)(dist*255)));
1314 if (dist
> 0.5) then dist
:= 0.5;
1315 a
:= round(dist
*255);
1316 if (a
< 0) then a
:= 0 else if (a
> 255) then a
:= 255;
1317 tpp
^ := 255; Inc(tpp
);
1318 tpp
^ := 255; Inc(tpp
);
1319 tpp
^ := 255; Inc(tpp
);
1320 tpp
^ := Byte(a
); Inc(tpp
);
1325 glGenTextures(1, @ltexid
);
1326 //if (tid == 0) assert(0, "VGL: can't create screen texture");
1328 glBindTexture(GL_TEXTURE_2D
, ltexid
);
1329 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
1330 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
1331 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
1332 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
1334 //GLfloat[4] bclr = 0.0;
1335 //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr);
1337 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, Radius
*2, Radius
*2, 0, GL_RGBA
{gltt}, GL_UNSIGNED_BYTE
, tex
);
1343 // setup sX, sY, sWidth, sHeight, and transformation matrix before calling this!
1344 //FIXME: broken for splitscreen mode
1345 procedure renderDynLightsInternal ();
1347 //hasAmbient: Boolean;
1348 //ambColor: TDFColor;
1350 lx
, ly
, lrad
: Integer;
1351 scxywh
: array[0..3] of GLint
;
1354 if e_NoGraphics
then exit
;
1356 //TODO: lights should be in separate grid, i think
1357 // but on the other side: grid may be slower for dynlights, as their lifetime is short
1358 if (not gwin_k8_enable_light_experiments
) or (not gwin_has_stencil
) or (g_dynLightCount
< 1) then exit
;
1361 //ambColor := gCurrentMap['light_ambient'].rgba;
1362 //hasAmbient := (not ambColor.isOpaque) or (not ambColor.isBlack);
1364 { // this will multiply incoming color to alpha from framebuffer
1366 glBlendFunc(GL_DST_ALPHA, GL_ONE);
1370 * light rendering: (INVALID!)
1371 * glStencilFunc(GL_EQUAL, 0, $ff);
1373 * glClear(GL_STENCIL_BUFFER_BIT);
1374 * glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
1375 * draw shadow volume into stencil buffer
1376 * glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // modify color buffer
1377 * glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // don't modify stencil buffer
1379 * draw color-less quad with light alpha (WARNING! don't touch color!)
1380 * glEnable(GL_BLEND);
1381 * glBlendFunc(GL_DST_ALPHA, GL_ONE);
1382 * draw all geometry up to and including walls (with alpha-testing, probably) -- this does lighting
1384 wassc
:= (glIsEnabled(GL_SCISSOR_TEST
) <> 0);
1385 if wassc
then glGetIntegerv(GL_SCISSOR_BOX
, @scxywh
[0]) else glGetIntegerv(GL_VIEWPORT
, @scxywh
[0]);
1387 // setup OpenGL parameters
1388 glStencilMask($FFFFFFFF);
1389 glStencilFunc(GL_ALWAYS
, 0, $FFFFFFFF);
1390 glEnable(GL_STENCIL_TEST
);
1391 glEnable(GL_SCISSOR_TEST
);
1392 glClear(GL_STENCIL_BUFFER_BIT
);
1393 glStencilFunc(GL_EQUAL
, 0, $ff);
1395 for lln
:= 0 to g_dynLightCount
-1 do
1397 lx
:= g_dynLights
[lln
].x
;
1398 ly
:= g_dynLights
[lln
].y
;
1399 lrad
:= g_dynLights
[lln
].radius
;
1400 if (lrad
< 3) then continue
;
1402 if (lx
-sX
+lrad
< 0) then continue
;
1403 if (ly
-sY
+lrad
< 0) then continue
;
1404 if (lx
-sX
-lrad
>= gPlayerScreenSize
.X
) then continue
;
1405 if (ly
-sY
-lrad
>= gPlayerScreenSize
.Y
) then continue
;
1407 // set scissor to optimize drawing
1408 if (g_dbg_scale
= 1.0) then
1410 glScissor((lx
-sX
)-lrad
+2, gPlayerScreenSize
.Y
-(ly
-sY
)-lrad
-1+2, lrad
*2-4, lrad
*2-4);
1414 glScissor(0, 0, gScreenWidth
, gScreenHeight
);
1416 // no need to clear stencil buffer, light blitting will do it for us... but only for normal scale
1417 if (g_dbg_scale
<> 1.0) then glClear(GL_STENCIL_BUFFER_BIT
);
1418 glStencilOp(GL_KEEP
, GL_KEEP
, GL_INCR
);
1419 // draw extruded panels
1420 glDisable(GL_TEXTURE_2D
);
1421 glDisable(GL_BLEND
);
1422 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
); // no need to modify color buffer
1423 if (lrad
> 4) then r_Map_DrawPanelShadowVolumes(lx
, ly
, lrad
);
1424 // render light texture
1425 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
); // modify color buffer
1426 glStencilOp(GL_ZERO
, GL_ZERO
, GL_ZERO
); // draw light, and clear stencil buffer
1429 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1430 glEnable(GL_TEXTURE_2D
);
1431 // color and opacity
1432 glColor4f(g_dynLights
[lln
].r
, g_dynLights
[lln
].g
, g_dynLights
[lln
].b
, g_dynLights
[lln
].a
);
1433 glBindTexture(GL_TEXTURE_2D
, g_Texture_Light());
1435 glTexCoord2f(0.0, 0.0); glVertex2i(lx
-lrad
, ly
-lrad
); // top-left
1436 glTexCoord2f(1.0, 0.0); glVertex2i(lx
+lrad
, ly
-lrad
); // top-right
1437 glTexCoord2f(1.0, 1.0); glVertex2i(lx
+lrad
, ly
+lrad
); // bottom-right
1438 glTexCoord2f(0.0, 1.0); glVertex2i(lx
-lrad
, ly
+lrad
); // bottom-left
1443 glDisable(GL_STENCIL_TEST
);
1444 glDisable(GL_BLEND
);
1445 glDisable(GL_SCISSOR_TEST
);
1446 //glScissor(0, 0, sWidth, sHeight);
1448 glScissor(scxywh
[0], scxywh
[1], scxywh
[2], scxywh
[3]);
1449 if wassc
then glEnable(GL_SCISSOR_TEST
) else glDisable(GL_SCISSOR_TEST
);
1453 function fixViewportForScale (): Boolean;
1455 nx0
, ny0
, nw
, nh
: Integer;
1458 if (g_dbg_scale
<> 1.0) then
1461 nx0
:= round(sX
-(gPlayerScreenSize
.X
-(sWidth
*g_dbg_scale
))/2/g_dbg_scale
);
1462 ny0
:= round(sY
-(gPlayerScreenSize
.Y
-(sHeight
*g_dbg_scale
))/2/g_dbg_scale
);
1463 nw
:= round(sWidth
/g_dbg_scale
);
1464 nh
:= round(sHeight
/g_dbg_scale
);
1473 // setup sX, sY, sWidth, sHeight, and transformation matrix before calling this!
1474 // WARNING! this WILL CALL `glTranslatef()`, but won't restore matrices!
1475 procedure renderMapInternal (backXOfs
, backYOfs
: Integer; setTransMatrix
: Boolean);
1477 TDrawCB
= procedure ();
1480 hasAmbient
: Boolean;
1482 doAmbient
: Boolean = false;
1484 procedure drawPanelType (profname
: AnsiString; panType
: DWord
; doDraw
: Boolean);
1489 if (profileFrameDraw
<> nil) then profileFrameDraw
.sectionBegin(profname
);
1490 if gdbg_map_use_accel_render
then
1492 tagmask
:= panelTypeToTag(panType
);
1493 while (gDrawPanelList
.count
> 0) do
1495 pan
:= TPanel(gDrawPanelList
.front());
1496 if ((pan
.tag
and tagmask
) = 0) then break
;
1497 if doDraw
then r_Panel_Draw(pan
, doAmbient
, ambColor
);
1498 gDrawPanelList
.popFront();
1503 if doDraw
then r_Map_DrawPanels(panType
, hasAmbient
, ambColor
);
1505 if (profileFrameDraw
<> nil) then profileFrameDraw
.sectionEnd();
1508 procedure drawOther (profname
: AnsiString; cb
: TDrawCB
);
1510 if (profileFrameDraw
<> nil) then profileFrameDraw
.sectionBegin(profname
);
1511 if assigned(cb
) then cb();
1512 if (profileFrameDraw
<> nil) then profileFrameDraw
.sectionEnd();
1516 if (profileFrameDraw
<> nil) then profileFrameDraw
.sectionBegin('total');
1518 // our accelerated renderer will collect all panels to gDrawPanelList
1519 // we can use panel tag to render level parts (see GridTagXXX in g_map.pas)
1520 if (profileFrameDraw
<> nil) then profileFrameDraw
.sectionBegin('collect');
1521 if gdbg_map_use_accel_render
then
1523 r_Map_CollectDrawPanels(sX
, sY
, sWidth
, sHeight
);
1525 if (profileFrameDraw
<> nil) then profileFrameDraw
.sectionEnd();
1527 if (profileFrameDraw
<> nil) then profileFrameDraw
.sectionBegin('skyback');
1528 r_Map_DrawBack(backXOfs
, backYOfs
);
1529 if (profileFrameDraw
<> nil) then profileFrameDraw
.sectionEnd();
1531 if setTransMatrix
then
1533 //if (g_dbg_scale <> 1.0) then glTranslatef(0.0, -0.375/2, 0);
1534 glScalef(g_dbg_scale
, g_dbg_scale
, 1.0);
1535 glTranslatef(-sX
, -sY
, 0);
1539 ambColor
:= gCurrentMap
['light_ambient'].rgba
;
1540 hasAmbient
:= (not ambColor
.isOpaque
) or (not ambColor
.isBlack
);
1545 //writeln('color: (', ambColor.r, ',', ambColor.g, ',', ambColor.b, ',', ambColor.a, ')');
1546 glColor4ub(ambColor.r, ambColor.g, ambColor.b, ambColor.a);
1547 glClear(GL_COLOR_BUFFER_BIT);
1550 //writeln('color: (', ambColor.r, ',', ambColor.g, ',', ambColor.b, ',', ambColor.a, ')');
1553 drawPanelType('*back', PANEL_BACK
, g_rlayer_back
);
1554 drawPanelType('*step', PANEL_STEP
, g_rlayer_step
);
1555 drawOther('items', @r_Items_Draw
);
1556 drawOther('weapons', @r_Weapon_Draw
);
1557 {$IFDEF ENABLE_SHELLS}
1558 drawOther('shells', @r_Player_DrawShells
);
1560 drawOther('drawall', @r_Player_DrawAll
);
1561 {$IFDEF ENABLE_GIBS}
1562 drawOther('gibs', @r_PlayerModel_DrawGibs
);
1564 {$IFDEF ENABLE_CORPSES}
1565 drawOther('corpses', @r_Player_DrawCorpses
);
1567 drawPanelType('*wall', PANEL_WALL
, g_rlayer_wall
);
1568 drawOther('monsters', @r_Monsters_Draw
);
1569 drawOther('itemdrop', @r_Items_DrawDrop
);
1570 drawPanelType('*door', PANEL_CLOSEDOOR
, g_rlayer_door
);
1572 drawOther('gfx', @r_GFX_Draw
);
1574 drawOther('flags', @r_Map_DrawFlags
);
1575 drawPanelType('*acid1', PANEL_ACID1
, g_rlayer_acid1
);
1576 drawPanelType('*acid2', PANEL_ACID2
, g_rlayer_acid2
);
1577 drawPanelType('*water', PANEL_WATER
, g_rlayer_water
);
1578 drawOther('dynlights', @renderDynLightsInternal
);
1580 if hasAmbient
{and ((not g_playerLight) or (not gwin_has_stencil) or (g_dynLightCount < 1))} then
1582 renderAmbientQuad(hasAmbient
, ambColor
);
1586 drawPanelType('*fore', PANEL_FORE
, g_rlayer_fore
);
1589 if g_debug_HealthBar
then
1591 r_Monsters_DrawHealth();
1592 r_Player_DrawHealth();
1595 if (profileFrameDraw
<> nil) then profileFrameDraw
.mainEnd(); // map rendering
1599 procedure DrawMapView(x
, y
, w
, h
: Integer);
1606 bx
:= Round(x
/(gMapInfo
.Width
- w
)*(gBackSize
.X
- w
));
1607 by
:= Round(y
/(gMapInfo
.Height
- h
)*(gBackSize
.Y
- h
));
1614 fixViewportForScale();
1615 renderMapInternal(-bx
, -by
, true);
1621 procedure DrawPlayer(p
: TPlayer
);
1623 px
, py
, a
, b
, c
, d
, i
, fX
, fY
: Integer;
1627 if (p
= nil) or (p
.FDummy
) then
1630 r_Map_DrawBack(0, 0);
1635 if (profileFrameDraw
= nil) then profileFrameDraw
:= TProfiler
.Create('RENDER', g_profile_history_size
);
1636 if (profileFrameDraw
<> nil) then profileFrameDraw
.mainBegin(g_profile_frame_draw
);
1642 {$IFDEF ENABLE_CORPSES}
1643 camObj
:= g_Corpses_GetCameraObj(p
);
1648 camObj
.lerp(gLerpFactor
, fX
, fY
);
1649 px
:= fX
+ PLAYER_RECT_CX
;
1650 py
:= fY
+ PLAYER_RECT_CY
+nlerp(p
.SlopeOld
, camObj
.slopeUpLeft
, gLerpFactor
);
1652 if (g_dbg_scale
= 1.0) and (not g_dbg_ignore_bounds
) then
1654 if (px
> (gPlayerScreenSize
.X
div 2)) then a
:= -px
+(gPlayerScreenSize
.X
div 2) else a
:= 0;
1655 if (py
> (gPlayerScreenSize
.Y
div 2)) then b
:= -py
+(gPlayerScreenSize
.Y
div 2) else b
:= 0;
1657 if (px
> gMapInfo
.Width
-(gPlayerScreenSize
.X
div 2)) then a
:= -gMapInfo
.Width
+gPlayerScreenSize
.X
;
1658 if (py
> gMapInfo
.Height
-(gPlayerScreenSize
.Y
div 2)) then b
:= -gMapInfo
.Height
+gPlayerScreenSize
.Y
;
1660 if (gMapInfo
.Width
= gPlayerScreenSize
.X
) then a
:= 0
1661 else if (gMapInfo
.Width
< gPlayerScreenSize
.X
) then
1664 a
:= (gPlayerScreenSize
.X
-gMapInfo
.Width
) div 2;
1667 if (gMapInfo
.Height
= gPlayerScreenSize
.Y
) then b
:= 0
1668 else if (gMapInfo
.Height
< gPlayerScreenSize
.Y
) then
1671 b
:= (gPlayerScreenSize
.Y
-gMapInfo
.Height
) div 2;
1676 // scaled, ignore level bounds
1677 a
:= -px
+(gPlayerScreenSize
.X
div 2);
1678 b
:= -py
+(gPlayerScreenSize
.Y
div 2);
1683 sWidth
:= gPlayerScreenSize
.X
;
1684 sHeight
:= gPlayerScreenSize
.Y
;
1685 fixViewportForScale();
1687 i
:= py
- (sY
+ sHeight
div 2);
1688 if (p
.IncCam
> 0) then
1690 // clamp to level bounds
1691 if (sY
- p
.IncCam
< 0) then
1692 p
.IncCam
:= nclamp(sY
, 0, 120);
1693 // clamp around player position
1695 p
.IncCam
:= nclamp(p
.IncCam
, 0, max(0, 120 - i
));
1697 else if (p
.IncCam
< 0) then
1699 // clamp to level bounds
1700 if (sY
+ sHeight
- p
.IncCam
> gMapInfo
.Height
) then
1701 p
.IncCam
:= nclamp(sY
+ sHeight
- gMapInfo
.Height
, -120, 0);
1702 // clamp around player position
1704 p
.IncCam
:= nclamp(p
.IncCam
, min(0, -120 - i
), 0);
1707 sY
:= sY
- nlerp(p
.IncCamOld
, p
.IncCam
, gLerpFactor
);
1709 if (not g_dbg_ignore_bounds
) then
1711 if (sX
+sWidth
> gMapInfo
.Width
) then sX
:= gMapInfo
.Width
-sWidth
;
1712 if (sY
+sHeight
> gMapInfo
.Height
) then sY
:= gMapInfo
.Height
-sHeight
;
1713 if (sX
< 0) then sX
:= 0;
1714 if (sY
< 0) then sY
:= 0;
1717 if (gBackSize
.X
<= gPlayerScreenSize
.X
) or (gMapInfo
.Width
<= sWidth
) then c
:= 0 else c
:= trunc((gBackSize
.X
-gPlayerScreenSize
.X
)*sX
/(gMapInfo
.Width
-sWidth
));
1718 if (gBackSize
.Y
<= gPlayerScreenSize
.Y
) or (gMapInfo
.Height
<= sHeight
) then d
:= 0 else d
:= trunc((gBackSize
.Y
-gPlayerScreenSize
.Y
)*sY
/(gMapInfo
.Height
-sHeight
));
1720 //r_smallmap_h: 0: left; 1: center; 2: right
1721 //r_smallmap_v: 0: top; 1: center; 2: bottom
1723 if (gMapInfo
.Width
= sWidth
) then
1727 else if (gMapInfo
.Width
< sWidth
) then
1729 case r_smallmap_h
of
1730 1: sX
:= -((sWidth
-gMapInfo
.Width
) div 2); // center
1731 2: sX
:= -(sWidth
-gMapInfo
.Width
); // right
1732 else sX
:= 0; // left
1736 if (gMapInfo
.Height
= sHeight
) then
1740 else if (gMapInfo
.Height
< sHeight
) then
1742 case r_smallmap_v
of
1743 1: sY
:= -((sHeight
-gMapInfo
.Height
) div 2); // center
1744 2: sY
:= -(sHeight
-gMapInfo
.Height
); // bottom
1745 else sY
:= 0; // top
1751 p
.viewPortW
:= sWidth
;
1752 p
.viewPortH
:= sHeight
;
1754 {$IFDEF ENABLE_HOLMES}
1755 if (p
= gPlayer1
) then
1757 g_Holmes_plrViewPos(sX
, sY
);
1758 g_Holmes_plrViewSize(sWidth
, sHeight
);
1762 renderMapInternal(-c
, -d
, true);
1764 if (gGameSettings
.GameMode
<> GM_SINGLE
) and (gPlayerIndicator
> 0) then
1765 case gPlayerIndicator
of
1767 r_Player_DrawIndicator(p
, _RGB(255, 255, 255));
1770 for i
:= 0 to High(gPlayers
) do
1771 if gPlayers
[i
] <> nil then
1772 if gPlayers
[i
] = p
then
1773 r_Player_DrawIndicator(p
, _RGB(255, 255, 255))
1774 else if (gPlayers
[i
].Team
= p
.Team
) and (gPlayers
[i
].Team
<> TEAM_NONE
) then
1775 if gPlayerIndicatorStyle
= 1 then
1776 r_Player_DrawIndicator(gPlayers
[i
], _RGB(192, 192, 192))
1778 r_Player_DrawIndicator(gPlayers
[i
], gPlayers
[i
].GetColor
);
1782 for a := 0 to High(gCollideMap) do
1783 for b := 0 to High(gCollideMap[a]) do
1786 if ByteBool(gCollideMap[a, b] and MARK_WALL) then
1788 if ByteBool(gCollideMap[a, b] and MARK_DOOR) then
1792 1: e_DrawPoint(1, b, a, 200, 200, 200);
1793 2: e_DrawPoint(1, b, a, 64, 64, 255);
1794 3: e_DrawPoint(1, b, a, 255, 0, 255);
1801 r_Player_DrawPain(p
);
1802 r_Player_DrawPickup(p
);
1803 r_Player_DrawRulez(p
);
1804 if gShowMap
then DrawMinimap(p
, _TRect(0, 0, 128, 128));
1805 if g_Debug_Player
then
1806 r_Player_DrawDebug(p
);
1807 r_Player_DrawGUI(p
);
1810 procedure drawProfilers ();
1815 if g_profile_frame_draw
and (profileFrameDraw
<> nil) then px
:= px
-drawProfiles(px
, py
, profileFrameDraw
);
1816 if g_profile_collision
and (profMapCollision
<> nil) then begin px
:= px
-drawProfiles(px
, py
, profMapCollision
); py
-= calcProfilesHeight(profMonsLOS
); end;
1817 if g_profile_los
and (profMonsLOS
<> nil) then begin px
:= px
-drawProfiles(px
, py
, profMonsLOS
); py
-= calcProfilesHeight(profMonsLOS
); end;
1820 procedure r_Game_Draw();
1827 plView1
, plView2
: TPlayer
;
1829 MsgLineLength
: Integer;
1832 if gExit
= EXIT_QUIT
then Exit
;
1834 Time
:= GetTickCount64() {div 1000};
1835 FPSCounter
:= FPSCounter
+1;
1836 if Time
- FPSTime
>= 1000 then
1843 e_SetRendertarget(True);
1844 e_SetViewPort(0, 0, gScreenWidth
, gScreenHeight
);
1846 if gGameOn
or (gState
= STATE_FOLD
) then
1848 if (gPlayer1
<> nil) and (gPlayer2
<> nil) then
1850 gSpectMode
:= SPECT_NONE
;
1851 if not gRevertPlayers
then
1853 plView1
:= gPlayer1
;
1854 plView2
:= gPlayer2
;
1858 plView1
:= gPlayer2
;
1859 plView2
:= gPlayer1
;
1863 if (gPlayer1
<> nil) or (gPlayer2
<> nil) then
1865 gSpectMode
:= SPECT_NONE
;
1866 if gPlayer2
= nil then
1869 plView1
:= gPlayer2
;
1878 if (plView1
= nil) and (plView2
= nil) and (gSpectMode
= SPECT_NONE
) then
1879 gSpectMode
:= SPECT_STATS
;
1881 if gSpectMode
= SPECT_PLAYERS
then
1882 if gPlayers
<> nil then
1884 plView1
:= GetActivePlayer_ByID(gSpectPID1
);
1885 if plView1
= nil then
1887 gSpectPID1
:= GetActivePlayerID_Next();
1888 plView1
:= GetActivePlayer_ByID(gSpectPID1
);
1890 if gSpectViewTwo
then
1892 plView2
:= GetActivePlayer_ByID(gSpectPID2
);
1893 if plView2
= nil then
1895 gSpectPID2
:= GetActivePlayerID_Next();
1896 plView2
:= GetActivePlayer_ByID(gSpectPID2
);
1901 if gSpectMode
= SPECT_MAPVIEW
then
1903 // Режим просмотра карты
1905 e_SetViewPort(0, 0, gScreenWidth
, gScreenHeight
);
1906 DrawMapView(gSpectX
, gSpectY
, gScreenWidth
, gScreenHeight
);
1907 gHearPoint1
.Active
:= True;
1908 gHearPoint1
.Coords
.X
:= gScreenWidth
div 2 + gSpectX
;
1909 gHearPoint1
.Coords
.Y
:= gScreenHeight
div 2 + gSpectY
;
1910 gHearPoint2
.Active
:= False;
1914 Split
:= (plView1
<> nil) and (plView2
<> nil);
1916 // Точки слуха игроков
1917 if plView1
<> nil then
1919 gHearPoint1
.Active
:= True;
1920 gHearPoint1
.Coords
.X
:= plView1
.GameX
+ PLAYER_RECT
.Width
;
1921 gHearPoint1
.Coords
.Y
:= plView1
.GameY
+ PLAYER_RECT
.Height
DIV 2;
1923 gHearPoint1
.Active
:= False;
1924 if plView2
<> nil then
1926 gHearPoint2
.Active
:= True;
1927 gHearPoint2
.Coords
.X
:= plView2
.GameX
+ PLAYER_RECT
.Width
;
1928 gHearPoint2
.Coords
.Y
:= plView2
.GameY
+ PLAYER_RECT
.Height
DIV 2;
1930 gHearPoint2
.Active
:= False;
1932 // Размер экранов игроков:
1933 gPlayerScreenSize
.X
:= gScreenWidth
-196;
1936 gPlayerScreenSize
.Y
:= gScreenHeight
div 2;
1937 if gScreenHeight
mod 2 = 0 then
1938 Dec(gPlayerScreenSize
.Y
);
1941 gPlayerScreenSize
.Y
:= gScreenHeight
;
1944 if gScreenHeight
mod 2 = 0 then
1945 e_SetViewPort(0, gPlayerScreenSize
.Y
+2, gPlayerScreenSize
.X
+196, gPlayerScreenSize
.Y
)
1947 e_SetViewPort(0, gPlayerScreenSize
.Y
+1, gPlayerScreenSize
.X
+196, gPlayerScreenSize
.Y
);
1949 DrawPlayer(plView1
);
1950 gPlayer1ScreenCoord
.X
:= sX
;
1951 gPlayer1ScreenCoord
.Y
:= sY
;
1955 e_SetViewPort(0, 0, gPlayerScreenSize
.X
+196, gPlayerScreenSize
.Y
);
1957 DrawPlayer(plView2
);
1958 gPlayer2ScreenCoord
.X
:= sX
;
1959 gPlayer2ScreenCoord
.Y
:= sY
;
1962 e_SetViewPort(0, 0, gScreenWidth
, gScreenHeight
);
1965 e_DrawLine(2, 0, gScreenHeight
div 2, gScreenWidth
, gScreenHeight
div 2, 0, 0, 0);
1968 {$IFDEF ENABLE_HOLMES}
1970 if (g_holmes_enabled
) then g_Holmes_Draw();
1973 if MessageText
<> '' then
1977 e_CharFont_GetSizeFmt(gMenuFont
, MessageText
, w
, h
);
1978 MsgLineLength
:= (gScreenWidth
- 204) div e_CharFont_GetMaxWidth(gMenuFont
);
1979 MsgText
:= b_Text_Wrap(b_Text_Format(MessageText
), MsgLineLength
);
1981 e_CharFont_PrintFmt(gMenuFont
, (gScreenWidth
div 2)-(w
div 2),
1982 (gScreenHeight
div 2)-(h
div 2), MsgText
)
1984 e_CharFont_PrintFmt(gMenuFont
, (gScreenWidth
div 2)-(w
div 2),
1985 Round(gScreenHeight
/ 2.75)-(h
div 2), MsgText
);
1988 if IsDrawStat
or (gSpectMode
= SPECT_STATS
) then
1991 if gSpectHUD
and (not gChatShow
) and (gSpectMode
<> SPECT_NONE
) and (not gSpectAuto
) then
1993 // Draw spectator GUI
1996 e_TextureFontGetSize(gStdFont
, ww
, hh
);
1999 e_TextureFontPrintEx(0, gScreenHeight
- (hh
+2)*2, 'MODE: Stats', gStdFont
, 255, 255, 255, 1);
2001 e_TextureFontPrintEx(0, gScreenHeight
- (hh
+2)*2, 'MODE: Observe Map', gStdFont
, 255, 255, 255, 1);
2003 e_TextureFontPrintEx(0, gScreenHeight
- (hh
+2)*2, 'MODE: Watch Players', gStdFont
, 255, 255, 255, 1);
2005 e_TextureFontPrintEx(2*ww
, gScreenHeight
- (hh
+2), '< jump >', gStdFont
, 255, 255, 255, 1);
2006 if gSpectMode
= SPECT_STATS
then
2008 e_TextureFontPrintEx(16*ww
, gScreenHeight
- (hh
+2)*2, 'Autoview', gStdFont
, 255, 255, 255, 1);
2009 e_TextureFontPrintEx(16*ww
, gScreenHeight
- (hh
+2), '< fire >', gStdFont
, 255, 255, 255, 1);
2011 if gSpectMode
= SPECT_MAPVIEW
then
2013 e_TextureFontPrintEx(22*ww
, gScreenHeight
- (hh
+2)*2, '[-]', gStdFont
, 255, 255, 255, 1);
2014 e_TextureFontPrintEx(26*ww
, gScreenHeight
- (hh
+2)*2, 'Step ' + IntToStr(gSpectStep
), gStdFont
, 255, 255, 255, 1);
2015 e_TextureFontPrintEx(34*ww
, gScreenHeight
- (hh
+2)*2, '[+]', gStdFont
, 255, 255, 255, 1);
2016 e_TextureFontPrintEx(18*ww
, gScreenHeight
- (hh
+2), '<prev weap>', gStdFont
, 255, 255, 255, 1);
2017 e_TextureFontPrintEx(30*ww
, gScreenHeight
- (hh
+2), '<next weap>', gStdFont
, 255, 255, 255, 1);
2019 if gSpectMode
= SPECT_PLAYERS
then
2021 e_TextureFontPrintEx(22*ww
, gScreenHeight
- (hh
+2)*2, 'Player 1', gStdFont
, 255, 255, 255, 1);
2022 e_TextureFontPrintEx(20*ww
, gScreenHeight
- (hh
+2), '<left/right>', gStdFont
, 255, 255, 255, 1);
2023 if gSpectViewTwo
then
2025 e_TextureFontPrintEx(37*ww
, gScreenHeight
- (hh
+2)*2, 'Player 2', gStdFont
, 255, 255, 255, 1);
2026 e_TextureFontPrintEx(34*ww
, gScreenHeight
- (hh
+2), '<prev w/next w>', gStdFont
, 255, 255, 255, 1);
2027 e_TextureFontPrintEx(52*ww
, gScreenHeight
- (hh
+2)*2, '2x View', gStdFont
, 255, 255, 255, 1);
2028 e_TextureFontPrintEx(51*ww
, gScreenHeight
- (hh
+2), '<up/down>', gStdFont
, 255, 255, 255, 1);
2032 e_TextureFontPrintEx(35*ww
, gScreenHeight
- (hh
+2)*2, '2x View', gStdFont
, 255, 255, 255, 1);
2033 e_TextureFontPrintEx(34*ww
, gScreenHeight
- (hh
+2), '<up/down>', gStdFont
, 255, 255, 255, 1);
2039 {$IFDEF ENABLE_MENU}
2040 if gPauseMain
and gGameOn
and (g_ActiveWindow
= nil) then
2042 if gPauseMain
and gGameOn
then
2045 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2046 e_DarkenQuadWH(0, 0, gScreenWidth
, gScreenHeight
, 150);
2048 e_CharFont_GetSize(gMenuFont
, _lc
[I_MENU_PAUSE
], w
, h
);
2049 e_CharFont_Print(gMenuFont
, (gScreenWidth
div 2)-(w
div 2),
2050 (gScreenHeight
div 2)-(h
div 2), _lc
[I_MENU_PAUSE
]);
2055 {$IFDEF ENABLE_MENU}
2056 if (gState
= STATE_MENU
) then
2058 if (g_ActiveWindow
= nil) or (g_ActiveWindow
.BackTexture
= '') then r_Game_DrawMenuBackground('MENU_BACKGROUND');
2059 // F3 at menu will show game loading dialog
2060 if e_KeyPressed(IK_F3
) then g_Menu_Show_LoadMenu(true);
2061 if (g_ActiveWindow
<> nil) then
2063 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2064 e_DarkenQuadWH(0, 0, gScreenWidth
, gScreenHeight
, 150);
2068 // F3 at titlepic will show game loading dialog
2069 if e_KeyPressed(IK_F3
) then
2071 g_Menu_Show_LoadMenu(true);
2072 if (g_ActiveWindow
<> nil) then e_DarkenQuadWH(0, 0, gScreenWidth
, gScreenHeight
, 150);
2077 r_Game_DrawMenuBackground('MENU_BACKGROUND');
2080 if gState
= STATE_FOLD
then
2082 e_DrawFillQuad(0, 0, gScreenWidth
-1, gScreenHeight
-1, 0, 0, 0, EndingGameCounter
);
2085 if gState
= STATE_INTERCUSTOM
then
2087 if gLastMap
and (gGameSettings
.GameMode
= GM_COOP
) then
2089 back
:= 'TEXTURE_endpic';
2090 if not g_Texture_Get(back
, ID
) then
2091 back
:= _lc
[I_TEXTURE_ENDPIC
];
2096 r_Game_DrawMenuBackground(back
);
2100 {$IFDEF ENABLE_MENU}
2101 if g_ActiveWindow
<> nil then
2103 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2104 e_DarkenQuadWH(0, 0, gScreenWidth
, gScreenHeight
, 150);
2109 if gState
= STATE_INTERSINGLE
then
2111 if EndingGameCounter
> 0 then
2113 e_DrawFillQuad(0, 0, gScreenWidth
-1, gScreenHeight
-1, 0, 0, 0, EndingGameCounter
);
2119 r_Game_DrawMenuBackground(back
);
2123 {$IFDEF ENABLE_MENU}
2124 if g_ActiveWindow
<> nil then
2126 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2127 e_DarkenQuadWH(0, 0, gScreenWidth
, gScreenHeight
, 150);
2133 if gState
= STATE_ENDPIC
then
2136 if g_Texture_Get('TEXTURE_endpic', ID
) then r_Game_DrawMenuBackground('TEXTURE_endpic')
2137 else r_Game_DrawMenuBackground(_lc
[I_TEXTURE_ENDPIC
]);
2139 {$IFDEF ENABLE_MENU}
2140 if g_ActiveWindow
<> nil then
2142 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2143 e_DarkenQuadWH(0, 0, gScreenWidth
, gScreenHeight
, 150);
2148 if gState
= STATE_SLIST
then
2150 // if g_Texture_Get('MENU_BACKGROUND', ID) then
2152 // e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight);
2153 // //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2155 r_Game_DrawMenuBackground('MENU_BACKGROUND');
2156 e_DarkenQuadWH(0, 0, gScreenWidth
, gScreenHeight
, 150);
2157 r_Serverlist_Draw(slCurrent
, slTable
);
2161 {$IFDEF ENABLE_MENU}
2162 if g_ActiveWindow
<> nil then
2166 //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2167 e_DarkenQuadWH(0, 0, gScreenWidth
, gScreenHeight
, 150);
2169 r_GUI_Draw_Window(g_ActiveWindow
);
2175 if g_debug_Sounds
and gGameOn
then
2177 for w
:= 0 to High(e_SoundsArray
) do
2178 for h
:= 0 to e_SoundsArray
[w
].nRefs
do
2179 e_DrawPoint(1, w
+100, h
+100, 255, 0, 0);
2184 e_TextureFontPrint(0, 0, Format('FPS: %d', [FPS
]), gStdFont
);
2185 e_TextureFontPrint(0, 16, Format('UPS: %d', [UPS
]), gStdFont
);
2188 if gGameOn
and gShowTime
then
2189 drawTime(gScreenWidth
-72, gScreenHeight
-16);
2191 if gGameOn
then drawProfilers();
2193 // TODO: draw this after the FBO and remap mouse click coordinates
2195 {$IFDEF ENABLE_HOLMES}
2199 // blit framebuffer to screen
2201 e_SetRendertarget(False);
2202 e_SetViewPort(0, 0, gWinSizeX
, gWinSizeY
);
2203 e_BlitFramebuffer(gWinSizeX
, gWinSizeY
);