Preserve stage-1 stability fixes alongside v5 lighting, IPC v2, weapons and studio updates. Fix barrel AOE pointer corruption and extend modal gameplay gating. Verify 137 editor checks, 191 ASM checks, lighting bake and preview parity. Document stage-2 scope without implementing it.
734 lines
19 KiB
PHP
734 lines
19 KiB
PHP
; ==============================================================================
|
|
; EBLAN ENGINE - Player Combat, Multi-Weapon Arsenal & Combat HUD
|
|
; ==============================================================================
|
|
|
|
.code
|
|
|
|
DrawPixel PROTO :DWORD, :DWORD, :DWORD
|
|
DrawRect PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
|
|
DrawRectOutline PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
|
|
DrawString8x8 PROTO :DWORD, :DWORD, :DWORD, :DWORD
|
|
DrawNumber8x8 PROTO :DWORD, :DWORD, :DWORD, :DWORD
|
|
ShowGameToast PROTO :DWORD, :DWORD, :DWORD
|
|
Game_OnEntityKilled PROTO :DWORD, :DWORD
|
|
|
|
; Trace the current world along the player's forward direction. EAX = first
|
|
; blocking boundary in 24.8 world units. Glass blocks shots (unlike rendering).
|
|
; No framebuffer/depth-buffer dependencies. Out-of-map cells are solid.
|
|
TraceShotWall PROC uses ebx ecx edx esi edi
|
|
LOCAL cellX:DWORD, cellY:DWORD, stepX:DWORD, stepY:DWORD
|
|
LOCAL deltaX:DWORD, deltaY:DWORD, sideX:DWORD, sideY:DWORD
|
|
LOCAL hitDistance:DWORD, remaining:DWORD
|
|
|
|
mov eax, playerX
|
|
sar eax, 6
|
|
mov cellX, eax
|
|
mov eax, playerY
|
|
sar eax, 6
|
|
mov cellY, eax
|
|
invoke GetMapCell, cellX, cellY
|
|
invoke IsSolidCell, eax
|
|
test eax, eax
|
|
jnz shot_wall_at_origin
|
|
|
|
mov eax, playerAngle
|
|
and eax, ANGLE_MASK
|
|
mov esi, [tableCos+eax*4]
|
|
mov edi, [tableSin+eax*4]
|
|
mov deltaX, 3FFFFFFFh
|
|
mov sideX, 3FFFFFFFh
|
|
mov stepX, 1
|
|
test esi, esi
|
|
jz shot_setup_y
|
|
mov eax, esi
|
|
cdq
|
|
xor eax, edx
|
|
sub eax, edx
|
|
mov ecx, eax
|
|
mov eax, (64 shl 24)
|
|
xor edx, edx
|
|
div ecx
|
|
mov deltaX, eax
|
|
mov eax, playerX
|
|
and eax, 63
|
|
test esi, esi
|
|
js shot_negative_x
|
|
neg eax
|
|
add eax, 64
|
|
jmp shot_side_x
|
|
shot_negative_x:
|
|
mov stepX, -1
|
|
shot_side_x:
|
|
imul deltaX
|
|
shrd eax, edx, 6
|
|
mov sideX, eax
|
|
shot_setup_y:
|
|
mov deltaY, 3FFFFFFFh
|
|
mov sideY, 3FFFFFFFh
|
|
mov stepY, 1
|
|
test edi, edi
|
|
jz shot_traverse_start
|
|
mov eax, edi
|
|
cdq
|
|
xor eax, edx
|
|
sub eax, edx
|
|
mov ecx, eax
|
|
mov eax, (64 shl 24)
|
|
xor edx, edx
|
|
div ecx
|
|
mov deltaY, eax
|
|
mov eax, playerY
|
|
and eax, 63
|
|
test edi, edi
|
|
js shot_negative_y
|
|
neg eax
|
|
add eax, 64
|
|
jmp shot_side_y
|
|
shot_negative_y:
|
|
mov stepY, -1
|
|
shot_side_y:
|
|
imul deltaY
|
|
shrd eax, edx, 6
|
|
mov sideY, eax
|
|
shot_traverse_start:
|
|
mov remaining, MAP_W+MAP_H+2
|
|
shot_traverse:
|
|
mov eax, sideX
|
|
cmp eax, sideY
|
|
jb shot_step_x
|
|
jne shot_step_y
|
|
; At a corner also test the X-adjacent cell: no shots through wall seams.
|
|
mov ebx, cellX
|
|
add ebx, stepX
|
|
invoke GetMapCell, ebx, cellY
|
|
invoke IsSolidCell, eax
|
|
test eax, eax
|
|
jz shot_step_y
|
|
mov eax, sideX
|
|
ret
|
|
shot_step_x:
|
|
mov hitDistance, eax
|
|
add eax, deltaX
|
|
mov sideX, eax
|
|
mov eax, stepX
|
|
add cellX, eax
|
|
jmp shot_test_cell
|
|
shot_step_y:
|
|
mov eax, sideY
|
|
mov hitDistance, eax
|
|
add eax, deltaY
|
|
mov sideY, eax
|
|
mov eax, stepY
|
|
add cellY, eax
|
|
shot_test_cell:
|
|
invoke GetMapCell, cellX, cellY
|
|
invoke IsSolidCell, eax
|
|
test eax, eax
|
|
jnz shot_wall_found
|
|
dec remaining
|
|
jnz shot_traverse
|
|
; Defensive bound: a valid ray exits a 32x32 map within 64 crossings.
|
|
shot_wall_found:
|
|
mov eax, hitDistance
|
|
ret
|
|
shot_wall_at_origin:
|
|
xor eax, eax
|
|
ret
|
|
TraceShotWall ENDP
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; UpdateCombat: Process weapon firing, hitscan raycasting, cooldowns & damage
|
|
; ------------------------------------------------------------------------------
|
|
UpdateCombat PROC uses ebx ecx edx esi edi
|
|
LOCAL camCos:DWORD, camSin:DWORD
|
|
LOCAL i:DWORD, closestIdx:DWORD, closestDist:DWORD
|
|
LOCAL sprX:DWORD, sprY:DWORD
|
|
LOCAL transX:DWORD, transY:DWORD
|
|
LOCAL targetHalfWidth:DWORD, wallDepth:DWORD
|
|
LOCAL weaponDamage:DWORD, maxHitDist:DWORD, hitHalfWidth:DWORD
|
|
|
|
call IsGameplayBlocked
|
|
test eax, eax
|
|
jnz combat_done
|
|
|
|
; 1. Decrement cooldowns
|
|
cmp playerAttackCooldown, 0
|
|
je @F
|
|
dec playerAttackCooldown
|
|
@@:
|
|
cmp playerFlashTimer, 0
|
|
je @F
|
|
dec playerFlashTimer
|
|
@@:
|
|
cmp playerHitFlash, 0
|
|
je @F
|
|
dec playerHitFlash
|
|
@@:
|
|
|
|
; If player is dead, game is paused, or in peaceful adventure mode, cannot attack
|
|
cmp isPlayerDead, 0
|
|
jne combat_done
|
|
cmp isGamePaused, 0
|
|
jne combat_done
|
|
cmp gameMode, GAME_MODE_ADVENTURE
|
|
je combat_done
|
|
cmp enableWeapons, 0
|
|
je combat_done
|
|
cmp playerWeapon, WEAPON_NONE
|
|
je combat_done
|
|
|
|
; 2. Check attack input
|
|
cmp keyAttack, 0
|
|
je combat_done
|
|
cmp playerAttackCooldown, 0
|
|
jne combat_done
|
|
|
|
; Set weapon parameters based on playerWeapon
|
|
mov weaponDamage, 35
|
|
mov maxHitDist, 999999
|
|
mov hitHalfWidth, 16
|
|
|
|
cmp playerWeapon, WEAPON_KNIFE
|
|
je setup_knife
|
|
cmp playerWeapon, WEAPON_SHOTGUN
|
|
je setup_shotgun
|
|
jmp setup_pistol
|
|
|
|
setup_knife:
|
|
; Knife: no ammo needed, close range (within 64 units = 1 cell), fast cooldown
|
|
mov weaponDamage, 30
|
|
mov maxHitDist, 64
|
|
mov hitHalfWidth, 24
|
|
mov playerAttackCooldown, 8
|
|
mov playerFlashTimer, 3
|
|
jmp fire_hitscan
|
|
|
|
setup_shotgun:
|
|
; Shotgun: needs 2 ammo, high damage (70), wider world hitbox, long cooldown
|
|
cmp playerAmmo, 2
|
|
jl combat_dry_fire
|
|
sub playerAmmo, 2
|
|
mov weaponDamage, 70
|
|
mov maxHitDist, 999999
|
|
mov hitHalfWidth, 32
|
|
mov playerAttackCooldown, 22
|
|
mov playerFlashTimer, 7
|
|
invoke SpawnMuzzleFlashLight, playerX, playerY
|
|
jmp fire_hitscan
|
|
|
|
setup_pistol:
|
|
; Pistol: needs 1 ammo, accurate world hitbox, medium cooldown (12)
|
|
cmp playerAmmo, 1
|
|
jl combat_dry_fire
|
|
dec playerAmmo
|
|
mov weaponDamage, 35
|
|
mov maxHitDist, 999999
|
|
mov hitHalfWidth, 16
|
|
mov playerAttackCooldown, 12
|
|
mov playerFlashTimer, 5
|
|
invoke SpawnMuzzleFlashLight, playerX, playerY
|
|
|
|
fire_hitscan:
|
|
; 3. Hitscan check against enemies & destructible barrels in crosshair
|
|
; Camera basis for -playerAngle
|
|
mov eax, ANGLE_512
|
|
sub eax, playerAngle
|
|
and eax, ANGLE_MASK
|
|
mov ecx, [tableCos + eax*4]
|
|
mov camCos, ecx
|
|
mov edx, [tableSin + eax*4]
|
|
mov camSin, edx
|
|
|
|
; Query current geometry, never the previous rendered frame.
|
|
call TraceShotWall
|
|
mov wallDepth, eax
|
|
|
|
mov closestIdx, -1
|
|
mov closestDist, 999999
|
|
|
|
mov i, 0
|
|
hitscan_loop:
|
|
mov eax, i
|
|
cmp eax, spriteCount
|
|
jge hitscan_eval
|
|
|
|
mov ecx, i
|
|
mov eax, [entityType + ecx*4]
|
|
|
|
; Check if Guard or Barrel
|
|
cmp eax, ENTITY_TYPE_GUARD
|
|
je hitscan_target_valid
|
|
cmp eax, ENTITY_TYPE_BARREL
|
|
je hitscan_target_valid
|
|
|
|
jmp next_hitscan_target
|
|
|
|
hitscan_target_valid:
|
|
mov eax, [entityState + ecx*4]
|
|
cmp eax, ENTITY_STATE_DEAD
|
|
je next_hitscan_target
|
|
|
|
mov ebx, i
|
|
imul ebx, sizeof SpriteStruct
|
|
add ebx, OFFSET spriteList
|
|
|
|
mov eax, [ebx].SpriteStruct.textureId
|
|
test eax, eax
|
|
jz next_hitscan_target
|
|
|
|
; Transform to camera space
|
|
mov eax, [ebx].SpriteStruct.x
|
|
sub eax, playerX
|
|
mov sprX, eax
|
|
|
|
mov eax, [ebx].SpriteStruct.y
|
|
sub eax, playerY
|
|
mov sprY, eax
|
|
|
|
; transY = sprX * camCos - sprY * camSin
|
|
mov eax, sprX
|
|
imul camCos
|
|
shrd eax, edx, 16
|
|
mov ecx, eax
|
|
mov eax, sprY
|
|
imul camSin
|
|
shrd eax, edx, 16
|
|
sub ecx, eax
|
|
mov transY, ecx
|
|
|
|
; Must be in front of player
|
|
cmp transY, 16
|
|
jle next_hitscan_target
|
|
|
|
; Must be closer than maximum weapon hit distance
|
|
mov eax, transY
|
|
cmp eax, maxHitDist
|
|
jg next_hitscan_target
|
|
|
|
; Compare in 24.8 so a target on a wall boundary is not hit through it.
|
|
mov eax, transY
|
|
shl eax, 8
|
|
cmp eax, wallDepth
|
|
jge next_hitscan_target
|
|
|
|
; transX = sprX * camSin + sprY * camCos
|
|
mov eax, sprX
|
|
imul camSin
|
|
shrd eax, edx, 16
|
|
mov ecx, eax
|
|
mov eax, sprY
|
|
imul camCos
|
|
shrd eax, edx, 16
|
|
add ecx, eax
|
|
mov transX, ecx
|
|
|
|
; World-space billboard hitbox: weapon-specific width, scaled with
|
|
; the authored sprite, never with screen distance. Zero means legacy 1.0.
|
|
mov eax, [ebx].SpriteStruct.scale
|
|
test eax, eax
|
|
jnz @F
|
|
mov eax, FIXED_ONE
|
|
@@:
|
|
imul eax, hitHalfWidth
|
|
sar eax, 16
|
|
mov targetHalfWidth, eax
|
|
mov eax, transX
|
|
cdq
|
|
xor eax, edx
|
|
sub eax, edx
|
|
cmp eax, targetHalfWidth
|
|
jg next_hitscan_target
|
|
|
|
; Check if closer than previous target
|
|
mov eax, transY
|
|
cmp eax, closestDist
|
|
jge next_hitscan_target
|
|
mov closestDist, eax
|
|
mov eax, i
|
|
mov closestIdx, eax
|
|
|
|
next_hitscan_target:
|
|
inc i
|
|
jmp hitscan_loop
|
|
|
|
hitscan_eval:
|
|
cmp closestIdx, -1
|
|
je combat_done
|
|
|
|
mov ecx, closestIdx
|
|
mov eax, [entityType + ecx*4]
|
|
|
|
; Check if hit an explosive barrel!
|
|
cmp eax, ENTITY_TYPE_BARREL
|
|
je explode_barrel
|
|
; Hit an enemy guard!
|
|
mov eax, [entityHealth + ecx*4]
|
|
sub eax, weaponDamage
|
|
jns @F
|
|
xor eax, eax
|
|
@@:
|
|
mov [entityHealth + ecx*4], eax
|
|
test eax, eax
|
|
jnz combat_done
|
|
|
|
; Guard died!
|
|
mov [entityState + ecx*4], ENTITY_STATE_DEAD
|
|
mov DWORD PTR [entityTimer + ecx*4], 0
|
|
add playerScore, 100
|
|
invoke Game_OnEntityKilled, closestIdx, ENTITY_TYPE_GUARD
|
|
|
|
; Drop ammo reward
|
|
mov eax, playerAmmo
|
|
add eax, 10
|
|
cmp eax, playerMaxAmmo
|
|
jle @F
|
|
mov eax, playerMaxAmmo
|
|
@@:
|
|
mov playerAmmo, eax
|
|
jmp combat_done
|
|
|
|
explode_barrel:
|
|
; Exploding Barrel: Destroy barrel and trigger AOE blast!
|
|
mov [entityState + ecx*4], ENTITY_STATE_DEAD
|
|
mov ebx, closestIdx
|
|
imul ebx, sizeof SpriteStruct
|
|
add ebx, OFFSET spriteList
|
|
mov [ebx].SpriteStruct.textureId, 0 ; disappear
|
|
|
|
; Fiery orange-red screen flash
|
|
mov playerHitFlash, 8
|
|
add playerScore, 200
|
|
invoke ShowGameToast, OFFSET szBarrelExplodedToast, 60, 00FFA020h
|
|
invoke Game_OnEntityKilled, closestIdx, ENTITY_TYPE_BARREL
|
|
|
|
; AOE damage to all surrounding guards within 128 units (2 cells)
|
|
push esi
|
|
push edi
|
|
mov esi, [ebx].SpriteStruct.x
|
|
mov edi, [ebx].SpriteStruct.y
|
|
invoke SpawnExplosionLight, esi, edi
|
|
|
|
mov i, 0
|
|
aoe_loop:
|
|
mov eax, i
|
|
cmp eax, spriteCount
|
|
jge aoe_check_player
|
|
|
|
mov ecx, i
|
|
cmp ecx, closestIdx
|
|
je next_aoe
|
|
|
|
mov eax, [entityType + ecx*4]
|
|
cmp eax, ENTITY_TYPE_GUARD
|
|
jne next_aoe
|
|
cmp [entityState + ecx*4], ENTITY_STATE_DEAD
|
|
je next_aoe
|
|
|
|
; EDX is volatile scratch for CDQ below, not a safe sprite pointer.
|
|
mov ebx, i
|
|
imul ebx, sizeof SpriteStruct
|
|
add ebx, OFFSET spriteList
|
|
|
|
mov eax, [ebx].SpriteStruct.x
|
|
sub eax, esi
|
|
cdq
|
|
xor eax, edx
|
|
sub eax, edx
|
|
cmp eax, 128
|
|
jg next_aoe
|
|
|
|
mov eax, [ebx].SpriteStruct.y
|
|
sub eax, edi
|
|
cdq
|
|
xor eax, edx
|
|
sub eax, edx
|
|
cmp eax, 128
|
|
jg next_aoe
|
|
|
|
; Within blast: deal 60 blast damage!
|
|
mov eax, [entityHealth + ecx*4]
|
|
sub eax, 60
|
|
jns @F
|
|
xor eax, eax
|
|
@@:
|
|
mov [entityHealth + ecx*4], eax
|
|
test eax, eax
|
|
jnz next_aoe
|
|
|
|
mov [entityState + ecx*4], ENTITY_STATE_DEAD
|
|
add playerScore, 150
|
|
|
|
next_aoe:
|
|
inc i
|
|
jmp aoe_loop
|
|
|
|
aoe_check_player:
|
|
; If player was standing too close to the barrel (< 96 units), player takes blast damage!
|
|
mov eax, playerX
|
|
sub eax, esi
|
|
cdq
|
|
xor eax, edx
|
|
sub eax, edx
|
|
cmp eax, 96
|
|
jg aoe_done
|
|
|
|
mov eax, playerY
|
|
sub eax, edi
|
|
cdq
|
|
xor eax, edx
|
|
sub eax, edx
|
|
cmp eax, 96
|
|
jg aoe_done
|
|
|
|
; Player blast damage
|
|
mov eax, playerHealth
|
|
sub eax, 25
|
|
jns @F
|
|
xor eax, eax
|
|
@@:
|
|
mov playerHealth, eax
|
|
test eax, eax
|
|
jnz aoe_done
|
|
mov isPlayerDead, 1
|
|
|
|
aoe_done:
|
|
pop edi
|
|
pop esi
|
|
jmp combat_done
|
|
|
|
combat_dry_fire:
|
|
mov playerAttackCooldown, 12
|
|
|
|
combat_done:
|
|
ret
|
|
UpdateCombat ENDP
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; RenderCombatHUD: Renders health bar, ammo, crosshair, weapon & death screen
|
|
; ------------------------------------------------------------------------------
|
|
RenderCombatHUD PROC uses ebx ecx edx esi edi
|
|
LOCAL barW:DWORD, gunY:DWORD
|
|
|
|
; If in adventure mode, unarmed, or weapons disabled, skip weapon & combat stats
|
|
cmp gameMode, GAME_MODE_ADVENTURE
|
|
je hud_damage_flash
|
|
cmp enableWeapons, 0
|
|
je hud_damage_flash
|
|
cmp playerWeapon, WEAPON_NONE
|
|
je hud_damage_flash
|
|
|
|
; 1. Center Crosshair (subtle cross at 160, 120)
|
|
cmp showCrosshair, 0
|
|
je skip_crosshair
|
|
invoke DrawRect, 156, 120, 9, 1, 00FFFFFFh
|
|
invoke DrawRect, 160, 116, 1, 9, 00FFFFFFh
|
|
invoke DrawRect, 160, 120, 1, 1, 0000FF00h
|
|
skip_crosshair:
|
|
|
|
; 2. Render Active Weapon at bottom center
|
|
cmp playerWeapon, WEAPON_KNIFE
|
|
je render_knife_weapon
|
|
cmp playerWeapon, WEAPON_SHOTGUN
|
|
je render_shotgun_weapon
|
|
jmp render_pistol_weapon
|
|
|
|
render_knife_weapon:
|
|
; Knife Combat Animation: thrusts forward when cooldown active
|
|
mov gunY, 190
|
|
cmp playerFlashTimer, 0
|
|
je draw_knife
|
|
sub gunY, 12 ; thrust forward!
|
|
|
|
draw_knife:
|
|
; Silver steel blade
|
|
invoke DrawRect, 166, gunY, 6, 26, 00D0D0D0h
|
|
invoke DrawRect, 168, gunY, 2, 26, 00FFFFFFh ; shine
|
|
invoke DrawRect, 167, gunY - 4, 4, 4, 00B0B0B0h ; blade tip
|
|
invoke DrawRect, 168, gunY - 7, 2, 3, 00E0E0E0h
|
|
; Brass crossguard
|
|
mov eax, gunY
|
|
add eax, 26
|
|
invoke DrawRect, 160, eax, 18, 5, 00D4AF37h
|
|
; Wooden grip
|
|
mov eax, gunY
|
|
add eax, 31
|
|
invoke DrawRect, 164, eax, 10, 22, 00502A10h
|
|
jmp hud_stats_draw
|
|
|
|
render_shotgun_weapon:
|
|
; Heavy Pump Shotgun
|
|
mov gunY, 188
|
|
cmp playerFlashTimer, 0
|
|
je draw_shotgun_barrels
|
|
add gunY, 4 ; heavy recoil!
|
|
|
|
; Massive dual blast flash!
|
|
invoke DrawRect, 146, 155, 28, 22, 00FFAA00h
|
|
invoke DrawRect, 150, 158, 20, 16, 00FFFF00h
|
|
invoke DrawRect, 154, 162, 12, 10, 00FFFFFFh
|
|
|
|
draw_shotgun_barrels:
|
|
; Twin heavy steel barrels
|
|
invoke DrawRect, 148, gunY, 10, 32, 002B2B2Bh
|
|
invoke DrawRect, 150, gunY, 6, 32, 00484848h
|
|
invoke DrawRect, 162, gunY, 10, 32, 002B2B2Bh
|
|
invoke DrawRect, 164, gunY, 6, 32, 00484848h
|
|
; Barrel rib connector
|
|
invoke DrawRect, 158, gunY, 4, 32, 00222222h
|
|
; Wooden pump forend
|
|
mov eax, gunY
|
|
add eax, 20
|
|
invoke DrawRect, 144, eax, 32, 18, 00603818h
|
|
invoke DrawRect, 146, eax, 28, 14, 007A4820h
|
|
jmp hud_stats_draw
|
|
|
|
render_pistol_weapon:
|
|
mov gunY, 192
|
|
cmp playerFlashTimer, 0
|
|
je draw_pistol_barrel
|
|
add gunY, 3 ; recoil offset
|
|
|
|
; Muzzle Flash Burst (Bright yellow & white star)
|
|
invoke DrawRect, 157, 165, 7, 18, 00FFFF00h
|
|
invoke DrawRect, 152, 170, 17, 8, 00FFAA00h
|
|
invoke DrawRect, 158, 168, 5, 12, 00FFFFFFh
|
|
|
|
draw_pistol_barrel:
|
|
; Weapon barrel & slide
|
|
invoke DrawRect, 154, gunY, 13, 28, 003A3A3Ah
|
|
invoke DrawRect, 156, gunY, 9, 28, 00555555h
|
|
invoke DrawRect, 158, gunY, 5, 28, 00777777h ; highlight strip
|
|
; Gun frame & grip
|
|
mov eax, gunY
|
|
add eax, 24
|
|
invoke DrawRect, 150, eax, 21, 24, 00252525h
|
|
mov eax, gunY
|
|
add eax, 26
|
|
invoke DrawRect, 152, eax, 17, 22, 00453020h ; brown wood grip plates
|
|
|
|
hud_stats_draw:
|
|
; 3. Health Bar at top-left: X=8, Y=8
|
|
invoke DrawString8x8, 8, 8, OFFSET strHpLabel, COLOR_GREEN
|
|
invoke DrawNumber8x8, 34, 8, playerHealth, COLOR_WHITE
|
|
|
|
invoke DrawRect, 66, 8, 50, 8, 00441010h
|
|
invoke DrawRectOutline, 66, 8, 50, 8, COLOR_WHITE
|
|
|
|
mov eax, playerHealth
|
|
imul eax, 48
|
|
xor edx, edx
|
|
mov ecx, playerMaxHealth
|
|
test ecx, ecx
|
|
jnz @F
|
|
mov ecx, 100
|
|
@@:
|
|
div ecx
|
|
mov barW, eax
|
|
cmp barW, 0
|
|
jle hud_ammo_draw
|
|
cmp barW, 48
|
|
jle @F
|
|
mov barW, 48
|
|
@@:
|
|
mov edx, 0000CC33h ; Green
|
|
cmp playerHealth, 30
|
|
jg @F
|
|
mov edx, 00FF2222h ; Red warning
|
|
@@:
|
|
invoke DrawRect, 67, 9, barW, 6, edx
|
|
|
|
hud_ammo_draw:
|
|
; 4. Ammo Display: X=126, Y=8
|
|
invoke DrawString8x8, 126, 8, OFFSET strAmmoLabel, COLOR_YELLOW
|
|
invoke DrawNumber8x8, 168, 8, playerAmmo, COLOR_YELLOW
|
|
|
|
; 5. Keys: X=204, Y=8 (if collected)
|
|
cmp playerKeys, 0
|
|
jle hud_score_draw
|
|
invoke DrawString8x8, 204, 8, OFFSET strKeysLabel, COLOR_MAGENTA
|
|
invoke DrawNumber8x8, 238, 8, playerKeys, COLOR_MAGENTA
|
|
|
|
hud_score_draw:
|
|
; 6. Score Display: only in Debug HUD style
|
|
cmp hudStyle, HUD_STYLE_CLEAN
|
|
je draw_weapon_badge
|
|
invoke DrawString8x8, 8, 20, OFFSET strScoreLabel, COLOR_CYAN
|
|
invoke DrawNumber8x8, 58, 20, playerScore, COLOR_CYAN
|
|
|
|
draw_weapon_badge:
|
|
; 7. Active Weapon Badge at bottom-right corner: X=228, Y=222
|
|
invoke DrawRect, 228, 222, 88, 14, 00141414h
|
|
invoke DrawRectOutline, 228, 222, 88, 14, 00444444h
|
|
|
|
cmp playerWeapon, WEAPON_KNIFE
|
|
jne @F
|
|
invoke DrawString8x8, 233, 225, OFFSET strWeaponKnife, COLOR_CYAN
|
|
jmp draw_weapon_slots
|
|
@@:
|
|
cmp playerWeapon, WEAPON_SHOTGUN
|
|
jne @F
|
|
invoke DrawString8x8, 233, 225, OFFSET strWeaponShotgun, 00FFAA00h
|
|
jmp draw_weapon_slots
|
|
@@:
|
|
invoke DrawString8x8, 233, 225, OFFSET strWeaponPistol, COLOR_YELLOW
|
|
|
|
draw_weapon_slots:
|
|
; Draw small weapon slot indicator boxes: [1] [2] [3]
|
|
invoke DrawRectOutline, 287, 225, 6, 8, 00555555h
|
|
invoke DrawRectOutline, 295, 225, 6, 8, 00555555h
|
|
invoke DrawRectOutline, 303, 225, 6, 8, 00555555h
|
|
|
|
; Highlight active slot
|
|
mov eax, playerWeapon
|
|
imul eax, 8
|
|
add eax, 287
|
|
invoke DrawRectOutline, eax, 225, 6, 8, COLOR_YELLOW
|
|
|
|
hud_damage_flash:
|
|
; 8. Damage Screen Flash
|
|
cmp playerHitFlash, 0
|
|
jle hud_death_check
|
|
; Red border vignette
|
|
invoke DrawRect, 0, 0, SCREEN_W, 3, 00FF0000h
|
|
invoke DrawRect, 0, 237, SCREEN_W, 3, 00FF0000h
|
|
invoke DrawRect, 0, 0, 3, SCREEN_H, 00FF0000h
|
|
invoke DrawRect, 317, 0, 3, SCREEN_H, 00FF0000h
|
|
|
|
hud_death_check:
|
|
; 9. Death Overlay Screen
|
|
cmp isPlayerDead, 0
|
|
je combat_hud_done
|
|
|
|
invoke DrawRect, 20, 95, 280, 50, 00880000h
|
|
invoke DrawRectOutline, 20, 95, 280, 50, COLOR_WHITE
|
|
invoke DrawString8x8, 32, 114, OFFSET strYouDied, COLOR_YELLOW
|
|
|
|
combat_hud_done:
|
|
ret
|
|
RenderCombatHUD ENDP
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; RenderPauseMenu: Renders stylish retro pause overlay when isGamePaused != 0
|
|
; ------------------------------------------------------------------------------
|
|
RenderPauseMenu PROC uses ebx ecx edx
|
|
cmp isGamePaused, 0
|
|
je pause_menu_done
|
|
|
|
; Centered semi-transparent panel 220x112 at (50, 64)
|
|
invoke DrawRect, 50, 64, 220, 112, 00141416h
|
|
invoke DrawRectOutline, 50, 64, 220, 112, COLOR_CYAN
|
|
invoke DrawRectOutline, 52, 66, 216, 108, COLOR_WHITE
|
|
|
|
; Header
|
|
invoke DrawString8x8, 112, 72, OFFSET strPauseTitle, COLOR_YELLOW
|
|
|
|
; Menu Options
|
|
invoke DrawString8x8, 64, 88, OFFSET strPauseOpt1, COLOR_GREEN
|
|
invoke DrawString8x8, 64, 102, OFFSET strPauseOpt2, COLOR_WHITE
|
|
invoke DrawString8x8, 64, 116, OFFSET strPauseOpt3, COLOR_CYAN
|
|
invoke DrawString8x8, 64, 130, OFFSET strPauseOpt4, COLOR_YELLOW
|
|
invoke DrawString8x8, 64, 146, OFFSET strPauseOpt5, 00FF4444h
|
|
|
|
pause_menu_done:
|
|
ret
|
|
RenderPauseMenu ENDP
|