EBLAN_ENGINE/include/engine_entity.inc
Игорь Федосеев f42679fe62 fix: stabilize gameplay and IDE source writes
Trace shots against current map geometry instead of stale render depth. Preserve outline counters across volatile pixel calls and freeze gameplay on cinematic, transition and death ticks.

Clamp packed HP before narrowing and match legacy archetype rules. Publish IDE saves atomically; failed saves block file switches and builds. Drain compiler output while hidden.

Verify runtime/editor builds, 112 editor checks, 148 ASM checks and live preview parity. Record remaining stages in docs/STABILIZATION.md.
2026-10-31 21:56:54 +03:00

391 lines
8.9 KiB
PHP

; ==============================================================================
; EBLAN ENGINE - Entity & Gameplay Behavior System
; ==============================================================================
.code
; ------------------------------------------------------------------------------
; InitEntities: Initialize entity runtime state from spriteList flags/defaults
; ------------------------------------------------------------------------------
InitEntities PROC uses eax ebx ecx edx esi edi
; 1. Clear runtime arrays
xor eax, eax
mov ecx, MAX_SPRITES
mov edi, OFFSET entityType
rep stosd
mov ecx, MAX_SPRITES
mov eax, 100
mov edi, OFFSET entityHealth
rep stosd
xor eax, eax
mov ecx, MAX_SPRITES
mov edi, OFFSET entityState
rep stosd
mov ecx, MAX_SPRITES
mov edi, OFFSET entityTimer
rep stosd
mov ecx, MAX_SPRITES
mov eax, 2
mov edi, OFFSET entitySpeed
rep stosd
mov ecx, MAX_SPRITES
mov eax, 384
mov edi, OFFSET entityAggro
rep stosd
; 2. Iterate spriteList and configure entity archetypes
xor ecx, ecx
init_spr_loop:
cmp ecx, spriteCount
jge init_spr_done
mov ebx, ecx
imul ebx, sizeof SpriteStruct
add ebx, OFFSET spriteList
mov eax, [ebx].SpriteStruct.flags
test eax, eax
jz fallback_archetype
; Parse flags:
; Byte 0: Entity Type (0=Prop, 1=Guard, 2=Medkit, 3=Ammo, 4=Key, 5=Switch)
; Byte 1: Health (if Guard)
; Byte 2: Speed (1..8)
; Byte 3: Aggro multiplier (1..15 -> cells * 64)
mov edx, eax
and edx, 0FFh
mov [entityType + ecx*4], edx
mov edx, eax
shr edx, 8
and edx, 0FFh
test edx, edx
jz @F
mov [entityHealth + ecx*4], edx
@@:
mov edx, eax
shr edx, 16
and edx, 0FFh
test edx, edx
jz @F
mov [entitySpeed + ecx*4], edx
@@:
mov edx, eax
shr edx, 24
and edx, 0FFh
test edx, edx
jz next_spr_slot
shl edx, 6 ; cells -> raw units
mov [entityAggro + ecx*4], edx
jmp next_spr_slot
fallback_archetype:
; If flags == 0, infer archetype from textureId:
; Slot 13 = Enemy Guard, 14 = Medkit, 15 = Ammo
mov edx, [ebx].SpriteStruct.textureId
cmp edx, 13
jne check_medkit_slot
mov [entityType + ecx*4], ENTITY_TYPE_GUARD
mov [entityHealth + ecx*4], 100
mov [entitySpeed + ecx*4], 2
jmp next_spr_slot
check_medkit_slot:
cmp edx, 14
jne check_ammo_slot
mov [entityType + ecx*4], ENTITY_TYPE_MEDKIT
jmp next_spr_slot
check_ammo_slot:
cmp edx, 15
jne next_spr_slot
mov [entityType + ecx*4], ENTITY_TYPE_AMMO
next_spr_slot:
inc ecx
jmp init_spr_loop
init_spr_done:
ret
InitEntities ENDP
; ------------------------------------------------------------------------------
; UpdateEntities: Updates AI, pickups, collision and interactions each tick
; ------------------------------------------------------------------------------
UpdateEntities PROC uses ebx ecx edx esi edi
LOCAL i:DWORD
LOCAL sprX:DWORD, sprY:DWORD
LOCAL deltaX:DWORD, deltaY:DWORD
LOCAL absDX:DWORD, absDY:DWORD
LOCAL distSq:DWORD
LOCAL speed:DWORD
LOCAL stepX:DWORD, stepY:DWORD
LOCAL cellX:DWORD, cellY:DWORD
; If player died and pressed Restart (R)
cmp isPlayerDead, 0
je entities_active
cmp keyRestart, 0
je entities_done
; Respawn player
mov playerHealth, 100
mov playerAmmo, 50
mov isPlayerDead, 0
mov playerHitFlash, 0
call LoadMapBinary
call InitEntities
ret
entities_active:
call IsGameplayBlocked
test eax, eax
jnz entities_done
mov i, 0
entity_loop:
mov eax, i
cmp eax, spriteCount
jge entities_done
mov ebx, i
imul ebx, sizeof SpriteStruct
add ebx, OFFSET spriteList
; If sprite is inactive (textureId == 0), skip
mov eax, [ebx].SpriteStruct.textureId
test eax, eax
jz next_entity
mov eax, [ebx].SpriteStruct.x
mov sprX, eax
mov eax, [ebx].SpriteStruct.y
mov sprY, eax
; Distance to player
mov eax, playerX
sub eax, sprX
mov deltaX, eax
cdq
xor eax, edx
sub eax, edx
mov absDX, eax
mov eax, playerY
sub eax, sprY
mov deltaY, eax
cdq
xor eax, edx
sub eax, edx
mov absDY, eax
; distSq = deltaX^2 + deltaY^2
mov eax, deltaX
imul eax, eax
mov ecx, eax
mov eax, deltaY
imul eax, eax
add eax, ecx
mov distSq, eax
mov ecx, i
mov edx, [entityType + ecx*4]
; --------------------------------------------------------------------------
; Medkit Pickup (+25 HP)
; --------------------------------------------------------------------------
cmp edx, ENTITY_TYPE_MEDKIT
jne check_ammo_pickup
cmp absDX, 32
jge next_entity
cmp absDY, 32
jge next_entity
mov eax, playerHealth
cmp eax, playerMaxHealth
jge next_entity
add eax, 25
cmp eax, playerMaxHealth
jle @F
mov eax, playerMaxHealth
@@:
mov playerHealth, eax
mov [ebx].SpriteStruct.textureId, 0 ; Hide item
mov ecx, i
mov [entityType + ecx*4], ENTITY_TYPE_PROP
add playerScore, 25
jmp next_entity
; --------------------------------------------------------------------------
; Ammo Pickup (+20 Ammo)
; --------------------------------------------------------------------------
check_ammo_pickup:
cmp edx, ENTITY_TYPE_AMMO
jne check_key_pickup
cmp absDX, 32
jge next_entity
cmp absDY, 32
jge next_entity
mov eax, playerAmmo
add eax, 20
cmp eax, playerMaxAmmo
jle @F
mov eax, playerMaxAmmo
@@:
mov playerAmmo, eax
mov [ebx].SpriteStruct.textureId, 0
mov ecx, i
mov [entityType + ecx*4], ENTITY_TYPE_PROP
add playerScore, 10
jmp next_entity
; --------------------------------------------------------------------------
; Key Pickup (+1 Key)
; --------------------------------------------------------------------------
check_key_pickup:
cmp edx, ENTITY_TYPE_KEY
jne check_guard_entity
cmp absDX, 32
jge next_entity
cmp absDY, 32
jge next_entity
inc playerKeys
mov [ebx].SpriteStruct.textureId, 0
mov ecx, i
mov [entityType + ecx*4], ENTITY_TYPE_PROP
add playerScore, 50
jmp next_entity
; --------------------------------------------------------------------------
; Guard Enemy AI
; --------------------------------------------------------------------------
check_guard_entity:
cmp edx, ENTITY_TYPE_GUARD
jne next_entity
mov ecx, i
mov eax, [entityState + ecx*4]
cmp eax, ENTITY_STATE_DEAD
jne guard_alive
; Dead guard: tick timer until disappear
inc DWORD PTR [entityTimer + ecx*4]
cmp DWORD PTR [entityTimer + ecx*4], 120
jl next_entity
mov [ebx].SpriteStruct.textureId, 0
jmp next_entity
guard_alive:
; Check aggro radius
mov eax, [entityAggro + ecx*4]
imul eax, eax ; aggroSq
cmp distSq, eax
jg next_entity
; Guard is alert & chasing player
mov ecx, i
mov [entityState + ecx*4], ENTITY_STATE_CHASE
mov eax, [entitySpeed + ecx*4]
mov speed, eax
; Calculate movement direction
mov stepX, 0
mov stepY, 0
cmp deltaX, 16
jle check_neg_x
mov eax, speed
mov stepX, eax
jmp check_step_y
check_neg_x:
cmp deltaX, -16
jge check_step_y
mov eax, speed
neg eax
mov stepX, eax
check_step_y:
cmp deltaY, 16
jle check_neg_y
mov eax, speed
mov stepY, eax
jmp apply_guard_step
check_neg_y:
cmp deltaY, -16
jge apply_guard_step
mov eax, speed
neg eax
mov stepY, eax
apply_guard_step:
; Try stepping X
cmp stepX, 0
je try_step_y
mov eax, sprX
add eax, stepX
sar eax, 6
mov cellX, eax
mov eax, sprY
sar eax, 6
mov cellY, eax
invoke GetMapCell, cellX, cellY
invoke IsSolidCell, eax
test eax, eax
jnz try_step_y
mov eax, stepX
add [ebx].SpriteStruct.x, eax
mov eax, [ebx].SpriteStruct.x
mov sprX, eax
try_step_y:
cmp stepY, 0
je check_guard_attack
mov eax, sprX
sar eax, 6
mov cellX, eax
mov eax, sprY
add eax, stepY
sar eax, 6
mov cellY, eax
invoke GetMapCell, cellX, cellY
invoke IsSolidCell, eax
test eax, eax
jnz check_guard_attack
mov eax, stepY
add [ebx].SpriteStruct.y, eax
check_guard_attack:
; Attack range check: within 48 raw units
cmp distSq, 2304 ; 48 * 48
jg next_entity
mov ecx, i
inc DWORD PTR [entityTimer + ecx*4]
cmp DWORD PTR [entityTimer + ecx*4], 35
jl next_entity
mov DWORD PTR [entityTimer + ecx*4], 0
; Guard hits player!
mov eax, playerHealth
sub eax, 8
jns @F
xor eax, eax
@@:
mov playerHealth, eax
mov playerHitFlash, 6
test eax, eax
jnz next_entity
mov isPlayerDead, 1
; Nothing else may collect items or attack after a lethal hit this tick.
jmp entities_done
next_entity:
inc i
jmp entity_loop
entities_done:
ret
UpdateEntities ENDP