mirror of
https://github.com/CorsixTH/CorsixTH.git
synced 2025-07-23 04:13:01 +02:00
Merge branch 'master' into win_install_iso
This commit is contained in:
40
.github/ISSUE_TEMPLATE.md
vendored
40
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,40 +0,0 @@
|
||||
#### Describe the issue
|
||||
|
||||
#### Steps to Reproduce
|
||||
1. *Load save game attached to this ticket*
|
||||
|
||||
2.
|
||||
|
||||
3.
|
||||
|
||||
#### Save Game
|
||||
*It is often useful for us if you have a save game from shortly before the
|
||||
issue occurs that can be used to recreate the problem. Sometimes a save that
|
||||
shows the issue happening may be useful as well. As GitHub currently only
|
||||
supports uploading of images, you will have to upload your your savegames to
|
||||
an another source such as [Google Drive](https://drive.google.com),
|
||||
[Dropbox](https://dropbox.com), or
|
||||
[SkyDrive/OneDrive](https://onedrive.live.com). Add the link to the file to
|
||||
your issue and make the file(s) public, so we can access your gamelog or
|
||||
savegame. The most important thing is to not remove these files after you
|
||||
uploaded them!*
|
||||
|
||||
#### Expected Behavior
|
||||
|
||||
#### System Information
|
||||
**CorsixTH Version:** *e.g. 0.50 or 7d886f35ca*
|
||||
|
||||
**Operating System:** *e.g. Windows 10*
|
||||
|
||||
**Theme Hospital Version:** *CD, GOG.com, Origin, or Demo*
|
||||
|
||||
#### Gamelog.txt
|
||||
*For information about where to find gamelog.txt see:
|
||||
https://github.com/CorsixTH/CorsixTH/wiki/Frequently-Asked-Questions#where-do-i-find-the-configuration-or-the-gamelog-file*
|
||||
```
|
||||
Paste gamelog.txt output here
|
||||
```
|
||||
|
||||
### Additional Info
|
||||
*Paste any screen shots or other additional information that might help
|
||||
illustrate the problem.*
|
46
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
46
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[Bug] Give a summary of the problem"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
#### Describe the issue
|
||||
|
||||
|
||||
#### Steps to Reproduce
|
||||
1. *Load save game attached to this ticket*
|
||||
|
||||
2.
|
||||
|
||||
3.
|
||||
|
||||
#### Save Game
|
||||
<!-- It is often useful for us if you have a save game from shortly before the issue occurs that can be used to recreate the problem. Sometimes a save that shows the issue happening may be useful as well.
|
||||
You can upload your save by putting it in zip file, then copy/pasting it directly into this text area. You can also click the "Attach files by dragging & dropping, selecting or pasting them" text at the bottom to upload the zip file.
|
||||
Alternatively, you can use an external source such as Google Drive, Dropbox, or OneDrive and sharing the public link below to access your save game. The most important thing is to not remove these files after you upload them. -->
|
||||
|
||||
|
||||
#### Expected Behavior
|
||||
|
||||
|
||||
#### System Information
|
||||
**CorsixTH Version:** *e.g. 0.50 or 7d886f35ca*
|
||||
|
||||
**Operating System:** *e.g. Windows 10*
|
||||
|
||||
**Theme Hospital Version:** *CD, GOG.com, Origin, or Demo*
|
||||
|
||||
#### Gamelog.txt
|
||||
<!-- For information about where to find gamelog.txt see:
|
||||
https://github.com/CorsixTH/CorsixTH/wiki/Frequently-Asked-Questions#where-do-i-find-the-configuration-or-the-gamelog-file
|
||||
-->
|
||||
```
|
||||
Paste gamelog.txt output here
|
||||
```
|
||||
|
||||
### Additional Info
|
||||
*Paste any screen shots or other additional information that might help
|
||||
illustrate the problem.*
|
28
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: Give a feature/enhancement summary
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**What feature or enhancement would you like to add?**
|
||||
Include here a description of what feature/enhancement you would like.
|
||||
|
||||
**How would this feature benefit the gameplay of CorsixTH?**
|
||||
This will help developers decide if it is a worthwhile endeavour.
|
||||
|
||||
**Was the feature in the original game?**
|
||||
Yes/No
|
||||
|
||||
**What version of CorsixTH are you using?**
|
||||
<!-- e.g. 0.60 or build number
|
||||
You can check and download the latest stable release at https://github.com/CorsixTH/CorsixTH/releases
|
||||
-->
|
||||
|
||||
**Does this feature/enhancement relate to a current problem?**
|
||||
Give a summary of the problem referencing an issue number if one exists.
|
||||
|
||||
**Additional information**
|
||||
Add any other information or screenshots about the feature request here.
|
6
.github/pull_request_template.md
vendored
Normal file
6
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
*Fixes #*
|
||||
|
||||
**Describe what the proposed change does**
|
||||
-
|
||||
-
|
||||
-
|
151
.github/workflows/Linux.yml
vendored
Normal file
151
.github/workflows/Linux.yml
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
---
|
||||
name: Linux and Tests
|
||||
|
||||
on: # yamllint disable-line rule:trurhy
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'gh-pages'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
Linux:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- static_analysis: 0
|
||||
docs: 0
|
||||
cmake: 1
|
||||
lua: LuaJIT
|
||||
luac: luac5.1
|
||||
animview: and AnimView
|
||||
packages: libluajit-5.1-dev luajit libwxgtk3.0-gtk3-dev
|
||||
cmakejit: '-DBUILD_ANIMVIEWER=ON -DWITH_LUAJIT=ON -DLUA_LIBRARY=/usr/lib/x86_64-linux-gnu/libluajit-5.1.so'
|
||||
- static_analysis: 0
|
||||
docs: 0
|
||||
lua: Lua 5.1
|
||||
luac: luac5.1
|
||||
packages: liblua5.1-dev lua5.1
|
||||
- static_analysis: 1
|
||||
docs: 1
|
||||
lua: Lua 5.3
|
||||
luac: luac5.3
|
||||
packages: liblua5.3-dev lua5.3
|
||||
catch2: -DENABLE_UNIT_TESTS=ON
|
||||
name: Linux and Tests on ${{ matrix.lua }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2 # Keeps the git OAuth token after checkout
|
||||
- name: Install ${{ matrix.lua }} ${{ matrix.animview }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install ${{ matrix.packages }} luarocks
|
||||
# Required for LDocGen
|
||||
sudo luarocks install lpeg
|
||||
# Required for lua lint check
|
||||
sudo luarocks install luacheck
|
||||
# Required for lua unit tests
|
||||
sudo luarocks install busted
|
||||
- name: Install CorsixTH requirements
|
||||
run: |
|
||||
sudo apt-get install libsdl2-dev libsdl2-mixer-dev \
|
||||
libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev
|
||||
- name: Install static analysis requirements
|
||||
if: matrix.static_analysis
|
||||
run: |
|
||||
sudo apt-get install doxygen yamllint clang-tidy-9
|
||||
|
||||
sudo pip3 install -I codespell==2.0 cmakelint==1.4
|
||||
|
||||
# Build catch2
|
||||
git clone --quiet https://github.com/catchorg/Catch2 \
|
||||
--branch v2.13.2 --depth=1
|
||||
cd Catch2
|
||||
cmake . -Bbuild -DBUILD_TESTING=OFF
|
||||
cd build
|
||||
sudo make install
|
||||
cd ../../
|
||||
rm -rf Catch2
|
||||
|
||||
- name: Install CMake 3.5
|
||||
if: matrix.cmake
|
||||
run: |
|
||||
# Install CMake version 3.5, the oldest CorsixTH-supported version, which does not support Lua 5.4
|
||||
curl -L https://github.com/Kitware/CMake/releases/download/v3.5.0/cmake-3.5.0-Linux-i386.sh -o cmake.sh
|
||||
sudo bash cmake.sh --prefix=/usr/local/ --exclude-subdir --skip-license
|
||||
cmake --version
|
||||
- name: Create CorsixTH ${{ matrix.animview }} makefiles with ${{ matrix.lua }}
|
||||
run: |
|
||||
cmake . -G"Unix Makefiles" -Bbuild --debug-output \
|
||||
-DWITH_AUDIO=ON -DWITH_MOVIES=ON ${{ matrix.catch2 }} \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON ${{ matrix.cmakejit }}
|
||||
- name: Build CorsixTH ${{ matrix.animview }} with ${{ matrix.lua }}
|
||||
run: |
|
||||
cmake --build build/ -- VERBOSE=1
|
||||
sudo cmake --build build/ -- install
|
||||
- name: Run ${{ matrix.lua }} tests
|
||||
run: |
|
||||
# Validate lua files
|
||||
find CorsixTH -name '*.lua' -print0 | xargs -0 -I{} ${{ matrix.luac }} -p {}
|
||||
# Run lua lint check
|
||||
luacheck --quiet --codes --ranges CorsixTH
|
||||
# Run lua unit tests
|
||||
busted --verbose --directory=CorsixTH/Luatest
|
||||
- name: Run simple code tests
|
||||
if: matrix.static_analysis
|
||||
run: |
|
||||
# Check if there are trailing whitespaces.
|
||||
python3 scripts/check_trailing_whitespaces.py
|
||||
# Check for incorrectly encoded files.
|
||||
python3 scripts/check_language_files_not_BOM.py
|
||||
# Check if there are lua classes with invalid/improper declarations.
|
||||
python3 scripts/check_lua_classes.py
|
||||
# Check for tabs (should be spaces)
|
||||
grep -Ire '\t' CorsixTH/Lua --exclude-dir=languages
|
||||
# Run CPP Tests
|
||||
cd build/CorsixTH
|
||||
ctest --extra-verbose --build-config Release --output-on-failure
|
||||
cd ../..
|
||||
# Build and package LevelEdit
|
||||
ant -buildfile LevelEdit/build.xml dist
|
||||
# Run codespell
|
||||
codespell --enable-colors --quiet-level 2 --skip="languages,corsix-th.6" \
|
||||
-L sav,unexpect,persistance,defin,uint,inout,currenty,blong \
|
||||
AnimView CorsixTH CorsixTH/Lua/languages/english.lua LevelEdit libs
|
||||
# Cmake file linter
|
||||
cmakelint --filter=-linelength AnimView/CMakeLists.txt CMakeLists.txt CorsixTH/CMakeLists.txt \
|
||||
CorsixTH/CppTest/CMakeLists.txt CorsixTH/Src/CMakeLists.txt CorsixTH/SrcUnshared/CMakeLists.txt \
|
||||
libs/CMakeLists.txt libs/rnc/CMakeLists.txt \
|
||||
CMake/GenerateDoc.cmake CMake/PrecompiledDeps.cmake CMake/VcpkgDeps.cmake
|
||||
# Validate these build files
|
||||
yamllint --config-data "rules: {line-length: disable}" .github/workflows/Linux.yml
|
||||
shellcheck --shell sh scripts/macos_luarocks
|
||||
- name: Run clang code tests
|
||||
if: matrix.static_analysis
|
||||
run: |
|
||||
# Check cpp format
|
||||
clang-format-9 -i CorsixTH/Src/*.cpp CorsixTH/Src/*.h AnimView/*.cpp \
|
||||
AnimView/*.h libs/rnc/*.cpp libs/rnc/*.h CorsixTH/SrcUnshared/main.cpp
|
||||
git diff --exit-code
|
||||
# Clang-tidy linter
|
||||
clang-tidy-9 -p build --warnings-as-errors=\* \
|
||||
CorsixTH/Src/*.c CorsixTH/Src/*.cpp libs/rnc/*.cpp CorsixTH/SrcUnshared/main.cpp
|
||||
- name: Generate documentation
|
||||
if: matrix.docs
|
||||
run: |
|
||||
cmake --build build/ --target -- doc
|
||||
- name: Upload documentation
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'CorsixTH/CorsixTH' && matrix.docs
|
||||
run: |
|
||||
git config user.email "documentationbot@corsixth.com"
|
||||
git config user.name "Docs Bot"
|
||||
git fetch origin gh-pages
|
||||
git checkout --force gh-pages
|
||||
rsync --recursive build/doc/ .
|
||||
git add animview/ corsixth_engine/ corsixth_lua/ index.html leveledit/
|
||||
if ! git diff --cached --exit-code; then
|
||||
git commit --message "Documentation from $(git rev-parse --short master) [no CI]"
|
||||
git push origin gh-pages
|
||||
else
|
||||
echo "No change to documentation."
|
||||
fi
|
@@ -38,10 +38,11 @@ globals = { -- Globals
|
||||
"GrimReaper", "Hospital", "Humanoid", "HumanoidRawWalk",
|
||||
"Inspector", "LoadGame", "LoadGameFile", "Litter", "Machine",
|
||||
"Map", "MoviePlayer", "NoRealClass", "Object", "ParentClass",
|
||||
"Patient", "Plant", "Queue", "ResearchDepartment", "Room",
|
||||
"Patient", "Plant", "PlayerHospital", "Queue", "ResearchDepartment", "Room",
|
||||
"SaveGame", "SaveGameFile", "Staff", "StaffProfile", "StaffRoom",
|
||||
"Strings", "SwingDoor", "TheApp", "TreeControl", "Vip", "Window",
|
||||
"World", "Date", "Doctor", "Handyman", "Nurse", "Receptionist",
|
||||
"Cheats",
|
||||
|
||||
-- UI
|
||||
"UI", "UIAdviser", "UIAnnualReport", "UIAudio", "UIBankManager",
|
||||
@@ -109,7 +110,7 @@ end
|
||||
-- W113: accessing undefined variable XYZ
|
||||
-- W314: value assigned to field XYZ is unused
|
||||
for _, lng in ipairs({"brazilian_portuguese", "czech", "danish", "developer",
|
||||
"dutch", "english", "finnish", "french", "german", "hungarian",
|
||||
"dutch", "english", "finnish", "french", "german", "greek", "hungarian",
|
||||
"iberic_portuguese", "italian", "korean", "norwegian", "original_strings",
|
||||
"polish", "russian", "simplified_chinese", "spanish", "swedish",
|
||||
"traditional_chinese"}) do
|
||||
@@ -238,3 +239,5 @@ add_ignore("CorsixTH/Lua/window.lua", "542")
|
||||
add_ignore("CorsixTH/Lua/world.lua", "212")
|
||||
add_ignore("CorsixTH/Lua/world.lua", "542")
|
||||
add_ignore("CorsixTH/Luatest/non_strict.lua", "212")
|
||||
add_ignore("CorsixTH/Luatest/spec/utility_spec.lua", "121")
|
||||
add_ignore("CorsixTH/CorsixTH.lua", "143") -- luacheck is missing 5.4 debug functions
|
||||
|
88
.travis.yml
88
.travis.yml
@@ -1,88 +0,0 @@
|
||||
dist: bionic
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
packages:
|
||||
- libssl-dev
|
||||
- luarocks
|
||||
- doxygen
|
||||
- sshpass
|
||||
- libavcodec-dev
|
||||
- libavformat-dev
|
||||
- libavutil-dev
|
||||
- libswresample-dev
|
||||
- libswscale-dev
|
||||
- libsdl2-dev
|
||||
- libsdl2-mixer-dev
|
||||
- libfreetype6-dev
|
||||
- libwxgtk3.0-gtk3-dev
|
||||
- clang-tidy-8
|
||||
|
||||
|
||||
before_install:
|
||||
# Bionic does not have catch2 in its repo so clone and install locally
|
||||
- cd $HOME
|
||||
- git clone https://github.com/catchorg/Catch2.git --depth=1
|
||||
- cd Catch2
|
||||
- cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||
- cd build && sudo make install
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
|
||||
- luarocks --local install --server=http://luarocks.org luasec OPENSSL_DIR=/usr OPENSSL_LIBDIR=/usr/lib/x86_64-linux-gnu/
|
||||
# Required for LDocGen
|
||||
- luarocks --local install lpeg
|
||||
- luarocks --local install luafilesystem
|
||||
- luarocks --local install luasocket
|
||||
- luarocks --local install luacheck 0.19.1
|
||||
# Required for lua unit tests
|
||||
- luarocks --local install busted
|
||||
- mkdir $TRAVIS_BUILD_DIR/LevelEdit/bin
|
||||
install:
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
# Create unix makefiles
|
||||
- cmake -DLUA_PROGRAM_PATH=`which lua` -DENABLE_UNIT_TESTS=ON -DWITH_AUDIO=ON -DWITH_MOVIES=ON -DWITH_LUAJIT=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -Bfresh -H. --debug-output
|
||||
before_script:
|
||||
# Don't ask for confirmation when using scp
|
||||
- echo -e "Host armedpineapple.co.uk\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
||||
- echo -e "Host server2.armedpineapple.co.uk\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
||||
script:
|
||||
# Check if there are trailing whitespaces.
|
||||
- ${TRAVIS_BUILD_DIR}/scripts/check_trailing_whitespaces.py $TRAVIS_BUILD_DIR
|
||||
# Check for incorrectly encoded language files.
|
||||
- ${TRAVIS_BUILD_DIR}/scripts/check_language_files_not_BOM.py $TRAVIS_BUILD_DIR/CorsixTH/Lua/languages
|
||||
# Check if there are lua classes with invalid/improper declarations.
|
||||
- ${TRAVIS_BUILD_DIR}/scripts/check_lua_classes.py
|
||||
# Check cpp format
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- clang-format -i CorsixTH/Src/*{.cpp,.h} AnimView/*{.cpp,.h} libs/rnc/*{.cpp,.h} CorsixTH/SrcUnshared/main.cpp
|
||||
# clang-tidy check. The valist test is buggy in this environment (https://bugs.llvm.org/show_bug.cgi?id=41311)
|
||||
- clang-tidy-8 -p $TRAVIS_BUILD_DIR/fresh --warnings-as-errors=\*,-clang-analyzer-valist.Uninitialized CorsixTH/Src/*{.cpp,.c} libs/rnc/*.cpp CorsixTH/SrcUnshared/main.cpp
|
||||
- git diff --exit-code
|
||||
# Build CorsixTH
|
||||
- cd fresh
|
||||
- make VERBOSE=1
|
||||
# Validate lua files
|
||||
- find $TRAVIS_BUILD_DIR -path $TRAVIS_BUILD_DIR/CorsixTH/Lua/languages -prune -o -name '*.lua' -print0 | xargs -0 luac -p --
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- /home/travis/.luarocks/bin/luacheck -q .
|
||||
# Run lua unit tests
|
||||
- cd $TRAVIS_BUILD_DIR/CorsixTH/Luatest
|
||||
- eval `luarocks --local path`
|
||||
- LUA_PATH="../Lua/?.lua;$LUA_PATH" /home/travis/.luarocks/bin/busted
|
||||
|
||||
# Run CPP Tests
|
||||
- cd $TRAVIS_BUILD_DIR/fresh/CorsixTH
|
||||
- eval 'ctest -VV'
|
||||
|
||||
# Build LevelEdit
|
||||
- cd $TRAVIS_BUILD_DIR/LevelEdit && ant dist
|
||||
# Build documentation
|
||||
- cd ${TRAVIS_BUILD_DIR}/fresh && make doc
|
||||
after_success:
|
||||
# Upload new docs
|
||||
- if [ $TRAVIS_REPO_SLUG == "CorsixTH/CorsixTH" -a $TRAVIS_BRANCH == "master" ]; then sshpass -p "$SCP_PASS" scp -r -v -P12349 $TRAVIS_BUILD_DIR/fresh/doc/* cthbuilder@server2.armedpineapple.co.uk:/home/cthbuilder/docs/; fi;
|
||||
env:
|
||||
global:
|
||||
secure: "mPtzSeDJKVeUu6KHJEbmHa91O+QK2XM0advYdr+13yr83w3C7cGFFjWgqzirsFUHVqPgdtSJIkom0DIxX7JtRoBZmt/xon+zfLq+Q4aSkJoYezWBqp2gavS8o1kSjtW7XuIuq995yjWvn7nehyoTYkKNtz/EzX5ZIVZ/iX73iyo="
|
@@ -1,3 +1,9 @@
|
||||
# Sanity check
|
||||
if(CORSIX_TH_DONE_TOP_LEVEL_CMAKE)
|
||||
else()
|
||||
message(FATAL_ERROR "Please run CMake from the top-level directory instead of here.")
|
||||
endif()
|
||||
|
||||
# Project Declaration
|
||||
project(AnimView)
|
||||
|
||||
@@ -34,7 +40,7 @@ if(APPLE)
|
||||
)
|
||||
set(MACOSX_BUNDLE_ICON_FILE Icon.icns)
|
||||
|
||||
add_executable(
|
||||
add_executable(
|
||||
AnimView
|
||||
MACOSX_BUNDLE
|
||||
${animview_source_files}
|
||||
@@ -44,8 +50,8 @@ if(APPLE)
|
||||
set_target_properties(AnimView PROPERTIES LINK_FLAGS_MINSIZEREL "-dead_strip")
|
||||
set_target_properties(AnimView PROPERTIES XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks")
|
||||
else()
|
||||
add_executable(
|
||||
AnimView
|
||||
add_executable(
|
||||
AnimView
|
||||
WIN32 # This prevents the dos console showing up
|
||||
${animview_source_files}
|
||||
)
|
||||
@@ -70,7 +76,7 @@ if(wxWidgets_FOUND)
|
||||
target_link_libraries(AnimView ${wxWidgets_LIBRARIES})
|
||||
message(" wxWidgets found")
|
||||
else()
|
||||
message(FATAL_ERROR "error: wxWdigets library not found, it is required to build")
|
||||
message(FATAL_ERROR "error: wxWidgets library not found, it is required to build")
|
||||
message("Make sure the path is correctly defined or set the environment variable WXWIN to the correct location")
|
||||
endif()
|
||||
|
||||
@@ -81,14 +87,14 @@ endif()
|
||||
|
||||
if(APPLE)
|
||||
install(TARGETS AnimView BUNDLE DESTINATION .)
|
||||
|
||||
# Fix the OS X bundle to include required libraries (create a redistributable app)
|
||||
|
||||
# Fix the macOS bundle to include required libraries (create a redistributable app)
|
||||
install(CODE "
|
||||
INCLUDE(BundleUtilities)
|
||||
SET(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
FIXUP_BUNDLE(${CMAKE_INSTALL_PREFIX}/AnimView.app \"\" \"\")
|
||||
FIXUP_BUNDLE(\"${CMAKE_INSTALL_PREFIX}/AnimView.app\" \"\" \"\")
|
||||
")
|
||||
else()
|
||||
install(TARGETS AnimView RUNTIME DESTINATION AnimView)
|
||||
install(FILES LICENSE.txt DESTINATION AnimView )
|
||||
install(FILES ../LICENSE.txt DESTINATION AnimView)
|
||||
endif()
|
||||
|
@@ -27,6 +27,7 @@ SOFTWARE.
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/dcclient.h>
|
||||
#include <wx/dcmemory.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/dir.h>
|
||||
#include <wx/dirdlg.h>
|
||||
#include <wx/filename.h>
|
||||
@@ -54,7 +55,7 @@ BEGIN_EVENT_TABLE(frmMain, wxFrame)
|
||||
EVT_BUTTON(ID_SEARCH_LAYER_ID, frmMain::_onSearchLayerId)
|
||||
EVT_BUTTON(ID_SEARCH_FRAME, frmMain::_onSearchFrame)
|
||||
EVT_BUTTON(ID_SEARCH_SOUND, frmMain::_onSearchSoundIndex)
|
||||
EVT_LISTBOX(ID_SEARCH_RESULTS, frmMain::_onGotoSearchResult)
|
||||
EVT_LISTBOX(ID_SEARCH_RESULTS, frmMain::_onAnimChar)
|
||||
EVT_RADIOBUTTON(ID_GHOST_0, frmMain::_onGhostFileChange)
|
||||
EVT_RADIOBUTTON(ID_GHOST_1, frmMain::_onGhostFileChange)
|
||||
EVT_RADIOBUTTON(ID_GHOST_2, frmMain::_onGhostFileChange)
|
||||
@@ -66,25 +67,40 @@ BEGIN_EVENT_TABLE(frmMain, wxFrame)
|
||||
EVT_CHECKBOX(ID_DRAW_COORDINATES, frmMain::_onToggleDrawCoordinates)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
namespace {
|
||||
constexpr int make_id(int layer, int id) {
|
||||
return frmMain::ID_LAYER_CHECKS + (layer * 25) + id;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
frmMain::frmMain()
|
||||
: wxFrame(nullptr, wxID_ANY, L"Theme Hospital Animation Viewer") {
|
||||
wxSizer* pMainSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
wxSizer* pSidebarSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
#define def wxDefaultPosition, wxDefaultSize
|
||||
wxSizerFlags fillSizerFlags(0);
|
||||
fillSizerFlags.Expand().Border(wxALL, 0);
|
||||
|
||||
wxSizerFlags fillBorderSizerFlags(0);
|
||||
fillBorderSizerFlags.Expand().Border(wxALL, 1);
|
||||
|
||||
wxSizerFlags buttonSizerFlags(0);
|
||||
buttonSizerFlags.Align(wxALIGN_CENTER_VERTICAL).Border(wxALL, 1);
|
||||
|
||||
wxStaticBoxSizer* pThemeHospital =
|
||||
new wxStaticBoxSizer(wxHORIZONTAL, this, L"Theme Hospital");
|
||||
pThemeHospital->Add(new wxStaticText(this, wxID_ANY, L"Directory:"), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pThemeHospital->Add(
|
||||
m_txtTHPath = new wxTextCtrl(this, wxID_ANY, L"", def, wxTE_CENTRE), 1,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pThemeHospital->Add(new wxButton(this, ID_BROWSE, L"Browse..."), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pThemeHospital->Add(new wxButton(this, ID_LOAD, L"Load"), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pSidebarSizer->Add(pThemeHospital, 0, wxEXPAND | wxALL, 0);
|
||||
new wxStaticText(this, wxID_ANY, L"Directory:"),
|
||||
wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL).Border(wxALL, 1));
|
||||
pThemeHospital->Add(
|
||||
m_txtTHPath = new wxTextCtrl(this, wxID_ANY, L"", wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_CENTRE),
|
||||
wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL).Border(wxALL, 1));
|
||||
pThemeHospital->Add(new wxButton(this, ID_BROWSE, L"Browse..."),
|
||||
buttonSizerFlags);
|
||||
pThemeHospital->Add(new wxButton(this, ID_LOAD, L"Load"), buttonSizerFlags);
|
||||
pSidebarSizer->Add(pThemeHospital, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pPalette =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, L"Palette");
|
||||
@@ -95,280 +111,274 @@ frmMain::frmMain()
|
||||
pPaletteTop->Add(new wxRadioButton(this, ID_GHOST_3, L"Ghost 66"), 1);
|
||||
m_iGhostFile = 0;
|
||||
m_iGhostIndex = 0;
|
||||
pPalette->Add(pPaletteTop, 0, wxEXPAND | wxALL, 1);
|
||||
pPalette->Add(new wxSpinCtrl(this, wxID_ANY, wxEmptyString, def,
|
||||
wxSP_ARROW_KEYS | wxSP_WRAP, 0, 255),
|
||||
0, wxALIGN_CENTER | wxALL, 1);
|
||||
pSidebarSizer->Add(pPalette, 0, wxEXPAND | wxALL, 0);
|
||||
pPalette->Add(pPaletteTop, fillBorderSizerFlags);
|
||||
pPalette->Add(
|
||||
new wxSpinCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxDefaultSize, wxSP_ARROW_KEYS | wxSP_WRAP, 0, 255),
|
||||
wxSizerFlags(0).Center().Border(wxALL, 1));
|
||||
pSidebarSizer->Add(pPalette, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pAnimation =
|
||||
new wxStaticBoxSizer(wxHORIZONTAL, this, L"Animation");
|
||||
pAnimation->Add(new wxButton(this, ID_FIRST_ANIM, L"<<", def, wxBU_EXACTFIT),
|
||||
0, wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pAnimation->Add(new wxButton(this, ID_PREV_ANIM, L"<", def, wxBU_EXACTFIT), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pAnimation->Add(m_txtAnimIndex = new wxTextCtrl(this, ID_ANIM_INDEX, L"0",
|
||||
def, wxTE_CENTRE),
|
||||
1, wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pAnimation->Add(new wxStaticText(this, wxID_ANY, L"of"), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pAnimation->Add(m_txtAnimCount = new wxTextCtrl(this, wxID_ANY, L"?", def,
|
||||
wxTE_CENTRE | wxTE_READONLY),
|
||||
1, wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pAnimation->Add(new wxButton(this, ID_NEXT_ANIM, L">", def, wxBU_EXACTFIT), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pAnimation->Add(new wxButton(this, ID_LAST_ANIM, L">>", def, wxBU_EXACTFIT),
|
||||
0, wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pSidebarSizer->Add(pAnimation, 0, wxEXPAND | wxALL, 0);
|
||||
pAnimation->Add(new wxButton(this, ID_FIRST_ANIM, L"<<", wxDefaultPosition,
|
||||
wxDefaultSize, wxBU_EXACTFIT),
|
||||
buttonSizerFlags);
|
||||
pAnimation->Add(new wxButton(this, ID_PREV_ANIM, L"<", wxDefaultPosition,
|
||||
wxDefaultSize, wxBU_EXACTFIT),
|
||||
buttonSizerFlags);
|
||||
m_txtAnimIndex = new wxTextCtrl(this, ID_ANIM_INDEX, L"0", wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_CENTRE);
|
||||
pAnimation->Add(
|
||||
m_txtAnimIndex,
|
||||
wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL).Border(wxALL, 1));
|
||||
pAnimation->Add(
|
||||
new wxStaticText(this, wxID_ANY, L"of"),
|
||||
wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL).Border(wxALL, 1));
|
||||
m_txtAnimCount = new wxTextCtrl(this, wxID_ANY, L"?", wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_CENTRE | wxTE_READONLY);
|
||||
pAnimation->Add(
|
||||
m_txtAnimCount,
|
||||
wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL).Border(wxALL, 1));
|
||||
pAnimation->Add(new wxButton(this, ID_NEXT_ANIM, L">", wxDefaultPosition,
|
||||
wxDefaultSize, wxBU_EXACTFIT),
|
||||
buttonSizerFlags);
|
||||
pAnimation->Add(new wxButton(this, ID_LAST_ANIM, L">>", wxDefaultPosition,
|
||||
wxDefaultSize, wxBU_EXACTFIT),
|
||||
buttonSizerFlags);
|
||||
pSidebarSizer->Add(pAnimation, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pFrame = new wxStaticBoxSizer(wxHORIZONTAL, this, L"Frame");
|
||||
pFrame->Add(new wxButton(this, ID_PREV_FRAME, L"<", def, wxBU_EXACTFIT), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pFrame->Add(new wxButton(this, ID_PREV_FRAME, L"<", wxDefaultPosition,
|
||||
wxDefaultSize, wxBU_EXACTFIT),
|
||||
buttonSizerFlags);
|
||||
pFrame->Add(
|
||||
m_txtFrameIndex = new wxTextCtrl(this, wxID_ANY, L"0", def, wxTE_CENTRE),
|
||||
1, wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pFrame->Add(new wxStaticText(this, wxID_ANY, L"of", def, wxALIGN_CENTRE), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pFrame->Add(m_txtFrameCount = new wxTextCtrl(this, wxID_ANY, L"?", def,
|
||||
wxTE_CENTRE | wxTE_READONLY),
|
||||
1, wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pFrame->Add(new wxButton(this, ID_NEXT_FRAME, L">", def, wxBU_EXACTFIT), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
pFrame->Add(m_btnPlayPause = new wxButton(this, ID_PLAY_PAUSE, L"Pause"), 1,
|
||||
wxALIGN_CENTER_VERTICAL | wxALL, 1);
|
||||
m_txtFrameIndex = new wxTextCtrl(this, wxID_ANY, L"0", wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_CENTRE),
|
||||
wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL).Border(wxALL, 1));
|
||||
pFrame->Add(new wxStaticText(this, wxID_ANY, L"of", wxDefaultPosition,
|
||||
wxDefaultSize, wxALIGN_CENTRE),
|
||||
wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL).Border(wxALL, 1));
|
||||
m_txtFrameCount = new wxTextCtrl(this, wxID_ANY, L"?", wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_CENTRE | wxTE_READONLY);
|
||||
pFrame->Add(m_txtFrameCount,
|
||||
wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL).Border(wxALL, 1));
|
||||
pFrame->Add(new wxButton(this, ID_NEXT_FRAME, L">", wxDefaultPosition,
|
||||
wxDefaultSize, wxBU_EXACTFIT),
|
||||
buttonSizerFlags);
|
||||
m_btnPlayPause = new wxButton(this, ID_PLAY_PAUSE, L"Pause");
|
||||
pFrame->Add(m_btnPlayPause,
|
||||
wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL).Border(wxALL, 1));
|
||||
m_bPlayingAnimation = true;
|
||||
// m_bPlayingAnimation = false;
|
||||
pSidebarSizer->Add(pFrame, 0, wxEXPAND | wxALL, 0);
|
||||
pSidebarSizer->Add(pFrame, fillSizerFlags);
|
||||
|
||||
wxSizerFlags layerSizerFlags(0);
|
||||
layerSizerFlags.Align(wxALIGN_CENTER).Border(wxALL, 1);
|
||||
|
||||
#define ID(layer, id) (ID_LAYER_CHECKS + (layer)*25 + (id))
|
||||
wxStaticBoxSizer* pLayer0 =
|
||||
new wxStaticBoxSizer(wxHORIZONTAL, this, L"Layer 0 (Patient Head)");
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 0), L"0"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 2), L"2"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 4), L"4"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 6), L"6"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 8), L"8"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 10), L"10"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 12), L"12"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 14), L"14"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 16), L"16"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 18), L"18"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 20), L"20"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer0->Add(new wxCheckBox(this, ID(0, 22), L"22"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pSidebarSizer->Add(pLayer0, 0, wxEXPAND | wxALL, 0);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 0), L"0"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 2), L"2"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 4), L"4"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 6), L"6"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 8), L"8"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 10), L"10"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 12), L"12"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 14), L"14"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 16), L"16"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 18), L"18"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 20), L"20"), layerSizerFlags);
|
||||
pLayer0->Add(new wxCheckBox(this, make_id(0, 22), L"22"), layerSizerFlags);
|
||||
pSidebarSizer->Add(pLayer0, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pLayer1 =
|
||||
new wxStaticBoxSizer(wxHORIZONTAL, this, L"Layer 1 (Patient Clothes)");
|
||||
pLayer1->Add(new wxCheckBox(this, ID(1, 0), L"0"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer1->Add(new wxCheckBox(this, ID(1, 2), L"2 (A)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer1->Add(new wxCheckBox(this, ID(1, 4), L"4 (B)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer1->Add(new wxCheckBox(this, ID(1, 6), L"6 (C)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer1->Add(new wxCheckBox(this, ID(1, 8), L"8"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer1->Add(new wxCheckBox(this, ID(1, 10), L"10"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pSidebarSizer->Add(pLayer1, 0, wxEXPAND | wxALL, 0);
|
||||
pLayer1->Add(new wxCheckBox(this, make_id(1, 0), L"0"), layerSizerFlags);
|
||||
pLayer1->Add(new wxCheckBox(this, make_id(1, 2), L"2 (A)"), layerSizerFlags);
|
||||
pLayer1->Add(new wxCheckBox(this, make_id(1, 4), L"4 (B)"), layerSizerFlags);
|
||||
pLayer1->Add(new wxCheckBox(this, make_id(1, 6), L"6 (C)"), layerSizerFlags);
|
||||
pLayer1->Add(new wxCheckBox(this, make_id(1, 8), L"8"), layerSizerFlags);
|
||||
pLayer1->Add(new wxCheckBox(this, make_id(1, 10), L"10"), layerSizerFlags);
|
||||
pSidebarSizer->Add(pLayer1, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pLayer2 = new wxStaticBoxSizer(
|
||||
wxHORIZONTAL, this, L"Layer 2 (Bandages / Patient Accessory)");
|
||||
pLayer2->Add(new wxCheckBox(this, ID(2, 2), L"2 (Head / Alt Shoes)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer2->Add(new wxCheckBox(this, ID(2, 4), L"4 (Arm / Hat)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer2->Add(new wxCheckBox(this, ID(2, 6), L"6"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pSidebarSizer->Add(pLayer2, 0, wxEXPAND | wxALL, 0);
|
||||
pLayer2->Add(new wxCheckBox(this, make_id(2, 2), L"2 (Head / Alt Shoes)"),
|
||||
layerSizerFlags);
|
||||
pLayer2->Add(new wxCheckBox(this, make_id(2, 4), L"4 (Arm / Hat)"),
|
||||
layerSizerFlags);
|
||||
pLayer2->Add(new wxCheckBox(this, make_id(2, 6), L"6"), layerSizerFlags);
|
||||
pSidebarSizer->Add(pLayer2, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pLayer3 =
|
||||
new wxStaticBoxSizer(wxHORIZONTAL, this, L"Layer 3 (Bandages / Colour)");
|
||||
pLayer3->Add(new wxCheckBox(this, ID(3, 0), L"0"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer3->Add(new wxCheckBox(this, ID(3, 2), L"2 (? / Yellow)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer3->Add(new wxCheckBox(this, ID(3, 4), L"4 (L Foot / Blue)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer3->Add(new wxCheckBox(this, ID(3, 6), L"6 (? / White)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer3->Add(new wxCheckBox(this, ID(3, 8), L"8 (R Arm)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer3->Add(new wxCheckBox(this, ID(3, 10), L"10 (R Foot)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pSidebarSizer->Add(pLayer3, 0, wxEXPAND | wxALL, 0);
|
||||
pLayer3->Add(new wxCheckBox(this, make_id(3, 0), L"0"), layerSizerFlags);
|
||||
pLayer3->Add(new wxCheckBox(this, make_id(3, 2), L"2 (? / Yellow)"),
|
||||
layerSizerFlags);
|
||||
pLayer3->Add(new wxCheckBox(this, make_id(3, 4), L"4 (L Foot / Blue)"),
|
||||
layerSizerFlags);
|
||||
pLayer3->Add(new wxCheckBox(this, make_id(3, 6), L"6 (? / White)"),
|
||||
layerSizerFlags);
|
||||
pLayer3->Add(new wxCheckBox(this, make_id(3, 8), L"8 (R Arm)"),
|
||||
layerSizerFlags);
|
||||
pLayer3->Add(new wxCheckBox(this, make_id(3, 10), L"10 (R Foot)"),
|
||||
layerSizerFlags);
|
||||
pSidebarSizer->Add(pLayer3, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pLayer4 =
|
||||
new wxStaticBoxSizer(wxHORIZONTAL, this, L"Layer 4 (Bandages / Repair)");
|
||||
pLayer4->Add(new wxCheckBox(this, ID(4, 0), L"0"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer4->Add(new wxCheckBox(this, ID(4, 2), L"2 (Head / Repair)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer4->Add(new wxCheckBox(this, ID(4, 4), L"4 (L Root)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer4->Add(new wxCheckBox(this, ID(4, 6), L"6"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer4->Add(new wxCheckBox(this, ID(4, 8), L"8 (R Arm)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer4->Add(new wxCheckBox(this, ID(4, 10), L"10 (R Foot)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pSidebarSizer->Add(pLayer4, 0, wxEXPAND | wxALL, 0);
|
||||
pLayer4->Add(new wxCheckBox(this, make_id(4, 0), L"0"), layerSizerFlags);
|
||||
pLayer4->Add(new wxCheckBox(this, make_id(4, 2), L"2 (Head / Repair)"),
|
||||
layerSizerFlags);
|
||||
pLayer4->Add(new wxCheckBox(this, make_id(4, 4), L"4 (L Root)"),
|
||||
layerSizerFlags);
|
||||
pLayer4->Add(new wxCheckBox(this, make_id(4, 6), L"6"), layerSizerFlags);
|
||||
pLayer4->Add(new wxCheckBox(this, make_id(4, 8), L"8 (R Arm)"),
|
||||
layerSizerFlags);
|
||||
pLayer4->Add(new wxCheckBox(this, make_id(4, 10), L"10 (R Foot)"),
|
||||
layerSizerFlags);
|
||||
pSidebarSizer->Add(pLayer4, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pLayer5 =
|
||||
new wxStaticBoxSizer(wxHORIZONTAL, this, L"Layer 5 (Staff Head)");
|
||||
pLayer5->Add(new wxCheckBox(this, ID(5, 0), L"0"), 0, wxALIGN_CENTER | wxALL,
|
||||
1);
|
||||
pLayer5->Add(new wxCheckBox(this, ID(5, 2), L"2 (W1)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer5->Add(new wxCheckBox(this, ID(5, 4), L"4 (B1)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer5->Add(new wxCheckBox(this, ID(5, 6), L"6 (W2)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer5->Add(new wxCheckBox(this, ID(5, 8), L"8 (B2)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer5->Add(new wxCheckBox(this, ID(5, 10), L"10"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pSidebarSizer->Add(pLayer5, 0, wxEXPAND | wxALL, 0);
|
||||
pLayer5->Add(new wxCheckBox(this, make_id(5, 0), L"0"), layerSizerFlags);
|
||||
pLayer5->Add(new wxCheckBox(this, make_id(5, 2), L"2 (W1)"), layerSizerFlags);
|
||||
pLayer5->Add(new wxCheckBox(this, make_id(5, 4), L"4 (B1)"), layerSizerFlags);
|
||||
pLayer5->Add(new wxCheckBox(this, make_id(5, 6), L"6 (W2)"), layerSizerFlags);
|
||||
pLayer5->Add(new wxCheckBox(this, make_id(5, 8), L"8 (B2)"), layerSizerFlags);
|
||||
pLayer5->Add(new wxCheckBox(this, make_id(5, 10), L"10"), layerSizerFlags);
|
||||
pSidebarSizer->Add(pLayer5, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pLayer10 = new wxStaticBoxSizer(
|
||||
wxHORIZONTAL, this, L"Layer 10 (Wall Colour / Smoke)");
|
||||
pLayer10->Add(new wxCheckBox(this, ID(10, 2), L"2 (Yellow / Smoke)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer10->Add(new wxCheckBox(this, ID(10, 4), L"4 (Blue)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer10->Add(new wxCheckBox(this, ID(10, 6), L"6 (White)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pSidebarSizer->Add(pLayer10, 0, wxEXPAND | wxALL, 0);
|
||||
pLayer10->Add(new wxCheckBox(this, make_id(10, 2), L"2 (Yellow / Smoke)"),
|
||||
layerSizerFlags);
|
||||
pLayer10->Add(new wxCheckBox(this, make_id(10, 4), L"4 (Blue)"),
|
||||
layerSizerFlags);
|
||||
pLayer10->Add(new wxCheckBox(this, make_id(10, 6), L"6 (White)"),
|
||||
layerSizerFlags);
|
||||
pSidebarSizer->Add(pLayer10, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pLayer11 = new wxStaticBoxSizer(
|
||||
wxHORIZONTAL, this, L"Layer 11 (Wall Colour / Smoke / Screen)");
|
||||
pLayer11->Add(new wxCheckBox(this, ID(11, 2), L"2 (Yellow / Smoke / On)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer11->Add(new wxCheckBox(this, ID(11, 4), L"4 (Blue)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pLayer11->Add(new wxCheckBox(this, ID(11, 6), L"6 (Green)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pSidebarSizer->Add(pLayer11, 0, wxEXPAND | wxALL, 0);
|
||||
pLayer11->Add(
|
||||
new wxCheckBox(this, make_id(11, 2), L"2 (Yellow / Smoke / On)"),
|
||||
layerSizerFlags);
|
||||
pLayer11->Add(new wxCheckBox(this, make_id(11, 4), L"4 (Blue)"),
|
||||
layerSizerFlags);
|
||||
pLayer11->Add(new wxCheckBox(this, make_id(11, 6), L"6 (Green)"),
|
||||
layerSizerFlags);
|
||||
pSidebarSizer->Add(pLayer11, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pLayer12 =
|
||||
new wxStaticBoxSizer(wxHORIZONTAL, this, L"Layer 12 (Smoke)");
|
||||
pLayer12->Add(new wxCheckBox(this, ID(12, 2), L"2 (Smoke)"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pSidebarSizer->Add(pLayer12, 0, wxEXPAND | wxALL, 0);
|
||||
pLayer12->Add(new wxCheckBox(this, make_id(12, 2), L"2 (Smoke)"),
|
||||
layerSizerFlags);
|
||||
pSidebarSizer->Add(pLayer12, fillSizerFlags);
|
||||
|
||||
wxStaticBoxSizer* pMoodOverlay =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, L"Overlays");
|
||||
pMoodOverlay->Add(new wxCheckBox(this, ID_DRAW_MOOD, L"Draw mood overlay"), 0,
|
||||
wxEXPAND | wxALL, 1);
|
||||
pMoodOverlay->Add(new wxCheckBox(this, ID_DRAW_MOOD, L"Draw mood overlay"),
|
||||
fillBorderSizerFlags);
|
||||
wxBoxSizer* pMoodRow = new wxBoxSizer(wxHORIZONTAL);
|
||||
pMoodRow->Add(
|
||||
new wxStaticText(this, wxID_ANY, L"Marker position (click to move it):"),
|
||||
0, wxEXPAND | wxRIGHT, 2);
|
||||
wxSizerFlags(0).Expand().Border(wxRIGHT, 2));
|
||||
pMoodRow->Add(
|
||||
m_txtMoodPosition[0] = new wxTextCtrl(this, wxID_ANY, L"{0, 0}"), 1,
|
||||
wxEXPAND | wxRIGHT, 1);
|
||||
m_txtMoodPosition[0] = new wxTextCtrl(this, wxID_ANY, L"{0, 0}"),
|
||||
wxSizerFlags(1).Expand().Border(wxRIGHT, 1));
|
||||
pMoodRow->Add(
|
||||
m_txtMoodPosition[1] = new wxTextCtrl(this, wxID_ANY, L"{0, 0, \"px\"}"),
|
||||
1, wxEXPAND);
|
||||
pMoodOverlay->Add(pMoodRow, 1, wxEXPAND | wxALL, 2);
|
||||
wxSizerFlags(1).Expand());
|
||||
pMoodOverlay->Add(pMoodRow, wxSizerFlags(1).Expand().Border(wxALL, 2));
|
||||
pMoodOverlay->Add(
|
||||
new wxCheckBox(this, ID_DRAW_COORDINATES, L"Draw tile coordinates"), 0,
|
||||
wxEXPAND | wxALL, 0);
|
||||
pSidebarSizer->Add(pMoodOverlay, 0, wxEXPAND | wxALL, 0);
|
||||
new wxCheckBox(this, ID_DRAW_COORDINATES, L"Draw tile coordinates"),
|
||||
fillSizerFlags);
|
||||
pSidebarSizer->Add(pMoodOverlay, fillSizerFlags);
|
||||
m_bDrawMood = false;
|
||||
m_bDrawCoordinates = false;
|
||||
m_iMoodDrawX = 0;
|
||||
m_iMoodDrawY = 0;
|
||||
|
||||
for (int iLayer = 0; iLayer < 13; ++iLayer) {
|
||||
wxCheckBox* pCheck = wxDynamicCast(FindWindow(ID(iLayer, 0)), wxCheckBox);
|
||||
wxCheckBox* pCheck =
|
||||
wxDynamicCast(FindWindow(make_id(iLayer, 0)), wxCheckBox);
|
||||
if (pCheck != nullptr) {
|
||||
pCheck->SetValue(true);
|
||||
m_mskLayers.set(iLayer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Connect(ID(0, 0), ID(12, 24), wxEVT_COMMAND_CHECKBOX_CLICKED,
|
||||
Connect(make_id(0, 0), make_id(12, 24), wxEVT_COMMAND_CHECKBOX_CLICKED,
|
||||
(wxObjectEventFunction)&frmMain::_onToggleMask);
|
||||
#undef ID
|
||||
|
||||
wxStaticBoxSizer* pSearch = new wxStaticBoxSizer(wxVERTICAL, this, L"Search");
|
||||
wxBoxSizer* pSearchButtons = new wxBoxSizer(wxHORIZONTAL);
|
||||
pSearchButtons->Add(new wxButton(this, ID_SEARCH_LAYER_ID, L"Layer/ID"), 0,
|
||||
wxALL, 1);
|
||||
pSearchButtons->Add(new wxButton(this, ID_SEARCH_FRAME, L"Frame"), 0, wxALL,
|
||||
1);
|
||||
pSearchButtons->Add(new wxButton(this, ID_SEARCH_SOUND, L"Sound"), 0, wxALL,
|
||||
1);
|
||||
pSearchButtons->Add(new wxButton(this, ID_SEARCH_LAYER_ID, L"Layer/ID"),
|
||||
buttonSizerFlags);
|
||||
pSearchButtons->Add(new wxButton(this, ID_SEARCH_FRAME, L"Frame"),
|
||||
buttonSizerFlags);
|
||||
pSearchButtons->Add(new wxButton(this, ID_SEARCH_SOUND, L"Sound"),
|
||||
buttonSizerFlags);
|
||||
pSearch->Add(pSearchButtons, 0);
|
||||
pSearch->Add(m_lstSearchResults = new wxListBox(this, ID_SEARCH_RESULTS), 1,
|
||||
wxEXPAND | wxALL, 1);
|
||||
m_lstSearchResults = new wxListBox(this, ID_SEARCH_RESULTS);
|
||||
pSearch->Add(m_lstSearchResults, wxSizerFlags(1).Expand().Border(wxALL, 1));
|
||||
|
||||
wxStaticBoxSizer* pFrameFlags =
|
||||
new wxStaticBoxSizer(wxHORIZONTAL, this, L"Frame Flags");
|
||||
wxSizerFlags frameSizerFlags(0);
|
||||
frameSizerFlags.Expand().Border(wxALL, 2);
|
||||
wxBoxSizer* pFlags1 = new wxBoxSizer(wxVERTICAL);
|
||||
pFlags1->Add(m_txtFrameFlags[0] = new wxTextCtrl(this, wxID_ANY), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags1->Add(m_chkFrameFlags[0] = new wxCheckBox(this, wxID_ANY, L"2^0"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags1->Add(m_chkFrameFlags[1] = new wxCheckBox(this, wxID_ANY, L"2^1"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags1->Add(m_chkFrameFlags[2] = new wxCheckBox(this, wxID_ANY, L"2^2"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags1->Add(m_chkFrameFlags[3] = new wxCheckBox(this, wxID_ANY, L"2^3"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags1->Add(m_chkFrameFlags[4] = new wxCheckBox(this, wxID_ANY, L"2^4"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags1->Add(m_chkFrameFlags[5] = new wxCheckBox(this, wxID_ANY, L"2^5"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags1->Add(m_chkFrameFlags[6] = new wxCheckBox(this, wxID_ANY, L"2^6"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags1->Add(m_chkFrameFlags[7] = new wxCheckBox(this, wxID_ANY, L"2^7"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFrameFlags->Add(pFlags1, 1, wxEXPAND);
|
||||
m_txtFrameFlags[0] = new wxTextCtrl(this, wxID_ANY);
|
||||
pFlags1->Add(m_txtFrameFlags[0], frameSizerFlags);
|
||||
m_chkFrameFlags[0] = new wxCheckBox(this, wxID_ANY, L"2^0");
|
||||
m_chkFrameFlags[1] = new wxCheckBox(this, wxID_ANY, L"2^1");
|
||||
m_chkFrameFlags[2] = new wxCheckBox(this, wxID_ANY, L"2^2");
|
||||
m_chkFrameFlags[3] = new wxCheckBox(this, wxID_ANY, L"2^3");
|
||||
m_chkFrameFlags[4] = new wxCheckBox(this, wxID_ANY, L"2^4");
|
||||
m_chkFrameFlags[5] = new wxCheckBox(this, wxID_ANY, L"2^5");
|
||||
m_chkFrameFlags[6] = new wxCheckBox(this, wxID_ANY, L"2^6");
|
||||
m_chkFrameFlags[7] = new wxCheckBox(this, wxID_ANY, L"2^7");
|
||||
pFlags1->Add(m_chkFrameFlags[0], frameSizerFlags);
|
||||
pFlags1->Add(m_chkFrameFlags[1], frameSizerFlags);
|
||||
pFlags1->Add(m_chkFrameFlags[2], frameSizerFlags);
|
||||
pFlags1->Add(m_chkFrameFlags[3], frameSizerFlags);
|
||||
pFlags1->Add(m_chkFrameFlags[4], frameSizerFlags);
|
||||
pFlags1->Add(m_chkFrameFlags[5], frameSizerFlags);
|
||||
pFlags1->Add(m_chkFrameFlags[6], frameSizerFlags);
|
||||
pFlags1->Add(m_chkFrameFlags[7], frameSizerFlags);
|
||||
pFrameFlags->Add(pFlags1, wxSizerFlags(1).Expand());
|
||||
wxBoxSizer* pFlags2 = new wxBoxSizer(wxVERTICAL);
|
||||
pFlags2->Add(m_txtFrameFlags[1] = new wxTextCtrl(this, wxID_ANY), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags2->Add(m_chkFrameFlags[8] =
|
||||
new wxCheckBox(this, wxID_ANY, L"2^8 (Animation Start)"),
|
||||
0, wxEXPAND | wxALL, 2);
|
||||
pFlags2->Add(m_chkFrameFlags[9] = new wxCheckBox(this, wxID_ANY, L"2^9"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags2->Add(m_chkFrameFlags[10] = new wxCheckBox(this, wxID_ANY, L"2^10"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags2->Add(m_chkFrameFlags[11] = new wxCheckBox(this, wxID_ANY, L"2^11"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags2->Add(m_chkFrameFlags[12] = new wxCheckBox(this, wxID_ANY, L"2^12"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags2->Add(m_chkFrameFlags[13] = new wxCheckBox(this, wxID_ANY, L"2^13"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags2->Add(m_chkFrameFlags[14] = new wxCheckBox(this, wxID_ANY, L"2^14"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFlags2->Add(m_chkFrameFlags[15] = new wxCheckBox(this, wxID_ANY, L"2^15"), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
pFrameFlags->Add(pFlags2, 1, wxEXPAND);
|
||||
|
||||
pMainSizer->Add(pSidebarSizer, 0, wxEXPAND | wxALL, 2);
|
||||
m_txtFrameFlags[1] = new wxTextCtrl(this, wxID_ANY);
|
||||
|
||||
pFlags2->Add(m_txtFrameFlags[1], frameSizerFlags);
|
||||
m_chkFrameFlags[8] = new wxCheckBox(this, wxID_ANY, L"2^8 (Animation Start)");
|
||||
m_chkFrameFlags[9] = new wxCheckBox(this, wxID_ANY, L"2^9");
|
||||
m_chkFrameFlags[10] = new wxCheckBox(this, wxID_ANY, L"2^10");
|
||||
m_chkFrameFlags[11] = new wxCheckBox(this, wxID_ANY, L"2^11");
|
||||
m_chkFrameFlags[12] = new wxCheckBox(this, wxID_ANY, L"2^12");
|
||||
m_chkFrameFlags[13] = new wxCheckBox(this, wxID_ANY, L"2^13");
|
||||
m_chkFrameFlags[14] = new wxCheckBox(this, wxID_ANY, L"2^14");
|
||||
m_chkFrameFlags[15] = new wxCheckBox(this, wxID_ANY, L"2^15");
|
||||
pFlags2->Add(m_chkFrameFlags[8], frameSizerFlags);
|
||||
pFlags2->Add(m_chkFrameFlags[9], frameSizerFlags);
|
||||
pFlags2->Add(m_chkFrameFlags[10], frameSizerFlags);
|
||||
pFlags2->Add(m_chkFrameFlags[11], frameSizerFlags);
|
||||
pFlags2->Add(m_chkFrameFlags[12], frameSizerFlags);
|
||||
pFlags2->Add(m_chkFrameFlags[13], frameSizerFlags);
|
||||
pFlags2->Add(m_chkFrameFlags[14], frameSizerFlags);
|
||||
pFlags2->Add(m_chkFrameFlags[15], frameSizerFlags);
|
||||
pFrameFlags->Add(pFlags2, wxSizerFlags(1).Expand());
|
||||
|
||||
pMainSizer->Add(pSidebarSizer, wxSizerFlags(0).Expand().Border(wxALL, 2));
|
||||
|
||||
wxSizer* pRightHandSizer = new wxBoxSizer(wxVERTICAL);
|
||||
pRightHandSizer->AddSpacer(1);
|
||||
|
||||
pRightHandSizer->Add(
|
||||
m_panFrame = new wxPanel(this, wxID_ANY, def, wxBORDER_SIMPLE), 0,
|
||||
wxEXPAND | wxALL, 2);
|
||||
m_panFrame = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
||||
wxBORDER_SIMPLE);
|
||||
pRightHandSizer->Add(m_panFrame, wxSizerFlags(0).Expand().Border(wxALL, 2));
|
||||
m_panFrame->Connect(wxEVT_PAINT,
|
||||
(wxObjectEventFunction)&frmMain::_onPanelPaint, nullptr,
|
||||
this);
|
||||
@@ -378,11 +388,10 @@ frmMain::frmMain()
|
||||
m_panFrame->SetMinSize(m_panFrame->ClientToWindowSize(wxSize(402, 402)));
|
||||
|
||||
pRightHandSizer->AddSpacer(1);
|
||||
pRightHandSizer->Add(pSearch, 1, wxEXPAND | wxALL, 0);
|
||||
pRightHandSizer->Add(pFrameFlags, 0, wxEXPAND | wxALL, 0);
|
||||
pMainSizer->Add(pRightHandSizer, 1, wxEXPAND | wxALL, 0);
|
||||
pRightHandSizer->Add(pSearch, wxSizerFlags(1).Expand().Border(wxALL, 0));
|
||||
pRightHandSizer->Add(pFrameFlags, fillSizerFlags);
|
||||
pMainSizer->Add(pRightHandSizer, wxSizerFlags(1).Expand().Border(wxALL, 0));
|
||||
|
||||
SetBackgroundColour(m_btnPlayPause->GetBackgroundColour());
|
||||
SetSizer(pMainSizer);
|
||||
|
||||
SetMinSize(ClientToWindowSize(pMainSizer->CalcMin()));
|
||||
@@ -444,7 +453,7 @@ void frmMain::load() {
|
||||
m_oAnims.markDuplicates();
|
||||
|
||||
m_txtAnimCount->SetValue(
|
||||
wxString::Format(L"%u", (int)m_oAnims.getAnimationCount()));
|
||||
wxString::Format(L"%zu", m_oAnims.getAnimationCount()));
|
||||
|
||||
m_imgBackground.Create(400, 400);
|
||||
{
|
||||
@@ -522,11 +531,13 @@ void frmMain::_onLastAnim(wxCommandEvent& evt) {
|
||||
}
|
||||
|
||||
void frmMain::_onAnimChar(wxCommandEvent& evt) {
|
||||
long iAnim;
|
||||
if (evt.GetString().ToLong(&iAnim)) {
|
||||
if (iAnim >= 0 && iAnim < (long)m_oAnims.getAnimationCount()) {
|
||||
_onAnimChange((size_t)iAnim);
|
||||
long conv;
|
||||
if (evt.GetString().ToLong(&conv)) {
|
||||
if (conv < 0 || conv >= m_oAnims.getAnimationCount()) {
|
||||
return;
|
||||
}
|
||||
size_t iAnim = static_cast<size_t>(conv);
|
||||
_onAnimChange(iAnim);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,7 +555,7 @@ void frmMain::_onGhostIndexChange(wxSpinEvent& evt) {
|
||||
|
||||
void frmMain::_onAnimChange(size_t iIndex) {
|
||||
m_iCurrentAnim = iIndex;
|
||||
m_txtAnimIndex->ChangeValue(wxString::Format(L"%u", (int)iIndex));
|
||||
m_txtAnimIndex->ChangeValue(wxString::Format(L"%zu", iIndex));
|
||||
m_iCurrentFrame = 0;
|
||||
|
||||
THLayerMask oMask;
|
||||
@@ -562,7 +573,7 @@ void frmMain::_onAnimChange(size_t iIndex) {
|
||||
m_panFrame->Refresh(false);
|
||||
m_txtFrameIndex->SetValue(wxString::Format(L"0"));
|
||||
m_txtFrameCount->SetValue(
|
||||
wxString::Format(L"%u", (int)m_oAnims.getFrameCount(iIndex)));
|
||||
wxString::Format(L"%zu", m_oAnims.getFrameCount(iIndex)));
|
||||
}
|
||||
|
||||
void frmMain::_onPlayPause(wxCommandEvent& evt) {
|
||||
@@ -581,7 +592,7 @@ void frmMain::_onPrevFrame(wxCommandEvent& evt) {
|
||||
else
|
||||
m_iCurrentFrame =
|
||||
(m_iCurrentFrame - 1) % m_oAnims.getFrameCount(m_iCurrentAnim);
|
||||
m_txtFrameIndex->SetValue(wxString::Format(L"%u", m_iCurrentFrame));
|
||||
m_txtFrameIndex->SetValue(wxString::Format(L"%zu", m_iCurrentFrame));
|
||||
m_panFrame->Refresh(false);
|
||||
}
|
||||
|
||||
@@ -590,7 +601,7 @@ void frmMain::_onNextFrame(wxCommandEvent& evt) {
|
||||
|
||||
m_iCurrentFrame =
|
||||
(m_iCurrentFrame + 1) % m_oAnims.getFrameCount(m_iCurrentAnim);
|
||||
m_txtFrameIndex->SetValue(wxString::Format(L"%u", m_iCurrentFrame));
|
||||
m_txtFrameIndex->SetValue(wxString::Format(L"%zu", m_iCurrentFrame));
|
||||
m_panFrame->Refresh(false);
|
||||
}
|
||||
|
||||
@@ -600,7 +611,7 @@ void frmMain::_onTimer(wxTimerEvent& evt) {
|
||||
|
||||
m_iCurrentFrame =
|
||||
(m_iCurrentFrame + 1) % m_oAnims.getFrameCount(m_iCurrentAnim);
|
||||
m_txtFrameIndex->SetValue(wxString::Format(L"%u", (int)m_iCurrentFrame));
|
||||
m_txtFrameIndex->SetValue(wxString::Format(L"%zu", m_iCurrentFrame));
|
||||
m_panFrame->Refresh(false);
|
||||
}
|
||||
}
|
||||
@@ -687,14 +698,17 @@ void frmMain::_onPanelClick(wxMouseEvent& evt) {
|
||||
}
|
||||
|
||||
void frmMain::_onSearchLayerId(wxCommandEvent& evt) {
|
||||
long iLayer = ::wxGetNumberFromUser(
|
||||
long input = ::wxGetNumberFromUser(
|
||||
L"Enter the layer number to search in (0 - 12)", L"Layer:",
|
||||
L"Search for Layer / ID Combo", 0, 0, 13, this);
|
||||
if (iLayer < 0 || iLayer > 12) return;
|
||||
long iID = ::wxGetNumberFromUser(
|
||||
L"Enter the ID number to search for (0 - 24)", L"ID:",
|
||||
L"Search for Layer / ID Combo", 0, 0, 24, this);
|
||||
if (iID < 0 || iID > 24) return;
|
||||
if (input < 0 || input > 12) return;
|
||||
int iLayer = static_cast<int>(input);
|
||||
|
||||
input = ::wxGetNumberFromUser(L"Enter the ID number to search for (0 - 24)",
|
||||
L"ID:", L"Search for Layer / ID Combo", 0, 0,
|
||||
24, this);
|
||||
if (input < 0 || input > 24) return;
|
||||
int iID = static_cast<int>(input);
|
||||
|
||||
m_lstSearchResults->Clear();
|
||||
wxBusyCursor oBusy;
|
||||
@@ -703,33 +717,35 @@ void frmMain::_onSearchLayerId(wxCommandEvent& evt) {
|
||||
|
||||
THLayerMask mskAnim;
|
||||
m_oAnims.getAnimationMask(i, mskAnim);
|
||||
if (mskAnim.isSet(static_cast<int>(iLayer), static_cast<int>(iID))) {
|
||||
m_lstSearchResults->Append(wxString::Format(L"%i", (int)i));
|
||||
if (mskAnim.isSet(iLayer, iID)) {
|
||||
m_lstSearchResults->Append(wxString::Format(L"%zu", i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void frmMain::_onSearchFrame(wxCommandEvent& evt) {
|
||||
long iFrame =
|
||||
long input =
|
||||
::wxGetNumberFromUser(L"Enter the frame number to search for.", L"Frame:",
|
||||
L"Search for frame", 0, 0, 20000, this);
|
||||
if (iFrame == -1) return;
|
||||
if (input == -1) return;
|
||||
size_t iFrame = static_cast<size_t>(input);
|
||||
|
||||
m_lstSearchResults->Clear();
|
||||
wxBusyCursor oBusy;
|
||||
for (size_t i = 0; i < m_oAnims.getAnimationCount(); ++i) {
|
||||
if (m_oAnims.isAnimationDuplicate(i)) continue;
|
||||
if (m_oAnims.doesAnimationIncludeFrame(i, iFrame)) {
|
||||
m_lstSearchResults->Append(wxString::Format(L"%i", (int)i));
|
||||
m_lstSearchResults->Append(wxString::Format(L"%zu", i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void frmMain::_onSearchSoundIndex(wxCommandEvent& evt) {
|
||||
long iFrame = ::wxGetNumberFromUser(L"Enter the sound index to search for.",
|
||||
L"Sound index:", L"Search for sound", 0,
|
||||
0, 256, this);
|
||||
if (iFrame == -1) return;
|
||||
long input = ::wxGetNumberFromUser(L"Enter the sound index to search for.",
|
||||
L"Sound index:", L"Search for sound", 0, 0,
|
||||
256, this);
|
||||
if (input == -1) return;
|
||||
size_t iFrame = static_cast<size_t>(input);
|
||||
|
||||
m_lstSearchResults->Clear();
|
||||
wxBusyCursor oBusy;
|
||||
@@ -738,19 +754,13 @@ void frmMain::_onSearchSoundIndex(wxCommandEvent& evt) {
|
||||
size_t iCount = m_oAnims.getFrameCount(i);
|
||||
for (size_t j = 0; j < iCount; ++j) {
|
||||
if ((m_oAnims.getFrameStruct(i, j)->flags & 0xFF) == iFrame) {
|
||||
m_lstSearchResults->Append(wxString::Format(L"%i", (int)i));
|
||||
m_lstSearchResults->Append(wxString::Format(L"%zu", i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void frmMain::_onGotoSearchResult(wxCommandEvent& evt) {
|
||||
long iAnim;
|
||||
evt.GetString().ToLong(&iAnim);
|
||||
_onAnimChange(iAnim);
|
||||
}
|
||||
|
||||
void frmMain::_drawCoordinates(wxPaintDC& DC, int i, int j) {
|
||||
int x = 122; // tile (0, 0) text start x-coordinate
|
||||
int y = 226; // tile (0, 0) text start y-coordinate
|
||||
@@ -761,9 +771,6 @@ void frmMain::_drawCoordinates(wxPaintDC& DC, int i, int j) {
|
||||
|
||||
wxString frmMain::_getCaseSensitivePath(const wxString& sInsensitivePathPart,
|
||||
const wxString& sPath) {
|
||||
bool found;
|
||||
bool cont;
|
||||
|
||||
if (!wxFileName::IsCaseSensitive()) {
|
||||
return sPath + sInsensitivePathPart;
|
||||
}
|
||||
@@ -781,9 +788,11 @@ wxString frmMain::_getCaseSensitivePath(const wxString& sInsensitivePathPart,
|
||||
wxString pathPart = pathTokenizer.GetNextToken();
|
||||
|
||||
wxString realName;
|
||||
cont = dir.GetFirst(&realName, wxEmptyString,
|
||||
wxDIR_DIRS | wxDIR_FILES | wxDIR_HIDDEN | wxDIR_DOTDOT);
|
||||
found = false;
|
||||
bool cont =
|
||||
dir.GetFirst(&realName, wxEmptyString,
|
||||
wxDIR_DIRS | wxDIR_FILES | wxDIR_HIDDEN | wxDIR_DOTDOT);
|
||||
|
||||
bool found = false;
|
||||
while (cont) {
|
||||
if (realName.Upper() == pathPart.Upper()) {
|
||||
if (retStr.Last() != wxFileName::GetPathSeparator()) {
|
||||
|
@@ -48,43 +48,46 @@ frmSprites::frmSprites()
|
||||
wxStaticBoxSizer* pFiles = new wxStaticBoxSizer(wxVERTICAL, this, L"Files");
|
||||
wxFlexGridSizer* pFilesGrid = new wxFlexGridSizer(4, 3, 2, 1);
|
||||
pFilesGrid->AddGrowableCol(1, 1);
|
||||
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Table:"), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
|
||||
pFilesGrid->Add(
|
||||
m_txtTable = new wxTextCtrl(
|
||||
this, wxID_ANY, L"X:\\ThemeHospital\\hospital\\QData\\Font00V.tab"),
|
||||
1, wxALIGN_CENTER_VERTICAL | wxEXPAND);
|
||||
pFilesGrid->Add(new wxButton(this, ID_BROWSE_TABLE, L"Browse..."), 0,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Data:"), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
|
||||
pFilesGrid->Add(m_txtData = new wxTextCtrl(this, wxID_ANY, L""), 1,
|
||||
wxALIGN_CENTER_VERTICAL | wxEXPAND);
|
||||
pFilesGrid->Add(new wxButton(this, ID_BROWSE_DATA, L"Browse..."), 0,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Palette:"), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
|
||||
pFilesGrid->Add(
|
||||
m_txtPalette = new wxTextCtrl(
|
||||
this, wxID_ANY, L"X:\\ThemeHospital\\hospital\\Data\\MPalette.dat"),
|
||||
1, wxALIGN_CENTER_VERTICAL | wxEXPAND);
|
||||
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Table:"),
|
||||
wxSizerFlags(0).Center().Right());
|
||||
m_txtTable = new wxTextCtrl(
|
||||
this, wxID_ANY, L"X:\\ThemeHospital\\hospital\\QData\\Font00V.tab");
|
||||
|
||||
pFilesGrid->Add(m_txtTable,
|
||||
wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL).Expand());
|
||||
pFilesGrid->Add(new wxButton(this, ID_BROWSE_TABLE, L"Browse..."),
|
||||
wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL));
|
||||
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Data:"),
|
||||
wxSizerFlags(0).Center().Right());
|
||||
m_txtData = new wxTextCtrl(this, wxID_ANY, L"");
|
||||
pFilesGrid->Add(m_txtData,
|
||||
wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL).Expand());
|
||||
pFilesGrid->Add(new wxButton(this, ID_BROWSE_DATA, L"Browse..."),
|
||||
wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL));
|
||||
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Palette:"),
|
||||
wxSizerFlags(0).Center().Right());
|
||||
|
||||
m_txtPalette = new wxTextCtrl(
|
||||
this, wxID_ANY, L"X:\\ThemeHospital\\hospital\\Data\\MPalette.dat");
|
||||
|
||||
pFilesGrid->Add(m_txtPalette,
|
||||
wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL).Expand());
|
||||
pFilesGrid->Add(new wxButton(this, ID_BROWSE_PALETTE, L"Browse..."), 0,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
pFiles->Add(pFilesGrid, 0, wxEXPAND | wxALL, 1);
|
||||
wxButton* pTmp;
|
||||
pFiles->Add(pTmp = new wxButton(this, ID_LOAD, L"Load Simple"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pFiles->Add(pTmp = new wxButton(this, ID_LOAD_COMPLEX, L"Load Complex"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
pFiles->Add(pTmp = new wxButton(this, ID_NEXT, L"Next"), 0,
|
||||
wxALIGN_CENTER | wxALL, 1);
|
||||
SetBackgroundColour(pTmp->GetBackgroundColour());
|
||||
pMainSizer->Add(pFiles, 0, wxEXPAND | wxALL, 2);
|
||||
pFiles->Add(pFilesGrid, wxSizerFlags(0).Expand().Border(wxALL, 1));
|
||||
pFiles->Add(new wxButton(this, ID_LOAD, L"Load Simple"),
|
||||
wxSizerFlags(0).Center().Border(wxALL, 1));
|
||||
pFiles->Add(new wxButton(this, ID_LOAD_COMPLEX, L"Load Complex"),
|
||||
wxSizerFlags(0).Center().Border(wxALL, 1));
|
||||
pFiles->Add(new wxButton(this, ID_NEXT, L"Next"),
|
||||
wxSizerFlags(0).Center().Border(wxALL, 1));
|
||||
pMainSizer->Add(pFiles, wxSizerFlags(0).Expand().Border(wxALL, 2));
|
||||
|
||||
wxStaticBoxSizer* pSprites =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, L"Sprites");
|
||||
pSprites->Add(m_panFrame = new MyVScrolled(this), 1, wxEXPAND);
|
||||
pMainSizer->Add(pSprites, 1, wxEXPAND | wxALL, 2);
|
||||
m_panFrame = new MyVScrolled(this);
|
||||
pSprites->Add(m_panFrame, wxSizerFlags(1).Expand());
|
||||
pMainSizer->Add(pSprites, wxSizerFlags(1).Expand().Border(wxALL, 2));
|
||||
m_panFrame->Connect(wxEVT_PAINT,
|
||||
(wxObjectEventFunction)&frmSprites::_onPanelPaint,
|
||||
nullptr, this);
|
||||
|
@@ -36,7 +36,9 @@ SOFTWARE.
|
||||
|
||||
#include "../libs/rnc/rnc.h"
|
||||
|
||||
static const unsigned char palette_upscale_map[0x40] = {
|
||||
namespace {
|
||||
|
||||
constexpr unsigned char palette_upscale_map[0x40] = {
|
||||
0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x28,
|
||||
0x2D, 0x31, 0x35, 0x39, 0x3D, 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55,
|
||||
0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, 0x82,
|
||||
@@ -115,8 +117,8 @@ class ChunkRenderer {
|
||||
bool m_skip_eol;
|
||||
};
|
||||
|
||||
static void decode_chunks(ChunkRenderer& renderer, const unsigned char* data,
|
||||
size_t datalen, unsigned char transparent) {
|
||||
void decode_chunks(ChunkRenderer& renderer, const unsigned char* data,
|
||||
size_t datalen, unsigned char transparent) {
|
||||
while (!renderer.isDone() && datalen > 0) {
|
||||
unsigned char b = *data;
|
||||
--datalen;
|
||||
@@ -136,9 +138,8 @@ static void decode_chunks(ChunkRenderer& renderer, const unsigned char* data,
|
||||
renderer.chunkFinish(transparent);
|
||||
}
|
||||
|
||||
static void decode_chunks_complex(ChunkRenderer& renderer,
|
||||
const unsigned char* data, size_t datalen,
|
||||
unsigned char transparent) {
|
||||
void decode_chunks_complex(ChunkRenderer& renderer, const unsigned char* data,
|
||||
size_t datalen, unsigned char transparent) {
|
||||
while (!renderer.isDone() && datalen > 0) {
|
||||
unsigned char b = *data;
|
||||
--datalen;
|
||||
@@ -178,6 +179,14 @@ static void decode_chunks_complex(ChunkRenderer& renderer,
|
||||
renderer.chunkFinish(transparent);
|
||||
}
|
||||
|
||||
void merge_colour(th_colour_t& dst, const th_colour_t& src) {
|
||||
dst.r = (uint8_t)(((unsigned int)dst.r + (unsigned int)src.r) / 2);
|
||||
dst.g = (uint8_t)(((unsigned int)dst.g + (unsigned int)src.g) / 2);
|
||||
dst.b = (uint8_t)(((unsigned int)dst.b + (unsigned int)src.b) / 2);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
THLayerMask::THLayerMask() { clear(); }
|
||||
|
||||
void THLayerMask::clear() {
|
||||
@@ -458,12 +467,6 @@ void Bitmap::blit(Bitmap& bmpCanvas, int iX, int iY, int iFlags) const {
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _merge(th_colour_t& dst, const th_colour_t& src) {
|
||||
dst.r = (uint8_t)(((unsigned int)dst.r + (unsigned int)src.r) / 2);
|
||||
dst.g = (uint8_t)(((unsigned int)dst.g + (unsigned int)src.g) / 2);
|
||||
dst.b = (uint8_t)(((unsigned int)dst.b + (unsigned int)src.b) / 2);
|
||||
}
|
||||
|
||||
void Bitmap::blit(wxImage& imgCanvas, int iX, int iY,
|
||||
const unsigned char* pColourTranslate,
|
||||
const th_colour_t* pPalette, int iFlags) const {
|
||||
@@ -491,10 +494,10 @@ void Bitmap::blit(wxImage& imgCanvas, int iX, int iY,
|
||||
th_colour_t dstc = pCanvas[iDstY * iCanvasWidth + iDstX];
|
||||
switch (iFlags & 0xC) {
|
||||
case 0x8:
|
||||
_merge(srcc, dstc);
|
||||
merge_colour(srcc, dstc);
|
||||
// fall-through
|
||||
case 0x4:
|
||||
_merge(srcc, dstc);
|
||||
merge_colour(srcc, dstc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -92,27 +92,26 @@ class THLayerMask {
|
||||
|
||||
inline void set(int iLayer, int iID) {
|
||||
if (0 <= iLayer && iLayer < 13 && 0 <= iID && iID < 32)
|
||||
m_iMask[iLayer] |= (1 << iID);
|
||||
m_iMask[iLayer] |= (1ul << iID);
|
||||
}
|
||||
|
||||
void clear();
|
||||
|
||||
inline void clear(int iLayer, int iID) {
|
||||
if (0 <= iLayer && iLayer < 13 && 0 <= iID && iID < 32)
|
||||
m_iMask[iLayer] &= ~(1 << iID);
|
||||
m_iMask[iLayer] &= ~(1ul << iID);
|
||||
}
|
||||
|
||||
inline bool isSet(int iLayer, int iID) const {
|
||||
if (0 <= iLayer && iLayer < 13 && 0 <= iID && iID < 32)
|
||||
return (m_iMask[iLayer] & (1 << iID)) != 0;
|
||||
return (m_iMask[iLayer] & (1ul << iID)) != 0;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
inline bool isSet(int iLayer) const {
|
||||
if (0 <= iLayer && iLayer < 13)
|
||||
for (int iId = 0; iId < 32; ++iId) {
|
||||
if ((m_iMask[iLayer] & (static_cast<std::uint32_t>(1) << iId)) != 0)
|
||||
return true;
|
||||
if ((m_iMask[iLayer] & (1ul << iId)) != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -216,7 +215,7 @@ class THAnimations {
|
||||
wxFile oFile(sFilename);
|
||||
if (!oFile.IsOpened()) return false;
|
||||
|
||||
size_t iLen = oFile.Length();
|
||||
size_t iLen = static_cast<size_t>(oFile.Length());
|
||||
unsigned char* pBuffer = new unsigned char[iLen];
|
||||
oFile.Read(pBuffer, iLen);
|
||||
if (memcmp(pBuffer, "RNC\001", 4) == 0) {
|
||||
|
@@ -5,14 +5,35 @@ add_custom_command(TARGET CorsixTH POST_BUILD
|
||||
$<TARGET_FILE_DIR:CorsixTH>/socket
|
||||
)
|
||||
|
||||
add_custom_command(TARGET CorsixTH POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${VCPKG_INSTALLED_PATH}/share/lua/ssl"
|
||||
$<TARGET_FILE_DIR:CorsixTH>/ssl
|
||||
)
|
||||
|
||||
add_custom_command(TARGET CorsixTH POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${VCPKG_INSTALLED_PATH}/share/lua/ltn12.lua"
|
||||
"${VCPKG_INSTALLED_PATH}/share/lua/mime.lua"
|
||||
"${VCPKG_INSTALLED_PATH}/share/lua/re.lua"
|
||||
"${VCPKG_INSTALLED_PATH}/share/lua/socket.lua"
|
||||
"${VCPKG_INSTALLED_PATH}/share/lua/ssl.lua"
|
||||
"${VCPKG_INSTALLED_PATH}/$<$<CONFIG:Debug>:debug/>bin/lfs.dll"
|
||||
"${VCPKG_INSTALLED_PATH}/$<$<CONFIG:Debug>:debug/>bin/lpeg.dll"
|
||||
"${VCPKG_INSTALLED_PATH}/$<$<CONFIG:Debug>:debug/>bin/ssl.dll"
|
||||
$<TARGET_FILE_DIR:CorsixTH>
|
||||
)
|
||||
|
||||
if(${_VCPKG_TARGET_TRIPLET} STREQUAL "x64-windows")
|
||||
set(_OPENSSL_SUFFIX "-x64")
|
||||
else()
|
||||
set(_OPENSSL_SUFFIX "")
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET CorsixTH POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${VCPKG_INSTALLED_PATH}/$<$<CONFIG:Debug>:debug/>bin/libcrypto-1_1${_OPENSSL_SUFFIX}.dll"
|
||||
"${VCPKG_INSTALLED_PATH}/$<$<CONFIG:Debug>:debug/>bin/libssl-1_1${_OPENSSL_SUFFIX}.dll"
|
||||
$<TARGET_FILE_DIR:CorsixTH>
|
||||
)
|
||||
|
||||
|
@@ -30,7 +30,7 @@ set(_DEPS_GIT_URL "https://github.com/CorsixTH/deps.git")
|
||||
# Select the optimal dependencies commit regardless where master is.
|
||||
set(_DEPS_GIT_SHA "a23eb28bb8998b93215eccf805ee5462d75a57f2")
|
||||
|
||||
ExternalProject_Add(${_DEPS_PROJECT_NAME}
|
||||
externalproject_add(${_DEPS_PROJECT_NAME}
|
||||
PREFIX ${PRECOMPILED_DEPS_BASE_DIR}
|
||||
GIT_REPOSITORY ${_DEPS_GIT_URL}
|
||||
GIT_TAG ${_DEPS_GIT_SHA}
|
||||
|
@@ -18,7 +18,7 @@
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
set(VCPKG_COMMIT_SHA "10ca4c5ba5218c14c4bf91570afe8bd5d63da387")
|
||||
set(VCPKG_COMMIT_SHA "c2691026a5e5aad05d7e7d89d605ccb595cbbcb6")
|
||||
|
||||
# Setup the various paths we are using
|
||||
set(_VCPKG_SCRIPT_NAME "build_vcpkg_deps.ps1")
|
||||
@@ -63,4 +63,4 @@ if(err_val)
|
||||
endif()
|
||||
|
||||
set(VCPKG_INSTALLED_PATH ${VCPKG_PARENT_DIR}/vcpkg/installed/${_VCPKG_TARGET_TRIPLET})
|
||||
set(CMAKE_TOOLCHAIN_FILE ${VCPKG_PARENT_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake)
|
||||
set(CMAKE_TOOLCHAIN_FILE ${VCPKG_PARENT_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake CACHE STRING "Vcpkg toolchain file")
|
||||
|
@@ -1,19 +1,20 @@
|
||||
# Cmake File for CorsixTH
|
||||
# OPTIONS AVAILABLE:
|
||||
# Any of the following: (default)
|
||||
# - WITH_AUDIO : Activate sound (yes)
|
||||
# - WITH_FREETYPE2 : Active support for non-Latin script alphabets (yes)
|
||||
# - WITH_MOVIES : Activate movies (requires with_audio, FFmpeg) (yes)
|
||||
# - WITH_LUAJIT : Use LuaJIT instead of Lua (must specify library path) (no)
|
||||
# - WITH_LIBAV : Use Libav instead of FFmpeg when building movies (no)
|
||||
# - WITH_AUDIO : Activate sound (yes)
|
||||
# - WITH_FREETYPE2 : Active support for non-Latin script alphabets (yes)
|
||||
# - WITH_MOVIES : Activate movies (requires with_audio, FFmpeg) (yes)
|
||||
# - WITH_LUAJIT : Use LuaJIT instead of Lua (must specify library path) (no)
|
||||
# - WITH_LIBAV : Use Libav instead of FFmpeg when building movies (no)
|
||||
# - USE_SOURCE_DATADIRS : Use the source directory for loading resources. Incompatible with the install target (no)
|
||||
|
||||
# - WITH_VLD : Build with Visual Leak Detector (requires Visual Studio) (no)
|
||||
# - WITH_VLD : Build with Visual Leak Detector (requires Visual Studio) (no)
|
||||
# - USE_PRECOMPILED_DEPS : Use precompiled dependencies on *nix (no)
|
||||
# - USE_VCPKG_DEPS : Build vcpkg dependencies locally (requires Visual Studio) (no)
|
||||
# - WITH_LUAROCKS : Install required luarocks in the macOS app (requires luarocks)
|
||||
|
||||
# - ENABLE_UNIT_TESTS : Enable Unit Testing Target (requires Catch2) (no)
|
||||
# - BUILD_ANIMVIEWER : Generate AnimViewer build files (no)
|
||||
# - BUILD_ANIMVIEW : Generate AnimViewer build files (no)
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
@@ -53,8 +54,12 @@ if(UNIX AND CMAKE_COMPILER_IS_GNU)
|
||||
option(USE_PRECOMPILED_DEPS "Use Precompiled Dependencies" OFF) # Make *nix systems opt in
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
option(WITH_LUAROCKS "Install required luarocks in the app" OFF)
|
||||
endif()
|
||||
|
||||
option(ENABLE_UNIT_TESTS "Enables Unit Testing Targets" OFF)
|
||||
option(BUILD_ANIMVIEWER "Build the animation viewer as part of the build process" OFF)
|
||||
option(BUILD_ANIMVIEW "Build the animation viewer as part of the build process" OFF)
|
||||
|
||||
if(WITH_AUDIO)
|
||||
set(CORSIX_TH_USE_SDL_MIXER ON)
|
||||
@@ -124,7 +129,7 @@ add_subdirectory("libs")
|
||||
message("Building CorsixTH")
|
||||
add_subdirectory(CorsixTH)
|
||||
|
||||
if(BUILD_ANIMVIEWER)
|
||||
if(BUILD_ANIMVIEW)
|
||||
message("Building AnimView")
|
||||
add_subdirectory(AnimView)
|
||||
endif()
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# Sanity check
|
||||
if(CORSIX_TH_DONE_TOP_LEVEL_CMAKE)
|
||||
else()
|
||||
message(FATAL_ERROR "Please run cmake on the top-level directory, not this one.")
|
||||
message(FATAL_ERROR "Please run CMake from the top-level directory instead of here.")
|
||||
endif()
|
||||
|
||||
# Project Declaration
|
||||
@@ -26,8 +26,6 @@ else()
|
||||
set(CORSIX_TH_INTERPRETER_PATH ${CMAKE_INSTALL_FULL_DATADIR}/corsix-th/CorsixTH.lua)
|
||||
endif()
|
||||
|
||||
add_library(CorsixTH_lib STATIC)
|
||||
|
||||
# Declaration of the executable
|
||||
if(APPLE)
|
||||
set(corsixth_icon_file ${CMAKE_SOURCE_DIR}/CorsixTH/Icon.icns)
|
||||
@@ -45,9 +43,25 @@ if(APPLE)
|
||||
elseif(MSVC)
|
||||
add_executable(CorsixTH CorsixTH.rc)
|
||||
else()
|
||||
add_executable(CorsixTH)
|
||||
add_executable(CorsixTH "")
|
||||
endif()
|
||||
|
||||
# Report operating system in compile_opts.os
|
||||
if(WIN32)
|
||||
set(CORSIX_TH_OS "windows")
|
||||
elseif(APPLE)
|
||||
set(CORSIX_TH_OS "macos")
|
||||
else()
|
||||
set(CORSIX_TH_OS "unix")
|
||||
endif()
|
||||
|
||||
# Ensure config.h is picked up by cmake - moving this into subdir cmake files will
|
||||
# prevent it applying to the CorsixTH project
|
||||
set(CorsixTH_generated_src_dir ${CMAKE_BINARY_DIR}/CorsixTH/Src/)
|
||||
add_library(CorsixTH_lib STATIC ${CorsixTH_generated_src_dir})
|
||||
|
||||
target_include_directories(CorsixTH_lib PUBLIC ${CorsixTH_generated_src_dir})
|
||||
|
||||
target_link_libraries(CorsixTH_lib RncLib)
|
||||
target_link_libraries(CorsixTH CorsixTH_lib)
|
||||
|
||||
@@ -60,10 +74,6 @@ endif()
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/Src)
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/SrcUnshared)
|
||||
|
||||
# Ensure config.h is picked up by cmake - moving this into subdir cmake files will
|
||||
# prevent it applying to the CorsixTH project
|
||||
target_include_directories(CorsixTH_lib PUBLIC ${CMAKE_BINARY_DIR}/CorsixTH/Src/)
|
||||
|
||||
# Set language standard
|
||||
set_property(TARGET CorsixTH_lib PROPERTY CXX_STANDARD 14)
|
||||
set_property(TARGET CorsixTH_lib PROPERTY CXX_EXTENSIONS OFF)
|
||||
@@ -77,7 +87,7 @@ set_property(TARGET CorsixTH PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
if(USE_VCPKG_DEPS)
|
||||
include(CopyVcpkgLua)
|
||||
include(CopyVcpkgSdlMixerBackends)
|
||||
ENDIF()
|
||||
endif()
|
||||
|
||||
## Finding libraries
|
||||
|
||||
@@ -267,8 +277,8 @@ if(NOT USE_SOURCE_DATADIRS)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
install(FILES corsix-th.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6)
|
||||
install(FILES com.corsixth.CorsixTH.appdata.xml DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo)
|
||||
install(FILES com.corsixth.CorsixTH.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
|
||||
install(FILES com.corsixth.corsixth.metainfo.xml DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo)
|
||||
install(FILES com.corsixth.corsixth.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
|
||||
install(FILES Original_Logo.svg DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps RENAME corsix-th.svg)
|
||||
endif()
|
||||
|
||||
@@ -277,7 +287,12 @@ if(NOT USE_SOURCE_DATADIRS)
|
||||
install(CODE "
|
||||
INCLUDE(BundleUtilities)
|
||||
SET(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
FIXUP_BUNDLE(${CMAKE_INSTALL_PREFIX}/CorsixTH.app \"\" \"\")
|
||||
FIXUP_BUNDLE(\"${CMAKE_INSTALL_PREFIX}/CorsixTH.app\" \"\" \"\")
|
||||
")
|
||||
if(WITH_LUAROCKS)
|
||||
install(CODE "execute_process(
|
||||
COMMAND bash \"${CMAKE_SOURCE_DIR}/scripts/macos_luarocks\" \"${CMAKE_INSTALL_PREFIX}\")
|
||||
")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
@@ -9,6 +9,12 @@ if (package and package.preload and package.preload.TH) == nil then
|
||||
error "This file must be invoked by the CorsixTH executable"
|
||||
end
|
||||
|
||||
-- Set a large enough cstacklimit to load complex saves in stack based
|
||||
-- versions of lua, such as 5.4.[01]
|
||||
if debug.setcstacklimit then
|
||||
debug.setcstacklimit(30000)
|
||||
end
|
||||
|
||||
-- Parse script parameters:
|
||||
local run_debugger = false
|
||||
for _, arg in ipairs({...}) do
|
||||
@@ -82,7 +88,7 @@ end
|
||||
|
||||
-- Check Lua version
|
||||
if _VERSION ~= "Lua 5.1" then
|
||||
if _VERSION == "Lua 5.2" or _VERSION == "Lua 5.3" then
|
||||
if _VERSION == "Lua 5.2" or _VERSION == "Lua 5.3" or _VERSION == "Lua 5.4" then
|
||||
-- Compatibility: Keep the global unpack function
|
||||
unpack = table.unpack
|
||||
-- Compatibility: Provide a replacement for deprecated ipairs()
|
||||
|
@@ -1,17 +1,17 @@
|
||||
# MIT License
|
||||
#
|
||||
#
|
||||
# Copyright (c) 2019 David Fairbrother
|
||||
#
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -28,8 +28,11 @@ add_custom_target(AllTests)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/CorsixTH/Src/)
|
||||
|
||||
add_executable(UnitTests "")
|
||||
target_link_libraries(UnitTests Catch2::Catch2)
|
||||
target_link_libraries(UnitTests CorsixTH_lib)
|
||||
target_link_libraries(UnitTests
|
||||
Catch2::Catch2
|
||||
CorsixTH_lib
|
||||
${LUA_LIBRARY}
|
||||
${CMAKE_DL_LIBS})
|
||||
|
||||
set_property(TARGET UnitTests PROPERTY CXX_STANDARD 14)
|
||||
set_property(TARGET UnitTests PROPERTY CXX_EXTENSIONS OFF)
|
||||
@@ -46,5 +49,9 @@ add_dependencies(AllTests UnitTests)
|
||||
target_sources(UnitTests
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_th_lua.cpp
|
||||
)
|
||||
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
catch_discover_tests(UnitTests)
|
||||
|
@@ -1,6 +0,0 @@
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
TEST_CASE("Example Test", "[example]")
|
||||
{
|
||||
REQUIRE(true);
|
||||
}
|
113
CorsixTH/CppTest/test_th_lua.cpp
Normal file
113
CorsixTH/CppTest/test_th_lua.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "../Src/th_lua.h"
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
TEST_CASE("luaT_rotate works", "[luaT_rotate]") {
|
||||
lua_State* L = luaL_newstate();
|
||||
lua_pushnumber(L, 1);
|
||||
lua_pushnumber(L, 2);
|
||||
lua_pushnumber(L, 3);
|
||||
lua_pushnumber(L, 4);
|
||||
lua_pushnumber(L, 5);
|
||||
lua_pushnumber(L, 6);
|
||||
lua_pushnumber(L, 7);
|
||||
|
||||
REQUIRE(lua_gettop(L) == 7);
|
||||
|
||||
SECTION("rotate 0") {
|
||||
luaT_rotate(L, 1, 0);
|
||||
|
||||
REQUIRE(lua_tonumber(L, 1) == 1);
|
||||
REQUIRE(lua_tonumber(L, 2) == 2);
|
||||
REQUIRE(lua_tonumber(L, 3) == 3);
|
||||
REQUIRE(lua_tonumber(L, 4) == 4);
|
||||
REQUIRE(lua_tonumber(L, 5) == 5);
|
||||
REQUIRE(lua_tonumber(L, 6) == 6);
|
||||
REQUIRE(lua_tonumber(L, 7) == 7);
|
||||
}
|
||||
|
||||
SECTION("rotate all up 1") {
|
||||
luaT_rotate(L, 1, 1);
|
||||
|
||||
REQUIRE(lua_tonumber(L, 1) == 7);
|
||||
REQUIRE(lua_tonumber(L, 2) == 1);
|
||||
REQUIRE(lua_tonumber(L, 3) == 2);
|
||||
REQUIRE(lua_tonumber(L, 4) == 3);
|
||||
REQUIRE(lua_tonumber(L, 5) == 4);
|
||||
REQUIRE(lua_tonumber(L, 6) == 5);
|
||||
REQUIRE(lua_tonumber(L, 7) == 6);
|
||||
}
|
||||
|
||||
SECTION("rotate all down 1") {
|
||||
luaT_rotate(L, 1, -1);
|
||||
|
||||
REQUIRE(lua_tonumber(L, 1) == 2);
|
||||
REQUIRE(lua_tonumber(L, 2) == 3);
|
||||
REQUIRE(lua_tonumber(L, 3) == 4);
|
||||
REQUIRE(lua_tonumber(L, 4) == 5);
|
||||
REQUIRE(lua_tonumber(L, 5) == 6);
|
||||
REQUIRE(lua_tonumber(L, 6) == 7);
|
||||
REQUIRE(lua_tonumber(L, 7) == 1);
|
||||
}
|
||||
|
||||
SECTION("rotate all up 2") {
|
||||
luaT_rotate(L, 1, 2);
|
||||
|
||||
REQUIRE(lua_tonumber(L, 1) == 6);
|
||||
REQUIRE(lua_tonumber(L, 2) == 7);
|
||||
REQUIRE(lua_tonumber(L, 3) == 1);
|
||||
REQUIRE(lua_tonumber(L, 4) == 2);
|
||||
REQUIRE(lua_tonumber(L, 5) == 3);
|
||||
REQUIRE(lua_tonumber(L, 6) == 4);
|
||||
REQUIRE(lua_tonumber(L, 7) == 5);
|
||||
}
|
||||
|
||||
SECTION("rotate all down 2") {
|
||||
luaT_rotate(L, 1, -2);
|
||||
|
||||
REQUIRE(lua_tonumber(L, 1) == 3);
|
||||
REQUIRE(lua_tonumber(L, 2) == 4);
|
||||
REQUIRE(lua_tonumber(L, 3) == 5);
|
||||
REQUIRE(lua_tonumber(L, 4) == 6);
|
||||
REQUIRE(lua_tonumber(L, 5) == 7);
|
||||
REQUIRE(lua_tonumber(L, 6) == 1);
|
||||
REQUIRE(lua_tonumber(L, 7) == 2);
|
||||
}
|
||||
|
||||
SECTION("rotate from 3rd up 1") {
|
||||
luaT_rotate(L, 3, 1);
|
||||
|
||||
REQUIRE(lua_tonumber(L, 1) == 1);
|
||||
REQUIRE(lua_tonumber(L, 2) == 2);
|
||||
REQUIRE(lua_tonumber(L, 3) == 7);
|
||||
REQUIRE(lua_tonumber(L, 4) == 3);
|
||||
REQUIRE(lua_tonumber(L, 5) == 4);
|
||||
REQUIRE(lua_tonumber(L, 6) == 5);
|
||||
REQUIRE(lua_tonumber(L, 7) == 6);
|
||||
}
|
||||
|
||||
SECTION("rotate from -3rd up 1") {
|
||||
luaT_rotate(L, -3, 1);
|
||||
|
||||
REQUIRE(lua_tonumber(L, 1) == 1);
|
||||
REQUIRE(lua_tonumber(L, 2) == 2);
|
||||
REQUIRE(lua_tonumber(L, 3) == 3);
|
||||
REQUIRE(lua_tonumber(L, 4) == 4);
|
||||
REQUIRE(lua_tonumber(L, 5) == 7);
|
||||
REQUIRE(lua_tonumber(L, 6) == 5);
|
||||
REQUIRE(lua_tonumber(L, 7) == 6);
|
||||
}
|
||||
|
||||
SECTION("rotate from -5th down 2") {
|
||||
luaT_rotate(L, -5, -2);
|
||||
|
||||
REQUIRE(lua_tonumber(L, 1) == 1);
|
||||
REQUIRE(lua_tonumber(L, 2) == 2);
|
||||
REQUIRE(lua_tonumber(L, 3) == 5);
|
||||
REQUIRE(lua_tonumber(L, 4) == 6);
|
||||
REQUIRE(lua_tonumber(L, 5) == 7);
|
||||
REQUIRE(lua_tonumber(L, 6) == 3);
|
||||
REQUIRE(lua_tonumber(L, 7) == 4);
|
||||
}
|
||||
|
||||
lua_close(L);
|
||||
}
|
@@ -209,7 +209,7 @@ Divides research input to get the amount of research points. must be > 0
|
||||
|
||||
--------------------- Competitor Information -----------------------
|
||||
|
||||
| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment |
|
||||
#computer[12].Playing 1 CORSIX
|
||||
#computer[13].Playing 1 ROUJIN
|
||||
#computer[14].Playing 1 EDVIN
|
||||
| Index in the away "computer" | Is that opponent playing? 1 is yes, 0 no | Name |
|
||||
#computer[12].Playing.Name 1 CORSIX
|
||||
#computer[13].Playing.Name 1 ROUJIN
|
||||
#computer[14].Playing.Name 1 EDVIN
|
||||
|
@@ -206,10 +206,10 @@ Divides research input to get the amount of research points. must be > 0
|
||||
|
||||
--------------------- Competitor Information -----------------------
|
||||
|
||||
| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment |
|
||||
#computer[12].Playing 1 CORSIX
|
||||
#computer[13].Playing 1 ROUJIN
|
||||
#computer[14].Playing 1 EDVIN
|
||||
| Index in the away "computer" | Is that opponent playing? 1 is yes, 0 no | Name |
|
||||
#computer[12].Playing.Name 1 CORSIX
|
||||
#computer[13].Playing.Name 1 ROUJIN
|
||||
#computer[14].Playing.Name 1 EDVIN
|
||||
|
||||
----------------------- Emergency Control --------------------------
|
||||
|
||||
|
@@ -108,6 +108,7 @@ When a drug is researched, what effectiveness does it have
|
||||
|
||||
--------------------- Competitor Information -----------------------
|
||||
|
||||
#computer[12].Playing 1 CORSIX
|
||||
#computer[13].Playing 1 ROUJIN
|
||||
#computer[14].Playing 1 EDVIN
|
||||
| Index in the away "computer" | Is that opponent playing? 1 is yes, 0 no | Name |
|
||||
#computer[12].Playing.Name 1 CORSIX
|
||||
#computer[13].Playing.Name 1 ROUJIN
|
||||
#computer[14].Playing.Name 1 EDVIN
|
||||
|
@@ -55,7 +55,7 @@ InterestRate is defined as centiprocent to allow for two decimals precision, i.e
|
||||
-------------------- Disease Configuration -------------------------
|
||||
|
||||
When a drug is researched, what effectiveness does it have
|
||||
#gbv.StartRating 100
|
||||
#gbv.StartRating 100
|
||||
|
||||
The following table contains all diagnoses and treatments that shows up in the drug casebook
|
||||
in the game. Known specifies whether it should show up from the beginning of the level and
|
||||
@@ -230,10 +230,10 @@ But we don't want any such conditions on the example level!
|
||||
|
||||
--------------------- Competitor Information -----------------------
|
||||
|
||||
| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment |
|
||||
#computer[12].Playing 1 CORSIX
|
||||
#computer[13].Playing 1 ROUJIN
|
||||
#computer[14].Playing 1 EDVIN
|
||||
| Index in the away "computer" | Is that opponent playing? 1 is yes, 0 no | Name |
|
||||
#computer[12].Playing 1.Name CORSIX
|
||||
#computer[13].Playing 1.Name ROUJIN
|
||||
#computer[14].Playing 1.Name EDVIN
|
||||
|
||||
----------------------- Emergency Control --------------------------
|
||||
|
||||
|
@@ -280,7 +280,7 @@ But we don't want any such conditions on the example level!
|
||||
|
||||
--------------------- Competitor Information -----------------------
|
||||
|
||||
| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment |
|
||||
#computer[12].Playing 1 CORSIX
|
||||
#computer[13].Playing 1 ROUJIN
|
||||
#computer[14].Playing 1 EDVIN
|
||||
| Index in the away "computer" | Is that opponent playing? 1 is yes, 0 no | Name |
|
||||
#computer[12].Playing.Name 1 CORSIX
|
||||
#computer[13].Playing.Name 1 ROUJIN
|
||||
#computer[14].Playing.Name 1 EDVIN
|
||||
|
@@ -372,7 +372,7 @@ But we don't want any such conditions on the example level!
|
||||
|
||||
--------------------- Competitor Information -----------------------
|
||||
|
||||
| Index in the away "computer" | Is that opponent playing? | 1 is yes, 0 no | Comment |
|
||||
#computer[12].Playing 1 Corsix
|
||||
#computer[13].Playing 1 Roujin
|
||||
#computer[14].Playing 1 Edvin
|
||||
| Index in the away "computer" | Is that opponent playing? 1 is yes, 0 no | Name |
|
||||
#computer[12].Playing.Name 1 Corsix
|
||||
#computer[13].Playing.Name 1 Roujin
|
||||
#computer[14].Playing.Name 1 Edvin
|
||||
|
@@ -18,6 +18,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. --]]
|
||||
|
||||
corsixth.require("date")
|
||||
|
||||
--! Pr
|
||||
local AnnouncementPriority = {
|
||||
Critical = 1,
|
||||
@@ -30,12 +32,13 @@ strict_declare_global "AnnouncementPriority"
|
||||
_G["AnnouncementPriority"] = AnnouncementPriority
|
||||
|
||||
local default_announcement_priority = AnnouncementPriority.Normal
|
||||
local hoursPerDay = Date.hoursPerDay()
|
||||
|
||||
local default_announcement_decay_hours = {
|
||||
[AnnouncementPriority.Critical] = -1, -- never decay
|
||||
[AnnouncementPriority.High] = 365*24,
|
||||
[AnnouncementPriority.Normal] = 31*24,
|
||||
[AnnouncementPriority.Low] = 7*24
|
||||
[AnnouncementPriority.High] = 31 * hoursPerDay,
|
||||
[AnnouncementPriority.Normal] = 7 * hoursPerDay,
|
||||
[AnnouncementPriority.Low] = 3 * hoursPerDay
|
||||
}
|
||||
|
||||
--! An announcement queue based on priority
|
||||
@@ -84,6 +87,22 @@ function AnnouncementQueue:isEmpty()
|
||||
return self.count == 0
|
||||
end
|
||||
|
||||
--! Checks for duplicates in the announcement queue and refreshes the announcement's created_date
|
||||
--!param sound the announcement to check
|
||||
--!param date the date to use, usually the current date
|
||||
function AnnouncementQueue:checkForDuplicates(sound, date)
|
||||
for _, entries in ipairs(self.priorities) do
|
||||
for _, entry in ipairs(entries) do
|
||||
if entry.name == sound then
|
||||
entry.created_date = date
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--! An announcement.
|
||||
class "AnnouncementEntry"
|
||||
|
||||
@@ -94,8 +113,8 @@ local AnnouncementEntry = _G["AnnouncementEntry"]
|
||||
function AnnouncementEntry:AnnouncementEntry()
|
||||
self.name = nil -- filename to play
|
||||
self.priority = default_announcement_priority
|
||||
self.created_tick = nil -- when it has been created
|
||||
self.decay_ticks = nil -- how long until the announcement isn't relevant anymore
|
||||
self.created_date = nil -- when it has been created
|
||||
self.decay_hours = nil -- how long until the announcement isn't relevant anymore
|
||||
self.played_callback = nil -- call me whenever the sound was played, ...
|
||||
self.played_callback_delay = nil -- but not until delay has passed
|
||||
end
|
||||
@@ -137,8 +156,15 @@ function Announcer:playAnnouncement(name, priority, decay_hours, played_callback
|
||||
-- It doesn't make sense to play the sacked announcement when the employee
|
||||
-- already has had several other jobs and has died already [joke].
|
||||
|
||||
-- Check for duplicate announcements, if there is we refresh the existing one
|
||||
local created_date = self.app.world:date()
|
||||
local duplicate_announcement = self.entries:checkForDuplicates(name, created_date)
|
||||
if duplicate_announcement then
|
||||
return
|
||||
end
|
||||
|
||||
local new_priority = priority or default_announcement_priority
|
||||
local created_date = self.app.world.game_date:clone()
|
||||
|
||||
local new_decay_hours = decay_hours or default_announcement_decay_hours[new_priority]
|
||||
|
||||
local entry = AnnouncementEntry()
|
||||
@@ -149,13 +175,17 @@ function Announcer:playAnnouncement(name, priority, decay_hours, played_callback
|
||||
entry.played_callback = played_callback
|
||||
entry.played_callback_delay = played_callback_delay
|
||||
|
||||
self.entries:push(new_priority, entry)
|
||||
if self.app.world:getLocalPlayerHospital():hasStaffedDesk() or priority == AnnouncementPriority.Critical then
|
||||
self.entries:push(new_priority, entry)
|
||||
end
|
||||
end
|
||||
|
||||
--! The announcer's (game) tick handler.
|
||||
-- Plays the actual sound of the announcements, if available.
|
||||
-- Also queues random announcements if no announcements have been played for a while.
|
||||
function Announcer:onTick()
|
||||
local staffedDesk = self.app.world:getLocalPlayerHospital():hasStaffedDesk()
|
||||
local criticalAnnounces = #self.entries.priorities[AnnouncementPriority.Critical]
|
||||
if not self.app.world:isCurrentSpeed("Pause") then
|
||||
local ticks_since_last_announcement = self.ticks_since_last_announcement
|
||||
if ticks_since_last_announcement >= self.random_announcement_ticks_target then
|
||||
@@ -164,19 +194,28 @@ function Announcer:onTick()
|
||||
else
|
||||
self.ticks_since_last_announcement = ticks_since_last_announcement + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Delay until someone is available at the desk
|
||||
if self.app.world:getLocalPlayerHospital():hasStaffedDesk() then
|
||||
while not self.playing and not self.entries:isEmpty() do
|
||||
local entry = self.entries:pop()
|
||||
local game_date = self.app.world.game_date
|
||||
-- Wait for an occupied desk or announcement is critical
|
||||
if staffedDesk or criticalAnnounces > 0 then
|
||||
while not self.playing and not self.entries:isEmpty() do
|
||||
local entry = self.entries:pop()
|
||||
local game_date = self.app.world:date()
|
||||
|
||||
if entry.decay_hours == -1 or game_date <= entry.created_date:plusHours(entry.decay_hours) then
|
||||
if self.app.config.play_announcements then
|
||||
self:_play(entry)
|
||||
if entry.decay_hours == -1 or game_date <= entry.created_date:plusHours(entry.decay_hours) then
|
||||
if self.app.config.play_announcements then
|
||||
self:_play(entry)
|
||||
end
|
||||
-- Drain the queue otherwise
|
||||
end
|
||||
-- Drain the queue otherwise
|
||||
end
|
||||
end
|
||||
-- The game is paused
|
||||
else
|
||||
-- Only play critical announcements when paused
|
||||
while not self.playing and not self.entries:isEmpty() and criticalAnnounces > 0 do
|
||||
local entry = self.entries:pop()
|
||||
if self.app.config.play_announcements then
|
||||
self:_play(entry)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -32,4 +32,4 @@ Note: This file compiles as both Lua and C++. */
|
||||
|
||||
#endif /*]]--*/
|
||||
|
||||
return 2678;
|
||||
return 2679;
|
||||
|
@@ -28,7 +28,7 @@ local runDebugger = corsixth.require("run_debugger")
|
||||
-- Increment each time a savegame break would occur
|
||||
-- and add compatibility code in afterLoad functions
|
||||
|
||||
local SAVEGAME_VERSION = 138
|
||||
local SAVEGAME_VERSION = 155
|
||||
|
||||
class "App"
|
||||
|
||||
@@ -121,10 +121,13 @@ function App:init()
|
||||
self:initScreenshotsDir()
|
||||
|
||||
-- Create the window
|
||||
if not SDL.init("audio", "video", "timer") then
|
||||
if not SDL.init("video", "timer") then
|
||||
return false, "Cannot initialise SDL"
|
||||
end
|
||||
local compile_opts = TH.GetCompileOptions()
|
||||
if compile_opts.audio then
|
||||
SDL.init("audio")
|
||||
end
|
||||
local api_version = corsixth.require("api_version")
|
||||
if api_version ~= compile_opts.api_version then
|
||||
api_version = api_version or 0
|
||||
@@ -137,6 +140,11 @@ function App:init()
|
||||
end
|
||||
end
|
||||
|
||||
-- Report operating system
|
||||
if compile_opts.os then
|
||||
self.os = compile_opts.os
|
||||
end
|
||||
|
||||
local modes = {}
|
||||
if compile_opts.renderer == "OpenGL" then
|
||||
modes[#modes + 1] = "opengl"
|
||||
@@ -316,6 +324,18 @@ function App:init()
|
||||
"Please make sure you have specified a font file in the config file."}))
|
||||
end
|
||||
|
||||
-- If the player wants to continue then load the youngest file in the Autosaves folder
|
||||
-- If they give a month number then load that month's autosave
|
||||
if self.command_line.continue then
|
||||
local num = self.command_line.continue
|
||||
local file = "Autosaves" .. pathsep .. "Autosave" .. num .. ".sav"
|
||||
if num >= "1" and num <= "12" and lfs.attributes(self.savegame_dir .. file, "size") then
|
||||
self.command_line.load = file
|
||||
else
|
||||
self.command_line.load = "Autosaves" .. pathsep ..
|
||||
FileTreeNode(self.savegame_dir .. "Autosaves"):getMostRecentlyModifiedChildFile(".sav").label
|
||||
end
|
||||
end
|
||||
-- If a savegame was specified, load it
|
||||
if self.command_line.load then
|
||||
local status, err = pcall(self.load, self, self.savegame_dir .. self.command_line.load)
|
||||
@@ -606,21 +626,7 @@ function App:loadLevel(level, difficulty, level_name, level_file, level_intro, m
|
||||
return
|
||||
end
|
||||
-- If going from another level, save progress.
|
||||
local carry_to_next_level
|
||||
if self.world and self.world.campaign_info then
|
||||
carry_to_next_level = {
|
||||
world = {
|
||||
room_built = self.world.room_built,
|
||||
campaign_info = self.world.campaign_info,
|
||||
},
|
||||
hospital = {
|
||||
player_salary = self.ui.hospital.player_salary,
|
||||
message_popup = self.ui.hospital.message_popup,
|
||||
hospital_littered = self.ui.hospital.hospital_littered,
|
||||
has_seen_pay_rise = self.ui.hospital.has_seen_pay_rise,
|
||||
},
|
||||
}
|
||||
end
|
||||
local campaign_data = self.world and self.world:getCampaignData()
|
||||
|
||||
-- Make sure there is no blue filter active.
|
||||
self.video:setBlueFilterActive(false)
|
||||
@@ -646,13 +652,9 @@ function App:loadLevel(level, difficulty, level_name, level_file, level_intro, m
|
||||
self.ui = GameUI(self, self.world:getLocalPlayerHospital(), map_editor)
|
||||
self.world:setUI(self.ui) -- Function call allows world to set up its keyHandlers
|
||||
|
||||
if tonumber(level) then
|
||||
self.moviePlayer:playAdvanceMovie(level)
|
||||
end
|
||||
|
||||
-- Now restore progress from previous levels.
|
||||
if carry_to_next_level then
|
||||
self.world:initFromPreviousLevel(carry_to_next_level)
|
||||
if campaign_data then
|
||||
self.world:setCampaignData(campaign_data)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -730,7 +732,7 @@ function App:dumpStrings()
|
||||
|
||||
self:checkMissingStringsInLanguage(dir, self.config.language)
|
||||
-- Uncomment these lines to get diffs for all languages in the game
|
||||
-- for _, lang in ipairs(self.strings.languages_english) do
|
||||
-- for _, lang in pairs(self.strings.languages_english) do
|
||||
-- self:checkMissingStringsInLanguage(dir, lang)
|
||||
-- end
|
||||
print("")
|
||||
@@ -746,7 +748,6 @@ end
|
||||
--!param dir The directory where the file to write to should be.
|
||||
--!param language The language to check against.
|
||||
function App:checkMissingStringsInLanguage(dir, language)
|
||||
|
||||
-- Accessors to reach through the userdata proxies on strings
|
||||
local LUT = debug.getregistry().StringProxyValues
|
||||
local function val(o)
|
||||
@@ -788,7 +789,7 @@ function App:checkMissingStringsInLanguage(dir, language)
|
||||
|
||||
-- if possible, use the English name of the language for the file name.
|
||||
local language_english = language
|
||||
for _, lang_eng in ipairs(self.strings.languages_english) do
|
||||
for _, lang_eng in pairs(self.strings.languages_english) do
|
||||
if ltc[language] == ltc[lang_eng:lower()] then
|
||||
language_english = lang_eng
|
||||
break
|
||||
@@ -853,7 +854,8 @@ end
|
||||
|
||||
function App:saveConfig()
|
||||
-- Load lines from config file
|
||||
local fi = io.open(self.command_line["config-file"] or "config.txt", "r")
|
||||
local config_file = self.command_line["config-file"] or "config.txt"
|
||||
local fi = io.open(config_file, "r")
|
||||
local lines = {}
|
||||
local handled_ids = {}
|
||||
if fi then
|
||||
@@ -904,13 +906,29 @@ function App:saveConfig()
|
||||
lines[#lines] = nil
|
||||
end
|
||||
|
||||
fi = io.open(self.command_line["config-file"] or "config.txt", "w")
|
||||
fi = self:writeToFileOrTmp(config_file)
|
||||
for _, line in ipairs(lines) do
|
||||
fi:write(line .. "\n")
|
||||
end
|
||||
fi:close()
|
||||
end
|
||||
|
||||
--! Tries to open the given file or a file in OS's temp dir.
|
||||
-- Returns the file handler
|
||||
--!param file The full path of the intended file
|
||||
--!param mode The mode in which the file is opened, defaults to write
|
||||
function App:writeToFileOrTmp(file, mode)
|
||||
local f, err = io.open(file, mode or "w")
|
||||
if err then
|
||||
local tmp_file = os.tmpname()
|
||||
f = io.open(tmp_file, mode or "w")
|
||||
self.ui:addWindow(UIInformation(self.ui,
|
||||
{_S.errors.save_to_tmp:format(file, tmp_file, err)}))
|
||||
end
|
||||
assert(f, "Error: cannot write to filesystem")
|
||||
return f
|
||||
end
|
||||
|
||||
function App:fixHotkeys()
|
||||
-- Fill in default values for things which don't exist
|
||||
local hotkeys_defaults = select(4, corsixth.require("config_finder"))
|
||||
@@ -934,7 +952,8 @@ end
|
||||
|
||||
function App:saveHotkeys()
|
||||
-- Load lines from config file
|
||||
local fi = io.open(self.command_line["hotkeys-file"] or "hotkeys.txt", "r")
|
||||
local hotkeys_filename = self.command_line["hotkeys-file"] or "hotkeys.txt"
|
||||
local fi = io.open(hotkeys_filename, "r")
|
||||
local lines = {}
|
||||
local handled_ids = {}
|
||||
|
||||
@@ -988,7 +1007,7 @@ function App:saveHotkeys()
|
||||
lines[#lines] = nil
|
||||
end
|
||||
|
||||
fi = io.open(self.command_line["hotkeys-file"] or "hotkeys.txt", "w")
|
||||
fi = self:writeToFileOrTmp(hotkeys_filename)
|
||||
for _, line in ipairs(lines) do
|
||||
fi:write(line .. "\n")
|
||||
end
|
||||
@@ -1035,6 +1054,7 @@ function App:run()
|
||||
local e, where = SDL.mainloop(co)
|
||||
debug.sethook(co, nil)
|
||||
self.running = false
|
||||
self.video:setCaptureMouse(false) -- Free the mouse, so the user can eg close the window.
|
||||
if e ~= nil then
|
||||
if where then
|
||||
-- Errors from an asynchronous callback done on the dispatcher coroutine
|
||||
@@ -1203,6 +1223,21 @@ function App:onMultiGesture(...)
|
||||
return self.ui:onMultiGesture(...)
|
||||
end
|
||||
|
||||
function App:isThemeHospitalPath(path)
|
||||
local ngot = 0
|
||||
for obj, _ in lfs.dir(path) do
|
||||
for _, thing in ipairs({"data", "levels", "qdata"}) do
|
||||
if obj:lower() == thing and
|
||||
lfs.attributes(path .. pathsep .. obj, "mode") == "directory" then
|
||||
ngot = ngot + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if ngot == 3 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function App:checkInstallFolder()
|
||||
self.fs = FileSystem()
|
||||
local status, _
|
||||
@@ -1213,10 +1248,41 @@ function App:checkInstallFolder()
|
||||
" a valid copy of the data files from the original game," ..
|
||||
" as said files are required for graphics and sounds."
|
||||
if not status then
|
||||
-- If the given directory didn't exist, then likely the config file hasn't
|
||||
-- been changed at all from the default, so we continue to initialise the
|
||||
-- app, and give the user a dialog asking for the correct directory.
|
||||
return false
|
||||
-- Table of predictable places. First three are platform independent,
|
||||
-- then macOS app and its parent folder, GOG bundle,
|
||||
-- then linux Filesystem Hierarchy Standard, then Windows Program Files
|
||||
-- mac_app_dir is the macOS app base directory named CorsixTH.app
|
||||
local mac_app_dir = debug.getinfo(1).short_src:match("(.*)/Contents/.")
|
||||
local user_dir = os.getenv("HOME") or os.getenv("HOMEPATH") or ""
|
||||
local possible_locations = { user_dir, user_dir .. pathsep .. "Documents",
|
||||
select(1, corsixth.require("config_finder")):match("(.*[/\\])"):sub(1, -2),
|
||||
mac_app_dir, mac_app_dir and mac_app_dir:match("(.*)/.*%.app"),
|
||||
"/Applications/Theme Hospital.app/Contents/Resources/game/Theme Hospital.app/" ..
|
||||
"Contents/Resources/Theme Hospital.boxer/C.harddisk",
|
||||
"/usr/share/games/corsix-th", "/usr/local/share/games/corsix-th",
|
||||
os.getenv("ProgramFiles"), os.getenv("ProgramFiles(x86)") }
|
||||
local possible_folders = { "ThemeHospital", "Theme Hospital", "HOSP", "TH97",
|
||||
[[GOG.com\Theme Hospital]], [[Origin Games\Theme Hospital\data\Game]] }
|
||||
for _, dir in ipairs(possible_locations) do
|
||||
if status then break end
|
||||
for _, folder in ipairs(possible_folders) do
|
||||
local path = dir .. pathsep .. folder
|
||||
if lfs.attributes(path, "mode") == "directory" and self:isThemeHospitalPath(path) then
|
||||
print("Game data found at: " .. path)
|
||||
print("This will be written to the config file")
|
||||
self.config.theme_hospital_install = path
|
||||
status, _ = self.fs:setRoot(path)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not status then
|
||||
-- If the given directory didn't exist, then likely the config file hasn't
|
||||
-- been changed at all from the default, and we looked unsuccessfully in
|
||||
-- some likely folders for the game data, so we continue to initialise the
|
||||
-- app, and give the user a dialog asking for the correct directory.
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- Check that a few core files are present
|
||||
@@ -1403,7 +1469,7 @@ function App:getVersion(version)
|
||||
if ver > 138 then
|
||||
return "Trunk"
|
||||
elseif ver > 134 then
|
||||
return "v0.64-rc1"
|
||||
return "v0.64"
|
||||
elseif ver > 127 then
|
||||
return "v0.63"
|
||||
elseif ver > 122 then
|
||||
@@ -1460,6 +1526,19 @@ function App:quickLoad()
|
||||
end
|
||||
end
|
||||
|
||||
--! Function to check the loaded game is compatible with the program
|
||||
--!param save_version (num)
|
||||
--!return true if compatible, otherwise false
|
||||
function App:checkCompatibility(save_version)
|
||||
local app_version = self.savegame_version
|
||||
if app_version >= save_version or self.config.debug then
|
||||
return true
|
||||
else
|
||||
UILoadGame:loadError(_S.errors.compatibility_error)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--! Restarts the current level (offers confirmation window first)
|
||||
function App:restart()
|
||||
assert(self.map, "Trying to restart while no map is loaded.")
|
||||
@@ -1519,20 +1598,27 @@ function App:afterLoad()
|
||||
self.world.original_savegame_version = old
|
||||
end
|
||||
local first = self.world.original_savegame_version
|
||||
|
||||
-- Generate the human-readable version number (old [loaded save], new [program], first [original])
|
||||
local first_version = first .. " (" .. self:getVersion(first) .. ")"
|
||||
local old_version = old .. " (" .. self:getVersion(old) .. ")"
|
||||
local new_version = new .. " (" .. self:getVersion() .. ")"
|
||||
|
||||
if new == old then
|
||||
self.world:gameLog("Savegame version is " .. new .. " (" .. self:getVersion() ..
|
||||
"), originally it was " .. first .. " (" .. self:getVersion(first) .. ")")
|
||||
local msg_same = "Savegame version is %s, originally it was %s."
|
||||
self.world:gameLog(msg_same:format(new_version, first_version))
|
||||
self.world:playLoadedEntitySounds()
|
||||
elseif new > old then
|
||||
self.world:gameLog("Savegame version changed from " .. old .. " (" .. self:getVersion(old) ..
|
||||
") to " .. new .. " (" .. self:getVersion() ..
|
||||
"). The save was created using " .. first ..
|
||||
" (" .. self:getVersion(first) .. ")")
|
||||
else
|
||||
-- TODO: This should maybe be forbidden completely.
|
||||
self.world:gameLog("Warning: loaded savegame version " .. old .. " (" .. self:getVersion(old) ..
|
||||
")" .. " in older version " .. new .. " (" .. self:getVersion() .. ").")
|
||||
local msg_older = "Savegame changed from %s to %s. The save was created using %s."
|
||||
self.world:gameLog(msg_older:format(old_version, new_version, first_version))
|
||||
else -- Save is newer than the game and can only proceed in debug mode
|
||||
local get_old_release_version = self.world.release_version or "Trunk" -- For compatibility
|
||||
old_version = old .. " (" .. get_old_release_version .. ")"
|
||||
local msg_newer = "Warning: loaded savegame version %s in older version %s."
|
||||
self.world:gameLog(msg_newer:format(old_version, new_version))
|
||||
self.ui:addWindow(UIInformation(self.ui, {_S.warnings.newersave}))
|
||||
end
|
||||
self.world.release_version = self:getVersion()
|
||||
self.world.savegame_version = new
|
||||
|
||||
if old < 87 then
|
||||
@@ -1561,11 +1647,11 @@ function App:checkForUpdates()
|
||||
|
||||
-- Default language to use for the changelog if no localised version is available
|
||||
local default_language = "en"
|
||||
local update_url = 'www.corsixth.com/check-for-updates'
|
||||
local update_url = 'https://corsixth.github.io/CorsixTH/check-for-updates'
|
||||
local current_version = self:getVersion()
|
||||
|
||||
-- Only URLs that match this list of trusted domains will be accepted.
|
||||
local trusted_domains = { 'corsixth.com', 'code.google.com' }
|
||||
local trusted_domains = { 'corsixth.com', 'github.com', 'corsixth.github.io' }
|
||||
|
||||
-- Only check for updates against released versions
|
||||
if current_version == "Trunk" then
|
||||
@@ -1573,26 +1659,15 @@ function App:checkForUpdates()
|
||||
return
|
||||
end
|
||||
|
||||
local success, _ = pcall(require, "socket")
|
||||
|
||||
if not success then
|
||||
-- LuaSocket is not available, just return
|
||||
print("Cannot check for updates since LuaSocket is not available.")
|
||||
local luasocket, _ = pcall(require, "socket")
|
||||
local luasec, _ = pcall(require, "ssl.https")
|
||||
if not (luasocket and luasec) then
|
||||
print("Cannot check for updates since LuaSocket and/or LuaSec are not available.")
|
||||
return
|
||||
else
|
||||
self.lua_socket_available = true
|
||||
end
|
||||
local http = require("socket.http")
|
||||
local url = require("socket.url")
|
||||
|
||||
-- Safely attempt to use luasec
|
||||
local hassec, _ = pcall(require, "ssl.https")
|
||||
if hassec then
|
||||
update_url = "https://" .. update_url
|
||||
else
|
||||
update_url = "http://" .. update_url
|
||||
end
|
||||
|
||||
print("Checking for CorsixTH updates...")
|
||||
local update_body, status, _ = http.request(update_url)
|
||||
|
||||
@@ -1653,6 +1728,10 @@ function App:finishVideoUpdate()
|
||||
self.video:startFrame()
|
||||
end
|
||||
|
||||
function App:isAudioEnabled()
|
||||
return TH.GetCompileOptions().audio
|
||||
end
|
||||
|
||||
-- Do not remove, for savegame compatibility < r1891
|
||||
local app_confirm_quit_stub = --[[persistable:app_confirm_quit]] function()
|
||||
end
|
||||
|
@@ -25,9 +25,13 @@ local configuration = {
|
||||
-----------------------------------------------------------
|
||||
-- New configuration values added in CorsixTH --
|
||||
-----------------------------------------------------------
|
||||
-- Interest rate and overdraft interest rate differential values will
|
||||
-- be divided by 10,000
|
||||
town = {
|
||||
InterestRate = 0.01,
|
||||
InterestRate = 100,
|
||||
StartCash = 40000,
|
||||
StartRep = 500,
|
||||
OverdraftDiff = 200,
|
||||
},
|
||||
|
||||
-- New value, but should only be defined if starting staff is included.
|
||||
@@ -133,19 +137,19 @@ local configuration = {
|
||||
},
|
||||
|
||||
towns = {
|
||||
{StartCash = 40000, InterestRate = 100}, -- Level 1
|
||||
{StartCash = 40000, InterestRate = 200}, -- Level 2
|
||||
{StartCash = 50000, InterestRate = 300}, -- Level 3
|
||||
{StartCash = 50000, InterestRate = 400}, -- Level 4
|
||||
{StartCash = 50000, InterestRate = 500}, -- Level 5
|
||||
{StartCash = 50000, InterestRate = 600}, -- Level 6
|
||||
{StartCash = 50000, InterestRate = 700}, -- Level 7
|
||||
{StartCash = 60000, InterestRate = 700}, -- Level 8
|
||||
{StartCash = 60000, InterestRate = 800}, -- Level 9
|
||||
{StartCash = 60000, InterestRate = 800}, -- Level 10
|
||||
{StartCash = 70000, InterestRate = 900}, -- Level 11
|
||||
{StartCash = 70000, InterestRate = 900}, -- Level 12
|
||||
{StartCash = 70000, InterestRate = 900}, -- Level 12
|
||||
{StartCash = 40000, InterestRate = 100, StartRep = 500, OverdraftDiff = 200}, -- Level 1
|
||||
{StartCash = 40000, InterestRate = 200, StartRep = 500, OverdraftDiff = 200}, -- Level 2
|
||||
{StartCash = 50000, InterestRate = 300, StartRep = 500, OverdraftDiff = 200}, -- Level 3
|
||||
{StartCash = 50000, InterestRate = 400, StartRep = 500, OverdraftDiff = 200}, -- Level 4
|
||||
{StartCash = 50000, InterestRate = 500, StartRep = 500, OverdraftDiff = 200}, -- Level 5
|
||||
{StartCash = 50000, InterestRate = 600, StartRep = 500, OverdraftDiff = 200}, -- Level 6
|
||||
{StartCash = 50000, InterestRate = 700, StartRep = 500, OverdraftDiff = 200}, -- Level 7
|
||||
{StartCash = 60000, InterestRate = 700, StartRep = 500, OverdraftDiff = 200}, -- Level 8
|
||||
{StartCash = 60000, InterestRate = 800, StartRep = 500, OverdraftDiff = 200}, -- Level 9
|
||||
{StartCash = 60000, InterestRate = 800, StartRep = 500, OverdraftDiff = 200}, -- Level 10
|
||||
{StartCash = 70000, InterestRate = 900, StartRep = 500, OverdraftDiff = 200}, -- Level 11
|
||||
{StartCash = 70000, InterestRate = 900, StartRep = 500, OverdraftDiff = 200}, -- Level 12
|
||||
{StartCash = 70000, InterestRate = 900, StartRep = 500, OverdraftDiff = 200}, -- Level 12
|
||||
},
|
||||
popn = {
|
||||
[0] = {Month = 0, Change = 4}, -- Standard: 4 patients the first month.
|
||||
@@ -372,21 +376,21 @@ local configuration = {
|
||||
[0] = {StartMonth = 0, EndMonth = 0, Min = 0, Max = 0, Illness = 0, PercWin = 0, Bonus = 0},
|
||||
},
|
||||
computer = {
|
||||
[0] = {Playing = 0}, -- ORAC
|
||||
{Playing = 0}, -- COLOSSUS
|
||||
{Playing = 0}, -- HAL
|
||||
{Playing = 0}, -- MULTIVAC
|
||||
{Playing = 0}, -- HOLLY
|
||||
{Playing = 0}, -- DEEP THOUGHT
|
||||
{Playing = 0}, -- ZEN
|
||||
{Playing = 0}, -- SKYNET
|
||||
{Playing = 0}, -- MARVIN
|
||||
{Playing = 0}, -- CEREBRO
|
||||
{Playing = 0}, -- MOTHER
|
||||
{Playing = 0}, -- JAYNE
|
||||
{Playing = 0}, -- CORSIX
|
||||
{Playing = 0}, -- ROUJIN
|
||||
{Playing = 0}, -- EDVIN
|
||||
[0] = {Playing = 0, Name = "ORAC"},
|
||||
{Playing = 0, Name = "COLOSSUS"},
|
||||
{Playing = 0, Name = "HAL"},
|
||||
{Playing = 0, Name = "MULTIVAC"},
|
||||
{Playing = 0, Name = "HOLLY"},
|
||||
{Playing = 0, Name = "DEEP THOUGHT"},
|
||||
{Playing = 0, Name = "ZEN"},
|
||||
{Playing = 0, Name = "SKYNET"},
|
||||
{Playing = 0, Name = "MARVIN"},
|
||||
{Playing = 0, Name = "CEREBRO"},
|
||||
{Playing = 0, Name = "MOTHER"},
|
||||
{Playing = 0, Name = "JAYNE"},
|
||||
{Playing = 0, Name = "CORSIX"},
|
||||
{Playing = 0, Name = "ROUJIN"},
|
||||
{Playing = 0, Name = "EDVIN"},
|
||||
},
|
||||
awards_trophies = {
|
||||
|
||||
@@ -427,9 +431,11 @@ local configuration = {
|
||||
PlantBonus = 5,
|
||||
-- Bonus - MIN 0 MAX 255 (REP BONUS)
|
||||
TrophyStaffHappinessBonus = 5,
|
||||
-- Bonus to money for curing every patient, no deaths or send-homes (MONEY BONUS)
|
||||
TrophyAllCuredBonus = 20000,
|
||||
-- Bonus to money for NO DEATHS in the year (MONEY BONUS)
|
||||
TrophyDeathBonus = 10000,
|
||||
-- Bonus to money for approximately 100% Cure Rate in the year (MONEY BONUS)
|
||||
-- Bonus to money for over 90% Cure Rate in the year (MONEY BONUS)
|
||||
TrophyCuresBonus = 6000,
|
||||
-- Bonus to reputation for pleasing VIPs in the year (REPUTATION BONUS)
|
||||
TrophyMayorBonus = 5,
|
||||
@@ -495,6 +501,8 @@ local configuration = {
|
||||
-- MIN -32000 MAX +32000 - MONEY
|
||||
CuresPenalty = -3000,
|
||||
-- MIN -32000 MAX +32000 - MONEY
|
||||
AllCuresBonus = 5000,
|
||||
-- MIN -32000 MAX +32000 - MONEY
|
||||
DeathsBonus = 3000,
|
||||
-- MIN -32000 MAX +32000 - MONEY
|
||||
DeathsPenalty = -5000,
|
||||
|
@@ -115,18 +115,12 @@ function CallsDispatcher:callForRepair(object, urgent, manual, lock_room)
|
||||
object:setRepairingMode(lock_room and true or false)
|
||||
local message
|
||||
local ui = object.world.ui
|
||||
if not object.world:getLocalPlayerHospital():hasStaffOfCategory("Handyman") then
|
||||
if object.world:getLocalPlayerHospital():countStaffOfCategory("Handyman", 1) == 0 then
|
||||
-- Advise about hiring Handyman
|
||||
message = _A.warnings.machinery_damaged2
|
||||
end
|
||||
|
||||
if not manual and urgent then
|
||||
local room = object:getRoom()
|
||||
local sound = room.room_info.handyman_call_sound
|
||||
if sound then
|
||||
ui:playAnnouncement(sound, AnnouncementPriority.High)
|
||||
ui:playSound("machwarn.wav")
|
||||
end
|
||||
message = _A.warnings.machines_falling_apart
|
||||
end
|
||||
if message then
|
||||
@@ -523,7 +517,7 @@ function CallsDispatcher.getPriorityForRoom(room, attribute, staff)
|
||||
end
|
||||
end
|
||||
|
||||
-- Prefer the tirer staff (such that less chance to have "resting sychronization issue")
|
||||
-- Prefer the tirer staff (such that less chance to have "resting synchronization issue")
|
||||
score = score - staff.attributes["fatigue"] * 40 -- 40 is just a weighting scale
|
||||
|
||||
-- TODO: Assign doctor with higher ability
|
||||
|
171
CorsixTH/Lua/cheats.lua
Normal file
171
CorsixTH/Lua/cheats.lua
Normal file
@@ -0,0 +1,171 @@
|
||||
--[[ Copyright (c) 2010 Manuel "Roujin" Wolf
|
||||
Copyright (c) 2020 lewri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. --]]
|
||||
|
||||
corsixth.require("announcer")
|
||||
|
||||
local AnnouncementPriority = _G["AnnouncementPriority"]
|
||||
|
||||
--! A holder for all cheats in the game
|
||||
class "Cheats"
|
||||
|
||||
---@type Cheats
|
||||
local Cheats = _G["Cheats"]
|
||||
|
||||
-- Cheats System
|
||||
function Cheats:Cheats(hospital)
|
||||
self.hospital = hospital
|
||||
-- Cheats to appear specifically in the cheats window
|
||||
-- New cheats require a persistable and a wrapped function in func
|
||||
self.cheat_list = {
|
||||
{name = "money", func = self.cheatMoney},
|
||||
{name = "all_research", func = self.cheatResearch},
|
||||
{name = "emergency", func = self.cheatEmergency},
|
||||
{name = "epidemic", func = self.cheatEpidemic},
|
||||
{name = "toggle_infected", func = self.cheatToggleInfected},
|
||||
{name = "vip", func = self.cheatVip},
|
||||
{name = "earthquake", func = self.cheatEarthquake},
|
||||
{name = "create_patient", func = self.cheatPatient},
|
||||
{name = "end_month", func = self.cheatMonth},
|
||||
{name = "end_year", func = self.cheatYear},
|
||||
{name = "lose_level", func = self.cheatLose},
|
||||
{name = "win_level", func = self.cheatWin},
|
||||
{name = "increase_prices", func = self.cheatIncreasePrices},
|
||||
{name = "decrease_prices", func = self.cheatDecreasePrices},
|
||||
}
|
||||
end
|
||||
|
||||
--! Performs a cheat from the cheat_list
|
||||
--!param num (integer) The cheat from the cheat_list called
|
||||
--!return true if cheat was successful, false otherwise
|
||||
function Cheats:performCheat(num)
|
||||
local cheat_success = self.cheat_list[num].func(self) ~= false
|
||||
return cheat_success and self.cheat_list[num].name ~= "lose_level"
|
||||
end
|
||||
|
||||
--! Updates the cheated status of the player, with a matching announcement
|
||||
function Cheats:announceCheat()
|
||||
local announcements = self.hospital.world.cheat_announcements
|
||||
if announcements then
|
||||
self.hospital.world.ui:playAnnouncement(announcements[math.random(1, #announcements)], AnnouncementPriority.Critical)
|
||||
end
|
||||
self.hospital.cheated = true
|
||||
end
|
||||
|
||||
function Cheats:cheatMoney()
|
||||
self.hospital:receiveMoney(10000, _S.transactions.cheat)
|
||||
end
|
||||
|
||||
function Cheats:cheatResearch()
|
||||
local hosp = self.hospital
|
||||
for _, cat in ipairs({"diagnosis", "cure"}) do
|
||||
while hosp.research.research_policy[cat].current do
|
||||
hosp.research:discoverObject(hosp.research.research_policy[cat].current)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Cheats:cheatEmergency()
|
||||
local err = self.hospital:createEmergency()
|
||||
local ui = self.hospital.world.ui
|
||||
if err == "undiscovered_disease" then
|
||||
ui:addWindow(UIInformation(ui, {_S.misc.cant_treat_emergency}))
|
||||
elseif err == "no_heliport" then
|
||||
ui:addWindow(UIInformation(ui, {_S.misc.no_heliport}))
|
||||
-- else 'err == nil', meaning success. The case doesn't need special handling
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Creates a new contagious patient in the hospital - potentially an epidemic]]
|
||||
function Cheats:cheatEpidemic()
|
||||
self.hospital:spawnContagiousPatient()
|
||||
end
|
||||
|
||||
--[[ Before an epidemic has been revealed toggle the infected icons
|
||||
to easily distinguish the infected patients -- will toggle icons
|
||||
for ALL future epidemics you cannot distinguish between epidemics
|
||||
by disease ]]
|
||||
function Cheats:cheatToggleInfected()
|
||||
local hosp = self.hospital
|
||||
if hosp.future_epidemics_pool and #hosp.future_epidemics_pool > 0 then
|
||||
for _, future_epidemic in ipairs(hosp.future_epidemics_pool) do
|
||||
local show_mood = future_epidemic.cheat_always_show_mood
|
||||
future_epidemic.cheat_always_show_mood = not show_mood
|
||||
local mood_action = show_mood and "deactivate" or "activate"
|
||||
for _, patient in ipairs(future_epidemic.infected_patients) do
|
||||
patient:setMood("epidemy4",mood_action)
|
||||
end
|
||||
end
|
||||
else
|
||||
self.hospital.world:gameLog("Unable to toggle icons - no epidemics in progress that are not revealed")
|
||||
end
|
||||
end
|
||||
|
||||
function Cheats:cheatVip()
|
||||
self.hospital:createVip()
|
||||
end
|
||||
|
||||
function Cheats:cheatEarthquake()
|
||||
return self.hospital.world:createEarthquake()
|
||||
end
|
||||
|
||||
function Cheats:cheatPatient()
|
||||
self.hospital.world:spawnPatient()
|
||||
end
|
||||
|
||||
function Cheats:cheatMonth()
|
||||
self.hospital.world:setEndMonth()
|
||||
end
|
||||
|
||||
function Cheats:cheatYear()
|
||||
self.hospital.world:setEndYear()
|
||||
end
|
||||
|
||||
function Cheats:cheatLose()
|
||||
self.hospital.world:loseGame(1) -- TODO adjust for multiplayer
|
||||
end
|
||||
|
||||
function Cheats:cheatWin()
|
||||
self.hospital.world:winGame(1) -- TODO adjust for multiplayer
|
||||
end
|
||||
|
||||
function Cheats:cheatIncreasePrices()
|
||||
local hosp = self.hospital
|
||||
for _, casebook in pairs(hosp.disease_casebook) do
|
||||
local new_price = casebook.price + 0.5
|
||||
if new_price > 2 then
|
||||
casebook.price = 2
|
||||
else
|
||||
casebook.price = new_price
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Cheats:cheatDecreasePrices()
|
||||
local hosp = self.hospital
|
||||
for _, casebook in pairs(hosp.disease_casebook) do
|
||||
local new_price = casebook.price - 0.5
|
||||
if new_price < 0.5 then
|
||||
casebook.price = 0.5
|
||||
else
|
||||
casebook.price = new_price
|
||||
end
|
||||
end
|
||||
end
|
@@ -120,6 +120,7 @@ local config_defaults = {
|
||||
alien_dna_can_knock_on_doors = false,
|
||||
disable_fractured_bones_females = true,
|
||||
enable_avg_contents = false,
|
||||
remove_destroyed_rooms = false,
|
||||
audio_frequency = 22050,
|
||||
audio_channels = 2,
|
||||
audio_buffer_size = 2048,
|
||||
@@ -138,6 +139,7 @@ local config_defaults = {
|
||||
new_graphics_folder = nil,
|
||||
use_new_graphics = false,
|
||||
check_for_updates = true,
|
||||
room_information_dialogs = true
|
||||
}
|
||||
|
||||
fi = io.open(config_filename, "r")
|
||||
@@ -172,9 +174,7 @@ else
|
||||
end
|
||||
|
||||
if needs_rewrite then
|
||||
fi = io.open(config_filename, "w")
|
||||
if fi then
|
||||
fi:write([=[
|
||||
local string_01 = [=[
|
||||
----------------------------------------- CorsixTH configuration file -------------------------------------------
|
||||
-- Lines starting with two dashes (like this one) are ignored.
|
||||
-- Text settings should have their values between double square braces, e.g.
|
||||
@@ -360,6 +360,13 @@ if needs_rewrite then
|
||||
-- If you would like the game to remember what you usually add, then change this option to true.
|
||||
-- ]=] .. '\n' ..
|
||||
'enable_avg_contents = ' .. tostring(config_values.enable_avg_contents) .. '\n' .. [=[
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
-- By default destroyed rooms can't be removed.
|
||||
-- If you would like the game to give you the option of removing a destroyed room change this option to true.
|
||||
-- ]=] .. '\n' ..
|
||||
'remove_destroyed_rooms = ' .. tostring(config_values.remove_destroyed_rooms) .. '\n' .. [=[]=]
|
||||
|
||||
local string_02 = [=[
|
||||
|
||||
----------------------------------------------- FOLDER SETTINGS ----------------------------------------------
|
||||
-- These settings can also be changed from the Folders Menu
|
||||
@@ -482,6 +489,19 @@ audio_music = nil -- [[X:\ThemeHospital\Music]]
|
||||
'scroll_speed = ' .. tostring(config_values.scroll_speed) .. '\n' ..
|
||||
'shift_scroll_speed = ' .. tostring(config_values.shift_scroll_speed) .. '\n' .. [=[
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
-- Room information dialogs: Information about new rooms, important for
|
||||
-- additional rooms in later levels. Affects campaign only.
|
||||
-- ]=] .. '\n' ..
|
||||
'room_information_dialogs = ' .. tostring(config_values.room_information_dialogs) .. '\n' .. [=[
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
-- If true, parts of the hospital can be made inaccessible by blocking the path
|
||||
-- with rooms or objects. If false, all parts of the hospital must be kept
|
||||
-- accessible, the game will disallow any attempt to blocking the path.
|
||||
-- ]=] .. '\n' ..
|
||||
'allow_blocking_off_areas = ' .. tostring(config_values.allow_blocking_off_areas) .. '\n' .. [=[
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -497,9 +517,10 @@ audio_music = nil -- [[X:\ThemeHospital\Music]]
|
||||
-- you play the game.
|
||||
-------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
]=])
|
||||
fi:close()
|
||||
end
|
||||
]=]
|
||||
fi = TheApp:writeToFileOrTmp(config_filename)
|
||||
fi:write(string_01 .. string_02)
|
||||
fi:close()
|
||||
end
|
||||
|
||||
-- Hotkey filename.
|
||||
@@ -523,8 +544,8 @@ local hotkeys_defaults = {
|
||||
global_runDebugScript = {"shift", "d"},
|
||||
global_screenshot = {"ctrl", "s"},
|
||||
global_stop_movie = "escape",
|
||||
global_window_close = "escape",
|
||||
global_stop_movie_alt = "q",
|
||||
global_window_close = "escape",
|
||||
global_window_close_alt = "q",
|
||||
ingame_showmenubar = "escape",
|
||||
ingame_showCheatWindow = "f11",
|
||||
@@ -797,11 +818,9 @@ local string_03 = [=[
|
||||
-- ]=] .. '\n' ..
|
||||
'ingame_patient_gohome = ' .. hotkeys_values.ingame_patient_gohome .. '\n' .. [=[
|
||||
]=]
|
||||
fi = io.open(hotkeys_filename, "w")
|
||||
if fi then
|
||||
fi:write(string_01 .. string_02 .. string_03)
|
||||
fi = TheApp:writeToFileOrTmp(hotkeys_filename)
|
||||
fi:write(string_01 .. string_02 .. string_03)
|
||||
fi:close()
|
||||
end
|
||||
end
|
||||
|
||||
for k, str_val in pairs(hotkeys_values) do
|
||||
|
@@ -261,16 +261,17 @@ function Date_mt.__eq(one, other)
|
||||
end
|
||||
|
||||
function Date_mt.__lt(one, other)
|
||||
if one._year == other._year then
|
||||
if one._month == other._month then
|
||||
if one._day == other._day then
|
||||
return one._hour < other._hour
|
||||
end
|
||||
return one._day < other._day
|
||||
end
|
||||
return one._month < other._month
|
||||
end
|
||||
return one._year < other._year
|
||||
if one._year ~= other._year then return one._year < other._year end
|
||||
if one._month ~= other._month then return one._month < other._month end
|
||||
if one._day ~= other._day then return one._day < other._day end
|
||||
return one._hour < other._hour
|
||||
end
|
||||
|
||||
function Date_mt.__le(one, other)
|
||||
if one._year ~= other._year then return one._year < other._year end
|
||||
if one._month ~= other._month then return one._month < other._month end
|
||||
if one._day ~= other._day then return one._day < other._day end
|
||||
return one._hour <= other._hour
|
||||
end
|
||||
|
||||
-- PRIVATE
|
||||
|
@@ -142,7 +142,9 @@ function UIBottomPanel:registerKeyHandlers()
|
||||
end
|
||||
|
||||
function UIBottomPanel:openJukebox()
|
||||
self.ui:addWindow(UIJukebox(self.ui.app))
|
||||
if self.ui.app.config.audio and self.ui.app:isAudioEnabled() then
|
||||
self.ui:addWindow(UIJukebox(self.ui.app))
|
||||
end
|
||||
end
|
||||
|
||||
function UIBottomPanel:openSave()
|
||||
@@ -484,6 +486,7 @@ function UIBottomPanel:createMessageWindow(index)
|
||||
if not message_info then
|
||||
return
|
||||
end
|
||||
-- Create the message window, note this does not show it to the player on creation.
|
||||
local alert_window = UIMessage(self.ui, 175, 1 + #message_windows * 30,
|
||||
onClose, message_info.type, message_info.message, message_info.owner, message_info.timeout, message_info.default_choice, message_info.callback)
|
||||
message_windows[#message_windows + 1] = alert_window
|
||||
@@ -863,9 +866,10 @@ function UIBottomPanel:afterLoad(old, new)
|
||||
end
|
||||
self.bank_button = self.buttons[1]:makeToggle()
|
||||
end
|
||||
-- Hotfix to force re-calculation of the money font (see issue #1193)
|
||||
self.money_font = self.ui.app.gfx:loadFont("QData", "Font05V")
|
||||
|
||||
self:registerKeyHandlers()
|
||||
|
||||
Window.afterLoad(self, old, new)
|
||||
end
|
||||
|
||||
|
@@ -96,22 +96,29 @@ function UIBuildRoom:UIBuildRoom(ui)
|
||||
_S.room_classes.clinics,
|
||||
_S.room_classes.facilities
|
||||
}
|
||||
self.category_rooms = {
|
||||
}
|
||||
|
||||
self:updateBuildableRooms()
|
||||
|
||||
self:makeTooltip(_S.tooltip.build_room_window.cost, 160, 228, 282, 242)
|
||||
end
|
||||
|
||||
--! Checks what rooms are now available to build
|
||||
function UIBuildRoom:updateBuildableRooms()
|
||||
local app = self.ui.app
|
||||
self.category_rooms = {}
|
||||
for i, category in ipairs({"diagnosis", "treatment", "clinics", "facilities"}) do
|
||||
local rooms = {}
|
||||
self.category_rooms[i] = rooms
|
||||
for _, room in ipairs(app.world.available_rooms) do
|
||||
for _, room_disc in pairs(self.ui.hospital.room_discoveries) do
|
||||
local room = room_disc.room
|
||||
-- NB: Unimplemented rooms are hidden unless in debug mode
|
||||
if (app.config.debug or room.class) and room.categories[category] and
|
||||
ui.hospital.discovered_rooms[room] then
|
||||
room_disc.is_discovered then
|
||||
rooms[#rooms + 1] = room
|
||||
end
|
||||
end
|
||||
table.sort(rooms, function(r1, r2) return r1.categories[category] < r2.categories[category] end)
|
||||
end
|
||||
|
||||
self:makeTooltip(_S.tooltip.build_room_window.cost, 160, 228, 282, 242)
|
||||
end
|
||||
|
||||
local cat_label_y = {21, 53, 84, 116}
|
||||
@@ -145,6 +152,7 @@ function UIBuildRoom:setCategory(index)
|
||||
self.ui:tutorialStep(3, 3, 2)
|
||||
end
|
||||
self.category_index = index
|
||||
self:updateBuildableRooms()
|
||||
self.list_title = _S.build_room_window.pick_room_type
|
||||
self.list = self.category_rooms[index]
|
||||
|
||||
|
@@ -69,6 +69,11 @@ function UIConfirmDialog:UIConfirmDialog(ui, text, callback_ok, callback_cancel)
|
||||
self:registerKeyHandlers()
|
||||
end
|
||||
|
||||
-- Confirm dialogs are used for errors and require the game to pause
|
||||
function UIConfirmDialog:mustPause()
|
||||
return true
|
||||
end
|
||||
|
||||
function UIConfirmDialog:registerKeyHandlers()
|
||||
self:addKeyHandler("global_confirm", self.ok)
|
||||
self:addKeyHandler("global_confirm_alt", self.ok)
|
||||
|
@@ -186,7 +186,7 @@ function UIEditRoom:cancel()
|
||||
end
|
||||
))
|
||||
else
|
||||
self:close()
|
||||
self:abortRoom()
|
||||
end
|
||||
self.ui:setCursor(self.ui.default_cursor)
|
||||
elseif self.phase == "objects" then
|
||||
@@ -595,9 +595,96 @@ function UIEditRoom:returnToWallPhase(early)
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove walls
|
||||
local function remove_wall_line(x, y, step_x, step_y, n_steps, layer, neigh_x, neigh_y, world)
|
||||
local map = world.map.th
|
||||
for _ = 1, n_steps do
|
||||
local existing = map:getCell(x, y, layer)
|
||||
-- Possibly add transparency.
|
||||
local flag = 0
|
||||
if world.ui.transparent_walls then
|
||||
flag = 1024
|
||||
end
|
||||
if world:getWallIdFromBlockId(existing) ~= "external" then
|
||||
local neighbour = world:getRoom(x + neigh_x, y + neigh_y)
|
||||
if neighbour then
|
||||
if neigh_x ~= 0 or neigh_y ~= 0 then
|
||||
local set = world:getWallSetFromBlockId(existing)
|
||||
local dir = world:getWallDirFromBlockId(existing)
|
||||
if set == "inside_tiles" then
|
||||
set = "outside_tiles"
|
||||
end
|
||||
map:setCell(x, y, layer, flag + world.wall_types[neighbour.room_info.wall_type][set][dir])
|
||||
end
|
||||
else
|
||||
map:setCell(x, y, layer, flag)
|
||||
end
|
||||
end
|
||||
x = x + step_x
|
||||
y = y + step_y
|
||||
end
|
||||
end
|
||||
|
||||
function UIEditRoom:removeRoom(save_objects, room, world)
|
||||
-- Remove any placed objects (add them to list again) when save_objects is true
|
||||
for x = room.x, room.x + room.width - 1 do
|
||||
for y = room.y, room.y + room.height - 1 do
|
||||
while true do
|
||||
-- get litter then any other object
|
||||
local obj = world:getObject(x, y, 'litter') or world:getObject(x, y)
|
||||
-- but we need to ignore doors
|
||||
if not obj or obj == room.door or class.is(obj, SwingDoor) then
|
||||
break
|
||||
end
|
||||
if obj.object_type.id == "litter" then -- Silently remove litter from the world.
|
||||
obj:remove()
|
||||
else
|
||||
if save_objects then
|
||||
local obj_state = obj:getState()
|
||||
world:destroyEntity(obj)
|
||||
if not obj.master then
|
||||
self:addObjects({{
|
||||
object = TheApp.objects[obj.object_type.id],
|
||||
state = obj_state,
|
||||
qty = 1
|
||||
}})
|
||||
end
|
||||
else
|
||||
-- just destroy it
|
||||
world:destroyEntity(obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- now doors
|
||||
world:destroyEntity(room.door)
|
||||
if room.door2 then
|
||||
world:destroyEntity(room.door2)
|
||||
end
|
||||
|
||||
if save_objects then
|
||||
-- backup list of objects
|
||||
self.objects_backup = {}
|
||||
for k, o in pairs(self.objects) do
|
||||
self.objects_backup[k] = { object = o.object, qty = o.qty, state = o.state }
|
||||
end
|
||||
|
||||
UIPlaceObjects.removeAllObjects(self, true)
|
||||
end
|
||||
|
||||
remove_wall_line(room.x, room.y, 0, 1, room.height, 3, -1, 0, world)
|
||||
remove_wall_line(room.x, room.y, 1, 0, room.width , 2, 0, -1, world)
|
||||
remove_wall_line(room.x + room.width, room.y , 0, 1, room.height, 3, 0, 0, world)
|
||||
remove_wall_line(room.x, room.y + room.height, 1, 0, room.width , 2, 0, 0, world)
|
||||
|
||||
-- Reset floor tiles and flags
|
||||
world.map.th:unmarkRoom(room.x, room.y, room.width, room.height)
|
||||
end
|
||||
|
||||
function UIEditRoom:returnToDoorPhase()
|
||||
self.ui:tutorialStep(3, {13, 14, 15}, 9)
|
||||
local map = self.ui.app.map.th
|
||||
local room = self.room
|
||||
room.built = false
|
||||
if room.door and room.door.queue then
|
||||
@@ -607,78 +694,7 @@ function UIEditRoom:returnToDoorPhase()
|
||||
self.purchase_button:enable(false)
|
||||
self.pickup_button:enable(false)
|
||||
|
||||
-- Remove any placed objects (add them to list again)
|
||||
for x = room.x, room.x + room.width - 1 do
|
||||
for y = room.y, room.y + room.height - 1 do
|
||||
while true do
|
||||
local obj = self.world:getObject(x, y)
|
||||
if not obj or obj == room.door or class.is(obj, SwingDoor) then
|
||||
break
|
||||
end
|
||||
if obj.object_type.id == "litter" then -- Silently remove litter from the world.
|
||||
obj:remove()
|
||||
break
|
||||
end
|
||||
local obj_state = obj:getState()
|
||||
self.world:destroyEntity(obj)
|
||||
if not obj.master then
|
||||
self:addObjects({{
|
||||
object = TheApp.objects[obj.object_type.id],
|
||||
state = obj_state,
|
||||
qty = 1
|
||||
}})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self.world:destroyEntity(self.room.door)
|
||||
if self.room.door2 then
|
||||
self.world:destroyEntity(self.room.door2)
|
||||
end
|
||||
|
||||
-- backup list of objects
|
||||
self.objects_backup = {}
|
||||
for k, o in pairs(self.objects) do
|
||||
self.objects_backup[k] = { object = o.object, qty = o.qty, state = o.state }
|
||||
end
|
||||
|
||||
UIPlaceObjects.removeAllObjects(self, true)
|
||||
|
||||
-- Remove walls
|
||||
local function remove_wall_line(x, y, step_x, step_y, n_steps, layer, neigh_x, neigh_y)
|
||||
for _ = 1, n_steps do
|
||||
local existing = map:getCell(x, y, layer)
|
||||
-- Possibly add transparency.
|
||||
local flag = 0
|
||||
if self.ui.transparent_walls then
|
||||
flag = 1024
|
||||
end
|
||||
if self.world:getWallIdFromBlockId(existing) ~= "external" then
|
||||
local neighbour = self.world:getRoom(x + neigh_x, y + neigh_y)
|
||||
if neighbour then
|
||||
if neigh_x ~= 0 or neigh_y ~= 0 then
|
||||
local set = self.world:getWallSetFromBlockId(existing)
|
||||
local dir = self.world:getWallDirFromBlockId(existing)
|
||||
if set == "inside_tiles" then
|
||||
set = "outside_tiles"
|
||||
end
|
||||
map:setCell(x, y, layer, flag + self.world.wall_types[neighbour.room_info.wall_type][set][dir])
|
||||
end
|
||||
else
|
||||
map:setCell(x, y, layer, flag)
|
||||
end
|
||||
end
|
||||
x = x + step_x
|
||||
y = y + step_y
|
||||
end
|
||||
end
|
||||
remove_wall_line(room.x, room.y, 0, 1, room.height, 3, -1, 0)
|
||||
remove_wall_line(room.x, room.y, 1, 0, room.width , 2, 0, -1)
|
||||
remove_wall_line(room.x + room.width, room.y , 0, 1, room.height, 3, 0, 0)
|
||||
remove_wall_line(room.x, room.y + room.height, 1, 0, room.width , 2, 0, 0)
|
||||
|
||||
-- Reset floor tiles and flags
|
||||
self.world.map.th:unmarkRoom(room.x, room.y, room.width, room.height)
|
||||
self:removeRoom(true, room, self.world)
|
||||
|
||||
-- Re-create blueprint
|
||||
local rect = self.blueprint_rect
|
||||
@@ -864,12 +880,16 @@ function UIEditRoom:enterDoorPhase()
|
||||
|
||||
-- check if all adjacent tiles of the rooms are still connected
|
||||
if not self:checkReachability() then
|
||||
-- undo passable flags and go back to walls phase
|
||||
self.phase = "walls"
|
||||
self:returnToWallPhase(true)
|
||||
self.ui:playSound("wrong2.wav")
|
||||
self.ui.adviser:say(_A.room_forbidden_non_reachable_parts)
|
||||
return
|
||||
if self.ui.app.config.allow_blocking_off_areas then
|
||||
print("Blocking off areas is allowed with room " .. self.blueprint_rect.x .. ", " .. self.blueprint_rect.y .. ".")
|
||||
else
|
||||
-- undo passable flags and go back to walls phase
|
||||
self.phase = "walls"
|
||||
self:returnToWallPhase(true)
|
||||
self.ui:playSound("wrong2.wav")
|
||||
self.ui.adviser:say(_A.room_forbidden_non_reachable_parts)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
self.desc_text = _S.place_objects_window.place_door
|
||||
@@ -1198,7 +1218,7 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall)
|
||||
if self.blueprint_door.anim[1] then
|
||||
-- retrieve the old door position details to reset the blue print
|
||||
local oldx, oldy
|
||||
local _, _, oldx_mod, oldy_mod, _ = doorWallOffsetCalculations(self.blueprint_door.floor_x,
|
||||
local _, _, oldx_mod, oldy_mod, _ = doorWallOffsetCalculations(self.blueprint_door.floor_x,
|
||||
self.blueprint_door.floor_y, self.blueprint_door.wall)
|
||||
-- If we're dealing with swing doors the anim variable is actually a table with three
|
||||
-- identical "doors".
|
||||
|
@@ -160,13 +160,14 @@ function UIAnnualReport:UIAnnualReport(ui, world)
|
||||
table.sort(self.value_sort, desc_order)
|
||||
table.sort(self.salary_sort, desc_order)
|
||||
|
||||
-- Pause the game to allow the player plenty of time to check all statistics and trophies won
|
||||
if world and not world:isCurrentSpeed("Pause") then
|
||||
world:setSpeed("Pause")
|
||||
end
|
||||
TheApp.video:setBlueFilterActive(false)
|
||||
end
|
||||
|
||||
-- Make sure this window pauses the game, we want to let the player browse their awards
|
||||
function UIAnnualReport:mustPause()
|
||||
return true
|
||||
end
|
||||
|
||||
--! Finds out which awards and/or trophies the player has been awarded this year.
|
||||
function UIAnnualReport:checkTrophiesAndAwards(world)
|
||||
|
||||
@@ -200,12 +201,15 @@ function UIAnnualReport:checkTrophiesAndAwards(world)
|
||||
self.rep_amount = self.rep_amount + win_value
|
||||
end
|
||||
-- Impressive Reputation in the year (above a threshold throughout the year)
|
||||
if hosp.reputation_above_threshold then
|
||||
if hosp.has_impressive_reputation then
|
||||
self:addTrophy(_S.trophy_room.consistant_rep.trophies[math.random(1, 2)], "money", prices.TrophyReputationBonus)
|
||||
self.won_amount = self.won_amount + prices.TrophyReputationBonus
|
||||
end
|
||||
-- No deaths or around a 100% Cure rate in the year
|
||||
if hosp.num_deaths_this_year == 0 then
|
||||
-- Everyone treated successfully, no deaths, or around a 100% Cure rate in the year
|
||||
if hosp.num_cured_ty > 1 and hosp.num_deaths_this_year == 0 and hosp.not_cured_ty == 0 then
|
||||
self:addTrophy(_S.trophy_room.all_cured.trophies[math.random(1, 2)], "money", prices.TrophyAllCuredBonus)
|
||||
self.won_amount = self.won_amount + prices.TrophyAllCuredBonus
|
||||
elseif hosp.num_deaths_this_year == 0 then
|
||||
self:addTrophy(_S.trophy_room.no_deaths.trophies[math.random(1, 3)], "money", prices.TrophyDeathBonus)
|
||||
self.won_amount = self.won_amount + prices.TrophyDeathBonus
|
||||
elseif hosp.num_cured_ty > (hosp.not_cured_ty * 0.9) then
|
||||
@@ -251,7 +255,10 @@ function UIAnnualReport:checkTrophiesAndAwards(world)
|
||||
end
|
||||
|
||||
-- Deaths
|
||||
if hosp.num_deaths_this_year < prices.DeathsAward then
|
||||
if hosp.num_cured_ty > 1 and hosp.num_deaths_this_year == 0 and hosp.not_cured_ty == 0 then
|
||||
self:addAward(_S.trophy_room.no_deaths.awards[1], "money", prices.AllCuresBonus)
|
||||
self.award_won_amount = self.award_won_amount + prices.AllCuresBonus
|
||||
elseif hosp.num_deaths_this_year < prices.DeathsAward then
|
||||
self:addAward(_S.trophy_room.no_deaths.awards[math.random(1, 2)], "money", prices.DeathsBonus)
|
||||
self.award_won_amount = self.award_won_amount + prices.DeathsBonus
|
||||
elseif hosp.num_deaths_this_year > prices.DeathsPoor then
|
||||
@@ -445,17 +452,8 @@ end
|
||||
--! Overridden close function. The game should be unpaused again when closing the dialog.
|
||||
function UIAnnualReport:close()
|
||||
if TheApp.world:getLocalPlayerHospital().game_won then
|
||||
if not TheApp.world:isCurrentSpeed("Pause") then
|
||||
TheApp.world:setSpeed("Pause")
|
||||
TheApp.video:setBlueFilterActive(false)
|
||||
end
|
||||
TheApp.video:setBlueFilterActive(false)
|
||||
TheApp.world.ui.bottom_panel:openLastMessage()
|
||||
elseif TheApp.world:isCurrentSpeed("Pause") then
|
||||
if TheApp.ui.speed_up_key_pressed then
|
||||
TheApp.world:setSpeed("Speed Up")
|
||||
else
|
||||
TheApp.world:setSpeed(TheApp.world.prev_speed)
|
||||
end
|
||||
end
|
||||
self:updateAwards()
|
||||
Window.close(self)
|
||||
|
@@ -149,7 +149,6 @@ end
|
||||
function UICasebook:updateIcons()
|
||||
local disease = self.selected_disease
|
||||
local hosp = self.hospital
|
||||
local world = hosp.world
|
||||
|
||||
local known = true
|
||||
-- Curable / not curable icons and their tooltip
|
||||
@@ -170,16 +169,14 @@ function UICasebook:updateIcons()
|
||||
local build = false
|
||||
local staff = false
|
||||
-- Room requirements
|
||||
if #req.rooms > 0 then
|
||||
for _, room_id in ipairs(req.rooms) do
|
||||
-- Not researched yet?
|
||||
if not hosp.discovered_rooms[world.available_rooms[room_id]] then
|
||||
known = false
|
||||
research = (research and (research .. ", ") or " (") .. TheApp.rooms[room_id].name
|
||||
end
|
||||
-- Researched, but not built. TODO: maybe make this an else clause to not oversize the tooltip that much
|
||||
build = (build and (build .. ", ") or " (") .. TheApp.rooms[room_id].name
|
||||
for _, room_id in ipairs(req.rooms) do
|
||||
-- Not researched yet?
|
||||
if not hosp:isRoomDiscovered(room_id) then
|
||||
known = false
|
||||
research = (research and (research .. ", ") or " (") .. TheApp.rooms[room_id].name
|
||||
end
|
||||
-- Researched, but not built. TODO: maybe make this an else clause to not oversize the tooltip that much
|
||||
build = (build and (build .. ", ") or " (") .. TheApp.rooms[room_id].name
|
||||
end
|
||||
research = research and (_S.tooltip.casebook.cure_requirement.research_machine .. research .. "). ") or ""
|
||||
build = build and (_S.tooltip.casebook.cure_requirement.build_room .. build .. "). ") or ""
|
||||
|
@@ -88,6 +88,11 @@ function UIFax:UIFax(ui, icon)
|
||||
self:addPanel(0, 326, 382):makeButton(0, 0, 44, 11, 13, button("#"))
|
||||
end
|
||||
|
||||
-- Faxes pause the game
|
||||
function UIFax:mustPause()
|
||||
return true
|
||||
end
|
||||
|
||||
function UIFax:updateChoices()
|
||||
local choices = self.message.choices
|
||||
for i, button in ipairs(self.choice_buttons) do
|
||||
@@ -173,7 +178,7 @@ function UIFax:choice(choice_number)
|
||||
end
|
||||
local vip_ignores_refusal = math.random(1, 2)
|
||||
if choice == "accept_emergency" then
|
||||
self.ui.app.world:newObject("helicopter", self.ui.hospital, "north")
|
||||
self.ui.app.world:newObject("helicopter", "north")
|
||||
self.ui:addWindow(UIWatch(self.ui, "emergency"))
|
||||
self.ui:playAnnouncement(self.ui.hospital.emergency.disease.emergency_sound, AnnouncementPriority.Critical)
|
||||
self.ui.adviser:say(_A.information.emergency)
|
||||
@@ -204,7 +209,9 @@ function UIFax:choice(choice_number)
|
||||
-- Set the new salary.
|
||||
self.ui.hospital.player_salary = self.ui.hospital.salary_offer
|
||||
if tonumber(self.ui.app.world.map.level_number) then
|
||||
self.ui.app:loadLevel(self.ui.app.world.map.level_number + 1, self.ui.app.map.difficulty)
|
||||
local next_level = self.ui.app.world.map.level_number + 1
|
||||
self.ui.app:loadLevel(next_level, self.ui.app.map.difficulty)
|
||||
self.ui.app.moviePlayer:playAdvanceMovie(next_level)
|
||||
else
|
||||
for i, level in ipairs(self.ui.app.world.campaign_info.levels) do
|
||||
if self.ui.app.world.map.level_number == level then
|
||||
@@ -221,6 +228,8 @@ function UIFax:choice(choice_number)
|
||||
elseif choice == "return_to_main_menu" then
|
||||
self.ui.app.moviePlayer:playWinMovie()
|
||||
self.ui.app:loadMainMenu()
|
||||
elseif choice == "stay_on_level" then
|
||||
self.ui.hospital.win_declined = true
|
||||
end
|
||||
self.icon:removeMessage()
|
||||
self:close()
|
||||
@@ -259,8 +268,11 @@ function UIFax:validate()
|
||||
if not hosp.spawn_rate_cheat then
|
||||
self.ui.adviser:say(_A.cheats.roujin_on_cheat)
|
||||
hosp.spawn_rate_cheat = true
|
||||
self:cheatByFax()
|
||||
else
|
||||
self.ui.adviser:say(_A.cheats.roujin_off_cheat)
|
||||
-- Clear the current month's spawns to give the player a break
|
||||
self.ui.app.world.spawn_dates = {}
|
||||
hosp.spawn_rate_cheat = nil
|
||||
end
|
||||
else
|
||||
@@ -273,18 +285,24 @@ function UIFax:validate()
|
||||
-- TODO: Other cheats (preferably with slight obfuscation, as above)
|
||||
end
|
||||
|
||||
function UIFax:cheatByFax()
|
||||
local cheatWindow = self.ui:getWindow(UICheats)
|
||||
local cheat = self.ui.hospital.hosp_cheats
|
||||
cheat:announceCheat()
|
||||
-- If a cheats window is open, make sure the UI is updated
|
||||
if cheatWindow then
|
||||
cheatWindow:updateCheatedStatus()
|
||||
end
|
||||
end
|
||||
|
||||
function UIFax:appendNumber(number)
|
||||
self.code = self.code .. number
|
||||
end
|
||||
|
||||
function UIFax:close()
|
||||
local world = self.ui.app.world
|
||||
self.icon.fax = nil
|
||||
self.icon:adjustToggle()
|
||||
UIFullscreen.close(self)
|
||||
if world and world:isCurrentSpeed("Pause") then
|
||||
world:setSpeed(world.prev_speed)
|
||||
end
|
||||
end
|
||||
|
||||
function UIFax:afterLoad(old, new)
|
||||
|
@@ -174,9 +174,8 @@ function UIStaffManagement:updateStaffList(staff_member_removed)
|
||||
Handyman = {},
|
||||
Receptionist = {},
|
||||
}
|
||||
staff_members.Surgeon = staff_members.Doctor
|
||||
for _, staff in ipairs(hosp.staff) do
|
||||
local list = staff_members[staff.humanoid_class]
|
||||
local list = staff_members[staff.profile.humanoid_class]
|
||||
list[#list + 1] = staff
|
||||
-- The selected staff might have been moved because someone else was removed from the list.
|
||||
if selected_staff == staff then
|
||||
@@ -225,7 +224,7 @@ end
|
||||
-- Function to select a given staff member.
|
||||
-- Includes switching to correct category and page.
|
||||
function UIStaffManagement:selectStaff(staff)
|
||||
self:setCategory(staff.humanoid_class == "Surgeon" and "Doctor" or staff.humanoid_class)
|
||||
self:setCategory(staff.profile.humanoid_class)
|
||||
for i, s in ipairs(self.staff_members[self.category]) do
|
||||
if s == staff then
|
||||
self:selectIndex(i)
|
||||
|
@@ -112,8 +112,9 @@ function UITownMap:onMouseMove(x, y)
|
||||
local tx = math.floor((x - 227) / 3)
|
||||
local ty = math.floor((y - 25) / 3)
|
||||
self.hover_plot = nil
|
||||
if 0 <= tx and tx < 128 and 0 <= ty and ty < 128 then
|
||||
local map = self.ui.hospital.world.map.th
|
||||
local map = self.ui.hospital.world.map.th
|
||||
local width, height = map:size()
|
||||
if 0 <= tx and tx < width and 0 <= ty and ty < height then
|
||||
self.hover_plot = map:getCellFlags(tx + 1, ty + 1, flag_cache).parcelId
|
||||
end
|
||||
return UIFullscreen.onMouseMove(self, x, y)
|
||||
@@ -124,8 +125,9 @@ function UITownMap:onMouseUp(button, x, y)
|
||||
if button == "left" then
|
||||
local tx = math.floor((x - 227) / 3)
|
||||
local ty = math.floor((y - 25) / 3)
|
||||
if 0 <= tx and tx < 128 and 0 <= ty and ty < 128 then
|
||||
local map = self.ui.hospital.world.map.th
|
||||
local map = self.ui.hospital.world.map.th
|
||||
local width, height = map:size()
|
||||
if 0 <= tx and tx < width and 0 <= ty and ty < height then
|
||||
local plot = map:getCellFlags(tx + 1, ty + 1, flag_cache).parcelId
|
||||
if plot ~= 0 then
|
||||
if self.ui.hospital:purchasePlot(plot) then
|
||||
@@ -140,7 +142,8 @@ function UITownMap:onMouseUp(button, x, y)
|
||||
local tx = math.floor((x - 227) / 3)
|
||||
local ty = math.floor((y - 25) / 3)
|
||||
local map = self.ui.hospital.world.map.th
|
||||
if 0 <= tx and tx < 128 and 0 <= ty and ty < 128 then
|
||||
local width, height = map:size()
|
||||
if 0 <= tx and tx < width and 0 <= ty and ty < height then
|
||||
local plot = map:getCellFlags(tx + 1, ty + 1, flag_cache).parcelId
|
||||
if plot ~= 0 then
|
||||
local sx, sy = self.ui.app.map:WorldToScreen(tx, ty)
|
||||
@@ -169,15 +172,15 @@ function UITownMap:draw(canvas, x, y)
|
||||
config = self:initRuntimeConfig()
|
||||
end
|
||||
|
||||
-- We need to draw number of people, plants, fire extinguisers, other objects
|
||||
-- We need to draw number of people, plants, fire extinguishers, other objects
|
||||
-- and radiators.
|
||||
-- NB: original TH's patient count was always 1 too big (started counting at 1)
|
||||
-- This is likely a bug and we do not copy this behavior.
|
||||
local patientcount = hospital.patientcount
|
||||
local plants = world.object_counts.plant
|
||||
local fireext = world.object_counts.extinguisher
|
||||
local objs = world.object_counts.general
|
||||
local radiators = world.object_counts.radiator
|
||||
local patientcount = hospital:countPatients()
|
||||
local plants = hospital:countPlants()
|
||||
local fireext = hospital:countFireExtinguishers()
|
||||
local objs = hospital:countGeneralObjects()
|
||||
local radiators = hospital:countRadiators()
|
||||
|
||||
self.info_font:draw(canvas, patientcount, x + 95, y + 57)
|
||||
self.info_font:draw(canvas, plants, x + 95, y + 110)
|
||||
@@ -186,7 +189,7 @@ function UITownMap:draw(canvas, x, y)
|
||||
self.info_font:draw(canvas, radiators, x + 95, y + 265)
|
||||
|
||||
-- Heating costs
|
||||
local heating_costs = math.floor(((hospital.radiator_heat *10)* radiators)* 7.5)
|
||||
local heating_costs = math.floor(((hospital.heating.radiator_heat *10)* radiators)* 7.5)
|
||||
self.info_font:draw(canvas, ("%8i"):format(heating_costs), x + 100, y + 355)
|
||||
|
||||
-- draw money balance
|
||||
@@ -194,7 +197,7 @@ function UITownMap:draw(canvas, x, y)
|
||||
|
||||
-- radiator heat
|
||||
local rad_max_width = 60 -- Radiator indicator width
|
||||
local rad_width = rad_max_width * hospital.radiator_heat
|
||||
local rad_width = rad_max_width * hospital.heating.radiator_heat
|
||||
for dx = 0, rad_width do
|
||||
self.panel_sprites:draw(canvas, 9, x + 101 + dx, y + 319)
|
||||
end
|
||||
@@ -314,25 +317,19 @@ end
|
||||
|
||||
function UITownMap:decreaseHeat()
|
||||
local h = self.ui.hospital
|
||||
local heat = math.floor(h.radiator_heat * 10 + 0.5)
|
||||
local heat = math.floor(h.heating.radiator_heat * 10 + 0.5)
|
||||
if not h.heating_broke then
|
||||
heat = heat - 1
|
||||
if heat < 1 then
|
||||
heat = 1
|
||||
end
|
||||
h.radiator_heat = heat / 10
|
||||
heat = math.max(heat - 1, 1)
|
||||
h.heating.radiator_heat = heat / 10
|
||||
end
|
||||
end
|
||||
|
||||
function UITownMap:increaseHeat()
|
||||
local h = self.ui.hospital
|
||||
local heat = math.floor(h.radiator_heat * 10 + 0.5)
|
||||
local heat = math.floor(h.heating.radiator_heat * 10 + 0.5)
|
||||
if not h.heating_broke then
|
||||
heat = heat + 1
|
||||
if heat > 10 then
|
||||
heat = 10
|
||||
end
|
||||
h.radiator_heat = heat / 10
|
||||
heat = math.min(heat + 1, 10)
|
||||
h.heating.radiator_heat = heat / 10
|
||||
end
|
||||
end
|
||||
|
||||
|
@@ -66,10 +66,10 @@ function UIJukebox:UIJukebox(app)
|
||||
end
|
||||
self.track_buttons[i] = self:addPanel(404, self.width - 61, y):makeToggleButton(19, 4, 24, 24, 405):setSound("selectx.wav")
|
||||
if not info.enabled then
|
||||
self.track_buttons[i]:toggle()
|
||||
self.track_buttons[i]:setToggleState(true)
|
||||
end
|
||||
self.track_buttons[i].on_click = --[[persistable:jukebox_toggle_track]] function(window, off)
|
||||
window:toggleTrack(i, info, not off)
|
||||
self.track_buttons[i].on_click = --[[persistable:jukebox_toggle_track]] function(window)
|
||||
window:toggleTrack(i)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -116,9 +116,11 @@ function UIJukebox:stopBackgroundTrack()
|
||||
self.audio:stopBackgroundTrack()
|
||||
end
|
||||
|
||||
function UIJukebox:toggleTrack(index, info, on)
|
||||
info.enabled = on
|
||||
if not on and self.audio.background_music == info.music then
|
||||
function UIJukebox:toggleTrack(index)
|
||||
local info = self.audio.background_playlist[index]
|
||||
self.track_buttons[index]:setToggleState(info.enabled)
|
||||
info.enabled = not info.enabled
|
||||
if not info.enabled and self.audio.background_music == info.music then
|
||||
self.audio:stopBackgroundTrack()
|
||||
self.audio:playRandomBackgroundTrack()
|
||||
end
|
||||
@@ -127,6 +129,7 @@ end
|
||||
function UIJukebox:loopTrack()
|
||||
local index = self.audio:findIndexOfCurrentTrack()
|
||||
local playlist = self.audio.background_playlist
|
||||
if not playlist[index] then return end
|
||||
|
||||
if playlist[index].loop then
|
||||
playlist[index].loop = false
|
||||
@@ -134,8 +137,7 @@ function UIJukebox:loopTrack()
|
||||
for i, list_entry in ipairs(playlist) do
|
||||
if list_entry.enabled_before_loop and index ~= i then
|
||||
list_entry.enabled_before_loop = nil
|
||||
self:toggleTrack(i, list_entry, true)
|
||||
self.track_buttons[i]:toggle()
|
||||
self:toggleTrack(i)
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -144,14 +146,16 @@ function UIJukebox:loopTrack()
|
||||
for i, list_entry in ipairs(playlist) do
|
||||
if list_entry.enabled and index ~= i then
|
||||
list_entry.enabled_before_loop = true
|
||||
self:toggleTrack(i, list_entry, false)
|
||||
self.track_buttons[i]:toggle()
|
||||
self:toggleTrack(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UIJukebox:draw(canvas, x, y)
|
||||
for i, info in ipairs(TheApp.audio.background_playlist) do
|
||||
self.track_buttons[i]:setToggleState(not info.enabled)
|
||||
end
|
||||
Window.draw(self, canvas, x, y)
|
||||
x, y = self.x + x, self.y + y
|
||||
|
||||
@@ -172,3 +176,10 @@ function UIJukebox:draw(canvas, x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UIJukebox:afterLoad(old, new)
|
||||
if not (self.app.config.audio and self.app:isAudioEnabled()) then
|
||||
self:close()
|
||||
end
|
||||
Window.afterLoad(self, old, new)
|
||||
end
|
||||
|
@@ -71,6 +71,7 @@ function UIMenuBar:onTick()
|
||||
self.menu_disappear_counter = nil
|
||||
else
|
||||
if self.menu_disappear_counter == 0 then
|
||||
self.ui.app:saveConfig()
|
||||
self.menu_disappear_counter = nil
|
||||
local close_to = self.active_menu and self.active_menu.level or 0
|
||||
for i = #self.open_menus, close_to + 1, -1 do
|
||||
@@ -577,21 +578,18 @@ function UIMenuBar:makeGameMenu(app)
|
||||
return level == app.config.music_volume,
|
||||
function()
|
||||
app.audio:setBackgroundVolume(level)
|
||||
app:saveConfig()
|
||||
end,
|
||||
""
|
||||
elseif setting == "sound" then
|
||||
return level == app.config.sound_volume,
|
||||
function()
|
||||
app.audio:setSoundVolume(level)
|
||||
app:saveConfig()
|
||||
end,
|
||||
""
|
||||
else
|
||||
return level == app.config.announcement_volume,
|
||||
function()
|
||||
app.audio:setAnnouncementVolume(level)
|
||||
app:saveConfig()
|
||||
end,
|
||||
""
|
||||
end
|
||||
@@ -609,7 +607,6 @@ function UIMenuBar:makeGameMenu(app)
|
||||
app.config.play_sounds,
|
||||
function(item)
|
||||
app.audio:playSoundEffects(item.checked)
|
||||
app:saveConfig()
|
||||
end,
|
||||
nil,
|
||||
function()
|
||||
@@ -621,7 +618,6 @@ function UIMenuBar:makeGameMenu(app)
|
||||
app.config.play_announcements,
|
||||
function(item)
|
||||
app.config.play_announcements = item.checked
|
||||
app:saveConfig()
|
||||
end,
|
||||
nil,
|
||||
function()
|
||||
@@ -633,7 +629,6 @@ function UIMenuBar:makeGameMenu(app)
|
||||
function(item)
|
||||
app.config.play_music = item.checked
|
||||
self.ui:togglePlayMusic(item)
|
||||
app:saveConfig()
|
||||
end,
|
||||
nil,
|
||||
function(musicStatus)
|
||||
@@ -665,7 +660,6 @@ function UIMenuBar:makeGameMenu(app)
|
||||
options:appendCheckItem(_S.menu_options.capture_mouse,
|
||||
app.config.capture_mouse,
|
||||
function(item) app.config.capture_mouse = item.checked
|
||||
app:saveConfig()
|
||||
app:setCaptureMouse()
|
||||
end)
|
||||
|
||||
@@ -673,7 +667,6 @@ function UIMenuBar:makeGameMenu(app)
|
||||
not app.config.adviser_disabled,
|
||||
function(item)
|
||||
app.config.adviser_disabled = not item.checked
|
||||
app:saveConfig()
|
||||
end,
|
||||
nil,
|
||||
function()
|
||||
@@ -684,7 +677,6 @@ function UIMenuBar:makeGameMenu(app)
|
||||
app.config.twentyfour_hour_clock,
|
||||
function(item)
|
||||
app.config.twentyfour_hour_clock = item.checked
|
||||
app:saveConfig()
|
||||
end)
|
||||
|
||||
local function temperatureDisplay(method)
|
||||
@@ -756,6 +748,9 @@ function UIMenuBar:makeGameMenu(app)
|
||||
local function disable_salary_raise(item)
|
||||
app.world:debugDisableSalaryRaise(item.checked)
|
||||
end
|
||||
local function allowBlockingAreas(item)
|
||||
app.config.allow_blocking_off_areas = item.checked
|
||||
end
|
||||
local function overlay(...)
|
||||
local args = {n = select('#', ...), ...}
|
||||
return function(item, m)
|
||||
@@ -770,7 +765,9 @@ function UIMenuBar:makeGameMenu(app)
|
||||
for L = 1, 12 do
|
||||
levels_menu:appendItem((" L%i "):format(L), function()
|
||||
local status, err = pcall(app.loadLevel, app, L)
|
||||
if not status then
|
||||
if status then
|
||||
self.ui.app.moviePlayer:playAdvanceMovie(L)
|
||||
else
|
||||
err = _S.errors.load_prefix .. err
|
||||
print(err)
|
||||
self.ui:addWindow(UIInformation(self.ui, {err}))
|
||||
@@ -783,6 +780,7 @@ function UIMenuBar:makeGameMenu(app)
|
||||
:appendItem(_S.menu_debug.connect_debugger:format(hotkey_value_label("global_connectDebugger", hotkeys)), function() self.ui:connectDebugger() end)
|
||||
:appendCheckItem(_S.menu_debug.limit_camera, true, limit_camera, nil, function() return self.ui.limit_to_visible_diamond end)
|
||||
:appendCheckItem(_S.menu_debug.disable_salary_raise, false, disable_salary_raise, nil, function() return self.ui.app.world.debug_disable_salary_raise end)
|
||||
:appendCheckItem(_S.menu_debug.allow_blocking_off_areas, false, allowBlockingAreas, nil, function() return self.ui.app.config.allow_blocking_off_areas end)
|
||||
:appendItem(_S.menu_debug.make_debug_fax, function() self.ui:makeDebugFax() end)
|
||||
:appendItem(_S.menu_debug.make_debug_patient, function() self.ui:addWindow(UIMakeDebugPatient(self.ui)) end)
|
||||
:appendItem(_S.menu_debug.cheats:format(hotkey_value_label("ingame_showCheatWindow", hotkeys)), function() self.ui:addWindow(UICheats(self.ui)) end)
|
||||
|
@@ -104,13 +104,16 @@ function UIMessage:adjustToggle()
|
||||
end
|
||||
end
|
||||
|
||||
--! Displays the fax/strike message to the player when opened from the bottom_panel.
|
||||
function UIMessage:openMessage()
|
||||
if TheApp.world:isUserActionProhibited() and not self.ui:checkForMustPauseWindows() then
|
||||
self.ui:playSound("wrong2.wav")
|
||||
self:adjustToggle()
|
||||
return
|
||||
end
|
||||
if TheApp.world:isCurrentSpeed("Speed Up") then
|
||||
TheApp.world:previousSpeed()
|
||||
end
|
||||
if not TheApp.world:isCurrentSpeed("Pause") then
|
||||
TheApp.world:setSpeed("Pause")
|
||||
end
|
||||
if self.type == "strike" then -- strikes are special cases, as they are not faxes
|
||||
self.ui:addWindow(UIStaffRise(self.ui, self.owner, self.message))
|
||||
self:removeMessage()
|
||||
|
@@ -697,7 +697,13 @@ function UIPlaceObjects:setBlueprintCell(x, y)
|
||||
end
|
||||
if self.object_anim and object.class ~= "SideObject" then
|
||||
if allgood then
|
||||
allgood = not world:wouldNonSideObjectBreakPathfindingIfSpawnedAt(x, y, object, self.object_orientation, roomId)
|
||||
if world:wouldNonSideObjectBreakPathfindingIfSpawnedAt(x, y, object, self.object_orientation, roomId) then
|
||||
if self.ui.app.config.allow_blocking_off_areas then
|
||||
print("Blocking off areas is allowed at " .. x .. ", " .. y .. ".")
|
||||
else
|
||||
allgood = false
|
||||
end
|
||||
end
|
||||
end
|
||||
if ATTACH_BLUEPRINT_TO_TILE then
|
||||
self.object_anim:setTile(map, x, y)
|
||||
@@ -721,7 +727,11 @@ function UIPlaceObjects:setBlueprintCell(x, y)
|
||||
if not world.pathfinder:findDistance(x, y, checked_x, checked_y) then
|
||||
--we need to check if the failure to get the distance is due to the presence of an object in the adjacent tile
|
||||
if map:getCellFlags(checked_x, checked_y)["passable"] then
|
||||
allgood = false
|
||||
if self.ui.app.config.allow_blocking_off_areas then
|
||||
print("Blocking off areas is allowed at " .. x .. ", " .. y .. ".")
|
||||
else
|
||||
allgood = false
|
||||
end
|
||||
end
|
||||
end
|
||||
flags[passable_flag] = true
|
||||
|
@@ -77,15 +77,34 @@ end
|
||||
|
||||
local flag_cache = {}
|
||||
local flag_altpal = 16
|
||||
--! Private function. Is the staff member (self) permitted
|
||||
-- to be placed where the user is hovering or clicking?
|
||||
function UIPlaceStaff:_isValidStaffPlacement()
|
||||
local world, x, y = self.world, self.tile_x, self.tile_y
|
||||
world.map.th:getCellFlags(x, y, flag_cache)
|
||||
-- Is the tile inside the player's hospital building?
|
||||
if not (self.ui.hospital:getPlayerIndex() == flag_cache.owner and
|
||||
flag_cache.hospital) then
|
||||
return false
|
||||
end
|
||||
local room = world:getRoom(x, y)
|
||||
-- On a tile humanoids can walk on?
|
||||
local walkable = flag_cache.passable and (not room and true or not room.crashed)
|
||||
-- and in an area the regular staff (doctors, nurses and handymen) can go?
|
||||
local staffable = (self.allow_in_rooms or flag_cache.roomId == 0)
|
||||
-- Or is it a receptionist placed on an unstaffed reception desk?
|
||||
local reception = false
|
||||
if self.profile.humanoid_class == "Receptionist" then
|
||||
local desk = world:getObject(x, y, "reception_desk") or
|
||||
world:findObjectNear(self, "reception_desk", 0)
|
||||
reception = desk and not desk.receptionist
|
||||
end
|
||||
return (walkable and staffable) or reception
|
||||
end
|
||||
|
||||
function UIPlaceStaff:draw(canvas)
|
||||
if self.world.user_actions_allowed then
|
||||
self.world.map.th:getCellFlags(self.tile_x, self.tile_y, flag_cache)
|
||||
local room = self.world:getRoom(self.tile_x, self.tile_y)
|
||||
local player_id = self.ui.hospital:getPlayerIndex()
|
||||
local valid = flag_cache.hospital and flag_cache.passable and
|
||||
(self.allow_in_rooms or flag_cache.roomId == 0) and
|
||||
(not room and true or not room.crashed) and
|
||||
flag_cache.owner == player_id
|
||||
local valid = self:_isValidStaffPlacement()
|
||||
self.anim:setFlag(valid and 0 or flag_altpal)
|
||||
local zoom = self.ui.zoom_factor
|
||||
if canvas:scale(zoom) then
|
||||
@@ -107,13 +126,7 @@ function UIPlaceStaff:onMouseUp(button, x, y)
|
||||
return true
|
||||
elseif button == "left" then
|
||||
self:onMouseMove(x, y)
|
||||
self.world.map.th:getCellFlags(self.tile_x, self.tile_y, flag_cache)
|
||||
local room = self.world:getRoom(self.tile_x, self.tile_y)
|
||||
local player_id = self.ui.hospital:getPlayerIndex()
|
||||
if flag_cache.hospital and flag_cache.passable and
|
||||
(self.allow_in_rooms or flag_cache.roomId == 0) and
|
||||
(not room or not room.crashed) and
|
||||
flag_cache.owner == player_id then
|
||||
if self:_isValidStaffPlacement() then
|
||||
if self.staff then
|
||||
self.staff:setTile(self.tile_x, self.tile_y)
|
||||
else
|
||||
|
@@ -1,246 +0,0 @@
|
||||
--[[ Copyright (c) 2010 Manuel "Roujin" Wolf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. --]]
|
||||
|
||||
--! A dialog for activating cheats
|
||||
class "UICheats" (UIResizable)
|
||||
|
||||
---@type UICheats
|
||||
local UICheats = _G["UICheats"]
|
||||
|
||||
local col_bg = {
|
||||
red = 154,
|
||||
green = 146,
|
||||
blue = 198,
|
||||
}
|
||||
|
||||
local col_caption = {
|
||||
red = 174,
|
||||
green = 166,
|
||||
blue = 218,
|
||||
}
|
||||
|
||||
local col_border = {
|
||||
red = 134,
|
||||
green = 126,
|
||||
blue = 178,
|
||||
}
|
||||
|
||||
local col_cheated_no = {
|
||||
red = 36,
|
||||
green = 154,
|
||||
blue = 36,
|
||||
}
|
||||
|
||||
local col_cheated_yes = {
|
||||
red = 224,
|
||||
green = 36,
|
||||
blue = 36,
|
||||
}
|
||||
|
||||
--[[ Constructs the cheat dialog.
|
||||
!param ui (UI) The active ui.
|
||||
]]
|
||||
function UICheats:UICheats(ui)
|
||||
self.cheats = {
|
||||
{name = "money", func = self.cheatMoney},
|
||||
{name = "all_research", func = self.cheatResearch},
|
||||
{name = "emergency", func = self.cheatEmergency},
|
||||
{name = "epidemic", func = self.cheatEpidemic},
|
||||
{name = "toggle_infected", func = self.cheatToggleInfected},
|
||||
{name = "vip", func = self.cheatVip},
|
||||
{name = "earthquake", func = self.cheatEarthquake},
|
||||
{name = "create_patient", func = self.cheatPatient},
|
||||
{name = "end_month", func = self.cheatMonth},
|
||||
{name = "end_year", func = self.cheatYear},
|
||||
{name = "lose_level", func = self.cheatLose},
|
||||
{name = "win_level", func = self.cheatWin},
|
||||
{name = "increase_prices", func = self.cheatIncreasePrices},
|
||||
{name = "decrease_prices", func = self.cheatDecreasePrices},
|
||||
}
|
||||
|
||||
|
||||
self:UIResizable(ui, 300, 200, col_bg)
|
||||
|
||||
self.default_button_sound = "selectx.wav"
|
||||
|
||||
self.modal_class = "cheats"
|
||||
self.esc_closes = true
|
||||
self.resizable = false
|
||||
self:setDefaultPosition(0.2, 0.4)
|
||||
|
||||
local y = 10
|
||||
self:addBevelPanel(20, y, 260, 20, col_caption):setLabel(_S.cheats_window.caption)
|
||||
.lowered = true
|
||||
|
||||
y = y + 30
|
||||
self:addColourPanel(20, y, 260, 40, col_bg.red, col_bg.green, col_bg.blue):setLabel({_S.cheats_window.warning})
|
||||
|
||||
y = y + 40
|
||||
self.cheated_panel = self:addBevelPanel(20, y, 260, 18, col_cheated_no, col_border, col_border)
|
||||
|
||||
local function button_clicked(num)
|
||||
return --[[persistable:cheats_button]] function(window)
|
||||
window:buttonClicked(num)
|
||||
end
|
||||
end
|
||||
|
||||
self.item_panels = {}
|
||||
self.item_buttons = {}
|
||||
|
||||
y = y + 30
|
||||
for num = 1, #self.cheats do
|
||||
self.item_panels[num] = self:addBevelPanel(20, y, 260, 20, col_bg)
|
||||
:setLabel(_S.cheats_window.cheats[self.cheats[num].name])
|
||||
self.item_buttons[num] = self.item_panels[num]:makeButton(0, 0, 260, 20, nil, button_clicked(num))
|
||||
:setTooltip(_S.tooltip.cheats_window.cheats[self.cheats[num].name])
|
||||
y = y + 20
|
||||
end
|
||||
|
||||
y = y + 20
|
||||
self:addBevelPanel(20, y, 260, 40, col_bg):setLabel(_S.cheats_window.close)
|
||||
:makeButton(0, 0, 260, 40, nil, self.buttonBack):setTooltip(_S.tooltip.cheats_window.close)
|
||||
|
||||
y = y + 60
|
||||
self:setSize(300, y)
|
||||
self:updateCheatedStatus()
|
||||
end
|
||||
|
||||
function UICheats:updateCheatedStatus()
|
||||
local cheated = self.ui.hospital.cheated
|
||||
self.cheated_panel:setLabel(cheated and _S.cheats_window.cheated.yes or _S.cheats_window.cheated.no)
|
||||
self.cheated_panel:setColour(cheated and col_cheated_yes or col_cheated_no)
|
||||
end
|
||||
|
||||
function UICheats:buttonClicked(num)
|
||||
-- Only the cheats that may fail return false in that case. All others return nothing.
|
||||
if self.cheats[num].func(self) ~= false then
|
||||
if self.cheats[num].name ~= "lose_level" then
|
||||
local announcements = self.ui.app.world.cheat_announcements
|
||||
if announcements then
|
||||
self.ui:playSound(announcements[math.random(1, #announcements)])
|
||||
end
|
||||
self.ui.hospital.cheated = true
|
||||
self:updateCheatedStatus()
|
||||
end
|
||||
else
|
||||
-- It was not possible to use this cheat.
|
||||
self.ui:addWindow(UIInformation(self.ui, {_S.information.cheat_not_possible}))
|
||||
end
|
||||
end
|
||||
|
||||
function UICheats:cheatMoney()
|
||||
self.ui.hospital:receiveMoney(10000, _S.transactions.cheat)
|
||||
end
|
||||
|
||||
function UICheats:cheatResearch()
|
||||
local hosp = self.ui.hospital
|
||||
for _, cat in ipairs({"diagnosis", "cure"}) do
|
||||
while hosp.research.research_policy[cat].current do
|
||||
hosp.research:discoverObject(hosp.research.research_policy[cat].current)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UICheats:cheatEmergency()
|
||||
if not self.ui.hospital:createEmergency() then
|
||||
self.ui:addWindow(UIInformation(self.ui, {_S.misc.no_heliport}))
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Creates a new contagious patient in the hospital - potentially an epidemic]]
|
||||
function UICheats:cheatEpidemic()
|
||||
self.ui.hospital:spawnContagiousPatient()
|
||||
end
|
||||
|
||||
--[[ Before an epidemic has been revealed toggle the infected icons
|
||||
to easily distinguish the infected patients -- will toggle icons
|
||||
for ALL future epidemics you cannot distinguish between epidemics
|
||||
by disease ]]
|
||||
function UICheats:cheatToggleInfected()
|
||||
local hospital = self.ui.hospital
|
||||
if hospital.future_epidemics_pool and #hospital.future_epidemics_pool > 0 then
|
||||
for _, future_epidemic in ipairs(hospital.future_epidemics_pool) do
|
||||
local show_mood = future_epidemic.cheat_always_show_mood
|
||||
future_epidemic.cheat_always_show_mood = not show_mood
|
||||
local mood_action = show_mood and "deactivate" or "activate"
|
||||
for _, patient in ipairs(future_epidemic.infected_patients) do
|
||||
patient:setMood("epidemy4",mood_action)
|
||||
end
|
||||
end
|
||||
else
|
||||
print("Unable to toggle icons - no epidemics in progress that are not revealed")
|
||||
end
|
||||
end
|
||||
|
||||
function UICheats:cheatVip()
|
||||
self.ui.hospital:createVip()
|
||||
end
|
||||
|
||||
function UICheats:cheatEarthquake()
|
||||
return self.ui.app.world:createEarthquake()
|
||||
end
|
||||
|
||||
function UICheats:cheatPatient()
|
||||
self.ui.app.world:spawnPatient()
|
||||
end
|
||||
|
||||
function UICheats:cheatMonth()
|
||||
self.ui.app.world:setEndMonth()
|
||||
end
|
||||
|
||||
function UICheats:cheatYear()
|
||||
self.ui.app.world:setEndYear()
|
||||
end
|
||||
|
||||
function UICheats:cheatLose()
|
||||
self.ui.app.world:loseGame(1) -- TODO adjust for multiplayer
|
||||
end
|
||||
|
||||
function UICheats:cheatWin()
|
||||
self.ui.app.world:winGame(1) -- TODO adjust for multiplayer
|
||||
end
|
||||
|
||||
function UICheats:cheatIncreasePrices()
|
||||
local hosp = self.ui.app.world.hospitals[1]
|
||||
for _, casebook in pairs(hosp.disease_casebook) do
|
||||
local new_price = casebook.price + 0.5
|
||||
if new_price > 2 then
|
||||
casebook.price = 2
|
||||
else
|
||||
casebook.price = new_price
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UICheats:cheatDecreasePrices()
|
||||
local hosp = self.ui.app.world.hospitals[1]
|
||||
for _, casebook in pairs(hosp.disease_casebook) do
|
||||
local new_price = casebook.price - 0.5
|
||||
if new_price < 0.5 then
|
||||
casebook.price = 0.5
|
||||
else
|
||||
casebook.price = new_price
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UICheats:buttonBack()
|
||||
self:close()
|
||||
end
|
140
CorsixTH/Lua/dialogs/resizables/cheats_dialog.lua
Normal file
140
CorsixTH/Lua/dialogs/resizables/cheats_dialog.lua
Normal file
@@ -0,0 +1,140 @@
|
||||
--[[ Copyright (c) 2010 Manuel "Roujin" Wolf
|
||||
Copyright (c) 2020 lewri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. --]]
|
||||
|
||||
|
||||
--! A dialog for activating cheats
|
||||
class "UICheats" (UIResizable)
|
||||
|
||||
---@type UICheats
|
||||
local UICheats = _G["UICheats"]
|
||||
|
||||
local col_bg = {
|
||||
red = 154,
|
||||
green = 146,
|
||||
blue = 198,
|
||||
}
|
||||
|
||||
local col_caption = {
|
||||
red = 174,
|
||||
green = 166,
|
||||
blue = 218,
|
||||
}
|
||||
|
||||
local col_border = {
|
||||
red = 134,
|
||||
green = 126,
|
||||
blue = 178,
|
||||
}
|
||||
|
||||
local col_cheated_no = {
|
||||
red = 36,
|
||||
green = 154,
|
||||
blue = 36,
|
||||
}
|
||||
|
||||
local col_cheated_yes = {
|
||||
red = 224,
|
||||
green = 36,
|
||||
blue = 36,
|
||||
}
|
||||
|
||||
--[[ Constructs the cheat dialog.
|
||||
!param ui (UI) The active ui.
|
||||
]]
|
||||
function UICheats:UICheats(ui)
|
||||
self.cheats = ui.hospital.hosp_cheats
|
||||
self.cheat_list = ui.hospital.hosp_cheats.cheat_list
|
||||
|
||||
self:UIResizable(ui, 300, 200, col_bg)
|
||||
|
||||
self.default_button_sound = "selectx.wav"
|
||||
|
||||
self.modal_class = "cheats"
|
||||
self.esc_closes = true
|
||||
self.resizable = false
|
||||
self:setDefaultPosition(0.2, 0.4)
|
||||
|
||||
local y = 10
|
||||
self:addBevelPanel(20, y, 260, 20, col_caption):setLabel(_S.cheats_window.caption)
|
||||
.lowered = true
|
||||
|
||||
y = y + 30
|
||||
self:addColourPanel(20, y, 260, 40, col_bg.red, col_bg.green, col_bg.blue):setLabel({_S.cheats_window.warning})
|
||||
|
||||
y = y + 40
|
||||
self.cheated_panel = self:addBevelPanel(20, y, 260, 18, col_cheated_no, col_border, col_border)
|
||||
|
||||
local function button_clicked(num)
|
||||
return --[[persistable:cheats_button]] function(window)
|
||||
window:buttonClicked(num)
|
||||
end
|
||||
end
|
||||
|
||||
self.item_panels = {}
|
||||
self.item_buttons = {}
|
||||
|
||||
y = y + 30
|
||||
for num = 1, #self.cheat_list do
|
||||
self.item_panels[num] = self:addBevelPanel(20, y, 260, 20, col_bg)
|
||||
:setLabel(_S.cheats_window.cheats[self.cheat_list[num].name])
|
||||
self.item_buttons[num] = self.item_panels[num]:makeButton(0, 0, 260, 20, nil, button_clicked(num))
|
||||
:setTooltip(_S.tooltip.cheats_window.cheats[self.cheat_list[num].name])
|
||||
y = y + 20
|
||||
end
|
||||
|
||||
y = y + 20
|
||||
self:addBevelPanel(20, y, 260, 40, col_bg):setLabel(_S.cheats_window.close)
|
||||
:makeButton(0, 0, 260, 40, nil, self.buttonBack):setTooltip(_S.tooltip.cheats_window.close)
|
||||
|
||||
y = y + 60
|
||||
self:setSize(300, y)
|
||||
self:updateCheatedStatus()
|
||||
end
|
||||
|
||||
function UICheats:updateCheatedStatus()
|
||||
local cheated = self.ui.hospital.cheated
|
||||
self.cheated_panel:setLabel(cheated and _S.cheats_window.cheated.yes or _S.cheats_window.cheated.no)
|
||||
self.cheated_panel:setColour(cheated and col_cheated_yes or col_cheated_no)
|
||||
end
|
||||
|
||||
function UICheats:buttonClicked(num)
|
||||
if self.cheats:performCheat(num) then
|
||||
self.cheats.announceCheat(self.ui)
|
||||
self:updateCheatedStatus()
|
||||
else
|
||||
self.ui:addWindow(UIInformation(self.ui, {_S.information.cheat_not_possible}))
|
||||
end
|
||||
end
|
||||
|
||||
function UICheats:buttonBack()
|
||||
self:close()
|
||||
end
|
||||
|
||||
function UICheats:afterLoad(old, new)
|
||||
if old < 145 then
|
||||
-- Window must be closed if open for compatibility
|
||||
local cheatWindow = self.ui:getWindow(UICheats)
|
||||
if cheatWindow then
|
||||
cheatWindow:close()
|
||||
end
|
||||
end
|
||||
UIResizable.afterLoad(self, old, new)
|
||||
end
|
@@ -43,7 +43,7 @@ local col_caption = {
|
||||
}
|
||||
|
||||
function UICustomise:UICustomise(ui, mode)
|
||||
self:UIResizable(ui, 320, 280, col_bg)
|
||||
self:UIResizable(ui, 340, 300, col_bg)
|
||||
|
||||
local app = ui.app
|
||||
self.mode = mode
|
||||
@@ -57,68 +57,79 @@ function UICustomise:UICustomise(ui, mode)
|
||||
|
||||
-- Window parts definition
|
||||
-- Title
|
||||
self:addBevelPanel(80, 10, 160, 20, col_caption):setLabel(_S.customise_window.caption)
|
||||
self:addBevelPanel(85, 10, 170, 20, col_caption):setLabel(_S.customise_window.caption)
|
||||
.lowered = true
|
||||
|
||||
-- Movies, global switch
|
||||
self:addBevelPanel(20, 40, 135, 20, col_shadow, col_bg, col_bg)
|
||||
local audio_status = app:isAudioEnabled()
|
||||
self:addBevelPanel(15, 40, 165, 20, col_shadow, col_bg, col_bg)
|
||||
:setLabel(_S.customise_window.movies):setTooltip(_S.tooltip.customise_window.movies).lowered = true
|
||||
self.movies_panel =
|
||||
self:addBevelPanel(160, 40, 135, 20, col_bg):setLabel(app.config.movies and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self:addBevelPanel(185, 40, 140, 20, col_bg):setLabel(app.config.movies and audio_status and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self.movies_button = self.movies_panel:makeToggleButton(0, 0, 140, 20, nil, self.buttonMoviesGlobal)
|
||||
:setToggleState(app.config.movies):setTooltip(_S.tooltip.customise_window.movies)
|
||||
:setToggleState(app.config.movies and audio_status):setTooltip(_S.tooltip.customise_window.movies)
|
||||
self.movies_button.enabled = audio_status
|
||||
|
||||
-- Intro movie
|
||||
self:addBevelPanel(20, 65, 135, 20, col_shadow, col_bg, col_bg)
|
||||
self:addBevelPanel(15, 65, 165, 20, col_shadow, col_bg, col_bg)
|
||||
:setLabel(_S.customise_window.intro):setTooltip(_S.tooltip.customise_window.intro).lowered = true
|
||||
self.intro_panel =
|
||||
self:addBevelPanel(160, 65, 135, 20, col_bg):setLabel(app.config.play_intro and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self:addBevelPanel(185, 65, 140, 20, col_bg):setLabel(app.config.play_intro and audio_status and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self.intro_button = self.intro_panel:makeToggleButton(0, 0, 140, 20, nil, self.buttonIntro)
|
||||
:setToggleState(app.config.play_intro):setTooltip(_S.tooltip.customise_window.intro)
|
||||
:setToggleState(app.config.play_intro and audio_status):setTooltip(_S.tooltip.customise_window.intro)
|
||||
self.intro_button.enabled = audio_status
|
||||
|
||||
-- Allow user actions when paused
|
||||
self:addBevelPanel(20, 90, 135, 20, col_shadow, col_bg, col_bg)
|
||||
self:addBevelPanel(15, 90, 165, 20, col_shadow, col_bg, col_bg)
|
||||
:setLabel(_S.customise_window.paused):setTooltip(_S.tooltip.customise_window.paused).lowered = true
|
||||
self.paused_panel =
|
||||
self:addBevelPanel(160, 90, 135, 20, col_bg):setLabel(app.config.allow_user_actions_while_paused and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self:addBevelPanel(185, 90, 140, 20, col_bg):setLabel(app.config.allow_user_actions_while_paused and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self.paused_button = self.paused_panel:makeToggleButton(0, 0, 140, 20, nil, self.buttonPaused)
|
||||
:setToggleState(app.config.allow_user_actions_while_paused):setTooltip(_S.tooltip.customise_window.paused)
|
||||
|
||||
-- Volume down is opening casebook
|
||||
self:addBevelPanel(20, 115, 135, 20, col_shadow, col_bg, col_bg)
|
||||
self:addBevelPanel(15, 115, 165, 20, col_shadow, col_bg, col_bg)
|
||||
:setLabel(_S.customise_window.volume):setTooltip(_S.tooltip.customise_window.volume).lowered = true
|
||||
self.volume_panel =
|
||||
self:addBevelPanel(160, 115, 135, 20, col_bg):setLabel(app.config.volume_opens_casebook and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self:addBevelPanel(185, 115, 140, 20, col_bg):setLabel(app.config.volume_opens_casebook and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self.volume_button = self.volume_panel:makeToggleButton(0, 0, 140, 20, nil, self.buttonVolume)
|
||||
:setToggleState(app.config.volume_opens_casebook):setTooltip(_S.tooltip.customise_window.volume)
|
||||
|
||||
-- Alien DNA from emergencies only/must stand/can knock on doors
|
||||
self:addBevelPanel(20, 140, 135, 20, col_shadow, col_bg, col_bg)
|
||||
self:addBevelPanel(15, 140, 165, 20, col_shadow, col_bg, col_bg)
|
||||
:setLabel(_S.customise_window.aliens):setTooltip(_S.tooltip.customise_window.aliens).lowered = true
|
||||
self.aliens_panel =
|
||||
self:addBevelPanel(160, 140, 135, 20, col_bg):setLabel(app.config.alien_dna_only_by_emergency and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self:addBevelPanel(185, 140, 140, 20, col_bg):setLabel(app.config.alien_dna_only_by_emergency and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self.aliens_button = self.aliens_panel:makeToggleButton(0, 0, 140, 20, nil, self.buttonAliens)
|
||||
:setToggleState(app.config.alien_dna_only_by_emergency):setTooltip(_S.tooltip.customise_window.aliens)
|
||||
|
||||
-- Allow female patients with Fractured Bones
|
||||
self:addBevelPanel(20, 165, 135, 20, col_shadow, col_bg, col_bg)
|
||||
self:addBevelPanel(15, 165, 165, 20, col_shadow, col_bg, col_bg)
|
||||
:setLabel(_S.customise_window.fractured_bones):setTooltip(_S.tooltip.customise_window.fractured_bones).lowered = true
|
||||
self.fractured_bones_panel =
|
||||
self:addBevelPanel(160, 165, 135, 20, col_bg):setLabel(app.config.disable_fractured_bones_females and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self:addBevelPanel(185, 165, 140, 20, col_bg):setLabel(app.config.disable_fractured_bones_females and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self.fractured_bones_button = self.fractured_bones_panel:makeToggleButton(0, 0, 140, 20, nil, self.buttonFractured_bones)
|
||||
:setToggleState(app.config.disable_fractured_bones_females):setTooltip(_S.tooltip.customise_window.fractured_bones)
|
||||
|
||||
-- Allow average contents when building rooms
|
||||
self:addBevelPanel(20, 190, 135, 20, col_shadow, col_bg, col_bg)
|
||||
self:addBevelPanel(15, 190, 165, 20, col_shadow, col_bg, col_bg)
|
||||
:setLabel(_S.customise_window.average_contents):setTooltip(_S.tooltip.customise_window.average_contents).lowered = true
|
||||
self.average_contents_panel =
|
||||
self:addBevelPanel(160, 190, 135, 20, col_bg):setLabel(app.config.enable_avg_contents and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self:addBevelPanel(185, 190, 140, 20, col_bg):setLabel(app.config.enable_avg_contents and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self.average_contents_button = self.average_contents_panel:makeToggleButton(0, 0, 140, 20, nil, self.buttonAverage_contents)
|
||||
:setToggleState(app.config.enable_avg_contents):setTooltip(_S.tooltip.customise_window.average_contents)
|
||||
|
||||
-- Allow removal of destroyed rooms
|
||||
self:addBevelPanel(15, 215, 165, 20, col_shadow, col_bg, col_bg)
|
||||
:setLabel(_S.customise_window.remove_destroyed_rooms):setTooltip(_S.tooltip.customise_window.remove_destroyed_rooms).lowered = true
|
||||
self.destroyed_rooms_panel =
|
||||
self:addBevelPanel(185, 215, 140, 20, col_bg):setLabel(app.config.remove_destroyed_rooms and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self.destroyed_rooms_button = self.destroyed_rooms_panel:makeToggleButton(0, 0, 140, 20, nil, self.buttonDestroyed_rooms)
|
||||
:setToggleState(app.config.remove_destroyed_rooms):setTooltip(_S.tooltip.customise_window.remove_destroyed_rooms)
|
||||
|
||||
-- "Back" button
|
||||
self:addBevelPanel(20, 220, 280, 40, col_bg):setLabel(_S.customise_window.back)
|
||||
:makeButton(0, 0, 280, 40, nil, self.buttonBack):setTooltip(_S.tooltip.customise_window.back)
|
||||
self:addBevelPanel(15, 245, 310, 40, col_bg):setLabel(_S.customise_window.back)
|
||||
:makeButton(0, 0, 310, 40, nil, self.buttonBack):setTooltip(_S.tooltip.customise_window.back)
|
||||
end
|
||||
|
||||
function UICustomise:buttonAudioGlobal(checked)
|
||||
@@ -195,6 +206,15 @@ function UICustomise:buttonAverage_contents(checked)
|
||||
self:reload()
|
||||
end
|
||||
|
||||
function UICustomise:buttonDestroyed_rooms(checked)
|
||||
local app = self.ui.app
|
||||
app.config.remove_destroyed_rooms = not app.config.remove_destroyed_rooms
|
||||
self.destroyed_rooms_button:toggle()
|
||||
self.destroyed_rooms_panel:setLabel(app.config.remove_destroyed_rooms and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
app:saveConfig()
|
||||
self:reload()
|
||||
end
|
||||
|
||||
function UICustomise:buttonBack()
|
||||
self:close()
|
||||
local window = UIOptions(self.ui, "menu")
|
||||
|
@@ -71,23 +71,13 @@ function InstallDirTreeNode:createNewNode(path)
|
||||
return InstallDirTreeNode(path)
|
||||
end
|
||||
|
||||
--! Test if file name has an .iso extension
|
||||
local function isIso(name)
|
||||
if name == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
local ext = 'iso'
|
||||
return string.sub(name:lower(), -string.len(ext)) == ext
|
||||
end
|
||||
|
||||
--! Test whether this file node is a directory or iso file.
|
||||
--
|
||||
--!return (bool) true if directory or iso, false otherwise
|
||||
function InstallDirTreeNode:isValidFile(name)
|
||||
-- Check parent criteria and that it's a directory.
|
||||
if FileTreeNode.isValidFile(self, name) then
|
||||
return DirTreeNode.isValidFile(self, name) or isIso(name)
|
||||
return DirTreeNode.isValidFile(self, name) or FileSystem:isIso(name)
|
||||
end
|
||||
return false
|
||||
end
|
||||
@@ -112,28 +102,12 @@ function InstallDirTreeNode:getHighlightColour(canvas)
|
||||
-- Assume root-level things are not TH directories, unless we've already
|
||||
-- got a list of their children.
|
||||
highlight_colour = nil
|
||||
elseif self:getChildCount() >= 3 then
|
||||
local ngot = 0
|
||||
local things_to_check = {"data", "levels", "qdata"}
|
||||
for _, thing in ipairs(things_to_check) do
|
||||
if not self.children[thing:lower()] then
|
||||
break
|
||||
else
|
||||
ngot = ngot + 1
|
||||
end
|
||||
end
|
||||
if ngot == 3 then
|
||||
highlight_colour = canvas:mapRGB(0, 255, 0)
|
||||
self.is_valid_directory = true
|
||||
end
|
||||
elseif isIso(self.path) then
|
||||
local file = io.open(self.path, "rb")
|
||||
if not file then return nil end
|
||||
if iso_fs:setRoot(file) then
|
||||
highlight_colour = canvas:mapRGB(0, 255, 0)
|
||||
self.is_valid_directory = true
|
||||
end
|
||||
io.close(file)
|
||||
elseif self:getChildCount() >= 3 and TheApp:isThemeHospitalPath(self.path) then
|
||||
highlight_colour = canvas:mapRGB(0, 255, 0)
|
||||
self.is_valid_directory = true
|
||||
elseif FileSystem:isIso(self.path) and iso_fs:setRoot(self.path) then
|
||||
highlight_colour = canvas:mapRGB(0, 255, 0)
|
||||
self.is_valid_directory = true
|
||||
end
|
||||
self.highlight_colour = highlight_colour
|
||||
end
|
||||
|
@@ -29,7 +29,7 @@ local UIDropdown = _G["UIDropdown"]
|
||||
--!param parent_window (Window) The window that this dropdown will be attached to
|
||||
--!param parent_button (Button) The button in the parent_window that this dropdown will be positioned under
|
||||
--!param items (table) A list of items for the list to display, where each item is a table with at least
|
||||
-- the field text, and optionally fields font and/or tooltip
|
||||
-- the field text, and optionally fields font and/or tooltip, which is a table containing text, x and y positions.
|
||||
--!param callback (function) A function to be called when an item is selected. It is called with two parameters:
|
||||
-- The parent window and the index of the selected item
|
||||
--!param colour (table) A colour in the form of {red = ..., green = ..., blue = ...}. Optional if parent_window is a UIResizable
|
||||
@@ -57,10 +57,16 @@ function UIDropdown:UIDropdown(ui, parent_window, parent_button, items, callback
|
||||
|
||||
local y = 0
|
||||
for i, item in ipairs(items) do
|
||||
if item.tooltip and item.tooltip[1] then
|
||||
self:addBevelPanel(1, y + 1, width - 2, height - 2, parent_window.colour):setLabel(item.text, item.font)
|
||||
:makeButton(-1, -1, width, height, nil, --[[persistable:dropdown_tooltip_callback]] function() self:selectItem(i) end)
|
||||
:setTooltip(item.tooltip[1], item.tooltip[2] or math.floor(self.ui.app.config.width / 2 - 25),
|
||||
math.floor(self.ui.app.config.height / 4 - 130 + item.tooltip[3]) or 0)
|
||||
-- Magic numbers used to find a static position across different screen resolutions.
|
||||
else
|
||||
self:addBevelPanel(1, y + 1, width - 2, height - 2, parent_window.colour):setLabel(item.text, item.font)
|
||||
:makeButton(-1, -1, width, height, nil, --[[persistable:dropdown_callback]] function() self:selectItem(i) end)
|
||||
-- TODO: tooltips for dropdown items currently deactivated because alignment and conditions for displaying are off for tooltips on sub-windows
|
||||
--:setTooltip(item.tooltip)
|
||||
end
|
||||
y = y + height
|
||||
end
|
||||
|
||||
|
@@ -88,12 +88,16 @@ function FilteredTreeControl:FilteredTreeControl(root, x, y, width, height, col_
|
||||
|
||||
self.num_rows = (self.tree_rect.h - self.y_offset) / self.row_height
|
||||
|
||||
-- Magic numbers used to find a static position across different screen resolutions.
|
||||
local button1x = math.floor(TheApp.ui.app.config.width / 2 - 90)
|
||||
local button2x = button1x + 210
|
||||
local buttony = math.floor(TheApp.ui.app.config.height / 4 - 95)
|
||||
-- Add the two column headers and make buttons on them.
|
||||
if show_dates then
|
||||
self:addBevelPanel(1, 1, width - 170, 13, col_bg):setLabel(_S.menu_list_window.name)
|
||||
:makeButton(0, 0, width - 170, 13, nil, self.sortByName):setTooltip(_S.tooltip.menu_list_window.name)
|
||||
:makeButton(0, 0, width - 170, 13, nil, self.sortByName):setTooltip(_S.tooltip.menu_list_window.name, button1x, buttony)
|
||||
self:addBevelPanel(width - 169, 1, 150, 13, col_bg):setLabel(_S.menu_list_window.save_date)
|
||||
:makeButton(0, 0, 150, 13, nil, self.sortByDate):setTooltip(_S.tooltip.menu_list_window.save_date)
|
||||
:makeButton(0, 0, 150, 13, nil, self.sortByDate):setTooltip(_S.tooltip.menu_list_window.save_date, button2x, buttony)
|
||||
end
|
||||
self.show_dates = show_dates
|
||||
end
|
||||
|
@@ -41,12 +41,18 @@ function UILoadGame:choiceMade(name)
|
||||
local status, err = pcall(app.load, app, name)
|
||||
if not status then
|
||||
err = _S.errors.load_prefix .. err
|
||||
print(err)
|
||||
app:loadMainMenu()
|
||||
app.ui:addWindow(UIInformation(self.ui, {err}))
|
||||
self:loadError(err)
|
||||
end
|
||||
end
|
||||
|
||||
--! Output the error when trying to load a game
|
||||
--!param err The error given
|
||||
function UILoadGame:loadError(err)
|
||||
print(err)
|
||||
TheApp:loadMainMenu()
|
||||
TheApp.ui:addWindow(UIInformation(TheApp.ui, {err}))
|
||||
end
|
||||
|
||||
function UILoadGame:close()
|
||||
UIResizable.close(self)
|
||||
if self.mode == "menu" then
|
||||
|
@@ -122,6 +122,7 @@ function UILuaConsole:buttonExecute()
|
||||
print("Error while executing UserFunction:")
|
||||
print(err)
|
||||
end
|
||||
_ = nil -- Clean up the global after use or it'll corrupt saves
|
||||
end
|
||||
|
||||
function UILuaConsole:buttonClose()
|
||||
|
@@ -79,14 +79,17 @@ function UINewGame:UINewGame(ui)
|
||||
|
||||
|
||||
local avail_diff = {
|
||||
{text = _S.new_game_window.medium, tooltip = _S.tooltip.new_game_window.medium, param = "full"},
|
||||
{text = _S.new_game_window.medium, tooltip = { _S.tooltip.new_game_window.medium,
|
||||
nil, 130 }, param = "full"}
|
||||
}
|
||||
if TheApp.fs:fileExists("Levels", "Easy01.SAM") then
|
||||
table.insert(avail_diff, 1, {text = _S.new_game_window.easy, tooltip = _S.tooltip.new_game_window.easy, param = "easy"})
|
||||
table.insert(avail_diff, 1, {text = _S.new_game_window.easy, tooltip = { _S.tooltip.new_game_window.easy,
|
||||
nil, 100 }, param = "easy"})
|
||||
self.difficulty = 2
|
||||
end
|
||||
if TheApp.fs:fileExists("Levels", "Hard01.SAM") then
|
||||
avail_diff[#avail_diff + 1] = {text = _S.new_game_window.hard, tooltip = _S.tooltip.new_game_window.hard, param = "hard"}
|
||||
avail_diff[#avail_diff + 1] = {text = _S.new_game_window.hard, tooltip = { _S.tooltip.new_game_window.hard,
|
||||
nil, 175 }, param = "hard"}
|
||||
end
|
||||
self.available_difficulties = avail_diff
|
||||
|
||||
@@ -194,6 +197,8 @@ end
|
||||
|
||||
function UINewGame:startGame(difficulty)
|
||||
self.ui.app:loadLevel(1, difficulty)
|
||||
self.ui.app.moviePlayer:playAdvanceMovie(1)
|
||||
|
||||
-- Initiate campaign progression. The UI above may now have changed.
|
||||
if not TheApp.using_demo_files then
|
||||
TheApp.world.campaign_info = "TH.campaign"
|
||||
|
@@ -24,6 +24,10 @@ class "UIOptions" (UIResizable)
|
||||
---@type UIOptions
|
||||
local UIOptions = _G["UIOptions"]
|
||||
|
||||
-- Constants for most button's width and height
|
||||
local BTN_WIDTH = 135
|
||||
local BTN_HEIGHT = 20
|
||||
|
||||
local col_bg = {
|
||||
red = 154,
|
||||
green = 146,
|
||||
@@ -89,10 +93,6 @@ function UIOptions:UIOptions(ui, mode)
|
||||
-- Tracks the current position of the object
|
||||
self._current_option_index = 1
|
||||
|
||||
-- Constants for most button's width and height
|
||||
local BTN_WIDTH = 135
|
||||
local BTN_HEIGHT = 20
|
||||
|
||||
self:checkForAvailableLanguages()
|
||||
|
||||
-- Set up list of resolutions
|
||||
@@ -166,13 +166,15 @@ function UIOptions:UIOptions(ui, mode)
|
||||
self.language_button = self.language_panel:makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.dropdownLanguage):setTooltip(_S.tooltip.options_window.select_language)
|
||||
|
||||
-- add the Audio global switch.
|
||||
local audio_status = app:isAudioEnabled()
|
||||
local audio_y_pos = self:_getOptionYPos()
|
||||
self:addBevelPanel(20, audio_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg)
|
||||
:setLabel(_S.options_window.audio):setTooltip(_S.tooltip.options_window.audio_button).lowered = true
|
||||
self.volume_panel =
|
||||
self:addBevelPanel(165, audio_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(app.config.audio and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self:addBevelPanel(165, audio_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(app.config.audio and audio_status and _S.customise_window.option_on or _S.customise_window.option_off)
|
||||
self.volume_button = self.volume_panel:makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.buttonAudioGlobal)
|
||||
:setToggleState(app.config.audio):setTooltip(_S.tooltip.options_window.audio_toggle)
|
||||
:setToggleState(app.config.audio and audio_status):setTooltip(_S.tooltip.options_window.audio_toggle)
|
||||
self.volume_button.enabled = audio_status
|
||||
|
||||
-- Set scroll speed.
|
||||
local scroll_y_pos = self:_getOptionYPos()
|
||||
@@ -221,12 +223,15 @@ local --[[persistable:options_height_textbox_reset]] function height_textbox_res
|
||||
function UIOptions:checkForAvailableLanguages()
|
||||
local app = self.app
|
||||
-- Set up list of available languages
|
||||
local langs = {}
|
||||
for _, lang in ipairs(app.strings.languages) do
|
||||
local langs, c = {}, 1
|
||||
for _, lang in pairs(app.strings.languages) do
|
||||
local font = app.strings:getFont(lang)
|
||||
if app.gfx:hasLanguageFont(font) then
|
||||
if app.gfx:hasLanguageFont(font) and app.strings.languages_english[lang] then
|
||||
local eng_name = app.strings.languages_english[lang]
|
||||
c = c + 1
|
||||
font = font and app.gfx:loadLanguageFont(font, app.gfx:loadSpriteTable("QData", "Font01V"))
|
||||
langs[#langs + 1] = {text = lang, font = font, tooltip = _S.tooltip.options_window.language_dropdown_item:format(lang)}
|
||||
langs[#langs + 1] = { text = lang, font = font,
|
||||
tooltip = { _S.tooltip.options_window.language_dropdown_item:format(eng_name), nil, BTN_HEIGHT * c } }
|
||||
end
|
||||
end
|
||||
self.available_languages = langs
|
||||
@@ -247,8 +252,9 @@ function UIOptions:dropdownLanguage(activate)
|
||||
end
|
||||
|
||||
function UIOptions:selectLanguage(number)
|
||||
local lang = self.app.strings.languages_english[self.available_languages[number]["text"]]
|
||||
local app = self.ui.app
|
||||
app.config.language = (self.available_languages[number].text)
|
||||
app.config.language = (lang)
|
||||
app:initLanguage()
|
||||
app:saveConfig()
|
||||
end
|
||||
|
@@ -69,14 +69,6 @@ function UIUpdate:UIUpdate(ui, this_version, new_version, brief_description, dow
|
||||
self.white_font = app.gfx:loadFont("QData", "Font01V")
|
||||
self.download_url = download_url
|
||||
|
||||
local pathsep = package.config:sub(1, 1)
|
||||
|
||||
if pathsep == "\\" then
|
||||
self.os_is_windows = true
|
||||
else
|
||||
self.os_is_windows = false
|
||||
end
|
||||
|
||||
self:addBevelPanel(20, 50, 140, 20, col_shadow, col_bg, col_bg)
|
||||
:setLabel(_S.update_window.current_version).lowered = true
|
||||
self:addBevelPanel(20, 70, 140, 20, col_shadow, col_bg, col_bg)
|
||||
@@ -109,8 +101,10 @@ end
|
||||
|
||||
function UIUpdate:buttonDownload()
|
||||
|
||||
if self.os_is_windows then
|
||||
if self.app.os == "windows" then
|
||||
os.execute("start " .. self.download_url)
|
||||
elseif self.app.os == "macos" then
|
||||
os.execute("open " .. self.download_url)
|
||||
else
|
||||
os.execute("xdg-open " .. self.download_url)
|
||||
end
|
||||
|
@@ -255,11 +255,6 @@ function UIStaff:onMouseDown(button, x, y)
|
||||
return Window.onMouseDown(self, button, x, y)
|
||||
end
|
||||
|
||||
-- Helper function to facilitate humanoid_class comparison wrt. Surgeons
|
||||
local function surg_compat(class)
|
||||
return class == "Surgeon" and "Doctor" or class
|
||||
end
|
||||
|
||||
function UIStaff:onMouseUp(button, x, y)
|
||||
local ui = self.ui
|
||||
if button == "left" then
|
||||
@@ -271,7 +266,7 @@ function UIStaff:onMouseUp(button, x, y)
|
||||
-- Right click goes to the next staff member of the same category (NB: Surgeon in same Category as Doctor)
|
||||
local staff_index = nil
|
||||
for i, staff in ipairs(ui.hospital.staff) do
|
||||
if staff_index and surg_compat(staff.humanoid_class) == surg_compat(self.staff.humanoid_class) then
|
||||
if staff_index and staff.profile.humanoid_class == self.staff.profile.humanoid_class then
|
||||
ui:addWindow(UIStaff(ui, staff))
|
||||
return false
|
||||
end
|
||||
@@ -282,7 +277,7 @@ function UIStaff:onMouseUp(button, x, y)
|
||||
-- Try again from beginning of list until staff_index
|
||||
for i = 1, staff_index - 1 do
|
||||
local staff = ui.hospital.staff[i]
|
||||
if surg_compat(staff.humanoid_class) == surg_compat(self.staff.humanoid_class) then
|
||||
if staff.profile.humanoid_class == self.staff.profile.humanoid_class then
|
||||
ui:addWindow(UIStaff(ui, staff))
|
||||
return false
|
||||
end
|
||||
@@ -327,6 +322,12 @@ function UIStaff:changeHandymanAttributes(increased)
|
||||
return
|
||||
end
|
||||
|
||||
-- Show a helpful message if this dialog hasn't been opened yet
|
||||
if not self.ui.hospital.handyman_popup then
|
||||
self.ui.adviser:say(_A.information.handyman_adjust)
|
||||
self.ui.hospital.handyman_popup = true
|
||||
end
|
||||
|
||||
local incr_value = 0.1 -- Increase of 'increased'
|
||||
local smallest_decr = 0.05 -- Smallest decrement that can be performed.
|
||||
local decr_attrs = {}
|
||||
|
@@ -102,6 +102,11 @@ function UIStaffRise:UIStaffRise(ui, staff, rise_amount)
|
||||
end
|
||||
end
|
||||
|
||||
-- Staff raise requests pause game
|
||||
function UIStaffRise:mustPause()
|
||||
return true
|
||||
end
|
||||
|
||||
function UIStaffRise:getStaffPosition(dx, dy)
|
||||
local staff = self.staff
|
||||
local x, y = self.ui.app.map:WorldToScreen(staff.tile_x, staff.tile_y)
|
||||
@@ -172,10 +177,6 @@ function UIStaffRise:fireStaff()
|
||||
self.staff.message_callback = nil
|
||||
self.staff:fire()
|
||||
self:close()
|
||||
local world = self.ui.app.world
|
||||
if world and world:isCurrentSpeed("Pause") then
|
||||
world:setSpeed(world.prev_speed)
|
||||
end
|
||||
end
|
||||
|
||||
function UIStaffRise:increaseSalary()
|
||||
@@ -183,10 +184,6 @@ function UIStaffRise:increaseSalary()
|
||||
self.staff:increaseWage(self.rise_amount)
|
||||
self.staff.quitting_in = nil
|
||||
self:close()
|
||||
local world = self.ui.app.world
|
||||
if world and world:isCurrentSpeed("Pause") then
|
||||
world:setSpeed(world.prev_speed)
|
||||
end
|
||||
end
|
||||
|
||||
function UIStaffRise:afterLoad(old, new)
|
||||
|
@@ -25,6 +25,10 @@ class "UIWatch" (Window)
|
||||
---@type UIWatch
|
||||
local UIWatch = _G["UIWatch"]
|
||||
|
||||
local TICK_DAYS = 100
|
||||
local TICK_DAYS_EMERGENCY = 52
|
||||
local TIMER_SEGMENTS = 13
|
||||
|
||||
--!param count_type (string) One of: "open_countdown" or "emergency" or "epidemic"
|
||||
function UIWatch:UIWatch(ui, count_type)
|
||||
self:Window()
|
||||
@@ -33,8 +37,13 @@ function UIWatch:UIWatch(ui, count_type)
|
||||
|
||||
self.esc_closes = false
|
||||
self.modal_class = "open_countdown"
|
||||
self.tick_rate = math.floor((100 * Date.hoursPerDay()) / 13)
|
||||
self.tick_timer = self.tick_rate -- Initialize tick timer
|
||||
if count_type == "emergency" then
|
||||
self.tick_rate = math.floor((TICK_DAYS_EMERGENCY * Date.hoursPerDay()) / TIMER_SEGMENTS)
|
||||
self.tick_timer = self.tick_rate
|
||||
else
|
||||
self.tick_rate = math.floor((TICK_DAYS * Date.hoursPerDay()) / TIMER_SEGMENTS)
|
||||
self.tick_timer = self.tick_rate -- Initialize tick timer
|
||||
end
|
||||
self.open_timer = 12
|
||||
self.ui = ui
|
||||
self.hospital = ui.hospital
|
||||
@@ -93,7 +102,6 @@ function UIWatch:onCountdownEnd()
|
||||
end
|
||||
elseif self.count_type == "initial_opening" then
|
||||
self.ui.hospital.opened = true
|
||||
self.ui.hospital.boiler_can_break = true -- boiler can't break whilst build timer is open
|
||||
self.ui:playSound("fanfare.wav")
|
||||
end
|
||||
end
|
||||
|
@@ -251,7 +251,7 @@ moods("cold", 3994, 0, true) -- These have no priority sin
|
||||
moods("hot", 3988, 0, true) -- they will be shown when hovering
|
||||
moods("queue", 4568, 70) -- no matter what other priorities.
|
||||
moods("poo", 3996, 5)
|
||||
moods("sad_money", 4018, 50)
|
||||
moods("sad_money", 4018, 55)
|
||||
moods("patient_wait", 5006, 40)
|
||||
moods("epidemy1", 4566, 55)
|
||||
moods("epidemy2", 4570, 55)
|
||||
@@ -492,8 +492,6 @@ local function Humanoid_startAction(self)
|
||||
elseif class.is(self, Staff) then
|
||||
ui:addWindow(UIStaff(ui, self))
|
||||
end
|
||||
-- Pause the game.
|
||||
self.world:setSpeed("Pause")
|
||||
|
||||
-- Tell the player what just happened.
|
||||
self.world:gameLog("")
|
||||
@@ -931,13 +929,14 @@ function Humanoid:tostring()
|
||||
|
||||
local result = string.format("%s - class: %s", full_name, class)
|
||||
|
||||
result = result .. string.format("\nWarmth: %.3f Happiness: %.3f Fatigue: %.3f Thirst: %.3f Toilet_Need: %.3f Health: %.3f",
|
||||
result = result .. string.format("\nWarmth: %.3f Happiness: %.3f Fatigue: %.3f Thirst: %.3f Toilet_Need: %.3f Health: %.3f Service Quality: %.3f",
|
||||
self.attributes["warmth"] or 0,
|
||||
self.attributes["happiness"] or 0,
|
||||
self.attributes["fatigue"] or 0,
|
||||
self.attributes["thirst"] or 0,
|
||||
self.attributes["toilet_need"] or 0,
|
||||
self.attributes["health"] or 0)
|
||||
self.attributes["health"] or 0,
|
||||
self.attributes["fatigue"] and self:getServiceQuality() or 0)
|
||||
|
||||
result = result .. "\nActions: ["
|
||||
for i = 1, #self.action_queue do
|
||||
|
@@ -301,8 +301,16 @@ function Patient:isTreatmentEffective()
|
||||
local cure_chance = self.hospital.disease_casebook[self.disease.id].cure_effectiveness
|
||||
cure_chance = cure_chance * self.diagnosis_progress
|
||||
|
||||
local die = self.die_anims and math.random(1, 100) > cure_chance
|
||||
return not die
|
||||
-- Service quality has a factor on cure chance
|
||||
local room = self:getRoom()
|
||||
local min_impact = 20
|
||||
local service_base = math.max(100 - cure_chance, min_impact)
|
||||
|
||||
local scale = 0.2 -- Quality scaled to +-10%
|
||||
local service_factor = (room:getStaffServiceQuality() - 0.5) * scale
|
||||
cure_chance = cure_chance + (service_base * service_factor)
|
||||
|
||||
return (cure_chance >= math.random(1,100))
|
||||
end
|
||||
|
||||
--! Change patient internal state to "cured".
|
||||
@@ -312,21 +320,11 @@ function Patient:cure()
|
||||
self.attributes["health"] = 1
|
||||
end
|
||||
|
||||
--! Patient died, process the event.
|
||||
function Patient:die()
|
||||
-- It may happen that this patient was just cured and then the room blew up.
|
||||
local hospital = self.hospital
|
||||
|
||||
if hospital.num_deaths < 1 then
|
||||
self.world.ui.adviser:say(_A.information.first_death)
|
||||
end
|
||||
hospital:humanoidDeath(self)
|
||||
if not self.is_debug then
|
||||
local casebook = hospital.disease_casebook[self.disease.id]
|
||||
casebook.fatalities = casebook.fatalities + 1
|
||||
end
|
||||
hospital:msgKilled()
|
||||
self.hospital:humanoidDeath(self)
|
||||
self:setMood("dead", "activate")
|
||||
self.world.ui:playSound("boo.wav") -- this sound is always heard
|
||||
|
||||
-- Remove any messages and/or callbacks related to the patient.
|
||||
self:unregisterCallbacks()
|
||||
@@ -337,9 +335,6 @@ function Patient:die()
|
||||
else
|
||||
self:setNextAction(MeanderAction():setCount(1))
|
||||
end
|
||||
if self.is_emergency then
|
||||
hospital.emergency.killed_emergency_patients = hospital.emergency.killed_emergency_patients + 1
|
||||
end
|
||||
self:queueAction(DieAction())
|
||||
self:updateDynamicInfo(_S.dynamic_info.patient.actions.dying)
|
||||
end
|
||||
@@ -472,14 +467,12 @@ function Patient:goHome(reason, disease_id)
|
||||
if reason == "cured" then
|
||||
self:setMood("cured", "activate")
|
||||
self:changeAttribute("happiness", 0.8)
|
||||
self.world.ui:playSound("cheer.wav") -- This sound is always heard
|
||||
self.hospital:updateCuredCounts(self)
|
||||
hosp:updateCuredCounts(self)
|
||||
self:updateDynamicInfo(_S.dynamic_info.patient.actions.cured)
|
||||
self.hospital:msgCured()
|
||||
|
||||
elseif reason == "kicked" then
|
||||
self:setMood("exit", "activate")
|
||||
self.hospital:updateNotCuredCounts(self, reason)
|
||||
hosp:updateNotCuredCounts(self, reason)
|
||||
|
||||
elseif reason == "over_priced" then
|
||||
self:setMood("sad_money", "activate")
|
||||
@@ -487,13 +480,13 @@ function Patient:goHome(reason, disease_id)
|
||||
|
||||
local treatment_name = self.hospital.disease_casebook[disease_id].disease.name
|
||||
self.world.ui.adviser:say(_A.warnings.patient_not_paying:format(treatment_name))
|
||||
self.hospital:updateNotCuredCounts(self, reason)
|
||||
hosp:updateNotCuredCounts(self, reason)
|
||||
self:clearDynamicInfo()
|
||||
self:updateDynamicInfo(_S.dynamic_info.patient.actions.prices_too_high)
|
||||
self:setDynamicInfo('text', {"", _S.dynamic_info.patient.actions.prices_too_high})
|
||||
|
||||
elseif reason == "evacuated" then
|
||||
self:clearDynamicInfo()
|
||||
self:setDynamicInfo('text', {_S.dynamic_info.patient.actions.epidemic_sent_home})
|
||||
self:setDynamicInfo('text', {"", _S.dynamic_info.patient.actions.epidemic_sent_home})
|
||||
self:setMood("exit","activate")
|
||||
|
||||
else
|
||||
@@ -516,6 +509,11 @@ function Patient:goHome(reason, disease_id)
|
||||
self.world.dispatcher:dropFromQueue(self)
|
||||
end
|
||||
|
||||
-- allow timer to end early and after going_home is set
|
||||
if self.is_emergency then
|
||||
hosp:checkEmergencyOver()
|
||||
end
|
||||
|
||||
local room = self:getRoom()
|
||||
if room then
|
||||
room:makeHumanoidLeave(self)
|
||||
@@ -691,13 +689,8 @@ function Patient:tickDay()
|
||||
-- It is nice to see plants, but dead plants make you unhappy
|
||||
self.world:findObjectNear(self, "plant", 2, function(x, y)
|
||||
local plant = self.world:getObject(x, y, "plant")
|
||||
if not plant then
|
||||
return
|
||||
end
|
||||
if plant:isPleasing() then
|
||||
self:changeAttribute("happiness", 0.0002)
|
||||
else
|
||||
self:changeAttribute("happiness", -0.0002)
|
||||
if plant then
|
||||
self:changeAttribute("happiness", -0.0003 + (plant:isPleasingFactor() * 0.0001))
|
||||
end
|
||||
end)
|
||||
-- It always makes you happy to see you are in safe place
|
||||
@@ -883,7 +876,7 @@ function Patient:setTile(x, y)
|
||||
self.hospital.hospital_littered = true
|
||||
|
||||
-- A callout is only needed if there are no handymen employed
|
||||
if not self.hospital:hasStaffOfCategory("Handyman") then
|
||||
if self.hospital:countStaffOfCategory("Handyman", 1) == 0 then
|
||||
self.world.ui.adviser:say(_A.staff_advice.need_handyman_litter)
|
||||
end
|
||||
end
|
||||
@@ -951,7 +944,11 @@ function Patient:updateDynamicInfo(action_string)
|
||||
-- The cure was guessed
|
||||
info = _S.dynamic_info.patient.guessed_diagnosis:format(self.disease.name)
|
||||
else
|
||||
info = _S.dynamic_info.patient.diagnosed:format(self.disease.name)
|
||||
if self.is_emergency then
|
||||
info = _S.dynamic_info.patient.emergency:format(self.disease.name)
|
||||
else
|
||||
info = _S.dynamic_info.patient.diagnosed:format(self.disease.name)
|
||||
end
|
||||
end
|
||||
self:setDynamicInfo('progress', nil)
|
||||
else
|
||||
@@ -975,6 +972,8 @@ function Patient:updateDynamicInfo(action_string)
|
||||
elseif self.vaccinated then
|
||||
self:setDynamicInfo('text',
|
||||
{action_string, _S.dynamic_info.patient.actions.epidemic_vaccinated, info})
|
||||
else
|
||||
self:setDynamicInfo('text', {action_string, "", info})
|
||||
end
|
||||
else
|
||||
self:setDynamicInfo('text', {action_string, "", info})
|
||||
@@ -999,8 +998,10 @@ function Patient:updateMessage(choice)
|
||||
-- enable only if research department is built and a room in the treatment chain is undiscovered
|
||||
local req = self.hospital:checkDiseaseRequirements(self.disease.id)
|
||||
if req then
|
||||
enabled = (self.hospital:countRoomOfType("research", 1) > 0 and
|
||||
self.hospital:countStaffOfCategory("Researcher", 1) > 0)
|
||||
|
||||
local strings = _S.fax.disease_discovered_patient_choice
|
||||
enabled = self.hospital:hasRoomOfType("research") and self.hospital:hasStaffOfCategory("Researcher")
|
||||
local output_text = strings.can_not_cure
|
||||
if #req.rooms == 1 then
|
||||
local room_name, required_staff, staff_name = self.world:getRoomNameAndRequiredStaffName(req.rooms[1])
|
||||
|
@@ -62,11 +62,7 @@ function Staff:tickDay()
|
||||
self.world:findObjectNear(self, "plant", 2, function(x, y)
|
||||
local plant = self.world:getObject(x, y, "plant")
|
||||
if plant then
|
||||
if plant:isPleasing() then
|
||||
self:changeAttribute("happiness", 0.002)
|
||||
else
|
||||
self:changeAttribute("happiness", -0.003)
|
||||
end
|
||||
self:changeAttribute("happiness", -0.003 + (plant:isPleasingFactor() * 0.001))
|
||||
end
|
||||
end)
|
||||
-- It always makes you happy to see you are in safe place
|
||||
@@ -97,8 +93,23 @@ function Staff:tickDay()
|
||||
self:changeAttribute("happiness", 0.05)
|
||||
end
|
||||
|
||||
--TODO windows in your work space and a large space to work in add to happiness
|
||||
-- working in a small space makes you unhappy
|
||||
local room = self:getRoom()
|
||||
if room then
|
||||
-- It always makes you happy to see the outdoors (or windows to anywhere)
|
||||
local count = room:countWindows()
|
||||
if room.room_info.id == "staff_room" then -- Pleased another bit
|
||||
count = count * 2
|
||||
end
|
||||
if count > 0 then
|
||||
-- More windows help but in smaller increments
|
||||
self:changeAttribute("happiness", math.round(math.log(count)) / 1000)
|
||||
end
|
||||
|
||||
-- Extra space in the room you are in adds to your happiness
|
||||
local extraspace = (room.width * room.height) / (room.room_info.minimum_size * room.room_info.minimum_size)
|
||||
-- Greater space helps but in smaller increments
|
||||
self:changeAttribute("happiness", math.round(math.log(extraspace)) / 1000)
|
||||
end
|
||||
end
|
||||
|
||||
function Staff:tick()
|
||||
@@ -441,7 +452,7 @@ function Staff:setHospital(hospital)
|
||||
end
|
||||
|
||||
-- Helper function to decide if Staff fulfills a criterion
|
||||
-- (one of "Doctor", "Nurse", "Psychiatrist", "Surgeon", "Researcher" and "Handyman")
|
||||
-- (one of "Doctor", "Nurse", "Psychiatrist", "Surgeon", "Researcher" and "Handyman", "Receptionist", "Junior", "Consultant")
|
||||
function Staff:fulfillsCriterion(criterion)
|
||||
return false
|
||||
end
|
||||
@@ -659,19 +670,20 @@ function Staff:getDrawingLayer()
|
||||
return 4
|
||||
end
|
||||
|
||||
--! Estimate staff service quality based on skills, fatigue and happiness.
|
||||
--! Estimate staff service quality based on skills, restfulness (inverse of fatigue) and happiness.
|
||||
--!return (float) between [0-1] indicating quality of the service.
|
||||
function Staff:getServiceQuality()
|
||||
-- weights
|
||||
local skill_weight = 0.7
|
||||
local fatigue_weight = 0.2
|
||||
local restfulness_weight = 0.2
|
||||
local happiness_weight = 0.1
|
||||
|
||||
local weighted_skill = skill_weight * self.profile.skill
|
||||
local weighted_fatigue = fatigue_weight * self.attributes["fatigue"]
|
||||
-- Less fatigue is better
|
||||
local weighted_restfulness = restfulness_weight * (1 - self.attributes["fatigue"])
|
||||
local weighted_happiness = happiness_weight * self.attributes["happiness"]
|
||||
|
||||
return weighted_skill + weighted_fatigue + weighted_happiness
|
||||
return weighted_skill + weighted_restfulness + weighted_happiness
|
||||
end
|
||||
|
||||
--[[ Return string representation
|
||||
|
@@ -249,17 +249,18 @@ local profile_attributes = {
|
||||
Psychiatrist = "is_psychiatrist",
|
||||
Surgeon = "is_surgeon",
|
||||
Researcher = "is_researcher",
|
||||
Junior = "is_junior",
|
||||
Consultant = "is_consultant",
|
||||
}
|
||||
|
||||
-- Helper function to decide if Staff fulfills a criterion
|
||||
-- (one of "Doctor", "Nurse", "Psychiatrist", "Surgeon", "Researcher" and "Handyman")
|
||||
-- (one of "Doctor", "Nurse", "Psychiatrist", "Surgeon", "Researcher" and "Handyman", "Receptionist", "Junior", "Consultant")
|
||||
function Doctor:fulfillsCriterion(criterion)
|
||||
if criterion == "Doctor" then
|
||||
return true
|
||||
elseif criterion == "Psychiatrist" or criterion == "Surgeon" or criterion == "Researcher" then
|
||||
if self.profile and self.profile[profile_attributes[criterion]] == 1.0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
if self.profile and self.profile[profile_attributes[criterion]] == 1.0 then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
@@ -84,12 +84,9 @@ function Handyman:onPlaceInCorridor()
|
||||
end
|
||||
|
||||
-- Helper function to decide if Handyman fulfills a criterion
|
||||
-- (one of "Doctor", "Nurse", "Psychiatrist", "Surgeon", "Researcher" and "Handyman")
|
||||
-- (one of "Doctor", "Nurse", "Psychiatrist", "Surgeon", "Researcher" and "Handyman", "Receptionist", "Junior", "Consultant")
|
||||
function Handyman:fulfillsCriterion(criterion)
|
||||
if criterion == "Handyman" then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
return criterion == "Handyman"
|
||||
end
|
||||
|
||||
function Handyman:afterLoad(old, new)
|
||||
|
@@ -42,12 +42,9 @@ function Nurse:leaveAnnounce()
|
||||
end
|
||||
|
||||
-- Helper function to decide if Staff fulfills a criterion
|
||||
-- (one of "Doctor", "Nurse", "Psychiatrist", "Surgeon", "Researcher" and "Handyman")
|
||||
-- (one of "Doctor", "Nurse", "Psychiatrist", "Surgeon", "Researcher" and "Handyman", "Receptionist", "Junior", "Consultant")
|
||||
function Nurse:fulfillsCriterion(criterion)
|
||||
if criterion == "Nurse" then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
return criterion == "Nurse"
|
||||
end
|
||||
|
||||
function Nurse:adviseWrongPersonForThisRoom()
|
||||
|
@@ -40,10 +40,8 @@ function Receptionist:tickDay()
|
||||
end
|
||||
|
||||
function Receptionist:leaveAnnounce()
|
||||
local announcement_priority = AnnouncementPriority.High
|
||||
|
||||
local receptionist_leave_sounds = {"sack007.wav", "sack008.wav",}
|
||||
self.world.ui:playAnnouncement(receptionist_leave_sounds[math.random(1, #receptionist_leave_sounds)], announcement_priority)
|
||||
self.world.ui:playAnnouncement(receptionist_leave_sounds[math.random(1, #receptionist_leave_sounds)], AnnouncementPriority.Critical) -- must always be played even without receptionist
|
||||
end
|
||||
|
||||
function Receptionist:isTiring()
|
||||
@@ -61,7 +59,7 @@ end
|
||||
|
||||
function Receptionist:needsWorkStation()
|
||||
if self.hospital and not self.hospital.receptionist_msg then
|
||||
if self.world.object_counts["reception_desk"] == 0 then
|
||||
if self.hospital:countReceptionDesks() == 0 then
|
||||
self.world.ui.adviser:say(_A.warnings.no_desk_4)
|
||||
self.hospital.receptionist_msg = true
|
||||
end
|
||||
@@ -85,9 +83,9 @@ end
|
||||
|
||||
|
||||
-- Helper function to decide if Staff fulfills a criterion
|
||||
-- (one of "Doctor", "Nurse", "Psychiatrist", "Surgeon", "Researcher" and "Handyman")
|
||||
function Receptionist:fulfillsCriterion(criterion) -- luacheck: no unused args
|
||||
return false
|
||||
-- (one of "Doctor", "Nurse", "Psychiatrist", "Surgeon", "Researcher" and "Handyman", "Receptionist", "Junior", "Consultant")
|
||||
function Receptionist:fulfillsCriterion(criterion)
|
||||
return criterion == "Receptionist"
|
||||
end
|
||||
|
||||
function Receptionist:getDrawingLayer()
|
||||
|
@@ -1,4 +1,5 @@
|
||||
--[[ Copyright (c) 2011 John Pirie
|
||||
Copyright (c) 2020 lewri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
@@ -18,7 +19,42 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. --]]
|
||||
|
||||
--[[
|
||||
---------------------------------- VIP Rating System --------------------------------
|
||||
Vip rating is calculated between 0 and 15
|
||||
If rating exceeds values, it will be capped as necessary
|
||||
1. LITTER OBJECTS
|
||||
- a. General litter and vomit 'litter' is counted
|
||||
- b. At end of visit, if number <=10 award -1
|
||||
- c. Otherwise, award +1
|
||||
2. STAFF TIREDNESS
|
||||
- a. If staff <=1, award +4 and skip other checks
|
||||
- b. If any staff member very tired (over 0.7), award 2
|
||||
- c. If average staff tiredness over tired (0.5), award 1
|
||||
- d. Else award -1
|
||||
3. PATIENTS
|
||||
- a. If average patient health >= 0.2, award -1
|
||||
- b. If average patient health < 0.2, award +1
|
||||
- c. Assess patient warmth, too hot/cold award +2, perfect -1
|
||||
- d. Average happiness, award 3 if <0.2; 2 if <0.4, 1 if <0.6, 0 if <0.8, else -1
|
||||
- e. Check if anyone has died during visit, punish based on severity
|
||||
- f. Check how many patients are cured vs. all patients, award based on %
|
||||
- g. Check seating. Award -1 for more seated than standing, else +1
|
||||
- h. Check maximum queue size. Award based on the longest queue
|
||||
4. DOCTORS
|
||||
- a. If no doctors, award +4 and skip other checks
|
||||
- b. If more than half doctors are consultants, award -2
|
||||
- c. If more than half doctors are juniors, award +2
|
||||
5. ROOMS
|
||||
- a. If there are no active rooms, award +4
|
||||
- b. If rooms not crashed (exploded) <3, award +1
|
||||
- c. Get average room evaluation score, award based on average level
|
||||
-------------------------------------------------------------------------------------
|
||||
--]]
|
||||
|
||||
--[[ initialisation --]]
|
||||
corsixth.require("announcer")
|
||||
corsixth.require("utility")
|
||||
|
||||
local AnnouncementPriority = _G["AnnouncementPriority"]
|
||||
|
||||
@@ -34,25 +70,29 @@ function Vip:Vip(...)
|
||||
self.action_string = ""
|
||||
self.name=""
|
||||
self.announced = false
|
||||
|
||||
self.vip_rating = 50
|
||||
--First we should generate an initial VIP rating
|
||||
self.vip_rating = 12 - math.random(0,5)
|
||||
|
||||
self.cash_reward = 0
|
||||
|
||||
self.rep_reward = 0
|
||||
self.vip_message = 0
|
||||
self.enter_deaths = 0
|
||||
self.enter_visitors = 0
|
||||
self.enter_explosions = 0
|
||||
-- patients in the hospital when VIP arrives
|
||||
self.enter_patients = 0
|
||||
self.enter_cures = 0
|
||||
self.num_vomit_noninducing = 0
|
||||
self.num_vomit_inducing = 0
|
||||
self.found_vomit = {}
|
||||
self.num_visited_rooms = 0
|
||||
self.room_eval = 0
|
||||
-- sets the chance VIP visits each room, default is 50% or 1/2. For every 40 rooms in a hospital over 79 we increase n by 1 and chance is 1/n+1
|
||||
self.room_visit_chance = 1
|
||||
self.waiting = 0
|
||||
|
||||
end
|
||||
|
||||
-- Check if it is cold or hot around the vip and increase/decrease the
|
||||
-- feeling of warmth accordingly. Returns whether the calling function should proceed.
|
||||
--[[--VIP while on premesis--]]
|
||||
function Vip:tickDay()
|
||||
-- for the vip
|
||||
if self.waiting then
|
||||
@@ -62,48 +102,63 @@ function Vip:tickDay()
|
||||
-- No rooms have been built yet
|
||||
self:goHome()
|
||||
end
|
||||
-- First let the previous room go.
|
||||
-- Include this when the VIP is supposed to block doors again.
|
||||
--[[if self.next_room then
|
||||
self.next_room.door.reserved_for = nil
|
||||
self.next_room:tryAdvanceQueue()
|
||||
end--]]
|
||||
-- Find out which next room to visit.
|
||||
self.next_room_no, self.next_room = next(self.world.rooms, self.next_room_no)
|
||||
-- Make sure that this room is active
|
||||
while self.next_room and not self.next_room.is_active do
|
||||
self.next_room_no, self.next_room = next(self.world.rooms, self.next_room_no)
|
||||
end
|
||||
self:setNextAction(VipGoToNextRoomAction())
|
||||
self:getNextRoom()
|
||||
self.waiting = nil
|
||||
end
|
||||
end
|
||||
if not self.going_home then
|
||||
self.world:findObjectNear(self, "litter", 8, function(x, y)
|
||||
local litter = self.world:getObject(x, y, "litter")
|
||||
if not litter then
|
||||
return
|
||||
end
|
||||
|
||||
self.world:findObjectNear(self, "litter", 8, function(x, y)
|
||||
local litter = self.world:getObject(x, y, "litter")
|
||||
if not litter then
|
||||
return
|
||||
end
|
||||
local alreadyFound = false
|
||||
for i=1, (self.num_vomit_noninducing + self.num_vomit_inducing) do
|
||||
if self.found_vomit[i] == litter then
|
||||
alreadyFound = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local alreadyFound = false
|
||||
for i=1, (self.num_vomit_noninducing + self.num_vomit_inducing) do
|
||||
if self.found_vomit[i] == litter then
|
||||
alreadyFound = true
|
||||
self.found_vomit[(self.num_vomit_noninducing + self.num_vomit_inducing + 1)] = litter
|
||||
|
||||
if not alreadyFound then
|
||||
if litter:anyLitter() then
|
||||
self.num_vomit_noninducing = self.num_vomit_noninducing + 1
|
||||
else
|
||||
self.num_vomit_inducing = self.num_vomit_inducing + 1
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
return Humanoid.tickDay(self)
|
||||
end
|
||||
|
||||
function Vip:getNextRoom()
|
||||
-- Find out the next room to visit.
|
||||
self.next_room_no, self.next_room = next(self.world.rooms, self.next_room_no)
|
||||
if self.next_room == nil then
|
||||
return self:setNextAction(VipGoToNextRoomAction())
|
||||
end
|
||||
-- Always visit the first room.
|
||||
if self.num_visited_rooms > 0 then
|
||||
local roll_to_visit = math.random(0, self.room_visit_chance)
|
||||
-- Run a loop until roll_to_visit passes, or we hit a room the VIP must visit
|
||||
while roll_to_visit ~= self.room_visit_chance and not self.next_room.room_info.vip_must_visit do
|
||||
self.next_room_no, self.next_room = next(self.world.rooms, self.next_room_no) -- get new room
|
||||
if self.next_room == nil then
|
||||
-- We ran out of rooms, time to leave
|
||||
break
|
||||
end
|
||||
roll_to_visit = math.random(0, self.room_visit_chance)
|
||||
end
|
||||
|
||||
self.found_vomit[(self.num_vomit_noninducing + self.num_vomit_inducing + 1)] = litter
|
||||
|
||||
if not alreadyFound then
|
||||
if litter:anyLitter() then
|
||||
self.num_vomit_noninducing = self.num_vomit_noninducing + 1
|
||||
else
|
||||
self.num_vomit_inducing = self.num_vomit_inducing + 1
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
return Humanoid.tickDay(self)
|
||||
end
|
||||
-- Make sure room is active. If not, always visit the next available room.
|
||||
while self.next_room and not self.next_room.is_active do
|
||||
self.next_room_no, self.next_room = next(self.world.rooms, self.next_room_no)
|
||||
end
|
||||
self:setNextAction(VipGoToNextRoomAction())
|
||||
end
|
||||
|
||||
-- display the VIP name in the info box
|
||||
@@ -111,6 +166,7 @@ function Vip:updateDynamicInfo(action_string)
|
||||
self:setDynamicInfo('text', {self.name})
|
||||
end
|
||||
|
||||
--[[--VIP is leaving--]]
|
||||
function Vip:goHome()
|
||||
if self.going_home then
|
||||
return
|
||||
@@ -126,62 +182,85 @@ function Vip:goHome()
|
||||
self:despawn()
|
||||
end
|
||||
|
||||
-- called when the vip is out of the hospital grounds
|
||||
function Vip:evaluateRoom()
|
||||
local room_extinguisher = 0
|
||||
local room_plant = 0
|
||||
local room_bin = 0
|
||||
-- Another room visited.
|
||||
self.num_visited_rooms = self.num_visited_rooms + 1
|
||||
local room = self.next_room
|
||||
-- If the player is about to kill a live patient for research, punish hard
|
||||
if room.room_info.id == "research" then
|
||||
if room:getPatient() then
|
||||
self.vip_rating = self.vip_rating + 6
|
||||
end
|
||||
end
|
||||
-- Evaluate the room we're currently looking at
|
||||
for object, _ in pairs(room.objects) do
|
||||
if object.object_type.id == "extinguisher" and room_extinguisher == 0 then
|
||||
self.room_eval = self.room_eval + 1
|
||||
-- Only count this object type once
|
||||
room_extinguisher = 1
|
||||
elseif object.object_type.id == "plant" then
|
||||
room_plant = object:isDying() and room_plant - 1 or room_plant + 1
|
||||
elseif object.object_type.id == "bin" and room_bin == 0 then
|
||||
self.room_eval = self.room_eval + 1
|
||||
-- Only count this object type once
|
||||
room_bin = 1
|
||||
end
|
||||
|
||||
if object.strength then
|
||||
self.room_eval = object:isBreaking() and self.room_eval - 1 or self.room_eval + 1
|
||||
end
|
||||
end
|
||||
-- Check whether we had more good or bad plants
|
||||
if room_plant < 0 then
|
||||
self.room_eval = self.room_eval - 1
|
||||
elseif room_plant > 0 then
|
||||
self.room_eval = self.room_eval + 1
|
||||
end
|
||||
self:getNextRoom()
|
||||
end
|
||||
|
||||
--[[--VIP has left--]]
|
||||
-- Called when the vip is out of the hospital grounds
|
||||
function Vip:onDestroy()
|
||||
local message
|
||||
-- First of all there's a special message if we're in free build mode.
|
||||
if self.world.free_build_mode then
|
||||
self.last_hospital.reputation = self.last_hospital.reputation + 20
|
||||
self.last_hospital:unconditionalChangeReputation(20)
|
||||
message = {
|
||||
{text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)},
|
||||
{text = _S.fax.vip_visit_result.remarks.free_build[math.random(1, 3)]},
|
||||
choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}}
|
||||
}
|
||||
elseif self.vip_rating == 1 then
|
||||
self.last_hospital.reputation = self.last_hospital.reputation - 10
|
||||
message = {
|
||||
{text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)},
|
||||
{text = _S.fax.vip_visit_result.remarks.very_bad[math.random(1, 3)]},
|
||||
{text = _S.fax.vip_visit_result.rep_loss},
|
||||
choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}}
|
||||
}
|
||||
elseif self.vip_rating == 2 then
|
||||
self.last_hospital.reputation = self.last_hospital.reputation - 5
|
||||
message = {
|
||||
{text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)},
|
||||
{text = _S.fax.vip_visit_result.remarks.bad[math.random(1, 3)]},
|
||||
{text = _S.fax.vip_visit_result.rep_loss},
|
||||
choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}}
|
||||
}
|
||||
elseif self.vip_rating == 3 then
|
||||
message = {
|
||||
{text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)},
|
||||
{text = _S.fax.vip_visit_result.remarks.mediocre[math.random(1, 3)]},
|
||||
choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}}
|
||||
}
|
||||
elseif self.vip_rating == 4 then
|
||||
elseif self.vip_rating <= 7 then
|
||||
self.last_hospital:receiveMoney(self.cash_reward, _S.transactions.vip_award)
|
||||
self.last_hospital.reputation = self.last_hospital.reputation + (math.round(self.cash_reward / 100))
|
||||
self.last_hospital:unconditionalChangeReputation(self.rep_reward)
|
||||
self.last_hospital.pleased_vips_ty = self.last_hospital.pleased_vips_ty + 1
|
||||
message = {
|
||||
{text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)},
|
||||
{text = _S.fax.vip_visit_result.remarks.good[math.random(1, 3)]},
|
||||
{text = _S.fax.vip_visit_result.ordered_remarks[self.vip_message]},
|
||||
{text = _S.fax.vip_visit_result.rep_boost},
|
||||
{text = _S.fax.vip_visit_result.cash_grant:format(self.cash_reward)},
|
||||
choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}}
|
||||
}
|
||||
elseif self.vip_rating >=8 and self.vip_rating < 11 then
|
||||
-- Dont tell player about any rep change in this range
|
||||
self.last_hospital:unconditionalChangeReputation(self.rep_reward)
|
||||
message = {
|
||||
{text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)},
|
||||
{text = _S.fax.vip_visit_result.ordered_remarks[self.vip_message]},
|
||||
choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}}
|
||||
}
|
||||
else
|
||||
self.last_hospital:receiveMoney(self.cash_reward, _S.transactions.vip_award)
|
||||
self.last_hospital.reputation = self.last_hospital.reputation + (math.round(self.cash_reward / 100))
|
||||
self.last_hospital.pleased_vips_ty = self.last_hospital.pleased_vips_ty + 1
|
||||
if self.vip_rating == 5 then
|
||||
message = {
|
||||
{text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)},
|
||||
{text = _S.fax.vip_visit_result.remarks.super[math.random(1, 3)]},
|
||||
{text = _S.fax.vip_visit_result.rep_boost},
|
||||
{text = _S.fax.vip_visit_result.cash_grant:format(self.cash_reward)},
|
||||
choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}}
|
||||
}
|
||||
end
|
||||
self.last_hospital:unconditionalChangeReputation(self.rep_reward)
|
||||
message = {
|
||||
{text = _S.fax.vip_visit_result.vip_remarked_name:format(self.name)},
|
||||
{text = _S.fax.vip_visit_result.ordered_remarks[self.vip_message]},
|
||||
{text = _S.fax.vip_visit_result.rep_loss},
|
||||
choices = {{text = _S.fax.vip_visit_result.close_text, choice = "close"}}
|
||||
}
|
||||
end
|
||||
self.world.ui.bottom_panel:queueMessage("report", message, nil, 24 * 20, 1)
|
||||
|
||||
@@ -202,268 +281,216 @@ function Vip:announce()
|
||||
end
|
||||
end
|
||||
|
||||
function Vip:evaluateRoom()
|
||||
-- Another room visited.
|
||||
self.num_visited_rooms = self.num_visited_rooms + 1
|
||||
local room = self.next_room
|
||||
|
||||
-- Consider doing this when reserving the door instead
|
||||
if room.door.queue then
|
||||
room.door.queue:unexpect(self)
|
||||
end
|
||||
|
||||
-- if the player is about to kill a live patient for research, lower their rating dramatically
|
||||
if room.room_info.id == "research" then
|
||||
if room:getPatient() then
|
||||
self.vip_rating = self.vip_rating - 80
|
||||
end
|
||||
end
|
||||
|
||||
if room.staff_member then
|
||||
if room.staff_member.profile.skill > 0.9 then
|
||||
self.room_eval = self.room_eval + 3
|
||||
end
|
||||
if room.staff_member.attributes["fatigue"] then
|
||||
if room.staff_member.attributes["fatigue"] < 0.4 then
|
||||
self.room_eval = self.room_eval + 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- evaluate the room we're currently looking at
|
||||
for object, _ in pairs(room.objects) do
|
||||
if object.object_type.id == "extinguisher" then
|
||||
self.room_eval = self.room_eval + 1
|
||||
break
|
||||
elseif object.object_type.id == "plant" then
|
||||
if object.days_left >= 10 then
|
||||
self.room_eval = self.room_eval + 1
|
||||
elseif object.days_left <= 3 then
|
||||
self.room_eval = self.room_eval - 1
|
||||
end
|
||||
break
|
||||
end
|
||||
|
||||
if object.strength then
|
||||
if object.strength > (object.object_type.default_strength / 2) then
|
||||
self.room_eval = self.room_eval + 1
|
||||
else
|
||||
self.room_eval = self.room_eval - 3
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Vip:evaluateEmergency(success)
|
||||
-- Make sure that the VIP is still actually in the process of evaluation
|
||||
if not self.going_home then
|
||||
if success then
|
||||
self.vip_rating = self.vip_rating + 10
|
||||
else
|
||||
self.vip_rating = self.vip_rating - 15
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Vip:setVIPRating()
|
||||
--check the visitor to patient death ratio
|
||||
local death_diff = self.hospital.num_deaths - self.enter_deaths
|
||||
local visitors_diff = self.hospital.num_visitors - self.enter_visitors
|
||||
if death_diff == 0 then
|
||||
if visitors_diff ~= 0 then --if there have been no new patients, no +/- points
|
||||
self.vip_rating = self.vip_rating + 20
|
||||
end
|
||||
else
|
||||
local death_ratio = visitors_diff / death_diff
|
||||
local death_ratio_rangemap = {
|
||||
{upper = 2, value = -20},
|
||||
{upper = 4, value = -10},
|
||||
{upper = 8, value = 0},
|
||||
{upper = 12, value = 5},
|
||||
{value = 10}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(death_ratio, death_ratio_rangemap)
|
||||
end
|
||||
|
||||
--check the visitor to patient cure ratio
|
||||
local cure_diff = self.hospital.num_cured - self.enter_cures
|
||||
if cure_diff == 0 then
|
||||
if visitors_diff ~= 0 then --if there have been no new patients, no +/- points
|
||||
self.vip_rating = self.vip_rating - 10
|
||||
end
|
||||
else
|
||||
local cure_ratio = visitors_diff / cure_diff
|
||||
local cure_ratio_rangemap = {
|
||||
{upper = 3, value = 20},
|
||||
{upper = 6, value = 10},
|
||||
{upper = 10, value = 0},
|
||||
{upper = 12, value = -5},
|
||||
{value = -10}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(cure_ratio, cure_ratio_rangemap)
|
||||
end
|
||||
|
||||
-- check for the average queue length
|
||||
local sum_queue = 0
|
||||
local room_count = 0
|
||||
-- First do room code for later
|
||||
local count_rooms = 0
|
||||
local max_queue = 0
|
||||
for _, room in pairs(self.world.rooms) do
|
||||
if room.door.queue then
|
||||
sum_queue = sum_queue + room.door.queue:size()
|
||||
end
|
||||
if not room.crashed then
|
||||
room_count = room_count + 1
|
||||
count_rooms = count_rooms + 1
|
||||
end
|
||||
if room.door.queue then
|
||||
max_queue = max_queue < room.door.queue:size() and room.door.queue:size() or max_queue
|
||||
end
|
||||
end
|
||||
|
||||
if room_count == 0 then
|
||||
self.vip_rating = self.vip_rating - 100
|
||||
elseif sum_queue == 0 then
|
||||
self.vip_rating = self.vip_rating + 6
|
||||
--[[-- Group factor 1: Litter--]]
|
||||
if (self.num_vomit_noninducing + self.num_vomit_inducing) <= 10 then
|
||||
self.vip_rating = self.vip_rating - 1
|
||||
else
|
||||
local queue_ratio = sum_queue / room_count
|
||||
local queue_ratio_rangemap = {
|
||||
{upper = 2, value = 6},
|
||||
{upper = 5, value = 3},
|
||||
{upper = 9, value = 0},
|
||||
{upper = 11, value = -3},
|
||||
{value = -6}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(queue_ratio, queue_ratio_rangemap)
|
||||
self.vip_rating = self.vip_rating + 1
|
||||
end
|
||||
|
||||
-- now we check for toilet presence
|
||||
local sum_toilets = 0
|
||||
for _, room in pairs(self.world.rooms) do
|
||||
if room.room_info.id == "toilets" then
|
||||
for object, _ in pairs(room.objects) do
|
||||
if object.object_type.id == "loo" then
|
||||
sum_toilets = sum_toilets + 1
|
||||
end
|
||||
--[[-- Group factor 2: Staff tiredness--]]
|
||||
-- First get staff members
|
||||
local count_staff = #self.hospital.staff
|
||||
if count_staff > 1 then
|
||||
-- Loop through staff tiredness, if any above verytired, break loop
|
||||
for _, staff in ipairs(self.hospital.staff) do
|
||||
if staff.attributes["fatigue"] ~= nil and staff.attributes["fatigue"] >= 0.7 then
|
||||
self.vip_rating = self.vip_rating + 2
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if sum_toilets == 0 then
|
||||
self.vip_rating = self.vip_rating - 6
|
||||
-- Average all staff tiredness
|
||||
local avg_tired = self.hospital:getAverageStaffAttribute("fatigue", 1)
|
||||
if avg_tired >= 0.5 then
|
||||
self.vip_rating = self.vip_rating + 1
|
||||
else
|
||||
self.vip_rating = self.vip_rating - 1
|
||||
end
|
||||
else
|
||||
local patients_per_toilet = #self.hospital.patients / sum_toilets
|
||||
local toilet_ratio_rangemap = {
|
||||
{upper = 10, value = 6},
|
||||
{upper = 20, value = 3},
|
||||
{upper = 40, value = 0},
|
||||
{value = -3}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(patients_per_toilet, toilet_ratio_rangemap)
|
||||
-- Penalise where there is one or no staff
|
||||
self.vip_rating = self.vip_rating + 4
|
||||
end
|
||||
|
||||
-- check the levels of non-vomit inducing litter in the hospital
|
||||
local litter_ratio_rangemap = {
|
||||
{upper = 3, value = 4},
|
||||
{upper = 5, value = 2},
|
||||
{upper = 7, value = 0},
|
||||
{upper = 8, value = -2},
|
||||
{value = -4}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(self.num_vomit_noninducing, litter_ratio_rangemap)
|
||||
--[[-- Group factor 3: Patients--]]
|
||||
-- First check we had patients this visit
|
||||
local patients_this_visit = self.enter_patients + self.hospital.num_visitors - self.enter_visitors
|
||||
if patients_this_visit > 0 then
|
||||
-- Average all patient health
|
||||
local avg_health = self.hospital:getAveragePatientAttribute("health", 0.19)
|
||||
if avg_health >= 0.2 then
|
||||
self.vip_rating = self.vip_rating - 1
|
||||
else
|
||||
self.vip_rating = self.vip_rating + 1
|
||||
end
|
||||
|
||||
-- check the levels of vomit inducing litter in the hospital
|
||||
local inducing_ratio_rangemap = {
|
||||
{upper = 3, value = 8},
|
||||
{upper = 5, value = 4},
|
||||
{upper = 6, value = 0},
|
||||
{upper = 7, value = -6},
|
||||
{upper = 10, value = -12},
|
||||
{upper = 12, value = -16},
|
||||
{value = -20}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(self.num_vomit_inducing, inducing_ratio_rangemap)
|
||||
-- Get patient warmth
|
||||
local avg_warmth = self.hospital:getAveragePatientAttribute("warmth", nil)
|
||||
-- Punish if too cold/hot
|
||||
if avg_warmth then
|
||||
local patients_warmth_ratio_rangemap = {
|
||||
{upper = 0.22, value = 2},
|
||||
{upper = 0.36, value = -1},
|
||||
{value = 2}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(avg_warmth, patients_warmth_ratio_rangemap)
|
||||
end
|
||||
|
||||
-- if there were explosions, hit the user hard
|
||||
if self.hospital.num_explosions ~= self.enter_explosions then
|
||||
self.vip_rating = self.vip_rating - 70
|
||||
-- Check average patient happiness
|
||||
local avg_happiness = self.hospital:getAveragePatientAttribute("happiness", nil)
|
||||
if avg_happiness then
|
||||
local patients_happy_ratio_rangemap = {
|
||||
{upper = 0.20, value = 3},
|
||||
{upper = 0.40, value = 2},
|
||||
{upper = 0.60, value = 1},
|
||||
{upper = 0.80, value = 0},
|
||||
{value = -1}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(avg_happiness, patients_happy_ratio_rangemap)
|
||||
end
|
||||
|
||||
-- Check the visitor to patient death ratio
|
||||
local death_diff = self.hospital.num_deaths - self.enter_deaths
|
||||
if death_diff ~= 0 then -- no deaths are good, but also expected
|
||||
local death_ratio = patients_this_visit / death_diff
|
||||
local death_ratio_rangemap = {
|
||||
{upper = 2, value = 4},
|
||||
{upper = 4, value = 3},
|
||||
{upper = 8, value = 2},
|
||||
{upper = 12, value = 1},
|
||||
{value = 0}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(death_ratio, death_ratio_rangemap)
|
||||
end
|
||||
|
||||
-- Check the visitor to patient cure ratio
|
||||
local cure_diff = self.hospital.num_cured - self.enter_cures
|
||||
if cure_diff ~= 0 then -- no cures are bad
|
||||
local cure_ratio = patients_this_visit / cure_diff
|
||||
local cure_ratio_rangemap = {
|
||||
{upper = 2, value = -1},
|
||||
{upper = 3, value = 0},
|
||||
{upper = 4, value = 1},
|
||||
{upper = 5, value = 2},
|
||||
{value = 3}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(cure_ratio, cure_ratio_rangemap)
|
||||
else
|
||||
self.vip_rating = self.vip_rating + 3
|
||||
end
|
||||
|
||||
-- Check the seating : standing ratio of waiting patients
|
||||
local sum_sitting, sum_standing = self.hospital:countSittingStanding()
|
||||
if (sum_sitting + sum_standing) ~= 0 then
|
||||
if sum_sitting >= sum_standing or sum_standing == 0 then
|
||||
self.vip_rating = self.vip_rating - 1
|
||||
else
|
||||
self.vip_rating = self.vip_rating + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Check the maximum queue length
|
||||
if max_queue == 0 then
|
||||
self.vip_rating = self.vip_rating - 1
|
||||
else
|
||||
local queue_ratio_rangemap = {
|
||||
{upper = 3, value = -1},
|
||||
{upper = 6, value = 0},
|
||||
{upper = 9, value = 1},
|
||||
{value = 2}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(max_queue, queue_ratio_rangemap)
|
||||
end
|
||||
end
|
||||
|
||||
-- check the vip heat level
|
||||
local heat_ratio_rangemap = {
|
||||
{upper = 0.20, value = -5},
|
||||
{upper = 0.40, value = -3},
|
||||
{upper = 0.60, value = 0},
|
||||
{upper = 0.80, value = 3},
|
||||
{value = 5}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(self.attributes["warmth"], heat_ratio_rangemap)
|
||||
|
||||
-- check the seating : standing ratio of waiting patients
|
||||
-- find all the patients who are currently waiting around
|
||||
local sum_sitting, sum_standing = self.hospital:countSittingStanding()
|
||||
if sum_sitting >= sum_standing then
|
||||
--[[--Group factor 4: Doctor ratios--]]
|
||||
-- First get all doctors
|
||||
local num_docs = self.hospital:countStaffOfCategory("Doctor")
|
||||
-- No doctors are bad
|
||||
if num_docs == 0 then
|
||||
self.vip_rating = self.vip_rating + 4
|
||||
else
|
||||
self.vip_rating = self.vip_rating - 4
|
||||
-- Count num. consultants, num. juniors
|
||||
local num_cons = self.hospital:countStaffOfCategory("Consultant")
|
||||
local num_junior = self.hospital:countStaffOfCategory("Junior")
|
||||
|
||||
-- Check consultant and junior proportions
|
||||
if num_cons / num_docs > 0.5 then
|
||||
self.vip_rating = self.vip_rating - 1
|
||||
elseif num_junior / num_docs > 0.5 then
|
||||
self.vip_rating = self.vip_rating + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- check average patient thirst
|
||||
local avg_thirst = self.hospital:getAveragePatientAttribute("thirst", nil)
|
||||
if avg_thirst then
|
||||
local thirst_ratio_rangemap = {
|
||||
{upper = 0.20, value = -5},
|
||||
{upper = 0.40, value = -1},
|
||||
{upper = 0.60, value = 0},
|
||||
{upper = 0.80, value = 1},
|
||||
{value = 3}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(avg_thirst, thirst_ratio_rangemap)
|
||||
end
|
||||
|
||||
if self.num_visited_rooms ~= 0 then
|
||||
self.vip_rating = self.vip_rating + self.room_eval / self.num_visited_rooms
|
||||
end
|
||||
|
||||
-- check average patient happiness
|
||||
local avg_happiness = self.hospital:getAveragePatientAttribute("happiness", nil)
|
||||
if avg_happiness then
|
||||
local patients_happy_ratio_rangemap = {
|
||||
{upper = 0.20, value = -10},
|
||||
{upper = 0.40, value = -5},
|
||||
{upper = 0.60, value = 0},
|
||||
{upper = 0.80, value = 5},
|
||||
{value = 10}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(avg_happiness, patients_happy_ratio_rangemap)
|
||||
end
|
||||
|
||||
-- check average staff happiness
|
||||
avg_happiness = self.hospital:getAverageStaffAttribute("happiness", nil)
|
||||
if avg_happiness then
|
||||
local staff_happy_ratio_rangemap = {
|
||||
{upper = 0.20, value = -10},
|
||||
{upper = 0.40, value = -5},
|
||||
{upper = 0.60, value = 0},
|
||||
{upper = 0.80, value = 5},
|
||||
{value = 10}
|
||||
}
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(avg_happiness, staff_happy_ratio_rangemap)
|
||||
end
|
||||
|
||||
-- set the cash reward value
|
||||
if tonumber(self.world.map.level_number) then
|
||||
self.cash_reward = math.round(self.world.map.level_number * self.vip_rating) * 10
|
||||
--[[--Group factor 5: Rooms--]]
|
||||
-- Low room numbers incur a penalty
|
||||
if count_rooms < 1 then
|
||||
self.vip_rating = self.vip_rating + 4
|
||||
else
|
||||
-- custom level, it has no level number. Default back to one.
|
||||
self.cash_reward = math.round(1 * self.vip_rating) * 10
|
||||
end
|
||||
if self.cash_reward > 2000 then
|
||||
self.cash_reward = 2000
|
||||
if count_rooms < 3 then
|
||||
self.vip_rating = self.vip_rating + 1
|
||||
end
|
||||
-- Room decor average
|
||||
local avg_room_eval = self.room_eval / self.num_visited_rooms
|
||||
local room_eval_rangemap = {
|
||||
{upper = 1.5, value = 3},
|
||||
{upper = 2, value = 1},
|
||||
{upper = 3, value = 0},
|
||||
{value = -1}
|
||||
}
|
||||
if self.num_visited_rooms ~= 0 then
|
||||
self.vip_rating = self.vip_rating + rangeMapLookup(avg_room_eval, room_eval_rangemap)
|
||||
end
|
||||
end
|
||||
|
||||
-- give the rating between 1 and 5
|
||||
local rating_ratio_rangemap = {
|
||||
{upper = 25, value = 1},
|
||||
{upper = 45, value = 2},
|
||||
{upper = 65, value = 3},
|
||||
{upper = 85, value = 4},
|
||||
{value = 5}
|
||||
--[[--Finalise score--]]
|
||||
-- Documented rewards
|
||||
local rewards = {
|
||||
[1] = 4000,
|
||||
[2] = 2000,
|
||||
[3] = 1500,
|
||||
[4] = 1200,
|
||||
[5] = 800,
|
||||
[6] = 400,
|
||||
[7] = 200,
|
||||
[8] = 0,
|
||||
}
|
||||
self.vip_rating = rangeMapLookup(self.vip_rating, rating_ratio_rangemap)
|
||||
-- Documented reps
|
||||
local rep_change = {
|
||||
[1] = 50,
|
||||
[2] = 45,
|
||||
[3] = 40,
|
||||
[4] = 35,
|
||||
[5] = 30,
|
||||
[6] = 25,
|
||||
[7] = 20,
|
||||
[8] = 15,
|
||||
[9] = 10,
|
||||
[10] = 5,
|
||||
[11] = -5,
|
||||
[12] = -10,
|
||||
[13] = -15,
|
||||
[14] = -20,
|
||||
[15] = -25,
|
||||
}
|
||||
-- Set rewards
|
||||
self.vip_rating = self.vip_rating > 15 and 15 or self.vip_rating
|
||||
self.vip_rating = self.vip_rating < 1 and 1 or self.vip_rating
|
||||
self.cash_reward = rewards[self.vip_rating] or 0
|
||||
self.rep_reward = rep_change[self.vip_rating]
|
||||
self.vip_message = self.vip_rating
|
||||
self.hospital.num_vips_ty = self.hospital.num_vips_ty + 1
|
||||
end
|
||||
|
||||
@@ -482,7 +509,42 @@ function Vip:afterLoad(old, new)
|
||||
if old < 79 then
|
||||
self.name = self.hospital.visitingVIP
|
||||
end
|
||||
if old < 144 then
|
||||
self.vip_rating = 12 - math.random(0,5)
|
||||
-- Make sure we only rate rooms from now on if a VIP was visiting
|
||||
self.room_eval = 0
|
||||
self.num_visited_rooms = 0
|
||||
-- VIP's room visit chance is 50% if total rooms in hospital is less than 80 (makes a math.random with 0 and 1 possibilities).
|
||||
-- Else decided by total rooms / 40 (0, 1, 2 [33%]; 0, 1, 2, 3 [25%] etc)
|
||||
local rooms_threshold = 79
|
||||
if #self.world.rooms > rooms_threshold then
|
||||
self.room_visit_chance = math.floor(#self.world.rooms / 40)
|
||||
else
|
||||
self.room_visit_chance = 1
|
||||
end
|
||||
-- If our hospital has more patients than counted visitors adjust enter_patients
|
||||
self.enter_patients = #self.hospital.patients + self.enter_visitors - self.hospital.num_visitors
|
||||
if self.enter_patients < 0 then
|
||||
self.enter_patients = 0
|
||||
end
|
||||
if self.going_home then
|
||||
--award max from old code if VIP leaving
|
||||
self.vip_rating = 2
|
||||
self.cash_reward = 2000
|
||||
self.rep_reward = 45
|
||||
self.vip_message = 2
|
||||
end
|
||||
for i, action in ipairs(self.action_queue) do
|
||||
if action.name == 'idle' and action.loop_callback and (self.waiting > 1 or i > 1) then
|
||||
action:setCount(50):setAfterUse(action.loop_callback)
|
||||
action.loop_callback = nil
|
||||
self.waiting = nil
|
||||
if i == 1 then
|
||||
self:queueAction(action, 1)
|
||||
self:finishAction()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Humanoid.afterLoad(self, old, new)
|
||||
end
|
||||
|
||||
|
||||
|
@@ -20,19 +20,23 @@ SOFTWARE. --]]
|
||||
|
||||
local TH = require("TH")
|
||||
|
||||
corsixth.require("announcer")
|
||||
|
||||
local AnnouncementPriority = _G["AnnouncementPriority"]
|
||||
|
||||
--! An `Object` which needs occasional repair (to prevent explosion).
|
||||
class "Machine" (Object)
|
||||
|
||||
---@type Machine
|
||||
local Machine = _G["Machine"]
|
||||
|
||||
function Machine:Machine(world, object_type, x, y, direction, etc)
|
||||
function Machine:Machine(hospital, object_type, x, y, direction, etc)
|
||||
self.total_usage = -1 -- Incremented in the constructor of Object.
|
||||
self:Object(world, object_type, x, y, direction, etc)
|
||||
self:Object(hospital, object_type, x, y, direction, etc)
|
||||
|
||||
if object_type.default_strength then
|
||||
-- Only for the main object. The slave doesn't need any strength
|
||||
local progress = world.ui.hospital.research.research_progress[object_type]
|
||||
local progress = self.world.ui.hospital.research.research_progress[object_type]
|
||||
self.strength = progress.start_strength
|
||||
end
|
||||
|
||||
@@ -60,6 +64,24 @@ function Machine:getRemainingUses()
|
||||
return self.strength - self.times_used
|
||||
end
|
||||
|
||||
--! Returns true if a machine is smoking/needs repair
|
||||
function Machine:isBreaking()
|
||||
local threshold = self:getRemainingUses()
|
||||
return threshold < 4
|
||||
end
|
||||
|
||||
--! Announces a machine needing repair
|
||||
--!param room The room of the machine
|
||||
function Machine:announceRepair(room)
|
||||
local sound = room.room_info.handyman_call_sound
|
||||
local earthquake = self.world.next_earthquake
|
||||
self.world.ui:playAnnouncement("machwarn.wav", AnnouncementPriority.Critical)
|
||||
-- If an earthquake is happening don't play the call sound to prevent spamming
|
||||
if earthquake.active and earthquake.warning_timer == 0 then return end
|
||||
-- TODO: Don't announce handyman call sound if there are no handymen
|
||||
if sound then self.world.ui:playAnnouncement(sound, AnnouncementPriority.Critical) end
|
||||
end
|
||||
|
||||
--! Set whether the smoke animation should be showing
|
||||
local function setSmoke(self, isSmoking)
|
||||
-- If turning smoke on for this machine
|
||||
@@ -99,9 +121,31 @@ function Machine:machineUsed(room)
|
||||
local threshold = self:getRemainingUses()
|
||||
-- Find a queued task for a handyman coming to repair this machine
|
||||
local taskIndex = self.hospital:getIndexOfTask(self.tile_x, self.tile_y, "repairing")
|
||||
|
||||
-- Too late it is about to explode
|
||||
local num_extinguishers = 0
|
||||
local explosion_chance
|
||||
local explode = false
|
||||
-- Room is set to explode
|
||||
if threshold < 1 then
|
||||
-- If a fire extinguisher in the room, room has chance not to explode
|
||||
for object, _ in pairs(room.objects) do
|
||||
if object.object_type.id == "extinguisher" and num_extinguishers < 4 then
|
||||
num_extinguishers = num_extinguishers + 1
|
||||
end
|
||||
end
|
||||
if num_extinguishers == 0 or threshold < -3 then
|
||||
-- If no extinguisher in room, or machine used 5 times over its strength always explode
|
||||
explode = true
|
||||
else
|
||||
-- Explosion chance increases 20% with every use over strength, and reduced by 5% for every additional extinguisher (up to 3 extra) in the room bar the first one
|
||||
explosion_chance = (2 / self.strength) + (threshold * -0.2) - (num_extinguishers * 0.05) + 0.05
|
||||
-- Cap it until guaranteed explosion
|
||||
explosion_chance = explosion_chance > 0.95 and 0.95 or explosion_chance
|
||||
explosion_chance = explosion_chance < 0.05 and 0.05 or explosion_chance
|
||||
explode = math.random() < explosion_chance
|
||||
end
|
||||
end
|
||||
-- Room failed to be saved, or no extinguishers were present
|
||||
if explode then
|
||||
-- Clean up any task of handyman coming to repair the machine
|
||||
self.hospital:removeHandymanTask(taskIndex, "repairing")
|
||||
-- Blow up the room
|
||||
@@ -121,14 +165,19 @@ function Machine:machineUsed(room)
|
||||
-- Clear the icon showing a handyman is coming to repair the machine
|
||||
self:setRepairing(nil)
|
||||
return true
|
||||
-- Else if urgent repair needed
|
||||
-- Else if urgent repair needed or room didn't explode
|
||||
elseif threshold < 4 then
|
||||
-- If the job of repairing the machine isn't queued, queue it now (higher priority)
|
||||
if taskIndex == -1 then
|
||||
local call = self.world.dispatcher:callForRepair(self, true, false, true)
|
||||
self.hospital:addHandymanTask(self, "repairing", 2, self.tile_x, self.tile_y, call)
|
||||
self:announceRepair(room)
|
||||
else -- Otherwise the task is already queued. Increase the priority to above that of machines with at least 4 uses left
|
||||
self.hospital:modifyHandymanTaskPriority(taskIndex, 2, "repairing")
|
||||
-- Upgrades task from low (1) priority to high (2) priority
|
||||
if self.hospital:getHandymanTaskPriority(taskIndex, "repairing") == 1 then
|
||||
self.hospital:modifyHandymanTaskPriority(taskIndex, 2, "repairing")
|
||||
self:announceRepair(room)
|
||||
end
|
||||
end
|
||||
-- Else if repair is needed, but not urgently
|
||||
elseif threshold < 6 then
|
||||
@@ -153,11 +202,8 @@ function Machine:calculateSmoke(room)
|
||||
-- How many uses this machine has left until it explodes
|
||||
local threshold = self:getRemainingUses()
|
||||
|
||||
-- If now exploding, clear any smoke
|
||||
if threshold < 1 then
|
||||
setSmoke(self, false)
|
||||
-- Else if urgent repair needed
|
||||
elseif threshold < 4 then
|
||||
-- Machines needing urgent repair show smoke
|
||||
if threshold < 4 then
|
||||
-- Display smoke, up to three animations per machine
|
||||
-- i.e. < 4 one plume, < 3 two plumes or < 2 three plumes of smoke
|
||||
setSmoke(self, true)
|
||||
|
@@ -37,7 +37,9 @@ function Object:getDrawingLayer()
|
||||
return 4
|
||||
end
|
||||
|
||||
function Object:Object(world, object_type, x, y, direction, etc)
|
||||
function Object:Object(hospital, object_type, x, y, direction, etc)
|
||||
assert(class.is(hospital, Hospital), "First argument is not a Hospital instance.")
|
||||
|
||||
local th = TH.animation()
|
||||
self:Entity(th)
|
||||
|
||||
@@ -51,8 +53,8 @@ function Object:Object(world, object_type, x, y, direction, etc)
|
||||
|
||||
self.ticks = object_type.ticks
|
||||
self.object_type = object_type
|
||||
self.world = world
|
||||
self.hospital = world:getLocalPlayerHospital()
|
||||
self.hospital = hospital
|
||||
self.world = hospital.world
|
||||
self.user = false
|
||||
self.times_used = -1 -- Incremented in the call on the next line
|
||||
self:updateDynamicInfo()
|
||||
@@ -118,8 +120,8 @@ function Object.slaveMixinClass(class_method_table)
|
||||
local super_constructor = super[class.name(super)]
|
||||
|
||||
-- Constructor
|
||||
class_method_table[name] = function(self, world, object_type, x, y, direction, ...)
|
||||
super_constructor(self, world, object_type, x, y, direction, ...)
|
||||
class_method_table[name] = function(self, hospital, object_type, x, y, direction, ...)
|
||||
super_constructor(self, hospital, object_type, x, y, direction, ...)
|
||||
if object_type.slave_id then
|
||||
local orientation = object_type.orientations
|
||||
orientation = orientation and orientation[direction]
|
||||
@@ -127,7 +129,7 @@ function Object.slaveMixinClass(class_method_table)
|
||||
x = x + orientation.slave_position[1]
|
||||
y = y + orientation.slave_position[2]
|
||||
end
|
||||
self.slave = world:newObject(object_type.slave_id, x, y, direction, ...)
|
||||
self.slave = hospital.world:newObject(object_type.slave_id, x, y, direction, ...)
|
||||
self.slave.master = self
|
||||
end
|
||||
end
|
||||
|
@@ -74,21 +74,27 @@ function FileSystem:_enumerate()
|
||||
end
|
||||
end
|
||||
|
||||
--! Test if file name has an .iso or .dmg extension
|
||||
function FileSystem:isIso(name)
|
||||
if name == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
local ext = name:lower():match("%.(.+)$")
|
||||
return ext == 'iso' or ext == 'iso9660$' or ext == 'dmg'
|
||||
end
|
||||
|
||||
--! Set the root physical path for this FileSystem.
|
||||
-- If the path is an ISO then set the provider. If the path is a directory
|
||||
-- then set the pysical_path and populate the files and sub_dirs.
|
||||
-- then set the physical_path and populate the files and sub_dirs.
|
||||
--
|
||||
--!param physical_path (string) a path on the filesystem to either a directory
|
||||
-- or theme hospital ISO file.
|
||||
function FileSystem:setRoot(physical_path)
|
||||
if physical_path:match"%.[iI][sS][oO]$" or physical_path:match"%.[iI][sS][oO]9660$" then
|
||||
if self:isIso(physical_path) then
|
||||
self.provider = ISO_FS()
|
||||
self.provider:setPathSeparator(pathsep)
|
||||
local file, err = io.open(physical_path, "rb")
|
||||
if not file then
|
||||
return nil, err
|
||||
end
|
||||
return self.provider:setRoot(file)
|
||||
return self.provider:setRoot(physical_path)
|
||||
end
|
||||
|
||||
if physical_path:sub(-1) == pathsep then
|
||||
|
@@ -107,7 +107,7 @@ function GameUI:setupGlobalKeyHandlers()
|
||||
[tostring(self.app.hotkeys["ingame_scroll_up"])] = {x = 0, y = -10},
|
||||
[tostring(self.app.hotkeys["ingame_scroll_down"])] = {x = 0, y = 10},
|
||||
[tostring(self.app.hotkeys["ingame_scroll_left"])] = {x = -10, y = 0},
|
||||
[tostring(self.app.hotkeys["ingame_scroll_right"])] = {x = 10, y = 0},
|
||||
[tostring(self.app.hotkeys["ingame_scroll_right"])] = {x = 10, y = 0},
|
||||
}
|
||||
|
||||
-- This is the long version of the shift speed key.
|
||||
@@ -608,7 +608,8 @@ function GameUI:onMouseMove(x, y, dx, dy)
|
||||
--map.th:setCell(highlight_x, highlight_y, 4, 0)
|
||||
highlight_x = nil
|
||||
end
|
||||
if 1 <= wx and wx <= 128 and 1 <= wy and wy <= 128 then
|
||||
local map_width, map_height = map.th:size()
|
||||
if 1 <= wx and wx <= map_width and 1 <= wy and wy <= map_height then
|
||||
if map.th:getCellFlags(wx, wy).passable then
|
||||
--map.th:setCell(wx, wy, 4, 24 + 8 * 256)
|
||||
highlight_x = wx
|
||||
@@ -643,10 +644,27 @@ function GameUI:onMouseUp(code, x, y)
|
||||
else -- No room chosen yet, but about to edit one.
|
||||
if button == "left" then -- Take the clicked one.
|
||||
local room = self.app.world:getRoom(self:ScreenToWorld(x, y))
|
||||
if room and not room.crashed then
|
||||
self:setCursor(self.waiting_cursor)
|
||||
self.edit_room = room
|
||||
room:tryToEdit()
|
||||
if room then
|
||||
if not room.crashed then
|
||||
self:setCursor(self.waiting_cursor)
|
||||
self.edit_room = room
|
||||
room:tryToEdit()
|
||||
else
|
||||
if self.app.config.remove_destroyed_rooms then
|
||||
local room_cost = room:calculateRemovalCost()
|
||||
self:setEditRoom(false)
|
||||
-- show confirmation dialog for removing the room
|
||||
self:addWindow(UIConfirmDialog(self,_S.confirmation.remove_destroyed_room:format(room_cost),
|
||||
--[[persistable:remove_destroyed_room_confirm_dialog]]function()
|
||||
local world = room.world
|
||||
UIEditRoom:removeRoom(false, room, world)
|
||||
world:resetSideObjects()
|
||||
world.rooms[room.id] = nil
|
||||
self.hospital:spendMoney(room_cost, _S.transactions.remove_room)
|
||||
end
|
||||
))
|
||||
end
|
||||
end
|
||||
end
|
||||
else -- right click, we don't want to edit a room after all.
|
||||
self:setEditRoom(false)
|
||||
@@ -1158,7 +1176,7 @@ function GameUI:setEditRoom(enabled)
|
||||
-- If the actual editing hasn't started yet but is on its way,
|
||||
-- activate the room again.
|
||||
if class.is(self.edit_room, Room) and self.cursor == self.waiting_cursor then
|
||||
self.edit_room.is_active = true
|
||||
self.app.world:markRoomAsBuilt(self.edit_room)
|
||||
else
|
||||
-- If we are currently editing a room it may happen that we need to abort it.
|
||||
-- Also remove any dialog where the user is buying items.
|
||||
|
@@ -127,6 +127,8 @@ function Graphics:loadFontFile()
|
||||
local windir = os.getenv("WINDIR")
|
||||
if windir and windir ~= "" then
|
||||
font_file = windir .. pathsep .. "Fonts" .. pathsep .. "ARIALUNI.TTF"
|
||||
elseif self.app.os == "macos" then
|
||||
font_file = "/Library/Fonts/Arial Unicode.ttf"
|
||||
else
|
||||
font_file = "/usr/share/fonts/truetype/arphic/uming.ttc"
|
||||
end
|
||||
@@ -393,6 +395,8 @@ end
|
||||
function Graphics:loadFont(sprite_table, x_sep, y_sep, ...)
|
||||
-- Allow (multiple) arguments for loading a sprite table in place of the
|
||||
-- sprite_table argument.
|
||||
-- TODO: Native number support for e.g. Korean languages. Current use of load_font is a stopgap solution for #1193 and should be eventually removed
|
||||
local load_font = x_sep
|
||||
if type(sprite_table) == "string" then
|
||||
local arg = {sprite_table, x_sep, y_sep, ...}
|
||||
local n_pass_on_args = #arg
|
||||
@@ -411,7 +415,8 @@ function Graphics:loadFont(sprite_table, x_sep, y_sep, ...)
|
||||
end
|
||||
|
||||
local use_bitmap_font = true
|
||||
if not sprite_table:isVisible(46) then -- uppercase M
|
||||
-- Force bitmap font for the moneybar (Font05V)
|
||||
if not sprite_table:isVisible(46) or load_font == "Font05V" then -- uppercase M
|
||||
-- The font doesn't contain an uppercase M, so (in all likelihood) is used
|
||||
-- for drawing special symbols rather than text, so the original bitmap
|
||||
-- font should be used.
|
||||
|
File diff suppressed because it is too large
Load Diff
55
CorsixTH/Lua/hospitals/ai_hospital.lua
Normal file
55
CorsixTH/Lua/hospitals/ai_hospital.lua
Normal file
@@ -0,0 +1,55 @@
|
||||
--[[ Copyright (c) 2020 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. --]]
|
||||
|
||||
class "AIHospital" (Hospital)
|
||||
|
||||
---@type AIHospital
|
||||
local AIHospital = _G["AIHospital"]
|
||||
|
||||
function AIHospital:AIHospital(competitor, world, avail_rooms, name)
|
||||
self:Hospital(world, avail_rooms, name)
|
||||
if name then
|
||||
self.name = name
|
||||
elseif _S.competitor_names[competitor] then
|
||||
self.name = _S.competitor_names[competitor]
|
||||
else
|
||||
self.name = "NONAME"
|
||||
end
|
||||
self.is_in_world = false
|
||||
|
||||
-- AI Hospitals can't cheat, so don't let them
|
||||
self.hosp_cheats = nil
|
||||
end
|
||||
|
||||
function AIHospital:spawnPatient()
|
||||
-- TODO: Simulate patient
|
||||
end
|
||||
|
||||
function AIHospital:logTransaction()
|
||||
-- AI doesn't need a log of transactions, as it is only used for UI purposes
|
||||
end
|
||||
|
||||
function AIHospital:afterLoad(old, new)
|
||||
if old < 145 then
|
||||
self.hosp_cheats = nil
|
||||
end
|
||||
|
||||
Hospital.afterLoad(self, old, new)
|
||||
end
|
425
CorsixTH/Lua/hospitals/player_hospital.lua
Normal file
425
CorsixTH/Lua/hospitals/player_hospital.lua
Normal file
@@ -0,0 +1,425 @@
|
||||
--[[ Copyright (c) 2020 Albert "Alberth" Hofkamp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. --]]
|
||||
|
||||
class "PlayerHospital" (Hospital)
|
||||
|
||||
---@type PlayerHospital
|
||||
local PlayerHospital = _G["PlayerHospital"]
|
||||
|
||||
local num_sitting_ratios = 15 -- Number of stored recent sitting ratio measurements.
|
||||
local ratio_interval = 2 -- Measurement interval in days.
|
||||
|
||||
function PlayerHospital:PlayerHospital(world, avail_rooms, name)
|
||||
self:Hospital(world, avail_rooms, name)
|
||||
-- The player hospital in single player can access the Cheat System should they wish to.
|
||||
self.hosp_cheats = Cheats(self)
|
||||
|
||||
self.adviser_data = { -- Variables handling player advice.
|
||||
temperature_advice = nil, -- Whether the player received advice about room temp.
|
||||
reception_advice = nil, -- Whether advice was given about building the reception.
|
||||
cured_died_message = nil, -- Whether the adviser reported about a cure or death.
|
||||
|
||||
sitting_ratios = {}, -- Measurements of recent sitting/standing ratios.
|
||||
sitting_index = 1 -- Next entry in 'sitting_ratios' to update.
|
||||
}
|
||||
|
||||
self.win_declined = false -- Has not yet declined the level win fax
|
||||
end
|
||||
|
||||
--! Give advice to the player at the end of a day.
|
||||
function PlayerHospital:dailyAdviceChecks()
|
||||
local current_date = self.world:date()
|
||||
local day = current_date:dayOfMonth()
|
||||
|
||||
-- Hold any advice back until the game has somewhat started.
|
||||
if current_date < Date(1, 5) then
|
||||
return
|
||||
end
|
||||
|
||||
-- Warn about lack of a staff room.
|
||||
if day == 3 and self:countRoomOfType("staff_room", 1) == 0 then
|
||||
local staffroom_advice = {
|
||||
_A.warnings.build_staffroom, _A.warnings.need_staffroom,
|
||||
_A.warnings.staff_overworked, _A.warnings.staff_tired,
|
||||
}
|
||||
self:giveAdvice(staffroom_advice)
|
||||
end
|
||||
|
||||
-- Warn about lack of toilets.
|
||||
if day == 8 and self:countRoomOfType("toilets", 1) == 0 then
|
||||
local toilet_advice = {
|
||||
_A.warnings.need_toilets, _A.warnings.build_toilets,
|
||||
_A.warnings.build_toilet_now,
|
||||
}
|
||||
self:giveAdvice(toilet_advice)
|
||||
end
|
||||
|
||||
-- Make players more aware of the need for radiators
|
||||
if self:countRadiators() == 0 then
|
||||
self:giveAdvice({_A.information.initial_general_advice.place_radiators})
|
||||
end
|
||||
|
||||
-- Verify patients well-being with respect to room temperature.
|
||||
if day == 15 and not self.adviser_data.temperature_advice
|
||||
and not self.heating.heating_broke then
|
||||
-- Check patients warmth, default value does not result in a message.
|
||||
local warmth = self:getAveragePatientAttribute("warmth", 0.3)
|
||||
if warmth < 0.22 then
|
||||
local cold_advice = {
|
||||
_A.information.initial_general_advice.increase_heating,
|
||||
_A.warnings.patients_very_cold, _A.warnings.people_freezing,
|
||||
}
|
||||
self:giveAdvice(cold_advice)
|
||||
self.adviser_data.temperature_advice = true
|
||||
|
||||
elseif warmth >= 0.36 then
|
||||
local hot_advice = {
|
||||
_A.information.initial_general_advice.decrease_heating,
|
||||
_A.warnings.patients_too_hot, _A.warnings.patients_getting_hot,
|
||||
}
|
||||
self:giveAdvice(hot_advice)
|
||||
self.adviser_data.temperature_advice = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Verify staff well-being with respect to room temperature.
|
||||
if day == 20 and not self.adviser_data.temperature_advice
|
||||
and not self.heating.heating_broke then
|
||||
-- Check staff warmth, default value does not result in a message.
|
||||
local warmth = self:getAverageStaffAttribute("warmth", 0.25)
|
||||
if warmth < 0.22 then
|
||||
self:giveAdvice({_A.warnings.staff_very_cold})
|
||||
self.adviser_data.temperature_advice = true
|
||||
|
||||
elseif warmth >= 0.36 then
|
||||
self:giveAdvice({_A.warnings.staff_too_hot})
|
||||
self.adviser_data.temperature_advice = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Are there sufficient drinks available?
|
||||
if day == 24 then
|
||||
-- Check patients thirst, default value does not result in a message.
|
||||
local thirst = self:getAveragePatientAttribute("thirst", 0)
|
||||
|
||||
-- Increase need after the first year.
|
||||
local threshold = current_date:year() == 1 and 0.9 or 0.8
|
||||
if thirst > threshold then
|
||||
self:giveAdvice({_A.warnings.patients_very_thirsty})
|
||||
elseif thirst > 0.6 then
|
||||
local thirst_advice = {
|
||||
_A.warnings.patients_thirsty, _A.warnings.patients_thirsty2,
|
||||
}
|
||||
self:giveAdvice(thirst_advice)
|
||||
end
|
||||
end
|
||||
|
||||
-- Track sitting / standing ratio of patients.
|
||||
if day % ratio_interval == 0 then
|
||||
-- Compute the ratio of today.
|
||||
local num_sitting, num_standing = self:countSittingStanding()
|
||||
local ratio = (num_sitting + num_standing > 10)
|
||||
and num_sitting / (num_sitting + num_standing) or nil
|
||||
|
||||
-- Store the measured ratio.
|
||||
self.adviser_data.sitting_ratios[self.adviser_data.sitting_index] = ratio
|
||||
self.adviser_data.sitting_index = (self.adviser_data.sitting_index >= num_sitting_ratios)
|
||||
and 1 or self.adviser_data.sitting_index + 1
|
||||
end
|
||||
|
||||
-- Check for enough (well-placed) benches.
|
||||
if day == 12 then
|
||||
-- Compute average sitting ratio.
|
||||
local sum_ratios = 0
|
||||
local index = 1
|
||||
while index <= num_sitting_ratios do
|
||||
local ratio = self.adviser_data.sitting_ratios[index]
|
||||
if ratio == nil then
|
||||
sum_ratios = nil
|
||||
break
|
||||
else
|
||||
sum_ratios = sum_ratios + ratio
|
||||
end
|
||||
|
||||
index = index + 1
|
||||
end
|
||||
|
||||
if sum_ratios ~= nil then -- Sufficient data available.
|
||||
local ratio = sum_ratios / num_sitting_ratios
|
||||
if ratio < 0.7 then -- At least 30% standing.
|
||||
local bench_advice = {
|
||||
_A.warnings.more_benches, _A.warnings.people_have_to_stand,
|
||||
}
|
||||
self:giveAdvice(bench_advice)
|
||||
|
||||
elseif ratio > 0.9 then
|
||||
-- Praise having enough well placed seats about once a year.
|
||||
local bench_advice = {
|
||||
_A.praise.many_benches, _A.praise.plenty_of_benches,
|
||||
_A.praise.few_have_to_stand,
|
||||
}
|
||||
self:giveAdvice(bench_advice, 1/12)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if day == 10 then
|
||||
self:warnForLongQueues()
|
||||
end
|
||||
|
||||
-- Reset advise flags at the end of the month.
|
||||
if day == 28 then
|
||||
self.adviser_data.temperature_advice = false
|
||||
end
|
||||
end
|
||||
|
||||
--! Give advice to the player at the end of a month.
|
||||
function PlayerHospital:monthlyAdviceChecks()
|
||||
local today = self.world:date()
|
||||
local current_month = today:monthOfYear()
|
||||
local current_year = today:year()
|
||||
|
||||
-- Check for advice on money.
|
||||
if not self.world.free_build_mode then
|
||||
if self.balance < 2000 and self.balance >= -500 then
|
||||
local cashlow_advice = {
|
||||
_A.warnings.money_low, _A.warnings.money_very_low_take_loan,
|
||||
_A.warnings.cash_low_consider_loan,
|
||||
}
|
||||
self:giveAdvice(cashlow_advice)
|
||||
|
||||
elseif self.balance < -2000 and current_month > 8 then
|
||||
-- TODO: Ideally this should be linked to the lose criteria for balance.
|
||||
self:giveAdvice({_A.warnings.bankruptcy_imminent})
|
||||
|
||||
elseif self.balance > 6000 and self.loan > 0 then
|
||||
self:giveAdvice({_A.warnings.pay_back_loan})
|
||||
end
|
||||
end
|
||||
|
||||
self:checkReceptionAdvice(current_month, current_year)
|
||||
end
|
||||
|
||||
--! Make players aware of the need for a receptionist and desk.
|
||||
--!param current_month (int) Month of the year.
|
||||
--!param current_year (int) Current game year.
|
||||
function PlayerHospital:checkReceptionAdvice(current_month, current_year)
|
||||
if current_year > 1 then return end -- Playing too long.
|
||||
if self:hasStaffedDesk() then return end -- Staffed desk available, all done.
|
||||
|
||||
local num_receptionists = self:countStaffOfCategory("Receptionist", 1)
|
||||
if num_receptionists ~= 0 and current_month > 2 and not self.adviser_data.reception_advice then
|
||||
self:giveAdvice({_A.warnings.no_desk_6})
|
||||
self.adviser_data.reception_advice = true
|
||||
|
||||
elseif num_receptionists == 0 and current_month > 2 and self:countReceptionDesks() ~= 0 then
|
||||
self:giveAdvice({_A.warnings.no_desk_7})
|
||||
|
||||
elseif current_month == 3 then
|
||||
self:giveAdvice({_A.warnings.no_desk}, 1, true)
|
||||
|
||||
elseif current_month == 8 then
|
||||
self:giveAdvice({_A.warnings.no_desk_1}, 1, true)
|
||||
|
||||
elseif current_month == 11 then
|
||||
if self.visitors == 0 then
|
||||
self:giveAdvice({_A.warnings.no_desk_2}, 1, true)
|
||||
else
|
||||
self:giveAdvice({_A.warnings.no_desk_3}, 1, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--! Give advice to the user about having bought a reception desk.
|
||||
function PlayerHospital:msgReceptionDesk()
|
||||
local num_receptionists = self:countStaffOfCategory("Receptionist", 1)
|
||||
|
||||
if not self.world.ui.start_tutorial and num_receptionists == 0 then
|
||||
self:giveAdvice({_A.room_requirements.reception_need_receptionist})
|
||||
elseif num_receptionists > 0 and self:countReceptionDesks() == 1 and
|
||||
not self.adviser_data.reception_advice and self.world:date():monthOfGame() > 3 then
|
||||
self:giveAdvice({_A.warnings.no_desk_5})
|
||||
self.adviser_data.reception_advice = true
|
||||
end
|
||||
end
|
||||
|
||||
--! Give advice to the user about maintenance of plants.
|
||||
function PlayerHospital:msgPlant()
|
||||
local num_handyman = self:countStaffOfCategory("Handyman", 1)
|
||||
|
||||
if num_handyman == 0 then
|
||||
self:giveAdvice({_A.staff_advice.need_handyman_plants})
|
||||
end
|
||||
end
|
||||
|
||||
--! Show the 'Gates to hell' animation.
|
||||
--!param entity (Entity) Gates to hell.
|
||||
function PlayerHospital:showGatesToHell(entity)
|
||||
local anim_func = --[[persistable:lava_hole_spawn_animation_end]]
|
||||
function(anim_entity)
|
||||
anim_entity:setAnimation(1602)
|
||||
end
|
||||
|
||||
entity:playEntitySounds("LAVA00*.WAV", {0,1350,1150,950,750,350},
|
||||
{0,1450,1250,1050,850,450}, 40)
|
||||
entity:setTimer(entity.world:getAnimLength(2550), anim_func)
|
||||
entity:setAnimation(2550)
|
||||
end
|
||||
|
||||
--! Advises the player.
|
||||
--!param msgs (array of string) Messages to select from.
|
||||
--!param rnd_frac (optional float in range (0, 1]) Fraction of times that the
|
||||
-- call actually says something.
|
||||
--!param stay_up (bool) If true, let the adviser remain visible afterwards.
|
||||
--!return (boolean) Whether a message was given to the user.
|
||||
function PlayerHospital:giveAdvice(msgs, rnd_frac, stay_up)
|
||||
local max_rnd = #msgs
|
||||
if rnd_frac and rnd_frac > 0 and rnd_frac < 1 then
|
||||
-- Scale by the fraction.
|
||||
max_rnd = math.floor(max_rnd / rnd_frac)
|
||||
end
|
||||
|
||||
local index = (max_rnd == 1) and 1 or math.random(1, max_rnd)
|
||||
if index <= #msgs then
|
||||
self.world.ui.adviser:say(msgs[index], stay_up)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--! Give the user possibly a message about a cured patient.
|
||||
function PlayerHospital:msgCured()
|
||||
self.world.ui:playSound("cheer.wav") -- This sound is always heard
|
||||
|
||||
if self.num_cured < 1 then -- First cure is always reported.
|
||||
self:giveAdvice({_A.information.first_cure})
|
||||
|
||||
elseif self.num_cured > 1 and not self.adviser_data.cured_died_message then
|
||||
local cured_msgs = {
|
||||
_A.level_progress.another_patient_cured:format(self.num_cured),
|
||||
_A.praise.patients_cured:format(self.num_cured)
|
||||
}
|
||||
self.adviser_data.cured_died_message = self:giveAdvice(cured_msgs, 2/15)
|
||||
end
|
||||
end
|
||||
|
||||
--! Give the user possibly a message about a dead patient.
|
||||
function PlayerHospital:msgKilled()
|
||||
self.world.ui:playSound("boo.wav") -- this sound is always heard
|
||||
|
||||
if self.num_deaths < 1 then -- First death is always reported.
|
||||
self:giveAdvice({_A.information.first_death})
|
||||
|
||||
elseif self.num_deaths > 1 and not self.adviser_data.cured_died_message then
|
||||
local died_msgs = {
|
||||
_A.warnings.many_killed:format(self.num_deaths),
|
||||
_A.level_progress.another_patient_killed:format(self.num_deaths)
|
||||
}
|
||||
self.adviser_data.cured_died_message = self:giveAdvice(died_msgs, 6/10)
|
||||
end
|
||||
end
|
||||
|
||||
--! Once a month the advisor may warn about long queues.
|
||||
--! Rooms requiring a doctor occasionally trigger the generic message
|
||||
function PlayerHospital:warnForLongQueues()
|
||||
local queue_rooms, total_queue = {}, 0
|
||||
for _, room in pairs(self.world.rooms) do
|
||||
if #room.door.queue then
|
||||
total_queue = total_queue + #room.door.queue
|
||||
end
|
||||
if #room.door.queue > 7 then
|
||||
queue_rooms[#queue_rooms + 1] = room
|
||||
end
|
||||
end
|
||||
if #queue_rooms == 0 or total_queue == 0 then return end
|
||||
|
||||
local busy_threshold = 1.5 * total_queue / #self.world.rooms
|
||||
local chosen_room = queue_rooms[math.random(1, #queue_rooms)]
|
||||
if busy_threshold > #chosen_room.door.queue then return end
|
||||
chosen_room = chosen_room.room_info
|
||||
-- Required staff that is not nurse is doctor, researcher, surgeon or psych
|
||||
if chosen_room.required_staff and not chosen_room.required_staff["Nurse"]
|
||||
and math.random(1, 3) > 1 then
|
||||
local warn_msgs = {
|
||||
_A.warnings.queue_too_long_send_doctor:format(chosen_room.name),
|
||||
_A.staff_advice.need_doctors
|
||||
}
|
||||
self:giveAdvice(warn_msgs)
|
||||
else
|
||||
self.world.ui.adviser:say(_A.warnings.queues_too_long)
|
||||
end
|
||||
end
|
||||
|
||||
--! Called at the end of each day.
|
||||
function PlayerHospital:onEndDay()
|
||||
-- Advise the player.
|
||||
if self:hasStaffedDesk() then
|
||||
self:dailyAdviceChecks()
|
||||
end
|
||||
|
||||
Hospital.onEndDay(self)
|
||||
end
|
||||
|
||||
-- Called at the end of each day.
|
||||
function PlayerHospital:onEndMonth()
|
||||
-- Advise the player on cash flow.
|
||||
if self:hasStaffedDesk() then
|
||||
self:monthlyAdviceChecks()
|
||||
end
|
||||
self.adviser_data.cured_died_message = nil -- Enable the message again.
|
||||
|
||||
-- Check if a player has won the level at months 3, 6 and 9. The annual report
|
||||
-- window will perform this check at month 12 when it has been closed.
|
||||
-- If the offer is declined then the next check is at month 6 and the annual report.
|
||||
local check_months = {
|
||||
[3] = not self.win_declined,
|
||||
[6] = true,
|
||||
[9] = not self.win_declined
|
||||
}
|
||||
if check_months[self.world.game_date:monthOfYear()] then self.world:checkIfGameWon() end
|
||||
|
||||
Hospital.onEndMonth(self)
|
||||
end
|
||||
|
||||
function PlayerHospital:afterLoad(old, new)
|
||||
if old < 145 then
|
||||
self.hosp_cheats = Cheats(self)
|
||||
end
|
||||
if old < 146 then
|
||||
self.adviser_data = {
|
||||
temperature_advise = nil,
|
||||
sitting_ratios = {},
|
||||
sitting_index = 1
|
||||
}
|
||||
end
|
||||
|
||||
if old < 147 then
|
||||
-- Copy value of the previous name of the variable.
|
||||
self.adviser_data.reception_advice = self.receptionist_msg
|
||||
end
|
||||
if old < 148 then
|
||||
self.adviser_data.cured_died_message = nil
|
||||
end
|
||||
if old < 149 then
|
||||
self.win_declined = false -- Has not yet declined the level win fax
|
||||
end
|
||||
|
||||
Hospital.afterLoad(self, old, new)
|
||||
end
|
@@ -102,8 +102,8 @@ local action_die_tick_reaper; action_die_tick_reaper = permanent"action_die_tick
|
||||
local mirror_grim = 0
|
||||
|
||||
local spawn_scenarios = {
|
||||
{"south", humanoid.tile_x, humanoid.tile_y + 4, 0, 1, "north", 0, -1, {{after_spawn_idle_direction = "east", hole_x_offset = -5, hole_y_offset = 2}, {hole_x_offset = 0, hole_y_offset = 3}} },
|
||||
{"east", humanoid.tile_x + 4, humanoid.tile_y, 1, 0, "west", -1, 0, {{hole_x_offset = 3, hole_y_offset = 0}} }
|
||||
{"south", humanoid.tile_x, humanoid.tile_y + 4, 1, 0, "west", -1, 0, {{after_spawn_idle_direction = "east", hole_x_offset = -5, hole_y_offset = 2}, {hole_x_offset = 0, hole_y_offset = 3}} },
|
||||
{"east", humanoid.tile_x + 4, humanoid.tile_y, 0, 1, "north", 0, -1, {{hole_x_offset = 3, hole_y_offset = 0}} }
|
||||
}
|
||||
|
||||
---
|
||||
@@ -114,15 +114,20 @@ local action_die_tick_reaper; action_die_tick_reaper = permanent"action_die_tick
|
||||
hole_x, hole_y = humanoid.world.pathfinder:findIdleTile(spawn_scenario[2], spawn_scenario[3], 0)
|
||||
|
||||
if hole_x and humanoid.world:canNonSideObjectBeSpawnedAt(hole_x, hole_y, "gates_to_hell", holes_orientation, 0, 0) then
|
||||
if holes_orientation == "east" then
|
||||
if holes_orientation == "south" then
|
||||
mirror_grim = 1
|
||||
end
|
||||
grim_use_tile_x = hole_x + spawn_scenario[4]
|
||||
grim_use_tile_y = hole_y + spawn_scenario[5]
|
||||
humanoid.hole_use_tile_x = hole_x + spawn_scenario[7]
|
||||
humanoid.hole_use_tile_y = hole_y + spawn_scenario[8]
|
||||
-- tile can't be in a room
|
||||
if humanoid.world:getRoom(humanoid.hole_use_tile_x, humanoid.hole_use_tile_y) then
|
||||
-- tile can't be in a room and must be accessible by the patient
|
||||
if not humanoid.world:getPathDistance(humanoid.tile_x, humanoid.tile_y, humanoid.hole_use_tile_x, humanoid.hole_use_tile_y)
|
||||
or humanoid.world:getRoom(humanoid.hole_use_tile_x, humanoid.hole_use_tile_y) then
|
||||
return false
|
||||
end
|
||||
-- ensure grim won't be in a room
|
||||
if humanoid.world:getRoom(grim_use_tile_x, grim_use_tile_y) then
|
||||
return false
|
||||
end
|
||||
--Ensure that the lava hole is passable on at least one of its sides to prevent it from blocking 1 tile wide corridors:
|
||||
@@ -137,7 +142,8 @@ local action_die_tick_reaper; action_die_tick_reaper = permanent"action_die_tick
|
||||
for _, find_grim_spawn_attempt in ipairs(spawn_scenario[9]) do
|
||||
grim_spawn_idle_direction = find_grim_spawn_attempt.after_spawn_idle_direction or spawn_scenario[6]
|
||||
grim_x, grim_y = humanoid.world.pathfinder:findIdleTile(hole_x + find_grim_spawn_attempt.hole_x_offset, hole_y + find_grim_spawn_attempt.hole_y_offset, 0)
|
||||
if grim_x and not humanoid.world:getRoom(grim_x, grim_y) then
|
||||
if grim_x and not humanoid.world:getRoom(grim_x, grim_y)
|
||||
and humanoid.world:getPathDistance(grim_x, grim_y, grim_use_tile_x, grim_use_tile_y) then
|
||||
grim_cant_walk_to_use_tile = false
|
||||
break
|
||||
end
|
||||
|
@@ -208,7 +208,7 @@ local action_queue_on_change_position = permanent"action_queue_on_change_positio
|
||||
local queue = action.queue
|
||||
if not must_stand then
|
||||
for i = 1, queue.bench_threshold do
|
||||
if queue[i] == humanoid then
|
||||
if queue:reportedHumanoid(i) == humanoid then
|
||||
must_stand = true
|
||||
break
|
||||
end
|
||||
|
@@ -38,6 +38,7 @@ local function action_seek_reception_start(action, humanoid)
|
||||
local world = humanoid.world
|
||||
local best_desk
|
||||
local score
|
||||
local queuetotal = 0
|
||||
|
||||
assert(humanoid.hospital, "humanoid must be associated with a hospital to seek reception")
|
||||
|
||||
@@ -62,6 +63,7 @@ local function action_seek_reception_start(action, humanoid)
|
||||
score = this_score
|
||||
best_desk = desk
|
||||
end
|
||||
queuetotal = queuetotal + #desk.queue
|
||||
end
|
||||
end
|
||||
if best_desk then
|
||||
@@ -93,6 +95,19 @@ local function action_seek_reception_start(action, humanoid)
|
||||
end
|
||||
end
|
||||
end
|
||||
local desks = #humanoid.hospital:findReceptionDesks()
|
||||
local receptionists = humanoid.hospital:countStaffOfCategory("Receptionist")
|
||||
if (receptionists > 1 and desks > 0) or (receptionists > 0 and desks > 1) then
|
||||
local queueavg = math.floor(queuetotal / desks)
|
||||
if receptionists < desks and queueavg > 5 then
|
||||
world.ui.adviser:say(_A.warnings.reception_bottleneck)
|
||||
elseif queueavg > 4 then
|
||||
world.ui.adviser:say(_A.warnings.queue_too_long_at_reception)
|
||||
elseif receptionists > desks then
|
||||
world.ui.adviser:say(_A.warnings.another_desk)
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
-- No reception desk found. One will probably be built soon, somewhere in
|
||||
-- the hospital, so either walk to the hospital, or walk around the hospital.
|
||||
|
@@ -74,7 +74,7 @@ local action_seek_room_find_room = permanent"action_seek_room_find_room"( functi
|
||||
table.remove(available_rooms, room_at_index)
|
||||
-- If the room can be built, set the flag for it.
|
||||
local diag = humanoid.world.available_rooms[room_type]
|
||||
if diag and humanoid.hospital.discovered_rooms[diag] then
|
||||
if diag and humanoid.hospital:isRoomDiscovered(diag.id) then
|
||||
action.diagnosis_exists = room_type
|
||||
end
|
||||
end
|
||||
@@ -135,7 +135,8 @@ local function action_seek_room_no_treatment_room_found(room_type, humanoid)
|
||||
local req = humanoid.hospital:checkDiseaseRequirements(humanoid.disease.id)
|
||||
local research_enabled = false
|
||||
if req then
|
||||
research_enabled = humanoid.hospital:hasRoomOfType("research") and humanoid.hospital:hasStaffOfCategory("Researcher")
|
||||
research_enabled = (humanoid.hospital:countRoomOfType("research", 1) > 0 and
|
||||
humanoid.hospital:countStaffOfCategory("Researcher", 1) > 0)
|
||||
if #req.rooms == 1 then
|
||||
local room_name, required_staff, staff_name = humanoid.world:getRoomNameAndRequiredStaffName(req.rooms[1])
|
||||
if req.staff[required_staff] or 0 > 0 then
|
||||
@@ -273,10 +274,10 @@ local function action_seek_room_start(action, humanoid)
|
||||
|
||||
-- check we can treat the patient - and just shortcut the processing
|
||||
local req = humanoid.hospital:checkDiseaseRequirements(humanoid.disease.id)
|
||||
if humanoid.diagnosed and not req then
|
||||
if humanoid.diagnosed then
|
||||
local room = action_seek_room_find_room(action, humanoid)
|
||||
-- if we have the room but not the staff we shouldn't seek out the room either
|
||||
if room then
|
||||
if room and (not req or not action.treatment_room) then
|
||||
if humanoid.message then
|
||||
TheApp.ui.bottom_panel:removeMessage(humanoid)
|
||||
end
|
||||
@@ -357,7 +358,7 @@ local function action_seek_room_start(action, humanoid)
|
||||
-- don't need this as we unregistered all previous callbacks if we went to research
|
||||
local room_req = humanoid.hospital:checkDiseaseRequirements(humanoid.disease.id)
|
||||
-- get required staff
|
||||
if not humanoid.diagnosed or not room_req then
|
||||
if not humanoid.diagnosed or (not room_req or not action.treatment_room) then
|
||||
action_seek_room_goto_room(rm, humanoid, action.diagnosis_room)
|
||||
TheApp.ui.bottom_panel:removeMessage(humanoid)
|
||||
humanoid:unregisterRoomBuildCallback(build_callback)
|
||||
|
@@ -50,7 +50,7 @@ local function action_vip_go_to_next_room_start(action, humanoid)
|
||||
humanoid.next_room.humanoids_enroute[humanoid] = nil
|
||||
--humanoid.next_room.door.reserved_for = humanoid
|
||||
humanoid:evaluateRoom()
|
||||
humanoid.waiting = 3
|
||||
humanoid.waiting = nil
|
||||
end
|
||||
-- Find direction to look at
|
||||
local ix, iy = humanoid.next_room:getEntranceXY(true)
|
||||
@@ -64,7 +64,7 @@ local function action_vip_go_to_next_room_start(action, humanoid)
|
||||
dir = "east"
|
||||
end
|
||||
end
|
||||
humanoid:queueAction(IdleAction():setLoopCallback(evaluate):setDirection(dir))
|
||||
humanoid:queueAction(IdleAction():setCount(50):setAfterUse(evaluate):setDirection(dir))
|
||||
|
||||
-- Finish this action and start the above sequence.
|
||||
humanoid:finishAction()
|
||||
|
@@ -58,6 +58,36 @@ vip_names = {
|
||||
[6] = "O Presidente da Cruz Vermelha",
|
||||
}
|
||||
|
||||
-- An override for the squits becoming the the squits see issue 1646
|
||||
adviser.research.drug_improved_1 = "Seu Centro de Pesquisa melhorou o medicamento para %s"
|
||||
|
||||
-- Disease overrides where there are typos
|
||||
golf_stones.cure = "Cura - Dois cirurgiöes operam para extrair os cálculos."
|
||||
ruptured_nodules.cure = "Cura - Dois cirurgiöes qualificados colocam certas partes com mäos firmes."
|
||||
slack_tongue.cause = "Causa - Fazer muita fofoca."
|
||||
slack_tongue.cure = "Cura - Coloca-se a língua no corta-línguas e elimina-se de forma rápida, eficaz e dolorosa."
|
||||
the_squits.cure = "Cura - Uma mistura pegajosa de substâncias viscosas preparada na farmácia solidifica as tripas do paciente."
|
||||
bloaty_head.cure = "Cura - Fura-se a cabeça inflada, em seguida, volta-se a inflar até o tamanho correto com uma máquina inteligente."
|
||||
|
||||
-- Rooms overrides where there are typos
|
||||
inflation[2] = "Os pacientes que sofrem a dolorosa doença de terem a cabeça inflada devem ir à sala de inflatoterapia, será desinflada sua cabeça e em seguida vota a ser inflada à pressäo correta.//"
|
||||
staff_room[2] = "Os seus funcionários se cansam quando realizam o seu trabalho. Precisam desta sala para descansar e se refrescar. Os funcionários cansados säo mais lentos, pedem mais dinheiro e por fim väo embora. Também cometem mais erros. Vale a pena construir uma sala que tenham muitos passatempos. Assegure-se de que há lugar para vários funcionários ao mesmo tempo. "
|
||||
|
||||
-- Staff description overrides where there are typos
|
||||
staff_descriptions.bad[14] = "Pessoa ardilosa, matreira e subversiva. "
|
||||
staff_descriptions.misc[11] = "Destila uísque. "
|
||||
|
||||
-- Correction to a pay rise prompt with typos
|
||||
pay_rise.regular[1] = "Estou esgotado. Preciso de umas boas férias, mais um aumento de %d, se näo quiser deixo este maldito emprego."
|
||||
|
||||
-- Level description overrides where there are typos. Note: This is the only portion of the game that SHOULD use double space after fullstops etc.
|
||||
introduction_texts.level17 = "Um último aviso. Fique de olho na sua Reputaçäo, é o que atrairá pacientes ao seu estabelecimento. Se näo matar muitas pessoas e as mantiver razoavelmente felizes näo deverá ter muitos problemas com este nível!//Agora é com você, boa sorte."
|
||||
introduction_texts.level11 = "Tem a oportunidade de construir o hospital definitivo. Esta é uma área de enorme prestígio e o Ministério quer que este seja o melhor hospital. Esperamos que ganhe muito dinheiro, alcance uma excelente reputaçäo e que se encarregue de todos os casos que sejam apresentados. Este é um trabalho importante. Terá que ser muito hábil para completá-lo. Também deve ter em conta que foram vistos OVNIs na área. Assegure-se de que os seus funcionários estejam preparados para receber algumas visitas inesperadas. O seu hospital terá que alcançar um valor de $240.000, precisará ter $500.000 no banco e uma reputaçäo de 700."
|
||||
introduction_texts.level9 = "Depois de depositar o dinheiro na conta bancária do Ministério e pagar uma nova limousine para o Ministro, agora pode dedicar a criar um bom hospital para cuidar dos doentes e necessitados. Aqui terá um montäo de problemas diferentes. Se os seus funcionários tiverem uma boa formaçäo e suficientes consultas, poderäo resolver qualquer situaçäo. O seu hospital terá que valer $200.000 e precisará ter $400.000 no banco. Se näo o conseguir näo poderá terminar o nível."
|
||||
introduction_texts.level16 = "Uma vez que tenha diagnosticado algum dos pacientes, precisará construir salas de tratamento e clínicas para curá-los. Pode começar com uma Farmácia, onde precisará de uma Enfermeira que distribua os remédios."
|
||||
introduction_texts.level10 = "Além de dever curar todas as doenças que possa haver, o Ministério pede que empregue um pouco de tempo em aumentar a eficácia dos seus remédios.//Houve algumas queixas por parte do D. Salutíssimo, o Cachorro Guardiäo da Saúde, assim deve procurar com que todos os seus remédios sejam extremamente eficazes para ficar bem. Também, assegure-se de que o seu hospital tenha uma reputaçäo irrepreensível. Procure deixar morrer poucos pacientes. Como sugestäo, deveria deixar espaço para um banho gelatinoso. Para ganhar, os seus remédios deveräo ter uma eficácia de, pelo menos, 80%, tem que conseguir uma reputaçäo de 650 e guardar $500.000 no banco."
|
||||
introduction_texts.level12 = "Agora enfrentará o maior dos desafios. Impressionado com os seus lucros, o Ministério tem uma grande tarefa para você; querem que construa outro magnífico hospital, que tenha um excelente lucro e uma reputaçäo incrível. Também querem que compre todo o terreno que puder, cure tudo (e queremos dizer todas as doenças) e ganhe todos os prêmios. Acha que conseguirá? Ganhe $650.000, cure 750 pessoas e consiga uma reputaçäo de 800 para ganhar este nível."
|
||||
introduction_texts.level15 = "Bem, estes säo os mecanismos básicos para pôr em funcionamento um hospital.//Os seus Médicos väo precisar de toda a ajuda que possam obter para diagnosticar alguns dos pacientes. Pode ajudá-los construindo outros equipamentos de diagnóstico como a sala de Diagnóstico Geral."
|
||||
-- A small error in the introduction text of level 2
|
||||
introduction_texts.level2 = "Há uma grande variedade de doenças nesta área. Prepare o seu hospital para tratar mais pacientes " ..
|
||||
"e para a construçäo de um Centro de Pesquisa. Lembre-se que deve manter limpo o hospital e procurar atingir a " ..
|
||||
@@ -66,8 +96,19 @@ introduction_texts.level2 = "Há uma grande variedade de doenças nesta área. P
|
||||
"ser pesquisadas antes de as construir. Também pode comprar mais terreno para aumentar o seu hospital. " ..
|
||||
"Para isso, utilize o mapa da cidade. Obtenha uma reputaçäo de 300 um saldo de bancário de $10,000 e 40 pessoas curadas. "
|
||||
|
||||
-- An override for the squits becoming the the squits see issue 1646
|
||||
adviser.research.drug_improved_1 = "Seu Centro de Pesquisa melhorou o medicamento para %s"
|
||||
-- Override for level progress typo
|
||||
level_progress.hospital_value_enough = "Mantenha o valor do seu hospital acima de %d e atenda os seus outros problemas para ganhar o nível."
|
||||
level_progress.cured_enough_patients = "Curou muitos pacientes, mas precisa manter o seu hospital em melhor estado para ganhar o nível."
|
||||
|
||||
-- Override for multiplayer typos
|
||||
multiplayer.players_failed = "O(s) seguinte jogador(es) falharam ao alcançar o último objetivo: "
|
||||
multiplayer.everyone_failed = "Todos falharam ao satisfazer aquele último objetivo."
|
||||
|
||||
-- Override for a disease patient choice typo
|
||||
disease_discovered_patient_choice.need_to_employ = "Contrate um(a) %s para corrigir esta situaçäo."
|
||||
|
||||
--Win message override typo
|
||||
letter[12][2] = "A sua bem-sucedida carreira como o melhor diretor de hospital desde Moisés está chegando ao seu fim. Você provocou tanto efeito nos círculos médicos, que o Ministério quer lhe oferecer um salário de %s, só para inaugurar festas, navios e organizar entrevistas em nosso nome. Você seria um excelente relaçöes públicas!//"
|
||||
------------------------------- NEW STRINGS -------------------------------
|
||||
date_format = {
|
||||
daymonth = "%1% %2:months%",
|
||||
@@ -113,10 +154,10 @@ menu_options = {
|
||||
menu_options_game_speed = {
|
||||
pause = " (%1%) PAUSAR ",
|
||||
slowest = " (%1%) MUITO LENTO ",
|
||||
slower = " (%1%) LENTO ",
|
||||
slower = " (%1%) LENTO ",
|
||||
normal = " (%1%) NORMAL ",
|
||||
max_speed = " (%1%) RAPIDO ",
|
||||
and_then_some_more = " (%1%) MUITO RAPIDO ",
|
||||
and_then_some_more = " (%1%) MUITO RAPIDO ",
|
||||
}
|
||||
|
||||
menu_options_warmth_colors = {
|
||||
@@ -127,20 +168,20 @@ menu_options_warmth_colors = {
|
||||
|
||||
menu_options_wage_increase = {
|
||||
grant = " PERMITIR ",
|
||||
deny = " NEGAR ",
|
||||
deny = " NEGAR ",
|
||||
}
|
||||
|
||||
-- Add F-keys to entries in charts menu (except briefing), also town_map was added.
|
||||
menu_charts = {
|
||||
bank_manager = " (%1%) GERENTE DO BANCO ",
|
||||
statement = " (%1%) ESTADO DA CONTA ",
|
||||
bank_manager = " (%1%) GERENTE DO BANCO ",
|
||||
statement = " (%1%) ESTADO DA CONTA ",
|
||||
staff_listing = " (%1%) LISTA DOS FUNCIONARIOS ",
|
||||
town_map = " (%1%) MAPA DA CIDADE ",
|
||||
casebook = " (%1%) FICHA CLINICA ",
|
||||
research = " (%1%) PESQUISA ",
|
||||
status = " (%1%) ESTADO ",
|
||||
graphs = " (%1%) GRAFICO ",
|
||||
policy = " (%1%) NORMAS ",
|
||||
town_map = " (%1%) MAPA DA CIDADE ",
|
||||
casebook = " (%1%) FICHA CLINICA ",
|
||||
research = " (%1%) PESQUISA ",
|
||||
status = " (%1%) ESTADO ",
|
||||
graphs = " (%1%) GRAFICO ",
|
||||
policy = " (%1%) NORMAS ",
|
||||
}
|
||||
|
||||
menu_debug = {
|
||||
@@ -175,10 +216,10 @@ menu_debug_overlay = {
|
||||
parcel = " PARCELA ",
|
||||
}
|
||||
menu_player_count = {
|
||||
players_1 = " 1 JOGADOR ",
|
||||
players_2 = " 2 JOGADORES ",
|
||||
players_3 = " 3 JOGADORES ",
|
||||
players_4 = " 4 JOGADORES ",
|
||||
players_1 = " 1 JOGADOR ",
|
||||
players_2 = " 2 JOGADORES ",
|
||||
players_3 = " 3 JOGADORES ",
|
||||
players_4 = " 4 JOGADORES ",
|
||||
}
|
||||
adviser = {
|
||||
room_forbidden_non_reachable_parts = "Construir a sala neste local resultará em alas do hospital que näo poderäo ser acessadas.",
|
||||
@@ -205,7 +246,7 @@ adviser = {
|
||||
researcher_needs_desk_2 = "Seu pesquisador agradece que lhe tenha dado um descanso. Se pretende ter mais pessoas pesquisando, deve dar a cada um uma mesa para trabalhar.",
|
||||
researcher_needs_desk_3 = "Cada pesquisa necessita de uma mesa para trabalhar.",
|
||||
nurse_needs_desk_1 = "Cada enfermeira necessita de uma mesa para trabalhar.",
|
||||
nurse_needs_desk_2 = "Sua enfermeira agradece que lhe tenha dado um descanso. Se pretende ter mais pessoas trabalhando na enfermaria, tem que dar a cada uma delas uma mesa para trabalhar.",
|
||||
nurse_needs_desk_2 = "Sua enfermeira agradece que lhe tenha dado um descanso. Se pretende ter mais pessoas trabalhando na Enfermaria, tem que dar a cada uma delas uma mesa para trabalhar.",
|
||||
low_prices = "Você está cobrando muito pouco pelo uso de %s. Isto trará pessoas para o seu hospital, mas você näo fará muito lucro com cada uma delas.",
|
||||
high_prices = "Você está cobrando muito pelo uso de %s. Isto trará grande lucro a curto prazo, mas no final das contas você começará a afugentar as pessoas para longe do seu hospital.",
|
||||
fair_prices = "O preço de %s parece justo.",
|
||||
@@ -221,6 +262,7 @@ adviser = {
|
||||
dynamic_info.patient.actions.no_gp_available = "Esperando que construa um Consultório Geral"
|
||||
dynamic_info.staff.actions.heading_for = "Dirigindo-se para %s"
|
||||
dynamic_info.staff.actions.fired = "Despedido"
|
||||
dynamic_info.staff.actions.vaccine = "Vacinando um paciente"
|
||||
dynamic_info.patient.actions.epidemic_vaccinated = "Eu näo sou mais contagioso"
|
||||
|
||||
progress_report.free_build = "CONSTRUÇAO LIVRE"
|
||||
@@ -372,6 +414,10 @@ options_window = {
|
||||
apply = "Aplicar",
|
||||
cancel = "Cancelar",
|
||||
back = "Voltar",
|
||||
scrollspeed = "Veloc. de Rolagem",
|
||||
shift_scrollspeed = "Veloc. Rolagem Acel.",
|
||||
zoom_speed = "Veloc. do Zoom",
|
||||
hotkey = "Atalhos",
|
||||
}
|
||||
|
||||
tooltip.options_window = {
|
||||
@@ -392,6 +438,16 @@ tooltip.options_window = {
|
||||
select_language = "Selecione o idioma do jogo",
|
||||
language_dropdown_item = "Selecionar %s como idioma",
|
||||
back = "Fechar a janela de Configuraçöes",
|
||||
scrollspeed = "Defina a velocidade de rolagem entre 1 (mais lenta) até 10 (mais rápida). O padräo é 2.",
|
||||
shift_scrollspeed = "Defina a velocidade da rolagem enquanto a tecla Shift é pressionada. 1 (mais lento) até 10 (mais rápido). O padräo é 4.",
|
||||
zoom_speed = "Defina a velocidade da aproximaçäo da câmera de 10 (mais lenta) até 1000 (mais rápida). O padräo é 80.",
|
||||
apply_scrollspeed = "Aplique a velocidade de rolagem inserida.",
|
||||
cancel_scrollspeed = "Retornar sem alterar a velocidade de rolagem.",
|
||||
apply_shift_scrollspeed = "Aplique a velocidade de rolagem de acelerada inserida.",
|
||||
cancel_shift_scrollspeed = "Retorne sem alterar a velocidade de rolagem acelerada.",
|
||||
apply_zoomspeed = "Aplique a velocidade de aproximaçäo inserida.",
|
||||
cancel_zoomspeed = "Retorne sem alterar a velocidade de aproximaçäo.",
|
||||
hotkey = "Altere as teclas de atalho do teclado.",
|
||||
}
|
||||
|
||||
customise_window = {
|
||||
@@ -454,6 +510,124 @@ tooltip.folders_window = {
|
||||
back = "Fechar este menu e voltar para o menu de Configuraçöes",
|
||||
}
|
||||
|
||||
hotkey_window = {
|
||||
caption_main = "Atribuiçäo de teclas de atalho",
|
||||
caption_panels = "Teclas do painel",
|
||||
button_accept = "Aceitar",
|
||||
button_defaults = "Restaurar padröes",
|
||||
button_cancel = "Cancelar",
|
||||
button_back = "Voltar",
|
||||
button_toggleKeys = "Teclas de alternância",
|
||||
button_recallPosKeys = "Tecla de retorno de posiçäo",
|
||||
panel_globalKeys = "Teclas globais",
|
||||
panel_generalInGameKeys = "Teclas gerais no jogo",
|
||||
panel_scrollKeys = "Teclas de rolagem",
|
||||
panel_zoomKeys = "Teclas de aproximaçäo",
|
||||
panel_gameSpeedKeys = "Teclas de velocidade do jogo",
|
||||
panel_miscInGameKeys = "Teclas diversas no jogo",
|
||||
panel_toggleKeys = "Teclas de alternância",
|
||||
panel_debugKeys = "Teclas de depuraçäo",
|
||||
panel_storePosKey = "Armazenamento de posiçäo",
|
||||
panel_recallPosKeys = "Retorno de posiçäo",
|
||||
panel_altPanelKeys = "Teclas de alternância do painel",
|
||||
global_confirm = "Confirmar",
|
||||
global_confirm_alt = "Alt. confirmar",
|
||||
global_cancel = "Cancelar",
|
||||
global_cancel_alt = "Alt. cancelar",
|
||||
global_fullscreen_toggle = "Tela cheia",
|
||||
global_exitApp = "Sair do app",
|
||||
global_resetApp = "Reiniciar app",
|
||||
global_releaseMouse = "Liberar mouse",
|
||||
global_connectDebugger = "Depurar",
|
||||
global_showLuaConsole = "Console Lua",
|
||||
global_runDebugScript = "Script de depuraçäo",
|
||||
global_screenshot = "Capturar tela",
|
||||
global_stop_movie_alt = "Parar filme",
|
||||
global_window_close_alt = "Fechar janela",
|
||||
ingame_scroll_up = "Rolar p/ cima",
|
||||
ingame_scroll_down = "Rolar p/ baixo",
|
||||
ingame_scroll_left = "Rolar p/ esq.",
|
||||
ingame_scroll_right = "Rolar p/ dir.",
|
||||
ingame_scroll_shift = "Veloc. aceler.",
|
||||
ingame_zoom_in = "Aproximar",
|
||||
ingame_zoom_in_more = "Aproximar mais",
|
||||
ingame_zoom_out = "Afastar",
|
||||
ingame_zoom_out_more = "Afastar mais",
|
||||
ingame_showmenubar = "Barra de menu",
|
||||
ingame_showCheatWindow = "Menu de trapaça",
|
||||
ingame_loadMenu = "Carregar jogo",
|
||||
ingame_saveMenu = "Salvar jogo",
|
||||
ingame_jukebox = "Máq. de discos",
|
||||
ingame_openFirstMessage = "Nív. mensagem",
|
||||
ingame_pause = "Pausa",
|
||||
ingame_gamespeed_slowest = "Muito lento",
|
||||
ingame_gamespeed_slower = "Lento",
|
||||
ingame_gamespeed_normal = "Normal",
|
||||
ingame_gamespeed_max = "Rápido",
|
||||
ingame_gamespeed_thensome = "Muito rápido",
|
||||
ingame_gamespeed_speedup = "Volume +",
|
||||
ingame_panel_bankManager = "Ger. do banco",
|
||||
ingame_panel_bankStats = "Estado da conta",
|
||||
ingame_panel_staffManage = "Lista de funcion.",
|
||||
ingame_panel_townMap = "Mapa da cidade",
|
||||
ingame_panel_casebook = "Ficha clinica",
|
||||
ingame_panel_research = "Pesquisa",
|
||||
ingame_panel_status = "Estado",
|
||||
ingame_panel_charts = "Gráfico",
|
||||
ingame_panel_policy = "Normas",
|
||||
ingame_panel_map_alt = "Mapa da cidade 2",
|
||||
ingame_panel_research_alt = "Pesquisa 2",
|
||||
ingame_panel_casebook_alt = "Ficha clinica 2",
|
||||
ingame_panel_casebook_alt02 = "Ficha clinica 3",
|
||||
ingame_panel_buildRoom = "Construir sala",
|
||||
ingame_panel_furnishCorridor = "Mobiliar corredor",
|
||||
ingame_panel_editRoom = "Editar sala",
|
||||
ingame_panel_hireStaff = "Contratar",
|
||||
ingame_rotateobject = "Girar objeto",
|
||||
ingame_quickSave = "Salvar rapid.",
|
||||
ingame_quickLoad = "Carregar rapid.",
|
||||
ingame_restartLevel = "Reiniciar nível",
|
||||
ingame_quitLevel = "Sair do nível",
|
||||
ingame_setTransparent = "Transparente",
|
||||
ingame_toggleAnnouncements = "Anúncios",
|
||||
ingame_toggleSounds = "Sons",
|
||||
ingame_toggleMusic = "Música",
|
||||
ingame_toggleAdvisor = "Conselheiro",
|
||||
ingame_toggleInfo = "Informaçäo",
|
||||
ingame_poopLog = "Extrair relatório",
|
||||
ingame_poopStrings = "Extrair textos",
|
||||
ingame_patient_gohome = "Enviar p/ casa",
|
||||
ingame_storePosition_1 = "1",
|
||||
ingame_storePosition_2 = "2",
|
||||
ingame_storePosition_3 = "3",
|
||||
ingame_storePosition_4 = "4",
|
||||
ingame_storePosition_5 = "5",
|
||||
ingame_storePosition_6 = "6",
|
||||
ingame_storePosition_7 = "7",
|
||||
ingame_storePosition_8 = "8",
|
||||
ingame_storePosition_9 = "9",
|
||||
ingame_storePosition_0 = "10",
|
||||
ingame_recallPosition_1 = "1",
|
||||
ingame_recallPosition_2 = "2",
|
||||
ingame_recallPosition_3 = "3",
|
||||
ingame_recallPosition_4 = "4",
|
||||
ingame_recallPosition_5 = "5",
|
||||
ingame_recallPosition_6 = "6",
|
||||
ingame_recallPosition_7 = "7",
|
||||
ingame_recallPosition_8 = "8",
|
||||
ingame_recallPosition_9 = "9",
|
||||
ingame_recallPosition_0 = "10",
|
||||
}
|
||||
|
||||
tooltip.hotkey_window = {
|
||||
button_accept = "Aceitar e salvar atribuiçöes de teclas de atalho",
|
||||
button_defaults = "Restaura todas as teclas de atalho para os padröes do programa",
|
||||
button_cancel = "Cancela a atribuiçäo e volta ao menu de opçöes",
|
||||
caption_panels = "Abre a janela para atribuir teclas do painel",
|
||||
button_recallPosKeys = "Abre a janela para definir teclas para armazenamento e retorno da posiçöes da câmera",
|
||||
button_back_02 = "Volta para a janela principal de teclas de atalho. As teclas de atalho alteradas nesta janela podem ser aceitas lá",
|
||||
}
|
||||
|
||||
font_location_window = {
|
||||
caption = "Selecionar fonte (%1%)",
|
||||
}
|
||||
@@ -464,7 +638,7 @@ handyman_window = {
|
||||
}
|
||||
|
||||
tooltip.handyman_window = {
|
||||
parcel_select = "Parcela onde o faz-tudo aceita tarefas, clique para alterar o configuraçäo"
|
||||
parcel_select = "Parcela onde o zelador aceita tarefas, clique para alterar o configuraçäo"
|
||||
}
|
||||
|
||||
new_game_window = {
|
||||
@@ -553,7 +727,7 @@ tooltip.information = {
|
||||
totd_window = {
|
||||
tips = {
|
||||
"Todo hospital precisa de uma Recepçäo e um Consultório Geral para começar. Depois disso, dependerá do tipo de pacientes que visitará seu hospital. Entretanto ter uma farmácia é sempre uma boa ideia.",
|
||||
"Máquinas como o Inflador precisam de constante manutençäo. Contrate um ou dois Faz-tudo para reparos nestas máquinas, ou colocará seus funcionários e pacientes em risco.",
|
||||
"Máquinas como o Inflador precisam de constante manutençäo. Contrate um ou dois Zeladores para reparos nestas máquinas, ou colocará seus funcionários e pacientes em risco.",
|
||||
"Depois de um certo período de trabalho, seus funcionários ficaräo cansados. Certifique-se de construir uma Sala de Descanso, para que posam relaxar.",
|
||||
"Instale Radiadores suficientes para manter seus funcionários e pacientes aquecidos, do contrário ficaräo infelizes. Use o Mapa da Cidade para localizar pontos do hospital que precisem ser aquecidos.",
|
||||
"O nível de habilidade de um médico reflete na qualidade e velocidade dos diagnósticos. Coloque um médico experiente no Consultório Geral, assim näo precisará de muitas salas de diagnósticos adicionais.",
|
||||
@@ -703,6 +877,35 @@ map_editor_window = {
|
||||
}
|
||||
}
|
||||
|
||||
fax = {
|
||||
vip_visit_result = {
|
||||
ordered_remarks = {
|
||||
[1] = "Que hospital eficaz! A próxima vez que estiver gravemente doente, eu venho aqui.",
|
||||
[2] = "É isto o que eu chamo de um hospital.",
|
||||
[3] = "É um hospital excelente. E sei o que digo; visito muitos hospitais.",
|
||||
[4] = "Que hospital bem administrado! Obrigado pelo seu convite.",
|
||||
[5] = "Mmmm. Certamente näo é uma má instituiçäo médica.",
|
||||
[6] = "Gostei do seu estupendo hospital. Agora, alguém quer um curry da Casa do Curry?",
|
||||
[7] = "Bom, já vi piores. Mas deveria fazer algumas melhoras.",
|
||||
[8] = "Oh céus! Näo é um lugar agradável para ir se estiver doente.",
|
||||
[9] = "Vou ser sincero, é um hospital normal. Francamente, eu esperava mais.",
|
||||
[10] = "Por que me zanguei? Foi pior que ir ver uma ópera de quatro horas!",
|
||||
[11] = "Estou aborrecido pelo que vi. Chama a isto um hospital? Mais parece uma pocilga!",
|
||||
[12] = "Estou farto de atrair a atençäo pública e de visitar buracos fedorentos como este! Eu me demito.",
|
||||
[13] = "Que lixo. Vou tentar fechá-lo.",
|
||||
[14] = "Eu nunca vi um hospital täo ruim. Que vergonha!",
|
||||
[15] = "Estou chocado. Você näo pode chamar isso de hospital! Näo me espere ver novamente.",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hotkeys_file_err = {
|
||||
file_err_01 = "Näo foi possível carregar o arquivo hotkeys.txt. Certifique-se de que o " ..
|
||||
"Theme Hospital tem permissäo de leitura/escrita ",
|
||||
file_err_02 = ", ou use a opçäo linha de comando --hotkeys-file=NomeDoArquivo para especificar um arquivo gravável. " ..
|
||||
"Para referência, o erro ao carregar o arquivo de teclas de atalho foi: ",
|
||||
}
|
||||
|
||||
-------------------------------- UNUSED -----------------------------------
|
||||
------------------- (kept for backwards compatibility) ----------------------
|
||||
|
||||
@@ -712,18 +915,18 @@ tooltip.options_window.change_resolution = "Altera a resoluçäo de janela para
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------- MISSING STRINGS IN LANGUAGE "PORTUGUêS DO BRASIL": -----------------------------------
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
rooms_long.ward = "Enfermaria"
|
||||
rooms_long.ward = "Sala de Enfermaria"
|
||||
rooms_long.blood_machine = "Sala de Transfusöes"
|
||||
rooms_long.emergency = "Sala de Emergências"
|
||||
rooms_long.general = "Sala de Clínica Geral"
|
||||
rooms_long.cardiogram = "Sala do Cardiograma"
|
||||
rooms_long.general = "Diagnóstico Geral"
|
||||
rooms_long.cardiogram = "Sala de Cardiograma"
|
||||
rooms_long.decontamination = "Sala de Descontaminaçäo"
|
||||
rooms_long.jelly_vat = "Banho Gelatinoso"
|
||||
rooms_long.staffroom = "Sala de Descanso"
|
||||
rooms_long.hair_restoration = "Sala de Peloterapia"
|
||||
rooms_long.inflation = "Sala de Inflatoterapia"
|
||||
rooms_long.operating_theatre = "Sala de Operaçöes"
|
||||
rooms_long.gps_office = "Consultório Geral"
|
||||
rooms_long.operating_theatre = "Sala de Cirurgia"
|
||||
rooms_long.gps_office = "Consultório de Clínica Geral"
|
||||
rooms_long.training_room = "Sala de Formaçäo"
|
||||
rooms_long.x_ray = "Sala de Raio-X"
|
||||
rooms_long.tongue_clinic = "Sala de Laringologia"
|
||||
@@ -788,7 +991,7 @@ fax.vip_visit_result.remarks.very_bad[3] = "Estou horrorizado. Chama a isto de h
|
||||
fax.vip_visit_result.remarks.bad[1] = "Por que me zanguei? Foi pior que ir ver uma ópera de quatro horas!"
|
||||
fax.vip_visit_result.remarks.bad[2] = "Estou aborrecido pelo que vi. Chama a isto um hospital? Mais parece uma pocilga!"
|
||||
fax.vip_visit_result.remarks.bad[3] = "Estou farto de atrair a atençäo pública e de visitar buracos fedorentos como este! Demito-me."
|
||||
fax.vip_visit_result.remarks.good[1] = "Que hospital bem dirigido! Obrigado pelo seu convite."
|
||||
fax.vip_visit_result.remarks.good[1] = "Que hospital bem administrado! Obrigado pelo seu convite."
|
||||
fax.vip_visit_result.remarks.good[2] = "Mmmm. Certamente näo é uma má instituiçäo médica."
|
||||
fax.vip_visit_result.remarks.good[3] = "Gostei do seu estupendo hospital. Agora, alguém quer um curry da Casa do Curry?"
|
||||
fax.vip_visit_result.cash_grant = "Você ganhou um prêmio em dinheiro de $%d."
|
||||
@@ -1133,7 +1336,7 @@ build_room_window.pick_room_type = "Escolha a sala"
|
||||
build_room_window.pick_department = "Departamento"
|
||||
build_room_window.cost = "Custo: "
|
||||
object.bench = "Banco"
|
||||
object.pharmacy_cabinet = "Primeiros socorros"
|
||||
object.pharmacy_cabinet = "Armário de remédios"
|
||||
object.console = "Console"
|
||||
object.atom_analyser = "Analisador atômico"
|
||||
object.fire_extinguisher = "Extintor"
|
||||
@@ -1141,7 +1344,7 @@ object.scanner = "Scanner"
|
||||
object.bin = "Cesto de papéis"
|
||||
object.swing_door1 = "Porta de batente"
|
||||
object.pool_table = "Mesa de bilhar"
|
||||
object.screen = "Tela"
|
||||
object.screen = "Biombo"
|
||||
object.cabinet = "Arquivo"
|
||||
object.sofa = "Sofá"
|
||||
object.projector = "Projetor"
|
||||
@@ -1191,7 +1394,7 @@ object.drinks_machine = "Máq. de bebidas"
|
||||
object.op_sink2 = "Pia"
|
||||
object.table1 = "Mesa"
|
||||
object.entrance_right = "Porta esquerda de entrada"
|
||||
object.operating_table = "Mesa de operaçöes"
|
||||
object.operating_table = "Mesa de cirurgia"
|
||||
object.tv = "Televisäo"
|
||||
transactions.bank_loan = "Empréstimo bancário"
|
||||
transactions.buy_object = "Comprou"
|
||||
@@ -1289,7 +1492,6 @@ staff_descriptions.bad[10] = "Pessoa desleal e rancorosa. Cheia de ódio. "
|
||||
staff_descriptions.bad[11] = "Näo toma cuidado e provoca acidentes. "
|
||||
staff_descriptions.bad[12] = "Näo se importa com o trabalho. Perde tempo. "
|
||||
staff_descriptions.bad[13] = "Pessoa temerária e sem cuidado. "
|
||||
staff_descriptions.bad[14] = "Pessoa ardilosa, matreira e subversiva. "
|
||||
staff_descriptions.bad[15] = "Pessoa arrogante e presunçosa. "
|
||||
staff_descriptions.misc[1] = "Joga golfe. "
|
||||
staff_descriptions.misc[2] = "Pratica mergulho. "
|
||||
@@ -1301,7 +1503,6 @@ staff_descriptions.misc[7] = "Coleciona latas de cerveja. "
|
||||
staff_descriptions.misc[8] = "Gosta de mergulhar no público em shows. "
|
||||
staff_descriptions.misc[9] = "Gosta de fazer surf. "
|
||||
staff_descriptions.misc[10] = "Pratica raffiting. "
|
||||
staff_descriptions.misc[11] = "Destila uísque. "
|
||||
staff_descriptions.misc[12] = "Especialista em 'faça você mesmo'. "
|
||||
staff_descriptions.misc[13] = "Gosta do cinema francês. "
|
||||
staff_descriptions.misc[14] = "Joga muito Theme Park. "
|
||||
@@ -1437,7 +1638,6 @@ level_names[13] = "Vila Amistosa"
|
||||
level_names[14] = "Vila Pancadaria"
|
||||
level_names[15] = "Vila Sepultura"
|
||||
pay_rise.definite_quit = "Faça o que fizer, näo ficarei. Estou farto deste local."
|
||||
pay_rise.regular[1] = "Estou esgotado. Preciso de umas boas férias, mais um aumento de %d, se näo quiser deixo este maldito emprego."
|
||||
pay_rise.regular[2] = "Estou muito cansado. Preciso de umas férias e de um aumento salarial de %d, até um total de %d. E quero já, seu tirano!"
|
||||
pay_rise.regular[3] = "Vamos! Trabalho como um escravo. Se me der um bônus de %d, ficarei no seu hospital."
|
||||
pay_rise.regular[4] = "Estou muito descontente. Exijo um aumento de %d, e um salário final de %d, caso contrário, vou embora."
|
||||
@@ -1448,7 +1648,7 @@ casebook.reputation = "reputaçäo"
|
||||
casebook.earned_money = "dinheiro ganho"
|
||||
casebook.cure_desc.no_cure_known = "Näo há cura conhecida."
|
||||
casebook.cure_desc.hire_doctors = "Você precisa contratar alguns médicos."
|
||||
casebook.cure_desc.build_ward = "Ainda tem que construir uma enfermaria."
|
||||
casebook.cure_desc.build_ward = "Ainda tem que construir uma Enfermaria."
|
||||
casebook.cure_desc.improve_cure = "Melhorar Cura."
|
||||
casebook.cure_desc.build_room = "Sugiro que construa %s"
|
||||
casebook.cure_desc.hire_surgeons = "Você precisa contratar cirurgiöes."
|
||||
@@ -1509,7 +1709,7 @@ diseases.discrete_itching.cause = "Causa - Insetos diminutos com os dentes afiad
|
||||
diseases.discrete_itching.name = "Coceira leve"
|
||||
diseases.discrete_itching.symptoms = "Sintomas - Arranhar-se, o que conduz a um inchaço da parte afetada."
|
||||
diseases.discrete_itching.cure = "Cura - O paciente bebe um xarope farmacêutico para evitar a coceira da pele."
|
||||
diseases.alien_dna.cause = "Causa - Enfrentara gigantes providos de sangue alienígena inteligente."
|
||||
diseases.alien_dna.cause = "Causa - Enfrentar gigantes providos de sangue alienígena inteligente."
|
||||
diseases.alien_dna.name = "DNA alienígena"
|
||||
diseases.alien_dna.symptoms = "Sintomas - Metamorfose alienígena gradual e desejo de destruir nossas cidades."
|
||||
diseases.alien_dna.cure = "Cura - O DNA é mecanicamente removido, limpo de elementos alienígenas e substituídos rapidamente."
|
||||
@@ -1537,8 +1737,8 @@ diseases.sleeping_illness.cure = "Cura - Uma enfermeira administra uma dose elev
|
||||
diseases.pregnancy.cause = "Causa - Cortes de eletricidade em áreas urbanas."
|
||||
diseases.pregnancy.name = "Grávida"
|
||||
diseases.pregnancy.symptoms = "Sintomas - Muita vontade de comer e um mal-estar no estômago."
|
||||
diseases.pregnancy.cure = "Cura - Extrai-se ao bebé na sala de operaçöes, limpa-se e entrega-se ao paciente."
|
||||
diseases.general_practice.name = "Clínica Geral"
|
||||
diseases.pregnancy.cure = "Cura - O bebê é retirado na Sala de Cirurgia, limpo e entregue ao paciente."
|
||||
diseases.general_practice.name = "Diagnóstico Geral"
|
||||
diseases.tv_personalities.cause = "Causa - Ver televisäo durante o dia."
|
||||
diseases.tv_personalities.name = "Personalitis"
|
||||
diseases.tv_personalities.symptoms = "Sintomas - Ter a ilusäo de apresentar na televisäo um programa de cozinha."
|
||||
@@ -1604,7 +1804,7 @@ diseases.golf_stones.cure = "Cura - Dois cirurgiöes operam para extrair os cál
|
||||
diseases.gastric_ejections.cause = "Causa - Comida mexicana ou da India muito condimentada."
|
||||
diseases.gastric_ejections.name = "Vômito"
|
||||
diseases.gastric_ejections.symptoms = "Sintomas - O paciente vomita a comida ao meio digerir em qualquer momento."
|
||||
diseases.gastric_ejections.cure = "Cura - Beber um preparado adstringente especial para parar os vômitos."
|
||||
diseases.gastric_ejections.cure = "Cura - Beber um adstringente especial para parar os vômitos."
|
||||
diseases.unexpected_swelling.cause = "Causa - Algo inesperado."
|
||||
diseases.unexpected_swelling.name = "Inchaço inesperado"
|
||||
diseases.unexpected_swelling.symptoms = "Sintomas - Inchaço."
|
||||
@@ -1631,7 +1831,7 @@ diseases.serious_radiation.cure = "Cura - O Paciente deve ir para a Ducha de Des
|
||||
diseases.iron_lungs.cause = "Causa - A contaminaçäo urbana misturada com restos do Kebab."
|
||||
diseases.iron_lungs.name = "Pulmäo de aço"
|
||||
diseases.iron_lungs.symptoms = "Sintomas - Capacidade para aspirar fogo e gritar debaixo da água."
|
||||
diseases.iron_lungs.cure = "Cura - Dois cirurgiöes realizam uma operaçäo para eliminar as partes duras do pulmäo na sala de operaçöes."
|
||||
diseases.iron_lungs.cure = "Cura - Dois cirurgiöes realizam uma operaçäo para eliminar as partes duras do pulmäo na Sala de Cirurgia."
|
||||
diseases.diag_ultrascan.name = "Diag: Ultra Scanner"
|
||||
diseases.autopsy.name = "Autópsia"
|
||||
dynamic_info.staff.ability = "Habilidade"
|
||||
@@ -1734,7 +1934,7 @@ competitor_names[21] = "JOSHUA"
|
||||
competitor_names[22] = "DANEEL"
|
||||
competitor_names[23] = "OLIVAW"
|
||||
competitor_names[24] = "NIC"
|
||||
staff_class.handyman = "Faz-tudo"
|
||||
staff_class.handyman = "Zelador"
|
||||
staff_class.nurse = "Enfermeira"
|
||||
staff_class.surgeon = "Cirurgiäo"
|
||||
staff_class.receptionist = "Recepcionista"
|
||||
@@ -1755,7 +1955,7 @@ menu_debug.lose_game_anim[5] = " PERDER JOGO 5 ANIM "
|
||||
menu_debug.lose_game_anim[6] = " PERDER JOGO 6 ANIM "
|
||||
menu_debug.lose_game_anim[7] = " PERDER JOGO 7 ANIM "
|
||||
menu_debug.show_help_hotspot = " MOSTRAR AJUDAS "
|
||||
menu_debug.porter_pagers = " PAGINADORES DE FAZ-TUDO "
|
||||
menu_debug.porter_pagers = " PAGINADORES DE ZELADOR "
|
||||
menu_debug.mapwho_checking = " VERIFICAR LOCALIZAÇAO "
|
||||
menu_debug.machine_pagers = " PAGINADORES DE MAQUINA "
|
||||
menu_debug.keep_clear_cells = " CONSERVAR AS CELAS LIMPAS "
|
||||
@@ -1790,10 +1990,10 @@ trophy_room.cleanliness.regional_bad[1] = "O seu hospital é o mais sujo da regi
|
||||
trophy_room.happy_vips.trophies[1] = "Ganhou o Prêmio Nobel de VIP Exemplares. Todos os que visitaram o seu hospital no ano passado o elogiaram muito."
|
||||
trophy_room.happy_vips.trophies[2] = "A Agência de Pessoas Famosas deseja-lhe conceder o Prêmio à Celebridade por ter agradado a todos os VIP que visitaram o seu hospital."
|
||||
trophy_room.happy_vips.trophies[3] = "Ganhou a VIAGEM VIP por melhorar a imagem dos trabalhadores aos olhos de todos os que visitaram o seu hospital. Estupendo!"
|
||||
trophy_room.gen_repairs.awards[1] = "Foi-lhe concedido um prêmio especial pela diligência dos seus faz-tudo na hora de manter as máquinas do seu hospital em bom estado. Muito bem. Tire umas férias."
|
||||
trophy_room.gen_repairs.awards[2] = "Os seus faz-tudo trabalharam melhor que os de qualquer outro hospital. Este é um importante acontecimento de felicidade."
|
||||
trophy_room.gen_repairs.awards[3] = "As suas máquinas estäo em um magnífico estado. A dedicaçäo dos seus faz-tudo foi extraordinária. Merecem este prestigioso prêmio. Um trabalho estupendo!"
|
||||
trophy_room.gen_repairs.penalty[1] = "Os seus faz-tudo näo cuidaram bem das suas máquinas. Deveria fiscalizá-los melhor ou contratar mais para que façam o trabalho melhor."
|
||||
trophy_room.gen_repairs.awards[1] = "Foi-lhe concedido um prêmio especial pela diligência dos seus zeladores na hora de manter as máquinas do seu hospital em bom estado. Muito bem. Tire umas férias."
|
||||
trophy_room.gen_repairs.awards[2] = "Os seus zeladores trabalharam melhor que os de qualquer outro hospital. Este é um importante acontecimento de felicidade."
|
||||
trophy_room.gen_repairs.awards[3] = "As suas máquinas estäo em um magnífico estado. A dedicaçäo dos seus zeladores foi extraordinária. Merecem este prestigioso prêmio. Um trabalho estupendo!"
|
||||
trophy_room.gen_repairs.penalty[1] = "Os seus zeladores näo cuidaram bem das suas máquinas. Deveria fiscalizá-los melhor ou contratar mais para que façam o trabalho melhor."
|
||||
trophy_room.gen_repairs.penalty[2] = "Näo fez uma boa manutençäo. Os seus funcionários deveriam cuidar melhor dos seus equipamentos."
|
||||
trophy_room.many_cured.penalty[1] = "O seu hospital näo cura com eficácia os pacientes que o necessitam. Tenha mais atençäo às curas para que sejam mais eficazes."
|
||||
trophy_room.many_cured.penalty[2] = "O seu hospital é o menos eficaz na hora de curar pacientes. Decepcionou o Ministério e defraudou a si mesmo. Näo diremos mais."
|
||||
@@ -1901,9 +2101,9 @@ rooms_short.jelly_vat = "Banho gelatinoso"
|
||||
rooms_short.staffroom = "Sala de Descanso"
|
||||
rooms_short.hair_restoration = "Pêloterapia"
|
||||
rooms_short.inflation = "Inflatoterapia"
|
||||
rooms_short.operating_theatre = "Sala de Operaçöes"
|
||||
rooms_short.operating_theatre = "Sala de Cirurgia"
|
||||
rooms_short.reception = "Recepçäo"
|
||||
rooms_short.gps_office = "Consultório Geral"
|
||||
rooms_short.gps_office = "Consultório de CG"
|
||||
rooms_short.training_room = "Formaçäo"
|
||||
rooms_short.x_ray = "Raio-X"
|
||||
rooms_short.tongue_clinic = "Laringologia"
|
||||
@@ -1941,7 +2141,7 @@ tooltip.objects.swing_door1 = "52 PORTAS DUPLAS 1"
|
||||
tooltip.objects.pool_table = "Mesa de bilhar: ajuda os seus funcionários a relaxarem."
|
||||
tooltip.objects.screen = "16 TELAS"
|
||||
tooltip.objects.cabinet = "Armário: contém fichas dos pacientes, notas e documentos sobre pesquisa."
|
||||
tooltip.objects.sofa = "Sofá: Os empregados que descansam na sala de descanso sentaräo em um sofá, a menos que tenham uma maneira melhor de relaxar-se."
|
||||
tooltip.objects.sofa = "Sofá: Os funcionários que descansam na Sala de Descanso sentaräo em um sofá, a menos que tenham uma maneira melhor de relaxar-se."
|
||||
tooltip.objects.projector = "37 PROJETORES"
|
||||
tooltip.objects.table2 = "12 MESAS"
|
||||
tooltip.objects.shower = "54 DUCHAS DESCONTAMINADORAS"
|
||||
@@ -2002,7 +2202,7 @@ tooltip.buy_objects_window.decrease = "Comprar menos um objeto"
|
||||
tooltip.buy_objects_window.total_value = "Custo total dos objetos solicitados"
|
||||
tooltip.machine_window.status = "Estado das máquinas."
|
||||
tooltip.machine_window.close = "Cancelar caixa de diálogo"
|
||||
tooltip.machine_window.repair = "Mandar o faz-tudo reparar as máquinas."
|
||||
tooltip.machine_window.repair = "Mandar o zelador reparar as máquinas."
|
||||
tooltip.machine_window.name = "Nome"
|
||||
tooltip.machine_window.times_used = "Número de vezes que reparou as máquinas."
|
||||
tooltip.machine_window.replace = "Substituir máquinas"
|
||||
@@ -2034,7 +2234,7 @@ tooltip.research.improvements_dec = "Reduzir a porcentagem nas melhorias"
|
||||
tooltip.research.drugs_inc = "Aumentar a porcentagem da pesquisa farmacêutica"
|
||||
tooltip.research.allocated_amount = "Quantidade do orçamento alocado"
|
||||
tooltip.statement.close = "Fechar tela do estado das contas"
|
||||
tooltip.rooms.ward = "As enfermarias säo úteis tanto para diagnosticar como para tratamento. Envie aqui os pacientes para observaçäo e para recuperar de uma operaçäo sob o cuidado de uma enfermeira."
|
||||
tooltip.rooms.ward = "As Enfermarias säo úteis tanto para diagnosticar como para tratamento. Envie aqui os pacientes para observaçäo e para recuperar de uma operaçäo sob o cuidado de uma enfermeira."
|
||||
tooltip.rooms.blood_machine = "O médico usa o Transfusiômetro para diagnosticar os pacientes"
|
||||
tooltip.rooms.fracture_clinic = "A enfermeira utiliza a consulta de traumatologia para arrumar fraturas"
|
||||
tooltip.rooms.cardiogram = "O médico usa a cardiologia para diagnosticar os pacientes"
|
||||
@@ -2043,16 +2243,16 @@ tooltip.rooms.jelly_vat = "O médico usa o Banho Gelatinoso para curar a gelatin
|
||||
tooltip.rooms.staffroom = "Os médicos e as enfermeiras descansam na Sala de Descanso"
|
||||
tooltip.rooms.hair_restoration = "O médico usa o Pêlo-restaurador para curar a calvície"
|
||||
tooltip.rooms.inflation = "O médico usa a Inflatoterapia para curar a cabeça inflada"
|
||||
tooltip.rooms.gps_office = "Os pacientes recebem sua primeira consulta na sala de Consultório Geral"
|
||||
tooltip.rooms.training_room = "A sala de formaçäo com um consultor serve para formar outros médicos"
|
||||
tooltip.rooms.gps_office = "Os pacientes recebem seu primeiro atendimento no Consultório de Clínica Geral"
|
||||
tooltip.rooms.training_room = "A Sala de Formaçäo com um consultor serve para formar outros médicos"
|
||||
tooltip.rooms.x_ray = "O médico usa Raio-X para diagnosticar os pacientes"
|
||||
tooltip.rooms.general_diag = "O médico utiliza a sala de Diagnóstico Geral para fazer um diagnóstico básico. É barato e frequentemente eficaz"
|
||||
tooltip.rooms.operating_theatre = "Na sala de operaçöes faltam dois cirurgiöes qualificados"
|
||||
tooltip.rooms.operating_theatre = "Na Sala de Cirurgia faltam dois cirurgiöes qualificados"
|
||||
tooltip.rooms.ultrascan = "O médico usa o Ultra-scanner para diagnosticar os pacientes"
|
||||
tooltip.rooms.psychiatry = "A consulta de psiquiatria cura os pacientes loucos e ajuda a diagnosticar outros pacientes, mas requer um médico qualificado em psiquiatria."
|
||||
tooltip.rooms.toilets = "Construa banheiros para impedir que os pacientes armem uma confusäo no seu hospital!"
|
||||
tooltip.rooms.psychiatry = "A Psiquiatria cura os pacientes loucos e ajuda a diagnosticar outros pacientes, mas requer um médico qualificado em psiquiatria."
|
||||
tooltip.rooms.toilets = "Construa Banheiros para impedir que os pacientes armem uma confusäo no seu hospital!"
|
||||
tooltip.rooms.dna_fixer = "O médico usa o Reparador de DNA para curar os pacientes com DNA alienígena"
|
||||
tooltip.rooms.pharmacy = "Na enfermaria, a enfermeira administra remédios para curar os pacientes"
|
||||
tooltip.rooms.pharmacy = "Na Enfermaria, a enfermeira administra remédios para curar os pacientes"
|
||||
tooltip.rooms.tongue_clinic = "O médico usa a Laringologia para curar a língua comprida"
|
||||
tooltip.rooms.research_room = "Os médicos pesquisadores investigam remédios e máquinas novas no Centro de Pesquisa"
|
||||
tooltip.rooms.scanner = "O médico usa o Scanner para diagnosticar os pacientes"
|
||||
@@ -2088,7 +2288,7 @@ tooltip.staff_list.nurses = "Ver a lista das enfermeiras contratadas neste hospi
|
||||
tooltip.staff_list.skills = "Outras qualificaçöes"
|
||||
tooltip.staff_list.detail = "Cuidar os detalhes"
|
||||
tooltip.staff_list.doctors = "Ver a lista dos médicos contratados neste hospital"
|
||||
tooltip.staff_list.handymen = "Ver a lista dos faz-tudo contratados neste hospital"
|
||||
tooltip.staff_list.handymen = "Ver a lista dos zeladores contratados neste hospital"
|
||||
tooltip.staff_list.researcher = "Pesquisador qualificado"
|
||||
tooltip.staff_list.psychiatrist_train = "Formado um %d%% para ser Psiquiatra"
|
||||
tooltip.place_objects_window.confirm = "Confirmar"
|
||||
@@ -2115,12 +2315,12 @@ tooltip.casebook.cure_type.surgery = "Esta doença requer cirurgia"
|
||||
tooltip.casebook.cure_requirement.hire_staff_old = "Você precisa contratar um %s para este tratamento"
|
||||
tooltip.casebook.cure_requirement.not_possible = "Näo pode administrar este tratamento"
|
||||
tooltip.casebook.cure_requirement.hire_surgeon = "Você precisa contratar um segundo cirurgiäo para que realize operaçöes"
|
||||
tooltip.casebook.cure_requirement.build_ward = "Você precisa construir uma enfermaria para administrar este tratamento"
|
||||
tooltip.casebook.cure_requirement.build_ward = "Você precisa construir uma Enfermaria para administrar este tratamento"
|
||||
tooltip.casebook.cure_requirement.possible = "Pode administrar este tratamento"
|
||||
tooltip.casebook.cure_requirement.build_room = "Você precisa construir uma consulta para dar este tratamento"
|
||||
tooltip.casebook.cure_requirement.hire_surgeons = "Você precisa contratar dois cirurgiöes para as operaçöes"
|
||||
tooltip.casebook.cure_requirement.research_machine = "Precisa inventar alguma máquina para este tratamento."
|
||||
tooltip.casebook.cure_requirement.ward_hire_nurse = "Você precisa de uma enfermeira que trabalhe na enfermaria para administrar este tratamento"
|
||||
tooltip.casebook.cure_requirement.ward_hire_nurse = "Você precisa de uma enfermeira que trabalhe na Enfermaria para administrar este tratamento"
|
||||
tooltip.patient_window.center_view = "Enfocar a pessoa"
|
||||
tooltip.patient_window.warmth = "Quanto calor tem a pessoa"
|
||||
tooltip.patient_window.close = "Cancelar caixa de diálogo"
|
||||
@@ -2203,10 +2403,10 @@ tooltip.jukebox.rewind = "Rebobinar máquina de discos"
|
||||
tooltip.jukebox.current_title = "Máquina de discos"
|
||||
tooltip.jukebox.loop = "Funcionamento contínuo da máquina de discos"
|
||||
tooltip.build_room_window.cost = "Preço da consulta selecionada"
|
||||
tooltip.build_room_window.room_classes.treatment = "Selecione consultas de clínica geral"
|
||||
tooltip.build_room_window.room_classes.facilities = "Selecione consultas especiais"
|
||||
tooltip.build_room_window.room_classes.treatment = "Selecione consultas de tratamentos gerais"
|
||||
tooltip.build_room_window.room_classes.facilities = "Selecione instalaçöes especiais"
|
||||
tooltip.build_room_window.room_classes.diagnosis = "Selecione consultas de diagnóstico"
|
||||
tooltip.build_room_window.room_classes.clinic = "Selecione consultas de especialidade médica"
|
||||
tooltip.build_room_window.room_classes.clinic = "Selecione clínicas especializadas"
|
||||
tooltip.build_room_window.close = "Sair desta caixa de diálogo e voltar para o jogo"
|
||||
tooltip.hire_staff_window.surgeon = "Cirurgiäo"
|
||||
tooltip.hire_staff_window.psychiatrist = "Psiquiatra"
|
||||
@@ -2222,20 +2422,20 @@ tooltip.hire_staff_window.salary = "Salário"
|
||||
tooltip.hire_staff_window.staff_ability = "Qualificaçäo dos funcionários"
|
||||
tooltip.hire_staff_window.doctors = "Ver os médicos que pode contratar"
|
||||
tooltip.hire_staff_window.next_person = "Ver pessoa seguinte"
|
||||
tooltip.hire_staff_window.handymen = "Ver os faz-tudo que pode contratar"
|
||||
tooltip.handyman_window.center_view = "Enfocar o faz-tudo"
|
||||
tooltip.hire_staff_window.handymen = "Ver os zeladores que pode contratar"
|
||||
tooltip.handyman_window.center_view = "Enfocar o zelador"
|
||||
tooltip.handyman_window.close = "Cancelar caixa de diálogo"
|
||||
tooltip.handyman_window.sack = "Despedir"
|
||||
tooltip.handyman_window.name = "Nome do faz-tudo"
|
||||
tooltip.handyman_window.name = "Nome do zelador"
|
||||
tooltip.handyman_window.pick_up = "Apanhar"
|
||||
tooltip.handyman_window.prio_litter = "Aumentar a prioridade do faz-tudo para a limpeza"
|
||||
tooltip.handyman_window.prio_litter = "Aumentar a prioridade do zelador para a limpeza"
|
||||
tooltip.handyman_window.ability = "Qualificaçäo"
|
||||
tooltip.handyman_window.prio_machines = "Aumentar a prioridade do faz-tudo para reparar as máquinas"
|
||||
tooltip.handyman_window.prio_machines = "Aumentar a prioridade do zelador para reparar as máquinas"
|
||||
tooltip.handyman_window.salary = "Salário"
|
||||
tooltip.handyman_window.face = "Face do faz-tudo"
|
||||
tooltip.handyman_window.face = "Face do zelador"
|
||||
tooltip.handyman_window.happiness = "Satisfaçäo"
|
||||
tooltip.handyman_window.tiredness = "Cansaço"
|
||||
tooltip.handyman_window.prio_plants = "Aumentar a prioridade do faz-tudo para regar as plantas"
|
||||
tooltip.handyman_window.prio_plants = "Aumentar a prioridade do zelador para regar as plantas"
|
||||
tooltip.window_general.cancel = "Cancelar"
|
||||
tooltip.window_general.confirm = "Confirmar"
|
||||
adviser.earthquake.ended = "Nossa! Acreditei que ia ser o pior de todos! Alcançou um %d na Escala Richter."
|
||||
@@ -2245,7 +2445,7 @@ adviser.staff_place_advice.only_psychiatrists = "Os Médicos só podem trabalhar
|
||||
adviser.staff_place_advice.doctors_cannot_work_in_room = "Os Médicos näo podem trabalhar em %s"
|
||||
adviser.staff_place_advice.only_researchers = "Os Médicos só podem trabalhar em um Centro de Pesquisa se estiverem qualificados para isso."
|
||||
adviser.staff_place_advice.nurses_cannot_work_in_room = "As Enfermeiras näo podem trabalhar em %s"
|
||||
adviser.staff_place_advice.only_surgeons = "Os Médicos só podem trabalhar em uma sala de operaçöes se estiverem qualificados para isso."
|
||||
adviser.staff_place_advice.only_surgeons = "Os Médicos só podem trabalhar em uma Sala de Cirurgia se estiverem qualificados para isso."
|
||||
adviser.staff_place_advice.receptionists_only_at_desk = "As Recepcionistas só podem trabalhar na Recepçäo."
|
||||
adviser.staff_place_advice.only_doctors_in_room = "Apenas Médicos podem trabalhar em %s"
|
||||
adviser.staff_place_advice.only_nurses_in_room = "Só Enfermeiras podem trabalhar na %s"
|
||||
@@ -2256,7 +2456,7 @@ adviser.epidemic.hurry_up = "Se näo acabar em seguida com esta epidemia, terá
|
||||
adviser.epidemic.multiple_epidemies = "Parece que tem mais de uma epidemia de uma vez. Isto poderia ser desastroso, sendo assim faz algo rapidamente."
|
||||
adviser.epidemic.serious_warning = "Esta doença contagiosa começa a ser grave. Tem que fazer algo brevemente!"
|
||||
adviser.warnings.patients_unhappy = "Os pacientes näo gostam do seu hospital. Deveria fazer algo para melhorá-lo."
|
||||
adviser.warnings.too_much_litter = "Há um problema de limpeza. Mais faz-tudo é a soluçäo."
|
||||
adviser.warnings.too_much_litter = "Há um problema de limpeza. Mais zeladores é a soluçäo."
|
||||
adviser.warnings.patients_very_thirsty = "Os pacientes têm muita sede. Se näo colocar logo algumas máquinas de bebidas, as pessoas iräo embora do seu hospital para tomar algum refresco."
|
||||
adviser.warnings.queue_too_long_at_reception = "Tem muitos pacientes à espera de reservas para as consultas na recepçäo. Coloque outra Recepçäo e contrate outra Recepcionista."
|
||||
adviser.warnings.patients_thirsty = "As pessoas começam a ter sede. Talvez deveria colocar máquinas de bebidas."
|
||||
@@ -2267,10 +2467,10 @@ adviser.warnings.machines_falling_apart = "Suas máquinas estäo caindo aos peda
|
||||
adviser.warnings.financial_trouble3 = "O seu saldo tem um aspecto preocupante. Faça algo de efetivo. Está a %d do desastre."
|
||||
adviser.warnings.nurses_tired2 = "As suas enfermeiras estäo muito cansadas. Faça descansá-las agora mesmo."
|
||||
adviser.warnings.people_have_to_stand = "Há pacientes de pé. Faça-os sentar já!"
|
||||
adviser.warnings.handymen_tired = "Os seus faz-tudo estäo muito cansados. Mande-os descansar agora mesmo."
|
||||
adviser.warnings.change_priorities_to_plants = "Tem que alterar as prioridades dos seus faz-tudo para que empreguem mais tempo regando as suas plantas."
|
||||
adviser.warnings.handymen_tired = "Os seus zeladores estäo muito cansados. Mande-os descansar agora mesmo."
|
||||
adviser.warnings.change_priorities_to_plants = "Tem que alterar as prioridades dos seus zeladores para que empreguem mais tempo regando as suas plantas."
|
||||
adviser.warnings.staff_tired = "Os seus funcionários estäo incrivelmente cansados. Se näo os deixa descansar um momento em uma Sala de Descanso, alguns poderäo cair de esgotamento."
|
||||
adviser.warnings.some_litter = "Os faz-tudo podem recolher tudo este lixo antes de que se converta em um grave problema."
|
||||
adviser.warnings.some_litter = "Os zeladores podem recolher todo este lixo antes de que se converta em um grave problema."
|
||||
adviser.warnings.cash_low_consider_loan = "As suas finanças andam mal. Já pensou em um empréstimo?"
|
||||
adviser.warnings.reduce_staff_rest_threshold = "Tente alterar o Tempo de Descanso dos funcionários no tela de Normas para que possam descansar mais frequentemente. É só uma sugestäo."
|
||||
adviser.warnings.build_staffroom = "Construa uma Sala de Descanso o mais rápido possível. Os seus funcionários trabalham muito e estäo à beira do colapso. Vamos, seja razoável!"
|
||||
@@ -2294,8 +2494,8 @@ adviser.warnings.money_very_low_take_loan = "O seu saldo bancário é muito baix
|
||||
adviser.warnings.finanical_trouble2 = "Consiga algum crédito ou estará acabado. Perderá o nível se perder outros %d."
|
||||
adviser.warnings.patients_very_cold = "Os pacientes têm muito frio. Suba o aquecimento ou coloque mais radiadores no seu hospital."
|
||||
adviser.warnings.deal_with_epidemic_now = "Se näo acabar em seguida com esta epidemia, terá muitos problemas. Despacha-se!"
|
||||
adviser.warnings.litter_catastrophy = "O problema da falta de limpeza é grave. Coloque vários faz-tudo para trabalhar agora mesmo!"
|
||||
adviser.warnings.litter_everywhere = "Há sujeira por toda parte. Coloque mais faz-tudo para trabalhar."
|
||||
adviser.warnings.litter_catastrophy = "O problema da falta de limpeza é grave. Coloque vários zeladores para trabalhar agora mesmo!"
|
||||
adviser.warnings.litter_everywhere = "Há sujeira por toda parte. Coloque mais zeladores para trabalhar."
|
||||
adviser.warnings.machinery_slightly_damaged = "A maquinaria do seu hospital está um pouco danificada. Näo se esqueça de as reparar."
|
||||
adviser.warnings.patients_getting_hot = "Os pacientes têm muito calor. Baixe o aquecimento ou retire alguns radiadores."
|
||||
adviser.warnings.no_patients_last_month = "No último mês, näo vieram novos pacientes ao seu hospital. Horrível!"
|
||||
@@ -2319,27 +2519,27 @@ adviser.warnings.more_benches = "Poderia colocar mais bancos. Os doentes protest
|
||||
adviser.warnings.bankruptcy_imminent = "Ei! Vai ficar sem máquinas. Tome cuidado!"
|
||||
adviser.warnings.need_toilets = "Os pacientes precisam de banheiros. Coloque-os em um lugar acessível."
|
||||
adviser.warnings.more_toilets = "Você precisa de mais banheiros. As pessoas näo aguentam mais."
|
||||
adviser.warnings.plants_dying = "As suas plantas estäo secando. Precisam de água. Consiga mais faz-tudo para que cuidem disso. Os pacientes näo gostam das plantas mortas."
|
||||
adviser.warnings.plants_dying = "As suas plantas estäo secando. Precisam de água. Consiga mais zeladores para que cuidem disso. Os pacientes näo gostam das plantas mortas."
|
||||
adviser.warnings.people_did_it_on_the_floor = "Alguns dos seus pacientes näo podem aguentar mais. Alguém vai ter que limpar sem descanso."
|
||||
adviser.warnings.need_staffroom = "Construa uma sala de descanso para que os seus empregados possam descansar."
|
||||
adviser.warnings.need_staffroom = "Construa uma Sala de Descanso para que os seus empregados possam descansar."
|
||||
adviser.warnings.plants_thirsty = "Precisa cuidar das suas plantas. Estäo secando."
|
||||
adviser.warnings.too_many_plants = "Tem muitas plantas. Isto parece uma selva."
|
||||
adviser.warnings.receptionists_tired2 = "As suas recepcionistas estäo esgotadas. Deixa que descansem agora mesmo."
|
||||
adviser.warnings.machine_severely_damaged = "%s está prestes a se quebrar."
|
||||
adviser.warnings.machinery_very_damaged = "É uma emergência! Faça com que que um faz-tudo repare as sas máquinas em seguida. Estäo a ponto de explodir!"
|
||||
adviser.warnings.machinery_very_damaged = "É uma emergência! Faça com que um zelador repare as suas máquinas em seguida. Estäo a ponto de explodir!"
|
||||
adviser.warnings.hospital_is_rubbish = "As pessoas estäo dizendo abertamente que seu hospital é lixo. Já sabe que logo iräo se queixar em outro lugar."
|
||||
adviser.warnings.handymen_tired2 = "Os seus faz-tudo estäo cansados. Mande-os descansar imediatamente."
|
||||
adviser.warnings.machinery_damaged2 = "Precisa contratar um faz-tudo para reparar as suas máquinas rapidamente."
|
||||
adviser.warnings.handymen_tired2 = "Os seus zeladores estäo cansados. Mande-os descansar imediatamente."
|
||||
adviser.warnings.machinery_damaged2 = "Precisa contratar um zelador para reparar as suas máquinas rapidamente."
|
||||
adviser.warnings.staff_very_cold = "O pessoal reclama do frio. Suba o aquecimento ou coloque mais radiadores."
|
||||
adviser.warnings.desperate_need_for_watering = "Necessita desesperadamente contratar um faz-tudo para que cuide das suas plantas."
|
||||
adviser.warnings.desperate_need_for_watering = "Necessita desesperadamente contratar um zelador para que cuide das suas plantas."
|
||||
adviser.warnings.staff_unhappy2 = "Os seus funcionários, no geral, estäo descontentes. Logo, pediräo mais dinheiro."
|
||||
adviser.staff_advice.too_many_nurses = "Está contratando muitas enfermeiras."
|
||||
adviser.staff_advice.need_handyman_litter = "Os pacientes estäo sujando o seu hospital. Contrate uma faz-tudo para se encarregar da limpeza."
|
||||
adviser.staff_advice.need_nurses = "Contrate mais enfermeiras. Na enfermaria e na farmácia faltam enfermeiras."
|
||||
adviser.staff_advice.need_handyman_litter = "Os pacientes estäo sujando o seu hospital. Contrate um zelador para se encarregar da limpeza."
|
||||
adviser.staff_advice.need_nurses = "Contrate mais enfermeiras. Na Enfermaria e na farmácia faltam enfermeiras."
|
||||
adviser.staff_advice.need_doctors = "Você precisa de mais médicos. Tente colocar os seus melhores médicos nas consultas com mais pacientes."
|
||||
adviser.staff_advice.too_many_doctors = "Tem muitos médicos. Alguns estäo desocupados neste momento."
|
||||
adviser.staff_advice.need_handyman_machines = "Terá que contratar um faz-tudo se quiser que as máquinas do seu hospital funcionem."
|
||||
adviser.staff_advice.need_handyman_plants = "Contrate um faz-tudo para regar as plantas."
|
||||
adviser.staff_advice.need_handyman_machines = "Terá que contratar um zelador se quiser que as máquinas do seu hospital funcionem."
|
||||
adviser.staff_advice.need_handyman_plants = "Contrate um zelador para regar as plantas."
|
||||
adviser.praise.few_have_to_stand = "Quase ninguém fica de pé no seu hospital. Os seus pacientes estäo contentes."
|
||||
adviser.praise.patients_cured = "%d pacientes curados."
|
||||
adviser.praise.plants_are_well = "Muito bem. Está cuidando bem das suas plantas. Estupendo."
|
||||
@@ -2347,8 +2547,8 @@ adviser.praise.plenty_of_benches = "Há muitos assentos, assim näo há problema
|
||||
adviser.praise.plants_thriving = "Muito bem. As suas plantas estäo muito viçosas. Têm um aspecto maravilhoso. Mantenha-as assim e poderá ganhar um prêmio por isto."
|
||||
adviser.praise.many_benches = "Agora os seus pacientes têm suficientes assentos. Muito bem!"
|
||||
adviser.praise.many_plants = "Fantástico! Tem muitas plantas. Os seus pacientes agradeceräo isso."
|
||||
adviser.surgery_requirements.need_surgeons_ward_op = "Precisa contratar dois cirurgiöes e construir uma enfermaria e uma sala de operaçöes para realizar operaçöes."
|
||||
adviser.surgery_requirements.need_surgeon_ward = "Precisa contratar um outro cirurgiäo e construir uma enfermaria para poder realizar operaçöes."
|
||||
adviser.surgery_requirements.need_surgeons_ward_op = "Precisa contratar dois cirurgiöes e construir uma Enfermaria e uma Sala de Cirurgia para realizar operaçöes."
|
||||
adviser.surgery_requirements.need_surgeon_ward = "Precisa contratar um outro cirurgiäo e construir uma Enfermaria para poder realizar operaçöes."
|
||||
adviser.multiplayer.objective_completed = "Completou o objetivo. Felicidades!"
|
||||
adviser.multiplayer.objective_failed = "Näo conseguiu completar o objetivo."
|
||||
adviser.multiplayer.everyone_failed = "Todos falharam ao satisfazer aquele último objetivo."
|
||||
@@ -2364,7 +2564,7 @@ adviser.research.new_available = "Já pode utilizar um novo %s."
|
||||
adviser.research.machine_improved = "O Centro de Pesquisa trouxe melhorias para %s."
|
||||
adviser.research.autopsy_discovered_rep_loss = "Foi descoberta uma máquina de autópsias. Aguarde uma reaçäo desfavorável das pessoas."
|
||||
adviser.information.emergency = "Há uma emergência! Mexa-se! Mexa-se! Mexa-se!"
|
||||
adviser.information.handyman_adjust = "Pode conseguir que o faz-tudo limpe melhor se estabelecer as suas prioridades."
|
||||
adviser.information.handyman_adjust = "Pode conseguir com que o zelador limpe melhor se estabelecer as suas prioridades."
|
||||
adviser.information.promotion_to_specialist = "Um dos seus Médicos foi promovido para %s."
|
||||
adviser.information.pay_rise = "Um funcionário ameaça se demitir. Pode atender a sua petiçäo ou despedi-lo. Clique no último ícone da esquerda para ver quem deseja demitir."
|
||||
adviser.information.first_death = "Acabou de matar o seu primeiro paciente. Como se sente?"
|
||||
@@ -2380,11 +2580,11 @@ adviser.information.patient_leaving_too_expensive = "Um paciente está indo embo
|
||||
adviser.information.place_windows = "Se colocar janelas, as salas teräo mais luz e os seus empregados estaräo mais contentes."
|
||||
adviser.information.initial_general_advice.first_patients_thirsty = "No seu hospital as pessoas têm sede. Coloque máquinas de bebidas."
|
||||
adviser.information.initial_general_advice.epidemic_spreading = "Há uma doença contagiosa no seu hospital. Tente curar as pessoas infectadas antes que elas possam ir embora."
|
||||
adviser.information.initial_general_advice.research_now_available = "Construiu o seu primeiro centro de pesquisa. Agora pode acessar a tela de pesquisa."
|
||||
adviser.information.initial_general_advice.research_now_available = "Construiu o seu primeiro centro de pesquisa. Agora você pode acessar a tela de pesquisa."
|
||||
adviser.information.initial_general_advice.autopsy_available = "Foi inventada uma máquina de autópsias. Com ela, poderá se livrar dos pacientes problemáticos e investigar os seus restos. Tome cuidado, o uso desta máquina suscita muita polêmica."
|
||||
adviser.information.initial_general_advice.rats_have_arrived = "Os ratos invadiram o seu hospital. Tente eliminá-los com o mouse."
|
||||
adviser.information.initial_general_advice.surgeon_symbol = "Os médicos especializados em cirurgia levam o símbolo: {"
|
||||
adviser.information.initial_general_advice.machine_needs_repair = "Há uma máquina que precisa ser reparada. Encontre a máquina e aperte sobre ela. Em seguida, aperte no botäo do faz-tudo."
|
||||
adviser.information.initial_general_advice.machine_needs_repair = "Há uma máquina que precisa ser reparada. Encontre a máquina e aperte sobre ela. Em seguida, aperte no botäo do zelador."
|
||||
adviser.information.initial_general_advice.research_symbol = "Os médicos pesquisadores levam o símbolo: }"
|
||||
adviser.information.initial_general_advice.decrease_heating = "As pessoas têm muito calor no seu hospital. Baixe o aquecimento. Isto é feito na tela de mapa da cidade."
|
||||
adviser.information.initial_general_advice.taking_your_staff = "Alguém está subornando a sua equipe. Terá que discutir com eles para que fiquem."
|
||||
@@ -2419,7 +2619,7 @@ adviser.level_progress.cured_enough_patients = "Curou muitos pacientes, mas prec
|
||||
adviser.level_progress.financial_criteria_met = "Tem satisfeito o critério financeiro deste nível. Agora mantenha o seu saldo acima de %d, enquanto assegura de que o hospital funcione eficazmente."
|
||||
adviser.level_progress.halfway_lost = "Falta 50%% para perder este nível."
|
||||
adviser.level_progress.another_patient_killed = "Oh, näo! Matou outro paciente. Agora há um total de %d mortes."
|
||||
adviser.vomit_wave.started = "Parece que tem um vírus de vômitos no seu hospital. Isto näo teria acontecido se o tivesse mantido limpo. Talvez devesse contratar um faz-tudo."
|
||||
adviser.vomit_wave.started = "Parece que tem um vírus de vômitos no seu hospital. Isto näo teria acontecido se o tivesse mantido limpo. Talvez devesse contratar um zelador."
|
||||
adviser.vomit_wave.ended = "Ufa! Parece que o vírus que causou essa epidemia de vômitos está controlado. No futuro, mantenha o seu hospital limpo."
|
||||
adviser.placement_info.staff_cannot_place = "Näo pode colocar este funcionário aqui. Desculpe."
|
||||
adviser.placement_info.room_cannot_place_2 = "Näo pode colocar a consulta aqui."
|
||||
@@ -2472,30 +2672,23 @@ adviser.tutorial.select_diagnosis_rooms = "Clique com o botäo esquerdo no ícon
|
||||
adviser.tutorial.reception_invalid_position = "A Recepçäo ficou cinzenta porque näo é possível colocar a¡. Mover ou girá-la."
|
||||
adviser.tutorial.build_pharmacy = "Parabéns! Agora, construa uma farmácia e contrate uma enfermeira para fazer o seu hospital funcionar."
|
||||
adviser.room_requirements.pharmacy_need_nurse = "Contrate uma enfermeira para a Farmácia."
|
||||
adviser.room_requirements.op_need_two_surgeons = "Contrate dois cirurgiöes para que operem na sala de operaçöes."
|
||||
adviser.room_requirements.training_room_need_consultant = "Terá que contratar um especialista para que de conferências nesta sala de formaçäo."
|
||||
adviser.room_requirements.op_need_two_surgeons = "Contrate dois cirurgiöes para que operem na Sala de Cirurgia."
|
||||
adviser.room_requirements.training_room_need_consultant = "Terá que contratar um especialista para que de conferências nesta Sala de Formaçäo."
|
||||
adviser.room_requirements.research_room_need_researcher = "Terá que contratar um médico pesquisador para que utilize o centro de pesquisa."
|
||||
adviser.room_requirements.op_need_ward = "Precisa construir uma enfermaria para os pacientes que väo ser operados."
|
||||
adviser.room_requirements.op_need_ward = "Precisa construir uma Enfermaria para os pacientes que väo ser operados."
|
||||
adviser.room_requirements.reception_need_receptionist = "Precisa contratar uma recepcionista para atender os seus pacientes."
|
||||
adviser.room_requirements.op_need_another_surgeon = "Precisa contratar um outro cirurgiäo para poder usar o sala de operaçöes."
|
||||
adviser.room_requirements.gps_office_need_doctor = "Contrate um médico para atender no consultório."
|
||||
adviser.room_requirements.ward_need_nurse = "Contrate uma enfermeira para que trabalhe na enfermaria."
|
||||
adviser.room_requirements.op_need_another_surgeon = "Precisa contratar um outro cirurgiäo para poder usar a Sala de Cirurgia."
|
||||
adviser.room_requirements.gps_office_need_doctor = "Contrate um médico para atender no Consultório de Clínica Geral."
|
||||
adviser.room_requirements.ward_need_nurse = "Contrate uma enfermeira para que trabalhe na Enfermaria."
|
||||
adviser.room_requirements.psychiatry_need_psychiatrist = "Agora que construiu uma sala de psiquiatria, precisará de um psiquiatra."
|
||||
introduction_texts.level15 = "Bem, estes säo os mecanismos básicos para pôr em funcionamento um hospital.//Os seus Médicos väo precisar de toda a ajuda que possam obter para diagnosticar alguns dos pacientes. Pode ajudá-los construindo outros equipamentos de diagnóstico como a sala de Diagnóstico Geral."
|
||||
introduction_texts.level6 = "Utilize toda a sua capacidade para conseguir um hospital que funcione bem e consiga curar muitos pacientes e que possa tratar qualquer caso que pressentem os doentes.//Está avisado de que o ambiente, aqui, é especialmente propenso a germes e infecçöes. A menos que mantenha uma escrupulosa limpeza na sua instituiçäo, terá que fazer frente a uma série de epidemias entre os pacientes. Procure obter um lucro de $20.000 e fazer o valor do seu hospital superar os $140.000. "
|
||||
introduction_texts.level3 = "Desta vez colocará o seu hospital em uma área rica.//O Ministério da Saúde espera que consiga curar muitos pacientes. Terá que ganhar uma boa reputaçäo para começar, mas uma vez que o hospital comece a funcionar, concentre-se em ganhar todo o dinheiro que puder. Também pode haver emergências. Produzem-se quando chega muita gente que sofre da mesma doença. Se os curar dentro de um prazo determinado, conseguirá aumentar a sua reputaçäo e ganhar um grande extra. Haverá doenças, como o complexo de rei, e deverá ter orçamento para construir uma sala de operaçöes e junto a ela, uma enfermaria. Tem que ganhar $20.000 para superar este nível."
|
||||
introduction_texts.level12 = "Agora enfrentará o maior dos desafios. Impressionado com os seus lucros, o Ministério tem uma grande tarefa para você; querem que construa outro magnífico hospital, que tenha um excelente lucro e uma reputaçäo incrível. Também querem que compre todo o terreno que puder, cure tudo (e queremos dizer todas as doenças) e ganhe todos os prêmios. Acha que conseguirá? Ganhe $650.000, cure 750 pessoas e consiga uma reputaçäo de 800 para ganhar este nível. "
|
||||
introduction_texts.level9 = "Depois de depositar o dinheiro na conta bancária do Ministério e pagar uma nova limousine para o Ministro, agora pode dedicar a criar um bom hospital para cuidar dos doentes e necessitados. Aqui terá um montäo de problemas diferentes. Se os seus funcionários tiverem uma boa formaçäo e suficientes consultas, poderäo resolver qualquer situaçäo. O seu hospital terá que valer $200.000 e precisará ter $400.000 no banco. Se näo o conseguir näo poderá terminar o nível."
|
||||
introduction_texts.level11 = "Tem a oportunidade de construir o hospital definitivo. Esta é uma área de enorme prestígio e o Ministério quer que este seja o melhor hospital. Esperamos que ganhe muito dinheiro, alcance uma excelente reputaçäo e que se encarregue de todos os casos que sejam apresentados. Este é um trabalho importante. Terá que ser muito hábil para completá-lo. Também deve ter em conta que foram vistos OVNIs na área. Assegure-se de que os seus funcionários estejam preparados para receber algumas visitas inesperadas. O seu hospital terá que alcançar um valor de $240.000, precisará ter $500.000 no banco e uma reputaçäo de 700."
|
||||
introduction_texts.level3 = "Desta vez colocará o seu hospital em uma área rica.//O Ministério da Saúde espera que consiga curar muitos pacientes. Terá que ganhar uma boa reputaçäo para começar, mas uma vez que o hospital comece a funcionar, concentre-se em ganhar todo o dinheiro que puder. Também pode haver emergências. Produzem-se quando chega muita gente que sofre da mesma doença. Se os curar dentro de um prazo determinado, conseguirá aumentar a sua reputaçäo e ganhar um grande extra. Haverá doenças, como o complexo de rei, e deverá ter orçamento para construir uma Sala de Cirurgia e junto a ela, uma Enfermaria. Tem que ganhar $20.000 para superar este nível."
|
||||
introduction_texts.level14 = "Ainda tem mais um desafio: um hospital surpresa totalmente imprevisível. Se conseguir ter êxito, será o vencedor dos vencedores. E näo espere que seja fácil, porque é a tarefa mais difícil que confrontará. Boa sorte!"
|
||||
introduction_texts.level10 = "Além de dever curar todas as doenças que possa haver, o Ministério pede que empregue um pouco de tempo em aumentar a eficácia dos seus remédios.//Houve algumas queixas por parte do D. Salutíssimo, o Cachorro Guardiäo da Saúde, assim deve procurar com que todos os seus remédios sejam extremamente eficazes para ficar bem. Também, assegure-se de que o seu hospital tenha uma reputaçäo irrepreensível. Procure deixar morrer poucos pacientes. Como sugestäo, deveria deixar espaço para um banho gelatinoso. Para ganhar, os seus remédios deveräo ter uma eficácia de, pelo menos, 80%, tem que conseguir uma reputaçäo de 650 e guardar $500.000 no banco."
|
||||
introduction_texts.level5 = "Este será um hospital concorrido, que tratará casos muito variados.//Os seus médicos acabam de sair da faculdade, por isso é fundamental que construa uma sala de formaçäo para que alcancem o nível de formaçäo necessário. Só tem três especialistas para ensinar os seus funcionários inexperientes, entäo faça com que estejam contentes. Tem que ter em conta que o hospital está localizado em cima da falha geológica de San Android. Sempre há risco de terremoto. Os terremotos provocaräo danos importantes nas suas máquinas e alteraräo o bom funcionamento do seu hospital. Aumente a sua reputaçäo até 400 e consiga ganhos de $50.000 para triunfar. Também, cure 200 pacientes. "
|
||||
introduction_texts.level1 = "Bem-vindo ao seu primeiro hospital!//Para fazê-lo funcionar, coloque uma Recepçäo, construa um Consultório e contrate uma recepcionista e um médico. Em seguida, espere que cheguem os pacientes. Seria uma boa ideia construir uma consulta de psiquiatria e contratar um psiquiatra. Uma farmácia e uma enfermeira säo fundamentais para curar os seus pacientes. Cuidado com os casos malignos de cabeça inflada; eles säo solucionados na sala de inflatoterapia. Terá que curar 10 pessoas e assegurar de que a sua reputaçäo näo seja inferior a 200."
|
||||
introduction_texts.level17 = "Um último aviso. Fique de olho na sua Reputaçäo, é o que atrairá pacientes ao seu estabelecimento. Se näo matar muitas pessoas e os mantiver razoavelmente felizes näo deverá ter muitos problemas com este nível!//Agora é com você, boa sorte."
|
||||
introduction_texts.level5 = "Este será um hospital concorrido, que tratará casos muito variados.//Os seus médicos acabam de sair da faculdade, por isso é fundamental que construa uma Sala de Formaçäo para que alcancem o nível de formaçäo necessário. Só tem três especialistas para ensinar os seus funcionários inexperientes, entäo faça com que estejam contentes. Tem que ter em conta que o hospital está localizado em cima da falha geológica de San Android. Sempre há risco de terremoto. Os terremotos provocaräo danos importantes nas suas máquinas e alteraräo o bom funcionamento do seu hospital. Aumente a sua reputaçäo até 400 e consiga ganhos de $50.000 para triunfar. Também, cure 200 pacientes. "
|
||||
introduction_texts.level1 = "Bem-vindo ao seu primeiro hospital!//Para fazê-lo funcionar, coloque uma Recepçäo, construa um Consultório de Clínica Geral e contrate uma recepcionista e um médico. Em seguida, espere que cheguem os pacientes. Seria uma boa ideia construir uma Psiquiatria e contratar um psiquiatra. Uma Farmácia e uma enfermeira säo fundamentais para curar os seus pacientes. Cuidado com os casos malignos de cabeça inflada; eles säo solucionados na Sala de Inflatoterapia. Terá que curar 10 pessoas e assegurar de que a sua reputaçäo näo seja inferior a 200."
|
||||
introduction_texts.level7 = "Aqui, estará sob a estrita vigilância do Ministério da Saúde, entäo faça com que suas contas reflitam excelentes lucros e aumente a sua reputaçäo.//Näo podemos permitir que haja mortes desnecessárias; Näo beneficiam nada o negócio. Certifique-se de que os seus funcionários estejam em plena forma e de ter todos os equipamentos necessários. Obtenha uma reputaçäo de 600, e um saldo bancário de $200.000."
|
||||
introduction_texts.level4 = "Mantenha seus pacientes felizes e trate-os com a maior eficácia possível, reduzindo ao máximo o número de óbitos.//A sua reputaçäo está em jogo, portanto procure aumentá-la o máximo que puder. Näo se preocupe muito com dinheiro, pois você o ganhará mais rápido à medida em que sua reputaçäo cresce. A partir de agora, você poderá formar os seus médicos ampliando seus conhecimentos, permitindo-os curar os pacientes com enfermidades mais difíceis. Alcance uma reputaçäo acima de 500."
|
||||
introduction_texts.level18 = ""
|
||||
introduction_texts.level16 = "Uma vez que tenha diagnosticado algum dos pacientes, precisará construir salas de tratamento e clínicas para curá-los. Pode começar com uma Farmácia, onde precisará de uma Enfermeira que distribua os remédios."
|
||||
introduction_texts.level13 = "A sua incrível habilidade como diretor do hospital atraiu a atençäo da Divisäo Secreta Especial do Serviço Secreto Especial. Tenho um trabalho especial para você. Há um hospital infestado de ratos que precisa de um exterminador eficiente. Você deve matar todos os ratos que puder antes de que o pessoal de Manutençäo limpe toda a sujeira. Acha que é apto para esta missäo?"
|
||||
introduction_texts.level8 = "Só depende de você construir o hospital mais rentável e eficiente possível.//As pessoas por aqui, säo bastante ricas, entäo tente arrecadar o máximo possível. Lembre-se que curar as pessoas é uma coisa muito bonita, mas o que PRECISAMOS de verdade é do dinheiro delas. Arranque todo o dinheiro destes doentes. Acumule a enorme quantia de $300.000 para completar este nível. "
|
||||
humanoid_name_starts[1] = "GOLD"
|
||||
@@ -2587,23 +2780,23 @@ insurance_companies[11] = "Seguros Sindicato"
|
||||
insurance_companies.out_of_business = "FECHADO"
|
||||
room_descriptions.ward[1] = "Enfermaria//"
|
||||
room_descriptions.ward[2] = "Os pacientes ficam aqui para serem atendidos por uma enfermeira enquanto säo diagnosticados. Permanecem aqui antes de serem operados.//"
|
||||
room_descriptions.ward[3] = "A enfermaria requer uma enfermeira. "
|
||||
room_descriptions.ward[3] = "A Enfermaria requer uma enfermeira. "
|
||||
room_descriptions.blood_machine[1] = "Sala de Transfusöes//"
|
||||
room_descriptions.blood_machine[2] = "O transfusiômetro é um elemento do equipamento de diagnóstico que revisa as células do sangue do paciente para descobrir do que sofrem.//"
|
||||
room_descriptions.blood_machine[3] = "A sala de transfusöes requer um médico. Também precisa de manutençäo. "
|
||||
room_descriptions.fracture_clinic[1] = "Traumatologia//"
|
||||
room_descriptions.fracture_clinic[2] = "Os pacientes que têm a desgraça de ter fraturas vêm aqui. O removedor de gesso usa poderosos lasers industriais para cortar os gessos mais duros, causando ao paciente só uma pequena dor.//"
|
||||
room_descriptions.fracture_clinic[3] = "A sala de traumatologia requer uma enfermeira. Também precisa de uma manutençäo muito frequente. "
|
||||
room_descriptions.cardiogram[1] = "Sala de Cardiologia//"
|
||||
room_descriptions.cardiogram[2] = "Aqui é diagnosticado e examinado os pacientes antes que voltem para a consulta, onde porá o tratamento.//"
|
||||
room_descriptions.cardiogram[3] = "A sala de cardiologia requer um médico. Também precisa de manutençäo. "
|
||||
room_descriptions.cardiogram[1] = "Cardiologia//"
|
||||
room_descriptions.cardiogram[2] = "Os pacientes säo diagnosticados aqui, antes de retornarem para o Consultório de Clínica Geral para conseguir um tratamento.//"
|
||||
room_descriptions.cardiogram[3] = "A Cardiologia requer um médico. Também precisa de manutençäo. "
|
||||
room_descriptions.decontamination[1] = "Descontaminaçäo//"
|
||||
room_descriptions.decontamination[2] = "Os pacientes que estiveram expostos à radiaçäo säo enviados rapidamente à consulta de descontaminaçäo. Esta consulta dispöe de uma ducha que os purifica de toda a horrível radioatividade e sujeira.//"
|
||||
room_descriptions.decontamination[3] = "A ducha descontaminadora requer um médico. Também precisa de um faz-tudo que se ocupe da sua manutençäo. "
|
||||
room_descriptions.decontamination[3] = "A ducha descontaminadora requer um médico. Também precisa de um zelador que se ocupe da sua manutençäo. "
|
||||
room_descriptions.jelly_vat[1] = "Banho Gelatinoso//"
|
||||
room_descriptions.jelly_vat[2] = "Os pacientes que sofrem da risível doença da gelatinitis devem ir a cambalear-se para a consulta de gelatinitis e ser inundados no banheiro gelatinoso. Isto faz com que se curem de um modo que näo resulta de tudo compreensível para a profissäo médica.//"
|
||||
room_descriptions.jelly_vat[3] = "O banho gelatinoso requer um médico. Também precisa de uma faz-tudo para a sua manutençäo. "
|
||||
room_descriptions.gp[1] = "Sala de Consultório Geral//"
|
||||
room_descriptions.jelly_vat[3] = "O banho gelatinoso requer um médico. Também precisa de um zelador para a sua manutençäo. "
|
||||
room_descriptions.gp[1] = "Consultório de Clínica Geral//"
|
||||
room_descriptions.gp[2] = "Esta é a consulta mais importante do seu hospital. Os novos pacientes säo enviados aqui para averiguar o que é que eles têm. Entäo, ou fazem outro diagnóstico ou mandam para uma consulta onde possam ser curados. Possivelmente queira construir outro consultório se o primeiro tiver muito trabalho. Quanto maior for o consultório e quanto mais objetos colocar nele, maior prestígio terá o médico. O mesmo acontece com todas as consultas abertas.//"
|
||||
room_descriptions.gp[3] = "O consultório geral requer um médico. "
|
||||
room_descriptions.hair_restoration[1] = "Peloterapia//"
|
||||
@@ -2611,29 +2804,29 @@ room_descriptions.hair_restoration[2] = "Os pacientes que sofrem de calvície se
|
||||
room_descriptions.hair_restoration[3] = "A consulta de peloterapia requer um médico. Também precisa de manutençäo periódica. "
|
||||
room_descriptions.inflation[1] = "Inflatoterapia//"
|
||||
room_descriptions.inflation[2] = "Os pacientes que sofrem a dolorosa doença de terem a cabeça inflada devem ir à sala de inflatoterapia, será desinflada sua cabeça e em seguida vota a ser inflada à pressäo correta.//"
|
||||
room_descriptions.inflation[3] = "A Inflatoterapia requer um médico. Também precisa de um faz-tudo que se ocupe do seu bom funcionamento. "
|
||||
room_descriptions.psych[1] = "Sala de Psiquiatria//"
|
||||
room_descriptions.inflation[3] = "A Inflatoterapia requer um médico. Também precisa de um zelador que se ocupe do seu bom funcionamento. "
|
||||
room_descriptions.psych[1] = "Psiquiatria//"
|
||||
room_descriptions.psych[2] = "Os pacientes que säo diagnosticados com uma doença psiquiátrica têm que ir a uma consulta de psiquiatria para receber o tratamento. Os psiquiatras também podem realizar diagnósticos para saber que tipo de doença que sofrem os pacientes, e se estas säo do tipo mental, podem tratá-los deitando-os no divä.//"
|
||||
room_descriptions.psych[3] = "A sala de psiquiatria requer um médico especializado em psiquiatria. "
|
||||
room_descriptions.operating_theatre[1] = "Sala de Operaçöes//"
|
||||
room_descriptions.operating_theatre[2] = "Esta importante instalaçäo serve para curar um grande número de doenças. A sala de operaçöes tem que ser espaçosa e deve estar bem equipada. É uma parte essencial do seu hospital.//"
|
||||
room_descriptions.operating_theatre[3] = "A sala de operaçöes requer dois médicos especializados em cirurgia. "
|
||||
room_descriptions.operating_theatre[1] = "Sala de Cirurgia//"
|
||||
room_descriptions.operating_theatre[2] = "Esta importante instalaçäo serve para curar um grande número de doenças. A Sala de Cirurgia tem que ser espaçosa e deve estar bem equipada. É uma parte essencial do seu hospital.//"
|
||||
room_descriptions.operating_theatre[3] = "A Sala de Cirurgia requer dois médicos especializados em cirurgia. "
|
||||
room_descriptions.no_room[1] = ""
|
||||
room_descriptions.x_ray[1] = "Sala de Raio X//"
|
||||
room_descriptions.x_ray[2] = "O Raio X fotografa o interior do paciente empregando uma radiaçäo especial para ajudar a equipe a descobrir o que acontece.//"
|
||||
room_descriptions.x_ray[3] = "A sala de Raio X requer um médico. Também precisa de manutençäo. "
|
||||
room_descriptions.x_ray[1] = "Sala de Raio-X//"
|
||||
room_descriptions.x_ray[2] = "O Raio-X fotografa o interior do paciente empregando uma radiaçäo especial para ajudar a equipe a descobrir o que acontece.//"
|
||||
room_descriptions.x_ray[3] = "A sala de Raio-X requer um médico. Também precisa de manutençäo. "
|
||||
room_descriptions.tv_room[1] = "TV ROOM NOT USED"
|
||||
room_descriptions.staff_room[1] = "Sala de Descanso//"
|
||||
room_descriptions.staff_room[2] = "Os seus funcionários se cansam quando realizam o seu trabalho. Precisam desta sala para descansar e se refrescar. Os funcionários cansados säo mais lentos, pedem mais dinheiro e por fim väo embora. Também cometem mais erros. Vale a pena construir uma sala que tenham muitos passatempos. Assegure-se de que há lugar para vários funcionários ao mesmo tempo. "
|
||||
room_descriptions.slack_tongue[1] = "Laringologia//"
|
||||
room_descriptions.slack_tongue[2] = "Os pacientes que sejam diagnosticados com língua comprida na consulta seräo enviados aqui para receber tratamento. O médico utilizará uma máquina de alta tecnologia para estirar a língua e cortá-la e, com o que o paciente voltará a estar säo.//"
|
||||
room_descriptions.slack_tongue[2] = "Os pacientes que sejam diagnosticados com língua comprida no Consultório de Clínica Geral, seräo enviados aqui para receber tratamento. O médico utilizará uma máquina de alta tecnologia para esticar a língua e cortá-la, assim o paciente ficará curado.//"
|
||||
room_descriptions.slack_tongue[3] = "A sala de laringologia requer um médico. Também precisa de uma manutençäo muito frequente. "
|
||||
room_descriptions.dna_fixer[1] = "Genética//"
|
||||
room_descriptions.dna_fixer[2] = "Os pacientes que foram manipulados por alienígenas, devem ter seu DNA substituído nesta sala. O reparador de DNA é uma máquina complexa e seria sensato ter um extintor na sala, só por garantia.//"
|
||||
room_descriptions.dna_fixer[3] = "O reparador de DNA requer que um faz-tudo o revise de vez em quando. Também requer um médico especializado em pesquisa para poder usá-lo. "
|
||||
room_descriptions.dna_fixer[3] = "O reparador de DNA requer que um zelador o revise de vez em quando. Também requer um médico especializado em pesquisa para poder usá-lo. "
|
||||
room_descriptions.training[1] = "Sala de Formaçäo//"
|
||||
room_descriptions.training[2] = "Os seus residentes e médicos podem obter uma valiosa qualificaçäo extra aprendendo nesta sala. Um especialista em cirurgia, pesquisa ou psiquiatria ensinará a sua especialidade aos médicos que recebem formaçäo. Os médicos que já possuem estas especialidades veräo a sua habilidade aumentar enquanto estäo aqui.//"
|
||||
room_descriptions.training[3] = "A sala de formaçäo requer um especialista. "
|
||||
room_descriptions.training[3] = "A Sala de Formaçäo requer um especialista. "
|
||||
room_descriptions.toilets[1] = "Banheiro//"
|
||||
room_descriptions.toilets[2] = "Os pacientes estäo sentindo um chamado da natureza e precisam se aliviar no conforto de suas instalaçöes de banheiro. Pode construir mais banheiros e pias se esperar muitos visitantes. Em alguns casos, terá que pôr mais banheiros em outras partes do hospital. "
|
||||
room_descriptions.ultrascan[1] = "Ultra Scanner//"
|
||||
@@ -2645,15 +2838,15 @@ room_descriptions.pharmacy[3] = "A farmácia requer uma enfermeira. "
|
||||
room_descriptions.research[1] = "Centro de Pesquisa//"
|
||||
room_descriptions.research[2] = "No centro de pesquisa säo inventados ou melhoram novos remédios e curas. É uma parte essencial do seu hospital, e fará maravilhas para elevar a sua porcentagem de curas.//"
|
||||
room_descriptions.research[3] = "O Centro de Pesquisa requer um médico especializado em pesquisa. "
|
||||
room_descriptions.general_diag[1] = "Sala de Diagnóstico Geral//"
|
||||
room_descriptions.general_diag[1] = "Diagnóstico Geral//"
|
||||
room_descriptions.general_diag[2] = "Aqui säo examinados os pacientes que precisam de outro diagnóstico. Se em uma consulta näo descobrir os seus problemas, o diagnosticador geral normalmente consegue. Em seguida, volta a enviar os pacientes para a consulta para analisar os resultados obtidos aqui.//"
|
||||
room_descriptions.general_diag[3] = "A sala de diagnóstico geral requer um médico. "
|
||||
room_descriptions.general_diag[3] = "A sala de Diagnóstico Geral requer um médico. "
|
||||
room_descriptions.scanner[1] = "Scanner//"
|
||||
room_descriptions.scanner[2] = "É diagnosticado com precisäo os pacientes empregando um sofisticado scanner. Em seguida, väo para a consulta para que o médico veja o tratamento posterior.//"
|
||||
room_descriptions.scanner[2] = "É diagnosticado com precisäo os pacientes empregando um sofisticado scanner. Em seguida, väo para o Consultório de Clínica Geral para que o médico veja o tratamento posterior.//"
|
||||
room_descriptions.scanner[3] = "O scanner requer um médico. Também precisa de manutençäo. "
|
||||
room_descriptions.electrolysis[1] = "Eletrólise//"
|
||||
room_descriptions.electrolysis[2] = "Os pacientes com peludismo säo enviados para esta consulta, onde uma máquina especial de eletrólise elimina os pelos e fecha os poros com eletricidade empregando um composto parecido ao cal.//"
|
||||
room_descriptions.electrolysis[3] = "A sala de eletrólise requer um médico. Também precisa que um faz-tudo faça a sua manutençäo. "
|
||||
room_descriptions.electrolysis[3] = "A sala de eletrólise requer um médico. Também precisa que um zelador faça a sua manutençäo. "
|
||||
staff_list.skill = "NIVEL"
|
||||
staff_list.morale = "MORAL"
|
||||
staff_list.tiredness = "CANSAÇO"
|
||||
@@ -2666,4 +2859,3 @@ menu_file_load[5] = " JOGO 5 "
|
||||
menu_file_load[6] = " JOGO 6 "
|
||||
menu_file_load[7] = " JOGO 7 "
|
||||
menu_file_load[8] = " JOGO 8 "
|
||||
|
||||
|
@@ -18,7 +18,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. --]]
|
||||
|
||||
Language("English", "en", "eng")
|
||||
Language("English", "English", "en", "eng")
|
||||
Inherit("original_strings", 0)
|
||||
|
||||
--Note: All strings should use a single space after full-stops. Only exception is level descriptions.
|
||||
@@ -59,16 +59,16 @@ vip_names = {
|
||||
adviser.research.drug_improved_1 = "%s drug has been improved by your Research Department."
|
||||
|
||||
-- Disease overrides where there are typos
|
||||
golf_stones.cure = "Cure - These must be removed by an operation requiring two Surgeons."
|
||||
ruptured_nodules.cure = "Cure - Two qualified Surgeons must remove the nodules using steady hands."
|
||||
slack_tongue.cause = "Cause - Chronic over-discussion of soap operas."
|
||||
slack_tongue.cure = "Cure - The tongue is placed in the Slicer Machine and removed quickly, efficiently, and painfully."
|
||||
the_squits.cure = "Cure - A glutinous mix of stringy pharmaceutical chemicals solidify the patient's innards."
|
||||
bloaty_head.cure = "Cure - The swollen head is popped, then re-inflated to the correct PSI using a clever machine."
|
||||
diseases.golf_stones.cure = "Cure - These must be removed by an operation requiring two Surgeons."
|
||||
diseases.ruptured_nodules.cure = "Cure - Two qualified Surgeons must remove the nodules using steady hands."
|
||||
diseases.slack_tongue.cause = "Cause - Chronic over-discussion of soap operas."
|
||||
diseases.slack_tongue.cure = "Cure - The tongue is placed in the Slicer Machine and removed quickly, efficiently, and painfully."
|
||||
diseases.the_squits.cure = "Cure - A glutinous mix of stringy pharmaceutical chemicals solidify the patient's innards."
|
||||
diseases.bloaty_head.cure = "Cure - The swollen head is popped, then re-inflated to the correct PSI using a clever machine."
|
||||
|
||||
-- Rooms overrides where there are typos
|
||||
inflation[2] = "Patients with the painful-yet-humorous condition of Bloaty Head must come to the Inflation Clinic, where the overlarge cranium will be popped and instantly re-inflated to the correct pressure.//"
|
||||
staff_room[2] = "Your staff get tired as they carry out their jobs. They require this room to relax and refresh themselves. Tired staff slow down, demand more money, and will eventually quit. They also make more mistakes. Building a staff room with plenty for them to do is very worthwhile. Make sure there is room for several staff members at one time. "
|
||||
room_descriptions.inflation[2] = "Patients with the painful-yet-humorous condition of Bloaty Head must come to the Inflation Clinic, where the overlarge cranium will be popped and instantly re-inflated to the correct pressure.//"
|
||||
room_descriptions.staff_room[2] = "Your staff get tired as they carry out their jobs. They require this room to relax and refresh themselves. Tired staff slow down, demand more money, and will eventually quit. They also make more mistakes. Building a staff room with plenty for them to do is very worthwhile. Make sure there is room for several staff members at one time. "
|
||||
|
||||
-- Staff description overrides where there are typos
|
||||
staff_descriptions.bad[14] = "Sly, cunning, and subversive. "
|
||||
@@ -104,8 +104,13 @@ multiplayer.everyone_failed = "Everyone failed to satisfy that last objective. S
|
||||
-- Override for a disease patient choice typo
|
||||
disease_discovered_patient_choice.need_to_employ = "Employ a %s to be able to handle this situation."
|
||||
|
||||
--Win message override typo
|
||||
letter[12][2] = "Your successful career as the best hospital administrator since Moses is nearing an end. However, such has been your impact on the cosy world of medicine, the Ministry would like to offer you a salary of $%d simply to appear on our behalf, opening fetes, launching ships, and doing chat shows. The whole world is clamouring for you, and it would be great PR for us all!//"
|
||||
-- Override for shorter messages and a typo in 12.2
|
||||
letter[9][2] = "You have proved yourself to be the best hospital administrator in medicine's long and chequered history. Such a momentous achievement cannot go unrewarded, so we would like to offer you the honorary post of Supreme Chief of All Hospitals. This comes with a salary of $%d. You will be given a tickertape parade, and people will show their appreciation wherever you go.//"
|
||||
letter[10][2] = "Congratulations on successfully running every hospital we assigned you to. Such a superb performance qualifies you for the freedom of all the world's cities. You are to be given a pension of $%d, and all we ask is that you travel, for free, around the nation, promoting the work of all hospitals to your adoring public.//"
|
||||
letter[11][2] = "Your career has been exemplary, and you are an inspiration to all of us. Thank you for running so many hospitals so well. We would like to grant you a lifetime salary of $%d, and would ask simply that you travel by official open-topped car from city to city, giving lectures about how you achieved so much so fast.//"
|
||||
letter[11][3] = "You are an example to every wise person, and without exception, everybody in the world regards you as a supreme asset.//"
|
||||
letter[12][2] = "Your successful career as the best hospital administrator since Moses is nearing an end. Befitting your impact on the nation, the Ministry would like to offer you a salary of $%d simply to appear on our behalf, opening fetes, launching ships, and doing chat shows. It would be great PR for us all!//"
|
||||
|
||||
------------------------------- NEW STRINGS -------------------------------
|
||||
date_format = {
|
||||
daymonth = "%1% %2:months%",
|
||||
@@ -187,6 +192,7 @@ menu_debug = {
|
||||
transparent_walls = " (%1%) TRANSPARENT WALLS ",
|
||||
limit_camera = " LIMIT CAMERA ",
|
||||
disable_salary_raise = " DISABLE SALARY RAISE ",
|
||||
allow_blocking_off_areas = " ALLOW BLOCKING OFF AREAS ",
|
||||
make_debug_fax = " MAKE DEBUG FAX ",
|
||||
make_debug_patient = " MAKE DEBUG PATIENT ",
|
||||
cheats = " (%1%) CHEATS ",
|
||||
@@ -229,6 +235,7 @@ adviser = {
|
||||
no_desk_5 = "Well it's about time, you should start to see some patients arriving soon!",
|
||||
no_desk_6 = "You have a receptionist, so how about building a reception desk for her to work from?",
|
||||
no_desk_7 = "You've built the reception desk, so how about hiring a receptionist? You won't see any patients until you get this sorted out you know!",
|
||||
another_desk = "You'll need to build another desk for that new receptionist.",
|
||||
cannot_afford = "You don't have enough money in the bank to hire that person!", -- I can't see anything like this in the original strings
|
||||
cannot_afford_2 = "You don't have enough money in the bank to make that purchase!",
|
||||
falling_1 = "Hey! That is not funny, watch where you click that mouse; someone could get hurt!",
|
||||
@@ -251,8 +258,8 @@ adviser = {
|
||||
},
|
||||
cheats = {
|
||||
th_cheat = "Congratulations, you have unlocked cheats!",
|
||||
roujin_on_cheat = "Roujin's challenge activated! Good luck...",
|
||||
roujin_off_cheat = "Roujin's challenge deactivated.",
|
||||
roujin_on_cheat = "Roujin's challenge activated! Good luck in the coming months...",
|
||||
roujin_off_cheat = "Roujin's challenge deactivated. Everything will be back to normal soon.",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -304,6 +311,7 @@ install = {
|
||||
|
||||
misc.not_yet_implemented = "(not yet implemented)"
|
||||
misc.no_heliport = "Either no diseases have been discovered yet, or there is no heliport on this map. It might be that you need to build a reception desk and hire a receptionist"
|
||||
misc.cant_treat_emergency = "Your hospital cannot treat this emergency because its disease has not been discovered. Feel free to try again."
|
||||
|
||||
main_menu = {
|
||||
new_game = "Campaign",
|
||||
@@ -459,6 +467,7 @@ customise_window = {
|
||||
aliens = "Alien Patients",
|
||||
fractured_bones = "Fractured Bones",
|
||||
average_contents = "Average Contents",
|
||||
remove_destroyed_rooms = "Remove destroyed rooms",
|
||||
}
|
||||
|
||||
tooltip.customise_window = {
|
||||
@@ -469,6 +478,7 @@ tooltip.customise_window = {
|
||||
aliens = "Because of the lack of proper animations we have by default made patients with Alien DNA only come from an emergency. To allow patients with Alien DNA to visit your hospital, other than by an emergency, turn this off",
|
||||
fractured_bones = "Because of a poor animation we have by default made it so there are no female patients with Fractured Bones. To allow female patients with Fractured Bones to visit your hospital, turn this off",
|
||||
average_contents = "If you would like the game to remember what extra objects you usually add when you build rooms, then turn this option on",
|
||||
remove_destroyed_rooms = "If you would like to be able to remove destroyed rooms, for a fee, turn this option on",
|
||||
back = "Close this menu and go back to the Settings Menu",
|
||||
}
|
||||
|
||||
@@ -678,6 +688,7 @@ errors = {
|
||||
dialog_missing_graphics = "Sorry, the demo data files don't contain this dialog.",
|
||||
save_prefix = "Error while saving game: ",
|
||||
load_prefix = "Error while loading game: ",
|
||||
compatibility_error = "Sorry, this save was created with a newer version of CorsixTH and is not compatible. Please update to a more recent version.",
|
||||
no_games_to_contine = "There are no saved games.",
|
||||
load_quick_save = "Error, cannot load the quicksave as it does not exist, not to worry as we have now created one for you!",
|
||||
map_file_missing = "Could not find the map file %s for this level!",
|
||||
@@ -687,17 +698,20 @@ errors = {
|
||||
fractured_bones = "NOTE: The animation for female patients with Fractured Bones is not perfect",
|
||||
could_not_load_campaign = "Failed to load the campaign: %s",
|
||||
could_not_find_first_campaign_level = "Could not find the first level of this campaign: %s",
|
||||
save_to_tmp = "The file at %s could not be used. The game has been saved to %s. Error: %s",
|
||||
}
|
||||
|
||||
warnings = {
|
||||
levelfile_variable_is_deprecated = "Notice: The level '%s' contains a deprecated variable definition in the level file." ..
|
||||
"'%LevelFile' has been renamed to '%MapFile'. Please advise the map creator to update the level.",
|
||||
newersave = "Warning, you have loaded a save from a newer version of CorsixTH. It is not recommended to continue as crashes may occur. Play at your own risk."
|
||||
}
|
||||
|
||||
confirmation = {
|
||||
needs_restart = "Changing this setting requires CorsixTH to restart. Any unsaved progress will be lost. Are you sure you want to do this?",
|
||||
abort_edit_room = "You are currently building or editing a room. If all required objects are placed it will be finished, but otherwise it will be deleted. Continue?",
|
||||
maximum_screen_size = "The screen size you have entered is greater than 3000 x 2000. Larger resolutions are possible but will require better hardware in order to maintain a playable frame rate. Are you sure you want to continue?",
|
||||
remove_destroyed_room = "Would you like to remove the room for $%d?",
|
||||
}
|
||||
|
||||
information = {
|
||||
@@ -874,6 +888,28 @@ map_editor_window = {
|
||||
}
|
||||
}
|
||||
|
||||
fax = {
|
||||
vip_visit_result = {
|
||||
ordered_remarks = {
|
||||
[1] = "What a storming hospital. When I'm next seriously ill, take me there.",
|
||||
[2] = "Now that's what I call a hospital.",
|
||||
[3] = "That's a super hospital. And I should know; I've been in a few.",
|
||||
[4] = "What a well-run hospital. Thanks for inviting me to it.",
|
||||
[5] = "Hmm. Not a bad medical establishment, certainly.",
|
||||
[6] = "I did enjoy your charming hospital. Now, anyone fancy a curry at the Taj?",
|
||||
[7] = "Well, I've seen worse. But you should make some improvements.",
|
||||
[8] = "Oh dear. Not a nice place to go if you're feeling peaky.",
|
||||
[9] = "It's a standard hospital, to be honest. Frankly, I expected more.",
|
||||
[10] = "Why did I bother? It was worse than going to see a four-hour opera!",
|
||||
[11] = "I'm disgusted by what I saw. Call that a hospital? Pig-sty, more like!",
|
||||
[12] = "I'm fed up of being in the public spotlight and visiting smelly holes like this! I resign.",
|
||||
[13] = "What a dump. I'm going to try and get it closed down.",
|
||||
[14] = "I have never seen such a dreadful hospital. What a disgrace!",
|
||||
[15] = "I'm shocked. You can't call that a hospital! I'm off for a pint.",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hotkeys_file_err = {
|
||||
file_err_01 = "Unable to load hotkeys.txt file. Please ensure that CorsixTH " ..
|
||||
"has permission to read/write ",
|
||||
@@ -881,6 +917,7 @@ hotkeys_file_err = {
|
||||
"For reference, the error loading the hotkeys file was: ",
|
||||
}
|
||||
|
||||
transactions.remove_room = "Build: Remove destroyed room"
|
||||
-------------------------------- UNUSED -----------------------------------
|
||||
------------------- (kept for backwards compatibility) ----------------------
|
||||
|
||||
|
3349
CorsixTH/Lua/languages/greek.lua
Normal file
3349
CorsixTH/Lua/languages/greek.lua
Normal file
File diff suppressed because it is too large
Load Diff
@@ -648,8 +648,8 @@ adviser = {
|
||||
patient_abducted = S[11][111], -- what the heck is this? I never got that far in the original...
|
||||
patient_leaving_too_expensive = S[11][118],
|
||||
|
||||
pay_rise = S[11][ 29], -- TODO only in tutorial / first time?
|
||||
handyman_adjust = S[11][ 71], -- TODO only in tutorial / first time?
|
||||
pay_rise = S[11][ 29], -- Once only
|
||||
handyman_adjust = S[11][ 71], -- Once only
|
||||
fax_received = S[11][136], -- Once only
|
||||
|
||||
vip_arrived = S[21][ 9], -- %s (name of VIP)
|
||||
@@ -1142,9 +1142,9 @@ trophy_room = {
|
||||
S[55][ 7],
|
||||
},
|
||||
},
|
||||
all_cured = { -- not implemented
|
||||
all_cured = {
|
||||
awards = {
|
||||
S[27][29], -- for 100% treat rate (does that mean none sent home or killed?)
|
||||
S[27][29], -- for 100% treat rate (none sent home or killed)
|
||||
},
|
||||
trophies = {
|
||||
S[27][30], -- for 100% cure rate
|
||||
|
@@ -18,7 +18,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE. --]]
|
||||
|
||||
Language("Castellano", "Spanish", "es", "spa", "esp", "sp")
|
||||
Language("Español", "Spanish", "es", "spa", "esp", "sp")
|
||||
Inherit("english")
|
||||
Inherit("original_strings", 4)
|
||||
|
||||
|
@@ -1350,7 +1350,7 @@ adviser = {
|
||||
hire_doctor = "您需要一個醫生來診斷和治療病人。",
|
||||
place_receptionist = "移動接待員並將她放到任意位置。她將很聰明地自己走到服務台。",
|
||||
place_windows = "設置窗戶的方法與設置房門的方法相同。您可以不需要窗戶,但是當您的員工可以從窗戶向外張望時,他們將感到快樂。",
|
||||
confirm_room = "左鍵單擊閃動標就可以開業了,也可以通過點擊交叉按鈕返回上一步。",
|
||||
confirm_room = "左鍵單擊閃動圖標就可以開業了,也可以通過點擊交叉按鈕返回上一步。",
|
||||
rotate_and_place_reception = "點擊滑鼠右鍵可以旋轉桌子,並用滑鼠左鍵將其放在醫院中合適位置。",
|
||||
build_reception = "你好。首先,您的醫院需要一個服務台,您可以從佈置走廊選單中選取。",
|
||||
doctor_in_invalid_position = "嘿!您不能將醫生放在那裡。",
|
||||
@@ -1361,21 +1361,21 @@ adviser = {
|
||||
choose_doctor = "在選擇醫生之前,應重點考慮其能力。",
|
||||
information_window = "協助視窗將告訴您剛剛建造的一般診斷室信息。",
|
||||
build_gps_office = "您必須建造一般診斷室才可以診斷病人。",
|
||||
select_doctors = "點擊閃動的標挑選可被雇用的醫生。",
|
||||
select_diagnosis_rooms = "點擊閃動的標將彈出診斷類房間列表。",
|
||||
select_receptionists = "使用滑鼠左鍵單擊閃動的標來查看當前可選擇的接待員。標下方的數字表示共有多少個接待員可供選擇。",
|
||||
select_doctors = "點擊閃動的圖標挑選可被雇用的醫生。",
|
||||
select_diagnosis_rooms = "點擊閃動的圖標將彈出診斷類房間列表。",
|
||||
select_receptionists = "使用滑鼠左鍵單擊閃動的圖標來查看當前可選擇的接待員。圖標下方的數字表示共有多少個接待員可供選擇。",
|
||||
order_one_reception = "使用滑鼠左鍵單擊閃動的光條,可以訂購一個服務台。",
|
||||
choose_receptionist = "判斷哪一個接待員擁有好的能力與合適的工資,再按左鍵單擊閃動的標來雇用她。",
|
||||
prev_receptionist = "左鍵單擊閃動的標將可以瀏覽到前一個可供選擇的接待員。",
|
||||
accept_purchase = "點擊閃動的標表示購買。",
|
||||
choose_receptionist = "判斷哪一個接待員擁有好的能力與合適的工資,再按左鍵單擊閃動的圖標來雇用她。",
|
||||
prev_receptionist = "左鍵單擊閃動的圖標將可以瀏覽到前一個可供選擇的接待員。",
|
||||
accept_purchase = "點擊閃動的圖標表示購買。",
|
||||
place_door = "沿藍圖牆壁移動滑鼠,尋找放置房門的合適位置。",
|
||||
click_and_drag_to_build = "建造一般診斷室時應先決定具體的尺寸。點擊並按住滑鼠左鍵可以設置房間尺寸。",
|
||||
room_in_invalid_position = "該藍圖是非法的,紅色區域表示藍圖與其它房間或牆壁重疊。",
|
||||
place_objects = "右擊可以旋轉房屋中的各種物品,再左擊表示確認。",
|
||||
room_too_small = "該房間的藍圖為紅色是因為其尺寸太小了。通過拖動使其尺寸增大。",
|
||||
click_gps_office = "點擊閃動標表示選擇一般診斷室。",
|
||||
click_gps_office = "點擊閃動圖標表示選擇一般診斷室。",
|
||||
reception_invalid_position = "如果服務台是灰色的,則表示當前位置是非法的。應嘗試移動或旋轉它。",
|
||||
next_receptionist = "這是接待員列表中的第一個。左鍵單擊閃動的標可以瀏覽下一個可供選用的接待員。",
|
||||
next_receptionist = "這是接待員列表中的第一個。左鍵單擊閃動的圖標可以瀏覽下一個可供選用的接待員。",
|
||||
room_big_enough = "藍圖尺寸已經足夠大了。當您鬆開滑鼠按鍵表示確認。如果需要的話,以後還可以根據需要移動或改變其尺寸。",
|
||||
object_in_invalid_position = "該物品當前位置非法。請要麼將其放到其它位置,要麼對其進行旋轉。",
|
||||
door_in_invalid_position = "房門設置位置非法。請嘗試藍圖牆壁上的其它位置。",
|
||||
@@ -1625,9 +1625,9 @@ adviser = {
|
||||
vip_arrived = "小心!%s正準備訪問您的醫院!保持醫院運轉正常,這樣才能使他感到愉快。",
|
||||
epidemic_health_inspector = "您的醫院中出現傳染病的消息已經到達了衛生署。衛生巡查員很快就要到達,快做準備。",
|
||||
first_death = "這是您第一次殺死病人。感覺如何?",
|
||||
pay_rise = "您的一個員工威脅要辭職。選擇是否同意其請求,或將其解雇。點擊屏幕左下方的標可以查看威脅要辭職的員工信息。",
|
||||
pay_rise = "您的一個員工威脅要辭職。選擇是否同意其請求,或將其解雇。點擊屏幕左下方的圖標可以查看威脅要辭職的員工信息。",
|
||||
place_windows = "設置窗戶將使房間更加明亮,並振奮員工的精神。",
|
||||
fax_received = "在屏幕左下角剛剛彈出的標表示一些重要事件的相關信息,或某些需要您決定的事情。",
|
||||
fax_received = "在屏幕左下角剛剛彈出的圖標表示一些重要事件的相關信息,或某些需要您決定的事情。",
|
||||
},
|
||||
build_advice = {
|
||||
placing_object_blocks_door = "設置該物品可以阻止其他人接近。",
|
||||
|
@@ -39,6 +39,10 @@ function Map:Map(app)
|
||||
self.debug_font = false
|
||||
self.debug_tick_timer = 1
|
||||
self:setTemperatureDisplayMethod(app.config.warmth_colors_display_default)
|
||||
|
||||
-- Difficulty of the level (string) "easy", "full", "hard".
|
||||
-- Use map:getDifficulty() to query the value.
|
||||
self.difficulty = nil
|
||||
end
|
||||
|
||||
local flag_cache = {}
|
||||
@@ -277,6 +281,14 @@ function Map:load(level, difficulty, level_name, map_file, level_intro, map_edit
|
||||
return objects
|
||||
end
|
||||
|
||||
--! Get the difficulty of the level. Custom levels and campaign always have medium difficulty.
|
||||
--!return (int) difficulty of the level, 1=easy, 2=medium, 3=hard.
|
||||
function Map:getDifficulty()
|
||||
if self.difficulty == "easy" then return 1 end
|
||||
if self.difficulty == "hard" then return 3 end
|
||||
return 2
|
||||
end
|
||||
|
||||
--[[! Sets the plot owner of the given plot number to the given new owner. Makes sure
|
||||
that any room adjacent to the new plot have walls in all directions after the purchase.
|
||||
!param plot_number (int) Number of the plot to change owner of. Plot 0 is the outside and
|
||||
|
@@ -166,6 +166,8 @@ function Door:checkForDeadlock()
|
||||
for _, action in ipairs(self.reserved_for.action_queue) do
|
||||
if action.name == "queue" then
|
||||
if action.queue ~= self.queue or self.queue[1] ~= self.reserved_for then
|
||||
self.world:gameLog("Warning: Trying to resolve door deadlock at ("
|
||||
.. tostring(self.tile_x) .. ", " .. tostring(self.tile_y) .. ")")
|
||||
self.reserved_for = nil
|
||||
self:getRoom():tryAdvanceQueue()
|
||||
end
|
||||
|
@@ -36,22 +36,22 @@ class "EntranceDoor" (Object)
|
||||
---@type EntranceDoor
|
||||
local EntranceDoor = _G["EntranceDoor"]
|
||||
|
||||
function EntranceDoor:EntranceDoor(world, object_type, x, y, direction, etc)
|
||||
function EntranceDoor:EntranceDoor(hospital, object_type, x, y, direction, etc)
|
||||
self.is_master = object_type == object
|
||||
self:Object(world, object_type, x, y, direction, etc)
|
||||
self:Object(hospital, object_type, x, y, direction, etc)
|
||||
self.occupant_count = 0
|
||||
self.is_open = false
|
||||
-- We need to link the master to the slave but we don't know in which order they will be initialized
|
||||
if self.is_master then -- The master will check for an adjacent slave
|
||||
local slave_type = "entrance_left_door"
|
||||
self.slave = world:getObject(x - 1, y, slave_type) or world:getObject(x, y - 1, slave_type) or nil
|
||||
self.slave = self.world:getObject(x - 1, y, slave_type) or self.world:getObject(x, y - 1, slave_type) or nil
|
||||
|
||||
if self.slave then
|
||||
self.slave.master = self
|
||||
end
|
||||
else -- The slave will check for an adjacent master
|
||||
local master_type = "entrance_right_door"
|
||||
self.master = world:getObject(x + 1, y, master_type) or world:getObject(x, y + 1, master_type) or nil
|
||||
self.master = self.world:getObject(x + 1, y, master_type) or self.world:getObject(x, y + 1, master_type) or nil
|
||||
|
||||
if self.master then
|
||||
self.master.slave = self
|
||||
|
@@ -35,14 +35,14 @@ class "SwingDoor" (Door)
|
||||
---@type SwingDoor
|
||||
local SwingDoor = _G["SwingDoor"]
|
||||
|
||||
function SwingDoor:SwingDoor(world, object_type, x, y, direction, etc)
|
||||
function SwingDoor:SwingDoor(hospital, object_type, x, y, direction, etc)
|
||||
self.is_master = object_type == object
|
||||
self:Door(world, object_type, x, y, direction, etc)
|
||||
self:Door(hospital, object_type, x, y, direction, etc)
|
||||
if self.is_master then
|
||||
-- Wait one tick before finding the slave so that we're sure it has been created.
|
||||
local --[[persistable:swing_door_creation]] function callback()
|
||||
local slave_type = "swing_door_left"
|
||||
self.slave = world:getObject(x - 1, y, slave_type) or world:getObject(x, y - 1, slave_type) or nil
|
||||
self.slave = self.world:getObject(x - 1, y, slave_type) or self.world:getObject(x, y - 1, slave_type) or nil
|
||||
self.slave:setAsSlave(self)
|
||||
self.ticks = false
|
||||
end
|
||||
|
@@ -34,20 +34,20 @@ object.orientations = {
|
||||
},
|
||||
}
|
||||
|
||||
--! An `Object` which drops of emergency patients.
|
||||
--! An `Object` which drops off emergency patients.
|
||||
class "Helicopter" (Object)
|
||||
|
||||
---@type Helicopter
|
||||
local Helicopter = _G["Helicopter"]
|
||||
|
||||
function Helicopter:Helicopter(world, object_type, hospital, direction, etc)
|
||||
function Helicopter:Helicopter(hospital, object_type, direction, etc)
|
||||
local x, y = hospital:getHeliportPosition()
|
||||
-- Helicoptor needs to land below tile to be positioned correctly
|
||||
-- Helicopter needs to land below tile to be positioned correctly
|
||||
y = y + 1
|
||||
self:Object(world, object_type, x, y, direction, etc)
|
||||
self:Object(hospital, object_type, x, y, direction, etc)
|
||||
self.th:makeInvisible()
|
||||
self:setPosition(0, -600)
|
||||
self.phase = -60
|
||||
self.phase = -120
|
||||
self.hospital = hospital
|
||||
-- TODO: Shadow: 3918
|
||||
hospital.emergency_patients = {}
|
||||
@@ -61,7 +61,7 @@ function Helicopter:tick()
|
||||
elseif phase == 60 then
|
||||
self:setSpeed(0, 0)
|
||||
self.spawned_patients = 0
|
||||
elseif phase == 80 then
|
||||
elseif phase == 85 then
|
||||
if self.spawned_patients < self.hospital.emergency.victims then
|
||||
self:spawnPatient()
|
||||
phase = 60
|
||||
@@ -82,17 +82,22 @@ function Helicopter:spawnPatient()
|
||||
local patient = self.world:newEntity("Patient", 2)
|
||||
patient:setDisease(hospital.emergency.disease)
|
||||
patient.diagnosis_progress = 1
|
||||
patient.is_emergency = self.spawned_patients
|
||||
patient:setDiagnosed()
|
||||
patient:setMood("emergency", "activate")
|
||||
patient.is_emergency = self.spawned_patients
|
||||
hospital.emergency_patients[#hospital.emergency_patients + 1] = patient
|
||||
hospital.emergency_patients[self.spawned_patients] = patient
|
||||
local x, y = hospital:getHeliportSpawnPosition()
|
||||
patient:setNextAction(SpawnAction("spawn", {x = x, y = y}):setOffset({y = 1}))
|
||||
patient:setHospital(hospital)
|
||||
-- TODO: If new combined diseases are added this will not work correctly anymore.
|
||||
patient.cure_rooms_visited = #patient.disease.treatment_rooms - 1
|
||||
local no_of_rooms = #patient.disease.treatment_rooms
|
||||
patient:queueAction(SeekRoomAction(patient.disease.treatment_rooms[no_of_rooms]))
|
||||
-- a spawning emergency patient might rather leave than pay
|
||||
if not patient:agreesToPay(patient.disease.id) then
|
||||
patient:goHome("over_priced", patient.disease.id)
|
||||
else
|
||||
patient:queueAction(SeekRoomAction(patient.disease.treatment_rooms[no_of_rooms]))
|
||||
end
|
||||
end
|
||||
|
||||
return object
|
||||
|
@@ -53,12 +53,13 @@ class "Litter" (Entity)
|
||||
---@type Litter
|
||||
local Litter = _G["Litter"]
|
||||
|
||||
function Litter:Litter(world, object_type, x, y, direction, etc)
|
||||
function Litter:Litter(hospital, object_type, x, y, direction, etc)
|
||||
local th = TH.animation()
|
||||
self:Entity(th)
|
||||
self.ticks = object_type.ticks
|
||||
self.object_type = object_type
|
||||
self.world = world
|
||||
self.hospital = hospital
|
||||
self.world = hospital.world
|
||||
self:setTile(x, y)
|
||||
end
|
||||
|
||||
@@ -86,22 +87,20 @@ function Litter:setLitterType(anim_type, mirrorFlag)
|
||||
error("Unknown litter type")
|
||||
end
|
||||
if self:isCleanable() then
|
||||
local hospital = self.world:getHospital(self.tile_x, self.tile_y)
|
||||
hospital:addHandymanTask(self, "cleaning", 1, self.tile_x, self.tile_y)
|
||||
self.hospital:addHandymanTask(self, "cleaning", 1, self.tile_x, self.tile_y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--! Remove the litter from the world.
|
||||
function Litter:remove()
|
||||
assert(self:isCleanable())
|
||||
assert(self:isCleanable()or TheApp.config.remove_destroyed_rooms)
|
||||
|
||||
if self.tile_x then
|
||||
self.world:removeObjectFromTile(self, self.tile_x, self.tile_y)
|
||||
|
||||
local hospital = self.world:getHospital(self.tile_x, self.tile_y)
|
||||
local taskIndex = hospital:getIndexOfTask(self.tile_x, self.tile_y, "cleaning", self)
|
||||
hospital:removeHandymanTask(taskIndex, "cleaning")
|
||||
local taskIndex = self.hospital:getIndexOfTask(self.tile_x, self.tile_y, "cleaning", self)
|
||||
self.hospital:removeHandymanTask(taskIndex, "cleaning")
|
||||
else
|
||||
print("Warning: Removing litter that has already been removed.")
|
||||
end
|
||||
@@ -140,7 +139,7 @@ end
|
||||
function Litter:afterLoad(old, new)
|
||||
if old < 52 then
|
||||
if self.tile_x then
|
||||
self.world.hospitals[1]:addHandymanTask(self, "cleaning", 1, self.tile_x, self.tile_y)
|
||||
self.hospital:addHandymanTask(self, "cleaning", 1, self.tile_x, self.tile_y)
|
||||
else
|
||||
-- This object was not properly removed from the world.
|
||||
self.world:destroyEntity(self)
|
||||
@@ -148,15 +147,18 @@ function Litter:afterLoad(old, new)
|
||||
end
|
||||
if old < 54 then
|
||||
if not self:isCleanable() then
|
||||
local hospital = self.world:getHospital(self.tile_x, self.tile_y)
|
||||
local taskIndex = hospital:getIndexOfTask(self.tile_x, self.tile_y, "cleaning", self)
|
||||
hospital:removeHandymanTask(taskIndex, "cleaning")
|
||||
local taskIndex = self.hospital:getIndexOfTask(self.tile_x, self.tile_y, "cleaning", self)
|
||||
self.hospital:removeHandymanTask(taskIndex, "cleaning")
|
||||
end
|
||||
end
|
||||
|
||||
if old < 121 then
|
||||
self.ticks = object.ticks
|
||||
end
|
||||
|
||||
if old < 151 then
|
||||
self.hospital = self.world:getHospital(self.tile_x, self.tile_y)
|
||||
end
|
||||
end
|
||||
|
||||
return object
|
||||
|
@@ -77,8 +77,9 @@ object.orientations = {
|
||||
-- * dying: 1953
|
||||
-- * dead: 1954
|
||||
|
||||
|
||||
local days_between_states = 75
|
||||
-- TH uses rough 50 days between state transitions
|
||||
-- to approximate that same average rate at ideal temperatures
|
||||
local days_between_states = 64
|
||||
|
||||
-- days before we reannouncing our watering status if we were unreachable
|
||||
local days_unreachable = 10
|
||||
@@ -89,15 +90,16 @@ class "Plant" (Object)
|
||||
---@type Plant
|
||||
local Plant = _G["Plant"]
|
||||
|
||||
function Plant:Plant(world, object_type, x, y, direction, etc)
|
||||
function Plant:Plant(hospital, object_type, x, y, direction, etc)
|
||||
-- It doesn't matter which direction the plant is facing. It will be rotated so that an approaching
|
||||
-- handyman uses the correct usage animation when appropriate.
|
||||
self:Object(world, object_type, x, y, direction, etc)
|
||||
self:Object(hospital, object_type, x, y, direction, etc)
|
||||
self.current_state = 0
|
||||
self.base_frame = self.th:getFrame()
|
||||
self.days_left = days_between_states
|
||||
self.unreachable = false
|
||||
self.unreachable_counter = days_unreachable
|
||||
self.phases = 5
|
||||
end
|
||||
|
||||
--! Goes one step forward (or backward) in the states of the plant.
|
||||
@@ -107,7 +109,7 @@ function Plant:setNextState(restoring)
|
||||
if self.current_state > 0 then
|
||||
self.current_state = self.current_state - 1
|
||||
end
|
||||
elseif self.current_state < 5 then
|
||||
elseif self.current_state < self.phases - 1 then
|
||||
self.current_state = self.current_state + 1
|
||||
end
|
||||
|
||||
@@ -157,13 +159,7 @@ end
|
||||
|
||||
--! Returns whether the plant is in need of watering right now.
|
||||
function Plant:needsWatering()
|
||||
if self.current_state == 0 then
|
||||
if self.days_left < 10 then
|
||||
return true
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
return self.current_state ~= 0
|
||||
end
|
||||
|
||||
--! When the plant needs water it periodically calls for a nearby handyman.
|
||||
@@ -229,7 +225,8 @@ function Plant:createHandymanActions(handyman)
|
||||
handyman:queueAction(AnswerCallAction())
|
||||
end
|
||||
|
||||
--! When a handyman should go to the plant he should approach it from the closest reachable tile.
|
||||
--! When a handyman should go to the plant he should approach it from the
|
||||
-- closest reachable tile within hospital buildings.
|
||||
--!param from_x (integer) The x coordinate of tile to calculate from.
|
||||
--!param from_y (integer) The y coordinate of tile to calculate from.
|
||||
function Plant:getBestUsageTileXY(from_x, from_y)
|
||||
@@ -243,8 +240,8 @@ function Plant:getBestUsageTileXY(from_x, from_y)
|
||||
for _, point in ipairs(access_points) do
|
||||
local dest_x, dest_y = self.tile_x + point.dx, self.tile_y + point.dy
|
||||
local room_there = self.world:getRoom(dest_x, dest_y)
|
||||
if room_here == room_there then
|
||||
local distance = self.world:getPathDistance(from_x, from_y, self.tile_x + point.dx, self.tile_y + point.dy)
|
||||
if room_here == room_there and self.hospital:isInHospital(dest_x, dest_y) then
|
||||
local distance = self.world:getPathDistance(from_x, from_y, dest_x, dest_y)
|
||||
if distance and (not best_point or shortest > distance) then
|
||||
best_point = point
|
||||
shortest = distance
|
||||
@@ -292,12 +289,18 @@ function Plant:onClick(ui, button)
|
||||
Object.onClick(self, ui, button)
|
||||
end
|
||||
|
||||
function Plant:isPleasing()
|
||||
if not self.ticks then
|
||||
--! Plant health/state should be used on evaluations of pleasantness
|
||||
--! returns (integer) score of this plants health, 1 to 5 (best)
|
||||
function Plant:isPleasingFactor()
|
||||
return self.phases - self.current_state
|
||||
end
|
||||
|
||||
--! Check if a plant is dying or about to start dying
|
||||
function Plant:isDying()
|
||||
if self.current_state ~= 0 or self.days_left < 3 then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Plant:onDestroy()
|
||||
@@ -312,6 +315,11 @@ function Plant:afterLoad(old, new)
|
||||
if old < 52 then
|
||||
self.hospital = self.world:getLocalPlayerHospital()
|
||||
end
|
||||
|
||||
if old < 150 then
|
||||
self.phases = 5
|
||||
end
|
||||
|
||||
Object.afterLoad(self, old, new)
|
||||
end
|
||||
|
||||
|
@@ -55,8 +55,8 @@ class "Rathole" (Object)
|
||||
---@type Rathole
|
||||
local Rathole = _G["Rathole"]
|
||||
|
||||
function Rathole:Rathole(world, oject_type, x, y, direction, etc)
|
||||
self:Object(world, oject_type, x, y, direction, etc)
|
||||
function Rathole:Rathole(hospital, oject_type, x, y, direction, etc)
|
||||
self:Object(hospital, oject_type, x, y, direction, etc)
|
||||
end
|
||||
|
||||
return object
|
||||
|
@@ -106,7 +106,7 @@ function ReceptionDesk:tick()
|
||||
if class.is(queue_front, Inspector) then
|
||||
local inspector = queue_front
|
||||
if not inspector.going_home then
|
||||
local epidemic = self.world:getLocalPlayerHospital().epidemic
|
||||
local epidemic = self.hospital.epidemic
|
||||
if epidemic then
|
||||
-- The result of the epidemic may already by determined
|
||||
-- i.e if an infected patient has left the hospital
|
||||
@@ -151,11 +151,10 @@ function ReceptionDesk:checkForNearbyStaff()
|
||||
end
|
||||
|
||||
local nearest_staff, nearest_d
|
||||
local world = self.world
|
||||
local use_x, use_y = self:getSecondaryUsageTile()
|
||||
for _, entity in ipairs(self.world.entities) do
|
||||
if entity.humanoid_class == "Receptionist" and not entity.associated_desk and not entity.fired then
|
||||
local distance = world.pathfinder:findDistance(entity.tile_x, entity.tile_y, use_x, use_y)
|
||||
local distance = self.world.pathfinder:findDistance(entity.tile_x, entity.tile_y, use_x, use_y)
|
||||
if not nearest_d or distance < nearest_d then
|
||||
nearest_staff = entity
|
||||
nearest_d = distance
|
||||
@@ -198,14 +197,14 @@ function ReceptionDesk:onDestroy()
|
||||
self.reserved_for = nil
|
||||
|
||||
-- Find a new reception desk for the receptionist
|
||||
local world = receptionist.world
|
||||
world:findObjectNear(receptionist, "reception_desk", nil, function(x, y)
|
||||
local obj = world:getObject(x, y, "reception_desk")
|
||||
-- Make sure we are not selecting the same desk again
|
||||
if obj and obj ~= self then
|
||||
return obj:occupy(receptionist)
|
||||
end
|
||||
end)
|
||||
self.world:findObjectNear(receptionist, "reception_desk", nil,
|
||||
function(x, y)
|
||||
local obj = self.world:getObject(x, y, "reception_desk")
|
||||
-- Make sure we are not selecting the same desk again
|
||||
if obj and obj ~= self then
|
||||
return obj:occupy(receptionist)
|
||||
end
|
||||
end)
|
||||
end
|
||||
self.queue:rerouteAllPatients(SeekReceptionAction())
|
||||
|
||||
|
@@ -26,7 +26,7 @@ strict_declare_global "unpermanent"
|
||||
|
||||
local th_getfenv
|
||||
local th_getupvalue
|
||||
if _G._VERSION == "Lua 5.2" or _G._VERSION == "Lua 5.3" then
|
||||
if _G._VERSION == "Lua 5.2" or _G._VERSION == "Lua 5.3" or _G._VERSION == "Lua 5.4" then
|
||||
th_getfenv = function(f)
|
||||
local _, val = nil, nil
|
||||
if type(f) == "function" then
|
||||
@@ -255,15 +255,19 @@ end
|
||||
--!param filename (string) Path of the file to write.
|
||||
function SaveGameFile(filename)
|
||||
local data = SaveGame()
|
||||
local f = assert(io.open(filename, "wb"))
|
||||
local f = TheApp:writeToFileOrTmp(filename, "wb")
|
||||
f:write(data)
|
||||
f:close()
|
||||
end
|
||||
|
||||
--! Puts loaded file into the game
|
||||
--!param data The file
|
||||
function LoadGame(data)
|
||||
--local status, res = xpcall(function()
|
||||
local objtable = MakePermanentObjectsTable(true)
|
||||
local state = assert(persist.load(data, objtable))
|
||||
-- Check the game we're loading is compatible with program
|
||||
if not TheApp:checkCompatibility(state.world.savegame_version) then return end
|
||||
state.ui:resync(TheApp.ui)
|
||||
TheApp.ui = state.ui
|
||||
TheApp.world = state.world
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user