DEADSOFTWARE

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