Merge branch dev into dev-gameplus

pyro-refactor
Fiftytwo 2021-03-21 22:30:23 +01:00
commit 8647deafc8
110 changed files with 3028 additions and 525 deletions

View File

@ -13,16 +13,22 @@ jobs:
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 dependencies
run: sudo apt-get install -y --no-install-recommends clang-3.6 libtinyxml2.6.2v5
- run: mkdir -p /tmp/colobot-lint
- name: Download colobot-lint
uses: dawidd6/action-download-artifact@v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
repo: colobot/colobot-lint
branch: master
workflow: build.yml
workflow_conclusion: success
name: colobot-lint
path: /tmp/colobot-lint/archive
- name: Unpack colobot-lint
working-directory: /tmp/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/
@ -73,15 +79,12 @@ jobs:
with:
name: HTML results
path: build/html_report
- run: pip install requests
- name: Send linter results to GitHub
- name: Generate GitHub annotations JSON and process check result
shell: python
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
import os
import sys
import requests
import json
import xml.etree.ElementTree as ET
OVERALL_STABLE_RULES=[
@ -134,18 +137,6 @@ jobs:
"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
@ -154,6 +145,7 @@ jobs:
results = ET.parse('build/colobot_lint_report.xml')
annotations = []
stable_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'])
@ -168,38 +160,35 @@ jobs:
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({
annotation = {
'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()
annotations.append(annotation)
if 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
stable_annotations.append(annotation)
print('{}:{}: [{}] {}'.format(file_name, line_num, type, msg))
summary = 'colobot-lint found {} issues'.format(len(stable_annotations))
all_ok = len(stable_annotations) == 0
print('Conclusion: {}'.format(summary))
with open("build/annotations.json", "w") as f:
json.dump(annotations, f, indent=4)
with open("build/stable_annotations.json", "w") as f:
json.dump(stable_annotations, f, indent=4)
sys.exit(0 if all_ok else 1)
- name: Upload results (JSON)
uses: actions/upload-artifact@v2
with:
name: JSON results
path: |
build/annotations.json
build/stable_annotations.json
if: ${{ always() }}

View File

@ -0,0 +1,67 @@
name: Linter upload results
# Upload linter results after succesful linter run
# This is done in a separate workflow to safely use the read-write GitHub token
# See https://securitylab.github.com/research/github-actions-preventing-pwn-requests
on:
workflow_run:
workflows: ["Linter"]
types:
- completed
jobs:
lint_upload:
runs-on: ubuntu-16.04
steps:
- run: pip install requests
- name: Download linter results
uses: dawidd6/action-download-artifact@v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
workflow: lint.yml
run_id: ${{ github.event.workflow_run.id }}
name: JSON results
path: results
- name: Send linter results to GitHub
shell: python
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RUN_ID: ${{ github.event.workflow_run.id }}
run: |
import os
import json
import requests
# Load the results from the lint job artifact
with open("results/stable_annotations.json", "r") as f:
annotations = json.load(f)
summary = 'colobot-lint found {} issues'.format(len(annotations))
# 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['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.
# 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()

View File

@ -1,14 +1,21 @@
name: Verify pull request target
on: [pull_request]
on: [pull_request_target]
jobs:
check_pr_target:
runs-on: ubuntu-latest
steps:
- name: Wrong pull request target
run: echo "This pull request targets the master branch. Please edit the pull request to target dev." && exit 1
- name: Send comment if wrong pull request target
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
run: echo "This pull request targets the correct branch." && exit 0
if: github.base_ref != 'master'
run: echo "This pull request targets the correct branch." && exit 0

View File

@ -189,12 +189,12 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(NORMAL_CXX_FLAGS "/wd\"4244\" /wd\"4309\" /wd\"4800\" /wd\"4996\" /wd\"4351\" /EHsc") # disable some useless warnings
if(MSVC_STATIC)
set(RELEASE_CXX_FLAGS "/MT /Ox")
set(DEBUG_CXX_FLAGS "/MTd /ZI")
set(DEBUG_CXX_FLAGS "/MTd /Od /ZI")
else(MSVC_STATIC)
set(RELEASE_CXX_FLAGS "/MD /Ox")
set(DEBUG_CXX_FLAGS "/MDd /ZI")
set(DEBUG_CXX_FLAGS "/MDd /Od /ZI")
endif()
set(TEST_CXX_FLAGS "")
set(TEST_CXX_FLAGS "${DEBUG_CXX_FLAGS}")
add_definitions(-DNOEXCEPT= -DHAS_MSVC_EXCEPTION_BUG)
# Needed for Debug information (it's set to "No" by default for some reason)

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
* openSUSE: http://software.opensuse.org/download.html?project=games&package=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

View File

@ -87,6 +87,9 @@ msgstr ""
msgid "Missions+"
msgstr ""
msgid "Mods"
msgstr ""
msgid "Chapters:"
msgstr ""
@ -169,6 +172,23 @@ msgstr ""
msgid "This menu is for userlevels from mods, but you didn't install any"
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;)"
msgstr ""
@ -283,6 +303,42 @@ msgstr ""
msgid "%s: %d pts"
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"
msgstr ""
@ -319,6 +375,9 @@ msgstr ""
msgid "SatCom"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Change player\\Change player"
msgstr ""
@ -349,6 +408,24 @@ msgstr ""
msgid "Play\\Start mission!"
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"
msgstr ""

View File

@ -128,6 +128,9 @@ msgstr "Vzhled\\Upravte svůj vzhled"
msgid "Apply changes\\Activates the changed settings"
msgstr "Uložit změny\\Aktivovat změny nastavení"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing"
msgstr "Chybí vhodný konstruktor"
@ -374,6 +377,9 @@ msgstr "Změnit kameru\\Přepíná mezi kamerou na robotu a za robotem"
msgid "Change player\\Change player"
msgstr "Změnit hráče\\Změnit hráče"
msgid "Changes"
msgstr ""
msgid "Chapters:"
msgstr "Kapitoly:"
@ -443,6 +449,12 @@ msgstr "Kopírovat"
msgid "Copy (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"
msgstr "Současná mise uložena"
@ -476,6 +488,9 @@ msgstr "Vrtná věž"
msgid "Descend\\Reduces the power of the jet"
msgstr "Klesat\\Snížit tah tryskového motoru"
msgid "Description:"
msgstr ""
msgid "Destroy"
msgstr "Zbourat"
@ -488,6 +503,9 @@ msgstr "Drtič"
msgid "Device\\Driver and resolution settings"
msgstr "Obrazovka\\Nastavení grafické karty a rozlišení"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero"
msgstr "Dělení nulou"
@ -504,6 +522,9 @@ msgstr "Dveře blokuje robot nebo jiný objekt"
msgid "Down (\\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"
msgstr "Tužkobot"
@ -531,6 +552,9 @@ msgstr "Vejce"
msgid "Empty character constant"
msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing"
msgstr "Chybí konec bloku"
@ -757,6 +781,9 @@ msgstr "Infikováno virem; dočasně mimo provoz"
msgid "Information exchange post"
msgstr "Komunikační stanice"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop"
msgstr "Příkaz \"break\" mimo cyklus"
@ -910,6 +937,15 @@ msgstr "Mise+"
msgid "Missions\\Select mission"
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"
msgstr "Vodorovné převrácení posunu\\Při vodorovném posunu kamery myší pousouvat opačným směrem"
@ -958,6 +994,12 @@ msgstr "Další objekt\\Vybere následující objekt"
msgid "No"
msgstr "Ne"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil"
msgstr "Pod povrchem není zdroj energie"
@ -1078,6 +1120,9 @@ msgstr "Otevřít"
msgid "Open (Ctrl+O)"
msgstr "Otevřít (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing"
msgstr "Chybí levá složená závorka"
@ -1288,6 +1333,9 @@ msgstr "Červená vlajka"
msgid "Reflections on the buttons \\Shiny buttons"
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"
msgstr "Pozůstatky mise Apollo"
@ -1558,6 +1606,10 @@ msgstr "Filtrování textur\\Filtrování textur"
msgid "Textures"
msgstr "Textury"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended"
msgstr "Souboj skončil"
@ -1570,9 +1622,16 @@ msgstr "Funkce nevrátila žádnou hodnotu"
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;)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible"
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"
msgstr "Tato třída již existuje"
@ -1697,6 +1756,9 @@ msgstr "Jednotka"
msgid "Unknown Object"
msgstr "Neznámý objekt"
msgid "Unknown author"
msgstr ""
msgid "Unknown command"
msgstr "Neznámý příkaz"
@ -1709,6 +1771,9 @@ msgstr "Neznámá funkce"
msgid "Up (\\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)"
msgstr "Uranové ložisko (místo pro vrtnou věž)"
@ -1730,6 +1795,9 @@ msgstr "Proměnná nebyla nastavena"
msgid "Vault"
msgstr "Trezor"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr ""
@ -1748,6 +1816,9 @@ msgstr "Vosa byla smrtelně raněna"
msgid "Waste"
msgstr "Odpad"
msgid "Website"
msgstr ""
msgid "Wheeled builder"
msgstr ""
@ -1781,6 +1852,9 @@ msgstr "Létající detektor"
msgid "Withdraw shield (\\key action;)"
msgstr "Vypnout štít (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm"
msgstr "Červ"
@ -1931,6 +2005,9 @@ msgstr "\\Fialové vlajky"
msgid "\\Yellow flags"
msgstr "\\Žluté vlajky"
msgid "by"
msgstr ""
msgid "colobot.info"
msgstr "colobot.info"

View File

@ -129,6 +129,9 @@ msgstr "Aussehen\\Erscheinungsbild des Astronauten einstellen"
msgid "Apply changes\\Activates the changed settings"
msgstr "Änderungen anwenden\\Getätigte Einstellungen anwenden"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing"
msgstr "Es gibt keinen geeigneten Konstruktor"
@ -375,6 +378,9 @@ msgstr "Andere Kamera\\Sichtpunkt einstellen"
msgid "Change player\\Change player"
msgstr "Anderer Spieler\\Spielername ändern"
msgid "Changes"
msgstr ""
msgid "Chapters:"
msgstr "Liste der Kapitel:"
@ -444,6 +450,12 @@ msgstr "Kopieren"
msgid "Copy (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"
msgstr "Mission gespeichert"
@ -477,6 +489,9 @@ msgstr "Bohrturm"
msgid "Descend\\Reduces the power of the jet"
msgstr "Sinken\\Leistung des Triebwerks drosseln"
msgid "Description:"
msgstr ""
msgid "Destroy"
msgstr "Zerstören"
@ -489,6 +504,9 @@ msgstr "Einstampfer"
msgid "Device\\Driver and resolution settings"
msgstr "Bildschirm\\Driver und Bildschirmauflösung"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero"
msgstr "Division durch Null"
@ -505,6 +523,9 @@ msgstr "Die Türen werden von einem Gegenstand blockiert"
msgid "Down (\\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"
msgstr "Zeichner"
@ -532,6 +553,9 @@ msgstr "Ei"
msgid "Empty character constant"
msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing"
msgstr "Es fehlt eine geschlossene geschweifte Klammer \"}\" (Ende des Blocks)"
@ -759,6 +783,9 @@ msgstr "Von Virus infiziert, zeitweise außer Betrieb"
msgid "Information exchange post"
msgstr "Infoserver"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop"
msgstr "Anweisung \"break\" außerhalb einer Schleife"
@ -926,6 +953,15 @@ msgstr "Missionen+"
msgid "Missions\\Select mission"
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"
msgstr "Umkehr X\\Umkehr der Kameradrehung X-Achse"
@ -974,6 +1010,12 @@ msgstr "Nächstes auswählen\\Nächstes Objekt auswählen"
msgid "No"
msgstr "Nein"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil"
msgstr "Kein unterirdisches Energievorkommen"
@ -1094,6 +1136,9 @@ msgstr "Öffnen"
msgid "Open (Ctrl+O)"
msgstr "Öffnen (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing"
msgstr "Es fehlt eine offene geschweifte Klammer\"{\""
@ -1305,6 +1350,9 @@ msgstr "Rote Fahne"
msgid "Reflections on the buttons \\Shiny buttons"
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"
msgstr "Überreste einer Apollo-Mission"
@ -1575,6 +1623,10 @@ msgstr "Texturfilterung\\Texturfilterung"
msgid "Textures"
msgstr "Texturen"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended"
msgstr ""
@ -1587,9 +1639,16 @@ msgstr "Die Funktion hat kein Ergebnis zurückgegeben"
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)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible"
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"
msgstr "Diese Klasse gibt es schon"
@ -1714,6 +1773,9 @@ msgstr "Einheit"
msgid "Unknown Object"
msgstr "Das Objekt existiert nicht"
msgid "Unknown author"
msgstr ""
msgid "Unknown command"
msgstr "Befehl unbekannt"
@ -1726,6 +1788,9 @@ msgstr "Unbekannte Funktion"
msgid "Up (\\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)"
msgstr "Markierung für unterirdisches Platinvorkommen"
@ -1747,6 +1812,9 @@ msgstr "Der Wert dieser Variable wurde nicht definiert"
msgid "Vault"
msgstr "Bunker"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr ""
@ -1765,6 +1833,9 @@ msgstr "Wespe tödlich verwundet"
msgid "Waste"
msgstr "Abfall"
msgid "Website"
msgstr ""
msgid "Wheeled builder"
msgstr ""
@ -1798,6 +1869,9 @@ msgstr "Schnüffler"
msgid "Withdraw shield (\\key action;)"
msgstr "Schutzschild einholen (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm"
msgstr "Wurm"
@ -1946,6 +2020,9 @@ msgstr "\\Violette Fahne"
msgid "\\Yellow flags"
msgstr "\\Gelbe Fahne"
msgid "by"
msgstr ""
msgid "colobot.info"
msgstr "colobot.info"

View File

@ -128,6 +128,9 @@ msgstr "Aspect\\Choisir votre aspect"
msgid "Apply changes\\Activates the changed settings"
msgstr "Appliquer les changements\\Active les changements effectués"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing"
msgstr "Constructeur approprié manquant"
@ -377,6 +380,9 @@ msgstr "Changement de caméra\\Autre de point de vue"
msgid "Change player\\Change player"
msgstr "Autre joueur\\Choix du nom du joueur"
msgid "Changes"
msgstr ""
msgid "Chapters:"
msgstr "Liste des chapitres :"
@ -446,6 +452,12 @@ msgstr "Copier"
msgid "Copy (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"
msgstr "Enregistrement effectué"
@ -479,6 +491,9 @@ msgstr "Derrick"
msgid "Descend\\Reduces the power of the jet"
msgstr "Descendre\\Diminuer la puissance du réacteur"
msgid "Description:"
msgstr ""
msgid "Destroy"
msgstr "Détruire"
@ -491,6 +506,9 @@ msgstr "Destructeur"
msgid "Device\\Driver and resolution settings"
msgstr "Affichage\\Pilote et résolution d'affichage"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero"
msgstr "Division par zéro"
@ -507,6 +525,9 @@ msgstr "Portes bloquées par un robot ou un objet"
msgid "Down (\\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"
msgstr "Robot dessinateur"
@ -534,6 +555,9 @@ msgstr "Oeuf"
msgid "Empty character constant"
msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing"
msgstr "Il manque la fin du bloc"
@ -761,6 +785,9 @@ msgstr "Infecté par un virus; ne fonctionne plus temporairement"
msgid "Information exchange post"
msgstr "Station relais"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop"
msgstr "Instruction \"break\" en dehors d'une boucle"
@ -928,6 +955,15 @@ msgstr "Missions+"
msgid "Missions\\Select mission"
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"
msgstr "Inversion souris X\\Inversion de la rotation lorsque la souris touche un bord"
@ -976,6 +1012,12 @@ msgstr "Sélectionner l'objet suivant\\Sélectionner l'objet suivant"
msgid "No"
msgstr "Non"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil"
msgstr "Pas d'énergie en sous-sol"
@ -1096,6 +1138,9 @@ msgstr "Ouvrir"
msgid "Open (Ctrl+O)"
msgstr "Ouvrir (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing"
msgstr "Début d'un bloc attendu"
@ -1307,6 +1352,9 @@ msgstr "Drapeau rouge"
msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Reflets sur les boutons\\Boutons brillants"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission"
msgstr "Vestige d'une mission Apollo"
@ -1577,6 +1625,10 @@ msgstr "Filtrage de textures\\Filtrage de textures"
msgid "Textures"
msgstr "Textures"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended"
msgstr "La bataille est terminée"
@ -1589,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)"
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"
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"
msgstr "Cette classe existe déjà"
@ -1716,6 +1775,9 @@ msgstr "Unité"
msgid "Unknown Object"
msgstr "Objet inconnu"
msgid "Unknown author"
msgstr ""
msgid "Unknown command"
msgstr "Commande inconnue"
@ -1728,6 +1790,9 @@ msgstr "Routine inconnue"
msgid "Up (\\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)"
msgstr "Emplacement pour un derrick (minerai d'uranium)"
@ -1749,6 +1814,9 @@ msgstr "Variable non initialisée"
msgid "Vault"
msgstr "Coffre-fort"
msgid "Version"
msgstr ""
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."
@ -1767,6 +1835,9 @@ msgstr "Guêpe mortellement touchée"
msgid "Waste"
msgstr "Déchet"
msgid "Website"
msgstr ""
msgid "Wheeled builder"
msgstr ""
@ -1800,6 +1871,9 @@ msgstr "Robot renifleur volant"
msgid "Withdraw shield (\\key action;)"
msgstr "Refermer le bouclier (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm"
msgstr "Ver"
@ -1948,6 +2022,9 @@ msgstr "\\Drapeaux violets"
msgid "\\Yellow flags"
msgstr "\\Drapeaux jaunes"
msgid "by"
msgstr ""
msgid "colobot.info"
msgstr "colobot.info"

