DEADSOFTWARE

render: separate player logic and drawing
[d2df-sdl.git] / src / game / opengl / r_player.pas
1 (* Copyright (C) Doom 2D: Forever Developers
2 *
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.
6 *
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.
11 *
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/>.
14 *)
15 {$INCLUDE ../../shared/a_modes.inc}
16 unit r_player;
18 interface
20 uses g_player, e_graphics; // TPlayer, TRGB
22 procedure r_Player_DrawAll;
23 procedure r_Player_DrawDebug (p: TPlayer);
24 procedure r_Player_DrawHealth;
26 procedure r_Player_DrawCorpses;
27 procedure r_Player_DrawShells;
29 procedure r_Player_Draw (p: TPlayer);
30 procedure r_Player_DrawIndicator (p: TPlayer; Color: TRGB);
31 procedure r_Player_DrawBubble (p: TPlayer);
32 procedure r_Player_DrawAim (p: TPlayer);
33 procedure r_Player_DrawGUI (pl: TPlayer);
34 procedure r_Player_DrawRulez (p: TPlayer);
35 procedure r_Player_DrawPain (p: TPlayer);
36 procedure r_Player_DrawPickup (p: TPlayer);
38 procedure r_Player_DrawCorpse (p: TCorpse);
40 implementation
42 uses
43 SysUtils, Classes, Math,
44 MAPDEF, utils,
45 g_basic, g_game, g_phys, g_map, g_textures, g_menu, g_language, g_weapons, g_items, g_net, g_options
46 ;
48 procedure r_Player_DrawAll;
49 var i: Integer;
50 begin
51 if gPlayers <> nil then
52 for i := 0 to High(gPlayers) do
53 if gPlayers[i] <> nil then
54 r_Player_Draw(gPlayers[i])
55 end;
57 procedure r_Player_DrawDebug (p: TPlayer);
58 var
59 fW, fH: Byte;
60 begin
61 if p = nil then Exit;
62 if (@p.Obj) = nil then Exit;
64 e_TextureFontGetSize(gStdFont, fW, fH);
66 e_TextureFontPrint(0, 0 , 'Pos X: ' + IntToStr(p.Obj.X), gStdFont);
67 e_TextureFontPrint(0, fH , 'Pos Y: ' + IntToStr(p.Obj.Y), gStdFont);
68 e_TextureFontPrint(0, fH * 2, 'Vel X: ' + IntToStr(p.Obj.Vel.X), gStdFont);
69 e_TextureFontPrint(0, fH * 3, 'Vel Y: ' + IntToStr(p.Obj.Vel.Y), gStdFont);
70 e_TextureFontPrint(0, fH * 4, 'Acc X: ' + IntToStr(p.Obj.Accel.X), gStdFont);
71 e_TextureFontPrint(0, fH * 5, 'Acc Y: ' + IntToStr(p.Obj.Accel.Y), gStdFont);
72 e_TextureFontPrint(0, fH * 6, 'Old X: ' + IntToStr(p.Obj.oldX), gStdFont);
73 e_TextureFontPrint(0, fH * 7, 'Old Y: ' + IntToStr(p.Obj.oldY), gStdFont);
74 end;
76 procedure r_Player_DrawHealth;
77 var
78 i: Integer;
79 fW, fH: Byte;
80 begin
81 if gPlayers = nil then Exit;
82 e_TextureFontGetSize(gStdFont, fW, fH);
84 for i := 0 to High(gPlayers) do
85 if gPlayers[i] <> nil then
86 begin
87 e_TextureFontPrint(gPlayers[i].Obj.X + gPlayers[i].Obj.Rect.X,
88 gPlayers[i].Obj.Y + gPlayers[i].Obj.Rect.Y + gPlayers[i].Obj.Rect.Height - fH * 2,
89 IntToStr(gPlayers[i].Health), gStdFont);
90 e_TextureFontPrint(gPlayers[i].Obj.X + gPlayers[i].Obj.Rect.X,
91 gPlayers[i].Obj.Y + gPlayers[i].Obj.Rect.Y + gPlayers[i].Obj.Rect.Height - fH,
92 IntToStr(gPlayers[i].Armor), gStdFont);
93 end;
94 end;
96 procedure r_Player_DrawCorpses;
97 var
98 i, fX, fY: Integer;
99 a: TDFPoint;
100 begin
101 if gGibs <> nil then
102 for i := 0 to High(gGibs) do
103 if gGibs[i].alive then
104 with gGibs[i] do
105 begin
106 if not g_Obj_Collide(sX, sY, sWidth, sHeight, @Obj) then
107 Continue;
109 Obj.lerp(gLerpFactor, fX, fY);
111 a.X := Obj.Rect.X+(Obj.Rect.Width div 2);
112 a.y := Obj.Rect.Y+(Obj.Rect.Height div 2);
114 e_DrawAdv(ID, fX, fY, 0, True, False, RAngle, @a, TMirrorType.None);
116 e_Colors := Color;
117 e_DrawAdv(MaskID, fX, fY, 0, True, False, RAngle, @a, TMirrorType.None);
118 e_Colors.R := 255;
119 e_Colors.G := 255;
120 e_Colors.B := 255;
121 end;
123 if gCorpses <> nil then
124 for i := 0 to High(gCorpses) do
125 if gCorpses[i] <> nil then
126 r_Player_DrawCorpse(gCorpses[i])
127 end;
129 procedure r_Player_DrawShells;
130 var
131 i, fX, fY: Integer;
132 a: TDFPoint;
133 begin
134 if gShells <> nil then
135 for i := 0 to High(gShells) do
136 if gShells[i].alive then
137 with gShells[i] do
138 begin
139 if not g_Obj_Collide(sX, sY, sWidth, sHeight, @Obj) then
140 Continue;
142 Obj.lerp(gLerpFactor, fX, fY);
144 a.X := CX;
145 a.Y := CY;
147 e_DrawAdv(SpriteID, fX, fY, 0, True, False, RAngle, @a, TMirrorType.None);
148 end;
149 end;
151 procedure r_Player_DrawIndicator (p: TPlayer; Color: TRGB);
152 var
153 indX, indY, fX, fY, fSlope: Integer;
154 indW, indH: Word;
155 indA: Single;
156 a: TDFPoint;
157 nW, nH: Byte;
158 ID: DWORD;
159 c: TRGB;
160 begin
161 if p.Alive then
162 begin
163 p.Obj.lerp(gLerpFactor, fX, fY);
164 fSlope := nlerp(p.SlopeOld, p.Obj.slopeUpLeft, gLerpFactor);
166 case gPlayerIndicatorStyle of
167 0:
168 begin
169 if g_Texture_Get('TEXTURE_PLAYER_INDICATOR', ID) then
170 begin
171 e_GetTextureSize(ID, @indW, @indH);
172 a.X := indW div 2;
173 a.Y := indH div 2;
175 if (p.Obj.X + p.Obj.Rect.X) < 0 then
176 begin
177 indA := 90;
178 indX := fX + p.Obj.Rect.X + p.Obj.Rect.Width;
179 indY := fY + p.Obj.Rect.Y + (p.Obj.Rect.Height - indW) div 2;
180 end
182 else if (p.Obj.X + p.Obj.Rect.X + p.Obj.Rect.Width) > Max(gMapInfo.Width, gPlayerScreenSize.X) then
183 begin
184 indA := 270;
185 indX := fX + p.Obj.Rect.X - indH;
186 indY := fY + p.Obj.Rect.Y + (p.Obj.Rect.Height - indW) div 2;
187 end
189 else if (p.Obj.Y - indH) < 0 then
190 begin
191 indA := 180;
192 indX := fX + p.Obj.Rect.X + (p.Obj.Rect.Width - indW) div 2;
193 indY := fY + p.Obj.Rect.Y + p.Obj.Rect.Height;
194 end
196 else
197 begin
198 indA := 0;
199 indX := fX + p.Obj.Rect.X + (p.Obj.Rect.Width - indW) div 2;
200 indY := fY - indH;
201 end;
203 indY := indY + fSlope;
204 indX := EnsureRange(indX, 0, Max(gMapInfo.Width, gPlayerScreenSize.X) - indW);
205 indY := EnsureRange(indY, 0, Max(gMapInfo.Height, gPlayerScreenSize.Y) - indH);
207 c := e_Colors;
208 e_Colors := Color;
209 e_DrawAdv(ID, indX, indY, 0, True, False, indA, @a);
210 e_Colors := c;
211 end;
212 end;
214 1:
215 begin
216 e_TextureFontGetSize(gStdFont, nW, nH);
217 indX := fX + p.Obj.Rect.X + (p.Obj.Rect.Width - Length(p.Name) * nW) div 2;
218 indY := fY - nH + fSlope;
219 e_TextureFontPrintEx(indX, indY, p.Name, gStdFont, Color.R, Color.G, Color.B, 1.0, True);
220 end;
221 end;
222 end
223 end;
225 procedure r_Player_DrawBubble (p: TPlayer);
226 var
227 bubX, bubY, fX, fY: Integer;
228 ID: LongWord;
229 Rb, Gb, Bb,
230 Rw, Gw, Bw: SmallInt;
231 Dot: Byte;
232 CObj: TObj;
233 begin
234 CObj := p.getCameraObj();
235 CObj.lerp(gLerpFactor, fX, fY);
236 // NB: _F_Obj.Rect is used to keep the bubble higher; this is not a mistake
237 bubX := fX + p.Obj.Rect.X + IfThen(p.Direction = TDirection.D_LEFT, -4, 18);
238 bubY := fY + p.Obj.Rect.Y - 18;
239 Rb := 64;
240 Gb := 64;
241 Bb := 64;
242 Rw := 240;
243 Gw := 240;
244 Bw := 240;
245 case gChatBubble of
246 1: // simple textual non-bubble
247 begin
248 bubX := fX + p.Obj.Rect.X - 11;
249 bubY := fY + p.Obj.Rect.Y - 17;
250 e_TextureFontPrint(bubX, bubY, '[...]', gStdFont);
251 Exit;
252 end;
253 2: // advanced pixel-perfect bubble
254 begin
255 if p.Team = TEAM_RED then
256 Rb := 255
257 else
258 if p.Team = TEAM_BLUE then
259 Bb := 255;
260 end;
261 3: // colored bubble
262 begin
263 Rb := p.Model.Color.R;
264 Gb := p.Model.Color.G;
265 Bb := p.Model.Color.B;
266 Rw := Min(Rb * 2 + 64, 255);
267 Gw := Min(Gb * 2 + 64, 255);
268 Bw := Min(Bb * 2 + 64, 255);
269 if (Abs(Rw - Rb) < 32)
270 or (Abs(Gw - Gb) < 32)
271 or (Abs(Bw - Bb) < 32) then
272 begin
273 Rb := Max(Rw div 2 - 16, 0);
274 Gb := Max(Gw div 2 - 16, 0);
275 Bb := Max(Bw div 2 - 16, 0);
276 end;
277 end;
278 4: // custom textured bubble
279 begin
280 if g_Texture_Get('TEXTURE_PLAYER_TALKBUBBLE', ID) then
281 if p.Direction = TDirection.D_RIGHT then
282 e_Draw(ID, bubX - 6, bubY - 7, 0, True, False)
283 else
284 e_Draw(ID, bubX - 6, bubY - 7, 0, True, False, TMirrorType.Horizontal);
285 Exit;
286 end;
287 end;
289 // Outer borders
290 e_DrawQuad(bubX + 1, bubY , bubX + 18, bubY + 13, Rb, Gb, Bb);
291 e_DrawQuad(bubX , bubY + 1, bubX + 19, bubY + 12, Rb, Gb, Bb);
292 // Inner box
293 e_DrawFillQuad(bubX + 1, bubY + 1, bubX + 18, bubY + 12, Rw, Gw, Bw, 0);
295 // Tail
296 Dot := IfThen(p.Direction = TDirection.D_LEFT, 14, 5);
297 e_DrawLine(1, bubX + Dot, bubY + 14, bubX + Dot, bubY + 16, Rb, Gb, Bb);
298 e_DrawLine(1, bubX + IfThen(p.Direction = TDirection.D_LEFT, Dot - 1, Dot + 1), bubY + 13, bubX + IfThen(p.Direction = TDirection.D_LEFT, Dot - 1, Dot + 1), bubY + 15, Rw, Gw, Bw);
299 e_DrawLine(1, bubX + IfThen(p.Direction = TDirection.D_LEFT, Dot - 2, Dot + 2), bubY + 13, bubX + IfThen(p.Direction = TDirection.D_LEFT, Dot - 2, Dot + 2), bubY + 14, Rw, Gw, Bw);
300 e_DrawLine(1, bubX + IfThen(p.Direction = TDirection.D_LEFT, Dot - 3, Dot + 3), bubY + 13, bubX + IfThen(p.Direction = TDirection.D_LEFT, Dot - 3, Dot + 3), bubY + 13, Rw, Gw, Bw);
301 e_DrawLine(1, bubX + IfThen(p.Direction = TDirection.D_LEFT, Dot - 3, Dot + 3), bubY + 14, bubX + IfThen(p.Direction = TDirection.D_LEFT, Dot - 1, Dot + 1), bubY + 16, Rb, Gb, Bb);
303 // Dots
304 Dot := 6;
305 e_DrawFillQuad(bubX + Dot, bubY + 8, bubX + Dot + 1, bubY + 9, Rb, Gb, Bb, 0);
306 e_DrawFillQuad(bubX + Dot + 3, bubY + 8, bubX + Dot + 4, bubY + 9, Rb, Gb, Bb, 0);
307 e_DrawFillQuad(bubX + Dot + 6, bubY + 8, bubX + Dot + 7, bubY + 9, Rb, Gb, Bb, 0);
308 end;
310 procedure r_Player_Draw (p: TPlayer);
311 var
312 ID: DWORD;
313 w, h: Word;
314 dr: Boolean;
315 Mirror: TMirrorType;
316 fX, fY, fSlope: Integer;
317 begin
318 p.Obj.lerp(gLerpFactor, fX, fY);
319 fSlope := nlerp(p.SlopeOld, p.Obj.slopeUpLeft, gLerpFactor);
321 if p.Alive then
322 begin
323 if p.Direction = TDirection.D_RIGHT then
324 Mirror := TMirrorType.None
325 else
326 Mirror := TMirrorType.Horizontal;
328 if p.PunchAnim <> nil then
329 begin
330 p.PunchAnim.Draw(fX + IfThen(p.Direction = TDirection.D_LEFT, 15 - p.Obj.Rect.X, p.Obj.Rect.X - 15), fY + fSlope + p.Obj.Rect.Y - 11, Mirror);
331 if p.PunchAnim.played then
332 begin
333 p.PunchAnim.Free;
334 p.PunchAnim := nil;
335 end;
336 end;
338 if (p.FMegaRulez[MR_INVUL] > gTime) and ((gPlayerDrawn <> p) or (p.SpawnInvul >= gTime)) then
339 if g_Texture_Get('TEXTURE_PLAYER_INVULPENTA', ID) then
340 begin
341 e_GetTextureSize(ID, @w, @h);
342 if p.Direction = TDirection.D_LEFT then
343 e_Draw(ID, fX + p.Obj.Rect.X + (p.Obj.Rect.Width div 2) - (w div 2) + 4,
344 fY + p.Obj.Rect.Y + (p.Obj.Rect.Height div 2) - (h div 2) - 7 + fSlope, 0, True, False)
345 else
346 e_Draw(ID, fX + p.Obj.Rect.X + (p.Obj.Rect.Width div 2) - (w div 2) - 2,
347 fY + p.Obj.Rect.Y + (p.Obj.Rect.Height div 2) - (h div 2) - 7 + fSlope, 0, True, False)
348 end;
350 if p.FMegaRulez[MR_INVIS] > gTime then
351 begin
352 if (gPlayerDrawn <> nil) and ((p = gPlayerDrawn) or
353 ((p.Team = gPlayerDrawn.Team) and (gGameSettings.GameMode <> GM_DM))) then
354 begin
355 if (p.FMegaRulez[MR_INVIS] - gTime) <= 2100 then
356 dr := not Odd((p.FMegaRulez[MR_INVIS] - gTime) div 300)
357 else
358 dr := True;
359 if dr then
360 p.Model.Draw(fX, fY + fSlope, 200)
361 else
362 p.Model.Draw(fX, fY + fSlope);
363 end
364 else
365 p.Model.Draw(fX, fY + fSlope, 254);
366 end
367 else
368 p.Model.Draw(fX, fY + fSlope);
369 end;
371 if g_debug_Frames then
372 begin
373 e_DrawQuad(p.Obj.X + p.Obj.Rect.X,
374 p.Obj.Y + p.Obj.Rect.Y,
375 p.Obj.X + p.Obj.Rect.X + p.Obj.Rect.Width - 1,
376 p.Obj.Y + p.Obj.Rect.Y + p.Obj.Rect.Height - 1,
377 0, 255, 0);
378 end;
380 if (gChatBubble > 0) and (p.FKeys[KEY_CHAT].Pressed) and not p.Ghost then
381 if (p.FMegaRulez[MR_INVIS] <= gTime) or ((gPlayerDrawn <> nil) and ((p = gPlayerDrawn) or
382 ((p.Team = gPlayerDrawn.Team) and (gGameSettings.GameMode <> GM_DM)))) then
383 r_Player_DrawBubble(p);
385 // e_DrawPoint(5, 335, 288, 255, 0, 0); // DL, UR, DL, UR
386 if gAimLine and p.Alive and ((p = gPlayer1) or (p = gPlayer2)) then
387 r_Player_DrawAim(p);
388 end;
390 procedure r_Player_DrawAim (p: TPlayer);
392 procedure drawCast (sz: Integer; ax0, ay0, ax1, ay1: Integer);
393 var
394 ex, ey: Integer;
395 begin
397 {$IFDEF ENABLE_HOLMES}
398 if isValidViewPort and (self = gPlayer1) then
399 begin
400 g_Holmes_plrLaser(ax0, ay0, ax1, ay1);
401 end;
402 {$ENDIF}
404 e_DrawLine(sz, ax0, ay0, ax1, ay1, 255, 0, 0, 96);
405 if (g_Map_traceToNearestWall(ax0, ay0, ax1, ay1, @ex, @ey) <> nil) then
406 begin
407 e_DrawLine(sz, ax0, ay0, ex, ey, 0, 255, 0, 96);
408 end
409 else
410 begin
411 e_DrawLine(sz, ax0, ay0, ex, ey, 0, 0, 255, 96);
412 end;
413 end;
415 var
416 wx, wy, xx, yy: Integer;
417 angle: SmallInt;
418 sz, len: Word;
419 begin
420 wx := p.Obj.X + WEAPONPOINT[p.Direction].X + IfThen(p.Direction = TDirection.D_LEFT, 7, -7);
421 wy := p.Obj.Y + WEAPONPOINT[p.Direction].Y;
422 angle := p.Angle_;
423 len := 1024;
424 sz := 2;
425 case p.CurrWeap of
426 0: begin // Punch
427 len := 12;
428 sz := 4;
429 end;
430 1: begin // Chainsaw
431 len := 24;
432 sz := 6;
433 end;
434 2: begin // Pistol
435 len := 1024;
436 sz := 2;
437 if angle = ANGLE_RIGHTUP then Dec(angle, 2);
438 if angle = ANGLE_RIGHTDOWN then Inc(angle, 4);
439 if angle = ANGLE_LEFTUP then Inc(angle, 2);
440 if angle = ANGLE_LEFTDOWN then Dec(angle, 4);
441 end;
442 3: begin // Shotgun
443 len := 1024;
444 sz := 3;
445 if angle = ANGLE_RIGHTUP then Dec(angle, 2);
446 if angle = ANGLE_RIGHTDOWN then Inc(angle, 4);
447 if angle = ANGLE_LEFTUP then Inc(angle, 2);
448 if angle = ANGLE_LEFTDOWN then Dec(angle, 4);
449 end;
450 4: begin // Double Shotgun
451 len := 1024;
452 sz := 4;
453 if angle = ANGLE_RIGHTUP then Dec(angle, 2);
454 if angle = ANGLE_RIGHTDOWN then Inc(angle, 4);
455 if angle = ANGLE_LEFTUP then Inc(angle, 2);
456 if angle = ANGLE_LEFTDOWN then Dec(angle, 4);
457 end;
458 5: begin // Chaingun
459 len := 1024;
460 sz := 3;
461 if angle = ANGLE_RIGHTUP then Dec(angle, 2);
462 if angle = ANGLE_RIGHTDOWN then Inc(angle, 4);
463 if angle = ANGLE_LEFTUP then Inc(angle, 2);
464 if angle = ANGLE_LEFTDOWN then Dec(angle, 4);
465 end;
466 6: begin // Rocket Launcher
467 len := 1024;
468 sz := 7;
469 if angle = ANGLE_RIGHTUP then Inc(angle, 2);
470 if angle = ANGLE_RIGHTDOWN then Inc(angle, 4);
471 if angle = ANGLE_LEFTUP then Dec(angle, 2);
472 if angle = ANGLE_LEFTDOWN then Dec(angle, 4);
473 end;
474 7: begin // Plasmagun
475 len := 1024;
476 sz := 5;
477 if angle = ANGLE_RIGHTUP then Inc(angle);
478 if angle = ANGLE_RIGHTDOWN then Inc(angle, 3);
479 if angle = ANGLE_LEFTUP then Dec(angle);
480 if angle = ANGLE_LEFTDOWN then Dec(angle, 3);
481 end;
482 8: begin // BFG
483 len := 1024;
484 sz := 12;
485 if angle = ANGLE_RIGHTUP then Inc(angle, 1);
486 if angle = ANGLE_RIGHTDOWN then Inc(angle, 2);
487 if angle = ANGLE_LEFTUP then Dec(angle, 1);
488 if angle = ANGLE_LEFTDOWN then Dec(angle, 2);
489 end;
490 9: begin // Super Chaingun
491 len := 1024;
492 sz := 4;
493 if angle = ANGLE_RIGHTUP then Dec(angle, 2);
494 if angle = ANGLE_RIGHTDOWN then Inc(angle, 4);
495 if angle = ANGLE_LEFTUP then Inc(angle, 2);
496 if angle = ANGLE_LEFTDOWN then Dec(angle, 4);
497 end;
498 end;
499 xx := Trunc(Cos(-DegToRad(angle)) * len) + wx;
500 yy := Trunc(Sin(-DegToRad(angle)) * len) + wy;
501 {$IF DEFINED(D2F_DEBUG)}
502 drawCast(sz, wx, wy, xx, yy);
503 {$ELSE}
504 e_DrawLine(sz, wx, wy, xx, yy, 255, 0, 0, 96);
505 {$ENDIF}
506 end;
508 procedure r_Player_DrawGUI (pl: TPlayer);
509 var
510 ID: DWORD;
511 X, Y, SY, a, p, m: Integer;
512 tw, th: Word;
513 cw, ch: Byte;
514 s: string;
515 stat: TPlayerStatArray;
516 begin
517 X := gPlayerScreenSize.X;
518 SY := gPlayerScreenSize.Y;
519 Y := 0;
521 if gShowGoals and (gGameSettings.GameMode in [GM_TDM, GM_CTF]) then
522 begin
523 if gGameSettings.GameMode = GM_CTF then
524 a := 32 + 8
525 else
526 a := 0;
527 if gGameSettings.GameMode = GM_CTF then
528 begin
529 s := 'TEXTURE_PLAYER_REDFLAG';
530 if gFlags[FLAG_RED].State = FLAG_STATE_CAPTURED then
531 s := 'TEXTURE_PLAYER_REDFLAG_S';
532 if gFlags[FLAG_RED].State = FLAG_STATE_DROPPED then
533 s := 'TEXTURE_PLAYER_REDFLAG_D';
534 if g_Texture_Get(s, ID) then
535 e_Draw(ID, X-16-32, 240-72-4, 0, True, False);
536 end;
538 s := IntToStr(gTeamStat[TEAM_RED].Goals);
539 e_CharFont_GetSize(gMenuFont, s, tw, th);
540 e_CharFont_PrintEx(gMenuFont, X-16-a-tw, 240-72-4, s, TEAMCOLOR[TEAM_RED]);
542 if gGameSettings.GameMode = GM_CTF then
543 begin
544 s := 'TEXTURE_PLAYER_BLUEFLAG';
545 if gFlags[FLAG_BLUE].State = FLAG_STATE_CAPTURED then
546 s := 'TEXTURE_PLAYER_BLUEFLAG_S';
547 if gFlags[FLAG_BLUE].State = FLAG_STATE_DROPPED then
548 s := 'TEXTURE_PLAYER_BLUEFLAG_D';
549 if g_Texture_Get(s, ID) then
550 e_Draw(ID, X-16-32, 240-32-4, 0, True, False);
551 end;
553 s := IntToStr(gTeamStat[TEAM_BLUE].Goals);
554 e_CharFont_GetSize(gMenuFont, s, tw, th);
555 e_CharFont_PrintEx(gMenuFont, X-16-a-tw, 240-32-4, s, TEAMCOLOR[TEAM_BLUE]);
556 end;
558 if g_Texture_Get('TEXTURE_PLAYER_HUDBG', ID) then
559 e_DrawFill(ID, X, 0, 1, (gPlayerScreenSize.Y div 256)+IfThen(gPlayerScreenSize.Y mod 256 > 0, 1, 0),
560 0, False, False);
562 if g_Texture_Get('TEXTURE_PLAYER_HUD', ID) then
563 e_Draw(ID, X+2, Y, 0, True, False);
565 if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
566 begin
567 if gShowStat then
568 begin
569 s := IntToStr(pl.Frags);
570 e_CharFont_GetSize(gMenuFont, s, tw, th);
571 e_CharFont_PrintEx(gMenuFont, X-16-tw, Y, s, _RGB(255, 0, 0));
573 s := '';
574 p := 1;
575 m := 0;
576 stat := g_Player_GetStats();
577 if stat <> nil then
578 begin
579 p := 1;
581 for a := 0 to High(stat) do
582 if stat[a].Name <> pl.Name then
583 begin
584 if stat[a].Frags > m then m := stat[a].Frags;
585 if stat[a].Frags > pl.Frags then p := p+1;
586 end;
587 end;
589 s := IntToStr(p)+' / '+IntToStr(Length(stat))+' ';
590 if pl.Frags >= m then s := s+'+' else s := s+'-';
591 s := s+IntToStr(Abs(pl.Frags-m));
593 e_CharFont_GetSize(gMenuSmallFont, s, tw, th);
594 e_CharFont_PrintEx(gMenuSmallFont, X-16-tw, Y+32, s, _RGB(255, 0, 0));
595 end;
597 if gLMSRespawn > LMS_RESPAWN_NONE then
598 begin
599 s := _lc[I_GAME_WARMUP];
600 e_CharFont_GetSize(gMenuFont, s, tw, th);
601 s := s + ': ' + IntToStr((gLMSRespawnTime - gTime) div 1000);
602 e_CharFont_PrintEx(gMenuFont, X-64-tw, SY-32, s, _RGB(0, 255, 0));
603 end
604 else if gShowLives and (gGameSettings.MaxLives > 0) then
605 begin
606 s := IntToStr(pl.Lives);
607 e_CharFont_GetSize(gMenuFont, s, tw, th);
608 e_CharFont_PrintEx(gMenuFont, X-16-tw, SY-32, s, _RGB(0, 255, 0));
609 end;
610 end;
612 e_CharFont_GetSize(gMenuSmallFont, pl.Name, tw, th);
613 e_CharFont_PrintEx(gMenuSmallFont, X+98-(tw div 2), Y+8, pl.Name, _RGB(255, 0, 0));
615 if R_BERSERK in pl.FRulez then
616 e_Draw(gItemsTexturesID[ITEM_MEDKIT_BLACK], X+37, Y+45, 0, True, False)
617 else
618 e_Draw(gItemsTexturesID[ITEM_MEDKIT_LARGE], X+37, Y+45, 0, True, False);
620 if g_Texture_Get('TEXTURE_PLAYER_ARMORHUD', ID) then
621 e_Draw(ID, X+36, Y+77, 0, True, False);
623 s := IntToStr(IfThen(pl.Health > 0, pl.Health, 0));
624 e_CharFont_GetSize(gMenuFont, s, tw, th);
625 e_CharFont_PrintEx(gMenuFont, X+178-tw, Y+40, s, _RGB(255, 0, 0));
627 s := IntToStr(pl.Armor);
628 e_CharFont_GetSize(gMenuFont, s, tw, th);
629 e_CharFont_PrintEx(gMenuFont, X+178-tw, Y+68, s, _RGB(255, 0, 0));
631 s := IntToStr(pl.GetAmmoByWeapon(pl.CurrWeap));
633 case pl.CurrWeap of
634 WEAPON_KASTET:
635 begin
636 s := '--';
637 ID := gItemsTexturesID[ITEM_WEAPON_KASTET];
638 end;
639 WEAPON_SAW:
640 begin
641 s := '--';
642 ID := gItemsTexturesID[ITEM_WEAPON_SAW];
643 end;
644 WEAPON_PISTOL: ID := gItemsTexturesID[ITEM_WEAPON_PISTOL];
645 WEAPON_CHAINGUN: ID := gItemsTexturesID[ITEM_WEAPON_CHAINGUN];
646 WEAPON_SHOTGUN1: ID := gItemsTexturesID[ITEM_WEAPON_SHOTGUN1];
647 WEAPON_SHOTGUN2: ID := gItemsTexturesID[ITEM_WEAPON_SHOTGUN2];
648 WEAPON_SUPERPULEMET: ID := gItemsTexturesID[ITEM_WEAPON_SUPERPULEMET];
649 WEAPON_ROCKETLAUNCHER: ID := gItemsTexturesID[ITEM_WEAPON_ROCKETLAUNCHER];
650 WEAPON_PLASMA: ID := gItemsTexturesID[ITEM_WEAPON_PLASMA];
651 WEAPON_BFG: ID := gItemsTexturesID[ITEM_WEAPON_BFG];
652 WEAPON_FLAMETHROWER: ID := gItemsTexturesID[ITEM_WEAPON_FLAMETHROWER];
653 end;
655 e_CharFont_GetSize(gMenuFont, s, tw, th);
656 e_CharFont_PrintEx(gMenuFont, X+178-tw, Y+158, s, _RGB(255, 0, 0));
657 e_Draw(ID, X+20, Y+160, 0, True, False);
659 if R_KEY_RED in pl.FRulez then
660 e_Draw(gItemsTexturesID[ITEM_KEY_RED], X+78, Y+214, 0, True, False);
662 if R_KEY_GREEN in pl.FRulez then
663 e_Draw(gItemsTexturesID[ITEM_KEY_GREEN], X+95, Y+214, 0, True, False);
665 if R_KEY_BLUE in pl.FRulez then
666 e_Draw(gItemsTexturesID[ITEM_KEY_BLUE], X+112, Y+214, 0, True, False);
668 if pl.JetFuel > 0 then
669 begin
670 if g_Texture_Get('TEXTURE_PLAYER_HUDAIR', ID) then
671 e_Draw(ID, X+2, Y+116, 0, True, False);
672 if g_Texture_Get('TEXTURE_PLAYER_HUDJET', ID) then
673 e_Draw(ID, X+2, Y+126, 0, True, False);
674 e_DrawLine(4, X+16, Y+122, X+16+Trunc(168*IfThen(pl.Air > 0, pl.Air, 0)/AIR_MAX), Y+122, 0, 0, 196);
675 e_DrawLine(4, X+16, Y+132, X+16+Trunc(168*pl.JetFuel/JET_MAX), Y+132, 208, 0, 0);
676 end
677 else
678 begin
679 if g_Texture_Get('TEXTURE_PLAYER_HUDAIR', ID) then
680 e_Draw(ID, X+2, Y+124, 0, True, False);
681 e_DrawLine(4, X+16, Y+130, X+16+Trunc(168*IfThen(pl.Air > 0, pl.Air, 0)/AIR_MAX), Y+130, 0, 0, 196);
682 end;
684 if gShowPing and g_Game_IsClient then
685 begin
686 s := _lc[I_GAME_PING_HUD] + IntToStr(NetPeer.lastRoundTripTime) + _lc[I_NET_SLIST_PING_MS];
687 e_TextureFontPrint(X + 4, Y + 242, s, gStdFont);
688 Y := Y + 16;
689 end;
691 if pl.Spectator then
692 begin
693 e_TextureFontPrint(X + 4, Y + 242, _lc[I_PLAYER_SPECT], gStdFont);
694 e_TextureFontPrint(X + 4, Y + 258, _lc[I_PLAYER_SPECT2], gStdFont);
695 e_TextureFontPrint(X + 4, Y + 274, _lc[I_PLAYER_SPECT1], gStdFont);
696 if pl.NoRespawn then
697 begin
698 e_TextureFontGetSize(gStdFont, cw, ch);
699 s := _lc[I_PLAYER_SPECT4];
700 e_TextureFontPrintEx(gScreenWidth div 2 - cw*(Length(s) div 2),
701 gScreenHeight-4-ch, s, gStdFont, 255, 255, 255, 1, True);
702 e_TextureFontPrint(X + 4, Y + 290, _lc[I_PLAYER_SPECT1S], gStdFont);
703 end;
705 end;
706 end;
708 procedure r_Player_DrawRulez (p: TPlayer);
709 var
710 dr: Boolean;
711 begin
712 // При взятии неуязвимости рисуется инверсионный белый фон
713 if (p.FMegaRulez[MR_INVUL] >= gTime) and (p.SpawnInvul < gTime) then
714 begin
715 if (p.FMegaRulez[MR_INVUL]-gTime) <= 2100 then
716 dr := not Odd((p.FMegaRulez[MR_INVUL]-gTime) div 300)
717 else
718 dr := True;
720 if dr then
721 e_DrawFillQuad(0, 0, gPlayerScreenSize.X-1, gPlayerScreenSize.Y-1,
722 191, 191, 191, 0, TBlending.Invert);
723 end;
725 // При взятии защитного костюма рисуется зеленоватый фон
726 if p.FMegaRulez[MR_SUIT] >= gTime then
727 begin
728 if (p.FMegaRulez[MR_SUIT]-gTime) <= 2100 then
729 dr := not Odd((p.FMegaRulez[MR_SUIT]-gTime) div 300)
730 else
731 dr := True;
733 if dr then
734 e_DrawFillQuad(0, 0, gPlayerScreenSize.X-1, gPlayerScreenSize.Y-1,
735 0, 96, 0, 200, TBlending.None);
736 end;
738 // При взятии берсерка рисуется красноватый фон
739 if (p.Berserk >= 0) and (LongWord(p.Berserk) >= gTime) and (gFlash = 2) then
740 begin
741 e_DrawFillQuad(0, 0, gPlayerScreenSize.X-1, gPlayerScreenSize.Y-1,
742 255, 0, 0, 200, TBlending.None);
743 end;
744 end;
746 procedure r_Player_DrawPain (p: TPlayer);
747 var
748 a, h: Integer;
749 begin
750 if p.Pain = 0 then Exit;
752 a := p.Pain;
754 if a < 15 then h := 0
755 else if a < 35 then h := 1
756 else if a < 55 then h := 2
757 else if a < 75 then h := 3
758 else if a < 95 then h := 4
759 else h := 5;
761 //if a > 255 then a := 255;
763 e_DrawFillQuad(0, 0, gPlayerScreenSize.X-1, gPlayerScreenSize.Y-1, 255, 0, 0, 255-h*50);
764 //e_DrawFillQuad(0, 0, gPlayerScreenSize.X-1, gPlayerScreenSize.Y-1, 255-min(128, a), 255-a, 255-a, 0, B_FILTER);
765 end;
767 procedure r_Player_DrawPickup (p: TPlayer);
768 var
769 a, h: Integer;
770 begin
771 if p.Pickup = 0 then Exit;
773 a := p.Pickup;
775 if a < 15 then h := 1
776 else if a < 35 then h := 2
777 else if a < 55 then h := 3
778 else if a < 75 then h := 4
779 else h := 5;
781 e_DrawFillQuad(0, 0, gPlayerScreenSize.X-1, gPlayerScreenSize.Y-1, 150, 200, 150, 255-h*50);
782 end;
784 procedure r_Player_DrawCorpse (p: TCorpse);
785 var
786 fX, fY: Integer;
787 begin
788 if p.State = CORPSE_STATE_REMOVEME then
789 Exit;
791 p.Obj.lerp(gLerpFactor, fX, fY);
793 if p.Animation <> nil then
794 p.Animation.Draw(fX, fY, TMirrorType.None);
796 if p.AnimationMask <> nil then
797 begin
798 e_Colors := p.Color;
799 p.AnimationMask.Draw(fX, fY, TMirrorType.None);
800 e_Colors.R := 255;
801 e_Colors.G := 255;
802 e_Colors.B := 255;
803 end;
804 end;
806 end.