diff --git a/.clang-tidy b/.clang-tidy index ef0f6fde7..0b57ab8ea 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,282 +1,18 @@ --- -Checks: 'clang-diagnostic-*,clang-analyzer-*,misc-static-assert,modernize-use-auto,modernize-use-default,modernize-usenullptr,modernize-use-override,performance-*,readability-non-const-parameter,readability-redundant-*,readability-simplify-*,bugprone-*' +Checks: 'clang-diagnostic-*,clang-analyzer-*,readability-non-const-parameter' +WarningsAsErrors: '' +HeaderFileExtensions: + - '' + - h + - hh + - hpp + - hxx +ImplementationFileExtensions: + - c + - cc + - cpp + - cxx HeaderFilterRegex: 'forms/.*|framework/.*|game/.*|library/.*|tests/.*|tools/.*' -AnalyzeTemporaryDtors: false -User: jonny -CheckOptions: - - key: google-readability-braces-around-statements.ShortStatementLines - value: '1' - - key: google-readability-function-size.StatementThreshold - value: '800' - - key: google-readability-namespace-comments.ShortNamespaceLines - value: '10' - - key: google-readability-namespace-comments.SpacesBeforeComments - value: '2' - - key: modernize-loop-convert.MaxCopySize - value: '16' - - key: modernize-loop-convert.MinConfidence - value: reasonable - - key: modernize-loop-convert.NamingStyle - value: CamelCase - - key: modernize-pass-by-value.IncludeStyle - value: llvm - - key: modernize-replace-auto-ptr.IncludeStyle - value: llvm - - key: modernize-use-nullptr.NullMacros - value: 'NULL' - - key: readability-identifier-naming.AbstractClassCase - value: CamelCase - - key: readability-identifier-naming.AbstractClassPrefix - value: '' - - key: readability-identifier-naming.AbstractClassSuffix - value: '' - - key: readability-identifier-naming.ClassCase - value: CamelCase - - key: readability-identifier-naming.ClassConstantCase - value: aNy_CasE - - key: readability-identifier-naming.ClassConstantPrefix - value: '' - - key: readability-identifier-naming.ClassConstantSuffix - value: '' - - key: readability-identifier-naming.ClassMemberCase - value: aNy_CasE - - key: readability-identifier-naming.ClassMemberPrefix - value: '' - - key: readability-identifier-naming.ClassMemberSuffix - value: '' - - key: readability-identifier-naming.ClassMethodCase - value: camelBack - - key: readability-identifier-naming.ClassMethodPrefix - value: '' - - key: readability-identifier-naming.ClassMethodSuffix - value: '' - - key: readability-identifier-naming.ClassPrefix - value: '' - - key: readability-identifier-naming.ClassSuffix - value: '' - - key: readability-identifier-naming.ConstantCase - value: aNy_CasE - - key: readability-identifier-naming.ConstantMemberCase - value: aNy_CasE - - key: readability-identifier-naming.ConstantMemberPrefix - value: '' - - key: readability-identifier-naming.ConstantMemberSuffix - value: '' - - key: readability-identifier-naming.ConstantParameterCase - value: aNy_CasE - - key: readability-identifier-naming.ConstantParameterPrefix - value: '' - - key: readability-identifier-naming.ConstantParameterSuffix - value: '' - - key: readability-identifier-naming.ConstantPrefix - value: '' - - key: readability-identifier-naming.ConstantSuffix - value: '' - - key: readability-identifier-naming.ConstexprFunctionCase - value: aNy_CasE - - key: readability-identifier-naming.ConstexprFunctionPrefix - value: '' - - key: readability-identifier-naming.ConstexprFunctionSuffix - value: '' - - key: readability-identifier-naming.ConstexprMethodCase - value: camelBack - - key: readability-identifier-naming.ConstexprMethodPrefix - value: '' - - key: readability-identifier-naming.ConstexprMethodSuffix - value: '' - - key: readability-identifier-naming.ConstexprVariableCase - value: aNy_CasE - - key: readability-identifier-naming.ConstexprVariablePrefix - value: '' - - key: readability-identifier-naming.ConstexprVariableSuffix - value: '' - - key: readability-identifier-naming.EnumCase - value: CamelCase - - key: readability-identifier-naming.EnumConstantCase - value: aNy_CasE - - key: readability-identifier-naming.EnumConstantPrefix - value: '' - - key: readability-identifier-naming.EnumConstantSuffix - value: '' - - key: readability-identifier-naming.EnumPrefix - value: '' - - key: readability-identifier-naming.EnumSuffix - value: '' - - key: readability-identifier-naming.FunctionCase - value: aNy_CasE - - key: readability-identifier-naming.FunctionPrefix - value: '' - - key: readability-identifier-naming.FunctionSuffix - value: '' - - key: readability-identifier-naming.GlobalConstantCase - value: aNy_CasE - - key: readability-identifier-naming.GlobalConstantPrefix - value: '' - - key: readability-identifier-naming.GlobalConstantSuffix - value: '' - - key: readability-identifier-naming.GlobalFunctionCase - value: aNy_CasE - - key: readability-identifier-naming.GlobalFunctionPrefix - value: '' - - key: readability-identifier-naming.GlobalFunctionSuffix - value: '' - - key: readability-identifier-naming.GlobalVariableCase - value: aNy_CasE - - key: readability-identifier-naming.GlobalVariablePrefix - value: '' - - key: readability-identifier-naming.GlobalVariableSuffix - value: '' - - key: readability-identifier-naming.IgnoreFailedSplit - value: '0' - - key: readability-identifier-naming.InlineNamespaceCase - value: aNy_CasE - - key: readability-identifier-naming.InlineNamespacePrefix - value: '' - - key: readability-identifier-naming.InlineNamespaceSuffix - value: '' - - key: readability-identifier-naming.LocalConstantCase - value: aNy_CasE - - key: readability-identifier-naming.LocalConstantPrefix - value: '' - - key: readability-identifier-naming.LocalConstantSuffix - value: '' - - key: readability-identifier-naming.LocalVariableCase - value: aNy_CasE - - key: readability-identifier-naming.LocalVariablePrefix - value: '' - - key: readability-identifier-naming.LocalVariableSuffix - value: '' - - key: readability-identifier-naming.MemberCase - value: aNy_CasE - - key: readability-identifier-naming.MemberPrefix - value: '' - - key: readability-identifier-naming.MemberSuffix - value: '' - - key: readability-identifier-naming.MethodCase - value: camelBack - - key: readability-identifier-naming.MethodPrefix - value: '' - - key: readability-identifier-naming.MethodSuffix - value: '' - - key: readability-identifier-naming.NamespaceCase - value: aNy_CasE - - key: readability-identifier-naming.NamespacePrefix - value: '' - - key: readability-identifier-naming.NamespaceSuffix - value: '' - - key: readability-identifier-naming.ParameterCase - value: aNy_CasE - - key: readability-identifier-naming.ParameterPackCase - value: aNy_CasE - - key: readability-identifier-naming.ParameterPackPrefix - value: '' - - key: readability-identifier-naming.ParameterPackSuffix - value: '' - - key: readability-identifier-naming.ParameterPrefix - value: '' - - key: readability-identifier-naming.ParameterSuffix - value: '' - - key: readability-identifier-naming.PrivateMemberCase - value: aNy_CasE - - key: readability-identifier-naming.PrivateMemberPrefix - value: '' - - key: readability-identifier-naming.PrivateMemberSuffix - value: '' - - key: readability-identifier-naming.PrivateMethodCase - value: camelBack - - key: readability-identifier-naming.PrivateMethodPrefix - value: '' - - key: readability-identifier-naming.PrivateMethodSuffix - value: '' - - key: readability-identifier-naming.ProtectedMemberCase - value: aNy_CasE - - key: readability-identifier-naming.ProtectedMemberPrefix - value: '' - - key: readability-identifier-naming.ProtectedMemberSuffix - value: '' - - key: readability-identifier-naming.ProtectedMethodCase - value: camelBack - - key: readability-identifier-naming.ProtectedMethodPrefix - value: '' - - key: readability-identifier-naming.ProtectedMethodSuffix - value: '' - - key: readability-identifier-naming.PublicMemberCase - value: aNy_CasE - - key: readability-identifier-naming.PublicMemberPrefix - value: '' - - key: readability-identifier-naming.PublicMemberSuffix - value: '' - - key: readability-identifier-naming.PublicMethodCase - value: camelBack - - key: readability-identifier-naming.PublicMethodPrefix - value: '' - - key: readability-identifier-naming.PublicMethodSuffix - value: '' - - key: readability-identifier-naming.StaticConstantCase - value: aNy_CasE - - key: readability-identifier-naming.StaticConstantPrefix - value: '' - - key: readability-identifier-naming.StaticConstantSuffix - value: '' - - key: readability-identifier-naming.StaticVariableCase - value: aNy_CasE - - key: readability-identifier-naming.StaticVariablePrefix - value: '' - - key: readability-identifier-naming.StaticVariableSuffix - value: '' - - key: readability-identifier-naming.StructCase - value: CamelCase - - key: readability-identifier-naming.StructPrefix - value: '' - - key: readability-identifier-naming.StructSuffix - value: '' - - key: readability-identifier-naming.TemplateParameterCase - value: aNy_CasE - - key: readability-identifier-naming.TemplateParameterPrefix - value: '' - - key: readability-identifier-naming.TemplateParameterSuffix - value: '' - - key: readability-identifier-naming.TemplateTemplateParameterCase - value: aNy_CasE - - key: readability-identifier-naming.TemplateTemplateParameterPrefix - value: '' - - key: readability-identifier-naming.TemplateTemplateParameterSuffix - value: '' - - key: readability-identifier-naming.TypeTemplateParameterCase - value: aNy_CasE - - key: readability-identifier-naming.TypeTemplateParameterPrefix - value: '' - - key: readability-identifier-naming.TypeTemplateParameterSuffix - value: '' - - key: readability-identifier-naming.TypedefCase - value: aNy_CasE - - key: readability-identifier-naming.TypedefPrefix - value: '' - - key: readability-identifier-naming.TypedefSuffix - value: '' - - key: readability-identifier-naming.UnionCase - value: CamelCase - - key: readability-identifier-naming.UnionPrefix - value: '' - - key: readability-identifier-naming.UnionSuffix - value: '' - - key: readability-identifier-naming.ValueTemplateParameterCase - value: aNy_CasE - - key: readability-identifier-naming.ValueTemplateParameterPrefix - value: '' - - key: readability-identifier-naming.ValueTemplateParameterSuffix - value: '' - - key: readability-identifier-naming.VariableCase - value: aNy_CasE - - key: readability-identifier-naming.VariablePrefix - value: '' - - key: readability-identifier-naming.VariableSuffix - value: '' - - key: readability-identifier-naming.VirtualMethodCase - value: camelBack - - key: readability-identifier-naming.VirtualMethodPrefix - value: '' - - key: readability-identifier-naming.VirtualMethodSuffix - value: '' +SystemHeaders: false ... diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index e6fd7b204..d5e9b4577 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -12,7 +12,7 @@ jobs: # well on Windows or Mac. You can convert this to a matrix build if you need # cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v2 @@ -34,7 +34,13 @@ jobs: run: sudo apt-get update - name: Install dependencies - run: sudo apt-get install libsdl2-dev cmake build-essential git libunwind8-dev libboost-locale-dev libboost-filesystem-dev libboost-program-options-dev qtbase5-dev libvorbis-dev ninja-build g++-13 + run: sudo apt-get install libsdl2-dev cmake build-essential git libunwind8-dev libboost-locale-dev libboost-filesystem-dev libboost-program-options-dev qt6-base-dev libvorbis-dev ninja-build + + - name: Install gcc-14 + run: sudo apt install gcc-14 g++-14 + + - name: GCC 14 version check + run: echo "GCC-14:"; which gcc-14;gcc-14 --version; - name: Configure CMake # Use a bash shell so we can use the same syntax for environment variable @@ -44,7 +50,7 @@ jobs: # Note the current convention is to use the -S and -B options here to specify source # and build directories, but this is only available with CMake 3.13 and higher. # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 - run: CC=gcc-13 CXX=g++-13 cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -GNinja + run: CC=gcc-14 CXX=g++-14 cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -GNinja -DUSE_PCH=ON - name: Build working-directory: ${{runner.workspace}}/build diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 3041d03a5..979b6d858 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,6 +5,8 @@ on: [push, pull_request] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release + CLANG_FORMAT: clang-format-18 + CLANG_TIDY: clang-tidy-18 jobs: build: @@ -35,7 +37,7 @@ jobs: run: sudo apt-get update - name: Install dependencies - run: sudo apt-get install libsdl2-dev cmake build-essential git libunwind8-dev libboost-locale-dev libboost-filesystem-dev libboost-program-options-dev qtbase5-dev libvorbis-dev ninja-build clang-format-15 clang-tidy-15 + run: sudo apt-get install libsdl2-dev cmake build-essential git libunwind8-dev libboost-locale-dev libboost-filesystem-dev libboost-program-options-dev qt6-base-dev libvorbis-dev ninja-build ${CLANG_FORMAT} ${CLANG_TIDY} - name: Configure CMake # Use a bash shell so we can use the same syntax for environment variable @@ -45,7 +47,7 @@ jobs: # Note the current convention is to use the -S and -B options here to specify source # and build directories, but this is only available with CMake 3.13 and higher. # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -GNinja -DCLANG_FORMAT=clang-format-15 -DCLANG_TIDY=clang-tidy-15 + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -GNinja -DCLANG_FORMAT=${CLANG_FORMAT} -DCLANG_TIDY=${CLANG_TIDY} - name: Setup Environment (PR) if: ${{ github.event_name == 'pull_request' }} @@ -65,14 +67,11 @@ jobs: working-directory: ${{runner.workspace}} shell: bash run: | - cd $GITHUB_WORKSPACE - if [ "${{env.BEFORE_COMMIT_SHA}}" == "0000000000000000000000000000000000000000" ] - then - echo '$GITHUB_WORKSPACE/tools/lint.sh ${{env.AFTER_COMMIT_SHA}}' - $GITHUB_WORKSPACE/tools/lint.sh ${{env.AFTER_COMMIT_SHA}} - else - echo '$GITHUB_WORKSPACE/tools/lint.sh ${{env.BEFORE_COMMIT_SHA}}..${{env.AFTER_COMMIT_SHA}}' - $GITHUB_WORKSPACE/tools/lint.sh ${{env.BEFORE_COMMIT_SHA}}..${{env.AFTER_COMMIT_SHA}} + cmake --build ${{runner.workspace}}/build -t format-sources + if [[ `git -C $GITHUB_WORKSPACE status --porcelain` ]]; then + echo "Format mismatch:"; + git -C $GITHUB_WORKSPACE diff; + exit 1; fi @@ -83,10 +82,10 @@ jobs: cd $GITHUB_WORKSPACE if [ "${{env.BEFORE_COMMIT_SHA}}" == "0000000000000000000000000000000000000000" ] then - echo 'CLANG_TIDY=clang-tidy-15 BUILD_DIR=${{runner.workspace}}/build $GITHUB_WORKSPACE/tools/lint-tidy.sh ${{env.AFTER_COMMIT_SHA}} || true;' - CLANG_TIDY=clang-tidy-15 BUILD_DIR=${{runner.workspace}}/build $GITHUB_WORKSPACE/tools/lint-tidy.sh ${{env.AFTER_COMMIT_SHA}} || true; + echo 'BUILD_DIR=${{runner.workspace}}/build $GITHUB_WORKSPACE/tools/lint-tidy.sh ${{env.AFTER_COMMIT_SHA}} || true;' + BUILD_DIR=${{runner.workspace}}/build $GITHUB_WORKSPACE/tools/lint-tidy.sh ${{env.AFTER_COMMIT_SHA}} || true; else - echo 'CLANG_TIDY=clang-tidy-15 BUILD_DIR=${{runner.workspace}}/build $GITHUB_WORKSPACE/tools/lint-tidy.sh ${{env.BEFORE_COMMIT_SHA}}..${{env.AFTER_COMMIT_SHA}} || true;' - CLANG_TIDY=clang-tidy-15 BUILD_DIR=${{runner.workspace}}/build $GITHUB_WORKSPACE/tools/lint-tidy.sh ${{env.BEFORE_COMMIT_SHA}}..${{env.AFTER_COMMIT_SHA}} || true; + echo 'BUILD_DIR=${{runner.workspace}}/build $GITHUB_WORKSPACE/tools/lint-tidy.sh ${{env.BEFORE_COMMIT_SHA}}..${{env.AFTER_COMMIT_SHA}} || true;' + BUILD_DIR=${{runner.workspace}}/build $GITHUB_WORKSPACE/tools/lint-tidy.sh ${{env.BEFORE_COMMIT_SHA}}..${{env.AFTER_COMMIT_SHA}} || true; fi diff --git a/.gitmodules b/.gitmodules index cdae4ef5a..73205b622 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,3 +23,6 @@ [submodule "dependencies/fmt"] path = dependencies/fmt url = https://github.com/fmtlib/fmt.git +[submodule "dependencies/magic_enum"] + path = dependencies/magic_enum + url = https://github.com/Neargye/magic_enum.git \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index ee6b7d33a..3bcf19ce1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # check cmake version -CMAKE_MINIMUM_REQUIRED(VERSION 3.9) +CMAKE_MINIMUM_REQUIRED(VERSION 3.30) # This changes the vcpkg features, so needs to be set before the first PROJECT() call option(BUILD_LAUNCHER "Build the launcher" ON) @@ -29,8 +29,9 @@ INCLUDE(CheckCCompilerFlag) string(TOLOWER "${CMAKE_BUILD_TYPE}" lower_build_type) option(LTO "Build using link-time-optimisations" OFF) -option(MSVC_PDB "Always generate PDB files" OFF) +option(MSVC_PDB "Always generate PDB files" ON) option(ENABLE_TESTS "Build some unit tests" ON) +option(USE_PCH "Enable precompiled header use during build" OFF) option(EXTRACT_DATA "Run the data extractor as part of the default target" ON) set(CD_PATH ${CMAKE_SOURCE_DIR}/data/cd.iso CACHE STRING "Path to cd.iso (used @@ -76,6 +77,8 @@ endif(LTO) # MSVC has default flags that CMake doesn't set if (MSVC) add_definitions(-DUNICODE -D_UNICODE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8") if (MSVC_VERSION GREATER_EQUAL 1910) if (MSVC_VERSION EQUAL 1928) @@ -188,7 +191,7 @@ add_dependencies(format format-sources) set(CLANG_FORMAT clang-format CACHE STRING "clang-format executable name in PATH") foreach(FORMAT_SOURCE ${FORMAT_SOURCES}) - add_custom_command(TARGET format-sources COMMAND ${CLANG_FORMAT} -i ${FORMAT_SOURCE} DEPENDS ${FORMAT_SOURCE} .clang-format) + add_custom_command(TARGET format-sources COMMAND ${CLANG_FORMAT} -i ${FORMAT_SOURCE} POST_BUILD) endforeach() file(GLOB_RECURSE XML_FILES ${CMAKE_SOURCE_DIR}/data/*.xml) diff --git a/CODE_STYLE.md b/CODE_STYLE.md index ac62d02ab..bfac4af08 100644 --- a/CODE_STYLE.md +++ b/CODE_STYLE.md @@ -15,7 +15,7 @@ GCCIsntMuchBetter C++11 features are heavily encouraged - patterns from 'older' c++ versions that have been superceded should be avoided. -The formatting sections of this document are enforced by the [clang-format tool](http://llvm.org/releases/15.0.0/tools/clang/docs/ClangFormat.html). Currently, version '15.0' of ``clang-format`` is to be used. The configuration file ``.clang-format`` in the root of the OpenApoc source repository should match the formatting guidelines specified below. +The formatting sections of this document are enforced by the [clang-format tool](https://releases.llvm.org/18.1.1/tools/clang/docs/ClangFormat.html). Currently, version '18.0' of ``clang-format`` is to be used. The configuration file ``.clang-format`` in the root of the OpenApoc source repository should match the formatting guidelines specified below. With this, it is highly recommended to run ``clang-format`` on all modified files before check-in. This can be run on source files with the following command: diff --git a/README.md b/README.md index 1aead7d8f..c05586225 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # OpenApocalypse [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Are%20you%20a%20fan%20of%20X-Com%20Apocalypse?%20OpenApoc%20is%20a%20clone%20of%20this%20great%20game%20-%20contribute!%20https://github.com/OpenApoc/OpenApoc&hashtags=games,openapoc,xcom) -> OpenApoc is an open-source re-implementation of the original [X-COM: Apocalypse](https://www.ufopaedia.org/index.php/Apocalypse), that requires the original files to run, licensed under the GPL3 and written in C++ / SDL2. It was originally founded by PmProg in July 2014, and has since grown in [community](https://www.ufopaedia.org/index.php/Credits_(OpenApoc)). +> OpenApoc is an open-source re-implementation of the original [X-COM: Apocalypse](https://www.ufopaedia.org/index.php/Apocalypse), that requires the original files to run, licensed under the GPL3 and written in C++ / SDL2. It was originally founded by PmProg in July 2014, and has since grown a significant [community](https://www.ufopaedia.org/index.php/Credits_(OpenApoc)). [![Linux Build Status](https://img.shields.io/travis/OpenApoc/OpenApoc?branch=master&label=Travis%20Linux&logo=Travis%20CI&logoColor=ffffff&labelColor=282828)](https://travis-ci.com/github/OpenApoc/OpenApoc) [![Windows Build Status](https://img.shields.io/appveyor/build/OpenApoc/openapoc?branch=master&label=AppVeyor%20Windows&logo=appveyor&logoColor=ffffff&labelColor=282828)](https://ci.appveyor.com/project/openapoc/openapoc/branch/master) @@ -33,44 +33,46 @@ ## Copyright -All rights for the original game and its resources belong to their respective owners. We do not encourage and do not support any form of illegal usage of the original game. We strongly advise to purchase the original game on GOG or other platforms. Pirated ISOs are not supported and will cause issues such as crashes and map problems with OpenApoc. +All rights for the original game and its resources belong to their respective owners. +We do not encourage and do not support any form of illegal usage of the original game. +We strongly advise to purchase the original game on STEAM or another platform of your choosing. +Pirated disc images and archives are not supported and will cause issues such as crashes and map problems with OpenApoc. ## Key Features -* Unlimited modding capabilities, which was not possible in the original -* Port the game to any platform you like (windows, linux, android etc) -* Support for modern screen resolutions -* Added a full debug system ([hot keys](https://github.com/OpenApoc/OpenApoc/blob/master/README_HOTKEYS.txt), etc.) -* Added 'more options' menu (with more than 40 improvements) -* Added skirmish module (fast fight) -* The new engine has ample opportunities for expansion and changes: - * High FPS, smooth sound during the game without bugs from original - * No limitations which were in vanilla - * Modern formats -* After release, we can add Julian Gollop's cut ideas to the game through mods. Many have already been added but they need functionality and balance. * [![Julian Gollop](https://img.shields.io/reddit/user-karma/combined/JulianGollop?style=social)](https://www.reddit.com/user/JulianGollop/) "Yes, I am aware of the openApoc project and I very much do support it." -* Fans creating Big Apoc Concept, for modders, thats should make OpenApoc more balanced, to provide: - * A variety of interesting gameplay solutions - * Make the game more complex and diverse - * L.O.R.E more fulfilling, deep and mysterious, intertwined with real history and other games - * Ending the game can be more interesting and less predictable +* Full modding capability - You can add or change almost anything! +* Options for modding that allow opportunity to make OpenApoc: + * More balanced + * More diverse + * More immersive +* Human-Readable Savegame editing - It's all XML in a ZIP archvive so you can edit/tweak in progress games to your liking! +* Support for modern screen resolutions and display scaling at a silky smooth 60fps +* Added a 'More Options' menu that allows players to select dozens of new optional improvements and enhancements +* Added a full debug system ([Hot Keys](https://github.com/OpenApoc/OpenApoc/blob/master/README_HOTKEYS.txt), etc.) +* Port the game to any platform you like (Windows, Linux, Etc.) +* Added a Skirmish Mode for quick fights and custom battles (Experimental) +* The new engine has ample opportunities for expansion and refinements including: + * High FPS + * Smooth sound playback with none of the pop/clicks/stutters of the original game +* The potential to add cut and missing features from the Original Game - some of these are already included even at current Alpha state or with the handful of mods already available! ## What's left? -1. [TO HAVE A TRULY PLAYABLE ALPHA STATE (DONE)](https://github.com/OpenApoc/OpenApoc/issues/263) -2. [TO REACH A BETA STATE (When All features implemented)](https://github.com/OpenApoc/OpenApoc/issues/264) -3. [TO REACH OPENAPOC RELEASE 1.0](https://github.com/OpenApoc/OpenApoc/issues/265) +1. [TO HAVE A TRULY PLAYABLE ALPHA STATE](https://github.com/OpenApoc/OpenApoc/issues/263) +2. [TO REACH A BETA STATE (All core Original Game features implemented)](https://github.com/OpenApoc/OpenApoc/issues/264) +3. [TO REACH OPENAPOC RELEASE 1.0 (Final polishing and testing to match or exceed Original Game state)](https://github.com/OpenApoc/OpenApoc/issues/265) 4. [Modding Functions, Extra Features, Enhancements and Quality of Life Updates](https://github.com/OpenApoc/OpenApoc/issues/941) ## Contribute and FAQ -http://openapoc.org/#contribute +http://openapoc.org/#contribute - Currently Offline, please use [Discord](https://discord.gg/f8Rayre) >Here you find news, detailing how you can participate in project. You can support the project by testing, translating, modding, drawing, modeling, concepting etc.. -http://openapoc.org/#faq ->Here you find the detailed FAQ (frequently asked questions) +http://openapoc.org/#faq - Currently Offline, please use [Discord](https://discord.gg/f8Rayre) +>Here you find the detailed FAQ (Frequently Asked Questions) ## Building @@ -94,6 +96,7 @@ The following libraries are also used, but are shipped as submodules in the repo * [physfs](https://icculus.org/physfs/) - Library for reading data from .iso files or directory trees (Note: We use a patched version, available on [GitHub](https://github.com/JonnyH/physfs-hg-import/tree/fix-iso) - required to read the .iso files we use). * [pugixml](https://pugixml.org) - XML library used for reading/writing the game data files. * [fmtlib](https://github.com/fmtlib/fmt) - A c++ string formatting library - proposed for c++20 standard. +* [magic_enum](https://github.com/Neargye/magic_enum) - Header-only C++17 library provides static reflection for enums, work with any enum type without any macro or boilerplate code. ### Building on Windows @@ -112,13 +115,13 @@ git submodule update --init --recursive * For x64 builds: ```cmd -vcpkg --triplet x64-windows install sdl2 boost-locale boost-program-options boost-uuid boost-crc qt5-base libvorbis +vcpkg --triplet x64-windows install sdl2 boost-locale boost-program-options boost-uuid boost-crc qt-base6-dev libvorbis ``` * For x86 builds: ```cmd -vcpkg --triplet x86-windows install sdl2 boost-locale boost-program-options boost-uuid boost-crc qt5-base libvorbis +vcpkg --triplet x86-windows install sdl2 boost-locale boost-program-options boost-uuid boost-crc qt-base6-dev libvorbis ``` * For list of all supported by Vcpkg architectures: `vcpkg help triplet` @@ -146,25 +149,25 @@ vcpkg --triplet x86-windows install sdl2 boost-locale boost-program-options boos ### Building on Linux -(Tested on Ubuntu 22.04) +(Tested on Ubuntu 22.04 and 24.04) * On Ubuntu, install the following packages: ```sh -sudo apt-get install sdl2-dev cmake build-essential git libunwind8-dev libboost-locale-dev libboost-program-options-dev qtbase5-dev libvorbis-dev +sudo apt-get install libsdl2-dev cmake build-essential git libunwind8-dev libboost-locale-dev libboost-program-options-dev qtbase5-dev libvorbis-dev ``` * On Mageia, install the following packages as root: ```sh -urpmi "cmake(sdl2)" libstdc++-static-devel boost-devel boost unwind-devel task-c++-devel cmake git qtbase5-devel libvorbis-devel +urpmi "cmake(sdl2)" libstdc++-static-devel boost-devel boost unwind-devel task-c++-devel cmake git qt6-devel libvorbis-devel ``` * On Fedora or other RedHat distro, install the folowing packages as root: ```sh yum groupinstall "Development Tools" "Development Libraries" -yum install git SDL2-devel cmake libunwind-devel qt5-qtbase-devel libvorbis-devel +yum install git SDL2-devel cmake libunwind-devel qt6-qtbase-devel libvorbis-devel ``` * Checkout OpenApoc from GitHub. @@ -205,7 +208,7 @@ make -j4 ### Building on macOS -(Tested on macOS Ventura 13.0 (22A380) +(Tested on macOS Sequoia 15.6 (24G84) * On macOS, install the [Homebrew](https://brew.sh): @@ -229,8 +232,18 @@ git submodule update --init --recursive * Use the homebrew install the following dependencies: ```sh -brew install cmake boost pkg-config sdl2 qt@5 libvorbis -echo 'export PATH="/opt/homebrew/opt/qt@5/bin:$PATH"' >> ~/.bashrc +brew install cmake boost pkg-config sdl2 qt@6 libvorbis +``` + +* Add the Qt install to path. + +* If using zsh (MacOS default since Catalina 10.15): +```sh +echo 'export PATH="/opt/homebrew/opt/qt@6/bin:$PATH"' >> ~/.zprofile +``` +* Or if using bash: +```sh +echo 'export PATH="/opt/homebrew/opt/qt@6/bin:$PATH"' >> ~/.bashrc ``` * Copy the cd.iso file to the 'data' directory under the repository root (Note - despite dosbox having good linux support, the steam version of X-Com Apocalypse will only install if Steam Play is enabled). @@ -276,13 +289,13 @@ OPENGL 2.0 SUPPORTIVE VIDEO CARDS ARE REQUIRED WINDOWS USERS: You will require the LATEST Visual C++ Libraries obtained from windows update to run OpenApoc https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170 -(Keep in mind that OpenApoc is ALPHA STATE - this means bugs, crushes and not all features implemented, use our bug-tracker at https://github.com/OpenApoc/OpenApoc/issues to report bugs and navigate known ones) +Simple steps to play OpenApoc on Windows right now +(Keep in mind that it is ALPHA - this means bugs, crushes and not all features implemented, use our bug-tracker at https://github.com/OpenApoc/OpenApoc/issues to report bugs and navigate known ones) -1) Download the OpenApoc core files: [![Windows Build Status](https://img.shields.io/appveyor/build/OpenApoc/openapoc?branch=master&label=AppVeyor%20Windows&logo=appveyor&logoColor=ffffff&labelColor=282828)](https://ci.appveyor.com/project/openapoc/openapoc/branch/master) (Latest master build) -- If the build link above doesn't work, visit https://ci.appveyor.com/project/OpenApoc/openapoc/history +1) Download the OpenApoc core files from https://github.com/OpenApoc/OpenApoc/releases +- For experimental builds visit https://ci.appveyor.com/project/OpenApoc/openapoc/history - If you see a green bar next to the latest build then you can download it, click a build that is green, or use "Show More" to list all builds - Click ARTIFACTS (Currently only Windows x64) -- If there are no artifacts use https://github.com/OpenApoc/OpenApoc/releases for the latest Winx64 compile - Download the option that ends with a ".exe" (and without "debug" in it) - Run the downloaded exe installer, this will guide you through the installation - Use "portable install" if you want saves and settings to remain in the install directory @@ -293,7 +306,7 @@ https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msv - If the disc image is in .iso format, rename it to "cd.iso" - We also support the GOG .cue / .bin files! -3) Put cd.iso (image or folder) into the data folder under the specified OpenApoc install folder +3) Put cd.iso (image or folder) into the "data" folder under the specified OpenApoc install folder - If you have already specified the "cd.iso" location in the installer, you don't need to do this step - To use GOG .cue/.bin you rename the XCOM.cue file to "cd.iso", put that in the OpenApoc data folder, then put the XCOM.BIN, without renaming it, into the data folder too @@ -302,11 +315,13 @@ https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msv ## Contact us -If you're interested, please visit our [website](http://openapoc.org). -* We have [forums](http://openapoc.org/forum/) - please pop by and introduce yourself! -* We have an [Discord](https://discord.gg/f8Rayre) channel -* We have an IRC channel on [Freenode](http://webchat.freenode.net/?channels=openapoc) - [#openapoc](irc://irc.freenode.net/#openapoc). +If you're interested, please visit our [website](http://openapoc.org) (Currently Offline, please use [Discord](https://discord.gg/f8Rayre)). +* We have a [Discord](https://discord.gg/f8Rayre) - MOST ACTIVE PLACE FOR ALL THINGS OPENAPOC! * We have a [Youtube](https://www.youtube.com/c/OpenApoc) channel. +* We have a [forum](http://openapoc.org/forum/) (Currently Offline, please use [Discord](https://discord.gg/f8Rayre)) + +## Unnofficial and Community Contacts + * We have a [Facebook](https://www.facebook.com/openapoc) page. -* We have a [Vkontakte](https://vk.com/openapoc) page. * We have a [Reddit](https://reddit.com/r/openapoc) page. +* All VK Presence is currently unofficial diff --git a/appveyor-dev.yml b/appveyor-dev.yml index 794473c1c..3c0642e5d 100644 --- a/appveyor-dev.yml +++ b/appveyor-dev.yml @@ -7,25 +7,19 @@ skip_tags: true os: Visual Studio 2022 configuration: - Release -# - Debug platform: - x64 -# - Win32 environment: APPVEYOR_SAVE_CACHE_ON_ERROR: true -init: - - if "%PLATFORM%"=="x64" (set VCPKG_DEFAULT_TRIPLET=x64-windows) - - if "%PLATFORM%"=="x64" (set VCVARS_ARCH=amd64) - - if "%PLATFORM%"=="x64" (set QTPATH=C:\Qt\5.15\msvc2019_64) - - if "%PLATFORM%"=="Win32" (set VCPKG_DEFAULT_TRIPLET=x86-windows) - - if "%PLATFORM%"=="Win32" (set VCVARS_ARCH=amd64_x86) - - if "%PLATFORM%"=="Win32" (set QTPATH=C:\Qt\5.15\msvc2019) + VCPKG_DEFAULT_TRIPLET: x64-windows + VCVARS_ARCH: amd64 + QTPATH: C:\Qt\6.9\msvc2022_64 #clone_depth: 10 cache: C:\Users\appveyor\AppData\Local\vcpkg\archives -> appveyor-dev.yml before_build: - cd c:\tools\vcpkg - git pull - - git checkout 2023.08.09 + - git checkout 2025.09.17 - .\bootstrap-vcpkg.bat - cd %APPVEYOR_BUILD_FOLDER% - vcpkg install @@ -34,7 +28,7 @@ before_build: - 7z e temp\cd.iso.xz -odata\ - call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" %VCVARS_ARCH% build_script: - - cmake -DMSVC_PDB=ON . -GNinja -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE="%CONFIGURATION%" -DCMAKE_PREFIX_PATH=%QTPATH% -DUSE_SYSTEM_QT=ON + - cmake -DMSVC_PDB=ON -DUSE_PCH=ON . -GNinja -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE="%CONFIGURATION%" -DCMAKE_PREFIX_PATH=%QTPATH% -DUSE_SYSTEM_QT=ON - cmake --build . after_build: - git describe --tags > build-id @@ -47,7 +41,7 @@ after_build: - copy bin\*.dll OpenApoc-%OPENAPOC_VERSION%\ - copy bin\openapoc.exe OpenApoc-%OPENAPOC_VERSION%\ - copy bin\openapoc_launcher.exe OpenApoc-%OPENAPOC_VERSION%\ - - start %QTPATH%\bin\windeployqt --no-angle --no-opengl-sw --no-compiler-runtime OpenApoc-%OPENAPOC_VERSION%\OpenApoc_Launcher.exe + - start %QTPATH%\bin\windeployqt --no-opengl-sw --no-compiler-runtime OpenApoc-%OPENAPOC_VERSION%\OpenApoc_Launcher.exe - del data\cd.iso - xcopy /E data OpenApoc-%OPENAPOC_VERSION%\data\ - copy portable.txt OpenApoc-%OPENAPOC_VERSION%\ diff --git a/appveyor.yml b/appveyor.yml index ecb2f42a3..717010aab 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,25 +7,19 @@ branches: os: Visual Studio 2022 configuration: - Release -# - Debug platform: - x64 -# - Win32 environment: APPVEYOR_SAVE_CACHE_ON_ERROR: true -init: - - if "%PLATFORM%"=="x64" (set VCPKG_DEFAULT_TRIPLET=x64-windows) - - if "%PLATFORM%"=="x64" (set VCVARS_ARCH=amd64) - - if "%PLATFORM%"=="x64" (set QTPATH=C:\Qt\5.15\msvc2019_64) - - if "%PLATFORM%"=="Win32" (set VCPKG_DEFAULT_TRIPLET=x86-windows) - - if "%PLATFORM%"=="Win32" (set VCVARS_ARCH=amd64_x86) - - if "%PLATFORM%"=="Win32" (set QTPATH=C:\Qt\5.15\msvc2019) + VCPKG_DEFAULT_TRIPLET: x64-windows + VCVARS_ARCH: amd64 + QTPATH: C:\Qt\6.9\msvc2022_64 #clone_depth: 10 cache: C:\Users\appveyor\AppData\Local\vcpkg\archives -> appveyor.yml before_build: - cd c:\tools\vcpkg - git pull - - git checkout 2023.08.09 + - git checkout 2025.09.17 - .\bootstrap-vcpkg.bat - cd %APPVEYOR_BUILD_FOLDER% - vcpkg install @@ -35,7 +29,7 @@ before_build: - choco install nsis -pre - call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" %VCVARS_ARCH% build_script: - - cmake -DMSVC_PDB=ON . -GNinja -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE="%CONFIGURATION%" -DCMAKE_PREFIX_PATH=%QTPATH% -DUSE_SYSTEM_QT=ON + - cmake -DMSVC_PDB=ON -DUSE_PCH=ON . -GNinja -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE="%CONFIGURATION%" -DCMAKE_PREFIX_PATH=%QTPATH% -DUSE_SYSTEM_QT=ON - cmake --build . after_build: - git describe --tags > build-id @@ -48,7 +42,7 @@ after_build: - copy bin\*.dll OpenApoc-%OPENAPOC_VERSION%\ - copy bin\openapoc.exe OpenApoc-%OPENAPOC_VERSION%\ - copy bin\openapoc_launcher.exe OpenApoc-%OPENAPOC_VERSION%\ - - start %QTPATH%\bin\windeployqt --no-angle --no-opengl-sw --no-compiler-runtime OpenApoc-%OPENAPOC_VERSION%\OpenApoc_Launcher.exe + - start %QTPATH%\bin\windeployqt ---no-opengl-sw --no-compiler-runtime OpenApoc-%OPENAPOC_VERSION%\OpenApoc_Launcher.exe - del data\cd.iso - xcopy /E data OpenApoc-%OPENAPOC_VERSION%\data\ - copy portable.txt OpenApoc-%OPENAPOC_VERSION%\ @@ -59,6 +53,9 @@ after_build: - del OpenApoc-%OPENAPOC_VERSION%\portable.txt - '"C:\Program Files (x86)\NSIS\makensis.exe" /DGAME_VERSION=%OPENAPOC_VERSION% install\windows\installer.nsi' - appveyor PushArtifact install\windows\install-openapoc-%OPENAPOC_VERSION%.exe + - copy bin\*.pdb OpenApoc-%OPENAPOC_VERSION%\ + - 7z a %OPENAPOC_DEBUG_FILENAME% OpenApoc-%OPENAPOC_VERSION%\OpenApoc.pdb OpenApoc-%OPENAPOC_VERSION%\OpenApoc_Launcher.pdb -mx=9 -myx=7 + - appveyor PushArtifact %OPENAPOC_DEBUG_FILENAME% before_test: - 7z e temp\cd.iso.xz -odata\ test_script: diff --git a/data/forms/aequipscreen.form b/data/forms/aequipscreen.form index 0504b6bb9..ef6124ad3 100644 --- a/data/forms/aequipscreen.form +++ b/data/forms/aequipscreen.form @@ -21,8 +21,8 @@ diff --git a/data/forms/basescreen.form b/data/forms/basescreen.form index c1f767fc1..34b92db7c 100644 --- a/data/forms/basescreen.form +++ b/data/forms/basescreen.form @@ -21,8 +21,8 @@ bigfont diff --git a/data/forms/cheatoptions.form b/data/forms/cheatoptions.form index 03c982f51..d5e518690 100644 --- a/data/forms/cheatoptions.form +++ b/data/forms/cheatoptions.form @@ -15,8 +15,8 @@ bigfont diff --git a/data/forms/city/alert.form b/data/forms/city/alert.form index 4215b7efe..5ea1fe0f1 100644 --- a/data/forms/city/alert.form +++ b/data/forms/city/alert.form @@ -17,8 +17,8 @@ bigfont diff --git a/data/forms/city/basebuy.form b/data/forms/city/basebuy.form index 3cc36fa0f..1d15ebf66 100644 --- a/data/forms/city/basebuy.form +++ b/data/forms/city/basebuy.form @@ -27,8 +27,8 @@ bigfont diff --git a/data/forms/city/baseselect.form b/data/forms/city/baseselect.form index db8d66115..4b723acbe 100644 --- a/data/forms/city/baseselect.form +++ b/data/forms/city/baseselect.form @@ -18,8 +18,8 @@ bigfont diff --git a/data/forms/city/bribe.form b/data/forms/city/bribe.form index 67d8b09bf..39e3d1ae6 100644 --- a/data/forms/city/bribe.form +++ b/data/forms/city/bribe.form @@ -16,8 +16,8 @@ bigfont diff --git a/data/forms/city/building.form b/data/forms/city/building.form index 24ba321d4..482a877ea 100644 --- a/data/forms/city/building.form +++ b/data/forms/city/building.form @@ -16,8 +16,8 @@ bigfont diff --git a/data/forms/city/debugoverlay_city.form b/data/forms/city/debugoverlay_city.form index 601b6d2ea..a787f8657 100644 --- a/data/forms/city/debugoverlay_city.form +++ b/data/forms/city/debugoverlay_city.form @@ -47,7 +47,7 @@ smalfont - diff --git a/data/forms/mapselector.form b/data/forms/mapselector.form index 1bc70f188..e6e7ef036 100644 --- a/data/forms/mapselector.form +++ b/data/forms/mapselector.form @@ -16,8 +16,8 @@ bigfont diff --git a/data/forms/messagelog.form b/data/forms/messagelog.form index 9ed607103..1ca946f22 100644 --- a/data/forms/messagelog.form +++ b/data/forms/messagelog.form @@ -16,8 +16,8 @@ bigfont diff --git a/data/forms/moreoptions.form b/data/forms/moreoptions.form index 772539b7f..adcdb4f96 100644 --- a/data/forms/moreoptions.form +++ b/data/forms/moreoptions.form @@ -15,8 +15,8 @@ bigfont @@ -56,6 +56,7 @@ --> + @@ -122,6 +123,18 @@ + + + + + BUTTON_CHECKBOX_FALSE + BUTTON_CHECKBOX_TRUE + + @@ -34,8 +34,8 @@ city/dollar-icon.png diff --git a/data/forms/researchscreen.form b/data/forms/researchscreen.form index 349f0778c..cd8337252 100644 --- a/data/forms/researchscreen.form +++ b/data/forms/researchscreen.form @@ -16,8 +16,8 @@ bigfont @@ -82,8 +82,8 @@ smalfont diff --git a/data/forms/researchselect.form b/data/forms/researchselect.form index e3f0f3305..91eaf7004 100644 --- a/data/forms/researchselect.form +++ b/data/forms/researchselect.form @@ -16,8 +16,8 @@ bigfont diff --git a/data/forms/savemenu.form b/data/forms/savemenu.form index b6f9376e9..9a2984839 100644 --- a/data/forms/savemenu.form +++ b/data/forms/savemenu.form @@ -11,8 +11,8 @@ diff --git a/data/forms/selectforces.form b/data/forms/selectforces.form index f625d1167..2a6790063 100644 --- a/data/forms/selectforces.form +++ b/data/forms/selectforces.form @@ -17,8 +17,8 @@ bigfont diff --git a/data/forms/skirmish.form b/data/forms/skirmish.form index 4000cc3a1..664098587 100644 --- a/data/forms/skirmish.form +++ b/data/forms/skirmish.form @@ -17,8 +17,8 @@ bigfont diff --git a/data/forms/transactionscreen.form b/data/forms/transactionscreen.form index 704786f36..a21750647 100644 --- a/data/forms/transactionscreen.form +++ b/data/forms/transactionscreen.form @@ -15,8 +15,8 @@ bigfont @@ -31,8 +31,8 @@ city/dollar-icon.png diff --git a/data/forms/ufopaedia.form b/data/forms/ufopaedia.form index db32120d4..a1e488ecd 100644 --- a/data/forms/ufopaedia.form +++ b/data/forms/ufopaedia.form @@ -85,6 +85,12 @@ smalfont + + diff --git a/data/languages/ufo_string.pot b/data/languages/ufo_string.pot index 5295cf704..563a8b8a6 100644 --- a/data/languages/ufo_string.pot +++ b/data/languages/ufo_string.pot @@ -4448,7 +4448,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_string_cs.po b/data/languages/ufo_string_cs.po index 6c3b47d54..71864e7d9 100644 --- a/data/languages/ufo_string_cs.po +++ b/data/languages/ufo_string_cs.po @@ -4450,7 +4450,7 @@ msgstr "Zásoba munice" msgid "Cargo" msgstr "Náklad" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Cizác. náklad" msgid "Jamming" diff --git a/data/languages/ufo_string_de_DE.po b/data/languages/ufo_string_de_DE.po index fa57cf1f1..46405c45b 100644 --- a/data/languages/ufo_string_de_DE.po +++ b/data/languages/ufo_string_de_DE.po @@ -4449,7 +4449,7 @@ msgstr "Munitionskapazität" msgid "Cargo" msgstr "Fracht" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Fstglt. Aliens" msgid "Jamming" diff --git a/data/languages/ufo_string_en_GB.po b/data/languages/ufo_string_en_GB.po index 5295cf704..563a8b8a6 100644 --- a/data/languages/ufo_string_en_GB.po +++ b/data/languages/ufo_string_en_GB.po @@ -4448,7 +4448,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_string_es.po b/data/languages/ufo_string_es.po index e81082f8a..d6b7ba2a6 100644 --- a/data/languages/ufo_string_es.po +++ b/data/languages/ufo_string_es.po @@ -4449,7 +4449,7 @@ msgstr "Capacidad de Munición" msgid "Cargo" msgstr "Carga" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Alienígenas" msgid "Jamming" diff --git a/data/languages/ufo_string_fr_FR.po b/data/languages/ufo_string_fr_FR.po index e65e0bc42..788caf0d7 100644 --- a/data/languages/ufo_string_fr_FR.po +++ b/data/languages/ufo_string_fr_FR.po @@ -4450,7 +4450,7 @@ msgstr "Capacité de munitions" msgid "Cargo" msgstr "Cargaison" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Aliens pris" msgid "Jamming" diff --git a/data/languages/ufo_string_it.po b/data/languages/ufo_string_it.po index 8b53d5d20..137097278 100644 --- a/data/languages/ufo_string_it.po +++ b/data/languages/ufo_string_it.po @@ -4450,7 +4450,7 @@ msgstr "Munizioni" msgid "Cargo" msgstr "Cargo" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Alieni cont." msgid "Jamming" diff --git a/data/languages/ufo_string_pl.po b/data/languages/ufo_string_pl.po index 61424cdab..6df7443e2 100644 --- a/data/languages/ufo_string_pl.po +++ b/data/languages/ufo_string_pl.po @@ -4450,7 +4450,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_string_pt_BR.po b/data/languages/ufo_string_pt_BR.po index 91330229c..5d14acca2 100644 --- a/data/languages/ufo_string_pt_BR.po +++ b/data/languages/ufo_string_pt_BR.po @@ -4450,7 +4450,7 @@ msgstr "Capacidade p/ munição" msgid "Cargo" msgstr "Carga" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Alienígenas Aprisionados" msgid "Jamming" diff --git a/data/languages/ufo_string_ru_RU.po b/data/languages/ufo_string_ru_RU.po index 71f752955..838629822 100644 --- a/data/languages/ufo_string_ru_RU.po +++ b/data/languages/ufo_string_ru_RU.po @@ -4455,7 +4455,7 @@ msgstr "Боезапас" msgid "Cargo" msgstr "Груз" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Пришельцев удерживается" msgid "Jamming" diff --git a/data/languages/ufo_string_uk.po b/data/languages/ufo_string_uk.po index 72926769b..463affb3b 100644 --- a/data/languages/ufo_string_uk.po +++ b/data/languages/ufo_string_uk.po @@ -4448,7 +4448,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_cs.po b/data/languages/ufo_stringpo_cs.po index 35609116b..fd9621fe1 100644 --- a/data/languages/ufo_stringpo_cs.po +++ b/data/languages/ufo_stringpo_cs.po @@ -4452,7 +4452,7 @@ msgstr "Zásoba munice" msgid "Cargo" msgstr "Náklad" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Cizác. náklad" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_de_DE.po b/data/languages/ufo_stringpo_de_DE.po index 00479ca34..02a3c2439 100644 --- a/data/languages/ufo_stringpo_de_DE.po +++ b/data/languages/ufo_stringpo_de_DE.po @@ -4449,7 +4449,7 @@ msgstr "Munitionskapazität" msgid "Cargo" msgstr "Fracht" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Fstglt. Aliens" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_en.po b/data/languages/ufo_stringpo_en.po index 639414b80..ee3e872d8 100644 --- a/data/languages/ufo_stringpo_en.po +++ b/data/languages/ufo_stringpo_en.po @@ -4448,8 +4448,8 @@ msgstr "Ammo capacity" msgid "Cargo" msgstr "Cargo" -msgid "Aliens Held" -msgstr "Aliens Held" +msgid "Max Samples" +msgstr "Max Samples" msgid "Jamming" msgstr "Jamming" diff --git a/data/languages/ufo_stringpo_en_GB.po b/data/languages/ufo_stringpo_en_GB.po index 0b3b375c0..98d00d97c 100644 --- a/data/languages/ufo_stringpo_en_GB.po +++ b/data/languages/ufo_stringpo_en_GB.po @@ -4450,7 +4450,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_es.po b/data/languages/ufo_stringpo_es.po index 72bfe14b4..0386849c6 100644 --- a/data/languages/ufo_stringpo_es.po +++ b/data/languages/ufo_stringpo_es.po @@ -4450,7 +4450,7 @@ msgstr "Capacidad de Munición" msgid "Cargo" msgstr "Carga" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Alienígenas" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_et_EE.po b/data/languages/ufo_stringpo_et_EE.po index 42cbc5343..00c0b7d3b 100644 --- a/data/languages/ufo_stringpo_et_EE.po +++ b/data/languages/ufo_stringpo_et_EE.po @@ -4448,7 +4448,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_fi.po b/data/languages/ufo_stringpo_fi.po index 54a0b942b..2c9513d6a 100644 --- a/data/languages/ufo_stringpo_fi.po +++ b/data/languages/ufo_stringpo_fi.po @@ -4450,7 +4450,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_fil_PH.po b/data/languages/ufo_stringpo_fil_PH.po index b1d6e2e08..a3a57b14d 100644 --- a/data/languages/ufo_stringpo_fil_PH.po +++ b/data/languages/ufo_stringpo_fil_PH.po @@ -4449,7 +4449,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_fr_FR.po b/data/languages/ufo_stringpo_fr_FR.po index 64c32fab1..8623da97e 100644 --- a/data/languages/ufo_stringpo_fr_FR.po +++ b/data/languages/ufo_stringpo_fr_FR.po @@ -4450,7 +4450,7 @@ msgstr "Capacité de munitions" msgid "Cargo" msgstr "Cargaison" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Aliens pris" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_hu_HU.po b/data/languages/ufo_stringpo_hu_HU.po index 23772a79f..d1998bfa2 100644 --- a/data/languages/ufo_stringpo_hu_HU.po +++ b/data/languages/ufo_stringpo_hu_HU.po @@ -4448,7 +4448,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_it.po b/data/languages/ufo_stringpo_it.po index f78dc92aa..8955cd340 100644 --- a/data/languages/ufo_stringpo_it.po +++ b/data/languages/ufo_stringpo_it.po @@ -4450,7 +4450,7 @@ msgstr "Munizioni" msgid "Cargo" msgstr "Cargo" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Alieni cont." msgid "Jamming" diff --git a/data/languages/ufo_stringpo_ja.po b/data/languages/ufo_stringpo_ja.po index 7980a6f1a..e3de7c65b 100644 --- a/data/languages/ufo_stringpo_ja.po +++ b/data/languages/ufo_stringpo_ja.po @@ -4448,7 +4448,7 @@ msgstr "装弾数" msgid "Cargo" msgstr "貨物" -msgid "Aliens Held" +msgid "Max Samples" msgstr "捕獲中のエイリアン" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_ja_JP.po b/data/languages/ufo_stringpo_ja_JP.po index cc4d7af60..803897b8d 100644 --- a/data/languages/ufo_stringpo_ja_JP.po +++ b/data/languages/ufo_stringpo_ja_JP.po @@ -4449,7 +4449,7 @@ msgstr "装弾数" msgid "Cargo" msgstr "貨物" -msgid "Aliens Held" +msgid "Max Samples" msgstr "捕獲中のエイリアン" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_lt.po b/data/languages/ufo_stringpo_lt.po index 960f1beee..29ad5bfe3 100644 --- a/data/languages/ufo_stringpo_lt.po +++ b/data/languages/ufo_stringpo_lt.po @@ -4449,7 +4449,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_nb_NO.po b/data/languages/ufo_stringpo_nb_NO.po index 5f8ad78ae..3cb845123 100644 --- a/data/languages/ufo_stringpo_nb_NO.po +++ b/data/languages/ufo_stringpo_nb_NO.po @@ -4449,7 +4449,7 @@ msgstr "Ammunisjonskapasitet" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_pl.po b/data/languages/ufo_stringpo_pl.po index c9f273162..3e19d9ce5 100644 --- a/data/languages/ufo_stringpo_pl.po +++ b/data/languages/ufo_stringpo_pl.po @@ -4454,7 +4454,7 @@ msgstr "Pojemność amunicji" msgid "Cargo" msgstr "Ładunek" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Pod kontrolą obcych" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_pt_BR.po b/data/languages/ufo_stringpo_pt_BR.po index 84da87de0..33d759328 100644 --- a/data/languages/ufo_stringpo_pt_BR.po +++ b/data/languages/ufo_stringpo_pt_BR.po @@ -4450,7 +4450,7 @@ msgstr "Capacidade p/ munição" msgid "Cargo" msgstr "Carga" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Alienígenas Aprisionados" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_pt_PT.po b/data/languages/ufo_stringpo_pt_PT.po index 845f0bcf1..aab4c6b42 100644 --- a/data/languages/ufo_stringpo_pt_PT.po +++ b/data/languages/ufo_stringpo_pt_PT.po @@ -4448,7 +4448,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_ro_RO.po b/data/languages/ufo_stringpo_ro_RO.po index 6ad5ab3e2..7275a2d26 100644 --- a/data/languages/ufo_stringpo_ro_RO.po +++ b/data/languages/ufo_stringpo_ro_RO.po @@ -4449,7 +4449,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_ru_RU.po b/data/languages/ufo_stringpo_ru_RU.po index 8efd52727..9d4b639a1 100644 --- a/data/languages/ufo_stringpo_ru_RU.po +++ b/data/languages/ufo_stringpo_ru_RU.po @@ -4453,7 +4453,7 @@ msgstr "Боезапас" msgid "Cargo" msgstr "Груз" -msgid "Aliens Held" +msgid "Max Samples" msgstr "Пришельцев удерживается" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_sk.po b/data/languages/ufo_stringpo_sk.po index 10ed82394..426016804 100644 --- a/data/languages/ufo_stringpo_sk.po +++ b/data/languages/ufo_stringpo_sk.po @@ -4448,7 +4448,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_sl_SI.po b/data/languages/ufo_stringpo_sl_SI.po index 6c07733fd..455504de5 100644 --- a/data/languages/ufo_stringpo_sl_SI.po +++ b/data/languages/ufo_stringpo_sl_SI.po @@ -4450,7 +4450,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_tr_TR.po b/data/languages/ufo_stringpo_tr_TR.po index d83887fc8..fc515af56 100644 --- a/data/languages/ufo_stringpo_tr_TR.po +++ b/data/languages/ufo_stringpo_tr_TR.po @@ -4448,7 +4448,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_uk.po b/data/languages/ufo_stringpo_uk.po index e95edba5c..3b6cfa59f 100644 --- a/data/languages/ufo_stringpo_uk.po +++ b/data/languages/ufo_stringpo_uk.po @@ -4448,7 +4448,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/data/languages/ufo_stringpo_zh_TW.po b/data/languages/ufo_stringpo_zh_TW.po index 2cb6e5825..b45b09069 100644 --- a/data/languages/ufo_stringpo_zh_TW.po +++ b/data/languages/ufo_stringpo_zh_TW.po @@ -4448,7 +4448,7 @@ msgstr "" msgid "Cargo" msgstr "" -msgid "Aliens Held" +msgid "Max Samples" msgstr "" msgid "Jamming" diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 80643ec20..b680c8016 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -1,9 +1,6 @@ # project name, and type PROJECT(OpenApoc_Dependencies C CXX) -# check cmake version -CMAKE_MINIMUM_REQUIRED(VERSION 3.9) - # hide dependency warnings add_compile_options("-w") diff --git a/dependencies/fmt b/dependencies/fmt index f19b1a521..7bdf0628b 160000 --- a/dependencies/fmt +++ b/dependencies/fmt @@ -1 +1 @@ -Subproject commit f19b1a521ee8b606dedcadfda69fd10ddf882753 +Subproject commit 7bdf0628b1276379886c7f6dda2cef2b3b374f0b diff --git a/dependencies/magic_enum b/dependencies/magic_enum new file mode 160000 index 000000000..adc7d2ba5 --- /dev/null +++ b/dependencies/magic_enum @@ -0,0 +1 @@ +Subproject commit adc7d2ba57e142b6ad018e01057233478a74c1e8 diff --git a/dependencies/physfs b/dependencies/physfs index 4b5c26a72..552e4f0ca 160000 --- a/dependencies/physfs +++ b/dependencies/physfs @@ -1 +1 @@ -Subproject commit 4b5c26a72a106b5f78b268674cf487054cccaacc +Subproject commit 552e4f0ca47c9c304ad23f5210ced3405a16306e diff --git a/forms/CMakeLists.txt b/forms/CMakeLists.txt index dcf9492fe..c79c14da9 100644 --- a/forms/CMakeLists.txt +++ b/forms/CMakeLists.txt @@ -4,9 +4,6 @@ PROJECT(OpenApoc_Forms CXX C) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package (Threads REQUIRED) -# check cmake version -CMAKE_MINIMUM_REQUIRED(VERSION 3.9) - set (FORMS_SOURCE_FILES checkbox.cpp control.cpp @@ -56,3 +53,7 @@ target_link_libraries(OpenApoc_Forms PUBLIC OpenApoc_Framework OpenApoc_LibPugixml) target_include_directories(OpenApoc_Forms PUBLIC ${CMAKE_SOURCE_DIR}) + +if (USE_PCH) + target_precompile_headers(OpenApoc_Forms PUBLIC forms_pch.h) +endif() \ No newline at end of file diff --git a/forms/control.cpp b/forms/control.cpp index 07835eb1a..f2ba76080 100644 --- a/forms/control.cpp +++ b/forms/control.cpp @@ -10,7 +10,6 @@ #include "framework/image.h" #include "framework/options.h" #include "framework/renderer.h" -#include "framework/sound.h" #include "library/sp.h" #include @@ -23,8 +22,8 @@ Control::Control(bool takesFocus) Size(0, 0), SelectionSize(0, 0), BackgroundColour(0, 0, 0, 0), takesFocus(takesFocus), showBounds(false), Enabled(true), canCopy(true), // Tooltip defaults - ToolTipBackground{128, 128, 128}, ToolTipBorders{ - {1, {0, 0, 0}}, {1, {255, 255, 255}}, {1, {0, 0, 0, 0}}} + ToolTipBackground{128, 128, 128}, + ToolTipBorders{{1, {0, 0, 0}}, {1, {255, 255, 255}}, {1, {0, 0, 0, 0}}} { this->ToolTipFont = ui().getFont(Options::defaultTooltipFont.get()); } diff --git a/forms/forms_pch.h b/forms/forms_pch.h index aa9734f1c..a402e3b2f 100644 --- a/forms/forms_pch.h +++ b/forms/forms_pch.h @@ -2,25 +2,10 @@ #include "dependencies/pugixml/src/pugixml.hpp" #include "forms/control.h" -#include "framework/apocresources/apocfont.h" -#include "framework/configfile.h" +#include "forms/forms_enums.h" #include "framework/data.h" #include "framework/event.h" -#include "framework/font.h" #include "framework/framework.h" #include "framework/image.h" -#include "framework/keycodes.h" -#include "framework/logger.h" #include "framework/renderer.h" -#include "framework/sound.h" -#include "framework/trace.h" -#include "library/colour.h" -#include "library/sp.h" -#include "library/strings.h" -#include "library/strings_format.h" -#include "library/vec.h" -#include -#include -#include -#include -#include +#include "library/sp.h" \ No newline at end of file diff --git a/forms/graphic.cpp b/forms/graphic.cpp index 40cf60739..82b81903b 100644 --- a/forms/graphic.cpp +++ b/forms/graphic.cpp @@ -1,7 +1,6 @@ #include "forms/graphic.h" #include "dependencies/pugixml/src/pugixml.hpp" #include "framework/data.h" -#include "framework/event.h" #include "framework/framework.h" #include "framework/image.h" #include "framework/renderer.h" diff --git a/forms/label.cpp b/forms/label.cpp index d637e2e16..4bea263bb 100644 --- a/forms/label.cpp +++ b/forms/label.cpp @@ -15,7 +15,7 @@ namespace OpenApoc Label::Label(const UString &Text, sp font) : Control(), text(Text), font(font), scrollOffset(0), TextHAlign(HorizontalAlignment::Left), - TextVAlign(VerticalAlignment::Top), WordWrap(true) + TextVAlign(VerticalAlignment::Top), WordWrap(false), wordWrapped(false) { if (font) { @@ -43,13 +43,14 @@ void Label::onRender() std::list lines = font->wordWrapText(text, Size.x); int ysize = font->getFontHeight(text, Size.x); + int ypos = !WordWrap ? align(TextVAlign, Size.y, ysize) : 0; + if (scroller) { scroller->setVisible(ysize > this->Size.y && lines.size() > 1); scroller->setMaximum(ysize - this->Size.y); } - int ypos = align(TextVAlign, Size.y, ysize); if (scroller && scroller->isVisible()) { ypos = -scrollOffset; @@ -85,11 +86,18 @@ void Label::setText(const UString &Text) { if (text == Text) return; + text = Text; + if (scroller) - { scroller->setValue(0); + + if (WordWrap) + { + auto lines = font->wordWrapText(text, Size.x); + wordWrapped = (lines.size() > 1); } + this->setDirty(); } diff --git a/forms/label.h b/forms/label.h index 50200d1ad..a691d2cea 100644 --- a/forms/label.h +++ b/forms/label.h @@ -28,6 +28,7 @@ class Label : public Control VerticalAlignment TextVAlign; bool WordWrap; Colour Tint{255, 255, 255, 255}; + bool wordWrapped; Label(const UString &Text = "", sp font = nullptr); ~Label() override; diff --git a/forms/textbutton.cpp b/forms/textbutton.cpp index 67ee0f0b8..a9335b69c 100644 --- a/forms/textbutton.cpp +++ b/forms/textbutton.cpp @@ -48,6 +48,17 @@ void TextButton::onRender() { Control::onRender(); + int shaderY1, shaderY2; +#ifdef __APPLE__ + // On apple, the shader line on the menu + // button is off by one pixel... + shaderY1 = 4; + shaderY2 = 3; +#else + shaderY1 = 5; + shaderY2 = 4; +#endif + if (label->getParent() == nullptr) { label->setParent(shared_from_this()); @@ -80,10 +91,12 @@ void TextButton::onRender() fw().renderer->drawFilledRect(Vec2{3, 3}, Size - 6, Colour{160, 160, 160}); fw().renderer->drawLine(Vec2{3, 3}, Vec2{Size.x - 3, 3}, Colour{220, 220, 220}); - fw().renderer->drawLine(Vec2{3, Size.y - 5}, - Vec2{Size.x - 3, Size.y - 5}, Colour{100, 100, 100}); - fw().renderer->drawLine(Vec2{3, Size.y - 4}, - Vec2{Size.x - 3, Size.y - 4}, Colour{64, 64, 64}); + fw().renderer->drawLine(Vec2{3, Size.y - shaderY1}, + Vec2{Size.x - 3, Size.y - shaderY1}, + Colour{100, 100, 100}); + fw().renderer->drawLine(Vec2{3, Size.y - shaderY2}, + Vec2{Size.x - 3, Size.y - shaderY2}, + Colour{64, 64, 64}); break; } } diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index f4a090ac8..8f95c298d 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -1,9 +1,6 @@ # project name, and type PROJECT(OpenApoc_Framework CXX C) -# check cmake version -CMAKE_MINIMUM_REQUIRED(VERSION 3.9) - option(DIALOG_ON_ERROR "Pop up a dialog box showing errors" ON) @@ -55,20 +52,13 @@ set (FRAMEWORK_HEADER_FILES renderer_interface.h sampleloader_interface.h serialization/serialize.h - serialization/providers/filedataprovider.h - serialization/providers/providerwithchecksum.h - serialization/providers/zipdataprovider.h - serialization/providers/serializationdataprovider.h sound.h sound_interface.h stage.h stagestack.h - ThreadPool/ThreadPool.h video.h - logger_sdldialog.h - logger_file.h options.h - modinfo.h translation.h) + modinfo.h) source_group(framework\\headers FILES ${FRAMEWORK_HEADER_FILES}) list(APPEND ALL_HEADER_FILES ${FRAMEWORK_HEADER_FILES}) @@ -216,7 +206,7 @@ endif() # We use boost::locale for utf conversions and boost::filesystem for # serialization -set(BOOST_PACKAGES locale system program_options) +set(BOOST_PACKAGES locale program_options) # Arbitrary version that I remember testing previously set(BOOST_VERSION 1.50) @@ -275,6 +265,7 @@ if (NOT OPENGL_FOUND) message(WARNING "OpenGL not found for GL_2_0 renderer") else() target_link_libraries(OpenApoc_Framework PUBLIC ${OPENGL_gl_LIBRARY}) + target_link_libraries(OpenApoc_Framework PUBLIC ${OPENGL_glx_LIBRARY}) target_include_directories(OpenApoc_Framework PUBLIC ${OPENGL_INCLUDE_DIR}) endif() target_link_libraries(OpenApoc_Framework PUBLIC OpenApoc_Library) @@ -293,3 +284,7 @@ endif() target_include_directories(OpenApoc_Framework PRIVATE ${CMAKE_SOURCE_DIR}/dependencies/physfs/src) target_include_directories(OpenApoc_Framework PUBLIC ${CMAKE_SOURCE_DIR}) + +if (USE_PCH) + target_precompile_headers(OpenApoc_Framework PUBLIC framework_pch.h) +endif() \ No newline at end of file diff --git a/framework/configfile.cpp b/framework/configfile.cpp index ebfba7eb7..e77f09ec4 100644 --- a/framework/configfile.cpp +++ b/framework/configfile.cpp @@ -5,7 +5,6 @@ #include "framework/configfile.h" #include "framework/filesystem.h" #include "framework/logger.h" -#include "framework/options.h" #include #include #include @@ -20,6 +19,11 @@ namespace po = boost::program_options; namespace OpenApoc { +// validate overload required by boost::program_options for UString +// boost should find this through ADL. +// this is required for string values with spaces +void validate(boost::any &v, const std::vector &values, UString *, int); + static ConfigFile *configInstance = nullptr; ConfigFile &ConfigFile::getInstance() diff --git a/framework/configfile.h b/framework/configfile.h index 6a7b66ab3..5e07a7484 100644 --- a/framework/configfile.h +++ b/framework/configfile.h @@ -2,7 +2,6 @@ #include "library/sp.h" #include "library/strings.h" -#include #include #include @@ -112,9 +111,4 @@ class ConfigOptionFloat : public ConfigOption }; static inline ConfigFile &config() { return ConfigFile::getInstance(); } -// validate overload required by boost::program_options for UString -// boost should find this through ADL. -// this is required for string values with spaces -void validate(boost::any &v, const std::vector &values, UString *, int); - }; // namespace OpenApoc diff --git a/framework/font.h b/framework/font.h index b669600d1..784bb7f4f 100644 --- a/framework/font.h +++ b/framework/font.h @@ -2,6 +2,8 @@ #include "library/sp.h" #include "library/strings.h" + +#include #include namespace OpenApoc diff --git a/framework/framework.cpp b/framework/framework.cpp index 4a26b653e..795b03975 100644 --- a/framework/framework.cpp +++ b/framework/framework.cpp @@ -5,7 +5,6 @@ #include "framework/data.h" #include "framework/event.h" #include "framework/filesystem.h" -#include "framework/font.h" #include "framework/image.h" #include "framework/jukebox.h" #include "framework/logger_file.h" @@ -891,6 +890,8 @@ void Framework::displayInitialise() SDL_GetWindowSize(p->window, &width, &height); p->windowSize = {width, height}; + setMouseGrab(); + // FIXME: Scale is currently stored as an integer in 1/100 units (ie 100 is 1.0 == same // size) int scaleX = Options::screenScaleXOption.get(); @@ -1114,6 +1115,13 @@ void Framework::showToolTip(sp image, const Vec2 &position) p->toolTipPosition = position; } +void Framework::setMouseGrab() +{ + auto mouseCapture = Options::mouseCaptureOption.get(); + SDL_SetWindowMouseGrab(p->window, mouseCapture ? SDL_TRUE : SDL_FALSE); + SDL_SetRelativeMouseMode(mouseCapture ? SDL_TRUE : SDL_FALSE); +} + UString Framework::textGetClipboard() { UString str; diff --git a/framework/framework.h b/framework/framework.h index 7bef44044..a90ad6f38 100644 --- a/framework/framework.h +++ b/framework/framework.h @@ -97,6 +97,8 @@ class Framework void toolTipTimerCallback(unsigned int interval, void *data); void showToolTip(sp image, const Vec2 &position); + void setMouseGrab(); + UString textGetClipboard(); void threadPoolTaskEnqueue(std::function task); diff --git a/framework/framework_pch.h b/framework/framework_pch.h index 1f767229e..a7e91bf2c 100644 --- a/framework/framework_pch.h +++ b/framework/framework_pch.h @@ -1,56 +1,12 @@ #pragma once -#define WIN32_MEAN_AND_LEAN -#include "framework/filesystem.h" +#include "framework/data.h" #include "framework/framework.h" -#include "library/colour.h" -#include "library/line.h" -#include "library/rect.h" -#include "library/resource.h" +#include "framework/image.h" +#include "framework/logger.h" +#include "library/sp.h" #include "library/strings.h" -#include "library/strings_format.h" #include "library/vec.h" -#include "library/voxel.h" -#include "library/xorshift.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include - -#undef max -#undef min diff --git a/framework/fs.h b/framework/fs.h index 7060e44b2..682ae1f2e 100644 --- a/framework/fs.h +++ b/framework/fs.h @@ -4,6 +4,7 @@ #include "library/strings.h" #include #include +#include #define PROGRAM_NAME "OpenApoc" #define PROGRAM_ORGANISATION "OpenApoc" diff --git a/framework/image.cpp b/framework/image.cpp index 10939fed1..68983a208 100644 --- a/framework/image.cpp +++ b/framework/image.cpp @@ -68,7 +68,7 @@ void PaletteImage::blit(sp src, sp dst, Vec2 size, Colour initialColour) : Image(size), - pixels(reinterpret_cast(operator new[](size.x *size.y * sizeof(Colour)))) + pixels(reinterpret_cast(operator new[](size.x * size.y * sizeof(Colour)))) { if (initialColour.r == initialColour.g && initialColour.r == initialColour.b && initialColour.r == initialColour.a) diff --git a/framework/jukebox.cpp b/framework/jukebox.cpp index 46e6163fc..08c53a61a 100644 --- a/framework/jukebox.cpp +++ b/framework/jukebox.cpp @@ -6,6 +6,7 @@ #include "framework/sound.h" #include "library/xorshift.h" #include +#include namespace OpenApoc { diff --git a/framework/logger.cpp b/framework/logger.cpp index a590919aa..92fb15b47 100644 --- a/framework/logger.cpp +++ b/framework/logger.cpp @@ -1,8 +1,6 @@ #include "framework/logger.h" #include "framework/configfile.h" -#include "framework/framework.h" #include "library/backtrace.h" -#include "library/sp.h" #include #include diff --git a/framework/logger.h b/framework/logger.h index 809eaf419..c889996e0 100644 --- a/framework/logger.h +++ b/framework/logger.h @@ -4,7 +4,6 @@ #include "library/strings_format.h" #include -#include #if defined(_MSC_VER) && _MSC_VER > 1400 #include diff --git a/framework/modinfo.h b/framework/modinfo.h index d5dcc5a3b..ab578934d 100644 --- a/framework/modinfo.h +++ b/framework/modinfo.h @@ -1,6 +1,8 @@ #pragma once #include "library/strings.h" + +#include #include namespace OpenApoc diff --git a/framework/options.cpp b/framework/options.cpp index 1be7cb332..b0033810f 100644 --- a/framework/options.cpp +++ b/framework/options.cpp @@ -45,6 +45,7 @@ void dumpOptionsToLog() dumpOption(screenScaleYOption); dumpOption(screenAutoScale); dumpOption(languageOption); + dumpOption(mouseCaptureOption); dumpOption(targetFPS); dumpOption(frameLimit); @@ -141,6 +142,8 @@ void dumpOptionsToLog() dumpOption(optionLoadSameAmmo); dumpOption(optionShowCurrentDimensionVehicles); dumpOption(optionShowNonXCOMVehiclesPrefix); + dumpOption(isoOnlyFollow); + dumpOption(formatAsCurrency); dumpOption(optionStunHostileAction); dumpOption(optionRaidHostileAction); @@ -247,6 +250,9 @@ ConfigOptionBool screenAutoScale( ConfigOptionString languageOption("Framework", "Language", "The language used ingame (empty for system default)", ""); +ConfigOptionBool mouseCaptureOption("Framework", "MouseCapture", + "Enable mouse capture for the window", false); + ConfigOptionInt targetFPS("Framework", "TargetFPS", "The target FPS count - affects game speed!", 60); ConfigOptionInt frameLimit("Framework", "FrameLimit", "Quit after this many frames - 0 = unlimited", @@ -347,7 +353,7 @@ ConfigOptionBool optionDebugCommandsVisible("OpenApoc.NewFeature", "DebugCommand ConfigOptionBool optionUFODamageModel("OpenApoc.NewFeature", "UFODamageModel", "X-Com 1 Damage model (0-200%)", false); ConfigOptionBool optionInstantExplosionDamage("OpenApoc.NewFeature", "InstantExplosionDamage", - "Explosions damage instantly", false); + "Explosions damage instantly", true); ConfigOptionBool optionGravliftSounds("OpenApoc.NewFeature", "GravliftSounds", "Gravlift sounds", true); ConfigOptionBool optionNoScrollSounds("OpenApoc.NewFeature", "NoScrollSounds", @@ -376,7 +382,7 @@ ConfigOptionBool optionAdditionalUnitIcons("OpenApoc.NewFeature", "AdditionalUni ConfigOptionBool optionAllowForceFiringParallel("OpenApoc.NewFeature", "AllowForceFiringParallel", "Allow force-firing parallel to the ground", true); ConfigOptionBool optionRequireLOSToMaintainPsi("OpenApoc.NewFeature", "RequireLOSToMaintainPsi", - "Require LOS to maintain psi attack", true); + "Require LOS to maintain psi attack", false); ConfigOptionBool optionAllowAttackingOwnedVehicles("OpenApoc.NewFeature", "AllowAttackingOwnedVehicles", "Allow attacking owned vehicles", true); @@ -405,7 +411,7 @@ ConfigOptionBool optionArmoredRoads("OpenApoc.NewFeature", "ArmoredRoads", "Armo ConfigOptionBool optionVanillaCityControls("OpenApoc.NewFeature", "OpenApocCityControls", "Improved city control scheme", true); ConfigOptionBool optionCollapseRaidedBuilding("OpenApoc.NewFeature", "CollapseRaidedBuilding", - "Successful raid collapses building", true); + "Successful raid collapses building", false); ConfigOptionBool optionScrambleOnUnintentionalHit("OpenApoc.NewFeature", "ScrambleOnUnintentionalHit", "Any hit on hostile building provokes retaliation", false); @@ -421,7 +427,7 @@ ConfigOptionBool optionFuelCrashingVehicles( ConfigOptionBool optionSkipTurbo("OpenApoc.NewFeature", "SkipTurboMovement", "Skip turbo movement calculations", false); ConfigOptionBool optionRunAndKneel("OpenApoc.NewFeature", "RunAndKneel", - "All units run and kneel by default", false); + "All units run and kneel by default", true); ConfigOptionBool optionSeedRng("OpenApoc.NewFeature", "SeedRng", "Seed RNG on game start", true); ConfigOptionBool optionAutoReload("OpenApoc.NewFeature", "AutoReload", "Automatically reload weapons when empty", true); @@ -435,7 +441,7 @@ ConfigOptionBool optionSingleSquadSelect("OpenApoc.NewFeature", "SingleSquadSele ConfigOptionBool optionATVUFOMission("OpenApoc.NewFeature", "ATVUFOMission", tr("Allow All Terrain Vehicles (ATV) to initiate UFO recovery missions"), - false); + true); ConfigOptionInt optionMaxTileRepair("OpenApoc.Mod", "MaxTileRepair", "Construction Vehicles will repair a maximum of X Tiles per night", 5); @@ -445,14 +451,17 @@ ConfigOptionFloat "pay for a Scenery Tile to be repaired", 10.0f); ConfigOptionBool optionLoadSameAmmo("OpenApoc.NewFeature", "LoadSameAmmo", - "Weapons autoreload only same ammo type", false); + "Weapons autoreload only same ammo type", true); ConfigOptionBool optionShowCurrentDimensionVehicles("OpenApoc.NewFeature", "ShowCurrentDimensionVehicles", "Show vehicles in current dimension (or entering / leaving)", true); ConfigOptionBool optionShowNonXCOMVehiclesPrefix("OpenApoc.NewFeature", "ShowNonXCOMVehiclesPrefix", tr("Add prefix to non-X-COM vehicles"), true); - +ConfigOptionBool isoOnlyFollow("OpenApoc.NewFeature", "IsoOnlyFollow", + tr("Don't follow vehicles in strategy view"), false); +ConfigOptionBool formatAsCurrency("OpenApoc.NewFeature", "formatAsCurrency", + "Use currency formatting", true); ConfigOptionBool optionStunHostileAction("OpenApoc.Mod", "StunHostileAction", "Stunning hurts relationships", false); ConfigOptionBool optionRaidHostileAction("OpenApoc.Mod", "RaidHostileAction", diff --git a/framework/options.h b/framework/options.h index c7b6afe0b..665fc862a 100644 --- a/framework/options.h +++ b/framework/options.h @@ -1,3 +1,5 @@ +#pragma once + #include "framework/configfile.h" namespace OpenApoc::Options @@ -23,6 +25,7 @@ extern ConfigOptionInt screenScaleXOption; extern ConfigOptionInt screenScaleYOption; extern ConfigOptionBool screenAutoScale; extern ConfigOptionString languageOption; +extern ConfigOptionBool mouseCaptureOption; extern ConfigOptionInt frameLimit; extern ConfigOptionInt targetFPS; @@ -119,6 +122,8 @@ extern ConfigOptionFloat optionSceneryRepairCostFactor; extern ConfigOptionBool optionLoadSameAmmo; extern ConfigOptionBool optionShowCurrentDimensionVehicles; extern ConfigOptionBool optionShowNonXCOMVehiclesPrefix; +extern ConfigOptionBool isoOnlyFollow; +extern ConfigOptionBool formatAsCurrency; extern ConfigOptionBool optionStunHostileAction; extern ConfigOptionBool optionRaidHostileAction; diff --git a/framework/renderer.h b/framework/renderer.h index 28e708fe8..a84ef0074 100644 --- a/framework/renderer.h +++ b/framework/renderer.h @@ -52,7 +52,7 @@ class Renderer virtual void flush() = 0; virtual UString getName() = 0; - virtual void newFrame(){}; + virtual void newFrame() {}; virtual sp getDefaultSurface() = 0; }; diff --git a/framework/serialization/providers/providerwithchecksum.cpp b/framework/serialization/providers/providerwithchecksum.cpp index 7e71f4f75..c850e7c59 100644 --- a/framework/serialization/providers/providerwithchecksum.cpp +++ b/framework/serialization/providers/providerwithchecksum.cpp @@ -27,11 +27,17 @@ static UString calculateSHA1Checksum(const std::string &str) boost::uuids::detail::sha1 sha; sha.process_bytes(str.c_str(), str.size()); +#if BOOST_VERSION >= 108600 + boost::uuids::detail::sha1::digest_type hash; +#else unsigned int hash[5]; +#endif sha.get_digest(hash); + std::array hashu32; + memcpy(hashu32.data(), hash, sizeof(hashu32)); for (int i = 0; i < 5; i++) { - unsigned int v = hash[i]; + unsigned int v = hashu32[i]; for (int j = 0; j < 4; j++) { // FIXME: Probably need to do the reverse for big endian? diff --git a/framework/sound.h b/framework/sound.h index 79b443dff..d07d70f7b 100644 --- a/framework/sound.h +++ b/framework/sound.h @@ -5,7 +5,6 @@ #include "library/strings.h" #include "library/vec.h" #include -#include namespace OpenApoc { diff --git a/framework/translation.h b/framework/translation.h deleted file mode 100644 index abca950e3..000000000 --- a/framework/translation.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "library/framework.h" -#include "library/strings.h" - -namespace OpenApoc -{ - -class LocalizedString -{ - public: - UStringView _id; - UStringView _pleural; - UStringView _context; - int _n; - - LocalizedString(UStringView id) : _id(id){}; - LocalizedString(UStringView context, UStringView id) : _id(id), _context(context){}; - LocalizedString(UStringView id, UStringView pleural, int n) - : _id(id), _pleural(pleural), _n(n){}; - LocalizedString(UStringView context, UStringView id, UStringView pleural, int n) - : _id(id), _pleural(pleural), _context(context), _n(n){}; -}; - -} // namespace OpenApoc \ No newline at end of file diff --git a/game/state/CMakeLists.txt b/game/state/CMakeLists.txt index b8f343a25..ea11b26a9 100644 --- a/game/state/CMakeLists.txt +++ b/game/state/CMakeLists.txt @@ -1,9 +1,6 @@ # project name, and type PROJECT(OpenApoc_GameState CXX C) -# check cmake version -CMAKE_MINIMUM_REQUIRED(VERSION 3.9) - set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) @@ -257,3 +254,7 @@ add_custom_target(generated-source DEPENDS gamestate_serialize_generated.h gamestate_serialize_generated.cpp luagamestate_support_generated.h luagamestate_support_generated.cpp) + +if (USE_PCH) + target_precompile_headers(OpenApoc_GameState PUBLIC gamestate_pch.h) +endif() \ No newline at end of file diff --git a/game/state/battle/ai/tacticalai.h b/game/state/battle/ai/tacticalai.h index e22bdbcd9..b29f203d0 100644 --- a/game/state/battle/ai/tacticalai.h +++ b/game/state/battle/ai/tacticalai.h @@ -1,12 +1,10 @@ #pragma once -#include "float.h" #include "game/state/battle/ai/aidecision.h" #include "game/state/gametime.h" #include "game/state/stateobject.h" #include "library/sp.h" #include "library/strings.h" -#include "library/vec.h" #include namespace OpenApoc @@ -27,8 +25,8 @@ class TacticalAI virtual ~TacticalAI() = default; const UString getName(); - virtual void reset(GameState &, StateRef){}; - virtual void beginTurnRoutine(GameState &, StateRef){}; + virtual void reset(GameState &, StateRef) {}; + virtual void beginTurnRoutine(GameState &, StateRef) {}; virtual std::list>, AIDecision>> think(GameState &, StateRef) { diff --git a/game/state/battle/ai/tacticalaivanilla.cpp b/game/state/battle/ai/tacticalaivanilla.cpp index c2097992e..558672c64 100644 --- a/game/state/battle/ai/tacticalaivanilla.cpp +++ b/game/state/battle/ai/tacticalaivanilla.cpp @@ -1,4 +1,6 @@ #include "game/state/battle/ai/tacticalaivanilla.h" + +#include "game/state/battle/ai/aitype.h" #include "game/state/battle/ai/unitaihelper.h" #include "game/state/battle/battle.h" #include "game/state/battle/battleunit.h" diff --git a/game/state/battle/ai/tacticalaivanilla.h b/game/state/battle/ai/tacticalaivanilla.h index 8cf35fceb..377bdb470 100644 --- a/game/state/battle/ai/tacticalaivanilla.h +++ b/game/state/battle/ai/tacticalaivanilla.h @@ -1,4 +1,5 @@ #pragma once + #include "game/state/battle/ai/tacticalai.h" namespace OpenApoc diff --git a/game/state/battle/ai/unitai.h b/game/state/battle/ai/unitai.h index 7b01c5af4..72774d7e2 100644 --- a/game/state/battle/ai/unitai.h +++ b/game/state/battle/ai/unitai.h @@ -29,13 +29,13 @@ class UnitAI // Whether AI is currently active bool active = false; - virtual void reset(GameState &, BattleUnit &){}; + virtual void reset(GameState &, BattleUnit &) {}; // Returns decision that was made, and whether we should stop going forward on the AI chain virtual std::tuple think(GameState &, BattleUnit &, bool) { return {}; }; - virtual void routine(GameState &, BattleUnit &){}; + virtual void routine(GameState &, BattleUnit &) {}; // virtual void reportExecuted(AIAction &action) {}; - virtual void reportExecuted(AIMovement &){}; + virtual void reportExecuted(AIMovement &) {}; virtual void notifyUnderFire(Vec3){}; virtual void notifyHit(Vec3){}; diff --git a/game/state/battle/ai/unitaihelper.cpp b/game/state/battle/ai/unitaihelper.cpp index 39eded034..737fd5b16 100644 --- a/game/state/battle/ai/unitaihelper.cpp +++ b/game/state/battle/ai/unitaihelper.cpp @@ -3,7 +3,7 @@ #include "game/state/battle/battleunit.h" #include "game/state/gamestate.h" #include "game/state/shared/aequipment.h" -#include +#include #include namespace OpenApoc diff --git a/game/state/battle/ai/unitaivanilla.cpp b/game/state/battle/ai/unitaivanilla.cpp index 1ab240868..2746a09a4 100644 --- a/game/state/battle/ai/unitaivanilla.cpp +++ b/game/state/battle/ai/unitaivanilla.cpp @@ -1,5 +1,6 @@ #include "game/state/battle/ai/unitaivanilla.h" #include "game/state/battle/ai/aidecision.h" +#include "game/state/battle/ai/aitype.h" #include "game/state/battle/ai/unitaihelper.h" #include "game/state/battle/battleunit.h" #include "game/state/gamestate.h" @@ -8,6 +9,7 @@ #include "game/state/rules/battle/damage.h" #include "game/state/shared/aequipment.h" #include "game/state/tilemap/tileobject_battleunit.h" +#include namespace OpenApoc { diff --git a/game/state/battle/battle.cpp b/game/state/battle/battle.cpp index 08ac2d620..c78491b29 100644 --- a/game/state/battle/battle.cpp +++ b/game/state/battle/battle.cpp @@ -37,7 +37,6 @@ #include "game/state/tilemap/tileobject_battleitem.h" #include "game/state/tilemap/tileobject_battlemappart.h" #include "game/state/tilemap/tileobject_battleunit.h" -#include "game/state/tilemap/tileobject_doodad.h" #include "game/state/tilemap/tileobject_projectile.h" #include "game/state/tilemap/tileobject_shadow.h" #include "library/strings_format.h" @@ -1023,7 +1022,7 @@ void Battle::initialUnitSpawn(GameState &state) break; offset++; } // end of spawning within a block cycle - } // end of if we have a position in a set + } // end of if we have a position in a set // If failed to spawn anything, then this block is no longer appropriate if (numSpawned == 0) @@ -2567,15 +2566,9 @@ void Battle::finishBattle(GameState &state) // Recharge all equipment auto payload = e->getPayloadType(); - if (payload) + if (payload && payload->recharge && e->ammo < payload->max_ammo) { - if (payload->recharge) - { - if (e->ammo < payload->max_ammo) - { - e->ammo = payload->max_ammo; - } - } + e->ammo = payload->max_ammo; } } } @@ -2680,7 +2673,7 @@ void Battle::finishBattle(GameState &state) // If mission == Alien extermination, remove the red alien spotted circle if (state.current_battle->mission_type == Battle::MissionType::AlienExtermination) { - StateRef location = {&state, state.current_battle->mission_location_id}; + StateRef location = state.current_battle->mission_location_building; location->detected = false; } @@ -2689,27 +2682,32 @@ void Battle::finishBattle(GameState &state) // - give him alien remains if (state.current_battle->playerWon && !state.current_battle->winnerHasRetreated) { - bool playerHasBioStorage = state.current_battle->player_craft && - state.current_battle->player_craft->getMaxBio() > 0; + const auto baseDefenseWithAlienStorage = + isBaseDefenseWithStorage(state, FacilityType::Capacity::Aliens); + + const auto playerVehicles = Battle::getPlayerVehicles(state); + const auto playerHasCraftBioStorage = Battle::isBioCarrierPresent(playerVehicles); + + const auto playerHasAlienStorage = playerHasCraftBioStorage || baseDefenseWithAlienStorage; + // Live alien loot for (auto &u : liveAliens) { if (u->agent->type->liveSpeciesItem) { - if (playerHasBioStorage) + if (playerHasAlienStorage) { state.current_battle->score.liveAlienCaptured += u->agent->type->liveSpeciesItem->score; } + if (u->agent->type->liveSpeciesItem->bioStorage) { - state.current_battle->bioLoot[u->agent->type->liveSpeciesItem] = - state.current_battle->bioLoot[u->agent->type->liveSpeciesItem] + 1; + state.current_battle->bioLoot[u->agent->type->liveSpeciesItem] += 1; } else { - state.current_battle->cargoLoot[u->agent->type->liveSpeciesItem] = - state.current_battle->cargoLoot[u->agent->type->liveSpeciesItem] + 1; + state.current_battle->cargoLoot[u->agent->type->liveSpeciesItem] += 1; } } else @@ -2725,13 +2723,11 @@ void Battle::finishBattle(GameState &state) { if (u->agent->type->deadSpeciesItem->bioStorage) { - state.current_battle->bioLoot[u->agent->type->deadSpeciesItem] = - state.current_battle->bioLoot[u->agent->type->deadSpeciesItem] + 1; + state.current_battle->bioLoot[u->agent->type->deadSpeciesItem] += 1; } else { - state.current_battle->cargoLoot[u->agent->type->deadSpeciesItem] = - state.current_battle->cargoLoot[u->agent->type->deadSpeciesItem] + 1; + state.current_battle->cargoLoot[u->agent->type->deadSpeciesItem] += 1; } } } @@ -2769,13 +2765,12 @@ void Battle::finishBattle(GameState &state) // If alien building - all aliens vanish else { - StateRef location = {&state, state.current_battle->mission_location_id}; + StateRef location = state.current_battle->mission_location_building; if (location->owner != aliens) { for (auto &a : liveAliens) { - location->current_crew[a->agent->type] = - location->current_crew[a->agent->type] + 1; + location->current_crew[a->agent->type] += 1; } } else @@ -2793,15 +2788,15 @@ void Battle::finishBattle(GameState &state) { state.current_battle->score.equipmentCaptured += e->type->score; } + int mult = e->type->type == AEquipmentType::Type::Ammo ? e->ammo : 1; if (e->type->bioStorage) { - state.current_battle->bioLoot[e->type] = state.current_battle->bioLoot[e->type] + mult; + state.current_battle->bioLoot[e->type] += mult; } else { - state.current_battle->cargoLoot[e->type] = - state.current_battle->cargoLoot[e->type] + mult; + state.current_battle->cargoLoot[e->type] += mult; } } // Regardless of what happened, retreated aliens go to a nearby building @@ -2814,13 +2809,13 @@ void Battle::finishBattle(GameState &state) StateRef city; if (state.current_battle->mission_type == Battle::MissionType::UfoRecovery) { - StateRef location = {&state, state.current_battle->mission_location_id}; + StateRef location = state.current_battle->mission_location_vehicle; city = location->city; battleLocation = {location->position.x, location->position.y}; } else { - StateRef location = {&state, state.current_battle->mission_location_id}; + StateRef location = state.current_battle->mission_location_building; city = location->city; battleLocation = location->bounds.p0; } @@ -2843,8 +2838,7 @@ void Battle::finishBattle(GameState &state) } for (auto &a : retreatedAliens) { - closestBuilding->current_crew[a->agent->type] = - closestBuilding->current_crew[a->agent->type] + 1; + closestBuilding->current_crew[a->agent->type] += 1; } } // Remove dead player agents and all enemy agents from the game and from vehicles @@ -3031,57 +3025,20 @@ void Battle::exitBattle(GameState &state) // LOOT! // Compile list of player vehicles - std::list> playerVehicles; + auto playerVehicles = Battle::getPlayerVehicles(state); std::set> returningVehicles; + if (state.current_battle->player_craft) { - playerVehicles.push_back(state.current_battle->player_craft); returningVehicles.insert(state.current_battle->player_craft); } - if (config().getBool("OpenApoc.NewFeature.AllowNearbyVehicleLootPickup")) - { - if (state.current_battle->mission_type == Battle::MissionType::UfoRecovery) - { - StateRef city; - StateRef location = {&state, state.current_battle->mission_location_id}; - city = location->city; - - for (auto &v : state.vehicles) - { - // Check every player owned vehicle located in city - if (v.second->owner != player || v.second->city != city || - v.second->currentBuilding - // Player's vehicle was already added and has priority - || v.first == state.current_battle->player_craft.id) - { - continue; - } - if (glm::length(location->position - v.second->position) < VEHICLE_NEARBY_THRESHOLD) - { - playerVehicles.emplace_back(&state, v.first); - } - } - } - else - { - StateRef location = {&state, state.current_battle->mission_location_id}; - for (auto &v : location->currentVehicles) - { - // Player's vehicle was already added and has priority - if (v->owner == player && v != state.current_battle->player_craft) - { - playerVehicles.push_back(v); - } - } - } - } // List of vehicle loot std::map, int> vehicleLoot; if (state.current_battle->mission_type == MissionType::UfoRecovery) { - auto vehicle = StateRef(&state, state.current_battle->mission_location_id); + auto vehicle = state.current_battle->mission_location_vehicle; for (auto &e : vehicle->loot) { vehicleLoot[e]++; @@ -3110,20 +3067,14 @@ void Battle::exitBattle(GameState &state) // If player has vehicle with bio capacity then all bio loot goes to leftover loot // This is regardless of "enforce limits" which only makes us enforce it // on vehicles that have capacity in the first place - bool bioCarrierPresent = false; - bool cargoCarrierPresent = false; - for (auto &v : playerVehicles) - { - if (v->getMaxCargo() > 0) - { - cargoCarrierPresent = true; - } - if (v->getMaxBio() > 0) - { - bioCarrierPresent = true; - } - } - if (!cargoCarrierPresent) + const auto cargoCarrierPresent = Battle::isCargoCarrierPresent(playerVehicles); + const auto bioCarrierPresent = Battle::isBioCarrierPresent(playerVehicles); + const auto baseDefenseWithItemStorage = + isBaseDefenseWithStorage(state, FacilityType::Capacity::Stores); + const auto baseDefenseWithAlienStorage = + isBaseDefenseWithStorage(state, FacilityType::Capacity::Aliens); + + if (!cargoCarrierPresent && !baseDefenseWithItemStorage) { for (auto &e : state.current_battle->cargoLoot) { @@ -3135,7 +3086,7 @@ void Battle::exitBattle(GameState &state) } state.current_battle->cargoLoot.clear(); } - if (!bioCarrierPresent) + if (!bioCarrierPresent && !baseDefenseWithAlienStorage) { for (auto &e : state.current_battle->bioLoot) { @@ -3148,39 +3099,81 @@ void Battle::exitBattle(GameState &state) if (!leftoverBioLoot.empty()) { // Bio loot is wasted if can't be loaded on player craft + LogWarning("Bio loot remaining"); } // Cargo loot remaining? - if (leftoverCargoLoot.empty()) + if (leftoverCargoLoot.empty() && + config().getBool("OpenApoc.NewFeature.AllowBuildingLootDeposit")) { - if (config().getBool("OpenApoc.NewFeature.AllowBuildingLootDeposit")) + if (state.current_battle->mission_type == Battle::MissionType::UfoRecovery) { - if (state.current_battle->mission_type == Battle::MissionType::UfoRecovery) + // Still can't do anything if we're recovering UFO + LogWarning("AllowBuildingLootDeposit and UfoRecovery mission type"); + } + else + { + // Deposit loot into building, call for pickup + StateRef location = state.current_battle->mission_location_building; + auto homeBuilding = + playerVehicles.empty() ? nullptr : playerVehicles.front()->homeBuilding; + if (!homeBuilding) { - // Still can't do anything if we're recovering UFO + homeBuilding = state.player_bases.begin()->second->building; } - else + + // Main loop only starts with leftoverCargoLoot.empty() + // This means that the following inner loop will NEVER be executed! + // TODO: check if this can be removed + for (auto &e : leftoverCargoLoot) { - // Deposit loot into building, call for pickup - StateRef location = {&state, state.current_battle->mission_location_id}; - auto homeBuilding = - playerVehicles.empty() ? nullptr : playerVehicles.front()->homeBuilding; - if (!homeBuilding) - { - homeBuilding = state.player_bases.begin()->second->building; - } - for (auto &e : leftoverCargoLoot) - { - int price = 0; - location->cargo.emplace_back(state, e.first, e.second, price, nullptr, - homeBuilding); - } - for (auto &e : leftoverVehicleLoot) - { - int price = 0; - location->cargo.emplace_back(state, e.first, e.second, price, nullptr, - homeBuilding); - } + int price = 0; + location->cargo.emplace_back(state, e.first, e.second, price, nullptr, + homeBuilding); + } + for (auto &e : leftoverVehicleLoot) + { + int price = 0; + location->cargo.emplace_back(state, e.first, e.second, price, nullptr, + homeBuilding); + } + } + } + + // Base defense missions only check for vehicles if no storage is available + // Items saved in this condition must NOT be saved again into vehicles! + if (state.current_battle->mission_type == Battle::MissionType::BaseDefense) + { + const auto defendedBase = getCurrentDefendedBase(state); + + const auto lootTypeList = { + std::tuple(FacilityType::Capacity::Stores, &state.current_battle->cargoLoot, + &defendedBase->inventoryAgentEquipment), + std::tuple(FacilityType::Capacity::Aliens, &state.current_battle->bioLoot, + &defendedBase->inventoryBioEquipment)}; + + for (const auto &lootType : lootTypeList) + { + const auto facilityTypeEnum = std::get<0>(lootType); + auto &lootList = *std::get<1>(lootType); + auto &inventoryEquipment = *std::get<2>(lootType); + + if (!isBaseDefenseWithStorage(state, facilityTypeEnum)) + continue; + + std::list> lootToRemove = {}; + + for (const auto &loot : lootList) + { + if (loot.second > 0) + inventoryEquipment[loot.first.id] += loot.second; + + lootToRemove.push_back(loot.first); + } + + for (const auto &loot : lootToRemove) + { + lootList.erase(loot); } } } @@ -3366,12 +3359,9 @@ void Battle::exitBattle(GameState &state) } } - // Give player vehicle a null cargo just so it comes back to base once - for (auto v : playerVehicles) + // Sending vehicles back to base + for (auto &v : playerVehicles) { - v->cargo.emplace_front( - state, StateRef(&state, state.agent_equipment.begin()->first), 0, 0, - nullptr, v->homeBuilding); if (v->city.id == "CITYMAP_HUMAN") { v->setMission(state, VehicleMission::gotoBuilding(state, *v)); @@ -3393,8 +3383,7 @@ void Battle::exitBattle(GameState &state) if (state.current_battle->playerWon) { state.eventFromBattle = GameEventType::MissionCompletedBuildingAlien; - auto building = - StateRef(&state, state.current_battle->mission_location_id); + auto building = state.current_battle->mission_location_building; for (auto &u : building->researchUnlock) { u->forceComplete(); @@ -3411,7 +3400,7 @@ void Battle::exitBattle(GameState &state) case Battle::MissionType::AlienExtermination: { state.eventFromBattle = GameEventType::MissionCompletedBuildingNormal; - state.missionLocationBattle = state.current_battle->mission_location_id; + state.missionLocationBattleBuilding = state.current_battle->mission_location_building; break; } case Battle::MissionType::BaseDefense: @@ -3419,14 +3408,15 @@ void Battle::exitBattle(GameState &state) if (state.current_battle->playerWon) { state.eventFromBattle = GameEventType::MissionCompletedBase; - state.missionLocationBattle = state.current_battle->mission_location_id; + state.missionLocationBattleBuilding = + state.current_battle->mission_location_building; } else { - auto building = - StateRef{&state, state.current_battle->mission_location_id}; + auto building = state.current_battle->mission_location_building; state.eventFromBattle = GameEventType::BaseDestroyed; - state.missionLocationBattle = state.current_battle->mission_location_id; + state.missionLocationBattleBuilding = + state.current_battle->mission_location_building; state.eventFromBattleText = building->base->name; building->base->die(state, false); } @@ -3435,11 +3425,10 @@ void Battle::exitBattle(GameState &state) case Battle::MissionType::RaidHumans: { state.eventFromBattle = GameEventType::MissionCompletedBuildingRaid; - state.missionLocationBattle = state.current_battle->mission_location_id; + state.missionLocationBattleBuilding = state.current_battle->mission_location_building; if (state.current_battle->playerWon) { - auto building = - StateRef(&state, state.current_battle->mission_location_id); + auto building = state.current_battle->mission_location_building; for (auto &u : building->researchUnlock) { u->forceComplete(); @@ -3460,7 +3449,7 @@ void Battle::exitBattle(GameState &state) case Battle::MissionType::UfoRecovery: { state.eventFromBattle = GameEventType::MissionCompletedVehicle; - auto vehicle = StateRef(&state, state.current_battle->mission_location_id); + auto vehicle = state.current_battle->mission_location_vehicle; for (auto &u : vehicle->type->researchUnlock) { u->forceComplete(); @@ -3481,6 +3470,38 @@ void Battle::exitBattle(GameState &state) state.cleanUpDeathNote(); } +sp Battle::getCurrentDefendedBase(GameState &state) +{ + if (state.current_battle->mission_type != Battle::MissionType::BaseDefense) + return {}; + + for (const auto &base : state.player_bases) + { + if (base.first == state.current_base.id) + return base.second; + } + + return {}; +} + +bool Battle::isBaseDefenseWithStorage(GameState &state, const FacilityType::Capacity capacityType) +{ + // Check if mission is base defense, and defended base has alien containment facility to store + // live aliens from battle + if (state.current_battle->mission_type != Battle::MissionType::BaseDefense) + return false; + + const auto defendedBase = getCurrentDefendedBase(state); + + // If base not found + if (!defendedBase) + return false; + + const auto availableStorageAtBase = defendedBase->getCapacityTotal(capacityType) > 0; + + return availableStorageAtBase; +} + void Battle::loadResources(GameState &state) { battle_map->loadTilesets(state); @@ -3766,6 +3787,88 @@ void Battle::loadMessages(GameState &state) } } +const std::list> Battle::getPlayerVehicles(GameState &state) +{ + std::list> playerVehicles; + const auto playerCraft = state.current_battle->player_craft; + + if (playerCraft) + { + playerVehicles.push_back(playerCraft); + } + + if (config().getBool("OpenApoc.NewFeature.AllowNearbyVehicleLootPickup")) + { + if (state.current_battle->mission_type == Battle::MissionType::UfoRecovery) + { + StateRef city; + StateRef location = state.current_battle->mission_location_vehicle; + city = location->city; + + for (const auto &v : state.vehicles) + { + // Check every player owned vehicle located in city + const auto isVehiclePlayerOwned = v.second->owner == state.player; + const auto isVehicleInTheCity = + v.second->city == city && !v.second->currentBuilding; + + // Player's vehicle was already added and has priority + const auto isVehiclePlayerCraft = v.first == playerCraft.id; + + if (!isVehiclePlayerOwned || !isVehicleInTheCity || isVehiclePlayerCraft) + { + continue; + } + + if (glm::length(location->position - v.second->position) < VEHICLE_NEARBY_THRESHOLD) + { + playerVehicles.emplace_back(&state, v.first); + } + } + } + else + { + StateRef location = state.current_battle->mission_location_building; + for (const auto &v : location->currentVehicles) + { + // Player's vehicle was already added and has priority + if (v->owner == state.player && v != playerCraft) + { + playerVehicles.push_back(v); + } + } + } + } + + return playerVehicles; +} + +const bool Battle::isCargoCarrierPresent(const std::list> &playerVehicles) +{ + for (const auto &v : playerVehicles) + { + if (v->getMaxCargo() > 0) + { + return true; + } + } + + return false; +} + +const bool Battle::isBioCarrierPresent(const std::list> &playerVehicles) +{ + for (const auto &v : playerVehicles) + { + if (v->getMaxBio() > 0) + { + return true; + } + } + + return false; +} + int BattleScore::getLeadershipBonus() { return (100 + 3 * casualtyPenalty) * (combatRating + friendlyFire + liveAlienCaptured) / 100; diff --git a/game/state/battle/battle.h b/game/state/battle/battle.h index 447d49663..653fed368 100644 --- a/game/state/battle/battle.h +++ b/game/state/battle/battle.h @@ -1,8 +1,8 @@ #pragma once -#include "game/state/battle/ai/aitype.h" #include "game/state/battle/ai/tacticalai.h" #include "game/state/battle/battleforces.h" +#include "game/state/city/base.h" #include "game/state/gametime.h" #include "game/state/rules/agenttype.h" #include "game/state/rules/battle/battlemapsector.h" @@ -131,7 +131,8 @@ class Battle : public std::enable_shared_from_this // - Map part which is door opening/closing std::set> tilesChangedForVision; MissionType mission_type = MissionType::AlienExtermination; - UString mission_location_id; + StateRef mission_location_building; + StateRef mission_location_vehicle; Mode mode = Mode::RealTime; BattleScore score = {}; unsigned missionEndTimer = 0; @@ -328,6 +329,15 @@ class Battle : public std::enable_shared_from_this // To be called after battle was finished and before returning to cityscape static void exitBattle(GameState &state); + // Get list of player vehicles in battle + static const std::list> getPlayerVehicles(GameState &state); + + // Check if cargo carrier is present at player vehicles list + static const bool isCargoCarrierPresent(const std::list> &playerVehicles); + + // Check if bio carrier is present at player vehicles list + static const bool isBioCarrierPresent(const std::list> &playerVehicles); + // Pathfinding functions public: @@ -351,6 +361,13 @@ class Battle : public std::enable_shared_from_this bool approachOnly = false, bool ignoreStaticUnits = false, bool ignoreMovingUnits = true, bool ignoreAllUnits = false, float *cost = nullptr, float maxCost = 0.0f); + // Returns defended base if mission is base defense, returns null otherwise + static sp getCurrentDefendedBase(GameState &state); + + // Check if mission is base defense and has storage for specified capacity type + static bool isBaseDefenseWithStorage(GameState &state, + const FacilityType::Capacity capacityType); + private: void loadResources(GameState &state); void unloadResources(GameState &state); diff --git a/game/state/battle/battledoor.cpp b/game/state/battle/battledoor.cpp index c73bec795..39e89d17b 100644 --- a/game/state/battle/battledoor.cpp +++ b/game/state/battle/battledoor.cpp @@ -9,7 +9,6 @@ #include "game/state/rules/battle/battlemapparttype.h" #include "game/state/tilemap/tilemap.h" #include "game/state/tilemap/tileobject_battlemappart.h" -#include "game/state/tilemap/tileobject_battleunit.h" namespace OpenApoc { diff --git a/game/state/battle/battleexplosion.cpp b/game/state/battle/battleexplosion.cpp index 51de4c224..6ba5feb92 100644 --- a/game/state/battle/battleexplosion.cpp +++ b/game/state/battle/battleexplosion.cpp @@ -1,8 +1,6 @@ #include "game/state/battle/battleexplosion.h" #include "framework/configfile.h" #include "framework/framework.h" -#include "framework/logger.h" -#include "framework/sound.h" #include "game/state/battle/battle.h" #include "game/state/battle/battlehazard.h" #include "game/state/battle/battleitem.h" diff --git a/game/state/battle/battlehazard.cpp b/game/state/battle/battlehazard.cpp index 84f600043..af0d1a606 100644 --- a/game/state/battle/battlehazard.cpp +++ b/game/state/battle/battlehazard.cpp @@ -1,7 +1,6 @@ #include "game/state/battle/battlehazard.h" #include "framework/framework.h" #include "framework/logger.h" -#include "framework/sound.h" #include "game/state/battle/battle.h" #include "game/state/battle/battleitem.h" #include "game/state/battle/battlemappart.h" @@ -10,7 +9,6 @@ #include "game/state/rules/battle/battlemapparttype.h" #include "game/state/rules/battle/damage.h" #include "game/state/rules/doodadtype.h" -#include "game/state/shared/aequipment.h" #include "game/state/tilemap/tilemap.h" #include "game/state/tilemap/tileobject_battlehazard.h" #include "game/state/tilemap/tileobject_battleitem.h" diff --git a/game/state/battle/battleitem.cpp b/game/state/battle/battleitem.cpp index d688668d2..9c9c9ed8e 100644 --- a/game/state/battle/battleitem.cpp +++ b/game/state/battle/battleitem.cpp @@ -7,7 +7,6 @@ #include "game/state/battle/battleunit.h" #include "game/state/gamestate.h" #include "game/state/rules/aequipmenttype.h" -#include "game/state/rules/battle/battlecommonsamplelist.h" #include "game/state/rules/battle/damage.h" #include "game/state/shared/aequipment.h" #include "game/state/tilemap/collision.h" diff --git a/game/state/battle/battlescanner.h b/game/state/battle/battlescanner.h index cd3a0ebbf..245ec746c 100644 --- a/game/state/battle/battlescanner.h +++ b/game/state/battle/battlescanner.h @@ -3,7 +3,6 @@ #include "game/state/battle/battle.h" #include "game/state/gametime.h" #include "game/state/stateobject.h" -#include "library/sp.h" #include "library/vec.h" #include diff --git a/game/state/battle/battleunit.cpp b/game/state/battle/battleunit.cpp index d9dc5caf9..6f01f23a8 100644 --- a/game/state/battle/battleunit.cpp +++ b/game/state/battle/battleunit.cpp @@ -5,6 +5,7 @@ #include "framework/configfile.h" #include "framework/framework.h" #include "framework/sound.h" +#include "game/state/battle/ai/aitype.h" #include "game/state/battle/ai/unitaihelper.h" #include "game/state/battle/battle.h" #include "game/state/battle/battleitem.h" @@ -13,13 +14,11 @@ #include "game/state/rules/battle/battlecommonsamplelist.h" #include "game/state/rules/battle/battleunitanimationpack.h" #include "game/state/rules/battle/damage.h" -#include "game/state/rules/city/facilitytype.h" #include "game/state/shared/aequipment.h" #include "game/state/shared/projectile.h" #include "game/state/tilemap/collision.h" #include "game/state/tilemap/tileobject_battleunit.h" #include "game/state/tilemap/tileobject_shadow.h" -#include "library/line.h" #include "library/strings_format.h" #include #include @@ -3839,6 +3838,7 @@ void BattleUnit::triggerBrainsuckers(GameState &state) state.current_battle->spawnUnit(state, aliens, {&state, "AGENTTYPE_BRAINSUCKER"}, i->position, {0, 1}, BodyState::Throwing); i->die(state, false); + state.current_battle->checkMissionEnd(state, false, true); } } } diff --git a/game/state/battle/battleunitmission.cpp b/game/state/battle/battleunitmission.cpp index 49629d15a..02cd94487 100644 --- a/game/state/battle/battleunitmission.cpp +++ b/game/state/battle/battleunitmission.cpp @@ -3,7 +3,6 @@ #include "framework/sound.h" #include "game/state/battle/battleitem.h" #include "game/state/battle/battleunit.h" -#include "game/state/gameevent.h" #include "game/state/gamestate.h" #include "game/state/rules/aequipmenttype.h" #include "game/state/rules/battle/battlecommonsamplelist.h" @@ -2054,7 +2053,7 @@ void BattleUnitMission::setPathTo(GameState &state, BattleUnit &u, Vec3 tar auto path = state.current_battle->findShortestPath( u.goalPosition, target, BattleUnitTileHelper{map, u}, approachOnly, demandGiveWay, - !blockedByMovingUnit); + !blockedByMovingUnit, TileMap::MAX_ITERATION_LIMIT_DIRECT_FOR_BATTLE); // Cancel movement if the closest path ends at the current position if (path.size() == 1 && path.back() == Vec3{u.position}) diff --git a/game/state/city/agentmission.cpp b/game/state/city/agentmission.cpp index 4aa52a54d..b0986a9f0 100644 --- a/game/state/city/agentmission.cpp +++ b/game/state/city/agentmission.cpp @@ -10,12 +10,7 @@ #include "game/state/rules/battle/battlecommonsamplelist.h" #include "game/state/rules/city/scenerytiletype.h" #include "game/state/shared/agent.h" -#include "game/state/shared/doodad.h" -#include "game/state/shared/organisation.h" #include "game/state/tilemap/tilemap.h" -#include "game/state/tilemap/tileobject_doodad.h" -#include "game/state/tilemap/tileobject_scenery.h" -#include "game/state/tilemap/tileobject_shadow.h" #include "library/strings_format.h" #include diff --git a/game/state/city/agentmission.h b/game/state/city/agentmission.h index 705c4f8d2..93f987adf 100644 --- a/game/state/city/agentmission.h +++ b/game/state/city/agentmission.h @@ -5,7 +5,6 @@ #include "library/strings.h" #include "library/vec.h" #include -#include namespace OpenApoc { diff --git a/game/state/city/base.cpp b/game/state/city/base.cpp index dbf557568..85cdab918 100644 --- a/game/state/city/base.cpp +++ b/game/state/city/base.cpp @@ -1,4 +1,5 @@ #include "game/state/city/base.h" +#include "dependencies/magic_enum/include/magic_enum/magic_enum.hpp" #include "framework/framework.h" #include "game/state/city/building.h" #include "game/state/city/city.h" @@ -282,86 +283,97 @@ Base::BuildError Base::canBuildFacility(StateRef type, Vec2 p void Base::buildFacility(GameState &state, StateRef type, Vec2 pos, bool free) { - if (canBuildFacility(type, pos, free) == BuildError::NoError) + const auto canBuildFacilityResult = canBuildFacility(type, pos, free); + + if (canBuildFacilityResult != BuildError::NoError) + { + const auto canBuildFacilityEnum = magic_enum::enum_name(canBuildFacilityResult); + const auto logMessage = + format("Error when trying to build facility: %s", canBuildFacilityEnum); + LogWarning(logMessage); + return; + } + + auto facility = mksp(type); + facilities.push_back(facility); + facility->pos = pos; + if (!free) { - auto facility = mksp(type); - facilities.push_back(facility); - facility->pos = pos; - if (!free) + if (!building) { - if (!building) - { - LogError("Building disappeared"); - } - else - { - building->owner->balance -= type->buildCost; - } - facility->buildTime = type->buildTime; + LogError("Building disappeared"); } - if (type->capacityAmount > 0) + else { - ResearchTopic::LabSize size; - // FIXME: Make LabSize set-able outside of the facility size? - if (type->size > 1) + building->owner->balance -= type->buildCost; + } + facility->buildTime = type->buildTime; + } + if (type->capacityAmount > 0) + { + ResearchTopic::LabSize size; + // FIXME: Make LabSize set-able outside of the facility size? + if (type->size > 1) + { + size = ResearchTopic::LabSize::Large; + } + else + { + size = ResearchTopic::LabSize::Small; + } + switch (type->capacityType) + { + case FacilityType::Capacity::Chemistry: { - size = ResearchTopic::LabSize::Large; + auto lab = mksp(); + lab->size = size; + lab->type = ResearchTopic::Type::BioChem; + auto id = Lab::generateObjectID(state); + state.research.labs[id] = lab; + facility->lab = {&state, id}; + break; } - else + case FacilityType::Capacity::Physics: { - size = ResearchTopic::LabSize::Small; + auto lab = mksp(); + lab->size = size; + lab->type = ResearchTopic::Type::Physics; + auto id = Lab::generateObjectID(state); + state.research.labs[id] = lab; + facility->lab = {&state, id}; + break; } - switch (type->capacityType) + case FacilityType::Capacity::Workshop: { - case FacilityType::Capacity::Chemistry: - { - auto lab = mksp(); - lab->size = size; - lab->type = ResearchTopic::Type::BioChem; - auto id = Lab::generateObjectID(state); - state.research.labs[id] = lab; - facility->lab = {&state, id}; - break; - } - case FacilityType::Capacity::Physics: - { - auto lab = mksp(); - lab->size = size; - lab->type = ResearchTopic::Type::Physics; - auto id = Lab::generateObjectID(state); - state.research.labs[id] = lab; - facility->lab = {&state, id}; - break; - } - case FacilityType::Capacity::Workshop: - { - auto lab = mksp(); - lab->size = size; - lab->type = ResearchTopic::Type::Engineering; - auto id = Lab::generateObjectID(state); - state.research.labs[id] = lab; - facility->lab = {&state, id}; - break; - } - default: - // Non-lab modules don't need special handling - break; + auto lab = mksp(); + lab->size = size; + lab->type = ResearchTopic::Type::Engineering; + auto id = Lab::generateObjectID(state); + state.research.labs[id] = lab; + facility->lab = {&state, id}; + break; } + default: + // Non-lab modules don't need special handling + break; } } } Base::BuildError Base::canDestroyFacility(GameState &state, Vec2 pos) const { - auto facility = getFacility(pos); + const auto facility = getFacility(pos); + if (facility == nullptr) { return BuildError::OutOfBounds; } + if (facility->type->fixed) { return BuildError::Indestructible; } + if (facility->buildTime > 0) { return BuildError::NoError; @@ -372,21 +384,23 @@ Base::BuildError Base::canDestroyFacility(GameState &state, Vec2 pos) const case FacilityType::Capacity::Quarters: case FacilityType::Capacity::Stores: case FacilityType::Capacity::Aliens: - if (getCapacityUsed(state, facility->type->capacityType) > - getCapacityTotal(facility->type->capacityType) - facility->type->capacityAmount) + { + const auto capacityUsed = getCapacityUsed(state, facility->type->capacityType); + const auto capacityTotal = getCapacityTotal(facility->type->capacityType); + const auto capacityAmount = facility->type->capacityAmount; + + if (capacityUsed > capacityTotal - capacityAmount) { return BuildError::Occupied; } break; + } case FacilityType::Capacity::Physics: case FacilityType::Capacity::Chemistry: case FacilityType::Capacity::Workshop: - if (facility->lab) + if (facility->lab && facility->lab->current_project) { - if (facility->lab->current_project) - { - return BuildError::Occupied; - } + return BuildError::Occupied; } break; default: @@ -397,46 +411,63 @@ Base::BuildError Base::canDestroyFacility(GameState &state, Vec2 pos) const void Base::destroyFacility(GameState &state, Vec2 pos) { - if (canDestroyFacility(state, pos) == BuildError::NoError) + const auto canDestroyFacilityResult = canDestroyFacility(state, pos); + + if (canDestroyFacilityResult != BuildError::NoError) + { + const auto canDestroyFacilityEnum = magic_enum::enum_name(canDestroyFacilityResult); + const auto logMessage = + format("Error when trying to destroy facility: %s", canDestroyFacilityEnum); + LogWarning(logMessage); + return; + } + + const auto facility = getFacility(pos); + + for (auto f = facilities.begin(); f != facilities.end(); ++f) { - auto facility = getFacility(pos); - for (auto f = facilities.begin(); f != facilities.end(); ++f) + if (*f != facility) + continue; + + if (facility->lab) { - if (*f == facility) + for (auto &a : facility->lab->assigned_agents) { - if (facility->lab) - { - auto id = facility->lab.id; - if (facility->lab->current_project) - { - facility->lab->current_project->current_lab = ""; - facility->lab->current_project = ""; - } - facility->lab = ""; - state.research.labs.erase(id); - } - if (facility->type->buildTime > 0) - { - building->owner->balance += - facility->type->buildCost * facility->buildTime / facility->type->buildTime; - } - facilities.erase(f); - break; + a->assigned_to_lab = false; + } + if (facility->lab->current_project) + { + facility->lab->current_project->current_lab = ""; + facility->lab->current_project = ""; } + facility->lab = ""; + state.research.labs.erase(facility->lab.id); } + + if (facility->type->buildTime > 0) + { + building->owner->balance += + facility->type->buildCost * facility->buildTime / facility->type->buildTime; + } + + facilities.erase(f); + break; } } -bool Base::containmentEmpty(GameState &state) +bool Base::alienContainmentExists() const { - for (auto &f : facilities) + return getCapacityTotal(FacilityType::Capacity::Aliens) > 0; +} + +bool Base::alienContainmentIsEmpty(GameState &state) +{ + for (const auto &f : facilities) { - if (f->type->capacityType == FacilityType::Capacity::Aliens) + if (f->type->capacityType == FacilityType::Capacity::Aliens && + getCapacityUsed(state, f->type->capacityType) != 0) { - if (getCapacityUsed(state, f->type->capacityType) != 0) - { - return false; - } + return false; } } return true; @@ -448,35 +479,35 @@ int Base::getCapacityUsed(GameState &state, FacilityType::Capacity type) const switch (type) { case FacilityType::Capacity::Repair: - for (auto &v : state.vehicles) + for (const auto &v : state.vehicles) { - if (v.second->homeBuilding == building && - v.second->getMaxHealth() > v.second->getHealth()) + const auto maxHealth = v.second->getMaxHealth(); + const auto health = v.second->getHealth(); + + if (v.second->homeBuilding == building && maxHealth > health) { - total += v.second->getMaxHealth() - v.second->getHealth(); + total += maxHealth - health; } } // Show percentage of repair bay used if it can repair in one hour, or 100% if can't if (total > 0) { - int max = getCapacityTotal(type); + const auto max = getCapacityTotal(type); return std::min(total, max); } break; case FacilityType::Capacity::Medical: - for (auto &a : state.agents) + for (const auto &a : state.agents) { - if (a.second->homeBuilding == building) + if (a.second->homeBuilding == building && + a.second->modified_stats.health < a.second->current_stats.health) { - if (a.second->modified_stats.health < a.second->current_stats.health) - { - total++; - } + total++; } } break; case FacilityType::Capacity::Training: - for (auto &a : state.agents) + for (const auto &a : state.agents) { if (a.second->homeBuilding == building && a.second->trainingAssignment == TrainingAssignment::Physical) @@ -486,7 +517,7 @@ int Base::getCapacityUsed(GameState &state, FacilityType::Capacity type) const } break; case FacilityType::Capacity::Psi: - for (auto &a : state.agents) + for (const auto &a : state.agents) { if (a.second->homeBuilding == building && a.second->trainingAssignment == TrainingAssignment::Psi) @@ -500,16 +531,16 @@ int Base::getCapacityUsed(GameState &state, FacilityType::Capacity type) const case FacilityType::Capacity::Physics: [[fallthrough]]; case FacilityType::Capacity::Workshop: - for (auto f = facilities.begin(); f != facilities.end(); ++f) + for (const auto &f : facilities) { - if ((*f)->type->capacityType == type && (*f)->lab) + if (f->type->capacityType == type && f->lab) { - total += (int)(*f)->lab->assigned_agents.size(); + total += (int)f->lab->assigned_agents.size(); } } break; case FacilityType::Capacity::Quarters: - for (auto &a : state.agents) + for (const auto &a : state.agents) { if (a.second->homeBuilding == building) { @@ -518,19 +549,19 @@ int Base::getCapacityUsed(GameState &state, FacilityType::Capacity type) const } break; case FacilityType::Capacity::Stores: - for (auto &e : inventoryAgentEquipment) + for (const auto &e : inventoryAgentEquipment) { StateRef ae = {&state, e.first}; total += ae->type == AEquipmentType::Type::Ammo ? ae->store_space * ((e.second + ae->max_ammo - 1) / ae->max_ammo) : ae->store_space * e.second; } - for (auto &e : inventoryVehicleEquipment) + for (const auto &e : inventoryVehicleEquipment) { StateRef ve = {&state, e.first}; total += ve->store_space * e.second; } - for (auto &e : inventoryVehicleAmmo) + for (const auto &e : inventoryVehicleAmmo) { StateRef va = {&state, e.first}; total += va->store_space * e.second; @@ -538,7 +569,7 @@ int Base::getCapacityUsed(GameState &state, FacilityType::Capacity type) const break; case FacilityType::Capacity::Aliens: { - for (auto &e : inventoryBioEquipment) + for (const auto &e : inventoryBioEquipment) { if (e.second == 0) continue; @@ -559,11 +590,11 @@ int Base::getCapacityUsed(GameState &state, FacilityType::Capacity type) const int Base::getCapacityTotal(FacilityType::Capacity type) const { int total = 0; - for (auto f = facilities.begin(); f != facilities.end(); ++f) + for (const auto &f : facilities) { - if ((*f)->type->capacityType == type && (*f)->buildTime == 0) + if (f->type->capacityType == type && f->buildTime == 0) { - total += (*f)->type->capacityAmount; + total += f->type->capacityAmount; } } return total; diff --git a/game/state/city/base.h b/game/state/city/base.h index 3cbe23f95..05c15b2d8 100644 --- a/game/state/city/base.h +++ b/game/state/city/base.h @@ -55,7 +55,12 @@ class Base : public StateObject, public std::enable_shared_from_this bool free = false); BuildError canDestroyFacility(GameState &state, Vec2 pos) const; void destroyFacility(GameState &state, Vec2 pos); - bool containmentEmpty(GameState &state); + + // Returns if an Alien Containment module exists at base + bool alienContainmentExists() const; + + // Returns if Alien Containment capacity is empty at base + bool alienContainmentIsEmpty(GameState &state); int getCapacityUsed(GameState &state, FacilityType::Capacity type) const; int getCapacityTotal(FacilityType::Capacity type) const; float getUsage(GameState &state, const sp facility, const int delta = 0) const; diff --git a/game/state/city/building.cpp b/game/state/city/building.cpp index 1fc68a388..2844a7bb7 100644 --- a/game/state/city/building.cpp +++ b/game/state/city/building.cpp @@ -354,7 +354,6 @@ void Building::updateCargo(GameState &state) } } } while (spawnedFerry); - return; } // Step 03.02: Compile list of carrying capacity required diff --git a/game/state/city/building.h b/game/state/city/building.h index e127caaf5..1edc36ca1 100644 --- a/game/state/city/building.h +++ b/game/state/city/building.h @@ -4,8 +4,8 @@ #include "game/state/stateobject.h" #include "library/rect.h" #include "library/vec.h" +#include #include -#include namespace OpenApoc { diff --git a/game/state/city/city.cpp b/game/state/city/city.cpp index 3bbe37940..f9fb3727c 100644 --- a/game/state/city/city.cpp +++ b/game/state/city/city.cpp @@ -6,8 +6,6 @@ #include "game/state/city/building.h" #include "game/state/city/scenery.h" #include "game/state/city/vehicle.h" -#include "game/state/city/vehiclemission.h" -#include "game/state/city/vequipment.h" #include "game/state/gamestate.h" #include "game/state/rules/city/citycommonimagelist.h" #include "game/state/rules/city/scenerytiletype.h" @@ -323,11 +321,43 @@ void City::dailyLoop(GameState &state) b.second->updateWorkforce(); } } - generatePortals(state); +} + +void City::weeklyLoop(GameState &state) { generatePortals(state); } + +bool City::canPlacePortal(Vec3 position) +{ + if (!(map->tileIsValid(position) && map->getTile(position)->ownedObjects.empty())) + { + return false; + } + + for (int i = 1; i < 5; i++) + { + for (int x = -1; x <= 1; x++) + { + for (int y = -1; y <= 1; y++) + { + for (int z = -2; z <= 2; z++) + { + const auto newTile = position + Vec3(x * i, y * i, z); + + if (!(map->tileIsValid(newTile) && map->getTile(newTile)->ownedObjects.empty())) + { + return false; + } + } + } + } + } + return true; } void City::generatePortals(GameState &state) { + const static auto zWeight = {1, 1, 3, 4, 6}; + const static double portalDev = 25.0; + if (portals.empty()) { if (!initial_portals.empty()) @@ -345,12 +375,8 @@ void City::generatePortals(GameState &state) } else { - // FIXME: Implement proper portals - // According to skin36, portals must have empty 4x4x4 around them - // and spawn within 100x100 around city center - // FIXME: Implement portals in alien city staying where they are - // and starting where they should + // and starting where they should (Need to be linked to portals in human city) static const int iterLimit = 1000; for (auto &p : portals) @@ -359,15 +385,17 @@ void City::generatePortals(GameState &state) } this->portals.clear(); - std::uniform_int_distribution xyPos(20, 120); - std::uniform_int_distribution zPos(2, 8); + std::normal_distribution xyPos(70.0, portalDev); + std::discrete_distribution zPos(zWeight.begin(), zWeight.end()); + for (int p = 0; p < 3; p++) { for (int i = 0; i < iterLimit; i++) { - Vec3 pos(xyPos(state.rng), xyPos(state.rng), zPos(state.rng)); - - if (map->tileIsValid(pos) && map->getTile(pos)->ownedObjects.empty()) + Vec3 pos(std::clamp(static_cast(xyPos(state.rng)), 20, 120), + std::clamp(static_cast(xyPos(state.rng)), 20, 120), + zPos(state.rng) + 4); + if (canPlacePortal(pos)) { auto doodad = mksp(pos + Vec3{0.5f, 0.5f, 0.5f}, @@ -383,9 +411,63 @@ void City::generatePortals(GameState &state) } else { - // FIXME: Implement moving portals - // According to skin36, portal is moved by +-(2*week + 15) on each coordinate - // and must stay within -5..105 which means within 15 from map border in our coords + if (this->id == "CITYMAP_HUMAN") + { + curPortalPosList.clear(); + + static const int iterLimit = 1000; + for (auto &p : portals) + { + curPortalPosList.push_back(p->position); + p->remove(state); + } + this->portals.clear(); + + int week = state.gameTime.getWeek(); + int offset = (2 * week) + 15; + std::uniform_int_distribution newxyOffset(-offset, offset); + std::discrete_distribution newzPos(zWeight.begin(), zWeight.end()); + + for (int p = 0; p < 3; p++) + { + bool portalPlaced = false; + for (int i = 0; i < iterLimit; i++) + { + Vec3 newPos(std::clamp(newxyOffset(state.rng) + + static_cast(curPortalPosList.back().x), + 20, 120), + std::clamp(newxyOffset(state.rng) + + static_cast(curPortalPosList.back().y), + 20, 120), + newzPos(state.rng) + 4); + + if (canPlacePortal(newPos)) + { + auto doodad = + mksp(newPos + Vec3{0.5f, 0.5f, 0.5f}, + StateRef{&state, "DOODAD_6_DIMENSION_GATE"}); + doodad->voxelMap = state.city_common_image_list->portalVoxelMap; + map->addObjectToMap(doodad); + this->portals.push_back(doodad); + curPortalPosList.pop_back(); + portalPlaced = true; + break; + } + } + if (!portalPlaced) + { + auto currentPos = curPortalPosList.back(); + auto doodad = + mksp(currentPos + Vec3{0.5f, 0.5f, 0.5f}, + StateRef{&state, "DOODAD_6_DIMENSION_GATE"}); + doodad->voxelMap = state.city_common_image_list->portalVoxelMap; + map->addObjectToMap(doodad); + this->portals.push_back(doodad); + curPortalPosList.pop_back(); + // break; + } + } + } } } diff --git a/game/state/city/city.h b/game/state/city/city.h index 699f9fb33..a99d33b8e 100644 --- a/game/state/city/city.h +++ b/game/state/city/city.h @@ -91,6 +91,7 @@ class City : public StateObject, public std::enable_shared_from_this std::vector> scenery; std::list> doodads; std::vector> portals; + std::list> curPortalPosList; std::set> projectiles; @@ -131,8 +132,10 @@ class City : public StateObject, public std::enable_shared_from_this void update(GameState &state, unsigned int ticks); void hourlyLoop(GameState &state); void dailyLoop(GameState &state); + void weeklyLoop(GameState &state); void generatePortals(GameState &state); + bool canPlacePortal(Vec3 position); void updateInfiltration(GameState &state); void repairVehicles(GameState &state); void repairScenery(GameState &state, bool debugRepair = false); diff --git a/game/state/city/research.cpp b/game/state/city/research.cpp index 1a8cf3599..d15e8f560 100644 --- a/game/state/city/research.cpp +++ b/game/state/city/research.cpp @@ -9,7 +9,6 @@ #include "game/state/gameevent.h" #include "game/state/gamestate.h" #include "game/state/rules/aequipmenttype.h" -#include "game/state/rules/city/citycommonimagelist.h" #include "game/state/rules/city/vehicletype.h" #include "game/state/shared/organisation.h" #include "library/strings_format.h" diff --git a/game/state/city/scenery.cpp b/game/state/city/scenery.cpp index 526c23b26..abec9c22c 100644 --- a/game/state/city/scenery.cpp +++ b/game/state/city/scenery.cpp @@ -3,7 +3,6 @@ #include "framework/framework.h" #include "framework/logger.h" #include "framework/sound.h" -#include "game/state/city/agentmission.h" #include "game/state/city/building.h" #include "game/state/city/city.h" #include "game/state/city/vehicle.h" @@ -961,8 +960,8 @@ bool Scenery::findSupport(bool allowClinging) } // for every connected way return true; } // if connected to more than one way - } // if more than 2 ways to connect to - } // If road or tube + } // if more than 2 ways to connect to + } // If road or tube // Step 04.02: With generals, we can shoot in x or in y, but connect only to hard support // We also do not re-try support when lost @@ -1092,7 +1091,7 @@ bool Scenery::findSupport(bool allowClinging) } // for every connected way return true; } // for every list of increments (vertical and horizontal) - } // If general + } // If general // If we didn't succeed, don't clear supportedBy! // supportedBy = lastSupportedBy; diff --git a/game/state/city/scenery.h b/game/state/city/scenery.h index dca1d85bf..f35a53878 100644 --- a/game/state/city/scenery.h +++ b/game/state/city/scenery.h @@ -4,6 +4,7 @@ #include "game/state/stateobject.h" #include "library/sp.h" #include "library/vec.h" +#include #include #define FALLING_ACCELERATION_MAP_PART 0.16666667f // 1/6th diff --git a/game/state/city/vehicle.cpp b/game/state/city/vehicle.cpp index 28b3b79a5..b7917c5c0 100644 --- a/game/state/city/vehicle.cpp +++ b/game/state/city/vehicle.cpp @@ -1,6 +1,7 @@ #ifndef _USE_MATH_DEFINES #define _USE_MATH_DEFINES #endif + #include "game/state/city/vehicle.h" #include "framework/configfile.h" #include "framework/framework.h" @@ -15,6 +16,7 @@ #include "game/state/city/vequipment.h" #include "game/state/gameevent.h" #include "game/state/gamestate.h" +#include "game/state/gametime.h" #include "game/state/rules/aequipmenttype.h" #include "game/state/rules/city/citycommonsamplelist.h" #include "game/state/rules/city/scenerytiletype.h" @@ -30,10 +32,12 @@ #include "game/state/tilemap/tileobject_shadow.h" #include "game/state/tilemap/tileobject_vehicle.h" #include "library/sp.h" +#include +#include #include #include +#include #include -#include #include namespace OpenApoc @@ -380,11 +384,14 @@ class FlyingVehicleMover : public VehicleMover } if (vehicle.carriedByVehicle) { - auto newPos = vehicle.carriedByVehicle->position; - newPos.z = std::max(0.0f, newPos.z - 0.5f); - vehicle.setPosition(newPos); - vehicle.facing = vehicle.carriedByVehicle->facing; - vehicle.updateSprite(state); + if (vehicle.tileObject) + { + auto newPos = vehicle.carriedByVehicle->position; + newPos.z = std::max(0.0f, newPos.z - 0.5f); + vehicle.setPosition(newPos); + vehicle.facing = vehicle.carriedByVehicle->facing; + vehicle.updateSprite(state); + } return; } if (vehicle.crashed) @@ -557,7 +564,6 @@ class FlyingVehicleMover : public VehicleMover // d += 0.12f * (float)M_PI; vehicle.ticksToTurn = floorf(d / vehicle.angularVelocity); - // FIXME: Introduce proper turning speed // Here we just slow down velocity if we're moving too quickly if (vehicle.position != vehicle.goalPosition) { @@ -567,10 +573,11 @@ class FlyingVehicleMover : public VehicleMover std::max(floorf(glm::length(vectorToGoal) / glm::length(vehicle.velocity) * (float)TICK_SCALE) - 5.0f, - 1.0f); + 2.0f); if (ticksToMove < vehicle.ticksToTurn) { - vehicle.velocity *= (float)ticksToMove / (float)vehicle.ticksToTurn; + vehicle.velocity *= + std::abs(vehicle.angularVelocity) * TURNING_SLOW_DOWN_CORRECTION; } } } @@ -1127,12 +1134,8 @@ void VehicleMover::updateCrashed(GameState &state, unsigned int ticks [[maybe_un if (vehicle.tileObject && vehicle.tileObject->getOwningTile() && vehicle.tileObject->getOwningTile()->presentScenery) { - auto presentScenery = vehicle.tileObject->getOwningTile()->presentScenery; - if (!presentScenery) - { - vehicle.setCrashed(state, false); - vehicle.startFalling(state); - } + vehicle.setCrashed(state, false); + vehicle.startFalling(state); } } @@ -1366,13 +1369,14 @@ void Vehicle::enterBuilding(GameState &state, StateRef b) { carriedByVehicle.clear(); crashed = false; - if (this->currentBuilding) + if (b->currentVehicles.find(&state) != b->currentVehicles.end()) { LogError("Vehicle already in a building?"); return; } this->currentBuilding = b; b->currentVehicles.insert({&state, shared_from_this()}); + if (carriedVehicle) { carriedVehicle->enterBuilding(state, b); @@ -1736,6 +1740,29 @@ StateRef Vehicle::getServiceDestination(GameState &state) { if (it->destination == currentBuilding) { + // Only add aliens if alien containment is available at base + const auto vehicleContainsAlienLoot = cargoContainsAlienLoot(); + const auto alienContainmentExists = + currentBuilding->base ? currentBuilding->base->alienContainmentExists() : false; + + // Vehicle must be stopped from unloading alien cargo when vehicle has alien loot but + // base has no alien containment + const auto isVehicleAllowedToUnloadAlienCargo = + !(vehicleContainsAlienLoot && !alienContainmentExists); + + if (!isVehicleAllowedToUnloadAlienCargo) + { + fw().pushEvent( + new GameVehicleEvent(GameEventType::VehicleWithAlienLootInBaseWithNoContainment, + {&state, shared_from_this()})); + } + // Only unload alien cargo when base has alien containment + if (it->type == Cargo::Type::Bio && !isVehicleAllowedToUnloadAlienCargo) + { + it++; + continue; + } + it->arrive(state, cargoArrived, bioArrived, recoveryArrived, transferArrived, suppliers); it = cargo.erase(it); @@ -3865,6 +3892,19 @@ const UString Vehicle::getFormattedVehicleNameForEventMessage(GameState &state) return name; } +const bool Vehicle::cargoContainsAlienLoot() const +{ + for (const auto &cargoItem : cargo) + { + if (cargoItem.type == Cargo::Type::Bio) + { + return true; + } + } + + return false; +} + Cargo::Cargo(GameState &state, StateRef equipment, int count, int price, StateRef originalOwner, StateRef destination) : Cargo(state, equipment->bioStorage ? Type::Bio : Type::Agent, equipment.id, count, diff --git a/game/state/city/vehicle.h b/game/state/city/vehicle.h index afb9bf0f4..7adebd611 100644 --- a/game/state/city/vehicle.h +++ b/game/state/city/vehicle.h @@ -9,7 +9,6 @@ #include "library/strings.h" #include "library/vec.h" #include -#include // Uncomment to allow projectiles to shoot down friendly projectiles // #define DEBUG_ALLOW_PROJECTILE_ON_PROJECTILE_FRIENDLY_FIRE @@ -57,6 +56,9 @@ static const int FV_SCRAPPED_COST_PERCENT = 25; static const int FUEL_TICKS_PER_SECOND = 144; // How much ticks is required to spend one unit of fuel static const int FUEL_TICKS_PER_UNIT = 40000; +// Correction factor for turning slowdown mechanic, purely found by data analysis, could not +// establish any logical conclusion +static const float TURNING_SLOW_DOWN_CORRECTION = 38.893f; class Image; class TileObjectVehicle; @@ -386,6 +388,8 @@ class Vehicle : public StateObject, const UString getFormattedVehicleNameForEventMessage(GameState &state) const; + const bool cargoContainsAlienLoot() const; + // Following members are not serialized, but rather setup during game up mover; diff --git a/game/state/city/vehiclemission.cpp b/game/state/city/vehiclemission.cpp index ae9558d1c..3020fb0df 100644 --- a/game/state/city/vehiclemission.cpp +++ b/game/state/city/vehiclemission.cpp @@ -22,7 +22,6 @@ #include "game/state/tilemap/tilemap.h" #include "game/state/tilemap/tileobject_doodad.h" #include "game/state/tilemap/tileobject_scenery.h" -#include "game/state/tilemap/tileobject_shadow.h" #include "game/state/tilemap/tileobject_vehicle.h" #include "library/strings_format.h" #include @@ -1037,19 +1036,11 @@ Reachability VehicleTargetHelper::isReachableTargetGround(const Vehicle &v, Vec3 bool VehicleMission::takeOffCheck(GameState &state, Vehicle &v) { - if (!v.tileObject) - { - if (v.currentBuilding) - { - v.addMission(state, VehicleMission::takeOff(v)); - return true; - } - else - { - return false; - } - } - return false; + if (v.tileObject || !v.currentBuilding) + return false; + + v.addMission(state, VehicleMission::takeOff(v)); + return true; } bool VehicleMission::teleportCheck(GameState &state, Vehicle &v) @@ -1277,6 +1268,9 @@ bool VehicleMission::getNextDestination(GameState &state, Vehicle &v, Vec3targetBuilding) @@ -1992,30 +1986,27 @@ void VehicleMission::start(GameState &state, Vehicle &v) } case MissionType::AttackBuilding: { - if (!targetBuilding) + if (!targetBuilding && !acquireTargetBuilding(state, v)) { - if (!acquireTargetBuilding(state, v)) - { - cancelled = true; - return; - } + cancelled = true; + return; } + if (takeOffCheck(state, v)) { return; } - else + + if (this->currentPlannedPath.empty()) { - if (this->currentPlannedPath.empty()) - { - std::uniform_int_distribution xPos(targetBuilding->bounds.p0.x - 5, - targetBuilding->bounds.p1.x + 5); - std::uniform_int_distribution yPos(targetBuilding->bounds.p0.y - 5, - targetBuilding->bounds.p1.y + 5); - setPathTo(state, v, v.getPreferredPosition(xPos(state.rng), yPos(state.rng)), - getDefaultIterationCount(v)); - } + std::uniform_int_distribution xPos(targetBuilding->bounds.p0.x - 5, + targetBuilding->bounds.p1.x + 5); + std::uniform_int_distribution yPos(targetBuilding->bounds.p0.y - 5, + targetBuilding->bounds.p1.y + 5); + setPathTo(state, v, v.getPreferredPosition(xPos(state.rng), yPos(state.rng)), + getDefaultIterationCount(v)); } + return; } case MissionType::Crash: diff --git a/game/state/city/vehiclemission.h b/game/state/city/vehiclemission.h index 2a2764955..998a4cfb4 100644 --- a/game/state/city/vehiclemission.h +++ b/game/state/city/vehiclemission.h @@ -7,8 +7,6 @@ #include "library/strings.h" #include "library/vec.h" #include -#include -#include namespace OpenApoc { diff --git a/game/state/city/vequipment.h b/game/state/city/vequipment.h index 3494bdbbe..e776b164a 100644 --- a/game/state/city/vequipment.h +++ b/game/state/city/vequipment.h @@ -3,9 +3,7 @@ #include "game/state/shared/equipment.h" #include "game/state/stateobject.h" #include "library/sp.h" -#include "library/strings.h" #include "library/vec.h" -#include namespace OpenApoc { diff --git a/game/state/gameevent.cpp b/game/state/gameevent.cpp index 64d838d77..45d0f7c5d 100644 --- a/game/state/gameevent.cpp +++ b/game/state/gameevent.cpp @@ -129,6 +129,10 @@ UString GameVehicleEvent::message() return format("%s %s", tr("Not enough ammo to rearm vehicle:"), vehicle->name); case GameEventType::NotEnoughFuel: return format("%s %s", tr("Not enough fuel to refuel vehicle"), vehicle->name); + case GameEventType::VehicleWithAlienLootInBaseWithNoContainment: + return format("%s %s", + tr("Vehicle landed with alien loot in base with no alien containment"), + vehicle->name); default: LogError("Invalid vehicle event type"); break; diff --git a/game/state/gameeventtypes.h b/game/state/gameeventtypes.h index 25a794972..541fc94c0 100644 --- a/game/state/gameeventtypes.h +++ b/game/state/gameeventtypes.h @@ -25,6 +25,7 @@ enum class GameEventType UnauthorizedVehicle, NotEnoughAmmo, NotEnoughFuel, + VehicleWithAlienLootInBaseWithNoContainment, // Vehicle event that starts recovery mission UfoRecoveryBegin, diff --git a/game/state/gamestate.cpp b/game/state/gamestate.cpp index 503bf6cce..995b78c8e 100644 --- a/game/state/gamestate.cpp +++ b/game/state/gamestate.cpp @@ -4,7 +4,6 @@ #include "framework/framework.h" #include "framework/modinfo.h" #include "framework/options.h" -#include "framework/sound.h" #include "game/state/battle/battle.h" #include "game/state/city/base.h" #include "game/state/city/building.h" @@ -23,10 +22,8 @@ #include "game/state/rules/battle/battlemapparttype.h" #include "game/state/rules/battle/battleunitanimationpack.h" #include "game/state/rules/battle/battleunitimagepack.h" -#include "game/state/rules/battle/damage.h" #include "game/state/rules/city/baselayout.h" #include "game/state/rules/city/citycommonimagelist.h" -#include "game/state/rules/city/citycommonsamplelist.h" #include "game/state/rules/city/scenerytiletype.h" #include "game/state/rules/city/ufogrowth.h" #include "game/state/rules/city/ufoincursion.h" @@ -35,8 +32,6 @@ #include "game/state/rules/city/vammotype.h" #include "game/state/rules/city/vehicletype.h" #include "game/state/rules/doodadtype.h" -#include "game/state/shared/aequipment.h" -#include "game/state/shared/doodad.h" #include "game/state/shared/organisation.h" #include "game/state/shared/projectile.h" #include "game/state/tilemap/tilemap.h" @@ -116,7 +111,12 @@ GameState::~GameState() // Just a handy shortcut since it's shown on every single screen UString GameState::getPlayerBalance() const { - return Strings::fromInteger(this->getPlayer()->balance); + auto playerBalance = Strings::fromInteger(this->getPlayer()->balance); + + if (config().getBool("OpenApoc.NewFeature.formatAsCurrency")) + playerBalance = Strings::formatTextAsCurrency(playerBalance); + + return playerBalance; } StateRef GameState::getOrganisation(const UString &orgID) @@ -639,7 +639,7 @@ void GameState::startGame() gameTime = GameTime::midday(); - updateEndOfWeek(); + updateEndOfWeek(true); newGame = true; firstDetection = true; @@ -796,8 +796,6 @@ void GameState::invasion() nextInvasion = gameTime.getTicks() + 24 * TICKS_PER_HOUR + randBoundsInclusive(rng, 0, (int)(72 * TICKS_PER_HOUR)); - invadedCity->generatePortals(*this); - auto invadingCity = StateRef{this, "CITYMAP_ALIEN"}; auto invadingOrg = StateRef{this, "ORG_ALIEN"}; @@ -1096,6 +1094,16 @@ void GameState::update(unsigned int ticks) { if (v.second->city == current_city) { + auto vehicleMission = v.second->missions; + if (!vehicleMission.empty() && + vehicleMission.back().type == VehicleMission::MissionType::AttackVehicle && + (vehicleMission.back().targetVehicle == nullptr || + vehicleMission.back().targetVehicle->city != current_city)) + { + v.second->clearMissions(*this); + v.second->addMission(*this, VehicleMission::gotoBuilding( + *this, *v.second, v.second->homeBuilding)); + } v.second->update(*this, ticks); } } @@ -1134,7 +1142,7 @@ void GameState::update(unsigned int ticks) } if (gameTime.weekPassed()) { - this->updateEndOfWeek(); + this->updateEndOfWeek(false); } gameTime.clearFlags(); @@ -1188,9 +1196,19 @@ void GameState::updateEndOfFiveMinutes() { continue; } + auto base = b.second->base; - for (auto v : b.second->currentVehicles) + for (auto it = b.second->currentVehicles.begin(); it != b.second->currentVehicles.end();) { + auto v = *it; + if (this->vehicles.find(v.id) == this->vehicles.end()) + { + LogWarning("%s not found, but removal was successful..", v.id); + v.clear(); + it = b.second->currentVehicles.erase(it); + continue; + } + for (auto &e : v->equipment) { // We only can reload VehicleWeapon and VehicleEngine(?) @@ -1222,6 +1240,8 @@ void GameState::updateEndOfFiveMinutes() } } } + + ++it; } } @@ -1311,7 +1331,7 @@ void GameState::updateEndOfDay() fw().pushEvent(new GameEvent(GameEventType::DailyReport)); } -void GameState::updateEndOfWeek() +void GameState::updateEndOfWeek(bool gameStart) { updateHumanEconomy(); @@ -1319,6 +1339,14 @@ void GameState::updateEndOfWeek() fw().pushEvent(new GameEvent(GameEventType::WeeklyReport)); weeklyPlayerUpdate(); + + if (!gameStart) + { + for (auto &c : this->cities) + { + c.second->weeklyLoop(*this); + } + } } void GameState::weeklyPlayerUpdate() @@ -1591,25 +1619,24 @@ void GameState::updateAfterBattle() } case GameEventType::MissionCompletedBuildingNormal: { - fw().pushEvent(new GameBuildingEvent(eventFromBattle, {this, missionLocationBattle})); + fw().pushEvent(new GameBuildingEvent(eventFromBattle, missionLocationBattleBuilding)); break; } case GameEventType::MissionCompletedBase: { - fw().pushEvent(new GameBaseEvent( - eventFromBattle, StateRef(this, missionLocationBattle)->base)); + fw().pushEvent(new GameBaseEvent(eventFromBattle, missionLocationBattleBuilding->base)); break; } case GameEventType::BaseDestroyed: { - auto building = StateRef{this, missionLocationBattle}; + auto building = missionLocationBattleBuilding; fw().pushEvent(new GameSomethingDiedEvent(eventFromBattle, eventFromBattleText, "bySomeone", building->crewQuarters)); break; } case GameEventType::MissionCompletedBuildingRaid: { - fw().pushEvent(new GameBuildingEvent(eventFromBattle, {this, missionLocationBattle})); + fw().pushEvent(new GameBuildingEvent(eventFromBattle, missionLocationBattleBuilding)); break; } case GameEventType::MissionCompletedVehicle: diff --git a/game/state/gamestate.h b/game/state/gamestate.h index b15dddee4..351b3d134 100644 --- a/game/state/gamestate.h +++ b/game/state/gamestate.h @@ -156,7 +156,7 @@ class GameState : public std::enable_shared_from_this // Used to move events from battle to city and remember time GameTime gameTimeBeforeBattle = GameTime(0); - UString missionLocationBattle; + StateRef missionLocationBattleBuilding; UString eventFromBattleText; GameEventType eventFromBattle = GameEventType::None; @@ -252,7 +252,7 @@ class GameState : public std::enable_shared_from_this void updateEndOfFiveMinutes(); void updateEndOfHour(); void updateEndOfDay(); - void updateEndOfWeek(); + void updateEndOfWeek(bool gameStart); void updateHumanEconomy(); void weeklyPlayerUpdate(); diff --git a/game/state/gamestate_pch.h b/game/state/gamestate_pch.h index 59bcad934..516d99896 100644 --- a/game/state/gamestate_pch.h +++ b/game/state/gamestate_pch.h @@ -1,46 +1,19 @@ #pragma once - #include "framework/configfile.h" -#include "framework/data.h" -#include "framework/event.h" #include "framework/framework.h" -#include "framework/image.h" #include "framework/logger.h" #include "framework/renderer.h" -#include "framework/serialization/serialize.h" #include "framework/sound.h" -#include "framework/trace.h" -#include "game/state/gamestate.h" -#include "library/colour.h" -#include "library/line.h" -#include "library/rect.h" +#include "game/state/stateobject.h" +#include "game/state/tilemap/tilemap.h" #include "library/sp.h" #include "library/strings.h" #include "library/strings_format.h" #include "library/vec.h" -#include "library/voxel.h" -#include "library/xorshift.h" #include -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include -#include #include -#include #include -#include -#include -#include #include -#include -#include -#include -#include +#include \ No newline at end of file diff --git a/game/state/gamestate_serialize.cpp b/game/state/gamestate_serialize.cpp index 27a1d105b..0a1a24875 100644 --- a/game/state/gamestate_serialize.cpp +++ b/game/state/gamestate_serialize.cpp @@ -3,24 +3,9 @@ #include "framework/framework.h" #include "framework/image.h" #include "framework/serialization/serialize.h" -#include "game/state/battle/battlemappart.h" -#include "game/state/city/building.h" -#include "game/state/city/city.h" -#include "game/state/city/facility.h" -#include "game/state/city/scenery.h" -#include "game/state/city/vehicle.h" -#include "game/state/city/vehiclemission.h" -#include "game/state/city/vequipment.h" #include "game/state/gamestate.h" #include "game/state/gamestate_serialize_generated.h" -#include "game/state/rules/aequipmenttype.h" -#include "game/state/rules/battle/battlemapparttype.h" -#include "game/state/rules/city/baselayout.h" #include "game/state/rules/city/scenerytiletype.h" -#include "game/state/rules/city/vammotype.h" -#include "game/state/rules/city/vequipmenttype.h" -#include "game/state/shared/doodad.h" -#include "game/state/shared/projectile.h" #include "library/voxel.h" namespace OpenApoc diff --git a/game/state/gamestate_serialize.xml b/game/state/gamestate_serialize.xml index 4556d7690..c96e58b87 100644 --- a/game/state/gamestate_serialize.xml +++ b/game/state/gamestate_serialize.xml @@ -1,2111 +1,2113 @@ - - GameState - vehicle_types - organisations - facility_types - doodad_types - vehicle_equipment - vehicle_ammo - cities - ufo_growth_lists - ufo_mission_preference - ufo_incursions - base_layouts - player_bases - vehicles - ufopaedia - research - agents - agent_types - agent_body_types - agent_equipment_layouts - agent_generator - organisation_raid_rules - weekly_rating_rules - agent_salary - agent_fired_penalty - initial_agents - initial_facilities - initial_agent_equipment - initial_vehicles - initial_vehicle_equipment - initial_vehicle_ammo - initial_base_agent_equipment - initial_aliens - current_city - current_base - agentEquipmentTemplates - totalScore - weekScore - micronoidRainChance - objectIdCount - city_common_image_list - city_common_sample_list - battle_common_image_list - battle_common_sample_list - economy - player - aliens - civilian - government - rng - gameTime - gameTimeBeforeBattle - missionLocationBattle - eventFromBattleText - eventFromBattle - battle_maps - current_battle - hazard_types - damage_modifiers - damage_types - agent_equipment - equipment_sets_by_score - equipment_sets_by_level - building_functions - messages - baseIndex - difficulty - fundingTerminated - firstDetection - nextInvasion - - - BattleMapTileset - map_part_types - - - EventMessage - time - text - location - - - GameTime - ticks - - - ResearchState - topics - labs - - - AgentGenerator - first_names - second_names - - - AgentBodyType - allowed_body_states - allowed_movement_states - allowed_fire_movement_states - allowed_facing - large - maxHeight - height - muzzleZPosition - size - voxelMaps - - - AgentEquipmentLayout - slots - - - AgentType - id - name - role - possible_genders - gender_chance - portraits - min_stats - max_stats - bodyType - shadow_pack - appearance_count - image_packs - animation_packs - armor - damage_modifier - inventory - built_in_weapon_left - built_in_weapon_right - equipment_layout - improvementPercentagePhysical - improvementPercentagePsi - canTrain - playable - availableAtTheGameStart - allowsDirectControl - aiType - immuneToFatalWounds - infiltrationSpeed - growthChance - growthOptions - growthInfiltration - detectionWeight - movementPercent - spreadHazardDamageType - spreadHazardMinPower - spreadHazardMaxPower - spreadHazardTTLDivizor - inventoryBackground - displayRank - missionObjective - liveSpeciesItem - deadSpeciesItem - score - walkSfx - crySfx - damageSfx - fatalWoundSfx - dieSfx - - - EquipmentLayoutSlot - type - align_x - align_y - bounds - - - AEquipment - type - payloadType - lastLoadedAmmoType - equippedPosition - equippedSlotType - ownerAgent - ownerOrganisation - ownerUnit - ammo - armor - primed - activated - triggerDelay - triggerRange - triggerType - recharge_ticks_accumulated - readyToFire - weapon_fire_ticks_remaining - aimingMode - inUse - battleScanner - - - EquipmentSet - id - min_score - max_score - weapons - grenades - equipment - - - EquipmentTemplate - equipment - - - EquipmentTemplate::EquipmentTemplateEntry - pos - type - payloadType - - - EquipmentSet::WeaponData - weapon - clip - clip_amount - - - EquipmentSet::GrenadeData - grenade - grenade_amount - - - EquipmentSet::EquipmentData - equipment - - - Agent - type - name - portrait - appearance - gender - initial_stats - current_stats - modified_stats - overEncumbred - rank - trainingPhysicalTicksAccumulated - trainingPsiTicksAccumulated - trainingAssignment - recentlyHired - recentlyTransferred - recentlyFought - healingProgress - owner - city - homeBuilding - currentBuilding - currentVehicle - position - goalPosition - lab_assigned - assigned_to_lab - unit - isBrainsucker - missions - teleportTicksAccumulated - equipment - destroyAfterBattle - hiredOn - killCount - missionCount - - - AgentPortrait - photo - icon - - - AgentStats - health - accuracy - reactions - speed - time_units - stamina - bravery - strength - morale - psi_energy - psi_attack - psi_defence - physics_skill - biochem_skill - engineering_skill - - - ResearchTopic - name - order - description - man_hours - type - required_lab_size - dependencies - ufopaedia_entry - man_hours_progress - current_lab - score - started - cost - item_type - itemId - hidden - picture - - - ProjectDependencies - research - items - - - ItemDependency - agentItemsRequired - vehicleItemsRequired - agentItemsConsumed - vehicleItemsConsumed - - - UfopaediaCategory - title - description - background - entries - - - GameEventType - UfoSpotted - UfoCrashed - UfoRecoveryUnmanned - VehicleLightDamage - VehicleModerateDamage - VehicleHeavyDamage - VehicleEscaping - VehicleNoAmmo - VehicleLowFuel - VehicleNoFuel - VehicleRepaired - VehicleRearmed - VehicleRefuelled - VehicleNoEngine - VehicleRecovered - UnauthorizedVehicle - NotEnoughAmmo - NotEnoughFuel - UfoRecoveryBegin - DefendTheBase - AgentRearmed - CargoArrived - TransferArrived - RecoveryArrived - CargoExpired - CargoSeized - MissionCompletedBase - BaseDestroyed - AgentDiedCity - VehicleDestroyed - AlienSpotted - CommenceInvestigation - BuildingAttacked - CargoExpiresSoon - MissionCompletedBuildingRaid - MissionCompletedBuildingNormal - OrganisationAttackBuilding - OrganisationRaidBuilding - OrganisationStormBuilding - OrganisationTreatySigned - AlienTakeover - OrganisationRequestBribe - OrganisationRequestAlliance - AgentArrived - AgentUnableToReach - HostileSpotted - AgentBrainsucked - AgentDiedBattle - HostileDied - UnknownDied - AgentCriticallyWounded - AgentBadlyInjured - AgentInjured - AgentUnderFire - AgentUnconscious - AgentLeftCombat - AgentFrozen - AgentBerserk - AgentPanicked - AgentPanicOver - AgentPsiAttacked - AgentPsiProbed - AgentPsiControlled - AgentPsiOver - NoLOF - NewTurn - ResearchCompleted - ManufactureCompleted - ManufactureHalted - FacilityCompleted - ZoomView - MarketUpdate - WeeklyReport - EnterAlienDimension - LeaveAlienDimension - MissionStarted - BuildingDisabled - MissionCompletedVehicle - MissionCompletedBuildingAlien - None - - - Cargo::Type - Agent - Bio - VehicleAmmo - VehicleEquipment - - - Cargo - type - id - count - divisor - space - cost - originalOwner - destination - expirationDate - warned - suppressEvents - - - Vehicle - type - owner - name - attackMode - altitude - missions - equipment - city - position - goalPosition - goalWaypoints - loot - velocity - facing - goalFacing - angularVelocity - ticksToTurn - banking - direction - shadowDirection - health - shield - shieldRecharge - stunTicksRemaining - falling - crashed - sliding - fuelSpentTicks - cloakTicksAccumulated - teleportTicksAccumulated - ticksAutoActionAvailable - homeBuilding - currentBuilding - currentAgents - cargo - carriedVehicle - carriedByVehicle - betweenDimensions - - - VEquipment - type - equippedPosition - weaponState - owner - ammo - reloadTime - - - VehicleMission - type - targetLocation - allowTeleporter - reRouteAttempts - pickNearest - patrolHome - pickedNearest - targetBuilding - targetVehicle - targets - timeToSnooze - missionCounter - currentPlannedPath - subvert - attackCrashed - cancelled - - - AgentMission - type - allowTeleporter - allowTaxi - targetBuilding - timeToSnooze - currentPlannedPath - cancelled - - - BattleUnitMission - type - targetLocation - facingDelta - giveWayAttemptsRemaining - demandGiveWay - blockedByMovingUnit - costPaidUpFront - allowSkipNodes - targetFacing - requireGoal - freeTurn - item - velocityXY - velocityZ - timeToSnooze - allowContinue - targetBodyState - currentPlannedPath - allowRunningAway - jumpTarget - jumped - targetUnit - brainsuckTicksAccumulated - brainsuckSoundsPlayed - cancelled - - - Base - corridors - facilities - inventoryBioEquipment - inventoryAgentEquipment - inventoryVehicleEquipment - inventoryVehicleAmmo - name - building - - - Facility - type - pos - buildTime - lab - - - Lab - size - type - current_project - assigned_agents - ticks_since_last_progress - manufacture_goal - manufacture_done - manufacture_man_hours_invested - - - BattleMapPartType - type - autoConvert - sprite - strategySprite - voxelMapLOF - voxelMapLOS - imageOffset - constitution - explosion_power - explosion_depletion_rate - explosion_type - fire_resist - fire_burn_time - block - size - damaged_map_part - alternative_map_part - animation_frames - transparent - sfxIndex - door - blocksLOS - floor - gravlift - movement_cost - height - floating - provides_support - supportedByAbove - supportedByDirections - supportedByTypes - vanillaSupportedById - independent_structure - exit - missionObjective - reinforcementSpawner - - - BattleScore - combatRating - casualtyPenalty - friendlyFire - liveAlienCaptured - equipmentCaptured - equipmentLost - - - Battle - size - battle_map - losBlocks - visibleTiles - visibleBlocks - visibleUnits - visibleEnemies - blockAvailable - blockCenterPos - linkAvailable - linkCost - blockNeedsUpdate - linkNeedsUpdate - tilesChangedForVision - mission_type - mission_location_id - mode - score - missionEndTimer - buildingCanBeDisabled - buildingDisabled - playerWon - locationOwner - loserHasRetreated - winnerHasRetreated - player_craft - map_parts - units - scanners - items - doodads - projectiles - doors - explosions - hazards - participants - leadershipBonus - aiBlock - currentPlayer - currentActiveOrganisation - hotseat - currentTurn - ticksWithoutAction - ticksWithoutSeenAction - lastSeenActionLocation - turnEndAllowed - interruptQueue - interruptUnits - skirmish - relationshipsBeforeSkirmish - scoreBeforeSkirmish - reinforcementsInterval - ticksUntilNextReinforcement - battleViewZLevel - battleViewScreenCenter - battleViewGroupMove - battleViewSquadIndex - battleViewSelectedUnits - - - BattleMap - id - chunk_size - max_battle_size - allow_entrance - allow_exit - entrance_level_min - entrance_level_max - exit_level_min - exit_level_max - exitsX - exitsY - reinforcementsInterval - tilesets - destroyed_ground_tile - rubble_left_wall - rubble_right_wall - rubble_feature - exit_grounds - sectors - - - BattleMapSector - size - occurrence_min - occurrence_max - sectorTilesName - tiles - spawnLocations - - - BattleMapSectorTiles - losBlocks - loot_locations - guardianLocations - initial_grounds - initial_left_walls - initial_right_walls - initial_features - - - BattleMapSector::LineOfSightBlock - start - end - ai_patrol_priority - ai_target_priority - spawn_type - spawn_priority - also_allow_civilians - low_priority - spawn_large_units - spawn_walking_units - - - BattleUnitImagePack - image_offset - images - - - BattleCommonImageList - strategyImages - loadingImage - focusArrows - burningDoodad - - - CityCommonImageList - strategyImages - projectileVoxelMap - portalVoxelMap - agentIsometric - agentStrategic - portalStrategic - - - BattleCommonSampleList - gravlift - door - brainsuckerHatch - brainsuckerSuck - teleport - burn - genericHitSounds - walkSounds - objectDropSounds - throwSounds - psiFailSounds - psiSuccessSounds - - - CityCommonSampleList - teleport - vehicleExplosion - sceneryExplosion - shieldHit - dimensionShiftIn - dimensionShiftOut - alertSounds - - - BattleUnitAnimationPack - standart_animations - hand_state_animations - body_state_animations - hasAlternativeFiringAnimations - useFiringAnimationForPsi - alt_fire_animations - - - BattleUnitAnimationPack::AnimationEntry - frames - is_overlay - frame_count - units_per_100_frames - - - BattleUnitAnimationPack::AnimationEntry::Frame - unit_image_parts - unit_image_draw_order - - - BattleUnitAnimationPack::AnimationEntry::Frame::InfoBlock - index - offset - - - BattleUnit - id - agent - owner - squadNumber - squadPosition - weaponStatus - targetingMode - targetTile - timesTargetMIA - targetUnit - focusUnit - focusedByUnits - ticksUntillNextTargetCheck - psiStatus - psiTarget - psiItem - ticksAccumulatedToNextPsiCheck - psiAttackers - brainSucker - experiencePoints - combatRating - fatalWounds - healingBodyPart - isHealing - woundTicksAccumulated - regenTicksAccumulated - stunDamage - enzymeDebuffTicksAccumulated - fireDebuffTicksAccumulated - enzymeDebuffIntensity - fireDebuffTicksRemaining - moraleState - moraleStateTicksRemaining - moraleTicksAccumulated - initialTU - reserveShotCost - cloakTicksAccumulated - ticksUntillNextCry - behavior_mode - fire_aiming_mode - fire_permission_mode - movement_mode - kneeling_mode - reserve_shot_mode - reserve_kneel_mode - body_animation_ticks_remaining - body_animation_ticks_total - body_animation_ticks_static - current_body_state - target_body_state - hand_animation_ticks_remaining - residual_aiming_ticks_remaining - firing_animation_ticks_remaining - current_hand_state - target_hand_state - movement_ticks_passed - movement_sounds_played - current_movement_state - turning_animation_ticks_remaining - missions - position - goalPosition - atGoal - usingLift - facing - goalFacing - flyingSpeedModifier - retreated - destroyed - falling - launched - launchGoal - bounced - collisionIgnoredTicks - velocity - tilesMoved - giveWayRequestData - displayedItem - visibleUnits - visibleEnemies - aiList - - - BattleItem - item - position - velocity - bounced - falling - ownerInvulnerableTicks - collisionIgnoredTicks - ticksUntilCollapse - owner - - - BattleHazard - position - damageType - hazardType - power - lifetime - age - frame - ticksUntilVisible - frameChangeTicksAccumulated - nextUpdateTicksAccumulated - ownerOrganisation - ownerUnit - - - BattleExplosion - position - power - ticksUntilExpansion - locationsToExpand - locationsVisited - damageInTheEnd - locationsToDamage - damageType - depletionRate - ownerUnit - ownerOrganisation - affectedUnits - - - BattleMapPart - type - alternative_type - position - ticksUntilCollapse - burnTicksAccumulated - damaged - falling - fallingSpeed - destroyed - providesHardSupport - door - supportedItems - supportedParts - owner - - - BattleDoor - id - operational - right - open - animationFrameCount - openTicksRemaining - animationTicksRemaining - doorSound - - - City - id - size - tile_types - initial_tiles - buildings - scenery - doodads - portals - projectiles - initial_portals - tileToRoadSegmentMap - roadSegments - civilianSalary - researchUnlock - cityViewScreenCenter - cityViewPageIndex - cityViewSelectedOwnedVehicles - cityViewSelectedOtherVehicles - cityViewSelectedSoldiers - cityViewSelectedBios - cityViewSelectedPhysics - cityViewSelectedEngineers - cityViewSelectedOrganisation - cityViewOrgButtonIndex - - - RoadSegment - connections - tilePosition - intact - tileIntact - middle - length - - - Projectile - type - position - velocity - turnRate - age - damage - delay_ticks_remaining - depletionRate - lifetime - firerVehicle - firerUnit - trackedVehicle - trackedUnit - targetPosition - previousPosition - stunTicks - splitIntoTypesCity - splitIntoTypesBattle - spritePositions - tail_length - projectile_sprites - sprite_distance - manualFire - voxelMapLof - voxelMapLos - impactSfx - doodadType - damageType - ownerInvulnerableTicks - velocityScale - - - Doodad - position - imageOffset - temporary - age - lifetime - sprite - type - voxelMap - - - DoodadType - lifetime - repeatable - imageOffset - frames - - - Scenery - type - initialPosition - currentPosition - ticksUntilCollapse - supportedParts - supportedBy - damaged - falling - fallingSpeed - destroyed - supportHardness - - - BuildingFunction - name - baseCost - baseIncome - workersPerTile - agentSpawnType - investmentValue - prestige - infiltrationSpeed - detectionWeight - ufopaedia_entry - - - Building - name - city - function - owner - bounds - base_layout - base - battle_map - preset_crew - current_crew - crewQuarters - currentVehicles - currentAgents - cargo - isPurchesable - purchasePrice - maintenanceCosts - maximumWorkforce - currentWorkforce - incomePerCapita - currentWage - investment - prestige - ticksDetectionTimeOut - ticksDetectionAttemptAccumulated - detected - timeOfLastAttackEvent - researchUnlock - accessTopic - victory - pendingInvestigatorCount - - - UFOIncursion - primaryMission - primaryList - escortList - attackList - priority - - - UFOGrowth - week - vehicleTypeList - - - UFOMissionPreference - week - missionList - - - BaseLayout - baseCorridors - baseLift - - - SceneryTileType - tile_type - road_type - walk_mode - connection - hill - tube - sprite - strategySprite - overlaySprite - voxelMap - damagedTile - imageOffset - isLandingPad - minimap_colour - constitution - value - mass - strength - height - overlayHeight - basement - isBuildingPart - commonProperty - isHill - - - VAmmoType - id - name - weight - ammo_id - manufacturer - store_space - - - DamageModifier - - - HazardType - doodadType - sound - minLifetime - maxLifetime - fire - - - DamageType::BlockType - Physical - Psionic - Gas - Fire - - - DamageType::EffectType - None - Stun - Smoke - Fire - Enzyme - Brainsucker - Psionic - - - DamageType - name - icon_sprite - ignore_shield - non_violent - modifiers - explosive - explosionDoodad - blockType - effectType - hazardType - explosionSounds - - - AEquipmentType - type - id - name - weight - held_image_pack - dropped_sprite - dropped_offset - dropped_shadow_sprite - shadow_offset - equipscreen_sprite - equipscreen_size - manufacturer - store_space - armor - score - research_dependency - two_handed - bioStorage - bioRemains - launcher - artifact - body_sprite - damage_modifier - body_part - body_image_pack - provides_flight - weapon_types - max_ammo - burst - recharge - rechargeTB - speed - projectile_sprites - damage - accuracy - fire_delay - projectile_delay - tail_size - guided - turn_rate - range - ttl - explosion_graphic - shield_graphic - fire_sfx - impact_sfx - damage_type - trigger_type - explosion_depletion_rate - spawnList - - - VEquipmentType - type - id - name - weight - max_ammo - burst - ammo_type - equipscreen_sprite - equipscreen_size - manufacturer - store_space - users - speed - projectile_sprites - damage - accuracy - fire_delay - tail_size - guided - turn_rate - range - ttl - firing_arc_1 - firing_arc_2 - point_defence - fire_sfx - impact_sfx - explosion_graphic - icon - stunTicks - splitIntoTypes - power - top_speed - accuracy_modifier - cargo_space - passengers - alien_space - missile_jamming - shielding - cloaking - teleporting - dimensionShifting - scoreRequirement - research_dependency - - - DoodadFrame - image - time - - - FacilityType - name - fixed - buildCost - buildTime - weeklyCost - capacityType - capacityAmount - size - sprite - dependency - ufopaedia_entry - sector - - - OrganisationRaid::Type - None - Attack - Raid - Storm - UnauthorizedVehicle - Treaty - - - OrganisationRaid - nextRaidTimer - attack_vehicle_types - neutral_low_manpower - neutral_normal - neutral_high_manpower - military_low_manpower - military_normal - military_high_manpower - - - Organisation::MissionPattern::Target - Owned - OwnedOrOther - Other - ArriveFromSpace - DepartToSpace - - - Organisation::Relation - Allied - Friendly - Neutral - Unfriendly - Hostile - - - Organisation::RecurringMission - time - pattern - - - Organisation::RaidMission - time - type - target - - - Organisation::MissionPattern - minIntervalRepeat - maxIntervalRepeat - minAmount - maxAmount - allowedTypes - target - relation - - - Organisation - id - name - balance - income - rebuildingRate - infiltrationValue - infiltrationHistory - infiltrationSpeed - ticksTakeOverAttemptAccumulated - takenOver - militarized - initiatesDiplomacy - providesTransportationServices - tech_level - average_guards - guard_types_reinforcements - guard_types_human - guard_types_alien - loot - icon - current_relations - long_term_relations - ufopaedia_entry - raid_missions - recurring_missions - vehiclePark - hirableAgentTypes - - - VehicleType - numCreated - type - name - manufacturer - image_offset - acceleration - top_speed - health - crash_health - weight - armour - passengers - aggressiveness - score - icon - battle_map - crew_downed - crew_deposit - equipment_screen - equip_icon_big - equip_icon_small - mapIconType - directional_sprites - shadow_offset - directional_shadow_sprites - animation_sprites - crashed_sprite - height - size - voxelMaps - voxelMapsLOS - equipment_layout_slots - initial_equipment_list - ufopaedia_entry - provideFreightAgent - provideFreightCargo - provideFreightBio - canRescueCrashed - canEnterDimensionGate - researchUnlock - - - UfopaediaEntry - title - description - background - data_id - data_type - dependency - - - ResearchDependency - type - topics - - - BattleUnitAnimationPack::AnimationKey - itemWieldMode - handState - movementState - bodyState - - - BattleUnitAnimationPack::ChangingHandAnimationKey - itemWieldMode - currentHand - targetHand - movementState - bodyState - - - BattleUnitAnimationPack::ChangingBodyStateAnimationKey - itemWieldMode - handState - movementState - currentBodyState - targetBodyState - - - BattleUnitAnimationPack::AltFireAnimationKey - itemWieldMode - handState - angle - movementState - bodyState - - - VEquipmentType::User - Ground - Air - Ammo - - - VehicleType::Type - Flying - UFO - Road - ATV - - - VehicleType::Direction - N - NNE - NE - NEE - E - SEE - SE - SSE - S - SSW - SW - SWW - W - NWW - NW - NNW - - - VehicleType::Banking - Flat - Left - Right - Ascending - Descending - - - VehicleType::ArmourDirection - Top - Bottom - Front - Rear - Left - Right - - - VehicleType::MapIconType - Arrow - SmallCircle - LargeCircle - - - ResearchTopic::Type - BioChem - Physics - Engineering - - - ResearchTopic::LabSize - Small - Large - - - ResearchTopic::ItemType - VehicleEquipment - AgentEquipment - VehicleEquipmentAmmo - Craft - - - Vehicle::AttackMode - Aggressive - Standard - Defensive - Evasive - - - Vehicle::Altitude - Highest - High - Standard - Low - - - VehicleMission::MissionType - GotoLocation - GotoBuilding - FollowVehicle - RecoverVehicle - AttackVehicle - AttackBuilding - RestartNextMission - Snooze - TakeOff - Land - Crash - Patrol - GotoPortal - InfiltrateSubvert - OfferService - Teleport - SelfDestruct - DepartToSpace - ArriveFromDimensionGate - InvestigateBuilding - - - AgentMission::MissionType - GotoBuilding - AwaitPickup - RestartNextMission - Snooze - Teleport - - - BattleUnitMission::Type - GotoLocation - Snooze - RestartNextMission - AcquireTU - ChangeBodyState - ThrowItem - DropItem - Turn - ReachGoal - Teleport - Brainsuck - Jump - - - VEquipment::WeaponState - Ready - Disabled - Reloading - OutOfAmmo - - - Battle::MissionType - AlienExtermination - RaidAliens - BaseDefense - RaidHumans - UfoRecovery - - - MapDirection - North - East - South - West - Up - Down - - - Battle::Mode - RealTime - TurnBased - - - SpawnType - Player - Enemy - Civilian - - - ItemWieldMode - None - OneHanded - TwoHanded - - - BattleUnitAnimationPack::AnimationEntry::Frame::UnitImagePart - Shadow - Body - Legs - Helmet - LeftArm - RightArm - Weapon - - - BattleUnit::BehaviorMode - Aggressive - Normal - Evasive - - - WeaponAimingMode - Aimed - Snap - Auto - - - ReserveShotMode - Aimed - Snap - Auto - None - - - BattleUnit::FirePermissionMode - AtWill - CeaseFire - - - MovementMode - Prone - Walking - Running - - - KneelingMode - None - Kneeling - - - WeaponStatus - NotFiring - FiringLeftHand - FiringRightHand - FiringBothHands - - - PsiStatus - NotEngaged - Control - Panic - Stun - Probe - - - BattleUnit::TargetingMode - NoTarget - Unit - TileCenter - TileGround - - - BattleUnitType - SmallWalker - SmallFlyer - LargeWalker - LargeFlyer - - - Organisation::LootPriority - A - B - C - - - BattleMapPartType::Type - Ground - LeftWall - RightWall - Feature - - - BattleMapPartType::AutoConvert - None - Fire - Smoke - - - Projectile::Type - Beam - Missile - - - UFOIncursion::PrimaryMission - Infiltration - Subversion - Attack - Overspawn - - - SceneryTileType::TileType - General - Road - PeopleTubeJunction - PeopleTube - CityWall - - - SceneryTileType::RoadType - StraightBend - Junction - Terminal - - - SceneryTileType::WalkMode - None - Into - Onto - - - FacilityType::Capacity - Nothing - Quarters - Stores - Medical - Training - Psi - Repair - Chemistry - Physics - Workshop - Aliens - - - ResearchDependency::Type - Any - All - - - UfopaediaEntry::Data - Nothing - Organisation - Vehicle - VehicleEquipment - Equipment - Facility - Building - - - AEquipmentType::Type - Armor - Weapon - Grenade - Ammo - MotionScanner - StructureProbe - VortexAnalyzer - MultiTracker - MindShield - MindBender - AlienDetector - DisruptorShield - Teleporter - CloakingField - DimensionForceField - MediKit - Brainsucker - Popper - Spawner - Loot - - - AgentType::Role - Soldier - Physicist - BioChemist - Engineer - - - AgentType::Gender - Male - Female - - - EquipmentSlotType - General - ArmorBody - ArmorLegs - ArmorHelmet - ArmorLeftHand - ArmorRightHand - LeftHand - RightHand - VehicleGeneral - VehicleWeapon - VehicleEngine - - - TriggerType - None - Timed - Contact - Proximity - Boomeroid - - - AlignmentX - Left - Right - Centre - - - AlignmentY - Top - Bottom - Centre - - - BodyPart - Body - Legs - Helmet - LeftArm - RightArm - - - BodyState - Standing - Flying - Kneeling - Prone - Jumping - Throwing - Downed - Dead - - - HandState - AtEase - Aiming - Firing - - - MovementState - None - Normal - Running - Strafing - Reverse - Brainsuck - - - AIType - None - Civilian - Loner - Group - PanicFreeze - PanicRun - Berserk - - - AIAction::Type - AttackWeaponTile - AttackWeaponUnit - AttackGrenade - AttackPsiPanic - AttackPsiStun - AttackPsiMC - AttackBrainsucker - AttackSuicide - - - AIMovement::Type - Stop - ChangeStance - Patrol - Advance - Pursue - GetInRange - TakeCover - Retreat - - - UnitAI::Type - LowMorale - Default - Behavior - Vanilla - Hardcore - - - TacticalAI::Type - Vanilla - - - Rank - Rookie - Squaddie - SquadLeader - Sergeant - Captain - Colonel - Commander - - - TrainingAssignment - None - Physical - Psi - - - MoraleState - Normal - PanicFreeze - PanicRun - Berserk - - - AIAction - type - targetUnit - item - weaponStatus - psiEnergySnapshot - preventOutOfTurnReThink - executed - - - AIMovement - type - targetLocation - movementMode - kneelingMode - executed - subordinate - - - AIDecision - action - movement - - - AIBlockUnit - aiList - ticksLastThink - ticksLastOutOfOrderThink - ticksUntilReThink - - - UnitAILowMorale - type - active - ticksActionAvailable - - - UnitAIDefault - type - active - ticksAutoTurnAvailable - ticksAutoTargetAvailable - attackerPosition - - - UnitAIBehavior - type - active - - - UnitAIVanilla - type - active - ticksLastThink - ticksUntilReThink - lastDecision - enemySpotted - enemySpottedPrevious - attackerPosition - lastSeenEnemyPosition - flagEnemySpotted - flagLastSeenPosition - flagLastAttackerPosition - - - UnitAIHardcore - type - active - - - AIBlockTactical - aiList - ticksLastThink - ticksUntilReThink - - - TacticalAIVanilla - type - - - BattleScanner - movementTicks - version - updateTicksAccumulated - lastPosition - holder - - - EconomyInfo - weekAvailable - basePrice - minStock - maxStock - currentPrice - currentStock - lastStock - - - GameScore - tacticalMissions - researchCompleted - alienIncidents - craftShotDownUFO - craftShotDownXCom - incursions - cityDamage - + + GameState + vehicle_types + organisations + facility_types + doodad_types + vehicle_equipment + vehicle_ammo + cities + ufo_growth_lists + ufo_mission_preference + ufo_incursions + base_layouts + player_bases + vehicles + ufopaedia + research + agents + agent_types + agent_body_types + agent_equipment_layouts + agent_generator + organisation_raid_rules + weekly_rating_rules + agent_salary + agent_fired_penalty + initial_agents + initial_facilities + initial_agent_equipment + initial_vehicles + initial_vehicle_equipment + initial_vehicle_ammo + initial_base_agent_equipment + initial_aliens + current_city + current_base + agentEquipmentTemplates + totalScore + weekScore + micronoidRainChance + objectIdCount + city_common_image_list + city_common_sample_list + battle_common_image_list + battle_common_sample_list + economy + player + aliens + civilian + government + rng + gameTime + gameTimeBeforeBattle + missionLocationBattleBuilding + eventFromBattleText + eventFromBattle + battle_maps + current_battle + hazard_types + damage_modifiers + damage_types + agent_equipment + equipment_sets_by_score + equipment_sets_by_level + building_functions + messages + baseIndex + difficulty + fundingTerminated + firstDetection + nextInvasion + + + BattleMapTileset + map_part_types + + + EventMessage + time + text + location + + + GameTime + ticks + + + ResearchState + topics + labs + + + AgentGenerator + first_names + second_names + + + AgentBodyType + allowed_body_states + allowed_movement_states + allowed_fire_movement_states + allowed_facing + large + maxHeight + height + muzzleZPosition + size + voxelMaps + + + AgentEquipmentLayout + slots + + + AgentType + id + name + role + possible_genders + gender_chance + portraits + min_stats + max_stats + bodyType + shadow_pack + appearance_count + image_packs + animation_packs + armor + damage_modifier + inventory + built_in_weapon_left + built_in_weapon_right + equipment_layout + improvementPercentagePhysical + improvementPercentagePsi + canTrain + playable + availableAtTheGameStart + allowsDirectControl + aiType + immuneToFatalWounds + infiltrationSpeed + growthChance + growthOptions + growthInfiltration + detectionWeight + movementPercent + spreadHazardDamageType + spreadHazardMinPower + spreadHazardMaxPower + spreadHazardTTLDivizor + inventoryBackground + displayRank + missionObjective + liveSpeciesItem + deadSpeciesItem + score + walkSfx + crySfx + damageSfx + fatalWoundSfx + dieSfx + + + EquipmentLayoutSlot + type + align_x + align_y + bounds + + + AEquipment + type + payloadType + lastLoadedAmmoType + equippedPosition + equippedSlotType + ownerAgent + ownerOrganisation + ownerUnit + ammo + armor + primed + activated + triggerDelay + triggerRange + triggerType + recharge_ticks_accumulated + readyToFire + weapon_fire_ticks_remaining + aimingMode + inUse + battleScanner + + + EquipmentSet + id + min_score + max_score + weapons + grenades + equipment + + + EquipmentTemplate + equipment + + + EquipmentTemplate::EquipmentTemplateEntry + pos + type + payloadType + + + EquipmentSet::WeaponData + weapon + clip + clip_amount + + + EquipmentSet::GrenadeData + grenade + grenade_amount + + + EquipmentSet::EquipmentData + equipment + + + Agent + type + name + portrait + appearance + gender + initial_stats + current_stats + modified_stats + overEncumbred + rank + trainingPhysicalTicksAccumulated + trainingPsiTicksAccumulated + trainingAssignment + recentlyHired + recentlyTransferred + recentlyFought + healingProgress + owner + city + homeBuilding + currentBuilding + currentVehicle + position + goalPosition + lab_assigned + assigned_to_lab + unit + isBrainsucker + missions + teleportTicksAccumulated + equipment + destroyAfterBattle + hiredOn + killCount + missionCount + + + AgentPortrait + photo + icon + + + AgentStats + health + accuracy + reactions + speed + time_units + stamina + bravery + strength + morale + psi_energy + psi_attack + psi_defence + physics_skill + biochem_skill + engineering_skill + + + ResearchTopic + name + order + description + man_hours + type + required_lab_size + dependencies + ufopaedia_entry + man_hours_progress + current_lab + score + started + cost + item_type + itemId + hidden + picture + + + ProjectDependencies + research + items + + + ItemDependency + agentItemsRequired + vehicleItemsRequired + agentItemsConsumed + vehicleItemsConsumed + + + UfopaediaCategory + title + description + background + entries + + + GameEventType + UfoSpotted + UfoCrashed + UfoRecoveryUnmanned + VehicleLightDamage + VehicleModerateDamage + VehicleHeavyDamage + VehicleEscaping + VehicleNoAmmo + VehicleLowFuel + VehicleNoFuel + VehicleRepaired + VehicleRearmed + VehicleRefuelled + VehicleNoEngine + VehicleRecovered + UnauthorizedVehicle + NotEnoughAmmo + NotEnoughFuel + VehicleWithAlienLootInBaseWithNoContainment + UfoRecoveryBegin + DefendTheBase + AgentRearmed + CargoArrived + TransferArrived + RecoveryArrived + CargoExpired + CargoSeized + MissionCompletedBase + BaseDestroyed + AgentDiedCity + VehicleDestroyed + AlienSpotted + CommenceInvestigation + BuildingAttacked + CargoExpiresSoon + MissionCompletedBuildingRaid + MissionCompletedBuildingNormal + OrganisationAttackBuilding + OrganisationRaidBuilding + OrganisationStormBuilding + OrganisationTreatySigned + AlienTakeover + OrganisationRequestBribe + OrganisationRequestAlliance + AgentArrived + AgentUnableToReach + HostileSpotted + AgentBrainsucked + AgentDiedBattle + HostileDied + UnknownDied + AgentCriticallyWounded + AgentBadlyInjured + AgentInjured + AgentUnderFire + AgentUnconscious + AgentLeftCombat + AgentFrozen + AgentBerserk + AgentPanicked + AgentPanicOver + AgentPsiAttacked + AgentPsiProbed + AgentPsiControlled + AgentPsiOver + NoLOF + NewTurn + ResearchCompleted + ManufactureCompleted + ManufactureHalted + FacilityCompleted + ZoomView + MarketUpdate + WeeklyReport + EnterAlienDimension + LeaveAlienDimension + MissionStarted + BuildingDisabled + MissionCompletedVehicle + MissionCompletedBuildingAlien + None + + + Cargo::Type + Agent + Bio + VehicleAmmo + VehicleEquipment + + + Cargo + type + id + count + divisor + space + cost + originalOwner + destination + expirationDate + warned + suppressEvents + + + Vehicle + type + owner + name + attackMode + altitude + missions + equipment + city + position + goalPosition + goalWaypoints + loot + velocity + facing + goalFacing + angularVelocity + ticksToTurn + banking + direction + shadowDirection + health + shield + shieldRecharge + stunTicksRemaining + falling + crashed + sliding + fuelSpentTicks + cloakTicksAccumulated + teleportTicksAccumulated + ticksAutoActionAvailable + homeBuilding + currentBuilding + currentAgents + cargo + carriedVehicle + carriedByVehicle + betweenDimensions + + + VEquipment + type + equippedPosition + weaponState + owner + ammo + reloadTime + + + VehicleMission + type + targetLocation + allowTeleporter + reRouteAttempts + pickNearest + patrolHome + pickedNearest + targetBuilding + targetVehicle + targets + timeToSnooze + missionCounter + currentPlannedPath + subvert + attackCrashed + cancelled + + + AgentMission + type + allowTeleporter + allowTaxi + targetBuilding + timeToSnooze + currentPlannedPath + cancelled + + + BattleUnitMission + type + targetLocation + facingDelta + giveWayAttemptsRemaining + demandGiveWay + blockedByMovingUnit + costPaidUpFront + allowSkipNodes + targetFacing + requireGoal + freeTurn + item + velocityXY + velocityZ + timeToSnooze + allowContinue + targetBodyState + currentPlannedPath + allowRunningAway + jumpTarget + jumped + targetUnit + brainsuckTicksAccumulated + brainsuckSoundsPlayed + cancelled + + + Base + corridors + facilities + inventoryBioEquipment + inventoryAgentEquipment + inventoryVehicleEquipment + inventoryVehicleAmmo + name + building + + + Facility + type + pos + buildTime + lab + + + Lab + size + type + current_project + assigned_agents + ticks_since_last_progress + manufacture_goal + manufacture_done + manufacture_man_hours_invested + + + BattleMapPartType + type + autoConvert + sprite + strategySprite + voxelMapLOF + voxelMapLOS + imageOffset + constitution + explosion_power + explosion_depletion_rate + explosion_type + fire_resist + fire_burn_time + block + size + damaged_map_part + alternative_map_part + animation_frames + transparent + sfxIndex + door + blocksLOS + floor + gravlift + movement_cost + height + floating + provides_support + supportedByAbove + supportedByDirections + supportedByTypes + vanillaSupportedById + independent_structure + exit + missionObjective + reinforcementSpawner + + + BattleScore + combatRating + casualtyPenalty + friendlyFire + liveAlienCaptured + equipmentCaptured + equipmentLost + + + Battle + size + battle_map + losBlocks + visibleTiles + visibleBlocks + visibleUnits + visibleEnemies + blockAvailable + blockCenterPos + linkAvailable + linkCost + blockNeedsUpdate + linkNeedsUpdate + tilesChangedForVision + mission_type + mission_location_building + mission_location_vehicle + mode + score + missionEndTimer + buildingCanBeDisabled + buildingDisabled + playerWon + locationOwner + loserHasRetreated + winnerHasRetreated + player_craft + map_parts + units + scanners + items + doodads + projectiles + doors + explosions + hazards + participants + leadershipBonus + aiBlock + currentPlayer + currentActiveOrganisation + hotseat + currentTurn + ticksWithoutAction + ticksWithoutSeenAction + lastSeenActionLocation + turnEndAllowed + interruptQueue + interruptUnits + skirmish + relationshipsBeforeSkirmish + scoreBeforeSkirmish + reinforcementsInterval + ticksUntilNextReinforcement + battleViewZLevel + battleViewScreenCenter + battleViewGroupMove + battleViewSquadIndex + battleViewSelectedUnits + + + BattleMap + id + chunk_size + max_battle_size + allow_entrance + allow_exit + entrance_level_min + entrance_level_max + exit_level_min + exit_level_max + exitsX + exitsY + reinforcementsInterval + tilesets + destroyed_ground_tile + rubble_left_wall + rubble_right_wall + rubble_feature + exit_grounds + sectors + + + BattleMapSector + size + occurrence_min + occurrence_max + sectorTilesName + tiles + spawnLocations + + + BattleMapSectorTiles + losBlocks + loot_locations + guardianLocations + initial_grounds + initial_left_walls + initial_right_walls + initial_features + + + BattleMapSector::LineOfSightBlock + start + end + ai_patrol_priority + ai_target_priority + spawn_type + spawn_priority + also_allow_civilians + low_priority + spawn_large_units + spawn_walking_units + + + BattleUnitImagePack + image_offset + images + + + BattleCommonImageList + strategyImages + loadingImage + focusArrows + burningDoodad + + + CityCommonImageList + strategyImages + projectileVoxelMap + portalVoxelMap + agentIsometric + agentStrategic + portalStrategic + + + BattleCommonSampleList + gravlift + door + brainsuckerHatch + brainsuckerSuck + teleport + burn + genericHitSounds + walkSounds + objectDropSounds + throwSounds + psiFailSounds + psiSuccessSounds + + + CityCommonSampleList + teleport + vehicleExplosion + sceneryExplosion + shieldHit + dimensionShiftIn + dimensionShiftOut + alertSounds + + + BattleUnitAnimationPack + standart_animations + hand_state_animations + body_state_animations + hasAlternativeFiringAnimations + useFiringAnimationForPsi + alt_fire_animations + + + BattleUnitAnimationPack::AnimationEntry + frames + is_overlay + frame_count + units_per_100_frames + + + BattleUnitAnimationPack::AnimationEntry::Frame + unit_image_parts + unit_image_draw_order + + + BattleUnitAnimationPack::AnimationEntry::Frame::InfoBlock + index + offset + + + BattleUnit + id + agent + owner + squadNumber + squadPosition + weaponStatus + targetingMode + targetTile + timesTargetMIA + targetUnit + focusUnit + focusedByUnits + ticksUntillNextTargetCheck + psiStatus + psiTarget + psiItem + ticksAccumulatedToNextPsiCheck + psiAttackers + brainSucker + experiencePoints + combatRating + fatalWounds + healingBodyPart + isHealing + woundTicksAccumulated + regenTicksAccumulated + stunDamage + enzymeDebuffTicksAccumulated + fireDebuffTicksAccumulated + enzymeDebuffIntensity + fireDebuffTicksRemaining + moraleState + moraleStateTicksRemaining + moraleTicksAccumulated + initialTU + reserveShotCost + cloakTicksAccumulated + ticksUntillNextCry + behavior_mode + fire_aiming_mode + fire_permission_mode + movement_mode + kneeling_mode + reserve_shot_mode + reserve_kneel_mode + body_animation_ticks_remaining + body_animation_ticks_total + body_animation_ticks_static + current_body_state + target_body_state + hand_animation_ticks_remaining + residual_aiming_ticks_remaining + firing_animation_ticks_remaining + current_hand_state + target_hand_state + movement_ticks_passed + movement_sounds_played + current_movement_state + turning_animation_ticks_remaining + missions + position + goalPosition + atGoal + usingLift + facing + goalFacing + flyingSpeedModifier + retreated + destroyed + falling + launched + launchGoal + bounced + collisionIgnoredTicks + velocity + tilesMoved + giveWayRequestData + displayedItem + visibleUnits + visibleEnemies + aiList + + + BattleItem + item + position + velocity + bounced + falling + ownerInvulnerableTicks + collisionIgnoredTicks + ticksUntilCollapse + owner + + + BattleHazard + position + damageType + hazardType + power + lifetime + age + frame + ticksUntilVisible + frameChangeTicksAccumulated + nextUpdateTicksAccumulated + ownerOrganisation + ownerUnit + + + BattleExplosion + position + power + ticksUntilExpansion + locationsToExpand + locationsVisited + damageInTheEnd + locationsToDamage + damageType + depletionRate + ownerUnit + ownerOrganisation + affectedUnits + + + BattleMapPart + type + alternative_type + position + ticksUntilCollapse + burnTicksAccumulated + damaged + falling + fallingSpeed + destroyed + providesHardSupport + door + supportedItems + supportedParts + owner + + + BattleDoor + id + operational + right + open + animationFrameCount + openTicksRemaining + animationTicksRemaining + doorSound + + + City + id + size + tile_types + initial_tiles + buildings + scenery + doodads + portals + projectiles + initial_portals + tileToRoadSegmentMap + roadSegments + civilianSalary + researchUnlock + cityViewScreenCenter + cityViewPageIndex + cityViewSelectedOwnedVehicles + cityViewSelectedOtherVehicles + cityViewSelectedSoldiers + cityViewSelectedBios + cityViewSelectedPhysics + cityViewSelectedEngineers + cityViewSelectedOrganisation + cityViewOrgButtonIndex + + + RoadSegment + connections + tilePosition + intact + tileIntact + middle + length + + + Projectile + type + position + velocity + turnRate + age + damage + delay_ticks_remaining + depletionRate + lifetime + firerVehicle + firerUnit + trackedVehicle + trackedUnit + targetPosition + previousPosition + stunTicks + splitIntoTypesCity + splitIntoTypesBattle + spritePositions + tail_length + projectile_sprites + sprite_distance + manualFire + voxelMapLof + voxelMapLos + impactSfx + doodadType + damageType + ownerInvulnerableTicks + velocityScale + + + Doodad + position + imageOffset + temporary + age + lifetime + sprite + type + voxelMap + + + DoodadType + lifetime + repeatable + imageOffset + frames + + + Scenery + type + initialPosition + currentPosition + ticksUntilCollapse + supportedParts + supportedBy + damaged + falling + fallingSpeed + destroyed + supportHardness + + + BuildingFunction + name + baseCost + baseIncome + workersPerTile + agentSpawnType + investmentValue + prestige + infiltrationSpeed + detectionWeight + ufopaedia_entry + + + Building + name + city + function + owner + bounds + base_layout + base + battle_map + preset_crew + current_crew + crewQuarters + currentVehicles + currentAgents + cargo + isPurchesable + purchasePrice + maintenanceCosts + maximumWorkforce + currentWorkforce + incomePerCapita + currentWage + investment + prestige + ticksDetectionTimeOut + ticksDetectionAttemptAccumulated + detected + timeOfLastAttackEvent + researchUnlock + accessTopic + victory + pendingInvestigatorCount + + + UFOIncursion + primaryMission + primaryList + escortList + attackList + priority + + + UFOGrowth + week + vehicleTypeList + + + UFOMissionPreference + week + missionList + + + BaseLayout + baseCorridors + baseLift + + + SceneryTileType + tile_type + road_type + walk_mode + connection + hill + tube + sprite + strategySprite + overlaySprite + voxelMap + damagedTile + imageOffset + isLandingPad + minimap_colour + constitution + value + mass + strength + height + overlayHeight + basement + isBuildingPart + commonProperty + isHill + + + VAmmoType + id + name + weight + ammo_id + manufacturer + store_space + + + DamageModifier + + + HazardType + doodadType + sound + minLifetime + maxLifetime + fire + + + DamageType::BlockType + Physical + Psionic + Gas + Fire + + + DamageType::EffectType + None + Stun + Smoke + Fire + Enzyme + Brainsucker + Psionic + + + DamageType + name + icon_sprite + ignore_shield + non_violent + modifiers + explosive + explosionDoodad + blockType + effectType + hazardType + explosionSounds + + + AEquipmentType + type + id + name + weight + held_image_pack + dropped_sprite + dropped_offset + dropped_shadow_sprite + shadow_offset + equipscreen_sprite + equipscreen_size + manufacturer + store_space + armor + score + research_dependency + two_handed + bioStorage + bioRemains + launcher + artifact + body_sprite + damage_modifier + body_part + body_image_pack + provides_flight + weapon_types + max_ammo + burst + recharge + rechargeTB + speed + projectile_sprites + damage + accuracy + fire_delay + projectile_delay + tail_size + guided + turn_rate + range + ttl + explosion_graphic + shield_graphic + fire_sfx + impact_sfx + damage_type + trigger_type + explosion_depletion_rate + spawnList + + + VEquipmentType + type + id + name + weight + max_ammo + burst + ammo_type + equipscreen_sprite + equipscreen_size + manufacturer + store_space + users + speed + projectile_sprites + damage + accuracy + fire_delay + tail_size + guided + turn_rate + range + ttl + firing_arc_1 + firing_arc_2 + point_defence + fire_sfx + impact_sfx + explosion_graphic + icon + stunTicks + splitIntoTypes + power + top_speed + accuracy_modifier + cargo_space + passengers + alien_space + missile_jamming + shielding + cloaking + teleporting + dimensionShifting + scoreRequirement + research_dependency + + + DoodadFrame + image + time + + + FacilityType + name + fixed + buildCost + buildTime + weeklyCost + capacityType + capacityAmount + size + sprite + dependency + ufopaedia_entry + sector + + + OrganisationRaid::Type + None + Attack + Raid + Storm + UnauthorizedVehicle + Treaty + + + OrganisationRaid + nextRaidTimer + attack_vehicle_types + neutral_low_manpower + neutral_normal + neutral_high_manpower + military_low_manpower + military_normal + military_high_manpower + + + Organisation::MissionPattern::Target + Owned + OwnedOrOther + Other + ArriveFromSpace + DepartToSpace + + + Organisation::Relation + Allied + Friendly + Neutral + Unfriendly + Hostile + + + Organisation::RecurringMission + time + pattern + + + Organisation::RaidMission + time + type + target + + + Organisation::MissionPattern + minIntervalRepeat + maxIntervalRepeat + minAmount + maxAmount + allowedTypes + target + relation + + + Organisation + id + name + balance + income + rebuildingRate + infiltrationValue + infiltrationHistory + infiltrationSpeed + ticksTakeOverAttemptAccumulated + takenOver + militarized + initiatesDiplomacy + providesTransportationServices + tech_level + average_guards + guard_types_reinforcements + guard_types_human + guard_types_alien + loot + icon + current_relations + long_term_relations + ufopaedia_entry + raid_missions + recurring_missions + vehiclePark + hirableAgentTypes + + + VehicleType + numCreated + type + name + manufacturer + image_offset + acceleration + top_speed + health + crash_health + weight + armour + passengers + aggressiveness + score + icon + battle_map + crew_downed + crew_deposit + equipment_screen + equip_icon_big + equip_icon_small + mapIconType + directional_sprites + shadow_offset + directional_shadow_sprites + animation_sprites + crashed_sprite + height + size + voxelMaps + voxelMapsLOS + equipment_layout_slots + initial_equipment_list + ufopaedia_entry + provideFreightAgent + provideFreightCargo + provideFreightBio + canRescueCrashed + canEnterDimensionGate + researchUnlock + + + UfopaediaEntry + title + description + background + data_id + data_type + dependency + + + ResearchDependency + type + topics + + + BattleUnitAnimationPack::AnimationKey + itemWieldMode + handState + movementState + bodyState + + + BattleUnitAnimationPack::ChangingHandAnimationKey + itemWieldMode + currentHand + targetHand + movementState + bodyState + + + BattleUnitAnimationPack::ChangingBodyStateAnimationKey + itemWieldMode + handState + movementState + currentBodyState + targetBodyState + + + BattleUnitAnimationPack::AltFireAnimationKey + itemWieldMode + handState + angle + movementState + bodyState + + + VEquipmentType::User + Ground + Air + Ammo + + + VehicleType::Type + Flying + UFO + Road + ATV + + + VehicleType::Direction + N + NNE + NE + NEE + E + SEE + SE + SSE + S + SSW + SW + SWW + W + NWW + NW + NNW + + + VehicleType::Banking + Flat + Left + Right + Ascending + Descending + + + VehicleType::ArmourDirection + Top + Bottom + Front + Rear + Left + Right + + + VehicleType::MapIconType + Arrow + SmallCircle + LargeCircle + + + ResearchTopic::Type + BioChem + Physics + Engineering + + + ResearchTopic::LabSize + Small + Large + + + ResearchTopic::ItemType + VehicleEquipment + AgentEquipment + VehicleEquipmentAmmo + Craft + + + Vehicle::AttackMode + Aggressive + Standard + Defensive + Evasive + + + Vehicle::Altitude + Highest + High + Standard + Low + + + VehicleMission::MissionType + GotoLocation + GotoBuilding + FollowVehicle + RecoverVehicle + AttackVehicle + AttackBuilding + RestartNextMission + Snooze + TakeOff + Land + Crash + Patrol + GotoPortal + InfiltrateSubvert + OfferService + Teleport + SelfDestruct + DepartToSpace + ArriveFromDimensionGate + InvestigateBuilding + + + AgentMission::MissionType + GotoBuilding + AwaitPickup + RestartNextMission + Snooze + Teleport + + + BattleUnitMission::Type + GotoLocation + Snooze + RestartNextMission + AcquireTU + ChangeBodyState + ThrowItem + DropItem + Turn + ReachGoal + Teleport + Brainsuck + Jump + + + VEquipment::WeaponState + Ready + Disabled + Reloading + OutOfAmmo + + + Battle::MissionType + AlienExtermination + RaidAliens + BaseDefense + RaidHumans + UfoRecovery + + + MapDirection + North + East + South + West + Up + Down + + + Battle::Mode + RealTime + TurnBased + + + SpawnType + Player + Enemy + Civilian + + + ItemWieldMode + None + OneHanded + TwoHanded + + + BattleUnitAnimationPack::AnimationEntry::Frame::UnitImagePart + Shadow + Body + Legs + Helmet + LeftArm + RightArm + Weapon + + + BattleUnit::BehaviorMode + Aggressive + Normal + Evasive + + + WeaponAimingMode + Aimed + Snap + Auto + + + ReserveShotMode + Aimed + Snap + Auto + None + + + BattleUnit::FirePermissionMode + AtWill + CeaseFire + + + MovementMode + Prone + Walking + Running + + + KneelingMode + None + Kneeling + + + WeaponStatus + NotFiring + FiringLeftHand + FiringRightHand + FiringBothHands + + + PsiStatus + NotEngaged + Control + Panic + Stun + Probe + + + BattleUnit::TargetingMode + NoTarget + Unit + TileCenter + TileGround + + + BattleUnitType + SmallWalker + SmallFlyer + LargeWalker + LargeFlyer + + + Organisation::LootPriority + A + B + C + + + BattleMapPartType::Type + Ground + LeftWall + RightWall + Feature + + + BattleMapPartType::AutoConvert + None + Fire + Smoke + + + Projectile::Type + Beam + Missile + + + UFOIncursion::PrimaryMission + Infiltration + Subversion + Attack + Overspawn + + + SceneryTileType::TileType + General + Road + PeopleTubeJunction + PeopleTube + CityWall + + + SceneryTileType::RoadType + StraightBend + Junction + Terminal + + + SceneryTileType::WalkMode + None + Into + Onto + + + FacilityType::Capacity + Nothing + Quarters + Stores + Medical + Training + Psi + Repair + Chemistry + Physics + Workshop + Aliens + + + ResearchDependency::Type + Any + All + + + UfopaediaEntry::Data + Nothing + Organisation + Vehicle + VehicleEquipment + Equipment + Facility + Building + + + AEquipmentType::Type + Armor + Weapon + Grenade + Ammo + MotionScanner + StructureProbe + VortexAnalyzer + MultiTracker + MindShield + MindBender + AlienDetector + DisruptorShield + Teleporter + CloakingField + DimensionForceField + MediKit + Brainsucker + Popper + Spawner + Loot + + + AgentType::Role + Soldier + Physicist + BioChemist + Engineer + + + AgentType::Gender + Male + Female + + + EquipmentSlotType + General + ArmorBody + ArmorLegs + ArmorHelmet + ArmorLeftHand + ArmorRightHand + LeftHand + RightHand + VehicleGeneral + VehicleWeapon + VehicleEngine + + + TriggerType + None + Timed + Contact + Proximity + Boomeroid + + + AlignmentX + Left + Right + Centre + + + AlignmentY + Top + Bottom + Centre + + + BodyPart + Body + Legs + Helmet + LeftArm + RightArm + + + BodyState + Standing + Flying + Kneeling + Prone + Jumping + Throwing + Downed + Dead + + + HandState + AtEase + Aiming + Firing + + + MovementState + None + Normal + Running + Strafing + Reverse + Brainsuck + + + AIType + None + Civilian + Loner + Group + PanicFreeze + PanicRun + Berserk + + + AIAction::Type + AttackWeaponTile + AttackWeaponUnit + AttackGrenade + AttackPsiPanic + AttackPsiStun + AttackPsiMC + AttackBrainsucker + AttackSuicide + + + AIMovement::Type + Stop + ChangeStance + Patrol + Advance + Pursue + GetInRange + TakeCover + Retreat + + + UnitAI::Type + LowMorale + Default + Behavior + Vanilla + Hardcore + + + TacticalAI::Type + Vanilla + + + Rank + Rookie + Squaddie + SquadLeader + Sergeant + Captain + Colonel + Commander + + + TrainingAssignment + None + Physical + Psi + + + MoraleState + Normal + PanicFreeze + PanicRun + Berserk + + + AIAction + type + targetUnit + item + weaponStatus + psiEnergySnapshot + preventOutOfTurnReThink + executed + + + AIMovement + type + targetLocation + movementMode + kneelingMode + executed + subordinate + + + AIDecision + action + movement + + + AIBlockUnit + aiList + ticksLastThink + ticksLastOutOfOrderThink + ticksUntilReThink + + + UnitAILowMorale + type + active + ticksActionAvailable + + + UnitAIDefault + type + active + ticksAutoTurnAvailable + ticksAutoTargetAvailable + attackerPosition + + + UnitAIBehavior + type + active + + + UnitAIVanilla + type + active + ticksLastThink + ticksUntilReThink + lastDecision + enemySpotted + enemySpottedPrevious + attackerPosition + lastSeenEnemyPosition + flagEnemySpotted + flagLastSeenPosition + flagLastAttackerPosition + + + UnitAIHardcore + type + active + + + AIBlockTactical + aiList + ticksLastThink + ticksUntilReThink + + + TacticalAIVanilla + type + + + BattleScanner + movementTicks + version + updateTicksAccumulated + lastPosition + holder + + + EconomyInfo + weekAvailable + basePrice + minStock + maxStock + currentPrice + currentStock + lastStock + + + GameScore + tacticalMissions + researchCompleted + alienIncidents + craftShotDownUFO + craftShotDownXCom + incursions + cityDamage + diff --git a/game/state/message.cpp b/game/state/message.cpp index da181d92f..5d540bf81 100644 --- a/game/state/message.cpp +++ b/game/state/message.cpp @@ -1,8 +1,5 @@ #include "game/state/message.h" #include "battle/battle.h" -#include "battle/battleunit.h" -#include "city/building.h" -#include "city/vehicle.h" #include "game/state/gamestate.h" namespace OpenApoc diff --git a/game/state/rules/aequipmenttype.cpp b/game/state/rules/aequipmenttype.cpp index 7549adfd9..f97b284e2 100644 --- a/game/state/rules/aequipmenttype.cpp +++ b/game/state/rules/aequipmenttype.cpp @@ -2,7 +2,6 @@ #include "game/state/gamestate.h" #include "game/state/shared/aequipment.h" #include "game/state/tilemap/tilemap.h" -#include namespace OpenApoc { @@ -127,6 +126,26 @@ bool AEquipmentType::canBeUsed(GameState &state, StateRef owner) c return true; } +bool AEquipmentType::isResearched() const +{ + StateRef equipmentTopic; + + for (auto &dependencyTopic : research_dependency.topics) + { + if (dependencyTopic->name == name) + { + equipmentTopic = dependencyTopic; + break; + } + } + + // If no research topic is found with same name as type, then we use "satisfied()" instead + // This is not the prefered method since it will consider not only specific topic but all + // children topics as well + + return equipmentTopic ? equipmentTopic->isComplete() : research_dependency.satisfied(); +} + float AEquipmentType::getRoundsPerSecond() const { return (float)TICKS_PER_SECOND / (float)fire_delay; diff --git a/game/state/rules/aequipmenttype.h b/game/state/rules/aequipmenttype.h index 8d2357536..889fd9157 100644 --- a/game/state/rules/aequipmenttype.h +++ b/game/state/rules/aequipmenttype.h @@ -176,6 +176,17 @@ class AEquipmentType : public StateObject std::map, int> spawnList; bool canBeUsed(GameState &state, StateRef user) const; + + /// + /// Get if type is researched. + /// + /// By default it will search through dependency topics via topic name. + /// If no topic with same name is found, then method will call "research_dependency.satisfied()" + /// instead, which unfortunately considers not only topic research, but children research status + /// as well. + /// + /// Returns if type is already researched. + bool isResearched() const; }; class EquipmentSet : public StateObject diff --git a/game/state/rules/agenttype.cpp b/game/state/rules/agenttype.cpp index a36e8a1cf..8a4822734 100644 --- a/game/state/rules/agenttype.cpp +++ b/game/state/rules/agenttype.cpp @@ -1,23 +1,10 @@ #include "game/state/rules/agenttype.h" #include "framework/framework.h" #include "game/state/battle/ai/aitype.h" -#include "game/state/battle/battleunit.h" #include "game/state/city/agentmission.h" -#include "game/state/city/base.h" -#include "game/state/city/building.h" -#include "game/state/city/city.h" -#include "game/state/city/facility.h" -#include "game/state/city/scenery.h" #include "game/state/city/vehicle.h" -#include "game/state/gameevent.h" #include "game/state/gamestate.h" -#include "game/state/rules/aequipmenttype.h" -#include "game/state/rules/city/scenerytiletype.h" -#include "game/state/shared/aequipment.h" -#include "game/state/shared/organisation.h" -#include "game/state/tilemap/tileobject_scenery.h" #include "library/strings_format.h" -#include namespace OpenApoc { diff --git a/game/state/rules/battle/battlecommonsamplelist.h b/game/state/rules/battle/battlecommonsamplelist.h index b0f0952f3..81058ba80 100644 --- a/game/state/rules/battle/battlecommonsamplelist.h +++ b/game/state/rules/battle/battlecommonsamplelist.h @@ -1,9 +1,7 @@ #pragma once -#include "game/state/stateobject.h" #include "library/sp.h" #include -#include #include namespace OpenApoc diff --git a/game/state/rules/battle/battlemap.cpp b/game/state/rules/battle/battlemap.cpp index e3de440b3..6c1ebbd09 100644 --- a/game/state/rules/battle/battlemap.cpp +++ b/game/state/rules/battle/battlemap.cpp @@ -2,7 +2,6 @@ #include "framework/configfile.h" #include "game/state/battle/battle.h" #include "game/state/battle/battledoor.h" -#include "game/state/battle/battleitem.h" #include "game/state/battle/battlemappart.h" #include "game/state/battle/battlescanner.h" #include "game/state/battle/battleunit.h" @@ -11,7 +10,6 @@ #include "game/state/city/facility.h" #include "game/state/city/vehicle.h" #include "game/state/gamestate.h" -#include "game/state/rules/aequipmenttype.h" #include "game/state/rules/battle/battlecommonsamplelist.h" #include "game/state/rules/battle/battlemapparttype.h" #include "game/state/rules/battle/battlemaptileset.h" @@ -155,7 +153,7 @@ sp BattleMap::createBattle(GameState &state, StateRef oppo return target_craft->type->battle_map->createBattle( state, target_craft->owner, opponent, player_agents, player_craft, - Battle::MissionType::UfoRecovery, target_craft.id); + Battle::MissionType::UfoRecovery, nullptr, target_craft); } // Create building battle @@ -384,7 +382,7 @@ sp BattleMap::createBattle(GameState &state, StateRef oppo } return map->createBattle(state, building->owner, opponent, player_agents, player_craft, - missionType, building.id); + missionType, building, nullptr); } namespace @@ -927,9 +925,9 @@ bool BattleMap::generateMap(std::vector> &sec_map, Vec3 } bool BattleMap::generateBase(std::vector> &sec_map, Vec3 &size, - GameState &state, UString mission_location_id) + GameState &state, StateRef mission_location) { - StateRef building = {&state, mission_location_id}; + StateRef building = mission_location; StateRef base; for (auto &b : state.player_bases) { @@ -941,7 +939,7 @@ bool BattleMap::generateBase(std::vector> &sec_map, Vec3, sp> GameState &state, StateRef propertyOwner, StateRef target_organisation, std::list> &agents, StateRef player_craft, Battle::MissionType mission_type, - UString mission_location_id) + StateRef mission_location_building, + StateRef mission_location_vehicle) { auto b = mksp(); @@ -1003,7 +1002,8 @@ BattleMap::fillMap(std::vector, sp> b->size = {chunk_size.x * size.x, chunk_size.y * size.y, chunk_size.z * size.z}; b->battle_map = {&state, id}; b->mission_type = mission_type; - b->mission_location_id = mission_location_id; + b->mission_location_building = mission_location_building; + b->mission_location_vehicle = mission_location_vehicle; b->player_craft = player_craft; b->loadResources(state); b->reinforcementsInterval = reinforcementsInterval * TICKS_PER_SECOND; @@ -1466,7 +1466,8 @@ sp BattleMap::createBattle(GameState &state, StateRef prop StateRef target_organisation, std::list> &agents, StateRef player_craft, Battle::MissionType mission_type, - UString mission_location_id) + StateRef mission_location_building, + StateRef mission_location_vehicle) { std::vector> sec_map; Vec3 size; @@ -1484,7 +1485,7 @@ sp BattleMap::createBattle(GameState &state, StateRef prop genSizeEnum = (GenerationSize)genSize; if (mission_type == Battle::MissionType::BaseDefense) { - generateBase(sec_map, size, state, mission_location_id); + generateBase(sec_map, size, state, mission_location_building); } else { @@ -1496,7 +1497,8 @@ sp BattleMap::createBattle(GameState &state, StateRef prop // Step 02: Fill map with map parts b = fillMap(doors, spawnCivilians, sec_map, size, state, propertyOwner, target_organisation, - agents, player_craft, mission_type, mission_location_id); + agents, player_craft, mission_type, mission_location_building, + mission_location_vehicle); // Step 03: Ensure enough space exists if (!b->initialMapCheck(state, agents)) diff --git a/game/state/rules/battle/battlemap.h b/game/state/rules/battle/battlemap.h index 3eb19a485..5fd7554a8 100644 --- a/game/state/rules/battle/battlemap.h +++ b/game/state/rules/battle/battlemap.h @@ -83,20 +83,23 @@ class BattleMap : public StateObject sp createBattle(GameState &state, StateRef propertyOwner, StateRef opponent, std::list> &agents, StateRef player_craft, Battle::MissionType mission_type, - UString mission_location_id); + StateRef mission_location_building, + StateRef mission_location_vehicle); bool generateMap(std::vector> &sec_map, Vec3 &size, GameState &state, GenerationSize genSize); bool generateBase(std::vector> &sec_map, Vec3 &size, GameState &state, - UString mission_location_id); + StateRef mission_location); sp fillMap(std::vector, sp>>> &doors, bool &spawnCivilians, std::vector> sec_map, Vec3 size, GameState &state, StateRef propertyOwner, StateRef target_organisation, std::list> &agents, StateRef player_craft, - Battle::MissionType mission_type, UString mission_location_id); + Battle::MissionType mission_type, + StateRef mission_location_building, + StateRef mission_location_vehicle); void linkDoors(sp b, std::vector, sp>>> doors, diff --git a/game/state/rules/battle/battlemapsector.cpp b/game/state/rules/battle/battlemapsector.cpp index 4365f9c9a..62f586c41 100644 --- a/game/state/rules/battle/battlemapsector.cpp +++ b/game/state/rules/battle/battlemapsector.cpp @@ -1,7 +1,6 @@ #include "game/state/rules/battle/battlemapsector.h" #include "framework/framework.h" #include "game/state/gamestate.h" -#include "game/state/rules/battle/battlemap.h" namespace OpenApoc { diff --git a/game/state/rules/battle/damage.h b/game/state/rules/battle/damage.h index 2ce29f86d..bfeb85a1c 100644 --- a/game/state/rules/battle/damage.h +++ b/game/state/rules/battle/damage.h @@ -2,6 +2,7 @@ #include "game/state/stateobject.h" #include "library/strings.h" +#include #include namespace OpenApoc diff --git a/game/state/rules/city/citycommonimagelist.h b/game/state/rules/city/citycommonimagelist.h index 47ad8391b..822e8bb4b 100644 --- a/game/state/rules/city/citycommonimagelist.h +++ b/game/state/rules/city/citycommonimagelist.h @@ -1,6 +1,5 @@ #pragma once -#include "game/state/stateobject.h" #include "library/sp.h" #include diff --git a/game/state/rules/city/citycommonsamplelist.h b/game/state/rules/city/citycommonsamplelist.h index ac7fdba22..e4b83e96c 100644 --- a/game/state/rules/city/citycommonsamplelist.h +++ b/game/state/rules/city/citycommonsamplelist.h @@ -1,10 +1,7 @@ #pragma once -#include "game/state/stateobject.h" #include "library/sp.h" #include -#include -#include namespace OpenApoc { diff --git a/game/state/rules/city/facilitytype.h b/game/state/rules/city/facilitytype.h index cad1ec881..92d29640a 100644 --- a/game/state/rules/city/facilitytype.h +++ b/game/state/rules/city/facilitytype.h @@ -4,7 +4,6 @@ #include "game/state/stateobject.h" #include "library/sp.h" #include "library/strings.h" -#include namespace OpenApoc { diff --git a/game/state/rules/city/organisationraid.h b/game/state/rules/city/organisationraid.h index 512679030..080ebdf9b 100644 --- a/game/state/rules/city/organisationraid.h +++ b/game/state/rules/city/organisationraid.h @@ -2,7 +2,6 @@ #include "game/state/stateobject.h" #include -#include namespace OpenApoc { diff --git a/game/state/rules/city/ufomissionpreference.h b/game/state/rules/city/ufomissionpreference.h index 26339fe6c..8be9409f8 100644 --- a/game/state/rules/city/ufomissionpreference.h +++ b/game/state/rules/city/ufomissionpreference.h @@ -2,8 +2,7 @@ #include "game/state/rules/city/ufoincursion.h" #include "game/state/stateobject.h" -#include "library/strings.h" -#include +#include namespace OpenApoc { diff --git a/game/state/rules/city/ufopaedia.h b/game/state/rules/city/ufopaedia.h index 3e9c494e7..c6261e165 100644 --- a/game/state/rules/city/ufopaedia.h +++ b/game/state/rules/city/ufopaedia.h @@ -4,7 +4,6 @@ #include "game/state/stateobject.h" #include "library/sp.h" #include "library/strings.h" -#include namespace OpenApoc { diff --git a/game/state/rules/city/vehicletype.h b/game/state/rules/city/vehicletype.h index dffd1b755..090b77a30 100644 --- a/game/state/rules/city/vehicletype.h +++ b/game/state/rules/city/vehicletype.h @@ -4,7 +4,6 @@ #include "game/state/rules/city/vequipmenttype.h" #include "game/state/shared/equipment.h" #include "game/state/stateobject.h" -#include "library/rect.h" #include "library/sp.h" #include "library/strings.h" #include "library/vec.h" @@ -279,16 +278,23 @@ class VehicleType : public StateObject sp>::value, "iterator must return sp"); - // FIXME: This is somehow modulated by weight? + int weight = this->getWeight(first, last); float speed = this->top_speed; + bool hasEngine = false; while (first != last) { if ((*first)->type == EquipmentSlotType::VehicleEngine) { speed += (*first)->top_speed; + hasEngine = true; } ++first; } + // Light vehicles have +4 speed + if (weight < 350 && hasEngine) + { + speed += 4; + } return speed; } diff --git a/game/state/rules/city/vequipmenttype.h b/game/state/rules/city/vequipmenttype.h index 72a52941c..3cd1a9ff3 100644 --- a/game/state/rules/city/vequipmenttype.h +++ b/game/state/rules/city/vequipmenttype.h @@ -7,7 +7,6 @@ #include "library/strings.h" #include "library/vec.h" #include -#include #include namespace OpenApoc diff --git a/game/state/rules/supportedmappart.cpp b/game/state/rules/supportedmappart.cpp index 152ee2f95..ad981fec5 100644 --- a/game/state/rules/supportedmappart.cpp +++ b/game/state/rules/supportedmappart.cpp @@ -1,8 +1,6 @@ #include "game/state/rules/supportedmappart.h" #include "game/state/battle/battlemappart.h" -#include "game/state/city/scenery.h" #include "game/state/tilemap/tileobject_battlemappart.h" -#include "game/state/tilemap/tileobject_scenery.h" // Uncomment to have verbose map part link up output // #define MAP_PART_LINK_DEBUG_OUTPUT diff --git a/game/state/rules/supportedmappart.h b/game/state/rules/supportedmappart.h index bf3bca6aa..724f426d0 100644 --- a/game/state/rules/supportedmappart.h +++ b/game/state/rules/supportedmappart.h @@ -1,7 +1,6 @@ #pragma once #include "game/state/stateobject.h" -#include "library/colour.h" #include "library/sp.h" #include "library/vec.h" #include diff --git a/game/state/savemanager.cpp b/game/state/savemanager.cpp index 3e203a92a..8470cb6bb 100644 --- a/game/state/savemanager.cpp +++ b/game/state/savemanager.cpp @@ -172,9 +172,8 @@ bool SaveManager::findFreePath(UString &path, const UString &name) const std::optional SaveManager::getSaveGameIfExists(const UString &name) const { const auto saveList = getSaveList(); - const auto it = - std::find_if(saveList.begin(), saveList.end(), - [&name](const SaveMetadata &obj) { return obj.getName() == name; }); + const auto it = std::find_if(saveList.begin(), saveList.end(), [&name](const SaveMetadata &obj) + { return obj.getName() == name; }); if (it != saveList.end()) { @@ -301,8 +300,7 @@ std::vector SaveManager::getSaveList() const LogError("Error while enumerating directory: \"%s\"", er.what()); } - sort(saveList.begin(), saveList.end(), - [](const SaveMetadata &lhs, const SaveMetadata &rhs) + sort(saveList.begin(), saveList.end(), [](const SaveMetadata &lhs, const SaveMetadata &rhs) { return lhs.getCreationDate() > rhs.getCreationDate(); }); return saveList; diff --git a/game/state/shared/aequipment.cpp b/game/state/shared/aequipment.cpp index d85869304..fe5b0b269 100644 --- a/game/state/shared/aequipment.cpp +++ b/game/state/shared/aequipment.cpp @@ -367,8 +367,8 @@ void AEquipment::loadAmmo(GameState &state, sp ammoItem) // Store the loaded ammo type for autoreload lastLoadedAmmoType = ammoItem->type; - // If this has ammo then swap - if (payloadType) + // If this has ammo, swap if clip can't be refilled + if (payloadType && (ammoItem->ammo + ammo > payloadType->max_ammo)) { auto ejectedType = payloadType; auto ejectedAmmo = ammo; @@ -380,7 +380,8 @@ void AEquipment::loadAmmo(GameState &state, sp ammoItem) else { payloadType = ammoItem->type; - ammo = ammoItem->ammo; + // Fill partial clip + ammo = ammoItem->ammo + ammo; // Spend ammo ammoItem->ammo = 0; // Remove item from battle/agent diff --git a/game/state/shared/agent.cpp b/game/state/shared/agent.cpp index c16f258d7..9a3e25856 100644 --- a/game/state/shared/agent.cpp +++ b/game/state/shared/agent.cpp @@ -1,22 +1,18 @@ #include "game/state/shared/agent.h" #include "framework/configfile.h" #include "framework/framework.h" -#include "game/state/battle/ai/aitype.h" #include "game/state/battle/battleunit.h" #include "game/state/city/agentmission.h" #include "game/state/city/base.h" #include "game/state/city/building.h" #include "game/state/city/city.h" #include "game/state/city/facility.h" -#include "game/state/city/scenery.h" #include "game/state/city/vehicle.h" #include "game/state/gameevent.h" #include "game/state/gamestate.h" #include "game/state/rules/aequipmenttype.h" -#include "game/state/rules/city/scenerytiletype.h" #include "game/state/shared/aequipment.h" #include "game/state/shared/organisation.h" -#include "game/state/tilemap/tileobject_scenery.h" #include "library/strings_format.h" #include diff --git a/game/state/shared/agent.h b/game/state/shared/agent.h index 616b0f005..ed747c00e 100644 --- a/game/state/shared/agent.h +++ b/game/state/shared/agent.h @@ -1,6 +1,5 @@ #pragma once -#include "framework/image.h" #include "game/state/gametime.h" #include "game/state/rules/aequipmenttype.h" #include "game/state/rules/agenttype.h" diff --git a/game/state/shared/doodad.cpp b/game/state/shared/doodad.cpp index b669e4a55..2509ff1f4 100644 --- a/game/state/shared/doodad.cpp +++ b/game/state/shared/doodad.cpp @@ -6,7 +6,6 @@ #include "game/state/rules/doodadtype.h" #include "game/state/tilemap/tilemap.h" #include "game/state/tilemap/tileobject_doodad.h" -#include namespace OpenApoc { diff --git a/game/state/shared/organisation.h b/game/state/shared/organisation.h index 76f55319a..a3276764e 100644 --- a/game/state/shared/organisation.h +++ b/game/state/shared/organisation.h @@ -124,6 +124,7 @@ class Organisation : public StateObject bool militarized = false; bool initiatesDiplomacy = false; bool providesTransportationServices = false; + bool infiltrationSelected = false; sp icon; diff --git a/game/state/shared/projectile.cpp b/game/state/shared/projectile.cpp index a27ed36dd..d74744b1c 100644 --- a/game/state/shared/projectile.cpp +++ b/game/state/shared/projectile.cpp @@ -10,9 +10,7 @@ #include "game/state/tilemap/tileobject_battleunit.h" #include "game/state/tilemap/tileobject_projectile.h" #include "game/state/tilemap/tileobject_vehicle.h" -#include #include -#include #include namespace OpenApoc diff --git a/game/state/shared/projectile.h b/game/state/shared/projectile.h index d97fefda3..c6a5c29d9 100644 --- a/game/state/shared/projectile.h +++ b/game/state/shared/projectile.h @@ -7,10 +7,8 @@ #include "game/state/gametime.h" #include "game/state/stateobject.h" #include "library/sp.h" -#include "library/strings.h" #include "library/vec.h" #include -#include // Based on the fact that retribution (tr = 10) turns 90 degrees (PI/2) per second #define PROJECTILE_TURN_PER_TICK ((float)(M_PI / 2.0f) / 10.0f / TICKS_PER_SECOND) diff --git a/game/state/stateobject.h b/game/state/stateobject.h index 5be947caa..73a8f7cda 100644 --- a/game/state/stateobject.h +++ b/game/state/stateobject.h @@ -4,7 +4,6 @@ #include "library/sp.h" #include "library/strings.h" #include "library/strings_format.h" -#include #include namespace OpenApoc @@ -41,7 +40,7 @@ template class StateObject return getPrefix() + Strings::fromU64(id); } - virtual void destroy(){}; + virtual void destroy() {}; // StateObjects are not copy-able StateObject(const StateObject &) = delete; // Move is fine diff --git a/game/state/tilemap/collision.cpp b/game/state/tilemap/collision.cpp index 6aae0690b..b30e37ab0 100644 --- a/game/state/tilemap/collision.cpp +++ b/game/state/tilemap/collision.cpp @@ -15,7 +15,6 @@ #include #include #include -#include namespace OpenApoc { diff --git a/game/state/tilemap/pathfinding.cpp b/game/state/tilemap/pathfinding.cpp index 4d89cdaba..79249be05 100644 --- a/game/state/tilemap/pathfinding.cpp +++ b/game/state/tilemap/pathfinding.cpp @@ -6,11 +6,8 @@ #include "game/state/city/vehicle.h" #include "game/state/city/vehiclemission.h" #include "game/state/gamestate.h" -#include "game/state/rules/battle/battlemap.h" #include "game/state/rules/city/scenerytiletype.h" #include "game/state/tilemap/tilemap.h" -#include "game/state/tilemap/tileobject_battleunit.h" -#include "game/state/tilemap/tileobject_vehicle.h" #include "limits.h" #include #include @@ -2030,7 +2027,7 @@ void City::fillRoadSegmentMap(GameState &state [[maybe_unused]]) } } } // End of loop for current pass - } // End of first loop + } // End of first loop for (int i = 0; i < roadSegments.size(); i++) { diff --git a/game/state/tilemap/tile.cpp b/game/state/tilemap/tile.cpp index 84b241d77..28f3ca01e 100644 --- a/game/state/tilemap/tile.cpp +++ b/game/state/tilemap/tile.cpp @@ -6,26 +6,16 @@ #include "game/state/battle/battlemappart.h" #include "game/state/battle/battleunit.h" #include "game/state/city/scenery.h" -#include "game/state/city/vehicle.h" -#include "game/state/rules/battle/battleunitimagepack.h" #include "game/state/rules/city/scenerytiletype.h" -#include "game/state/shared/doodad.h" -#include "game/state/shared/projectile.h" -#include "game/state/tilemap/collision.h" #include "game/state/tilemap/tilemap.h" #include "game/state/tilemap/tileobject_battlehazard.h" #include "game/state/tilemap/tileobject_battleitem.h" #include "game/state/tilemap/tileobject_battlemappart.h" #include "game/state/tilemap/tileobject_battleunit.h" -#include "game/state/tilemap/tileobject_doodad.h" -#include "game/state/tilemap/tileobject_projectile.h" #include "game/state/tilemap/tileobject_scenery.h" -#include "game/state/tilemap/tileobject_shadow.h" -#include "game/state/tilemap/tileobject_vehicle.h" #include "library/sp.h" #include #include -#include namespace OpenApoc { diff --git a/game/state/tilemap/tile.h b/game/state/tilemap/tile.h index 61364cbb4..d032d31e3 100644 --- a/game/state/tilemap/tile.h +++ b/game/state/tilemap/tile.h @@ -1,12 +1,9 @@ #pragma once #include "framework/logger.h" -#include "game/state/gametime.h" -#include "game/state/stateobject.h" -#include "library/colour.h" #include "library/rect.h" #include "library/sp.h" -#include +#include #include #include diff --git a/game/state/tilemap/tilemap.cpp b/game/state/tilemap/tilemap.cpp index 2c43c2f3d..5ff45c6ea 100644 --- a/game/state/tilemap/tilemap.cpp +++ b/game/state/tilemap/tilemap.cpp @@ -24,7 +24,6 @@ #include "library/sp.h" #include #include -#include namespace OpenApoc { diff --git a/game/state/tilemap/tilemap.h b/game/state/tilemap/tilemap.h index 5880afbbf..37927aae7 100644 --- a/game/state/tilemap/tilemap.h +++ b/game/state/tilemap/tilemap.h @@ -5,9 +5,9 @@ #include "game/state/stateobject.h" #include "game/state/tilemap/tile.h" #include "game/state/tilemap/tileobject.h" -#include "library/colour.h" #include "library/rect.h" #include "library/sp.h" +#include #include #include #include @@ -85,6 +85,7 @@ class TileMap std::vector> layerMap; public: + const static int MAX_ITERATION_LIMIT_DIRECT_FOR_BATTLE = 1000; const bool isTileInBounds(int x, int y, int z) const { if (x < 0 || x >= size.x) diff --git a/game/state/tilemap/tileobject_battleunit.h b/game/state/tilemap/tileobject_battleunit.h index fed9d60a4..f879f5875 100644 --- a/game/state/tilemap/tileobject_battleunit.h +++ b/game/state/tilemap/tileobject_battleunit.h @@ -3,6 +3,8 @@ #include "game/state/tilemap/tileobject.h" #include "library/sp.h" #include "library/vec.h" + +#include #include namespace OpenApoc diff --git a/game/state/tilemap/tileobject_vehicle.h b/game/state/tilemap/tileobject_vehicle.h index c25004b9e..f5c78202c 100644 --- a/game/state/tilemap/tileobject_vehicle.h +++ b/game/state/tilemap/tileobject_vehicle.h @@ -3,7 +3,6 @@ #include "game/state/tilemap/tileobject.h" #include "library/sp.h" #include "library/vec.h" -#include namespace OpenApoc { diff --git a/game/ui/CMakeLists.txt b/game/ui/CMakeLists.txt index 1e2270278..6e0d3b312 100644 --- a/game/ui/CMakeLists.txt +++ b/game/ui/CMakeLists.txt @@ -1,9 +1,6 @@ # project name, and type PROJECT(OpenApoc_GameUI CXX C) -# check cmake version -CMAKE_MINIMUM_REQUIRED(VERSION 3.9) - set(THREADS_PREFER_PTHREAD_FLAG ON) find_package (Threads REQUIRED) @@ -166,3 +163,7 @@ target_link_libraries(OpenApoc_GameUI PUBLIC OpenApoc_Forms) # version.h is used in the main menu, and that's generated in the bin dir target_include_directories(OpenApoc_GameUI PRIVATE ${CMAKE_BINARY_DIR}) + +if (USE_PCH) + target_precompile_headers(OpenApoc_GameUI PUBLIC gameui_pch.h) +endif() \ No newline at end of file diff --git a/game/ui/base/aliencontainmentscreen.cpp b/game/ui/base/aliencontainmentscreen.cpp index e02bea118..57a098ac2 100644 --- a/game/ui/base/aliencontainmentscreen.cpp +++ b/game/ui/base/aliencontainmentscreen.cpp @@ -4,12 +4,9 @@ #include "forms/graphicbutton.h" #include "forms/label.h" #include "forms/radiobutton.h" -#include "forms/scrollbar.h" #include "forms/ui.h" #include "framework/data.h" -#include "framework/event.h" #include "framework/framework.h" -#include "framework/logger.h" #include "framework/renderer.h" #include "game/state/city/base.h" #include "game/state/city/building.h" diff --git a/game/ui/base/basescreen.cpp b/game/ui/base/basescreen.cpp index 558b774b9..b59bc0e4b 100644 --- a/game/ui/base/basescreen.cpp +++ b/game/ui/base/basescreen.cpp @@ -90,22 +90,19 @@ void BaseScreen::begin() graphic->Name = "FACILITY_BUILD_TILE"; facilities->addItem(graphic); } + facilities->update(); form->findControlTyped("BUTTON_OK") ->addCallback(FormEventType::ButtonClick, [](Event *) { fw().stageQueueCommand({StageCmd::Command::POP}); }); form->findControlTyped("BUTTON_BASE_BUYSELL") ->addCallback( - FormEventType::ButtonClick, - [this](Event *) { - fw().stageQueueCommand({StageCmd::Command::PUSH, mksp(state)}); - }); + FormEventType::ButtonClick, [this](Event *) + { fw().stageQueueCommand({StageCmd::Command::PUSH, mksp(state)}); }); form->findControlTyped("BUTTON_BASE_HIREFIRESTAFF") ->addCallback( - FormEventType::ButtonClick, - [this](Event *) { - fw().stageQueueCommand({StageCmd::Command::PUSH, mksp(state)}); - }); + FormEventType::ButtonClick, [this](Event *) + { fw().stageQueueCommand({StageCmd::Command::PUSH, mksp(state)}); }); form->findControlTyped("BUTTON_BASE_TRANSFER") ->addCallback( FormEventType::ButtonClick, @@ -130,7 +127,15 @@ void BaseScreen::begin() FormEventType::ButtonClick, [this](Event *) { - if (this->state->current_base->containmentEmpty(*state)) + if (!this->state->current_base->alienContainmentExists()) + { + fw().stageQueueCommand( + {StageCmd::Command::PUSH, + mksp(tr("Alien Containment"), + tr("Alien Containment does not exist at this base."), + MessageBox::ButtonOptions::Ok)}); + } + else if (this->state->current_base->alienContainmentIsEmpty(*state)) { fw().stageQueueCommand( {StageCmd::Command::PUSH, @@ -145,54 +150,54 @@ void BaseScreen::begin() } }); form->findControlTyped("BUTTON_BASE_EQUIPAGENT") - ->addCallback( - FormEventType::ButtonClick, - [this](Event *) - { - bool playerHasSoldiers = false; - for (auto &a : this->state->agents) - { - auto agent = a.second; - if (agent->owner == this->state->getPlayer() && - agent->type->role == AgentType::Role::Soldier) - { - playerHasSoldiers = true; - break; - } - } - if (playerHasSoldiers) - { - fw().stageQueueCommand({StageCmd::Command::PUSH, mksp(state)}); - } - }); + ->addCallback(FormEventType::ButtonClick, + [this](Event *) + { + bool playerHasSoldiers = false; + for (auto &a : this->state->agents) + { + auto agent = a.second; + if (agent->owner == this->state->getPlayer() && + agent->type->role == AgentType::Role::Soldier) + { + playerHasSoldiers = true; + break; + } + } + if (playerHasSoldiers) + { + fw().stageQueueCommand( + {StageCmd::Command::PUSH, mksp(state)}); + } + }); form->findControlTyped("BUTTON_BASE_EQUIPVEHICLE") - ->addCallback( - FormEventType::ButtonClick, - [this](Event *) - { - bool playerHasVehicles = false; - for (auto &v : this->state->vehicles) - { - auto vehicle = v.second; - if (vehicle->owner == this->state->getPlayer()) - { - playerHasVehicles = true; - break; - } - } - if (playerHasVehicles) - { - fw().stageQueueCommand({StageCmd::Command::PUSH, mksp(state)}); - } - }); + ->addCallback(FormEventType::ButtonClick, + [this](Event *) + { + bool playerHasVehicles = false; + for (auto &v : this->state->vehicles) + { + auto vehicle = v.second; + if (vehicle->owner == this->state->getPlayer()) + { + playerHasVehicles = true; + break; + } + } + if (playerHasVehicles) + { + fw().stageQueueCommand( + {StageCmd::Command::PUSH, mksp(state)}); + } + }); form->findControlTyped("BUTTON_BASE_RES_AND_MANUF") - ->addCallback( - FormEventType::ButtonClick, - [this](Event *) - { - // FIXME: If you don't have any facilities this button should do nothing - fw().stageQueueCommand({StageCmd::Command::PUSH, mksp(state)}); - }); + ->addCallback(FormEventType::ButtonClick, + [this](Event *) + { + // FIXME: If you don't have any facilities this button should do nothing + fw().stageQueueCommand( + {StageCmd::Command::PUSH, mksp(state)}); + }); // Base name edit form->findControlTyped("TEXT_BASE_NAME") ->addCallback(FormEventType::TextEditFinish, @@ -212,7 +217,11 @@ void BaseScreen::begin() void BaseScreen::pause() {} -void BaseScreen::resume() { textFunds->setText(state->getPlayerBalance()); } +void BaseScreen::resume() +{ + BaseStage::begin(); + textFunds->setText(state->getPlayerBalance()); +} void BaseScreen::finish() {} @@ -456,11 +465,11 @@ void BaseScreen::eventOccurred(Event *e) selText->setText(tr(dragFacility->name)); selGraphic->setImage(dragFacility->sprite); statsLabels[0]->setText(tr("Cost to build")); - statsValues[0]->setText(format("$%d", dragFacility->buildCost)); + statsValues[0]->setText(format("$%s", Strings::fromInteger(dragFacility->buildCost))); statsLabels[1]->setText(tr("Days to build")); statsValues[1]->setText(format("%d", dragFacility->buildTime)); statsLabels[2]->setText(tr("Maintenance cost")); - statsValues[2]->setText(format("$%d", dragFacility->weeklyCost)); + statsValues[2]->setText(format("$%s", Strings::fromInteger(dragFacility->weeklyCost))); } else if (selFacility != nullptr) { @@ -546,4 +555,4 @@ void BaseScreen::renderBase() } } -}; // namespace OpenApoc +}; // namespace OpenApoc \ No newline at end of file diff --git a/game/ui/base/basestage.cpp b/game/ui/base/basestage.cpp index 946ecb879..fd645b003 100644 --- a/game/ui/base/basestage.cpp +++ b/game/ui/base/basestage.cpp @@ -55,6 +55,7 @@ void BaseStage::begin() if (state->current_base == viewBase) { currentView = view; + prevBase = viewBase; } view->setData(viewBase); auto viewImage = drawMiniBase(*viewBase, viewHighlight, viewFacility); @@ -88,6 +89,7 @@ void BaseStage::begin() } textViewBase = form->findControlTyped