feat: add peaceful adventure mode, clean immersive HUD, and genre toggle
This commit is contained in:
parent
25bd6377a7
commit
341966debe
14 changed files with 473 additions and 80 deletions
13
AGENTS.md
13
AGENTS.md
|
|
@ -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.
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
BIN
engine.exe
BIN
engine.exe
Binary file not shown.
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
85
main.asm
85
main.asm
|
|
@ -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
BIN
main.obj
Binary file not shown.
Loading…
Add table
Reference in a new issue