1 (* Copyright (C) Doom 2D: Forever Developers
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.
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.
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/>.
15 {$INCLUDE ../../shared/a_modes.inc}
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
;
42 {$IFDEF ENABLE_CORPSES}
43 procedure r_Player_DrawCorpses
;
49 {$IFDEF ENABLE_HOLMES}
55 {$IFDEF ENABLE_SHELLS}
58 {$IFDEF ENABLE_CORPSES}
61 SysUtils
, Classes
, Math
,
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
68 gItemsTexturesID
: array [0..ITEM_MAX
] of DWORD
;
69 PunchFrames
: array [Boolean, 0..2] of DWORD
;
73 procedure r_Player_Load
;
75 g_Frames_CreateWAD(nil, 'FRAMES_ITEM_BLUESPHERE', GameWAD
+':TEXTURES\SBLUE', 32, 32, 4, True);
76 g_Frames_CreateWAD(nil, 'FRAMES_ITEM_WHITESPHERE', GameWAD
+':TEXTURES\SWHITE', 32, 32, 4, True);
77 g_Frames_CreateWAD(nil, 'FRAMES_ITEM_ARMORGREEN', GameWAD
+':TEXTURES\ARMORGREEN', 32, 16, 3, True);
78 g_Frames_CreateWAD(nil, 'FRAMES_ITEM_ARMORBLUE', GameWAD
+':TEXTURES\ARMORBLUE', 32, 16, 3, True);
79 g_Frames_CreateWAD(nil, 'FRAMES_ITEM_JETPACK', GameWAD
+':TEXTURES\JETPACK', 32, 32, 3, True);
80 g_Frames_CreateWAD(nil, 'FRAMES_ITEM_INVUL', GameWAD
+':TEXTURES\INVUL', 32, 32, 4, True);
81 g_Frames_CreateWAD(nil, 'FRAMES_ITEM_INVIS', GameWAD
+':TEXTURES\INVIS', 32, 32, 4, True);
82 g_Frames_CreateWAD(nil, 'FRAMES_ITEM_RESPAWN', GameWAD
+':TEXTURES\ITEMRESPAWN', 32, 32, 5, True);
83 g_Frames_CreateWAD(nil, 'FRAMES_ITEM_BOTTLE', GameWAD
+':TEXTURES\BOTTLE', 16, 32, 4, True);
84 g_Frames_CreateWAD(nil, 'FRAMES_ITEM_HELMET', GameWAD
+':TEXTURES\HELMET', 16, 16, 4, True);
85 g_Frames_CreateWAD(nil, 'FRAMES_FLAG_RED', GameWAD
+':TEXTURES\FLAGRED', 64, 64, 5, False);
86 g_Frames_CreateWAD(nil, 'FRAMES_FLAG_BLUE', GameWAD
+':TEXTURES\FLAGBLUE', 64, 64, 5, False);
87 g_Frames_CreateWAD(nil, 'FRAMES_FLAG_DOM', GameWAD
+':TEXTURES\FLAGDOM', 64, 64, 5, False);
88 g_Texture_CreateWADEx('ITEM_MEDKIT_SMALL', GameWAD
+':TEXTURES\MED1');
89 g_Texture_CreateWADEx('ITEM_MEDKIT_LARGE', GameWAD
+':TEXTURES\MED2');
90 g_Texture_CreateWADEx('ITEM_WEAPON_SAW', GameWAD
+':TEXTURES\SAW');
91 g_Texture_CreateWADEx('ITEM_WEAPON_PISTOL', GameWAD
+':TEXTURES\PISTOL');
92 g_Texture_CreateWADEx('ITEM_WEAPON_KASTET', GameWAD
+':TEXTURES\KASTET');
93 g_Texture_CreateWADEx('ITEM_WEAPON_SHOTGUN1', GameWAD
+':TEXTURES\SHOTGUN1');
94 g_Texture_CreateWADEx('ITEM_WEAPON_SHOTGUN2', GameWAD
+':TEXTURES\SHOTGUN2');
95 g_Texture_CreateWADEx('ITEM_WEAPON_CHAINGUN', GameWAD
+':TEXTURES\MGUN');
96 g_Texture_CreateWADEx('ITEM_WEAPON_ROCKETLAUNCHER', GameWAD
+':TEXTURES\RLAUNCHER');
97 g_Texture_CreateWADEx('ITEM_WEAPON_PLASMA', GameWAD
+':TEXTURES\PGUN');
98 g_Texture_CreateWADEx('ITEM_WEAPON_BFG', GameWAD
+':TEXTURES\BFG');
99 g_Texture_CreateWADEx('ITEM_WEAPON_SUPERPULEMET', GameWAD
+':TEXTURES\SPULEMET');
100 g_Texture_CreateWADEx('ITEM_WEAPON_FLAMETHROWER', GameWAD
+':TEXTURES\FLAMETHROWER');
101 g_Texture_CreateWADEx('ITEM_AMMO_BULLETS', GameWAD
+':TEXTURES\CLIP');
102 g_Texture_CreateWADEx('ITEM_AMMO_BULLETS_BOX', GameWAD
+':TEXTURES\AMMO');
103 g_Texture_CreateWADEx('ITEM_AMMO_SHELLS', GameWAD
+':TEXTURES\SHELL1');
104 g_Texture_CreateWADEx('ITEM_AMMO_SHELLS_BOX', GameWAD
+':TEXTURES\SHELL2');
105 g_Texture_CreateWADEx('ITEM_AMMO_ROCKET', GameWAD
+':TEXTURES\ROCKET');
106 g_Texture_CreateWADEx('ITEM_AMMO_ROCKET_BOX', GameWAD
+':TEXTURES\ROCKETS');
107 g_Texture_CreateWADEx('ITEM_AMMO_CELL', GameWAD
+':TEXTURES\CELL');
108 g_Texture_CreateWADEx('ITEM_AMMO_CELL_BIG', GameWAD
+':TEXTURES\CELL2');
109 g_Texture_CreateWADEx('ITEM_AMMO_FUELCAN', GameWAD
+':TEXTURES\FUELCAN');
110 g_Texture_CreateWADEx('ITEM_AMMO_BACKPACK', GameWAD
+':TEXTURES\BPACK');
111 g_Texture_CreateWADEx('ITEM_KEY_RED', GameWAD
+':TEXTURES\KEYR');
112 g_Texture_CreateWADEx('ITEM_KEY_GREEN', GameWAD
+':TEXTURES\KEYG');
113 g_Texture_CreateWADEx('ITEM_KEY_BLUE', GameWAD
+':TEXTURES\KEYB');
114 g_Texture_CreateWADEx('ITEM_OXYGEN', GameWAD
+':TEXTURES\OXYGEN');
115 g_Texture_CreateWADEx('ITEM_SUIT', GameWAD
+':TEXTURES\SUIT');
116 g_Texture_CreateWADEx('ITEM_WEAPON_KASTET', GameWAD
+':TEXTURES\KASTET');
117 g_Texture_CreateWADEx('ITEM_MEDKIT_BLACK', GameWAD
+':TEXTURES\BMED');
119 g_Texture_Get('ITEM_MEDKIT_SMALL', gItemsTexturesID
[ITEM_MEDKIT_SMALL
]);
120 g_Texture_Get('ITEM_MEDKIT_LARGE', gItemsTexturesID
[ITEM_MEDKIT_LARGE
]);
121 g_Texture_Get('ITEM_MEDKIT_BLACK', gItemsTexturesID
[ITEM_MEDKIT_BLACK
]);
122 g_Texture_Get('ITEM_SUIT', gItemsTexturesID
[ITEM_SUIT
]);
123 g_Texture_Get('ITEM_OXYGEN', gItemsTexturesID
[ITEM_OXYGEN
]);
124 g_Texture_Get('ITEM_WEAPON_SAW', gItemsTexturesID
[ITEM_WEAPON_SAW
]);
125 g_Texture_Get('ITEM_WEAPON_SHOTGUN1', gItemsTexturesID
[ITEM_WEAPON_SHOTGUN1
]);
126 g_Texture_Get('ITEM_WEAPON_SHOTGUN2', gItemsTexturesID
[ITEM_WEAPON_SHOTGUN2
]);
127 g_Texture_Get('ITEM_WEAPON_CHAINGUN', gItemsTexturesID
[ITEM_WEAPON_CHAINGUN
]);
128 g_Texture_Get('ITEM_WEAPON_ROCKETLAUNCHER', gItemsTexturesID
[ITEM_WEAPON_ROCKETLAUNCHER
]);
129 g_Texture_Get('ITEM_WEAPON_PLASMA', gItemsTexturesID
[ITEM_WEAPON_PLASMA
]);
130 g_Texture_Get('ITEM_WEAPON_BFG', gItemsTexturesID
[ITEM_WEAPON_BFG
]);
131 g_Texture_Get('ITEM_WEAPON_SUPERPULEMET', gItemsTexturesID
[ITEM_WEAPON_SUPERPULEMET
]);
132 g_Texture_Get('ITEM_WEAPON_FLAMETHROWER', gItemsTexturesID
[ITEM_WEAPON_FLAMETHROWER
]);
133 g_Texture_Get('ITEM_AMMO_BULLETS', gItemsTexturesID
[ITEM_AMMO_BULLETS
]);
134 g_Texture_Get('ITEM_AMMO_BULLETS_BOX', gItemsTexturesID
[ITEM_AMMO_BULLETS_BOX
]);
135 g_Texture_Get('ITEM_AMMO_SHELLS', gItemsTexturesID
[ITEM_AMMO_SHELLS
]);
136 g_Texture_Get('ITEM_AMMO_SHELLS_BOX', gItemsTexturesID
[ITEM_AMMO_SHELLS_BOX
]);
137 g_Texture_Get('ITEM_AMMO_ROCKET', gItemsTexturesID
[ITEM_AMMO_ROCKET
]);
138 g_Texture_Get('ITEM_AMMO_ROCKET_BOX', gItemsTexturesID
[ITEM_AMMO_ROCKET_BOX
]);
139 g_Texture_Get('ITEM_AMMO_CELL', gItemsTexturesID
[ITEM_AMMO_CELL
]);
140 g_Texture_Get('ITEM_AMMO_CELL_BIG', gItemsTexturesID
[ITEM_AMMO_CELL_BIG
]);
141 g_Texture_Get('ITEM_AMMO_FUELCAN', gItemsTexturesID
[ITEM_AMMO_FUELCAN
]);
142 g_Texture_Get('ITEM_AMMO_BACKPACK', gItemsTexturesID
[ITEM_AMMO_BACKPACK
]);
143 g_Texture_Get('ITEM_KEY_RED', gItemsTexturesID
[ITEM_KEY_RED
]);
144 g_Texture_Get('ITEM_KEY_GREEN', gItemsTexturesID
[ITEM_KEY_GREEN
]);
145 g_Texture_Get('ITEM_KEY_BLUE', gItemsTexturesID
[ITEM_KEY_BLUE
]);
146 g_Texture_Get('ITEM_WEAPON_KASTET', gItemsTexturesID
[ITEM_WEAPON_KASTET
]);
147 g_Texture_Get('ITEM_WEAPON_PISTOL', gItemsTexturesID
[ITEM_WEAPON_PISTOL
]);
149 g_Frames_CreateWAD(@PunchFrames
[False, 0], 'FRAMES_PUNCH', GameWAD
+ ':WEAPONS\PUNCH', 64, 64, 4, False);
150 g_Frames_CreateWAD(@PunchFrames
[False, 1], 'FRAMES_PUNCH_UP', GameWAD
+ ':WEAPONS\PUNCH_UP', 64, 64, 4, False);
151 g_Frames_CreateWAD(@PunchFrames
[False, 2], 'FRAMES_PUNCH_DN', GameWAD
+ ':WEAPONS\PUNCH_DN', 64, 64, 4, False);
152 g_Frames_CreateWAD(@PunchFrames
[True, 0], 'FRAMES_PUNCH_BERSERK', GameWAD
+ ':WEAPONS\PUNCHB', 64, 64, 4, False);
153 g_Frames_CreateWAD(@PunchFrames
[True, 1], 'FRAMES_PUNCH_BERSERK_UP', GameWAD
+ ':WEAPONS\PUNCHB_UP', 64, 64, 4, False);
154 g_Frames_CreateWAD(@PunchFrames
[True, 2], 'FRAMES_PUNCH_BERSERK_DN', GameWAD
+ ':WEAPONS\PUNCHB_DN', 64, 64, 4, False);
155 g_Texture_CreateWADEx('TEXTURE_SHELL_BULLET', GameWAD
+ ':TEXTURES\EBULLET');
156 g_Texture_CreateWADEx('TEXTURE_SHELL_SHELL', GameWAD
+ ':TEXTURES\ESHELL');
157 g_Texture_Get('TEXTURE_SHELL_BULLET', BulletTexture
);
158 g_Texture_Get('TEXTURE_SHELL_SHELL', ShellTexture
);
161 procedure r_Player_Free
;
163 g_Frames_DeleteByName('FRAMES_PUNCH');
164 g_Frames_DeleteByName('FRAMES_PUNCH_UP');
165 g_Frames_DeleteByName('FRAMES_PUNCH_DN');
166 g_Frames_DeleteByName('FRAMES_PUNCH_BERSERK');
167 g_Frames_DeleteByName('FRAMES_PUNCH_BERSERK_UP');
168 g_Frames_DeleteByName('FRAMES_PUNCH_BERSERK_DN');
171 procedure r_Player_DrawAll
;
174 if gPlayers
<> nil then
175 for i
:= 0 to High(gPlayers
) do
176 if gPlayers
[i
] <> nil then
177 r_Player_Draw(gPlayers
[i
])
180 procedure r_Player_DrawDebug (p
: TPlayer
);
184 if p
= nil then Exit
;
185 if (@p
.Obj
) = nil then Exit
;
187 e_TextureFontGetSize(gStdFont
, fW
, fH
);
189 e_TextureFontPrint(0, 0 , 'Pos X: ' + IntToStr(p
.Obj
.X
), gStdFont
);
190 e_TextureFontPrint(0, fH
, 'Pos Y: ' + IntToStr(p
.Obj
.Y
), gStdFont
);
191 e_TextureFontPrint(0, fH
* 2, 'Vel X: ' + IntToStr(p
.Obj
.Vel
.X
), gStdFont
);
192 e_TextureFontPrint(0, fH
* 3, 'Vel Y: ' + IntToStr(p
.Obj
.Vel
.Y
), gStdFont
);
193 e_TextureFontPrint(0, fH
* 4, 'Acc X: ' + IntToStr(p
.Obj
.Accel
.X
), gStdFont
);
194 e_TextureFontPrint(0, fH
* 5, 'Acc Y: ' + IntToStr(p
.Obj
.Accel
.Y
), gStdFont
);
195 e_TextureFontPrint(0, fH
* 6, 'Old X: ' + IntToStr(p
.Obj
.oldX
), gStdFont
);
196 e_TextureFontPrint(0, fH
* 7, 'Old Y: ' + IntToStr(p
.Obj
.oldY
), gStdFont
);
199 procedure r_Player_DrawHealth
;
204 if gPlayers
= nil then Exit
;
205 e_TextureFontGetSize(gStdFont
, fW
, fH
);
207 for i
:= 0 to High(gPlayers
) do
208 if gPlayers
[i
] <> nil then
210 e_TextureFontPrint(gPlayers
[i
].Obj
.X
+ gPlayers
[i
].Obj
.Rect
.X
,
211 gPlayers
[i
].Obj
.Y
+ gPlayers
[i
].Obj
.Rect
.Y
+ gPlayers
[i
].Obj
.Rect
.Height
- fH
* 2,
212 IntToStr(gPlayers
[i
].Health
), gStdFont
);
213 e_TextureFontPrint(gPlayers
[i
].Obj
.X
+ gPlayers
[i
].Obj
.Rect
.X
,
214 gPlayers
[i
].Obj
.Y
+ gPlayers
[i
].Obj
.Rect
.Y
+ gPlayers
[i
].Obj
.Rect
.Height
- fH
,
215 IntToStr(gPlayers
[i
].Armor
), gStdFont
);
219 {$IFDEF ENABLE_CORPSES}
220 procedure r_Player_DrawCorpse (p
: TCorpse
);
223 if (p
.State
<> CORPSE_STATE_REMOVEME
) and (p
.Model
<> nil) then
225 p
.Obj
.lerp(gLerpFactor
, fX
, fY
);
226 r_PlayerModel_Draw(p
.Model
, fX
, fY
)
230 procedure r_Player_DrawCorpses
;
233 if gCorpses
<> nil then
234 for i
:= 0 to High(gCorpses
) do
235 if gCorpses
[i
] <> nil then
236 r_Player_DrawCorpse(gCorpses
[i
])
240 {$IFDEF ENABLE_SHELLS}
241 procedure r_Player_DrawShells
;
242 var i
, fX
, fY
: Integer; a
: TDFPoint
; TextureID
: DWORD
= DWORD(-1);
244 if gShells
<> nil then
246 for i
:= 0 to High(gShells
) do
248 if gShells
[i
].alive
and g_Obj_Collide(sX
, sY
, sWidth
, sHeight
, @gShells
[i
].Obj
) then
250 gShells
[i
].Obj
.lerp(gLerpFactor
, fX
, fY
);
251 case gShells
[i
].SType
of
254 TextureID
:= BulletTexture
;
258 SHELL_SHELL
, SHELL_DBLSHELL
:
260 TextureID
:= ShellTexture
;
267 e_DrawAdv(TextureID
, fX
, fY
, 0, True, False, gShells
[i
].RAngle
, @a
, TMirrorType
.None
);
274 procedure r_Player_DrawIndicator (p
: TPlayer
; Color
: TRGB
);
276 indX
, indY
, fX
, fY
, fSlope
: Integer;
286 p
.Obj
.lerp(gLerpFactor
, fX
, fY
);
287 fSlope
:= nlerp(p
.SlopeOld
, p
.Obj
.slopeUpLeft
, gLerpFactor
);
289 case gPlayerIndicatorStyle
of
292 if g_Texture_Get('TEXTURE_PLAYER_INDICATOR', ID
) then
294 e_GetTextureSize(ID
, @indW
, @indH
);
298 if (p
.Obj
.X
+ p
.Obj
.Rect
.X
) < 0 then
301 indX
:= fX
+ p
.Obj
.Rect
.X
+ p
.Obj
.Rect
.Width
;
302 indY
:= fY
+ p
.Obj
.Rect
.Y
+ (p
.Obj
.Rect
.Height
- indW
) div 2;
305 else if (p
.Obj
.X
+ p
.Obj
.Rect
.X
+ p
.Obj
.Rect
.Width
) > Max(gMapInfo
.Width
, gPlayerScreenSize
.X
) then
308 indX
:= fX
+ p
.Obj
.Rect
.X
- indH
;
309 indY
:= fY
+ p
.Obj
.Rect
.Y
+ (p
.Obj
.Rect
.Height
- indW
) div 2;
312 else if (p
.Obj
.Y
- indH
) < 0 then
315 indX
:= fX
+ p
.Obj
.Rect
.X
+ (p
.Obj
.Rect
.Width
- indW
) div 2;
316 indY
:= fY
+ p
.Obj
.Rect
.Y
+ p
.Obj
.Rect
.Height
;
322 indX
:= fX
+ p
.Obj
.Rect
.X
+ (p
.Obj
.Rect
.Width
- indW
) div 2;
326 indY
:= indY
+ fSlope
;
327 indX
:= EnsureRange(indX
, 0, Max(gMapInfo
.Width
, gPlayerScreenSize
.X
) - indW
);
328 indY
:= EnsureRange(indY
, 0, Max(gMapInfo
.Height
, gPlayerScreenSize
.Y
) - indH
);
332 e_DrawAdv(ID
, indX
, indY
, 0, True, False, indA
, @a
);
339 e_TextureFontGetSize(gStdFont
, nW
, nH
);
340 indX
:= fX
+ p
.Obj
.Rect
.X
+ (p
.Obj
.Rect
.Width
- Length(p
.Name
) * nW
) div 2;
341 indY
:= fY
- nH
+ fSlope
;
342 e_TextureFontPrintEx(indX
, indY
, p
.Name
, gStdFont
, Color
.R
, Color
.G
, Color
.B
, 1.0, True);
348 procedure r_Player_DrawBubble (p
: TPlayer
);
350 bubX
, bubY
, fX
, fY
: Integer;
353 Rw
, Gw
, Bw
: SmallInt;
357 {$IFDEF ENABLE_CORPSES}
358 CObj
:= g_Corpses_GetCameraObj(p
);
362 CObj
.lerp(gLerpFactor
, fX
, fY
);
363 // NB: _F_Obj.Rect is used to keep the bubble higher; this is not a mistake
364 bubX
:= fX
+ p
.Obj
.Rect
.X
+ IfThen(p
.Direction
= TDirection
.D_LEFT
, -4, 18);
365 bubY
:= fY
+ p
.Obj
.Rect
.Y
- 18;
373 1: // simple textual non-bubble
375 bubX
:= fX
+ p
.Obj
.Rect
.X
- 11;
376 bubY
:= fY
+ p
.Obj
.Rect
.Y
- 17;
377 e_TextureFontPrint(bubX
, bubY
, '[...]', gStdFont
);
380 2: // advanced pixel-perfect bubble
382 if p
.Team
= TEAM_RED
then
385 if p
.Team
= TEAM_BLUE
then
390 Rb
:= p
.Model
.Color
.R
;
391 Gb
:= p
.Model
.Color
.G
;
392 Bb
:= p
.Model
.Color
.B
;
393 Rw
:= Min(Rb
* 2 + 64, 255);
394 Gw
:= Min(Gb
* 2 + 64, 255);
395 Bw
:= Min(Bb
* 2 + 64, 255);
396 if (Abs(Rw
- Rb
) < 32)
397 or (Abs(Gw
- Gb
) < 32)
398 or (Abs(Bw
- Bb
) < 32) then
400 Rb
:= Max(Rw
div 2 - 16, 0);
401 Gb
:= Max(Gw
div 2 - 16, 0);
402 Bb
:= Max(Bw
div 2 - 16, 0);
405 4: // custom textured bubble
407 if g_Texture_Get('TEXTURE_PLAYER_TALKBUBBLE', ID
) then
408 if p
.Direction
= TDirection
.D_RIGHT
then
409 e_Draw(ID
, bubX
- 6, bubY
- 7, 0, True, False)
411 e_Draw(ID
, bubX
- 6, bubY
- 7, 0, True, False, TMirrorType
.Horizontal
);
417 e_DrawQuad(bubX
+ 1, bubY
, bubX
+ 18, bubY
+ 13, Rb
, Gb
, Bb
);
418 e_DrawQuad(bubX
, bubY
+ 1, bubX
+ 19, bubY
+ 12, Rb
, Gb
, Bb
);
420 e_DrawFillQuad(bubX
+ 1, bubY
+ 1, bubX
+ 18, bubY
+ 12, Rw
, Gw
, Bw
, 0);
423 Dot
:= IfThen(p
.Direction
= TDirection
.D_LEFT
, 14, 5);
424 e_DrawLine(1, bubX
+ Dot
, bubY
+ 14, bubX
+ Dot
, bubY
+ 16, Rb
, Gb
, Bb
);
425 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
);
426 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
);
427 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
);
428 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
);
432 e_DrawFillQuad(bubX
+ Dot
, bubY
+ 8, bubX
+ Dot
+ 1, bubY
+ 9, Rb
, Gb
, Bb
, 0);
433 e_DrawFillQuad(bubX
+ Dot
+ 3, bubY
+ 8, bubX
+ Dot
+ 4, bubY
+ 9, Rb
, Gb
, Bb
, 0);
434 e_DrawFillQuad(bubX
+ Dot
+ 6, bubY
+ 8, bubX
+ Dot
+ 7, bubY
+ 9, Rb
, Gb
, Bb
, 0);
437 procedure r_Player_Draw (p
: TPlayer
);
443 fX
, fY
, fSlope
: Integer;
445 p
.Obj
.lerp(gLerpFactor
, fX
, fY
);
446 fSlope
:= nlerp(p
.SlopeOld
, p
.Obj
.slopeUpLeft
, gLerpFactor
);
450 if p
.Direction
= TDirection
.D_RIGHT
then
451 Mirror
:= TMirrorType
.None
453 Mirror
:= TMirrorType
.Horizontal
;
455 if p
.PunchAnim
.IsValid() and p
.PunchAnim
.enabled
then
457 if p
.FKeys
[KEY_DOWN
].Pressed
then ID
:= PunchFrames
[R_BERSERK
in p
.FRulez
, 2]
458 else if p
.FKeys
[KEY_UP
].Pressed
then ID
:= PunchFrames
[R_BERSERK
in p
.FRulez
, 1]
459 else ID
:= PunchFrames
[R_BERSERK
in p
.FRulez
, 0];
460 r_AnimState_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);
463 if (p
.FMegaRulez
[MR_INVUL
] > gTime
) and ((gPlayerDrawn
<> p
) or (p
.SpawnInvul
>= gTime
)) then
464 if g_Texture_Get('TEXTURE_PLAYER_INVULPENTA', ID
) then
466 e_GetTextureSize(ID
, @w
, @h
);
467 if p
.Direction
= TDirection
.D_LEFT
then
468 e_Draw(ID
, fX
+ p
.Obj
.Rect
.X
+ (p
.Obj
.Rect
.Width
div 2) - (w
div 2) + 4,
469 fY
+ p
.Obj
.Rect
.Y
+ (p
.Obj
.Rect
.Height
div 2) - (h
div 2) - 7 + fSlope
, 0, True, False)
471 e_Draw(ID
, fX
+ p
.Obj
.Rect
.X
+ (p
.Obj
.Rect
.Width
div 2) - (w
div 2) - 2,
472 fY
+ p
.Obj
.Rect
.Y
+ (p
.Obj
.Rect
.Height
div 2) - (h
div 2) - 7 + fSlope
, 0, True, False)
475 if p
.FMegaRulez
[MR_INVIS
] > gTime
then
477 if (gPlayerDrawn
<> nil) and ((p
= gPlayerDrawn
) or
478 ((p
.Team
= gPlayerDrawn
.Team
) and (gGameSettings
.GameMode
<> GM_DM
))) then
480 if (p
.FMegaRulez
[MR_INVIS
] - gTime
) <= 2100 then
481 dr
:= not Odd((p
.FMegaRulez
[MR_INVIS
] - gTime
) div 300)
485 r_PlayerModel_Draw(p
.Model
, fX
, fY
+ fSlope
, 200)
487 r_PlayerModel_Draw(p
.Model
, fX
, fY
+ fSlope
);
490 r_PlayerModel_Draw(p
.Model
, fX
, fY
+ fSlope
, 254);
493 r_PlayerModel_Draw(p
.Model
, fX
, fY
+ fSlope
);
496 if g_debug_Frames
then
498 e_DrawQuad(p
.Obj
.X
+ p
.Obj
.Rect
.X
,
499 p
.Obj
.Y
+ p
.Obj
.Rect
.Y
,
500 p
.Obj
.X
+ p
.Obj
.Rect
.X
+ p
.Obj
.Rect
.Width
- 1,
501 p
.Obj
.Y
+ p
.Obj
.Rect
.Y
+ p
.Obj
.Rect
.Height
- 1,
505 if (gChatBubble
> 0) and (p
.FKeys
[KEY_CHAT
].Pressed
) and not p
.Ghost
then
506 if (p
.FMegaRulez
[MR_INVIS
] <= gTime
) or ((gPlayerDrawn
<> nil) and ((p
= gPlayerDrawn
) or
507 ((p
.Team
= gPlayerDrawn
.Team
) and (gGameSettings
.GameMode
<> GM_DM
)))) then
508 r_Player_DrawBubble(p
);
510 // e_DrawPoint(5, 335, 288, 255, 0, 0); // DL, UR, DL, UR
511 if gAimLine
and p
.Alive
and ((p
= gPlayer1
) or (p
= gPlayer2
)) then
515 procedure r_Player_DrawAim (p
: TPlayer
);
517 procedure drawCast (sz
: Integer; ax0
, ay0
, ax1
, ay1
: Integer);
522 {$IFDEF ENABLE_HOLMES}
523 if p
.isValidViewPort() and (p
= gPlayer1
) then
525 g_Holmes_plrLaser(ax0
, ay0
, ax1
, ay1
);
529 e_DrawLine(sz
, ax0
, ay0
, ax1
, ay1
, 255, 0, 0, 96);
530 if (g_Map_traceToNearestWall(ax0
, ay0
, ax1
, ay1
, @ex
, @ey
) <> nil) then
532 e_DrawLine(sz
, ax0
, ay0
, ex
, ey
, 0, 255, 0, 96);
536 e_DrawLine(sz
, ax0
, ay0
, ex
, ey
, 0, 0, 255, 96);
541 wx
, wy
, xx
, yy
: Integer;
545 wx
:= p
.Obj
.X
+ WEAPONPOINT
[p
.Direction
].X
+ IfThen(p
.Direction
= TDirection
.D_LEFT
, 7, -7);
546 wy
:= p
.Obj
.Y
+ WEAPONPOINT
[p
.Direction
].Y
;
562 if angle
= ANGLE_RIGHTUP
then Dec(angle
, 2);
563 if angle
= ANGLE_RIGHTDOWN
then Inc(angle
, 4);
564 if angle
= ANGLE_LEFTUP
then Inc(angle
, 2);
565 if angle
= ANGLE_LEFTDOWN
then Dec(angle
, 4);
570 if angle
= ANGLE_RIGHTUP
then Dec(angle
, 2);
571 if angle
= ANGLE_RIGHTDOWN
then Inc(angle
, 4);
572 if angle
= ANGLE_LEFTUP
then Inc(angle
, 2);
573 if angle
= ANGLE_LEFTDOWN
then Dec(angle
, 4);
575 4: begin // Double Shotgun
578 if angle
= ANGLE_RIGHTUP
then Dec(angle
, 2);
579 if angle
= ANGLE_RIGHTDOWN
then Inc(angle
, 4);
580 if angle
= ANGLE_LEFTUP
then Inc(angle
, 2);
581 if angle
= ANGLE_LEFTDOWN
then Dec(angle
, 4);
586 if angle
= ANGLE_RIGHTUP
then Dec(angle
, 2);
587 if angle
= ANGLE_RIGHTDOWN
then Inc(angle
, 4);
588 if angle
= ANGLE_LEFTUP
then Inc(angle
, 2);
589 if angle
= ANGLE_LEFTDOWN
then Dec(angle
, 4);
591 6: begin // Rocket Launcher
594 if angle
= ANGLE_RIGHTUP
then Inc(angle
, 2);
595 if angle
= ANGLE_RIGHTDOWN
then Inc(angle
, 4);
596 if angle
= ANGLE_LEFTUP
then Dec(angle
, 2);
597 if angle
= ANGLE_LEFTDOWN
then Dec(angle
, 4);
599 7: begin // Plasmagun
602 if angle
= ANGLE_RIGHTUP
then Inc(angle
);
603 if angle
= ANGLE_RIGHTDOWN
then Inc(angle
, 3);
604 if angle
= ANGLE_LEFTUP
then Dec(angle
);
605 if angle
= ANGLE_LEFTDOWN
then Dec(angle
, 3);
610 if angle
= ANGLE_RIGHTUP
then Inc(angle
, 1);
611 if angle
= ANGLE_RIGHTDOWN
then Inc(angle
, 2);
612 if angle
= ANGLE_LEFTUP
then Dec(angle
, 1);
613 if angle
= ANGLE_LEFTDOWN
then Dec(angle
, 2);
615 9: begin // Super Chaingun
618 if angle
= ANGLE_RIGHTUP
then Dec(angle
, 2);
619 if angle
= ANGLE_RIGHTDOWN
then Inc(angle
, 4);
620 if angle
= ANGLE_LEFTUP
then Inc(angle
, 2);
621 if angle
= ANGLE_LEFTDOWN
then Dec(angle
, 4);
624 xx
:= Trunc(Cos(-DegToRad(angle
)) * len
) + wx
;
625 yy
:= Trunc(Sin(-DegToRad(angle
)) * len
) + wy
;
626 {$IF DEFINED(D2F_DEBUG)}
627 drawCast(sz
, wx
, wy
, xx
, yy
);
629 e_DrawLine(sz
, wx
, wy
, xx
, yy
, 255, 0, 0, 96);
633 procedure r_Player_DrawGUI (pl
: TPlayer
);
636 X
, Y
, SY
, a
, p
, m
: Integer;
640 stat
: TPlayerStatArray
;
642 X
:= gPlayerScreenSize
.X
;
643 SY
:= gPlayerScreenSize
.Y
;
646 if gShowScore
and (gGameSettings
.GameMode
in [GM_TDM
, GM_CTF
]) then
648 if gGameSettings
.GameMode
= GM_CTF
then
652 if gGameSettings
.GameMode
= GM_CTF
then
654 s
:= 'TEXTURE_PLAYER_REDFLAG';
655 if gFlags
[FLAG_RED
].State
= FLAG_STATE_CAPTURED
then
656 s
:= 'TEXTURE_PLAYER_REDFLAG_S';
657 if gFlags
[FLAG_RED
].State
= FLAG_STATE_DROPPED
then
658 s
:= 'TEXTURE_PLAYER_REDFLAG_D';
659 if g_Texture_Get(s
, ID
) then
660 e_Draw(ID
, X
-16-32, 240-72-4, 0, True, False);
663 s
:= IntToStr(gTeamStat
[TEAM_RED
].Score
);
664 e_CharFont_GetSize(gMenuFont
, s
, tw
, th
);
665 e_CharFont_PrintEx(gMenuFont
, X
-16-a
-tw
, 240-72-4, s
, TEAMCOLOR
[TEAM_RED
]);
667 if gGameSettings
.GameMode
= GM_CTF
then
669 s
:= 'TEXTURE_PLAYER_BLUEFLAG';
670 if gFlags
[FLAG_BLUE
].State
= FLAG_STATE_CAPTURED
then
671 s
:= 'TEXTURE_PLAYER_BLUEFLAG_S';
672 if gFlags
[FLAG_BLUE
].State
= FLAG_STATE_DROPPED
then
673 s
:= 'TEXTURE_PLAYER_BLUEFLAG_D';
674 if g_Texture_Get(s
, ID
) then
675 e_Draw(ID
, X
-16-32, 240-32-4, 0, True, False);
678 s
:= IntToStr(gTeamStat
[TEAM_BLUE
].Score
);
679 e_CharFont_GetSize(gMenuFont
, s
, tw
, th
);
680 e_CharFont_PrintEx(gMenuFont
, X
-16-a
-tw
, 240-32-4, s
, TEAMCOLOR
[TEAM_BLUE
]);
683 if g_Texture_Get('TEXTURE_PLAYER_HUDBG', ID
) then
684 e_DrawFill(ID
, X
, 0, 1, (gPlayerScreenSize
.Y
div 256)+IfThen(gPlayerScreenSize
.Y
mod 256 > 0, 1, 0),
687 if g_Texture_Get('TEXTURE_PLAYER_HUD', ID
) then
688 e_Draw(ID
, X
+2, Y
, 0, True, False);
690 if gGameSettings
.GameType
in [GT_CUSTOM
, GT_SERVER
, GT_CLIENT
] then
694 s
:= IntToStr(pl
.Frags
);
695 e_CharFont_GetSize(gMenuFont
, s
, tw
, th
);
696 e_CharFont_PrintEx(gMenuFont
, X
-16-tw
, Y
, s
, _RGB(255, 0, 0));
701 stat
:= g_Player_GetStats();
706 for a
:= 0 to High(stat
) do
707 if stat
[a
].Name
<> pl
.Name
then
709 if stat
[a
].Frags
> m
then m
:= stat
[a
].Frags
;
710 if stat
[a
].Frags
> pl
.Frags
then p
:= p
+1;
714 s
:= IntToStr(p
)+' / '+IntToStr(Length(stat
))+' ';
715 if pl
.Frags
>= m
then s
:= s
+'+' else s
:= s
+'-';
716 s
:= s
+IntToStr(Abs(pl
.Frags
-m
));
718 e_CharFont_GetSize(gMenuSmallFont
, s
, tw
, th
);
719 e_CharFont_PrintEx(gMenuSmallFont
, X
-16-tw
, Y
+32, s
, _RGB(255, 0, 0));
722 if gLMSRespawn
> LMS_RESPAWN_NONE
then
724 s
:= _lc
[I_GAME_WARMUP
];
725 e_CharFont_GetSize(gMenuFont
, s
, tw
, th
);
726 s
:= s
+ ': ' + IntToStr((gLMSRespawnTime
- gTime
) div 1000);
727 e_CharFont_PrintEx(gMenuFont
, X
-64-tw
, SY
-32, s
, _RGB(0, 255, 0));
729 else if gShowLives
and (gGameSettings
.MaxLives
> 0) then
731 s
:= IntToStr(pl
.Lives
);
732 e_CharFont_GetSize(gMenuFont
, s
, tw
, th
);
733 e_CharFont_PrintEx(gMenuFont
, X
-16-tw
, SY
-32, s
, _RGB(0, 255, 0));
737 e_CharFont_GetSize(gMenuSmallFont
, pl
.Name
, tw
, th
);
738 e_CharFont_PrintEx(gMenuSmallFont
, X
+98-(tw
div 2), Y
+8, pl
.Name
, _RGB(255, 0, 0));
740 if R_BERSERK
in pl
.FRulez
then
741 e_Draw(gItemsTexturesID
[ITEM_MEDKIT_BLACK
], X
+37, Y
+45, 0, True, False)
743 e_Draw(gItemsTexturesID
[ITEM_MEDKIT_LARGE
], X
+37, Y
+45, 0, True, False);
745 if g_Texture_Get('TEXTURE_PLAYER_ARMORHUD', ID
) then
746 e_Draw(ID
, X
+36, Y
+77, 0, True, False);
748 s
:= IntToStr(IfThen(pl
.Health
> 0, pl
.Health
, 0));
749 e_CharFont_GetSize(gMenuFont
, s
, tw
, th
);
750 e_CharFont_PrintEx(gMenuFont
, X
+178-tw
, Y
+40, s
, _RGB(255, 0, 0));
752 s
:= IntToStr(pl
.Armor
);
753 e_CharFont_GetSize(gMenuFont
, s
, tw
, th
);
754 e_CharFont_PrintEx(gMenuFont
, X
+178-tw
, Y
+68, s
, _RGB(255, 0, 0));
756 s
:= IntToStr(pl
.GetAmmoByWeapon(pl
.CurrWeap
));
762 ID
:= gItemsTexturesID
[ITEM_WEAPON_KASTET
];
767 ID
:= gItemsTexturesID
[ITEM_WEAPON_SAW
];
769 WEAPON_PISTOL
: ID
:= gItemsTexturesID
[ITEM_WEAPON_PISTOL
];
770 WEAPON_CHAINGUN
: ID
:= gItemsTexturesID
[ITEM_WEAPON_CHAINGUN
];
771 WEAPON_SHOTGUN1
: ID
:= gItemsTexturesID
[ITEM_WEAPON_SHOTGUN1
];
772 WEAPON_SHOTGUN2
: ID
:= gItemsTexturesID
[ITEM_WEAPON_SHOTGUN2
];
773 WEAPON_SUPERPULEMET
: ID
:= gItemsTexturesID
[ITEM_WEAPON_SUPERPULEMET
];
774 WEAPON_ROCKETLAUNCHER
: ID
:= gItemsTexturesID
[ITEM_WEAPON_ROCKETLAUNCHER
];
775 WEAPON_PLASMA
: ID
:= gItemsTexturesID
[ITEM_WEAPON_PLASMA
];
776 WEAPON_BFG
: ID
:= gItemsTexturesID
[ITEM_WEAPON_BFG
];
777 WEAPON_FLAMETHROWER
: ID
:= gItemsTexturesID
[ITEM_WEAPON_FLAMETHROWER
];
780 e_CharFont_GetSize(gMenuFont
, s
, tw
, th
);
781 e_CharFont_PrintEx(gMenuFont
, X
+178-tw
, Y
+158, s
, _RGB(255, 0, 0));
782 e_Draw(ID
, X
+20, Y
+160, 0, True, False);
784 if R_KEY_RED
in pl
.FRulez
then
785 e_Draw(gItemsTexturesID
[ITEM_KEY_RED
], X
+78, Y
+214, 0, True, False);
787 if R_KEY_GREEN
in pl
.FRulez
then
788 e_Draw(gItemsTexturesID
[ITEM_KEY_GREEN
], X
+95, Y
+214, 0, True, False);
790 if R_KEY_BLUE
in pl
.FRulez
then
791 e_Draw(gItemsTexturesID
[ITEM_KEY_BLUE
], X
+112, Y
+214, 0, True, False);
793 if pl
.JetFuel
> 0 then
795 if g_Texture_Get('TEXTURE_PLAYER_HUDAIR', ID
) then
796 e_Draw(ID
, X
+2, Y
+116, 0, True, False);
797 if g_Texture_Get('TEXTURE_PLAYER_HUDJET', ID
) then
798 e_Draw(ID
, X
+2, Y
+126, 0, True, False);
799 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);
800 e_DrawLine(4, X
+16, Y
+132, X
+16+Trunc(168*pl
.JetFuel
/JET_MAX
), Y
+132, 208, 0, 0);
804 if g_Texture_Get('TEXTURE_PLAYER_HUDAIR', ID
) then
805 e_Draw(ID
, X
+2, Y
+124, 0, True, False);
806 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);
809 if gShowPing
and g_Game_IsClient
then
811 s
:= _lc
[I_GAME_PING_HUD
] + IntToStr(NetPeer
.lastRoundTripTime
) + _lc
[I_NET_SLIST_PING_MS
];
812 e_TextureFontPrint(X
+ 4, Y
+ 242, s
, gStdFont
);
818 e_TextureFontPrint(X
+ 4, Y
+ 242, _lc
[I_PLAYER_SPECT
], gStdFont
);
819 e_TextureFontPrint(X
+ 4, Y
+ 258, _lc
[I_PLAYER_SPECT2
], gStdFont
);
820 e_TextureFontPrint(X
+ 4, Y
+ 274, _lc
[I_PLAYER_SPECT1
], gStdFont
);
823 e_TextureFontGetSize(gStdFont
, cw
, ch
);
824 s
:= _lc
[I_PLAYER_SPECT4
];
825 e_TextureFontPrintEx(gScreenWidth
div 2 - cw
*(Length(s
) div 2),
826 gScreenHeight
-4-ch
, s
, gStdFont
, 255, 255, 255, 1, True);
827 e_TextureFontPrint(X
+ 4, Y
+ 290, _lc
[I_PLAYER_SPECT1S
], gStdFont
);
833 procedure r_Player_DrawRulez (p
: TPlayer
);
837 // При взятии неуязвимости рисуется инверсионный белый фон
838 if (p
.FMegaRulez
[MR_INVUL
] >= gTime
) and (p
.SpawnInvul
< gTime
) then
840 if (p
.FMegaRulez
[MR_INVUL
]-gTime
) <= 2100 then
841 dr
:= not Odd((p
.FMegaRulez
[MR_INVUL
]-gTime
) div 300)
846 e_DrawFillQuad(0, 0, gPlayerScreenSize
.X
-1, gPlayerScreenSize
.Y
-1,
847 191, 191, 191, 0, TBlending
.Invert
);
850 // При взятии защитного костюма рисуется зеленоватый фон
851 if p
.FMegaRulez
[MR_SUIT
] >= gTime
then
853 if (p
.FMegaRulez
[MR_SUIT
]-gTime
) <= 2100 then
854 dr
:= not Odd((p
.FMegaRulez
[MR_SUIT
]-gTime
) div 300)
859 e_DrawFillQuad(0, 0, gPlayerScreenSize
.X
-1, gPlayerScreenSize
.Y
-1,
860 0, 96, 0, 200, TBlending
.None
);
863 // При взятии берсерка рисуется красноватый фон
864 if (p
.Berserk
>= 0) and (LongWord(p
.Berserk
) >= gTime
) and (gFlash
= 2) then
866 e_DrawFillQuad(0, 0, gPlayerScreenSize
.X
-1, gPlayerScreenSize
.Y
-1,
867 255, 0, 0, 200, TBlending
.None
);
871 procedure r_Player_DrawPain (p
: TPlayer
);
875 if p
.Pain
= 0 then Exit
;
879 if a
< 15 then h
:= 0
880 else if a
< 35 then h
:= 1
881 else if a
< 55 then h
:= 2
882 else if a
< 75 then h
:= 3
883 else if a
< 95 then h
:= 4
886 //if a > 255 then a := 255;
888 e_DrawFillQuad(0, 0, gPlayerScreenSize
.X
-1, gPlayerScreenSize
.Y
-1, 255, 0, 0, 255-h
*50);
889 //e_DrawFillQuad(0, 0, gPlayerScreenSize.X-1, gPlayerScreenSize.Y-1, 255-min(128, a), 255-a, 255-a, 0, B_FILTER);
892 procedure r_Player_DrawPickup (p
: TPlayer
);
896 if p
.Pickup
= 0 then Exit
;
900 if a
< 15 then h
:= 1
901 else if a
< 35 then h
:= 2
902 else if a
< 55 then h
:= 3
903 else if a
< 75 then h
:= 4
906 e_DrawFillQuad(0, 0, gPlayerScreenSize
.X
-1, gPlayerScreenSize
.Y
-1, 150, 200, 150, 255-h
*50);