DEADSOFTWARE

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