View File

@ -127,6 +127,9 @@ msgstr "Wygląd\\Wybierz swoją postać"
msgid "Apply changes\\Activates the changed settings"
msgstr "Zastosuj zmiany\\Aktywuje zmienione ustawienia"
msgid "Apply\\Apply the current mod configuration"
msgstr "Zastosuj\\Zastosuj obecną konfigurację modów"
msgid "Appropriate constructor missing"
msgstr "Brak odpowiedniego konstruktora"
@ -373,6 +376,9 @@ msgstr "Zmień kamerę\\Przełącza pomiędzy kamerą pokładową i śledzącą"
msgid "Change player\\Change player"
msgstr "Zmień gracza\\Zmień gracza"
msgid "Changes"
msgstr "Zmiany"
msgid "Chapters:"
msgstr "Rozdziały:"
@ -442,6 +448,12 @@ msgstr "Kopiuj"
msgid "Copy (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"
msgstr "Bieżąca misja zapisana"
@ -475,6 +487,9 @@ msgstr "Kopalnia"
msgid "Descend\\Reduces the power of the jet"
msgstr "W dół\\Zmniejsza moc silnika"
msgid "Description:"
msgstr "Opis:"
msgid "Destroy"
msgstr "Zniszcz"
@ -487,6 +502,9 @@ msgstr "Destroyer"
msgid "Device\\Driver and resolution settings"
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"
msgstr "Dzielenie przez zero"
@ -503,6 +521,9 @@ msgstr "Drzwi zablokowane przez robota lub inny obiekt"
msgid "Down (\\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"
msgstr "Robot rysownik"
@ -530,6 +551,9 @@ msgstr "Jajo"
msgid "Empty character constant"
msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr "Włącz\\Włącza zaznaczonego moda"
msgid "End of block missing"
msgstr "Brak końca bloku"
@ -756,6 +780,9 @@ msgstr "Zainfekowane wirusem, chwilowo niesprawne"
msgid "Information exchange post"
msgstr "Stacja przekaźnikowa informacji"
msgid "Information:"
msgstr "Informacje:"
msgid "Instruction \"break\" outside a loop"
msgstr "Polecenie \"break\" na zewnątrz pętli"
@ -909,6 +936,15 @@ msgstr "Misje+"
msgid "Missions\\Select mission"
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"
msgstr "Odwrócenie myszy X\\Odwrócenie kierunków przewijania w poziomie"
@ -957,6 +993,12 @@ msgstr "Następny obiekt\\Zaznacza następny obiekt"
msgid "No"
msgstr "Nie"
msgid "No changes."
msgstr "Brak zmian."
msgid "No description."
msgstr "Brak opisu."
msgid "No energy in the subsoil"
msgstr "Brak energii w ziemi"
@ -1077,6 +1119,9 @@ msgstr "Otwórz"
msgid "Open (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"
msgstr "Brak klamry otwierającej"
@ -1287,6 +1332,9 @@ msgstr "Czerwona flaga"
msgid "Reflections on the buttons \\Shiny buttons"
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"
msgstr "Pozostałości z misji Apollo"
@ -1557,6 +1605,10 @@ msgstr "Filtrowanie tekstur\\Filtrowanie tekstur"
msgid "Textures"
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"
msgstr "Bitwa zakończyła się"
@ -1569,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)"
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"
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"
msgstr "Taka klasa już istnieje"
@ -1696,6 +1755,9 @@ msgstr "Jednostka"
msgid "Unknown Object"
msgstr "Obiekt nieznany"
msgid "Unknown author"
msgstr "Nieznany autor"
msgid "Unknown command"
msgstr "Nieznane polecenie"
@ -1708,6 +1770,9 @@ msgstr "Funkcja nieznana"
msgid "Up (\\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)"
msgstr "Złoże uranu (miejsce na kopalnię)"
@ -1729,6 +1794,9 @@ msgstr "Zmienna nie została zainicjalizowana"
msgid "Vault"
msgstr "Skrytka"
msgid "Version"
msgstr "Wersja"
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"
@ -1747,6 +1815,9 @@ msgstr "Osa śmiertelnie raniona"
msgid "Waste"
msgstr "Odpady"
msgid "Website"
msgstr "Strona internetowa"
msgid "Wheeled builder"
msgstr ""
@ -1780,6 +1851,9 @@ msgstr "Szperacz latający"
msgid "Withdraw shield (\\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"
msgstr "Robal"
@ -1930,6 +2004,9 @@ msgstr "\\Fioletowe flagi"
msgid "\\Yellow flags"
msgstr "\\Żółte flagi"
msgid "by"
msgstr "autorstwa"
msgid "colobot.info"
msgstr "colobot.info"

View File

@ -125,6 +125,9 @@ msgstr "Aparência\\Escolha sua aparência"
msgid "Apply changes\\Activates the changed settings"
msgstr "Aplicar mudanças\\Ativa as configurações alteradas"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing"
msgstr "Construtor apropriado faltando"
@ -371,6 +374,9 @@ msgstr "Mudar câmera\\Alterna entre câmera incorporada e câmera seguidora"
msgid "Change player\\Change player"
msgstr "Mudar jogador\\Mudar jogador"
msgid "Changes"
msgstr ""
msgid "Chapters:"
msgstr "Capítulos:"
@ -441,6 +447,12 @@ msgstr "Copiar"
msgid "Copy (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"
msgstr "Missão atual salva"
@ -474,6 +486,9 @@ msgstr "Extrator"
msgid "Descend\\Reduces the power of the jet"
msgstr "Descer\\Diminui o poder do jato"
msgid "Description:"
msgstr ""
msgid "Destroy"
msgstr "Destruir"
@ -486,6 +501,9 @@ msgstr "Destruidor"
msgid "Device\\Driver and resolution settings"
msgstr "Dispositivo\\Configurações de driver e resolução"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero"
msgstr "Dividindo por zero"
@ -502,6 +520,9 @@ msgstr "Portas bloqueadas por um robô ou outro objeto"
msgid "Down (\\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"
msgstr "Robô cartoonista"
@ -529,6 +550,9 @@ msgstr "Ovo"
msgid "Empty character constant"
msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing"
msgstr "Fim do bloco ausente"
@ -756,6 +780,9 @@ msgstr "Infectado por vírus; temporariamento fora de serviço"
msgid "Information exchange post"
msgstr "Posto de troca de informação"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop"
msgstr "Intrução \"break\" fora de um laço"
@ -923,6 +950,15 @@ msgstr "Missões+"
msgid "Missions\\Select mission"
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"
msgstr "Inversão de mouse X\\Inverte a direção da rolagem no eixo X"
@ -971,6 +1007,12 @@ msgstr "Próximo objeto\\Selecionar o próximo objeto"
msgid "No"
msgstr "Não"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil"
msgstr "Nenhuma energia no subsolo"
@ -1091,6 +1133,9 @@ msgstr "Abrir"
msgid "Open (Ctrl+O)"
msgstr "Abrir (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing"
msgstr "Chave de abertura ausente"
@ -1302,6 +1347,9 @@ msgstr "Bandeira vermelha"
msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Reflexões nos botões\\Botões brilhantes"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission"
msgstr "Restos da missão Apollo"
@ -1572,6 +1620,10 @@ msgstr "Filtragem de textura\\Filtragem de textura"
msgid "Textures"
msgstr "Texturas"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended"
msgstr "A batalha acabou"
@ -1584,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)"
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"
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"
msgstr "Esta classe já existe"
@ -1711,6 +1770,9 @@ msgstr "Unidade"
msgid "Unknown Object"
msgstr "Objeto desconhecido"
msgid "Unknown author"
msgstr ""
msgid "Unknown command"
msgstr "Comando desconhecido"
@ -1723,6 +1785,9 @@ msgstr "Função desconhecida"
msgid "Up (\\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)"
msgstr "Depósito de urânio (local para extrator)"
@ -1744,6 +1809,9 @@ msgstr "Variável não inicializada"
msgid "Vault"
msgstr "Cofre"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr ""
@ -1762,6 +1830,9 @@ msgstr "Vespa fatalmente ferida"
msgid "Waste"
msgstr "Desperdício"
msgid "Website"
msgstr ""
msgid "Wheeled builder"
msgstr ""
@ -1795,6 +1866,9 @@ msgstr "Farejador alado"
msgid "Withdraw shield (\\key action;)"
msgstr "Retirar escudo (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm"
msgstr "Verme"
@ -1943,6 +2017,9 @@ msgstr "\\Bandeiras violetas"
msgid "\\Yellow flags"
msgstr "\\Bandeiras amarelas"
msgid "by"
msgstr ""
msgid "colobot.info"
msgstr "colobot.info"

View File

@ -127,6 +127,9 @@ msgstr "Внешность\\Настройка внешности"
msgid "Apply changes\\Activates the changed settings"
msgstr "Принять\\Принять изменения настроек"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing"
msgstr "Соответствующий конструктор отсутствует"
@ -378,6 +381,9 @@ msgstr "Изменить вид\\Переключение между борто
msgid "Change player\\Change player"
msgstr "Новый игрок\\Выберите имя для игрока"
msgid "Changes"
msgstr ""
msgid "Chapters:"
msgstr "Разделы:"
@ -449,6 +455,12 @@ msgstr "Копировать"
msgid "Copy (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"
msgstr "Текущая миссия сохранена"
@ -483,6 +495,9 @@ msgstr "Космический корабль"
msgid "Descend\\Reduces the power of the jet"
msgstr "Снижение и посадка\\Понижение мощности реактивного двигателя"
msgid "Description:"
msgstr ""
msgid "Destroy"
msgstr "Уничтожить"
@ -495,6 +510,9 @@ msgstr "Уничтожитель"
msgid "Device\\Driver and resolution settings"
msgstr "Устройство\\Драйвер и настройки разрешения"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero"
msgstr "Деление на ноль (запрещено!)"
@ -511,6 +529,9 @@ msgstr "Двери заблокированы роботом или другим
msgid "Down (\\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"
msgstr "Рисовальщик"
@ -538,6 +559,9 @@ msgstr "Яйцо"
msgid "Empty character constant"
msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing"
msgstr "Отсутствует конец блока"
@ -765,6 +789,9 @@ msgstr "Заражено вирусом. Временно вышел из стр
msgid "Information exchange post"
msgstr "Пост обмена информацией"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop"
msgstr "Инструкция \"break\" вне цикла"
@ -932,6 +959,15 @@ msgstr "Миссии+"
msgid "Missions\\Select mission"
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"
msgstr "Инверсия мыши по оси X\\Инверсия прокрутки по оси Х"
@ -982,6 +1018,12 @@ msgstr "Следующий объект\\Выбор следующего объ
msgid "No"
msgstr "Нет"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil"
msgstr "Под землей нет запасов энергии"
@ -1102,6 +1144,9 @@ msgstr "Открыть"
msgid "Open (Ctrl+O)"
msgstr "Открыть (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing"
msgstr "Открывающая скобка отсутствует"
@ -1314,6 +1359,9 @@ msgstr "Красный флаг"
msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Отражения на кнопках \\Блестящие кнопки"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission"
msgstr "Остатки миссии Аполлон"
@ -1588,6 +1636,10 @@ msgstr "Фильтрация текстур\\Фильтрация текстур
msgid "Textures"
msgstr "Текстуры"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended"
msgstr ""
@ -1600,9 +1652,16 @@ msgstr "Функция не возвратила значения"
msgid "The mission is not accomplished yet (press \\key help; for more details)"
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"
msgstr "Типы операндов несовместимы"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists"
msgstr "Этот класс уже существует"
@ -1727,6 +1786,9 @@ msgstr "Юнит"
msgid "Unknown Object"
msgstr "Неизвестный объект"
msgid "Unknown author"
msgstr ""
msgid "Unknown command"
msgstr "Неизвестная команда"
@ -1739,6 +1801,9 @@ msgstr "Неизвестная функция"
msgid "Up (\\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)"
msgstr "Запасы урана (место для буровой вышки)"
@ -1760,6 +1825,9 @@ msgstr "Переменная не инициализирована"
msgid "Vault"
msgstr "Хранилище"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr ""
@ -1778,6 +1846,9 @@ msgstr "Оса смертельно ранена"
msgid "Waste"
msgstr "Мусор"
msgid "Website"
msgstr ""
msgid "Wheeled builder"
msgstr ""
@ -1811,6 +1882,9 @@ msgstr "Летающий искатель"
msgid "Withdraw shield (\\key action;)"
msgstr "Снять щит (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm"
msgstr "Червь"
@ -1959,6 +2033,9 @@ msgstr "\\Фиолетовый флаг"
msgid "\\Yellow flags"
msgstr "\\Желтый флаг"
msgid "by"
msgstr ""
msgid "colobot.info"
msgstr "colobot.info"

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)
{
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;
}
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()"
bool rFloor(CBotVar* var, CBotVar* result, int& exception, void* user)
@ -209,7 +232,7 @@ void InitMathFunctions()
CBotProgram::AddFunction("sqrt", rSqrt, cOneFloat);
CBotProgram::AddFunction("pow", rPow, cTwoFloat);
CBotProgram::AddFunction("rand", rRand, cNull);
CBotProgram::AddFunction("abs", rAbs, cOneFloat);
CBotProgram::AddFunction("abs", rAbs, cAbs);
CBotProgram::AddFunction("floor", rFloor, cOneFloat);
CBotProgram::AddFunction("ceil", rCeil, cOneFloat);
CBotProgram::AddFunction("round", rRound, cOneFloat);

View File

