EBLAN_ENGINE/include/engine_map.inc

367 lines
9.8 KiB
PHP

; ==============================================================================
; EBLAN ENGINE - Map System & World Grid
; ==============================================================================
.code
; ------------------------------------------------------------------------------
; InitMap: Creates a rich test level with rooms, hallways, pillars & doors
; ------------------------------------------------------------------------------
InitMap PROC uses eax ecx edi
; Clear map to empty
mov edi, OFFSET gameMap
mov ecx, MAP_SIZE
xor eax, eax
rep stosb
; 1. Build Outer Boundary Walls (Type 1: Brick)
mov ecx, 0
loop_boundary_x:
; Top row (y = 0)
mov byte ptr [gameMap + ecx], CELL_BRICK
; Bottom row (y = 31)
mov byte ptr [gameMap + (31 * MAP_W) + ecx], CELL_BRICK
inc ecx
cmp ecx, MAP_W
jl loop_boundary_x
mov ecx, 0
loop_boundary_y:
; Left column (x = 0)
mov eax, ecx
shl eax, 5 ; eax = ecx * 32
mov byte ptr [gameMap + eax], CELL_BRICK
; Right column (x = 31)
mov byte ptr [gameMap + eax + 31], CELL_BRICK
inc ecx
cmp ecx, MAP_H
jl loop_boundary_y
; 2. Build Internal Room Walls (y = 8, x from 1 to 20, Stone Brick)
mov ecx, 1
loop_wall1:
mov byte ptr [gameMap + (8 * MAP_W) + ecx], CELL_STONE
inc ecx
cmp ecx, 20
jle loop_wall1
; Create Door at (x = 10, y = 8)
mov byte ptr [gameMap + (8 * MAP_W) + 10], CELL_DOOR
; 3. Build Vertical Dividing Wall (x = 20, y from 1 to 24, Wood)
mov ecx, 1
loop_wall2:
cmp ecx, 14 ; Leave opening at y = 14
je @F
mov eax, ecx
shl eax, 5 ; ecx * 32
mov byte ptr [gameMap + eax + 20], CELL_WOOD
@@:
inc ecx
cmp ecx, 24
jle loop_wall2
; 4. Add Pillars in the main courtyard (Type 4: Metal / Type 7: Pillar)
mov byte ptr [gameMap + (4 * MAP_W) + 4], CELL_PILLAR
mov byte ptr [gameMap + (4 * MAP_W) + 7], CELL_PILLAR
mov byte ptr [gameMap + (12 * MAP_W) + 5], CELL_METAL
mov byte ptr [gameMap + (12 * MAP_W) + 15], CELL_METAL
mov byte ptr [gameMap + (18 * MAP_W) + 8], CELL_PILLAR
mov byte ptr [gameMap + (18 * MAP_W) + 12], CELL_PILLAR
; 5. South wing decorative walls
mov byte ptr [gameMap + (24 * MAP_W) + 5], CELL_STONE
mov byte ptr [gameMap + (24 * MAP_W) + 6], CELL_STONE
mov byte ptr [gameMap + (24 * MAP_W) + 7], CELL_DOOR
mov byte ptr [gameMap + (24 * MAP_W) + 8], CELL_STONE
mov byte ptr [gameMap + (24 * MAP_W) + 9], CELL_STONE
; Safe player spawn + clear entities (raw world units)
mov playerX, 160
mov playerY, 160
mov playerAngle, 0
mov spriteCount, 0
ret
InitMap ENDP
; ------------------------------------------------------------------------------
; GetMapCell: Returns cell value at grid coordinates (gridX, gridY)
; ------------------------------------------------------------------------------
GetMapCell PROC mapX:DWORD, mapY:DWORD
mov eax, mapX
cmp eax, 0
jl out_of_bounds
cmp eax, MAP_W
jge out_of_bounds
mov edx, mapY
cmp edx, 0
jl out_of_bounds
cmp edx, MAP_H
jge out_of_bounds
shl edx, 5 ; mapY * 32
add edx, eax
movzx eax, byte ptr [gameMap + edx]
ret
out_of_bounds:
mov eax, CELL_BRICK ; Solid wall outside bounds
ret
GetMapCell ENDP
; ------------------------------------------------------------------------------
; SetMapCell: Sets cell value at grid coordinates (gridX, gridY)
; ------------------------------------------------------------------------------
SetMapCell PROC mapX:DWORD, mapY:DWORD, cellVal:DWORD
mov eax, mapX
cmp eax, 0
jl done_set
cmp eax, MAP_W
jge done_set
mov edx, mapY
cmp edx, 0
jl done_set
cmp edx, MAP_H
jge done_set
shl edx, 5
add edx, eax
mov al, byte ptr [cellVal]
mov byte ptr [gameMap + edx], al
done_set:
ret
SetMapCell ENDP
; ------------------------------------------------------------------------------
; IsSolidCell: Returns 1 if cell blocks player and rays, 0 otherwise
; ------------------------------------------------------------------------------
IsSolidCell PROC cellType:DWORD
mov eax, cellType
cmp eax, CELL_EMPTY
je not_solid
cmp eax, CELL_DOOR_OPEN
je not_solid
mov eax, 1 ; Solid wall or closed door
ret
not_solid:
xor eax, eax
ret
IsSolidCell ENDP
; ------------------------------------------------------------------------------
; InteractDoor: Checks if player is facing a door and toggles open/close
; ------------------------------------------------------------------------------
InteractDoor PROC uses ebx ecx edx
LOCAL targetX:DWORD, targetY:DWORD
; Compute point 60 units in front of player
mov eax, playerAngle
and eax, ANGLE_MASK
; dx = cos(angle) * 60
mov ebx, [tableCos + eax*4]
imul ebx, 60
sar ebx, 16
add ebx, playerX
sar ebx, 6 ; divide by CELL_SIZE (64)
mov targetX, ebx
; dy = sin(angle) * 60
mov ecx, [tableSin + eax*4]
imul ecx, 60
sar ecx, 16
add ecx, playerY
sar ecx, 6
mov targetY, ecx
invoke GetMapCell, targetX, targetY
cmp eax, CELL_DOOR
jne check_door_close
; Open the door!
invoke SetMapCell, targetX, targetY, CELL_DOOR_OPEN
ret
check_door_close:
cmp eax, CELL_DOOR_OPEN
jne no_door
; Close the door!
invoke SetMapCell, targetX, targetY, CELL_DOOR
no_door:
ret
InteractDoor ENDP
; ------------------------------------------------------------------------------
; CheckDoorHint: Returns eax=1 if player is facing a door (for HUD hint)
; ------------------------------------------------------------------------------
CheckDoorHint PROC uses ebx ecx edx
LOCAL targetX:DWORD, targetY:DWORD
; Compute point 60 units in front of player
mov eax, playerAngle
and eax, ANGLE_MASK
mov ebx, [tableCos + eax*4]
imul ebx, 60
sar ebx, 16
add ebx, playerX
sar ebx, 6
mov targetX, ebx
mov ecx, [tableSin + eax*4]
imul ecx, 60
sar ecx, 16
add ecx, playerY
sar ecx, 6
mov targetY, ecx
invoke GetMapCell, targetX, targetY
cmp eax, CELL_DOOR
je hint_yes
cmp eax, CELL_DOOR_OPEN
je hint_yes
xor eax, eax
ret
hint_yes:
mov eax, 1
ret
CheckDoorHint ENDP
; ------------------------------------------------------------------------------
; LoadMapBinary: Checks if assets/map.dat exists and loads custom map,
; player spawn position, angle, ceiling/floor colors, and sprites.
; Returns: eax = 1 if custom map loaded, 0 if fallback to procedural map
; ------------------------------------------------------------------------------
LoadMapBinary PROC uses ebx ecx edx esi edi
LOCAL hFile:DWORD
LOCAL bytesRead:DWORD
LOCAL header:MapHeader
LOCAL count:DWORD
; Try to open assets/map.dat
invoke CreateFileA, OFFSET szMapFilePath, GENERIC_READ, FILE_SHARE_READ,\
0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
mov hFile, eax
cmp hFile, INVALID_HANDLE_VALUE
je load_fallback
; Read MapHeader (38 bytes, packed)
invoke ReadFile, hFile, ADDR header, sizeof MapHeader, ADDR bytesRead, 0
test eax, eax
jz close_and_fallback
cmp bytesRead, sizeof MapHeader
jl close_and_fallback
; Verify Magic 'EBLN'
cmp header.magic, MAP_MAGIC
jne close_and_fallback
; Validate version (1 = legacy 16.16 sprite coords, 2 = raw units)
movzx eax, header.version
cmp eax, 1
jl close_and_fallback
cmp eax, 2
jg close_and_fallback
; Validate grid dimensions (engine is fixed at 32x32)
cmp header.mapWidth, MAP_W
jne close_and_fallback
cmp header.mapHeight, MAP_H
jne close_and_fallback
; Apply Player Spawn Position (in cells -> fixed-point world units)
movzx eax, header.playerStartX
shl eax, 6 ; * 64
add eax, 32 ; center in cell
mov playerX, eax
movzx eax, header.playerStartY
shl eax, 6 ; * 64
add eax, 32
mov playerY, eax
; Apply Player Start Angle (0..511)
movzx eax, header.playerStartAngle
and eax, ANGLE_MASK
mov playerAngle, eax
; Apply Custom Ceiling and Floor Colors if specified
cmp header.ceilingColor, 0
je @F
mov eax, header.ceilingColor
mov mapCeilingColor, eax
@@:
cmp header.floorColor, 0
je @F
mov eax, header.floorColor
mov mapFloorColor, eax
@@:
; Read 1024 bytes of gameMap
invoke ReadFile, hFile, OFFSET gameMap, MAP_SIZE, ADDR bytesRead, 0
test eax, eax
jz close_and_fallback
cmp bytesRead, MAP_SIZE
jne close_and_fallback
; Read Sprites
movzx eax, header.spriteCount
cmp eax, MAX_SPRITES
jle @F
mov eax, MAX_SPRITES
@@:
mov count, eax
mov spriteCount, eax
test eax, eax
jz finish_load
imul eax, sizeof SpriteStruct
mov ecx, eax
invoke ReadFile, hFile, OFFSET spriteList, ecx, ADDR bytesRead, 0
test eax, eax
jz close_and_fallback
mov eax, count
imul eax, sizeof SpriteStruct
cmp bytesRead, eax
jne close_and_fallback
; Format v1 stored sprite x/y as 16.16 fixed point -> convert to raw units
cmp header.version, 1
jne finish_load
mov ecx, 0
convert_v1_sprites:
cmp ecx, count
jge finish_load
mov eax, ecx
imul eax, sizeof SpriteStruct
add eax, OFFSET spriteList
mov edx, [eax].SpriteStruct.x
sar edx, 16
mov [eax].SpriteStruct.x, edx
mov edx, [eax].SpriteStruct.y
sar edx, 16
mov [eax].SpriteStruct.y, edx
inc ecx
jmp convert_v1_sprites
finish_load:
invoke CloseHandle, hFile
mov eax, 1 ; Custom map loaded!
ret
close_and_fallback:
invoke CloseHandle, hFile
load_fallback:
call InitMap ; Procedural fallback level
xor eax, eax
ret
LoadMapBinary ENDP