feat: add peaceful adventure mode, clean immersive HUD, and genre toggle

This commit is contained in:
Artvasil09 2026-10-23 09:07:57 +03:00
parent 25bd6377a7
commit 341966debe
14 changed files with 473 additions and 80 deletions

View file

@ -259,3 +259,16 @@ EblanStudio has evolved from a pure level editor into a **Full Game Engine Studi
- `Game_OnCustomHUD`: custom 2D canvas drawing (health bars, gauges, quest markers).
- `PlayGameSFX(pszRelativePath)`: safe asynchronous WinMM audio player.
- Built-in automatic gameplay toasts for keys, medkits, ammo, switches, doors, and explosions.
6. **Game Genres, Peaceful Adventure Mode & Immersive Clean HUD**:
- `GAME_MODE_ADVENTURE (0)`: pure exploration / quest / horror / puzzle mode without weapons, ammo, crosshair, or combat overlays.
- `GAME_MODE_ACTION (1)`: full combat shooter mode with weapon models, crosshair, health bar, and ammo counter.
- `HUD_STYLE_CLEAN (0)`: 100% immersive full-screen view (no debug banners, no text collisions, no bottom controls clutter).
- `HUD_STYLE_DEBUG (1)`: developer mode displaying FPS counter at top-right (X=250), engine title, score, and controls hints.
- Instant in-game switching:
- `[ESC] -> [2]`: toggle weapons / peaceful mode on the fly with toast notifications.
- `[ESC] -> [3]`: toggle clean vs debug HUD.
- `[F1]` or `[H]`: quick hotkey to toggle clean HUD vs debug HUD.
- Editor toolbar 1-click genre switcher: `☮ КВЕСТ / БЕЗ ОРУЖИЯ` vs `⚔ ЭКШЕН / С ОРУЖИЕМ`.
- Project settings (`project.eblanproj`) persist `GameMode`, `ShowWeapons`, and `ShowCrosshair`.

Binary file not shown.

View file

