diff --git a/.ci_scripts/build_upload.ps1 b/.ci_scripts/build_upload.ps1 index 6d77137ce7..8da70250a2 100644 --- a/.ci_scripts/build_upload.ps1 +++ b/.ci_scripts/build_upload.ps1 @@ -30,7 +30,7 @@ if ("${env:COMPILER}" -eq "msvc") { CopyFile ext\SDL2\SDL2-${env:SDL_VERSION}\lib\x64\SDL2.dll . CopyFile ext\SDL2\SDL2_mixer-${env:SDL_MIXER_VERSION}\lib\x64\SDL2_mixer.dll . } elseif ("${env:COMPILER}" -eq "msvc-arm64") { - $suffix = "windows-msvc-arm64" + $suffix = "windows-arm64" CopyFile build/RelWithDebInfo/augustus.exe . CopyFile build/RelWithDebInfo/augustus.pdb . CopyFile ext\SDL2\SDL2\SDL2.dll . @@ -107,13 +107,17 @@ if (!$env:UPLOAD_TOKEN) { exit } -echo "Uploading $deploy_file to $repo/windows/$version" -curl -u "$env:UPLOAD_TOKEN" -T "deploy/$deploy_file" "https://augustus.josecadete.net/upload/$repo/windows/$version/${deploy_file}" +echo "Uploading $deploy_file to $repo/$suffix/$version" +curl -u "$env:UPLOAD_TOKEN" -T "deploy/$deploy_file" "https://augustus.josecadete.net/upload/$repo/$suffix/$version/${deploy_file}" if (!$?) { throw "Unable to upload" } echo "Uploaded. URL: https://augustus.josecadete.net/$repo.html" +if ($suffix -ne "windows") { + exit +} + if (!$packed_assets) { echo "Packing the assets" diff --git a/.ci_scripts/build_upload.sh b/.ci_scripts/build_upload.sh index 0e94194716..43ae61e8b6 100755 --- a/.ci_scripts/build_upload.sh +++ b/.ci_scripts/build_upload.sh @@ -28,6 +28,13 @@ case "$DEPLOY" in DEPLOY_FILE=augustus-$VERSION-linux-x86_64.zip cp "${build_dir}/augustus.zip" "deploy/$DEPLOY_FILE" ;; +"flatpak") + PACKAGE=linux-flatpak + DEPLOY_FILE=augustus-$VERSION-linux.flatpak + flatpak build-export export repo + flatpak build-bundle export augustus.flatpak com.github.keriew.augustus --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo + cp augustus.flatpak "deploy/$DEPLOY_FILE" + ;; "vita") PACKAGE=vita DEPLOY_FILE=augustus-$VERSION-vita.vpk diff --git a/.ci_scripts/install_dependencies.sh b/.ci_scripts/install_dependencies.sh index 752ca9ff03..0f3979e897 100755 --- a/.ci_scripts/install_dependencies.sh +++ b/.ci_scripts/install_dependencies.sh @@ -86,6 +86,12 @@ mkdir -p deps if [ "$BUILD_TARGET" == "appimage" ] || [ "$BUILD_TARGET" == "codeql-cpp" ] then sudo add-apt-repository universe && sudo add-apt-repository ppa:savoury1/multimedia && sudo apt-get update && sudo apt-get -y install libgl1-mesa-dev libsdl2-dev libsdl2-mixer-dev libfuse2 +elif [ "$BUILD_TARGET" == "flatpak" ] +then + sudo apt-get update && sudo apt-get -y install flatpak-builder + sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo + sudo flatpak-builder repo res/com.github.keriew.augustus.json --install-deps-from=flathub --install-deps-only --delete-build-dirs + sudo rm -R .flatpak-builder elif [ ! -z "$SDL_VERSION" ] && [ ! -z "$SDL_MIXER_VERSION" ] then if [ "$BUILD_TARGET" == "mac" ] diff --git a/.ci_scripts/run_build.sh b/.ci_scripts/run_build.sh index 74aded00f5..abbd76e61f 100755 --- a/.ci_scripts/run_build.sh +++ b/.ci_scripts/run_build.sh @@ -24,6 +24,10 @@ case "$BUILD_TARGET" in zip -r augustus.zip augustus.dmg fi ;; +"flatpak") + flatpak-builder repo res/com.github.keriew.augustus.json --install-deps-from=flathub --keep-build-dirs + cp .flatpak-builder/build/augustus/res/version.txt res/version.txt + ;; "appimage") cp -r res/maps ./build cp -r res/manual ./build diff --git a/.ci_scripts/run_cmake.sh b/.ci_scripts/run_cmake.sh index b6c81bfac7..a37e0be6b7 100755 --- a/.ci_scripts/run_cmake.sh +++ b/.ci_scripts/run_cmake.sh @@ -10,6 +10,8 @@ case "$BUILD_TARGET" in "mac") mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" .. ;; +"flatpak") + ;; "appimage") mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr .. ;; diff --git a/.ci_scripts/setup_environment.sh b/.ci_scripts/setup_environment.sh index a468436ca9..c086f08e52 100755 --- a/.ci_scripts/setup_environment.sh +++ b/.ci_scripts/setup_environment.sh @@ -5,12 +5,12 @@ case "$BUILD_TARGET" in # Note: Using a tagged version of the container to make sure that it's not updated unexpectedly # You can update the tag by obtaining a recent one from here: https://hub.docker.com/r/gnuton/vitasdk-docker/tags # Make sure that it compiles correctly and runs on a Vita prior to pushing the change - docker run -d --name vitasdk --workdir /build/git -v "${PWD}:/build/git" gnuton/vitasdk-docker:20230823 tail -f /dev/null + docker run -d --name vitasdk --workdir /build/git -v "${PWD}:/build/git" gnuton/vitasdk-docker:20240412 tail -f /dev/null ;; "switch") # You can obtain a recent devkitA64 image from https://hub.docker.com/repository/docker/devkitpro/devkita64/general # As for Vita above, make sure that it compiles correctly and runs on a Switch prior to pushing the change - docker run -d --name switchdev --workdir /build/git -v "${PWD}:/build/git" devkitpro/devkita64:20231108 tail -f /dev/null + docker run -d --name switchdev --workdir /build/git -v "${PWD}:/build/git" devkitpro/devkita64:20240324 tail -f /dev/null ;; "android") # Decrypt the key files diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 974d8ea3f2..17cc760fd9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,6 +13,10 @@ jobs: fail-fast: false matrix: include: + - name: Linux Flatpak + os: ubuntu-20.04 + BUILD_TARGET: flatpak + DEPLOY: flatpak - name: Linux AppImage os: ubuntu-20.04 BUILD_TARGET: appimage @@ -129,7 +133,6 @@ jobs: - name: Windows MSVC ARM64 cache-key: msvc-arm64 COMPILER: msvc-arm64 - SKIP_UPLOAD: true name: ${{ matrix.name }} runs-on: windows-latest env: diff --git a/CMakeLists.txt b/CMakeLists.txt index 485b5e940f..c553ca66cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,9 +50,9 @@ set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_SOURCE_DIR}/cmake/") set(CMAKE_C_STANDARD 99) -if(CMAKE_COMPILER_IS_GNUCC) +if(CMAKE_COMPILER_IS_GNUCC OR MINGW) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -Wno-unused-parameter -Wno-missing-field-initializers -Wno-sign-compare -Werror=implicit-function-declaration") - if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 5.0) + if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 5.0) set(CMAKE_C_FLAGS "-Werror=incompatible-pointer-types -Werror=int-conversion -Wstrict-prototypes ${CMAKE_C_FLAGS}") endif() @@ -60,7 +60,7 @@ if(CMAKE_COMPILER_IS_GNUCC) set_source_files_properties(${SOURCE_FILES} PROPERTIES COMPILE_FLAGS "-Walloc-zero -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wformat=2 -Wformat-signedness -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-prototypes -Wshadow -Wundef -Wunused-macros -Wwrite-strings") endif() elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND "${CMAKE_BUILD_TYPE}" MATCHES "Debug" AND NOT ${TARGET_PLATFORM} STREQUAL "android") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -Wall -Wextra -Wpedantic -Wdocumentation -Wno-unused-parameter -Wno-missing-field-initializers -Wno-sign-compare -Wno-unused-but-set-variable") endif() set(PROJECT_VERSION_MAJOR 4) @@ -88,7 +88,7 @@ elseif (EXISTS "${CMAKE_SOURCE_DIR}/.git") OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( - COMMAND git diff-index --quiet HEAD -- + COMMAND git diff --quiet HEAD -- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} RESULT_VARIABLE VERSION_COMMIT_DIRTY ) @@ -202,6 +202,7 @@ set(PLATFORM_FILES ${PROJECT_SOURCE_DIR}/src/platform/screen.c ${PROJECT_SOURCE_DIR}/src/platform/sound_device.c ${PROJECT_SOURCE_DIR}/src/platform/touch.c + ${PROJECT_SOURCE_DIR}/src/platform/user_path.c ${PROJECT_SOURCE_DIR}/src/platform/version.c ${PROJECT_SOURCE_DIR}/src/platform/virtual_keyboard.c ) @@ -654,6 +655,7 @@ set(WINDOW_FILES ${PROJECT_SOURCE_DIR}/src/window/text_input.c ${PROJECT_SOURCE_DIR}/src/window/trade_opened.c ${PROJECT_SOURCE_DIR}/src/window/trade_prices.c + ${PROJECT_SOURCE_DIR}/src/window/user_path_setup.c ${PROJECT_SOURCE_DIR}/src/window/victory_dialog.c ${PROJECT_SOURCE_DIR}/src/window/video.c ) @@ -780,7 +782,7 @@ endif() if(${TARGET_PLATFORM} STREQUAL "emscripten") set(CMAKE_EXECUTABLE_SUFFIX .html) - set_target_properties(${SHORT_NAME} PROPERTIES LINK_FLAGS "-lidbfs.js -s SINGLE_FILE=1 -s DEMANGLE_SUPPORT=1 -s DYNCALLS=1 --shell-file ${PROJECT_SOURCE_DIR}/res/shell.html --embed-file ${ASSETS_DIR}@/assets -s INITIAL_MEMORY=268435456 -s ALLOW_MEMORY_GROWTH=1 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 -s SAFE_HEAP=1 -s INVOKE_RUN=0 -s EXPORTED_FUNCTIONS=[\"_main\"] -s EXPORTED_RUNTIME_METHODS=[\"callMain\",\"FS\"] -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[\"$autoResumeAudioContext\"] --bind") + set_target_properties(${SHORT_NAME} PROPERTIES LINK_FLAGS "-lidbfs.js -s SINGLE_FILE=1 -s DYNCALLS=1 --shell-file ${PROJECT_SOURCE_DIR}/res/shell.html --embed-file ${ASSETS_DIR}@/assets -s INITIAL_MEMORY=268435456 -s ALLOW_MEMORY_GROWTH=1 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 -s SAFE_HEAP=1 -s INVOKE_RUN=0 -s EXPORTED_FUNCTIONS=[\"_main\"] -s EXPORTED_RUNTIME_METHODS=[\"callMain\",\"FS\"] -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[\"$autoResumeAudioContext\"] --bind") endif() if(MSVC) diff --git a/README.md b/README.md index 2f0e8b518f..2ca507098a 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Chat: [Discord](http://www.discord.gg/GamerZakh) (kindly hosted by GamerZakh) |----------|----------------|----------------| | Windows | [![Download](https://augustus.josecadete.net/badge/release/windows.svg)](https://augustus.josecadete.net/download/latest/release/windows) | [![Download](https://augustus.josecadete.net/badge/development/windows.svg)](https://augustus.josecadete.net/download/latest/development/windows) [(Download development assets)](https://augustus.josecadete.net/download/latest/development/assets) | | Linux AppImage | [![Download](https://augustus.josecadete.net/badge/release/linux-appimage.svg)](https://augustus.josecadete.net/download/latest/release/linux-appimage) | [![Download](https://augustus.josecadete.net/badge/development/linux-appimage.svg)](https://augustus.josecadete.net/download/latest/development/linux-appimage) +| Linux Flatpak | Next release! | [![Download](https://augustus.josecadete.net/badge/development/linux-flatpak.svg)](https://augustus.josecadete.net/download/latest/development/linux-flatpak) | Mac | [![Download](https://augustus.josecadete.net/badge/release/mac.svg)](https://augustus.josecadete.net/download/latest/release/mac) | [![Download](https://augustus.josecadete.net/badge/development/mac.svg)](https://augustus.josecadete.net/download/latest/development/mac) | | PS Vita | [![Download](https://augustus.josecadete.net/badge/release/vita.svg)](https://augustus.josecadete.net/download/latest/release/vita)| [![Download](https://augustus.josecadete.net/badge/development/vita.svg)](https://augustus.josecadete.net/download/latest/development/vita) | | Switch | [![Download](https://augustus.josecadete.net/badge/release/switch.svg)](https://augustus.josecadete.net/download/latest/release/switch) | [![Download](https://augustus.josecadete.net/badge/development/switch.svg)](https://augustus.josecadete.net/download/latest/development/switch) | diff --git a/android/SDL2/build.gradle b/android/SDL2/build.gradle index fc40c908ee..591156c709 100644 --- a/android/SDL2/build.gradle +++ b/android/SDL2/build.gradle @@ -38,7 +38,7 @@ tasks.register('findSDL2Mixer') { } android { - ndkVersion "26.2.11394342" + ndkVersion "26.3.11579264" defaultConfig { compileSdk 34 diff --git a/android/augustus/build.gradle b/android/augustus/build.gradle index 3cfe4ee805..28b014d115 100644 --- a/android/augustus/build.gradle +++ b/android/augustus/build.gradle @@ -65,7 +65,7 @@ tasks.register('getVersion') { } android { - ndkVersion "26.2.11394342" + ndkVersion "26.3.11579264" defaultConfig { compileSdk 34 diff --git a/android/augustus/src/main/java/com/github/Keriew/augustus/AugustusMainActivity.java b/android/augustus/src/main/java/com/github/Keriew/augustus/AugustusMainActivity.java index 5571172fb8..6277b85a3b 100644 --- a/android/augustus/src/main/java/com/github/Keriew/augustus/AugustusMainActivity.java +++ b/android/augustus/src/main/java/com/github/Keriew/augustus/AugustusMainActivity.java @@ -42,6 +42,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } } + @SuppressWarnings("unused") public float getScreenDensity() { return getResources().getDisplayMetrics().density; } diff --git a/android/augustus/src/main/java/com/github/Keriew/augustus/FileManager.java b/android/augustus/src/main/java/com/github/Keriew/augustus/FileManager.java index af2c65f618..467301e0e3 100644 --- a/android/augustus/src/main/java/com/github/Keriew/augustus/FileManager.java +++ b/android/augustus/src/main/java/com/github/Keriew/augustus/FileManager.java @@ -83,15 +83,24 @@ private static FileInfo findFile(Activity activity, FileInfo folder, String file } private static FileInfo getDirectoryFromPath(Activity activity, String[] path) { - FileInfo currentDir = FileInfo.base; + ArrayList dirList = new ArrayList<>(); + dirList.add(FileInfo.base); for (int i = 0; i < path.length - 1; ++i) { - currentDir = findFile(activity, currentDir, path[i]); - if (currentDir == null || !currentDir.isDirectory()) { - return null; + if (path[i].equals("..")) { + if (dirList.size() == 1) { + return null; + } + dirList.remove(dirList.size() - 1); + } else if (!path[i].isEmpty() && !path[i].equals(".")) { + FileInfo currentDir = findFile(activity, dirList.get(dirList.size() - 1), path[i]); + if (currentDir == null || !currentDir.isDirectory()) { + return null; + } + dirList.add(currentDir); } } - return currentDir; + return dirList.get(dirList.size() - 1); } private static FileInfo getFileFromPath(AugustusMainActivity activity, String filePath) { @@ -99,7 +108,7 @@ private static FileInfo getFileFromPath(AugustusMainActivity activity, String fi if (baseUri == Uri.EMPTY) { return null; } - String[] filePart = filePath.split("(\\|/)"); + String[] filePart = filePath.split("[\\\\/]"); FileInfo dirInfo = getDirectoryFromPath(activity, filePart); if (dirInfo == null) { return null; @@ -146,6 +155,7 @@ public static FileInfo[] getDirectoryFileList(AugustusMainActivity activity, Str return fileList.toArray(result); } + @SuppressWarnings("unused") public static boolean deleteFile(AugustusMainActivity activity, String filePath) { try { FileInfo fileInfo = getFileFromPath(activity, filePath); @@ -212,8 +222,9 @@ public static int openFileDescriptor(AugustusMainActivity activity, String fileP fileInfo.updateModifiedTime(); } } - ParcelFileDescriptor pfd = activity.getContentResolver().openFileDescriptor(fileUri, internalMode); - return (pfd == null) ? 0 : pfd.detachFd(); + try (ParcelFileDescriptor pfd = activity.getContentResolver().openFileDescriptor(fileUri, internalMode)) { + return (pfd == null) ? 0 : pfd.detachFd(); + } } catch (Exception e) { Log.e("augustus", "Error in openFileDescriptor: " + e); return 0; diff --git a/android/build.gradle b/android/build.gradle index 3083f3413a..d7a73dbbbe 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.3.0' + classpath 'com.android.tools.build:gradle:8.4.0' classpath 'com.github.triplet.gradle:play-publisher:3.7.0' } } diff --git a/android/gradle.properties b/android/gradle.properties index 80ca111a0e..960c41f1e0 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -21,6 +21,5 @@ org.gradle.configureondemand=true org.gradle.caching=true android.useAndroidX=true android.enableJetifier=false -android.defaults.buildfeatures.buildconfig=true android.nonTransitiveRClass=true android.nonFinalResIds=false diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index e411586a54..17655d0ef2 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/ext/spng/spng.c b/ext/spng/spng.c index 76f12190f9..989bb6d53f 100644 --- a/ext/spng/spng.c +++ b/ext/spng/spng.c @@ -2362,7 +2362,7 @@ static int read_non_idat_chunks(spng_ctx *ctx) ctx->undo = NULL; ctx->prev_stored = ctx->stored; - while( !(ret = read_header(ctx))) + while( (ret = read_header(ctx)) == 0 ) { if(ctx->discard) { @@ -3914,7 +3914,7 @@ int spng_decode_image(spng_ctx *ctx, void *out, size_t len, int fmt, int flags) if(f.apply_trns) { - uint16_t mask = ~0; + uint16_t mask = (uint16_t)~0; if(ctx->ihdr.bit_depth < 16) mask = (1 << ctx->ihdr.bit_depth) - 1; if(fmt & (SPNG_FMT_RGBA8 | SPNG_FMT_RGBA16)) @@ -4933,7 +4933,7 @@ spng_ctx *spng_ctx_new2(struct spng_alloc *alloc, int flags) ctx->image_options = image_defaults; ctx->text_options = text_defaults; - ctx->optimize_option = ~0; + ctx->optimize_option = ~0u; ctx->encode_flags.filter_choice = SPNG_FILTER_CHOICE_ALL; ctx->flags = flags; diff --git a/ext/sxml/sxml.c b/ext/sxml/sxml.c index 3fc1999f4e..906a697b3f 100644 --- a/ext/sxml/sxml.c +++ b/ext/sxml/sxml.c @@ -53,11 +53,11 @@ static const char* str_findstr (const char* start, const char* end, const char* static BOOL str_startswith (const char* start, const char* end, const char* prefix) { - long nbytes; + size_t nbytes; assert (start <= end); nbytes= strlen (prefix); - if (end - start < nbytes) + if ((size_t) (end - start) < nbytes) return FALSE; return memcmp (prefix, start, nbytes) == 0; @@ -543,7 +543,7 @@ sxmlerr_t sxml_parse(sxml_t *state, const char *buffer, UINT bufferlen, sxmltok_ const char* lt= str_findchr (start, end, '<'); while (buffer_fromoffset (&args, temp.bufferpos) != lt) { - sxmlerr_t err= parse_characters (&temp, &args, lt); + err= parse_characters (&temp, &args, lt); if (err != SXML_SUCCESS) return err; diff --git a/ext/tinyfiledialogs/tinyfiledialogs.c b/ext/tinyfiledialogs/tinyfiledialogs.c index 48d49fd1bf..dcbe26c297 100644 --- a/ext/tinyfiledialogs/tinyfiledialogs.c +++ b/ext/tinyfiledialogs/tinyfiledialogs.c @@ -1,26 +1,33 @@ /* -Note: This file is a heavily stripped-down version of Tinyfiledialogs, customized for Julius. +Note: This file is a heavily stripped-down version of Tinyfiledialogs, customized for Augustus. If you are interested in Tinyfiledialogs, please download its original version from the links below. -Tinyfiledialogs: -Copyright (c) 2014 - 2018 Guillaume Vareille http://ysengrin.com -http://tinyfiledialogs.sourceforge.net +SPDX-License-Identifier: Zlib +Copyright (c) 2014 - 2024 Guillaume Vareille http://ysengrin.com -Thanks for contributions, bug corrections & thorough testing to: -- Don Heyse http://ldglite.sf.net for bug corrections & thorough testing! -- Paul Rouget +********* TINY FILE DIALOGS OFFICIAL WEBSITE IS ON SOURCEFORGE ********* + _________ + / \ tinyfiledialogs.c v3.18.1 [May 2, 2024] zlib licence + |tiny file| Unique code file created [November 9, 2014] + | dialogs | + \____ ___/ http://tinyfiledialogs.sourceforge.net + \| git clone http://git.code.sf.net/p/tinyfiledialogs/code tinyfd + ____________________________________________ + | | + | email: tinyfiledialogs at ysengrin.com | + |____________________________________________| -- License - +If you like tinyfiledialogs, please upvote my stackoverflow answer +https://stackoverflow.com/a/47651444 +- License - This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be @@ -30,8 +37,25 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#ifndef __sun -#define _POSIX_C_SOURCE 2 /* to accept POSIX 2 in old ANSI C standards */ +#include "tinyfiledialogs.h" + +#ifndef USE_TINYFILEDIALOGS +char *tinyfd_selectFolderDialog(char const *aTitle, char const *aDefaultPath) { return 0; } +#else + +#if defined(__GNUC__) || defined(__clang__) +#ifndef _GNU_SOURCE + #define _GNU_SOURCE /* used only to resolve symbolic links. Can be commented out */ + #ifndef _POSIX_C_SOURCE + #ifdef __FreeBSD__ + #define _POSIX_C_SOURCE 199506L /* 199506L is enough for freebsd for realpath() */ + #elif defined(__illumos__) || defined(__solaris__) + #define _POSIX_C_SOURCE 200112L /* illumos/solaris needs 200112L for realpath() */ + #else + #define _POSIX_C_SOURCE 2 /* to accept POSIX 2 in old ANSI C standards */ + #endif + #endif +#endif #endif #include @@ -40,1237 +64,1178 @@ misrepresented as being the original software. #include #include -#include "tinyfiledialogs.h" - -#ifdef USE_TINYFILEDIALOGS - #ifdef _WIN32 -#ifdef __BORLANDC__ -#define _getch getch -#endif -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0500 -#endif -#include -#include -#include -#include + #ifdef __BORLANDC__ + #define _getch getch + #endif + #ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0500 + #endif + #include + #include + #define TINYFD_SLASH "\\" #else -#include -#include -#include /* on old systems try instead */ -#include -#include -#include /* on old systems try instead */ + #include /* on old systems try instead */ + #include + #include /* on old systems try instead */ + #include + #define TINYFD_SLASH "/" #endif /* _WIN32 */ #define MAX_PATH_OR_CMD 1024 /* _MAX_PATH or MAX_PATH */ -int tinyfd_verbose = 0; /* on unix: prints the command line calls */ -int tinyfd_silent = 1; /* 1 (default) or 0 : on unix, - hide errors and warnings from called dialog*/ - -#ifdef _WIN32 -char const tinyfd_needs[] = "\ - ___________\n\ -/ \\ \n\ -| tiny file |\n\ -| dialogs |\n\ -\\_____ ____/\n\ - \\|\ -\ntiny file dialogs on Windows needs:\ -\n a graphic display\ -\nor dialog.exe (enhanced console mode)\ -\nor a console for basic input"; -#else -char const tinyfd_needs[] = "\ - ___________\n\ -/ \\ \n\ -| tiny file |\n\ -| dialogs |\n\ -\\_____ ____/\n\ - \\|\ -\ntiny file dialogs on UNIX needs:\ -\n applescript\ -\nor kdialog\ -\nor zenity (or matedialog or qarma)\ -\nor python (2 or 3)\ -\n + tkinter + python-dbus (optional)\ -\nor dialog (opens console if needed)\ -\nor xterm + bash\ -\n (opens console for basic input)\ -\nor existing console for basic input"; -#endif - #ifdef _MSC_VER #pragma warning(disable:4996) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */ #pragma warning(disable:4100) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */ #pragma warning(disable:4706) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */ #endif +static int tfd_quoteDetected(char const * aString) +{ + char const * p; + + if (!aString) return 0; + + p = aString; + if ( strchr(p, '\'')) + { + return 1; + } + + if ( strchr(p, '\"')) + { + return 1; + } + + if ( strchr(p, '`')) + { + return 1; + } + + p = aString; + while ((p = strchr(p, '$'))) + { + p ++ ; + if ( ( * p == '(' ) || ( * p == '_' ) || isalpha( * p) ) return 1 ; + } + + return 0; +} + #ifdef _WIN32 #if !defined(WC_ERR_INVALID_CHARS) /* undefined prior to Vista, so not yet in MINGW header file */ -#define WC_ERR_INVALID_CHARS 0x00000080 +#define WC_ERR_INVALID_CHARS 0x00000000 /* 0x00000080 for MINGW maybe ? */ #endif -static wchar_t *utf8to16(char const *const utf8) +static int sizeUtf16From8(char const * aUtf8string) { - int charactersNeeded = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8, -1, NULL, 0); - wchar_t *utf16 = (wchar_t *) malloc(charactersNeeded * sizeof(wchar_t)); - int charactersWritten = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8, -1, utf16, charactersNeeded); - if (charactersWritten == 0) { - free(utf16); - return NULL; - } - return utf16; + return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + aUtf8string, -1, NULL, 0); } -static char *utf16to8(wchar_t const *const utf16) +static int sizeUtf16FromMbcs(char const * aMbcsString) { - int bytesNeeded = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, NULL, 0, NULL, NULL); - char *utf8 = (char *) malloc(bytesNeeded); - int bytesWritten = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, utf8, bytesNeeded, NULL, NULL); - if (bytesWritten == 0) { - free(utf8); - return NULL; - } - return utf8; + return MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, + aMbcsString, -1, NULL, 0); } -static int dirExists(wchar_t const *const dirPath) +static int sizeUtf8(wchar_t const * aUtf16string) { - if (!dirPath) { - return 0; - } - size_t dirLen = wcslen(dirPath); - if (dirLen == 0) { - return 0; - } else if (dirLen == 2 && dirPath[1] == L':') { - return 1; - } - - struct _stat info; - int statResult = _wstat(dirPath, &info); - return statResult == 0 && info.st_mode & S_IFDIR; + return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + aUtf16string, -1, NULL, 0, NULL, NULL); } -int tinyfd_messageBox( - char const *const aTitle, /* NULL or "" */ - char const *const aMessage, /* NULL or "" may contain \n and \t */ - char const *const aDialogType, /* "ok" "okcancel" */ - char const *const aIconType, /* "info" "warning" "error" "question" */ - int const aDefaultButton) /* 0 for cancel, 1 for ok */ +static wchar_t* tinyfd_mbcsTo16(char const* aMbcsString) { - wchar_t *wTitle = utf8to16(aTitle); - wchar_t *wMessage = utf8to16(aMessage); - - UINT mbCode; - if (aIconType && strcmp("warning", aIconType) == 0) { - mbCode = MB_ICONWARNING; - } else if (aIconType && strcmp("error", aIconType) == 0) { - mbCode = MB_ICONERROR; - } else if (aIconType && strcmp("question", aIconType) == 0) { - mbCode = MB_ICONQUESTION; - } else { - mbCode = MB_ICONINFORMATION; - } + static wchar_t* lMbcsString = NULL; + int lSize; + + free(lMbcsString); + if (!aMbcsString) { lMbcsString = NULL; return NULL; } + lSize = sizeUtf16FromMbcs(aMbcsString); + if (lSize) + { + lMbcsString = (wchar_t*) malloc(lSize * sizeof(wchar_t)); + lSize = MultiByteToWideChar(CP_ACP, 0, aMbcsString, -1, lMbcsString, lSize); + } + else wcscpy(lMbcsString, L""); + return lMbcsString; +} - if (aDialogType && strcmp("okcancel", aDialogType) == 0) { - mbCode |= MB_OKCANCEL; - if (aDefaultButton == 0) { - mbCode |= MB_DEFBUTTON2; - } - } else { - mbCode |= MB_OK; - } - mbCode |= MB_TOPMOST; +static wchar_t * tinyfd_utf8to16(char const * aUtf8string) +{ + static wchar_t * lUtf16string = NULL; + int lSize; + + free(lUtf16string); + if (!aUtf8string) {lUtf16string = NULL; return NULL;} + lSize = sizeUtf16From8(aUtf8string); + if (lSize) + { + lUtf16string = (wchar_t*) malloc(lSize * sizeof(wchar_t)); + lSize = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + aUtf8string, -1, lUtf16string, lSize); + return lUtf16string; + } + else + { + /* let's try mbcs anyway */ + lUtf16string = NULL; + return tinyfd_mbcsTo16(aUtf8string); + } +} - int mbResult = MessageBoxW(GetForegroundWindow(), wMessage, wTitle, mbCode); +static char * tinyfd_utf16to8(wchar_t const * aUtf16string) +{ + static char * lUtf8string = NULL; + int lSize; + + free(lUtf8string); + if (!aUtf16string) { lUtf8string = NULL; return NULL; } + lSize = sizeUtf8(aUtf16string); + if (lSize) + { + lUtf8string = (char*) malloc(lSize); + lSize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, aUtf16string, -1, lUtf8string, lSize, NULL, NULL); + } + else strcpy(lUtf8string, ""); + return lUtf8string; +} - free(wTitle); - free(wMessage); +static int dirExists(char const * aDirPath) +{ +#if (defined(__MINGW32_MAJOR_VERSION) && !defined(__MINGW64__) && (__MINGW32_MAJOR_VERSION <= 3)) || defined(__BORLANDC__) || defined(__WATCOMC__) + struct _stat lInfo; +#else + struct __stat64 lInfo; +#endif + wchar_t * lTmpWChar; + int lStatRet; + size_t lDirLen; + + if (!aDirPath) + return 0; + lDirLen = strlen(aDirPath); + if (!lDirLen) + return 1; + if ( (lDirLen == 2) && (aDirPath[1] == ':') ) + return 1; + + lTmpWChar = tinyfd_utf8to16(aDirPath); +#if (defined(__MINGW32_MAJOR_VERSION) && !defined(__MINGW64__) && (__MINGW32_MAJOR_VERSION <= 3)) || defined(__BORLANDC__) || defined(__WATCOMC__) + lStatRet = _wstat(lTmpWChar, &lInfo); +#else + lStatRet = _wstat64(lTmpWChar, &lInfo); +#endif + if (lStatRet != 0) + return 0; + else if (lInfo.st_mode & S_IFDIR) + return 1; + else + return 0; +} - if ((aDialogType && strcmp("okcancel", aDialogType)) || (mbResult == IDOK)) { - return 1; - } else { - return 0; - } +static BOOL CALLBACK BrowseCallbackProcW_enum(HWND hWndChild, LPARAM lParam) +{ + wchar_t buf[255]; + (void)lParam; + GetClassNameW(hWndChild, buf, sizeof(buf)); + if (wcscmp(buf, L"SysTreeView32") == 0) + { + HTREEITEM hNode = TreeView_GetSelection(hWndChild); + TreeView_EnsureVisible(hWndChild, hNode); + return FALSE; + } + return TRUE; } static int __stdcall BrowseCallbackProcW(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) { - if (uMsg == BFFM_INITIALIZED) { - SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) pData); - } - return 0; + (void)lp; + switch (uMsg) + { + case BFFM_INITIALIZED: + SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM)pData); + break; + case BFFM_SELCHANGED: + EnumChildWindows(hwnd, BrowseCallbackProcW_enum, 0); + } + return 0; } -char const *tinyfd_selectFolderDialog(char const *const aTitle) /* NULL or "" */ +static wchar_t * tinyfd_selectFolderDialogW( + wchar_t const * aTitle, /* NULL or "" */ + wchar_t const * aDefaultPath) /* NULL or "" */ { - static char resultBuff[MAX_PATH_OR_CMD]; - static wchar_t wBuff[MAX_PATH_OR_CMD]; - - wchar_t *wTitle = utf8to16(aTitle); - - BROWSEINFOW bInfo; - HRESULT hResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - - bInfo.hwndOwner = GetForegroundWindow(); - bInfo.pidlRoot = NULL; - bInfo.pszDisplayName = wBuff; - bInfo.lpszTitle = wTitle && wcslen(wTitle) ? wTitle : NULL; - if (hResult == S_OK || hResult == S_FALSE) { - bInfo.ulFlags = BIF_USENEWUI; - } - bInfo.lpfn = BrowseCallbackProcW; - bInfo.lParam = 0; - bInfo.iImage = -1; - bInfo.ulFlags |= BIF_RETURNONLYFSDIRS; - - LPITEMIDLIST lpItem = SHBrowseForFolderW(&bInfo); - if (lpItem) { - SHGetPathFromIDListW(lpItem, wBuff); - } - - if (hResult == S_OK || hResult == S_FALSE) { - CoUninitialize(); - } - - free(wTitle); - - if (!dirExists(wBuff)) { - return NULL; - } + static wchar_t lBuff[MAX_PATH_OR_CMD]; + wchar_t * lRetval; + + BROWSEINFOW bInfo; + LPITEMIDLIST lpItem; + HRESULT lHResult; + + lHResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + bInfo.hwndOwner = GetForegroundWindow(); + bInfo.pidlRoot = NULL; + bInfo.pszDisplayName = lBuff; + bInfo.lpszTitle = aTitle && wcslen(aTitle) ? aTitle : NULL; + if (lHResult == S_OK || lHResult == S_FALSE) + { + bInfo.ulFlags = BIF_USENEWUI; + } + bInfo.lpfn = BrowseCallbackProcW; + bInfo.lParam = (LPARAM)aDefaultPath; + bInfo.iImage = -1; + + lpItem = SHBrowseForFolderW(&bInfo); + if (!lpItem) + { + lRetval = NULL; + } + else + { + SHGetPathFromIDListW(lpItem, lBuff); + lRetval = lBuff ; + } + + if (lHResult == S_OK || lHResult == S_FALSE) + { + CoUninitialize(); + } + return lRetval; +} - char *dirPath = utf16to8(wBuff); - strcpy(resultBuff, dirPath); - free(dirPath); +static char * selectFolderDialogWinGui( + char * aoBuff, + char const * aTitle, /* NULL or "" */ + char const * aDefaultPath) /* NULL or "" */ +{ + wchar_t lTitle[128] = L""; + wchar_t lDefaultPath[MAX_PATH_OR_CMD] = L""; + wchar_t * lTmpWChar; + char * lTmpChar; + + if (aTitle) + { + lTmpWChar = tinyfd_utf8to16(aTitle); + wcscpy(lTitle, lTmpWChar); + } + if (aDefaultPath) + { + lTmpWChar = tinyfd_utf8to16(aDefaultPath); + wcscpy(lDefaultPath, lTmpWChar); + } + + lTmpWChar = tinyfd_selectFolderDialogW( + lTitle, + lDefaultPath); + + if (!lTmpWChar) + { + return NULL; + } + + lTmpChar = tinyfd_utf16to8(lTmpWChar); + strcpy(aoBuff, lTmpChar); + + return aoBuff; +} - return resultBuff; +char * tinyfd_selectFolderDialog( + char const * aTitle , /* NULL or "" */ + char const * aDefaultPath ) /* NULL or "" */ +{ + static char lBuff[MAX_PATH_OR_CMD]; + char * p = NULL; + + if (tfd_quoteDetected(aTitle)) return tinyfd_selectFolderDialog("INVALID TITLE WITH QUOTES", aDefaultPath); + if (tfd_quoteDetected(aDefaultPath)) return tinyfd_selectFolderDialog(aTitle, "INVALID DEFAULT_PATH WITH QUOTES"); + + if (!getenv("SSH_CLIENT") || getenv("DISPLAY")) + { + p = selectFolderDialogWinGui(lBuff, aTitle, aDefaultPath); + } + + if ( ! p || ! strlen( p ) || ! dirExists( p ) ) + { + return NULL ; + } + return p ; } #else /* unix */ -#define RETURN_CACHED_INT(setter) static int result = -1; if (result == -1) { result = setter; } return result; - -static int gWarningDisplayed = 0; - -static char const gTitle[] = "missing software! (we will try basic console input)"; - static char gPython2Name[16]; static char gPython3Name[16]; -static void replaceSubStr( - char const *const aSource, - char const *const aOldSubStr, - char const *const aNewSubStr, - char *const aoDestination) +static int tfd_isDarwin(void) { - char const *pOccurence; - char const *p; - char const *lNewSubStr = ""; - size_t lOldSubLen = strlen(aOldSubStr); - - if (!aSource) { - *aoDestination = '\0'; - return; - } - if (!aOldSubStr) { - strcpy(aoDestination, aSource); - return; - } - if (aNewSubStr) { - lNewSubStr = aNewSubStr; - } - p = aSource; - *aoDestination = '\0'; - while ((pOccurence = strstr(p, aOldSubStr)) != NULL) { - strncat(aoDestination, p, pOccurence - p); - strcat(aoDestination, lNewSubStr); - p = pOccurence + lOldSubLen; - } - strcat(aoDestination, p); + static int lsIsDarwin = -1 ; + struct utsname lUtsname ; + if ( lsIsDarwin < 0 ) + { + lsIsDarwin = !uname(&lUtsname) && !strcmp(lUtsname.sysname,"Darwin") ; + } + return lsIsDarwin ; } -static int dirExists(char const *const dirPath) +static char * getPathWithoutFinalSlash( + char * aoDestination, /* make sure it is allocated, use _MAX_PATH */ + char const * aSource) /* aoDestination and aSource can be the same */ { - if (!dirPath || !strlen(dirPath)) { - return 0; - } - DIR *dir = opendir(dirPath); - if (!dir) { - return 0; - } - closedir(dir); - return 1; + char const * lTmp ; + if ( aSource ) + { + lTmp = strrchr(aSource, '/'); + if (!lTmp) + { + lTmp = strrchr(aSource, '\\'); + } + if (lTmp) + { + strncpy(aoDestination, aSource, lTmp - aSource ); + aoDestination[lTmp - aSource] = '\0'; + } + else + { + * aoDestination = '\0'; + } + } + else + { + * aoDestination = '\0'; + } + return aoDestination; } -static int detectPresence(char const *const aExecutable) +static void ensureFinalSlash( char * aioString ) { - char lBuff[MAX_PATH_OR_CMD]; - char lTestedString[MAX_PATH_OR_CMD] = "which "; - FILE *lIn; - - strcat(lTestedString, aExecutable); - strcat(lTestedString, " 2>/dev/null "); - lIn = popen(lTestedString, "r"); - if ((fgets(lBuff, sizeof(lBuff), lIn) != NULL) - && (!strchr(lBuff, ':')) - && (strncmp(lBuff, "no ", 3))) { /* present */ - pclose(lIn); - if (tinyfd_verbose) printf("detectPresence %s %d\n", aExecutable, 1); - return 1; - } else { - pclose(lIn); - if (tinyfd_verbose) printf("detectPresence %s %d\n", aExecutable, 0); - return 0; - } + if ( aioString && strlen( aioString ) ) + { + char * lastcar = aioString + strlen( aioString ) - 1 ; + if ( strncmp( lastcar , TINYFD_SLASH , 1 ) ) + { + strcat( lastcar , TINYFD_SLASH ) ; + } + } } - -static int tryCommand(char const *const aCommand) +static int dirExists( char const * aDirPath ) { - char lBuff[MAX_PATH_OR_CMD]; - FILE *lIn; - - lIn = popen(aCommand, "r"); - if (fgets(lBuff, sizeof(lBuff), lIn) == NULL) { /* present */ - pclose(lIn); - return 1; - } else { - pclose(lIn); - return 0; - } + DIR * lDir ; + if ( ! aDirPath || ! strlen( aDirPath ) ) + return 0 ; + lDir = opendir( aDirPath ) ; + if ( ! lDir ) + { + return 0 ; + } + closedir( lDir ) ; + return 1 ; } -static int copyAndDetectPresence(char *aExecutable, char const *const path) +static int detectPresence( char const * aExecutable ) { - strcpy(aExecutable, path); - return detectPresence(aExecutable); + char lBuff[MAX_PATH_OR_CMD] ; + char lTestedString[MAX_PATH_OR_CMD] = "command -v " ; + FILE * lIn ; +#ifdef _GNU_SOURCE + char* lAllocatedCharString; + int lSubstringUndetected; +#endif + + strcat( lTestedString , aExecutable ) ; + strcat( lTestedString, " 2>/dev/null "); + lIn = popen( lTestedString , "r" ) ; + if ( ( fgets( lBuff , sizeof( lBuff ) , lIn ) != NULL ) + && ( ! strchr( lBuff , ':' ) ) && ( strncmp(lBuff, "no ", 3) ) ) + { /* present */ + pclose( lIn ) ; + +#ifdef _GNU_SOURCE /*to bypass this, just comment out "#define _GNU_SOURCE" at the top of the file*/ + if ( lBuff[strlen( lBuff ) -1] == '\n' ) lBuff[strlen( lBuff ) -1] = '\0' ; + lAllocatedCharString = realpath(lBuff,NULL); /*same as canonicalize_file_name*/ + lSubstringUndetected = ! strstr(lAllocatedCharString, aExecutable); + free(lAllocatedCharString); + if (lSubstringUndetected) + { + return 0; + } +#endif /*_GNU_SOURCE*/ + + return 1 ; + } + else + { + pclose( lIn ) ; + return 0 ; + } } -static int isTerminalRunning(void) +static char * getVersion( char const * aExecutable ) /*version must be first numeral*/ { - static int lIsTerminalRunning = -1; - if (lIsTerminalRunning < 0) { - lIsTerminalRunning = isatty(1); - if (tinyfd_verbose) printf("isTerminalRunning %d\n", lIsTerminalRunning); - } - return lIsTerminalRunning; + static char lBuff[MAX_PATH_OR_CMD] ; + char lTestedString[MAX_PATH_OR_CMD] ; + FILE * lIn ; + char * lTmp ; + + strcpy( lTestedString , aExecutable ) ; + strcat( lTestedString , " --version" ) ; + + lIn = popen( lTestedString , "r" ) ; + lTmp = fgets( lBuff , sizeof( lBuff ) , lIn ) ; + pclose( lIn ) ; + + lTmp += strcspn(lTmp,"0123456789"); + /* printf("lTmp:%s\n", lTmp); */ + return lTmp ; } +static int * getMajorMinorPatch( char const * aExecutable ) +{ + static int lArray[3] ; + char * lTmp ; + + lTmp = (char *) getVersion(aExecutable); + lArray[0] = atoi( strtok(lTmp," ,.-") ) ; + /* printf("lArray0 %d\n", lArray[0]); */ + lArray[1] = atoi( strtok(0," ,.-") ) ; + /* printf("lArray1 %d\n", lArray[1]); */ + lArray[2] = atoi( strtok(0," ,.-") ) ; + /* printf("lArray2 %d\n", lArray[2]); */ + + if ( !lArray[0] && !lArray[1] && !lArray[2] ) return NULL; + return lArray ; +} -static char const *terminalName(void) +static int tryCommand( char const * aCommand ) { - static char lTerminalName[128] = "*"; - char lShellName[64] = "*"; - - if (lTerminalName[0] == '*') { - if (detectPresence("bash")) { - strcpy(lShellName, "bash -c "); /*good for basic input*/ - } else { - strcpy(lTerminalName, ""); - return NULL; - } + char lBuff[MAX_PATH_OR_CMD] ; + FILE * lIn ; + + lIn = popen( aCommand , "r" ) ; + if ( fgets( lBuff , sizeof( lBuff ) , lIn ) == NULL ) + { /* present */ + pclose( lIn ) ; + return 1 ; + } + else + { + pclose( lIn ) ; + return 0 ; + } - if (copyAndDetectPresence(lTerminalName, "xterm")) { /*good (small without parameters)*/ - strcat(lTerminalName, " -fa 'DejaVu Sans Mono' -fs 10 -title tinyfiledialogs -e "); - strcat(lTerminalName, lShellName); - } else if (copyAndDetectPresence(lTerminalName, "terminator")) { /*good*/ - strcat(lTerminalName, " -x "); - strcat(lTerminalName, lShellName); - } else if (copyAndDetectPresence(lTerminalName, "lxterminal")) { /*good*/ - strcat(lTerminalName, " -e "); - strcat(lTerminalName, lShellName); - } else if (copyAndDetectPresence(lTerminalName, "konsole")) { /*good*/ - strcat(lTerminalName, " -e "); - strcat(lTerminalName, lShellName); - } else if (copyAndDetectPresence(lTerminalName, "kterm")) { /*good*/ - strcat(lTerminalName, " -e "); - strcat(lTerminalName, lShellName); - } else if (copyAndDetectPresence(lTerminalName, "tilix")) { /*good*/ - strcat(lTerminalName, " -e "); - strcat(lTerminalName, lShellName); - } else if (copyAndDetectPresence(lTerminalName, "xfce4-terminal")) { /*good*/ - strcat(lTerminalName, " -x "); - strcat(lTerminalName, lShellName); - } else if (copyAndDetectPresence(lTerminalName, "mate-terminal")) { /*good*/ - strcat(lTerminalName, " -x "); - strcat(lTerminalName, lShellName); - } else if (copyAndDetectPresence(lTerminalName, "Eterm")) { /*good*/ - strcat(lTerminalName, " -e "); - strcat(lTerminalName, lShellName); - } else if (copyAndDetectPresence(lTerminalName, "evilvte")) { /*good*/ - strcat(lTerminalName, " -e "); - strcat(lTerminalName, lShellName); - } else if (copyAndDetectPresence(lTerminalName, "pterm")) { /*good (only letters)*/ - strcat(lTerminalName, " -e "); - strcat(lTerminalName, lShellName); - } else { - strcpy(lTerminalName, ""); - } - /* bad: koi rxterm guake tilda vala-terminal qterminal - aterm Terminal terminology sakura lilyterm weston-terminal - roxterm termit xvt rxvt mrxvt urxvt */ - } - if (strlen(lTerminalName)) { - return lTerminalName; - } else { - return NULL; - } } -static int xmessagePresent(void) +static int isTerminalRunning(void) { - RETURN_CACHED_INT(detectPresence("xmessage")); + static int lIsTerminalRunning = -1 ; + if ( lIsTerminalRunning < 0 ) + { + lIsTerminalRunning = isatty(1); + } + return lIsTerminalRunning; } -static int gxmessagePresent(void) +static char * terminalName(void) { - RETURN_CACHED_INT(detectPresence("gxmessage")); + static char lTerminalName[128] = "*" ; + char lShellName[64] = "*" ; + int * lArray; + + if ( lTerminalName[0] == '*' ) + { + if ( detectPresence( "bash" ) ) + { + strcpy(lShellName , "bash -c " ) ; /*good for basic input*/ + } + else + { + strcpy(lTerminalName , "" ) ; + return NULL ; + } + + if ( tfd_isDarwin() ) + { + if ( * strcpy(lTerminalName , "/opt/X11/bin/xterm" ) + && detectPresence( lTerminalName ) ) + { + strcat(lTerminalName , " -fa 'DejaVu Sans Mono' -fs 10 -title tinyfiledialogs -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else + { + strcpy(lTerminalName , "" ) ; + } + } + else if ( * strcpy(lTerminalName,"xterm") /*good (small without parameters)*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -fa 'DejaVu Sans Mono' -fs 10 -title tinyfiledialogs -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"terminator") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -x " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"lxterminal") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"konsole") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"kterm") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"tilix") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"xfce4-terminal") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -x " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"mate-terminal") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -x " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"Eterm") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"evilvte") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"pterm") /*good (only letters)*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( * strcpy(lTerminalName,"gnome-terminal") + && detectPresence(lTerminalName) && (lArray = getMajorMinorPatch(lTerminalName)) + && ((lArray[0]<3) || (lArray[0]==3 && lArray[1]<=6)) ) + { + strcat(lTerminalName , " --disable-factory -x " ) ; + strcat(lTerminalName , lShellName ) ; + } + else + { + strcpy(lTerminalName , "" ) ; + } + /* bad: koi rxterm guake tilda vala-terminal qterminal kgx + aterm Terminal terminology sakura lilyterm weston-terminal + roxterm termit xvt rxvt mrxvt urxvt */ + } + if ( strlen(lTerminalName) ) + { + return lTerminalName ; + } + else + { + return NULL ; + } } -static int gmessagePresent(void) +static int graphicMode(void) { - RETURN_CACHED_INT(detectPresence("gmessage")); + return getenv("DISPLAY") + || (tfd_isDarwin() && (!getenv("SSH_TTY") || getenv("DISPLAY") ) ) ; } static int xdialogPresent(void) { - RETURN_CACHED_INT(detectPresence("Xdialog")); + static int lXdialogPresent = -1 ; + if ( lXdialogPresent < 0 ) + { + lXdialogPresent = detectPresence("Xdialog") ; + } + return lXdialogPresent && graphicMode( ) ; } static int gdialogPresent(void) { - RETURN_CACHED_INT(detectPresence("gdialog")); + static int lGdialoglPresent = -1 ; + if ( lGdialoglPresent < 0 ) + { + lGdialoglPresent = detectPresence( "gdialog" ) ; + } + return lGdialoglPresent && graphicMode( ) ; } static int osascriptPresent(void) { - RETURN_CACHED_INT(detectPresence("osascript")); + static int lOsascriptPresent = -1 ; + if ( lOsascriptPresent < 0 ) + { + lOsascriptPresent = detectPresence( "osascript" ) ; + } + return lOsascriptPresent && graphicMode() && !getenv("SSH_TTY") ; } -static int qarmaPresent(void) +static int tfd_qarmaPresent(void) { - RETURN_CACHED_INT(detectPresence("qarma")); + static int lQarmaPresent = -1 ; + if ( lQarmaPresent < 0 ) + { + lQarmaPresent = detectPresence("qarma") ; + } + return lQarmaPresent && graphicMode( ) ; } -static int matedialogPresent(void) +static int tfd_matedialogPresent(void) { - RETURN_CACHED_INT(detectPresence("matedialog")); + static int lMatedialogPresent = -1 ; + if ( lMatedialogPresent < 0 ) + { + lMatedialogPresent = detectPresence("matedialog") ; + } + return lMatedialogPresent && graphicMode( ) ; } -static int zenityPresent(void) +static int tfd_shellementaryPresent(void) { - RETURN_CACHED_INT(detectPresence("zenity")); + static int lShellementaryPresent = -1 ; + if ( lShellementaryPresent < 0 ) + { + lShellementaryPresent = 0 ; /*detectPresence("shellementary"); shellementary is not ready yet */ + } + return lShellementaryPresent && graphicMode( ) ; } -static int zenity3Present(void) +static int tfd_xpropPresent(void) { - static int lZenity3Present = -1; - char lBuff[MAX_PATH_OR_CMD]; - FILE *lIn; - int lIntTmp; - - if (lZenity3Present < 0) { - lZenity3Present = 0; - if (zenityPresent()) { - lIn = popen("zenity --version", "r"); - if (fgets(lBuff, sizeof(lBuff), lIn) != NULL) { - if (atoi(lBuff) >= 3) { - lZenity3Present = 3; - lIntTmp = atoi(strtok(lBuff, ".") + 2); - if (lIntTmp >= 18) { - lZenity3Present = 5; - } else if (lIntTmp >= 10) { - lZenity3Present = 4; - } - } else if ((atoi(lBuff) == 2) && (atoi(strtok(lBuff, ".") + 2) >= 32)) { - lZenity3Present = 2; - } - if (tinyfd_verbose) printf("zenity %d\n", lZenity3Present); - } - pclose(lIn); - } - } - return lZenity3Present; + static int lXpropReady = 0 ; + static int lXpropDetected = -1 ; + char lBuff[MAX_PATH_OR_CMD] ; + FILE * lIn ; + + if ( lXpropDetected < 0 ) + { + lXpropDetected = detectPresence("xprop") ; + } + + if ( !lXpropReady && lXpropDetected ) + { /* xwayland Debian issue reported by Kay F. Jahnke and solved with his help */ + lIn = popen( "xprop -root 32x ' $0' _NET_ACTIVE_WINDOW" , "r" ) ; + if ( fgets( lBuff , sizeof( lBuff ) , lIn ) != NULL ) + { + if ( ! strstr( lBuff , "not found" ) ) + { + lXpropReady = 1 ; + } + } + pclose( lIn ) ; + } + return graphicMode() ? lXpropReady : 0 ; +} + +static int tfd_zenityPresent(void) +{ + static int lZenityPresent = -1 ; + if ( lZenityPresent < 0 ) + { + lZenityPresent = detectPresence("zenity") ; + } + return lZenityPresent && graphicMode( ) ; } -static int kdialogPresent(void) +static int tfd_yadPresent(void) { - static int lKdialogPresent = -1; - char lBuff[MAX_PATH_OR_CMD]; - FILE *lIn; - char *lDesktop; - - if (lKdialogPresent < 0) { - if (zenityPresent()) { - lDesktop = getenv("XDG_SESSION_DESKTOP"); - if (!lDesktop || (strcmp(lDesktop, "KDE") && strcmp(lDesktop, "lxqt"))) { - lKdialogPresent = 0; - return lKdialogPresent; + static int lYadPresent = -1; + if (lYadPresent < 0) + { + lYadPresent = detectPresence("yad"); + } + return lYadPresent && graphicMode(); +} + +static int tfd_zenity3Present(void) +{ + static int lZenity3Present = -1 ; + char lBuff[MAX_PATH_OR_CMD] ; + FILE * lIn ; + int lIntTmp ; + + if ( lZenity3Present < 0 ) + { + lZenity3Present = 0 ; + if ( tfd_zenityPresent() ) + { + lIn = popen( "zenity --version" , "r" ) ; + if ( fgets( lBuff , sizeof( lBuff ) , lIn ) != NULL ) + { + if ( atoi(lBuff) >= 3 ) + { + lZenity3Present = 3 ; + lIntTmp = atoi(strtok(lBuff,".")+2 ) ; + if ( lIntTmp >= 18 ) + { + lZenity3Present = 5 ; + } + else if ( lIntTmp >= 10 ) + { + lZenity3Present = 4 ; + } + } + else if ( ( atoi(lBuff) == 2 ) && ( atoi(strtok(lBuff,".")+2 ) >= 32 ) ) + { + lZenity3Present = 2 ; + } + } + pclose( lIn ) ; + } + } + return graphicMode() ? lZenity3Present : 0 ; +} + +static int tfd_kdialogPresent(void) +{ + static int lKdialogPresent = -1 ; + char lBuff[MAX_PATH_OR_CMD] ; + FILE * lIn ; + char * lDesktop; + + if ( lKdialogPresent < 0 ) + { + lDesktop = getenv("XDG_SESSION_DESKTOP"); + if ( !lDesktop || ( strcmp(lDesktop, "KDE") && strcmp(lDesktop, "lxqt") ) ) + { + if ( tfd_zenityPresent() ) + { + lKdialogPresent = 0 ; + return lKdialogPresent ; } } - lKdialogPresent = detectPresence("kdialog"); - if (lKdialogPresent && !getenv("SSH_TTY")) { - lIn = popen("kdialog --attach 2>&1", "r"); - if (fgets(lBuff, sizeof(lBuff), lIn) != NULL) { - if (!strstr("Unknown", lBuff)) { - lKdialogPresent = 2; - if (tinyfd_verbose) printf("kdialog-attach %d\n", lKdialogPresent); + lKdialogPresent = detectPresence("kdialog") ; + if ( lKdialogPresent && !getenv("SSH_TTY") ) + { + lIn = popen( "kdialog --attach 2>&1" , "r" ) ; + if ( fgets( lBuff , sizeof( lBuff ) , lIn ) != NULL ) + { + if ( ! strstr( "Unknown" , lBuff ) ) + { + lKdialogPresent = 2 ; } } - pclose(lIn); - - if (lKdialogPresent == 2) { - lKdialogPresent = 1; - lIn = popen("kdialog --passivepopup 2>&1", "r"); - if (fgets(lBuff, sizeof(lBuff), lIn) != NULL) { - if (!strstr("Unknown", lBuff)) { - lKdialogPresent = 2; - if (tinyfd_verbose) printf("kdialog-popup %d\n", lKdialogPresent); + pclose( lIn ) ; + + if (lKdialogPresent == 2) + { + lKdialogPresent = 1 ; + lIn = popen( "kdialog --passivepopup 2>&1" , "r" ) ; + if ( fgets( lBuff , sizeof( lBuff ) , lIn ) != NULL ) + { + if ( ! strstr( "Unknown" , lBuff ) ) + { + lKdialogPresent = 2 ; } } - pclose(lIn); + pclose( lIn ) ; } } } - return lKdialogPresent; + return graphicMode() ? lKdialogPresent : 0 ; } -static int python2Present(void) +static int osx9orBetter(void) { - static int lPython2Present = -1; - int i; - - if (lPython2Present < 0) { - lPython2Present = 0; - strcpy(gPython2Name, "python2"); - if (detectPresence(gPython2Name)) { - lPython2Present = 1; - } else { - for (i = 9; i >= 0; i--) { - sprintf(gPython2Name, "python2.%d", i); - if (detectPresence(gPython2Name)) { - lPython2Present = 1; - break; - } - } - } - if (tinyfd_verbose) printf("lPython2Present %d\n", lPython2Present); - if (tinyfd_verbose) printf("gPython2Name %s\n", gPython2Name); - } - return lPython2Present; + static int lOsx9orBetter = -1 ; + char lBuff[MAX_PATH_OR_CMD] ; + FILE * lIn ; + int V,v; + + if ( lOsx9orBetter < 0 ) + { + lOsx9orBetter = 0 ; + lIn = popen( "osascript -e 'set osver to system version of (system info)'" , "r" ) ; + V = 0 ; + if ( ( fgets( lBuff , sizeof( lBuff ) , lIn ) != NULL ) + && ( 2 == sscanf(lBuff, "%d.%d", &V, &v) ) ) + { + V = V * 100 + v; + if ( V >= 1009 ) + { + lOsx9orBetter = 1 ; + } + } + pclose( lIn ) ; + } + return lOsx9orBetter ; } static int python3Present(void) { - static int lPython3Present = -1; - int i; - - if (lPython3Present < 0) { - lPython3Present = 0; - strcpy(gPython3Name, "python3"); - if (detectPresence(gPython3Name)) { - lPython3Present = 1; - } else { - for (i = 9; i >= 0; i--) { - sprintf(gPython3Name, "python3.%d", i); - if (detectPresence(gPython3Name)) { - lPython3Present = 1; - break; - } - } - } - if (tinyfd_verbose) printf("lPython3Present %d\n", lPython3Present); - if (tinyfd_verbose) printf("gPython3Name %s\n", gPython3Name); - } - return lPython3Present; + static int lPython3Present = -1 ; + + if ( lPython3Present < 0 ) + { + lPython3Present = 0 ; + strcpy(gPython3Name , "python3" ) ; + if ( detectPresence(gPython3Name) ) lPython3Present = 1; + } + return lPython3Present ; } -static int tkinter2Present(void) +static int python2Present(void) { - static int lTkinter2Present = -1; - char lPythonCommand[300]; - char lPythonParams[256] = "-S -c \"try:\n\timport Tkinter;\nexcept:\n\tprint 0;\""; - - if (lTkinter2Present < 0) { - lTkinter2Present = 0; - if (python2Present()) { - sprintf(lPythonCommand, "%s %s", gPython2Name, lPythonParams); - lTkinter2Present = tryCommand(lPythonCommand); - } - if (tinyfd_verbose) printf("lTkinter2Present %d\n", lTkinter2Present); - } - return lTkinter2Present; + static int lPython2Present = -1 ; + + if ( lPython2Present < 0 ) + { + lPython2Present = 0 ; + strcpy(gPython2Name , "python2" ) ; + if ( detectPresence(gPython2Name) ) lPython2Present = 1; + } + return lPython2Present ; } static int tkinter3Present(void) { - static int lTkinter3Present = -1; - char lPythonCommand[300]; - char lPythonParams[256] = - "-S -c \"try:\n\timport tkinter;\nexcept:\n\tprint(0);\""; - - if (lTkinter3Present < 0) { - lTkinter3Present = 0; - if (python3Present()) { - sprintf(lPythonCommand, "%s %s", gPython3Name, lPythonParams); - lTkinter3Present = tryCommand(lPythonCommand); - } - if (tinyfd_verbose) printf("lTkinter3Present %d\n", lTkinter3Present); - } - return lTkinter3Present; + static int lTkinter3Present = -1 ; + char lPythonCommand[256]; + char lPythonParams[128] = + "-S -c \"try:\n\timport tkinter;\nexcept:\n\tprint(0);\""; + + if ( lTkinter3Present < 0 ) + { + lTkinter3Present = 0 ; + if ( python3Present() ) + { + sprintf( lPythonCommand , "%s %s" , gPython3Name , lPythonParams ) ; + lTkinter3Present = tryCommand(lPythonCommand) ; + } + } + return lTkinter3Present && graphicMode() && !(tfd_isDarwin() && getenv("SSH_TTY") ); } - -int tinyfd_messageBox( - char const *const aTitle, /* NULL or "" */ - char const *const aMessage, /* NULL or "" may contain \n and \t */ - char const *const aDialogType, /* "ok" "okcancel" */ - char const *const aIconType, /* "info" "warning" "error" "question" */ - int const aDefaultButton) /* 0 for cancel, 1 for ok */ +static int tkinter2Present(void) { - char lBuff[MAX_PATH_OR_CMD]; - char *lDialogString = NULL; - char *lpDialogString; - FILE *lIn; - int lResult; - char lChar; - struct termios infoOri; - struct termios info; - size_t lTitleLen; - size_t lMessageLen; - - lBuff[0] = '\0'; - - lTitleLen = aTitle ? strlen(aTitle) : 0; - lMessageLen = aMessage ? strlen(aMessage) : 0; - lDialogString = (char *) malloc(MAX_PATH_OR_CMD + lTitleLen + lMessageLen); - - if (osascriptPresent()) { - strcpy(lDialogString, "osascript "); - strcat(lDialogString, " -e 'try' -e 'set {vButton} to {button returned} of ( display dialog \""); - if (aMessage && strlen(aMessage)) { - strcat(lDialogString, aMessage); - } - strcat(lDialogString, "\" "); - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, "with title \""); - strcat(lDialogString, aTitle); - strcat(lDialogString, "\" "); - } - strcat(lDialogString, "with icon "); - if (aIconType && !strcmp("error", aIconType)) { - strcat(lDialogString, "stop "); - } else if (aIconType && !strcmp("warning", aIconType)) { - strcat(lDialogString, "caution "); - } else { /* question or info */ - strcat(lDialogString, "note "); - } - if (aDialogType && !strcmp("okcancel", aDialogType)) { - if (!aDefaultButton) { - strcat(lDialogString, "default button \"Cancel\" "); - } - } else { - strcat(lDialogString, "buttons {\"OK\"} "); - strcat(lDialogString, "default button \"OK\" "); - } - strcat(lDialogString, ")' "); - - strcat(lDialogString, -"-e 'if vButton is \"Yes\" then' -e 'return 1'\ - -e 'else if vButton is \"OK\" then' -e 'return 1'\ - -e 'else if vButton is \"No\" then' -e 'return 2'\ - -e 'else' -e 'return 0' -e 'end if' "); - - strcat(lDialogString, "-e 'on error number -128' "); - strcat(lDialogString, "-e '0' "); - - strcat(lDialogString, "-e 'end try'"); - } else if (kdialogPresent()) { - strcpy(lDialogString, "kdialog"); - strcat(lDialogString, " --"); - if (aDialogType && !strcmp("okcancel", aDialogType)) { - if (aIconType && (!strcmp("warning", aIconType) || !strcmp("error", aIconType))) { - strcat(lDialogString, "warning"); - } - strcat(lDialogString, "yesno"); - } else if (aIconType && !strcmp("error", aIconType)) { - strcat(lDialogString, "error"); - } else if (aIconType && !strcmp("warning", aIconType)) { - strcat(lDialogString, "sorry"); - } else { - strcat(lDialogString, "msgbox"); - } - strcat(lDialogString, " \""); - if (aMessage) { - strcat(lDialogString, aMessage); - } - strcat(lDialogString, "\""); - if (aDialogType && !strcmp("okcancel", aDialogType)) { - strcat(lDialogString, " --yes-label Ok --no-label Cancel"); - } - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, " --title \""); - strcat(lDialogString, aTitle); - strcat(lDialogString, "\""); - } - - strcat(lDialogString, ";if [ $? = 0 ];then echo 1;else echo 0;fi"); - } else if (zenityPresent() || matedialogPresent() || qarmaPresent()) { - if (zenityPresent()) { - strcpy(lDialogString, "szAnswer=$(zenity"); - } else if (matedialogPresent()) { - strcpy(lDialogString, "szAnswer=$(matedialog"); - } else { - strcpy(lDialogString, "szAnswer=$(qarma"); - } - strcat(lDialogString, " --"); - - if (aDialogType && !strcmp("okcancel", aDialogType)) { - strcat(lDialogString, "question --ok-label=Ok --cancel-label=Cancel"); - } else if (aIconType && !strcmp("error", aIconType)) { - strcat(lDialogString, "error"); - } else if (aIconType && !strcmp("warning", aIconType)) { - strcat(lDialogString, "warning"); - } else { - strcat(lDialogString, "info"); - } - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, " --title=\""); - strcat(lDialogString, aTitle); - strcat(lDialogString, "\""); - } - if (aMessage && strlen(aMessage)) { - strcat(lDialogString, " --no-wrap --text=\""); - strcat(lDialogString, aMessage); - strcat(lDialogString, "\""); - } - if ((zenity3Present() >= 3) || (!zenityPresent() && qarmaPresent())) { - strcat(lDialogString, " --icon-name=dialog-"); - if (aIconType && (!strcmp("question", aIconType) - || !strcmp("error", aIconType) - || !strcmp("warning", aIconType))) { - strcat(lDialogString, aIconType); - } else { - strcat(lDialogString, "information"); - } - } - - if (tinyfd_silent) strcat(lDialogString, " 2>/dev/null "); - - strcat(lDialogString, ");if [ $? = 0 ];then echo 1;else echo 0;fi"); - } else if (!gxmessagePresent() && !gmessagePresent() && !gdialogPresent() && !xdialogPresent() && tkinter2Present()) { - strcpy(lDialogString, gPython2Name); - strcat(lDialogString, " -S -c \"import Tkinter,tkMessageBox;root=Tkinter.Tk();root.withdraw();"); - - strcat(lDialogString, "res=tkMessageBox."); - if (aDialogType && !strcmp("okcancel", aDialogType)) { - strcat(lDialogString, "askokcancel("); - if (aDefaultButton) { - strcat(lDialogString, "default=tkMessageBox.OK,"); - } else { - strcat(lDialogString, "default=tkMessageBox.CANCEL,"); - } - } else { - strcat(lDialogString, "showinfo("); - } - - strcat(lDialogString, "icon='"); - if (aIconType && (!strcmp("question", aIconType) - || !strcmp("error", aIconType) - || !strcmp("warning", aIconType))) { - strcat(lDialogString, aIconType); - } else { - strcat(lDialogString, "info"); - } - - strcat(lDialogString, "',"); - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, "title='"); - strcat(lDialogString, aTitle); - strcat(lDialogString, "',"); - } - if (aMessage && strlen(aMessage)) { - strcat(lDialogString, "message='"); - lpDialogString = lDialogString + strlen(lDialogString); - replaceSubStr(aMessage, "\n", "\\n", lpDialogString); - strcat(lDialogString, "'"); - } - - strcat(lDialogString, ");\n\ -if res is False :\n\tprint 0\n\ -else :\n\tprint 1\n\""); - } else if (!gxmessagePresent() && !gmessagePresent() && !gdialogPresent() && !xdialogPresent() && tkinter3Present()) { - strcpy(lDialogString, gPython3Name); - strcat(lDialogString, - " -S -c \"import tkinter;from tkinter import messagebox;root=tkinter.Tk();root.withdraw();"); - - strcat(lDialogString, "res=messagebox."); - if (aDialogType && !strcmp("okcancel", aDialogType)) { - strcat(lDialogString, "askokcancel("); - if (aDefaultButton) { - strcat(lDialogString, "default=messagebox.OK,"); - } else { - strcat(lDialogString, "default=messagebox.CANCEL,"); - } - } else { - strcat(lDialogString, "showinfo("); - } - - strcat(lDialogString, "icon='"); - if (aIconType && (!strcmp("question", aIconType) - || !strcmp("error", aIconType) - || !strcmp("warning", aIconType))) { - strcat(lDialogString, aIconType); - } else { - strcat(lDialogString, "info"); - } - - strcat(lDialogString, "',"); - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, "title='"); - strcat(lDialogString, aTitle); - strcat(lDialogString, "',"); - } - if (aMessage && strlen(aMessage)) { - strcat(lDialogString, "message='"); - lpDialogString = lDialogString + strlen(lDialogString); - replaceSubStr(aMessage, "\n", "\\n", lpDialogString); - strcat(lDialogString, "'"); - } - - strcat(lDialogString, ");\n\ -if res is False :\n\tprint(0)\n\ -else :\n\tprint(1)\n\""); - } else if (gxmessagePresent() || gmessagePresent() || (!gdialogPresent() && !xdialogPresent() && xmessagePresent())) { - if (gxmessagePresent()) { - strcpy(lDialogString, "gxmessage"); - } else if (gmessagePresent()) { - strcpy(lDialogString, "gmessage"); - } else { - strcpy(lDialogString, "xmessage"); - } - - if (aDialogType && !strcmp("okcancel", aDialogType)) { - strcat(lDialogString, " -buttons Ok:1,Cancel:0"); - switch (aDefaultButton) { - case 1: strcat(lDialogString, " -default Ok"); break; - case 0: strcat(lDialogString, " -default Cancel"); break; - } - } else { - strcat(lDialogString, " -buttons Ok:1"); - strcat(lDialogString, " -default Ok"); - } - - strcat(lDialogString, " -center \""); - if (aMessage && strlen(aMessage)) { - strcat(lDialogString, aMessage); - } - strcat(lDialogString, "\""); - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, " -title \""); - strcat(lDialogString, aTitle); - strcat(lDialogString, "\""); - } - strcat(lDialogString, " ; echo $? "); - } else if (xdialogPresent() || gdialogPresent()) { - if (gdialogPresent()) { - strcpy(lDialogString, "(gdialog "); - } else if (xdialogPresent()) { - strcpy(lDialogString, "(Xdialog "); - } - - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, "--title \""); - strcat(lDialogString, aTitle); - strcat(lDialogString, "\" "); - } - - if (aDialogType && !strcmp("okcancel", aDialogType)) { - if (!aDefaultButton) { - strcat(lDialogString, "--defaultno "); - } - strcat(lDialogString, "--yes-label \"Ok\" --no-label \"Cancel\" --yesno "); - } else { - strcat(lDialogString, "--msgbox "); - - } - strcat(lDialogString, "\""); - if (aMessage && strlen(aMessage)) { - strcat(lDialogString, aMessage); - } - strcat(lDialogString, "\" "); - - strcat(lDialogString, "10 60 ) 2>&1;if [ $? = 0 ];then echo 1;else echo 0;fi"); - } else if (!isTerminalRunning() && terminalName()) { - strcpy(lDialogString, terminalName()); - strcat(lDialogString, "'"); - if (!gWarningDisplayed) { - gWarningDisplayed = 1; - strcat(lDialogString, "echo \""); - strcat(lDialogString, gTitle); - strcat(lDialogString, "\";"); - strcat(lDialogString, "echo \""); - strcat(lDialogString, tinyfd_needs); - strcat(lDialogString, "\";echo;echo;"); - } - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, "echo \""); - strcat(lDialogString, aTitle); - strcat(lDialogString, "\";echo;"); - } - if (aMessage && strlen(aMessage)) { - strcat(lDialogString, "echo \""); - strcat(lDialogString, aMessage); - strcat(lDialogString, "\"; "); - } - if (aDialogType && !strcmp("okcancel", aDialogType)) { - strcat(lDialogString, "echo -n \"[O]kay/[C]ancel: \"; "); - strcat(lDialogString, "stty sane -echo;"); - strcat(lDialogString, "answer=$( while ! head -c 1 | grep -i [oc];do true ;done);"); - strcat(lDialogString, "if echo \"$answer\" | grep -iq \"^o\";then\n"); - strcat(lDialogString, "\techo 1\nelse\n\techo 0\nfi"); - } else { - strcat(lDialogString, "echo -n \"press enter to continue \"; "); - strcat(lDialogString, "stty sane -echo;"); - strcat(lDialogString, "answer=$( while ! head -c 1;do true ;done);echo 1"); - } - strcat(lDialogString, " >/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); - } else { - if (!gWarningDisplayed) { - gWarningDisplayed = 1; - printf("\n\n%s\n", gTitle); - printf("%s\n\n", tinyfd_needs); - } - if (aTitle && strlen(aTitle)) { - printf("\n%s\n", aTitle); - } - - tcgetattr(0, &infoOri); - tcgetattr(0, &info); - info.c_lflag &= ~ICANON; - info.c_cc[VMIN] = 1; - info.c_cc[VTIME] = 0; - tcsetattr(0, TCSANOW, &info); - if (aDialogType && !strcmp("okcancel", aDialogType)) { - do { - if (aMessage && strlen(aMessage)) { - printf("\n%s\n", aMessage); - } - printf("[O]kay/[C]ancel: "); fflush(stdout); - lChar = tolower(getchar()); - printf("\n\n"); - } while (lChar != 'o' && lChar != 'c'); - lResult = lChar == 'o' ? 1 : 0; - } else { - if (aMessage && strlen(aMessage)) { - printf("\n%s\n\n", aMessage); - } - printf("press enter to continue "); fflush(stdout); - getchar(); - printf("\n\n"); - lResult = 1; - } - tcsetattr(0, TCSANOW, &infoOri); - free(lDialogString); - return lResult; - } - - if (tinyfd_verbose) printf("lDialogString: %s\n", lDialogString); - - if (!(lIn = popen(lDialogString, "r"))) { - free(lDialogString); - return 0; - } - while (fgets(lBuff, sizeof(lBuff), lIn) != NULL) { - } - - pclose(lIn); - - /* printf( "lBuff: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ - if (lBuff[strlen(lBuff) - 1] == '\n') { - lBuff[strlen(lBuff) - 1] = '\0'; - } - /* printf( "lBuff1: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ - - lResult = !strcmp(lBuff, "2") ? 2 : !strcmp(lBuff, "1") ? 1 : 0; - - /* printf( "lResult: %d\n" , lResult ) ; */ - free(lDialogString); - return lResult; + static int lTkinter2Present = -1 ; + char lPythonCommand[256]; + char lPythonParams[128] = + "-S -c \"try:\n\timport Tkinter;\nexcept:\n\tprint 0;\""; + + if ( lTkinter2Present < 0 ) + { + lTkinter2Present = 0 ; + if ( python2Present() ) + { + sprintf( lPythonCommand , "%s %s" , gPython2Name , lPythonParams ) ; + lTkinter2Present = tryCommand(lPythonCommand) ; + } + } + return lTkinter2Present && graphicMode() && !(tfd_isDarwin() && getenv("SSH_TTY") ); } -/* returns NULL on cancel */ -static char const *selectFolderUsingInputBox(char const *const aTitle) /* NULL or "" */ +char * tinyfd_selectFolderDialog( + char const * aTitle , /* "" */ + char const * aDefaultPath ) /* "" */ { - static char lBuff[MAX_PATH_OR_CMD]; - char *lDialogString = NULL; - FILE *lIn; - int lResult; - int lWasBasicXterm = 0; - struct termios oldt; - struct termios newt; - char *lEOF; - size_t lTitleLen; - - lBuff[0] = '\0'; - - lTitleLen = aTitle ? strlen(aTitle) : 0; - lDialogString = (char *) malloc(MAX_PATH_OR_CMD + lTitleLen); - - if (gxmessagePresent() || gmessagePresent()) { - if (gxmessagePresent()) { - strcpy(lDialogString, "szAnswer=$(gxmessage -buttons Ok:1,Cancel:0 -center \""); - } else { - strcpy(lDialogString, "szAnswer=$(gmessage -buttons Ok:1,Cancel:0 -center \""); - } - - strcat(lDialogString, "\""); - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, " -title \""); - strcat(lDialogString, aTitle); - strcat(lDialogString, "\" "); - } - strcat(lDialogString, " -entrytext \""); - strcat(lDialogString, "\""); - strcat(lDialogString, ");echo $?$szAnswer"); - } else if (gdialogPresent() || xdialogPresent()) { - if (gdialogPresent()) { - strcpy(lDialogString, "(gdialog "); - } else if (xdialogPresent()) { - strcpy(lDialogString, "(Xdialog "); - } - - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, "--title \""); - strcat(lDialogString, aTitle); - strcat(lDialogString, "\" "); - } - - strcat(lDialogString, "--inputbox"); - strcat(lDialogString, " \"\" 10 60 "); - strcat(lDialogString, ") 2>/tmp/tinyfd.txt;\ -if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\ -tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes"); - } else if (!isTerminalRunning() && terminalName()) { - lWasBasicXterm = 1; - strcpy(lDialogString, terminalName()); - strcat(lDialogString, "'"); - if (!gWarningDisplayed) { - gWarningDisplayed = 1; - tinyfd_messageBox(gTitle, tinyfd_needs, "ok", "warning", 0); - } - if (aTitle && strlen(aTitle)) { - strcat(lDialogString, "echo \""); - strcat(lDialogString, aTitle); - strcat(lDialogString, "\";echo;"); - } - - strcat(lDialogString, "echo \""); - strcat(lDialogString, "\";read "); - strcat(lDialogString, "-s "); - strcat(lDialogString, "-p \""); - strcat(lDialogString, "(esc+enter to cancel): \" ANSWER "); - strcat(lDialogString, ";echo 1$ANSWER >/tmp/tinyfd.txt';"); - strcat(lDialogString, "cat -v /tmp/tinyfd.txt"); - } else if (!gWarningDisplayed && !isTerminalRunning() && !terminalName()) { - gWarningDisplayed = 1; - tinyfd_messageBox(gTitle, tinyfd_needs, "ok", "warning", 0); - return NULL; - } else { - if (!gWarningDisplayed) { - gWarningDisplayed = 1; - tinyfd_messageBox(gTitle, tinyfd_needs, "ok", "warning", 0); - } - if (aTitle && strlen(aTitle)) { - printf("\n%s\n", aTitle); - } - printf("(esc+enter to cancel): "); fflush(stdout); - tcgetattr(STDIN_FILENO, &oldt); - newt = oldt; - newt.c_lflag &= ~ECHO; - tcsetattr(STDIN_FILENO, TCSANOW, &newt); - - lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin); - /* printf("lbuff<%c><%d>\n",lBuff[0],lBuff[0]); */ - if (!lEOF || (lBuff[0] == '\0')) { - free(lDialogString); - return NULL; - } - - if (lBuff[0] == '\n') { - lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin); - /* printf("lbuff<%c><%d>\n",lBuff[0],lBuff[0]); */ - if (!lEOF || (lBuff[0] == '\0')) { - free(lDialogString); - return NULL; - } - } - - tcsetattr(STDIN_FILENO, TCSANOW, &oldt); - printf("\n"); - if (strchr(lBuff, 27)) { - free(lDialogString); - return NULL; - } - if (lBuff[strlen(lBuff) - 1] == '\n') { - lBuff[strlen(lBuff) - 1] = '\0'; - } - free(lDialogString); - return lBuff; - } - - if (tinyfd_verbose) printf("lDialogString: %s\n", lDialogString); - lIn = popen(lDialogString, "r"); - if (!lIn) { - remove("/tmp/tinyfd.txt"); - remove("/tmp/tinyfd0.txt"); - free(lDialogString); - return NULL; - } - while (fgets(lBuff, sizeof(lBuff), lIn) != NULL) { + static char lBuff[MAX_PATH_OR_CMD] ; + static char lLastDirectory[MAX_PATH_OR_CMD] = "$PWD"; + + char lDialogString[MAX_PATH_OR_CMD] ; + FILE * lIn ; + int lWasGraphicDialog = 0 ; + int lWasXterm = 0 ; + lBuff[0]='\0'; + + if (tfd_quoteDetected(aTitle)) return tinyfd_selectFolderDialog("INVALID TITLE WITH QUOTES", aDefaultPath); + if (tfd_quoteDetected(aDefaultPath)) return tinyfd_selectFolderDialog(aTitle, "INVALID DEFAULT_PATH WITH QUOTES"); + + char *realPath = NULL; + + if (aDefaultPath && strlen(aDefaultPath)) realPath = realpath(aDefaultPath, NULL); + + if ( osascriptPresent( )) + { + strcpy( lDialogString , "osascript "); + if ( ! osx9orBetter() ) strcat( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); + strcat( lDialogString , " -e 'try' -e 'POSIX path of ( choose folder "); + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "with prompt \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + if ( realPath && strlen(realPath) ) + { + strcat(lDialogString, "default location \"") ; + strcat(lDialogString, realPath ) ; + strcat(lDialogString , "\" " ) ; + } + strcat( lDialogString , ")' " ) ; + strcat(lDialogString, "-e 'on error number -128' " ) ; + strcat(lDialogString, "-e 'end try'") ; + if ( ! osx9orBetter() ) strcat( lDialogString, " -e 'end tell'") ; + } + else if ( tfd_kdialogPresent() ) + { + strcpy( lDialogString , "kdialog" ) ; + if ( (tfd_kdialogPresent() == 2) && tfd_xpropPresent() ) + { + strcat(lDialogString, " --attach=$(xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2)"); /* contribution: Paul Rouget */ + } + strcat( lDialogString , " --getexistingdirectory " ) ; + + if ( realPath && strlen(realPath) ) + { + if ( realPath[0] != '/' ) + { + strcat(lDialogString, lLastDirectory) ; + strcat(lDialogString , "/" ) ; + } + strcat(lDialogString, "\"") ; + strcat(lDialogString, realPath ) ; + strcat(lDialogString , "\"" ) ; + } + else + { + strcat(lDialogString, lLastDirectory) ; + strcat(lDialogString , "/" ) ; + } + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + } + else if ( tfd_zenityPresent() || tfd_matedialogPresent() || tfd_shellementaryPresent() || tfd_qarmaPresent() ) + { + if ( tfd_zenityPresent() ) + { + strcpy( lDialogString , "zenity" ) ; + if ( (tfd_zenity3Present() >= 4) && !getenv("SSH_TTY") && tfd_xpropPresent() ) + { + strcat( lDialogString, " --attach=$(sleep .01;xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2)"); /* contribution: Paul Rouget */ + } + } + else if ( tfd_matedialogPresent() ) + { + strcpy( lDialogString , "matedialog" ) ; + } + else if ( tfd_shellementaryPresent() ) + { + strcpy( lDialogString , "shellementary" ) ; + } + else + { + strcpy( lDialogString , "qarma" ) ; + if ( !getenv("SSH_TTY") && tfd_xpropPresent() ) + { + strcat(lDialogString, " --attach=$(xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2)"); /* contribution: Paul Rouget */ + } + } + strcat( lDialogString , " --file-selection --directory" ) ; + + strcat(lDialogString, " --title=\"") ; + if (aTitle && strlen(aTitle)) strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + + if ( realPath && strlen(realPath) ) + { + strcat(lDialogString, " --filename=\"") ; + strcat(lDialogString, realPath) ; + strcat(lDialogString, "\"") ; + } + strcat( lDialogString , " 2>/dev/null "); + } + else if (tfd_yadPresent()) + { + strcpy(lDialogString, "yad --file --directory"); + if (aTitle && strlen(aTitle)) + { + strcat(lDialogString, " --title=\""); + strcat(lDialogString, aTitle); + strcat(lDialogString, "\""); + } + if (realPath && strlen(realPath)) + { + strcat(lDialogString, " --filename=\""); + strcat(lDialogString, realPath); + strcat(lDialogString, "\""); + } + strcat(lDialogString, " 2>/dev/null "); + } + else if ( !xdialogPresent() && tkinter3Present( ) ) + { + strcpy( lDialogString , gPython3Name ) ; + strcat( lDialogString , + " -S -c \"import tkinter;from tkinter import filedialog;root=tkinter.Tk();root.withdraw();"); + strcat( lDialogString , "res=filedialog.askdirectory("); + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "title='") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "',") ; + } + if ( realPath && strlen(realPath) ) + { + strcat(lDialogString, "initialdir='") ; + strcat(lDialogString, realPath ) ; + strcat(lDialogString , "'" ) ; + } + strcat( lDialogString, ");\nif not isinstance(res, tuple):\n\tprint(res)\n\"" ) ; + } + else if ( !xdialogPresent() && tkinter2Present( ) ) + { + strcpy( lDialogString , "export PYTHONIOENCODING=utf-8;" ) ; + strcat( lDialogString , gPython2Name ) ; + if ( ! isTerminalRunning( ) && tfd_isDarwin( ) ) + { + strcat( lDialogString , " -i" ) ; /* for osx without console */ + } + strcat( lDialogString , +" -S -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();"); + + if ( tfd_isDarwin( ) ) + { + strcat( lDialogString , +"import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \ +frontmost of process \\\"Python\\\" to true' ''');"); + } + + strcat( lDialogString , "print tkFileDialog.askdirectory("); + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "title='") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "',") ; + } + if ( realPath && strlen(realPath) ) + { + strcat(lDialogString, "initialdir='") ; + strcat(lDialogString, realPath ) ; + strcat(lDialogString , "'" ) ; + } + strcat( lDialogString , ")\"" ) ; + } + else if ( xdialogPresent() ) + { + if ( xdialogPresent( ) ) + { + lWasGraphicDialog = 1 ; + strcpy( lDialogString , "(Xdialog " ) ; + } + else if ( isTerminalRunning( ) ) + { + strcpy( lDialogString , "(dialog " ) ; + } + else + { + lWasXterm = 1 ; + strcpy( lDialogString , terminalName() ) ; + strcat( lDialogString , "'(" ) ; + strcat( lDialogString , " " ) ; + } + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + if ( !xdialogPresent() && !gdialogPresent() ) + { + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, + "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; + strcat(lDialogString, "\" ") ; + } + + strcat( lDialogString , "--dselect \"" ) ; + if ( realPath && strlen(realPath) ) + { + strcat(lDialogString, realPath) ; + ensureFinalSlash(lDialogString); + } + else + { + strcat(lDialogString, "./") ; + } + + if ( lWasGraphicDialog ) + { + strcat(lDialogString, "\" 0 60 ) 2>&1 ") ; + } + else + { + strcat(lDialogString, "\" 0 60 >/dev/tty) ") ; + if ( lWasXterm ) + { + strcat( lDialogString , + "2>/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); + } + else + { + strcat(lDialogString, "2>&1 ; clear >/dev/tty") ; + } + } + } + else + { + free((void *)realPath); + return NULL ; + } + free((void *)realPath); + if ( ! ( lIn = popen( lDialogString , "r" ) ) ) + { + return NULL ; + } + while ( fgets( lBuff , sizeof( lBuff ) , lIn ) != NULL ) + {} + pclose( lIn ) ; + if ( strlen( lBuff ) && lBuff[strlen( lBuff ) -1] == '\n' ) + { + lBuff[strlen( lBuff ) -1] = '\0' ; + } + /* printf( "lBuff: %s\n" , lBuff ) ; */ + if ( ! strlen( lBuff ) || ! dirExists( lBuff ) ) + { + return NULL ; } - pclose(lIn); + getPathWithoutFinalSlash( lLastDirectory , lBuff ) ; - remove("/tmp/tinyfd.txt"); - remove("/tmp/tinyfd0.txt"); - - /* printf( "len Buff: %lu\n" , strlen(lBuff) ) ; */ - /* printf( "lBuff0: %s\n" , lBuff ) ; */ - if (lBuff[strlen(lBuff) - 1] == '\n') { - lBuff[strlen(lBuff) - 1] = '\0'; - } - /* printf( "lBuff1: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ - if (lWasBasicXterm) { - if (strstr(lBuff, "^[")) { /* esc was pressed */ - free(lDialogString); - return NULL; - } - } - - lResult = strncmp(lBuff, "1", 1) ? 0 : 1; - /* printf( "lResult: %d \n" , lResult ) ; */ - if (!lResult) { - free(lDialogString); - return NULL; - } - /* printf( "lBuff+1: %s\n" , lBuff+1 ) ; */ - free(lDialogString); - - return lBuff + 1; -} - - -char const *tinyfd_selectFolderDialog(char const *const aTitle) -{ - static char resultBuff[MAX_PATH_OR_CMD]; - char dialogString[MAX_PATH_OR_CMD]; - char const *p; - resultBuff[0] = '\0'; - - if (osascriptPresent()) { - strcpy(dialogString, "osascript "); - strcat(dialogString, " -e 'try' -e 'POSIX path of ( choose folder "); - if (aTitle && strlen(aTitle)) { - strcat(dialogString, "with prompt \""); - strcat(dialogString, aTitle); - strcat(dialogString, "\" "); - } - strcat(dialogString, ")' "); - strcat(dialogString, "-e 'on error number -128' "); - strcat(dialogString, "-e 'end try'"); - } else if (kdialogPresent()) { - strcpy(dialogString, "kdialog"); - strcat(dialogString, " --getexistingdirectory "); - - strcat(dialogString, "$PWD/"); - - if (aTitle && strlen(aTitle)) { - strcat(dialogString, " --title \""); - strcat(dialogString, aTitle); - strcat(dialogString, "\""); - } - } else if (zenityPresent() || matedialogPresent() || qarmaPresent()) { - if (zenityPresent()) { - strcpy(dialogString, "zenity"); - } else if (matedialogPresent()) { - strcpy(dialogString, "matedialog"); - } else { - strcpy(dialogString, "qarma"); - } - strcat(dialogString, " --file-selection --directory"); - - if (aTitle && strlen(aTitle)) { - strcat(dialogString, " --title=\""); - strcat(dialogString, aTitle); - strcat(dialogString, "\""); - } - if (tinyfd_silent) strcat(dialogString, " 2>/dev/null "); - } else if (xdialogPresent()) { - strcpy(dialogString, "(Xdialog "); - if (aTitle && strlen(aTitle)) { - strcat(dialogString, "--title \""); - strcat(dialogString, aTitle); - strcat(dialogString, "\" "); - } - strcat(dialogString, "--dselect \"./\" 0 60 ) 2>&1 "); - } else if (tkinter2Present()) { - strcpy(dialogString, gPython2Name); - strcat(dialogString, " -S -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();"); - strcat(dialogString, "print tkFileDialog.askdirectory("); - if (aTitle && strlen(aTitle)) { - strcat(dialogString, "title='"); - strcat(dialogString, aTitle); - strcat(dialogString, "',"); - } - strcat(dialogString, ")\""); - } else if (tkinter3Present()) { - strcpy(dialogString, gPython3Name); - strcat(dialogString, - " -S -c \"import tkinter;from tkinter import filedialog;root=tkinter.Tk();root.withdraw();"); - strcat(dialogString, "print(filedialog.askdirectory("); - if (aTitle && strlen(aTitle)) { - strcat(dialogString, "title='"); - strcat(dialogString, aTitle); - strcat(dialogString, "',"); - } - strcat(dialogString, ") )\""); - } else { - p = selectFolderUsingInputBox(aTitle ? aTitle : "Select folder"); - if (!dirExists(p)) { - return NULL; - } - return p; - } - if (tinyfd_verbose) printf("dialogString: %s\n", dialogString); - FILE *pin = popen(dialogString, "r"); - if (!pin) { - return NULL; - } - while (fgets(resultBuff, sizeof(resultBuff), pin) != NULL) {} - pclose(pin); - if (resultBuff[strlen(resultBuff) - 1] == '\n') { - resultBuff[strlen(resultBuff) - 1] = '\0'; - } - if (!dirExists(resultBuff)) { - return NULL; - } - return resultBuff; + return lBuff ; } #endif /* _WIN32 */ - #ifdef _MSC_VER #pragma warning(default:4996) #pragma warning(default:4100) #pragma warning(default:4706) #endif -#endif /* USE_TINYFILEDIALOGS */ +#endif // USE_TINYFILEDIALOGS diff --git a/ext/tinyfiledialogs/tinyfiledialogs.h b/ext/tinyfiledialogs/tinyfiledialogs.h index bb294da2e5..9c2014a443 100644 --- a/ext/tinyfiledialogs/tinyfiledialogs.h +++ b/ext/tinyfiledialogs/tinyfiledialogs.h @@ -1,26 +1,33 @@ /* -Note: This file is a heavily stripped-down version of Tinyfiledialogs, customized for Julius. +Note: This file is a heavily stripped-down version of Tinyfiledialogs, customized for Augustus. If you are interested in Tinyfiledialogs, please download its original version from the links below. -Tinyfiledialogs: -Copyright (c) 2014 - 2018 Guillaume Vareille http://ysengrin.com -http://tinyfiledialogs.sourceforge.net +SPDX-License-Identifier: Zlib +Copyright (c) 2014 - 2024 Guillaume Vareille http://ysengrin.com -Thanks for contributions, bug corrections & thorough testing to: -- Don Heyse http://ldglite.sf.net for bug corrections & thorough testing! -- Paul Rouget +********* TINY FILE DIALOGS OFFICIAL WEBSITE IS ON SOURCEFORGE ********* + _________ + / \ tinyfiledialogs.c v3.18.1 [May 2, 2024] zlib licence + |tiny file| Unique code file created [November 9, 2014] + | dialogs | + \____ ___/ http://tinyfiledialogs.sourceforge.net + \| git clone http://git.code.sf.net/p/tinyfiledialogs/code tinyfd + ____________________________________________ + | | + | email: tinyfiledialogs at ysengrin.com | + |____________________________________________| -- License - +If you like tinyfiledialogs, please upvote my stackoverflow answer +https://stackoverflow.com/a/47651444 +- License - This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be @@ -37,33 +44,9 @@ misrepresented as being the original software. #define USE_TINYFILEDIALOGS 1 #endif -#ifdef USE_TINYFILEDIALOGS - -#ifdef __cplusplus -extern "C" { -#endif - -extern char const tinyfd_needs[]; /* info about requirements */ -extern int tinyfd_verbose; /* 0 (default) or 1 : on unix, prints the command line calls */ -extern int tinyfd_silent; /* 1 (default) or 0 : on unix, - hide errors and warnings from called dialog*/ - -int tinyfd_messageBox( - char const * const aTitle , /* NULL or "" */ - char const * const aMessage , /* NULL or "" may contain \n \t */ - char const * const aDialogType , /* "ok" "okcancel" */ - char const * const aIconType , /* "info" "warning" "error" "question" */ - int const aDefaultButton ) ; - /* 0 for cancel, 1 for ok */ - -char const * tinyfd_selectFolderDialog( - char const * const aTitle); /* NULL or "" */ +char * tinyfd_selectFolderDialog( + char const * aTitle, /* NULL or "" */ + char const * aDefaultPath); /* NULL or "" */ /* returns NULL on cancel */ -#ifdef __cplusplus -} -#endif - -#endif /* USE_TINYFILEDIALOGS */ - #endif /* TINYFILEDIALOGS_H */ diff --git a/ext/zip/zip.c b/ext/zip/zip.c index dac8e2577f..13eacd8d87 100644 --- a/ext/zip/zip.c +++ b/ext/zip/zip.c @@ -448,7 +448,7 @@ static ssize_t zip_entry_mark(struct zip_t *zip, mz_zip_archive_file_stat file_stat; mz_uint64 d_pos = UINT64_MAX; for (i = 0; i < n; ++i) { - if ((err = zip_entry_openbyindex(zip, i))) { + if ((err = zip_entry_openbyindex(zip, i)) != 0) { return (ssize_t)err; } @@ -505,7 +505,7 @@ static ssize_t zip_entry_markbyindex(struct zip_t *zip, mz_zip_archive_file_stat file_stat; mz_uint64 d_pos = UINT64_MAX; for (i = 0; i < n; ++i) { - if ((err = zip_entry_openbyindex(zip, i))) { + if ((err = zip_entry_openbyindex(zip, i)) != 0) { return (ssize_t)err; } @@ -1225,7 +1225,7 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); if (!mz_zip_writer_create_local_dir_header( - pzip, zip->entry.header, entrylen, (mz_uint16)extra_size, 0, 0, 0, + pzip, zip->entry.header, (mz_uint16)entrylen, (mz_uint16)extra_size, 0, 0, 0, zip->entry.method, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 | MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR, @@ -1324,10 +1324,10 @@ int zip_entry_openbyindex(struct zip_t *zip, size_t index) { return ZIP_EINVIDX; } - if (!(pHeader = &MZ_ZIP_ARRAY_ELEMENT( + if ((pHeader = &MZ_ZIP_ARRAY_ELEMENT( &pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, - mz_uint32, index)))) { + mz_uint32, (mz_uint)index))) == 0) { // cannot find header in central directory return ZIP_ENOHDR; } @@ -1617,7 +1617,7 @@ int zip_entry_fwrite(struct zip_t *zip, const char *filename) { zip->entry.m_time = file_stat.st_mtime; - if (!(stream = MZ_FOPEN(filename, "rb"))) { + if ((stream = MZ_FOPEN(filename, "rb")) == 0) { // Cannot open filename return ZIP_EOPNFILE; } @@ -1922,7 +1922,7 @@ ssize_t zip_stream_copy(struct zip_t *zip, void **buf, size_t *bufsize) { *bufsize = n; } - *buf = calloc(sizeof(unsigned char), n); + *buf = calloc(n, sizeof(unsigned char)); memcpy(*buf, zip->archive.m_pState->m_pMem, n); return (ssize_t)n; diff --git a/ext/zip/zip.h b/ext/zip/zip.h index 9bd2c74f7d..5a42573613 100644 --- a/ext/zip/zip.h +++ b/ext/zip/zip.h @@ -130,7 +130,7 @@ extern ZIP_EXPORT struct zip_t *zip_open(const char *zipname, int level, /** * Opens zip archive with compression level using the given mode. - * The function additionally returns @param errnum - + * The function additionally returns errnum * * @param zipname zip archive file name. * @param level compression level (0-9 are the standard zlib-style levels). @@ -162,7 +162,7 @@ extern ZIP_EXPORT struct zip_t *zip_cstream_open(FILE *cstream, int level, char mode); /** * Opens zip archive from existing FILE stream with compression level using the given mode. - * The function additionally returns @param errnum - + * The function additionally returns errnum * The stream will not be closed when calling zip_close. * * @param cstream C File stream. @@ -255,7 +255,7 @@ extern ZIP_EXPORT int zip_entry_close(struct zip_t *zip); * All slashes MUST be forward slashes '/' as opposed to backwards slashes '\' * for compatibility with Amiga and UNIX file systems etc. * - * @param zip: zip archive handler. + * @param zip zip archive handler. * * @return the pointer to the current zip entry name, or NULL on error. */ @@ -495,7 +495,7 @@ extern ZIP_EXPORT struct zip_t *zip_stream_open(const char *stream, size_t size, /** * Opens zip archive stream into memory. - * The function additionally returns @param errnum - + * The function additionally returns errnum * * @param stream zip archive stream. * @param size stream size.* @@ -529,8 +529,6 @@ extern ZIP_EXPORT ssize_t zip_stream_copy(struct zip_t *zip, void **buf, * Close zip archive releases resources. * * @param zip zip archive handler. - * - * @return */ extern ZIP_EXPORT void zip_stream_close(struct zip_t *zip); @@ -539,7 +537,7 @@ extern ZIP_EXPORT void zip_stream_close(struct zip_t *zip); * * @param zipname zip archive file. * @param filenames input files. - * @param len: number of input files. + * @param len number of input files. * * @return the return code - 0 on success, negative number (< 0) on error. */ diff --git a/res/asset_packer/src/asset_packer.c b/res/asset_packer/src/asset_packer.c index 93955741f8..6dfc284f99 100644 --- a/res/asset_packer/src/asset_packer.c +++ b/res/asset_packer/src/asset_packer.c @@ -71,6 +71,16 @@ typedef struct { static array(packed_asset) packed_assets; +const char *pref_user_dir(void) +{ + return ""; +} + +int random_from_stdlib(void) +{ + return 0; +} + static int remove_file(const char *filename, long unused) { snprintf(current_file, FILE_NAME_MAX, "%s/%s", PACKED_ASSETS_DIR, filename); @@ -92,8 +102,8 @@ static int prepare_packed_assets_dir(void) return 0; } } - if (!platform_file_manager_create_directory(PACKED_ASSETS_DIR "/" ASSETS_IMAGE_PATH, 1) || - !platform_file_manager_create_directory(PACKED_ASSETS_DIR "/" CURSORS_DIR, 1)) { + if (!platform_file_manager_create_directory(PACKED_ASSETS_DIR "/" ASSETS_IMAGE_PATH, 0, 1) || + !platform_file_manager_create_directory(PACKED_ASSETS_DIR "/" CURSORS_DIR, 0, 1)) { log_error("Failed to create directories", 0, 0); return 0; } @@ -765,7 +775,7 @@ int main(int argc, char **argv) log_info("Copying other assets...", 0, 0); - platform_file_manager_copy_directory(ASSETS_DIRECTORY, PACKED_ASSETS_DIR); + platform_file_manager_copy_directory(ASSETS_DIRECTORY, PACKED_ASSETS_DIR, 1); log_info("All done!", 0, 0); diff --git a/res/assets/Graphics/Admin_Logistics/Basilica_Off.png b/res/assets/Graphics/Admin_Logistics/Basilica_Off.png deleted file mode 100644 index 97b237de19..0000000000 Binary files a/res/assets/Graphics/Admin_Logistics/Basilica_Off.png and /dev/null differ diff --git a/res/assets/Graphics/Admin_Logistics/Basilica_On.png b/res/assets/Graphics/Admin_Logistics/Basilica_On.png deleted file mode 100644 index a7de49f0f5..0000000000 Binary files a/res/assets/Graphics/Admin_Logistics/Basilica_On.png and /dev/null differ diff --git a/res/assets/Graphics/Industry.xml b/res/assets/Graphics/Industry.xml index 4f7968d227..f05524a462 100644 --- a/res/assets/Graphics/Industry.xml +++ b/res/assets/Graphics/Industry.xml @@ -269,10 +269,12 @@ - + + - + + @@ -391,8 +393,14 @@ - - + + + + + + + + @@ -598,8 +606,14 @@ - - + + + + + + + + diff --git a/res/assets/Graphics/Industry/Brickworks_ON_Static.png b/res/assets/Graphics/Industry/Brickworks_ON_Static.png index ca8e17ba66..0011c89bbd 100644 Binary files a/res/assets/Graphics/Industry/Brickworks_ON_Static.png and b/res/assets/Graphics/Industry/Brickworks_ON_Static.png differ diff --git a/res/assets/Graphics/Industry/Brickworks_n_OFF.png b/res/assets/Graphics/Industry/Brickworks_n_OFF.png index 63b99f94c7..bebd65dee1 100644 Binary files a/res/assets/Graphics/Industry/Brickworks_n_OFF.png and b/res/assets/Graphics/Industry/Brickworks_n_OFF.png differ diff --git a/res/assets/Graphics/Industry/Brickworks_s_OFF.png b/res/assets/Graphics/Industry/Brickworks_s_OFF.png index 94d4ee9043..cf46040e87 100644 Binary files a/res/assets/Graphics/Industry/Brickworks_s_OFF.png and b/res/assets/Graphics/Industry/Brickworks_s_OFF.png differ diff --git a/res/assets/Graphics/Industry/Gold_Mine_C_OFF.png b/res/assets/Graphics/Industry/Gold_Mine_C_OFF.png index e411c8eec0..908277a6eb 100644 Binary files a/res/assets/Graphics/Industry/Gold_Mine_C_OFF.png and b/res/assets/Graphics/Industry/Gold_Mine_C_OFF.png differ diff --git a/res/assets/Graphics/Industry/Gold_Mine_N_OFF.png b/res/assets/Graphics/Industry/Gold_Mine_N_OFF.png index 3cda8002b1..0744d79e03 100644 Binary files a/res/assets/Graphics/Industry/Gold_Mine_N_OFF.png and b/res/assets/Graphics/Industry/Gold_Mine_N_OFF.png differ diff --git a/res/assets/Graphics/Industry/Gold_Mine_S_OFF.png b/res/assets/Graphics/Industry/Gold_Mine_S_OFF.png index 3983e92b22..553ac34938 100644 Binary files a/res/assets/Graphics/Industry/Gold_Mine_S_OFF.png and b/res/assets/Graphics/Industry/Gold_Mine_S_OFF.png differ diff --git a/res/assets/Graphics/Industry/Sand_Pit_N_OFF.png b/res/assets/Graphics/Industry/Sand_Pit_N_OFF.png index ac46e4bc32..bab051e348 100644 Binary files a/res/assets/Graphics/Industry/Sand_Pit_N_OFF.png and b/res/assets/Graphics/Industry/Sand_Pit_N_OFF.png differ diff --git a/res/assets/Graphics/Industry/Sand_Pit_S_OFF.png b/res/assets/Graphics/Industry/Sand_Pit_S_OFF.png index 5aa6e35652..e926f76c29 100644 Binary files a/res/assets/Graphics/Industry/Sand_Pit_S_OFF.png and b/res/assets/Graphics/Industry/Sand_Pit_S_OFF.png differ diff --git a/res/assets/Graphics/Industry/Stone_Quarry_N_OFF.png b/res/assets/Graphics/Industry/Stone_Quarry_N_OFF.png index 2e111b8fe7..e1af8a5194 100644 Binary files a/res/assets/Graphics/Industry/Stone_Quarry_N_OFF.png and b/res/assets/Graphics/Industry/Stone_Quarry_N_OFF.png differ diff --git a/res/assets/Graphics/Industry/Stone_Quarry_ON.png b/res/assets/Graphics/Industry/Stone_Quarry_ON.png index 49cc711acc..748b223892 100644 Binary files a/res/assets/Graphics/Industry/Stone_Quarry_ON.png and b/res/assets/Graphics/Industry/Stone_Quarry_ON.png differ diff --git a/res/assets/Graphics/Industry/Stone_Quarry_S_OFF.png b/res/assets/Graphics/Industry/Stone_Quarry_S_OFF.png index ace02b8dcc..33101b335f 100644 Binary files a/res/assets/Graphics/Industry/Stone_Quarry_S_OFF.png and b/res/assets/Graphics/Industry/Stone_Quarry_S_OFF.png differ diff --git a/res/assets/Graphics/Monuments/Ceres_Temple_Construction_01.png b/res/assets/Graphics/Monuments/Ceres_Temple_Construction_01.png index cf51ccaa34..74fecabe12 100644 Binary files a/res/assets/Graphics/Monuments/Ceres_Temple_Construction_01.png and b/res/assets/Graphics/Monuments/Ceres_Temple_Construction_01.png differ diff --git a/res/assets/Graphics/Monuments/Construction_Part_Pillar.png b/res/assets/Graphics/Monuments/Construction_Part_Pillar.png new file mode 100644 index 0000000000..1393387125 Binary files /dev/null and b/res/assets/Graphics/Monuments/Construction_Part_Pillar.png differ diff --git a/res/assets/Graphics/Monuments/Construction_Part_Shadow_B.png b/res/assets/Graphics/Monuments/Construction_Part_Shadow_B.png new file mode 100644 index 0000000000..d175267a1a Binary files /dev/null and b/res/assets/Graphics/Monuments/Construction_Part_Shadow_B.png differ diff --git a/res/assets/Graphics/Monuments/Construction_Part_Shadow_L.png b/res/assets/Graphics/Monuments/Construction_Part_Shadow_L.png new file mode 100644 index 0000000000..513840bde4 Binary files /dev/null and b/res/assets/Graphics/Monuments/Construction_Part_Shadow_L.png differ diff --git a/res/assets/Graphics/Monuments/Grand_Temple_Construction_Base_01.png b/res/assets/Graphics/Monuments/Grand_Temple_Construction_Base_01.png index d4e9aacc7c..3cc8b58647 100644 Binary files a/res/assets/Graphics/Monuments/Grand_Temple_Construction_Base_01.png and b/res/assets/Graphics/Monuments/Grand_Temple_Construction_Base_01.png differ diff --git a/res/assets/Graphics/Monuments/Senate_T2_Construction_04_Top.png b/res/assets/Graphics/Monuments/Senate_T2_Construction_04_Top.png index cb969451a3..d7e7e12bed 100644 Binary files a/res/assets/Graphics/Monuments/Senate_T2_Construction_04_Top.png and b/res/assets/Graphics/Monuments/Senate_T2_Construction_04_Top.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_death_01.png b/res/assets/Graphics/Walkers/caravanserai_overseer_death_01.png new file mode 100644 index 0000000000..2c7f3b940c Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_death_01.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_death_02.png b/res/assets/Graphics/Walkers/caravanserai_overseer_death_02.png new file mode 100644 index 0000000000..0104e3447a Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_death_02.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_death_03.png b/res/assets/Graphics/Walkers/caravanserai_overseer_death_03.png new file mode 100644 index 0000000000..b10081cb58 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_death_03.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_death_04.png b/res/assets/Graphics/Walkers/caravanserai_overseer_death_04.png new file mode 100644 index 0000000000..ec9b3e2513 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_death_04.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_01.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_01.png new file mode 100644 index 0000000000..890045232f Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_01.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_02.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_02.png new file mode 100644 index 0000000000..2909fdb4e0 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_02.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_03.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_03.png new file mode 100644 index 0000000000..052bfdbad1 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_03.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_04.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_04.png new file mode 100644 index 0000000000..c9168506ff Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_04.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_05.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_05.png new file mode 100644 index 0000000000..628019ec3f Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_05.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_06.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_06.png new file mode 100644 index 0000000000..98fd12957b Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_06.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_07.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_07.png new file mode 100644 index 0000000000..07ee825116 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_07.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_08.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_08.png new file mode 100644 index 0000000000..3cc2fe8a51 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_08.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_09.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_09.png new file mode 100644 index 0000000000..75d2a94326 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_09.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_10.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_10.png new file mode 100644 index 0000000000..8c08c00627 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_10.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_11.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_11.png new file mode 100644 index 0000000000..5f3a0bb440 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_11.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_e_12.png b/res/assets/Graphics/Walkers/caravanserai_overseer_e_12.png new file mode 100644 index 0000000000..b8b9840308 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_e_12.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_01.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_01.png new file mode 100644 index 0000000000..8b91c41568 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_01.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_02.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_02.png new file mode 100644 index 0000000000..e502fdb953 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_02.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_03.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_03.png new file mode 100644 index 0000000000..13a8cb417e Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_03.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_04.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_04.png new file mode 100644 index 0000000000..a85d45b0e3 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_04.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_05.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_05.png new file mode 100644 index 0000000000..15d9209192 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_05.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_06.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_06.png new file mode 100644 index 0000000000..016e386882 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_06.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_07.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_07.png new file mode 100644 index 0000000000..731267fdda Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_07.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_08.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_08.png new file mode 100644 index 0000000000..bc8145d9b2 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_08.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_09.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_09.png new file mode 100644 index 0000000000..bb40ddc0e6 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_09.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_10.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_10.png new file mode 100644 index 0000000000..6c7242e781 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_10.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_11.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_11.png new file mode 100644 index 0000000000..fe69e4450e Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_11.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_n_12.png b/res/assets/Graphics/Walkers/caravanserai_overseer_n_12.png new file mode 100644 index 0000000000..19d9d517c8 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_n_12.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_01.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_01.png new file mode 100644 index 0000000000..51830ad17c Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_01.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_02.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_02.png new file mode 100644 index 0000000000..efe9fdc914 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_02.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_03.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_03.png new file mode 100644 index 0000000000..81c8d808a0 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_03.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_04.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_04.png new file mode 100644 index 0000000000..62ac0bb038 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_04.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_05.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_05.png new file mode 100644 index 0000000000..6eca28e4fc Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_05.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_06.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_06.png new file mode 100644 index 0000000000..6678c56fb1 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_06.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_07.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_07.png new file mode 100644 index 0000000000..248b3d3524 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_07.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_08.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_08.png new file mode 100644 index 0000000000..ae41068c14 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_08.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_09.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_09.png new file mode 100644 index 0000000000..8826504527 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_09.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_10.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_10.png new file mode 100644 index 0000000000..24a273a617 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_10.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_11.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_11.png new file mode 100644 index 0000000000..e235cc0be7 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_11.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_ne_12.png b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_12.png new file mode 100644 index 0000000000..4e3b1aec32 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_ne_12.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_01.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_01.png new file mode 100644 index 0000000000..ca1ad9c2c9 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_01.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_02.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_02.png new file mode 100644 index 0000000000..fd290864d4 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_02.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_03.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_03.png new file mode 100644 index 0000000000..1880fd768f Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_03.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_04.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_04.png new file mode 100644 index 0000000000..1cee08e8fa Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_04.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_05.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_05.png new file mode 100644 index 0000000000..5ce2861915 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_05.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_06.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_06.png new file mode 100644 index 0000000000..521bed8c41 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_06.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_07.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_07.png new file mode 100644 index 0000000000..4615f19c4d Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_07.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_08.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_08.png new file mode 100644 index 0000000000..b632cbe38f Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_08.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_09.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_09.png new file mode 100644 index 0000000000..14a2c644a8 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_09.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_10.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_10.png new file mode 100644 index 0000000000..1f7ed506f0 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_10.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_11.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_11.png new file mode 100644 index 0000000000..72e6401978 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_11.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_nw_12.png b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_12.png new file mode 100644 index 0000000000..c97e79c744 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_nw_12.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_portrait_overlay.png b/res/assets/Graphics/Walkers/caravanserai_overseer_portrait_overlay.png new file mode 100644 index 0000000000..b3b9a70aee Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_portrait_overlay.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_01.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_01.png new file mode 100644 index 0000000000..205f5b3422 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_01.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_02.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_02.png new file mode 100644 index 0000000000..3e8a213dd4 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_02.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_03.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_03.png new file mode 100644 index 0000000000..fa806ae52a Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_03.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_04.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_04.png new file mode 100644 index 0000000000..04217c922e Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_04.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_05.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_05.png new file mode 100644 index 0000000000..c1d14e075b Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_05.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_06.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_06.png new file mode 100644 index 0000000000..ffcdbf6be1 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_06.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_07.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_07.png new file mode 100644 index 0000000000..7b253fcd81 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_07.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_08.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_08.png new file mode 100644 index 0000000000..fcdb0c463a Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_08.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_09.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_09.png new file mode 100644 index 0000000000..c64cac0b21 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_09.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_10.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_10.png new file mode 100644 index 0000000000..ed6bee9b94 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_10.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_11.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_11.png new file mode 100644 index 0000000000..206c9b8348 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_11.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_s_12.png b/res/assets/Graphics/Walkers/caravanserai_overseer_s_12.png new file mode 100644 index 0000000000..179c91efd3 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_s_12.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_01.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_01.png new file mode 100644 index 0000000000..1db79050a6 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_01.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_02.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_02.png new file mode 100644 index 0000000000..56653916d6 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_02.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_03.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_03.png new file mode 100644 index 0000000000..ca3f5280ef Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_03.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_04.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_04.png new file mode 100644 index 0000000000..71e8507114 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_04.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_05.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_05.png new file mode 100644 index 0000000000..e155b1c26d Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_05.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_06.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_06.png new file mode 100644 index 0000000000..e20e6e7153 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_06.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_07.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_07.png new file mode 100644 index 0000000000..34573ba0db Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_07.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_08.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_08.png new file mode 100644 index 0000000000..211f002d04 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_08.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_09.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_09.png new file mode 100644 index 0000000000..24d818d7a4 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_09.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_10.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_10.png new file mode 100644 index 0000000000..6776d74ffb Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_10.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_11.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_11.png new file mode 100644 index 0000000000..e9d8e53be9 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_11.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_se_12.png b/res/assets/Graphics/Walkers/caravanserai_overseer_se_12.png new file mode 100644 index 0000000000..9d158c2b36 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_se_12.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_01.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_01.png new file mode 100644 index 0000000000..87364f5c0a Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_01.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_02.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_02.png new file mode 100644 index 0000000000..4816840045 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_02.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_03.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_03.png new file mode 100644 index 0000000000..ed19da675f Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_03.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_04.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_04.png new file mode 100644 index 0000000000..c112f46f66 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_04.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_05.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_05.png new file mode 100644 index 0000000000..bdc53b56e5 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_05.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_06.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_06.png new file mode 100644 index 0000000000..8acd40333c Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_06.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_07.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_07.png new file mode 100644 index 0000000000..0af03980b6 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_07.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_08.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_08.png new file mode 100644 index 0000000000..55d5a7d75d Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_08.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_09.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_09.png new file mode 100644 index 0000000000..b185309217 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_09.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_10.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_10.png new file mode 100644 index 0000000000..1f7cf6f978 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_10.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_11.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_11.png new file mode 100644 index 0000000000..abff50cfbf Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_11.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_sw_12.png b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_12.png new file mode 100644 index 0000000000..5d8b55d8cb Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_sw_12.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_01.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_01.png new file mode 100644 index 0000000000..5eec4a030b Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_01.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_02.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_02.png new file mode 100644 index 0000000000..03385def18 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_02.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_03.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_03.png new file mode 100644 index 0000000000..8c591e633e Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_03.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_04.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_04.png new file mode 100644 index 0000000000..1ea9b04703 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_04.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_05.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_05.png new file mode 100644 index 0000000000..0d5816a40e Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_05.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_06.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_06.png new file mode 100644 index 0000000000..740262d3e8 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_06.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_07.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_07.png new file mode 100644 index 0000000000..3c3a72f5d4 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_07.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_08.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_08.png new file mode 100644 index 0000000000..2bdea08793 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_08.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_09.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_09.png new file mode 100644 index 0000000000..3e72160206 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_09.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_10.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_10.png new file mode 100644 index 0000000000..7b73bf8177 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_10.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_11.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_11.png new file mode 100644 index 0000000000..890a23f729 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_11.png differ diff --git a/res/assets/Graphics/Walkers/caravanserai_overseer_w_12.png b/res/assets/Graphics/Walkers/caravanserai_overseer_w_12.png new file mode 100644 index 0000000000..929ad4d455 Binary files /dev/null and b/res/assets/Graphics/Walkers/caravanserai_overseer_w_12.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_death_01.png b/res/assets/Graphics/Walkers/magistrate_death_01.png new file mode 100644 index 0000000000..e998f787ae Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_death_01.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_death_02.png b/res/assets/Graphics/Walkers/magistrate_death_02.png new file mode 100644 index 0000000000..4089bcc7ed Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_death_02.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_death_03.png b/res/assets/Graphics/Walkers/magistrate_death_03.png new file mode 100644 index 0000000000..e860c6db1a Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_death_03.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_death_04.png b/res/assets/Graphics/Walkers/magistrate_death_04.png new file mode 100644 index 0000000000..ad583d5fe9 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_death_04.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_death_05.png b/res/assets/Graphics/Walkers/magistrate_death_05.png new file mode 100644 index 0000000000..8f92138979 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_death_05.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_01.png b/res/assets/Graphics/Walkers/magistrate_e_01.png new file mode 100644 index 0000000000..77bdab081d Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_01.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_02.png b/res/assets/Graphics/Walkers/magistrate_e_02.png new file mode 100644 index 0000000000..cc3d2bb1b1 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_02.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_03.png b/res/assets/Graphics/Walkers/magistrate_e_03.png new file mode 100644 index 0000000000..146b89cf84 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_03.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_04.png b/res/assets/Graphics/Walkers/magistrate_e_04.png new file mode 100644 index 0000000000..d3d248f0bd Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_04.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_05.png b/res/assets/Graphics/Walkers/magistrate_e_05.png new file mode 100644 index 0000000000..9aa192c57c Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_05.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_06.png b/res/assets/Graphics/Walkers/magistrate_e_06.png new file mode 100644 index 0000000000..0af9455ea4 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_06.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_07.png b/res/assets/Graphics/Walkers/magistrate_e_07.png new file mode 100644 index 0000000000..b0b4692dd5 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_07.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_08.png b/res/assets/Graphics/Walkers/magistrate_e_08.png new file mode 100644 index 0000000000..1f647a34de Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_08.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_09.png b/res/assets/Graphics/Walkers/magistrate_e_09.png new file mode 100644 index 0000000000..995b69c4b1 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_09.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_10.png b/res/assets/Graphics/Walkers/magistrate_e_10.png new file mode 100644 index 0000000000..9546464d0b Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_10.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_11.png b/res/assets/Graphics/Walkers/magistrate_e_11.png new file mode 100644 index 0000000000..5bcf9378a4 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_11.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_e_12.png b/res/assets/Graphics/Walkers/magistrate_e_12.png new file mode 100644 index 0000000000..af85fe27d2 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_e_12.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_01.png b/res/assets/Graphics/Walkers/magistrate_n_01.png new file mode 100644 index 0000000000..3efb8beb0b Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_01.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_02.png b/res/assets/Graphics/Walkers/magistrate_n_02.png new file mode 100644 index 0000000000..d2cd4dca58 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_02.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_03.png b/res/assets/Graphics/Walkers/magistrate_n_03.png new file mode 100644 index 0000000000..20598b88ce Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_03.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_04.png b/res/assets/Graphics/Walkers/magistrate_n_04.png new file mode 100644 index 0000000000..b4b7e29799 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_04.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_05.png b/res/assets/Graphics/Walkers/magistrate_n_05.png new file mode 100644 index 0000000000..f8438f6051 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_05.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_06.png b/res/assets/Graphics/Walkers/magistrate_n_06.png new file mode 100644 index 0000000000..6c55a1049e Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_06.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_07.png b/res/assets/Graphics/Walkers/magistrate_n_07.png new file mode 100644 index 0000000000..c6e8ef4635 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_07.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_08.png b/res/assets/Graphics/Walkers/magistrate_n_08.png new file mode 100644 index 0000000000..0ebba04781 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_08.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_09.png b/res/assets/Graphics/Walkers/magistrate_n_09.png new file mode 100644 index 0000000000..cc7556128c Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_09.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_10.png b/res/assets/Graphics/Walkers/magistrate_n_10.png new file mode 100644 index 0000000000..6eadee8064 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_10.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_11.png b/res/assets/Graphics/Walkers/magistrate_n_11.png new file mode 100644 index 0000000000..da48b05c86 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_11.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_n_12.png b/res/assets/Graphics/Walkers/magistrate_n_12.png new file mode 100644 index 0000000000..390b46d7b1 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_n_12.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_01.png b/res/assets/Graphics/Walkers/magistrate_ne_01.png new file mode 100644 index 0000000000..577d567c1c Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_01.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_02.png b/res/assets/Graphics/Walkers/magistrate_ne_02.png new file mode 100644 index 0000000000..4e9c8bdcea Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_02.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_03.png b/res/assets/Graphics/Walkers/magistrate_ne_03.png new file mode 100644 index 0000000000..f4057c2704 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_03.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_04.png b/res/assets/Graphics/Walkers/magistrate_ne_04.png new file mode 100644 index 0000000000..5a425d8f88 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_04.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_05.png b/res/assets/Graphics/Walkers/magistrate_ne_05.png new file mode 100644 index 0000000000..808744ff89 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_05.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_06.png b/res/assets/Graphics/Walkers/magistrate_ne_06.png new file mode 100644 index 0000000000..f3c3b9b491 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_06.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_07.png b/res/assets/Graphics/Walkers/magistrate_ne_07.png new file mode 100644 index 0000000000..edbe20e0cc Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_07.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_08.png b/res/assets/Graphics/Walkers/magistrate_ne_08.png new file mode 100644 index 0000000000..767ce8c909 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_08.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_09.png b/res/assets/Graphics/Walkers/magistrate_ne_09.png new file mode 100644 index 0000000000..929ad4ba57 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_09.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_10.png b/res/assets/Graphics/Walkers/magistrate_ne_10.png new file mode 100644 index 0000000000..bc434fd9cb Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_10.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_11.png b/res/assets/Graphics/Walkers/magistrate_ne_11.png new file mode 100644 index 0000000000..5135fea13c Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_11.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_ne_12.png b/res/assets/Graphics/Walkers/magistrate_ne_12.png new file mode 100644 index 0000000000..11b975ab19 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_ne_12.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_01.png b/res/assets/Graphics/Walkers/magistrate_nw_01.png new file mode 100644 index 0000000000..90f79fcc4c Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_01.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_02.png b/res/assets/Graphics/Walkers/magistrate_nw_02.png new file mode 100644 index 0000000000..02f767c8e9 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_02.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_03.png b/res/assets/Graphics/Walkers/magistrate_nw_03.png new file mode 100644 index 0000000000..975db2e6f5 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_03.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_04.png b/res/assets/Graphics/Walkers/magistrate_nw_04.png new file mode 100644 index 0000000000..7362587d59 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_04.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_05.png b/res/assets/Graphics/Walkers/magistrate_nw_05.png new file mode 100644 index 0000000000..391eccbac9 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_05.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_06.png b/res/assets/Graphics/Walkers/magistrate_nw_06.png new file mode 100644 index 0000000000..d6e30ea102 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_06.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_07.png b/res/assets/Graphics/Walkers/magistrate_nw_07.png new file mode 100644 index 0000000000..9d9efb0d96 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_07.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_08.png b/res/assets/Graphics/Walkers/magistrate_nw_08.png new file mode 100644 index 0000000000..cb35eb5138 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_08.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_09.png b/res/assets/Graphics/Walkers/magistrate_nw_09.png new file mode 100644 index 0000000000..b048f8118f Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_09.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_10.png b/res/assets/Graphics/Walkers/magistrate_nw_10.png new file mode 100644 index 0000000000..4cc0d40f35 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_10.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_11.png b/res/assets/Graphics/Walkers/magistrate_nw_11.png new file mode 100644 index 0000000000..5878ea21ae Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_11.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_nw_12.png b/res/assets/Graphics/Walkers/magistrate_nw_12.png new file mode 100644 index 0000000000..1504e75737 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_nw_12.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_portrait_overlay.png b/res/assets/Graphics/Walkers/magistrate_portrait_overlay.png new file mode 100644 index 0000000000..4574ef2b12 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_portrait_overlay.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_01.png b/res/assets/Graphics/Walkers/magistrate_s_01.png new file mode 100644 index 0000000000..40e907ef13 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_01.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_02.png b/res/assets/Graphics/Walkers/magistrate_s_02.png new file mode 100644 index 0000000000..88060ad9bd Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_02.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_03.png b/res/assets/Graphics/Walkers/magistrate_s_03.png new file mode 100644 index 0000000000..c1778ba642 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_03.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_04.png b/res/assets/Graphics/Walkers/magistrate_s_04.png new file mode 100644 index 0000000000..499250551e Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_04.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_05.png b/res/assets/Graphics/Walkers/magistrate_s_05.png new file mode 100644 index 0000000000..fb3b0042e3 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_05.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_06.png b/res/assets/Graphics/Walkers/magistrate_s_06.png new file mode 100644 index 0000000000..6bd2df0652 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_06.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_07.png b/res/assets/Graphics/Walkers/magistrate_s_07.png new file mode 100644 index 0000000000..b7e61c4e2a Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_07.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_08.png b/res/assets/Graphics/Walkers/magistrate_s_08.png new file mode 100644 index 0000000000..253b2cf4d5 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_08.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_09.png b/res/assets/Graphics/Walkers/magistrate_s_09.png new file mode 100644 index 0000000000..6f9a6d6999 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_09.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_10.png b/res/assets/Graphics/Walkers/magistrate_s_10.png new file mode 100644 index 0000000000..7e81756dd9 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_10.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_11.png b/res/assets/Graphics/Walkers/magistrate_s_11.png new file mode 100644 index 0000000000..664f2c6a66 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_11.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_s_12.png b/res/assets/Graphics/Walkers/magistrate_s_12.png new file mode 100644 index 0000000000..fd60d14947 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_s_12.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_01.png b/res/assets/Graphics/Walkers/magistrate_se_01.png new file mode 100644 index 0000000000..19882469e9 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_01.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_02.png b/res/assets/Graphics/Walkers/magistrate_se_02.png new file mode 100644 index 0000000000..734ee66038 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_02.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_03.png b/res/assets/Graphics/Walkers/magistrate_se_03.png new file mode 100644 index 0000000000..51d372f606 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_03.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_04.png b/res/assets/Graphics/Walkers/magistrate_se_04.png new file mode 100644 index 0000000000..96d5fdecdb Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_04.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_05.png b/res/assets/Graphics/Walkers/magistrate_se_05.png new file mode 100644 index 0000000000..775a6c6611 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_05.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_06.png b/res/assets/Graphics/Walkers/magistrate_se_06.png new file mode 100644 index 0000000000..7e77170e80 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_06.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_07.png b/res/assets/Graphics/Walkers/magistrate_se_07.png new file mode 100644 index 0000000000..f27e3cbcb6 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_07.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_08.png b/res/assets/Graphics/Walkers/magistrate_se_08.png new file mode 100644 index 0000000000..90cf5a73e4 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_08.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_09.png b/res/assets/Graphics/Walkers/magistrate_se_09.png new file mode 100644 index 0000000000..3d08a0bdc9 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_09.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_10.png b/res/assets/Graphics/Walkers/magistrate_se_10.png new file mode 100644 index 0000000000..dbf344a4df Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_10.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_11.png b/res/assets/Graphics/Walkers/magistrate_se_11.png new file mode 100644 index 0000000000..f71cfab37a Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_11.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_se_12.png b/res/assets/Graphics/Walkers/magistrate_se_12.png new file mode 100644 index 0000000000..78806a917b Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_se_12.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_01.png b/res/assets/Graphics/Walkers/magistrate_sw_01.png new file mode 100644 index 0000000000..71408f0122 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_01.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_02.png b/res/assets/Graphics/Walkers/magistrate_sw_02.png new file mode 100644 index 0000000000..8fe1eebd85 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_02.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_03.png b/res/assets/Graphics/Walkers/magistrate_sw_03.png new file mode 100644 index 0000000000..58d19b54ce Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_03.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_04.png b/res/assets/Graphics/Walkers/magistrate_sw_04.png new file mode 100644 index 0000000000..5855c698d0 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_04.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_05.png b/res/assets/Graphics/Walkers/magistrate_sw_05.png new file mode 100644 index 0000000000..67eb7189c1 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_05.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_06.png b/res/assets/Graphics/Walkers/magistrate_sw_06.png new file mode 100644 index 0000000000..5b2695bbe3 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_06.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_07.png b/res/assets/Graphics/Walkers/magistrate_sw_07.png new file mode 100644 index 0000000000..0cec19b815 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_07.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_08.png b/res/assets/Graphics/Walkers/magistrate_sw_08.png new file mode 100644 index 0000000000..4c26462b34 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_08.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_09.png b/res/assets/Graphics/Walkers/magistrate_sw_09.png new file mode 100644 index 0000000000..795c6d9e9e Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_09.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_10.png b/res/assets/Graphics/Walkers/magistrate_sw_10.png new file mode 100644 index 0000000000..8e48e268f5 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_10.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_11.png b/res/assets/Graphics/Walkers/magistrate_sw_11.png new file mode 100644 index 0000000000..f88e3ad08a Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_11.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_sw_12.png b/res/assets/Graphics/Walkers/magistrate_sw_12.png new file mode 100644 index 0000000000..4f01f63ab5 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_sw_12.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_01.png b/res/assets/Graphics/Walkers/magistrate_w_01.png new file mode 100644 index 0000000000..d48c16c95d Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_01.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_02.png b/res/assets/Graphics/Walkers/magistrate_w_02.png new file mode 100644 index 0000000000..8e7aefbe27 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_02.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_03.png b/res/assets/Graphics/Walkers/magistrate_w_03.png new file mode 100644 index 0000000000..b6d8fc99f0 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_03.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_04.png b/res/assets/Graphics/Walkers/magistrate_w_04.png new file mode 100644 index 0000000000..8144904723 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_04.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_05.png b/res/assets/Graphics/Walkers/magistrate_w_05.png new file mode 100644 index 0000000000..fa9e6977f9 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_05.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_06.png b/res/assets/Graphics/Walkers/magistrate_w_06.png new file mode 100644 index 0000000000..144b7fab90 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_06.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_07.png b/res/assets/Graphics/Walkers/magistrate_w_07.png new file mode 100644 index 0000000000..83e73509b2 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_07.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_08.png b/res/assets/Graphics/Walkers/magistrate_w_08.png new file mode 100644 index 0000000000..3d5e68491d Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_08.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_09.png b/res/assets/Graphics/Walkers/magistrate_w_09.png new file mode 100644 index 0000000000..d699f8e026 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_09.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_10.png b/res/assets/Graphics/Walkers/magistrate_w_10.png new file mode 100644 index 0000000000..caed54aa56 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_10.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_11.png b/res/assets/Graphics/Walkers/magistrate_w_11.png new file mode 100644 index 0000000000..9070f39537 Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_11.png differ diff --git a/res/assets/Graphics/Walkers/magistrate_w_12.png b/res/assets/Graphics/Walkers/magistrate_w_12.png new file mode 100644 index 0000000000..5e3f5e299d Binary files /dev/null and b/res/assets/Graphics/Walkers/magistrate_w_12.png differ diff --git a/res/assets/Graphics/Walkers/overseer_death_01.png b/res/assets/Graphics/Walkers/overseer_death_01.png new file mode 100644 index 0000000000..5003b60c6c Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_death_01.png differ diff --git a/res/assets/Graphics/Walkers/overseer_death_02.png b/res/assets/Graphics/Walkers/overseer_death_02.png new file mode 100644 index 0000000000..10b84ee93f Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_death_02.png differ diff --git a/res/assets/Graphics/Walkers/overseer_death_03.png b/res/assets/Graphics/Walkers/overseer_death_03.png new file mode 100644 index 0000000000..5fab05418d Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_death_03.png differ diff --git a/res/assets/Graphics/Walkers/overseer_death_04.png b/res/assets/Graphics/Walkers/overseer_death_04.png new file mode 100644 index 0000000000..53b97d3cbe Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_death_04.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_01.png b/res/assets/Graphics/Walkers/overseer_e_01.png new file mode 100644 index 0000000000..8c014e83ff Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_01.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_02.png b/res/assets/Graphics/Walkers/overseer_e_02.png new file mode 100644 index 0000000000..c20424d845 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_02.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_03.png b/res/assets/Graphics/Walkers/overseer_e_03.png new file mode 100644 index 0000000000..821897335a Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_03.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_04.png b/res/assets/Graphics/Walkers/overseer_e_04.png new file mode 100644 index 0000000000..e8366a7456 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_04.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_05.png b/res/assets/Graphics/Walkers/overseer_e_05.png new file mode 100644 index 0000000000..c538ddb008 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_05.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_06.png b/res/assets/Graphics/Walkers/overseer_e_06.png new file mode 100644 index 0000000000..f54169a422 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_06.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_07.png b/res/assets/Graphics/Walkers/overseer_e_07.png new file mode 100644 index 0000000000..89d5ad95d4 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_07.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_08.png b/res/assets/Graphics/Walkers/overseer_e_08.png new file mode 100644 index 0000000000..532b061b7c Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_08.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_09.png b/res/assets/Graphics/Walkers/overseer_e_09.png new file mode 100644 index 0000000000..36434c8a2b Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_09.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_10.png b/res/assets/Graphics/Walkers/overseer_e_10.png new file mode 100644 index 0000000000..9f1b240ba5 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_10.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_11.png b/res/assets/Graphics/Walkers/overseer_e_11.png new file mode 100644 index 0000000000..93e3a0c747 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_11.png differ diff --git a/res/assets/Graphics/Walkers/overseer_e_12.png b/res/assets/Graphics/Walkers/overseer_e_12.png new file mode 100644 index 0000000000..b764b3d0a3 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_e_12.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_01.png b/res/assets/Graphics/Walkers/overseer_n_01.png new file mode 100644 index 0000000000..f020befdcf Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_01.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_02.png b/res/assets/Graphics/Walkers/overseer_n_02.png new file mode 100644 index 0000000000..62ba32583c Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_02.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_03.png b/res/assets/Graphics/Walkers/overseer_n_03.png new file mode 100644 index 0000000000..add687d674 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_03.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_04.png b/res/assets/Graphics/Walkers/overseer_n_04.png new file mode 100644 index 0000000000..8ebcb0c78e Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_04.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_05.png b/res/assets/Graphics/Walkers/overseer_n_05.png new file mode 100644 index 0000000000..8e8b9782c2 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_05.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_06.png b/res/assets/Graphics/Walkers/overseer_n_06.png new file mode 100644 index 0000000000..be92970639 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_06.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_07.png b/res/assets/Graphics/Walkers/overseer_n_07.png new file mode 100644 index 0000000000..6b5fe916fe Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_07.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_08.png b/res/assets/Graphics/Walkers/overseer_n_08.png new file mode 100644 index 0000000000..5b1f1b84fb Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_08.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_09.png b/res/assets/Graphics/Walkers/overseer_n_09.png new file mode 100644 index 0000000000..3e0cc6ff63 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_09.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_10.png b/res/assets/Graphics/Walkers/overseer_n_10.png new file mode 100644 index 0000000000..6bfbe5444a Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_10.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_11.png b/res/assets/Graphics/Walkers/overseer_n_11.png new file mode 100644 index 0000000000..c8a93e2c90 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_11.png differ diff --git a/res/assets/Graphics/Walkers/overseer_n_12.png b/res/assets/Graphics/Walkers/overseer_n_12.png new file mode 100644 index 0000000000..56a33af035 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_n_12.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_01.png b/res/assets/Graphics/Walkers/overseer_ne_01.png new file mode 100644 index 0000000000..9e22a505da Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_01.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_02.png b/res/assets/Graphics/Walkers/overseer_ne_02.png new file mode 100644 index 0000000000..26b025d60c Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_02.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_03.png b/res/assets/Graphics/Walkers/overseer_ne_03.png new file mode 100644 index 0000000000..fc34b27891 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_03.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_04.png b/res/assets/Graphics/Walkers/overseer_ne_04.png new file mode 100644 index 0000000000..f621e0e033 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_04.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_05.png b/res/assets/Graphics/Walkers/overseer_ne_05.png new file mode 100644 index 0000000000..85ed2da0ea Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_05.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_06.png b/res/assets/Graphics/Walkers/overseer_ne_06.png new file mode 100644 index 0000000000..6c0e8adced Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_06.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_07.png b/res/assets/Graphics/Walkers/overseer_ne_07.png new file mode 100644 index 0000000000..cf23042a78 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_07.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_08.png b/res/assets/Graphics/Walkers/overseer_ne_08.png new file mode 100644 index 0000000000..3bfa726039 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_08.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_09.png b/res/assets/Graphics/Walkers/overseer_ne_09.png new file mode 100644 index 0000000000..7d4c128ce0 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_09.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_10.png b/res/assets/Graphics/Walkers/overseer_ne_10.png new file mode 100644 index 0000000000..cdb9e5abe5 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_10.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_11.png b/res/assets/Graphics/Walkers/overseer_ne_11.png new file mode 100644 index 0000000000..6c87e2fbe7 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_11.png differ diff --git a/res/assets/Graphics/Walkers/overseer_ne_12.png b/res/assets/Graphics/Walkers/overseer_ne_12.png new file mode 100644 index 0000000000..eebaf6c90e Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_ne_12.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_01.png b/res/assets/Graphics/Walkers/overseer_nw_01.png new file mode 100644 index 0000000000..66a6aab292 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_01.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_02.png b/res/assets/Graphics/Walkers/overseer_nw_02.png new file mode 100644 index 0000000000..67db536fcf Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_02.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_03.png b/res/assets/Graphics/Walkers/overseer_nw_03.png new file mode 100644 index 0000000000..bb70c75259 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_03.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_04.png b/res/assets/Graphics/Walkers/overseer_nw_04.png new file mode 100644 index 0000000000..44fde78674 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_04.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_05.png b/res/assets/Graphics/Walkers/overseer_nw_05.png new file mode 100644 index 0000000000..169ac2d85e Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_05.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_06.png b/res/assets/Graphics/Walkers/overseer_nw_06.png new file mode 100644 index 0000000000..3059c308f9 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_06.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_07.png b/res/assets/Graphics/Walkers/overseer_nw_07.png new file mode 100644 index 0000000000..4ee101eaef Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_07.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_08.png b/res/assets/Graphics/Walkers/overseer_nw_08.png new file mode 100644 index 0000000000..ff8086850b Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_08.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_09.png b/res/assets/Graphics/Walkers/overseer_nw_09.png new file mode 100644 index 0000000000..2cdd50fb14 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_09.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_10.png b/res/assets/Graphics/Walkers/overseer_nw_10.png new file mode 100644 index 0000000000..8257548967 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_10.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_11.png b/res/assets/Graphics/Walkers/overseer_nw_11.png new file mode 100644 index 0000000000..9c2d1a4f40 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_11.png differ diff --git a/res/assets/Graphics/Walkers/overseer_nw_12.png b/res/assets/Graphics/Walkers/overseer_nw_12.png new file mode 100644 index 0000000000..23ab4880f4 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_nw_12.png differ diff --git a/res/assets/Graphics/Walkers/overseer_portrait_overlay.png b/res/assets/Graphics/Walkers/overseer_portrait_overlay.png new file mode 100644 index 0000000000..db9adc5da8 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_portrait_overlay.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_01.png b/res/assets/Graphics/Walkers/overseer_s_01.png new file mode 100644 index 0000000000..f0fc29d824 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_01.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_02.png b/res/assets/Graphics/Walkers/overseer_s_02.png new file mode 100644 index 0000000000..5ceeb39a8c Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_02.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_03.png b/res/assets/Graphics/Walkers/overseer_s_03.png new file mode 100644 index 0000000000..f57e1f629c Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_03.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_04.png b/res/assets/Graphics/Walkers/overseer_s_04.png new file mode 100644 index 0000000000..d5cda56f99 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_04.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_05.png b/res/assets/Graphics/Walkers/overseer_s_05.png new file mode 100644 index 0000000000..fc699f18c5 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_05.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_06.png b/res/assets/Graphics/Walkers/overseer_s_06.png new file mode 100644 index 0000000000..38cb45a14a Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_06.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_07.png b/res/assets/Graphics/Walkers/overseer_s_07.png new file mode 100644 index 0000000000..850b7201a0 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_07.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_08.png b/res/assets/Graphics/Walkers/overseer_s_08.png new file mode 100644 index 0000000000..93262563ab Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_08.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_09.png b/res/assets/Graphics/Walkers/overseer_s_09.png new file mode 100644 index 0000000000..507202cb86 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_09.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_10.png b/res/assets/Graphics/Walkers/overseer_s_10.png new file mode 100644 index 0000000000..8fbc45c0b0 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_10.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_11.png b/res/assets/Graphics/Walkers/overseer_s_11.png new file mode 100644 index 0000000000..0fe6f79e0e Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_11.png differ diff --git a/res/assets/Graphics/Walkers/overseer_s_12.png b/res/assets/Graphics/Walkers/overseer_s_12.png new file mode 100644 index 0000000000..b35c416e8a Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_s_12.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_01.png b/res/assets/Graphics/Walkers/overseer_se_01.png new file mode 100644 index 0000000000..b8d56dc5f2 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_01.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_02.png b/res/assets/Graphics/Walkers/overseer_se_02.png new file mode 100644 index 0000000000..efd411bfe7 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_02.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_03.png b/res/assets/Graphics/Walkers/overseer_se_03.png new file mode 100644 index 0000000000..860e1572a5 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_03.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_04.png b/res/assets/Graphics/Walkers/overseer_se_04.png new file mode 100644 index 0000000000..0484d9baf4 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_04.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_05.png b/res/assets/Graphics/Walkers/overseer_se_05.png new file mode 100644 index 0000000000..4cff7b3a8d Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_05.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_06.png b/res/assets/Graphics/Walkers/overseer_se_06.png new file mode 100644 index 0000000000..acad760077 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_06.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_07.png b/res/assets/Graphics/Walkers/overseer_se_07.png new file mode 100644 index 0000000000..6d27daca0f Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_07.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_08.png b/res/assets/Graphics/Walkers/overseer_se_08.png new file mode 100644 index 0000000000..2bc19235d4 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_08.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_09.png b/res/assets/Graphics/Walkers/overseer_se_09.png new file mode 100644 index 0000000000..c5718714ce Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_09.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_10.png b/res/assets/Graphics/Walkers/overseer_se_10.png new file mode 100644 index 0000000000..52084d90e2 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_10.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_11.png b/res/assets/Graphics/Walkers/overseer_se_11.png new file mode 100644 index 0000000000..f18a0748d1 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_11.png differ diff --git a/res/assets/Graphics/Walkers/overseer_se_12.png b/res/assets/Graphics/Walkers/overseer_se_12.png new file mode 100644 index 0000000000..51b3745449 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_se_12.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_01.png b/res/assets/Graphics/Walkers/overseer_sw_01.png new file mode 100644 index 0000000000..41dd8a0298 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_01.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_02.png b/res/assets/Graphics/Walkers/overseer_sw_02.png new file mode 100644 index 0000000000..625576f459 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_02.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_03.png b/res/assets/Graphics/Walkers/overseer_sw_03.png new file mode 100644 index 0000000000..4175460c4a Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_03.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_04.png b/res/assets/Graphics/Walkers/overseer_sw_04.png new file mode 100644 index 0000000000..4b4f53be1b Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_04.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_05.png b/res/assets/Graphics/Walkers/overseer_sw_05.png new file mode 100644 index 0000000000..87f13a5fb8 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_05.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_06.png b/res/assets/Graphics/Walkers/overseer_sw_06.png new file mode 100644 index 0000000000..4c36b275a1 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_06.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_07.png b/res/assets/Graphics/Walkers/overseer_sw_07.png new file mode 100644 index 0000000000..ee2faf8fdc Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_07.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_08.png b/res/assets/Graphics/Walkers/overseer_sw_08.png new file mode 100644 index 0000000000..6ce41e5362 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_08.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_09.png b/res/assets/Graphics/Walkers/overseer_sw_09.png new file mode 100644 index 0000000000..aedc1f579b Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_09.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_10.png b/res/assets/Graphics/Walkers/overseer_sw_10.png new file mode 100644 index 0000000000..0ca611f843 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_10.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_11.png b/res/assets/Graphics/Walkers/overseer_sw_11.png new file mode 100644 index 0000000000..b888bad556 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_11.png differ diff --git a/res/assets/Graphics/Walkers/overseer_sw_12.png b/res/assets/Graphics/Walkers/overseer_sw_12.png new file mode 100644 index 0000000000..2980679150 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_sw_12.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_01.png b/res/assets/Graphics/Walkers/overseer_w_01.png new file mode 100644 index 0000000000..ac74adea9f Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_01.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_02.png b/res/assets/Graphics/Walkers/overseer_w_02.png new file mode 100644 index 0000000000..b5d24abf4a Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_02.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_03.png b/res/assets/Graphics/Walkers/overseer_w_03.png new file mode 100644 index 0000000000..66f889aa55 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_03.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_04.png b/res/assets/Graphics/Walkers/overseer_w_04.png new file mode 100644 index 0000000000..9e28830c6d Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_04.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_05.png b/res/assets/Graphics/Walkers/overseer_w_05.png new file mode 100644 index 0000000000..c752b0850c Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_05.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_06.png b/res/assets/Graphics/Walkers/overseer_w_06.png new file mode 100644 index 0000000000..9194fcd945 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_06.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_07.png b/res/assets/Graphics/Walkers/overseer_w_07.png new file mode 100644 index 0000000000..0b5c977c84 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_07.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_08.png b/res/assets/Graphics/Walkers/overseer_w_08.png new file mode 100644 index 0000000000..89f56da306 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_08.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_09.png b/res/assets/Graphics/Walkers/overseer_w_09.png new file mode 100644 index 0000000000..31233c9173 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_09.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_10.png b/res/assets/Graphics/Walkers/overseer_w_10.png new file mode 100644 index 0000000000..81d22386d1 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_10.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_11.png b/res/assets/Graphics/Walkers/overseer_w_11.png new file mode 100644 index 0000000000..56895643d4 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_11.png differ diff --git a/res/assets/Graphics/Walkers/overseer_w_12.png b/res/assets/Graphics/Walkers/overseer_w_12.png new file mode 100644 index 0000000000..44ecee0538 Binary files /dev/null and b/res/assets/Graphics/Walkers/overseer_w_12.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_e_01.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_e_01.png new file mode 100644 index 0000000000..0aeb1682ab Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_e_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_e_02.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_e_02.png new file mode 100644 index 0000000000..b1151a28cf Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_e_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_e_03.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_e_03.png new file mode 100644 index 0000000000..013e7e8825 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_e_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_e_04.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_e_04.png new file mode 100644 index 0000000000..c8e3a37012 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_e_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_e_05.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_e_05.png new file mode 100644 index 0000000000..acbdde79dd Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_e_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_n_01.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_n_01.png new file mode 100644 index 0000000000..1b893d0887 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_n_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_n_02.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_n_02.png new file mode 100644 index 0000000000..d2ead64736 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_n_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_n_03.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_n_03.png new file mode 100644 index 0000000000..bfd450b0f1 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_n_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_n_04.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_n_04.png new file mode 100644 index 0000000000..c4301211ab Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_n_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_n_05.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_n_05.png new file mode 100644 index 0000000000..0c82fef49c Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_n_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_01.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_01.png new file mode 100644 index 0000000000..abec23002b Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_02.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_02.png new file mode 100644 index 0000000000..59bdfa8fb5 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_03.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_03.png new file mode 100644 index 0000000000..986701085d Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_04.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_04.png new file mode 100644 index 0000000000..00be182fac Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_05.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_05.png new file mode 100644 index 0000000000..67579ad8f8 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_ne_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_01.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_01.png new file mode 100644 index 0000000000..7f1edf6287 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_02.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_02.png new file mode 100644 index 0000000000..9eda3aa4cf Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_03.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_03.png new file mode 100644 index 0000000000..aa29045d51 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_04.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_04.png new file mode 100644 index 0000000000..68e2183394 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_05.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_05.png new file mode 100644 index 0000000000..bf0a271e4a Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_nw_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_s_01.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_s_01.png new file mode 100644 index 0000000000..ed87243b3e Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_s_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_s_02.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_s_02.png new file mode 100644 index 0000000000..0608b079e9 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_s_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_s_03.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_s_03.png new file mode 100644 index 0000000000..4d546c9dbd Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_s_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_s_04.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_s_04.png new file mode 100644 index 0000000000..6b28004f0a Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_s_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_s_05.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_s_05.png new file mode 100644 index 0000000000..0dae4ccde4 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_s_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_se_01.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_se_01.png new file mode 100644 index 0000000000..a87d02c827 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_se_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_se_02.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_se_02.png new file mode 100644 index 0000000000..ac65a13926 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_se_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_se_03.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_se_03.png new file mode 100644 index 0000000000..3f446799b7 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_se_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_se_04.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_se_04.png new file mode 100644 index 0000000000..61f1d4cd26 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_se_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_se_05.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_se_05.png new file mode 100644 index 0000000000..3875b2863d Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_se_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_01.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_01.png new file mode 100644 index 0000000000..e6b6bbdb00 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_02.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_02.png new file mode 100644 index 0000000000..35489feb12 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_03.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_03.png new file mode 100644 index 0000000000..753f9e2f9a Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_04.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_04.png new file mode 100644 index 0000000000..38b368d24d Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_05.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_05.png new file mode 100644 index 0000000000..d7001d3379 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_sw_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_w_01.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_w_01.png new file mode 100644 index 0000000000..1eb870a6a2 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_w_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_w_02.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_w_02.png new file mode 100644 index 0000000000..9ab13eebae Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_w_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_w_03.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_w_03.png new file mode 100644 index 0000000000..c08909aef2 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_w_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_w_04.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_w_04.png new file mode 100644 index 0000000000..d96dc5e316 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_w_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_legionary_fr_w_05.png b/res/assets/Graphics/Warriors/caesar_legionary_fr_w_05.png new file mode 100644 index 0000000000..d090b73d41 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_legionary_fr_w_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_death_01.png b/res/assets/Graphics/Warriors/caesar_sentry_death_01.png new file mode 100644 index 0000000000..d43f0e2576 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_death_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_death_02.png b/res/assets/Graphics/Warriors/caesar_sentry_death_02.png new file mode 100644 index 0000000000..7bc98a2f27 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_death_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_death_03.png b/res/assets/Graphics/Warriors/caesar_sentry_death_03.png new file mode 100644 index 0000000000..0e92ed2de4 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_death_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_death_04.png b/res/assets/Graphics/Warriors/caesar_sentry_death_04.png new file mode 100644 index 0000000000..41fa1b7555 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_death_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_death_05.png b/res/assets/Graphics/Warriors/caesar_sentry_death_05.png new file mode 100644 index 0000000000..5bac962ad5 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_death_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_01.png b/res/assets/Graphics/Warriors/caesar_sentry_e_01.png new file mode 100644 index 0000000000..8d752f6ecb Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_02.png b/res/assets/Graphics/Warriors/caesar_sentry_e_02.png new file mode 100644 index 0000000000..43b8018ecd Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_03.png b/res/assets/Graphics/Warriors/caesar_sentry_e_03.png new file mode 100644 index 0000000000..0eb910fd79 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_04.png b/res/assets/Graphics/Warriors/caesar_sentry_e_04.png new file mode 100644 index 0000000000..50de7ebc13 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_05.png b/res/assets/Graphics/Warriors/caesar_sentry_e_05.png new file mode 100644 index 0000000000..153d488ded Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_06.png b/res/assets/Graphics/Warriors/caesar_sentry_e_06.png new file mode 100644 index 0000000000..58bcbeb679 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_06.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_07.png b/res/assets/Graphics/Warriors/caesar_sentry_e_07.png new file mode 100644 index 0000000000..0ee6d5ab9d Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_07.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_08.png b/res/assets/Graphics/Warriors/caesar_sentry_e_08.png new file mode 100644 index 0000000000..94d921c463 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_08.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_09.png b/res/assets/Graphics/Warriors/caesar_sentry_e_09.png new file mode 100644 index 0000000000..2a8cf7c930 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_09.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_10.png b/res/assets/Graphics/Warriors/caesar_sentry_e_10.png new file mode 100644 index 0000000000..0ec4368eb6 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_10.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_11.png b/res/assets/Graphics/Warriors/caesar_sentry_e_11.png new file mode 100644 index 0000000000..09fce277d1 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_11.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_e_12.png b/res/assets/Graphics/Warriors/caesar_sentry_e_12.png new file mode 100644 index 0000000000..efa67c4c88 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_e_12.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_e_01.png b/res/assets/Graphics/Warriors/caesar_sentry_f_e_01.png new file mode 100644 index 0000000000..d135096710 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_e_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_e_02.png b/res/assets/Graphics/Warriors/caesar_sentry_f_e_02.png new file mode 100644 index 0000000000..a4ab7fe8b1 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_e_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_e_03.png b/res/assets/Graphics/Warriors/caesar_sentry_f_e_03.png new file mode 100644 index 0000000000..dc2e848372 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_e_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_e_04.png b/res/assets/Graphics/Warriors/caesar_sentry_f_e_04.png new file mode 100644 index 0000000000..84cf9f6167 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_e_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_e_05.png b/res/assets/Graphics/Warriors/caesar_sentry_f_e_05.png new file mode 100644 index 0000000000..69f28a3d7e Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_e_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_n_01.png b/res/assets/Graphics/Warriors/caesar_sentry_f_n_01.png new file mode 100644 index 0000000000..dbff71bc6b Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_n_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_n_02.png b/res/assets/Graphics/Warriors/caesar_sentry_f_n_02.png new file mode 100644 index 0000000000..d93b5b25b4 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_n_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_n_03.png b/res/assets/Graphics/Warriors/caesar_sentry_f_n_03.png new file mode 100644 index 0000000000..961d9b688b Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_n_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_n_04.png b/res/assets/Graphics/Warriors/caesar_sentry_f_n_04.png new file mode 100644 index 0000000000..a2ae529112 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_n_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_n_05.png b/res/assets/Graphics/Warriors/caesar_sentry_f_n_05.png new file mode 100644 index 0000000000..aa86acc879 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_n_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_ne_01.png b/res/assets/Graphics/Warriors/caesar_sentry_f_ne_01.png new file mode 100644 index 0000000000..c70848245d Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_ne_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_ne_02.png b/res/assets/Graphics/Warriors/caesar_sentry_f_ne_02.png new file mode 100644 index 0000000000..6e9af9fae6 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_ne_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_ne_03.png b/res/assets/Graphics/Warriors/caesar_sentry_f_ne_03.png new file mode 100644 index 0000000000..3068bfd60f Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_ne_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_ne_04.png b/res/assets/Graphics/Warriors/caesar_sentry_f_ne_04.png new file mode 100644 index 0000000000..b858962162 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_ne_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_ne_05.png b/res/assets/Graphics/Warriors/caesar_sentry_f_ne_05.png new file mode 100644 index 0000000000..8808cf60b1 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_ne_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_nw_01.png b/res/assets/Graphics/Warriors/caesar_sentry_f_nw_01.png new file mode 100644 index 0000000000..52ecd49c2f Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_nw_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_nw_02.png b/res/assets/Graphics/Warriors/caesar_sentry_f_nw_02.png new file mode 100644 index 0000000000..6f12c8a0be Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_nw_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_nw_03.png b/res/assets/Graphics/Warriors/caesar_sentry_f_nw_03.png new file mode 100644 index 0000000000..3a99971e33 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_nw_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_nw_04.png b/res/assets/Graphics/Warriors/caesar_sentry_f_nw_04.png new file mode 100644 index 0000000000..4bb997838e Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_nw_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_nw_05.png b/res/assets/Graphics/Warriors/caesar_sentry_f_nw_05.png new file mode 100644 index 0000000000..2e2b18c59a Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_nw_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_s_01.png b/res/assets/Graphics/Warriors/caesar_sentry_f_s_01.png new file mode 100644 index 0000000000..7a88cad6c2 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_s_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_s_02.png b/res/assets/Graphics/Warriors/caesar_sentry_f_s_02.png new file mode 100644 index 0000000000..b0dde8d8ad Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_s_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_s_03.png b/res/assets/Graphics/Warriors/caesar_sentry_f_s_03.png new file mode 100644 index 0000000000..626a0d37f1 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_s_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_s_04.png b/res/assets/Graphics/Warriors/caesar_sentry_f_s_04.png new file mode 100644 index 0000000000..1f401b4275 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_s_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_s_05.png b/res/assets/Graphics/Warriors/caesar_sentry_f_s_05.png new file mode 100644 index 0000000000..45d31d9345 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_s_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_se_01.png b/res/assets/Graphics/Warriors/caesar_sentry_f_se_01.png new file mode 100644 index 0000000000..cf368085ab Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_se_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_se_02.png b/res/assets/Graphics/Warriors/caesar_sentry_f_se_02.png new file mode 100644 index 0000000000..42a00b7469 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_se_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_se_03.png b/res/assets/Graphics/Warriors/caesar_sentry_f_se_03.png new file mode 100644 index 0000000000..b73dcd0080 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_se_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_se_04.png b/res/assets/Graphics/Warriors/caesar_sentry_f_se_04.png new file mode 100644 index 0000000000..24a1b7d90e Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_se_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_se_05.png b/res/assets/Graphics/Warriors/caesar_sentry_f_se_05.png new file mode 100644 index 0000000000..c940f50688 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_se_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_sw_01.png b/res/assets/Graphics/Warriors/caesar_sentry_f_sw_01.png new file mode 100644 index 0000000000..62d7234ee4 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_sw_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_sw_02.png b/res/assets/Graphics/Warriors/caesar_sentry_f_sw_02.png new file mode 100644 index 0000000000..206554ae19 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_sw_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_sw_03.png b/res/assets/Graphics/Warriors/caesar_sentry_f_sw_03.png new file mode 100644 index 0000000000..fa5e408070 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_sw_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_sw_04.png b/res/assets/Graphics/Warriors/caesar_sentry_f_sw_04.png new file mode 100644 index 0000000000..e3b8352746 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_sw_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_sw_05.png b/res/assets/Graphics/Warriors/caesar_sentry_f_sw_05.png new file mode 100644 index 0000000000..854662cf46 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_sw_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_w_01.png b/res/assets/Graphics/Warriors/caesar_sentry_f_w_01.png new file mode 100644 index 0000000000..837e686090 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_w_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_w_02.png b/res/assets/Graphics/Warriors/caesar_sentry_f_w_02.png new file mode 100644 index 0000000000..72f8b6a50d Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_w_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_w_03.png b/res/assets/Graphics/Warriors/caesar_sentry_f_w_03.png new file mode 100644 index 0000000000..e050260030 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_w_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_w_04.png b/res/assets/Graphics/Warriors/caesar_sentry_f_w_04.png new file mode 100644 index 0000000000..5005f110f5 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_w_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_f_w_05.png b/res/assets/Graphics/Warriors/caesar_sentry_f_w_05.png new file mode 100644 index 0000000000..c775656ff7 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_f_w_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_01.png b/res/assets/Graphics/Warriors/caesar_sentry_n_01.png new file mode 100644 index 0000000000..6ea1d4a2fa Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_02.png b/res/assets/Graphics/Warriors/caesar_sentry_n_02.png new file mode 100644 index 0000000000..23b6508fc9 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_03.png b/res/assets/Graphics/Warriors/caesar_sentry_n_03.png new file mode 100644 index 0000000000..1575f0e543 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_04.png b/res/assets/Graphics/Warriors/caesar_sentry_n_04.png new file mode 100644 index 0000000000..9a5d8f1592 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_05.png b/res/assets/Graphics/Warriors/caesar_sentry_n_05.png new file mode 100644 index 0000000000..719e696e52 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_06.png b/res/assets/Graphics/Warriors/caesar_sentry_n_06.png new file mode 100644 index 0000000000..331be81147 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_06.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_07.png b/res/assets/Graphics/Warriors/caesar_sentry_n_07.png new file mode 100644 index 0000000000..220ba0d4e4 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_07.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_08.png b/res/assets/Graphics/Warriors/caesar_sentry_n_08.png new file mode 100644 index 0000000000..10098bcc10 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_08.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_09.png b/res/assets/Graphics/Warriors/caesar_sentry_n_09.png new file mode 100644 index 0000000000..5cf930606a Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_09.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_10.png b/res/assets/Graphics/Warriors/caesar_sentry_n_10.png new file mode 100644 index 0000000000..9c21acea64 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_10.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_11.png b/res/assets/Graphics/Warriors/caesar_sentry_n_11.png new file mode 100644 index 0000000000..d172464dd3 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_11.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_n_12.png b/res/assets/Graphics/Warriors/caesar_sentry_n_12.png new file mode 100644 index 0000000000..bd6d3febb6 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_n_12.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_01.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_01.png new file mode 100644 index 0000000000..2ce6fa8a95 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_02.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_02.png new file mode 100644 index 0000000000..6b13892907 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_03.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_03.png new file mode 100644 index 0000000000..a340756822 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_04.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_04.png new file mode 100644 index 0000000000..b704aa707a Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_05.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_05.png new file mode 100644 index 0000000000..3e4f4fe12e Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_06.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_06.png new file mode 100644 index 0000000000..41409e5261 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_06.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_07.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_07.png new file mode 100644 index 0000000000..63dc0aab32 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_07.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_08.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_08.png new file mode 100644 index 0000000000..05ecd2e745 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_08.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_09.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_09.png new file mode 100644 index 0000000000..28f68304eb Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_09.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_10.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_10.png new file mode 100644 index 0000000000..1006533465 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_10.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_11.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_11.png new file mode 100644 index 0000000000..240f7ae16b Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_11.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_ne_12.png b/res/assets/Graphics/Warriors/caesar_sentry_ne_12.png new file mode 100644 index 0000000000..4f8761c40c Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_ne_12.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_01.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_01.png new file mode 100644 index 0000000000..5d808d2ab5 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_02.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_02.png new file mode 100644 index 0000000000..792802ccde Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_03.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_03.png new file mode 100644 index 0000000000..466ae55a61 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_04.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_04.png new file mode 100644 index 0000000000..59a56aa916 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_05.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_05.png new file mode 100644 index 0000000000..06d84772ad Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_06.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_06.png new file mode 100644 index 0000000000..eb9063a488 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_06.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_07.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_07.png new file mode 100644 index 0000000000..2d36d2e092 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_07.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_08.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_08.png new file mode 100644 index 0000000000..405c9314bf Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_08.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_09.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_09.png new file mode 100644 index 0000000000..e997a0b3f0 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_09.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_10.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_10.png new file mode 100644 index 0000000000..6a9832701b Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_10.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_11.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_11.png new file mode 100644 index 0000000000..b649d7646b Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_11.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_nw_12.png b/res/assets/Graphics/Warriors/caesar_sentry_nw_12.png new file mode 100644 index 0000000000..691f8abcf6 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_nw_12.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_01.png b/res/assets/Graphics/Warriors/caesar_sentry_s_01.png new file mode 100644 index 0000000000..0a01fc60a4 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_02.png b/res/assets/Graphics/Warriors/caesar_sentry_s_02.png new file mode 100644 index 0000000000..1812509769 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_03.png b/res/assets/Graphics/Warriors/caesar_sentry_s_03.png new file mode 100644 index 0000000000..3b3b9ddebf Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_04.png b/res/assets/Graphics/Warriors/caesar_sentry_s_04.png new file mode 100644 index 0000000000..5b577e2816 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_05.png b/res/assets/Graphics/Warriors/caesar_sentry_s_05.png new file mode 100644 index 0000000000..f2a2807227 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_06.png b/res/assets/Graphics/Warriors/caesar_sentry_s_06.png new file mode 100644 index 0000000000..9d4907f5ca Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_06.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_07.png b/res/assets/Graphics/Warriors/caesar_sentry_s_07.png new file mode 100644 index 0000000000..89a536cca6 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_07.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_08.png b/res/assets/Graphics/Warriors/caesar_sentry_s_08.png new file mode 100644 index 0000000000..ea22c6ba03 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_08.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_09.png b/res/assets/Graphics/Warriors/caesar_sentry_s_09.png new file mode 100644 index 0000000000..7ddfdf7798 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_09.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_10.png b/res/assets/Graphics/Warriors/caesar_sentry_s_10.png new file mode 100644 index 0000000000..e8adc85527 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_10.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_11.png b/res/assets/Graphics/Warriors/caesar_sentry_s_11.png new file mode 100644 index 0000000000..e206abc135 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_11.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_s_12.png b/res/assets/Graphics/Warriors/caesar_sentry_s_12.png new file mode 100644 index 0000000000..10e6f28d1b Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_s_12.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_01.png b/res/assets/Graphics/Warriors/caesar_sentry_se_01.png new file mode 100644 index 0000000000..fc4d4a892b Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_02.png b/res/assets/Graphics/Warriors/caesar_sentry_se_02.png new file mode 100644 index 0000000000..91bd975125 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_03.png b/res/assets/Graphics/Warriors/caesar_sentry_se_03.png new file mode 100644 index 0000000000..ff124a0fb4 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_04.png b/res/assets/Graphics/Warriors/caesar_sentry_se_04.png new file mode 100644 index 0000000000..b2165e16ff Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_05.png b/res/assets/Graphics/Warriors/caesar_sentry_se_05.png new file mode 100644 index 0000000000..50621c934a Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_06.png b/res/assets/Graphics/Warriors/caesar_sentry_se_06.png new file mode 100644 index 0000000000..322a35b591 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_06.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_07.png b/res/assets/Graphics/Warriors/caesar_sentry_se_07.png new file mode 100644 index 0000000000..cce3ff52e2 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_07.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_08.png b/res/assets/Graphics/Warriors/caesar_sentry_se_08.png new file mode 100644 index 0000000000..49dc724e30 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_08.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_09.png b/res/assets/Graphics/Warriors/caesar_sentry_se_09.png new file mode 100644 index 0000000000..af50bf69db Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_09.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_10.png b/res/assets/Graphics/Warriors/caesar_sentry_se_10.png new file mode 100644 index 0000000000..07dd62ed47 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_10.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_11.png b/res/assets/Graphics/Warriors/caesar_sentry_se_11.png new file mode 100644 index 0000000000..0be9299c45 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_11.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_se_12.png b/res/assets/Graphics/Warriors/caesar_sentry_se_12.png new file mode 100644 index 0000000000..e10f4d2c38 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_se_12.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_01.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_01.png new file mode 100644 index 0000000000..632b1b8f0f Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_02.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_02.png new file mode 100644 index 0000000000..279ee51046 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_03.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_03.png new file mode 100644 index 0000000000..0392bb22e0 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_04.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_04.png new file mode 100644 index 0000000000..1835c8bd0b Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_05.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_05.png new file mode 100644 index 0000000000..445935be7d Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_06.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_06.png new file mode 100644 index 0000000000..539cb9104f Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_06.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_07.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_07.png new file mode 100644 index 0000000000..99bd8fa2e1 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_07.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_08.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_08.png new file mode 100644 index 0000000000..b4dbf18e2b Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_08.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_09.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_09.png new file mode 100644 index 0000000000..34b8e19f03 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_09.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_10.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_10.png new file mode 100644 index 0000000000..8adfcce826 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_10.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_11.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_11.png new file mode 100644 index 0000000000..be469203b3 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_11.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_sw_12.png b/res/assets/Graphics/Warriors/caesar_sentry_sw_12.png new file mode 100644 index 0000000000..fb27422298 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_sw_12.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_01.png b/res/assets/Graphics/Warriors/caesar_sentry_w_01.png new file mode 100644 index 0000000000..2cecce8901 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_01.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_02.png b/res/assets/Graphics/Warriors/caesar_sentry_w_02.png new file mode 100644 index 0000000000..ff2853c1c5 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_02.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_03.png b/res/assets/Graphics/Warriors/caesar_sentry_w_03.png new file mode 100644 index 0000000000..eb4c0bee45 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_03.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_04.png b/res/assets/Graphics/Warriors/caesar_sentry_w_04.png new file mode 100644 index 0000000000..95cb694549 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_04.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_05.png b/res/assets/Graphics/Warriors/caesar_sentry_w_05.png new file mode 100644 index 0000000000..1c2cc8198f Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_05.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_06.png b/res/assets/Graphics/Warriors/caesar_sentry_w_06.png new file mode 100644 index 0000000000..4e9d5e0c17 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_06.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_07.png b/res/assets/Graphics/Warriors/caesar_sentry_w_07.png new file mode 100644 index 0000000000..a586e9f5e4 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_07.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_08.png b/res/assets/Graphics/Warriors/caesar_sentry_w_08.png new file mode 100644 index 0000000000..2fad7a583d Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_08.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_09.png b/res/assets/Graphics/Warriors/caesar_sentry_w_09.png new file mode 100644 index 0000000000..df4b4ccb8e Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_09.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_10.png b/res/assets/Graphics/Warriors/caesar_sentry_w_10.png new file mode 100644 index 0000000000..14894a9939 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_10.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_11.png b/res/assets/Graphics/Warriors/caesar_sentry_w_11.png new file mode 100644 index 0000000000..cedb9085b4 Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_11.png differ diff --git a/res/assets/Graphics/Warriors/caesar_sentry_w_12.png b/res/assets/Graphics/Warriors/caesar_sentry_w_12.png new file mode 100644 index 0000000000..3cdd1e762f Binary files /dev/null and b/res/assets/Graphics/Warriors/caesar_sentry_w_12.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_e_01.png b/res/assets/Graphics/Warriors/legionary_fr_e_01.png new file mode 100644 index 0000000000..be9398b046 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_e_01.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_e_02.png b/res/assets/Graphics/Warriors/legionary_fr_e_02.png new file mode 100644 index 0000000000..bdbc729cb7 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_e_02.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_e_03.png b/res/assets/Graphics/Warriors/legionary_fr_e_03.png new file mode 100644 index 0000000000..3a431e2384 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_e_03.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_e_04.png b/res/assets/Graphics/Warriors/legionary_fr_e_04.png new file mode 100644 index 0000000000..74320b65ff Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_e_04.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_e_05.png b/res/assets/Graphics/Warriors/legionary_fr_e_05.png new file mode 100644 index 0000000000..68c9c2ee39 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_e_05.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_n_01.png b/res/assets/Graphics/Warriors/legionary_fr_n_01.png new file mode 100644 index 0000000000..b3bc805e11 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_n_01.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_n_02.png b/res/assets/Graphics/Warriors/legionary_fr_n_02.png new file mode 100644 index 0000000000..a1e18afbe3 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_n_02.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_n_03.png b/res/assets/Graphics/Warriors/legionary_fr_n_03.png new file mode 100644 index 0000000000..d05e1a85ad Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_n_03.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_n_04.png b/res/assets/Graphics/Warriors/legionary_fr_n_04.png new file mode 100644 index 0000000000..e3f8ca80ca Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_n_04.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_n_05.png b/res/assets/Graphics/Warriors/legionary_fr_n_05.png new file mode 100644 index 0000000000..5b63c05509 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_n_05.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_ne_01.png b/res/assets/Graphics/Warriors/legionary_fr_ne_01.png new file mode 100644 index 0000000000..8b21bbf757 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_ne_01.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_ne_02.png b/res/assets/Graphics/Warriors/legionary_fr_ne_02.png new file mode 100644 index 0000000000..c211a666c3 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_ne_02.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_ne_03.png b/res/assets/Graphics/Warriors/legionary_fr_ne_03.png new file mode 100644 index 0000000000..afbd1b7c32 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_ne_03.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_ne_04.png b/res/assets/Graphics/Warriors/legionary_fr_ne_04.png new file mode 100644 index 0000000000..0b767f08c5 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_ne_04.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_ne_05.png b/res/assets/Graphics/Warriors/legionary_fr_ne_05.png new file mode 100644 index 0000000000..cbdee7ccfd Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_ne_05.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_nw_01.png b/res/assets/Graphics/Warriors/legionary_fr_nw_01.png new file mode 100644 index 0000000000..86b0958012 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_nw_01.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_nw_02.png b/res/assets/Graphics/Warriors/legionary_fr_nw_02.png new file mode 100644 index 0000000000..83518809c3 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_nw_02.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_nw_03.png b/res/assets/Graphics/Warriors/legionary_fr_nw_03.png new file mode 100644 index 0000000000..4e34b47fed Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_nw_03.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_nw_04.png b/res/assets/Graphics/Warriors/legionary_fr_nw_04.png new file mode 100644 index 0000000000..d2497f3b13 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_nw_04.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_nw_05.png b/res/assets/Graphics/Warriors/legionary_fr_nw_05.png new file mode 100644 index 0000000000..f6915fc73f Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_nw_05.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_s_01.png b/res/assets/Graphics/Warriors/legionary_fr_s_01.png new file mode 100644 index 0000000000..cba88a1775 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_s_01.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_s_02.png b/res/assets/Graphics/Warriors/legionary_fr_s_02.png new file mode 100644 index 0000000000..7392a0e6f8 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_s_02.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_s_03.png b/res/assets/Graphics/Warriors/legionary_fr_s_03.png new file mode 100644 index 0000000000..06a716ece1 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_s_03.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_s_04.png b/res/assets/Graphics/Warriors/legionary_fr_s_04.png new file mode 100644 index 0000000000..b4e43b7c1f Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_s_04.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_s_05.png b/res/assets/Graphics/Warriors/legionary_fr_s_05.png new file mode 100644 index 0000000000..8a6a94c700 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_s_05.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_se_01.png b/res/assets/Graphics/Warriors/legionary_fr_se_01.png new file mode 100644 index 0000000000..a970eda92b Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_se_01.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_se_02.png b/res/assets/Graphics/Warriors/legionary_fr_se_02.png new file mode 100644 index 0000000000..494043f5e7 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_se_02.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_se_03.png b/res/assets/Graphics/Warriors/legionary_fr_se_03.png new file mode 100644 index 0000000000..69c7599f40 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_se_03.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_se_04.png b/res/assets/Graphics/Warriors/legionary_fr_se_04.png new file mode 100644 index 0000000000..44e8e547e5 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_se_04.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_se_05.png b/res/assets/Graphics/Warriors/legionary_fr_se_05.png new file mode 100644 index 0000000000..80b69d4139 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_se_05.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_sw_01.png b/res/assets/Graphics/Warriors/legionary_fr_sw_01.png new file mode 100644 index 0000000000..eb36c4954d Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_sw_01.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_sw_02.png b/res/assets/Graphics/Warriors/legionary_fr_sw_02.png new file mode 100644 index 0000000000..8f087a78cf Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_sw_02.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_sw_03.png b/res/assets/Graphics/Warriors/legionary_fr_sw_03.png new file mode 100644 index 0000000000..c28185c2da Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_sw_03.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_sw_04.png b/res/assets/Graphics/Warriors/legionary_fr_sw_04.png new file mode 100644 index 0000000000..475428eaf5 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_sw_04.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_sw_05.png b/res/assets/Graphics/Warriors/legionary_fr_sw_05.png new file mode 100644 index 0000000000..3db6589c42 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_sw_05.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_w_01.png b/res/assets/Graphics/Warriors/legionary_fr_w_01.png new file mode 100644 index 0000000000..8248864906 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_w_01.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_w_02.png b/res/assets/Graphics/Warriors/legionary_fr_w_02.png new file mode 100644 index 0000000000..247bff1bb8 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_w_02.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_w_03.png b/res/assets/Graphics/Warriors/legionary_fr_w_03.png new file mode 100644 index 0000000000..fe760f5e54 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_w_03.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_w_04.png b/res/assets/Graphics/Warriors/legionary_fr_w_04.png new file mode 100644 index 0000000000..2b5b928d3b Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_w_04.png differ diff --git a/res/assets/Graphics/Warriors/legionary_fr_w_05.png b/res/assets/Graphics/Warriors/legionary_fr_w_05.png new file mode 100644 index 0000000000..74247f6515 Binary files /dev/null and b/res/assets/Graphics/Warriors/legionary_fr_w_05.png differ diff --git a/res/assets/Graphics/admin_logistics.xml b/res/assets/Graphics/admin_logistics.xml index 4b5846d208..8e640ffd15 100644 --- a/res/assets/Graphics/admin_logistics.xml +++ b/res/assets/Graphics/admin_logistics.xml @@ -260,11 +260,4 @@ - - - - - - - \ No newline at end of file diff --git a/res/assets/Graphics/monuments.xml b/res/assets/Graphics/monuments.xml index e277bd18f0..7a9eaf9c15 100644 --- a/res/assets/Graphics/monuments.xml +++ b/res/assets/Graphics/monuments.xml @@ -66,6 +66,16 @@ + + + + + + + + + + @@ -534,7 +544,13 @@ - + + + + + + + @@ -545,7 +561,11 @@ - + + + + + diff --git a/res/assets/Graphics/walkers.xml b/res/assets/Graphics/walkers.xml index 5072a2c159..857b883084 100644 --- a/res/assets/Graphics/walkers.xml +++ b/res/assets/Graphics/walkers.xml @@ -1521,7 +1521,7 @@ - + @@ -2923,5 +2923,1285 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/assets/Graphics/warriors.xml b/res/assets/Graphics/warriors.xml index ce72656b78..9d2ff00c1c 100644 --- a/res/assets/Graphics/warriors.xml +++ b/res/assets/Graphics/warriors.xml @@ -394,4 +394,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/augustus.metainfo.xml b/res/augustus.metainfo.xml index 26335d666f..e32f54769f 100644 --- a/res/augustus.metainfo.xml +++ b/res/augustus.metainfo.xml @@ -4,7 +4,7 @@ CC0-1.0 AGPL-3.0 Augustus - Augustus is an open source re-implementation of Caesar III with changes to gameplay + Roman city management game

Augustus is an open source re-implementation of Caesar III with changes to gameplay.

The aim of this project is to provide enhanced, customizable gameplay to Caesar 3 using project Julius UI enhancements.

@@ -19,32 +19,62 @@
  • Roadblocks
  • Market special orders
  • Partial warehouse storage
  • -
  • Increased game limits
  • - +
  • No game building or walker limits
  • +
  • Monument construction
  • +
  • Improved map editor with custom enents
  • +
  • Custom campaigns
  • +

    Augustus requires the original assets (graphics, sounds, etc) from Caesar 3 to run. It optionally supports the high-quality MP3 files once provided on the Sierra website.

    com.github.keriew.augustus.desktop https://raw.githubusercontent.com/keriew/augustus/master/doc/main-image.png + A full city in Augustus - - - - - - - - - + + https://github.com/Keriew/augustus/releases/tag/v4.0.0 + + + https://github.com/Keriew/augustus/releases/tag/v3.2.0 + + + https://github.com/Keriew/augustus/releases/tag/v3.1.0 + + + https://github.com/Keriew/augustus/releases/tag/v3.0.1 + + + https://github.com/Keriew/augustus/releases/tag/v2.0.1 + + + https://github.com/Keriew/augustus/releases/tag/v2.0.0 + + + https://github.com/Keriew/augustus/releases/tag/v1.4.1a + + + https://github.com/Keriew/augustus/releases/tag/v1.4.1 + + + https://github.com/Keriew/augustus/releases/tag/v1.4.0 + https://github.com/Keriew/augustus - Augustus Dev Team + https://github.com/Keriew/augustus/issues + https://github.com/Keriew/augustus/blob/master/res/manual/augustus_manual_en_4_0.pdf + + Augustus Dev Team + moderate + mild + mild + mild + mild diff --git a/res/com.github.keriew.augustus.json b/res/com.github.keriew.augustus.json new file mode 100644 index 0000000000..ee8c2ed277 --- /dev/null +++ b/res/com.github.keriew.augustus.json @@ -0,0 +1,26 @@ +{ + "id" : "com.github.keriew.augustus", + "runtime" : "org.freedesktop.Platform", + "runtime-version" : "23.08", + "sdk" : "org.freedesktop.Sdk", + "command" : "augustus", + "finish-args" : [ + "--share=ipc", + "--device=dri", + "--socket=wayland", + "--socket=fallback-x11", + "--socket=pulseaudio" + ], + "modules" : [ + { + "name" : "augustus", + "buildsystem" : "cmake-ninja", + "sources" : [ + { + "type" : "dir", + "path" : ".." + } + ] + } + ] +} diff --git a/src/assets/group.c b/src/assets/group.c index 52610ccd23..f1f1e51a94 100644 --- a/src/assets/group.c +++ b/src/assets/group.c @@ -53,7 +53,7 @@ void group_set_for_external_files(void) log_error("Failed to allocate memory for external files group name. The game will now crash.", 0, 0); return; } - strcpy(name, ASSET_EXTERNAL_FILE_LIST); + memcpy(name, ASSET_EXTERNAL_FILE_LIST, sizeof(ASSET_EXTERNAL_FILE_LIST)); external_files_group->name = name; external_files_group->first_image_index = -1; external_files_group->last_image_index = -1; diff --git a/src/assets/image.c b/src/assets/image.c index 1d5c77150b..dcefd3dcf1 100644 --- a/src/assets/image.c +++ b/src/assets/image.c @@ -713,7 +713,7 @@ const asset_image *asset_image_create_external(const char *filename) asset_image_unload(img); return 0; } - strcpy(id, filename); + memcpy(id, filename, sizeof(char) * (strlen(filename) + 1)); img->id = id; img->img.atlas.id = ATLAS_UNPACKED_EXTRA_ASSET << IMAGE_ATLAS_BIT_OFFSET; img->img.atlas.id += img->index; diff --git a/src/assets/layer.c b/src/assets/layer.c index 735d746be5..63e4df0ee5 100644 --- a/src/assets/layer.c +++ b/src/assets/layer.c @@ -335,12 +335,13 @@ static char *copy_attribute(const char *attribute) if (!attribute) { return 0; } - char *dest = malloc((strlen(attribute) + 1) * sizeof(char)); + size_t buf_size = (strlen(attribute) + 1) * sizeof(char); + char *dest = malloc(buf_size); if (!dest) { log_error("There was no memory to copy the attribute", attribute, 0); return 0; } - strcpy(dest, attribute); + memcpy(dest, attribute, buf_size); return dest; } #endif diff --git a/src/assets/xml.c b/src/assets/xml.c index 5aad528b7c..cfab1efafc 100644 --- a/src/assets/xml.c +++ b/src/assets/xml.c @@ -27,8 +27,7 @@ static void xml_end_image_element(void); static void xml_end_animation_element(void); static struct { - char file_name[FILE_NAME_MAX]; - size_t file_name_position; + char base_path[FILE_NAME_MAX]; int finished; int in_animation; image_groups *current_group; @@ -49,8 +48,7 @@ static const char *ROTATE_VALUES[3] = { "90", "180", "270" }; static void set_asset_image_base_path(const char *name) { - snprintf(data.file_name, FILE_NAME_MAX, "%s/%s/", ASSETS_IMAGE_PATH, name); - data.file_name_position = strlen(data.file_name); + snprintf(data.base_path, FILE_NAME_MAX, "%s/%s", ASSETS_IMAGE_PATH, name); } static int xml_start_assetlist_element(void) @@ -271,13 +269,13 @@ int xml_process_assetlist_file(const char *xml_file_name) } #ifdef BUILDING_ASSET_PACKER else { - size_t xml_file_name_length = strlen(xml_file_name); - char *path = malloc(sizeof(char *) * (xml_file_name_length + 1)); + size_t buf_size = sizeof(char *) * (strlen(xml_file_name) + 1); + char *path = malloc(buf_size); if (!path) { error = 1; group_unload_current(); } else { - strcpy(path, xml_file_name); + memcpy(path, xml_file_name, buf_size); group_get_current()->path = path; } } @@ -298,9 +296,7 @@ void xml_finish(void) void xml_get_full_image_path(char *full_path, const char *image_file_name) { - strncpy(full_path, data.file_name, data.file_name_position); - size_t file_name_size = strlen(image_file_name); - strncpy(full_path + data.file_name_position, image_file_name, FILE_NAME_MAX - data.file_name_position); - strncpy(full_path + data.file_name_position + file_name_size, ".png", - FILE_NAME_MAX - data.file_name_position - file_name_size); + if (snprintf(full_path, FILE_NAME_MAX, "%s/%s.png", data.base_path, image_file_name) > FILE_NAME_MAX) { + log_error("Image path too long", image_file_name, 0); + } } diff --git a/src/building/barracks.c b/src/building/barracks.c index 2ec69f1bd7..83aba396c9 100644 --- a/src/building/barracks.c +++ b/src/building/barracks.c @@ -91,6 +91,9 @@ static int has_recruitment_priority(int current_type, int legion_type, int prior return 1; } } + if (priority_type != LEGION_RECRUIT_NONE && current_type == priority_type && legion_type != priority_type) { + return 0; + } return dist < min_distance; } diff --git a/src/building/clone.c b/src/building/clone.c index 3057fa6cd2..af6e08cd38 100644 --- a/src/building/clone.c +++ b/src/building/clone.c @@ -13,8 +13,8 @@ * For example, given a fort, return the enumaration value corresponding to * the specific type of fort rather than the general value * - * @param building Building to examine (can be null for destroyed building) - * @param building_type Type of the building to clone (can be original building type before a fire) + * @param b Building to examine (can be null for destroyed building) + * @param clone_type Type of the building to clone (can be original building type before a fire) * @return the building_type value to clone, or BUILDING_NONE if not cloneable */ static building_type get_clone_type_from_building(building *b, building_type clone_type) diff --git a/src/building/granary.c b/src/building/granary.c index b0242e4e41..39ea13da5f 100644 --- a/src/building/granary.c +++ b/src/building/granary.c @@ -578,7 +578,7 @@ void building_granary_bless(void) const resource_list *list = city_resource_get_available_foods(); - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { for (int n = 0; n < 6; n++) { building_granary_add_resource(min_building, list->items[i], 0); } diff --git a/src/building/menu.c b/src/building/menu.c index 6d3342462b..4e9ef2a051 100644 --- a/src/building/menu.c +++ b/src/building/menu.c @@ -175,6 +175,9 @@ static void disable_finished(int *enabled, building_type menu_building_type, bui static void disable_if_no_enabled_submenu_items(int *enabled, int submenu) { for (int item = 0; item < BUILD_MENU_ITEM_MAX && MENU_BUILDING_TYPE[submenu][item]; item++) { + if (BUILD_MENU_TYPE_TO_BUILDING_TYPE[submenu] == MENU_BUILDING_TYPE[submenu][item]) { + continue; + } if (is_building_type_allowed(MENU_BUILDING_TYPE[submenu][item])) { return; } @@ -198,6 +201,11 @@ static void enable_normal(int *enabled, building_type type) enable_if_allowed(enabled, type, BUILDING_HOSPITAL); enable_if_allowed(enabled, type, BUILDING_MENU_SMALL_TEMPLES); enable_if_allowed(enabled, type, BUILDING_MENU_LARGE_TEMPLES); + enable_if_allowed(enabled, type, BUILDING_LARGE_TEMPLE_CERES); + enable_if_allowed(enabled, type, BUILDING_LARGE_TEMPLE_NEPTUNE); + enable_if_allowed(enabled, type, BUILDING_LARGE_TEMPLE_MERCURY); + enable_if_allowed(enabled, type, BUILDING_LARGE_TEMPLE_MARS); + enable_if_allowed(enabled, type, BUILDING_LARGE_TEMPLE_VENUS); enable_if_allowed(enabled, type, BUILDING_MENU_GRAND_TEMPLES); enable_if_allowed(enabled, type, BUILDING_ORACLE); enable_if_allowed(enabled, type, BUILDING_MENU_SHRINES); diff --git a/src/building/rotation.h b/src/building/rotation.h index 91b8aff62d..1a0104bee4 100644 --- a/src/building/rotation.h +++ b/src/building/rotation.h @@ -23,4 +23,4 @@ void building_rotation_remove_rotation(void); int building_rotation_type_has_rotations(building_type type); -#endif // BUILDING_ROTATION_H \ No newline at end of file +#endif // BUILDING_ROTATION_H diff --git a/src/building/storage.h b/src/building/storage.h index d39faf1f0c..b3e7bfc527 100644 --- a/src/building/storage.h +++ b/src/building/storage.h @@ -153,7 +153,7 @@ void building_storage_reset_building_ids(void); /** * Gets the maximum (in full units) a given storage will store of a given resource - * @param storage_id Storage id + * @param b The building to check * @param resource_id Resource id * @return Max amount that can be stored, 0 if it does not accept the resource at all. */ diff --git a/src/campaign/campaign.c b/src/campaign/campaign.c index b1b824713b..dbff763fb4 100644 --- a/src/campaign/campaign.c +++ b/src/campaign/campaign.c @@ -62,7 +62,7 @@ int campaign_load(const char *filename) campaign_file_set_path(filename); get_campaign_data(); if (data.active) { - strncpy(data.file_name, filename, FILE_NAME_MAX); + snprintf(data.file_name, FILE_NAME_MAX, "%s", filename); } return data.active; } @@ -161,7 +161,7 @@ int campaign_load_scenario(int scenario_id) if (!scenario_data) { return 0; } - log_info("Loading custom campaign scenario", scenario->path, scenario->id); + log_info("Loading custom campaign scenario", file_remove_directory(scenario->path), scenario->id); int is_save_game = file_has_extension(scenario->path, "sav") || file_has_extension(scenario->path, "svx"); int result = game_file_start_scenario_from_buffer(scenario_data, (int) length, is_save_game); free(scenario_data); @@ -178,7 +178,7 @@ const campaign_scenario *campaign_get_scenario(int scenario_id) void campaign_suspend(void) { - strncpy(data.suspended_filename, data.file_name, FILE_NAME_MAX); + snprintf(data.suspended_filename, FILE_NAME_MAX, "%s", data.file_name); data.active = 0; } diff --git a/src/campaign/file.c b/src/campaign/file.c index 31e62afd77..0b983aef4e 100644 --- a/src/campaign/file.c +++ b/src/campaign/file.c @@ -19,8 +19,8 @@ static struct { int campaign_file_exists(const char *filename) { if (data.is_folder) { - strncpy(&data.file_name[data.file_name_offset], filename, FILE_NAME_MAX - data.file_name_offset); - return file_exists(data.file_name, NOT_LOCALIZED); + snprintf(&data.file_name[data.file_name_offset], FILE_NAME_MAX - data.file_name_offset, "/%s", filename); + return dir_get_file_at_location(data.file_name, PATH_LOCATION_CAMPAIGN) != 0; } int close_at_end = data.zip.parser == 0; if (!campaign_file_open_zip()) { @@ -37,8 +37,12 @@ int campaign_file_exists(const char *filename) static void *load_file_from_folder(const char *file, size_t *length) { *length = 0; - strncpy(&data.file_name[data.file_name_offset], file, FILE_NAME_MAX - data.file_name_offset); - FILE *campaign_file = file_open(data.file_name, "rb"); + snprintf(&data.file_name[data.file_name_offset], FILE_NAME_MAX - data.file_name_offset, "/%s", file); + const char *filename = dir_get_file_at_location(data.file_name, PATH_LOCATION_CAMPAIGN); + if (!filename) { + return 0; + } + FILE *campaign_file = file_open(filename, "rb"); if (!campaign_file) { return 0; } @@ -109,12 +113,7 @@ void campaign_file_set_path(const char *path) campaign_file_close_zip(); if (path && path[0]) { data.is_folder = !file_has_extension(path, "campaign"); - if (data.is_folder) { - data.file_name_offset = snprintf(data.file_name, FILE_NAME_MAX, "%s/%s/", CAMPAIGNS_DIR_NAME, path); - } else { - strncpy(data.file_name, path, FILE_NAME_MAX); - data.file_name_offset = 0; - } + data.file_name_offset = snprintf(data.file_name, FILE_NAME_MAX, "%s", path); } else { data.file_name[0] = 0; data.file_name_offset = 0; @@ -149,7 +148,11 @@ int campaign_file_open_zip(void) return 0; } if (!data.zip.stream) { - data.zip.stream = file_open(data.file_name, "rb"); + const char *filename = dir_get_file_at_location(data.file_name, PATH_LOCATION_CAMPAIGN); + if (!filename) { + return 0; + } + data.zip.stream = file_open(filename, "rb"); if (!data.zip.stream) { return 0; } diff --git a/src/city/emperor.c b/src/city/emperor.c index 7007c9dbd7..31a8c062f4 100644 --- a/src/city/emperor.c +++ b/src/city/emperor.c @@ -376,4 +376,4 @@ void city_emperor_force_attack(int size){ void city_emperor_decrement_personal_savings(int amount) { city_data.emperor.personal_savings -= calc_bound(amount, 0, city_data.emperor.personal_savings - city_data.games.bet_amount); -} \ No newline at end of file +} diff --git a/src/city/festival.c b/src/city/festival.c index 8862ca76b0..d78be30526 100644 --- a/src/city/festival.c +++ b/src/city/festival.c @@ -248,4 +248,4 @@ void city_festival_calculate_costs(void) city_data.festival.selected.size = FESTIVAL_LARGE; } } -} \ No newline at end of file +} diff --git a/src/city/resource.h b/src/city/resource.h index 3a276599ff..e041cacffc 100644 --- a/src/city/resource.h +++ b/src/city/resource.h @@ -8,7 +8,7 @@ #define FOOD_PER_TRADER_MONTHLY 10 typedef struct { - int size; + unsigned int size; resource_type items[RESOURCE_MAX]; } resource_list; diff --git a/src/core/buffer.c b/src/core/buffer.c index 56fb868d83..ae7c7ffcde 100644 --- a/src/core/buffer.c +++ b/src/core/buffer.c @@ -22,7 +22,7 @@ void buffer_set(buffer *buf, int offset) buf->index = offset; } -static int check_size(buffer *buf, int size) +static int check_size(buffer *buf, size_t size) { if (buf->index + size > buf->size) { buf->overflow = 1; @@ -81,7 +81,7 @@ void buffer_write_i32(buffer *buf, int32_t value) } } -void buffer_write_raw(buffer *buf, const void *value, int size) +void buffer_write_raw(buffer *buf, const void *value, size_t size) { if (check_size(buf, size)) { memcpy(&buf->data[buf->index], value, size); @@ -155,7 +155,7 @@ int32_t buffer_read_i32(buffer *buf) } } -size_t buffer_read_raw(buffer *buf, void *value, int max_size) +size_t buffer_read_raw(buffer *buf, void *value, size_t max_size) { size_t size = buf->size - buf->index; if (size > max_size) { @@ -166,7 +166,7 @@ size_t buffer_read_raw(buffer *buf, void *value, int max_size) return size; } -void buffer_skip(buffer *buf, int size) +void buffer_skip(buffer *buf, size_t size) { buf->index += size; } diff --git a/src/core/buffer.h b/src/core/buffer.h index 3e79a819cc..a75954650f 100644 --- a/src/core/buffer.h +++ b/src/core/buffer.h @@ -88,7 +88,7 @@ void buffer_write_i32(buffer *buffer, int32_t value); * @param value Value to write * @param size Size in bytes */ -void buffer_write_raw(buffer *buffer, const void *value, int size); +void buffer_write_raw(buffer *buffer, const void *value, size_t size); /** * Reads an unsigned 8-bit integer @@ -139,14 +139,14 @@ int32_t buffer_read_i32(buffer *buffer); * @param max_size Size of the value, max bytes to read * @return Bytes read */ -size_t buffer_read_raw(buffer *buffer, void *value, int max_size); +size_t buffer_read_raw(buffer *buffer, void *value, size_t max_size); /** * Skip data in the buffer * @param buffer Buffer * @param size Bytes to skip */ -void buffer_skip(buffer *buffer, int size); +void buffer_skip(buffer *buffer, size_t size); /** * Returns whether the pointer of this buffer is at the end of the buffer diff --git a/src/core/config.c b/src/core/config.c index f7659abb25..475b6f94b9 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -1,5 +1,6 @@ #include "config.h" +#include "core/dir.h" #include "core/file.h" #include "core/log.h" @@ -9,6 +10,7 @@ #define MAX_LINE 100 static const char *INI_FILENAME = "augustus.ini"; +static int needs_user_directory_setup; // Keep this in the same order as the config_keys in config.h static const char *ini_keys[] = { @@ -16,6 +18,7 @@ static const char *ini_keys[] = { "master_volume", "enable_audio_in_videos", "video_volume", + "has_set_user_directories", "gameplay_fix_immigration", "gameplay_fix_100y_ghosts", "screen_display_scale", @@ -74,7 +77,7 @@ static const char *ini_keys[] = { }; static const char *ini_string_keys[] = { - "ui_language_dir" + "ui_language_dir", }; static int values[CONFIG_MAX_ENTRIES]; @@ -85,6 +88,7 @@ static int default_values[CONFIG_MAX_ENTRIES] = { [CONFIG_GENERAL_MASTER_VOLUME] = 100, [CONFIG_GENERAL_ENABLE_VIDEO_SOUND] = 1, [CONFIG_GENERAL_VIDEO_VOLUME] = 100, + [CONFIG_GENERAL_HAS_SET_USER_DIRECTORIES] = 1, [CONFIG_UI_SIDEBAR_INFO] = 1, [CONFIG_UI_SMOOTH_SCROLLING] = 1, [CONFIG_UI_SHOW_WATER_STRUCTURE_RANGE] = 1, @@ -119,7 +123,7 @@ void config_set_string(config_string_key key, const char *value) if (!value) { string_values[key][0] = 0; } else { - strncpy(string_values[key], value, CONFIG_STRING_VALUE_MAX - 1); + snprintf(string_values[key], CONFIG_STRING_VALUE_MAX, "%s", value); } } @@ -138,14 +142,21 @@ static void set_defaults(void) for (int i = 0; i < CONFIG_MAX_ENTRIES; ++i) { values[i] = default_values[i]; } - strncpy(string_values[CONFIG_STRING_UI_LANGUAGE_DIR], - default_string_values[CONFIG_STRING_UI_LANGUAGE_DIR], CONFIG_STRING_VALUE_MAX); + snprintf(string_values[CONFIG_STRING_UI_LANGUAGE_DIR], CONFIG_STRING_VALUE_MAX, "%s", + default_string_values[CONFIG_STRING_UI_LANGUAGE_DIR]); } void config_load(void) { set_defaults(); - FILE *fp = file_open(INI_FILENAME, "rt"); + // Override default, if value is the same at end, then we never setup the directories + needs_user_directory_setup = 0; + values[CONFIG_GENERAL_HAS_SET_USER_DIRECTORIES] = -1; + const char *file_name = dir_get_file_at_location(INI_FILENAME, PATH_LOCATION_CONFIG); + if (!file_name) { + return; + } + FILE *fp = file_open(file_name, "rt"); if (!fp) { return; } @@ -173,18 +184,31 @@ void config_load(void) const char *value = &equals[1]; log_info("Config key", ini_string_keys[i], 0); log_info("Config value", value, 0); - strncpy(string_values[i], value, CONFIG_STRING_VALUE_MAX - 1); + snprintf(string_values[i], CONFIG_STRING_VALUE_MAX, "%s", value); break; } } } } file_close(fp); + if (values[CONFIG_GENERAL_HAS_SET_USER_DIRECTORIES] == -1) { + values[CONFIG_GENERAL_HAS_SET_USER_DIRECTORIES] = default_values[CONFIG_GENERAL_HAS_SET_USER_DIRECTORIES]; + needs_user_directory_setup = 1; + } +} + +int config_must_configure_user_directory(void) +{ + return needs_user_directory_setup; } void config_save(void) { - FILE *fp = file_open(INI_FILENAME, "wt"); + const char *file_name = dir_append_location(INI_FILENAME, PATH_LOCATION_CONFIG); + if (!file_name) { + return; + } + FILE *fp = file_open(file_name, "wt"); if (!fp) { log_error("Unable to write configuration file", INI_FILENAME, 0); return; @@ -196,4 +220,5 @@ void config_save(void) fprintf(fp, "%s=%s\n", ini_string_keys[i], string_values[i]); } file_close(fp); + needs_user_directory_setup = 0; } diff --git a/src/core/config.h b/src/core/config.h index 7a759eba0c..184f78c0d2 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -8,6 +8,7 @@ typedef enum { CONFIG_GENERAL_MASTER_VOLUME, CONFIG_GENERAL_ENABLE_VIDEO_SOUND, CONFIG_GENERAL_VIDEO_VOLUME, + CONFIG_GENERAL_HAS_SET_USER_DIRECTORIES, CONFIG_GP_FIX_IMMIGRATION_BUG, CONFIG_GP_FIX_100_YEAR_GHOSTS, CONFIG_SCREEN_DISPLAY_SCALE, @@ -118,6 +119,13 @@ const char *config_get_default_string_value(config_string_key key); */ void config_load(void); +/** + * Whether the user directory must be configured + * + * @return 1 If the user directory still needs to be set, 0 otherwise + */ +int config_must_configure_user_directory(void); + /** * Save config to file */ diff --git a/src/core/dir.c b/src/core/dir.c index 226ce591cf..d05a588830 100644 --- a/src/core/dir.c +++ b/src/core/dir.c @@ -14,6 +14,7 @@ static struct { dir_listing listing; int max_files; char *cased_filename; + char current_dir[FILE_NAME_MAX]; } data; static void allocate_listing_files(int min, int max) @@ -27,6 +28,7 @@ static void allocate_listing_files(int min, int max) static void clear_dir_listing(void) { data.listing.num_files = 0; + data.current_dir[0] = 0; if (data.max_files <= 0) { data.listing.files = (dir_entry *) malloc(BASE_MAX_FILES * sizeof(dir_entry)); allocate_listing_files(0, BASE_MAX_FILES); @@ -61,8 +63,7 @@ static int add_to_listing(const char *filename, long modified_time) if (data.listing.num_files >= data.max_files) { expand_dir_listing(); } - strncpy(data.listing.files[data.listing.num_files].name, filename, FILE_NAME_MAX); - data.listing.files[data.listing.num_files].name[FILE_NAME_MAX - 1] = 0; + snprintf(data.listing.files[data.listing.num_files].name, FILE_NAME_MAX, "%s", filename); data.listing.files[data.listing.num_files].modified_time = modified_time; ++data.listing.num_files; return LIST_CONTINUE; @@ -71,22 +72,35 @@ static int add_to_listing(const char *filename, long modified_time) const dir_listing *dir_find_files_with_extension(const char *dir, const char *extension) { clear_dir_listing(); + snprintf(data.current_dir, FILE_NAME_MAX, "%s", dir); platform_file_manager_list_directory_contents(dir, TYPE_FILE, extension, add_to_listing); qsort(data.listing.files, data.listing.num_files, sizeof(dir_entry), compare_lower); return &data.listing; } +const dir_listing *dir_find_files_with_extension_at_location(int location, const char *extension) +{ + return dir_find_files_with_extension(platform_file_manager_get_directory_for_location(location, 0), extension); +} + const dir_listing *dir_find_all_subdirectories(const char *dir) { clear_dir_listing(); + snprintf(data.current_dir, FILE_NAME_MAX, "%s", dir); platform_file_manager_list_directory_contents(dir, TYPE_DIR, 0, add_to_listing); qsort(data.listing.files, data.listing.num_files, sizeof(dir_entry), compare_lower); return &data.listing; } +const dir_listing *dir_find_all_subdirectories_at_location(int location) +{ + return dir_find_all_subdirectories(platform_file_manager_get_directory_for_location(location, 0)); +} + static int compare_case(const char *filename, long unused) { if (platform_file_manager_compare_filename(filename, data.cased_filename) == 0) { + // We are copying anyway because the comparison is case insensitive, so we can't use the original filename strcpy(data.cased_filename, filename); return LIST_MATCH; } @@ -111,7 +125,6 @@ static void move_left(char *str) static const char *get_case_corrected_file(const char *dir, const char *filepath) { static char corrected_filename[2 * FILE_NAME_MAX]; - corrected_filename[2 * FILE_NAME_MAX - 1] = 0; size_t dir_len = 0; size_t dir_skip = 0; @@ -120,7 +133,7 @@ static const char *get_case_corrected_file(const char *dir, const char *filepath dir_skip = 2; } dir_len = strlen(dir); - strncpy(corrected_filename, dir, 2 * FILE_NAME_MAX - 1); + snprintf(corrected_filename, 2 * FILE_NAME_MAX, "%s", dir); if (dir_len) { if (dir[dir_len - 1] != '/') { corrected_filename[dir_len] = '/'; @@ -128,7 +141,7 @@ static const char *get_case_corrected_file(const char *dir, const char *filepath } } - strncpy(&corrected_filename[dir_len], filepath, 2 * FILE_NAME_MAX - dir_len - 1); + snprintf(&corrected_filename[dir_len], 2 * FILE_NAME_MAX - dir_len, "%s", filepath); FILE *fp = file_open(corrected_filename, "rb"); if (fp) { @@ -172,7 +185,7 @@ static const char *get_case_corrected_file(const char *dir, const char *filepath const dir_listing *dir_append_files_with_extension(const char *extension) { - platform_file_manager_list_directory_contents(0, TYPE_FILE, extension, add_to_listing); + platform_file_manager_list_directory_contents(data.current_dir, TYPE_FILE, extension, add_to_listing); qsort(data.listing.files, data.listing.num_files, sizeof(dir_entry), compare_lower); return &data.listing; } @@ -194,7 +207,15 @@ const char *dir_get_file(const char *filepath, int localizable) return get_case_corrected_file(0, filepath); } -const char *dir_get_asset(const char *asset_path, const char *filepath) +const char *dir_get_file_at_location(const char *filename, int location) +{ + return get_case_corrected_file(platform_file_manager_get_directory_for_location(location, 0), filename); +} + +const char *dir_append_location(const char *filename, int location) { - return get_case_corrected_file(asset_path, filepath); + static char corrected_filename[FILE_NAME_MAX]; + snprintf(corrected_filename, FILE_NAME_MAX, "%s%s", + platform_file_manager_get_directory_for_location(location, 0), filename); + return corrected_filename; } diff --git a/src/core/dir.h b/src/core/dir.h index e2a564d28c..b22b293d89 100644 --- a/src/core/dir.h +++ b/src/core/dir.h @@ -17,6 +17,21 @@ enum { MUST_BE_LOCALIZED = 2 }; +enum { + PATH_LOCATION_ROOT = 0, + PATH_LOCATION_CONFIG = 1, + PATH_LOCATION_ASSET = 2, + PATH_LOCATION_SAVEGAME = 3, + PATH_LOCATION_SCENARIO = 4, + PATH_LOCATION_CAMPAIGN = 5, + PATH_LOCATION_SCREENSHOT = 6, + PATH_LOCATION_COMMUNITY = 7, + PATH_LOCATION_EDITOR_CUSTOM_EMPIRES = 8, + PATH_LOCATION_EDITOR_CUSTOM_MESSAGES = 9, + PATH_LOCATION_EDITOR_CUSTOM_EVENTS = 10, + PATH_LOCATION_MAX = 11 +}; + /** * File information */ @@ -40,6 +55,20 @@ typedef struct { * @return Directory listing */ const dir_listing *dir_find_files_with_extension(const char *dir, const char *extension); + +/** + * Finds files with the given extension at the requested location ID + * @param location The location ID where the files should reside + * @param extension Extension of the files to find + * @return Directory listing + */ +const dir_listing *dir_find_files_with_extension_at_location(int location, const char *extension); + +/** + * Appends files with the given extension to the current directory listing + * @param extension Extension of the files to find + * @return Directory listing + */ const dir_listing *dir_append_files_with_extension(const char *extension); /** @@ -49,6 +78,13 @@ const dir_listing *dir_append_files_with_extension(const char *extension); */ const dir_listing *dir_find_all_subdirectories(const char *dir); +/** + * Finds all subdirectories at the requested location ID + * @param location The location ID where the subdirectories should reside + * @return Directory listing + */ +const dir_listing *dir_find_all_subdirectories_at_location(int location); + /** * Get the case sensitive and localized filename of the file * @param filepath File path to match to a case-sensitive file on the filesystem @@ -58,11 +94,19 @@ const dir_listing *dir_find_all_subdirectories(const char *dir); const char *dir_get_file(const char *filepath, int localizable); /** - * Get the case sensitive filename of the asset - * @param asset_path The path to the asset directory - * @param filepath Asset path to match to a case-sensitive asset file on the filesystem + * Get the case sensitive filename from the requested location ID + * @param filepath File path to match to a case-sensitive file on the filesystem + * @param location The location ID where the file should reside * @return Corrected file, or NULL if the file was not found */ -const char *dir_get_asset(const char *asset_path, const char *filepath); +const char *dir_get_file_at_location(const char *filepath, int location); + +/** + * Appends the location to the filename + * @param filename File path to append the location to + * @param location The location ID to append to the filename + * @return Filename with location appended + */ +const char *dir_append_location(const char *filename, int location); #endif // CORE_DIR_H diff --git a/src/core/encoding.h b/src/core/encoding.h index 09265b9e77..cc9c6a88d7 100644 --- a/src/core/encoding.h +++ b/src/core/encoding.h @@ -63,7 +63,7 @@ int encoding_can_display(const char *utf8_char); void encoding_to_utf8(const uint8_t *input, char *output, int output_length, int decompose); /** - * Converts the internally-encoded input to UTF-8 output + * Converts the UTF-8 to internally-encoded output * @param input Input to convert, UTF-8 encoded * @param output Output buffer to store the internally encoded input * @param output_length Length of the output buffer diff --git a/src/core/file.c b/src/core/file.c index ca2b182bbc..d38ab62b7b 100644 --- a/src/core/file.c +++ b/src/core/file.c @@ -30,63 +30,56 @@ int file_has_extension(const char *filename, const char *extension) if (!extension || !*extension) { return 1; } - char c; - do { - c = *filename; - filename++; - } while (c != '.' && c); - if (!c) { - filename--; - } - return platform_file_manager_compare_filename(filename, extension) == 0; + filename = strrchr(filename, '.'); + return filename ? platform_file_manager_compare_filename(filename + 1, extension) == 0 : 0; } void file_change_extension(char *filename, const char *new_extension) { - char c; - do { - c = *filename; - filename++; - } while (c != '.' && c); - if (c == '.') { - filename[0] = new_extension[0]; - filename[1] = new_extension[1]; - filename[2] = new_extension[2]; - filename[3] = 0; + if (!new_extension || !*new_extension) { + return; + } + filename = strrchr(filename, '.'); + if (!filename) { + return; } + filename++; + snprintf(filename, strlen(filename) + 1, "%s", new_extension); } -void file_append_extension(char *filename, const char *extension) +void file_append_extension(char *filename, const char *extension, size_t length) { - char c; - do { - c = *filename; - filename++; - } while (c); - filename--; - *filename = '.'; - filename++; - size_t len = strlen(extension); - for (size_t i = 0; i < len; i++) { - *filename = extension[i]; - filename++; + if (!extension || !*extension) { + return; } - *filename = 0; + size_t actual_length = strlen(filename); + if (actual_length + strlen(extension) + 1 > length) { + return; + } + snprintf(filename + actual_length, length - actual_length, ".%s", extension); } void file_remove_extension(char *filename) { - uint8_t c; - do { - c = *filename; - filename++; - } while (c != '.' && c); - if (c == '.') { - filename--; + filename = strrchr(filename, '.'); + if (filename) { *filename = 0; } } +const char *file_remove_directory(const char *filename) +{ + char *filename_without_directory = strrchr(filename, '/'); + if (filename_without_directory) { + return filename_without_directory + 1; + } + filename_without_directory = strrchr(filename, '\\'); + if (filename_without_directory) { + return filename_without_directory + 1; + } + return filename; +} + int file_exists(const char *filename, int localizable) { return NULL != dir_get_file(filename, localizable); diff --git a/src/core/file.h b/src/core/file.h index c37d048343..270425880f 100644 --- a/src/core/file.h +++ b/src/core/file.h @@ -28,7 +28,7 @@ FILE *file_open(const char *filename, const char *mode); /** * Wrapper for fopen converting filename to path in asset directory - * @param filename Asset filename + * @param asset Asset filename * @param mode Mode to open the asset file (e.g. "wb"). * @return FILE */ @@ -61,8 +61,9 @@ void file_change_extension(char *filename, const char *new_extension); * Appends the extension to the file * @param[in,out] filename Filename to change * @param extension Extension to append + * @param length Length of the filename buffer */ -void file_append_extension(char *filename, const char *extension); +void file_append_extension(char *filename, const char *extension, size_t length); /** * Removes the extension from the file @@ -70,6 +71,13 @@ void file_append_extension(char *filename, const char *extension); */ void file_remove_extension(char *filename); +/** + * Removes the directory from the filename + * @param filename Filename to change + * @return Filename without directory + */ +const char *file_remove_directory(const char *filename); + /** * Check if file exists * @param filename Filename to check diff --git a/src/core/image.c b/src/core/image.c index 2b3b33db2b..808705fbb7 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -1148,8 +1148,8 @@ int image_is_external(const image *img) int image_load_external_pixels(color_t *dst, const image *img, int row_width) { image_draw_data *draw_data = &data.external_draw_data[img->atlas.id & IMAGE_ATLAS_BIT_MASK]; - char filename[FILE_NAME_MAX] = "555/"; - strcpy(&filename[4], data.bitmaps[draw_data->bitmap_id]); + char filename[FILE_NAME_MAX]; + snprintf(filename, FILE_NAME_MAX, "555/%s", data.bitmaps[draw_data->bitmap_id]); file_change_extension(filename, "555"); if (!draw_data->buffer) { draw_data->buffer = malloc(draw_data->data_length * sizeof(uint8_t)); diff --git a/src/core/lang.c b/src/core/lang.c index f534685521..3c31d19b81 100644 --- a/src/core/lang.c +++ b/src/core/lang.c @@ -45,10 +45,7 @@ static struct { static int file_exists_in_dir(const char *dir, const char *file) { char path[2 * FILE_NAME_MAX]; - path[2 * FILE_NAME_MAX - 1] = 0; - strncpy(path, dir, 2 * FILE_NAME_MAX - 1); - strncat(path, "/", 2 * FILE_NAME_MAX - 1); - strncat(path, file, 2 * FILE_NAME_MAX - 1); + snprintf(path, 2 * FILE_NAME_MAX, "%s/%s", dir, file); return file_exists(path, NOT_LOCALIZED); } diff --git a/src/core/memory_block.c b/src/core/memory_block.c index c8ed08a1af..c7801af786 100644 --- a/src/core/memory_block.c +++ b/src/core/memory_block.c @@ -4,7 +4,7 @@ int core_memory_block_init(memory_block *block, size_t initial_size) { - block->memory = calloc(sizeof(char), initial_size); + block->memory = calloc(initial_size, sizeof(char)); if (!block->memory) { block->size = 0; return 0; diff --git a/src/core/png_read.c b/src/core/png_read.c index 54a77bba7f..c74e2d2d3a 100644 --- a/src/core/png_read.c +++ b/src/core/png_read.c @@ -55,7 +55,7 @@ int png_load_from_file(const char *path, int is_asset) return 0; } data.cache.type = CACHE_TYPE_FILE; - strncpy(data.cache.path, path, FILE_NAME_MAX - 1); + snprintf(data.cache.path, FILE_NAME_MAX, "%s", path); return 1; } diff --git a/src/core/speed.h b/src/core/speed.h index 7699431bc8..10d21268b8 100644 --- a/src/core/speed.h +++ b/src/core/speed.h @@ -57,7 +57,7 @@ void speed_set_target(speed_type *speed, double new_speed, time_millis total_tim /** * Immediately invert the speed (positive speed becomes negative and vice-versa) - * @param sp Speed structure to act on + * @param speed Speed structure to act on */ void speed_invert(speed_type *speed); diff --git a/src/core/xml_parser.c b/src/core/xml_parser.c index 2ec2f7e29e..702ff149fd 100644 --- a/src/core/xml_parser.c +++ b/src/core/xml_parser.c @@ -26,7 +26,7 @@ static struct { struct { sxml_t context; sxmltok_t *tokens; - int num_tokens; + unsigned int num_tokens; int line_number; unsigned int current_position; } parser; @@ -43,7 +43,7 @@ static struct { element_text *texts; } data; -static const char EMPTY_STRING; +static const char EMPTY_STRING = 0; static int dummy_element_on_enter(void) { @@ -163,7 +163,7 @@ static int handle_attributes(const sxmltok_t *first, unsigned int size) return 1; } data.attributes.first = first; - for (int i = 0; i < size; i++) { + for (unsigned int i = 0; i < size; i++) { data.buffer.data[first[i].endpos] = 0; i += handle_attribute_value(first + i + 1, size - i - 1); } @@ -263,7 +263,7 @@ static void handle_element_text(const sxmltok_t *token) static int expand_xml_token_array(void) { - size_t expanded_size = data.parser.num_tokens + XML_TOKENS_SIZE_STEP; + unsigned int expanded_size = data.parser.num_tokens + XML_TOKENS_SIZE_STEP; sxmltok_t *expanded_tokens = realloc(data.parser.tokens, sizeof(sxmltok_t) * expanded_size); if (!expanded_tokens) { return 0; @@ -483,12 +483,12 @@ char *xml_parser_copy_attribute_string(const char *key) if (!value) { return 0; } - size_t value_size = strlen(value); - char *result = malloc(sizeof(char) * (value_size + 1)); + size_t buf_size = sizeof(char) * (strlen(value) + 1); + char *result = malloc(buf_size); if (!result) { return 0; } - strcpy(result, value); + memcpy(result, value, buf_size); return result; } diff --git a/src/core/xml_parser.h b/src/core/xml_parser.h index e17ec5459b..7beb7df9e6 100644 --- a/src/core/xml_parser.h +++ b/src/core/xml_parser.h @@ -81,7 +81,7 @@ char *xml_parser_copy_attribute_string(const char *key); int xml_parser_get_attribute_bool(const char *key); /** - * @brief + * @brief Gets an attribute as an enumeration * * @param key The key to obtain. * @param values The possibe values for the enum, as an array of strings. You can have multiple values per index by separating them with "|". diff --git a/src/empire/empire.c b/src/empire/empire.c index 1fa331084b..ba86c2375c 100644 --- a/src/empire/empire.c +++ b/src/empire/empire.c @@ -59,19 +59,26 @@ static void set_image_id(const char *path) return; } char *paths[] = { - CAMPAIGNS_DIRECTORY "/image/", - "community/image/", + CAMPAIGNS_DIRECTORY "/image", + "image", 0 }; for (int i = 0; paths[i]; i++) { char full_path[FILE_NAME_MAX]; - snprintf(full_path, FILE_NAME_MAX, "%s%s", paths[i], path); - if (campaign_has_file(full_path) || file_exists(full_path, NOT_LOCALIZED)) { - data.image.id = assets_get_external_image(full_path, 1); - strncpy(data.image.path, path, FILE_NAME_MAX); + const char *found_path = 0; + snprintf(full_path, FILE_NAME_MAX, "%s/%s", paths[i], path); + if (campaign_has_file(full_path)) { + found_path = full_path; + } else { + found_path = dir_get_file_at_location(full_path, PATH_LOCATION_COMMUNITY); + } + if (found_path) { + data.image.id = assets_get_external_image(found_path, 1); + snprintf(data.image.path, FILE_NAME_MAX, "%s", path); return; } } + log_error("Unable to find map image file", path, 0); data.image.id = image_group(editor_is_active() ? GROUP_EDITOR_EMPIRE_MAP : GROUP_EMPIRE_MAP); data.image.path[0] = 0; } diff --git a/src/empire/trade_prices.h b/src/empire/trade_prices.h index b44fbd0600..f54f6df079 100644 --- a/src/empire/trade_prices.h +++ b/src/empire/trade_prices.h @@ -23,7 +23,7 @@ int trade_price_base_buy(resource_type resource); /** * Get the buy price for the resource * @param resource Resource - * @param int land_trader 1 if land_trader 0 else sea_trader + * @param land_trader 1 if land_trader 0 else sea_trader */ int trade_price_buy(resource_type resource, int land_trader); @@ -36,7 +36,7 @@ int trade_price_base_sell(resource_type resource); /** * Get the sell price for the resource * @param resource Resource - * @param int land_trader 1 if land_trader 0 else sea_trader + * @param land_trader 1 if land_trader 0 else sea_trader */ int trade_price_sell(resource_type resource, int land_trader); diff --git a/src/empire/trade_route.c b/src/empire/trade_route.c index 6c8b485432..df6773841f 100644 --- a/src/empire/trade_route.c +++ b/src/empire/trade_route.c @@ -37,8 +37,7 @@ int trade_route_count(void) int trade_route_is_valid(int route_id) { - route_resource *route = array_item(routes, route_id); - return route != 0; + return route_id >= 0 && route_id < routes.size; } void trade_route_set(int route_id, resource_type resource, int limit) diff --git a/src/figure/formation_enemy.c b/src/figure/formation_enemy.c index db3f8c6647..f59ffc8e97 100644 --- a/src/figure/formation_enemy.c +++ b/src/figure/formation_enemy.c @@ -342,7 +342,8 @@ static void set_native_target_building(formation *m) if (min_building) { formation_set_destination_building(m, min_building->x, min_building->y, min_building->id); } else { - int dst_x, dst_y; + int dst_x = 0; + int dst_y = 0; int has_target = get_structures_on_native_land(&dst_x, &dst_y); if (has_target) { formation_set_destination_building(m, dst_x, dst_y, 0); diff --git a/src/figure/image.c b/src/figure/image.c index eb12ebee24..3359837a9e 100644 --- a/src/figure/image.c +++ b/src/figure/image.c @@ -13,7 +13,7 @@ static const int CORPSE_IMAGE_OFFSETS[128] = { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }; -static const int MISSILE_LAUNCHER_OFFSETS[128] = { +static const int DEFAULT_MISSILE_LAUNCHER_OFFSETS[128] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -24,6 +24,18 @@ static const int MISSILE_LAUNCHER_OFFSETS[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static const int LEGION_MISSILE_LAUNCHER_OFFSETS[128] = { + -1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + + static const int CART_OFFSETS_X[] = {13, 18, 12, 0, -13, -18, -13, 0}; static const int CART_OFFSETS_Y[] = {-7, -1, 7, 11, 6, -1, -7, -12}; @@ -57,7 +69,12 @@ int figure_image_corpse_offset(figure *f) int figure_image_missile_launcher_offset(figure *f) { - return MISSILE_LAUNCHER_OFFSETS[f->attack_image_offset / 2]; + switch (f->type) { + case FIGURE_FORT_LEGIONARY: + return LEGION_MISSILE_LAUNCHER_OFFSETS[f->attack_image_offset / 2]; + default: + return DEFAULT_MISSILE_LAUNCHER_OFFSETS[f->attack_image_offset / 2]; + } } int figure_image_direction(figure *f) diff --git a/src/figure/movement.c b/src/figure/movement.c index 29f018c491..2fbba8941e 100644 --- a/src/figure/movement.c +++ b/src/figure/movement.c @@ -332,8 +332,8 @@ void figure_movement_init_roaming(figure *f) if (b->figure_roam_direction > 6) { b->figure_roam_direction = 0; } - int x = b->x; - int y = b->y; + int x = f->x; + int y = f->y; switch (roam_dir) { case DIR_0_TOP: y -= 8; break; case DIR_2_RIGHT: x += 8; break; diff --git a/src/figure/phrase.c b/src/figure/phrase.c index b5bdde1c91..f7778d6b22 100644 --- a/src/figure/phrase.c +++ b/src/figure/phrase.c @@ -11,11 +11,12 @@ #include "city/resource.h" #include "city/sentiment.h" #include "core/calc.h" +#include "core/file.h" #include "figure/trader.h" #include "figuretype/trader.h" #include "sound/speech.h" -#include +#include #define SOUND_FILENAME_MAX 32 @@ -268,9 +269,8 @@ enum { static void play_sound_file(int sound_id, int phrase_id) { if (sound_id >= 0 && phrase_id >= 0) { - char path[SOUND_FILENAME_MAX]; - strcpy(path, "wavs/"); - strcat(path, FIGURE_SOUNDS[sound_id][phrase_id]); + char path[FILE_NAME_MAX]; + snprintf(path, FILE_NAME_MAX, "wavs/%s", FIGURE_SOUNDS[sound_id][phrase_id]); sound_speech_play_file(path); } } diff --git a/src/figure/properties.c b/src/figure/properties.c index df25daa887..a5960a689f 100644 --- a/src/figure/properties.c +++ b/src/figure/properties.c @@ -69,7 +69,7 @@ static const figure_properties properties[FIGURE_TYPE_MAX] = { [FIGURE_FORT_LEGIONARY] = { .category = FIGURE_CATEGORY_ARMED, .max_damage = 150, .attack_value = 10, .defense_value = 2, - .missile_defense_value = 0, .missile_attack_value = 0, .missile_delay = 0 + .missile_defense_value = 0, .missile_attack_value = 2, .missile_delay = 150 }, [FIGURE_FORT_STANDARD] = { .category = FIGURE_CATEGORY_INACTIVE, @@ -289,7 +289,7 @@ static const figure_properties properties[FIGURE_TYPE_MAX] = { [FIGURE_ENEMY_CAESAR_LEGIONARY] = { .category = FIGURE_CATEGORY_HOSTILE, .max_damage = 150, .attack_value = 13, .defense_value = 2, - .missile_defense_value = 0, .missile_attack_value = 0, .missile_delay = 0 + .missile_defense_value = 0, .missile_attack_value = 2, .missile_delay = 150 }, [FIGURE_NATIVE_TRADER] = { .category = FIGURE_CATEGORY_NATIVE, diff --git a/src/figure/roamer_preview.c b/src/figure/roamer_preview.c index 16a8646fee..83a996f510 100644 --- a/src/figure/roamer_preview.c +++ b/src/figure/roamer_preview.c @@ -269,7 +269,7 @@ void figure_roamer_preview_create(building_type b_type, int x, int y) if (map_grid_is_valid_offset(roamer.grid_offset)) { data.travelled_tiles.items[roamer.grid_offset] = FIGURE_ROAMER_PREVIEW_EXIT_TILE; } - init_roaming(&roamer, i * 2, x, y); + init_roaming(&roamer, i * 2, roamer.x, roamer.y); while (++roamer.roam_length < roamer.max_roam_length) { if (roamer.progress_on_tile == 0 && data.travelled_tiles.items[roamer.grid_offset] < FIGURE_ROAMER_PREVIEW_MAX_PASSAGES) { data.travelled_tiles.items[roamer.grid_offset]++; diff --git a/src/figuretype/soldier.c b/src/figuretype/soldier.c index bcc2720e05..70f7ea49fd 100644 --- a/src/figuretype/soldier.c +++ b/src/figuretype/soldier.c @@ -42,6 +42,8 @@ static const map_point ALTERNATIVE_POINTS[] = { {-1, -6}, {-6, -4}, {-6, -5}, {-6, -6}, {-5, -6}, {-4, -6}, {-3, -6}, {-2, -6}, {-1, -6}, }; + + void figure_military_standard_action(figure *f) { const formation *m = formation_get(f->formation_id); @@ -100,14 +102,29 @@ void figure_military_standard_action(figure *f) } } +static int ticks_to_shoot(figure *f) +{ + switch (f->type) { + case FIGURE_FORT_LEGIONARY: + return 19; + default: + return 1; + } +} + static figure *soldier_launch_missile(figure *f) { + if (f->action_state == FIGURE_ACTION_150_ATTACK) { + return f; + } int range = 10; int projectile_type = FIGURE_JAVELIN; if (f->type == FIGURE_FORT_ARCHER) { range = 12; projectile_type = FIGURE_FRIENDLY_ARROW; - } + } else if (f->type == FIGURE_FORT_LEGIONARY) { + range = 6; + } int missile_delay = figure_properties_for_type(f->type)->missile_delay; @@ -123,7 +140,13 @@ static figure *soldier_launch_missile(figure *f) } } if (f->attack_image_offset) { - if (f->attack_image_offset == 1) { + if (f->attack_image_offset == ticks_to_shoot(f)) { + if (ticks_to_shoot(f) > 1) { + // Adjust the target in case of long delay + if (figure_combat_get_missile_target_for_soldier(f, range, &tile)) { + f->direction = calc_missile_shooter_direction(f->x, f->y, tile.x, tile.y); + } + } if (tile.x == -1 || tile.y == -1) { map_point_get_last_result(&tile); } @@ -219,8 +242,11 @@ static void update_image_legionary(figure *f, const formation *m, int dir) } else if (f->action_state == FIGURE_ACTION_149_CORPSE) { f->image_id = image_id + 152 + figure_image_corpse_offset(f); } else if (f->action_state == FIGURE_ACTION_84_SOLDIER_AT_STANDARD) { + int missile_offset = figure_image_missile_launcher_offset(f); if (m->is_halted && m->layout == FORMATION_COLUMN && m->missile_attack_timeout) { f->image_id = image_id + dir + 144; + } else if (missile_offset >= 0 && dir < DIR_8_NONE) { + f->image_id = assets_get_image_id("Warriors", "legionary_fr_ne_01") + dir * 5 + missile_offset; } else { f->image_id = image_id + dir; } @@ -360,6 +386,7 @@ void figure_soldier_action(figure *f) f->wait_ticks = 0; f->formation_at_rest = 1; f->image_offset = 0; + f->attack_image_offset = 0; if (f->x != f->formation_position_x.soldier || f->y != f->formation_position_y.soldier) { f->action_state = FIGURE_ACTION_81_SOLDIER_GOING_TO_FORT; } @@ -392,6 +419,7 @@ void figure_soldier_action(figure *f) } break; case FIGURE_ACTION_83_SOLDIER_GOING_TO_STANDARD: + f->attack_image_offset = 0; f->formation_at_rest = 0; f->destination_x = m->standard_x + formation_layout_position_x(m->layout, f->index_in_formation); f->destination_y = m->standard_y + formation_layout_position_y(m->layout, f->index_in_formation); @@ -435,7 +463,12 @@ void figure_soldier_action(figure *f) f = soldier_launch_missile(f); } else if (f->type == FIGURE_FORT_ARCHER) { f = soldier_launch_missile(f); - } else if (f->type == FIGURE_FORT_LEGIONARY || f->type == FIGURE_FORT_INFANTRY || f->type == FIGURE_FORT_MOUNTED) { + } else if (f->type == FIGURE_FORT_LEGIONARY) { + legionary_attack_adjacent_enemy(f); + if (m->layout == FORMATION_DOUBLE_LINE_1 || m->layout == FORMATION_DOUBLE_LINE_2) { + f = soldier_launch_missile(f); + } + } else if (f->type == FIGURE_FORT_INFANTRY || f->type == FIGURE_FORT_MOUNTED) { legionary_attack_adjacent_enemy(f); } } diff --git a/src/figuretype/supplier.c b/src/figuretype/supplier.c index 3a49dff750..9c2604f5d2 100644 --- a/src/figuretype/supplier.c +++ b/src/figuretype/supplier.c @@ -307,21 +307,29 @@ void figure_supplier_action(figure *f) dir * 12 + f->image_offset; } } else if (f->type == FIGURE_LIGHTHOUSE_SUPPLIER) { + if (f->action_state == FIGURE_ACTION_146_SUPPLIER_RETURNING) { + f->cart_image_id = resource_get_data(f->collecting_item_id)->image.cart.single_load; + } else { + f->cart_image_id = image_group(GROUP_FIGURE_CARTPUSHER_CART); + } int dir = figure_image_normalize_direction(f->direction < 8 ? f->direction : f->previous_tile_direction); if (f->action_state == FIGURE_ACTION_149_CORPSE) { - f->image_id = assets_get_image_id("Walkers", "Slave death 01") + - figure_image_corpse_offset(f); + f->image_id = image_group(GROUP_FIGURE_CARTPUSHER) + figure_image_corpse_offset(f) + 96; + f->cart_image_id = 0; } else { - f->image_id = assets_get_image_id("Walkers", "Slave NE 01") + - dir * 12 + f->image_offset; + f->image_id = image_group(GROUP_FIGURE_CARTPUSHER) + dir + 8 * f->image_offset; + } + if (f->cart_image_id) { + f->cart_image_id += dir; + figure_image_set_cart_offset(f, dir); } } else if (f->type == FIGURE_CARAVANSERAI_SUPPLIER) { int dir = figure_image_normalize_direction(f->direction < 8 ? f->direction : f->previous_tile_direction); if (f->action_state == FIGURE_ACTION_149_CORPSE) { - f->image_id = assets_get_image_id("Walkers", "caravanserai_walker_death_01") + + f->image_id = assets_get_image_id("Walkers", "caravanserai_overseer_death_01") + figure_image_corpse_offset(f); } else { - f->image_id = assets_get_image_id("Walkers", "caravanserai_walker_ne_01") + + f->image_id = assets_get_image_id("Walkers", "caravanserai_overseer_ne_01") + dir * 12 + f->image_offset; } } else { diff --git a/src/figuretype/workcamp.c b/src/figuretype/workcamp.c index 3b8dd58780..18d05ed68d 100644 --- a/src/figuretype/workcamp.c +++ b/src/figuretype/workcamp.c @@ -80,6 +80,17 @@ static int has_valid_monument_destination(figure *f) return 1; } +static void workcamp_worker_image_update(figure *f) +{ + int dir = figure_image_normalize_direction(f->direction < 8 ? f->direction : f->previous_tile_direction); + if (f->action_state == FIGURE_ACTION_149_CORPSE) { + f->image_id = assets_get_image_id("Walkers", "overseer_death_01") + + figure_image_corpse_offset(f); + } else { + f->image_id = assets_get_image_id("Walkers", "overseer_ne_01") + dir * 12 + f->image_offset; + } +} + void figure_workcamp_worker_action(figure *f) { f->terrain_usage = TERRAIN_USAGE_ROADS_HIGHWAY; @@ -117,8 +128,8 @@ void figure_workcamp_worker_action(figure *f) continue; } if (warehouse_id) { - building *b = building_get(warehouse_id); - if (!building_storage_get_permission(BUILDING_STORAGE_PERMISSION_WORKCAMP, b)) { + building *warehouse = building_get(warehouse_id); + if (!building_storage_get_permission(BUILDING_STORAGE_PERMISSION_WORKCAMP, warehouse)) { continue; } } @@ -206,7 +217,7 @@ void figure_workcamp_worker_action(figure *f) break; } - figure_image_update(f, image_group(GROUP_FIGURE_PATRICIAN)); + workcamp_worker_image_update(f); } void figure_workcamp_slave_action(figure *f) diff --git a/src/game/cheats.c b/src/game/cheats.c index f5d86b5e21..73a11973d3 100644 --- a/src/game/cheats.c +++ b/src/game/cheats.c @@ -154,13 +154,13 @@ void game_cheat_victory(void) } } -void game_cheat_breakpoint() +void game_cheat_breakpoint(void) { if (data.is_cheating) { } } -void game_cheat_console() +void game_cheat_console(void) { if (data.is_cheating) { building_construction_clear_type(); diff --git a/src/game/file.c b/src/game/file.c index 9cfbd0352b..3a6ad8a189 100644 --- a/src/game/file.c +++ b/src/game/file.c @@ -223,10 +223,6 @@ static int load_scenario_data(const char *scenario_file) static int load_custom_scenario(const uint8_t *scenario_name, const char *scenario_file) { - if (!file_exists(scenario_file, NOT_LOCALIZED)) { - return 0; - } - clear_scenario_data(); if (!load_scenario_data(scenario_file)) { return 0; @@ -339,11 +335,15 @@ static int start_scenario(const uint8_t *scenario_name, const char *scenario_fil map_bookmarks_clear(); int is_save_game = 0; if (scenario_is_custom()) { - if (!load_custom_scenario(scenario_name, scenario_file)) { - uint8_t scenario_mapx_name[FILE_NAME_MAX]; - string_copy(scenario_name, scenario_mapx_name, FILE_NAME_MAX); - if (game_file_load_saved_game(scenario_file) == FILE_LOAD_SUCCESS) { + const char *full_scenario_file = dir_get_file_at_location(scenario_file, PATH_LOCATION_SCENARIO); + if (!full_scenario_file) { + return 0; + } + if (!load_custom_scenario(scenario_name, full_scenario_file)) { + if (game_file_load_saved_game(full_scenario_file) == FILE_LOAD_SUCCESS) { is_save_game = 1; + uint8_t scenario_mapx_name[FILE_NAME_MAX]; + string_copy(scenario_name, scenario_mapx_name, FILE_NAME_MAX); scenario_set_name(scenario_mapx_name); } else { return 0; @@ -383,7 +383,7 @@ static const char *get_scenario_filename(const uint8_t *scenario_name, const cha static char filename[FILE_NAME_MAX]; encoding_to_utf8(scenario_name, filename, FILE_NAME_MAX, decomposed); if (!file_has_extension(filename, extension)) { - file_append_extension(filename, extension); + file_append_extension(filename, extension, FILE_NAME_MAX); } return filename; } @@ -503,7 +503,7 @@ void game_file_write_mission_saved_game(void) if (locale_translate_rank_autosaves()) { encoding_to_utf8(lang_get_string(32, rank), localized_filename, FILE_NAME_MAX, encoding_system_uses_decomposed()); - strcat(localized_filename, ".svx"); + strncat(localized_filename, ".svx", FILE_NAME_MAX - strlen(localized_filename) - 1); filename = localized_filename; } } else { @@ -518,7 +518,7 @@ void game_file_write_mission_saved_game(void) encoding_to_utf8(encoded_filename, localized_filename, FILE_NAME_MAX, encoding_system_uses_decomposed()); filename = localized_filename; } - if (!file_exists(filename, NOT_LOCALIZED)) { - game_file_io_write_saved_game(filename); + if (!dir_get_file_at_location(filename, PATH_LOCATION_SAVEGAME)) { + game_file_io_write_saved_game(dir_append_location(filename, PATH_LOCATION_SAVEGAME)); } } diff --git a/src/game/file_io.c b/src/game/file_io.c index 3640103364..fce30d0ba0 100644 --- a/src/game/file_io.c +++ b/src/game/file_io.c @@ -936,7 +936,7 @@ static int read_compressed_chunk_from_buffer(buffer *buf, void *dst, size_t byte { int input_size = buffer_read_i32(buf); if ((unsigned int) input_size == UNCOMPRESSED) { - return buffer_read_raw(buf, dst, bytes_to_read) == bytes_to_read; + return buffer_read_raw(buf, dst, (int) bytes_to_read) == bytes_to_read; } else { if (!core_memory_block_ensure_size(compress_buffer, input_size)) { return 0; @@ -1079,7 +1079,7 @@ static int load_scenario_from_buffer(buffer *buf) static int load_scenario_to_buffers(const char *filename, scenario_version_t *version) { - FILE *fp = file_open(dir_get_file(filename, NOT_LOCALIZED), "rb"); + FILE *fp = file_open(filename, "rb"); if (!fp) { return 0; } @@ -1279,7 +1279,7 @@ static int savegame_read_from_buffer(buffer *buf, savegame_version_t version) core_memory_block_init(&compress_buffer, COMPRESS_BUFFER_INITIAL_SIZE); for (int i = 0; i < savegame_data.num_pieces; i++) { file_piece *piece = &savegame_data.pieces[i]; - int result = 0; + size_t result = 0; if (!prepare_dynamic_piece_from_buffer(buf, piece)) { continue; } @@ -1291,7 +1291,7 @@ static int savegame_read_from_buffer(buffer *buf, savegame_version_t version) } // The last piece may be smaller than buf.size if (!result && i != (savegame_data.num_pieces - 1)) { - log_info("Incorrect buffer size, got", 0, result); + log_info("Incorrect buffer size, got", 0, (int) result); log_info("Incorrect buffer size, expected", 0, (int) piece->buf.size); core_memory_block_free(&compress_buffer); return 0; @@ -1414,7 +1414,7 @@ int game_file_io_read_save_game_from_buffer(buffer *buf) int game_file_io_read_saved_game(const char *filename, int offset) { log_info("Loading saved game", filename, 0); - FILE *fp = file_open(dir_get_file(filename, NOT_LOCALIZED), "rb"); + FILE *fp = file_open(filename, "rb"); if (!fp) { log_error("Unable to load game, unable to open file.", 0, 0); return FILE_LOAD_DOES_NOT_EXIST; @@ -1717,7 +1717,7 @@ int game_file_io_read_saved_game_info(const char *filename, saved_game_info *inf return SAVEGAME_STATUS_INVALID; } memset(info, 0, sizeof(saved_game_info)); - FILE *fp = file_open(dir_get_file(filename, NOT_LOCALIZED), "rb"); + FILE *fp = file_open(filename, "rb"); if (!fp) { return SAVEGAME_STATUS_INVALID; } diff --git a/src/game/game.c b/src/game/game.c index b2a1cb594c..ab7018c7c8 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -27,6 +27,9 @@ #include "graphics/text.h" #include "graphics/video.h" #include "graphics/window.h" +#include "platform/file_manager.h" +#include "platform/prefs.h" +#include "platform/user_path.h" #include "scenario/property.h" #include "scenario/scenario.h" #include "sound/city.h" @@ -111,8 +114,29 @@ int game_init(void) sound_system_init(); game_state_init(); resource_init(); + int actions = ACTION_NONE; + if (missing_fonts) { + actions |= ACTION_SHOW_MESSAGE_MISSING_FONTS; + } + if (is_unpatched()) { + actions |= ACTION_SHOW_MESSAGE_MISSING_PATCH; + } int missing_assets = !assets_get_image_id("Admin_Logistics", "roadblock"); // If can't find roadblocks asset, extra assets not installed properly - window_logo_show(missing_fonts ? MESSAGE_MISSING_FONTS : (is_unpatched() ? MESSAGE_MISSING_PATCH : (missing_assets ? MESSAGE_MISSING_EXTRA_ASSETS : MESSAGE_NONE))); + if (missing_assets) { + actions |= ACTION_SHOW_MESSAGE_MISSING_EXTRA_ASSETS; + } + if (config_must_configure_user_directory()) { + actions |= ACTION_SETUP_USER_DIR; + } else if (!platform_file_manager_is_directory_writeable(pref_user_dir())) { + actions |= ACTION_SHOW_MESSAGE_USER_DIR_NOT_WRITABLE; + } else { + platform_user_path_create_subdirectories(); + } + if (config_get(CONFIG_UI_SHOW_INTRO_VIDEO)) { + actions |= ACTION_SHOW_INTRO_VIDEOS; + } + + window_logo_show(actions); return 1; } diff --git a/src/game/settings.c b/src/game/settings.c index 1fd7b80950..e913fe1346 100644 --- a/src/game/settings.c +++ b/src/game/settings.c @@ -3,7 +3,8 @@ #include "city/constants.h" #include "core/buffer.h" #include "core/calc.h" -#include "core/io.h" +#include "core/dir.h" +#include "core/file.h" #include "core/string.h" #define INF_SIZE 560 @@ -118,8 +119,23 @@ void settings_load(void) { load_default_settings(); - int size = io_read_file_into_buffer("c3.inf", NOT_LOCALIZED, data.inf_file, INF_SIZE); - if (!size) { + const char *settings_file = dir_get_file_at_location("c3.inf", PATH_LOCATION_CONFIG); + if (!settings_file) { + return; + } + FILE *fp = file_open(settings_file, "rb"); + if (!fp) { + return; + } + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + if (size > INF_SIZE) { + size = INF_SIZE; + } + fseek(fp, 0, SEEK_SET); + size_t bytes_read = fread(data.inf_file, 1, INF_SIZE, fp); + file_close(fp); + if (!bytes_read) { return; } @@ -180,7 +196,14 @@ void settings_save(void) buffer_write_i32(buf, data.difficulty); buffer_write_i32(buf, data.gods_enabled); - io_write_buffer_to_file("c3.inf", data.inf_file, INF_SIZE); + // Find existing file to overwrite + const char *settings_file = dir_append_location("c3.inf", PATH_LOCATION_CONFIG); + FILE *fp = file_open(settings_file, "wb"); + if (!fp) { + return; + } + fwrite(data.inf_file, 1, INF_SIZE, fp); + file_close(fp); } int setting_fullscreen(void) diff --git a/src/game/system.h b/src/game/system.h index 51848e9626..f79e9eded3 100644 --- a/src/game/system.h +++ b/src/game/system.h @@ -192,6 +192,20 @@ void system_set_mouse_position(int *x, int *y); */ void system_setup_crash_handler(void); +/** + * Indicates whether the current platform supports a "selct folder" dialog + * @return 1 if it supports displaying a folder dialog, 0 otherwise + */ +int system_supports_select_folder_dialog(void); + +/** + * Shows a "select folder" dialog + * @param title Title of the dialog + * @param default_path Default path to show + * @return The selected folder, or 0 if the dialog was cancelled + */ +const char *system_show_select_folder_dialog(const char *title, const char *default_path); + /** * Exit the game */ diff --git a/src/game/tick.c b/src/game/tick.c index 0772df7265..d5b8a4f895 100644 --- a/src/game/tick.c +++ b/src/game/tick.c @@ -32,6 +32,7 @@ #include "city/trade.h" #include "city/victory.h" #include "core/config.h" +#include "core/dir.h" #include "core/random.h" #include "editor/editor.h" #include "empire/city.h" @@ -117,10 +118,10 @@ static void advance_month(void) scenario_events_progress_paused(1); scenario_events_process_all(); if (setting_monthly_autosave()) { - game_file_write_saved_game("autosave.svx"); + game_file_write_saved_game(dir_append_location("autosave.svx", PATH_LOCATION_SAVEGAME)); } if (new_year && config_get(CONFIG_GP_CH_YEARLY_AUTOSAVE)) { - game_file_write_saved_game("autosave-year.svx"); + game_file_write_saved_game(dir_append_location("autosave-year.svx", PATH_LOCATION_SAVEGAME)); } } diff --git a/src/graphics/arrow_button.c b/src/graphics/arrow_button.c index 0f76cd683f..f77d90d203 100644 --- a/src/graphics/arrow_button.c +++ b/src/graphics/arrow_button.c @@ -11,9 +11,9 @@ static const int REPEATS[] = { static const time_millis REPEAT_MILLIS = 30; static const unsigned int BUTTON_PRESSED_FRAMES = 3; -void arrow_buttons_draw(int x, int y, arrow_button *buttons, int num_buttons) +void arrow_buttons_draw(int x, int y, arrow_button *buttons, unsigned int num_buttons) { - for (int i = 0; i < num_buttons; i++) { + for (unsigned int i = 0; i < num_buttons; i++) { int image_id = buttons[i].image_id; if (buttons[i].pressed) { image_id += 1; @@ -22,9 +22,9 @@ void arrow_buttons_draw(int x, int y, arrow_button *buttons, int num_buttons) } } -static int get_button(const mouse *m, int x, int y, arrow_button *buttons, int num_buttons) +static unsigned int get_button(const mouse *m, int x, int y, arrow_button *buttons, unsigned int num_buttons) { - for (int i = 0; i < num_buttons; i++) { + for (unsigned int i = 0; i < num_buttons; i++) { if (x + buttons[i].x_offset <= m->x && x + buttons[i].x_offset + buttons[i].size > m->x && y + buttons[i].y_offset <= m->y && @@ -36,7 +36,7 @@ static int get_button(const mouse *m, int x, int y, arrow_button *buttons, int n } int arrow_buttons_handle_mouse( - const mouse *m, int x, int y, arrow_button *buttons, int num_buttons, int *focus_button_id) + const mouse *m, int x, int y, arrow_button *buttons, unsigned int num_buttons, unsigned int *focus_button_id) { time_millis curr_time = time_get_millis(); int should_repeat = 0; @@ -44,7 +44,7 @@ int arrow_buttons_handle_mouse( should_repeat = 1; buttons->last_time = curr_time; } - for (int i = 0; i < num_buttons; i++) { + for (unsigned int i = 0; i < num_buttons; i++) { arrow_button *btn = &buttons[i]; if (btn->pressed) { btn->pressed--; diff --git a/src/graphics/arrow_button.h b/src/graphics/arrow_button.h index ea43fc968c..c21687cba4 100644 --- a/src/graphics/arrow_button.h +++ b/src/graphics/arrow_button.h @@ -18,9 +18,9 @@ typedef struct { time_millis last_time; } arrow_button; -void arrow_buttons_draw(int x, int y, arrow_button *buttons, int num_buttons); +void arrow_buttons_draw(int x, int y, arrow_button *buttons, unsigned int num_buttons); int arrow_buttons_handle_mouse( - const mouse *m, int x, int y, arrow_button *buttons, int num_buttons, int *focus_button_id); + const mouse *m, int x, int y, arrow_button *buttons, unsigned int num_buttons, unsigned int *focus_button_id); #endif // GRAPHICS_ARROW_BUTTON_H diff --git a/src/graphics/generic_button.c b/src/graphics/generic_button.c index f24e5a79f8..408843040d 100644 --- a/src/graphics/generic_button.c +++ b/src/graphics/generic_button.c @@ -2,9 +2,9 @@ #include "graphics/lang_text.h" -static int get_button(const mouse *m, int x, int y, generic_button *buttons, int num_buttons) +static unsigned int get_button(const mouse *m, int x, int y, generic_button *buttons, unsigned int num_buttons) { - for (int i = 0; i < num_buttons; i++) { + for (unsigned int i = 0; i < num_buttons; i++) { if (x + buttons[i].x <= m->x && x + buttons[i].x + buttons[i].width > m->x && y + buttons[i].y <= m->y && @@ -15,22 +15,10 @@ static int get_button(const mouse *m, int x, int y, generic_button *buttons, int return 0; } -static int get_button_min(const mouse* m, int x, int y, generic_button* buttons, int num_buttons, int minimum_button) +int generic_buttons_handle_mouse(const mouse *m, int x, int y, generic_button *buttons, unsigned int num_buttons, + unsigned int *focus_button_id) { - for (int i = minimum_button; i < num_buttons; i++) { - if (x + buttons[i].x <= m->x && - x + buttons[i].x + buttons[i].width > m->x&& - y + buttons[i].y <= m->y && - y + buttons[i].y + buttons[i].height > m->y) { - return i + 1; - } - } - return 0; -} - -int generic_buttons_handle_mouse(const mouse *m, int x, int y, generic_button *buttons, int num_buttons, int *focus_button_id) -{ - int button_id = get_button(m, x, y, buttons, num_buttons); + unsigned int button_id = get_button(m, x, y, buttons, num_buttons); if (focus_button_id) { *focus_button_id = button_id; } @@ -48,28 +36,3 @@ int generic_buttons_handle_mouse(const mouse *m, int x, int y, generic_button *b return 0; } } - -int generic_buttons_min_handle_mouse(const mouse* m, int x, int y, generic_button* buttons, int num_buttons, int* focus_button_id, int minimum_button) -{ - int button_id = get_button_min(m, x, y, buttons, num_buttons,minimum_button); - if (focus_button_id) { - *focus_button_id = button_id; - } - if (!button_id) { - return 0; - } - generic_button* button = &buttons[button_id - 1]; - if (m->left.went_up) { - button->left_click_handler(button->parameter1, button->parameter2); - } - else if (m->right.went_up) { - button->right_click_handler(button->parameter1, button->parameter2); - } - else { - return 0; - } - return button_id; -} - - - diff --git a/src/graphics/generic_button.h b/src/graphics/generic_button.h index ee157e124d..6bb0b1a623 100644 --- a/src/graphics/generic_button.h +++ b/src/graphics/generic_button.h @@ -16,7 +16,7 @@ typedef struct { int parameter2; } generic_button; -int generic_buttons_handle_mouse(const mouse *m, int x, int y, generic_button *buttons, int num_buttons, int *focus_button_id); -int generic_buttons_min_handle_mouse(const mouse* m, int x, int y, generic_button* buttons, int num_buttons, int* focus_button_id, int minimum_button); +int generic_buttons_handle_mouse(const mouse *m, int x, int y, generic_button *buttons, unsigned int num_buttons, + unsigned int *focus_button_id); #endif // GRAPHICS_CUSTOM_BUTTON_H diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index ce7ef33ecf..9ddea0c3fd 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -14,12 +14,13 @@ static void set_translation(int x, int y) void graphics_in_dialog(void) { - set_translation(screen_dialog_offset_x(), screen_dialog_offset_y()); + graphics_in_dialog_with_size(640, 480); } void graphics_in_dialog_with_size(int width, int height) { set_translation((screen_width() - width) / 2, (screen_height() - height) / 2); + screen_set_dialog_offset(width, height); } void graphics_reset_dialog(void) diff --git a/src/graphics/image_button.c b/src/graphics/image_button.c index 94e1a947a4..28f2f3054f 100644 --- a/src/graphics/image_button.c +++ b/src/graphics/image_button.c @@ -8,10 +8,10 @@ #define PRESSED_REPEAT_INITIAL_MILLIS 300 #define PRESSED_REPEAT_MILLIS 50 -static void fade_pressed_effect(image_button *buttons, int num_buttons) +static void fade_pressed_effect(image_button *buttons, unsigned int num_buttons) { time_millis current_time = time_get_millis(); - for (int i = 0; i < num_buttons; i++) { + for (unsigned int i = 0; i < num_buttons; i++) { image_button *btn = &buttons[i]; if (btn->pressed) { if (current_time - btn->pressed_since > PRESSED_EFFECT_MILLIS) { @@ -25,9 +25,9 @@ static void fade_pressed_effect(image_button *buttons, int num_buttons) } } -static void fade_pressed_effect_build(image_button *buttons, int num_buttons) +static void fade_pressed_effect_build(image_button *buttons, unsigned int num_buttons) { - for (int i = 0; i < num_buttons; i++) { + for (unsigned int i = 0; i < num_buttons; i++) { image_button *btn = &buttons[i]; if (btn->pressed && btn->button_type == IB_BUILD) { btn->pressed--; @@ -35,10 +35,10 @@ static void fade_pressed_effect_build(image_button *buttons, int num_buttons) } } -void image_buttons_draw(int x, int y, image_button *buttons, int num_buttons) +void image_buttons_draw(int x, int y, image_button *buttons, unsigned int num_buttons) { fade_pressed_effect(buttons, num_buttons); - for (int i = 0; i < num_buttons; i++) { + for (unsigned int i = 0; i < num_buttons; i++) { image_button *btn = &buttons[i]; int image_id = 0; if (btn->image_collection) { @@ -59,7 +59,6 @@ void image_buttons_draw(int x, int y, image_button *buttons, int num_buttons) } } - static int should_be_pressed(const image_button *btn, const mouse *m) { if ((m->left.went_down || m->left.is_down) && btn->left_click_handler != button_none) { @@ -72,7 +71,7 @@ static int should_be_pressed(const image_button *btn, const mouse *m) } int image_buttons_handle_mouse( - const mouse *m, int x, int y, image_button *buttons, int num_buttons, int *focus_button_id) + const mouse *m, int x, int y, image_button *buttons, unsigned int num_buttons, unsigned int *focus_button_id) { fade_pressed_effect(buttons, num_buttons); fade_pressed_effect_build(buttons, num_buttons); @@ -80,7 +79,7 @@ int image_buttons_handle_mouse( if (focus_button_id) { *focus_button_id = 0; } - for (int i = 0; i < num_buttons; i++) { + for (unsigned int i = 0; i < num_buttons; i++) { image_button *btn = &buttons[i]; if (btn->focused) { btn->focused--; diff --git a/src/graphics/image_button.h b/src/graphics/image_button.h index f6119a2772..b7cafd3619 100644 --- a/src/graphics/image_button.h +++ b/src/graphics/image_button.h @@ -34,9 +34,9 @@ typedef struct { time_millis pressed_since; } image_button; -void image_buttons_draw(int x, int y, image_button *buttons, int num_buttons); +void image_buttons_draw(int x, int y, image_button *buttons, unsigned int num_buttons); int image_buttons_handle_mouse( - const mouse *m, int x, int y, image_button *buttons, int num_buttons, int *focus_button_id); + const mouse *m, int x, int y, image_button *buttons, unsigned int num_buttons, unsigned int *focus_button_id); #endif // GRAPHICS_IMAGE_BUTTON_H diff --git a/src/graphics/lang_text.c b/src/graphics/lang_text.c index 027ac525ff..5d6d306597 100644 --- a/src/graphics/lang_text.c +++ b/src/graphics/lang_text.c @@ -131,5 +131,5 @@ void lang_text_draw_month_year_max_width( int lang_text_draw_multiline(int group, int number, int x_offset, int y_offset, int box_width, font_t font) { const uint8_t *str = lang_get_string(group, number); - return text_draw_multiline(str, x_offset, y_offset, box_width, font, 0); + return text_draw_multiline(str, x_offset, y_offset, box_width, 0, font, 0); } diff --git a/src/graphics/list_box.c b/src/graphics/list_box.c index 154dba8100..37d85b8a54 100644 --- a/src/graphics/list_box.c +++ b/src/graphics/list_box.c @@ -8,29 +8,38 @@ #include "graphics/window.h" #include "input/scroll.h" +static unsigned int calculate_scrollable_items(const list_box_type *list_box) +{ + if (list_box->num_columns == 1) { + return list_box->total_items; + } + return (list_box->total_items + list_box->num_columns - 1) / list_box->num_columns; +} -void list_box_init(list_box_type *list_box, int total_items) +void list_box_init(list_box_type *list_box, unsigned int total_items) { list_box->selected_index = LIST_BOX_NO_SELECTION; list_box->total_items = total_items; list_box->focus_button_id = LIST_BOX_NO_SELECTION; - - scrollbar_init(&list_box->scrollbar, 0, list_box->total_items); + if (list_box->num_columns < 1) { + list_box->num_columns = 1; + } + scrollbar_init(&list_box->scrollbar, 0, calculate_scrollable_items(list_box)); } -void list_box_update_total_items(list_box_type *list_box, int total_items) +void list_box_update_total_items(list_box_type *list_box, unsigned int total_items) { list_box->total_items = total_items; - scrollbar_update_total_elements(&list_box->scrollbar, total_items); + scrollbar_update_total_elements(&list_box->scrollbar, calculate_scrollable_items(list_box)); list_box_request_refresh(list_box); } -int list_box_get_total_items(const list_box_type *list_box) +unsigned int list_box_get_total_items(const list_box_type *list_box) { return list_box->total_items; } -void list_box_select_index(list_box_type *list_box, int index) +void list_box_select_index(list_box_type *list_box, unsigned int index) { if (index == list_box->selected_index) { return; @@ -42,21 +51,21 @@ void list_box_select_index(list_box_type *list_box, int index) } } -int list_box_get_selected_index(const list_box_type *list_box) +unsigned int list_box_get_selected_index(const list_box_type *list_box) { return list_box->selected_index; } -void list_box_show_index(list_box_type *list_box, int index) +void list_box_show_index(list_box_type *list_box, unsigned int index) { if (index == LIST_BOX_NO_SELECTION) { return; } scrollbar_type *scrollbar = &list_box->scrollbar; if (index >= list_box->total_items) { - scrollbar_reset(scrollbar, list_box->total_items - scrollbar->elements_in_view + 1); + scrollbar_reset(scrollbar, calculate_scrollable_items(list_box) - scrollbar->elements_in_view + 1); } else { - scrollbar_reset(scrollbar, index); + scrollbar_reset(scrollbar, index / list_box->num_columns); } } @@ -81,7 +90,8 @@ void list_box_request_refresh(list_box_type *list_box) static int get_actual_width_blocks(const list_box_type *list_box) { int width_blocks = list_box->width_blocks; - if (!list_box->extend_to_hidden_scrollbar || list_box->total_items > list_box->scrollbar.elements_in_view) { + if (!list_box->extend_to_hidden_scrollbar || + calculate_scrollable_items(list_box) > list_box->scrollbar.elements_in_view) { width_blocks -= 2; } return width_blocks; @@ -105,7 +115,7 @@ static void draw_scrollbar(list_box_type *list_box) } scrollbar->elements_in_view = scrollable_height_pixels / list_box->item_height; - scrollbar_update_total_elements(scrollbar, list_box->total_items); + scrollbar_update_total_elements(scrollbar, calculate_scrollable_items(list_box)); if (list_box->decorate_scrollbar && list_box->total_items > scrollbar->elements_in_view) { inner_panel_draw(scrollbar->x + 4, scrollbar->y + 32, 2, scrollbar->height / BLOCK_SIZE - 4); @@ -132,25 +142,27 @@ void list_box_draw(list_box_type *list_box) if (list_box->draw_item) { list_box_item item = { - .x = list_box->x + padding, .y = list_box->y + padding, - .width = width_blocks * BLOCK_SIZE - padding * 2, + .width = (width_blocks * BLOCK_SIZE - padding * 2) / list_box->num_columns, .height = list_box->item_height }; - int elements_in_view = list_box->scrollbar.elements_in_view; - int index = list_box->scrollbar.scroll_position; + unsigned int elements_in_view = list_box->scrollbar.elements_in_view * list_box->num_columns; + unsigned int index = list_box->scrollbar.scroll_position * list_box->num_columns; - for (int i = 0; i < elements_in_view; i++, index++) { + for (unsigned int i = 0; i < elements_in_view; i++, index++) { if (index >= list_box->total_items) { break; } + item.x = list_box->x + padding + item.width * (i % list_box->num_columns); item.index = index; - item.button_position = i; + item.position = i; item.is_selected = index == list_box->selected_index; item.is_focused = list_box->focus_button_id == i; list_box->draw_item(&item); - item.y += list_box->item_height; + if (i % list_box->num_columns == list_box->num_columns - 1) { + item.y += list_box->item_height; + } } } } @@ -172,7 +184,7 @@ static int handle_arrow_keys(list_box_type *list_box, int direction) default: return 0; } - int max_index = list_box->total_items - 1; + unsigned int max_index = list_box->total_items - 1; if (list_box->selected_index == LIST_BOX_NO_SELECTION) { if (delta == 1) { list_box->selected_index = 0; @@ -200,19 +212,25 @@ static int handle_arrow_keys(list_box_type *list_box, int direction) return 1; } -static int get_button_id_from_position(const list_box_type *list_box, int x, int y) +static unsigned int get_button_id_from_position(const list_box_type *list_box, int x, int y) { int padding = list_box->draw_inner_panel ? BLOCK_SIZE / 2 : 0; int width_blocks = get_actual_width_blocks(list_box); - if (x < list_box->x + padding || x > list_box->x + width_blocks * BLOCK_SIZE - padding || y < list_box->y) { + if (x < list_box->x + padding || x >= list_box->x + width_blocks * BLOCK_SIZE - padding || y < list_box->y) { return LIST_BOX_NO_SELECTION; } - int button_id = (y - padding / 2 - list_box->y) / list_box->item_height; - if (button_id < 0 || button_id >= list_box->scrollbar.elements_in_view || + unsigned int button_id = (y - padding / 2 - list_box->y) / list_box->item_height; + if (button_id >= list_box->scrollbar.elements_in_view || button_id + list_box->scrollbar.scroll_position >= list_box->total_items) { return LIST_BOX_NO_SELECTION; } - return button_id; + if (list_box->num_columns == 1) { + return button_id; + } + button_id *= list_box->num_columns; + int item_width = (width_blocks * BLOCK_SIZE - padding * 2) / list_box->num_columns; + int line_index = (x - list_box->x - padding) / item_width; + return button_id + line_index; } int list_box_handle_input(list_box_type *list_box, const mouse *m, int in_dialog) @@ -224,7 +242,7 @@ int list_box_handle_input(list_box_type *list_box, const mouse *m, int in_dialog list_box_request_refresh(list_box); return 1; } - int old_focus_button_id = list_box->focus_button_id; + unsigned int old_focus_button_id = list_box->focus_button_id; list_box->focus_button_id = get_button_id_from_position(list_box, m->x, m->y); if (old_focus_button_id != list_box->focus_button_id) { @@ -235,8 +253,14 @@ int list_box_handle_input(list_box_type *list_box, const mouse *m, int in_dialog return 0; } - if (list_box->selected_index != list_box->focus_button_id + scrollbar->scroll_position) { - list_box->selected_index = list_box->focus_button_id + scrollbar->scroll_position; + unsigned int selected_index = list_box->focus_button_id + scrollbar->scroll_position * list_box->num_columns; + + if (selected_index >= list_box->total_items) { + return 0; + } + + if (list_box->selected_index != selected_index) { + list_box->selected_index = selected_index; list_box_request_refresh(list_box); } if (list_box->on_select) { @@ -252,15 +276,18 @@ void list_box_handle_tooltip(const list_box_type *list_box, tooltip_context *c) return; } int padding = list_box->draw_inner_panel ? BLOCK_SIZE / 2 : 0; + int item_width = (get_actual_width_blocks(list_box) * BLOCK_SIZE - padding * 2) / list_box->num_columns; list_box_item item = { - .x = list_box->x + padding, - .y = list_box->y + padding, - .width = get_actual_width_blocks(list_box) * BLOCK_SIZE - padding * 2, + .width = item_width, .height = list_box->item_height, - .index = list_box->focus_button_id + list_box->scrollbar.scroll_position, - .button_position = list_box->focus_button_id, + .index = list_box->focus_button_id + list_box->scrollbar.scroll_position * list_box->num_columns, + .position = list_box->focus_button_id, + .x = list_box->x + padding + item_width * (list_box->focus_button_id % list_box->num_columns), + .y = list_box->y + padding + list_box->item_height * (list_box->focus_button_id / list_box->num_columns), .is_selected = item.index == list_box->selected_index, .is_focused = 1 }; - list_box->handle_tooltip(&item, c); + if (item.index < list_box->total_items) { + list_box->handle_tooltip(&item, c); + } } diff --git a/src/graphics/list_box.h b/src/graphics/list_box.h index 3c208a6ac6..c813eec763 100644 --- a/src/graphics/list_box.h +++ b/src/graphics/list_box.h @@ -5,15 +5,15 @@ #include "graphics/tooltip.h" #include "input/mouse.h" -#define LIST_BOX_NO_SELECTION -1 +#define LIST_BOX_NO_SELECTION ((unsigned int) -1) typedef struct { int x; int y; int width; int height; - int index; - int button_position; + unsigned int index; + unsigned int position; int is_selected; int is_focused; } list_box_item; @@ -21,34 +21,35 @@ typedef struct { typedef struct { int x; int y; - int width_blocks; - int height_blocks; - int item_height; + unsigned int width_blocks; + unsigned int height_blocks; + unsigned int item_height; + unsigned int num_columns; int draw_inner_panel; int extend_to_hidden_scrollbar; int decorate_scrollbar; void (*draw_item)(const list_box_item *item); - void (*on_select)(int index, int is_double_click); + void (*on_select)(unsigned int index, int is_double_click); void (*handle_tooltip)(const list_box_item *item, tooltip_context *c); /* Private elements */ - int total_items; - int selected_index; + unsigned int total_items; + unsigned int selected_index; + unsigned int focus_button_id; scrollbar_type scrollbar; - int focus_button_id; int refresh_requested; } list_box_type; -void list_box_init(list_box_type *list_box, int total_items); -void list_box_update_total_items(list_box_type *list_box, int total_items); -int list_box_get_total_items(const list_box_type *list_box); +void list_box_init(list_box_type *list_box, unsigned int total_items); +void list_box_update_total_items(list_box_type *list_box, unsigned int total_items); +unsigned int list_box_get_total_items(const list_box_type *list_box); void list_box_draw(list_box_type *list_box); int list_box_handle_input(list_box_type *list_box, const mouse *m, int in_dialog); void list_box_handle_tooltip(const list_box_type *list_box, tooltip_context *c); -void list_box_show_index(list_box_type *list_box, int index); +void list_box_show_index(list_box_type *list_box, unsigned int index); void list_box_show_selected_index(list_box_type *list_box); -void list_box_select_index(list_box_type *list_box, int index); -int list_box_get_selected_index(const list_box_type *list_box); +void list_box_select_index(list_box_type *list_box, unsigned int index); +unsigned int list_box_get_selected_index(const list_box_type *list_box); void list_box_request_refresh(list_box_type *list_box); int list_box_get_scroll_position(const list_box_type *list_box); diff --git a/src/graphics/rich_text.c b/src/graphics/rich_text.c index 5da0319de7..5999a100f0 100644 --- a/src/graphics/rich_text.c +++ b/src/graphics/rich_text.c @@ -253,19 +253,20 @@ static int get_raw_text_width(const uint8_t *str) static int get_external_image_id(const char *filename) { char full_path[FILE_NAME_MAX]; - char *paths[] = { CAMPAIGNS_DIRECTORY "/image", "community/image" }; - int found_path = 0; - for (int i = 0; i < 2; i++) { + char *paths[] = { CAMPAIGNS_DIRECTORY "/image", "image" }; + const char *found_path = 0; + for (int i = 0; i < 2 && !found_path; i++) { snprintf(full_path, FILE_NAME_MAX, "%s/%s", paths[i], filename); - if (campaign_has_file(full_path) || file_exists(full_path, NOT_LOCALIZED)) { - found_path = 1; - break; + if (campaign_has_file(full_path)) { + found_path = full_path; + } else { + found_path = dir_get_file_at_location(full_path, PATH_LOCATION_COMMUNITY); } } if (!found_path) { return 0; } - return assets_get_external_image(full_path, 0); + return assets_get_external_image(found_path, 0); } int rich_text_parse_image_id(const uint8_t **position, int default_image_group, int can_be_filepath) @@ -297,8 +298,7 @@ int rich_text_parse_image_id(const uint8_t **position, int default_image_group, cursor += length + 1; char *location = malloc((length + 1) * sizeof(char)); if (location) { - strncpy(location, begin, length); - location[length] = 0; + snprintf(location, length + 1, "%s", begin); char *divider = strchr(location, ':'); // "[:]" if (divider) { @@ -341,7 +341,7 @@ int rich_text_parse_image_id(const uint8_t **position, int default_image_group, } static int draw_text(const uint8_t *text, int x_offset, int y_offset, - int box_width, int height_lines, color_t color, int measure_only) + int box_width, unsigned int height_lines, color_t color, int measure_only) { if (!measure_only) { graphics_set_clip_rectangle(x_offset, y_offset, box_width, data.line_height * height_lines); @@ -357,8 +357,8 @@ static int draw_text(const uint8_t *text, int x_offset, int y_offset, int has_more_characters = 1; int y = y_offset; int guard = 0; - int line = 0; - int num_lines = 0; + unsigned int line = 0; + unsigned int num_lines = 0; int heading = 0; while (has_more_characters || lines_to_skip) { if (++guard >= 1000) { @@ -374,6 +374,7 @@ static int draw_text(const uint8_t *text, int x_offset, int y_offset, int current_width = x_line_offset; const font_definition *def = heading ? data.heading_font : data.normal_font; paragraph = 0; + int centered = heading; while (!line_break && (has_more_characters || lines_to_skip)) { if (lines_to_skip) { lines_to_skip--; @@ -415,6 +416,7 @@ static int draw_text(const uint8_t *text, int x_offset, int y_offset, lines_to_skip = 1; } else { def = data.heading_font; + centered = 1; } text++; break; @@ -483,7 +485,7 @@ static int draw_text(const uint8_t *text, int x_offset, int y_offset, } } if (!outside_viewport) { - if (def == data.heading_font) { + if (centered) { x_line_offset = (box_width - current_width) / 2; } draw_line(tmp_line, def, x_line_offset + x_offset, y, color, measure_only); diff --git a/src/graphics/screen.c b/src/graphics/screen.c index 683a8ac42d..3d2b0d7a1a 100644 --- a/src/graphics/screen.c +++ b/src/graphics/screen.c @@ -14,12 +14,17 @@ static struct { } dialog_offset; } data; +void screen_set_dialog_offset(int width, int height) +{ + data.dialog_offset.x = (data.width - width) / 2; + data.dialog_offset.y = (data.height - height) / 2; +} + void screen_set_resolution(int width, int height) { data.width = width; data.height = height; - data.dialog_offset.x = (width - 640) / 2; - data.dialog_offset.y = (height - 480) / 2; + screen_set_dialog_offset(640, 480); graphics_renderer()->clear_screen(); graphics_renderer()->set_clip_rectangle(0, 0, width, height); diff --git a/src/graphics/screen.h b/src/graphics/screen.h index 764a3f4227..d65f2fba03 100644 --- a/src/graphics/screen.h +++ b/src/graphics/screen.h @@ -3,6 +3,8 @@ #include "graphics/color.h" +void screen_set_dialog_offset(int width, int height); + void screen_set_resolution(int width, int height); color_t *screen_pixel(int x, int y); diff --git a/src/graphics/screenshot.c b/src/graphics/screenshot.c index c4152a7bfc..5fbaa5f7ad 100644 --- a/src/graphics/screenshot.c +++ b/src/graphics/screenshot.c @@ -93,7 +93,7 @@ static int image_create(int width, int height, int has_alpha_channel, int rows_i static const char *generate_filename(screenshot_type type) { - static char filename[FILE_NAME_MAX]; + char filename[FILE_NAME_MAX]; time_t curtime = time(NULL); struct tm *loctime = localtime(&curtime); switch (type) { @@ -108,7 +108,7 @@ static const char *generate_filename(screenshot_type type) strftime(filename, FILE_NAME_MAX, "city %Y-%m-%d %H.%M.%S.png", loctime); break; } - return filename; + return dir_append_location(filename, PATH_LOCATION_SCREENSHOT); } static int image_begin_io(const char *filename) diff --git a/src/graphics/scrollbar.c b/src/graphics/scrollbar.c index 333d88bf01..0b7c301ead 100644 --- a/src/graphics/scrollbar.c +++ b/src/graphics/scrollbar.c @@ -31,11 +31,13 @@ static image_button image_button_scroll_down = { static scrollbar_type *current; -void scrollbar_init(scrollbar_type *scrollbar, int scroll_position, int total_elements) +void scrollbar_init(scrollbar_type *scrollbar, unsigned int scroll_position, unsigned int total_elements) { - int max_scroll_position = total_elements - scrollbar->elements_in_view; - if (max_scroll_position < 0) { + unsigned int max_scroll_position; + if (total_elements <= scrollbar->elements_in_view) { max_scroll_position = 0; + } else { + max_scroll_position = total_elements - scrollbar->elements_in_view; } scrollbar->scroll_position = calc_bound(scroll_position, 0, max_scroll_position); scrollbar->max_scroll_position = max_scroll_position; @@ -43,18 +45,20 @@ void scrollbar_init(scrollbar_type *scrollbar, int scroll_position, int total_el scrollbar->touch_drag_state = TOUCH_DRAG_NONE; } -void scrollbar_reset(scrollbar_type *scrollbar, int scroll_position) +void scrollbar_reset(scrollbar_type *scrollbar, unsigned int scroll_position) { scrollbar->scroll_position = calc_bound(scroll_position, 0, scrollbar->max_scroll_position); scrollbar->is_dragging_scrollbar_dot = 0; scrollbar->touch_drag_state = TOUCH_DRAG_NONE; } -void scrollbar_update_total_elements(scrollbar_type *scrollbar, int total_elements) +void scrollbar_update_total_elements(scrollbar_type *scrollbar, unsigned int total_elements) { - int max_scroll_position = total_elements - scrollbar->elements_in_view; - if (max_scroll_position < 0) { + unsigned int max_scroll_position; + if (total_elements <= scrollbar->elements_in_view) { max_scroll_position = 0; + } else { + max_scroll_position = total_elements - scrollbar->elements_in_view; } scrollbar->max_scroll_position = max_scroll_position; if (scrollbar->scroll_position > max_scroll_position) { @@ -104,7 +108,7 @@ static int touch_inside_scrollable_area(const scrollbar_type *scrollbar, const t static int handle_touch(scrollbar_type *scrollbar, const touch *t, int in_dialog) { - int old_position = scrollbar->scroll_position; + unsigned int old_position = scrollbar->scroll_position; int active = scrollbar->touch_drag_state == TOUCH_DRAG_IN_PROGRESS; if (t->has_started && touch_inside_scrollable_area(scrollbar, t, in_dialog)) { @@ -204,9 +208,10 @@ static void text_scroll(int is_down, int num_lines) scrollbar->scroll_position = scrollbar->max_scroll_position; } } else { - scrollbar->scroll_position -= num_lines; - if (scrollbar->scroll_position < 0) { + if (scrollbar->scroll_position <= (unsigned int) num_lines) { scrollbar->scroll_position = 0; + } else { + scrollbar->scroll_position -= num_lines; } } scrollbar->is_dragging_scrollbar_dot = 0; diff --git a/src/graphics/scrollbar.h b/src/graphics/scrollbar.h index 01233ae51b..52085aa8ec 100644 --- a/src/graphics/scrollbar.h +++ b/src/graphics/scrollbar.h @@ -10,13 +10,13 @@ typedef struct { int y; int height; int scrollable_width; - int elements_in_view; + unsigned int elements_in_view; void (*on_scroll_callback)(void); int has_y_margin; int dot_padding; int always_visible; - int max_scroll_position; - int scroll_position; + unsigned int max_scroll_position; + unsigned int scroll_position; int is_dragging_scrollbar_dot; int scrollbar_dot_drag_offset; int touch_drag_state; @@ -29,21 +29,21 @@ typedef struct { * @param scroll_position Scroll position to set * @param total_elements The number of elements to scroll */ -void scrollbar_init(scrollbar_type *scrollbar, int scroll_position, int total_elements); +void scrollbar_init(scrollbar_type *scrollbar, unsigned int scroll_position, unsigned int total_elements); /** * Resets the text to the specified scroll position and forces recalculation of lines * @param scrollbar Scrollbar * @param scroll_position Scroll position to set */ -void scrollbar_reset(scrollbar_type *scrollbar, int scroll_position); +void scrollbar_reset(scrollbar_type *scrollbar, unsigned int scroll_position); /** * Update the number of total elements, adjusting the scroll position if necessary * @param scrollbar Scrollbar - * @param total_items New number of total elements + * @param total_elements New number of total elements */ -void scrollbar_update_total_elements(scrollbar_type *scrollbar, int total_elements); +void scrollbar_update_total_elements(scrollbar_type *scrollbar, unsigned int total_elements); /** * Draws the scrollbar diff --git a/src/graphics/text.c b/src/graphics/text.c index dc41afd23b..aff4654d5a 100644 --- a/src/graphics/text.c +++ b/src/graphics/text.c @@ -285,22 +285,6 @@ static int get_word_width(const uint8_t *str, font_t font, int *out_num_chars, i return width; } -void text_draw_centered_with_linebreaks(const uint8_t *str, int x, int y, int box_width, font_t font, color_t color) -{ - int count = 0; - char *split; - - char oldstr[512]; - strcpy(oldstr, (char *) str); - - split = strtok(oldstr, "\n"); - while (split != NULL) { - text_draw_centered((uint8_t *) split, x, y + (20 * count), box_width, font, color); - count++; - split = strtok(NULL, "\n"); - } -} - void text_draw_centered(const uint8_t *str, int x, int y, int box_width, font_t font, color_t color) { int offset = (box_width - text_get_width(str, font)) / 2; @@ -575,7 +559,8 @@ void text_draw_number_centered_colored( text_draw_centered(str, x_offset, y_offset, box_width, font, color); } -int text_draw_multiline(const uint8_t *str, int x_offset, int y_offset, int box_width, font_t font, uint32_t color) +int text_draw_multiline(const uint8_t *str, int x_offset, int y_offset, int box_width, + int centered, font_t font, color_t color) { int line_height = font_definition_for(font)->line_height; if (line_height < 11) { @@ -594,37 +579,36 @@ int text_draw_multiline(const uint8_t *str, int x_offset, int y_offset, int box_ } int current_width = 0; int line_index = 0; - while (has_more_characters && current_width < box_width) { + while (has_more_characters) { int word_num_chars; int word_width = get_word_width(str, font, &word_num_chars, 0); if (word_width >= box_width) { word_width = get_word_width(str, font, &word_num_chars, box_width - current_width); if (!word_num_chars) { - current_width = box_width; + has_more_characters = 0; + break; } } + if (current_width + word_width >= box_width) { + break; + } current_width += word_width; - if (current_width >= box_width) { - if (current_width == 0) { - has_more_characters = 0; - } - } else { - for (int i = 0; i < word_num_chars; i++) { - if (line_index == 0 && *str <= ' ') { - str++; // skip whitespace at start of line - } else { - tmp_line[line_index++] = *str++; - } - } - if (!*str) { - has_more_characters = 0; - } else if (*str == '\n') { - str++; - break; + for (int i = 0; i < word_num_chars; i++) { + if (line_index == 0 && *str <= ' ') { + str++; // skip whitespace at start of line + } else { + tmp_line[line_index++] = *str++; } } + if (!*str) { + has_more_characters = 0; + } else if (*str == '\n') { + str++; + break; + } } - text_draw(tmp_line, x_offset, y, font, color); + int line_offset = centered ? (box_width - current_width) / 2 : 0; + text_draw(tmp_line, x_offset + line_offset, y, font, color); y += line_height + 5; } return y - y_offset; diff --git a/src/graphics/text.h b/src/graphics/text.h index b8d0abb780..e12e19a1da 100644 --- a/src/graphics/text.h +++ b/src/graphics/text.h @@ -45,8 +45,9 @@ void text_draw_number_centered_postfix( void text_draw_number_centered_colored( int value, int x_offset, int y_offset, int box_width, font_t font, color_t color); -int text_draw_multiline(const uint8_t *str, int x_offset, int y_offset, int box_width, font_t font, uint32_t color); -void text_draw_centered_with_linebreaks(const uint8_t *str, int x, int y, int box_width, font_t font, color_t color); +int text_draw_multiline(const uint8_t *str, int x_offset, int y_offset, int box_width, + int centered, font_t font, color_t color); + /** * @return Number of lines required to draw the text */ diff --git a/src/graphics/tooltip.c b/src/graphics/tooltip.c index d9fe37a303..2f57454cf8 100644 --- a/src/graphics/tooltip.c +++ b/src/graphics/tooltip.c @@ -238,7 +238,7 @@ static void draw_button_tooltip(tooltip_context *c) graphics_draw_rect(0, 0, width, height, COLOR_BLACK); graphics_fill_rect(1, 1, width - 2, height - 2, COLOR_WHITE); - text_draw_multiline(text, 8, 8, width - 15, FONT_SMALL_PLAIN, COLOR_TOOLTIP); + text_draw_multiline(text, 8, 8, width - 15, 0, FONT_SMALL_PLAIN, COLOR_TOOLTIP); graphics_renderer()->finish_tooltip_creation(); } @@ -286,7 +286,7 @@ static void draw_overlay_tooltip(tooltip_context *c) graphics_draw_rect(0, 0, width, height, COLOR_BLACK); graphics_fill_rect(1, 1, width - 2, height - 2, COLOR_WHITE); - text_draw_multiline(text, 8, 8, width - 15, FONT_SMALL_PLAIN, COLOR_TOOLTIP); + text_draw_multiline(text, 8, 8, width - 15, 0, FONT_SMALL_PLAIN, COLOR_TOOLTIP); graphics_renderer()->finish_tooltip_creation(); diff --git a/src/graphics/video.c b/src/graphics/video.c index d9502dbc7c..5b5fe7b228 100644 --- a/src/graphics/video.c +++ b/src/graphics/video.c @@ -8,6 +8,7 @@ #include "core/time.h" #include "game/system.h" #include "graphics/renderer.h" +#include "platform/file_manager.h" #include "sound/device.h" #include "sound/music.h" #include "sound/speech.h" @@ -87,7 +88,7 @@ static int load_mpg(const char *filename) return 0; } char mpg_filename[FILE_NAME_MAX]; - strncpy(mpg_filename, filename, FILE_NAME_MAX - 1); + snprintf(mpg_filename, FILE_NAME_MAX, "%s", filename); file_change_extension(mpg_filename, "mpg"); if (strncmp(mpg_filename, "smk/", 4) == 0 || strncmp(mpg_filename, "smk\\", 4) == 0) { mpg_filename[0] = 'm'; @@ -101,7 +102,13 @@ static int load_mpg(const char *filename) data.plm = plm_create_with_memory(video_buffer, length, 1); } if (!data.plm) { - const char *path = dir_get_file(mpg_filename, MAY_BE_LOCALIZED); + const char *path; + const char *community_location = platform_file_manager_get_directory_for_location(PATH_LOCATION_COMMUNITY, 0); + if (strncmp(community_location, mpg_filename, strlen(community_location)) == 0) { + path = filename; + } else { + path = dir_get_file(mpg_filename, MAY_BE_LOCALIZED); + } if (!path) { return 0; } diff --git a/src/graphics/window.h b/src/graphics/window.h index 71d4707b57..94ab49cdde 100644 --- a/src/graphics/window.h +++ b/src/graphics/window.h @@ -92,7 +92,8 @@ typedef enum { // New window types WINDOW_ASSET_PREVIEWER, WINDOW_CUSTOM_MESSAGE, - WINDOW_TEXT_INPUT + WINDOW_TEXT_INPUT, + WINDOW_USER_PATH_SETUP } window_id; typedef struct { diff --git a/src/input/keys.c b/src/input/keys.c index 36999886d6..b38c819ec0 100644 --- a/src/input/keys.c +++ b/src/input/keys.c @@ -4,6 +4,7 @@ #include "game/system.h" #include "graphics/font.h" +#include #include static const char *key_names[KEY_TYPE_MAX_ITEMS] = { @@ -51,13 +52,16 @@ const char *key_combination_name(key_type key, key_modifier_type modifiers) { static char name[100]; name[0] = 0; + int cursor = 0; for (const modifier_name *modname = modifier_names; modname->modifier; modname++) { if (modifiers & modname->modifier) { - strcat(name, modname->name); - strcat(name, " "); + cursor += snprintf(&name[cursor], 100 - cursor, "%s ", modname->name); + if (cursor >= 100) { + return name; + } } } - strcat(name, key_names[key]); + snprintf(&name[cursor], 100 - cursor, "%s", key_names[key]); return name; } @@ -83,8 +87,8 @@ static key_type parse_key(const char *name) int key_combination_from_name(const char *name, key_type *key, key_modifier_type *modifiers) { - char editable_name[100] = {0}; - strncpy(editable_name, name, 99); + char editable_name[100]; + snprintf(editable_name, 100, "%s", name); *key = KEY_TYPE_NONE; *modifiers = KEY_MOD_NONE; @@ -126,54 +130,52 @@ const uint8_t *key_combination_display_name(key_type key, key_modifier_type modi static uint8_t str_result[100]; result[0] = 0; + int cursor = 0; if (modifiers & KEY_MOD_CTRL) { - strcat(result, system_keyboard_key_modifier_name(KEY_MOD_CTRL)); - strcat(result, " "); + cursor = snprintf(result, 100, "%s ", system_keyboard_key_modifier_name(KEY_MOD_CTRL)); } - if (modifiers & KEY_MOD_ALT) { - strcat(result, system_keyboard_key_modifier_name(KEY_MOD_ALT)); - strcat(result, " "); + if (cursor < 100 && modifiers & KEY_MOD_ALT) { + cursor += snprintf(&result[cursor], 100 - cursor, "%s ", system_keyboard_key_modifier_name(KEY_MOD_ALT)); } - if (modifiers & KEY_MOD_GUI) { - strcat(result, system_keyboard_key_modifier_name(KEY_MOD_GUI)); - strcat(result, " "); + if (cursor < 100 && modifiers & KEY_MOD_GUI) { + cursor += snprintf(&result[cursor], 100 - cursor, "%s ", system_keyboard_key_modifier_name(KEY_MOD_GUI)); } - if (modifiers & KEY_MOD_SHIFT) { - strcat(result, system_keyboard_key_modifier_name(KEY_MOD_SHIFT)); - strcat(result, " "); + if (cursor < 100 && modifiers & KEY_MOD_SHIFT) { + cursor += snprintf(&result[cursor], 100 - cursor, "%s ", system_keyboard_key_modifier_name(KEY_MOD_SHIFT)); } - // Modifiers are easy, now for key name... - const char *key_name = system_keyboard_key_name(key); - if ((key_name[0] & 0x80) == 0) { - // Special cases where we know the key is not displayable using the internal font - switch (key_name[0]) { - case '[': key_name = "Left bracket"; break; - case ']': key_name = "Right bracket"; break; - case '\\': key_name = "Backslash"; break; - case '`': key_name = "Backtick"; break; - case '~': key_name = "Tilde"; break; - case '#': key_name = "Hash"; break; - case '$': key_name = "Dollar"; break; - case '&': key_name = "Ampersand"; break; - case '<': key_name = "Less than"; break; - case '>': key_name = "Greater than"; break; - case '@': key_name = "At-sign"; break; - case '^': key_name = "Caret"; break; - case '_': key_name = "Underscore"; break; - case '|': key_name = "Pipe"; break; - case '{': key_name = "Left curly brace"; break; - case '}': key_name = "Right curly brace"; break; - case '\0': key_name = key_display_names[key]; + if (cursor < 100) { + // Modifiers are easy, now for key name... + const char *key_name = system_keyboard_key_name(key); + if ((key_name[0] & 0x80) == 0) { + // Special cases where we know the key is not displayable using the internal font + switch (key_name[0]) { + case '[': key_name = "Left bracket"; break; + case ']': key_name = "Right bracket"; break; + case '\\': key_name = "Backslash"; break; + case '`': key_name = "Backtick"; break; + case '~': key_name = "Tilde"; break; + case '#': key_name = "Hash"; break; + case '$': key_name = "Dollar"; break; + case '&': key_name = "Ampersand"; break; + case '<': key_name = "Less than"; break; + case '>': key_name = "Greater than"; break; + case '@': key_name = "At-sign"; break; + case '^': key_name = "Caret"; break; + case '_': key_name = "Underscore"; break; + case '|': key_name = "Pipe"; break; + case '{': key_name = "Left curly brace"; break; + case '}': key_name = "Right curly brace"; break; + case '\0': key_name = key_display_names[key]; + } + snprintf(&result[cursor], 100 - cursor, "%s", key_name); + } else if (can_display(key_name)) { + snprintf(&result[cursor], 100 - cursor, "%s", key_name); + } else { + snprintf(&result[cursor], 100 - cursor, "? (%s)", key_display_names[key]); } - strcat(result, key_name); - } else if (can_display(key_name)) { - strcat(result, key_name); - } else { - strcat(result, "? ("); - strcat(result, key_display_names[key]); - strcat(result, ")"); } + encoding_from_utf8(result, str_result, 100); return str_result; } diff --git a/src/map/terrain.h b/src/map/terrain.h index e067deaef6..eae9dd7291 100644 --- a/src/map/terrain.h +++ b/src/map/terrain.h @@ -95,7 +95,7 @@ int map_terrain_count_directly_adjacent_with_type(int grid_offset, int terrain); /** * Check orthogonal neighbours of a tile if they contain a terrain. * @param grid_offset Tile which neighbours will be checked. - * @param terrain Terrain bitmask to be checked for. + * @param terrain_sum Terrain bitmask to be checked for. * @return 1 if any orthogonal tiles matches all terrains from the bitmask, 0 otherwise. */ int map_terrain_count_directly_adjacent_with_types(int grid_offset, int terrain_sum); diff --git a/src/platform/android/android.c b/src/platform/android/android.c index 963a9c9da5..db15af3021 100644 --- a/src/platform/android/android.c +++ b/src/platform/android/android.c @@ -23,7 +23,7 @@ static const char *get_c3_path(void) jobject result = (*handler.env)->CallStaticObjectMethod(handler.env, handler.class, handler.method); const char *temp_path = (*handler.env)->GetStringUTFChars(handler.env, (jstring) result, NULL); - strncpy(path, temp_path, FILE_NAME_MAX - 1); + snprintf(path, FILE_NAME_MAX, "%s", temp_path); (*handler.env)->ReleaseStringUTFChars(handler.env, (jstring) result, temp_path); (*handler.env)->DeleteLocalRef(handler.env, result); jni_destroy_function_handler(&handler); diff --git a/src/platform/android/android.h b/src/platform/android/android.h index 38acfe7a1a..2285604d51 100644 --- a/src/platform/android/android.h +++ b/src/platform/android/android.h @@ -3,6 +3,8 @@ #ifdef __ANDROID__ +#define PLATFORM_NO_USER_DIRECTORIES + const char *android_show_c3_path_dialog(int again); float android_get_screen_density(void); int android_get_file_descriptor(const char *filename, const char *mode); diff --git a/src/platform/android/asset_handler.c b/src/platform/android/asset_handler.c index adb8bcd76e..30148d2df9 100644 --- a/src/platform/android/asset_handler.c +++ b/src/platform/android/asset_handler.c @@ -74,17 +74,11 @@ static int asset_close(void *asset) void *asset_handler_open_asset(const char *asset_name, const char *mode) { - static char location[FILE_NAME_MAX]; - static int assets_dir_length; - if (!assets_dir_length) { - assets_dir_length = strlen(ASSETS_DIR_NAME) + 1; - strncpy(location, ASSETS_DIR_NAME, FILE_NAME_MAX); - location[assets_dir_length - 1] = '/'; - } + char location[FILE_NAME_MAX]; switch (assets_location) { case ASSETS_LOCATION_DIRECTORY: - strncpy(location + assets_dir_length, asset_name, FILE_NAME_MAX - assets_dir_length - 1); + snprintf(location, FILE_NAME_MAX, "%s/%s", ASSETS_DIR_NAME, asset_name); int fd = android_get_file_descriptor(location, mode); if (!fd) { return 0; diff --git a/src/platform/augustus.c b/src/platform/augustus.c index cb5d1007ff..76d15fc7e0 100644 --- a/src/platform/augustus.c +++ b/src/platform/augustus.c @@ -121,6 +121,24 @@ static void post_event(int code) SDL_PushEvent(&event); } +int system_supports_select_folder_dialog(void) +{ +#ifdef USE_TINYFILEDIALOGS + return 1; +#else + return 0; +#endif +} + +const char *system_show_select_folder_dialog(const char *title, const char *default_path) +{ +#ifdef USE_TINYFILEDIALOGS + return tinyfd_selectFolderDialog(title, default_path); +#else + return 0; +#endif +} + void system_exit(void) { post_event(USER_EVENT_QUIT); @@ -456,11 +474,10 @@ static int init_sdl(int enable_joysticks) #ifdef SHOW_FOLDER_SELECT_DIALOG static const char *ask_for_data_dir(int again) { -#ifdef __ANDROID__ if (again) { const SDL_MessageBoxButtonData buttons[] = { - {SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "OK"}, - {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, "Cancel"} + {SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "OK"}, + {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, "Cancel"} }; const SDL_MessageBoxData messageboxdata = { SDL_MESSAGEBOX_WARNING, NULL, "Wrong folder selected", @@ -476,19 +493,10 @@ static const char *ask_for_data_dir(int again) return NULL; } } +#ifdef __ANDROID__ return android_show_c3_path_dialog(again); #else - if (again) { - int result = tinyfd_messageBox("Wrong folder selected", - "Augustus requires the original files from Caesar 3 to run.\n\n" - "The selected folder is not a proper Caesar 3 folder.\n\n" - "Press OK to select another folder or Cancel to exit.", - "okcancel", "warning", 1); - if (!result) { - return NULL; - } - } - return tinyfd_selectFolderDialog("Please select your Caesar 3 folder"); + return system_show_select_folder_dialog("Please select your Caesar 3 folder", 0); #endif } #endif @@ -502,7 +510,7 @@ static int pre_init(const char *custom_data_dir) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Augustus requires the original files from Caesar 3.\n\n" - "Please insert the proper directory or copy the files to the selected directory.", + "Please enter the proper directory or copy the files to the selected directory.", NULL); return 0; } @@ -532,7 +540,7 @@ static int pre_init(const char *custom_data_dir) #ifdef SHOW_FOLDER_SELECT_DIALOG const char *user_dir = pref_data_dir(); - if (user_dir) { + if (*user_dir) { SDL_Log("Loading game from user pref %s", user_dir); if (platform_file_manager_set_base_path(user_dir) && game_pre_init()) { return 1; diff --git a/src/platform/crash_handler.c b/src/platform/crash_handler.c index 22b2b06b9a..2312b468fa 100644 --- a/src/platform/crash_handler.c +++ b/src/platform/crash_handler.c @@ -251,7 +251,7 @@ static void print_stacktrace(LPEXCEPTION_POINTERS e) if (mod_base) { GetModuleFileName((HINSTANCE) mod_base, modname, MAX_PATH); } else { - strcpy(modname, "Unknown"); + snprintf(modname, MAX_PATH, "Unknown"); } log_info_sprintf("(%d) %s [0x%p]\n", frame, modname, (void *) stackframe.AddrPC.Offset); } diff --git a/src/platform/emscripten/emscripten.h b/src/platform/emscripten/emscripten.h index e80807dc08..62b91a4db7 100644 --- a/src/platform/emscripten/emscripten.h +++ b/src/platform/emscripten/emscripten.h @@ -5,5 +5,7 @@ #include +#define PLATFORM_NO_USER_DIRECTORIES + #endif // __EMSCRIPTEN__ #endif // PLATFORM_EMSCRIPTEN_H diff --git a/src/platform/file_manager.c b/src/platform/file_manager.c index 155914c576..67af9739f4 100644 --- a/src/platform/file_manager.c +++ b/src/platform/file_manager.c @@ -1,13 +1,16 @@ #include "file_manager.h" #include "assets/assets.h" +#include "core/config.h" #include "core/file.h" #include "core/log.h" +#include "core/random.h" #include "core/string.h" #include "platform/android/android.h" #include "platform/emscripten/emscripten.h" #include "platform/file_manager_cache.h" #include "platform/platform.h" +#include "platform/prefs.h" #include "platform/vita/vita.h" #ifndef BUILDING_ASSET_PACKER @@ -30,6 +33,7 @@ #ifdef _WIN32 #include +#include #define fs_dir_type _WDIR #define fs_dir_entry struct _wdirent @@ -66,6 +70,17 @@ static wchar_t *utf8_to_wchar(const char *str) return result; } +static void copy_file_times(FILE *src, FILE *dst) +{ + stat_info file_info; + if (_fstat(_fileno(src), &file_info) == -1) { + return; + } + struct _utimbuf ut; + ut.actime = file_info.st_atime; + ut.modtime = file_info.st_mtime; + _futime(_fileno(dst), &ut); +} #else // not _WIN32 #include #include @@ -83,6 +98,33 @@ static wchar_t *utf8_to_wchar(const char *str) #define fs_remove remove typedef struct stat stat_info; typedef char file_name; + +#ifdef __SWITCH__ +static void copy_file_times(const char *src, const char *dst) +{ + stat_info file_info; + if (stat(src, &file_info) == -1) { + return; + } + struct timeval times[2] = { 0 }; + times[0].tv_sec = file_info.st_atime; + times[1].tv_sec = file_info.st_mtime; + utimes(dst, times); +} +#else +static void copy_file_times(FILE *src, FILE *dst) +{ + stat_info file_info; + if (fstat(fileno(src), &file_info) == -1) { + return; + } + struct timespec times[2] = { 0 }; + times[0].tv_sec = file_info.st_atime; + times[1].tv_sec = file_info.st_mtime; + futimens(fileno(dst), times); +} +#endif + #endif #ifndef S_ISLNK @@ -121,7 +163,7 @@ static int is_file(int mode) #endif #ifdef __ANDROID__ -static const char *assets_directory = ASSETS_DIRECTORY; +static const char *const assets_directory = ASSETS_DIRECTORY; #else #define MAX_ASSET_DIRS 10 @@ -167,7 +209,7 @@ static int write_base_path_to(char *dest) if (!base_path) { return 0; } - strncpy(dest, base_path, FILE_NAME_MAX - 1); + snprintf(dest, FILE_NAME_MAX, "%s", base_path); SDL_free(base_path); return 1; #else @@ -179,8 +221,35 @@ static int write_base_path_to(char *dest) static struct { char current_src_path[FILE_NAME_MAX]; char current_dst_path[FILE_NAME_MAX]; + int overwrite_files; } directory_copy_data; +static struct { + const char *root; + const char *configs; + const char *assets; + const char *savegames; + const char *scenarios; + const char *campaigns; + const char *screenshots; + const char *community; + const char *editor_custom_empires; + const char *editor_custom_messages; + const char *editor_custom_events; +} paths = { + "", + "config/", + assets_directory, + "savegames/", + "scenarios/", + "campaigns/", + "screenshots/", + "community/", + "editor/empires/", + "editor/messages/", + "editor/events/" +}; + static void set_assets_directory(void) { #ifndef __ANDROID__ @@ -195,9 +264,7 @@ static void set_assets_directory(void) if (!home_dir) { continue; } - size_t home_dir_length = strlen(home_dir); - strncpy(assets_directory, home_dir, FILE_NAME_MAX); - strncpy(assets_directory + home_dir_length, &ASSET_DIRS[i][1], FILE_NAME_MAX - home_dir_length); + snprintf(assets_directory, FILE_NAME_MAX, "%s%s", home_dir, &ASSET_DIRS[i][1]); // Special case - SDL base path } else if (strcmp(ASSET_DIRS[i], "***SDL_BASE_PATH***") == 0) { if (!write_base_path_to(assets_directory)) { @@ -216,14 +283,14 @@ static void set_assets_directory(void) if (!parent) { continue; } - strncpy(parent, "/share/augustus-game", FILE_NAME_MAX - (parent - assets_directory) - 1); + snprintf(parent, FILE_NAME_MAX - (parent - assets_directory), "/share/augustus-game"); #endif } else if (strcmp(ASSET_DIRS[i], "***EXEC_PATH***") == 0) { #if defined(_WIN32) || defined(__vita__) || defined(__SWITCH__) || defined(__APPLE__) log_error("***EXEC_PATH*** is not available on your platform.", 0, 0); continue; #else - char arg0_dir[FILE_NAME_MAX] = { 0 }; + char arg0_dir[FILE_NAME_MAX]; if (readlink("/proc/self/exe" /* Linux */, arg0_dir, FILE_NAME_MAX) == -1) { if (readlink("/proc/curproc/file" /* FreeBSD */, arg0_dir, FILE_NAME_MAX) == -1) { if (readlink("/proc/self/path/a.out" /* Solaris */, arg0_dir, FILE_NAME_MAX) == -1) { @@ -232,7 +299,7 @@ static void set_assets_directory(void) } } dirname(arg0_dir); - strncpy(assets_directory, arg0_dir, FILE_NAME_MAX); + snprintf(assets_directory, FILE_NAME_MAX, "%s", arg0_dir); #endif } else if (strcmp(ASSET_DIRS[i], "***RELATIVE_EXEC_PATH***") == 0) { #if defined(_WIN32) || defined(__vita__) || defined(__SWITCH__) || defined(__APPLE__) @@ -248,24 +315,20 @@ static void set_assets_directory(void) } } dirname(arg0_dir); - size_t arg0_dir_length = strlen(arg0_dir); - strncpy(assets_directory, arg0_dir, FILE_NAME_MAX); - strncpy(assets_directory + arg0_dir_length, "/../share/augustus-game", - FILE_NAME_MAX - arg0_dir_length); + if (snprintf(assets_directory, FILE_NAME_MAX, "%s/../share/augustus-game", arg0_dir) > FILE_NAME_MAX) { + log_error("Path too long", arg0_dir, 0); + continue; + } #endif } else { - strncpy(assets_directory, ASSET_DIRS[i], FILE_NAME_MAX - 1); + snprintf(assets_directory, FILE_NAME_MAX, "%s", ASSET_DIRS[i]); } size_t offset = strlen(assets_directory); - assets_directory[offset++] = '/'; + offset += snprintf(&assets_directory[offset], FILE_NAME_MAX - offset, "/"); // Special case for romfs on switch -#ifdef __SWITCH__ if (strcmp(assets_directory, "romfs:/") != 0) { -#endif - strncpy(&assets_directory[offset], ASSETS_DIR_NAME, FILE_NAME_MAX - offset); -#ifdef __SWITCH__ + snprintf(&assets_directory[offset], FILE_NAME_MAX - offset, "%s", ASSETS_DIR_NAME); } -#endif log_info("Trying asset path at", assets_directory, 0); const file_name *result = set_file_name(assets_directory); fs_dir_type *dir = fs_dir_open(result); @@ -277,7 +340,7 @@ static void set_assets_directory(void) } free_file_name(result); } - strncpy(assets_directory, ".", FILE_NAME_MAX - 1); + snprintf(assets_directory, FILE_NAME_MAX, "."); #endif } @@ -300,7 +363,8 @@ int platform_file_manager_list_directory_contents( } else { char full_asset_path[FILE_NAME_MAX]; // Prevent double slashes as they may not work - if (*assets_directory && assets_directory[strlen(assets_directory) - 1] == '/' && dir[assets_directory_length] == '/') { + if (*assets_directory && assets_directory[strlen(assets_directory) - 1] == '/' && + dir[assets_directory_length] == '/') { assets_directory_length++; } snprintf(full_asset_path, FILE_NAME_MAX, "%s%s", assets_directory, dir + assets_directory_length); @@ -452,6 +516,101 @@ int platform_file_manager_set_base_path(const char *path) #endif } +const char *platform_file_manager_get_directory_for_location(int location, const char *user_directory) +{ + static char full_path[FILE_NAME_MAX]; + if (!user_directory) { + user_directory = pref_user_dir(); + } + int cursor = 0; + char slash[2] = { 0 }; + size_t user_directory_length = strlen(user_directory); + if (user_directory_length && + user_directory[user_directory_length - 1] != '/' && user_directory[user_directory_length - 1] != '\\') { + slash[0] = '/'; + } + + switch (location) { + default: + full_path[0] = 0; + break; + case PATH_LOCATION_CONFIG: + if (*user_directory) { + cursor = snprintf(full_path, FILE_NAME_MAX, "%s%s%s", user_directory, slash, paths.configs); + } else { + full_path[0] = 0; + } + break; + case PATH_LOCATION_ASSET: + set_assets_directory(); + cursor = snprintf(full_path, FILE_NAME_MAX, "%s", paths.assets); + break; + case PATH_LOCATION_SAVEGAME: + if (*user_directory) { + cursor = snprintf(full_path, FILE_NAME_MAX, "%s%s%s", user_directory, slash, paths.savegames); + } else { + full_path[0] = 0; + } + break; + case PATH_LOCATION_SCENARIO: + if (*user_directory) { + cursor = snprintf(full_path, FILE_NAME_MAX, "%s%s%s", user_directory, slash, paths.scenarios); + } else { + full_path[0] = 0; + } + break; + case PATH_LOCATION_CAMPAIGN: + cursor = snprintf(full_path, FILE_NAME_MAX, "%s%s%s", user_directory, slash, paths.campaigns); + break; + case PATH_LOCATION_SCREENSHOT: + if (*user_directory) { + cursor = snprintf(full_path, FILE_NAME_MAX, "%s%s%s", user_directory, slash, paths.screenshots); + } else { + full_path[0] = 0; + } + break; + case PATH_LOCATION_COMMUNITY: + cursor = snprintf(full_path, FILE_NAME_MAX, "%s%s%s", user_directory, slash, paths.community); + break; + case PATH_LOCATION_EDITOR_CUSTOM_EMPIRES: + cursor = snprintf(full_path, FILE_NAME_MAX, "%s%s%s", user_directory, slash, paths.editor_custom_empires); + break; + case PATH_LOCATION_EDITOR_CUSTOM_EVENTS: + cursor = snprintf(full_path, FILE_NAME_MAX, "%s%s%s", user_directory, slash, paths.editor_custom_events); + break; + case PATH_LOCATION_EDITOR_CUSTOM_MESSAGES: + cursor = snprintf(full_path, FILE_NAME_MAX, "%s%s%s", user_directory, slash, paths.editor_custom_messages); + break; + } + + if (cursor >= FILE_NAME_MAX) { + log_error("Path ID too long for location: ", 0, location); + } + return full_path; +} + +int platform_file_manager_is_directory_writeable(const char *directory) +{ + char file_name[FILE_NAME_MAX]; + if (!directory || !*directory) { + directory = "."; + } + int attempt = 0; + do { + snprintf(file_name, FILE_NAME_MAX, "%s/test_%d.txt", directory, random_from_stdlib()); + attempt++; + } while (file_exists(file_name, NOT_LOCALIZED) && attempt < 5); + FILE *fp = file_open(file_name, "w"); + if (!fp) { + return 0; + } + fclose(fp); + if (!file_remove(file_name)) { + return 0; + } + return 1; +} + #if defined(__ANDROID__) FILE *platform_file_manager_open_file(const char *filename, const char *mode) @@ -518,9 +677,8 @@ int platform_file_manager_remove_file(const char *filename) FILE *platform_file_manager_open_asset(const char *asset, const char *mode) { - set_assets_directory(); - const char *cased_asset_path = dir_get_asset(assets_directory, asset); - return platform_file_manager_open_file(cased_asset_path, mode); + const char *cased_asset_path = dir_get_file_at_location(asset, PATH_LOCATION_ASSET); + return cased_asset_path ? platform_file_manager_open_file(cased_asset_path, mode) : 0; } #endif @@ -538,16 +696,37 @@ int platform_file_manager_close_file(FILE *stream) return result == 0; } -int platform_file_manager_create_directory(const char *name, int overwrite) +int platform_file_manager_create_directory(const char *name, const char *location, int overwrite) { - char tokenized_name[FILE_NAME_MAX] = { 0 }; + char tokenized_name[FILE_NAME_MAX]; char temporary_path[FILE_NAME_MAX] = { 0 }; - strncpy(tokenized_name, name, FILE_NAME_MAX - 1); - char *token = strtok(tokenized_name, "/\\"); int overwrite_last = 0; + int cursor = 0; + if (location) { + cursor = snprintf(temporary_path, FILE_NAME_MAX, "%s", location); + if (cursor > FILE_NAME_MAX) { + log_error("Path too long", name, 0); + return 0; + } + size_t location_length = strlen(location); + if (strncmp(name, location, location_length) == 0) { + name += location_length; + } + } + if (*name == '/' || *name == '\\') { + cursor += snprintf(&temporary_path[cursor], FILE_NAME_MAX - cursor, "/"); + name++; + } + snprintf(tokenized_name, FILE_NAME_MAX, "%s", name); + char *token = strtok(tokenized_name, "/\\"); + while (token) { overwrite_last = 0; - strncat(temporary_path, token, FILE_NAME_MAX - 1); + cursor += snprintf(&temporary_path[cursor], FILE_NAME_MAX - cursor, "%s", token); + if (cursor > FILE_NAME_MAX) { + log_error("Path too long", name, 0); + return 0; + } #ifdef _WIN32 wchar_t *wpath = utf8_to_wchar(temporary_path); if (CreateDirectoryW(wpath, 0) == 0) { @@ -577,12 +756,17 @@ int platform_file_manager_create_directory(const char *name, int overwrite) } } #endif - strncat(temporary_path, "/", FILE_NAME_MAX - 1); + cursor += snprintf(&temporary_path[cursor], FILE_NAME_MAX - cursor, "/"); + if (cursor > FILE_NAME_MAX) { + log_error("Path too long", name, 0); + return 0; + } token = strtok(0, "/\\"); } return !overwrite_last; } + int platform_file_manager_copy_file(const char *src, const char *dst) { FILE *in = platform_file_manager_open_file(src, "rb"); @@ -598,13 +782,26 @@ int platform_file_manager_copy_file(const char *src, const char *dst) char buf[1024]; size_t read = 0; + while ((read = fread(buf, 1, 1024, in)) == 1024) { fwrite(buf, 1, 1024, out); } fwrite(buf, 1, read, out); - file_close(out); + out = platform_file_manager_open_file(dst, "rb"); + if (!out) { + fclose(in); + return 1; + } +#ifndef __SWITCH__ + copy_file_times(in, out); +#endif file_close(in); + file_close(out); + +#ifdef __SWITCH__ + copy_file_times(src, dst); +#endif return 1; } @@ -634,6 +831,13 @@ static void move_up_path(void) static int copy_file(const char *name, long unused) { append_name_to_path(name); + if (!directory_copy_data.overwrite_files) { + FILE *file = platform_file_manager_open_file(directory_copy_data.current_dst_path, "rb"); + if (file) { + file_close(file); + return LIST_CONTINUE; + } + } int result = platform_file_manager_copy_file(directory_copy_data.current_src_path, directory_copy_data.current_dst_path) != 0; @@ -644,13 +848,10 @@ static int copy_file(const char *name, long unused) static int copy_directory(const char *name, long unused) { -#ifdef __ANDROID__ - return LIST_ERROR; -#else if (name) { append_name_to_path(name); } - if (!platform_file_manager_create_directory(directory_copy_data.current_dst_path, 0)) { + if (!platform_file_manager_create_directory(directory_copy_data.current_dst_path, 0, 0)) { if (name) { move_up_path(); return LIST_CONTINUE; @@ -666,7 +867,6 @@ static int copy_directory(const char *name, long unused) move_up_path(); return result; -#endif } static void copy_directory_name(const char *name, char *dst) @@ -674,12 +874,12 @@ static void copy_directory_name(const char *name, char *dst) if (strncmp(name, ASSETS_DIRECTORY, strlen(ASSETS_DIRECTORY)) == 0) { set_assets_directory(); if (strlen(name) == strlen(ASSETS_DIRECTORY)) { - strncpy(dst, assets_directory, FILE_NAME_MAX); + snprintf(dst, FILE_NAME_MAX, "%s", assets_directory); } else { snprintf(dst, FILE_NAME_MAX, "%s%s", assets_directory, name + strlen(assets_directory)); } } else { - strncpy(dst, name, FILE_NAME_MAX); + snprintf(dst, FILE_NAME_MAX, "%s", name); } char *cursor = dst; @@ -694,10 +894,19 @@ static void copy_directory_name(const char *name, char *dst) } } -int platform_file_manager_copy_directory(const char *src, const char *dst) +static int do_nothing(const char *name, long unused) { + return LIST_MATCH; +} + +int platform_file_manager_copy_directory(const char *src, const char *dst, int overwrite_files) +{ + if (!platform_file_manager_list_directory_contents(src, TYPE_DIR, 0, do_nothing)) { + return 0; + } copy_directory_name(src, directory_copy_data.current_src_path); copy_directory_name(dst, directory_copy_data.current_dst_path); + directory_copy_data.overwrite_files = overwrite_files; return copy_directory(0, 0); } diff --git a/src/platform/file_manager.h b/src/platform/file_manager.h index a53df1ed62..ef2dce5cea 100644 --- a/src/platform/file_manager.h +++ b/src/platform/file_manager.h @@ -24,6 +24,23 @@ enum { */ int platform_file_manager_set_base_path(const char *path); +/** + * Gets a directory location for the specified type + * @param location The location to get + * @param user_directory The user directory to use, or 0 to use the one from the preferences + * @return The path for the provided location, or an empty string if the location is the base path. + * If there is an actual path, it is guaranteeed to end with "/". + * The return value is a pointer to a static buffer, so it should be copied if needed. + */ +const char *platform_file_manager_get_directory_for_location(int location, const char *user_directory); + +/** + * Checks if a directory is writeable + * @param directory The directory to check + * @return 1 if the directory is writeable, 0 otherwise + */ +int platform_file_manager_is_directory_writeable(const char *directory); + /** * Gets the contents of a directory by the specified extension * @param dir The directory to search on, or null if base directory @@ -76,7 +93,7 @@ FILE *platform_file_manager_open_file(const char *filename, const char *mode); /** * Opens an asset file - * @param filename The asset file to open + * @param asset The asset file to open * @param mode The mode to open the asset file - refer to fopen() * @return A pointer to a FILE structure on success, NULL otherwise */ @@ -100,11 +117,13 @@ int platform_file_manager_remove_file(const char *filename); /** * Creates a directory - * @param path The full path to the new directory + * @param name The full path to the new directory + * @param location The base location to create the directory. The game won't attempt to create the directories in location. + * If location and name are similar, the game will create the directory in the location. Can be 0. * @param overwrite Whether to return error if overwriting the directory * @return 1 if creation was successful, 0 otherwise */ -int platform_file_manager_create_directory(const char *name, int overwrite); +int platform_file_manager_create_directory(const char *name, const char *location, int overwrite); /** * Copies a file @@ -118,9 +137,10 @@ int platform_file_manager_copy_file(const char *src, const char *dst); * Copies a directory recursively * @param src The source directory * @param dst The destination directory + * @param overwrite_files Whether to overwrite existing files * @return 1 if copying was successful, 0 otherwise */ -int platform_file_manager_copy_directory(const char *src, const char *dst); +int platform_file_manager_copy_directory(const char *src, const char *dst, int overwrite_files); /** * Removes a directory recursively - use with care!!! diff --git a/src/platform/file_manager_cache.c b/src/platform/file_manager_cache.c index 1f932d2dd5..d9bc8c79b7 100644 --- a/src/platform/file_manager_cache.c +++ b/src/platform/file_manager_cache.c @@ -45,13 +45,17 @@ const dir_info *platform_file_manager_cache_get_dir_info(const char *dir) info->next = malloc(sizeof(dir_info)); info = info->next; } - strncpy(info->name, dir, FILE_NAME_MAX - 1); - info->name[FILE_NAME_MAX - 1] = 0; + snprintf(info->name, FILE_NAME_MAX, "%s", dir); info->first_file = 0; info->next = 0; struct dirent *entry; file_info *file_item = 0; - int dir_name_offset = 0; + char full_name[FILE_NAME_MAX]; + size_t dir_name_offset = 0; + if (*info->name) { + dir_name_offset = snprintf(full_name, FILE_NAME_MAX, "%s/", info->name); + } + while ((entry = readdir(d))) { const char *name = entry->d_name; if (name[0] == '.') { @@ -68,27 +72,30 @@ const dir_info *platform_file_manager_cache_get_dir_info(const char *dir) file_item->next = 0; // Copy name - strncpy(file_item->name, name, FILE_NAME_MAX - 1); - file_item->name[FILE_NAME_MAX - 1] = 0; + snprintf(file_item->name, FILE_NAME_MAX, "%s", name); + snprintf(&full_name[dir_name_offset], FILE_NAME_MAX - dir_name_offset, "%s", name); // Copy extension - char c; - const char *extension = file_item->name; - do { - c = *extension; - extension++; - } while (c != '.' && c); - file_item->extension = extension; + file_item->extension = strrchr(file_item->name, '.'); + if (!file_item->extension) { + file_item->extension = file_item->name + strlen(file_item->name); + } else { + file_item->extension++; + } // Check type int type = TYPE_FILE; struct stat current_file_info; + int has_stat = 0; + if (stat_status == STAT_UNTESTED) { - stat_status = stat(file_item->name, ¤t_file_info) == STAT_DOESNT_WORK ? STAT_DOESNT_WORK : STAT_WORKS; + stat_status = stat(full_name, ¤t_file_info) == 0 ? STAT_WORKS : STAT_DOESNT_WORK; + has_stat = stat_status == STAT_WORKS; + } else if (stat_status == STAT_WORKS) { + has_stat = stat(full_name, ¤t_file_info) == 0; } - if (stat_status == STAT_WORKS) { - stat(file_item->name, ¤t_file_info); + if (has_stat) { if (S_ISDIR(current_file_info.st_mode)) { type = TYPE_DIR; } @@ -98,16 +105,6 @@ const dir_info *platform_file_manager_cache_get_dir_info(const char *dir) // For performance reasons, we only check for a directory if the name has no extension // This is effectively a hack, and definitely not full-proof, but the performance gains are well worth it if (!*file_item->extension) { - static char full_name[FILE_NAME_MAX]; - if (!dir_name_offset) { - strncpy(full_name, info->name, FILE_NAME_MAX); - dir_name_offset = strlen(info->name); - if(full_name[dir_name_offset - 1] != '/') { - full_name[dir_name_offset++] = '/'; - full_name[dir_name_offset] = 0; - } - } - strncpy(full_name + dir_name_offset, name, FILE_NAME_MAX - 1 - dir_name_offset); DIR *file_d = opendir(full_name); if (file_d) { type = TYPE_DIR; @@ -136,8 +133,7 @@ void platform_file_manager_cache_update_file_info(const char *filename) } if (!current_file) { current_file = malloc(sizeof(file_info)); - strncpy(current_file->name, filename, FILE_NAME_MAX - 1); - current_file->name[FILE_NAME_MAX - 1] = 0; + snprintf(current_file->name, FILE_NAME_MAX, "%s", filename); current_file->type = TYPE_FILE; char c; const char *name = current_file->name; diff --git a/src/platform/joystick.c b/src/platform/joystick.c index 220b6fa72f..a92a56de68 100644 --- a/src/platform/joystick.c +++ b/src/platform/joystick.c @@ -216,11 +216,11 @@ static void create_new_model(const char *guid, const char *name, int instance_id { joystick_model model; memset(&model, 0, sizeof(model)); - strncpy(model.guid, guid, JOYSTICK_MAX_GUID); + snprintf(model.guid, JOYSTICK_MAX_GUID, "%s", guid); if (!name) { snprintf(model.name, JOYSTICK_MAX_NAME, "Joystick %d", instance_id); } else { - strncpy(model.name, name, JOYSTICK_MAX_NAME - 1); + snprintf(model.name, JOYSTICK_MAX_NAME, "Joystick %s", name); } if (controller) { set_default_controller_mapping(&model, controller); diff --git a/src/platform/log.c b/src/platform/log.c index 3d90f2a81b..c7e7300318 100644 --- a/src/platform/log.c +++ b/src/platform/log.c @@ -38,7 +38,7 @@ static int count_archived_message(void) if (old_message_index == MAX_OLD_MESSAGES) { log_repeated_messages(); } - strncpy(previous_log_messages[old_message_index++].buffer, log_buffer, MSG_SIZE); + snprintf(previous_log_messages[old_message_index++].buffer, MSG_SIZE, "%s", log_buffer); if (old_message_index < MAX_OLD_MESSAGES) { previous_log_messages[old_message_index].count = 0; } diff --git a/src/platform/platform.c b/src/platform/platform.c index 6f812f9664..c8c51b231c 100644 --- a/src/platform/platform.c +++ b/src/platform/platform.c @@ -136,6 +136,16 @@ int platform_sdl_version_at_least(int major, int minor, int patch) return SDL_VERSIONNUM(version.major, version.minor, version.patch) >= SDL_VERSIONNUM(major, minor, patch); } +char *platform_get_pref_path(void) +{ +#if SDL_VERSION_ATLEAST(2, 0, 1) + if (platform_sdl_version_at_least(2, 0, 1)) { + return SDL_GetPrefPath("augustus", "augustus"); + } +#endif + return 0; +} + void exit_with_status(int status) { #ifdef __EMSCRIPTEN__ diff --git a/src/platform/platform.h b/src/platform/platform.h index b44441cac7..575894bfb4 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -2,6 +2,7 @@ #define PLATFORM_PLATFORM_H int platform_sdl_version_at_least(int major, int minor, int patch); +char *platform_get_pref_path(void); void exit_with_status(int status); #endif // PLATFORM_PLATFORM_H diff --git a/src/platform/prefs.c b/src/platform/prefs.c index 2416cd86b0..0f897d5984 100644 --- a/src/platform/prefs.c +++ b/src/platform/prefs.c @@ -1,6 +1,7 @@ #include "platform/prefs.h" #include "core/log.h" +#include "core/file.h" #include "platform/platform.h" #include "SDL.h" @@ -9,53 +10,85 @@ #include #include +typedef struct { + const char *filename; + int retrieved; + char location[FILE_NAME_MAX]; +} directory; + +static struct { + directory data; + directory user; + int location_printed; +} prefs = { + { .filename = "data_dir.txt" }, + { .filename = "user_dir.txt" } +}; + static FILE *open_pref_file(const char *filename, const char *mode) { - #if SDL_VERSION_ATLEAST(2, 0, 1) - if (platform_sdl_version_at_least(2, 0, 1)) { - char *pref_dir = SDL_GetPrefPath("augustus", "augustus"); - log_info("Location:",pref_dir,0); - if (!pref_dir) { - return NULL; - } - size_t dir_len = strlen(pref_dir); - char *pref_file = malloc((strlen(filename) + dir_len + 2) * sizeof(char)); - if (!pref_file) { - SDL_free(pref_dir); - return NULL; - } - strcpy(pref_file, pref_dir); - strcpy(&pref_file[dir_len], filename); + char *pref_dir = platform_get_pref_path(); + if (!prefs.location_printed) { + log_info("Pref dir location:", pref_dir ? pref_dir : ".", 0); + prefs.location_printed = 1; + } + size_t file_len = strlen(filename) + strlen(pref_dir) + 1; + char *pref_file = malloc(file_len * sizeof(char)); + if (!pref_file) { SDL_free(pref_dir); - - FILE *fp = fopen(pref_file, mode); - free(pref_file); - return fp; + return NULL; } - #endif - return NULL; + snprintf(pref_file, file_len, "%s%s", pref_dir ? pref_dir : "", filename); + SDL_free(pref_dir); + FILE *fp = fopen(pref_file, mode); + free(pref_file); + return fp; } -const char *pref_data_dir(void) +const char *retrieve_directory(directory *dir) { - static char data_dir[1000]; - FILE *fp = open_pref_file("data_dir.txt", "r"); + if (dir->retrieved) { + return dir->location; + } + FILE *fp = open_pref_file(dir->filename, "r"); if (fp) { - size_t length = fread(data_dir, 1, 1000, fp); + size_t length = fread(dir->location, 1, FILE_NAME_MAX - 1, fp); fclose(fp); if (length > 0) { - data_dir[length] = 0; - return data_dir; + dir->location[length] = 0; } } - return NULL; + dir->retrieved = 1; + return dir->location; } -void pref_save_data_dir(const char *data_dir) +void save_directory(directory *dir, const char *location) { - FILE *fp = open_pref_file("data_dir.txt", "w"); + snprintf(dir->location, FILE_NAME_MAX, "%s", location); + FILE *fp = open_pref_file(dir->filename, "w"); if (fp) { - fwrite(data_dir, 1, strlen(data_dir), fp); + fwrite(location, 1, strlen(location), fp); fclose(fp); } + dir->retrieved = 1; +} + +const char *pref_data_dir(void) +{ + return retrieve_directory(&prefs.data); +} + +void pref_save_data_dir(const char *data_dir) +{ + save_directory(&prefs.data, data_dir); +} + +const char *pref_user_dir(void) +{ + return retrieve_directory(&prefs.user); +} + +void pref_save_user_dir(const char *user_dir) +{ + save_directory(&prefs.user, user_dir); } diff --git a/src/platform/prefs.h b/src/platform/prefs.h index cb13ee70d7..adf2f99e07 100644 --- a/src/platform/prefs.h +++ b/src/platform/prefs.h @@ -5,4 +5,8 @@ const char *pref_data_dir(void); void pref_save_data_dir(const char *data_dir); +const char *pref_user_dir(void); + +void pref_save_user_dir(const char *user_dir); + #endif // PLATFORM_PREFS_H diff --git a/src/platform/sound_device.c b/src/platform/sound_device.c index 4869cb4839..d99542d812 100644 --- a/src/platform/sound_device.c +++ b/src/platform/sound_device.c @@ -203,7 +203,7 @@ static void load_music_for_vita(const char *filename) free(vita_music_data.buffer); vita_music_data.buffer = 0; } - strncpy(vita_music_data.filename, filename, FILE_NAME_MAX - 1); + snprintf(vita_music_data.filename, FILE_NAME_MAX, "%s", filename); FILE *fp = file_open(filename, "rb"); if (!fp) { return; diff --git a/src/platform/switch/switch.h b/src/platform/switch/switch.h index e4b6a4e2eb..74848b382f 100644 --- a/src/platform/switch/switch.h +++ b/src/platform/switch/switch.h @@ -22,5 +22,7 @@ void platform_hide_virtual_keyboard(void); #define PLATFORM_USE_SOFTWARE_CURSOR +#define PLATFORM_NO_USER_DIRECTORIES + #endif // __SWITCH__ #endif // PLATFORM_SWITCH_H diff --git a/src/platform/user_path.c b/src/platform/user_path.c new file mode 100644 index 0000000000..70d0cb00f6 --- /dev/null +++ b/src/platform/user_path.c @@ -0,0 +1,151 @@ +#include "user_path.h" + +#include "core/file.h" +#include "platform/file_manager.h" +#include "platform/platform.h" +#include "platform/prefs.h" + +#include +#include + +#if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !defined(__SWITCH__) +static int is_container(void) +{ + return getenv("container") || getenv("APPIMAGE") || getenv("SNAP"); +} +#endif + +const char *platform_user_path_recommend(void) +{ +#if defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(__SWITCH__) + return 0; +#else + if (is_container()) { + return 0; + } + + static const char *user_path; + if (!user_path) { + user_path = platform_get_pref_path(); + } + return user_path; +#endif +} + +void platform_user_path_create_subdirectories(void) +{ + for (int i = 0; i < PATH_LOCATION_MAX; i++) { + if (i == PATH_LOCATION_ROOT || i == PATH_LOCATION_ASSET) { + continue; + } + const char *new_directory = platform_file_manager_get_directory_for_location(i, 0); + if (*new_directory) { + platform_file_manager_create_directory(new_directory, pref_user_dir(), 0); + } + } +} + +static int is_same_directory(const char *original_directory, const char *new_directory) +{ + if (strncmp(original_directory, "./", 2) == 0) { + original_directory += 2; + } + if (strncmp(new_directory, "./", 2) == 0) { + new_directory += 2; + } + return strcmp(new_directory, original_directory) == 0; +} + +void platform_user_path_copy_files(const char *original_user_path, int overwrite) +{ + for (int location = 0; location < PATH_LOCATION_MAX; location++) { + if (location == PATH_LOCATION_ROOT || location == PATH_LOCATION_ASSET) { + continue; + } + char original_directory[FILE_NAME_MAX]; + char new_directory[FILE_NAME_MAX]; + snprintf(original_directory, FILE_NAME_MAX, "%s", + platform_file_manager_get_directory_for_location(location, original_user_path)); + snprintf(new_directory, FILE_NAME_MAX, "%s", + platform_file_manager_get_directory_for_location(location, 0)); + if (is_same_directory(original_directory, new_directory)) { + continue; + } + const dir_listing *listing = 0; + int has_subdirectories = 0; + switch (location) { + case PATH_LOCATION_CONFIG: + listing = dir_find_files_with_extension(original_directory, "inf"); + listing = dir_append_files_with_extension("ini"); + break; + case PATH_LOCATION_SAVEGAME: + listing = dir_find_files_with_extension(original_directory, "sav"); + listing = dir_append_files_with_extension("svx"); + break; + case PATH_LOCATION_SCENARIO: + listing = dir_find_files_with_extension(original_directory, "map"); + listing = dir_append_files_with_extension("mapx"); + break; + case PATH_LOCATION_CAMPAIGN: + listing = dir_find_files_with_extension(original_directory, "campaign"); + has_subdirectories = 1; + break; + case PATH_LOCATION_SCREENSHOT: + listing = dir_find_files_with_extension(original_directory, "png"); + listing = dir_append_files_with_extension("bmp"); + break; + case PATH_LOCATION_COMMUNITY: + has_subdirectories = 1; + break; + case PATH_LOCATION_EDITOR_CUSTOM_EMPIRES: + case PATH_LOCATION_EDITOR_CUSTOM_MESSAGES: + case PATH_LOCATION_EDITOR_CUSTOM_EVENTS: + listing = dir_find_files_with_extension(original_directory, "xml"); + break; + default: + continue; + } + if (listing) { + char original_name[FILE_NAME_MAX]; + char new_name[FILE_NAME_MAX]; + for (int i = 0; i < listing->num_files; i++) { + snprintf(original_name, FILE_NAME_MAX, "%s%s", original_directory, listing->files[i].name); + snprintf(new_name, FILE_NAME_MAX, "%s%s", new_directory, listing->files[i].name); + if (overwrite || !dir_get_file_at_location(listing->files[i].name, location)) { + platform_file_manager_copy_file(original_name, new_name); + } + } + } + if (has_subdirectories) { + listing = dir_find_all_subdirectories(original_directory); + char original_name[FILE_NAME_MAX]; + char new_name[FILE_NAME_MAX]; + for (int i = 0; i < listing->num_files; i++) { + snprintf(original_name, FILE_NAME_MAX, "%s%s", original_directory, listing->files[i].name); + snprintf(new_name, FILE_NAME_MAX, "%s%s", new_directory, listing->files[i].name); + platform_file_manager_copy_directory(original_name, new_name, overwrite); + } + } + } +} + +void platform_user_path_copy_campaigns_and_custom_empires(void) +{ + if (*pref_user_dir()) { + return; + } + const dir_listing *listing = dir_find_files_with_extension(0, "campaign"); + if (listing->num_files > 0) { + char new_name[FILE_NAME_MAX]; + const char *campaign_directory = platform_file_manager_get_directory_for_location(PATH_LOCATION_CAMPAIGN, 0); + platform_file_manager_create_directory(campaign_directory, pref_user_dir(), 0); + for (int i = 0; i < listing->num_files; i++) { + snprintf(new_name, FILE_NAME_MAX, "%s%s", campaign_directory, listing->files[i].name); + if (!dir_get_file_at_location(listing->files[i].name, PATH_LOCATION_CAMPAIGN)) { + platform_file_manager_copy_file(listing->files[i].name, new_name); + } + } + } + platform_file_manager_copy_directory("custom_empires", + platform_file_manager_get_directory_for_location(PATH_LOCATION_EDITOR_CUSTOM_EMPIRES, 0), 0); +} diff --git a/src/platform/user_path.h b/src/platform/user_path.h new file mode 100644 index 0000000000..1ae8a00ead --- /dev/null +++ b/src/platform/user_path.h @@ -0,0 +1,31 @@ +#ifndef PLATFORM_USER_PATH_H +#define PLATFORM_USER_PATH_H + +/** + * Recommends a user path + * Only works on Windows right now + * + * @return The recommended user path, or 0 if unsupported + */ +const char *platform_user_path_recommend(void); + +/** + * Creates subdirectories for a user path + */ +void platform_user_path_create_subdirectories(void); + +/** + * Copies files from the default user path to the new user path + * + * @param original_user_path The user path to copy files from + * @param overwrite Whether to overwrite existing files + */ +void platform_user_path_copy_files(const char *original_user_path, int overwrite); + +/** + * Copies campaigns and custom empires from the default place to the new subdirectories + */ +void platform_user_path_copy_campaigns_and_custom_empires(void); + +#endif // PLATFORM_USER_PATH_H + diff --git a/src/platform/vita/vita.h b/src/platform/vita/vita.h index 5f133445be..20c01bfcdb 100644 --- a/src/platform/vita/vita.h +++ b/src/platform/vita/vita.h @@ -21,5 +21,7 @@ void platform_hide_virtual_keyboard(void); #define PLATFORM_USE_SOFTWARE_CURSOR +#define PLATFORM_NO_USER_DIRECTORIES + #endif // __vita__ #endif // PLATFORM_VITA_H diff --git a/src/scenario/custom_messages.c b/src/scenario/custom_messages.c index 96ae851ab7..dceffb1567 100644 --- a/src/scenario/custom_messages.c +++ b/src/scenario/custom_messages.c @@ -10,18 +10,18 @@ #define CUSTOM_MESSAGES_ARRAY_SIZE_STEP 100 static const char *AUDIO_FILE_PATHS[] = { - CAMPAIGNS_DIRECTORY "/audio/", - "community/audio/", - "mp3/", - "wavs/", + CAMPAIGNS_DIRECTORY "/audio", + "community/audio", + "mp3", + "wavs", 0 }; static const char *VIDEO_FILE_PATHS[] = { - CAMPAIGNS_DIRECTORY "/video/", - "community/video/", - "smk/", - "mpg/", + CAMPAIGNS_DIRECTORY "/video", + "community/video", + "smk", + "mpg", 0 }; @@ -233,11 +233,18 @@ uint8_t *custom_messages_get_text(custom_message_t *message) static const char *check_for_file_in_dir(const char *filename, const char *directory) { static char filepath[FILE_NAME_MAX]; - strncpy(filepath, directory, FILE_NAME_MAX); - size_t directory_length = strlen(directory); - strncpy(&filepath[directory_length], filename, FILE_NAME_MAX - directory_length); - filepath[FILE_NAME_MAX - 1] = 0; - return campaign_has_file(filepath) || file_exists(filepath, MAY_BE_LOCALIZED) ? filepath : 0; + int location = PATH_LOCATION_ROOT; + if (strncmp(directory, "community/", 10) == 0) { + directory += 10; + location = PATH_LOCATION_COMMUNITY; + } + if (snprintf(filepath, FILE_NAME_MAX, "%s/%s", directory, filename) > FILE_NAME_MAX) { + log_error("Filename too long. The file will not be loaded.", filename, 0); + } + if (campaign_has_file(filepath)) { + return filepath; + } + return dir_get_file_at_location(filepath, location); } static const char *search_for_file(const uint8_t *filename, const char *paths[]) diff --git a/src/scenario/custom_messages_import_xml.c b/src/scenario/custom_messages_import_xml.c index 0a359b9441..f5f532275f 100644 --- a/src/scenario/custom_messages_import_xml.c +++ b/src/scenario/custom_messages_import_xml.c @@ -14,9 +14,11 @@ #include #include +#define ERROR_MESSAGE_LENGTH 200 + static struct { int success; - char error_message[200]; + char error_message[ERROR_MESSAGE_LENGTH]; int error_line_number; uint8_t error_line_number_text[50]; int version; @@ -155,7 +157,7 @@ static void display_and_log_error(const char *msg) { data.success = 0; data.error_line_number = xml_parser_get_current_line_number(); - strcpy(data.error_message, msg); + snprintf(data.error_message, ERROR_MESSAGE_LENGTH, "%s", msg); log_error("Error while importing custom messages from XML. ", data.error_message, 0); log_error("Line:", 0, data.error_line_number); diff --git a/src/scenario/editor.c b/src/scenario/editor.c index 4206411f6d..25b98e0040 100644 --- a/src/scenario/editor.c +++ b/src/scenario/editor.c @@ -373,7 +373,7 @@ void scenario_editor_change_empire(int change) void scenario_editor_set_custom_empire(const char *filename) { scenario.empire.id = SCENARIO_CUSTOM_EMPIRE; - strncpy(scenario.empire.custom_name, filename, sizeof(scenario.empire.custom_name) - 1); + snprintf(scenario.empire.custom_name, FILE_NAME_MAX, "%s", filename); } void scenario_editor_unset_custom_empire(void) @@ -382,7 +382,7 @@ void scenario_editor_unset_custom_empire(void) return; } scenario.empire.id = 0; - memset(scenario.empire.custom_name, 0, sizeof(scenario.empire.custom_name)); + scenario.empire.custom_name[0] = 0; } int scenario_editor_is_building_allowed(int id) diff --git a/src/scenario/scenario_events_export_xml.c b/src/scenario/scenario_events_export_xml.c index 13f0708b5c..e80a036a54 100644 --- a/src/scenario/scenario_events_export_xml.c +++ b/src/scenario/scenario_events_export_xml.c @@ -12,19 +12,20 @@ #include "scenario/scenario_events_parameter_data.h" #include "window/plain_message_dialog.h" -#include +#include #define XML_EXPORT_MAX_SIZE 5000000 +#define ERROR_MESSAGE_LENGTH 200 static struct { int success; - char error_message[200]; + char error_message[ERROR_MESSAGE_LENGTH]; } data; static void log_exporting_error(const char *msg) { data.success = 0; - strcpy(data.error_message, msg); + snprintf(data.error_message, ERROR_MESSAGE_LENGTH, "%s", msg); log_error("Error while exporting scenario events to XML. ", data.error_message, 0); window_plain_message_dialog_show_with_extra( @@ -80,16 +81,18 @@ static int export_attribute_resource(xml_data_attribute_t *attr, int target) } const char *resource_name = resource_get_data(target)->xml_attr_name; - char resource_name_to_use[50] = " "; + char resource_name_to_use[50]; const char *next = strchr(resource_name, '|'); - size_t length = next ? (size_t) (next - resource_name) : strlen(resource_name); - if (length > 48) { - length = 48; + if (next) { + size_t length = ((size_t) (next - resource_name) + 1) * sizeof(char); + if (length > sizeof(resource_name_to_use)) { + length = sizeof(resource_name_to_use); + } + snprintf(resource_name_to_use, length, "%s", resource_name); + resource_name = resource_name_to_use; } - strncpy(resource_name_to_use, resource_name, length); - - xml_exporter_add_attribute_text(attr->name, string_from_ascii(resource_name_to_use)); + xml_exporter_add_attribute_text(attr->name, string_from_ascii(resource_name)); return 1; } diff --git a/src/scenario/scenario_events_import_xml.c b/src/scenario/scenario_events_import_xml.c index 0cf3d3cef9..6305a6de00 100644 --- a/src/scenario/scenario_events_import_xml.c +++ b/src/scenario/scenario_events_import_xml.c @@ -17,13 +17,13 @@ #include #include -#include #define XML_TOTAL_ELEMENTS 61 +#define ERROR_MESSAGE_LENGTH 200 static struct { int success; - char error_message[200]; + char error_message[ERROR_MESSAGE_LENGTH]; int error_line_number; uint8_t error_line_number_text[50]; int version; @@ -289,7 +289,7 @@ static void xml_import_log_error(const char *msg) { data.success = 0; data.error_line_number = xml_parser_get_current_line_number(); - strcpy(data.error_message, msg); + snprintf(data.error_message, ERROR_MESSAGE_LENGTH, "%s", msg); log_error("Error while import scenario events from XML. ", data.error_message, 0); log_error("Line:", 0, data.error_line_number); @@ -640,6 +640,7 @@ int scenario_events_xml_parse_file(const char *filename) free(xml_contents); if (!success) { log_error("Error parsing file", filename, 0); + scenario_events_clear(); } return success; } diff --git a/src/sound/system.c b/src/sound/system.c index 23fc3b720b..3824e76307 100644 --- a/src/sound/system.c +++ b/src/sound/system.c @@ -9,7 +9,7 @@ #include "sound/music.h" #include "sound/speech.h" -#include +#include static char channel_filenames[SOUND_CHANNEL_MAX][CHANNEL_FILENAME_MAX] = { "", // speech channel @@ -180,7 +180,7 @@ static void correct_channel_filenames(void) if (!corrected) { channel_filenames[i][0] = 0; } else if (corrected != original) { - strncpy(original, corrected, CHANNEL_FILENAME_MAX); + snprintf(original, CHANNEL_FILENAME_MAX, "%s", corrected); } } } diff --git a/src/translation/english.c b/src/translation/english.c index 690a78fc2f..ec02302b7b 100644 --- a/src/translation/english.c +++ b/src/translation/english.c @@ -864,6 +864,8 @@ static translation_string all_strings[] = { {TR_BUILDING_ACADEMY_UPGRADE_DESC, "This academy is operational. Local development allowed your citizens to expand the building, providing more halls for orations and research to take place."}, {TR_BUILDING_PALISADE_GATE, "Palisade gate"}, {TR_BUILDING_PALISADE_GATE_DESC, "This narrow wooden gateway controls the movement of people in and out of your city's defenses."}, + {TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TITLE, "File does not exist"}, + {TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TEXT, "The selected file does not exist.\nPlease select a different file."}, {TR_SAVE_DIALOG_INVALID_FILE, "Invalid file"}, {TR_SAVE_DIALOG_INVALID_FILE_DESC, "The savegame you're trying to load is invalid.\n\nThe save may have been corrupted due to a bug.\n\nIf you're sure this should be a valid save, please report the bug to:\n\nhttps://github.com/Keriew/augustus/issues/new\n\nPlease attach the save as well."}, {TR_SAVE_DIALOG_INCOMPATIBLE_VERSION, "Incompatible version"}, @@ -1475,6 +1477,25 @@ static translation_string all_strings[] = { {TR_BUILDING_LATRINES_MISSING_EVOLVE, "This house cannot evolve, as it does not have access to a latrine or a clean water supply from a fountain."}, {TR_BUILDING_LATRINES_MISSING_DEVOLVE, "This house will devolve soon, as it does not have access to a latrine or a clean water from a fountain."}, {TR_BUILDING_LATRINES_NO_WORKERS, "Without employees to maintain the latrines, citizens avoid coming to relax there."}, + {TR_CONFIG_USER_PATH_DEFAULT, "Default (Caesar III installation path, no subdirectories)" }, + {TR_CONFIG_USER_PATH_WITH_SUBDIRECTORIES, "Caesar III installation path, using subdirectories" }, + {TR_CONFIG_USER_PATH_RECOMMENDED, "Recommended ("}, + {TR_CONFIG_USER_PATH_CUSTOM, "Set custom directory..."}, + {TR_USER_DIRECTORIES_NOT_SET_UP_TITLE, "Custom user directories not setup"}, + {TR_USER_DIRECTORIES_NOT_SET_UP_TEXT, "You have not setup your user directory, where the savegames, scenarios and maps will be stored.\n" \ + "Do you wish to do it now?"}, + {TR_USER_DIRECTORIES_CANCELLED_TITLE, "Directory selection canceled"}, + {TR_USER_DIRECTORIES_CANCELLED_TEXT, "You have decided not to set a user directory. The C3 install directory will be used.\n" + "You can change your settings later in the configuration window."}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TITLE, "User directory not writeable"}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT, "The selected user directory is not writeable.\n\nPlease select a different user directory."}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT_DETAILED, "The selected user directory is not writeable.\n\nYou will not be able to save your games.\nPlease select a different user directory from the options window on the main menu."}, + {TR_USER_DIRECTORIES_WINDOW_TITLE, "Set user directory"}, + {TR_USER_DIRETORIES_WINDOW_USER_PATH, "User directory:" }, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_TITLE, "User path changed"}, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_TEXT, "The user path was successfully changed.\nDo you want to copy over your files?"}, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_OVERWRITE, "Overwrite existing files"}, + {TR_FIGURE_TYPE_ARMORY_CARTPUSHER, "Armory deliveryman"} }; void translation_english(const translation_string **strings, int *num_strings) diff --git a/src/translation/french.c b/src/translation/french.c index b0c49b0a75..2803e93b56 100644 --- a/src/translation/french.c +++ b/src/translation/french.c @@ -397,10 +397,6 @@ static translation_string all_strings[] = { {TR_TOOLTIP_BUTTON_DELETE_READ_MESSAGES, "Supprimer les messages lus"}, {TR_TOOLTIP_BUTTON_MOTHBALL_ON, "Désactiver ce bâtiment"}, {TR_TOOLTIP_BUTTON_MOTHBALL_OFF, "Activer ce bâtiment"}, - {TR_TOOLTIP_BUTTON_ACCEPT_MARKET_LADIES, "Autoriser les marchés à se fournir ici"}, - {TR_TOOLTIP_BUTTON_ACCEPT_TRADE_CARAVAN, "Autoriser les caravanes à commercer ici"}, - {TR_TOOLTIP_BUTTON_ACCEPT_TRADE_SHIPS, "Autoriser les navires à commercer ici"}, - {TR_TOOLTIP_BUTTON_ACCEPT_WORKERS, "Suspendre la livraison des biens vers les ateliers, fabriques, ou greniers"}, {TR_TOOLTIP_BUTTON_STOCKPILING_ON, " Activer le stockage vers un entrepôt"}, {TR_TOOLTIP_BUTTON_STOCKPILING_OFF, "Désactiver le stockage"}, {TR_BUILDING_LIGHTHOUSE, "Phare"}, @@ -463,7 +459,6 @@ static translation_string all_strings[] = { {TR_TOOLTIP_OVERLAY_PANTHEON_ACCESS, "Cette maison a accès aux cinq dieux vénérés au Panthéon"}, {TR_BUILDING_LEGION_FOOD_BONUS, "La nourriture abondante renforce le moral"}, {TR_BUILDING_LEGION_FOOD_STATUS, "Statut alimentaire"}, - {TR_TOOLTIP_BUTTON_ACCEPT_QUARTERMASTER, "Autoriser l'intendant à obtenir de la nourriture ici"}, {TR_WARNING_RESOURCES_NOT_AVAILABLE, "Vous ne pouvez pas obtenir les matériaux nécessaires"}, {TR_CONFIG_GP_CH_MONUMENTS_BOOST_CULTURE_RATING, "Les temples monumentaux confèrent un bonus de culture de +6"}, {TR_CONFIG_GP_CH_DISABLE_INFINITE_WOLVES_SPAWNING, "Désactiver la réapparition des loups"}, @@ -780,7 +775,6 @@ static translation_string all_strings[] = { {TR_WINDOW_RACE_RED_HORSE_DESCRIPTION, "L'équipe Rouge - connue pour accueillir le plus talentueux aurige de l'histoire de Rome - un ancien rameur, et sauveur d'un consul Romain." }, {TR_WINDOW_RACE_WHITE_HORSE_DESCRIPTION, "L'équipe Blanche - fondée par d'anciens gladiateurs. Le combat coule dans leurs veines, et même en hommes libres, ils ne vivent que pour la compétition." }, {TR_WINDOW_RACE_GREEN_HORSE_DESCRIPTION, "L'équipe Verte - les descendants des cavaliers 'Celeres', au temps jadis du Royaume de Rome. Ils se considèrent comme l'élite parmi l'élite." }, - {TR_TOOLTIP_BUTTON_REJECT_WORKERS, "Reprendre la livraison des biens"}, {TR_CONFIG_DIGIT_SEPARATOR, "Afficher un séparateur de milliers pour les nombres"}, {TR_TOOLTIP_OVERLAY_PROBLEMS_NO_LABOR, "Pas de main-d'œuvre" }, {TR_WINDOW_BUILDING_DISTRIBUTION_GRANARY_CART_PUSHER_GETTING, "Le magasinier est parti chercher des vivres dans un autre grenier."}, @@ -870,6 +864,8 @@ static translation_string all_strings[] = { {TR_BUILDING_ACADEMY_UPGRADE_DESC, "Cette université est opérationnelle. Le développement local a permis d'agrandir le bâtiment. De nombreuses conférences et recherches peuvent à présent s'y tenir."}, {TR_BUILDING_PALISADE_GATE, "Portail de palissade"}, {TR_BUILDING_PALISADE_GATE_DESC, "Cet étroit portail en bois permet de contrôler le passage des citoyens à travers les défenses de la cité."}, + {TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TITLE, "Le fichier n'existe pas"}, + {TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TEXT, "Le fichier choisi n'existe pas.\nVeuillez sélectionner un autre fichier."}, {TR_SAVE_DIALOG_INVALID_FILE, "Fichier non valide"}, {TR_SAVE_DIALOG_INVALID_FILE_DESC, "Cette sauvegarde n'est pas valide.\n\nCelle-ci a pu être corrompue en raison d'un bug.\n\nSi vous êtes sûr(e) qu'il s'agit d'une sauvegarde valide, veuillez signaler le bug sur :\n\nhttps://github.com/Keriew/augustus/issues/new\n\nMerci de joindre le fichier de sauvegarde."}, {TR_SAVE_DIALOG_INCOMPATIBLE_VERSION, "Version incompatible"}, @@ -1433,7 +1429,6 @@ static translation_string all_strings[] = { {TR_WINDOW_CAMPAIGN_MISSION_FAILED_TO_LOAD_TEXT, "Cette mission ne peut pas être lancée.\nVeuillez consulter le fichier augustus-log.txt dans votre répertoire Augustus pour plus de détails."}, {TR_EDITOR_CAESAR_SALARY, "Salaire de César"}, {TR_CITY_MESSAGE_TEXT_CARAVANSERAI_COMPLETE, "Le Caravansérail est achevé, et de nouvelles opportunités commerciales se profilent déjà à l'horizon. Les caravanes des quatre coins du monde sont plus qu'enthousiastes à l'idée de venir commercer dans votre cité."}, - {TR_CONFIG_SHOW_DESIRABILITY_RANGE , "Voir l'attrait des mausolées et nymphées lors du placement"}, {TR_WINDOW_BARRACKS_PRIORITY, "Priorité de recrutement :"}, {TR_WINDOW_BARRACKS_FORTS, "Forts"}, {TR_WINDOW_BARRACKS_TOWERS, "Tours"}, @@ -1444,16 +1439,31 @@ static translation_string all_strings[] = { {TR_TOOLTIP_BARRACKS_PRIORITY_AUXARCH, "Former en priorité des Archers"}, {TR_TOOLTIP_BARRACKS_PRIORITY_TOWER, "Former en priorité des Sentinelles pour les Tours"}, {TR_TOOLTIP_BARRACKS_PRIORITY_WATCHTOWER, "Former en priorité des Gardes pour les Tours de guet"}, - {TR_TOOLTIP_BUTTON_REJECT_DELIVERY, "Suspendre la livraison d'armes par l'Armurerie"}, - {TR_TOOLTIP_BUTTON_ACCEPT_DELIVERY, "Autoriser la livraison d'armes par l'Armurerie"}, + {TR_TOOLTIP_BUTTON_REJECT_DELIVERY, "Ne pas autoriser l'Armurerie à livrer des armes ici"}, + {TR_TOOLTIP_BUTTON_ACCEPT_DELIVERY, "Autoriser l'Armurerie à livrer des armes ici"}, {TR_CONFIG_SHOW_DESIRABILITY_RANGE, "Voir l'attrait des mausolées et nymphées lors du placement"}, {TR_BUILDING_FORT_ARCHERS, "Auxiliaires - Arc"}, {TR_WINDOW_ADVISOR_MILITARY_ARCHER, "Archers"}, + {TR_TOOLTIP_BUTTON_ACCEPT_MARKET_LADIES, "Autoriser les marchés à se fournir ici"}, + {TR_TOOLTIP_BUTTON_REJECT_MARKET_LADIES, "Ne pas autoriser les marchés à se fournir ici"}, + {TR_TOOLTIP_BUTTON_ACCEPT_TRADE_CARAVAN, "Autoriser les caravanes à commercer ici"}, + {TR_TOOLTIP_BUTTON_REJECT_TRADE_CARAVAN, "Ne pas autoriser les caravanes à commercer ici"}, + {TR_TOOLTIP_BUTTON_ACCEPT_TRADE_SHIPS, "Autoriser les navires à commercer ici"}, + {TR_TOOLTIP_BUTTON_REJECT_TRADE_SHIPS, "Ne pas autoriser les navires à commercer ici"}, + {TR_TOOLTIP_BUTTON_ACCEPT_QUARTERMASTER, "Autoriser le réfectoire à obtenir de la nourriture ici"}, + {TR_TOOLTIP_BUTTON_REJECT_QUARTERMASTER, "Ne pas autoriser le réfectoire à obtenir de la nourriture ici"}, + {TR_TOOLTIP_BUTTON_ACCEPT_WORKERS, "Reprendre la livraison des biens vers les ateliers, fabriques, ou greniers"}, + {TR_TOOLTIP_BUTTON_REJECT_WORKERS, "Suspendre la livraison des biens vers les ateliers, fabriques, ou greniers"}, {TR_TOOLTIP_BUTTON_ACCEPT_BARKEEP, "Autoriser les tavernes à se fournir ici"}, + {TR_TOOLTIP_BUTTON_REJECT_BARKEEP, "Ne pas autoriser les tavernes à se fournir ici"}, {TR_TOOLTIP_BUTTON_ACCEPT_CARAVANSERAI, "Autoriser le Caravansérail à se fournir ici"}, - {TR_TOOLTIP_BUTTON_ACCEPT_ARMOURY, "Autoriser l'Armurerie à se fournir ici"}, + {TR_TOOLTIP_BUTTON_REJECT_CARAVANSERAI, "Ne pas autoriser le Caravansérail à se fournir ici"}, {TR_TOOLTIP_BUTTON_ACCEPT_LIGHTHOUSE, "Autoriser le Phare à se fournir ici"}, + {TR_TOOLTIP_BUTTON_REJECT_LIGHTHOUSE, "Ne pas autoriser le Phare à se fournir ici"}, + {TR_TOOLTIP_BUTTON_ACCEPT_ARMOURY, "Autoriser l'Armurerie à se fournir ici"}, + {TR_TOOLTIP_BUTTON_REJECT_ARMOURY, "Ne pas autoriser l'Armurerie à se fournir ici"}, {TR_TOOLTIP_BUTTON_ACCEPT_WORKCAMP, "Autoriser les chantiers à se fournir ici"}, + {TR_TOOLTIP_BUTTON_REJECT_WORKCAMP, "Ne pas autoriser les chantiers à se fournir ici"}, {TR_BUILDING_FORT_LEGIONARIES, "Légionnaires" }, {TR_WINDOW_ADVISOR_LEGIONARIES, "Légionnaires" }, {TR_BUILDING_FORT_MOUNTED, "Auxiliaires - Cavalerie" }, @@ -1467,7 +1477,25 @@ static translation_string all_strings[] = { {TR_BUILDING_LATRINES_MISSING_EVOLVE, "Cette maison ne peut pas évoluer, car elle n'a pas accès à des latrines ou à l'eau propre d'une fontaine."}, {TR_BUILDING_LATRINES_MISSING_DEVOLVE, "Cette maison va bientôt régresser, car elle n'a pas accès à des latrines ou à l'eau propre d'une fontaine."}, {TR_BUILDING_LATRINES_NO_WORKERS, "Sans employés pour entretenir les latrines, les citoyens évitent de venir s'y relaxer."}, - + {TR_CONFIG_USER_PATH_DEFAULT, "Défaut (répertoire d'installation de Caesar III, pas de sous-dossiers)" }, + {TR_CONFIG_USER_PATH_WITH_SUBDIRECTORIES, "répertoire d'installation de Caesar III, avec sous-dossiers" }, + {TR_CONFIG_USER_PATH_RECOMMENDED, "Recommandé ("}, + {TR_CONFIG_USER_PATH_CUSTOM, "Définir le répertoire..."}, + {TR_USER_DIRECTORIES_NOT_SET_UP_TITLE, "Répertoire personnalisé non défini"}, + {TR_USER_DIRECTORIES_NOT_SET_UP_TEXT, "Vous n'avez pas défini le répertoire dans lequel les sauvegardes, scénarios et cartes seront stockés.\n" \ + "Voulez-vous le définir maintenant ?"}, + {TR_USER_DIRECTORIES_CANCELLED_TITLE, "Choix du répertoire annulé"}, + {TR_USER_DIRECTORIES_CANCELLED_TEXT, "Vous avez décidé de ne pas définir de répertoire. Le répertoire par défaut de C3 sera utilisé.\n" + "Vous pouvez modifier ce réglage dans le menu Options."}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TITLE, "Répertoire protégé en écriture"}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT, "Le répertoire défini est protégé en écriture.\n\nVeuillez sélectionner un répertoire différent."}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT_DETAILED, "Le répertoire défini est protégé en écriture.\n\nVous ne pourrez pas sauvegarder vos parties.\nVeuillez sélectionner un autre répertoire depuis le menu Options."}, + {TR_USER_DIRECTORIES_WINDOW_TITLE, "Définir le répertoire"}, + {TR_USER_DIRETORIES_WINDOW_USER_PATH, "Répertoire :" }, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_TITLE, "Répertoire modifié"}, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_TEXT, "Le chemin du répertoire a été modifié avec succès.\nVoulez-vous y copier vos fichiers ?"}, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_OVERWRITE, "Écraser les fichiers existants"}, + {TR_FIGURE_TYPE_ARMORY_CARTPUSHER, "Livreur de l'Armurerie"} }; void translation_french(const translation_string **strings, int *num_strings) diff --git a/src/translation/italian.c b/src/translation/italian.c index a4d321a91d..f9a8c96534 100644 --- a/src/translation/italian.c +++ b/src/translation/italian.c @@ -37,6 +37,7 @@ static translation_string all_strings[] = { {TR_CONFIG_HEADER_CITY_MANAGEMENT_CHANGES, "Gestione della città"}, {TR_CONFIG_LANGUAGE_LABEL, "Lingua:"}, {TR_CONFIG_LANGUAGE_DEFAULT, "(default)"}, + {TR_CONFIG_DEFAULT_PLAYER_NAME, "Nome giocatore di default:"}, {TR_CONFIG_GAME_SPEED, "Velocità del gioco:"}, {TR_CONFIG_VIDEO, "Opzioni Video"}, {TR_CONFIG_FULLSCREEN, "A schermo pieno"}, @@ -62,6 +63,7 @@ static translation_string all_strings[] = { {TR_CONFIG_ALLOW_CYCLING_TEMPLES, "Consente la costruzione di ogni tempio in successione"}, {TR_CONFIG_SHOW_WATER_STRUCTURE_RANGE, "Mostra la copertura di cisterne, fontane e pozzi"}, {TR_CONFIG_SHOW_WATER_STRUCTURE_RANGE_HOUSES, "Mostra il raggio di azione di fontane e pozzi durante la costruzione delle case"}, + {TR_CONFIG_SHOW_MARKET_RANGE, "Mostra range quando costruisci il mercato"}, {TR_CONFIG_SHOW_CONSTRUCTION_SIZE, "Mostra le dimensioni della costruzione durante il trascinamento"}, {TR_CONFIG_HIGHLIGHT_LEGIONS, "Evidenzia la legione al passaggio del cursore"}, {TR_CONFIG_ROTATE_MANUALLY, "Ruota i Bastioni e l'Arco di Trionfo tramite scorciatoie da tastiera"}, @@ -110,7 +112,7 @@ static translation_string all_strings[] = { {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Disegna le ombre delle nuvole"}, {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Chiedi conferma alla sovrascrittura di un file"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "I portali civili fanno passare tutti i passeggiatori di default"}, - {TR_HOTKEY_TITLE, "Configurazione scorciatoie da tastiera Augustus"}, + {TR_HOTKEY_TITLE, "Configura scorciatoie da tastiera Augustus"}, {TR_HOTKEY_LABEL, "Tasto"}, {TR_HOTKEY_ALTERNATIVE_LABEL, "Alternativa"}, {TR_HOTKEY_HEADER_ARROWS, "Pulsanti frecce"}, @@ -179,8 +181,8 @@ static translation_string all_strings[] = { {TR_HOTKEY_EDIT_TITLE, "Premi nuova pulsante scorciatoia"}, {TR_BUILDING_ROADBLOCK, "Blocco stradale"}, {TR_BUILDING_ROADBLOCK_DESC, "Il Blocco stradale blocca i vagabondi."}, - {TR_BUILDING_ARCHITECT_GUILD, "Gilda degli Ingienieri"}, - {TR_BUILDING_ARCHITECT_GUILD_DESC, "Gli ingenieri di questa gilda lavorano senza sosta alla costruzione dei monumenti per la gloria di Roma"}, + {TR_BUILDING_ARCHITECT_GUILD, "Gilda degli Ingegneri"}, + {TR_BUILDING_ARCHITECT_GUILD_DESC, "Gli ingegneri di questa gilda lavorano senza sosta alla costruzione dei monumenti per la gloria di Roma"}, {TR_BUILDING_GRAND_TEMPLE_ADD_MODULE, "Concedi un epiteto sul tempio"}, {TR_BUILDING_GRAND_TEMPLE_CERES, "Tempio Grande di Cerere"}, {TR_BUILDING_GRAND_TEMPLE_NEPTUNE, "Tempio Grande di Nettuno"}, @@ -468,6 +470,11 @@ static translation_string all_strings[] = { {TR_LABEL_PAUSE_MENU, "Pausa"}, {TR_OVERLAY_LEVY, "Leva"}, {TR_TOOLTIP_OVERLAY_LEVY, " denari mensili pagati per la leva."}, + {TR_OVERLAY_EMPLOYMENT, "Occupazione" }, + {TR_TOOLTIP_OVERLAY_EMPLOYMENT_FULL, "Questa struttura è a pieno organico" }, + {TR_TOOLTIP_OVERLAY_EMPLOYMENT_MISSING_1, " lavoratore mancante in questa struttura" }, + {TR_TOOLTIP_OVERLAY_EMPLOYMENT_MISSING_2, " lavoratori mancanti in questa struttura" }, + {TR_TOOLTIP_OVERLAY_EMPLOYMENT_MOTHBALL, " lavoratori mancanti in questa struttura (in sospeso)" }, {TR_MAP_EDITOR_OPTIONS, "Impostazioni scenario"}, {TR_BUILDING_TAVERN, "Taverna"}, {TR_BUILDING_GRAND_GARDEN, "Grande giardino"}, @@ -545,7 +552,8 @@ static translation_string all_strings[] = { {TR_BUILDING_HIPPODROME_PHASE_4_TEXT, "Più che una semplica pista, gli artigiani stanno creando un monumento degno degli dei e del popolo di Roma."}, {TR_BUILDING_MONUMENT_CONSTRUCTION_DESC, "La costruzione del monumento richiede materiali in magazzino, lavoratori da un campo di lavoro, e architetti dalla gilda degli architetti."}, {TR_BUILDING_MONUMENT_CONSTRUCTION_HALTED, "Costruzione interrotta."}, - {TR_WINDOW_ADVISOR_ENTERTAINMENT_ARENA_COVERAGE, "Arene"}, + {TR_WINDOW_ADVISOR_ENTERTAINMENT_ARENA_COVERAGE, "Arena"}, + {TR_WINDOW_ADVISOR_ENTERTAINMENT_ARENA_COVERAGE_PLURAL, "Arene"}, {TR_BUILDING_INFO_TOURISM, "(Viandanti)"}, {TR_CITY_MESSAGE_TEXT_COLOSSEUM_COMPLETE, "Il Colosseo è completo! Che i giochi comincino!"}, {TR_CITY_MESSAGE_TEXT_HIPPODROME_COMPLETE, "L'Ippodromo è completo. I tuoi cittadini aspettano con ansia il tuo ordine di dare inizio alle corse!"}, @@ -785,11 +793,26 @@ static translation_string all_strings[] = { {TR_BUILDING_WAREHOUSE_NO_GOODS, "Non ci sono merci stoccate in questo magazzino."}, {TR_BUILDING_HOUSE_DISEASE_DESC, "La pestilenza ha colpito! Senza un'adeguata assistenza sanitaria, gli abitanti di questa casa sono morti. Questa casa è in quarantena mentre un medico o un chirurgo sanifica l'area."}, {TR_BUILDING_FUMIGATION_DESC, "La sanificazione di questo edificio è in corso, la fumigazione dovrebbe durare qualche giorno."}, + {TR_OVERLAY_HEALTH, "Globale"}, {TR_OVERLAY_SICKNESS, "Malattie"}, + {TR_ADVISOR_HEALTH_RATING, "Valutazione:"}, + {TR_ADVISOR_HEALTH_SURVEILLANCE, "Sorveglianza Malattie:"}, {TR_ADVISOR_SICKNESS_LEVEL_LOW, "In città sono diffuse pochissime malattie e il commercio procede senza restrizioni. Il livello d'igiene cittadina permette di arginare efficaciemente le epidemie provenienti da altre città."}, {TR_ADVISOR_SICKNESS_LEVEL_MEDIUM, "Sono riportati in città alcuni casi di malattie infettive, ma la situazione è sotto controllo. Assicurati che sia mantenuto un corretto livello di igiene per evitare restizioni al commercio. Gli ospedali sono efficaci nella prevenzione delle epidemie."}, {TR_ADVISOR_SICKNESS_LEVEL_HIGH, "Molte malattie infettive si stanno diffondendo in alcune aree della città. Se non prendi subito provvedimenti efficaci, scali, magazzini e granai potrebbero essere messi in quarantena, impedendo il commercio. Costruisci ospedali vicino a questi edifici per arginare le epidemie provenienti da altre città."}, {TR_ADVISOR_SICKNESS_LEVEL_PLAGUE, "La peste dilaga in città e il commercio ne è gravemente limitato. I dottori sono costretti a concentrarsi sulla decontaminazione dei luoghi più colpiti dall'epidemia. Occorrono provvedimenti urgenti!"}, + {TR_TOOLTIP_OVERLAY_HEALTH_NONE, "Nessun cittadino vive qui ancora"}, + {TR_TOOLTIP_OVERLAY_HEALTH_0, "La salute in questa casa è spaventosa"}, + {TR_TOOLTIP_OVERLAY_HEALTH_1, "La salute in questa casa è terribile"}, + {TR_TOOLTIP_OVERLAY_HEALTH_2, "La salute in questa casa è molto scarsa"}, + {TR_TOOLTIP_OVERLAY_HEALTH_3, "La salute in questa casa è scarsa"}, + {TR_TOOLTIP_OVERLAY_HEALTH_4, "La salute in questa casa è sotto la media"}, + {TR_TOOLTIP_OVERLAY_HEALTH_5, "La salute in questa casa è media"}, + {TR_TOOLTIP_OVERLAY_HEALTH_6, "La salute in questa casa è buona"}, + {TR_TOOLTIP_OVERLAY_HEALTH_7, "La salute in questa casa è molto buona"}, + {TR_TOOLTIP_OVERLAY_HEALTH_8, "La salute in questa casa è eccellente"}, + {TR_TOOLTIP_OVERLAY_HEALTH_9, "La salute in questa casa è quasi perfetta"}, + {TR_TOOLTIP_OVERLAY_HEALTH_10, "La salute in questa casa è perfetta"}, {TR_TOOLTIP_OVERLAY_SICKNESS_NONE, "Nessuna malattia"}, {TR_TOOLTIP_OVERLAY_SICKNESS_LOW, "Pochissime malattie"}, {TR_TOOLTIP_OVERLAY_SICKNESS_MEDIUM, "Qualche caso di malattie infettive"}, @@ -820,6 +843,7 @@ static translation_string all_strings[] = { {TR_HOTKEY_SHOW_OVERLAY_SCHOOL, "Overlay scuole"}, {TR_HOTKEY_SHOW_OVERLAY_LIBRARY, "Overlay biblioteche"}, {TR_HOTKEY_SHOW_OVERLAY_ACADEMY, "Overlay Accademie"}, + {TR_HOTKEY_SHOW_OVERLAY_HEALTH, "Overlay Salute" }, {TR_HOTKEY_SHOW_OVERLAY_BARBER, "Overlay barbieri"}, {TR_HOTKEY_SHOW_OVERLAY_BATHHOUSE, "Overlay bagni"}, {TR_HOTKEY_SHOW_OVERLAY_CLINIC, "Overlay cliniche"}, @@ -832,6 +856,7 @@ static translation_string all_strings[] = { {TR_HOTKEY_SHOW_OVERLAY_RELIGION, "Overlay religione"}, {TR_HOTKEY_SHOW_OVERLAY_ROADS, "Overlay strade"}, {TR_HOTKEY_SHOW_OVERLAY_LEVY, "Overlay leve"}, + {TR_HOTKEY_SHOW_OVERLAY_EMPLOYMENT, "Overlay Occupazione" }, {TR_HOTKEY_ROTATE_MAP_NORTH, "Ruota mappa con Nord in alto"}, {TR_HOTKEY_BUILD_WHEAT_FARM, "Coltivazione di grano"}, {TR_HOTKEY_SHOW_MESSAGES, "Mostra messaggi"}, @@ -845,6 +870,7 @@ static translation_string all_strings[] = { {TR_BUILDING_PALISADE_GATE, "Cancello a palizzata"}, {TR_BUILDING_PALISADE_GATE_DESC, "Questa stretta porta di legno controlla il movimento delle persone all'interno e all'esterno delle difese della città."}, {TR_SAVE_DIALOG_INVALID_FILE, "File non valido"}, + {TR_SAVE_DIALOG_INVALID_FILE_DESC, "Il salvataggio che stai cercando di aprire non è valido.\n\nIl file potrebbe risultare corrotto a causa di un bug.\n\nSe sei sicuro che il salvataggio sia valido, per favore segnala il problema a:\n\nhttps://github.com/Keriew/augustus/issues/new\n\nPer favore ricorda di allegare anche il file alla segnalazione."}, {TR_SAVE_DIALOG_INCOMPATIBLE_VERSION, "Versione incompatibile"}, {TR_SAVE_DIALOG_NEW_FILE, "Nuovo File"}, {TR_SAVE_DIALOG_SELECT_FILE, "Seleziona un file"}, @@ -856,6 +882,12 @@ static translation_string all_strings[] = { {TR_SAVE_DIALOG_MISSION, "Missione"}, {TR_SAVE_DIALOG_MILITARY, "Militare"}, {TR_SAVE_DIALOG_PEACEFUL, "Pacifico"}, + {TR_SAVE_DIALOG_FILTER, "Filtra"}, + {TR_SAVE_DIALOG_SORTING_BY_NAME, "Ordina per nome"}, + {TR_SAVE_DIALOG_SORTING_BY_DATE, "Sorting per data"}, + {TR_SAVE_DIALOG_OVERWRITE_FILE, "Sovrascrivi file?"}, + {TR_SAVE_DIALOG_OVERWRITE_FILE_DESC, "Il file esiste già. Sovrascrivi?"}, + {TR_SAVE_DIALOG_OVERWRITE_FILE_DO_NOT_ASK_AGAIN, "Non chiedere più"}, {TR_CITY_MESSAGE_TITLE_MARS_MINOR_CURSE_PREVENTED, "L'ira di Marte"}, {TR_CITY_MESSAGE_TEXT_MARS_MINOR_CURSE_PREVENTED, "Marte è infuriato! Abbiamo poco da temere in una terra così pacifica, ma siate certi che la pace non durerà per sempre!"}, {TR_TOOLTIP_MONUMENT_PHASE, " fase. "}, @@ -951,7 +983,7 @@ static translation_string all_strings[] = { {TR_ADVISOR_ACTIVE_COLOSSEUM, "La città è dotata di un colosseo"}, {TR_ADVISOR_NO_ACTIVE_HIPPODROME, "Nessun ippodromo attivo in città"}, {TR_ADVISOR_ACTIVE_HIPPODROME, "La città è dotata di un ippodromo"}, - {TR_WINDOW_ADVISOR_EDUCATION_MISSION_POSTS, "Messaggi di missione"}, // verificare contesto + {TR_WINDOW_ADVISOR_EDUCATION_MISSION_POSTS, "Missioni"}, // 04/05/24 verificato contesto, post è inteso come "edificio della missione" in questo caso {TR_CITY_MESSAGE_TITLE_ENEMIES_LEAVING, "Nemici in ritirata"}, {TR_CITY_MESSAGE_TEXT_ENEMIES_LEAVING, "Humpf! La vostra gracile città non ha nient'altro che valga la pena di distruggere. Per ora ce ne andiamo, ma attenzione, possiamo sempre tornare!"}, {TR_ZOOM, "Zoom:"}, @@ -998,9 +1030,9 @@ static translation_string all_strings[] = { {TR_EDITOR_SELECTED_COORDS, "Coordinate Selezionate: "}, {TR_EDITOR_MAX_WAGES, "Fino a"}, {TR_EDITOR_MIN_WAGES, "Fino a"}, - {TR_EDITOR_FAVOUR_DISFAVOR, "Favor lost if extension needed"}, - {TR_EDITOR_FAVOUR_IGNORED, "Favor lost if request ignored entirely"}, - {TR_EDITOR_FAVOUR_EXTENSION_MONTHS, "Extension months allowed"}, + {TR_EDITOR_FAVOUR_DISFAVOR, "Favor lost if extension needed"}, // verificare contesto + {TR_EDITOR_FAVOUR_IGNORED, "Favor lost if request ignored entirely"}, // verificare contesto + {TR_EDITOR_FAVOUR_EXTENSION_MONTHS, "Extension months allowed"}, // verificare contesto {TR_EDITOR_SCENARIO_EVENTS_TITLE, "Eventi scenario" }, {TR_EDITOR_SCENARIO_EVENTS_IMPORT, "Importa" }, {TR_EDITOR_SCENARIO_EVENTS_IMPORT_FULL, "Importa eventi scenario" }, @@ -1042,9 +1074,15 @@ static translation_string all_strings[] = { {TR_EDITOR_UNABLE_TO_LOAD_CUSTOM_MESSAGES_TITLE, "Impossibile caricare i messaggi personalizzati"}, {TR_EDITOR_SCENARIO_SELECT_INTRO, "Seleziona lo scenario di ingresso"}, {TR_EDITOR_SCENARIO_DESELECT_INTRO, "Deseleziona lo scenario di ingresso"}, + {TR_EDITOR_SCENARIO_SELECT_VICTORY, "Scegli il messaggio di vittoria"}, + {TR_EDITOR_SCENARIO_DESELECT_VICTORY, "Rimuovi il messaggio di vittoria"}, {TR_EDITOR_CUSTOM_VARIABLES_TITLE, "Variabili personalizzate" }, {TR_EDITOR_CUSTOM_VARIABLES_COUNT, "Massime variabili possibili" }, - {TR_EDITOR_GRID_OFFSET, " offset" }, + {TR_EDITOR_CUSTOM_VARIABLE_UNABLE_TO_CHANGE_TITLE, "Impossibile cambiare la variabile personalizzata"}, + {TR_EDITOR_CUSTOM_VARIABLE_UNABLE_TO_CHANGE_TEXT, "La variabile personalizzata è usata almeno da un evento.\n\nRimuovi la variabile dal relativo evento per poterne cambiare il nome o rimuoverla."}, + {TR_EDITOR_CUSTOM_VARIABLE_UNABLE_TO_CHANGE_EVENT_ID, "ID del primo evento dove la variabile è usata: "}, + {TR_EDITOR_GRID_OFFSET, " offset" }, + {TR_EDITOR_RETURN_TO_CITY, "Ritorna alla città"}, {TR_PARAMETER_TYPE_CHECK, "Check di comparazione"}, {TR_PARAMETER_TYPE_MIN_MAX_NUMBER_MIN, "Minimo"}, {TR_PARAMETER_TYPE_MIN_MAX_NUMBER_MAX, "Massimo"}, @@ -1082,6 +1120,7 @@ static translation_string all_strings[] = { {TR_PARAMETER_TYPE_INVASION_POINT, "Punto di invasione"}, {TR_PARAMETER_TYPE_TARGET_TYPE, "Tipo Obiettivo"}, {TR_PARAMETER_TYPE_ENEMY_TYPE, "Tipo Nemico"}, + {TR_PARAMETER_TYPE_GOD, "Dio" }, {TR_CONDITION_TYPE_TIME_PASSED, "Tempo trascorso"}, {TR_CONDITION_TYPE_DIFFICULTY, "Difficultà"}, {TR_CONDITION_TYPE_MONEY, "Denaro cittadino"}, @@ -1120,7 +1159,7 @@ static translation_string all_strings[] = { {TR_ACTION_TYPE_SEND_STANDARD_MESSAGE, "Manda un messaggio standard"}, {TR_ACTION_TYPE_ADJUST_CITY_HEALTH, "Aggiusta salute cittadina"}, {TR_ACTION_TYPE_TRADE_SET_PRICE, "Imposta prezzo di compravendita"}, - {TR_ACTION_TYPE_EMPIRE_MAP_CONVERT_FUTURE_TRADE_CITY, "Convert empire future trade city"}, + {TR_ACTION_TYPE_EMPIRE_MAP_CONVERT_FUTURE_TRADE_CITY, "Converti una città di commercio del futuro"}, {TR_ACTION_TYPE_REQUEST_IMMEDIATELY_START, "Inizia immediatamente la richiesta"}, {TR_ACTION_TYPE_SHOW_CUSTOM_MESSAGE, "Mostra messaggio personalizzato"}, {TR_ACTION_TYPE_TAX_RATE_SET, "Imposta livello di tasse"}, @@ -1135,6 +1174,9 @@ static translation_string all_strings[] = { {TR_ACTION_TYPE_TRADE_SET_SELL_PRICE_ONLY, "Imposta solo il prezzo di acquisto"}, {TR_ACTION_TYPE_BUILDING_FORCE_COLLAPSE, "Forza il collasso struttura"}, {TR_ACTION_TYPE_INVASION_IMMEDIATE, "Inizia invasione immediata"}, + {TR_ACTION_TYPE_CAUSE_BLESSING, "Causa una benedizione" }, + {TR_ACTION_TYPE_CAUSE_MINOR_CURSE, "Causa una maledizione minore" }, + {TR_ACTION_TYPE_CAUSE_MAJOR_CURSE, "Cause una maledizione importante" }, {TR_PARAMETER_VALUE_COMPARISON_TYPE_EQUAL, "Uguale"}, {TR_PARAMETER_VALUE_COMPARISON_TYPE_EQUAL_OR_LESS, "Minore o uguale"}, {TR_PARAMETER_VALUE_COMPARISON_TYPE_EQUAL_OR_MORE, "Maggiore o uguale"}, @@ -1241,6 +1283,8 @@ static translation_string all_strings[] = { {TR_PARAMETER_VALUE_MESSAGE_ENEMIES_LEAVING, "I nemici fuggono"}, {TR_PARAMETER_VALUE_MEDIA_TYPE_SOUND, "Suono"}, {TR_PARAMETER_VALUE_MEDIA_TYPE_VIDEO, "Video"}, + {TR_PARAMETER_VALUE_MEDIA_TYPE_SPEECH, "Parlato"}, + {TR_PARAMETER_VALUE_MEDIA_TYPE_BACKGROUND_IMAGE, "Background image"}, {TR_PARAMETER_VALUE_RATING_TYPE_PEACE, "Pace"}, {TR_PARAMETER_VALUE_RATING_TYPE_PROSPERITY, "Prosperità"}, {TR_PARAMETER_VALUE_STORAGE_TYPE_ALL, "Tutti"}, @@ -1268,6 +1312,11 @@ static translation_string all_strings[] = { {TR_PARAMETER_VALUE_ENEMY_9_EGYPTIAN, "Egizia"}, {TR_PARAMETER_VALUE_ENEMY_10_CARTHAGINIAN, "Cartaginese"}, {TR_PARAMETER_VALUE_ENEMY_11_CAESAR, "Cesare"}, + {TR_PARAMETER_VALUE_GOD_CERES, "Cerere"}, + {TR_PARAMETER_VALUE_GOD_MARS, "Marte"}, + {TR_PARAMETER_VALUE_GOD_MERCURY, "Mercurio"}, + {TR_PARAMETER_VALUE_GOD_NEPTUNE, "Nettuno"}, + {TR_PARAMETER_VALUE_GOD_VENUS, "Venere"}, {TR_PARAMETER_DISPLAY_SET_TO, "impostato"}, {TR_PARAMETER_DISPLAY_ADD_TO, "aggiunto"}, {TR_PARAMETER_DISPLAY_BETWEEN, "entro"}, @@ -1343,8 +1392,89 @@ static translation_string all_strings[] = { {TR_BUILDING_OVERGROWN_GARDENS, "Giardini Incolti" }, {TR_WINDOW_ADVISOR_RELIGION_ALTARS_HEADER, "Altari"}, {TR_REPLAY_MAP_NOT_FOUND_TITLE, "Impossibile rigiocare la mappa"}, - {TR_REPLAY_MAP_NOT_FOUND_MESSAGE, "Il file di mappa originale di questo salvataggio non è stato trovato.\nHai bisogno di questo file in formato .map o .mapx :"} -}; + {TR_REPLAY_MAP_NOT_FOUND_MESSAGE, "Il file di mappa originale di questo salvataggio non è stato trovato.\nHai bisogno di questo file in formato .map o .mapx :"}, + {TR_BUILDING_FORT_AUXILIA_INFANTRY, "Ausiliari - Spadaccini"}, + {TR_WINDOW_ADVISOR_MILITARY_INFANTRY, "Spadaccini"}, + {TR_TOOLTIP_BUTTON_ROADBLOCK_ORDER_ACCEPT_ALL, "Accetta tutti i passanti"}, + {TR_TOOLTIP_BUTTON_ROADBLOCK_ORDER_REJECT_ALL, "Rifiuta tutti i passanti"}, + {TR_TOOLTIP_BUTTON_STORAGE_ORDER_ACCEPT_ALL, "Accetta tutti i beni"}, + {TR_TOOLTIP_BUTTON_STORAGE_ORDER_REJECT_ALL, "Rifiuta tutti i beni"}, + {TR_FIGURE_TYPE_BEGGAR, "Povero"}, + {TR_BUILDING_ARMOURY, "Armeria" }, + {TR_BUILDING_ARMOURY_NO_EMPLOYEES, "Senza accesso alla forza lavoro, questa armeria non può consegnare armi ai nostri soldati. Che Marte ci protegga, poichè dei soldati senza armi di certo non potranno farlo!"}, + {TR_BUILDING_ARMOURY_SOME_EMPLOYEES, "Visti i pochi lavoratori in armeria, armare completamente le legioni necessiterà di parecchio tempo. Speriamo che anche i soldati nemici ci mettano molto ad arrivare!"}, + {TR_BUILDING_ARMOURY_MANY_EMPLOYEES, "Questa armeria può consegnare armi ai soldati, ma alcuni lavoratori mancanti causano saltuarie mancate consegne"}, + {TR_BUILDING_ARMOURY_DESC, "L'armeria assicura che i nostri soldati siano riforniti di armi rapidamente ed efficientemente. I barbari non sono una minaccia per la logistica Romana!" }, + {TR_BUILDING_TAVERN_DESC_UPGRADED_WINE_NO_FOOD, "Questa taverna intrattiene i cittadini, fino a che il vino continui ad essere versato. Una fornitura di carne o pesce aumenterebbe il suo appeal. Lo sviluppo locale ha permesso ai tuoi cittadini di espandere la struttura, fornendo più spazio agli avventori." }, + {TR_BUILDING_TAVERN_DESC_UPGRADED_WINE_AND_FOOD, "Questa taverna offre vino in abbondanza e l'odore della carne arrostita attira una folla vivace impegnata nel gioco d'azzardo, nella musica e nell'allegria. Lo sviluppo locale ha permesso ai tuoi cittadini di espandere l'edificio, fornendo più spazio agli avventori." }, + {TR_BUILDING_AMPHITHEATER_DESC_UPGRADED_BOTH_SHOWS, "Questo anfiteatro offre alla sua comunità sia emozionanti combattimenti tra gladiatori che spettacoli di attori locali. Lo sviluppo locale ha consentito ai tuoi cittadini di espandere l'edificio, fornendo più posti a sedere per assistere agli spettacoli."}, + {TR_BUILDING_AMPHITHEATER_DESC_UPGRADED_NO_GLADIATORS, "Questo anfiteatro mette in scena spettacoli teatrali con attori locali. Attirerebbe maggior pubblico se ci fossero gladiatori a mettere in scena combattimenti dal vivo. Lo sviluppo locale ha permesso ai tuoi cittadini di espandere l'edificio, ma i gladiatori avrebbero assicurato che i posti extra fossero pieni." }, + {TR_BUILDING_AMPHITHEATER_DESC_UPGRADED_NO_ACTORS, "Questo anfiteatro ospita combattimenti di gladiatori per il divertimento della comunità locale, ma mancano gli spettacoli teatrali. Lo sviluppo locale ha permesso ai cittadini di espandere l’edificio, ma gli attori avrebbero assicurato che i posti a sedere extra fossero pieni." }, + {TR_BUILDING_AMPHITHEATER_DESC_UPGRADED_NO_SHOWS, "In questo anfiteatro non ha mai in programma spettacoli. Ha bisogno di attori e gladiatori che forniscano intrattenimento. Lo sviluppo locale ha consentito ai tuoi cittadini di espandere l'edificio, ma senza spettacoli i posti a sedere extra rimarranno vuoti." }, + {TR_BUILDING_ARENA_DESC_UPGRADED_BOTH_SHOWS, "Questa arena ospita gladiatori e combattimenti con i leoni, per la gioia del pubblico. Lo sviluppo locale ha consentito ai tuoi cittadini di espandere l'edificio, fornendo più posti a sedere per assistere agli spettacoli." }, + {TR_BUILDING_ARENA_DESC_UPGRADED_NO_GLADIATORS, "In quest'arena si possono ammirare leoni affamati in cerca di prede, ma la mancanza di gladiatori rende gli spettacoli brevi. Lo sviluppo locale ha permesso ai tuoi cittadini di espandere l'edificio, ma i gladiatori avrebbero assicurato che i posti a sedere extra fossero pieni." }, + {TR_BUILDING_ARENA_DESC_UPGRADED_NO_LIONS, "Questa arena ospita regolarmente spettacoli di gladiatori per intrattenere la folla, ma gli la presenza aggiuntiva di leoni migliorerebbero lo spettacolo. Lo sviluppo locale ha permesso ai tuoi cittadini di espandere l'edificio, ma i leoni avrebbero assicurato che i posti a sedere extra fossero pieni." }, + {TR_BUILDING_ARENA_DESC_UPGRADED_NO_SHOWS, "Questa arena non ospita né leoni né gladiatori e offre poco intrattenimento. Lo sviluppo locale ha consentito ai tuoi cittadini di espandere l'edificio, ma senza spettacoli i posti a sedere extra rimarranno vuoti." }, + {TR_CHEAT_CASTED_CURSE, "Lancia una maledizione"}, + {TR_CHEAT_BUILDINGS_INVINCIBLE, "Le costruzioni non crollano"}, + {TR_CHEAT_CLIMATE_CHANGE, "Cambiamento climatico in azione" }, + {TR_CHEAT_EDITOR_WARNING_TITLE, "Attenzione"}, + {TR_CHEAT_EDITOR_WARNING_TEXT, "Usare l'editor di mappe in modalità città può corrompere il salvataggio o causare un crash del gioco.\n\nProcedere a proprio rischio e pericolo e assicurarsi di avere una copia di sicurezza del salvataggio corrente."}, + {TR_MAIN_MENU_NEW_CAMPAIGN, "Inizia nuova campagna"}, + {TR_WINDOW_SELECT_CAMPAIGN, "Seleziona una campagna"}, + {TR_WINDOW_CAMPAIGN_AUTHOR, "Autore:"}, + {TR_WINDOW_CAMPAIGN_NO_DESC, "Nessuna descrizione"}, + {TR_WINDOW_ORIGINAL_CAMPAIGN_NAME, "Campagna Originale" }, + {TR_WINDOW_ORIGINAL_CAMPAIGN_DESC, "La campagna originale di Caesar 3 del 1998, in tutta la sua antica gloria."}, + {TR_WINDOW_INVALID_CAMPAIGN_TITLE, "File campagna invalido" }, + {TR_WINDOW_INVALID_CAMPAIGN_TEXT, "Il file di campagna selezionato non è valido.\nControlla il log augustus-log.txt nella cartella di Augustus per i dettagli."}, + {TR_WINDOW_CAMPAIGN_MISSION_FAILED_TO_LOAD_TITLE, "Impossibile aprire la missione"}, + {TR_WINDOW_CAMPAIGN_MISSION_FAILED_TO_LOAD_TEXT, "Il file della missione selezionato non può essere aperto.\nControlla il log augustus-log.txt nella cartella di Augustus per i dettagli."}, + {TR_EDITOR_CAESAR_SALARY, "Salario di Cesare"}, + {TR_CITY_MESSAGE_TEXT_CARAVANSERAI_COMPLETE, "Il Caravanserraglio è completo, e nuove oppurtunità di commercio appariranno sicuramente. Carovane da tutto il mondo hanno già annunciato di non vedere l'ora di commerciare con la tua città."}, + {TR_WINDOW_BARRACKS_PRIORITY, "Priorità reclutamento:"}, + {TR_WINDOW_BARRACKS_FORTS, "Forti"}, + {TR_WINDOW_BARRACKS_TOWERS, "Torri"}, + {TR_TOOLTIP_BARRACKS_PRIORITY_FORT, "Prioritizza addestramento dei Legionari"}, + {TR_TOOLTIP_BARRACKS_PRIORITY_JAVELIN, "Prioritizza addestramento dei Giavellottieri"}, + {TR_TOOLTIP_BARRACKS_PRIORITY_MOUNTED, "Prioritizza addestramento dei Cavalieri"}, + {TR_TOOLTIP_BARRACKS_PRIORITY_AUXINF, "Prioritizza addestramento degli Spadaccini"}, + {TR_TOOLTIP_BARRACKS_PRIORITY_AUXARCH, "Prioritizza addestramento degli Arcieri"}, + {TR_TOOLTIP_BARRACKS_PRIORITY_TOWER, "Prioritizza addestramento delle Sentinelle"}, + {TR_TOOLTIP_BARRACKS_PRIORITY_WATCHTOWER, "Prioritizza addestramento delle Guardie alle torri"}, + {TR_TOOLTIP_BUTTON_REJECT_DELIVERY, "Ferma le consegne delle armerie qui"}, + {TR_TOOLTIP_BUTTON_ACCEPT_DELIVERY, "Permetti le consegne delle armerie qui"}, + {TR_CONFIG_SHOW_DESIRABILITY_RANGE, "Mostra la desiderabilità quando costruisci un Ninfeo o un Mausoleo"}, + {TR_BUILDING_FORT_ARCHERS, "Ausiliari - Arcieri"}, + {TR_WINDOW_ADVISOR_MILITARY_ARCHER, "Arcieri"}, + {TR_TOOLTIP_BUTTON_ACCEPT_MARKET_LADIES, "Permetti alle mercanti di passare di qui"}, + {TR_TOOLTIP_BUTTON_REJECT_MARKET_LADIES, "Impedisci alle mercanti di passare di qui"}, + {TR_TOOLTIP_BUTTON_ACCEPT_TRADE_CARAVAN, "Permetti alle carovane di passare di qui"}, + {TR_TOOLTIP_BUTTON_REJECT_TRADE_CARAVAN, "Impedisci alle carovane di passare di qui"}, + {TR_TOOLTIP_BUTTON_ACCEPT_TRADE_SHIPS, "Permetti alle navi attraccate di passare di qui"}, + {TR_TOOLTIP_BUTTON_REJECT_TRADE_SHIPS, "Impedisci alle navi attraccate di passare di qui"}, + {TR_TOOLTIP_BUTTON_ACCEPT_QUARTERMASTER, "Permetti ai quartiermastri to get food here"}, + {TR_TOOLTIP_BUTTON_REJECT_QUARTERMASTER, "Impedisci ai quartiermastri to get food here"}, + {TR_TOOLTIP_BUTTON_ACCEPT_WORKERS, "Ripristina la consegna di risorse alle officine o ai granai"}, + {TR_TOOLTIP_BUTTON_REJECT_WORKERS, "Ferma la consegna di risorse alle officine o ai granai"}, + {TR_TOOLTIP_BUTTON_ACCEPT_BARKEEP, "Permetti ai tavernieri di passare di qui"}, + {TR_TOOLTIP_BUTTON_REJECT_BARKEEP, "Impedisci ai tavernieri di passare di qui"}, + {TR_TOOLTIP_BUTTON_ACCEPT_CARAVANSERAI, "Permetti al Caravanserraglio di passare di qui"}, + {TR_TOOLTIP_BUTTON_REJECT_CARAVANSERAI, "Impedisci al Caravanserraglio di passare di qui"}, + {TR_TOOLTIP_BUTTON_ACCEPT_LIGHTHOUSE, "Permetti al custode del Faro di passare di qui"}, + {TR_TOOLTIP_BUTTON_REJECT_LIGHTHOUSE, "Impedisci al custode del Faro di passare di qui"}, + {TR_TOOLTIP_BUTTON_ACCEPT_ARMOURY, "Permetti alle armerie di passare di qui"}, + {TR_TOOLTIP_BUTTON_REJECT_ARMOURY, "Impedisci alle armerie di passare di qui"}, + {TR_TOOLTIP_BUTTON_ACCEPT_WORKCAMP, "Permetti ai braccianti di passare di qui"}, + {TR_TOOLTIP_BUTTON_REJECT_WORKCAMP, "Impedisci ai braccianti di passare di qui"}, + {TR_BUILDING_FORT_LEGIONARIES, "Legionari" }, + {TR_WINDOW_ADVISOR_LEGIONARIES, "Legionari" }, + {TR_BUILDING_FORT_MOUNTED, "Ausiliari - Cavalieri" }, + {TR_WINDOW_ADVISOR_MOUNTED, "Cavalieri" }, + {TR_BUILDING_FORT_JAVELIN, "Ausiliari - Giavellottieri" }, + {TR_WINDOW_ADVISOR_JAVELIN, "Giavellottieri" }, + {TR_WARNING_NO_ARMOURY, "Costruisci un'armeria per consegnare armi alle scuderie" }, +}; void translation_italian(const translation_string **strings, int *num_strings) { diff --git a/src/translation/russian.c b/src/translation/russian.c index ba18eae8a6..4983036374 100644 --- a/src/translation/russian.c +++ b/src/translation/russian.c @@ -373,7 +373,7 @@ static translation_string all_strings[] = { {TR_MARKET_SPECIAL_ORDERS_HEADER, "Товары для торговли" }, {TR_DOCK_SPECIAL_ORDERS_HEADER, "Указания доку"}, {TR_TEMPLE_SPECIAL_ORDERS_HEADER, "Указания храму"}, - {TR_TAVERN_SPECIAL_ORDERS_HEADER, "Указания кабаку"}, + {TR_TAVERN_SPECIAL_ORDERS_HEADER, "Указания таверне"}, {TR_WARNING_NO_MESS_HALL, "Сначала вы должны построить пост снабжения, чтобы кормить своих солдат." }, {TR_WARNING_MAX_GRAND_TEMPLES, "Можно построить только два великих храма." }, {TR_CITY_MESSAGE_TITLE_GRAND_TEMPLE_COMPLETE, "Великий храм возведен" }, @@ -483,21 +483,21 @@ static translation_string all_strings[] = { {TR_TOOLTIP_OVERLAY_EMPLOYMENT_MOTHBALL, " сотрудников нужно в этом здании (выкл.)" }, {TR_MAP_EDITOR_OPTIONS, "Настройки сценария" }, {TR_BUTTON_GO_TO_SITE, "Перейти к локации" }, - {TR_BUILDING_TAVERN, "Кабак" }, + {TR_BUILDING_TAVERN, "Таверна" }, {TR_BUILDING_GRAND_GARDEN, "Великий сад" }, - {TR_BUILDING_TAVERN_DESC_1, "В этом кабаке нет рабочих, и он не может быть открыт для посетителей." }, - {TR_BUILDING_TAVERN_DESC_2, "В этом кабаке нету вина, и он не может быть открыт для посетителей." }, - {TR_BUILDING_TAVERN_DESC_3, "В кабаке можно развлекаться до тех пор, пока не перестанет поступать вино. Поставка мяса или рыбы повышает привлекательность кабака." }, - {TR_BUILDING_TAVERN_DESC_4, "Обилие вина и запах жареной еды привлекают в этот кабак радостную толпу для азартных игр, музыки и веселья." }, + {TR_BUILDING_TAVERN_DESC_1, "В этой таверне нет рабочих, и она не может быть открыта для посетителей." }, + {TR_BUILDING_TAVERN_DESC_2, "В этой таверне нет вина, и она не может быть открыта для посетителей." }, + {TR_BUILDING_TAVERN_DESC_3, "В таверне можно развлекаться до тех пор, пока не перестанет поступать вино. Поставка мяса или рыбы повышает привлекательность таверны." }, + {TR_BUILDING_TAVERN_DESC_4, "Обилие вина и запах жареной еды привлекают в эту таверну радостную толпу для азартных игр, музыки и веселья." }, {TR_FIGURE_TYPE_BARKEEP, "Шинкарница" }, - {TR_FIGURE_TYPE_BARKEEP_SUPPLIER, "Поставщик кабака" }, - {TR_OVERLAY_TAVERN, "Кабаки" }, - {TR_TOOLTIP_OVERLAY_TAVERN_1, "Этот дом не имеет доступа к кабаку, или в ближнем кабаке закончилось вино." }, - {TR_TOOLTIP_OVERLAY_TAVERN_2, "Ни одна шинкарница не проходила мимо долгое время. Скоро этот дом потеряет доступ к кабаку." }, - {TR_TOOLTIP_OVERLAY_TAVERN_3, "Мимо этого дома проходила шинкарница из кабака с вином." }, - {TR_TOOLTIP_OVERLAY_TAVERN_4, "Мимо этого дома проходила шинкарница из кабака с вином и мясом или рыбой." }, - {TR_TOOLTIP_OVERLAY_TAVERN_5, "Мимо этого дома недавно проходила шинкарница из кабака с вином" }, - {TR_TOOLTIP_OVERLAY_TAVERN_6, "Мимо этого дома недавно проходила шинкарница из кабака с вином и мясом или рыбой. Веселье начинается!" }, + {TR_FIGURE_TYPE_BARKEEP_SUPPLIER, "Поставщик таверны" }, + {TR_OVERLAY_TAVERN, "Таверны" }, + {TR_TOOLTIP_OVERLAY_TAVERN_1, "Этот дом не имеет доступа к таверне, или в ближайшей таверне закончилось вино." }, + {TR_TOOLTIP_OVERLAY_TAVERN_2, "Ни одна шинкарница не проходила мимо долгое время. Скоро этот дом потеряет доступ к таверне." }, + {TR_TOOLTIP_OVERLAY_TAVERN_3, "Мимо этого дома проходила шинкарница из таверны с вином." }, + {TR_TOOLTIP_OVERLAY_TAVERN_4, "Мимо этого дома проходила шинкарница из таверны с вином и мясом или рыбой." }, + {TR_TOOLTIP_OVERLAY_TAVERN_5, "Мимо этого дома недавно проходила шинкарница из таверны с вином" }, + {TR_TOOLTIP_OVERLAY_TAVERN_6, "Мимо этого дома недавно проходила шинкарница из таверны с вином и мясом или рыбой. Веселье начинается!" }, {TR_BUILDING_WINDOW_HOUSE_SENTIMENT_1, "Весь город ненавидит вас."}, {TR_BUILDING_WINDOW_HOUSE_SENTIMENT_2, "Жители очень сердиты на вас." }, {TR_BUILDING_WINDOW_HOUSE_SENTIMENT_3, "Жители сердиты на вас." }, @@ -519,8 +519,8 @@ static translation_string all_strings[] = { {TR_BUILDING_WINDOW_HOUSE_SUGGEST_DESIRABILITY, "Жители хотят больше привлекательности в районе." }, {TR_BUILDING_WINDOW_HOUSE_RECENT_EVENT_POSITIVE, "Настроение жителей поднялось от недавнего события." }, {TR_BUILDING_WINDOW_HOUSE_RECENT_EVENT_NEGATIVE, "Настроение жителей понизилось от недавнего события." }, - {TR_WINDOW_ADVISOR_ENTERTAINMENT_TAVERN_COVERAGE, "кабак" }, - {TR_WINDOW_ADVISOR_ENTERTAINMENT_TAVERN_COVERAGE_PLURAL, "кабаки" }, + {TR_WINDOW_ADVISOR_ENTERTAINMENT_TAVERN_COVERAGE, "таверна" }, + {TR_WINDOW_ADVISOR_ENTERTAINMENT_TAVERN_COVERAGE_PLURAL, "таверны" }, {TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_HEADER, "Игры" }, {TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_DESC, "Спонсируйте великие игры в Колизее или на Ипподроме за счет личных сбережений." }, {TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_BUTTON, "Провести игры" }, @@ -685,9 +685,9 @@ static translation_string all_strings[] = { {TR_CITY_WARNING_THEFT, "Были украдены средства из форума или сената" }, {TR_CITY_MESSAGE_TITLE_LOOTING, "Мародерство в городе"}, {TR_CITY_MESSAGE_TEXT_LOOTING, "Разгневанные граждане разграбили склад или амбар и украли товары. Плохое настроение делает такие инциденты более вероятными."}, - {TR_SIDEBAR_EXTRA_INVASIONS, "Вторжения " }, + {TR_SIDEBAR_EXTRA_INVASIONS, "Вторжения" }, {TR_SIDEBAR_EXTRA_INVASION_UNDERWAY, "Вторжение началось" }, - {TR_SIDEBAR_EXTRA_NO_INVASIONS, "Нету " }, + {TR_SIDEBAR_EXTRA_NO_INVASIONS, "Нет" }, {TR_SIDEBAR_EXTRA_INVASION_IMMINENT, "Неминуемое" }, {TR_SIDEBAR_EXTRA_ENEMIES_CLOSING, "Приближаются" }, {TR_SIDEBAR_EXTRA_ENEMIES_DISTANT, "Далеко" }, @@ -873,6 +873,8 @@ static translation_string all_strings[] = { {TR_BUILDING_ACADEMY_UPGRADE_DESC, "Эта академия работает. Местное развитие позволило вашим горожанам расширить здание, предоставив больше места для речей и исследований."}, {TR_BUILDING_PALISADE_GATE, "Частокольные ворота"}, {TR_BUILDING_PALISADE_GATE_DESC, "Эти узкие деревянные ворота контролируют движение людей внутрь и наружу оборонительных сооружений вашего города."}, + {TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TITLE, "Файл не существует"}, + {TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TEXT, "Выбранный файл не существует.\nПожалуйста, выберите другой файл."}, {TR_SAVE_DIALOG_INVALID_FILE, "Недействительный файл"}, {TR_SAVE_DIALOG_INVALID_FILE_DESC, "Сохранение, которое вы пытаетесь загрузить, недействительно.\n\nВозможно, сохранение было повреждено из-за глюка.\n\nЕсли вы уверены, что это должно быть корректное сохранение, сообщите об ошибке по адресу:\n\nhttps://github.com/Keriew/augustus/issues/new\n\nПожалуйста, прикрепите сохранение."}, {TR_SAVE_DIALOG_INCOMPATIBLE_VERSION, "Несовместимая версия"}, @@ -958,7 +960,7 @@ static translation_string all_strings[] = { {TR_BUILDING_CONCRETE_MAKER_HALF_EMPLOYEES, "В этой мастерской не хватает работников. На производство бетона уходит больше времени, чем должно быть."}, {TR_BUILDING_CONCRETE_MAKER_SOME_EMPLOYEES, "В этой мастерской работают очень мало людей. В результате производство бетона идет медленно."}, {TR_BUILDING_CONCRETE_MAKER_FEW_EMPLOYEES, "Поскольку рабочих здесь почти нет, производство почти остановилось. В ближайший год здесь будет произведено мало бетона."}, - {TR_BUILDING_CONCRETE_MAKER_NO_RESOURCES, "Эта мастерская нуждается в доступе к резервуару, а также к песку, доставляемом к нему со склада или песчаного карьера, для замешивания бетона."}, + {TR_BUILDING_CONCRETE_MAKER_NO_RESOURCES, "Эта мастерская нуждается в доступе к воде из резервуара, фонтана или колодца, а также к песку, доставляемом к нему со склада или песчаного карьера, для замешивания бетона."}, {TR_BUILDING_CONCRETE_MAKER_STORED_SAND, "Накопленный песок,"}, {TR_BUILDING_CONCRETE_MAKER_NO_TARGETS, "Нет зданий, требующих бетона. Производство остановлено."}, {TR_BUILDING_CONCRETE_MAKER_IMPROVE_WATER_ACCESS, "Эта мастерская имеет доступ только к колодцу или фонтану. Производительность можно было бы повысить, если бы имелся прямой доступ к резервуару."}, @@ -1048,7 +1050,7 @@ static translation_string all_strings[] = { {TR_EDITOR_SCENARIO_EVENTS_ACTIONS, "действия" }, {TR_EDITOR_UNABLE_TO_LOAD_EVENTS_TITLE, "Невозможно загрузить события сценария."}, {TR_EDITOR_CHECK_LOG_MESSAGE, "Пожалуйста, проверьте файл augustus-log.txt в вашем каталоге Augustus для получения подробной информации."}, - {TR_EDITOR_UNABLE_TO_SAVE_EVENTS_TITLE, "Unable to save scenario events"}, + {TR_EDITOR_UNABLE_TO_SAVE_EVENTS_TITLE, "Невозможно сохранить события сценария"}, {TR_EDITOR_IMPORT_LINE, "Строка: "}, {TR_EDITOR_SCENARIO_EVENT_ID, "ИД: "}, {TR_EDITOR_SCENARIO_EVENT_REPEAT_MIN_MONTHS, "Мин. кол. месяцев до повторения: "}, @@ -1369,9 +1371,9 @@ static translation_string all_strings[] = { {TR_FIGURE_INFO_DEPOT_TO, " на " }, {TR_BUILDING_DEPOT_NO_EMPLOYEES, "Зданию очень сильно не хватает рабочих. В пустых телегах спят кошки, и волы становятся подозрительными." }, {TR_BUILDING_DEPOT_FEW_EMPLOYEES, "Зданию очень не хватает рабочих. Скорость работы будет значительно снижена." }, - {TR_BUILDING_DEPOT_SOME_EMPLOYEES, "В здание наполовину работников. Оно будет работать на пониженной скорости." }, + {TR_BUILDING_DEPOT_SOME_EMPLOYEES, "В здании половина работников. Оно будет работать на пониженной скорости." }, {TR_BUILDING_DEPOT_HALF_EMPLOYEES, "Зданию сильно не хватает рабочих. Оно будет работать неоптимально." }, - {TR_BUILDING_DEPOT_MANY_EMPLOYEES, "Building has some workers. Will have some inefficiency." }, + {TR_BUILDING_DEPOT_MANY_EMPLOYEES, "В здании нехватка рабочих. Эффективность работы снижена." }, {TR_BUILDING_INFO_MOTHBALL_WARNING, "Это здание выключено." }, {TR_BUILDING_INFO_CARTLOAD, "тележка." }, {TR_BUILDING_INFO_CARTLOADS, "тележек." }, @@ -1388,18 +1390,18 @@ static translation_string all_strings[] = { {TR_WINDOW_ADVISOR_RELIGION_ALTARS_HEADER, "святил."}, {TR_REPLAY_MAP_NOT_FOUND_TITLE, "Невозможно повторить карту"}, {TR_REPLAY_MAP_NOT_FOUND_MESSAGE, "Оригинальный файл карты для этой сохраненной игры не был найден.\nВам нужен следующий файл с расширением .map или .mapx:"}, - {TR_TOOLTIP_BUTTON_ROADBLOCK_ORDER_ACCEPT_ALL, "Принимать все товары"}, - {TR_TOOLTIP_BUTTON_ROADBLOCK_ORDER_REJECT_ALL, "Отказывать все товары"}, - {TR_TOOLTIP_BUTTON_STORAGE_ORDER_ACCEPT_ALL, "Принимать все goods" }, - {TR_TOOLTIP_BUTTON_STORAGE_ORDER_REJECT_ALL, "Refuse all goods" }, + {TR_TOOLTIP_BUTTON_ROADBLOCK_ORDER_ACCEPT_ALL, "Разрешить всем пешеходам"}, + {TR_TOOLTIP_BUTTON_ROADBLOCK_ORDER_REJECT_ALL, "Запретить всем пешеходам"}, + {TR_TOOLTIP_BUTTON_STORAGE_ORDER_ACCEPT_ALL, "Принимать все товары" }, + {TR_TOOLTIP_BUTTON_STORAGE_ORDER_REJECT_ALL, "Запретить все товары" }, {TR_FIGURE_TYPE_BEGGAR, "Нищий"}, {TR_BUILDING_ARMOURY, "Оружейная"}, {TR_BUILDING_ARMOURY_NO_EMPLOYEES, "Без доступа к сотрудникам арсенал не сможет поставлять оружие нашим солдатам. Пусть Марс защитит вас, потому что безоружные легионы не смогут этого сделать."}, {TR_BUILDING_ARMOURY_SOME_EMPLOYEES, "Поскольку оружейные склады работают лишь частично, полное вооружение легионов займет значительное время. Остается надеяться, что враги Рима не будут торопиться."}, {TR_BUILDING_ARMOURY_MANY_EMPLOYEES, "Оружейная способна поставлять оружие солдатам, но из-за нехватки работников его периодически не хватает."}, {TR_BUILDING_ARMOURY_DESC, "Оружейная следит за тем, чтобы наши солдаты быстро и эффективно снабжались оружием. Варвары не могут сравниться с римской логистикой."}, - {TR_BUILDING_TAVERN_DESC_UPGRADED_WINE_NO_FOOD, "Этот кабак развлекает ваших граждан до тех пор, пока в нем есть вино. Поставки мяса или рыбы повысят ее привлекательность. Местное развитие позволило вашим жителям расширить здание, предоставив больше места для посетителей."}, - {TR_BUILDING_TAVERN_DESC_UPGRADED_WINE_AND_FOOD, "В этом кабаке много вина, а запах жареного мяса привлекает оживленную публику для азартных игр, музыки и веселья. Местное развитие позволило вашим жителям расширить здание, предоставив больше места для посетителей."}, + {TR_BUILDING_TAVERN_DESC_UPGRADED_WINE_NO_FOOD, "Эта таверна развлекает ваших граждан до тех пор, пока в ней есть вино. Поставки мяса или рыбы повысят ее привлекательность. Местное развитие позволило вашим жителям расширить здание, предоставив больше места для посетителей."}, + {TR_BUILDING_TAVERN_DESC_UPGRADED_WINE_AND_FOOD, "В этой таверне много вина, а запах жареного мяса привлекает оживленную публику для азартных игр, музыки и веселья. Местное развитие позволило вашим жителям расширить здание, предоставив больше места для посетителей."}, {TR_BUILDING_AMPHITHEATER_DESC_UPGRADED_BOTH_SHOWS, "Этот амфитеатр предлагает своим жителям как захватывающие гладиаторские бои, так и спектакли с участием местных актеров. Местное развитие позволило горожанам расширить здание, предоставив больше мест для просмотра представлений."}, {TR_BUILDING_AMPHITHEATER_DESC_UPGRADED_NO_GLADIATORS, "В этом амфитеатре ставят спектакли с участием местных актеров. Зрители могли бы получить больше удовольствия, если бы в нем были гладиаторы для проведения живых боев. Местное развитие позволило вашим гражданам расширить здание, но гладиаторы обеспечат заполненность дополнительных мест."}, {TR_BUILDING_AMPHITHEATER_DESC_UPGRADED_NO_ACTORS, "В этом амфитеатре проводятся гладиаторские бои на потеху местной публике, но между ними не хватает драматических постановок. Местное развитие позволило вашим жителям расширить здание, но актеры должны следить за тем, чтобы дополнительные места оставались полными."}, @@ -1442,8 +1444,8 @@ static translation_string all_strings[] = { {TR_TOOLTIP_BUTTON_REJECT_WORKERS, "Отправлять ресурсы на переработку и в амбары"}, {TR_TOOLTIP_BUTTON_ACCEPT_QUARTERMASTER, "Разрешить доступ Квартирмейстерам к еде"}, {TR_TOOLTIP_BUTTON_REJECT_QUARTERMASTER, "Запретить доступ Квартирмейстерам к еде"}, - {TR_TOOLTIP_BUTTON_ACCEPT_BARKEEP, "Разрешить кабакам брать отсюда"}, - {TR_TOOLTIP_BUTTON_REJECT_BARKEEP, "Запретить кабакам брать отсюда"}, + {TR_TOOLTIP_BUTTON_ACCEPT_BARKEEP, "Разрешить тавернам брать отсюда"}, + {TR_TOOLTIP_BUTTON_REJECT_BARKEEP, "Запретить тавернам брать отсюда"}, {TR_TOOLTIP_BUTTON_ACCEPT_CARAVANSERAI, "Разрешить караван-сараю брать отсюда"}, {TR_TOOLTIP_BUTTON_REJECT_CARAVANSERAI, "Запретить караван-сараю брать отсюда"}, {TR_TOOLTIP_BUTTON_ACCEPT_LIGHTHOUSE, "Разрешить маяку брать отсюда"}, @@ -1462,6 +1464,25 @@ static translation_string all_strings[] = { {TR_WINDOW_ADVISOR_MILITARY_INFANTRY, "пехотинцев"}, {TR_BUILDING_FORT_ARCHERS, "Ауксиларии - Лучники"}, {TR_WINDOW_ADVISOR_MILITARY_ARCHER, "лучников"}, + {TR_CONFIG_USER_PATH_DEFAULT, "По умолчанию (путь установки Цезаря III, без подкаталогов)" }, + {TR_CONFIG_USER_PATH_WITH_SUBDIRECTORIES, "Путь установки Цезаря III, используя подкаталоги" }, + {TR_CONFIG_USER_PATH_RECOMMENDED, "Рекомендовано ("}, + {TR_CONFIG_USER_PATH_CUSTOM, "Установите пользовательский каталог..."}, + {TR_USER_DIRECTORIES_NOT_SET_UP_TITLE, "Пользовательские каталоги не настроены"}, + {TR_USER_DIRECTORIES_NOT_SET_UP_TEXT, "Вы не настроили каталог пользователя, в котором будут храниться сохранения, сценарии и карты.\n" \ + "Хотите ли вы сделать это сейчас?"}, + {TR_USER_DIRECTORIES_CANCELLED_TITLE, "Выбор каталога отменен"}, + {TR_USER_DIRECTORIES_CANCELLED_TEXT, "Вы решили не задавать каталог пользователя. Будет использоваться каталог установки Ц3.\n" + "Вы можете изменить настройки позже в окне конфигурации."}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TITLE, "Каталог пользователя недоступен для записи"}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT, "Выбранный каталог пользователя недоступен для записи.\n\nПожалуйста, выберите другой каталог пользователя."}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT_DETAILED, "Выбранный каталог пользователя недоступен для записи.\n\nВы не сможете сохранить свои игры.\nПожалуйста, выберите другой каталог пользователя в окне опций главного меню."}, + {TR_USER_DIRECTORIES_WINDOW_TITLE, "Установить каталог пользователя"}, + {TR_USER_DIRETORIES_WINDOW_USER_PATH, "Каталог пользователя:" }, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_TITLE, "Путь пользователя изменен"}, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_TEXT, "Путь пользователя был успешно изменен.\nНе хотите ли вы скопировать свои файлы?"}, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_OVERWRITE, "Перезаписать существующие файлы"}, + {TR_FIGURE_TYPE_ARMORY_CARTPUSHER, "Разносчик оружия"}, }; diff --git a/src/translation/simplified_chinese.c b/src/translation/simplified_chinese.c index 2798c66ff5..90e164fdfd 100644 --- a/src/translation/simplified_chinese.c +++ b/src/translation/simplified_chinese.c @@ -843,4 +843,4 @@ void translation_simplified_chinese(const translation_string **strings, int *num { *strings = all_strings; *num_strings = sizeof(all_strings) / sizeof(translation_string); -} \ No newline at end of file +} diff --git a/src/translation/spanish.c b/src/translation/spanish.c index fa68f0d1f6..1e15ac5ed5 100644 --- a/src/translation/spanish.c +++ b/src/translation/spanish.c @@ -109,7 +109,7 @@ static translation_string all_strings[] = { {TR_CONFIG_SHOW_MAX_POSSIBLE_PROSPERITY, "Mostrar puntuación de prosperidad máxima obtenible"}, {TR_CONFIG_AUTO_KILL_ANIMALS, "Ciudadanos pueden matar automáticamente animales inofensivos"}, {TR_CONFIG_SHOW_ROAMING_PATH, "Previsualizar los recorridos de los caminantes errantes"}, - {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Dibuja sobras de nubes"}, + {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Dibuja sombras de nubes"}, {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Preguntar el confirmar al sobreescribir un archivo"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Puertas no militar permite por defecto a los caminantes "}, {TR_HOTKEY_TITLE, "Configuración de atajos de teclado de Augustus"}, @@ -395,7 +395,7 @@ static translation_string all_strings[] = { {TR_CITY_MESSAGE_TEXT_PANTHEON_FESTIVAL_MARS, "Ciudadanos se reúnen en las afueras de la ciudad para la celebración de Equirria, buscando el favor de Marte. El aire se llena con el tronar de los cascos y el crujir de los carros mientras los fieles compiten en honor a su dios."}, {TR_CITY_MESSAGE_TEXT_PANTHEON_FESTIVAL_VENUS, "Los fieles se reúnen para la celebración de Veneralia, día consagrado a Venus. Tus ciudadanos ruegan por buena fortuna en asuntos del corazón."}, {TR_TOOLTIP_BUTTON_DELETE_READ_MESSAGES, "Borrar mensajes leídos"}, - {TR_TOOLTIP_BUTTON_MOTHBALL_ON, "Suspender este edificio"}, + {TR_TOOLTIP_BUTTON_MOTHBALL_ON, "Clausurar este edificio"}, {TR_TOOLTIP_BUTTON_MOTHBALL_OFF, "Reactivar este edificio"}, {TR_TOOLTIP_BUTTON_STOCKPILING_ON, "Priorizar la acumulación en un almacén"}, {TR_TOOLTIP_BUTTON_STOCKPILING_OFF, "Desactivar la acumulación"}, @@ -740,7 +740,7 @@ static translation_string all_strings[] = { {TR_WINDOW_GAMES_NO_WATER_ACCESS, "El Coliseo no tiene acceso a una red de agua proveniente de un depósito." }, {TR_HOTKEY_COPY_SETTINGS, "Copiar la configuración del edificio" }, {TR_HOTKEY_PASTE_SETTINGS, "Pegar la configuración del edificio" }, - {TR_HOTKEY_MOTHBALL_TOGGLE, "Suspender/Reactivar edificio" }, + {TR_HOTKEY_MOTHBALL_TOGGLE, "Clausurar/Reactivar edificio" }, {TR_HOTKEY_SPECIAL_ORDERS, "Mostrar órdenes especiales del edificio" }, {TR_WINDOW_ADVISOR_RELIGION_LARARIUMS, "Lararios en la ciudad" }, {TR_WINDOW_RACE_BET_BUTTON, "Apostar por un caballo" }, @@ -779,8 +779,8 @@ static translation_string all_strings[] = { {TR_TOOLTIP_OVERLAY_PROBLEMS_NO_LABOR, "No hay trabajo" }, {TR_WINDOW_BUILDING_DISTRIBUTION_GRANARY_CART_PUSHER_GETTING, "El carretero se dirige a buscar comida a otro granero."}, {TR_WINDOW_BUILDING_DISTRIBUTION_CART_PUSHER_RETURNING_WITH, "El carretero regresa con una entrega." }, - {TR_BUTTON_YEARLY_AUTOSAVE_OFF, "Auto guardado anual OFF"}, - {TR_BUTTON_YEARLY_AUTOSAVE_ON, "Auto guardado anual ON" }, + {TR_BUTTON_YEARLY_AUTOSAVE_OFF, "Guardado automático anual DESACTIVADO"}, + {TR_BUTTON_YEARLY_AUTOSAVE_ON, "Guardado automático anual ACTIVADO" }, {TR_BUILDING_DOCK_PLAGUE_DESC, "La peste fue traída aquí por un barco mercante. Este muelle está en cuarentena mientras un médico o cirujano descontamina la zona."}, {TR_BUILDING_GRANARY_PLAGUE_DESC, "La peste fue traída aquí por un trabajador contaminado. Este granero está en cuarentena mientras un médico o cirujano descontamina la zona."}, {TR_BUILDING_GRANARY_NO_FOOD, "No hay comida almacenada en este granero."}, @@ -864,6 +864,8 @@ static translation_string all_strings[] = { {TR_BUILDING_ACADEMY_UPGRADE_DESC, "Esta academia está operativa. El desarrollo local permitió a sus ciudadanos ampliar el edificio, dotándolo de más salas para catedras e investigación."}, {TR_BUILDING_PALISADE_GATE, "Puerta empalizada"}, {TR_BUILDING_PALISADE_GATE_DESC, "Esta estrecha puerta de madera controla el movimiento de la gente dentro y fuera de las defensas de tu ciudad."}, + + {TR_SAVE_DIALOG_INVALID_FILE, "Archivo inválido"}, {TR_SAVE_DIALOG_INVALID_FILE_DESC, "La partida guardada que estás intentando cargar no es válido.\n\nLa partida guardada puede haberse corrompido debido a un error.\n\nSi estás seguro de que es un juego guardado válido, por favor, informa del error a:\n\nhttps://github.com/Keriew/augustus/issues/new\n\nPor favor, adjunta también el juego guardado."}, {TR_SAVE_DIALOG_INCOMPATIBLE_VERSION, "Versión incompatible"}, @@ -1442,26 +1444,26 @@ static translation_string all_strings[] = { {TR_TOOLTIP_BUTTON_ACCEPT_DELIVERY, "Permitir que las armerías entreguen armas aquí."}, {TR_BUILDING_FORT_ARCHERS, "Auxiliares - Arqueros"}, {TR_WINDOW_ADVISOR_MILITARY_ARCHER, "Arqueros"}, - {TR_TOOLTIP_BUTTON_ACCEPT_MARKET_LADIES, "Permitir al mercado obtener bienes desde aquí."}, - {TR_TOOLTIP_BUTTON_REJECT_MARKET_LADIES, "No permitir al mercado obtener bienes desde aquí."}, + {TR_TOOLTIP_BUTTON_ACCEPT_MARKET_LADIES, "Permitir al mercado abastercerse desde aquí."}, + {TR_TOOLTIP_BUTTON_REJECT_MARKET_LADIES, "No permitir al mercado abastercerse desde aquí."}, {TR_TOOLTIP_BUTTON_ACCEPT_TRADE_CARAVAN, "Permitir despachar a las caravanas mercantes desde aquí."}, {TR_TOOLTIP_BUTTON_REJECT_TRADE_CARAVAN, "No permitir despachar a las caravanas mercantes desde aquí."}, {TR_TOOLTIP_BUTTON_ACCEPT_TRADE_SHIPS, "Permitir despachar a los buques mercantes atracados desde aquí"}, {TR_TOOLTIP_BUTTON_REJECT_TRADE_SHIPS, "No permitir despachar a los buques mercantes atracados desde aquí"}, {TR_TOOLTIP_BUTTON_ACCEPT_WORKERS, "Reanudar distribución de recursos a talleres o graneros"}, {TR_TOOLTIP_BUTTON_REJECT_WORKERS, "Detener distribución de recursos a talleres o graneros"}, - {TR_TOOLTIP_BUTTON_ACCEPT_QUARTERMASTER, "Permitir a los intendentes militares obtener alimentos desde aquí"}, - {TR_TOOLTIP_BUTTON_REJECT_QUARTERMASTER, "No permitir a los intendentes militares obtener alimentos desde aquí"}, - {TR_TOOLTIP_BUTTON_ACCEPT_BARKEEP, "Permitir a las tabernas que obtengan alimentos desde aquí."}, - {TR_TOOLTIP_BUTTON_REJECT_BARKEEP, "No permitir a las tabernas que obtengan alimentos desde aquí."}, - {TR_TOOLTIP_BUTTON_ACCEPT_CARAVANSERAI, "Permitir al caravasar obtener alimentos desde aquí."}, - {TR_TOOLTIP_BUTTON_REJECT_CARAVANSERAI, "No permitir al caravasar obtener alimentos desde aquí."}, - {TR_TOOLTIP_BUTTON_ACCEPT_LIGHTHOUSE, "Permitir al farero obtener madera desde aquí."}, - {TR_TOOLTIP_BUTTON_REJECT_LIGHTHOUSE, "No permitir al farero obtener madera desde aquí."}, - {TR_TOOLTIP_BUTTON_ACCEPT_ARMOURY, "Permitir a las armerías que obtengan armas desde aquí."}, - {TR_TOOLTIP_BUTTON_REJECT_ARMOURY, "No permitir a las armerías que obtengan armas desde aquí."}, - {TR_TOOLTIP_BUTTON_ACCEPT_WORKCAMP, "Permitir que los capataces obtengan recursos desde aquí."}, - {TR_TOOLTIP_BUTTON_REJECT_WORKCAMP, "No permitir que los capataces obtengan recursos desde aquí."}, + {TR_TOOLTIP_BUTTON_ACCEPT_QUARTERMASTER, "Permitir al puesto de suministros aprovisionarse desde aquí"}, + {TR_TOOLTIP_BUTTON_REJECT_QUARTERMASTER, "No permitir al puesto de suministros aprovisionarse desde aquí"}, + {TR_TOOLTIP_BUTTON_ACCEPT_BARKEEP, "Permitir a las tabernas aprovisionarse desde aquí."}, + {TR_TOOLTIP_BUTTON_REJECT_BARKEEP, "No permitir a las tabernas aprovisionarse desde aquí."}, + {TR_TOOLTIP_BUTTON_ACCEPT_CARAVANSERAI, "Permitir al caravasar aprovisionarse desde aquí."}, + {TR_TOOLTIP_BUTTON_REJECT_CARAVANSERAI, "No permitir al caravasar aprovisionarse desde aquí."}, + {TR_TOOLTIP_BUTTON_ACCEPT_LIGHTHOUSE, "Permitir al faro abastercerse desde aquí."}, + {TR_TOOLTIP_BUTTON_REJECT_LIGHTHOUSE, "No permitir al faro abastercerse desde aquí."}, + {TR_TOOLTIP_BUTTON_ACCEPT_ARMOURY, "Permitir a las armerías abastercerse desde aquí."}, + {TR_TOOLTIP_BUTTON_REJECT_ARMOURY, "No permitir a las armerías abastercerse desde aquí."}, + {TR_TOOLTIP_BUTTON_ACCEPT_WORKCAMP, "Permitir a los campamentos de trabajadores abastecerse desde aquí."}, + {TR_TOOLTIP_BUTTON_REJECT_WORKCAMP, "No permitir a los campamentos de trabajadores abastecerse desde aquí."}, {TR_BUILDING_FORT_LEGIONARIES, "Legionarios" }, {TR_WINDOW_ADVISOR_LEGIONARIES, "Legionarios" }, {TR_BUILDING_FORT_MOUNTED, "Auxiliares - Caballeria" }, @@ -1469,7 +1471,26 @@ static translation_string all_strings[] = { {TR_BUILDING_FORT_JAVELIN, "Auxiliares - Jabalineros" }, {TR_WINDOW_ADVISOR_JAVELIN, "Jabalineros" }, {TR_WARNING_NO_ARMOURY, "Construye una armería para entregar armas a los barracones" }, - + {TR_CONFIG_USER_PATH_DEFAULT, "Por defecto (ruta de instalación de Caesar III, sin subdirectorios)" }, + {TR_CONFIG_USER_PATH_WITH_SUBDIRECTORIES, "Ruta de instalación de Caesar III, utilizando subdirectorios" }, + {TR_CONFIG_USER_PATH_RECOMMENDED, "Recomendado ("}, + {TR_CONFIG_USER_PATH_CUSTOM, "Establecer directorio personalizado..."}, + {TR_USER_DIRECTORIES_NOT_SET_UP_TITLE, "Directorios personalizados del usuario no se han configurado"}, + {TR_USER_DIRECTORIES_NOT_SET_UP_TEXT, "No has configurado tu directorio de usuario, donde se almacenarán las partidas guardadas, los escenarios y los mapas.\n" \ + "¿Desea hacerlo ahora?"}, + {TR_USER_DIRECTORIES_CANCELLED_TITLE, "Selección de directorio cancelada"}, + {TR_USER_DIRECTORIES_CANCELLED_TEXT, "Ha decidido no establecer un directorio de usuario. Se utilizará el directorio de instalación de C3.\n" + "Puedes cambiar los ajustes más tarde en la ventana de configuración."}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TITLE, "Directorio de usuario no modificable"}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT, "No se puede escribir en el directorio de usuario seleccionado.\n\nSeleccione otro directorio de usuario."}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT_DETAILED, "No se puede escribir en el directorio de usuario seleccionado.\n\nNo podrás guardar tus partidas.\nSeleccione otro directorio de usuario en la ventana de opciones del menú principal."}, + {TR_USER_DIRECTORIES_WINDOW_TITLE, "Establecer directorio de usuario"}, + {TR_USER_DIRETORIES_WINDOW_USER_PATH, "Directorio de usuario:" }, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_TITLE, "Ruta de usuario modificada"}, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_TEXT, "La ruta de usuario se ha modificado correctamente.\n¿Quieres copiar tus archivos?"}, + {TR_USER_DIRECTORIES_USER_PATH_CHANGED_OVERWRITE, "Sobrescribir archivos existentes"}, + {TR_FIGURE_TYPE_ARMORY_CARTPUSHER, "Repartidor de armería"} + }; void translation_spanish(const translation_string **strings, int *num_strings) diff --git a/src/translation/translation.h b/src/translation/translation.h index 4a69628556..0a596eb5a5 100644 --- a/src/translation/translation.h +++ b/src/translation/translation.h @@ -858,6 +858,8 @@ typedef enum { TR_CITY_MESSAGE_TEXT_EMPERORS_WRATH, TR_BUILDING_PALISADE_GATE, TR_BUILDING_PALISADE_GATE_DESC, + TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TITLE, + TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TEXT, TR_SAVE_DIALOG_INVALID_FILE, TR_SAVE_DIALOG_INVALID_FILE_DESC, TR_SAVE_DIALOG_INCOMPATIBLE_VERSION, @@ -1469,6 +1471,23 @@ typedef enum { TR_BUILDING_LATRINES_MISSING_EVOLVE, TR_BUILDING_LATRINES_MISSING_DEVOLVE, TR_BUILDING_LATRINES_NO_WORKERS, + TR_CONFIG_USER_PATH_DEFAULT, + TR_CONFIG_USER_PATH_WITH_SUBDIRECTORIES, + TR_CONFIG_USER_PATH_RECOMMENDED, + TR_CONFIG_USER_PATH_CUSTOM, + TR_USER_DIRECTORIES_NOT_SET_UP_TITLE, + TR_USER_DIRECTORIES_NOT_SET_UP_TEXT, + TR_USER_DIRECTORIES_CANCELLED_TITLE, + TR_USER_DIRECTORIES_CANCELLED_TEXT, + TR_USER_DIRECTORIES_NOT_WRITEABLE_TITLE, + TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT, + TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT_DETAILED, + TR_USER_DIRECTORIES_WINDOW_TITLE, + TR_USER_DIRETORIES_WINDOW_USER_PATH, + TR_USER_DIRECTORIES_USER_PATH_CHANGED_TITLE, + TR_USER_DIRECTORIES_USER_PATH_CHANGED_TEXT, + TR_USER_DIRECTORIES_USER_PATH_CHANGED_OVERWRITE, + TR_FIGURE_TYPE_ARMORY_CARTPUSHER, TRANSLATION_MAX_KEY } translation_key; diff --git a/src/widget/city_figure.c b/src/widget/city_figure.c index 36ed073778..aff5c9051b 100644 --- a/src/widget/city_figure.c +++ b/src/widget/city_figure.c @@ -257,6 +257,7 @@ static void draw_figure(const figure *f, int x, int y, float scale, int highligh case FIGURE_NATIVE_TRADER: case FIGURE_IMMIGRANT: case FIGURE_EMIGRANT: + case FIGURE_LIGHTHOUSE_SUPPLIER: draw_figure_with_cart(f, x, y, scale); break; case FIGURE_HIPPODROME_HORSES: diff --git a/src/widget/city_overlay_entertainment.c b/src/widget/city_overlay_entertainment.c index 6eea63b2f3..ab1db9ced4 100644 --- a/src/widget/city_overlay_entertainment.c +++ b/src/widget/city_overlay_entertainment.c @@ -356,4 +356,4 @@ const city_overlay *city_overlay_for_tavern(void) 0 }; return &overlay; -} \ No newline at end of file +} diff --git a/src/widget/city_pause_menu.c b/src/widget/city_pause_menu.c index 736712727b..95e41c836d 100644 --- a/src/widget/city_pause_menu.c +++ b/src/widget/city_pause_menu.c @@ -1,11 +1,13 @@ #include "city_pause_menu.h" #include "building/construction.h" +#include "campaign/campaign.h" #include "core/lang.h" #include "game/file.h" -#include "game/undo.h" +#include "game/settings.h" #include "game/state.h" #include "game/system.h" +#include "game/undo.h" #include "graphics/generic_button.h" #include "graphics/graphics.h" #include "graphics/lang_text.h" @@ -19,12 +21,12 @@ #include "window/popup_dialog.h" #include "window/city.h" #include "window/main_menu.h" -#include "window/mission_briefing.h" +#include "window/mission_selection.h" #include "window/plain_message_dialog.h" static void button_click(int type, int param2); -static int focus_button_id; +static unsigned int focus_button_id; static generic_button buttons[] = { {192, 100, 192, 25, button_click, button_none, 1, 0}, @@ -82,7 +84,7 @@ static void replay_map_confirmed(int confirmed, int checked) if (!confirmed) { return; } - if (scenario_is_custom()) { + if (scenario_is_custom() && !campaign_is_active()) { if (!game_file_start_scenario_by_name(scenario_name())) { window_plain_message_dialog_show_with_extra(TR_REPLAY_MAP_NOT_FOUND_TITLE, TR_REPLAY_MAP_NOT_FOUND_MESSAGE, 0, scenario_name()); @@ -90,8 +92,9 @@ static void replay_map_confirmed(int confirmed, int checked) window_city_show(); } } else { + setting_set_personal_savings_for_mission(0, scenario_starting_personal_savings()); scenario_save_campaign_player_name(); - window_mission_briefing_show(); + window_mission_selection_show_again(); } } diff --git a/src/widget/city_water_ghost.c b/src/widget/city_water_ghost.c index 7f356d52d8..ad710a6323 100644 --- a/src/widget/city_water_ghost.c +++ b/src/widget/city_water_ghost.c @@ -71,4 +71,4 @@ void city_water_ghost_draw_water_structure_ranges(void) last_well_count = num_wells; last_fountain_count = num_fountains; city_view_foreach_valid_map_tile(draw_water_access); -} \ No newline at end of file +} diff --git a/src/widget/map_editor_pause_menu.c b/src/widget/map_editor_pause_menu.c index 1ac0ecc8aa..0f2ed87960 100644 --- a/src/widget/map_editor_pause_menu.c +++ b/src/widget/map_editor_pause_menu.c @@ -36,15 +36,15 @@ static void menu_file_confirm_exit(int accepted, int checked) static void button_click(int type, int param2); -static int focus_button_id; +static unsigned int focus_button_id; static generic_button buttons[] = { - {192, 100, 192, 25, button_click, button_none, 1, 0}, - {192, 140, 192, 25, button_click, button_none, 2, 0}, - {192, 180, 192, 25, button_click, button_none, 3, 0}, - {192, 220, 192, 25, button_click, button_none, 4, 0}, - {192, 260, 192, 25, button_click, button_none, 5, 0}, - {192, 300, 192, 25, button_click, button_none, 6, 0}, + {192, 100, 192, 25, button_click, button_none, 1, 0}, + {192, 140, 192, 25, button_click, button_none, 2, 0}, + {192, 180, 192, 25, button_click, button_none, 3, 0}, + {192, 220, 192, 25, button_click, button_none, 4, 0}, + {192, 260, 192, 25, button_click, button_none, 5, 0}, + {192, 300, 192, 25, button_click, button_none, 6, 0}, }; static void draw_foreground(void) @@ -53,7 +53,7 @@ static void draw_foreground(void) outer_panel_draw(160, 44, 16, 19); - for (int i = 0; i < MAX_BUTTONS; i++) { + for (unsigned int i = 0; i < MAX_BUTTONS; i++) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, focus_button_id == i + 1 ? 1 : 0); } diff --git a/src/widget/sidebar/city.c b/src/widget/sidebar/city.c index 8f5660e01f..e1a64f65d1 100644 --- a/src/widget/sidebar/city.c +++ b/src/widget/sidebar/city.c @@ -226,7 +226,7 @@ int widget_sidebar_city_handle_mouse(const mouse *m) return 0; } int handled = 0; - int button_id; + unsigned int button_id; data.focus_button_for_tooltip = 0; if (city_view_is_sidebar_collapsed()) { int x_offset = sidebar_common_get_x_offset_collapsed(); @@ -238,8 +238,7 @@ int widget_sidebar_city_handle_mouse(const mouse *m) if (button_id) { data.focus_button_for_tooltip = button_id + 19; } - } - else { + } else { if (widget_minimap_handle_mouse(m)) { return 1; } diff --git a/src/widget/sidebar/extra.c b/src/widget/sidebar/extra.c index d2fac97c39..b105c5c093 100644 --- a/src/widget/sidebar/extra.c +++ b/src/widget/sidebar/extra.c @@ -113,13 +113,13 @@ static struct { int angry; } gods; int next_invasion; - int visible_requests; - int active_requests; + unsigned int visible_requests; + unsigned int active_requests; int objectives_y_offset; int request_buttons_y_offset; - int focused_request_button_id; - int selected_request_id; - int selected_resource; + unsigned int focused_request_button_id; + unsigned int selected_request_id; + unsigned int selected_resource; request requests[MAX_REQUESTS_TO_DISPLAY]; } data; @@ -212,7 +212,7 @@ static int calculate_extra_info_height(int available_height) } if (data.info_to_display & SIDEBAR_EXTRA_DISPLAY_REQUESTS) { height += EXTRA_INFO_HEIGHT_REQUESTS_MIN; - int num_requests = count_active_requests(); + unsigned int num_requests = count_active_requests(); data.visible_requests = 1; while (data.visible_requests < num_requests) { if (height + EXTRA_INFO_HEIGHT_REQUESTS_PANEL > available_height) { @@ -325,7 +325,7 @@ static int update_extra_info(int is_background) changed |= update_extra_info_value(city_population(), &data.objectives.population.value); } if (data.info_to_display & SIDEBAR_EXTRA_DISPLAY_REQUESTS) { - int new_requests = update_extra_info_value(count_active_requests(), &data.active_requests); + int new_requests = update_extra_info_value(count_active_requests(), (int *)&data.active_requests); int troop_requests = city_request_has_troop_request(); if (troop_requests) { @@ -407,7 +407,7 @@ static int draw_request_buttons(int y_offset) y_offset += EXTRA_INFO_VERTICAL_PADDING; - for (int i = 0; i < data.visible_requests; i++) { + for (unsigned int i = 0; i < data.visible_requests; i++) { const request *r = &data.requests[i]; int base_button_y_offset = i * EXTRA_INFO_HEIGHT_REQUESTS_PANEL; @@ -634,8 +634,7 @@ static void draw_extra_info_buttons(void) image_buttons_draw(data.x_offset, data.y_offset, &play_paused_button, 1); } if (data.info_to_display & SIDEBAR_EXTRA_DISPLAY_REQUESTS && data.active_requests) { - for (int i = 0; i < data.visible_requests; i++) { - + for (unsigned int i = 0; i < data.visible_requests; i++) { button_border_draw(data.x_offset + 2, data.request_buttons_y_offset + buttons_emperor_requests[i].y, data.width - 4, buttons_emperor_requests[i].height, i == data.focused_request_button_id - 1); } @@ -656,7 +655,7 @@ int sidebar_extra_handle_mouse(const mouse *m) } if ((data.info_to_display & SIDEBAR_EXTRA_DISPLAY_REQUESTS) && generic_buttons_handle_mouse(m, data.x_offset, data.request_buttons_y_offset, - buttons_emperor_requests, data.visible_requests, &data.focused_request_button_id)) { + buttons_emperor_requests, data.visible_requests, &data.focused_request_button_id)) { return 1; } return 0; @@ -750,7 +749,7 @@ static void confirm_send_goods(int accepted, int checked) static void button_handle_request(int index, int param2) { - if (data.active_requests > data.visible_requests && index == data.visible_requests - 1) { + if (data.active_requests > data.visible_requests && index == (int) data.visible_requests - 1) { window_advisors_show_advisor(ADVISOR_IMPERIAL); return; } diff --git a/src/widget/sidebar/military.c b/src/widget/sidebar/military.c index 050145282c..de2efc4df0 100644 --- a/src/widget/sidebar/military.c +++ b/src/widget/sidebar/military.c @@ -145,9 +145,9 @@ typedef struct { static struct { legion_info active_legion; - int top_buttons_focus_id; - int inner_buttons_focus_id; - int bottom_buttons_focus_id; + unsigned int top_buttons_focus_id; + unsigned int inner_buttons_focus_id; + unsigned int bottom_buttons_focus_id; int city_view_was_collapsed; } data; @@ -177,7 +177,7 @@ static void draw_layout_buttons(int x, int y, int background, const formation *m int start_formation = LAYOUTS_PER_LEGION - formation_types; const generic_button *button_offsets = buttons_formation_layout[formation_types - 3]; - for (int i = start_formation; i < LAYOUTS_PER_LEGION; i++) { + for (unsigned int i = start_formation; i < LAYOUTS_PER_LEGION; i++) { const generic_button *btn = &button_offsets[i - start_formation]; if (background) { @@ -344,7 +344,7 @@ static void draw_legion_buttons(int x_offset, int y_offset) const formation *m = formation_get(data.active_legion.formation_id); if (m->num_figures) { draw_layout_buttons(x_offset, y_offset + Y_OFFSET_LAYOUT_BUTTONS, 0, m); - for (int i = 0; i < 3; i++) { + for (unsigned int i = 0; i < 3; i++) { button_border_draw(x_offset + buttons_bottom[i].x, y_offset + Y_OFFSET_BOTTOM_BUTTONS, 30, 30, data.bottom_buttons_focus_id == i + 1); } diff --git a/src/window/advisor/entertainment.c b/src/window/advisor/entertainment.c index 0fb72969d3..3fa7be5a2c 100644 --- a/src/window/advisor/entertainment.c +++ b/src/window/advisor/entertainment.c @@ -25,7 +25,8 @@ #define COVERAGE_OFFSET 470 #define COVERAGE_WIDTH 130 -static int focus_button_id; +static unsigned int focus_button_id; + static void button_hold_games(int param1, int param2); static generic_button hold_games_button[] = { @@ -63,18 +64,24 @@ void window_entertainment_draw_games_text(int x, int y) int cooldown = city_festival_games_cooldown(); if (cooldown) { - text_draw_centered(translation_for(TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_COOLDOWN_TEXT), x, y + 15, 400, FONT_NORMAL_WHITE, 0); - int width = text_draw(translation_for(TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_COOLDOWN), x + 46, y + 50, FONT_NORMAL_WHITE, 0); + text_draw_centered(translation_for(TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_COOLDOWN_TEXT), x, y + 15, + 400, FONT_NORMAL_WHITE, 0); + int width = text_draw(translation_for(TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_COOLDOWN), x + 46, y + 50, + FONT_NORMAL_WHITE, 0); text_draw_number(cooldown, '@', "", x + 46 + width, y + 50, FONT_NORMAL_WHITE, 0); } else if (city_festival_games_planning_time()) { - text_draw_centered(translation_for(TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_PREPARING), x, y + 15, 400, FONT_NORMAL_WHITE, 0); - int width = text_draw(translation_for(text_data[game->id].preparation_text), x + 56, y + 50, FONT_NORMAL_WHITE, 0); + text_draw_centered(translation_for(TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_PREPARING), x, y + 15, 400, + FONT_NORMAL_WHITE, 0); + int width = text_draw(translation_for(text_data[game->id].preparation_text), x + 56, y + 50, + FONT_NORMAL_WHITE, 0); text_draw_number(city_festival_games_planning_time(), '@', "", x + 56 + width, y + 50, FONT_NORMAL_WHITE, 0); } else if (city_festival_games_active()) { - text_draw_multiline(translation_for(text_data[game->id].ongoing_text), x + 4, y, 400, FONT_NORMAL_WHITE, 0); + text_draw_multiline(translation_for(text_data[game->id].ongoing_text), x + 4, y, 400, 0, FONT_NORMAL_WHITE, 0); } else { - text_draw_multiline(translation_for(TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_DESC), x + 4, y, 400, FONT_NORMAL_WHITE, 0); - text_draw_centered(translation_for(TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_BUTTON), x + 56, y + 60, 300, FONT_NORMAL_WHITE, 0); + text_draw_multiline(translation_for(TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_DESC), x + 4, y, + 400, 0, FONT_NORMAL_WHITE, 0); + text_draw_centered(translation_for(TR_WINDOW_ADVISOR_ENTERTAINMENT_GAMES_BUTTON), x + 56, y + 60, + 300, FONT_NORMAL_WHITE, 0); } } diff --git a/src/window/advisor/financial.c b/src/window/advisor/financial.c index a4ffb8d221..cbbe9f6d99 100644 --- a/src/window/advisor/financial.c +++ b/src/window/advisor/financial.c @@ -21,7 +21,7 @@ static arrow_button arrow_buttons_taxes[] = { {204, 75, 15, 24, button_change_taxes, 0, 0} }; -static int arrow_button_focus; +static unsigned int arrow_button_focus; static void draw_row(int group, int number, int y, int value_last_year, int value_this_year) { diff --git a/src/window/advisor/health.c b/src/window/advisor/health.c index e4ff92c979..0b71748b35 100644 --- a/src/window/advisor/health.c +++ b/src/window/advisor/health.c @@ -96,7 +96,7 @@ static int draw_background(void) lang_text_draw(CUSTOM_TRANSLATION, TR_ADVISOR_HEALTH_SURVEILLANCE, 60, 246 + text_height, FONT_NORMAL_BLACK); text_height += 16; text_draw_multiline(translation_for(TR_ADVISOR_SICKNESS_LEVEL_LOW + sickness_level), - 60, 246 + text_height, 512, FONT_NORMAL_BLACK, 0); + 60, 246 + text_height, 512, 0, FONT_NORMAL_BLACK, 0); return ADVISOR_HEIGHT; } diff --git a/src/window/advisor/housing.c b/src/window/advisor/housing.c index 1fd4e882de..a61fc570e6 100644 --- a/src/window/advisor/housing.c +++ b/src/window/advisor/housing.c @@ -48,7 +48,7 @@ static void draw_housing_table(void) } total_residences += residences_at_level; - for (int i = 0; i < list.size; i++) { + for (unsigned int i = 0; i < list.size; i++) { if (model_house_uses_inventory(level, list.items[i])) { houses_using_goods[list.items[i]] += residences_at_level; } @@ -73,7 +73,7 @@ static void draw_housing_table(void) text_draw(translation_for(TR_ADVISOR_TOTAL_HOUSING_CAPACITY), 320, y_offset + 220, FONT_NORMAL_GREEN, 0); text_draw_number(city_population_total_housing_capacity(), '@', " ", 500, y_offset + 220, FONT_NORMAL_WHITE, 0); - for (int i = 0; i < list.size; i++) { + for (unsigned int i = 0; i < list.size; i++) { image_draw(resource_get_data(list.items[i])->image.icon, 54, y_offset + 260 + (23 * i), COLOR_MASK_NONE, SCALE_NONE); text_draw(translation_for(TR_ADVISOR_RESIDENCES_USING_POTTERY + i), 90, y_offset + 263 + (23 * i), diff --git a/src/window/advisor/imperial.c b/src/window/advisor/imperial.c index 359a02c3ce..047e627ca0 100644 --- a/src/window/advisor/imperial.c +++ b/src/window/advisor/imperial.c @@ -47,9 +47,9 @@ static generic_button imperial_buttons[] = { {38, 264, 560, 40, button_request, button_request_resource, 4, 0}, }; -static int focus_button_id; -static int selected_request_id; -static int selected_resource; +static unsigned int focus_button_id; +static unsigned int selected_request_id; +static unsigned int selected_resource; static uint8_t tooltip_resource_info[RESOURCE_INFO_MAX_TEXT]; static void draw_request(int index, const scenario_request *request) @@ -163,7 +163,7 @@ static void draw_foreground(void) lang_text_draw_centered(52, 49, 320, 346, 250, FONT_NORMAL_WHITE); // Request buttons - for (int i = 0; i < CITY_REQUEST_MAX_ACTIVE; i++) { + for (unsigned int i = 0; i < CITY_REQUEST_MAX_ACTIVE; i++) { if (city_request_get_status(i)) { button_border_draw(38, 96 + i * 42, 560, 40, focus_button_id == i + 4); } diff --git a/src/window/advisor/labor.c b/src/window/advisor/labor.c index 813e55f4dd..6f75c20061 100644 --- a/src/window/advisor/labor.c +++ b/src/window/advisor/labor.c @@ -34,8 +34,8 @@ static arrow_button wage_buttons[] = { {182, 354, 15, 24, arrow_button_wages, 0, 0} }; -static int focus_button_id; -static int arrow_button_focus; +static unsigned int focus_button_id; +static unsigned int arrow_button_focus; static int draw_background(void) { @@ -78,7 +78,7 @@ static void draw_foreground(void) inner_panel_draw(32, 70, 36, 15); - for (int i = 0; i < 9; i++) { + for (unsigned int i = 0; i < 9; i++) { int focus = i == focus_button_id - 1; int y_offset = 82 + 25 * i; button_border_draw(40, 77 + 25 * i, 560, 22, focus); diff --git a/src/window/advisor/military.c b/src/window/advisor/military.c index 90d0a7e716..a9392b8ef9 100644 --- a/src/window/advisor/military.c +++ b/src/window/advisor/military.c @@ -57,9 +57,9 @@ static generic_button additional_buttons[] = { {445, 28, 60, 40, button_return_all_to_fort, button_none, 0, 0} }; -static int focus_button_id; -static int focus_additional_button_id; -static int num_legions; +static unsigned int focus_button_id; +static unsigned int focus_additional_button_id; +static unsigned int num_legions; static void init(void) { @@ -147,7 +147,7 @@ static int draw_background(void) lang_text_draw_multiline(51, 16, 64, 200, 496, FONT_NORMAL_GREEN); return ADVISOR_HEIGHT; } - for (int i = 0; i < 6 && i < num_legions; i++) { + for (unsigned int i = 0; i < 6 && i < num_legions; i++) { const formation *m = formation_get(formation_for_legion(i + 1 + scrollbar.scroll_position)); button_border_draw(22, 77 + 44 * i, 560, 40, 0); image_draw(image_group(GROUP_FIGURE_FORT_STANDARD_ICONS) + m->legion_id, 32, 82 + 44 * i, @@ -198,10 +198,10 @@ static int draw_background(void) return ADVISOR_HEIGHT; } -static int get_num_legions_not_at_fort(void) +static unsigned int get_num_legions_not_at_fort(void) { - int num_legions_not_at_fort = 0; - for (int i = 0; i < num_legions; i++) { + unsigned int num_legions_not_at_fort = 0; + for (unsigned int i = 0; i < num_legions; i++) { const formation* m = formation_get(formation_for_legion(i + 1)); if (!m->in_distant_battle && !m->is_at_fort) { num_legions_not_at_fort++; @@ -214,7 +214,7 @@ static void draw_foreground(void) { scrollbar_draw(&scrollbar); num_legions = formation_get_num_legions(); - for (int i = 0; i < 6 && i < num_legions; i++) { + for (unsigned int i = 0; i < 6 && i < num_legions; i++) { button_border_draw(384, 83 + 44 * i, 30, 30, focus_button_id == 3 * i + 1); button_border_draw(464, 83 + 44 * i, 30, 30, focus_button_id == 3 * i + 2); button_border_draw(544, 83 + 44 * i, 30, 30, focus_button_id == 3 * i + 3); @@ -233,7 +233,7 @@ static int handle_mouse(const mouse *m) focus_button_id = 0; return 1; } - int buttons = 3 * num_legions; + unsigned int buttons = 3 * num_legions; if (buttons > MAX_BUTTONS) { buttons = MAX_BUTTONS; } @@ -278,9 +278,9 @@ static void button_empire_service(int legion_id, int param2) static void button_return_all_to_fort(int param1, int param2) { - int num_legions_not_at_fort = get_num_legions_not_at_fort(); + unsigned int num_legions_not_at_fort = get_num_legions_not_at_fort(); if (num_legions_not_at_fort > 0) { - for (int i = 0; i < num_legions; i++) { + for (unsigned int i = 0; i < num_legions; i++) { return_legion_to_fort(i + 1); } } diff --git a/src/window/advisor/population.c b/src/window/advisor/population.c index 3d230bf2b7..a8b6d83359 100644 --- a/src/window/advisor/population.c +++ b/src/window/advisor/population.c @@ -30,7 +30,7 @@ static generic_button graph_buttons[] = { { 509, 161, 104, 55, button_graph, button_none, 1, 0 } }; -static int focus_button_id; +static unsigned int focus_button_id; static void get_y_axis(int max_value, int *y_max, int *y_shift) { diff --git a/src/window/advisor/ratings.c b/src/window/advisor/ratings.c index e2bfa0379a..735a8a0d9d 100644 --- a/src/window/advisor/ratings.c +++ b/src/window/advisor/ratings.c @@ -25,7 +25,7 @@ static generic_button rating_buttons[] = { {440, 286, 110, 66, button_rating, button_none, SELECTED_RATING_FAVOR, 0}, }; -static int focus_button_id; +static unsigned int focus_button_id; void draw_rating_column(int x_offset, int y_offset, int value, int has_reached) { diff --git a/src/window/advisor/religion.c b/src/window/advisor/religion.c index 1e31fa10d1..0a2116c6e6 100644 --- a/src/window/advisor/religion.c +++ b/src/window/advisor/religion.c @@ -19,7 +19,7 @@ static generic_button hold_festival_button[] = { {102, 340, 300, 20, button_hold_festival, button_none, 0, 0}, }; -static int focus_button_id; +static unsigned int focus_button_id; static int get_religion_advice(void) { diff --git a/src/window/advisor/trade.c b/src/window/advisor/trade.c index 938b4b4b36..c3380a93e0 100644 --- a/src/window/advisor/trade.c +++ b/src/window/advisor/trade.c @@ -15,8 +15,8 @@ #include "graphics/graphics.h" #include "graphics/image.h" #include "graphics/lang_text.h" +#include "graphics/list_box.h" #include "graphics/panel.h" -#include "graphics/scrollbar.h" #include "graphics/text.h" #include "graphics/window.h" #include "sound/speech.h" @@ -33,30 +33,33 @@ #define RESOURCE_ROW_HEIGHT 41 #define MAX_VISIBLE_ROWS 8 -static void on_scroll(void); +static void draw_resource_info(const list_box_item *item); +static void resource_item_tooltip(const list_box_item *item, tooltip_context *c); static void button_prices(int param1, int param2); static void button_empire(int param1, int param2); static void button_policy(int param1, int param2); -static void button_resource(int resource_index, int param2); - -static scrollbar_type scrollbar = { - 580, RESOURCE_Y_OFFSET, RESOURCE_ROW_HEIGHT * MAX_VISIBLE_ROWS, 560, MAX_VISIBLE_ROWS, on_scroll, 0, 4 +static void select_resource(unsigned int index, int param2); + +static list_box_type resource_list_box = { + .x = 16, + .y = 52, + .width_blocks = 37, + .height_blocks = 21, + .item_height = 40, + .decorate_scrollbar = 1, + .draw_inner_panel = 1, + .extend_to_hidden_scrollbar = 1, + .draw_item = draw_resource_info, + .on_select = select_resource, + .handle_tooltip = resource_item_tooltip }; static generic_button resource_buttons[] = { {375, 392, 200, 24, button_prices, button_none, 1, 0}, {160, 392, 200, 24, button_empire, button_none, 1, 0}, {45, 390, 40, 30, button_policy, button_none, LAND_TRADE_POLICY, 0}, - {95, 390, 40, 30, button_policy, button_none, SEA_TRADE_POLICY, 0}, - {64, 56, 480, RESOURCE_ROW_HEIGHT - 2, button_resource, button_none, 0, 0}, - {64, 97, 480, RESOURCE_ROW_HEIGHT - 2, button_resource, button_none, 1, 0}, - {64, 138, 480, RESOURCE_ROW_HEIGHT - 2, button_resource, button_none, 2, 0}, - {64, 179, 480, RESOURCE_ROW_HEIGHT - 2, button_resource, button_none, 3, 0}, - {64, 220, 480, RESOURCE_ROW_HEIGHT - 2, button_resource, button_none, 4, 0}, - {64, 261, 480, RESOURCE_ROW_HEIGHT - 2, button_resource, button_none, 5, 0}, - {64, 302, 480, RESOURCE_ROW_HEIGHT - 2, button_resource, button_none, 6, 0}, - {64, 343, 480, RESOURCE_ROW_HEIGHT - 2, button_resource, button_none, 7, 0} + {95, 390, 40, 30, button_policy, button_none, SEA_TRADE_POLICY, 0} }; static struct { @@ -91,9 +94,8 @@ static struct { }; static struct { - int focus_button_id; + unsigned int focus_button_id; resource_list list; - int margin_right; trade_policy_type policy_type; } data; @@ -103,10 +105,49 @@ static void init(void) const resource_list *list = city_resource_get_potential(); // We need to copy over the struct to prevent bugs when the trade prices window is shown memcpy(&data.list, list, sizeof(resource_list)); - scrollbar_init(&scrollbar, 0, data.list.size); - if (data.list.size > MAX_VISIBLE_ROWS) { - data.margin_right = 48; + list_box_init(&resource_list_box, data.list.size); +} + +static int draw_background(void) +{ + outer_panel_draw(0, 0, 40, ADVISOR_HEIGHT); + image_draw(image_group(GROUP_ADVISOR_ICONS) + 4, 10, 10, COLOR_MASK_NONE, SCALE_NONE); + + lang_text_draw(54, 0, 60, 12, FONT_LARGE_BLACK); + int width = lang_text_get_width(54, 1, FONT_NORMAL_BLACK); + lang_text_draw(54, 1, 600 - width, 38, FONT_NORMAL_BLACK); + + button_border_draw(375, 392, 200, 24, data.focus_button_id == 1); + lang_text_draw_centered(54, 2, 375, 398, 200, FONT_NORMAL_BLACK); + + button_border_draw(160, 392, 200, 24, data.focus_button_id == 2); + lang_text_draw_centered(54, 30, 160, 398, 200, FONT_NORMAL_BLACK); + + int land_policy_available = building_monument_working(BUILDING_CARAVANSERAI); + int sea_policy_available = building_monument_working(BUILDING_LIGHTHOUSE); + + button_border_draw(45, 390, 40, 30, land_policy_available && data.focus_button_id == 3); + int image_id; + + if (land_policy_available) { + image_id = image_group(GROUP_EMPIRE_TRADE_ROUTE_TYPE) + 1; + } else { + image_id = assets_get_image_id("UI", "Land Trade Policy Off Button"); + } + image_draw(image_id, 51, 394, COLOR_MASK_NONE, SCALE_NONE); + + button_border_draw(95, 390, 40, 30, sea_policy_available && data.focus_button_id == 4); + + if (sea_policy_available) { + image_id = image_group(GROUP_EMPIRE_TRADE_ROUTE_TYPE); + } else { + image_id = assets_get_image_id("UI", "Sea Trade Policy Off Button"); } + image_draw(image_id, 99, 394, COLOR_MASK_NONE, SCALE_NONE); + + list_box_request_refresh(&resource_list_box); + + return ADVISOR_HEIGHT; } static void draw_resource_status_text(int resource, int x, int y, int box_width) @@ -179,87 +220,43 @@ static void draw_resource_status_text(int resource, int x, int y, int box_width) } } -static int draw_background(void) +static void draw_resource_info(const list_box_item *item) { - outer_panel_draw(0, 0, 40, ADVISOR_HEIGHT); - image_draw(image_group(GROUP_ADVISOR_ICONS) + 4, 10, 10, COLOR_MASK_NONE, SCALE_NONE); - - lang_text_draw(54, 0, 60, 12, FONT_LARGE_BLACK); - int width = lang_text_get_width(54, 1, FONT_NORMAL_BLACK); - lang_text_draw(54, 1, 600 - width, 38, FONT_NORMAL_BLACK); - - button_border_draw(375, 392, 200, 24, data.focus_button_id == 1); - lang_text_draw_centered(54, 2, 375, 398, 200, FONT_NORMAL_BLACK); - - button_border_draw(160, 392, 200, 24, data.focus_button_id == 2); - lang_text_draw_centered(54, 30, 160, 398, 200, FONT_NORMAL_BLACK); - - if (data.list.size > MAX_VISIBLE_ROWS) { - inner_panel_draw(scrollbar.x + 4, scrollbar.y + 28, 2, scrollbar.height / BLOCK_SIZE - 3); + resource_type resource = data.list.items[item->index]; + int image_id = resource_get_data(resource)->image.icon; + const image *img = image_get(image_id); + int image_x = (40 - img->original.width) / 2; + int image_y = (item->height - img->original.height) / 2; + image_draw(image_id, item->x + image_x, item->y + image_y, COLOR_MASK_NONE, SCALE_NONE); + image_draw(image_id, item->x + item->width - 40 + image_x, item->y + image_y, COLOR_MASK_NONE, SCALE_NONE); + + if (item->is_focused) { + button_border_draw(item->x + 40, item->y - 2, item->width - 80, item->height, 1); } - - int land_policy_available = building_monument_working(BUILDING_CARAVANSERAI); - int sea_policy_available = building_monument_working(BUILDING_LIGHTHOUSE); - - button_border_draw(45, 390, 40, 30, land_policy_available && data.focus_button_id == 3); - int image_id; - - if (land_policy_available) { - image_id = image_group(GROUP_EMPIRE_TRADE_ROUTE_TYPE) + 1; + text_draw(resource_get_data(resource)->text, item->x + 48, item->y + 15, FONT_NORMAL_WHITE, COLOR_MASK_NONE); + if (resource_is_storable(resource)) { + int amount = city_resource_count(resource); + if (resource_is_food(resource)) { + amount += city_resource_count_food_on_granaries(resource) / 100; + } + text_draw_number_centered(amount, item->x + 140, item->y + 15, 60, FONT_NORMAL_WHITE); } else { - image_id = assets_get_image_id("UI", "Land Trade Policy Off Button"); + lang_text_draw_centered(56, 2, item->x + 140, item->y + 15, 60, FONT_NORMAL_WHITE); } - image_draw(image_id, 51, 394, COLOR_MASK_NONE, SCALE_NONE); - - button_border_draw(95, 390, 40, 30, sea_policy_available && data.focus_button_id == 4); - - if (sea_policy_available) { - image_id = image_group(GROUP_EMPIRE_TRADE_ROUTE_TYPE); - } else { - image_id = assets_get_image_id("UI", "Sea Trade Policy Off Button"); + if (city_resource_is_mothballed(resource)) { + lang_text_draw_centered(18, 5, item->x + 180, item->y + 15, 100, FONT_NORMAL_WHITE); } - image_draw(image_id, 99, 394, COLOR_MASK_NONE, SCALE_NONE); + draw_resource_status_text(resource, item->x + 176, item->y + 5, item->width - 206); - return ADVISOR_HEIGHT; + if (item->position < resource_list_box.scrollbar.elements_in_view - 1) { + graphics_draw_inset_rect(item->x, item->y + item->height - 2, item->width, 2, + COLOR_INSET_DARK, COLOR_INSET_LIGHT); + } } static void draw_foreground(void) { - inner_panel_draw(16, RESOURCE_Y_OFFSET - 2, 38 - data.margin_right / BLOCK_SIZE, 21); - - int y_offset = RESOURCE_Y_OFFSET; - for (int i = 0; i < data.list.size && i < MAX_VISIBLE_ROWS; i++) { - int resource = data.list.items[i + scrollbar.scroll_position]; - int image_id = resource_get_data(resource)->image.icon; - const image *img = image_get(image_id); - int base_y = (RESOURCE_ROW_HEIGHT - img->height) / 2; - image_draw(image_id, 32, y_offset + base_y, COLOR_MASK_NONE, SCALE_NONE); - image_draw(image_id, 584 - data.margin_right, y_offset + base_y, COLOR_MASK_NONE, SCALE_NONE); - - if (data.focus_button_id - 5 == i) { - button_border_draw(64, y_offset, 512 - data.margin_right, RESOURCE_ROW_HEIGHT, 1); - } - text_draw(resource_get_data(resource)->text, 72, y_offset + 17, FONT_NORMAL_WHITE, COLOR_MASK_NONE); - if (resource_is_storable(resource)) { - int amount = city_resource_count(resource); - if (resource_is_food(resource)) { - amount += city_resource_count_food_on_granaries(resource) / 100; - } - text_draw_number_centered(amount, 164, y_offset + 17, 60, FONT_NORMAL_WHITE); - } else { - lang_text_draw_centered(56, 2, 164, y_offset + 17, 60, FONT_NORMAL_WHITE); - } - if (city_resource_is_mothballed(resource)) { - lang_text_draw_centered(18, 5, 204, y_offset + 17, 100, FONT_NORMAL_WHITE); - } - draw_resource_status_text(resource, 240, y_offset + 7, 352 - data.margin_right); - - y_offset += RESOURCE_ROW_HEIGHT; - - if (i < MAX_VISIBLE_ROWS - 1) { - graphics_draw_inset_rect(24, y_offset, 592 - data.margin_right, 2, COLOR_INSET_DARK, COLOR_INSET_LIGHT); - } - } + list_box_draw(&resource_list_box); button_border_draw(375, 392, 200, 24, data.focus_button_id == 1); button_border_draw(160, 392, 200, 24, data.focus_button_id == 2); @@ -268,21 +265,12 @@ static void draw_foreground(void) int sea_policy_available = building_monument_working(BUILDING_LIGHTHOUSE); button_border_draw(45, 390, 40, 30, land_policy_available && data.focus_button_id == 3); button_border_draw(95, 390, 40, 30, sea_policy_available && data.focus_button_id == 4); - - if (data.list.size > MAX_VISIBLE_ROWS) { - scrollbar_draw(&scrollbar); - } -} - -static void on_scroll(void) -{ - window_request_refresh(); } static int handle_mouse(const mouse *m) { data.focus_button_id = 0; - return scrollbar_handle_mouse(&scrollbar, m, 1) || + return list_box_handle_input(&resource_list_box, m, 1) || generic_buttons_handle_mouse(m, 0, 0, resource_buttons, MAX_VISIBLE_ROWS + 4, &data.focus_button_id); } @@ -330,12 +318,12 @@ static void button_policy(int policy_type, int param2) show_policy(policy_type); } -static void button_resource(int resource_index, int param2) +static void select_resource(unsigned int index, int param2) { - window_resource_settings_show(data.list.items[resource_index + scrollbar.scroll_position]); + window_resource_settings_show(data.list.items[index]); } -static void write_resource_storage_tooltip(advisor_tooltip_result *r, int resource) +static void write_resource_storage_tooltip(tooltip_context *c, resource_type resource) { static uint8_t tooltip_resource_info[200]; int amount_warehouse = city_resource_count(resource); @@ -351,7 +339,18 @@ static void write_resource_storage_tooltip(advisor_tooltip_result *r, int resour *text = ' '; text++; text = string_copy(translation_for(TR_ADVISOR_FROM_GRANARIES), text, 200 - (int) (text - tooltip_resource_info)); - r->precomposed_text = tooltip_resource_info; + c->precomposed_text = tooltip_resource_info; +} + +static void resource_item_tooltip(const list_box_item *item, tooltip_context *c) +{ + const mouse *m = mouse_in_dialog(mouse_get()); + resource_type resource = data.list.items[item->index]; + if (resource_is_food(resource) && m->x > item->x + 156 && m->x < item->x + 196) { + write_resource_storage_tooltip(c, resource); + } else { + c->text_id = 107; + } } static void get_tooltip_text(advisor_tooltip_result *r) @@ -372,14 +371,12 @@ static void get_tooltip_text(advisor_tooltip_result *r) } else { r->translation_key = TR_TOOLTIP_ADVISOR_TRADE_SEA_POLICY_REQUIRED; } - } else if (data.focus_button_id > 4) { - const mouse *m = mouse_in_dialog(mouse_get()); - int resource = data.list.items[data.focus_button_id - 5 + scrollbar.scroll_position]; - if (resource_is_food(resource) && m->x > 180 && m->x < 220) { - write_resource_storage_tooltip(r, resource); - return; - } - r->text_id = 107; + } else { + tooltip_context c = { 0 }; + list_box_handle_tooltip(&resource_list_box, &c); + r->precomposed_text = c.precomposed_text; + r->text_id = c.text_id; + r->translation_key = c.translation_key; } } diff --git a/src/window/advisors.c b/src/window/advisors.c index 0bb0340fd6..6bc59171e6 100644 --- a/src/window/advisors.c +++ b/src/window/advisors.c @@ -119,7 +119,7 @@ static int advisor_image_ids[2][ADVISOR_MAX]; static const advisor_window_type *current_advisor_window = 0; static advisor_type current_advisor = ADVISOR_NONE; -static int focus_button_id; +static unsigned int focus_button_id; static int advisor_height; static void set_advisor_window(void) @@ -235,10 +235,10 @@ static void handle_input(const mouse *m, const hotkeys *h) if (generic_buttons_handle_mouse(m_dialog, 0, 440, advisor_buttons, ADVISOR_MAX, &focus_button_id)) { return; } - int button_id; + unsigned int button_id; image_buttons_handle_mouse(m_dialog, 0, BLOCK_SIZE * (advisor_height - 2), &help_button, 1, &button_id); if (button_id) { - focus_button_id = -1; + focus_button_id = 0; } if (current_advisor_window->handle_mouse && current_advisor_window->handle_mouse(m_dialog)) { return; diff --git a/src/window/asset_previewer.c b/src/window/asset_previewer.c index b5a863f30f..4d73b16538 100644 --- a/src/window/asset_previewer.c +++ b/src/window/asset_previewer.c @@ -62,7 +62,7 @@ typedef enum { #define REFRESHED_INFO_TIME_MS 5000 static void draw_asset_entry(const list_box_item *item); -static void select_asset(int index, int unused); +static void select_asset(unsigned int index, int unused); static void handle_tooltip(const list_box_item *item, tooltip_context *c); static void button_top(int option, int param2); static void button_toggle_animation_frames(int param1, int param2); @@ -111,8 +111,8 @@ static struct { const uint8_t *zoom_texts[TOTAL_ZOOM_VALUES]; uint8_t *encoded_asset_id; int encoded_asset_id_size; - int focus_button_id; - int animation_button_focused; + unsigned int focus_button_id; + unsigned int animation_button_focused; int x_offset_top; asset_entry *entries; char *selected_asset_id; @@ -161,16 +161,16 @@ static int update_entries(void) return total_entries; } -static void select_asset(int index, int unused) +static void select_asset(unsigned int index, int unused) { const asset_image *img = asset_image_get_from_id(data.active_group->first_image_index + data.entries[index].index); free(data.selected_asset_id); data.selected_asset_id = 0; if (img->id) { - size_t id_length = strlen(img->id) + 1; - data.selected_asset_id = malloc(id_length * sizeof(char)); + size_t id_length = (strlen(img->id) + 1) * sizeof(char); + data.selected_asset_id = malloc(id_length); if (data.selected_asset_id) { - strncpy(data.selected_asset_id, img->id, id_length); + snprintf(data.selected_asset_id, id_length, "%s", img->id); } } if (data.animation.enabled) { @@ -233,7 +233,7 @@ static int update_asset_groups_list(void) static char original_file[FILE_NAME_MAX]; for (int i = 0; i < data.xml_files->num_files; i++) { - strncpy(original_file, data.xml_files->files[i].name, FILE_NAME_MAX - 1); + snprintf(original_file, FILE_NAME_MAX, "%s", data.xml_files->files[i].name); file_remove_extension(original_file); int size = (int) strlen(original_file) + 1; uint8_t *file = malloc(sizeof(uint8_t) * size); @@ -512,7 +512,7 @@ static void advance_animation_frame(const image *img) static void draw_foreground(void) { - for (int i = 0; i < NUM_BUTTONS; i++) { + for (unsigned int i = 0; i < NUM_BUTTONS; i++) { const generic_button *btn = &buttons[i]; int x_offset = btn->x + data.x_offset_top + 16; int width = btn->width; @@ -748,7 +748,7 @@ static void button_toggle_animation_frames(int param1, int param2) recalculate_selected_index(); window_invalidate(); - for (int i = 0; i < list_box_get_total_items(&list_box); i++) { + for (unsigned int i = 0; i < list_box_get_total_items(&list_box); i++) { if (data.entries[i].index == asset_index || (is_animation_frame && data.hide_animation_frames && data.entries[i].index > asset_index)) { list_box_show_index(&list_box, i); diff --git a/src/window/build_menu.c b/src/window/build_menu.c index 68b97a4c2c..75236f5fcf 100644 --- a/src/window/build_menu.c +++ b/src/window/build_menu.c @@ -85,9 +85,9 @@ static const int Y_MENU_OFFSETS[] = { static struct { build_menu_group selected_submenu; - int num_items; + unsigned int num_items; int y_offset; - int focus_button_id; + unsigned int focus_button_id; } data = { SUBMENU_NONE }; static int init(build_menu_group submenu) @@ -189,7 +189,7 @@ static void draw_menu_buttons(void) int x_offset = get_sidebar_x_offset(); int item_index = -1; int item_x_align = x_offset - MENU_X_OFFSET; - for (int i = 0; i < data.num_items; i++) { + for (unsigned int i = 0; i < data.num_items; i++) { item_index = building_menu_next_index(data.selected_submenu, item_index); label_draw(item_x_align, data.y_offset + MENU_Y_OFFSET + MENU_ITEM_HEIGHT * i, 18, data.focus_button_id == i + 1 ? 1 : 2); @@ -252,7 +252,7 @@ static int click_outside_menu(const mouse *m, int x_offset) (m->x < x_offset - MENU_X_OFFSET - MENU_CLICK_MARGIN || m->x > x_offset + MENU_CLICK_MARGIN || m->y < data.y_offset + MENU_Y_OFFSET - MENU_CLICK_MARGIN || - m->y > data.y_offset + MENU_Y_OFFSET + MENU_CLICK_MARGIN + MENU_ITEM_HEIGHT * data.num_items); + m->y > data.y_offset + MENU_Y_OFFSET + MENU_CLICK_MARGIN + MENU_ITEM_HEIGHT * (int) data.num_items); } static int handle_build_submenu(const mouse *m) diff --git a/src/window/building/common.c b/src/window/building/common.c index feefa74f59..5b916c1835 100644 --- a/src/window/building/common.c +++ b/src/window/building/common.c @@ -214,7 +214,7 @@ static void window_building_draw_monument_resources_needed(building_info_context } } else { text_draw_multiline(translation_for(TR_BUILDING_MONUMENT_CONSTRUCTION_ARCHITECT_NEEDED), - c->x_offset + 22, c->y_offset + 95, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 95, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); } } @@ -228,7 +228,7 @@ void window_building_draw_monument_construction_process(building_info_context *c window_building_draw_description(c, CUSTOM_TRANSLATION, TR_WINDOW_BUILDING_INFO_WARNING_NO_MONUMENT_ROAD_ACCESS); text_draw_multiline(translation_for(tr_construction_desc), - c->x_offset + 22, c->y_offset + 180, 16 * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 180, 16 * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); return; } int width = text_draw(translation_for(TR_CONSTRUCTION_PHASE), @@ -242,14 +242,16 @@ void window_building_draw_monument_construction_process(building_info_context *c text_draw(translation_for(TR_REQUIRED_RESOURCES), c->x_offset + 22, c->y_offset + 70, FONT_NORMAL_BLACK, 0); window_building_draw_monument_resources_needed(c); int height = text_draw_multiline(translation_for(tr_phase_name_text + b->monument.phase - 1), - c->x_offset + 22, c->y_offset + 170, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 170, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); if (building_monument_is_construction_halted(b)) { height += text_draw_multiline(translation_for(TR_BUILDING_MONUMENT_CONSTRUCTION_HALTED), - c->x_offset + 22, c->y_offset + 180 + height, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 180 + height, BLOCK_SIZE * (c->width_blocks - 4), + 0, FONT_NORMAL_BLACK, 0); } else { height += text_draw_multiline(translation_for(tr_construction_desc), - c->x_offset + 22, c->y_offset + 180 + height, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 180 + height, BLOCK_SIZE * (c->width_blocks - 4), + 0, FONT_NORMAL_BLACK, 0); } if (c->height_blocks > 26) { int phase_offset = b->monument.phase % 2; diff --git a/src/window/building/culture.c b/src/window/building/culture.c index e2379a8ec0..f3dc24470d 100644 --- a/src/window/building/culture.c +++ b/src/window/building/culture.c @@ -73,9 +73,9 @@ static generic_button hold_games_button[] = { }; static struct { - int focus_button_id; + unsigned int focus_button_id; int building_id; - int lighthouse_focus_button_id; + unsigned int lighthouse_focus_button_id; int module_choices[2]; } data; @@ -295,7 +295,7 @@ static void draw_temple_info(building_info_context *c, int image_offset) text_draw_number(b->resources[RESOURCE_OIL], '@', " ", c->x_offset + 222, c->y_offset + 60, font, 0); text_draw_multiline(translation_for(TR_BUILDING_CERES_TEMPLE_MODULE_DESC), - c->x_offset + 112, c->y_offset + 90, BLOCK_SIZE * c->width_blocks - 132, FONT_NORMAL_BLACK, 0); + c->x_offset + 112, c->y_offset + 90, BLOCK_SIZE * c->width_blocks - 132, 0, FONT_NORMAL_BLACK, 0); image_draw(image_offset + image_group(GROUP_PANEL_WINDOWS), c->x_offset + 16, c->y_offset + 45, COLOR_MASK_NONE, SCALE_NONE); return; @@ -308,7 +308,7 @@ static void draw_temple_info(building_info_context *c, int image_offset) text_draw_number(b->resources[RESOURCE_WINE], '@', " ", c->x_offset + 132, c->y_offset + 60, font, 0); text_draw_multiline(translation_for(TR_BUILDING_VENUS_TEMPLE_MODULE_DESC), - c->x_offset + 112, c->y_offset + 90, BLOCK_SIZE * c->width_blocks - 132, FONT_NORMAL_BLACK, 0); + c->x_offset + 112, c->y_offset + 90, BLOCK_SIZE * c->width_blocks - 132, 0, FONT_NORMAL_BLACK, 0); image_draw(image_offset + image_group(GROUP_PANEL_WINDOWS), c->x_offset + BLOCK_SIZE, c->y_offset + 45, COLOR_MASK_NONE, SCALE_NONE); @@ -318,7 +318,7 @@ static void draw_temple_info(building_info_context *c, int image_offset) int x_offset = 112; if (building_is_mars_temple(b->type) && building_monument_gt_module_is_active(MARS_MODULE_1_MESS_HALL)) { const resource_list *list = city_resource_get_potential_foods(); - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { resource_type r = list->items[i]; if (!resource_is_inventory(r) || (list->size > 4 && !b->resources[r])) { continue; @@ -334,11 +334,11 @@ static void draw_temple_info(building_info_context *c, int image_offset) if (city_buildings_get_mess_hall()) { text_draw_multiline(translation_for(TR_BUILDING_MARS_TEMPLE_MODULE_DESC), c->x_offset + 112, c->y_offset + 90, - BLOCK_SIZE * c->width_blocks - 132, FONT_NORMAL_BLACK, 0); + BLOCK_SIZE * c->width_blocks - 132, 0, FONT_NORMAL_BLACK, 0); } else { text_draw_multiline(translation_for(TR_BUILDING_MARS_TEMPLE_MODULE_DESC_NO_MESS), c->x_offset + 112, c->y_offset + 90, - BLOCK_SIZE * c->width_blocks - 132, FONT_NORMAL_BLACK, 0); + BLOCK_SIZE * c->width_blocks - 132, 0, FONT_NORMAL_BLACK, 0); } image_draw(image_offset + image_group(GROUP_PANEL_WINDOWS), c->x_offset + 16, c->y_offset + 45, @@ -709,14 +709,15 @@ static void draw_grand_temple(building_info_context *c, const char *sound_file, if (b->monument.phase == MONUMENT_FINISHED) { if (building_monument_has_labour_problems(b)) { height = text_draw_multiline(translation_for(TR_BUILDING_GRAND_TEMPLE_NEEDS_WORKERS), - c->x_offset + 22, c->y_offset + 56 + extra_y, 15 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 56 + extra_y, 15 * c->width_blocks, 0, FONT_NORMAL_BLACK, 0); } else { height = text_draw_multiline(translation_for(bonus_desc), - c->x_offset + 22, c->y_offset + 56 + extra_y, 15 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 56 + extra_y, 15 * c->width_blocks, 0, FONT_NORMAL_BLACK, 0); if (b->monument.upgrades) { int module_desc = temple_module_options[god_id * 2 + (b->monument.upgrades - 1)].option.desc; height += text_draw_multiline(translation_for(module_desc), - c->x_offset + 22, c->y_offset + 66 + height + extra_y, 15 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 66 + height + extra_y, 15 * c->width_blocks, + 0, FONT_NORMAL_BLACK, 0); } } if (b->type == BUILDING_GRAND_TEMPLE_MARS) { @@ -734,8 +735,9 @@ static void draw_grand_temple(building_info_context *c, const char *sound_file, c->x_offset + 32, c->y_offset + 166 + height + extra_y, COLOR_MASK_NONE); image_draw(banner_id, c->x_offset + 37, c->y_offset + 171 + height + extra_y, COLOR_MASK_NONE, SCALE_NONE); - text_draw_centered_with_linebreaks(translation_for(quote), - c->x_offset, c->y_offset + 386 + height + extra_y, BLOCK_SIZE * c->width_blocks - 16, FONT_NORMAL_BLACK, 0); + text_draw_multiline(translation_for(quote), + c->x_offset, c->y_offset + 386 + height + extra_y, BLOCK_SIZE * c->width_blocks - 16, + 1, FONT_NORMAL_BLACK, 0); } } } @@ -831,7 +833,7 @@ void window_building_draw_work_camp(building_info_context *c) text_draw_centered(translation_for(TR_BUILDING_WORK_CAMP), c->x_offset, c->y_offset + 12, BLOCK_SIZE * c->width_blocks, FONT_LARGE_BLACK, 0); text_draw_multiline(translation_for(TR_BUILDING_WORK_CAMP_DESC), - c->x_offset + 32, c->y_offset + 76, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 32, c->y_offset + 76, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); window_building_draw_employment(c, 138); window_building_draw_risks(c, c->x_offset + c->width_blocks * BLOCK_SIZE - 76, c->y_offset + 144); } @@ -847,7 +849,7 @@ void window_building_draw_architect_guild(building_info_context *c) text_draw_centered(translation_for(TR_BUILDING_ARCHITECT_GUILD), c->x_offset, c->y_offset + 12, BLOCK_SIZE * c->width_blocks, FONT_LARGE_BLACK, 0); text_draw_multiline(translation_for(TR_BUILDING_ARCHITECT_GUILD_DESC), - c->x_offset + 32, c->y_offset + 76, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 32, c->y_offset + 76, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); window_building_draw_employment(c, 138); window_building_draw_risks(c, c->x_offset + c->width_blocks * BLOCK_SIZE - 76, c->y_offset + 144); } @@ -889,24 +891,24 @@ void window_building_draw_tavern(building_info_context *c) window_building_draw_description_at(c, 96, 69, 25); } else if (b->num_workers <= 0) { text_draw_multiline(translation_for(TR_BUILDING_TAVERN_DESC_1), - c->x_offset + 32, c->y_offset + 96, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 32, c->y_offset + 96, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); } else if (!b->resources[RESOURCE_WINE]) { text_draw_multiline(translation_for(TR_BUILDING_TAVERN_DESC_2), - c->x_offset + 32, c->y_offset + 96, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 32, c->y_offset + 96, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); } else if (!b->resources[RESOURCE_MEAT] && !b->resources[RESOURCE_FISH]) { int string_key = TR_BUILDING_TAVERN_DESC_3; if (b->upgrade_level) { string_key = TR_BUILDING_TAVERN_DESC_UPGRADED_WINE_NO_FOOD; } text_draw_multiline(translation_for(string_key), - c->x_offset + 32, c->y_offset + 96, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 32, c->y_offset + 96, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); } else { int string_key = TR_BUILDING_TAVERN_DESC_4; if (b->upgrade_level) { string_key = TR_BUILDING_TAVERN_DESC_UPGRADED_WINE_AND_FOOD; } text_draw_multiline(translation_for(string_key), - c->x_offset + 32, c->y_offset + 96, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 32, c->y_offset + 96, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); } inner_panel_draw(c->x_offset + 16, c->y_offset + 188, c->width_blocks - 2, 4); @@ -974,7 +976,7 @@ void window_building_draw_colosseum_background(building_info_context *c) // todo: better link of venue to game if (b->type == BUILDING_COLOSSEUM && building_monument_has_labour_problems(b)) { text_draw_multiline(translation_for(TR_BUILDING_COLOSSEUM_NEEDS_WORKERS), - c->x_offset + 22, c->y_offset + 56, 15 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 56, 15 * c->width_blocks, 0, FONT_NORMAL_BLACK, 0); } else { if (active_games && active_games <= 3 && b->type == BUILDING_COLOSSEUM) { window_building_draw_description(c, CUSTOM_TRANSLATION, TR_WINDOW_ADVISOR_ENTERTAINMENT_UNDERWAY_NG + @@ -1137,10 +1139,10 @@ void window_building_draw_lighthouse(building_info_context *c) if (building_monument_has_labour_problems(b)) { text_draw_multiline(translation_for(TR_BUILDING_LIGHTHOUSE_NEEDS_WORKERS), - c->x_offset + 22, c->y_offset + 70, 15 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 70, 15 * c->width_blocks, 0, FONT_NORMAL_BLACK, 0); } else { text_draw_multiline(translation_for(TR_BUILDING_LIGHTHOUSE_BONUS_DESC), - c->x_offset + 22, c->y_offset + 70, 15 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 70, 15 * c->width_blocks, 0, FONT_NORMAL_BLACK, 0); } if (!sea_trade_policy.items[0].image_id) { @@ -1155,10 +1157,10 @@ void window_building_draw_lighthouse(building_info_context *c) trade_policy policy = city_trade_policy_get(SEA_TRADE_POLICY); text_draw_multiline(translation_for(sea_trade_policy.items[policy].header), - c->x_offset + 160, c->y_offset + 156, 260, FONT_NORMAL_BLACK, 0); + c->x_offset + 160, c->y_offset + 156, 260, 0, FONT_NORMAL_BLACK, 0); if (policy != NO_POLICY) { text_draw_multiline(translation_for(sea_trade_policy.items[policy].desc), - c->x_offset + 160, c->y_offset + 181, 260, FONT_NORMAL_BLACK, 0); + c->x_offset + 160, c->y_offset + 181, 260, 0, FONT_NORMAL_BLACK, 0); } image_draw(sea_trade_policy.items[policy].image_id, c->x_offset + 32, c->y_offset + 150, COLOR_MASK_NONE, SCALE_NONE); @@ -1222,7 +1224,7 @@ void window_building_draw_hippodrome_background(building_info_context *c) window_building_draw_description(c, 69, 25); } else if (building_monument_has_labour_problems(b)) { text_draw_multiline(translation_for(TR_BUILDING_HIPPODROME_NEEDS_WORKERS), - c->x_offset + 22, c->y_offset + 56, 15 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 56, 15 * c->width_blocks, 0, FONT_NORMAL_BLACK, 0); } else if (!b->data.entertainment.num_shows) { window_building_draw_description(c, 73, 2); } else if (b->data.entertainment.days1) { @@ -1261,7 +1263,7 @@ void window_building_draw_hippodrome_background(building_info_context *c) text_draw_multiline(translation_for(TR_WINDOW_RACE_BLUE_HORSE_DESCRIPTION + city_data.games.chosen_horse - 1), c->x_offset + 132, c->y_offset + y_offset + 240, 338, - FONT_NORMAL_BLACK, 0); + 0, FONT_NORMAL_BLACK, 0); } text_draw_centered(translation_for(city_data.games.chosen_horse ? TR_WINDOW_IN_PROGRESS_BET_BUTTON : TR_WINDOW_RACE_BET_TITLE), c->x_offset + 88, c->y_offset + y_offset + 351, 300, FONT_NORMAL_BLACK, 0); @@ -1290,7 +1292,7 @@ void window_building_draw_nymphaeum(building_info_context *c) text_draw_centered(translation_for(TR_BUILDING_NYMPHAEUM), c->x_offset, c->y_offset + 12, BLOCK_SIZE * c->width_blocks, FONT_LARGE_BLACK, 0); text_draw_multiline(translation_for(TR_BUILDING_NYMPHAEUM_DESC), - c->x_offset + 22, c->y_offset + 56, 14 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 56, 14 * c->width_blocks, 0, FONT_NORMAL_BLACK, 0); inner_panel_draw(c->x_offset + 16, c->y_offset + 146, c->width_blocks - 2, 4); window_building_draw_employment(c, 152); window_building_draw_risks(c, c->x_offset + c->width_blocks * BLOCK_SIZE - 76, c->y_offset + 154); @@ -1312,7 +1314,7 @@ void window_building_draw_small_mausoleum(building_info_context *c) text_draw_centered(translation_for(TR_BUILDING_SMALL_MAUSOLEUM), c->x_offset, c->y_offset + 12, BLOCK_SIZE * c->width_blocks, FONT_LARGE_BLACK, 0); text_draw_multiline(translation_for(TR_BUILDING_SMALL_MAUSOLEUM_DESC), - c->x_offset + 22, c->y_offset + 56, 14 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 56, 14 * c->width_blocks, 0, FONT_NORMAL_BLACK, 0); inner_panel_draw(c->x_offset + 16, c->y_offset + 146, c->width_blocks - 2, 4); window_building_draw_employment(c, 152); window_building_draw_risks(c, c->x_offset + c->width_blocks * BLOCK_SIZE - 76, c->y_offset + 154); @@ -1334,7 +1336,7 @@ void window_building_draw_large_mausoleum(building_info_context *c) text_draw_centered(translation_for(TR_BUILDING_LARGE_MAUSOLEUM), c->x_offset, c->y_offset + 12, BLOCK_SIZE * c->width_blocks, FONT_LARGE_BLACK, 0); text_draw_multiline(translation_for(TR_BUILDING_LARGE_MAUSOLEUM_DESC), - c->x_offset + 22, c->y_offset + 56, 14 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 56, 14 * c->width_blocks, 0, FONT_NORMAL_BLACK, 0); inner_panel_draw(c->x_offset + 16, c->y_offset + 146, c->width_blocks - 2, 4); window_building_draw_employment(c, 152); window_building_draw_risks(c, c->x_offset + c->width_blocks * BLOCK_SIZE - 76, c->y_offset + 154); diff --git a/src/window/building/depot.c b/src/window/building/depot.c index 80fba3bf1b..38502b2c55 100644 --- a/src/window/building/depot.c +++ b/src/window/building/depot.c @@ -36,14 +36,14 @@ static void set_camera_position(int building_id, int param2); #define MAX_RESOURCE_ROWS 24 static struct { - int focus_button_id; - int orders_focus_button_id; - int resource_focus_button_id; - int storage_building_focus_button_id; - int storage_building_view_focus_button_id; - int depot_resource_focus_button_id; + unsigned int focus_button_id; + unsigned int orders_focus_button_id; + unsigned int resource_focus_button_id; + unsigned int storage_building_focus_button_id; + unsigned int storage_building_view_focus_button_id; + unsigned int depot_resource_focus_button_id; int depot_building_id; - int available_storages; + unsigned int available_storages; resource_type target_resource_id; pixel_area window_area; } data; @@ -135,7 +135,7 @@ static void setup_buttons_for_selected_depot(void) int button_index = 0; int storage_array_size = building_storage_get_array_size(); - int current_storage_offset = 0; + unsigned int current_storage_offset = 0; for (int i = 0; i < storage_array_size; i++) { if (current_storage_offset >= data.available_storages || button_index >= MAX_VISIBLE_ROWS) { break; @@ -408,7 +408,7 @@ void window_building_draw_depot_select_source_destination(building_info_context scrollbar.y = y_offset + 46; scrollbar_draw(&scrollbar); - int index = 0; + unsigned int index = 0; int base_width = BLOCK_SIZE * (c->width_blocks - 4) - 4 - (scrollbar.max_scroll_position > 0 ? 39 : 0); for (index = 0; index < MAX_VISIBLE_ROWS; index++) { @@ -566,9 +566,9 @@ void window_building_draw_depot_select_resource_foreground(building_info_context } const resource_list *list = city_resource_get_potential(); - int list_index = scrollbar.scroll_position * 2; // Two items per scroll bar step + unsigned int list_index = scrollbar.scroll_position * 2; // Two items per scroll bar step - for (int i = 0; i < MAX_RESOURCE_ROWS && list_index < list->size; i++, list_index++) { + for (unsigned int i = 0; i < MAX_RESOURCE_ROWS && list_index < list->size; i++, list_index++) { resource_type resource_id = list->items[list_index]; int image_id = resource_get_data(resource_id)->image.icon; const uint8_t *str = resource_get_data(resource_id)->text; diff --git a/src/window/building/distribution.c b/src/window/building/distribution.c index 407d95436b..4b6be7a748 100644 --- a/src/window/building/distribution.c +++ b/src/window/building/distribution.c @@ -115,7 +115,7 @@ static generic_button granary_distribution_permissions_buttons[] = { static generic_button dock_distribution_permissions_buttons[20]; -static int dock_distribution_permissions_buttons_count; +static unsigned int dock_distribution_permissions_buttons_count; static scrollbar_type scrollbar = { .on_scroll_callback = on_scroll }; @@ -166,17 +166,17 @@ static generic_button primary_product_producer_button_stockpiling[] = { }; static struct { - int focus_button_id; - int orders_focus_button_id; - int resource_focus_button_id; - int permission_focus_button_id; + unsigned int focus_button_id; + unsigned int orders_focus_button_id; + unsigned int resource_focus_button_id; + unsigned int permission_focus_button_id; int building_id; - int partial_resource_focus_button_id; + unsigned int partial_resource_focus_button_id; int tooltip_id; - int dock_max_cities_visible; - int caravanserai_focus_button_id; - int primary_product_stockpiling_id; - int image_button_focus_id; + unsigned int dock_max_cities_visible; + unsigned int caravanserai_focus_button_id; + unsigned int primary_product_stockpiling_id; + unsigned int image_button_focus_id; int showing_special_orders; int caravanserai_button_y_offset; resource_list stored_resources; @@ -227,7 +227,7 @@ static void draw_accept_none_button(int x, int y, int focused, affect_all_button } } -static void draw_permissions_buttons(int x, int y, int buttons, building_info_context *c) +static void draw_permissions_buttons(int x, int y, unsigned int buttons, building_info_context *c) { int images_permission[] = { assets_get_image_id("Walkers", "marketbuyer_sw_01"), @@ -241,7 +241,7 @@ static void draw_permissions_buttons(int x, int y, int buttons, building_info_co int image_offset_x, image_offset_y; - for (int i = 0; i < buttons; i++) { + for (unsigned int i = 0; i < buttons; i++) { int permission = warehouse_distribution_permissions_buttons[i].parameter1; int is_sea_trade_route = permission == BUILDING_STORAGE_PERMISSION_DOCK; @@ -273,7 +273,7 @@ static void draw_permissions_buttons(int x, int y, int buttons, building_info_co image_buttons_draw(c->x_offset + 421, c->y_offset + 10, image_buttons_maintain, button); } -static void draw_granary_permissions_buttons(int x, int y, int buttons) +static void draw_granary_permissions_buttons(int x, int y, unsigned int buttons) { static int images_permission[6]; if (!images_permission[0]) { @@ -282,12 +282,12 @@ static void draw_granary_permissions_buttons(int x, int y, int buttons) images_permission[2] = image_group(GROUP_EMPIRE_TRADE_ROUTE_TYPE); images_permission[3] = assets_get_image_id("Walkers", "Barkeep SW 01"); images_permission[4] = assets_get_image_id("Walkers", "M Hall SW 01"); - images_permission[5] = assets_get_image_id("Walkers", "caravanserai_walker_sw_01"); + images_permission[5] = assets_get_image_id("Walkers", "caravanserai_overseer_sw_01"); } int image_offset_x, image_offset_y; - for (int i = 0; i < buttons; i++) { + for (unsigned int i = 0; i < buttons; i++) { int permission = granary_distribution_permissions_buttons[i].parameter1; int is_sea_trade_route = permission == BUILDING_STORAGE_PERMISSION_DOCK; int permission_state = building_storage_get_permission(permission, building_get(data.building_id)); @@ -329,7 +329,7 @@ static void init_dock_permission_buttons(void) static void draw_dock_permission_buttons(int x_offset, int y_offset, int dock_id) { - for (int i = 0; i < dock_distribution_permissions_buttons_count; i++) { + for (unsigned int i = 0; i < dock_distribution_permissions_buttons_count; i++) { if (i < scrollbar.scroll_position || i - scrollbar.scroll_position >= data.dock_max_cities_visible) { continue; } @@ -456,7 +456,7 @@ static int count_food_types_in_stock(building *b) int count = 0; const resource_list *list = city_resource_get_potential_foods(); - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { resource_type r = list->items[i]; if (resource_is_inventory(r) && b->resources[r] > 0) { count++; @@ -471,7 +471,7 @@ static void draw_food_stocks(building_info_context *c, building *b, int y_offset const resource_list *list = city_resource_get_potential_foods(); int food_type_index = 0; - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { resource_type r = list->items[i]; if (!resource_is_inventory(r) || b->resources[r] <= 0) { continue; @@ -552,12 +552,12 @@ void window_building_distributor_draw_foreground(building_info_context *c) static void set_distributed_resources(building_type type) { - for (int i = 0; i < data.stored_resources.size; i++) { + for (unsigned int i = 0; i < data.stored_resources.size; i++) { data.stored_resources.items[i] = RESOURCE_NONE; } data.stored_resources.size = 0; const resource_list *list = city_resource_get_potential(); - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { if (building_distribution_resource_is_handled(list->items[i], type)) { data.stored_resources.items[data.stored_resources.size++] = list->items[i]; } @@ -634,7 +634,7 @@ void window_building_draw_distributor_orders_foreground(building_info_context *c int scrollbar_shown = scrollbar.max_scroll_position > 0; - for (int i = 0; i < scrollbar.elements_in_view && i < data.stored_resources.size; i++) { + for (unsigned int i = 0; i < scrollbar.elements_in_view && i < data.stored_resources.size; i++) { resource_type resource = data.stored_resources.items[i + scrollbar.scroll_position]; int image_id = resource_get_data(resource)->image.icon; image_draw(image_id, c->x_offset + 32, y_offset + 46 + 22 * i, COLOR_MASK_NONE, SCALE_NONE); @@ -750,7 +750,7 @@ void window_building_draw_granary(building_info_context *c) int y = c->y_offset + 31; int food_offset = 0; const resource_list *list = city_resource_get_potential_foods(); - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { resource_type r = list->items[i]; if (!resource_is_inventory(r) || b->resources[r] <= 0) { continue; @@ -795,7 +795,7 @@ void window_building_draw_granary(building_info_context *c) } else if (f->loads_sold_or_carrying) { text_draw_multiline(translation_for(TR_WINDOW_BUILDING_DISTRIBUTION_CART_PUSHER_RETURNING_WITH), c->x_offset + 64, c->y_offset + y_offset + 63, - BLOCK_SIZE * (c->width_blocks - 5), FONT_NORMAL_BROWN, 0); + BLOCK_SIZE * (c->width_blocks - 5), 0, FONT_NORMAL_BROWN, 0); } else { lang_text_draw_multiline(99, 17, c->x_offset + 64, c->y_offset + y_offset + 63, BLOCK_SIZE * (c->width_blocks - 5), FONT_NORMAL_BROWN); @@ -803,7 +803,7 @@ void window_building_draw_granary(building_info_context *c) } else { text_draw_multiline(translation_for(TR_WINDOW_BUILDING_DISTRIBUTION_GRANARY_CART_PUSHER_GETTING), c->x_offset + 64, c->y_offset + y_offset + 63, - BLOCK_SIZE * (c->width_blocks - 5), FONT_NORMAL_BROWN, 0); + BLOCK_SIZE * (c->width_blocks - 5), 0, FONT_NORMAL_BROWN, 0); } } else if (b->num_workers) { // cartpusher is waiting for orders @@ -916,7 +916,7 @@ static void draw_resource_orders_buttons(int x, int y, const resource_list *list { int scrollbar_shown = scrollbar.max_scroll_position > 0; - for (int i = 0; i < scrollbar.elements_in_view && i < list->size - scrollbar.scroll_position; i++) { + for (unsigned int i = 0; i < scrollbar.elements_in_view && i < list->size - scrollbar.scroll_position; i++) { resource_type resource = list->items[i + scrollbar.scroll_position]; int image_id = resource_get_data(resource)->image.icon; int y_offset = y + 22 * i; @@ -965,7 +965,7 @@ int window_building_handle_mouse_granary_orders(const mouse *m, building_info_co data.building_id = c->building_id; - int buttons_to_show = city_resource_get_potential_foods()->size < scrollbar.elements_in_view ? + unsigned int buttons_to_show = city_resource_get_potential_foods()->size < scrollbar.elements_in_view ? city_resource_get_potential_foods()->size : scrollbar.elements_in_view; return scrollbar_handle_mouse(&scrollbar, m, 1) || @@ -990,7 +990,7 @@ void window_building_get_tooltip_granary_orders(int *group_id, int *text_id, int static void generate_warehouse_resource_list(building *warehouse) { - for (int i = 0; i < data.stored_resources.size; i++) { + for (unsigned int i = 0; i < data.stored_resources.size; i++) { data.stored_resources.items[i] = RESOURCE_NONE; } data.stored_resources.size = 0; @@ -1042,7 +1042,7 @@ void window_building_draw_warehouse(building_info_context *c) int total_stored = 0; int x; int y = c->y_offset + 31; - for (int i = 0; i < data.stored_resources.size; i++) { + for (unsigned int i = 0; i < data.stored_resources.size; i++) { if (i & 1) { x = c->x_offset + 240; } else { @@ -1085,7 +1085,7 @@ void window_building_draw_warehouse(building_info_context *c) } else if (f->loads_sold_or_carrying) { text_draw_multiline(translation_for(TR_WINDOW_BUILDING_DISTRIBUTION_CART_PUSHER_RETURNING_WITH), c->x_offset + 64, c->y_offset + y_offset + 63, - BLOCK_SIZE * (c->width_blocks - 5), FONT_NORMAL_BROWN, 0); + BLOCK_SIZE * (c->width_blocks - 5), 0, FONT_NORMAL_BROWN, 0); } else { lang_text_draw_multiline(99, 17, c->x_offset + 64, c->y_offset + y_offset + 63, BLOCK_SIZE * (c->width_blocks - 5), FONT_NORMAL_BROWN); @@ -1094,7 +1094,8 @@ void window_building_draw_warehouse(building_info_context *c) image_draw(resource_get_data(f->collecting_item_id)->image.icon, c->x_offset + 32, c->y_offset + y_offset + 60, COLOR_MASK_NONE, SCALE_NONE); text_draw_multiline(translation_for(TR_WINDOW_BUILDING_DISTRIBUTION_CART_PUSHER_GETTING), - c->x_offset + 64, c->y_offset + y_offset + 63, BLOCK_SIZE * (c->width_blocks - 5), FONT_NORMAL_BROWN, 0); + c->x_offset + 64, c->y_offset + y_offset + 63, BLOCK_SIZE * (c->width_blocks - 5), + 0, FONT_NORMAL_BROWN, 0); } } else if (b->num_workers) { // cartpusher is waiting for orders @@ -1196,7 +1197,7 @@ int window_building_handle_mouse_warehouse_orders(const mouse *m, building_info_ data.building_id = c->building_id; - int buttons_to_show = city_resource_get_potential()->size < scrollbar.elements_in_view ? + unsigned int buttons_to_show = city_resource_get_potential()->size < scrollbar.elements_in_view ? city_resource_get_potential()->size : scrollbar.elements_in_view; return scrollbar_handle_mouse(&scrollbar, m, 1) || @@ -1245,7 +1246,7 @@ const uint8_t *window_building_dock_get_tooltip(building_info_context *c) int height = 20; const mouse *m = mouse_get(); - for (int i = 0; i < dock_distribution_permissions_buttons_count; i++) { + for (unsigned int i = 0; i < dock_distribution_permissions_buttons_count; i++) { if (i < scrollbar.scroll_position || i - scrollbar.scroll_position >= data.dock_max_cities_visible) { continue; } @@ -1481,17 +1482,17 @@ void window_building_draw_mess_hall(building_info_context *c) if (city_mess_hall_food_types() == 2) { text_draw_multiline(translation_for(TR_BUILDING_MESS_HALL_FOOD_TYPES_BONUS_1), c->x_offset + 32, - c->y_offset + 175 + y_offset, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->y_offset + 175 + y_offset, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); } else if (city_mess_hall_food_types() >= 3) { text_draw_multiline(translation_for(TR_BUILDING_MESS_HALL_FOOD_TYPES_BONUS_2), c->x_offset + 32, - c->y_offset + 175 + y_offset, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->y_offset + 175 + y_offset, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); } } else { text_draw_centered(translation_for(TR_BUILDING_MESS_HALL_NO_SOLDIERS), c->x_offset, c->y_offset + 150 + y_offset, BLOCK_SIZE * (c->width_blocks), FONT_NORMAL_BLACK, 0); } text_draw_multiline(translation_for(TR_BUILDING_MESS_HALL_DESC), c->x_offset + 32, c->y_offset + 226 + y_offset, - BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); inner_panel_draw(c->x_offset + 16, c->y_offset + 308 + y_offset, c->width_blocks - 2, 4); window_building_draw_employment(c, 308 + y_offset); @@ -1560,10 +1561,10 @@ void window_building_draw_caravanserai(building_info_context *c) } if (building_monument_has_labour_problems(b)) { text_draw_multiline(translation_for(TR_BUILDING_CARAVANSERAI_NEEDS_WORKERS), - c->x_offset + 22, c->y_offset + 80 + y_offset, 15 * c->width_blocks, FONT_NORMAL_BLACK, 0); + c->x_offset + 22, c->y_offset + 80 + y_offset, 15 * c->width_blocks, 0, FONT_NORMAL_BLACK, 0); } else { text_draw_multiline(translation_for(TR_BUILDING_CARAVANSERAI_DESC), c->x_offset + 32, - c->y_offset + 80 + y_offset, BLOCK_SIZE * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->y_offset + 80 + y_offset, BLOCK_SIZE * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); } if (!land_trade_policy.items[0].image_id) { int base_policy_image = assets_get_image_id("UI", @@ -1577,10 +1578,10 @@ void window_building_draw_caravanserai(building_info_context *c) trade_policy policy = city_trade_policy_get(LAND_TRADE_POLICY); text_draw_multiline(translation_for(land_trade_policy.items[policy].header), - c->x_offset + 160, c->y_offset + 156 + y_offset, 260, FONT_NORMAL_BLACK, 0); + c->x_offset + 160, c->y_offset + 156 + y_offset, 260, 0, FONT_NORMAL_BLACK, 0); if (policy != NO_POLICY) { text_draw_multiline(translation_for(land_trade_policy.items[policy].desc), - c->x_offset + 160, c->y_offset + 181 + y_offset, 260, FONT_NORMAL_BLACK, 0); + c->x_offset + 160, c->y_offset + 181 + y_offset, 260, 0, FONT_NORMAL_BLACK, 0); } image_draw(land_trade_policy.items[policy].image_id, c->x_offset + 32, c->y_offset + 150 + y_offset, COLOR_MASK_NONE, SCALE_NONE); diff --git a/src/window/building/figures.c b/src/window/building/figures.c index 558541a881..50c9d34989 100644 --- a/src/window/building/figures.c +++ b/src/window/building/figures.c @@ -44,7 +44,7 @@ static const int FIGURE_TYPE_TO_BIG_FIGURE_IMAGE[] = { 8, 8, 34, 39, 33, 43, 27, 48, 63, 8, //50-59 8, 8, 8, 8, 53, 8, 38, 62, 54, 55, //60-69 56, 8, 8, 58, 0, 7, 50, 0, 14, 3, //70-79 - 3, 58, 50, 0, 0, 3, 15, 15, 0, 3, //80-89 + 3, 58, 50, 0, 0, 3, 15, 15, 0, 51, //80-89 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, //90-99 }; // Starting with FIGURE_WORK_CAMP_WORKER = 73, @@ -70,8 +70,8 @@ static generic_button depot_figure_buttons[] = { static struct { int figure_images[7]; - int focus_button_id; - int depot_focus_button_id; + unsigned int focus_button_id; + unsigned int depot_focus_button_id; building_info_context *context_for_callback; } data; @@ -79,9 +79,9 @@ static int big_people_image(figure_type type) { switch (type) { case FIGURE_WORK_CAMP_SLAVE: - case FIGURE_LIGHTHOUSE_SUPPLIER: return assets_get_image_id("Walkers", "Slave Portrait"); case FIGURE_CARAVANSERAI_SUPPLIER: + return assets_get_image_id("Walkers", "caravanserai_overseer_portrait"); case FIGURE_CARAVANSERAI_COLLECTOR: return assets_get_image_id("Walkers", "caravanserai_walker_portrait"); case FIGURE_MESS_HALL_COLLECTOR: @@ -99,9 +99,11 @@ static int big_people_image(figure_type type) case FIGURE_DEPOT_CART_PUSHER: return assets_lookup_image_id(ASSET_OX); case FIGURE_MARKET_SUPPLIER: - return assets_get_image_id("Walkers", "marketbuyer_portrait_overlay"); + return assets_get_image_id("Walkers", "marketbuyer_portrait"); case FIGURE_WORK_CAMP_ARCHITECT: return assets_get_image_id("Walkers", "architect_portrait"); + case FIGURE_WORK_CAMP_WORKER: + return assets_get_image_id("Walkers", "overseer_portrait"); default: break; } @@ -325,8 +327,12 @@ static void draw_cartpusher(building_info_context *c, figure *f) image_draw(big_people_image(f->type), c->x_offset + 28, c->y_offset + 112, COLOR_MASK_NONE, SCALE_NONE); } lang_text_draw(65, f->name, c->x_offset + 90, c->y_offset + 108, FONT_LARGE_BROWN); - int width = lang_text_draw(64, f->type, c->x_offset + 92, c->y_offset + 139, FONT_NORMAL_BROWN); - + int width = 0; + if (building_get(f->building_id)->type == BUILDING_ARMOURY) { + width = text_draw(translation_for(TR_FIGURE_TYPE_ARMORY_CARTPUSHER), c->x_offset + 92, c->y_offset + 139, FONT_NORMAL_BROWN, 0); + } else { + width = lang_text_draw(64, f->type, c->x_offset + 92, c->y_offset + 139, FONT_NORMAL_BROWN); + } if (f->action_state != FIGURE_ACTION_132_DOCKER_IDLING && f->resource_id) { int resource = f->resource_id; image_draw(resource_get_data(resource)->image.icon, @@ -613,7 +619,7 @@ int window_building_handle_mouse_figure_list(const mouse *m, building_info_conte figure *f = figure_get(c->figure.figure_ids[c->figure.selected_index]); if (f->type == FIGURE_DEPOT_CART_PUSHER && !is_depot_cartpusher_recalled(f)) { depot_figure_buttons[0].parameter1 = f->id; - int focus_id = data.depot_focus_button_id; + unsigned int focus_id = data.depot_focus_button_id; generic_buttons_handle_mouse(m, c->x_offset, c->y_offset, depot_figure_buttons, 1, &data.depot_focus_button_id); if (focus_id != data.depot_focus_button_id) { window_request_refresh(); diff --git a/src/window/building/house.c b/src/window/building/house.c index 62272de8f9..574705bf98 100644 --- a/src/window/building/house.c +++ b/src/window/building/house.c @@ -157,7 +157,7 @@ void window_building_draw_house(building_info_context *c) int total_food_types = 0; int total_food_amount = 0; if (list->size > 4) { - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { resource_type r = list->items[i]; if (resource_is_inventory(r) && b->resources[r]) { total_food_types++; @@ -172,7 +172,7 @@ void window_building_draw_house(building_info_context *c) FONT_NORMAL_BROWN, 0); x_offset += text_draw(string_from_ascii("("), c->x_offset + x_offset, c->y_offset + y_content, FONT_NORMAL_BROWN, 0); - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { resource_type r = list->items[i]; if (!resource_is_inventory(r) || !b->resources[r]) { continue; @@ -187,7 +187,7 @@ void window_building_draw_house(building_info_context *c) text_draw(string_from_ascii(")"), c->x_offset + x_offset, c->y_offset + y_content, FONT_NORMAL_BROWN, 0); } else { - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { resource_type r = list->items[i]; if (!resource_is_inventory(r) || (list->size > 4 && !b->resources[r])) { continue; @@ -264,7 +264,7 @@ const uint8_t *window_building_house_get_tooltip(const building_info_context *c) int total_food_types = 0; if (list->size > 4) { - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { resource_type r = list->items[i]; if (resource_is_inventory(r) && b->resources[r]) { total_food_types++; @@ -276,7 +276,7 @@ const uint8_t *window_building_house_get_tooltip(const building_info_context *c) } static uint8_t text[400]; uint8_t *cursor = text; - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { resource_type r = list->items[i]; if (resource_is_inventory(r) && b->resources[r]) { if (cursor != text) { diff --git a/src/window/building/industry.c b/src/window/building/industry.c index fc61f215f3..0feb5e1d1a 100644 --- a/src/window/building/industry.c +++ b/src/window/building/industry.c @@ -36,7 +36,7 @@ static generic_button mint_conversion_buttons[] = { static struct { int city_mint_id; - int focus_button_id; + unsigned int focus_button_id; } data; static void draw_farm(building_info_context *c, int help_id, const char *sound_file, int group_id, int resource) diff --git a/src/window/building/military.c b/src/window/building/military.c index afa639c8de..658286cb31 100644 --- a/src/window/building/military.c +++ b/src/window/building/military.c @@ -55,20 +55,20 @@ static generic_button return_button[] = { }; static struct { - int focus_button_id; - int focus_priority_button_id; - int focus_delivery_button_id; - int return_button_id; + unsigned int focus_button_id; + unsigned int focus_priority_button_id; + unsigned int focus_delivery_button_id; + unsigned int return_button_id; int building_id; building_info_context *context_for_callback; } data; -static void draw_priority_buttons(int x, int y, int buttons, int building_id) +static void draw_priority_buttons(int x, int y, unsigned int buttons, int building_id) { int base_priority_image_id = assets_get_image_id("UI", "Barracks_Priority_Legionaries_OFF"); data.building_id = building_id; - for (int i = 0; i < buttons; i++) { + for (unsigned int i = 0; i < buttons; i++) { int has_focus = 0; if (data.focus_priority_button_id) { if (data.focus_priority_button_id - 1 == i) { @@ -79,7 +79,7 @@ static void draw_priority_buttons(int x, int y, int buttons, int building_id) int y_adj = y + priority_buttons[i].y; building *barracks = building_get(data.building_id); - int priority = building_barracks_get_priority(barracks); + unsigned int priority = building_barracks_get_priority(barracks); if (has_focus || priority == i) { button_border_draw(x_adj - 3, y_adj - 3, 46, 46, 1); @@ -180,10 +180,10 @@ void window_building_draw_barracks(building_info_context *c) } if (city_data.mess_hall.food_stress_cumulative > 50) { text_draw_multiline(translation_for(TR_BUILDING_BARRACKS_FOOD_WARNING_2), - c->x_offset + 32, c->y_offset + 106, 16 * c->width_blocks - 30, FONT_NORMAL_BLACK, 0); + c->x_offset + 32, c->y_offset + 106, 16 * c->width_blocks - 30, 0, FONT_NORMAL_BLACK, 0); } else if (city_data.mess_hall.food_stress_cumulative > 20) { text_draw_multiline(translation_for(TR_BUILDING_BARRACKS_FOOD_WARNING), - c->x_offset + 32, c->y_offset + 106, 16 * c->width_blocks - 30, FONT_NORMAL_BLACK, 0); + c->x_offset + 32, c->y_offset + 106, 16 * c->width_blocks - 30, 0, FONT_NORMAL_BLACK, 0); } else if (c->worker_percentage >= 100) { window_building_draw_description_at(c, 106, 136, 5 + offset); } else if (c->worker_percentage >= 66) { @@ -458,7 +458,7 @@ void window_building_draw_legion_info_foreground(building_info_context *c) if (!m->num_figures) { return; } - for (int i = 5 - c->formation_types; i < 5; i++) { + for (unsigned int i = 5 - c->formation_types; i < 5; i++) { int has_focus = 0; if (data.focus_button_id) { if (data.focus_button_id - 1 == i) { @@ -710,10 +710,10 @@ void window_building_draw_watchtower(building_info_context *c) building *b = building_get(c->building_id); if (!b->figure_id4) { text_draw_multiline(translation_for(TR_BUILDING_WATCHTOWER_DESC_NO_SOLDIERS), - c->x_offset + 32, c->y_offset + 76, 16 * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 32, c->y_offset + 76, 16 * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); } else { text_draw_multiline(translation_for(TR_BUILDING_WATCHTOWER_DESC), - c->x_offset + 32, c->y_offset + 76, 16 * (c->width_blocks - 4), FONT_NORMAL_BLACK, 0); + c->x_offset + 32, c->y_offset + 76, 16 * (c->width_blocks - 4), 0, FONT_NORMAL_BLACK, 0); } } inner_panel_draw(c->x_offset + 16, c->y_offset + 136, c->width_blocks - 2, 4); diff --git a/src/window/building/utility.c b/src/window/building/utility.c index 33391625b5..6a6fd2ef0f 100644 --- a/src/window/building/utility.c +++ b/src/window/building/utility.c @@ -23,9 +23,9 @@ static void roadblock_orders(int index, int param2); static struct { - int focus_button_id; - int orders_focus_button_id; - int figure_focus_button_id; + unsigned int focus_button_id; + unsigned int orders_focus_button_id; + unsigned int figure_focus_button_id; int building_id; int tooltip_id; } data = { 0, 0, 0, 0, 0 }; @@ -65,7 +65,7 @@ static generic_button roadblock_orders_buttons[] = { {309, 0, 20, 20, roadblock_orders, button_none, 1, 0 }, }; -static int size_of_orders_permission_buttons = sizeof(orders_permission_buttons) / sizeof(*orders_permission_buttons); +static unsigned int size_of_orders_permission_buttons = sizeof(orders_permission_buttons) / sizeof(*orders_permission_buttons); typedef enum { REJECT_ALL = 0, @@ -207,7 +207,7 @@ void window_building_draw_roadblock_orders_foreground(building_info_context *c) data.building_id = b->id; draw_roadblock_orders_buttons(c->x_offset + 365, y_offset + 404, data.orders_focus_button_id == 1); - for (int i = 0; i < size_of_orders_permission_buttons; i++) { + for (unsigned int i = 0; i < size_of_orders_permission_buttons; i++) { image_draw(image_group(ids[i * 2]) + 4, c->x_offset + 32, y_offset + 46 + 32 * i, COLOR_MASK_NONE, SCALE_NONE); image_draw(image_group(ids[i * 2 + 1]) + 4, c->x_offset + 64, y_offset + 46 + 32 * i, COLOR_MASK_NONE, SCALE_NONE); diff --git a/src/window/building_info.c b/src/window/building_info.c index 35c1d21bcb..03da32e44f 100644 --- a/src/window/building_info.c +++ b/src/window/building_info.c @@ -74,9 +74,9 @@ static generic_button generic_button_monument_construction[] = { }; static building_info_context context; -static int focus_image_button_id; -static int focus_mothball_image_button_id; -static int focus_monument_construction_button_id; +static unsigned int focus_image_button_id; +static unsigned int focus_mothball_image_button_id; +static unsigned int focus_monument_construction_button_id; static int original_overlay; static int get_height_id(void) diff --git a/src/window/cck_selection.c b/src/window/cck_selection.c index 8c6be0d6ce..96e1cf7339 100644 --- a/src/window/cck_selection.c +++ b/src/window/cck_selection.c @@ -31,7 +31,7 @@ #define BACKGROUND_WIDTH 1024 #define BACKGROUND_HEIGHT 768 -static void select_scenario(int index, int is_double_click); +static void select_scenario(unsigned int index, int is_double_click); static void button_start_scenario(int param1, int param2); static void button_back(int param1, int param2); static void button_toggle_minimap(int param1, int param2); @@ -61,7 +61,7 @@ static list_box_type list_box = { }; static struct { - int focus_toggle_button; + unsigned int focus_toggle_button; int show_minimap; char selected_scenario_filename[FILE_NAME_MAX]; uint8_t selected_scenario_display[FILE_NAME_MAX]; @@ -72,7 +72,7 @@ static struct { static void init(void) { - data.scenarios = dir_find_files_with_extension(".", "map"); + data.scenarios = dir_find_files_with_extension_at_location(PATH_LOCATION_SCENARIO, "map"); data.scenarios = dir_append_files_with_extension("mapx"); data.focus_toggle_button = 0; data.show_minimap = 0; @@ -272,11 +272,14 @@ static void button_back(int param1, int param2) window_go_back(); } -static void select_scenario(int index, int is_double_click) +static void select_scenario(unsigned int index, int is_double_click) { if (strcmp(data.selected_scenario_filename, data.scenarios->files[index].name) != 0) { - strcpy(data.selected_scenario_filename, data.scenarios->files[index].name); - game_file_io_read_scenario_info(data.selected_scenario_filename, &data.info); + snprintf(data.selected_scenario_filename, FILE_NAME_MAX, "%s", data.scenarios->files[index].name); + const char *filename = dir_get_file_at_location(data.selected_scenario_filename, PATH_LOCATION_SCENARIO); + if (filename) { + game_file_io_read_scenario_info(filename, &data.info); + } encoding_from_utf8(data.selected_scenario_filename, data.selected_scenario_display, FILE_NAME_MAX); file_remove_extension((char *) data.selected_scenario_display); window_invalidate(); diff --git a/src/window/config.c b/src/window/config.c index 601e651a40..84a8909e48 100644 --- a/src/window/config.c +++ b/src/window/config.c @@ -29,12 +29,13 @@ #include "window/plain_message_dialog.h" #include "window/select_list.h" #include "window/text_input.h" +#include "window/user_path_setup.h" -#include +#include #include #define MAX_LANGUAGE_DIRS 20 -#define MAX_WIDGETS 30 +#define MAX_WIDGETS 32 #define NUM_VISIBLE_ITEMS 13 @@ -58,12 +59,14 @@ static void on_scroll(void); static void toggle_switch(int key); static void button_language_select(int height, int param2); static void button_edit_player_name(int param1, int param2); +static void button_change_user_directory(int param1, int param2); static void button_reset_defaults(int param1, int param2); static void button_hotkeys(int param1, int param2); static void button_close(int save, int param2); static void button_page(int page, int param2); static const uint8_t *display_text_language(void); +static const uint8_t *display_text_user_directory(void); static const uint8_t *display_text_player_name(void); static const uint8_t *display_text_game_speed(void); static const uint8_t *display_text_resolution(void); @@ -95,7 +98,8 @@ enum { enum { SELECT_LANGUAGE, - SELECT_PLAYER_NAME + SELECT_PLAYER_NAME, + SELECT_USER_DIRECTORY }; enum { @@ -162,6 +166,8 @@ typedef struct { static config_widget all_widgets[CONFIG_PAGES][MAX_WIDGETS] = { { // General Settings + {TYPE_SELECT, SELECT_USER_DIRECTORY, TR_USER_DIRETORIES_WINDOW_USER_PATH, display_text_user_directory}, + {TYPE_SPACE}, {TYPE_SELECT, SELECT_LANGUAGE, TR_CONFIG_LANGUAGE_LABEL, display_text_language}, {TYPE_SPACE}, {TYPE_SELECT, SELECT_PLAYER_NAME, TR_CONFIG_DEFAULT_PLAYER_NAME, display_text_player_name}, @@ -268,6 +274,7 @@ static resolution available_resolutions[sizeof(resolutions) / sizeof(resolution) static generic_button select_buttons[] = { {225, 0, 200, 24, button_language_select, button_none}, {225, 0, 200, 24, button_edit_player_name, button_none}, + {225, 0, 200, 24, button_change_user_directory, button_none}, }; static numerical_range_widget ranges[] = { @@ -310,22 +317,22 @@ static translation_key page_names[CONFIG_PAGES] = { static struct { config_widget *widgets[MAX_WIDGETS * CONFIG_PAGES]; - int num_widgets; - int focus_button; - int bottom_focus_button; - int page_focus_button; - int page; - int widgets_per_page[CONFIG_PAGES]; + unsigned int num_widgets; + unsigned int focus_button; + unsigned int bottom_focus_button; + unsigned int page_focus_button; + unsigned int page; + unsigned int widgets_per_page[CONFIG_PAGES]; int starting_option; struct { int original_value; int new_value; - int (*change_action)(config_key key); + int (*change_action)(int key); } config_values[CONFIG_MAX_ALL]; struct { char original_value[CONFIG_STRING_VALUE_MAX]; char new_value[CONFIG_STRING_VALUE_MAX]; - int (*change_action)(config_string_key key); + int (*change_action)(int key); } config_string_values[CONFIG_STRING_MAX_ALL]; struct { const uint8_t *options[MAX_LANGUAGE_DIRS]; @@ -345,33 +352,33 @@ static struct { int graphics_behind_tab[CONFIG_PAGES]; } data; -static int config_change_basic(config_key key); -static int config_change_string_basic(config_string_key key); +static int config_change_basic(int key); +static int config_change_string_basic(int key); -static int config_change_string_language(config_string_key key); -static int config_change_string_player_name(config_string_key key); +static int config_change_string_language(int key); +static int config_change_string_player_name(int key); -static int config_change_game_speed(config_key key); -static int config_change_fullscreen(config_key key); -static int config_change_display_resolution(config_key key); -static int config_change_display_scale(config_key key); -static int config_change_cursors(config_key key); +static int config_change_game_speed(int key); +static int config_change_fullscreen(int key); +static int config_change_display_resolution(int key); +static int config_change_display_scale(int key); +static int config_change_cursors(int key); -static int config_enable_audio(config_key key); -static int config_set_master_volume(config_key key); -static int config_enable_music(config_key key); -static int config_set_music_volume(config_key key); -static int config_enable_speech(config_key key); -static int config_set_speech_volume(config_key key); -static int config_enable_effects(config_key key); -static int config_set_effects_volume(config_key key); -static int config_enable_city_sounds(config_key key); -static int config_set_city_sounds_volume(config_key key); +static int config_enable_audio(int key); +static int config_set_master_volume(int key); +static int config_enable_music(int key); +static int config_set_music_volume(int key); +static int config_enable_speech(int key); +static int config_set_speech_volume(int key); +static int config_enable_effects(int key); +static int config_set_effects_volume(int key); +static int config_enable_city_sounds(int key); +static int config_set_city_sounds_volume(int key); -static int config_change_scroll_speed(config_key key); +static int config_change_scroll_speed(int key); -static int config_set_difficulty(config_key key); -static int config_enable_gods_effects(config_key key); +static int config_set_difficulty(int key); +static int config_enable_gods_effects(int key); static inline void set_custom_config_changes(void) { @@ -482,8 +489,8 @@ static void fetch_original_config_values(void) string_copy(player_name, data.player_name, PLAYER_NAME_LENGTH); encoding_to_utf8(data.player_name, data.config_string_values[CONFIG_STRING_ORIGINAL_PLAYER_NAME].original_value, PLAYER_NAME_LENGTH, 0); - strncpy(data.config_string_values[CONFIG_STRING_ORIGINAL_PLAYER_NAME].new_value, - data.config_string_values[CONFIG_STRING_ORIGINAL_PLAYER_NAME].original_value, PLAYER_NAME_LENGTH); + snprintf(data.config_string_values[CONFIG_STRING_ORIGINAL_PLAYER_NAME].new_value, CONFIG_STRING_VALUE_MAX, "%s", + data.config_string_values[CONFIG_STRING_ORIGINAL_PLAYER_NAME].original_value); set_player_name_width(); } @@ -540,7 +547,7 @@ static void set_page(int page) { data.page = page; data.starting_option = 0; - for (int i = 0; i < data.page; i++) { + for (unsigned int i = 0; i < data.page; i++) { data.starting_option += data.widgets_per_page[i]; } scrollbar_init(&scrollbar, 0, data.widgets_per_page[page]); @@ -563,8 +570,8 @@ static void init(int page, int show_background_image) } for (int i = 0; i < CONFIG_STRING_MAX_ENTRIES; i++) { const char *value = config_get_string(i); - strncpy(data.config_string_values[i].original_value, value, CONFIG_STRING_VALUE_MAX - 1); - strncpy(data.config_string_values[i].new_value, value, CONFIG_STRING_VALUE_MAX - 1); + snprintf(data.config_string_values[i].original_value, CONFIG_STRING_VALUE_MAX, "%s", value); + snprintf(data.config_string_values[i].new_value, CONFIG_STRING_VALUE_MAX, "%s", value); } fetch_original_config_values(); @@ -578,7 +585,7 @@ static void init(int page, int show_background_image) for (int i = 0; i < subdirs->num_files; i++) { if (data.language_options.total < MAX_LANGUAGE_DIRS && lang_dir_is_valid(subdirs->files[i].name)) { int opt_id = data.language_options.total; - strncpy(data.language_options.data_utf8[opt_id], subdirs->files[i].name, CONFIG_STRING_VALUE_MAX - 1); + snprintf(data.language_options.data_utf8[opt_id], CONFIG_STRING_VALUE_MAX, "%s", subdirs->files[i].name); encoding_from_utf8(subdirs->files[i].name, data.language_options.data[opt_id], CONFIG_STRING_VALUE_MAX); data.language_options.options[opt_id] = data.language_options.data[opt_id]; if (strcmp(original_value, subdirs->files[i].name) == 0) { @@ -653,6 +660,11 @@ static const uint8_t *display_text_language(void) return data.language_options.options[data.language_options.selected]; } +static const uint8_t *display_text_user_directory(void) +{ + return translation_for(TR_USER_DIRECTORIES_WINDOW_TITLE); +} + static const uint8_t *display_text_player_name(void) { return data.player_name; @@ -849,7 +861,7 @@ static void draw_background(void) int page_x_offset = 30; int open_tab_width = text_get_width(translation_for(page_names[data.page]), FONT_NORMAL_BLACK) + 6; int max_closed_tab_width = (600 - page_x_offset * CONFIG_PAGES - open_tab_width) / (CONFIG_PAGES - 1); - for (int i = 0; i < CONFIG_PAGES; ++i) { + for (unsigned int i = 0; i < CONFIG_PAGES; ++i) { page_x_offset += 15; int width = 0; if (data.page == i) { @@ -867,7 +879,7 @@ static void draw_background(void) button_border_draw(10, 75, 620, 355, 0); - for (int i = 0; i < NUM_VISIBLE_ITEMS && i < data.widgets_per_page[data.page]; i++) { + for (unsigned int i = 0; i < NUM_VISIBLE_ITEMS && i < data.widgets_per_page[data.page]; i++) { config_widget *w = data.widgets[i + data.starting_option + scrollbar.scroll_position]; int y = ITEM_Y_OFFSET + ITEM_HEIGHT * i; if (w->type == TYPE_HEADER) { @@ -902,7 +914,7 @@ static void draw_foreground(void) { graphics_in_dialog(); - for (int i = 0; i < CONFIG_PAGES; ++i) { + for (unsigned int i = 0; i < CONFIG_PAGES; ++i) { button_border_draw(page_buttons[i].x, page_buttons[i].y, page_buttons[i].width, page_buttons[i].height, data.page_focus_button == i + 1); @@ -913,7 +925,7 @@ static void draw_foreground(void) } } - for (int i = 0; i < NUM_VISIBLE_ITEMS && i < data.widgets_per_page[data.page]; i++) { + for (unsigned int i = 0; i < NUM_VISIBLE_ITEMS && i < data.widgets_per_page[data.page]; i++) { config_widget *w = data.widgets[i + data.starting_option + scrollbar.scroll_position]; int y = ITEM_Y_OFFSET + ITEM_HEIGHT * i; if (w->type == TYPE_CHECKBOX) { @@ -946,7 +958,7 @@ static int is_checkbox(const mouse *m, int x, int y) return 0; } -static int checkbox_handle_mouse(const mouse *m, int x, int y, int value_key, int *focus) +static int checkbox_handle_mouse(const mouse *m, int x, int y, int value_key, unsigned int *focus) { if (!is_checkbox(m, x, y)) { return 0; @@ -1023,11 +1035,11 @@ static void handle_input(const mouse *m, const hotkeys *h) } int handled = 0; - for (int i = 0; i < NUM_VISIBLE_ITEMS && i < data.widgets_per_page[data.page]; i++) { + for (unsigned int i = 0; i < NUM_VISIBLE_ITEMS && i < data.widgets_per_page[data.page]; i++) { config_widget *w = data.widgets[i + data.starting_option + scrollbar.scroll_position]; int y = ITEM_Y_OFFSET + ITEM_HEIGHT * i; if (w->type == TYPE_CHECKBOX) { - int focus = 0; + unsigned int focus = 0; handled |= checkbox_handle_mouse(m_dialog, 20, y + w->y_offset, w->subtype, &focus); if (focus) { data.focus_button = i + 1; @@ -1035,7 +1047,7 @@ static void handle_input(const mouse *m, const hotkeys *h) } else if (w->type == TYPE_SELECT) { generic_button *btn = &select_buttons[w->subtype]; btn->parameter1 = y + w->y_offset; - int focus = 0; + unsigned int focus = 0; handled |= generic_buttons_handle_mouse(m_dialog, 0, y + w->y_offset, btn, 1, &focus); if (focus) { data.focus_button = i + 1; @@ -1069,7 +1081,7 @@ static void toggle_switch(int key) static void set_language(int index) { const char *dir = index == 0 ? "" : data.language_options.data_utf8[index]; - strncpy(data.config_string_values[CONFIG_STRING_UI_LANGUAGE_DIR].new_value, dir, CONFIG_STRING_VALUE_MAX - 1); + snprintf(data.config_string_values[CONFIG_STRING_UI_LANGUAGE_DIR].new_value, CONFIG_STRING_VALUE_MAX, "%s", dir); data.language_options.selected = index; } @@ -1110,14 +1122,19 @@ static void button_edit_player_name(int param1, int param2) PLAYER_NAME_LENGTH, set_player_name); } +static void button_change_user_directory(int param1, int param2) +{ + window_user_path_setup_show(0); +} + static void button_reset_defaults(int param1, int param2) { for (int i = 0; i < CONFIG_MAX_ENTRIES; ++i) { data.config_values[i].new_value = config_get_default_value(i); } for (int i = 0; i < CONFIG_STRING_MAX_ENTRIES; ++i) { - strncpy(data.config_string_values[i].new_value, - config_get_default_string_value(i), CONFIG_STRING_VALUE_MAX - 1); + snprintf(data.config_string_values[i].new_value, CONFIG_STRING_VALUE_MAX, "%s", + config_get_default_string_value(i)); } set_language(0); window_invalidate(); @@ -1130,13 +1147,12 @@ static void cancel_values(void) data.config_values[i].new_value = data.config_values[i].original_value; } for (int i = 0; i < CONFIG_STRING_MAX_ALL; i++) { - // memcpy required to fix warning on Switch build - memcpy(data.config_string_values[i].new_value, - data.config_string_values[i].original_value, CONFIG_STRING_VALUE_MAX - 1); + memcpy(data.config_string_values[i].new_value, data.config_string_values[i].original_value, + CONFIG_STRING_VALUE_MAX); } } -static int config_change_basic(config_key key) +static int config_change_basic(int key) { if (key < CONFIG_MAX_ENTRIES) { config_set(key, data.config_values[key].new_value); @@ -1145,7 +1161,7 @@ static int config_change_basic(config_key key) return 1; } -static int config_change_game_speed(config_key key) +static int config_change_game_speed(int key) { config_change_basic(key); @@ -1160,7 +1176,7 @@ static int config_change_game_speed(config_key key) return 1; } -static int config_change_fullscreen(config_key key) +static int config_change_fullscreen(int key) { if (!system_is_fullscreen_only()) { system_set_fullscreen(data.config_values[key].new_value); @@ -1174,7 +1190,7 @@ static int config_change_fullscreen(config_key key) return 1; } -static int config_change_display_resolution(config_key key) +static int config_change_display_resolution(int key) { if (!system_is_fullscreen_only()) { const resolution *r = &available_resolutions[data.config_values[key].new_value]; @@ -1191,7 +1207,7 @@ static int config_change_display_resolution(config_key key) return 1; } -static int config_change_display_scale(config_key key) +static int config_change_display_scale(int key) { data.config_values[key].new_value = system_scale_display(data.config_values[key].new_value); config_change_basic(key); @@ -1206,14 +1222,14 @@ static void restart_cursors(void) } } -static int config_change_cursors(config_key key) +static int config_change_cursors(int key) { config_change_basic(key); data.reload_cursors = 1; return 1; } -static int config_enable_audio(config_key key) +static int config_enable_audio(int key) { config_change_basic(key); if (data.config_values[key].new_value) { @@ -1230,7 +1246,7 @@ static int config_enable_audio(config_key key) return 1; } -static int config_set_master_volume(config_key key) +static int config_set_master_volume(int key) { config_change_basic(key); sound_music_set_volume(setting_sound(SOUND_MUSIC)->volume); @@ -1240,7 +1256,7 @@ static int config_set_master_volume(config_key key) return 1; } -static int config_enable_music(config_key key) +static int config_enable_music(int key) { config_change_basic(key); @@ -1260,7 +1276,7 @@ static int config_enable_music(config_key key) return 1; } -static int config_set_music_volume(config_key key) +static int config_set_music_volume(int key) { config_change_basic(key); setting_set_sound_volume(SOUND_MUSIC, data.config_values[key].new_value); @@ -1268,7 +1284,7 @@ static int config_set_music_volume(config_key key) return 1; } -static int config_enable_speech(config_key key) +static int config_enable_speech(int key) { config_change_basic(key); @@ -1281,7 +1297,7 @@ static int config_enable_speech(config_key key) return 1; } -static int config_set_speech_volume(config_key key) +static int config_set_speech_volume(int key) { config_change_basic(key); setting_set_sound_volume(SOUND_SPEECH, data.config_values[key].new_value); @@ -1289,7 +1305,7 @@ static int config_set_speech_volume(config_key key) return 1; } -static int config_enable_effects(config_key key) +static int config_enable_effects(int key) { config_change_basic(key); @@ -1299,7 +1315,7 @@ static int config_enable_effects(config_key key) return 1; } -static int config_set_effects_volume(config_key key) +static int config_set_effects_volume(int key) { config_change_basic(key); setting_set_sound_volume(SOUND_EFFECTS, data.config_values[key].new_value); @@ -1307,7 +1323,7 @@ static int config_set_effects_volume(config_key key) return 1; } -static int config_enable_city_sounds(config_key key) +static int config_enable_city_sounds(int key) { config_change_basic(key); @@ -1317,7 +1333,7 @@ static int config_enable_city_sounds(config_key key) return 1; } -static int config_set_city_sounds_volume(config_key key) +static int config_set_city_sounds_volume(int key) { config_change_basic(key); setting_set_sound_volume(SOUND_CITY, data.config_values[key].new_value); @@ -1325,7 +1341,7 @@ static int config_set_city_sounds_volume(config_key key) return 1; } -static int config_change_scroll_speed(config_key key) +static int config_change_scroll_speed(int key) { config_change_basic(key); @@ -1338,7 +1354,7 @@ static int config_change_scroll_speed(config_key key) return 1; } -static int config_set_difficulty(config_key key) +static int config_set_difficulty(int key) { config_change_basic(key); @@ -1351,7 +1367,7 @@ static int config_set_difficulty(config_key key) return 1; } -static int config_enable_gods_effects(config_key key) +static int config_enable_gods_effects(int key) { config_change_basic(key); @@ -1361,15 +1377,15 @@ static int config_enable_gods_effects(config_key key) return 1; } -static int config_change_string_basic(config_string_key key) +static int config_change_string_basic(int key) { config_set_string(key, data.config_string_values[key].new_value); - strncpy(data.config_string_values[key].original_value, - data.config_string_values[key].new_value, CONFIG_STRING_VALUE_MAX - 1); + memcpy(data.config_string_values[key].original_value, data.config_string_values[key].new_value, + CONFIG_STRING_VALUE_MAX); return 1; } -static int config_change_string_language(config_string_key key) +static int config_change_string_language(int key) { config_set_string(CONFIG_STRING_UI_LANGUAGE_DIR, data.config_string_values[key].new_value); if (!game_reload_language()) { @@ -1383,8 +1399,8 @@ static int config_change_string_language(config_string_key key) encoding_to_utf8(lang_get_string(9, 0), title, 100, 0); system_change_window_title(title); - strncpy(data.config_string_values[key].original_value, - data.config_string_values[key].new_value, CONFIG_STRING_VALUE_MAX - 1); + memcpy(data.config_string_values[key].original_value, data.config_string_values[key].new_value, + CONFIG_STRING_VALUE_MAX); string_copy(translation_for(TR_CONFIG_LANGUAGE_DEFAULT), data.language_options.data[0], CONFIG_STRING_VALUE_MAX); data.volume_offset = string_copy(translation_for(TR_CONFIG_VOLUME), data.volume_text, 63); @@ -1394,13 +1410,13 @@ static int config_change_string_language(config_string_key key) return 1; } -static int config_change_string_player_name(config_string_key key) +static int config_change_string_player_name(int key) { uint8_t player_name[PLAYER_NAME_LENGTH]; encoding_from_utf8(data.config_string_values[key].new_value, player_name, PLAYER_NAME_LENGTH); setting_set_player_name(player_name); - strncpy(data.config_string_values[key].original_value, - data.config_string_values[key].new_value, PLAYER_NAME_LENGTH); + memcpy(data.config_string_values[key].original_value, data.config_string_values[key].new_value, + CONFIG_STRING_VALUE_MAX); return 1; } @@ -1451,7 +1467,7 @@ static void button_page(int page, int param2) static void get_tooltip(tooltip_context *c) { if (data.page_focus_button) { - int page = data.page_focus_button - 1; + unsigned int page = data.page_focus_button - 1; if (page == data.page) { return; } diff --git a/src/window/console.c b/src/window/console.c index 4e1d692941..2bf82d07cb 100644 --- a/src/window/console.c +++ b/src/window/console.c @@ -76,7 +76,7 @@ static void send_command(int param1, int param2) game_cheat_parse_command(command_copy); } -void window_console_show() +void window_console_show(void) { window_type window = { WINDOW_FILE_DIALOG, @@ -86,4 +86,4 @@ void window_console_show() }; init(); window_show(&window); -} \ No newline at end of file +} diff --git a/src/window/console.h b/src/window/console.h index 867fa740df..2d97bdd0da 100644 --- a/src/window/console.h +++ b/src/window/console.h @@ -2,4 +2,5 @@ #define WINDOW_CONSOLE_H void window_console_show(void); -#endif // WINDOW_CONSOLE_H \ No newline at end of file + +#endif // WINDOW_CONSOLE_H diff --git a/src/window/donate_to_city.c b/src/window/donate_to_city.c index 4578977b04..682d2225ae 100644 --- a/src/window/donate_to_city.c +++ b/src/window/donate_to_city.c @@ -35,8 +35,8 @@ static arrow_button arrow_buttons[] = { }; static struct { - int focus_button_id; - int focus_arrow_button_id; + unsigned int focus_button_id; + unsigned int focus_arrow_button_id; } data; static void draw_background(void) diff --git a/src/window/editor/allowed_buildings.c b/src/window/editor/allowed_buildings.c index 36ee83b467..ed88b4f4aa 100644 --- a/src/window/editor/allowed_buildings.c +++ b/src/window/editor/allowed_buildings.c @@ -2,9 +2,9 @@ #include "graphics/button.h" #include "graphics/color.h" -#include "graphics/generic_button.h" #include "graphics/graphics.h" #include "graphics/lang_text.h" +#include "graphics/list_box.h" #include "graphics/panel.h" #include "graphics/window.h" #include "input/input.h" @@ -12,100 +12,59 @@ #include "window/editor/attributes.h" #include "window/editor/map.h" -static void toggle_building(int id, int param2); +static void draw_allowed_building(const list_box_item *item); +static void toggle_building(unsigned int id, int param2); -static generic_button buttons[] = { - {25, 82, 190, 18, toggle_building, button_none, 1, 0}, - {25, 102, 190, 18, toggle_building, button_none, 2, 0}, - {25, 122, 190, 18, toggle_building, button_none, 3, 0}, - {25, 142, 190, 18, toggle_building, button_none, 4, 0}, - {25, 162, 190, 18, toggle_building, button_none, 5, 0}, - {25, 182, 190, 18, toggle_building, button_none, 6, 0}, - {25, 202, 190, 18, toggle_building, button_none, 7, 0}, - {25, 222, 190, 18, toggle_building, button_none, 8, 0}, - {25, 242, 190, 18, toggle_building, button_none, 9, 0}, - {25, 262, 190, 18, toggle_building, button_none, 10, 0}, - {25, 282, 190, 18, toggle_building, button_none, 11, 0}, - {25, 302, 190, 18, toggle_building, button_none, 12, 0}, - {25, 322, 190, 18, toggle_building, button_none, 13, 0}, - {25, 342, 190, 18, toggle_building, button_none, 14, 0}, - {25, 362, 190, 18, toggle_building, button_none, 15, 0}, - {25, 382, 190, 18, toggle_building, button_none, 16, 0}, - {224, 82, 190, 18, toggle_building, button_none, 17, 0}, - {224, 102, 190, 18, toggle_building, button_none, 18, 0}, - {224, 122, 190, 18, toggle_building, button_none, 19, 0}, - {224, 142, 190, 18, toggle_building, button_none, 20, 0}, - {224, 162, 190, 18, toggle_building, button_none, 21, 0}, - {224, 182, 190, 18, toggle_building, button_none, 22, 0}, - {224, 202, 190, 18, toggle_building, button_none, 23, 0}, - {224, 222, 190, 18, toggle_building, button_none, 24, 0}, - {224, 242, 190, 18, toggle_building, button_none, 25, 0}, - {224, 262, 190, 18, toggle_building, button_none, 26, 0}, - {224, 282, 190, 18, toggle_building, button_none, 27, 0}, - {224, 302, 190, 18, toggle_building, button_none, 28, 0}, - {224, 322, 190, 18, toggle_building, button_none, 29, 0}, - {224, 342, 190, 18, toggle_building, button_none, 30, 0}, - {224, 362, 190, 18, toggle_building, button_none, 31, 0}, - {224, 382, 190, 18, toggle_building, button_none, 32, 0}, - {423, 82, 190, 18, toggle_building, button_none, 33, 0}, - {423, 102, 190, 18, toggle_building, button_none, 34, 0}, - {423, 122, 190, 18, toggle_building, button_none, 35, 0}, - {423, 142, 190, 18, toggle_building, button_none, 36, 0}, - {423, 162, 190, 18, toggle_building, button_none, 37, 0}, - {423, 182, 190, 18, toggle_building, button_none, 38, 0}, - {423, 202, 190, 18, toggle_building, button_none, 39, 0}, - {423, 222, 190, 18, toggle_building, button_none, 40, 0}, - {423, 242, 190, 18, toggle_building, button_none, 41, 0}, - {423, 262, 190, 18, toggle_building, button_none, 42, 0}, - {423, 282, 190, 18, toggle_building, button_none, 43, 0}, - {423, 302, 190, 18, toggle_building, button_none, 44, 0}, - {423, 322, 190, 18, toggle_building, button_none, 45, 0}, - {423, 342, 190, 18, toggle_building, button_none, 46, 0}, - {423, 362, 190, 18, toggle_building, button_none, 47, 0}, - {423, 382, 190, 18, toggle_building, button_none, 48, 0}, +static list_box_type allowed_building_list = { + .x = 25, + .y = 82, + .width_blocks = 36, + .height_blocks = 20, + .item_height = 20, + .num_columns = 3, + .extend_to_hidden_scrollbar = 1, + .draw_item = draw_allowed_building, + .on_select = toggle_building }; -static int focus_button_id; - static void draw_background(void) { window_editor_map_draw_all(); -} -static void draw_foreground(void) -{ graphics_in_dialog(); outer_panel_draw(16, 32, 38, 26); - lang_text_draw(44, 47, 26, 42, FONT_LARGE_BLACK); lang_text_draw_centered(13, 3, 16, 424, 608, FONT_NORMAL_BLACK); - for (int i = 1; i <= 48; i++) { - int x, y; - if (i <= 16) { - x = 25; - y = 82 + 20 * (i - 1); - } else if (i <= 32) { - x = 224; - y = 82 + 20 * (i - 17); - } else { - x = 423; - y = 82 + 20 * (i - 33); - } - button_border_draw(x, y, 190, 18, focus_button_id == i); - if (scenario_editor_is_building_allowed(i)) { - lang_text_draw_centered(67, i, x, y + 4, 190, FONT_NORMAL_BLACK); - } else { - lang_text_draw_centered_colored(67, i, x, y + 4, 190, FONT_NORMAL_PLAIN, COLOR_FONT_RED); - } + + graphics_reset_dialog(); + + list_box_request_refresh(&allowed_building_list); +} + +static void draw_allowed_building(const list_box_item *item) +{ + button_border_draw(item->x + 5, item->y + 1, item->width - 10, item->height - 2, item->is_focused); + if (scenario_editor_is_building_allowed(item->index + 1)) { + lang_text_draw_centered(67, item->index + 1, item->x + 5, item->y + 5, item->width - 10, FONT_NORMAL_BLACK); + } else { + lang_text_draw_centered_colored(67, item->index + 1, item->x + 5, item->y + 5, item->width - 10, + FONT_NORMAL_PLAIN, COLOR_FONT_RED); } +} + +static void draw_foreground(void) +{ + graphics_in_dialog(); + + list_box_draw(&allowed_building_list); graphics_reset_dialog(); } static void handle_input(const mouse *m, const hotkeys *h) { - if (generic_buttons_handle_mouse(mouse_in_dialog(m), 0, 0, buttons, 48, &focus_button_id)) { + if (list_box_handle_input(&allowed_building_list, mouse_in_dialog(m), 1)) { return; } if (input_go_back_requested(m, h)) { @@ -113,9 +72,10 @@ static void handle_input(const mouse *m, const hotkeys *h) } } -void toggle_building(int id, int param2) +void toggle_building(unsigned int id, int param2) { - scenario_editor_toggle_building_allowed(id); + scenario_editor_toggle_building_allowed(id + 1); + list_box_request_refresh(&allowed_building_list); } void window_editor_allowed_buildings_show(void) @@ -126,5 +86,6 @@ void window_editor_allowed_buildings_show(void) draw_foreground, handle_input }; + list_box_init(&allowed_building_list, 48); window_show(&window); } diff --git a/src/window/editor/attributes.c b/src/window/editor/attributes.c index 2af2917ad8..31a004782a 100644 --- a/src/window/editor/attributes.c +++ b/src/window/editor/attributes.c @@ -84,7 +84,7 @@ static arrow_button image_arrows[] = { static struct { int is_paused; uint8_t brief_description[BRIEF_DESC_LENGTH]; - int focus_button_id; + unsigned int focus_button_id; } data; static input_box scenario_description_input = { diff --git a/src/window/editor/build_menu.c b/src/window/editor/build_menu.c index 7cef93d375..e1e0e3cdbd 100644 --- a/src/window/editor/build_menu.c +++ b/src/window/editor/build_menu.c @@ -55,16 +55,15 @@ static const int MENU_TYPES[MENU_NUM_ITEMS][MAX_ITEMS_PER_MENU] = { static struct { int selected_submenu; - int num_items; + unsigned int num_items; int y_offset; - - int focus_button_id; + unsigned int focus_button_id; } data = {MENU_NONE}; static int count_items(int submenu) { int count = 0; - for (int i = 0; i < MAX_ITEMS_PER_MENU && MENU_TYPES[submenu][i] >= 0; i++) { + for (unsigned int i = 0; i < MAX_ITEMS_PER_MENU && MENU_TYPES[submenu][i] >= 0; i++) { count++; } return count; @@ -92,7 +91,7 @@ static int get_sidebar_x_offset(void) static void draw_menu_buttons(void) { int x_offset = get_sidebar_x_offset(); - for (int i = 0; i < data.num_items; i++) { + for (unsigned int i = 0; i < data.num_items; i++) { label_draw(x_offset - MENU_X_OFFSET, data.y_offset + MENU_Y_OFFSET + MENU_ITEM_HEIGHT * i, 10, data.focus_button_id == i + 1 ? 1 : 2); lang_text_draw_centered(48, MENU_TYPES[data.selected_submenu][i], x_offset - MENU_X_OFFSET, @@ -113,7 +112,7 @@ static int click_outside_menu(const mouse *m, int x_offset) (m->x < x_offset - MENU_X_OFFSET - MENU_CLICK_MARGIN || m->x > x_offset + MENU_CLICK_MARGIN || m->y < data.y_offset + MENU_Y_OFFSET - MENU_CLICK_MARGIN || - m->y > data.y_offset + MENU_Y_OFFSET + MENU_CLICK_MARGIN + MENU_ITEM_HEIGHT * data.num_items); + m->y > data.y_offset + MENU_Y_OFFSET + MENU_CLICK_MARGIN + MENU_ITEM_HEIGHT * (int) data.num_items); } static int handle_build_submenu(const mouse *m) diff --git a/src/window/editor/custom_messages.c b/src/window/editor/custom_messages.c index e5b33b3bea..b652eb79ca 100644 --- a/src/window/editor/custom_messages.c +++ b/src/window/editor/custom_messages.c @@ -58,9 +58,8 @@ static generic_button buttons[] = { #define MAX_BUTTONS (sizeof(buttons) / sizeof(generic_button)) static struct { - int focus_button_id; - - int total_messages; + unsigned int focus_button_id; + unsigned int total_messages; custom_message_t *list[MAX_VISIBLE_ROWS]; } data; @@ -81,7 +80,7 @@ static void populate_list(int offset) offset = 0; } for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { - int target_id = i + offset + 1; // Skip entry zero custom message + unsigned int target_id = i + offset + 1; // Skip entry zero custom message if (target_id <= data.total_messages) { data.list[i] = custom_messages_get(target_id); } else { @@ -105,7 +104,7 @@ static void draw_foreground(void) text_draw_label_and_number(translation_for(TR_EDITOR_CUSTOM_MESSAGES_COUNT), data.total_messages, "", 48, 106, FONT_NORMAL_PLAIN, COLOR_BLACK); int y_offset = MESSAGES_Y_OFFSET; - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { if (data.list[i]) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / BLOCK_SIZE, data.focus_button_id == i + 1 ? 1 : 0); diff --git a/src/window/editor/custom_variables.c b/src/window/editor/custom_variables.c index 76a48a2d27..58642f2c34 100644 --- a/src/window/editor/custom_variables.c +++ b/src/window/editor/custom_variables.c @@ -66,7 +66,7 @@ static generic_button buttons[] = { #define MAX_BUTTONS (sizeof(buttons) / sizeof(generic_button)) static struct { - int focus_button_id; + unsigned int focus_button_id; int target_variable; custom_variable_t *list[MAX_VISIBLE_ROWS]; @@ -116,8 +116,8 @@ static void draw_foreground(void) text_draw_label_and_number(translation_for(TR_EDITOR_CUSTOM_VARIABLES_COUNT), MAX_CUSTOM_VARIABLES, "", 48, 106, FONT_NORMAL_PLAIN, COLOR_BLACK); - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { - int j = (i * 2); + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { + unsigned int j = (i * 2); if (data.list[i]) { large_label_draw(buttons[j].x, buttons[j].y, buttons[j].width / BLOCK_SIZE, data.focus_button_id == j + 1); @@ -183,12 +183,6 @@ static void button_name_click(int button_index, int param2) return; }; - scenario_event_t *event = scenario_events_get_using_custom_variable(data.list[button_index]->id); - if (event) { - show_used_event_popup_dialog(event); - return; - } - int has_name = data.list[button_index]->linked_uid && data.list[button_index]->linked_uid->in_use; if (data.select_only) { if (!has_name) { @@ -197,6 +191,11 @@ static void button_name_click(int button_index, int param2) data.callback(data.list[button_index]); window_go_back(); } else { + scenario_event_t *event = scenario_events_get_using_custom_variable(data.list[button_index]->id); + if (event) { + show_used_event_popup_dialog(event); + return; + } data.target_variable = data.list[button_index]->id; static uint8_t text_input_title[100]; uint8_t *cursor = string_copy(translation_for(TR_PARAMETER_TYPE_CUSTOM_VARIABLE), text_input_title, 100); diff --git a/src/window/editor/demand_changes.c b/src/window/editor/demand_changes.c index 4ac0a15294..074b9b45a4 100644 --- a/src/window/editor/demand_changes.c +++ b/src/window/editor/demand_changes.c @@ -44,7 +44,7 @@ static generic_button buttons[] = { {320, 312, 290, 25, button_demand_change, button_none, 19, 0}, }; -static int focus_button_id; +static unsigned int focus_button_id; static void draw_background(void) { @@ -90,7 +90,7 @@ static void draw_foreground(void) lang_text_draw(44, 94, 20, 14, FONT_LARGE_BLACK); lang_text_draw_centered(13, 3, 0, 342, 640, FONT_NORMAL_BLACK); - for (int i = 0; i < MAX_DEMAND_CHANGES; i++) { + for (unsigned int i = 0; i < MAX_DEMAND_CHANGES; i++) { int x, y; if (i < 10) { x = 20; diff --git a/src/window/editor/edit_demand_change.c b/src/window/editor/edit_demand_change.c index b875b461a1..57a400d418 100644 --- a/src/window/editor/edit_demand_change.c +++ b/src/window/editor/edit_demand_change.c @@ -46,10 +46,10 @@ static const uint8_t NA[4] = { 'N', '/', 'A', 0 }; static struct { int id; editor_demand_change demand_change; - int focus_button_id; + unsigned int focus_button_id; int *route_ids; const uint8_t **route_names; - int num_routes; + unsigned int num_routes; resource_type available_resources[RESOURCE_MAX]; } data; @@ -73,7 +73,7 @@ static void create_route_info(int route_id, const uint8_t *city_name) static void init(int id) { data.id = id; - for (int i = 0; i < data.num_routes; i++) { + for (unsigned int i = 0; i < data.num_routes; i++) { free((uint8_t *) data.route_names[i]); } free(data.route_ids); @@ -117,7 +117,7 @@ static const uint8_t *get_text_for_route_id(int route_id) if (route_id == 0) { return data.route_names[0]; } - for (int i = 0; i < data.num_routes; i++) { + for (unsigned int i = 0; i < data.num_routes; i++) { if (data.route_ids[i] == route_id) { return data.route_names[i]; } diff --git a/src/window/editor/edit_invasion.c b/src/window/editor/edit_invasion.c index badcbf1816..a5cccf3177 100644 --- a/src/window/editor/edit_invasion.c +++ b/src/window/editor/edit_invasion.c @@ -38,7 +38,7 @@ static generic_button buttons[] = { static struct { int id; editor_invasion invasion; - int focus_button_id; + unsigned int focus_button_id; } data; static void init(int id) diff --git a/src/window/editor/edit_price_change.c b/src/window/editor/edit_price_change.c index c813e06b26..40f311ec77 100644 --- a/src/window/editor/edit_price_change.c +++ b/src/window/editor/edit_price_change.c @@ -36,7 +36,7 @@ static generic_button buttons[] = { static struct { int id; editor_price_change price_change; - int focus_button_id; + unsigned int focus_button_id; resource_type available_resources[RESOURCE_MAX]; } data; diff --git a/src/window/editor/edit_request.c b/src/window/editor/edit_request.c index d1febd2011..3a59b49af8 100644 --- a/src/window/editor/edit_request.c +++ b/src/window/editor/edit_request.c @@ -44,7 +44,7 @@ static generic_button buttons[] = { static struct { int id; editor_request request; - int focus_button_id; + unsigned int focus_button_id; resource_type avaialble_resources[RESOURCE_MAX]; } data; diff --git a/src/window/editor/empire.c b/src/window/editor/empire.c index 1011b5066e..ff8e57af9f 100644 --- a/src/window/editor/empire.c +++ b/src/window/editor/empire.c @@ -51,16 +51,16 @@ static generic_button preview_button[] = { }; static struct { - int selected_button; + unsigned int selected_button; int selected_city; int x_min, x_max, y_min, y_max; int x_draw_offset, y_draw_offset; - int focus_button_id; + unsigned int focus_button_id; int is_scrolling; int finished_scroll; int show_battle_objects; int preview_image_group; - int preview_button_focused; + unsigned int preview_button_focused; struct { int x; int y; @@ -508,7 +508,11 @@ static void refresh_empire(void) if (scenario.empire.id != SCENARIO_CUSTOM_EMPIRE) { return; } - empire_xml_parse_file(scenario.empire.custom_name); + const char *filename = dir_get_file_at_location(scenario.empire.custom_name, PATH_LOCATION_EDITOR_CUSTOM_EMPIRES); + if (!filename) { + return; + } + empire_xml_parse_file(filename); window_invalidate(); } diff --git a/src/window/editor/invasions.c b/src/window/editor/invasions.c index ad58925d6b..56c495bad2 100644 --- a/src/window/editor/invasions.c +++ b/src/window/editor/invasions.c @@ -38,7 +38,7 @@ static generic_button buttons[] = { {320, 312, 290, 25, button_invasion, button_none, 19, 0}, }; -static int focus_button_id; +static unsigned int focus_button_id; static void draw_background(void) { @@ -54,7 +54,7 @@ static void draw_foreground(void) lang_text_draw_centered(13, 3, 0, 456, 640, FONT_NORMAL_BLACK); lang_text_draw_multiline(152, 2, 32, 376, 576, FONT_NORMAL_BLACK); - for (int i = 0; i < 20; i++) { + for (unsigned int i = 0; i < 20; i++) { int x, y; if (i < 10) { x = 20; diff --git a/src/window/editor/price_changes.c b/src/window/editor/price_changes.c index 6d859dba33..2cf8d657fe 100644 --- a/src/window/editor/price_changes.c +++ b/src/window/editor/price_changes.c @@ -42,7 +42,7 @@ static generic_button buttons[] = { {320, 312, 290, 25, button_price_change, button_none, 19, 0}, }; -static int focus_button_id; +static unsigned int focus_button_id; static void draw_background(void) { @@ -58,7 +58,7 @@ static void draw_foreground(void) lang_text_draw_centered(13, 3, 0, 456, 640, FONT_NORMAL_BLACK); lang_text_draw_multiline(152, 3, 32, 376, 576, FONT_NORMAL_BLACK); - for (int i = 0; i < 20; i++) { + for (unsigned int i = 0; i < 20; i++) { int x, y; if (i < 10) { x = 20; diff --git a/src/window/editor/requests.c b/src/window/editor/requests.c index 32403352ba..bba39d6bbf 100644 --- a/src/window/editor/requests.c +++ b/src/window/editor/requests.c @@ -42,7 +42,7 @@ static generic_button buttons[] = { {320, 312, 290, 25, button_request, button_none, 19, 0}, }; -static int focus_button_id; +static unsigned int focus_button_id; static void draw_background(void) { @@ -58,7 +58,7 @@ static void draw_foreground(void) lang_text_draw_centered(13, 3, 0, 456, 640, FONT_NORMAL_BLACK); lang_text_draw_multiline(152, 1, 32, 376, 576, FONT_NORMAL_BLACK); - for (int i = 0; i < 20; i++) { + for (unsigned int i = 0; i < 20; i++) { int x, y; if (i < 10) { x = 20; diff --git a/src/window/editor/scenario_action_edit.c b/src/window/editor/scenario_action_edit.c index 33bd637b28..56fd53e820 100644 --- a/src/window/editor/scenario_action_edit.c +++ b/src/window/editor/scenario_action_edit.c @@ -52,7 +52,7 @@ static generic_button buttons[] = { #define MAX_BUTTONS (sizeof(buttons) / sizeof(generic_button)) static struct { - int focus_button_id; + unsigned int focus_button_id; int parameter_being_edited; int parameter_being_edited_current_value; @@ -86,7 +86,7 @@ static void draw_foreground(void) outer_panel_draw(0, 0, 42, 24); - for (int i = 5; i <= 6; i++) { + for (unsigned int i = 5; i <= 6; i++) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i + 1 ? 1 : 0); } @@ -94,7 +94,7 @@ static void draw_foreground(void) text_draw_centered(translation_for(data.xml_info->xml_attr.key), 32, 72, BUTTON_WIDTH, FONT_NORMAL_GREEN, COLOR_MASK_NONE); - int button_id = 0; + unsigned int button_id = 0; if (data.xml_info->xml_parm1.type > PARAMETER_TYPE_UNDEFINED) { large_label_draw(buttons[button_id].x, buttons[button_id].y, buttons[button_id].width / 16, data.focus_button_id == button_id + 1 ? 1 : 0); diff --git a/src/window/editor/scenario_condition_edit.c b/src/window/editor/scenario_condition_edit.c index 6fb08142f2..05143ec2db 100644 --- a/src/window/editor/scenario_condition_edit.c +++ b/src/window/editor/scenario_condition_edit.c @@ -52,7 +52,7 @@ static generic_button buttons[] = { #define MAX_BUTTONS (sizeof(buttons) / sizeof(generic_button)) static struct { - int focus_button_id; + unsigned int focus_button_id; int parameter_being_edited; int parameter_being_edited_current_value; @@ -86,7 +86,7 @@ static void draw_foreground(void) outer_panel_draw(0, 0, 42, 24); - for (int i = 5; i <= 6; i++) { + for (unsigned int i = 5; i <= 6; i++) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i + 1 ? 1 : 0); } @@ -94,7 +94,7 @@ static void draw_foreground(void) text_draw_centered(translation_for(data.xml_info->xml_attr.key), 32, 72, BUTTON_WIDTH, FONT_NORMAL_GREEN, COLOR_MASK_NONE); - int button_id = 0; + unsigned int button_id = 0; if (data.xml_info->xml_parm1.type > PARAMETER_TYPE_UNDEFINED) { large_label_draw(buttons[button_id].x, buttons[button_id].y, buttons[button_id].width / 16, data.focus_button_id == button_id + 1 ? 1 : 0); diff --git a/src/window/editor/scenario_event_details.c b/src/window/editor/scenario_event_details.c index 6b48c1bc91..9c66288b8b 100644 --- a/src/window/editor/scenario_event_details.c +++ b/src/window/editor/scenario_event_details.c @@ -41,7 +41,7 @@ enum { static void init(int event_id); static void init_scroll_list(void); static void on_scroll(void); -static void button_click(int param1, int param2); +static void button_click(int index, int param2); static void button_amount(int param1, int param2); static void button_add(int param1, int param2); static void button_delete_event(int param1, int param2); @@ -97,10 +97,10 @@ typedef struct { } sub_item_entry_t; static struct { - int focus_button_id; - int total_sub_items; - int conditions_count; - int actions_count; + unsigned int focus_button_id; + unsigned int total_sub_items; + unsigned int conditions_count; + unsigned int actions_count; scenario_event_t *event; @@ -117,7 +117,7 @@ static void populate_list(int offset) offset = 0; } for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { - int target_id = i + offset; + unsigned int target_id = i + offset; if (target_id < data.conditions_count) { int condition_id = target_id; sub_item_entry_t entry; @@ -220,10 +220,10 @@ static void draw_foreground(void) outer_panel_draw(0, 0, 42, 38); - for (int i = 0; i < 4; i++) { + for (unsigned int i = 0; i < 4; i++) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i + 1 ? 1 : 0); } - for (int i = 14; i < 16; i++) { + for (unsigned int i = 14; i < 16; i++) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i + 1 ? 1 : 0); } @@ -272,7 +272,7 @@ static void draw_foreground(void) y_offset = DETAILS_Y_OFFSET; int i_button_offset = 4; - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { if (data.list[i].sub_type != SUB_ITEM_TYPE_UNDEFINED) { large_label_draw(buttons[i + i_button_offset].x, buttons[i + i_button_offset].y, buttons[i + i_button_offset].width / 16, data.focus_button_id == i + i_button_offset + 1 ? 1 : 0); @@ -366,20 +366,20 @@ static void button_delete_event(int param1, int param2) window_go_back(); } -static void button_click(int param1, int param2) +static void button_click(int index, int param2) { - if (param1 > MAX_VISIBLE_ROWS || - param1 >= data.total_sub_items) { + if (index > MAX_VISIBLE_ROWS || + index >= (int) data.total_sub_items) { return; } - if (data.list[param1].sub_type == SUB_ITEM_TYPE_ACTION) { - scenario_action_t *action = scenario_event_get_action(data.event, data.list[param1].id); + if (data.list[index].sub_type == SUB_ITEM_TYPE_ACTION) { + scenario_action_t *action = scenario_event_get_action(data.event, data.list[index].id); if (action->type != ACTION_TYPE_UNDEFINED) { window_editor_scenario_action_edit_show(action); } } else { - scenario_condition_t *condition = scenario_event_get_condition(data.event, data.list[param1].id); + scenario_condition_t *condition = scenario_event_get_condition(data.event, data.list[index].id); if (condition->type != CONDITION_TYPE_UNDEFINED) { window_editor_scenario_condition_edit_show(condition); } diff --git a/src/window/editor/scenario_events.c b/src/window/editor/scenario_events.c index 32ce1fdc3b..178c9fdf81 100644 --- a/src/window/editor/scenario_events.c +++ b/src/window/editor/scenario_events.c @@ -60,9 +60,8 @@ static generic_button buttons[] = { #define MAX_BUTTONS (sizeof(buttons) / sizeof(generic_button)) static struct { - int focus_button_id; - - int total_events; + unsigned int focus_button_id; + unsigned int total_events; scenario_event_t *list[MAX_VISIBLE_ROWS]; } data; @@ -89,7 +88,7 @@ static void populate_list(int offset) offset = 0; } for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { - int target_id = i + offset; + unsigned int target_id = i + offset; if (target_id < data.total_events) { data.list[i] = scenario_event_get(target_id); } else { @@ -134,7 +133,7 @@ static void draw_foreground(void) text_draw_label_and_number(translation_for(TR_EDITOR_SCENARIO_EVENTS_COUNT), data.total_events, "", 48, 106, FONT_NORMAL_PLAIN, COLOR_BLACK); - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { if (data.list[i]) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i + 1 ? 1 : 0); diff --git a/src/window/editor/select_city_by_type.c b/src/window/editor/select_city_by_type.c index c6bf98b41a..84266d9cca 100644 --- a/src/window/editor/select_city_by_type.c +++ b/src/window/editor/select_city_by_type.c @@ -29,7 +29,7 @@ #define INITIAL_ID_LIST_SIZE 20 static void on_scroll(void); -static void button_click(int param1, int param2); +static void button_click(int index, int param2); static const uint8_t UNKNOWN[4] = { '?', '?', '?', 0 }; @@ -60,9 +60,9 @@ typedef struct { } list_item_entry_t; static struct { - int focus_button_id; + unsigned int focus_button_id; empire_city_type filter_type; - int list_size; + unsigned int list_size; void (*callback)(int); int *valid_city_ids; @@ -78,7 +78,7 @@ static void populate_list(int offset) if (offset < 0) { offset = 0; } - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { int target_id = data.valid_city_ids[i + offset]; if (i + offset < data.list_size) { data.list[i].city_id = target_id; @@ -145,7 +145,7 @@ static void draw_foreground(void) outer_panel_draw(16, 16, 42, 33); int y_offset = DETAILS_Y_OFFSET; - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { if (i < data.list_size) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i + 1 ? 1 : 0); if (data.focus_button_id == (i + 1)) { @@ -182,13 +182,13 @@ static void handle_input(const mouse *m, const hotkeys *h) populate_list(scrollbar.scroll_position); } -static void button_click(int param1, int param2) +static void button_click(int index, int param2) { - if (param1 >= data.list_size) { + if (index >= (int) data.list_size) { return; } - data.callback(data.list[param1].city_id); + data.callback(data.list[index].city_id); close(); } diff --git a/src/window/editor/select_city_trade_route.c b/src/window/editor/select_city_trade_route.c index e1033713db..03cc098528 100644 --- a/src/window/editor/select_city_trade_route.c +++ b/src/window/editor/select_city_trade_route.c @@ -27,7 +27,7 @@ #define MAX_VISIBLE_ROWS 14 static void on_scroll(void); -static void button_click(int param1, int param2); +static void button_click(int index, int param2); static const uint8_t UNKNOWN[4] = { '?', '?', '?', 0 }; @@ -58,8 +58,8 @@ typedef struct { } list_item_entry_t; static struct { - int focus_button_id; - int list_size; + unsigned int focus_button_id; + unsigned int list_size; void (*callback)(int); list_item_entry_t list[MAX_VISIBLE_ROWS]; @@ -74,7 +74,7 @@ static void populate_list(int offset) offset = 0; } for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { - int target_id = i + offset + 1; + unsigned int target_id = i + offset + 1; if (target_id < data.list_size) { data.list[i].route_id = target_id; int city_id = empire_city_get_for_trade_route(target_id); @@ -114,7 +114,7 @@ static void draw_foreground(void) outer_panel_draw(16, 16, 42, 33); int y_offset = DETAILS_Y_OFFSET; - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { if (i < data.list_size - 1) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i + 1 ? 1 : 0); if (data.focus_button_id == (i + 1)) { @@ -151,13 +151,13 @@ static void handle_input(const mouse *m, const hotkeys *h) populate_list(scrollbar.scroll_position); } -static void button_click(int param1, int param2) +static void button_click(int index, int param2) { - if (param1 >= data.list_size) { + if (index >= (int) data.list_size) { return; } - data.callback(data.list[param1].route_id); + data.callback(data.list[index].route_id); window_go_back(); } diff --git a/src/window/editor/select_custom_message.c b/src/window/editor/select_custom_message.c index 928893620f..b53587c4d5 100644 --- a/src/window/editor/select_custom_message.c +++ b/src/window/editor/select_custom_message.c @@ -49,9 +49,9 @@ static generic_button buttons[] = { #define MAX_BUTTONS (sizeof(buttons) / sizeof(generic_button)) static struct { - int focus_button_id; + unsigned int focus_button_id; - int total_messages; + unsigned int total_messages; void (*callback)(int); custom_message_t *list[MAX_VISIBLE_ROWS]; } data; @@ -73,8 +73,8 @@ static void populate_list(int offset) if (offset < 0) { offset = 0; } - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { - int target_id = i + offset + 1; // Skip entry zero custom message + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { + unsigned int target_id = i + offset + 1; // Skip entry zero custom message if (target_id <= data.total_messages) { data.list[i] = custom_messages_get(target_id); } else { @@ -98,7 +98,7 @@ static void draw_foreground(void) text_draw_label_and_number(translation_for(TR_EDITOR_CUSTOM_MESSAGES_COUNT), data.total_messages, "", 48, 106, FONT_NORMAL_PLAIN, COLOR_BLACK); int y_offset = MESSAGES_Y_OFFSET; - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { if (data.list[i]) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i ? 1 : 0); diff --git a/src/window/editor/select_scenario_action_type.c b/src/window/editor/select_scenario_action_type.c index ab5c23a092..56cbb0e17a 100644 --- a/src/window/editor/select_scenario_action_type.c +++ b/src/window/editor/select_scenario_action_type.c @@ -45,8 +45,8 @@ static generic_button buttons[] = { }; static struct { - int focus_button_id; - int total_types; + unsigned int focus_button_id; + unsigned int total_types; scenario_action_t *action; scenario_action_data_t *list[MAX_VISIBLE_ROWS]; } data; @@ -68,8 +68,8 @@ static void populate_list(int offset) if (offset < 0) { offset = 0; } - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { - int target_index = i + offset; + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { + unsigned int target_index = i + offset; if (target_index < data.total_types) { data.list[i] = scenario_events_parameter_data_get_actions_xml_attributes_alphabetical(target_index); } @@ -88,7 +88,7 @@ static void draw_foreground(void) outer_panel_draw(16, 16, 42, 33); int y_offset = DETAILS_Y_OFFSET; - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { if (data.list[i]) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i + 1 ? 1 : 0); if (data.focus_button_id == (i + 1)) { diff --git a/src/window/editor/select_scenario_condition_type.c b/src/window/editor/select_scenario_condition_type.c index 26cb5876f7..3e780fb391 100644 --- a/src/window/editor/select_scenario_condition_type.c +++ b/src/window/editor/select_scenario_condition_type.c @@ -45,8 +45,8 @@ static generic_button buttons[] = { }; static struct { - int focus_button_id; - int total_types; + unsigned int focus_button_id; + unsigned int total_types; scenario_condition_t *condition; scenario_condition_data_t *list[MAX_VISIBLE_ROWS]; } data; @@ -69,7 +69,7 @@ static void populate_list(int offset) offset = 0; } for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { - int target_index = i + offset; + unsigned int target_index = i + offset; if (target_index < data.total_types) { data.list[i] = scenario_events_parameter_data_get_conditions_xml_attributes_alphabetical(target_index); } @@ -88,7 +88,7 @@ static void draw_foreground(void) outer_panel_draw(16, 16, 42, 33); int y_offset = DETAILS_Y_OFFSET; - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { if (data.list[i]) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i + 1 ? 1 : 0); if (data.focus_button_id == (i + 1)) { diff --git a/src/window/editor/select_special_attribute_mapping.c b/src/window/editor/select_special_attribute_mapping.c index 5670b94474..acea30ca8c 100644 --- a/src/window/editor/select_special_attribute_mapping.c +++ b/src/window/editor/select_special_attribute_mapping.c @@ -23,7 +23,7 @@ #define MAX_VISIBLE_ROWS 13 static void on_scroll(void); -static void button_click(int param1, int param2); +static void button_click(int index, int param2); static scrollbar_type scrollbar = { 640, DETAILS_Y_OFFSET, DETAILS_ROW_HEIGHT * MAX_VISIBLE_ROWS, BUTTON_WIDTH, MAX_VISIBLE_ROWS, on_scroll, 0, 4 @@ -46,8 +46,8 @@ static generic_button buttons[] = { }; static struct { - int focus_button_id; - int list_size; + unsigned int focus_button_id; + unsigned int list_size; int parameter_type; void (*callback)(int); @@ -65,8 +65,8 @@ static void populate_list(int offset) if (offset < 0) { offset = 0; } - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { - int target_index = i + offset; + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { + unsigned int target_index = i + offset; if (target_index < data.list_size) { data.list[i] = scenario_events_parameter_data_get_attribute_mapping(data.parameter_type, target_index); } @@ -143,7 +143,7 @@ static void draw_foreground(void) text_draw(data.heading_text, 48, 40, FONT_NORMAL_PLAIN, COLOR_BLACK); int y_offset = DETAILS_Y_OFFSET; - for (int i = 0; i < MAX_VISIBLE_ROWS; i++) { + for (unsigned int i = 0; i < MAX_VISIBLE_ROWS; i++) { if (i < data.list_size) { large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / 16, data.focus_button_id == i + 1 ? 1 : 0); if (data.focus_button_id == (i + 1)) { @@ -180,13 +180,13 @@ static void handle_input(const mouse *m, const hotkeys *h) populate_list(scrollbar.scroll_position); } -static void button_click(int param1, int param2) +static void button_click(int index, int param2) { - if (param1 >= data.list_size) { + if (index >= (int) data.list_size) { return; } - data.callback(data.list[param1]->value); + data.callback(data.list[index]->value); window_go_back(); } diff --git a/src/window/editor/special_events.c b/src/window/editor/special_events.c index 259066d820..42281b3ba1 100644 --- a/src/window/editor/special_events.c +++ b/src/window/editor/special_events.c @@ -49,7 +49,7 @@ static generic_button buttons[] = { {216, 376, 100, 24, button_clay_pit_toggle, button_none}, }; -static int focus_button_id; +static unsigned int focus_button_id; static void draw_background(void) { diff --git a/src/window/editor/start_year.c b/src/window/editor/start_year.c index a496fe4edc..b4a4b9c9ca 100644 --- a/src/window/editor/start_year.c +++ b/src/window/editor/start_year.c @@ -23,7 +23,7 @@ static generic_button buttons[] = { {278, 100, 120, 30, button_year, button_none}, }; -static int focus_button_id; +static unsigned int focus_button_id; static void draw_background(void) { diff --git a/src/window/editor/starting_conditions.c b/src/window/editor/starting_conditions.c index a61460e953..1ce941f8d8 100644 --- a/src/window/editor/starting_conditions.c +++ b/src/window/editor/starting_conditions.c @@ -40,7 +40,7 @@ static generic_button buttons[] = { {262, 408, 200, 30, button_milestone, button_none, 75} }; -static int focus_button_id; +static unsigned int focus_button_id; static void draw_background(void) { diff --git a/src/window/editor/win_criteria.c b/src/window/editor/win_criteria.c index 579c03f963..165aa483b2 100644 --- a/src/window/editor/win_criteria.c +++ b/src/window/editor/win_criteria.c @@ -51,7 +51,7 @@ static generic_button buttons[] = { {316, 92, 80, 30, button_open_play_toggle, button_none}, }; -static int focus_button_id; +static unsigned int focus_button_id; static void draw_background(void) { diff --git a/src/window/empire.c b/src/window/empire.c index 901845996e..2b1d3a42f8 100644 --- a/src/window/empire.c +++ b/src/window/empire.c @@ -80,11 +80,11 @@ static generic_button generic_button_open_trade[] = { }; static struct { - int selected_button; + unsigned int selected_button; int selected_city; int x_min, x_max, y_min, y_max; int x_draw_offset, y_draw_offset; - int focus_button_id; + unsigned int focus_button_id; int is_scrolling; int finished_scroll; resource_type focus_resource; @@ -702,7 +702,7 @@ static void handle_input(const mouse *m, const hotkeys *h) } data.focus_button_id = 0; data.focus_resource = 0; - int button_id; + unsigned int button_id; image_buttons_handle_mouse(m, data.panel.x_min + 20, data.y_max - 44, image_button_help, 1, &button_id); if (button_id) { data.focus_button_id = 1; diff --git a/src/window/file_dialog.c b/src/window/file_dialog.c index e96d70a8db..b29e5e2494 100644 --- a/src/window/file_dialog.c +++ b/src/window/file_dialog.c @@ -7,8 +7,8 @@ #include "core/file.h" #include "core/image_group.h" #include "core/lang.h" +#include "core/log.h" #include "core/string.h" -#include "core/time.h" #include "editor/empire.h" #include "empire/xml.h" #include "game/file.h" @@ -48,13 +48,11 @@ #define FILTER_TEXT_SIZE 16 #define MIN_FILTER_SIZE 2 -static const time_millis NOT_EXIST_MESSAGE_TIMEOUT = 500; - static void button_toggle_sort_type(int param1, int param2); static void button_ok_cancel(int is_ok, int param2); static void input_box_changed(int is_addition_at_end); static void draw_file(const list_box_item *item); -static void select_file(int index, int is_double_click); +static void select_file(unsigned int index, int is_double_click); static void file_tooltip(const list_box_item *item, tooltip_context *c); static image_button image_buttons[] = { @@ -68,12 +66,11 @@ static generic_button sort_by_button[] = { typedef struct { const char *extension; - const char *path; + int location; char last_loaded_file[FILE_NAME_MAX]; } file_type_data; static struct { - time_millis message_not_exist_start_time; file_type type; file_dialog_type dialog_type; @@ -84,7 +81,7 @@ static struct { SORT_BY_NAME, SORT_BY_DATE } sort_type; - int sort_by_button_focused; + unsigned int sort_by_button_focused; file_type_data *file_data; char selected_file[FILE_NAME_MAX]; @@ -123,13 +120,13 @@ static const int MISSION_ID_TO_CITY_ID[] = { 0, 3, 2, 1, 7, 10, 18, 4, 30, 6, 12, 14, 16, 27, 31, 23, 36, 38, 28, 25 }; -static file_type_data saved_game_data = { "sav", "." }; -static file_type_data saved_game_data_expanded = { "svx", "." }; -static file_type_data scenario_data = { "map", "." }; -static file_type_data scenario_data_expanded = { "mapx", "." }; -static file_type_data empire_data = { "xml", "custom_empires" }; -static file_type_data scenario_event_data = { "xml", "editor/events" }; -static file_type_data custom_messages_data = { "xml", "editor/messages" }; +static file_type_data saved_game_data = { "sav", PATH_LOCATION_SAVEGAME }; +static file_type_data saved_game_data_expanded = { "svx", PATH_LOCATION_SAVEGAME }; +static file_type_data scenario_data = { "map", PATH_LOCATION_SCENARIO }; +static file_type_data scenario_data_expanded = { "mapx", PATH_LOCATION_SCENARIO}; +static file_type_data empire_data = { "xml", PATH_LOCATION_EDITOR_CUSTOM_EMPIRES }; +static file_type_data scenario_event_data = { "xml", PATH_LOCATION_EDITOR_CUSTOM_EVENTS }; +static file_type_data custom_messages_data = { "xml", PATH_LOCATION_EDITOR_CUSTOM_MESSAGES }; static int compare_name(const void *va, const void *vb) { @@ -219,22 +216,20 @@ static void init(file_type type, file_dialog_type dialog_type) } data.dialog_type = dialog_type; - data.message_not_exist_start_time = 0; - if (strlen(data.file_data->last_loaded_file) > 0) { - strncpy(data.selected_file, data.file_data->last_loaded_file, FILE_NAME_MAX); + snprintf(data.selected_file, FILE_NAME_MAX, "%s", data.file_data->last_loaded_file); if (data.dialog_type == FILE_DIALOG_SAVE) { file_remove_extension(data.selected_file); } encoding_from_utf8(data.selected_file, data.typed_name, FILE_NAME_MAX); if (data.dialog_type == FILE_DIALOG_SAVE) { - file_append_extension(data.selected_file, data.file_data->extension); + file_append_extension(data.selected_file, data.file_data->extension, FILE_NAME_MAX); } } else if (dialog_type == FILE_DIALOG_SAVE) { // Suggest default filename string_copy(lang_get_string(9, type == FILE_TYPE_SCENARIO ? 7 : 6), data.typed_name, FILE_NAME_MAX); encoding_to_utf8(data.typed_name, data.selected_file, FILE_NAME_MAX, encoding_system_uses_decomposed()); - file_append_extension(data.selected_file, data.file_data->extension); + file_append_extension(data.selected_file, data.file_data->extension, FILE_NAME_MAX); } else { // Use empty string data.typed_name[0] = 0; @@ -243,20 +238,20 @@ static void init(file_type type, file_dialog_type dialog_type) if (data.dialog_type != FILE_DIALOG_SAVE) { if (type == FILE_TYPE_SCENARIO) { - data.file_list = dir_find_files_with_extension(scenario_data.path, scenario_data.extension); + data.file_list = dir_find_files_with_extension_at_location(scenario_data.location, scenario_data.extension); data.file_list = dir_append_files_with_extension(scenario_data_expanded.extension); } else if (type == FILE_TYPE_EMPIRE) { - data.file_list = dir_find_files_with_extension(empire_data.path, empire_data.extension); + data.file_list = dir_find_files_with_extension_at_location(empire_data.location, empire_data.extension); } else if (type == FILE_TYPE_SCENARIO_EVENTS) { - data.file_list = dir_find_files_with_extension(scenario_event_data.path, scenario_event_data.extension); + data.file_list = dir_find_files_with_extension_at_location(scenario_event_data.location, scenario_event_data.extension); } else if (type == FILE_TYPE_CUSTOM_MESSAGES) { - data.file_list = dir_find_files_with_extension(custom_messages_data.path, custom_messages_data.extension); + data.file_list = dir_find_files_with_extension_at_location(custom_messages_data.location, custom_messages_data.extension); } else { - data.file_list = dir_find_files_with_extension(saved_game_data.path, saved_game_data.extension); + data.file_list = dir_find_files_with_extension_at_location(saved_game_data.location, saved_game_data.extension); data.file_list = dir_append_files_with_extension(saved_game_data_expanded.extension); } } else { - data.file_list = dir_find_files_with_extension(data.file_data->path, data.file_data->extension); + data.file_list = dir_find_files_with_extension_at_location(data.file_data->location, data.file_data->extension); } init_filtered_file_list(); list_box_init(&list_box, data.filtered_file_list.num_files); @@ -308,10 +303,15 @@ static void draw_background(void) { window_draw_underlying_window(); if (*data.selected_file) { - if (data.type == FILE_TYPE_SAVED_GAME) { - data.savegame_info_status = game_file_io_read_saved_game_info(data.selected_file, &data.info); + const char *filename = dir_get_file_at_location(data.selected_file, data.file_data->location); + if (filename) { + if (data.type == FILE_TYPE_SAVED_GAME) { + data.savegame_info_status = game_file_io_read_saved_game_info(filename, &data.info); + } else { + data.savegame_info_status = game_file_io_read_scenario_info(filename, &data.info); + } } else { - data.savegame_info_status = game_file_io_read_scenario_info(data.selected_file, &data.info); + data.savegame_info_status = SAVEGAME_STATUS_INVALID; } } data.redraw_full_window = 1; @@ -338,10 +338,7 @@ static void draw_foreground(void) list_box_request_refresh(&list_box); // title - if (data.message_not_exist_start_time - && time_get_millis() - data.message_not_exist_start_time < NOT_EXIST_MESSAGE_TIMEOUT) { - lang_text_draw_centered(43, 2, 32, 14, 554, FONT_LARGE_BLACK); - } else if (data.dialog_type == FILE_DIALOG_DELETE) { + if (data.dialog_type == FILE_DIALOG_DELETE) { lang_text_draw_centered(43, 6, 32, 14, 554, FONT_LARGE_BLACK); } else if (data.type == FILE_TYPE_EMPIRE) { lang_text_draw_centered(CUSTOM_TRANSLATION, TR_EDITOR_CUSTOM_EMPIRE_TITLE, 32, 14, 554, FONT_LARGE_BLACK); @@ -441,12 +438,6 @@ static void handle_input(const mouse *m, const hotkeys *h) return; } - if (data.message_not_exist_start_time && - time_get_millis() - data.message_not_exist_start_time >= NOT_EXIST_MESSAGE_TIMEOUT) { - data.redraw_full_window = 1; - data.message_not_exist_start_time = 0; - } - const mouse *m_dialog = mouse_in_dialog(m); if (input_box_handle_mouse(m_dialog, &main_input) || @@ -521,8 +512,8 @@ static void input_box_changed(int is_addition_at_end) if (data.file_list->num_files > NUM_FILES_IN_VIEW) { scroll_index = find_first_file_with_prefix(data.selected_file); } - file_append_extension(data.selected_file, data.file_data->extension); - if (scroll_index >= 0 && + file_append_extension(data.selected_file, data.file_data->extension, FILE_NAME_MAX); + if (scroll_index >= 0 && data.filtered_file_list.num_files > scroll_index && platform_file_manager_compare_filename(data.selected_file, data.filtered_file_list.files[scroll_index].name) == 0) { list_box_select_index(&list_box, scroll_index); @@ -544,27 +535,12 @@ static void input_box_changed(int is_addition_at_end) list_box_update_total_items(&list_box, data.filtered_file_list.num_files); } -static const char *prepare_filename(void) -{ - static char filename[FILE_NAME_MAX]; - memset(filename, 0, sizeof(filename)); - if (data.type == FILE_TYPE_EMPIRE) { - strncpy(filename, "custom_empires/", FILE_NAME_MAX - 1); - } else if (data.type == FILE_TYPE_SCENARIO_EVENTS) { - strncpy(filename, "editor/events/", FILE_NAME_MAX - 1); - } else if (data.type == FILE_TYPE_CUSTOM_MESSAGES) { - strncpy(filename, "editor/messages/", FILE_NAME_MAX - 1); - } - strncat(filename, data.selected_file, sizeof(filename) - strlen(filename)); - return filename; -} - static void confirm_save_file(int accepted, int checked) { if (!accepted) { return; } - const char *filename = prepare_filename(); + const char *filename = dir_append_location(data.selected_file, data.file_data->location); input_box_stop(&main_input); if (checked) { config_set(CONFIG_UI_ASK_CONFIRMATION_ON_FILE_OVERWRITE, 0); @@ -586,7 +562,7 @@ static void confirm_save_file(int accepted, int checked) custom_messages_export_to_xml(filename); window_editor_custom_messages_show(); } - strncpy(data.file_data->last_loaded_file, data.selected_file, FILE_NAME_MAX); + snprintf(data.file_data->last_loaded_file, FILE_NAME_MAX, "%s", data.selected_file); } static void button_ok_cancel(int is_ok, int param2) @@ -601,11 +577,17 @@ static void button_ok_cancel(int is_ok, int param2) return; } - const char *filename = prepare_filename(); + const char *filename; - if (data.dialog_type != FILE_DIALOG_SAVE && !file_exists(filename, NOT_LOCALIZED)) { - data.message_not_exist_start_time = time_get_millis(); - return; + if (data.dialog_type == FILE_DIALOG_SAVE) { + filename = dir_append_location(data.selected_file, data.file_data->location); + } else { + filename = dir_get_file_at_location(data.selected_file, data.file_data->location); + if (!filename) { + window_plain_message_dialog_show(TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TITLE, + TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TEXT, 1); + return; + } } if (data.dialog_type == FILE_DIALOG_LOAD) { @@ -614,7 +596,8 @@ static void button_ok_cancel(int is_ok, int param2) if (result == FILE_LOAD_SUCCESS) { window_city_show(); } else if (result == FILE_LOAD_DOES_NOT_EXIST) { - data.message_not_exist_start_time = time_get_millis(); + window_plain_message_dialog_show(TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TITLE, + TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TEXT, 1); return; } else if (result == FILE_LOAD_INCOMPATIBLE_VERSION) { window_plain_message_dialog_show(TR_SAVEGAME_LARGER_VERSION_TITLE, @@ -629,13 +612,14 @@ static void button_ok_cancel(int is_ok, int param2) if (game_file_editor_load_scenario(filename)) { window_editor_map_show(); } else { - data.message_not_exist_start_time = time_get_millis(); + window_plain_message_dialog_show(TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TITLE, + TR_SAVE_DIALOG_FILE_DOES_NOT_EXIST_TEXT, 1); return; } } else if (data.type == FILE_TYPE_EMPIRE) { int result = empire_xml_parse_file(filename); if (result) { - scenario_editor_set_custom_empire(filename); + scenario_editor_set_custom_empire(data.selected_file); window_editor_empire_show(); } else { window_plain_message_dialog_show(TR_EDITOR_UNABLE_TO_LOAD_EMPIRE_TITLE, @@ -661,9 +645,10 @@ static void button_ok_cancel(int is_ok, int param2) } } input_box_stop(&main_input); - strncpy(data.file_data->last_loaded_file, data.selected_file, FILE_NAME_MAX); + snprintf(data.file_data->last_loaded_file, FILE_NAME_MAX, "%s", data.selected_file); } else if (data.dialog_type == FILE_DIALOG_SAVE) { - if (config_get(CONFIG_UI_ASK_CONFIRMATION_ON_FILE_OVERWRITE) && file_exists(filename, NOT_LOCALIZED)) { + if (config_get(CONFIG_UI_ASK_CONFIRMATION_ON_FILE_OVERWRITE) && + dir_get_file_at_location(data.selected_file, data.file_data->location)) { window_popup_dialog_show_confirmation(lang_get_string(CUSTOM_TRANSLATION, TR_SAVE_DIALOG_OVERWRITE_FILE), lang_get_string(CUSTOM_TRANSLATION, TR_SAVE_DIALOG_OVERWRITE_FILE_DESC), lang_get_string(CUSTOM_TRANSLATION, TR_SAVE_DIALOG_OVERWRITE_FILE_DO_NOT_ASK_AGAIN), confirm_save_file); @@ -672,13 +657,13 @@ static void button_ok_cancel(int is_ok, int param2) } } else if (data.dialog_type == FILE_DIALOG_DELETE) { if (game_file_delete_saved_game(filename)) { - dir_find_files_with_extension(saved_game_data.path, saved_game_data.extension); + data.file_list = dir_find_files_with_extension_at_location(saved_game_data.location, saved_game_data.extension); dir_append_files_with_extension(saved_game_data_expanded.extension); init_filtered_file_list(); list_box_update_total_items(&list_box, data.filtered_file_list.num_files); select_correct_index(); - strncpy(data.file_data->last_loaded_file, data.selected_file, FILE_NAME_MAX); + snprintf(data.file_data->last_loaded_file, FILE_NAME_MAX, "%s", data.selected_file); window_request_refresh(); } } @@ -697,21 +682,20 @@ static void button_toggle_sort_type(int param1, int param2) data.redraw_full_window = 1; } -static void select_file(int index, int is_double_click) +static void select_file(unsigned int index, int is_double_click) { if (index == LIST_BOX_NO_SELECTION) { return; } if (strcmp(data.selected_file, data.filtered_file_list.files[index].name) != 0) { - data.message_not_exist_start_time = 0; - strncpy(data.selected_file, data.filtered_file_list.files[index].name, FILE_NAME_MAX - 1); + snprintf(data.selected_file, FILE_NAME_MAX, "%s", data.filtered_file_list.files[index].name); if (data.dialog_type == FILE_DIALOG_SAVE) { file_remove_extension(data.selected_file); } encoding_from_utf8(data.selected_file, data.typed_name, FILE_NAME_MAX); if (data.dialog_type == FILE_DIALOG_SAVE) { input_box_refresh_text(&main_input); - file_append_extension(data.selected_file, data.file_data->extension); + file_append_extension(data.selected_file, data.file_data->extension, FILE_NAME_MAX); } window_request_refresh(); } diff --git a/src/window/gift_to_emperor.c b/src/window/gift_to_emperor.c index d7a2c43ea3..297e553273 100644 --- a/src/window/gift_to_emperor.c +++ b/src/window/gift_to_emperor.c @@ -24,7 +24,7 @@ static generic_button buttons[] = { {400, 336, 160, 20, button_cancel, button_none, 0, 0}, }; -static int focus_button_id; +static unsigned int focus_button_id; static void init(void) { diff --git a/src/window/hold_festival.c b/src/window/hold_festival.c index 9287421624..61a399f6c4 100644 --- a/src/window/hold_festival.c +++ b/src/window/hold_festival.c @@ -42,8 +42,8 @@ static generic_button buttons_gods_size[] = { {102, 276, 430, 26, button_size, button_none, 3, 0}, }; -static int focus_button_id; -static int focus_image_button_id; +static unsigned int focus_button_id; +static unsigned int focus_image_button_id; static void draw_buttons(void) { diff --git a/src/window/hold_games.c b/src/window/hold_games.c index 45ca726420..81bc44a0ae 100644 --- a/src/window/hold_games.c +++ b/src/window/hold_games.c @@ -48,9 +48,9 @@ static generic_button buttons_games_size[] = { }; static struct { - int focus_button_id; - int focus_image_button_id; - int focus_game_button_id; + unsigned int focus_button_id; + unsigned int focus_image_button_id; + unsigned int focus_game_button_id; int return_to_city; int game_possible; } data; @@ -86,7 +86,7 @@ static void draw_background(void) image_draw(base_image_id + i, 100 * i + 175, 101, COLOR_MASK_NONE, SCALE_NONE); image_draw_border(highlight_image_id, 100 * i + 175, 101, highlight_color); } - text_draw_multiline(translation_for(game->description_key), 70, 222, 500, FONT_NORMAL_BLACK, 0); + text_draw_multiline(translation_for(game->description_key), 70, 222, 500, 0, FONT_NORMAL_BLACK, 0); int width = text_draw(translation_for(TR_WINDOW_GAMES_COST), 120, 300, FONT_NORMAL_BLACK, 0); width += text_draw_money(city_games_money_cost(selected_game_id), 120 + width, 300, FONT_NORMAL_BLACK); diff --git a/src/window/hotkey_config.c b/src/window/hotkey_config.c index a4b0e1316b..7617238959 100644 --- a/src/window/hotkey_config.c +++ b/src/window/hotkey_config.c @@ -206,8 +206,8 @@ static translation_key bottom_button_texts[] = { }; static struct { - int focus_button; - int bottom_focus_button; + unsigned int focus_button; + unsigned int bottom_focus_button; hotkey_mapping mappings[HOTKEY_MAX_ITEMS][2]; } data; @@ -293,7 +293,7 @@ static void draw_foreground(void) scrollbar_draw(&scrollbar); - for (int i = 0; i < NUM_VISIBLE_OPTIONS; i++) { + for (unsigned int i = 0; i < NUM_VISIBLE_OPTIONS; i++) { hotkey_widget *widget = &hotkey_widgets[i + scrollbar.scroll_position]; if (widget->action != HOTKEY_HEADER) { generic_button *btn = &hotkey_buttons[2 * i]; @@ -303,7 +303,7 @@ static void draw_foreground(void) } } - for (int i = 0; i < NUM_BOTTOM_BUTTONS; i++) { + for (unsigned int i = 0; i < NUM_BOTTOM_BUTTONS; i++) { button_border_draw(bottom_buttons[i].x, bottom_buttons[i].y, bottom_buttons[i].width, bottom_buttons[i].height, data.bottom_focus_button == i + 1); @@ -333,7 +333,7 @@ static void handle_input(const mouse *m, const hotkeys *h) static const uint8_t *hotkey_action_name_for(hotkey_action action) { const uint8_t *name = 0; - for (int i = 0; i < NUM_VISIBLE_OPTIONS + scrollbar.max_scroll_position; i++) { + for (unsigned int i = 0; i < NUM_VISIBLE_OPTIONS + scrollbar.max_scroll_position; i++) { hotkey_widget *widget = &hotkey_widgets[i]; if (widget->action == action) { if (widget->name_translation != TR_NONE) { diff --git a/src/window/hotkey_editor.c b/src/window/hotkey_editor.c index dca3b9276a..167fc56c1d 100644 --- a/src/window/hotkey_editor.c +++ b/src/window/hotkey_editor.c @@ -31,7 +31,7 @@ static struct { key_type key; key_modifier_type modifiers; void (*callback)(hotkey_action, int, key_type, key_modifier_type); - int focus_button; + unsigned int focus_button; } data; static void init(hotkey_action action, int index, @@ -72,7 +72,7 @@ static void draw_foreground(void) text_draw_centered(key_combination_display_name(data.key, data.modifiers), 192, 193, 256, FONT_NORMAL_WHITE, 0); - for (int i = 0; i < NUM_BOTTOM_BUTTONS; i++) { + for (unsigned int i = 0; i < NUM_BOTTOM_BUTTONS; i++) { generic_button *btn = &bottom_buttons[i]; button_border_draw(btn->x, btn->y, btn->width, btn->height, data.focus_button == i + 1); } diff --git a/src/window/labor_priority.c b/src/window/labor_priority.c index 4fa9f414fc..0b2abf6261 100644 --- a/src/window/labor_priority.c +++ b/src/window/labor_priority.c @@ -14,8 +14,8 @@ static void button_set_priority(int new_priority, int param2); static struct { int category; - int max_items; - int focus_button_id; + unsigned int max_items; + unsigned int focus_button_id; } data; static generic_button priority_buttons[] = { @@ -63,7 +63,7 @@ static void draw_background(void) int dialog_x = 160 - (dialog_width - MIN_DIALOG_WIDTH) / 2; outer_panel_draw(dialog_x, 176, dialog_width / BLOCK_SIZE, 9); lang_text_draw_centered(50, 25, 160, 185, 320, FONT_LARGE_BLACK); - for (int i = 0; i < 9; i++) { + for (unsigned int i = 0; i < 9; i++) { graphics_draw_rect(178 + 32 * i, 221, 27, 27, COLOR_BLACK); lang_text_draw_centered(50, 27 + i, 178 + 32 * i, 224, 27, FONT_LARGE_BLACK); if (i >= data.max_items) { @@ -82,7 +82,7 @@ static void draw_foreground(void) graphics_in_dialog(); color_t color; - for (int i = 0; i < 9; i++) { + for (unsigned int i = 0; i < 9; i++) { color = COLOR_BLACK; if (i == data.focus_button_id - 2) { color = COLOR_RED; diff --git a/src/window/logo.c b/src/window/logo.c index 832267e836..03be875a84 100644 --- a/src/window/logo.c +++ b/src/window/logo.c @@ -9,14 +9,58 @@ #include "window/intro_video.h" #include "window/main_menu.h" #include "window/plain_message_dialog.h" +#include "window/popup_dialog.h" +#include "window/user_path_setup.h" -static void init(void) +static int pending_actions; + +static void init(int actions) { + pending_actions = actions; sound_music_play_intro(); } +static int process_pending_actions(void) +{ + if (pending_actions & ACTION_SHOW_MESSAGE_MISSING_PATCH) { + window_plain_message_dialog_show(TR_NO_PATCH_TITLE, TR_NO_PATCH_MESSAGE, 0); + pending_actions ^= ACTION_SHOW_MESSAGE_MISSING_PATCH; + return 1; + } + if (pending_actions & ACTION_SHOW_MESSAGE_MISSING_FONTS) { + window_plain_message_dialog_show(TR_MISSING_FONTS_TITLE, TR_MISSING_FONTS_MESSAGE, 0); + pending_actions ^= ACTION_SHOW_MESSAGE_MISSING_FONTS; + return 1; + } + if (pending_actions & ACTION_SHOW_MESSAGE_MISSING_EXTRA_ASSETS) { + window_plain_message_dialog_show(TR_NO_EXTRA_ASSETS_TITLE, TR_NO_EXTRA_ASSETS_MESSAGE, 0); + pending_actions ^= ACTION_SHOW_MESSAGE_MISSING_EXTRA_ASSETS; + return 1; + } + if (pending_actions & ACTION_SETUP_USER_DIR) { + window_user_path_setup_show(1); + pending_actions ^= ACTION_SETUP_USER_DIR; + return 1; + } + if (pending_actions & ACTION_SHOW_MESSAGE_USER_DIR_NOT_WRITABLE) { + window_plain_message_dialog_show(TR_USER_DIRECTORIES_NOT_WRITEABLE_TITLE, + TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT_DETAILED, 0); + pending_actions ^= ACTION_SHOW_MESSAGE_USER_DIR_NOT_WRITABLE; + return 1; + } + if (pending_actions & ACTION_SHOW_INTRO_VIDEOS) { + window_intro_video_show(); + pending_actions ^= ACTION_SHOW_INTRO_VIDEOS; + return 1; + } + return 0; +} + static void draw_background(void) { + if (process_pending_actions()) { + return; + } graphics_clear_screen(); graphics_in_dialog(); @@ -27,6 +71,9 @@ static void draw_background(void) static void handle_input(const mouse *m, const hotkeys *h) { + if (pending_actions) { + return; + } if (m->left.went_up || m->right.went_up) { window_main_menu_show(0); return; @@ -36,7 +83,7 @@ static void handle_input(const mouse *m, const hotkeys *h) } } -void window_logo_show(int show_patch_message) +void window_logo_show(int actions) { window_type window = { WINDOW_LOGO, @@ -44,16 +91,6 @@ void window_logo_show(int show_patch_message) 0, handle_input }; - init(); + init(actions); window_show(&window); - if (show_patch_message == MESSAGE_MISSING_PATCH) { - window_plain_message_dialog_show(TR_NO_PATCH_TITLE, TR_NO_PATCH_MESSAGE, 0); - } else if (show_patch_message == MESSAGE_MISSING_FONTS) { - window_plain_message_dialog_show(TR_MISSING_FONTS_TITLE, TR_MISSING_FONTS_MESSAGE, 0); - } else if (show_patch_message == MESSAGE_MISSING_EXTRA_ASSETS) { - window_plain_message_dialog_show(TR_NO_EXTRA_ASSETS_TITLE, TR_NO_EXTRA_ASSETS_MESSAGE, 0); - } - if (config_get(CONFIG_UI_SHOW_INTRO_VIDEO)) { - window_intro_video_show(); - } } diff --git a/src/window/logo.h b/src/window/logo.h index d4538fb2db..9821ecbc28 100644 --- a/src/window/logo.h +++ b/src/window/logo.h @@ -2,12 +2,15 @@ #define WINDOW_LOGO_H enum { - MESSAGE_NONE = 0, - MESSAGE_MISSING_PATCH = 1, - MESSAGE_MISSING_FONTS = 2, - MESSAGE_MISSING_EXTRA_ASSETS = 3, + ACTION_NONE = 0, + ACTION_SHOW_MESSAGE_MISSING_PATCH = 1 << 0, + ACTION_SHOW_MESSAGE_MISSING_FONTS = 1 << 1, + ACTION_SHOW_MESSAGE_MISSING_EXTRA_ASSETS = 1 << 2, + ACTION_SETUP_USER_DIR = 1 << 3, + ACTION_SHOW_MESSAGE_USER_DIR_NOT_WRITABLE = 1 << 4, + ACTION_SHOW_INTRO_VIDEOS = 1 << 5 }; -void window_logo_show(int show_patch_message); +void window_logo_show(int actions); #endif // WINDOW_LOGO_H diff --git a/src/window/main_menu.c b/src/window/main_menu.c index e40b7fd172..742efd9cae 100644 --- a/src/window/main_menu.c +++ b/src/window/main_menu.c @@ -29,7 +29,7 @@ static void button_click(int type, int param2); static struct { - int focus_button_id; + unsigned int focus_button_id; int logo_image_id; } data; @@ -79,8 +79,9 @@ static void draw_foreground(void) { graphics_in_dialog(); - for (int i = 0; i < MAX_BUTTONS; i++) { - large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / BLOCK_SIZE, data.focus_button_id == i + 1 ? 1 : 0); + for (unsigned int i = 0; i < MAX_BUTTONS; i++) { + large_label_draw(buttons[i].x, buttons[i].y, buttons[i].width / BLOCK_SIZE, + data.focus_button_id == i + 1 ? 1 : 0); } lang_text_draw_centered(CUSTOM_TRANSLATION, TR_MAIN_MENU_NEW_CAMPAIGN, 192, 137, 256, FONT_NORMAL_GREEN); diff --git a/src/window/message_dialog.c b/src/window/message_dialog.c index 97ecfa65cf..8396620099 100644 --- a/src/window/message_dialog.c +++ b/src/window/message_dialog.c @@ -108,7 +108,7 @@ static struct { int y_text; int text_height_blocks; int text_width_blocks; - int focus_button_id; + unsigned int focus_button_id; lang_message custom_lang_message; custom_message_t *custom_msg; @@ -474,7 +474,7 @@ static void draw_subtitle(const lang_message *msg) if (msg->subtitle.x && msg->subtitle.text) { int width = BLOCK_SIZE * (msg->width_blocks - 1) - msg->subtitle.x; int height = text_draw_multiline(msg->subtitle.text, - data.x + msg->subtitle.x, data.y + msg->subtitle.y, width, FONT_NORMAL_BLACK, 0); + data.x + msg->subtitle.x, data.y + msg->subtitle.y, width, 0, FONT_NORMAL_BLACK, 0); if (data.y + msg->subtitle.y + height > data.y_text) { data.y_text = data.y + msg->subtitle.y + height; } diff --git a/src/window/message_list.c b/src/window/message_list.c index 89996a6fdb..5e34301471 100644 --- a/src/window/message_list.c +++ b/src/window/message_list.c @@ -75,7 +75,7 @@ static struct { int y_text; int text_width_blocks; int text_height_blocks; - int focus_button_id; + unsigned int focus_button_id; } data; static int review_briefing_button_should_be_active(void) @@ -134,11 +134,11 @@ static void draw_background(void) graphics_reset_dialog(); } -static void draw_messages(int total_messages) +static void draw_messages(unsigned int total_messages) { - int max = total_messages < MAX_MESSAGES ? total_messages : MAX_MESSAGES; - int index = scrollbar.scroll_position; - for (int i = 0; i < max; i++, index++) { + unsigned int max = total_messages < MAX_MESSAGES ? total_messages : MAX_MESSAGES; + unsigned int index = scrollbar.scroll_position; + for (unsigned int i = 0; i < max; i++, index++) { const city_message *msg = city_message_get(index); int image_offset = 0; const lang_message *lang_msg = 0; @@ -202,7 +202,7 @@ static void draw_foreground(void) static void handle_input(const mouse *m, const hotkeys *h) { const mouse *m_dialog = mouse_in_dialog(m); - int old_button_id = data.focus_button_id; + unsigned int old_button_id = data.focus_button_id; data.focus_button_id = 0; if (scrollbar_handle_mouse(&scrollbar, m_dialog, 1)) { @@ -210,7 +210,7 @@ static void handle_input(const mouse *m, const hotkeys *h) return; } - int button_id; + unsigned int button_id; int handled = image_buttons_handle_mouse(m_dialog, 16, 32 + BLOCK_SIZE * data.height_blocks - 42, &image_button_help, 1, &button_id); if (button_id) { diff --git a/src/window/military_menu.c b/src/window/military_menu.c index 3c2de62ec5..a05548846f 100644 --- a/src/window/military_menu.c +++ b/src/window/military_menu.c @@ -17,8 +17,8 @@ #define MENU_CLICK_MARGIN 20 static struct { - int active_buttons; - int focus_button_id; + unsigned int active_buttons; + unsigned int focus_button_id; } data; static void button_menu_item(int index, int param2); @@ -47,10 +47,10 @@ static void draw_background(void) static void draw_foreground(void) { window_city_draw(); - int num_legions = formation_get_num_legions(); + unsigned int num_legions = formation_get_num_legions(); int x_offset = get_sidebar_x_offset(); - for (int i = 0; i < num_legions; i++) { + for (unsigned int i = 0; i < num_legions; i++) { const formation *m = formation_get(formation_for_legion(i + 1)); label_draw(x_offset - 170, 74 + 24 * i, 10, data.focus_button_id == i + 1 ? 1 : 2); lang_text_draw_centered(138, m->legion_id, x_offset - 170, 77 + 24 * i, 160, FONT_NORMAL_GREEN); @@ -64,7 +64,7 @@ static int click_outside_menu(const mouse *m, int x_offset) (m->x < x_offset - MENU_X_OFFSET - MENU_CLICK_MARGIN || m->x > x_offset + MENU_CLICK_MARGIN || m->y < MENU_Y_OFFSET - MENU_CLICK_MARGIN || - m->y > MENU_Y_OFFSET + MENU_CLICK_MARGIN + MENU_ITEM_HEIGHT * data.active_buttons); + m->y > MENU_Y_OFFSET + MENU_CLICK_MARGIN + MENU_ITEM_HEIGHT * (int) data.active_buttons); } diff --git a/src/window/mission_briefing.c b/src/window/mission_briefing.c index d4b0a52d9a..a5a0b297ae 100644 --- a/src/window/mission_briefing.c +++ b/src/window/mission_briefing.c @@ -155,15 +155,15 @@ static void play_audio(void) const char *audio_file = custom_messages_get_audio(custom_message); if (audio_file) { - strncpy(data.paths.audio, audio_file, FILE_NAME_MAX); + snprintf(data.paths.audio, FILE_NAME_MAX, "%s", audio_file); } const char *speech_file = custom_messages_get_speech(custom_message); if (speech_file) { - strncpy(data.paths.speech, speech_file, FILE_NAME_MAX); + snprintf(data.paths.speech, FILE_NAME_MAX, "%s", speech_file); } const char *background_music = custom_messages_get_background_music(custom_message); if (background_music) { - strncpy(data.paths.background_music, background_music, FILE_NAME_MAX); + snprintf(data.paths.background_music, FILE_NAME_MAX, "%s", background_music); } if (!audio_file && !speech_file && !background_music) { diff --git a/src/window/mission_end.c b/src/window/mission_end.c index f27020eae6..b770fc47de 100644 --- a/src/window/mission_end.c +++ b/src/window/mission_end.c @@ -44,7 +44,7 @@ static generic_button fired_buttons[] = { }; static struct { - int focus_button_id; + unsigned int focus_button_id; int audio_playing; int background_image_id; struct { @@ -128,15 +128,15 @@ static void play_audio(void) const char *audio_file = custom_messages_get_audio(custom_message); if (audio_file) { - strncpy(data.paths.audio, audio_file, FILE_NAME_MAX); + snprintf(data.paths.audio, FILE_NAME_MAX, "%s", audio_file); } const char *speech_file = custom_messages_get_speech(custom_message); if (speech_file) { - strncpy(data.paths.speech, speech_file, FILE_NAME_MAX); + snprintf(data.paths.speech, FILE_NAME_MAX, "%s", speech_file); } const char *background_music = custom_messages_get_background_music(custom_message); if (background_music) { - strncpy(data.paths.background_music, background_music, FILE_NAME_MAX); + snprintf(data.paths.background_music, FILE_NAME_MAX, "%s", background_music); } int playing_audio = 0; @@ -182,8 +182,8 @@ static void draw_background_image(void) static void draw_won(void) { - int panel_height_blocks; - int y_offset; + int panel_height_blocks = 18; + int y_offset = 128; const uint8_t *victory_message_text = 0; if (has_custom_victory_message()) { custom_message_t *victory_message = custom_messages_get(scenario_victory_message()); @@ -192,9 +192,6 @@ static void draw_won(void) y_offset = 0; panel_height_blocks = 30; } - } else { - y_offset = 128; - panel_height_blocks = 18; } play_audio(); diff --git a/src/window/mission_selection.c b/src/window/mission_selection.c index e6270571f0..5f44f7c77a 100644 --- a/src/window/mission_selection.c +++ b/src/window/mission_selection.c @@ -171,10 +171,10 @@ static void draw_background(void) if (data.choice) { const campaign_scenario *scenario = data.mission.scenarios[data.choice - 1]; if (scenario->name) { - text_draw_multiline(scenario->name, 20, 440, 560, FONT_NORMAL_BLACK, 0); + text_draw_multiline(scenario->name, 20, 440, 560, 0, FONT_NORMAL_BLACK, 0); } if (scenario->description) { - text_draw_multiline(scenario->description, 20, 456, 560, FONT_NORMAL_BLACK, 0); + text_draw_multiline(scenario->description, 20, 456, 560, 0, FONT_NORMAL_BLACK, 0); } } else { lang_text_draw_multiline(144, 0, 20, 440, 560, FONT_NORMAL_BLACK); diff --git a/src/window/new_campaign.c b/src/window/new_campaign.c index 1089464019..5c3831f632 100644 --- a/src/window/new_campaign.c +++ b/src/window/new_campaign.c @@ -33,7 +33,7 @@ static void start_mission(int param1, int param2); static void button_back(int param1, int param2); static void draw_campaign_item(const list_box_item *item); -static void select_campaign(int index, int is_double_click); +static void select_campaign(unsigned int index, int is_double_click); static void campaign_name_tooltip(const list_box_item *item, tooltip_context *c); static image_button image_buttons[] = { @@ -94,7 +94,7 @@ static void init(void) if (string_equals(player_name_input.placeholder, data.player_name)) { *data.player_name = 0; } - data.campaign_list = dir_find_all_subdirectories(CAMPAIGNS_DIR_NAME); + data.campaign_list = dir_find_all_subdirectories_at_location(PATH_LOCATION_CAMPAIGN); data.campaign_list = dir_append_files_with_extension("campaign"); calculate_input_box_width(); input_box_start(&player_name_input); @@ -202,7 +202,7 @@ static void button_back(int param1, int param2) window_go_back(); } -static void select_campaign(int index, int is_double_click) +static void select_campaign(unsigned int index, int is_double_click) { if (index == ORIGINAL_CAMPAIGN_ID) { campaign_clear(); diff --git a/src/window/numeric_input.c b/src/window/numeric_input.c index 487d40f5da..f46510f18a 100644 --- a/src/window/numeric_input.c +++ b/src/window/numeric_input.c @@ -44,15 +44,15 @@ static generic_button buttons[] = { static struct { int x; int y; - int max_digits; + unsigned int max_digits; int min_value; int max_value; void (*callback)(int); - int num_digits; + unsigned int num_digits; int value; int is_negative_value; - int focus_button_id; + unsigned int focus_button_id; } data; static void init(int x, int y, int max_digits, int min_value, int max_value, void (*callback)(int)) diff --git a/src/window/option_popup.c b/src/window/option_popup.c index fe1287cd71..187a353b94 100644 --- a/src/window/option_popup.c +++ b/src/window/option_popup.c @@ -40,16 +40,16 @@ static struct { int title; int subtitle; option_menu_item *options; - int num_options; + unsigned int num_options; int width_blocks; int height_blocks; void (*close_func)(int selection); - int focus_button_id; - int original_option; - int selected_option; + unsigned int focus_button_id; + unsigned int original_option; + unsigned int selected_option; int price; - int visible_options; - int scroll_position; + unsigned int visible_options; + unsigned int scroll_position; int height; option_menu_row_size row_size; } data; @@ -129,7 +129,7 @@ static void draw_background(void) outer_panel_draw(0, 0, data.width_blocks, data.height_blocks); text_draw_centered(translation_for(data.title), 0, 20, 480, FONT_LARGE_BLACK, 0); - text_draw_multiline(translation_for(data.subtitle), 20, 60, 440, FONT_NORMAL_BLACK, 0); + text_draw_multiline(translation_for(data.subtitle), 20, 60, 440, 0, FONT_NORMAL_BLACK, 0); if (data.price) { text_draw_with_money(translation_for(TR_OPTION_MENU_COST), data.price, " ", ".", 20, 110, 0, FONT_NORMAL_BLACK, 0); @@ -137,7 +137,7 @@ static void draw_background(void) int y_offset = START_Y_OFFSET; - for (int i = 0; i < data.visible_options; i++) { + for (unsigned int i = 0; i < data.visible_options; i++) { int text_width = data.num_options == data.visible_options ? 448 : 400; int text_x = 20; @@ -154,10 +154,10 @@ static void draw_background(void) Y_OFFSET_PER_OPTION[data.row_size] / 16 - 1); } text_draw_multiline(translation_for(data.options[i + scrollbar.scroll_position].header), - text_x, y_offset + 49, text_width - 8, + text_x, y_offset + 49, text_width - 8, 0, data.selected_option == i + scrollbar.scroll_position + 1 ? FONT_NORMAL_WHITE : FONT_NORMAL_BLACK, 0); text_draw_multiline(translation_for(data.options[i + scrollbar.scroll_position].desc), - text_x, y_offset + 69, text_width - 8, + text_x, y_offset + 69, text_width - 8, 0, data.selected_option == i + scrollbar.scroll_position + 1 ? FONT_NORMAL_WHITE : FONT_NORMAL_BLACK, 0); @@ -174,7 +174,7 @@ static void draw_background(void) static void draw_foreground(void) { graphics_in_dialog_with_size(16 * data.width_blocks, 16 * data.height_blocks); - for (int i = 0; i < data.visible_options; i++) { + for (unsigned int i = 0; i < data.visible_options; i++) { if (data.options[i + scrollbar.scroll_position].image_id) { color_t color = data.focus_button_id == i + 3 ? COLOR_BORDER_RED : COLOR_BORDER_GREEN; image_draw_border(border_image_ids[data.row_size], 20, buttons[i + 2].y + 2, color); diff --git a/src/window/overlay_menu.c b/src/window/overlay_menu.c index 0b1edadf0e..12577262ac 100644 --- a/src/window/overlay_menu.c +++ b/src/window/overlay_menu.c @@ -68,11 +68,11 @@ static const int SUBMENU_ID_TO_OVERLAY[6][OVERLAY_BUTTONS] = { static struct { int selected_menu; int selected_submenu; - int num_submenu_items; + unsigned int num_submenu_items; time_millis submenu_focus_time; - int menu_focus_button_id; - int submenu_focus_button_id; + unsigned int menu_focus_button_id; + unsigned int submenu_focus_button_id; int keep_submenu_open; } data; @@ -99,7 +99,7 @@ static void draw_foreground(void) { window_city_draw(); int x_offset = get_sidebar_x_offset(); - for (int i = 0; i < OVERLAY_BUTTONS; i++) { + for (unsigned int i = 0; i < OVERLAY_BUTTONS; i++) { label_draw(x_offset - 170, 74 + 24 * i, 10, data.menu_focus_button_id == i + 1 ? 1 : 2); int overlay = MENU_ID_TO_OVERLAY[i]; int translation = get_overlay_translation(overlay); @@ -112,7 +112,7 @@ static void draw_foreground(void) if (data.selected_submenu > 0) { image_draw(image_group(GROUP_BULLET), x_offset - 185, 80 + 24 * data.selected_menu, COLOR_MASK_NONE, SCALE_NONE); - for (int i = 0; i < data.num_submenu_items; i++) { + for (unsigned int i = 0; i < data.num_submenu_items; i++) { int overlay = SUBMENU_ID_TO_OVERLAY[data.selected_submenu][i]; int translation = get_overlay_translation(overlay); diff --git a/src/window/plain_message_dialog.c b/src/window/plain_message_dialog.c index cf9d03ed8e..60b3713eb9 100644 --- a/src/window/plain_message_dialog.c +++ b/src/window/plain_message_dialog.c @@ -46,7 +46,7 @@ static void draw_background(void) graphics_in_dialog(); outer_panel_draw(80, 80, 30, 13); text_draw_centered(data.title, 80, 100, 480, FONT_LARGE_BLACK, 0); - text_draw_multiline(data.message, 100, 140, 450, FONT_NORMAL_BLACK, 0); + text_draw_multiline(data.message, 100, 140, 450, 0, FONT_NORMAL_BLACK, 0); if (data.extra) { text_draw_centered(data.extra, 100, 180, 450, FONT_NORMAL_BLACK, 0); } diff --git a/src/window/popup_dialog.c b/src/window/popup_dialog.c index 0ec8797c14..5e5fd3c896 100644 --- a/src/window/popup_dialog.c +++ b/src/window/popup_dialog.c @@ -38,7 +38,7 @@ static struct { int has_buttons; int translation_key; int checked; - int has_focus; + unsigned int has_focus; int checkbox_start_width; const uint8_t *custom_title; const uint8_t *custom_text; @@ -77,7 +77,7 @@ static void draw_background(void) text_draw_centered(data.custom_title, 80, 100, 480, FONT_LARGE_BLACK, 0); } if (text_get_width(data.custom_text, FONT_NORMAL_BLACK) >= 420) { - text_draw_multiline(data.custom_text, 110, 140, 420, FONT_NORMAL_BLACK, 0); + text_draw_multiline(data.custom_text, 110, 140, 420, 0, FONT_NORMAL_BLACK, 0); } else { text_draw_centered(data.custom_text, 80, 140, 480, FONT_NORMAL_BLACK, 0); } @@ -97,7 +97,7 @@ static void draw_foreground(void) button_border_draw(data.checkbox_start_width, 180, CHECKBOX_CHECK_SIZE, CHECKBOX_CHECK_SIZE, data.has_focus); } if (data.has_buttons) { - image_buttons_draw(80, data.checkbox_text ? 110 : 80, buttons, 2); + image_buttons_draw(80, data.checkbox_text ? 110 : 90, buttons, 2); } else { lang_text_draw_centered(13, 1, 80, 208, 480, FONT_NORMAL_BLACK); } @@ -110,12 +110,12 @@ static void handle_input(const mouse *m, const hotkeys *h) return; } if (data.has_buttons && image_buttons_handle_mouse(mouse_in_dialog(m), 80, - data.checkbox_text ? 110 : 80, buttons, 2, 0)) { + data.checkbox_text ? 110 : 90, buttons, 2, 0)) { return; } if (input_go_back_requested(m, h)) { - data.close_func(0, 0); window_go_back(); + data.close_func(0, 0); } if (h->enter_pressed) { confirm(); diff --git a/src/window/race_bet.c b/src/window/race_bet.c index 352b235cb0..2890621c47 100644 --- a/src/window/race_bet.c +++ b/src/window/race_bet.c @@ -41,13 +41,13 @@ static image_button image_button_close[] = { static struct { - int chosen_horse; - int bet_amount; + unsigned int chosen_horse; + unsigned int bet_amount; int in_progress_bet; - int focus_button_id; - int focus_button_id2; - int focus_button_id3; - int focus_image_button_id; + unsigned int focus_button_id; + unsigned int focus_button_id2; + unsigned int focus_button_id3; + unsigned int focus_image_button_id; int width_blocks; int height_blocks; } data; @@ -80,7 +80,7 @@ static void draw_background(void) text_draw_centered(translation_for(TR_WINDOW_RACE_BET_TITLE), 0, 20, BLOCK_SIZE * data.width_blocks, FONT_LARGE_BLACK, 0); - text_draw_multiline(translation_for(TR_WINDOW_RACE_BET_DESCRIPTION), 25, 65, 438, FONT_NORMAL_BLACK, 0); + text_draw_multiline(translation_for(TR_WINDOW_RACE_BET_DESCRIPTION), 25, 65, 438, 0, FONT_NORMAL_BLACK, 0); inner_panel_draw(18, 300, 28, 2); text_draw_centered(translation_for(TR_WINDOW_RACE_BET_AMOUNT), 18, 310, 80, FONT_NORMAL_WHITE, 0); @@ -95,7 +95,7 @@ static void draw_background(void) horse_description = TR_WINDOW_RACE_BLUE_HORSE_DESCRIPTION + data.chosen_horse - 1; } if (horse_description) { - text_draw_multiline(translation_for(horse_description), 25, 250, 438, FONT_NORMAL_BLACK, 0); + text_draw_multiline(translation_for(horse_description), 25, 250, 438, 0, FONT_NORMAL_BLACK, 0); } int button_enabled = data.bet_amount > 0 && data.chosen_horse != 0 && !data.in_progress_bet; @@ -119,7 +119,7 @@ static void draw_foreground(void) int border_id = assets_get_image_id("UI", "Image Border Small"); - for (int i = 0; i < 4; i++) { + for (unsigned int i = 0; i < 4; i++) { color_t color = data.focus_button_id == (i + 1) || data.chosen_horse == (i + 1) ? COLOR_BORDER_RED : COLOR_BORDER_GREEN; image_draw_border(border_id, 34 + i * 110, 145, color); diff --git a/src/window/resource_settings.c b/src/window/resource_settings.c index 56ca3b7da2..371f52328a 100644 --- a/src/window/resource_settings.c +++ b/src/window/resource_settings.c @@ -53,8 +53,8 @@ static generic_button resource_generic_buttons[] = { static struct { resource_type resource; - int focus_button_id; - int focus_image_button_id; + unsigned int focus_button_id; + unsigned int focus_image_button_id; } data; static void init(resource_type resource) @@ -218,14 +218,14 @@ static void handle_input(const mouse* m, const hotkeys* h) return; } if (city_resource_trade_status(data.resource) & TRADE_STATUS_IMPORT) { - int button = 0; + unsigned int button = 0; arrow_buttons_handle_mouse(m_dialog, 0, 0, import_amount_arrow_buttons, 2, &button); if (button) { return; } } if (city_resource_trade_status(data.resource) & TRADE_STATUS_EXPORT) { - int button = 0; + unsigned int button = 0; arrow_buttons_handle_mouse(m_dialog, 0, 0, export_amount_arrow_buttons, 2, &button); if (button) { return; diff --git a/src/window/select_list.c b/src/window/select_list.c index 4fc9b461ab..d533da1bd7 100644 --- a/src/window/select_list.c +++ b/src/window/select_list.c @@ -10,6 +10,8 @@ #include "input/input.h" #define MAX_ITEMS_PER_LIST 20 +#define BASE_LIST_WIDTH 200 +#define MAX_LIST_WIDTH 496 enum { MODE_TEXT, @@ -70,9 +72,10 @@ static struct { int mode; int group; const uint8_t **items; - int num_items; + unsigned int num_items; + int width; void (*callback)(int); - int focus_button_id; + unsigned int focus_button_id; } data; static void init_group(int x, int y, int group, int num_items, void (*callback)(int)) @@ -81,8 +84,12 @@ static void init_group(int x, int y, int group, int num_items, void (*callback)( data.y = y; data.mode = MODE_GROUP; data.group = group; + data.width = BASE_LIST_WIDTH; data.num_items = num_items; data.callback = callback; + for (int i = 0; i < MAX_ITEMS_PER_LIST; i++) { + buttons_list1[i].width = data.width - 10; + } } static void init_text(int x, int y, const uint8_t **items, int num_items, void (*callback)(int)) @@ -93,9 +100,29 @@ static void init_text(int x, int y, const uint8_t **items, int num_items, void ( data.items = items; data.num_items = num_items; data.callback = callback; + data.width = BASE_LIST_WIDTH; + if (data.num_items <= MAX_ITEMS_PER_LIST) { + for (int i = 0; i < num_items; i++) { + int width = text_get_width(data.items[i], FONT_NORMAL_PLAIN) + 10; + if (width > data.width) { + data.width = width; + data.width += BLOCK_SIZE - (data.width % BLOCK_SIZE); + if (width > MAX_LIST_WIDTH) { + data.width = MAX_LIST_WIDTH; + } + } + } + for (int i = 0; i < num_items; i++) { + buttons_list1[i].width = data.width; + } + } else { + for (int i = 0; i < MAX_ITEMS_PER_LIST; i++) { + buttons_list1[i].width = data.width - 10; + } + } } -static int items_in_first_list(void) +static unsigned int items_in_first_list(void) { return data.num_items / 2 + data.num_items % 2; } @@ -104,26 +131,33 @@ static void draw_item(int item_id, int x, int y, int selected) { color_t color = selected ? COLOR_FONT_BLUE : COLOR_BLACK; if (data.mode == MODE_GROUP) { - lang_text_draw_centered_colored(data.group, item_id, data.x + x, data.y + y, 190, FONT_NORMAL_PLAIN, color); + lang_text_draw_centered_colored(data.group, item_id, data.x + x, data.y + y, data.width - 10, + FONT_NORMAL_PLAIN, color); } else { - text_draw_centered(data.items[item_id], data.x + x, data.y + y, 190, FONT_NORMAL_PLAIN, color); + if (data.width == BASE_LIST_WIDTH) { + text_draw_centered(data.items[item_id], data.x + x, data.y + y, BASE_LIST_WIDTH - 10, FONT_NORMAL_PLAIN, color); + } else { + text_draw_ellipsized(data.items[item_id], data.x + x + 5, data.y + y, + data.width - 10, FONT_NORMAL_PLAIN, color); + } } } static void draw_foreground(void) { if (data.num_items > MAX_ITEMS_PER_LIST) { - int max_first = items_in_first_list(); + unsigned int max_first = items_in_first_list(); outer_panel_draw(data.x, data.y, 26, (20 * max_first + 24) / BLOCK_SIZE); - for (int i = 0; i < max_first; i++) { + for (unsigned int i = 0; i < max_first; i++) { draw_item(i, 5, 11 + 20 * i, i + 1 == data.focus_button_id); } - for (int i = 0; i < data.num_items - max_first; i++) { + for (unsigned int i = 0; i < data.num_items - max_first; i++) { draw_item(i + max_first, 205, 11 + 20 * i, MAX_ITEMS_PER_LIST + i + 1 == data.focus_button_id); } } else { - outer_panel_draw(data.x, data.y, 13, (20 * data.num_items + 24) / BLOCK_SIZE); - for (int i = 0; i < data.num_items; i++) { + int width_blocks = (data.width + BLOCK_SIZE - 1) / BLOCK_SIZE; + outer_panel_draw(data.x, data.y, width_blocks, (20 * data.num_items + 24) / BLOCK_SIZE); + for (unsigned int i = 0; i < data.num_items; i++) { draw_item(i, 5, 11 + 20 * i, i + 1 == data.focus_button_id); } } @@ -137,7 +171,7 @@ static int click_outside_window(const mouse *m) width = 26 * BLOCK_SIZE; height = 20 * items_in_first_list() + 24; } else { - width = 13 * BLOCK_SIZE; + width = data.width + BLOCK_SIZE - 1; height = 20 * data.num_items + 24; } return m->left.went_up && (m->x < data.x || m->x >= data.x + width || m->y < data.y || m->y >= data.y + height); @@ -146,11 +180,11 @@ static int click_outside_window(const mouse *m) static void handle_input(const mouse *m, const hotkeys *h) { if (data.num_items > MAX_ITEMS_PER_LIST) { - int items_first = items_in_first_list(); + unsigned int items_first = items_in_first_list(); if (generic_buttons_handle_mouse(m, data.x, data.y, buttons_list1, items_first, &data.focus_button_id)) { return; } - int second_id = 0; + unsigned int second_id = 0; generic_buttons_handle_mouse(m, data.x, data.y, buttons_list2, data.num_items - items_first, &second_id); if (second_id > 0) { data.focus_button_id = second_id + MAX_ITEMS_PER_LIST; diff --git a/src/window/set_salary.c b/src/window/set_salary.c index 9c9841a40a..c84c33dc4f 100644 --- a/src/window/set_salary.c +++ b/src/window/set_salary.c @@ -35,7 +35,7 @@ static generic_button buttons[] = { {144, 285, 352, 20, button_set_salary, button_none, 10, 0}, }; -static int focus_button_id; +static unsigned int focus_button_id; static int get_dialog_width(void) { @@ -62,7 +62,7 @@ static void draw_foreground(void) inner_panel_draw(144, 80, 22, 15); - for (int rank = 0; rank < 11; rank++) { + for (unsigned int rank = 0; rank < 11; rank++) { font_t font = focus_button_id == rank + 2 ? FONT_NORMAL_RED : FONT_NORMAL_WHITE; int width = lang_text_draw(52, rank + 4, 176, 90 + 20 * rank, font); text_draw_money(city_emperor_salary_for_rank(rank), 176 + width, 90 + 20 * rank, font); diff --git a/src/window/text_input.c b/src/window/text_input.c index 5bf510d416..bad3465270 100644 --- a/src/window/text_input.c +++ b/src/window/text_input.c @@ -35,7 +35,7 @@ static struct { int y_offset; int height_blocks; - int focus_button_id; + unsigned int focus_button_id; } data; static void init(const uint8_t *title, const uint8_t *placeholder, const uint8_t *text, int max_length, diff --git a/src/window/trade_prices.c b/src/window/trade_prices.c index d7cb0796d8..336862ccc5 100644 --- a/src/window/trade_prices.c +++ b/src/window/trade_prices.c @@ -109,7 +109,7 @@ static void draw_background(void) const resource_list *list = city_resource_get_potential(); int resource_offset = BLOCK_SIZE * 2; - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { resource_type r = list->items[i]; image_draw(resource_get_data(r)->image.icon, icon_shift + i * resource_offset, 50, COLOR_MASK_NONE, SCALE_NONE); @@ -200,7 +200,7 @@ static resource_type get_tooltip_resource(tooltip_context *c) const resource_list *list = city_resource_get_potential(); - for (int i = 0; i < list->size; i++) { + for (unsigned int i = 0; i < list->size; i++) { int x = x_base + i * BLOCK_SIZE * 2; if (x <= x_mouse && x + 24 > x_mouse && y <= y_mouse && y + 24 > y_mouse) { return list->items[i]; diff --git a/src/window/user_path_setup.c b/src/window/user_path_setup.c new file mode 100644 index 0000000000..c8687b07a8 --- /dev/null +++ b/src/window/user_path_setup.c @@ -0,0 +1,288 @@ +#include "user_path_setup.h" + +#include "core/encoding.h" +#include "core/file.h" +#include "core/image_group.h" +#include "core/string.h" +#include "game/system.h" +#include "graphics/image_button.h" +#include "graphics/generic_button.h" +#include "graphics/panel.h" +#include "graphics/graphics.h" +#include "graphics/lang_text.h" +#include "graphics/screen.h" +#include "graphics/text.h" +#include "graphics/window.h" +#include "platform/file_manager.h" +#include "platform/prefs.h" +#include "platform/user_path.h" +#include "window/plain_message_dialog.h" +#include "window/popup_dialog.h" +#include "window/select_list.h" + +#include + +static struct { + int show_window; + int window_status; + unsigned int button_in_focus; + int first_time; + char user_path[FILE_NAME_MAX]; +} data; + +static void button_pick_option(int param1, int param2); +static void button_ok_cancel(int is_ok, int param2); + +static generic_button path_button = { + 150, 55, 458, 30, button_pick_option, button_none +}; + +static image_button ok_cancel_buttons[] = { + {270, 100, 39, 26, IB_NORMAL, GROUP_OK_CANCEL_SCROLL_BUTTONS, 0, button_ok_cancel, button_none, 1, 0, 1}, + {330, 100, 39, 26, IB_NORMAL, GROUP_OK_CANCEL_SCROLL_BUTTONS, 4, button_ok_cancel, button_none, 0, 0, 1}, +}; + +static void init(int first_time) +{ + data.show_window = !first_time; + snprintf(data.user_path, FILE_NAME_MAX, "%s", pref_user_dir()); + data.button_in_focus = 0; + data.first_time = first_time; + if (data.first_time) { + platform_user_path_copy_campaigns_and_custom_empires(); + } +} + +static void cancel(void) +{ + window_go_back(); + if (data.first_time) { + window_plain_message_dialog_show(TR_USER_DIRECTORIES_CANCELLED_TITLE, TR_USER_DIRECTORIES_CANCELLED_TEXT, 0); + } +} + +static void show_window(int accepted, int checked) +{ + if (!accepted) { + cancel(); + return; + } + data.show_window = 1; +} + +static int encode_path(uint8_t *output, const char *input, int output_size) +{ + encoding_from_utf8(input, output, output_size); + int length = 0; + while (output[length]) { + if (output[length] == '\\') { + output[length] = '/'; + } + length++; + } + return length; +} + +static const uint8_t *get_path_text(void) +{ + static uint8_t text[FILE_NAME_MAX]; + const uint8_t *path_text; + if (*data.user_path) { + if (strcmp(data.user_path, "./") == 0) { + path_text = translation_for(TR_CONFIG_USER_PATH_WITH_SUBDIRECTORIES); + } else if (platform_user_path_recommend() && strcmp(data.user_path, platform_user_path_recommend()) == 0) { + uint8_t *cursor = string_copy(translation_for(TR_CONFIG_USER_PATH_RECOMMENDED), text, FILE_NAME_MAX); + cursor += encode_path(cursor, data.user_path, FILE_NAME_MAX - (cursor - text)); + string_copy(string_from_ascii(")"), cursor, FILE_NAME_MAX - (cursor - text)); + path_text = text; + } else { + encode_path(text, data.user_path, FILE_NAME_MAX); + path_text = text; + } + } else { + path_text = translation_for(TR_CONFIG_USER_PATH_DEFAULT); + } + return path_text; +} + +static void draw_background(void) +{ + graphics_clear_screen(); + + if (!data.first_time) { + window_draw_underlying_window(); + } + if (!data.show_window) { + return; + } + graphics_in_dialog_with_size(640, 144); + + outer_panel_draw(0, 0, 40, 9); + lang_text_draw_centered(CUSTOM_TRANSLATION, TR_USER_DIRECTORIES_WINDOW_TITLE, 0, 20, 640, FONT_LARGE_BLACK); + + lang_text_draw(CUSTOM_TRANSLATION, TR_USER_DIRETORIES_WINDOW_USER_PATH, 16, 64, FONT_NORMAL_BLACK); + + text_draw_ellipsized(get_path_text(), path_button.x + 10, path_button.y + 9, path_button.width - 20, + FONT_NORMAL_BLACK, 0); + + graphics_reset_dialog(); +} + +static void draw_foreground(void) +{ + if (!data.show_window) { + return; + } + + graphics_in_dialog_with_size(640, 144); + + button_border_draw(path_button.x, path_button.y, path_button.width, path_button.height, data.button_in_focus); + image_buttons_draw(0, 0, ok_cancel_buttons, 2); + + graphics_reset_dialog(); +} + +static void handle_input(const mouse *m, const hotkeys *h) +{ + const mouse *m_dialog = mouse_in_dialog_with_size(m, 640, 144); + if (m->right.went_up) { + window_go_back(); + return; + } + if (generic_buttons_handle_mouse(m_dialog, 0, 0, &path_button, 1, &data.button_in_focus) || + image_buttons_handle_mouse(m_dialog, 0, 0, ok_cancel_buttons, 2, 0)) { + return; + } + if (h->escape_pressed) { + hotkey_handle_escape(); + } +} + +static const char *get_path_from_dialog(void) +{ + const char *user_path = data.user_path; + if (!*user_path) { + user_path = pref_user_dir(); + } + if (!*user_path || strcmp(user_path, "./") == 0) { + user_path = pref_data_dir(); + } + const char *path = system_show_select_folder_dialog("Please select your user path folder:", user_path); + if (!path) { + return 0; + } + return path; +} + +static void set_paths(int index) +{ + const char *path = ""; + if (index == 0) { + path = ""; + } else if (index == 1) { + path = "./"; + } else if (index == 2) { + const char *recommended = platform_user_path_recommend(); + if (recommended) { + path = recommended; + } else if (system_supports_select_folder_dialog()) { + path = get_path_from_dialog(); + } + } else if (index == 3 && system_supports_select_folder_dialog()) { + path = get_path_from_dialog(); + } + if (!path) { + return; + } + if (*path && strcmp(path, pref_data_dir()) == 0) { + snprintf(data.user_path, FILE_NAME_MAX, "./"); + } else { + snprintf(data.user_path, FILE_NAME_MAX, "%s", path); + } +} + +static void button_pick_option(int param1, int param2) +{ + static const uint8_t *texts[4]; + static uint8_t recommended_text[FILE_NAME_MAX]; + const char *recommended = platform_user_path_recommend(); + static int total_options = 2; + if (!texts[0]) { + texts[0] = translation_for(TR_CONFIG_USER_PATH_DEFAULT); + texts[1] = translation_for(TR_CONFIG_USER_PATH_WITH_SUBDIRECTORIES); + if (recommended) { + texts[total_options++] = recommended_text; + uint8_t *cursor = string_copy(translation_for(TR_CONFIG_USER_PATH_RECOMMENDED), + recommended_text, FILE_NAME_MAX); + cursor += encode_path(cursor, recommended, FILE_NAME_MAX - (cursor - recommended_text)); + string_copy(string_from_ascii(")"), cursor, FILE_NAME_MAX - (cursor - recommended_text)); + } + if (system_supports_select_folder_dialog()) { + texts[total_options++] = translation_for(TR_CONFIG_USER_PATH_CUSTOM); + } + }; + + window_select_list_show_text(screen_dialog_offset_x() + 150, + screen_dialog_offset_y() + path_button.y + path_button.height, texts, total_options, set_paths); +} + +static void copy_user_files(int accepted, int overwrite) +{ + window_go_back(); + char original_path[FILE_NAME_MAX]; + snprintf(original_path, FILE_NAME_MAX, "%s", pref_user_dir()); + pref_save_user_dir(data.user_path); + platform_user_path_create_subdirectories(); + if (!accepted) { + return; + } + platform_user_path_copy_files(original_path, overwrite); +} + +static void button_ok_cancel(int is_ok, int param2) +{ + if (!is_ok) { + cancel(); + return; + } + if (strcmp(data.user_path, pref_user_dir()) == 0) { + window_go_back(); + return; + } + if (!platform_file_manager_is_directory_writeable(data.user_path)) { + window_plain_message_dialog_show(TR_USER_DIRECTORIES_NOT_WRITEABLE_TITLE, + TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT, !data.first_time); + return; + } + window_popup_dialog_show_confirmation(translation_for(TR_USER_DIRECTORIES_USER_PATH_CHANGED_TITLE), + translation_for(TR_USER_DIRECTORIES_USER_PATH_CHANGED_TEXT), + translation_for(TR_USER_DIRECTORIES_USER_PATH_CHANGED_OVERWRITE), copy_user_files); +} + +static void get_tooltip(tooltip_context *c) +{ + if (data.button_in_focus) { + const uint8_t *path_text = get_path_text(); + if (text_get_width(path_text, FONT_NORMAL_BLACK) > path_button.width - 20) { + c->precomposed_text = path_text; + c->type = TOOLTIP_BUTTON; + } + } +} + +void window_user_path_setup_show(int first_time) +{ + window_type window = { + WINDOW_USER_PATH_SETUP, + draw_background, + draw_foreground, + handle_input, + get_tooltip + }; + init(first_time); + window_show(&window); + if (data.first_time) { + window_popup_dialog_show_confirmation(translation_for(TR_USER_DIRECTORIES_NOT_SET_UP_TITLE), + translation_for(TR_USER_DIRECTORIES_NOT_SET_UP_TEXT), 0, show_window); + } +} diff --git a/src/window/user_path_setup.h b/src/window/user_path_setup.h new file mode 100644 index 0000000000..9676d2862a --- /dev/null +++ b/src/window/user_path_setup.h @@ -0,0 +1,6 @@ +#ifndef WINDOW_USER_PATH_SETUP_H +#define WINDOW_USER_PATH_SETUP_H + +void window_user_path_setup_show(int first_time); + +#endif // WINDOW_USER_PATH_SETUP_H diff --git a/src/window/victory_dialog.c b/src/window/victory_dialog.c index e0a5ffaf61..2ea1a3b3bf 100644 --- a/src/window/victory_dialog.c +++ b/src/window/victory_dialog.c @@ -25,7 +25,7 @@ static generic_button victory_buttons[] = { {32, 176, 480, 20, button_continue_governing, button_none, 60, 0}, }; -static int focus_button_id = 0; +static unsigned int focus_button_id = 0; static int get_next_rank(void) {