Compare commits

...

8 Commits

Author SHA1 Message Date
Vladislav Khorev
a11c4614ea Resize Android even more, fixing crash when changing languages on Android 2026-08-01 20:18:18 +03:00
Vladislav Khorev
5cbe7a345e Android version bug fix 2026-08-01 19:42:21 +03:00
Vladislav Khorev
2add42c1cb Minor changes for the Windows non-steam version 2026-07-25 17:27:21 +03:00
Vladislav Khorev
4039c24372 change permissions 2026-07-25 16:58:18 +03:00
Vladislav Khorev
7df68febca Fixing minor stuff, working on Web version 2026-07-25 16:56:02 +03:00
Vladislav Khorev
5ecf5fb9d7 Adapting music to web, fixing scripts, fixing bug in initial state 2026-07-24 23:58:29 +03:00
Vladislav Khorev
c3f449b999 Prepare a version for Steam and fixing bugs 2026-07-22 10:59:20 +03:00
Vladislav Khorev
8a0a8390b2 Windows, make portable version + NSIS installer 2026-07-20 21:54:43 +03:00
229 changed files with 3205 additions and 602 deletions

3
.gitattributes vendored
View File

@ -5,3 +5,6 @@
*.wav filter=lfs diff=lfs merge=lfs -text *.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text *.ogg filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text *.mp3 filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text

2
.gitignore vendored
View File

@ -409,7 +409,7 @@ web_resources/
pc_resources/ pc_resources/
resources_hd/ resources_hd/
web_resources_x2/ web_resources_x2/
android_resources/
.artifacts/ .artifacts/

View File

@ -185,3 +185,44 @@ make -j$(nproc) -C build #Компилируем
Для постройки без звука Для постройки без звука
rm -rf build #Очищаем build папку rm -rf build #Очищаем build папку
cmake -B build -DAUDIO=1 #Пересоздаём конфигурацию CMake cmake -B build -DAUDIO=1 #Пересоздаём конфигурацию CMake
# Cmake Build NSIS and Portable for Windows:
```
cmake --build . --config Release
cpack -C Release
```
Если есть такая ошибка:
CPack Error: Cannot find NSIS compiler makensis: likely it is not installed, or not in your PATH
CPack Error: Could not read NSIS registry value. This is usually caused by NSIS not being installed. Please install NSIS from http://nsis.sourceforge.net
CPack Error: Cannot initialize the generator NSIS
То нужно установить nsis отсюда: https://nsis.sourceforge.io/Download
# Steam windows
```
cmake -DSTEAMSDK=ON ..
cmake --build . --config Release
```
# Steam Linux
```
docker run -it --rm -v "${PWD}:/work2" -w /work2 registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest bash
apt-get update
apt-get install libboost-dev libeigen3-dev liblua5.4-dev libzip-dev libglu1-mesa-dev
cmake -DSTEAMSDK=ON -DCMAKE_BUILD_TYPE=Release ..
cmake --build . -j 4
```

View File

