303 lines
7.5 KiB
PHP
303 lines
7.5 KiB
PHP
; ==============================================================================
|
|
; EBLAN ENGINE - Player Combat, Weapon Shooting & 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
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; 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 sprScreenX:DWORD, wallDepth:DWORD
|
|
|
|
; 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, cannot attack
|
|
cmp isPlayerDead, 0
|
|
jne combat_done
|
|
|
|
; 2. Check attack input
|
|
cmp keyAttack, 0
|
|
je combat_done
|
|
cmp playerAttackCooldown, 0
|
|
jne combat_done
|
|
|
|
; Check ammo
|
|
cmp playerAmmo, 0
|
|
jle combat_dry_fire
|
|
|
|
; Fire weapon!
|
|
dec playerAmmo
|
|
mov playerAttackCooldown, 10
|
|
mov playerFlashTimer, 5
|
|
|
|
; 3. Hitscan check against enemies in center 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
|
|
|
|
; Center wall depth from depthBuffer[160]
|
|
mov eax, [depthBuffer + SCREEN_HALF_W * 4]
|
|
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]
|
|
cmp eax, ENTITY_TYPE_GUARD
|
|
jne next_hitscan_target
|
|
|
|
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 the wall at center screen
|
|
mov eax, transY
|
|
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
|
|
|
|
; sprScreenX = (transX * PROJ_DIST) / transY + SCREEN_HALF_W
|
|
mov eax, transX
|
|
imul eax, PROJ_DIST
|
|
cdq
|
|
idiv transY
|
|
add eax, SCREEN_HALF_W
|
|
mov sprScreenX, eax
|
|
|
|
; Crosshair hitbox: within 22 pixels of center (SCREEN_HALF_W = 160)
|
|
sub eax, SCREEN_HALF_W
|
|
cdq
|
|
xor eax, edx
|
|
sub eax, edx ; abs(sprScreenX - 160)
|
|
cmp eax, 22
|
|
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
|
|
|
|
; Apply damage to hit guard
|
|
mov ecx, closestIdx
|
|
mov eax, [entityHealth + ecx*4]
|
|
sub eax, 35
|
|
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
|
|
|
|
; Drop 10 ammo reward
|
|
mov eax, playerAmmo
|
|
add eax, 10
|
|
cmp eax, playerMaxAmmo
|
|
jle @F
|
|
mov eax, playerMaxAmmo
|
|
@@:
|
|
mov playerAmmo, eax
|
|
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
|
|
|
|
; 1. Center Crosshair (subtle cross at 160, 120)
|
|
invoke DrawRect, 156, 120, 9, 1, 00FFFFFFh
|
|
invoke DrawRect, 160, 116, 1, 9, 00FFFFFFh
|
|
invoke DrawRect, 160, 120, 1, 1, 0000FF00h
|
|
|
|
; 2. Render Retro Weapon at bottom center
|
|
mov gunY, 192
|
|
cmp playerFlashTimer, 0
|
|
je draw_gun_barrel
|
|
; Recoil offset
|
|
add gunY, 3
|
|
|
|
; 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_gun_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
|
|
|
|
; 3. Health Bar
|
|
invoke DrawString8x8, 8, 42, OFFSET strHpLabel, COLOR_GREEN
|
|
invoke DrawNumber8x8, 34, 42, playerHealth, COLOR_WHITE
|
|
|
|
invoke DrawRect, 68, 42, 60, 8, 00441010h
|
|
invoke DrawRectOutline, 68, 42, 60, 8, COLOR_WHITE
|
|
|
|
mov eax, playerHealth
|
|
imul eax, 58
|
|
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, 58
|
|
jle @F
|
|
mov barW, 58
|
|
@@:
|
|
mov edx, 0000CC33h ; Green
|
|
cmp playerHealth, 30
|
|
jg @F
|
|
mov edx, 00FF2222h ; Red warning
|
|
@@:
|
|
invoke DrawRect, 69, 43, barW, 6, edx
|
|
|
|
hud_ammo_draw:
|
|
; 4. Ammo Display
|
|
invoke DrawString8x8, 140, 42, OFFSET strAmmoLabel, COLOR_YELLOW
|
|
invoke DrawNumber8x8, 182, 42, playerAmmo, COLOR_YELLOW
|
|
|
|
; 5. Score Display
|
|
invoke DrawString8x8, 222, 42, OFFSET strScoreLabel, COLOR_CYAN
|
|
invoke DrawNumber8x8, 272, 42, playerScore, COLOR_CYAN
|
|
|
|
; 6. Keys (if collected)
|
|
cmp playerKeys, 0
|
|
jle hud_damage_flash
|
|
invoke DrawString8x8, 222, 10, OFFSET strKeysLabel, COLOR_MAGENTA
|
|
invoke DrawNumber8x8, 258, 10, playerKeys, COLOR_MAGENTA
|
|
|
|
hud_damage_flash:
|
|
; 7. 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:
|
|
; 8. 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
|