12 Commits

Author SHA1 Message Date
f03b8537c5 Release build squashed
Some checks failed
/ release (Debug, map[deps:macos-universal flag:arm64 name:macos scons-script:./.github/workflows/scripts/mac/scons-build.sh suffix:-silicon version:14]) (push) Has been cancelled
/ release (Debug, map[deps:macos-universal flag:x86_64 name:macos scons-script:./.github/workflows/scripts/mac/scons-build.sh suffix:-intel version:13]) (push) Has been cancelled
/ release (Debug, map[name:windows scons-script:./.github/workflows/scripts/win/scons-build.bat suffix: version:2019]) (push) Has been cancelled
/ release (Release, map[deps:macos-universal flag:arm64 name:macos scons-script:./.github/workflows/scripts/mac/scons-build.sh suffix:-silicon version:14]) (push) Has been cancelled
/ release (Release, map[deps:macos-universal flag:x86_64 name:macos scons-script:./.github/workflows/scripts/mac/scons-build.sh suffix:-intel version:13]) (push) Has been cancelled
/ release (Release, map[name:windows scons-script:./.github/workflows/scripts/win/scons-build.bat suffix: version:2019]) (push) Has been cancelled
2025-05-25 15:30:45 -05:00
abb19bbe15 find .EXS scenarios. fix #748 2025-05-25 15:30:35 -05:00
3aa35cf151 default values for editor_state_t (might fix #744) 2025-05-25 11:52:59 -05:00
dddae03915 Add button to open scenario folder & refresh list 2025-05-24 16:32:06 -05:00
dee6d988a6 Fix out-of-range access check for legacy town entrance
Fix #745
2025-05-24 15:16:24 -05:00
e7bf5847d0 add conveyor belts flag to game. fix #747 2025-05-24 14:30:34 -05:00
e846540ebd remove out-of-range node in VoDT outdoors (fix #741) 2025-05-23 14:28:41 -05:00
4ed73bf72d Update src/dialogxml/dialogs/dialog.cpp
Co-authored-by: Celtic Minstrel <CelticMinstrel@users.noreply.github.com>
2025-05-23 14:02:50 -05:00
1084f26a88 Count preferences dialog when detecting max UI scale to fit (Fix #740) 2025-05-23 09:11:27 -05:00
b7c1089508 Fix save file dialog with first party. (#740) 2025-05-23 08:55:14 -05:00
1734e7b055 Fix Load screen with no parties in save folder (#740) 2025-05-23 08:48:31 -05:00
42cffb6704 fix itch build when itch client apps folder doesn't exist 2025-05-21 15:21:58 -05:00
20 changed files with 509 additions and 46 deletions

73
.github/workflows/mac-universal.yml vendored Normal file
View File

@@ -0,0 +1,73 @@
name: Mac universal build
on:
push:
branches:
- universal
release:
types: [published]
jobs:
build:
runs-on: macos-14
env:
CONFIGURATION: ${{ matrix.configuration }}
BUTLER_API_KEY: ${{ secrets.BUTLER_API_KEY }}
PROD_MACOS_CERTIFICATE: '${{ secrets.PROD_MACOS_CERTIFICATE }}'
PROD_MACOS_CERTIFICATE_PWD: '${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}'
PROD_MACOS_CERTIFICATE_NAME: '${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}'
PROD_MACOS_CI_KEYCHAIN_PWD: '${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}'
PROD_MACOS_NOTARIZATION_APPLE_ID: '${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}'
PROD_MACOS_NOTARIZATION_TEAM_ID: '${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}'
PROD_MACOS_NOTARIZATION_PWD: '${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}'
BUILD_OS: macos
strategy:
fail-fast: false
matrix:
configuration:
- Release
- Debug
steps:
- uses: actions/checkout@v4
# Download macos-intel
- uses: robinraju/release-downloader@v1
id: download
with:
latest: true
fileName: 'cboe-macos-intel-${{ matrix.configuration }}.tar'
extract: true
out-file-path: 'cboe-macos-intel-${{ matrix.configuration }}'
# Download macos-silicon
- uses: robinraju/release-downloader@v1
with:
latest: true
fileName: 'cboe-macos-silicon-${{ matrix.configuration }}.tar'
extract: true
out-file-path: 'cboe-macos-silicon-${{ matrix.configuration }}'
- run: .github/workflows/scripts/mac/make-universal.sh
# Skipping this for now because of issue nqnstudios#13
- name: Codesign and notarize
run: 'SIGN="no" NOTARIZE="no" .github/workflows/scripts/mac/sign-apps.sh'
- name: 'Tar files'
run: 'tar -cvf cboe-macos-universal-${{matrix.configuration}}.tar "build/Blades of Exile"'
# Upload everything as artifact
- uses: actions/upload-artifact@v4
with:
name: mac-universal-dependencies-${{matrix.configuration}}
path: cboe-macos-universal-${{matrix.configuration}}.tar
# upload a release
- name: Github release
uses: softprops/action-gh-release@v2
with:
files: cboe-macos-universal-${{ matrix.configuration }}.tar
tag_name: ${{ steps.download.outputs.tag_name }}
- name: 'Itch.io release'
run: './.github/workflows/scripts/butler_push.sh'
shell: bash
if: ${{ matrix.configuration == 'Release' }}

131
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,131 @@
on:
push:
branches:
- 'itch-edition'
tags:
- "v*.*.*"
pull_request:
branches:
- itch-edition
jobs:
release:
env:
ARCH: ${{ matrix.os.flag }}
MACOSX_DEPLOYMENT_TARGET: 10.15
BUTLER_API_KEY: ${{ secrets.BUTLER_API_KEY }}
PROD_MACOS_CERTIFICATE: '${{ secrets.PROD_MACOS_CERTIFICATE }}'
PROD_MACOS_CERTIFICATE_PWD: '${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}'
PROD_MACOS_CERTIFICATE_NAME: '${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}'
PROD_MACOS_CI_KEYCHAIN_PWD: '${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}'
PROD_MACOS_NOTARIZATION_APPLE_ID: '${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}'
PROD_MACOS_NOTARIZATION_TEAM_ID: '${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}'
PROD_MACOS_NOTARIZATION_PWD: '${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}'
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
DEBUG_FLAG: ${{ matrix.configuration == 'Debug' && 'true' || 'false' }}
BUILD_OS: ${{ matrix.os.name }}
strategy:
fail-fast: false
matrix:
os:
- name: macos
suffix: '-intel'
flag: x86_64
deps: macos-universal
version: 13
scons-script: './.github/workflows/scripts/mac/scons-build.sh'
- name: macos
flag: arm64
suffix: '-silicon'
deps: macos-universal
version: 14
scons-script: './.github/workflows/scripts/mac/scons-build.sh'
# - name: ubuntu
# suffix: ''
# version: 22.04
# scons-script: scons
- name: windows
suffix: ''
version: 2019
scons-script: './.github/workflows/scripts/win/scons-build.bat'
configuration:
- Release
- Debug
runs-on: '${{ matrix.os.name }}-${{ matrix.os.version }}'
steps:
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@v7
with:
script: "core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');"
- name: checkout
uses: actions/checkout@v4
with:
submodules: true
- name: Download dependency build
uses: robinraju/release-downloader@v1
with:
repository: NQNStudios/cboe-dependencies
latest: true
fileName: 'dependencies-${{ matrix.os.deps || matrix.os.name }}-${{ matrix.configuration }}.tar'
extract: true
out-file-path: 'deps'
- name: Windows build dependencies
run: 'vcpkg install libxml2 && pip install scons'
if: ${{ matrix.os.name == 'windows' }}
- name: Mac build dependencies
run: brew install scons
if: ${{ matrix.os.name == 'macos' }}
- name: Linux build dependencies
run: sudo apt-get update && sudo apt-get install scons libxml2-utils libgl-dev libopenal-dev
if: ${{ matrix.os.name == 'ubuntu' }}
- name: Install TGUI
run: 'sudo ./.github/workflows/scripts/linux/install-tgui.sh'
if: ${{ matrix.os.name == 'ubuntu' }}
- name: Build
run: '${{ matrix.os.scons-script }} test=false debug=$DEBUG_FLAG'
shell: bash
- name: Download fix-rpaths.py script
run: git clone https://gist.github.com/NQNStudios/7145bcf6621891f5176c8caa165d6b93
if: ${{ matrix.os.name == 'macos' }}
- name: Fix rpaths game
run: 'python 7145bcf6621891f5176c8caa165d6b93/fix-rpaths.py "build/Blades of Exile/Blades of Exile.app"'
if: ${{ matrix.os.name == 'macos' }}
- name: Fix rpaths scenario editor
run: 'python 7145bcf6621891f5176c8caa165d6b93/fix-rpaths.py "build/Blades of Exile/BoE Scenario Editor.app"'
if: ${{ matrix.os.name == 'macos' }}
- name: Fix rpaths character editor
run: 'python 7145bcf6621891f5176c8caa165d6b93/fix-rpaths.py "build/Blades of Exile/BoE Character Editor.app"'
if: ${{ matrix.os.name == 'macos' }}
- run: cp .itch.toml "build/Blades of Exile/"
shell: bash
- name: 'Tar unsigned files'
run: 'tar -cvf cboe-${{ matrix.os.name }}${{ matrix.os.suffix }}-${{ matrix.configuration }}-unsigned.tar "Blades of Exile"'
working-directory: '${{ github.workspace }}/build'
- name: upload pre-signing artifact
uses: actions/upload-artifact@v4
with:
name: cboe-${{ matrix.os.name }}${{ matrix.os.suffix }}-${{ matrix.configuration }}-unsigned
path: '${{ github.workspace }}/build/cboe-${{ matrix.os.name }}${{ matrix.os.suffix }}-${{ matrix.configuration }}-unsigned.tar'
# Skipping this for now because of issue nqnstudios#13
- name: Codesign and notarize
run: 'SIGN="no" NOTARIZE="no" ./.github/workflows/scripts/mac/sign-apps.sh'
if: ${{ matrix.os.name == 'macos' }}
- name: 'Tar files'
run: 'tar -cvf cboe-${{ matrix.os.name }}${{ matrix.os.suffix }}-${{ matrix.configuration }}.tar "Blades of Exile"'
working-directory: '${{ github.workspace }}/build'
- name: 'Upload Artifact'
uses: actions/upload-artifact@v4
with:
name: cboe-${{ matrix.os.name }}${{ matrix.os.suffix }}-${{ matrix.configuration }}
path: '${{ github.workspace }}/build/cboe-${{ matrix.os.name }}${{ matrix.os.suffix }}-${{ matrix.configuration }}.tar'
- name: Github release
uses: softprops/action-gh-release@v2
with:
files: '${{ github.workspace }}/build/cboe-${{ matrix.os.name }}${{ matrix.os.suffix }}-${{ matrix.configuration }}.tar'
if: ${{ startsWith(github.ref, 'refs/tags/') }}
- name: 'Itch.io release'
run: './.github/workflows/scripts/butler_push.sh'
shell: bash
if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.configuration == 'Release' && matrix.os.name != 'macos' }}

28
.github/workflows/scripts/butler_push.sh vendored Executable file
View File

@@ -0,0 +1,28 @@
#! /bin/bash
butler_channel=""
butler_exe=""
release_dir=""
if [ "$BUILD_OS" = "ubuntu" ]; then
butler_channel=linux-amd64
butler_exe=butler
release_dir="linux"
elif [ "$BUILD_OS" = "windows" ]; then
butler_channel=windows-amd64
butler_exe=butler.exe
release_dir="windows"
elif [ "$BUILD_OS" = "macos" ]; then
butler_channel=darwin-amd64
butler_exe=butler
release_dir="macos"
fi
# -L follows redirects
# -O specifies output name
curl -L -o butler.zip https://broth.itch.ovh/butler/${butler_channel}/LATEST/archive/default
unzip butler.zip
# GNU unzip tends to not set the executable bit even though it's set in the .zip
chmod +x ${butler_exe}
# just a sanity check run (and also helpful in case you're sharing CI logs)
./${butler_exe} -V
./${butler_exe} push "build/Blades of Exile/" nqn/blades-of-exile:${release_dir}

View File

@@ -3,7 +3,7 @@
git clone --depth 1 -b 0.9 https://github.com/texus/TGUI.git
cd TGUI
export CLICOLOR_FORCE=1
cmake -D TGUI_CXX_STANDARD=14 .
SFML_DIR=../deps/lib/cmake/SFML cmake -D TGUI_CXX_STANDARD=14 -D SFML_DIR=../deps/lib/cmake/SFML .
make
cmake --install .
cd .. # Probably not needed but...

View File

@@ -0,0 +1,27 @@
#! /bin/bash
if [ -z "$CONFIGURATION" ]; then
CONFIGURATION=Release
fi
INTEL=cboe-macos-intel-$CONFIGURATION
SILICON=cboe-macos-silicon-$CONFIGURATION
combine() {
mkdir -p "build/Blades of Exile/$1.app/Contents/MacOS"
lipo -create "$SILICON/Blades of Exile/$1.app/Contents/MacOS/$1" "$INTEL/Blades of Exile/$1.app/Contents/MacOS/$1" -output "build/Blades of Exile/$1.app/Contents/MacOS/$1"
cp -r "$SILICON/Blades of Exile/$1.app/Contents/Frameworks" "build/Blades of Exile/$1.app/Contents/"
cp -r "$SILICON/Blades of Exile/$1.app/Contents/Resources" "build/Blades of Exile/$1.app/Contents/"
cp "$SILICON/Blades of Exile/$1.app/Contents/Info.plist" "build/Blades of Exile/$1.app/Contents/"
cp "$SILICON/Blades of Exile/$1.app/Contents/PkgInfo" "build/Blades of Exile/$1.app/Contents/"
}
combine "Blades of Exile"
combine "BoE Scenario Editor"
combine "BoE Character Editor"
cp -r "$SILICON/Blades of Exile/Blades of Exile Base" "build/Blades of Exile/"
cp -r "$SILICON/Blades of Exile/Blades of Exile Scenarios" "build/Blades of Exile/"
cp -r "$SILICON/Blades of Exile/data" "build/Blades of Exile/"
cp -r "$SILICON/Blades of Exile/docs" "build/Blades of Exile/"
cp "$SILICON/Blades of Exile/.itch.toml" "build/Blades of Exile/"

View File

@@ -4,4 +4,4 @@ export CC="$(brew --prefix llvm)/bin/clang"
export CXX="$(brew --prefix llvm)/bin/clang++"
export SDKROOT="$(xcrun --show-sdk-path)"
scons CXXFLAGS="-I/usr/local/opt/zlib/include" LINKFLAGS="-L/usr/local/opt/zlib/lib" $@
scons CXXFLAGS="-I/usr/local/opt/zlib/include -arch $ARCH" LINKFLAGS="-L/usr/local/opt/zlib/lib" $@

79
.github/workflows/scripts/mac/sign-apps.sh vendored Executable file
View File

@@ -0,0 +1,79 @@
#! /bin/bash
# CODE-SIGNING STEP
# Original Source: https://federicoterzi.com/blog/automatic-code-signing-and-notarization-for-macos-apps-using-github-actions/
# Modified by NQNStudios
# Turn our base64-encoded certificate back to a regular .p12 file
echo $PROD_MACOS_CERTIFICATE | base64 --decode > certificate.p12
# We need to create a new keychain, otherwise using the certificate will prompt
# with a UI dialog asking for the certificate password, which we can't
# use in a headless CI environment
security create-keychain -p "$PROD_MACOS_CI_KEYCHAIN_PWD" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "$PROD_MACOS_CI_KEYCHAIN_PWD" build.keychain
security import certificate.p12 -k build.keychain -P "$PROD_MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$PROD_MACOS_CI_KEYCHAIN_PWD" build.keychain
sign() {
if [ "$SIGN" = "no" ];
then
return
fi
APP_PATH="build/Blades of Exile/$1.app"
# We finally codesign our app bundle, specifying the Hardened runtime option
/usr/bin/codesign --force -s "$PROD_MACOS_CERTIFICATE_NAME" --options runtime "$APP_PATH"/Contents/Frameworks/*.dylib -v
(cd "$APP_PATH" && frameworks=Contents/Frameworks/*.framework/Versions/A/* && \
for framework in $frameworks; do
if [ -f "$framework" ]; then
/usr/bin/codesign --force -s "$PROD_MACOS_CERTIFICATE_NAME" --options runtime "$framework" -v
fi
done)
/usr/bin/codesign --force -s "$PROD_MACOS_CERTIFICATE_NAME" --options runtime "$APP_PATH"/Contents/Frameworks/*.framework/Versions/A/Resources/Info.plist -v
/usr/bin/codesign --force -s "$PROD_MACOS_CERTIFICATE_NAME" --options runtime "$APP_PATH/Contents/Info.plist" -v
/usr/bin/codesign --force -s "$PROD_MACOS_CERTIFICATE_NAME" --options runtime "$APP_PATH" -v
# NOTARIZATION STEP
if [ "$NOTARIZE" = "no" ];
then
return
fi
# (same source)
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
# We can't notarize an app bundle directly, but we need to compress it as an archive.
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
# notarization service
echo "Creating temp notarization archive"
ditto -c -k --keepParent "$APP_PATH" "notarization.zip"
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
# characteristics. Visit the Notarization docs for more information and strategies on how to optimize it if
# you're curious
echo "Notarize app"
xcrun notarytool submit "notarization.zip" --keychain-profile "notarytool-profile" --wait
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
# validated by macOS even when an internet connection is not available.
echo "Attach staple"
xcrun stapler staple "$APP_PATH" || exit 1
}
sign "Blades of Exile"
sign "BoE Scenario Editor"
sign "BoE Character Editor"

9
.itch.toml Normal file
View File

@@ -0,0 +1,9 @@
[[actions]]
name = "Play"
path = "Blades of Exile.exe"
platform = "windows"
[[actions]]
name = "Play"
path = "Blades of Exile.app"
platform = "osx"

View File

@@ -232,13 +232,15 @@ elif platform == "win32":
vcpkg_other_libs = list(filter(path.exists, vcpkg_other_libs))
vcpkg_other_bins = [path.join(d.get_abspath(), 'bin') for d in vcpkg_other_packages]
vcpkg_other_bins = list(filter(path.exists, vcpkg_other_bins))
include_paths=[path.join(vcpkg_installed, 'include')] + vcpkg_other_includes
project_includes = []
for (root, dirs, files) in os.walk('src'):
project_includes.append(path.join(os.getcwd(), root))
include_paths=project_includes
env.Append(
LINKFLAGS=['/SUBSYSTEM:WINDOWS','/ENTRY:mainCRTStartup',f'/MACHINE:X{arch_short}'],
LINKFLAGS=['/SUBSYSTEM:WINDOWS','/ENTRY:mainCRTStartup',f'/MACHINE:X{arch_short}', '/VERBOSE', '/NODEFAULTLIB:libboost_filesystem-vc142-mt-x64-1_85.lib'],
CXXFLAGS=['/EHsc','/MD','/FIglobal.hpp'],
CPPPATH=include_paths,
LIBPATH=[path.join(vcpkg_installed, 'lib')] + vcpkg_other_libs + vcpkg_other_bins,
LIBPATH=[],
LIBS=Split("""
kernel32
user32
@@ -259,7 +261,10 @@ elif platform == "win32":
def build_app_package(env, source, build_dir, info):
env.Install(build_dir, source)
elif platform == "posix":
env.Append(CXXFLAGS=["-std=c++14","-include","global.hpp"])
env.Append(
CXXFLAGS=["-std=c++14","-include","global.hpp"],
#LINKFLAGS=["-rpath-link", "deps/lib/", "-rpath", "./"]
)
def build_app_package(env, source, build_dir, info):
env.Install(build_dir, source)
@@ -415,6 +420,7 @@ if not env.GetOption('clean'):
if platform == 'posix':
def check_tgui(conf, second_attempt=False):
if conf.CheckLib('libtgui', language='C++'):
bundled_libs.append('tgui')
return conf
else:
if second_attempt:
@@ -496,7 +502,31 @@ Export("data_dir")
SConscript(["rsrc/SConscript", "doc/SConscript"])
# Bundle required frameworks and libraries
def handle_bundled_libs(extension, prefix=''):
target_dirs = ["#build/Blades of Exile", "#build/test"]
for lib in bundled_libs:
for lpath in env['LIBPATH']:
def check_path(src_file):
_dir = os.path.dirname(src_file)
print(f'checking {_dir} for {prefix}{lib}')
try:
print(os.listdir(_dir))
except:
pass
if path.exists(src_file) and src_file != "/usr/lib/x86_64-linux-gnu/libz.so":
for targ in target_dirs:
for so in os.listdir(_dir):
if os.path.basename(src_file) in so:
print(f'found {path.join(_dir, so)}')
env.Install(targ, path.join(_dir, so))
return True
return False
if check_path(path.join(lpath, prefix + lib + extension)):
break
elif check_path(path.join(lpath.replace('lib', 'bin'), prefix + lib + extension)):
break
elif check_path(path.join(lpath, 'x86_64-linux-gnu', prefix + lib + extension)):
break
if platform == "darwin":
app_targets = []
if 'game' in targets:
@@ -535,20 +565,7 @@ elif platform == "win32":
brotlidec
brotlicommon
""")
target_dirs = ["#build/Blades of Exile", "#build/test"]
for lib in bundled_libs:
for lpath in env['LIBPATH']:
src_file = path.join(lpath, lib + ".dll")
if path.exists(src_file):
for targ in target_dirs:
env.Install(targ, src_file)
break
elif 'lib' in lpath:
src_file = path.join(lpath.replace('lib', 'bin'), lib + ".dll")
if path.exists(src_file):
for targ in target_dirs:
env.Install(targ, src_file)
break
handle_bundled_libs(".dll")
# Extra: Microsoft redistributable libraries installer
if 'msvc' in env["TOOLS"]:
if path.exists("deps/VCRedistInstall.exe"):
@@ -556,11 +573,41 @@ elif platform == "win32":
else:
print("WARNING: Cannot find installer for the MSVC redistributable libraries for your version of Visual Studio.")
print("Please download it from Microsoft's website and place it at:")
print(" deps/VCRedistInstall.exe")
print(" deps/VCRedistInstall.exe")
# Create it so its lack doesn't cause makensis to break
# (Because the installer is an optional component.)
os.makedirs("build/Blades of Exile", exist_ok=True)
open("build/Blades of Exile/VCRedistInstall.exe", 'w').close()
elif platform == "posix":
targets = [
"Blades of Exile",
"BoE Character Editor",
"BoE Scenario Editor",
]
def patchelf():
to_patch = targets + [so for so in os.listdir("build/Blades of Exile") if '.so' in so]
for targ in to_patch:
subprocess.call(['patchelf', '--set-rpath', '.', targ], cwd='build/Blades of Exile')
atexit.register(patchelf)
bundled_libs += Split("""
GL
X11
stdc++
Xrandr
Xcursor
udev
openal
vorbisenc
vorbisfile
vorbis
ogg
FLAC
freetype
GLdispatch
GLX
xcb
""")
handle_bundled_libs(".so", "lib")
if env["package"]:
if platform == "darwin":

View File

@@ -46,7 +46,9 @@
<text outline='double' name='start3' top='205' left='59' width='342' height='84'/>
</page>
</stack>
<button name='prev' type='left' def-key='left' top='294' left='62'/>
<button name='next' type='right' def-key='right' top='294' left='125'/>
<button name='cancel' type='regular' top='294' left='337'>Cancel</button>
<button name='cancel' type='regular' top='294' left='5'>Cancel</button>
<button name='prev' type='left' def-key='left' relative='pos pos-in' rel-anchor='prev' top='0' left='14'/>
<button name='next' type='right' def-key='right' relative='pos pos-in' rel-anchor='prev' top='0' left='0'/>
<button name='folder' type='large' relative='pos pos-in' rel-anchor='prev' top='0' left='14'>Show Folder</button>
<button name='refresh' type='regular' relative='pos pos-in' rel-anchor='prev' top='0' left='7'>Refresh</button>
</dialog>

View File

@@ -9,10 +9,17 @@
Spiderweb Software, created in 1997 and later released as
Free Open-Source Software.
</text>
<text name='spidweb' relative='pos-in pos' rel-anchor='prev' top='3' left='16' colour='link' underline='true'>
http://www.spidweb.com/blades/opensource.html
<text relative='pos-in pos' rel-anchor='prev' top='2' left='0' width='413'>
You're playing an Itch Edition release of OpenBoE. The Itch Edition
was funded by many generous supporters through IndieGoGo, and is
currently funded by donations on Patreon. Click below to follow the project
and see the rewards for becoming a supporter!
</text>
<text relative='neg pos' rel-anchor='prev' top='3' left='16' width='413'>
<text name='patreon' relative='pos-in pos' rel-anchor='prev' top='0' left='16' width='230' colour='link' underline='true'>
http://patreon.com/blades_itch_edition
</text>
<pict type='item' num='17' relative='pos neg' rel-anchor='prev' top='15' left='2'/>
<text relative='neg pos' anchor='patreon' top='3' left='16' width='413'>
Three exciting original scenarios await you, filled
with many hours of puzzles, fighting and adventure!
In addition to these, hundreds more written by

View File

@@ -39,7 +39,7 @@
2,111,2,2,2,3,2,58,51,59,61,54,31,32,22,22,22,35,25,49,39,4,3,3,43,42,42,47,36,49,38,38,39,2,87,2,44,30,26,36,36,30,23,23,22,22,22,22
4,2,3,111,3,111,3,2,2,57,50,61,54,30,35,240@5,32,26,49,39,3,2,2,2,44,36,37,37,37,40,2,3,2,3,2,4,44,30,34,27,36,31,32,23,23,22,22,22
4,3,2,3,2,3,111,3,2,58,59,50,53,31,25,36,31,25,40,3,4,2,3,2,45,46,36,36,37,48,41,2,2,2,2,2,44,30,22,26,36,36,30,23,23,22,22,22
2,2,4,111,2,2,111,3,2:22,2,57,50,53,45,38,38,38,38,39,2,3,4,3,2,2,45*1,38,38,46,36,40,3,2,2,2,2,44,31,32,34,27,36,30,23,23,23,22,22
2,2,4,111,2,2,111,3,2,2,57,50,53,45,38,38,38,38,39,2,3,4,3,2,2,45*1,38,38,46,36,40,3,2,2,2,2,44,31,32,34,27,36,30,23,23,23,22,22
2,2,3,2,2,2,2,111,111,2,57,50,53,3,111,2,4,113,2,2,4,2,4,2,87,2,2,3,45,46,48,41,2,2,3,2,45,46,31,32,26,36,30,23,23,23,22,22
111,3,3,2,111,111,2,111,2,2,57,50,53,2&9:1,111,112,4,2,2,2,3,2,3,43,41,2,2,2,87,44,37,40,2,2,2,4,3,45,46,30:17,26:17,36,30,22,23,23,22,22
3,2,110,110:20,110,4,111,111,111,3,57,50,53,3,112,3,3,2,111,112,2,2,2,44,40,2,2,2,2,45,38,39,2,2,2,2,3,2,44,30,34,28,33,22,23,22,22,22

View File

@@ -445,6 +445,12 @@ void cDialog::recalcRect(){
winRect.right *= get_ui_scale();
winRect.bottom *= get_ui_scale();
// Uncomment if you need to measure any dialogs.
/*
LOG_VALUE(fname);
LOG_VALUE(winRect.right);
LOG_VALUE(winRect.bottom);
//*/
}
bool cDialog::initCalled = false;

View File

@@ -68,8 +68,8 @@ static std::string get_file_error() {
// Debug builds run from working directory "build/Blades of Exile"
// should helpfully let you enter replay test scenarios.
// Support for multiple scenario directories will also help with how I plan
// to handle scenario packaging/distribution for my fork's release.
// The Itch Edition finds scenarios in the Itch client's install path,
// so scenarios can be distributed as Itch games.
// - Nat
std::vector<fs::path> all_scen_dirs() {
std::vector<fs::path> scen_dirs = { scenDir };
@@ -86,6 +86,30 @@ std::vector<fs::path> all_scen_dirs() {
}
#endif
// Itch Edition: Search Itch client apps.
// But not recursively, because the player could have tons of games installed
// and that would search ALL of the installed files.
// In fact, try to disqualify folders ASAP by only allowing .boes, .txt,
// and Itch meta files
// (designers might want to ship a README.txt)
fs::path itch_apps_path = scenDir/".."/".."/"itch"/"apps";
if(fs::is_directory(itch_apps_path)){
for(fs::directory_iterator app_iter(itch_apps_path); app_iter != fs::directory_iterator(); app_iter++){
fs::path app = *app_iter;
if(!fs::is_directory(app)) continue;
for(fs::directory_iterator file_iter(app); file_iter != fs::directory_iterator(); file_iter++){
fs::path file = *file_iter;
if(file.extension() == ".boes"){
scen_dirs.push_back(*app_iter);
break;
}else if(file.extension() == ".itch"){
}else if(file.extension() != ".txt"){
break;
}
}
}
}
return scen_dirs;
}
@@ -99,6 +123,9 @@ fs::path locate_scenario(std::string scen_name, bool allow_unpacked) {
fs::path scenPath;
for(fs::path scenDir : all_scen_dirs()){
// Some possible directories, like the Itch client installation folder, might not exist
if(!fs::is_directory(scenDir)) continue;
for(fs::recursive_directory_iterator iter(scenDir); iter != fs::recursive_directory_iterator(); iter++) {
fs::file_status stat = iter->status();
std::string fname = iter->path().filename().string().c_str();

View File

@@ -1810,11 +1810,28 @@ class cChooseScenario {
me.toast(true);
return true;
}
// Show the custom scenario folder
bool showFolder() {
extern fs::path scenDir;
launchURL("file://" + scenDir.string());
return true;
}
// Refresh the scenario list (check if custom scenarios added/removed)
bool refreshList() {
scen_headers = build_scen_headers();
auto& stk = dynamic_cast<cStack&>(me["list"]);
short page = stk.getPage();
// Redo the stack
put_scen_info();
// Put the viewer to the same page it was (clamped in case the list got shorter)
stk.setPage(min(page, stk.getPageCount() - 1));
return true;
}
public:
cChooseScenario() {
// TODO: Add a button to jump to the scenarios folder
// Note: if the player jumps to the scenarios folder and adds scenarios, build_scen_headers() must be called again
scen_headers = build_scen_headers(); // TODO: Either make this local to this class, or make it take scen_headers by reference
scen_headers = build_scen_headers();
}
scen_header_type run() {
using namespace std::placeholders;
@@ -1831,6 +1848,8 @@ public:
me["scen1"].attachClickHandler(std::bind(&cChooseScenario::doSelectScenario, this, 0));
me["scen2"].attachClickHandler(std::bind(&cChooseScenario::doSelectScenario, this, 1));
me["scen3"].attachClickHandler(std::bind(&cChooseScenario::doSelectScenario, this, 2));
me["folder"].attachClickHandler(std::bind(&cChooseScenario::showFolder, this));
me["refresh"].attachClickHandler(std::bind(&cChooseScenario::refreshList, this));
put_scen_info();
@@ -1889,7 +1908,7 @@ class cFilePicker {
save_files.resize(save_file_mtimes.size());
cStack& stk = get_stack();
int num_pages = ceil((float)save_file_mtimes.size() / parties_per_page);
int num_pages = max(1, ceil((float)save_file_mtimes.size() / parties_per_page));
stk.setPageCount(num_pages);
// HACK: For some reason which should be fixed, the buttons and labels on subsequent pages
// aren't getting text on the static buttons and labels
@@ -2098,7 +2117,7 @@ class cFilePicker {
if(party_idx < parties_needed)
populate_slot(slot_idx, save_file_mtimes[party_idx].first, save_file_mtimes[party_idx].second, save_files[party_idx]);
else
empty_slot(party_idx - start_idx);
empty_slot(slot_idx);
}
++pages_populated;

View File

@@ -22,6 +22,7 @@
#include <boost/filesystem.hpp>
#include "replay.hpp"
#include <sstream>
#include <boost/algorithm/string.hpp>
#define DONE_BUTTON_ITEM 1
@@ -373,8 +374,10 @@ std::vector<scen_header_type> build_scen_headers() {
while(iter != fs::recursive_directory_iterator()) {
fs::file_status stat = iter->status();
if(stat.type() == fs::regular_file) {
std::string extension = iter->path().extension().string();
boost::algorithm::to_lower(extension);
// Skip various data files of unpacked scenarios
if(!scen_extensions.count(iter->path().extension().string())){
if(!scen_extensions.count(extension)){
++iter;
continue;
}

View File

@@ -102,6 +102,7 @@ std::string help_text_rsrc = "help";
std::map<std::string,std::vector<std::string>> feature_flags = {
// Legacy scenario flags
{"resurrection-balm", {"required"}}, // This means it CAN be supported, if the scenario has the flag.
{"conveyor-belts", {"V2"}}, // Diagonal conveyor belts and big monster physics
// Legacy behavior of the T debug action (used by some replays)
// does not change the party's outdoors location
{"debug-enter-town", {"move-outdoors"}},
@@ -1079,6 +1080,7 @@ void init_boe(int argc, char* argv[]) {
init_tiling();
init_snd_tool();
// see fallback_scale() in winutil.cpp for where the default UI scale is calculated based on screen size
adjust_window_mode();
init_ui();
// If we don't do this now it'll flash white to start with

View File

@@ -1244,8 +1244,8 @@ void erase_hidden_towns(cOutdoors& sector, int quadrant_x, int quadrant_y) {
for(short tile_index = 0; tile_index < sector.city_locs.size(); tile_index++) {
auto city_loc = sector.city_locs[tile_index];
if(!univ.scenario.is_town_entrance_valid(city_loc) ||
!does_location_have_special(sector, city_loc, eTerSpec::TOWN_ENTRANCE) ||
!sector.is_on_map(city_loc)) {
!sector.is_on_map(city_loc) ||
!does_location_have_special(sector, city_loc, eTerSpec::TOWN_ENTRANCE)) {
continue;
}
auto town_pos_x = AREA_MEDIUM * quadrant_x + sector.city_locs[tile_index].x;

View File

@@ -56,14 +56,14 @@ struct terrain_view_t {
// access to scenedit-specific global variables (which won't work unless we want to compile the common
// sources 3 times), or globals redeclared for no reason in boe.main.cpp and pc.main.cpp
struct editor_state_t {
bool drawing;
bool editing_town;
bool drawing = false;
bool editing_town = true; // I don't think this starting value of the default editor state matters.
short last_town_edited;
short last_town_edited = 0;
// Remember last view and zoom for each town
std::map<short, terrain_view_t> town_view_state;
location last_out_edited;
location last_out_edited = {0, 0};
// Remember last view and zoom for each outdoor section--
// but only for when the designer makes a discontinuous section change.
// When simply shifting over by 1 section we won't want to

View File

@@ -3,8 +3,11 @@
#include <boost/filesystem/operations.hpp>
#include "keymods.hpp"
// Measured on 5/23/25. For now, must be re-measured at 1x UI scale whenever preferences change (unless making the window smaller, maybe).
short prefs_height = 529;
// The default scale should be the largest that the user's screen can fit all three
// BoE application windows (because they should probably default to match each other).
// BoE application windows and core dialogs of the main game (because they should probably default to match each other).
double fallback_scale() {
static double scale = 0;
// Suppress the float comparison warning.
@@ -17,7 +20,7 @@ double fallback_scale() {
sf::VideoMode desktop = sf::VideoMode::getDesktopMode();
short max_width = max(boe_width, max(pc_width, scen_width));
short max_height = max(boe_height, max(pc_height, scen_height)) + getMenubarHeight();
short max_height = max(prefs_height, max(boe_height, max(pc_height, scen_height))) + getMenubarHeight();
std::vector<double> scale_options = {1.0, 1.5, 2.0, 3.0, 4.0};
for(auto it = scale_options.rbegin(); it != scale_options.rend(); ++it){