@ -1,22 +1,22 @@
[Window][Workspace]
Pos=0,60
Size=2560,1292
LastUsed=20261022
LastUsed=20261023
[Window][Debug##Default]
Pos=60,60
Size=400,400
LastUsed=20261022
LastUsed=20261023
[Window][Toolbar]
Pos=0,20
Size=2560,38
LastUsed=20261022
LastUsed=20261023
[Window][StatusBar]
Pos=0,1352
Size=2560,32
LastUsed=20261022
LastUsed=20261023
[Window][Не удалось запустить игру]
Pos=649,356
@ -29,7 +29,12 @@ Size=900,650
LastUsed=20261022
[Window][Менеджер ассетов (Texture & Audio Manager)]
Pos=60,60
Pos=61,60
Size=820,580
LastUsed=20261022
LastUsed=20261023
[Window][Редактор кода MASM32 & Игровых скриптов (F7)]
Pos=60,60
Size=1020,680
LastUsed=20261023

View file

@ -255,6 +255,12 @@ bool EditorApp::PreparePlaytest(std::string& startMap, std::string& enginePath)
if (ec) return copyFailure();
if (fs::is_directory(sounds, ec)) fs::copy(sounds, sandbox / "assets/sounds", fs::copy_options::recursive, ec);
if (ec) return copyFailure();
char modulePath[MAX_PATH]{};
GetModuleFileNameA(nullptr, modulePath, MAX_PATH);
fs::path projFile = fs::path(modulePath).parent_path() / "project.eblanproj";
if (fs::exists(projFile, ec)) {
fs::copy_file(projFile, sandbox / "project.eblanproj", fs::copy_options::overwrite_existing, ec);
}
// Validate all reachable maps and destination spawns, including reverse links.
std::vector<std::string> pending{source.filename().string()};
std::set<std::string> visited;
@ -1617,6 +1623,42 @@ void EditorApp::RenderToolbar() {
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
// Game Mode Quick Selector (Peaceful Adventure vs Action Shooter)
if (project && project->gameMode == 0) {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.12f, 0.45f, 0.40f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.18f, 0.58f, 0.50f, 1.0f));
if (ImGui::Button(" ☮ КВЕСТ / БЕЗ ОРУЖИЯ ")) {
project->gameMode = 1;
project->showWeapons = true;
char module[MAX_PATH]{};
GetModuleFileNameA(nullptr, module, MAX_PATH);
std::string projPath = (fs::path(module).parent_path() / "project.eblanproj").string();
project->Save(projPath);
statusMessage = "Режим игры: ЭКШЕН / ШУТЕР (с оружием и стрельбой)";
}
ImGui::PopStyleColor(2);
} else if (project) {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.55f, 0.30f, 0.10f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.70f, 0.38f, 0.12f, 1.0f));
if (ImGui::Button(" ⚔ ЭКШЕН / С ОРУЖИЕМ ")) {
project->gameMode = 0;
project->showWeapons = false;
char module[MAX_PATH]{};
GetModuleFileNameA(nullptr, module, MAX_PATH);
std::string projPath = (fs::path(module).parent_path() / "project.eblanproj").string();
project->Save(projPath);
statusMessage = "Режим игры: КВЕСТ / МИРНЫЙ (без оружия)";
}
ImGui::PopStyleColor(2);
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Нажмите для быстрого переключения жанра игры (Квест без оружия / Шутер с оружием)");
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
// Tools
auto ToolButton = [&](const char* label, ToolMode mode) {
bool active = (currentTool == mode);
@ -2292,12 +2334,18 @@ void EditorApp::RenderProjectSettingsModal() {
static char authorBuf[128] = "";
static char versionBuf[32] = "";
static char windowTitleBuf[128] = "";
static int modeChoice = 1;
static bool showWeap = true;
static bool showCross = true;
static bool init = true;
if (init) {
strncpy_s(titleBuf, project->title.c_str(), sizeof(titleBuf) - 1);
strncpy_s(authorBuf, project->author.c_str(), sizeof(authorBuf) - 1);
strncpy_s(versionBuf, project->version.c_str(), sizeof(versionBuf) - 1);
strncpy_s(windowTitleBuf, project->windowTitle.c_str(), sizeof(windowTitleBuf) - 1);
modeChoice = project->gameMode;
showWeap = project->showWeapons;
showCross = project->showCrosshair;
init = false;
}
@ -2309,6 +2357,20 @@ void EditorApp::RenderProjectSettingsModal() {
ImGui::InputText("Версия", versionBuf, sizeof(versionBuf));
ImGui::InputText("Заголовок окна", windowTitleBuf, sizeof(windowTitleBuf));
ImGui::Spacing();
ImGui::TextColored(ImVec4(0.2f, 0.8f, 1.0f, 1.0f), "Жанр и режим геймплея:");
ImGui::RadioButton("Квест / Приключение / Хоррор (Мирный режим, без оружия)", &modeChoice, 0);
ImGui::RadioButton("Экшен / Шутер (С оружием, патронами и перестрелками)", &modeChoice, 1);
if (modeChoice == 1) {
ImGui::Checkbox("Отображать оружие от 1-го лица", &showWeap);
ImGui::Checkbox("Отображать перекрестие прицела", &showCross);
} else {
showWeap = false;
showCross = false;
ImGui::TextDisabled("В мирном режиме оружие, прицел и счетчик патронов скрыты.");
}
ImGui::Spacing();
ImGui::Text("Стартовая карта: %s", project->startupMap.c_str());
@ -2318,6 +2380,9 @@ void EditorApp::RenderProjectSettingsModal() {
project->author = authorBuf;
project->version = versionBuf;
project->windowTitle = windowTitleBuf;
project->gameMode = modeChoice;
project->showWeapons = showWeap;
project->showCrosshair = showCross;
char module[MAX_PATH]{};
GetModuleFileNameA(nullptr, module, MAX_PATH);

View file

@ -16,6 +16,9 @@ struct EblanProject {
std::string windowTitle = "EBLAN ENGINE 3D - Standalone Retro Game";
int defaultWidth = 1280;
int defaultHeight = 960;
int gameMode = 1; // 0 = Adventure (No weapons / Peaceful), 1 = Action (Weapons)
bool showWeapons = true;
bool showCrosshair = true;
bool Save(const std::string& path) const {
HANDLE hFile = CreateFileA(path.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
@ -31,6 +34,10 @@ struct EblanProject {
content += std::string("DefaultWidth=") + numBuf + "\r\n";
snprintf(numBuf, sizeof(numBuf), "%d", defaultHeight);
content += std::string("DefaultHeight=") + numBuf + "\r\n";
snprintf(numBuf, sizeof(numBuf), "%d", gameMode);
content += std::string("GameMode=") + numBuf + "\r\n";
content += std::string("ShowWeapons=") + (showWeapons ? "1" : "0") + "\r\n";
content += std::string("ShowCrosshair=") + (showCrosshair ? "1" : "0") + "\r\n";
DWORD written = 0;
WriteFile(hFile, content.data(), static_cast<DWORD>(content.size()), &written, nullptr);
CloseHandle(hFile);
@ -65,6 +72,9 @@ struct EblanProject {
else if (key == "WindowTitle") windowTitle = val;
else if (key == "DefaultWidth") defaultWidth = std::atoi(val.c_str());
else if (key == "DefaultHeight") defaultHeight = std::atoi(val.c_str());
else if (key == "GameMode") gameMode = std::atoi(val.c_str());
else if (key == "ShowWeapons") showWeapons = (val == "1" || val == "true");
else if (key == "ShowCrosshair") showCrosshair = (val == "1" || val == "true");
}
}

Binary file not shown.

View file

@ -37,11 +37,17 @@ UpdateCombat PROC uses ebx ecx edx esi edi
dec playerHitFlash
@@:
; If player is dead or game is paused, cannot attack
; If player is dead, game is paused, or in peaceful adventure mode, cannot attack
cmp isPlayerDead, 0
jne combat_done
cmp isGamePaused, 0
jne combat_done
cmp gameMode, GAME_MODE_ADVENTURE
je combat_done
cmp enableWeapons, 0
je combat_done
cmp playerWeapon, WEAPON_NONE
je combat_done
; 2. Check attack input
cmp keyAttack, 0
@ -383,10 +389,21 @@ UpdateCombat ENDP
RenderCombatHUD PROC uses ebx ecx edx esi edi
LOCAL barW:DWORD, gunY:DWORD
; If in adventure mode, unarmed, or weapons disabled, skip weapon & combat stats
cmp gameMode, GAME_MODE_ADVENTURE
je hud_damage_flash
cmp enableWeapons, 0
je hud_damage_flash
cmp playerWeapon, WEAPON_NONE
je hud_damage_flash
; 1. Center Crosshair (subtle cross at 160, 120)
cmp showCrosshair, 0
je skip_crosshair
invoke DrawRect, 156, 120, 9, 1, 00FFFFFFh
invoke DrawRect, 160, 116, 1, 9, 00FFFFFFh
invoke DrawRect, 160, 120, 1, 1, 0000FF00h
skip_crosshair:
; 2. Render Active Weapon at bottom center
cmp playerWeapon, WEAPON_KNIFE
@ -470,15 +487,15 @@ draw_pistol_barrel:
invoke DrawRect, 152, eax, 17, 22, 00453020h ; brown wood grip plates
hud_stats_draw:
; 3. Health Bar
invoke DrawString8x8, 8, 42, OFFSET strHpLabel, COLOR_GREEN
invoke DrawNumber8x8, 34, 42, playerHealth, COLOR_WHITE
; 3. Health Bar at top-left: X=8, Y=8
invoke DrawString8x8, 8, 8, OFFSET strHpLabel, COLOR_GREEN
invoke DrawNumber8x8, 34, 8, playerHealth, COLOR_WHITE
invoke DrawRect, 68, 42, 60, 8, 00441010h
invoke DrawRectOutline, 68, 42, 60, 8, COLOR_WHITE
invoke DrawRect, 66, 8, 50, 8, 00441010h
invoke DrawRectOutline, 66, 8, 50, 8, COLOR_WHITE
mov eax, playerHealth
imul eax, 58
imul eax, 48
xor edx, edx
mov ecx, playerMaxHealth
test ecx, ecx
@ -489,57 +506,63 @@ hud_stats_draw:
mov barW, eax
cmp barW, 0
jle hud_ammo_draw
cmp barW, 58
cmp barW, 48
jle @F
mov barW, 58
mov barW, 48
@@:
mov edx, 0000CC33h ; Green
cmp playerHealth, 30
jg @F
mov edx, 00FF2222h ; Red warning
@@:
invoke DrawRect, 69, 43, barW, 6, edx
invoke DrawRect, 67, 9, barW, 6, edx
hud_ammo_draw:
; 4. Ammo Display
invoke DrawString8x8, 140, 42, OFFSET strAmmoLabel, COLOR_YELLOW
invoke DrawNumber8x8, 182, 42, playerAmmo, COLOR_YELLOW
; 4. Ammo Display: X=126, Y=8
invoke DrawString8x8, 126, 8, OFFSET strAmmoLabel, COLOR_YELLOW
invoke DrawNumber8x8, 168, 8, playerAmmo, COLOR_YELLOW
; 5. Score Display
invoke DrawString8x8, 222, 42, OFFSET strScoreLabel, COLOR_CYAN
invoke DrawNumber8x8, 272, 42, playerScore, COLOR_CYAN
; 5. Keys: X=204, Y=8 (if collected)
cmp playerKeys, 0
jle hud_score_draw
invoke DrawString8x8, 204, 8, OFFSET strKeysLabel, COLOR_MAGENTA
invoke DrawNumber8x8, 238, 8, playerKeys, COLOR_MAGENTA
hud_score_draw:
; 6. Score Display: only in Debug HUD style
cmp hudStyle, HUD_STYLE_CLEAN
je draw_weapon_badge
invoke DrawString8x8, 8, 20, OFFSET strScoreLabel, COLOR_CYAN
invoke DrawNumber8x8, 58, 20, playerScore, COLOR_CYAN
draw_weapon_badge:
; 7. Active Weapon Badge at bottom-right corner: X=228, Y=222
invoke DrawRect, 228, 222, 88, 14, 00141414h
invoke DrawRectOutline, 228, 222, 88, 14, 00444444h
; 6. Active Weapon Name & Slot Indicators at top left
invoke DrawString8x8, 8, 26, OFFSET strWeaponLabel, COLOR_WHITE
cmp playerWeapon, WEAPON_KNIFE
jne @F
invoke DrawString8x8, 42, 26, OFFSET strWeaponKnife, COLOR_CYAN
invoke DrawString8x8, 233, 225, OFFSET strWeaponKnife, COLOR_CYAN
jmp draw_weapon_slots
@@:
cmp playerWeapon, WEAPON_SHOTGUN
jne @F
invoke DrawString8x8, 42, 26, OFFSET strWeaponShotgun, 00FFAA00h
invoke DrawString8x8, 233, 225, OFFSET strWeaponShotgun, 00FFAA00h
jmp draw_weapon_slots
@@:
invoke DrawString8x8, 42, 26, OFFSET strWeaponPistol, COLOR_YELLOW
invoke DrawString8x8, 233, 225, OFFSET strWeaponPistol, COLOR_YELLOW
draw_weapon_slots:
; Draw small weapon slot indicator boxes: [1] [2] [3]
invoke DrawRectOutline, 100, 26, 8, 8, 00555555h
invoke DrawRectOutline, 112, 26, 8, 8, 00555555h
invoke DrawRectOutline, 124, 26, 8, 8, 00555555h
invoke DrawRectOutline, 287, 225, 6, 8, 00555555h
invoke DrawRectOutline, 295, 225, 6, 8, 00555555h
invoke DrawRectOutline, 303, 225, 6, 8, 00555555h
; Highlight active slot
mov eax, playerWeapon
imul eax, 12
add eax, 100
invoke DrawRectOutline, eax, 26, 8, 8, COLOR_YELLOW
; 7. Keys (if collected)
cmp playerKeys, 0
jle hud_damage_flash
invoke DrawString8x8, 222, 10, OFFSET strKeysLabel, COLOR_MAGENTA
invoke DrawNumber8x8, 258, 10, playerKeys, COLOR_MAGENTA
imul eax, 8
add eax, 287
invoke DrawRectOutline, eax, 225, 6, 8, COLOR_YELLOW
hud_damage_flash:
; 8. Damage Screen Flash
@ -571,19 +594,20 @@ RenderPauseMenu PROC uses ebx ecx edx
cmp isGamePaused, 0
je pause_menu_done
; Semi-transparent dark overlay panel (centered 200x105 at 60, 65)
invoke DrawRect, 60, 65, 200, 105, 00141416h
invoke DrawRectOutline, 60, 65, 200, 105, COLOR_CYAN
invoke DrawRectOutline, 62, 67, 196, 101, COLOR_WHITE
; Centered semi-transparent panel 220x112 at (50, 64)
invoke DrawRect, 50, 64, 220, 112, 00141416h
invoke DrawRectOutline, 50, 64, 220, 112, COLOR_CYAN
invoke DrawRectOutline, 52, 66, 216, 108, COLOR_WHITE
; Header
invoke DrawString8x8, 112, 75, OFFSET strPauseTitle, COLOR_YELLOW
invoke DrawString8x8, 112, 72, OFFSET strPauseTitle, COLOR_YELLOW
; Menu Options
invoke DrawString8x8, 76, 95, OFFSET strPauseOpt1, COLOR_GREEN
invoke DrawString8x8, 76, 110, OFFSET strPauseOpt2, COLOR_WHITE
invoke DrawString8x8, 76, 125, OFFSET strPauseOpt3, COLOR_CYAN
invoke DrawString8x8, 76, 140, OFFSET strPauseOpt4, 00FF4444h
invoke DrawString8x8, 64, 88, OFFSET strPauseOpt1, COLOR_GREEN
invoke DrawString8x8, 64, 102, OFFSET strPauseOpt2, COLOR_WHITE
invoke DrawString8x8, 64, 116, OFFSET strPauseOpt3, COLOR_CYAN
invoke DrawString8x8, 64, 130, OFFSET strPauseOpt4, COLOR_YELLOW
invoke DrawString8x8, 64, 146, OFFSET strPauseOpt5, 00FF4444h
pause_menu_done:
ret

View file

@ -69,10 +69,18 @@ keyWeapon3 db 0
keyWeapon4 db 0
keyPause db 0
keyPauseHeld db 0
keyHudStyleHeld db 0
keyMenuHeld db 0
isGamePaused dd 0
; 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
playerWeapon dd 1 ; Default: WEAPON_PISTOL
playerHealth dd 100
playerMaxHealth dd 100
playerAmmo dd 50
@ -129,12 +137,13 @@ strWeaponLabel db "WPN:",0
strWeaponKnife db "KNIFE",0
strWeaponPistol db "PISTOL",0
strWeaponShotgun db "SHOTGUN",0
strPauseTitle db "== PAUSED ==",0
strPauseOpt1 db "[1] RESUME",0
strPauseOpt2 db "[2] RESTART LEVEL",0
strPauseOpt3 db "[3] MINIMAP RADAR",0
strPauseOpt4 db "[4] QUIT TO WINDOWS",0
strYouDied db "YOU DIED! PRESS [R] TO RESTART",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
@ -262,3 +271,17 @@ szSwitchOffToast db "ПЕРЕКЛЮЧАТЕЛЬ: ВЫКЛ", 0
szDoorOpenedToast db "ДВЕРЬ ОТКРЫТА", 0
szDoorClosedToast db "ДВЕРЬ ЗАКРЫТА", 0
szBarrelExplodedToast db "ВЗРЫВ БОЧКИ!", 0
szWeaponsEnabledToast db "РЕЖИМ: ОРУЖИЕ ВКЛЮЧЕНО", 0
szWeaponsDisabledToast db "РЕЖИМ: БЕЗ ОРУЖИЯ (КВЕСТ)", 0
szHudCleanToast db "ИНТЕРФЕЙС: ЧИСТЫЙ ВИД", 0
szHudDebugToast db "ИНТЕРФЕЙС: РЕЖИМ ОТЛАДКИ", 0
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

View file

@ -71,8 +71,20 @@ VK_KEY_1 equ 31h
VK_KEY_2 equ 32h
VK_KEY_3 equ 33h
VK_KEY_4 equ 34h
VK_KEY_5 equ 35h
VK_KEY_F1 equ 70h
VK_KEY_H equ 48h
; Game Modes
GAME_MODE_ADVENTURE equ 0 ; Exploration / Quest / Horror / Puzzle (No weapons, clean view)
GAME_MODE_ACTION equ 1 ; Combat Action (Weapons, Crosshair, Ammo, Health bar)
; HUD Styles
HUD_STYLE_CLEAN equ 0 ; Clean / Immersive (No debug watermark, no bottom bar)
HUD_STYLE_DEBUG equ 1 ; Debug Mode (FPS counter, Engine watermark, Minimap)
; Weapon Archetypes
WEAPON_NONE equ -1 ; No weapon (Unarmed / Peaceful / Quest)
WEAPON_KNIFE equ 0 ; Melee blade (no ammo, fast, 30 damage)
WEAPON_PISTOL equ 1 ; Handgun (1 ammo, accurate, 35 damage)
WEAPON_SHOTGUN equ 2 ; Pump Shotgun (2 ammo, 3-ray spread, 70 damage)

View file

@ -240,3 +240,104 @@ RenderGameHUDOverlays PROC
call Game_OnCustomHUD
ret
RenderGameHUDOverlays ENDP
; ------------------------------------------------------------------------------
; CheckCmdFlag: Case-insensitive substring search (EAX = 1 if found, 0 if not)
; ------------------------------------------------------------------------------
CheckCmdFlag PROC uses esi edi ecx, pszCmd:DWORD, pszFlag:DWORD
mov esi, pszCmd
test esi, esi
jz flag_not_found
check_next_char:
cmp byte ptr [esi], 0
je flag_not_found
mov edi, pszFlag
mov ecx, esi
compare_loop:
mov al, byte ptr [edi]
test al, al
jz flag_found
mov ah, byte ptr [ecx]
cmp al, 'A'
jl @F
cmp al, 'Z'
jg @F
add al, 32
@@:
cmp ah, 'A'
jl @F
cmp ah, 'Z'
jg @F
add ah, 32
@@:
cmp al, ah
jne mismatch
inc edi
inc ecx
jmp compare_loop
mismatch:
inc esi
jmp check_next_char
flag_found:
mov eax, 1
ret
flag_not_found:
xor eax, eax
ret
CheckCmdFlag ENDP
; ------------------------------------------------------------------------------
; LoadProjectSettings: Reads project.eblanproj if present in working directory
; ------------------------------------------------------------------------------
LoadProjectSettings PROC uses ebx ecx edx esi edi
LOCAL hFile:DWORD, bytesRead:DWORD
LOCAL projBuf[1024]:BYTE
invoke CreateFileA, OFFSET szProjectFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0
cmp eax, INVALID_HANDLE_VALUE
je proj_done
mov hFile, eax
lea edx, projBuf
invoke ReadFile, hFile, edx, 1023, ADDR bytesRead, 0
invoke CloseHandle, hFile
cmp bytesRead, 0
jle proj_done
mov eax, bytesRead
mov byte ptr [projBuf + eax], 0
lea edx, projBuf
invoke CheckCmdFlag, edx, OFFSET szProjGameMode0
test eax, eax
jnz set_adv_mode
lea edx, projBuf
invoke CheckCmdFlag, edx, OFFSET szProjShowWeapons0
test eax, eax
jnz set_adv_mode
lea edx, projBuf
invoke CheckCmdFlag, edx, OFFSET szProjGameMode1
test eax, eax
jnz set_act_mode
jmp proj_done
set_adv_mode:
mov gameMode, GAME_MODE_ADVENTURE
mov enableWeapons, 0
mov playerWeapon, WEAPON_NONE
mov showCrosshair, 0
jmp proj_done
set_act_mode:
mov gameMode, GAME_MODE_ACTION
mov enableWeapons, 1
mov playerWeapon, WEAPON_PISTOL
mov showCrosshair, 1
proj_done:
ret
LoadProjectSettings ENDP

View file

@ -181,7 +181,34 @@ restart_released:
mov keyRestartHeld, 0
restart_sampled:
; Weapon Selection Keys: 1, 2, 3
; F1 / H: Toggle Clean HUD vs Debug HUD
invoke GetAsyncKeyState, VK_KEY_F1
mov bx, ax
invoke GetAsyncKeyState, VK_KEY_H
or bx, ax
test bx, 8000h
jz hud_key_released
cmp keyHudStyleHeld, 0
jne hud_key_sampled
xor hudStyle, 1
mov keyHudStyleHeld, 1
cmp hudStyle, HUD_STYLE_CLEAN
je toast_hud_clean
invoke ShowGameToast, OFFSET szHudDebugToast, 60, COLOR_CYAN
jmp hud_key_sampled
toast_hud_clean:
invoke ShowGameToast, OFFSET szHudCleanToast, 60, COLOR_GREEN
jmp hud_key_sampled
hud_key_released:
mov keyHudStyleHeld, 0
hud_key_sampled:
; Weapon Selection Keys: 1, 2, 3 (only in Action mode with weapons enabled)
cmp gameMode, GAME_MODE_ACTION
jne skip_weapon_select
cmp enableWeapons, 0
je skip_weapon_select
invoke GetAsyncKeyState, VK_KEY_1
test ax, 8000h
jz @F
@ -197,6 +224,7 @@ restart_sampled:
jz @F
mov playerWeapon, WEAPON_SHOTGUN
@@:
skip_weapon_select:
; Escape / Pause Key
invoke GetAsyncKeyState, VK_KEY_ESCAPE
@ -224,31 +252,83 @@ pause_key_sampled:
mov keyAttack, 0
mov keyAction, 0
; Check if any menu key is pressed
invoke GetAsyncKeyState, VK_KEY_1
mov bx, ax
invoke GetAsyncKeyState, VK_KEY_2
or bx, ax
invoke GetAsyncKeyState, VK_KEY_3
or bx, ax
invoke GetAsyncKeyState, VK_KEY_4
or bx, ax
invoke GetAsyncKeyState, VK_KEY_5
or bx, ax
test bx, 8000h
jz menu_keys_released
; If a key is pressed, check if already held
cmp keyMenuHeld, 0
jne pause_menu_done
mov keyMenuHeld, 1
; Option 1: Resume
invoke GetAsyncKeyState, VK_KEY_1
test ax, 8000h
jz @F
mov isGamePaused, 0
jmp pause_menu_done
@@:
; Option 2: Restart level
; Option 2: Toggle Weapons / Peaceful Mode
invoke GetAsyncKeyState, VK_KEY_2
test ax, 8000h
jz @F
xor enableWeapons, 1
cmp enableWeapons, 0
je set_peaceful_mode
mov gameMode, GAME_MODE_ACTION
mov playerWeapon, WEAPON_PISTOL
mov showCrosshair, 1
invoke ShowGameToast, OFFSET szWeaponsEnabledToast, 80, COLOR_YELLOW
jmp pause_menu_done
set_peaceful_mode:
mov gameMode, GAME_MODE_ADVENTURE
mov playerWeapon, WEAPON_NONE
mov showCrosshair, 0
invoke ShowGameToast, OFFSET szWeaponsDisabledToast, 80, COLOR_GREEN
jmp pause_menu_done
@@:
; Option 3: Toggle HUD (Clean vs Debug)
invoke GetAsyncKeyState, VK_KEY_3
test ax, 8000h
jz @F
xor hudStyle, 1
cmp hudStyle, HUD_STYLE_CLEAN
je toast_pause_clean
invoke ShowGameToast, OFFSET szHudDebugToast, 60, COLOR_CYAN
jmp pause_menu_done
toast_pause_clean:
invoke ShowGameToast, OFFSET szHudCleanToast, 60, COLOR_GREEN
jmp pause_menu_done
@@:
; Option 4: Restart level
invoke GetAsyncKeyState, VK_KEY_4
test ax, 8000h
jz @F
mov isGamePaused, 0
mov keyRestart, 1
jmp pause_menu_done
@@:
; Option 3: Toggle Map
invoke GetAsyncKeyState, VK_KEY_3
; Option 5: Quit to Windows
invoke GetAsyncKeyState, VK_KEY_5
test ax, 8000h
jz @F
xor keyShowMap, 1
@@:
; Option 4: Quit
invoke GetAsyncKeyState, VK_KEY_4
test ax, 8000h
jz @F
jz pause_menu_done
mov isRunning, 0
@@:
jmp pause_menu_done
menu_keys_released:
mov keyMenuHeld, 0
pause_menu_done:
ret
not_in_pause_menu:

View file

@ -1,7 +1,6 @@
; Windowless renderer used by EblanStudio. Same Render3DScene and overlays as game.
; Fixed wire layout is mirrored by editor/src/preview_protocol.h.
.data
previewPrefix db "--preview:",0
previewHandle dd 0
previewMemory dd 0
previewParent dd 0

View file

@ -220,19 +220,30 @@ Engine_RenderHUD PROC uses ebx ecx edx
call RenderCutsceneOverlay
ret
normal_engine_hud:
cmp hudStyle, HUD_STYLE_DEBUG
jne clean_hud_mode
; --- DEBUG / DEVELOPER HUD MODE ---
; 1. Top HUD Header
invoke DrawString8x8, 10, 10, OFFSET strEngineName, COLOR_YELLOW
invoke DrawString8x8, 8, 8, OFFSET strEngineName, COLOR_YELLOW
; 2. FPS Counter
invoke DrawString8x8, 10, 24, OFFSET szFpsLabel, COLOR_CYAN
invoke DrawNumber8x8, 42, 24, currentFps, COLOR_CYAN
; 2. FPS Counter (drawn at top right X=250 so it never overlaps left elements)
invoke DrawString8x8, 250, 8, OFFSET szFpsLabel, COLOR_CYAN
invoke DrawNumber8x8, 282, 8, currentFps, COLOR_CYAN
; 3. Controls Bar at Bottom
; 3. Controls Bar at Bottom (Debug mode only)
invoke DrawRect, 0, 215, SCREEN_W, 25, 00101010h
invoke DrawString8x8, 10, 218, OFFSET strControls1, COLOR_WHITE
invoke DrawString8x8, 10, 228, OFFSET strControls3, COLOR_GREEN
jmp check_hints
; 4. Door / Portal Interaction Hint (center screen)
clean_hud_mode:
; --- CLEAN / IMMERSIVE HUD MODE ---
; In clean mode, no watermarks and no permanent bottom bar.
; Full 320x240 view is dedicated to the game world.
check_hints:
; 4. Door / Portal Interaction Hint (Cleanly centered above crosshair)
call CheckDoorHint
cmp eax, 1
je show_door_hint
@ -241,11 +252,11 @@ normal_engine_hud:
jmp check_minimap
show_door_hint:
invoke DrawString8x8, 128, 150, OFFSET strDoorHint, COLOR_YELLOW
invoke DrawString8x8, 116, 140, OFFSET strDoorHint, COLOR_YELLOW
jmp check_minimap
show_portal_hint:
invoke DrawString8x8, 110, 150, OFFSET strPortalHint, COLOR_CYAN
invoke DrawString8x8, 110, 140, OFFSET strPortalHint, COLOR_CYAN
check_minimap:
cmp mapErrorFrames, 0
@ -369,14 +380,14 @@ ParseStartupMap PROC uses ebx ecx edx esi edi
skip_executable_quote:
lodsb
test al, al
jz startup_arg_done
jz check_cmdline_flags
cmp al, 34
jne skip_executable_quote
jmp skip_argument_spaces
skip_executable_word:
lodsb
test al, al
jz startup_arg_done
jz check_cmdline_flags
cmp al, 32
jne skip_executable_word
skip_argument_spaces:
@ -413,10 +424,59 @@ write_startup_char:
dec ecx
jnz startup_argument_loop
mov startupMapPath, 0
ret
jmp check_cmdline_flags
terminate_startup_arg:
mov byte ptr [edi], 0
startup_arg_done:
; If startupMapPath starts with '-' and not '--preview:', clear it
mov al, byte ptr [startupMapPath]
cmp al, '-'
jne check_cmdline_flags
mov esi, OFFSET startupMapPath
mov edi, OFFSET previewPrefix
mov ecx, 10
repe cmpsb
je check_cmdline_flags
mov byte ptr [startupMapPath], 0
check_cmdline_flags:
invoke GetCommandLineA
mov ebx, eax
invoke CheckCmdFlag, ebx, OFFSET szFlagNoWeapons
test eax, eax
jz @F
mov gameMode, GAME_MODE_ADVENTURE
mov enableWeapons, 0
mov playerWeapon, WEAPON_NONE
mov showCrosshair, 0
@@:
invoke CheckCmdFlag, ebx, OFFSET szFlagAdventure
test eax, eax
jz @F
mov gameMode, GAME_MODE_ADVENTURE
mov enableWeapons, 0
mov playerWeapon, WEAPON_NONE
mov showCrosshair, 0
@@:
invoke CheckCmdFlag, ebx, OFFSET szFlagAction
test eax, eax
jz @F
mov gameMode, GAME_MODE_ACTION
mov enableWeapons, 1
mov playerWeapon, WEAPON_PISTOL
mov showCrosshair, 1
@@:
invoke CheckCmdFlag, ebx, OFFSET szFlagDebugHud
test eax, eax
jz @F
mov hudStyle, HUD_STYLE_DEBUG
@@:
invoke CheckCmdFlag, ebx, OFFSET szFlagCleanHud
test eax, eax
jz @F
mov hudStyle, HUD_STYLE_CLEAN
@@:
ret
ParseStartupMap ENDP
@ -427,6 +487,7 @@ main PROC
LOCAL msg:MSG
LOCAL curTick:DWORD, elapsed:DWORD
call LoadProjectSettings
call ParseStartupMap
call TryEnginePreview
call Engine_Init

BIN
main.obj

Binary file not shown.