@ -48,25 +48,30 @@ elseif(PLATFORM_WINDOWS)
if(${MSVC_STATIC})
if (${OPENAL_SOUND})
find_library(FLAC_LIBRARY NAMES flac.lib)
find_library(VORBIS_LIBRARY NAMES vorbis.lib)
find_library(VORBISENC_LIBRARY NAMES vorbisenc.lib)
find_library(OGG_LIBRARY NAMES ogg.lib)
find_library(FLAC_LIBRARY NAMES flac)
find_library(VORBIS_LIBRARY NAMES vorbis)
find_library(VORBISENC_LIBRARY NAMES vorbisenc)
find_library(OGG_LIBRARY NAMES ogg)
find_library(OPUS_LIBRARY NAMES opus)
set(OPENAL_MSVC_LIBS
${FLAC_LIBRARY}
${VORBIS_LIBRARY}
${VORBISENC_LIBRARY}
${OGG_LIBRARY}
${OPUS_LIBRARY}
)
endif()
find_library(BZ2_LIBRARY NAMES bz2.lib)
find_library(JPEG_LIBRARY NAMES jpeg.lib)
find_library(TIFF_LIBRARY NAMES tiff.lib)
find_library(LZMA_LIBRARY NAMES lzma.lib)
find_library(FREETYPE_LIBRARY NAMES freetype.lib)
find_library(ICONV_LIBRARY NAMES libiconv.lib)
find_library(CHARSET_LIBRARY NAMES libcharset.lib)
find_library(BZ2_LIBRARY NAMES bz2)
find_library(JPEG_LIBRARY NAMES jpeg)
find_library(TIFF_LIBRARY NAMES tiff)
find_library(LZMA_LIBRARY NAMES lzma)
find_library(FREETYPE_LIBRARY NAMES freetype)
find_library(ICONV_LIBRARY NAMES iconv)
find_library(CHARSET_LIBRARY NAMES charset)
find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon-static)
find_library(BROTLIENC_LIBRARY NAMES brotlienc-static)
find_library(BROTLIDEC_LIBRARY NAMES brotlidec-static)
set(MSVC_LIBS
${LIBINTL_LIBRARY}
${OPENAL_MSVC_LIBS}
@ -77,6 +82,9 @@ elseif(PLATFORM_WINDOWS)
${FREETYPE_LIBRARY}
${ICONV_LIBRARY}
${CHARSET_LIBRARY}
${BROTLICOMMON_LIBRARY}
${BROTLIENC_LIBRARY}
${BROTLIDEC_LIBRARY}
winmm.lib
dxguid.lib
imm32.lib
@ -145,6 +153,8 @@ set(BASE_SOURCES
app/controller.h
app/input.cpp
app/input.h
app/modman.cpp
app/modman.h
app/pathman.cpp
app/pathman.h
app/pausemanager.cpp
@ -418,6 +428,7 @@ set(BASE_SOURCES
object/object_interface_type.h
object/object_manager.cpp
object/object_manager.h
object/object_type.cpp
object/object_type.h
object/old_object.cpp
object/old_object.h
@ -567,6 +578,8 @@ set(BASE_SOURCES
ui/screen/screen_loading.h
ui/screen/screen_main_menu.cpp
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.h
ui/screen/screen_quit.cpp

View File

@ -21,6 +21,7 @@
#include "app/controller.h"
#include "app/input.h"
#include "app/modman.h"
#include "app/pathman.h"
#include "common/config_file.h"
@ -113,7 +114,8 @@ CApplication::CApplication(CSystemUtils* systemUtils)
m_private(MakeUnique<ApplicationPrivate>()),
m_configFile(MakeUnique<CConfigFile>()),
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_active = false;
@ -220,6 +222,11 @@ CSoundInterface* CApplication::GetSound()
return m_sound.get();
}
CModManager* CApplication::GetModManager()
{
return m_modManager.get();
}
void CApplication::LoadEnvironmentVariables()
{
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");
}
m_modManager->FindMods();
m_modManager->SaveMods();
m_modManager->MountAllMods();
// Create the sound instance.
#ifdef OPENAL_SOUND
if (!m_headless)
@ -538,6 +549,8 @@ bool CApplication::Create()
/* 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;
@ -682,8 +695,6 @@ bool CApplication::Create()
}
// Create the 3D engine
m_engine = MakeUnique<Gfx::CEngine>(this, m_systemUtils);
m_engine->SetDevice(m_device.get());
if (! m_engine->Create() )
@ -698,21 +709,7 @@ bool CApplication::Create()
// Create the robot application.
m_controller = MakeUnique<CController>();
CThread musicLoadThread([this]()
{
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();
StartLoadingMusic();
if (m_runSceneCategory == LevelCategory::Max)
m_controller->StartApp();
@ -726,6 +723,15 @@ bool CApplication::Create()
return true;
}
void CApplication::ReloadResources()
{
GetLogger()->Info("Reloading resources\n");
m_engine->ReloadAllTextures();
StartLoadingMusic();
m_controller->GetRobotMain()->UpdateCustomLevelList();
}
bool CApplication::CreateVideoSurface()
{
Uint32 videoFlags = SDL_WINDOW_OPENGL;
@ -844,24 +850,9 @@ bool CApplication::CreateVideoSurface()
int vsync = 0;
if (GetConfigFile().GetIntProperty("Setup", "VSync", vsync))
{
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);
TryToSetVSync();
vsync = m_engine->GetVSync();
GetConfigFile().SetIntProperty("Setup", "VSync", vsync);
GetLogger()->Info("Using Vsync: %s\n", (vsync == -1 ? "adaptive" : (vsync ? "true" : "false")));
@ -870,6 +861,32 @@ bool CApplication::CreateVideoSurface()
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)
{
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_SetWindowFullscreen(m_private->window, m_deviceConfig.fullScreen ? SDL_WINDOW_FULLSCREEN : 0);
int vsync = m_engine->GetVSync();
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);
TryToSetVSync();
m_device->ConfigChanged(m_deviceConfig);
@ -1060,11 +1058,9 @@ int CApplication::Run()
MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start
SystemTimeStamp *lastLoopTimeStamp = m_systemUtils->CreateTimeStamp();
SystemTimeStamp *previousTimeStamp = m_systemUtils->CreateTimeStamp();
SystemTimeStamp *currentTimeStamp = m_systemUtils->CreateTimeStamp();
SystemTimeStamp *interpolatedTimeStamp = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(lastLoopTimeStamp);
m_systemUtils->CopyTimeStamp(currentTimeStamp, lastLoopTimeStamp);
while (true)
{
@ -1168,11 +1164,11 @@ int CApplication::Run()
// If game speed is increased then we do extra ticks per loop iteration to improve physics accuracy.
int numTickSlices = static_cast<int>(GetSimulationSpeed());
if(numTickSlices < 1) numTickSlices = 1;
m_systemUtils->CopyTimeStamp(lastLoopTimeStamp, currentTimeStamp);
m_systemUtils->CopyTimeStamp(previousTimeStamp, m_curTimeStamp);
m_systemUtils->GetCurrentTimeStamp(currentTimeStamp);
for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++)
{
m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, lastLoopTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast<float>(numTickSlices));
m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast<float>(numTickSlices));
Event event = CreateUpdateEvent(interpolatedTimeStamp);
if (event.type != EVENT_NULL && m_controller != nullptr)
{
@ -1203,7 +1199,7 @@ int CApplication::Run()
}
end:
m_systemUtils->DestroyTimeStamp(lastLoopTimeStamp);
m_systemUtils->DestroyTimeStamp(previousTimeStamp);
m_systemUtils->DestroyTimeStamp(currentTimeStamp);
m_systemUtils->DestroyTimeStamp(interpolatedTimeStamp);
@ -1539,6 +1535,26 @@ void CApplication::InternalResumeSimulation()
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
{
return m_simulationSuspended;

View File

@ -42,6 +42,7 @@ class CEventQueue;
class CController;
class CSoundInterface;
class CInput;
class CModManager;
class CPathManager;
class CConfigFile;
class CSystemUtils;
@ -162,6 +163,8 @@ public:
CEventQueue* GetEventQueue();
//! Returns the sound subsystem
CSoundInterface* GetSound();
//! Returns the mod manager
CModManager* GetModManager();
public:
//! Loads some data from environment variables
@ -170,6 +173,8 @@ public:
ParseArgsStatus ParseArguments(int argc, char *argv[]);
//! Initializes the application
bool Create();
//! Reloads the application resources, e.g. mods
void ReloadResources();
//! Main event loop
int Run();
//! Returns the code to be returned at main() exit
@ -283,6 +288,9 @@ public:
protected:
//! Creates the window's SDL_Surface
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
Event ProcessSystemEvent();
@ -301,6 +309,9 @@ protected:
//! Internal procedure to reset time counters
void InternalResumeSimulation();
//! Loads music in a new thread
void StartLoadingMusic();
protected:
//! System utils instance
CSystemUtils* m_systemUtils;
@ -322,6 +333,8 @@ protected:
std::unique_ptr<CInput> m_input;
//! Path manager
std::unique_ptr<CPathManager> m_pathManager;
//! Mod manager
std::unique_ptr<CModManager> m_modManager;
//! Code to return at exit
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_langPath(systemUtils->GetLangPath())
, m_savePath(systemUtils->GetSaveDir())
, m_modAutoloadDir{}
, m_mods{}
, m_modSearchDirs{}
{
}
@ -65,16 +64,6 @@ void CPathManager::SetSavePath(const std::string &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()
{
return m_dataPath;
@ -131,40 +120,18 @@ void CPathManager::InitPaths()
GetLogger()->Info("Data path: %s\n", m_dataPath.c_str());
GetLogger()->Info("Save path: %s\n", m_savePath.c_str());
m_modAutoloadDir.push_back(m_dataPath + "/mods");
m_modAutoloadDir.push_back(m_savePath + "/mods");
m_modSearchDirs.push_back(m_dataPath + "/mods");
m_modSearchDirs.push_back(m_savePath + "/mods");
if (!m_modAutoloadDir.empty())
if (!m_modSearchDirs.empty())
{
GetLogger()->Info("Mod autoload dirs:\n");
for(const std::string& modAutoloadDir : m_modAutoloadDir)
GetLogger()->Info(" * %s\n", modAutoloadDir.c_str());
}
if (!m_mods.empty())
{
GetLogger()->Info("Mods:\n");
for(const std::string& modPath : m_mods)
GetLogger()->Info(" * %s\n", modPath.c_str());
GetLogger()->Info("Mod search dirs:\n");
for(const std::string& modSearchDir : m_modSearchDirs)
GetLogger()->Info(" * %s\n", modSearchDir.c_str());
}
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::AddLocation(m_savePath);
@ -174,7 +141,45 @@ void CPathManager::InitPaths()
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;
try

View File

@ -37,8 +37,6 @@ public:
void SetDataPath(const std::string &dataPath);
void SetLangPath(const std::string &langPath);
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& GetLangPath();
@ -49,9 +47,15 @@ public:
//! Loads configured paths
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:
//! Loads all mods from given directory
std::vector<std::string> FindModsInDir(const std::string &dir);
std::vector<std::string> FindModsInDir(const std::string &dir) const;
private:
//! Data path
@ -60,8 +64,8 @@ private:
std::string m_langPath;
//! Save path
std::string m_savePath;
//! Mod autoload paths
std::vector<std::string> m_modAutoloadDir;
//! Mod paths
//! Mod search paths
std::vector<std::string> m_modSearchDirs;
//! Additional mod paths
std::vector<std::string> m_mods;
};

View File

@ -26,9 +26,15 @@
#include "common/singleton.h"
#include "common/logger.h"
#include <boost/property_tree/ptree.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <sstream>
#include <vector>
#include <stdexcept>
/**
@ -100,6 +106,76 @@ public:
*/
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:
boost::property_tree::ptree m_propertyTree;
bool m_needsSave;

View File

@ -191,6 +191,7 @@ void InitializeEventTypeTexts()
EVENT_TYPE_TEXT[EVENT_INTERFACE_USER] = "EVENT_INTERFACE_USER";
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_LIST] = "EVENT_INTERFACE_LIST";
@ -277,6 +278,16 @@ void InitializeEventTypeTexts()
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_GLINTr] = "EVENT_INTERFACE_GLINTr";
EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTu] = "EVENT_INTERFACE_GLINTu";

View File

@ -226,6 +226,7 @@ enum EventType
EVENT_INTERFACE_USER = 413,
EVENT_INTERFACE_SATCOM = 414,
EVENT_INTERFACE_PLUS = 415,
EVENT_INTERFACE_MODS = 416,
EVENT_INTERFACE_CHAP = 420,
EVENT_INTERFACE_LIST = 421,
@ -316,6 +317,17 @@ enum EventType
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_GLINTr = 591,
EVENT_INTERFACE_GLINTu = 592,

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());
return false;
@ -95,6 +95,12 @@ std::vector<std::string> CResourceManager::GetLocations()
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)
{

View File

@ -36,11 +36,13 @@ public:
static std::string CleanPath(const std::string &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
static bool RemoveLocation(const std::string &location);
//! List all locations in the search path
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 std::string GetSaveLocation();

View File

@ -71,13 +71,14 @@ void InitializeRestext()
stringsText[RT_TITLE_MISSION] = TR("Missions");
stringsText[RT_TITLE_FREE] = TR("Free game");
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_NAME] = TR("Player's name");
stringsText[RT_TITLE_PERSO] = TR("Customize your appearance");
stringsText[RT_TITLE_WRITE] = TR("Save the current 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_PLANETS] = TR("Planets:");
@ -109,6 +110,11 @@ void InitializeRestext()
stringsText[RT_DIALOG_OK] = TR("OK");
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_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_COMPOK] = TR("Compilation ok (0 errors)");
@ -154,7 +160,18 @@ void InitializeRestext()
stringsText[RT_SCOREBOARD_RESULTS_TIME]= TR("Time: %s");
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");
@ -174,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_USER] = TR("Custom levels\\Levels from mods created by the users");
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_SETUP] = TR("Options\\Preferences");
stringsEvent[EVENT_INTERFACE_AGAIN] = TR("Restart\\Restart the mission from the beginning");
@ -184,6 +202,12 @@ void InitializeRestext()
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_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_SETUPg] = TR("Graphics\\Graphics settings");
stringsEvent[EVENT_INTERFACE_SETUPp] = TR("Game\\Game settings");

View File

@ -72,6 +72,7 @@ enum ResTextType
RT_TITLE_READ = 51,
RT_TITLE_USER = 52,
RT_TITLE_PLUS = 53,
RT_TITLE_MODS = 54,
RT_PLAY_CHAP_CHAPTERS = 60,
RT_PLAY_CHAP_PLANETS = 61,
@ -103,6 +104,11 @@ enum ResTextType
RT_DIALOG_OK = 110,
RT_DIALOG_NOUSRLVL_TITLE = 111,
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_COMPOK = 121,
@ -148,6 +154,18 @@ enum ResTextType
RT_SCOREBOARD_RESULTS_TIME= 232,
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
};

View File

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

View File

@ -145,6 +145,14 @@ public:
//! 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);
//! 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
virtual void Usleep(int usecs) = 0;

View File

@ -150,6 +150,28 @@ std::string CSystemUtilsLinux::GetEnvVar(const std::string& name)
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)
{
usleep(usec);

View File

@ -48,6 +48,9 @@ public:
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;
private:

View File

@ -119,6 +119,28 @@ std::string CSystemUtilsMacOSX::GetEnvVar(const std::string& str)
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)
{
usleep(usec);

View File

@ -38,6 +38,9 @@ public:
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;
private:

View File

@ -21,6 +21,7 @@
#include "common/logger.h"
#include <boost/filesystem.hpp>
#include <windows.h>
@ -152,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)
{
LARGE_INTEGER ft;

View File

@ -46,6 +46,9 @@ public:
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;
public:

View File

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

View File

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

View File

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

View File

@ -323,7 +323,7 @@ CObject* CLightning::SearchObject(Math::Vector pos)
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;
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())
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)
{

View File

@ -953,7 +953,7 @@ void CParticle::FrameParticle(float rTime)
m_particle[i].goal = m_particle[i].pos;
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);
@ -1156,7 +1156,7 @@ void CParticle::FrameParticle(float rTime)
{
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++;
@ -1222,7 +1222,7 @@ void CParticle::FrameParticle(float rTime)
m_particle[i].goal = m_particle[i].pos;
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);
if (m_lastTimeGunDel > 0.2f)
@ -1240,7 +1240,7 @@ void CParticle::FrameParticle(float rTime)
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;
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);
if (m_lastTimeGunDel > 0.2f)
@ -1285,7 +1285,7 @@ void CParticle::FrameParticle(float rTime)
{
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))
{
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 ++;
@ -2422,7 +2422,7 @@ void CParticle::FrameParticle(float rTime)
if (object != nullptr)
{
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);
}
}

View File

@ -129,7 +129,7 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
CObject* power = nullptr;
if (obj->Implements(ObjectInterfaceType::Powered))
power = dynamic_cast<CPoweredObject*>(obj)->GetPower();
power = dynamic_cast<CPoweredObject&>(*obj).GetPower();
if (power == nullptr)
{
@ -260,7 +260,7 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
m_sound->Play(SOUND_DEADw, m_pos);
}
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_engine->GetEyePt());
@ -278,10 +278,10 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
if ( m_type == PT_DEADG )
{
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));
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->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 )
{
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));
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->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 )
{
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);
}
@ -1413,7 +1413,7 @@ void CPyro::DeleteObject(bool primary, bool secondary)
if (m_object->Implements(ObjectInterfaceType::Transportable))
{
// 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->Implements(ObjectInterfaceType::Powered))
@ -1582,12 +1582,12 @@ void CPyro::ExploStart()
m_object->Simplify();
m_object->SetLock(true); // ruin not usable yet
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();
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_main->DeselectAll();
}
@ -1611,7 +1611,7 @@ void CPyro::ExploStart()
// TODO: temporary hack (hopefully)
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;
float weight;
@ -1658,9 +1658,9 @@ void CPyro::BurnStart()
m_object->Simplify();
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_main->DeselectAll();
}
@ -2198,7 +2198,7 @@ void CPyro::BurnProgress()
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?
sub->SetScaleY(1.0f - m_progress); // complete flattening
}
@ -2292,7 +2292,7 @@ CObject* CPyro::FallSearchBeeExplo()
if (obj->GetType() == OBJECT_MOBILErs)
{
float shieldRadius = dynamic_cast<CShielder*>(obj)->GetActiveShieldRadius();
float shieldRadius = dynamic_cast<CShielder&>(*obj).GetActiveShieldRadius();
if ( shieldRadius > 0.0f )
{
float distance = Math::Distance(oPos, bulletCrashSphere.sphere.pos);
@ -2360,12 +2360,12 @@ void CPyro::FallProgress(float rTime)
{
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
// TODO: implement "killer"?
dynamic_cast<CDestroyableObject*>(m_object)->DestroyObject(DestructionType::Explosion);
dynamic_cast<CDestroyableObject&>(*m_object).DestroyObject(DestructionType::Explosion);
}
}
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),
Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f, 0.0f, 0.0f);
@ -2376,7 +2376,7 @@ void CPyro::FallProgress(float rTime)
else
{
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
}
@ -2384,7 +2384,7 @@ void CPyro::FallProgress(float rTime)
{
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
// TODO: implement "killer"?
dynamic_cast<CDestroyableObject*>(m_object)->DestroyObject(DestructionType::Explosion);
dynamic_cast<CDestroyableObject&>(*m_object).DestroyObject(DestructionType::Explosion);
}
}
}

View File

