Group level edits across inspector and canvas gestures, preserve legacy maps, and expose opt-in switch/key door bindings without changing wire layouts. Refresh studio and pause UI with UE5-inspired surfaces and content drawer. Verify 162 editor and 307 ASM checks plus renderer parity.
739 lines
19 KiB
PHP
739 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
|
|
|
|
; Compact charcoal surfaces, restrained blue accent, consistent option rows.
|
|
invoke DrawRect, 46, 52, 228, 144, 000B0B0Bh
|
|
invoke DrawRect, 44, 50, 228, 144, 00202020h
|
|
invoke DrawRectOutline, 44, 50, 228, 144, 003C3C3Ch
|
|
invoke DrawRect, 44, 50, 228, 2, 002DA5E0h
|
|
invoke DrawRect, 45, 53, 226, 24, 00292929h
|
|
invoke DrawRect, 52, 84, 212, 18, 00353535h
|
|
|
|
; Header
|
|
invoke DrawString8x8, 112, 61, OFFSET strPauseTitle, 00DEDEDEh
|
|
|
|
; Menu Options
|
|
invoke DrawRect, 52, 84, 2, 18, 002DA5E0h
|
|
invoke DrawString8x8, 60, 89, OFFSET strPauseOpt1, 00FFFFFFh
|
|
invoke DrawString8x8, 60, 109, OFFSET strPauseOpt2, 00CDCDCDh
|
|
invoke DrawString8x8, 60, 129, OFFSET strPauseOpt3, 00CDCDCDh
|
|
invoke DrawString8x8, 60, 149, OFFSET strPauseOpt4, 00CDCDCDh
|
|
invoke DrawRect, 52, 166, 212, 1, 003C3C3Ch
|
|
invoke DrawString8x8, 60, 177, OFFSET strPauseOpt5, 00D99898h
|
|
|
|
pause_menu_done:
|
|
ret
|
|
RenderPauseMenu ENDP
|