DEADSOFTWARE

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