Merge branch 'dev' into dev-modern

fix-squashed-planets
MrSimbax 2021-09-04 19:11:24 +02:00
commit 5e37f84bc7
167 changed files with 4398 additions and 1110 deletions

View File

@ -9,7 +9,7 @@ jobs:
strategy: strategy:
matrix: matrix:
target_os: [linux] target_os: [linux]
host_os: [ubuntu-16.04, ubuntu-18.04, ubuntu-20.04] host_os: [ubuntu-18.04, ubuntu-20.04]
container: [''] container: ['']
include: include:
- target_os: windows - target_os: windows

View File

@ -1,207 +0,0 @@
name: Linter
on: [push, pull_request]
jobs:
lint:
# it's easiest if it matches the version that was used to build colobot-lint, newer versions don't have llvm-3.6-dev in repo...
runs-on: ubuntu-16.04
env:
CC: /usr/lib/llvm-3.6/bin/clang
CXX: /usr/lib/llvm-3.6/bin/clang++
CLANG_PREFIX: /usr/lib/llvm-3.6
steps:
- name: Download Colobot dependencies
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng-dev libglew-dev libopenal-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-regex-dev libphysfs-dev gettext git po4a vorbis-tools librsvg2-bin xmlstarlet
# TODO: migrate colobot-lint to GitHub Actions
- name: Download colobot-lint
run: |
sudo apt-get install -y --no-install-recommends clang-3.6 libtinyxml2.6.2v5
mkdir -p /tmp/colobot-lint
cd /tmp/colobot-lint
wget -O colobot-lint.zip "https://compiled.colobot.info/job/colobot/job/colobot-lint/job/dev/lastSuccessfulBuild/artifact/*zip*/archive.zip"
# Unzip the archive
unzip ./colobot-lint.zip
# Workaround for Clang not finding system headers
mkdir ./bin
mv ./archive/build/colobot-lint ./bin/
chmod +x ./bin/colobot-lint
ln -s ${CLANG_PREFIX}/lib ./lib
# Unpack HtmlReport
tar -zxf ./archive/build/html_report.tar.gz
# Clean up
rm -r ./archive
- uses: actions/checkout@v2
- name: Checkout the Google Test submodule
run: git submodule update --init -- lib/googletest
- name: Create build directory
run: cmake -E make_directory build
- name: Run CMake
working-directory: build
run: cmake -DCOLOBOT_LINT_BUILD=1 -DTESTS=1 -DTOOLS=1 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
- name: Run linter
shell: bash
run: |
set -e +x
WORKSPACE="$GITHUB_WORKSPACE"
COLOBOT_DIR="$WORKSPACE"
COLOBOT_BUILD_DIR="$WORKSPACE/build"
COLOBOT_LINT_REPORT_FILE="$WORKSPACE/build/colobot_lint_report.xml"
cd "/tmp/colobot-lint"
find "$WORKSPACE" \( -wholename "$COLOBOT_DIR/src/*.cpp" \
-or -wholename "$COLOBOT_DIR/test/unit/*.cpp" \
-or -wholename "$COLOBOT_BUILD_DIR/fake_header_sources/src/*.cpp" \
-or -wholename "$COLOBOT_BUILD_DIR/fake_header_sources/test/unit/*.cpp" \) \
-exec ./bin/colobot-lint \
-verbose \
-output-format xml \
-output-file "$COLOBOT_LINT_REPORT_FILE" \
-p "$COLOBOT_BUILD_DIR" \
-project-local-include-path "$COLOBOT_DIR/src" -project-local-include-path "$COLOBOT_BUILD_DIR/src" \
-license-template-file "$COLOBOT_DIR/LICENSE-HEADER.txt" \
{} +
- name: Upload results (XML)
uses: actions/upload-artifact@v2
with:
name: XML results
path: build/colobot_lint_report.xml
- name: Generate HTML report
shell: bash
run: /tmp/colobot-lint/HtmlReport/generate.py --xml-report "build/colobot_lint_report.xml" --output-dir "build/html_report"
- name: Upload results (HTML)
uses: actions/upload-artifact@v2
with:
name: HTML results
path: build/html_report
- run: pip install requests
- name: Send linter results to GitHub
shell: python
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
import os
import sys
import requests
import xml.etree.ElementTree as ET
OVERALL_STABLE_RULES=[
"class naming",
"code block placement",
"compile error",
# "compile warning",
# "enum naming",
# "function naming",
"header file not self-contained",
# "implicit bool cast",
# "include style",
# "inconsistent declaration parameter name",
"license header",
# "naked delete",
# "naked new",
# "old style function",
"old-style null pointer",
# "possible forward declaration",
"undefined function",
# "uninitialized field",
# "uninitialized local variable",
# "unused forward declaration",
# "variable naming",
"whitespace",
]
STABLE_RULES_WITHOUT_CBOT=[
"class naming",
"code block placement",
"compile error",
"compile warning",
# "enum naming",
# "function naming",
"header file not self-contained",
# "implicit bool cast",
"include style",
"inconsistent declaration parameter name",
"license header",
"naked delete",
"naked new",
# "old style function",
"old-style null pointer",
# "possible forward declaration",
"undefined function",
"uninitialized field",
# "uninitialized local variable",
"unused forward declaration",
# "variable naming",
"whitespace",
]
# None of the available actions seem to do what I want, they all do stupid things like adding another check... let's just do it manually
# GitHub also doesn't seem to provide you with the check suite or check run ID, so we have to get it from the action ID via the API
s = requests.Session()
s.headers.update({
'Authorization': 'token ' + os.environ['GITHUB_TOKEN'],
'Accept': 'application/vnd.github.antiope-preview+json' # Annotations are still technically a preview feature of the API
})
action_run = s.get(os.environ['GITHUB_API_URL'] + "/repos/" + os.environ['GITHUB_REPOSITORY'] + "/actions/runs/" + os.environ['GITHUB_RUN_ID']).json()
check_suite = s.get(action_run['check_suite_url']).json()
check_suite_runs = s.get(check_suite['check_runs_url']).json()
check_run = check_suite_runs['check_runs'][0] # NOTE: This assumes that the 'lint' job is the first one in the workflow. You could find it by name if you really wanted.
def we_care_about(file_name, type):
if 'CBot' in file_name:
return type in OVERALL_STABLE_RULES
else:
return type in STABLE_RULES_WITHOUT_CBOT
results = ET.parse('build/colobot_lint_report.xml')
annotations = []
for error in results.find('errors').findall('error'):
location = error.find('location')
file_name = os.path.relpath(location.get('file'), os.environ['GITHUB_WORKSPACE'])
line_num = int(location.get('line'))
type = error.get('id')
severity = error.get('severity')
msg = error.get('msg')
gh_severity = 'warning'
if severity == 'error':
gh_severity = 'failure'
elif severity == 'information':
gh_severity = 'notice'
if not we_care_about(file_name, type):
# don't send the unstable rules to github at all as there are way too many of them and it would overload the API rate limit
continue
print('{}:{}: [{}] {}'.format(file_name, line_num, type, msg))
annotations.append({
'path': file_name,
'start_line': line_num,
'end_line': line_num,
'annotation_level': gh_severity,
'title': type,
'message': msg
})
summary = 'colobot-lint found {} issues'.format(len(annotations))
all_ok = len(annotations) == 0
# Annotations have to be sent in batches of 50
first = True
while first or len(annotations) > 0:
first = False
to_send = annotations[:50]
annotations = annotations[50:]
data = {
'output': {
'title': summary,
'summary': summary,
'annotations': to_send
}
}
r = s.patch(check_run['url'], json=data)
r.raise_for_status()
sys.exit(0 if all_ok else 1)

View File

