Release 0.1.10-alpha: Merge branch 'dev'

master
krzys-h 2017-05-24 14:34:19 +02:00
commit 1dcc70c097
142 changed files with 4891 additions and 2421 deletions

View File

@ -16,9 +16,9 @@ set(COLOBOT_VERSION_MINOR 1)
set(COLOBOT_VERSION_REVISION 9) set(COLOBOT_VERSION_REVISION 9)
# Used on official releases # Used on official releases
set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha") #set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha")
# Used on unreleased, development builds # Used on unreleased, development builds
#set(COLOBOT_VERSION_UNRELEASED "+alpha") set(COLOBOT_VERSION_UNRELEASED "+alpha")
# Append git characteristics to version # Append git characteristics to version
if(DEFINED COLOBOT_VERSION_UNRELEASED) if(DEFINED COLOBOT_VERSION_UNRELEASED)
@ -132,8 +132,8 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
message(STATUS "Detected GCC version 4.7+") message(STATUS "Detected GCC version 4.7+")
set(NORMAL_CXX_FLAGS "-std=gnu++11 -Wall -Wold-style-cast -pedantic-errors") set(NORMAL_CXX_FLAGS "-std=gnu++11 -Wall -Werror -Wold-style-cast -pedantic-errors")
set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -fno-delete-null-pointer-checks") # Temporary hack, see #828 set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -Wno-error=deprecated-declarations") # updated version of physfs is not available on some platforms so we keep using deprecated functions, see #958
set(RELEASE_CXX_FLAGS "-O2") set(RELEASE_CXX_FLAGS "-O2")
set(DEBUG_CXX_FLAGS "-g -O0") set(DEBUG_CXX_FLAGS "-g -O0")
set(TEST_CXX_FLAGS "-pthread") set(TEST_CXX_FLAGS "-pthread")
@ -145,7 +145,8 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message(STATUS "Detected Clang version 3.1+") message(STATUS "Detected Clang version 3.1+")
set(NORMAL_CXX_FLAGS "-std=c++11 -Wall -Wold-style-cast -pedantic-errors") set(NORMAL_CXX_FLAGS "-std=c++11 -Wall -Werror -Wold-style-cast -pedantic-errors")
set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -Wno-error=deprecated-declarations") # updated version of physfs is not available on some platforms so we keep using deprecated functions, see #958
set(RELEASE_CXX_FLAGS "-O2") set(RELEASE_CXX_FLAGS "-O2")
set(DEBUG_CXX_FLAGS "-g -O0") set(DEBUG_CXX_FLAGS "-g -O0")
set(TEST_CXX_FLAGS "-pthread") set(TEST_CXX_FLAGS "-pthread")

View File

@ -351,7 +351,7 @@ IDL_PROPERTY_SUPPORT = YES
# all members of a group must be documented explicitly. # all members of a group must be documented explicitly.
# The default value is: NO. # The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO DISTRIBUTE_GROUP_DOC = YES
# Set the SUBGROUPING tag to YES to allow class member groups of the same type # Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that # (for instance a group of public functions) to be put as a subgroup of that
@ -993,7 +993,7 @@ USE_HTAGS = NO
# See also: Section \class. # See also: Section \class.
# The default value is: YES. # The default value is: YES.
VERBATIM_HEADERS = YES VERBATIM_HEADERS = NO
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the

113
Jenkinsfile vendored
View File

@ -1,50 +1,67 @@
node('master') { #!/usr/bin/env groovy
stage 'Pull changes' if (env.BRANCH_NAME.startsWith('PR-')) {
checkout scm properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactNumToKeepStr: '1']]])
} else {
stage 'Build Windows' properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '30', artifactNumToKeepStr: '20']]])
sh 'mkdir -p build/windows'
dir('build/windows') {
sh '''
cmake \
-DCMAKE_INSTALL_PREFIX=/install \
-DCMAKE_TOOLCHAIN_FILE=/opt/mxe/usr/i686-w64-mingw32.static/share/cmake/mxe-conf.cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DDEV_BUILD=1 -DPORTABLE=1 -DTOOLS=1 -DTESTS=0 ../..
make
rm -rf install
DESTDIR=. make install
'''
}
sh 'rm -f windows-debug.zip'
zip zipFile: 'windows-debug.zip', archive: true, dir: 'build/windows/install'
stage 'Build Linux'
sh 'mkdir -p build/linux'
dir('build/linux') {
sh '''
cmake \
-DCMAKE_INSTALL_PREFIX=/install -DCOLOBOT_INSTALL_BIN_DIR=/install -DCOLOBOT_INSTALL_LIB_DIR=/install -DCOLOBOT_INSTALL_DATA_DIR=/install/data -DCOLOBOT_INSTALL_I18N_DIR=/install/lang -DCMAKE_SKIP_INSTALL_RPATH=ON \
-DBOOST_STATIC=ON -DGLEW_STATIC=ON -DGLEW_LIBRARY=/usr/lib64/libGLEW.a \
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DDEV_BUILD=1 -DPORTABLE=1 -DTOOLS=1 -DTESTS=1 -DDESKTOP=0 ../..
make
rm -rf install
DESTDIR=. make install
patchelf --set-rpath '.' install/colobot
'''
}
sh 'rm -f linux-debug.zip'
zip zipFile: 'linux-debug.zip', archive: true, dir: 'build/linux/install'
stage 'Doxygen'
dir('build/linux') {
sh 'make doc'
}
publishHTML target: [$class: 'HtmlPublisherTarget', reportName: 'Doxygen', reportDir: 'build/linux/doc/html', reportFiles: 'index.html']
stage 'Run tests'
dir('build/linux') {
sh './colobot_ut --gtest_output=xml:gtestresults.xml || true'
}
step([$class: 'XUnitBuilder', testTimeMargin: '3000', thresholdMode: 1, thresholds: [[$class: 'FailedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '0'], [$class: 'SkippedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '']], tools: [[$class: 'GoogleTestType', deleteOutputFiles: true, failIfNotNew: true, pattern: 'build/linux/gtestresults.xml', skipNoTestFiles: false, stopProcessingIfError: true]]])
} }
node('master') {
stage('Pull changes') {
checkout scm
}
stage('Build Windows') {
sh 'mkdir -p build/windows'
dir('build/windows') {
sh '''
cmake \
-DCMAKE_INSTALL_PREFIX=/install \
-DCMAKE_TOOLCHAIN_FILE=/opt/mxe/usr/i686-w64-mingw32.static/share/cmake/mxe-conf.cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DDEV_BUILD=1 -DPORTABLE=1 -DTOOLS=1 -DTESTS=0 ../..
make
rm -rf install
DESTDIR=. make install
'''
}
sh 'rm -f windows-debug.zip'
zip zipFile: 'windows-debug.zip', archive: true, dir: 'build/windows/install'
}
stage('Build Linux') {
sh 'mkdir -p build/linux'
dir('build/linux') {
sh '''
cmake \
-DCMAKE_INSTALL_PREFIX=/install -DCOLOBOT_INSTALL_BIN_DIR=/install -DCOLOBOT_INSTALL_LIB_DIR=/install -DCOLOBOT_INSTALL_DATA_DIR=/install/data -DCOLOBOT_INSTALL_I18N_DIR=/install/lang -DCMAKE_SKIP_INSTALL_RPATH=ON \
-DBOOST_STATIC=ON -DGLEW_STATIC=ON -DGLEW_LIBRARY=/usr/lib64/libGLEW.a \
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DDEV_BUILD=1 -DPORTABLE=1 -DTOOLS=1 -DTESTS=1 -DDESKTOP=0 ../..
make
rm -rf install
DESTDIR=. make install
patchelf --set-rpath '.' install/colobot
'''
}
sh 'rm -f linux-debug.zip'
zip zipFile: 'linux-debug.zip', archive: true, dir: 'build/linux/install'
}
stage('Doxygen') {
dir('build/linux') {
sh 'make doc'
}
publishHTML target: [$class: 'HtmlPublisherTarget', reportName: 'Doxygen', reportDir: 'build/linux/doc/html', reportFiles: 'index.html']
}
stage('Run tests') {
dir('build/linux') {
sh './colobot_ut --gtest_output=xml:gtestresults.xml || true'
}
step([$class: 'XUnitBuilder', testTimeMargin: '3000', thresholdMode: 1, thresholds: [[$class: 'FailedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '0'], [$class: 'SkippedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '']], tools: [[$class: 'GoogleTestType', deleteOutputFiles: true, failIfNotNew: true, pattern: 'build/linux/gtestresults.xml', skipNoTestFiles: false, stopProcessingIfError: true]]])
}
// Clean workspace after building pull requests
// to save disk space on the Jenkins host
if (env.BRANCH_NAME.startsWith('PR-')) {
cleanWs()
}
}

View File

@ -6,7 +6,7 @@ This is official repository for the open-source Colobot: Gold Edition project de
The source code contained here was released by Epsitec -- the original creator of the game -- on open source (GPLv3) license. The code was given and the rights granted specifically to ICC community in March 2012. Since then, we have been developing the game further. The source code contained here was released by Epsitec -- the original creator of the game -- on open source (GPLv3) license. The code was given and the rights granted specifically to ICC community in March 2012. Since then, we have been developing the game further.
More information for developers (in English) can be found on the [developer wiki](http://colobot.info/wiki/dev/) or [our forum](http://colobot.info/forum/). However, the freshest source of information is our IRC channels (see below). More information for developers (in English) can be found on [our forum](http://colobot.info/forum/). However, the freshest source of information is our IRC channels (see below).
This repository contains only the source code of the project. The game requires also data files which are now provided as git submodule and are hosted in [separate repository](https://github.com/colobot/colobot-data). This repository contains only the source code of the project. The game requires also data files which are now provided as git submodule and are hosted in [separate repository](https://github.com/colobot/colobot-data).

2
data

@ -1 +1 @@
Subproject commit f96cf394a327210ac9e40d68d68963f25633f758 Subproject commit 2794fd57c32412d4c9103d20c1ec0c888e1e97a0

View File

@ -260,6 +260,19 @@ msgstr ""
msgid "Generating" msgid "Generating"
msgstr "" msgstr ""
msgid "Results"
msgstr ""
msgid "The battle has ended"
msgstr ""
#, c-format
msgid "%s: %d pts"
msgstr ""
msgid "Code battle"
msgstr ""
msgid "Cancel" msgid "Cancel"
msgstr "" msgstr ""
@ -1346,6 +1359,9 @@ msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "" msgstr ""
msgid "This object is currently busy"
msgstr ""
msgid "Impossible when flying" msgid "Impossible when flying"
msgstr "" msgstr ""
@ -1598,6 +1614,18 @@ msgstr ""
msgid "Press \\key help; to read instructions on your SatCom" msgid "Press \\key help; to read instructions on your SatCom"
msgstr "" msgstr ""
#, c-format
msgid "<<< Team %s finished! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s lost! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s recieved %d points >>>"
msgstr ""
msgid "Opening bracket missing" msgid "Opening bracket missing"
msgstr "" msgstr ""
@ -1733,6 +1761,18 @@ msgstr ""
msgid "Ambiguous call to overloaded function" msgid "Ambiguous call to overloaded function"
msgstr "" msgstr ""
msgid "Function needs return type \"void\""
msgstr ""
msgid "Class name expected"
msgstr ""
msgid "Non-void function needs \"return;\""
msgstr ""
msgid "This parameter needs a default value"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "" msgstr ""

286
po/de.po
View File

@ -1,21 +1,21 @@
# SOME DESCRIPTIVE TITLE. # SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # Chris <marius.romanus@gmx.net>, 2016.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: DATE\n" "POT-Creation-Date: DATE\n"
"PO-Revision-Date: 2014-07-28 09:27+0200\n" "PO-Revision-Date: 2016-10-28 21:29+0200\n"
"Last-Translator: krzys_h <krzys_h@interia.pl>\n" "Last-Translator: Chris <marius.romanus@gmx.net>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: Colobot: Gold Edition freelancer\n"
"Language: de\n" "Language: de\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Pootle 2.5.1.1\n" "X-Generator: Virtaal 0.7.1\n"
"X-Language: de_DE\n" "X-Language: de_DE\n"
"X-Source-Language: en_US\n" "X-Source-Language: en_US\n"
"X-POOTLE-MTIME: 1406536037.000000\n" "X-POOTLE-MTIME: 1406536037.000000\n"
@ -29,6 +29,10 @@ msgstr "Es fehlt eine offene eckige Klammer \" [ \""
msgid "\" ] \" missing" msgid "\" ] \" missing"
msgstr "Es fehlt eine geschlossene eckige Klammer \" ] \"" msgstr "Es fehlt eine geschlossene eckige Klammer \" ] \""
#, c-format
msgid "%s: %d pts"
msgstr ""
msgid "..behind" msgid "..behind"
msgstr "..hinten" msgstr "..hinten"
@ -42,7 +46,7 @@ msgid "1) First click on the key you want to redefine."
msgstr "1) Klicken Sie auf die neu zu definierende Taste." msgstr "1) Klicken Sie auf die neu zu definierende Taste."
msgid "2) Then press the key you want to use instead." msgid "2) Then press the key you want to use instead."
msgstr "2) Drücken Sie auf die neue Taste." msgstr "2) Drücken Sie auf die neu zu verwendende Taste."
msgid "<< Back \\Back to the previous screen" msgid "<< Back \\Back to the previous screen"
msgstr "<< Zurück \\Zurück zum Hauptmenü" msgstr "<< Zurück \\Zurück zum Hauptmenü"
@ -50,6 +54,18 @@ msgstr "<< Zurück \\Zurück zum Hauptmenü"
msgid "<<< Sorry; mission failed >>>" msgid "<<< Sorry; mission failed >>>"
msgstr "<<< Mission gescheitert >>>" msgstr "<<< Mission gescheitert >>>"
#, c-format
msgid "<<< Team %s finished! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s lost! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s recieved %d points >>>"
msgstr ""
msgid "<<< Well done; mission accomplished >>>" msgid "<<< Well done; mission accomplished >>>"
msgstr "<<< Bravo, Mission vollendet >>>" msgstr "<<< Bravo, Mission vollendet >>>"
@ -57,7 +73,7 @@ msgid "A label must be followed by \"for\"; \"while\"; \"do\" or \"switch\""
msgstr "Ein Label kann nur vor den Anweisungen \"for\", \"while\", \"do\" oder \"switch\" vorkommen" msgstr "Ein Label kann nur vor den Anweisungen \"for\", \"while\", \"do\" oder \"switch\" vorkommen"
msgid "A variable can not be declared twice" msgid "A variable can not be declared twice"
msgstr "Eine Variable wird zum zweiten Mal deklariert" msgstr "Eine Variable darf nicht zwei Mal deklariert werden"
msgid "Abort\\Abort the current mission" msgid "Abort\\Abort the current mission"
msgstr "Abbrechen\\Mission abbrechen" msgstr "Abbrechen\\Mission abbrechen"
@ -72,7 +88,7 @@ msgid "Access to solutions\\Show program \"4: Solution\" in the exercises"
msgstr "Lösung zugänglich\\Die Lösung ist im Programmslot \"4: Lösung\" zugänglich" msgstr "Lösung zugänglich\\Die Lösung ist im Programmslot \"4: Lösung\" zugänglich"
msgid "Add new program" msgid "Add new program"
msgstr "" msgstr "Neues Programm hinzufügen"
msgid "Alien Queen" msgid "Alien Queen"
msgstr "Insektenkönigin" msgstr "Insektenkönigin"
@ -85,6 +101,8 @@ msgstr "Trägt schon etwas"
msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)" msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)"
msgstr "" msgstr ""
"Alternativer Kameramodus\\Seitwärts bewegen statt rotieren (bei freier "
"Kamera)"
msgid "Ambiguous call to overloaded function" msgid "Ambiguous call to overloaded function"
msgstr "" msgstr ""
@ -99,7 +117,7 @@ msgid "Analyzes only organic matter"
msgstr "Analysiert nur Orgastoff" msgstr "Analysiert nur Orgastoff"
msgid "Anisotropy level\\Anisotropy level" msgid "Anisotropy level\\Anisotropy level"
msgstr "" msgstr "Anisotropie-Level\\Anisotropie-Level"
msgid "Ant" msgid "Ant"
msgstr "Ameise" msgstr "Ameise"
@ -111,7 +129,7 @@ msgid "Appearance\\Choose your appearance"
msgstr "Aussehen\\Erscheinungsbild des Astronauten einstellen" msgstr "Aussehen\\Erscheinungsbild des Astronauten einstellen"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Änderungen ausführen\\Getätigte Einstellungen ausführen" msgstr "Änderungen anwenden\\Getätigte Einstellungen anwenden"
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Es gibt keinen geeigneten Konstruktor" msgstr "Es gibt keinen geeigneten Konstruktor"
@ -127,19 +145,22 @@ msgstr "Automatisches Einrücken\\Beim Bearbeiten der Programme"
msgid "Autosave interval\\How often your game will autosave" msgid "Autosave interval\\How often your game will autosave"
msgstr "" msgstr ""
"Auto-Speichern Zeitintervall\\Wie oft das Spiel automatisch abgespeichert "
"wird"
msgid "Autosave slots\\How many autosave slots you'll have" msgid "Autosave slots\\How many autosave slots you'll have"
msgstr "" msgstr ""
"Auto-Speicherplätze\\Wie viele Plätze zum automatischen Speichern zur "
"Verfügung stehen"
msgid "Autosave\\Enables autosave" msgid "Autosave\\Enables autosave"
msgstr "" msgstr "Auto-Speichern\\Aktiviert die automatische Speicherung"
msgid "Back" msgid "Back"
msgstr "Vorherg. Seite" msgstr "Vorherg. Seite"
#, fuzzy
msgid "Background sound:\\Volume of audio tracks" msgid "Background sound:\\Volume of audio tracks"
msgstr "Geräuschkulisse:\\Lautstärke der Soundtracks der CD" msgstr "Hintergrundgeräusche:\\Lautstärke der Soundtracks"
msgid "Backward (\\key down;)" msgid "Backward (\\key down;)"
msgstr "Rückwärts (\\key down;)" msgstr "Rückwärts (\\key down;)"
@ -157,7 +178,7 @@ msgid "Black box"
msgstr "Flugschreiber" msgstr "Flugschreiber"
msgid "Blood\\Display blood when the astronaut is hit" msgid "Blood\\Display blood when the astronaut is hit"
msgstr "" msgstr "Blut\\Blut anzeigen, wenn der Astronaut verletzt wird"
msgid "Blue" msgid "Blue"
msgstr "Blau" msgstr "Blau"
@ -294,28 +315,25 @@ msgstr "Kamera (\\key camera;)"
msgid "Camera back\\Moves the camera backward" msgid "Camera back\\Moves the camera backward"
msgstr "Kamera weiter\\Bewegung der Kamera rückwärts" msgstr "Kamera weiter\\Bewegung der Kamera rückwärts"
#, fuzzy
msgid "Camera border scrolling\\Scrolling when the mouse touches right or left border" msgid "Camera border scrolling\\Scrolling when the mouse touches right or left border"
msgstr "Kameradrehung mit der Maus\\Die Kamera dreht wenn die Maus den Rand erreicht" msgstr ""
"Kamerabewegung am Bildschirmrand\\Die Kamera dreht wenn die Maus den rechten "
"oder linken Rand erreicht"
msgid "Camera closer\\Moves the camera forward" msgid "Camera closer\\Moves the camera forward"
msgstr "Kamera näher\\Bewegung der Kamera vorwärts" msgstr "Kamera näher\\Bewegung der Kamera vorwärts"
#, fuzzy
msgid "Camera down\\Turns the camera down" msgid "Camera down\\Turns the camera down"
msgstr "Kamera näher\\Bewegung der Kamera vorwärts" msgstr "Kamera ab\\Bewegt die Kamera abwärts"
#, fuzzy
msgid "Camera left\\Turns the camera left" msgid "Camera left\\Turns the camera left"
msgstr "Kamera näher\\Bewegung der Kamera vorwärts" msgstr "Kamera links\\Schwenkt die Kamera nach links"
#, fuzzy
msgid "Camera right\\Turns the camera right" msgid "Camera right\\Turns the camera right"
msgstr "Drehung nach rechts\\Steuer rechts" msgstr "Kamera rechts\\Schwenkt die Kamera nach rechts"
#, fuzzy
msgid "Camera up\\Turns the camera up" msgid "Camera up\\Turns the camera up"
msgstr "Kamera (\\key camera;)" msgstr "Kamera auf\\Bewegt die Kamera aufwärts"
msgid "Can not produce not researched object" msgid "Can not produce not researched object"
msgstr "Das erforschte Objekt kann nicht produziert werden" msgstr "Das erforschte Objekt kann nicht produziert werden"
@ -333,13 +351,13 @@ msgid "Cancel\\Cancel all changes"
msgstr "Abbrechen\\Editor schließen" msgstr "Abbrechen\\Editor schließen"
msgid "Challenges" msgid "Challenges"
msgstr "Challenges" msgstr "Herausforderungen"
msgid "Challenges in the chapter:" msgid "Challenges in the chapter:"
msgstr "Liste der Challenges des Kapitels:" msgstr "Herausforderungen in diesem Kapitel:"
msgid "Challenges\\Programming challenges" msgid "Challenges\\Programming challenges"
msgstr "Challenges\\Herausforderungen" msgstr "Herausforderungen\\Programmieraufgaben"
msgid "Change camera\\Switches between onboard camera and following camera" msgid "Change camera\\Switches between onboard camera and following camera"
msgstr "Andere Kamera\\Sichtpunkt einstellen" msgstr "Andere Kamera\\Sichtpunkt einstellen"
@ -351,20 +369,22 @@ msgid "Chapters:"
msgstr "Liste der Kapitel:" msgstr "Liste der Kapitel:"
msgid "Cheat console\\Show cheat console" msgid "Cheat console\\Show cheat console"
msgstr "" msgstr "Mogel-Konsole\\Zeige die Mogel-Konsole"
msgid "Checkpoint" msgid "Checkpoint"
msgstr "Checkpoint" msgstr "Kontrollstelle"
msgid "Class name expected"
msgstr ""
msgid "Climb\\Increases the power of the jet" msgid "Climb\\Increases the power of the jet"
msgstr "Steigen\\Leistung des Triebwerks steigern" msgstr "Steigen\\Leistung des Triebwerks steigern"
msgid "Clone program" msgid "Clone program"
msgstr "" msgstr "Programm duplizieren"
#, fuzzy
msgid "Clone selected program" msgid "Clone selected program"
msgstr "Gewähltes Programm bearbeiten" msgstr "Gewähltes Programm duplizieren"
msgid "Close" msgid "Close"
msgstr "Schließen" msgstr "Schließen"
@ -372,11 +392,14 @@ msgstr "Schließen"
msgid "Closing bracket missing" msgid "Closing bracket missing"
msgstr "Es fehlt eine geschlossene Klammer \")\"" msgstr "Es fehlt eine geschlossene Klammer \")\""
msgid "Code battles" msgid "Code battle"
msgstr "" msgstr ""
msgid "Code battles"
msgstr "Programmierschlacht"
msgid "Code battles\\Program your robot to be the best of them all!" msgid "Code battles\\Program your robot to be the best of them all!"
msgstr "" msgstr "Programmierschlacht\\Schreibe das Programm für den besten Roboter!"
msgid "Colobot rules!" msgid "Colobot rules!"
msgstr "Colobot ist wunderbar!" msgstr "Colobot ist wunderbar!"
@ -385,7 +408,7 @@ msgid "Colobot: Gold Edition"
msgstr "Colobot: Gold Edition" msgstr "Colobot: Gold Edition"
msgid "Command line" msgid "Command line"
msgstr "Befehleingabe" msgstr "Befehlseingabe"
msgid "Compilation ok (0 errors)" msgid "Compilation ok (0 errors)"
msgstr "Kompilieren OK (0 Fehler)" msgstr "Kompilieren OK (0 Fehler)"
@ -403,7 +426,7 @@ msgid "Controls\\Keyboard, joystick and mouse settings"
msgstr "Steuerung\\Auswahl der Tasten" msgstr "Steuerung\\Auswahl der Tasten"
msgid "Converts ore to titanium" msgid "Converts ore to titanium"
msgstr "Konverter Erz-Titan" msgstr "Konvertiert Erz in Titan"
msgid "Copy" msgid "Copy"
msgstr "Kopieren" msgstr "Kopieren"
@ -414,12 +437,11 @@ msgstr "Kopieren (Ctrl+C)"
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Mission gespeichert" msgstr "Mission gespeichert"
#, fuzzy
msgid "Custom levels:" msgid "Custom levels:"
msgstr "Userlevels:" msgstr "Benutzerdefinierte Level:"
msgid "Custom levels\\Levels from mods created by the users" msgid "Custom levels\\Levels from mods created by the users"
msgstr "" msgstr "Benutzerdefinierte Level\\Level die von anderen Spieler erstellt wurden"
msgid "Customize your appearance" msgid "Customize your appearance"
msgstr "Aussehen einstellen" msgstr "Aussehen einstellen"
@ -430,9 +452,8 @@ msgstr "Ausschneiden (Ctrl+X)"
msgid "Defense tower" msgid "Defense tower"
msgstr "Geschützturm" msgstr "Geschützturm"
#, fuzzy
msgid "Delete mark" msgid "Delete mark"
msgstr "Zerstören" msgstr "Markierung entfernen"
msgid "Delete player\\Deletes the player from the list" msgid "Delete player\\Deletes the player from the list"
msgstr "Spieler löschen\\Löscht den Spieler aus der Liste" msgstr "Spieler löschen\\Löscht den Spieler aus der Liste"
@ -459,7 +480,7 @@ msgid "Device\\Driver and resolution settings"
msgstr "Bildschirm\\Driver und Bildschirmauflösung" msgstr "Bildschirm\\Driver und Bildschirmauflösung"
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Teilung durch Null" msgstr "Division durch Null"
msgid "Do you really want to destroy the selected building?" msgid "Do you really want to destroy the selected building?"
msgstr "Wollen Sie das angewählte Gebäude wirklich zerstören ?" msgstr "Wollen Sie das angewählte Gebäude wirklich zerstören ?"
@ -484,10 +505,10 @@ msgid "Dynamic lighting\\Mobile light sources"
msgstr "Dynamische Beleuchtung\\Dynamische Beleuchtung" msgstr "Dynamische Beleuchtung\\Dynamische Beleuchtung"
msgid "Dynamic shadows ++\\Dynamic shadows + self shadowing" msgid "Dynamic shadows ++\\Dynamic shadows + self shadowing"
msgstr "" msgstr "Dynamische Schatten ++\\Dynamische Schatten + Eigenschatten"
msgid "Dynamic shadows\\Beautiful shadows!" msgid "Dynamic shadows\\Beautiful shadows!"
msgstr "" msgstr "Dynamische Schatten\\Hübsche Schatten!"
msgid "Edit the selected program" msgid "Edit the selected program"
msgstr "Gewähltes Programm bearbeiten" msgstr "Gewähltes Programm bearbeiten"
@ -529,7 +550,7 @@ msgid "Explosive"
msgstr "Sprengstoff" msgstr "Sprengstoff"
msgid "Expression expected after =" msgid "Expression expected after ="
msgstr "" msgstr "Nach = wird ein Ausdruck erwartet"
msgid "Extend shield (\\key action;)" msgid "Extend shield (\\key action;)"
msgstr "Schutzschild ausfahren (\\key action;)" msgstr "Schutzschild ausfahren (\\key action;)"
@ -556,7 +577,7 @@ msgid "Fixed mine"
msgstr "Landmine" msgstr "Landmine"
msgid "Flat ground not large enough" msgid "Flat ground not large enough"
msgstr "Ebener Boden nicht groß genug" msgstr "Ebene Fläche nicht groß genug"
msgid "Fog\\Fog" msgid "Fog\\Fog"
msgstr "Nebel\\Nebelschwaden" msgstr "Nebel\\Nebelschwaden"
@ -569,7 +590,7 @@ msgid "Folder: %s"
msgstr "Ordner: %s" msgstr "Ordner: %s"
msgid "Font size" msgid "Font size"
msgstr "Zeichengröße" msgstr "Schriftgröße"
msgid "Forward" msgid "Forward"
msgstr "Nächste Seite" msgstr "Nächste Seite"
@ -599,13 +620,13 @@ msgid "Found key D (site for derrick)"
msgstr "Markierung für vergrabenen Schlüssel D" msgstr "Markierung für vergrabenen Schlüssel D"
msgid "Free game" msgid "Free game"
msgstr "Freestyle" msgstr "Freies Spiel"
msgid "Free game on this planet:" msgid "Free game on this planet:"
msgstr "Liste der freien Levels des Planeten:" msgstr "Liste der freien Levels des Planeten:"
msgid "Free game\\Free game without a specific goal" msgid "Free game\\Free game without a specific goal"
msgstr "Freestyle\\Freies Spielen ohne vorgegebenes Ziel" msgstr "Freies Spiel\\Freies Spielen ohne vorgegebenes Ziel"
msgid "Full screen\\Full screen or window mode" msgid "Full screen\\Full screen or window mode"
msgstr "Vollbildschirm\\Vollbildschirm oder Fenster" msgstr "Vollbildschirm\\Vollbildschirm oder Fenster"
@ -616,6 +637,9 @@ msgstr "Diese Funktion gibt es schon"
msgid "Function name missing" msgid "Function name missing"
msgstr "Hier muss der Name der Funktion stehen" msgstr "Hier muss der Name der Funktion stehen"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed" msgid "Game speed"
msgstr "Spielgeschwindigkeit" msgstr "Spielgeschwindigkeit"
@ -626,10 +650,10 @@ msgid "Gantry crane"
msgstr "Träger" msgstr "Träger"
msgid "Generating" msgid "Generating"
msgstr "" msgstr "Generieren"
msgid "Gold Edition development by:" msgid "Gold Edition development by:"
msgstr "Goldausgabe Entwicklung von:" msgstr "Gold-Edition entwickelt von:"
msgid "Goto: destination occupied" msgid "Goto: destination occupied"
msgstr "Ziel ist schon besetzt" msgstr "Ziel ist schon besetzt"
@ -641,7 +665,7 @@ msgid "Grab or drop (\\key action;)"
msgstr "Nehmen oder hinlegen (\\key action;)" msgstr "Nehmen oder hinlegen (\\key action;)"
msgid "Graphics\\Graphics settings" msgid "Graphics\\Graphics settings"
msgstr "Grafik\\Grafische Einstellungen" msgstr "Grafik\\Grafik-Einstellungen"
msgid "Green" msgid "Green"
msgstr "Grün" msgstr "Grün"
@ -662,7 +686,7 @@ msgid "Help about selected object"
msgstr "Anweisungen über das ausgewählte Objekt" msgstr "Anweisungen über das ausgewählte Objekt"
msgid "Help balloons\\Explain the function of the buttons" msgid "Help balloons\\Explain the function of the buttons"
msgstr "Hilfsblasen\\Hilfsblasen" msgstr "Hilfeblasen\\Hilfeblasen"
msgid "Highest\\Highest graphic quality (lowest frame rate)" msgid "Highest\\Highest graphic quality (lowest frame rate)"
msgstr "Max.\\Beste Qualität (niedriges Framerate)" msgstr "Max.\\Beste Qualität (niedriges Framerate)"
@ -697,9 +721,8 @@ msgstr "Roboter ungeeignet"
msgid "Inappropriate cell type" msgid "Inappropriate cell type"
msgstr "Falscher Batterietyp" msgstr "Falscher Batterietyp"
#, fuzzy
msgid "Inappropriate object" msgid "Inappropriate object"
msgstr "Roboter ungeeignet" msgstr "Objekt ungeeignet"
msgid "Incorrect index type" msgid "Incorrect index type"
msgstr "Falscher Typ für einen Index" msgstr "Falscher Typ für einen Index"
@ -738,10 +761,10 @@ msgid "Instructions\\Shows the instructions for the current mission"
msgstr "Anweisungen\\Anweisungen für die Mission oder Übung" msgstr "Anweisungen\\Anweisungen für die Mission oder Übung"
msgid "Internal error - tell the developers" msgid "Internal error - tell the developers"
msgstr "Interner Fehler - Benachrichtige die Entwickler" msgstr "Interner Fehler - Benachrichtige bitte die Entwickler"
msgid "Invert\\Invert values on this axis" msgid "Invert\\Invert values on this axis"
msgstr "" msgstr "Invertieren\\Die Werte dieser Achse invertieren"
msgid "Jet temperature" msgid "Jet temperature"
msgstr "Triebwerktemperatur" msgstr "Triebwerktemperatur"
@ -801,39 +824,37 @@ msgid "Load\\Loads the selected mission"
msgstr "Laden\\Öffnet eine gespeicherte Mission" msgstr "Laden\\Öffnet eine gespeicherte Mission"
msgid "Loading basic level settings" msgid "Loading basic level settings"
msgstr "" msgstr "Lade Level-Grundeinstellungen"
#, fuzzy
msgid "Loading finished!" msgid "Loading finished!"
msgstr "Programm beendet" msgstr "Laden beendet!"
msgid "Loading music" msgid "Loading music"
msgstr "" msgstr "Lade Musik"
#, fuzzy
msgid "Loading objects" msgid "Loading objects"
msgstr "Liste der Objekte" msgstr "Lade Objekte"
msgid "Loading terrain" msgid "Loading terrain"
msgstr "" msgstr "Lade Gelände"
msgid "Lowest\\Minimum graphic quality (highest frame rate)" msgid "Lowest\\Minimum graphic quality (highest frame rate)"
msgstr "Min.\\Minimale Qualität (großes Framerate)" msgstr "Min.\\Minimale Qualität (großes Framerate)"
msgid "Lunar Roving Vehicle" msgid "Lunar Roving Vehicle"
msgstr "Lunar Roving Vehicle" msgstr "Mondlandefahrzeug"
msgid "MSAA\\Multisample anti-aliasing" msgid "MSAA\\Multisample anti-aliasing"
msgstr "" msgstr "MSAA\\Multisample anti-aliasing"
msgid "Maximize" msgid "Maximize"
msgstr "Großes Fenster" msgstr "Großes Fenster"
msgid "Minimize" msgid "Minimize"
msgstr "Reduzieren" msgstr "Verkleinern"
msgid "Mipmap level\\Mipmap level" msgid "Mipmap level\\Mipmap level"
msgstr "" msgstr "Mipmap-Level\\Mipmap-Level"
msgid "Mission name" msgid "Mission name"
msgstr "Name der Mission" msgstr "Name der Mission"
@ -853,13 +874,11 @@ msgstr "Umkehr X\\Umkehr der Kameradrehung X-Achse"
msgid "Mouse inversion Y\\Inversion of the scrolling direction on the Y axis" msgid "Mouse inversion Y\\Inversion of the scrolling direction on the Y axis"
msgstr "Umkehr Y\\Umkehr der Kameradrehung Y-Achse" msgstr "Umkehr Y\\Umkehr der Kameradrehung Y-Achse"
#, fuzzy
msgid "Move selected program down" msgid "Move selected program down"
msgstr "Gewähltes Programm bearbeiten" msgstr "Gewähltes Programm nach unten"
#, fuzzy
msgid "Move selected program up" msgid "Move selected program up"
msgstr "Gewähltes Programm bearbeiten" msgstr "Gewähltes Programm nach oben"
msgid "Mute\\No sound" msgid "Mute\\No sound"
msgstr "Kein Ton\\Keine Geräusche und Geräuschkulisse" msgstr "Kein Ton\\Keine Geräusche und Geräuschkulisse"
@ -889,7 +908,7 @@ msgid "Next object\\Selects the next object"
msgstr "Nächstes auswählen\\Nächstes Objekt auswählen" msgstr "Nächstes auswählen\\Nächstes Objekt auswählen"
msgid "No" msgid "No"
msgstr "" msgstr "Nein"
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Kein unterirdisches Energievorkommen" msgstr "Kein unterirdisches Energievorkommen"
@ -901,10 +920,10 @@ msgid "No function running"
msgstr "Keine Funktion wird ausgeführt" msgstr "Keine Funktion wird ausgeführt"
msgid "No function with this name accepts this kind of parameter" msgid "No function with this name accepts this kind of parameter"
msgstr "Keine Funktion mit diesem Namen verträgt Parameter diesen Typs" msgstr "Keine Funktion mit diesem Namen akzeptiert Parameter diesen Typs"
msgid "No function with this name accepts this number of parameters" msgid "No function with this name accepts this number of parameters"
msgstr "Keine Funktion mit diesem Namen verträgt diese Anzahl Parameter" msgstr "Keine Funktion mit diesem Namen akzeptiert diese Anzahl Parameter"
msgid "No information exchange post within range" msgid "No information exchange post within range"
msgstr "Kein Infoserver in Reichweite" msgstr "Kein Infoserver in Reichweite"
@ -934,6 +953,9 @@ msgid "No uranium to transform"
msgstr "Kein konvertierbares Platin" msgstr "Kein konvertierbares Platin"
msgid "No userlevels installed!" msgid "No userlevels installed!"
msgstr "Keine benutzerdefinierten Level vorhanden"
msgid "Non-void function needs \"return;\""
msgstr "" msgstr ""
msgid "Normal size" msgid "Normal size"
@ -1012,7 +1034,7 @@ msgid "Opening bracket missing"
msgstr "Es fehlt eine offene Klammer \"(\"" msgstr "Es fehlt eine offene Klammer \"(\""
msgid "Operation impossible with value \"nan\"" msgid "Operation impossible with value \"nan\""
msgstr "Operation mit dem Wert \"nan\"" msgstr "Operation mit dem Wert \"nan\" nicht möglich"
msgid "Options" msgid "Options"
msgstr "Einstellungen" msgstr "Einstellungen"
@ -1039,16 +1061,18 @@ msgid "Paste (Ctrl+V)"
msgstr "Einfügen (Ctrl+V)" msgstr "Einfügen (Ctrl+V)"
msgid "Pause blur\\Blur the background on the pause screen" msgid "Pause blur\\Blur the background on the pause screen"
msgstr "" msgstr "Pausen-Unschärfe\\Während der Pause den Hintergrund unscharf zeichnen"
msgid "Pause in background\\Pause the game when the window is unfocused" msgid "Pause in background\\Pause the game when the window is unfocused"
msgstr "" msgstr ""
"Pausieren im Hintergrund\\Spiel anhalten,enn das Spielfenster im Hintergrund "
"ist"
msgid "Pause/continue" msgid "Pause/continue"
msgstr "Pause/Weitermachen" msgstr "Pause/Weitermachen"
msgid "Pause\\Pause the game without opening menu" msgid "Pause\\Pause the game without opening menu"
msgstr "" msgstr "Pause\\Spiel pausieren, ohne das Menü zu öffnen"
msgid "Phazer shooter" msgid "Phazer shooter"
msgstr "Phazershooter" msgstr "Phazershooter"
@ -1093,10 +1117,10 @@ msgid "Player"
msgstr "Spieler" msgstr "Spieler"
msgid "Player name" msgid "Player name"
msgstr "Name " msgstr "Spielername "
msgid "Player's name" msgid "Player's name"
msgstr "Name " msgstr "Name des Spielers"
msgid "Power cell" msgid "Power cell"
msgstr "Elektrolytische Batterie" msgstr "Elektrolytische Batterie"
@ -1117,7 +1141,7 @@ msgid "Press \\key help; to read instructions on your SatCom"
msgstr "Beziehen Sie sich auf Ihren SatCom, indem Sie auf \\key help; drücken" msgstr "Beziehen Sie sich auf Ihren SatCom, indem Sie auf \\key help; drücken"
msgid "Previous" msgid "Previous"
msgstr "Vorherg" msgstr "Vorherg."
msgid "Previous object\\Selects the previous object" msgid "Previous object\\Selects the previous object"
msgstr "Vorherg. Auswahl\\Das vorhergehende Objekt auswählen" msgstr "Vorherg. Auswahl\\Das vorhergehende Objekt auswählen"
@ -1132,11 +1156,10 @@ msgid "Private\\Private folder"
msgstr "Privat\\Privater Ordner" msgstr "Privat\\Privater Ordner"
msgid "Processing level file" msgid "Processing level file"
msgstr "" msgstr "Verarbeite Level-Datei"
#, fuzzy
msgid "Program cloned" msgid "Program cloned"
msgstr "Programm beendet" msgstr "Programm dupliziert"
msgid "Program editor" msgid "Program editor"
msgstr "Programmeditor" msgstr "Programmeditor"
@ -1172,7 +1195,7 @@ msgid "Quake at explosions\\The screen shakes at explosions"
msgstr "Beben bei Explosionen\\Die Kamera bebt bei Explosionen" msgstr "Beben bei Explosionen\\Die Kamera bebt bei Explosionen"
msgid "Quit\\Quit Colobot: Gold Edition" msgid "Quit\\Quit Colobot: Gold Edition"
msgstr "" msgstr "Beenden\\Colobot: Gold Edition schließen"
msgid "Quit\\Quit the current mission or exercise" msgid "Quit\\Quit the current mission or exercise"
msgstr "Mission verlassen\\Eine Mission oder Übung verlassen" msgstr "Mission verlassen\\Eine Mission oder Übung verlassen"
@ -1207,11 +1230,9 @@ msgstr "Überreste einer Apollo-Mission"
msgid "Remove a flag" msgid "Remove a flag"
msgstr "Sammelt die Fahne ein" msgstr "Sammelt die Fahne ein"
#, fuzzy
msgid "Remove selected program" msgid "Remove selected program"
msgstr "Gewähltes Programm bearbeiten" msgstr "Gewähltes Programm entfernen"
#, fuzzy
msgid "Render distance\\Maximum visibility" msgid "Render distance\\Maximum visibility"
msgstr "Sichtweite\\Maximale Sichtweite" msgstr "Sichtweite\\Maximale Sichtweite"
@ -1227,9 +1248,8 @@ msgstr "Forschungsprogramm schon ausgeführt"
msgid "Research program completed" msgid "Research program completed"
msgstr "Forschungsprogramm abgeschlossen" msgstr "Forschungsprogramm abgeschlossen"
#, fuzzy
msgid "Reserved keyword of CBOT language" msgid "Reserved keyword of CBOT language"
msgstr "Dieses Wort ist reserviert" msgstr "Reserviertes Schlüsselwort in der CBOT Sprache"
msgid "Resolution" msgid "Resolution"
msgstr "Auflösung" msgstr "Auflösung"
@ -1238,15 +1258,18 @@ msgid "Resolution:"
msgstr "Auflösung:" msgstr "Auflösung:"
msgid "Resources" msgid "Resources"
msgstr "" msgstr "Ressourcen"
msgid "Restart\\Restart the mission from the beginning" msgid "Restart\\Restart the mission from the beginning"
msgstr "Neu anfangen\\Die Mission von vorne anfangen" msgstr "Neu anfangen\\Die Mission von vorne anfangen"
msgid "Restoring CBot execution state" msgid "Restoring CBot execution state"
msgstr "" msgstr "CBOT Ausführungsstatus wiederherstellen"
msgid "Restoring saved objects" msgid "Restoring saved objects"
msgstr "Gespeicherte Objekte wiederherstellen"
msgid "Results"
msgstr "" msgstr ""
msgid "Return to start" msgid "Return to start"
@ -1316,10 +1339,10 @@ msgid "Semicolon terminator missing"
msgstr "Es fehlt ein Strichpunkt \";\" am Ende der Anweisung" msgstr "Es fehlt ein Strichpunkt \";\" am Ende der Anweisung"
msgid "Shadow resolution\\Higher means better range and quality, but slower" msgid "Shadow resolution\\Higher means better range and quality, but slower"
msgstr "" msgstr "Schatten-Auflösung\\Höher heißt bessere Qualität, aber langsamer"
msgid "Shield level" msgid "Shield level"
msgstr "Schäden" msgstr "Schildstärke"
msgid "Shield radius" msgid "Shield radius"
msgstr "Reichweite Schutzschild" msgstr "Reichweite Schutzschild"
@ -1345,9 +1368,8 @@ msgstr "Zeigt die Lösung"
msgid "Sign \" : \" missing" msgid "Sign \" : \" missing"
msgstr "Es fehlt ein Doppelpunkt \" : \"" msgstr "Es fehlt ein Doppelpunkt \" : \""
#, fuzzy
msgid "Simple shadows\\Shadows spots on the ground" msgid "Simple shadows\\Shadows spots on the ground"
msgstr "Schatten\\Schlagschatten auf dem Boden" msgstr "Einfacher Schatten\\Schlagschatten auf dem Boden"
msgid "Size 1" msgid "Size 1"
msgstr "Größe 1" msgstr "Größe 1"
@ -1380,11 +1402,10 @@ msgid "Spaceship"
msgstr "Raumschiff" msgstr "Raumschiff"
msgid "Spaceship ruin" msgid "Spaceship ruin"
msgstr "Raumschiffruine" msgstr "Raumschiffswrack"
#, fuzzy
msgid "Speed 0.5x\\Half speed" msgid "Speed 0.5x\\Half speed"
msgstr "Geschwindigkeit 1.0x\\Normale Spielgeschwindigkeit" msgstr "Geschwindigkeit 0.5x\\Halbe Spielgeschwindigkeit"
msgid "Speed 1.0x\\Normal speed" msgid "Speed 1.0x\\Normal speed"
msgstr "Geschwindigkeit 1.0x\\Normale Spielgeschwindigkeit" msgstr "Geschwindigkeit 1.0x\\Normale Spielgeschwindigkeit"
@ -1395,17 +1416,14 @@ msgstr "Geschwindigkeit 1.5x\\Spielgeschwindigkeit anderthalb Mal schneller"
msgid "Speed 2.0x\\Double speed" msgid "Speed 2.0x\\Double speed"
msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell" msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell"
#, fuzzy
msgid "Speed 3.0x\\Triple speed" msgid "Speed 3.0x\\Triple speed"
msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell" msgstr "Geschwindigkeit 3.0x\\Dreifache Spielgeschwindigkeit"
#, fuzzy
msgid "Speed 4.0x\\Quadruple speed" msgid "Speed 4.0x\\Quadruple speed"
msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell" msgstr "Geschwindigkeit 4.0x\\Vierfache Spielgeschwindigkeit"
#, fuzzy
msgid "Speed 6.0x\\Sextuple speed" msgid "Speed 6.0x\\Sextuple speed"
msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell" msgstr "Geschwindigkeit 6.0x\\Sechsfache Spielgeschwindigkeit"
msgid "Spider" msgid "Spider"
msgstr "Spinne" msgstr "Spinne"
@ -1428,12 +1446,11 @@ msgstr "Standard\\Standardfarben einsetzen"
msgid "Start" msgid "Start"
msgstr "Startfläche" msgstr "Startfläche"
#, fuzzy
msgid "Starting..." msgid "Starting..."
msgstr "Startfläche" msgstr "Starte..."
msgid "Still working ..." msgid "Still working ..."
msgstr "Prozess im Gang ..." msgstr "Verarbeitung ..."
msgid "String missing" msgid "String missing"
msgstr "Hier wird eine Zeichenkette erwartet" msgstr "Hier wird eine Zeichenkette erwartet"
@ -1469,12 +1486,15 @@ msgid "Target bot"
msgstr "Mobile Zielscheibe" msgstr "Mobile Zielscheibe"
msgid "Terrain relief" msgid "Terrain relief"
msgstr "" msgstr "Geländestruktur"
msgid "Texture filtering\\Texture filtering" msgid "Texture filtering\\Texture filtering"
msgstr "" msgstr "Texturfilterung\\Texturfilterung"
msgid "Textures" msgid "Textures"
msgstr "Texturen"
msgid "The battle has ended"
msgstr "" msgstr ""
msgid "The expression must return a boolean value" msgid "The expression must return a boolean value"
@ -1496,7 +1516,7 @@ msgid "This class does not exist"
msgstr "Diese Klasse existiert nicht" msgstr "Diese Klasse existiert nicht"
msgid "This is example code that cannot be run directly" msgid "This is example code that cannot be run directly"
msgstr "" msgstr "Das ist ein Beispiel Programm, das nicht direkt ausgeführt werden kann"
msgid "This is not a member of this class" msgid "This is not a member of this class"
msgstr "Dieses Element gibt es nicht in dieser Klasse" msgstr "Dieses Element gibt es nicht in dieser Klasse"
@ -1506,13 +1526,21 @@ msgstr "Dieses Label existiert nicht"
msgid "This menu is for userlevels from mods, but you didn't install any" msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr "" msgstr ""
"Dieses Menü ist für nachinstallierte Benutzer-Level, aber Du hast keine "
"installiert"
msgid "This object is currently busy"
msgstr ""
msgid "This object is not a member of a class" msgid "This object is not a member of a class"
msgstr "Das Objekt ist nicht eine Instanz einer Klasse" msgstr "Das Objekt ist nicht eine Instanz einer Klasse"
msgid "This program is read-only, clone it to edit" msgid "This parameter needs a default value"
msgstr "" msgstr ""
msgid "This program is read-only, clone it to edit"
msgstr "Dieses Programm ist schreibgeschützt. Dupliziere es zum Bearbeiten"
msgid "Thump (\\key action;)" msgid "Thump (\\key action;)"
msgstr "Stampfen (\\key action;)" msgstr "Stampfen (\\key action;)"
@ -1589,10 +1617,10 @@ msgid "Type declaration missing"
msgstr "Hier muss ein Variablentyp stehen" msgstr "Hier muss ein Variablentyp stehen"
msgid "Unable to control enemy objects" msgid "Unable to control enemy objects"
msgstr "" msgstr "Feindliches Objekt kann nicht gesteuert werden"
msgid "Undo (Ctrl+Z)" msgid "Undo (Ctrl+Z)"
msgstr "Widerrufen (Ctrl+Z)" msgstr "Rückgängig (Ctrl+Z)"
msgid "Unit" msgid "Unit"
msgstr "Einheit" msgstr "Einheit"
@ -1691,7 +1719,7 @@ msgid "Yellow flag"
msgstr "Gelbe Fahne" msgstr "Gelbe Fahne"
msgid "Yes" msgid "Yes"
msgstr "" msgstr "Ja"
msgid "You can fly with the keys (\\key gup;) and (\\key gdown;)" msgid "You can fly with the keys (\\key gup;) and (\\key gdown;)"
msgstr "Sie können jetzt mit den Tasten \\key gup; und \\key gdown; fliegen" msgstr "Sie können jetzt mit den Tasten \\key gup; und \\key gdown; fliegen"
@ -1702,27 +1730,35 @@ msgstr "Sie können keinen radioaktiven Gegenstand tragen"
msgid "You can not carry an object under water" msgid "You can not carry an object under water"
msgstr "Sie können unter Wasser nichts tragen" msgstr "Sie können unter Wasser nichts tragen"
#, fuzzy, c-format #, c-format
msgid "You cannot use \"%s\" in this exercise (used: %d)" msgid "You cannot use \"%s\" in this exercise (used: %d)"
msgstr "In dieser Übung verboten" msgstr "\"%s\" kann in dieser Übung nicht verwendet werden (benutzt: %d)"
msgid "You found a usable object" msgid "You found a usable object"
msgstr "Sie haben ein brauchbares Objekt gefunden" msgstr "Sie haben ein brauchbares Objekt gefunden"
#, fuzzy, c-format #, c-format
msgid "You have to use \"%1$s\" at least once in this exercise (used: %2$d)" msgid "You have to use \"%1$s\" at least once in this exercise (used: %2$d)"
msgid_plural "You have to use \"%1$s\" at least %3$d times in this exercise (used: %2$d)" msgid_plural "You have to use \"%1$s\" at least %3$d times in this exercise (used: %2$d)"
msgstr[0] "In dieser Übung verboten" msgstr[0] ""
msgstr[1] "In dieser Übung verboten" "In dieser Übung \"%1$s\" muß mindestens einmal verwendet werden (benutzt: %"
"2$d)"
msgstr[1] ""
"In dieser Übung muß \"%1$s\" mindestes %3$d Mal verwendet werden (benutzt: %"
"2$d)"
#, fuzzy, c-format #, c-format
msgid "You have to use \"%1$s\" at most once in this exercise (used: %2$d)" msgid "You have to use \"%1$s\" at most once in this exercise (used: %2$d)"
msgid_plural "You have to use \"%1$s\" at most %3$d times in this exercise (used: %2$d)" msgid_plural "You have to use \"%1$s\" at most %3$d times in this exercise (used: %2$d)"
msgstr[0] "In dieser Übung verboten" msgstr[0] ""
msgstr[1] "In dieser Übung verboten" "In dieser Übung darf \"%1$s\" höchstens einmal verwendet werden (benutzt: %"
"2$d)"
msgstr[1] ""
"In dieser Übung darf \"%1$s\" höchstens %3$d Mal verwendet werden (benutzt: %"
"2$d)"
msgid "You must get on the spaceship to take off" msgid "You must get on the spaceship to take off"
msgstr "Gehen Sie an Bord, bevor Sie abheben" msgstr "Begib Dich an Bord, bevor Du abhebst"
msgid "Zoom mini-map" msgid "Zoom mini-map"
msgstr "Zoom Minikarte" msgstr "Zoom Minikarte"
@ -1773,7 +1809,7 @@ msgid "\\Red flags"
msgstr "\\Rote Fahne" msgstr "\\Rote Fahne"
msgid "\\Return to Colobot: Gold Edition" msgid "\\Return to Colobot: Gold Edition"
msgstr "" msgstr "\\Zurück zu Colobot: Gold-Edition"
msgid "\\SatCom on standby" msgid "\\SatCom on standby"
msgstr "\\SatCom in Standby" msgstr "\\SatCom in Standby"

View File

@ -1,11 +1,12 @@
# Didier Raboud <odyx@debian.org>, 2012, 2015, 2016. # Didier Raboud <odyx@debian.org>, 2012, 2015, 2016.
# Martin Quinson <mquinson@debian.org>, 2016
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Colobot 0.1.6\n" "Project-Id-Version: Colobot 0.1.6\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: DATE\n" "POT-Creation-Date: DATE\n"
"PO-Revision-Date: 2016-03-25 15:01+0100\n" "PO-Revision-Date: 2016-12-02 15:31+0100\n"
"Last-Translator: Didier Raboud <odyx@debian.org>\n" "Last-Translator: Martin Quinson <mquinson@debian.org>\n"
"Language: fr\n" "Language: fr\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@ -24,6 +25,10 @@ msgstr "\" [ \" attendu"
msgid "\" ] \" missing" msgid "\" ] \" missing"
msgstr "\" ] \" attendu" msgstr "\" ] \" attendu"
#, c-format
msgid "%s: %d pts"
msgstr ""
msgid "..behind" msgid "..behind"
msgstr "..derrière" msgstr "..derrière"
@ -45,6 +50,18 @@ msgstr "<< Retour \\Retour au niveau précédent"
msgid "<<< Sorry; mission failed >>>" msgid "<<< Sorry; mission failed >>>"
msgstr "<<< Désolé; mission échouée >>>" msgstr "<<< Désolé; mission échouée >>>"
#, c-format
msgid "<<< Team %s finished! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s lost! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s recieved %d points >>>"
msgstr ""
msgid "<<< Well done; mission accomplished >>>" msgid "<<< Well done; mission accomplished >>>"
msgstr "<<< Bravo; mission terminée >>>" msgstr "<<< Bravo; mission terminée >>>"
@ -79,10 +96,10 @@ msgid "Already carrying something"
msgstr "Porte déjà quelque chose" msgstr "Porte déjà quelque chose"
msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)" msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)"
msgstr "" msgstr "Mode caméra alternatif\\Déplacements latéraux au lieu des rotations (pour la caméra libre)"
msgid "Ambiguous call to overloaded function" msgid "Ambiguous call to overloaded function"
msgstr "" msgstr "Appel ambigu à une fonction surchargée"
msgid "Analysis already performed" msgid "Analysis already performed"
msgstr "Analyse déjà effectuée" msgstr "Analyse déjà effectuée"
@ -294,21 +311,17 @@ msgstr "Défilement dans les bords\\Défilement lorsque la souris touche les bor
msgid "Camera closer\\Moves the camera forward" msgid "Camera closer\\Moves the camera forward"
msgstr "Caméra plus proche\\Avance la caméra" msgstr "Caméra plus proche\\Avance la caméra"
#, fuzzy
msgid "Camera down\\Turns the camera down" msgid "Camera down\\Turns the camera down"
msgstr "Caméra plus proche\\Avance la caméra" msgstr "Baisser caméra\\Baisse la caméra"
#, fuzzy
msgid "Camera left\\Turns the camera left" msgid "Camera left\\Turns the camera left"
msgstr "Caméra plus proche\\Avance la caméra" msgstr "Caméra à gauche\\Tourne la caméra vers la gauche"
#, fuzzy
msgid "Camera right\\Turns the camera right" msgid "Camera right\\Turns the camera right"
msgstr "Tourner à droite\\Moteur à droite" msgstr "Caméra à droite\\Tourne la caméra vers la droite"
#, fuzzy
msgid "Camera up\\Turns the camera up" msgid "Camera up\\Turns the camera up"
msgstr "Caméra (\\key camera;)" msgstr "Lever caméra\\Monte la caméra"
msgid "Can not produce not researched object" msgid "Can not produce not researched object"
msgstr "Impossible de créer un objet n'ayant pas été recherché" msgstr "Impossible de créer un objet n'ayant pas été recherché"
@ -349,6 +362,9 @@ msgstr "Console de triche\\Montre la console de triche"
msgid "Checkpoint" msgid "Checkpoint"
msgstr "Indicateur" msgstr "Indicateur"
msgid "Class name expected"
msgstr ""
msgid "Climb\\Increases the power of the jet" msgid "Climb\\Increases the power of the jet"
msgstr "Monter\\Augmenter la puissance du réacteur" msgstr "Monter\\Augmenter la puissance du réacteur"
@ -364,6 +380,10 @@ msgstr "Fermer"
msgid "Closing bracket missing" msgid "Closing bracket missing"
msgstr "Il manque une parenthèse fermante" msgstr "Il manque une parenthèse fermante"
#, fuzzy
msgid "Code battle"
msgstr "Batailles de code"
msgid "Code battles" msgid "Code battles"
msgstr "Batailles de code" msgstr "Batailles de code"
@ -519,7 +539,7 @@ msgid "Explosive"
msgstr "Explosif" msgstr "Explosif"
msgid "Expression expected after =" msgid "Expression expected after ="
msgstr "" msgstr "Expression attendue après ="
msgid "Extend shield (\\key action;)" msgid "Extend shield (\\key action;)"
msgstr "Déploie le bouclier (\\key action;)" msgstr "Déploie le bouclier (\\key action;)"
@ -606,6 +626,9 @@ msgstr "Cette fonction existe déjà"
msgid "Function name missing" msgid "Function name missing"
msgstr "Nom de la fonction attendu" msgstr "Nom de la fonction attendu"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed" msgid "Game speed"
msgstr "Vitesse du jeu" msgstr "Vitesse du jeu"
@ -730,7 +753,7 @@ msgid "Internal error - tell the developers"
msgstr "Erreur interne - contacter les développeurs" msgstr "Erreur interne - contacter les développeurs"
msgid "Invert\\Invert values on this axis" msgid "Invert\\Invert values on this axis"
msgstr "" msgstr "Inversion\\Inverse les valeurs sur cet axe"
msgid "Jet temperature" msgid "Jet temperature"
msgstr "Température du réacteur" msgstr "Température du réacteur"
@ -921,6 +944,9 @@ msgstr "Pas d'uranium à transformer"
msgid "No userlevels installed!" msgid "No userlevels installed!"
msgstr "Pas de niveaux spéciaux installés !" msgstr "Pas de niveaux spéciaux installés !"
msgid "Non-void function needs \"return;\""
msgstr ""
msgid "Normal size" msgid "Normal size"
msgstr "Taille normale" msgstr "Taille normale"
@ -1024,10 +1050,10 @@ msgid "Paste (Ctrl+V)"
msgstr "Coller (Ctrl+V)" msgstr "Coller (Ctrl+V)"
msgid "Pause blur\\Blur the background on the pause screen" msgid "Pause blur\\Blur the background on the pause screen"
msgstr "" msgstr "Flouter les pauses\\Floute le fond de l'écran de pause"
msgid "Pause in background\\Pause the game when the window is unfocused" msgid "Pause in background\\Pause the game when the window is unfocused"
msgstr "" msgstr "Pause en arrière-plan\\Met le jeu en pause quand la fenêtre n'a plus le focus"
msgid "Pause/continue" msgid "Pause/continue"
msgstr "Pause/continuer" msgstr "Pause/continuer"
@ -1219,15 +1245,18 @@ msgid "Resolution:"
msgstr "Résolutions :" msgstr "Résolutions :"
msgid "Resources" msgid "Resources"
msgstr "" msgstr "Ressources"
msgid "Restart\\Restart the mission from the beginning" msgid "Restart\\Restart the mission from the beginning"
msgstr "Recommencer\\Recommencer la mission au début" msgstr "Recommencer\\Recommencer la mission au début"
msgid "Restoring CBot execution state" msgid "Restoring CBot execution state"
msgstr "" msgstr "Restaurer l'état d'exécution CBOT"
msgid "Restoring saved objects" msgid "Restoring saved objects"
msgstr "Restaurer des objets sauvés"
msgid "Results"
msgstr "" msgstr ""
msgid "Return to start" msgid "Return to start"
@ -1452,6 +1481,9 @@ msgstr "Filtrage de textures\\Filtrage de textures"
msgid "Textures" msgid "Textures"
msgstr "Textures" msgstr "Textures"
msgid "The battle has ended"
msgstr ""
msgid "The expression must return a boolean value" msgid "The expression must return a boolean value"
msgstr "L'expression doit ętre un boolean" msgstr "L'expression doit ętre un boolean"
@ -1482,9 +1514,15 @@ msgstr "Cette étiquette n'existe pas"
msgid "This menu is for userlevels from mods, but you didn't install any" msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr "Ce menu donne accès aux niveaux spéciaux (importés ou personnalisés), mais aucun n'est installé." msgstr "Ce menu donne accès aux niveaux spéciaux (importés ou personnalisés), mais aucun n'est installé."
msgid "This object is currently busy"
msgstr ""
msgid "This object is not a member of a class" msgid "This object is not a member of a class"
msgstr "L'objet n'est pas une instance d'une classe" msgstr "L'objet n'est pas une instance d'une classe"
msgid "This parameter needs a default value"
msgstr ""
msgid "This program is read-only, clone it to edit" msgid "This program is read-only, clone it to edit"
msgstr "Ce programme est en lecture-seule, le dupliquer pour pouvoir l'éditer" msgstr "Ce programme est en lecture-seule, le dupliquer pour pouvoir l'éditer"
@ -1677,24 +1715,24 @@ msgstr "Vous ne pouvez pas transporter un objet radioactif"
msgid "You can not carry an object under water" msgid "You can not carry an object under water"
msgstr "Vous ne pouvez pas transporter un objet sous l'eau" msgstr "Vous ne pouvez pas transporter un objet sous l'eau"
#, fuzzy, c-format #, c-format
msgid "You cannot use \"%s\" in this exercise (used: %d)" msgid "You cannot use \"%s\" in this exercise (used: %d)"
msgstr "Interdit dans cet exercice" msgstr "Vous ne pouvez pas utiliser «%s» dans cet exercice (utilisé : %d)"
msgid "You found a usable object" msgid "You found a usable object"
msgstr "Vous avez trouvé un objet utilisable" msgstr "Vous avez trouvé un objet utilisable"
#, fuzzy, c-format #, c-format
msgid "You have to use \"%1$s\" at least once in this exercise (used: %2$d)" msgid "You have to use \"%1$s\" at least once in this exercise (used: %2$d)"
msgid_plural "You have to use \"%1$s\" at least %3$d times in this exercise (used: %2$d)" msgid_plural "You have to use \"%1$s\" at least %3$d times in this exercise (used: %2$d)"
msgstr[0] "Interdit dans cet exercice" msgstr[0] "Vous devez utiliser «%1$s» au moins une fois dans cet exercice (utilisé %2$d fois)"
msgstr[1] "Interdit dans cet exercice" msgstr[1] "Vous devez utiliser «%1$s» au moins %3$d fois dans cet exercice (utilisé %2$d fois)"
#, fuzzy, c-format #, c-format
msgid "You have to use \"%1$s\" at most once in this exercise (used: %2$d)" msgid "You have to use \"%1$s\" at most once in this exercise (used: %2$d)"
msgid_plural "You have to use \"%1$s\" at most %3$d times in this exercise (used: %2$d)" msgid_plural "You have to use \"%1$s\" at most %3$d times in this exercise (used: %2$d)"
msgstr[0] "Interdit dans cet exercice" msgstr[0] "Vous devez utiliser «%1$s» au plus une fois dans cet exercice (utilisé %2$d fois)"
msgstr[1] "Interdit dans cet exercice" msgstr[1] "Vous devez utiliser «%1$s» au plus %3$d fois dans cet exercice (utilisé %2$d fois)"
msgid "You must get on the spaceship to take off" msgid "You must get on the spaceship to take off"
msgstr "Vous devez embarquer pour pouvoir décoller" msgstr "Vous devez embarquer pour pouvoir décoller"
@ -1864,9 +1902,8 @@ msgstr "epsitec.com"
#~ msgid "Developed by :" #~ msgid "Developed by :"
#~ msgstr "Développé par :" #~ msgstr "Développé par :"
#, fuzzy
#~ msgid "Do you want to quit Colobot: Gold Edition?" #~ msgid "Do you want to quit Colobot: Gold Edition?"
#~ msgstr "Voulez-vous quitter COLOBOT ?" #~ msgstr "Voulez-vous quitter Colobot: Édition Gold ?"
#~ msgid "Exit film\\Film at the exit of exercises" #~ msgid "Exit film\\Film at the exit of exercises"
#~ msgstr "Retour animé\\Retour animé dans les exercices" #~ msgstr "Retour animé\\Retour animé dans les exercices"

View File

@ -27,6 +27,10 @@ msgstr "Oczekiwane \" [ \""
msgid "\" ] \" missing" msgid "\" ] \" missing"
msgstr "Brak \" ] \"" msgstr "Brak \" ] \""
#, c-format
msgid "%s: %d pts"
msgstr "%s: %d pkt"
msgid "..behind" msgid "..behind"
msgstr "..za" msgstr "..za"
@ -48,6 +52,18 @@ msgstr "<< Wstecz \\Wraca do poprzedniego ekranu"
msgid "<<< Sorry; mission failed >>>" msgid "<<< Sorry; mission failed >>>"
msgstr "<<< Niestety, misja nie powiodła się >>>" msgstr "<<< Niestety, misja nie powiodła się >>>"
#, c-format
msgid "<<< Team %s finished! >>>"
msgstr "<<< Drużyna %s zakończyła rozgrywkę! >>>"
#, c-format
msgid "<<< Team %s lost! >>>"
msgstr "<<< Drużyna %s odpadła! >>>"
#, c-format
msgid "<<< Team %s recieved %d points >>>"
msgstr "<<< Drużyna %s zdobyła %d punktów >>>"
msgid "<<< Well done; mission accomplished >>>" msgid "<<< Well done; mission accomplished >>>"
msgstr "<<< Dobra robota, misja wypełniona >>>" msgstr "<<< Dobra robota, misja wypełniona >>>"
@ -348,6 +364,9 @@ msgstr "Konsola komend\\Pokaż konsolę komend"
msgid "Checkpoint" msgid "Checkpoint"
msgstr "Punkt kontrolny" msgstr "Punkt kontrolny"
msgid "Class name expected"
msgstr ""
msgid "Climb\\Increases the power of the jet" msgid "Climb\\Increases the power of the jet"
msgstr "W górę\\Zwiększa moc silnika" msgstr "W górę\\Zwiększa moc silnika"
@ -363,6 +382,9 @@ msgstr "Zamknij"
msgid "Closing bracket missing" msgid "Closing bracket missing"
msgstr "Brak nawiasu zamykającego" msgstr "Brak nawiasu zamykającego"
msgid "Code battle"
msgstr "Programobitwa"
msgid "Code battles" msgid "Code battles"
msgstr "Programobitwy" msgstr "Programobitwy"
@ -605,6 +627,9 @@ msgstr "Funkcja już istnieje"
msgid "Function name missing" msgid "Function name missing"
msgstr "Brakująca nazwa funkcji" msgstr "Brakująca nazwa funkcji"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed" msgid "Game speed"
msgstr "Prędkość gry" msgstr "Prędkość gry"
@ -920,6 +945,9 @@ msgstr "Brak uranu do przetworzenia"
msgid "No userlevels installed!" msgid "No userlevels installed!"
msgstr "Brak zainstalowanych poziomów użytkownika!" msgstr "Brak zainstalowanych poziomów użytkownika!"
msgid "Non-void function needs \"return;\""
msgstr ""
msgid "Normal size" msgid "Normal size"
msgstr "Normalna wielkość" msgstr "Normalna wielkość"
@ -1229,6 +1257,9 @@ msgstr "Przywracanie stanu CBot"
msgid "Restoring saved objects" msgid "Restoring saved objects"
msgstr "Przywracanie obiektów" msgstr "Przywracanie obiektów"
msgid "Results"
msgstr "Wyniki"
msgid "Return to start" msgid "Return to start"
msgstr "Powrót do początku" msgstr "Powrót do początku"
@ -1451,6 +1482,9 @@ msgstr "Filtrowanie tekstur\\Filtrowanie tekstur"
msgid "Textures" msgid "Textures"
msgstr "Tekstury" msgstr "Tekstury"
msgid "The battle has ended"
msgstr "Bitwa zakończyła się"
msgid "The expression must return a boolean value" msgid "The expression must return a boolean value"
msgstr "Wyrażenie musi zwrócić wartość logiczną" msgstr "Wyrażenie musi zwrócić wartość logiczną"
@ -1481,9 +1515,15 @@ msgstr "Taka etykieta nie istnieje"
msgid "This menu is for userlevels from mods, but you didn't install any" msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr "To menu jest przeznaczone na poziomy użytkownika z modyfikacji, ale żadne nie są zainstalowane" msgstr "To menu jest przeznaczone na poziomy użytkownika z modyfikacji, ale żadne nie są zainstalowane"
msgid "This object is currently busy"
msgstr "Ten objekt jest obecnie zajęty"
msgid "This object is not a member of a class" msgid "This object is not a member of a class"
msgstr "Ten obiekt nie jest członkiem klasy" msgstr "Ten obiekt nie jest członkiem klasy"
msgid "This parameter needs a default value"
msgstr ""
msgid "This program is read-only, clone it to edit" msgid "This program is read-only, clone it to edit"
msgstr "Ten program jest tylko do odczytu, skopiuj go, aby edytować" msgstr "Ten program jest tylko do odczytu, skopiuj go, aby edytować"

View File

@ -27,6 +27,10 @@ msgstr "Ожидалось \" [ \""
msgid "\" ] \" missing" msgid "\" ] \" missing"
msgstr "Отсутствует \"]\" " msgstr "Отсутствует \"]\" "
#, c-format
msgid "%s: %d pts"
msgstr ""
msgid "..behind" msgid "..behind"
msgstr "Сзади" msgstr "Сзади"
@ -48,6 +52,18 @@ msgstr "<< Назад \\Вернуться на предыдущую стран
msgid "<<< Sorry; mission failed >>>" msgid "<<< Sorry; mission failed >>>"
msgstr "<<< Миссия провалена >>>" msgstr "<<< Миссия провалена >>>"
#, c-format
msgid "<<< Team %s finished! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s lost! >>>"
msgstr ""
#, c-format
msgid "<<< Team %s recieved %d points >>>"
msgstr ""
msgid "<<< Well done; mission accomplished >>>" msgid "<<< Well done; mission accomplished >>>"
msgstr "<<< Отлично, миссия выполнена >>>" msgstr "<<< Отлично, миссия выполнена >>>"
@ -85,7 +101,7 @@ msgid "Alternative camera mode\\Move sideways instead of rotating (in free camer
msgstr "Альтернативный режим камеры\\Движение в стороны вместо поворачивания (в режиме свободной камеры)" msgstr "Альтернативный режим камеры\\Движение в стороны вместо поворачивания (в режиме свободной камеры)"
msgid "Ambiguous call to overloaded function" msgid "Ambiguous call to overloaded function"
msgstr "" msgstr "Странный вызов перегруженной функции"
msgid "Analysis already performed" msgid "Analysis already performed"
msgstr "Анализ уже выполнен" msgstr "Анализ уже выполнен"
@ -353,6 +369,9 @@ msgstr "Консоль чит-кодов\\Показать консоль для
msgid "Checkpoint" msgid "Checkpoint"
msgstr "Контрольная точка" msgstr "Контрольная точка"
msgid "Class name expected"
msgstr ""
msgid "Climb\\Increases the power of the jet" msgid "Climb\\Increases the power of the jet"
msgstr "Взлет и подъем\\Увеличивает мощность реактивного двигателя" msgstr "Взлет и подъем\\Увеличивает мощность реактивного двигателя"
@ -369,11 +388,15 @@ msgstr "Закрыть"
msgid "Closing bracket missing" msgid "Closing bracket missing"
msgstr "Закрывающая скобка отсутствует" msgstr "Закрывающая скобка отсутствует"
#, fuzzy
msgid "Code battle"
msgstr "Битвы роботов"
msgid "Code battles" msgid "Code battles"
msgstr "" msgstr "Битвы роботов"
msgid "Code battles\\Program your robot to be the best of them all!" msgid "Code battles\\Program your robot to be the best of them all!"
msgstr "Code battles\\Запрограммируйте собственного робота чтобы быть лучшим среди них!" msgstr "Битвы роботов\\Запрограммируйте собственного робота чтобы быть лучшим среди них!"
msgid "Colobot rules!" msgid "Colobot rules!"
msgstr "Правила игры!" msgstr "Правила игры!"
@ -612,6 +635,9 @@ msgstr "Функция уже существует"
msgid "Function name missing" msgid "Function name missing"
msgstr "Имя функции отсутствует" msgstr "Имя функции отсутствует"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed" msgid "Game speed"
msgstr "Скорость игры" msgstr "Скорость игры"
@ -817,7 +843,7 @@ msgid "Lunar Roving Vehicle"
msgstr "Луноход" msgstr "Луноход"
msgid "MSAA\\Multisample anti-aliasing" msgid "MSAA\\Multisample anti-aliasing"
msgstr "" msgstr "MSAA\\Улучшенная фильтрация"
msgid "Maximize" msgid "Maximize"
msgstr "Развернуть" msgstr "Развернуть"
@ -826,7 +852,7 @@ msgid "Minimize"
msgstr "Свернуть" msgstr "Свернуть"
msgid "Mipmap level\\Mipmap level" msgid "Mipmap level\\Mipmap level"
msgstr "" msgstr "Уровень уменьшающей фильтрации\\Уровень уменьшающей фильтрации"
msgid "Mission name" msgid "Mission name"
msgstr "Название миссии" msgstr "Название миссии"
@ -929,6 +955,9 @@ msgstr "Нет урана для преобразования"
msgid "No userlevels installed!" msgid "No userlevels installed!"
msgstr "Не установленны пользовательские уровни!" msgstr "Не установленны пользовательские уровни!"
msgid "Non-void function needs \"return;\""
msgstr ""
msgid "Normal size" msgid "Normal size"
msgstr "Нормальный размер" msgstr "Нормальный размер"
@ -1230,17 +1259,20 @@ msgid "Resolution:"
msgstr "Разрешение:" msgstr "Разрешение:"
msgid "Resources" msgid "Resources"
msgstr "" msgstr "Ресурсы"
msgid "Restart\\Restart the mission from the beginning" msgid "Restart\\Restart the mission from the beginning"
msgstr "Заново\\Начать данную миссию с начала" msgstr "Заново\\Начать данную миссию с начала"
msgid "Restoring CBot execution state" msgid "Restoring CBot execution state"
msgstr "" msgstr "Восстановление состояния CBot"
msgid "Restoring saved objects" msgid "Restoring saved objects"
msgstr "Восстановить сохранённые объекты" msgstr "Восстановить сохранённые объекты"
msgid "Results"
msgstr ""
msgid "Return to start" msgid "Return to start"
msgstr "Вернуться в начало" msgstr "Вернуться в начало"
@ -1465,6 +1497,9 @@ msgstr "Фильтрация текстур\\Фильтрация текстур
msgid "Textures" msgid "Textures"
msgstr "Текстуры" msgstr "Текстуры"
msgid "The battle has ended"
msgstr ""
msgid "The expression must return a boolean value" msgid "The expression must return a boolean value"
msgstr "Выражение должно возвращать логическое значение" msgstr "Выражение должно возвращать логическое значение"
@ -1495,9 +1530,15 @@ msgstr "Эта метка не существует"
msgid "This menu is for userlevels from mods, but you didn't install any" msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr "Это меню для пользовательских уровней из модов, но вы ни одного не уставили" msgstr "Это меню для пользовательских уровней из модов, но вы ни одного не уставили"
msgid "This object is currently busy"
msgstr ""
msgid "This object is not a member of a class" msgid "This object is not a member of a class"
msgstr "Этот объект не член класса" msgstr "Этот объект не член класса"
msgid "This parameter needs a default value"
msgstr ""
msgid "This program is read-only, clone it to edit" msgid "This program is read-only, clone it to edit"
msgstr "Эта программа только для чтения, для редактирования клонируйте её" msgstr "Эта программа только для чтения, для редактирования клонируйте её"

View File

@ -350,7 +350,7 @@ CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nId
val = m_prog->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this); val = m_prog->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this);
if (val.GetType() < 0) if (val.GetType() < 0)
{ {
val = m_prog->GetFunctions()->CompileCall(p->GetString(), ppVars, nIdent); val = CBotFunction::CompileCall(m_prog->GetFunctions(), p->GetString(), ppVars, nIdent);
if ( val.GetType() < 0 ) if ( val.GetType() < 0 )
{ {
// pVar = nullptr; // the error is not on a particular parameter // pVar = nullptr; // the error is not on a particular parameter
@ -369,8 +369,7 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
if ( m_prog->GetExternalCalls()->CheckCall(name) ) return true; if ( m_prog->GetExternalCalls()->CheckCall(name) ) return true;
CBotFunction* pp = m_prog->GetFunctions(); for (CBotFunction* pp : m_prog->GetFunctions())
while ( pp != nullptr )
{ {
if ( pToken->GetString() == pp->GetName() ) if ( pToken->GetString() == pp->GetName() )
{ {
@ -378,7 +377,6 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
if ( pp->CheckParam( pParam ) ) if ( pp->CheckParam( pParam ) )
return true; return true;
} }
pp = pp->Next();
} }
for (CBotFunction* pp : CBotFunction::m_publicFunctions) for (CBotFunction* pp : CBotFunction::m_publicFunctions)

View File

@ -1,113 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotCallMethode.h"
#include "CBot/CBotUtils.h"
#include "CBot/CBotStack.h"
#include "CBot/CBotCStack.h"
#include "CBot/CBotVar/CBotVar.h"
namespace CBot
{
////////////////////////////////////////////////////////////////////////////////
CBotCallMethode::CBotCallMethode(const std::string& name,
bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user),
CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar))
{
m_name = name;
m_rExec = rExec;
m_rComp = rCompile;
}
////////////////////////////////////////////////////////////////////////////////
CBotCallMethode::~CBotCallMethode()
{
}
////////////////////////////////////////////////////////////////////////////////
CBotTypResult CBotCallMethode::CompileCall(const std::string& name, CBotVar* pThis, CBotVar** ppVar,
CBotCStack* pStack)
{
CBotCallMethode* pt = this;
while ( pt != nullptr )
{
if ( pt->m_name == name )
{
CBotVar* pVar = MakeListVars(ppVar, true);
CBotVar* pVar2 = pVar;
CBotTypResult r = pt->m_rComp(pThis, pVar2);
int ret = r.GetType();
if ( ret > 20 )
{
if (pVar2) pStack->SetError(static_cast<CBotError>(ret), pVar2->GetToken());
}
delete pVar;
return r;
}
pt = pt->m_next;
}
return CBotTypResult(-1);
}
////////////////////////////////////////////////////////////////////////////////
int CBotCallMethode::DoCall(const std::string& name, CBotVar* pThis, CBotVar** ppVars, CBotVar*& pResult,
CBotStack* pStack, CBotToken* pToken)
{
CBotCallMethode* pt = this;
// search by name
while ( pt != nullptr )
{
if ( pt->m_name == name )
{
// lists the parameters depending on the contents of the stack (pStackVar)
CBotVar* pVar = MakeListVars(ppVars, true);
CBotVar* pVarToDelete = pVar;
int Exception = 0; // TODO: Change this to CBotError
int res = pt->m_rExec(pThis, pVar, pResult, Exception, pStack->GetUserPtr());
pStack->SetVar(pResult);
if (res == false)
{
if (Exception!=0)
{
// pStack->SetError(Exception, pVar->GetToken());
pStack->SetError(static_cast<CBotError>(Exception), pToken);
}
delete pVarToDelete;
return false;
}
delete pVarToDelete;
return true;
}
pt = pt->m_next;
}
return -1;
}
} // namespace CBot

View File

@ -1,88 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "CBot/CBotTypResult.h"
#include "CBot/CBotUtils.h"
namespace CBot
{
class CBotVar;
class CBotCStack;
class CBotStack;
class CBotToken;
/*!
* \brief The CBotCallMethode class Class managing the methods declared by
* AddFunction on a class.
*/
class CBotCallMethode : public CBotLinkedList<CBotCallMethode>
{
public:
/*!
* \brief CBotCallMethode
* \param name
* \param rExec
* \param rCompile
*/
CBotCallMethode(const std::string& name,
bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user),
CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar));
/*!
* \brief ~CBotCallMethode
*/
~CBotCallMethode();
/*!
* \brief CompileCall Is acceptable by a call procedure name and given
* parameters.
* \param name
* \param pThis
* \param ppVars
* \param pStack
* \return
*/
CBotTypResult CompileCall(const std::string& name, CBotVar* pThis, CBotVar** ppVars,
CBotCStack* pStack);
/*!
* \brief DoCall
* \param name
* \param pThis
* \param ppVars
* \param pResult
* \param pStack
* \param pFunc
* \return
*/
int DoCall(const std::string& name, CBotVar* pThis, CBotVar** ppVars, CBotVar*& pResult,
CBotStack* pStack, CBotToken* pFunc);
private:
std::string m_name;
bool (*m_rExec) (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user);
CBotTypResult (*m_rComp) (CBotVar* pThis, CBotVar* &pVar);
friend class CBotClass;
};
} // namespace CBot

View File

@ -37,7 +37,6 @@
#include "CBot/CBotDefParam.h" #include "CBot/CBotDefParam.h"
#include "CBot/CBotUtils.h" #include "CBot/CBotUtils.h"
#include "CBot/CBotFileUtils.h" #include "CBot/CBotFileUtils.h"
#include "CBot/CBotCallMethode.h"
#include <algorithm> #include <algorithm>
@ -55,8 +54,7 @@ CBotClass::CBotClass(const std::string& name,
m_parent = parent; m_parent = parent;
m_name = name; m_name = name;
m_pVar = nullptr; m_pVar = nullptr;
m_pCalls = nullptr; m_externalMethods = new CBotExternalCallList();
m_pMethod = nullptr;
m_rUpdate = nullptr; m_rUpdate = nullptr;
m_IsDef = true; m_IsDef = true;
m_bIntrinsic= bIntrinsic; m_bIntrinsic= bIntrinsic;
@ -71,8 +69,7 @@ CBotClass::~CBotClass()
m_publicClasses.erase(this); m_publicClasses.erase(this);
delete m_pVar; delete m_pVar;
delete m_pCalls; delete m_externalMethods;
delete m_pMethod;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -86,26 +83,24 @@ CBotClass* CBotClass::Create(const std::string& name,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotClass::ClearPublic() void CBotClass::ClearPublic()
{ {
m_publicClasses.clear(); while ( !m_publicClasses.empty() )
{
auto it = m_publicClasses.begin();
delete *it; // calling destructor removes the class from the list
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotClass::Purge() void CBotClass::Purge()
{ {
assert ( this != nullptr );
delete m_pVar; delete m_pVar;
m_pVar = nullptr; m_pVar = nullptr;
delete m_pCalls; m_externalMethods->Clear();
m_pCalls = nullptr; for (CBotFunction* f : m_pMethod) delete f;
delete m_pMethod; m_pMethod.clear();
m_pMethod = nullptr;
m_IsDef = false; m_IsDef = false;
m_nbVar = m_parent == nullptr ? 0 : m_parent->m_nbVar; m_nbVar = m_parent == nullptr ? 0 : m_parent->m_nbVar;
if (m_next != nullptr) m_next->Purge();
m_next = nullptr; // no longer belongs to this chain
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -205,7 +200,6 @@ std::string CBotClass::GetName()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotClass* CBotClass::GetParent() CBotClass* CBotClass::GetParent()
{ {
assert ( this != nullptr );
return m_parent; return m_parent;
} }
@ -255,6 +249,19 @@ CBotVar* CBotClass::GetItemRef(int nIdent)
return nullptr; return nullptr;
} }
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::CheckVar(const std::string &name)
{
CBotVar* p = m_pVar;
while ( p != nullptr )
{
if ( p->GetName() == name ) return true;
p = p->GetNext();
}
return false;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotClass::IsIntrinsic() bool CBotClass::IsIntrinsic()
{ {
@ -283,29 +290,7 @@ bool CBotClass::AddFunction(const std::string& name,
bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user), bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user),
CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar)) CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar))
{ {
// stores pointers to the two functions return m_externalMethods->AddFunction(name, std::unique_ptr<CBotExternalCall>(new CBotExternalCallClass(rExec, rCompile)));
CBotCallMethode* p = m_pCalls;
CBotCallMethode* pp = nullptr;
while ( p != nullptr )
{
if ( name == p->m_name )
{
if ( pp == nullptr ) m_pCalls = p->m_next;
else pp->m_next = p->m_next;
delete p;
break;
}
pp = p;
p = p->m_next;
}
p = new CBotCallMethode(name, rExec, rCompile);
if (m_pCalls == nullptr) m_pCalls = p;
else m_pCalls->AddNext(p); // added to the list
return true;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -316,22 +301,22 @@ bool CBotClass::SetUpdateFunc(void rUpdate(CBotVar* thisVar, void* user))
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotTypResult CBotClass::CompileMethode(const std::string& name, CBotTypResult CBotClass::CompileMethode(CBotToken* name,
CBotVar* pThis, CBotVar* pThis,
CBotVar** ppParams, CBotVar** ppParams,
CBotCStack* pStack, CBotCStack* pStack,
long& nIdent) long &nIdent)
{ {
nIdent = 0; // forget the previous one if necessary nIdent = 0; // forget the previous one if necessary
// find the methods declared by AddFunction // find the methods declared by AddFunction
CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack); CBotTypResult r = m_externalMethods->CompileCall(name, pThis, ppParams, pStack);
if ( r.GetType() >= 0) return r; if ( r.GetType() >= 0) return r;
// find the methods declared by user // find the methods declared by user
r = m_pMethod->CompileCall(name, ppParams, nIdent); r = CBotFunction::CompileCall(m_pMethod, name->GetString(), ppParams, nIdent);
if ( r.Eq(CBotErrUndefCall) && m_parent != nullptr ) if ( r.Eq(CBotErrUndefCall) && m_parent != nullptr )
return m_parent->CompileMethode(name, pThis, ppParams, pStack, nIdent); return m_parent->CompileMethode(name, pThis, ppParams, pStack, nIdent);
return r; return r;
@ -339,37 +324,39 @@ CBotTypResult CBotClass::CompileMethode(const std::string& name,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotClass::ExecuteMethode(long& nIdent, bool CBotClass::ExecuteMethode(long& nIdent,
const std::string& name,
CBotVar* pThis, CBotVar* pThis,
CBotVar** ppParams, CBotVar** ppParams,
CBotVar*& pResult, CBotTypResult pResultType,
CBotStack*& pStack, CBotStack*& pStack,
CBotToken* pToken) CBotToken* pToken)
{ {
int ret = m_pCalls->DoCall(name, pThis, ppParams, pResult, pStack, pToken); int ret = m_externalMethods->DoCall(pToken, pThis, ppParams, pStack, pResultType);
if (ret>=0) return ret; if (ret >= 0) return ret;
ret = m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, this); ret = CBotFunction::DoCall(m_pMethod, nIdent, pToken->GetString(), pThis, ppParams, pStack, pToken, this);
if (ret >= 0) return ret; if (ret >= 0) return ret;
if (m_parent != nullptr) if (m_parent != nullptr)
{ {
ret = m_parent->ExecuteMethode(nIdent, name, pThis, ppParams, pResult, pStack, pToken); ret = m_parent->ExecuteMethode(nIdent, pThis, ppParams, pResultType, pStack, pToken);
} }
return ret; return ret;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotClass::RestoreMethode(long& nIdent, void CBotClass::RestoreMethode(long& nIdent,
const std::string& name, CBotToken* name,
CBotVar* pThis, CBotVar* pThis,
CBotVar** ppParams, CBotVar** ppParams,
CBotStack*& pStack) CBotStack*& pStack)
{ {
if (m_externalMethods->RestoreCall(name, pThis, ppParams, pStack))
return;
CBotClass* pClass = this; CBotClass* pClass = this;
while (pClass != nullptr) while (pClass != nullptr)
{ {
bool ok = pClass->m_pMethod->RestoreCall(nIdent, name, pThis, ppParams, pStack, pClass); bool ok = CBotFunction::RestoreCall(pClass->m_pMethod, nIdent, name->GetString(), pThis, ppParams, pStack, pClass);
if (ok) return; if (ok) return;
pClass = pClass->m_parent; pClass = pClass->m_parent;
} }
@ -455,8 +442,7 @@ bool CBotClass::CheckCall(CBotProgram* program, CBotDefParam* pParam, CBotToken*
if ( program->GetExternalCalls()->CheckCall(name) ) return true; if ( program->GetExternalCalls()->CheckCall(name) ) return true;
CBotFunction* pp = m_pMethod; for (CBotFunction* pp : m_pMethod)
while ( pp != nullptr )
{ {
if ( pToken->GetString() == pp->GetName() ) if ( pToken->GetString() == pp->GetName() )
{ {
@ -464,7 +450,6 @@ bool CBotClass::CheckCall(CBotProgram* program, CBotDefParam* pParam, CBotToken*
if ( pp->CheckParam( pParam ) ) if ( pp->CheckParam( pParam ) )
return true; return true;
} }
pp = pp->Next();
} }
return false; return false;
@ -483,30 +468,32 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
std::string name = p->GetString(); std::string name = p->GetString();
CBotClass* pOld = CBotClass::Find(name);
if ( pOld != nullptr && pOld->m_IsDef )
{
pStack->SetError( CBotErrRedefClass, p );
return nullptr;
}
// a name of the class is there? // a name of the class is there?
if (IsOfType(p, TokenTypVar)) if (IsOfType(p, TokenTypVar))
{ {
CBotClass* pOld = CBotClass::Find(name);
if ((pOld != nullptr && pOld->m_IsDef) || /* public class exists in different program */
pStack->GetProgram()->ClassExists(name)) /* class exists in this program */
{
pStack->SetError(CBotErrRedefClass, p->GetPrev());
return nullptr;
}
CBotClass* pPapa = nullptr; CBotClass* pPapa = nullptr;
if ( IsOfType( p, ID_EXTENDS ) ) if ( IsOfType( p, ID_EXTENDS ) )
{ {
std::string name = p->GetString(); std::string name = p->GetString();
pPapa = CBotClass::Find(name); pPapa = CBotClass::Find(name);
CBotToken* pp = p;
if (!IsOfType(p, TokenTypVar) || pPapa == nullptr ) if (!IsOfType(p, TokenTypVar) || pPapa == nullptr )
{ {
pStack->SetError( CBotErrNotClass, p ); pStack->SetError(CBotErrNoClassName, pp);
return nullptr; return nullptr;
} }
} }
CBotClass* classe = (pOld == nullptr) ? new CBotClass(name, pPapa) : pOld; CBotClass* classe = (pOld == nullptr) ? new CBotClass(name, pPapa) : pOld;
classe->Purge(); // empty the old definitions // TODO: Doesn't this remove all classes of the current program? classe->Purge(); // empty the old definitions
classe->m_IsDef = false; // current definition classe->m_IsDef = false; // current definition
classe->m_pOpenblk = p; classe->m_pOpenblk = p;
@ -518,27 +505,29 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
} }
int level = 1; int level = 1;
do // skip over the definition while (level > 0 && p != nullptr)
{ {
int type = p->GetType(); int type = p->GetType();
p = p->GetNext(); p = p->GetNext();
if (type == ID_OPBLK) level++; if (type == ID_OPBLK) level++;
if (type == ID_CLBLK) level--; if (type == ID_CLBLK) level--;
} }
while (level > 0 && p != nullptr);
if (level > 0) pStack->SetError(CBotErrCloseBlock, classe->m_pOpenblk); if (level > 0) pStack->SetError(CBotErrCloseBlock, classe->m_pOpenblk);
if (pStack->IsOk()) return classe; if (pStack->IsOk()) return classe;
} }
else
pStack->SetError(CBotErrNoClassName, p);
pStack->SetError(CBotErrNoTerminator, p); pStack->SetError(CBotErrNoTerminator, p);
return nullptr; return nullptr;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotClass::DefineClasses(CBotClass* pClass, CBotCStack* pStack) void CBotClass::DefineClasses(std::list<CBotClass*> pClassList, CBotCStack* pStack)
{ {
while (pClass != nullptr) for (CBotClass* pClass : pClassList)
{ {
CBotClass* pParent = pClass->m_parent; CBotClass* pParent = pClass->m_parent;
pClass->m_nbVar = (pParent == nullptr) ? 0 : pParent->m_nbVar; pClass->m_nbVar = (pParent == nullptr) ? 0 : pParent->m_nbVar;
@ -550,8 +539,6 @@ void CBotClass::DefineClasses(CBotClass* pClass, CBotCStack* pStack)
} }
if (!pStack->IsOk()) return; if (!pStack->IsOk()) return;
pClass = pClass->GetNext();
} }
} }
@ -587,6 +574,8 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
while (pStack->IsOk()) while (pStack->IsOk())
{ {
CBotTypResult type2 = CBotTypResult(type); // reset type after comma CBotTypResult type2 = CBotTypResult(type); // reset type after comma
CBotToken* varToken = p;
std::string pp = p->GetString(); std::string pp = p->GetString();
if ( IsOfType(p, ID_NOT) ) if ( IsOfType(p, ID_NOT) )
{ {
@ -595,60 +584,30 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
if (IsOfType(p, TokenTypVar)) if (IsOfType(p, TokenTypVar))
{ {
CBotInstr* limites = nullptr;
while ( IsOfType( p, ID_OPBRK ) ) // a table?
{
CBotInstr* i = nullptr;
pStack->SetStartError( p->GetStart() );
if ( p->GetType() != ID_CLBRK )
{
i = CBotExpression::Compile( p, pStack ); // expression for the value
if (i == nullptr || pStack->GetType() != CBotTypInt) // must be a number
{
pStack->SetError(CBotErrBadIndex, p->GetStart());
return false;
}
}
else
i = new CBotEmpty(); // special if not a formula
type2 = CBotTypResult(CBotTypArrayPointer, type2);
if (limites == nullptr) limites = i;
else limites->AddNext3(i);
if (IsOfType(p, ID_CLBRK)) continue;
pStack->SetError(CBotErrCloseIndex, p->GetStart());
return false;
}
if ( p->GetType() == ID_OPENPAR ) if ( p->GetType() == ID_OPENPAR )
{ {
if ( !bSecond ) if ( !bSecond )
{ {
p = pBase; p = pBase;
CBotFunction* f = CBotFunction* f = CBotFunction::Compile1(p, pStack, this);
CBotFunction::Compile1(p, pStack, this);
if ( f == nullptr ) return false; if ( f == nullptr ) return false;
if (m_pMethod == nullptr) m_pMethod = f; m_pMethod.push_back(f);
else m_pMethod->AddNext(f);
} }
else else
{ {
// return a method precompiled in pass 1 // return a method precompiled in pass 1
CBotFunction* pf = m_pMethod;
CBotToken* ppp = p;
CBotCStack* pStk = pStack->TokenStack(nullptr, true); CBotCStack* pStk = pStack->TokenStack(nullptr, true);
CBotDefParam* params = CBotDefParam::Compile(p, pStk ); CBotDefParam* params = CBotDefParam::Compile(p, pStk );
delete pStk; delete pStk;
p = ppp; std::list<CBotFunction*>::iterator pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, &params](CBotFunction* x)
while ( pf != nullptr ) // search by name and parameters
{ {
if (pf->GetName() == pp && pf->CheckParam( params )) break; return x->GetName() == pp && x->CheckParam( params );
pf = pf->Next(); });
} assert(pfIter != m_pMethod.end());
CBotFunction* pf = *pfIter;
delete params;
bool bConstructor = (pp == GetName()); bool bConstructor = (pp == GetName());
CBotCStack* pile = pStack->TokenStack(nullptr, true); CBotCStack* pile = pStack->TokenStack(nullptr, true);
@ -706,12 +665,51 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
} }
// definition of an element // definition of an element
if (type2.Eq(0)) if (type.Eq(0))
{ {
pStack->SetError(CBotErrNoTerminator, p); pStack->SetError(CBotErrNoTerminator, p);
return false; return false;
} }
if (pp[0] == '~' || pp == GetName()) // bad variable name
{
pStack->SetError(CBotErrNoVar, varToken);
return false;
}
if (!bSecond && CheckVar(pp)) // variable already exists
{
pStack->SetError(CBotErrRedefVar, varToken);
return false;
}
CBotInstr* limites = nullptr;
while ( IsOfType( p, ID_OPBRK ) ) // an array
{
CBotInstr* i = nullptr;
pStack->SetStartError( p->GetStart() );
if ( p->GetType() != ID_CLBRK )
{
i = CBotExpression::Compile( p, pStack ); // expression for the value
if (i == nullptr || pStack->GetType() != CBotTypInt) // must be a number
{
pStack->SetError(CBotErrBadIndex, p->GetStart());
}
}
else
i = new CBotEmpty(); // special if not a formula
type2 = CBotTypResult(CBotTypArrayPointer, type2);
if (limites == nullptr) limites = i;
else limites->AddNext3(i);
if (pStack->IsOk() && IsOfType(p, ID_CLBRK)) continue;
pStack->SetError(CBotErrCloseIndex, p->GetStart());
delete limites;
return false;
}
CBotInstr* i = nullptr; CBotInstr* i = nullptr;
if ( IsOfType(p, ID_ASS ) ) if ( IsOfType(p, ID_ASS ) )
{ {
@ -781,7 +779,10 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
} }
} }
else else
{
delete i; delete i;
delete limites;
}
if ( IsOfType(p, ID_COMMA) ) continue; if ( IsOfType(p, ID_COMMA) ) continue;
if ( IsOfType(p, ID_SEP) ) break; if ( IsOfType(p, ID_SEP) ) break;
@ -810,10 +811,11 @@ CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack)
// TODO: Not sure how correct is that - I have no idea how the precompilation (Compile1 method) works ~krzys_h // TODO: Not sure how correct is that - I have no idea how the precompilation (Compile1 method) works ~krzys_h
std::string name = p->GetString(); std::string name = p->GetString();
CBotClass* pPapa = CBotClass::Find(name); CBotClass* pPapa = CBotClass::Find(name);
CBotToken* pp = p;
if (!IsOfType(p, TokenTypVar) || pPapa == nullptr) if (!IsOfType(p, TokenTypVar) || pPapa == nullptr)
{ {
pStack->SetError( CBotErrNotClass, p ); pStack->SetError(CBotErrNoClassName, pp);
return nullptr; return nullptr;
} }
pOld->m_parent = pPapa; pOld->m_parent = pPapa;

View File

@ -26,6 +26,7 @@
#include <string> #include <string>
#include <deque> #include <deque>
#include <set> #include <set>
#include <list>
namespace CBot namespace CBot
{ {
@ -37,6 +38,7 @@ class CBotStack;
class CBotDefParam; class CBotDefParam;
class CBotToken; class CBotToken;
class CBotCStack; class CBotCStack;
class CBotExternalCallList;
/** /**
* \brief A CBot class definition * \brief A CBot class definition
@ -102,7 +104,7 @@ class CBotCStack;
* float y = var->GetValFloat(); * float y = var->GetValFloat();
* \endcode * \endcode
*/ */
class CBotClass : public CBotLinkedList<CBotClass> class CBotClass
{ {
public: public:
/*! /*!
@ -133,13 +135,8 @@ public:
bool intrinsic = false); bool intrinsic = false);
/*! /*!
* \brief AddFunction This call allows to add as external new method * \brief Add a function that can be called from CBot
* used by the objects of this class. See (**) at end of this file for * \see CBotProgram::AddFunction
* more details.
* \param name
* \param rExec
* \param rCompile
* \return
*/ */
bool AddFunction(const std::string& name, bool AddFunction(const std::string& name,
bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user), bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user),
@ -224,6 +221,13 @@ public:
*/ */
CBotVar* GetItemRef(int nIdent); CBotVar* GetItemRef(int nIdent);
/*!
* \brief Check whether a variable is already defined in a class
* \param name Name of the variable
* \return True if a variable is defined in the class
*/
bool CheckVar(const std::string &name);
/*! /*!
* \brief CompileMethode Compiles a method associated with an instance of * \brief CompileMethode Compiles a method associated with an instance of
* class the method can be declared by the user or AddFunction. * class the method can be declared by the user or AddFunction.
@ -234,11 +238,11 @@ public:
* \param nIdent * \param nIdent
* \return * \return
*/ */
CBotTypResult CompileMethode(const std::string& name, CBotTypResult CompileMethode(CBotToken* name,
CBotVar* pThis, CBotVar* pThis,
CBotVar** ppParams, CBotVar** ppParams,
CBotCStack* pStack, CBotCStack* pStack,
long& nIdent); long &nIdent);
/*! /*!
* \brief ExecuteMethode Executes a method. * \brief ExecuteMethode Executes a method.
@ -246,18 +250,13 @@ public:
* \param name * \param name
* \param pThis * \param pThis
* \param ppParams * \param ppParams
* \param pResult * \param pResultType
* \param pStack * \param pStack
* \param pToken * \param pToken
* \return * \return
*/ */
bool ExecuteMethode(long& nIdent, bool ExecuteMethode(long &nIdent, CBotVar* pThis, CBotVar** ppParams, CBotTypResult pResultType,
const std::string& name, CBotStack*&pStack, CBotToken* pToken);
CBotVar* pThis,
CBotVar** ppParams,
CBotVar*& pResult,
CBotStack*& pStack,
CBotToken* pToken);
/*! /*!
* \brief RestoreMethode Restored the execution stack. * \brief RestoreMethode Restored the execution stack.
@ -267,11 +266,11 @@ public:
* \param ppParams * \param ppParams
* \param pStack * \param pStack
*/ */
void RestoreMethode(long& nIdent, void RestoreMethode(long &nIdent,
const std::string& name, CBotToken* name,
CBotVar* pThis, CBotVar* pThis,
CBotVar** ppParams, CBotVar** ppParams,
CBotStack*& pStack); CBotStack*&pStack);
/*! /*!
* \brief Compile Compiles a class declared by the user. * \brief Compile Compiles a class declared by the user.
@ -283,10 +282,15 @@ public:
CBotCStack* pStack); CBotCStack* pStack);
/*! /*!
* \brief Compile1 * \brief Pre-compile a new class
* \param p * \param p[in, out] Pointer to first token of the class, will be updated to point to first token after the class definition
* \param pStack * \param pStack Compile stack
* \return *
* This function is used to find the beginning and end of class definition.
*
* If any errors in the code are detected, this function will set the error on compile stack and return nullptr.
*
* \return Precompiled class, or nullptr in case of error
*/ */
static CBotClass* Compile1(CBotToken* &p, static CBotClass* Compile1(CBotToken* &p,
CBotCStack* pStack); CBotCStack* pStack);
@ -294,10 +298,10 @@ public:
/*! /*!
* \brief DefineClasses Calls CompileDefItem for each class in a list * \brief DefineClasses Calls CompileDefItem for each class in a list
* of classes, defining fields and pre-compiling methods. * of classes, defining fields and pre-compiling methods.
* \param pClass List of classes * \param pClassList List of classes
* \param pStack * \param pStack
*/ */
static void DefineClasses(CBotClass* pClass, CBotCStack* pStack); static void DefineClasses(std::list<CBotClass*> pClassList, CBotCStack* pStack);
/*! /*!
* \brief CompileDefItem * \brief CompileDefItem
@ -388,9 +392,9 @@ private:
//! Linked list of all class fields //! Linked list of all class fields
CBotVar* m_pVar; CBotVar* m_pVar;
//! Linked list of all class external calls //! Linked list of all class external calls
CBotCallMethode* m_pCalls; CBotExternalCallList* m_externalMethods;
//! Linked list of all class methods //! List of all class methods
CBotFunction* m_pMethod; std::list<CBotFunction*> m_pMethod{};
void (*m_rUpdate)(CBotVar* thisVar, void* user); void (*m_rUpdate)(CBotVar* thisVar, void* user);
CBotToken* m_pOpenblk; CBotToken* m_pOpenblk;

View File

@ -36,12 +36,10 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program)
std::stringstream ss; std::stringstream ss;
ss << "digraph {" << std::endl; ss << "digraph {" << std::endl;
CBotFunction* func = program->GetFunctions();
std::map<long, CBotFunction*> funcIdMap; std::map<long, CBotFunction*> funcIdMap;
while (func != nullptr) for (CBotFunction* func : program->GetFunctions())
{ {
funcIdMap[func->m_nFuncIdent] = func; funcIdMap[func->m_nFuncIdent] = func;
func = func->Next();
} }
std::set<CBotInstr*> finished; std::set<CBotInstr*> finished;
@ -111,9 +109,8 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program)
{ {
DumpInstr(program->m_entryPoint); DumpInstr(program->m_entryPoint);
} }
func = program->GetFunctions();
std::string prev = GetPointerAsString(program->m_entryPoint); std::string prev = GetPointerAsString(program->m_entryPoint);
while (func != nullptr) for (CBotFunction* func : program->GetFunctions())
{ {
if (func != program->m_entryPoint) if (func != program->m_entryPoint)
{ {
@ -122,8 +119,6 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program)
//ss << prev << " -> " << GetPointerAsString(func) << " [style=invis]" << std::endl; //ss << prev << " -> " << GetPointerAsString(func) << " [style=invis]" << std::endl;
prev = GetPointerAsString(func); prev = GetPointerAsString(func);
} }
func = func->Next();
} }
ss << "}" << std::endl; ss << "}" << std::endl;

View File

@ -19,6 +19,9 @@
#include "CBot/CBotDefParam.h" #include "CBot/CBotDefParam.h"
#include "CBot/CBotInstr/CBotInstrUtils.h"
#include "CBot/CBotInstr/CBotParExpr.h"
#include "CBot/CBotUtils.h" #include "CBot/CBotUtils.h"
#include "CBot/CBotCStack.h" #include "CBot/CBotCStack.h"
@ -33,11 +36,13 @@ namespace CBot
CBotDefParam::CBotDefParam() CBotDefParam::CBotDefParam()
{ {
m_nIdent = 0; m_nIdent = 0;
m_expr = nullptr;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotDefParam::~CBotDefParam() CBotDefParam::~CBotDefParam()
{ {
delete m_expr;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -51,8 +56,9 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
if (IsOfType(p, ID_OPENPAR)) if (IsOfType(p, ID_OPENPAR))
{ {
CBotDefParam* list = nullptr; CBotDefParam* list = nullptr;
bool prevHasDefault = false;
while (!IsOfType(p, ID_CLOSEPAR)) if (!IsOfType(p, ID_CLOSEPAR)) while (true)
{ {
CBotDefParam* param = new CBotDefParam(); CBotDefParam* param = new CBotDefParam();
if (list == nullptr) list = param; if (list == nullptr) list = param;
@ -77,6 +83,26 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
break; break;
} }
if (IsOfType(p, ID_ASS)) // default value assignment
{
CBotCStack* pStk = pStack->TokenStack(nullptr, true);
if (nullptr != (param->m_expr = CBotParExpr::CompileLitExpr(p, pStk)))
{
CBotTypResult valueType = pStk->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
if (!TypesCompatibles(type, valueType))
pStack->SetError(CBotErrBadType1, p->GetPrev());
prevHasDefault = true;
}
else pStack->SetError(CBotErrNoExpression, p);
delete pStk;
}
else
if (prevHasDefault) pStack->SetError(CBotErrDefaultValue, p->GetPrev());
if (!pStack->IsOk()) break;
if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody); if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody);
CBotVar* var = CBotVar::Create(pp->GetString(), type); // creates the variable CBotVar* var = CBotVar::Create(pp->GetString(), type); // creates the variable
// if ( pClass ) var->SetClass(pClass); // if ( pClass ) var->SetClass(pClass);
@ -85,10 +111,12 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
var->SetUniqNum(param->m_nIdent); var->SetUniqNum(param->m_nIdent);
pStack->AddVar(var); // place on the stack pStack->AddVar(var); // place on the stack
if (IsOfType(p, ID_COMMA) || p->GetType() == ID_CLOSEPAR) if (IsOfType(p, ID_COMMA)) continue;
continue; if (IsOfType(p, ID_CLOSEPAR)) break;
pStack->SetError(CBotErrClosePar, p->GetStart());
} }
pStack->SetError(CBotErrClosePar, p->GetStart()); pStack->SetError(CBotErrNoVar, p->GetStart());
} }
pStack->SetError(CBotErrNoType, p); pStack->SetError(CBotErrNoType, p);
delete list; delete list;
@ -106,40 +134,71 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
int i = 0; int i = 0;
CBotDefParam* p = this; CBotDefParam* p = this;
bool useDefault = false;
CBotStack* pile = pj->AddStack();
while ( p != nullptr ) while ( p != nullptr )
{ {
pile = pile->AddStack();
if (pile->GetState() == 1) // already done?
{
if (ppVars != nullptr && ppVars[i] != nullptr) ++i;
p = p->m_next;
continue; // next param
}
CBotVar* pVar = nullptr;
if (useDefault || (ppVars == nullptr || ppVars[i] == nullptr))
{
assert(p->m_expr != nullptr);
useDefault = true;
if (!p->m_expr->Execute(pile)) return false; // interupt here
pVar = pile->GetVar();
}
else
pVar = ppVars[i];
pile->SetState(1); // mark this param done
// creates a local variable on the stack // creates a local variable on the stack
CBotVar* newvar = CBotVar::Create(p->m_token.GetString(), p->m_type); CBotVar* newvar = CBotVar::Create(p->m_token.GetString(), p->m_type);
// serves to make the transformation of types: // serves to make the transformation of types:
if ( ppVars != nullptr && ppVars[i] != nullptr ) if ((useDefault && pVar != nullptr) ||
(ppVars != nullptr && pVar != nullptr))
{ {
switch (p->m_type.GetType()) switch (p->m_type.GetType())
{ {
case CBotTypInt: case CBotTypInt:
newvar->SetValInt(ppVars[i]->GetValInt()); newvar->SetValInt(pVar->GetValInt());
newvar->SetInit(pVar->GetInit()); // copy nan
break; break;
case CBotTypFloat: case CBotTypFloat:
newvar->SetValFloat(ppVars[i]->GetValFloat()); newvar->SetValFloat(pVar->GetValFloat());
newvar->SetInit(pVar->GetInit()); // copy nan
break; break;
case CBotTypString: case CBotTypString:
newvar->SetValString(ppVars[i]->GetValString()); newvar->SetValString(pVar->GetValString());
break; break;
case CBotTypBoolean: case CBotTypBoolean:
newvar->SetValInt(ppVars[i]->GetValInt()); newvar->SetValInt(pVar->GetValInt());
break; break;
case CBotTypIntrinsic: case CBotTypIntrinsic:
(static_cast<CBotVarClass*>(newvar))->Copy(ppVars[i], false); (static_cast<CBotVarClass*>(newvar))->Copy(pVar, false);
break; break;
case CBotTypPointer: case CBotTypPointer:
{ {
newvar->SetPointer(ppVars[i]->GetPointer()); newvar->SetPointer(pVar->GetPointer());
newvar->SetType(p->m_type); // keep pointer type newvar->SetType(p->m_type); // keep pointer type
} }
break; break;
case CBotTypArrayPointer: case CBotTypArrayPointer:
{ {
newvar->SetPointer(ppVars[i]->GetPointer()); newvar->SetPointer(pVar->GetPointer());
} }
break; break;
default: default:
@ -149,23 +208,41 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
newvar->SetUniqNum(p->m_nIdent); newvar->SetUniqNum(p->m_nIdent);
pj->AddVar(newvar); // add a variable pj->AddVar(newvar); // add a variable
p = p->m_next; p = p->m_next;
i++; if (!useDefault) i++;
} }
return true; return true;
} }
////////////////////////////////////////////////////////////////////////////////
bool CBotDefParam::HasDefault()
{
return (m_expr != nullptr);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain) void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain)
{ {
// int i = 0;
CBotDefParam* p = this; CBotDefParam* p = this;
CBotStack* pile = nullptr;
if (bMain) pile = pj->RestoreStack();
while ( p != nullptr ) while ( p != nullptr )
{ {
if (bMain && pile != nullptr)
{
pile = pile->RestoreStack();
if (pile != nullptr && pile->GetState() == 0)
{
assert(p->m_expr != nullptr);
p->m_expr->RestoreState(pile, true);
return;
}
}
// creates a local variable on the stack // creates a local variable on the stack
CBotVar* var = pj->FindVar(p->m_token.GetString()); CBotVar* var = pj->FindVar(p->m_token.GetString());
var->SetUniqNum(p->m_nIdent); if (var != nullptr) var->SetUniqNum(p->m_nIdent);
p = p->m_next; p = p->m_next;
} }
} }

View File

@ -63,6 +63,12 @@ public:
*/ */
bool Execute(CBotVar** ppVars, CBotStack* &pj); bool Execute(CBotVar** ppVars, CBotStack* &pj);
/*!
* \brief Check if this parameter has a default value expression.
* \return true if the parameter was compiled with a default value.
*/
bool HasDefault();
/*! /*!
* \brief RestoreState * \brief RestoreState
* \param pj * \param pj
@ -96,6 +102,9 @@ private:
//! Type of paramteter. //! Type of paramteter.
CBotTypResult m_type; CBotTypResult m_type;
long m_nIdent; long m_nIdent;
//! Default value expression for the parameter.
CBotInstr* m_expr;
}; };
} // namespace CBot } // namespace CBot

View File

@ -237,6 +237,10 @@ enum CBotError : int
CBotErrNoPublic = 5042, //!< missing word "public" CBotErrNoPublic = 5042, //!< missing word "public"
CBotErrNoExpression = 5043, //!< expression expected after = CBotErrNoExpression = 5043, //!< expression expected after =
CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function
CBotErrFuncNotVoid = 5045, //!< function needs return type "void"
CBotErrNoClassName = 5046, //!< class name expected
CBotErrNoReturn = 5047, //!< non-void function needs "return;"
CBotErrDefaultValue = 5048, //!< this parameter needs a default value
// Runtime errors // Runtime errors
CBotErrZeroDiv = 6000, //!< division by zero CBotErrZeroDiv = 6000, //!< division by zero

View File

@ -168,4 +168,48 @@ bool CBotExternalCallDefault::Run(CBotVar* thisVar, CBotStack* pStack)
return true; return true;
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CBotExternalCallClass::CBotExternalCallClass(RuntimeFunc rExec, CompileFunc rCompile)
{
m_rExec = rExec;
m_rComp = rCompile;
}
CBotExternalCallClass::~CBotExternalCallClass()
{
}
CBotTypResult CBotExternalCallClass::Compile(CBotVar* thisVar, CBotVar* args, void* user)
{
return m_rComp(thisVar, args);
}
bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack)
{
if (pStack->IsCallFinished()) return true;
CBotStack* pile = pStack->AddStackExternalCall(this);
CBotVar* args = pile->GetVar();
CBotStack* pile2 = pile->AddStack();
CBotVar* result = pile2->GetVar();
int exception = CBotNoErr; // TODO: Change to CBotError
bool res = m_rExec(thisVar, args, result, exception, pStack->GetUserPtr());
if (!res)
{
if (exception != CBotNoErr)
{
pStack->SetError(static_cast<CBotError>(exception));
}
return false;
}
if (result != nullptr) pStack->SetCopyVar(result);
return true;
}
} }

View File

@ -105,6 +105,36 @@ private:
CompileFunc m_rComp; CompileFunc m_rComp;
}; };
/**
* \brief Implementation of CBot external call for class methods, using compilation and runtime functions
*/
class CBotExternalCallClass : public CBotExternalCall
{
public:
typedef bool (*RuntimeFunc)(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user);
typedef CBotTypResult (*CompileFunc)(CBotVar* pThis, CBotVar*& pVar);
/**
* \brief Constructor
* \param rExec Runtime function
* \param rCompile Compilation function
* \see CBotProgram::AddFunction()
*/
CBotExternalCallClass(RuntimeFunc rExec, CompileFunc rCompile);
/**
* \brief Destructor
*/
virtual ~CBotExternalCallClass();
virtual CBotTypResult Compile(CBotVar* thisVar, CBotVar* args, void* user) override;
virtual bool Run(CBotVar* thisVar, CBotStack* pStack) override;
private:
RuntimeFunc m_rExec;
CompileFunc m_rComp;
};
/** /**
* \brief Class for mangaging CBot external calls * \brief Class for mangaging CBot external calls

View File

@ -51,6 +51,9 @@ CBotDefClass::CBotDefClass()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotDefClass::~CBotDefClass() CBotDefClass::~CBotDefClass()
{ {
delete m_parameters;
delete m_exprRetVar;
delete m_expr;
delete m_var; delete m_var;
} }
@ -131,7 +134,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p
{ {
// the constructor is there? // the constructor is there?
// std::string noname; // std::string noname;
CBotTypResult r = pClass->CompileMethode(pClass->GetName(), var, ppVars, pStk, inst->m_nMethodeIdent); CBotTypResult r = pClass->CompileMethode(&token, var, ppVars, pStk, inst->m_nMethodeIdent);
delete pStk->TokenStack(); // releases the supplement stack delete pStk->TokenStack(); // releases the supplement stack
int typ = r.GetType(); int typ = r.GetType();
@ -246,9 +249,9 @@ bool CBotDefClass::Execute(CBotStack* &pj)
if (m_exprRetVar != nullptr) // Class c().method(); if (m_exprRetVar != nullptr) // Class c().method();
{ {
if (pile->IfStep()) return false;
if (pile->GetState() == 4) if (pile->GetState() == 4)
{ {
if (pile->IfStep()) return false;
CBotStack* pile3 = pile->AddStack(); CBotStack* pile3 = pile->AddStack();
if (!m_exprRetVar->Execute(pile3)) return false; if (!m_exprRetVar->Execute(pile3)) return false;
pile3->SetVar(nullptr); pile3->SetVar(nullptr);
@ -369,11 +372,7 @@ bool CBotDefClass::Execute(CBotStack* &pj)
ppVars[i] = nullptr; ppVars[i] = nullptr;
// creates a variable for the result // creates a variable for the result
CBotVar* pResult = nullptr; // constructor still void if ( !pClass->ExecuteMethode(m_nMethodeIdent, pThis, ppVars, CBotTypResult(CBotTypVoid), pile2, GetToken())) return false; // interrupt
if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GetName(),
pThis, ppVars,
pResult, pile2, GetToken())) return false; // interrupt
pThis->SetInit(CBotVar::InitType::DEF); pThis->SetInit(CBotVar::InitType::DEF);
pThis->ConstructorSet(); // indicates that the constructor has been called pThis->ConstructorSet(); // indicates that the constructor has been called
@ -483,9 +482,7 @@ void CBotDefClass::RestoreState(CBotStack* &pj, bool bMain)
ppVars[i] = nullptr; ppVars[i] = nullptr;
// creates a variable for the result // creates a variable for the result
// CBotVar* pResult = nullptr; // constructor still void pClass->RestoreMethode(m_nMethodeIdent, pt, pThis, ppVars, pile2);
pClass->RestoreMethode(m_nMethodeIdent, pClass->GetName(), pThis, ppVars, pile2);
return; return;
} }
} }

View File

@ -41,7 +41,7 @@ CBotExprUnaire::~CBotExprUnaire()
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack) CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral)
{ {
int op = p->GetType(); int op = p->GetType();
CBotToken* pp = p; CBotToken* pp = p;
@ -52,7 +52,10 @@ CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack)
CBotExprUnaire* inst = new CBotExprUnaire(); CBotExprUnaire* inst = new CBotExprUnaire();
inst->SetToken(pp); inst->SetToken(pp);
if (nullptr != (inst->m_expr = CBotParExpr::Compile(p, pStk ))) if (!bLiteral) inst->m_expr = CBotParExpr::Compile(p, pStk);
else inst->m_expr = CBotParExpr::CompileLitExpr(p, pStk);
if (inst->m_expr != nullptr)
{ {
if (op == ID_ADD && pStk->GetType() < CBotTypBoolean) // only with the number if (op == ID_ADD && pStk->GetType() < CBotTypBoolean) // only with the number
return pStack->Return(inst, pStk); return pStack->Return(inst, pStk);

View File

@ -34,12 +34,13 @@ public:
~CBotExprUnaire(); ~CBotExprUnaire();
/*! /*!
* \brief Compile * \brief Compile an expression with a unary operator
* \param p * \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression
* \param pStack * \param pStack Current compilation stack frame
* \return * \param bLiteral If true, compiles only literal expressions Ex: ~11, -4.0, !false, not true
* \return The compiled instruction or nullptr
*/ */
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral = false);
/*! /*!
* \brief Execute * \brief Execute

View File

@ -44,7 +44,7 @@ CBotExprVar::~CBotExprVar()
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::ProtectionLevel privat) CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, bool bCheckReadOnly)
{ {
// CBotToken* pDebut = p; // CBotToken* pDebut = p;
CBotCStack* pStk = pStack->TokenStack(); CBotCStack* pStk = pStack->TokenStack();
@ -67,7 +67,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
if (ident > 0 && ident < 9000) if (ident > 0 && ident < 9000)
{ {
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, privat)) if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, bCheckReadOnly))
{ {
pStk->SetError(CBotErrPrivate, p); pStk->SetError(CBotErrPrivate, p);
goto err; goto err;
@ -122,6 +122,8 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
{ {
if (p->GetNext()->GetType() == ID_OPENPAR) // a method call? if (p->GetNext()->GetType() == ID_OPENPAR) // a method call?
{ {
if (bCheckReadOnly) goto err; // don't allow increment a method call "++"
CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var); CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var);
if (!pStk->IsOk()) goto err; if (!pStk->IsOk()) goto err;
inst->AddNext3(i); // added after inst->AddNext3(i); // added after
@ -137,7 +139,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
if (var != nullptr) if (var != nullptr)
{ {
i->SetUniqNum(var->GetUniqNum()); i->SetUniqNum(var->GetUniqNum());
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, privat)) if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, bCheckReadOnly))
{ {
pStk->SetError(CBotErrPrivate, pp); pStk->SetError(CBotErrPrivate, pp);
goto err; goto err;

View File

@ -40,14 +40,13 @@ public:
~CBotExprVar(); ~CBotExprVar();
/*! /*!
* \brief Compile * \brief Compile an expression of a variable, possibly chained with index operators and/or dot operators
* \param p * \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression
* \param pStack * \param pStack Current compilation stack frame
* \param privat * \param bCheckReadOnly True for operations that would modify the value of the variable
* \return * \return
*/ */
static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack, static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack, bool bCheckReadOnly = false);
CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected);
/*! /*!
* \brief CompileMethode * \brief CompileMethode
@ -81,6 +80,8 @@ public:
*/ */
bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep); bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep);
using CBotInstr::ExecuteVar;
/*! /*!
* \brief RestoreStateVar Fetch variable at runtime. * \brief RestoreStateVar Fetch variable at runtime.
* \param pj * \param pj

View File

@ -135,12 +135,11 @@ std::string CBotFieldExpr::GetDebugData()
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotFieldExpr::CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool CBotFieldExpr::CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool bCheckReadOnly)
CBotVar::ProtectionLevel privat)
{ {
CBotVar::ProtectionLevel varPriv = pVar->GetPrivate(); CBotVar::ProtectionLevel varPriv = pVar->GetPrivate();
if (privat == CBotVar::ProtectionLevel::ReadOnly && varPriv == privat) if (bCheckReadOnly && varPriv == CBotVar::ProtectionLevel::ReadOnly)
return true; return true;
if (varPriv == CBotVar::ProtectionLevel::Public) return false; if (varPriv == CBotVar::ProtectionLevel::Public) return false;

View File

@ -72,13 +72,12 @@ public:
* This function doesn't set the error flag itself. * This function doesn't set the error flag itself.
* *
* \param pStack Current compilation stack frame * \param pStack Current compilation stack frame
* \param pPrev Class instance which variable to check is part of, or nullptr if not part of a class * \param pPrev Class instance which variable to check is part of, or nullptr when compiler inserts 'this.' before
* \param pVar Variable to check * \param pVar Variable to check
* \param privat CBotVar::ProtectionLevel::ReadOnly if requesting read-only access, anything else otherwise * \param bCheckReadOnly True for operations that would modify the value of the variable
* \return true if pVar is inaccessible in the current context, false if access should be allowed * \return true if pVar is inaccessible in the current context, false if access should be allowed
*/ */
static bool CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, static bool CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool bCheckReadOnly = false);
CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected);
protected: protected:
virtual const std::string GetDebugName() override { return "CBotFieldExpr"; } virtual const std::string GetDebugName() override { return "CBotFieldExpr"; }

View File

@ -46,7 +46,6 @@ CBotFunction::CBotFunction()
{ {
m_param = nullptr; // empty parameter list m_param = nullptr; // empty parameter list
m_block = nullptr; // the instruction block m_block = nullptr; // the instruction block
m_next = nullptr; // functions can be chained
m_bPublic = false; // function not public m_bPublic = false; // function not public
m_bExtern = false; // function not extern m_bExtern = false; // function not extern
m_pProg = nullptr; m_pProg = nullptr;
@ -63,7 +62,6 @@ CBotFunction::~CBotFunction()
{ {
delete m_param; // empty parameter list delete m_param; // empty parameter list
delete m_block; // the instruction block delete m_block; // the instruction block
delete m_next;
// remove public list if there is // remove public list if there is
if (m_bPublic) if (m_bPublic)
@ -167,6 +165,7 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
if ( IsOfType(p, ID_NOT) ) if ( IsOfType(p, ID_NOT) )
{ {
CBotToken d(std::string("~") + p->GetString()); CBotToken d(std::string("~") + p->GetString());
d.SetPos(pp->GetStart(), p->GetEnd());
func->m_token = d; func->m_token = d;
} }
@ -178,7 +177,11 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
func->m_MasterClass = pp->GetString(); func->m_MasterClass = pp->GetString();
func->m_classToken = *pp; func->m_classToken = *pp;
CBotClass* pClass = CBotClass::Find(pp); CBotClass* pClass = CBotClass::Find(pp);
if ( pClass == nullptr ) goto bad; if ( pClass == nullptr )
{
pStk->SetError(CBotErrNoClassName, pp);
goto bad;
}
// pp = p; // pp = p;
func->m_token = *p; func->m_token = *p;
@ -186,6 +189,7 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
} }
func->m_openpar = *p; func->m_openpar = *p;
delete func->m_param;
func->m_param = CBotDefParam::Compile(p, pStk ); func->m_param = CBotDefParam::Compile(p, pStk );
func->m_closepar = *(p->GetPrev()); func->m_closepar = *(p->GetPrev());
if (pStk->IsOk()) if (pStk->IsOk())
@ -224,6 +228,12 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
func->m_closeblk = (p != nullptr && p->GetPrev() != nullptr) ? *(p->GetPrev()) : CBotToken(); func->m_closeblk = (p != nullptr && p->GetPrev() != nullptr) ? *(p->GetPrev()) : CBotToken();
if ( pStk->IsOk() ) if ( pStk->IsOk() )
{ {
if (!func->m_retTyp.Eq(CBotTypVoid) && !func->HasReturn())
{
int errPos = func->m_closeblk.GetStart();
pStk->ResetError(CBotErrNoReturn, errPos, errPos);
goto bad;
}
return pStack->ReturnFunc(func, pStk); return pStack->ReturnFunc(func, pStk);
} }
} }
@ -270,6 +280,7 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas
if ( IsOfType(p, ID_NOT) ) if ( IsOfType(p, ID_NOT) )
{ {
CBotToken d(std::string("~") + p->GetString()); CBotToken d(std::string("~") + p->GetString());
d.SetPos(pp->GetStart(), p->GetEnd());
func->m_token = d; func->m_token = d;
} }
@ -279,22 +290,47 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas
if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class
{ {
func->m_MasterClass = pp->GetString(); func->m_MasterClass = pp->GetString();
CBotClass* pClass = CBotClass::Find(pp); // existence of the class is checked
if ( pClass == nullptr ) // later in CBotFunction::Compile()
{
pStk->SetError(CBotErrNotClass, pp);
goto bad;
}
pp = p; pp = p;
func->m_token = *p; func->m_token = *p;
if (!IsOfType(p, TokenTypVar)) goto bad; if (!IsOfType(p, TokenTypVar)) goto bad;
} }
func->m_param = CBotDefParam::Compile(p, pStk );
CBotToken* openPar = p;
func->m_param = CBotDefParam::Compile(p, pStk); // compile parameters
if (pStk->IsOk() && pClass != nullptr) // method in a class
{
// check if a constructor has return type void
if (func->GetName() == pClass->GetName() && !func->m_retTyp.Eq(CBotTypVoid))
{
pp = &(func->m_retToken);
pStk->SetError(CBotErrFuncNotVoid, pp);
}
if (pStk->IsOk() && pp->GetString() == "~") // destructor
{
// check destructor name
if (func->GetName() != ("~" + pClass->GetName()))
pStk->SetError(CBotErrNoFunc, pp);
// confirm no parameters
if (pStk->IsOk() && func->m_param != nullptr)
pStk->SetError(CBotErrClosePar, openPar->GetNext());
// must return void
if (pStk->IsOk() && !func->m_retTyp.Eq(CBotTypVoid))
{
pp = &(func->m_retToken);
pStk->SetError(CBotErrFuncNotVoid, pp);
}
}
}
if (pStk->IsOk()) if (pStk->IsOk())
{ {
// looks if the function exists elsewhere // looks if the function exists elsewhere
pp = &(func->m_token);
if (( pClass != nullptr || !pStack->CheckCall(pp, func->m_param)) && if (( pClass != nullptr || !pStack->CheckCall(pp, func->m_param)) &&
( pClass == nullptr || !pClass->CheckCall(pStack->GetProgram(), func->m_param, pp)) ) ( pClass == nullptr || !pClass->CheckCall(pStack->GetProgram(), func->m_param, pp)) )
{ {
@ -334,9 +370,19 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
pile->SetProgram(m_pProg); // bases for routines pile->SetProgram(m_pProg); // bases for routines
if ( pile->IfStep() ) return false;
if ( pile->GetState() == 0 ) if ( pile->GetState() == 0 )
{ {
if ( !m_param->Execute(ppVars, pile) ) return false; // define parameters if (m_param != nullptr)
{
// stack for parameters and default args
CBotStack* pile3b = pile->AddStack();
pile3b->SetState(1);
if ( !m_param->Execute(ppVars, pile) ) return false; // define parameters
pile3b->Delete(); // done with param stack
}
pile->IncState(); pile->IncState();
} }
@ -369,8 +415,6 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
pile->IncState(); pile->IncState();
} }
if ( pile->IfStep() ) return false;
if ( !m_block->Execute(pile) ) if ( !m_block->Execute(pile) )
{ {
if ( pile->GetError() < 0 ) if ( pile->GetError() < 0 )
@ -399,7 +443,22 @@ void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInst
pile2->Delete(); pile2->Delete();
} }
m_param->RestoreState(pile2, true); // parameters if ( pile->GetState() == 0 )
{
if (m_param != nullptr)
{
CBotStack* pile3b = pile2->RestoreStack();
if (pile3b != nullptr && pile3b->GetState() == 1)
m_param->RestoreState(pile2, true); // restore executing default arguments
else
m_param->RestoreState(pile2, false); // restore parameter IDs
}
return;
}
if (m_param != nullptr)
m_param->RestoreState(pile2, false); // restore parameter IDs
if ( !m_MasterClass.empty() ) if ( !m_MasterClass.empty() )
{ {
@ -412,37 +471,28 @@ void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInst
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotFunction::AddNext(CBotFunction* p) CBotTypResult CBotFunction::CompileCall(const std::list<CBotFunction*>& localFunctionList, const std::string &name, CBotVar** ppVars, long &nIdent)
{ {
CBotFunction* pp = this; CBotTypResult type;
while (pp->m_next != nullptr) pp = pp->m_next; if (!FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type))
{
pp->m_next = p; // Reset the identifier to "not found" value
} nIdent = 0;
}
////////////////////////////////////////////////////////////////////////////////
CBotTypResult CBotFunction::CompileCall(const std::string& name, CBotVar** ppVars, long& nIdent)
{
nIdent = 0;
CBotTypResult type;
// CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
FindLocalOrPublic(nIdent, name, ppVars, type);
return type; return type;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& name, CBotVar** ppVars, CBotFunction* CBotFunction::FindLocalOrPublic(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name,
CBotTypResult& TypeOrError, bool bPublic) CBotVar** ppVars, CBotTypResult &TypeOrError, bool bPublic)
{ {
TypeOrError.SetType(CBotErrUndefCall); // no routine of the name TypeOrError.SetType(CBotErrUndefCall); // no routine of the name
CBotFunction* pt;
if ( nIdent ) if ( nIdent )
{ {
if ( this != nullptr ) for ( pt = this ; pt != nullptr ; pt = pt->m_next ) for (CBotFunction* pt : localFunctionList)
{ {
if ( pt->m_nFuncIdent == nIdent ) if (pt->m_nFuncIdent == nIdent)
{ {
TypeOrError = pt->m_retTyp; TypeOrError = pt->m_retTyp;
return pt; return pt;
@ -464,62 +514,64 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
std::map<CBotFunction*, int> funcMap; std::map<CBotFunction*, int> funcMap;
if ( this != nullptr ) for (CBotFunction* pt : localFunctionList)
{ {
for ( pt = this ; pt != nullptr ; pt = pt->m_next ) if ( pt->m_token.GetString() == name )
{ {
if ( pt->m_token.GetString() == name ) int i = 0;
int alpha = 0; // signature of parameters
// parameters are compatible?
CBotDefParam* pv = pt->m_param; // expected list of parameters
CBotVar* pw = ppVars[i++]; // provided list parameter
while ( pv != nullptr && (pw != nullptr || pv->HasDefault()) )
{ {
int i = 0; if (pw == nullptr) // end of arguments
int alpha = 0; // signature of parameters
// parameters are compatible?
CBotDefParam* pv = pt->m_param; // expected list of parameters
CBotVar* pw = ppVars[i++]; // provided list parameter
while ( pv != nullptr && pw != nullptr)
{ {
CBotTypResult paramType = pv->GetTypResult();
CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
if (!TypesCompatibles(paramType, argType))
{
if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam);
break;
}
if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer))
{
CBotClass* c1 = paramType.GetClass();
CBotClass* c2 = argType.GetClass();
while (c2 != c1 && c2 != nullptr) // implicit cast
{
alpha += 10;
c2 = c2->GetParent();
}
}
else
{
int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
}
pv = pv->GetNext(); pv = pv->GetNext();
pw = ppVars[i++]; continue; // skip params with default values
} }
if ( pw != nullptr ) CBotTypResult paramType = pv->GetTypResult();
CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
if (!TypesCompatibles(paramType, argType))
{ {
if ( !funcMap.empty() ) continue; if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam);
if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam); break;
if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam);
continue; // too many parameters
} }
if ( pv != nullptr )
if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer))
{ {
if ( !funcMap.empty() ) continue; CBotClass* c1 = paramType.GetClass();
if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam); CBotClass* c2 = argType.GetClass();
if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam); while (c2 != c1 && c2 != nullptr) // implicit cast
continue; // not enough parameters {
alpha += 10;
c2 = c2->GetParent();
}
} }
funcMap.insert( std::pair<CBotFunction*, int>(pt, alpha) ); else
{
int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
}
pv = pv->GetNext();
pw = ppVars[i++];
} }
if ( pw != nullptr )
{
if ( !funcMap.empty() ) continue;
if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam);
if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam);
continue; // too many parameters
}
if ( pv != nullptr )
{
if ( !funcMap.empty() ) continue;
if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam);
if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam);
continue; // not enough parameters
}
funcMap.insert( std::pair<CBotFunction*, int>(pt, alpha) );
} }
} }
@ -534,8 +586,13 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
// parameters sont-ils compatibles ? // parameters sont-ils compatibles ?
CBotDefParam* pv = pt->m_param; // list of expected parameters CBotDefParam* pv = pt->m_param; // list of expected parameters
CBotVar* pw = ppVars[i++]; // list of provided parameters CBotVar* pw = ppVars[i++]; // list of provided parameters
while ( pv != nullptr && pw != nullptr) while ( pv != nullptr && (pw != nullptr || pv->HasDefault()) )
{ {
if (pw == nullptr) // end of arguments
{
pv = pv->GetNext();
continue; // skip params with default values
}
CBotTypResult paramType = pv->GetTypResult(); CBotTypResult paramType = pv->GetTypResult();
CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
@ -610,12 +667,13 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken) int CBotFunction::DoCall(CBotProgram* program, const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name,
CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken)
{ {
CBotTypResult type; CBotTypResult type;
CBotFunction* pt = nullptr; CBotFunction* pt = nullptr;
pt = FindLocalOrPublic(nIdent, name, ppVars, type); pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type);
if ( pt != nullptr ) if ( pt != nullptr )
{ {
@ -632,9 +690,12 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars
if ( pStk1->GetState() == 0 ) if ( pStk1->GetState() == 0 )
{ {
if ( !pt->m_MasterClass.empty() ) // stack for parameters and default args
CBotStack* pStk3b = pStk3->AddStack();
if (pStk3b->GetState() == 0 && !pt->m_MasterClass.empty())
{ {
CBotVar* pInstance = m_pProg->m_thisVar; CBotVar* pInstance = program->m_thisVar;
// make "this" known // make "this" known
CBotVar* pThis ; CBotVar* pThis ;
if ( pInstance == nullptr ) if ( pInstance == nullptr )
@ -658,10 +719,21 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars
pThis->SetUniqNum(-2); pThis->SetUniqNum(-2);
pStk1->AddVar(pThis); pStk1->AddVar(pThis);
} }
pStk3b->SetState(1); // set 'this' was created
// initializes the variables as parameters // initializes the variables as parameters
pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted if (pt->m_param != nullptr)
{
if (!pt->m_param->Execute(ppVars, pStk3)) // interupt here
{
if (!pStk3->IsOk() && pt->m_pProg != program)
{
pStk3->SetPosError(pToken); // indicates the error on the procedure call
}
return false;
}
}
pStk3b->Delete(); // done with param stack
pStk1->IncState(); pStk1->IncState();
} }
@ -670,7 +742,7 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars
if ( !pStk3->GetRetVar( // puts the result on the stack if ( !pStk3->GetRetVar( // puts the result on the stack
pt->m_block->Execute(pStk3) )) // GetRetVar said if it is interrupted pt->m_block->Execute(pStk3) )) // GetRetVar said if it is interrupted
{ {
if ( !pStk3->IsOk() && pt->m_pProg != m_pProg ) if ( !pStk3->IsOk() && pt->m_pProg != program )
{ {
pStk3->SetPosError(pToken); // indicates the error on the procedure call pStk3->SetPosError(pToken); // indicates the error on the procedure call
} }
@ -683,7 +755,8 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar** ppVars, CBotStack* pStack) void CBotFunction::RestoreCall(const std::list<CBotFunction*>& localFunctionList,
long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack)
{ {
CBotTypResult type; CBotTypResult type;
CBotFunction* pt = nullptr; CBotFunction* pt = nullptr;
@ -692,7 +765,7 @@ void CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar**
// search function to return the ok identifier // search function to return the ok identifier
pt = FindLocalOrPublic(nIdent, name, ppVars, type); pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type);
if ( pt != nullptr ) if ( pt != nullptr )
{ {
@ -729,24 +802,33 @@ void CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar**
if ( pStk1->GetState() == 0 ) if ( pStk1->GetState() == 0 )
{ {
pt->m_param->RestoreState(pStk3, true); if (pt->m_param != nullptr)
{
CBotStack* pStk3b = pStk3->RestoreStack();
if (pStk3b != nullptr && pStk3b->GetState() == 1)
pt->m_param->RestoreState(pStk3, true); // restore executing default arguments
else
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
}
return; return;
} }
// initializes the variables as parameters // initializes the variables as parameters
pt->m_param->RestoreState(pStk3, false); if (pt->m_param != nullptr)
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
pt->m_block->RestoreState(pStk3, true); pt->m_block->RestoreState(pStk3, true);
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, int CBotFunction::DoCall(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis,
CBotToken* pToken, CBotClass* pClass) CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass)
{ {
CBotTypResult type; CBotTypResult type;
CBotProgram* pProgCurrent = pStack->GetProgram(); CBotProgram* pProgCurrent = pStack->GetProgram();
CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false); CBotFunction* pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type, false);
if ( pt != nullptr ) if ( pt != nullptr )
{ {
@ -762,23 +844,42 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar* pThis,
if ( pStk->GetState() == 0 ) if ( pStk->GetState() == 0 )
{ {
// sets the variable "this" on the stack // stack for parameters and default args
CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer); CBotStack* pStk3b = pStk3->AddStack();
pthis->Copy(pThis, false);
pthis->SetUniqNum(-2); // special value
pStk->AddVar(pthis);
CBotClass* pClass = pThis->GetClass()->GetParent(); if (pStk3b->GetState() == 0)
if ( pClass )
{ {
// sets the variable "super" on the stack // sets the variable "this" on the stack
CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer); CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer);
psuper->Copy(pThis, false); // in fact identical to "this" pthis->Copy(pThis, false);
psuper->SetUniqNum(-3); // special value pthis->SetUniqNum(-2); // special value
pStk->AddVar(psuper); pStk->AddVar(pthis);
CBotClass* pClass = pThis->GetClass()->GetParent();
if ( pClass )
{
// sets the variable "super" on the stack
CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer);
psuper->Copy(pThis, false); // in fact identical to "this"
psuper->SetUniqNum(-3); // special value
pStk->AddVar(psuper);
}
} }
pStk3b->SetState(1); // set 'this' was created
// initializes the variables as parameters // initializes the variables as parameters
pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted if (pt->m_param != nullptr)
{
if (!pt->m_param->Execute(ppVars, pStk3)) // interupt here
{
if (!pStk3->IsOk() && pt->m_pProg != pProgCurrent)
{
pStk3->SetPosError(pToken); // indicates the error on the procedure call
}
return false;
}
}
pStk3b->Delete(); // done with param stack
pStk->IncState(); pStk->IncState();
} }
@ -822,11 +923,11 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar* pThis,
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar* pThis, CBotVar** ppVars, bool CBotFunction::RestoreCall(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis,
CBotStack* pStack, CBotClass* pClass) CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass)
{ {
CBotTypResult type; CBotTypResult type;
CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type); CBotFunction* pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type);
if ( pt != nullptr ) if ( pt != nullptr )
{ {
@ -846,7 +947,21 @@ bool CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar* p
CBotStack* pStk3 = pStk->RestoreStack(nullptr); // to set parameters passed CBotStack* pStk3 = pStk->RestoreStack(nullptr); // to set parameters passed
if ( pStk3 == nullptr ) return true; if ( pStk3 == nullptr ) return true;
pt->m_param->RestoreState(pStk3, true); // parameters if ( pStk->GetState() == 0 )
{
if (pt->m_param != nullptr)
{
CBotStack* pStk3b = pStk3->RestoreStack();
if (pStk3b != nullptr && pStk3b->GetState() == 1)
pt->m_param->RestoreState(pStk3, true); // restore executing default arguments
else
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
}
return true;
}
if (pt->m_param != nullptr)
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
if ( pStk->GetState() > 1 && // latching is effective? if ( pStk->GetState() > 1 && // latching is effective?
pt->m_bSynchro ) pt->m_bSynchro )
@ -903,18 +1018,18 @@ std::string CBotFunction::GetParams()
return params; return params;
} }
////////////////////////////////////////////////////////////////////////////////
CBotFunction* CBotFunction::Next()
{
return m_next;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotFunction::AddPublic(CBotFunction* func) void CBotFunction::AddPublic(CBotFunction* func)
{ {
m_publicFunctions.insert(func); m_publicFunctions.insert(func);
} }
bool CBotFunction::HasReturn()
{
if (m_block != nullptr) return m_block->HasReturn();
return false;
}
std::string CBotFunction::GetDebugData() std::string CBotFunction::GetDebugData()
{ {
std::stringstream ss; std::stringstream ss;

View File

@ -60,11 +60,16 @@ public:
bool bLocal = true); bool bLocal = true);
/*! /*!
* \brief Compile1 Pre-compile a new function. * \brief Pre-compile a new function
* \param p * \param p[in, out] Pointer to first token of the function, will be updated to point to first token after the function definition
* \param pStack * \param pStack Compile stack
* \param pClass * \param pClass If this is a class method, pointer to class this function is part of, otherwise nullptr
* \return *
* This function is used to find the beginning and end of function definition.
*
* If any errors in the code are detected, this function will set the error on compile stack and return nullptr.
*
* \return Precompiled function, or nullptr in case of error
*/ */
static CBotFunction* Compile1(CBotToken* &p, static CBotFunction* Compile1(CBotToken* &p,
CBotCStack* pStack, CBotCStack* pStack,
@ -81,6 +86,8 @@ public:
CBotStack* &pj, CBotStack* &pj,
CBotVar* pInstance = nullptr); CBotVar* pInstance = nullptr);
using CBotInstr::Execute;
/*! /*!
* \brief RestoreState * \brief RestoreState
* \param ppVars * \param ppVars
@ -91,40 +98,46 @@ public:
CBotStack* &pj, CBotStack* &pj,
CBotVar* pInstance = nullptr); CBotVar* pInstance = nullptr);
/*! using CBotInstr::RestoreState;
* \brief AddNext
* \param p
*/
void AddNext(CBotFunction* p);
/*! /*!
* \brief CompileCall * \brief Compile a function call
* \param name *
* \param ppVars * See FindLocalOrPublic for more detailed explanation
* \param nIdent *
* \return * \param localFunctionList Linked list of local functions to search in, can be null
* \param name Name of the function
* \param ppVars List of function arguments
* \param nIdent[in, out] Unique identifier of the function
* \return Type returned by the function or error code
* \see FindLocalOrPublic
*/ */
CBotTypResult CompileCall(const std::string& name, static CBotTypResult CompileCall(const std::list<CBotFunction*>& localFunctionList,
CBotVar** ppVars, const std::string &name, CBotVar** ppVars, long &nIdent);
long& nIdent);
/*! /*!
* \brief FindLocalOrPublic Is a function according to its unique identifier * \brief Finds a local or public function
* if the identifier is not found, looking by name and parameters. *
* \param nIdent * <p>Finds a local or (if bPublic is true) public function to call
* \param name *
* \param ppVars * <p>First, it looks for a function according to its unique identifier.<br>
* \param TypeOrError * If the identifier is not found, looks by name and parameters.
* \param bPublic *
* \return * \param localFunctionList Linked list of local functions to search in, can be null
* \param nIdent[in, out] Unique identifier of the function
* \param name Name of the function
* \param ppVars List of function arguments
* \param TypeOrError Type returned by the function or error code
* \param bPublic Whether to look in public functions or not
* \return Pointer to found CBotFunction instance, or nullptr in case of no match or ambiguity (see TypeOrError for error code)
*/ */
CBotFunction* FindLocalOrPublic(long& nIdent, const std::string& name, static CBotFunction* FindLocalOrPublic(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name,
CBotVar** ppVars, CBotVar** ppVars, CBotTypResult &TypeOrError, bool bPublic = true);
CBotTypResult& TypeOrError,
bool bPublic = true);
/*! /*!
* \brief DoCall Fait un appel à une fonction. * \brief DoCall Fait un appel à une fonction.
* \param program
* \param localFunctionList
* \param nIdent * \param nIdent
* \param name * \param name
* \param ppVars * \param ppVars
@ -133,27 +146,24 @@ public:
* \return * \return
*/ */
int DoCall(long& nIdent, static int DoCall(CBotProgram* program, const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name,
const std::string& name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken);
CBotVar** ppVars,
CBotStack* pStack,
CBotToken* pToken);
/*! /*!
* \brief RestoreCall * \brief RestoreCall
* \param localFunctionList
* \param nIdent * \param nIdent
* \param name * \param name
* \param ppVars * \param ppVars
* \param pStack * \param pStack
*/ */
void RestoreCall(long& nIdent, static void RestoreCall(const std::list<CBotFunction*>& localFunctionList,
const std::string& name, long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack);
CBotVar** ppVars,
CBotStack* pStack);
/*! /*!
* \brief DoCall Makes call of a method note: this is already on the stack, * \brief DoCall Makes call of a method
* the pointer pThis is just to simplify. * note: this is already on the stack, the pointer pThis is just to simplify.
* \param localFunctionList
* \param nIdent * \param nIdent
* \param name * \param name
* \param pThis * \param pThis
@ -163,16 +173,12 @@ public:
* \param pClass * \param pClass
* \return * \return
*/ */
int DoCall(long& nIdent, static int DoCall(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis,
const std::string& name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass);
CBotVar* pThis,
CBotVar** ppVars,
CBotStack* pStack,
CBotToken* pToken,
CBotClass* pClass);
/*! /*!
* \brief RestoreCall * \brief RestoreCall
* \param localFunctionList
* \param nIdent * \param nIdent
* \param name * \param name
* \param pThis * \param pThis
@ -181,12 +187,8 @@ public:
* \param pClass * \param pClass
* \return Returns true if the method call was restored. * \return Returns true if the method call was restored.
*/ */
bool RestoreCall(long& nIdent, static bool RestoreCall(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis,
const std::string& name, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass);
CBotVar* pThis,
CBotVar** ppVars,
CBotStack* pStack,
CBotClass* pClass);
/*! /*!
* \brief CheckParam See if the "signature" of parameters is identical. * \brief CheckParam See if the "signature" of parameters is identical.
@ -225,12 +227,6 @@ public:
*/ */
bool IsExtern(); bool IsExtern();
/*!
* \brief Next
* \return
*/
CBotFunction* Next();
/*! /*!
* \brief GetPosition * \brief GetPosition
* \param start * \param start
@ -243,6 +239,12 @@ public:
CBotGet modestart, CBotGet modestart,
CBotGet modestop); CBotGet modestop);
/*!
* \brief Check if the function has a return statment that will execute.
* \return true if a return statment was found.
*/
bool HasReturn() override;
protected: protected:
virtual const std::string GetDebugName() override { return "CBotFunction"; } virtual const std::string GetDebugName() override { return "CBotFunction"; }
virtual std::string GetDebugData() override; virtual std::string GetDebugData() override;
@ -258,7 +260,6 @@ private:
CBotDefParam* m_param; CBotDefParam* m_param;
//! The instruction block. //! The instruction block.
CBotInstr* m_block; CBotInstr* m_block;
CBotFunction* m_next;
//! If returns CBotTypClass. //! If returns CBotTypClass.
CBotToken m_retToken; CBotToken m_retToken;
//! Complete type of the result. //! Complete type of the result.

View File

@ -163,6 +163,15 @@ void CBotIf :: RestoreState(CBotStack* &pj, bool bMain)
} }
} }
bool CBotIf::HasReturn()
{
if (m_block != nullptr && m_blockElse != nullptr)
{
if (m_block->HasReturn() && m_blockElse->HasReturn()) return true;
}
return CBotInstr::HasReturn(); // check next block or instruction
}
std::map<std::string, CBotInstr*> CBotIf::GetDebugLinks() std::map<std::string, CBotInstr*> CBotIf::GetDebugLinks()
{ {
auto links = CBotInstr::GetDebugLinks(); auto links = CBotInstr::GetDebugLinks();

View File

@ -56,6 +56,14 @@ public:
*/ */
void RestoreState(CBotStack* &pj, bool bMain) override; void RestoreState(CBotStack* &pj, bool bMain) override;
/**
* \brief Check 'if' and 'else' for return statements.
* Returns true when 'if' and 'else' have return statements,
* if not, the next block or instruction is checked.
* \return true if a return statement is found.
*/
bool HasReturn() override;
protected: protected:
virtual const std::string GetDebugName() override { return "CBotIf"; } virtual const std::string GetDebugName() override { return "CBotIf"; }
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override; virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;

View File

@ -359,6 +359,12 @@ CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypRes
return nullptr; return nullptr;
} }
bool CBotInstr::HasReturn()
{
if (m_next != nullptr) return m_next->HasReturn();
return false; // end of the list
}
std::map<std::string, CBotInstr*> CBotInstr::GetDebugLinks() std::map<std::string, CBotInstr*> CBotInstr::GetDebugLinks()
{ {
return { return {

View File

@ -281,6 +281,12 @@ public:
*/ */
static bool ChkLvl(const std::string& label, int type); static bool ChkLvl(const std::string& label, int type);
/**
* \brief Check a list of instructions for a return statement.
* \return true if a return statement was found.
*/
virtual bool HasReturn();
protected: protected:
friend class CBotDebug; friend class CBotDebug;
/** /**

View File

@ -36,6 +36,7 @@ namespace CBot
CBotInstrCall::CBotInstrCall() CBotInstrCall::CBotInstrCall()
{ {
m_parameters = nullptr; m_parameters = nullptr;
m_exprRetVar = nullptr;
m_nFuncIdent = 0; m_nFuncIdent = 0;
} }
@ -43,6 +44,7 @@ CBotInstrCall::CBotInstrCall()
CBotInstrCall::~CBotInstrCall() CBotInstrCall::~CBotInstrCall()
{ {
delete m_parameters; delete m_parameters;
delete m_exprRetVar;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -36,6 +36,7 @@ namespace CBot
CBotInstrMethode::CBotInstrMethode() CBotInstrMethode::CBotInstrMethode()
{ {
m_parameters = nullptr; m_parameters = nullptr;
m_exprRetVar = nullptr;
m_MethodeIdent = 0; m_MethodeIdent = 0;
} }
@ -43,6 +44,7 @@ CBotInstrMethode::CBotInstrMethode()
CBotInstrMethode::~CBotInstrMethode() CBotInstrMethode::~CBotInstrMethode()
{ {
delete m_parameters; delete m_parameters;
delete m_exprRetVar;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -67,8 +69,7 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar*
inst->m_thisIdent = var->GetUniqNum(); inst->m_thisIdent = var->GetUniqNum();
CBotClass* pClass = var->GetClass(); // pointer to the class CBotClass* pClass = var->GetClass(); // pointer to the class
inst->m_className = pClass->GetName(); // name of the class inst->m_className = pClass->GetName(); // name of the class
CBotTypResult r = pClass->CompileMethode(inst->m_methodName, var, ppVars, CBotTypResult r = pClass->CompileMethode(pp, var, ppVars, pStack, inst->m_MethodeIdent);
pStack, inst->m_MethodeIdent);
delete pStack->TokenStack(); // release parameters on the stack delete pStack->TokenStack(); // release parameters on the stack
inst->m_typRes = r; inst->m_typRes = r;
@ -176,18 +177,7 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre
else else
pClass = pThis->GetClass(); pClass = pThis->GetClass();
CBotVar* pResult = nullptr; if ( !pClass->ExecuteMethode(m_MethodeIdent, pThis, ppVars, m_typRes, pile2, GetToken())) return false;
if (m_typRes.GetType() > 0) pResult = CBotVar::Create("", m_typRes);
if (m_typRes.Eq(CBotTypClass))
{
pResult->SetClass(m_typRes.GetClass());
}
CBotVar* pRes = pResult;
if ( !pClass->ExecuteMethode(m_MethodeIdent, m_methodName,
pThis, ppVars,
pResult, pile2, GetToken())) return false;
if (pRes != pResult) delete pRes;
if (m_exprRetVar != nullptr) // .func().member if (m_exprRetVar != nullptr) // .func().member
{ {
@ -264,8 +254,7 @@ void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain)
// CBotVar* pRes = pResult; // CBotVar* pRes = pResult;
pClass->RestoreMethode(m_MethodeIdent, m_methodName, pClass->RestoreMethode(m_MethodeIdent, &m_token, pThis, ppVars, pile2);
pThis, ppVars, pile2);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -316,24 +305,12 @@ bool CBotInstrMethode::Execute(CBotStack* &pj)
else else
pClass = pThis->GetClass(); pClass = pThis->GetClass();
CBotVar* pResult = nullptr; if ( !pClass->ExecuteMethode(m_MethodeIdent, pThis, ppVars, m_typRes, pile2, GetToken())) return false; // interupted
if (m_typRes.GetType()>0) pResult = CBotVar::Create("", m_typRes);
if (m_typRes.Eq(CBotTypClass))
{
pResult->SetClass(m_typRes.GetClass());
}
CBotVar* pRes = pResult;
if ( !pClass->ExecuteMethode(m_MethodeIdent, m_methodName,
pThis, ppVars,
pResult, pile2, GetToken())) return false; // interupted
// set the new value of this in place of the old variable // set the new value of this in place of the old variable
CBotVar* old = pile1->FindVar(m_token, false); CBotVar* old = pile1->FindVar(m_token, false);
old->Copy(pThis, false); old->Copy(pThis, false);
if (pRes != pResult) delete pRes;
return pj->Return(pile2); // release the entire stack return pj->Return(pile2); // release the entire stack
} }

View File

@ -64,7 +64,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
inst->m_nIdent = var->GetUniqNum(); inst->m_nIdent = var->GetUniqNum();
if (inst->m_nIdent > 0 && inst->m_nIdent < 9000) if (inst->m_nIdent > 0 && inst->m_nIdent < 9000)
{ {
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, CBotVar::ProtectionLevel::ReadOnly)) if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, true))
{ {
pStk->SetError(CBotErrPrivate, p); pStk->SetError(CBotErrPrivate, p);
goto err; goto err;
@ -128,8 +128,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
var = var->GetItem(p->GetString()); // get item correspondent var = var->GetItem(p->GetString()); // get item correspondent
if (var != nullptr) if (var != nullptr)
{ {
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, true))
CBotVar::ProtectionLevel::ReadOnly))
{ {
pStk->SetError(CBotErrPrivate, pp); pStk->SetError(CBotErrPrivate, pp);
goto err; goto err;

View File

@ -61,6 +61,8 @@ public:
*/ */
bool Execute(CBotStack* &pStack, CBotStack* array); bool Execute(CBotStack* &pStack, CBotStack* array);
using CBotInstr::Execute;
/*! /*!
* \brief ExecuteVar Fetch a variable during compilation. * \brief ExecuteVar Fetch a variable during compilation.
* \param pVar * \param pVar
@ -69,6 +71,8 @@ public:
*/ */
bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) override; bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) override;
using CBotInstr::ExecuteVar;
/*! /*!
* \brief ExecuteVar Fetch the variable at runtume. * \brief ExecuteVar Fetch the variable at runtume.
* \param pVar * \param pVar

View File

@ -52,7 +52,7 @@ CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal
if (IsOfType(p, ID_SEP)) continue; // empty statement ignored if (IsOfType(p, ID_SEP)) continue; // empty statement ignored
if (p->GetType() == ID_CLBLK) break; if (p->GetType() == ID_CLBLK) break;
if (IsOfType(p, 0)) if (p->GetType() == TokenTypNone)
{ {
pStack->SetError(CBotErrCloseBlock, p->GetStart()); pStack->SetError(CBotErrCloseBlock, p->GetStart());
delete inst; delete inst;
@ -117,6 +117,12 @@ void CBotListInstr::RestoreState(CBotStack* &pj, bool bMain)
if (p != nullptr) p->RestoreState(pile, true); if (p != nullptr) p->RestoreState(pile, true);
} }
bool CBotListInstr::HasReturn()
{
if (m_instr != nullptr && m_instr->HasReturn()) return true;
return CBotInstr::HasReturn(); // check next block or instruction
}
std::map<std::string, CBotInstr*> CBotListInstr::GetDebugLinks() std::map<std::string, CBotInstr*> CBotListInstr::GetDebugLinks()
{ {
auto links = CBotInstr::GetDebugLinks(); auto links = CBotInstr::GetDebugLinks();

View File

@ -56,6 +56,13 @@ public:
*/ */
void RestoreState(CBotStack* &pj, bool bMain) override; void RestoreState(CBotStack* &pj, bool bMain) override;
/**
* \brief Check this block of instructions for a return statement.
* If not found, the next block or instruction is checked.
* \return true if a return statement was found.
*/
bool HasReturn() override;
protected: protected:
virtual const std::string GetDebugName() override { return "CBotListInstr"; } virtual const std::string GetDebugName() override { return "CBotListInstr"; }
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override; virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;

View File

@ -36,12 +36,15 @@ namespace CBot
CBotNew::CBotNew() CBotNew::CBotNew()
{ {
m_parameters = nullptr; m_parameters = nullptr;
m_exprRetVar = nullptr;
m_nMethodeIdent = 0; m_nMethodeIdent = 0;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotNew::~CBotNew() CBotNew::~CBotNew()
{ {
delete m_parameters;
delete m_exprRetVar;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -83,7 +86,7 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
if (!pStk->IsOk()) goto error; if (!pStk->IsOk()) goto error;
// constructor exist? // constructor exist?
CBotTypResult r = pClass->CompileMethode(pClass->GetName(), pVar, ppVars, pStk, inst->m_nMethodeIdent); CBotTypResult r = pClass->CompileMethode(&inst->m_vartoken, pVar, ppVars, pStk, inst->m_nMethodeIdent);
delete pStk->TokenStack(); // release extra stack delete pStk->TokenStack(); // release extra stack
int typ = r.GetType(); int typ = r.GetType();
@ -197,12 +200,7 @@ bool CBotNew::Execute(CBotStack* &pj)
} }
ppVars[i] = nullptr; ppVars[i] = nullptr;
// create a variable for the result if ( !pClass->ExecuteMethode(m_nMethodeIdent, pThis, ppVars, CBotTypResult(CBotTypVoid), pile2, &m_vartoken)) return false; // interrupt
CBotVar* pResult = nullptr; // constructos still void
if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GetName(),
pThis, ppVars,
pResult, pile2, GetToken())) return false; // interrupt
pThis->ConstructorSet(); // indicates that the constructor has been called pThis->ConstructorSet(); // indicates that the constructor has been called
} }
@ -284,8 +282,7 @@ void CBotNew::RestoreState(CBotStack* &pj, bool bMain)
} }
ppVars[i] = nullptr; ppVars[i] = nullptr;
pClass->RestoreMethode(m_nMethodeIdent, m_vartoken.GetString(), pThis, pClass->RestoreMethode(m_nMethodeIdent, &m_vartoken, pThis, ppVars, pile2); // interrupt here!
ppVars, pile2) ; // interrupt here!
} }
} }

View File

@ -90,17 +90,16 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
// post incremented or decremented? // post incremented or decremented?
if (IsOfType(p, ID_INC, ID_DEC)) if (IsOfType(p, ID_INC, ID_DEC))
{ {
// recompile the variable for read-only
delete inst;
p = pvar;
inst = CBotExprVar::Compile(p, pStk, true);
if (pStk->GetType() >= CBotTypBoolean) if (pStk->GetType() >= CBotTypBoolean)
{ {
pStk->SetError(CBotErrBadType1, pp); pStk->SetError(CBotErrBadType1, pp);
delete inst; delete inst;
return pStack->Return(nullptr, pStk); return pStack->Return(nullptr, pStk);
} }
// recompile the variable for read-only
delete inst;
p = pvar;
inst = CBotExprVar::Compile(p, pStk, CBotVar::ProtectionLevel::ReadOnly);
p = p->GetNext(); p = p->GetNext();
CBotPostIncExpr* i = new CBotPostIncExpr(); CBotPostIncExpr* i = new CBotPostIncExpr();
@ -115,26 +114,39 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
CBotToken* pp = p; CBotToken* pp = p;
if (IsOfType(p, ID_INC, ID_DEC)) if (IsOfType(p, ID_INC, ID_DEC))
{ {
CBotPreIncExpr* i = new CBotPreIncExpr();
i->SetToken(pp);
if (p->GetType() == TokenTypVar) if (p->GetType() == TokenTypVar)
{ {
if (nullptr != (i->m_instr = CBotExprVar::Compile(p, pStk, CBotVar::ProtectionLevel::ReadOnly))) if (nullptr != (inst = CBotExprVar::Compile(p, pStk, true)))
{ {
if (pStk->GetType() >= CBotTypBoolean) if (pStk->GetType() < CBotTypBoolean) // a number ?
{ {
pStk->SetError(CBotErrBadType1, pp); CBotPreIncExpr* i = new CBotPreIncExpr();
delete inst; i->SetToken(pp);
return pStack->Return(nullptr, pStk); i->m_instr = inst;
return pStack->Return(i, pStk);
} }
return pStack->Return(i, pStk); delete inst;
} }
delete i;
return pStack->Return(nullptr, pStk);
} }
pStk->SetError(CBotErrBadType1, pp);
return pStack->Return(nullptr, pStk);
} }
return CBotParExpr::CompileLitExpr(p, pStack);
}
////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotParExpr::CompileLitExpr(CBotToken* &p, CBotCStack* pStack)
{
CBotCStack* pStk = pStack->TokenStack();
CBotToken* pp = p;
// is this a unary operation?
CBotInstr* inst = CBotExprUnaire::Compile(p, pStk, true);
if (inst != nullptr || !pStk->IsOk())
return pStack->Return(inst, pStk);
// is it a number or DefineNum? // is it a number or DefineNum?
if (p->GetType() == TokenTypNum || if (p->GetType() == TokenTypNum ||
p->GetType() == TokenTypDef ) p->GetType() == TokenTypDef )

View File

@ -54,6 +54,14 @@ public:
*/ */
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
/*!
* \brief Compile a literal expression ("string", number, true, false, null, nan, new)
* \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression
* \param pStack Current compilation stack frame
* \return The compiled instruction or nullptr on error
*/
static CBotInstr* CompileLitExpr(CBotToken* &p, CBotCStack* pStack);
private: private:
CBotParExpr() = delete; CBotParExpr() = delete;
CBotParExpr(const CBotParExpr&) = delete; CBotParExpr(const CBotParExpr&) = delete;

View File

@ -111,6 +111,11 @@ void CBotReturn::RestoreState(CBotStack* &pj, bool bMain)
} }
} }
bool CBotReturn::HasReturn()
{
return true;
}
std::map<std::string, CBotInstr*> CBotReturn::GetDebugLinks() std::map<std::string, CBotInstr*> CBotReturn::GetDebugLinks()
{ {
auto links = CBotInstr::GetDebugLinks(); auto links = CBotInstr::GetDebugLinks();

View File

@ -55,6 +55,12 @@ public:
*/ */
void RestoreState(CBotStack* &pj, bool bMain) override; void RestoreState(CBotStack* &pj, bool bMain) override;
/*!
* \brief Always returns true.
* \return true to signal a return statment has been found.
*/
bool HasReturn() override;
protected: protected:
virtual const std::string GetDebugName() override { return "CBotReturn"; } virtual const std::string GetDebugName() override { return "CBotReturn"; }
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override; virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;

View File

@ -30,6 +30,8 @@
#include "CBot/stdlib/stdlib.h" #include "CBot/stdlib/stdlib.h"
#include <algorithm>
namespace CBot namespace CBot
{ {
@ -47,27 +49,30 @@ CBotProgram::CBotProgram(CBotVar* thisVar)
CBotProgram::~CBotProgram() CBotProgram::~CBotProgram()
{ {
// delete m_classes; // delete m_classes;
if (m_classes != nullptr) m_classes->Purge(); for (CBotClass* c : m_classes)
m_classes = nullptr; c->Purge();
m_classes.clear();
CBotClass::FreeLock(this); CBotClass::FreeLock(this);
delete m_functions; for (CBotFunction* f : m_functions) delete f;
if (m_stack != nullptr) m_stack->Delete(); m_functions.clear();
} }
bool CBotProgram::Compile(const std::string& program, std::vector<std::string>& functions, void* pUser) bool CBotProgram::Compile(const std::string& program, std::vector<std::string>& externFunctions, void* pUser)
{ {
// Cleanup the previously compiled program // Cleanup the previously compiled program
Stop(); Stop();
// delete m_classes; for (CBotClass* c : m_classes)
if (m_classes != nullptr) m_classes->Purge(); // purge the old definitions of classes c->Purge(); // purge the old definitions of classes
// but without destroying the object // but without destroying the object
m_classes = nullptr;
delete m_functions; m_functions = nullptr;
functions.clear(); m_classes.clear();
for (CBotFunction* f : m_functions) delete f;
m_functions.clear();
externFunctions.clear();
m_error = CBotNoErr; m_error = CBotNoErr;
// Step 1. Process the code into tokens // Step 1. Process the code into tokens
@ -88,15 +93,15 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
if ( p->GetType() == ID_CLASS || if ( p->GetType() == ID_CLASS ||
( p->GetType() == ID_PUBLIC && p->GetNext()->GetType() == ID_CLASS )) ( p->GetType() == ID_PUBLIC && p->GetNext()->GetType() == ID_CLASS ))
{ {
CBotClass* nxt = CBotClass::Compile1(p, pStack.get()); CBotClass* newclass = CBotClass::Compile1(p, pStack.get());
if (m_classes == nullptr ) m_classes = nxt; if (newclass != nullptr)
else m_classes->AddNext(nxt); m_classes.push_back(newclass);
} }
else else
{ {
CBotFunction* next = CBotFunction::Compile1(p, pStack.get(), nullptr); CBotFunction* newfunc = CBotFunction::Compile1(p, pStack.get(), nullptr);
if (m_functions == nullptr ) m_functions = next; if (newfunc != nullptr)
else m_functions->AddNext(next); m_functions.push_back(newfunc);
} }
} }
@ -106,17 +111,14 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
if ( !pStack->IsOk() ) if ( !pStack->IsOk() )
{ {
m_error = pStack->GetError(m_errorStart, m_errorEnd); m_error = pStack->GetError(m_errorStart, m_errorEnd);
delete m_functions; for (CBotFunction* f : m_functions) delete f;
m_functions = nullptr; m_functions.clear();
return false; return false;
} }
// Step 3. Real compilation // Step 3. Real compilation
// CBotFunction* temp = nullptr; std::list<CBotFunction*>::iterator next = m_functions.begin();
CBotFunction* next = m_functions; // rewind the list
p = tokens.get()->GetNext(); // returns to the beginning p = tokens.get()->GetNext(); // returns to the beginning
while ( pStack->IsOk() && p != nullptr && p->GetType() != 0 ) while ( pStack->IsOk() && p != nullptr && p->GetType() != 0 )
{ {
if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking
@ -128,43 +130,35 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
} }
else else
{ {
CBotFunction::Compile(p, pStack.get(), next); CBotFunction::Compile(p, pStack.get(), *next);
if (next->IsExtern()) functions.push_back(next->GetName()/* + next->GetParams()*/); if ((*next)->IsExtern()) externFunctions.push_back((*next)->GetName()/* + next->GetParams()*/);
if (next->IsPublic()) CBotFunction::AddPublic(next); if ((*next)->IsPublic()) CBotFunction::AddPublic(*next);
next->m_pProg = this; // keeps pointers to the module (*next)->m_pProg = this; // keeps pointers to the module
next = next->Next(); ++next;
} }
} }
// delete m_Prog; // the list of first pass
// m_Prog = temp; // list of the second pass
if ( !pStack->IsOk() ) if ( !pStack->IsOk() )
{ {
m_error = pStack->GetError(m_errorStart, m_errorEnd); m_error = pStack->GetError(m_errorStart, m_errorEnd);
delete m_functions; for (CBotFunction* f : m_functions) delete f;
m_functions = nullptr; m_functions.clear();
} }
return (m_functions != nullptr); return !m_functions.empty();
} }
bool CBotProgram::Start(const std::string& name) bool CBotProgram::Start(const std::string& name)
{ {
Stop(); Stop();
m_entryPoint = m_functions; auto it = std::find_if(m_functions.begin(), m_functions.end(), [&name](CBotFunction* x) { return x->GetName() == name; });
while (m_entryPoint != nullptr) if (it == m_functions.end())
{
if (m_entryPoint->GetName() == name ) break;
m_entryPoint = m_entryPoint->m_next;
}
if (m_entryPoint == nullptr)
{ {
m_error = CBotErrNoRun; m_error = CBotErrNoRun;
return false; return false;
} }
m_entryPoint = *it;
m_stack = CBotStack::AllocateStack(); m_stack = CBotStack::AllocateStack();
m_stack->SetProgram(this); m_stack->SetProgram(this);
@ -174,16 +168,10 @@ bool CBotProgram::Start(const std::string& name)
bool CBotProgram::GetPosition(const std::string& name, int& start, int& stop, CBotGet modestart, CBotGet modestop) bool CBotProgram::GetPosition(const std::string& name, int& start, int& stop, CBotGet modestart, CBotGet modestop)
{ {
CBotFunction* p = m_functions; auto it = std::find_if(m_functions.begin(), m_functions.end(), [&name](CBotFunction* x) { return x->GetName() == name; });
while (p != nullptr) if (it == m_functions.end()) return false;
{
if ( p->GetName() == name ) break;
p = p->m_next;
}
if ( p == nullptr ) return false; (*it)->GetPosition(start, stop, modestart, modestop);
p->GetPosition(start, stop, modestart, modestop);
return true; return true;
} }
@ -212,16 +200,16 @@ bool CBotProgram::Run(void* pUser, int timer)
} }
// completed on a mistake? // completed on a mistake?
if (!ok && !m_stack->IsOk()) if (ok || !m_stack->IsOk())
{ {
m_error = m_stack->GetError(m_errorStart, m_errorEnd); m_error = m_stack->GetError(m_errorStart, m_errorEnd);
m_stack->Delete(); m_stack->Delete();
m_stack = nullptr; m_stack = nullptr;
CBotClass::FreeLock(this); CBotClass::FreeLock(this);
m_entryPoint = nullptr;
return true; // execution is finished! return true; // execution is finished!
} }
if ( ok ) m_entryPoint = nullptr; // more function in execution
return ok; return ok;
} }
@ -288,11 +276,21 @@ bool CBotProgram::GetError(CBotError& code, int& start, int& end, CBotProgram*&
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotFunction* CBotProgram::GetFunctions() const std::list<CBotFunction*>& CBotProgram::GetFunctions()
{ {
return m_functions; return m_functions;
} }
bool CBotProgram::ClassExists(std::string name)
{
for (CBotClass* p : m_classes)
{
if ( p->GetName() == name ) return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser ) CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser )
{ {
@ -304,7 +302,7 @@ CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser )
bool rSizeOf( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) bool rSizeOf( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
{ {
if ( pVar == nullptr ) return CBotErrLowParam; if ( pVar == nullptr ) { ex = CBotErrLowParam; return true; }
int i = 0; int i = 0;
pVar = pVar->GetItemList(); pVar = pVar->GetItemList();
@ -375,8 +373,7 @@ bool CBotProgram::RestoreState(FILE* pf)
} }
// retrieves the stack from the memory // retrieves the stack from the memory
// uses a nullptr pointer (m_stack) but it's ok like that m_stack = CBotStack::AllocateStack();
// TODO: no it's not okay like that! but it looks like it doesn't get optimized out at least ~krzys_h
if (!m_stack->RestoreState(pf, m_stack)) return false; if (!m_stack->RestoreState(pf, m_stack)) return false;
m_stack->SetProgram(this); // bases for routines m_stack->SetProgram(this); // bases for routines

View File

@ -23,6 +23,7 @@
#include "CBot/CBotEnums.h" #include "CBot/CBotEnums.h"
#include <vector> #include <vector>
#include <list>
namespace CBot namespace CBot
{ {
@ -124,12 +125,12 @@ public:
* 3. Second pass - compiling definitions of all functions and classes * 3. Second pass - compiling definitions of all functions and classes
* *
* \param program Code to compile * \param program Code to compile
* \param[out] functions Returns the names of functions declared as extern * \param[out] externFunctions Returns the names of functions declared as extern
* \param pUser Optional pointer to be passed to compile function (see AddFunction()) * \param pUser Optional pointer to be passed to compile function (see AddFunction())
* \return true if compilation is successful, false if an compilation error occurs * \return true if compilation is successful, false if an compilation error occurs
* \see GetError() to retrieve the error * \see GetError() to retrieve the error
*/ */
bool Compile(const std::string& program, std::vector<std::string>& functions, void* pUser = nullptr); bool Compile(const std::string& program, std::vector<std::string>& externFunctions, void* pUser = nullptr);
/** /**
* \brief Returns the last error * \brief Returns the last error
@ -328,9 +329,15 @@ public:
* *
* This list includes all the functions (not only extern) * This list includes all the functions (not only extern)
* *
* \return Linked list of CBotFunction instances * \return List of CBotFunction instances
*/ */
CBotFunction* GetFunctions(); const std::list<CBotFunction*>& GetFunctions();
/**
* \brief Check if class with that name was created in this program
* \return True if class was defined in this program, otherwise, false
*/
bool ClassExists(std::string name);
/** /**
* \brief Returns static list of all registered external calls * \brief Returns static list of all registered external calls
@ -341,11 +348,11 @@ private:
//! All external calls //! All external calls
static CBotExternalCallList* m_externalCalls; static CBotExternalCallList* m_externalCalls;
//! All user-defined functions //! All user-defined functions
CBotFunction* m_functions = nullptr; std::list<CBotFunction*> m_functions{};
//! The entry point function //! The entry point function
CBotFunction* m_entryPoint = nullptr; CBotFunction* m_entryPoint = nullptr;
//! Classes defined in this program //! Classes defined in this program
CBotClass* m_classes = nullptr; std::list<CBotClass*> m_classes{};
//! Execution stack //! Execution stack
CBotStack* m_stack = nullptr; CBotStack* m_stack = nullptr;
//! "this" variable //! "this" variable

View File

@ -82,8 +82,6 @@ CBotStack* CBotStack::AllocateStack()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotStack::Delete() void CBotStack::Delete()
{ {
assert ( this != nullptr );
if (m_next != nullptr) m_next->Delete(); if (m_next != nullptr) m_next->Delete();
if (m_next2 != nullptr) m_next2->Delete(); if (m_next2 != nullptr) m_next2->Delete();
@ -192,8 +190,18 @@ bool CBotStack::Return(CBotStack* pfils)
m_var = pfils->m_var; // result transmitted m_var = pfils->m_var; // result transmitted
pfils->m_var = nullptr; // not to destroy the variable pfils->m_var = nullptr; // not to destroy the variable
if (m_next != nullptr) m_next->Delete();m_next = nullptr; // releases the stack above if (m_next != nullptr)
if (m_next2 != nullptr) m_next2->Delete();m_next2 = nullptr; // also the second stack (catch) {
// releases the stack above
m_next->Delete();
m_next = nullptr;
}
if (m_next2 != nullptr)
{
// also the second stack (catch)
m_next2->Delete();
m_next2 = nullptr;
}
return IsOk(); // interrupted if error return IsOk(); // interrupted if error
} }
@ -260,7 +268,7 @@ bool CBotStack::IfStep()
bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name) bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name)
{ {
if ( m_error>=0 ) return false; // normal output if ( m_error>=0 ) return false; // normal output
if ( m_error==-3 ) return false; // normal output (return current) if ( m_error==CBotError(-3) ) return false; // normal output (return current)
if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name)) if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name))
return false; // it's not for me return false; // it's not for me
@ -273,7 +281,7 @@ bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotStack::IfContinue(int state, const std::string& name) bool CBotStack::IfContinue(int state, const std::string& name)
{ {
if ( m_error != -2 ) return false; if ( m_error != CBotError(-2) ) return false;
if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name)) if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name))
return false; // it's not for me return false; // it's not for me
@ -301,7 +309,7 @@ void CBotStack::SetBreak(int val, const std::string& name)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotStack::GetRetVar(bool bRet) bool CBotStack::GetRetVar(bool bRet)
{ {
if (m_error == -3) if (m_error == CBotError(-3))
{ {
if ( m_var ) delete m_var; if ( m_var ) delete m_var;
m_var = m_retvar; m_var = m_retvar;
@ -568,7 +576,7 @@ bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, con
res = m_prog->GetExternalCalls()->DoCall(nullptr, nullptr, ppVar, this, rettype); res = m_prog->GetExternalCalls()->DoCall(nullptr, nullptr, ppVar, this, rettype);
if (res >= 0) return res; if (res >= 0) return res;
res = m_prog->GetFunctions()->DoCall(nIdent, "", ppVar, this, token ); res = CBotFunction::DoCall(m_prog, m_prog->GetFunctions(), nIdent, "", ppVar, this, token);
if (res >= 0) return res; if (res >= 0) return res;
// if not found (recompile?) seeks by name // if not found (recompile?) seeks by name
@ -577,7 +585,7 @@ bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, con
res = m_prog->GetExternalCalls()->DoCall(token, nullptr, ppVar, this, rettype); res = m_prog->GetExternalCalls()->DoCall(token, nullptr, ppVar, this, rettype);
if (res >= 0) return res; if (res >= 0) return res;
res = m_prog->GetFunctions()->DoCall(nIdent, token->GetString(), ppVar, this, token ); res = CBotFunction::DoCall(m_prog, m_prog->GetFunctions(), nIdent, token->GetString(), ppVar, this, token);
if (res >= 0) return res; if (res >= 0) return res;
SetError(CBotErrUndefFunc, token); SetError(CBotErrUndefFunc, token);
@ -592,7 +600,7 @@ void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar)
if (m_prog->GetExternalCalls()->RestoreCall(token, nullptr, ppVar, this)) if (m_prog->GetExternalCalls()->RestoreCall(token, nullptr, ppVar, this))
return; return;
m_prog->GetFunctions()->RestoreCall(nIdent, token->GetString(), ppVar, this); CBotFunction::RestoreCall(m_prog->GetFunctions(), nIdent, token->GetString(), ppVar, this);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -727,12 +735,11 @@ bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack)
{ {
unsigned short w; unsigned short w;
pStack = nullptr; if (pStack != this) pStack = nullptr;
if (!ReadWord(pf, w)) return false; if (!ReadWord(pf, w)) return false;
if ( w == 0 ) return true; // 0 - terminator if ( w == 0 ) return true; // 0 - terminator
if ( this == nullptr ) pStack = AllocateStack(); if (pStack == nullptr) pStack = AddStack();
else pStack = AddStack();
if ( w == 2 ) // 2 - m_next2 if ( w == 2 ) // 2 - m_next2
{ {

View File

@ -199,7 +199,6 @@ const CBotToken& CBotToken::operator=(const CBotToken& src)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int CBotToken::GetType() int CBotToken::GetType()
{ {
if (this == nullptr) return 0;
if (m_type == TokenTypKeyWord) return m_keywordId; if (m_type == TokenTypKeyWord) return m_keywordId;
return m_type; return m_type;
} }
@ -225,14 +224,12 @@ void CBotToken::SetString(const std::string& name)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int CBotToken::GetStart() int CBotToken::GetStart()
{ {
if (this == nullptr) return -1;
return m_start; return m_start;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int CBotToken::GetEnd() int CBotToken::GetEnd()
{ {
if (this == nullptr) return -1;
return m_end; return m_end;
} }
@ -439,6 +436,13 @@ std::unique_ptr<CBotToken> CBotToken::CompileTokens(const std::string& program)
pp = p; pp = p;
} }
// terminator token
nxt = new CBotToken();
nxt->m_type = TokenTypNone;
nxt->m_end = nxt->m_start = pos;
prv->m_next = nxt;
nxt->m_prev = prv;
return std::unique_ptr<CBotToken>(tokenbase); return std::unique_ptr<CBotToken>(tokenbase);
} }

View File

@ -167,11 +167,16 @@ CBotTypResult& CBotTypResult::operator=(const CBotTypResult& src)
m_type = src.m_type; m_type = src.m_type;
m_limite = src.m_limite; m_limite = src.m_limite;
m_class = src.m_class; m_class = src.m_class;
m_next = nullptr;
if (src.m_next != nullptr ) if (src.m_next != nullptr )
{ {
delete m_next;
m_next = new CBotTypResult(*src.m_next); m_next = new CBotTypResult(*src.m_next);
} }
else
{
delete m_next;
m_next = nullptr;
}
return *this; return *this;
} }

View File

@ -22,6 +22,7 @@
#include "CBot/CBotStack.h" #include "CBot/CBotStack.h"
#include "CBot/CBotInstr/CBotInstr.h"
#include "CBot/CBotVar/CBotVarArray.h" #include "CBot/CBotVar/CBotVarArray.h"
#include "CBot/CBotVar/CBotVarPointer.h" #include "CBot/CBotVar/CBotVarPointer.h"
#include "CBot/CBotVar/CBotVarClass.h" #include "CBot/CBotVar/CBotVarClass.h"
@ -70,6 +71,8 @@ CBotVar::CBotVar(const CBotToken &name) : CBotVar()
CBotVar::~CBotVar( ) CBotVar::~CBotVar( )
{ {
delete m_token; delete m_token;
delete m_InitExpr;
delete m_LimExpr;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -394,12 +394,13 @@ void CBotVarClass::DecrementUse()
CBotVar* pThis = CBotVar::Create("this", CBotTypNullPointer); CBotVar* pThis = CBotVar::Create("this", CBotTypNullPointer);
pThis->SetPointer(this); pThis->SetPointer(this);
CBotVar* pResult = nullptr;
std::string nom = std::string("~") + m_pClass->GetName(); std::string nom = std::string("~") + m_pClass->GetName();
long ident = 0; long ident = 0;
while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, nom, pThis, ppVars, pResult, pile, nullptr)) ; // waits for the end CBotToken token(nom); // TODO
while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, pThis, ppVars, CBotTypResult(CBotTypVoid), pile, &token)) ; // waits for the end
pile->ResetError(err, start,end); pile->ResetError(err, start,end);

View File

@ -48,12 +48,12 @@ public:
SetValString(ToString(val)); SetValString(ToString(val));
} }
int GetValInt() int GetValInt() override
{ {
return FromString<int>(GetValString()); return FromString<int>(GetValString());
} }
float GetValFloat() float GetValFloat() override
{ {
return FromString<float>(GetValString()); return FromString<float>(GetValString());
} }

View File

@ -2,8 +2,6 @@ set(SOURCES
CBot.h CBot.h
CBotCStack.cpp CBotCStack.cpp
CBotCStack.h CBotCStack.h
CBotCallMethode.cpp
CBotCallMethode.h
CBotClass.cpp CBotClass.cpp
CBotClass.h CBotClass.h
CBotDebug.cpp CBotDebug.cpp

View File

@ -38,7 +38,7 @@ int g_nextFileId = 1;
bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception) bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{ {
std::string mode; CBotFileAccessHandler::OpenMode openMode = CBotFileAccessHandler::OpenMode::Read;
// must be a character string // must be a character string
if ( pVar->GetType() != CBotTypString ) { Exception = CBotErrBadString; return false; } if ( pVar->GetType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
@ -50,8 +50,11 @@ bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exc
if ( pVar != nullptr ) if ( pVar != nullptr )
{ {
// recover mode // recover mode
mode = pVar->GetValString(); std::string mode = pVar->GetValString();
if ( mode != "r" && mode != "w" && mode != "a" ) { Exception = CBotErrBadParam; return false; } if ( mode == "r" ) openMode = CBotFileAccessHandler::OpenMode::Read;
else if ( mode == "w" ) openMode = CBotFileAccessHandler::OpenMode::Write;
else if ( mode == "a" ) openMode = CBotFileAccessHandler::OpenMode::Append;
else { Exception = CBotErrBadParam; return false; }
// no third parameter // no third parameter
if ( pVar->GetNext() != nullptr ) { Exception = CBotErrOverParam; return false; } if ( pVar->GetNext() != nullptr ) { Exception = CBotErrOverParam; return false; }
@ -66,27 +69,20 @@ bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exc
// which must not be initialized // which must not be initialized
if ( pVar->IsDefined()) { Exception = CBotErrFileOpen; return false; } if ( pVar->IsDefined()) { Exception = CBotErrFileOpen; return false; }
if ( !mode.empty() ) // opens the requested file
{ assert(g_fileHandler != nullptr);
// opens the requested file
assert(g_fileHandler != nullptr);
CBotFileAccessHandler::OpenMode openMode; std::unique_ptr<CBotFile> file = g_fileHandler->OpenFile(filename, openMode);
if ( mode == "r" ) openMode = CBotFileAccessHandler::OpenMode::Read;
else if ( mode == "w" ) openMode = CBotFileAccessHandler::OpenMode::Write;
else if ( mode == "a" ) openMode = CBotFileAccessHandler::OpenMode::Append;
std::unique_ptr<CBotFile> file = g_fileHandler->OpenFile(filename, openMode); if (!file->Opened()) { Exception = CBotErrFileOpen; return false; }
if (!file->Opened()) { Exception = CBotErrFileOpen; return false; } int fileHandle = g_nextFileId++;
g_files[fileHandle] = std::move(file);
int fileHandle = g_nextFileId++; // save the file handle
g_files[fileHandle] = std::move(file); pVar = pThis->GetItem("handle");
pVar->SetValInt(fileHandle);
// save the file handle
pVar = pThis->GetItem("handle");
pVar->SetValInt(fileHandle);
}
return true; return true;
} }

View File

@ -225,8 +225,14 @@ bool rStrFind( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
// puts the result on the stack // puts the result on the stack
std::size_t res = s.find(s2); std::size_t res = s.find(s2);
pResult->SetValInt( res != std::string::npos ? res : -1 ); if (res != std::string::npos)
if ( res < 0 ) pResult->SetInit( CBotVar::InitType::IS_NAN ); {
pResult->SetValInt(res);
}
else
{
pResult->SetInit(CBotVar::InitType::IS_NAN);
}
return true; return true;
} }

View File

@ -165,6 +165,8 @@ set(BASE_SOURCES
graphics/core/nulldevice.cpp graphics/core/nulldevice.cpp
graphics/core/nulldevice.h graphics/core/nulldevice.h
graphics/core/texture.h graphics/core/texture.h
graphics/core/type.cpp
graphics/core/type.h
graphics/core/vertex.h graphics/core/vertex.h
graphics/engine/camera.cpp graphics/engine/camera.cpp
graphics/engine/camera.h graphics/engine/camera.h
@ -239,10 +241,14 @@ set(BASE_SOURCES
level/robotmain.h level/robotmain.h
level/scene_conditions.cpp level/scene_conditions.cpp
level/scene_conditions.h level/scene_conditions.h
level/scoreboard.cpp
level/scoreboard.h
math/all.h math/all.h
math/const.h math/const.h
math/func.h math/func.h
math/geometry.h math/geometry.h
math/half.cpp
math/half.h
math/intpoint.h math/intpoint.h
math/matrix.h math/matrix.h
math/point.h math/point.h

View File

@ -674,7 +674,8 @@ bool CApplication::Create()
// Create the robot application. // Create the robot application.
m_controller = MakeUnique<CController>(); m_controller = MakeUnique<CController>();
CThread musicLoadThread([this]() { CThread musicLoadThread([this]()
{
GetLogger()->Debug("Cache sounds...\n"); GetLogger()->Debug("Cache sounds...\n");
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp(); SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadStart); m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
@ -685,7 +686,8 @@ bool CApplication::Create()
m_systemUtils->GetCurrentTimeStamp(musicLoadEnd); m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC); float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime); GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
}, "Sound loading thread"); },
"Sound loading thread");
musicLoadThread.Start(); musicLoadThread.Start();
if (m_runSceneCategory == LevelCategory::Max) if (m_runSceneCategory == LevelCategory::Max)
@ -1852,9 +1854,10 @@ bool CApplication::GetSceneTestMode()
return m_sceneTest; return m_sceneTest;
} }
void CApplication::SetTextInput(bool textInputEnabled) void CApplication::SetTextInput(bool textInputEnabled, int id)
{ {
if (textInputEnabled) m_textInputEnabled[id] = textInputEnabled;
if (std::any_of(m_textInputEnabled.begin(), m_textInputEnabled.end(), [](std::pair<int, bool> v) { return v.second; }))
{ {
SDL_StartTextInput(); SDL_StartTextInput();
} }

View File

@ -35,6 +35,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
class CEventQueue; class CEventQueue;
@ -245,7 +246,7 @@ public:
//! Enable/disable text input, this toggles the on-screen keyboard on some platforms //! Enable/disable text input, this toggles the on-screen keyboard on some platforms
/** This also allows for writing in CJK languages (not tested!), see https://wiki.libsdl.org/Tutorials/TextInput for detailed explanation */ /** This also allows for writing in CJK languages (not tested!), see https://wiki.libsdl.org/Tutorials/TextInput for detailed explanation */
void SetTextInput(bool textInputEnabled); void SetTextInput(bool textInputEnabled, int id);
//! Moves (warps) the mouse cursor to the specified position (in interface coords) //! Moves (warps) the mouse cursor to the specified position (in interface coords)
void MoveMouse(Math::Point pos); void MoveMouse(Math::Point pos);
@ -403,4 +404,6 @@ protected:
//! Static buffer for putenv locale //! Static buffer for putenv locale
static char m_languageLocale[50]; static char m_languageLocale[50];
std::map<int, bool> m_textInputEnabled;
}; };

View File

@ -46,7 +46,7 @@ void CSignalHandlers::Init(CSystemUtils* systemUtils)
void CSignalHandlers::SignalHandler(int sig) void CSignalHandlers::SignalHandler(int sig)
{ {
std::string signalStr = StrUtils::ToString(signal); std::string signalStr = StrUtils::ToString(sig);
switch(sig) switch(sig)
{ {
case SIGSEGV: signalStr = "SIGSEGV, segmentation fault"; break; case SIGSEGV: signalStr = "SIGSEGV, segmentation fault"; break;

View File

@ -19,6 +19,10 @@
#pragma once #pragma once
/**
* \file common/error.h
* \brief Definition of the Error enum
*/
/** /**
* \enum Error * \enum Error
@ -26,87 +30,88 @@
*/ */
enum Error enum Error
{ {
ERR_OK = 0, //! < ok ERR_OK = 0, //!< ok
ERR_UNKNOWN = 1, //! < any error ERR_UNKNOWN = 1, //!< any error
ERR_CONTINUE = 2, //! < continues ERR_CONTINUE = 2, //!< continues
ERR_STOP = 3, //! < stops ERR_STOP = 3, //!< stops
ERR_CMD = 4, //! < unknown command ERR_CMD = 4, //!< unknown command
ERR_MANIP_FLY = 101, //! < impossible in flight ERR_OBJ_BUSY = 5, //!< object is busy
ERR_MANIP_BUSY = 102, //! < taking: hands already occupied ERR_MANIP_FLY = 101, //!< impossible in flight
ERR_MANIP_NIL = 103, //! < taking: nothing has to take ERR_MANIP_BUSY = 102, //!< taking: hands already occupied
ERR_MANIP_MOTOR = 105, //! < busy: impossible to move ERR_MANIP_NIL = 103, //!< taking: nothing has to take
ERR_MANIP_OCC = 106, //! < busy: location already occupied ERR_MANIP_MOTOR = 105, //!< busy: impossible to move
ERR_MANIP_RADIO = 108, //! < impossible because radioactive ERR_MANIP_OCC = 106, //!< busy: location already occupied
ERR_MANIP_WATER = 109, //! < not possible under water ERR_MANIP_RADIO = 108, //!< impossible because radioactive
ERR_MANIP_EMPTY = 110, //! < nothing to deposit ERR_MANIP_WATER = 109, //!< not possible under water
ERR_BUILD_FLY = 120, //! < not possible in flight ERR_MANIP_EMPTY = 110, //!< nothing to deposit
ERR_BUILD_WATER = 121, //! < not possible under water ERR_BUILD_FLY = 120, //!< not possible in flight
ERR_BUILD_METALAWAY = 123, //! < lack of metal (too far) ERR_BUILD_WATER = 121, //!< not possible under water
ERR_BUILD_METALNEAR = 124, //! < lack of metal (too close) ERR_BUILD_METALAWAY = 123, //!< lack of metal (too far)
ERR_BUILD_METALINEX = 125, //! < lack of metal ERR_BUILD_METALNEAR = 124, //!< lack of metal (too close)
ERR_BUILD_FLAT = 126, //! < not enough flat ground ERR_BUILD_METALINEX = 125, //!< lack of metal
ERR_BUILD_FLATLIT = 127, //! < not enough flat ground space ERR_BUILD_FLAT = 126, //!< not enough flat ground
ERR_BUILD_BUSY = 128, //! < location occupied ERR_BUILD_FLATLIT = 127, //!< not enough flat ground space
ERR_BUILD_BASE = 129, //! < too close to the rocket ERR_BUILD_BUSY = 128, //!< location occupied
ERR_BUILD_NARROW = 130, //! < buildings too close ERR_BUILD_BASE = 129, //!< too close to the rocket
ERR_BUILD_MOTOR = 131, //! < built: not possible in movement ERR_BUILD_NARROW = 130, //!< buildings too close
ERR_BUILD_DISABLED = 132, //! < built: can not produce this object in this mission ERR_BUILD_MOTOR = 131, //!< built: not possible in movement
ERR_BUILD_RESEARCH = 133, //! < built: can not produce not researched object ERR_BUILD_DISABLED = 132, //!< built: can not produce this object in this mission
ERR_SEARCH_FLY = 140, //! < not possible in flight ERR_BUILD_RESEARCH = 133, //!< built: can not produce not researched object
ERR_SEARCH_MOTOR = 142, //! < impossible in movement ERR_SEARCH_FLY = 140, //!< not possible in flight
ERR_TERRA_ENERGY = 151, //! < not enough energy ERR_SEARCH_MOTOR = 142, //!< impossible in movement
ERR_FIRE_ENERGY = 161, //! < not enough energy ERR_TERRA_ENERGY = 151, //!< not enough energy
ERR_RECOVER_ENERGY = 171, //! < not enough energy ERR_FIRE_ENERGY = 161, //!< not enough energy
ERR_RECOVER_NULL = 172, //! < lack of ruin ERR_RECOVER_ENERGY = 171, //!< not enough energy
ERR_CONVERT_EMPTY = 180, //! < no stone was transformed ERR_RECOVER_NULL = 172, //!< lack of ruin
ERR_SHIELD_ENERGY = 191, //! < not enough energy ERR_CONVERT_EMPTY = 180, //!< no stone was transformed
ERR_MOVE_IMPOSSIBLE = 200, //! < move impossible ERR_SHIELD_ENERGY = 191, //!< not enough energy
ERR_GOTO_IMPOSSIBLE = 210, //! < goto impossible ERR_MOVE_IMPOSSIBLE = 200, //!< move impossible
ERR_GOTO_ITER = 211, //! < goto too complicated ERR_GOTO_IMPOSSIBLE = 210, //!< goto impossible
ERR_GOTO_BUSY = 212, //! < goto destination occupied ERR_GOTO_ITER = 211, //!< goto too complicated
ERR_DERRICK_NULL = 300, //! < no ore underground ERR_GOTO_BUSY = 212, //!< goto destination occupied
ERR_STATION_NULL = 301, //! < no energy underground ERR_DERRICK_NULL = 300, //!< no ore underground
ERR_TOWER_POWER = 310, //! < no battery ERR_STATION_NULL = 301, //!< no energy underground
ERR_TOWER_ENERGY = 311, //! < more energy ERR_TOWER_POWER = 310, //!< no battery
ERR_RESEARCH_POWER = 320, //! < no battery ERR_TOWER_ENERGY = 311, //!< more energy
ERR_RESEARCH_ENERGY = 321, //! < more energy ERR_RESEARCH_POWER = 320, //!< no battery
ERR_RESEARCH_TYPE = 322, //! < the wrong type of battery ERR_RESEARCH_ENERGY = 321, //!< more energy
ERR_RESEARCH_ALREADY = 323, //! < research already done ERR_RESEARCH_TYPE = 322, //!< the wrong type of battery
ERR_ENERGY_NULL = 330, //! < no energy underground ERR_RESEARCH_ALREADY = 323, //!< research already done
ERR_ENERGY_LOW = 331, //! < not enough energy ERR_ENERGY_NULL = 330, //!< no energy underground
ERR_ENERGY_EMPTY = 332, //! < lack of metal ERR_ENERGY_LOW = 331, //!< not enough energy
ERR_ENERGY_BAD = 333, //! < transforms only the metal ERR_ENERGY_EMPTY = 332, //!< lack of metal
ERR_BASE_DLOCK = 340, //! < doors locked ERR_ENERGY_BAD = 333, //!< transforms only the metal
ERR_BASE_DHUMAN = 341, //! < you must be on spaceship ERR_BASE_DLOCK = 340, //!< doors locked
ERR_LABO_NULL = 350, //! < nothing to analyze ERR_BASE_DHUMAN = 341, //!< you must be on spaceship
ERR_LABO_BAD = 351, //! < analyzes only organic ball ERR_LABO_NULL = 350, //!< nothing to analyze
ERR_LABO_ALREADY = 352, //! < analysis already made ERR_LABO_BAD = 351, //!< analyzes only organic ball
ERR_NUCLEAR_EMPTY = 362, //! < lack of uranium ERR_LABO_ALREADY = 352, //!< analysis already made
ERR_NUCLEAR_BAD = 363, //! < transforms only uranium ERR_NUCLEAR_EMPTY = 362, //!< lack of uranium
ERR_FACTORY_NULL = 370, //! < no metal ERR_NUCLEAR_BAD = 363, //!< transforms only uranium
ERR_FACTORY_NEAR = 371, //! < vehicle too close ERR_FACTORY_NULL = 370, //!< no metal
ERR_INFO_NULL = 390, //! < no information terminal ERR_FACTORY_NEAR = 371, //!< vehicle too close
ERR_VEH_VIRUS = 400, //! < vehicle infected by a virus ERR_INFO_NULL = 390, //!< no information terminal
ERR_BAT_VIRUS = 401, //! < building infected by a virus ERR_VEH_VIRUS = 400, //!< vehicle infected by a virus
ERR_DESTROY_NOTFOUND = 410, //! < not found anything to destroy ERR_BAT_VIRUS = 401, //!< building infected by a virus
ERR_WRONG_OBJ = 420, //! < inappropriate vehicle ERR_DESTROY_NOTFOUND = 410, //!< not found anything to destroy
ERR_VEH_POWER = 500, //! < no battery ERR_WRONG_OBJ = 420, //!< inappropriate vehicle
ERR_VEH_ENERGY = 501, //! < more energy ERR_VEH_POWER = 500, //!< no battery
ERR_FLAG_FLY = 510, //! < impossible in flight ERR_VEH_ENERGY = 501, //!< more energy
ERR_FLAG_WATER = 511, //! < impossible during swimming ERR_FLAG_FLY = 510, //!< impossible in flight
ERR_FLAG_MOTOR = 512, //! < impossible in movement ERR_FLAG_WATER = 511, //!< impossible during swimming
ERR_FLAG_BUSY = 513, //! < taking: already creating flag ERR_FLAG_MOTOR = 512, //!< impossible in movement
ERR_FLAG_CREATE = 514, //! < too many flags ERR_FLAG_BUSY = 513, //!< taking: already creating flag
ERR_FLAG_PROXY = 515, //! < too close ERR_FLAG_CREATE = 514, //!< too many flags
ERR_FLAG_DELETE = 516, //! < nothing to remove ERR_FLAG_PROXY = 515, //!< too close
ERR_MISSION_NOTERM = 600, //! < Mission not completed ERR_FLAG_DELETE = 516, //!< nothing to remove
ERR_DELETEMOBILE = 700, //! < vehicle destroyed ERR_MISSION_NOTERM = 600, //!< Mission not completed
ERR_DELETEBUILDING = 701, //! < building destroyed ERR_DELETEMOBILE = 700, //!< vehicle destroyed
ERR_ENEMY_OBJECT = 703, //! < can't control enemy object ERR_DELETEBUILDING = 701, //!< building destroyed
ERR_OBLIGATORYTOKEN = 800, //! < compulsory instruction missing ERR_ENEMY_OBJECT = 703, //!< can't control enemy object
ERR_PROHIBITEDTOKEN = 801, //! < instruction prohibited ERR_OBLIGATORYTOKEN = 800, //!< compulsory instruction missing
ERR_AIM_IMPOSSIBLE = 900, //! < cannot aim at specified angle(s) ERR_PROHIBITEDTOKEN = 801, //!< instruction prohibited
ERR_WRONG_BOT = 910, //! < inappropriate bot ERR_AIM_IMPOSSIBLE = 900, //!< cannot aim at specified angle(s)
ERR_WRONG_BOT = 910, //!< inappropriate bot
INFO_FIRST = 10000, //! < first information INFO_FIRST = 10000, //! < first information
INFO_BUILD = 10001, //! < construction builded INFO_BUILD = 10001, //! < construction builded
@ -142,6 +147,9 @@ enum Error
INFO_DELETEWORM = 10103, //! < insect killed INFO_DELETEWORM = 10103, //! < insect killed
INFO_DELETESPIDER = 10104, //! < insect killed INFO_DELETESPIDER = 10104, //! < insect killed
INFO_BEGINSATCOM = 10105, //! < use your SatCom INFO_BEGINSATCOM = 10105, //! < use your SatCom
INFO_TEAM_FINISH = 10110,
INFO_TEAM_DEAD = 10111,
INFO_TEAM_SCORE = 10112,
ERR_MAX //! < number of values ERR_MAX //! < number of values
}; };

View File

@ -172,7 +172,7 @@ enum EventType
EVENT_LABEL16 = 106, EVENT_LABEL16 = 106,
EVENT_LABEL17 = 107, EVENT_LABEL17 = 107,
EVENT_LABEL18 = 108, EVENT_LABEL18 = 108,
EVENT_LABEL19 = 109, EVENT_LABEL19 = 109, // cursor position overlay
EVENT_LIST0 = 110, EVENT_LIST0 = 110,
EVENT_LIST1 = 111, EVENT_LIST1 = 111,
@ -187,6 +187,11 @@ enum EventType
EVENT_LOADING = 120, EVENT_LOADING = 120,
EVENT_LABEL_CODE_BATTLE = 121,
EVENT_SCOREBOARD = 130,
EVENT_SCOREBOARD_MAX = 169,
EVENT_TOOLTIP = 200, EVENT_TOOLTIP = 200,
EVENT_DIALOG_OK = 300, EVENT_DIALOG_OK = 300,

View File

@ -39,7 +39,7 @@ public:
/** Construct and Open Stream for writing /** Construct and Open Stream for writing
* *
* \param filename * \param filename
* \param Mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file * \param mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file
* *
*/ */
COutputStream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out); COutputStream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out);
@ -48,7 +48,7 @@ public:
/** Open Stream for writing /** Open Stream for writing
* *
* \param filename * \param filename
* \param Mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file * \param mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file
* *
*/ */
void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out); void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out);

View File

@ -38,7 +38,7 @@ public:
/** Open Stream Buffer for writing /** Open Stream Buffer for writing
* *
* \param filename * \param filename
* \param Mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file * \param mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file
* *
*/ */
void open(const std::string &filename, std::ios_base::openmode mode); void open(const std::string &filename, std::ios_base::openmode mode);

View File

@ -143,8 +143,14 @@ void InitializeRestext()
stringsText[RT_LOADING_TERRAIN_TEX] = TR("Textures"); stringsText[RT_LOADING_TERRAIN_TEX] = TR("Textures");
stringsText[RT_LOADING_TERRAIN_GEN] = TR("Generating"); stringsText[RT_LOADING_TERRAIN_GEN] = TR("Generating");
stringsText[RT_SCOREBOARD_RESULTS] = TR("Results");
stringsText[RT_SCOREBOARD_RESULTS_TEXT]= TR("The battle has ended");
stringsText[RT_SCOREBOARD_RESULTS_LINE]= TR("%s: %d pts");
stringsEvent[EVENT_LABEL_CODE_BATTLE] = TR("Code battle");
stringsEvent[EVENT_BUTTON_OK] = TR("OK"); stringsEvent[EVENT_BUTTON_OK] = TR("OK");
stringsEvent[EVENT_BUTTON_CANCEL] = TR("Cancel"); stringsEvent[EVENT_BUTTON_CANCEL] = TR("Cancel");
stringsEvent[EVENT_BUTTON_NEXT] = TR("Next"); stringsEvent[EVENT_BUTTON_NEXT] = TR("Next");
@ -563,6 +569,7 @@ void InitializeRestext()
stringsErr[ERR_UNKNOWN] = TR("Internal error - tell the developers"); stringsErr[ERR_UNKNOWN] = TR("Internal error - tell the developers");
stringsErr[ERR_CMD] = TR("Unknown command"); stringsErr[ERR_CMD] = TR("Unknown command");
stringsErr[ERR_OBJ_BUSY] = TR("This object is currently busy");
stringsErr[ERR_MANIP_FLY] = TR("Impossible when flying"); stringsErr[ERR_MANIP_FLY] = TR("Impossible when flying");
stringsErr[ERR_MANIP_BUSY] = TR("Already carrying something"); stringsErr[ERR_MANIP_BUSY] = TR("Already carrying something");
stringsErr[ERR_MANIP_NIL] = TR("Nothing to grab"); stringsErr[ERR_MANIP_NIL] = TR("Nothing to grab");
@ -670,6 +677,9 @@ void InitializeRestext()
stringsErr[INFO_DELETEWORM] = TR("Worm fatally wounded"); stringsErr[INFO_DELETEWORM] = TR("Worm fatally wounded");
stringsErr[INFO_DELETESPIDER] = TR("Spider fatally wounded"); stringsErr[INFO_DELETESPIDER] = TR("Spider fatally wounded");
stringsErr[INFO_BEGINSATCOM] = TR("Press \\key help; to read instructions on your SatCom"); stringsErr[INFO_BEGINSATCOM] = TR("Press \\key help; to read instructions on your SatCom");
stringsErr[INFO_TEAM_FINISH] = TR("<<< Team %s finished! >>>");
stringsErr[INFO_TEAM_DEAD] = TR("<<< Team %s lost! >>>");
stringsErr[INFO_TEAM_SCORE] = TR("<<< Team %s recieved %d points >>>");
@ -718,6 +728,10 @@ void InitializeRestext()
stringsCbot[CBot::CBotErrNoPublic] = TR("Public required"); stringsCbot[CBot::CBotErrNoPublic] = TR("Public required");
stringsCbot[CBot::CBotErrNoExpression] = TR("Expression expected after ="); stringsCbot[CBot::CBotErrNoExpression] = TR("Expression expected after =");
stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function"); stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function");
stringsCbot[CBot::CBotErrFuncNotVoid] = TR("Function needs return type \"void\"");
stringsCbot[CBot::CBotErrNoClassName] = TR("Class name expected");
stringsCbot[CBot::CBotErrNoReturn] = TR("Non-void function needs \"return;\"");
stringsCbot[CBot::CBotErrDefaultValue] = TR("This parameter needs a default value");
stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero"); stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero");
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized"); stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");

View File

@ -140,6 +140,10 @@ enum ResTextType
RT_LOADING_TERRAIN_TEX = 222, RT_LOADING_TERRAIN_TEX = 222,
RT_LOADING_TERRAIN_GEN = 223, RT_LOADING_TERRAIN_GEN = 223,
RT_SCOREBOARD_RESULTS = 230,
RT_SCOREBOARD_RESULTS_TEXT= 231,
RT_SCOREBOARD_RESULTS_LINE= 232,
RT_MAX //! < number of values RT_MAX //! < number of values
}; };

View File

@ -22,6 +22,8 @@
#include "common/config.h" #include "common/config.h"
#include "common/make_unique.h"
#if defined(PLATFORM_WINDOWS) #if defined(PLATFORM_WINDOWS)
#include "common/system/system_windows.h" #include "common/system/system_windows.h"
#elif defined(PLATFORM_LINUX) #elif defined(PLATFORM_LINUX)
@ -32,8 +34,6 @@
#include "common/system/system_other.h" #include "common/system/system_other.h"
#endif #endif
#include "common/make_unique.h"
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>

View File

@ -26,6 +26,7 @@
#include "graphics/core/color.h" #include "graphics/core/color.h"
#include "graphics/core/texture.h" #include "graphics/core/texture.h"
#include "graphics/core/vertex.h"
#include "math/intpoint.h" #include "math/intpoint.h"
@ -267,8 +268,10 @@ enum PrimitiveType
PRIMITIVE_POINTS, PRIMITIVE_POINTS,
PRIMITIVE_LINES, PRIMITIVE_LINES,
PRIMITIVE_LINE_STRIP, PRIMITIVE_LINE_STRIP,
PRIMITIVE_LINE_LOOP,
PRIMITIVE_TRIANGLES, PRIMITIVE_TRIANGLES,
PRIMITIVE_TRIANGLE_STRIP PRIMITIVE_TRIANGLE_STRIP,
PRIMITIVE_TRIANGLE_FAN
}; };
/** /**
@ -413,6 +416,14 @@ public:
//! Sets only the texture wrap modes (for faster than thru stage params) //! Sets only the texture wrap modes (for faster than thru stage params)
virtual void SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) = 0; virtual void SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) = 0;
//! Renders primitive composed of generic vertices
virtual void DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount) = 0;
//! Renders multiple primitives composed of generic vertices
virtual void DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount) = 0;
//! Renders primitive composed of vertices with single texture //! Renders primitive composed of vertices with single texture
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) = 0; Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) = 0;

View File

@ -168,6 +168,16 @@ void CNullDevice::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
{ {
} }
void CNullDevice::DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount)
{
}
void CNullDevice::DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount)
{
}
void CNullDevice::DrawPrimitives(PrimitiveType type, const Vertex *vertices, void CNullDevice::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
int first[], int count[], int drawCount, Color color) int first[], int count[], int drawCount, Color color)
{ {

View File

@ -81,6 +81,11 @@ public:
void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override;
void DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount) override;
void DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount) override;
void DrawPrimitive(PrimitiveType type, const Vertex* vertices, int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; void DrawPrimitive(PrimitiveType type, const Vertex* vertices, int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override;
void DrawPrimitive(PrimitiveType type, const VertexTex2* vertices, int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; void DrawPrimitive(PrimitiveType type, const VertexTex2* vertices, int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override;
void DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) override; void DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) override;

View File

@ -205,47 +205,6 @@ struct TextureStageParams
} }
}; };
/**
* \struct TexGenMode
* \brief Texture generation mode
*/
enum TexGenMode
{
//! No texture generation
TEX_GEN_NONE,
//! Object linear mode
TEX_GEN_OBJECT_LINEAR,
//! Eye linear mode
TEX_GEN_EYE_LINEAR,
//! Spherical mapping mode
TEX_GEN_SPHERE_MAP,
//! Normal mapping mode
TEX_GEN_NORMAL_MAP,
//! Reflection mapping mode
TEX_GEN_REFLECTION_MAP
};
/**
* \struct TextureGenerationParams
* \brief Parameters for texture coordinate generation
*
* These params define the generation of texture coordinate for given texture unit.
*/
struct TextureGenerationParams
{
struct Coord
{
TexGenMode mode = TEX_GEN_NONE;
float plane[4] = {};
};
Coord coords[4];
void LoadDefault()
{
*this = TextureGenerationParams();
}
};
/** /**
* \struct Texture * \struct Texture
* \brief Info about a texture * \brief Info about a texture

View File

@ -0,0 +1,56 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2016, 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
*/
/**
* \file graphics/core/type.cpp
* \brief Type support and conversion
*/
#include "graphics/core/type.h"
#include <cassert>
// Graphics module namespace
namespace Gfx
{
//! Returns size in bytes of given type
int GetTypeSize(Type type)
{
switch (type)
{
case Type::BYTE:
case Type::UBYTE:
return 1;
case Type::SHORT:
case Type::USHORT:
case Type::HALF:
return 2;
case Type::INT:
case Type::UINT:
case Type::FLOAT:
return 4;
case Type::DOUBLE:
return 8;
default:
return 0;
}
}
} // namespace Gfx

62
src/graphics/core/type.h Normal file
View File

@ -0,0 +1,62 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2016, 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
*/
/**
* \file graphics/core/type.h
* \brief Type support and conversion
*/
#pragma once
// Graphics module namespace
namespace Gfx
{
/**
* \enum class Type
* \brief Value types for vertex attributes
*/
enum class Type : unsigned char
{
//! Unsigned byte (8-bit)
UBYTE = 0,
//! Signed byte (8-bit)
BYTE,
//! Unsigned short (16-bit)
USHORT,
//! Signed short (16-bit)
SHORT,
//! Unsigned int (32-bit)
UINT,
//! Signed int (32-bit)
INT,
//! Half precision floating-point (16-bit)
HALF,
//! Single precision floating-point (32-bit)
FLOAT,
//! Double precision floating-point (64-bit)
DOUBLE,
};
//! Returns size in bytes of given type
int GetTypeSize(Type type);
// TODO: functions for conversion between types
} // namespace Gfx

View File

@ -26,11 +26,13 @@
#include "graphics/core/color.h" #include "graphics/core/color.h"
#include "graphics/core/type.h"
#include "math/point.h" #include "math/point.h"
#include "math/vector.h" #include "math/vector.h"
#include <sstream> #include <sstream>
#include <cstdint>
// Graphics module namespace // Graphics module namespace
@ -38,6 +40,58 @@ namespace Gfx
{ {
/**
* \struct VertexAttribute
* \brief Vertex attribute
*
* This structure contains parameters for a vertex attribute.
*/
struct VertexAttribute
{
//! true enables vertex attribute
bool enabled = false;
//! true means normalized value (integer types only)
bool normalized = false;
//! Number of elements in the vertex attribute.
//! Valid values are 1, 2, 3, and 4. Depends on specific attribute.
unsigned char size = 0;
//! Type of values in vertex attribute
Type type = Type::UBYTE;
//! Offset to the vertex attribute
int offset = 0;
//! Stride of vertex attribute
int stride = 0;
//! Default values used when attribute is disabled
float values[4] = {0.0f, 0.0f, 0.0f, 0.0f};
};
/**
* \struct VertexFormat
* \brief Vertex format
*
* This structure defines vertex formats for generic vertex arrays.
*
* It contains:
* - vertex coordinate specification
* - color specification
* - normal specification
* - texture coordinate 1 specification
* - texture coordinate 2 specification
*/
struct VertexFormat
{
//! Vertex coordinate
VertexAttribute vertex{};
//! Color
VertexAttribute color{};
//! Normal
VertexAttribute normal{};
//! Texture coordinate 1
VertexAttribute tex1{};
//! Texture coordinate 2
VertexAttribute tex2{};
};
/** /**
* \struct Vertex * \struct Vertex
* \brief Vertex of a primitive * \brief Vertex of a primitive

View File

@ -234,8 +234,6 @@ void CCloud::Create(const std::string& fileName,
m_lines.clear(); m_lines.clear();
for (int y = 0; y < m_brickCount; y++) for (int y = 0; y < m_brickCount; y++)
CreateLine(0, y, m_brickCount); CreateLine(0, y, m_brickCount);
return;
} }
void CCloud::Flush() void CCloud::Flush()

View File

@ -2194,7 +2194,7 @@ void CEngine::SetState(int state, const Color& color)
m_device->SetTextureStageWrap(0, TEX_WRAP_REPEAT, TEX_WRAP_REPEAT); m_device->SetTextureStageWrap(0, TEX_WRAP_REPEAT, TEX_WRAP_REPEAT);
m_device->SetTextureStageWrap(1, TEX_WRAP_REPEAT, TEX_WRAP_REPEAT); m_device->SetTextureStageWrap(1, TEX_WRAP_REPEAT, TEX_WRAP_REPEAT);
} }
else // if (state & ENG_RSTATE_CLAMP) or otherwise else if (state & ENG_RSTATE_CLAMP)
{ {
m_device->SetTextureStageWrap(0, TEX_WRAP_CLAMP, TEX_WRAP_CLAMP); m_device->SetTextureStageWrap(0, TEX_WRAP_CLAMP, TEX_WRAP_CLAMP);
m_device->SetTextureStageWrap(1, TEX_WRAP_CLAMP, TEX_WRAP_CLAMP); m_device->SetTextureStageWrap(1, TEX_WRAP_CLAMP, TEX_WRAP_CLAMP);
@ -3087,6 +3087,11 @@ const Math::Matrix& CEngine::GetMatView()
return m_matView; return m_matView;
} }
const Math::Matrix& CEngine::GetMatProj()
{
return m_matProj;
}
Math::Vector CEngine::GetEyePt() Math::Vector CEngine::GetEyePt()
{ {
return m_eyePt; return m_eyePt;
@ -3261,7 +3266,9 @@ void CEngine::Draw3DScene()
m_device->SetTransform(TRANSFORM_PROJECTION, m_matProj); m_device->SetTransform(TRANSFORM_PROJECTION, m_matProj);
m_device->SetTransform(TRANSFORM_VIEW, m_matView); m_device->SetTransform(TRANSFORM_VIEW, m_matView);
m_water->DrawBack(); // draws water background // TODO: This causes a rendering artifact and I can't see anything that breaks if you just comment it out
// So I'll just leave it like that for now ~krzys_h
//m_water->DrawBack(); // draws water background
CProfiler::StartPerformanceCounter(PCNT_RENDER_TERRAIN); CProfiler::StartPerformanceCounter(PCNT_RENDER_TERRAIN);
@ -4262,15 +4269,15 @@ void CEngine::UpdateGroundSpotTextures()
else else
intensity = Math::Point(ppx-cx, ppy-cy).Length()/dot; intensity = Math::Point(ppx-cx, ppy-cy).Length()/dot;
Gfx::Color color;
color.r = Math::Norm(m_groundSpots[i].color.r+intensity);
color.g = Math::Norm(m_groundSpots[i].color.g+intensity);
color.b = Math::Norm(m_groundSpots[i].color.b+intensity);
ppx -= min.x; // on the texture ppx -= min.x; // on the texture
ppy -= min.y; ppy -= min.y;
Math::IntPoint pp(ppx, ppy);
shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color); Gfx::Color color = shadowImg.GetPixel(pp);
color.r *= Math::Norm(m_groundSpots[i].color.r+intensity);
color.g *= Math::Norm(m_groundSpots[i].color.g+intensity);
color.b *= Math::Norm(m_groundSpots[i].color.b+intensity);
shadowImg.SetPixel(pp, color);
} }
} }
} }
@ -4298,12 +4305,13 @@ void CEngine::UpdateGroundSpotTextures()
if (intensity < 0.0f) intensity = 0.0f; if (intensity < 0.0f) intensity = 0.0f;
Gfx::Color color; Math::IntPoint pp(ix, iy);
color.r = Math::Norm(m_groundSpots[i].color.r+intensity);
color.g = Math::Norm(m_groundSpots[i].color.g+intensity);
color.b = Math::Norm(m_groundSpots[i].color.b+intensity);
shadowImg.SetPixel(Math::IntPoint(ix, iy), color); Gfx::Color color = shadowImg.GetPixel(pp);
color.r *= Math::Norm(m_groundSpots[i].color.r+intensity);
color.g *= Math::Norm(m_groundSpots[i].color.g+intensity);
color.b *= Math::Norm(m_groundSpots[i].color.b+intensity);
shadowImg.SetPixel(pp, color);
} }
} }
} }
@ -4351,19 +4359,21 @@ void CEngine::UpdateGroundSpotTextures()
int j = (ix+dot) + (iy+dot) * m_groundMark.dx; int j = (ix+dot) + (iy+dot) * m_groundMark.dx;
if (m_groundMark.table[j] == 1) // green ? if (m_groundMark.table[j] == 1) // green ?
{ {
Gfx::Color color; Math::IntPoint pp(ppx, ppy);
color.r = Math::Norm(1.0f-intensity); Gfx::Color color = shadowImg.GetPixel(pp);
color.g = 1.0f; color.r *= Math::Norm(1.0f-intensity);
color.b = Math::Norm(1.0f-intensity); color.g *= 1.0f;
shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color); color.b *= Math::Norm(1.0f-intensity);
shadowImg.SetPixel(pp, color);
} }
if (m_groundMark.table[j] == 2) // red ? if (m_groundMark.table[j] == 2) // red ?
{ {
Gfx::Color color; Math::IntPoint pp(ppx, ppy);
color.r = 1.0f; Gfx::Color color = shadowImg.GetPixel(pp);
color.g = Math::Norm(1.0f-intensity); color.r *= 1.0f;
color.b = Math::Norm(1.0f-intensity); color.g *= Math::Norm(1.0f-intensity);
shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color); color.b *= Math::Norm(1.0f-intensity);
shadowImg.SetPixel(pp, color);
} }
} }
} }
@ -4401,6 +4411,9 @@ void CEngine::UpdateGroundSpotTextures()
{ {
int px = x / 4.0f / 254.0f * size.x; int px = x / 4.0f / 254.0f * size.x;
int py = y / 4.0f / 254.0f * size.y; int py = y / 4.0f / 254.0f * size.y;
// This can happen because the shadow??.png textures have a 1 pixel margin around them
if (px < 0 || px >= size.x || py < 0 || py >= size.y)
continue;
shadowImg.SetPixelInt(Math::IntPoint(x-min.x, y-min.y), m_displayGotoImage->GetPixelInt(Math::IntPoint(px, py))); shadowImg.SetPixelInt(Math::IntPoint(x-min.x, y-min.y), m_displayGotoImage->GetPixelInt(Math::IntPoint(px, py)));
} }
} }

View File

@ -1135,6 +1135,8 @@ public:
//! Returns the view matrix //! Returns the view matrix
const Math::Matrix& GetMatView(); const Math::Matrix& GetMatView();
//! Returns the projection matrix
const Math::Matrix& GetMatProj();
//! Returns the camera center point //! Returns the camera center point
TEST_VIRTUAL Math::Vector GetEyePt(); TEST_VIRTUAL Math::Vector GetEyePt();
//! Returns the camera target point //! Returns the camera target point

View File

@ -131,7 +131,7 @@ bool CLightning::EventFrame(const Event &event)
else else
{ {
assert(obj->Implements(ObjectInterfaceType::Destroyable)); assert(obj->Implements(ObjectInterfaceType::Destroyable));
dynamic_cast<CDestroyableObject*>(obj)->DamageObject(DamageType::Lightning); dynamic_cast<CDestroyableObject*>(obj)->DamageObject(DamageType::Lightning, std::numeric_limits<float>::infinity());
} }
} }

View File

@ -952,10 +952,9 @@ void CParticle::FrameParticle(float rTime)
{ {
CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather);
m_particle[i].goal = m_particle[i].pos; m_particle[i].goal = m_particle[i].pos;
if (object != nullptr) if (object != nullptr && object->Implements(ObjectInterfaceType::Damageable))
{ {
assert(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].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration);
@ -1107,7 +1106,7 @@ void CParticle::FrameParticle(float rTime)
continue; continue;
} }
if (m_particle[i].testTime >= 0.1f) if (m_particle[i].testTime >= 0.05f)
{ {
m_particle[i].testTime = 0.0f; m_particle[i].testTime = 0.0f;
@ -1156,8 +1155,10 @@ void CParticle::FrameParticle(float rTime)
m_particle[i].goal = m_particle[i].pos; m_particle[i].goal = m_particle[i].pos;
if (object != nullptr) if (object != nullptr)
{ {
assert(object->Implements(ObjectInterfaceType::Damageable)); if (object->Implements(ObjectInterfaceType::Damageable))
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, 0.002f); {
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, 0.001f, m_particle[i].objFather);
}
m_exploGunCounter++; m_exploGunCounter++;
@ -1215,7 +1216,7 @@ void CParticle::FrameParticle(float rTime)
continue; continue;
} }
if (m_particle[i].testTime >= 0.2f) if (m_particle[i].testTime >= 0.1f)
{ {
m_particle[i].testTime = 0.0f; m_particle[i].testTime = 0.0f;
CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather);
@ -1238,8 +1239,10 @@ void CParticle::FrameParticle(float rTime)
if (object->GetType() != OBJECT_HUMAN) if (object->GetType() != OBJECT_HUMAN)
Play(SOUND_TOUCH, m_particle[i].pos, 1.0f); Play(SOUND_TOUCH, m_particle[i].pos, 1.0f);
assert(object->Implements(ObjectInterfaceType::Damageable)); if (object->Implements(ObjectInterfaceType::Damageable))
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.2f); // starts explosion {
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.1f, m_particle[i].objFather); // starts explosion
}
} }
} }
} }
@ -1261,7 +1264,7 @@ void CParticle::FrameParticle(float rTime)
continue; continue;
} }
if (m_particle[i].testTime >= 0.2f) if (m_particle[i].testTime >= 0.1f)
{ {
m_particle[i].testTime = 0.0f; m_particle[i].testTime = 0.0f;
CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather);
@ -1281,8 +1284,10 @@ void CParticle::FrameParticle(float rTime)
} }
else else
{ {
assert(object->Implements(ObjectInterfaceType::Damageable)); if (object->Implements(ObjectInterfaceType::Damageable))
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire); // starts explosion {
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Fire, std::numeric_limits<float>::infinity(), m_particle[i].objFather); // starts explosion
}
} }
} }
} }
@ -1301,7 +1306,7 @@ void CParticle::FrameParticle(float rTime)
continue; continue;
} }
if (m_particle[i].testTime >= 0.1f) if (m_particle[i].testTime >= 0.05f)
{ {
m_particle[i].testTime = 0.0f; m_particle[i].testTime = 0.0f;
@ -1338,8 +1343,10 @@ void CParticle::FrameParticle(float rTime)
m_particle[i].goal = m_particle[i].pos; m_particle[i].goal = m_particle[i].pos;
if (object != nullptr) if (object != nullptr)
{ {
assert(object->Implements(ObjectInterfaceType::Damageable)); if (object->Implements(ObjectInterfaceType::Damageable))
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.002f); {
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Organic, 0.001f, m_particle[i].objFather);
}
m_exploGunCounter ++; m_exploGunCounter ++;
@ -2416,7 +2423,7 @@ void CParticle::FrameParticle(float rTime)
if (object != nullptr) if (object != nullptr)
{ {
assert(object->Implements(ObjectInterfaceType::Damageable)); assert(object->Implements(ObjectInterfaceType::Damageable));
dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Tower); dynamic_cast<CDamageableObject*>(object)->DamageObject(DamageType::Tower, std::numeric_limits<float>::infinity(), m_particle[i].objFather);
} }
} }
@ -3502,6 +3509,7 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos,
box2.z += min; box2.z += min;
CObject* best = nullptr; CObject* best = nullptr;
float best_dist = std::numeric_limits<float>::infinity();
bool shield = false; bool shield = false;
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
{ {
@ -3535,7 +3543,7 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos,
{ {
continue; continue;
} }
if (!obj->Implements(ObjectInterfaceType::Damageable)) continue; if (!obj->Implements(ObjectInterfaceType::Damageable) && !obj->IsBulletWall()) continue;
Math::Vector oPos = obj->GetPosition(); Math::Vector oPos = obj->GetPosition();
@ -3563,8 +3571,12 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos,
// Test the center of the object, which is necessary for objects // Test the center of the object, which is necessary for objects
// that have no sphere in the center (station). // that have no sphere in the center (station).
float dist = Math::Distance(oPos, pos)-4.0f; float dist = Math::Distance(oPos, pos)-4.0f;
if (dist < min) float obj_dist = Math::Distance(old, oPos);
if (dist < min && obj_dist < best_dist)
{
best = obj; best = obj;
best_dist = obj_dist;
}
for (const auto& crashSphere : obj->GetAllCrashSpheres()) for (const auto& crashSphere : obj->GetAllCrashSpheres())
{ {
@ -3577,8 +3589,12 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos,
Math::Vector p = Math::Projection(old, pos, oPos); Math::Vector p = Math::Projection(old, pos, oPos);
float ddist = Math::Distance(p, oPos)-oRadius; float ddist = Math::Distance(p, oPos)-oRadius;
if (ddist < min) float obj_dist = Math::Distance(old, oPos);
if (ddist < min && obj_dist < best_dist)
{
best = obj; best = obj;
best_dist = obj_dist;
}
} }
} }
@ -3724,4 +3740,24 @@ Color CParticle::GetFogColor(Math::Vector pos)
return result; return result;
} }
void CParticle::CutObjectLink(CObject* obj)
{
for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++)
{
if (!m_particle[i].used) continue;
if (m_particle[i].objLink == obj)
{
// If the object this particle's coordinates are linked to doesn't exist anymore, remove the particle
DeleteRank(i);
}
if (m_particle[i].objFather == obj)
{
// If the object that spawned this partcle doesn't exist anymore, remove the link
m_particle[i].objFather = nullptr;
}
}
}
} // namespace Gfx } // namespace Gfx

View File

@ -291,6 +291,9 @@ public:
//! Draws all the particles //! Draws all the particles
void DrawParticle(int sheet); void DrawParticle(int sheet);
//! Indicates that the object binds to the particle no longer exists, without deleting it
void CutObjectLink(CObject* obj);
protected: protected:
//! Removes a particle of given rank //! Removes a particle of given rank
void DeleteRank(int rank); void DeleteRank(int rank);

View File

@ -2157,6 +2157,9 @@ bool CPyro::BurnIsKeepPart(int part)
void CPyro::BurnTerminate() void CPyro::BurnTerminate()
{ {
if (m_object == nullptr)
return;
if (m_type == PT_BURNO) // organic object is burning? if (m_type == PT_BURNO) // organic object is burning?
{ {
DeleteObject(true, true); // removes the insect DeleteObject(true, true); // removes the insect
@ -2296,6 +2299,7 @@ void CPyro::FallProgress(float rTime)
if (floor) // reaches the ground? if (floor) // reaches the ground?
{ {
assert(m_object->Implements(ObjectInterfaceType::Destroyable)); 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);
} }
} }
@ -2319,6 +2323,7 @@ void CPyro::FallProgress(float rTime)
else else
{ {
assert(m_object->Implements(ObjectInterfaceType::Destroyable)); 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

@ -229,7 +229,7 @@ bool CTerrain::LoadResources(const std::string& fileName)
if ( (data->surface->w != size) || (data->surface->h != size) ) if ( (data->surface->w != size) || (data->surface->h != size) )
{ {
GetLogger()->Error("Invalid resource file\n"); GetLogger()->Error("Invalid resource file! Expected %dx%d\n", size, size);
return false; return false;
} }
@ -311,10 +311,11 @@ bool CTerrain::LoadRelief(const std::string &fileName, float scaleRelief,
ImageData *data = img.GetData(); ImageData *data = img.GetData();
int size = (m_mosaicCount*m_brickCount)+1; int size = (m_mosaicCount*m_brickCount)+1;
GetLogger()->Debug("Expected relief size for current terrain configuration is %dx%d\n", size, size);
if ( (data->surface->w != size) || (data->surface->h != size) ) if ( (data->surface->w != size) || (data->surface->h != size) )
{ {
GetLogger()->Error("Invalid relief file!\n"); GetLogger()->Error("Invalid relief file! Expected %dx%d\n", size, size);
return false; return false;
} }

View File

@ -643,37 +643,37 @@ UTF8Char CText::TranslateSpecialChar(int specialChar)
case CHAR_NEWLINE: case CHAR_NEWLINE:
// Unicode: U+21B2 // Unicode: U+21B2
ch.c1 = 0xE2; ch.c1 = static_cast<char>(0xE2);
ch.c2 = 0x86; ch.c2 = static_cast<char>(0x86);
ch.c3 = 0xB2; ch.c3 = static_cast<char>(0xB2);
break; break;
case CHAR_DOT: case CHAR_DOT:
// Unicode: U+23C5 // Unicode: U+23C5
ch.c1 = 0xE2; ch.c1 = static_cast<char>(0xE2);
ch.c2 = 0x8F; ch.c2 = static_cast<char>(0x8F);
ch.c3 = 0x85; ch.c3 = static_cast<char>(0x85);
break; break;
case CHAR_SQUARE: case CHAR_SQUARE:
// Unicode: U+25FD // Unicode: U+25FD
ch.c1 = 0xE2; ch.c1 = static_cast<char>(0xE2);
ch.c2 = 0x97; ch.c2 = static_cast<char>(0x97);
ch.c3 = 0xBD; ch.c3 = static_cast<char>(0xBD);
break; break;
case CHAR_SKIP_RIGHT: case CHAR_SKIP_RIGHT:
// Unicode: U+25B6 // Unicode: U+25B6
ch.c1 = 0xE2; ch.c1 = static_cast<char>(0xE2);
ch.c2 = 0x96; ch.c2 = static_cast<char>(0x96);
ch.c3 = 0xB6; ch.c3 = static_cast<char>(0xB6);
break; break;
case CHAR_SKIP_LEFT: case CHAR_SKIP_LEFT:
// Unicode: U+25C0 // Unicode: U+25C0
ch.c1 = 0xE2; ch.c1 = static_cast<char>(0xE2);
ch.c2 = 0x97; ch.c2 = static_cast<char>(0x97);
ch.c3 = 0x80; ch.c3 = static_cast<char>(0x80);
break; break;
default: default:

View File

@ -258,11 +258,25 @@ bool CGL14Device::Create()
{ {
GetLogger()->Info("Core VBO supported\n", glMajor, glMinor); GetLogger()->Info("Core VBO supported\n", glMajor, glMinor);
m_vertexBufferType = VBT_VBO_CORE; m_vertexBufferType = VBT_VBO_CORE;
// Set function pointers
m_glGenBuffers = glGenBuffers;
m_glDeleteBuffers = glDeleteBuffers;
m_glBindBuffer = glBindBuffer;
m_glBufferData = glBufferData;
m_glBufferSubData = glBufferSubData;
} }
else if (vboARB) // VBO ARB extension available else if (vboARB) // VBO ARB extension available
{ {
GetLogger()->Info("ARB VBO supported\n"); GetLogger()->Info("ARB VBO supported\n");
m_vertexBufferType = VBT_VBO_ARB; m_vertexBufferType = VBT_VBO_ARB;
// Set function pointers
m_glGenBuffers = glGenBuffersARB;
m_glDeleteBuffers = glDeleteBuffersARB;
m_glBindBuffer = glBindBufferARB;
m_glBufferData = glBufferDataARB;
m_glBufferSubData = glBufferSubDataARB;
} }
else // no VBO support else // no VBO support
{ {
@ -800,44 +814,22 @@ Texture CGL14Device::CreateDepthTexture(int width, int height, int depth)
GLuint format = GL_DEPTH_COMPONENT; GLuint format = GL_DEPTH_COMPONENT;
if (m_shadowMappingSupport == SMS_CORE) switch (depth)
{ {
switch (depth) case 16:
{ format = GL_DEPTH_COMPONENT16;
case 16: break;
format = GL_DEPTH_COMPONENT16; case 24:
break; format = GL_DEPTH_COMPONENT24;
case 24: break;
format = GL_DEPTH_COMPONENT24; case 32:
break; format = GL_DEPTH_COMPONENT32;
case 32: break;
format = GL_DEPTH_COMPONENT32;
break;
}
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
} }
else
{
switch (depth)
{
case 16:
format = GL_DEPTH_COMPONENT16_ARB;
break;
case 24:
format = GL_DEPTH_COMPONENT24_ARB;
break;
case 32:
format = GL_DEPTH_COMPONENT32_ARB;
break;
}
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
}
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
@ -1379,6 +1371,168 @@ void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_COLOR_ARRAY);
} }
void CGL14Device::DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount)
{
const char *ptr = reinterpret_cast<const char*>(vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(format.vertex.size,
TransformType(format.vertex.type),
format.vertex.stride,
ptr + format.vertex.offset);
if (format.color.enabled)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(format.color.size,
TransformType(format.color.type),
format.color.stride,
ptr + format.color.offset);
}
else
glColor4fv(format.color.values);
if (format.normal.enabled)
{
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(TransformType(format.normal.type),
format.normal.stride,
ptr + format.normal.offset);
}
else
glNormal3fv(format.normal.values);
glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
if (format.tex1.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex1.size,
TransformType(format.tex1.type),
format.tex1.stride,
ptr + format.tex1.offset);
}
else
glTexCoord2fv(format.tex1.values);
glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
if (format.tex2.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex2.size,
TransformType(format.tex2.type),
format.tex2.stride,
ptr + format.tex2.offset);
}
else
glTexCoord2fv(format.tex2.values);
glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY);
if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY);
if (format.tex1.enabled)
{
glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (format.tex2.enabled)
{
glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
void CGL14Device::DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount)
{
const char *ptr = reinterpret_cast<const char*>(vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(format.vertex.size,
TransformType(format.vertex.type),
format.vertex.stride,
ptr + format.vertex.offset);
if (format.color.enabled)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(format.color.size,
TransformType(format.color.type),
format.color.stride,
ptr + format.color.offset);
}
else
glColor4fv(format.color.values);
if (format.normal.enabled)
{
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(TransformType(format.normal.type),
format.normal.stride,
ptr + format.normal.offset);
}
else
glNormal3fv(format.normal.values);
glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
if (format.tex1.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex1.size,
TransformType(format.tex1.type),
format.tex1.stride,
ptr + format.tex1.offset);
}
else
glTexCoord2fv(format.tex1.values);
glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
if (format.tex2.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex2.size,
TransformType(format.tex2.type),
format.tex2.stride,
ptr + format.tex2.offset);
}
else
glTexCoord2fv(format.tex2.values);
GLenum t = TranslateGfxPrimitive(type);
if (m_multiDrawArrays)
{
glMultiDrawArrays(t, first, count, drawCount);
}
else
{
for (int i = 0; i < drawCount; i++)
glDrawArrays(t, first[i], count[i]);
}
glDisableClientState(GL_VERTEX_ARRAY);
if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY);
if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY);
if (format.tex1.enabled)
{
glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (format.tex2.enabled)
{
glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
void CGL14Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, void CGL14Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
int first[], int count[], int drawCount, Color color) int first[], int count[], int drawCount, Color color)
{ {
@ -1494,20 +1648,10 @@ unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const
info.vertexCount = vertexCount; info.vertexCount = vertexCount;
info.bufferId = 0; info.bufferId = 0;
if(m_vertexBufferType == VBT_VBO_CORE) m_glGenBuffers(1, &info.bufferId);
{ m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glGenBuffers(1, &info.bufferId); m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); m_glBindBuffer(GL_ARRAY_BUFFER, 0);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glGenBuffersARB(1, &info.bufferId);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
m_vboObjects[id] = info; m_vboObjects[id] = info;
} }
@ -1538,20 +1682,10 @@ unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const
info.vertexCount = vertexCount; info.vertexCount = vertexCount;
info.bufferId = 0; info.bufferId = 0;
if(m_vertexBufferType == VBT_VBO_CORE) m_glGenBuffers(1, &info.bufferId);
{ m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glGenBuffers(1, &info.bufferId); m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); m_glBindBuffer(GL_ARRAY_BUFFER, 0);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glGenBuffersARB(1, &info.bufferId);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
m_vboObjects[id] = info; m_vboObjects[id] = info;
} }
@ -1582,20 +1716,10 @@ unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const
info.vertexCount = vertexCount; info.vertexCount = vertexCount;
info.bufferId = 0; info.bufferId = 0;
if(m_vertexBufferType == VBT_VBO_CORE) m_glGenBuffers(1, &info.bufferId);
{ m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glGenBuffers(1, &info.bufferId); m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); m_glBindBuffer(GL_ARRAY_BUFFER, 0);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glGenBuffersARB(1, &info.bufferId);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
m_vboObjects[id] = info; m_vboObjects[id] = info;
} }
@ -1626,18 +1750,9 @@ void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
info.vertexType = VERTEX_TYPE_NORMAL; info.vertexType = VERTEX_TYPE_NORMAL;
info.vertexCount = vertexCount; info.vertexCount = vertexCount;
if(m_vertexBufferType == VBT_VBO_CORE) m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
{ m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); m_glBindBuffer(GL_ARRAY_BUFFER, 0);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
} }
else else
{ {
@ -1662,18 +1777,9 @@ void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
info.vertexType = VERTEX_TYPE_TEX2; info.vertexType = VERTEX_TYPE_TEX2;
info.vertexCount = vertexCount; info.vertexCount = vertexCount;
if(m_vertexBufferType == VBT_VBO_CORE) m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
{ m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); m_glBindBuffer(GL_ARRAY_BUFFER, 0);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
} }
else else
{ {
@ -1698,18 +1804,9 @@ void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
info.vertexType = VERTEX_TYPE_COL; info.vertexType = VERTEX_TYPE_COL;
info.vertexCount = vertexCount; info.vertexCount = vertexCount;
if(m_vertexBufferType == VBT_VBO_CORE) m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
{ m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); m_glBindBuffer(GL_ARRAY_BUFFER, 0);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
} }
else else
{ {
@ -1729,10 +1826,7 @@ void CGL14Device::DrawStaticBuffer(unsigned int bufferId)
if (it == m_vboObjects.end()) if (it == m_vboObjects.end())
return; return;
if(m_vertexBufferType == VBT_VBO_CORE) m_glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId);
glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId);
else
glBindBufferARB(GL_ARRAY_BUFFER_ARB, (*it).second.bufferId);
if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) if ((*it).second.vertexType == VERTEX_TYPE_NORMAL)
{ {
@ -1795,10 +1889,7 @@ void CGL14Device::DrawStaticBuffer(unsigned int bufferId)
glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_COLOR_ARRAY);
} }
if(m_vertexBufferType == VBT_VBO_CORE) m_glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
else
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
} }
else else
{ {
@ -1814,10 +1905,7 @@ void CGL14Device::DestroyStaticBuffer(unsigned int bufferId)
if (it == m_vboObjects.end()) if (it == m_vboObjects.end())
return; return;
if(m_vertexBufferType == VBT_VBO_CORE) m_glDeleteBuffers(1, &(*it).second.bufferId);
glDeleteBuffers(1, &(*it).second.bufferId);
else
glDeleteBuffersARB(1, &(*it).second.bufferId);
m_vboObjects.erase(it); m_vboObjects.erase(it);
} }

View File

@ -119,6 +119,11 @@ public:
void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override;
virtual void DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount) override;
virtual void DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount) override;
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override;
virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
@ -290,6 +295,14 @@ private:
bool m_shadowMapping = false; bool m_shadowMapping = false;
//! true means that quality shadows are enabled //! true means that quality shadows are enabled
bool m_shadowQuality = true; bool m_shadowQuality = true;
//! Pointers to OpenGL functions
PFNGLGENBUFFERSPROC m_glGenBuffers = nullptr;
PFNGLDELETEBUFFERSPROC m_glDeleteBuffers = nullptr;
PFNGLBINDBUFFERPROC m_glBindBuffer = nullptr;
PFNGLBUFFERDATAPROC m_glBufferData = nullptr;
PFNGLBUFFERSUBDATAPROC m_glBufferSubData = nullptr;
}; };

View File

@ -242,7 +242,7 @@ bool CGL21Device::Create()
glViewport(0, 0, m_config.size.x, m_config.size.y); glViewport(0, 0, m_config.size.x, m_config.size.y);
// this is set in shader // this is set in shader
int numLights = 8; int numLights = 4;
m_lights = std::vector<Light>(numLights, Light()); m_lights = std::vector<Light>(numLights, Light());
m_lightsEnabled = std::vector<bool> (numLights, false); m_lightsEnabled = std::vector<bool> (numLights, false);
@ -408,7 +408,7 @@ bool CGL21Device::Create()
uni.fogColor = glGetUniformLocation(m_normalProgram, "uni_FogColor"); uni.fogColor = glGetUniformLocation(m_normalProgram, "uni_FogColor");
uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor"); uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor");
uni.lightingEnabled = glGetUniformLocation(m_normalProgram, "uni_LightingEnabled"); uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount");
uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_Material.ambient"); uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_Material.ambient");
uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_Material.diffuse"); uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_Material.diffuse");
@ -417,12 +417,6 @@ bool CGL21Device::Create()
GLchar name[64]; GLchar name[64];
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
sprintf(name, "uni_Light[%d].Enabled", i);
uni.lights[i].enabled = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].Type", i);
uni.lights[i].type = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].Position", i); sprintf(name, "uni_Light[%d].Position", i);
uni.lights[i].position = glGetUniformLocation(m_normalProgram, name); uni.lights[i].position = glGetUniformLocation(m_normalProgram, name);
@ -434,18 +428,6 @@ bool CGL21Device::Create()
sprintf(name, "uni_Light[%d].Specular", i); sprintf(name, "uni_Light[%d].Specular", i);
uni.lights[i].specular = glGetUniformLocation(m_normalProgram, name); uni.lights[i].specular = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].Attenuation", i);
uni.lights[i].attenuation = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].SpotDirection", i);
uni.lights[i].spotDirection = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].Exponent", i);
uni.lights[i].spotExponent = glGetUniformLocation(m_normalProgram, name);
sprintf(name, "uni_Light[%d].SpotCutoff", i);
uni.lights[i].spotCutoff = glGetUniformLocation(m_normalProgram, name);
} }
// Set default uniform values // Set default uniform values
@ -476,10 +458,7 @@ bool CGL21Device::Create()
glUniform1f(uni.shadowColor, 0.5f); glUniform1f(uni.shadowColor, 0.5f);
glUniform1i(uni.lightingEnabled, 0); glUniform1i(uni.lightCount, 0);
for (int i = 0; i < 8; i++)
glUniform1i(uni.lights[i].enabled, 0);
} }
// Obtain uniform locations from interface rendering program and initialize them // Obtain uniform locations from interface rendering program and initialize them
@ -594,6 +573,7 @@ void CGL21Device::ConfigChanged(const DeviceConfig& newConfig)
// Reset state // Reset state
m_lighting = false; m_lighting = false;
m_updateLights = true;
glViewport(0, 0, m_config.size.x, m_config.size.y); glViewport(0, 0, m_config.size.x, m_config.size.y);
@ -721,36 +701,7 @@ void CGL21Device::SetLight(int index, const Light &light)
m_lights[index] = light; m_lights[index] = light;
LightLocations &loc = m_uniforms[m_mode].lights[index]; m_updateLights = true;
glUniform4fv(loc.ambient, 1, light.ambient.Array());
glUniform4fv(loc.diffuse, 1, light.diffuse.Array());
glUniform4fv(loc.specular, 1, light.specular.Array());
glUniform3f(loc.attenuation, light.attenuation0, light.attenuation1, light.attenuation2);
if (light.type == LIGHT_DIRECTIONAL)
{
glUniform1i(loc.type, 1);
glUniform4f(loc.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f);
}
else if (light.type == LIGHT_POINT)
{
glUniform1i(loc.type, 2);
glUniform4f(loc.position, light.position.x, light.position.y, light.position.z, 1.0f);
glUniform3f(loc.spotDirection, 0.0f, 1.0f, 0.0f);
glUniform1f(loc.spotCutoff, -1.0f);
glUniform1f(loc.spotExponent, 1.0f);
}
else if (light.type == LIGHT_SPOT)
{
glUniform1i(loc.type, 3);
glUniform4f(loc.position, light.position.x, light.position.y, light.position.z, 1.0f);
glUniform3f(loc.spotDirection, -light.direction.x, -light.direction.y, -light.direction.z);
glUniform1f(loc.spotCutoff, std::cos(light.spotAngle));
glUniform1f(loc.spotExponent, light.spotIntensity);
}
} }
void CGL21Device::SetLightEnabled(int index, bool enabled) void CGL21Device::SetLightEnabled(int index, bool enabled)
@ -760,7 +711,7 @@ void CGL21Device::SetLightEnabled(int index, bool enabled)
m_lightsEnabled[index] = enabled; m_lightsEnabled[index] = enabled;
glUniform1i(m_uniforms[m_mode].lights[index].enabled, enabled ? 1 : 0); m_updateLights = true;
} }
/** If image is invalid, returns invalid texture. /** If image is invalid, returns invalid texture.
@ -798,12 +749,13 @@ Texture CGL21Device::CreateTexture(ImageData *data, const TextureCreateParams &p
result.originalSize = result.size; result.originalSize = result.size;
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &result.id); glGenTextures(1, &result.id);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, result.id); glBindTexture(GL_TEXTURE_2D, result.id);
glEnable(GL_TEXTURE_2D);
// Set texture parameters // Set texture parameters
GLint minF = GL_NEAREST, magF = GL_NEAREST; GLint minF = GL_NEAREST, magF = GL_NEAREST;
int mipmapLevel = 1; int mipmapLevel = 1;
@ -991,7 +943,7 @@ void CGL21Device::SetTexture(int index, const Texture &texture)
glBindTexture(GL_TEXTURE_2D, texture.id); glBindTexture(GL_TEXTURE_2D, texture.id);
// Params need to be updated for the new bound texture // Params need to be updated for the new bound texture
UpdateTextureStatus(); UpdateTextureState(index);
UpdateTextureParams(index); UpdateTextureParams(index);
} }
@ -1009,7 +961,7 @@ void CGL21Device::SetTexture(int index, unsigned int textureId)
glBindTexture(GL_TEXTURE_2D, textureId); glBindTexture(GL_TEXTURE_2D, textureId);
// Params need to be updated for the new bound texture // Params need to be updated for the new bound texture
UpdateTextureStatus(); UpdateTextureState(index);
UpdateTextureParams(index); UpdateTextureParams(index);
} }
@ -1024,15 +976,54 @@ void CGL21Device::SetTextureEnabled(int index, bool enabled)
if (same) if (same)
return; // nothing to do return; // nothing to do
UpdateTextureStatus(); UpdateTextureState(index);
} }
void CGL21Device::UpdateTextureStatus() void CGL21Device::UpdateTextureState(int index)
{ {
for (int i = 0; i < 3; i++) bool enabled = m_texturesEnabled[index] && (m_currentTextures[index].id != 0);
glUniform1i(m_uniforms[m_mode].textureEnabled[index], enabled ? 1 : 0);
}
void CGL21Device::UpdateLights()
{
m_updateLights = false;
// If not in normal rendering mode, return immediately
if (m_mode != 0) return;
// Lighting enabled
if (m_lighting)
{ {
bool enabled = m_texturesEnabled[i] && (m_currentTextures[i].id != 0); int index = 0;
glUniform1i(m_uniforms[m_mode].textureEnabled[i], enabled ? 1 : 0);
// Iterate all lights
for (unsigned int i = 0; i < m_lights.size(); i++)
{
// If disabled, ignore and continue
if (!m_lightsEnabled[i]) continue;
// If not directional, ignore and continue
if (m_lights[i].type != LIGHT_DIRECTIONAL) continue;
Light &light = m_lights[i];
LightLocations &uni = m_uniforms[m_mode].lights[index];
glUniform4fv(uni.ambient, 1, light.ambient.Array());
glUniform4fv(uni.diffuse, 1, light.diffuse.Array());
glUniform4fv(uni.specular, 1, light.specular.Array());
glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f);
index++;
}
glUniform1i(m_uniforms[m_mode].lightCount, index);
}
// Lighting disabled
else
{
glUniform1i(m_uniforms[m_mode].lightCount, 0);
} }
} }
@ -1044,6 +1035,12 @@ inline void CGL21Device::BindVBO(GLuint vbo)
m_currentVBO = vbo; m_currentVBO = vbo;
} }
inline void CGL21Device::BindTexture(int index, GLuint texture)
{
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, texture);
}
/** /**
Sets the texture parameters for the given texture stage. Sets the texture parameters for the given texture stage.
If the given texture was not set (bound) yet, nothing happens. If the given texture was not set (bound) yet, nothing happens.
@ -1121,6 +1118,8 @@ void CGL21Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode
void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount,
Color color) Color color)
{ {
if (m_updateLights) UpdateLights();
BindVBO(0); BindVBO(0);
Vertex* vs = const_cast<Vertex*>(vertices); Vertex* vs = const_cast<Vertex*>(vertices);
@ -1148,6 +1147,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int
void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
Color color) Color color)
{ {
if (m_updateLights) UpdateLights();
BindVBO(0); BindVBO(0);
VertexTex2* vs = const_cast<VertexTex2*>(vertices); VertexTex2* vs = const_cast<VertexTex2*>(vertices);
@ -1180,6 +1181,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices,
void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount)
{ {
if (m_updateLights) UpdateLights();
BindVBO(0); BindVBO(0);
VertexCol* vs = const_cast<VertexCol*>(vertices); VertexCol* vs = const_cast<VertexCol*>(vertices);
@ -1196,9 +1199,171 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_COLOR_ARRAY);
} }
void CGL21Device::DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount)
{
if (m_updateLights) UpdateLights();
BindVBO(0);
const char *ptr = reinterpret_cast<const char*>(vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(format.vertex.size,
TransformType(format.vertex.type),
format.vertex.stride,
ptr + format.vertex.offset);
if (format.color.enabled)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(format.color.size,
TransformType(format.color.type),
format.color.stride,
ptr + format.color.offset);
}
else
glColor4fv(format.color.values);
if (format.normal.enabled)
{
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(TransformType(format.normal.type),
format.normal.stride,
ptr + format.normal.offset);
}
else
glNormal3fv(format.normal.values);
glClientActiveTexture(GL_TEXTURE0);
if (format.tex1.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex1.size,
TransformType(format.tex1.type),
format.tex1.stride,
ptr + format.tex1.offset);
}
else
glTexCoord2fv(format.tex1.values);
glClientActiveTexture(GL_TEXTURE1);
if (format.tex2.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex2.size,
TransformType(format.tex2.type),
format.tex2.stride,
ptr + format.tex2.offset);
}
else
glTexCoord2fv(format.tex2.values);
glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY);
if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY);
if (format.tex1.enabled)
{
glClientActiveTexture(GL_TEXTURE0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (format.tex2.enabled)
{
glClientActiveTexture(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
void CGL21Device::DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount)
{
if (m_updateLights) UpdateLights();
BindVBO(0);
const char *ptr = reinterpret_cast<const char*>(vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(format.vertex.size,
TransformType(format.vertex.type),
format.vertex.stride,
ptr + format.vertex.offset);
if (format.color.enabled)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(format.color.size,
TransformType(format.color.type),
format.color.stride,
ptr + format.color.offset);
}
else
glColor4fv(format.color.values);
if (format.normal.enabled)
{
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(TransformType(format.normal.type),
format.normal.stride,
ptr + format.normal.offset);
}
else
glNormal3fv(format.normal.values);
glClientActiveTexture(GL_TEXTURE0);
if (format.tex1.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex1.size,
TransformType(format.tex1.type),
format.tex1.stride,
ptr + format.tex1.offset);
}
else
glTexCoord2fv(format.tex1.values);
glClientActiveTexture(GL_TEXTURE1);
if (format.tex2.enabled)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(format.tex2.size,
TransformType(format.tex2.type),
format.tex2.stride,
ptr + format.tex2.offset);
}
else
glTexCoord2fv(format.tex2.values);
glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount);
glDisableClientState(GL_VERTEX_ARRAY);
if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY);
if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY);
if (format.tex1.enabled)
{
glClientActiveTexture(GL_TEXTURE0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (format.tex2.enabled)
{
glClientActiveTexture(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
int first[], int count[], int drawCount, Color color) int first[], int count[], int drawCount, Color color)
{ {
if (m_updateLights) UpdateLights();
BindVBO(0); BindVBO(0);
Vertex* vs = const_cast<Vertex*>(vertices); Vertex* vs = const_cast<Vertex*>(vertices);
@ -1225,6 +1390,8 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
int first[], int count[], int drawCount, Color color) int first[], int count[], int drawCount, Color color)
{ {
if (m_updateLights) UpdateLights();
BindVBO(0); BindVBO(0);
VertexTex2* vs = const_cast<VertexTex2*>(vertices); VertexTex2* vs = const_cast<VertexTex2*>(vertices);
@ -1258,6 +1425,8 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
int first[], int count[], int drawCount) int first[], int count[], int drawCount)
{ {
if (m_updateLights) UpdateLights();
BindVBO(0); BindVBO(0);
VertexCol* vs = const_cast<VertexCol*>(vertices); VertexCol* vs = const_cast<VertexCol*>(vertices);
@ -1418,6 +1587,8 @@ void CGL21Device::DrawStaticBuffer(unsigned int bufferId)
if (it == m_vboObjects.end()) if (it == m_vboObjects.end())
return; return;
if (m_updateLights) UpdateLights();
BindVBO((*it).second.bufferId); BindVBO((*it).second.bufferId);
if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) if ((*it).second.vertexType == VERTEX_TYPE_NORMAL)
@ -1585,9 +1756,11 @@ void CGL21Device::SetRenderState(RenderState state, bool enabled)
} }
else if (state == RENDER_STATE_LIGHTING) else if (state == RENDER_STATE_LIGHTING)
{ {
if (m_lighting == enabled) return;
m_lighting = enabled; m_lighting = enabled;
glUniform1i(m_uniforms[m_mode].lightingEnabled, enabled ? 1 : 0); m_updateLights = true;
return; return;
} }

View File

@ -100,6 +100,11 @@ public:
void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override;
virtual void DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount) override;
virtual void DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount) override;
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override;
virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
@ -178,10 +183,14 @@ public:
private: private:
//! Updates the texture params for given texture stage //! Updates the texture params for given texture stage
void UpdateTextureParams(int index); void UpdateTextureParams(int index);
//! Updates texture status //! Updates texture state
void UpdateTextureStatus(); void UpdateTextureState(int index);
//! Update light parameters
void UpdateLights();
//! Binds VBO //! Binds VBO
inline void BindVBO(GLuint vbo); inline void BindVBO(GLuint vbo);
//! Binds texture
inline void BindTexture(int index, GLuint texture);
private: private:
//! Current config //! Current config
@ -203,6 +212,8 @@ private:
//! Whether lighting is enabled //! Whether lighting is enabled
bool m_lighting = false; bool m_lighting = false;
//! true means that lights need to be updated
bool m_updateLights = false;
//! Current lights //! Current lights
std::vector<Light> m_lights; std::vector<Light> m_lights;
//! Current lights enable status //! Current lights enable status

View File

@ -233,7 +233,7 @@ bool CGL33Device::Create()
glViewport(0, 0, m_config.size.x, m_config.size.y); glViewport(0, 0, m_config.size.x, m_config.size.y);
// this is set in shader // this is set in shader
m_capabilities.maxLights = 8; m_capabilities.maxLights = 4;
m_lights = std::vector<Light>(m_capabilities.maxLights, Light()); m_lights = std::vector<Light>(m_capabilities.maxLights, Light());
m_lightsEnabled = std::vector<bool>(m_capabilities.maxLights, false); m_lightsEnabled = std::vector<bool>(m_capabilities.maxLights, false);
@ -381,14 +381,14 @@ bool CGL33Device::Create()
uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor"); uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor");
uni.lightingEnabled = glGetUniformLocation(m_normalProgram, "uni_LightingEnabled"); uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount");
uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_AmbientColor"); uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_AmbientColor");
uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_DiffuseColor"); uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_DiffuseColor");
uni.specularColor = glGetUniformLocation(m_normalProgram, "uni_SpecularColor"); uni.specularColor = glGetUniformLocation(m_normalProgram, "uni_SpecularColor");
GLchar name[64]; GLchar name[64];
for (int i = 0; i < 8; i++) for (int i = 0; i < m_capabilities.maxLights; i++)
{ {
LightLocations &light = uni.lights[i]; LightLocations &light = uni.lights[i];
@ -440,12 +440,9 @@ bool CGL33Device::Create()
glUniform1f(uni.shadowColor, 0.5f); glUniform1f(uni.shadowColor, 0.5f);
glUniform1i(uni.alphaTestEnabled, 0); glUniform1i(uni.alphaTestEnabled, 0);
glUniform1f(uni.alphaReference, 1.0f); glUniform1f(uni.alphaReference, 0.5f);
glUniform1i(uni.lightingEnabled, 0); glUniform1i(uni.lightCount, 0);
for (int i = 0; i < 8; i++)
glUniform1i(uni.lights[i].enabled, 0);
} }
// Obtain uniform locations for interface program // Obtain uniform locations for interface program
@ -523,21 +520,18 @@ bool CGL33Device::Create()
m_framebuffers["default"] = MakeUnique<CDefaultFramebuffer>(framebufferParams); m_framebuffers["default"] = MakeUnique<CDefaultFramebuffer>(framebufferParams);
// create dynamic buffers // create dynamic buffer
for (int i = 0; i < 3; i++) glGenVertexArrays(1, &m_dynamicBuffer.vao);
{
glGenVertexArrays(1, &m_dynamicBuffers[i].vao);
m_dynamicBuffers[i].size = 4 * 1024 * 1024; m_dynamicBuffer.size = 4 * 1024 * 1024;
m_dynamicBuffers[i].offset = 0; m_dynamicBuffer.offset = 0;
glGenBuffers(1, &m_dynamicBuffers[i].vbo); glGenBuffers(1, &m_dynamicBuffer.vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_dynamicBuffers[i].vbo); glBindBuffer(GL_ARRAY_BUFFER, m_dynamicBuffer.vbo);
glBufferData(GL_ARRAY_BUFFER, m_dynamicBuffers[i].size, nullptr, GL_STREAM_DRAW); glBufferData(GL_ARRAY_BUFFER, m_dynamicBuffer.size, nullptr, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
m_vboMemory += m_dynamicBuffers[i].size; m_vboMemory += m_dynamicBuffer.size;
}
GetLogger()->Info("CDevice created successfully\n"); GetLogger()->Info("CDevice created successfully\n");
@ -563,13 +557,10 @@ void CGL33Device::Destroy()
DestroyAllTextures(); DestroyAllTextures();
// delete dynamic buffer // delete dynamic buffer
for (int i = 0; i < 3; i++) glDeleteVertexArrays(1, &m_dynamicBuffer.vao);
{ glDeleteBuffers(1, &m_dynamicBuffer.vbo);
glDeleteVertexArrays(1, &m_dynamicBuffers[i].vao);
glDeleteBuffers(1, &m_dynamicBuffers[i].vbo);
m_vboMemory -= m_dynamicBuffers[i].size; m_vboMemory -= m_dynamicBuffer.size;
}
m_lights.clear(); m_lights.clear();
m_lightsEnabled.clear(); m_lightsEnabled.clear();
@ -643,7 +634,9 @@ void CGL33Device::SetRenderMode(RenderMode mode)
m_uni = &m_uniforms[m_mode]; m_uni = &m_uniforms[m_mode];
UpdateRenderingMode(); UpdateTextureState(0);
UpdateTextureState(1);
UpdateTextureState(2);
} }
void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix) void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix)
@ -714,23 +707,7 @@ void CGL33Device::SetLight(int index, const Light &light)
m_lights[index] = light; m_lights[index] = light;
LightLocations &uni = m_uni->lights[index]; m_updateLights = true;
glUniform4fv(uni.ambient, 1, light.ambient.Array());
glUniform4fv(uni.diffuse, 1, light.diffuse.Array());
glUniform4fv(uni.specular, 1, light.specular.Array());
glUniform3f(uni.attenuation, light.attenuation0, light.attenuation1, light.attenuation2);
if (light.type == LIGHT_DIRECTIONAL)
{
glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f);
}
else
{
glUniform4f(uni.position, light.position.x, light.position.y, light.position.z, 1.0f);
}
// TODO: add spotlight params
} }
void CGL33Device::SetLightEnabled(int index, bool enabled) void CGL33Device::SetLightEnabled(int index, bool enabled)
@ -740,7 +717,7 @@ void CGL33Device::SetLightEnabled(int index, bool enabled)
m_lightsEnabled[index] = enabled; m_lightsEnabled[index] = enabled;
glUniform1i(m_uni->lights[index].enabled, enabled ? 1 : 0); m_updateLights = true;
} }
/** If image is invalid, returns invalid texture. /** If image is invalid, returns invalid texture.
@ -775,10 +752,9 @@ Texture CGL33Device::CreateTexture(ImageData *data, const TextureCreateParams &p
result.originalSize = result.size; result.originalSize = result.size;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &result.id); glGenTextures(1, &result.id);
glBindTexture(GL_TEXTURE_2D, result.id);
BindTexture(m_freeTexture, result.id);
// Set texture parameters // Set texture parameters
GLint minF = GL_NEAREST, magF = GL_NEAREST; GLint minF = GL_NEAREST, magF = GL_NEAREST;
@ -841,9 +817,6 @@ Texture CGL33Device::CreateTexture(ImageData *data, const TextureCreateParams &p
m_allTextures.insert(result); m_allTextures.insert(result);
// Restore the previous state of 1st stage
glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
return result; return result;
} }
@ -855,10 +828,9 @@ Texture CGL33Device::CreateDepthTexture(int width, int height, int depth)
result.size.x = width; result.size.x = width;
result.size.y = height; result.size.y = height;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &result.id); glGenTextures(1, &result.id);
glBindTexture(GL_TEXTURE_2D, result.id);
BindTexture(m_freeTexture, result.id);
GLuint format = GL_DEPTH_COMPONENT; GLuint format = GL_DEPTH_COMPONENT;
@ -887,16 +859,14 @@ Texture CGL33Device::CreateDepthTexture(int width, int height, int depth)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
return result; return result;
} }
void CGL33Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format) void CGL33Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format)
{ {
glActiveTexture(GL_TEXTURE0); if (texture.id == 0) return;
glBindTexture(GL_TEXTURE_2D, texture.id); BindTexture(m_freeTexture, texture.id);
PreparedTextureData texData = PrepareTextureData(data, format); PreparedTextureData texData = PrepareTextureData(data, format);
@ -951,18 +921,16 @@ void CGL33Device::SetTexture(int index, const Texture &texture)
{ {
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() )); assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() ));
bool same = m_currentTextures[index].id == texture.id; if (m_currentTextures[index].id == texture.id)
return;
BindTexture(index, texture.id);
m_currentTextures[index] = texture; // remember the new value m_currentTextures[index] = texture; // remember the new value
if (same)
return; // nothing to do
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, texture.id);
// Params need to be updated for the new bound texture // Params need to be updated for the new bound texture
UpdateTextureParams(index); UpdateTextureParams(index);
UpdateTextureState(index);
} }
void CGL33Device::SetTexture(int index, unsigned int textureId) void CGL33Device::SetTexture(int index, unsigned int textureId)
@ -972,27 +940,25 @@ void CGL33Device::SetTexture(int index, unsigned int textureId)
if (m_currentTextures[index].id == textureId) if (m_currentTextures[index].id == textureId)
return; // nothing to do return; // nothing to do
m_currentTextures[index].id = textureId; BindTexture(index, textureId);
glActiveTexture(GL_TEXTURE0 + index); m_currentTextures[index].id = textureId;
glBindTexture(GL_TEXTURE_2D, textureId);
// Params need to be updated for the new bound texture // Params need to be updated for the new bound texture
UpdateTextureParams(index); UpdateTextureParams(index);
UpdateTextureState(index);
} }
void CGL33Device::SetTextureEnabled(int index, bool enabled) void CGL33Device::SetTextureEnabled(int index, bool enabled)
{ {
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() )); assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() ));
bool same = m_texturesEnabled[index] == enabled; if (m_texturesEnabled[index] == enabled)
return;
m_texturesEnabled[index] = enabled; m_texturesEnabled[index] = enabled;
if (same) UpdateTextureState(index);
return; // nothing to do
UpdateRenderingMode();
} }
/** /**
@ -1071,148 +1037,176 @@ void CGL33Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode
void CGL33Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, Color color) void CGL33Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, Color color)
{ {
if (m_updateLights) UpdateLights();
Vertex* vs = const_cast<Vertex*>(vertices); Vertex* vs = const_cast<Vertex*>(vertices);
unsigned int size = vertexCount * sizeof(Vertex); unsigned int size = vertexCount * sizeof(Vertex);
DynamicBuffer& buffer = m_dynamicBuffers[0]; DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao); BindVAO(buffer.vao);
BindVBO(buffer.vbo); BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size); unsigned int offset = UploadVertexData(buffer, vs, size);
// Start of the buffer, reinitialize binding state // Vertex coordinate
if (offset == 0) glEnableVertexAttribArray(0);
{ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
// Vertex coordinate reinterpret_cast<void*>(offset + offsetof(Vertex, coord)));
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, coord)));
// Normal // Normal
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, normal))); reinterpret_cast<void*>(offset + offsetof(Vertex, normal)));
// Color
glDisableVertexAttribArray(2);
// Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, texCoord)));
// Texture coordinate 1
glDisableVertexAttribArray(4);
glVertexAttrib2f(4, 0.0f, 0.0f);
}
// Color
glDisableVertexAttribArray(2);
glVertexAttrib4fv(2, color.Array()); glVertexAttrib4fv(2, color.Array());
UpdateRenderingMode(); // Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offset + offsetof(Vertex, texCoord)));
int first = offset / sizeof(Vertex); // Texture coordinate 1
glDisableVertexAttribArray(4);
glVertexAttrib2f(4, 0.0f, 0.0f);
glDrawArrays(TranslateGfxPrimitive(type), first, vertexCount); glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
} }
void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, Color color) void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, Color color)
{ {
if (m_updateLights) UpdateLights();
VertexTex2* vs = const_cast<VertexTex2*>(vertices); VertexTex2* vs = const_cast<VertexTex2*>(vertices);
unsigned int size = vertexCount * sizeof(VertexTex2); unsigned int size = vertexCount * sizeof(VertexTex2);
DynamicBuffer& buffer = m_dynamicBuffers[1]; DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao); BindVAO(buffer.vao);
BindVBO(buffer.vbo); BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size); unsigned int offset = UploadVertexData(buffer, vs, size);
if (offset == 0) // Vertex coordinate
{ glEnableVertexAttribArray(0);
// Vertex coordinate glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
glEnableVertexAttribArray(0); reinterpret_cast<void*>(offset + offsetof(VertexTex2, coord)));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, coord)));
// Normal // Normal
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, normal))); reinterpret_cast<void*>(offset + offsetof(VertexTex2, normal)));
// Color
glDisableVertexAttribArray(2);
// Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, texCoord)));
// Texture coordinate 1
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, texCoord2)));
}
// Color
glDisableVertexAttribArray(2);
glVertexAttrib4fv(2, color.Array()); glVertexAttrib4fv(2, color.Array());
UpdateRenderingMode(); // Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offset + offsetof(VertexTex2, texCoord)));
int first = offset / sizeof(VertexTex2); // Texture coordinate 1
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offset + offsetof(VertexTex2, texCoord2)));
glDrawArrays(TranslateGfxPrimitive(type), first, vertexCount); glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
} }
void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount)
{ {
if (m_updateLights) UpdateLights();
VertexCol* vs = const_cast<VertexCol*>(vertices); VertexCol* vs = const_cast<VertexCol*>(vertices);
unsigned int size = vertexCount * sizeof(VertexCol); unsigned int size = vertexCount * sizeof(VertexCol);
DynamicBuffer& buffer = m_dynamicBuffers[2]; DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao); BindVAO(buffer.vao);
BindVBO(buffer.vbo); BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size); unsigned int offset = UploadVertexData(buffer, vs, size);
if (offset == 0) // Vertex coordinate
{ glEnableVertexAttribArray(0);
// Vertex coordinate glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol),
glEnableVertexAttribArray(0); reinterpret_cast<void*>(offset + offsetof(VertexCol, coord)));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol),
reinterpret_cast<void*>(offsetof(VertexCol, coord)));
// Normal // Normal
glDisableVertexAttribArray(1); glDisableVertexAttribArray(1);
glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f); glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f);
// Color // Color
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol), glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol),
reinterpret_cast<void*>(offsetof(VertexCol, color))); reinterpret_cast<void*>(offset + offsetof(VertexCol, color)));
// Texture coordinate 0 // Texture coordinate 0
glDisableVertexAttribArray(3); glDisableVertexAttribArray(3);
glVertexAttrib2f(3, 0.0f, 0.0f); glVertexAttrib2f(3, 0.0f, 0.0f);
// Texture coordinate 1 // Texture coordinate 1
glDisableVertexAttribArray(4); glDisableVertexAttribArray(4);
glVertexAttrib2f(4, 0.0f, 0.0f); glVertexAttrib2f(4, 0.0f, 0.0f);
}
UpdateRenderingMode(); glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
}
int first = offset / sizeof(VertexCol); void CGL33Device::DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount)
{
if (m_updateLights) UpdateLights();
glDrawArrays(TranslateGfxPrimitive(type), first, vertexCount); DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao);
BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vertices, size);
// Update vertex attribute bindings
UpdateVertexAttribute(0, format.vertex, offset);
UpdateVertexAttribute(1, format.normal, offset);
UpdateVertexAttribute(2, format.color, offset);
UpdateVertexAttribute(3, format.tex1, offset);
UpdateVertexAttribute(4, format.tex2, offset);
glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount);
}
void CGL33Device::DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount)
{
if (m_updateLights) UpdateLights();
DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao);
BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vertices, size);
// Update vertex attribute bindings
UpdateVertexAttribute(0, format.vertex, offset);
UpdateVertexAttribute(1, format.normal, offset);
UpdateVertexAttribute(2, format.color, offset);
UpdateVertexAttribute(3, format.tex1, offset);
UpdateVertexAttribute(4, format.tex2, offset);
glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount);
} }
void CGL33Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, void CGL33Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
int first[], int count[], int drawCount, Color color) int first[], int count[], int drawCount, Color color)
{ {
if (m_updateLights) UpdateLights();
Vertex* vs = const_cast<Vertex*>(vertices); Vertex* vs = const_cast<Vertex*>(vertices);
int vertexCount = 0; int vertexCount = 0;
@ -1227,56 +1221,44 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
unsigned int size = vertexCount * sizeof(Vertex); unsigned int size = vertexCount * sizeof(Vertex);
DynamicBuffer& buffer = m_dynamicBuffers[0]; DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao); BindVAO(buffer.vao);
BindVBO(buffer.vbo); BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size); unsigned int offset = UploadVertexData(buffer, vs, size);
if (offset == 0) // Vertex coordinate
{ glEnableVertexAttribArray(0);
// Vertex coordinate glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
glEnableVertexAttribArray(0); reinterpret_cast<void*>(offset + offsetof(Vertex, coord)));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, coord)));
// Normal // Normal
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, normal))); reinterpret_cast<void*>(offset + offsetof(Vertex, normal)));
// Color
glDisableVertexAttribArray(2);
// Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, texCoord)));
// Texture coordinate 1
glDisableVertexAttribArray(4);
glVertexAttrib2f(4, 0.0f, 0.0f);
}
// Color
glDisableVertexAttribArray(2);
glVertexAttrib4fv(2, color.Array()); glVertexAttrib4fv(2, color.Array());
UpdateRenderingMode(); // Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offset + offsetof(Vertex, texCoord)));
int firstOffset = offset / sizeof(Vertex); // Texture coordinate 1
glDisableVertexAttribArray(4);
for (int i = 0; i < drawCount; i++) glVertexAttrib2f(4, 0.0f, 0.0f);
first[i] += firstOffset;
glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount);
for (int i = 0; i < drawCount; i++)
first[i] -= firstOffset;
} }
void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
int first[], int count[], int drawCount, Color color) int first[], int count[], int drawCount, Color color)
{ {
if (m_updateLights) UpdateLights();
VertexTex2* vs = const_cast<VertexTex2*>(vertices); VertexTex2* vs = const_cast<VertexTex2*>(vertices);
int vertexCount = 0; int vertexCount = 0;
@ -1291,57 +1273,45 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
unsigned int size = vertexCount * sizeof(VertexTex2); unsigned int size = vertexCount * sizeof(VertexTex2);
DynamicBuffer& buffer = m_dynamicBuffers[1]; DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao); BindVAO(buffer.vao);
BindVBO(buffer.vbo); BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size); unsigned int offset = UploadVertexData(buffer, vs, size);
if (offset == 0) // Vertex coordinate
{ glEnableVertexAttribArray(0);
// Vertex coordinate glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
glEnableVertexAttribArray(0); reinterpret_cast<void*>(offset + offsetof(VertexTex2, coord)));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, coord)));
// Normal // Normal
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, normal))); reinterpret_cast<void*>(offset + offsetof(VertexTex2, normal)));
// Color
glDisableVertexAttribArray(2);
// Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, texCoord)));
// Texture coordinate 1
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offsetof(VertexTex2, texCoord2)));
}
// Color
glDisableVertexAttribArray(2);
glVertexAttrib4fv(2, color.Array()); glVertexAttrib4fv(2, color.Array());
UpdateRenderingMode(); // Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
reinterpret_cast<void*>(offset + offsetof(VertexTex2, texCoord)));
int firstOffset = offset / sizeof(VertexTex2); // Texture coordinate 1
glEnableVertexAttribArray(4);
for (int i = 0; i < drawCount; i++) glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2),
first[i] += firstOffset; reinterpret_cast<void*>(offset + offsetof(VertexTex2, texCoord2)));
glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount);
for (int i = 0; i < drawCount; i++)
first[i] -= firstOffset;
} }
void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
int first[], int count[], int drawCount) int first[], int count[], int drawCount)
{ {
if (m_updateLights) UpdateLights();
VertexCol* vs = const_cast<VertexCol*>(vertices); VertexCol* vs = const_cast<VertexCol*>(vertices);
int vertexCount = 0; int vertexCount = 0;
@ -1356,49 +1326,36 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
unsigned int size = vertexCount * sizeof(VertexCol); unsigned int size = vertexCount * sizeof(VertexCol);
DynamicBuffer& buffer = m_dynamicBuffers[2]; DynamicBuffer& buffer = m_dynamicBuffer;
BindVAO(buffer.vao); BindVAO(buffer.vao);
BindVBO(buffer.vbo); BindVBO(buffer.vbo);
unsigned int offset = UploadVertexData(buffer, vs, size); unsigned int offset = UploadVertexData(buffer, vs, size);
if (offset == 0) // Vertex coordinate
{ glEnableVertexAttribArray(0);
// Vertex coordinate glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol),
glEnableVertexAttribArray(0); reinterpret_cast<void*>(offset + offsetof(VertexCol, coord)));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol),
reinterpret_cast<void*>(offsetof(VertexCol, coord)));
// Normal // Normal
glDisableVertexAttribArray(1); glDisableVertexAttribArray(1);
glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f); glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f);
// Color // Color
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol), glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol),
reinterpret_cast<void*>(offsetof(VertexCol, color))); reinterpret_cast<void*>(offset + offsetof(VertexCol, color)));
// Texture coordinate 0 // Texture coordinate 0
glDisableVertexAttribArray(3); glDisableVertexAttribArray(3);
glVertexAttrib2f(3, 0.0f, 0.0f); glVertexAttrib2f(3, 0.0f, 0.0f);
// Texture coordinate 1 // Texture coordinate 1
glDisableVertexAttribArray(4); glDisableVertexAttribArray(4);
glVertexAttrib2f(4, 0.0f, 0.0f); glVertexAttrib2f(4, 0.0f, 0.0f);
}
UpdateRenderingMode();
int firstOffset = offset / sizeof(VertexCol);
for (int i = 0; i < drawCount; i++)
first[i] += firstOffset;
glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount);
for (int i = 0; i < drawCount; i++)
first[i] -= firstOffset;
} }
unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount)
@ -1716,14 +1673,14 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
void CGL33Device::DrawStaticBuffer(unsigned int bufferId) void CGL33Device::DrawStaticBuffer(unsigned int bufferId)
{ {
if (m_updateLights) UpdateLights();
auto it = m_vboObjects.find(bufferId); auto it = m_vboObjects.find(bufferId);
if (it == m_vboObjects.end()) if (it == m_vboObjects.end())
return; return;
VertexBufferInfo &info = (*it).second; VertexBufferInfo &info = (*it).second;
UpdateRenderingMode();
BindVAO(info.vao); BindVAO(info.vao);
GLenum mode = TranslateGfxPrimitive(info.primitiveType); GLenum mode = TranslateGfxPrimitive(info.primitiveType);
@ -1851,7 +1808,9 @@ void CGL33Device::SetRenderState(RenderState state, bool enabled)
{ {
m_lighting = enabled; m_lighting = enabled;
glUniform1i(m_uni->lightingEnabled, enabled ? 1 : 0); m_updateLights = true;
//glUniform1i(m_uni->lightingEnabled, enabled ? 1 : 0);
return; return;
} }
@ -1977,13 +1936,9 @@ void CGL33Device::CopyFramebufferToTexture(Texture& texture, int xOffset, int yO
{ {
if (texture.id == 0) return; if (texture.id == 0) return;
glActiveTexture(GL_TEXTURE0); BindTexture(m_freeTexture, texture.id);
glBindTexture(GL_TEXTURE_2D, texture.id);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);
// Restore previous texture
glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
} }
std::unique_ptr<CFrameBufferPixels> CGL33Device::GetFrameBufferPixels() const std::unique_ptr<CFrameBufferPixels> CGL33Device::GetFrameBufferPixels() const
@ -2029,16 +1984,52 @@ void CGL33Device::DeleteFramebuffer(std::string name)
} }
} }
void CGL33Device::UpdateRenderingMode() inline void CGL33Device::UpdateTextureState(int index)
{ {
bool enabled = m_texturesEnabled[0] && m_currentTextures[0].id != 0; bool enabled = m_texturesEnabled[index] && (m_currentTextures[index].id != 0);
glUniform1i(m_uni->textureEnabled[0], enabled ? 1 : 0); glUniform1i(m_uni->textureEnabled[index], enabled ? 1 : 0);
}
enabled = m_texturesEnabled[1] && m_currentTextures[1].id != 0; void CGL33Device::UpdateLights()
glUniform1i(m_uni->textureEnabled[1], enabled ? 1 : 0); {
m_updateLights = false;
enabled = m_texturesEnabled[2] && m_currentTextures[2].id != 0; // If not in normal rendering mode, return immediately
glUniform1i(m_uni->textureEnabled[2], enabled ? 1 : 0); if (m_mode != 0) return;
// Lighting enabled
if (m_lighting)
{
int index = 0;
// Iterate all lights
for (unsigned int i = 0; i < m_lights.size(); i++)
{
// If disabled, ignore and continue
if (!m_lightsEnabled[i]) continue;
// If not directional, ignore and continue
if (m_lights[i].type != LIGHT_DIRECTIONAL) continue;
Light &light = m_lights[i];
LightLocations &uni = m_uni->lights[index];
glUniform4fv(uni.ambient, 1, light.ambient.Array());
glUniform4fv(uni.diffuse, 1, light.diffuse.Array());
glUniform4fv(uni.specular, 1, light.specular.Array());
glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f);
index++;
}
glUniform1i(m_uni->lightCount, index);
}
// Lighting disabled
else
{
glUniform1i(m_uni->lightCount, 0);
}
} }
inline void CGL33Device::BindVBO(GLuint vbo) inline void CGL33Device::BindVBO(GLuint vbo)
@ -2057,7 +2048,13 @@ inline void CGL33Device::BindVAO(GLuint vao)
m_currentVAO = vao; m_currentVAO = vao;
} }
unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, void* data, unsigned int size) inline void CGL33Device::BindTexture(int index, GLuint texture)
{
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, texture);
}
unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, const void* data, unsigned int size)
{ {
unsigned int nextOffset = buffer.offset + size; unsigned int nextOffset = buffer.offset + size;
@ -2095,6 +2092,25 @@ unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, void* data, un
return currentOffset; return currentOffset;
} }
void CGL33Device::UpdateVertexAttribute(int index, const VertexAttribute &attribute, int offset)
{
if (attribute.enabled)
{
glEnableVertexAttribArray(index);
glVertexAttribPointer(index,
attribute.size,
TranslateType(attribute.type),
attribute.normalized ? GL_TRUE : GL_FALSE,
attribute.stride,
reinterpret_cast<void*>(offset + attribute.offset));
}
else
{
glDisableVertexAttribArray(index);
glVertexAttrib4fv(index, attribute.values);
}
}
bool CGL33Device::IsAnisotropySupported() bool CGL33Device::IsAnisotropySupported()
{ {
return m_capabilities.anisotropySupported; return m_capabilities.anisotropySupported;

View File

@ -115,6 +115,11 @@ public:
void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override;
virtual void DrawPrimitive(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int vertexCount) override;
virtual void DrawPrimitives(PrimitiveType type, const void *vertices,
int size, const VertexFormat &format, int first[], int count[], int drawCount) override;
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override;
virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
@ -193,16 +198,22 @@ public:
private: private:
//! Updates the texture params for given texture stage //! Updates the texture params for given texture stage
void UpdateTextureParams(int index); void UpdateTextureParams(int index);
//! Updates rendering mode //! Updates texture state
void UpdateRenderingMode(); inline void UpdateTextureState(int index);
//! Update light parameters
void UpdateLights();
//! Binds VBO //! Binds VBO
inline void BindVBO(GLuint vbo); inline void BindVBO(GLuint vbo);
//! Binds VAO //! Binds VAO
inline void BindVAO(GLuint vao); inline void BindVAO(GLuint vao);
//! Binds texture
inline void BindTexture(int index, GLuint texture);
//! Uploads data to dynamic buffer and returns offset to it //! Uploads data to dynamic buffer and returns offset to it
unsigned int UploadVertexData(DynamicBuffer& buffer, void* data, unsigned int size); unsigned int UploadVertexData(DynamicBuffer& buffer, const void* data, unsigned int size);
inline void UpdateVertexAttribute(int index, const VertexAttribute &attribute, int offset);
private: private:
//! Current config //! Current config
@ -226,6 +237,8 @@ private:
//! Whether lighting is enabled //! Whether lighting is enabled
bool m_lighting = false; bool m_lighting = false;
//! true means that light update is needed
bool m_updateLights = false;
//! Current lights //! Current lights
std::vector<Light> m_lights; std::vector<Light> m_lights;
//! Current lights enable status //! Current lights enable status
@ -240,6 +253,8 @@ private:
//! Set of all created textures //! Set of all created textures
std::set<Texture> m_allTextures; std::set<Texture> m_allTextures;
//! Free texture unit
const int m_freeTexture = 3;
//! Type of vertex structure //! Type of vertex structure
enum VertexType enum VertexType
@ -283,7 +298,7 @@ private:
//! Shader program for shadow rendering //! Shader program for shadow rendering
GLuint m_shadowProgram = 0; GLuint m_shadowProgram = 0;
DynamicBuffer m_dynamicBuffers[3]; DynamicBuffer m_dynamicBuffer;
//! Current mode //! Current mode
unsigned int m_mode = 0; unsigned int m_mode = 0;

View File

@ -335,8 +335,10 @@ GLenum TranslateGfxPrimitive(PrimitiveType type)
case PRIMITIVE_POINTS: flag = GL_POINTS; break; case PRIMITIVE_POINTS: flag = GL_POINTS; break;
case PRIMITIVE_LINES: flag = GL_LINES; break; case PRIMITIVE_LINES: flag = GL_LINES; break;
case PRIMITIVE_LINE_STRIP: flag = GL_LINE_STRIP; break; case PRIMITIVE_LINE_STRIP: flag = GL_LINE_STRIP; break;
case PRIMITIVE_LINE_LOOP: flag = GL_LINE_LOOP; break;
case PRIMITIVE_TRIANGLES: flag = GL_TRIANGLES; break; case PRIMITIVE_TRIANGLES: flag = GL_TRIANGLES; break;
case PRIMITIVE_TRIANGLE_STRIP: flag = GL_TRIANGLE_STRIP; break; case PRIMITIVE_TRIANGLE_STRIP: flag = GL_TRIANGLE_STRIP; break;
case PRIMITIVE_TRIANGLE_FAN: flag = GL_TRIANGLE_FAN; break;
default: assert(false); break; default: assert(false); break;
} }
return flag; return flag;
@ -441,6 +443,23 @@ GLenum TranslateTextureCoordinateGen(int index)
return textureCoordGen[index]; return textureCoordGen[index];
} }
GLenum TranslateType(Type type)
{
switch (type)
{
case Type::BYTE: return GL_BYTE;
case Type::UBYTE: return GL_UNSIGNED_BYTE;
case Type::SHORT: return GL_SHORT;
case Type::USHORT: return GL_UNSIGNED_SHORT;
case Type::INT: return GL_INT;
case Type::UINT: return GL_UNSIGNED_INT;
case Type::HALF: return GL_HALF_FLOAT;
case Type::FLOAT: return GL_FLOAT;
case Type::DOUBLE: return GL_DOUBLE;
default: return 0;
}
}
std::string lastShaderError; std::string lastShaderError;
std::string GetLastShaderError() std::string GetLastShaderError()

View File

@ -93,6 +93,8 @@ GLenum TranslateTextureCoordinate(int index);
GLenum TranslateTextureCoordinateGen(int index); GLenum TranslateTextureCoordinateGen(int index);
GLenum TranslateType(Type type);
std::string GetLastShaderError(); std::string GetLastShaderError();
GLint LoadShader(GLint type, const char* filename); GLint LoadShader(GLint type, const char* filename);
@ -192,8 +194,8 @@ struct UniformLocations
//! Shadow color //! Shadow color
GLint shadowColor = -1; GLint shadowColor = -1;
//! true enables lighting // Number of enabled lights
GLint lightingEnabled = -1; GLint lightCount = -1;
//! Ambient color //! Ambient color
GLint ambientColor = -1; GLint ambientColor = -1;
//! Diffuse color //! Diffuse color

View File

@ -19,6 +19,8 @@
// FRAGMENT SHADER - NORMAL MODE // FRAGMENT SHADER - NORMAL MODE
#version 120 #version 120
#define CONFIG_QUALITY_SHADOWS 1
uniform sampler2D uni_PrimaryTexture; uniform sampler2D uni_PrimaryTexture;
uniform sampler2D uni_SecondaryTexture; uniform sampler2D uni_SecondaryTexture;
uniform sampler2DShadow uni_ShadowTexture; uniform sampler2DShadow uni_ShadowTexture;
@ -34,6 +36,26 @@ uniform vec4 uni_FogColor;
uniform float uni_ShadowColor; uniform float uni_ShadowColor;
struct LightParams
{
vec4 Position;
vec4 Ambient;
vec4 Diffuse;
vec4 Specular;
};
struct Material
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
uniform Material uni_Material;
uniform int uni_LightCount;
uniform LightParams uni_Light[4];
varying float pass_Distance; varying float pass_Distance;
varying vec4 pass_Color; varying vec4 pass_Color;
varying vec3 pass_Normal; varying vec3 pass_Normal;
@ -47,6 +69,55 @@ void main()
{ {
vec4 color = pass_Color; vec4 color = pass_Color;
if (uni_LightCount > 0)
{
vec4 ambient = vec4(0.0f);
vec4 diffuse = vec4(0.0f);
vec4 specular = vec4(0.0f);
vec3 normal = normalize(pass_Normal);
for (int i = 0; i < uni_LightCount; i++)
{
LightParams light = uni_Light[i];
vec3 lightDirection = light.Position.xyz;
vec3 reflectDirection = -reflect(lightDirection, normal);
float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f);
float specularComponent = clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f);
ambient += light.Ambient;
diffuse += diffuseComponent * light.Diffuse;
specular += specularComponent * light.Specular;
}
float shadow = 1.0f;
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);
shadow = mix(uni_ShadowColor, 1.0f, value);
#else
shadow = mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, pass_TexCoord2).x);
#endif
}
vec4 result = ambient * uni_Material.ambient
+ diffuse * uni_Material.diffuse * shadow
+ specular * uni_Material.specular * shadow;
color = clamp(vec4(result.rgb, 1.0f), 0.0f, 1.0f);
}
if (uni_TextureEnabled[0]) if (uni_TextureEnabled[0])
{ {
color = color * texture2D(uni_PrimaryTexture, pass_TexCoord0); color = color * texture2D(uni_PrimaryTexture, pass_TexCoord0);
@ -57,16 +128,6 @@ void main()
color = color * texture2D(uni_SecondaryTexture, pass_TexCoord1); color = color * texture2D(uni_SecondaryTexture, pass_TexCoord1);
} }
if (uni_TextureEnabled[2])
{
vec3 normal = pass_Normal * (2.0f * gl_Color.x - 1.0f);
if (dot(normal, const_LightDirection) < 0.0f)
color.rgb *= uni_ShadowColor;
else
color.rgb *= mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, pass_TexCoord2).x);
}
if (uni_FogEnabled) if (uni_FogEnabled)
{ {
float interpolate = (pass_Distance - uni_FogRange.x) / (uni_FogRange.y - uni_FogRange.x); float interpolate = (pass_Distance - uni_FogRange.x) / (uni_FogRange.y - uni_FogRange.x);

View File

@ -25,33 +25,6 @@ uniform mat4 uni_ModelMatrix;
uniform mat4 uni_ShadowMatrix; uniform mat4 uni_ShadowMatrix;
uniform mat4 uni_NormalMatrix; uniform mat4 uni_NormalMatrix;
struct LightParams
{
bool Enabled;
int Type;
vec4 Position;
vec4 Ambient;
vec4 Diffuse;
vec4 Specular;
float Shininess;
vec3 Attenuation;
vec3 SpotDirection;
float SpotCutoff;
float SpotExponent;
};
struct Material
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
uniform Material uni_Material;
uniform bool uni_LightingEnabled;
uniform LightParams uni_Light[8];
varying float pass_Distance; varying float pass_Distance;
varying vec4 pass_Color; varying vec4 pass_Color;
varying vec3 pass_Normal; varying vec3 pass_Normal;
@ -65,75 +38,11 @@ void main()
vec4 eyeSpace = uni_ViewMatrix * position; vec4 eyeSpace = uni_ViewMatrix * position;
vec4 shadowCoord = uni_ShadowMatrix * position; vec4 shadowCoord = uni_ShadowMatrix * position;
vec4 color = gl_Color;
vec3 normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz);
if (uni_LightingEnabled)
{
vec4 ambient = vec4(0.0f);
vec4 diffuse = vec4(0.0f);
vec4 specular = vec4(0.0f);
for (int i = 0; i < 8; i++)
{
if (uni_Light[i].Enabled)
{
LightParams light = uni_Light[i];
vec3 lightDirection = light.Position.xyz;
float atten = 1.0f;
if (light.Position.w > 0.5f)
{
float dist = distance(light.Position.xyz, position.xyz);
float atten = 1.0f / dot(light.Attenuation,
vec3(1.0f, dist, dist * dist));
lightDirection = normalize(light.Position.xyz - position.xyz);
}
float spot = 1.0f;
if (light.SpotCutoff > 0.0f)
{
float cone = dot(light.SpotDirection, lightDirection);
if (cone > light.SpotCutoff)
{
spot = pow(cone, light.SpotExponent);
}
else
{
continue;
}
}
vec3 reflectDirection = -reflect(lightDirection, normal);
float component = atten * spot;
float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f);
float specularComponent = clamp(pow(dot(normal, lightDirection + reflectDirection), light.Shininess), 0.0f, 1.0f);
ambient += component * light.Ambient * uni_Material.ambient;
diffuse += component * diffuseComponent * light.Diffuse * uni_Material.diffuse;
specular += component * specularComponent * light.Specular * uni_Material.specular;
}
}
vec4 result = ambient + diffuse + specular;
color = clamp(vec4(result.rgb, uni_Material.diffuse), 0.0f, 1.0f);
}
gl_Position = uni_ProjectionMatrix * eyeSpace; gl_Position = uni_ProjectionMatrix * eyeSpace;
gl_FrontColor = vec4(1.0f);
gl_BackColor = vec4(0.0f);
pass_Color = gl_Color;
pass_Normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz);
pass_Distance = abs(eyeSpace.z / eyeSpace.w); pass_Distance = abs(eyeSpace.z / eyeSpace.w);
pass_Color = color;
pass_Normal = normal;
pass_TexCoord0 = gl_MultiTexCoord0.st; pass_TexCoord0 = gl_MultiTexCoord0.st;
pass_TexCoord1 = gl_MultiTexCoord1.st; pass_TexCoord1 = gl_MultiTexCoord1.st;
pass_TexCoord2 = shadowCoord.xyz / shadowCoord.w; pass_TexCoord2 = shadowCoord.xyz / shadowCoord.w;

View File

@ -20,6 +20,8 @@
// FRAGMENT SHADER - NORMAL MODE // FRAGMENT SHADER - NORMAL MODE
#version 330 core #version 330 core
#define CONFIG_QUALITY_SHADOWS 1
uniform sampler2D uni_PrimaryTexture; uniform sampler2D uni_PrimaryTexture;
uniform sampler2D uni_SecondaryTexture; uniform sampler2D uni_SecondaryTexture;
uniform sampler2DShadow uni_ShadowTexture; uniform sampler2DShadow uni_ShadowTexture;
@ -37,11 +39,27 @@ uniform float uni_ShadowColor;
uniform bool uni_AlphaTestEnabled; uniform bool uni_AlphaTestEnabled;
uniform float uni_AlphaReference; uniform float uni_AlphaReference;
struct LightParams
{
vec4 Position;
vec4 Ambient;
vec4 Diffuse;
vec4 Specular;
};
uniform vec4 uni_AmbientColor;
uniform vec4 uni_DiffuseColor;
uniform vec4 uni_SpecularColor;
uniform int uni_LightCount;
uniform LightParams uni_Light[4];
in VertexData in VertexData
{ {
vec4 Color; vec4 Color;
vec2 TexCoord0; vec2 TexCoord0;
vec2 TexCoord1; vec2 TexCoord1;
vec3 Normal;
vec4 ShadowCoord; vec4 ShadowCoord;
vec4 LightColor; vec4 LightColor;
float Distance; float Distance;
@ -53,6 +71,53 @@ void main()
{ {
vec4 color = data.Color; vec4 color = data.Color;
if (uni_LightCount > 0)
{
vec4 ambient = vec4(0.0f);
vec4 diffuse = vec4(0.0f);
vec4 specular = vec4(0.0f);
vec3 normal = normalize(data.Normal);
for (int i = 0; i < uni_LightCount; i++)
{
vec3 lightDirection = uni_Light[i].Position.xyz;
vec3 reflectDirection = -reflect(lightDirection, normal);
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)
* uni_Light[i].Specular;
}
float shadow = 1.0f;
if (uni_ShadowTextureEnabled)
{
#ifdef CONFIG_QUALITY_SHADOWS
float offset = 0.00025f;
float value = (1.0f / 5.0f) * (texture(uni_ShadowTexture, data.ShadowCoord.xyz)
+ texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3( offset, 0.0f, 0.0f))
+ texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3(-offset, 0.0f, 0.0f))
+ texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3( 0.0f, offset, 0.0f))
+ texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3( 0.0f, -offset, 0.0f)));
shadow = mix(uni_ShadowColor, 1.0f, value);
#else
shadow = mix(uni_ShadowColor, 1.0f, texture(uni_ShadowTexture, data.ShadowCoord.xyz));
#endif
}
vec4 result = uni_AmbientColor * ambient
+ uni_DiffuseColor * diffuse * shadow
+ uni_SpecularColor * specular * shadow;
color = vec4(min(vec3(1.0f), result.rgb), 1.0f);
}
if (uni_PrimaryTextureEnabled) if (uni_PrimaryTextureEnabled)
{ {
color = color * texture(uni_PrimaryTexture, data.TexCoord0); color = color * texture(uni_PrimaryTexture, data.TexCoord0);
@ -63,11 +128,6 @@ void main()
color = color * texture(uni_SecondaryTexture, data.TexCoord1); color = color * texture(uni_SecondaryTexture, data.TexCoord1);
} }
if (uni_ShadowTextureEnabled)
{
color = color * mix(uni_ShadowColor, 1.0f, texture(uni_ShadowTexture, data.ShadowCoord.xyz));
}
if (uni_FogEnabled) if (uni_FogEnabled)
{ {
float interpolate = (data.Distance - uni_FogRange.x) / (uni_FogRange.y - uni_FogRange.x); float interpolate = (data.Distance - uni_FogRange.x) / (uni_FogRange.y - uni_FogRange.x);

View File

@ -20,24 +20,6 @@
// VERTEX SHADER - NORMAL MODE // VERTEX SHADER - NORMAL MODE
#version 330 core #version 330 core
struct LightParams
{
bool Enabled;
vec4 Position;
vec4 Ambient;
vec4 Diffuse;
vec4 Specular;
float Shininess;
vec3 Attenuation;
};
uniform vec4 uni_AmbientColor;
uniform vec4 uni_DiffuseColor;
uniform vec4 uni_SpecularColor;
uniform bool uni_LightingEnabled;
uniform LightParams uni_Light[8];
uniform mat4 uni_ProjectionMatrix; uniform mat4 uni_ProjectionMatrix;
uniform mat4 uni_ViewMatrix; uniform mat4 uni_ViewMatrix;
uniform mat4 uni_ModelMatrix; uniform mat4 uni_ModelMatrix;
@ -55,6 +37,7 @@ out VertexData
vec4 Color; vec4 Color;
vec2 TexCoord0; vec2 TexCoord0;
vec2 TexCoord1; vec2 TexCoord1;
vec3 Normal;
vec4 ShadowCoord; vec4 ShadowCoord;
vec4 LightColor; vec4 LightColor;
float Distance; float Distance;
@ -70,58 +53,7 @@ void main()
data.Color = in_Color; data.Color = in_Color;
data.TexCoord0 = in_TexCoord0; data.TexCoord0 = in_TexCoord0;
data.TexCoord1 = in_TexCoord1; data.TexCoord1 = in_TexCoord1;
data.Normal = normalize((uni_NormalMatrix * vec4(in_Normal, 0.0f)).xyz);
data.ShadowCoord = vec4(shadowCoord.xyz / shadowCoord.w, 1.0f); data.ShadowCoord = vec4(shadowCoord.xyz / shadowCoord.w, 1.0f);
data.Distance = abs(eyeSpace.z); data.Distance = abs(eyeSpace.z);
vec4 color = in_Color;
if (uni_LightingEnabled)
{
vec4 ambient = vec4(0.0f);
vec4 diffuse = vec4(0.0f);
vec4 specular = vec4(0.0f);
vec3 normal = normalize((uni_NormalMatrix * vec4(in_Normal, 0.0f)).xyz);
for(int i=0; i<8; i++)
{
if(uni_Light[i].Enabled)
{
vec3 lightDirection = vec3(0.0f);
float atten;
// Directional light
if(uni_Light[i].Position[3] == 0.0f)
{
lightDirection = uni_Light[i].Position.xyz;
atten = 1.0f;
}
// Point light
else
{
vec3 lightDirection = normalize(uni_Light[i].Position.xyz - position.xyz);
float dist = distance(uni_Light[i].Position.xyz, position.xyz);
atten = 1.0f / (uni_Light[i].Attenuation.x
+ uni_Light[i].Attenuation.y * dist
+ uni_Light[i].Attenuation.z * dist * dist);
}
vec3 reflectDirection = -reflect(lightDirection, normal);
ambient += uni_Light[i].Ambient;
diffuse += atten * clamp(dot(normal, lightDirection), 0.0f, 1.0f) * uni_Light[i].Diffuse;
specular += atten * clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f) * uni_Light[i].Specular;
}
}
vec4 result = uni_AmbientColor * ambient
+ uni_DiffuseColor * diffuse
+ uni_SpecularColor * specular;
color.rgb = min(vec3(1.0f), result.rgb);
color.a = 1.0f; //min(1.0f, 1.0f);
data.Color = color;
}
} }

View File

@ -467,6 +467,8 @@ ObjectType CLevelParserParam::ToObjectType(std::string value)
if (value == "Barrier1" ) return OBJECT_BARRIER1; if (value == "Barrier1" ) return OBJECT_BARRIER1;
if (value == "Barrier2" ) return OBJECT_BARRIER2; if (value == "Barrier2" ) return OBJECT_BARRIER2;
if (value == "Barrier3" ) return OBJECT_BARRIER3; if (value == "Barrier3" ) return OBJECT_BARRIER3;
if (value == "Barricade0" ) return OBJECT_BARRICADE0;
if (value == "Barricade1" ) return OBJECT_BARRICADE1;
if (value == "Teen0" ) return OBJECT_TEEN0; if (value == "Teen0" ) return OBJECT_TEEN0;
if (value == "Teen1" ) return OBJECT_TEEN1; if (value == "Teen1" ) return OBJECT_TEEN1;
if (value == "Teen2" ) return OBJECT_TEEN2; if (value == "Teen2" ) return OBJECT_TEEN2;
@ -662,6 +664,8 @@ const std::string CLevelParserParam::FromObjectType(ObjectType value)
if (value == OBJECT_BARRIER1 ) return "Barrier1"; if (value == OBJECT_BARRIER1 ) return "Barrier1";
if (value == OBJECT_BARRIER2 ) return "Barrier2"; if (value == OBJECT_BARRIER2 ) return "Barrier2";
if (value == OBJECT_BARRIER3 ) return "Barrier3"; if (value == OBJECT_BARRIER3 ) return "Barrier3";
if (value == OBJECT_BARRICADE0 ) return "Barricade0";
if (value == OBJECT_BARRICADE1 ) return "Barricade1";
if (value == OBJECT_TEEN0 ) return "Teen0"; if (value == OBJECT_TEEN0 ) return "Teen0";
if (value == OBJECT_TEEN1 ) return "Teen1"; if (value == OBJECT_TEEN1 ) return "Teen1";
if (value == OBJECT_TEEN2 ) return "Teen2"; if (value == OBJECT_TEEN2 ) return "Teen2";

View File

@ -133,7 +133,7 @@ std::string CPlayerProfile::GetLastName()
{ {
std::string name; std::string name;
if(!GetConfigFile().GetStringProperty("Gamer", "LastName", name)) if(!GetConfigFile().GetStringProperty("Gamer", "LastName", name) || name.empty())
GetResource(RES_TEXT, RT_NAME_DEFAULT, name); GetResource(RES_TEXT, RT_NAME_DEFAULT, name);
return name; return name;

View File

@ -55,6 +55,7 @@
#include "level/mainmovie.h" #include "level/mainmovie.h"
#include "level/player_profile.h" #include "level/player_profile.h"
#include "level/scene_conditions.h" #include "level/scene_conditions.h"
#include "level/scoreboard.h"
#include "level/parser/parser.h" #include "level/parser/parser.h"
@ -202,8 +203,8 @@ CRobotMain::CRobotMain()
m_editLock = false; m_editLock = false;
m_editFull = false; m_editFull = false;
m_hilite = false; m_hilite = false;
m_selectInsect = false; m_cheatSelectInsect = false;
m_showSoluce = false; m_cheatShowSoluce = false;
m_codeBattleInit = false; m_codeBattleInit = false;
m_codeBattleStarted = false; m_codeBattleStarted = false;
@ -211,14 +212,14 @@ CRobotMain::CRobotMain()
m_teamNames.clear(); m_teamNames.clear();
#if DEV_BUILD #if DEV_BUILD
m_showAll = true; // for development m_cheatAllMission = true; // for development
#else #else
m_showAll = false; m_cheatAllMission = false;
#endif #endif
m_cheatRadar = false; m_cheatRadar = false;
m_fixScene = false; m_fixScene = false;
m_trainerPilot = false; m_cheatTrainerPilot = false;
m_friendAim = false; m_friendAim = false;
m_resetCreate = false; m_resetCreate = false;
m_shortCut = true; m_shortCut = true;
@ -451,7 +452,7 @@ void CRobotMain::ChangePhase(Phase phase)
m_lightning->Flush(); m_lightning->Flush();
m_planet->Flush(); m_planet->Flush();
m_interface->Flush(); m_interface->Flush();
FlushNewScriptName(); m_newScriptName.clear();
m_sound->SetListener(Math::Vector(0.0f, 0.0f, 0.0f), Math::Vector(0.0f, 0.0f, 1.0f)); m_sound->SetListener(Math::Vector(0.0f, 0.0f, 0.0f), Math::Vector(0.0f, 0.0f, 1.0f));
m_sound->StopAll(); m_sound->StopAll();
m_camera->SetType(Gfx::CAM_TYPE_NULL); m_camera->SetType(Gfx::CAM_TYPE_NULL);
@ -763,6 +764,7 @@ bool CRobotMain::ProcessEvent(Event &event)
m_interface->SetFocus(pe); m_interface->SetFocus(pe);
if (m_phase == PHASE_SIMUL) m_cmdEditPause = m_pause->ActivatePause(PAUSE_ENGINE); if (m_phase == PHASE_SIMUL) m_cmdEditPause = m_pause->ActivatePause(PAUSE_ENGINE);
m_cmdEdit = true; m_cmdEdit = true;
m_commandHistoryIndex = -1; // no element selected in command history
} }
return false; return false;
} }
@ -777,6 +779,28 @@ bool CRobotMain::ProcessEvent(Event &event)
} }
} }
// Browse forward command history with UP key
if (event.type == EVENT_KEY_DOWN &&
event.GetData<KeyEventData>()->key == KEY(UP) && m_cmdEdit)
{
Ui::CEdit* pe = static_cast<Ui::CEdit*>(m_interface->SearchControl(EVENT_CMD));
if (pe == nullptr) return false;
std::string cmd = GetNextFromCommandHistory();
if (!cmd.empty()) pe->SetText(cmd);
return false;
}
// Browse backward command history with DOWN key
if (event.type == EVENT_KEY_DOWN &&
event.GetData<KeyEventData>()->key == KEY(DOWN) && m_cmdEdit)
{
Ui::CEdit* pe = static_cast<Ui::CEdit*>(m_interface->SearchControl(EVENT_CMD));
if (pe == nullptr) return false;
std::string cmd = GetPreviousFromCommandHistory();
if (!cmd.empty()) pe->SetText(cmd);
return false;
}
if (event.type == EVENT_KEY_DOWN && if (event.type == EVENT_KEY_DOWN &&
event.GetData<KeyEventData>()->key == KEY(RETURN) && m_cmdEdit) event.GetData<KeyEventData>()->key == KEY(RETURN) && m_cmdEdit)
{ {
@ -793,6 +817,7 @@ bool CRobotMain::ProcessEvent(Event &event)
m_cmdEditPause = nullptr; m_cmdEditPause = nullptr;
} }
ExecuteCmd(cmd); ExecuteCmd(cmd);
PushToCommandHistory(cmd);
m_cmdEdit = false; m_cmdEdit = false;
return false; return false;
} }
@ -922,7 +947,7 @@ bool CRobotMain::ProcessEvent(Event &event)
} }
if (data->slot == INPUT_SLOT_HUMAN) if (data->slot == INPUT_SLOT_HUMAN)
{ {
SelectHuman(); SelectObject(SearchHuman());
} }
if (data->slot == INPUT_SLOT_NEXT && ((event.kmodState & KEY_MOD(CTRL)) != 0)) if (data->slot == INPUT_SLOT_NEXT && ((event.kmodState & KEY_MOD(CTRL)) != 0))
{ {
@ -1159,7 +1184,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
if (cmd == "trainerpilot") if (cmd == "trainerpilot")
{ {
m_trainerPilot = !m_trainerPilot; m_cheatTrainerPilot = !m_cheatTrainerPilot;
return; return;
} }
@ -1410,20 +1435,20 @@ void CRobotMain::ExecuteCmd(const std::string& cmd)
if (cmd == "selectinsect") if (cmd == "selectinsect")
{ {
m_selectInsect = !m_selectInsect; m_cheatSelectInsect = !m_cheatSelectInsect;
return; return;
} }
if (cmd == "showsoluce") if (cmd == "showsoluce")
{ {
m_showSoluce = !m_showSoluce; m_cheatShowSoluce = !m_cheatShowSoluce;
m_ui->ShowSoluceUpdate(); m_ui->ShowSoluceUpdate();
return; return;
} }
if (cmd == "allmission") if (cmd == "allmission")
{ {
m_showAll = !m_showAll; m_cheatAllMission = !m_cheatAllMission;
m_ui->AllMissionUpdate(); m_ui->AllMissionUpdate();
return; return;
} }
@ -1763,20 +1788,17 @@ void CRobotMain::StopDisplayVisit()
//! Updates all the shortcuts
void CRobotMain::UpdateShortcuts() void CRobotMain::UpdateShortcuts()
{ {
m_short->UpdateShortcuts(); m_short->UpdateShortcuts();
} }
//! Returns the object that default was select after the creation of a scene
CObject* CRobotMain::GetSelectObject() CObject* CRobotMain::GetSelectObject()
{ {
if (m_selectObject != nullptr) return m_selectObject; if (m_selectObject != nullptr) return m_selectObject;
return SearchHuman(); return SearchHuman();
} }
//! Deselects everything, and returns the object that was selected
CObject* CRobotMain::DeselectAll() CObject* CRobotMain::DeselectAll()
{ {
CObject* prev = nullptr; CObject* prev = nullptr;
@ -1833,17 +1855,8 @@ void CRobotMain::SelectOneObject(CObject* obj, bool displayError)
{ {
m_camera->SetType(Gfx::CAM_TYPE_BACK); m_camera->SetType(Gfx::CAM_TYPE_BACK);
} }
CObject* toto = SearchToto();
if (toto != nullptr)
{
assert(toto->Implements(ObjectInterfaceType::Movable));
CMotionToto* mt = static_cast<CMotionToto*>(dynamic_cast<CMovableObject*>(toto)->GetMotion());
mt->SetLinkType(type);
}
} }
//! Selects the object aimed by the mouse
bool CRobotMain::SelectObject(CObject* obj, bool displayError) bool CRobotMain::SelectObject(CObject* obj, bool displayError)
{ {
if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT) if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT)
@ -1851,7 +1864,8 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError)
if (m_movieLock || m_editLock) return false; if (m_movieLock || m_editLock) return false;
if (m_movie->IsExist()) return false; if (m_movie->IsExist()) return false;
if (obj != nullptr && !IsSelectable(obj)) return false; if (obj != nullptr &&
(!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast<CControllableObject*>(obj)->GetSelectable() || m_cheatSelectInsect))) return false;
if (m_missionType == MISSION_CODE_BATTLE && m_codeBattleStarted && m_codeBattleSpectator) if (m_missionType == MISSION_CODE_BATTLE && m_codeBattleStarted && m_codeBattleSpectator)
{ {
@ -1882,7 +1896,6 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError)
return true; return true;
} }
//! Deselects the selected object
bool CRobotMain::DeselectObject() bool CRobotMain::DeselectObject()
{ {
DeselectAll(); DeselectAll();
@ -1918,49 +1931,11 @@ void CRobotMain::DeleteAllObjects()
m_objMan->DeleteAllObjects(); m_objMan->DeleteAllObjects();
} }
//! Selects the human
void CRobotMain::SelectHuman()
{
SelectObject(SearchHuman());
}
//! Returns the object human
CObject* CRobotMain::SearchHuman() CObject* CRobotMain::SearchHuman()
{ {
return m_objMan->FindNearest(nullptr, OBJECT_HUMAN); return m_objMan->FindNearest(nullptr, OBJECT_HUMAN);
} }
//! Returns the object toto
CObject* CRobotMain::SearchToto()
{
return m_objMan->FindNearest(nullptr, OBJECT_TOTO);
}
//! Returns the nearest selectable object from a given position
CObject* CRobotMain::SearchNearest(Math::Vector pos, CObject* exclu)
{
float min = 100000.0f;
CObject* best = nullptr;
for (CObject* obj : m_objMan->GetAllObjects())
{
if (obj == exclu) continue;
if (!IsSelectable(obj)) continue;
ObjectType type = obj->GetType();
if (type == OBJECT_TOTO) continue;
Math::Vector oPos = obj->GetPosition();
float dist = Math::DistanceProjected(oPos, pos);
if (dist < min)
{
min = dist;
best = obj;
}
}
return best;
}
//! Returns the selected object
CObject* CRobotMain::GetSelect() CObject* CRobotMain::GetSelect()
{ {
for (CObject* obj : m_objMan->GetAllObjects()) for (CObject* obj : m_objMan->GetAllObjects())
@ -2019,30 +1994,6 @@ CObject* CRobotMain::DetectObject(Math::Point pos)
return nullptr; return nullptr;
} }
//! Indicates whether an object is selectable
// TODO: Refactor this, calling CControllableObject::GetSelectable should always be enough
bool CRobotMain::IsSelectable(CObject* obj)
{
if (obj->GetType() == OBJECT_TOTO) return true;
if (!obj->Implements(ObjectInterfaceType::Controllable)) return false;
if (!m_selectInsect)
{
// TODO: Some function in CControllableObject
if ( obj->GetType() == OBJECT_MOTHER ||
obj->GetType() == OBJECT_ANT ||
obj->GetType() == OBJECT_SPIDER ||
obj->GetType() == OBJECT_BEE ||
obj->GetType() == OBJECT_WORM ||
obj->GetType() == OBJECT_MOBILEtg )
{
return false;
}
}
return dynamic_cast<CControllableObject*>(obj)->GetSelectable();
}
//! Deletes the selected object //! Deletes the selected object
bool CRobotMain::DestroySelectedObject() bool CRobotMain::DestroySelectedObject()
@ -2136,10 +2087,13 @@ void CRobotMain::HiliteObject(Math::Point pos)
} }
} }
if (IsSelectable(obj)) if (obj->Implements(ObjectInterfaceType::Controllable) && (dynamic_cast<CControllableObject*>(obj)->GetSelectable() || m_cheatSelectInsect))
{ {
assert(obj->Implements(ObjectInterfaceType::Controllable)); if (dynamic_cast<CControllableObject*>(obj)->GetSelectable())
dynamic_cast<CControllableObject*>(obj)->SetHighlight(true); {
// Don't highlight objects that would not be selectable without selectinsect
dynamic_cast<CControllableObject*>(obj)->SetHighlight(true);
}
m_map->SetHighlight(obj); m_map->SetHighlight(obj);
m_short->SetHighlight(obj); m_short->SetHighlight(obj);
m_hilite = true; m_hilite = true;
@ -2565,7 +2519,7 @@ bool CRobotMain::EventFrame(const Event &event)
if (m_phase == PHASE_SIMUL) if (m_phase == PHASE_SIMUL)
{ {
if (!m_editLock) if (!m_editLock && !m_engine->GetPause())
{ {
CheckEndMission(true); CheckEndMission(true);
UpdateAudio(true); UpdateAudio(true);
@ -2589,31 +2543,34 @@ bool CRobotMain::EventFrame(const Event &event)
if (m_lostDelay <= 0.0f) if (m_lostDelay <= 0.0f)
{ {
if (m_movieLock) if (m_movieLock)
m_winDelay = 1.0f; m_lostDelay = 1.0f;
else else
m_eventQueue->AddEvent(Event(EVENT_LOST)); m_eventQueue->AddEvent(Event(EVENT_LOST));
} }
} }
}
if (GetMissionType() == MISSION_CODE_BATTLE) if (GetMissionType() == MISSION_CODE_BATTLE)
{
if (!m_codeBattleInit)
{ {
// NOTE: It's important to do this AFTER the first update event finished processing if (!m_codeBattleInit)
// because otherwise all robot parts are misplaced {
m_userPause = m_pause->ActivatePause(PAUSE_ENGINE); // NOTE: It's important to do this AFTER the first update event finished processing
m_codeBattleInit = true; // Will start on resume // because otherwise all robot parts are misplaced
} m_userPause = m_pause->ActivatePause(PAUSE_ENGINE);
m_codeBattleInit = true; // Will start on resume
}
if (!m_codeBattleStarted && m_userPause == nullptr) if (!m_codeBattleStarted && m_userPause == nullptr)
{ {
m_codeBattleStarted = true; m_codeBattleStarted = true;
CreateCodeBattleInterface(); ApplyCodeBattleInterface();
CreateCodeBattleInterface();
SetCodeBattleSpectatorMode(true); SetCodeBattleSpectatorMode(true);
m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE)); m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE));
}
UpdateCodeBattleInterface();
} }
} }
@ -2672,7 +2629,6 @@ bool CRobotMain::EventObject(const Event &event)
//! Load the scene for the character
void CRobotMain::ScenePerso() void CRobotMain::ScenePerso()
{ {
DeleteAllObjects(); // removes all the current 3D Scene DeleteAllObjects(); // removes all the current 3D Scene
@ -2743,6 +2699,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
m_endTakeResearch = 0; m_endTakeResearch = 0;
m_endTakeWinDelay = 2.0f; m_endTakeWinDelay = 2.0f;
m_endTakeLostDelay = 2.0f; m_endTakeLostDelay = 2.0f;
m_teamFinished.clear();
m_scoreboard.reset();
m_globalMagnifyDamage = 1.0f; m_globalMagnifyDamage = 1.0f;
m_obligatoryTokens.clear(); m_obligatoryTokens.clear();
m_mapShow = true; m_mapShow = true;
@ -3365,6 +3323,9 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
assert(m_controller->Implements(ObjectInterfaceType::Programmable)); assert(m_controller->Implements(ObjectInterfaceType::Programmable));
assert(m_controller->Implements(ObjectInterfaceType::ProgramStorage)); assert(m_controller->Implements(ObjectInterfaceType::ProgramStorage));
assert(m_controller->Implements(ObjectInterfaceType::Old));
dynamic_cast<COldObject*>(m_controller)->SetCheckToken(false);
if (line->GetParam("script")->IsDefined()) if (line->GetParam("script")->IsDefined())
{ {
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(m_controller); CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(m_controller);
@ -3600,6 +3561,34 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
continue; continue;
} }
if (line->GetCommand() == "Scoreboard" && !resetObject)
{
if (line->GetParam("enable")->AsBool(false))
{
// Create the scoreboard
m_scoreboard = MakeUnique<CScoreboard>();
}
continue;
}
if (line->GetCommand() == "ScoreboardKillRule" && !resetObject)
{
if (!m_scoreboard)
throw CLevelParserException("ScoreboardKillRule encountered but scoreboard is not enabled");
auto rule = MakeUnique<CScoreboard::CScoreboardKillRule>();
rule->Read(line.get());
m_scoreboard->AddKillRule(std::move(rule));
continue;
}
if (line->GetCommand() == "ScoreboardEndTakeRule" && !resetObject)
{
if (!m_scoreboard)
throw CLevelParserException("ScoreboardEndTakeRule encountered but scoreboard is not enabled");
auto rule = MakeUnique<CScoreboard::CScoreboardEndTakeRule>();
rule->Read(line.get());
m_scoreboard->AddEndTakeRule(std::move(rule));
continue;
}
if (line->GetCommand() == "ObligatoryToken" && !resetObject) if (line->GetCommand() == "ObligatoryToken" && !resetObject)
{ {
std::string token = line->GetParam("text")->AsString(); std::string token = line->GetParam("text")->AsString();
@ -3649,7 +3638,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
if (line->GetCommand() == "NewScript" && !resetObject) if (line->GetCommand() == "NewScript" && !resetObject)
{ {
AddNewScriptName(line->GetParam("type")->AsObjectType(OBJECT_NULL), const_cast<char*>(line->GetParam("name")->AsPath("ai").c_str())); m_newScriptName.push_back(NewScriptName(line->GetParam("type")->AsObjectType(OBJECT_NULL), const_cast<char*>(line->GetParam("name")->AsPath("ai").c_str())));
continue; continue;
} }
@ -3970,15 +3959,17 @@ void CRobotMain::ChangeColor()
} }
//! Calculates the distance to the nearest object //! Calculates the distance to the nearest object
float CRobotMain::SearchNearestObject(Math::Vector center, CObject *exclu) namespace
{
float SearchNearestObject(CObjectManager* objMan, Math::Vector center, CObject* exclu)
{ {
float min = 100000.0f; float min = 100000.0f;
for (CObject* obj : m_objMan->GetAllObjects()) for (CObject* obj : objMan->GetAllObjects())
{ {
if (!obj->GetDetectable()) continue; // inactive? if (!obj->GetDetectable()) continue; // inactive?
if (IsObjectBeingTransported(obj)) continue; if (IsObjectBeingTransported(obj)) continue;
if (obj == exclu) continue; if (obj == exclu) continue;
ObjectType type = obj->GetType(); ObjectType type = obj->GetType();
@ -3988,35 +3979,36 @@ float CRobotMain::SearchNearestObject(Math::Vector center, CObject *exclu)
if (oPos.x != center.x || if (oPos.x != center.x ||
oPos.z != center.z) oPos.z != center.z)
{ {
float dist = Math::Distance(center, oPos)-80.0f; float dist = Math::Distance(center, oPos) - 80.0f;
if (dist < 0.0f) dist = 0.0f; if (dist < 0.0f) dist = 0.0f;
min = Math::Min(min, dist); min = Math::Min(min, dist);
continue; continue;
} }
} }
if (type == OBJECT_STATION || if (type == OBJECT_STATION ||
type == OBJECT_REPAIR || type == OBJECT_REPAIR ||
type == OBJECT_DESTROYER) type == OBJECT_DESTROYER)
{ {
Math::Vector oPos = obj->GetPosition(); Math::Vector oPos = obj->GetPosition();
float dist = Math::Distance(center, oPos)-8.0f; float dist = Math::Distance(center, oPos) - 8.0f;
if (dist < 0.0f) dist = 0.0f; if (dist < 0.0f) dist = 0.0f;
min = Math::Min(min, dist); min = Math::Min(min, dist);
} }
for (const auto& crashSphere : obj->GetAllCrashSpheres()) for (const auto &crashSphere : obj->GetAllCrashSpheres())
{ {
Math::Vector oPos = crashSphere.sphere.pos; Math::Vector oPos = crashSphere.sphere.pos;
float oRadius = crashSphere.sphere.radius; float oRadius = crashSphere.sphere.radius;
float dist = Math::Distance(center, oPos)-oRadius; float dist = Math::Distance(center, oPos) - oRadius;
if (dist < 0.0f) dist = 0.0f; if (dist < 0.0f) dist = 0.0f;
min = Math::Min(min, dist); min = Math::Min(min, dist);
} }
} }
return min; return min;
} }
}
//! Calculates a free space //! Calculates a free space
bool CRobotMain::FreeSpace(Math::Vector &center, float minRadius, float maxRadius, bool CRobotMain::FreeSpace(Math::Vector &center, float minRadius, float maxRadius,
@ -4038,7 +4030,7 @@ bool CRobotMain::FreeSpace(Math::Vector &center, float minRadius, float maxRadiu
pos.z = p.y; pos.z = p.y;
pos.y = 0.0f; pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true); m_terrain->AdjustToFloor(pos, true);
float dist = SearchNearestObject(pos, exclu); float dist = SearchNearestObject(m_objMan.get(), pos, exclu);
if (dist >= space) if (dist >= space)
{ {
float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f); float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f);
@ -4067,7 +4059,7 @@ bool CRobotMain::FreeSpace(Math::Vector &center, float minRadius, float maxRadiu
pos.z = p.y; pos.z = p.y;
pos.y = 0.0f; pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true); m_terrain->AdjustToFloor(pos, true);
float dist = SearchNearestObject(pos, exclu); float dist = SearchNearestObject(m_objMan.get(), pos, exclu);
if (dist >= space) if (dist >= space)
{ {
float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f); float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f);
@ -4103,7 +4095,7 @@ bool CRobotMain::FlatFreeSpace(Math::Vector &center, float minFlat, float minRad
pos.z = p.y; pos.z = p.y;
pos.y = 0.0f; pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true); m_terrain->AdjustToFloor(pos, true);
float dist = SearchNearestObject(pos, exclu); float dist = SearchNearestObject(m_objMan.get(), pos, exclu);
if (dist >= space) if (dist >= space)
{ {
float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f); float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f);
@ -4136,7 +4128,7 @@ bool CRobotMain::FlatFreeSpace(Math::Vector &center, float minFlat, float minRad
pos.z = p.y; pos.z = p.y;
pos.y = 0.0f; pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true); m_terrain->AdjustToFloor(pos, true);
float dist = SearchNearestObject(pos, exclu); float dist = SearchNearestObject(m_objMan.get(), pos, exclu);
if (dist >= space) if (dist >= space)
{ {
float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f); float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f);
@ -4160,7 +4152,7 @@ bool CRobotMain::FlatFreeSpace(Math::Vector &center, float minFlat, float minRad
float CRobotMain::GetFlatZoneRadius(Math::Vector center, float maxRadius, float CRobotMain::GetFlatZoneRadius(Math::Vector center, float maxRadius,
CObject *exclu) CObject *exclu)
{ {
float dist = SearchNearestObject(center, exclu); float dist = SearchNearestObject(m_objMan.get(), center, exclu);
if (dist == 0.0f) return 0.0f; if (dist == 0.0f) return 0.0f;
if (dist < maxRadius) if (dist < maxRadius)
maxRadius = dist; maxRadius = dist;
@ -4432,36 +4424,19 @@ bool CRobotMain::ReadFileStack(CObject *obj, FILE *file, int objRank)
return programmable->ReadStack(file); return programmable->ReadStack(file);
} }
std::vector<std::string> CRobotMain::GetNewScriptNames(ObjectType type)
//! Empty the list
void CRobotMain::FlushNewScriptName()
{ {
m_newScriptName.clear(); std::vector<std::string> names;
} for (const auto& newScript : m_newScriptName)
//! Adds a script name
void CRobotMain::AddNewScriptName(ObjectType type, const std::string& name)
{
NewScriptName newscript;
newscript.type = type;
newscript.name = name;
m_newScriptName.push_back(newscript);
}
//! Seeks a script name for a given type
std::string CRobotMain::GetNewScriptName(ObjectType type, int rank)
{
for (unsigned int i = 0; i < m_newScriptName.size(); i++)
{ {
if (m_newScriptName[i].type == type || if (newScript.type == type ||
m_newScriptName[i].type == OBJECT_NULL ) newScript.type == OBJECT_NULL )
{ {
if (rank == 0) return m_newScriptName[i].name; names.push_back(newScript.name);
else rank --;
} }
} }
return ""; return names;
} }
@ -4960,56 +4935,81 @@ Error CRobotMain::ProcessEndMissionTakeForGroup(std::vector<CSceneEndCondition*>
Error CRobotMain::ProcessEndMissionTake() Error CRobotMain::ProcessEndMissionTake()
{ {
// Sort end conditions by teams // Sort end conditions by teams
std::map<int, std::vector<CSceneEndCondition*>> teams; std::map<int, std::vector<CSceneEndCondition*>> teamsEndTake;
for (std::unique_ptr<CSceneEndCondition>& endTake : m_endTake) for (std::unique_ptr<CSceneEndCondition>& endTake : m_endTake)
teams[endTake->winTeam].push_back(endTake.get()); teamsEndTake[endTake->winTeam].push_back(endTake.get());
int teamCount = 0; // This is just a smart way to check if we have any map values other than 0 defined
bool usesTeamConditions = false; bool usesTeamConditions = teamsEndTake.size() > teamsEndTake.count(0);
for (auto it : teams)
{
int team = it.first;
if (team == 0) continue;
usesTeamConditions = true;
if (!m_objMan->TeamExists(team)) continue;
teamCount++;
}
if (!usesTeamConditions) if (!usesTeamConditions)
{ {
m_missionResult = ProcessEndMissionTakeForGroup(teams[0]); m_missionResult = ProcessEndMissionTakeForGroup(teamsEndTake[0]);
} }
else else
{ {
// Special handling for teams // Special handling for teams
m_missionResult = ERR_MISSION_NOTERM; m_missionResult = ERR_MISSION_NOTERM;
if (teamCount == 0) if (GetAllActiveTeams().empty())
{ {
GetLogger()->Info("All teams died, mission ended with failure\n"); GetLogger()->Info("All teams died, mission ended\n");
m_missionResult = INFO_LOST; if (m_scoreboard)
{
std::string title, text, details_line;
GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS, title);
GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_TEXT, text);
GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_LINE, details_line);
std::string details = "";
for (int team : GetAllTeams())
{
if (!details.empty())
details += ", ";
details += StrUtils::Format(details_line.c_str(), GetTeamName(team).c_str(), m_scoreboard->GetScore(team));
}
m_ui->GetDialog()->StartInformation(
title,
text,
details,
false, true,
[&]() {
ChangePhase(PHASE_WIN);
}
);
m_endTakeWinDelay = 0.0f;
m_missionResult = ERR_OK;
}
else
{
m_missionResult = INFO_LOST;
}
} }
else else
{ {
for (auto it : teams) for (auto it : teamsEndTake)
{ {
int team = it.first; int team = it.first;
if (team == 0) continue; if (team == 0) continue;
if (!m_objMan->TeamExists(team)) continue; if (m_teamFinished[team]) continue;
Error result = ProcessEndMissionTakeForGroup(it.second); Error result = ProcessEndMissionTakeForGroup(it.second);
if (result == INFO_LOST || result == INFO_LOSTq) if (result == INFO_LOST || result == INFO_LOSTq)
{ {
GetLogger()->Info("Team %d lost\n", team); GetLogger()->Info("Team %d lost\n", team);
m_displayText->DisplayText(("<<< Team "+boost::lexical_cast<std::string>(team)+" lost! >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_ERROR); std::string text;
GetResource(RES_ERR, INFO_TEAM_DEAD, text);
text = StrUtils::Format(text.c_str(), GetTeamName(team).c_str());
m_displayText->DisplayText(text.c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_ERROR);
m_displayText->SetEnable(false); // To prevent "bot destroyed" messages m_displayText->SetEnable(false); // To prevent "bot destroyed" messages
m_objMan->DestroyTeam(team); m_objMan->DestroyTeam(team);
m_displayText->SetEnable(true); m_displayText->SetEnable(true);
m_teamFinished[team] = true;
} }
else if (result == ERR_OK) else if (result == ERR_OK)
{ {
if (m_winDelay == 0.0f) /*if (m_winDelay == 0.0f)
{ {
GetLogger()->Info("Team %d won\n", team); GetLogger()->Info("Team %d won\n", team);
@ -5025,7 +5025,16 @@ Error CRobotMain::ProcessEndMissionTake()
m_displayText->SetEnable(false); m_displayText->SetEnable(false);
} }
m_missionResult = ERR_OK; m_missionResult = ERR_OK;
return ERR_OK; return ERR_OK;*/
GetLogger()->Info("Team %d finished\n", team);
std::string text;
GetResource(RES_ERR, INFO_TEAM_FINISH, text);
text = StrUtils::Format(text.c_str(), GetTeamName(team).c_str());
m_displayText->DisplayText(text.c_str(), Math::Vector(0.0f,0.0f,0.0f));
if (m_scoreboard)
m_scoreboard->ProcessEndTake(team);
m_objMan->DestroyTeam(team, DestructionType::Win);
m_teamFinished[team] = true;
} }
} }
} }
@ -5054,7 +5063,6 @@ Error CRobotMain::CheckEndMission(bool frame)
Error result = ProcessEndMissionTake(); Error result = ProcessEndMissionTake();
if (result != ERR_MISSION_NOTERM) return result; if (result != ERR_MISSION_NOTERM) return result;
} }
// Take action depending on m_missionResult // Take action depending on m_missionResult
if (m_missionResult == INFO_LOSTq) if (m_missionResult == INFO_LOSTq)
@ -5135,7 +5143,7 @@ const std::map<std::string, MinMax>& CRobotMain::GetObligatoryTokenList()
//! Indicates whether it is possible to control a driving robot //! Indicates whether it is possible to control a driving robot
bool CRobotMain::GetTrainerPilot() bool CRobotMain::GetTrainerPilot()
{ {
return m_trainerPilot; return m_cheatTrainerPilot;
} }
//! Indicates whether the scene is fixed, without interaction //! Indicates whether the scene is fixed, without interaction
@ -5158,7 +5166,7 @@ const std::string& CRobotMain::GetScriptFile()
bool CRobotMain::GetShowSoluce() bool CRobotMain::GetShowSoluce()
{ {
return m_showSoluce; return m_cheatShowSoluce;
} }
bool CRobotMain::GetSceneSoluce() bool CRobotMain::GetSceneSoluce()
@ -5169,7 +5177,7 @@ bool CRobotMain::GetSceneSoluce()
bool CRobotMain::GetShowAll() bool CRobotMain::GetShowAll()
{ {
return m_showAll; return m_cheatAllMission;
} }
bool CRobotMain::GetRadar() bool CRobotMain::GetRadar()
@ -5293,7 +5301,6 @@ void CRobotMain::UpdateSpeedLabel()
} }
//! Creates interface shortcuts to the units
bool CRobotMain::CreateShortcuts() bool CRobotMain::CreateShortcuts()
{ {
if (m_phase != PHASE_SIMUL) return false; if (m_phase != PHASE_SIMUL) return false;
@ -5638,7 +5645,7 @@ bool CRobotMain::IsBuildingEnabled(ObjectType type)
if(type == OBJECT_PARA) return IsBuildingEnabled(BUILD_PARA); if(type == OBJECT_PARA) return IsBuildingEnabled(BUILD_PARA);
if(type == OBJECT_DESTROYER) return IsBuildingEnabled(BUILD_DESTROYER); if(type == OBJECT_DESTROYER) return IsBuildingEnabled(BUILD_DESTROYER);
return true; return false;
} }
bool CRobotMain::IsResearchEnabled(ResearchType type) bool CRobotMain::IsResearchEnabled(ResearchType type)
@ -5683,11 +5690,6 @@ Error CRobotMain::CanBuildError(ObjectType type, int team)
return ERR_OK; return ERR_OK;
} }
bool CRobotMain::CanBuild(ObjectType type, int team)
{
return CanBuildError(type, team) == ERR_OK;
}
Error CRobotMain::CanFactoryError(ObjectType type, int team) Error CRobotMain::CanFactoryError(ObjectType type, int team)
{ {
ToolType tool = GetToolFromObject(type); ToolType tool = GetToolFromObject(type);
@ -5711,11 +5713,6 @@ Error CRobotMain::CanFactoryError(ObjectType type, int team)
return ERR_OK; return ERR_OK;
} }
bool CRobotMain::CanFactory(ObjectType type, int team)
{
return CanFactoryError(type, team) == ERR_OK;
}
void CRobotMain::PushToSelectionHistory(CObject* obj) void CRobotMain::PushToSelectionHistory(CObject* obj)
{ {
if (!m_selectionHistory.empty() && m_selectionHistory.back() == obj) if (!m_selectionHistory.empty() && m_selectionHistory.back() == obj)
@ -5791,12 +5788,16 @@ void CRobotMain::StartDetectEffect(COldObject* object, CObject* target)
void CRobotMain::CreateCodeBattleInterface() void CRobotMain::CreateCodeBattleInterface()
{ {
if(m_phase == PHASE_SIMUL) if (m_phase == PHASE_SIMUL)
{ {
Math::Point pos, ddim; Math::Point pos, ddim;
int numTeams = m_scoreboard ? GetAllTeams().size() : 0;
assert(numTeams < EVENT_SCOREBOARD_MAX-EVENT_SCOREBOARD+1);
float textHeight = m_engine->GetText()->GetHeight(Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL);
ddim.x = 100.0f/640.0f; ddim.x = 100.0f/640.0f;
ddim.y = 100.0f/480.0f; ddim.y = 100.0f/480.0f + numTeams * textHeight;
pos.x = 540.0f/640.0f; pos.x = 540.0f/640.0f;
pos.y = 100.0f/480.0f; pos.y = 100.0f/480.0f;
Ui::CWindow* pw = m_interface->CreateWindows(pos, ddim, 3, EVENT_WINDOW6); Ui::CWindow* pw = m_interface->CreateWindows(pos, ddim, 3, EVENT_WINDOW6);
@ -5804,8 +5805,10 @@ void CRobotMain::CreateCodeBattleInterface()
ddim.x = 100.0f/640.0f; ddim.x = 100.0f/640.0f;
ddim.y = 16.0f/480.0f; ddim.y = 16.0f/480.0f;
pos.x = 540.0f/640.0f; pos.x = 540.0f/640.0f;
pos.y = 178.0f/480.0f; pos.y = 178.0f/480.0f + numTeams * textHeight;
pw->CreateLabel(pos, ddim, 0, EVENT_LABEL0, "Code battle"); std::string text;
GetResource(RES_EVENT, EVENT_LABEL_CODE_BATTLE, text);
pw->CreateLabel(pos, ddim, 0, EVENT_LABEL_CODE_BATTLE, text);
float titleBarSize = (11.0f/64.0f); // this is from the texture float titleBarSize = (11.0f/64.0f); // this is from the texture
ddim.x = 80.0f/640.0f; ddim.x = 80.0f/640.0f;
@ -5820,6 +5823,84 @@ void CRobotMain::CreateCodeBattleInterface()
{ {
pw->CreateButton(pos, ddim, 13, EVENT_CODE_BATTLE_SPECTATOR); pw->CreateButton(pos, ddim, 13, EVENT_CODE_BATTLE_SPECTATOR);
} }
pos.y += ddim.y;
ddim.y = textHeight;
int i = 0;
auto teams = GetAllTeams();
for (auto it = teams.rbegin(); it != teams.rend(); ++it)
{
int team = *it;
Ui::CControl* pl;
ddim.x = 55.0f/640.0f;
pl = m_codeBattleStarted
? static_cast<Ui::CControl*>(pw->CreateLabel(pos, ddim, 0, static_cast<EventType>(EVENT_SCOREBOARD+2*(numTeams-i-1)+0), "XXXXX"))
: static_cast<Ui::CControl*>(pw->CreateEdit( pos, ddim, 0, static_cast<EventType>(EVENT_SCOREBOARD+2*(numTeams-i-1)+0)));
pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT);
pl->SetFontSize(m_codeBattleStarted ? Gfx::FONT_SIZE_SMALL : Gfx::FONT_SIZE_SMALL*0.75f);
m_codeBattleStarted ? pl->SetName(GetTeamName(team)) : static_cast<Ui::CEdit*>(pl)->SetText(GetTeamName(team));
pos.x += 57.5f/640.0f;
ddim.x = 22.5f/640.0f;
pl = m_codeBattleStarted
? static_cast<Ui::CControl*>(pw->CreateLabel(pos, ddim, 0, static_cast<EventType>(EVENT_SCOREBOARD+2*(numTeams-i-1)+1), "???"))
: static_cast<Ui::CControl*>(pw->CreateEdit( pos, ddim, 0, static_cast<EventType>(EVENT_SCOREBOARD+2*(numTeams-i-1)+1)));
pl->SetTextAlign(Gfx::TEXT_ALIGN_RIGHT);
pl->SetFontSize(m_codeBattleStarted ? Gfx::FONT_SIZE_SMALL : Gfx::FONT_SIZE_SMALL*0.75f);
m_codeBattleStarted ? pl->SetName(StrUtils::ToString<int>(m_scoreboard->GetScore(team))) : static_cast<Ui::CEdit*>(pl)->SetText(StrUtils::ToString<int>(m_scoreboard->GetScore(team)));
pos.x -= 57.5f/640.0f;
pos.y += ddim.y;
i++;
}
}
}
void CRobotMain::ApplyCodeBattleInterface()
{
assert(GetMissionType() == MISSION_CODE_BATTLE);
if (!m_scoreboard) return;
Ui::CWindow* pw = static_cast<Ui::CWindow*>(m_interface->SearchControl(EVENT_WINDOW6));
assert(pw != nullptr);
int i = 0;
for (int team : GetAllTeams())
{
Ui::CEdit* pl;
pl = static_cast<Ui::CEdit*>(pw->SearchControl(static_cast<EventType>(EVENT_SCOREBOARD+2*i+0)));
assert(pl != nullptr);
m_teamNames[team] = pl->GetText(pl->GetTextLength());
pl = static_cast<Ui::CEdit*>(pw->SearchControl(static_cast<EventType>(EVENT_SCOREBOARD+2*i+1)));
assert(pl != nullptr);
m_scoreboard->SetScore(team, StrUtils::FromString<int>(pl->GetText(pl->GetTextLength())));
i++;
}
}
void CRobotMain::UpdateCodeBattleInterface()
{
assert(GetMissionType() == MISSION_CODE_BATTLE);
if (!m_scoreboard) return;
Ui::CWindow* pw = static_cast<Ui::CWindow*>(m_interface->SearchControl(EVENT_WINDOW6));
assert(pw != nullptr);
int i = 0;
for (int team : GetAllTeams())
{
Ui::CControl* pl;
pl = pw->SearchControl(static_cast<EventType>(EVENT_SCOREBOARD+2*i+0));
assert(pl != nullptr);
pl->SetName(GetTeamName(team));
pl = pw->SearchControl(static_cast<EventType>(EVENT_SCOREBOARD+2*i+1));
assert(pl != nullptr);
pl->SetName(StrUtils::ToString<int>(m_scoreboard->GetScore(team)));
i++;
} }
} }
@ -5866,3 +5947,55 @@ bool CRobotMain::GetDebugCrashSpheres()
{ {
return m_debugCrashSpheres; return m_debugCrashSpheres;
} }
void CRobotMain::PushToCommandHistory(std::string str)
{
if (!m_commandHistory.empty() && m_commandHistory.front() == str) // already in history
return;
m_commandHistory.push_front(str);
if (m_commandHistory.size() > 50) // to avoid infinite growth
m_commandHistory.pop_back();
}
std::string CRobotMain::GetNextFromCommandHistory()
{
if (m_commandHistory.empty() || static_cast<int>(m_commandHistory.size()) <= m_commandHistoryIndex + 1) // no next element
return "";
return m_commandHistory[++m_commandHistoryIndex];
}
std::string CRobotMain::GetPreviousFromCommandHistory()
{
if (m_commandHistory.empty() || m_commandHistoryIndex < 1) // first or none element selected
return "";
return m_commandHistory[--m_commandHistoryIndex];
}
CScoreboard* CRobotMain::GetScoreboard()
{
return m_scoreboard.get();
}
std::set<int> CRobotMain::GetAllTeams()
{
std::set<int> teams = GetAllActiveTeams();
for(auto& it : m_teamFinished)
{
teams.insert(it.first);
}
return teams;
}
std::set<int> CRobotMain::GetAllActiveTeams()
{
std::set<int> teams;
for (CObject* obj : m_objMan->GetAllObjects())
{
int team = obj->GetTeam();
if (team == 0) continue;
teams.insert(team);
}
return teams;
}

View File

@ -87,6 +87,7 @@ class CInput;
class CObjectManager; class CObjectManager;
class CSceneEndCondition; class CSceneEndCondition;
class CAudioChangeCondition; class CAudioChangeCondition;
class CScoreboard;
class CPlayerProfile; class CPlayerProfile;
class CSettings; class CSettings;
class COldObject; class COldObject;
@ -120,6 +121,8 @@ struct NewScriptName
{ {
ObjectType type = OBJECT_NULL; ObjectType type = OBJECT_NULL;
std::string name = ""; std::string name = "";
NewScriptName(ObjectType type, const std::string& name) : type(type), name(name) {}
}; };
@ -156,6 +159,17 @@ const int SATCOM_PROG = 4;
const int SATCOM_SOLUCE = 5; const int SATCOM_SOLUCE = 5;
const int SATCOM_MAX = 6; const int SATCOM_MAX = 6;
/**
* \brief Main class managing the game world
*
* This is the main class of the whole game engine. It's main job is to manage main parts of the gameplay,
* like loading levels and checking for win conditions, but it's also a place where all things that don't fit
* elsewhere have landed.
*
* \todo In the future, it would be nice to refactor this class to remove as much unrelated stuff as possible
*
* \nosubgrouping
*/
class CRobotMain : public CSingleton<CRobotMain> class CRobotMain : public CSingleton<CRobotMain>
{ {
public: public:
@ -168,11 +182,16 @@ public:
Ui::CDisplayText* GetDisplayText(); Ui::CDisplayText* GetDisplayText();
CPauseManager* GetPauseManager(); CPauseManager* GetPauseManager();
/**
* \name Phase management
*/
//@{
void ChangePhase(Phase phase); void ChangePhase(Phase phase);
bool ProcessEvent(Event &event); bool ProcessEvent(Event &event);
Phase GetPhase(); Phase GetPhase();
//@}
bool CreateShortcuts(); //! Load the scene for apperance customization
void ScenePerso(); void ScenePerso();
void SetMovieLock(bool lock); void SetMovieLock(bool lock);
@ -187,16 +206,32 @@ public:
void SetFriendAim(bool friendAim); void SetFriendAim(bool friendAim);
bool GetFriendAim(); bool GetFriendAim();
//! \name Simulation speed management
//@{
void SetSpeed(float speed); void SetSpeed(float speed);
float GetSpeed(); float GetSpeed();
//@}
//! \brief Create the shortcuts at the top of the screen, if they should be visible
//! \see CMainShort::CreateShortcuts
bool CreateShortcuts();
//! \brief Update the shortcuts at the top of the screen
//! \see CMainShort::UpdateShortcuts
void UpdateShortcuts(); void UpdateShortcuts();
void SelectHuman(); //! Find the astronaut (::OBJECT_HUMAN) object
CObject* SearchHuman(); CObject* SearchHuman();
CObject* SearchToto(); /**
CObject* SearchNearest(Math::Vector pos, CObject* exclu); * \brief Select an object
* \param obj Object to select
* \param displayError If true and the object is currently in error state, automatically display the error message
*
* \note This function automatically adds objects to selection history (see PushToSelectionHistory())
*/
bool SelectObject(CObject* obj, bool displayError=true); bool SelectObject(CObject* obj, bool displayError=true);
//! Return the object that was selected at the start of the scene
CObject* GetSelectObject(); CObject* GetSelectObject();
//! Deselect currently selected object
//! \return Object that was deselected
CObject* DeselectAll(); CObject* DeselectAll();
void ResetObject(); void ResetObject();
@ -251,9 +286,10 @@ public:
void ClearInterface(); void ClearInterface();
void ChangeColor(); void ChangeColor();
float SearchNearestObject(Math::Vector center, CObject *exclu);
bool FreeSpace(Math::Vector &center, float minRadius, float maxRadius, float space, CObject *exclu); bool FreeSpace(Math::Vector &center, float minRadius, float maxRadius, float space, CObject *exclu);
bool FlatFreeSpace(Math::Vector &center, float minFlat, float minRadius, float maxRadius, float space, CObject *exclu); bool FlatFreeSpace(Math::Vector &center, float minFlat, float minRadius, float maxRadius, float space, CObject *exclu);
//! \name In-world indicators
//@{
float GetFlatZoneRadius(Math::Vector center, float maxRadius, CObject *exclu); float GetFlatZoneRadius(Math::Vector center, float maxRadius, CObject *exclu);
void HideDropZone(CObject* metal); void HideDropZone(CObject* metal);
void ShowDropZone(CObject* metal, CObject* transporter); void ShowDropZone(CObject* metal, CObject* transporter);
@ -262,28 +298,38 @@ public:
float radius, float duration=SHOWLIMITTIME); float radius, float duration=SHOWLIMITTIME);
void StartShowLimit(); void StartShowLimit();
void FrameShowLimit(float rTime); void FrameShowLimit(float rTime);
//@}
void SaveAllScript(); void SaveAllScript();
void SaveOneScript(CObject *obj); void SaveOneScript(CObject *obj);
bool SaveFileStack(CObject *obj, FILE *file, int objRank); bool SaveFileStack(CObject *obj, FILE *file, int objRank);
bool ReadFileStack(CObject *obj, FILE *file, int objRank); bool ReadFileStack(CObject *obj, FILE *file, int objRank);
void FlushNewScriptName(); //! Return list of scripts to load to robot created in BotFactory
void AddNewScriptName(ObjectType type, const std::string& name); std::vector<std::string> GetNewScriptNames(ObjectType type);
std::string GetNewScriptName(ObjectType type, int rank);
//! Return the scoreboard manager
//! Note: this may return nullptr if the scoreboard is not enabled!
CScoreboard* GetScoreboard();
void SelectPlayer(std::string playerName); void SelectPlayer(std::string playerName);
CPlayerProfile* GetPlayerProfile(); CPlayerProfile* GetPlayerProfile();
/**
* \name Saved game read/write
*/
//@{
bool IOIsBusy(); bool IOIsBusy();
bool IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, const std::string& info, bool emergencySave = false); bool IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, const std::string& info, bool emergencySave = false);
void IOWriteSceneFinished(); void IOWriteSceneFinished();
CObject* IOReadScene(std::string filename, std::string filecbot); CObject* IOReadScene(std::string filename, std::string filecbot);
void IOWriteObject(CLevelParserLine *line, CObject* obj, const std::string& programDir, int objRank); void IOWriteObject(CLevelParserLine *line, CObject* obj, const std::string& programDir, int objRank);
CObject* IOReadObject(CLevelParserLine *line, const std::string& programDir, const std::string& objCounterText, float objectProgress, int objRank = -1); CObject* IOReadObject(CLevelParserLine *line, const std::string& programDir, const std::string& objCounterText, float objectProgress, int objRank = -1);
//@}
int CreateSpot(Math::Vector pos, Gfx::Color color); int CreateSpot(Math::Vector pos, Gfx::Color color);
//! Find the currently selected object
CObject* GetSelect(); CObject* GetSelect();
void DisplayError(Error err, CObject* pObj, float time=10.0f); void DisplayError(Error err, CObject* pObj, float time=10.0f);
@ -298,12 +344,17 @@ public:
void StartMissionTimer(); void StartMissionTimer();
/**
* \name Autosave management
*/
//@{
void SetAutosave(bool enable); void SetAutosave(bool enable);
bool GetAutosave(); bool GetAutosave();
void SetAutosaveInterval(int interval); void SetAutosaveInterval(int interval);
int GetAutosaveInterval(); int GetAutosaveInterval();
void SetAutosaveSlots(int slots); void SetAutosaveSlots(int slots);
int GetAutosaveSlots(); int GetAutosaveSlots();
//@}
//! Enable mode where completing mission closes the game //! Enable mode where completing mission closes the game
void SetExitAfterMission(bool exit); void SetExitAfterMission(bool exit);
@ -311,49 +362,97 @@ public:
//! Returns true if player can interact with things manually //! Returns true if player can interact with things manually
bool CanPlayerInteract(); bool CanPlayerInteract();
/**
* \name Team definition management
*/
//@{
//! Returns team name for the given team id //! Returns team name for the given team id
const std::string& GetTeamName(int id); const std::string& GetTeamName(int id);
//! Returns true if team-specific colored texture is available //! Returns true if team-specific colored texture is available
bool IsTeamColorDefined(int id); bool IsTeamColorDefined(int id);
//@}
//! Get/set enabled buildings /**
* \name EnableBuild/EnableResearch/DoneResearch
* Management of enabled buildings, enabled researches, and completed researches
*/
//@{ //@{
/**
* \brief Get enabled buildings
* \return Bitmask of BuildType values
*/
int GetEnableBuild(); int GetEnableBuild();
/**
* \brief Set enabled buildings
* \param enableBuild Bitmask of BuildType values
*/
void SetEnableBuild(int enableBuild); void SetEnableBuild(int enableBuild);
//@}
//! Get/set enabled researches
//@{
int GetEnableResearch();
void SetEnableResearch(int enableResearch);
//@}
//! Get/set done researches
//@{
int GetDoneResearch(int team);
void SetDoneResearch(int doneResearch, int team);
//@}
//! Returns true if the given building is enabled /**
//@{ * \brief Get enabled researches
* \return Bitmask of ResearchType values
*/
int GetEnableResearch();
/**
* \brief Set enabled researches
* \param enableResearch Bitmask of ResearchType values
*/
void SetEnableResearch(int enableResearch);
/**
* \brief Get done researches
* \param team Team to get researches for
* \return Bitmask of ResearchType values
*/
int GetDoneResearch(int team = 0);
/**
* \brief Set done researches
* \param doneResearch Bitmask of ResearchType values
* \param team Team to set researches for
*/
void SetDoneResearch(int doneResearch, int team = 0);
//! \brief Check if the given building is enabled
bool IsBuildingEnabled(BuildType type); bool IsBuildingEnabled(BuildType type);
//! \brief Check if the given building is enabled
bool IsBuildingEnabled(ObjectType type); bool IsBuildingEnabled(ObjectType type);
//@} //! \brief Check if the given research is enabled
//! Returns true if the given research is enabled
bool IsResearchEnabled(ResearchType type); bool IsResearchEnabled(ResearchType type);
//! Returns true if the given research is done //! \brief Check if the given research is done
bool IsResearchDone(ResearchType type, int team); bool IsResearchDone(ResearchType type, int team);
//! Marks research as done //! \brief Mark given research as done
void MarkResearchDone(ResearchType type, int team); void MarkResearchDone(ResearchType type, int team);
//! Retruns true if all requirements to build this object are met (EnableBuild + DoneResearch) /**
//@{ * \brief Check if all requirements to build this object are met (EnableBuild + DoneResearch)
bool CanBuild(ObjectType type, int team); * \return true if the building can be built, false otherwise
* \see CanBuildError() for a version which returns a specific reason for the build being denied
*/
inline bool CanBuild(ObjectType type, int team)
{
return CanBuildError(type, team) == ERR_OK;
}
/**
* \brief Check if all requirements to build this object are met (EnableBuild + DoneResearch)
* \return One of Error values - ::ERR_OK if the building can be built, ::ERR_BUILD_DISABLED or ::ERR_BUILD_RESEARCH otherwise
* \see CanBuild() for a version which returns a boolean
*/
Error CanBuildError(ObjectType type, int team); Error CanBuildError(ObjectType type, int team);
//@}
//! Retruns true if all requirements to create this object in BotFactory are met (DoneResearch) /**
//@{ * \brief Check if all requirements to build this object in BotFactory are met (DoneResearch)
bool CanFactory(ObjectType type, int team); * \return true if the robot can be built, false otherwise
* \see CanFactoryError() for a version which returns a specific reason for the build being denied
*/
inline bool CanFactory(ObjectType type, int team)
{
return CanFactoryError(type, team) == ERR_OK;
}
/**
* \brief Check if all requirements to build this object in BotFactory are met (DoneResearch)
* \return One of Error values - ::ERR_OK if the robot can be built, ::ERR_BUILD_DISABLED or ::ERR_BUILD_RESEARCH otherwise
* \see CanFactory() for a version which returns a boolean
*/
Error CanFactoryError(ObjectType type, int team); Error CanFactoryError(ObjectType type, int team);
//@} //@}
@ -364,12 +463,16 @@ public:
void StartDetectEffect(COldObject* object, CObject* target); void StartDetectEffect(COldObject* object, CObject* target);
bool IsSelectable(CObject* obj); //! Enable crash sphere debug rendering
void SetDebugCrashSpheres(bool draw); void SetDebugCrashSpheres(bool draw);
//! Check if crash sphere debug rendering is enabled
bool GetDebugCrashSpheres(); bool GetDebugCrashSpheres();
//! Returns a set of all team IDs in the current level
std::set<int> GetAllTeams();
//! Returns a set of all team IDs in the current level that are still active
std::set<int> GetAllActiveTeams();
protected: protected:
bool EventFrame(const Event &event); bool EventFrame(const Event &event);
bool EventObject(const Event &event); bool EventObject(const Event &event);
@ -391,8 +494,11 @@ protected:
CObject* DetectObject(Math::Point pos); CObject* DetectObject(Math::Point pos);
void ChangeCamera(); void ChangeCamera();
void AbortMovie(); void AbortMovie();
//! \brief Select an object, without deselecting the previous one
void SelectOneObject(CObject* obj, bool displayError=true); void SelectOneObject(CObject* obj, bool displayError=true);
void HelpObject(); void HelpObject();
//! \brief Switch to previous object
//! \see PopFromSelectionHistory()
bool DeselectObject(); bool DeselectObject();
void DeleteAllObjects(); void DeleteAllObjects();
void UpdateInfoText(); void UpdateInfoText();
@ -408,11 +514,24 @@ protected:
void PushToSelectionHistory(CObject* obj); void PushToSelectionHistory(CObject* obj);
CObject* PopFromSelectionHistory(); CObject* PopFromSelectionHistory();
//! \name Code battle interface
//@{
void CreateCodeBattleInterface(); void CreateCodeBattleInterface();
void UpdateCodeBattleInterface();
void ApplyCodeBattleInterface();
void DestroyCodeBattleInterface(); void DestroyCodeBattleInterface();
void SetCodeBattleSpectatorMode(bool mode); void SetCodeBattleSpectatorMode(bool mode);
//@}
void UpdateDebugCrashSpheres(); void UpdateDebugCrashSpheres();
//! Adds element to the beginning of command history
void PushToCommandHistory(std::string obj);
//! Returns next/previous element from command history and updates index
//@{
std::string GetNextFromCommandHistory();
std::string GetPreviousFromCommandHistory();
//@}
protected: protected:
CApplication* m_app = nullptr; CApplication* m_app = nullptr;
@ -472,9 +591,9 @@ protected:
ActivePause* m_freePhotoPause = nullptr; ActivePause* m_freePhotoPause = nullptr;
bool m_cmdEdit = false; bool m_cmdEdit = false;
ActivePause* m_cmdEditPause = nullptr; ActivePause* m_cmdEditPause = nullptr;
bool m_selectInsect = false; bool m_cheatSelectInsect = false;
bool m_showSoluce = false; bool m_cheatShowSoluce = false;
bool m_showAll = false; bool m_cheatAllMission = false;
bool m_cheatRadar = false; bool m_cheatRadar = false;
bool m_shortCut = false; bool m_shortCut = false;
std::string m_audioTrack; std::string m_audioTrack;
@ -496,7 +615,7 @@ protected:
bool m_editLock = false; // edition in progress? bool m_editLock = false; // edition in progress?
bool m_editFull = false; // edition in full screen? bool m_editFull = false; // edition in full screen?
bool m_hilite = false; bool m_hilite = false;
bool m_trainerPilot = false; // remote trainer? bool m_cheatTrainerPilot = false; // remote trainer?
bool m_friendAim = false; bool m_friendAim = false;
bool m_resetCreate = false; bool m_resetCreate = false;
bool m_mapShow = false; bool m_mapShow = false;
@ -548,9 +667,15 @@ protected:
long m_endTakeResearch = 0; long m_endTakeResearch = 0;
float m_endTakeWinDelay = 0.0f; float m_endTakeWinDelay = 0.0f;
float m_endTakeLostDelay = 0.0f; float m_endTakeLostDelay = 0.0f;
//! Set to true for teams that have already finished
std::map<int, bool> m_teamFinished;
std::vector<std::unique_ptr<CAudioChangeCondition>> m_audioChange; std::vector<std::unique_ptr<CAudioChangeCondition>> m_audioChange;
//! The scoreboard
//! If the scoreboard is not enabled for this level, this will be null
std::unique_ptr<CScoreboard> m_scoreboard;
std::map<std::string, MinMax> m_obligatoryTokens; std::map<std::string, MinMax> m_obligatoryTokens;
//! Enabled buildings //! Enabled buildings
@ -585,4 +710,9 @@ protected:
std::deque<CObject*> m_selectionHistory; std::deque<CObject*> m_selectionHistory;
bool m_debugCrashSpheres; bool m_debugCrashSpheres;
//! Cheat console command history
std::deque<std::string> m_commandHistory;
//! Index of currently selected element in command history
int m_commandHistoryIndex;
}; };

View File

@ -29,11 +29,13 @@
#include "object/interface/powered_object.h" #include "object/interface/powered_object.h"
#include "object/interface/transportable_object.h" #include "object/interface/transportable_object.h"
#include <limits>
void CSceneCondition::Read(CLevelParserLine* line)
void CObjectCondition::Read(CLevelParserLine* line)
{ {
this->pos = line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit; this->pos = line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit;
this->dist = line->GetParam("dist")->AsFloat(8.0f)*g_unit; this->dist = line->GetParam("dist")->AsFloat(std::numeric_limits<float>::infinity())*g_unit;
this->type = line->GetParam("type")->AsObjectType(OBJECT_NULL); this->type = line->GetParam("type")->AsObjectType(OBJECT_NULL);
this->powermin = line->GetParam("powermin")->AsFloat(-1); this->powermin = line->GetParam("powermin")->AsFloat(-1);
this->powermax = line->GetParam("powermax")->AsFloat(100); this->powermax = line->GetParam("powermax")->AsFloat(100);
@ -41,6 +43,82 @@ void CSceneCondition::Read(CLevelParserLine* line)
this->drive = line->GetParam("drive")->AsDriveType(DriveType::Other); this->drive = line->GetParam("drive")->AsDriveType(DriveType::Other);
this->countTransported = line->GetParam("countTransported")->AsBool(true); this->countTransported = line->GetParam("countTransported")->AsBool(true);
this->team = line->GetParam("team")->AsInt(0); this->team = line->GetParam("team")->AsInt(0);
}
bool CObjectCondition::CheckForObject(CObject* obj)
{
if (!this->countTransported)
{
if (IsObjectBeingTransported(obj)) return false;
}
ObjectType type = obj->GetType();
ToolType tool = GetToolFromObject(type);
DriveType drive = GetDriveFromObject(type);
if (this->tool != ToolType::Other &&
tool != this->tool)
return false;
if (this->drive != DriveType::Other &&
drive != this->drive)
return false;
if (this->tool == ToolType::Other &&
this->drive == DriveType::Other &&
type != this->type &&
this->type != OBJECT_NULL)
return false;
if ((this->team > 0 && obj->GetTeam() != this->team) ||
(this->team < 0 && (obj->GetTeam() == -(this->team) || obj->GetTeam() == 0)))
return false;
float energyLevel = -1;
CPowerContainerObject* power = nullptr;
if (obj->Implements(ObjectInterfaceType::PowerContainer))
{
power = dynamic_cast<CPowerContainerObject*>(obj);
}
else if (obj->Implements(ObjectInterfaceType::Powered))
{
CObject* powerObj = dynamic_cast<CPoweredObject*>(obj)->GetPower();
if(powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer))
{
power = dynamic_cast<CPowerContainerObject*>(powerObj);
}
}
if (power != nullptr)
{
energyLevel = power->GetEnergy();
if (power->GetCapacity() > 1.0f) energyLevel *= 10; // TODO: Who designed it like that ?!?!
}
if (energyLevel < this->powermin || energyLevel > this->powermax) return false;
Math::Vector oPos;
if (IsObjectBeingTransported(obj))
oPos = dynamic_cast<CTransportableObject*>(obj)->GetTransporter()->GetPosition();
else
oPos = obj->GetPosition();
oPos.y = 0.0f;
Math::Vector bPos = this->pos;
bPos.y = 0.0f;
if (Math::DistanceProjected(oPos, bPos) <= this->dist)
return true;
return false;
}
void CSceneCondition::Read(CLevelParserLine* line)
{
CObjectCondition::Read(line);
// Scene conditions STILL use a different default value
// See issue #759
this->dist = line->GetParam("dist")->AsFloat(8.0f)*g_unit;
this->min = line->GetParam("min")->AsInt(1); this->min = line->GetParam("min")->AsInt(1);
this->max = line->GetParam("max")->AsInt(9999); this->max = line->GetParam("max")->AsInt(9999);
@ -48,74 +126,12 @@ void CSceneCondition::Read(CLevelParserLine* line)
int CSceneCondition::CountObjects() int CSceneCondition::CountObjects()
{ {
Math::Vector bPos = this->pos;
bPos.y = 0.0f;
Math::Vector oPos;
int nb = 0; int nb = 0;
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
{ {
if (!obj->GetActive()) continue; if (!obj->GetActive()) continue;
if (!CheckForObject(obj)) continue;
if (!this->countTransported) nb ++;
{
if (IsObjectBeingTransported(obj)) continue;
}
ObjectType type = obj->GetType();
ToolType tool = GetToolFromObject(type);
DriveType drive = GetDriveFromObject(type);
if (this->tool != ToolType::Other &&
tool != this->tool)
continue;
if (this->drive != DriveType::Other &&
drive != this->drive)
continue;
if (this->tool == ToolType::Other &&
this->drive == DriveType::Other &&
type != this->type &&
this->type != OBJECT_NULL)
continue;
if ((this->team > 0 && obj->GetTeam() != this->team) ||
(this->team < 0 && (obj->GetTeam() == -(this->team) || obj->GetTeam() == 0)))
continue;
float energyLevel = -1;
CPowerContainerObject* power = nullptr;
if (obj->Implements(ObjectInterfaceType::PowerContainer))
{
power = dynamic_cast<CPowerContainerObject*>(obj);
}
else if (obj->Implements(ObjectInterfaceType::Powered))
{
CObject* powerObj = dynamic_cast<CPoweredObject*>(obj)->GetPower();
if(powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer))
{
power = dynamic_cast<CPowerContainerObject*>(powerObj);
}
}
if (power != nullptr)
{
energyLevel = power->GetEnergy();
if (power->GetCapacity() > 1.0f) energyLevel *= 10; // TODO: Who designed it like that ?!?!
}
if (energyLevel < this->powermin || energyLevel > this->powermax) continue;
if (IsObjectBeingTransported(obj))
oPos = dynamic_cast<CTransportableObject*>(obj)->GetTransporter()->GetPosition();
else
oPos = obj->GetPosition();
oPos.y = 0.0f;
if (Math::DistanceProjected(oPos, bPos) <= this->dist)
nb ++;
} }
return nb; return nb;
} }
@ -126,7 +142,6 @@ bool CSceneCondition::Check()
return nb >= this->min && nb <= this->max; return nb >= this->min && nb <= this->max;
} }
void CSceneEndCondition::Read(CLevelParserLine* line) void CSceneEndCondition::Read(CLevelParserLine* line)
{ {
CSceneCondition::Read(line); CSceneCondition::Read(line);

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