@ -191,17 +191,32 @@ CText::~CText()
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)
{
m_error = std::string("TTF_Init error: ") + std::string(TTF_GetError());
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})
{
m_fonts[static_cast<Gfx::FontType>(type)] = MakeUnique<MultisizeFont>(fontLoader.GetFont(type));
@ -214,7 +229,10 @@ bool CText::Create()
FontType type = (*it).first;
CachedFont* cf = GetOrOpenFont(type, m_defaultSize);
if (cf == nullptr || cf->font == nullptr)
{
m_fonts = std::move(fonts);
return false;
}
}
return true;
@ -430,7 +448,7 @@ float CText::GetStringWidth(const std::string &text,
UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index);
int len = GetCharSizeAt(font, text, index);
if (len >= 1)
ch.c1 = text[index];
if (len >= 2)
@ -441,7 +459,7 @@ float CText::GetStringWidth(const std::string &text,
width += GetCharWidth(ch, font, size, width);
index += len;
fmtIndex++;
fmtIndex += len;
}
return width;
@ -565,7 +583,7 @@ int CText::Justify(const std::string &text, std::vector<FontMetaChar>::iterator
UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index);
int len = GetCharSizeAt(font, text, index);
if (len >= 1)
ch.c1 = text[index];
if (len >= 2)
@ -589,7 +607,7 @@ int CText::Justify(const std::string &text, std::vector<FontMetaChar>::iterator
}
index += len;
fmtIndex++;
fmtIndex += len;
}
return index;
@ -606,7 +624,7 @@ int CText::Justify(const std::string &text, FontType font, float size, float wid
{
UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index);
int len = GetCharSizeAt(font, text, index);
if (len >= 1)
ch.c1 = text[index];
if (len >= 2)
@ -648,12 +666,9 @@ int CText::Detect(const std::string &text, std::vector<FontMetaChar>::iterator f
if (format + fmtIndex != end)
font = static_cast<FontType>(*(format + fmtIndex) & FONT_MASK_FONT);
// TODO: if (font == FONT_BUTTON)
//if (font == FONT_BUTTON) continue;
UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index);
int len = GetCharSizeAt(font, text, index);
if (len >= 1)
ch.c1 = text[index];
if (len >= 2)
@ -670,7 +685,7 @@ int CText::Detect(const std::string &text, std::vector<FontMetaChar>::iterator f
pos += width;
index += len;
fmtIndex++;
fmtIndex += len;
}
return index;
@ -686,7 +701,7 @@ int CText::Detect(const std::string &text, FontType font, float size, float offs
{
UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index);
int len = GetCharSizeAt(font, text, index);
if (len >= 1)
ch.c1 = text[index];
if (len >= 2)
@ -898,16 +913,7 @@ void CText::StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &
if (format + index != end)
font = static_cast<FontType>(*(format + index) & FONT_MASK_FONT);
int len;
if(font == FONT_BUTTON)
{
len = 1;
}
else
{
len = StrUtils::Utf8CharSizeAt(text, index);
}
int len = GetCharSizeAt(font, text, index);
if (len >= 1)
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,
float size, Math::IntPoint pos, int width, int eol, Color color)
{

View File

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

View File

@ -388,6 +388,7 @@ bool CGL21Device::Create()
uni.modelMatrix = glGetUniformLocation(m_normalProgram, "uni_ModelMatrix");
uni.normalMatrix = glGetUniformLocation(m_normalProgram, "uni_NormalMatrix");
uni.shadowMatrix = glGetUniformLocation(m_normalProgram, "uni_ShadowMatrix");
uni.cameraPosition = glGetUniformLocation(m_normalProgram, "uni_CameraPosition");
uni.primaryTexture = glGetUniformLocation(m_normalProgram, "uni_PrimaryTexture");
uni.secondaryTexture = glGetUniformLocation(m_normalProgram, "uni_SecondaryTexture");
@ -408,6 +409,7 @@ bool CGL21Device::Create()
uni.fogColor = glGetUniformLocation(m_normalProgram, "uni_FogColor");
uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor");
uni.shadowTexelSize = glGetUniformLocation(m_normalProgram, "uni_ShadowTexelSize");
uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount");
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.normalMatrix, 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.secondaryTexture, 1);
@ -457,6 +460,7 @@ bool CGL21Device::Create()
glUniform4f(uni.fogColor, 0.8f, 0.8f, 0.8f, 1.0f);
glUniform1f(uni.shadowColor, 0.5f);
glUniform1f(uni.shadowTexelSize, 0.5f);
glUniform1i(uni.lightCount, 0);
}
@ -653,6 +657,7 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix)
else if (type == TRANSFORM_VIEW)
{
Math::Matrix scale;
Math::Vector cameraPosition;
scale.Set(3, 3, -1.0f);
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);
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)
{
@ -1439,6 +1451,7 @@ void CGL21Device::SetRenderState(RenderState state, bool enabled)
}
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);
return;

View File

@ -363,6 +363,7 @@ bool CGL33Device::Create()
uni.modelMatrix = glGetUniformLocation(m_normalProgram, "uni_ModelMatrix");
uni.normalMatrix = glGetUniformLocation(m_normalProgram, "uni_NormalMatrix");
uni.shadowMatrix = glGetUniformLocation(m_normalProgram, "uni_ShadowMatrix");
uni.cameraPosition = glGetUniformLocation(m_normalProgram, "uni_CameraPosition");
uni.primaryTexture = glGetUniformLocation(m_normalProgram, "uni_PrimaryTexture");
uni.secondaryTexture = glGetUniformLocation(m_normalProgram, "uni_SecondaryTexture");
@ -420,6 +421,7 @@ bool CGL33Device::Create()
glUniformMatrix4fv(uni.modelMatrix, 1, GL_FALSE, matrix.Array());
glUniformMatrix4fv(uni.normalMatrix, 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.secondaryTexture, 1);
@ -660,6 +662,7 @@ void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix)
else if (type == TRANSFORM_VIEW)
{
Math::Matrix scale;
Math::Vector cameraPosition;
scale.Set(3, 3, -1.0f);
m_viewMat = Math::MultiplyMatrices(scale, matrix);
@ -667,6 +670,13 @@ void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix)
m_combinedMatrixOutdated = true;
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)
{
@ -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,
texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels);
glGenerateMipmap(GL_TEXTURE_2D);
SDL_FreeSurface(texData.convertedSurface);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -90,7 +90,7 @@ bool CMainMovie::Start(MainMovieType type, float time)
}
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->SetType(Gfx::CAM_TYPE_SCRIPT);
@ -110,7 +110,7 @@ bool CMainMovie::Start(MainMovieType type, float time)
if ( pObj != nullptr )
{
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);
@ -132,7 +132,7 @@ bool CMainMovie::Stop()
if ( pObj != nullptr )
{
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/replace.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
CLevelParser::CLevelParser()
{
@ -172,13 +173,28 @@ void CLevelParser::Load()
boost::replace_all(line, "\t", " "); // replace tab by space
// ignore comments
std::size_t comment = line.find("//");
if (comment != std::string::npos)
line = line.substr(0, comment);
size_t pos = 0;
std::string linesuffix = line;
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);
std::size_t pos = line.find_first_of(" \t\n");
pos = line.find_first_of(" \t\n");
std::string command = line.substr(0, pos);
if (pos != std::string::npos)
{

View File

@ -320,6 +320,7 @@ std::string PhaseToString(Phase phase)
if (phase == PHASE_APPERANCE) return "PHASE_APPERANCE";
if (phase == PHASE_MAIN_MENU) return "PHASE_MAIN_MENU";
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_SETUPd) return "PHASE_SETUPd";
if (phase == PHASE_SETUPg) return "PHASE_SETUPg";
@ -1360,7 +1361,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
{
CObject* object = GetSelect();
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;
}
@ -1368,7 +1369,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
{
CObject* object = GetSelect();
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;
}
@ -1393,16 +1394,16 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
{
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))
dynamic_cast<CPowerContainerObject*>(power)->SetEnergyLevel(1.0f);
dynamic_cast<CPowerContainerObject&>(*power).SetEnergyLevel(1.0f);
}
if (object->Implements(ObjectInterfaceType::Shielded))
dynamic_cast<CShieldedObject*>(object)->SetShield(1.0f);
dynamic_cast<CShieldedObject&>(*object).SetShield(1.0f);
if (object->Implements(ObjectInterfaceType::JetFlying))
dynamic_cast<CJetFlyingObject*>(object)->SetReactorRange(1.0f);
dynamic_cast<CJetFlyingObject&>(*object).SetReactorRange(1.0f);
}
return;
}
@ -1415,9 +1416,9 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
{
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))
dynamic_cast<CPowerContainerObject*>(power)->SetEnergyLevel(1.0f);
dynamic_cast<CPowerContainerObject&>(*power).SetEnergyLevel(1.0f);
}
}
return;
@ -1427,7 +1428,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
{
CObject* object = GetSelect();
if (object != nullptr && object->Implements(ObjectInterfaceType::Shielded))
dynamic_cast<CShieldedObject*>(object)->SetShield(1.0f);
dynamic_cast<CShieldedObject&>(*object).SetShield(1.0f);
return;
}
@ -1437,7 +1438,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
if (object != nullptr)
{
if (object->Implements(ObjectInterfaceType::JetFlying))
dynamic_cast<CJetFlyingObject*>(object)->SetReactorRange(1.0f);
dynamic_cast<CJetFlyingObject&>(*object).SetReactorRange(1.0f);
}
return;
}
@ -1537,7 +1538,7 @@ void CRobotMain::StartDisplayInfo(int index, bool movie)
if (!m_editLock && movie && !m_movie->IsExist() && human)
{
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_movie->Start(MM_SATCOMopen, 2.5f);
@ -1851,7 +1852,7 @@ CObject* CRobotMain::DeselectAll()
void CRobotMain::SelectOneObject(CObject* obj, bool displayError)
{
assert(obj->Implements(ObjectInterfaceType::Controllable));
dynamic_cast<CControllableObject*>(obj)->SetSelect(true, displayError);
dynamic_cast<CControllableObject&>(*obj).SetSelect(true, displayError);
m_camera->SetControllingObject(obj);
ObjectType type = obj->GetType();
@ -1890,7 +1891,7 @@ void CRobotMain::SelectOneObject(CObject* obj, bool displayError)
type == OBJECT_MOBILEdr ||
type == OBJECT_APOLLO2 )
{
m_camera->SetType(dynamic_cast<CControllableObject*>(obj)->GetCameraType());
m_camera->SetType(dynamic_cast<CControllableObject&>(*obj).GetCameraType());
}
else
{
@ -1906,7 +1907,7 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError)
if (m_movieLock || m_editLock) return false;
if (m_movie->IsExist()) return false;
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)
{
@ -1982,7 +1983,7 @@ CObject* CRobotMain::GetSelect()
for (CObject* obj : m_objMan->GetAllObjects())
{
if (!obj->Implements(ObjectInterfaceType::Controllable)) continue;
if (dynamic_cast<CControllableObject*>(obj)->GetSelect())
if (dynamic_cast<CControllableObject&>(*obj).GetSelect())
return obj;
}
return nullptr;
@ -2000,7 +2001,7 @@ CObject* CRobotMain::DetectObject(Math::Point pos)
CObject* transporter = nullptr;
if (obj->Implements(ObjectInterfaceType::Transportable))
transporter = dynamic_cast<CTransportableObject*>(obj)->GetTransporter();
transporter = dynamic_cast<CTransportableObject&>(*obj).GetTransporter();
if (transporter != nullptr && !transporter->GetDetectable()) continue;
if (obj->GetProxyActivate()) continue;
@ -2008,14 +2009,14 @@ CObject* CRobotMain::DetectObject(Math::Point pos)
CObject* target = obj;
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)
{
target = obj; // standalone battery
}
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
target = obj;
@ -2045,7 +2046,7 @@ bool CRobotMain::DestroySelectedObject()
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);
DeselectAll();
RemoveFromSelectionHistory(obj);
@ -2068,7 +2069,7 @@ void CRobotMain::HiliteClear()
for (CObject* obj : m_objMan->GetAllObjects())
{
if (!obj->Implements(ObjectInterfaceType::Controllable)) continue;
dynamic_cast<CControllableObject*>(obj)->SetHighlight(false);
dynamic_cast<CControllableObject&>(*obj).SetHighlight(false);
}
m_map->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
dynamic_cast<CControllableObject*>(obj)->SetHighlight(true);
dynamic_cast<CControllableObject&>(*obj).SetHighlight(true);
}
m_map->SetHighlight(obj);
m_short->SetHighlight(obj);
@ -2390,7 +2391,7 @@ bool CRobotMain::EventFrame(const Event &event)
if (obj->GetType() == OBJECT_TOTO)
toto = obj;
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?
{
@ -2413,7 +2414,7 @@ bool CRobotMain::EventFrame(const Event &event)
continue;
if (obj->Implements(ObjectInterfaceType::Interactive))
dynamic_cast<CInteractiveObject*>(obj)->EventProcess(event);
dynamic_cast<CInteractiveObject&>(*obj).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.
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
@ -2671,7 +2672,7 @@ bool CRobotMain::EventObject(const Event &event)
{
if (obj->Implements(ObjectInterfaceType::Interactive))
{
dynamic_cast<CInteractiveObject*>(obj)->EventProcess(event);
dynamic_cast<CInteractiveObject&>(*obj).EventProcess(event);
}
}
@ -2712,7 +2713,7 @@ void CRobotMain::ScenePerso()
obj->SetDrawFront(true); // draws the interface
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();
}
}
@ -3150,6 +3151,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
m_missionType = line->GetParam("type")->AsMissionType(MISSION_NORMAL);
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;
}
@ -3380,7 +3383,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
assert(m_controller->Implements(ObjectInterfaceType::ProgramStorage));
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())
{
@ -3388,7 +3391,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
Program* program = programStorage->AddProgram();
programStorage->ReadProgram(program, line->GetParam("script")->AsPath("ai"));
program->readOnly = true;
dynamic_cast<CProgrammableObject*>(m_controller)->RunProgram(program);
dynamic_cast<CProgrammableObject&>(*m_controller).RunProgram(program);
}
continue;
}
@ -3413,7 +3416,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
if (m_fixScene && obj->GetType() == OBJECT_HUMAN)
{
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_LOST) motion->SetAction(MHS_LOST, 0.5f);
}
@ -3428,7 +3431,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
{
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);
}
@ -3817,7 +3820,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
assert(obj->Implements(ObjectInterfaceType::Controllable));
SelectObject(obj);
m_camera->SetControllingObject(obj);
m_camera->SetType(dynamic_cast<CControllableObject*>(obj)->GetCameraType());
m_camera->SetType(dynamic_cast<CControllableObject&>(*obj).GetCameraType());
}
}
@ -3918,6 +3921,7 @@ void CRobotMain::ChangeColor()
m_phase != PHASE_SETUPps &&
m_phase != PHASE_SETUPcs &&
m_phase != PHASE_SETUPss &&
m_phase != PHASE_MOD_LIST &&
m_phase != PHASE_WIN &&
m_phase != PHASE_LOST &&
m_phase != PHASE_APPERANCE ) return;
@ -4413,7 +4417,7 @@ void CRobotMain::StartShowLimit()
CObject* obj = GetSelect();
if (obj == nullptr) 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;
SetShowLimit(0, Gfx::PARTILIMIT1, obj, obj->GetPosition(), range);
}
@ -4583,8 +4587,8 @@ bool CRobotMain::IOIsBusy()
{
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 (dynamic_cast<CTaskExecutorObject*>(obj)->IsForegroundTask()) return true;
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;
}
return false;
}
@ -4635,7 +4639,7 @@ void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std::
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)
{
line->AddParam("run", MakeUnique<CLevelParserParam>(run+1));
@ -4710,11 +4714,11 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
{
if (obj->GetType() == OBJECT_TOTO) 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))
{
CObject* cargo = dynamic_cast<CCarrierObject*>(obj)->GetCargo();
CObject* cargo = dynamic_cast<CCarrierObject&>(*obj).GetCargo();
if (cargo != nullptr) // object transported?
{
line = MakeUnique<CLevelParserLine>("CreateFret");
@ -4725,7 +4729,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
if (obj->Implements(ObjectInterfaceType::Powered))
{
CObject* power = dynamic_cast<CPoweredObject*>(obj)->GetPower();
CObject* power = dynamic_cast<CPoweredObject&>(*obj).GetPower();
if (power != nullptr) // battery transported?
{
line = MakeUnique<CLevelParserLine>("CreatePower");
@ -4764,7 +4768,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
{
if (obj->GetType() == OBJECT_TOTO) 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))
{
@ -4915,7 +4919,7 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
{
assert(obj->Implements(ObjectInterfaceType::Carrier)); // TODO: exception?
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));
task->Start(TMO_AUTO, TMA_GRAB); // holds the object!
}
@ -4923,9 +4927,9 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
if (power != nullptr)
{
assert(obj->Implements(ObjectInterfaceType::Powered));
dynamic_cast<CPoweredObject*>(obj)->SetPower(power);
dynamic_cast<CPoweredObject&>(*obj).SetPower(power);
assert(power->Implements(ObjectInterfaceType::Transportable));
dynamic_cast<CTransportableObject*>(power)->SetTransporter(obj);
dynamic_cast<CTransportableObject&>(*power).SetTransporter(obj);
}
cargo = nullptr;
power = nullptr;
@ -4957,7 +4961,7 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
{
if (obj->GetType() == OBJECT_TOTO) 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))
{
@ -5314,7 +5318,7 @@ Error CRobotMain::CheckEndMission(bool frame)
if (m_base != nullptr && !m_endTakeImmediat)
{
assert(m_base->Implements(ObjectInterfaceType::Controllable));
if(dynamic_cast<CControllableObject*>(m_base)->GetSelectable())
if(dynamic_cast<CControllableObject&>(*m_base).GetSelectable())
return ERR_MISSION_NOTERM;
}
}
@ -5996,6 +6000,16 @@ float CRobotMain::GetGlobalMagnifyDamage()
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.
void CRobotMain::StartDetectEffect(COldObject* object, CObject* target)

View File

@ -55,6 +55,7 @@ enum Phase
PHASE_APPERANCE,
PHASE_MAIN_MENU,
PHASE_LEVEL_LIST,
PHASE_MOD_LIST,
PHASE_SIMUL,
PHASE_SETUPd,
PHASE_SETUPg,
@ -469,6 +470,11 @@ public:
//! Returns global magnifyDamage setting
float GetGlobalMagnifyDamage();
//! Returns global NuclearCell capacity Setting
float GetGlobalNuclearCapacity();
//! Returns global PowerCell capacity setting
float GetGlobalCellCapacity();
void StartDetectEffect(COldObject* object, CObject* target);
//! Enable crash sphere debug rendering
@ -651,6 +657,9 @@ protected:
float m_globalMagnifyDamage = 0.0f;
float m_globalNuclearCapacity = 10.0f;
float m_globalCellCapacity = 1.0f;
bool m_exitAfterMission = false;
bool m_codeBattleInit = false;

View File

@ -82,7 +82,7 @@ bool CObjectCondition::CheckForObject(CObject* obj)
}
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))
{
power = dynamic_cast<CPowerContainerObject*>(powerObj);
@ -98,7 +98,7 @@ bool CObjectCondition::CheckForObject(CObject* obj)
Math::Vector oPos;
if (IsObjectBeingTransported(obj))
oPos = dynamic_cast<CTransportableObject*>(obj)->GetTransporter()->GetPosition();
oPos = dynamic_cast<CTransportableObject&>(*obj).GetTransporter()->GetPosition();
else
oPos = obj->GetPosition();
oPos.y = 0.0f;

View File

@ -169,7 +169,7 @@ begin:
else
{
assert(pObj->Implements(ObjectInterfaceType::Controllable));
m_camera->SetType(dynamic_cast<CControllableObject*>(pObj)->GetCameraType());
m_camera->SetType(dynamic_cast<CControllableObject&>(*pObj).GetCameraType());
}
m_main->StartMusic();
@ -594,7 +594,7 @@ begin:
else
{
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_soundChannel = -1;
@ -1124,7 +1124,7 @@ bool CAutoBase::Abort()
else
{
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);
@ -1248,7 +1248,7 @@ void CAutoBase::FreezeCargo(bool freeze)
m_cargoObjects.insert(obj);
if ( obj->Implements(ObjectInterfaceType::Movable) )
{
CPhysics* physics = dynamic_cast<CMovableObject*>(obj)->GetPhysics();
CPhysics* physics = dynamic_cast<CMovableObject&>(*obj).GetPhysics();
physics->SetFreeze(freeze);
}
}

View File

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

View File

@ -74,7 +74,7 @@ void CAutoEgg::DeleteObject(bool all)
alien->SetLock(false);
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
@ -123,7 +123,7 @@ void CAutoEgg::Init()
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->Implements(ObjectInterfaceType::Programmable))
{
dynamic_cast<CProgrammableObject*>(alien)->SetActivity(false);
dynamic_cast<CProgrammableObject&>(*alien).SetActivity(false);
}
m_progress += event.rTime*m_speed;
@ -265,7 +265,7 @@ Error CAutoEgg::IsEnded()
alien->SetLock(false);
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 )
{
assert(vehicle->Implements(ObjectInterfaceType::Movable));
physics = dynamic_cast<CMovableObject*>(vehicle)->GetPhysics();
physics = dynamic_cast<CMovableObject&>(*vehicle).GetPhysics();
physics->SetFreeze(false); // can move
vehicle->SetLock(false); // vehicle useable
@ -408,7 +408,7 @@ bool CAutoFactory::EventProcess(const Event &event)
{
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?
{
@ -424,7 +424,7 @@ bool CAutoFactory::EventProcess(const Event &event)
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
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
if (vehicle->Implements(ObjectInterfaceType::ProgramStorage))

View File

@ -400,7 +400,7 @@ void CAutoNuclearPlant::CreatePower()
float powerLevel = 1.0f;
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));
m_object->SetPower(power);
}