@ -0,0 +1,128 @@
#!/usr/bin/env python3
"""
optimize_web_resources.py - Resize PNG images for the web build.
Copies <src> to <dst>/resources/, then downscales all PNG files:
- resources/w/ui/img/** -> 1/8 original size
- all other PNGs -> 1/4 original size
Files listed in EXCEPTIONS are copied unchanged.
Usage (manual):
python optimize_web_resources.py [--src resources] [--dst web_resources]
Usage (CMake):
${Python3_EXECUTABLE} optimize_web_resources.py --src <abs_src> --dst <abs_dst>
"""
import argparse
import os
import shutil
try:
from PIL import Image
except ImportError:
raise SystemExit("Pillow is required: pip install Pillow")
# 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",
"w/exterior/texAtlas002.png",
}
# Path prefixes (relative to resources root, forward-slash) that get 8x reduction.
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
for prefix in LOW_REDUCTION_POSTFIXES:
if norm.endswith(prefix):
return 2
return 4
def _next_pot(n: int) -> int:
if n < 1:
return 1
p = 1
while p < n:
p <<= 1
return p
def optimize(src_dir: str, dst_parent: str) -> None:
src_dir = os.path.abspath(src_dir)
dst_resources = os.path.join(os.path.abspath(dst_parent), "resources")
print(f"Copying {src_dir} -> {dst_resources}")
if os.path.exists(dst_resources):
shutil.rmtree(dst_resources)
shutil.copytree(src_dir, dst_resources)
total = 0
for root, _dirs, files in os.walk(dst_resources):
for filename in files:
if not filename.lower().endswith(".png"):
continue
full_path = os.path.join(root, filename)
rel = os.path.relpath(full_path, dst_resources).replace("\\", "/")
if rel in EXCEPTIONS:
print(f" skip (exception): {rel}")
continue
factor = _resize_factor(rel)
with Image.open(full_path) as img:
orig_w, orig_h = img.size
new_w = _next_pot(max(1, orig_w // factor))
new_h = _next_pot(max(1, orig_h // factor))
resized = img.resize((new_w, new_h), Image.LANCZOS)
resized.save(full_path)
print(f" {rel}: {orig_w}x{orig_h} -> {new_w}x{new_h} (/{factor} + POT)")
total += 1
print(f"Done. Resized {total} PNG file(s).")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Optimize PNG images for web build")
parser.add_argument("--src", default="resources",
help="Source resources directory (default: resources)")
parser.add_argument("--dst", default="android_resources",
help="Destination parent directory; will contain a 'resources' subdir "
"(default: android_resources)")
args = parser.parse_args()
optimize(args.src, args.dst)

View File

@ -27,7 +27,18 @@ except ImportError:
# Paths relative to the resources directory — these files are never resized. # Paths relative to the resources directory — these files are never resized.
EXCEPTIONS = { EXCEPTIONS = {
"loading.png", "loading.png",
"loading_land003_en.png",
"loading_land003_ru.png",
"black.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. # Path prefixes (relative to resources root, forward-slash) that get 8x reduction.
@ -35,13 +46,28 @@ HIGH_REDUCTION_PREFIXES = (
"w/ui/img", "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: def _resize_factor(rel: str) -> int:
norm = rel.replace("\\", "/") norm = rel.replace("\\", "/")
for prefix in HIGH_REDUCTION_PREFIXES: for prefix in HIGH_REDUCTION_PREFIXES:
if norm.startswith(prefix): if norm.startswith(prefix):
return 8 return 8
return 4 for prefix in LOW_REDUCTION_POSTFIXES:
if norm.endswith(prefix):
return 2
return 8
def _next_pot(n: int) -> int: def _next_pot(n: int) -> int:

View File

@ -61,6 +61,5 @@ app/jni/libpng
app/jni/SDL app/jni/SDL
app/jni/zlib app/jni/zlib
app/src/main/assets/resources app/src/main/assets
app/src/main/assets/audio

View File

@ -1,4 +1,4 @@
def buildAsLibrary = project.hasProperty('BUILD_AS_LIBRARY'); def buildAsLibrary = project.hasProperty('BUILD_AS_LIBRARY')
def buildAsApplication = !buildAsLibrary def buildAsApplication = !buildAsLibrary
if (buildAsApplication) { if (buildAsApplication) {
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
@ -15,8 +15,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 37 targetSdkVersion 37
versionCode 1 versionCode 4
versionName "1.0" versionName "1.0.7"
externalNativeBuild { externalNativeBuild {
/*ndkBuild { /*ndkBuild {
arguments "APP_PLATFORM=android-19" arguments "APP_PLATFORM=android-19"
@ -31,7 +31,10 @@ android {
} }
buildTypes { buildTypes {
release { release {
minifyEnabled false // Enables code optimizations.
minifyEnabled = true
// Enables resource shrinking.
shrinkResources = true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }
} }

View File

@ -16,18 +16,21 @@
# public *; # public *;
#} #}
-keep,includedescriptorclasses,allowoptimization class fishrungames.shadowoverbishkek.SDLInputConnection { # SDL2 specific rules
-keep class org.libsdl.app.** { *; }
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLInputConnection {
void nativeCommitText(java.lang.String, int); void nativeCommitText(java.lang.String, int);
void nativeGenerateScancodeForUnichar(char); void nativeGenerateScancodeForUnichar(char);
} }
-keep,includedescriptorclasses class fishrungames.shadowoverbishkek.SDLActivity { -keep,includedescriptorclasses class org.libsdl.app.SDLActivity {
# for some reason these aren't compatible with allowoptimization modifier # for some reason these aren't compatible with allowoptimization modifier
boolean supportsRelativeMouse(); boolean supportsRelativeMouse();
void setWindowStyle(boolean); void setWindowStyle(boolean);
} }
-keep,includedescriptorclasses,allowoptimization class fishrungames.shadowoverbishkek.SDLActivity { -keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLActivity {
java.lang.String nativeGetHint(java.lang.String); # Java-side doesn't use this, so it gets minified, but C-side still tries to register it java.lang.String nativeGetHint(java.lang.String); # Java-side doesn't use this, so it gets minified, but C-side still tries to register it
boolean onNativeSoftReturnKey(); boolean onNativeSoftReturnKey();
void onNativeKeyboardFocusLost(); void onNativeKeyboardFocusLost();
@ -62,7 +65,7 @@
boolean showTextInput(int, int, int, int); boolean showTextInput(int, int, int, int);
} }
-keep,includedescriptorclasses,allowoptimization class fishrungames.shadowoverbishkek.HIDDeviceManager { -keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
boolean initialize(boolean, boolean); boolean initialize(boolean, boolean);
boolean openDevice(int); boolean openDevice(int);
int sendOutputReport(int, byte[]); int sendOutputReport(int, byte[]);
@ -71,7 +74,7 @@
void closeDevice(int); void closeDevice(int);
} }
-keep,includedescriptorclasses,allowoptimization class fishrungames.shadowoverbishkek.SDLAudioManager { -keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLAudioManager {
int[] getAudioOutputDevices(); int[] getAudioOutputDevices();
int[] getAudioInputDevices(); int[] getAudioInputDevices();
int[] audioOpen(int, int, int, int, int); int[] audioOpen(int, int, int, int, int);
@ -90,9 +93,12 @@
native void addAudioDevice(boolean, int); native void addAudioDevice(boolean, int);
} }
-keep,includedescriptorclasses,allowoptimization class fishrungames.shadowoverbishkek.SDLControllerManager { -keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLControllerManager {
void pollInputDevices(); void pollInputDevices();
void pollHapticDevices(); void pollHapticDevices();
void hapticRun(int, float, int); void hapticRun(int, float, int);
void hapticStop(int); void hapticStop(int);
} }
# Keep our main activity
-keep class fishrungames.shadowoverbishkek.ShadowOverBishkekActivity { *; }

View File

@ -19,7 +19,7 @@ android.r8.strictFullModeForKeepRules=false
android.sdk.defaultTargetSdkToCompileSdkIfUnset=false android.sdk.defaultTargetSdkToCompileSdkIfUnset=false
android.uniquePackageNames=false android.uniquePackageNames=false
android.usesSdkInManifest.disallowed=false android.usesSdkInManifest.disallowed=false
org.gradle.jvmargs=-Xmx1536m org.gradle.jvmargs=-Xmx4096m
android.useAndroidX=true android.useAndroidX=true
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.

View File

@ -290,7 +290,7 @@ endif()
# =========================================== # ===========================================
set(RUNTIME_RESOURCE_DIRS set(RUNTIME_RESOURCE_DIRS
"resources" "resources"
"audio" "music"
) )
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS) foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)

View File

@ -8,13 +8,19 @@ if(NOT CMAKE_MAKE_PROGRAM AND WIN32)
endif() endif()
endif() endif()
project(bishkek-witcher LANGUAGES C CXX) project(ShadowOverBishkekDemo LANGUAGES C CXX)
option(OPTIMIZE_WEB_RESOURCES "Resize PNG images for web build (requires Python3 + Pillow)" ON) option(OPTIMIZE_WEB_RESOURCES "Resize PNG images for web build (requires Python3 + Pillow)" ON)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) 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") include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FetchDependencies.cmake")
# Теперь гарантированно есть папка ../thirdparty со всеми исходниками # Теперь гарантированно есть папка ../thirdparty со всеми исходниками
@ -152,10 +158,10 @@ set(SOURCES
../src/render/UiQuad.h ../src/render/UiQuad.h
) )
add_executable(bishkek-witcher ${SOURCES}) add_executable(ShadowOverBishkekDemo ${SOURCES})
# Настройка путей к инклудам (используем скачанные исходники) # Настройка путей к инклудам (используем скачанные исходники)
target_include_directories(bishkek-witcher PRIVATE target_include_directories(ShadowOverBishkekDemo PRIVATE
../src ../src
../thirdparty/eigen-5.0.0 ../thirdparty/eigen-5.0.0
../thirdparty/boost_1_90_0 ../thirdparty/boost_1_90_0
@ -170,7 +176,7 @@ set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
add_subdirectory("../thirdparty/libzip-1.11.4" libzip-build) add_subdirectory("../thirdparty/libzip-1.11.4" libzip-build)
target_link_libraries(bishkek-witcher PRIVATE zip z lua_static websocket.js) target_link_libraries(ShadowOverBishkekDemo PRIVATE zip z lua_static websocket.js)
# Эмскриптен-флаги # Эмскриптен-флаги
set(EMSCRIPTEN_FLAGS set(EMSCRIPTEN_FLAGS
@ -187,7 +193,7 @@ set(EMSCRIPTEN_FLAGS
"-DNETWORK" "-DNETWORK"
) )
target_compile_options(bishkek-witcher PRIVATE ${EMSCRIPTEN_FLAGS} "-O2") target_compile_options(ShadowOverBishkekDemo PRIVATE ${EMSCRIPTEN_FLAGS} "-O2")
# Only loading.png and the shaders used before resources.zip is ready are preloaded. # Only loading.png and the shaders used before resources.zip is ready are preloaded.
# resources.zip is downloaded asynchronously at runtime and served as a separate file. # resources.zip is downloaded asynchronously at runtime and served as a separate file.
@ -205,15 +211,14 @@ set(EMSCRIPTEN_LINK_FLAGS
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_uni_interior.lua@resources/start_uni_interior.lua" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_uni_interior.lua@resources/start_uni_interior.lua"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_uni_exterior.lua@resources/start_uni_exterior.lua" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_uni_exterior.lua@resources/start_uni_exterior.lua"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_dorm.lua@resources/start_dorm.lua" "--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_dorm.lua@resources/start_dorm.lua"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../audio@audio"
) )
# Применяем настройки линковки # Применяем настройки линковки
target_link_options(bishkek-witcher PRIVATE ${EMSCRIPTEN_LINK_FLAGS}) target_link_options(ShadowOverBishkekDemo PRIVATE ${EMSCRIPTEN_LINK_FLAGS})
# Для совместимости со старыми версиями CMake, если target_link_options недостаточно # Для совместимости со старыми версиями CMake, если target_link_options недостаточно
string(REPLACE ";" " " EMSCRIPTEN_LINK_FLAGS_STR "${EMSCRIPTEN_LINK_FLAGS}") string(REPLACE ";" " " EMSCRIPTEN_LINK_FLAGS_STR "${EMSCRIPTEN_LINK_FLAGS}")
set_target_properties(bishkek-witcher PROPERTIES set_target_properties(ShadowOverBishkekDemo PROPERTIES
LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS_STR}" LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS_STR}"
SUFFIX ".html" SUFFIX ".html"
) )
@ -257,23 +262,40 @@ else()
) )
endif() endif()
# music resources
set(MUSIC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../music")
set(MUSIC_ZIP "${CMAKE_CURRENT_BINARY_DIR}/music.zip")
get_filename_component(MUSIC_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.." ABSOLUTE)
add_custom_command(
OUTPUT "${MUSIC_ZIP}"
COMMAND ${CMAKE_COMMAND} -E tar "cf" "${MUSIC_ZIP}" --format=zip "music"
WORKING_DIRECTORY "${MUSIC_PARENT_DIR}"
DEPENDS "${MUSIC_PARENT_DIR}/music"
)
add_custom_target(pack_resources DEPENDS "${RESOURCES_ZIP}") add_custom_target(pack_resources DEPENDS "${RESOURCES_ZIP}")
add_dependencies(bishkek-witcher pack_resources) add_dependencies(ShadowOverBishkekDemo pack_resources)
add_custom_target(pack_music DEPENDS "${MUSIC_ZIP}")
add_dependencies(ShadowOverBishkekDemo pack_music)
# Определяем путь к директории установки (относительно папки билда) # Определяем путь к директории установки (относительно папки билда)
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/public") set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/public")
# 1. Устанавливаем основной HTML файл # 1. Устанавливаем основной HTML файл
install(TARGETS bishkek-witcher install(TARGETS ShadowOverBishkekDemo
RUNTIME DESTINATION . RUNTIME DESTINATION .
) )
# 2. Устанавливаем сопутствующие файлы (JS, WASM и сгенерированный архив данных) # 2. Устанавливаем сопутствующие файлы (JS, WASM и сгенерированный архив данных)
install(FILES install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/bishkek-witcher.js" "${CMAKE_CURRENT_BINARY_DIR}/ShadowOverBishkekDemo.js"
"${CMAKE_CURRENT_BINARY_DIR}/bishkek-witcher.wasm" "${CMAKE_CURRENT_BINARY_DIR}/ShadowOverBishkekDemo.wasm"
"${CMAKE_CURRENT_BINARY_DIR}/bishkek-witcher.data" "${CMAKE_CURRENT_BINARY_DIR}/ShadowOverBishkekDemo.data"
DESTINATION . DESTINATION .
) )
@ -281,10 +303,15 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/index.html"
DESTINATION . DESTINATION .
) )
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/favicon.ico"
DESTINATION .
)
# resources.zip is served separately and downloaded asynchronously at runtime # resources.zip is served separately and downloaded asynchronously at runtime
install(FILES "${RESOURCES_ZIP}" DESTINATION .) install(FILES "${RESOURCES_ZIP}" DESTINATION .)
install(FILES "${MUSIC_ZIP}" DESTINATION .)
add_custom_command(TARGET bishkek-witcher POST_BUILD add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD
COMMAND ${CMAKE_COMMAND} --install . COMMAND ${CMAKE_COMMAND} --install .
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
COMMENT "Automatically deploying to public directory..." COMMENT "Automatically deploying to public directory..."

View File

@ -37,3 +37,14 @@ Run:
``` ```
emrun --no_browser --port 8080 public 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
```

File diff suppressed because one or more lines are too long

BIN
proj-web/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -39,7 +39,7 @@
function loadGameScript() { function loadGameScript() {
var s = document.createElement('script'); var s = document.createElement('script');
s.src = 'bishkek-witcher.js'; s.src = 'ShadowOverBishkekDemo.js';
s.async = true; s.async = true;
document.body.appendChild(s); document.body.appendChild(s);
} }

View File

@ -1,2 +0,0 @@
<!doctypehtml><html lang=en-us><head><meta charset=utf-8><meta content="text/html; charset=utf-8"http-equiv=Content-Type><title>Emscripten-Generated Code</title><style>body{font-family:arial;margin:0;padding:none}.emscripten{padding-right:0;margin-left:auto;margin-right:auto;display:block}div.emscripten{text-align:center}div.emscripten_border{border:1px solid #000}canvas.emscripten{border:0 none;background-color:#000}#emscripten_logo{display:inline-block;margin:0;padding:6px;width:265px}.spinner{height:30px;width:30px;margin:0;margin-top:20px;margin-left:20px;display:inline-block;vertical-align:top;-webkit-animation:rotation .8s linear infinite;-moz-animation:rotation .8s linear infinite;-o-animation:rotation .8s linear infinite;animation:rotation .8s linear infinite;border-left:5px solid #ebebeb;border-right:5px solid #ebebeb;border-bottom:5px solid #ebebeb;border-top:5px solid #787878;border-radius:100%;background-color:#bdd72e}@-webkit-keyframes rotation{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}@-moz-keyframes rotation{from{-moz-transform:rotate(0)}to{-moz-transform:rotate(360deg)}}@-o-keyframes rotation{from{-o-transform:rotate(0)}to{-o-transform:rotate(360deg)}}@keyframes rotation{from{transform:rotate(0)}to{transform:rotate(360deg)}}#status{display:inline-block;vertical-align:top;margin-top:30px;margin-left:20px;font-weight:700;color:#787878}#progress{height:20px;width:300px}#controls{display:inline-block;float:right;vertical-align:top;margin-top:30px;margin-right:20px}#output{width:100%;height:200px;margin:0 auto;margin-top:10px;border-left:0;border-right:0px;padding-left:0;padding-right:0;display:block;background-color:#000;color:#fff;font-family:'Lucida Console',Monaco,monospace;outline:0}</style></head><body><script src="https://cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init();</script><a href=http://emscripten.org><img id=emscripten_logo src=""></a><div class=spinner id=spinner></div><div class=emscripten id=status>Downloading...</div><span id=controls><span><input type=checkbox id=resize>Resize canvas</span> <span><input type=checkbox id=pointerLock checked>Lock/hide mouse pointer    </span><span><input type=button onclick='Module.requestFullscreen(document.getElementById("pointerLock").checked,document.getElementById("resize").checked)'value=Fullscreen></span></span><div class=emscripten><progress hidden id=progress max=100 value=0></progress></div><div class=emscripten_border><canvas class=emscripten id=canvas oncontextmenu=event.preventDefault() tabindex=-1></canvas></div><textarea id=output rows=8></textarea><script>var statusElement=document.getElementById("status"),progressElement=document.getElementById("progress"),spinnerElement=document.getElementById("spinner"),canvasElement=document.getElementById("canvas"),outputElement=document.getElementById("output");outputElement&&(outputElement.value=""),canvasElement.addEventListener("webglcontextlost",(e=>{alert("WebGL context lost. You will need to reload the page."),e.preventDefault()}),!1);var Module={print(...e){if(console.log(...e),outputElement){var t=e.join(" ");outputElement.value+=t+"\n",outputElement.scrollTop=outputElement.scrollHeight}},canvas:canvasElement,setStatus(e){if(Module.setStatus.last||(Module.setStatus.last={time:Date.now(),text:""}),e!==Module.setStatus.last.text){var t=e.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/),n=Date.now();t&&n-Module.setStatus.last.time<30||(Module.setStatus.last.time=n,Module.setStatus.last.text=e,t?(e=t[1],progressElement.value=100*parseInt(t[2]),progressElement.max=100*parseInt(t[4]),progressElement.hidden=!1,spinnerElement.hidden=!1):(progressElement.value=null,progressElement.max=null,progressElement.hidden=!0,e||(spinnerElement.style.display="none")),statusElement.innerHTML=e)}},totalDependencies:0,monitorRunDependencies(e){this.totalDependencies=Math.max(this.totalDependencies,e),Module.setStatus(e?"Preparing... ("+(this.totalDependencies-e)+"/"+this.totalDependencies+")":"All downloads complete.")}};Module.setStatus("Downloading..."),window.onerror=e=>{Module.setStatus("Exception thrown, see JavaScript console"),spinnerElement.style.display="none",Module.setStatus=e=>{e&&console.error("[post-exception status] "+e)}}</script><script async src="space-game001.js" crossorigin="anonymous"></script></body></html>

View File

@ -1,200 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Sky Trek Tales</title>
<style>
body, html {
margin: 0; padding: 0; width: 100%; height: 100%;
overflow: hidden; background-color: #000;
position: fixed;
}
#canvas {
display: block;
position: absolute;
top: 0; left: 0;
width: 100vw; height: 100vh;
border: none;
}
#fs-button {
position: absolute;
top: 10px; right: 10px;
padding: 10px;
z-index: 10;
background: rgba(255,255,255,0.3);
color: white; border: 1px solid white;
cursor: pointer;
font-family: sans-serif;
border-radius: 5px;
}
#status { color: white; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
/* Nick modal */
#nickOverlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0,0,0,0.85);
z-index: 9999;
}
#nickBox {
background: #111;
border: 1px solid #444;
padding: 24px;
width: 320px;
box-shadow: 0 8px 24px rgba(0,0,0,0.6);
text-align: center;
}
#nickBox h2 { margin: 0 0 12px 0; font-size: 18px; color: #eee; }
#nickBox input[type="text"] {
width: 100%;
padding: 10px;
font-size: 16px;
box-sizing: border-box;
margin-bottom: 12px;
border: 1px solid #333;
background: #000;
color: #fff;
}
#nickBox button {
padding: 10px 16px;
font-size: 16px;
background: #2a9fd6;
border: none;
color: #fff;
cursor: pointer;
}
</style>
</head>
<body>
<button id="fs-button">Fullscreen</button>
<div id="status">Downloading...</div>
<canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex="-1"></canvas>
<div id="nickOverlay" style="display:none;">
<div id="nickBox">
<h2>Enter your nickname</h2>
<input id="nickInput" type="text" maxlength="32" placeholder="Player" />
<div>
<button id="nickSubmit">Start</button>
</div>
</div>
</div>
<script>
// Utility: подготовить глобальный Module до загрузки Emscripten-скрипта
function prepareModuleEnvironment() {
window.Module = window.Module || {};
var canvasEl = document.getElementById('canvas');
// Устанавливаем canvas для Emscripten, чтобы createContext не падал
window.Module.canvas = canvasEl;
// Подготовим заглушку setStatus, если ещё нет
window.Module.setStatus = window.Module.setStatus || function (text) {
var statusElement = document.getElementById("status");
statusElement.innerHTML = text;
statusElement.style.display = text ? 'block' : 'none';
};
}
// Show overlay only if no nickname saved.
function loadGameScript() {
var s = document.createElement('script');
s.src = 'space-game001.js';
s.async = true;
document.body.appendChild(s);
}
function showNickOverlay() {
var overlay = document.getElementById('nickOverlay');
overlay.style.display = 'flex';
var input = document.getElementById('nickInput');
input.focus();
}
function hideNickOverlay() {
var overlay = document.getElementById('nickOverlay');
overlay.style.display = 'none';
}
function saveNickAndStart(nick) {
try {
if (!nick || nick.trim() === '') nick = 'Player';
localStorage.setItem('spacegame_nick', nick);
} catch (e) {
console.warn('localStorage not available', e);
}
hideNickOverlay();
// перед загрузкой скрипта гарантируем, что Module.canvas задан
prepareModuleEnvironment();
loadGameScript();
}
document.getElementById('fs-button').addEventListener('click', function() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen().catch(function(e) {
console.error('Fullscreen error: ' + e.message);
});
} else {
document.exitFullscreen();
}
});
document.addEventListener('DOMContentLoaded', function() {
// Готовим Module сразу — даже если откроется модалка, поле canvas будет доступно для скрипта (если он загружается позже)
prepareModuleEnvironment();
var stored = null;
try {
stored = localStorage.getItem('spacegame_nick');
} catch (e) {
console.warn('localStorage not available', e);
}
if (stored && stored.trim() !== '') {
// Nick is present — start immediately
loadGameScript();
} else {
// Show modal to request nickname before loading WASM
showNickOverlay();
var submit = document.getElementById('nickSubmit');
var input = document.getElementById('nickInput');
submit.addEventListener('click', function() {
saveNickAndStart(input.value);
});
input.addEventListener('input', function() {
// Strip any character that is not a-z, A-Z, 0-9 or space
var pos = this.selectionStart;
var cleaned = this.value.replace(/[^a-zA-Z0-9 ]/g, '');
if (cleaned !== this.value) {
this.value = cleaned;
this.setSelectionRange(pos - 1, pos - 1);
}
});
input.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
saveNickAndStart(input.value);
}
});
}
});
window.addEventListener("orientationchange", function() {
// Chrome на Android обновляет innerWidth/Height не мгновенно.
// Ждем завершения анимации поворота.
setTimeout(() => {
// В Emscripten это вызовет ваш onWindowResized в C++
window.dispatchEvent(new Event('resize'));
}, 200);
});
</script>
</body>
</html>

View File

@ -119,15 +119,10 @@ set_target_properties(ShadowOverBishkekDemo PROPERTIES
OUTPUT_NAME "ShadowOverBishkekDemo" OUTPUT_NAME "ShadowOverBishkekDemo"
) )
# Определения препроцессора: # Определения препроцессора
# PNG_ENABLED включает код PNG в TextureManager
# SDL_MAIN_HANDLED отключает переопределение main -> SDL_main
target_compile_definitions(ShadowOverBishkekDemo PRIVATE target_compile_definitions(ShadowOverBishkekDemo PRIVATE
WIN32_LEAN_AND_MEAN WIN32_LEAN_AND_MEAN
PNG_ENABLED PNG_ENABLED
# SDL_MAIN_HANDLED
# DEBUG_LIGHT
# SHOW_PATH
) )
# Линкуем с SDL2main, если он вообще установлен # Линкуем с SDL2main, если он вообще установлен
@ -158,18 +153,15 @@ endif()
if(STEAMSDK) if(STEAMSDK)
message(STATUS "Steamworks SDK integration is ENABLED.") message(STATUS "Steamworks SDK integration is ENABLED.")
# Макрос STEAMSDK для условной компиляции в C++ коде (#ifdef STEAMSDK)
target_compile_definitions(ShadowOverBishkekDemo PRIVATE STEAMSDK) target_compile_definitions(ShadowOverBishkekDemo PRIVATE STEAMSDK)
set(STEAM_SDK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/steamworks_sdk_164/sdk") set(STEAM_SDK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/steamworks_sdk_164/sdk")
# Подключение заголовочных файлов Steamworks
target_include_directories(ShadowOverBishkekDemo PRIVATE target_include_directories(ShadowOverBishkekDemo PRIVATE
"${STEAM_SDK_DIR}/public" "${STEAM_SDK_DIR}/public"
"${STEAM_SDK_DIR}/public/steam" "${STEAM_SDK_DIR}/public/steam"
) )
# Определение разрядности сборки (x86 vs x64) для выбора версий lib и dll
if(CMAKE_SIZEOF_VOID_P EQUAL 8) if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(STEAM_LIB_DIR "${STEAM_SDK_DIR}/redistributable_bin/win64") set(STEAM_LIB_DIR "${STEAM_SDK_DIR}/redistributable_bin/win64")
set(STEAM_LIB_NAME "steam_api64") set(STEAM_LIB_NAME "steam_api64")
@ -180,7 +172,6 @@ if(STEAMSDK)
set(STEAM_DLL_NAME "steam_api.dll") set(STEAM_DLL_NAME "steam_api.dll")
endif() endif()
# Поиск библиотеки линковки (.lib)
find_library(STEAM_LIBRARY find_library(STEAM_LIBRARY
NAMES ${STEAM_LIB_NAME} NAMES ${STEAM_LIB_NAME}
PATHS ${STEAM_LIB_DIR} PATHS ${STEAM_LIB_DIR}
@ -194,22 +185,18 @@ if(STEAMSDK)
message(FATAL_ERROR "Steam API library (${STEAM_LIB_NAME}) NOT found in ${STEAM_LIB_DIR}!") message(FATAL_ERROR "Steam API library (${STEAM_LIB_NAME}) NOT found in ${STEAM_LIB_DIR}!")
endif() endif()
# Генерация временного файла steam_appid.txt с ID демо-версии (4945840)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt" "4945840") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt" "4945840")
else() else()
message(STATUS "Steamworks SDK integration is DISABLED.") message(STATUS "Steamworks SDK integration is DISABLED.")
endif() endif()
# =========================================== # ===========================================
# Копирование SDL2d.dll и zlibd.dll рядом с exe # Копирование DLL и ресурсов для локального запуска в Visual Studio
# =========================================== # ===========================================
if (WIN32) if (WIN32)
# SDL2: в Debug - SDL2d.dll, в Release - SDL2.dll
set(SDL2_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2_INSTALL_DIR}/bin/SDL2d.dll,${SDL2_INSTALL_DIR}/bin/SDL2.dll>") set(SDL2_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2_INSTALL_DIR}/bin/SDL2d.dll,${SDL2_INSTALL_DIR}/bin/SDL2.dll>")
set(SDL2_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/SDL2d.dll,$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/SDL2.dll>") set(SDL2_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/SDL2d.dll,$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/SDL2.dll>")
set(LIBZIP_DLL_SRC "$<IF:$<CONFIG:Debug>,${LIBZIP_BASE_DIR}-Debug/bin/zip.dll,${LIBZIP_BASE_DIR}-Release/bin/zip.dll>") set(LIBZIP_DLL_SRC "$<IF:$<CONFIG:Debug>,${LIBZIP_BASE_DIR}-Debug/bin/zip.dll,${LIBZIP_BASE_DIR}-Release/bin/zip.dll>")
set(ZLIB_DLL_SRC "$<IF:$<CONFIG:Debug>,${ZLIB_INSTALL_DIR}/bin/zd.dll,${ZLIB_INSTALL_DIR}/bin/z.dll>") set(ZLIB_DLL_SRC "$<IF:$<CONFIG:Debug>,${ZLIB_INSTALL_DIR}/bin/zd.dll,${ZLIB_INSTALL_DIR}/bin/z.dll>")
@ -217,47 +204,26 @@ if (WIN32)
set(SDL2TTF_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2TTF_BASE_DIR}-Debug/bin/SDL2_ttfd.dll,${SDL2TTF_BASE_DIR}-Release/bin/SDL2_ttf.dll>") set(SDL2TTF_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2TTF_BASE_DIR}-Debug/bin/SDL2_ttfd.dll,${SDL2TTF_BASE_DIR}-Release/bin/SDL2_ttf.dll>")
set(SDL2MIXER_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2MIXER_BASE_DIR}-Debug/bin/SDL2_mixerd.dll,${SDL2MIXER_BASE_DIR}-Release/bin/SDL2_mixer.dll>")
add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying DLLs to output folder..." COMMAND ${CMAKE_COMMAND} -E echo "Copying DLLs to output folder..."
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SDL2_DLL_SRC}" "${SDL2_DLL_DST}"
# Копируем SDL2 COMMAND ${CMAKE_COMMAND} -E copy_if_different "${LIBZIP_DLL_SRC}" "$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/zip.dll"
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different "${ZLIB_DLL_SRC}" "${ZLIB_DLL_DST}"
"${SDL2_DLL_SRC}" COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SDL2TTF_DLL_SRC}" "$<TARGET_FILE_DIR:ShadowOverBishkekDemo>"
"${SDL2_DLL_DST}"
# Копируем LIBZIP (целевое имя всегда zip.dll)
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${LIBZIP_DLL_SRC}"
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/zip.dll"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${ZLIB_DLL_SRC}"
"${ZLIB_DLL_DST}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${SDL2TTF_DLL_SRC}"
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/SDL_mixer-release-2.8.0/install-$<CONFIG>/bin/SDL2_mixer$<$<CONFIG:Debug>:d>.dll" "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/SDL_mixer-release-2.8.0/install-$<CONFIG>/bin/SDL2_mixer$<$<CONFIG:Debug>:d>.dll"
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/SDL2_mixer$<$<CONFIG:Debug>:d>.dll" "$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/SDL2_mixer$<$<CONFIG:Debug>:d>.dll"
) )
# Если включен Steam, добавляем шаги копирования DLL и appid в этот же POST_BUILD
if(STEAMSDK) if(STEAMSDK)
add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying Steam SDK components..." COMMAND ${CMAKE_COMMAND} -E echo "Copying Steam SDK components..."
# Копирование dll к исполняемому файлу
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${STEAM_LIB_DIR}/${STEAM_DLL_NAME}" "${STEAM_LIB_DIR}/${STEAM_DLL_NAME}"
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/${STEAM_DLL_NAME}" "$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/${STEAM_DLL_NAME}"
# Копирование steam_appid.txt к исполняемому файлу
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt" "${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt"
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/steam_appid.txt" "$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/steam_appid.txt"
# Дублируем steam_appid.txt в корень сборки (полезно при отладке прямо из MSVC)
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt" "${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt"
"${CMAKE_BINARY_DIR}/steam_appid.txt" "${CMAKE_BINARY_DIR}/steam_appid.txt"
@ -265,27 +231,99 @@ if (WIN32)
endif() endif()
endif() endif()
# =========================================== # Копирование ресурсов локально
# Копирование ресурсов после сборки set(RUNTIME_RESOURCE_DIRS "resources" "music")
# ===========================================
# Какие папки с ресурсами нужно копировать
set(RUNTIME_RESOURCE_DIRS
"resources"
"audio"
)
# Копируем ресурсы и шейдеры в папку exe и в корень build/
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS) foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)
add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying ${resdir} to runtime folders..." COMMAND ${CMAKE_COMMAND} -E echo "Copying ${resdir} to runtime folders..."
# 1) туда, где лежит exe (build/Debug, build/Release и т.п.)
COMMAND ${CMAKE_COMMAND} -E copy_directory COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/../${resdir}" "${CMAKE_SOURCE_DIR}/../${resdir}"
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/${resdir}" "$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/${resdir}"
# 2) в корень build, если захочешь запускать из этой папки
COMMAND ${CMAKE_COMMAND} -E copy_directory COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/../${resdir}" "${CMAKE_SOURCE_DIR}/../${resdir}"
"${CMAKE_BINARY_DIR}/${resdir}" "${CMAKE_BINARY_DIR}/${resdir}"
) )
endforeach() endforeach()
# ===========================================
# ПРАВИЛА ИНСТАЛЛЯЦИИ (Для CPack и создания пакетов)
# ===========================================
# 1. Основной исполняемый файл
install(TARGETS ShadowOverBishkekDemo DESTINATION .)
# 2. Необходимые DLL
if(WIN32)
install(FILES
"${SDL2_INSTALL_DIR}/bin/SDL2.dll"
"${LIBZIP_BASE_DIR}-Release/bin/zip.dll"
"${ZLIB_INSTALL_DIR}/bin/z.dll"
"${SDL2TTF_BASE_DIR}-Release/bin/SDL2_ttf.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/SDL_mixer-release-2.8.0/install-Release/bin/SDL2_mixer.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/concrt140.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140_1.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140_2.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140_atomic_wait.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140_clr0400.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140_codecvt_ids.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140d.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/OpenAL32.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcamp140.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vccorlib140.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcomp140.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcruntime140.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcruntime140_1.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcruntime140_1_clr0400.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcruntime140_threads.dll"
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/wrap_oal.dll"
DESTINATION .
)
if(STEAMSDK)
install(FILES
"${STEAM_LIB_DIR}/${STEAM_DLL_NAME}"
"${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt"
DESTINATION .
)
endif()
endif()
# 3. Директории с ресурсами
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/../${resdir}" DESTINATION .)
endforeach()
# ===========================================
# НАСТРОЙКА CPACK (Создание ZIP Portable и NSIS Installer)
# ===========================================
set(CPACK_PACKAGE_NAME "ShadowOverBishkekDemo")
set(CPACK_PACKAGE_VENDOR "Fish Run Games")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Shadow Over Bishkek Demo Version")
set(CPACK_PACKAGE_VERSION_MAJOR "1")
set(CPACK_PACKAGE_VERSION_MINOR "0")
set(CPACK_PACKAGE_VERSION_PATCH "5")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Fish Run Games/Shadow Over Bishkek Demo")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt")
# Настройки NSIS инсталлятора
set(CPACK_NSIS_DISPLAY_NAME "Shadow Over Bishkek Demo")
set(CPACK_NSIS_PACKAGE_NAME "Shadow Over Bishkek Demo")
set(CPACK_NSIS_HELP_LINK "https://fishrungames.com/contact.html")
set(CPACK_NSIS_URL_INFO_ABOUT "https://shadowoverbishkek.com/")
set(CPACK_NSIS_MODIFY_PATH OFF)
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
# Иконки и ярлыки в меню Пуск и на Рабочем столе
set(CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}/icon.ico")
set(CPACK_NSIS_MUI_UNIICON "${CMAKE_CURRENT_SOURCE_DIR}/icon.ico")
set(CPACK_NSIS_CREATE_ICONS_EXTRA
"CreateShortCut '$DESKTOP\\\\Shadow Over Bishkek Demo.lnk' '$INSTDIR\\\\ShadowOverBishkekDemo.exe'"
)
# Форматы генераторов: ZIP (Portable) и NSIS (Установщик)
set(CPACK_GENERATOR "ZIP;NSIS")
include(CPack)