@ -1,14 +1,21 @@
name: Verify pull request target name: Verify pull request target
on: [pull_request] on: [pull_request_target]
jobs: jobs:
check_pr_target: check_pr_target:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Wrong pull request target - name: Send comment if wrong pull request target
run: echo "This pull request targets the master branch. Please edit the pull request to target dev." && exit 1
if: github.base_ref == 'master' if: github.base_ref == 'master'
uses: peter-evans/create-or-update-comment@v1
with:
issue-number: ${{ github.event.number }}
body: |
Hey! This pull request targets the `master` branch. You should probably target `dev` instead. Make sure to read the [contributing guidelines](https://github.com/colobot/colobot/blob/master/CONTRIBUTING.md#submitting-pull-requests) and [edit the target branch if necessary](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/changing-the-base-branch-of-a-pull-request).
- name: Wrong pull request target
if: github.base_ref == 'master'
run: echo "This pull request targets the master branch. Please edit the pull request to target dev." && exit 1
- name: Correct pull request target - name: Correct pull request target
run: echo "This pull request targets the correct branch." && exit 0
if: github.base_ref != 'master' if: github.base_ref != 'master'
run: echo "This pull request targets the correct branch." && exit 0

View File

@ -16,8 +16,8 @@ set(CMAKE_CXX_EXTENSIONS NO)
## ##
set(COLOBOT_VERSION_CODENAME "Gold") set(COLOBOT_VERSION_CODENAME "Gold")
set(COLOBOT_VERSION_MAJOR 0) set(COLOBOT_VERSION_MAJOR 0)
set(COLOBOT_VERSION_MINOR 1) set(COLOBOT_VERSION_MINOR 2)
set(COLOBOT_VERSION_REVISION 12) set(COLOBOT_VERSION_REVISION 0)
# Used on official releases # Used on official releases
#set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha") #set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha")

View File

@ -110,7 +110,7 @@ Easy, isn't it?
If you are lazy, you can just use this one-line command, although there is no guarantee it will work or install everything (might be out of date): If you are lazy, you can just use this one-line command, although there is no guarantee it will work or install everything (might be out of date):
```sh ```sh
pacman -S mingw-w64-i686-boost mingw-w64-i686-glew mingw-w64-i686-libpng gettext mingw-w64-i686-gettext mingw-w64-i686-libpng mingw-w64-i686-libsndfile mingw-w64-i686-libvorbis mingw-w64-i686-libogg mingw-w64-i686-openal mingw-w64-i686-SDL2 mingw-w64-i686-SDL2_image mingw-w64-i686-SDL2_ttf pacman -S mingw-w64-i686-boost mingw-w64-i686-glew mingw-w64-i686-libpng gettext mingw-w64-i686-gettext mingw-w64-i686-libpng mingw-w64-i686-libsndfile mingw-w64-i686-libvorbis mingw-w64-i686-libogg mingw-w64-i686-openal mingw-w64_i686-physfs mingw-w64-i686-SDL2 mingw-w64-i686-SDL2_image mingw-w64-i686-SDL2_ttf
``` ```
You should now have everything set up and working. You can close all instances of MSYS2 and autorebase to ensure everything installed properly. You should now have everything set up and working. You can close all instances of MSYS2 and autorebase to ensure everything installed properly.

View File

@ -31,6 +31,7 @@ On some Linux distributions there are also distribution packages available:
* Arch Linux (AUR): https://aur.archlinux.org/packages/colobot-gold * Arch Linux (AUR): https://aur.archlinux.org/packages/colobot-gold
* openSUSE: http://software.opensuse.org/download.html?project=games&package=colobot * openSUSE: http://software.opensuse.org/download.html?project=games&package=colobot
* Fedora: https://src.fedoraproject.org/rpms/colobot * Fedora: https://src.fedoraproject.org/rpms/colobot
* Guix https://guix.gnu.org/en/packages/colobot-0.1.12-alpha/
## Compiling and running the game ## Compiling and running the game
@ -43,9 +44,4 @@ If you want to contribute to the project, see [CONTRIBUTING.md](CONTRIBUTING.md)
## Contact ## Contact
If you want to help in the project, please contact us on our IRC channels or [our forum](http://colobot.info/forum/). If you want to help in the project, please contact us on our [Discord server](https://discord.gg/56Fm9kb).
### IRC channels
* [#colobot on Freenode](irc://freenode.net#colobot) - main development channel (English);
* [#colobot on pirc.pl](irc://pirc.pl#colobot) - Polish community channel;

2
data

@ -1 +1 @@
Subproject commit 611cbfdd079e97a71f97810636f2ab2358cb4eeb Subproject commit 0ac8197b7a8a005c714b7696d36c642cf0e81474

View File

@ -12,7 +12,7 @@ add_custom_command(OUTPUT ${_potFile}
COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/app/app.cpp --output=${_potFile} --no-wrap COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/app/app.cpp --output=${_potFile} --no-wrap
COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/common/restext.cpp --output=${_potFile} --no-wrap --join-existing --no-location --keyword=TR COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/common/restext.cpp --output=${_potFile} --no-wrap --join-existing --no-location --keyword=TR
COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/script/script.cpp --output=${_potFile} --no-wrap --join-existing --no-location COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/script/script.cpp --output=${_potFile} --no-wrap --join-existing --no-location
COMMAND sed -i -e "s|^\\(\"POT-Creation-Date:\\).*$|\\1 DATE\\\\n\"|" ${_potFile} COMMAND sed -bi -e "s/^\\(\"POT-Creation-Date:\\).*$/\\1 DATE\\\\n\"/" ${_potFile}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Extract translatable messages to ${_potFile}" COMMENT "Extract translatable messages to ${_potFile}"

View File

@ -84,6 +84,12 @@ msgstr ""
msgid "Load a saved mission" msgid "Load a saved mission"
msgstr "" msgstr ""
msgid "Missions+"
msgstr ""
msgid "Mods"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "" msgstr ""
@ -166,6 +172,23 @@ msgstr ""
msgid "This menu is for userlevels from mods, but you didn't install any" msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr "" msgstr ""
msgid "Could not open the file explorer!"
msgstr ""
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "Keyword help(\\key cbot;)" msgid "Keyword help(\\key cbot;)"
msgstr "" msgstr ""
@ -280,6 +303,42 @@ msgstr ""
msgid "%s: %d pts" msgid "%s: %d pts"
msgstr "" msgstr ""
msgid "Mods:"
msgstr ""
msgid "Information:"
msgstr ""
msgid "Description:"
msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Unknown author"
msgstr ""
msgid "by"
msgstr ""
msgid "Version"
msgstr ""
msgid "Website"
msgstr ""
msgid "Changes"
msgstr ""
msgid "No description."
msgstr ""
msgid "No changes."
msgstr ""
msgid "Code battle" msgid "Code battle"
msgstr "" msgstr ""
@ -316,6 +375,9 @@ msgstr ""
msgid "SatCom" msgid "SatCom"
msgstr "" msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "" msgstr ""
@ -340,9 +402,30 @@ msgstr ""
msgid "<< Back \\Back to the previous screen" msgid "<< Back \\Back to the previous screen"
msgstr "" msgstr ""
msgid "+\\Missions with bonus content and optional challenges"
msgstr ""
msgid "Play\\Start mission!" msgid "Play\\Start mission!"
msgstr "" msgstr ""
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "" msgstr ""
@ -415,6 +498,9 @@ msgstr ""
msgid "Pause in background\\Pause the game when the window is unfocused" msgid "Pause in background\\Pause the game when the window is unfocused"
msgstr "" msgstr ""
msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused"
msgstr ""
msgid "Automatic indent\\When program editing" msgid "Automatic indent\\When program editing"
msgstr "" msgstr ""
@ -580,6 +666,15 @@ msgstr ""
msgid "Invert\\Invert values on this axis" msgid "Invert\\Invert values on this axis"
msgstr "" msgstr ""
msgid "Space Programmer\\Disables radio-control"
msgstr ""
msgid "Space Researcher\\Disables using all previously researched technologies"
msgstr ""
msgid "Space Explorer\\Disables astronaut abilities"
msgstr ""
msgid "\\New player name" msgid "\\New player name"
msgstr "" msgstr ""
@ -751,7 +846,7 @@ msgstr ""
msgid "Build a exchange post" msgid "Build a exchange post"
msgstr "" msgstr ""
msgid "Build a destroyer" msgid "Build a vault"
msgstr "" msgstr ""
msgid "Show if the ground is flat" msgid "Show if the ground is flat"

113
po/cs.po
View File

@ -32,6 +32,9 @@ msgstr "Chybí \"]\""
msgid "%s: %d pts" msgid "%s: %d pts"
msgstr "%s: %d bodů" msgstr "%s: %d bodů"
msgid "+\\Missions with bonus content and optional challenges"
msgstr ""
msgid "..behind" msgid "..behind"
msgstr "...za sebou" msgstr "...za sebou"
@ -125,6 +128,9 @@ msgstr "Vzhled\\Upravte svůj vzhled"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Uložit změny\\Aktivovat změny nastavení" msgstr "Uložit změny\\Aktivovat změny nastavení"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Chybí vhodný konstruktor" msgstr "Chybí vhodný konstruktor"
@ -197,9 +203,6 @@ msgstr "Postavit obrannou věž"
msgid "Build a derrick" msgid "Build a derrick"
msgstr "Postavit vrtnou věž" msgstr "Postavit vrtnou věž"
msgid "Build a destroyer"
msgstr "Postavit drtič"
msgid "Build a exchange post" msgid "Build a exchange post"
msgstr "Postavit komunikační stanici" msgstr "Postavit komunikační stanici"
@ -272,6 +275,9 @@ msgstr "Vyrobit pásový kanón"
msgid "Build a tracked sniffer" msgid "Build a tracked sniffer"
msgstr "Vyrobit pásový detektor" msgstr "Vyrobit pásový detektor"
msgid "Build a vault"
msgstr ""
msgid "Build a wheeled builder" msgid "Build a wheeled builder"
msgstr "" msgstr ""
@ -371,6 +377,9 @@ msgstr "Změnit kameru\\Přepíná mezi kamerou na robotu a za robotem"
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Změnit hráče\\Změnit hráče" msgstr "Změnit hráče\\Změnit hráče"
msgid "Changes"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "Kapitoly:" msgstr "Kapitoly:"
@ -440,6 +449,12 @@ msgstr "Kopírovat"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Kopírovat (Ctrl+C)" msgstr "Kopírovat (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Současná mise uložena" msgstr "Současná mise uložena"
@ -473,6 +488,9 @@ msgstr "Vrtná věž"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "Klesat\\Snížit tah tryskového motoru" msgstr "Klesat\\Snížit tah tryskového motoru"
msgid "Description:"
msgstr ""
msgid "Destroy" msgid "Destroy"
msgstr "Zbourat" msgstr "Zbourat"
@ -485,6 +503,9 @@ msgstr "Drtič"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Obrazovka\\Nastavení grafické karty a rozlišení" msgstr "Obrazovka\\Nastavení grafické karty a rozlišení"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Dělení nulou" msgstr "Dělení nulou"
@ -501,6 +522,9 @@ msgstr "Dveře blokuje robot nebo jiný objekt"
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Dolů (\\key gdown;)" msgstr "Dolů (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Tužkobot" msgstr "Tužkobot"
@ -528,6 +552,9 @@ msgstr "Vejce"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing" msgid "End of block missing"
msgstr "Chybí konec bloku" msgstr "Chybí konec bloku"
@ -754,6 +781,9 @@ msgstr "Infikováno virem; dočasně mimo provoz"
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Komunikační stanice" msgstr "Komunikační stanice"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Příkaz \"break\" mimo cyklus" msgstr "Příkaz \"break\" mimo cyklus"
@ -901,9 +931,21 @@ msgstr "Mise"
msgid "Missions on this planet:" msgid "Missions on this planet:"
msgstr "Mise na této planetě:" msgstr "Mise na této planetě:"
msgid "Missions+"
msgstr "Mise+"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Mise\\Vyberte misi" msgstr "Mise\\Vyberte misi"
msgid "Mods"
msgstr ""
msgid "Mods:"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Vodorovné převrácení posunu\\Při vodorovném posunu kamery myší pousouvat opačným směrem" msgstr "Vodorovné převrácení posunu\\Při vodorovném posunu kamery myší pousouvat opačným směrem"
@ -916,6 +958,9 @@ msgstr "Posunout vybraný program níže"
msgid "Move selected program up" msgid "Move selected program up"
msgstr "Posunout vybraný program výše" msgstr "Posunout vybraný program výše"
msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused"
msgstr ""
msgid "Mute\\No sound" msgid "Mute\\No sound"
msgstr "Ticho\\Bez zvuku" msgstr "Ticho\\Bez zvuku"
@ -934,6 +979,9 @@ msgstr "Nový"
msgid "New ..." msgid "New ..."
msgstr "Nový..." msgstr "Nový..."
msgid "New Folder"
msgstr ""
msgid "New bot available" msgid "New bot available"
msgstr "Robot vyroben" msgstr "Robot vyroben"
@ -946,6 +994,12 @@ msgstr "Další objekt\\Vybere následující objekt"
msgid "No" msgid "No"
msgstr "Ne" msgstr "Ne"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Pod povrchem není zdroj energie" msgstr "Pod povrchem není zdroj energie"
@ -1066,6 +1120,9 @@ msgstr "Otevřít"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Otevřít (Ctrl+O)" msgstr "Otevřít (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Chybí levá složená závorka" msgstr "Chybí levá složená závorka"
@ -1090,6 +1147,9 @@ msgstr "Zdroj poslední zprávy\\Zobrazí objekt, který poslal poslední zpráv
msgid "Original game developed by:" msgid "Original game developed by:"
msgstr "Vývojáři původní hry:" msgstr "Vývojáři původní hry:"
msgid "Overwrite existing file?"
msgstr ""
msgid "Parameters missing" msgid "Parameters missing"
msgstr "Některé parametry nejsou vyplněné" msgstr "Některé parametry nejsou vyplněné"
@ -1273,6 +1333,9 @@ msgstr "Červená vlajka"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Odlesky na tlačítkách\\Blyštivá tlačítka" msgstr "Odlesky na tlačítkách\\Blyštivá tlačítka"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Pozůstatky mise Apollo" msgstr "Pozůstatky mise Apollo"
@ -1387,6 +1450,9 @@ msgstr "Uložit\\Uložit současnou misi"
msgid "Save\\Saves the current mission" msgid "Save\\Saves the current mission"
msgstr "Uložit\\Uloží současnou misi" msgstr "Uložit\\Uloží současnou misi"
msgid "Select Folder"
msgstr ""
msgid "Select the astronaut\\Selects the astronaut" msgid "Select the astronaut\\Selects the astronaut"
msgstr "Vybrat kosmonauta\\Vybere kosmonauta" msgstr "Vybrat kosmonauta\\Vybere kosmonauta"
@ -1453,6 +1519,15 @@ msgstr "Zvukové efekty:\\Hlasitost motorů, hlasů, střelby, atd."
msgid "Sound\\Music and game sound volume" msgid "Sound\\Music and game sound volume"
msgstr "Zvuk\\Hlasitost hudby a zvukových efektů" msgstr "Zvuk\\Hlasitost hudby a zvukových efektů"
msgid "Space Explorer\\Disables astronaut abilities"
msgstr ""
msgid "Space Programmer\\Disables radio-control"
msgstr ""
msgid "Space Researcher\\Disables using all previously researched technologies"
msgstr ""
msgid "Spaceship" msgid "Spaceship"
msgstr "Raketa" msgstr "Raketa"
@ -1531,6 +1606,10 @@ msgstr "Filtrování textur\\Filtrování textur"
msgid "Textures" msgid "Textures"
msgstr "Textury" msgstr "Textury"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended" msgid "The battle has ended"
msgstr "Souboj skončil" msgstr "Souboj skončil"
@ -1543,9 +1622,16 @@ msgstr "Funkce nevrátila žádnou hodnotu"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "Mise ještě nebyla splněna (pro podrobnosti stiskněte \\key help;)" msgstr "Mise ještě nebyla splněna (pro podrobnosti stiskněte \\key help;)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Operaci nelze provést s operandy těchto dvou typů" msgstr "Operaci nelze provést s operandy těchto dvou typů"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists" msgid "This class already exists"
msgstr "Tato třída již existuje" msgstr "Tato třída již existuje"
@ -1670,6 +1756,9 @@ msgstr "Jednotka"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Neznámý objekt" msgstr "Neznámý objekt"
msgid "Unknown author"
msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "Neznámý příkaz" msgstr "Neznámý příkaz"
@ -1682,6 +1771,9 @@ msgstr "Neznámá funkce"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Vzhůru (\\key gup;)" msgstr "Vzhůru (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Uranové ložisko (místo pro vrtnou věž)" msgstr "Uranové ložisko (místo pro vrtnou věž)"
@ -1703,6 +1795,9 @@ msgstr "Proměnná nebyla nastavena"
msgid "Vault" msgid "Vault"
msgstr "Trezor" msgstr "Trezor"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "" msgstr ""
@ -1721,6 +1816,9 @@ msgstr "Vosa byla smrtelně raněna"
msgid "Waste" msgid "Waste"
msgstr "Odpad" msgstr "Odpad"
msgid "Website"
msgstr ""
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1754,6 +1852,9 @@ msgstr "Létající detektor"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Vypnout štít (\\key action;)" msgstr "Vypnout štít (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm" msgid "Worm"
msgstr "Červ" msgstr "Červ"
@ -1904,8 +2005,14 @@ msgstr "\\Fialové vlajky"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Žluté vlajky" msgstr "\\Žluté vlajky"
msgid "by"
msgstr ""
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"
msgid "epsitec.com" msgid "epsitec.com"
msgstr "epsitec.com" msgstr "epsitec.com"
#~ msgid "Build a destroyer"
#~ msgstr "Postavit drtič"

104
po/de.po
View File

@ -33,6 +33,9 @@ msgstr "Es fehlt eine geschlossene eckige Klammer \" ] \""
msgid "%s: %d pts" msgid "%s: %d pts"
msgstr "" msgstr ""
msgid "+\\Missions with bonus content and optional challenges"
msgstr ""
msgid "..behind" msgid "..behind"
msgstr "..hinten" msgstr "..hinten"
@ -126,6 +129,9 @@ msgstr "Aussehen\\Erscheinungsbild des Astronauten einstellen"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Änderungen anwenden\\Getätigte Einstellungen anwenden" msgstr "Änderungen anwenden\\Getätigte Einstellungen anwenden"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Es gibt keinen geeigneten Konstruktor" msgstr "Es gibt keinen geeigneten Konstruktor"
@ -198,9 +204,6 @@ msgstr "Baut einen Geschützturm"
msgid "Build a derrick" msgid "Build a derrick"
msgstr "Baut einen Bohrturm" msgstr "Baut einen Bohrturm"
msgid "Build a destroyer"
msgstr "Baue einen Zerstörer"
msgid "Build a exchange post" msgid "Build a exchange post"
msgstr "Baut einen Infoserver" msgstr "Baut einen Infoserver"
@ -273,6 +276,9 @@ msgstr "Baut einen Kettenshooter"
msgid "Build a tracked sniffer" msgid "Build a tracked sniffer"
msgstr "Baut einen Kettenschnüffler" msgstr "Baut einen Kettenschnüffler"
msgid "Build a vault"
msgstr ""
msgid "Build a wheeled builder" msgid "Build a wheeled builder"
msgstr "" msgstr ""
@ -372,6 +378,9 @@ msgstr "Andere Kamera\\Sichtpunkt einstellen"
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Anderer Spieler\\Spielername ändern" msgstr "Anderer Spieler\\Spielername ändern"
msgid "Changes"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "Liste der Kapitel:" msgstr "Liste der Kapitel:"
@ -441,6 +450,12 @@ msgstr "Kopieren"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Kopieren (Ctrl+C)" msgstr "Kopieren (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Mission gespeichert" msgstr "Mission gespeichert"
@ -474,6 +489,9 @@ msgstr "Bohrturm"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "Sinken\\Leistung des Triebwerks drosseln" msgstr "Sinken\\Leistung des Triebwerks drosseln"
msgid "Description:"
msgstr ""
msgid "Destroy" msgid "Destroy"
msgstr "Zerstören" msgstr "Zerstören"
@ -486,6 +504,9 @@ msgstr "Einstampfer"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Bildschirm\\Driver und Bildschirmauflösung" msgstr "Bildschirm\\Driver und Bildschirmauflösung"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Division durch Null" msgstr "Division durch Null"
@ -502,6 +523,9 @@ msgstr "Die Türen werden von einem Gegenstand blockiert"
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Sinkt (\\key gdown;)" msgstr "Sinkt (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Zeichner" msgstr "Zeichner"
@ -529,6 +553,9 @@ msgstr "Ei"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing" msgid "End of block missing"
msgstr "Es fehlt eine geschlossene geschweifte Klammer \"}\" (Ende des Blocks)" msgstr "Es fehlt eine geschlossene geschweifte Klammer \"}\" (Ende des Blocks)"
@ -756,6 +783,9 @@ msgstr "Von Virus infiziert, zeitweise außer Betrieb"
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Infoserver" msgstr "Infoserver"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Anweisung \"break\" außerhalb einer Schleife" msgstr "Anweisung \"break\" außerhalb einer Schleife"
@ -917,9 +947,21 @@ msgstr "Missionen"
msgid "Missions on this planet:" msgid "Missions on this planet:"
msgstr "Liste der Missionen des Planeten:" msgstr "Liste der Missionen des Planeten:"
msgid "Missions+"
msgstr "Missionen+"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Missionen\\Aufbruch ins Weltall" msgstr "Missionen\\Aufbruch ins Weltall"
msgid "Mods"
msgstr ""
msgid "Mods:"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Umkehr X\\Umkehr der Kameradrehung X-Achse" msgstr "Umkehr X\\Umkehr der Kameradrehung X-Achse"
@ -932,6 +974,9 @@ msgstr "Gewähltes Programm nach unten"
msgid "Move selected program up" msgid "Move selected program up"
msgstr "Gewähltes Programm nach oben" msgstr "Gewähltes Programm nach oben"
msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused"
msgstr ""
msgid "Mute\\No sound" msgid "Mute\\No sound"
msgstr "Kein Ton\\Keine Geräusche und Geräuschkulisse" msgstr "Kein Ton\\Keine Geräusche und Geräuschkulisse"
@ -965,6 +1010,12 @@ msgstr "Nächstes auswählen\\Nächstes Objekt auswählen"
msgid "No" msgid "No"
msgstr "Nein" msgstr "Nein"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Kein unterirdisches Energievorkommen" msgstr "Kein unterirdisches Energievorkommen"
@ -1085,6 +1136,9 @@ msgstr "Öffnen"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Öffnen (Ctrl+O)" msgstr "Öffnen (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Es fehlt eine offene geschweifte Klammer\"{\"" msgstr "Es fehlt eine offene geschweifte Klammer\"{\""
@ -1296,6 +1350,9 @@ msgstr "Rote Fahne"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Glänzende Tasten\\Glänzende Tasten in den Menüs" msgstr "Glänzende Tasten\\Glänzende Tasten in den Menüs"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Überreste einer Apollo-Mission" msgstr "Überreste einer Apollo-Mission"
@ -1479,6 +1536,15 @@ msgstr "Geräusche:\\Lautstärke Motoren, Stimmen, usw."
msgid "Sound\\Music and game sound volume" msgid "Sound\\Music and game sound volume"
msgstr "Geräusche\\Lautstärke Geräusche und Musik" msgstr "Geräusche\\Lautstärke Geräusche und Musik"
msgid "Space Explorer\\Disables astronaut abilities"
msgstr ""
msgid "Space Programmer\\Disables radio-control"
msgstr ""
msgid "Space Researcher\\Disables using all previously researched technologies"
msgstr ""
msgid "Spaceship" msgid "Spaceship"
msgstr "Raumschiff" msgstr "Raumschiff"
@ -1557,6 +1623,10 @@ msgstr "Texturfilterung\\Texturfilterung"
msgid "Textures" msgid "Textures"
msgstr "Texturen" msgstr "Texturen"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended" msgid "The battle has ended"
msgstr "" msgstr ""
@ -1569,9 +1639,16 @@ msgstr "Die Funktion hat kein Ergebnis zurückgegeben"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "Mission noch nicht beendet (Drücken Sie auf \\key help; für weitere Informationen)" msgstr "Mission noch nicht beendet (Drücken Sie auf \\key help; für weitere Informationen)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Die zwei Operanden sind nicht kompatibel" msgstr "Die zwei Operanden sind nicht kompatibel"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists" msgid "This class already exists"
msgstr "Diese Klasse gibt es schon" msgstr "Diese Klasse gibt es schon"
@ -1696,6 +1773,9 @@ msgstr "Einheit"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Das Objekt existiert nicht" msgstr "Das Objekt existiert nicht"
msgid "Unknown author"
msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "Befehl unbekannt" msgstr "Befehl unbekannt"
@ -1708,6 +1788,9 @@ msgstr "Unbekannte Funktion"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Steigt (\\key gup;)" msgstr "Steigt (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Markierung für unterirdisches Platinvorkommen" msgstr "Markierung für unterirdisches Platinvorkommen"
@ -1729,6 +1812,9 @@ msgstr "Der Wert dieser Variable wurde nicht definiert"
msgid "Vault" msgid "Vault"
msgstr "Bunker" msgstr "Bunker"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "" msgstr ""
@ -1747,6 +1833,9 @@ msgstr "Wespe tödlich verwundet"
msgid "Waste" msgid "Waste"
msgstr "Abfall" msgstr "Abfall"
msgid "Website"
msgstr ""
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1780,6 +1869,9 @@ msgstr "Schnüffler"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Schutzschild einholen (\\key action;)" msgstr "Schutzschild einholen (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm" msgid "Worm"
msgstr "Wurm" msgstr "Wurm"
@ -1928,6 +2020,9 @@ msgstr "\\Violette Fahne"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Gelbe Fahne" msgstr "\\Gelbe Fahne"
msgid "by"
msgstr ""
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"
@ -1949,6 +2044,9 @@ msgstr "epsitec.com"
#~ msgid "3D sound\\3D positioning of the sound" #~ msgid "3D sound\\3D positioning of the sound"
#~ msgstr "3D-Geräusche\\Orten der Geräusche im Raum" #~ msgstr "3D-Geräusche\\Orten der Geräusche im Raum"
#~ msgid "Build a destroyer"
#~ msgstr "Baue einen Zerstörer"
#~ msgid "Building too close" #~ msgid "Building too close"
#~ msgstr "Gebäude zu nahe" #~ msgstr "Gebäude zu nahe"

104
po/fr.po
View File

@ -32,6 +32,9 @@ msgstr "\" ] \" manquant"
msgid "%s: %d pts" msgid "%s: %d pts"
msgstr "%s: %d points" msgstr "%s: %d points"
msgid "+\\Missions with bonus content and optional challenges"
msgstr ""
msgid "..behind" msgid "..behind"
msgstr "..derrière" msgstr "..derrière"
@ -125,6 +128,9 @@ msgstr "Aspect\\Choisir votre aspect"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Appliquer les changements\\Active les changements effectués" msgstr "Appliquer les changements\\Active les changements effectués"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Constructeur approprié manquant" msgstr "Constructeur approprié manquant"
@ -200,9 +206,6 @@ msgstr "Construire une tour"
msgid "Build a derrick" msgid "Build a derrick"
msgstr "Construire un derrick" msgstr "Construire un derrick"
msgid "Build a destroyer"
msgstr "Construire un destructeur"
msgid "Build a exchange post" msgid "Build a exchange post"
msgstr "Construire une station relais" msgstr "Construire une station relais"
@ -275,6 +278,9 @@ msgstr "Fabriquer un tireur à chenilles"
msgid "Build a tracked sniffer" msgid "Build a tracked sniffer"
msgstr "Fabriquer un renifleur à chenilles" msgstr "Fabriquer un renifleur à chenilles"
msgid "Build a vault"
msgstr ""
msgid "Build a wheeled builder" msgid "Build a wheeled builder"
msgstr "" msgstr ""
@ -374,6 +380,9 @@ msgstr "Changement de caméra\\Autre de point de vue"
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Autre joueur\\Choix du nom du joueur" msgstr "Autre joueur\\Choix du nom du joueur"
msgid "Changes"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "Liste des chapitres :" msgstr "Liste des chapitres :"
@ -443,6 +452,12 @@ msgstr "Copier"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Copier (Ctrl+C)" msgstr "Copier (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Enregistrement effectué" msgstr "Enregistrement effectué"
@ -476,6 +491,9 @@ msgstr "Derrick"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "Descendre\\Diminuer la puissance du réacteur" msgstr "Descendre\\Diminuer la puissance du réacteur"
msgid "Description:"
msgstr ""
msgid "Destroy" msgid "Destroy"
msgstr "Détruire" msgstr "Détruire"
@ -488,6 +506,9 @@ msgstr "Destructeur"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Affichage\\Pilote et résolution d'affichage" msgstr "Affichage\\Pilote et résolution d'affichage"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Division par zéro" msgstr "Division par zéro"
@ -504,6 +525,9 @@ msgstr "Portes bloquées par un robot ou un objet"
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Descend (\\key gdown;)" msgstr "Descend (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Robot dessinateur" msgstr "Robot dessinateur"
@ -531,6 +555,9 @@ msgstr "Oeuf"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing" msgid "End of block missing"
msgstr "Il manque la fin du bloc" msgstr "Il manque la fin du bloc"
@ -758,6 +785,9 @@ msgstr "Infecté par un virus; ne fonctionne plus temporairement"
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Station relais" msgstr "Station relais"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Instruction \"break\" en dehors d'une boucle" msgstr "Instruction \"break\" en dehors d'une boucle"
@ -919,9 +949,21 @@ msgstr "Missions"
msgid "Missions on this planet:" msgid "Missions on this planet:"
msgstr "Liste des missions du chapitre :" msgstr "Liste des missions du chapitre :"
msgid "Missions+"
msgstr "Missions+"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Missions\\La grande aventure" msgstr "Missions\\La grande aventure"
msgid "Mods"
msgstr ""
msgid "Mods:"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Inversion souris X\\Inversion de la rotation lorsque la souris touche un bord" msgstr "Inversion souris X\\Inversion de la rotation lorsque la souris touche un bord"
@ -934,6 +976,9 @@ msgstr "Déplace le programme sélectionné vers le bas"
msgid "Move selected program up" msgid "Move selected program up"
msgstr "Déplace le programme sélectionné vers le haut" msgstr "Déplace le programme sélectionné vers le haut"
msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused"
msgstr ""
msgid "Mute\\No sound" msgid "Mute\\No sound"
msgstr "Silencieux\\Totalement silencieux" msgstr "Silencieux\\Totalement silencieux"
@ -967,6 +1012,12 @@ msgstr "Sélectionner l'objet suivant\\Sélectionner l'objet suivant"
msgid "No" msgid "No"
msgstr "Non" msgstr "Non"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Pas d'énergie en sous-sol" msgstr "Pas d'énergie en sous-sol"
@ -1087,6 +1138,9 @@ msgstr "Ouvrir"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Ouvrir (Ctrl+O)" msgstr "Ouvrir (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Début d'un bloc attendu" msgstr "Début d'un bloc attendu"
@ -1298,6 +1352,9 @@ msgstr "Drapeau rouge"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Reflets sur les boutons\\Boutons brillants" msgstr "Reflets sur les boutons\\Boutons brillants"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Vestige d'une mission Apollo" msgstr "Vestige d'une mission Apollo"
@ -1481,6 +1538,15 @@ msgstr "Sons :\\Volume des moteurs, voix, etc."
msgid "Sound\\Music and game sound volume" msgid "Sound\\Music and game sound volume"
msgstr "Son\\Volumes des sons & musiques" msgstr "Son\\Volumes des sons & musiques"
msgid "Space Explorer\\Disables astronaut abilities"
msgstr ""
msgid "Space Programmer\\Disables radio-control"
msgstr ""
msgid "Space Researcher\\Disables using all previously researched technologies"
msgstr ""
msgid "Spaceship" msgid "Spaceship"
msgstr "Vaisseau spatial" msgstr "Vaisseau spatial"
@ -1559,6 +1625,10 @@ msgstr "Filtrage de textures\\Filtrage de textures"
msgid "Textures" msgid "Textures"
msgstr "Textures" msgstr "Textures"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended" msgid "The battle has ended"
msgstr "La bataille est terminée" msgstr "La bataille est terminée"
@ -1571,9 +1641,16 @@ msgstr "La fonction n'a pas retourné de résultat"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "La mission n'est pas terminée (appuyez sur \\key help; pour plus de détails)" msgstr "La mission n'est pas terminée (appuyez sur \\key help; pour plus de détails)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Les deux opérandes ne sont pas de types compatibles" msgstr "Les deux opérandes ne sont pas de types compatibles"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists" msgid "This class already exists"
msgstr "Cette classe existe déjà" msgstr "Cette classe existe déjà"
@ -1698,6 +1775,9 @@ msgstr "Unité"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Objet inconnu" msgstr "Objet inconnu"
msgid "Unknown author"
msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "Commande inconnue" msgstr "Commande inconnue"
@ -1710,6 +1790,9 @@ msgstr "Routine inconnue"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Monte (\\key gup;)" msgstr "Monte (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Emplacement pour un derrick (minerai d'uranium)" msgstr "Emplacement pour un derrick (minerai d'uranium)"
@ -1731,6 +1814,9 @@ msgstr "Variable non initialisée"
msgid "Vault" msgid "Vault"
msgstr "Coffre-fort" msgstr "Coffre-fort"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "Synchronisation verticale :\\Réduit la fréquence d'images par seconde à afficher." msgstr "Synchronisation verticale :\\Réduit la fréquence d'images par seconde à afficher."
@ -1749,6 +1835,9 @@ msgstr "Guêpe mortellement touchée"
msgid "Waste" msgid "Waste"
msgstr "Déchet" msgstr "Déchet"
msgid "Website"
msgstr ""
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1782,6 +1871,9 @@ msgstr "Robot renifleur volant"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Refermer le bouclier (\\key action;)" msgstr "Refermer le bouclier (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm" msgid "Worm"
msgstr "Ver" msgstr "Ver"
@ -1930,6 +2022,9 @@ msgstr "\\Drapeaux violets"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Drapeaux jaunes" msgstr "\\Drapeaux jaunes"
msgid "by"
msgstr ""
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"
@ -1948,6 +2043,9 @@ msgstr "epsitec.com"
#~ msgid "3D sound\\3D positioning of the sound" #~ msgid "3D sound\\3D positioning of the sound"
#~ msgstr "Bruitages 3D\\Positionnement sonore dans l'espace" #~ msgstr "Bruitages 3D\\Positionnement sonore dans l'espace"
#~ msgid "Build a destroyer"
#~ msgstr "Construire un destructeur"
#~ msgid "Building too close" #~ msgid "Building too close"
#~ msgstr "Bâtiment trop proche" #~ msgstr "Bâtiment trop proche"

146
po/pl.po
View File

@ -31,6 +31,9 @@ msgstr "Brak \" ] \""
msgid "%s: %d pts" msgid "%s: %d pts"
msgstr "%s: %d pkt" msgstr "%s: %d pkt"
msgid "+\\Missions with bonus content and optional challenges"
msgstr "+\\Misje z dodatkową zawartością i opcjonalnymi wyzwaniami"
msgid "..behind" msgid "..behind"
msgstr "..za" msgstr "..za"
@ -124,6 +127,9 @@ msgstr "Wygląd\\Wybierz swoją postać"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Zastosuj zmiany\\Aktywuje zmienione ustawienia" msgstr "Zastosuj zmiany\\Aktywuje zmienione ustawienia"
msgid "Apply\\Apply the current mod configuration"
msgstr "Zastosuj\\Zastosuj obecną konfigurację modów"
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Brak odpowiedniego konstruktora" msgstr "Brak odpowiedniego konstruktora"
@ -182,7 +188,7 @@ msgid "Bot factory"
msgstr "Fabryka robotów" msgstr "Fabryka robotów"
msgid "Build (\\key action;)" msgid "Build (\\key action;)"
msgstr "" msgstr "Buduj (\\key action;)"
msgid "Build a bot factory" msgid "Build a bot factory"
msgstr "Zbuduj fabrykę robotów" msgstr "Zbuduj fabrykę robotów"
@ -196,14 +202,11 @@ msgstr "Zbuduj wieżę obronną"
msgid "Build a derrick" msgid "Build a derrick"
msgstr "Zbuduj kopalnię" msgstr "Zbuduj kopalnię"
msgid "Build a destroyer"
msgstr "Zbuduj niszczarkę"
msgid "Build a exchange post" msgid "Build a exchange post"
msgstr "Zbuduj stację przekaźnikową" msgstr "Zbuduj stację przekaźnikową"
msgid "Build a legged builder" msgid "Build a legged builder"
msgstr "" msgstr "Zbuduj budowniczego na nogach"
msgid "Build a legged grabber" msgid "Build a legged grabber"
msgstr "Zbuduj transporter na nogach" msgstr "Zbuduj transporter na nogach"
@ -251,13 +254,13 @@ msgid "Build a subber"
msgstr "Zbuduj robota nurka" msgstr "Zbuduj robota nurka"
msgid "Build a target bot" msgid "Build a target bot"
msgstr "" msgstr "Zbuduj robota-cel"
msgid "Build a thumper" msgid "Build a thumper"
msgstr "Zbuduj robota uderzacza" msgstr "Zbuduj robota uderzacza"
msgid "Build a tracked builder" msgid "Build a tracked builder"
msgstr "" msgstr "Zbuduj budowniczego na gąsienicach"
msgid "Build a tracked grabber" msgid "Build a tracked grabber"
msgstr "Zbuduj transporter na gąsienicach" msgstr "Zbuduj transporter na gąsienicach"
@ -271,8 +274,11 @@ msgstr "Zbuduj działo na gąsienicach"
msgid "Build a tracked sniffer" msgid "Build a tracked sniffer"
msgstr "Zbuduj szperacz na gąsienicach" msgstr "Zbuduj szperacz na gąsienicach"
msgid "Build a vault"
msgstr "Zbuduj skrytkę"
msgid "Build a wheeled builder" msgid "Build a wheeled builder"
msgstr "" msgstr "Zbuduj budowniczego na kołach"
msgid "Build a wheeled grabber" msgid "Build a wheeled grabber"
msgstr "Zbuduj transporter na kołach" msgstr "Zbuduj transporter na kołach"
@ -287,7 +293,7 @@ msgid "Build a wheeled sniffer"
msgstr "Zbuduj szperacz na kołach" msgstr "Zbuduj szperacz na kołach"
msgid "Build a winged builder" msgid "Build a winged builder"
msgstr "" msgstr "Zbuduj latającego budowniczego"
msgid "Build a winged grabber" msgid "Build a winged grabber"
msgstr "Zbuduj transporter latający" msgstr "Zbuduj transporter latający"
@ -370,6 +376,9 @@ msgstr "Zmień kamerę\\Przełącza pomiędzy kamerą pokładową i śledzącą"
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Zmień gracza\\Zmień gracza" msgstr "Zmień gracza\\Zmień gracza"
msgid "Changes"
msgstr "Zmiany"
msgid "Chapters:" msgid "Chapters:"
msgstr "Rozdziały:" msgstr "Rozdziały:"
@ -439,6 +448,12 @@ msgstr "Kopiuj"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Kopiuj (Ctrl+C)" msgstr "Kopiuj (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr "Nie udało się otworzyć przeglądarki plików!"
msgid "Could not open the web browser!"
msgstr "Nie udało się otworzyć przeglądarki internetowej!"
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Bieżąca misja zapisana" msgstr "Bieżąca misja zapisana"
@ -472,6 +487,9 @@ msgstr "Kopalnia"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "W dół\\Zmniejsza moc silnika" msgstr "W dół\\Zmniejsza moc silnika"
msgid "Description:"
msgstr "Opis:"
msgid "Destroy" msgid "Destroy"
msgstr "Zniszcz" msgstr "Zniszcz"
@ -484,6 +502,9 @@ msgstr "Destroyer"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Urządzenie\\Ustawienia sterownika i rozdzielczości" msgstr "Urządzenie\\Ustawienia sterownika i rozdzielczości"
msgid "Disable\\Disable the selected mod"
msgstr "Wyłącz\\Wyłącza zaznaczonego moda"
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Dzielenie przez zero" msgstr "Dzielenie przez zero"
@ -500,11 +521,14 @@ msgstr "Drzwi zablokowane przez robota lub inny obiekt"
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Dół (\\key gdown;)" msgstr "Dół (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr "W dół\\Przenieś zaznaczonego moda w dół, aby był załadowany później (mody mogą nadpisywać pliki modów wyżej)"
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Robot rysownik" msgstr "Robot rysownik"
msgid "Duplicate label in switch" msgid "Duplicate label in switch"
msgstr "" msgstr "Zduplikowana wartość w instrukcji switch"
msgid "Dust\\Dust and dirt on bots and buildings" msgid "Dust\\Dust and dirt on bots and buildings"
msgstr "Kurz\\Kurz i bród na robotach i budynkach" msgstr "Kurz\\Kurz i bród na robotach i budynkach"
@ -525,7 +549,10 @@ msgid "Egg"
msgstr "Jajo" msgstr "Jajo"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr "Stała będąca pustym znakiem"
msgid "Enable\\Enable the selected mod"
msgstr "Włącz\\Włącza zaznaczonego moda"
msgid "End of block missing" msgid "End of block missing"
msgstr "Brak końca bloku" msgstr "Brak końca bloku"
@ -742,7 +769,7 @@ msgid "Inappropriate object"
msgstr "Nieodpowiedni obiekt" msgstr "Nieodpowiedni obiekt"
msgid "Inappropriate sample" msgid "Inappropriate sample"
msgstr "" msgstr "Nieprawidłowa próbka"
msgid "Incorrect index type" msgid "Incorrect index type"
msgstr "Nieprawidłowy typ indeksu" msgstr "Nieprawidłowy typ indeksu"
@ -753,6 +780,9 @@ msgstr "Zainfekowane wirusem, chwilowo niesprawne"
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Stacja przekaźnikowa informacji" msgstr "Stacja przekaźnikowa informacji"
msgid "Information:"
msgstr "Informacje:"
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Polecenie \"break\" na zewnątrz pętli" msgstr "Polecenie \"break\" na zewnątrz pętli"
@ -784,7 +814,7 @@ msgid "Internal error - tell the developers"
msgstr "Błąd wewnętrzny - powiadom twórców gry" msgstr "Błąd wewnętrzny - powiadom twórców gry"
msgid "Invalid universal character name" msgid "Invalid universal character name"
msgstr "" msgstr "Nieprawidłowy znak Unicode"
msgid "Invert\\Invert values on this axis" msgid "Invert\\Invert values on this axis"
msgstr "Odwróć\\Odwróć wartości na tej osi" msgstr "Odwróć\\Odwróć wartości na tej osi"
@ -814,7 +844,7 @@ msgid "LOADING"
msgstr "WCZYTYWANIE" msgstr "WCZYTYWANIE"
msgid "Legged builder" msgid "Legged builder"
msgstr "" msgstr "Budowniczy na nogach"
msgid "Legged grabber" msgid "Legged grabber"
msgstr "Transporter na nogach" msgstr "Transporter na nogach"
@ -900,9 +930,21 @@ msgstr "Misje"
msgid "Missions on this planet:" msgid "Missions on this planet:"
msgstr "Misje na tej planecie:" msgstr "Misje na tej planecie:"
msgid "Missions+"
msgstr "Misje+"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Misje\\Wybierz misję" msgstr "Misje\\Wybierz misję"
msgid "Mods"
msgstr "Mody"
msgid "Mods:"
msgstr "Mody:"
msgid "Mods\\Mod manager"
msgstr "Mody\\Zarządzanie modami"
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Odwrócenie myszy X\\Odwrócenie kierunków przewijania w poziomie" msgstr "Odwrócenie myszy X\\Odwrócenie kierunków przewijania w poziomie"
@ -915,6 +957,9 @@ msgstr "Przenieś zaznaczony program w dół"
msgid "Move selected program up" msgid "Move selected program up"
msgstr "Przenieś zaznaczony program w górę" msgstr "Przenieś zaznaczony program w górę"
msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused"
msgstr "Cisza, gdy okno jest w tle\\Wycisza wszystkie dźwięki, gdy okno gry stanie się nieaktywne"
msgid "Mute\\No sound" msgid "Mute\\No sound"
msgstr "Cisza\\Brak dźwięków" msgstr "Cisza\\Brak dźwięków"
@ -934,7 +979,7 @@ msgid "New ..."
msgstr "Nowy ..." msgstr "Nowy ..."
msgid "New Folder" msgid "New Folder"
msgstr "" msgstr "Nowy folder"
msgid "New bot available" msgid "New bot available"
msgstr "Dostępny nowy robot" msgstr "Dostępny nowy robot"
@ -948,6 +993,12 @@ msgstr "Następny obiekt\\Zaznacza następny obiekt"
msgid "No" msgid "No"
msgstr "Nie" msgstr "Nie"
msgid "No changes."
msgstr "Brak zmian."
msgid "No description."
msgstr "Brak opisu."
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Brak energii w ziemi" msgstr "Brak energii w ziemi"
@ -1068,6 +1119,9 @@ msgstr "Otwórz"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Otwórz (Ctrl+O)" msgstr "Otwórz (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr "Otwórz katalog\\Otwórz katalog z modami"
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Brak klamry otwierającej" msgstr "Brak klamry otwierającej"
@ -1093,7 +1147,7 @@ msgid "Original game developed by:"
msgstr "Twórcy oryginalnej gry:" msgstr "Twórcy oryginalnej gry:"
msgid "Overwrite existing file?" msgid "Overwrite existing file?"
msgstr "" msgstr "Nadpisać istniejący plik?"
msgid "Parameters missing" msgid "Parameters missing"
msgstr "Brak wymaganego parametru" msgstr "Brak wymaganego parametru"
@ -1129,7 +1183,7 @@ msgid "Planets:"
msgstr "Planety:" msgstr "Planety:"
msgid "Plans for builder available" msgid "Plans for builder available"
msgstr "" msgstr "Dostępne plany robota budowniczego"
msgid "Plans for defense tower available" msgid "Plans for defense tower available"
msgstr "Dostępne plany wieży obronnej" msgstr "Dostępne plany wieży obronnej"
@ -1278,6 +1332,9 @@ msgstr "Czerwona flaga"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Odbicia na przyciskach \\Świecące przyciski" msgstr "Odbicia na przyciskach \\Świecące przyciski"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr "Odśwież\\Odśwież listę obecnie zainstalowanych modów"
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Pozostałości z misji Apollo" msgstr "Pozostałości z misji Apollo"
@ -1336,7 +1393,7 @@ msgid "Ruin"
msgstr "Ruiny" msgstr "Ruiny"
msgid "Run research program for builder" msgid "Run research program for builder"
msgstr "" msgstr "Rozpocznij prace badawcze nad robotem budowniczym"
msgid "Run research program for defense tower" msgid "Run research program for defense tower"
msgstr "Rozpocznij prace badawcze nad wieżą obronną" msgstr "Rozpocznij prace badawcze nad wieżą obronną"
@ -1360,7 +1417,7 @@ msgid "Run research program for shooter"
msgstr "Rozpocznij prace badawcze nad działem" msgstr "Rozpocznij prace badawcze nad działem"
msgid "Run research program for target bot" msgid "Run research program for target bot"
msgstr "" msgstr "Rozpocznij prace badawcze nad robotem-celem"
msgid "Run research program for thumper" msgid "Run research program for thumper"
msgstr "Rozpocznij prace badawcze nad robotem uderzaczem" msgstr "Rozpocznij prace badawcze nad robotem uderzaczem"
@ -1393,7 +1450,7 @@ msgid "Save\\Saves the current mission"
msgstr "Zapisz\\Zapisuje bieżącą misję" msgstr "Zapisz\\Zapisuje bieżącą misję"
msgid "Select Folder" msgid "Select Folder"
msgstr "" msgstr "Wybierz folder"
msgid "Select the astronaut\\Selects the astronaut" msgid "Select the astronaut\\Selects the astronaut"
msgstr "Zaznacz astronautę\\Zaznacza astronautę" msgstr "Zaznacz astronautę\\Zaznacza astronautę"
@ -1461,6 +1518,15 @@ msgstr "Efekty dźwiękowe:\\Głośność silników, głosów, strzałów, itp."
msgid "Sound\\Music and game sound volume" msgid "Sound\\Music and game sound volume"
msgstr "Dźwięk\\Głośność muzyki i dźwięków gry" msgstr "Dźwięk\\Głośność muzyki i dźwięków gry"
msgid "Space Explorer\\Disables astronaut abilities"
msgstr "Kosmiczny odkrywca\\Wyłącza umiejętności astronauty"
msgid "Space Programmer\\Disables radio-control"
msgstr "Kosmiczny koder\\Wyłącza zdalną kontrolę"
msgid "Space Researcher\\Disables using all previously researched technologies"
msgstr "Kosmiczny badacz\\Blokuje dostęp do poprzednio wynalezionych technologii"
msgid "Spaceship" msgid "Spaceship"
msgstr "Statek kosmiczny" msgstr "Statek kosmiczny"
@ -1539,6 +1605,10 @@ msgstr "Filtrowanie tekstur\\Filtrowanie tekstur"
msgid "Textures" msgid "Textures"
msgstr "Tekstury" msgstr "Tekstury"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr "Nie udało się otworzyć adresu %s w przeglądarce internetowej."
msgid "The battle has ended" msgid "The battle has ended"
msgstr "Bitwa zakończyła się" msgstr "Bitwa zakończyła się"
@ -1551,9 +1621,16 @@ msgstr "Funkcja nie zwróciła żadnej wartości"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "Misja nie jest wypełniona (naciśnij \\key help; aby uzyskać szczegóły)" msgstr "Misja nie jest wypełniona (naciśnij \\key help; aby uzyskać szczegóły)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr "Nie udało się otworzyć ścieżki %s w przeglądarce plików."
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Niezgodne typy operatorów" msgstr "Niezgodne typy operatorów"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr "Są niezapisane zmiany. Czy chcesz je zapisać przed wyjściem?"
msgid "This class already exists" msgid "This class already exists"
msgstr "Taka klasa już istnieje" msgstr "Taka klasa już istnieje"
@ -1628,7 +1705,7 @@ msgid "Too many parameters"
msgstr "Za dużo parametrów" msgstr "Za dużo parametrów"
msgid "Tracked builder" msgid "Tracked builder"
msgstr "" msgstr "Budowniczy na gąsienicach"
msgid "Tracked grabber" msgid "Tracked grabber"
msgstr "Transporter na gąsienicach" msgstr "Transporter na gąsienicach"
@ -1678,11 +1755,14 @@ msgstr "Jednostka"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Obiekt nieznany" msgstr "Obiekt nieznany"
msgid "Unknown author"
msgstr "Nieznany autor"
msgid "Unknown command" msgid "Unknown command"
msgstr "Nieznane polecenie" msgstr "Nieznane polecenie"
msgid "Unknown escape sequence" msgid "Unknown escape sequence"
msgstr "" msgstr "Nieznany znak ucieczki"
msgid "Unknown function" msgid "Unknown function"
msgstr "Funkcja nieznana" msgstr "Funkcja nieznana"
@ -1690,6 +1770,9 @@ msgstr "Funkcja nieznana"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Góra (\\key gup;)" msgstr "Góra (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr "W górę\\Przenieś zaznaczonego moda w górę, aby był załadowany wcześniej (mody mogą nadpisywać pliki modów wyżej)"
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Złoże uranu (miejsce na kopalnię)" msgstr "Złoże uranu (miejsce na kopalnię)"
@ -1711,6 +1794,9 @@ msgstr "Zmienna nie została zainicjalizowana"
msgid "Vault" msgid "Vault"
msgstr "Skrytka" msgstr "Skrytka"
msgid "Version"
msgstr "Wersja"
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "Synchronizacja pionowa\\Ogranicza ilość klatek na sekundę do wartości odświeżania ekranu" msgstr "Synchronizacja pionowa\\Ogranicza ilość klatek na sekundę do wartości odświeżania ekranu"
@ -1729,8 +1815,11 @@ msgstr "Osa śmiertelnie raniona"
msgid "Waste" msgid "Waste"
msgstr "Odpady" msgstr "Odpady"
msgid "Website"
msgstr "Strona internetowa"
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr "Budowniczy na kołach"
msgid "Wheeled grabber" msgid "Wheeled grabber"
msgstr "Transporter na kołach" msgstr "Transporter na kołach"
@ -1745,7 +1834,7 @@ msgid "Wheeled sniffer"
msgstr "Szperacz na kołach" msgstr "Szperacz na kołach"
msgid "Winged builder" msgid "Winged builder"
msgstr "" msgstr "Budowniczy latający"
msgid "Winged grabber" msgid "Winged grabber"
msgstr "Transporter latający" msgstr "Transporter latający"
@ -1762,6 +1851,9 @@ msgstr "Szperacz latający"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Wyłącz osłonę (\\key action;)" msgstr "Wyłącz osłonę (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr "Warsztat\\Otwórz warsztat, aby poszukać modów"
msgid "Worm" msgid "Worm"
msgstr "Robal" msgstr "Robal"
@ -1912,6 +2004,9 @@ msgstr "\\Fioletowe flagi"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Żółte flagi" msgstr "\\Żółte flagi"
msgid "by"
msgstr "autorstwa"
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"
@ -1927,6 +2022,9 @@ msgstr "epsitec.com"
#~ msgid "3D sound\\3D positioning of the sound" #~ msgid "3D sound\\3D positioning of the sound"
#~ msgstr "Dźwięk 3D\\Przestrzenne pozycjonowanie dźwięków" #~ msgstr "Dźwięk 3D\\Przestrzenne pozycjonowanie dźwięków"
#~ msgid "Build a destroyer"
#~ msgstr "Zbuduj niszczarkę"
#~ msgid "Building too close" #~ msgid "Building too close"
#~ msgstr "Budynek za blisko" #~ msgstr "Budynek za blisko"

113
po/pt.po
View File

@ -29,6 +29,9 @@ msgstr "\" ] \" faltando"
msgid "%s: %d pts" msgid "%s: %d pts"
msgstr "" msgstr ""
msgid "+\\Missions with bonus content and optional challenges"
msgstr ""
msgid "..behind" msgid "..behind"
msgstr "..atrás" msgstr "..atrás"
@ -122,6 +125,9 @@ msgstr "Aparência\\Escolha sua aparência"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Aplicar mudanças\\Ativa as configurações alteradas" msgstr "Aplicar mudanças\\Ativa as configurações alteradas"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Construtor apropriado faltando" msgstr "Construtor apropriado faltando"
@ -194,9 +200,6 @@ msgstr "Construir uma torre de defesa"
msgid "Build a derrick" msgid "Build a derrick"
msgstr "Construir um extrator" msgstr "Construir um extrator"
msgid "Build a destroyer"
msgstr "Construir um destruidor"
msgid "Build a exchange post" msgid "Build a exchange post"
msgstr "Construir um posto de troca" msgstr "Construir um posto de troca"
@ -269,6 +272,9 @@ msgstr "Construir um atirador com esteiras"
msgid "Build a tracked sniffer" msgid "Build a tracked sniffer"
msgstr "Construir um farejador com esteiras" msgstr "Construir um farejador com esteiras"
msgid "Build a vault"
msgstr ""
msgid "Build a wheeled builder" msgid "Build a wheeled builder"
msgstr "" msgstr ""
@ -368,6 +374,9 @@ msgstr "Mudar câmera\\Alterna entre câmera incorporada e câmera seguidora"
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Mudar jogador\\Mudar jogador" msgstr "Mudar jogador\\Mudar jogador"
msgid "Changes"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "Capítulos:" msgstr "Capítulos:"
@ -438,6 +447,12 @@ msgstr "Copiar"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Copiar (Ctrl+C)" msgstr "Copiar (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Missão atual salva" msgstr "Missão atual salva"
@ -471,6 +486,9 @@ msgstr "Extrator"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "Descer\\Diminui o poder do jato" msgstr "Descer\\Diminui o poder do jato"
msgid "Description:"
msgstr ""
msgid "Destroy" msgid "Destroy"
msgstr "Destruir" msgstr "Destruir"
@ -483,6 +501,9 @@ msgstr "Destruidor"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Dispositivo\\Configurações de driver e resolução" msgstr "Dispositivo\\Configurações de driver e resolução"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Dividindo por zero" msgstr "Dividindo por zero"
@ -499,6 +520,9 @@ msgstr "Portas bloqueadas por um robô ou outro objeto"
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Baixo (\\key gdown;)" msgstr "Baixo (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Robô cartoonista" msgstr "Robô cartoonista"
@ -526,6 +550,9 @@ msgstr "Ovo"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing" msgid "End of block missing"
msgstr "Fim do bloco ausente" msgstr "Fim do bloco ausente"
@ -753,6 +780,9 @@ msgstr "Infectado por vírus; temporariamento fora de serviço"
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Posto de troca de informação" msgstr "Posto de troca de informação"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Intrução \"break\" fora de um laço" msgstr "Intrução \"break\" fora de um laço"
@ -914,9 +944,21 @@ msgstr "Missões"
msgid "Missions on this planet:" msgid "Missions on this planet:"
msgstr "Lista de missões neste planeta:" msgstr "Lista de missões neste planeta:"
msgid "Missions+"
msgstr "Missões+"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Missões\\Selecione uma missão" msgstr "Missões\\Selecione uma missão"
msgid "Mods"
msgstr ""
msgid "Mods:"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Inversão de mouse X\\Inverte a direção da rolagem no eixo X" msgstr "Inversão de mouse X\\Inverte a direção da rolagem no eixo X"
@ -929,6 +971,9 @@ msgstr "Move o programa selecionado para baixo"
msgid "Move selected program up" msgid "Move selected program up"
msgstr "Move o programa selecionado para cima" msgstr "Move o programa selecionado para cima"
msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused"
msgstr ""
msgid "Mute\\No sound" msgid "Mute\\No sound"
msgstr "Mudo\\Sem som" msgstr "Mudo\\Sem som"
@ -947,6 +992,9 @@ msgstr "Novo"
msgid "New ..." msgid "New ..."
msgstr "Novo ..." msgstr "Novo ..."
msgid "New Folder"
msgstr ""
msgid "New bot available" msgid "New bot available"
msgstr "Novo robô disponível" msgstr "Novo robô disponível"
@ -959,6 +1007,12 @@ msgstr "Próximo objeto\\Selecionar o próximo objeto"
msgid "No" msgid "No"
msgstr "Não" msgstr "Não"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Nenhuma energia no subsolo" msgstr "Nenhuma energia no subsolo"
@ -1079,6 +1133,9 @@ msgstr "Abrir"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Abrir (Ctrl+O)" msgstr "Abrir (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Chave de abertura ausente" msgstr "Chave de abertura ausente"
@ -1103,6 +1160,9 @@ msgstr "Origem da última mensagem\\Mostra de onde a última mensagem foi enviad
msgid "Original game developed by:" msgid "Original game developed by:"
msgstr "Jogo original desenvolvido por:" msgstr "Jogo original desenvolvido por:"
msgid "Overwrite existing file?"
msgstr ""
msgid "Parameters missing" msgid "Parameters missing"
msgstr "Parâmetros ausentes" msgstr "Parâmetros ausentes"
@ -1287,6 +1347,9 @@ msgstr "Bandeira vermelha"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Reflexões nos botões\\Botões brilhantes" msgstr "Reflexões nos botões\\Botões brilhantes"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Restos da missão Apollo" msgstr "Restos da missão Apollo"
@ -1401,6 +1464,9 @@ msgstr "Salvar\\Salve a missão atual"
msgid "Save\\Saves the current mission" msgid "Save\\Saves the current mission"
msgstr "Salvar\\Salva a missão atual" msgstr "Salvar\\Salva a missão atual"
msgid "Select Folder"
msgstr ""
msgid "Select the astronaut\\Selects the astronaut" msgid "Select the astronaut\\Selects the astronaut"
msgstr "Selecione o astronauta\\Seleciona o astronauta" msgstr "Selecione o astronauta\\Seleciona o astronauta"
@ -1467,6 +1533,15 @@ msgstr "Efeitos sonoros:\\Volume dos motores, voz, tiros, etc."
msgid "Sound\\Music and game sound volume" msgid "Sound\\Music and game sound volume"
msgstr "Som\\Volume do som das músicas e do jogo" msgstr "Som\\Volume do som das músicas e do jogo"
msgid "Space Explorer\\Disables astronaut abilities"
msgstr ""
msgid "Space Programmer\\Disables radio-control"
msgstr ""
msgid "Space Researcher\\Disables using all previously researched technologies"
msgstr ""
msgid "Spaceship" msgid "Spaceship"
msgstr "Nave espacial" msgstr "Nave espacial"
@ -1545,6 +1620,10 @@ msgstr "Filtragem de textura\\Filtragem de textura"
msgid "Textures" msgid "Textures"
msgstr "Texturas" msgstr "Texturas"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended" msgid "The battle has ended"
msgstr "A batalha acabou" msgstr "A batalha acabou"
@ -1557,9 +1636,16 @@ msgstr "A função não retornou nenhum valor"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "A missão não foi completada ainda (pressione \\key help; para mais detalhes)" msgstr "A missão não foi completada ainda (pressione \\key help; para mais detalhes)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Os tipos dos dois operandos são incompativeis" msgstr "Os tipos dos dois operandos são incompativeis"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists" msgid "This class already exists"
msgstr "Esta classe já existe" msgstr "Esta classe já existe"
@ -1684,6 +1770,9 @@ msgstr "Unidade"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Objeto desconhecido" msgstr "Objeto desconhecido"
msgid "Unknown author"
msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "Comando desconhecido" msgstr "Comando desconhecido"
@ -1696,6 +1785,9 @@ msgstr "Função desconhecida"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Cima (\\key gup;)" msgstr "Cima (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Depósito de urânio (local para extrator)" msgstr "Depósito de urânio (local para extrator)"
@ -1717,6 +1809,9 @@ msgstr "Variável não inicializada"
msgid "Vault" msgid "Vault"
msgstr "Cofre" msgstr "Cofre"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "" msgstr ""
@ -1735,6 +1830,9 @@ msgstr "Vespa fatalmente ferida"
msgid "Waste" msgid "Waste"
msgstr "Desperdício" msgstr "Desperdício"
msgid "Website"
msgstr ""
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1768,6 +1866,9 @@ msgstr "Farejador alado"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Retirar escudo (\\key action;)" msgstr "Retirar escudo (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm" msgid "Worm"
msgstr "Verme" msgstr "Verme"
@ -1916,6 +2017,9 @@ msgstr "\\Bandeiras violetas"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Bandeiras amarelas" msgstr "\\Bandeiras amarelas"
msgid "by"
msgstr ""
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"
@ -1937,6 +2041,9 @@ msgstr "epsitec.com"
#~ msgid "3D sound\\3D positioning of the sound" #~ msgid "3D sound\\3D positioning of the sound"
#~ msgstr "Bruitages 3D\\Positionnement sonore dans l'espace" #~ msgstr "Bruitages 3D\\Positionnement sonore dans l'espace"
#~ msgid "Build a destroyer"
#~ msgstr "Construir um destruidor"
#~ msgid "Building too close" #~ msgid "Building too close"
#~ msgstr "Bâtiment trop proche" #~ msgstr "Bâtiment trop proche"

104
po/ru.po
View File

@ -31,6 +31,9 @@ msgstr "Отсутствует \"]\" "
msgid "%s: %d pts" msgid "%s: %d pts"
msgstr "" msgstr ""
msgid "+\\Missions with bonus content and optional challenges"
msgstr ""
msgid "..behind" msgid "..behind"
msgstr "Сзади" msgstr "Сзади"
@ -124,6 +127,9 @@ msgstr "Внешность\\Настройка внешности"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Принять\\Принять изменения настроек" msgstr "Принять\\Принять изменения настроек"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Соответствующий конструктор отсутствует" msgstr "Соответствующий конструктор отсутствует"
@ -197,9 +203,6 @@ msgstr "Построить защитную башню"
msgid "Build a derrick" msgid "Build a derrick"
msgstr "Построить буровую вышку" msgstr "Построить буровую вышку"
msgid "Build a destroyer"
msgstr "Построить уничтожитель"
msgid "Build a exchange post" msgid "Build a exchange post"
msgstr "Построить пост по обмену сообщениями" msgstr "Построить пост по обмену сообщениями"
@ -272,6 +275,9 @@ msgstr "Собрать гусеничного стрелка"
msgid "Build a tracked sniffer" msgid "Build a tracked sniffer"
msgstr "Собрать гусеничного искателя" msgstr "Собрать гусеничного искателя"
msgid "Build a vault"
msgstr ""
msgid "Build a wheeled builder" msgid "Build a wheeled builder"
msgstr "" msgstr ""
@ -375,6 +381,9 @@ msgstr "Изменить вид\\Переключение между борто
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Новый игрок\\Выберите имя для игрока" msgstr "Новый игрок\\Выберите имя для игрока"
msgid "Changes"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "Разделы:" msgstr "Разделы:"
@ -446,6 +455,12 @@ msgstr "Копировать"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Копировать (Ctrl+C)" msgstr "Копировать (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Текущая миссия сохранена" msgstr "Текущая миссия сохранена"
@ -480,6 +495,9 @@ msgstr "Космический корабль"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "Снижение и посадка\\Понижение мощности реактивного двигателя" msgstr "Снижение и посадка\\Понижение мощности реактивного двигателя"
msgid "Description:"
msgstr ""
msgid "Destroy" msgid "Destroy"
msgstr "Уничтожить" msgstr "Уничтожить"
@ -492,6 +510,9 @@ msgstr "Уничтожитель"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Устройство\\Драйвер и настройки разрешения" msgstr "Устройство\\Драйвер и настройки разрешения"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Деление на ноль (запрещено!)" msgstr "Деление на ноль (запрещено!)"
@ -508,6 +529,9 @@ msgstr "Двери заблокированы роботом или другим
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Вниз (\\key gdown;)" msgstr "Вниз (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Рисовальщик" msgstr "Рисовальщик"
@ -535,6 +559,9 @@ msgstr "Яйцо"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing" msgid "End of block missing"
msgstr "Отсутствует конец блока" msgstr "Отсутствует конец блока"
@ -762,6 +789,9 @@ msgstr "Заражено вирусом. Временно вышел из стр
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Пост обмена информацией" msgstr "Пост обмена информацией"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Инструкция \"break\" вне цикла" msgstr "Инструкция \"break\" вне цикла"
@ -923,9 +953,21 @@ msgstr "Миссии"
msgid "Missions on this planet:" msgid "Missions on this planet:"
msgstr "Миссии на этой планете:" msgstr "Миссии на этой планете:"
msgid "Missions+"
msgstr "Миссии+"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Миссии\\Выбор миссии" msgstr "Миссии\\Выбор миссии"
msgid "Mods"
msgstr ""
msgid "Mods:"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Инверсия мыши по оси X\\Инверсия прокрутки по оси Х" msgstr "Инверсия мыши по оси X\\Инверсия прокрутки по оси Х"
@ -940,6 +982,9 @@ msgstr "Изменить выбранную программу"
msgid "Move selected program up" msgid "Move selected program up"
msgstr "Изменить выбранную программу" msgstr "Изменить выбранную программу"
msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused"
msgstr ""
msgid "Mute\\No sound" msgid "Mute\\No sound"
msgstr "Без звука\\Без звука" msgstr "Без звука\\Без звука"
@ -973,6 +1018,12 @@ msgstr "Следующий объект\\Выбор следующего объ
msgid "No" msgid "No"
msgstr "Нет" msgstr "Нет"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Под землей нет запасов энергии" msgstr "Под землей нет запасов энергии"
@ -1093,6 +1144,9 @@ msgstr "Открыть"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Открыть (Ctrl+O)" msgstr "Открыть (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Открывающая скобка отсутствует" msgstr "Открывающая скобка отсутствует"
@ -1305,6 +1359,9 @@ msgstr "Красный флаг"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Отражения на кнопках \\Блестящие кнопки" msgstr "Отражения на кнопках \\Блестящие кнопки"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Остатки миссии Аполлон" msgstr "Остатки миссии Аполлон"
@ -1491,6 +1548,15 @@ msgstr "Общий звук:\\Гормкость двигателя, голос
msgid "Sound\\Music and game sound volume" msgid "Sound\\Music and game sound volume"
msgstr "Звук\\Громкость музыки и звуков" msgstr "Звук\\Громкость музыки и звуков"
msgid "Space Explorer\\Disables astronaut abilities"
msgstr ""
msgid "Space Programmer\\Disables radio-control"
msgstr ""
msgid "Space Researcher\\Disables using all previously researched technologies"
msgstr ""
msgid "Spaceship" msgid "Spaceship"
msgstr "Космический корабль" msgstr "Космический корабль"
@ -1570,6 +1636,10 @@ msgstr "Фильтрация текстур\\Фильтрация текстур
msgid "Textures" msgid "Textures"
msgstr "Текстуры" msgstr "Текстуры"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended" msgid "The battle has ended"
msgstr "" msgstr ""
@ -1582,9 +1652,16 @@ msgstr "Функция не возвратила значения"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "Миссия еще не выполнена (нажмите \\key help; для более подробной информации)" msgstr "Миссия еще не выполнена (нажмите \\key help; для более подробной информации)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Типы операндов несовместимы" msgstr "Типы операндов несовместимы"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists" msgid "This class already exists"
msgstr "Этот класс уже существует" msgstr "Этот класс уже существует"
@ -1709,6 +1786,9 @@ msgstr "Юнит"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Неизвестный объект" msgstr "Неизвестный объект"
msgid "Unknown author"
msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "Неизвестная команда" msgstr "Неизвестная команда"
@ -1721,6 +1801,9 @@ msgstr "Неизвестная функция"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Вверх (\\key gup;)" msgstr "Вверх (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Запасы урана (место для буровой вышки)" msgstr "Запасы урана (место для буровой вышки)"
@ -1742,6 +1825,9 @@ msgstr "Переменная не инициализирована"
msgid "Vault" msgid "Vault"
msgstr "Хранилище" msgstr "Хранилище"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "" msgstr ""
@ -1760,6 +1846,9 @@ msgstr "Оса смертельно ранена"
msgid "Waste" msgid "Waste"
msgstr "Мусор" msgstr "Мусор"
msgid "Website"
msgstr ""
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1793,6 +1882,9 @@ msgstr "Летающий искатель"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Снять щит (\\key action;)" msgstr "Снять щит (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm" msgid "Worm"
msgstr "Червь" msgstr "Червь"
@ -1941,6 +2033,9 @@ msgstr "\\Фиолетовый флаг"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Желтый флаг" msgstr "\\Желтый флаг"
msgid "by"
msgstr ""
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"
@ -1962,6 +2057,9 @@ msgstr "epsitec.com"
#~ msgid "3D sound\\3D positioning of the sound" #~ msgid "3D sound\\3D positioning of the sound"
#~ msgstr "3D-звук\\Стерео звук" #~ msgstr "3D-звук\\Стерео звук"
#~ msgid "Build a destroyer"
#~ msgstr "Построить уничтожитель"
#~ msgid "Building too close" #~ msgid "Building too close"
#~ msgstr "Здание слишком близко" #~ msgstr "Здание слишком близко"

View File

@ -31,107 +31,100 @@
namespace CBot namespace CBot
{ {
//////////////////////////////////////////////////////////////////////////////// struct CBotCStack::Data
CBotProgram* CBotCStack::m_prog = nullptr; // init the static variable {
CBotError CBotCStack::m_error = CBotNoErr; //! The program currently being compiled
int CBotCStack::m_end = 0; CBotProgram* prog = nullptr;
CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0); //! The current error state of the compile stack
CBotError error = CBotNoErr;
int errEnd = 0;
//! The return type of the function currently being compiled
CBotTypResult retTyp = CBotTypResult(CBotTypVoid);
};
////////////////////////////////////////////////////////////////////////////////
CBotCStack::CBotCStack(CBotCStack* ppapa) CBotCStack::CBotCStack(CBotCStack* ppapa)
{ {
m_next = nullptr;
m_prev = ppapa; m_prev = ppapa;
if (ppapa == nullptr) if (ppapa == nullptr)
{ {
m_error = CBotNoErr; m_data = new CBotCStack::Data;
m_start = 0; m_errStart = 0;
m_end = 0;
m_bBlock = true; m_bBlock = true;
} }
else else
{ {
m_start = ppapa->m_start; m_data = ppapa->m_data;
m_errStart = ppapa->m_errStart;
m_bBlock = false; m_bBlock = false;
} }
m_listVar = nullptr;
m_var = nullptr;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotCStack::~CBotCStack() CBotCStack::~CBotCStack()
{ {
if (m_next != nullptr) delete m_next; if (m_prev == nullptr) delete m_data;
if (m_prev != nullptr) m_prev->m_next = nullptr; // removes chain
delete m_var;
delete m_listVar;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock) CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock)
{ {
if (m_next != nullptr) return m_next; // include on an existing stack if (m_next) return m_next.get(); // include on an existing stack
CBotCStack* p = new CBotCStack(this); m_next.reset(new CBotCStack(this));
m_next = p; // channel element m_next->m_bBlock = bBlock;
p->m_bBlock = bBlock;
if (pToken != nullptr) p->SetStartError(pToken->GetStart()); if (pToken != nullptr) m_next->SetStartError(pToken->GetStart());
return p; return m_next.get();
}
void CBotCStack::DeleteNext()
{
m_next.reset();
} }
////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils) CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils)
{ {
if ( pfils == this ) return inst; if ( pfils == this ) return inst;
if (m_var != nullptr) delete m_var; // value replaced? m_var = std::move(pfils->m_var); // result transmitted
m_var = pfils->m_var; // result transmitted
pfils->m_var = nullptr; // not to destroy the variable
if (m_error) if (m_data->error != CBotNoErr)
{ {
m_start = pfils->m_start; // retrieves the position of the error m_errStart = pfils->m_errStart; // retrieves the position of the error
m_end = pfils->m_end;
} }
delete pfils; m_next.reset();
return inst; return inst;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils) CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils)
{ {
if (m_var != nullptr) delete m_var; // value replaced? m_var = std::move(pfils->m_var); // result transmitted
m_var = pfils->m_var; // result transmitted
pfils->m_var = nullptr; // not to destroy the variable
if (m_error) if (m_data->error != CBotNoErr)
{ {
m_start = pfils->m_start; // retrieves the position of the error m_errStart = pfils->m_errStart; // retrieves the position of the error
m_end = pfils->m_end;
} }
delete pfils; m_next.reset();
return inst; return inst;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotError CBotCStack::GetError(int& start, int& end) CBotError CBotCStack::GetError(int& start, int& end)
{ {
start = m_start; start = m_errStart;
end = m_end; end = m_data->errEnd;
return m_error; return m_data->error;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotError CBotCStack::GetError() CBotError CBotCStack::GetError()
{ {
return m_error; return m_data->error;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -171,18 +164,13 @@ void CBotCStack::SetType(CBotTypResult& type)
CBotVar* CBotCStack::FindVar(CBotToken* &pToken) CBotVar* CBotCStack::FindVar(CBotToken* &pToken)
{ {
CBotCStack* p = this; CBotCStack* p = this;
std::string name = pToken->GetString(); const auto& name = pToken->GetString();
while (p != nullptr) while (p != nullptr)
{ {
CBotVar* pp = p->m_listVar; if (p->m_bBlock) for (auto& var : p->m_listVar)
while ( pp != nullptr)
{ {
if (name == pp->GetName()) if (name == var->GetName()) return var.get();
{
return pp;
}
pp = pp->m_next;
} }
p = p->m_prev; p = p->m_prev;
} }
@ -211,39 +199,39 @@ CBotVar* CBotCStack::CopyVar(CBotToken& Token)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotCStack::IsOk() bool CBotCStack::IsOk()
{ {
return (m_error == 0); return (m_data->error == CBotNoErr);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotCStack::SetStartError( int pos ) void CBotCStack::SetStartError( int pos )
{ {
if ( m_error != 0) return; // does not change existing error if (m_data->error != CBotNoErr) return; // does not change existing error
m_start = pos; m_errStart = pos;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotCStack::SetError(CBotError n, int pos) void CBotCStack::SetError(CBotError n, int pos)
{ {
if ( n!= 0 && m_error != 0) return; // does not change existing error if (n != CBotNoErr && m_data->error != CBotNoErr) return; // does not change existing error
m_error = n; m_data->error = n;
m_end = pos; m_data->errEnd = pos;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotCStack::SetError(CBotError n, CBotToken* p) void CBotCStack::SetError(CBotError n, CBotToken* p)
{ {
if (m_error) return; // does not change existing error if (m_data->error != CBotNoErr) return; // does not change existing error
m_error = n; m_data->error = n;
m_start = p->GetStart(); m_errStart = p->GetStart();
m_end = p->GetEnd(); m_data->errEnd = p->GetEnd();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotCStack::ResetError(CBotError n, int start, int end) void CBotCStack::ResetError(CBotError n, int start, int end)
{ {
m_error = n; m_data->error = n;
m_start = start; m_errStart = start;
m_end = end; m_data->errEnd = end;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -261,48 +249,47 @@ bool CBotCStack::NextToken(CBotToken* &p)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotCStack::SetProgram(CBotProgram* p) void CBotCStack::SetProgram(CBotProgram* p)
{ {
m_prog = p; m_data->prog = p;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotProgram* CBotCStack::GetProgram() CBotProgram* CBotCStack::GetProgram()
{ {
return m_prog; return m_data->prog;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotCStack::SetRetType(CBotTypResult& type) void CBotCStack::SetRetType(CBotTypResult& type)
{ {
m_retTyp = type; m_data->retTyp = type;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotTypResult CBotCStack::GetRetType() CBotTypResult CBotCStack::GetRetType()
{ {
return m_retTyp; return m_data->retTyp;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotCStack::SetVar( CBotVar* var ) void CBotCStack::SetVar( CBotVar* var )
{ {
if (m_var) delete m_var; // replacement of a variable m_var.reset(var);
m_var = var;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotCStack::SetCopyVar( CBotVar* var ) void CBotCStack::SetCopyVar( CBotVar* var )
{ {
if (m_var) delete m_var; // replacement of a variable m_var.reset();
if ( var == nullptr ) return; if ( var == nullptr ) return;
m_var = CBotVar::Create("", var->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC)); m_var.reset(CBotVar::Create("", var->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC)));
m_var->Copy( var ); m_var->Copy( var );
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotVar* CBotCStack::GetVar() CBotVar* CBotCStack::GetVar()
{ {
return m_var; return m_var.get();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -310,15 +297,12 @@ void CBotCStack::AddVar(CBotVar* pVar)
{ {
CBotCStack* p = this; CBotCStack* p = this;
// returns to the father element // find the level of the current block
while (p != nullptr && p->m_bBlock == 0) p = p->m_prev; while (p != nullptr && p->m_bBlock == 0) p = p->m_prev;
if ( p == nullptr ) return; if (p == nullptr || pVar == nullptr) return;
CBotVar** pp = &p->m_listVar; p->m_listVar.emplace_back(pVar);
while ( *pp != nullptr ) pp = &(*pp)->m_next;
*pp = pVar; // added after
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -369,19 +353,14 @@ void CBotCStack::CreateMemberVars(CBotClass* pClass, bool setDefined)
bool CBotCStack::CheckVarLocal(CBotToken* &pToken) bool CBotCStack::CheckVarLocal(CBotToken* &pToken)
{ {
CBotCStack* p = this; CBotCStack* p = this;
std::string name = pToken->GetString(); const auto& name = pToken->GetString();
while (p != nullptr) // find the level of the current block
while (p != nullptr && p->m_bBlock == 0) p = p->m_prev;
if (p != nullptr) for (auto& var : p->m_listVar)
{ {
CBotVar* pp = p->m_listVar; if (name == var->GetName()) return true;
while ( pp != nullptr)
{
if (name == pp->GetName())
return true;
pp = pp->m_next;
}
if ( p->m_bBlock ) return false;
p = p->m_prev;
} }
return false; return false;
} }
@ -392,10 +371,10 @@ CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nId
nIdent = 0; nIdent = 0;
CBotTypResult val(-1); CBotTypResult val(-1);
val = m_prog->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this); val = GetProgram()->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this);
if (val.GetType() < 0) if (val.GetType() < 0)
{ {
val = CBotFunction::CompileCall(p->GetString(), ppVars, nIdent, m_prog); val = CBotFunction::CompileCall(p->GetString(), ppVars, nIdent, GetProgram());
if ( val.GetType() < 0 ) if ( val.GetType() < 0 )
{ {
// pVar = nullptr; // the error is not on a particular parameter // pVar = nullptr; // the error is not on a particular parameter
@ -410,13 +389,13 @@ CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nId
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam, const std::string& className) bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam, const std::string& className)
{ {
std::string name = pToken->GetString(); const auto& name = pToken->GetString();
if ( m_prog->GetExternalCalls()->CheckCall(name) ) return true; if ( GetProgram()->GetExternalCalls()->CheckCall(name) ) return true;
for (CBotFunction* pp : m_prog->GetFunctions()) for (CBotFunction* pp : GetProgram()->GetFunctions())
{ {
if ( pToken->GetString() == pp->GetName() ) if ( name == pp->GetName() )
{ {
// ignore methods for a different class // ignore methods for a different class
if ( className != pp->GetClassName() ) if ( className != pp->GetClassName() )
@ -429,7 +408,7 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam, const std::
for (CBotFunction* pp : CBotFunction::m_publicFunctions) for (CBotFunction* pp : CBotFunction::m_publicFunctions)
{ {
if ( pToken->GetString() == pp->GetName() ) if ( name == pp->GetName() )
{ {
// ignore methods for a different class // ignore methods for a different class
if ( className != pp->GetClassName() ) if ( className != pp->GetClassName() )
@ -443,4 +422,4 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam, const std::
return false; return false;
} }
} } // namespace CBot

View File

@ -22,6 +22,9 @@
#include "CBot/CBotVar/CBotVar.h" #include "CBot/CBotVar/CBotVar.h"
#include "CBot/CBotProgram.h" #include "CBot/CBotProgram.h"
#include <list>
#include <memory>
namespace CBot namespace CBot
{ {
@ -157,6 +160,11 @@ public:
*/ */
CBotCStack* TokenStack(CBotToken* pToken = nullptr, bool bBlock = false); CBotCStack* TokenStack(CBotToken* pToken = nullptr, bool bBlock = false);
/*!
* \brief Deletes all subsequent stack frames created by TokenStack.
*/
void DeleteNext();
/*! /*!
* \brief Return Transmits the result upper. * \brief Return Transmits the result upper.
* \param p * \param p
@ -269,21 +277,20 @@ public:
bool NextToken(CBotToken* &p); bool NextToken(CBotToken* &p);
private: private:
CBotCStack* m_next; std::unique_ptr<CBotCStack> m_next;
CBotCStack* m_prev; CBotCStack* m_prev;
static CBotError m_error; int m_errStart = 0;
static int m_end;
int m_start; struct Data;
CBotCStack::Data* m_data;
//! Result of the operations. //! Result of the operations.
CBotVar* m_var; std::unique_ptr<CBotVar> m_var;
//! Is part of a block (variables are local to this block). //! Is part of a block (variables are local to this block).
bool m_bBlock; bool m_bBlock;
CBotVar* m_listVar; std::list<std::unique_ptr<CBotVar>> m_listVar;
//! List of compiled functions.
static CBotProgram* m_prog;
static CBotTypResult m_retTyp;
}; };
} // namespace CBot } // namespace CBot

View File

@ -605,8 +605,8 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
// return a method precompiled in pass 1 // return a method precompiled in pass 1
CBotCStack* pStk = pStack->TokenStack(nullptr, true); CBotCStack* pStk = pStack->TokenStack(nullptr, true);
CBotDefParam* params = CBotDefParam::Compile(p, pStk ); CBotDefParam* params = CBotDefParam::Compile(p, pStk );
delete pStk; pStack->DeleteNext();
std::list<CBotFunction*>::iterator pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, &params](CBotFunction* x) auto pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, &params](CBotFunction* x)
{ {
return x->GetName() == pp && x->CheckParam( params ); return x->GetName() == pp && x->CheckParam( params );
}); });
@ -626,7 +626,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
f->m_pProg = pStack->GetProgram(); f->m_pProg = pStack->GetProgram();
f->m_bSynchro = bSynchro; f->m_bSynchro = bSynchro;
} }
pStack->Return(nullptr, pile); pStack->DeleteNext();
} }
return pStack->IsOk(); return pStack->IsOk();

View File

@ -94,7 +94,7 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
prevHasDefault = true; prevHasDefault = true;
} }
else pStack->SetError(CBotErrNoExpression, p); else pStack->SetError(CBotErrNoExpression, p);
delete pStk; pStack->DeleteNext();
} }
else else
if (prevHasDefault) pStack->SetError(CBotErrDefaultValue, p->GetPrev()); if (prevHasDefault) pStack->SetError(CBotErrDefaultValue, p->GetPrev());
@ -137,6 +137,7 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
while ( p != nullptr ) while ( p != nullptr )
{ {
pile = pile->AddStack(); pile = pile->AddStack();
if (pile->StackOver()) return pj->Return(pile);
if (pile->GetState() == 1) // already done? if (pile->GetState() == 1) // already done?
{ {
if (ppVars != nullptr && ppVars[i] != nullptr) ++i; if (ppVars != nullptr && ppVars[i] != nullptr) ++i;

View File

@ -100,6 +100,7 @@ enum TokenId
ID_STATIC, ID_STATIC,
ID_PROTECTED, ID_PROTECTED,
ID_PRIVATE, ID_PRIVATE,
ID_REPEAT,
ID_INT, ID_INT,
ID_FLOAT, ID_FLOAT,
ID_BOOLEAN, ID_BOOLEAN,

View File

@ -82,19 +82,23 @@ int CBotExternalCallList::DoCall(CBotToken* token, CBotVar* thisVar, CBotVar** p
CBotExternalCall* pt = m_list[token->GetString()].get(); CBotExternalCall* pt = m_list[token->GetString()].get();
if (pStack->IsCallFinished()) return true; if (thisVar == nullptr && pStack->IsCallFinished()) return true; // only for non-method external call
CBotStack* pile = pStack->AddStackExternalCall(pt);
// lists the parameters depending on the contents of the stack (pStackVar) // if this is a method call we need to use AddStack()
CBotVar* pVar = MakeListVars(ppVar, true); CBotStack* pile = (thisVar != nullptr) ? pStack->AddStack() : pStack->AddStackExternalCall(pt);
// creates a variable to the result if (pile->GetState() == 0) // the first time?
CBotVar* pResult = rettype.Eq(CBotTypVoid) ? nullptr : CBotVar::Create("", rettype); {
// lists the parameters depending on the contents of the stack
CBotVar* pVar = MakeListVars(ppVar, true);
pile->SetVar(pVar);
pile->SetVar(pVar); CBotStack* pile2 = pile->AddStack();
// creates a variable to the result
CBotStack* pile2 = pile->AddStack(); CBotVar* pResult = rettype.Eq(CBotTypVoid) ? nullptr : CBotVar::Create("", rettype);
pile2->SetVar(pResult); pile2->SetVar(pResult);
pile->IncState(); // increment state to mark this step done
}
pile->SetError(CBotNoErr, token); // save token for the position in case of error pile->SetError(CBotNoErr, token); // save token for the position in case of error
return pt->Run(thisVar, pStack); return pt->Run(thisVar, pStack);
@ -107,7 +111,8 @@ bool CBotExternalCallList::RestoreCall(CBotToken* token, CBotVar* thisVar, CBotV
CBotExternalCall* pt = m_list[token->GetString()].get(); CBotExternalCall* pt = m_list[token->GetString()].get();
CBotStack* pile = pStack->RestoreStackEOX(pt); // if this is a method call we need to use RestoreStack()
CBotStack* pile = (thisVar != nullptr) ? pStack->RestoreStack() : pStack->RestoreStackEOX(pt);
if (pile == nullptr) return true; if (pile == nullptr) return true;
pile->RestoreStack(); pile->RestoreStack();
@ -163,8 +168,7 @@ bool CBotExternalCallDefault::Run(CBotVar* thisVar, CBotStack* pStack)
return false; return false;
} }
if (result != nullptr) pStack->SetCopyVar(result); pStack->Return(pile2); // return 'result' and clear extra stack
return true; return true;
} }
@ -187,8 +191,8 @@ CBotTypResult CBotExternalCallClass::Compile(CBotVar* thisVar, CBotVar* args, vo
bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack) bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack)
{ {
if (pStack->IsCallFinished()) return true; assert(thisVar != nullptr);
CBotStack* pile = pStack->AddStackExternalCall(this); CBotStack* pile = pStack->AddStack();
CBotVar* args = pile->GetVar(); CBotVar* args = pile->GetVar();
CBotStack* pile2 = pile->AddStack(); CBotStack* pile2 = pile->AddStack();
@ -207,9 +211,8 @@ bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack)
return false; return false;
} }
if (result != nullptr) pStack->SetCopyVar(result); pStack->Return(pile2); // return 'result' and clear extra stack
return true; return true;
} }
} } // namespace CBot

View File

@ -135,7 +135,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p
// the constructor is there? // the constructor is there?
// std::string noname; // std::string noname;
CBotTypResult r = pClass->CompileMethode(&token, var, ppVars, pStk, inst->m_nMethodeIdent); CBotTypResult r = pClass->CompileMethode(&token, var, ppVars, pStk, inst->m_nMethodeIdent);
delete pStk->TokenStack(); // releases the supplement stack pStk->DeleteNext(); // releases the supplement stack
int typ = r.GetType(); int typ = r.GetType();
if (typ == CBotErrUndefCall) if (typ == CBotErrUndefCall)
@ -160,7 +160,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true))) if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true)))
{ {
inst->m_exprRetVar->SetToken(vartoken); inst->m_exprRetVar->SetToken(vartoken);
delete pStk->TokenStack(); pStk->DeleteNext();
} }
pStk->SetVar(nullptr); pStk->SetVar(nullptr);
@ -360,6 +360,7 @@ bool CBotDefClass::Execute(CBotStack* &pj)
if ( p != nullptr) while ( true ) if ( p != nullptr) while ( true )
{ {
pile2 = pile2->AddStack(); // place on the stack for the results pile2 = pile2->AddStack(); // place on the stack for the results
if (pile2->StackOver()) return pj->Return(pile2);
if ( pile2->GetState() == 0 ) if ( pile2->GetState() == 0 )
{ {
if (!p->Execute(pile2)) return false; // interrupted here? if (!p->Execute(pile2)) return false; // interrupted here?

View File

@ -445,7 +445,7 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
pile->IncState(); pile->IncState();
} }
if ( !m_block->Execute(pile) ) if (!pile->GetRetVar(m_block->Execute(pile)))
{ {
if ( pile->GetError() < 0 ) if ( pile->GetError() < 0 )
pile->SetError( CBotNoErr ); pile->SetError( CBotNoErr );

View File

@ -30,6 +30,7 @@
#include "CBot/CBotInstr/CBotExpression.h" #include "CBot/CBotInstr/CBotExpression.h"
#include "CBot/CBotInstr/CBotFor.h" #include "CBot/CBotInstr/CBotFor.h"
#include "CBot/CBotInstr/CBotIf.h" #include "CBot/CBotInstr/CBotIf.h"
#include "CBot/CBotInstr/CBotRepeat.h"
#include "CBot/CBotInstr/CBotReturn.h" #include "CBot/CBotInstr/CBotReturn.h"
#include "CBot/CBotInstr/CBotSwitch.h" #include "CBot/CBotInstr/CBotSwitch.h"
#include "CBot/CBotInstr/CBotThrow.h" #include "CBot/CBotInstr/CBotThrow.h"
@ -176,7 +177,7 @@ CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack)
{ {
type = pp->GetType(); type = pp->GetType();
// Allow only instructions that accept a label // Allow only instructions that accept a label
if (!IsOfTypeList(pp, ID_WHILE, ID_FOR, ID_DO, 0)) if (!IsOfTypeList(pp, ID_WHILE, ID_FOR, ID_DO, ID_REPEAT, 0))
{ {
pStack->SetError(CBotErrLabel, pp->GetStart()); pStack->SetError(CBotErrLabel, pp->GetStart());
return nullptr; return nullptr;
@ -195,6 +196,9 @@ CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack)
case ID_DO: case ID_DO:
return CBotDo::Compile(p, pStack); return CBotDo::Compile(p, pStack);
case ID_REPEAT:
return CBotRepeat::Compile(p, pStack);
case ID_BREAK: case ID_BREAK:
case ID_CONTINUE: case ID_CONTINUE:
return CBotBreak::Compile(p, pStack); return CBotBreak::Compile(p, pStack);

View File

@ -78,12 +78,12 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
{ {
// if (pVar2!=nullptr) pp = pVar2->RetToken(); // if (pVar2!=nullptr) pp = pVar2->RetToken();
pStack->SetError( static_cast<CBotError>(inst->m_typRes.GetType()), pp ); pStack->SetError( static_cast<CBotError>(inst->m_typRes.GetType()), pp );
delete pStack->TokenStack(); pStack->DeleteNext();
delete inst; delete inst;
return nullptr; return nullptr;
} }
delete pStack->TokenStack(); pStack->DeleteNext();
if ( inst->m_typRes.GetType() > 0 ) if ( inst->m_typRes.GetType() > 0 )
{ {
CBotVar* pRes = CBotVar::Create("", inst->m_typRes); CBotVar* pRes = CBotVar::Create("", inst->m_typRes);
@ -94,7 +94,7 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack))) if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack)))
{ {
inst->m_exprRetVar->SetToken(&inst->m_token); inst->m_exprRetVar->SetToken(&inst->m_token);
delete pStack->TokenStack(); pStack->DeleteNext();
} }
if ( !pStack->IsOk() ) if ( !pStack->IsOk() )
{ {
@ -105,7 +105,7 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
return inst; return inst;
} }
p = pp; p = pp;
delete pStack->TokenStack(); pStack->DeleteNext();
return nullptr; return nullptr;
} }
@ -138,6 +138,7 @@ bool CBotInstrCall::Execute(CBotStack* &pj)
if ( p != nullptr) while ( true ) if ( p != nullptr) while ( true )
{ {
pile = pile->AddStack(); // place on the stack for the results pile = pile->AddStack(); // place on the stack for the results
if (pile->StackOver()) return pj->Return(pile);
if ( pile->GetState() == 0 ) if ( pile->GetState() == 0 )
{ {
if (!p->Execute(pile)) return false; // interrupted here? if (!p->Execute(pile)) return false; // interrupted here?

View File

@ -70,7 +70,7 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar*
CBotClass* pClass = var->GetClass(); // pointer to the class CBotClass* pClass = var->GetClass(); // pointer to the class
inst->m_className = pClass->GetName(); // name of the class inst->m_className = pClass->GetName(); // name of the class
CBotTypResult r = pClass->CompileMethode(pp, var, ppVars, pStack, inst->m_MethodeIdent); CBotTypResult r = pClass->CompileMethode(pp, var, ppVars, pStack, inst->m_MethodeIdent);
delete pStack->TokenStack(); // release parameters on the stack pStack->DeleteNext(); // release parameters on the stack
inst->m_typRes = r; inst->m_typRes = r;
if (inst->m_typRes.GetType() > 20) if (inst->m_typRes.GetType() > 20)
@ -95,7 +95,7 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar*
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack, bMethodChain))) if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack, bMethodChain)))
{ {
inst->m_exprRetVar->SetToken(pp); inst->m_exprRetVar->SetToken(pp);
delete pStack->TokenStack(); pStack->DeleteNext();
} }
if ( pStack->IsOk() ) if ( pStack->IsOk() )
@ -164,6 +164,7 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre
} }
ppVars[i++] = pile2->GetVar(); // construct the list of pointers ppVars[i++] = pile2->GetVar(); // construct the list of pointers
pile2 = pile2->AddStack(); // space on the stack for the result pile2 = pile2->AddStack(); // space on the stack for the result
if (pile2->StackOver()) return pj->Return(pile2);
p = p->GetNext(); p = p->GetNext();
if ( p == nullptr) break; if ( p == nullptr) break;
} }

View File

@ -65,7 +65,7 @@ CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars)
{ {
if (pile->GetTypResult().Eq(99)) if (pile->GetTypResult().Eq(99))
{ {
delete pStack->TokenStack(); pStack->DeleteNext();
pStack->SetError(CBotErrVoid, p->GetStart()); pStack->SetError(CBotErrVoid, p->GetStart());
return nullptr; return nullptr;
} }
@ -78,7 +78,7 @@ CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars)
} }
pStack->SetError(CBotErrClosePar, p->GetStart()); pStack->SetError(CBotErrClosePar, p->GetStart());
delete pStack->TokenStack(); pStack->DeleteNext();
return nullptr; return nullptr;
} }
} }

View File

@ -87,7 +87,7 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
// constructor exist? // constructor exist?
CBotTypResult r = pClass->CompileMethode(&inst->m_vartoken, pVar, ppVars, pStk, inst->m_nMethodeIdent); CBotTypResult r = pClass->CompileMethode(&inst->m_vartoken, pVar, ppVars, pStk, inst->m_nMethodeIdent);
delete pStk->TokenStack(); // release extra stack pStk->DeleteNext(); // release extra stack
int typ = r.GetType(); int typ = r.GetType();
// if there is no constructor, and no parameters either, it's ok // if there is no constructor, and no parameters either, it's ok
@ -115,7 +115,7 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true))) if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true)))
{ {
inst->m_exprRetVar->SetToken(pp); inst->m_exprRetVar->SetToken(pp);
delete pStk->TokenStack(); pStk->DeleteNext();
} }
if (pStack->IsOk()) if (pStack->IsOk())
@ -189,6 +189,7 @@ bool CBotNew::Execute(CBotStack* &pj)
if (p != nullptr) while ( true) if (p != nullptr) while ( true)
{ {
pile2 = pile2->AddStack(); // space on the stack for the result pile2 = pile2->AddStack(); // space on the stack for the result
if (pile2->StackOver()) return pj->Return(pile2);
if (pile2->GetState() == 0) if (pile2->GetState() == 0)
{ {
if (!p->Execute(pile2)) return false; // interrupted here? if (!p->Execute(pile2)) return false; // interrupted here?

View File

@ -0,0 +1,165 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotInstr/CBotRepeat.h"
#include "CBot/CBotInstr/CBotBlock.h"
#include "CBot/CBotInstr/CBotExpression.h"
#include "CBot/CBotCStack.h"
#include "CBot/CBotStack.h"
namespace CBot
{
CBotRepeat::CBotRepeat()
{
m_expr = nullptr;
m_block = nullptr;
}
CBotRepeat::~CBotRepeat()
{
delete m_expr;
delete m_block;
}
CBotInstr* CBotRepeat::Compile(CBotToken* &p, CBotCStack* pStack)
{
CBotRepeat* inst = new CBotRepeat(); // creates the object
CBotToken* pp = p; // preserves at the ^ token (starting position)
if ( IsOfType( p, TokenTypVar ) && IsOfType( p, ID_DOTS ) )
inst->m_label = pp->GetString(); // register the name of label
inst->SetToken(p);
if (!IsOfType(p, ID_REPEAT)) return nullptr; // should never happen
CBotCStack* pStk = pStack->TokenStack(pp);
if ( IsOfType(p, ID_OPENPAR ) )
{
CBotToken* ppp = p; // preserves the ^ token (starting position)
if ( nullptr != (inst->m_expr = CBotExpression::Compile( p, pStk )) )
{
if ( pStk->GetType() < CBotTypLong )
{
if ( IsOfType(p, ID_CLOSEPAR ) )
{
IncLvl(inst->m_label);
inst->m_block = CBotBlock::CompileBlkOrInst( p, pStk, true );
DecLvl();
if ( pStk->IsOk() ) // the statement block is ok (it may be empty!)
return pStack->Return(inst, pStk);
}
pStack->SetError(CBotErrClosePar, p->GetStart());
}
pStk->SetStartError(ppp->GetStart());
pStk->SetError(CBotErrBadType1, p->GetStart());
}
pStack->SetError(CBotErrBadNum, p);
}
pStack->SetError(CBotErrOpenPar, p->GetStart());
delete inst;
return pStack->Return(nullptr, pStk);
}
// execution of intruction "repeat"
bool CBotRepeat::Execute(CBotStack* &pj)
{
CBotStack* pile = pj->AddStack(this); // adds an item to the stack
// or find in case of recovery
if ( pile->IfStep() ) return false;
while( true ) switch( pile->GetState() ) // executes the loop
{ // there are two possible states (depending on recovery)
case 0:
// evaluates the number of iterations
if ( !m_expr->Execute(pile) ) return false; // interrupted here ?
// the result of the condition is on the stack
// terminates if an error or if the condition is false
int n;
if ( !pile->IsOk() || ( n = pile->GetVal() ) < 1 )
return pj->Return(pile); // releases the stack
// puts the number of iterations +1 to the "state"
if (!pile->SetState(n+1)) return false; // ready for further
continue; // continue as a result
case 1:
// normal end of the loop
return pj->Return(pile); // releases the stack
default:
// evaluates the associated statement block
if ( m_block != nullptr && !m_block->Execute(pile) )
{
if (pile->IfContinue(pile->GetState()-1, m_label)) continue; // if continued, will return to test
return pj->BreakReturn(pile, m_label); // releases the stack
}
// terminates if there is an error
if (!pile->IsOk()) return pj->Return(pile); // releases the stack
// returns to the test again
if (!pile->SetState(pile->GetState()-1, 0)) return false;
continue;
}
}
void CBotRepeat::RestoreState(CBotStack* &pj, bool bMain)
{
if ( !bMain ) return;
CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack
if ( pile == nullptr ) return;
switch( pile->GetState() )
{ // there are two possible states (depending on recovery)
case 0:
// evaluates the condition
m_expr->RestoreState(pile, bMain);
return;
case 1:
// evaluates the associated statement block
if ( m_block != nullptr ) m_block->RestoreState(pile, bMain);
return;
}
}
std::string CBotRepeat::GetDebugData()
{
return !m_label.empty() ? "m_label = " + m_label : "";
}
std::map<std::string, CBotInstr*> CBotRepeat::GetDebugLinks()
{
auto links = CBotInstr::GetDebugLinks();
links["m_expr"] = m_expr;
links["m_block"] = m_block;
return links;
}
} // namespace CBot

View File

@ -0,0 +1,62 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "CBot/CBotInstr/CBotInstr.h"
namespace CBot
{
/**
* \brief The "repeat" loop - repeat (times) { ... }
*/
class CBotRepeat : public CBotInstr
{
public:
CBotRepeat();
~CBotRepeat();
/// Static method used for compilation
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
/// Execute
bool Execute(CBotStack* &pj) override;
/// Restore state
void RestoreState(CBotStack* &pj, bool bMain) override;
protected:
virtual const std::string GetDebugName() override { return "CBotRepeat"; }
virtual std::string GetDebugData() override;
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;
private:
/// Number of iterations
CBotInstr* m_expr;
/// Instructions
CBotInstr* m_block;
/// Label
std::string m_label; // a label if there is
};
} // namespace CBot

View File

@ -71,7 +71,7 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
{ {
if ( p->GetType() == ID_CASE || p->GetType() == ID_DEFAULT) if ( p->GetType() == ID_CASE || p->GetType() == ID_DEFAULT)
{ {
delete pStk2; pStk->DeleteNext();
pStk2 = pStk->TokenStack(p, true); // some space for a stack, plz pStk2 = pStk->TokenStack(p, true); // some space for a stack, plz
caseInst = static_cast<CBotCase*>(CBotCase::Compile(p, pStk2, inst->m_labels)); caseInst = static_cast<CBotCase*>(CBotCase::Compile(p, pStk2, inst->m_labels));

View File

@ -357,6 +357,7 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack
// or return in case of recovery // or return in case of recovery
if (pStk2->StackOver()) return pStack->Return(pStk2);
// 2nd state, evalute right operand // 2nd state, evalute right operand
if ( pStk2->GetState() == 0 ) if ( pStk2->GetState() == 0 )
@ -514,7 +515,6 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
pStk2->SetVar(result); // puts the result on the stack pStk2->SetVar(result); // puts the result on the stack
if ( err ) pStk2->SetError(err, &m_token); // and the possible error (division by zero) if ( err ) pStk2->SetError(err, &m_token); // and the possible error (division by zero)
// pStk1->Return(pStk2); // releases the stack
return pStack->Return(pStk2); // transmits the result return pStack->Return(pStk2); // transmits the result
} }

View File

@ -34,7 +34,7 @@
namespace CBot namespace CBot
{ {
CBotExternalCallList* CBotProgram::m_externalCalls = new CBotExternalCallList(); std::unique_ptr<CBotExternalCallList> CBotProgram::m_externalCalls;
CBotProgram::CBotProgram() CBotProgram::CBotProgram()
{ {
@ -243,13 +243,6 @@ CBotVar* CBotProgram::GetStackVars(std::string& functionName, int level)
return m_stack->GetStackVars(functionName, level); return m_stack->GetStackVars(functionName, level);
} }
////////////////////////////////////////////////////////////////////////////////
void CBotProgram::SetTimer(int n)
{
CBotStack::SetTimer( n );
}
////////////////////////////////////////////////////////////////////////////////
CBotError CBotProgram::GetError() CBotError CBotProgram::GetError()
{ {
return m_error; return m_error;
@ -395,6 +388,8 @@ int CBotProgram::GetVersion()
void CBotProgram::Init() void CBotProgram::Init()
{ {
m_externalCalls.reset(new CBotExternalCallList);
CBotProgram::DefineNum("CBotErrZeroDiv", CBotErrZeroDiv); // division by zero CBotProgram::DefineNum("CBotErrZeroDiv", CBotErrZeroDiv); // division by zero
CBotProgram::DefineNum("CBotErrNotInit", CBotErrNotInit); // uninitialized variable CBotProgram::DefineNum("CBotErrNotInit", CBotErrNotInit); // uninitialized variable
CBotProgram::DefineNum("CBotErrBadThrow", CBotErrBadThrow); // throw a negative value CBotProgram::DefineNum("CBotErrBadThrow", CBotErrBadThrow); // throw a negative value
@ -420,9 +415,10 @@ void CBotProgram::Free()
CBotToken::ClearDefineNum(); CBotToken::ClearDefineNum();
m_externalCalls->Clear(); m_externalCalls->Clear();
CBotClass::ClearPublic(); CBotClass::ClearPublic();
m_externalCalls.reset();
} }
CBotExternalCallList* CBotProgram::GetExternalCalls() const std::unique_ptr<CBotExternalCallList>& CBotProgram::GetExternalCalls()
{ {
return m_externalCalls; return m_externalCalls;
} }

View File

@ -19,11 +19,12 @@
#pragma once #pragma once
#include "CBot/CBotTypResult.h"
#include "CBot/CBotEnums.h" #include "CBot/CBotEnums.h"
#include <vector>
#include <list> #include <list>
#include <memory>
#include <string>
#include <vector>
namespace CBot namespace CBot
{ {
@ -31,6 +32,7 @@ namespace CBot
class CBotFunction; class CBotFunction;
class CBotClass; class CBotClass;
class CBotStack; class CBotStack;
class CBotTypResult;
class CBotVar; class CBotVar;
class CBotExternalCallList; class CBotExternalCallList;
@ -200,14 +202,6 @@ public:
*/ */
void Stop(); void Stop();
/**
* \brief Sets the number of steps (parts of instructions) to execute in Run() before suspending the program execution
* \param n new timer value
*
* FIXME: Seems to be currently kind of broken (see issue #410)
*/
static void SetTimer(int n);
/** /**
* \brief Add a function that can be called from CBot * \brief Add a function that can be called from CBot
* *
@ -335,11 +329,11 @@ public:
/** /**
* \brief Returns static list of all registered external calls * \brief Returns static list of all registered external calls
*/ */
static CBotExternalCallList* GetExternalCalls(); static const std::unique_ptr<CBotExternalCallList>& GetExternalCalls();
private: private:
//! All external calls //! All external calls
static CBotExternalCallList* m_externalCalls; static std::unique_ptr<CBotExternalCallList> m_externalCalls;
//! All user-defined functions //! All user-defined functions
std::list<CBotFunction*> m_functions{}; std::list<CBotFunction*> m_functions{};
//! The entry point function //! The entry point function

View File

@ -39,16 +39,24 @@ namespace CBot
const int DEFAULT_TIMER = 100; const int DEFAULT_TIMER = 100;
int CBotStack::m_initimer = DEFAULT_TIMER; struct CBotStack::Data
int CBotStack::m_timer = 0; {
CBotVar* CBotStack::m_retvar = nullptr; int initimer = DEFAULT_TIMER;
CBotError CBotStack::m_error = CBotNoErr; int timer = 0;
int CBotStack::m_start = 0;
int CBotStack::m_end = 0; CBotError error = CBotNoErr;
std::string CBotStack::m_labelBreak=""; int errStart = 0;
void* CBotStack::m_pUser = nullptr; int errEnd = 0;
std::string labelBreak = "";
CBotProgram* baseProg = nullptr;
CBotStack* topStack = nullptr;
void* pUser = nullptr;
std::unique_ptr<CBotVar> retvar;
};
////////////////////////////////////////////////////////////////////////////////
CBotStack* CBotStack::AllocateStack() CBotStack* CBotStack::AllocateStack()
{ {
CBotStack* p; CBotStack* p;
@ -73,7 +81,8 @@ CBotStack* CBotStack::AllocateStack()
pp ++; pp ++;
} }
m_error = CBotNoErr; // avoids deadlocks because m_error is static p->m_data = new CBotStack::Data;
p->m_data->topStack = p;
return p; return p;
} }
@ -97,6 +106,7 @@ void CBotStack::Delete()
CBotStack* p = m_prev; CBotStack* p = m_prev;
bool bOver = m_bOver; bool bOver = m_bOver;
if ( m_prev == nullptr ) delete m_data;
// clears the freed block // clears the freed block
memset(this, 0, sizeof(CBotStack)); memset(this, 0, sizeof(CBotStack));
@ -123,6 +133,7 @@ CBotStack* CBotStack::AddStack(CBotInstr* instr, BlockVisibilityType bBlock)
while ( p->m_prev != nullptr ); while ( p->m_prev != nullptr );
m_next = p; // chain an element m_next = p; // chain an element
p->m_data = m_data;
p->m_block = bBlock; p->m_block = bBlock;
p->m_instr = instr; p->m_instr = instr;
p->m_prog = m_prog; p->m_prog = m_prog;
@ -166,6 +177,7 @@ CBotStack* CBotStack::AddStack2(BlockVisibilityType bBlock)
while ( p->m_prev != nullptr ); while ( p->m_prev != nullptr );
m_next2 = p; // chain an element m_next2 = p; // chain an element
p->m_data = m_data;
p->m_prev = this; p->m_prev = this;
p->m_block = bBlock; p->m_block = bBlock;
p->m_prog = m_prog; p->m_prog = m_prog;
@ -220,18 +232,32 @@ bool CBotStack::ReturnKeep(CBotStack* pfils)
bool CBotStack::StackOver() bool CBotStack::StackOver()
{ {
if (!m_bOver) return false; if (!m_bOver) return false;
m_error = CBotErrStackOver; m_data->error = CBotErrStackOver;
return true; return true;
} }
//////////////////////////////////////////////////////////////////////////////// CBotError CBotStack::GetError(int& start, int& end)
{
start = m_data->errStart;
end = m_data->errEnd;
return m_data->error;
}
CBotError CBotStack::GetError()
{
return m_data->error;
}
bool CBotStack::IsOk()
{
return m_data->error == CBotNoErr;
}
void CBotStack::Reset() void CBotStack::Reset()
{ {
m_timer = m_initimer; // resets the timer m_data->timer = m_data->initimer; // resets the timer
m_error = CBotNoErr; m_data->error = CBotNoErr;
// m_start = 0; m_data->labelBreak.clear();
// m_end = 0;
m_labelBreak.clear();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -258,35 +284,35 @@ CBotStack* CBotStack::RestoreStackEOX(CBotExternalCall* instr)
// routine for execution step by step // routine for execution step by step
bool CBotStack::IfStep() bool CBotStack::IfStep()
{ {
if ( m_initimer > 0 || m_step++ > 0 ) return false; if (m_data->initimer > 0 || m_step++ > 0) return false;
return true; return true;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name) bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name)
{ {
if ( m_error>=0 ) return false; // normal output if (m_data->error >= CBotNoErr) return false; // normal output
if ( m_error==CBotError(-3) ) return false; // normal output (return current) if (m_data->error == CBotError(-3)) return false; // normal output (return current)
if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name)) if (!m_data->labelBreak.empty() && (name.empty() || m_data->labelBreak != name))
return false; // it's not for me return false; // it's not for me
m_error = CBotNoErr; m_data->error = CBotNoErr;
m_labelBreak.clear(); m_data->labelBreak.clear();
return Return(pfils); return Return(pfils);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotStack::IfContinue(int state, const std::string& name) bool CBotStack::IfContinue(int state, const std::string& name)
{ {
if ( m_error != CBotError(-2) ) return false; if (m_data->error != CBotError(-2)) return false;
if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name)) if (!m_data->labelBreak.empty() && (name.empty() || m_data->labelBreak != name))
return false; // it's not for me return false; // it's not for me
m_state = state; // where again? m_state = state; // where again?
m_error = CBotNoErr; m_data->error = CBotNoErr;
m_labelBreak.clear(); m_data->labelBreak.clear();
if (m_next != nullptr) m_next->Delete(); // purge above stack if (m_next != nullptr) m_next->Delete(); // purge above stack
return true; return true;
} }
@ -294,11 +320,11 @@ bool CBotStack::IfContinue(int state, const std::string& name)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotStack::SetBreak(int val, const std::string& name) void CBotStack::SetBreak(int val, const std::string& name)
{ {
m_error = static_cast<CBotError>(-val); // reacts as an Exception m_data->error = static_cast<CBotError>(-val); // reacts as an Exception
m_labelBreak = name; m_data->labelBreak = name;
if (val == 3) // for a return if (val == 3) // for a return
{ {
m_retvar = m_var; m_data->retvar.reset(m_var);
m_var = nullptr; m_var = nullptr;
} }
} }
@ -307,12 +333,11 @@ void CBotStack::SetBreak(int val, const std::string& name)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotStack::GetRetVar(bool bRet) bool CBotStack::GetRetVar(bool bRet)
{ {
if (m_error == CBotError(-3)) if (m_data->error == CBotError(-3))
{ {
if ( m_var ) delete m_var; if ( m_var ) delete m_var;
m_var = m_retvar; m_var = m_data->retvar.release();
m_retvar = nullptr; m_data->error = CBotNoErr;
m_error = CBotNoErr;
return true; return true;
} }
return bRet; // interrupted by something other than return return bRet; // interrupted by something other than return
@ -322,7 +347,7 @@ bool CBotStack::GetRetVar(bool bRet)
CBotVar* CBotStack::FindVar(CBotToken*& pToken, bool bUpdate) CBotVar* CBotStack::FindVar(CBotToken*& pToken, bool bUpdate)
{ {
CBotStack* p = this; CBotStack* p = this;
std::string name = pToken->GetString(); const auto& name = pToken->GetString();
while (p != nullptr) while (p != nullptr)
{ {
@ -332,7 +357,7 @@ CBotVar* CBotStack::FindVar(CBotToken*& pToken, bool bUpdate)
if (pp->GetName() == name) if (pp->GetName() == name)
{ {
if ( bUpdate ) if ( bUpdate )
pp->Update(m_pUser); pp->Update(m_data->pUser);
return pp; return pp;
} }
@ -375,7 +400,7 @@ CBotVar* CBotStack::FindVar(long ident, bool bUpdate)
if (pp->GetUniqNum() == ident) if (pp->GetUniqNum() == ident)
{ {
if ( bUpdate ) if ( bUpdate )
pp->Update(m_pUser); pp->Update(m_data->pUser);
return pp; return pp;
} }
@ -410,8 +435,8 @@ bool CBotStack::SetState(int n, int limite)
{ {
m_state = n; m_state = n;
m_timer--; // decrement the timer m_data->timer--; // decrement the timer
return ( m_timer > limite ); // interrupted if timer pass return (m_data->timer > limite); // interrupted if timer pass
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -419,46 +444,46 @@ bool CBotStack::IncState(int limite)
{ {
m_state++; m_state++;
m_timer--; // decrement the timer m_data->timer--; // decrement the timer
return ( m_timer > limite ); // interrupted if timer pass return (m_data->timer > limite); // interrupted if timer pass
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotStack::SetError(CBotError n, CBotToken* token) void CBotStack::SetError(CBotError n, CBotToken* token)
{ {
if (n != CBotNoErr && m_error != CBotNoErr) return; // does not change existing error if (n != CBotNoErr && m_data->error != CBotNoErr) return; // does not change existing error
m_error = n; m_data->error = n;
if (token != nullptr) if (token != nullptr)
{ {
m_start = token->GetStart(); m_data->errStart = token->GetStart();
m_end = token->GetEnd(); m_data->errEnd = token->GetEnd();
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotStack::ResetError(CBotError n, int start, int end) void CBotStack::ResetError(CBotError n, int start, int end)
{ {
m_error = n; m_data->error = n;
m_start = start; m_data->errStart = start;
m_end = end; m_data->errEnd = end;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotStack::SetPosError(CBotToken* token) void CBotStack::SetPosError(CBotToken* token)
{ {
m_start = token->GetStart(); m_data->errStart = token->GetStart();
m_end = token->GetEnd(); m_data->errEnd = token->GetEnd();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotStack::SetTimer(int n) void CBotStack::SetTimer(int n)
{ {
m_initimer = n; m_data->initimer = n;
} }
int CBotStack::GetTimer() int CBotStack::GetTimer()
{ {
return m_initimer; return m_data->initimer;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -542,26 +567,25 @@ void CBotStack::SetProgram(CBotProgram* p)
{ {
m_prog = p; m_prog = p;
m_func = IsFunction::YES; m_func = IsFunction::YES;
if (this == m_data->topStack) m_data->baseProg = p;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotProgram* CBotStack::GetProgram(bool bFirst) CBotProgram* CBotStack::GetProgram(bool bFirst)
{ {
if ( ! bFirst ) return m_prog; if ( ! bFirst ) return m_prog;
CBotStack* p = this; return m_data->baseProg;
while ( p->m_prev != nullptr ) p = p->m_prev;
return p->m_prog;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void* CBotStack::GetUserPtr() void* CBotStack::GetUserPtr()
{ {
return m_pUser; return m_data->pUser;
} }
void CBotStack::SetUserPtr(void* user) void CBotStack::SetUserPtr(void* user)
{ {
m_pUser = user; m_data->pUser = user;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -908,13 +932,18 @@ bool CBotVar::RestoreState(std::istream &istr, CBotVar* &pVar)
if (isClass && p == nullptr) // set id for each item in this instance if (isClass && p == nullptr) // set id for each item in this instance
{ {
CBotVar* pVars = pNew->GetItemList(); CBotClass* pClass = pNew->GetClass();
CBotVar* pv = pNew->GetClass()->GetVar(); CBotVar* pVars = (static_cast<CBotVarClass*>(pNew))->m_pVar;
while (pVars != nullptr && pv != nullptr) while (pClass != nullptr && pVars != nullptr)
{ {
pVars->m_ident = pv->m_ident; CBotVar* pv = pClass->GetVar();
pv = pv->GetNext(); while (pVars != nullptr && pv != nullptr)
pVars = pVars->GetNext(); {
pVars->m_ident = pv->m_ident;
pVars = pVars->m_next;
pv = pv->m_next;
}
pClass = pClass->GetParent();
} }
} }

View File

@ -82,9 +82,6 @@ public:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** \name Error management /** \name Error management
*
* BE CAREFUL - errors are stored in static variables!
* \todo Refactor that
*/ */
//@{ //@{
@ -94,24 +91,21 @@ public:
* \param[out] end Ending position in code of the error * \param[out] end Ending position in code of the error
* \return Error number * \return Error number
*/ */
CBotError GetError(int& start, int& end) { start = m_start; end = m_end; return m_error; } CBotError GetError(int& start, int& end);
/** /**
* \brief Get last error * \brief Get last error
* \return Error number * \return Error number
* \see GetError(int&, int&) for error position in code * \see GetError(int&, int&) for error position in code
*/ */
CBotError GetError() { return m_error; } CBotError GetError();
/** /**
* \brief Check if there was an error * \brief Check if there was an error
* \return false if an error occurred * \return false if an error occurred
* \see GetError() * \see GetError()
*/ */
bool IsOk() bool IsOk();
{
return m_error == CBotNoErr;
}
/** /**
* \brief Set execution error unless it's already set unless you are trying to reset it * \brief Set execution error unless it's already set unless you are trying to reset it
@ -357,7 +351,7 @@ public:
/** /**
* \todo Document * \todo Document
* *
* Copies the result value from static m_retvar (m_var at a moment of SetBreak(3)) to this stack result * Copies the result value from m_data->retvar (m_var at a moment of SetBreak(3)) to this stack result
*/ */
bool GetRetVar(bool bRet); bool GetRetVar(bool bRet);
@ -446,11 +440,11 @@ public:
* *
* \todo Full documentation of the timer * \todo Full documentation of the timer
*/ */
static void SetTimer(int n); void SetTimer(int n);
/** /**
* \brief Get the current configured maximum number of "timer ticks" (parts of instructions) to execute * \brief Get the current configured maximum number of "timer ticks" (parts of instructions) to execute
*/ */
static int GetTimer(); int GetTimer();
/** /**
* \brief Get current position in the program * \brief Get current position in the program
@ -476,10 +470,10 @@ private:
int m_state; int m_state;
int m_step; int m_step;
static CBotError m_error;
static int m_start; struct Data;
static int m_end;
static CBotVar* m_retvar; // result of a return CBotStack::Data* m_data;
CBotVar* m_var; // result of the operations CBotVar* m_var; // result of the operations
CBotVar* m_listVar; // variables declared at this level CBotVar* m_listVar; // variables declared at this level
@ -489,11 +483,6 @@ private:
//! CBotProgram instance the execution is in in this stack level //! CBotProgram instance the execution is in in this stack level
CBotProgram* m_prog; CBotProgram* m_prog;
static int m_initimer;
static int m_timer;
static std::string m_labelBreak;
static void* m_pUser;
//! The corresponding instruction //! The corresponding instruction
CBotInstr* m_instr; CBotInstr* m_instr;
//! If this stack level holds a function call //! If this stack level holds a function call

View File

@ -65,6 +65,7 @@ static const boost::bimap<TokenId, std::string> KEYWORDS = makeBimap<TokenId, st
{ID_STATIC, "static"}, {ID_STATIC, "static"},
{ID_PROTECTED, "protected"}, {ID_PROTECTED, "protected"},
{ID_PRIVATE, "private"}, {ID_PRIVATE, "private"},
{ID_REPEAT, "repeat"},
{ID_INT, "int"}, {ID_INT, "int"},
{ID_FLOAT, "float"}, {ID_FLOAT, "float"},
{ID_BOOLEAN, "boolean"}, {ID_BOOLEAN, "boolean"},

View File

@ -54,7 +54,6 @@ CBotVarClass::CBotVarClass(const CBotToken& name, const CBotTypResult& type) : C
// official type for this object // official type for this object
m_pClass = nullptr; m_pClass = nullptr;
m_pParent = nullptr;
m_binit = InitType::UNDEF; m_binit = InitType::UNDEF;
m_bStatic = false; m_bStatic = false;
m_mPrivate = ProtectionLevel::Public; m_mPrivate = ProtectionLevel::Public;
@ -63,14 +62,9 @@ CBotVarClass::CBotVarClass(const CBotToken& name, const CBotTypResult& type) : C
m_ItemIdent = type.Eq(CBotTypIntrinsic) ? 0 : CBotVar::NextUniqNum(); m_ItemIdent = type.Eq(CBotTypIntrinsic) ? 0 : CBotVar::NextUniqNum();
// add to the list // add to the list
m_instances.insert(this); if (m_ItemIdent != 0) m_instances.insert(this);
CBotClass* pClass = type.GetClass(); CBotClass* pClass = type.GetClass();
if ( pClass != nullptr && pClass->GetParent() != nullptr )
{
// also creates an instance of the parent class
m_pParent = new CBotVarClass(name, CBotTypResult(type.GetType(), pClass->GetParent()) ); //, nIdent);
}
SetClass( pClass ); SetClass( pClass );
@ -82,11 +76,8 @@ CBotVarClass::~CBotVarClass( )
if ( m_CptUse != 0 ) if ( m_CptUse != 0 )
assert(0); assert(0);
if ( m_pParent ) delete m_pParent;
m_pParent = nullptr;
// removes the class list // removes the class list
m_instances.erase(this); if (m_ItemIdent != 0) m_instances.erase(this);
delete m_pVar; delete m_pVar;
} }
@ -113,10 +104,6 @@ void CBotVarClass::Copy(CBotVar* pSrc, bool bName)
m_binit = p->m_binit; m_binit = p->m_binit;
//- m_bStatic = p->m_bStatic; //- m_bStatic = p->m_bStatic;
m_pClass = p->m_pClass; m_pClass = p->m_pClass;
if ( p->m_pParent )
{
assert(0); // "que faire du pParent";
}
// m_next = nullptr; // m_next = nullptr;
m_pUserPtr = p->m_pUserPtr; m_pUserPtr = p->m_pUserPtr;
@ -162,9 +149,11 @@ void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent)
if (pClass == nullptr) return; if (pClass == nullptr) return;
CBotVar* pv = pClass->GetVar(); // first on a list CBotVar* pv = nullptr;
while ( pv != nullptr ) while (pClass != nullptr)
{ {
if ( pv == nullptr ) pv = pClass->GetVar();
if ( pv == nullptr ) { pClass = pClass->GetParent(); continue; }
// seeks the maximum dimensions of the table // seeks the maximum dimensions of the table
CBotInstr* p = pv->m_LimExpr; // the different formulas CBotInstr* p = pv->m_LimExpr; // the different formulas
if ( p != nullptr ) if ( p != nullptr )
@ -214,6 +203,7 @@ void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent)
if ( m_pVar == nullptr) m_pVar = pn; if ( m_pVar == nullptr) m_pVar = pn;
else m_pVar->AddNext( pn ); else m_pVar->AddNext( pn );
pv = pv->GetNext(); pv = pv->GetNext();
if ( pv == nullptr ) pClass = pClass->GetParent();
} }
} }
@ -246,7 +236,6 @@ CBotVar* CBotVarClass::GetItem(const std::string& name)
p = p->GetNext(); p = p->GetNext();
} }
if ( m_pParent != nullptr ) return m_pParent->GetItem(name);
return nullptr; return nullptr;
} }
@ -261,7 +250,6 @@ CBotVar* CBotVarClass::GetItemRef(int nIdent)
p = p->GetNext(); p = p->GetNext();
} }
if ( m_pParent != nullptr ) return m_pParent->GetItemRef(nIdent);
return nullptr; return nullptr;
} }
@ -311,32 +299,46 @@ std::string CBotVarClass::GetValString()
{ {
res = m_pClass->GetName() + std::string("( "); res = m_pClass->GetName() + std::string("( ");
CBotVarClass* my = this; CBotClass* pClass = m_pClass;
while ( my != nullptr ) long prevID = 0;
{ {
CBotVar* pv = my->m_pVar; CBotVar* pv = m_pVar;
while ( pv != nullptr ) if (pv != nullptr) while (true)
{ {
if (pv->GetUniqNum() < prevID)
{
pClass = pClass->GetParent();
if (pClass == nullptr) break;
res += " ) extends ";
res += pClass->GetName();
res += "( ";
if (pClass->GetVar() == nullptr) continue;
}
prevID = pv->GetUniqNum();
res += pv->GetName() + std::string("="); res += pv->GetName() + std::string("=");
if ( pv->IsStatic() ) if ( pv->IsStatic() )
{ {
CBotVar* pvv = my->m_pClass->GetItem(pv->GetName()); res += pClass->GetItemRef(prevID)->GetValString();
res += pvv->GetValString();
} }
else else
{ {
res += pv->GetValString(); res += pv->GetValString();
} }
pv = pv->GetNext(); pv = pv->GetNext();
if ( pv != nullptr ) res += ", "; if ( pv == nullptr ) break;
if ( pv->GetUniqNum() > prevID ) res += ", ";
} }
my = my->m_pParent;
if ( my != nullptr ) if (pClass != nullptr) while (true)
{ {
res += ") extends "; pClass = pClass->GetParent();
res += my->m_pClass->GetName(); if (pClass == nullptr) break;
res += " ("; res += " ) extends ";
res += pClass->GetName();
res += "( ";
} }
} }
@ -378,14 +380,7 @@ void CBotVarClass::DecrementUse()
{ {
m_CptUse++; // does not return to the destructor m_CptUse++; // does not return to the destructor
// m_error is static in the stack CBotStack* pile = CBotStack::AllocateStack();
// saves the value for return
CBotError err;
int start, end;
CBotStack* pile = nullptr;
err = pile->GetError(start,end); // stack == nullptr it does not bother!
pile = CBotStack::AllocateStack(); // clears the error
CBotVar* ppVars[1]; CBotVar* ppVars[1];
ppVars[0] = nullptr; ppVars[0] = nullptr;
@ -399,8 +394,6 @@ void CBotVarClass::DecrementUse()
while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, pThis, ppVars, CBotTypResult(CBotTypVoid), pile, &token)) ; // waits for the end while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, pThis, ppVars, CBotTypResult(CBotTypVoid), pile, &token)) ; // waits for the end
pile->ResetError(err, start,end);
pile->Delete(); pile->Delete();
delete pThis; delete pThis;
m_CptUse--; m_CptUse--;

View File

@ -99,8 +99,6 @@ private:
static std::set<CBotVarClass*> m_instances; static std::set<CBotVarClass*> m_instances;
//! Class definition //! Class definition
CBotClass* m_pClass; CBotClass* m_pClass;
//! Parent class instance
CBotVarClass* m_pParent;
//! Class members //! Class members
CBotVar* m_pVar; CBotVar* m_pVar;
//! Reference counter //! Reference counter

View File

@ -110,6 +110,8 @@ target_sources(CBot PRIVATE
CBotInstr/CBotPostIncExpr.h CBotInstr/CBotPostIncExpr.h
CBotInstr/CBotPreIncExpr.cpp CBotInstr/CBotPreIncExpr.cpp
CBotInstr/CBotPreIncExpr.h CBotInstr/CBotPreIncExpr.h
CBotInstr/CBotRepeat.cpp
CBotInstr/CBotRepeat.h
CBotInstr/CBotReturn.cpp CBotInstr/CBotReturn.cpp
CBotInstr/CBotReturn.h CBotInstr/CBotReturn.h
CBotInstr/CBotSwitch.cpp CBotInstr/CBotSwitch.cpp

View File

@ -144,13 +144,36 @@ bool rRand(CBotVar* var, CBotVar* result, int& exception, void* user)
bool rAbs(CBotVar* var, CBotVar* result, int& exception, void* user) bool rAbs(CBotVar* var, CBotVar* result, int& exception, void* user)
{ {
float value; switch (result->GetType())
{
case CBotTypDouble:
*result = fabs(var->GetValDouble());
break;
case CBotTypFloat:
*result = fabs(var->GetValFloat());
break;
case CBotTypLong:
*result = labs(var->GetValLong());
break;
default:
*result = abs(var->GetValInt());
break;
}
value = var->GetValFloat();
result->SetValFloat(fabs(value));
return true; return true;
} }
CBotTypResult cAbs(CBotVar* &var, void* user)
{
if ( var == nullptr ) return CBotTypResult(CBotErrLowParam);
if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
CBotTypResult returnType(var->GetType());
var = var->GetNext();
if ( var != nullptr ) return CBotTypResult(CBotErrOverParam);
return returnType;
}
// Instruction "floor()" // Instruction "floor()"
bool rFloor(CBotVar* var, CBotVar* result, int& exception, void* user) bool rFloor(CBotVar* var, CBotVar* result, int& exception, void* user)
@ -209,7 +232,7 @@ void InitMathFunctions()
CBotProgram::AddFunction("sqrt", rSqrt, cOneFloat); CBotProgram::AddFunction("sqrt", rSqrt, cOneFloat);
CBotProgram::AddFunction("pow", rPow, cTwoFloat); CBotProgram::AddFunction("pow", rPow, cTwoFloat);
CBotProgram::AddFunction("rand", rRand, cNull); CBotProgram::AddFunction("rand", rRand, cNull);
CBotProgram::AddFunction("abs", rAbs, cOneFloat); CBotProgram::AddFunction("abs", rAbs, cAbs);
CBotProgram::AddFunction("floor", rFloor, cOneFloat); CBotProgram::AddFunction("floor", rFloor, cOneFloat);
CBotProgram::AddFunction("ceil", rCeil, cOneFloat); CBotProgram::AddFunction("ceil", rCeil, cOneFloat);
CBotProgram::AddFunction("round", rRound, cOneFloat); CBotProgram::AddFunction("round", rRound, cOneFloat);

View File

@ -24,6 +24,8 @@ add_library(colobotbase STATIC
app/controller.h app/controller.h
app/input.cpp app/input.cpp
app/input.h app/input.h
app/modman.cpp
app/modman.h
app/pathman.cpp app/pathman.cpp
app/pathman.h app/pathman.h
app/pausemanager.cpp app/pausemanager.cpp
@ -297,6 +299,7 @@ add_library(colobotbase STATIC
object/object_interface_type.h object/object_interface_type.h
object/object_manager.cpp object/object_manager.cpp
object/object_manager.h object/object_manager.h
object/object_type.cpp
object/object_type.h object/object_type.h
object/old_object.cpp object/old_object.cpp
object/old_object.h object/old_object.h
@ -446,6 +449,8 @@ add_library(colobotbase STATIC
ui/screen/screen_loading.h ui/screen/screen_loading.h
ui/screen/screen_main_menu.cpp ui/screen/screen_main_menu.cpp
ui/screen/screen_main_menu.h ui/screen/screen_main_menu.h
ui/screen/screen_mod_list.cpp
ui/screen/screen_mod_list.h
ui/screen/screen_player_select.cpp ui/screen/screen_player_select.cpp
ui/screen/screen_player_select.h ui/screen/screen_player_select.h
ui/screen/screen_quit.cpp ui/screen/screen_quit.cpp

View File

@ -21,6 +21,7 @@
#include "app/controller.h" #include "app/controller.h"
#include "app/input.h" #include "app/input.h"
#include "app/modman.h"
#include "app/pathman.h" #include "app/pathman.h"
#include "common/config_file.h" #include "common/config_file.h"
@ -113,7 +114,8 @@ CApplication::CApplication(CSystemUtils* systemUtils)
m_private(MakeUnique<ApplicationPrivate>()), m_private(MakeUnique<ApplicationPrivate>()),
m_configFile(MakeUnique<CConfigFile>()), m_configFile(MakeUnique<CConfigFile>()),
m_input(MakeUnique<CInput>()), m_input(MakeUnique<CInput>()),
m_pathManager(MakeUnique<CPathManager>(systemUtils)) m_pathManager(MakeUnique<CPathManager>(systemUtils)),
m_modManager(MakeUnique<CModManager>(this, m_pathManager.get()))
{ {
m_exitCode = 0; m_exitCode = 0;
m_active = false; m_active = false;
@ -220,6 +222,11 @@ CSoundInterface* CApplication::GetSound()
return m_sound.get(); return m_sound.get();
} }
CModManager* CApplication::GetModManager()
{
return m_modManager.get();
}
void CApplication::LoadEnvironmentVariables() void CApplication::LoadEnvironmentVariables()
{ {
auto dataDir = m_systemUtils->GetEnvVar("COLOBOT_DATA_DIR"); auto dataDir = m_systemUtils->GetEnvVar("COLOBOT_DATA_DIR");
@ -513,6 +520,10 @@ bool CApplication::Create()
GetLogger()->Warn("Config could not be loaded. Default values will be used!\n"); GetLogger()->Warn("Config could not be loaded. Default values will be used!\n");
} }
m_modManager->FindMods();
m_modManager->SaveMods();
m_modManager->MountAllMods();
// Create the sound instance. // Create the sound instance.
#ifdef OPENAL_SOUND #ifdef OPENAL_SOUND
if (!m_headless) if (!m_headless)
@ -538,6 +549,8 @@ bool CApplication::Create()
/* SDL initialization sequence */ /* SDL initialization sequence */
// Creating the m_engine now because it holds the vsync flag
m_engine = MakeUnique<Gfx::CEngine>(this, m_systemUtils);
Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_TIMER; Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_TIMER;
@ -682,8 +695,6 @@ bool CApplication::Create()
} }
// Create the 3D engine // Create the 3D engine
m_engine = MakeUnique<Gfx::CEngine>(this, m_systemUtils);
m_engine->SetDevice(m_device.get()); m_engine->SetDevice(m_device.get());
if (! m_engine->Create() ) if (! m_engine->Create() )
@ -698,21 +709,7 @@ bool CApplication::Create()
// Create the robot application. // Create the robot application.
m_controller = MakeUnique<CController>(); m_controller = MakeUnique<CController>();
CThread musicLoadThread([this]() StartLoadingMusic();
{
GetLogger()->Debug("Cache sounds...\n");
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
m_sound->CacheAll();
SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
},
"Sound loading thread");
musicLoadThread.Start();
if (m_runSceneCategory == LevelCategory::Max) if (m_runSceneCategory == LevelCategory::Max)
m_controller->StartApp(); m_controller->StartApp();
@ -726,6 +723,15 @@ bool CApplication::Create()
return true; return true;
} }
void CApplication::ReloadResources()
{
GetLogger()->Info("Reloading resources\n");
m_engine->ReloadAllTextures();
StartLoadingMusic();
m_controller->GetRobotMain()->UpdateCustomLevelList();
}
bool CApplication::CreateVideoSurface() bool CApplication::CreateVideoSurface()
{ {
Uint32 videoFlags = SDL_WINDOW_OPENGL; Uint32 videoFlags = SDL_WINDOW_OPENGL;
@ -844,24 +850,9 @@ bool CApplication::CreateVideoSurface()
int vsync = 0; int vsync = 0;
if (GetConfigFile().GetIntProperty("Setup", "VSync", vsync)) if (GetConfigFile().GetIntProperty("Setup", "VSync", vsync))
{ {
while (SDL_GL_SetSwapInterval(vsync) == -1) m_engine->SetVSync(vsync);
{ TryToSetVSync();
switch(vsync) vsync = m_engine->GetVSync();
{
case -1: //failed with adaptive sync?
GetLogger()->Warn("Adaptive sync not supported.\n");
vsync = 1;
break;
case 1: //failed with VSync enabled?
GetLogger()->Warn("Couldn't enable VSync.\n");
vsync = 0;
break;
case 0: //failed with VSync disabled?
GetLogger()->Warn("Couldn't disable VSync.\n");
vsync = 1;
break;
}
}
GetConfigFile().SetIntProperty("Setup", "VSync", vsync); GetConfigFile().SetIntProperty("Setup", "VSync", vsync);
GetLogger()->Info("Using Vsync: %s\n", (vsync == -1 ? "adaptive" : (vsync ? "true" : "false"))); GetLogger()->Info("Using Vsync: %s\n", (vsync == -1 ? "adaptive" : (vsync ? "true" : "false")));
@ -870,6 +861,32 @@ bool CApplication::CreateVideoSurface()
return true; return true;
} }
void CApplication::TryToSetVSync()
{
int vsync = m_engine->GetVSync();
int result = SDL_GL_SetSwapInterval(vsync);
if (result == -1)
{
switch (vsync)
{
case -1:
GetLogger()->Warn("Adaptive sync not supported: %s\n", SDL_GetError());
m_engine->SetVSync(1);
TryToSetVSync();
break;
case 1:
GetLogger()->Warn("Couldn't enable VSync: %s\n", SDL_GetError());
m_engine->SetVSync(0);
TryToSetVSync();
break;
case 0:
GetLogger()->Warn("Couldn't disable VSync: %s\n", SDL_GetError());
m_engine->SetVSync(SDL_GL_GetSwapInterval());
break;
}
}
}
bool CApplication::ChangeVideoConfig(const Gfx::DeviceConfig &newConfig) bool CApplication::ChangeVideoConfig(const Gfx::DeviceConfig &newConfig)
{ {
m_deviceConfig = newConfig; m_deviceConfig = newConfig;
@ -878,26 +895,7 @@ bool CApplication::ChangeVideoConfig(const Gfx::DeviceConfig &newConfig)
SDL_SetWindowSize(m_private->window, m_deviceConfig.size.x, m_deviceConfig.size.y); SDL_SetWindowSize(m_private->window, m_deviceConfig.size.x, m_deviceConfig.size.y);
SDL_SetWindowFullscreen(m_private->window, m_deviceConfig.fullScreen ? SDL_WINDOW_FULLSCREEN : 0); SDL_SetWindowFullscreen(m_private->window, m_deviceConfig.fullScreen ? SDL_WINDOW_FULLSCREEN : 0);
int vsync = m_engine->GetVSync(); TryToSetVSync();
while (SDL_GL_SetSwapInterval(vsync) == -1)
{
switch(vsync)
{
case -1: //failed with adaptive sync?
GetLogger()->Warn("Adaptive sync not supported.\n");
vsync = 1;
break;
case 1: //failed with VSync enabled?
GetLogger()->Warn("Couldn't enable VSync.\n");
vsync = 0;
break;
case 0: //failed with VSync disabled?
GetLogger()->Warn("Couldn't disable VSync.\n");
vsync = 1;
break;
}
}
m_engine->SetVSync(vsync);
m_device->ConfigChanged(m_deviceConfig); m_device->ConfigChanged(m_deviceConfig);
@ -1060,6 +1058,10 @@ int CApplication::Run()
MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start
SystemTimeStamp *previousTimeStamp = m_systemUtils->CreateTimeStamp();
SystemTimeStamp *currentTimeStamp = m_systemUtils->CreateTimeStamp();
SystemTimeStamp *interpolatedTimeStamp = m_systemUtils->CreateTimeStamp();
while (true) while (true)
{ {
if (m_active) if (m_active)
@ -1158,21 +1160,30 @@ int CApplication::Run()
CProfiler::StartPerformanceCounter(PCNT_UPDATE_ALL); CProfiler::StartPerformanceCounter(PCNT_UPDATE_ALL);
// Prepare and process step simulation event // Prepare and process step simulation event(s)
Event event = CreateUpdateEvent(); // If game speed is increased then we do extra ticks per loop iteration to improve physics accuracy.
if (event.type != EVENT_NULL && m_controller != nullptr) int numTickSlices = static_cast<int>(GetSimulationSpeed());
if(numTickSlices < 1) numTickSlices = 1;
m_systemUtils->CopyTimeStamp(previousTimeStamp, m_curTimeStamp);
m_systemUtils->GetCurrentTimeStamp(currentTimeStamp);
for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++)
{ {
LogEvent(event); m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast<float>(numTickSlices));
Event event = CreateUpdateEvent(interpolatedTimeStamp);
if (event.type != EVENT_NULL && m_controller != nullptr)
{
LogEvent(event);
m_sound->FrameMove(m_relTime); m_sound->FrameMove(m_relTime);
CProfiler::StartPerformanceCounter(PCNT_UPDATE_GAME); CProfiler::StartPerformanceCounter(PCNT_UPDATE_GAME);
m_controller->ProcessEvent(event); m_controller->ProcessEvent(event);
CProfiler::StopPerformanceCounter(PCNT_UPDATE_GAME); CProfiler::StopPerformanceCounter(PCNT_UPDATE_GAME);
CProfiler::StartPerformanceCounter(PCNT_UPDATE_ENGINE); CProfiler::StartPerformanceCounter(PCNT_UPDATE_ENGINE);
m_engine->FrameUpdate(); m_engine->FrameUpdate();
CProfiler::StopPerformanceCounter(PCNT_UPDATE_ENGINE); CProfiler::StopPerformanceCounter(PCNT_UPDATE_ENGINE);
}
} }
CProfiler::StopPerformanceCounter(PCNT_UPDATE_ALL); CProfiler::StopPerformanceCounter(PCNT_UPDATE_ALL);
@ -1188,6 +1199,10 @@ int CApplication::Run()
} }
end: end:
m_systemUtils->DestroyTimeStamp(previousTimeStamp);
m_systemUtils->DestroyTimeStamp(currentTimeStamp);
m_systemUtils->DestroyTimeStamp(interpolatedTimeStamp);
return m_exitCode; return m_exitCode;
} }
@ -1520,6 +1535,26 @@ void CApplication::InternalResumeSimulation()
m_absTimeBase = m_exactAbsTime; m_absTimeBase = m_exactAbsTime;
} }
void CApplication::StartLoadingMusic()
{
CThread musicLoadThread([this]()
{
GetLogger()->Debug("Cache sounds...\n");
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
m_sound->Reset();
m_sound->CacheAll();
SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
},
"Sound loading thread");
musicLoadThread.Start();
}
bool CApplication::GetSimulationSuspended() const bool CApplication::GetSimulationSuspended() const
{ {
return m_simulationSuspended; return m_simulationSuspended;
@ -1529,20 +1564,20 @@ void CApplication::SetSimulationSpeed(float speed)
{ {
m_simulationSpeed = speed; m_simulationSpeed = speed;
m_systemUtils->GetCurrentTimeStamp(m_baseTimeStamp); m_systemUtils->CopyTimeStamp(m_baseTimeStamp, m_curTimeStamp);
m_realAbsTimeBase = m_realAbsTime; m_realAbsTimeBase = m_realAbsTime;
m_absTimeBase = m_exactAbsTime; m_absTimeBase = m_exactAbsTime;
GetLogger()->Info("Simulation speed = %.2f\n", speed); GetLogger()->Info("Simulation speed = %.2f\n", speed);
} }
Event CApplication::CreateUpdateEvent() Event CApplication::CreateUpdateEvent(SystemTimeStamp *newTimeStamp)
{ {
if (m_simulationSuspended) if (m_simulationSuspended)
return Event(EVENT_NULL); return Event(EVENT_NULL);
m_systemUtils->CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp); m_systemUtils->CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp);
m_systemUtils->GetCurrentTimeStamp(m_curTimeStamp); m_systemUtils->CopyTimeStamp(m_curTimeStamp, newTimeStamp);
long long absDiff = m_systemUtils->TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp); long long absDiff = m_systemUtils->TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp);
long long newRealAbsTime = m_realAbsTimeBase + absDiff; long long newRealAbsTime = m_realAbsTimeBase + absDiff;

View File

@ -42,6 +42,7 @@ class CEventQueue;
class CController; class CController;
class CSoundInterface; class CSoundInterface;
class CInput; class CInput;
class CModManager;
class CPathManager; class CPathManager;
class CConfigFile; class CConfigFile;
class CSystemUtils; class CSystemUtils;
@ -162,6 +163,8 @@ public:
CEventQueue* GetEventQueue(); CEventQueue* GetEventQueue();
//! Returns the sound subsystem //! Returns the sound subsystem
CSoundInterface* GetSound(); CSoundInterface* GetSound();
//! Returns the mod manager
CModManager* GetModManager();
public: public:
//! Loads some data from environment variables //! Loads some data from environment variables
@ -170,6 +173,8 @@ public:
ParseArgsStatus ParseArguments(int argc, char *argv[]); ParseArgsStatus ParseArguments(int argc, char *argv[]);
//! Initializes the application //! Initializes the application
bool Create(); bool Create();
//! Reloads the application resources, e.g. mods
void ReloadResources();
//! Main event loop //! Main event loop
int Run(); int Run();
//! Returns the code to be returned at main() exit //! Returns the code to be returned at main() exit
@ -283,13 +288,16 @@ public:
protected: protected:
//! Creates the window's SDL_Surface //! Creates the window's SDL_Surface
bool CreateVideoSurface(); bool CreateVideoSurface();
//! Tries to set the SDL vsync state desired by the 3D engine
//! The final state of SDL vsync is set in the 3D engine afterwards
void TryToSetVSync();
//! Processes the captured SDL event to Event struct //! Processes the captured SDL event to Event struct
Event ProcessSystemEvent(); Event ProcessSystemEvent();
//! If applicable, creates a virtual event to match the changed state as of new event //! If applicable, creates a virtual event to match the changed state as of new event
Event CreateVirtualEvent(const Event& sourceEvent); Event CreateVirtualEvent(const Event& sourceEvent);
//! Prepares a simulation update event //! Prepares a simulation update event
TEST_VIRTUAL Event CreateUpdateEvent(); TEST_VIRTUAL Event CreateUpdateEvent(SystemTimeStamp *newTimeStamp);
//! Logs debug data for event //! Logs debug data for event
void LogEvent(const Event& event); void LogEvent(const Event& event);
@ -301,6 +309,9 @@ protected:
//! Internal procedure to reset time counters //! Internal procedure to reset time counters
void InternalResumeSimulation(); void InternalResumeSimulation();
//! Loads music in a new thread
void StartLoadingMusic();
protected: protected:
//! System utils instance //! System utils instance
CSystemUtils* m_systemUtils; CSystemUtils* m_systemUtils;
@ -322,6 +333,8 @@ protected:
std::unique_ptr<CInput> m_input; std::unique_ptr<CInput> m_input;
//! Path manager //! Path manager
std::unique_ptr<CPathManager> m_pathManager; std::unique_ptr<CPathManager> m_pathManager;
//! Mod manager
std::unique_ptr<CModManager> m_modManager;
//! Code to return at exit //! Code to return at exit
int m_exitCode; int m_exitCode;

358
src/app/modman.cpp Normal file
View File

@ -0,0 +1,358 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "app/modman.h"
#include "common/config.h"
#include "app/app.h"
#include "app/pathman.h"
#include "common/config_file.h"
#include "common/logger.h"
#include "common/resources/resourcemanager.h"
#include "level/parser/parser.h"
#include <algorithm>
#include <map>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
using namespace boost::filesystem;
CModManager::CModManager(CApplication* app, CPathManager* pathManager)
: m_app{app},
m_pathManager{pathManager}
{
}
void CModManager::FindMods()
{
m_mods.clear();
m_userChanges = false;
// Load names from the config file
std::vector<std::string> savedModNames;
GetConfigFile().GetArrayProperty("Mods", "Names", savedModNames);
std::vector<bool> savedEnabled;
GetConfigFile().GetArrayProperty("Mods", "Enabled", savedEnabled);
// Transform the data into Mod structures
m_mods.reserve(savedModNames.size());
for (size_t i = 0; i < savedModNames.size(); ++i)
{
Mod mod{};
mod.name = savedModNames[i];
if (i < savedEnabled.size())
{
mod.enabled = savedEnabled[i];
}
mod.path = ""; // Find the path later
m_mods.push_back(mod);
}
// Search the folders for mods
auto rawPaths = m_pathManager->FindMods();
std::map<std::string, std::string> modPaths;
for (const auto& path : rawPaths)
{
auto modName = boost::filesystem::path(path).stem().string();
modPaths.insert(std::make_pair(modName, path));
}
// Find paths for already saved mods
auto it = m_mods.begin();
while (it != m_mods.end())
{
auto& mod = *it;
const auto pathsIt = modPaths.find(mod.name);
if (pathsIt != modPaths.end())
{
mod.path = (*pathsIt).second;
modPaths.erase(pathsIt);
++it;
}
else
{
GetLogger()->Warn("Could not find mod %s, removing it from the list\n", mod.name.c_str());
it = m_mods.erase(it);
}
}
// Add the remaining found mods to the end of the list
for (const auto& newMod : modPaths)
{
Mod mod{};
mod.name = newMod.first;
mod.path = newMod.second;
m_mods.push_back(mod);
}
// Load the metadata for each mod
// Unfortunately, the paths are distinguished by their real paths, not mount points
// So we must unmount mods temporarily
for (const auto& path : m_mountedModPaths)
{
UnmountMod(path);
}
for (auto& mod : m_mods)
{
MountMod(mod, "/temp/mod");
LoadModData(mod);
UnmountMod(mod);
}
// Mount back
for (const auto& path : m_mountedModPaths)
{
MountMod(path);
}
}
void CModManager::ReloadMods()
{
UnmountAllMountedMods();
MountAllMods();
ReloadResources();
}
void CModManager::EnableMod(size_t i)
{
m_mods[i].enabled = true;
m_userChanges = true;
}
void CModManager::DisableMod(size_t i)
{
m_mods[i].enabled = false;
m_userChanges = true;
}
size_t CModManager::MoveUp(size_t i)
{
if (i != 0)
{
std::swap(m_mods[i - 1], m_mods[i]);
m_userChanges = true;
return i - 1;
}
else
{
return i;
}
}
size_t CModManager::MoveDown(size_t i)
{
if (i != m_mods.size() - 1)
{
std::swap(m_mods[i], m_mods[i + 1]);
m_userChanges = true;
return i + 1;
}
else
{
return i;
}
}
bool CModManager::Changes()
{
std::vector<std::string> paths;
for (const auto& mod : m_mods)
{
if (mod.enabled)
{
paths.push_back(mod.path);
}
}
return paths != m_mountedModPaths || m_userChanges;
}
void CModManager::MountAllMods()
{
for (const auto& mod : m_mods)
{
if (mod.enabled)
{
MountMod(mod);
m_mountedModPaths.push_back(mod.path);
}
}
}
void CModManager::ReloadResources()
{
m_app->ReloadResources();
}
void CModManager::SaveMods()
{
std::vector<std::string> savedNames;
savedNames.reserve(m_mods.size());
std::transform(m_mods.begin(), m_mods.end(), std::back_inserter(savedNames), [](const Mod& mod) { return mod.name; });
GetConfigFile().SetArrayProperty("Mods", "Names", savedNames);
std::vector<bool> savedEnabled;
savedEnabled.reserve(m_mods.size());
std::transform(m_mods.begin(), m_mods.end(), std::back_inserter(savedEnabled), [](const Mod& mod) { return mod.enabled; });
GetConfigFile().SetArrayProperty("Mods", "Enabled", savedEnabled);
GetConfigFile().Save();
m_userChanges = false;
}
size_t CModManager::CountMods() const
{
return m_mods.size();
}
const Mod& CModManager::GetMod(size_t i) const
{
return m_mods[i];
}
const std::vector<Mod>& CModManager::GetMods() const
{
return m_mods;
}
void CModManager::LoadModData(Mod& mod)
{
auto& data = mod.data;
data.displayName = mod.name;
try
{
CLevelParser levelParser("temp/mod/manifest.txt");
if (levelParser.Exists())
{
levelParser.Load();
CLevelParserLine* line = nullptr;
// DisplayName
line = levelParser.GetIfDefined("DisplayName");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.displayName = line->GetParam("text")->AsString();
}
// Author
line = levelParser.GetIfDefined("Author");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.author = line->GetParam("text")->AsString();
}
// Version
line = levelParser.GetIfDefined("Version");
if (line != nullptr)
{
if (line->GetParam("text")->IsDefined())
{
data.version = line->GetParam("text")->AsString();
}
else if (line->GetParam("major")->IsDefined() && line->GetParam("minor")->IsDefined() && line->GetParam("patch")->IsDefined())
{
auto major = boost::lexical_cast<std::string>(line->GetParam("major")->AsInt());
auto minor = boost::lexical_cast<std::string>(line->GetParam("minor")->AsInt());
auto patch = boost::lexical_cast<std::string>(line->GetParam("patch")->AsInt());
data.version = boost::algorithm::join(std::vector<std::string>{ major, minor, patch }, ".");
}
}
// Website
line = levelParser.GetIfDefined("Website");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.website = line->GetParam("text")->AsString();
}
// Summary
line = levelParser.GetIfDefined("Summary");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.summary = line->GetParam("text")->AsString();
}
}
else
{
GetLogger()->Warn("No manifest file for mod %s\n", mod.name.c_str());
}
}
catch (CLevelParserException& e)
{
GetLogger()->Warn("Failed parsing manifest for mod %s: %s\n", mod.name.c_str(), e.what());
}
// Changes
data.changes = CResourceManager::ListDirectories("temp/mod");
auto levelsIt = std::find(data.changes.begin(), data.changes.end(), "levels");
if (levelsIt != data.changes.end())
{
auto levelsDirs = CResourceManager::ListDirectories("temp/mod/levels");
if (!levelsDirs.empty())
{
std::transform(levelsDirs.begin(), levelsDirs.end(), levelsDirs.begin(), [](const std::string& dir) { return "levels/" + dir; });
levelsIt = data.changes.erase(levelsIt);
data.changes.insert(levelsIt, levelsDirs.begin(), levelsDirs.end());
}
}
}
void CModManager::MountMod(const Mod& mod, const std::string& mountPoint)
{
MountMod(mod.path, mountPoint);
}
void CModManager::MountMod(const std::string& path, const std::string& mountPoint)
{
GetLogger()->Debug("Mounting mod: '%s' at path %s\n", path.c_str(), mountPoint.c_str());
CResourceManager::AddLocation(path, true, mountPoint);
}
void CModManager::UnmountMod(const Mod& mod)
{
UnmountMod(mod.path);
}
void CModManager::UnmountMod(const std::string& path)
{
if (CResourceManager::LocationExists(path))
{
GetLogger()->Debug("Unmounting mod: '%s'\n", path.c_str());
CResourceManager::RemoveLocation(path);
}
}
void CModManager::UnmountAllMountedMods()
{
for (const auto& path : m_mountedModPaths)
{
UnmountMod(path);
}
m_mountedModPaths.clear();
}

124
src/app/modman.h Normal file
View File

@ -0,0 +1,124 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
class CApplication;
class CPathManager;
struct ModData
{
std::string displayName{};
std::string author{};
std::string version{};
std::string website{};
std::string summary{};
std::vector<std::string> changes{};
};
struct Mod
{
std::string name{};
std::string path{};
bool enabled = false;
ModData data{};
};
/**
* \class CModManager
* \brief This class handles the list of mods.
*
* The order matters since the order in which files are loaded matters,
* because some files can be overwritten.
*
* The changes in the list do not immediately apply.
*/
class CModManager
{
public:
CModManager(CApplication* app, CPathManager* pathManager);
//! Finds all the mods along with their metadata
void FindMods();
//! Applies the current configuration and reloads the application
void ReloadMods();
//! Removes a mod from the list of loaded mods
void EnableMod(size_t i);
//! Adds a mod to the list of loaded mods
void DisableMod(size_t i);
//! Moves the selected mod up in the list so that it's loaded sooner than others, returns the new index
size_t MoveUp(size_t i);
//! Moves the selected mod down in the list so that it's loaded later than others, returns the new index
size_t MoveDown(size_t i);
//! Checks if the list of currently used mods differs from the current configuration or there were changes made by the user
bool Changes();
//! Saves the current configuration of mods to the config file
void SaveMods();
//! Number of mods loaded
size_t CountMods() const;
//! Returns the reference to the mod in given position
const Mod& GetMod(size_t i) const;
//! Returns the list of mods
const std::vector<Mod>& GetMods() const;
private:
// Allow access to MountAllMods() as CApplication doesn't want to reload itself during initialization
friend CApplication;
//! Reloads application resources so the enabled mods are applied
void ReloadResources();
//! Load mod data into mod
void LoadModData(Mod& mod);
//! Updates the paths in Path Manager according to the current mod configuration
void MountAllMods();
void MountMod(const Mod& mod, const std::string& mountPoint = "");
void MountMod(const std::string& path, const std::string& mountPoint = "");
void UnmountMod(const Mod& mod);
void UnmountMod(const std::string& path);
void UnmountAllMountedMods();
private:
CApplication* m_app;
CPathManager* m_pathManager;
//! Paths to mods already in the virtual filesystem
std::vector<std::string> m_mountedModPaths;
//! List of mods
std::vector<Mod> m_mods;
bool m_userChanges = false;
};

View File

@ -41,8 +41,7 @@ CPathManager::CPathManager(CSystemUtils* systemUtils)
: m_dataPath(systemUtils->GetDataPath()) : m_dataPath(systemUtils->GetDataPath())
, m_langPath(systemUtils->GetLangPath()) , m_langPath(systemUtils->GetLangPath())
, m_savePath(systemUtils->GetSaveDir()) , m_savePath(systemUtils->GetSaveDir())
, m_modAutoloadDir{} , m_modSearchDirs{}
, m_mods{}
{ {
} }
@ -65,16 +64,6 @@ void CPathManager::SetSavePath(const std::string &savePath)
m_savePath = savePath; m_savePath = savePath;
} }
void CPathManager::AddModAutoloadDir(const std::string &modAutoloadDirPath)
{
m_modAutoloadDir.push_back(modAutoloadDirPath);
}
void CPathManager::AddMod(const std::string &modPath)
{
m_mods.push_back(modPath);
}
const std::string& CPathManager::GetDataPath() const std::string& CPathManager::GetDataPath()
{ {
return m_dataPath; return m_dataPath;
@ -131,40 +120,18 @@ void CPathManager::InitPaths()
GetLogger()->Info("Data path: %s\n", m_dataPath.c_str()); GetLogger()->Info("Data path: %s\n", m_dataPath.c_str());
GetLogger()->Info("Save path: %s\n", m_savePath.c_str()); GetLogger()->Info("Save path: %s\n", m_savePath.c_str());
m_modAutoloadDir.push_back(m_dataPath + "/mods"); m_modSearchDirs.push_back(m_dataPath + "/mods");
m_modAutoloadDir.push_back(m_savePath + "/mods"); m_modSearchDirs.push_back(m_savePath + "/mods");
if (!m_modAutoloadDir.empty()) if (!m_modSearchDirs.empty())
{ {
GetLogger()->Info("Mod autoload dirs:\n"); GetLogger()->Info("Mod search dirs:\n");
for(const std::string& modAutoloadDir : m_modAutoloadDir) for(const std::string& modSearchDir : m_modSearchDirs)
GetLogger()->Info(" * %s\n", modAutoloadDir.c_str()); GetLogger()->Info(" * %s\n", modSearchDir.c_str());
}
if (!m_mods.empty())
{
GetLogger()->Info("Mods:\n");
for(const std::string& modPath : m_mods)
GetLogger()->Info(" * %s\n", modPath.c_str());
} }
CResourceManager::AddLocation(m_dataPath); CResourceManager::AddLocation(m_dataPath);
for (const std::string& modAutoloadDir : m_modAutoloadDir)
{
GetLogger()->Trace("Searching for mods in '%s'...\n", modAutoloadDir.c_str());
for (const std::string& modPath : FindModsInDir(modAutoloadDir))
{
GetLogger()->Info("Autoloading mod: '%s'\n", modPath.c_str());
CResourceManager::AddLocation(modPath);
}
}
for (const std::string& modPath : m_mods)
{
GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str());
CResourceManager::AddLocation(modPath);
}
CResourceManager::SetSaveLocation(m_savePath); CResourceManager::SetSaveLocation(m_savePath);
CResourceManager::AddLocation(m_savePath); CResourceManager::AddLocation(m_savePath);
@ -174,7 +141,45 @@ void CPathManager::InitPaths()
GetLogger()->Debug(" * %s\n", path.c_str()); GetLogger()->Debug(" * %s\n", path.c_str());
} }
std::vector<std::string> CPathManager::FindModsInDir(const std::string &dir) void CPathManager::AddMod(const std::string &path)
{
m_mods.push_back(path);
}
std::vector<std::string> CPathManager::FindMods() const
{
std::vector<std::string> mods;
GetLogger()->Info("Found mods:\n");
for (const auto &searchPath : m_modSearchDirs)
{
for (const auto &modPath : FindModsInDir(searchPath))
{
GetLogger()->Info(" * %s\n", modPath.c_str());
mods.push_back(modPath);
}
}
GetLogger()->Info("Additional mod paths:\n");
for (const auto& modPath : m_mods)
{
if (boost::filesystem::exists(modPath))
{
GetLogger()->Info(" * %s\n", modPath.c_str());
mods.push_back(modPath);
}
else
{
GetLogger()->Warn("Mod does not exist: %s\n", modPath.c_str());
}
}
return mods;
}
void CPathManager::AddModSearchDir(const std::string &modSearchDirPath)
{
m_modSearchDirs.push_back(modSearchDirPath);
}
std::vector<std::string> CPathManager::FindModsInDir(const std::string &dir) const
{ {
std::vector<std::string> ret; std::vector<std::string> ret;
try try

View File

@ -37,8 +37,6 @@ public:
void SetDataPath(const std::string &dataPath); void SetDataPath(const std::string &dataPath);
void SetLangPath(const std::string &langPath); void SetLangPath(const std::string &langPath);
void SetSavePath(const std::string &savePath); void SetSavePath(const std::string &savePath);
void AddModAutoloadDir(const std::string &modAutoloadDirPath);
void AddMod(const std::string &modPath);
const std::string& GetDataPath(); const std::string& GetDataPath();
const std::string& GetLangPath(); const std::string& GetLangPath();
@ -49,9 +47,15 @@ public:
//! Loads configured paths //! Loads configured paths
void InitPaths(); void InitPaths();
//! Adds a path to a mod
void AddMod(const std::string& path);
//! Find paths to mods in mod search directories
std::vector<std::string> FindMods() const;
//! Adds a mod search directory
void AddModSearchDir(const std::string &modSearchDirPath);
private: private:
//! Loads all mods from given directory std::vector<std::string> FindModsInDir(const std::string &dir) const;
std::vector<std::string> FindModsInDir(const std::string &dir);
private: private:
//! Data path //! Data path
@ -60,8 +64,8 @@ private:
std::string m_langPath; std::string m_langPath;
//! Save path //! Save path
std::string m_savePath; std::string m_savePath;
//! Mod autoload paths //! Mod search paths
std::vector<std::string> m_modAutoloadDir; std::vector<std::string> m_modSearchDirs;
//! Mod paths //! Additional mod paths
std::vector<std::string> m_mods; std::vector<std::string> m_mods;
}; };

View File

@ -26,9 +26,15 @@
#include "common/singleton.h" #include "common/singleton.h"
#include "common/logger.h"
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/lexical_cast.hpp>
#include <string> #include <string>
#include <sstream>
#include <vector>
#include <stdexcept>
/** /**
@ -100,6 +106,76 @@ public:
*/ */
bool GetBoolProperty(std::string section, std::string key, bool &value); bool GetBoolProperty(std::string section, std::string key, bool &value);
/** Gets an array of values of type T in section under specified key
* The value separator is ','.
* \a array will only be changed if key exists
* \return return true on success
*/
template<typename T>
bool SetArrayProperty(std::string section, std::string key, const std::vector<T>& array)
{
try
{
std::string convertedValue = ArrayToString(array);
m_propertyTree.put(section + "." + key, convertedValue);
m_needsSave = true;
}
catch (std::exception & e)
{
GetLogger()->Error("Error on editing config file: %s\n", e.what());
return false;
}
return true;
}
/** Sets an array of values of type T in section under specified key.
* The value separator is ','.
* \a array will only be changed if key exists
* \return return true on success
*/
template<typename T>
bool GetArrayProperty(std::string section, std::string key, std::vector<T>& array)
{
try
{
std::string readValue = m_propertyTree.get<std::string>(section + "." + key);
std::vector<T> convertedValue = StringToArray<T>(readValue);
array = std::move(convertedValue);
}
catch (std::exception & e)
{
GetLogger()->Log(m_loaded ? LOG_INFO : LOG_TRACE, "Error on parsing config file: %s\n", e.what());
return false;
}
return true;
}
private:
template<typename T>
std::vector<T> StringToArray(const std::string& s)
{
std::vector<T> result;
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, ','))
{
result.push_back(boost::lexical_cast<T>(item));
}
return result;
}
template<typename T>
std::string ArrayToString(const std::vector<T> &array)
{
std::ostringstream oss;
if (!array.empty())
{
std::copy(array.begin(), array.end() - 1, std::ostream_iterator<T>(oss, ","));
oss << array.back();
}
return oss.str();
}
private: private:
boost::property_tree::ptree m_propertyTree; boost::property_tree::ptree m_propertyTree;
bool m_needsSave; bool m_needsSave;

View File

@ -190,6 +190,8 @@ void InitializeEventTypeTexts()
EVENT_TYPE_TEXT[EVENT_INTERFACE_ABORT] = "EVENT_INTERFACE_ABORT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_ABORT] = "EVENT_INTERFACE_ABORT";
EVENT_TYPE_TEXT[EVENT_INTERFACE_USER] = "EVENT_INTERFACE_USER"; EVENT_TYPE_TEXT[EVENT_INTERFACE_USER] = "EVENT_INTERFACE_USER";
EVENT_TYPE_TEXT[EVENT_INTERFACE_SATCOM] = "EVENT_INTERFACE_SATCOM"; EVENT_TYPE_TEXT[EVENT_INTERFACE_SATCOM] = "EVENT_INTERFACE_SATCOM";
EVENT_TYPE_TEXT[EVENT_INTERFACE_PLUS] = "EVENT_INTERFACE_PLUS";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS] = "EVENT_INTERFACE_MODS";
EVENT_TYPE_TEXT[EVENT_INTERFACE_CHAP] = "EVENT_INTERFACE_CHAP"; EVENT_TYPE_TEXT[EVENT_INTERFACE_CHAP] = "EVENT_INTERFACE_CHAP";
EVENT_TYPE_TEXT[EVENT_INTERFACE_LIST] = "EVENT_INTERFACE_LIST"; EVENT_TYPE_TEXT[EVENT_INTERFACE_LIST] = "EVENT_INTERFACE_LIST";
@ -272,6 +274,20 @@ void InitializeEventTypeTexts()
EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT";
EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT";
EVENT_TYPE_TEXT[EVENT_INTERFACE_PLUS_TRAINER] = "EVENT_INTERFACE_PLUS_TRAINER";
EVENT_TYPE_TEXT[EVENT_INTERFACE_PLUS_RESEARCH] = "EVENT_INTERFACE_PLUS_RESEARCH";
EVENT_TYPE_TEXT[EVENT_INTERFACE_PLUS_EXPLORER] = "EVENT_INTERFACE_PLUS_EXPLORER";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_LIST] = "EVENT_INTERFACE_MOD_LIST";
EVENT_TYPE_TEXT[EVENT_INTERFACE_WORKSHOP] = "EVENT_INTERFACE_WORKSHOP";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_DIR] = "EVENT_INTERFACE_MODS_DIR";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE] = "EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_APPLY] = "EVENT_INTERFACE_MODS_APPLY";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_DETAILS] = "EVENT_INTERFACE_MOD_DETAILS";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_MOVE_UP] = "EVENT_INTERFACE_MOD_MOVE_UP";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_MOVE_DOWN] = "EVENT_INTERFACE_MOD_MOVE_DOWN";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_REFRESH] = "EVENT_INTERFACE_MODS_REFRESH";
EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTl] = "EVENT_INTERFACE_GLINTl"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTl] = "EVENT_INTERFACE_GLINTl";
EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTr] = "EVENT_INTERFACE_GLINTr"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTr] = "EVENT_INTERFACE_GLINTr";
EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTu] = "EVENT_INTERFACE_GLINTu"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTu] = "EVENT_INTERFACE_GLINTu";
@ -405,7 +421,7 @@ void InitializeEventTypeTexts()
EVENT_TYPE_TEXT[EVENT_OBJECT_BNUCLEAR] = "EVENT_OBJECT_BNUCLEAR"; EVENT_TYPE_TEXT[EVENT_OBJECT_BNUCLEAR] = "EVENT_OBJECT_BNUCLEAR";
EVENT_TYPE_TEXT[EVENT_OBJECT_BPARA] = "EVENT_OBJECT_BPARA"; EVENT_TYPE_TEXT[EVENT_OBJECT_BPARA] = "EVENT_OBJECT_BPARA";
EVENT_TYPE_TEXT[EVENT_OBJECT_BINFO] = "EVENT_OBJECT_BINFO"; EVENT_TYPE_TEXT[EVENT_OBJECT_BINFO] = "EVENT_OBJECT_BINFO";
EVENT_TYPE_TEXT[EVENT_OBJECT_BDESTROYER] = "EVENT_OBJECT_BDESTROYER"; EVENT_TYPE_TEXT[EVENT_OBJECT_BSAFE] = "EVENT_OBJECT_BSAFE";
EVENT_TYPE_TEXT[EVENT_OBJECT_GFLAT] = "EVENT_OBJECT_GFLAT"; EVENT_TYPE_TEXT[EVENT_OBJECT_GFLAT] = "EVENT_OBJECT_GFLAT";
EVENT_TYPE_TEXT[EVENT_OBJECT_FCREATE] = "EVENT_OBJECT_FCREATE"; EVENT_TYPE_TEXT[EVENT_OBJECT_FCREATE] = "EVENT_OBJECT_FCREATE";
EVENT_TYPE_TEXT[EVENT_OBJECT_FDELETE] = "EVENT_OBJECT_FDELETE"; EVENT_TYPE_TEXT[EVENT_OBJECT_FDELETE] = "EVENT_OBJECT_FDELETE";

View File

@ -225,6 +225,8 @@ enum EventType
EVENT_INTERFACE_ABORT = 412, EVENT_INTERFACE_ABORT = 412,
EVENT_INTERFACE_USER = 413, EVENT_INTERFACE_USER = 413,
EVENT_INTERFACE_SATCOM = 414, EVENT_INTERFACE_SATCOM = 414,
EVENT_INTERFACE_PLUS = 415,
EVENT_INTERFACE_MODS = 416,
EVENT_INTERFACE_CHAP = 420, EVENT_INTERFACE_CHAP = 420,
EVENT_INTERFACE_LIST = 421, EVENT_INTERFACE_LIST = 421,
@ -311,6 +313,21 @@ enum EventType
EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT = 573, EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT = 573,
EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT = 574, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT = 574,
EVENT_INTERFACE_PLUS_TRAINER = 575,
EVENT_INTERFACE_PLUS_RESEARCH = 576,
EVENT_INTERFACE_PLUS_EXPLORER = 577,
EVENT_INTERFACE_MOD_LIST = 580,
EVENT_INTERFACE_WORKSHOP = 581,
EVENT_INTERFACE_MODS_DIR = 582,
EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE = 583,
EVENT_INTERFACE_MODS_APPLY = 584,
EVENT_INTERFACE_MOD_SUMMARY = 585,
EVENT_INTERFACE_MOD_DETAILS = 586,
EVENT_INTERFACE_MOD_MOVE_UP = 587,
EVENT_INTERFACE_MOD_MOVE_DOWN = 888,
EVENT_INTERFACE_MODS_REFRESH = 589,
EVENT_INTERFACE_GLINTl = 590, EVENT_INTERFACE_GLINTl = 590,
EVENT_INTERFACE_GLINTr = 591, EVENT_INTERFACE_GLINTr = 591,
EVENT_INTERFACE_GLINTu = 592, EVENT_INTERFACE_GLINTu = 592,
@ -469,7 +486,7 @@ enum EventType
EVENT_OBJECT_BNUCLEAR = 1060, EVENT_OBJECT_BNUCLEAR = 1060,
EVENT_OBJECT_BPARA = 1061, EVENT_OBJECT_BPARA = 1061,
EVENT_OBJECT_BINFO = 1062, EVENT_OBJECT_BINFO = 1062,
EVENT_OBJECT_BDESTROYER = 1063, EVENT_OBJECT_BSAFE = 1063,
EVENT_OBJECT_GFLAT = 1070, EVENT_OBJECT_GFLAT = 1070,
EVENT_OBJECT_FCREATE = 1071, EVENT_OBJECT_FCREATE = 1071,
EVENT_OBJECT_FDELETE = 1072, EVENT_OBJECT_FDELETE = 1072,

View File

@ -62,9 +62,9 @@ std::string CResourceManager::CleanPath(const std::string& path)
} }
bool CResourceManager::AddLocation(const std::string &location, bool prepend) bool CResourceManager::AddLocation(const std::string &location, bool prepend, const std::string &mountPoint)
{ {
if (!PHYSFS_mount(location.c_str(), nullptr, prepend ? 0 : 1)) if (!PHYSFS_mount(location.c_str(), mountPoint.c_str(), prepend ? 0 : 1))
{ {
GetLogger()->Error("Error while mounting \"%s\": %s\n", location.c_str(), PHYSFS_getLastError()); GetLogger()->Error("Error while mounting \"%s\": %s\n", location.c_str(), PHYSFS_getLastError());
return false; return false;
@ -95,6 +95,12 @@ std::vector<std::string> CResourceManager::GetLocations()
return ret; return ret;
} }
bool CResourceManager::LocationExists(const std::string& location)
{
auto locations = GetLocations();
auto it = std::find(locations.cbegin(), locations.cend(), location);
return it != locations.cend();
}
bool CResourceManager::SetSaveLocation(const std::string &location) bool CResourceManager::SetSaveLocation(const std::string &location)
{ {

View File

@ -36,11 +36,13 @@ public:
static std::string CleanPath(const std::string &path); static std::string CleanPath(const std::string &path);
//! Add a location to the search path //! Add a location to the search path
static bool AddLocation(const std::string &location, bool prepend = true); static bool AddLocation(const std::string &location, bool prepend = true, const std::string &mountPoint = "");
//! Remove a location from the search path //! Remove a location from the search path
static bool RemoveLocation(const std::string &location); static bool RemoveLocation(const std::string &location);
//! List all locations in the search path //! List all locations in the search path
static std::vector<std::string> GetLocations(); static std::vector<std::string> GetLocations();
//! Check if given location is in the search path
static bool LocationExists(const std::string &location);
static bool SetSaveLocation(const std::string &location); static bool SetSaveLocation(const std::string &location);
static std::string GetSaveLocation(); static std::string GetSaveLocation();

View File

@ -48,8 +48,8 @@ const char* stringsCbot[CBot::CBotErrMAX] = { nullptr };
*/ */
#define TR(x) x #define TR(x) x
/* Please run `make update-pot` after changing this file /* Please run `cmake --build <path_to_build_folder> --target update-pot`
* in order to update translation files. Thank you. * after changing this file in order to update translation files. Thank you.
*/ */
void InitializeRestext() void InitializeRestext()
@ -71,12 +71,14 @@ void InitializeRestext()
stringsText[RT_TITLE_MISSION] = TR("Missions"); stringsText[RT_TITLE_MISSION] = TR("Missions");
stringsText[RT_TITLE_FREE] = TR("Free game"); stringsText[RT_TITLE_FREE] = TR("Free game");
stringsText[RT_TITLE_USER] = TR("User levels"); stringsText[RT_TITLE_USER] = TR("User levels");
stringsText[RT_TITLE_CODE_BATTLES]=TR("Code battles"); stringsText[RT_TITLE_CODE_BATTLES] = TR("Code battles");
stringsText[RT_TITLE_SETUP] = TR("Options"); stringsText[RT_TITLE_SETUP] = TR("Options");
stringsText[RT_TITLE_NAME] = TR("Player's name"); stringsText[RT_TITLE_NAME] = TR("Player's name");
stringsText[RT_TITLE_PERSO] = TR("Customize your appearance"); stringsText[RT_TITLE_PERSO] = TR("Customize your appearance");
stringsText[RT_TITLE_WRITE] = TR("Save the current mission"); stringsText[RT_TITLE_WRITE] = TR("Save the current mission");
stringsText[RT_TITLE_READ] = TR("Load a saved mission"); stringsText[RT_TITLE_READ] = TR("Load a saved mission");
stringsText[RT_TITLE_PLUS] = TR("Missions+");
stringsText[RT_TITLE_MODS] = TR("Mods");
stringsText[RT_PLAY_CHAP_CHAPTERS] = TR("Chapters:"); stringsText[RT_PLAY_CHAP_CHAPTERS] = TR("Chapters:");
stringsText[RT_PLAY_CHAP_PLANETS] = TR("Planets:"); stringsText[RT_PLAY_CHAP_PLANETS] = TR("Planets:");
@ -108,6 +110,11 @@ void InitializeRestext()
stringsText[RT_DIALOG_OK] = TR("OK"); stringsText[RT_DIALOG_OK] = TR("OK");
stringsText[RT_DIALOG_NOUSRLVL_TITLE] = TR("No userlevels installed!"); stringsText[RT_DIALOG_NOUSRLVL_TITLE] = TR("No userlevels installed!");
stringsText[RT_DIALOG_NOUSRLVL_TEXT] = TR("This menu is for userlevels from mods, but you didn't install any"); stringsText[RT_DIALOG_NOUSRLVL_TEXT] = TR("This menu is for userlevels from mods, but you didn't install any");
stringsText[RT_DIALOG_OPEN_PATH_FAILED_TITLE] = TR("Could not open the file explorer!");
stringsText[RT_DIALOG_OPEN_PATH_FAILED_TEXT] = TR("The path %s could not be opened in a file explorer.");
stringsText[RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE] = TR("Could not open the web browser!");
stringsText[RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT] = TR("The address %s could not be opened in a web browser.");
stringsText[RT_DIALOG_CHANGES_QUESTION] = TR("There are unsaved changes. Do you want to save them before leaving?");
stringsText[RT_STUDIO_LISTTT] = TR("Keyword help(\\key cbot;)"); stringsText[RT_STUDIO_LISTTT] = TR("Keyword help(\\key cbot;)");
stringsText[RT_STUDIO_COMPOK] = TR("Compilation ok (0 errors)"); stringsText[RT_STUDIO_COMPOK] = TR("Compilation ok (0 errors)");
@ -153,7 +160,18 @@ void InitializeRestext()
stringsText[RT_SCOREBOARD_RESULTS_TIME]= TR("Time: %s"); stringsText[RT_SCOREBOARD_RESULTS_TIME]= TR("Time: %s");
stringsText[RT_SCOREBOARD_RESULTS_LINE]= TR("%s: %d pts"); stringsText[RT_SCOREBOARD_RESULTS_LINE]= TR("%s: %d pts");
stringsText[RT_MOD_LIST] = TR("Mods:");
stringsText[RT_MOD_DETAILS] = TR("Information:");
stringsText[RT_MOD_SUMMARY] = TR("Description:");
stringsText[RT_MOD_ENABLE] = TR("Enable\\Enable the selected mod");
stringsText[RT_MOD_DISABLE] = TR("Disable\\Disable the selected mod");
stringsText[RT_MOD_UNKNOWN_AUTHOR] = TR("Unknown author");
stringsText[RT_MOD_AUTHOR_FIELD_NAME] = TR("by");
stringsText[RT_MOD_VERSION_FIELD_NAME] = TR("Version");
stringsText[RT_MOD_WEBSITE_FIELD_NAME] = TR("Website");
stringsText[RT_MOD_CHANGES_FIELD_NAME] = TR("Changes");
stringsText[RT_MOD_NO_SUMMARY] = TR("No description.");
stringsText[RT_MOD_NO_CHANGES] = TR("No changes.");
stringsEvent[EVENT_LABEL_CODE_BATTLE] = TR("Code battle"); stringsEvent[EVENT_LABEL_CODE_BATTLE] = TR("Code battle");
@ -173,6 +191,7 @@ void InitializeRestext()
stringsEvent[EVENT_INTERFACE_CODE_BATTLES] = TR("Code battles\\Program your robot to be the best of them all!"); stringsEvent[EVENT_INTERFACE_CODE_BATTLES] = TR("Code battles\\Program your robot to be the best of them all!");
stringsEvent[EVENT_INTERFACE_USER] = TR("Custom levels\\Levels from mods created by the users"); stringsEvent[EVENT_INTERFACE_USER] = TR("Custom levels\\Levels from mods created by the users");
stringsEvent[EVENT_INTERFACE_SATCOM] = TR("SatCom"); stringsEvent[EVENT_INTERFACE_SATCOM] = TR("SatCom");
stringsEvent[EVENT_INTERFACE_MODS] = TR("Mods\\Mod manager");
stringsEvent[EVENT_INTERFACE_NAME] = TR("Change player\\Change player"); stringsEvent[EVENT_INTERFACE_NAME] = TR("Change player\\Change player");
stringsEvent[EVENT_INTERFACE_SETUP] = TR("Options\\Preferences"); stringsEvent[EVENT_INTERFACE_SETUP] = TR("Options\\Preferences");
stringsEvent[EVENT_INTERFACE_AGAIN] = TR("Restart\\Restart the mission from the beginning"); stringsEvent[EVENT_INTERFACE_AGAIN] = TR("Restart\\Restart the mission from the beginning");
@ -181,7 +200,14 @@ void InitializeRestext()
stringsEvent[EVENT_INTERFACE_ABORT] = TR("\\Return to Colobot: Gold Edition"); stringsEvent[EVENT_INTERFACE_ABORT] = TR("\\Return to Colobot: Gold Edition");
stringsEvent[EVENT_INTERFACE_QUIT] = TR("Quit\\Quit Colobot: Gold Edition"); stringsEvent[EVENT_INTERFACE_QUIT] = TR("Quit\\Quit Colobot: Gold Edition");
stringsEvent[EVENT_INTERFACE_BACK] = TR("<< Back \\Back to the previous screen"); stringsEvent[EVENT_INTERFACE_BACK] = TR("<< Back \\Back to the previous screen");
stringsEvent[EVENT_INTERFACE_PLUS] = TR("+\\Missions with bonus content and optional challenges");
stringsEvent[EVENT_INTERFACE_PLAY] = TR("Play\\Start mission!"); stringsEvent[EVENT_INTERFACE_PLAY] = TR("Play\\Start mission!");
stringsEvent[EVENT_INTERFACE_WORKSHOP] = TR("Workshop\\Open the workshop to search for mods");
stringsEvent[EVENT_INTERFACE_MODS_DIR] = TR("Open Directory\\Open the mods directory");
stringsEvent[EVENT_INTERFACE_MODS_APPLY] = TR("Apply\\Apply the current mod configuration");
stringsEvent[EVENT_INTERFACE_MOD_MOVE_UP] = TR("Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)");
stringsEvent[EVENT_INTERFACE_MOD_MOVE_DOWN] = TR("Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)");
stringsEvent[EVENT_INTERFACE_MODS_REFRESH] = TR("Refresh\\Refresh the list of currently installed mods");
stringsEvent[EVENT_INTERFACE_SETUPd] = TR("Device\\Driver and resolution settings"); stringsEvent[EVENT_INTERFACE_SETUPd] = TR("Device\\Driver and resolution settings");
stringsEvent[EVENT_INTERFACE_SETUPg] = TR("Graphics\\Graphics settings"); stringsEvent[EVENT_INTERFACE_SETUPg] = TR("Graphics\\Graphics settings");
stringsEvent[EVENT_INTERFACE_SETUPp] = TR("Game\\Game settings"); stringsEvent[EVENT_INTERFACE_SETUPp] = TR("Game\\Game settings");
@ -275,6 +301,10 @@ void InitializeRestext()
stringsEvent[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT] = TR("Invert\\Invert values on this axis"); stringsEvent[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT] = TR("Invert\\Invert values on this axis");
stringsEvent[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT] = TR("Invert\\Invert values on this axis"); stringsEvent[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT] = TR("Invert\\Invert values on this axis");
stringsEvent[EVENT_INTERFACE_PLUS_TRAINER] = TR("Space Programmer\\Disables radio-control");
stringsEvent[EVENT_INTERFACE_PLUS_RESEARCH] = TR("Space Researcher\\Disables using all previously researched technologies");
stringsEvent[EVENT_INTERFACE_PLUS_EXPLORER] = TR("Space Explorer\\Disables astronaut abilities");
stringsEvent[EVENT_INTERFACE_NEDIT] = TR("\\New player name"); stringsEvent[EVENT_INTERFACE_NEDIT] = TR("\\New player name");
stringsEvent[EVENT_INTERFACE_NOK] = TR("OK\\Choose the selected player"); stringsEvent[EVENT_INTERFACE_NOK] = TR("OK\\Choose the selected player");
stringsEvent[EVENT_INTERFACE_NDELETE] = TR("Delete player\\Deletes the player from the list"); stringsEvent[EVENT_INTERFACE_NDELETE] = TR("Delete player\\Deletes the player from the list");
@ -341,7 +371,7 @@ void InitializeRestext()
stringsEvent[EVENT_OBJECT_BNUCLEAR] = TR("Build a nuclear power plant"); stringsEvent[EVENT_OBJECT_BNUCLEAR] = TR("Build a nuclear power plant");
stringsEvent[EVENT_OBJECT_BPARA] = TR("Build a lightning conductor"); stringsEvent[EVENT_OBJECT_BPARA] = TR("Build a lightning conductor");
stringsEvent[EVENT_OBJECT_BINFO] = TR("Build a exchange post"); stringsEvent[EVENT_OBJECT_BINFO] = TR("Build a exchange post");
stringsEvent[EVENT_OBJECT_BDESTROYER] = TR("Build a destroyer"); stringsEvent[EVENT_OBJECT_BSAFE] = TR("Build a vault");
stringsEvent[EVENT_OBJECT_GFLAT] = TR("Show if the ground is flat"); stringsEvent[EVENT_OBJECT_GFLAT] = TR("Show if the ground is flat");
stringsEvent[EVENT_OBJECT_FCREATE] = TR("Plant a flag"); stringsEvent[EVENT_OBJECT_FCREATE] = TR("Plant a flag");
stringsEvent[EVENT_OBJECT_FDELETE] = TR("Remove a flag"); stringsEvent[EVENT_OBJECT_FDELETE] = TR("Remove a flag");

View File

@ -71,6 +71,8 @@ enum ResTextType
RT_TITLE_WRITE = 50, RT_TITLE_WRITE = 50,
RT_TITLE_READ = 51, RT_TITLE_READ = 51,
RT_TITLE_USER = 52, RT_TITLE_USER = 52,
RT_TITLE_PLUS = 53,
RT_TITLE_MODS = 54,
RT_PLAY_CHAP_CHAPTERS = 60, RT_PLAY_CHAP_CHAPTERS = 60,
RT_PLAY_CHAP_PLANETS = 61, RT_PLAY_CHAP_PLANETS = 61,
@ -102,6 +104,11 @@ enum ResTextType
RT_DIALOG_OK = 110, RT_DIALOG_OK = 110,
RT_DIALOG_NOUSRLVL_TITLE = 111, RT_DIALOG_NOUSRLVL_TITLE = 111,
RT_DIALOG_NOUSRLVL_TEXT = 112, RT_DIALOG_NOUSRLVL_TEXT = 112,
RT_DIALOG_OPEN_PATH_FAILED_TITLE = 113,
RT_DIALOG_OPEN_PATH_FAILED_TEXT = 114,
RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE = 115,
RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT = 116,
RT_DIALOG_CHANGES_QUESTION = 117,
RT_STUDIO_LISTTT = 120, RT_STUDIO_LISTTT = 120,
RT_STUDIO_COMPOK = 121, RT_STUDIO_COMPOK = 121,
@ -147,6 +154,18 @@ enum ResTextType
RT_SCOREBOARD_RESULTS_TIME= 232, RT_SCOREBOARD_RESULTS_TIME= 232,
RT_SCOREBOARD_RESULTS_LINE= 233, RT_SCOREBOARD_RESULTS_LINE= 233,
RT_MOD_LIST = 234,
RT_MOD_DETAILS = 235,
RT_MOD_SUMMARY = 236,
RT_MOD_ENABLE = 237,
RT_MOD_DISABLE = 238,
RT_MOD_UNKNOWN_AUTHOR = 239,
RT_MOD_AUTHOR_FIELD_NAME = 240,
RT_MOD_VERSION_FIELD_NAME = 241,
RT_MOD_WEBSITE_FIELD_NAME = 242,
RT_MOD_CHANGES_FIELD_NAME = 243,
RT_MOD_NO_SUMMARY = 244,
RT_MOD_NO_CHANGES = 245,
RT_MAX //! < number of values RT_MAX //! < number of values
}; };

View File

@ -72,7 +72,6 @@ void CSettings::SaveSettings()
CRobotMain* main = CRobotMain::GetInstancePointer(); CRobotMain* main = CRobotMain::GetInstancePointer();
Gfx::CEngine* engine = Gfx::CEngine::GetInstancePointer(); Gfx::CEngine* engine = Gfx::CEngine::GetInstancePointer();
Gfx::CCamera* camera = main->GetCamera(); Gfx::CCamera* camera = main->GetCamera();
CSoundInterface* sound = app->GetSound();
GetConfigFile().SetBoolProperty("Setup", "Tooltips", m_tooltips); GetConfigFile().SetBoolProperty("Setup", "Tooltips", m_tooltips);
GetConfigFile().SetBoolProperty("Setup", "InterfaceGlint", m_interfaceGlint); GetConfigFile().SetBoolProperty("Setup", "InterfaceGlint", m_interfaceGlint);
@ -80,7 +79,6 @@ void CSettings::SaveSettings()
GetConfigFile().SetBoolProperty("Setup", "Soluce4", m_soluce4); GetConfigFile().SetBoolProperty("Setup", "Soluce4", m_soluce4);
GetConfigFile().SetBoolProperty("Setup", "Movies", m_movies); GetConfigFile().SetBoolProperty("Setup", "Movies", m_movies);
GetConfigFile().SetBoolProperty("Setup", "FocusLostPause", m_focusLostPause); GetConfigFile().SetBoolProperty("Setup", "FocusLostPause", m_focusLostPause);
GetConfigFile().SetBoolProperty("Setup", "FocusLostMute", m_focusLostMute);
GetConfigFile().SetBoolProperty("Setup", "OldCameraScroll", camera->GetOldCameraScroll()); GetConfigFile().SetBoolProperty("Setup", "OldCameraScroll", camera->GetOldCameraScroll());
GetConfigFile().SetBoolProperty("Setup", "CameraInvertX", camera->GetCameraInvertX()); GetConfigFile().SetBoolProperty("Setup", "CameraInvertX", camera->GetCameraInvertX());
GetConfigFile().SetBoolProperty("Setup", "CameraInvertY", camera->GetCameraInvertY()); GetConfigFile().SetBoolProperty("Setup", "CameraInvertY", camera->GetCameraInvertY());
@ -95,8 +93,6 @@ void CSettings::SaveSettings()
GetConfigFile().SetIntProperty("Setup", "JoystickIndex", app->GetJoystickEnabled() ? app->GetJoystick().index : -1); GetConfigFile().SetIntProperty("Setup", "JoystickIndex", app->GetJoystickEnabled() ? app->GetJoystick().index : -1);
GetConfigFile().SetFloatProperty("Setup", "ParticleDensity", engine->GetParticleDensity()); GetConfigFile().SetFloatProperty("Setup", "ParticleDensity", engine->GetParticleDensity());
GetConfigFile().SetFloatProperty("Setup", "ClippingDistance", engine->GetClippingDistance()); GetConfigFile().SetFloatProperty("Setup", "ClippingDistance", engine->GetClippingDistance());
GetConfigFile().SetIntProperty("Setup", "AudioVolume", sound->GetAudioVolume());
GetConfigFile().SetIntProperty("Setup", "MusicVolume", sound->GetMusicVolume());
GetConfigFile().SetBoolProperty("Setup", "EditIndentMode", engine->GetEditIndentMode()); GetConfigFile().SetBoolProperty("Setup", "EditIndentMode", engine->GetEditIndentMode());
GetConfigFile().SetIntProperty("Setup", "EditIndentValue", engine->GetEditIndentValue()); GetConfigFile().SetIntProperty("Setup", "EditIndentValue", engine->GetEditIndentValue());
GetConfigFile().SetBoolProperty("Setup", "PauseBlur", engine->GetPauseBlurEnabled()); GetConfigFile().SetBoolProperty("Setup", "PauseBlur", engine->GetPauseBlurEnabled());
@ -112,6 +108,9 @@ void CSettings::SaveSettings()
GetConfigFile().SetIntProperty("Setup", "ShadowMappingResolution", GetConfigFile().SetIntProperty("Setup", "ShadowMappingResolution",
engine->GetShadowMappingOffscreen() ? engine->GetShadowMappingOffscreenResolution() : 0); engine->GetShadowMappingOffscreen() ? engine->GetShadowMappingOffscreenResolution() : 0);
// Save Audio settings
SaveAudioSettings();
// Experimental settings // Experimental settings
GetConfigFile().SetBoolProperty("Experimental", "TerrainShadows", engine->GetTerrainShadows()); GetConfigFile().SetBoolProperty("Experimental", "TerrainShadows", engine->GetTerrainShadows());
GetConfigFile().SetIntProperty("Setup", "VSync", engine->GetVSync()); GetConfigFile().SetIntProperty("Setup", "VSync", engine->GetVSync());
@ -140,6 +139,16 @@ void CSettings::SaveSettings()
GetConfigFile().Save(); GetConfigFile().Save();
} }
void CSettings::SaveAudioSettings()
{
CApplication* app = CApplication::GetInstancePointer();
CSoundInterface* sound = app->GetSound();
GetConfigFile().SetIntProperty("Setup", "AudioVolume", sound->GetAudioVolume());
GetConfigFile().SetIntProperty("Setup", "MusicVolume", sound->GetMusicVolume());
GetConfigFile().SetBoolProperty("Setup", "FocusLostMute", m_focusLostMute);
}
void CSettings::LoadSettings() void CSettings::LoadSettings()
{ {
CApplication* app = CApplication::GetInstancePointer(); CApplication* app = CApplication::GetInstancePointer();

View File

@ -37,6 +37,7 @@ public:
void SaveSettings(); void SaveSettings();
void LoadSettings(); void LoadSettings();
void SaveAudioSettings();
void SetTooltips(bool tooltips); void SetTooltips(bool tooltips);
bool GetTooltips(); bool GetTooltips();

View File

@ -215,3 +215,13 @@ std::string CSystemUtils::GetEnvVar(const std::string& name)
{ {
return ""; return "";
} }
bool CSystemUtils::OpenPath(const std::string& path)
{
return false;
}
bool CSystemUtils::OpenWebsite(const std::string& url)
{
return false;
}

View File

@ -116,6 +116,9 @@ public:
//! Copies the time stamp from \a src to \a dst //! Copies the time stamp from \a src to \a dst
TEST_VIRTUAL void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src); TEST_VIRTUAL void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src);
//! Interpolates between two timestamps. If i=0 then dst=a. If i=1 then dst=b. If i=0.5 then dst is halfway between.
virtual void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) = 0;
//! Returns a time stamp associated with current time //! Returns a time stamp associated with current time
virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) = 0; virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) = 0;
@ -142,6 +145,14 @@ public:
//! Returns the environment variable with the given name or an empty string if it does not exist //! Returns the environment variable with the given name or an empty string if it does not exist
virtual std::string GetEnvVar(const std::string &name); virtual std::string GetEnvVar(const std::string &name);
//! Opens a path with default file browser
/** \returns true if successful */
virtual bool OpenPath(const std::string& path);
//! Opens a website with default web browser
/** \returns true if successful */
virtual bool OpenWebsite(const std::string& url);
//! Sleep for given amount of microseconds //! Sleep for given amount of microseconds
virtual void Usleep(int usecs) = 0; virtual void Usleep(int usecs) = 0;

View File

@ -83,6 +83,19 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const
return result; return result;
} }
void CSystemUtilsLinux::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i)
{
long long delta = TimeStampExactDiff(a, b);
delta *= i; // truncates
dst->clockTime.tv_sec = a->clockTime.tv_sec + delta / 1000000000;
dst->clockTime.tv_nsec = a->clockTime.tv_nsec + delta % 1000000000;
if(dst->clockTime.tv_nsec >= 1000000000)
{
dst->clockTime.tv_nsec -= 1000000000;
dst->clockTime.tv_sec++;
}
}
void CSystemUtilsLinux::GetCurrentTimeStamp(SystemTimeStamp *stamp) void CSystemUtilsLinux::GetCurrentTimeStamp(SystemTimeStamp *stamp)
{ {
clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime); clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime);
@ -137,6 +150,28 @@ std::string CSystemUtilsLinux::GetEnvVar(const std::string& name)
return ""; return "";
} }
bool CSystemUtilsLinux::OpenPath(const std::string& path)
{
int result = system(("xdg-open \"" + path + "\"").c_str());
if (result != 0)
{
GetLogger()->Error("Failed to open path: %s, error code: %i\n", path.c_str(), result);
return false;
}
return true;
}
bool CSystemUtilsLinux::OpenWebsite(const std::string& url)
{
int result = system(("xdg-open \"" + url + "\"").c_str());
if (result != 0)
{
GetLogger()->Error("Failed to open website: %s, error code: %i\n", url.c_str(), result);
return false;
}
return true;
}
void CSystemUtilsLinux::Usleep(int usec) void CSystemUtilsLinux::Usleep(int usec)
{ {
usleep(usec); usleep(usec);

View File

@ -40,6 +40,7 @@ public:
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override;
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
@ -47,6 +48,9 @@ public:
std::string GetEnvVar(const std::string& name) override; std::string GetEnvVar(const std::string& name) override;
bool OpenPath(const std::string& path) override;
bool OpenWebsite(const std::string& url) override;
void Usleep(int usec) override; void Usleep(int usec) override;
private: private:

View File

@ -119,6 +119,28 @@ std::string CSystemUtilsMacOSX::GetEnvVar(const std::string& str)
return std::string(); return std::string();
} }
bool CSystemUtilsMacOSX::OpenPath(const std::string& path)
{
int result = system(("open \"" + path + "\"").c_str()); // TODO: Test on macOS
if (result != 0)
{
GetLogger()->Error("Failed to open path: %s, error code: %i\n", path.c_str(), result);
return false;
}
return true;
}
bool CSystemUtilsMacOSX::OpenWebsite(const std::string& url)
{
int result = system(("open \"" + url + "\"").c_str()); // TODO: Test on macOS
if (result != 0)
{
GetLogger()->Error("Failed to open website: %s, error code: %i\n", website.c_str(), result);
return false;
}
return true;
}
void CSystemUtilsMacOSX::Usleep(int usec) void CSystemUtilsMacOSX::Usleep(int usec)
{ {
usleep(usec); usleep(usec);

View File

@ -38,6 +38,9 @@ public:
std::string GetEnvVar(const std::string& name) override; std::string GetEnvVar(const std::string& name) override;
bool OpenPath(const std::string& path) override;
bool OpenWebsite(const std::string& url) override;
void Usleep(int usec) override; void Usleep(int usec) override;
private: private:

View File

@ -34,6 +34,11 @@ void CSystemUtilsOther::GetCurrentTimeStamp(SystemTimeStamp* stamp)
stamp->sdlTicks = SDL_GetTicks(); stamp->sdlTicks = SDL_GetTicks();
} }
void CSystemUtilsOther::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i)
{
dst->sdlTicks = a->sdlTicks + static_cast<Uint32>((b->sdlTicks - a->sdlTicks) * i);
}
long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after) long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after)
{ {
return (after->sdlTicks - before->sdlTicks) * 1000000ll; return (after->sdlTicks - before->sdlTicks) * 1000000ll;

View File

@ -46,6 +46,7 @@ public:
void Init() override; void Init() override;
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override;
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;

View File

@ -21,6 +21,7 @@
#include "common/logger.h" #include "common/logger.h"
#include <boost/filesystem.hpp>
#include <windows.h> #include <windows.h>
@ -83,6 +84,11 @@ void CSystemUtilsWindows::GetCurrentTimeStamp(SystemTimeStamp* stamp)
stamp->counterValue = value.QuadPart; stamp->counterValue = value.QuadPart;
} }
void CSystemUtilsWindows::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i)
{
dst->counterValue = a->counterValue + static_cast<long long>((b->counterValue - a->counterValue) * static_cast<double>(i));
}
long long int CSystemUtilsWindows::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after) long long int CSystemUtilsWindows::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after)
{ {
float floatValue = static_cast<double>(after->counterValue - before->counterValue) * (1e9 / static_cast<double>(m_counterFrequency)); float floatValue = static_cast<double>(after->counterValue - before->counterValue) * (1e9 / static_cast<double>(m_counterFrequency));
@ -147,6 +153,28 @@ std::string CSystemUtilsWindows::GetEnvVar(const std::string& name)
} }
} }
bool CSystemUtilsWindows::OpenPath(const std::string& path)
{
int result = system(("start explorer \"" + boost::filesystem::path(path).make_preferred().string() + "\"").c_str());
if (result != 0)
{
GetLogger()->Error("Failed to open path: %s, error code: %i\n", path.c_str(), result);
return false;
}
return true;
}
bool CSystemUtilsWindows::OpenWebsite(const std::string& url)
{
int result = system(("rundll32 url.dll,FileProtocolHandler \"" + url + "\"").c_str());
if (result != 0)
{
GetLogger()->Error("Failed to open website: %s, error code: %i\n", url.c_str(), result);
return false;
}
return true;
}
void CSystemUtilsWindows::Usleep(int usec) void CSystemUtilsWindows::Usleep(int usec)
{ {
LARGE_INTEGER ft; LARGE_INTEGER ft;

View File

@ -38,6 +38,7 @@ public:
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override;
void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
@ -45,6 +46,9 @@ public:
std::string GetEnvVar(const std::string& name) override; std::string GetEnvVar(const std::string& name) override;
bool OpenPath(const std::string& path) override;
bool OpenWebsite(const std::string& url) override;
void Usleep(int usec) override; void Usleep(int usec) override;
public: public:

View File

@ -59,14 +59,14 @@ static void SetTransparency(CObject* obj, float value)
if (obj->Implements(ObjectInterfaceType::Carrier)) if (obj->Implements(ObjectInterfaceType::Carrier))
{ {
CObject* cargo = dynamic_cast<CCarrierObject*>(obj)->GetCargo(); CObject* cargo = dynamic_cast<CCarrierObject&>(*obj).GetCargo();
if (cargo != nullptr) if (cargo != nullptr)
cargo->SetTransparency(value); cargo->SetTransparency(value);
} }
if (obj->Implements(ObjectInterfaceType::Powered)) if (obj->Implements(ObjectInterfaceType::Powered))
{ {
CObject* power = dynamic_cast<CPoweredObject*>(obj)->GetPower(); CObject* power = dynamic_cast<CPoweredObject&>(*obj).GetPower();
if (power != nullptr) if (power != nullptr)
power->SetTransparency(value); power->SetTransparency(value);
} }
@ -1233,7 +1233,7 @@ bool CCamera::EventFrameBack(const Event &event)
bool ground = true; bool ground = true;
if (m_cameraObj->Implements(ObjectInterfaceType::Movable)) if (m_cameraObj->Implements(ObjectInterfaceType::Movable))
ground = dynamic_cast<CMovableObject*>(m_cameraObj)->GetPhysics()->GetLand(); ground = dynamic_cast<CMovableObject&>(*m_cameraObj).GetPhysics()->GetLand();
if ( ground ) // ground? if ( ground ) // ground?
{ {
Math::Vector pos = lookatPt + (lookatPt - m_eyePt); Math::Vector pos = lookatPt + (lookatPt - m_eyePt);
@ -1326,7 +1326,7 @@ bool CCamera::EventFrameOnBoard(const Event &event)
{ {
assert(m_cameraObj->Implements(ObjectInterfaceType::Controllable)); assert(m_cameraObj->Implements(ObjectInterfaceType::Controllable));
Math::Vector lookatPt, upVec; Math::Vector lookatPt, upVec;
dynamic_cast<CControllableObject*>(m_cameraObj)->AdjustCamera(m_eyePt, m_directionH, m_directionV, lookatPt, upVec, m_type); dynamic_cast<CControllableObject&>(*m_cameraObj).AdjustCamera(m_eyePt, m_directionH, m_directionV, lookatPt, upVec, m_type);
Math::Vector eye = m_effectOffset * 0.3f + m_eyePt; Math::Vector eye = m_effectOffset * 0.3f + m_eyePt;
Math::Vector lookat = m_effectOffset * 0.3f + lookatPt; Math::Vector lookat = m_effectOffset * 0.3f + lookatPt;

View File

@ -408,6 +408,7 @@ void CEngine::ReloadAllTextures()
{ {
FlushTextureCache(); FlushTextureCache();
m_text->FlushCache(); m_text->FlushCache();
m_text->ReloadFonts();
m_app->GetEventQueue()->AddEvent(Event(EVENT_RELOAD_TEXTURES)); m_app->GetEventQueue()->AddEvent(Event(EVENT_RELOAD_TEXTURES));
UpdateGroundSpotTextures(); UpdateGroundSpotTextures();

View File

@ -1189,6 +1189,10 @@ public:
void EnablePauseBlur(); void EnablePauseBlur();
void DisablePauseBlur(); void DisablePauseBlur();
//! Reloads all textures
/** This additionally sends EVENT_RELOAD_TEXTURES to reload all textures not maintained by CEngine **/
void ReloadAllTextures();
protected: protected:
//! Resets some states and flushes textures after device was changed (e.g. resoulution changed) //! Resets some states and flushes textures after device was changed (e.g. resoulution changed)
/** Instead of calling this directly, send EVENT_RESOLUTION_CHANGED event **/ /** Instead of calling this directly, send EVENT_RESOLUTION_CHANGED event **/
@ -1287,10 +1291,6 @@ protected:
}; };
static void WriteScreenShotThread(std::unique_ptr<WriteScreenShotData> data); static void WriteScreenShotThread(std::unique_ptr<WriteScreenShotData> data);
//! Reloads all textures
/** This additionally sends EVENT_RELOAD_TEXTURES to reload all textures not maintained by CEngine **/
void ReloadAllTextures();
protected: protected:
CApplication* m_app; CApplication* m_app;
CSystemUtils* m_systemUtils; CSystemUtils* m_systemUtils;

View File

@ -323,7 +323,7 @@ CObject* CLightning::SearchObject(Math::Vector pos)
if (!obj->Implements(ObjectInterfaceType::Destroyable)) continue; if (!obj->Implements(ObjectInterfaceType::Destroyable)) continue;
float detect = m_magnetic * dynamic_cast<CDestroyableObject*>(obj)->GetLightningHitProbability(); float detect = m_magnetic * dynamic_cast<CDestroyableObject&>(*obj).GetLightningHitProbability();
if (detect == 0.0f) continue; if (detect == 0.0f) continue;
Math::Vector oPos = obj->GetPosition(); Math::Vector oPos = obj->GetPosition();

View File

@ -57,7 +57,18 @@ bool COldModelManager::LoadModel(const std::string& fileName, bool mirrored, int
if (!stream.is_open()) if (!stream.is_open())
throw CModelIOException(std::string("Could not open file '") + fileName + "'"); throw CModelIOException(std::string("Could not open file '") + fileName + "'");
model = ModelInput::Read(stream, ModelFormat::Old); std::string::size_type extension_index = fileName.find_last_of('.');
if (extension_index == std::string::npos)
throw CModelIOException(std::string("Filename '") + fileName + "' has no extension");
std::string extension = fileName.substr(extension_index + 1);
if (extension == "mod")
model = ModelInput::Read(stream, ModelFormat::Old);
else if (extension == "txt")
model = ModelInput::Read(stream, ModelFormat::Text);
else
throw CModelIOException(std::string("Filename '") + fileName + "' has unknown extension");
} }
catch (const CModelIOException& e) catch (const CModelIOException& e)
{ {

View File

@ -953,7 +953,7 @@ void CParticle::FrameParticle(float rTime)
m_particle[i].goal = m_particle[i].pos; m_particle[i].goal = m_particle[i].pos;
if (object != nullptr && object->Implements(ObjectInterfaceType::Damageable)) if (object != nullptr && object->Implements(ObjectInterfaceType::Damageable))
{ {
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Phazer, 0.002f, m_particle[i].objFather); dynamic_cast<CDamageableObject&>(*object).DamageObject(DamageType::Phazer, 0.002f, m_particle[i].objFather);
} }
m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration);
@ -1156,7 +1156,7 @@ void CParticle::FrameParticle(float rTime)
{ {
if (object->Implements(ObjectInterfaceType::Damageable)) if (object->Implements(ObjectInterfaceType::Damageable))
{ {
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, 0.001f, m_particle[i].objFather); dynamic_cast<CDamageableObject&>(*object).DamageObject(DamageType::Fire, 0.001f, m_particle[i].objFather);
} }
m_exploGunCounter++; m_exploGunCounter++;
@ -1222,7 +1222,7 @@ void CParticle::FrameParticle(float rTime)
m_particle[i].goal = m_particle[i].pos; m_particle[i].goal = m_particle[i].pos;
if (object != nullptr) if (object != nullptr)
{ {
if (object->GetType() == OBJECT_MOBILErs && dynamic_cast<CShielder*>(object)->GetActiveShieldRadius() > 0.0f) // protected by shield? if (object->GetType() == OBJECT_MOBILErs && dynamic_cast<CShielder&>(*object).GetActiveShieldRadius() > 0.0f) // protected by shield?
{ {
CreateParticle(m_particle[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); CreateParticle(m_particle[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f);
if (m_lastTimeGunDel > 0.2f) if (m_lastTimeGunDel > 0.2f)
@ -1240,7 +1240,7 @@ void CParticle::FrameParticle(float rTime)
if (object->Implements(ObjectInterfaceType::Damageable)) if (object->Implements(ObjectInterfaceType::Damageable))
{ {
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.1f, m_particle[i].objFather); // starts explosion dynamic_cast<CDamageableObject&>(*object).DamageObject(DamageType::Organic, 0.1f, m_particle[i].objFather); // starts explosion
} }
} }
} }
@ -1270,7 +1270,7 @@ void CParticle::FrameParticle(float rTime)
m_particle[i].goal = m_particle[i].pos; m_particle[i].goal = m_particle[i].pos;
if (object != nullptr) if (object != nullptr)
{ {
if (object->GetType() == OBJECT_MOBILErs && dynamic_cast<CShielder*>(object)->GetActiveShieldRadius() > 0.0f) if (object->GetType() == OBJECT_MOBILErs && dynamic_cast<CShielder&>(*object).GetActiveShieldRadius() > 0.0f)
{ {
CreateParticle(m_particle[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); CreateParticle(m_particle[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f);
if (m_lastTimeGunDel > 0.2f) if (m_lastTimeGunDel > 0.2f)
@ -1285,7 +1285,7 @@ void CParticle::FrameParticle(float rTime)
{ {
if (object->Implements(ObjectInterfaceType::Damageable)) if (object->Implements(ObjectInterfaceType::Damageable))
{ {
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, std::numeric_limits<float>::infinity(), m_particle[i].objFather); // starts explosion dynamic_cast<CDamageableObject&>(*object).DamageObject(DamageType::Fire, std::numeric_limits<float>::infinity(), m_particle[i].objFather); // starts explosion
} }
} }
} }
@ -1344,7 +1344,7 @@ void CParticle::FrameParticle(float rTime)
{ {
if (object->Implements(ObjectInterfaceType::Damageable)) if (object->Implements(ObjectInterfaceType::Damageable))
{ {
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.001f, m_particle[i].objFather); dynamic_cast<CDamageableObject&>(*object).DamageObject(DamageType::Organic, 0.001f, m_particle[i].objFather);
} }
m_exploGunCounter ++; m_exploGunCounter ++;
@ -2422,7 +2422,7 @@ void CParticle::FrameParticle(float rTime)
if (object != nullptr) if (object != nullptr)
{ {
assert(object->Implements(ObjectInterfaceType::Damageable)); assert(object->Implements(ObjectInterfaceType::Damageable));
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Tower, std::numeric_limits<float>::infinity(), m_particle[i].objFather); dynamic_cast<CDamageableObject&>(*object).DamageObject(DamageType::Tower, std::numeric_limits<float>::infinity(), m_particle[i].objFather);
} }
} }
@ -3543,6 +3543,7 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos,
continue; continue;
} }
if (!obj->Implements(ObjectInterfaceType::Damageable) && !obj->IsBulletWall()) continue; if (!obj->Implements(ObjectInterfaceType::Damageable) && !obj->IsBulletWall()) continue;
if (obj->Implements(ObjectInterfaceType::Jostleable)) continue;
Math::Vector oPos = obj->GetPosition(); Math::Vector oPos = obj->GetPosition();

View File

@ -129,7 +129,7 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
CObject* power = nullptr; CObject* power = nullptr;
if (obj->Implements(ObjectInterfaceType::Powered)) if (obj->Implements(ObjectInterfaceType::Powered))
power = dynamic_cast<CPoweredObject*>(obj)->GetPower(); power = dynamic_cast<CPoweredObject&>(*obj).GetPower();
if (power == nullptr) if (power == nullptr)
{ {
@ -260,7 +260,7 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
m_sound->Play(SOUND_DEADw, m_pos); m_sound->Play(SOUND_DEADw, m_pos);
} }
assert(m_object->Implements(ObjectInterfaceType::Controllable)); assert(m_object->Implements(ObjectInterfaceType::Controllable));
if ( type == PT_SHOTH && dynamic_cast<CControllableObject*>(m_object)->GetSelect() ) if ( type == PT_SHOTH && dynamic_cast<CControllableObject&>(*m_object).GetSelect() )
{ {
m_sound->Play(SOUND_AIE, m_pos); m_sound->Play(SOUND_AIE, m_pos);
m_sound->Play(SOUND_AIE, m_engine->GetEyePt()); m_sound->Play(SOUND_AIE, m_engine->GetEyePt());
@ -278,10 +278,10 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
if ( m_type == PT_DEADG ) if ( m_type == PT_DEADG )
{ {
assert(m_object->Implements(ObjectInterfaceType::Destroyable)); assert(m_object->Implements(ObjectInterfaceType::Destroyable));
dynamic_cast<CDestroyableObject*>(m_object)->SetDying(DeathType::Dead); dynamic_cast<CDestroyableObject&>(*m_object).SetDying(DeathType::Dead);
assert(obj->Implements(ObjectInterfaceType::Movable)); assert(obj->Implements(ObjectInterfaceType::Movable));
dynamic_cast<CMovableObject*>(obj)->GetMotion()->SetAction(MHS_DEADg, 1.0f); dynamic_cast<CMovableObject&>(*obj).GetMotion()->SetAction(MHS_DEADg, 1.0f);
m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 1.5f); m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 1.5f);
m_camera->StartOver(CAM_OVER_EFFECT_FADEOUT_WHITE, m_pos, 1.0f); m_camera->StartOver(CAM_OVER_EFFECT_FADEOUT_WHITE, m_pos, 1.0f);
@ -291,10 +291,10 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
if ( m_type == PT_DEADW ) if ( m_type == PT_DEADW )
{ {
assert(m_object->Implements(ObjectInterfaceType::Destroyable)); assert(m_object->Implements(ObjectInterfaceType::Destroyable));
dynamic_cast<CDestroyableObject*>(m_object)->SetDying(DeathType::Dead); dynamic_cast<CDestroyableObject&>(*m_object).SetDying(DeathType::Dead);
assert(obj->Implements(ObjectInterfaceType::Movable)); assert(obj->Implements(ObjectInterfaceType::Movable));
dynamic_cast<CMovableObject*>(obj)->GetMotion()->SetAction(MHS_DEADw, 1.0f); dynamic_cast<CMovableObject&>(*obj).GetMotion()->SetAction(MHS_DEADw, 1.0f);
m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 3.0f); m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 3.0f);
m_camera->StartOver(CAM_OVER_EFFECT_FADEOUT_BLACK, m_pos, 1.0f); m_camera->StartOver(CAM_OVER_EFFECT_FADEOUT_BLACK, m_pos, 1.0f);
@ -312,7 +312,7 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
if ( m_type == PT_SHOTH ) if ( m_type == PT_SHOTH )
{ {
assert(m_object->Implements(ObjectInterfaceType::Controllable)); assert(m_object->Implements(ObjectInterfaceType::Controllable));
if ( m_camera->GetBlood() && dynamic_cast<CControllableObject*>(m_object)->GetSelect() ) if ( m_camera->GetBlood() && dynamic_cast<CControllableObject&>(*m_object).GetSelect() )
{ {
m_camera->StartOver(CAM_OVER_EFFECT_BLOOD, m_pos, force); m_camera->StartOver(CAM_OVER_EFFECT_BLOOD, m_pos, force);
} }
@ -356,6 +356,12 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
if (oType == OBJECT_APOLLO2) limit = 2.0f; if (oType == OBJECT_APOLLO2) limit = 2.0f;
m_speed = 1.0f/limit; m_speed = 1.0f/limit;
} }
if ( m_type == PT_SQUASH )
{
m_speed = 1.0f/2.0f;
m_object->SetLock(true);
}
if ( m_type == PT_EXPLOT || if ( m_type == PT_EXPLOT ||
m_type == PT_EXPLOO || m_type == PT_EXPLOO ||
@ -399,7 +405,8 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
if ( m_type != PT_FRAGV && if ( m_type != PT_FRAGV &&
m_type != PT_EGG && m_type != PT_EGG &&
m_type != PT_WIN && m_type != PT_WIN &&
m_type != PT_LOST ) m_type != PT_LOST &&
m_type != PT_SQUASH)
{ {
float h = 40.0f; float h = 40.0f;
if ( m_type == PT_FRAGO || if ( m_type == PT_FRAGO ||
@ -454,7 +461,8 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
m_type != PT_FLCREATE && m_type != PT_FLCREATE &&
m_type != PT_FLDELETE && m_type != PT_FLDELETE &&
m_type != PT_RESET && m_type != PT_RESET &&
m_type != PT_FINDING ) m_type != PT_FINDING &&
m_type != PT_SQUASH )
{ {
m_camera->StartEffect(CAM_EFFECT_EXPLO, m_pos, force); m_camera->StartEffect(CAM_EFFECT_EXPLO, m_pos, force);
} }
@ -1049,6 +1057,11 @@ bool CPyro::EventProcess(const Event &event)
} }
} }
if ( m_type == PT_SQUASH && m_object != nullptr )
{
m_object->SetScaleY(1.0f-sinf(m_progress)*0.5f);
}
if ( (m_type == PT_BURNT || m_type == PT_BURNO) && if ( (m_type == PT_BURNT || m_type == PT_BURNO) &&
m_object != nullptr ) m_object != nullptr )
{ {
@ -1229,6 +1242,11 @@ Error CPyro::IsEnded()
m_object->SetScale(1.0f); m_object->SetScale(1.0f);
} }
if ( m_type == PT_SQUASH )
{
m_object->SetType(OBJECT_PLANT19);
}
if ( m_lightRank != -1 ) if ( m_lightRank != -1 )
{ {
m_lightMan->DeleteLight(m_lightRank); m_lightMan->DeleteLight(m_lightRank);
@ -1395,7 +1413,7 @@ void CPyro::DeleteObject(bool primary, bool secondary)
if (m_object->Implements(ObjectInterfaceType::Transportable)) if (m_object->Implements(ObjectInterfaceType::Transportable))
{ {
// TODO: this should be handled in the object's destructor // TODO: this should be handled in the object's destructor
CObject* transporter = dynamic_cast<CTransportableObject*>(m_object)->GetTransporter(); CObject* transporter = dynamic_cast<CTransportableObject&>(*m_object).GetTransporter();
if (transporter != nullptr) if (transporter != nullptr)
{ {
if (transporter->Implements(ObjectInterfaceType::Powered)) if (transporter->Implements(ObjectInterfaceType::Powered))
@ -1564,12 +1582,12 @@ void CPyro::ExploStart()
m_object->Simplify(); m_object->Simplify();
m_object->SetLock(true); // ruin not usable yet m_object->SetLock(true); // ruin not usable yet
assert(m_object->Implements(ObjectInterfaceType::Destroyable)); assert(m_object->Implements(ObjectInterfaceType::Destroyable));
dynamic_cast<CDestroyableObject*>(m_object)->SetDying(DeathType::Exploding); // being destroyed dynamic_cast<CDestroyableObject&>(*m_object).SetDying(DeathType::Exploding); // being destroyed
m_object->FlatParent(); m_object->FlatParent();
if ( m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject*>(m_object)->GetSelect() ) if ( m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject&>(*m_object).GetSelect() )
{ {
dynamic_cast<CControllableObject*>(m_object)->SetSelect(false); // deselects the object dynamic_cast<CControllableObject&>(*m_object).SetSelect(false); // deselects the object
m_camera->SetType(CAM_TYPE_EXPLO); m_camera->SetType(CAM_TYPE_EXPLO);
m_main->DeselectAll(); m_main->DeselectAll();
} }
@ -1593,7 +1611,7 @@ void CPyro::ExploStart()
// TODO: temporary hack (hopefully) // TODO: temporary hack (hopefully)
assert(m_object->Implements(ObjectInterfaceType::Old)); assert(m_object->Implements(ObjectInterfaceType::Old));
Math::Vector pos = dynamic_cast<COldObject*>(m_object)->GetPartPosition(i); Math::Vector pos = dynamic_cast<COldObject&>(*m_object).GetPartPosition(i);
Math::Vector speed; Math::Vector speed;
float weight; float weight;
@ -1640,9 +1658,9 @@ void CPyro::BurnStart()
m_object->Simplify(); m_object->Simplify();
m_object->SetLock(true); // ruin not usable yet m_object->SetLock(true); // ruin not usable yet
if ( m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject*>(m_object)->GetSelect() ) if ( m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject&>(*m_object).GetSelect() )
{ {
dynamic_cast<CControllableObject*>(m_object)->SetSelect(false); // deselects the object dynamic_cast<CControllableObject&>(*m_object).SetSelect(false); // deselects the object
m_camera->SetType(CAM_TYPE_EXPLO); m_camera->SetType(CAM_TYPE_EXPLO);
m_main->DeselectAll(); m_main->DeselectAll();
} }
@ -2180,7 +2198,7 @@ void CPyro::BurnProgress()
if (m_object->Implements(ObjectInterfaceType::Powered)) if (m_object->Implements(ObjectInterfaceType::Powered))
{ {
CObject* sub = dynamic_cast<CPoweredObject*>(m_object)->GetPower(); CObject* sub = dynamic_cast<CPoweredObject&>(*m_object).GetPower();
if (sub != nullptr) // is there a battery? if (sub != nullptr) // is there a battery?
sub->SetScaleY(1.0f - m_progress); // complete flattening sub->SetScaleY(1.0f - m_progress); // complete flattening
} }
@ -2274,7 +2292,7 @@ CObject* CPyro::FallSearchBeeExplo()
if (obj->GetType() == OBJECT_MOBILErs) if (obj->GetType() == OBJECT_MOBILErs)
{ {
float shieldRadius = dynamic_cast<CShielder*>(obj)->GetActiveShieldRadius(); float shieldRadius = dynamic_cast<CShielder&>(*obj).GetActiveShieldRadius();
if ( shieldRadius > 0.0f ) if ( shieldRadius > 0.0f )
{ {
float distance = Math::Distance(oPos, bulletCrashSphere.sphere.pos); float distance = Math::Distance(oPos, bulletCrashSphere.sphere.pos);
@ -2342,12 +2360,12 @@ void CPyro::FallProgress(float rTime)
{ {
assert(m_object->Implements(ObjectInterfaceType::Destroyable)); assert(m_object->Implements(ObjectInterfaceType::Destroyable));
// TODO: implement "killer"? // TODO: implement "killer"?
dynamic_cast<CDestroyableObject*>(m_object)->DestroyObject(DestructionType::Explosion); dynamic_cast<CDestroyableObject&>(*m_object).DestroyObject(DestructionType::Explosion);
} }
} }
else else
{ {
if (obj->GetType() == OBJECT_MOBILErs && dynamic_cast<CShielder*>(obj)->GetActiveShieldRadius() > 0.0f) // protected by shield? if (obj->GetType() == OBJECT_MOBILErs && dynamic_cast<CShielder&>(*obj).GetActiveShieldRadius() > 0.0f) // protected by shield?
{ {
m_particle->CreateParticle(pos, Math::Vector(0.0f, 0.0f, 0.0f), m_particle->CreateParticle(pos, Math::Vector(0.0f, 0.0f, 0.0f),
Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f, 0.0f, 0.0f); Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f, 0.0f, 0.0f);
@ -2358,7 +2376,7 @@ void CPyro::FallProgress(float rTime)
else else
{ {
assert(obj->Implements(ObjectInterfaceType::Damageable)); assert(obj->Implements(ObjectInterfaceType::Damageable));
if (dynamic_cast<CDamageableObject*>(obj)->DamageObject(DamageType::FallingObject)) if (dynamic_cast<CDamageableObject&>(*obj).DamageObject(DamageType::FallingObject))
{ {
DeleteObject(true, true); // removes the ball DeleteObject(true, true); // removes the ball
} }
@ -2366,7 +2384,7 @@ void CPyro::FallProgress(float rTime)
{ {
assert(m_object->Implements(ObjectInterfaceType::Destroyable)); assert(m_object->Implements(ObjectInterfaceType::Destroyable));
// TODO: implement "killer"? // TODO: implement "killer"?
dynamic_cast<CDestroyableObject*>(m_object)->DestroyObject(DestructionType::Explosion); dynamic_cast<CDestroyableObject&>(*m_object).DestroyObject(DestructionType::Explosion);
} }
} }
} }

View File

@ -59,6 +59,7 @@ enum PyroType
PT_DEADW = 25, //! < drowning death PT_DEADW = 25, //! < drowning death
PT_FINDING = 26, //! < object discovered PT_FINDING = 26, //! < object discovered
PT_FRAGV = 27, //! < fragmentation of plant object PT_FRAGV = 27, //! < fragmentation of plant object
PT_SQUASH = 28, //! < flattening plants
}; };
} // namespace Gfx } // namespace Gfx

View File

@ -191,17 +191,32 @@ CText::~CText()
bool CText::Create() bool CText::Create()
{ {
CFontLoader fontLoader;
if (!fontLoader.Init())
{
GetLogger()->Warn("Error on parsing fonts config file: failed to open file\n");
}
if (TTF_Init() != 0) if (TTF_Init() != 0)
{ {
m_error = std::string("TTF_Init error: ") + std::string(TTF_GetError()); m_error = std::string("TTF_Init error: ") + std::string(TTF_GetError());
return false; return false;
} }
if (!ReloadFonts())
{
return false;
}
return true;
}
bool CText::ReloadFonts()
{
CFontLoader fontLoader;
if (!fontLoader.Init())
{
GetLogger()->Debug("Error on parsing fonts config file: failed to open file\n");
}
// Backup previous fonts
auto fonts = std::move(m_fonts);
m_fonts.clear();
for (auto type : {FONT_COMMON, FONT_STUDIO, FONT_SATCOM}) for (auto type : {FONT_COMMON, FONT_STUDIO, FONT_SATCOM})
{ {
m_fonts[static_cast<Gfx::FontType>(type)] = MakeUnique<MultisizeFont>(fontLoader.GetFont(type)); m_fonts[static_cast<Gfx::FontType>(type)] = MakeUnique<MultisizeFont>(fontLoader.GetFont(type));
@ -214,7 +229,10 @@ bool CText::Create()
FontType type = (*it).first; FontType type = (*it).first;
CachedFont* cf = GetOrOpenFont(type, m_defaultSize); CachedFont* cf = GetOrOpenFont(type, m_defaultSize);
if (cf == nullptr || cf->font == nullptr) if (cf == nullptr || cf->font == nullptr)
{
m_fonts = std::move(fonts);
return false; return false;
}
} }
return true; return true;
@ -430,7 +448,7 @@ float CText::GetStringWidth(const std::string &text,
UTF8Char ch; UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index); int len = GetCharSizeAt(font, text, index);
if (len >= 1) if (len >= 1)
ch.c1 = text[index]; ch.c1 = text[index];
if (len >= 2) if (len >= 2)
@ -441,7 +459,7 @@ float CText::GetStringWidth(const std::string &text,
width += GetCharWidth(ch, font, size, width); width += GetCharWidth(ch, font, size, width);
index += len; index += len;
fmtIndex++; fmtIndex += len;
} }
return width; return width;
@ -565,7 +583,7 @@ int CText::Justify(const std::string &text, std::vector<FontMetaChar>::iterator
UTF8Char ch; UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index); int len = GetCharSizeAt(font, text, index);
if (len >= 1) if (len >= 1)
ch.c1 = text[index]; ch.c1 = text[index];
if (len >= 2) if (len >= 2)
@ -589,7 +607,7 @@ int CText::Justify(const std::string &text, std::vector<FontMetaChar>::iterator
} }
index += len; index += len;
fmtIndex++; fmtIndex += len;
} }
return index; return index;
@ -606,7 +624,7 @@ int CText::Justify(const std::string &text, FontType font, float size, float wid
{ {
UTF8Char ch; UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index); int len = GetCharSizeAt(font, text, index);
if (len >= 1) if (len >= 1)
ch.c1 = text[index]; ch.c1 = text[index];
if (len >= 2) if (len >= 2)
@ -648,12 +666,9 @@ int CText::Detect(const std::string &text, std::vector<FontMetaChar>::iterator f
if (format + fmtIndex != end) if (format + fmtIndex != end)
font = static_cast<FontType>(*(format + fmtIndex) & FONT_MASK_FONT); font = static_cast<FontType>(*(format + fmtIndex) & FONT_MASK_FONT);
// TODO: if (font == FONT_BUTTON)
//if (font == FONT_BUTTON) continue;
UTF8Char ch; UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index); int len = GetCharSizeAt(font, text, index);
if (len >= 1) if (len >= 1)
ch.c1 = text[index]; ch.c1 = text[index];
if (len >= 2) if (len >= 2)
@ -670,7 +685,7 @@ int CText::Detect(const std::string &text, std::vector<FontMetaChar>::iterator f
pos += width; pos += width;
index += len; index += len;
fmtIndex++; fmtIndex += len;
} }
return index; return index;
@ -686,7 +701,7 @@ int CText::Detect(const std::string &text, FontType font, float size, float offs
{ {
UTF8Char ch; UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index); int len = GetCharSizeAt(font, text, index);
if (len >= 1) if (len >= 1)
ch.c1 = text[index]; ch.c1 = text[index];
if (len >= 2) if (len >= 2)
@ -898,16 +913,7 @@ void CText::StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &
if (format + index != end) if (format + index != end)
font = static_cast<FontType>(*(format + index) & FONT_MASK_FONT); font = static_cast<FontType>(*(format + index) & FONT_MASK_FONT);
int len; int len = GetCharSizeAt(font, text, index);
if(font == FONT_BUTTON)
{
len = 1;
}
else
{
len = StrUtils::Utf8CharSizeAt(text, index);
}
if (len >= 1) if (len >= 1)
ch.c1 = text[index]; ch.c1 = text[index];
@ -922,6 +928,20 @@ void CText::StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &
} }
} }
int CText::GetCharSizeAt(Gfx::FontType font, const std::string& text, unsigned int index) const
{
int len = 0;
if (font == FONT_BUTTON)
{
len = 1;
}
else
{
len = StrUtils::Utf8CharSizeAt(text, index);
}
return len;
}
void CText::DrawString(const std::string &text, FontType font, void CText::DrawString(const std::string &text, FontType font,
float size, Math::IntPoint pos, int width, int eol, Color color) float size, Math::IntPoint pos, int width, int eol, Color color)
{ {

View File

@ -256,6 +256,8 @@ public:
//! Flushes cached textures //! Flushes cached textures
void FlushCache(); void FlushCache();
//! Try to load new font files
bool ReloadFonts();
//@{ //@{
//! Tab size management //! Tab size management
@ -337,6 +339,8 @@ protected:
void StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &chars); void StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &chars);
void StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &chars, std::vector<FontMetaChar>::iterator format, std::vector<FontMetaChar>::iterator end); void StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &chars, std::vector<FontMetaChar>::iterator format, std::vector<FontMetaChar>::iterator end);
int GetCharSizeAt(Gfx::FontType font, const std::string& text, unsigned int index) const;
protected: protected:
CEngine* m_engine; CEngine* m_engine;
CDevice* m_device; CDevice* m_device;

View File

@ -388,6 +388,7 @@ bool CGL21Device::Create()
uni.modelMatrix = glGetUniformLocation(m_normalProgram, "uni_ModelMatrix"); uni.modelMatrix = glGetUniformLocation(m_normalProgram, "uni_ModelMatrix");
uni.normalMatrix = glGetUniformLocation(m_normalProgram, "uni_NormalMatrix"); uni.normalMatrix = glGetUniformLocation(m_normalProgram, "uni_NormalMatrix");
uni.shadowMatrix = glGetUniformLocation(m_normalProgram, "uni_ShadowMatrix"); uni.shadowMatrix = glGetUniformLocation(m_normalProgram, "uni_ShadowMatrix");
uni.cameraPosition = glGetUniformLocation(m_normalProgram, "uni_CameraPosition");
uni.primaryTexture = glGetUniformLocation(m_normalProgram, "uni_PrimaryTexture"); uni.primaryTexture = glGetUniformLocation(m_normalProgram, "uni_PrimaryTexture");
uni.secondaryTexture = glGetUniformLocation(m_normalProgram, "uni_SecondaryTexture"); uni.secondaryTexture = glGetUniformLocation(m_normalProgram, "uni_SecondaryTexture");
@ -408,6 +409,7 @@ bool CGL21Device::Create()
uni.fogColor = glGetUniformLocation(m_normalProgram, "uni_FogColor"); uni.fogColor = glGetUniformLocation(m_normalProgram, "uni_FogColor");
uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor"); uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor");
uni.shadowTexelSize = glGetUniformLocation(m_normalProgram, "uni_ShadowTexelSize");
uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount"); uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount");
uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_Material.ambient"); uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_Material.ambient");
@ -441,6 +443,7 @@ bool CGL21Device::Create()
glUniformMatrix4fv(uni.modelMatrix, 1, GL_FALSE, matrix.Array()); glUniformMatrix4fv(uni.modelMatrix, 1, GL_FALSE, matrix.Array());
glUniformMatrix4fv(uni.normalMatrix, 1, GL_FALSE, matrix.Array()); glUniformMatrix4fv(uni.normalMatrix, 1, GL_FALSE, matrix.Array());
glUniformMatrix4fv(uni.shadowMatrix, 1, GL_FALSE, matrix.Array()); glUniformMatrix4fv(uni.shadowMatrix, 1, GL_FALSE, matrix.Array());
glUniform3f(uni.cameraPosition, 0.0f, 0.0f, 0.0f);
glUniform1i(uni.primaryTexture, 0); glUniform1i(uni.primaryTexture, 0);
glUniform1i(uni.secondaryTexture, 1); glUniform1i(uni.secondaryTexture, 1);
@ -457,6 +460,7 @@ bool CGL21Device::Create()
glUniform4f(uni.fogColor, 0.8f, 0.8f, 0.8f, 1.0f); glUniform4f(uni.fogColor, 0.8f, 0.8f, 0.8f, 1.0f);
glUniform1f(uni.shadowColor, 0.5f); glUniform1f(uni.shadowColor, 0.5f);
glUniform1f(uni.shadowTexelSize, 0.5f);
glUniform1i(uni.lightCount, 0); glUniform1i(uni.lightCount, 0);
} }
@ -653,6 +657,7 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix)
else if (type == TRANSFORM_VIEW) else if (type == TRANSFORM_VIEW)
{ {
Math::Matrix scale; Math::Matrix scale;
Math::Vector cameraPosition;
scale.Set(3, 3, -1.0f); scale.Set(3, 3, -1.0f);
m_viewMat = Math::MultiplyMatrices(scale, matrix); m_viewMat = Math::MultiplyMatrices(scale, matrix);
@ -660,6 +665,13 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix)
m_combinedMatrix = Math::MultiplyMatrices(m_projectionMat, m_modelviewMat); m_combinedMatrix = Math::MultiplyMatrices(m_projectionMat, m_modelviewMat);
glUniformMatrix4fv(m_uniforms[m_mode].viewMatrix, 1, GL_FALSE, m_viewMat.Array()); glUniformMatrix4fv(m_uniforms[m_mode].viewMatrix, 1, GL_FALSE, m_viewMat.Array());
if (m_uniforms[m_mode].cameraPosition >= 0)
{
cameraPosition.LoadZero();
cameraPosition = MatrixVectorMultiply(m_viewMat.Inverse(), cameraPosition);
glUniform3fv(m_uniforms[m_mode].cameraPosition, 1, cameraPosition.Array());
}
} }
else if (type == TRANSFORM_PROJECTION) else if (type == TRANSFORM_PROJECTION)
{ {
@ -1439,6 +1451,7 @@ void CGL21Device::SetRenderState(RenderState state, bool enabled)
} }
else if (state == RENDER_STATE_SHADOW_MAPPING) else if (state == RENDER_STATE_SHADOW_MAPPING)
{ {
glUniform1f(m_uniforms[m_mode].shadowTexelSize, 1.0/m_currentTextures[TEXTURE_SHADOW].size.x);
SetTextureEnabled(TEXTURE_SHADOW, enabled); SetTextureEnabled(TEXTURE_SHADOW, enabled);
return; return;

View File

@ -363,6 +363,7 @@ bool CGL33Device::Create()
uni.modelMatrix = glGetUniformLocation(m_normalProgram, "uni_ModelMatrix"); uni.modelMatrix = glGetUniformLocation(m_normalProgram, "uni_ModelMatrix");
uni.normalMatrix = glGetUniformLocation(m_normalProgram, "uni_NormalMatrix"); uni.normalMatrix = glGetUniformLocation(m_normalProgram, "uni_NormalMatrix");
uni.shadowMatrix = glGetUniformLocation(m_normalProgram, "uni_ShadowMatrix"); uni.shadowMatrix = glGetUniformLocation(m_normalProgram, "uni_ShadowMatrix");
uni.cameraPosition = glGetUniformLocation(m_normalProgram, "uni_CameraPosition");
uni.primaryTexture = glGetUniformLocation(m_normalProgram, "uni_PrimaryTexture"); uni.primaryTexture = glGetUniformLocation(m_normalProgram, "uni_PrimaryTexture");
uni.secondaryTexture = glGetUniformLocation(m_normalProgram, "uni_SecondaryTexture"); uni.secondaryTexture = glGetUniformLocation(m_normalProgram, "uni_SecondaryTexture");
@ -420,6 +421,7 @@ bool CGL33Device::Create()
glUniformMatrix4fv(uni.modelMatrix, 1, GL_FALSE, matrix.Array()); glUniformMatrix4fv(uni.modelMatrix, 1, GL_FALSE, matrix.Array());
glUniformMatrix4fv(uni.normalMatrix, 1, GL_FALSE, matrix.Array()); glUniformMatrix4fv(uni.normalMatrix, 1, GL_FALSE, matrix.Array());
glUniformMatrix4fv(uni.shadowMatrix, 1, GL_FALSE, matrix.Array()); glUniformMatrix4fv(uni.shadowMatrix, 1, GL_FALSE, matrix.Array());
glUniform3f(uni.cameraPosition, 0.0f, 0.0f, 0.0f);
glUniform1i(uni.primaryTexture, 0); glUniform1i(uni.primaryTexture, 0);
glUniform1i(uni.secondaryTexture, 1); glUniform1i(uni.secondaryTexture, 1);
@ -660,6 +662,7 @@ void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix)
else if (type == TRANSFORM_VIEW) else if (type == TRANSFORM_VIEW)
{ {
Math::Matrix scale; Math::Matrix scale;
Math::Vector cameraPosition;
scale.Set(3, 3, -1.0f); scale.Set(3, 3, -1.0f);
m_viewMat = Math::MultiplyMatrices(scale, matrix); m_viewMat = Math::MultiplyMatrices(scale, matrix);
@ -667,6 +670,13 @@ void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix)
m_combinedMatrixOutdated = true; m_combinedMatrixOutdated = true;
glUniformMatrix4fv(m_uni->viewMatrix, 1, GL_FALSE, m_viewMat.Array()); glUniformMatrix4fv(m_uni->viewMatrix, 1, GL_FALSE, m_viewMat.Array());
if (m_uni->cameraPosition >= 0)
{
cameraPosition.LoadZero();
cameraPosition = MatrixVectorMultiply(m_viewMat.Inverse(), cameraPosition);
glUniform3fv(m_uni->cameraPosition, 1, cameraPosition.Array());
}
} }
else if (type == TRANSFORM_PROJECTION) else if (type == TRANSFORM_PROJECTION)
{ {
@ -876,6 +886,8 @@ void CGL33Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, I
glTexSubImage2D(GL_TEXTURE_2D, 0, offset.x, offset.y, texData.actualSurface->w, texData.actualSurface->h, glTexSubImage2D(GL_TEXTURE_2D, 0, offset.x, offset.y, texData.actualSurface->w, texData.actualSurface->h,
texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels); texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels);
glGenerateMipmap(GL_TEXTURE_2D);
SDL_FreeSurface(texData.convertedSurface); SDL_FreeSurface(texData.convertedSurface);
} }

View File

@ -167,6 +167,8 @@ struct UniformLocations
GLint shadowMatrix = -1; GLint shadowMatrix = -1;
//! Normal matrix //! Normal matrix
GLint normalMatrix = -1; GLint normalMatrix = -1;
//! Camera position
GLint cameraPosition = -1;
//! Primary texture sampler //! Primary texture sampler
GLint primaryTexture = -1; GLint primaryTexture = -1;
@ -193,6 +195,8 @@ struct UniformLocations
//! Shadow color //! Shadow color
GLint shadowColor = -1; GLint shadowColor = -1;
//! Shadow texel size
GLint shadowTexelSize = -1;
// Number of enabled lights // Number of enabled lights
GLint lightCount = -1; GLint lightCount = -1;

View File

@ -35,6 +35,7 @@ uniform vec2 uni_FogRange;
uniform vec4 uni_FogColor; uniform vec4 uni_FogColor;
uniform float uni_ShadowColor; uniform float uni_ShadowColor;
uniform float uni_ShadowTexelSize;
struct LightParams struct LightParams
{ {
@ -56,6 +57,7 @@ uniform Material uni_Material;
uniform int uni_LightCount; uniform int uni_LightCount;
uniform LightParams uni_Light[4]; uniform LightParams uni_Light[4];
varying vec3 pass_CameraDirection;
varying float pass_Distance; varying float pass_Distance;
varying vec4 pass_Color; varying vec4 pass_Color;
varying vec3 pass_Normal; varying vec3 pass_Normal;
@ -76,16 +78,17 @@ void main()
vec4 specular = vec4(0.0f); vec4 specular = vec4(0.0f);
vec3 normal = normalize(pass_Normal); vec3 normal = normalize(pass_Normal);
vec3 camera = normalize(pass_CameraDirection);
for (int i = 0; i < uni_LightCount; i++) for (int i = 0; i < uni_LightCount; i++)
{ {
LightParams light = uni_Light[i]; LightParams light = uni_Light[i];
vec3 lightDirection = light.Position.xyz; vec3 lightDirection = light.Position.xyz;
vec3 reflectDirection = -reflect(lightDirection, normal); vec3 reflectAxis = normalize(normalize(lightDirection) + camera);
float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f); float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f);
float specularComponent = clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f); float specularComponent = pow(clamp(dot(normal, reflectAxis), 0.0f, 1.0f), 10.0f);
ambient += light.Ambient; ambient += light.Ambient;
diffuse += diffuseComponent * light.Diffuse; diffuse += diffuseComponent * light.Diffuse;
@ -97,13 +100,11 @@ void main()
if (uni_TextureEnabled[2]) if (uni_TextureEnabled[2])
{ {
#ifdef CONFIG_QUALITY_SHADOWS #ifdef CONFIG_QUALITY_SHADOWS
float offset = 0.00025f;
float value = (1.0f / 5.0f) * (shadow2D(uni_ShadowTexture, pass_TexCoord2).x float value = (1.0f / 5.0f) * (shadow2D(uni_ShadowTexture, pass_TexCoord2).x
+ shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( offset, 0.0f, 0.0f)).x + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( uni_ShadowTexelSize, 0.0f, 0.0f)).x
+ shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3(-offset, 0.0f, 0.0f)).x + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3(-uni_ShadowTexelSize, 0.0f, 0.0f)).x
+ shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, offset, 0.0f)).x + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, uni_ShadowTexelSize, 0.0f)).x
+ shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, -offset, 0.0f)).x); + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, -uni_ShadowTexelSize, 0.0f)).x);
shadow = mix(uni_ShadowColor, 1.0f, value); shadow = mix(uni_ShadowColor, 1.0f, value);
#else #else

View File

@ -24,7 +24,9 @@ uniform mat4 uni_ViewMatrix;
uniform mat4 uni_ModelMatrix; uniform mat4 uni_ModelMatrix;
uniform mat4 uni_ShadowMatrix; uniform mat4 uni_ShadowMatrix;
uniform mat4 uni_NormalMatrix; uniform mat4 uni_NormalMatrix;
uniform vec3 uni_CameraPosition;
varying vec3 pass_CameraDirection;
varying float pass_Distance; varying float pass_Distance;
varying vec4 pass_Color; varying vec4 pass_Color;
varying vec3 pass_Normal; varying vec3 pass_Normal;
@ -40,6 +42,7 @@ void main()
gl_Position = uni_ProjectionMatrix * eyeSpace; gl_Position = uni_ProjectionMatrix * eyeSpace;
pass_CameraDirection = uni_CameraPosition - position.xyz;
pass_Color = gl_Color; pass_Color = gl_Color;
pass_Normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz); pass_Normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz);
pass_Distance = abs(eyeSpace.z / eyeSpace.w); pass_Distance = abs(eyeSpace.z / eyeSpace.w);

View File

@ -63,6 +63,7 @@ in VertexData
vec4 ShadowCoord; vec4 ShadowCoord;
vec4 LightColor; vec4 LightColor;
float Distance; float Distance;
vec3 CameraDirection;
} data; } data;
out vec4 out_FragColor; out vec4 out_FragColor;
@ -78,17 +79,17 @@ void main()
vec4 specular = vec4(0.0f); vec4 specular = vec4(0.0f);
vec3 normal = normalize(data.Normal); vec3 normal = normalize(data.Normal);
vec3 camera = normalize(data.CameraDirection);
for (int i = 0; i < uni_LightCount; i++) for (int i = 0; i < uni_LightCount; i++)
{ {
vec3 lightDirection = uni_Light[i].Position.xyz; vec3 lightDirection = uni_Light[i].Position.xyz;
vec3 reflectAxis = normalize(normalize(lightDirection) + camera);
vec3 reflectDirection = -reflect(lightDirection, normal);
ambient += uni_Light[i].Ambient; ambient += uni_Light[i].Ambient;
diffuse += clamp(dot(normal, lightDirection), 0.0f, 1.0f) diffuse += clamp(dot(normal, lightDirection), 0.0f, 1.0f)
* uni_Light[i].Diffuse; * uni_Light[i].Diffuse;
specular += clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f) specular += pow(clamp(dot(normal, reflectAxis), 0.0f, 1.0f), 10.0f)
* uni_Light[i].Specular; * uni_Light[i].Specular;
} }

View File

@ -25,6 +25,7 @@ uniform mat4 uni_ViewMatrix;
uniform mat4 uni_ModelMatrix; uniform mat4 uni_ModelMatrix;
uniform mat4 uni_ShadowMatrix; uniform mat4 uni_ShadowMatrix;
uniform mat4 uni_NormalMatrix; uniform mat4 uni_NormalMatrix;
uniform vec3 uni_CameraPosition;
layout(location = 0) in vec4 in_VertexCoord; layout(location = 0) in vec4 in_VertexCoord;
layout(location = 1) in vec3 in_Normal; layout(location = 1) in vec3 in_Normal;
@ -41,6 +42,7 @@ out VertexData
vec4 ShadowCoord; vec4 ShadowCoord;
vec4 LightColor; vec4 LightColor;
float Distance; float Distance;
vec3 CameraDirection;
} data; } data;
void main() void main()
@ -56,4 +58,5 @@ void main()
data.Normal = normalize((uni_NormalMatrix * vec4(in_Normal, 0.0f)).xyz); data.Normal = normalize((uni_NormalMatrix * vec4(in_Normal, 0.0f)).xyz);
data.ShadowCoord = vec4(shadowCoord.xyz / shadowCoord.w, 1.0f); data.ShadowCoord = vec4(shadowCoord.xyz / shadowCoord.w, 1.0f);
data.Distance = abs(eyeSpace.z); data.Distance = abs(eyeSpace.z);
data.CameraDirection = uni_CameraPosition - position.xyz;
} }

View File

@ -41,7 +41,8 @@ enum BuildType
BUILD_LABO = (1<<10), //! < AutoLab BUILD_LABO = (1<<10), //! < AutoLab
BUILD_PARA = (1<<11), //! < PowerCaptor BUILD_PARA = (1<<11), //! < PowerCaptor
BUILD_INFO = (1<<12), //! < ExchangePost BUILD_INFO = (1<<12), //! < ExchangePost
BUILD_DESTROYER = (1<<13), //! < Destroyer BUILD_SAFE = (1<<13), //! < Vault
BUILD_DESTROYER = (1<<14), //! < Destroyer
BUILD_GFLAT = (1<<16), //! < checking flat ground BUILD_GFLAT = (1<<16), //! < checking flat ground
BUILD_FLAG = (1<<17) //! < putting / removing flags BUILD_FLAG = (1<<17) //! < putting / removing flags
}; };

View File

@ -25,10 +25,11 @@
// TODO: I'm not sure about "challenges" + "custom". It may be messing things up already right now. // TODO: I'm not sure about "challenges" + "custom". It may be messing things up already right now.
const std::map<LevelCategory, std::string> CATEGORY_DIR_MAP = { const std::map<LevelCategory, std::string> CATEGORY_DIR_MAP = {
{ LevelCategory::Missions, "missions" }, { LevelCategory::Missions, "missions" },
{ LevelCategory::FreeGame, "freemissions" }, { LevelCategory::FreeGame, "free" },
{ LevelCategory::Exercises, "exercises" }, { LevelCategory::Exercises, "exercises" },
{ LevelCategory::Challenges, "challenges" }, { LevelCategory::Challenges, "challenges" },
{ LevelCategory::CodeBattles, "battles" }, { LevelCategory::CodeBattles, "battles" },
{ LevelCategory::GamePlus, "plus" },
{ LevelCategory::CustomLevels, "custom" }, { LevelCategory::CustomLevels, "custom" },
}; };

View File

@ -28,6 +28,7 @@ enum class LevelCategory
Missions, Missions,
FreeGame, FreeGame,
CodeBattles, CodeBattles,
GamePlus,
CustomLevels, CustomLevels,
Max, Max,
}; };

View File

@ -90,7 +90,7 @@ bool CMainMovie::Start(MainMovieType type, float time)
} }
assert(pObj->Implements(ObjectInterfaceType::Movable)); assert(pObj->Implements(ObjectInterfaceType::Movable));
dynamic_cast<CMovableObject*>(pObj)->GetMotion()->SetAction(MHS_SATCOM, 0.5f); // reads the SatCom dynamic_cast<CMovableObject&>(*pObj).GetMotion()->SetAction(MHS_SATCOM, 0.5f); // reads the SatCom
m_camera->GetCamera(m_initialEye, m_initialLookat); m_camera->GetCamera(m_initialEye, m_initialLookat);
m_camera->SetType(Gfx::CAM_TYPE_SCRIPT); m_camera->SetType(Gfx::CAM_TYPE_SCRIPT);
@ -110,7 +110,7 @@ bool CMainMovie::Start(MainMovieType type, float time)
if ( pObj != nullptr ) if ( pObj != nullptr )
{ {
assert(pObj->Implements(ObjectInterfaceType::Movable)); assert(pObj->Implements(ObjectInterfaceType::Movable));
dynamic_cast<CMovableObject*>(pObj)->GetMotion()->SetAction(-1); // finishes reading SatCom dynamic_cast<CMovableObject&>(*pObj).GetMotion()->SetAction(-1); // finishes reading SatCom
} }
m_camera->SetType(Gfx::CAM_TYPE_BACK); m_camera->SetType(Gfx::CAM_TYPE_BACK);
@ -132,7 +132,7 @@ bool CMainMovie::Stop()
if ( pObj != nullptr ) if ( pObj != nullptr )
{ {
assert(pObj->Implements(ObjectInterfaceType::Movable)); assert(pObj->Implements(ObjectInterfaceType::Movable));
dynamic_cast<CMovableObject*>(pObj)->GetMotion()->SetAction(-1); // finishes reading SatCom dynamic_cast<CMovableObject&>(*pObj).GetMotion()->SetAction(-1); // finishes reading SatCom
} }
} }

View File

@ -41,6 +41,7 @@
#include <boost/algorithm/string/trim.hpp> #include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
CLevelParser::CLevelParser() CLevelParser::CLevelParser()
{ {
@ -172,13 +173,28 @@ void CLevelParser::Load()
boost::replace_all(line, "\t", " "); // replace tab by space boost::replace_all(line, "\t", " "); // replace tab by space
// ignore comments // ignore comments
std::size_t comment = line.find("//"); size_t pos = 0;
if (comment != std::string::npos) std::string linesuffix = line;
line = line.substr(0, comment); boost::regex commentRegex{ R"(("[^"]*")|('[^']*')|(//.*$))" };
boost::smatch matches;
while (boost::regex_search(linesuffix, matches, commentRegex))
{
if (matches[3].matched)
{
pos += std::distance(linesuffix.cbegin(), matches.prefix().second);
line = line.substr(0, pos);
linesuffix = "";
}
else
{
pos += std::distance(linesuffix.cbegin(), matches.suffix().first);
linesuffix = matches.suffix().str();
}
}
boost::algorithm::trim(line); boost::algorithm::trim(line);
std::size_t pos = line.find_first_of(" \t\n"); pos = line.find_first_of(" \t\n");
std::string command = line.substr(0, pos); std::string command = line.substr(0, pos);
if (pos != std::string::npos) if (pos != std::string::npos)
{ {

View File

@ -885,6 +885,7 @@ int CLevelParserParam::ToBuildFlag(std::string value)
if (value == "AutoLab" ) return BUILD_LABO; if (value == "AutoLab" ) return BUILD_LABO;
if (value == "PowerCaptor" ) return BUILD_PARA; if (value == "PowerCaptor" ) return BUILD_PARA;
if (value == "ExchangePost" ) return BUILD_INFO; if (value == "ExchangePost" ) return BUILD_INFO;
if (value == "Vault" ) return BUILD_SAFE;
if (value == "Destroyer" ) return BUILD_DESTROYER; if (value == "Destroyer" ) return BUILD_DESTROYER;
if (value == "FlatGround" ) return BUILD_GFLAT; if (value == "FlatGround" ) return BUILD_GFLAT;
if (value == "Flag" ) return BUILD_FLAG; if (value == "Flag" ) return BUILD_FLAG;

View File

@ -320,6 +320,7 @@ std::string PhaseToString(Phase phase)
if (phase == PHASE_APPERANCE) return "PHASE_APPERANCE"; if (phase == PHASE_APPERANCE) return "PHASE_APPERANCE";
if (phase == PHASE_MAIN_MENU) return "PHASE_MAIN_MENU"; if (phase == PHASE_MAIN_MENU) return "PHASE_MAIN_MENU";
if (phase == PHASE_LEVEL_LIST) return "PHASE_LEVEL_LIST"; if (phase == PHASE_LEVEL_LIST) return "PHASE_LEVEL_LIST";
if (phase == PHASE_MOD_LIST) return "PHASE_MOD_LIST";
if (phase == PHASE_SIMUL) return "PHASE_SIMUL"; if (phase == PHASE_SIMUL) return "PHASE_SIMUL";
if (phase == PHASE_SETUPd) return "PHASE_SETUPd"; if (phase == PHASE_SETUPd) return "PHASE_SETUPd";
if (phase == PHASE_SETUPg) return "PHASE_SETUPg"; if (phase == PHASE_SETUPg) return "PHASE_SETUPg";
@ -742,7 +743,7 @@ bool CRobotMain::ProcessEvent(Event &event)
} }
else else
{ {
m_sound->SetMusicVolume(100); m_sound->SetMusicVolume(MAXVOLUME*3/4);
} }
// Set audio volume // Set audio volume
if (GetConfigFile().GetIntProperty("Setup", "AudioVolume", volume)) if (GetConfigFile().GetIntProperty("Setup", "AudioVolume", volume))
@ -751,7 +752,7 @@ bool CRobotMain::ProcessEvent(Event &event)
} }
else else
{ {
m_sound->SetAudioVolume(100); m_sound->SetAudioVolume(MAXVOLUME);
} }
} }
@ -1360,7 +1361,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
{ {
CObject* object = GetSelect(); CObject* object = GetSelect();
if (object != nullptr && object->Implements(ObjectInterfaceType::Shielded)) if (object != nullptr && object->Implements(ObjectInterfaceType::Shielded))
dynamic_cast<CShieldedObject*>(object)->SetMagnifyDamage(dynamic_cast<CShieldedObject*>(object)->GetMagnifyDamage()*0.1f); dynamic_cast<CShieldedObject&>(*object).SetMagnifyDamage(dynamic_cast<CShieldedObject&>(*object).GetMagnifyDamage()*0.1f);
return; return;
} }
@ -1368,7 +1369,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
{ {
CObject* object = GetSelect(); CObject* object = GetSelect();
if (object != nullptr && object->Implements(ObjectInterfaceType::JetFlying)) if (object != nullptr && object->Implements(ObjectInterfaceType::JetFlying))
dynamic_cast<CJetFlyingObject*>(object)->SetRange(dynamic_cast<CJetFlyingObject*>(object)->GetRange()*10.0f); dynamic_cast<CJetFlyingObject&>(*object).SetRange(dynamic_cast<CJetFlyingObject&>(*object).GetRange()*10.0f);
return; return;
} }
@ -1393,16 +1394,16 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
{ {
if (object->Implements(ObjectInterfaceType::Powered)) if (object->Implements(ObjectInterfaceType::Powered))
{ {
CObject* power = dynamic_cast<CPoweredObject*>(object)->GetPower(); CObject* power = dynamic_cast<CPoweredObject&>(*object).GetPower();
if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer)) if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer))
dynamic_cast<CPowerContainerObject*>(power)->SetEnergyLevel(1.0f); dynamic_cast<CPowerContainerObject&>(*power).SetEnergyLevel(1.0f);
} }
if (object->Implements(ObjectInterfaceType::Shielded)) if (object->Implements(ObjectInterfaceType::Shielded))
dynamic_cast<CShieldedObject*>(object)->SetShield(1.0f); dynamic_cast<CShieldedObject&>(*object).SetShield(1.0f);
if (object->Implements(ObjectInterfaceType::JetFlying)) if (object->Implements(ObjectInterfaceType::JetFlying))
dynamic_cast<CJetFlyingObject*>(object)->SetReactorRange(1.0f); dynamic_cast<CJetFlyingObject&>(*object).SetReactorRange(1.0f);
} }
return; return;
} }
@ -1415,9 +1416,9 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
{ {
if (object->Implements(ObjectInterfaceType::Powered)) if (object->Implements(ObjectInterfaceType::Powered))
{ {
CObject* power = dynamic_cast<CPoweredObject*>(object)->GetPower(); CObject* power = dynamic_cast<CPoweredObject&>(*object).GetPower();
if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer)) if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer))
dynamic_cast<CPowerContainerObject*>(power)->SetEnergyLevel(1.0f); dynamic_cast<CPowerContainerObject&>(*power).SetEnergyLevel(1.0f);
} }
} }
return; return;
@ -1427,7 +1428,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
{ {
CObject* object = GetSelect(); CObject* object = GetSelect();
if (object != nullptr && object->Implements(ObjectInterfaceType::Shielded)) if (object != nullptr && object->Implements(ObjectInterfaceType::Shielded))
dynamic_cast<CShieldedObject*>(object)->SetShield(1.0f); dynamic_cast<CShieldedObject&>(*object).SetShield(1.0f);
return; return;
} }
@ -1437,7 +1438,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
if (object != nullptr) if (object != nullptr)
{ {
if (object->Implements(ObjectInterfaceType::JetFlying)) if (object->Implements(ObjectInterfaceType::JetFlying))
dynamic_cast<CJetFlyingObject*>(object)->SetReactorRange(1.0f); dynamic_cast<CJetFlyingObject&>(*object).SetReactorRange(1.0f);
} }
return; return;
} }
@ -1537,7 +1538,7 @@ void CRobotMain::StartDisplayInfo(int index, bool movie)
if (!m_editLock && movie && !m_movie->IsExist() && human) if (!m_editLock && movie && !m_movie->IsExist() && human)
{ {
assert(obj->Implements(ObjectInterfaceType::Movable)); assert(obj->Implements(ObjectInterfaceType::Movable));
if (dynamic_cast<CMovableObject*>(obj)->GetMotion()->GetAction() == -1) if (dynamic_cast<CMovableObject&>(*obj).GetMotion()->GetAction() == -1)
{ {
m_movieInfoIndex = index; m_movieInfoIndex = index;
m_movie->Start(MM_SATCOMopen, 2.5f); m_movie->Start(MM_SATCOMopen, 2.5f);
@ -1851,7 +1852,7 @@ CObject* CRobotMain::DeselectAll()
void CRobotMain::SelectOneObject(CObject* obj, bool displayError) void CRobotMain::SelectOneObject(CObject* obj, bool displayError)
{ {
assert(obj->Implements(ObjectInterfaceType::Controllable)); assert(obj->Implements(ObjectInterfaceType::Controllable));
dynamic_cast<CControllableObject*>(obj)->SetSelect(true, displayError); dynamic_cast<CControllableObject&>(*obj).SetSelect(true, displayError);
m_camera->SetControllingObject(obj); m_camera->SetControllingObject(obj);
ObjectType type = obj->GetType(); ObjectType type = obj->GetType();
@ -1890,7 +1891,7 @@ void CRobotMain::SelectOneObject(CObject* obj, bool displayError)
type == OBJECT_MOBILEdr || type == OBJECT_MOBILEdr ||
type == OBJECT_APOLLO2 ) type == OBJECT_APOLLO2 )
{ {
m_camera->SetType(dynamic_cast<CControllableObject*>(obj)->GetCameraType()); m_camera->SetType(dynamic_cast<CControllableObject&>(*obj).GetCameraType());
} }
else else
{ {
@ -1906,7 +1907,7 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError)
if (m_movieLock || m_editLock) return false; if (m_movieLock || m_editLock) return false;
if (m_movie->IsExist()) return false; if (m_movie->IsExist()) return false;
if (obj != nullptr && if (obj != nullptr &&
(!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast<CControllableObject*>(obj)->GetSelectable() || m_cheatSelectInsect))) return false; (!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast<CControllableObject&>(*obj).GetSelectable() || m_cheatSelectInsect))) return false;
if (m_missionType == MISSION_CODE_BATTLE && m_codeBattleStarted && m_codeBattleSpectator) if (m_missionType == MISSION_CODE_BATTLE && m_codeBattleStarted && m_codeBattleSpectator)
{ {
@ -1982,7 +1983,7 @@ CObject* CRobotMain::GetSelect()
for (CObject* obj : m_objMan->GetAllObjects()) for (CObject* obj : m_objMan->GetAllObjects())
{ {
if (!obj->Implements(ObjectInterfaceType::Controllable)) continue; if (!obj->Implements(ObjectInterfaceType::Controllable)) continue;
if (dynamic_cast<CControllableObject*>(obj)->GetSelect()) if (dynamic_cast<CControllableObject&>(*obj).GetSelect())
return obj; return obj;
} }
return nullptr; return nullptr;
@ -2000,7 +2001,7 @@ CObject* CRobotMain::DetectObject(Math::Point pos)
CObject* transporter = nullptr; CObject* transporter = nullptr;
if (obj->Implements(ObjectInterfaceType::Transportable)) if (obj->Implements(ObjectInterfaceType::Transportable))
transporter = dynamic_cast<CTransportableObject*>(obj)->GetTransporter(); transporter = dynamic_cast<CTransportableObject&>(*obj).GetTransporter();
if (transporter != nullptr && !transporter->GetDetectable()) continue; if (transporter != nullptr && !transporter->GetDetectable()) continue;
if (obj->GetProxyActivate()) continue; if (obj->GetProxyActivate()) continue;
@ -2008,14 +2009,14 @@ CObject* CRobotMain::DetectObject(Math::Point pos)
CObject* target = obj; CObject* target = obj;
if (obj->Implements(ObjectInterfaceType::PowerContainer) && obj->Implements(ObjectInterfaceType::Transportable)) if (obj->Implements(ObjectInterfaceType::PowerContainer) && obj->Implements(ObjectInterfaceType::Transportable))
{ {
target = dynamic_cast<CTransportableObject*>(obj)->GetTransporter(); // battery connected target = dynamic_cast<CTransportableObject&>(*obj).GetTransporter(); // battery connected
if (target == nullptr) if (target == nullptr)
{ {
target = obj; // standalone battery target = obj; // standalone battery
} }
else else
{ {
if (!target->Implements(ObjectInterfaceType::Powered) || dynamic_cast<CPoweredObject*>(target)->GetPower() != obj) if (!target->Implements(ObjectInterfaceType::Powered) || dynamic_cast<CPoweredObject&>(*target).GetPower() != obj)
{ {
// transported, but not in the power slot // transported, but not in the power slot
target = obj; target = obj;
@ -2045,7 +2046,7 @@ bool CRobotMain::DestroySelectedObject()
m_engine->GetPyroManager()->Create(Gfx::PT_FRAGT, obj); m_engine->GetPyroManager()->Create(Gfx::PT_FRAGT, obj);
dynamic_cast<CControllableObject*>(obj)->SetSelect(false); // deselects the object dynamic_cast<CControllableObject&>(*obj).SetSelect(false); // deselects the object
m_camera->SetType(Gfx::CAM_TYPE_EXPLO); m_camera->SetType(Gfx::CAM_TYPE_EXPLO);
DeselectAll(); DeselectAll();
RemoveFromSelectionHistory(obj); RemoveFromSelectionHistory(obj);
@ -2068,7 +2069,7 @@ void CRobotMain::HiliteClear()
for (CObject* obj : m_objMan->GetAllObjects()) for (CObject* obj : m_objMan->GetAllObjects())
{ {
if (!obj->Implements(ObjectInterfaceType::Controllable)) continue; if (!obj->Implements(ObjectInterfaceType::Controllable)) continue;
dynamic_cast<CControllableObject*>(obj)->SetHighlight(false); dynamic_cast<CControllableObject&>(*obj).SetHighlight(false);
} }
m_map->SetHighlight(nullptr); m_map->SetHighlight(nullptr);
m_short->SetHighlight(nullptr); m_short->SetHighlight(nullptr);
@ -2128,12 +2129,12 @@ void CRobotMain::HiliteObject(Math::Point pos)
} }
} }
if (obj->Implements(ObjectInterfaceType::Controllable) && (dynamic_cast<CControllableObject*>(obj)->GetSelectable() || m_cheatSelectInsect)) if (obj->Implements(ObjectInterfaceType::Controllable) && (dynamic_cast<CControllableObject&>(*obj).GetSelectable() || m_cheatSelectInsect))
{ {
if (dynamic_cast<CControllableObject*>(obj)->GetSelectable()) if (dynamic_cast<CControllableObject&>(*obj).GetSelectable())
{ {
// Don't highlight objects that would not be selectable without selectinsect // Don't highlight objects that would not be selectable without selectinsect
dynamic_cast<CControllableObject*>(obj)->SetHighlight(true); dynamic_cast<CControllableObject&>(*obj).SetHighlight(true);
} }
m_map->SetHighlight(obj); m_map->SetHighlight(obj);
m_short->SetHighlight(obj); m_short->SetHighlight(obj);
@ -2390,7 +2391,7 @@ bool CRobotMain::EventFrame(const Event &event)
if (obj->GetType() == OBJECT_TOTO) if (obj->GetType() == OBJECT_TOTO)
toto = obj; toto = obj;
else if (obj->Implements(ObjectInterfaceType::Interactive)) else if (obj->Implements(ObjectInterfaceType::Interactive))
dynamic_cast<CInteractiveObject*>(obj)->EventProcess(event); dynamic_cast<CInteractiveObject&>(*obj).EventProcess(event);
if ( obj->GetProxyActivate() ) // active if it is near? if ( obj->GetProxyActivate() ) // active if it is near?
{ {
@ -2413,7 +2414,7 @@ bool CRobotMain::EventFrame(const Event &event)
continue; continue;
if (obj->Implements(ObjectInterfaceType::Interactive)) if (obj->Implements(ObjectInterfaceType::Interactive))
dynamic_cast<CInteractiveObject*>(obj)->EventProcess(event); dynamic_cast<CInteractiveObject&>(*obj).EventProcess(event);
} }
m_engine->GetPyroManager()->EventProcess(event); m_engine->GetPyroManager()->EventProcess(event);
@ -2437,7 +2438,7 @@ bool CRobotMain::EventFrame(const Event &event)
// Advances toto following the camera, because its position depends on the camera. // Advances toto following the camera, because its position depends on the camera.
if (toto != nullptr) if (toto != nullptr)
dynamic_cast<CInteractiveObject*>(toto)->EventProcess(event); dynamic_cast<CInteractiveObject&>(*toto).EventProcess(event);
// NOTE: m_movieLock is set only after the first update of CAutoBase finishes // NOTE: m_movieLock is set only after the first update of CAutoBase finishes
@ -2461,6 +2462,7 @@ bool CRobotMain::EventFrame(const Event &event)
{ {
if (m_levelCategory == LevelCategory::Missions || if (m_levelCategory == LevelCategory::Missions ||
m_levelCategory == LevelCategory::FreeGame || m_levelCategory == LevelCategory::FreeGame ||
m_levelCategory == LevelCategory::GamePlus ||
m_levelCategory == LevelCategory::CustomLevels) m_levelCategory == LevelCategory::CustomLevels)
{ {
if (!IOIsBusy() && m_missionType != MISSION_CODE_BATTLE) if (!IOIsBusy() && m_missionType != MISSION_CODE_BATTLE)
@ -2670,7 +2672,7 @@ bool CRobotMain::EventObject(const Event &event)
{ {
if (obj->Implements(ObjectInterfaceType::Interactive)) if (obj->Implements(ObjectInterfaceType::Interactive))
{ {
dynamic_cast<CInteractiveObject*>(obj)->EventProcess(event); dynamic_cast<CInteractiveObject&>(*obj).EventProcess(event);
} }
} }
@ -2711,7 +2713,7 @@ void CRobotMain::ScenePerso()
obj->SetDrawFront(true); // draws the interface obj->SetDrawFront(true); // draws the interface
assert(obj->Implements(ObjectInterfaceType::Movable)); assert(obj->Implements(ObjectInterfaceType::Movable));
CMotionHuman* mh = static_cast<CMotionHuman*>(dynamic_cast<CMovableObject*>(obj)->GetMotion()); CMotionHuman* mh = static_cast<CMotionHuman*>(dynamic_cast<CMovableObject&>(*obj).GetMotion());
mh->StartDisplayPerso(); mh->StartDisplayPerso();
} }
} }
@ -3149,6 +3151,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
m_missionType = line->GetParam("type")->AsMissionType(MISSION_NORMAL); m_missionType = line->GetParam("type")->AsMissionType(MISSION_NORMAL);
m_globalMagnifyDamage = line->GetParam("magnifyDamage")->AsFloat(1.0f); m_globalMagnifyDamage = line->GetParam("magnifyDamage")->AsFloat(1.0f);
m_globalNuclearCapacity = line->GetParam("nuclearCapacity")->AsFloat(10.0f);
m_globalCellCapacity = line->GetParam("cellCapacity")->AsFloat(1.0f);
continue; continue;
} }
@ -3379,7 +3383,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
assert(m_controller->Implements(ObjectInterfaceType::ProgramStorage)); assert(m_controller->Implements(ObjectInterfaceType::ProgramStorage));
assert(m_controller->Implements(ObjectInterfaceType::Old)); assert(m_controller->Implements(ObjectInterfaceType::Old));
dynamic_cast<COldObject*>(m_controller)->SetCheckToken(false); dynamic_cast<COldObject&>(*m_controller).SetCheckToken(false);
if (line->GetParam("script")->IsDefined()) if (line->GetParam("script")->IsDefined())
{ {
@ -3387,7 +3391,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
Program* program = programStorage->AddProgram(); Program* program = programStorage->AddProgram();
programStorage->ReadProgram(program, line->GetParam("script")->AsPath("ai")); programStorage->ReadProgram(program, line->GetParam("script")->AsPath("ai"));
program->readOnly = true; program->readOnly = true;
dynamic_cast<CProgrammableObject*>(m_controller)->RunProgram(program); dynamic_cast<CProgrammableObject&>(*m_controller).RunProgram(program);
} }
continue; continue;
} }
@ -3412,7 +3416,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
if (m_fixScene && obj->GetType() == OBJECT_HUMAN) if (m_fixScene && obj->GetType() == OBJECT_HUMAN)
{ {
assert(obj->Implements(ObjectInterfaceType::Movable)); assert(obj->Implements(ObjectInterfaceType::Movable));
CMotion* motion = dynamic_cast<CMovableObject*>(obj)->GetMotion(); CMotion* motion = dynamic_cast<CMovableObject&>(*obj).GetMotion();
if (m_phase == PHASE_WIN ) motion->SetAction(MHS_WIN, 0.4f); if (m_phase == PHASE_WIN ) motion->SetAction(MHS_WIN, 0.4f);
if (m_phase == PHASE_LOST) motion->SetAction(MHS_LOST, 0.5f); if (m_phase == PHASE_LOST) motion->SetAction(MHS_LOST, 0.5f);
} }
@ -3427,7 +3431,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
{ {
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj); CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
if (obj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject*>(obj)->GetSelectable() && obj->GetType() != OBJECT_HUMAN) if (obj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject&>(*obj).GetSelectable() && obj->GetType() != OBJECT_HUMAN)
{ {
programStorage->SetProgramStorageIndex(rankObj); programStorage->SetProgramStorageIndex(rankObj);
} }
@ -3781,6 +3785,12 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
m_build |= BUILD_FLAG; m_build |= BUILD_FLAG;
} }
if (m_levelCategory == LevelCategory::GamePlus && !m_ui->GetPlusResearch() && !resetObject) // new game plus?
{
m_researchDone[0] |= m_playerProfile->GetFreeGameResearchUnlock();
m_build |= m_playerProfile->GetFreeGameBuildUnlock();
}
if (!resetObject) if (!resetObject)
{ {
m_short->SetMode(false); // vehicles? m_short->SetMode(false); // vehicles?
@ -3810,7 +3820,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
assert(obj->Implements(ObjectInterfaceType::Controllable)); assert(obj->Implements(ObjectInterfaceType::Controllable));
SelectObject(obj); SelectObject(obj);
m_camera->SetControllingObject(obj); m_camera->SetControllingObject(obj);
m_camera->SetType(dynamic_cast<CControllableObject*>(obj)->GetCameraType()); m_camera->SetType(dynamic_cast<CControllableObject&>(*obj).GetCameraType());
} }
} }
@ -3911,6 +3921,7 @@ void CRobotMain::ChangeColor()
m_phase != PHASE_SETUPps && m_phase != PHASE_SETUPps &&
m_phase != PHASE_SETUPcs && m_phase != PHASE_SETUPcs &&
m_phase != PHASE_SETUPss && m_phase != PHASE_SETUPss &&
m_phase != PHASE_MOD_LIST &&
m_phase != PHASE_WIN && m_phase != PHASE_WIN &&
m_phase != PHASE_LOST && m_phase != PHASE_LOST &&
m_phase != PHASE_APPERANCE ) return; m_phase != PHASE_APPERANCE ) return;
@ -4406,7 +4417,7 @@ void CRobotMain::StartShowLimit()
CObject* obj = GetSelect(); CObject* obj = GetSelect();
if (obj == nullptr) return; if (obj == nullptr) return;
if (!obj->Implements(ObjectInterfaceType::Ranged)) return; if (!obj->Implements(ObjectInterfaceType::Ranged)) return;
float range = dynamic_cast<CRangedObject*>(obj)->GetShowLimitRadius(); float range = dynamic_cast<CRangedObject&>(*obj).GetShowLimitRadius();
if (range == 0.0f) return; if (range == 0.0f) return;
SetShowLimit(0, Gfx::PARTILIMIT1, obj, obj->GetPosition(), range); SetShowLimit(0, Gfx::PARTILIMIT1, obj, obj->GetPosition(), range);
} }
@ -4576,8 +4587,8 @@ bool CRobotMain::IOIsBusy()
{ {
if (! obj->Implements(ObjectInterfaceType::TaskExecutor)) continue; if (! obj->Implements(ObjectInterfaceType::TaskExecutor)) continue;
if (obj->Implements(ObjectInterfaceType::Programmable) && dynamic_cast<CProgrammableObject*>(obj)->IsProgram()) continue; // TODO: I'm not sure if this is correct but this is how it worked earlier if (obj->Implements(ObjectInterfaceType::Programmable) && dynamic_cast<CProgrammableObject&>(*obj).IsProgram()) continue; // TODO: I'm not sure if this is correct but this is how it worked earlier
if (dynamic_cast<CTaskExecutorObject*>(obj)->IsForegroundTask()) return true; if (dynamic_cast<CTaskExecutorObject&>(*obj).IsForegroundTask()) return true;
} }
return false; return false;
} }
@ -4628,7 +4639,7 @@ void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std::
if (obj->Implements(ObjectInterfaceType::Programmable)) if (obj->Implements(ObjectInterfaceType::Programmable))
{ {
int run = dynamic_cast<CProgramStorageObject*>(obj)->GetProgramIndex(dynamic_cast<CProgrammableObject*>(obj)->GetCurrentProgram()); int run = dynamic_cast<CProgramStorageObject&>(*obj).GetProgramIndex(dynamic_cast<CProgrammableObject&>(*obj).GetCurrentProgram());
if (run != -1) if (run != -1)
{ {
line->AddParam("run", MakeUnique<CLevelParserParam>(run+1)); line->AddParam("run", MakeUnique<CLevelParserParam>(run+1));
@ -4703,11 +4714,11 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
{ {
if (obj->GetType() == OBJECT_TOTO) continue; if (obj->GetType() == OBJECT_TOTO) continue;
if (IsObjectBeingTransported(obj)) continue; if (IsObjectBeingTransported(obj)) continue;
if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(obj)->IsDying()) continue; if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject&>(*obj).IsDying()) continue;
if (obj->Implements(ObjectInterfaceType::Carrier)) if (obj->Implements(ObjectInterfaceType::Carrier))
{ {
CObject* cargo = dynamic_cast<CCarrierObject*>(obj)->GetCargo(); CObject* cargo = dynamic_cast<CCarrierObject&>(*obj).GetCargo();
if (cargo != nullptr) // object transported? if (cargo != nullptr) // object transported?
{ {
line = MakeUnique<CLevelParserLine>("CreateFret"); line = MakeUnique<CLevelParserLine>("CreateFret");
@ -4718,7 +4729,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
if (obj->Implements(ObjectInterfaceType::Powered)) if (obj->Implements(ObjectInterfaceType::Powered))
{ {
CObject* power = dynamic_cast<CPoweredObject*>(obj)->GetPower(); CObject* power = dynamic_cast<CPoweredObject&>(*obj).GetPower();
if (power != nullptr) // battery transported? if (power != nullptr) // battery transported?
{ {
line = MakeUnique<CLevelParserLine>("CreatePower"); line = MakeUnique<CLevelParserLine>("CreatePower");
@ -4757,7 +4768,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
{ {
if (obj->GetType() == OBJECT_TOTO) continue; if (obj->GetType() == OBJECT_TOTO) continue;
if (IsObjectBeingTransported(obj)) continue; if (IsObjectBeingTransported(obj)) continue;
if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(obj)->IsDying()) continue; if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject&>(*obj).IsDying()) continue;
if (!SaveFileStack(obj, ostr)) if (!SaveFileStack(obj, ostr))
{ {
@ -4908,7 +4919,7 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
{ {
assert(obj->Implements(ObjectInterfaceType::Carrier)); // TODO: exception? assert(obj->Implements(ObjectInterfaceType::Carrier)); // TODO: exception?
assert(obj->Implements(ObjectInterfaceType::Old)); assert(obj->Implements(ObjectInterfaceType::Old));
dynamic_cast<CCarrierObject*>(obj)->SetCargo(cargo); dynamic_cast<CCarrierObject&>(*obj).SetCargo(cargo);
auto task = MakeUnique<CTaskManip>(dynamic_cast<COldObject*>(obj)); auto task = MakeUnique<CTaskManip>(dynamic_cast<COldObject*>(obj));
task->Start(TMO_AUTO, TMA_GRAB); // holds the object! task->Start(TMO_AUTO, TMA_GRAB); // holds the object!
} }
@ -4916,9 +4927,9 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
if (power != nullptr) if (power != nullptr)
{ {
assert(obj->Implements(ObjectInterfaceType::Powered)); assert(obj->Implements(ObjectInterfaceType::Powered));
dynamic_cast<CPoweredObject*>(obj)->SetPower(power); dynamic_cast<CPoweredObject&>(*obj).SetPower(power);
assert(power->Implements(ObjectInterfaceType::Transportable)); assert(power->Implements(ObjectInterfaceType::Transportable));
dynamic_cast<CTransportableObject*>(power)->SetTransporter(obj); dynamic_cast<CTransportableObject&>(*power).SetTransporter(obj);
} }
cargo = nullptr; cargo = nullptr;
power = nullptr; power = nullptr;
@ -4950,7 +4961,7 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
{ {
if (obj->GetType() == OBJECT_TOTO) continue; if (obj->GetType() == OBJECT_TOTO) continue;
if (IsObjectBeingTransported(obj)) continue; if (IsObjectBeingTransported(obj)) continue;
if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(obj)->IsDying()) continue; if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject&>(*obj).IsDying()) continue;
if (!ReadFileStack(obj, istr)) if (!ReadFileStack(obj, istr))
{ {
@ -5307,7 +5318,7 @@ Error CRobotMain::CheckEndMission(bool frame)
if (m_base != nullptr && !m_endTakeImmediat) if (m_base != nullptr && !m_endTakeImmediat)
{ {
assert(m_base->Implements(ObjectInterfaceType::Controllable)); assert(m_base->Implements(ObjectInterfaceType::Controllable));
if(dynamic_cast<CControllableObject*>(m_base)->GetSelectable()) if(dynamic_cast<CControllableObject&>(*m_base).GetSelectable())
return ERR_MISSION_NOTERM; return ERR_MISSION_NOTERM;
} }
} }
@ -5347,6 +5358,16 @@ bool CRobotMain::GetTrainerPilot()
return m_cheatTrainerPilot; return m_cheatTrainerPilot;
} }
bool CRobotMain::GetPlusTrainer()
{
return m_ui->GetPlusTrainer();
}
bool CRobotMain::GetPlusExplorer()
{
return m_ui->GetPlusExplorer();
}
//! Indicates whether the scene is fixed, without interaction //! Indicates whether the scene is fixed, without interaction
bool CRobotMain::GetFixScene() bool CRobotMain::GetFixScene()
{ {
@ -5870,6 +5891,7 @@ bool CRobotMain::IsBuildingEnabled(ObjectType type)
if(type == OBJECT_NUCLEAR) return IsBuildingEnabled(BUILD_NUCLEAR); if(type == OBJECT_NUCLEAR) return IsBuildingEnabled(BUILD_NUCLEAR);
if(type == OBJECT_INFO) return IsBuildingEnabled(BUILD_INFO); if(type == OBJECT_INFO) return IsBuildingEnabled(BUILD_INFO);
if(type == OBJECT_PARA) return IsBuildingEnabled(BUILD_PARA); if(type == OBJECT_PARA) return IsBuildingEnabled(BUILD_PARA);
if(type == OBJECT_SAFE) return IsBuildingEnabled(BUILD_SAFE);
if(type == OBJECT_DESTROYER) return IsBuildingEnabled(BUILD_DESTROYER); if(type == OBJECT_DESTROYER) return IsBuildingEnabled(BUILD_DESTROYER);
return false; return false;
@ -5940,6 +5962,8 @@ Error CRobotMain::CanFactoryError(ObjectType type, int team)
if (type == OBJECT_MOBILEst && !IsResearchDone(RESEARCH_SUBM, team)) return ERR_BUILD_DISABLED; if (type == OBJECT_MOBILEst && !IsResearchDone(RESEARCH_SUBM, team)) return ERR_BUILD_DISABLED;
if (type == OBJECT_MOBILEtg && !IsResearchDone(RESEARCH_TARGET, team)) return ERR_BUILD_RESEARCH; if (type == OBJECT_MOBILEtg && !IsResearchDone(RESEARCH_TARGET, team)) return ERR_BUILD_RESEARCH;
if (tool == ToolType::Other && drive == DriveType::Other && type != OBJECT_MOBILEtg) return ERR_WRONG_OBJ;
return ERR_OK; return ERR_OK;
} }
@ -5976,6 +6000,16 @@ float CRobotMain::GetGlobalMagnifyDamage()
return m_globalMagnifyDamage; return m_globalMagnifyDamage;
} }
float CRobotMain::GetGlobalNuclearCapacity()
{
return m_globalNuclearCapacity;
}
float CRobotMain::GetGlobalCellCapacity()
{
return m_globalCellCapacity;
}
// Beginning of the effect when the instruction "detect" is used. // Beginning of the effect when the instruction "detect" is used.
void CRobotMain::StartDetectEffect(COldObject* object, CObject* target) void CRobotMain::StartDetectEffect(COldObject* object, CObject* target)

View File

@ -55,6 +55,7 @@ enum Phase
PHASE_APPERANCE, PHASE_APPERANCE,
PHASE_MAIN_MENU, PHASE_MAIN_MENU,
PHASE_LEVEL_LIST, PHASE_LEVEL_LIST,
PHASE_MOD_LIST,
PHASE_SIMUL, PHASE_SIMUL,
PHASE_SETUPd, PHASE_SETUPd,
PHASE_SETUPg, PHASE_SETUPg,
@ -266,6 +267,8 @@ public:
const std::string& GetScriptName(); const std::string& GetScriptName();
const std::string& GetScriptFile(); const std::string& GetScriptFile();
bool GetTrainerPilot(); bool GetTrainerPilot();
bool GetPlusTrainer();
bool GetPlusExplorer();
bool GetFixScene(); bool GetFixScene();
bool GetShowSoluce(); bool GetShowSoluce();
bool GetSceneSoluce(); bool GetSceneSoluce();
@ -467,6 +470,11 @@ public:
//! Returns global magnifyDamage setting //! Returns global magnifyDamage setting
float GetGlobalMagnifyDamage(); float GetGlobalMagnifyDamage();
//! Returns global NuclearCell capacity Setting
float GetGlobalNuclearCapacity();
//! Returns global PowerCell capacity setting
float GetGlobalCellCapacity();
void StartDetectEffect(COldObject* object, CObject* target); void StartDetectEffect(COldObject* object, CObject* target);
//! Enable crash sphere debug rendering //! Enable crash sphere debug rendering
@ -649,6 +657,9 @@ protected:
float m_globalMagnifyDamage = 0.0f; float m_globalMagnifyDamage = 0.0f;
float m_globalNuclearCapacity = 10.0f;
float m_globalCellCapacity = 1.0f;
bool m_exitAfterMission = false; bool m_exitAfterMission = false;
bool m_codeBattleInit = false; bool m_codeBattleInit = false;

View File

@ -82,7 +82,7 @@ bool CObjectCondition::CheckForObject(CObject* obj)
} }
else if (obj->Implements(ObjectInterfaceType::Powered)) else if (obj->Implements(ObjectInterfaceType::Powered))
{ {
CObject* powerObj = dynamic_cast<CPoweredObject*>(obj)->GetPower(); CObject* powerObj = dynamic_cast<CPoweredObject&>(*obj).GetPower();
if(powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer)) if(powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer))
{ {
power = dynamic_cast<CPowerContainerObject*>(powerObj); power = dynamic_cast<CPowerContainerObject*>(powerObj);
@ -98,7 +98,7 @@ bool CObjectCondition::CheckForObject(CObject* obj)
Math::Vector oPos; Math::Vector oPos;
if (IsObjectBeingTransported(obj)) if (IsObjectBeingTransported(obj))
oPos = dynamic_cast<CTransportableObject*>(obj)->GetTransporter()->GetPosition(); oPos = dynamic_cast<CTransportableObject&>(*obj).GetTransporter()->GetPosition();
else else
oPos = obj->GetPosition(); oPos = obj->GetPosition();
oPos.y = 0.0f; oPos.y = 0.0f;

View File

@ -169,7 +169,7 @@ begin:
else else
{ {
assert(pObj->Implements(ObjectInterfaceType::Controllable)); assert(pObj->Implements(ObjectInterfaceType::Controllable));
m_camera->SetType(dynamic_cast<CControllableObject*>(pObj)->GetCameraType()); m_camera->SetType(dynamic_cast<CControllableObject&>(*pObj).GetCameraType());
} }
m_main->StartMusic(); m_main->StartMusic();
@ -594,7 +594,7 @@ begin:
else else
{ {
assert(pObj->Implements(ObjectInterfaceType::Controllable)); assert(pObj->Implements(ObjectInterfaceType::Controllable));
m_camera->SetType(dynamic_cast<CControllableObject*>(pObj)->GetCameraType()); m_camera->SetType(dynamic_cast<CControllableObject&>(*pObj).GetCameraType());
} }
m_sound->Play(SOUND_BOUM, m_object->GetPosition()); m_sound->Play(SOUND_BOUM, m_object->GetPosition());
m_soundChannel = -1; m_soundChannel = -1;
@ -1124,7 +1124,7 @@ bool CAutoBase::Abort()
else else
{ {
assert(pObj->Implements(ObjectInterfaceType::Controllable)); assert(pObj->Implements(ObjectInterfaceType::Controllable));
m_camera->SetType(dynamic_cast<CControllableObject*>(pObj)->GetCameraType()); m_camera->SetType(dynamic_cast<CControllableObject&>(*pObj).GetCameraType());
} }
m_engine->SetFogStart(m_fogStart); m_engine->SetFogStart(m_fogStart);
@ -1248,7 +1248,7 @@ void CAutoBase::FreezeCargo(bool freeze)
m_cargoObjects.insert(obj); m_cargoObjects.insert(obj);
if ( obj->Implements(ObjectInterfaceType::Movable) ) if ( obj->Implements(ObjectInterfaceType::Movable) )
{ {
CPhysics* physics = dynamic_cast<CMovableObject*>(obj)->GetPhysics(); CPhysics* physics = dynamic_cast<CMovableObject&>(*obj).GetPhysics();
physics->SetFreeze(freeze); physics->SetFreeze(freeze);
} }
} }

View File

@ -176,7 +176,7 @@ bool CAutoDestroyer::EventProcess(const Event &event)
if ( scrap != nullptr ) if ( scrap != nullptr )
{ {
assert(scrap->Implements(ObjectInterfaceType::Destroyable)); assert(scrap->Implements(ObjectInterfaceType::Destroyable));
dynamic_cast<CDestroyableObject*>(scrap)->DestroyObject(DestructionType::Explosion); dynamic_cast<CDestroyableObject&>(*scrap).DestroyObject(DestructionType::Explosion);
} }
m_bExplo = true; m_bExplo = true;
} }

View File

@ -74,7 +74,7 @@ void CAutoEgg::DeleteObject(bool all)
alien->SetLock(false); alien->SetLock(false);
if (alien->Implements(ObjectInterfaceType::Programmable)) if (alien->Implements(ObjectInterfaceType::Programmable))
{ {
dynamic_cast<CProgrammableObject*>(alien)->SetActivity(true); // the insect is active dynamic_cast<CProgrammableObject&>(*alien).SetActivity(true); // the insect is active
} }
} }
else else
@ -123,7 +123,7 @@ void CAutoEgg::Init()
if (alien->Implements(ObjectInterfaceType::Programmable)) if (alien->Implements(ObjectInterfaceType::Programmable))
{ {
dynamic_cast<CProgrammableObject*>(alien)->SetActivity(false); dynamic_cast<CProgrammableObject&>(*alien).SetActivity(false);
} }
} }
@ -204,7 +204,7 @@ bool CAutoEgg::EventProcess(const Event &event)
if ( alien == nullptr ) return true; if ( alien == nullptr ) return true;
if (alien->Implements(ObjectInterfaceType::Programmable)) if (alien->Implements(ObjectInterfaceType::Programmable))
{ {
dynamic_cast<CProgrammableObject*>(alien)->SetActivity(false); dynamic_cast<CProgrammableObject&>(*alien).SetActivity(false);
} }
m_progress += event.rTime*m_speed; m_progress += event.rTime*m_speed;
@ -265,7 +265,7 @@ Error CAutoEgg::IsEnded()
alien->SetLock(false); alien->SetLock(false);
if(alien->Implements(ObjectInterfaceType::Programmable)) if(alien->Implements(ObjectInterfaceType::Programmable))
{ {
dynamic_cast<CProgrammableObject*>(alien)->SetActivity(true); // the insect is active dynamic_cast<CProgrammableObject&>(*alien).SetActivity(true); // the insect is active
} }
} }

View File

@ -397,7 +397,7 @@ bool CAutoFactory::EventProcess(const Event &event)
if ( vehicle != nullptr ) if ( vehicle != nullptr )
{ {
assert(vehicle->Implements(ObjectInterfaceType::Movable)); assert(vehicle->Implements(ObjectInterfaceType::Movable));
physics = dynamic_cast<CMovableObject*>(vehicle)->GetPhysics(); physics = dynamic_cast<CMovableObject&>(*vehicle).GetPhysics();
physics->SetFreeze(false); // can move physics->SetFreeze(false); // can move
vehicle->SetLock(false); // vehicle useable vehicle->SetLock(false); // vehicle useable
@ -408,7 +408,7 @@ bool CAutoFactory::EventProcess(const Event &event)
{ {
if (vehicle->Implements(ObjectInterfaceType::Programmable) && vehicle->Implements(ObjectInterfaceType::ProgramStorage)) if (vehicle->Implements(ObjectInterfaceType::Programmable) && vehicle->Implements(ObjectInterfaceType::ProgramStorage))
{ {
Program* program = dynamic_cast<CProgramStorageObject*>(vehicle)->AddProgram(); Program* program = dynamic_cast<CProgramStorageObject&>(*vehicle).AddProgram();
if (boost::regex_match(m_program, boost::regex("[A-Za-z0-9_]+"))) // Public function name? if (boost::regex_match(m_program, boost::regex("[A-Za-z0-9_]+"))) // Public function name?
{ {
@ -424,7 +424,7 @@ bool CAutoFactory::EventProcess(const Event &event)
program->script->SendScript(m_program.c_str()); program->script->SendScript(m_program.c_str());
} }
dynamic_cast<CProgrammableObject*>(vehicle)->RunProgram(program); dynamic_cast<CProgrammableObject&>(*vehicle).RunProgram(program);
} }
} }
} }
@ -670,7 +670,7 @@ bool CAutoFactory::CreateVehicle()
vehicle->SetLock(true); // not usable vehicle->SetLock(true); // not usable
assert(vehicle->Implements(ObjectInterfaceType::Movable)); assert(vehicle->Implements(ObjectInterfaceType::Movable));
CPhysics* physics = dynamic_cast<CMovableObject*>(vehicle)->GetPhysics(); CPhysics* physics = dynamic_cast<CMovableObject&>(*vehicle).GetPhysics();
physics->SetFreeze(true); // it doesn't move physics->SetFreeze(true); // it doesn't move
if (vehicle->Implements(ObjectInterfaceType::ProgramStorage)) if (vehicle->Implements(ObjectInterfaceType::ProgramStorage))

View File

@ -400,7 +400,7 @@ void CAutoNuclearPlant::CreatePower()
float powerLevel = 1.0f; float powerLevel = 1.0f;
CObject* power = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, OBJECT_ATOMIC, powerLevel); CObject* power = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, OBJECT_ATOMIC, powerLevel);
dynamic_cast<CTransportableObject*>(power)->SetTransporter(m_object); dynamic_cast<CTransportableObject&>(*power).SetTransporter(m_object);
power->SetPosition(Math::Vector(22.0f, 3.0f, 0.0f)); power->SetPosition(Math::Vector(22.0f, 3.0f, 0.0f));
m_object->SetPower(power); m_object->SetPower(power);
} }

View File

@ -269,7 +269,7 @@ void CAutoPowerCaptor::ChargeObject(float rTime)
if (obj->Implements(ObjectInterfaceType::Powered)) if (obj->Implements(ObjectInterfaceType::Powered))
{ {
CObject* power = dynamic_cast<CPoweredObject*>(obj)->GetPower(); CObject* power = dynamic_cast<CPoweredObject&>(*obj).GetPower();
if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) ) if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) )
{ {
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power); CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power);
@ -285,7 +285,7 @@ void CAutoPowerCaptor::ChargeObject(float rTime)
if (obj->Implements(ObjectInterfaceType::Carrier)) if (obj->Implements(ObjectInterfaceType::Carrier))
{ {
CObject* power = dynamic_cast<CCarrierObject*>(obj)->GetCargo(); CObject* power = dynamic_cast<CCarrierObject&>(*obj).GetCargo();
if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) ) if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) )
{ {
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power); CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power);

View File

@ -331,7 +331,7 @@ bool CAutoPowerPlant::EventProcess(const Event &event)
cargo->SetScale(1.0f); cargo->SetScale(1.0f);
cargo->SetLock(false); // usable battery cargo->SetLock(false); // usable battery
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object); dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
cargo->SetPosition(Math::Vector(0.0f, 3.0f, 0.0f)); cargo->SetPosition(Math::Vector(0.0f, 3.0f, 0.0f));
m_object->SetPower(cargo); m_object->SetPower(cargo);

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