View File

@ -269,7 +269,7 @@ void CAutoPowerCaptor::ChargeObject(float rTime)
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) )
{
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power);
@ -285,7 +285,7 @@ void CAutoPowerCaptor::ChargeObject(float rTime)
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) )
{
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power);

View File

@ -331,7 +331,7 @@ bool CAutoPowerPlant::EventProcess(const Event &event)
cargo->SetScale(1.0f);
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));
m_object->SetPower(cargo);

View File

@ -138,7 +138,7 @@ bool CAutoPowerStation::EventProcess(const Event &event)
{
if (vehicle->Implements(ObjectInterfaceType::Powered))
{
CObject* power = dynamic_cast<CPoweredObject*>(vehicle)->GetPower();
CObject* power = dynamic_cast<CPoweredObject&>(*vehicle).GetPower();
if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) )
{
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power);
@ -158,7 +158,7 @@ bool CAutoPowerStation::EventProcess(const Event &event)
if (vehicle->Implements(ObjectInterfaceType::Carrier))
{
CObject* power = dynamic_cast<CCarrierObject*>(vehicle)->GetCargo();
CObject* power = dynamic_cast<CCarrierObject&>(*vehicle).GetCargo();
if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) )
{
CPowerContainerObject* powerContainer = dynamic_cast<CPowerContainerObject*>(power);

View File

@ -148,7 +148,7 @@ bool CAutoRepair::EventProcess(const Event &event)
assert(vehicle->Implements(ObjectInterfaceType::Shielded));
if ( m_progress < 1.0f ||
(vehicle != nullptr && dynamic_cast<CShieldedObject*>(vehicle)->GetShield() < 1.0f) )
(vehicle != nullptr && dynamic_cast<CShieldedObject&>(*vehicle).GetShield() < 1.0f) )
{
if ( vehicle != nullptr )
{
@ -243,9 +243,9 @@ CObject* CAutoRepair::SearchVehicle()
{
if (obj == m_object) continue;
if ( !obj->Implements(ObjectInterfaceType::Shielded) ) continue;
if ( !dynamic_cast<CShieldedObject*>(obj)->IsRepairable() ) continue;
if ( !dynamic_cast<CShieldedObject&>(*obj).IsRepairable() ) continue;
if ( obj->Implements(ObjectInterfaceType::Movable) && !dynamic_cast<CMovableObject*>(obj)->GetPhysics()->GetLand() ) continue; // in flight?
if ( obj->Implements(ObjectInterfaceType::Movable) && !dynamic_cast<CMovableObject&>(*obj).GetPhysics()->GetLand() ) continue; // in flight?
Math::Vector oPos = obj->GetPosition();
float dist = Math::Distance(oPos, sPos);

View File

@ -289,7 +289,7 @@ CObject* CAutoTower::SearchTarget(Math::Vector &impact)
{
if ( obj->Implements(ObjectInterfaceType::Movable) )
{
CPhysics* physics = dynamic_cast<CMovableObject*>(obj)->GetPhysics();
CPhysics* physics = dynamic_cast<CMovableObject&>(*obj).GetPhysics();
float speed = fabs(physics->GetLinMotionX(MO_REASPEED));
if ( speed > 20.0f ) continue; // moving too fast?
}
@ -302,8 +302,7 @@ CObject* CAutoTower::SearchTarget(Math::Vector &impact)
if ( distance > TOWER_SCOPE ) continue; // too far
if ( distance < min )
{
min = distance;
best = obj;
min = distance; best = obj;
}
}
if ( best == nullptr ) return nullptr;
@ -327,7 +326,7 @@ Error CAutoTower::GetError()
return ERR_TOWER_POWER; // no battery
}
if ( dynamic_cast<CPowerContainerObject*>(m_object->GetPower())->GetEnergy() < ENERGY_FIRE )
if ( dynamic_cast<CPowerContainerObject&>(*m_object->GetPower()).GetEnergy() < ENERGY_FIRE )
{
return ERR_TOWER_ENERGY; // not enough energy
}

View File

@ -270,7 +270,7 @@ void CProgramStorageObjectImpl::LoadAllProgramsForLevel(CLevelParserLine* levelS
if (m_object->Implements(ObjectInterfaceType::Programmable) && i == run)
{
dynamic_cast<CProgrammableObject*>(m_object)->RunProgram(program);
dynamic_cast<CProgrammableObject&>(*m_object).RunProgram(program);
}
}
else
@ -327,7 +327,7 @@ void CProgramStorageObjectImpl::SaveAllProgramsForSavedScene(CLevelParserLine* l
}
if (m_programStorageIndex < 0) return;
if (!m_object->Implements(ObjectInterfaceType::Controllable) || !dynamic_cast<CControllableObject*>(m_object)->GetSelectable() || m_object->GetType() == OBJECT_HUMAN) return;
if (!m_object->Implements(ObjectInterfaceType::Controllable) || !dynamic_cast<CControllableObject&>(*m_object).GetSelectable() || m_object->GetType() == OBJECT_HUMAN) return;
GetLogger()->Debug("Saving saved scene programs to '%s/prog%.3d___.txt'\n", levelSource.c_str(), m_programStorageIndex);
for (unsigned int i = 0; i < m_program.size(); i++)
@ -379,7 +379,7 @@ void CProgramStorageObjectImpl::LoadAllProgramsForSavedScene(CLevelParserLine* l
if (m_object->Implements(ObjectInterfaceType::Programmable) && i == run)
{
dynamic_cast<CProgrammableObject*>(m_object)->RunProgram(program);
dynamic_cast<CProgrammableObject&>(*m_object).RunProgram(program);
}
}
}
@ -403,7 +403,7 @@ void CProgramStorageObjectImpl::LoadAllProgramsForSavedScene(CLevelParserLine* l
if (m_object->Implements(ObjectInterfaceType::Programmable) && i == run)
{
dynamic_cast<CProgrammableObject*>(m_object)->RunProgram(program);
dynamic_cast<CProgrammableObject&>(*m_object).RunProgram(program);
}
}
}

View File

@ -68,7 +68,7 @@ bool CProgrammableObjectImpl::EventProcess(const Event &event)
{
if (event.type == EVENT_FRAME)
{
if ( m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(m_object)->IsDying() && IsProgram() )
if ( m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject&>(*m_object).IsDying() && IsProgram() )
{
StopProgram();
}
@ -113,7 +113,7 @@ void CProgrammableObjectImpl::RunProgram(Program* program)
{
m_currentProgram = program; // start new program
m_object->UpdateInterface();
if (m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject*>(m_object)->GetTrainer())
if (m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject&>(*m_object).GetTrainer())
CRobotMain::GetInstancePointer()->StartMissionTimer();
}
}
@ -155,7 +155,7 @@ bool CProgrammableObjectImpl::ReadStack(std::istream &istr)
{
if (m_object->Implements(ObjectInterfaceType::ProgramStorage))
{
int count = static_cast<int>(dynamic_cast<CProgramStorageObject*>(m_object)->GetProgramCount());
int count = static_cast<int>(dynamic_cast<CProgramStorageObject&>(*m_object).GetProgramCount());
if (!(op < count))
{
GetLogger()->Info("Object program count: %i\n", count);
@ -163,7 +163,7 @@ bool CProgrammableObjectImpl::ReadStack(std::istream &istr)
return false;
}
m_currentProgram = dynamic_cast<CProgramStorageObject*>(m_object)->GetProgram(op);
m_currentProgram = dynamic_cast<CProgramStorageObject&>(*m_object).GetProgram(op);
if (!m_currentProgram->script->ReadStack(istr))
{
GetLogger()->Error("Restore state failed at program index: %i\n", op);
@ -203,7 +203,7 @@ bool CProgrammableObjectImpl::WriteStack(std::ostream &ostr)
op = -1;
if (m_object->Implements(ObjectInterfaceType::ProgramStorage))
{
op = dynamic_cast<CProgramStorageObject*>(m_object)->GetProgramIndex(m_currentProgram);
op = dynamic_cast<CProgramStorageObject&>(*m_object).GetProgramIndex(m_currentProgram);
}
if (!CBot::WriteShort(ostr, op)) return false;
@ -266,7 +266,7 @@ void CProgrammableObjectImpl::TraceRecordFrame()
assert(m_object->Implements(ObjectInterfaceType::TraceDrawing));
CTraceDrawingObject* traceDrawing = dynamic_cast<CTraceDrawingObject*>(m_object);
CPhysics* physics = dynamic_cast<CMovableObject*>(m_object)->GetPhysics();
CPhysics* physics = dynamic_cast<CMovableObject&>(*m_object).GetPhysics();
speed = physics->GetLinMotionX(MO_REASPEED);
if ( speed > 0.0f ) oper = TO_ADVANCE;
@ -353,7 +353,7 @@ void CProgrammableObjectImpl::TraceRecordStop()
buffer << "}\n";
assert(m_object->Implements(ObjectInterfaceType::ProgramStorage));
Program* prog = dynamic_cast<CProgramStorageObject*>(m_object)->AddProgram();
Program* prog = dynamic_cast<CProgramStorageObject&>(*m_object).AddProgram();
prog->script->SendScript(buffer.str().c_str());
}

View File

@ -51,5 +51,5 @@ public:
inline bool IsObjectCarryingCargo(CObject* obj)
{
return obj->Implements(ObjectInterfaceType::Carrier) &&
dynamic_cast<CCarrierObject*>(obj)->IsCarryingCargo();
dynamic_cast<CCarrierObject&>(*obj).IsCarryingCargo();
}

View File

@ -61,10 +61,10 @@ inline float GetObjectEnergy(CObject* object)
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))
{
energy = dynamic_cast<CPowerContainerObject*>(power)->GetEnergy();
energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy();
}
}
@ -77,10 +77,10 @@ inline float GetObjectEnergyLevel(CObject* object)
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))
{
energy = dynamic_cast<CPowerContainerObject*>(power)->GetEnergyLevel();
energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergyLevel();
}
}
@ -90,5 +90,5 @@ inline float GetObjectEnergyLevel(CObject* object)
inline bool ObjectHasPowerCell(CObject* object)
{
return object->Implements(ObjectInterfaceType::Powered) &&
dynamic_cast<CPoweredObject*>(object)->GetPower() != nullptr;
dynamic_cast<CPoweredObject&>(*object).GetPower() != nullptr;
}

View File

@ -54,5 +54,5 @@ public:
inline bool IsObjectBeingTransported(CObject* obj)
{
return obj->Implements(ObjectInterfaceType::Transportable) &&
dynamic_cast<CTransportableObject*>(obj)->IsBeingTransported();
dynamic_cast<CTransportableObject&>(*obj).IsBeingTransported();
}

View File

@ -429,7 +429,7 @@ bool CMotionAnt::EventFrame(const Event &event)
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
if ( dynamic_cast<CDestroyableObject*>(m_object)->GetDying() == DeathType::Burning ) // burning?
{
if ( dynamic_cast<CBaseAlien*>(m_object)->GetFixed() )
if ( dynamic_cast<CBaseAlien&>(*m_object).GetFixed() )
{
m_actionType = MAS_BURN;
}
@ -724,7 +724,7 @@ bool CMotionAnt::EventFrame(const Event &event)
if ( m_progress >= 1.0f )
{
SetAction(-1);
dynamic_cast<CBaseAlien*>(m_object)->SetFixed(false); // moving again
dynamic_cast<CBaseAlien&>(*m_object).SetFixed(false); // moving again
}
}
else

View File

@ -364,7 +364,7 @@ bool CMotionSpider::EventFrame(const Event &event)
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
if (dynamic_cast<CDestroyableObject*>(m_object)->GetDying() == DeathType::Burning ) // burning?
{
if ( dynamic_cast<CBaseAlien*>(m_object)->GetFixed() )
if ( dynamic_cast<CBaseAlien&>(*m_object).GetFixed() )
{
m_actionType = MSS_BURN;
}
@ -648,7 +648,7 @@ bool CMotionSpider::EventFrame(const Event &event)
if ( m_progress >= 1.0f )
{
SetAction(-1);
dynamic_cast<CBaseAlien*>(m_object)->SetFixed(false); // moving again
dynamic_cast<CBaseAlien&>(*m_object).SetFixed(false); // moving again
}
}
else

View File

@ -1075,7 +1075,7 @@ void CMotionVehicle::Create(Math::Vector pos, float angle, ObjectType type,
powerCell->SetPosition(powerCellPos);
powerCell->SetRotation(Math::Vector(0.0f, powerCellAngle, 0.0f));
dynamic_cast<CTransportableObject*>(powerCell)->SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*powerCell).SetTransporter(m_object);
assert(m_object->Implements(ObjectInterfaceType::Powered));
m_object->SetPower(powerCell);
}

View File

