; ============================================================================== ; 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 ; ------------------------------------------------------------------------------ ; 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 LOCAL weaponDamage:DWORD, maxHitDist:DWORD, hitTolerance: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 or game is paused, cannot attack cmp isPlayerDead, 0 jne combat_done cmp isGamePaused, 0 jne 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 hitTolerance, 22 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 hitTolerance, 32 mov playerAttackCooldown, 8 mov playerFlashTimer, 3 jmp fire_hitscan setup_shotgun: ; Shotgun: needs 2 ammo, high damage (70), wide spread (hitTolerance 40), long cooldown cmp playerAmmo, 2 jl combat_dry_fire sub playerAmmo, 2 mov weaponDamage, 70 mov maxHitDist, 999999 mov hitTolerance, 40 mov playerAttackCooldown, 22 mov playerFlashTimer, 7 jmp fire_hitscan setup_pistol: ; Pistol: needs 1 ammo, accurate (hitTolerance 22), medium cooldown (12) cmp playerAmmo, 1 jl combat_dry_fire dec playerAmmo mov weaponDamage, 35 mov maxHitDist, 999999 mov hitTolerance, 22 mov playerAttackCooldown, 12 mov playerFlashTimer, 5 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 ; 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] ; Check if Guard or Barrel cmp eax, ENTITY_TYPE_GUARD je hitscan_target_valid cmp eax, ENTITY_TYPE_BARREL je hitscan_target_valid ; Also check if prop has barrel texture (11) mov ebx, i imul ebx, sizeof SpriteStruct add ebx, OFFSET spriteList mov eax, [ebx].SpriteStruct.textureId cmp eax, 11 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 ; 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 check sub eax, SCREEN_HALF_W cdq xor eax, edx sub eax, edx ; abs(sprScreenX - 160) cmp eax, hitTolerance 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 mov ebx, closestIdx imul ebx, sizeof SpriteStruct add ebx, OFFSET spriteList cmp [ebx].SpriteStruct.textureId, 11 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 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 mov edx, i imul edx, sizeof SpriteStruct add edx, OFFSET spriteList mov eax, [edx].SpriteStruct.x sub eax, esi cdq xor eax, edx sub eax, edx cmp eax, 128 jg next_aoe mov eax, [edx].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 ; 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 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 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. Active Weapon Name & Slot Indicators at top left invoke DrawString8x8, 8, 26, OFFSET strWeaponLabel, COLOR_WHITE cmp playerWeapon, WEAPON_KNIFE jne @F invoke DrawString8x8, 42, 26, OFFSET strWeaponKnife, COLOR_CYAN jmp draw_weapon_slots @@: cmp playerWeapon, WEAPON_SHOTGUN jne @F invoke DrawString8x8, 42, 26, OFFSET strWeaponShotgun, 00FFAA00h jmp draw_weapon_slots @@: invoke DrawString8x8, 42, 26, OFFSET strWeaponPistol, COLOR_YELLOW draw_weapon_slots: ; Draw small weapon slot indicator boxes: [1] [2] [3] invoke DrawRectOutline, 100, 26, 8, 8, 00555555h invoke DrawRectOutline, 112, 26, 8, 8, 00555555h invoke DrawRectOutline, 124, 26, 8, 8, 00555555h ; Highlight active slot mov eax, playerWeapon imul eax, 12 add eax, 100 invoke DrawRectOutline, eax, 26, 8, 8, COLOR_YELLOW ; 7. 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: ; 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 ; Semi-transparent dark overlay panel (centered 200x105 at 60, 65) invoke DrawRect, 60, 65, 200, 105, 00141416h invoke DrawRectOutline, 60, 65, 200, 105, COLOR_CYAN invoke DrawRectOutline, 62, 67, 196, 101, COLOR_WHITE ; Header invoke DrawString8x8, 112, 75, OFFSET strPauseTitle, COLOR_YELLOW ; Menu Options invoke DrawString8x8, 76, 95, OFFSET strPauseOpt1, COLOR_GREEN invoke DrawString8x8, 76, 110, OFFSET strPauseOpt2, COLOR_WHITE invoke DrawString8x8, 76, 125, OFFSET strPauseOpt3, COLOR_CYAN invoke DrawString8x8, 76, 140, OFFSET strPauseOpt4, 00FF4444h pause_menu_done: ret RenderPauseMenu ENDP