DEADSOFTWARE

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