Add a painting entrance, Freedoom combat and Doom-style HUD. Persist the one-time clear reward in signed saves without changing file sizes. Include native regression checks and synchronized game/launcher builds.
764 lines
16 KiB
PHP
764 lines
16 KiB
PHP
; All positions/velocities are signed 16.16; bounded pools and fixed ticks.
|
|
HFDistance PROC x0:DWORD,y0:DWORD,x1:DWORD,y1:DWORD
|
|
mov eax,x0
|
|
sub eax,x1
|
|
cdq
|
|
xor eax,edx
|
|
sub eax,edx
|
|
mov ecx,eax
|
|
mov eax,y0
|
|
sub eax,y1
|
|
cdq
|
|
xor eax,edx
|
|
sub eax,edx
|
|
cmp eax,ecx
|
|
jae @F
|
|
mov eax,ecx
|
|
@@:
|
|
ret
|
|
HFDistance ENDP
|
|
|
|
HFPlayerCanWalk PROC uses esi edi px:DWORD,py:DWORD
|
|
invoke CanWalk3D,px,py
|
|
test eax,eax
|
|
jz hf_player_walk_done
|
|
mov esi,OFFSET hfEnemies
|
|
mov edi,HF_ENEMIES
|
|
hf_player_body:
|
|
cmp [esi].HFEnemy.hp,0
|
|
jle hf_player_body_next
|
|
invoke HFDistance,px,py,[esi].HFEnemy.x,[esi].HFEnemy.y
|
|
cmp eax,FP_1*9/20
|
|
jb hf_player_body_block
|
|
hf_player_body_next:
|
|
add esi,SIZEOF HFEnemy
|
|
dec edi
|
|
jnz hf_player_body
|
|
mov eax,1
|
|
ret
|
|
hf_player_body_block:
|
|
xor eax,eax
|
|
hf_player_walk_done:
|
|
ret
|
|
HFPlayerCanWalk ENDP
|
|
|
|
HFLineClear PROC uses ebx esi edi x0:DWORD,y0:DWORD,x1:DWORD,y1:DWORD
|
|
local stepX:DWORD,stepY:DWORD,rx:DWORD,ry:DWORD
|
|
invoke HFDistance,x0,y0,x1,y1
|
|
shr eax,12 ; quarter of a collision radius per sample, <= 1/16 tile
|
|
inc eax
|
|
mov ebx,eax
|
|
mov eax,x1
|
|
sub eax,x0
|
|
cdq
|
|
idiv ebx
|
|
mov stepX,eax
|
|
mov eax,y1
|
|
sub eax,y0
|
|
cdq
|
|
idiv ebx
|
|
mov stepY,eax
|
|
mov esi,x0
|
|
mov edi,y0
|
|
hf_los_step:
|
|
add esi,stepX
|
|
add edi,stepY
|
|
mov eax,esi
|
|
sar eax,16
|
|
cmp eax,32
|
|
jae hf_los_blocked
|
|
mov ecx,edi
|
|
sar ecx,16
|
|
cmp ecx,32
|
|
jae hf_los_blocked
|
|
shl ecx,5
|
|
add eax,ecx
|
|
cmp hfMap[eax],0
|
|
jne hf_los_blocked
|
|
dec ebx
|
|
jnz hf_los_step
|
|
mov eax,1
|
|
ret
|
|
hf_los_blocked:
|
|
xor eax,eax
|
|
ret
|
|
HFLineClear ENDP
|
|
|
|
HFDamagePlayer PROC uses ebx amount:DWORD
|
|
cmp hfState,0
|
|
jne hf_damage_done
|
|
mov ebx,amount
|
|
mov eax,ebx
|
|
shr eax,1
|
|
cmp eax,hfArmor
|
|
jbe @F
|
|
mov eax,hfArmor
|
|
@@:
|
|
sub hfArmor,eax
|
|
sub ebx,eax
|
|
sub hfHealth,ebx
|
|
mov hfHurt,10
|
|
invoke HFPlaySound,2
|
|
cmp hfHealth,0
|
|
jg hf_damage_done
|
|
mov hfHealth,0
|
|
mov hfState,1
|
|
mov hfFireHeld,0
|
|
hf_damage_done:
|
|
ret
|
|
HFDamagePlayer ENDP
|
|
|
|
HFDamageEnemy PROC uses esi enemy:DWORD,amount:DWORD
|
|
mov esi,enemy
|
|
cmp [esi].HFEnemy.hp,0
|
|
jle hf_enemy_damage_done
|
|
mov eax,amount
|
|
sub [esi].HFEnemy.hp,eax
|
|
mov [esi].HFEnemy.awake,1
|
|
mov [esi].HFEnemy.pose,6
|
|
mov [esi].HFEnemy.timer,4
|
|
cmp [esi].HFEnemy.hp,0
|
|
jg hf_enemy_damage_done
|
|
mov [esi].HFEnemy.hp,0
|
|
mov [esi].HFEnemy.pose,7
|
|
mov [esi].HFEnemy.timer,0
|
|
inc hfKills
|
|
hf_enemy_damage_done:
|
|
ret
|
|
HFDamageEnemy ENDP
|
|
|
|
HFFire PROC uses esi edi ebx
|
|
local pellet:DWORD,angle:DWORD,rx:DWORD,ry:DWORD,stepX:DWORD,stepY:DWORD,steps:DWORD
|
|
cmp hfCooldown,0
|
|
jne hf_fire_done
|
|
cmp hfWeapon,1
|
|
je hf_fire_shotgun
|
|
cmp hfBullets,0
|
|
je hf_fire_done
|
|
dec hfBullets
|
|
mov hfCooldown,9
|
|
mov pellet,1
|
|
invoke HFPlaySound,4
|
|
jmp hf_fire_begin
|
|
hf_fire_shotgun:
|
|
cmp hfShells,0
|
|
je hf_fire_done
|
|
dec hfShells
|
|
mov hfCooldown,29
|
|
mov pellet,HF_SHOT_PELLETS
|
|
invoke HFPlaySound,0
|
|
hf_fire_begin:
|
|
mov hfFlash,4
|
|
hf_fire_pellet:
|
|
mov eax,playerAngle
|
|
cmp hfWeapon,0
|
|
je @F
|
|
mov ecx,pellet
|
|
add eax,hfPelletSpread[ecx*4-4]
|
|
@@:
|
|
and eax,511
|
|
mov angle,eax
|
|
mov ecx,tableCos[eax*4]
|
|
sar ecx,3
|
|
mov stepX,ecx
|
|
mov ecx,tableSin[eax*4]
|
|
sar ecx,3
|
|
mov stepY,ecx
|
|
mov eax,playerX
|
|
mov rx,eax
|
|
mov eax,playerY
|
|
mov ry,eax
|
|
mov steps,192
|
|
hf_ray_step:
|
|
mov eax,stepX
|
|
add rx,eax
|
|
mov eax,stepY
|
|
add ry,eax
|
|
mov eax,rx
|
|
sar eax,16
|
|
cmp eax,32
|
|
jae hf_ray_end
|
|
mov ecx,ry
|
|
sar ecx,16
|
|
cmp ecx,32
|
|
jae hf_ray_end
|
|
shl ecx,5
|
|
add eax,ecx
|
|
cmp hfMap[eax],0
|
|
jne hf_ray_end
|
|
mov esi,OFFSET hfEnemies
|
|
mov ebx,HF_ENEMIES
|
|
hf_ray_enemy:
|
|
cmp [esi].HFEnemy.hp,0
|
|
jle hf_ray_next_enemy
|
|
invoke HFDistance,rx,ry,[esi].HFEnemy.x,[esi].HFEnemy.y
|
|
cmp eax,FP_1*7/20
|
|
ja hf_ray_next_enemy
|
|
invoke RandomRange3D,9
|
|
add eax,8
|
|
invoke HFDamageEnemy,esi,eax
|
|
jmp hf_ray_end
|
|
hf_ray_next_enemy:
|
|
add esi,SIZEOF HFEnemy
|
|
dec ebx
|
|
jnz hf_ray_enemy
|
|
dec steps
|
|
jnz hf_ray_step
|
|
hf_ray_end:
|
|
; Each pellet owns its own impact; stay just in front of a wall's depth.
|
|
mov ecx,pellet
|
|
dec ecx
|
|
imul ecx,SIZEOF HFImpact
|
|
mov eax,rx
|
|
sub eax,stepX
|
|
sub eax,stepX
|
|
mov hfImpacts[ecx].x,eax
|
|
mov eax,ry
|
|
sub eax,stepY
|
|
sub eax,stepY
|
|
mov hfImpacts[ecx].y,eax
|
|
mov hfImpacts[ecx].life,8
|
|
dec pellet
|
|
jnz hf_fire_pellet
|
|
hf_fire_done:
|
|
ret
|
|
HFFire ENDP
|
|
|
|
HFSpawnBolt PROC uses esi ebx x:DWORD,y:DWORD,damage:DWORD
|
|
local distance:DWORD
|
|
mov esi,OFFSET hfBolts
|
|
mov ebx,32
|
|
@@:
|
|
cmp [esi].HFBolt.life,0
|
|
je hf_bolt_slot
|
|
add esi,SIZEOF HFBolt
|
|
dec ebx
|
|
jnz @B
|
|
ret
|
|
hf_bolt_slot:
|
|
invoke HFDistance,x,y,playerX,playerY
|
|
cmp eax,FP_1/2
|
|
jae @F
|
|
mov eax,FP_1/2
|
|
@@:
|
|
mov distance,eax
|
|
mov eax,x
|
|
mov [esi].HFBolt.x,eax
|
|
mov eax,y
|
|
mov [esi].HFBolt.y,eax
|
|
mov eax,damage
|
|
mov [esi].HFBolt.damage,eax
|
|
mov [esi].HFBolt.life,210
|
|
mov eax,playerX
|
|
sub eax,x
|
|
mov ecx,FP_1/7
|
|
imul ecx
|
|
idiv distance
|
|
mov [esi].HFBolt.vx,eax
|
|
mov eax,playerY
|
|
sub eax,y
|
|
mov ecx,FP_1/7
|
|
imul ecx
|
|
idiv distance
|
|
mov [esi].HFBolt.vy,eax
|
|
invoke HFPlaySound,1
|
|
ret
|
|
HFSpawnBolt ENDP
|
|
|
|
; Breadth-first distance field permits monsters to navigate around room pillars.
|
|
HFBuildFlow PROC uses esi edi ebx
|
|
local head:DWORD,tail:DWORD,current:DWORD,neighbor:DWORD
|
|
cld
|
|
mov edi,OFFSET hfFlow
|
|
mov eax,0FFFFFFFFh
|
|
mov ecx,512
|
|
rep stosd
|
|
mov eax,playerY
|
|
sar eax,16
|
|
shl eax,5
|
|
mov ecx,playerX
|
|
sar ecx,16
|
|
add eax,ecx
|
|
mov hfFlow[eax*2],0
|
|
mov hfQueue,eax
|
|
mov head,0
|
|
mov tail,1
|
|
hf_flow_pop:
|
|
mov eax,head
|
|
cmp eax,tail
|
|
jae hf_flow_done
|
|
mov eax,hfQueue[eax*4]
|
|
mov current,eax
|
|
movzx ebx,hfFlow[eax*2]
|
|
inc ebx
|
|
xor esi,esi
|
|
hf_flow_neighbor:
|
|
mov eax,current
|
|
cmp esi,0
|
|
jne @F
|
|
dec eax
|
|
@@:
|
|
cmp esi,1
|
|
jne @F
|
|
inc eax
|
|
@@:
|
|
cmp esi,2
|
|
jne @F
|
|
sub eax,32
|
|
@@:
|
|
cmp esi,3
|
|
jne @F
|
|
add eax,32
|
|
@@:
|
|
cmp eax,1024
|
|
jae hf_flow_next
|
|
cmp hfMap[eax],0
|
|
jne hf_flow_next
|
|
cmp hfFlow[eax*2],0FFFFh
|
|
jne hf_flow_next
|
|
mov hfFlow[eax*2],bx
|
|
mov ecx,tail
|
|
mov hfQueue[ecx*4],eax
|
|
inc tail
|
|
hf_flow_next:
|
|
inc esi
|
|
cmp esi,4
|
|
jb hf_flow_neighbor
|
|
inc head
|
|
jmp hf_flow_pop
|
|
hf_flow_done:
|
|
ret
|
|
HFBuildFlow ENDP
|
|
|
|
HFMoveEnemy PROC uses esi edi ebx enemy:DWORD
|
|
local tx:DWORD,ty:DWORD,distance:DWORD,speed:DWORD,best:DWORD,cell:DWORD,nx:DWORD,ny:DWORD
|
|
mov esi,enemy
|
|
mov eax,playerX
|
|
mov tx,eax
|
|
mov eax,playerY
|
|
mov ty,eax
|
|
invoke HFLineClear,[esi].HFEnemy.x,[esi].HFEnemy.y,playerX,playerY
|
|
test eax,eax
|
|
jnz hf_move_target
|
|
mov eax,[esi].HFEnemy.y
|
|
sar eax,16
|
|
shl eax,5
|
|
mov ecx,[esi].HFEnemy.x
|
|
sar ecx,16
|
|
add eax,ecx
|
|
mov cell,eax
|
|
movzx eax,hfFlow[eax*2]
|
|
mov best,eax
|
|
mov edi,-1
|
|
xor ebx,ebx
|
|
hf_move_flow:
|
|
mov eax,cell
|
|
cmp ebx,0
|
|
jne @F
|
|
dec eax
|
|
@@:
|
|
cmp ebx,1
|
|
jne @F
|
|
inc eax
|
|
@@:
|
|
cmp ebx,2
|
|
jne @F
|
|
sub eax,32
|
|
@@:
|
|
cmp ebx,3
|
|
jne @F
|
|
add eax,32
|
|
@@:
|
|
cmp eax,1024
|
|
jae hf_move_flow_next
|
|
movzx ecx,hfFlow[eax*2]
|
|
cmp ecx,best
|
|
jae hf_move_flow_next
|
|
mov best,ecx
|
|
mov edi,eax
|
|
hf_move_flow_next:
|
|
inc ebx
|
|
cmp ebx,4
|
|
jb hf_move_flow
|
|
cmp edi,-1
|
|
je hf_move_done
|
|
mov eax,edi
|
|
and eax,31
|
|
shl eax,16
|
|
add eax,FP_HALF
|
|
mov tx,eax
|
|
shr edi,5
|
|
shl edi,16
|
|
add edi,FP_HALF
|
|
mov ty,edi
|
|
hf_move_target:
|
|
invoke HFDistance,[esi].HFEnemy.x,[esi].HFEnemy.y,tx,ty
|
|
cmp eax,FP_1/8
|
|
jb hf_move_done
|
|
mov distance,eax
|
|
mov eax,[esi].HFEnemy.kind
|
|
mov eax,hfMonsterSpeed[eax*4]
|
|
mov speed,eax
|
|
mov eax,tx
|
|
sub eax,[esi].HFEnemy.x
|
|
imul speed
|
|
idiv distance
|
|
add eax,[esi].HFEnemy.x
|
|
mov nx,eax
|
|
invoke CanWalk3D,eax,[esi].HFEnemy.y
|
|
test eax,eax
|
|
jz @F
|
|
mov eax,nx
|
|
mov [esi].HFEnemy.x,eax
|
|
@@:
|
|
mov eax,ty
|
|
sub eax,[esi].HFEnemy.y
|
|
imul speed
|
|
idiv distance
|
|
add eax,[esi].HFEnemy.y
|
|
mov ny,eax
|
|
invoke CanWalk3D,[esi].HFEnemy.x,eax
|
|
test eax,eax
|
|
jz hf_move_done
|
|
mov eax,ny
|
|
mov [esi].HFEnemy.y,eax
|
|
hf_move_done:
|
|
ret
|
|
HFMoveEnemy ENDP
|
|
|
|
HFEnemiesTick PROC uses esi edi ebx
|
|
local distance:DWORD,visible:DWORD
|
|
mov esi,OFFSET hfEnemies
|
|
mov edi,HF_ENEMIES
|
|
hf_ai_enemy:
|
|
cmp [esi].HFEnemy.hp,0
|
|
jg hf_ai_alive
|
|
cmp [esi].HFEnemy.pose,11
|
|
jae hf_ai_next
|
|
inc [esi].HFEnemy.timer
|
|
cmp [esi].HFEnemy.timer,6
|
|
jb hf_ai_next
|
|
mov [esi].HFEnemy.timer,0
|
|
inc [esi].HFEnemy.pose
|
|
jmp hf_ai_next
|
|
hf_ai_alive:
|
|
cmp [esi].HFEnemy.cooldown,0
|
|
je @F
|
|
dec [esi].HFEnemy.cooldown
|
|
@@:
|
|
cmp [esi].HFEnemy.timer,0
|
|
je hf_ai_perceive
|
|
dec [esi].HFEnemy.timer
|
|
jnz hf_ai_next
|
|
cmp [esi].HFEnemy.pose,4
|
|
jne hf_ai_next
|
|
invoke HFLineClear,[esi].HFEnemy.x,[esi].HFEnemy.y,playerX,playerY
|
|
test eax,eax
|
|
jz hf_ai_next
|
|
invoke HFDistance,[esi].HFEnemy.x,[esi].HFEnemy.y,playerX,playerY
|
|
mov distance,eax
|
|
mov ebx,[esi].HFEnemy.kind
|
|
cmp eax,FP_1*7/10
|
|
jbe hf_ai_melee
|
|
cmp ebx,1
|
|
je hf_ai_next
|
|
cmp ebx,0
|
|
jne hf_ai_projectile
|
|
invoke RandomRange3D,4
|
|
test eax,eax
|
|
jz hf_ai_attack_pose
|
|
invoke HFDamagePlayer,6
|
|
jmp hf_ai_attack_pose
|
|
hf_ai_perceive:
|
|
invoke HFDistance,[esi].HFEnemy.x,[esi].HFEnemy.y,playerX,playerY
|
|
mov distance,eax
|
|
mov visible,0
|
|
cmp eax,16*FP_1
|
|
ja hf_ai_awake
|
|
invoke HFLineClear,[esi].HFEnemy.x,[esi].HFEnemy.y,playerX,playerY
|
|
mov visible,eax
|
|
test eax,eax
|
|
jz hf_ai_awake
|
|
mov [esi].HFEnemy.awake,1
|
|
hf_ai_awake:
|
|
cmp [esi].HFEnemy.awake,0
|
|
je hf_ai_next
|
|
mov eax,hfTicks
|
|
shr eax,3
|
|
and eax,3
|
|
mov [esi].HFEnemy.pose,eax
|
|
cmp visible,0
|
|
je hf_ai_move
|
|
mov ebx,[esi].HFEnemy.kind
|
|
cmp [esi].HFEnemy.cooldown,0
|
|
jne hf_ai_spacing
|
|
cmp distance,FP_1*7/10
|
|
jbe hf_ai_windup
|
|
cmp ebx,1
|
|
je hf_ai_move
|
|
hf_ai_windup:
|
|
mov [esi].HFEnemy.pose,4
|
|
mov [esi].HFEnemy.timer,12
|
|
jmp hf_ai_next
|
|
hf_ai_projectile:
|
|
invoke HFSpawnBolt,[esi].HFEnemy.x,[esi].HFEnemy.y,hfMonsterDamage[ebx*4]
|
|
jmp hf_ai_attack_pose
|
|
hf_ai_melee:
|
|
invoke HFDamagePlayer,hfMonsterDamage[ebx*4]
|
|
hf_ai_attack_pose:
|
|
mov [esi].HFEnemy.pose,5
|
|
mov [esi].HFEnemy.timer,10
|
|
mov [esi].HFEnemy.cooldown,55
|
|
cmp ebx,3
|
|
jne hf_ai_next
|
|
mov [esi].HFEnemy.cooldown,18
|
|
jmp hf_ai_next
|
|
hf_ai_spacing:
|
|
cmp distance,FP_1*7/10
|
|
jb hf_ai_next
|
|
cmp ebx,1
|
|
je hf_ai_move
|
|
cmp distance,4*FP_1
|
|
jb hf_ai_next
|
|
hf_ai_move:
|
|
invoke HFMoveEnemy,esi
|
|
hf_ai_next:
|
|
add esi,SIZEOF HFEnemy
|
|
dec edi
|
|
jnz hf_ai_enemy
|
|
ret
|
|
HFEnemiesTick ENDP
|
|
|
|
HFBoltsTick PROC uses esi edi
|
|
mov esi,OFFSET hfBolts
|
|
mov edi,32
|
|
hf_projectile:
|
|
cmp [esi].HFBolt.life,0
|
|
je hf_projectile_next
|
|
dec [esi].HFBolt.life
|
|
mov eax,[esi].HFBolt.vx
|
|
add [esi].HFBolt.x,eax
|
|
mov eax,[esi].HFBolt.vy
|
|
add [esi].HFBolt.y,eax
|
|
invoke CanWalk3D,[esi].HFBolt.x,[esi].HFBolt.y
|
|
test eax,eax
|
|
jz hf_projectile_destroy
|
|
invoke HFDistance,[esi].HFBolt.x,[esi].HFBolt.y,playerX,playerY
|
|
cmp eax,FP_1*3/10
|
|
ja hf_projectile_next
|
|
invoke HFDamagePlayer,[esi].HFBolt.damage
|
|
hf_projectile_destroy:
|
|
mov [esi].HFBolt.life,0
|
|
hf_projectile_next:
|
|
add esi,SIZEOF HFBolt
|
|
dec edi
|
|
jnz hf_projectile
|
|
ret
|
|
HFBoltsTick ENDP
|
|
|
|
HFPickups PROC uses esi edi ebx
|
|
xor ebx,ebx
|
|
mov esi,OFFSET hfItemSeeds
|
|
hf_pickup:
|
|
cmp hfItemTaken[ebx*4],0
|
|
jne hf_pickup_next
|
|
invoke HFDistance,playerX,playerY,[esi],[esi+4]
|
|
cmp eax,FP_1*3/5
|
|
ja hf_pickup_next
|
|
mov edi,[esi+8]
|
|
cmp edi,0
|
|
jne hf_pick_armor
|
|
cmp hfHealth,100
|
|
jae hf_pickup_next
|
|
add hfHealth,25
|
|
cmp hfHealth,100
|
|
jbe hf_pick_commit
|
|
mov hfHealth,100
|
|
jmp hf_pick_commit
|
|
hf_pick_armor:
|
|
cmp edi,1
|
|
jne hf_pick_bullets
|
|
cmp hfArmor,100
|
|
jae hf_pickup_next
|
|
mov hfArmor,100
|
|
jmp hf_pick_commit
|
|
hf_pick_bullets:
|
|
cmp edi,2
|
|
jne hf_pick_shells
|
|
add hfBullets,40
|
|
jmp hf_pick_commit
|
|
hf_pick_shells:
|
|
cmp edi,3
|
|
jne hf_pick_shotgun
|
|
add hfShells,12
|
|
jmp hf_pick_commit
|
|
hf_pick_shotgun:
|
|
cmp edi,4
|
|
jne hf_pick_key
|
|
mov hfHasShotgun,1
|
|
mov hfWeapon,1
|
|
add hfShells,16
|
|
jmp hf_pick_commit
|
|
hf_pick_key:
|
|
mov hfKey,1
|
|
hf_pick_commit:
|
|
mov hfItemTaken[ebx*4],1
|
|
mov hfMessage,OFFSET hfPickupText
|
|
cmp edi,5
|
|
jne @F
|
|
mov hfMessage,OFFSET hfKeyFoundText
|
|
@@:
|
|
mov hfMessageTime,105
|
|
invoke HFPlaySound,3
|
|
hf_pickup_next:
|
|
add esi,12
|
|
inc ebx
|
|
cmp ebx,HF_ITEMS
|
|
jb hf_pickup
|
|
ret
|
|
HFPickups ENDP
|
|
|
|
HFUse PROC uses ebx esi
|
|
invoke HFDistance,playerX,playerY,FP_1*11/2,FP_1*25/2
|
|
cmp eax,FP_1*8/5
|
|
ja hf_use_secret_two
|
|
test hfDoorMask,1
|
|
jnz hf_use_secret_two
|
|
or hfDoorMask,1
|
|
mov hfMap[12*32+5],0
|
|
mov hfMap[12*32+6],0
|
|
jmp hf_use_secret
|
|
hf_use_secret_two:
|
|
invoke HFDistance,playerX,playerY,FP_1*45/2,27*FP_1
|
|
cmp eax,FP_1*8/5
|
|
ja hf_use_gate
|
|
test hfDoorMask,2
|
|
jnz hf_use_gate
|
|
or hfDoorMask,2
|
|
mov hfMap[26*32+22],0
|
|
mov hfMap[27*32+22],0
|
|
hf_use_secret:
|
|
inc hfSecrets
|
|
mov hfMessage,OFFSET hfSecretText
|
|
mov hfMessageTime,105
|
|
invoke HFPlaySound,5
|
|
ret
|
|
hf_use_gate:
|
|
invoke HFDistance,playerX,playerY,FP_1*45/2,7*FP_1
|
|
cmp eax,2*FP_1
|
|
ja hf_use_exit
|
|
cmp hfKey,0
|
|
jne hf_use_unlock
|
|
mov hfMessage,OFFSET hfNeedKeyText
|
|
mov hfMessageTime,105
|
|
ret
|
|
hf_use_unlock:
|
|
mov hfMap[6*32+22],0
|
|
mov hfMap[7*32+22],0
|
|
or hfDoorMask,4
|
|
mov hfMessage,OFFSET hfDoorText
|
|
mov hfMessageTime,105
|
|
invoke HFPlaySound,5
|
|
ret
|
|
hf_use_exit:
|
|
invoke HFDistance,playerX,playerY,28*FP_1,29*FP_1
|
|
cmp eax,2*FP_1
|
|
ja hf_use_done
|
|
mov esi,OFFSET hfEnemies
|
|
mov ebx,HF_ENEMIES
|
|
@@:
|
|
cmp [esi].HFEnemy.kind,3
|
|
jne hf_exit_next
|
|
cmp [esi].HFEnemy.hp,0
|
|
jg hf_exit_locked
|
|
hf_exit_next:
|
|
add esi,SIZEOF HFEnemy
|
|
dec ebx
|
|
jnz @B
|
|
mov hfState,2
|
|
mov hfFireHeld,0
|
|
mov hfMessageTime,0
|
|
cmp hfCompleted,0
|
|
jne hf_use_done
|
|
mov hfCompleted,1
|
|
mov hfAwarded,1
|
|
invoke ArtifactCredit3D,6660
|
|
call SaveProgress3D
|
|
ret
|
|
hf_exit_locked:
|
|
mov hfMessage,OFFSET hfExitText
|
|
mov hfMessageTime,105
|
|
hf_use_done:
|
|
ret
|
|
HFUse ENDP
|
|
|
|
HFTick PROC uses esi ecx
|
|
mov esi,OFFSET hfImpacts
|
|
mov ecx,HF_SHOT_PELLETS
|
|
hf_impact_tick:
|
|
cmp [esi].HFImpact.life,0
|
|
je @F
|
|
dec [esi].HFImpact.life
|
|
@@:
|
|
add esi,SIZEOF HFImpact
|
|
loop hf_impact_tick
|
|
inc hfTicks
|
|
cmp hfCooldown,0
|
|
je @F
|
|
dec hfCooldown
|
|
@@:
|
|
cmp hfFlash,0
|
|
je @F
|
|
dec hfFlash
|
|
@@:
|
|
cmp hfHurt,0
|
|
je @F
|
|
dec hfHurt
|
|
@@:
|
|
cmp hfMessageTime,0
|
|
je @F
|
|
dec hfMessageTime
|
|
@@:
|
|
mov eax,hfFireHeld
|
|
or eax,hfFirePending
|
|
or al,keys3D[20h]
|
|
jz @F
|
|
call HFFire
|
|
@@:
|
|
mov hfFirePending,0
|
|
cmp hfUsePending,0
|
|
je @F
|
|
mov hfUsePending,0
|
|
call HFUse
|
|
@@:
|
|
cmp hfState,0
|
|
jne hf_tick_done
|
|
mov eax,hfTicks
|
|
and eax,7
|
|
jnz @F
|
|
call HFBuildFlow
|
|
@@:
|
|
call HFEnemiesTick
|
|
call HFBoltsTick
|
|
cmp hfState,0
|
|
jne hf_tick_done
|
|
call HFPickups
|
|
; Central lava channel: visible floor patch exactly matches damage bounds.
|
|
mov eax,hfTicks
|
|
xor edx,edx
|
|
mov ecx,18
|
|
div ecx
|
|
test edx,edx
|
|
jnz hf_tick_done
|
|
cmp playerX,16*FP_1
|
|
jb hf_tick_done
|
|
cmp playerX,18*FP_1
|
|
jae hf_tick_done
|
|
cmp playerY,17*FP_1
|
|
jb hf_tick_done
|
|
cmp playerY,20*FP_1
|
|
jae hf_tick_done
|
|
invoke HFDamagePlayer,8
|
|
hf_tick_done:
|
|
ret
|
|
HFTick ENDP
|