Fixing minor stuff, working on Web version
This commit is contained in:
1 parent
5ecf5fb9d7
commit
7df68febca
38 files changed
+502
-167
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -27,7 +27,18 @@ except ImportError:
|
||||
# Paths relative to the resources directory — these files are never resized.
|
||||
EXCEPTIONS = {
|
||||
"loading.png",
|
||||
"loading_land003_en.png",
|
||||
"loading_land003_ru.png",
|
||||
"black.png",
|
||||
"transparent.png",
|
||||
"w/blue.png",
|
||||
"w/red.png",
|
||||
"w/spark.png",
|
||||
"w/star.png",
|
||||
"w/star_red.png",
|
||||
"w/white.png",
|
||||
"w/ui/img/main/aboutPage003android.png",
|
||||
"w/ui_en/img/main/aboutPage003android.png"
|
||||
}
|
||||
|
||||
# Path prefixes (relative to resources root, forward-slash) that get 8x reduction.
|
||||
@@ -35,13 +46,28 @@ HIGH_REDUCTION_PREFIXES = (
|
||||
"w/ui/img",
|
||||
)
|
||||
|
||||
LOW_REDUCTION_POSTFIXES = (
|
||||
"texAtlas002.png",
|
||||
"Building_work014.png",
|
||||
"Building_Floors_tex004.png",
|
||||
"Building_Walls_tex006.png",
|
||||
"asphalt003small.png",
|
||||
"Ext_Building004.png",
|
||||
"Plane3_tex002.png",
|
||||
"darklands_building002.png",
|
||||
"Staircase001.png",
|
||||
"Staircase_Obj002.png"
|
||||
)
|
||||
|
||||
def _resize_factor(rel: str) -> int:
|
||||
norm = rel.replace("\\", "/")
|
||||
for prefix in HIGH_REDUCTION_PREFIXES:
|
||||
if norm.startswith(prefix):
|
||||
return 8
|
||||
return 4
|
||||
for prefix in LOW_REDUCTION_POSTFIXES:
|
||||
if norm.endswith(prefix):
|
||||
return 2
|
||||
return 8
|
||||
|
||||
|
||||
def _next_pot(n: int) -> int:
|
||||
|
||||
@@ -15,6 +15,12 @@ option(OPTIMIZE_WEB_RESOURCES "Resize PNG images for web build (requires Python3
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
# Максимальная оптимизация кода и LTO (Link-Time Optimization)
|
||||
add_compile_options(-O3 -flto)
|
||||
add_link_options(-O3 -flto)
|
||||
endif()
|
||||
|
||||
# --- АВТО-ЗАГРУЗКА ЗАВИСИМОСТЕЙ ---
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FetchDependencies.cmake")
|
||||
# Теперь гарантированно есть папка ../thirdparty со всеми исходниками
|
||||
@@ -297,6 +303,10 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/index.html"
|
||||
DESTINATION .
|
||||
)
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/favicon.ico"
|
||||
DESTINATION .
|
||||
)
|
||||
|
||||
# resources.zip is served separately and downloaded asynchronously at runtime
|
||||
install(FILES "${RESOURCES_ZIP}" DESTINATION .)
|
||||
install(FILES "${MUSIC_ZIP}" DESTINATION .)
|
||||
|
||||
@@ -37,3 +37,14 @@ Run:
|
||||
```
|
||||
emrun --no_browser --port 8080 public
|
||||
```
|
||||
|
||||
# Release build
|
||||
|
||||
|
||||
```
|
||||
mkdir build_release
|
||||
cd build_release
|
||||
emcmake cmake -G Ninja -DCMAKE_BUILD_TYPE=Release ..
|
||||
cmake --build . --config Release
|
||||
cmake --install . --prefix ../dist
|
||||
```
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
@@ -2276,9 +2276,9 @@
|
||||
"en": "And maybe she will even give me some difficult assignment."
|
||||
},
|
||||
{
|
||||
"key": "Я даже уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"ru": "Я даже уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"en": "I'm even sure she's looking for me. She wants to give me some kind of assignment."
|
||||
"key": "Я уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"ru": "Я уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"en": "I'm sure she's looking for me. She wants to give me some kind of assignment."
|
||||
},
|
||||
{
|
||||
"key": "Пока ты не принесешь мне нож из учительской, никуда я тебя не выпущу. Ошо!",
|
||||
|
||||
@@ -293,14 +293,6 @@
|
||||
"speaker": "Бекзат",
|
||||
"portrait": "resources/dialogue/portrait_hero_neutral.png",
|
||||
"text": "Почему?",
|
||||
"next": "line_30"
|
||||
},
|
||||
{
|
||||
"id": "line_30",
|
||||
"type": "Line",
|
||||
"speaker": "Айпери",
|
||||
"portrait": "resources/dialogue/portrait_aiperi.png",
|
||||
"text": "Она опять будет скафнить.",
|
||||
"next": "line_25"
|
||||
},
|
||||
{
|
||||
@@ -308,7 +300,7 @@
|
||||
"type": "Line",
|
||||
"speaker": "Айпери",
|
||||
"portrait": "resources/dialogue/portrait_aiperi.png",
|
||||
"text": "Я даже уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"text": "Я уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"next": "line_26"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "websiteButton",
|
||||
"name": "reviewButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"y": 200,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Сайт игры Тень над Бишкеком",
|
||||
"text": "Оставьте отзыв в Google Play",
|
||||
"fontSize": 36,
|
||||
"color": [0.55, 0.9, 1.0, 1.0],
|
||||
"textCentered": true
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"root": {
|
||||
"type": "FrameLayout",
|
||||
"width": "match_parent",
|
||||
"height": "match_parent",
|
||||
"children": [
|
||||
{
|
||||
"type": "StaticImage",
|
||||
"name": "aboutBkg",
|
||||
"width": 2992,
|
||||
"height": 1632,
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"texture": "resources/w/ui/img/main/MenuBkg001_v001.png"
|
||||
},
|
||||
{
|
||||
"type": "StaticImage",
|
||||
"name": "aboutPicture",
|
||||
"width": 720,
|
||||
"height": 720,
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"texture": "resources/w/ui/img/main/aboutPage003android.png"
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "websiteButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"y": 200,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Сайт игры Тень над Бишкеком",
|
||||
"fontSize": 36,
|
||||
"color": [0.55, 0.9, 1.0, 1.0],
|
||||
"textCentered": true
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "telegramButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"y": -240,
|
||||
"x": -150,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Telegram-канал",
|
||||
"fontSize": 40,
|
||||
"color": [0.55, 0.9, 1.0, 1.0],
|
||||
"textCentered": true
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "discordButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"y": -240,
|
||||
"x": 150,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Наш Discord",
|
||||
"fontSize": 40,
|
||||
"color": [0.55, 0.9, 1.0, 1.0],
|
||||
"textCentered": true
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "aboutBackButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "bottom",
|
||||
"y": 40,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Назад",
|
||||
"fontSize": 40,
|
||||
"textCentered": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@
|
||||
"textCentered": false,
|
||||
"topAligned": true,
|
||||
"paddingX": 10,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
"color": [0.7, 0.7, 0.7, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "Slider",
|
||||
@@ -68,7 +68,7 @@
|
||||
"textCentered": false,
|
||||
"topAligned": true,
|
||||
"paddingX": 10,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
"color": [0.7, 0.7, 0.7, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "Slider",
|
||||
|
||||
@@ -38,31 +38,19 @@
|
||||
"name": "noMusicText1",
|
||||
"width": 500,
|
||||
"height": 40,
|
||||
"text": "Настройки музыки отсутствуют.",
|
||||
"text": "Музыка отсутствует.",
|
||||
"fontSize": 32,
|
||||
"textCentered": false,
|
||||
"topAligned": true,
|
||||
"paddingX": 10,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "TextView",
|
||||
"name": "noMusicText2",
|
||||
"width": 500,
|
||||
"height": 40,
|
||||
"text": "Пакет с музыкой не установлен.",
|
||||
"fontSize": 32,
|
||||
"textCentered": false,
|
||||
"topAligned": true,
|
||||
"paddingX": 10,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
"color": [0.7, 0.7, 0.7, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "musicDownloadButton",
|
||||
"width": 500,
|
||||
"height": 40,
|
||||
"text": "Нажмите сюда, чтобы скачать и установить музыку (30 MB).",
|
||||
"text": "Скачать пакет с музыкой (27 MB).",
|
||||
"fontSize": 32,
|
||||
"textCentered": true,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
@@ -77,7 +65,7 @@
|
||||
"textCentered": false,
|
||||
"topAligned": true,
|
||||
"paddingX": 10,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
"color": [0.7, 0.7, 0.7, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "Slider",
|
||||
|
||||
Binary file not shown.
@@ -24,13 +24,13 @@
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "websiteButton",
|
||||
"name": "reviewButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"y": 200,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Shadow over Bishkek website",
|
||||
"text": "Leave a review on Google Play",
|
||||
"fontSize": 36,
|
||||
"color": [0.55, 0.9, 1.0, 1.0],
|
||||
"textCentered": true
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"root": {
|
||||
"type": "FrameLayout",
|
||||
"width": "match_parent",
|
||||
"height": "match_parent",
|
||||
"children": [
|
||||
{
|
||||
"type": "StaticImage",
|
||||
"name": "aboutBkg",
|
||||
"width": 2992,
|
||||
"height": 1632,
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"texture": "resources/w/ui/img/main/MenuBkg001_v001.png"
|
||||
},
|
||||
{
|
||||
"type": "StaticImage",
|
||||
"name": "aboutPicture",
|
||||
"width": 720,
|
||||
"height": 720,
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"texture": "resources/w/ui_en/img/main/aboutPage003android.png"
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "websiteButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"y": 200,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Shadow over Bishkek website",
|
||||
"fontSize": 36,
|
||||
"color": [0.55, 0.9, 1.0, 1.0],
|
||||
"textCentered": true
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "telegramButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"y": -240,
|
||||
"x": -150,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Telegram channel",
|
||||
"fontSize": 40,
|
||||
"color": [0.55, 0.9, 1.0, 1.0],
|
||||
"textCentered": true
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "discordButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"y": -240,
|
||||
"x": 150,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Our Discord",
|
||||
"fontSize": 40,
|
||||
"color": [0.55, 0.9, 1.0, 1.0],
|
||||
"textCentered": true
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "aboutBackButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "bottom",
|
||||
"y": 40,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Back",
|
||||
"fontSize": 40,
|
||||
"textCentered": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -43,16 +43,6 @@
|
||||
"width": "match_parent",
|
||||
"height": "match_parent"
|
||||
},
|
||||
{
|
||||
"type": "StaticImage",
|
||||
"name": "chatTopCover",
|
||||
"width": 446.25,
|
||||
"height": 70.82,
|
||||
"x": 0,
|
||||
"y": -50.82,
|
||||
"horizontal_gravity": "center",
|
||||
"texture": "resources/w/ui/img/phone/chat_top_cover001.png"
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "chatTitleButton",
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"textCentered": false,
|
||||
"topAligned": true,
|
||||
"paddingX": 10,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
"color": [0.7, 0.7, 0.7, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "Slider",
|
||||
@@ -68,7 +68,7 @@
|
||||
"textCentered": false,
|
||||
"topAligned": true,
|
||||
"paddingX": 10,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
"color": [0.7, 0.7, 0.7, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "Slider",
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
{
|
||||
"root": {
|
||||
"type": "FrameLayout",
|
||||
"width": "match_parent",
|
||||
"height": "match_parent",
|
||||
"children": [
|
||||
{
|
||||
"type": "StaticImage",
|
||||
"name": "settingsBkg",
|
||||
"width": 2992,
|
||||
"height": 1632,
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"texture": "resources/w/ui/img/main/MenuBkg001_v001.png"
|
||||
},
|
||||
{
|
||||
"type": "LinearLayout",
|
||||
"orientation": "vertical",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "center",
|
||||
"horizontal_align": "left",
|
||||
"width": 500,
|
||||
"height": 600,
|
||||
"spacing": 20,
|
||||
"children": [
|
||||
{
|
||||
"type": "TextView",
|
||||
"name": "settingsTitleText",
|
||||
"width": 500,
|
||||
"height": 60,
|
||||
"text": "Settings",
|
||||
"fontSize": 40,
|
||||
"textCentered": true,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "TextView",
|
||||
"name": "noMusicText1",
|
||||
"width": 500,
|
||||
"height": 40,
|
||||
"text": "There is no music.",
|
||||
"fontSize": 32,
|
||||
"textCentered": false,
|
||||
"topAligned": true,
|
||||
"paddingX": 10,
|
||||
"color": [0.7, 0.7, 0.7, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "musicDownloadButton",
|
||||
"width": 500,
|
||||
"height": 40,
|
||||
"text": "Download music package (27 MB).",
|
||||
"fontSize": 32,
|
||||
"textCentered": true,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "TextView",
|
||||
"name": "soundVolumeText",
|
||||
"width": 500,
|
||||
"height": 40,
|
||||
"text": "",
|
||||
"fontSize": 32,
|
||||
"textCentered": false,
|
||||
"topAligned": true,
|
||||
"paddingX": 10,
|
||||
"color": [0.7, 0.7, 0.7, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "Slider",
|
||||
"name": "soundVolumeSlider",
|
||||
"width": 500,
|
||||
"height": 40,
|
||||
"orientation": "horizontal",
|
||||
"value": 0.625,
|
||||
"interactive": true,
|
||||
"textures": {
|
||||
"track": "resources/loadingProgressBarFrame.png",
|
||||
"knob": "resources/loadingProgressBar.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "soundToggleButton",
|
||||
"width": 500,
|
||||
"height": 40,
|
||||
"text": "",
|
||||
"fontSize": 32,
|
||||
"textCentered": true,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "graphicsButton",
|
||||
"width": 500,
|
||||
"height": 60,
|
||||
"text": "Graphics settings",
|
||||
"fontSize": 40,
|
||||
"textCentered": true,
|
||||
"color": [1.0, 1.0, 1.0, 1.0]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "TextButton",
|
||||
"name": "settingsBackButton",
|
||||
"horizontal_gravity": "center",
|
||||
"vertical_gravity": "bottom",
|
||||
"y": 40,
|
||||
"width": 200,
|
||||
"height": 60,
|
||||
"text": "Back",
|
||||
"fontSize": 40,
|
||||
"textCentered": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ int Environment::width = CONST_DEFAULT_WIDTH;
|
||||
int Environment::height = CONST_DEFAULT_HEIGHT;
|
||||
float Environment::zoom = DEFAULT_ZOOM;
|
||||
|
||||
|
||||
bool Environment::enableLogging = true;
|
||||
|
||||
SDL_Window* Environment::window = nullptr;
|
||||
|
||||
@@ -1291,6 +1291,8 @@ namespace FRG
|
||||
menuManager.onOrientationChanged();
|
||||
}
|
||||
|
||||
menuManager.refreshFullScreenToggleButton();
|
||||
|
||||
logger() << "Window resized (Render Size): " << Environment::width << "x" << Environment::height << std::endl;
|
||||
}
|
||||
|
||||
|
||||
+57
-11
@@ -28,9 +28,12 @@ namespace FRG {
|
||||
static const std::string BACK_TO_MAIN_MENU_EN = "Back to Main Menu";
|
||||
|
||||
static const std::string MUSIC_DOWNLOAD_ERROR_RU = u8"Ошибка скачивания музыки";
|
||||
static const std::string MUSIC_DOWNLOAD_NOT_STARTED_RU = u8"Нажмите сюда, чтобы скачать и установить музыку (27 MB).";
|
||||
static const std::string MUSIC_DOWNLOAD_NOT_STARTED_RU = u8"Скачать пакет с музыкой (27 MB).";
|
||||
static const std::string MUSIC_DOWNLOAD_PROGRESS_PREFIX_RU = u8"Загрузка музыки: ";
|
||||
//static const std::string MUSIC_DOWNLOAD_COMPLETED_RU = u8"Музыка успешно загружена.";
|
||||
|
||||
static const std::string MUSIC_DOWNLOAD_ERROR_EN = u8"Music download error";
|
||||
static const std::string MUSIC_DOWNLOAD_NOT_STARTED_EN = u8"Download music package (27 MB).";
|
||||
static const std::string MUSIC_DOWNLOAD_PROGRESS_PREFIX_EN = u8"Music download: ";
|
||||
|
||||
|
||||
static int questStatusPriority(Quest::QuestStatus status) {
|
||||
@@ -246,7 +249,7 @@ namespace FRG {
|
||||
void MenuManager::loadUiRoots(const std::string& zipFile) {
|
||||
hudRoot = loadLocalizedUi("resources/w/ui/hud_step0.json", zipFile);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__)
|
||||
hudStep1Root = loadLocalizedUi("resources/w/ui/hud_step1android.json", zipFile);
|
||||
hudStep2Root = loadLocalizedUi("resources/w/ui/hud_step2android.json", zipFile);
|
||||
#else
|
||||
@@ -288,7 +291,10 @@ namespace FRG {
|
||||
hudUniIntDarkFullRoot = loadLocalizedUi("resources/w/ui/hud_uni_int_dark_full.json", zipFile);
|
||||
hudUniExtDarkRoot = loadLocalizedUi("resources/w/ui/hud_uni_ext_dark.json", zipFile);
|
||||
|
||||
hudCutsceneRoot_ = loadLocalizedUi("resources/w/ui/hud_cutscene.json", zipFile);
|
||||
//hudCutsceneRoot_ = loadLocalizedUi("resources/w/ui/hud_cutscene.json", zipFile);
|
||||
hudCutsceneRoot_ = loadUiFromFile("resources/w/ui/hud_cutscene.json", renderer, zipFile);
|
||||
|
||||
|
||||
hudTopHintRoot_ = loadLocalizedUi("resources/w/ui/hud_top_hint01.json", zipFile);
|
||||
|
||||
phoneMainRoot = loadLocalizedUi("resources/w/ui/screen_phone.json", zipFile);
|
||||
@@ -329,12 +335,18 @@ namespace FRG {
|
||||
portraitQuestJournalListRoot = loadLocalizedUi("resources/w/ui/portrait_screen_journal.json", zipFile);
|
||||
portraitQuestJournalItemRoot = loadLocalizedUi("resources/w/ui/portrait_screen_journal_item.json", zipFile);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__EMSCRIPTEN__)
|
||||
mainMenuRoot = loadLocalizedUi("resources/w/ui/screen_main_menu_android.json", zipFile);
|
||||
aboutScreenRoot = loadLocalizedUi("resources/w/ui/screen_about_android.json", zipFile);
|
||||
#else
|
||||
mainMenuRoot = loadLocalizedUi("resources/w/ui/screen_main_menu.json", zipFile);
|
||||
aboutScreenRoot = loadLocalizedUi("resources/w/ui/screen_about.json", zipFile);
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
aboutScreenRoot = loadLocalizedUi("resources/w/ui/screen_about_android.json", zipFile);
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
aboutScreenRoot = loadLocalizedUi("resources/w/ui/screen_about_web.json", zipFile);
|
||||
#else
|
||||
aboutScreenRoot = loadLocalizedUi("resources/w/ui/screen_about.json", zipFile);
|
||||
#endif
|
||||
|
||||
creditsScreenRoot = loadLocalizedUi("resources/w/ui/screen_credits.json", zipFile);
|
||||
@@ -615,13 +627,19 @@ namespace FRG {
|
||||
});
|
||||
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#ifdef __EMSCRIPTEN__
|
||||
uiManager.setTextButtonCallback("websiteButton", [this](const std::string&) {
|
||||
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
||||
SDL_OpenURL("https://shadowoverbishkek.com/");
|
||||
});
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
uiManager.setTextButtonCallback("reviewButton", [this](const std::string&) {
|
||||
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
||||
SDL_OpenURL("https://play.google.com/store/apps/details?id=fishrungames.shadowoverbishkek");
|
||||
});
|
||||
#endif
|
||||
uiManager.setTextButtonCallback("telegramButton", [this](const std::string&) {
|
||||
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
||||
SDL_OpenURL("https://telegram.me/fishrungames");
|
||||
@@ -838,6 +856,23 @@ namespace FRG {
|
||||
});
|
||||
}
|
||||
|
||||
void MenuManager::refreshFullScreenToggleButton()
|
||||
{
|
||||
// Localization
|
||||
if (g_currentLanguage == Language::English)
|
||||
{
|
||||
fullScreenToggleOn = "Full Screen: ON";
|
||||
fullScreenToggleOff = "Full Screen: OFF";
|
||||
}
|
||||
else if (g_currentLanguage == Language::Russian)
|
||||
{
|
||||
fullScreenToggleOn = u8"Полноэкранный режим: ВКЛ";
|
||||
fullScreenToggleOff = u8"Полноэкранный режим: ВЫКЛ";
|
||||
}
|
||||
|
||||
const bool on = Environment::isFullscreen;
|
||||
uiManager.setTextButtonText("fullScreenToggleButton", on ? fullScreenToggleOn : fullScreenToggleOff);
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
void MenuManager::showSettingsNoMusicWebScreen()
|
||||
@@ -863,23 +898,30 @@ namespace FRG {
|
||||
const float soundFrac = audioPlayer_.getSoundVolume() / 128.0f;
|
||||
uiManager.setSliderValue("soundVolumeSlider", soundFrac);
|
||||
|
||||
static std::string musicDownloadErrorString;// = MUSIC_DOWNLOAD_ERROR_RU;
|
||||
static std::string musicDownloadNotStartedString;// = MUSIC_DOWNLOAD_NOT_STARTED_RU;
|
||||
static std::string musicDownloadProgressPrefix;// = MUSIC_DOWNLOAD_PROGRESS_PREFIX_RU;
|
||||
|
||||
// Localization
|
||||
if (g_currentLanguage == Language::English)
|
||||
{
|
||||
soundVolumePrefix = "Sound volume: ";
|
||||
soundToggleOn = "Sound: ON";
|
||||
soundToggleOff = "Sound: OFF";
|
||||
musicDownloadErrorString = MUSIC_DOWNLOAD_ERROR_EN;
|
||||
musicDownloadNotStartedString = MUSIC_DOWNLOAD_NOT_STARTED_EN;
|
||||
musicDownloadProgressPrefix = MUSIC_DOWNLOAD_PROGRESS_PREFIX_EN;
|
||||
}
|
||||
else if (g_currentLanguage == Language::Russian)
|
||||
{
|
||||
soundVolumePrefix = u8"Громкость звука: ";
|
||||
soundToggleOn = u8"Звук: ВКЛ";
|
||||
soundToggleOff = u8"Звук: ВЫКЛ";
|
||||
musicDownloadErrorString = MUSIC_DOWNLOAD_ERROR_RU;
|
||||
musicDownloadNotStartedString = MUSIC_DOWNLOAD_NOT_STARTED_RU;
|
||||
musicDownloadProgressPrefix = MUSIC_DOWNLOAD_PROGRESS_PREFIX_RU;
|
||||
}
|
||||
|
||||
static std::string musicDownloadErrorString = u8"Ошибка скачивания музыки";
|
||||
static std::string musicDownloadNotStartedString = u8"Нажмите сюда, чтобы скачать\nи установить музыку (27 MB).";
|
||||
static std::string musicDownloadProgressPrefix = u8"Загрузка музыки: ";
|
||||
|
||||
// musicDownloadStarted = false;
|
||||
//musicDownloadError = false;
|
||||
@@ -969,13 +1011,17 @@ namespace FRG {
|
||||
});
|
||||
|
||||
uiManager.setTextButtonCallback("languageRussianButton", [this](const std::string&) {
|
||||
#ifndef __EMSCRIPTEN__
|
||||
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
||||
#endif
|
||||
FRG::g_currentLanguage = FRG::Language::Russian;
|
||||
reloadLocalizedGameContent();
|
||||
saveSettings();
|
||||
});
|
||||
uiManager.setTextButtonCallback("languageEnglishButton", [this](const std::string&) {
|
||||
#ifndef __EMSCRIPTEN__
|
||||
audioPlayer_.playSoundAsync("resources/audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
|
||||
#endif
|
||||
FRG::g_currentLanguage = FRG::Language::English;
|
||||
reloadLocalizedGameContent();
|
||||
saveSettings();
|
||||
|
||||
@@ -129,7 +129,14 @@ namespace FRG {
|
||||
std::shared_ptr<Texture> languageLoadingRu;
|
||||
std::shared_ptr<Texture> languageLoadingEn;
|
||||
|
||||
|
||||
void refreshFullScreenToggleButton();
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
bool shadowsEnabled = false;
|
||||
#else
|
||||
bool shadowsEnabled = true;
|
||||
#endif
|
||||
std::string lastMusicTrack;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
@@ -189,6 +196,7 @@ namespace FRG {
|
||||
void showCreditsScreen();
|
||||
void showSettingsScreen();
|
||||
void showSettingsGraphicsScreen();
|
||||
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
void showSettingsNoMusicWebScreen();
|
||||
|
||||
+4
-4
@@ -798,14 +798,14 @@ namespace FRG {
|
||||
else {
|
||||
auto buf = readFileFromZIP(path, zipFile);
|
||||
if (buf.empty()) {
|
||||
std::cerr << "UiManager: failed to read " << path << " from zip " << zipFile << std::endl;
|
||||
logger() << "UiManager: failed to read " << path << " from zip " << zipFile << std::endl;
|
||||
throw std::runtime_error("Failed to load UI file: " + path);
|
||||
}
|
||||
content.assign(buf.begin(), buf.end());
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "UiManager: failed to open " << path << " : " << e.what() << std::endl;
|
||||
logger() << "UiManager: failed to open " << path << " : " << e.what() << std::endl;
|
||||
throw std::runtime_error("Failed to load UI file: " + path);
|
||||
}
|
||||
|
||||
@@ -814,12 +814,12 @@ namespace FRG {
|
||||
j = json::parse(content);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "UiManager: json parse error: " << e.what() << std::endl;
|
||||
logger() << "UiManager: json parse error: " << e.what() << std::endl;
|
||||
throw std::runtime_error("Failed to load UI file: " + path);
|
||||
}
|
||||
|
||||
if (!j.contains("root") || !j["root"].is_object()) {
|
||||
std::cerr << "UiManager: root node missing or invalid" << std::endl;
|
||||
logger() << "UiManager: root node missing or invalid" << std::endl;
|
||||
throw std::runtime_error("Failed to load UI file: " + path);
|
||||
}
|
||||
|
||||
|
||||
+80
-59
@@ -20,15 +20,48 @@
|
||||
FRG::Game* g_game = nullptr;
|
||||
|
||||
|
||||
// Read the persisted fullscreen preference (if any) before creating the
|
||||
// window, so it opens directly in the right mode instead of flashing
|
||||
// windowed -> fullscreen once settings are loaded later during setupPart2().
|
||||
|
||||
void readSettings()
|
||||
{
|
||||
|
||||
const std::string settingsContent = FRG::readSavedTextFile("settings.json");
|
||||
if (!settingsContent.empty()) {
|
||||
try {
|
||||
const nlohmann::json settingsRoot = nlohmann::json::parse(settingsContent);
|
||||
if (settingsRoot.contains("fullscreen")) {
|
||||
FRG::Environment::isFullscreen = settingsRoot["fullscreen"].get<bool>();
|
||||
}
|
||||
|
||||
if (settingsRoot.contains("isHighDPIEnabled")) {
|
||||
FRG::Environment::isHighDPIEnabled = settingsRoot["isHighDPIEnabled"].get<bool>();
|
||||
}
|
||||
|
||||
if (settingsRoot.contains("enableLogging")) {
|
||||
FRG::Environment::enableLogging = settingsRoot["enableLogging"].get<bool>();
|
||||
}
|
||||
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "[settings] Failed to parse settings.json: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(EMSCRIPTEN)
|
||||
static SDL_GLContext glContext_x;
|
||||
static bool g_isFsLoaded = false; // Флаг готовности
|
||||
|
||||
static bool g_pendingFullscreenResize = false;
|
||||
|
||||
// Макрос EMSCRIPTEN_KEEPALIVE экспортирует функцию в глобальный объект Module
|
||||
extern "C" void EMSCRIPTEN_KEEPALIVE onFileSystemLoaded() {
|
||||
// 1. Файлы загружены. Теперь можно читать настройки и логи
|
||||
// Если функции readSettings() нет для Emscripten, форсируем логгер:
|
||||
FRG::Environment::enableLogging = true;
|
||||
//FRG::Environment::enableLogging = true;
|
||||
//readSettings();
|
||||
FRG::initLogger();
|
||||
|
||||
FRG::logger() << "[boot] File system is ready. Setting up game..." << std::endl;
|
||||
@@ -40,26 +73,7 @@ extern "C" void EMSCRIPTEN_KEEPALIVE onFileSystemLoaded() {
|
||||
// 3. Даем отмашку главному циклу
|
||||
g_isFsLoaded = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainLoop() {
|
||||
#if defined(EMSCRIPTEN)
|
||||
// Крутим цикл вхолостую, пока JS читает IndexedDB
|
||||
if (!g_isFsLoaded) return;
|
||||
#endif
|
||||
|
||||
g_game->update();
|
||||
}
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
|
||||
EM_BOOL onWebGLContextLost(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
|
||||
return EM_TRUE;
|
||||
}
|
||||
|
||||
EM_BOOL onWebGLContextRestored(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
|
||||
return EM_TRUE;
|
||||
}
|
||||
|
||||
static void applyResize(int logicalW, int logicalH) {
|
||||
// Получаем коэффициент плотности пикселей (например, 2.625 на Pixel или 3.0 на Samsung)
|
||||
@@ -92,22 +106,59 @@ static void applyResize(int logicalW, int logicalH) {
|
||||
<< " (physical: " << physicalW << "x" << physicalH
|
||||
<< ", DPR: " << dpr << ")" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainLoop() {
|
||||
#if defined(EMSCRIPTEN)
|
||||
// Крутим цикл вхолостую, пока JS читает IndexedDB
|
||||
if (!g_isFsLoaded) return;
|
||||
|
||||
if (g_pendingFullscreenResize) {
|
||||
g_pendingFullscreenResize = false;
|
||||
|
||||
// Теперь DOM перестроен, можно забирать актуальные размеры.
|
||||
// Если canvas должен занимать все окно браузера:
|
||||
int canvasW = EM_ASM_INT({ return window.innerWidth; });
|
||||
int canvasH = EM_ASM_INT({ return window.innerHeight; });
|
||||
|
||||
applyResize(canvasW, canvasH);
|
||||
}
|
||||
#endif
|
||||
|
||||
g_game->update();
|
||||
}
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
|
||||
|
||||
EM_BOOL onWebGLContextLost(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
|
||||
return EM_TRUE;
|
||||
}
|
||||
|
||||
EM_BOOL onWebGLContextRestored(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
|
||||
return EM_TRUE;
|
||||
}
|
||||
|
||||
|
||||
EM_BOOL onWindowResized(int /*eventType*/, const EmscriptenUiEvent* e, void* /*userData*/) {
|
||||
// Use the event's window dimensions — querying the canvas element would
|
||||
// return its old fixed size (e.g. 1280x720) before it has been resized.
|
||||
applyResize(e->windowInnerWidth, e->windowInnerHeight);
|
||||
double w, h;
|
||||
emscripten_get_element_css_size("window", &w, &h);
|
||||
|
||||
// Если "window" не поддерживается вашей версией SDK, используем данные из e:
|
||||
// int logicalW = e->windowInnerWidth;
|
||||
// int logicalH = e->windowInnerHeight;
|
||||
|
||||
applyResize(static_cast<int>(w), static_cast<int>(h));
|
||||
return EM_FALSE;
|
||||
}
|
||||
|
||||
EM_BOOL onFullscreenChanged(int /*eventType*/, const EmscriptenFullscreenChangeEvent* e, void* /*userData*/) {
|
||||
FRG::Environment::isFullscreen = e->isFullscreen;
|
||||
FRG::logger() << "onFullscreenChanged: isFullscreen = " << e->isFullscreen << std::endl;
|
||||
|
||||
// Браузер еще не обновил DOM. Ставим флаг, чтобы применить размеры в следующем кадре.
|
||||
g_pendingFullscreenResize = true;
|
||||
|
||||
// Вместо window.innerWidth, попробуйте запросить размер целевого элемента
|
||||
// так как после перехода в FS именно он растягивается на весь экран.
|
||||
double clientW, clientH;
|
||||
emscripten_get_element_css_size("#canvas", &clientW, &clientH);
|
||||
applyResize(clientW, clientH);
|
||||
return EM_FALSE;
|
||||
}
|
||||
|
||||
@@ -128,7 +179,7 @@ int main(int argc, char* argv[]) {
|
||||
emscripten_set_webglcontextrestored_callback("#canvas", nullptr, EM_TRUE, onWebGLContextRestored);
|
||||
|
||||
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_FALSE, onWindowResized);
|
||||
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, EM_FALSE, onFullscreenChanged);
|
||||
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, EM_TRUE, onFullscreenChanged);
|
||||
|
||||
int canvasW = EM_ASM_INT({ return window.innerWidth; });
|
||||
int canvasH = EM_ASM_INT({ return window.innerHeight; });
|
||||
@@ -289,36 +340,6 @@ int main(int argc, char* argv[]) {
|
||||
#ifndef __ANDROID__
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__linux__)
|
||||
|
||||
// Read the persisted fullscreen preference (if any) before creating the
|
||||
// window, so it opens directly in the right mode instead of flashing
|
||||
// windowed -> fullscreen once settings are loaded later during setupPart2().
|
||||
void readSettings()
|
||||
{
|
||||
|
||||
const std::string settingsContent = FRG::readSavedTextFile("settings.json");
|
||||
if (!settingsContent.empty()) {
|
||||
try {
|
||||
const nlohmann::json settingsRoot = nlohmann::json::parse(settingsContent);
|
||||
if (settingsRoot.contains("fullscreen")) {
|
||||
FRG::Environment::isFullscreen = settingsRoot["fullscreen"].get<bool>();
|
||||
}
|
||||
|
||||
if (settingsRoot.contains("isHighDPIEnabled")) {
|
||||
FRG::Environment::isHighDPIEnabled = settingsRoot["isHighDPIEnabled"].get<bool>();
|
||||
}
|
||||
|
||||
if (settingsRoot.contains("enableLogging")) {
|
||||
FRG::Environment::enableLogging = settingsRoot["enableLogging"].get<bool>();
|
||||
}
|
||||
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "[settings] Failed to parse settings.json: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
SDL_GLContext ctx = nullptr;
|
||||
|
||||
@@ -509,8 +509,13 @@ namespace FRG
|
||||
}
|
||||
#ifdef __ANDROID__
|
||||
return g_androidStream;
|
||||
#else
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return g_nullStream; //For web, remove all logging to browser console
|
||||
#else
|
||||
return std::cout;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user