Center resting barrels and anchor every firing pose to the HUD edge. Add native framebuffer regression checks for all nine poses and update game assets, binaries and launcher integrity hash.
568 lines
15 KiB
PHP
568 lines
15 KiB
PHP
.data
|
|
hfTestStage dd 1
|
|
hfTestIo dd 0
|
|
hfTestFrame db 'build\scratch\hell-entry.bgra',0
|
|
hfTestCourt db 'build\scratch\hell-court.bgra',0
|
|
hfTestHall db 'build\scratch\hell-portal.bgra',0
|
|
hfTestWin db 'build\scratch\hell-victory.bgra',0
|
|
hfTestPreview db 'build\scratch\hf-prev.dat',0
|
|
hfTestProfileDir db 'build\scratch',0
|
|
hfTestProfileName db 'hell-profile.dat',0
|
|
hfTestBoss dd 0
|
|
hfTestStrafe dd 5000
|
|
hfTestWeaponBase0 db 'build\scratch\hell-weapon-pistol-base.bgra',0
|
|
hfTestWeaponBase1 db 'build\scratch\hell-weapon-shotgun-base.bgra',0
|
|
hfTestWeapon0 db 'build\scratch\hell-weapon-0.bgra',0
|
|
hfTestWeapon1 db 'build\scratch\hell-weapon-1.bgra',0
|
|
hfTestWeapon2 db 'build\scratch\hell-weapon-2.bgra',0
|
|
hfTestWeapon3 db 'build\scratch\hell-weapon-3.bgra',0
|
|
hfTestWeapon4 db 'build\scratch\hell-weapon-4.bgra',0
|
|
hfTestWeapon5 db 'build\scratch\hell-weapon-5.bgra',0
|
|
hfTestWeapon6 db 'build\scratch\hell-weapon-6.bgra',0
|
|
hfTestWeapon7 db 'build\scratch\hell-weapon-7.bgra',0
|
|
hfTestWeapon8 db 'build\scratch\hell-weapon-8.bgra',0
|
|
; Weapon, cooldown (-1 hides both packs for a clean reference), capture path.
|
|
hfTestWeaponCases dd 0,-1,OFFSET hfTestWeaponBase0
|
|
dd 0,0,OFFSET hfTestWeapon0
|
|
dd 0,9,OFFSET hfTestWeapon1
|
|
dd 0,7,OFFSET hfTestWeapon2
|
|
dd 0,5,OFFSET hfTestWeapon3
|
|
dd 0,3,OFFSET hfTestWeapon4
|
|
dd 1,-1,OFFSET hfTestWeaponBase1
|
|
dd 1,0,OFFSET hfTestWeapon5
|
|
dd 1,29,OFFSET hfTestWeapon6
|
|
dd 1,18,OFFSET hfTestWeapon7
|
|
dd 1,10,OFFSET hfTestWeapon8
|
|
HFTestCapture PROTO :DWORD
|
|
.code
|
|
HFTestWeaponFrames PROC uses esi ebx
|
|
local pistolPixels:DWORD,shotgunPixels:DWORD
|
|
mov eax,hfPistol.pixels
|
|
mov pistolPixels,eax
|
|
mov eax,hfShotgun.pixels
|
|
mov shotgunPixels,eax
|
|
call HFReset
|
|
mov hfHasShotgun,1
|
|
mov esi,OFFSET hfTestWeaponCases
|
|
mov ebx,11
|
|
hf_test_weapon_frame:
|
|
mov eax,[esi]
|
|
mov hfWeapon,eax
|
|
mov eax,[esi+4]
|
|
mov hfCooldown,eax
|
|
cmp eax,-1
|
|
jne @F
|
|
mov hfCooldown,0
|
|
mov hfPistol.pixels,0
|
|
mov hfShotgun.pixels,0
|
|
@@:
|
|
call RenderHellFPS3D
|
|
invoke HFTestCapture,DWORD PTR [esi+8]
|
|
mov eax,pistolPixels
|
|
mov hfPistol.pixels,eax
|
|
mov eax,shotgunPixels
|
|
mov hfShotgun.pixels,eax
|
|
add esi,12
|
|
dec ebx
|
|
jnz hf_test_weapon_frame
|
|
call HFReset
|
|
ret
|
|
HFTestWeaponFrames ENDP
|
|
|
|
HFTestAimBoss PROC uses esi edi ebx
|
|
local vx:DWORD,vy:DWORD,best:DWORD
|
|
mov esi,hfTestBoss
|
|
mov eax,[esi].HFEnemy.x
|
|
sub eax,playerX
|
|
sar eax,8
|
|
mov vx,eax
|
|
mov eax,[esi].HFEnemy.y
|
|
sub eax,playerY
|
|
sar eax,8
|
|
mov vy,eax
|
|
mov best,80000000h
|
|
xor edi,edi
|
|
hf_test_aim_angle:
|
|
mov eax,tableCos[edi*4]
|
|
sar eax,8
|
|
imul eax,vx
|
|
mov ebx,eax
|
|
mov eax,tableSin[edi*4]
|
|
sar eax,8
|
|
imul eax,vy
|
|
add eax,ebx
|
|
cmp eax,best
|
|
jle @F
|
|
mov best,eax
|
|
mov playerAngle,edi
|
|
@@:
|
|
inc edi
|
|
cmp edi,512
|
|
jb hf_test_aim_angle
|
|
ret
|
|
HFTestAimBoss ENDP
|
|
|
|
HFTestCapture PROC uses ebx path:DWORD
|
|
invoke CreateFileA,path,40000000h,0,0,2,80h,0
|
|
mov ebx,eax
|
|
invoke WriteFile,ebx,OFFSET screenBuffer,SCREEN_SIZE*4,OFFSET hfTestIo,0
|
|
invoke CloseHandle,ebx
|
|
ret
|
|
HFTestCapture ENDP
|
|
|
|
RunHellFPSTest PROC uses esi edi ebx
|
|
call InitHall3D
|
|
call LoadTextures3D
|
|
call LoadHallAssets3D
|
|
call InitializeCasinoSprites3D
|
|
mov hfTestStage,2
|
|
call HFLoad
|
|
test eax,eax
|
|
jz hf_test_fail
|
|
mov playerX,HF_PORTAL_X
|
|
mov playerY,29*FP_1
|
|
mov playerAngle,128
|
|
mov engineMode,MODE_WALK
|
|
call UpdateCamera3D
|
|
call CheckHallInteractions3D
|
|
; Approach must be within the standard interaction distance.
|
|
mov playerY,FP_1*294/10
|
|
call CheckHallInteractions3D
|
|
cmp interactTargetId,INTERACT_HELL_FPS
|
|
jne hf_test_fail
|
|
invoke CanWalk3D,HF_PORTAL_X,FP_1*294/10
|
|
cmp eax,1
|
|
jne hf_test_fail
|
|
; Old standing frame no longer blocks the west aisle.
|
|
invoke CanWalk3D,FP_1*25/10,11*FP_1
|
|
cmp eax,1
|
|
jne hf_test_fail
|
|
mov playerX,4*FP_1
|
|
mov playerY,12*FP_1
|
|
mov playerAngle,256
|
|
call UpdateCamera3D
|
|
mov interactTargetId,0
|
|
call CheckHallInteractions3D
|
|
cmp interactTargetId,INTERACT_HELL_FPS
|
|
je hf_test_fail
|
|
mov playerX,HF_PORTAL_X
|
|
mov playerY,FP_1*255/10
|
|
mov playerAngle,128
|
|
call UpdateCamera3D
|
|
call RenderCeilingAndFloor
|
|
call RenderWalls
|
|
call PrepareCityDepth3D
|
|
call RenderHall3D
|
|
invoke HFTestCapture,OFFSET hfTestHall
|
|
mov hfOldX,HF_PORTAL_X
|
|
mov hfOldY,FP_1*294/10
|
|
mov hfOldAngle,128
|
|
mov hfOldMap,OFFSET casinoMap
|
|
mov hfOldFloor,100
|
|
mov hfOldLevel,0
|
|
mov hfOldEye,HALL_STANDING_EYE
|
|
mov hfOldCeiling,FP_1*5/2
|
|
call HFReset
|
|
mov hfTestStage,3
|
|
call HFTestWeaponFrames
|
|
call RenderHellFPS3D
|
|
invoke HFTestCapture,OFFSET hfTestFrame
|
|
invoke HFLineClear,3*FP_1+FP_HALF,26*FP_1+FP_HALF,7*FP_1+FP_HALF,26*FP_1+FP_HALF
|
|
cmp eax,1
|
|
jne hf_test_fail
|
|
invoke HFLineClear,3*FP_1+FP_HALF,26*FP_1+FP_HALF,13*FP_1,26*FP_1+FP_HALF
|
|
test eax,eax
|
|
jnz hf_test_fail
|
|
invoke CanWalk3D,0,0
|
|
test eax,eax
|
|
jnz hf_test_fail
|
|
mov hfTestStage,4
|
|
; Same hitscan must stop at wall, then damage the nearest target in open space.
|
|
mov hfEnemies.x,12*FP_1
|
|
mov hfEnemies.y,26*FP_1+FP_HALF
|
|
mov hfEnemies.hp,100
|
|
mov hfEnemies[SIZEOF HFEnemy].hp,0
|
|
call HFFire
|
|
cmp hfEnemies.hp,100
|
|
jne hf_test_fail
|
|
mov hfEnemies.x,7*FP_1
|
|
mov hfCooldown,0
|
|
call HFFire
|
|
cmp hfEnemies.hp,100
|
|
jae hf_test_fail
|
|
cmp hfBullets,78
|
|
jne hf_test_fail
|
|
mov hfTestStage,5
|
|
mov bankroll,12345
|
|
invoke HFPlayerCanWalk,hfEnemies.x,hfEnemies.y
|
|
test eax,eax
|
|
jnz hf_test_fail
|
|
mov hfArmor,20
|
|
invoke HFDamagePlayer,10
|
|
cmp hfHealth,95
|
|
jne hf_test_fail
|
|
cmp hfArmor,15
|
|
jne hf_test_fail
|
|
mov hfArmor,0
|
|
invoke HFDamagePlayer,1000
|
|
cmp hfState,1
|
|
jne hf_test_fail
|
|
call HFReset
|
|
cmp hfState,0
|
|
jne hf_test_fail
|
|
cmp hfHealth,100
|
|
jne hf_test_fail
|
|
cmp bankroll,12345
|
|
jne hf_test_fail
|
|
; Natural shotgun pickup and consumption; no injected weapon ownership.
|
|
mov playerX,3*FP_1+FP_HALF
|
|
mov playerY,27*FP_1+FP_HALF
|
|
call HFPickups
|
|
cmp hfHasShotgun,1
|
|
jne hf_test_fail
|
|
cmp hfShells,16
|
|
jne hf_test_fail
|
|
call HFFire
|
|
cmp hfShells,15
|
|
jne hf_test_fail
|
|
mov hfTestStage,12
|
|
; Three separated targets: pistol hits centre only; one shell hits all three.
|
|
call HFReset
|
|
mov esi,OFFSET hfEnemies
|
|
mov ecx,HF_ENEMIES
|
|
@@:
|
|
mov [esi].HFEnemy.hp,0
|
|
add esi,SIZEOF HFEnemy
|
|
loop @B
|
|
mov hfEnemies.x,8*FP_1
|
|
mov hfEnemies.y,FP_1*103/4
|
|
mov hfEnemies.hp,1000
|
|
mov hfEnemies[SIZEOF HFEnemy].x,8*FP_1
|
|
mov hfEnemies[SIZEOF HFEnemy].y,FP_1*106/4
|
|
mov hfEnemies[SIZEOF HFEnemy].hp,1000
|
|
mov hfEnemies[2*SIZEOF HFEnemy].x,8*FP_1
|
|
mov hfEnemies[2*SIZEOF HFEnemy].y,FP_1*109/4
|
|
mov hfEnemies[2*SIZEOF HFEnemy].hp,1000
|
|
call HFFire
|
|
cmp hfEnemies.hp,1000
|
|
jne hf_test_fail
|
|
cmp hfEnemies[SIZEOF HFEnemy].hp,1000
|
|
jae hf_test_fail
|
|
cmp hfEnemies[2*SIZEOF HFEnemy].hp,1000
|
|
jne hf_test_fail
|
|
mov hfCooldown,0
|
|
mov hfWeapon,1
|
|
mov hfShells,2
|
|
call HFFire
|
|
cmp hfShells,1
|
|
jne hf_test_fail
|
|
cmp hfEnemies.hp,1000
|
|
jae hf_test_fail
|
|
cmp hfEnemies[2*SIZEOF HFEnemy].hp,1000
|
|
jae hf_test_fail
|
|
mov esi,OFFSET hfImpacts
|
|
mov ecx,HF_SHOT_PELLETS
|
|
@@:
|
|
cmp [esi].HFImpact.life,8
|
|
jne hf_test_fail
|
|
add esi,SIZEOF HFImpact
|
|
loop @B
|
|
; The whole pellet cone must stop at the separating wall.
|
|
mov hfEnemies.x,12*FP_1
|
|
mov hfEnemies.hp,1000
|
|
mov hfEnemies[SIZEOF HFEnemy].x,12*FP_1
|
|
mov hfEnemies[SIZEOF HFEnemy].hp,1000
|
|
mov hfEnemies[2*SIZEOF HFEnemy].x,12*FP_1
|
|
mov hfEnemies[2*SIZEOF HFEnemy].hp,1000
|
|
mov hfCooldown,0
|
|
call HFFire
|
|
cmp hfEnemies.hp,1000
|
|
jne hf_test_fail
|
|
cmp hfEnemies[SIZEOF HFEnemy].hp,1000
|
|
jne hf_test_fail
|
|
cmp hfEnemies[2*SIZEOF HFEnemy].hp,1000
|
|
jne hf_test_fail
|
|
cmp hfShells,0
|
|
jne hf_test_fail
|
|
mov hfCooldown,0
|
|
call HFFire
|
|
cmp hfCooldown,0
|
|
jne hf_test_fail
|
|
call HFReset
|
|
mov hfTestStage,6
|
|
mov playerX,21*FP_1+FP_HALF
|
|
mov playerY,6*FP_1+FP_HALF
|
|
call HFUse
|
|
cmp hfMap[6*32+22],188
|
|
jne hf_test_fail
|
|
mov playerX,20*FP_1+FP_HALF
|
|
mov playerY,3*FP_1+FP_HALF
|
|
call HFPickups
|
|
cmp hfKey,1
|
|
jne hf_test_fail
|
|
mov playerX,21*FP_1+FP_HALF
|
|
mov playerY,6*FP_1+FP_HALF
|
|
call HFUse
|
|
cmp hfMap[6*32+22],0
|
|
jne hf_test_fail
|
|
mov playerX,5*FP_1+FP_HALF
|
|
mov playerY,13*FP_1+FP_HALF
|
|
call HFUse
|
|
call HFUse
|
|
cmp hfSecrets,1
|
|
jne hf_test_fail
|
|
mov playerX,23*FP_1
|
|
mov playerY,27*FP_1
|
|
call HFUse
|
|
cmp hfSecrets,2
|
|
jne hf_test_fail
|
|
mov hfTestStage,7
|
|
; Real AI/projectile/pickup loop stress; no alternate Python simulation.
|
|
call HFReset
|
|
mov playerX,14*FP_1
|
|
mov playerY,21*FP_1
|
|
mov playerAngle,430
|
|
mov hfWeapon,1
|
|
mov hfHasShotgun,1
|
|
mov hfShells,80
|
|
mov hfFireHeld,1
|
|
mov ebx,1050
|
|
hf_test_combat:
|
|
mov hfHealth,100
|
|
mov hfState,0
|
|
call HFTick
|
|
dec ebx
|
|
jnz hf_test_combat
|
|
mov hfFireHeld,0
|
|
call RenderHellFPS3D
|
|
invoke HFTestCapture,OFFSET hfTestCourt
|
|
mov hfTestStage,11
|
|
; Isolated boss encounter: real pickups, finite ammo, normal damage and ticks.
|
|
call HFReset
|
|
mov esi,OFFSET hfEnemies
|
|
mov ecx,HF_ENEMIES
|
|
hf_test_isolate_boss:
|
|
cmp [esi].HFEnemy.kind,3
|
|
jne hf_test_disable_enemy
|
|
mov hfTestBoss,esi
|
|
jmp @F
|
|
hf_test_disable_enemy:
|
|
mov [esi].HFEnemy.hp,0
|
|
@@:
|
|
add esi,SIZEOF HFEnemy
|
|
loop hf_test_isolate_boss
|
|
mov playerX,3*FP_1+FP_HALF
|
|
mov playerY,27*FP_1+FP_HALF
|
|
call HFPickups
|
|
mov playerX,4*FP_1+FP_HALF
|
|
mov playerY,28*FP_1+FP_HALF
|
|
call HFPickups
|
|
mov playerX,8*FP_1+FP_HALF
|
|
mov playerY,14*FP_1+FP_HALF
|
|
call HFPickups
|
|
mov playerX,27*FP_1+FP_HALF
|
|
mov playerY,24*FP_1+FP_HALF
|
|
mov playerAngle,128
|
|
mov hfFireHeld,1
|
|
mov ebx,1400
|
|
hf_test_boss_fight:
|
|
cmp playerX,28*FP_1+FP_HALF
|
|
jl @F
|
|
mov hfTestStrafe,-5000
|
|
@@:
|
|
cmp playerX,26*FP_1+FP_HALF
|
|
jg @F
|
|
mov hfTestStrafe,5000
|
|
@@:
|
|
mov eax,playerX
|
|
add eax,hfTestStrafe
|
|
push eax
|
|
invoke HFPlayerCanWalk,eax,playerY
|
|
pop ecx
|
|
test eax,eax
|
|
jz @F
|
|
mov playerX,ecx
|
|
@@:
|
|
call HFTestAimBoss
|
|
call HFTick
|
|
cmp hfState,0
|
|
jne hf_test_fail
|
|
cmp hfKills,1
|
|
je hf_test_boss_killed
|
|
dec ebx
|
|
jnz hf_test_boss_fight
|
|
jmp hf_test_fail
|
|
hf_test_boss_killed:
|
|
mov hfFireHeld,0
|
|
mov hfTestStage,8
|
|
; Locked exit, then one-time reward, then repeat use cannot pay twice.
|
|
call HFReset
|
|
mov bankroll,10000
|
|
mov hfCompleted,0
|
|
mov playerX,28*FP_1
|
|
mov playerY,28*FP_1
|
|
call HFUse
|
|
cmp hfState,0
|
|
jne hf_test_fail
|
|
mov esi,OFFSET hfEnemies
|
|
mov ecx,HF_ENEMIES
|
|
@@:
|
|
mov [esi].HFEnemy.hp,0
|
|
add esi,SIZEOF HFEnemy
|
|
loop @B
|
|
call HFUse
|
|
cmp hfState,2
|
|
jne hf_test_fail
|
|
cmp bankroll,16660
|
|
jne hf_test_fail
|
|
call HFUse
|
|
cmp bankroll,16660
|
|
jne hf_test_fail
|
|
mov playerX,26*FP_1
|
|
mov playerY,24*FP_1
|
|
mov playerAngle,96
|
|
mov hfTicks,18000
|
|
mov hfKills,28
|
|
mov hfSecrets,2
|
|
call RenderHellFPS3D
|
|
invoke HFTestCapture,OFFSET hfTestWin
|
|
mov hfTestStage,9
|
|
; Save extension survives native signed profile round trip.
|
|
mov nativeProfilesDirPtr3D,OFFSET hfTestProfileDir
|
|
mov nativeProfileActive3D,1
|
|
invoke CopyCString,OFFSET saveFileName,OFFSET hfTestProfileName
|
|
call BuildNativeProfileDir3D
|
|
call SaveGame
|
|
mov hfCompleted,0
|
|
call LoadSave
|
|
cmp hfCompleted,1
|
|
jne hf_test_fail
|
|
cmp bankroll,16660
|
|
jne hf_test_fail
|
|
mov hfTestStage,10
|
|
; Preview save uses the same new bit without changing its 40-byte format.
|
|
mov nativeProfileActive3D,0
|
|
mov arrivalConfirmed3D,1
|
|
invoke CopyCString,OFFSET savePath3D,OFFSET hfTestPreview
|
|
call SaveProgress3D
|
|
mov hfCompleted,0
|
|
call LoadProgress3D
|
|
cmp hfCompleted,1
|
|
jne hf_test_fail
|
|
cmp bankroll,16660
|
|
jne hf_test_fail
|
|
mov arrivalConfirmed3D,0
|
|
call LeaveHellFPS3D
|
|
cmp engineMode,MODE_WALK
|
|
jne hf_test_fail
|
|
cmp playerX,HF_PORTAL_X
|
|
jne hf_test_fail
|
|
cmp hallLevel3D,0
|
|
jne hf_test_fail
|
|
call FreeHellFPS3D
|
|
xor eax,eax
|
|
ret
|
|
hf_test_fail:
|
|
mov eax,hfTestStage
|
|
ret
|
|
RunHellFPSTest ENDP
|
|
|
|
IFDEF HELL_FPS_WINDOW_TEST
|
|
.data
|
|
hfWindowShot db 'build\scratch\hell-window.bgra',0
|
|
hfMusicStatus db 'status hellmusic mode',0
|
|
hfAudioMode db 32 dup(0)
|
|
.code
|
|
RunHellFPSWindowTest PROC uses esi ebx
|
|
call InitPaths3D
|
|
call Create3DWindow
|
|
test eax,eax
|
|
jz hf_window_failed
|
|
; Keep test window modest and avoid taking keyboard/mouse focus.
|
|
cmp fullscreen3D,0
|
|
je @F
|
|
call ToggleFullscreen3D
|
|
@@:
|
|
invoke SetWindowPos,h3DWnd,0,80,80,800,640,14h
|
|
call InitHall3D
|
|
call LoadTextures3D
|
|
call LoadHallAssets3D
|
|
call InitializeCasinoSprites3D
|
|
mov playerX,HF_PORTAL_X
|
|
mov playerY,FP_1*294/10
|
|
mov playerAngle,128
|
|
mov engineMode,MODE_WALK
|
|
call BeginHellFPS3D
|
|
cmp engineMode,MODE_HELL_FPS
|
|
jne hf_window_failed
|
|
cmp hfMusicError,0
|
|
jne hf_window_failed
|
|
cmp hfSoundFailures,0
|
|
jne hf_window_failed
|
|
cmp hfVolumeError,0
|
|
jne hf_window_failed
|
|
mov settingsVolume,10
|
|
call HFUpdateMusicVolume
|
|
cmp hfVolumeError,0
|
|
jne hf_window_failed
|
|
mov eax,SIZEOF hfVolumePrefix-1
|
|
cmp DWORD PTR hfVolumeCommand[eax],00303533h ; "350", not full volume 1000
|
|
jne hf_window_failed
|
|
mov settingsVolume,0
|
|
call HFUpdateMusicVolume
|
|
cmp hfVolumeError,0
|
|
jne hf_window_failed
|
|
mov eax,SIZEOF hfVolumePrefix-1
|
|
cmp WORD PTR hfVolumeCommand[eax],0030h
|
|
jne hf_window_failed
|
|
mov settingsVolume,5
|
|
call HFUpdateMusicVolume
|
|
cmp hfVolumeError,0
|
|
jne hf_window_failed
|
|
invoke ShowWindow,h3DWnd,4
|
|
mov esi,120
|
|
hf_window_frame:
|
|
invoke PeekMessageA,OFFSET msg3D,0,0,0,PM_REMOVE
|
|
test eax,eax
|
|
jz hf_window_simulate
|
|
invoke TranslateMessage,OFFSET msg3D
|
|
invoke DispatchMessageA,OFFSET msg3D
|
|
jmp hf_window_frame
|
|
hf_window_simulate:
|
|
mov deltaTime3D,17
|
|
add animationClock3D,17
|
|
cmp esi,110
|
|
jne @F
|
|
invoke WindowEvents3D,h3DWnd,201h,1,0
|
|
@@:
|
|
cmp esi,35
|
|
jne @F
|
|
invoke WindowEvents3D,h3DWnd,202h,0,0
|
|
@@:
|
|
call HandleHellFPS3D
|
|
call RenderHellFPS3D
|
|
call Present3D
|
|
invoke Sleep,17
|
|
dec esi
|
|
jnz hf_window_frame
|
|
invoke HFTestCapture,OFFSET hfWindowShot
|
|
cmp hfBullets,80
|
|
jae hf_window_failed
|
|
cmp hfFireHeld,0
|
|
jne hf_window_failed
|
|
invoke mciSendStringA,OFFSET hfMusicStatus,OFFSET hfAudioMode,32,0
|
|
test eax,eax
|
|
jnz hf_window_failed
|
|
cmp DWORD PTR hfAudioMode,'yalp'
|
|
jne hf_window_failed
|
|
call LeaveHellFPS3D
|
|
call FreeHellFPS3D
|
|
invoke DestroyWindow,h3DWnd
|
|
xor eax,eax
|
|
ret
|
|
hf_window_failed:
|
|
call FreeHellFPS3D
|
|
mov eax,111
|
|
ret
|
|
RunHellFPSWindowTest ENDP
|
|
ENDIF
|