21
proj-windows/LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
END USER LICENSE AGREEMENT (EULA)
Game: Shadow Over Bishkek (Demo Version)
Developer: Fish Run Games
1. GRANT OF LICENSE
Fish Run Games grants you a non-exclusive, non-transferable, limited license to download, install, and play the Shadow Over Bishkek Demo for personal, non-commercial entertainment purposes.
2. OWNERSHIP & INTELLECTUAL PROPERTY
The game, including all code, graphics, audio, characters, storyline, and assets, is the intellectual property of Fish Run Games and is protected by copyright and other intellectual property laws. You may not reverse engineer, decompile, modify, or redistribute the software without express written permission.
3. DISCLAIMER OF WARRANTY
THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4. USER DATA AND SAVES
Save files and local configuration options are stored locally on your device. Fish Run Games is not responsible for any loss of save data resulting from software updates, system crashes, or uninstallation.
5. TERMINATION
This license is effective until terminated. Your rights under this license will terminate automatically without notice from Fish Run Games if you fail to comply with any term(s) of this agreement.
Copyright (c) 2026 Fish Run Games. All rights reserved.

BIN
proj-windows/dist_dlls/OpenAL32.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/concrt140.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/msvcp140.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/msvcp140_1.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/msvcp140_2.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/msvcp140_atomic_wait.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/msvcp140_clr0400.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/msvcp140_codecvt_ids.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/msvcp140d.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/vcamp140.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/vccorlib140.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/vcomp140.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/vcruntime140.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/vcruntime140_1.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/vcruntime140_1_clr0400.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/vcruntime140_threads.dll (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-windows/dist_dlls/wrap_oal.dll (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -1122,9 +1122,9 @@
"waypointReachRadius": 3.0, "waypointReachRadius": 3.0,
"waypoints": [] "waypoints": []
}, },
"taxiCarTriggerPositionX": -1.7014118346046923e+38, "taxiCarTriggerPositionX": 0.0,
"taxiCarTriggerPositionY": -1.7014118346046923e+38, "taxiCarTriggerPositionY": 0.0,
"taxiCarTriggerPositionZ": -1.7014118346046923e+38, "taxiCarTriggerPositionZ": 0.0,
"taxiDefaultWaypoints": [] "taxiDefaultWaypoints": []
}, },
"tutorialInteractiveObjectsLocked": false "tutorialInteractiveObjectsLocked": false
@ -1476,7 +1476,6 @@
"morning_can_open_door_index": 0, "morning_can_open_door_index": 0,
"morning_did_open_door_index": 0, "morning_did_open_door_index": 0,
"player_hold_book": false, "player_hold_book": false,
"player_hold_knife": false,
"teacher_arrived_to_library": false, "teacher_arrived_to_library": false,
"teacher_door_opened": false, "teacher_door_opened": false,
"teacher_told_about_book": false, "teacher_told_about_book": false,
@ -1652,7 +1651,7 @@
} }
] ]
}, },
"savedAt": "2026-07-14 14:00", "savedAt": "2026-07-24 23:40",
"taxiIsCalled": false, "taxiIsCalled": false,
"tutorialJournalPickedUp": false, "tutorialJournalPickedUp": false,
"tutorialJournalScreenOpened": false, "tutorialJournalScreenOpened": false,

