Decouple gameplay from presentation and preserve signed movement fractions. Separate cinematic camera ownership with safe body handoff and transactional current-room restarts. Resample input latches on focus regain, discard modal timing debt, and attach cinematic lighting to the view to match editor preview. Verify editor 137/137 and ASM 288/288, cinematic traces, RGB bake and IPC framebuffer parity without changing project assets.
369 lines
14 KiB
PHP
369 lines
14 KiB
PHP
|
||
COMM screenBuffer:BYTE:FRAME_BUFFER_SIZE
|
||
COMM textureBuffer:BYTE:MAX_TEXTURES * TEX_SIZE_BYTES
|
||
COMM portalTextureBuffer:BYTE:TEX_SIZE_BYTES
|
||
COMM texturePackStaging:BYTE:MAX_TEXTURES * TEX_SIZE_BYTES
|
||
; ==============================================================================
|
||
; EBLAN ENGINE - Global State and Data Structures
|
||
; ==============================================================================
|
||
|
||
.data
|
||
; Window and GDI
|
||
szClassName db "EblanEngine3DWndClass",0
|
||
szWindowTitle db "EBLAN ENGINE 3D - Retro Raycaster [Pure x86 Assembly]",0
|
||
hEngineWnd dd 0
|
||
hEngineDC dd 0
|
||
hEngineInstance dd 0
|
||
isRunning dd 1
|
||
|
||
; High Precision Timing
|
||
; Latched by UpdatePlayer: scene/end/skip/instant-transition ticks never run AI
|
||
; or combat, even if they return control partway through the tick.
|
||
gameplayTickBlocked dd 0
|
||
qpcFrequency dq 0
|
||
qpcPrevious dq 0
|
||
qpcNow dq 0
|
||
tickAccumulator dq 0 ; QPC counts multiplied by 60
|
||
clockReset dd 0
|
||
simulationTicks dd 0
|
||
simulationState dd 0
|
||
inputFocused dd 1
|
||
playerFractionX dd 0 ; signed 16.16 remainder, truncated toward zero
|
||
playerFractionY dd 0
|
||
viewX dd 160
|
||
viewY dd 160
|
||
viewAngle dd 0
|
||
csCameraX dd 160
|
||
csCameraY dd 160
|
||
csCameraAngle dd 0
|
||
currentMapPath db MAX_PATH_BYTES dup(0)
|
||
roomEntryX dd 2
|
||
roomEntryY dd 2
|
||
roomEntryAngle dd 0
|
||
fpsCounter dd 0
|
||
fpsTimer dd 0
|
||
currentFps dd 60
|
||
szFpsLabel db "FPS: ",0
|
||
|
||
; Software Framebuffer & BITMAPINFO
|
||
ALIGN 4
|
||
bmiEngine BITMAPINFOHEADER <sizeof BITMAPINFOHEADER, SCREEN_W, -SCREEN_H, 1, 32, 0, 0, 0, 0, 0, 0>
|
||
dd 0 ; palette dummy
|
||
|
||
rngSeed dd 12345678h
|
||
|
||
; Player State
|
||
; Position in RAW world units (1 cell = 64 units; e.g. 160 = cell 2.5)
|
||
playerX dd 160
|
||
playerY dd 160
|
||
playerAngle dd 0 ; 0..511 (0 = East, 128 = South, 256 = West, 384 = North)
|
||
playerMoveSpeed dd 3 ; raw units per 60 Hz tick (walk)
|
||
playerRunSpeed dd 6 ; raw units per 60 Hz tick (sprint)
|
||
playerTurnSpeed dd 4 ; angle units per 60 Hz tick
|
||
playerRadius dd 16 ; collision radius (raw units)
|
||
|
||
; Input State Flags
|
||
keyForward db 0
|
||
keyBackward db 0
|
||
keyStrafeLeft db 0
|
||
keyStrafeRight db 0
|
||
keyTurnLeft db 0
|
||
keyTurnRight db 0
|
||
keyAction db 0
|
||
keyRun db 0
|
||
keyShowMap db 1 ; minimap toggle
|
||
keyScreenshot db 0 ; F12 screenshot request
|
||
keyActionHeld db 0
|
||
keyMapHeld db 0
|
||
keyShotHeld db 0
|
||
keyCutscene db 0
|
||
keySkipScene db 0
|
||
keySceneHeld db 0
|
||
keySkipHeld db 0
|
||
keyAttack db 0
|
||
keyAttackHeld db 0
|
||
keySpaceAttackHeld db 0
|
||
keyRestart db 0
|
||
keyRestartHeld db 0
|
||
keyWeapon1 db 0
|
||
keyWeapon2 db 0
|
||
keyWeapon3 db 0
|
||
keyWeapon4 db 0
|
||
keyPause db 0
|
||
keyPauseHeld db 0
|
||
keyHudStyleHeld db 0
|
||
keyMenuHeld db 0
|
||
keyFlashlight db 0
|
||
keyFlashlightHeld db 0
|
||
keyLightMode db 0
|
||
keyLightModeHeld db 0
|
||
keyMap db 0
|
||
keyHud db 0
|
||
keyWeaponHeld1 db 0
|
||
keyWeaponHeld2 db 0
|
||
keyWeaponHeld3 db 0
|
||
keyMenu1 db 0
|
||
keyMenu2 db 0
|
||
keyMenu3 db 0
|
||
keyMenu4 db 0
|
||
keyMenu5 db 0
|
||
keyMenuHeld1 db 0
|
||
keyMenuHeld2 db 0
|
||
keyMenuHeld3 db 0
|
||
keyMenuHeld4 db 0
|
||
keyMenuHeld5 db 0
|
||
keyDismiss db 0
|
||
keyDismissHeld db 0
|
||
isGamePaused dd 0
|
||
|
||
; Lighting Configuration & Dynamic State
|
||
lightingMode dd LIGHTING_MODE_NONE ; 0 = None, 1 = Baked, 2 = Dynamic+Baked (InitLightingSystem enables DYNAMIC)
|
||
ambientLightLevel dd 40 ; Base shadow level (40/256 = ~15% darkness)
|
||
isFlashlightOn dd 1 ; 1 = Player flashlight active
|
||
flashlightRadius dd 384 ; 6 cells distance
|
||
flashlightIntensity dd 240 ; Bright focused beam
|
||
flashlightConeAngle dd 45 ; Half-angle of beam (~32 degrees in 512-angle circle)
|
||
|
||
; Game Mode & HUD Configuration
|
||
gameMode dd GAME_MODE_ACTION ; 0 = Adventure (No weapons), 1 = Action / Combat
|
||
hudStyle dd HUD_STYLE_CLEAN ; 0 = Clean / Immersive, 1 = Debug / Classic
|
||
enableWeapons dd 1 ; 1 = Weapons active, 0 = Pure exploration
|
||
showCrosshair dd 1 ; 1 = Show crosshair in Action mode, 0 = Hidden
|
||
|
||
; Player Combat & Gameplay Stats
|
||
playerWeapon dd 1 ; Default: WEAPON_PISTOL
|
||
playerHealth dd 100
|
||
playerMaxHealth dd 100
|
||
playerAmmo dd 50
|
||
playerMaxAmmo dd 99
|
||
playerScore dd 0
|
||
playerKeys dd 0
|
||
playerAttackCooldown dd 0
|
||
playerFlashTimer dd 0
|
||
playerHitFlash dd 0
|
||
isPlayerDead dd 0
|
||
|
||
; Map palette (overridable by map.dat header)
|
||
mapCeilingColor dd COLOR_CEILING
|
||
mapFloorColor dd COLOR_FLOOR
|
||
szMapFilePath db "assets\map.dat",0
|
||
szAssetsPrefix db "assets\",0
|
||
startupMapPath db MAX_PATH_BYTES dup(0)
|
||
portalLatchCell dd -1 ; suppress repeated entry until the player leaves the cell
|
||
mapErrorFrames dd 0
|
||
|
||
; Sector Streaming & Portals
|
||
transitionCount dd 0
|
||
pendingMapPath db 64 dup(0)
|
||
szSublevelFullPath db 80 dup(0)
|
||
pendingSpawnX dd 0
|
||
pendingSpawnY dd 0
|
||
pendingSpawnAngle dd 0
|
||
|
||
; Screen Fade Transition State Machine
|
||
fadeState dd 0 ; 0 = None, 1 = Fading Out, 2 = Black / Switching, 3 = Fading In
|
||
fadeLevel dd 0 ; 0..16 (0 = visible, 16 = black)
|
||
|
||
; Texture pack (optional; falls back to procedural textures)
|
||
szTexPackPath db "assets\textures\texturepack.bin",0
|
||
texPackLoaded dd 0
|
||
|
||
; Sprite Manager
|
||
spriteCount dd 0
|
||
|
||
; Engine HUD & Strings
|
||
strControls1 db "WASD: Move / Strafe | Shift: Run",0
|
||
strControls2 db "Arrows: Turn Camera",0
|
||
strControls3 db "E:Use C:Scene M:Map F12:Shot Esc:Exit",0
|
||
strEngineName db "EBLAN ENGINE 3D (x86 MASM)",0
|
||
strDoorHint db "[E] - Door",0
|
||
strPortalHint db "[E] - Enter Portal",0
|
||
strMapLoadError db "Cannot load destination level",0
|
||
strSkipScene db "[Tab] Skip",0
|
||
strHpLabel db "HP:",0
|
||
strAmmoLabel db "AMMO:",0
|
||
strScoreLabel db "SCORE:",0
|
||
strKeysLabel db "KEY:",0
|
||
strWeaponLabel db "WPN:",0
|
||
strWeaponKnife db "KNIFE",0
|
||
strWeaponPistol db "PISTOL",0
|
||
strWeaponShotgun db "SHOTGUN",0
|
||
strPauseTitle db "== ПАУЗА ==",0
|
||
strPauseOpt1 db "[1] ПРОДОЛЖИТЬ",0
|
||
strPauseOpt2 db "[2] ОРУЖИЕ: ВКЛ/ВЫКЛ",0
|
||
strPauseOpt3 db "[3] ИНТЕРФЕЙС: ЧИСТЫЙ/ИНФО",0
|
||
strPauseOpt4 db "[4] ПЕРЕЗАПУСК УРОВНЯ",0
|
||
strPauseOpt5 db "[5] ВЫХОД В WINDOWS",0
|
||
strYouDied db "ВЫ ПОГИБЛИ! НАЖМИТЕ [R]",0
|
||
cutsceneCount dd 0
|
||
cutsceneStringCount dd 0
|
||
cutsceneFlags dd 0
|
||
isCutsceneActive dd 0
|
||
cutscenePending dd 0
|
||
cutsceneTick dd 0
|
||
cutsceneIndex dd 0
|
||
cutsceneWait dd 0
|
||
cutsceneSubtitle dd -1
|
||
cutsceneSubtitleUntil dd 0
|
||
cutsceneFade dd 0
|
||
csMoveFromX dd 0
|
||
csMoveFromY dd 0
|
||
csMoveToX dd 0
|
||
csMoveToY dd 0
|
||
csMoveDuration dd 0
|
||
csMoveElapsed dd 0
|
||
csAngleFrom dd 0
|
||
csAngleDelta dd 0
|
||
csAngleDuration dd 0
|
||
csAngleElapsed dd 0
|
||
csFadeFrom dd 0
|
||
csFadeTo dd 0
|
||
csFadeDuration dd 0
|
||
csFadeElapsed dd 0
|
||
csSoundPrefix db "assets\sounds\",0
|
||
csSoundPath db 128 dup(0)
|
||
csLineBuffer db 40 dup(0)
|
||
|
||
; Screenshot (F12): writes 32-bit top-down BMP of screenBuffer
|
||
szScreenshotPath db "screenshot.bmp",0
|
||
ALIGN 4
|
||
screenshotHeader db 'B','M'
|
||
dd (54 + FRAME_BUFFER_SIZE) ; bfSize
|
||
dd 0 ; bfReserved
|
||
dd 54 ; bfOffBits
|
||
dd 40 ; BITMAPINFOHEADER.biSize
|
||
dd SCREEN_W ; biWidth
|
||
dd -SCREEN_H ; biHeight (top-down)
|
||
dw 1 ; biPlanes
|
||
dw 32 ; biBitCount
|
||
dd 0 ; biCompression = BI_RGB
|
||
dd FRAME_BUFFER_SIZE ; biSizeImage
|
||
dd 0, 0, 0, 0
|
||
|
||
; ------------------------------------------------------------------------------
|
||
; Large buffers live in BSS (.data?) so they are NOT baked into the .exe
|
||
; ------------------------------------------------------------------------------
|
||
.data?
|
||
ALIGN 4
|
||
; (moved to COMM)
|
||
|
||
ALIGN 4
|
||
depthBuffer dd SCREEN_W dup(?)
|
||
|
||
; Glass (Transparent Wall) per-column buffers
|
||
ALIGN 4
|
||
glassDistBuffer dd SCREEN_W dup(?)
|
||
glassDrawStartBuf dd SCREEN_W dup(?)
|
||
glassDrawEndBuf dd SCREEN_W dup(?)
|
||
glassLineHeightBuf dd SCREEN_W dup(?)
|
||
glassTexXBuf dd SCREEN_W dup(?)
|
||
glassSideHitBuf dd SCREEN_W dup(?)
|
||
|
||
; Fixed-point Math Lookup Tables (512 angles, 16.16 signed fixed point)
|
||
ALIGN 4
|
||
tableSin dd ANGLE_512 dup(?)
|
||
tableCos dd ANGLE_512 dup(?)
|
||
ALIGN 4
|
||
tableRayAngleOffset dd SCREEN_W dup(?)
|
||
ALIGN 4
|
||
tableRayCos dd SCREEN_W dup(?)
|
||
|
||
; Game Map Grid (32x32 = 1024 bytes)
|
||
gameMap db MAP_SIZE dup(?)
|
||
|
||
; Texture Memory (16 slots of 128x128 32-bit BGRA = 1 MB)
|
||
ALIGN 4
|
||
; (moved to COMM)
|
||
|
||
; (moved to COMM)
|
||
|
||
; (moved to COMM)
|
||
|
||
|
||
ALIGN 4
|
||
spriteList db MAX_SPRITES * (sizeof SpriteStruct) dup(?)
|
||
spriteOrder dd MAX_SPRITES dup(?) ; sprite indices sorted far-to-near
|
||
|
||
ALIGN 4
|
||
transitionList db MAX_TRANSITIONS * (sizeof LevelTransition) dup(?)
|
||
|
||
ALIGN 4
|
||
cutsceneEvents db MAX_CUTSCENE_EVENTS * (sizeof CutsceneEvent) dup(?)
|
||
cutsceneStrings db MAX_CUTSCENE_STRINGS * CUTSCENE_STRING_BYTES dup(?)
|
||
stagedCutsceneEvents db MAX_CUTSCENE_EVENTS * (sizeof CutsceneEvent) dup(?)
|
||
stagedCutsceneStrings db MAX_CUTSCENE_STRINGS * CUTSCENE_STRING_BYTES dup(?)
|
||
|
||
ALIGN 4
|
||
entityType dd MAX_SPRITES dup(?)
|
||
entityHealth dd MAX_SPRITES dup(?)
|
||
entityState dd MAX_SPRITES dup(?)
|
||
entityTimer dd MAX_SPRITES dup(?)
|
||
entitySpeed dd MAX_SPRITES dup(?)
|
||
entityAggro dd MAX_SPRITES dup(?)
|
||
|
||
ALIGN 4
|
||
lightGrid db MAP_SIZE dup(?) ; 1024 bytes: baked light level (0..255) per cell
|
||
ALIGN 4
|
||
lightSources db MAX_LIGHTS * (sizeof LightSource) dup(?)
|
||
|
||
; Gameplay Variables & Built-in Toast Strings (CP1251)
|
||
.data
|
||
ALIGN 4
|
||
gameToastTimer dd 0
|
||
gameToastColor dd 0
|
||
gameToastText db 64 dup(0)
|
||
|
||
ALIGN 4
|
||
gameDialogActive dd 0
|
||
gameDialogSpeaker db 32 dup(0)
|
||
gameDialogText db 128 dup(0)
|
||
|
||
szDialogCloseHint db "[ENTER / E] - ЗАКРЫТЬ", 0
|
||
szKeyPickedToast db "ПОЛУЧЕН КЛЮЧ", 0
|
||
szMedkitPickedToast db "АПТЕЧКА +25 ЗДОРОВЬЯ", 0
|
||
szAmmoPickedToast db "БОЕПРИПАСЫ +20 ПАТРОНОВ", 0
|
||
szSwitchOnToast db "ПЕРЕКЛЮЧАТЕЛЬ: ВКЛ", 0
|
||
szSwitchOffToast db "ПЕРЕКЛЮЧАТЕЛЬ: ВЫКЛ", 0
|
||
szDoorOpenedToast db "ДВЕРЬ ОТКРЫТА", 0
|
||
szDoorClosedToast db "ДВЕРЬ ЗАКРЫТА", 0
|
||
szBarrelExplodedToast db "ВЗРЫВ БОЧКИ!", 0
|
||
szWeaponsEnabledToast db "РЕЖИМ: ОРУЖИЕ ВКЛЮЧЕНО", 0
|
||
szWeaponsDisabledToast db "РЕЖИМ: БЕЗ ОРУЖИЯ (КВЕСТ)", 0
|
||
szHudCleanToast db "ИНТЕРФЕЙС: ЧИСТЫЙ ВИД", 0
|
||
szHudDebugToast db "ИНТЕРФЕЙС: РЕЖИМ ОТЛАДКИ", 0
|
||
szFlashlightOn db 0D4h,0CEh,0CDh,0C0h,0D0h,0C8h,0CAh,03Ah,020h,0C2h,0CAh,0CBh,020h,05Bh,046h,05Dh,0 ; ФОНАРИК: ВКЛ [F] (CP1251)
|
||
szFlashlightOff db 0D4h,0CEh,0CDh,0C0h,0D0h,0C8h,0CAh,03Ah,020h,0C2h,0DBh,0CAh,0CBh,020h,05Bh,046h,05Dh,0 ; ФОНАРИК: ВЫКЛ [F] (CP1251)
|
||
szLightMode0 db 0D1h,0C2h,0C5h,0D2h,03Ah,020h,0C2h,0DBh,0CAh,0CBh,0DEh,0D7h,0C5h,0CDh,020h,028h,057h,06Fh,06Ch,066h,033h,044h,029h,0 ; СВЕТ: ВЫКЛЮЧЕН (Wolf3D) (CP1251)
|
||
szLightMode1 db 0D1h,0C2h,0C5h,0D2h,03Ah,020h,0C7h,0C0h,0CFh,0C5h,0D7h,0A8h,0CDh,0CDh,0DBh,0C9h,020h,028h,04Ch,069h,067h,068h,074h,06Dh,061h,070h,029h,0 ; СВЕТ: ЗАПЕЧЁННЫЙ (Lightmap) (CP1251)
|
||
szLightMode2 db 0D1h,0C2h,0C5h,0D2h,03Ah,020h,0C4h,0C8h,0CDh,0C0h,0CCh,0C8h,0D7h,0C5h,0D1h,0CAh,0C8h,0C9h,020h,0D1h,020h,0D4h,0C8h,0C7h,0C8h,0CAh,0CEh,0C9h,0 ; СВЕТ: ДИНАМИЧЕСКИЙ С ФИЗИКОЙ (CP1251)
|
||
szBakeDoneToast db 0D1h,0C2h,0C5h,0D2h,020h,0C7h,0C0h,0CFh,0C5h,0D7h,0A8h,0CDh,03Ah,020h,031h,030h,032h,034h,020h,0DFh,0D7h,0C5h,0C9h,0CAh,0C8h,0 ; СВЕТ ЗАПЕЧЁН: 1024 ЯЧЕЙКИ (CP1251)
|
||
szProjectFile db "project.eblanproj", 0
|
||
szProjGameMode0 db "GameMode=0", 0
|
||
szProjGameMode1 db "GameMode=1", 0
|
||
szProjShowWeapons0 db "ShowWeapons=0", 0
|
||
szFlagNoWeapons db "noweapons", 0
|
||
szFlagAdventure db "adventure", 0
|
||
szFlagAction db "action", 0
|
||
szFlagDebugHud db "debug-hud", 0
|
||
szFlagCleanHud db "clean-hud", 0
|
||
previewPrefix db "--preview:", 0
|
||
|
||
; Persistent and staged lighting buffers (declared before the map loader).
|
||
.data
|
||
lightingTick dd 0
|
||
authoredLightCount dd 0
|
||
legacyLightingSettings dd 0,40,1,384,240,45,1,0
|
||
lightRed dd 256
|
||
lightGreen dd 256
|
||
lightBlue dd 256
|
||
lightAccumR dd 0
|
||
lightAccumG dd 0
|
||
lightAccumB dd 0
|
||
lightWeight dd 0
|
||
.data?
|
||
ALIGN 4
|
||
lightGridRGB dd MAP_SIZE dup(?)
|
||
lightSmoothRGB dd MAP_SIZE dup(?)
|
||
stagedLightSettings dd 8 dup(?)
|
||
stagedLightSources db 13*40 dup(?)
|
||
stagedLightRGB dd MAP_SIZE dup(?)
|