@ -142,6 +142,8 @@ CObject* CObjectManager::CreateObject(ObjectCreateParams params)
}
}
params.power = ClampPower(params.type,params.power);
assert(m_objects.find(params.id) == m_objects.end());
auto objectUPtr = m_objectFactory->CreateObject(params);
@ -163,10 +165,20 @@ CObject* CObjectManager::CreateObject(Math::Vector pos, float angle, ObjectType
params.angle = angle;
params.type = type;
params.power = power;
return CreateObject(params);
}
float CObjectManager::ClampPower(ObjectType type, float power)
{
float min = 0;
float max = 100;
if (type == OBJECT_POWER || type == OBJECT_ATOMIC)
{
max = 1;
}
return Math::Clamp(power, min, max);
}
std::vector<CObject*> CObjectManager::GetObjectsOfTeam(int team)
{
std::vector<CObject*> result;
@ -205,7 +217,7 @@ void CObjectManager::DestroyTeam(int team, DestructionType destructionType)
{
if (object->Implements(ObjectInterfaceType::Destroyable))
{
dynamic_cast<CDestroyableObject*>(object)->DestroyObject(destructionType);
dynamic_cast<CDestroyableObject&>(*object).DestroyObject(destructionType);
}
else
{
@ -351,7 +363,7 @@ std::vector<CObject*> CObjectManager::RadarAll(CObject* pThis, Math::Vector this
{
if ( pObj->Implements(ObjectInterfaceType::Movable) )
{
CPhysics* physics = dynamic_cast<CMovableObject*>(pObj)->GetPhysics();
CPhysics* physics = dynamic_cast<CMovableObject&>(*pObj).GetPhysics();
if ( physics != nullptr )
{
if ( !physics->GetLand() ) continue;
@ -361,7 +373,7 @@ std::vector<CObject*> CObjectManager::RadarAll(CObject* pThis, Math::Vector this
if ( filter_flying == FILTER_ONLYFLYING )
{
if ( !pObj->Implements(ObjectInterfaceType::Movable) ) continue;
CPhysics* physics = dynamic_cast<CMovableObject*>(pObj)->GetPhysics();
CPhysics* physics = dynamic_cast<CMovableObject&>(*pObj).GetPhysics();
if ( physics == nullptr ) continue;
if ( physics->GetLand() ) continue;
}

View File

@ -303,6 +303,8 @@ public:
//@}
private:
//! Prevents creation of overcharged power cells
float ClampPower(ObjectType type, float power);
void CleanRemovedObjectsIfNeeded();
private:

236
src/object/object_type.cpp Normal file
View File

@ -0,0 +1,236 @@
/*
* 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 "object/object_type.h"
#include <unordered_set>
bool IsValidObjectTypeId(int id)
{
static const std::unordered_set<int> validIds{
OBJECT_NULL,
OBJECT_PORTICO,
OBJECT_BASE,
OBJECT_DERRICK,
OBJECT_FACTORY,
OBJECT_STATION,
OBJECT_CONVERT,
OBJECT_REPAIR,
OBJECT_TOWER,
OBJECT_NEST,
OBJECT_RESEARCH,
OBJECT_RADAR,
OBJECT_ENERGY,
OBJECT_LABO,
OBJECT_NUCLEAR,
OBJECT_START,
OBJECT_END,
OBJECT_INFO,
OBJECT_PARA,
OBJECT_TARGET1,
OBJECT_TARGET2,
OBJECT_SAFE,
OBJECT_HUSTON,
OBJECT_DESTROYER,
OBJECT_STONE,
OBJECT_URANIUM,
OBJECT_METAL,
OBJECT_POWER,
OBJECT_ATOMIC,
OBJECT_BULLET,
OBJECT_BBOX,
OBJECT_TNT,
OBJECT_MARKPOWER,
OBJECT_MARKSTONE,
OBJECT_MARKURANIUM,
OBJECT_MARKKEYa,
OBJECT_MARKKEYb,
OBJECT_MARKKEYc,
OBJECT_MARKKEYd,
OBJECT_BOMB,
OBJECT_WINFIRE,
OBJECT_SHOW,
OBJECT_BAG,
OBJECT_PLANT0,
OBJECT_PLANT1,
OBJECT_PLANT2,
OBJECT_PLANT3,
OBJECT_PLANT4,
OBJECT_PLANT5,
OBJECT_PLANT6,
OBJECT_PLANT7,
OBJECT_PLANT8,
OBJECT_PLANT9,
OBJECT_PLANT10,
OBJECT_PLANT11,
OBJECT_PLANT12,
OBJECT_PLANT13,
OBJECT_PLANT14,
OBJECT_PLANT15,
OBJECT_PLANT16,
OBJECT_PLANT17,
OBJECT_PLANT18,
OBJECT_PLANT19,
OBJECT_TREE0,
OBJECT_TREE1,
OBJECT_TREE2,
OBJECT_TREE3,
OBJECT_TREE4,
OBJECT_TREE5,
OBJECT_MOBILEwt,
OBJECT_MOBILEtt,
OBJECT_MOBILEft,
OBJECT_MOBILEit,
OBJECT_MOBILErp,
OBJECT_MOBILEst,
OBJECT_MOBILEwa,
OBJECT_MOBILEta,
OBJECT_MOBILEfa,
OBJECT_MOBILEia,
OBJECT_MOBILEwc,
OBJECT_MOBILEtc,
OBJECT_MOBILEfc,
OBJECT_MOBILEic,
OBJECT_MOBILEwi,
OBJECT_MOBILEti,
OBJECT_MOBILEfi,
OBJECT_MOBILEii,
OBJECT_MOBILEws,
OBJECT_MOBILEts,
OBJECT_MOBILEfs,
OBJECT_MOBILEis,
OBJECT_MOBILErt,
OBJECT_MOBILErc,
OBJECT_MOBILErr,
OBJECT_MOBILErs,
OBJECT_MOBILEsa,
OBJECT_MOBILEtg,
OBJECT_MOBILEdr,
OBJECT_CONTROLLER,
OBJECT_MOBILEwb,
OBJECT_MOBILEtb,
OBJECT_MOBILEfb,
OBJECT_MOBILEib,
OBJECT_MOBILEpr,
OBJECT_WAYPOINT,
OBJECT_FLAGb,
OBJECT_FLAGr,
OBJECT_FLAGg,
OBJECT_FLAGy,
OBJECT_FLAGv,
OBJECT_KEYa,
OBJECT_KEYb,
OBJECT_KEYc,
OBJECT_KEYd,
OBJECT_HUMAN,
OBJECT_TOTO,
OBJECT_TECH,
OBJECT_BARRIER0,
OBJECT_BARRIER1,
OBJECT_BARRIER2,
OBJECT_BARRIER3,
OBJECT_BARRICADE0,
OBJECT_BARRICADE1,
OBJECT_MOTHER,
OBJECT_EGG,
OBJECT_ANT,
OBJECT_SPIDER,
OBJECT_BEE,
OBJECT_WORM,
OBJECT_RUINmobilew1,
OBJECT_RUINmobilew2,
OBJECT_RUINmobilet1,
OBJECT_RUINmobilet2,
OBJECT_RUINmobiler1,
OBJECT_RUINmobiler2,
OBJECT_RUINfactory,
OBJECT_RUINdoor,
OBJECT_RUINsupport,
OBJECT_RUINradar,
OBJECT_RUINconvert,
OBJECT_RUINbase,
OBJECT_RUINhead,
OBJECT_TEEN0,
OBJECT_TEEN1,
OBJECT_TEEN2,
OBJECT_TEEN3,
OBJECT_TEEN4,
OBJECT_TEEN5,
OBJECT_TEEN6,
OBJECT_TEEN7,
OBJECT_TEEN8,
OBJECT_TEEN9,
OBJECT_TEEN10,
OBJECT_TEEN11,
OBJECT_TEEN12,
OBJECT_TEEN13,
OBJECT_TEEN14,
OBJECT_TEEN15,
OBJECT_TEEN16,
OBJECT_TEEN17,
OBJECT_TEEN18,
OBJECT_TEEN19,
OBJECT_TEEN20,
OBJECT_TEEN21,
OBJECT_TEEN22,
OBJECT_TEEN23,
OBJECT_TEEN24,
OBJECT_TEEN25,
OBJECT_TEEN26,
OBJECT_TEEN27,
OBJECT_TEEN28,
OBJECT_TEEN29,
OBJECT_TEEN30,
OBJECT_TEEN31,
OBJECT_TEEN32,
OBJECT_TEEN33,
OBJECT_TEEN34,
OBJECT_TEEN35,
OBJECT_TEEN36,
OBJECT_TEEN37,
OBJECT_TEEN38,
OBJECT_TEEN39,
OBJECT_TEEN40,
OBJECT_TEEN41,
OBJECT_TEEN42,
OBJECT_TEEN43,
OBJECT_TEEN44,
OBJECT_QUARTZ0,
OBJECT_QUARTZ1,
OBJECT_QUARTZ2,
OBJECT_QUARTZ3,
OBJECT_ROOT0,
OBJECT_ROOT1,
OBJECT_ROOT2,
OBJECT_ROOT3,
OBJECT_ROOT4,
OBJECT_ROOT5,
OBJECT_MUSHROOM1,
OBJECT_MUSHROOM2,
OBJECT_APOLLO1,
OBJECT_APOLLO2,
OBJECT_APOLLO3,
OBJECT_APOLLO4,
OBJECT_APOLLO5,
OBJECT_HOME1,
OBJECT_MAX
};
return validIds.count(id);
}

View File

@ -248,3 +248,5 @@ struct ObjectTypeHash
return std::hash<int>()(t);
}
};
bool IsValidObjectTypeId(int id);

View File

@ -285,8 +285,8 @@ void COldObject::DeleteObject(bool bAll)
{
if (m_power->Implements(ObjectInterfaceType::Old))
{
dynamic_cast<COldObject*>(m_power)->SetTransporter(nullptr);
dynamic_cast<COldObject*>(m_power)->DeleteObject(bAll);
dynamic_cast<COldObject&>(*m_power).SetTransporter(nullptr);
dynamic_cast<COldObject&>(*m_power).DeleteObject(bAll);
}
m_power = nullptr;
}
@ -294,8 +294,8 @@ void COldObject::DeleteObject(bool bAll)
{
if (m_cargo->Implements(ObjectInterfaceType::Old))
{
dynamic_cast<COldObject*>(m_cargo)->SetTransporter(nullptr);
dynamic_cast<COldObject*>(m_cargo)->DeleteObject(bAll);
dynamic_cast<COldObject&>(*m_cargo).SetTransporter(nullptr);
dynamic_cast<COldObject&>(*m_cargo).DeleteObject(bAll);
}
m_cargo = nullptr;
}
@ -2505,7 +2505,7 @@ float COldObject::GetAbsTime()
float COldObject::GetCapacity()
{
return m_type == OBJECT_ATOMIC ? 10.0f : 1.0f;
return m_type == OBJECT_ATOMIC ? m_main->GetGlobalNuclearCapacity() : m_main->GetGlobalCellCapacity() ;
}
bool COldObject::IsRechargeable()

View File

@ -317,7 +317,7 @@ Error CTaskFire::Start(float delay)
CObject* power = dynamic_cast<CPoweredObject*>(m_object)->GetPower();
if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) return ERR_FIRE_ENERGY;
energy = dynamic_cast<CPowerContainerObject*>(power)->GetEnergy();
energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy();
if ( m_bOrganic ) fire = m_delay*ENERGY_FIREi;
else if ( m_bRay ) fire = m_delay*ENERGY_FIREr;
else fire = m_delay*ENERGY_FIRE;

View File

@ -60,7 +60,7 @@ bool CTaskFireAnt::EventProcess(const Event &event)
if ( event.type != EVENT_FRAME ) return true;
if ( m_bError ) return false;
if ( dynamic_cast<CBaseAlien*>(m_object)->GetFixed() ) // insect on its back?
if ( dynamic_cast<CBaseAlien&>(*m_object).GetFixed() ) // insect on its back?
{
m_bError = true;
return false;
@ -100,7 +100,7 @@ Error CTaskFireAnt::Start(Math::Vector impact)
if ( type != OBJECT_ANT ) return ERR_WRONG_BOT;
// Insect on its back?
if ( dynamic_cast<CBaseAlien*>(m_object)->GetFixed() ) return ERR_WRONG_BOT;
if ( dynamic_cast<CBaseAlien&>(*m_object).GetFixed() ) return ERR_WRONG_BOT;
m_physics->SetMotorSpeed(Math::Vector(0.0f, 0.0f, 0.0f));
@ -130,7 +130,7 @@ Error CTaskFireAnt::IsEnded()
if ( m_engine->GetPause() ) return ERR_CONTINUE;
if ( m_bError ) return ERR_STOP;
if ( dynamic_cast<CBaseAlien*>(m_object)->GetFixed() ) return ERR_STOP; // insect on its back?
if ( dynamic_cast<CBaseAlien&>(*m_object).GetFixed() ) return ERR_STOP; // insect on its back?
if ( m_phase == TFA_TURN ) // rotation ?
{

View File

@ -1202,7 +1202,7 @@ bool CTaskGoto::AdjustTarget(CObject* pObj, Math::Vector &pos, float &distance)
type == OBJECT_MOBILEdr )
{
assert(pObj->Implements(ObjectInterfaceType::Powered));
pos = dynamic_cast<CPoweredObject*>(pObj)->GetPowerPosition();
pos = dynamic_cast<CPoweredObject&>(*pObj).GetPowerPosition();
pos.x -= TAKE_DIST+TAKE_DIST_OTHER+distance;
mat = pObj->GetWorldMatrix(0);
pos = Transform(*mat, pos);

View File

@ -304,8 +304,8 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
assert(other->Implements(ObjectInterfaceType::Transportable));
m_object->SetCargo(other); // takes the ball
dynamic_cast<CTransportableObject*>(other)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(other)->SetTransporterPart(0); // taken with the base
dynamic_cast<CTransportableObject&>(*other).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*other).SetTransporterPart(0); // taken with the base
other->SetPosition(Math::Vector(0.0f, -3.0f, 0.0f));
}
else
@ -314,7 +314,7 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
assert(other->Implements(ObjectInterfaceType::Transportable));
m_object->SetCargo(nullptr); // lick the ball
dynamic_cast<CTransportableObject*>(other)->SetTransporter(nullptr);
dynamic_cast<CTransportableObject&>(*other).SetTransporter(nullptr);
pos = m_object->GetPosition();
pos.y -= 3.0f;
other->SetPosition(pos);
@ -903,7 +903,7 @@ CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos,
ObjectType type = pObj->GetType();
if ( !pObj->Implements(ObjectInterfaceType::Powered) ) continue;
CObject* power = dynamic_cast<CPoweredObject*>(pObj)->GetPower();
CObject* power = dynamic_cast<CPoweredObject&>(*pObj).GetPower();
if (power != nullptr)
{
if (power->GetLock()) continue;
@ -911,7 +911,7 @@ CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos,
}
mat = pObj->GetWorldMatrix(0);
Math::Vector oPos = Transform(*mat, dynamic_cast<CPoweredObject*>(pObj)->GetPowerPosition());
Math::Vector oPos = Transform(*mat, dynamic_cast<CPoweredObject&>(*pObj).GetPowerPosition());
oAngle = pObj->GetRotationY();
if ( type == OBJECT_TOWER ||
@ -946,7 +946,7 @@ CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos,
angle = Math::RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
if ( Math::TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
{
Math::Vector powerPos = dynamic_cast<CPoweredObject*>(pObj)->GetPowerPosition();
Math::Vector powerPos = dynamic_cast<CPoweredObject&>(*pObj).GetPowerPosition();
height = powerPos.y;
pos = oPos;
return pObj;
@ -974,8 +974,8 @@ bool CTaskManip::TransporterTakeObject()
if ( m_object->GetType() == OBJECT_HUMAN ||
m_object->GetType() == OBJECT_TECH )
{
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(4); // takes with the hand
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(4); // takes with the hand
cargo->SetPosition(Math::Vector(1.7f, -0.5f, 1.1f));
cargo->SetRotationY(0.1f);
@ -984,8 +984,8 @@ bool CTaskManip::TransporterTakeObject()
}
else if ( m_bSubm )
{
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(2); // takes with the right claw
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(2); // takes with the right claw
Math::Vector pos = Math::Vector(1.1f, -1.0f, 1.0f); // relative
cargo->SetPosition(pos);
@ -995,8 +995,8 @@ bool CTaskManip::TransporterTakeObject()
}
else
{
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(3); // takes with the hand
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(3); // takes with the hand
Math::Vector pos = Math::Vector(4.7f, 0.0f, 0.0f); // relative to the hand (lem4)
cargo->SetPosition(pos);
@ -1020,8 +1020,8 @@ bool CTaskManip::TransporterTakeObject()
if ( m_bSubm )
{
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(2); // takes with the right claw
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(2); // takes with the right claw
pos = Math::Vector(1.1f, -1.0f, 1.0f); // relative
cargo->SetPosition(pos);
@ -1031,8 +1031,8 @@ bool CTaskManip::TransporterTakeObject()
}
else
{
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(3); // takes with the hand
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(3); // takes with the hand
pos = Math::Vector(4.7f, 0.0f, 0.0f); // relative to the hand (lem4)
cargo->SetPosition(pos);
@ -1054,8 +1054,8 @@ bool CTaskManip::TransporterTakeObject()
m_cargoType = cargo->GetType();
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(3); // takes with the hand
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(3); // takes with the hand
pos = Math::Vector(4.7f, 0.0f, 0.0f); // relative to the hand (lem4)
cargo->SetPosition(pos);
@ -1080,7 +1080,7 @@ bool CTaskManip::TransporterTakeObject()
cargo->SetRotationX(0.0f);
cargo->SetRotationZ(Math::PI/2.0f);
cargo->SetRotationY(0.0f);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(3); // takes with the hand
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(3); // takes with the hand
m_object->SetPower(nullptr);
m_object->SetCargo(cargo); // takes
@ -1094,15 +1094,15 @@ bool CTaskManip::TransporterTakeObject()
if (other == nullptr) return false;
assert(other->Implements(ObjectInterfaceType::Powered));
CObject* cargo = dynamic_cast<CPoweredObject*>(other)->GetPower();
CObject* cargo = dynamic_cast<CPoweredObject&>(*other).GetPower();
if (cargo == nullptr) return false; // the other does not have a battery?
assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType();
dynamic_cast<CPoweredObject*>(other)->SetPower(nullptr);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(3); // takes with the hand
dynamic_cast<CPoweredObject&>(*other).SetPower(nullptr);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(3); // takes with the hand
pos = Math::Vector(4.7f, 0.0f, 0.0f); // relative to the hand (lem4)
cargo->SetPosition(pos);
@ -1137,7 +1137,7 @@ bool CTaskManip::TransporterDeposeObject()
cargo->SetRotationZ(0.0f);
cargo->FloorAdjust(); // plate well on the ground
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(nullptr);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(nullptr);
m_object->SetCargo(nullptr); // deposit
}
@ -1157,7 +1157,7 @@ bool CTaskManip::TransporterDeposeObject()
cargo->SetRotationX(0.0f);
cargo->SetRotationZ(0.0f);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(nullptr);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(nullptr);
m_object->SetCargo(nullptr); // deposit
}
@ -1172,8 +1172,8 @@ bool CTaskManip::TransporterDeposeObject()
if (m_object->GetPower() != nullptr) return false;
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(0); // carried by the base
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(0); // carried by the base
cargo->SetPosition(m_object->GetPowerPosition());
cargo->SetRotationY(0.0f);
@ -1193,7 +1193,7 @@ bool CTaskManip::TransporterDeposeObject()
if (other == nullptr) return false;
assert(other->Implements(ObjectInterfaceType::Powered));
CObject* cargo = dynamic_cast<CPoweredObject*>(other)->GetPower();
CObject* cargo = dynamic_cast<CPoweredObject&>(*other).GetPower();
if (cargo != nullptr) return false; // the other already has a battery?
cargo = m_object->GetCargo();
@ -1202,14 +1202,14 @@ bool CTaskManip::TransporterDeposeObject()
m_cargoType = cargo->GetType();
dynamic_cast<CPoweredObject*>(other)->SetPower(cargo);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(other);
dynamic_cast<CPoweredObject&>(*other).SetPower(cargo);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(other);
cargo->SetPosition(dynamic_cast<CPoweredObject*>(other)->GetPowerPosition());
cargo->SetPosition(dynamic_cast<CPoweredObject&>(*other).GetPowerPosition());
cargo->SetRotationY(0.0f);
cargo->SetRotationX(0.0f);
cargo->SetRotationZ(0.0f);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(0); // carried by the base
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(0); // carried by the base
m_object->SetCargo(nullptr); // deposit
}

View File

@ -194,7 +194,7 @@ Error CTaskRecover::Start()
CObject* power = dynamic_cast<CPoweredObject*>(m_object)->GetPower();
if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) return ERR_RECOVER_ENERGY;
float energy = dynamic_cast<CPowerContainerObject*>(power)->GetEnergy();
float energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy();
if ( energy < ENERGY_RECOVER+0.05f ) return ERR_RECOVER_ENERGY;
Math::Matrix* mat = m_object->GetWorldMatrix(0);

View File

@ -309,7 +309,7 @@ Error CTaskShield::Start(TaskShieldMode mode, float delay)
CObject* power = m_object->GetPower();
if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) return ERR_SHIELD_ENERGY;
float energy = dynamic_cast<CPowerContainerObject*>(power)->GetEnergy();
float energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy();
if ( energy == 0.0f ) return ERR_SHIELD_ENERGY;
Math::Matrix* mat = m_object->GetWorldMatrix(0);

View File

@ -57,7 +57,7 @@ bool CTaskSpiderExplo::EventProcess(const Event &event)
if ( event.type != EVENT_FRAME ) return true;
// Momentarily stationary object (ant on the back)?
if ( dynamic_cast<CBaseAlien*>(m_object)->GetFixed() )
if ( dynamic_cast<CBaseAlien&>(*m_object).GetFixed() )
{
m_bError = true;
return true;

View File

@ -131,9 +131,9 @@ Error CTaskTake::Start()
CObject* other = SearchFriendObject(oAngle, 1.5f, Math::PI*0.50f);
if (other != nullptr) assert(other->Implements(ObjectInterfaceType::Powered));
if (other != nullptr && dynamic_cast<CPoweredObject*>(other)->GetPower() != nullptr)
if (other != nullptr && dynamic_cast<CPoweredObject&>(*other).GetPower() != nullptr)
{
CObject* power = dynamic_cast<CPoweredObject*>(other)->GetPower();
CObject* power = dynamic_cast<CPoweredObject&>(*other).GetPower();
type = power->GetType();
if ( type == OBJECT_URANIUM ) return ERR_MANIP_RADIO;
assert(power->Implements(ObjectInterfaceType::Transportable));
@ -161,7 +161,7 @@ Error CTaskTake::Start()
CObject* other = SearchFriendObject(oAngle, 1.5f, Math::PI*0.50f);
if (other != nullptr) assert(other->Implements(ObjectInterfaceType::Powered));
if (other != nullptr && dynamic_cast<CPoweredObject*>(other)->GetPower() == nullptr )
if (other != nullptr && dynamic_cast<CPoweredObject&>(*other).GetPower() == nullptr )
{
//? m_camera->StartCentering(m_object, Math::PI*0.3f, -Math::PI*0.1f, 0.0f, 0.8f);
m_arm = TTA_FRIEND;
@ -390,7 +390,7 @@ CObject* CTaskTake::SearchFriendObject(float &angle,
assert(pObj->Implements(ObjectInterfaceType::Powered));
CObject* power = dynamic_cast<CPoweredObject*>(pObj)->GetPower();
CObject* power = dynamic_cast<CPoweredObject&>(*pObj).GetPower();
if (power != nullptr)
{
if ( power->GetLock() ) continue;
@ -398,7 +398,7 @@ CObject* CTaskTake::SearchFriendObject(float &angle,
}
Math::Matrix* mat = pObj->GetWorldMatrix(0);
Math::Vector oPos = Math::Transform(*mat, dynamic_cast<CPoweredObject*>(pObj)->GetPowerPosition());
Math::Vector oPos = Math::Transform(*mat, dynamic_cast<CPoweredObject&>(*pObj).GetPowerPosition());
float distance = fabs(Math::Distance(oPos, iPos) - (iRad+1.0f));
if ( distance <= dLimit )
@ -406,7 +406,7 @@ CObject* CTaskTake::SearchFriendObject(float &angle,
angle = Math::RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
if ( Math::TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
{
Math::Vector powerPos = dynamic_cast<CPoweredObject*>(pObj)->GetPowerPosition();
Math::Vector powerPos = dynamic_cast<CPoweredObject&>(*pObj).GetPowerPosition();
m_height = powerPos.y;
return pObj;
}
@ -430,8 +430,8 @@ bool CTaskTake::TransporterTakeObject()
m_cargoType = cargo->GetType();
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(4); // takes with the hand
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(4); // takes with the hand
//? cargo->SetPosition(Math::Vector(2.2f, -1.0f, 1.1f));
cargo->SetPosition(Math::Vector(1.7f, -0.5f, 1.1f));
@ -449,15 +449,15 @@ bool CTaskTake::TransporterTakeObject()
if (other == nullptr) return false;
assert(other->Implements(ObjectInterfaceType::Powered));
CObject* cargo = dynamic_cast<CPoweredObject*>(other)->GetPower();
CObject* cargo = dynamic_cast<CPoweredObject&>(*other).GetPower();
if (cargo == nullptr) return false; // the other does not have a battery?
assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType();
dynamic_cast<CPoweredObject*>(other)->SetPower(nullptr);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(m_object);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(4); // takes with the hand
dynamic_cast<CPoweredObject&>(*other).SetPower(nullptr);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(m_object);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(4); // takes with the hand
//? cargo->SetPosition(Math::Vector(2.2f, -1.0f, 1.1f));
cargo->SetPosition(Math::Vector(1.7f, -0.5f, 1.1f));
@ -492,7 +492,7 @@ bool CTaskTake::TransporterDeposeObject()
cargo->SetRotationZ(0.0f);
cargo->FloorAdjust(); // plate well on the ground
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(nullptr);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(nullptr);
m_object->SetCargo(nullptr); // deposit
}
@ -503,7 +503,7 @@ bool CTaskTake::TransporterDeposeObject()
if (other == nullptr) return false;
assert(other->Implements(ObjectInterfaceType::Powered));
CObject* cargo = dynamic_cast<CPoweredObject*>(other)->GetPower();
CObject* cargo = dynamic_cast<CPoweredObject&>(*other).GetPower();
if (cargo != nullptr) return false; // the other already has a battery?
cargo = m_object->GetCargo();
@ -511,14 +511,14 @@ bool CTaskTake::TransporterDeposeObject()
assert(cargo->Implements(ObjectInterfaceType::Transportable));
m_cargoType = cargo->GetType();
dynamic_cast<CPoweredObject*>(other)->SetPower(cargo);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporter(other);
dynamic_cast<CPoweredObject&>(*other).SetPower(cargo);
dynamic_cast<CTransportableObject&>(*cargo).SetTransporter(other);
cargo->SetPosition(dynamic_cast<CPoweredObject*>(other)->GetPowerPosition());
cargo->SetPosition(dynamic_cast<CPoweredObject&>(*other).GetPowerPosition());
cargo->SetRotationY(0.0f);
cargo->SetRotationX(0.0f);
cargo->SetRotationZ(0.0f);
dynamic_cast<CTransportableObject*>(cargo)->SetTransporterPart(0); // carried by the base
dynamic_cast<CTransportableObject&>(*cargo).SetTransporterPart(0); // carried by the base
m_object->SetCargo(nullptr); // deposit
}

View File

@ -215,7 +215,7 @@ Error CTaskTerraform::Start()
power = m_object->GetPower();
if ( power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer) ) return ERR_TERRA_ENERGY;
energy = dynamic_cast<CPowerContainerObject*>(power)->GetEnergy();
energy = dynamic_cast<CPowerContainerObject&>(*power).GetEnergy();
if ( energy < ENERGY_TERRA+0.05f ) return ERR_TERRA_ENERGY;
speed = m_physics->GetMotorSpeed();
@ -426,7 +426,7 @@ bool CTaskTerraform::Terraform()
{
if ( dist > 5.0f ) continue;
m_engine->GetPyroManager()->Create(Gfx::PT_EXPLOT, pObj);
dynamic_cast<CDamageableObject*>(m_object)->DamageObject(DamageType::Explosive, 0.9f);
dynamic_cast<CDamageableObject&>(*m_object).DamageObject(DamageType::Explosive, 0.9f);
}
else if ( type == OBJECT_PLANT0 ||
type == OBJECT_PLANT1 ||
@ -444,6 +444,7 @@ bool CTaskTerraform::Terraform()
{
if ( dist > 7.5f ) continue;
m_engine->GetPyroManager()->Create(Gfx::PT_FRAGV, pObj);
}
else // Other?
{
@ -454,7 +455,7 @@ bool CTaskTerraform::Terraform()
else
{
if ( !pObj->Implements(ObjectInterfaceType::Movable) ) continue;
motion = dynamic_cast<CMovableObject*>(pObj)->GetMotion();
motion = dynamic_cast<CMovableObject&>(*pObj).GetMotion();
dist = Math::Distance(m_terraPos, pObj->GetPosition());
if ( dist > ACTION_RADIUS ) continue;
@ -462,13 +463,13 @@ bool CTaskTerraform::Terraform()
if ( type == OBJECT_ANT || type == OBJECT_SPIDER )
{
assert(pObj->Implements(ObjectInterfaceType::TaskExecutor));
dynamic_cast<CTaskExecutorObject*>(pObj)->StopForegroundTask();
dynamic_cast<CTaskExecutorObject&>(*pObj).StopForegroundTask();
int actionType = -1;
if (type == OBJECT_ANT) actionType = MAS_BACK1;
if (type == OBJECT_SPIDER) actionType = MSS_BACK1;
motion->SetAction(actionType, 0.8f+Math::Rand()*0.3f);
dynamic_cast<CBaseAlien*>(pObj)->SetFixed(true); // not moving
dynamic_cast<CBaseAlien&>(*pObj).SetFixed(true); // not moving
if ( dist > 5.0f ) continue;
m_engine->GetPyroManager()->Create(Gfx::PT_EXPLOO, pObj);

View File

@ -804,7 +804,7 @@ void CPhysics::MotorUpdate(float aTime, float rTime)
if (m_object->Implements(ObjectInterfaceType::Powered))
{
power = dynamic_cast<CPowerContainerObject*>(dynamic_cast<CPoweredObject*>(m_object)->GetPower()); // searches for the object battery uses
power = dynamic_cast<CPowerContainerObject*>(dynamic_cast<CPoweredObject&>(*m_object).GetPower()); // searches for the object battery uses
if ( GetObjectEnergy(m_object) == 0.0f ) // no battery or flat?
{
motorSpeed.x = 0.0f;
@ -822,7 +822,7 @@ void CPhysics::MotorUpdate(float aTime, float rTime)
}
}
if ( m_object->GetType() == OBJECT_HUMAN && dynamic_cast<CDestroyableObject*>(m_object)->GetDying() == DeathType::Dead ) // dead man?
if ( m_object->GetType() == OBJECT_HUMAN && dynamic_cast<CDestroyableObject&>(*m_object).GetDying() == DeathType::Dead ) // dead man?
{
motorSpeed.x = 0.0f;
motorSpeed.z = 0.0f;
@ -852,7 +852,7 @@ void CPhysics::MotorUpdate(float aTime, float rTime)
}
if ( m_object->Implements(ObjectInterfaceType::JetFlying) &&
dynamic_cast<CJetFlyingObject*>(m_object)->GetRange() > 0.0f ) // limited flight range?
dynamic_cast<CJetFlyingObject&>(*m_object).GetRange() > 0.0f ) // limited flight range?
{
CJetFlyingObject* jetFlying = dynamic_cast<CJetFlyingObject*>(m_object);
if ( m_bLand || m_bSwim || m_bObstacle ) // on the ground or in the water?
@ -960,7 +960,7 @@ void CPhysics::MotorUpdate(float aTime, float rTime)
bool reactorCool = true;
if ( m_object->Implements(ObjectInterfaceType::JetFlying) )
{
reactorCool = dynamic_cast<CJetFlyingObject*>(m_object)->GetReactorRange() > 0.1f;
reactorCool = dynamic_cast<CJetFlyingObject&>(*m_object).GetReactorRange() > 0.1f;
}
if ( motorSpeed.y > 0.0f && reactorCool && pos.y < h )
{
@ -1463,7 +1463,7 @@ bool CPhysics::EventFrame(const Event &event)
iAngle = angle = m_object->GetRotation();
// Accelerate is the descent, brake is the ascent.
if ( m_bFreeze || (m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(m_object)->IsDying()) )
if ( m_bFreeze || (m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject&>(*m_object).IsDying()) )
{
m_linMotion.terrainSpeed.x = 0.0f;
m_linMotion.terrainSpeed.z = 0.0f;
@ -1618,8 +1618,8 @@ void CPhysics::SoundMotor(float rTime)
else if ( type == OBJECT_ANT )
{
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
if ( dynamic_cast<CDestroyableObject*>(m_object)->GetDying() == DeathType::Burning ||
dynamic_cast<CBaseAlien*>(m_object)->GetFixed() )
if ( dynamic_cast<CDestroyableObject&>(*m_object).GetDying() == DeathType::Burning ||
dynamic_cast<CBaseAlien&>(*m_object).GetFixed() )
{
if ( m_lastSoundInsect <= 0.0f )
{
@ -1649,7 +1649,7 @@ void CPhysics::SoundMotor(float rTime)
else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f;
}
}
else if ( dynamic_cast<CDestroyableObject*>(m_object)->GetDying() == DeathType::Burning )
else if ( dynamic_cast<CDestroyableObject&>(*m_object).GetDying() == DeathType::Burning )
{
if ( m_lastSoundInsect <= 0.0f )
{
@ -1670,7 +1670,7 @@ void CPhysics::SoundMotor(float rTime)
else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f;
}
}
else if ( dynamic_cast<CDestroyableObject*>(m_object)->GetDying() == DeathType::Burning )
else if ( dynamic_cast<CDestroyableObject&>(*m_object).GetDying() == DeathType::Burning )
{
if ( m_lastSoundInsect <= 0.0f )
{
@ -1682,8 +1682,8 @@ void CPhysics::SoundMotor(float rTime)
else if ( type == OBJECT_SPIDER )
{
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
if ( dynamic_cast<CDestroyableObject*>(m_object)->GetDying() == DeathType::Burning ||
dynamic_cast<CBaseAlien*>(m_object)->GetFixed() )
if ( dynamic_cast<CDestroyableObject&>(*m_object).GetDying() == DeathType::Burning ||
dynamic_cast<CBaseAlien&>(*m_object).GetFixed() )
{
if ( m_lastSoundInsect <= 0.0f )
{
@ -2506,7 +2506,7 @@ int CPhysics::ObjectAdapt(const Math::Vector &pos, const Math::Vector &angle)
int colType;
ObjectType iType, oType;
if ( m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(m_object)->IsDying() ) return 0; // is burning or exploding?
if ( m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject&>(*m_object).IsDying() ) return 0; // is burning or exploding?
if ( !m_object->GetCollisions() ) return 0;
// iiPos = sphere center is the old position.
@ -2525,7 +2525,7 @@ int CPhysics::ObjectAdapt(const Math::Vector &pos, const Math::Vector &angle)
{
if ( pObj == m_object ) continue; // yourself?
if (IsObjectBeingTransported(pObj)) continue;
if ( pObj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(pObj)->GetDying() == DeathType::Exploding ) continue; // is exploding?
if ( pObj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject&>(*pObj).GetDying() == DeathType::Exploding ) continue; // is exploding?
oType = pObj->GetType();
if ( oType == OBJECT_TOTO ) continue;
@ -2627,7 +2627,7 @@ int CPhysics::ObjectAdapt(const Math::Vector &pos, const Math::Vector &angle)
CPhysics* ph = nullptr;
if (pObj->Implements(ObjectInterfaceType::Movable))
ph = dynamic_cast<CMovableObject*>(pObj)->GetPhysics();
ph = dynamic_cast<CMovableObject&>(*pObj).GetPhysics();
if ( ph != nullptr )
{
oAngle = pObj->GetRotation();
@ -2727,7 +2727,7 @@ bool CPhysics::ExploOther(ObjectType iType,
if ( force > destructionForce && destructionForce >= 0.0f )
{
// TODO: implement "killer"?
dynamic_cast<CDamageableObject*>(pObj)->DamageObject(damageType);
dynamic_cast<CDamageableObject&>(*pObj).DamageObject(damageType);
}
}
@ -2753,7 +2753,7 @@ bool CPhysics::ExploOther(ObjectType iType,
{
assert(pObj->Implements(ObjectInterfaceType::Damageable));
// TODO: implement "killer"?
dynamic_cast<CDamageableObject*>(pObj)->DamageObject(DamageType::Collision, force/400.0f);
dynamic_cast<CDamageableObject&>(*pObj).DamageObject(DamageType::Collision, force/400.0f);
}
if (oType == OBJECT_MOBILEwa ||
@ -2790,7 +2790,7 @@ bool CPhysics::ExploOther(ObjectType iType,
{
assert(pObj->Implements(ObjectInterfaceType::Damageable));
// TODO: implement "killer"?
dynamic_cast<CDamageableObject*>(pObj)->DamageObject(DamageType::Collision, force/200.0f);
dynamic_cast<CDamageableObject&>(*pObj).DamageObject(DamageType::Collision, force/200.0f);
}
}
@ -2830,7 +2830,7 @@ int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force)
if ( force > destructionForce && destructionForce >= 0.0f )
{
// TODO: implement "killer"?
dynamic_cast<CDamageableObject*>(m_object)->DamageObject(DamageType::Explosive);
dynamic_cast<CDamageableObject&>(*m_object).DamageObject(DamageType::Explosive);
return 2;
}
@ -2917,7 +2917,7 @@ int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force)
}
// TODO: implement "killer"?
if ( dynamic_cast<CDamageableObject*>(m_object)->DamageObject(DamageType::Collision, force) ) return 2;
if ( dynamic_cast<CDamageableObject&>(*m_object).DamageObject(DamageType::Collision, force) ) return 2;
}
}
@ -2969,9 +2969,9 @@ void CPhysics::PowerParticle(float factor, bool bBreak)
bCarryPower = false;
if (m_object->Implements(ObjectInterfaceType::Carrier))
{
CObject* cargo = dynamic_cast<CCarrierObject*>(m_object)->GetCargo();
CObject* cargo = dynamic_cast<CCarrierObject&>(*m_object).GetCargo();
if ( cargo != nullptr && cargo->Implements(ObjectInterfaceType::PowerContainer) &&
dynamic_cast<CPowerContainerObject*>(cargo)->IsRechargeable() &&
dynamic_cast<CPowerContainerObject&>(*cargo).IsRechargeable() &&
m_object->GetPartRotationZ(1) == ARM_STOCK_ANGLE1 )
{
bCarryPower = true; // carries a battery
@ -3264,7 +3264,7 @@ void CPhysics::MotorParticle(float aTime, float rTime)
}
else // in flight?
{
if ( !m_bMotor || (m_object->Implements(ObjectInterfaceType::JetFlying) && dynamic_cast<CJetFlyingObject*>(m_object)->GetReactorRange() == 0.0f) ) return;
if ( !m_bMotor || (m_object->Implements(ObjectInterfaceType::JetFlying) && dynamic_cast<CJetFlyingObject&>(*m_object).GetReactorRange() == 0.0f) ) return;
if ( m_reactorTemperature < 1.0f ) // not too hot?
{
@ -3394,7 +3394,7 @@ void CPhysics::MotorParticle(float aTime, float rTime)
}
else // in flight?
{
if ( !m_bMotor || (m_object->Implements(ObjectInterfaceType::JetFlying) && dynamic_cast<CJetFlyingObject*>(m_object)->GetReactorRange() == 0.0f) ) return;
if ( !m_bMotor || (m_object->Implements(ObjectInterfaceType::JetFlying) && dynamic_cast<CJetFlyingObject&>(*m_object).GetReactorRange() == 0.0f) ) return;
if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.02f) ) return;
m_lastMotorParticle = aTime;
@ -3455,7 +3455,7 @@ void CPhysics::MotorParticle(float aTime, float rTime)
if ( (type == OBJECT_HUMAN || type == OBJECT_TECH) && m_bSwim )
{
if ( !m_object->Implements(ObjectInterfaceType::Destroyable) || dynamic_cast<CDestroyableObject*>(m_object)->GetDying() != DeathType::Dead )
if ( !m_object->Implements(ObjectInterfaceType::Destroyable) || dynamic_cast<CDestroyableObject&>(*m_object).GetDying() != DeathType::Dead )
{
h = Math::Mod(aTime, 5.0f);
if ( h < 3.5f && ( h < 1.5f || h > 1.6f ) ) return;
@ -3778,7 +3778,7 @@ Error CPhysics::GetError()
if (m_object->Implements(ObjectInterfaceType::ProgramStorage))
{
if ( dynamic_cast<CProgramStorageObject*>(m_object)->GetActiveVirus() )
if ( dynamic_cast<CProgramStorageObject&>(*m_object).GetActiveVirus() )
{
return ERR_VEH_VIRUS;
}
@ -3786,14 +3786,14 @@ Error CPhysics::GetError()
if (m_object->Implements(ObjectInterfaceType::Powered))
{
CObject* power = dynamic_cast<CPoweredObject*>(m_object)->GetPower(); // searches for the object battery used
CObject* power = dynamic_cast<CPoweredObject&>(*m_object).GetPower(); // searches for the object battery used
if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer))
{
return ERR_VEH_POWER;
}
else
{
if ( dynamic_cast<CPowerContainerObject*>(power)->GetEnergy() == 0.0f ) return ERR_VEH_ENERGY;
if ( dynamic_cast<CPowerContainerObject&>(*power).GetEnergy() == 0.0f ) return ERR_VEH_ENERGY;
}
}

View File

@ -729,15 +729,18 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo
}
CObject* obj = CObjectManager::GetInstancePointer()->GetObjectById(rank);
if ( obj == nullptr || (obj->Implements(ObjectInterfaceType::Old) && dynamic_cast<COldObject*>(obj)->IsDying()) )
if ( obj == nullptr || (obj->Implements(ObjectInterfaceType::Old) && dynamic_cast<COldObject&>(*obj).IsDying()) )
{
return true;
}
else
{
CScript* script = static_cast<CScript*>(user);
bool deleteSelf = (obj == script->m_object);
if ( exploType != DestructionType::NoEffect && obj->Implements(ObjectInterfaceType::Destroyable) )
{
dynamic_cast<CDestroyableObject*>(obj)->DestroyObject(static_cast<DestructionType>(exploType));
dynamic_cast<CDestroyableObject&>(*obj).DestroyObject(static_cast<DestructionType>(exploType));
}
else
{
@ -753,12 +756,13 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo
}
CObjectManager::GetInstancePointer()->DeleteObject(obj);
}
// Returning "false" here makes sure the program doesn't try to keep executing
// if the robot just destroyed itself using delete(this.id)
// See issue #925
return !deleteSelf;
}
// Returning "false" here makes sure the program doesn't try to keep executing if the robot just destroyed itself
// using delete(this.id)
// See issue #925
return false;
return true;
}
static CBotTypResult compileSearch(CBotVar* &var, void* user, CBotTypResult returnValue)
@ -1653,7 +1657,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v
CObjectManager::GetInstancePointer()->CreateObject(pos, angle, OBJECT_EGG);
if (object->Implements(ObjectInterfaceType::Programmable))
{
dynamic_cast<CProgrammableObject*>(object)->SetActivity(false);
dynamic_cast<CProgrammableObject&>(*object).SetActivity(false);
}
}
else
@ -1662,7 +1666,11 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v
{
power = 1.0f;
}
object = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type, power);
bool exists = IsValidObjectTypeId(type) && type != OBJECT_NULL && type != OBJECT_MAX && type != OBJECT_MOBILEpr;
if (exists)
{
object = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type, power);
}
if (object == nullptr)
{
result->SetValInt(1); // error
@ -1671,7 +1679,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v
if (type == OBJECT_MOBILEdr)
{
assert(object->Implements(ObjectInterfaceType::Old)); // TODO: temporary hack
dynamic_cast<COldObject*>(object)->SetManual(true);
dynamic_cast<COldObject&>(*object).SetManual(true);
}
script->m_main->CreateShortcuts();
}
@ -1686,7 +1694,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v
programStorage->ReadProgram(program, name2.c_str());
program->readOnly = true;
program->filename = name;
dynamic_cast<CProgrammableObject*>(object)->RunProgram(program);
dynamic_cast<CProgrammableObject&>(*object).RunProgram(program);
}
}
@ -2292,7 +2300,7 @@ bool CScriptFunctions::rReceive(CBotVar* var, CBotVar* result, int& exception, v
return true;
}
CExchangePost* exchangePost = dynamic_cast<CTaskInfo*>(script->m_taskExecutor->GetForegroundTask())->FindExchangePost(power);
CExchangePost* exchangePost = dynamic_cast<CTaskInfo&>(*script->m_taskExecutor->GetForegroundTask()).FindExchangePost(power);
script->m_returnValue = exchangePost->GetInfoValue(p);
}
if ( !WaitForForegroundTask(script, result, exception) ) return false; // not finished
@ -2577,7 +2585,7 @@ bool CScriptFunctions::rShield(CBotVar* var, CBotVar* result, int& exception, vo
}
else // up ?
{
dynamic_cast<CShielder*>(pThis)->SetShieldRadius(radius);
dynamic_cast<CShielder&>(*pThis).SetShieldRadius(radius);
err = script->m_taskExecutor->StartTaskShield(TSM_UP, 1000.0f);
if ( err != ERR_OK )
{
@ -2595,7 +2603,7 @@ bool CScriptFunctions::rShield(CBotVar* var, CBotVar* result, int& exception, vo
else // up?
{
//? result->SetValInt(1); // shows the error
dynamic_cast<CShielder*>(pThis)->SetShieldRadius(radius);
dynamic_cast<CShielder&>(*pThis).SetShieldRadius(radius);
script->m_taskExecutor->StartTaskShield(TSM_UPDATE, 0.0f);
}
}
@ -2769,7 +2777,7 @@ bool CScriptFunctions::rMotor(CBotVar* var, CBotVar* result, int& exception, voi
if ( turn < -1.0f ) turn = -1.0f;
if ( turn > 1.0f ) turn = 1.0f;
if ( dynamic_cast<CBaseAlien*>(pThis) != nullptr && dynamic_cast<CBaseAlien*>(pThis)->GetFixed() ) // ant on the back?
if ( dynamic_cast<CBaseAlien*>(pThis) != nullptr && dynamic_cast<CBaseAlien&>(*pThis).GetFixed() ) // ant on the back?
{
speed = 0.0f;
turn = 0.0f;
@ -2878,7 +2886,7 @@ bool CScriptFunctions::rCmdline(CBotVar* var, CBotVar* result, int& exception, v
assert(pThis->Implements(ObjectInterfaceType::Programmable));
rank = var->GetValInt();
value = dynamic_cast<CProgrammableObject*>(pThis)->GetCmdLine(rank);
value = dynamic_cast<CProgrammableObject&>(*pThis).GetCmdLine(rank);
result->SetValFloat(value);
return true;

View File

@ -47,22 +47,7 @@ void CALSound::CleanUp()
if (m_enabled)
{
GetLogger()->Info("Unloading files and closing device...\n");
StopAll();
StopMusic();
m_channels.clear();
m_currentMusic.reset();
m_oldMusic.clear();
m_previousMusic.music.reset();
m_sounds.clear();
m_music.clear();
m_enabled = false;
Reset();
alcDestroyContext(m_context);
alcCloseDevice(m_device);
@ -99,6 +84,24 @@ bool CALSound::Create()
return true;
}
void CALSound::Reset()
{
StopAll();
StopMusic();
m_channels.clear();
m_currentMusic.reset();
m_oldMusic.clear();
m_previousMusic.music.reset();
m_sounds.clear();
m_music.clear();
}
bool CALSound::GetEnable()
{
return m_enabled;

View File

@ -84,6 +84,7 @@ public:
~CALSound();
bool Create() override;
void Reset() override;
bool Cache(SoundType, const std::string &) override;
void CacheMusic(const std::string &) override;
bool IsCached(SoundType) override;

View File

@ -52,6 +52,10 @@ void CSoundInterface::CacheAll()
}
}
void CSoundInterface::Reset()
{
}
bool CSoundInterface::Cache(SoundType sound, const std::string &file)
{
return true;

View File

@ -72,6 +72,10 @@ public:
*/
void CacheAll();
/** Stop all sounds and music and clean cache.
*/
virtual void Reset();
/** Function called to cache sound effect file.
* This function is called by plugin interface for each file.
* \param sound - id of a file, will be used to identify sound files

View File

@ -1299,7 +1299,9 @@ void CEdit::SetText(const std::string& text, bool bNew)
if( m_len >= GetMaxChar() ) m_len = GetMaxChar();
m_text.resize( m_len + 1, '\0' );
m_text[m_len] = '\0';
m_format.resize( m_len + 1, m_fontType );
m_format[m_len] = m_fontType;
font = m_fontType;
j = 0;

View File

@ -1197,7 +1197,7 @@ void CMap::UpdateObject(CObject* pObj)
type != OBJECT_WORM &&
type != OBJECT_MOBILEtg )
{
if (pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast<CControllableObject*>(pObj)->GetSelectable()) return;
if (pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast<CControllableObject&>(*pObj).GetSelectable()) return;
}
if ( pObj->GetProxyActivate() ) return;
if (IsObjectBeingTransported(pObj)) return;
@ -1330,7 +1330,7 @@ void CMap::UpdateObject(CObject* pObj)
color != MAPCOLOR_MOVE ) return;
}*/
if ( pObj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject*>(pObj)->GetSelect() )
if ( pObj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject&>(*pObj).GetSelect() )
{
m_map[MAPMAXOBJECT-1].type = type;
m_map[MAPMAXOBJECT-1].object = pObj;

View File

@ -143,13 +143,13 @@ CObject* CTarget::DetectFriendObject(Math::Point pos)
CObject* target = obj;
if ( obj->Implements(ObjectInterfaceType::PowerContainer) && IsObjectBeingTransported(obj) )
{
target = dynamic_cast<CTransportableObject*>(obj)->GetTransporter();
target = dynamic_cast<CTransportableObject&>(*obj).GetTransporter();
}
if ( !target->GetDetectable() ) continue;
if ( target->GetProxyActivate() ) continue;
if ( target->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject*>(target)->GetSelect() ) continue;
if ( !target->Implements(ObjectInterfaceType::Controllable) || !dynamic_cast<CControllableObject*>(target)->GetSelectable() ) continue;
if ( target->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject&>(*target).GetSelect() ) continue;
if ( !target->Implements(ObjectInterfaceType::Controllable) || !dynamic_cast<CControllableObject&>(*target).GetSelectable() ) continue;
if (!target->Implements(ObjectInterfaceType::Old)) continue; // TODO: To be removed after COldObjectInterface is gone

View File

@ -109,7 +109,7 @@ bool CDisplayInfo::EventProcess(const Event &event)
if ( m_toto != nullptr )
{
assert(m_toto->Implements(ObjectInterfaceType::Movable));
CMotionToto* toto = static_cast<CMotionToto*>(dynamic_cast<CMovableObject*>(m_toto)->GetMotion());
CMotionToto* toto = static_cast<CMotionToto*>(dynamic_cast<CMovableObject&>(*m_toto).GetMotion());
assert(toto != nullptr);
toto->SetMousePos(event.mousePos);
}
@ -449,7 +449,7 @@ void CDisplayInfo::StartDisplayInfo(std::string filename, int index, bool bSoluc
m_toto->SetDrawFront(true);
assert(m_toto->Implements(ObjectInterfaceType::Movable));
CMotionToto* toto = static_cast<CMotionToto*>(dynamic_cast<CMovableObject*>(m_toto)->GetMotion());
CMotionToto* toto = static_cast<CMotionToto*>(dynamic_cast<CMovableObject&>(*m_toto).GetMotion());
assert(toto != nullptr);
toto->StartDisplayInfo();
}
@ -840,7 +840,7 @@ void CDisplayInfo::StopDisplayInfo()
if ( m_toto != nullptr )
{
assert(m_toto->Implements(ObjectInterfaceType::Movable));
CMotionToto* toto = static_cast<CMotionToto*>(dynamic_cast<CMovableObject*>(m_toto)->GetMotion());
CMotionToto* toto = static_cast<CMotionToto*>(dynamic_cast<CMovableObject&>(*m_toto).GetMotion());
assert(toto != nullptr);
toto->StopDisplayInfo();
}

View File

@ -258,7 +258,7 @@ void CDisplayText::DisplayText(const char *text, Math::Vector goal, float height
if ( toto != nullptr )
{
assert(toto->Implements(ObjectInterfaceType::Movable));
motion = dynamic_cast<CMovableObject*>(toto)->GetMotion();
motion = dynamic_cast<CMovableObject&>(*toto).GetMotion();
if ( type == TT_ERROR )
{

View File

@ -150,7 +150,7 @@ bool CMainShort::CreateShortcuts()
for (CObject* pObj : CObjectManager::GetInstancePointer()->GetAllObjects())
{
if ( !pObj->GetDetectable() ) continue;
if ( pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast<CControllableObject*>(pObj)->GetSelectable() ) continue;
if ( pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast<CControllableObject&>(*pObj).GetSelectable() ) continue;
if ( pObj->GetProxyActivate() ) continue;
int icon = GetShortcutIcon(pObj->GetType());
@ -274,9 +274,9 @@ bool CMainShort::UpdateShortcuts()
if ( pc != nullptr )
{
assert(m_shortcuts[i]->Implements(ObjectInterfaceType::Controllable));
pc->SetState(STATE_CHECK, dynamic_cast<CControllableObject*>(m_shortcuts[i])->GetSelect());
pc->SetState(STATE_RUN, m_shortcuts[i]->Implements(ObjectInterfaceType::Programmable) && dynamic_cast<CProgrammableObject*>(m_shortcuts[i])->IsProgram());
pc->SetState(STATE_DAMAGE, dynamic_cast<CDamageableObject*>(m_shortcuts[i])->IsDamaging());
pc->SetState(STATE_CHECK, dynamic_cast<CControllableObject&>(*m_shortcuts[i]).GetSelect());
pc->SetState(STATE_RUN, m_shortcuts[i]->Implements(ObjectInterfaceType::Programmable) && dynamic_cast<CProgrammableObject&>(*m_shortcuts[i]).IsProgram());
pc->SetState(STATE_DAMAGE, dynamic_cast<CDamageableObject&>(*m_shortcuts[i]).IsDamaging());
}
}
return true;

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