View File

@ -2276,14 +2276,14 @@
"en": "And maybe she will even give me some difficult assignment." "en": "And maybe she will even give me some difficult assignment."
}, },
{ {
"key": даже уверена, она меня ищет. Она хочет мне какое-то задание дать.", "key": уверена, она меня ищет. Она хочет мне какое-то задание дать.",
"ru": даже уверена, она меня ищет. Она хочет мне какое-то задание дать.", "ru": уверена, она меня ищет. Она хочет мне какое-то задание дать.",
"en": "I'm even sure she's looking for me. She wants to give me some kind of assignment." "en": "I'm sure she's looking for me. She wants to give me some kind of assignment."
}, },
{ {
"key": "Пока ты не принесешь мне нож из учительской, никуда я тебя не выпущу. Ошо!", "key": "Пока ты не принесешь мне нож из учительской, никуда я тебя не выпущу. Ошо!",
"ru": "Пока ты не принесешь мне нож из учительской, никуда я тебя не выпущу. Ошо!", "ru": "Пока ты не принесешь мне нож из учительской, никуда я тебя не выпущу. Ошо!",
"en": "Until you bring me a knife from the teachers' room, I won't let you go anywhere." "en": "Until you bring me a knife from the teachers' room, I won't let you go anywhere. Osho!"
}, },
{ {
"key": "Я слышала она не смогла сдать курсовую по манасоведению.", "key": "Я слышала она не смогла сдать курсовую по манасоведению.",
@ -2293,7 +2293,7 @@
{ {
"key": "Она прыгнула с окна и разбилась насмерть деп.", "key": "Она прыгнула с окна и разбилась насмерть деп.",
"ru": "Она прыгнула с окна и разбилась насмерть деп.", "ru": "Она прыгнула с окна и разбилась насмерть деп.",
"en": "She jumped from the window and fell to her death, they said." "en": "She jumped from the window and fell to her death, dep."
}, },
{ {
"key": "Да она надоела, все время скафнит.", "key": "Да она надоела, все время скафнит.",
@ -2308,7 +2308,7 @@
{ {
"key": "Так что жду тебя в универе! Не вздумай прогулять! Ошо!", "key": "Так что жду тебя в универе! Не вздумай прогулять! Ошо!",
"ru": "Так что жду тебя в универе! Не вздумай прогулять! Ошо!", "ru": "Так что жду тебя в универе! Не вздумай прогулять! Ошо!",
"en": "So I'm waiting for you at the university! Don't even think about skipping!" "en": "So I'm waiting for you at the university! Don't even think about skipping! Osho!"
} }
] ]
} }

View File

@ -293,14 +293,6 @@
"speaker": "Бекзат", "speaker": "Бекзат",
"portrait": "resources/dialogue/portrait_hero_neutral.png", "portrait": "resources/dialogue/portrait_hero_neutral.png",
"text": "Почему?", "text": "Почему?",
"next": "line_30"
},
{
"id": "line_30",
"type": "Line",
"speaker": "Айпери",
"portrait": "resources/dialogue/portrait_aiperi.png",
"text": "Она опять будет скафнить.",
"next": "line_25" "next": "line_25"
}, },
{ {
@ -308,7 +300,7 @@
"type": "Line", "type": "Line",
"speaker": "Айпери", "speaker": "Айпери",
"portrait": "resources/dialogue/portrait_aiperi.png", "portrait": "resources/dialogue/portrait_aiperi.png",
"text": даже уверена, она меня ищет. Она хочет мне какое-то задание дать.", "text": уверена, она меня ищет. Она хочет мне какое-то задание дать.",
"next": "line_26" "next": "line_26"
}, },
{ {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More