diff --git a/.gitignore b/.gitignore index f9f69301..f3461be1 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,7 @@ CMakeLists.txt.user.* # Ignore Visual Studio Code files /.vscode + +# Ignore Visual Studio files +/CMakeSettings.json +/.vs diff --git a/CMakeLists.txt b/CMakeLists.txt index 89cf5344..ba6cd2d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ project(colobot C CXX) set(COLOBOT_VERSION_CODENAME "Gold") set(COLOBOT_VERSION_MAJOR 0) set(COLOBOT_VERSION_MINOR 1) -set(COLOBOT_VERSION_REVISION 11) +set(COLOBOT_VERSION_REVISION 12) # Used on official releases #set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha") @@ -60,6 +60,7 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES "Windows") set(PLATFORM_GNU 0) set(PLATFORM_LINUX 0) set(PLATFORM_MACOSX 0) + set(PLATFORM_FREEBSD 0) set(PLATFORM_OTHER 0) # Platform-dependent implementation of system.h @@ -71,6 +72,7 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") set(PLATFORM_LINUX 1) set(PLATFORM_GNU 1) set(PLATFORM_MACOSX 0) + set(PLATFORM_FREEBSD 0) set(PLATFORM_OTHER 0) # Platform-dependent implementation of system.h @@ -82,6 +84,7 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "kFreeBSD" OR "${CMAKE_SYSTEM_NAME}" STREQ set(PLATFORM_LINUX 0) set(PLATFORM_GNU 1) set(PLATFORM_MACOSX 0) + set(PLATFORM_FREEBSD 0) set(PLATFORM_OTHER 0) # Platform-dependent implementation of system.h @@ -94,18 +97,35 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin") set(PLATFORM_GNU 0) set(PLATFORM_MACOSX 1) set(PLATFORM_OTHER 0) + set(PLATFORM_FREEBSD 0) # Platform-dependent implementation of system.h set(SYSTEM_CPP_MODULE "system_macosx.cpp") set(SYSTEM_H_MODULE "system_macosx.h") # To avoid CMake warning set(CMAKE_MACOSX_RPATH 1) +elseif("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") + message(STATUS "Build for FreeBSD system") + set(PLATFORM_WINDOWS 0) + set(PLATFORM_LINUX 0) + set(PLATFORM_GNU 0) + set(PLATFORM_MACOSX 0) + set(PLATFORM_FREEBSD 1) + set(PLATFORM_OTHER 0) + + # Platform-dependent implementation of system.h + # On FreeBSD we can use *_other + set(SYSTEM_CPP_MODULE "system_other.cpp") + set(SYSTEM_H_MODULE "system_other.h") + # To avoid CMake warning + set(CMAKE_MACOSX_RPATH 1) else() message(STATUS "Build for other system") set(PLATFORM_WINDOWS 0) set(PLATFORM_LINUX 0) set(PLATFORM_GNU 0) set(PLATFORM_MACOSX 0) + set(PLATFORM_FREEBSD 0) set(PLATFORM_OTHER 1) # Platform-dependent implementation of system.h @@ -124,6 +144,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) # Include cmake directory with some additional scripts set(CMAKE_MODULE_PATH "${colobot_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +# MSVC needs different flags if linking statically +option(MSVC_STATIC "Link statically when using MSVC" OFF) + # Compiler detection if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7) @@ -150,6 +173,10 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") message(STATUS "Detected Clang version 3.1+") + if (${PLATFORM_FREEBSD}) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=bfd") + endif() + set(NORMAL_CXX_FLAGS "-std=c++11 -Wall -Werror -Wold-style-cast -pedantic-errors -Wmissing-prototypes") 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") @@ -160,14 +187,19 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") message(STATUS "Detected MSVC compiler") set(NORMAL_CXX_FLAGS "/wd\"4244\" /wd\"4309\" /wd\"4800\" /wd\"4996\" /wd\"4351\" /EHsc") # disable some useless warnings - set(RELEASE_CXX_FLAGS "/MD") - set(DEBUG_CXX_FLAGS "/MDd /ZI") + if(MSVC_STATIC) + set(RELEASE_CXX_FLAGS "/MT /Ox") + set(DEBUG_CXX_FLAGS "/MTd /ZI") + else(MSVC_STATIC) + set(RELEASE_CXX_FLAGS "/MD /Ox") + set(DEBUG_CXX_FLAGS "/MDd /ZI") + endif() set(TEST_CXX_FLAGS "") add_definitions(-DNOEXCEPT= -DHAS_MSVC_EXCEPTION_BUG) # Needed for Debug information (it's set to "No" by default for some reason) - set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG") - set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG") + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS} /DEBUG") + set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS} /DEBUG") else() message(FATAL_ERROR "Your C++ compiler doesn't seem to be supported.") endif() @@ -196,11 +228,14 @@ option(DEV_BUILD "Enable development build (enables some debugging tools, local # Official build - changes text on the crash screen # PLEASE DO NOT USE ON UNOFFICIAL BUILDS. Thanks. -option(OFFICIAL_BUILD "Official build (changes crash screen text)" OFF) +option(OFFICIAL_COLOBOT_BUILD "Official build (changes crash screen text)" OFF) # Portable build - load all data from current directory option(PORTABLE "Portable build" OFF) +# Portable saves - suitable for e.g. putting the whole game on external storage and moving your saves with it +option(PORTABLE_SAVES "Portable saves" OFF) + # Building tests can be enabled/disabled option(TESTS "Build tests" OFF) @@ -312,6 +347,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(CBOT_STATIC 1) # only this works for some reason set(WINGETOPT 1) # use wingetopt library + + # Hide console in release builds + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_WIN32_EXECUTABLE 1) + endif() endif() ## @@ -350,21 +390,19 @@ endif() ## # Installation paths defined before compiling sources -if(PLATFORM_WINDOWS) - if(MXE) - # We need to use STRING because PATH doesn't accept relative paths - set(COLOBOT_INSTALL_BIN_DIR ./ CACHE STRING "Colobot binary directory") - set(COLOBOT_INSTALL_LIB_DIR ./ CACHE STRING "Colobot libraries directory") - set(COLOBOT_INSTALL_DATA_DIR ./data CACHE STRING "Colobot shared data directory") - set(COLOBOT_INSTALL_I18N_DIR ./lang CACHE STRING "Colobot translations directory") - set(COLOBOT_INSTALL_DOC_DIR ./doc CACHE STRING "Colobot documentation directory") - else() - set(COLOBOT_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot binary directory") - set(COLOBOT_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot libraries directory") - set(COLOBOT_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/data CACHE PATH "Colobot shared data directory") - set(COLOBOT_INSTALL_I18N_DIR ${CMAKE_INSTALL_PREFIX}/lang CACHE PATH "Colobot translations directory") - set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/doc CACHE PATH "Colobot documentation directory") - endif() +if(PORTABLE OR (PLATFORM_WINDOWS AND MXE)) + # We need to use STRING because PATH doesn't accept relative paths + set(COLOBOT_INSTALL_BIN_DIR ./ CACHE STRING "Colobot binary directory") + set(COLOBOT_INSTALL_LIB_DIR ./ CACHE STRING "Colobot libraries directory") + set(COLOBOT_INSTALL_DATA_DIR ./data CACHE STRING "Colobot shared data directory") + set(COLOBOT_INSTALL_I18N_DIR ./lang CACHE STRING "Colobot translations directory") + set(COLOBOT_INSTALL_DOC_DIR ./doc CACHE STRING "Colobot documentation directory") +elseif(PLATFORM_WINDOWS) + set(COLOBOT_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot binary directory") + set(COLOBOT_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot libraries directory") + set(COLOBOT_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/data CACHE PATH "Colobot shared data directory") + set(COLOBOT_INSTALL_I18N_DIR ${CMAKE_INSTALL_PREFIX}/lang CACHE PATH "Colobot translations directory") + set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/doc CACHE PATH "Colobot documentation directory") elseif(PLATFORM_MACOSX) set(COLOBOT_INSTALL_BIN_DIR ../MacOS CACHE STRING "Colobot binary directory") set(COLOBOT_INSTALL_LIB_DIR ../MacOS CACHE STRING "Colobot libraries directory") diff --git a/INSTALL.md b/INSTALL.md index 423166dc..fc69342c 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -71,7 +71,7 @@ You will need: On Ubuntu (and probably any other Debian-based system), you can use the following command to install all required packages: ``` - $ apt-get install build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng12-dev libglew-dev libopenal-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-regex-dev libphysfs-dev gettext git po4a vorbis-tools + $ apt-get install build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng-dev libglew-dev libopenal-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-regex-dev libphysfs-dev gettext git po4a vorbis-tools ``` Make sure you install the packages along with header files (often distributed in separate *-dev packages). If you miss any requirements, diff --git a/Jenkinsfile b/Jenkinsfile index 9ba966a7..47dbd3c2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,7 +1,7 @@ #!/usr/bin/env groovy pipeline { - agent { label 'colobot-build' } + agent none options { buildDiscarder(logRotator(artifactDaysToKeepStr: '30', artifactNumToKeepStr: '20')) } @@ -19,13 +19,17 @@ pipeline { stage('Build') { parallel { stage('Build Windows') { + agent { + docker { image 'krzysh/colobot-build:latest' } + } steps { sh 'mkdir -p build/windows' dir('build/windows') { sh ''' - cmake \ + # FIXME: without -lsetupapi linking sdl2 fails + /opt/mxe/usr/bin/i686-w64-mingw32.static-cmake \ + -DCMAKE_CXX_STANDARD_LIBRARIES="-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -lsetupapi" \ -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 @@ -42,14 +46,16 @@ pipeline { } stage('Build Linux') { + agent { + docker { image 'krzysh/colobot-build:latest' } + } steps { 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 ../.. + -DCMAKE_INSTALL_PREFIX=/install -DCMAKE_SKIP_INSTALL_RPATH=ON \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo -DDEV_BUILD=1 -DPORTABLE=1 -DTOOLS=1 -DTESTS=1 -DDESKTOP=1 ../.. make rm -rf install DESTDIR=. make install @@ -60,7 +66,33 @@ pipeline { post { success { sh 'rm -f linux-debug.zip' - zip zipFile: 'linux-debug.zip', archive: true, dir: 'build/linux/install' + dir('build/linux') { + sh ''' + # Clean up + rm -rf squashfs-root + rm -rf colobot.AppDir + rm -rf appimage + rm -f Colobot-x86_64.AppImage + + # Download app image tool + wget -N https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage + chmod +x linuxdeploy-x86_64.AppImage + ./linuxdeploy-x86_64.AppImage --appimage-extract + + # Create AppImage + NO_STRIP=1 ./squashfs-root/AppRun -e colobot --output appimage --appdir colobot.AppDir -d desktop/colobot.desktop -i ../../desktop/colobot.svg + #rename AppImage file to avoid "No such file or directory" errors + find . -maxdepth 1 -type f -name '*AppImage' -name 'Colobot*' -exec sh -c 'x="{}"; mv "$x" "Colobot-x86_64.AppImage"' \\; + chmod +x Colobot-x86_64.AppImage + + # Prepare folder for zip + mkdir -p appimage + cp -rp install/data appimage/data + cp -rp install/lang appimage/lang + cp -p Colobot-x86_64.AppImage appimage/colobot + ''' + } + zip zipFile: 'linux-debug.zip', archive: true, dir: 'build/linux/appimage' } } } @@ -68,6 +100,9 @@ pipeline { } stage('Generate docs') { + agent { + docker { image 'krzysh/colobot-build:latest' } + } steps { dir('build/linux') { sh 'make doc' @@ -81,6 +116,9 @@ pipeline { } stage('Run tests') { + agent { + docker { image 'krzysh/colobot-build:latest' } + } steps { dir('build/linux') { sh './colobot_ut --gtest_output=xml:gtestresults.xml || true' @@ -91,6 +129,9 @@ pipeline { } stage('Run colobot-lint') { + agent { + label 'colobot-build' + } environment { CC = '/usr/lib/llvm-3.6/bin/clang' CXX = '/usr/lib/llvm-3.6/bin/clang++' @@ -245,11 +286,10 @@ exit $ret } } - // TODO: cppcheck publisher STILL doesn't have pipeline support - // There is an open pull request though, merged but no release yet... https://github.com/jenkinsci/cppcheck-plugin/pull/36 - + publishCppcheck pattern: 'build/lint/colobot_lint_report.xml' publishHTML([reportName: 'Colobot-lint HTML report', reportDir: 'build/lint/html_report', reportFiles: 'index.html', reportTitles: '', allowMissing: false, alwaysLinkToLastBuild: true, keepAll: true]) } } } } + diff --git a/cmake/FindLibSndFile.cmake b/cmake/FindLibSndFile.cmake index 8666c66f..7a6d32b6 100644 --- a/cmake/FindLibSndFile.cmake +++ b/cmake/FindLibSndFile.cmake @@ -5,7 +5,7 @@ FIND_PATH(LIBSNDFILE_INCLUDE_DIR sndfile.h) -SET(LIBSNDFILE_NAMES ${LIBSNDFILE_NAMES} sndfile libsndfile) +SET(LIBSNDFILE_NAMES ${LIBSNDFILE_NAMES} sndfile libsndfile libsndfile-1) FIND_LIBRARY(LIBSNDFILE_LIBRARY NAMES ${LIBSNDFILE_NAMES} PATH) IF(LIBSNDFILE_INCLUDE_DIR AND LIBSNDFILE_LIBRARY) diff --git a/cmake/FindPhysFS.cmake b/cmake/FindPhysFS.cmake index fae83786..6d4c93d4 100644 --- a/cmake/FindPhysFS.cmake +++ b/cmake/FindPhysFS.cmake @@ -7,7 +7,7 @@ IF (WIN32) FIND_PATH( PHYSFS_INCLUDE_PATH physfs.h DOC "The directory where physfs.h resides") FIND_LIBRARY( PHYSFS_LIBRARY - NAMES physfs + NAMES physfs physfs-static PATHS /mingw/lib DOC "The PhysFS library") ELSE (WIN32) diff --git a/data b/data index b2792c32..c467bd99 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit b2792c325a6e6871311207559199f77f35bbe524 +Subproject commit c467bd994e60fb54cf977fbe8583f92957330695 diff --git a/desktop/CMakeLists.txt b/desktop/CMakeLists.txt index dcca3b77..2ee308cc 100644 --- a/desktop/CMakeLists.txt +++ b/desktop/CMakeLists.txt @@ -70,26 +70,18 @@ if(PLATFORM_GNU) DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications/ ) + # Install appdata + install( + FILES info.colobot.Colobot.appdata.xml + DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo/ + ) + # Install Icon install( FILES ${COLOBOT_ICON_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps/ ) - # Translate translatable material - find_program(PO4A po4a) - if(NOT PO4A) - message(WARNING "po4a not found; desktop and manpage files will not be translated") - endif() - - if(PO4A) - add_custom_target(desktop_po4a - COMMAND ${PO4A} po4a.cfg - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - add_dependencies(desktopfile desktop_po4a) - endif() - # Create manpage from pod-formatted file find_program(POD2MAN pod2man) if(NOT POD2MAN) @@ -127,11 +119,30 @@ if(PLATFORM_GNU) # Create the english manpage podman(PODFILE colobot.pod) + # Translate translatable material + find_program(PO4A po4a) + if(NOT PO4A) + message(WARNING "po4a not found; desktop and manpage files will not be translated") + endif() + if(PO4A) # Translate the manpage to other languages - add_dependencies(man desktop_po4a) file(GLOB LINGUAS_PO RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/po/ ${CMAKE_CURRENT_SOURCE_DIR}/po/*.po) string(REGEX REPLACE ".po$" "" LINGUAS ${LINGUAS_PO}) + + set(PO4A_OUTPUTS) + foreach(LOCALE ${LINGUAS}) + list(APPEND PO4A_OUTPUTS ${CMAKE_CURRENT_SOURCE_DIR}/lang/${LOCALE}/colobot.pod) + endforeach() + add_custom_command( + OUTPUT ${PO4A_OUTPUTS} + COMMAND ${PO4A} po4a.cfg + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + add_custom_target(desktop_po4a DEPENDS ${PO4A_OUTPUTS}) + add_dependencies(man desktop_po4a) + add_dependencies(desktopfile desktop_po4a) + foreach(LOCALE ${LINGUAS}) podman(PODFILE lang/${LOCALE}/colobot.pod LOCALE ${LOCALE}) add_dependencies(man${PM_LOCALE} desktop_po4a) @@ -145,7 +156,12 @@ if(PLATFORM_MACOSX) endif(PLATFORM_MACOSX) if(PLATFORM_WINDOWS) - set(COLOBOT_VERSION_4COMMAS "${COLOBOT_VERSION_MAJOR},${COLOBOT_VERSION_MINOR},${COLOBOT_VERSION_REVISION},0") + if(COLOBOT_VERSION_REVISION MATCHES "([0-9]+)\\.([0-9]+)") + string(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\1,\\2" COLOBOT_VERSION_REVISION_COMMA "${COLOBOT_VERSION_REVISION}") + set(COLOBOT_VERSION_4COMMAS "${COLOBOT_VERSION_MAJOR},${COLOBOT_VERSION_MINOR},${COLOBOT_VERSION_REVISION_COMMA}") + else() + set(COLOBOT_VERSION_4COMMAS "${COLOBOT_VERSION_MAJOR},${COLOBOT_VERSION_MINOR},${COLOBOT_VERSION_REVISION},0") + endif() configure_file(colobot.rc.cmake ${CMAKE_CURRENT_BINARY_DIR}/colobot.rc) endif(PLATFORM_WINDOWS) diff --git a/desktop/colobot.ini b/desktop/colobot.ini index 0cba2158..3a78019a 100644 --- a/desktop/colobot.ini +++ b/desktop/colobot.ini @@ -1,4 +1,4 @@ Name="Colobot" GenericName="Game to learn programming" Comment="Colonize with bots" -Keywords="robots;3d;space;astronaut;java;c++" +Keywords="robots;3d;space;astronaut;java;c++;" diff --git a/desktop/info.colobot.Colobot.appdata.xml b/desktop/info.colobot.Colobot.appdata.xml new file mode 100644 index 00000000..8a2a75d6 --- /dev/null +++ b/desktop/info.colobot.Colobot.appdata.xml @@ -0,0 +1,38 @@ + + + info.colobot.Colobot + CC0-1.0 + GPL-3.0 + TerranovaTeam + contact@colobot.info + Colobot + Colonize with bots + + +

Colobot (Colonize with Bots) is an educational game aiming to teach programming through entertainment. You are playing as an astronaut on a journey with robot helpers to find a planet for colonization. It features 3D real-time graphics and a C++ and Java-like, object-oriented language, CBOT, which can be used to program the robots available in the game.

+
+ + colobot.desktop + + + + Alpha 0.1.5 + https://colobot.info/wordpress/wp-content/uploads/alpha-0.1.5.png + + + + https://colobot.info/ + https://github.com/colobot/colobot/issues + http://colobot.info/forum/ + https://colobot.info/donate/ + + + moderate + moderate + mild + + + + + +
diff --git a/desktop/po/colobot-desktop.pot b/desktop/po/colobot-desktop.pot index 52e6e1a8..c33ab83d 100644 --- a/desktop/po/colobot-desktop.pot +++ b/desktop/po/colobot-desktop.pot @@ -37,7 +37,7 @@ msgstr "" #. type: Keywords= #: colobot.ini:4 #, no-wrap -msgid "robots;3d;space;astronaut;java;c++" +msgid "robots;3d;space;astronaut;java;c++;" msgstr "" #. type: =head1 diff --git a/desktop/po/fr.po b/desktop/po/fr.po index 5032271f..784113ba 100644 --- a/desktop/po/fr.po +++ b/desktop/po/fr.po @@ -3,18 +3,20 @@ # This file is distributed under the same license as the Colobot package. # # Didier Raboud , 2012, 2016. +# B-CE <.>, 2019. msgid "" msgstr "" -"Project-Id-Version: colobot 0.1.7\n" +"Project-Id-Version: colobot 0.1.12\n" "POT-Creation-Date: 2016-03-30 13:45+0200\n" -"PO-Revision-Date: 2016-03-30 13:49+0100\n" -"Last-Translator: Didier Raboud \n" +"PO-Revision-Date: 2019-06-01 09:43+0200\n" +"Last-Translator: BCE <.>\n" +"Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Lokalize 2.0\n" +"X-Generator: Lokalize 18.12.3\n" #. type: Name= #: colobot.ini:1 @@ -32,13 +34,13 @@ msgstr "Apprentissage de la programmation par le jeu" #: colobot.ini:3 #, no-wrap msgid "Colonize with bots" -msgstr "Colonise avec des roBots" +msgstr "COlonise avec des roBOTs" #. type: Keywords= #: colobot.ini:4 #, no-wrap -msgid "robots;3d;space;astronaut;java;c++" -msgstr "robots;3d;espace;astronaute;cosmonaute;java;c++" +msgid "robots;3d;space;astronaut;java;c++;" +msgstr "robots;3d;espace;astronaute;cosmonaute;java;c++;programmation;jeux" #. type: =head1 #: colobot.pod:3 @@ -74,12 +76,12 @@ msgid "" "real-time graphics and a C++ and Java-like, object-oriented language, CBOT, " "which can be used to program the robots available in the game." msgstr "" -"Colobot (Colonise avec des roBots) est un jeu éducatif visant à " -"l'enseignement de la programmation par le jeu. Vous jouez un astronaute en " +"Colobot (Colonise avec des roBots) est un jeu éducatif visant " +"à l'enseignement de la programmation par le jeu. Vous jouez un astronaute en " "voyage avec des robots à la recherche d'une planète à coloniser. Son " -"interface est en trois-dimensions et en temps réel; le language utilisé " -"(CBOT) ressemble au C++ et à Java et peut être utilisé pour programmer les " -"robots disponibles dans le jeu." +"interface est en trois-dimensions et en temps réel. Le langage utilisé " +"(CBOT), orienté objet , ressemble au C++ et à Java. Il peut être utilisé " +"pour programmer les robots disponibles dans le jeu." #. type: =head1 #: colobot.pod:19 @@ -208,9 +210,9 @@ msgid "" "Enable debug mode (more info printed in logs). Possible values are as " "follows, as well as any comma-separated combination" msgstr "" -"Active le mode de I (plus d'informations dans les logs). Les valeurs" -" possibles sont les suivantes, ainsi que toute combinaison séparée par des" -" virgules" +"Active le mode de I (plus d'informations dans les logs). " +"Les valeurs possibles sont les suivantes, " +"ainsi que toute combinaison séparée par des virgules" #. type: =item #: colobot.pod:81 @@ -260,7 +262,7 @@ msgstr "models" #. type: textblock #: colobot.pod:99 msgid "Models-related debugging" -msgstr "Debug pour les modèles" +msgstr "Débug pour les modèles" #. type: =item #: colobot.pod:101 @@ -270,7 +272,7 @@ msgstr "all" #. type: textblock #: colobot.pod:103 msgid "All above debugging statements" -msgstr "Tout les messages de debug ci-dessus" +msgstr "Tous les messages de debug ci-dessus" #. type: =item #: colobot.pod:107 @@ -280,9 +282,7 @@ msgstr "B<-headless>" #. type: textblock #: colobot.pod:109 msgid "Run in headless mode - disables graphics, sound and user interaction" -msgstr "" -"Lance en mode I - désactive les graphiques, sons et interactions" -" utilisateurs" +msgstr "Lance en mode I - désactive les graphiques, sons et interactions utilisateurs" #. type: =item #: colobot.pod:111 @@ -292,7 +292,7 @@ msgstr "B<-runscene> I" #. type: textblock #: colobot.pod:113 msgid "Run given scene on start (skip menus)" -msgstr "Lance une scène donnée au lancement (saute les menus)" +msgstr "Démarre directement une scène (saute les menus)" #. type: =item #: colobot.pod:115 @@ -317,7 +317,7 @@ msgstr "LC_MESSAGES" #. type: textblock #: colobot.pod:127 msgid "Used to determine the runtime language." -msgstr "Utilisé pour déterminer la langue au lancement" +msgstr "Utilisé pour déterminer la langue au lancement." #. type: =head1 #: colobot.pod:131 diff --git a/po/colobot.pot b/po/colobot.pot index 419b88e9..7cbb92d7 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -266,6 +266,10 @@ msgstr "" msgid "The battle has ended" msgstr "" +#, c-format +msgid "Time: %s" +msgstr "" + #, c-format msgid "%s: %d pts" msgstr "" @@ -447,6 +451,9 @@ msgstr "" msgid "Shadow resolution\\Higher means better range and quality, but slower" msgstr "" +msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" +msgstr "" + msgid "Standard controls\\Standard key functions" msgstr "" @@ -1788,6 +1795,12 @@ msgstr "" msgid "Invalid universal character name" msgstr "" +msgid "Empty character constant" +msgstr "" + +msgid "Duplicate label in switch" +msgstr "" + msgid "Dividing by zero" msgstr "" diff --git a/po/cs.po b/po/cs.po index 867a8482..b14eb434 100644 --- a/po/cs.po +++ b/po/cs.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: 0.1.11\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: DATE\n" -"PO-Revision-Date: 2018-02-24 20:39+01\n" +"PO-Revision-Date: 2018-08-20 22:48+02\n" "Last-Translator: next_ghost \n" "Language-Team: Czech \n" "Language: Czech\n" @@ -489,6 +489,9 @@ msgstr "Dolů (\\key gdown;)" msgid "Drawer bot" msgstr "Tužkobot" +msgid "Duplicate label in switch" +msgstr "" + msgid "Dust\\Dust and dirt on bots and buildings" msgstr "Prach\\Prach a špína na robotech a budovách" @@ -507,6 +510,9 @@ msgstr "Upravit vybraný program" msgid "Egg" msgstr "Vejce" +msgid "Empty character constant" +msgstr "" + msgid "End of block missing" msgstr "Chybí konec bloku" @@ -1193,7 +1199,7 @@ msgid "Programming help\\Gives more detailed help with programming" msgstr "Nápověda\\Zobrazí nápovědu pro psaní programů" msgid "Programs dispatched by Houston" -msgstr "Program poslaný z Houstonu" +msgstr "Programy poslané z Houstonu" msgid "Public required" msgstr "Tato definice musí být veřejná (public)" @@ -1546,6 +1552,10 @@ msgstr "Úder (\\key action;)" msgid "Thumper" msgstr "Buchar" +#, c-format +msgid "Time: %s" +msgstr "Čas: %s" + msgid "Titanium" msgstr "Titan" @@ -1660,6 +1670,9 @@ msgstr "Proměnná nebyla nastavena" msgid "Vault" msgstr "Trezor" +msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" +msgstr "" + msgid "Violet flag" msgstr "Fialová vlajka" @@ -1737,7 +1750,7 @@ msgid "You cannot use \"%s\" in this exercise (used: %d)" msgstr "V tomto cvičení nesmíte použít \"%s\" (použito: %dx)" msgid "You found a usable object" -msgstr "Našli jste fungující objekt" +msgstr "Našli jste použitelný objekt" #, c-format msgid "You have to use \"%1$s\" at least once in this exercise (used: %2$d)" diff --git a/po/de.po b/po/de.po index 1c839a09..f031a049 100644 --- a/po/de.po +++ b/po/de.po @@ -490,6 +490,9 @@ msgstr "Sinkt (\\key gdown;)" msgid "Drawer bot" msgstr "Zeichner" +msgid "Duplicate label in switch" +msgstr "" + msgid "Dust\\Dust and dirt on bots and buildings" msgstr "Schmutz\\Schmutz auf Robotern und Bauten" @@ -508,6 +511,9 @@ msgstr "Gewähltes Programm bearbeiten" msgid "Egg" msgstr "Ei" +msgid "Empty character constant" +msgstr "" + msgid "End of block missing" msgstr "Es fehlt eine geschlossene geschweifte Klammer \"}\" (Ende des Blocks)" @@ -1563,6 +1569,10 @@ msgstr "Stampfen (\\key action;)" msgid "Thumper" msgstr "Stampfer" +#, c-format +msgid "Time: %s" +msgstr "" + msgid "Titanium" msgstr "Titan" @@ -1677,6 +1687,9 @@ msgstr "Der Wert dieser Variable wurde nicht definiert" msgid "Vault" msgstr "Bunker" +msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" +msgstr "" + msgid "Violet flag" msgstr "Violette Fahne" diff --git a/po/fr.po b/po/fr.po index 1dd2d7f4..add42032 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1,20 +1,21 @@ # Didier Raboud , 2012, 2015, 2016. -# Martin Quinson , 2016 -# B-CE, 2018 - +# Martin Quinson , 2016. +# B-CE <.>, 2018, 2019. +# Pascal Audoux , 2018. msgid "" msgstr "" -"Project-Id-Version: Colobot 0.1.11\n" +"Project-Id-Version: Colobot 0.1.12\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: DATE\n" -"PO-Revision-Date: 2018-02-28 20:00+0100\n" -"Last-Translator: B-CE\n" +"PO-Revision-Date: 2019-06-13 01:31+0200\n" +"Last-Translator: BCE <.>\n" +"Language-Team: French <>\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Lokalize 2.0\n" +"X-Generator: Lokalize 18.12.3\n" "X-Language: fr_FR\n" "X-Source-Language: en_US\n" @@ -38,7 +39,7 @@ msgid "..in front" msgstr "..devant" msgid "..power cell" -msgstr "..pile" +msgstr "..batterie" msgid "1) First click on the key you want to redefine." msgstr "1) Cliquez d'abord sur la touche à redéfinir." @@ -140,10 +141,10 @@ msgid "Automatic indent\\When program editing" msgstr "Indentation automatique\\Pendant l'édition d'un programme" msgid "Autosave interval\\How often your game will autosave" -msgstr "Interval d'auto-sauvegarde\\À quels intervals les parties vont-t-elles êtres sauvegardées automatiquement" +msgstr "Interval auto-sauvegarde\\À quels intervals les parties vont-t-elles êtres sauvegardées automatiquement" msgid "Autosave slots\\How many autosave slots you'll have" -msgstr "Nombre d'auto-sauvegardes\\Combien d'auto-sauvegarde seront conservées" +msgstr "Nb auto-sauvegardes\\Combien d'auto-sauvegarde seront conservées" msgid "Autosave\\Enables autosave" msgstr "Auto-sauvegarde\\Activer l'auto-sauvegarde" @@ -174,10 +175,10 @@ msgstr "Sang\\Afficher du sang quand le cosmonaute est touché" msgid "Blue" msgstr "Bleue" + # tocheck : for team (fem): bleue # tocheck : for flag/pen/bot (masc): bleu # + capital also to check - msgid "Blue flag" msgstr "Drapeau bleu" @@ -185,13 +186,13 @@ msgid "Bot destroyed" msgstr "Robot détruit" msgid "Bot factory" -msgstr "Fabrique de robots" +msgstr "Usine de robots" msgid "Build a bot factory" -msgstr "Construire une fabrique de robots" +msgstr "Construire une usine de robots" msgid "Build a converter" -msgstr "Construire un convertisseur" +msgstr "Construire une raffinerie" msgid "Build a defense tower" msgstr "Construire une tour" @@ -203,10 +204,10 @@ msgid "Build a destroyer" msgstr "Construire un destructeur" msgid "Build a exchange post" -msgstr "Construire une borne d'information" +msgstr "Construire une station relais" msgid "Build a legged grabber" -msgstr "Fabriquer un déménageur à pattes" +msgstr "Fabriquer un préhenseur à pattes" msgid "Build a legged orga shooter" msgstr "Fabriquer un tireur organique à pattes" @@ -224,10 +225,10 @@ msgid "Build a nuclear power plant" msgstr "Construire une centrale nucléaire" msgid "Build a phazer shooter" -msgstr "Fabriquer un robot canon à phases" +msgstr "Fabriquer un robot canon hachoir" msgid "Build a power cell factory" -msgstr "Construire une fabrique de piles" +msgstr "Construire une fabrique de batteries" msgid "Build a power station" msgstr "Construire une station de recharge" @@ -254,7 +255,7 @@ msgid "Build a thumper" msgstr "Fabriquer un robot secoueur" msgid "Build a tracked grabber" -msgstr "Fabriquer un déménageur à chenilles" +msgstr "Fabriquer un préhenseur à chenilles" msgid "Build a tracked orga shooter" msgstr "Fabriquer un tireur organique à chenilles" @@ -266,7 +267,7 @@ msgid "Build a tracked sniffer" msgstr "Fabriquer un renifleur à chenilles" msgid "Build a wheeled grabber" -msgstr "Fabriquer un déménageur à roues" +msgstr "Fabriquer un préhenseur à roues" msgid "Build a wheeled orga shooter" msgstr "Fabriquer un tireur organique à roues" @@ -278,7 +279,7 @@ msgid "Build a wheeled sniffer" msgstr "Fabriquer un renifleur à roues" msgid "Build a winged grabber" -msgstr "Fabriquer un déménageur volant" +msgstr "Fabriquer un préhenseur volant" msgid "Build a winged orga shooter" msgstr "Fabriquer un tireur organique volant" @@ -314,19 +315,19 @@ msgid "Camera border scrolling\\Scrolling when the mouse touches right or left b msgstr "Défilement dans les bords\\Défilement lorsque la souris touche les bords gauche ou droite" msgid "Camera closer\\Moves the camera forward" -msgstr "Caméra plus proche\\Avance la caméra" +msgstr "Plus proche\\Avance la caméra" msgid "Camera down\\Turns the camera down" -msgstr "Baisser caméra\\Baisse la caméra" +msgstr "Plus bas\\Tourne la caméra vers le bas" msgid "Camera left\\Turns the camera left" -msgstr "Caméra à gauche\\Tourne la caméra vers la gauche" +msgstr "À gauche\\Tourne la caméra vers la gauche" msgid "Camera right\\Turns the camera right" -msgstr "Caméra à droite\\Tourne la caméra vers la droite" +msgstr "À droite\\Tourne la caméra vers la droite" msgid "Camera up\\Turns the camera up" -msgstr "Lever caméra\\Monte la caméra" +msgstr "Plus haut\\Tourne la caméra vers le haut" msgid "Can not produce not researched object" msgstr "Impossible de créer un objet n'ayant pas été recherché" @@ -365,7 +366,7 @@ msgid "Cheat console\\Show cheat console" msgstr "Console de triche\\Montre la console de triche" msgid "Checkpoint" -msgstr "Indicateur" +msgstr "Point de passage" msgid "Class name expected" msgstr "Nom de classe attendu" @@ -385,9 +386,8 @@ msgstr "Fermer" msgid "Closing bracket missing" msgstr "Il manque une parenthèse fermante" -#, fuzzy msgid "Code battle" -msgstr "Batailles de code" +msgstr "Bataille de code" msgid "Code battles" msgstr "Batailles de code" @@ -420,7 +420,7 @@ msgid "Controls\\Keyboard, joystick and mouse settings" msgstr "Commandes\\Touches du clavier" msgid "Converts ore to titanium" -msgstr "Conversion de minerai en titane" +msgstr "Raffinage de minerai en titane" msgid "Copy" msgstr "Copier" @@ -492,6 +492,9 @@ msgstr "Descend (\\key gdown;)" msgid "Drawer bot" msgstr "Robot dessinateur" +msgid "Duplicate label in switch" +msgstr "" + msgid "Dust\\Dust and dirt on bots and buildings" msgstr "Salissures\\Salissures des robots et bâtiments" @@ -502,7 +505,7 @@ msgid "Dynamic shadows ++\\Dynamic shadows + self shadowing" msgstr "Ombres dynamiques ++\\Active les ombres dynamiques et l'auto-ombrage" msgid "Dynamic shadows\\Beautiful shadows!" -msgstr "Ombres dynamiques\\Magnifiques ombres !" +msgstr "Ombres dynamiques\\Magnifiques ombres !" msgid "Edit the selected program" msgstr "Éditer le programme sélectionné" @@ -510,11 +513,14 @@ msgstr "Éditer le programme sélectionné" msgid "Egg" msgstr "Oeuf" +msgid "Empty character constant" +msgstr "" + msgid "End of block missing" msgstr "Il manque la fin du bloc" msgid "Energy deposit (site for power station)" -msgstr "Emplacement pour une station de recharge ou une fabrique de pile" +msgstr "Sous sol énergétique (Emplacement pour une station de recharge ou une fabrique de batteries)" msgid "Energy level" msgstr "Niveau d'énergie" @@ -566,10 +572,10 @@ msgstr "Séquences cinématiques\\Films avant ou après une mission" msgid "Finish" msgstr "But/Objectif" -# OBJECT_END : GoalArea +# OBJECT_END : GoalArea msgid "Fixed mine" -msgstr "Mine fixe" +msgstr "Mine anti-personnel" msgid "Flat ground not large enough" msgstr "Sol plat pas assez grand" @@ -600,7 +606,7 @@ msgid "Found a site for a derrick" msgstr "Emplacement pour un derrick trouvé" msgid "Found a site for power station" -msgstr "Emplacement pour station de recharge ou fabrique de pile trouvé" +msgstr "Emplacement pour station de recharge ou fabrique de batteries trouvé" msgid "Found key A (site for derrick)" msgstr "Emplacement pour un derrick (clé A)" @@ -648,7 +654,7 @@ msgid "Generating" msgstr "Génération" msgid "Gold Edition development by:" -msgstr "Édition Gold développée par :" +msgstr "Édition Gold développée par :" msgid "Goto: destination occupied" msgstr "Goto: destination occupée" @@ -686,9 +692,8 @@ msgstr "Bulles d'aide\\Bulles explicatives" msgid "Hex value out of range" msgstr "Valeur hexadécimale impossible" -#, fuzzy msgid "Higher speed\\Doubles speed" -msgstr "Vitesse 2.0x\\Deux fois plus rapide" +msgstr "Vitesse augmentée\\Deux fois plus rapide" msgid "Highest\\Highest graphic quality (lowest frame rate)" msgstr "Maxi\\Haute qualité (+ lent)" @@ -721,7 +726,7 @@ msgid "Inappropriate bot" msgstr "Robot inadapté" msgid "Inappropriate cell type" -msgstr "Pas le bon type de pile" +msgstr "Source d'énergie non adapté" msgid "Inappropriate object" msgstr "Pas le bon objet" @@ -733,7 +738,7 @@ msgid "Infected by a virus; temporarily out of order" msgstr "Infecté par un virus; ne fonctionne plus temporairement" msgid "Information exchange post" -msgstr "Borne d'information" +msgstr "Station relais" msgid "Instruction \"break\" outside a loop" msgstr "Instruction \"break\" en dehors d'une boucle" @@ -796,7 +801,7 @@ msgid "LOADING" msgstr "CHARGEMENT" msgid "Legged grabber" -msgstr "Robot déménageur à pattes" +msgstr "Robot préhenseur à pattes" msgid "Legged orga shooter" msgstr "Robot tireur organique à pattes" @@ -832,7 +837,7 @@ msgid "Loading basic level settings" msgstr "Chargement des configurations de base du niveau" msgid "Loading finished!" -msgstr "Chargement terminé !" +msgstr "Chargement terminé !" msgid "Loading music" msgstr "Chargement de la musique" @@ -857,7 +862,6 @@ msgstr "Chargement du terrain" # msgstr "" # msgid "Speed 6.0x\\Sextuple speed" # msgstr "" - msgid "Lower speed\\Decrease speed by half" msgstr "Moins rapide\\Diminuer la vitesse de moitié" @@ -868,7 +872,7 @@ msgid "Lunar Roving Vehicle" msgstr "Véhicule d'exploration lunaire" msgid "MSAA\\Multisample anti-aliasing" -msgstr "ACME\\Anticrénelage multiéchantillon" +msgstr "ACME\\Anticrénelage multiéchantillon (MSAA: Multisample anti-aliasing)" msgid "Maximize" msgstr "Taille maximale" @@ -955,7 +959,7 @@ msgid "No function with this name accepts this number of parameters" msgstr "Aucune fonction de ce nom n'accepte ce nombre de paramètres" msgid "No information exchange post within range" -msgstr "Pas de borne d'information accessible" +msgstr "Pas de station relais accessible" msgid "No more energy" msgstr "Plus d'énergie" @@ -964,7 +968,7 @@ msgid "No ore in the subsoil" msgstr "Pas de minerai en sous-sol" msgid "No power cell" -msgstr "Pas de pile" +msgstr "Pas de source d'énergie" msgid "No titanium" msgstr "Pas de titane" @@ -973,7 +977,7 @@ msgid "No titanium around" msgstr "Pas de titane accessible" msgid "No titanium ore to convert" -msgstr "Pas de minerai de titane à convertir" +msgstr "Pas de minerai de titane à raffiner" msgid "No titanium to transform" msgstr "Pas de titane à transformer" @@ -982,7 +986,7 @@ msgid "No uranium to transform" msgstr "Pas de minerai d'uranium à transformer" 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 "Les fonctions avec retour autre que void doivent comporter l'instruction \"return;\"" @@ -1018,10 +1022,10 @@ msgid "Nothing to recycle" msgstr "Rien à recycler" msgid "Nuclear power cell" -msgstr "Pile nucléaire" +msgstr "Pile atomique" msgid "Nuclear power cell available" -msgstr "Pile nucléaire disponible" +msgstr "Pile atomique disponible" msgid "Nuclear power station" msgstr "Centrale nucléaire" @@ -1042,7 +1046,7 @@ msgid "OK\\Choose the selected player" msgstr "D'accord\\Choisir le joueur" msgid "OK\\Close program editor and return to game" -msgstr "D'accord\\Compiler le programme" +msgstr "D'accord\\Compiler le programme et fermer la fenêtre d'édition" msgid "Object too close" msgstr "Objet trop proche" @@ -1105,7 +1109,7 @@ msgid "Pause\\Pause the game without opening menu" msgstr "Pause\\Mettre le jeu en pause sans ouvrir le menu" msgid "Phazer shooter" -msgstr "Robot canon à phases" +msgstr "Robot canon hachoir" msgid "Photography" msgstr "Vue de la mission" @@ -1123,7 +1127,7 @@ msgid "Plans for nuclear power plant available" msgstr "Construction d'une centrale nucléaire possible" msgid "Plans for phazer shooter available" -msgstr "Fabrication des robots canon à phases possible" +msgstr "Fabrication des robots canon hachoir possible" msgid "Plans for shielder available" msgstr "Fabrication d'un robot bouclier possible" @@ -1153,13 +1157,13 @@ msgid "Player's name" msgstr "Nom du joueur" msgid "Power cell" -msgstr "Pile normale" +msgstr "Batterie standard" msgid "Power cell available" -msgstr "Pile disponible" +msgstr "Batterie disponible" msgid "Power cell factory" -msgstr "Fabrique de piles" +msgstr "Fabrique de batteries" msgid "Power station" msgstr "Station de recharge" @@ -1230,15 +1234,14 @@ msgstr "Chargement rapide\\Chargement direct d'une sauvegarde" msgid "Quick save\\Immediately save game" msgstr "Sauvegarde rapide\\Sauvegarde direct" -#, fuzzy msgid "Quicksave slot not found" -msgstr "Objet n'existe pas" +msgstr "Emplacement de sauvegarde rapide non trouvé" msgid "Quit\\Quit Colobot: Gold Edition" -msgstr "Quitter\\Quitter Colobot : Édition Gold" +msgstr "Quitter\\Quitter Colobot : Édition Gold" msgid "Quit\\Quit the current mission or exercise" -msgstr "Quitter la mission en cours\\Terminer un exercice ou une mssion" +msgstr "Quitter la mission en cours\\Terminer un exercice ou une mission" msgid "Radar station" msgstr "Radar" @@ -1257,8 +1260,8 @@ msgstr "Robot recycleur" msgid "Red" msgstr "Rouge" -# toCheck : capital (for team?) +# toCheck : capital (for team?) msgid "Red flag" msgstr "Drapeau rouge" @@ -1323,34 +1326,34 @@ msgid "Ruin" msgstr "Bâtiment en ruine" msgid "Run research program for defense tower" -msgstr "Recherche la tour de défense" +msgstr "Lancer la recherche de la tour de défense" msgid "Run research program for legged bots" -msgstr "Recherche du fonctionnement des pattes" +msgstr "Lancer la recherche du fonctionnement des pattes" msgid "Run research program for nuclear power" -msgstr "Recherche du programme nucléaire" +msgstr "Lancer la recherche du programme nucléaire" msgid "Run research program for orga shooter" -msgstr "Recherche le canon organique" +msgstr "Lancer la recherche du canon organique" msgid "Run research program for phazer shooter" -msgstr "Recherche le canon à phases" +msgstr "Lancer la recherche du canon hachoir" msgid "Run research program for shielder" -msgstr "Recherche le bouclier" +msgstr "Lancer la recherche du bouclier" msgid "Run research program for shooter" -msgstr "Recherche le canon de tir" +msgstr "Lancer la recherche du canon de tir" msgid "Run research program for thumper" -msgstr "Recherche le secoueur" +msgstr "Lancer la recherche du secoueur" msgid "Run research program for tracked bots" -msgstr "Recherche du fonctionnement des chenilles" +msgstr "Lancer la recherche du fonctionnement des chenilles" msgid "Run research program for winged bots" -msgstr "Recherche du fonctionnement du jet" +msgstr "Lancer la recherche du fonctionnement du jet" msgid "SatCom" msgstr "SatCom" @@ -1443,7 +1446,7 @@ msgid "Spaceship" msgstr "Vaisseau spatial" msgid "Spaceship ruin" -msgstr "Epave de vaisseau spatial" +msgstr "Épave de vaisseau spatial" msgid "Spider" msgstr "Araignée" @@ -1500,7 +1503,7 @@ msgid "Switch bots <-> buildings" msgstr "Permute robots <-> bâtiments" msgid "Take off to finish the mission" -msgstr "Décolle pour terminer la mission" +msgstr "Décollage pour terminer la mission" msgid "Target" msgstr "Cible" @@ -1563,11 +1566,15 @@ msgid "This program is read-only, clone it to edit" msgstr "Ce programme est en lecture-seule, le dupliquer pour pouvoir le modifier" msgid "Thump (\\key action;)" -msgstr "Secoue (\\key action;)" +msgstr "Secouer (\\key action;)" msgid "Thumper" msgstr "Robot secoueur" +#, c-format +msgid "Time: %s" +msgstr "Temps : %s" + msgid "Titanium" msgstr "Titane" @@ -1602,7 +1609,7 @@ msgid "Too many parameters" msgstr "Trop de paramètres" msgid "Tracked grabber" -msgstr "Robot déménageur à chenilles" +msgstr "Robot préhenseur à chenilles" msgid "Tracked orga shooter" msgstr "Robot tireur organique à chenilles" @@ -1653,7 +1660,7 @@ msgid "Unknown command" msgstr "Commande inconnue" msgid "Unknown escape sequence" -msgstr "" +msgstr "Séquence d'échappement inconnue" msgid "Unknown function" msgstr "Routine inconnue" @@ -1682,6 +1689,9 @@ msgstr "Variable non initialisée" msgid "Vault" msgstr "Coffre-fort" +msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" +msgstr "Synchronisation verticale :\\Réduit la fréquence d'images par seconde à afficher." + msgid "Violet flag" msgstr "Drapeau violet" @@ -1698,7 +1708,7 @@ msgid "Waste" msgstr "Déchet" msgid "Wheeled grabber" -msgstr "Robot déménageur à roues" +msgstr "Robot préhenseur à roues" msgid "Wheeled orga shooter" msgstr "Robot tireur organique à roues" @@ -1710,7 +1720,7 @@ msgid "Wheeled sniffer" msgstr "Robot renifleur à roues" msgid "Winged grabber" -msgstr "Robot déménageur volant" +msgstr "Robot préhenseur volant" msgid "Winged orga shooter" msgstr "Robot tireur organique volant" @@ -1731,7 +1741,7 @@ msgid "Worm fatally wounded" msgstr "Ver mortellement touché" msgid "Wreckage" -msgstr "Epave de robot" +msgstr "Épave de robot" msgid "Write error" msgstr "Erreur lors de l'écriture" @@ -1816,7 +1826,7 @@ msgid "\\New player name" msgstr "\\Nom du joueur à créer" msgid "\\No eyeglasses" -msgstr "\\Pas de lunettes" +msgstr "\\Pas de lunette" msgid "\\Raise the pencil" msgstr "\\Relève le crayon" @@ -1825,7 +1835,7 @@ msgid "\\Red flags" msgstr "\\Drapeaux rouges" msgid "\\Return to Colobot: Gold Edition" -msgstr "\\Revenir à Colobot : Édition Gold" +msgstr "\\Revenir à Colobot : Édition Gold" msgid "\\SatCom on standby" msgstr "\\Mettre le SatCom en veille" @@ -1878,9 +1888,6 @@ msgstr "colobot.info" msgid "epsitec.com" msgstr "epsitec.com" -#~ msgid " " -#~ msgstr " " - #~ msgid " Drivers:" #~ msgstr " Pilotes :" diff --git a/po/pl.po b/po/pl.po index bb288518..2ddf9832 100644 --- a/po/pl.po +++ b/po/pl.po @@ -365,7 +365,7 @@ msgid "Checkpoint" msgstr "Punkt kontrolny" msgid "Class name expected" -msgstr "" +msgstr "Oczekiwano nazwy klasy" msgid "Climb\\Increases the power of the jet" msgstr "W górę\\Zwiększa moc silnika" @@ -488,6 +488,9 @@ msgstr "Dół (\\key gdown;)" msgid "Drawer bot" msgstr "Robot rysownik" +msgid "Duplicate label in switch" +msgstr "" + msgid "Dust\\Dust and dirt on bots and buildings" msgstr "Kurz\\Kurz i bród na robotach i budynkach" @@ -506,6 +509,9 @@ msgstr "Edytuj zaznaczony program" msgid "Egg" msgstr "Jajo" +msgid "Empty character constant" +msgstr "" + msgid "End of block missing" msgstr "Brak końca bloku" @@ -628,7 +634,7 @@ msgid "Function name missing" msgstr "Brakująca nazwa funkcji" msgid "Function needs return type \"void\"" -msgstr "" +msgstr "Funkcja potrzebuje typu zwracanego \"void\"" msgid "Game speed" msgstr "Prędkość gry" @@ -679,7 +685,7 @@ msgid "Help balloons\\Explain the function of the buttons" msgstr "Dymki pomocy\\Wyjaśnia funkcje przycisków" msgid "Hex value out of range" -msgstr "" +msgstr "Wartość heksadecymalna poza zakresem" msgid "Higher speed\\Doubles speed" msgstr "Zwiększ prędkość\\Podwaja prędkość" @@ -859,10 +865,10 @@ msgid "Mipmap level\\Mipmap level" msgstr "Poziom mipmap\\Poziom mipmap" msgid "Missing end quote" -msgstr "" +msgstr "Brak cudzysłowu zamykającego" msgid "Missing hex digits after escape sequence" -msgstr "" +msgstr "Brak cyfr heksadecymalnych po znaku ucieczki" msgid "Mission name" msgstr "Nazwa misji" @@ -964,7 +970,7 @@ msgid "No userlevels installed!" msgstr "Brak zainstalowanych poziomów użytkownika!" msgid "Non-void function needs \"return;\"" -msgstr "" +msgstr "Funkcja zwracająca typ inny, niż \"void\", wymaga \"return;\"" msgid "Normal size" msgstr "Normalna wielkość" @@ -1027,7 +1033,7 @@ msgid "Object too close" msgstr "Obiekt za blisko" msgid "Octal value out of range" -msgstr "" +msgstr "Wartość ósemkowa poza zakresem" msgid "One step" msgstr "Jeden krok" @@ -1072,7 +1078,7 @@ msgid "Paste (Ctrl+V)" msgstr "Wklej (Ctrl+V)" msgid "Pause blur\\Blur the background on the pause screen" -msgstr "" +msgstr "Rozmyta pauza\\Rozmyj tło na ekranie pauzy" msgid "Pause in background\\Pause the game when the window is unfocused" msgstr "Wstrzymaj w tle\\Wstrzymaj grę gdy okno stanie się nieaktywne" @@ -1534,7 +1540,7 @@ msgid "This object is not a member of a class" msgstr "Ten obiekt nie jest członkiem klasy" msgid "This parameter needs a default value" -msgstr "" +msgstr "Ten parametr wymaga podania domyślnej wartości" msgid "This program is read-only, clone it to edit" msgstr "Ten program jest tylko do odczytu, skopiuj go, aby edytować" @@ -1545,6 +1551,10 @@ msgstr "Uderz (\\key action;)" msgid "Thumper" msgstr "Uderzacz" +#, c-format +msgid "Time: %s" +msgstr "Czas: %s" + msgid "Titanium" msgstr "Tytan" @@ -1659,6 +1669,9 @@ msgstr "Zmienna nie została zainicjalizowana" msgid "Vault" msgstr "Skrytka" +msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" +msgstr "Synchronizacja pionowa\\Ogranicza ilość klatek na sekundę do wartości odświeżania ekranu" + msgid "Violet flag" msgstr "Fioletowa flaga" diff --git a/po/pt.po b/po/pt.po new file mode 100644 index 00000000..06bb43e3 --- /dev/null +++ b/po/pt.po @@ -0,0 +1,2055 @@ +# José Robson Mariano Alves , 2018. +msgid "" +msgstr "" +"Project-Id-Version: Colobot Alpha\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: DATE\n" +"PO-Revision-Date: 2018-04-17 10:39-0300\n" +"Last-Translator: José Robson Mariano Alves \n" +"Language-Team: Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 2.0\n" +"X-Language: pt_BR\n" +"X-Source-Language: en_US\n" + +msgid " or " +msgstr " ou " + +msgid "\" [ \" expected" +msgstr "\" [ \" esperado" + +msgid "\" ] \" missing" +msgstr "\" ] \" faltando" + +#, c-format +msgid "%s: %d pts" +msgstr "" + +msgid "..behind" +msgstr "..atrás" + +msgid "..in front" +msgstr "..em frente" + +msgid "..power cell" +msgstr "..célula de energia" + +msgid "1) First click on the key you want to redefine." +msgstr "1) Primeiro clique na chave que você quer redefinir." + +msgid "2) Then press the key you want to use instead." +msgstr "2) Então pressione a chave que você quer usar no lugar." + +msgid "<< Back \\Back to the previous screen" +msgstr "<< Voltar \\Voltar para a tela anterior" + +msgid "<<< Sorry; mission failed >>>" +msgstr "<<< Desculpe; missão fracassada >>>" + +#, c-format +msgid "<<< Team %s finished! >>>" +msgstr "<<< Time %s terminou! >>>" + +#, c-format +msgid "<<< Team %s lost! >>>" +msgstr "<<< Time %s perdeu! >>>" + +#, c-format +msgid "<<< Team %s recieved %d points >>>" +msgstr "<<< Time %s recebeu %d pontos >>>" + +msgid "<<< Well done; mission accomplished >>>" +msgstr "<<< Bem feito; missão cumprida >>>" + +msgid "A label must be followed by \"for\"; \"while\"; \"do\" or \"switch\"" +msgstr "Um rótulo deve ser precedido por um \"for\"; \"while\"; \"do\" ou um \"switch\"" + +msgid "A variable can not be declared twice" +msgstr "Uma variável não pode ser declarada duas vezes" + +msgid "Abort\\Abort the current mission" +msgstr "Abortar\\Abortar a missão atual" + +msgid "Access beyond array limit" +msgstr "Acesso além dos limites da matriz" + +msgid "Access to solution\\Shows the solution (detailed instructions for missions)" +msgstr "Acesso a solução\\Exibe a solução (instruções detalhadas para missões)" + +msgid "Access to solutions\\Show program \"4: Solution\" in the exercises" +msgstr "Acesso as soluções\\Exibir programa \"4: Solução\" nos exercícios" + +msgid "Add new program" +msgstr "Adicionar novo programa" + +msgid "Alien Queen" +msgstr "Rainha Alienígena" + +msgid "Alien Queen killed" +msgstr "Rainha Alienígena morta" + +msgid "Already carrying something" +msgstr "Já está carregando algo" + +msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)" +msgstr "Modo de câmera alternativo\\Move de lado em vez de rotacionar (em câmera livre)" + +msgid "Ambiguous call to overloaded function" +msgstr "Chamada ambígua a uma função sobrecarregada" + +msgid "Analysis already performed" +msgstr "Análise já realizada" + +msgid "Analysis performed" +msgstr "Análise realizada" + +msgid "Analyzes only organic matter" +msgstr "Analisa apenas matéria orgânica" + +msgid "Anisotropy level\\Anisotropy level" +msgstr "Nível de anisotropia\\Nível de anisotropia" + +msgid "Ant" +msgstr "Formiga" + +msgid "Ant fatally wounded" +msgstr "Formiga gravemente ferida" + +msgid "Appearance\\Choose your appearance" +msgstr "Aparência\\Escolha sua aparência" + +msgid "Apply changes\\Activates the changed settings" +msgstr "Aplicar mudanças\\Ativa as configurações alteradas" + +msgid "Appropriate constructor missing" +msgstr "Construtor apropriado faltando" + +msgid "Assignment impossible" +msgstr "Tarefa impossível" + +msgid "Autolab" +msgstr "Laboratório de matérias orgânicas" + +msgid "Automatic indent\\When program editing" +msgstr "Indentação automática\\Enquanto editando programa" + +msgid "Autosave interval\\How often your game will autosave" +msgstr "Intervalo de salvamento automático\\Com que frequência seu jogo irá auto-salvar" + +msgid "Autosave slots\\How many autosave slots you'll have" +msgstr "Slots de salvamento automático\\Quantos slots de salvamento automático você terá" + +msgid "Autosave\\Enables autosave" +msgstr "Salvamento automático\\Ativa o salvamento automático" + +msgid "Back" +msgstr "Voltar" + +msgid "Background sound:\\Volume of audio tracks" +msgstr "Som de fundo:\\Volume das trilhas de áudio" + +msgid "Backward (\\key down;)" +msgstr "Retroceder (\\key down;)" + +msgid "Backward\\Moves backward" +msgstr "Retroceder\\Move para trás" + +msgid "Bad argument for \"new\"" +msgstr "Argumento inválido para \"new\"" + +msgid "Big indent\\Indent 2 or 4 spaces per level defined by braces" +msgstr "Grande indentação\\Indente 2 ou 4 espaços por nível definido por colchetes" + +msgid "Black box" +msgstr "Caixa preta" + +msgid "Blood\\Display blood when the astronaut is hit" +msgstr "Sangue\\Exibe sangue quando o astronauta é atingido" + +msgid "Blue" +msgstr "Azul" + +msgid "Blue flag" +msgstr "Bandeira azul" + +msgid "Bot destroyed" +msgstr "Robo destruido" + +msgid "Bot factory" +msgstr "Fábrica de robos" + +msgid "Build a bot factory" +msgstr "Construir uma fábrica de robos" + +msgid "Build a converter" +msgstr "Construir um conversor" + +msgid "Build a defense tower" +msgstr "Construir uma torre de defesa" + +msgid "Build a derrick" +msgstr "Construir um extrator" + +msgid "Build a destroyer" +msgstr "Construir um destruidor" + +msgid "Build a exchange post" +msgstr "Construir um posto de troca" + +msgid "Build a legged grabber" +msgstr "Construir um agarrador com pernas" + +msgid "Build a legged orga shooter" +msgstr "Construir um atirador orgânico com pernas" + +msgid "Build a legged shooter" +msgstr "Construir um atirador com pernas" + +msgid "Build a legged sniffer" +msgstr "Construir um farejador com pernas" + +msgid "Build a lightning conductor" +msgstr "Construir um condutor elétrico" + +msgid "Build a nuclear power plant" +msgstr "Construir uma planta de energia nuclear" + +msgid "Build a phazer shooter" +msgstr "Construir um atirador phazer" + +msgid "Build a power cell factory" +msgstr "Construir uma fábrica de células de energia" + +msgid "Build a power station" +msgstr "Construir uma estação de energia" + +msgid "Build a radar station" +msgstr "Construir uma estação de radar" + +msgid "Build a recycler" +msgstr "Construir um reciclador" + +msgid "Build a repair center" +msgstr "Construir um centro de reparação" + +msgid "Build a research center" +msgstr "Construir um centro de pesquisa" + +msgid "Build a shielder" +msgstr "Construir um defensor" + +msgid "Build a subber" +msgstr "Construir um mergulhador" + +msgid "Build a thumper" +msgstr "Construir um batedor" + +msgid "Build a tracked grabber" +msgstr "Construir um agarrador com esteiras" + +msgid "Build a tracked orga shooter" +msgstr "Construir um atirador orgânico com esteiras" + +msgid "Build a tracked shooter" +msgstr "Construir um atirador com esteiras" + +msgid "Build a tracked sniffer" +msgstr "Construir um farejador com esteiras" + +msgid "Build a wheeled grabber" +msgstr "Construir um agarrador com rodas" + +msgid "Build a wheeled orga shooter" +msgstr "Construir um atirador orgânico com rodas" + +msgid "Build a wheeled shooter" +msgstr "Construir um atirador com rodas" + +msgid "Build a wheeled sniffer" +msgstr "Construir um farejador com rodas" + +msgid "Build a winged grabber" +msgstr "Construir um agarrador alado" + +msgid "Build a winged orga shooter" +msgstr "Construir um atirador orgânico alado" + +msgid "Build a winged shooter" +msgstr "Construir um atirador alado" + +msgid "Build a winged sniffer" +msgstr "Construir um farejador alado" + +msgid "Build an autolab" +msgstr "Construir um laboratório" + +msgid "Building completed" +msgstr "Construção completada" + +msgid "Building destroyed" +msgstr "Construção destruida" + +msgid "Button %1" +msgstr "Botão %1" + +msgid "Calling an unknown function" +msgstr "Chamando uma função desconhecida" + +msgid "Camera (\\key camera;)" +msgstr "Câmera (\\key camera;)" + +msgid "Camera back\\Moves the camera backward" +msgstr "Voltar câmera\\Move a câmera para trás" + +msgid "Camera border scrolling\\Scrolling when the mouse touches right or left border" +msgstr "Rolagem de borda da câmera\\Rola quando o mouse toca a borda esquerda ou direita" + +msgid "Camera closer\\Moves the camera forward" +msgstr "Câmera mais perto\\Move a câmera para frente" + +msgid "Camera down\\Turns the camera down" +msgstr "Baixar câmera\\Vira a câmera para baixo" + +msgid "Camera left\\Turns the camera left" +msgstr "Câmera a esquerda\\Gira a câmera para a esquerda" + +msgid "Camera right\\Turns the camera right" +msgstr "Câmera a direita\\Gira a câmera para a direita" + +msgid "Camera up\\Turns the camera up" +msgstr "Subir câmera\\Gira a câmera para cima" + +msgid "Can not produce not researched object" +msgstr "Impossível produzir objetos não pesquisados" + +msgid "Can not produce this object in this mission" +msgstr "Impossível produzir este objeto nesta missão" + +msgid "Can't open file" +msgstr "Não é possível abrir o arquivo" + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Cancel\\Cancel all changes" +msgstr "Cancelar\\Cancela todas as mudanças" + +msgid "Challenges" +msgstr "Desafios" + +msgid "Challenges in the chapter:" +msgstr "Desafios no capítulo:" + +msgid "Challenges\\Programming challenges" +msgstr "Desafios\\Desafios de programação" + +msgid "Change camera\\Switches between onboard camera and following camera" +msgstr "Mudar câmera\\Alterna entre câmera incorporada e câmera seguidora" + +msgid "Change player\\Change player" +msgstr "Mudar jogador\\Mudar jogador" + +msgid "Chapters:" +msgstr "Capítulos:" + +msgid "Cheat console\\Show cheat console" +msgstr "Console de cheats\\Mostrar console de cheats" + +msgid "Checkpoint" +msgstr "Ponto de verificação" + +msgid "Class name expected" +msgstr "Nome de classe experado" + +msgid "Climb\\Increases the power of the jet" +msgstr "Subir\\Aumenta o poder do jato" + +msgid "Clone program" +msgstr "Clonar programa" + +msgid "Clone selected program" +msgstr "Clonar o programa selecionado" + +msgid "Close" +msgstr "Fechar" + +msgid "Closing bracket missing" +msgstr "Colchete de fechamento ausente" + +#, fuzzy +msgid "Code battle" +msgstr "Batalha de código" + +msgid "Code battles" +msgstr "Batalhas de código" + +msgid "Code battles\\Program your robot to be the best of them all!" +msgstr "Batalhas de código\\Programe seu robô para ser o melhor de todos!" + +msgid "Colobot rules!" +msgstr "Regras Colobot!" + +msgid "Colobot: Gold Edition" +msgstr "Colobot: Edição de ouro" + +msgid "Command line" +msgstr "Linha de comando" + +msgid "Compilation ok (0 errors)" +msgstr "Compilação ok (0 erros)" + +msgid "Compile" +msgstr "Compilar" + +msgid "Continue" +msgstr "Continuar" + +msgid "Continue\\Continue the current mission" +msgstr "Continuar\\Continua a missão atual" + +msgid "Controls\\Keyboard, joystick and mouse settings" +msgstr "Controles\\Configurações de teclado, mouse e controles" + +msgid "Converts ore to titanium" +msgstr "Converter minério para titânio" + +msgid "Copy" +msgstr "Copiar" + +msgid "Copy (Ctrl+C)" +msgstr "Copiar (Ctrl+C)" + +msgid "Current mission saved" +msgstr "Missão atual salva" + +msgid "Custom levels:" +msgstr "Níveis personalizados:" + +msgid "Custom levels\\Levels from mods created by the users" +msgstr "Níveis personalizados\\Níveis criados pelos usuários" + +msgid "Customize your appearance" +msgstr "Personalize sua aparência" + +msgid "Cut (Ctrl+X)" +msgstr "Recortar (Ctrl+X)" + +msgid "Defense tower" +msgstr "Torre de defesa" + +msgid "Delete mark" +msgstr "Excluir marca" + +msgid "Delete player\\Deletes the player from the list" +msgstr "Excluir jogador\\Exclui o jogador da lista" + +msgid "Delete\\Deletes the selected file" +msgstr "Excluir\\Exclui o arquivo selecionado" + +msgid "Derrick" +msgstr "Extrator" + +msgid "Descend\\Reduces the power of the jet" +msgstr "Descer\\Diminui o poder do jato" + +msgid "Destroy" +msgstr "Destruir" + +msgid "Destroy the building" +msgstr "Destroi a construção" + +msgid "Destroyer" +msgstr "Destruidor" + +msgid "Device\\Driver and resolution settings" +msgstr "Dispositivo\\Configurações de driver e resolução" + +msgid "Dividing by zero" +msgstr "Dividindo por zero" + +msgid "Do you really want to destroy the selected building?" +msgstr "Você realmente deseja destruir o prédio selecionado?" + +#, c-format +msgid "Do you want to delete %s's saved games?" +msgstr "Você quer deletar os %'s jogos salvos?" + +msgid "Doors blocked by a robot or another object" +msgstr "Portas bloqueadas por um robô ou outro objeto" + +msgid "Down (\\key gdown;)" +msgstr "Baixo (\\key gdown;)" + +msgid "Drawer bot" +msgstr "Robô cartoonista" + +msgid "Duplicate label in switch" +msgstr "" + +msgid "Dust\\Dust and dirt on bots and buildings" +msgstr "Poeira\\Poeira e sujeira nos robôs e prédios" + +msgid "Dynamic lighting\\Mobile light sources" +msgstr "Iluminação dinâmica\\Fontes móveis de luz" + +msgid "Dynamic shadows ++\\Dynamic shadows + self shadowing" +msgstr "Sombras dinâmicas ++\\Sombras dinâmicas + auto-sombreamento" + +msgid "Dynamic shadows\\Beautiful shadows!" +msgstr "Sombras dinâmicas\\Sombras magníficas!" + +msgid "Edit the selected program" +msgstr "Alterar o programa selecionado" + +msgid "Egg" +msgstr "Ovo" + +msgid "Empty character constant" +msgstr "" + +msgid "End of block missing" +msgstr "Fim do bloco ausente" + +msgid "Energy deposit (site for power station)" +msgstr "Depósito de energia (local para estação de energia)" + +msgid "Energy level" +msgstr "Nível de energia" + +msgid "Engineer" +msgstr "Engenheiro" + +msgid "Error in instruction move" +msgstr "Deslocamento impossível" + +msgid "Execute the selected program" +msgstr "Execute o programa selecionado" + +msgid "Execute/stop" +msgstr "Executar/Parar" + +msgid "Exercises in the chapter:" +msgstr "Lista de exercícios do capítulo:" + +msgid "Exercises\\Programming exercises" +msgstr "Exercícios\\Exercícios de programação" + +msgid "Explode (\\key action;)" +msgstr "Explodir (\\key action;)" + +msgid "Explosive" +msgstr "Explosivo" + +msgid "Expression expected after =" +msgstr "Expressão experada após =" + +msgid "Extend shield (\\key action;)" +msgstr "Estender escudo (\\key action;)" + +msgid "Eyeglasses:" +msgstr "Óculos:" + +msgid "Face type:" +msgstr "Tipo de face:" + +msgid "File not open" +msgstr "Arquivo não aberto" + +msgid "Filename:" +msgstr "Nome do arquivo:" + +msgid "Film sequences\\Films before and after the missions" +msgstr "Filmes de sequência\\Filmes antes de depois das missões" + +msgid "Finish" +msgstr "Finalizar" + +msgid "Fixed mine" +msgstr "Mina fixa" + +msgid "Flat ground not large enough" +msgstr "Terra plana não larga o suficiente" + +msgid "Fog\\Fog" +msgstr "Neblina\\Neblina" + +msgid "Folder:" +msgstr "Pasta:" + +#, c-format +msgid "Folder: %s" +msgstr "Pasta: %s" + +msgid "Font size" +msgstr "Tamanho da fonte" + +msgid "Forward" +msgstr "Avançar" + +msgid "Forward (\\key up;)" +msgstr "Avançar (\\key up;)" + +msgid "Forward\\Moves forward" +msgstr "Avançar\\Move para frente" + +msgid "Found a site for a derrick" +msgstr "Encontrou um local para o extrator" + +msgid "Found a site for power station" +msgstr "Encontrou um local para um estação de energia" + +msgid "Found key A (site for derrick)" +msgstr "Encontrou uma chave A (local para extrator)" + +msgid "Found key B (site for derrick)" +msgstr "Encontrou uma chave B (local para extrator)" + +msgid "Found key C (site for derrick)" +msgstr "Encontrou uma chave C (local para extrator)" + +msgid "Found key D (site for derrick)" +msgstr "Encontrou uma chave D (local para extrator)" + +msgid "Free game" +msgstr "Jogo livre" + +msgid "Free game on this planet:" +msgstr "Logo livre neste planeta:" + +msgid "Free game\\Free game without a specific goal" +msgstr "Jogo livre\\Jogo livre sem um objetivo específico" + +msgid "Full screen\\Full screen or window mode" +msgstr "Tela cheia\\Tela cheia ou modo janela" + +msgid "Function already exists" +msgstr "Função já existe" + +msgid "Function name missing" +msgstr "Falta o nome da função" + +msgid "Function needs return type \"void\"" +msgstr "Função precisa de um tipo de retorno \"void\"" + +msgid "Game speed" +msgstr "Velocidade do jogo" + +msgid "Game\\Game settings" +msgstr "Jogo\\Opções de jogabilidade" + +msgid "Gantry crane" +msgstr "Guindaste pórtico" + +msgid "Generating" +msgstr "Gerando" + +msgid "Gold Edition development by:" +msgstr "Versão de ouro desenvolvida por:" + +msgid "Goto: destination occupied" +msgstr "Vá para: destino ocupado" + +msgid "Goto: inaccessible destination" +msgstr "Vá para: destino inacessível" + +msgid "Grab or drop (\\key action;)" +msgstr "Pegar ou soltar (\\key action;)" + +msgid "Graphics\\Graphics settings" +msgstr "Gráficos\\Opções gráficas" + +msgid "Green" +msgstr "Verde" + +msgid "Green flag" +msgstr "Bandeira verde" + +msgid "Ground not flat enough" +msgstr "Chão não plano o suficiente" + +msgid "Hair color:" +msgstr "Cor do cabelo:" + +msgid "Head\\Face and hair" +msgstr "Cabeça\\Face e cabelo" + +msgid "Help about selected object" +msgstr "Ajuda sobre o objeto selecionado" + +msgid "Help balloons\\Explain the function of the buttons" +msgstr "Balões de ajuda\\Explica a função dos botões" + +msgid "Hex value out of range" +msgstr "Valor hexadecimal fora de alcance" + +#, fuzzy +msgid "Higher speed\\Doubles speed" +msgstr "Alta velocidade\\Dobra a velocidade" + +msgid "Highest\\Highest graphic quality (lowest frame rate)" +msgstr "Elevado\\Alta qualidade gráfica (baixa taxa de quadros)" + +msgid "Home" +msgstr "Início" + +msgid "Houston Mission Control" +msgstr "Centro de controle de missões Houston" + +msgid "Illegal object" +msgstr "Objeto inacessível" + +msgid "Impossible under water" +msgstr "Impossível debaixo d'água" + +msgid "Impossible when carrying an object" +msgstr "Impossível enquanto carregando um objeto" + +msgid "Impossible when flying" +msgstr "Impossível enquanto voando" + +msgid "Impossible when moving" +msgstr "Impossível enquanto movendo" + +msgid "Impossible when swimming" +msgstr "Impossível enquanto nadando" + +msgid "Inappropriate bot" +msgstr "Robô inapropriado" + +msgid "Inappropriate cell type" +msgstr "Tipo de célula inapropriada" + +msgid "Inappropriate object" +msgstr "Objeto inapropiado" + +msgid "Incorrect index type" +msgstr "Tipo de índice inválido" + +msgid "Infected by a virus; temporarily out of order" +msgstr "Infectado por vírus; temporariamento fora de serviço" + +msgid "Information exchange post" +msgstr "Posto de troca de informação" + +msgid "Instruction \"break\" outside a loop" +msgstr "Intrução \"break\" fora de um laço" + +msgid "Instruction \"case\" missing" +msgstr "Instrução \"case\" faltando" + +msgid "Instruction \"case\" outside a block \"switch\"" +msgstr "Instrução \"case\" fora de um bloco \"switch\"" + +msgid "Instruction \"else\" without corresponding \"if\"" +msgstr "Instrução \"else\" sem o \"if\" correspondente" + +msgid "Instructions (\\key help;)" +msgstr "Instruções (\\key help;)" + +msgid "Instructions after the final closing brace" +msgstr "Instruções depois do último colchete de fechamento" + +msgid "Instructions for the mission (\\key help;)" +msgstr "Instruções para a missão (\\key help;)" + +msgid "Instructions from Houston" +msgstr "Instruções de Houston" + +msgid "Instructions\\Shows the instructions for the current mission" +msgstr "Instruções\\Mostra as instruções para a missão atual" + +msgid "Internal error - tell the developers" +msgstr "Erro interno - contacte os desenvolvedores" + +msgid "Invalid universal character name" +msgstr "Nome de carácter universal inválido" + +msgid "Invert\\Invert values on this axis" +msgstr "Inverter\\Inverte os valores neste eixo" + +msgid "Jet temperature" +msgstr "Temperatura do jato" + +msgid "Key A" +msgstr "Tecla A" + +msgid "Key B" +msgstr "Tecla B" + +msgid "Key C" +msgstr "Tecla C" + +msgid "Key D" +msgstr "Tecla D" + +msgid "Keyword \"while\" missing" +msgstr "Palavra-chave \"while\" faltando" + +msgid "Keyword help(\\key cbot;)" +msgstr "Palavra-chave ajuda (\\key cbot;)" + +msgid "LOADING" +msgstr "CARREGANDO" + +msgid "Legged grabber" +msgstr "Agarrador com pernas" + +msgid "Legged orga shooter" +msgstr "Atirador orgânico com pernas" + +msgid "Legged shooter" +msgstr "Atirador com pernas" + +msgid "Legged sniffer" +msgstr "Farejador com pernas" + +msgid "Levels in this chapter:" +msgstr "Níveis neste capítulo:" + +msgid "Lightning conductor" +msgstr "Condutor elétrico" + +msgid "List of objects" +msgstr "Lista dos objetos" + +msgid "List of saved missions" +msgstr "Lista das missões salvas" + +msgid "Load a saved mission" +msgstr "Carregar uma missão salva" + +msgid "Load\\Load a saved mission" +msgstr "Carregar\\Carregar uma missão salva" + +msgid "Load\\Loads the selected mission" +msgstr "Carregar\\Carrega a missão selecionada" + +msgid "Loading basic level settings" +msgstr "Carregando configurações de nível básico" + +msgid "Loading finished!" +msgstr "Carregamento finalizado!" + +msgid "Loading music" +msgstr "Carregando música" + +msgid "Loading objects" +msgstr "Carregando objetos" + +msgid "Loading terrain" +msgstr "Carregando terreno" + +# msgid "Speed 0.5x\\Half speed" +# msgstr "" +# msgid "Speed 1.0x\\Normal speed" +# msgstr "" +# msgid "Speed 1.5x\\1.5 times faster" +# msgstr "" +# msgid "Speed 2.0x\\Double speed" +# msgstr "" +# msgid "Speed 3.0x\\Triple speed" +# msgstr "" +# msgid "Speed 4.0x\\Quadruple speed" +# msgstr "" +# msgid "Speed 6.0x\\Sextuple speed" +# msgstr "" +msgid "Lower speed\\Decrease speed by half" +msgstr "Velocidade baixa\\Diminuir velocidade pela metade" + +msgid "Lowest\\Minimum graphic quality (highest frame rate)" +msgstr "Mínimo\\Qualidade gráfica mínima (alta taxa de quadros)" + +msgid "Lunar Roving Vehicle" +msgstr "Veículo rotativo Lunar" + +msgid "MSAA\\Multisample anti-aliasing" +msgstr "MSAA\\Antisserrilhamento multiamostragem" + +msgid "Maximize" +msgstr "Maximizar" + +msgid "Minimize" +msgstr "Minimizar" + +msgid "Mipmap level\\Mipmap level" +msgstr "Nível do mini-mapa\\Nível do mini-mapa" + +msgid "Missing end quote" +msgstr "Aspas de fechamento ausentes" + +msgid "Missing hex digits after escape sequence" +msgstr "Digitos hexademais ausentes após sequência de escape" + +msgid "Mission name" +msgstr "Nome da missão" + +msgid "Missions" +msgstr "Missões" + +msgid "Missions on this planet:" +msgstr "Lista de missões neste planeta:" + +msgid "Missions\\Select mission" +msgstr "Missões\\Selecione uma missão" + +msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" +msgstr "Inversão de mouse X\\Inverte a direção da rolagem no eixo X" + +msgid "Mouse inversion Y\\Inversion of the scrolling direction on the Y axis" +msgstr "Inversão de mouse Y\\Inverte a direção da rolagem no eixo Y" + +msgid "Move selected program down" +msgstr "Move o programa selecionado para baixo" + +msgid "Move selected program up" +msgstr "Move o programa selecionado para cima" + +msgid "Mute\\No sound" +msgstr "Mudo\\Sem som" + +msgid "Name:" +msgstr "Nome:" + +msgid "Negative value rejected by \"throw\"" +msgstr "Valor negativo rejeitado por \"throw\"" + +msgid "Nest" +msgstr "Ninho" + +msgid "New" +msgstr "Novo" + +msgid "New ..." +msgstr "Novo ..." + +msgid "New bot available" +msgstr "Novo robô disponível" + +msgid "Next" +msgstr "Próximo" + +msgid "Next object\\Selects the next object" +msgstr "Próximo objeto\\Selecionar o próximo objeto" + +msgid "No" +msgstr "Não" + +msgid "No energy in the subsoil" +msgstr "Nenhuma energia no subsolo" + +msgid "No flag nearby" +msgstr "Nenhuma bandeira próxima" + +msgid "No function running" +msgstr "Nenhuma função executando" + +msgid "No function with this name accepts this kind of parameter" +msgstr "Nenhuma função com este nome aceita este tipo de parâmetro" + +msgid "No function with this name accepts this number of parameters" +msgstr "Nenhuma função com este nome aceita este número de parâmetros" + +msgid "No information exchange post within range" +msgstr "Nenhum posto de troca de informação ao alcance" + +msgid "No more energy" +msgstr "Não há mais energia" + +msgid "No ore in the subsoil" +msgstr "Nenhum mineral no subsolo" + +msgid "No power cell" +msgstr "Sem célula de energia" + +msgid "No titanium" +msgstr "Sem titânio" + +msgid "No titanium around" +msgstr "Nenhum titânio ao redor" + +msgid "No titanium ore to convert" +msgstr "Sem minério de titânio para converter" + +msgid "No titanium to transform" +msgstr "Nenhum titânio para transformar" + +msgid "No uranium to transform" +msgstr "Nenhum urânio para transformar" + +msgid "No userlevels installed!" +msgstr "Nenhum nível de usuário instalado!" + +msgid "Non-void function needs \"return;\"" +msgstr "Funções não void precisam de \"return;\"" + +msgid "Normal size" +msgstr "Tamanho normal" + +msgid "Normal\\Normal graphic quality" +msgstr "Normal\\Qualidade gráfica normal" + +msgid "Normal\\Normal sound volume" +msgstr "Normal\\Volume de som normal" + +msgid "Not enough energy" +msgstr "Sem energia suficiente" + +msgid "Not enough energy yet" +msgstr "Ainda sem energia suficiente" + +msgid "Not found anything to destroy" +msgstr "Não encontrou nada para destruir" + +msgid "Nothing to analyze" +msgstr "Nada para analisar" + +msgid "Nothing to drop" +msgstr "Nada para largar" + +msgid "Nothing to grab" +msgstr "Nada para pegar" + +msgid "Nothing to recycle" +msgstr "Nada para reciclar" + +msgid "Nuclear power cell" +msgstr "Célula de energia núclear" + +msgid "Nuclear power cell available" +msgstr "Célula de energia núclear disponível" + +msgid "Nuclear power station" +msgstr "Estação de energia núclear" + +msgid "Number missing" +msgstr "Número ausente" + +msgid "Number of insects detected" +msgstr "Número de insetos detectados" + +msgid "Number of particles\\Explosions, dust, reflections, etc." +msgstr "Quantidade de particulas\\Explosões, poeira, reflexões, etc." + +msgid "OK" +msgstr "OK" + +msgid "OK\\Choose the selected player" +msgstr "OK\\Escolher o jogador selecionado" + +msgid "OK\\Close program editor and return to game" +msgstr "OK\\Fechar o editor e retornar ao jogo" + +msgid "Object too close" +msgstr "Objeto muito próximo" + +msgid "Octal value out of range" +msgstr "Valor octal fora do limite" + +msgid "One step" +msgstr "Um passo" + +msgid "Open" +msgstr "Abrir" + +msgid "Open (Ctrl+O)" +msgstr "Abrir (Ctrl+O)" + +msgid "Opening brace missing" +msgstr "Chave de abertura ausente" + +msgid "Opening bracket missing" +msgstr "Colchete de abertura ausente" + +msgid "Operation impossible with value \"nan\"" +msgstr "Operação impossível com o valor \"nan\"" + +msgid "Options" +msgstr "Opções" + +msgid "Options\\Preferences" +msgstr "Opções\\Preferências" + +msgid "Organic matter" +msgstr "Matéria orgânica" + +msgid "Origin of last message\\Shows where the last message was sent from" +msgstr "Origem da última mensagem\\Mostra de onde a última mensagem foi enviada" + +msgid "Original game developed by:" +msgstr "Jogo original desenvolvido por:" + +msgid "Parameters missing" +msgstr "Parâmetros ausentes" + +msgid "Particles in the interface\\Steam clouds and sparks in the interface" +msgstr "Partículas na interface\\Núvens de vapor e faíscas na interface" + +msgid "Paste (Ctrl+V)" +msgstr "Colar (Ctrl+V)" + +msgid "Pause blur\\Blur the background on the pause screen" +msgstr "Borrão de pausa\\Borra o fundo na tela de pausa" + +msgid "Pause in background\\Pause the game when the window is unfocused" +msgstr "Pausar quando em background\\Pausa o jogo quando a janela está sem foco" + +msgid "Pause/continue" +msgstr "Pausar/Continuar" + +msgid "Pause\\Pause the game without opening menu" +msgstr "Pausar\\Pausa o jogo sem abrir o menu" + +msgid "Phazer shooter" +msgstr "Atirador phazer" + +msgid "Photography" +msgstr "Fotografia" + +msgid "Place occupied" +msgstr "Local ocupado" + +msgid "Planets:" +msgstr "Planetas:" + +msgid "Plans for defense tower available" +msgstr "Planos para a torre de defesa disponíveis" + +msgid "Plans for nuclear power plant available" +msgstr "Planos para a planta nuclear disponíveis" + +msgid "Plans for phazer shooter available" +msgstr "Planos para o atirador phazer disponíveis" + +msgid "Plans for shielder available" +msgstr "Planos para o defensor disponíveis" + +msgid "Plans for shooter available" +msgstr "Planos para o atirador disponíveis" + +msgid "Plans for thumper available" +msgstr "Planos para o batedor disponíveis" + +msgid "Plans for tracked robots available" +msgstr "Planos para robôs com esteiras disponíveis" + +msgid "Plant a flag" +msgstr "Colocar uma bandeira" + +msgid "Play\\Start mission!" +msgstr "Jogar\\Iniciar missão!" + +msgid "Player" +msgstr "Jogador" + +msgid "Player name" +msgstr "Nome do jogador" + +msgid "Player's name" +msgstr "Nome dos jogadores" + +msgid "Power cell" +msgstr "Célula de energia" + +msgid "Power cell available" +msgstr "Célula de energia disponível" + +msgid "Power cell factory" +msgstr "Fábrica de células de energia" + +msgid "Power station" +msgstr "Estação de energia" + +msgid "Practice bot" +msgstr "Robô de prática" + +msgid "Press \\key help; to read instructions on your SatCom" +msgstr "Pressione \\key help; para ler as intruções no seu SatCom" + +msgid "Previous" +msgstr "Anterior" + +msgid "Previous object\\Selects the previous object" +msgstr "Objeto anterior\\Seleciona o objeto anterior" + +msgid "Previous selection (\\key desel;)" +msgstr "Seleção anterior (\\key desel;)" + +msgid "Private element" +msgstr "Elemento privado" + +msgid "Private\\Private folder" +msgstr "Privado\\Pasta privada" + +msgid "Processing level file" +msgstr "Processando o arquivo de nível" + +msgid "Program cloned" +msgstr "Programa clonado" + +msgid "Program editor" +msgstr "Editor" + +msgid "Program finished" +msgstr "Programa finalizado" + +msgid "Program infected by a virus" +msgstr "Programa infectado por vírus" + +msgid "Programming exercises" +msgstr "Exercícios de programação" + +msgid "Programming help" +msgstr "Ajuda de programação" + +msgid "Programming help (\\key prog;)" +msgstr "Ajuda de programação (\\key prog;)" + +msgid "Programming help\\Gives more detailed help with programming" +msgstr "Ajuda de programação\\Fornece uma ajuda mais detalhada sobre programação" + +msgid "Programs dispatched by Houston" +msgstr "Programas enviados por Houston" + +msgid "Public required" +msgstr "Necessário público" + +msgid "Public\\Common folder" +msgstr "Público\\Pasta comum" + +msgid "Quake at explosions\\The screen shakes at explosions" +msgstr "Tremer em explosões\\A tela sacode em explosões" + +msgid "Quick load\\Immediately load game" +msgstr "Carregando rápido\\Imediatamente carrega o jogo" + +msgid "Quick save\\Immediately save game" +msgstr "Salvamento rápido\\Imediatamente salva o jogo" + +#, fuzzy +msgid "Quicksave slot not found" +msgstr "Slot para salvamento rápido não encontrado" + +msgid "Quit\\Quit Colobot: Gold Edition" +msgstr "Sair\\Fecha Colobot: ediçao de ouro" + +msgid "Quit\\Quit the current mission or exercise" +msgstr "Sair\\Termina a missão atual ou exercício" + +msgid "Radar station" +msgstr "Estação de radar" + +msgid "Read error" +msgstr "Erro de leitura" + +msgid "Recorder" +msgstr "Gravador" + +msgid "Recycle (\\key action;)" +msgstr "Reciclar (\\key action;)" + +msgid "Recycler" +msgstr "Reciclador" + +msgid "Red" +msgstr "Vermelho" + +msgid "Red flag" +msgstr "Bandeira vermelha" + +msgid "Reflections on the buttons \\Shiny buttons" +msgstr "Reflexões nos botões\\Botões brilhantes" + +msgid "Remains of Apollo mission" +msgstr "Restos da missão Apollo" + +msgid "Remove a flag" +msgstr "Remover a bandeira" + +msgid "Remove selected program" +msgstr "Remover o programa selecionado" + +msgid "Render distance\\Maximum visibility" +msgstr "Distância de renderização\\Visibilidade máxima" + +msgid "Repair center" +msgstr "Centro de reparos" + +msgid "Research center" +msgstr "Centro de pesquisa" + +msgid "Research program already performed" +msgstr "Programa de pesquisa já realizado" + +msgid "Research program completed" +msgstr "Programa de pesquisa completado" + +msgid "Reserved keyword of CBOT language" +msgstr "Palavra-chave reservada para a linguagem CBOT" + +msgid "Resolution" +msgstr "Resolução" + +msgid "Resolution:" +msgstr "Resolução:" + +msgid "Resources" +msgstr "Recursos" + +msgid "Restart\\Restart the mission from the beginning" +msgstr "Reiniciar\\Reinicia a missão do começo" + +msgid "Restoring CBot execution state" +msgstr "Restaura o estado de execução do CBot" + +msgid "Restoring saved objects" +msgstr "Restaurando objetos salvos" + +msgid "Results" +msgstr "Resultados" + +msgid "Return to start" +msgstr "Retornar para o início" + +msgid "Robbie" +msgstr "Robbie" + +msgid "Ruin" +msgstr "Ruína" + +msgid "Run research program for defense tower" +msgstr "Executar programa de pesquisa para torre de defesa" + +msgid "Run research program for legged bots" +msgstr "Executar programa de pesquisa para robôs com pernas" + +msgid "Run research program for nuclear power" +msgstr "Executar programa de pesquisa para energia nuclear" + +msgid "Run research program for orga shooter" +msgstr "Executar programa de pesquisa para atirador orgânico" + +msgid "Run research program for phazer shooter" +msgstr "Executar programa de pesquisa para atirador phazer" + +msgid "Run research program for shielder" +msgstr "Executar programa de pesquisa para defensor" + +msgid "Run research program for shooter" +msgstr "Executar programa de pesquisa para atirador" + +msgid "Run research program for thumper" +msgstr "Executar programa de pesquisa para batedor" + +msgid "Run research program for tracked bots" +msgstr "Executar programa de pesquisa para robôs com esteira" + +msgid "Run research program for winged bots" +msgstr "Executar programa de pesquisa para robôs alados" + +msgid "SatCom" +msgstr "SatCom" + +msgid "Satellite report" +msgstr "Relatório do satélite" + +msgid "Save" +msgstr "Salvar" + +msgid "Save (Ctrl+S)" +msgstr "Salvar (Ctrl+S)" + +msgid "Save the current mission" +msgstr "Salve a missão atual" + +msgid "Save\\Save the current mission" +msgstr "Salvar\\Salve a missão atual" + +msgid "Save\\Saves the current mission" +msgstr "Salvar\\Salva a missão atual" + +msgid "Select the astronaut\\Selects the astronaut" +msgstr "Selecione o astronauta\\Seleciona o astronauta" + +msgid "Semicolon terminator missing" +msgstr "Falta o terminador ponto e vírgula" + +msgid "Shadow resolution\\Higher means better range and quality, but slower" +msgstr "Resolução das sombras\\Valores altos significam alcance e qualidade melhores, porém mais devagar" + +msgid "Shield level" +msgstr "Nível de escudo" + +msgid "Shield radius" +msgstr "Raio do escudo" + +msgid "Shielder" +msgstr "Defensor" + +msgid "Shoot (\\key action;)" +msgstr "Atirar (\\key action;)" + +msgid "Show if the ground is flat" +msgstr "Mostre se o solo é plano" + +msgid "Show the place" +msgstr "Mostre o local" + +msgid "Show the range" +msgstr "Mostre o alcance" + +msgid "Show the solution" +msgstr "Mostre a solução" + +msgid "Sign \" : \" missing" +msgstr "Sinal \" : \" ausente" + +msgid "Simple shadows\\Shadows spots on the ground" +msgstr "Sombras simples\\Pontos de sombra no chão" + +msgid "Size 1" +msgstr "Tamanho 1" + +msgid "Size 2" +msgstr "Tamanho 2" + +msgid "Size 3" +msgstr "Tamanho 3" + +msgid "Size 4" +msgstr "Tamanho 4" + +msgid "Size 5" +msgstr "Tamanho 5" + +msgid "Sniff (\\key action;)" +msgstr "Farejar (\\key action;)" + +msgid "Solution" +msgstr "Solução" + +msgid "Sound effects:\\Volume of engines, voice, shooting, etc." +msgstr "Efeitos sonoros:\\Volume dos motores, voz, tiros, etc." + +msgid "Sound\\Music and game sound volume" +msgstr "Som\\Volume do som das músicas e do jogo" + +msgid "Spaceship" +msgstr "Nave espacial" + +msgid "Spaceship ruin" +msgstr "Ruína de nave espacial" + +msgid "Spider" +msgstr "Aranha" + +msgid "Spider fatally wounded" +msgstr "Aranha fatalmente ferida" + +msgid "Stack overflow" +msgstr "Estouro de pilha" + +msgid "Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" +msgstr "Ação padrão\\Ação padrão do robô (pegar/agarrar, atirar, farejar, etc)" + +msgid "Standard controls\\Standard key functions" +msgstr "Controles padrões\\Funções padrões das teclas" + +msgid "Standard speed\\Reset speed to normal" +msgstr "Velocidade padrão\\Reiniciar a velocidade para o normal" + +msgid "Standard\\Standard appearance settings" +msgstr "Padrão\\Configurações de aparência padrão" + +msgid "Start" +msgstr "Iniciar" + +msgid "Starting..." +msgstr "Iniciando..." + +msgid "Still working ..." +msgstr "Ainda trabalhando ..." + +msgid "String missing" +msgstr "Carácteres ausentes" + +msgid "Strip color:" +msgstr "Cor da tira:" + +msgid "Subber" +msgstr "Mergulhador" + +msgid "Suit color:" +msgstr "Cor do traje:" + +msgid "Suit\\Astronaut suit" +msgstr "Traje\\Traje de astronauta" + +msgid "Summary:" +msgstr "Sumário:" + +msgid "Survival kit" +msgstr "Kit de sobrevivência" + +msgid "Switch bots <-> buildings" +msgstr "Trocar robôs <-> prédios" + +msgid "Take off to finish the mission" +msgstr "Decole para finalizar a missão" + +msgid "Target" +msgstr "Alvo" + +msgid "Target bot" +msgstr "Robô alvo" + +msgid "Terrain relief" +msgstr "Relevo do terreno" + +msgid "Texture filtering\\Texture filtering" +msgstr "Filtragem de textura\\Filtragem de textura" + +msgid "Textures" +msgstr "Texturas" + +msgid "The battle has ended" +msgstr "A batalha acabou" + +msgid "The expression must return a boolean value" +msgstr "A expressão deve retornar um valor booleano" + +msgid "The function returned no value" +msgstr "A função não retornou nenhum valor" + +msgid "The mission is not accomplished yet (press \\key help; for more details)" +msgstr "A missão não foi completada ainda (pressione \\key help; para mais detalhes)" + +msgid "The types of the two operands are incompatible" +msgstr "Os tipos dos dois operandos são incompativeis" + +msgid "This class already exists" +msgstr "Esta classe já existe" + +msgid "This class does not exist" +msgstr "Esta classe não existe" + +msgid "This is example code that cannot be run directly" +msgstr "Este é um código de exemplo que não pode ser executado diretamente" + +msgid "This is not a member of this class" +msgstr "Este não é um membro desta classe" + +msgid "This label does not exist" +msgstr "Este rótulo não existe" + +msgid "This menu is for userlevels from mods, but you didn't install any" +msgstr "Este menu é para níveis de usuários, mas você não instalou nenhum." + +msgid "This object is currently busy" +msgstr "Este objeto está ocupado atualmente" + +msgid "This object is not a member of a class" +msgstr "Este objeto não é um membro de uma classe" + +msgid "This parameter needs a default value" +msgstr "Este parâmetro necessita de um valor padrão" + +msgid "This program is read-only, clone it to edit" +msgstr "Este programa é somente-leitura, clone-o para edita-lo" + +msgid "Thump (\\key action;)" +msgstr "Bater (\\key action;)" + +msgid "Thumper" +msgstr "Batedor" + +#, c-format +msgid "Time: %s" +msgstr "Tempo: %s" + +msgid "Titanium" +msgstr "Titânio" + +msgid "Titanium available" +msgstr "Titânio disponível" + +msgid "Titanium deposit (site for derrick)" +msgstr "Depósito de titânio (local para extrator)" + +msgid "Titanium ore" +msgstr "Mineral de titânio" + +msgid "Titanium too close" +msgstr "Titânio muito perto" + +msgid "Titanium too far away" +msgstr "Titânio muito longe" + +msgid "Too close to a building" +msgstr "Muito perto de um prédio" + +msgid "Too close to an existing flag" +msgstr "Muito perto de uma bandeira" + +msgid "Too close to space ship" +msgstr "Muito perto da nave espacial" + +msgid "Too many flags of this color (maximum 5)" +msgstr "Muitas bandeiras dessa cor (máximo 5)" + +msgid "Too many parameters" +msgstr "Muitos parâmetros" + +msgid "Tracked grabber" +msgstr "Pegador com esteiras" + +msgid "Tracked orga shooter" +msgstr "Atirador orgânico com esteiras" + +msgid "Tracked shooter" +msgstr "Atirador com esteiras" + +msgid "Tracked sniffer" +msgstr "Farejador com esteiras" + +msgid "Transforms only titanium" +msgstr "Transformar somente titânio" + +msgid "Transforms only uranium" +msgstr "Transformar somente urânio" + +msgid "Transmitted information" +msgstr "Informação transmitida" + +msgid "Turn left (\\key left;)" +msgstr "Vire a esquerda (\\key left;)" + +msgid "Turn left\\turns the bot to the left" +msgstr "Vire a esquerda\\vira o robô para a esquerda" + +msgid "Turn right (\\key right;)" +msgstr "Vire a direita (\\key right;)" + +msgid "Turn right\\turns the bot to the right" +msgstr "Vire a direita\\vira o robô para a direita" + +msgid "Type declaration missing" +msgstr "Declaração de tipo ausente" + +msgid "Unable to control enemy objects" +msgstr "Impossível controlar objetos inimigos" + +msgid "Undo (Ctrl+Z)" +msgstr "Desfazer (Ctrl+Z)" + +msgid "Unit" +msgstr "Unidade" + +msgid "Unknown Object" +msgstr "Objeto desconhecido" + +msgid "Unknown command" +msgstr "Comando desconhecido" + +msgid "Unknown escape sequence" +msgstr "Sequência de escape desconhecidade" + +msgid "Unknown function" +msgstr "Função desconhecida" + +msgid "Up (\\key gup;)" +msgstr "Cima (\\key gup;)" + +msgid "Uranium deposit (site for derrick)" +msgstr "Depósito de urânio (local para extrator)" + +msgid "Uranium ore" +msgstr "Mineral de urânio" + +msgid "User levels" +msgstr "Níveis de usuário" + +msgid "Variable name missing" +msgstr "Nome de variável ausente" + +msgid "Variable not declared" +msgstr "Variável não declarada" + +msgid "Variable not initialized" +msgstr "Variável não inicializada" + +msgid "Vault" +msgstr "Cofre" + +msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" +msgstr "" + +msgid "Violet flag" +msgstr "Bandeira violeta" + +msgid "Void parameter" +msgstr "Parâmetro vazio" + +msgid "Wasp" +msgstr "Vespa" + +msgid "Wasp fatally wounded" +msgstr "Vespa fatalmente ferida" + +msgid "Waste" +msgstr "Desperdício" + +msgid "Wheeled grabber" +msgstr "Agarrador com rodas" + +msgid "Wheeled orga shooter" +msgstr "Atirador orgânico com rodas" + +msgid "Wheeled shooter" +msgstr "Atirador com rodas" + +msgid "Wheeled sniffer" +msgstr "Farejador com rodas" + +msgid "Winged grabber" +msgstr "Agarrador alado" + +msgid "Winged orga shooter" +msgstr "Atirador orgânico alado" + +msgid "Winged shooter" +msgstr "Atirador alado" + +msgid "Winged sniffer" +msgstr "Farejador alado" + +msgid "Withdraw shield (\\key action;)" +msgstr "Retirar escudo (\\key action;)" + +msgid "Worm" +msgstr "Verme" + +msgid "Worm fatally wounded" +msgstr "Verme fatalmente ferido" + +msgid "Wreckage" +msgstr "Destroços" + +msgid "Write error" +msgstr "Erro de escrita" + +msgid "Wrong type for the assignment" +msgstr "Tipo errado para a tarefa" + +msgid "Yellow flag" +msgstr "Bandeira amarela" + +msgid "Yes" +msgstr "Sim" + +msgid "You can fly with the keys (\\key gup;) and (\\key gdown;)" +msgstr "Você pode voar com as teclas (\\key gup;) e (\\key gdown;)" + +msgid "You can not carry a radioactive object" +msgstr "Você não pode carregar um objeto radioativo" + +msgid "You can not carry an object under water" +msgstr "Você não pode carregar um objeto debaixo d'água" + +#, c-format +msgid "You cannot use \"%s\" in this exercise (used: %d)" +msgstr "Você não pode usar \"%s\" neste exercício (usado: %d)" + +msgid "You found a usable object" +msgstr "Você encontrou um objeto utilizável" + +#, c-format +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)" +msgstr[0] "Você deve usar \"%1$s\" pelo menos uma vez neste exercício (usado: %2$d)" +msgstr[1] "Você deve usar \"%1$s\" pelo menos %3$d vezes neste exercício (usado: %2$d)" + +#, c-format +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)" +msgstr[0] "Você deve usar \"%1$s\" pelo menos uma vez neste exercício (usado: %2$d)" +msgstr[1] "Você deve usar \"%1$s\" pelo menos %3$d vezes neste exercício (usado: %2$d)" + +msgid "You must get on the spaceship to take off" +msgstr "Você deve estar na nave espacial para decolar" + +msgid "Zoom mini-map" +msgstr "Zoom no mini-mapa" + +msgid "\\Blue flags" +msgstr "\\Bandeiras azuis" + +msgid "\\Eyeglasses 1" +msgstr "\\Óculos 1" + +msgid "\\Eyeglasses 2" +msgstr "\\Óculos 2" + +msgid "\\Eyeglasses 3" +msgstr "\\Óculos 3" + +msgid "\\Eyeglasses 4" +msgstr "\\Óculos 4" + +msgid "\\Eyeglasses 5" +msgstr "\\Óculos 5" + +msgid "\\Face 1" +msgstr "\\Face 1" + +msgid "\\Face 2" +msgstr "\\Face 2" + +msgid "\\Face 3" +msgstr "\\Face 3" + +msgid "\\Face 4" +msgstr "\\Face 4" + +msgid "\\Green flags" +msgstr "\\Bandeiras verdes" + +msgid "\\New player name" +msgstr "\\Nome do novo jogador" + +msgid "\\No eyeglasses" +msgstr "\\Sem óculos" + +msgid "\\Raise the pencil" +msgstr "\\Levante o lápis" + +msgid "\\Red flags" +msgstr "\\Bandeiras vermelhas" + +msgid "\\Return to Colobot: Gold Edition" +msgstr "\\Voltar a Colobot: edição de ouro" + +msgid "\\SatCom on standby" +msgstr "\\SatCom em espera" + +msgid "\\Start recording" +msgstr "\\Iniciar gravação" + +msgid "\\Stop recording" +msgstr "\\Parar gravação" + +msgid "\\Turn left" +msgstr "\\Virar a esquerda" + +msgid "\\Turn right" +msgstr "\\Virar a direita" + +msgid "\\Use the black pencil" +msgstr "\\Use o lápis preto" + +msgid "\\Use the blue pencil" +msgstr "\\Use o lápis azul" + +msgid "\\Use the brown pencil" +msgstr "\\Use o lápis marrom" + +msgid "\\Use the green pencil" +msgstr "\\Use o lápis verde" + +msgid "\\Use the orange pencil" +msgstr "\\Use o lápis laranja" + +msgid "\\Use the purple pencil" +msgstr "\\Use o lápis roxo" + +msgid "\\Use the red pencil" +msgstr "\\Use o lápis vermelho" + +msgid "\\Use the yellow pencil" +msgstr "\\Use o lápis amarelo" + +msgid "\\Violet flags" +msgstr "\\Bandeiras violetas" + +msgid "\\Yellow flags" +msgstr "\\Bandeiras amarelas" + +msgid "colobot.info" +msgstr "colobot.info" + +msgid "epsitec.com" +msgstr "epsitec.com" + +#~ msgid " " +#~ msgstr " " + +#~ msgid " Drivers:" +#~ msgstr " Pilotes :" + +#~ msgid " Missions on this level:" +#~ msgstr " Missions du niveau :" + +#~ msgid "\"%s\" missing in this exercise" +#~ msgstr "Il manque \"%s\" dans le programme" + +#~ msgid "3D sound\\3D positioning of the sound" +#~ msgstr "Bruitages 3D\\Positionnement sonore dans l'espace" + +#~ msgid "Building too close" +#~ msgstr "Bâtiment trop proche" + +#~ msgid "COLOBOT" +#~ msgstr "COLOBOT" + +#~ msgid "Camera awayest" +#~ msgstr "Caméra plus loin" + +#~ msgid "Camera down\\Decrease camera angle while visiting message origin" +#~ msgstr "Caméra plus basse\\Réduit l'angle de caméra lors de la vue de l'origine des messages" + +#~ msgid "Camera nearest" +#~ msgstr "Caméra plus proche" + +#~ msgid "Camera to left" +#~ msgstr "Caméra à gauche" + +#~ msgid "Camera to right" +#~ msgstr "Caméra à droite" + +#~ msgid "Camera up\\Increase camera angle while visiting message origin" +#~ msgstr "Caméra plus haute\\Augmente l'angle de caméra lors de la vue de l'origine des messages" + +#~ msgid "Can not create this; there are too many objects" +#~ msgstr "Création impossible; il y a trop d'objets" + +#~ msgid "Cancel\\Keep current player name" +#~ msgstr "Annuler\\Conserver le joueur actuel" + +#~ msgid "Checkpoint crossed" +#~ msgstr "Indicateur atteint" + +#~ msgid "Compass" +#~ msgstr "Boussole" + +#~ msgid "Continue\\Continue the game" +#~ msgstr "Continuer\\Continuer de jouer" + +#~ msgid "Delete" +#~ msgstr "Détruire" + +#~ msgid "Details\\Visual quality of 3D objects" +#~ msgstr "Détails des objets\\Qualité des objets en 3D" + +#~ msgid "Developed by :" +#~ msgstr "Développé par :" + +#~ msgid "Do you want to quit Colobot: Gold Edition?" +#~ msgstr "Voulez-vous quitter Colobot: Édition Gold ?" + +#~ msgid "Exit film\\Film at the exit of exercises" +#~ msgstr "Retour animé\\Retour animé dans les exercices" + +#~ msgid "Friendly fire\\Your shooting can damage your own objects " +#~ msgstr "Dégâts à soi-même\\Vos tirs infligent des dommages à vos unités" + +#~ msgid "Ground inappropriate" +#~ msgstr "Terrain inadapté" + +#~ msgid "Key word help\\More detailed help about key words" +#~ msgstr "Instructions mot-clé\\Explication sur le mot-clé" + +#~ msgid "Marks on the ground\\Marks on the ground" +#~ msgstr "Marques sur le sol\\Marques dessinées sur le sol" + +#~ msgid "Mouse shadow\\Gives the mouse a shadow" +#~ msgstr "Souris ombrée\\Jolie souris avec une ombre" + +#~ msgid "No other robot" +#~ msgstr "Pas d'autre robot" + +#~ msgid "Not yet enough energy" +#~ msgstr "Pas encore assez d'énergie" + +#~ msgid "Num of decorative objects\\Number of purely ornamental objects" +#~ msgstr "Nb d'objets décoratifs\\Qualité d'objets non indispensables" + +#~ msgid "Planets and stars\\Astronomical objects in the sky" +#~ msgstr "Planètes et étoiles\\Motifs mobiles dans le ciel" + +#~ msgid "Quit the mission?" +#~ msgstr "Quitter la mission ?" + +#~ msgid "Quit\\Quit COLOBOT" +#~ msgstr "Quitter\\Quitter COLOBOT" + +#~ msgid "Robbie\\Your assistant" +#~ msgstr "Robbie\\Votre assistant" + +#~ msgid "Sky\\Clouds and nebulae" +#~ msgstr "Ciel\\Ciel et nuages" + +#~ msgid "Speed 0.5x\\Half speed" +#~ msgstr "Vitesse 0.5x\\Demi-vitesse" + +#~ msgid "Speed 1.0x\\Normal speed" +#~ msgstr "Vitesse 1.0x\\Vitesse normale" + +#~ msgid "Speed 1.5x\\1.5 times faster" +#~ msgstr "Vitesse 1.5x\\Une fois et demi plus rapide" + +#~ msgid "Speed 3.0x\\Three times faster" +#~ msgstr "Vitesse 3.0x\\Trois fois plus rapide" + +#~ msgid "Speed 3.0x\\Triple speed" +#~ msgstr "Vitesse 3.0x\\Trois fois plus rapide " + +#~ msgid "Speed 4.0x\\Quadruple speed" +#~ msgstr "Vitesse 4.0x\\Quatre fois plus rapide" + +#~ msgid "Speed 6.0x\\Sextuple speed" +#~ msgstr "Vitesse 6.0x\\Six fois plus rapide" + +#~ msgid "Sunbeams\\Sunbeams in the sky" +#~ msgstr "Rayons du soleil\\Rayons selon l'orientation" + +#~ msgid "System mouse\\Use system mouse cursor" +#~ msgstr "Souris système\\Utiliser le curseur de la souris système" + +#~ msgid "Textures\\Quality of textures " +#~ msgstr "Qualité des textures\\Qualité des images" + +#~ msgid "The list is only available if a \\l;radar station\\u object\\radar; is working.\n" +#~ msgstr "Liste non disponible sans \\l;radar\\u object\\radar;.\n" + +#~ msgid "Use a joystick\\Joystick or keyboard" +#~ msgstr "Utilise un joystick\\Joystick ou clavier" + +#~ msgid "User\\User levels" +#~ msgstr "Suppl.\\Niveaux supplémentaires" + +#~ msgid "\\Return to COLOBOT" +#~ msgstr "\\Retourner dans COLOBOT" + +#~ msgid "\\b;Aliens\n" +#~ msgstr "\\b;Listes des ennemis\n" + +#~ msgid "\\b;Buildings\n" +#~ msgstr "\\b;Listes des bâtiments\n" + +#~ msgid "\\b;Error\n" +#~ msgstr "\\b;Erreur\n" + +#~ msgid "\\b;List of objects\n" +#~ msgstr "\\b;Listes des objets\n" + +#~ msgid "\\b;Moveable objects\n" +#~ msgstr "\\b;Listes des objets transportables\n" + +#~ msgid "\\b;Robots\n" +#~ msgstr "\\b;Listes des robots\n" + +#~ msgid "\\c; (none)\\n;\n" +#~ msgstr "\\c; (aucun)\\n;\n" diff --git a/po/ru.po b/po/ru.po index f2b25354..37852277 100644 --- a/po/ru.po +++ b/po/ru.po @@ -496,6 +496,9 @@ msgstr "Вниз (\\key gdown;)" msgid "Drawer bot" msgstr "Рисовальщик" +msgid "Duplicate label in switch" +msgstr "" + msgid "Dust\\Dust and dirt on bots and buildings" msgstr "Пыль\\Пыль и грязь на ботах и зданиях" @@ -514,6 +517,9 @@ msgstr "Изменить выбранную программу" msgid "Egg" msgstr "Яйцо" +msgid "Empty character constant" +msgstr "" + msgid "End of block missing" msgstr "Отсутствует конец блока" @@ -1576,6 +1582,10 @@ msgstr "Удар (\\key action;)" msgid "Thumper" msgstr "Ударник" +#, c-format +msgid "Time: %s" +msgstr "" + msgid "Titanium" msgstr "Титан" @@ -1690,6 +1700,9 @@ msgstr "Переменная не инициализирована" msgid "Vault" msgstr "Хранилище" +msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" +msgstr "" + msgid "Violet flag" msgstr "Фиолетовый флаг" diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index f1a658ad..628bb907 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -36,7 +36,6 @@ #include "CBot/CBotCStack.h" #include "CBot/CBotDefParam.h" #include "CBot/CBotUtils.h" -#include "CBot/CBotFileUtils.h" #include @@ -364,69 +363,70 @@ void CBotClass::RestoreMethode(long& nIdent, } //////////////////////////////////////////////////////////////////////////////// -bool CBotClass::SaveStaticState(FILE* pf) +bool CBotClass::SaveStaticState(std::ostream &ostr) { - if (!WriteWord( pf, CBOTVERSION*2)) return false; + if (!WriteLong(ostr, CBOTVERSION*2)) return false; // saves the state of static variables in classes for (CBotClass* p : m_publicClasses) { - if (!WriteWord( pf, 1 )) return false; + if (!WriteWord(ostr, 1)) return false; // save the name of the class - if (!WriteString( pf, p->GetName() )) return false; + if (!WriteString(ostr, p->GetName())) return false; CBotVar* pv = p->GetVar(); while( pv != nullptr ) { if ( pv->IsStatic() ) { - if (!WriteWord( pf, 1 )) return false; - if (!WriteString( pf, pv->GetName() )) return false; + if (!WriteWord(ostr, 1)) return false; + if (!WriteString(ostr, pv->GetName())) return false; - if ( !pv->Save0State(pf) ) return false; // common header - if ( !pv->Save1State(pf) ) return false; // saves as the child class - if ( !WriteWord( pf, 0 ) ) return false; + if (!pv->Save0State(ostr)) return false; // common header + if (!pv->Save1State(ostr)) return false; // saves as the child class + if (!WriteWord(ostr, 0)) return false; } pv = pv->GetNext(); } - if (!WriteWord( pf, 0 )) return false; + if (!WriteWord(ostr, 0)) return false; } - if (!WriteWord( pf, 0 )) return false; + if (!WriteWord(ostr, 0)) return false; return true; } //////////////////////////////////////////////////////////////////////////////// -bool CBotClass::RestoreStaticState(FILE* pf) +bool CBotClass::RestoreStaticState(std::istream &istr) { std::string ClassName, VarName; CBotClass* pClass; unsigned short w; - if (!ReadWord( pf, w )) return false; - if ( w != CBOTVERSION*2 ) return false; + long version; + if (!ReadLong(istr, version)) return false; + if (version != CBOTVERSION*2) return false; while (true) { - if (!ReadWord( pf, w )) return false; + if (!ReadWord(istr, w)) return false; if ( w == 0 ) return true; - if (!ReadString( pf, ClassName )) return false; + if (!ReadString(istr, ClassName)) return false; pClass = Find(ClassName); while (true) { - if (!ReadWord( pf, w )) return false; + if (!ReadWord(istr, w)) return false; if ( w == 0 ) break; CBotVar* pVar = nullptr; CBotVar* pv = nullptr; - if (!ReadString( pf, VarName )) return false; + if (!ReadString(istr, VarName)) return false; if ( pClass != nullptr ) pVar = pClass->GetItem(VarName); - if (!CBotVar::RestoreState(pf, pv)) return false; // the temp variable + if (!CBotVar::RestoreState(istr, pv)) return false; // the temp variable if ( pVar != nullptr ) pVar->Copy(pv); delete pv; diff --git a/src/CBot/CBotClass.h b/src/CBot/CBotClass.h index 0f9a8ce4..eeafe2d1 100644 --- a/src/CBot/CBotClass.h +++ b/src/CBot/CBotClass.h @@ -331,18 +331,18 @@ public: static void ClearPublic(); /*! - * \brief SaveStaticState - * \param pf - * \return + * \brief Save all static variables from each public class + * \param ostr Output stream + * \return true on success */ - static bool SaveStaticState(FILE* pf); + static bool SaveStaticState(std::ostream &ostr); /*! - * \brief RestoreStaticState - * \param pf - * \return + * \brief Restore all static variables in each public class + * \param istr Input stream + * \return true on success */ - static bool RestoreStaticState(FILE* pf); + static bool RestoreStaticState(std::istream &istr); /** * \brief Request a lock on this class (for "synchronized" keyword) diff --git a/src/CBot/CBotDebug.cpp b/src/CBot/CBotDebug.cpp index 892d1d0e..bef509b0 100644 --- a/src/CBot/CBotDebug.cpp +++ b/src/CBot/CBotDebug.cpp @@ -23,6 +23,7 @@ #include "CBot/CBotInstr/CBotFunction.h" #include "CBot/CBotInstr/CBotInstrCall.h" +#include #include #include #include diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp index af4fb6ec..fe4a37b6 100644 --- a/src/CBot/CBotDefParam.cpp +++ b/src/CBot/CBotDefParam.cpp @@ -173,14 +173,34 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) { switch (p->m_type.GetType()) { + case CBotTypByte: + newvar->SetValByte(pVar->GetValByte()); + newvar->SetInit(pVar->GetInit()); // copy nan + break; + case CBotTypShort: + newvar->SetValShort(pVar->GetValShort()); + newvar->SetInit(pVar->GetInit()); // copy nan + break; + case CBotTypChar: + newvar->SetValChar(pVar->GetValChar()); + newvar->SetInit(pVar->GetInit()); // copy nan + break; case CBotTypInt: newvar->SetValInt(pVar->GetValInt()); newvar->SetInit(pVar->GetInit()); // copy nan break; + case CBotTypLong: + newvar->SetValLong(pVar->GetValLong()); + newvar->SetInit(pVar->GetInit()); // copy nan + break; case CBotTypFloat: newvar->SetValFloat(pVar->GetValFloat()); newvar->SetInit(pVar->GetInit()); // copy nan break; + case CBotTypDouble: + newvar->SetValDouble(pVar->GetValDouble()); + newvar->SetInit(pVar->GetInit()); // copy nan + break; case CBotTypString: newvar->SetValString(pVar->GetValString()); break; diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h index 0b33bfdc..2f04707d 100644 --- a/src/CBot/CBotEnums.h +++ b/src/CBot/CBotEnums.h @@ -35,13 +35,13 @@ namespace CBot enum CBotType { CBotTypVoid = 0, //!< void - CBotTypByte = 1, //!< byte (NOT IMPLEMENTED) - CBotTypShort = 2, //!< short (NOT IMPLEMENTED) - CBotTypChar = 3, //!< char (NOT IMPLEMENTED) + CBotTypByte = 1, //!< byte + CBotTypShort = 2, //!< short + CBotTypChar = 3, //!< char CBotTypInt = 4, //!< int - CBotTypLong = 5, //!< long (NOT IMPLEMENTED) + CBotTypLong = 5, //!< long CBotTypFloat = 6, //!< float - CBotTypDouble = 7, //!< double (NOT IMPLEMENTED) + CBotTypDouble = 7, //!< double CBotTypBoolean = 8, //!< bool CBotTypString = 9, //!< string @@ -106,6 +106,11 @@ enum TokenId ID_STRING, ID_VOID, ID_BOOL, + ID_BYTE, + ID_SHORT, + ID_CHAR, + ID_LONG, + ID_DOUBLE, TokenKeyVal = 2200, //!< keywords that represent values (true, false, null, nan) ID_TRUE = 2200, @@ -177,7 +182,8 @@ enum TokenType TokenTypNum = 2, //!< number TokenTypString = 3, //!< string TokenTypVar = 4, //!< a variable name - TokenTypDef = 5 //!< value according DefineNum + TokenTypDef = 5, //!< value according DefineNum + TokenTypChar = 6, //!< character literal }; /** @@ -247,6 +253,8 @@ enum CBotError : int CBotErrHexDigits = 5052, //!< missing hex digits after escape sequence CBotErrHexRange = 5053, //!< hex value out of range CBotErrUnicodeName = 5054, //!< invalid universal character name + CBotErrCharEmpty = 5055, //!< empty character constant + CBotErrRedefCase = 5056, //!< duplicate label in switch // Runtime errors CBotErrZeroDiv = 6000, //!< division by zero diff --git a/src/CBot/CBotFileUtils.cpp b/src/CBot/CBotFileUtils.cpp index c473493a..b2a19cb1 100644 --- a/src/CBot/CBotFileUtils.cpp +++ b/src/CBot/CBotFileUtils.cpp @@ -21,129 +21,261 @@ #include "CBot/CBotClass.h" #include "CBot/CBotEnums.h" -#include "CBot/CBotUtils.h" namespace CBot { - -// file management - -// necessary because it is not possible to do the fopen in the main program -// fwrite and fread in a dll or using the FILE * returned. - -//////////////////////////////////////////////////////////////////////////////// -FILE* fOpen(const char* name, const char* mode) +template +static bool WriteBinary(std::ostream &ostr, T value, unsigned padTo = 0) { - return fopen(name, mode); -} - -//////////////////////////////////////////////////////////////////////////////// -int fClose(FILE* filehandle) -{ - return fclose(filehandle); -} - -//////////////////////////////////////////////////////////////////////////////// -std::size_t fWrite(const void *buffer, - std::size_t elemsize, - std::size_t length, - FILE* filehandle) -{ - return fwrite(buffer, elemsize, length, filehandle); -} - -//////////////////////////////////////////////////////////////////////////////// -std::size_t fRead(void *buffer, - std::size_t elemsize, - std::size_t length, - FILE* filehandle) -{ - return fread(buffer, elemsize, length, filehandle); -} - - -//////////////////////////////////////////////////////////////////////////////// -bool ReadWord(FILE* pf, unsigned short& w) -{ - size_t lg; - - lg = fread(&w, sizeof( unsigned short ), 1, pf ); - - return (lg == 1); -} - -//////////////////////////////////////////////////////////////////////////////// -bool ReadFloat(FILE* pf, float& w) -{ - size_t lg; - - lg = fread(&w, sizeof( float ), 1, pf ); - - return (lg == 1); -} - -//////////////////////////////////////////////////////////////////////////////// -bool WriteLong(FILE* pf, long w) -{ - size_t lg; - - lg = fwrite(&w, sizeof( long ), 1, pf ); - - return (lg == 1); -} - -//////////////////////////////////////////////////////////////////////////////// -bool ReadLong(FILE* pf, long& w) -{ - size_t lg; - - lg = fread(&w, sizeof( long ), 1, pf ); - - return (lg == 1); -} - -//////////////////////////////////////////////////////////////////////////////// -bool ReadString(FILE* pf, std::string& s) -{ - unsigned short w; - char buf[1000]; - size_t lg1, lg2; - - if (!ReadWord(pf, w)) return false; - lg1 = w; - lg2 = fread(buf, 1, lg1, pf ); - buf[lg2] = 0; - - s = buf; - return (lg1 == lg2); -} - -//////////////////////////////////////////////////////////////////////////////// -bool WriteType(FILE* pf, const CBotTypResult &type) -{ - int typ = type.GetType(); - if ( typ == CBotTypIntrinsic ) typ = CBotTypClass; - if ( !WriteWord(pf, typ) ) return false; - if ( typ == CBotTypClass ) + unsigned char chr; + unsigned count = 1; + while (value > 127) // unsigned LEB128 { - CBotClass* p = type.GetClass(); - if ( !WriteString(pf, p->GetName()) ) return false; + ++count; + chr = (value & 0x7F) | 0x80; + if (!ostr.write(reinterpret_cast(&chr), 1)) return false; + value >>= 7; } - if ( type.Eq( CBotTypArrayBody ) || - type.Eq( CBotTypArrayPointer ) ) + chr = value & 0x7F; + if (count < padTo) chr |= 0x80; + if (!ostr.write(reinterpret_cast(&chr), 1)) return false; + + if (count < padTo) { - if ( !WriteWord(pf, type.GetLimite()) ) return false; - if ( !WriteType(pf, type.GetTypElem()) ) return false; + while (++count < padTo) + if (!(ostr << '\x80')) return false; + if (!(ostr << '\x00')) return false; } return true; } -//////////////////////////////////////////////////////////////////////////////// -bool ReadType(FILE* pf, CBotTypResult &type) +template +static bool ReadBinary(std::istream &istr, T &value) +{ + value = 0; + unsigned char chr; + unsigned shift = 0; + while (true) // unsigned LEB128 + { + if (!istr.read(reinterpret_cast(&chr), 1)) return false; + if (shift < sizeof(T) * 8 - 1) + value |= static_cast(chr & 0x7F) << shift; + shift += 7; + if ((chr & 0x80) == 0) break; + } + return true; +} + +template +static bool WriteSignedBinary(std::ostream &ostr, T value, unsigned padTo = 0) +{ + signed char sign = value >> (8 * sizeof(T) - 1); + unsigned count = 0; + while (true) // signed LEB128 + { + ++count; + unsigned char chr = value & 0x7F; + value >>= 7; + if (!(value != sign || ((chr ^ sign) & 0x40) != 0)) + { + if (count < padTo) chr |= 0x80; + if (!ostr.write(reinterpret_cast(&chr), 1)) return false; + break; + } + chr |= 0x80; + if (!ostr.put(chr)) return false; + } + + if (count < padTo) + { + char chr = (sign < 0) ? 0x7F : 0x00; + while (++count < padTo) + if (!ostr.put(chr | 0x80)) return false; + if (!ostr.put(chr)) return false; + } + return true; +} + +template +static bool ReadSignedBinary(std::istream &istr, T &value) +{ + value = 0; + unsigned char chr; + unsigned shift = 0; + while (true) // signed LEB128 + { + if (!istr.read(reinterpret_cast(&chr), 1)) return false; + if (shift < sizeof(T) * 8 - 1) + value |= (static_cast(chr & 0x7F) << shift); + shift += 7; + if ((chr & 0x80) == 0) break; + } + + if (shift >= 8 * sizeof(T) - 1) shift = 8 * sizeof(T) - 1; + if ((chr & 0x40) != 0) + value |= static_cast(-1) << shift; + + return true; +} + +bool WriteWord(std::ostream &ostr, unsigned short w) +{ + return WriteBinary(ostr, w); +} + +bool ReadWord(std::istream &istr, unsigned short &w) +{ + return ReadBinary(istr, w); +} + +bool WriteByte(std::ostream &ostr, char c) +{ + if (!ostr.put(c)) return false; + return true; +} + +bool ReadByte(std::istream &istr, char& c) +{ + if (!istr.get(c)) return false; + return true; +} + +bool WriteShort(std::ostream &ostr, short s) +{ + return WriteSignedBinary(ostr, s); +} + +bool ReadShort(std::istream &istr, short &s) +{ + return ReadSignedBinary(istr, s); +} + +bool WriteUInt32(std::ostream &ostr, uint32_t i) +{ + return WriteBinary(ostr, i); +} + +bool ReadUInt32(std::istream &istr, uint32_t &i) +{ + return ReadBinary(istr, i); +} + +bool WriteInt(std::ostream &ostr, int i) +{ + return WriteSignedBinary(ostr, i); +} + +bool ReadInt(std::istream &istr, int &i) +{ + return ReadSignedBinary(istr, i); +} + +bool WriteLong(std::ostream &ostr, long l, unsigned padTo) +{ + return WriteSignedBinary(ostr, l, padTo); +} + +bool ReadLong(std::istream &istr, long &l) +{ + return ReadSignedBinary(istr, l); +} + +bool WriteFloat(std::ostream &ostr, float f) +{ + union {float fValue; unsigned int iValue;} u; + u.fValue = 0.0f; + u.iValue = 0; + + u.fValue = f; + return WriteBinary(ostr, u.iValue); +} + +bool ReadFloat(std::istream &istr, float &f) +{ + union {float fValue; unsigned int iValue;} u; + u.fValue = 0.0f; + u.iValue = 0; + + if (!ReadBinary(istr, u.iValue)) return false; + f = u.fValue; + return true; +} + +bool WriteDouble(std::ostream &ostr, double d) +{ + union {double dValue; unsigned long iValue;} u; + u.dValue = 0.0; + u.iValue = 0; + + u.dValue = d; + return WriteBinary(ostr, u.iValue); +} + +bool ReadDouble(std::istream &istr, double &d) +{ + union {double dValue; unsigned long iValue;} u; + u.dValue = 0.0; + u.iValue = 0; + + if (!ReadBinary(istr, u.iValue)) return false; + d = u.dValue; + return true; +} + +bool WriteString(std::ostream &ostr, const std::string &s) +{ + if (!WriteBinary(ostr, s.size())) return false; + if (!ostr.write(&(s[0]), s.size())) return false; + + return true; +} + +bool ReadString(std::istream &istr, std::string &s) +{ + size_t length = 0; + if (!ReadBinary(istr, length)) return false; + + s.resize(length); + if (length != 0) + { + if (!istr.read(&(s[0]), length)) return false; + } + return true; +} + +bool WriteType(std::ostream &ostr, const CBotTypResult &type) +{ + int typ = type.GetType(); + if ( typ == CBotTypIntrinsic ) typ = CBotTypClass; + if ( !WriteWord(ostr, typ) ) return false; + if ( typ == CBotTypClass ) + { + CBotClass* p = type.GetClass(); + if (!WriteString(ostr, p->GetName())) return false; + } + if ( type.Eq( CBotTypArrayBody ) || + type.Eq( CBotTypArrayPointer ) ) + { + if (!WriteWord(ostr, type.GetLimite())) return false; + if (!WriteType(ostr, type.GetTypElem())) return false; + } + + if ( type.Eq(CBotTypPointer) ) + { + if (type.GetClass() != nullptr) + { + if (!WriteString(ostr, type.GetClass()->GetName())) return false; + } + else if (!WriteString(ostr, "")) return false; + } + return true; +} + +bool ReadType(std::istream &istr, CBotTypResult &type) { unsigned short w, ww; - if ( !ReadWord(pf, w) ) return false; + if (!ReadWord(istr, w)) return false; type.SetType(w); if ( type.Eq( CBotTypIntrinsic ) ) @@ -154,7 +286,7 @@ bool ReadType(FILE* pf, CBotTypResult &type) if ( type.Eq( CBotTypClass ) ) { std::string s; - if ( !ReadString(pf, s) ) return false; + if (!ReadString(istr, s)) return false; type = CBotTypResult( w, s ); } @@ -162,11 +294,45 @@ bool ReadType(FILE* pf, CBotTypResult &type) type.Eq( CBotTypArrayBody ) ) { CBotTypResult r; - if ( !ReadWord(pf, ww) ) return false; - if ( !ReadType(pf, r) ) return false; + if (!ReadWord(istr, ww)) return false; + if (!ReadType(istr, r)) return false; type = CBotTypResult( w, r ); type.SetLimite(static_cast(ww)); } + + if ( type.Eq(CBotTypPointer) ) + { + std::string className; + if (!ReadString(istr, className)) return false; + type = CBotTypResult(w, className); + } + return true; +} + +bool WriteStream(std::ostream &ostr, std::istream& istr) +{ + if (!istr.seekg(0, istr.end)) return false; + auto size = istr.tellg(); + + if (size == 0) return WriteLong(ostr, 0); + if (!WriteLong(ostr, size)) return false; + + if (!istr.seekg(0, istr.beg)) return false; + if (!(ostr << istr.rdbuf())) return false; + + return true; +} + +bool ReadStream(std::istream& istr, std::ostream &ostr) +{ + long length; + if (!ReadLong(istr, length)) return false; + if (length == 0) return true; + + while (length-- > 0) + { + if (!(ostr << istr.get())) return false; + } return true; } diff --git a/src/CBot/CBotFileUtils.h b/src/CBot/CBotFileUtils.h index fec6298a..900dd81d 100644 --- a/src/CBot/CBotFileUtils.h +++ b/src/CBot/CBotFileUtils.h @@ -19,7 +19,7 @@ #pragma once -#include +#include #include namespace CBot @@ -28,128 +28,189 @@ namespace CBot class CBotVar; class CBotTypResult; -/////////////////////////////////////////////////////////////////////////////// -// routines for file management (* FILE) - /*! - * \brief fOpen - * \param name - * \param mode - * \return + * \brief Save a linked list if variables + * \param ostr Output stream + * \param pVar First variable in the list + * \return true on success */ -FILE* fOpen(const char* name, const char* mode); - -/*! - * \brief fClose - * \param filehandle - * \return - */ -int fClose(FILE* filehandle); - -/*! - * \brief fWrite - * \param buffer - * \param elemsize - * \param length - * \param filehandle - * \return - */ -std::size_t fWrite(const void *buffer, - std::size_t elemsize, - std::size_t length, - FILE* filehandle); - -/*! - * \brief fRead - * \param buffer - * \param elemsize - * \param length - * \param filehandle - * \return - */ -std::size_t fRead(void *buffer, - std::size_t elemsize, - std::size_t length, - FILE* filehandle); - -/*! - * \brief SaveVars - * \param pf - * \param pVar - * \return - */ -bool SaveVars(FILE* pf, CBotVar* pVar); +bool SaveVars(std::ostream &ostr, CBotVar* pVar); /*! * \brief WriteWord - * \param pf + * \param ostr Output stream * \param w - * \return + * \return true on success */ -bool WriteWord(FILE* pf, unsigned short w); +bool WriteWord(std::ostream &ostr, unsigned short w); /*! * \brief ReadWord - * \param pf - * \param w - * \return + * \param istr Input stream + * \param[out] w + * \return true on success */ -bool ReadWord(FILE* pf, unsigned short& w); +bool ReadWord(std::istream &istr, unsigned short &w); /*! - * \brief ReadLong - * \param pf - * \param w - * \return + * \brief WriteByte + * \param ostr Output stream + * \param c + * \return true on success */ -bool ReadLong(FILE* pf, long& w); +bool WriteByte(std::ostream &ostr, char c); /*! - * \brief WriteFloat - * \param pf - * \param w - * \return + * \brief ReadByte + * \param istr Input stream + * \param[out] c + * \return true on success */ -bool WriteFloat(FILE* pf, float w); +bool ReadByte(std::istream &istr, char& c); + +/*! + * \brief WriteShort + * \param ostr Output stream + * \param s + * \return true on success + */ +bool WriteShort(std::ostream &ostr, short s); + +/*! + * \brief ReadShort + * \param istr Input stream + * \param[out] s + * \return true on success + */ +bool ReadShort(std::istream &istr, short &s); + +/*! + * \brief WriteUInt32 + * \param ostr Output stream + * \param i + * \return true on success + */ +bool WriteUInt32(std::ostream &ostr, uint32_t i); + +/*! + * \brief ReadUInt32 + * \param istr Input stream + * \param[out] i + * \return true on success + */ +bool ReadUInt32(std::istream &istr, uint32_t &i); + +/*! + * \brief WriteInt + * \param ostr Output stream + * \param i + * \return true on success + */ +bool WriteInt(std::ostream &ostr, int i); + +/*! + * \brief ReadInt + * \param istr Input stream + * \param[out] i + * \return true on success + */ +bool ReadInt(std::istream &istr, int &i); /*! * \brief WriteLong - * \param pf - * \param w - * \return + * \param ostr Output stream + * \param l + * \param padTo minimum number of bytes to write + * \return true on success */ -bool WriteLong(FILE* pf, long w); +bool WriteLong(std::ostream &ostr, long l, unsigned padTo = 0); + +/*! + * \brief ReadLong + * \param istr Input stream + * \param[out] l + * \return true on success + */ +bool ReadLong(std::istream &istr, long &l); + +/*! + * \brief WriteFloat + * \param ostr Output stream + * \param f + * \return true on success + */ +bool WriteFloat(std::ostream &ostr, float f); /*! * \brief ReadFloat - * \param pf - * \param w - * \return + * \param istr Input stream + * \param[out] f + * \return true on success */ -bool ReadFloat(FILE* pf, float& w); +bool ReadFloat(std::istream &istr, float &f); + +/*! + * \brief WriteDouble + * \param ostr Output stream + * \param d + * \return true on success + */ +bool WriteDouble(std::ostream &ostr, double d); + +/*! + * \brief ReadDouble + * \param istr Input stream + * \param[out] d + * \return true on success + */ +bool ReadDouble(std::istream &istr, double &d); + +/*! + * \brief WriteString + * \param ostr Output stream + * \param s + * \return true on success + */ +bool WriteString(std::ostream &ostr, const std::string &s); /*! * \brief ReadString - * \param pf - * \param s - * \return + * \param istr Input stream + * \param[out] s + * \return true on success */ -bool ReadString(FILE* pf, std::string& s); +bool ReadString(std::istream &istr, std::string &s); /*! * \brief WriteType - * \param pf + * \param ostr Output stream * \param type - * \return + * \return true on success */ -bool WriteType(FILE* pf, const CBotTypResult &type); +bool WriteType(std::ostream &ostr, const CBotTypResult &type); /*! * \brief ReadType - * \param pf - * \param type - * \return + * \param istr Input stream + * \param[out] type + * \return true on success */ -bool ReadType(FILE* pf, CBotTypResult &type); +bool ReadType(std::istream &istr, CBotTypResult &type); + +/*! + * \brief WriteStream + * \param ostr Output stream + * \param istr Input stream + * \return true on success + */ +bool WriteStream(std::ostream &ostr, std::istream& istr); + +/*! + * \brief ReadStream + * \param istr Input stream + * \param ostr Output stream + * \return true on success + */ +bool ReadStream(std::istream& istr, std::ostream &ostr); } // namespace CBot diff --git a/src/CBot/CBotInstr/CBotCase.cpp b/src/CBot/CBotInstr/CBotCase.cpp index 35e17d3d..2e0cc7f0 100644 --- a/src/CBot/CBotInstr/CBotCase.cpp +++ b/src/CBot/CBotInstr/CBotCase.cpp @@ -19,7 +19,7 @@ #include "CBot/CBotInstr/CBotCase.h" -#include "CBot/CBotInstr/CBotExprLitNum.h" +#include "CBot/CBotInstr/CBotTwoOpExpr.h" #include "CBot/CBotStack.h" #include "CBot/CBotCStack.h" @@ -30,69 +30,107 @@ namespace CBot //////////////////////////////////////////////////////////////////////////////// CBotCase::CBotCase() { - m_value = nullptr; + m_instr = nullptr; } //////////////////////////////////////////////////////////////////////////////// CBotCase::~CBotCase() { - delete m_value; + delete m_instr; } -//////////////////////////////////////////////////////////////////////////////// -CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack) +CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack, std::unordered_map& labels) { - CBotCase* inst = new CBotCase(); // creates the object CBotToken* pp = p; // preserves at the ^ token (starting position) - inst->SetToken(p); if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return nullptr; // should never happen + pStack->SetStartError(pp->GetStart()); - if ( pp->GetType() == ID_CASE ) + long labelValue = 0; + + if (pp->GetType() == ID_CASE) { - pp = p; - inst->m_value = CBotExprLitNum::Compile(p, pStack); - if (inst->m_value == nullptr ) + CBotInstr* i = nullptr; + if (nullptr != (i = CBotTwoOpExpr::Compile(p, pStack, nullptr, true))) { - pStack->SetError( CBotErrBadNum, pp ); - delete inst; - return nullptr; + if (pStack->GetType() <= CBotTypLong) + { + CBotStack* pile = CBotStack::AllocateStack(); + while ( !i->Execute(pile) ); + labelValue = pile->GetVar()->GetValLong(); + pile->Delete(); + + if (labels.count(labelValue) > 0) + { + pStack->SetError(CBotErrRedefCase, p->GetStart()); + } + } + else + pStack->SetError(CBotErrBadNum, p->GetStart()); + delete i; } - } - if ( !IsOfType( p, ID_DOTS )) - { - pStack->SetError( CBotErrNoDoubleDots, p->GetStart() ); - delete inst; - return nullptr; + else + pStack->SetError(CBotErrBadNum, p->GetStart()); } - return inst; + if (pStack->IsOk() && IsOfType(p, ID_DOTS)) + { + CBotCase* newCase = new CBotCase(); + newCase->SetToken(pp); + if (pp->GetType() == ID_CASE) + labels[labelValue] = newCase; + return newCase; + } + + pStack->SetError(CBotErrNoDoubleDots, p->GetStart()); + return nullptr; } //////////////////////////////////////////////////////////////////////////////// bool CBotCase::Execute(CBotStack* &pj) { - return true; // the "case" statement does nothing! + if (m_instr == nullptr) return true; + CBotStack* pile = pj->AddStack(this, CBotStack::BlockVisibilityType::BLOCK); + + int state = pile->GetState(); + CBotInstr* p = m_instr; + while (state-- > 0) p = p->GetNext(); + + while (p != nullptr) + { + if (!p->Execute(pile)) return false; + pile->IncState(); + p = p->GetNext(); + } + + pile->Delete(); + return pj->IsOk(); } //////////////////////////////////////////////////////////////////////////////// void CBotCase::RestoreState(CBotStack* &pj, bool bMain) { -} + if (!bMain) return; -//////////////////////////////////////////////////////////////////////////////// -bool CBotCase::CompCase(CBotStack* &pile, int val) -{ - if (m_value == nullptr ) return true; // "default" case + CBotStack* pile = pj->RestoreStack(this); + if (pile == nullptr) return; - while (!m_value->Execute(pile)); // puts the value on the correspondent stack (without interruption) - return (pile->GetVal() == val); // compared with the given value + CBotInstr* p = m_instr; + + int state = pile->GetState(); + while (p != nullptr && state-- > 0) + { + p->RestoreState(pile, bMain); + p = p->GetNext(); + } + + if (p != nullptr) p->RestoreState(pile, bMain); } std::map CBotCase::GetDebugLinks() { auto links = CBotInstr::GetDebugLinks(); - links["m_value"] = m_value; + links["m_instr"] = m_instr; return links; } diff --git a/src/CBot/CBotInstr/CBotCase.h b/src/CBot/CBotInstr/CBotCase.h index e2863cde..ccd031e8 100644 --- a/src/CBot/CBotInstr/CBotCase.h +++ b/src/CBot/CBotInstr/CBotCase.h @@ -21,6 +21,8 @@ #include "CBot/CBotInstr/CBotInstr.h" +#include + namespace CBot { @@ -42,7 +44,7 @@ public: * \param pStack * \return */ - static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, std::unordered_map& labels); /*! * \brief Execute Execution of instruction "case". @@ -58,22 +60,15 @@ public: */ void RestoreState(CBotStack* &pj, bool bMain) override; - /*! - * \brief CompCase Routine to find the entry point of "case" corresponding - * to the value seen. - * \param pj - * \param val - * \return - */ - bool CompCase(CBotStack* &pj, int val) override; - protected: virtual const std::string GetDebugName() override { return "CBotCase"; } virtual std::map GetDebugLinks() override; private: - //! Value to compare. - CBotInstr* m_value; + //! List of instructions after case label + CBotInstr* m_instr; + + friend class CBotSwitch; }; } // namespace CBot diff --git a/src/CBot/CBotInstr/CBotDefClass.cpp b/src/CBot/CBotInstr/CBotDefClass.cpp index 174b973f..3245ab05 100644 --- a/src/CBot/CBotInstr/CBotDefClass.cpp +++ b/src/CBot/CBotInstr/CBotDefClass.cpp @@ -140,7 +140,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p if (typ == CBotErrUndefCall) { - // si le constructeur n'existe pas + // if the ctor don't exist if (inst->m_parameters != nullptr) // with parameters { pStk->SetError(CBotErrNoConstruct, vartoken); diff --git a/src/CBot/CBotInstr/CBotDefFloat.cpp b/src/CBot/CBotInstr/CBotDefFloat.cpp index 65449b02..0bb6f5f8 100644 --- a/src/CBot/CBotInstr/CBotDefFloat.cpp +++ b/src/CBot/CBotInstr/CBotDefFloat.cpp @@ -46,13 +46,22 @@ CBotDefFloat::~CBotDefFloat() } //////////////////////////////////////////////////////////////////////////////// -CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) +CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip, CBotTypResult vartype) { CBotToken* pp = cont ? nullptr : p; - if (!cont && !IsOfType(p, ID_FLOAT)) return nullptr; + if (!cont) + { + switch (p->GetType()) + { + case ID_FLOAT: vartype.SetType(CBotTypFloat ); break; + case ID_DOUBLE: vartype.SetType(CBotTypDouble); break; + default: return nullptr; + } + p = p->GetNext(); + } - CBotDefFloat* inst = static_cast(CompileArray(p, pStack, CBotTypFloat)); + CBotDefFloat* inst = static_cast(CompileArray(p, pStack, vartype)); if (inst != nullptr || !pStack->IsOk()) return inst; CBotCStack* pStk = pStack->TokenStack(pp); @@ -67,7 +76,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) { - (static_cast(inst->m_var))->m_typevar = CBotTypFloat; + (static_cast(inst->m_var))->m_typevar = vartype; if (pStk->CheckVarLocal(vartoken)) // redefinition of a variable { pStk->SetStartError(vartoken->GetStart()); @@ -79,7 +88,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b { delete inst; p = vartoken; - inst = static_cast(CBotDefArray::Compile(p, pStk, CBotTypFloat)); + inst = static_cast(CBotDefArray::Compile(p, pStk, vartype)); goto suite; // no assignment, variable already created } @@ -103,7 +112,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b } } - var = CBotVar::Create(*vartoken, CBotTypFloat); + var = CBotVar::Create(*vartoken, vartype); var->SetInit(inst->m_expr != nullptr ? CBotVar::InitType::DEF : CBotVar::InitType::UNDEF); var->SetUniqNum( (static_cast(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); @@ -111,7 +120,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b suite: if (pStk->IsOk() && IsOfType(p, ID_COMMA)) { - if (nullptr != ( inst->m_next2b = CBotDefFloat::Compile(p, pStk, true, noskip))) + if (nullptr != ( inst->m_next2b = CBotDefFloat::Compile(p, pStk, true, noskip, vartype))) { return pStack->Return(inst, pStk); } diff --git a/src/CBot/CBotInstr/CBotDefFloat.h b/src/CBot/CBotInstr/CBotDefFloat.h index a8060b41..8c3fa44d 100644 --- a/src/CBot/CBotInstr/CBotDefFloat.h +++ b/src/CBot/CBotInstr/CBotDefFloat.h @@ -41,7 +41,7 @@ public: * \param noskip * \return */ - static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false); + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false, CBotTypResult vartype = CBotTypFloat); /*! * \brief Execute Executes the definition of a real variable. diff --git a/src/CBot/CBotInstr/CBotDefInt.cpp b/src/CBot/CBotInstr/CBotDefInt.cpp index 6cfb30e6..6835f901 100644 --- a/src/CBot/CBotInstr/CBotDefInt.cpp +++ b/src/CBot/CBotInstr/CBotDefInt.cpp @@ -47,13 +47,25 @@ CBotDefInt::~CBotDefInt() } //////////////////////////////////////////////////////////////////////////////// -CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) +CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip, CBotTypResult vartype) { CBotToken* pp = cont ? nullptr : p; // no repetition of the token "int" - if (!cont && !IsOfType(p, ID_INT)) return nullptr; + if (!cont) + { + switch (p->GetType()) + { + case ID_BYTE: vartype.SetType(CBotTypByte ); break; + case ID_SHORT: vartype.SetType(CBotTypShort); break; + case ID_CHAR: vartype.SetType(CBotTypChar ); break; + case ID_INT: vartype.SetType(CBotTypInt ); break; + case ID_LONG: vartype.SetType(CBotTypLong ); break; + default: return nullptr; + } + p = p->GetNext(); + } - CBotDefInt* inst = static_cast(CompileArray(p, pStack, CBotTypInt)); + CBotDefInt* inst = static_cast(CompileArray(p, pStack, vartype)); if (inst != nullptr || !pStack->IsOk()) return inst; CBotCStack* pStk = pStack->TokenStack(pp); @@ -68,7 +80,7 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo // determines the expression is valid for the item on the left side if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) { - (static_cast(inst->m_var))->m_typevar = CBotTypInt; + (static_cast(inst->m_var))->m_typevar = vartype; if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable { pStk->SetError(CBotErrRedefVar, vartoken); @@ -82,7 +94,7 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo // compiles an array declaration - CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, CBotTypInt); + CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, vartype); inst = static_cast(inst2); goto suite; // no assignment, variable already created @@ -108,7 +120,7 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo } { - CBotVar* var = CBotVar::Create(*vartoken, CBotTypInt);// create the variable (evaluated after the assignment) + CBotVar* var = CBotVar::Create(*vartoken, vartype); // create the variable (evaluated after the assignment) var->SetInit(inst->m_expr != nullptr ? CBotVar::InitType::DEF : CBotVar::InitType::UNDEF); // if initialized with assignment var->SetUniqNum( //set it with a unique number (static_cast(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); @@ -117,7 +129,7 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo suite: if (pStk->IsOk() && IsOfType(p, ID_COMMA)) // chained several definitions { - if (nullptr != ( inst->m_next2b = CBotDefInt::Compile(p, pStk, true, noskip))) // compile next one + if (nullptr != ( inst->m_next2b = CBotDefInt::Compile(p, pStk, true, noskip, vartype))) // compile next one { return pStack->Return(inst, pStk); } diff --git a/src/CBot/CBotInstr/CBotDefInt.h b/src/CBot/CBotInstr/CBotDefInt.h index 2962eab3..867ab4dd 100644 --- a/src/CBot/CBotInstr/CBotDefInt.h +++ b/src/CBot/CBotInstr/CBotDefInt.h @@ -41,7 +41,7 @@ public: * \param noskip * \return */ - static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip = false); + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip = false, CBotTypResult vartype = CBotTypInt); /*! * \brief Execute Execute the definition of the integer variable. diff --git a/src/CBot/CBotInstr/CBotDo.cpp b/src/CBot/CBotInstr/CBotDo.cpp index caf10920..c5b1debc 100644 --- a/src/CBot/CBotInstr/CBotDo.cpp +++ b/src/CBot/CBotInstr/CBotDo.cpp @@ -57,7 +57,7 @@ CBotInstr* CBotDo::Compile(CBotToken* &p, CBotCStack* pStack) inst->SetToken(p); if (!IsOfType(p, ID_DO)) return nullptr; // should never happen - CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp + CBotCStack* pStk = pStack->TokenStack(pp); // some space for a stack, plz // looking for a statement block after the do diff --git a/src/CBot/CBotInstr/CBotExprLitChar.cpp b/src/CBot/CBotInstr/CBotExprLitChar.cpp new file mode 100644 index 00000000..dc7de906 --- /dev/null +++ b/src/CBot/CBotInstr/CBotExprLitChar.cpp @@ -0,0 +1,151 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "CBot/CBotInstr/CBotExprLitChar.h" + +#include "CBot/CBotStack.h" +#include "CBot/CBotCStack.h" + +#include "CBot/CBotVar/CBotVar.h" + +namespace CBot +{ + +CBotExprLitChar::CBotExprLitChar() +{ +} + +CBotExprLitChar::~CBotExprLitChar() +{ +} + +CBotInstr* CBotExprLitChar::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + const auto& s = p->GetString(); + + auto it = s.cbegin(); + if (++it != s.cend()) + { + if (*it != '\'') // not empty quotes ? + { + uint32_t valchar = 0; + int pos = p->GetStart() + 1; + + if (*it != '\\') valchar = *(it++); // not escape sequence ? + else if (++it != s.cend()) + { + pStk->SetStartError(pos++); + unsigned char c = *(it++); + if (c == '\"' || c == '\'' || c == '\\') valchar = c; + else if (c == 'a') valchar = '\a'; // alert bell + else if (c == 'b') valchar = '\b'; // backspace + else if (c == 'f') valchar = '\f'; // form feed + else if (c == 'n') valchar = '\n'; // new line + else if (c == 'r') valchar = '\r'; // carriage return + else if (c == 't') valchar = '\t'; // horizontal tab + else if (c == 'v') valchar = '\v'; // vertical tab + else if (c == 'u' || c == 'U') // unicode escape + { + if (it != s.cend()) + { + std::string hex = ""; + size_t maxlen = (c == 'u') ? 4 : 8; + + for (size_t i = 0; i < maxlen; i++) + { + if (!CharInList(*it, "0123456789ABCDEFabcdef")) break; + ++pos; + hex += *it; + if (++it == s.cend()) break; + } + + if (maxlen == hex.length()) // unicode character + { + try + { + valchar = std::stoi(hex, nullptr, 16); + if (0x10FFFF < valchar || (0xD7FF < valchar && valchar < 0xE000)) + pStk->SetError(CBotErrUnicodeName, pos + 1); + } + catch (const std::out_of_range& e) + { + pStk->SetError(CBotErrHexRange, pos + 1); + } + } + else + pStk->SetError(CBotErrHexDigits, pos + 1); + } + else + pStk->SetError(CBotErrHexDigits, pos + 1); + } + else + pStk->SetError(CBotErrBadEscape, pos + 1); + } + + if (it == s.cend() || *it != '\'') + pStk->SetError(CBotErrEndQuote, p); + + if (pStk->IsOk()) + { + CBotExprLitChar* inst = new CBotExprLitChar(); + inst->m_valchar = valchar; + inst->SetToken(p); + p = p->GetNext(); + + CBotVar* var = CBotVar::Create("", CBotTypChar); + pStk->SetVar(var); + + return pStack->Return(inst, pStk); + } + } + pStk->SetError(CBotErrCharEmpty, p); + } + + pStk->SetError(CBotErrEndQuote, p); + return pStack->Return(nullptr, pStk); +} + +bool CBotExprLitChar::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + + CBotVar* var = CBotVar::Create("", CBotTypChar); + + var->SetValChar(m_valchar); + + pile->SetVar(var); + + return pj->Return(pile); +} + +void CBotExprLitChar::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +std::string CBotExprLitChar::GetDebugData() +{ + return m_token.GetString(); +} + +} // namespace CBot diff --git a/src/CBot/CBotInstr/CBotExprLitChar.h b/src/CBot/CBotInstr/CBotExprLitChar.h new file mode 100644 index 00000000..1f31d6d2 --- /dev/null +++ b/src/CBot/CBotInstr/CBotExprLitChar.h @@ -0,0 +1,60 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include "CBot/CBotInstr/CBotInstr.h" + +namespace CBot +{ + +/** + * \brief A character literal + * \verbatim 'a', '\n', '\t', '\uFFFD', '\U0000FFFD', etc. \endverbatim + */ +class CBotExprLitChar : public CBotInstr +{ +public: + CBotExprLitChar(); + ~CBotExprLitChar(); + + /*! + * \brief Compile a character literal + */ + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + + /*! + * \brief Execute, returns the corresponding char. + */ + bool Execute(CBotStack* &pj) override; + + /*! + * \brief RestoreState + */ + void RestoreState(CBotStack* &pj, bool bMain) override; + +protected: + virtual const std::string GetDebugName() override { return "CBotExprLitChar"; } + virtual std::string GetDebugData() override; + +private: + uint32_t m_valchar = 0; +}; + +} // namespace CBot diff --git a/src/CBot/CBotInstr/CBotExprLitNum.cpp b/src/CBot/CBotInstr/CBotExprLitNum.cpp index 9273e8ee..0e0f8f88 100644 --- a/src/CBot/CBotInstr/CBotExprLitNum.cpp +++ b/src/CBot/CBotInstr/CBotExprLitNum.cpp @@ -25,52 +25,85 @@ #include "CBot/CBotUtils.h" +#include #include namespace CBot { -//////////////////////////////////////////////////////////////////////////////// -CBotExprLitNum::CBotExprLitNum() +template <> +CBotExprLitNum::CBotExprLitNum(int val) : m_numtype(CBotTypInt), m_value(val) { } -//////////////////////////////////////////////////////////////////////////////// -CBotExprLitNum::~CBotExprLitNum() +template <> +CBotExprLitNum::CBotExprLitNum(long val) : m_numtype(CBotTypLong), m_value(val) { } -//////////////////////////////////////////////////////////////////////////////// -CBotInstr* CBotExprLitNum::Compile(CBotToken* &p, CBotCStack* pStack) +template <> +CBotExprLitNum::CBotExprLitNum(float val) : m_numtype(CBotTypFloat), m_value(val) +{ +} + +template <> +CBotExprLitNum::CBotExprLitNum(double val) : m_numtype(CBotTypDouble), m_value(val) +{ +} + +template +CBotExprLitNum::~CBotExprLitNum() +{ +} + +CBotInstr* CompileExprLitNum(CBotToken* &p, CBotCStack* pStack) { CBotCStack* pStk = pStack->TokenStack(); - CBotExprLitNum* inst = new CBotExprLitNum(); + const auto& s = p->GetString(); - inst->SetToken(p); - std::string s = p->GetString(); + CBotInstr* inst = nullptr; + CBotType numtype = CBotTypInt; - inst->m_numtype = CBotTypInt; if (p->GetType() == TokenTypDef) { - inst->m_valint = p->GetKeywordId(); + inst = new CBotExprLitNum(static_cast(p->GetKeywordId())); } else { if (s.find('.') != std::string::npos || ( s.find('x') == std::string::npos && ( s.find_first_of("eE") != std::string::npos ) )) { - inst->m_numtype = CBotTypFloat; - inst->m_valfloat = GetNumFloat(s); + double val = GetNumFloat(s); + if (val > static_cast(std::numeric_limits::max())) + { + numtype = CBotTypDouble; + inst = new CBotExprLitNum(val); + } + else + { + numtype = CBotTypFloat; + inst = new CBotExprLitNum(static_cast(val)); + } } else { - inst->m_valint = GetNumInt(s); + long val = GetNumInt(s); + if (val > std::numeric_limits::max()) + { + numtype = CBotTypLong; + inst = new CBotExprLitNum(val); + } + else + { + inst = new CBotExprLitNum(static_cast(val)); + } } } + inst->SetToken(p); if (pStk->NextToken(p)) { - CBotVar* var = CBotVar::Create("", inst->m_numtype); + CBotVar* var = CBotVar::Create("", numtype); pStk->SetVar(var); return pStack->Return(inst, pStk); @@ -79,8 +112,48 @@ CBotInstr* CBotExprLitNum::Compile(CBotToken* &p, CBotCStack* pStack) return pStack->Return(nullptr, pStk); } -//////////////////////////////////////////////////////////////////////////////// -bool CBotExprLitNum::Execute(CBotStack* &pj) +CBotInstr* CompileSizeOf(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; + + if (!IsOfType(p, TokenTypVar)) return nullptr; + if (pp->GetString() == "sizeof" && IsOfType(p, ID_OPENPAR)) + { + CBotCStack* pStk = pStack->TokenStack(); + + int value; + + if (IsOfType(p, ID_BYTE)) value = sizeof(signed char); + else if (IsOfType(p, ID_SHORT)) value = sizeof(short); + else if (IsOfType(p, ID_CHAR)) value = sizeof(uint32_t); + else if (IsOfType(p, ID_INT)) value = sizeof(int); + else if (IsOfType(p, ID_LONG)) value = sizeof(long); + else if (IsOfType(p, ID_FLOAT)) value = sizeof(float); + else if (IsOfType(p, ID_DOUBLE)) value = sizeof(double); + else + { + p = pp; + return pStack->Return(nullptr, pStk); + } + + if (IsOfType(p, ID_CLOSEPAR)) + { + auto inst = new CBotExprLitNum(value); + inst->SetToken(pp); + + CBotVar* var = CBotVar::Create("", CBotTypInt); + pStk->SetVar(var); + return pStack->Return(inst, pStk); + } + pStk->SetError(CBotErrClosePar, p->GetStart()); + return pStack->Return(nullptr, pStk); + } + p = pp; + return nullptr; +} + +template +bool CBotExprLitNum::Execute(CBotStack* &pj) { CBotStack* pile = pj->AddStack(this); @@ -88,39 +161,38 @@ bool CBotExprLitNum::Execute(CBotStack* &pj) CBotVar* var = CBotVar::Create("", m_numtype); - std::string nombre ; if (m_token.GetType() == TokenTypDef) { - nombre = m_token.GetString(); + var->SetValInt(m_value, m_token.GetString()); } - - switch (m_numtype) + else { - case CBotTypShort: - case CBotTypInt: - var->SetValInt(m_valint, nombre); - break; - case CBotTypFloat: - var->SetValFloat(m_valfloat); - break; - default: - assert(false); + *var = m_value; } pile->SetVar(var); // place on the stack return pj->Return(pile); // it's ok } -//////////////////////////////////////////////////////////////////////////////// -void CBotExprLitNum::RestoreState(CBotStack* &pj, bool bMain) +template +void CBotExprLitNum::RestoreState(CBotStack* &pj, bool bMain) { if (bMain) pj->RestoreStack(this); } -std::string CBotExprLitNum::GetDebugData() +template +std::string CBotExprLitNum::GetDebugData() { std::stringstream ss; - ss << "(" << (m_numtype == CBotTypFloat ? "float" : "int") << ") " << (m_numtype == CBotTypFloat ? m_valfloat : m_valint); + switch (m_numtype) + { + case CBotTypInt : ss << "(int) "; break; + case CBotTypLong : ss << "(long) "; break; + case CBotTypFloat : ss << "(float) "; break; + case CBotTypDouble: ss << "(double) "; break; + default: assert(false); + } + ss << m_value; return ss.str(); } diff --git a/src/CBot/CBotInstr/CBotExprLitNum.h b/src/CBot/CBotInstr/CBotExprLitNum.h index 414f2d8e..8d7edcc1 100644 --- a/src/CBot/CBotInstr/CBotExprLitNum.h +++ b/src/CBot/CBotInstr/CBotExprLitNum.h @@ -24,26 +24,23 @@ namespace CBot { +CBotInstr* CompileExprLitNum(CBotToken* &p, CBotCStack* pStack); + +CBotInstr* CompileSizeOf(CBotToken* &p, CBotCStack* pStack); + /** * \brief A number literal - 5, 1, 2.5, 3.75, etc. or a predefined numerical constant (see CBotToken::DefineNum()) * - * Can be of type ::CBotTypInt or ::CBotTypFloat + * Can be of type ::CBotTypInt, ::CBotTypLong, ::CBotTypFloat, or ::CBotTypDouble */ +template class CBotExprLitNum : public CBotInstr { public: - CBotExprLitNum(); + CBotExprLitNum(T val); ~CBotExprLitNum(); - /*! - * \brief Compile - * \param p - * \param pStack - * \return - */ - static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); - /*! * \brief Execute Execute, returns the corresponding number. * \param pj @@ -65,10 +62,8 @@ protected: private: //! The type of number. CBotType m_numtype; - //! Value for an int. - long m_valint; - //! Value for a float. - float m_valfloat; + //! Value + T m_value; }; diff --git a/src/CBot/CBotInstr/CBotExprLitString.cpp b/src/CBot/CBotInstr/CBotExprLitString.cpp index 72cca72b..69e42d60 100644 --- a/src/CBot/CBotInstr/CBotExprLitString.cpp +++ b/src/CBot/CBotInstr/CBotExprLitString.cpp @@ -24,6 +24,8 @@ #include "CBot/CBotVar/CBotVar.h" +#include + namespace CBot { @@ -42,7 +44,7 @@ CBotInstr* CBotExprLitString::Compile(CBotToken* &p, CBotCStack* pStack) { CBotCStack* pStk = pStack->TokenStack(); - std::string s = p->GetString(); + const auto& s = p->GetString(); auto it = s.cbegin(); if (++it != s.cend()) @@ -51,7 +53,7 @@ CBotInstr* CBotExprLitString::Compile(CBotToken* &p, CBotCStack* pStack) std::string valstring = ""; while (it != s.cend() && *it != '\"') { - pStk->SetStartError(++pos); + ++pos; if (*it != '\\') // not escape sequence ? { valstring += *(it++); @@ -59,6 +61,7 @@ CBotInstr* CBotExprLitString::Compile(CBotToken* &p, CBotCStack* pStack) } if (++it == s.cend()) break; + pStk->SetStartError(pos); if (CharInList(*it, "01234567")) // octal { diff --git a/src/CBot/CBotInstr/CBotExprUnaire.cpp b/src/CBot/CBotInstr/CBotExprUnaire.cpp index c39fd89e..d9a6c4d4 100644 --- a/src/CBot/CBotInstr/CBotExprUnaire.cpp +++ b/src/CBot/CBotInstr/CBotExprUnaire.cpp @@ -40,8 +40,7 @@ CBotExprUnaire::~CBotExprUnaire() delete m_expr; } -//////////////////////////////////////////////////////////////////////////////// -CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral) +CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral, bool bConstExpr) { int op = p->GetType(); CBotToken* pp = p; @@ -52,8 +51,10 @@ CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLite CBotExprUnaire* inst = new CBotExprUnaire(); inst->SetToken(pp); - if (!bLiteral) inst->m_expr = CBotParExpr::Compile(p, pStk); - else inst->m_expr = CBotParExpr::CompileLitExpr(p, pStk); + if (bConstExpr || !bLiteral) + inst->m_expr = CBotParExpr::Compile(p, pStk, bConstExpr); + else + inst->m_expr = CBotParExpr::CompileLitExpr(p, pStk); if (inst->m_expr != nullptr) { diff --git a/src/CBot/CBotInstr/CBotExprUnaire.h b/src/CBot/CBotInstr/CBotExprUnaire.h index 8a743a81..82d124a5 100644 --- a/src/CBot/CBotInstr/CBotExprUnaire.h +++ b/src/CBot/CBotInstr/CBotExprUnaire.h @@ -40,7 +40,7 @@ public: * \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, bool bLiteral = false); + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral = false, bool bConstExpr = false); /*! * \brief Execute diff --git a/src/CBot/CBotInstr/CBotFor.cpp b/src/CBot/CBotInstr/CBotFor.cpp index 92aafa0b..91013e43 100644 --- a/src/CBot/CBotInstr/CBotFor.cpp +++ b/src/CBot/CBotInstr/CBotFor.cpp @@ -67,7 +67,7 @@ CBotInstr* CBotFor::Compile(CBotToken* &p, CBotCStack* pStack) return nullptr; } - CBotCStack* pStk = pStack->TokenStack(pp, true); // un petit bout de pile svp + CBotCStack* pStk = pStack->TokenStack(pp, true); // some size for a stack, plz // compiles instructions for initialization inst->m_init = CBotListExpression::Compile(p, pStk ); diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index b4473cd8..4916d870 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -169,7 +169,7 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct func->m_token = d; } - // un nom de fonction est-il là ? + // is there a function name here ? if (IsOfType(p, TokenTypVar)) { if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class @@ -284,7 +284,7 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas func->m_token = d; } - // un nom de fonction est-il là ? + // is there a function name here ? if (IsOfType(p, TokenTypVar)) { if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class @@ -584,7 +584,7 @@ CBotFunction* CBotFunction::FindLocalOrPublic(const std::list& lo { int i = 0; int alpha = 0; // signature of parameters - // parameters sont-ils compatibles ? + // are parameters compatible ? CBotDefParam* pv = pt->m_param; // list of expected parameters CBotVar* pw = ppVars[i++]; // list of provided parameters while ( pv != nullptr && (pw != nullptr || pv->HasDefault()) ) diff --git a/src/CBot/CBotInstr/CBotInstr.cpp b/src/CBot/CBotInstr/CBotInstr.cpp index f69785f6..54d9cee9 100644 --- a/src/CBot/CBotInstr/CBotInstr.cpp +++ b/src/CBot/CBotInstr/CBotInstr.cpp @@ -208,10 +208,15 @@ CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack) case ID_THROW: return CBotThrow::Compile(p, pStack); + case ID_BYTE: + case ID_SHORT: + case ID_CHAR: case ID_INT: + case ID_LONG: return CBotDefInt::Compile(p, pStack); case ID_FLOAT: + case ID_DOUBLE: return CBotDefFloat::Compile(p, pStack); case ID_STRING: @@ -312,13 +317,6 @@ void CBotInstr::RestoreStateVar(CBotStack* &pile, bool bMain) assert(0); // dad do not know, see the girls } -//////////////////////////////////////////////////////////////////////////////// -bool CBotInstr::CompCase(CBotStack* &pj, int val) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first) { if (IsOfType(p, ID_OPBRK)) diff --git a/src/CBot/CBotInstr/CBotInstr.h b/src/CBot/CBotInstr/CBotInstr.h index 712b379d..2c4d5884 100644 --- a/src/CBot/CBotInstr/CBotInstr.h +++ b/src/CBot/CBotInstr/CBotInstr.h @@ -191,17 +191,6 @@ public: virtual void RestoreStateVar(CBotStack* &pile, bool bMain); - /** - * \brief CompCase This routine is defined only for the subclass CBotCase - * this allows to make the call on all instructions CompCase to see if it's - * a case to the desired value.. - * \param pj - * \param val - * \return - */ - virtual bool CompCase(CBotStack* &pj, - int val); - /** * \brief SetToken Set the token corresponding to the instruction. * \param p diff --git a/src/CBot/CBotInstr/CBotInstrUtils.cpp b/src/CBot/CBotInstr/CBotInstrUtils.cpp index 04c42211..774a4e37 100644 --- a/src/CBot/CBotInstr/CBotInstrUtils.cpp +++ b/src/CBot/CBotInstr/CBotInstrUtils.cpp @@ -129,6 +129,13 @@ bool TypeCompatible(CBotTypResult& type1, CBotTypResult& type2, int op) return true; } + if (op == ID_ASR || op == ID_SR || op == ID_SL || + op == ID_ASSOR || op == ID_ASSSL || op == ID_ASSSR || + op == ID_ASSAND || op == ID_ASSXOR || op == ID_ASSASR) + { + if (max > CBotTypLong) return false; + } + type1.SetType(max); type2.SetType(max); return true; diff --git a/src/CBot/CBotInstr/CBotParExpr.cpp b/src/CBot/CBotInstr/CBotParExpr.cpp index b879ebec..f3be0593 100644 --- a/src/CBot/CBotInstr/CBotParExpr.cpp +++ b/src/CBot/CBotInstr/CBotParExpr.cpp @@ -21,6 +21,7 @@ #include "CBot/CBotInstr/CBotExpression.h" #include "CBot/CBotInstr/CBotExprLitBool.h" +#include "CBot/CBotInstr/CBotExprLitChar.h" #include "CBot/CBotInstr/CBotExprLitNan.h" #include "CBot/CBotInstr/CBotExprLitNull.h" #include "CBot/CBotInstr/CBotExprLitNum.h" @@ -31,6 +32,7 @@ #include "CBot/CBotInstr/CBotNew.h" #include "CBot/CBotInstr/CBotPostIncExpr.h" #include "CBot/CBotInstr/CBotPreIncExpr.h" +#include "CBot/CBotInstr/CBotTwoOpExpr.h" #include "CBot/CBotVar/CBotVar.h" @@ -39,13 +41,15 @@ namespace CBot { -//////////////////////////////////////////////////////////////////////////////// -CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) +CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack, bool bConstExpr) { CBotCStack* pStk = pStack->TokenStack(); pStk->SetStartError(p->GetStart()); + if (bConstExpr) + return CBotParExpr::CompileConstExpr(p, pStack); + // is it an expression in parentheses? if (IsOfType(p, ID_OPENPAR)) { @@ -68,6 +72,13 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) if (inst != nullptr || !pStk->IsOk()) return pStack->Return(inst, pStk); + // is it sizeof operator ? + inst = CBot::CompileSizeOf(p, pStk); + if (inst != nullptr || !pStk->IsOk()) + { + return pStack->Return(inst, pStk); + } + // is it a variable name? if (p->GetType() == TokenTypVar) { @@ -83,7 +94,7 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) CBotToken* pvar = p; - // no, it an "ordinaty" variable + // no, it's an "ordinaty" variable inst = CBotExprVar::Compile(p, pStk); CBotToken* pp = p; @@ -151,7 +162,21 @@ CBotInstr* CBotParExpr::CompileLitExpr(CBotToken* &p, CBotCStack* pStack) if (p->GetType() == TokenTypNum || p->GetType() == TokenTypDef ) { - CBotInstr* inst = CBotExprLitNum::Compile(p, pStk); + CBotInstr* inst = CBot::CompileExprLitNum(p, pStk); + return pStack->Return(inst, pStk); + } + + // is it sizeof operator ? + inst = CBot::CompileSizeOf(p, pStk); + if (inst != nullptr || !pStk->IsOk()) + { + return pStack->Return(inst, pStk); + } + + // is this a character? + if (p->GetType() == TokenTypChar) + { + CBotInstr* inst = CBotExprLitChar::Compile(p, pStk); return pStack->Return(inst, pStk); } @@ -202,4 +227,55 @@ CBotInstr* CBotParExpr::CompileLitExpr(CBotToken* &p, CBotCStack* pStack) return pStack->Return(nullptr, pStk); } +CBotInstr* CBotParExpr::CompileConstExpr(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + // is it an expression in parentheses? + if (IsOfType(p, ID_OPENPAR)) + { + CBotInstr* inst = CBotTwoOpExpr::Compile(p, pStk, nullptr, true); + + if (nullptr != inst) + { + if (IsOfType(p, ID_CLOSEPAR)) + { + return pStack->Return(inst, pStk); + } + pStk->SetError(CBotErrClosePar, p->GetStart()); + } + delete inst; + return pStack->Return(nullptr, pStk); + } + + // is this a unary operation? + CBotInstr* inst = CBotExprUnaire::Compile(p, pStk, true, true); + if (inst != nullptr || !pStk->IsOk()) + return pStack->Return(inst, pStk); + + // is it a number or DefineNum? + if (p->GetType() == TokenTypNum || + p->GetType() == TokenTypDef ) + { + CBotInstr* inst = CBot::CompileExprLitNum(p, pStk); + return pStack->Return(inst, pStk); + } + + // is this a character? + if (p->GetType() == TokenTypChar) + { + CBotInstr* inst = CBotExprLitChar::Compile(p, pStk); + return pStack->Return(inst, pStk); + } + + // is it sizeof operator ? + inst = CBot::CompileSizeOf(p, pStk); + if (inst != nullptr || !pStk->IsOk()) + { + return pStack->Return(inst, pStk); + } + + return pStack->Return(nullptr, pStk); +} + } // namespace CBot diff --git a/src/CBot/CBotInstr/CBotParExpr.h b/src/CBot/CBotInstr/CBotParExpr.h index 235dab11..826b1cd1 100644 --- a/src/CBot/CBotInstr/CBotParExpr.h +++ b/src/CBot/CBotInstr/CBotParExpr.h @@ -52,7 +52,7 @@ public: * \param pStack * \return */ - static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bConstExpr = false); /*! * \brief Compile a literal expression ("string", number, true, false, null, nan, new) @@ -62,6 +62,8 @@ public: */ static CBotInstr* CompileLitExpr(CBotToken* &p, CBotCStack* pStack); + static CBotInstr* CompileConstExpr(CBotToken* &p, CBotCStack* pStack); + private: CBotParExpr() = delete; CBotParExpr(const CBotParExpr&) = delete; diff --git a/src/CBot/CBotInstr/CBotSwitch.cpp b/src/CBot/CBotInstr/CBotSwitch.cpp index e8d1b24d..f59dc829 100644 --- a/src/CBot/CBotInstr/CBotSwitch.cpp +++ b/src/CBot/CBotInstr/CBotSwitch.cpp @@ -51,13 +51,13 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack) inst->SetToken(p); if (!IsOfType(p, ID_SWITCH)) return nullptr; // should never happen - CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp + CBotCStack* pStk = pStack->TokenStack(pp); // some space for a stack, plz if ( IsOfType(p, ID_OPENPAR ) ) { if ( nullptr != (inst->m_value = CBotExpression::Compile(p, pStk )) ) { - if ( pStk->GetType() < CBotTypLong ) + if ( pStk->GetType() <= CBotTypLong ) { if ( IsOfType(p, ID_CLOSEPAR ) ) { @@ -65,21 +65,35 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack) { IncLvl(); + CBotCase* caseInst = nullptr; + CBotCStack* pStk2 = nullptr; while( !IsOfType( p, ID_CLBLK ) ) { if ( p->GetType() == ID_CASE || p->GetType() == ID_DEFAULT) { - CBotCStack* pStk2 = pStk->TokenStack(p); // un petit bout de pile svp + delete pStk2; + pStk2 = pStk->TokenStack(p, true); // some space for a stack, plz - CBotInstr* i = CBotCase::Compile( p, pStk2 ); - if (i == nullptr) + caseInst = static_cast(CBotCase::Compile(p, pStk2, inst->m_labels)); + if (caseInst == nullptr) { delete inst; return pStack->Return(nullptr, pStk2); } - delete pStk2; - if (inst->m_block == nullptr ) inst->m_block = i; - else inst->m_block->AddNext(i); + + if (inst->m_block == nullptr ) inst->m_block = caseInst; + else inst->m_block->AddNext(caseInst); + + if (ID_DEFAULT == caseInst->GetTokenType()) + { + if (inst->m_default != nullptr) + { + pStk->SetError(CBotErrRedefCase, caseInst->GetToken()); + delete inst; + return pStack->Return(nullptr, pStk); + } + inst->m_default = caseInst; + } continue; } @@ -90,13 +104,14 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack) return pStack->Return(nullptr, pStk); } - CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, true ); - if ( !pStk->IsOk() ) + CBotInstr* i = CBotBlock::CompileBlkOrInst(p, pStk2); + if ( !pStk2->IsOk() ) { delete inst; - return pStack->Return(nullptr, pStk); + return pStack->Return(nullptr, pStk2); } - inst->m_block->AddNext(i); + if (caseInst->m_instr == nullptr ) caseInst->m_instr = i; + else caseInst->m_instr->AddNext(i); if ( p == nullptr ) { @@ -133,40 +148,21 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack) bool CBotSwitch :: Execute(CBotStack* &pj) { CBotStack* pile1 = pj->AddStack(this); // adds an item to the stack -// if ( pile1 == EOX ) return true; - - CBotInstr* p = m_block; // first expression int state = pile1->GetState(); if (state == 0) { if ( !m_value->Execute(pile1) ) return false; - pile1->SetState(state = -1); + pile1->SetState(state = 1); } if ( pile1->IfStep() ) return false; - if ( state == -1 ) - { - state = 0; - int val = pile1->GetVal(); // result of the value + auto it = m_labels.find(pile1->GetVar()->GetValLong()); - CBotStack* pile2 = pile1->AddStack(); - while ( p != nullptr ) // search for the corresponding case in a list - { - state++; - if ( p->CompCase( pile2, val ) ) break; // found the case - p = p->GetNext(); - } - pile2->Delete(); + CBotInstr* p = (it != m_labels.end()) ? it->second : m_default; - if ( p == nullptr ) return pj->Return(pile1); // completed if nothing - - if ( !pile1->SetState(state) ) return false; - } - - p = m_block; // returns to the beginning - while (state-->0) p = p->GetNext(); // advance in the list + while (--state > 0) p = p->GetNext(); while( p != nullptr ) { @@ -185,8 +181,6 @@ void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain) CBotStack* pile1 = pj->RestoreStack(this); // adds an item to the stack if ( pile1 == nullptr ) return; - CBotInstr* p = m_block; // first expression - int state = pile1->GetState(); if (state == 0) { @@ -194,13 +188,11 @@ void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain) return; } - if ( state == -1 ) - { - return; - } + auto it = m_labels.find(pile1->GetVar()->GetValLong()); -// p = m_block; // returns to the beginning - while ( p != nullptr && state-- > 0 ) + CBotInstr* p = (it != m_labels.end()) ? it->second : m_default; + + while (p != nullptr && --state > 0) { p->RestoreState(pile1, false); p = p->GetNext(); // advance in the list diff --git a/src/CBot/CBotInstr/CBotSwitch.h b/src/CBot/CBotInstr/CBotSwitch.h index ca6b2b20..0ebcddf0 100644 --- a/src/CBot/CBotInstr/CBotSwitch.h +++ b/src/CBot/CBotInstr/CBotSwitch.h @@ -21,6 +21,8 @@ #include "CBot/CBotInstr/CBotInstr.h" +#include + namespace CBot { @@ -64,8 +66,12 @@ protected: private: //! Value to seek CBotInstr* m_value; - //! Instructions - CBotInstr* m_block; + //! List of case instructions + CBotInstr* m_block = nullptr; + //! Pointer to default label + CBotInstr* m_default = nullptr; + //! Map of case labels + std::unordered_map m_labels; }; } // namespace CBot diff --git a/src/CBot/CBotInstr/CBotTry.cpp b/src/CBot/CBotInstr/CBotTry.cpp index 1a881c99..ed099033 100644 --- a/src/CBot/CBotInstr/CBotTry.cpp +++ b/src/CBot/CBotInstr/CBotTry.cpp @@ -52,7 +52,7 @@ CBotInstr* CBotTry::Compile(CBotToken* &p, CBotCStack* pStack) inst->SetToken(p); if (!IsOfType(p, ID_TRY)) return nullptr; // should never happen - CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp + CBotCStack* pStk = pStack->TokenStack(pp); // some space for a stack, plz inst->m_block = CBotBlock::CompileBlkOrInst(p, pStk ); CBotCatch** pn = &inst->m_catchList; @@ -102,11 +102,11 @@ bool CBotTry::Execute(CBotStack* &pj) val = pile1->GetError(); if ( val == CBotNoErr && pile1->GetTimer() == 0 ) // mode step? - return false; // does not make the catch + return false; // don't jump to the catch pile1->IncState(); pile2->SetState(val); // stores the error number - pile1->SetError(CBotNoErr); // for now there is are more errors! + pile1->SetError(CBotNoErr); // for now there are more errors! if ( val == CBotNoErr && pile1->GetTimer() < 0 ) // mode step? return false; // does not make the catch @@ -124,8 +124,7 @@ bool CBotTry::Execute(CBotStack* &pj) { if ( --state <= 0 ) { - // request to the catch block if they feel concerned - // demande au bloc catch s'il se sent concerné + // ask to the catch block if it feels concerned if ( !pc->TestCatch(pile2, val) ) return false; // suspend ! pile1->IncState(); } @@ -200,8 +199,7 @@ void CBotTry::RestoreState(CBotStack* &pj, bool bMain) { if ( --state <= 0 ) { - // request to the catch block if they feel concerned - // demande au bloc catch s'il se sent concerné + // ask to the catch block if it feels concerned pc->RestoreCondState(pile2, bMain); // suspend ! return; } diff --git a/src/CBot/CBotInstr/CBotTwoOpExpr.cpp b/src/CBot/CBotInstr/CBotTwoOpExpr.cpp index 3d5fc6a4..554e9022 100644 --- a/src/CBot/CBotInstr/CBotTwoOpExpr.cpp +++ b/src/CBot/CBotInstr/CBotTwoOpExpr.cpp @@ -133,8 +133,7 @@ static bool TypeOk(int type, int test) } } -//////////////////////////////////////////////////////////////////////////////// -CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations) +CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations, bool bConstExpr) { int typeMask; @@ -146,8 +145,8 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera // search the intructions that may be suitable to the left of the operation CBotInstr* left = (*pOp == 0) ? - CBotParExpr::Compile( p, pStk ) : // expression (...) left - CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A * B left + CBotParExpr::Compile(p, pStk, bConstExpr) : // expression (...) left + CBotTwoOpExpr::Compile(p, pStk, pOp, bConstExpr); // expression A * B left if (left == nullptr) return pStack->Return(nullptr, pStk); // if error, transmit @@ -158,7 +157,7 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera CBotTypResult type1, type2; type1 = pStk->GetTypResult(); // what kind of the first operand? - if (typeOp == ID_LOGIC) // special case provided for: ? op1: op2; + if (!bConstExpr && typeOp == ID_LOGIC) // special case provided for: ? op1: op2; { if ( !type1.Eq(CBotTypBoolean) ) { @@ -207,7 +206,7 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera // looking statements that may be suitable for right - if ( nullptr != (inst->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp )) ) + if ( nullptr != (inst->m_rightop = CBotTwoOpExpr::Compile(p, pStk, pOp, bConstExpr)) ) // expression (...) right { // there is an second operand acceptable @@ -264,7 +263,7 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera type1 = TypeRes; p = p->GetNext(); // advance after - i->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp ); + i->m_rightop = CBotTwoOpExpr::Compile(p, pStk, pOp, bConstExpr); type2 = pStk->GetTypResult(); if ( !TypeCompatible (type1, type2, typeOp) ) // the results are compatible @@ -359,7 +358,7 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack) CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack // or return in case of recovery - // 2e état, évalue l'opérande de droite + // 2nd state, evalute right operand if ( pStk2->GetState() == 0 ) { if ( !m_rightop->Execute(pStk2) ) return false; // interrupted here? @@ -399,7 +398,10 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack) TypeRes = CBotTypBoolean; break; case ID_DIV: - TypeRes = std::max(TypeRes, static_cast(CBotTypFloat)); + if (TypeRes == CBotTypFloat) + { + if (type1.Eq(CBotTypLong) || type2.Eq(CBotTypLong)) TypeRes = CBotTypDouble; + } } // creates a variable for the result diff --git a/src/CBot/CBotInstr/CBotTwoOpExpr.h b/src/CBot/CBotInstr/CBotTwoOpExpr.h index c1110e13..baf70a14 100644 --- a/src/CBot/CBotInstr/CBotTwoOpExpr.h +++ b/src/CBot/CBotInstr/CBotTwoOpExpr.h @@ -65,7 +65,7 @@ public: * \param pOperations * \return */ - static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = nullptr); + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = nullptr, bool bConstExpr = false); /*! * \brief Execute Performes the operation on two operands. diff --git a/src/CBot/CBotInstr/CBotWhile.cpp b/src/CBot/CBotInstr/CBotWhile.cpp index 9254ad02..8f55aa1c 100644 --- a/src/CBot/CBotInstr/CBotWhile.cpp +++ b/src/CBot/CBotInstr/CBotWhile.cpp @@ -56,8 +56,7 @@ CBotInstr* CBotWhile::Compile(CBotToken* &p, CBotCStack* pStack) inst->SetToken(p); if (!IsOfType(p, ID_WHILE)) return nullptr; // should never happen - CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp - // a bit of battery please (??) + CBotCStack* pStk = pStack->TokenStack(pp); // some space for a stack, plz if ( nullptr != (inst->m_condition = CBotCondition::Compile(p, pStk )) ) { diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index e8065f47..14ec2b2e 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -24,7 +24,6 @@ #include "CBot/CBotCStack.h" #include "CBot/CBotClass.h" #include "CBot/CBotUtils.h" -#include "CBot/CBotFileUtils.h" #include "CBot/CBotInstr/CBotFunction.h" @@ -332,51 +331,56 @@ bool CBotProgram::DefineNum(const std::string& name, long val) } //////////////////////////////////////////////////////////////////////////////// -bool CBotProgram::SaveState(FILE* pf) +bool CBotProgram::SaveState(std::ostream &ostr) { - if (!WriteWord( pf, CBOTVERSION)) return false; + if (!WriteLong(ostr, CBOTVERSION)) return false; if (m_stack != nullptr ) { - if (!WriteWord( pf, 1)) return false; - if (!WriteString( pf, m_entryPoint->GetName() )) return false; - if (!m_stack->SaveState(pf)) return false; + if (!WriteWord(ostr, 1)) return false; + if (!WriteString(ostr, m_entryPoint->GetName())) return false; + if (!m_stack->SaveState(ostr)) return false; } else { - if (!WriteWord( pf, 0)) return false; + if (!WriteWord(ostr, 0)) return false; } return true; } -bool CBotProgram::RestoreState(FILE* pf) +bool CBotProgram::RestoreState(std::istream &istr) { unsigned short w; std::string s; Stop(); - if (!ReadWord( pf, w )) return false; - if ( w != CBOTVERSION ) return false; + long version; + if (!ReadLong(istr, version)) return false; + if ( version != CBOTVERSION ) return false; - if (!ReadWord( pf, w )) return false; + if (!ReadWord(istr, w)) return false; if ( w == 0 ) return true; - if (!ReadString( pf, s )) return false; - Start(s); // point de reprise + // don't restore if compile error exists + if (m_error != CBotNoErr) return false; - if (m_stack != nullptr) + if (!ReadString(istr, s)) return false; + if (!Start(s)) return false; // point de reprise + // Start() already created the new stack + // and called m_stack->SetProgram(this); + + // retrieves the stack from the memory + if (!m_stack->RestoreState(istr, m_stack)) { m_stack->Delete(); m_stack = nullptr; + m_stack = CBotStack::AllocateStack(); // start from the top + m_stack->SetProgram(this); + return false; // signal error } - // retrieves the stack from the memory - m_stack = CBotStack::AllocateStack(); - if (!m_stack->RestoreState(pf, m_stack)) return false; - m_stack->SetProgram(this); // bases for routines - // restored some states in the stack according to the structure m_entryPoint->RestoreState(nullptr, m_stack, m_thisVar); return true; diff --git a/src/CBot/CBotProgram.h b/src/CBot/CBotProgram.h index e258fff0..c448b82c 100644 --- a/src/CBot/CBotProgram.h +++ b/src/CBot/CBotProgram.h @@ -282,27 +282,20 @@ public: /** * \brief Save the current execution status into a file - * \param pf - * \parblock - * file handle - * - * This file handle must have been opened by this library! Otherwise crashes on Windows - * - * TODO: Verify this - * \endparblock + * \param ostr Output stream * \return true on success, false on write error */ - bool SaveState(FILE* pf); + bool SaveState(std::ostream &ostr); /** * \brief Restore the execution state from a file * * The previous program code must already have been recompiled with Compile() before calling this function * - * \param pf file handle + * \param istr Input stream * \return true on success, false on read error */ - bool RestoreState(FILE* pf); + bool RestoreState(std::istream &istr); /** * \brief GetPosition Gives the position of a routine in the original text diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index 9f9db2d6..5101bbf2 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -26,7 +26,6 @@ #include "CBot/CBotVar/CBotVarPointer.h" #include "CBot/CBotVar/CBotVarClass.h" -#include "CBot/CBotFileUtils.h" #include "CBot/CBotUtils.h" #include "CBot/CBotExternalCall.h" @@ -687,108 +686,106 @@ CBotVar* CBotStack::GetStackVars(std::string& functionName, int level) } //////////////////////////////////////////////////////////////////////////////// -bool CBotStack::SaveState(FILE* pf) +bool CBotStack::SaveState(std::ostream &ostr) { if (m_next2 != nullptr) { - if (!WriteWord(pf, 2)) return false; // a marker of type (m_next2) - if (!m_next2->SaveState(pf)) return false; // saves the next element + if (!WriteWord(ostr, 2)) return false; // a marker of type (m_next2) + if (!m_next2->SaveState(ostr)) return false; // saves the next element } else { - if (!WriteWord(pf, 1)) return false; // a marker of type (m_next) + if (!WriteWord(ostr, 1)) return false; // a marker of type (m_next) } - if (!WriteWord(pf, static_cast(m_block))) return false; - if (!WriteWord(pf, m_state)) return false; - if (!WriteWord(pf, 0)) return false; // for backwards combatibility (m_bDontDelete) - if (!WriteWord(pf, m_step)) return false; + if (!WriteWord(ostr, static_cast(m_block))) return false; + if (!WriteInt(ostr, m_state)) return false; + if (!WriteWord(ostr, 0)) return false; // for backwards combatibility (m_bDontDelete) + if (!WriteInt(ostr, m_step)) return false; - - if (!SaveVars(pf, m_var)) return false; // current result - if (!SaveVars(pf, m_listVar)) return false; // local variables + if (!SaveVars(ostr, m_var)) return false; // current result + if (!SaveVars(ostr, m_listVar)) return false; // local variables if (m_next != nullptr) { - if (!m_next->SaveState(pf)) return false; // saves the next element + if (!m_next->SaveState(ostr)) return false; // saves the next element } else { - if (!WriteWord(pf, 0)) return false; // terminator + if (!WriteWord(ostr, 0)) return false; // 0 - CBotStack::SaveState terminator } return true; } -bool SaveVars(FILE* pf, CBotVar* pVar) +bool SaveVars(std::ostream &ostr, CBotVar* pVar) { while (pVar != nullptr) { - if (!pVar->Save0State(pf)) return false; // common header - if (!pVar->Save1State(pf)) return false; // saves the data + if (!pVar->Save0State(ostr)) return false; // common header + if (!pVar->Save1State(ostr)) return false; // saves the data pVar = pVar->GetNext(); } - return WriteWord(pf, 0); // terminator + return WriteWord(ostr, 0); // 0 - CBot::SaveVars terminator } //////////////////////////////////////////////////////////////////////////////// -bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack) +bool CBotStack::RestoreState(std::istream &istr, CBotStack* &pStack) { unsigned short w; if (pStack != this) pStack = nullptr; - if (!ReadWord(pf, w)) return false; - if ( w == 0 ) return true; // 0 - terminator + if (!ReadWord(istr, w)) return false; + if ( w == 0 ) return true; // 0 - CBotStack::SaveState terminator if (pStack == nullptr) pStack = AddStack(); if ( w == 2 ) // 2 - m_next2 { - if (!pStack->RestoreState(pf, pStack->m_next2)) return false; + if (!pStack->RestoreState(istr, pStack->m_next2)) return false; } - if (!ReadWord(pf, w)) return false; + if (!ReadWord(istr, w)) return false; pStack->m_block = static_cast(w); - if (!ReadWord(pf, w)) return false; - pStack->SetState(static_cast(w)); + int state; + if (!ReadInt(istr, state)) return false; + pStack->SetState(state); - if (!ReadWord(pf, w)) return false; // backwards compatibility (m_bDontDelete) + if (!ReadWord(istr, w)) return false; // backwards compatibility (m_bDontDelete) - if (!ReadWord(pf, w)) return false; - pStack->m_step = w; + if (!ReadInt(istr, state)) return false; + pStack->m_step = state; - if (!CBotVar::RestoreState(pf, pStack->m_var)) return false; // temp variable - if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return false;// local variables + if (!CBotVar::RestoreState(istr, pStack->m_var)) return false; // temp variable + if (!CBotVar::RestoreState(istr, pStack->m_listVar)) return false; // local variables - return pStack->RestoreState(pf, pStack->m_next); + return pStack->RestoreState(istr, pStack->m_next); } //////////////////////////////////////////////////////////////////////////////// -bool CBotVar::Save0State(FILE* pf) +bool CBotVar::Save0State(std::ostream &ostr) { - if (!WriteWord(pf, 100+static_cast(m_mPrivate)))return false; // private variable? - if (!WriteWord(pf, m_bStatic))return false; // static variable? - if (!WriteWord(pf, m_type.GetType()))return false; // saves the type (always non-zero) + if (!WriteWord(ostr, 100+static_cast(m_mPrivate)))return false; // private variable? + if (!WriteWord(ostr, m_bStatic))return false; // static variable? + if (!WriteWord(ostr, m_type.GetType()))return false; // saves the type (always non-zero) if (m_type.Eq(CBotTypPointer) && GetPointer() != nullptr) { if (GetPointer()->m_bConstructor) // constructor was called? { - if (!WriteWord(pf, (2000 + static_cast(m_binit)) )) return false; - return WriteString(pf, m_token->GetString()); // and variable name + if (!WriteWord(ostr, (2000 + static_cast(m_binit)) )) return false; + return WriteString(ostr, m_token->GetString()); // and variable name } } - if (!WriteWord(pf, static_cast(m_binit))) return false; // variable defined? - return WriteString(pf, m_token->GetString()); // and variable name + if (!WriteWord(ostr, static_cast(m_binit))) return false; // variable defined? + return WriteString(ostr, m_token->GetString()); // and variable name } //////////////////////////////////////////////////////////////////////////////// -bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) +bool CBotVar::RestoreState(std::istream &istr, CBotVar* &pVar) { unsigned short w, wi, prv, st; - float ww; - std::string name, s; delete pVar; @@ -798,27 +795,27 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) while ( true ) // retrieves a list { - if (!ReadWord(pf, w)) return false; // private or type? - if ( w == 0 ) return true; + if (!ReadWord(istr, w)) return false; // private or type? + if ( w == 0 ) return true; // 0 - CBot::SaveVars terminator std::string defnum; if ( w == 200 ) { - if (!ReadString(pf, defnum)) return false; // number with identifier - if (!ReadWord(pf, w)) return false; // type + if (!ReadString(istr, defnum)) return false; // number with identifier + if (!ReadWord(istr, w)) return false; // type } prv = 100; st = 0; if ( w >= 100 ) { prv = w; - if (!ReadWord(pf, st)) return false; // static - if (!ReadWord(pf, w)) return false; // type + if (!ReadWord(istr, st)) return false; // static + if (!ReadWord(istr, w)) return false; // type } if ( w == CBotTypClass ) w = CBotTypIntrinsic; // necessarily intrinsic - if (!ReadWord(pf, wi)) return false; // init ? + if (!ReadWord(istr, wi)) return false; // init ? bool bConstructor = false; if (w == CBotTypPointer && wi >= 2000) { @@ -827,31 +824,70 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) } CBotVar::InitType initType = static_cast(wi); - if (!ReadString(pf, name)) return false; // variable name - - CBotToken token(name, std::string()); + std::string varname; + if (!ReadString(istr, varname)) return false; // variable name + CBotToken token(varname, std::string()); bool isClass = false; switch (w) { - case CBotTypInt: case CBotTypBoolean: + char valBool; + if (!ReadByte(istr, valBool)) return false; pNew = CBotVar::Create(token, w); // creates a variable - if (!ReadWord(pf, w)) return false; - pNew->SetValInt(static_cast(w), defnum); + pNew->SetValInt(valBool); + break; + case CBotTypByte: + char valByte; + if (!ReadByte(istr, valByte)) return false; + pNew = CBotVar::Create(token, w); // creates a variable + pNew->SetValByte(valByte); + break; + case CBotTypShort: + short valShort; + if (!ReadShort(istr, valShort)) return false; + pNew = CBotVar::Create(token, w); // creates a variable + pNew->SetValShort(valShort); + break; + case CBotTypChar: + uint32_t valChar; + if (!ReadUInt32(istr, valChar)) return false; + pNew = CBotVar::Create(token, w); // creates a variable + pNew->SetValChar(valChar); + break; + case CBotTypInt: + int valInt; + if (!ReadInt(istr, valInt)) return false; + pNew = CBotVar::Create(token, w); // creates a variable + pNew->SetValInt(valInt, defnum); + break; + case CBotTypLong: + long valLong; + if (!ReadLong(istr, valLong)) return false; + pNew = CBotVar::Create(token, w); // creates a variable + pNew->SetValInt(valLong); break; case CBotTypFloat: + float valFloat; + if (!ReadFloat(istr, valFloat)) return false; pNew = CBotVar::Create(token, w); // creates a variable - if (!ReadFloat(pf, ww)) return false; - pNew->SetValFloat(ww); + pNew->SetValFloat(valFloat); + break; + case CBotTypDouble: + double valDouble; + if (!ReadDouble(istr, valDouble)) return false; + pNew = CBotVar::Create(token, w); // creates a variable + pNew->SetValDouble(valDouble); break; case CBotTypString: - pNew = CBotVar::Create(token, w); // creates a variable - if (!ReadString(pf, s)) return false; - pNew->SetValString(s); - break; - + { + std::string valString; + if (!ReadString(istr, valString)) return false; + pNew = CBotVar::Create(token, w); // creates a variable + pNew->SetValString(valString); + break; + } // returns an intrinsic object or element of an array case CBotTypIntrinsic: isClass = true; @@ -859,17 +895,16 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) { CBotTypResult r; long id; - if (!ReadType(pf, r)) return false; // complete type - if (!ReadLong(pf, id) ) return false; + if (!ReadType(istr, r)) return false; // complete type + if (!ReadLong(istr, id)) return false; -// if (!ReadString(pf, s)) return false; { CBotVar* p = nullptr; if ( id ) p = CBotVarClass::Find(id) ; pNew = new CBotVarClass(token, r); // directly creates an instance // attention cptuse = 0 - if ( !RestoreState(pf, (static_cast(pNew))->m_pVar)) return false; + if (!RestoreState(istr, (static_cast(pNew))->m_pVar)) return false; pNew->SetIdent(id); if (isClass && p == nullptr) // set id for each item in this instance @@ -895,18 +930,20 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) case CBotTypPointer: case CBotTypNullPointer: - if (!ReadString(pf, s)) return false; // name of the class + { + std::string className; + if (!ReadString(istr, className)) return false; // name of the class { - CBotTypResult ptrType(w, s); - pNew = CBotVar::Create(token, ptrType);// creates a variable // CBotVarClass* p = nullptr; long id; - ReadLong(pf, id); + if (!ReadLong(istr, id)) return false; // if ( id ) p = CBotVarClass::Find(id); // found the instance (made by RestoreInstance) + CBotTypResult ptrType(w, className); + pNew = CBotVar::Create(token, ptrType); // creates a variable // returns a copy of the original instance CBotVar* pInstance = nullptr; - if ( !CBotVar::RestoreState( pf, pInstance ) ) return false; + if (!CBotVar::RestoreState(istr, pInstance)) return false; (static_cast(pNew))->SetPointer( pInstance ); // and point over if (bConstructor) pNew->ConstructorSet(); // constructor was called @@ -916,22 +953,22 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) } break; - + } case CBotTypArrayPointer: { CBotTypResult r; - if (!ReadType(pf, r)) return false; + if (!ReadType(istr, r)) return false; pNew = CBotVar::Create(token, r); // creates a variable // returns a copy of the original instance CBotVar* pInstance = nullptr; - if ( !CBotVar::RestoreState( pf, pInstance ) ) return false; + if (!CBotVar::RestoreState(istr, pInstance)) return false; (static_cast(pNew))->SetPointer( pInstance ); // and point over } break; default: - assert(0); + return false; // signal error } if ( pPrev != nullptr ) pPrev->m_next = pNew; diff --git a/src/CBot/CBotStack.h b/src/CBot/CBotStack.h index a72b3e4a..498ccd78 100644 --- a/src/CBot/CBotStack.h +++ b/src/CBot/CBotStack.h @@ -434,8 +434,8 @@ public: //! \name Write to file //@{ - bool SaveState(FILE* pf); - bool RestoreState(FILE* pf, CBotStack* &pStack); + bool SaveState(std::ostream &ostr); + bool RestoreState(std::istream &istr, CBotStack* &pStack); //@} diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp index 9663e299..9764d237 100644 --- a/src/CBot/CBotToken.cpp +++ b/src/CBot/CBotToken.cpp @@ -26,7 +26,8 @@ namespace CBot { -namespace { +namespace +{ template boost::bimap makeBimap(std::initializer_list::value_type> list) { @@ -70,6 +71,11 @@ static const boost::bimap KEYWORDS = makeBimap KEYWORDS = makeBimap>>="}, {ID_ASSASR, ">>="}, {ID_SL, "<<"}, - {ID_SR, ">>"}, + {ID_SR, ">>>"}, {ID_ASR, ">>"}, {ID_INC, "++"}, {ID_DEC, "--"}, @@ -298,12 +304,53 @@ CBotToken* CBotToken::NextToken(const char*& program, bool first) stop = true; } + // special case for characters + if (token[0] == '\'') + { + if (c == '\\') // escape sequence + { + token += c; + c = *(program++); + + if (c == 'u' || c == 'U') // unicode escape + { + int maxlen = (c == 'u') ? 4 : 8; + token += c; + c = *(program++); + for (int i = 0; i < maxlen; i++) + { + if (c == 0 || !CharInList(c, hexnum)) break; + token += c; + c = *(program++); + } + } + else if (c != 0 && !CharInList(c, nch)) // other escape char + { + token += c; + c = *(program++); + } + } + else if (c != 0 && c != '\'' && !CharInList(c, nch)) // single character + { + token += c; + c = *(program++); + } + + if (c == '\'') // close quote + { + token += c; + c = *(program++); + } + stop = true; + } + // special case for numbers if ( CharInList(token[0], num )) { bool bdot = false; // found a point? bool bexp = false; // found an exponent? + char bin[] = "01"; char* liste = num; if (token[0] == '0' && c == 'x') // hexadecimal value? { @@ -311,6 +358,12 @@ CBotToken* CBotToken::NextToken(const char*& program, bool first) c = *(program++); // next character liste = hexnum; } + else if (token[0] == '0' && c == 'b') // binary literal + { + liste = bin; + token += c; + c = *(program++); + } cw: while (c != 0 && CharInList(c, liste)) { @@ -393,6 +446,7 @@ bis: if (CharInList(token[0], num )) t->m_type = TokenTypNum; if (token[0] == '\"') t->m_type = TokenTypString; + if (token[0] == '\'') t->m_type = TokenTypChar; if (first) t->m_type = TokenTypNone; t->m_keywordId = GetKeyWord(token); @@ -449,10 +503,11 @@ std::unique_ptr CBotToken::CompileTokens(const std::string& program) //////////////////////////////////////////////////////////////////////////////// int CBotToken::GetKeyWord(const std::string& w) { - auto it = KEYWORDS.right.find(w); - if (it != KEYWORDS.right.end()) { - return it->second; - } + auto it = KEYWORDS.right.find(w); + if (it != KEYWORDS.right.end()) + { + return it->second; + } return -1; } diff --git a/src/CBot/CBotTypResult.cpp b/src/CBot/CBotTypResult.cpp index 61e96530..60104c80 100644 --- a/src/CBot/CBotTypResult.cpp +++ b/src/CBot/CBotTypResult.cpp @@ -185,8 +185,13 @@ std::string CBotTypResult::ToString() switch (m_type) { case CBotTypVoid: return "void"; + case CBotTypByte: return "byte"; + case CBotTypShort: return "short"; + case CBotTypChar: return "char"; case CBotTypInt: return "int"; + case CBotTypLong: return "long"; case CBotTypFloat: return "float"; + case CBotTypDouble: return "double"; case CBotTypBoolean: return "bool"; case CBotTypString: return "string"; case CBotTypArrayPointer: return m_next->ToString() + "[]"; diff --git a/src/CBot/CBotUtils.cpp b/src/CBot/CBotUtils.cpp index a6c6ef9c..afa05bbc 100644 --- a/src/CBot/CBotUtils.cpp +++ b/src/CBot/CBotUtils.cpp @@ -62,12 +62,27 @@ CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile) switch (p->GetType()) { + case ID_BYTE: + p = p->GetNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypByte )); + case ID_SHORT: + p = p->GetNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypShort )); + case ID_CHAR: + p = p->GetNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypChar )); case ID_INT: p = p->GetNext(); return ArrayType(p, pile, CBotTypResult( CBotTypInt )); + case ID_LONG: + p = p->GetNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypLong )); case ID_FLOAT: p = p->GetNext(); return ArrayType(p, pile, CBotTypResult( CBotTypFloat )); + case ID_DOUBLE: + p = p->GetNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypDouble )); case ID_BOOLEAN: case ID_BOOL: p = p->GetNext(); @@ -108,38 +123,6 @@ CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type) return type; } -//////////////////////////////////////////////////////////////////////////////// -bool WriteWord(FILE* pf, unsigned short w) -{ - size_t lg; - - lg = fwrite(&w, sizeof( unsigned short ), 1, pf ); - - return (lg == 1); -} - -//////////////////////////////////////////////////////////////////////////////// -bool WriteString(FILE* pf, std::string s) -{ - size_t lg1, lg2; - - lg1 = s.size(); - if (!WriteWord(pf, lg1)) return false; - - lg2 = fwrite(s.c_str(), 1, lg1, pf ); - return (lg1 == lg2); -} - -//////////////////////////////////////////////////////////////////////////////// -bool WriteFloat(FILE* pf, float w) -{ - size_t lg; - - lg = fwrite(&w, sizeof( float ), 1, pf ); - - return (lg == 1); -} - //////////////////////////////////////////////////////////////////////////////// long GetNumInt(const std::string& str) { @@ -172,11 +155,23 @@ long GetNumInt(const std::string& str) break; } } + else if (*p == 'b') + { + while (*++p != 0) + { + if (*p == '0' || *p == '1') + { + num = (num << 1) + *p - '0'; + continue; + } + break; + } + } return num; } //////////////////////////////////////////////////////////////////////////////// -float GetNumFloat(const std::string& str) +double GetNumFloat(const std::string& str) { const char* p = str.c_str(); double num = 0; @@ -233,7 +228,7 @@ float GetNumFloat(const std::string& str) } if (bNeg) num = -num; - return static_cast(num); + return num; } bool CharInList(const char c, const char* list) diff --git a/src/CBot/CBotUtils.h b/src/CBot/CBotUtils.h index 9042b0f8..5bc4fe33 100644 --- a/src/CBot/CBotUtils.h +++ b/src/CBot/CBotUtils.h @@ -19,9 +19,8 @@ #pragma once -#include "CBot/CBotTypResult.h" +#include "CBot/CBotFileUtils.h" -#include #include #include @@ -31,6 +30,8 @@ namespace CBot class CBotVar; class CBotToken; class CBotCStack; +class CBotTypResult; + /*! * \brief MakeListVars Transforms the array of pointers to variables in a @@ -58,30 +59,6 @@ CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile); */ CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type); -/*! - * \brief WriteWord - * \param pf - * \param w - * \return - */ -bool WriteWord(FILE* pf, unsigned short w); - -/*! - * \brief WriteString - * \param pf - * \param s - * \return - */ -bool WriteString(FILE* pf, std::string s); - -/*! - * \brief WriteFloat - * \param pf - * \param w - * \return - */ -bool WriteFloat(FILE* pf, float w); - /*! * \brief GetNumInt Converts a string into integer may be of the form 0xabc123. * \param str @@ -94,7 +71,7 @@ long GetNumInt(const std::string& str); * \param str * \return */ -float GetNumFloat(const std::string& str); +double GetNumFloat(const std::string& str); /*! * \brief Search a null-terminated string for a char value. diff --git a/src/CBot/CBotVar/CBotVar.cpp b/src/CBot/CBotVar/CBotVar.cpp index 62ba41f4..23567a52 100644 --- a/src/CBot/CBotVar/CBotVar.cpp +++ b/src/CBot/CBotVar/CBotVar.cpp @@ -24,12 +24,17 @@ #include "CBot/CBotInstr/CBotInstr.h" #include "CBot/CBotVar/CBotVarArray.h" -#include "CBot/CBotVar/CBotVarPointer.h" -#include "CBot/CBotVar/CBotVarClass.h" #include "CBot/CBotVar/CBotVarBoolean.h" -#include "CBot/CBotVar/CBotVarString.h" +#include "CBot/CBotVar/CBotVarByte.h" +#include "CBot/CBotVar/CBotVarChar.h" +#include "CBot/CBotVar/CBotVarClass.h" +#include "CBot/CBotVar/CBotVarDouble.h" #include "CBot/CBotVar/CBotVarFloat.h" #include "CBot/CBotVar/CBotVarInt.h" +#include "CBot/CBotVar/CBotVarLong.h" +#include "CBot/CBotVar/CBotVarPointer.h" +#include "CBot/CBotVar/CBotVarShort.h" +#include "CBot/CBotVar/CBotVarString.h" #include "CBot/CBotClass.h" #include "CBot/CBotToken.h" @@ -134,7 +139,7 @@ void* CBotVar::GetUserPtr() } //////////////////////////////////////////////////////////////////////////////// -bool CBotVar::Save1State(FILE* pf) +bool CBotVar::Save1State(std::ostream &ostr) { // this routine "virtual" must never be called, // there must be a routine for each of the subclasses (CBotVarInt, CBotVarFloat, etc) @@ -160,11 +165,20 @@ CBotVar* CBotVar::Create(const CBotToken& name, CBotTypResult type) { switch (type.GetType()) { + case CBotTypByte: + return new CBotVarByte(name); case CBotTypShort: + return new CBotVarShort(name); + case CBotTypChar: + return new CBotVarChar(name); case CBotTypInt: return new CBotVarInt(name); + case CBotTypLong: + return new CBotVarLong(name); case CBotTypFloat: return new CBotVarFloat(name); + case CBotTypDouble: + return new CBotVarDouble(name); case CBotTypBoolean: return new CBotVarBoolean(name); case CBotTypString: @@ -223,11 +237,20 @@ CBotVar* CBotVar::Create(const std::string& n, CBotTypResult type) switch (type.GetType()) { + case CBotTypByte: + return new CBotVarByte(name); case CBotTypShort: + return new CBotVarShort(name); + case CBotTypChar: + return new CBotVarChar(name); case CBotTypInt: return new CBotVarInt(name); + case CBotTypLong: + return new CBotVarLong(name); case CBotTypFloat: return new CBotVarFloat(name); + case CBotTypDouble: + return new CBotVarDouble(name); case CBotTypBoolean: return new CBotVarBoolean(name); case CBotTypString: @@ -359,7 +382,7 @@ CBotVar::InitType CBotVar::GetInit() const void CBotVar::SetInit(CBotVar::InitType initType) { m_binit = initType; - if (initType == CBotVar::InitType::IS_POINTER ) m_binit = CBotVar::InitType::DEF; // cas spécial + if (initType == CBotVar::InitType::IS_POINTER ) m_binit = CBotVar::InitType::DEF; // special case if ( m_type.Eq(CBotTypPointer) && initType == CBotVar::InitType::IS_POINTER ) { @@ -472,12 +495,27 @@ void CBotVar::SetVal(CBotVar* var) case CBotTypBoolean: SetValInt(var->GetValInt()); break; + case CBotTypByte: + SetValByte(var->GetValByte()); + break; + case CBotTypShort: + SetValShort(var->GetValShort()); + break; + case CBotTypChar: + SetValChar(var->GetValChar()); + break; case CBotTypInt: SetValInt(var->GetValInt(), (static_cast(var))->m_defnum); break; + case CBotTypLong: + SetValLong(var->GetValLong()); + break; case CBotTypFloat: SetValFloat(var->GetValFloat()); break; + case CBotTypDouble: + SetValDouble(var->GetValDouble()); + break; case CBotTypString: SetValString(var->GetValString()); break; @@ -497,7 +535,7 @@ void CBotVar::SetVal(CBotVar* var) assert(0); } - m_binit = var->m_binit; // copie l'état nan s'il y a + m_binit = var->m_binit; // copy the nan status if it has } //////////////////////////////////////////////////////////////////////////////// @@ -545,33 +583,84 @@ CBotVarClass* CBotVar::GetPointer() // All these functions must be defined in the subclasses // derived from class CBotVar -//////////////////////////////////////////////////////////////////////////////// + +signed char CBotVar::GetValByte() +{ + assert(0); + return 0; +} + +short CBotVar::GetValShort() +{ + assert(0); + return 0; +} + +uint32_t CBotVar::GetValChar() +{ + assert(0); + return 0; +} + int CBotVar::GetValInt() { assert(0); return 0; } -//////////////////////////////////////////////////////////////////////////////// +long CBotVar::GetValLong() +{ + assert(0); + return 0; +} + float CBotVar::GetValFloat() { assert(0); return 0; } -//////////////////////////////////////////////////////////////////////////////// +double CBotVar::GetValDouble() +{ + assert(0); + return 0; +} + +void CBotVar::SetValByte(signed char val) +{ + assert(false); +} + +void CBotVar::SetValShort(short val) +{ + assert(false); +} + +void CBotVar::SetValChar(uint32_t val) +{ + assert(false); +} + void CBotVar::SetValInt(int c, const std::string& s) { assert(0); } -//////////////////////////////////////////////////////////////////////////////// +void CBotVar::SetValLong(long val) +{ + assert(false); +} + void CBotVar::SetValFloat(float c) { assert(0); } -//////////////////////////////////////////////////////////////////////////////// +void CBotVar::SetValDouble(double val) +{ + assert(false); +} + void CBotVar::Mul(CBotVar* left, CBotVar* right) { assert(0); @@ -752,16 +841,46 @@ CBotClass* CBotVar::GetClass() return nullptr; } +CBotVar::operator bool() +{ + return static_cast(GetValInt()); +} + +CBotVar::operator signed char() +{ + return GetValByte(); +} + +CBotVar::operator short() +{ + return GetValShort(); +} + +CBotVar::operator uint32_t() +{ + return GetValChar(); +} + CBotVar::operator int() { return GetValInt(); } +CBotVar::operator long() +{ + return GetValLong(); +} + CBotVar::operator float() { return GetValFloat(); } +CBotVar::operator double() +{ + return GetValDouble(); +} + CBotVar::operator std::string() { return GetValString(); @@ -772,16 +891,41 @@ void CBotVar::operator=(const CBotVar &var) SetVal(const_cast(&var)); } +void CBotVar::operator=(signed char x) +{ + SetValByte(x); +} + +void CBotVar::operator=(short x) +{ + SetValShort(x); +} + +void CBotVar::operator=(uint32_t x) +{ + SetValChar(x); +} + void CBotVar::operator=(int x) { SetValInt(x); } +void CBotVar::operator=(long x) +{ + SetValLong(x); +} + void CBotVar::operator=(float x) { SetValFloat(x); } +void CBotVar::operator=(double x) +{ + SetValDouble(x); +} + void CBotVar::operator=(const std::string &x) { SetValString(x); diff --git a/src/CBot/CBotVar/CBotVar.h b/src/CBot/CBotVar/CBotVar.h index d2805ddf..ef86f40f 100644 --- a/src/CBot/CBotVar/CBotVar.h +++ b/src/CBot/CBotVar/CBotVar.h @@ -444,12 +444,23 @@ public: */ //@{ + operator bool(); + operator signed char(); + operator short(); + operator uint32_t(); operator int(); + operator long(); operator float(); + operator double(); operator std::string(); void operator=(const CBotVar& var); + void operator=(signed char x); + void operator=(short x); + void operator=(uint32_t x); void operator=(int x); + void operator=(long x); void operator=(float x); + void operator=(double x); void operator=(const std::string &x); /** @@ -465,6 +476,12 @@ public: */ virtual void Copy(CBotVar* pSrc, bool bName = true); + virtual void SetValByte(signed char val); + + virtual void SetValShort(short val); + + virtual void SetValChar(uint32_t val); + /** * \brief Set value as an integer * @@ -475,30 +492,44 @@ public: */ virtual void SetValInt(int val, const std::string& name = ""); + virtual void SetValLong(long val); + /** * \brief Set value as float * \param val New value */ virtual void SetValFloat(float val); + virtual void SetValDouble(double val); + /** * \brief Set value as string * \param val New value */ virtual void SetValString(const std::string& val); + virtual signed char GetValByte(); + + virtual short GetValShort(); + + virtual uint32_t GetValChar(); + /** * \brief Get value as integer * \return Current value */ virtual int GetValInt(); + virtual long GetValLong(); + /** * \brief Get value as float * \return Current value */ virtual float GetValFloat(); + virtual double GetValDouble(); + /** * \brief Get value as string * @@ -623,28 +654,28 @@ public: /** * \brief Save common variable header (name, type, etc.) - * \param pf file pointer + * \param ostr Output stream * \return false on write error */ - virtual bool Save0State(FILE* pf); + virtual bool Save0State(std::ostream &ostr); /** * \brief Save variable data * * Overriden in child classes * - * \param pf file pointer + * \param ostr Output stream * \return false on write error */ - virtual bool Save1State(FILE* pf); + virtual bool Save1State(std::ostream &ostr); /** * \brief Restore variable - * \param pf file pointer + * \param istr Input stream * \param[out] pVar Pointer to recieve the variable * \return false on read error */ - static bool RestoreState(FILE* pf, CBotVar* &pVar); + static bool RestoreState(std::istream &istr, CBotVar* &pVar); //@} diff --git a/src/CBot/CBotVar/CBotVarArray.cpp b/src/CBot/CBotVar/CBotVarArray.cpp index 6462d119..e6ab0e14 100644 --- a/src/CBot/CBotVar/CBotVarArray.cpp +++ b/src/CBot/CBotVar/CBotVarArray.cpp @@ -20,7 +20,6 @@ #include "CBot/CBotVar/CBotVarArray.h" #include "CBot/CBotVar/CBotVarClass.h" #include "CBot/CBotToken.h" -#include "CBot/CBotFileUtils.h" #include "CBot/CBotEnums.h" @@ -94,7 +93,7 @@ void CBotVarArray::SetPointer(CBotVar* pVarClass) !pVarClass->m_type.Eq(CBotTypArrayBody)) assert(0); - (static_cast(pVarClass))->IncrementUse(); // incement the reference + (static_cast(pVarClass))->IncrementUse(); // increment the reference } if ( m_pInstance != nullptr ) m_pInstance->DecrementUse(); @@ -137,10 +136,10 @@ std::string CBotVarArray::GetValString() } //////////////////////////////////////////////////////////////////////////////// -bool CBotVarArray::Save1State(FILE* pf) +bool CBotVarArray::Save1State(std::ostream &ostr) { - if ( !WriteType(pf, m_type) ) return false; - return SaveVars(pf, m_pInstance); // saves the instance that manages the table + if (!WriteType(ostr, m_type)) return false; + return SaveVars(ostr, m_pInstance); // saves the instance that manages the table } } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarArray.h b/src/CBot/CBotVar/CBotVarArray.h index 68b00b28..fb211055 100644 --- a/src/CBot/CBotVar/CBotVarArray.h +++ b/src/CBot/CBotVar/CBotVarArray.h @@ -51,7 +51,7 @@ public: std::string GetValString() override; - bool Save1State(FILE* pf) override; + bool Save1State(std::ostream &ostr) override; private: //! Array data diff --git a/src/CBot/CBotVar/CBotVarBoolean.cpp b/src/CBot/CBotVar/CBotVarBoolean.cpp index d36de078..b733e933 100644 --- a/src/CBot/CBotVar/CBotVarBoolean.cpp +++ b/src/CBot/CBotVar/CBotVarBoolean.cpp @@ -40,9 +40,9 @@ void CBotVarBoolean::Not() SetValInt(!GetValInt()); } -bool CBotVarBoolean::Save1State(FILE* pf) +bool CBotVarBoolean::Save1State(std::ostream &ostr) { - return WriteWord(pf, m_val); // the value of the variable + return WriteByte(ostr, m_val); // the value of the variable } } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarBoolean.h b/src/CBot/CBotVar/CBotVarBoolean.h index 44774a9f..da810e98 100644 --- a/src/CBot/CBotVar/CBotVarBoolean.h +++ b/src/CBot/CBotVar/CBotVarBoolean.h @@ -37,7 +37,7 @@ public: void XOr(CBotVar* left, CBotVar* right) override; void Not() override; - bool Save1State(FILE* pf) override; + bool Save1State(std::ostream &ostr) override; }; } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarByte.h b/src/CBot/CBotVar/CBotVarByte.h new file mode 100644 index 00000000..68c9088e --- /dev/null +++ b/src/CBot/CBotVar/CBotVarByte.h @@ -0,0 +1,46 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, 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/CBotVar/CBotVarValue.h" + +namespace CBot +{ + +/** + * \brief CBotVar subclass for managing 1-byte integer values (::CBotTypByte) + */ +class CBotVarByte : public CBotVarInteger +{ +public: + CBotVarByte(const CBotToken &name) : CBotVarInteger(name) {} + + void SR(CBotVar* left, CBotVar* right) override + { + SetValByte(static_cast(left->GetValByte()) >> right->GetValInt()); + } + + bool Save1State(std::ostream &ostr) override + { + return WriteByte(ostr, m_val); + } +}; + +} // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarChar.h b/src/CBot/CBotVar/CBotVarChar.h new file mode 100644 index 00000000..07f51358 --- /dev/null +++ b/src/CBot/CBotVar/CBotVarChar.h @@ -0,0 +1,59 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, 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/CBotVar/CBotVarValue.h" + +namespace CBot +{ + +/** + * \brief CBotVar subclass for managing 32-bit Unicode values (::CBotTypChar) + */ +class CBotVarChar : public CBotVarInteger +{ +public: + CBotVarChar(const CBotToken &name) : CBotVarInteger(name) {} + + std::string GetValString() override + { + if (m_binit == CBotVar::InitType::UNDEF) + return LoadString(TX_UNDEF); + if (m_binit == CBotVar::InitType::IS_NAN) + return LoadString(TX_NAN); + + if (0x10FFFF < m_val || (0xD7FF < m_val && m_val < 0xE000)) + return "\xEF\xBF\xBD"; // replacement character U+FFFD + + return CodePointToUTF8(m_val); + } + + void SR(CBotVar* left, CBotVar* right) override + { + SetValChar(left->GetValChar() >> right->GetValInt()); + } + + bool Save1State(std::ostream &ostr) override + { + return WriteUInt32(ostr, m_val); + } +}; + +} // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarClass.cpp b/src/CBot/CBotVar/CBotVarClass.cpp index 36952d18..0fffacf4 100644 --- a/src/CBot/CBotVar/CBotVarClass.cpp +++ b/src/CBot/CBotVar/CBotVarClass.cpp @@ -23,8 +23,6 @@ #include "CBot/CBotStack.h" #include "CBot/CBotDefines.h" -#include "CBot/CBotFileUtils.h" - #include "CBot/CBotInstr/CBotInstr.h" #include @@ -53,7 +51,7 @@ CBotVarClass::CBotVarClass(const CBotToken& name, const CBotTypResult& type) : C m_type = type; if ( type.Eq(CBotTypArrayPointer) ) m_type.SetType( CBotTypArrayBody ); else if ( !type.Eq(CBotTypArrayBody) ) m_type.SetType( CBotTypClass ); - // officel type for this object + // official type for this object m_pClass = nullptr; m_pParent = nullptr; @@ -464,12 +462,12 @@ bool CBotVarClass::Ne(CBotVar* left, CBotVar* right) } //////////////////////////////////////////////////////////////////////////////// -bool CBotVarClass::Save1State(FILE* pf) +bool CBotVarClass::Save1State(std::ostream &ostr) { - if ( !WriteType(pf, m_type) ) return false; - if ( !WriteLong(pf, m_ItemIdent) ) return false; + if (!WriteType(ostr, m_type)) return false; + if (!WriteLong(ostr, m_ItemIdent)) return false; - return SaveVars(pf, m_pVar); // content of the object + return SaveVars(ostr, m_pVar); // content of the object } } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarClass.h b/src/CBot/CBotVar/CBotVarClass.h index 55bdd891..34ec732e 100644 --- a/src/CBot/CBotVar/CBotVarClass.h +++ b/src/CBot/CBotVar/CBotVarClass.h @@ -54,7 +54,7 @@ public: CBotVar* GetItemList() override; std::string GetValString() override; - bool Save1State(FILE* pf) override; + bool Save1State(std::ostream &ostr) override; void Update(void* pUser) override; diff --git a/src/CBot/CBotVar/CBotVarDouble.h b/src/CBot/CBotVar/CBotVarDouble.h new file mode 100644 index 00000000..1df79cfb --- /dev/null +++ b/src/CBot/CBotVar/CBotVarDouble.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, 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/CBotVar/CBotVarValue.h" + +namespace CBot +{ + +/** + * \brief CBotVar subclass for managing double values (::CBotTypDouble) + */ +class CBotVarDouble : public CBotVarNumber +{ +public: + CBotVarDouble(const CBotToken &name) : CBotVarNumber(name) {} + + bool Save1State(std::ostream &ostr) override + { + return WriteDouble(ostr, m_val); + } +}; + +} // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarFloat.cpp b/src/CBot/CBotVar/CBotVarFloat.cpp index a1c4217f..bfa1c1f9 100644 --- a/src/CBot/CBotVar/CBotVarFloat.cpp +++ b/src/CBot/CBotVar/CBotVarFloat.cpp @@ -22,9 +22,9 @@ namespace CBot { -bool CBotVarFloat::Save1State(FILE* pf) +bool CBotVarFloat::Save1State(std::ostream &ostr) { - return WriteFloat(pf, m_val); // the value of the variable + return WriteFloat(ostr, m_val); // the value of the variable } } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarFloat.h b/src/CBot/CBotVar/CBotVarFloat.h index 81cbcde0..dfdecd9b 100644 --- a/src/CBot/CBotVar/CBotVarFloat.h +++ b/src/CBot/CBotVar/CBotVarFloat.h @@ -32,7 +32,7 @@ class CBotVarFloat : public CBotVarNumber public: CBotVarFloat(const CBotToken &name) : CBotVarNumber(name) {} - bool Save1State(FILE* pf) override; + bool Save1State(std::ostream &ostr) override; }; } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarInt.cpp b/src/CBot/CBotVar/CBotVarInt.cpp index 477629ae..cd602614 100644 --- a/src/CBot/CBotVar/CBotVarInt.cpp +++ b/src/CBot/CBotVar/CBotVarInt.cpp @@ -45,67 +45,44 @@ std::string CBotVarInt::GetValString() void CBotVarInt::Neg() { CBotVarNumber::Neg(); - m_defnum.empty(); + m_defnum.clear(); } void CBotVarInt::Inc() { CBotVarNumber::Inc(); - m_defnum.empty(); + m_defnum.clear(); } void CBotVarInt::Dec() { CBotVarNumber::Dec(); - m_defnum.empty(); + m_defnum.clear(); } -void CBotVarInt::XOr(CBotVar* left, CBotVar* right) -{ - SetValInt(left->GetValInt() ^ right->GetValInt()); -} -void CBotVarInt::And(CBotVar* left, CBotVar* right) -{ - SetValInt(left->GetValInt() & right->GetValInt()); -} -void CBotVarInt::Or(CBotVar* left, CBotVar* right) -{ - SetValInt(left->GetValInt() | right->GetValInt()); -} - -void CBotVarInt::SL(CBotVar* left, CBotVar* right) -{ - SetValInt(left->GetValInt() << right->GetValInt()); -} -void CBotVarInt::ASR(CBotVar* left, CBotVar* right) -{ - SetValInt(left->GetValInt() >> right->GetValInt()); -} void CBotVarInt::SR(CBotVar* left, CBotVar* right) { - int source = left->GetValInt(); - int shift = right->GetValInt(); - if (shift >= 1) source &= 0x7fffffff; - SetValInt(source >> shift); + SetValInt(static_cast(left->GetValInt()) >> right->GetValInt()); } void CBotVarInt::Not() { m_val = ~m_val; + m_defnum.clear(); } -bool CBotVarInt::Save0State(FILE* pf) +bool CBotVarInt::Save0State(std::ostream &ostr) { if (!m_defnum.empty()) { - if(!WriteWord(pf, 200)) return false; // special marker - if(!WriteString(pf, m_defnum)) return false; + if(!WriteWord(ostr, 200)) return false; // special marker + if(!WriteString(ostr, m_defnum)) return false; } - return CBotVar::Save0State(pf); + return CBotVar::Save0State(ostr); } -bool CBotVarInt::Save1State(FILE* pf) +bool CBotVarInt::Save1State(std::ostream &ostr) { - return WriteWord(pf, m_val); + return WriteInt(ostr, m_val); } } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarInt.h b/src/CBot/CBotVar/CBotVarInt.h index 906a402d..6fb51208 100644 --- a/src/CBot/CBotVar/CBotVarInt.h +++ b/src/CBot/CBotVar/CBotVarInt.h @@ -27,10 +27,10 @@ namespace CBot /** * \brief CBotVar subclass for managing integer values (::CBotTypInt) */ -class CBotVarInt : public CBotVarNumber +class CBotVarInt : public CBotVarInteger { public: - CBotVarInt(const CBotToken &name) : CBotVarNumber(name) {} + CBotVarInt(const CBotToken &name) : CBotVarInteger(name) {} void SetValInt(int val, const std::string& s = "") override; std::string GetValString() override; @@ -40,18 +40,20 @@ public: void Neg() override; void Inc() override; void Dec() override; - - void XOr(CBotVar* left, CBotVar* right) override; - void Or(CBotVar* left, CBotVar* right) override; - void And(CBotVar* left, CBotVar* right) override; void Not() override; - void SL(CBotVar* left, CBotVar* right) override; void SR(CBotVar* left, CBotVar* right) override; - void ASR(CBotVar* left, CBotVar* right) override; - bool Save0State(FILE* pf) override; - bool Save1State(FILE* pf) override; + bool Save0State(std::ostream &ostr) override; + bool Save1State(std::ostream &ostr) override; + +protected: + + void SetValue(int val) override + { + CBotVarNumberBase::SetValue(val); + m_defnum.clear(); + } protected: //! The name if given by DefineNum. diff --git a/src/CBot/CBotVar/CBotVarLong.h b/src/CBot/CBotVar/CBotVarLong.h new file mode 100644 index 00000000..84164c41 --- /dev/null +++ b/src/CBot/CBotVar/CBotVarLong.h @@ -0,0 +1,46 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, 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/CBotVar/CBotVarValue.h" + +namespace CBot +{ + +/** + * \brief CBotVar subclass for managing long integer values (::CBotTypLong) + */ +class CBotVarLong : public CBotVarInteger +{ +public: + CBotVarLong(const CBotToken &name) : CBotVarInteger(name) {} + + void SR(CBotVar* left, CBotVar* right) override + { + SetValLong(static_cast(left->GetValLong()) >> right->GetValInt()); + } + + bool Save1State(std::ostream &ostr) override + { + return WriteLong(ostr, m_val); + } +}; + +} // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarPointer.cpp b/src/CBot/CBotVar/CBotVarPointer.cpp index 2f78c90a..24f9a5cb 100644 --- a/src/CBot/CBotVar/CBotVarPointer.cpp +++ b/src/CBot/CBotVar/CBotVarPointer.cpp @@ -24,7 +24,6 @@ #include "CBot/CBotEnums.h" #include "CBot/CBotUtils.h" -#include "CBot/CBotFileUtils.h" #include @@ -171,21 +170,21 @@ CBotClass* CBotVarPointer::GetClass() } //////////////////////////////////////////////////////////////////////////////// -bool CBotVarPointer::Save1State(FILE* pf) +bool CBotVarPointer::Save1State(std::ostream &ostr) { if ( m_type.GetClass() != nullptr ) { - if (!WriteString(pf, m_type.GetClass()->GetName())) return false; // name of the class + if (!WriteString(ostr, m_type.GetClass()->GetName())) return false; // name of the class } else { - if (!WriteString(pf, "")) return false; + if (!WriteString(ostr, "")) return false; } - if (!WriteLong(pf, GetIdent())) return false; // the unique reference + if (!WriteLong(ostr, GetIdent())) return false; // the unique reference // also saves the proceedings copies - return SaveVars(pf, GetPointer()); + return SaveVars(ostr, GetPointer()); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/CBot/CBotVar/CBotVarPointer.h b/src/CBot/CBotVar/CBotVarPointer.h index 75c9bc98..6f9c0155 100644 --- a/src/CBot/CBotVar/CBotVarPointer.h +++ b/src/CBot/CBotVar/CBotVarPointer.h @@ -61,7 +61,7 @@ public: void ConstructorSet() override; - bool Save1State(FILE* pf) override; + bool Save1State(std::ostream &ostr) override; void Update(void* pUser) override; diff --git a/src/CBot/CBotVar/CBotVarShort.h b/src/CBot/CBotVar/CBotVarShort.h new file mode 100644 index 00000000..3f0723e3 --- /dev/null +++ b/src/CBot/CBotVar/CBotVarShort.h @@ -0,0 +1,46 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, 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/CBotVar/CBotVarValue.h" + +namespace CBot +{ + +/** + * \brief CBotVar subclass for managing short integer values (::CBotTypShort) + */ +class CBotVarShort : public CBotVarInteger +{ +public: + CBotVarShort(const CBotToken &name) : CBotVarInteger(name) {} + + void SR(CBotVar* left, CBotVar* right) override + { + SetValShort(static_cast(left->GetValShort()) >> right->GetValInt()); + } + + bool Save1State(std::ostream &ostr) override + { + return WriteShort(ostr, m_val); + } +}; + +} // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarString.cpp b/src/CBot/CBotVar/CBotVarString.cpp index 91a0e618..90856b82 100644 --- a/src/CBot/CBotVar/CBotVarString.cpp +++ b/src/CBot/CBotVar/CBotVarString.cpp @@ -37,9 +37,9 @@ bool CBotVarString::Ne(CBotVar* left, CBotVar* right) return left->GetValString() != right->GetValString(); } -bool CBotVarString::Save1State(FILE* pf) +bool CBotVarString::Save1State(std::ostream &ostr) { - return WriteString(pf, m_val); + return WriteString(ostr, m_val); } } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarString.h b/src/CBot/CBotVar/CBotVarString.h index d01a80f6..ac04a310 100644 --- a/src/CBot/CBotVar/CBotVarString.h +++ b/src/CBot/CBotVar/CBotVarString.h @@ -63,7 +63,7 @@ public: bool Eq(CBotVar* left, CBotVar* right) override; bool Ne(CBotVar* left, CBotVar* right) override; - bool Save1State(FILE* pf) override; + bool Save1State(std::ostream &ostr) override; private: template diff --git a/src/CBot/CBotVar/CBotVarValue.h b/src/CBot/CBotVar/CBotVarValue.h index 76e820e8..035d7930 100644 --- a/src/CBot/CBotVar/CBotVarValue.h +++ b/src/CBot/CBotVar/CBotVarValue.h @@ -74,6 +74,13 @@ public: return s.str(); } +protected: + virtual void SetValue(T val) + { + this->m_val = val; + this->m_binit = CBotVar::InitType::DEF; + } + protected: //! The value T m_val; @@ -86,18 +93,59 @@ template class CBotVarNumberBase : public CBotVarValue { public: - CBotVarNumberBase(const CBotToken &name) : CBotVarValue(name) {} + CBotVarNumberBase(const CBotToken &name) : CBotVarValue(name) + { + this->m_val = static_cast(0); + } + + void SetValByte(signed char val) override + { + this->SetValue(static_cast(val)); + } + + void SetValShort(short val) override + { + this->SetValue(static_cast(val)); + } + + void SetValChar(uint32_t val) override + { + this->SetValue(static_cast(val)); + } void SetValInt(int val, const std::string &s = "") override { - this->m_val = static_cast(val); - this->m_binit = CBotVar::InitType::DEF; + this->SetValue(static_cast(val)); + } + + void SetValLong(long val) override + { + this->SetValue(static_cast(val)); } void SetValFloat(float val) override { - this->m_val = static_cast(val); - this->m_binit = CBotVar::InitType::DEF; + this->SetValue(static_cast(val)); + } + + void SetValDouble(double val) override + { + this->SetValue(static_cast(val)); + } + + signed char GetValByte() override + { + return static_cast(this->m_val); + } + + short GetValShort() override + { + return static_cast(this->m_val); + } + + uint32_t GetValChar() override + { + return static_cast(this->m_val); } int GetValInt() override @@ -105,19 +153,28 @@ public: return static_cast(this->m_val); } + long GetValLong() override + { + return static_cast(this->m_val); + } + float GetValFloat() override { return static_cast(this->m_val); } + double GetValDouble() override + { + return static_cast(this->m_val); + } bool Eq(CBotVar* left, CBotVar* right) override { - return left->GetValFloat() == right->GetValFloat(); + return static_cast(*left) == static_cast(*right); } bool Ne(CBotVar* left, CBotVar* right) override { - return left->GetValFloat() != right->GetValFloat(); + return static_cast(*left) != static_cast(*right); } }; @@ -132,33 +189,33 @@ public: void Mul(CBotVar* left, CBotVar* right) override { - this->SetValFloat(left->GetValFloat() * right->GetValFloat()); + this->SetValue(static_cast(*left) * static_cast(*right)); } void Power(CBotVar* left, CBotVar* right) override { - this->SetValFloat(pow(left->GetValFloat(), right->GetValFloat())); + this->SetValue(pow(static_cast(*left), static_cast(*right))); } CBotError Div(CBotVar* left, CBotVar* right) override { - float r = right->GetValFloat(); - if (r == 0) return CBotErrZeroDiv; - this->SetValFloat(left->GetValFloat() / r); + T r = static_cast(*right); + if ( r == static_cast(0) ) return CBotErrZeroDiv; + this->SetValue(static_cast(*left) / r); return CBotNoErr; } CBotError Modulo(CBotVar* left, CBotVar* right) override { - float r = right->GetValFloat(); - if (r == 0) return CBotErrZeroDiv; - this->SetValFloat(fmod(left->GetValFloat(), r)); + T r = static_cast(*right); + if ( r == static_cast(0) ) return CBotErrZeroDiv; + this->SetValue(fmod(static_cast(*left), r)); return CBotNoErr; } void Add(CBotVar* left, CBotVar* right) override { - this->SetValFloat(left->GetValFloat() + right->GetValFloat()); + this->SetValue(static_cast(*left) + static_cast(*right)); } void Sub(CBotVar* left, CBotVar* right) override { - this->SetValFloat(left->GetValFloat() - right->GetValFloat()); + this->SetValue(static_cast(*left) - static_cast(*right)); } void Neg() override @@ -176,21 +233,65 @@ public: bool Lo(CBotVar* left, CBotVar* right) override { - return left->GetValFloat() < right->GetValFloat(); + return static_cast(*left) < static_cast(*right); } bool Hi(CBotVar* left, CBotVar* right) override { - return left->GetValFloat() > right->GetValFloat(); + return static_cast(*left) > static_cast(*right); } bool Ls(CBotVar* left, CBotVar* right) override { - return left->GetValFloat() <= right->GetValFloat(); + return static_cast(*left) <= static_cast(*right); } bool Hs(CBotVar* left, CBotVar* right) override { - return left->GetValFloat() >= right->GetValFloat(); + return static_cast(*left) >= static_cast(*right); } }; -} +/** + * \brief An integer variable (byte, short, char, int, long) + */ +template +class CBotVarInteger : public CBotVarNumber +{ +public: + CBotVarInteger(const CBotToken &name) : CBotVarNumber(name) {} + CBotError Modulo(CBotVar* left, CBotVar* right) override + { + T r = static_cast(*right); + if ( r == static_cast(0) ) return CBotErrZeroDiv; + this->SetValue(static_cast(*left) % r); + return CBotNoErr; + } + + void XOr(CBotVar* left, CBotVar* right) override + { + this->SetValue(static_cast(*left) ^ static_cast(*right)); + } + void And(CBotVar* left, CBotVar* right) override + { + this->SetValue(static_cast(*left) & static_cast(*right)); + } + void Or(CBotVar* left, CBotVar* right) override + { + this->SetValue(static_cast(*left) | static_cast(*right)); + } + + void SL(CBotVar* left, CBotVar* right) override + { + this->SetValue(static_cast(*left) << right->GetValInt()); + } + void ASR(CBotVar* left, CBotVar* right) override + { + this->SetValue(static_cast(*left) >> right->GetValInt()); + } + + void Not() override + { + this->m_val = ~(this->m_val); + } +}; + +} // namespace CBot diff --git a/src/CBot/CMakeLists.txt b/src/CBot/CMakeLists.txt index dcb39e1a..45af8639 100644 --- a/src/CBot/CMakeLists.txt +++ b/src/CBot/CMakeLists.txt @@ -44,6 +44,8 @@ set(SOURCES CBotInstr/CBotEmpty.h CBotInstr/CBotExprLitBool.cpp CBotInstr/CBotExprLitBool.h + CBotInstr/CBotExprLitChar.cpp + CBotInstr/CBotExprLitChar.h CBotInstr/CBotExprLitNan.cpp CBotInstr/CBotExprLitNan.h CBotInstr/CBotExprLitNull.cpp @@ -127,14 +129,19 @@ set(SOURCES CBotVar/CBotVarArray.h CBotVar/CBotVarBoolean.cpp CBotVar/CBotVarBoolean.h + CBotVar/CBotVarByte.h + CBotVar/CBotVarChar.h CBotVar/CBotVarClass.cpp CBotVar/CBotVarClass.h + CBotVar/CBotVarDouble.h CBotVar/CBotVarFloat.cpp CBotVar/CBotVarFloat.h CBotVar/CBotVarInt.cpp CBotVar/CBotVarInt.h + CBotVar/CBotVarLong.h CBotVar/CBotVarPointer.cpp CBotVar/CBotVarPointer.h + CBotVar/CBotVarShort.h CBotVar/CBotVarString.cpp CBotVar/CBotVarString.h stdlib/Compilation.cpp @@ -151,7 +158,12 @@ set(LOCAL_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/.. ) +set(SYSTEM_INCLUDES + ${Boost_INCLUDE_DIRS} +) + include_directories(${LOCAL_INCLUDES}) +include_directories(SYSTEM ${SYSTEM_INCLUDES}) if(CBOT_STATIC) diff --git a/src/CBot/stdlib/FileFunctions.cpp b/src/CBot/stdlib/FileFunctions.cpp index b185ac13..381a7b6d 100644 --- a/src/CBot/stdlib/FileFunctions.cpp +++ b/src/CBot/stdlib/FileFunctions.cpp @@ -181,7 +181,7 @@ CBotTypResult cfopen (CBotVar* pThis, CBotVar* &pVar) // process FILE :: close -// execeution +// execution bool rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user) { // it shouldn't be any parameters diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e0857506..506046c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,8 +44,49 @@ if(MXE) # MXE requires special treatment elseif(PLATFORM_WINDOWS) # because it isn't included in standard linking libraries if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - find_library(LIBINTL_LIBRARY NAMES intl.lib) - set(PLATFORM_LIBS ${LIBINTL_LIBRARY}) + find_library(LIBINTL_LIBRARY NAMES intl.lib libintl) + + if(${MSVC_STATIC}) + if (${OPENAL_SOUND}) + find_library(FLAC_LIBRARY NAMES flac.lib) + find_library(VORBIS_LIBRARY NAMES vorbis.lib) + find_library(VORBISENC_LIBRARY NAMES vorbisenc.lib) + find_library(OGG_LIBRARY NAMES ogg.lib) + set(OPENAL_MSVC_LIBS + ${FLAC_LIBRARY} + ${VORBIS_LIBRARY} + ${VORBISENC_LIBRARY} + ${OGG_LIBRARY} + ) + endif() + + find_library(BZ2_LIBRARY NAMES bz2.lib) + find_library(JPEG_LIBRARY NAMES jpeg.lib) + find_library(TIFF_LIBRARY NAMES tiff.lib) + find_library(LZMA_LIBRARY NAMES lzma.lib) + find_library(FREETYPE_LIBRARY NAMES freetype.lib) + set(MSVC_LIBS + ${LIBINTL_LIBRARY} + ${OPENAL_MSVC_LIBS} + ${JPEG_LIBRARY} + ${TIFF_LIBRARY} + ${BZ2_LIBRARY} + ${LZMA_LIBRARY} + ${FREETYPE_LIBRARY} + winmm.lib + dxguid.lib + imm32.lib + ole32.lib + oleaut32.lib + version.lib + wsock32.lib + ws2_32.lib + ) + else(${MSVC_STATIC}) + set(MSVC_LIBS ${LIBINTL_LIBRARY}) + endif() + + set(PLATFORM_LIBS ${MSVC_LIBS}) else() set(PLATFORM_LIBS "-lintl") endif() @@ -58,6 +99,10 @@ elseif(PLATFORM_MACOSX) find_library(LIBINTL_LIBRARY NAMES intl libintl) find_path(LIBINTL_INCLUDE_PATH NAMES libintl.h) set(PLATFORM_LIBS ${LIBINTL_LIBRARY}) +elseif(PLATFORM_FREEBSD) + find_library(LIBINTL_LIBRARY NAMES intl libintl) + find_path(LIBINTL_INCLUDE_PATH NAMES libintl.h) + set(PLATFORM_LIBS ${LIBINTL_LIBRARY}) endif() @@ -106,6 +151,8 @@ set(BASE_SOURCES common/error.h common/event.cpp common/event.h + common/font_loader.h + common/font_loader.cpp common/global.h common/image.cpp common/image.h diff --git a/src/app/app.cpp b/src/app/app.cpp index 3444481c..6f864572 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -815,11 +815,29 @@ bool CApplication::CreateVideoSurface() m_private->glcontext = SDL_GL_CreateContext(m_private->window); int vsync = 0; - if (GetConfigFile().GetIntProperty("Experimental", "VSync", vsync)) + if (GetConfigFile().GetIntProperty("Setup", "VSync", vsync)) { - SDL_GL_SetSwapInterval(vsync); + while (SDL_GL_SetSwapInterval(vsync) == -1) + { + switch(vsync) + { + case -1: //failed with adaptive sync? + GetLogger()->Warn("Adaptive sync not supported.\n"); + vsync = 1; + break; + case 1: //failed with VSync enabled? + GetLogger()->Warn("Couldn't enable VSync.\n"); + vsync = 0; + break; + case 0: //failed with VSync disabled? + GetLogger()->Warn("Couldn't disable VSync.\n"); + vsync = 1; + break; + } + } + GetConfigFile().SetIntProperty("Setup", "VSync", vsync); - GetLogger()->Info("Using Vsync: %s\n", (vsync ? "true" : "false")); + GetLogger()->Info("Using Vsync: %s\n", (vsync == -1 ? "adaptive" : (vsync ? "true" : "false"))); } return true; @@ -833,6 +851,27 @@ bool CApplication::ChangeVideoConfig(const Gfx::DeviceConfig &newConfig) SDL_SetWindowSize(m_private->window, m_deviceConfig.size.x, m_deviceConfig.size.y); SDL_SetWindowFullscreen(m_private->window, m_deviceConfig.fullScreen ? SDL_WINDOW_FULLSCREEN : 0); + int vsync = m_engine->GetVSync(); + while (SDL_GL_SetSwapInterval(vsync) == -1) + { + switch(vsync) + { + case -1: //failed with adaptive sync? + GetLogger()->Warn("Adaptive sync not supported.\n"); + vsync = 1; + break; + case 1: //failed with VSync enabled? + GetLogger()->Warn("Couldn't enable VSync.\n"); + vsync = 0; + break; + case 0: //failed with VSync disabled? + GetLogger()->Warn("Couldn't disable VSync.\n"); + vsync = 1; + break; + } + } + m_engine->SetVSync(vsync); + m_device->ConfigChanged(m_deviceConfig); m_eventQueue->AddEvent(Event(EVENT_RESOLUTION_CHANGED)); @@ -1718,6 +1757,11 @@ char CApplication::GetLanguageChar() const case LANGUAGE_RUSSIAN: langChar = 'R'; break; + + case LANGUAGE_PORTUGUESE_BRAZILIAN: + langChar = 'B'; + break; + } return langChar; } @@ -1774,6 +1818,10 @@ void CApplication::SetLanguage(Language language) { m_language = LANGUAGE_RUSSIAN; } + else if (strncmp(envLang,"pt",2) == 0) + { + m_language = LANGUAGE_PORTUGUESE_BRAZILIAN; + } else { GetLogger()->Warn("Enviromnent locale ('%s') is not supported, setting default language\n", envLang); @@ -1812,6 +1860,10 @@ void CApplication::SetLanguage(Language language) case LANGUAGE_RUSSIAN: locale = "ru_RU.utf8"; break; + + case LANGUAGE_PORTUGUESE_BRAZILIAN: + locale = "pt_BR.utf8"; + break; } std::string langStr = "LANGUAGE="; @@ -1832,7 +1884,12 @@ void CApplication::SetLanguage(Language language) // Update C++ locale try { +#if defined(_MSC_VER) && defined(_DEBUG) + // Avoids failed assertion in VS debugger + throw -1; +#else std::locale::global(std::locale(systemLocale.c_str())); +#endif } catch (...) { diff --git a/src/app/main.cpp b/src/app/main.cpp index 9fdb89a3..46b0b88f 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -61,7 +61,7 @@ object-oriented language, CBOT, which can be used to program the robots availabl The original version of the game was developed by [Epsitec](http://www.epsitec.ch/) and released in 2001. Later, in 2005 another version named Ceebot was released. In March 2012, through attempts by Polish Colobot fans, Epsitec agreeed to release the source code of the game on GPLv3 license. -The license was given specfifically to our community, TerranovaTeam, +The license was given specifically to our community, TerranovaTeam, part of International Colobot Community (ICC) (previously known as Polish Portal of Colobot (PPC); Polish: Polski Portal Colobota) with our website at http://colobot.info/. diff --git a/src/app/pathman.cpp b/src/app/pathman.cpp index e86780e5..60715ac1 100644 --- a/src/app/pathman.cpp +++ b/src/app/pathman.cpp @@ -38,46 +38,41 @@ #include CPathManager::CPathManager(CSystemUtils* systemUtils) - : m_systemUtils(systemUtils) + : m_dataPath(systemUtils->GetDataPath()) + , m_langPath(systemUtils->GetLangPath()) + , m_savePath(systemUtils->GetSaveDir()) + , m_modAutoloadDir{ m_dataPath + "/mods", m_savePath + "/mods" } + , m_mods{} { - #ifdef PORTABLE - m_dataPath = "./data"; - m_langPath = "./lang"; - m_savePath = "./saves"; - #else - m_dataPath = m_systemUtils->GetDataPath(); - m_langPath = m_systemUtils->GetLangPath(); - #ifdef DEV_BUILD - m_savePath = "./saves"; - #else - m_savePath = m_systemUtils->GetSaveDir(); - #endif - #endif } CPathManager::~CPathManager() { } -void CPathManager::SetDataPath(std::string dataPath) +void CPathManager::SetDataPath(const std::string &dataPath) { m_dataPath = dataPath; } -void CPathManager::SetLangPath(std::string langPath) +void CPathManager::SetLangPath(const std::string &langPath) { m_langPath = langPath; } -void CPathManager::SetSavePath(std::string savePath) +void CPathManager::SetSavePath(const std::string &savePath) { m_savePath = savePath; } -void CPathManager::AddMod(std::string modPath) +void CPathManager::AddModAutoloadDir(const std::string &modAutoloadDirPath) { - GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); - CResourceManager::AddLocation(modPath, true); + m_modAutoloadDir.push_back(modAutoloadDirPath); +} + +void CPathManager::AddMod(const std::string &modPath) +{ + m_mods.push_back(modPath); } const std::string& CPathManager::GetDataPath() @@ -106,8 +101,8 @@ std::string CPathManager::VerifyPaths() { GetLogger()->Error("Data directory '%s' doesn't exist or is not a directory\n", m_dataPath.c_str()); return std::string("Could not read from data directory:\n") + - std::string("'") + m_dataPath + std::string("'\n") + - std::string("Please check your installation, or supply a valid data directory by -datadir option."); + std::string("'") + m_dataPath + std::string("'\n") + + std::string("Please check your installation, or supply a valid data directory by -datadir option."); } #if PLATFORM_WINDOWS @@ -133,19 +128,51 @@ std::string CPathManager::VerifyPaths() void CPathManager::InitPaths() { - LoadModsFromDir(m_dataPath+"/mods"); - LoadModsFromDir(m_savePath+"/mods"); - GetLogger()->Info("Data path: %s\n", m_dataPath.c_str()); GetLogger()->Info("Save path: %s\n", m_savePath.c_str()); - CResourceManager::AddLocation(m_dataPath, false); + if (!m_modAutoloadDir.empty()) + { + GetLogger()->Info("Mod autoload dirs:\n"); + for(const std::string& modAutoloadDir : m_modAutoloadDir) + GetLogger()->Info(" * %s\n", modAutoloadDir.c_str()); + } + if (!m_mods.empty()) + { + GetLogger()->Info("Mods:\n"); + for(const std::string& modPath : m_mods) + GetLogger()->Info(" * %s\n", modPath.c_str()); + } + + CResourceManager::AddLocation(m_dataPath); + + for (const std::string& modAutoloadDir : m_modAutoloadDir) + { + GetLogger()->Trace("Searching for mods in '%s'...\n", modAutoloadDir.c_str()); + for (const std::string& modPath : FindModsInDir(modAutoloadDir)) + { + GetLogger()->Info("Autoloading mod: '%s'\n", modPath.c_str()); + CResourceManager::AddLocation(modPath); + } + } + + for (const std::string& modPath : m_mods) + { + GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); + CResourceManager::AddLocation(modPath); + } + CResourceManager::SetSaveLocation(m_savePath); - CResourceManager::AddLocation(m_savePath, true); + CResourceManager::AddLocation(m_savePath); + + GetLogger()->Debug("Finished initalizing data paths\n"); + GetLogger()->Debug("PHYSFS search path is:\n"); + for (const std::string& path : CResourceManager::GetLocations()) + GetLogger()->Debug(" * %s\n", path.c_str()); } -void CPathManager::LoadModsFromDir(const std::string &dir) +std::vector CPathManager::FindModsInDir(const std::string &dir) { - GetLogger()->Trace("Looking for mods in '%s' ...\n", dir.c_str()); + std::vector ret; try { #if PLATFORM_WINDOWS @@ -156,9 +183,9 @@ void CPathManager::LoadModsFromDir(const std::string &dir) for(; iterator != boost::filesystem::directory_iterator(); ++iterator) { #if PLATFORM_WINDOWS - AddMod(CSystemUtilsWindows::UTF8_Encode(iterator->path().wstring())); + ret.push_back(CSystemUtilsWindows::UTF8_Encode(iterator->path().wstring())); #else - AddMod(iterator->path().string()); + ret.push_back(iterator->path().string()); #endif } } @@ -166,4 +193,5 @@ void CPathManager::LoadModsFromDir(const std::string &dir) { GetLogger()->Warn("Unable to load mods from directory '%s': %s\n", dir.c_str(), e.what()); } + return ret; } diff --git a/src/app/pathman.h b/src/app/pathman.h index 39c780df..dd18d66e 100644 --- a/src/app/pathman.h +++ b/src/app/pathman.h @@ -17,16 +17,10 @@ * along with this program. If not, see http://gnu.org/licenses */ -/** - * \file app/pathman.h - * \brief Class for managing data/lang/save paths - */ - #pragma once -#include "common/singleton.h" - #include +#include class CSystemUtils; @@ -34,16 +28,17 @@ class CSystemUtils; * \class CPathManager * \brief Class for managing data/lang/save paths */ -class CPathManager : public CSingleton +class CPathManager { public: CPathManager(CSystemUtils* systemUtils); ~CPathManager(); - void SetDataPath(std::string dataPath); - void SetLangPath(std::string langPath); - void SetSavePath(std::string savePath); - void AddMod(std::string modPath); + void SetDataPath(const std::string &dataPath); + void SetLangPath(const std::string &langPath); + void SetSavePath(const std::string &savePath); + void AddModAutoloadDir(const std::string &modAutoloadDirPath); + void AddMod(const std::string &modPath); const std::string& GetDataPath(); const std::string& GetLangPath(); @@ -56,14 +51,17 @@ public: private: //! Loads all mods from given directory - void LoadModsFromDir(const std::string &dir); + std::vector FindModsInDir(const std::string &dir); private: - CSystemUtils* m_systemUtils; //! Data path std::string m_dataPath; //! Lang path std::string m_langPath; //! Save path std::string m_savePath; + //! Mod autoload paths + std::vector m_modAutoloadDir; + //! Mod paths + std::vector m_mods; }; diff --git a/src/app/signal_handlers.cpp b/src/app/signal_handlers.cpp index 1974ba3f..03771dab 100644 --- a/src/app/signal_handlers.cpp +++ b/src/app/signal_handlers.cpp @@ -133,7 +133,7 @@ void CSignalHandlers::ReportError(const std::string& errorMessage) msg << "including information on what you were doing before this happened and all the information below." << std::endl; msg << "==============================" << std::endl; #if BUILD_NUMBER == 0 - #ifdef OFFICIAL_BUILD + #ifdef OFFICIAL_COLOBOT_BUILD msg << "You are running official " << COLOBOT_VERSION_DISPLAY << " build." << std::endl; #else // COLOBOT_VERSION_DISPLAY doesn't update if you don't run CMake after "git pull" diff --git a/src/common/config.h.cmake b/src/common/config.h.cmake index b4767724..f6d0bcae 100644 --- a/src/common/config.h.cmake +++ b/src/common/config.h.cmake @@ -16,7 +16,7 @@ #cmakedefine OPENAL_SOUND -#cmakedefine PORTABLE @PORTABLE@ +#cmakedefine PORTABLE_SAVES @PORTABLE_SAVES@ #define COLOBOT_DEFAULT_DATADIR "@COLOBOT_INSTALL_DATA_DIR@" #define COLOBOT_I18N_DIR "@COLOBOT_INSTALL_I18N_DIR@" diff --git a/src/common/event.cpp b/src/common/event.cpp index 8dded9e1..302c2702 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -232,6 +232,7 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_INTERFACE_SHADOW_MAPPING_QUALITY] = "EVENT_INTERFACE_SHADOW_MAPPING_QUALITY"; EVENT_TYPE_TEXT[EVENT_INTERFACE_SHADOW_MAPPING_BUFFER] = "EVENT_INTERFACE_SHADOW_MAPPING_BUFFER"; EVENT_TYPE_TEXT[EVENT_INTERFACE_LANGUAGE] = "EVENT_INTERFACE_LANGUAGE"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_VSYNC] = "EVENT_INTERFACE_VSYNC"; EVENT_TYPE_TEXT[EVENT_INTERFACE_KINFO1] = "EVENT_INTERFACE_KINFO1"; EVENT_TYPE_TEXT[EVENT_INTERFACE_KINFO2] = "EVENT_INTERFACE_KINFO2"; diff --git a/src/common/event.h b/src/common/event.h index 64c52e41..a9353e5e 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -268,6 +268,7 @@ enum EventType EVENT_INTERFACE_SHADOW_MAPPING_QUALITY = 788, EVENT_INTERFACE_SHADOW_MAPPING_BUFFER = 789, EVENT_INTERFACE_LANGUAGE = 790, + EVENT_INTERFACE_VSYNC = 791, EVENT_INTERFACE_KINFO1 = 500, EVENT_INTERFACE_KINFO2 = 501, diff --git a/src/common/font_loader.cpp b/src/common/font_loader.cpp new file mode 100644 index 00000000..79b9375c --- /dev/null +++ b/src/common/font_loader.cpp @@ -0,0 +1,115 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, 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 "common/font_loader.h" + +#include "common/logger.h" +#include "common/make_unique.h" + +#include "common/resources/inputstream.h" +#include "common/resources/outputstream.h" + +#include "common/system/system.h" + +#include "graphics/engine/text.h" + +#include +#include +#include +#include +#include +#include + +namespace bp = boost::property_tree; + +const std::map DEFAULT_FONT = +{ + { Gfx::FONT_COMMON, "dvu_sans.ttf" }, + { Gfx::FONT_COMMON_BOLD, "dvu_sans_bold.ttf" }, + { Gfx::FONT_COMMON_ITALIC, "dvu_sans_italic.ttf" }, + { Gfx::FONT_STUDIO, "dvu_sans_mono.ttf" }, + { Gfx::FONT_STUDIO_BOLD, "dvu_sans_mono_bold.ttf" }, + { Gfx::FONT_STUDIO_ITALIC, "dvu_sans_mono.ttf" }, //placeholder for future use, DejaVu Sans Mono doesn't have italic variant + { Gfx::FONT_SATCOM, "dvu_sans.ttf" }, + { Gfx::FONT_SATCOM_BOLD, "dvu_sans_bold.ttf" }, + { Gfx::FONT_SATCOM_ITALIC, "dvu_sans_italic.ttf" }, +}; + +const std::map FONT_TYPE = +{ + { Gfx::FONT_COMMON, "FontCommon" }, + { Gfx::FONT_COMMON_BOLD, "FontCommonBold" }, + { Gfx::FONT_COMMON_ITALIC, "FontCommonItalic" }, + { Gfx::FONT_STUDIO, "FontStudio" }, + { Gfx::FONT_STUDIO_BOLD, "FontStudioBold" }, + { Gfx::FONT_STUDIO_ITALIC, "FontStudioItalic" }, + { Gfx::FONT_SATCOM, "FontSatCom" }, + { Gfx::FONT_SATCOM_BOLD, "FontSatComBold" }, + { Gfx::FONT_SATCOM_ITALIC, "FontSatComItalic" }, +}; + +CFontLoader::CFontLoader() +{ +} + +CFontLoader::~CFontLoader() +{ +} + +bool CFontLoader::Init() +{ + try + { + std::unique_ptr stream; + auto inputStream = MakeUnique("/fonts/fonts.ini"); + bool good = inputStream->is_open(); + stream = std::move(inputStream); + + if (good) + { + bp::ini_parser::read_ini(*stream, m_propertyTree); + GetLogger()->Debug("Fonts config file loaded correctly. \n"); + } + else + { + return false; + } + } + catch (std::exception & e) + { + GetLogger()->Error("Error on parsing config file: %s\n", e.what()); + return false; + } + return true; +} + +std::string CFontLoader::GetFont(Gfx::FontType type) +{ + return std::string("/fonts/") + m_propertyTree.get(GetFontType(type), GetDefaultFont(type)); +} + +std::string CFontLoader::GetDefaultFont(Gfx::FontType type) const +{ + return DEFAULT_FONT.at(type); +} + +std::string CFontLoader::GetFontType(Gfx::FontType type) const +{ + return FONT_TYPE.at(type); +} diff --git a/src/common/font_loader.h b/src/common/font_loader.h new file mode 100644 index 00000000..a68fc0ad --- /dev/null +++ b/src/common/font_loader.h @@ -0,0 +1,72 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, 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 common/font_loader.h + * \brief Class for loading fonts from /data/fonts/fonts.ini + */ + +#pragma once + +#include "common/singleton.h" + +#include "graphics/engine/text.h" + +#include + +#include + +/** +* \class CFontLoader +* +* \brief Class for loading config file +* +*/ + +class CFontLoader +{ +public: + CFontLoader(); + virtual ~CFontLoader(); + + /** Loads fonts.ini + * \return return true on success + */ + bool Init(); + + /** Reads given font from file + * \return return path to font file + */ + std::string GetFont(Gfx::FontType type); + + /** Const type method to read filenames of fonts from defaultFont map + * used as a fallback if it wasn't possible to read font from fonts.ini + * \return return filename of default path + */ + std::string GetDefaultFont(Gfx::FontType type) const; + + /** Const type method converting Gfx::FontType to string + * \return return id of font used in fonts.ini file + */ + + std::string GetFontType(Gfx::FontType type) const; + +private: + boost::property_tree::ptree m_propertyTree; +}; diff --git a/src/common/language.cpp b/src/common/language.cpp index a9f62419..37a8dca1 100644 --- a/src/common/language.cpp +++ b/src/common/language.cpp @@ -27,7 +27,8 @@ const std::map LANGUAGE_MAP = { { LANGUAGE_GERMAN, "de" }, { LANGUAGE_FRENCH, "fr" }, { LANGUAGE_POLISH, "pl" }, - { LANGUAGE_RUSSIAN, "ru" } + { LANGUAGE_RUSSIAN, "ru" }, + { LANGUAGE_PORTUGUESE_BRAZILIAN, "pt" } }; bool ParseLanguage(const std::string& str, Language& language) diff --git a/src/common/language.h b/src/common/language.h index f25f7f77..0310cb73 100644 --- a/src/common/language.h +++ b/src/common/language.h @@ -33,7 +33,8 @@ enum Language LANGUAGE_GERMAN = 2, LANGUAGE_POLISH = 3, LANGUAGE_RUSSIAN = 4, - LANGUAGE_CZECH = 5 + LANGUAGE_CZECH = 5, + LANGUAGE_PORTUGUESE_BRAZILIAN = 6 }; bool ParseLanguage(const std::string& str, Language& language); diff --git a/src/common/resources/resourcemanager.cpp b/src/common/resources/resourcemanager.cpp index 820495b8..0ad82816 100644 --- a/src/common/resources/resourcemanager.cpp +++ b/src/common/resources/resourcemanager.cpp @@ -85,6 +85,16 @@ bool CResourceManager::RemoveLocation(const std::string &location) return true; } +std::vector CResourceManager::GetLocations() +{ + std::vector ret; + char **list = PHYSFS_getSearchPath(); + for (char **it = list; *it != nullptr; ++it) + ret.push_back(*it); + PHYSFS_freeList(list); + return ret; +} + bool CResourceManager::SetSaveLocation(const std::string &location) { diff --git a/src/common/resources/resourcemanager.h b/src/common/resources/resourcemanager.h index d0b4ab24..95661a4f 100644 --- a/src/common/resources/resourcemanager.h +++ b/src/common/resources/resourcemanager.h @@ -35,8 +35,12 @@ public: static std::string CleanPath(const std::string &path); + //! Add a location to the search path static bool AddLocation(const std::string &location, bool prepend = true); + //! Remove a location from the search path static bool RemoveLocation(const std::string &location); + //! List all locations in the search path + static std::vector GetLocations(); static bool SetSaveLocation(const std::string &location); static std::string GetSaveLocation(); diff --git a/src/common/restext.cpp b/src/common/restext.cpp index c5704362..a79f3f55 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -48,6 +48,9 @@ const char* stringsCbot[CBot::CBotErrMAX] = { nullptr }; */ #define TR(x) x +/* Please run `make update-pot` after changing this file + * in order to update translation files. Thank you. + */ void InitializeRestext() { @@ -145,6 +148,7 @@ void InitializeRestext() stringsText[RT_SCOREBOARD_RESULTS] = TR("Results"); stringsText[RT_SCOREBOARD_RESULTS_TEXT]= TR("The battle has ended"); + stringsText[RT_SCOREBOARD_RESULTS_TIME]= TR("Time: %s"); stringsText[RT_SCOREBOARD_RESULTS_LINE]= TR("%s: %d pts"); @@ -215,6 +219,7 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_SHADOW_MAPPING] = TR("Dynamic shadows\\Beautiful shadows!"); stringsEvent[EVENT_INTERFACE_SHADOW_MAPPING_QUALITY]= TR("Dynamic shadows ++\\Dynamic shadows + self shadowing"); stringsEvent[EVENT_INTERFACE_SHADOW_MAPPING_BUFFER] = TR("Shadow resolution\\Higher means better range and quality, but slower"); + stringsEvent[EVENT_INTERFACE_VSYNC] = TR("Vertical Synchronization\\Limits the number of frames per second to display frequency"); stringsEvent[EVENT_INTERFACE_KDEF] = TR("Standard controls\\Standard key functions"); assert(INPUT_SLOT_MAX < EVENT_INTERFACE_KEY_END-EVENT_INTERFACE_KEY); @@ -737,6 +742,8 @@ void InitializeRestext() stringsCbot[CBot::CBotErrHexDigits] = TR("Missing hex digits after escape sequence"); stringsCbot[CBot::CBotErrHexRange] = TR("Hex value out of range"); stringsCbot[CBot::CBotErrUnicodeName] = TR("Invalid universal character name"); + stringsCbot[CBot::CBotErrCharEmpty] = TR("Empty character constant"); + stringsCbot[CBot::CBotErrRedefCase] = TR("Duplicate label in switch"); stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero"); stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized"); diff --git a/src/common/restext.h b/src/common/restext.h index 80808468..6acfb610 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -142,7 +142,8 @@ enum ResTextType RT_SCOREBOARD_RESULTS = 230, RT_SCOREBOARD_RESULTS_TEXT= 231, - RT_SCOREBOARD_RESULTS_LINE= 232, + RT_SCOREBOARD_RESULTS_TIME= 232, + RT_SCOREBOARD_RESULTS_LINE= 233, RT_MAX //! < number of values diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 93db8102..488666d2 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -112,6 +112,7 @@ void CSettings::SaveSettings() // Experimental settings GetConfigFile().SetBoolProperty("Experimental", "TerrainShadows", engine->GetTerrainShadows()); + GetConfigFile().SetIntProperty("Setup", "VSync", engine->GetVSync()); CInput::GetInstancePointer()->SaveKeyBindings(); @@ -274,6 +275,10 @@ void CSettings::LoadSettings() if (GetConfigFile().GetBoolProperty("Experimental", "TerrainShadows", bValue)) engine->SetTerrainShadows(bValue); + if (GetConfigFile().GetIntProperty("Setup", "VSync", iValue)) + { + engine->SetVSync(iValue); + } CInput::GetInstancePointer()->LoadKeyBindings(); diff --git a/src/common/system/system.cpp b/src/common/system/system.cpp index 01b633cc..12dc1d36 100644 --- a/src/common/system/system.cpp +++ b/src/common/system/system.cpp @@ -20,8 +20,6 @@ #include "common/system/system.h" -#include "common/config.h" - #include "common/make_unique.h" #if defined(PLATFORM_WINDOWS) @@ -190,5 +188,5 @@ std::string CSystemUtils::GetLangPath() std::string CSystemUtils::GetSaveDir() { - return std::string("saves"); + return "./saves"; } diff --git a/src/common/system/system.h b/src/common/system/system.h index aaf54954..36e736c9 100644 --- a/src/common/system/system.h +++ b/src/common/system/system.h @@ -24,6 +24,8 @@ #pragma once +#include "common/config.h" + #include #include #include diff --git a/src/common/system/system_linux.cpp b/src/common/system/system_linux.cpp index 3cd25ed2..9bfe431a 100644 --- a/src/common/system/system_linux.cpp +++ b/src/common/system/system_linux.cpp @@ -96,16 +96,20 @@ long long CSystemUtilsLinux::TimeStampExactDiff(SystemTimeStamp *before, SystemT std::string CSystemUtilsLinux::GetSaveDir() { +#if PORTABLE_SAVES || DEV_BUILD + return CSystemUtils::GetSaveDir(); +#else std::string savegameDir; // Determine savegame dir according to XDG Base Directory Specification - char *envXDG_DATA_HOME = getenv("XDG_CONFIG_DATA"); + char *envXDG_DATA_HOME = getenv("XDG_DATA_HOME"); if (envXDG_DATA_HOME == nullptr) { char *envHOME = getenv("HOME"); if (envHOME == nullptr) { - savegameDir = "/tmp/colobot-save"; + GetLogger()->Warn("Unable to find directory for saves - using current directory"); + savegameDir = "./saves"; } else { @@ -119,6 +123,7 @@ std::string CSystemUtilsLinux::GetSaveDir() GetLogger()->Trace("Saved game files are going to %s\n", savegameDir.c_str()); return savegameDir; +#endif } void CSystemUtilsLinux::Usleep(int usec) diff --git a/src/common/system/system_macosx.cpp b/src/common/system/system_macosx.cpp index ede5b481..9ef7ce1d 100644 --- a/src/common/system/system_macosx.cpp +++ b/src/common/system/system_macosx.cpp @@ -102,10 +102,15 @@ std::string CSystemUtilsMacOSX::GetLangPath() std::string CSystemUtilsMacOSX::GetSaveDir() { +#if PORTABLE_SAVES || DEV_BUILD + // TODO: I have no idea if this actually works on Mac OS + return "./saves"; +#else std::string savegameDir = m_ASPath; GetLogger()->Trace("Saved game files are going to %s\n", savegameDir.c_str()); return savegameDir; +#endif } void CSystemUtilsMacOSX::Usleep(int usec) diff --git a/src/common/system/system_windows.cpp b/src/common/system/system_windows.cpp index f51959b4..a20bfcf1 100644 --- a/src/common/system/system_windows.cpp +++ b/src/common/system/system_windows.cpp @@ -110,11 +110,15 @@ std::wstring CSystemUtilsWindows::UTF8_Decode(const std::string& str) std::string CSystemUtilsWindows::GetSaveDir() { +#if PORTABLE_SAVES || DEV_BUILD + return CSystemUtils::GetSaveDir(); +#else std::string savegameDir; wchar_t* envUSERPROFILE = _wgetenv(L"USERPROFILE"); if (envUSERPROFILE == nullptr) { + GetLogger()->Warn("Unable to find directory for saves - using current directory"); savegameDir = "./saves"; } else @@ -124,6 +128,7 @@ std::string CSystemUtilsWindows::GetSaveDir() GetLogger()->Trace("Saved game files are going to %s\n", savegameDir.c_str()); return savegameDir; +#endif } void CSystemUtilsWindows::Usleep(int usec) diff --git a/src/common/version.h.cmake b/src/common/version.h.cmake index ad3714b3..ca377e4f 100644 --- a/src/common/version.h.cmake +++ b/src/common/version.h.cmake @@ -4,4 +4,4 @@ #define COLOBOT_VERSION_DISPLAY "@COLOBOT_VERSION_DISPLAY@" #define BUILD_NUMBER @BUILD_NUMBER@ -#cmakedefine OFFICIAL_BUILD +#cmakedefine OFFICIAL_COLOBOT_BUILD diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h index 3302488c..2cc94992 100644 --- a/src/graphics/core/device.h +++ b/src/graphics/core/device.h @@ -416,14 +416,6 @@ public: //! Sets only the texture wrap modes (for faster than thru stage params) 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 virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) = 0; diff --git a/src/graphics/core/framebuffer.h b/src/graphics/core/framebuffer.h index e668b036..3c5e6de8 100644 --- a/src/graphics/core/framebuffer.h +++ b/src/graphics/core/framebuffer.h @@ -41,10 +41,15 @@ struct FramebufferParams int depth = 16; //! Requested number of samples for multisampling int samples = 1; - //! true requests color texture - bool colorTexture = false; - //! true requests depth texture - bool depthTexture = false; + + enum class AttachmentType + { + Texture, + Renderbuffer, + None, + }; + AttachmentType colorAttachment = AttachmentType::Renderbuffer; + AttachmentType depthAttachment = AttachmentType::Renderbuffer; //! Loads default values void LoadDefault() diff --git a/src/graphics/core/nulldevice.cpp b/src/graphics/core/nulldevice.cpp index 1fd1a09b..cf9f5a67 100644 --- a/src/graphics/core/nulldevice.cpp +++ b/src/graphics/core/nulldevice.cpp @@ -168,16 +168,6 @@ 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, int first[], int count[], int drawCount, Color color) { diff --git a/src/graphics/core/nulldevice.h b/src/graphics/core/nulldevice.h index 4816251b..0d6c7ab8 100644 --- a/src/graphics/core/nulldevice.h +++ b/src/graphics/core/nulldevice.h @@ -81,11 +81,6 @@ public: 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 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; diff --git a/src/graphics/core/vertex.h b/src/graphics/core/vertex.h index 1af5832e..e5b71733 100644 --- a/src/graphics/core/vertex.h +++ b/src/graphics/core/vertex.h @@ -39,57 +39,11 @@ namespace Gfx { - -/** -* \struct VertexAttribute -* \brief Vertex attribute -* -* This structure contains parameters for a vertex attribute. -*/ -struct VertexAttribute +enum VertexType { - //! 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{}; + VERTEX_TYPE_NORMAL, + VERTEX_TYPE_TEX2, + VERTEX_TYPE_COL, }; /** @@ -105,6 +59,8 @@ struct VertexFormat */ struct Vertex { + static constexpr VertexType VERTEX_TYPE = VERTEX_TYPE_NORMAL; + Math::Vector coord; Math::Vector normal; Math::Point texCoord; @@ -137,6 +93,8 @@ struct Vertex */ struct VertexCol { + static constexpr VertexType VERTEX_TYPE = VERTEX_TYPE_COL; + Math::Vector coord; Color color; @@ -166,6 +124,8 @@ struct VertexCol */ struct VertexTex2 { + static constexpr VertexType VERTEX_TYPE = VERTEX_TYPE_TEX2; + Math::Vector coord; Math::Vector normal; Math::Point texCoord; diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 40d4d1d1..348514bb 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -197,6 +197,7 @@ CEngine::CEngine(CApplication *app, CSystemUtils* systemUtils) m_terrainShadows = false; m_shadowRange = 0.0f; m_multisample = 2; + m_vsync = 0; m_backForce = true; m_lightMode = true; @@ -323,6 +324,7 @@ bool CEngine::Create() SetShadowMappingOffscreen(m_offscreenShadowRendering); SetShadowMappingOffscreenResolution(m_offscreenShadowRenderingResolution); SetMultiSample(m_multisample); + SetVSync(m_vsync); m_modelManager = MakeUnique(this); m_pyroManager = MakeUnique(); @@ -431,7 +433,7 @@ bool CEngine::ProcessEvent(const Event &event) { auto data = event.GetData(); - if (data->key == KEY(F12)) + if (data->key == KEY(F11) || data->key == KEY(F12)) { m_showStats = !m_showStats; return false; @@ -3023,6 +3025,19 @@ bool CEngine::GetTerrainShadows() return m_terrainShadows; } +void CEngine::SetVSync(int value) +{ + if (value < -1) value = -1; + if (value > 1) value = 1; + if(m_vsync == value) return; + m_vsync = value; +} + +int CEngine::GetVSync() +{ + return m_vsync; +} + void CEngine::SetBackForce(bool present) { m_backForce = present; @@ -3786,7 +3801,8 @@ void CEngine::RenderShadowMap() FramebufferParams params; params.width = params.height = width; params.depth = depth = 32; - params.depthTexture = true; + params.colorAttachment = FramebufferParams::AttachmentType::None; + params.depthAttachment = FramebufferParams::AttachmentType::Texture; CFramebuffer *framebuffer = m_device->CreateFramebuffer("shadow", params); if (framebuffer == nullptr) @@ -4032,7 +4048,10 @@ void CEngine::UseMSAA(bool enable) } } - framebuffer->Bind(); + if (framebuffer != nullptr) + { + framebuffer->Bind(); + } m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, true); m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, true); @@ -5117,7 +5136,7 @@ void CEngine::DrawStats() if (!m_showStats) return; - float height = m_text->GetAscent(FONT_COLOBOT, 13.0f); + float height = m_text->GetAscent(FONT_COMMON, 13.0f); float width = 0.4f; const int TOTAL_LINES = 22; @@ -5144,13 +5163,13 @@ void CEngine::DrawStats() auto drawStatsLine = [&](const std::string& name, const std::string& value, const std::string& value2) { if (!name.empty()) - m_text->DrawText(name+":", FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + m_text->DrawText(name+":", FONT_COMMON, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); pos.x += 0.25f; if (!value.empty()) - m_text->DrawText(value, FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + m_text->DrawText(value, FONT_COMMON, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); pos.x += 0.15f; if (!value2.empty()) - m_text->DrawText(value2, FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_RIGHT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + m_text->DrawText(value2, FONT_COMMON, 12.0f, pos, 1.0f, TEXT_ALIGN_RIGHT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); pos.x -= 0.4f; pos.y -= height; }; @@ -5218,8 +5237,8 @@ void CEngine::DrawTimer() { SetState(ENG_RSTATE_TEXT); - Math::Point pos(0.98f, 0.98f-m_text->GetAscent(FONT_COLOBOT, 15.0f)); - m_text->DrawText(m_timerText, FONT_COLOBOT, 15.0f, pos, 1.0f, TEXT_ALIGN_RIGHT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + Math::Point pos(0.98f, 0.98f-m_text->GetAscent(FONT_COMMON, 15.0f)); + m_text->DrawText(m_timerText, FONT_COMMON, 15.0f, pos, 1.0f, TEXT_ALIGN_RIGHT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); } void CEngine::AddBaseObjTriangles(int baseObjRank, const std::vector& triangles) diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 794bd9e8..88a35dda 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -1072,6 +1072,13 @@ public: bool GetTerrainShadows(); //@} + //@{ + //! Management of vertical synchronization + // NOTE: This is an user configuration setting + void SetVSync(int value); + int GetVSync(); + //@} + //@{ //! Management of shadow color // NOTE: This is a setting configurable only in INI file @@ -1336,6 +1343,9 @@ protected: //! Texture bias for sampling shadow maps Math::Matrix m_shadowBias; + //! Vertical synchronization controll + int m_vsync; + //! World matrix for 2D interface Math::Matrix m_matWorldInterface; //! Projection matrix for 2D interface diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp index 233e5974..effbaff5 100644 --- a/src/graphics/engine/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -877,7 +877,7 @@ void CParticle::FrameParticle(float rTime) m_track[r].drawParticle = (progress < 1.0f); } - if (m_particle[i].type == PARTITRACK1) // explosion technique? + if (m_particle[i].type == PARTITRACK1) // technical explosion? { m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); @@ -2407,7 +2407,7 @@ void CParticle::FrameParticle(float rTime) ti.y = ts.y+0.125f; } - if (m_particle[i].type == PARTIRAY1) // rayon tour ? + if (m_particle[i].type == PARTIRAY1) // tower ray ? { if (progress >= 1.0f) { @@ -2517,7 +2517,7 @@ void CParticle::TrackDraw(int i, ParticleType type) Math::Point texInf, texSup; - if (type == PARTITRACK1) // explosion technique? + if (type == PARTITRACK1) // technical explosion? { texInf.x = 64.5f/256.0f; texInf.y = 21.0f/256.0f; @@ -3301,7 +3301,7 @@ void CParticle::DrawParticleCylinder(int i) void CParticle::DrawParticleText(int i) { - CharTexture tex = m_engine->GetText()->GetCharTexture(static_cast(m_particle[i].text), FONT_COURIER, FONT_SIZE_BIG*2.0f); + CharTexture tex = m_engine->GetText()->GetCharTexture(static_cast(m_particle[i].text), FONT_STUDIO, FONT_SIZE_BIG*2.0f); if (tex.id == 0) return; m_device->SetTexture(0, tex.id); diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index 0ecd5820..df284160 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -22,6 +22,7 @@ #include "app/app.h" +#include "common/font_loader.h" #include "common/image.h" #include "common/logger.h" #include "common/stringutils.h" @@ -32,6 +33,7 @@ #include "math/func.h" +#include #include #include @@ -174,7 +176,7 @@ CText::CText(CEngine* engine) m_defaultSize = 12.0f; m_tabSize = 4; - m_lastFontType = FONT_COLOBOT; + m_lastFontType = FONT_COMMON; m_lastFontSize = 0; m_lastCachedFont = nullptr; @@ -189,18 +191,23 @@ CText::~CText() bool CText::Create() { + CFontLoader fontLoader; + if (!fontLoader.Init()) + { + GetLogger()->Warn("Error on parsing fonts config file: failed to open file\n"); + } if (TTF_Init() != 0) { m_error = std::string("TTF_Init error: ") + std::string(TTF_GetError()); return false; } - m_fonts[FONT_COLOBOT] = MakeUnique("fonts/dvu_sans.ttf"); - m_fonts[FONT_COLOBOT_BOLD] = MakeUnique("fonts/dvu_sans_bold.ttf"); - m_fonts[FONT_COLOBOT_ITALIC] = MakeUnique("fonts/dvu_sans_italic.ttf"); - - m_fonts[FONT_COURIER] = MakeUnique("fonts/dvu_sans_mono.ttf"); - m_fonts[FONT_COURIER_BOLD] = MakeUnique("fonts/dvu_sans_mono_bold.ttf"); + for (auto type : {FONT_COMMON, FONT_STUDIO, FONT_SATCOM}) + { + m_fonts[static_cast(type)] = MakeUnique(fontLoader.GetFont(type)); + m_fonts[static_cast(type|FONT_BOLD)] = MakeUnique(fontLoader.GetFont(static_cast(type|FONT_BOLD))); + m_fonts[static_cast(type|FONT_ITALIC)] = MakeUnique(fontLoader.GetFont(static_cast(type|FONT_ITALIC))); + } for (auto it = m_fonts.begin(); it != m_fonts.end(); ++it) { @@ -218,7 +225,7 @@ void CText::Destroy() m_fonts.clear(); m_lastCachedFont = nullptr; - m_lastFontType = FONT_COLOBOT; + m_lastFontType = FONT_COMMON; m_lastFontSize = 0; TTF_Quit(); @@ -253,7 +260,7 @@ void CText::FlushCache() } m_lastCachedFont = nullptr; - m_lastFontType = FONT_COLOBOT; + m_lastFontType = FONT_COMMON; m_lastFontSize = 0; } @@ -336,8 +343,8 @@ void CText::SizeText(const std::string &text, std::vector::iterato end.x -= sw; } - start.y -= GetDescent(FONT_COLOBOT, size); - end.y += GetAscent(FONT_COLOBOT, size); + start.y -= GetDescent(FONT_COMMON, size); + end.y += GetAscent(FONT_COMMON, size); } void CText::SizeText(const std::string &text, FontType font, @@ -417,7 +424,7 @@ float CText::GetStringWidth(const std::string &text, unsigned int fmtIndex = 0; while (index < text.length()) { - FontType font = FONT_COLOBOT; + FontType font = FONT_COMMON; if (format + fmtIndex != end) font = static_cast(*(format + fmtIndex) & FONT_MASK_FONT); @@ -464,7 +471,7 @@ float CText::GetCharWidth(UTF8Char ch, FontType font, float size, float offset) if (font == FONT_BUTTON) { Math::IntPoint windowSize = m_engine->GetWindowSize(); - float height = GetHeight(FONT_COLOBOT, size); + float height = GetHeight(FONT_COMMON, size); float width = height*(static_cast(windowSize.y)/windowSize.x); return width; } @@ -506,7 +513,7 @@ int CText::GetCharWidthInt(UTF8Char ch, FontType font, float size, float offset) if (font == FONT_BUTTON) { Math::IntPoint windowSize = m_engine->GetWindowSize(); - int height = GetHeightInt(FONT_COLOBOT, size); + int height = GetHeightInt(FONT_COMMON, size); int width = height*(static_cast(windowSize.y)/windowSize.x); return width; } @@ -552,7 +559,7 @@ int CText::Justify(const std::string &text, std::vector::iterator unsigned int fmtIndex = 0; while (index < text.length()) { - FontType font = FONT_COLOBOT; + FontType font = FONT_COMMON; if (format + fmtIndex != end) font = static_cast(*(format + fmtIndex) & FONT_MASK_FONT); @@ -636,7 +643,7 @@ int CText::Detect(const std::string &text, std::vector::iterator f unsigned int fmtIndex = 0; while (index < text.length()) { - FontType font = FONT_COLOBOT; + FontType font = FONT_COMMON; if (format + fmtIndex != end) font = static_cast(*(format + fmtIndex) & FONT_MASK_FONT); @@ -773,7 +780,7 @@ void CText::DrawString(const std::string &text, std::vector::itera StringToUTFCharList(text, chars, format, end); for (auto it = chars.begin(); it != chars.end(); ++it) { - FontType font = FONT_COLOBOT; + FontType font = FONT_COMMON; if (format + fmtIndex != end) font = static_cast(*(format + fmtIndex) & FONT_MASK_FONT); @@ -846,7 +853,7 @@ void CText::DrawString(const std::string &text, std::vector::itera if (eol != 0) { - FontType font = FONT_COLOBOT; + FontType font = FONT_COMMON; UTF8Char ch = TranslateSpecialChar(eol); color = Color(1.0f, 0.0f, 0.0f); DrawCharAndAdjustPos(ch, font, size, pos, color); @@ -887,7 +894,7 @@ void CText::StringToUTFCharList(const std::string &text, std::vector & { UTF8Char ch; - FontType font = FONT_COLOBOT; + FontType font = FONT_COMMON; if (format + index != end) font = static_cast(*(format + index) & FONT_MASK_FONT); @@ -993,7 +1000,7 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::I if (font == FONT_BUTTON) { Math::IntPoint windowSize = m_engine->GetWindowSize(); - int height = GetHeightInt(FONT_COLOBOT, size); + int height = GetHeightInt(FONT_COMMON, size); int width = height * (static_cast(windowSize.y)/windowSize.x); Math::IntPoint p1(pos.x, pos.y - height); @@ -1004,22 +1011,9 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::I // For whatever reason ch.c1 is a SIGNED char, we need to fix that unsigned char icon = static_cast(ch.c1); - unsigned int texID; - - if ( icon >= 128 ) - { - icon -= 128; - texID = m_engine->LoadTexture("textures/interface/button3.png").id; - } - else if ( icon >= 64 ) - { - icon -= 64; - texID = m_engine->LoadTexture("textures/interface/button2.png").id; - } - else - { - texID = m_engine->LoadTexture("textures/interface/button1.png").id; - } + // TODO: A bit of code duplication, see CControl::SetButtonTextureForIcon() + unsigned int texID = m_engine->LoadTexture("textures/interface/button" + StrUtils::ToString((icon/64) + 1) + ".png").id; + icon = icon%64; Math::Point uv1, uv2; uv1.x = (32.0f / 256.0f) * (icon%8); @@ -1259,13 +1253,13 @@ FontTexture CText::CreateFontTexture(Math::IntPoint tileSize) Math::IntPoint CText::GetNextTilePos(const FontTexture& fontTexture) { - int horizontalTiles = FONT_TEXTURE_SIZE.x / fontTexture.tileSize.x; - int verticalTiles = FONT_TEXTURE_SIZE.y / fontTexture.tileSize.y; + int horizontalTiles = FONT_TEXTURE_SIZE.x / std::max(1, fontTexture.tileSize.x); //this should prevent crashes in some combinations of resolution and font size, see issue #1128 + int verticalTiles = FONT_TEXTURE_SIZE.y / std::max(1, fontTexture.tileSize.y); int totalTiles = horizontalTiles * verticalTiles; int tileNumber = totalTiles - fontTexture.freeSlots; - int verticalTileIndex = tileNumber / horizontalTiles; + int verticalTileIndex = tileNumber / std::max(1, horizontalTiles); int horizontalTileIndex = tileNumber % horizontalTiles; return Math::IntPoint(horizontalTileIndex * fontTexture.tileSize.x, diff --git a/src/graphics/engine/text.h b/src/graphics/engine/text.h index 40fb90fa..0405c7d2 100644 --- a/src/graphics/engine/text.h +++ b/src/graphics/engine/text.h @@ -77,18 +77,25 @@ enum FontType FONT_ITALIC = 0x08, //! Default colobot font used for interface - FONT_COLOBOT = 0x00, + FONT_COMMON = 0x00, //! Alias for bold colobot font - FONT_COLOBOT_BOLD = FONT_COLOBOT | FONT_BOLD, + FONT_COMMON_BOLD = FONT_COMMON | FONT_BOLD, //! Alias for italic colobot font - FONT_COLOBOT_ITALIC = FONT_COLOBOT | FONT_ITALIC, + FONT_COMMON_ITALIC = FONT_COMMON | FONT_ITALIC, - //! Courier (monospace) font used mainly in code editor (only regular & bold) - FONT_COURIER = 0x01, - //! Alias for bold courier font - FONT_COURIER_BOLD = FONT_COURIER | FONT_BOLD, + //! Studio font used mainly in code editor + FONT_STUDIO = 0x01, + //! Alias for bold studio font + FONT_STUDIO_BOLD = FONT_STUDIO | FONT_BOLD, + //! Alias for italic studio font (at this point not used anywhere) + FONT_STUDIO_ITALIC = FONT_STUDIO | FONT_ITALIC, - // 0x02 left for possible another font + //! SatCom font used for interface (currently bold and italic wariants aren't used anywhere) + FONT_SATCOM = 0x02, + //! Alias for bold satcom font + FONT_SATCOM_BOLD = FONT_SATCOM | FONT_BOLD, + //! Alias for italic satcom font + FONT_SATCOM_ITALIC = FONT_SATCOM | FONT_ITALIC, //! Pseudo-font loaded from textures for buttons, icons, etc. FONT_BUTTON = 0x03, diff --git a/src/graphics/model/model_io_structs.h b/src/graphics/model/model_io_structs.h index 36f4f7f1..5646bafd 100644 --- a/src/graphics/model/model_io_structs.h +++ b/src/graphics/model/model_io_structs.h @@ -188,7 +188,7 @@ struct OldModelTriangleV1 Vertex p2; Vertex p3; Material material; - char texName[20] = {}; + char texName[21] = {'\0'}; float min = 0; float max = 0; }; @@ -207,7 +207,7 @@ struct OldModelTriangleV2 Vertex p2; Vertex p3; Material material; - char texName[20] = {}; + char texName[21] = {'\0'}; float min = 0.0f; float max = 0.0f; long state = 0; @@ -231,7 +231,7 @@ struct OldModelTriangleV3 VertexTex2 p2; VertexTex2 p3; Material material; - char texName[20] = {}; + char texName[21] = {'\0'}; float min = 0.0f; float max = 0.0f; long state = 0; diff --git a/src/graphics/model/model_output.cpp b/src/graphics/model/model_output.cpp index 15ebeb75..ef94a3a5 100644 --- a/src/graphics/model/model_output.cpp +++ b/src/graphics/model/model_output.cpp @@ -328,7 +328,10 @@ void ModelOutput::WriteOldModel(const CModel& model, std::ostream &stream) t.material.ambient = triangle.ambient; t.material.diffuse = triangle.diffuse; t.material.specular = triangle.specular; - strncpy(t.texName, triangle.tex1Name.c_str(), 20); + + strncpy(t.texName, triangle.tex1Name.c_str(), sizeof(t.texName)-1); + t.texName[sizeof(t.texName)-1] = '\0'; + t.min = 0.0f; t.max = 1000000.0f; t.state = ConvertToOldState(triangle); diff --git a/src/graphics/opengl/gl14device.cpp b/src/graphics/opengl/gl14device.cpp index fc950f49..3a8b6dca 100644 --- a/src/graphics/opengl/gl14device.cpp +++ b/src/graphics/opengl/gl14device.cpp @@ -257,7 +257,6 @@ bool CGL14Device::Create() if (glVersion >= 15) { GetLogger()->Info("Core VBO supported\n", glMajor, glMinor); - m_vertexBufferType = VBT_VBO_CORE; // Set function pointers m_glGenBuffers = glGenBuffers; @@ -269,7 +268,6 @@ bool CGL14Device::Create() else if (vboARB) // VBO ARB extension available { GetLogger()->Info("ARB VBO supported\n"); - m_vertexBufferType = VBT_VBO_ARB; // Set function pointers m_glGenBuffers = glGenBuffersARB; @@ -280,8 +278,11 @@ bool CGL14Device::Create() } else // no VBO support { - GetLogger()->Info("VBO not supported\n"); - m_vertexBufferType = VBT_DISPLAY_LIST; + m_errorMessage = "Your graphics card or drivers don't support OpenGL 1.5 or vertex buffer objects.\n" + "Ensure you have the latest graphics drivers for your graphics card.\n\n"; + GetLogger()->Error(m_errorMessage.c_str()); + m_errorMessage += GetHardwareInfo(); + return false; } // This is mostly done in all modern hardware by default @@ -1299,255 +1300,93 @@ void CGL14Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode else assert(false); } +namespace +{ +void SetVertexAttributes(const Vertex* bufferBase, const std::vector& textureRemapping) +{ + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, coord)); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, normal)); + + glClientActiveTexture(GL_TEXTURE0 + textureRemapping[1]); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0 + textureRemapping[0]); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, texCoord)); + + glDisableClientState(GL_COLOR_ARRAY); +} + +void SetVertexAttributes(const VertexTex2* bufferBase, const std::vector& textureRemapping) +{ + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, coord)); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, normal)); + + glClientActiveTexture(GL_TEXTURE0 + textureRemapping[1]); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, texCoord2)); + glClientActiveTexture(GL_TEXTURE0 + textureRemapping[0]); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, texCoord)); + + glDisableClientState(GL_COLOR_ARRAY); +} + +void SetVertexAttributes(const VertexCol* bufferBase, const std::vector& textureRemapping) +{ + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(bufferBase) + offsetof(VertexCol, coord)); + + glDisableClientState(GL_NORMAL_ARRAY); + + glClientActiveTexture(GL_TEXTURE0 + textureRemapping[1]); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0 + textureRemapping[0]); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(bufferBase) + offsetof(VertexCol, color)); +} +} // namespace + void CGL14Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, Color color) { - Vertex* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].normal)); - - glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].texCoord)); - + m_glBindBuffer(GL_ARRAY_BUFFER, 0); + SetVertexAttributes(vertices, m_remap); glColor4fv(color.Array()); glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE0 } void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, Color color) { - VertexTex2* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].normal)); - - glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].texCoord)); - - glClientActiveTexture(GL_TEXTURE0 + m_remap[1]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].texCoord2)); - + m_glBindBuffer(GL_ARRAY_BUFFER, 0); + SetVertexAttributes(vertices, m_remap); glColor4fv(color.Array()); glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1 - - glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); - - glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) { - VertexCol* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(&vs[0].color)); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); + SetVertexAttributes(vertices, m_remap); glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); - - glDisableClientState(GL_VERTEX_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(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(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, int first[], int count[], int drawCount, Color color) { - Vertex* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].normal)); - - glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].texCoord)); - + m_glBindBuffer(GL_ARRAY_BUFFER, 0); + SetVertexAttributes(vertices, m_remap); glColor4fv(color.Array()); GLenum t = TranslateGfxPrimitive(type); @@ -1561,31 +1400,13 @@ void CGL14Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, for (int i = 0; i < drawCount; i++) glDrawArrays(t, first[i], count[i]); } - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE0 } void CGL14Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, int first[], int count[], int drawCount, Color color) { - VertexTex2* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].normal)); - - glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].texCoord)); - - glClientActiveTexture(GL_TEXTURE0 + m_remap[1]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].texCoord2)); - + m_glBindBuffer(GL_ARRAY_BUFFER, 0); + SetVertexAttributes(vertices, m_remap); glColor4fv(color.Array()); GLenum t = TranslateGfxPrimitive(type); @@ -1599,25 +1420,13 @@ void CGL14Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, for (int i = 0; i < drawCount; i++) glDrawArrays(t, first[i], count[i]); } - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1 - - glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void CGL14Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, int first[], int count[], int drawCount) { - VertexCol* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(&vs[0].color)); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); + SetVertexAttributes(vertices, m_remap); GLenum t = TranslateGfxPrimitive(type); @@ -1630,289 +1439,81 @@ void CGL14Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, for (int i = 0; i < drawCount; i++) glDrawArrays(t, first[i], count[i]); } - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); } -unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) +template +unsigned int CGL14Device::CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) { - unsigned int id = 0; - if (m_vertexBufferType != VBT_DISPLAY_LIST) - { - id = ++m_lastVboId; + unsigned int id = ++m_lastVboId; - VboObjectInfo info; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_NORMAL; - info.vertexCount = vertexCount; - info.bufferId = 0; + VboObjectInfo info; + info.primitiveType = primitiveType; + info.vertexType = Vertex::VERTEX_TYPE; + info.vertexCount = vertexCount; + info.bufferId = 0; - m_glGenBuffers(1, &info.bufferId); - m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); - m_glBindBuffer(GL_ARRAY_BUFFER, 0); + m_glGenBuffers(1, &info.bufferId); + m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); - m_vboObjects[id] = info; - } - else - { - id = glGenLists(1); - - glNewList(id, GL_COMPILE); - - DrawPrimitive(primitiveType, vertices, vertexCount); - - glEndList(); - } + m_vboObjects[id] = info; return id; } -unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) +template +void CGL14Device::UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) { - unsigned int id = 0; - if (m_vertexBufferType != VBT_DISPLAY_LIST) - { - id = ++m_lastVboId; + auto it = m_vboObjects.find(bufferId); + if (it == m_vboObjects.end()) + return; - VboObjectInfo info; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_TEX2; - info.vertexCount = vertexCount; - info.bufferId = 0; + VboObjectInfo& info = (*it).second; + info.primitiveType = primitiveType; + info.vertexType = Vertex::VERTEX_TYPE; + info.vertexCount = vertexCount; - m_glGenBuffers(1, &info.bufferId); - m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW); - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - - m_vboObjects[id] = info; - } - else - { - id = glGenLists(1); - - glNewList(id, GL_COMPILE); - - DrawPrimitive(primitiveType, vertices, vertexCount); - - glEndList(); - } - - return id; -} - -unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) -{ - unsigned int id = 0; - if (m_vertexBufferType != VBT_DISPLAY_LIST) - { - id = ++m_lastVboId; - - VboObjectInfo info; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_COL; - info.vertexCount = vertexCount; - info.bufferId = 0; - - m_glGenBuffers(1, &info.bufferId); - m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW); - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - - m_vboObjects[id] = info; - } - else - { - id = glGenLists(1); - - glNewList(id, GL_COMPILE); - - DrawPrimitive(primitiveType, vertices, vertexCount); - - glEndList(); - } - - return id; -} - -void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) -{ - if (m_vertexBufferType != VBT_DISPLAY_LIST) - { - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - VboObjectInfo& info = (*it).second; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_NORMAL; - info.vertexCount = vertexCount; - - m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - } - else - { - glNewList(bufferId, GL_COMPILE); - - DrawPrimitive(primitiveType, vertices, vertexCount); - - glEndList(); - } -} - -void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) -{ - if (m_vertexBufferType != VBT_DISPLAY_LIST) - { - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - VboObjectInfo& info = (*it).second; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_TEX2; - info.vertexCount = vertexCount; - - m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW); - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - } - else - { - glNewList(bufferId, GL_COMPILE); - - DrawPrimitive(primitiveType, vertices, vertexCount); - - glEndList(); - } -} - -void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) -{ - if (m_vertexBufferType != VBT_DISPLAY_LIST) - { - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - VboObjectInfo& info = (*it).second; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_COL; - info.vertexCount = vertexCount; - - m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW); - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - } - else - { - glNewList(bufferId, GL_COMPILE); - - DrawPrimitive(primitiveType, vertices, vertexCount); - - glEndList(); - } + m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); } void CGL14Device::DrawStaticBuffer(unsigned int bufferId) { - if (m_vertexBufferType != VBT_DISPLAY_LIST) + auto it = m_vboObjects.find(bufferId); + if (it == m_vboObjects.end()) + return; + + m_glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId); + + if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) { - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - m_glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId); - - if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) - { - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(Vertex), static_cast(nullptr) + offsetof(Vertex, coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(Vertex), static_cast(nullptr) + offsetof(Vertex, normal)); - - glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), static_cast(nullptr) + offsetof(Vertex, texCoord)); - } - else if ((*it).second.vertexType == VERTEX_TYPE_TEX2) - { - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), static_cast(nullptr) + offsetof(VertexTex2, coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexTex2), static_cast(nullptr) + offsetof(VertexTex2, normal)); - - glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast(nullptr) + offsetof(VertexTex2, texCoord)); - - glClientActiveTexture(GL_TEXTURE0 + m_remap[1]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast(nullptr) + offsetof(VertexTex2, texCoord2)); - } - else if ((*it).second.vertexType == VERTEX_TYPE_COL) - { - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), static_cast(nullptr) + offsetof(VertexCol, coord)); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_FLOAT, sizeof(VertexCol), static_cast(nullptr) + offsetof(VertexCol, color)); - } - - GLenum mode = TranslateGfxPrimitive((*it).second.primitiveType); - glDrawArrays(mode, 0, (*it).second.vertexCount); - - if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) - { - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE0 - } - else if ((*it).second.vertexType == VERTEX_TYPE_TEX2) - { - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1 - - glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - else if ((*it).second.vertexType == VERTEX_TYPE_COL) - { - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - } - - m_glBindBuffer(GL_ARRAY_BUFFER, 0); + SetVertexAttributes(static_cast(nullptr), m_remap); } - else + else if ((*it).second.vertexType == VERTEX_TYPE_TEX2) { - glCallList(bufferId); + SetVertexAttributes(static_cast(nullptr), m_remap); } + else if ((*it).second.vertexType == VERTEX_TYPE_COL) + { + SetVertexAttributes(static_cast(nullptr), m_remap); + } + + GLenum mode = TranslateGfxPrimitive((*it).second.primitiveType); + + glDrawArrays(mode, 0, (*it).second.vertexCount); } void CGL14Device::DestroyStaticBuffer(unsigned int bufferId) { - if (m_vertexBufferType != VBT_DISPLAY_LIST) - { - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; + auto it = m_vboObjects.find(bufferId); + if (it == m_vboObjects.end()) + return; - m_glDeleteBuffers(1, &(*it).second.bufferId); + m_glDeleteBuffers(1, &(*it).second.bufferId); - m_vboObjects.erase(it); - } - else - { - glDeleteLists(bufferId, 1); - } + m_vboObjects.erase(it); } /* Based on libwine's implementation */ diff --git a/src/graphics/opengl/gl14device.h b/src/graphics/opengl/gl14device.h index 7bc533af..39785efd 100644 --- a/src/graphics/opengl/gl14device.h +++ b/src/graphics/opengl/gl14device.h @@ -43,17 +43,6 @@ namespace Gfx { -/** - \enum VertexBufferType - \brief Specifies type of vertex buffer to use - */ -enum VertexBufferType -{ - VBT_DISPLAY_LIST, //! use display lists - VBT_VBO_CORE, //! use core OpenGL 1.5 VBOs - VBT_VBO_ARB //! use ARB extension VBOs -}; - enum ShadowMappingSupport { SMS_NONE, //! No support for depth textures @@ -119,11 +108,6 @@ public: 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, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, @@ -139,12 +123,31 @@ public: virtual void DrawPrimitives(PrimitiveType type, const VertexCol *vertices, int first[], int count[], int drawCount) override; - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override; - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override; - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override; - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override; - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override; - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override; + unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override + { + return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); + } + unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override + { + return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); + } + unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override + { + return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); + } + void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override + { + UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); + } + void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override + { + UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); + } + void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override + { + UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); + } + void DrawStaticBuffer(unsigned int bufferId) override; void DestroyStaticBuffer(unsigned int bufferId) override; @@ -214,6 +217,11 @@ private: //! Disables shadows void DisableShadows(); + template + unsigned int CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); + template + void UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); + private: //! Current config DeviceConfig m_config; @@ -260,14 +268,6 @@ private: //! Map of framebuffers std::map> m_framebuffers; - //! Type of vertex structure - enum VertexType - { - VERTEX_TYPE_NORMAL, - VERTEX_TYPE_TEX2, - VERTEX_TYPE_COL, - }; - //! Info about static VBO buffers struct VboObjectInfo { @@ -284,8 +284,6 @@ private: bool m_multiDrawArrays = false; //! Framebuffer support FramebufferSupport m_framebufferSupport = FBS_NONE; - //! Which vertex buffer type to use - VertexBufferType m_vertexBufferType = VBT_DISPLAY_LIST; //! Map of saved VBO objects std::map m_vboObjects; //! Last ID of VBO object diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp index f0bbdbb5..41660578 100644 --- a/src/graphics/opengl/gl21device.cpp +++ b/src/graphics/opengl/gl21device.cpp @@ -1115,33 +1115,70 @@ void CGL21Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode else assert(false); } +namespace +{ +void SetVertexAttributes(const Vertex* bufferBase) +{ + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, coord)); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, normal)); + + glClientActiveTexture(GL_TEXTURE1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, texCoord)); + + glDisableClientState(GL_COLOR_ARRAY); +} + +void SetVertexAttributes(const VertexTex2* bufferBase) +{ + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, coord)); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, normal)); + + glClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, texCoord2)); + glClientActiveTexture(GL_TEXTURE0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, texCoord)); + + glDisableClientState(GL_COLOR_ARRAY); +} + +void SetVertexAttributes(const VertexCol* bufferBase) +{ + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(bufferBase) + offsetof(VertexCol, coord)); + + glDisableClientState(GL_NORMAL_ARRAY); + + glClientActiveTexture(GL_TEXTURE1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(bufferBase) + offsetof(VertexCol, color)); +} +} // namespace + void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, Color color) { if (m_updateLights) UpdateLights(); BindVBO(0); - - Vertex* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].normal)); - - glClientActiveTexture(GL_TEXTURE0); - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].texCoord)); - + SetVertexAttributes(vertices); glColor4fv(color.Array()); glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE0 } void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, @@ -1150,33 +1187,10 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, if (m_updateLights) UpdateLights(); BindVBO(0); - - VertexTex2* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].normal)); - - glClientActiveTexture(GL_TEXTURE0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].texCoord)); - - glClientActiveTexture(GL_TEXTURE1); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].texCoord2)); - + SetVertexAttributes(vertices); glColor4fv(color.Array()); glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1 - - glClientActiveTexture(GL_TEXTURE0); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) @@ -1184,179 +1198,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i if (m_updateLights) UpdateLights(); BindVBO(0); - - VertexCol* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(&vs[0].color)); - + SetVertexAttributes(vertices); glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); - - glDisableClientState(GL_VERTEX_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(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(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, @@ -1365,26 +1208,10 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, if (m_updateLights) UpdateLights(); BindVBO(0); - - Vertex* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].normal)); - - glClientActiveTexture(GL_TEXTURE0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast(&vs[0].texCoord)); - + SetVertexAttributes(vertices); glColor4fv(color.Array()); glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE0 } void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, @@ -1393,33 +1220,10 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, if (m_updateLights) UpdateLights(); BindVBO(0); - - VertexTex2* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].normal)); - - glClientActiveTexture(GL_TEXTURE0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].texCoord)); - - glClientActiveTexture(GL_TEXTURE1); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(&vs[0].texCoord2)); - + SetVertexAttributes(vertices); glColor4fv(color.Array()); glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1 - - glClientActiveTexture(GL_TEXTURE0); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, @@ -1428,28 +1232,20 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, if (m_updateLights) UpdateLights(); BindVBO(0); - - VertexCol* vs = const_cast(vertices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(&vs[0].coord)); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(&vs[0].color)); + SetVertexAttributes(vertices); glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); } -unsigned int CGL21Device::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) + +template +unsigned int CGL21Device::CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) { unsigned int id = ++m_lastVboId; VboObjectInfo info; info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_NORMAL; + info.vertexType = Vertex::VERTEX_TYPE; info.vertexCount = vertexCount; info.bufferId = 0; info.size = vertexCount * sizeof(Vertex); @@ -1463,47 +1259,8 @@ unsigned int CGL21Device::CreateStaticBuffer(PrimitiveType primitiveType, const return id; } -unsigned int CGL21Device::CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) -{ - unsigned int id = ++m_lastVboId; - - VboObjectInfo info; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_TEX2; - info.vertexCount = vertexCount; - info.bufferId = 0; - info.size = vertexCount * sizeof(VertexTex2); - - glGenBuffers(1, &info.bufferId); - BindVBO(info.bufferId); - glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW); - - m_vboObjects[id] = info; - - return id; -} - -unsigned int CGL21Device::CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) -{ - unsigned int id = ++m_lastVboId; - - VboObjectInfo info; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_COL; - info.vertexCount = vertexCount; - info.bufferId = 0; - info.size = vertexCount * sizeof(VertexCol); - - glGenBuffers(1, &info.bufferId); - BindVBO(info.bufferId); - glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW); - - m_vboObjects[id] = info; - - return id; -} - -void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) +template +void CGL21Device::UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) { auto it = m_vboObjects.find(bufferId); if (it == m_vboObjects.end()) @@ -1513,7 +1270,7 @@ void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit VboObjectInfo& info = (*it).second; info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_NORMAL; + info.vertexType = Vertex::VERTEX_TYPE; info.vertexCount = vertexCount; BindVBO(info.bufferId); @@ -1529,58 +1286,6 @@ void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit } } -void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) -{ - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - VboObjectInfo& info = (*it).second; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_TEX2; - info.vertexCount = vertexCount; - - int newSize = vertexCount * sizeof(VertexTex2); - - BindVBO(info.bufferId); - - if (info.size < newSize) - { - glBufferData(GL_ARRAY_BUFFER, newSize, vertices, GL_STATIC_DRAW); - info.size = newSize; - } - else - { - glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, vertices); - } -} - -void CGL21Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) -{ - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - VboObjectInfo& info = (*it).second; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_COL; - info.vertexCount = vertexCount; - - int newSize = vertexCount * sizeof(VertexCol); - - BindVBO(info.bufferId); - - if (info.size < newSize) - { - glBufferData(GL_ARRAY_BUFFER, newSize, vertices, GL_STATIC_DRAW); - info.size = newSize; - } - else - { - glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, vertices); - } -} - void CGL21Device::DrawStaticBuffer(unsigned int bufferId) { auto it = m_vboObjects.find(bufferId); @@ -1593,64 +1298,20 @@ void CGL21Device::DrawStaticBuffer(unsigned int bufferId) if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) { - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(Vertex), static_cast(nullptr) + offsetof(Vertex, coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(Vertex), static_cast(nullptr) + offsetof(Vertex, normal)); - - glClientActiveTexture(GL_TEXTURE0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), static_cast(nullptr) + offsetof(Vertex, texCoord)); + SetVertexAttributes(static_cast(nullptr)); } else if ((*it).second.vertexType == VERTEX_TYPE_TEX2) { - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), static_cast(nullptr) + offsetof(VertexTex2, coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexTex2), static_cast(nullptr) + offsetof(VertexTex2, normal)); - - glClientActiveTexture(GL_TEXTURE0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast(nullptr) + offsetof(VertexTex2, texCoord)); - - glClientActiveTexture(GL_TEXTURE1); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast(nullptr) + offsetof(VertexTex2, texCoord2)); + SetVertexAttributes(static_cast(nullptr)); } else if ((*it).second.vertexType == VERTEX_TYPE_COL) { - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), static_cast(nullptr) + offsetof(VertexCol, coord)); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_FLOAT, sizeof(VertexCol), static_cast(nullptr) + offsetof(VertexCol, color)); + SetVertexAttributes(static_cast(nullptr)); } GLenum mode = TranslateGfxPrimitive((*it).second.primitiveType); + glDrawArrays(mode, 0, (*it).second.vertexCount); - - if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) - { - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE0 - } - else if ((*it).second.vertexType == VERTEX_TYPE_TEX2) - { - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1 - - glClientActiveTexture(GL_TEXTURE0); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - else if ((*it).second.vertexType == VERTEX_TYPE_COL) - { - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - } } void CGL21Device::DestroyStaticBuffer(unsigned int bufferId) diff --git a/src/graphics/opengl/gl21device.h b/src/graphics/opengl/gl21device.h index 6e1bf261..873afdf7 100644 --- a/src/graphics/opengl/gl21device.h +++ b/src/graphics/opengl/gl21device.h @@ -100,11 +100,6 @@ public: 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, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, @@ -120,12 +115,30 @@ public: virtual void DrawPrimitives(PrimitiveType type, const VertexCol *vertices, int first[], int count[], int drawCount) override; - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override; - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override; - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override; - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override; - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override; - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override; + unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override + { + return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); + } + unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override + { + return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); + } + unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override + { + return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); + } + void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override + { + UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); + } + void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override + { + UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); + } + void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override + { + UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); + } void DrawStaticBuffer(unsigned int bufferId) override; void DestroyStaticBuffer(unsigned int bufferId) override; @@ -192,6 +205,11 @@ private: //! Binds texture inline void BindTexture(int index, GLuint texture); + template + unsigned int CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); + template + void UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); + private: //! Current config DeviceConfig m_config; @@ -232,14 +250,6 @@ private: //! Map of framebuffers std::map> m_framebuffers; - //! Type of vertex structure - enum VertexType - { - VERTEX_TYPE_NORMAL, - VERTEX_TYPE_TEX2, - VERTEX_TYPE_COL, - }; - //! Info about static VBO buffers struct VboObjectInfo { diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp index 776f1547..0180f247 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl/gl33device.cpp @@ -1158,50 +1158,6 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); } -void CGL33Device::DrawPrimitive(PrimitiveType type, const void *vertices, - int size, const VertexFormat &format, int vertexCount) -{ - 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); - - 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, int first[], int count[], int drawCount, Color color) { @@ -1358,27 +1314,12 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); } -unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) +namespace { - unsigned int id = 0; - - id = ++m_lastVboId; - - VertexBufferInfo info; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_NORMAL; - info.vertexCount = vertexCount; - info.size = vertexCount * sizeof(Vertex); - - glGenVertexArrays(1, &info.vao); - BindVAO(info.vao); - - glGenBuffers(1, &info.vbo); - BindVBO(info.vbo); - - glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW); - m_vboMemory += info.size; +template void SetVertexAttributes(); +template <> void SetVertexAttributes() +{ // Vertex coordinate glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, coord))); @@ -1398,33 +1339,10 @@ unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const // Texture coordinate 1 glDisableVertexAttribArray(4); glVertexAttrib2f(4, 0.0f, 0.0f); - - m_vboObjects[id] = info; - - return id; } -unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) +template <> void SetVertexAttributes() { - unsigned int id = 0; - - id = ++m_lastVboId; - - VertexBufferInfo info; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_TEX2; - info.vertexCount = vertexCount; - info.size = vertexCount * sizeof(VertexTex2); - - glGenVertexArrays(1, &info.vao); - BindVAO(info.vao); - - glGenBuffers(1, &info.vbo); - BindVBO(info.vbo); - - glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW); - m_vboMemory += info.size; - // Vertex coordinate glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), reinterpret_cast(offsetof(VertexTex2, coord))); @@ -1444,31 +1362,10 @@ unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const // Texture coordinate 1 glEnableVertexAttribArray(4); glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), reinterpret_cast(offsetof(VertexTex2, texCoord2))); - - m_vboObjects[id] = info; - - return id; } -unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) +template <> void SetVertexAttributes() { - unsigned int id = ++m_lastVboId; - - VertexBufferInfo info; - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_COL; - info.vertexCount = vertexCount; - info.size = vertexCount * sizeof(VertexCol); - - glGenVertexArrays(1, &info.vao); - BindVAO(info.vao); - - glGenBuffers(1, &info.vbo); - BindVBO(info.vbo); - - glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW); - m_vboMemory += info.size; - // Vertex coordinate glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol), reinterpret_cast(offsetof(VertexCol, coord))); @@ -1488,13 +1385,40 @@ unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const // Texture coordinate 1 glDisableVertexAttribArray(4); glVertexAttrib2f(4, 0.0f, 0.0f); +} +} // namespace + +template +unsigned int CGL33Device::CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) +{ + unsigned int id = 0; + + id = ++m_lastVboId; + + VertexBufferInfo info; + info.primitiveType = primitiveType; + info.vertexType = Vertex::VERTEX_TYPE; + info.vertexCount = vertexCount; + info.size = vertexCount * sizeof(Vertex); + + glGenVertexArrays(1, &info.vao); + BindVAO(info.vao); + + glGenBuffers(1, &info.vbo); + BindVBO(info.vbo); + + glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW); + m_vboMemory += info.size; + + SetVertexAttributes(); m_vboObjects[id] = info; return id; } -void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) +template +void CGL33Device::UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) { auto it = m_vboObjects.find(bufferId); if (it == m_vboObjects.end()) @@ -1504,12 +1428,12 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit unsigned int size = vertexCount * sizeof(Vertex); - bool changed = (info.vertexType != VERTEX_TYPE_NORMAL) || (size > info.size); + bool changed = (info.vertexType != Vertex::VERTEX_TYPE) || (size > info.size); - if (info.vertexType != VERTEX_TYPE_NORMAL) CLogger::GetInstance().Debug("Changing static buffer type\n"); + if (info.vertexType != Vertex::VERTEX_TYPE) CLogger::GetInstance().Debug("Changing static buffer type\n"); info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_NORMAL; + info.vertexType = Vertex::VERTEX_TYPE; info.vertexCount = vertexCount; BindVBO(info.vbo); @@ -1531,143 +1455,7 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit { BindVAO(info.vao); - // Vertex coordinate - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, coord))); - - // Normal - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, normal))); - - // Color - glDisableVertexAttribArray(2); - glVertexAttrib4f(2, 1.0f, 1.0f, 1.0f, 1.0f); - - // Texture coordinate 0 - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, texCoord))); - - // Texture coordinate 1 - glDisableVertexAttribArray(4); - glVertexAttrib2f(4, 0.0f, 0.0f); - } -} - -void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) -{ - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - VertexBufferInfo& info = (*it).second; - - unsigned int size = vertexCount * sizeof(VertexTex2); - - bool changed = (info.vertexType != VERTEX_TYPE_TEX2) || (size > info.size); - - if (info.vertexType != VERTEX_TYPE_TEX2) CLogger::GetInstance().Debug("Changing static buffer type\n"); - - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_TEX2; - info.vertexCount = vertexCount; - - BindVBO(info.vbo); - - if (info.size < size) - { - CLogger::GetInstance().Debug("Resizing static buffer: %d->%d\n", info.size, size); - glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW); - m_vboMemory -= info.size; - info.size = size; - m_vboMemory += info.size; - } - else - { - glBufferSubData(GL_ARRAY_BUFFER, 0, size, vertices); - } - - if (changed) // Update vertex array bindings - { - BindVAO(info.vao); - - // Vertex coordinate - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), reinterpret_cast(offsetof(VertexTex2, coord))); - - // Normal - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), reinterpret_cast(offsetof(VertexTex2, normal))); - - // Color - glDisableVertexAttribArray(2); - glVertexAttrib4f(2, 1.0f, 1.0f, 1.0f, 1.0f); - - // Texture coordinate 0 - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), reinterpret_cast(offsetof(VertexTex2, texCoord))); - - // Texture coordinate 1 - glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), reinterpret_cast(offsetof(VertexTex2, texCoord2))); - } -} - -void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) -{ - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - VertexBufferInfo& info = (*it).second; - - unsigned int size = vertexCount * sizeof(VertexCol); - - bool changed = (info.vertexType != VERTEX_TYPE_COL) || (size > info.size); - - if (info.vertexType != VERTEX_TYPE_NORMAL) CLogger::GetInstance().Debug("Changing static buffer type\n"); - - info.primitiveType = primitiveType; - info.vertexType = VERTEX_TYPE_COL; - info.vertexCount = vertexCount; - - BindVBO(info.vbo); - - if (info.size < size) - { - CLogger::GetInstance().Debug("Resizing static buffer: %d->%d\n", info.size, size); - glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW); - m_vboMemory -= info.size; - info.size = size; - m_vboMemory += info.size; - } - else - { - glBufferSubData(GL_ARRAY_BUFFER, 0, size, vertices); - } - - if (changed) // Update vertex array bindings - { - BindVAO(info.vao); - - // Vertex coordinate - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol), reinterpret_cast(offsetof(VertexCol, coord))); - - // Normal - glDisableVertexAttribArray(1); - glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f); - - // Color - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol), reinterpret_cast(offsetof(VertexCol, color))); - - // Texture coordinate 0 - glDisableVertexAttribArray(3); - glVertexAttrib2f(3, 0.0f, 0.0f); - - // Texture coordinate 1 - glDisableVertexAttribArray(4); - glVertexAttrib2f(4, 0.0f, 0.0f); + SetVertexAttributes(); } } @@ -2092,25 +1880,6 @@ unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, const void* da 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(offset + attribute.offset)); - } - else - { - glDisableVertexAttribArray(index); - glVertexAttrib4fv(index, attribute.values); - } -} - bool CGL33Device::IsAnisotropySupported() { return m_capabilities.anisotropySupported; diff --git a/src/graphics/opengl/gl33device.h b/src/graphics/opengl/gl33device.h index b0b452e0..7b3aa26a 100644 --- a/src/graphics/opengl/gl33device.h +++ b/src/graphics/opengl/gl33device.h @@ -115,11 +115,6 @@ public: 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, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, @@ -135,12 +130,30 @@ public: virtual void DrawPrimitives(PrimitiveType type, const VertexCol *vertices, int first[], int count[], int drawCount) override; - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override; - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override; - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override; - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override; - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override; - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override; + unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override + { + return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); + } + unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override + { + return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); + } + unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override + { + return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); + } + void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override + { + UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); + } + void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override + { + UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); + } + void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override + { + UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); + } void DrawStaticBuffer(unsigned int bufferId) override; void DestroyStaticBuffer(unsigned int bufferId) override; @@ -213,7 +226,10 @@ private: //! Uploads data to dynamic buffer and returns offset to it unsigned int UploadVertexData(DynamicBuffer& buffer, const void* data, unsigned int size); - inline void UpdateVertexAttribute(int index, const VertexAttribute &attribute, int offset); + template + unsigned int CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); + template + void UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); private: //! Current config @@ -256,14 +272,6 @@ private: //! Free texture unit const int m_freeTexture = 3; - //! Type of vertex structure - enum VertexType - { - VERTEX_TYPE_NORMAL, - VERTEX_TYPE_TEX2, - VERTEX_TYPE_COL, - }; - //! Info about static VBO buffers struct VertexBufferInfo { diff --git a/src/graphics/opengl/glframebuffer.cpp b/src/graphics/opengl/glframebuffer.cpp index c58d90d7..75fe020a 100644 --- a/src/graphics/opengl/glframebuffer.cpp +++ b/src/graphics/opengl/glframebuffer.cpp @@ -55,7 +55,7 @@ bool CGLFramebuffer::Create() glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); // create color texture - if (m_params.colorTexture) + if (m_params.colorAttachment == FramebufferParams::AttachmentType::Texture) { GLint previous; glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous); @@ -76,7 +76,7 @@ bool CGLFramebuffer::Create() glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorTexture, 0); } // create color renderbuffer - else + else if (m_params.colorAttachment == FramebufferParams::AttachmentType::Renderbuffer) { glGenRenderbuffers(1, &m_colorRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer); @@ -92,6 +92,10 @@ bool CGLFramebuffer::Create() glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorRenderbuffer); } + else + { + glDrawBuffer(GL_NONE); + } GLuint depthFormat = 0; @@ -104,7 +108,7 @@ bool CGLFramebuffer::Create() } // create depth texture - if (m_params.depthTexture) + if (m_params.depthAttachment == FramebufferParams::AttachmentType::Texture) { GLint previous; glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous); @@ -132,7 +136,7 @@ bool CGLFramebuffer::Create() GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexture, 0); } // create depth renderbuffer - else + else if (m_params.depthAttachment == FramebufferParams::AttachmentType::Renderbuffer) { glGenRenderbuffers(1, &m_depthRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderbuffer); @@ -323,7 +327,7 @@ bool CGLFramebufferEXT::Create() glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); // create color texture - if (m_params.colorTexture) + if (m_params.colorAttachment == FramebufferParams::AttachmentType::Texture) { GLint previous; glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous); @@ -346,7 +350,7 @@ bool CGLFramebufferEXT::Create() GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_colorTexture, 0); } // create color renderbuffer - else + else if (m_params.colorAttachment == FramebufferParams::AttachmentType::Renderbuffer) { glGenRenderbuffersEXT(1, &m_colorRenderbuffer); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_colorRenderbuffer); @@ -363,6 +367,10 @@ bool CGLFramebufferEXT::Create() glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_colorRenderbuffer); } + else + { + glDrawBuffer(GL_NONE); + } GLuint depthFormat = 0; @@ -375,7 +383,7 @@ bool CGLFramebufferEXT::Create() } // create depth texture - if (m_params.depthTexture) + if (m_params.depthAttachment == FramebufferParams::AttachmentType::Texture) { GLint previous; glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous); @@ -403,7 +411,7 @@ bool CGLFramebufferEXT::Create() GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_depthTexture, 0); } // create depth renderbuffer - else + else if (m_params.depthAttachment == FramebufferParams::AttachmentType::Renderbuffer) { glGenRenderbuffersEXT(1, &m_depthRenderbuffer); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthRenderbuffer); diff --git a/src/level/parser/parserparam.cpp b/src/level/parser/parserparam.cpp index 751654c2..c4ee9b31 100644 --- a/src/level/parser/parserparam.cpp +++ b/src/level/parser/parserparam.cpp @@ -955,21 +955,21 @@ int CLevelParserParam::AsResearchFlag(int def) return AsResearchFlag(); } -SortType CLevelParserParam::ToSortType(std::string value) +CScoreboard::SortType CLevelParserParam::ToSortType(std::string value) { - if (value == "Points" ) return SortType::SORT_POINTS; - if (value == "Name" ) return SortType::SORT_ID; - return SortType::SORT_ID; + if (value == "Points") return CScoreboard::SortType::SORT_POINTS; + if (value == "Name" ) return CScoreboard::SortType::SORT_ID; + return CScoreboard::SortType::SORT_ID; } -SortType CLevelParserParam::AsSortType() +CScoreboard::SortType CLevelParserParam::AsSortType() { if (m_empty) throw CLevelParserExceptionMissingParam(this); return ToSortType(m_value); } -SortType CLevelParserParam::AsSortType(SortType def) +CScoreboard::SortType CLevelParserParam::AsSortType(CScoreboard::SortType def) { if (m_empty) return def; diff --git a/src/level/parser/parserparam.h b/src/level/parser/parserparam.h index d011c669..62838dc7 100644 --- a/src/level/parser/parserparam.h +++ b/src/level/parser/parserparam.h @@ -87,7 +87,7 @@ public: Gfx::EngineObjectType AsTerrainType(); int AsBuildFlag(); int AsResearchFlag(); - SortType AsSortType(); + CScoreboard::SortType AsSortType(); Gfx::PyroType AsPyroType(); Gfx::CameraType AsCameraType(); MissionType AsMissionType(); @@ -111,7 +111,7 @@ public: Gfx::EngineObjectType AsTerrainType(Gfx::EngineObjectType def); int AsBuildFlag(int def); int AsResearchFlag(int def); - SortType AsSortType(SortType def); + CScoreboard::SortType AsSortType(CScoreboard::SortType def); Gfx::PyroType AsPyroType(Gfx::PyroType def); Gfx::CameraType AsCameraType(Gfx::CameraType def); MissionType AsMissionType(MissionType def); @@ -143,7 +143,7 @@ private: Gfx::EngineObjectType ToTerrainType(std::string value); int ToBuildFlag(std::string value); int ToResearchFlag(std::string value); - SortType ToSortType(std::string value); + CScoreboard::SortType ToSortType(std::string value); Gfx::PyroType ToPyroType(std::string value); Gfx::CameraType ToCameraType(std::string value); MissionType ToMissionType(std::string value); diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index ceb8daa9..dea86bcb 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -60,6 +60,7 @@ #include "level/parser/parser.h" #include "math/const.h" +#include "math/func.h" #include "math/geometry.h" #include "object/object.h" @@ -119,6 +120,10 @@ const float UNIT = 4.0f; // default for g_unit float g_unit; // conversion factor +// Min/max values for the game speed. +const float MIN_SPEED = 1/8.0f; +const float MAX_SPEED = 256.0f; + // Reference colors used when recoloring textures, see ChangeColor() const Gfx::Color COLOR_REF_BOT = Gfx::Color( 10.0f/256.0f, 166.0f/256.0f, 254.0f/256.0f); // blue const Gfx::Color COLOR_REF_ALIEN = Gfx::Color(135.0f/256.0f, 170.0f/256.0f, 13.0f/256.0f); // green @@ -589,7 +594,7 @@ void CRobotMain::ChangePhase(Phase phase) ddim.x = dim.x*15; ddim.y = dim.y*3.0f; pe = m_interface->CreateEdit(pos, ddim, 0, EVENT_EDIT0); pe->SetGenericMode(true); - pe->SetFontType(Gfx::FONT_COLOBOT); + pe->SetFontType(Gfx::FONT_COMMON); pe->SetEditCap(false); pe->SetHighlightCap(false); pe->ReadText(std::string("help/") + m_app->GetLanguageChar() + std::string("/win.txt")); @@ -779,7 +784,7 @@ bool CRobotMain::ProcessEvent(Event &event) if (IsPhaseWithWorld(m_phase)) { - if (data->key == KEY(F11)) + if (data->key == KEY(F10)) { m_debugMenu->ToggleInterface(); return false; @@ -2127,7 +2132,7 @@ void CRobotMain::CreateTooltip(Math::Point pos, const std::string& text) Math::Point start, end; - m_engine->GetText()->SizeText(text, Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL, + m_engine->GetText()->SizeText(text, Gfx::FONT_COMMON, Gfx::FONT_SIZE_SMALL, corner, Gfx::TEXT_ALIGN_LEFT, start, end); @@ -2162,7 +2167,7 @@ void CRobotMain::CreateTooltip(Math::Point pos, const std::string& text) pw->SetState(Ui::STATE_SHADOW); pw->SetTrashEvent(false); - pos.y -= m_engine->GetText()->GetHeight(Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL) / 2.0f; + pos.y -= m_engine->GetText()->GetHeight(Gfx::FONT_COMMON, Gfx::FONT_SIZE_SMALL) / 2.0f; pw->CreateLabel(pos, dim, -1, EVENT_LABEL2, text); } } @@ -2527,6 +2532,8 @@ bool CRobotMain::EventFrame(const Event &event) { CheckEndMission(true); UpdateAudio(true); + if (m_scoreboard) + m_scoreboard->UpdateObjectCount(); } if (m_winDelay > 0.0f && !m_editLock) @@ -2701,6 +2708,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_endTake.clear(); m_endTakeImmediat = false; m_endTakeResearch = 0; + m_endTakeTimeout = -1.0f; + m_endTakeTeamImmediateWin = false; m_endTakeWinDelay = 2.0f; m_endTakeLostDelay = 2.0f; m_teamFinished.clear(); @@ -3551,8 +3560,9 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) continue; } Viewpoint tmp; - tmp.eye = line->GetParam("eye")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit; - tmp.look = line->GetParam("lookat")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit; + tmp.eye = line->GetParam("eye")->AsPoint()*g_unit; + tmp.look = line->GetParam("lookat")->AsPoint()*g_unit; + tmp.button = line->GetParam("button")->AsInt(13); // 13 is the camera button m_viewpoints.push_back(tmp); continue; } @@ -3571,6 +3581,11 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) } continue; } + if (line->GetCommand() == "EndMissionTeams" && !resetObject) + { + m_endTakeTeamImmediateWin = line->GetParam("immediateWin")->AsBool(false); // false = finishing removes the team that finished, true = finishing for one team ends the whole game + continue; + } if (line->GetCommand() == "EndMissionDelay" && !resetObject) { m_endTakeWinDelay = line->GetParam("win")->AsFloat(2.0f); @@ -3582,6 +3597,11 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_endTakeResearch |= line->GetParam("type")->AsResearchFlag(); continue; } + if (line->GetCommand() == "EndMissionTimeout" && !resetObject) + { + m_endTakeTimeout = line->GetParam("time")->AsFloat(); + continue; + } if (line->GetCommand() == "Scoreboard" && !resetObject) { @@ -3589,16 +3609,11 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) { // Create the scoreboard m_scoreboard = MakeUnique(); + m_scoreboard->SetSortType(line->GetParam("sort")->AsSortType(CScoreboard::SortType::SORT_ID)); } continue; } - if (line->GetCommand() == "ScoreboardSortType" && !resetObject) - { - m_scoreboard->SetSortType(static_cast(line->GetParam("sort")->AsSortType() ) ); - continue; - } - if (line->GetCommand() == "ScoreboardKillRule" && !resetObject) { if (!m_scoreboard) @@ -3608,6 +3623,15 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_scoreboard->AddKillRule(std::move(rule)); continue; } + if (line->GetCommand() == "ScoreboardObjectRule" && !resetObject) + { + if (!m_scoreboard) + throw CLevelParserException("ScoreboardObjectRule encountered but scoreboard is not enabled"); + auto rule = MakeUnique(); + rule->Read(line.get()); + m_scoreboard->AddObjectRule(std::move(rule)); + continue; + } if (line->GetCommand() == "ScoreboardEndTakeRule" && !resetObject) { if (!m_scoreboard) @@ -4425,10 +4449,8 @@ void CRobotMain::SaveOneScript(CObject *obj) } //! Saves the stack of the program in execution of a robot -bool CRobotMain::SaveFileStack(CObject *obj, FILE *file, int objRank) +bool CRobotMain::SaveFileStack(CObject *obj, std::ostream &ostr) { - if (objRank == -1) return true; - if (! obj->Implements(ObjectInterfaceType::Programmable)) return true; CProgrammableObject* programmable = dynamic_cast(obj); @@ -4436,14 +4458,24 @@ bool CRobotMain::SaveFileStack(CObject *obj, FILE *file, int objRank) ObjectType type = obj->GetType(); if (type == OBJECT_HUMAN) return true; - return programmable->WriteStack(file); + long status = 1; + std::stringstream sstr(""); + + if (!programmable->WriteStack(sstr)) + { + GetLogger()->Error("WriteStack failed at object id = %i\n", obj->GetID()); + status = 100; // marked bad + } + + if (!CBot::WriteLong(ostr, status)) return false; + if (!CBot::WriteStream(ostr, sstr)) return false; + + return true; } //! Resumes the execution stack of the program in a robot -bool CRobotMain::ReadFileStack(CObject *obj, FILE *file, int objRank) +bool CRobotMain::ReadFileStack(CObject *obj, std::istream &istr) { - if (objRank == -1) return true; - if (! obj->Implements(ObjectInterfaceType::Programmable)) return true; CProgrammableObject* programmable = dynamic_cast(obj); @@ -4451,7 +4483,29 @@ bool CRobotMain::ReadFileStack(CObject *obj, FILE *file, int objRank) ObjectType type = obj->GetType(); if (type == OBJECT_HUMAN) return true; - return programmable->ReadStack(file); + long status; + if (!CBot::ReadLong(istr, status)) return false; + + if (status == 100) // was marked bad ? + { + if (!CBot::ReadLong(istr, status)) return false; + if (!istr.seekg(status, istr.cur)) return false; + return true; // next program + } + + if (status == 1) + { + std::stringstream sstr(""); + if (!CBot::ReadStream(istr, sstr)) return false; + + if (!programmable->ReadStack(sstr)) + { + GetLogger()->Error("ReadStack failed at object id = %i\n", obj->GetID()); + } + return true; // next program + } + + return false; // error: status == ?? } std::vector CRobotMain::GetNewScriptNames(ObjectType type) @@ -4646,25 +4700,36 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s } // Writes the file of stacks of execution. - FILE* file = CBot::fOpen((CResourceManager::GetSaveLocation() + "/" + filecbot).c_str(), "wb"); - if (file == nullptr) return false; + COutputStream ostr(filecbot); + if (!ostr.is_open()) return false; + bool bError = false; long version = 1; - CBot::fWrite(&version, sizeof(long), 1, file); // version of COLOBOT + CBot::WriteLong(ostr, version); // version of COLOBOT version = CBot::CBotProgram::GetVersion(); - CBot::fWrite(&version, sizeof(long), 1, file); // version of CBOT + CBot::WriteLong(ostr, version); // version of CBOT + CBot::WriteWord(ostr, 0); // TODO - objRank = 0; for (CObject* obj : m_objMan->GetAllObjects()) { if (obj->GetType() == OBJECT_TOTO) continue; if (IsObjectBeingTransported(obj)) continue; if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(obj)->IsDying()) continue; - if (!SaveFileStack(obj, file, objRank++)) break; + if (!SaveFileStack(obj, ostr)) + { + GetLogger()->Error("SaveFileStack failed at object id = %i\n", obj->GetID()); + bError = true; + break; + } } - CBot::CBotClass::SaveStaticState(file); - CBot::fClose(file); + + if (!bError && !CBot::CBotClass::SaveStaticState(ostr)) + { + GetLogger()->Error("CBotClass save static state failed\n"); + } + + ostr.close(); if (!emergencySave) { @@ -4822,29 +4887,48 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot) m_ui->GetLoadingScreen()->SetProgress(0.95f, RT_LOADING_CBOT_SAVE); // Reads the file of stacks of execution. - FILE* file = CBot::fOpen((CResourceManager::GetSaveLocation() + "/" + filecbot).c_str(), "rb"); - if (file != nullptr) + CInputStream istr(filecbot); + + if (istr.is_open()) { - long version; - CBot::fRead(&version, sizeof(long), 1, file); // version of COLOBOT + bool bError = false; + long version = 0; + CBot::ReadLong(istr, version); // version of COLOBOT if (version == 1) { - CBot::fRead(&version, sizeof(long), 1, file); // version of CBOT + CBot::ReadLong(istr, version); // version of CBOT if (version == CBot::CBotProgram::GetVersion()) { - objRank = 0; - for (CObject* obj : m_objMan->GetAllObjects()) + unsigned short flag; + CBot::ReadWord(istr, flag); // TODO + bError = (flag != 0); + + if (!bError) for (CObject* obj : m_objMan->GetAllObjects()) { if (obj->GetType() == OBJECT_TOTO) continue; if (IsObjectBeingTransported(obj)) continue; if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(obj)->IsDying()) continue; - if (!ReadFileStack(obj, file, objRank++)) break; + if (!ReadFileStack(obj, istr)) + { + GetLogger()->Error("ReadFileStack failed at object id = %i\n", obj->GetID()); + bError = true; + break; + } + } + + if (!bError && !CBot::CBotClass::RestoreStaticState(istr)) + { + GetLogger()->Error("CBotClass restore static state failed\n"); + bError = true; } } + else + GetLogger()->Error("cbot.run file is wrong version: %i\n", version); } - CBot::CBotClass::RestoreStaticState(file); - CBot::fClose(file); + + if (bError) GetLogger()->Error("Restoring CBOT state failed at stream position: %li\n", istr.tellg()); + istr.close(); } m_ui->GetLoadingScreen()->SetProgress(1.0f, RT_LOADING_FINISHED); @@ -4968,6 +5052,22 @@ Error CRobotMain::ProcessEndMissionTakeForGroup(std::vector //! If return value is different than ERR_MISSION_NOTERM, assume the mission is finished and pass on the result Error CRobotMain::ProcessEndMissionTake() { + bool timeout = false; + if (m_missionResult != INFO_LOST && m_missionResult != INFO_LOSTq) + { + if (m_endTakeTimeout >= 0.0f) + { + // Use the mission timer if available, or global mission time otherwise + // Useful for exercises where the time starts when you start the program, not the mission itself + float currentTime = m_missionTimerEnabled ? m_missionTimer : m_gameTime; + if (currentTime > m_endTakeTimeout) + { + m_missionResult = INFO_LOST; + timeout = true; + } + } + } + // Sort end conditions by teams std::map> teamsEndTake; for (std::unique_ptr& endTake : m_endTake) @@ -4978,28 +5078,50 @@ Error CRobotMain::ProcessEndMissionTake() if (!usesTeamConditions) { - m_missionResult = ProcessEndMissionTakeForGroup(teamsEndTake[0]); + if (!timeout) + m_missionResult = ProcessEndMissionTakeForGroup(teamsEndTake[0]); + + if (m_missionResult != INFO_LOST && m_missionResult != INFO_LOSTq) + { + if (m_endTakeResearch != 0) + { + if (m_endTakeResearch != (m_endTakeResearch&m_researchDone[0])) + { + m_missionResult = ERR_MISSION_NOTERM; + } + } + } } else { + assert(m_endTakeResearch == 0); // TODO: Add support for per-team EndTakeResearch + // Special handling for teams m_missionResult = ERR_MISSION_NOTERM; - if (GetAllActiveTeams().empty()) + if (GetAllActiveTeams().empty() || timeout) { GetLogger()->Info("All teams died, mission ended\n"); if (m_scoreboard) { std::string title, text, details_line; GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS, title); - GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_TEXT, text); + if (m_missionTimerEnabled && m_missionTimerStarted) + { + GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_TIME, text); + text = StrUtils::Format(text.c_str(), TimeFormat(m_missionTimer).c_str()); + } + else + { + GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_TEXT, text); + } GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_LINE, details_line); std::string details = ""; - for (int team : GetAllTeams()) + for (std::pair team : m_scoreboard->GetSortedScores()) { if (!details.empty()) details += ", "; - details += StrUtils::Format(details_line.c_str(), GetTeamName(team).c_str(), m_scoreboard->GetScore(team).points); + details += StrUtils::Format(details_line.c_str(), GetTeamName(team.first).c_str(), team.second.points); } m_ui->GetDialog()->StartInformation( title, @@ -5070,18 +5192,19 @@ Error CRobotMain::ProcessEndMissionTake() m_scoreboard->ProcessEndTake(team); m_objMan->DestroyTeam(team, DestructionType::Win); m_teamFinished[team] = true; - } - } - } - } + if (m_endTakeTeamImmediateWin) + { + // All other teams fail + for(int other_team : GetAllActiveTeams()) + { + m_displayText->SetEnable(false); // To prevent "bot destroyed" messages + m_objMan->DestroyTeam(other_team); + m_displayText->SetEnable(true); - if (m_missionResult != INFO_LOST && m_missionResult != INFO_LOSTq) - { - if (m_endTakeResearch != 0) - { - if (m_endTakeResearch != (m_endTakeResearch&m_researchDone[0])) - { - m_missionResult = ERR_MISSION_NOTERM; + m_teamFinished[other_team] = true; + } + } + } } } } @@ -5300,10 +5423,11 @@ void CRobotMain::UpdateChapterPassed() return m_ui->UpdateChapterPassed(); } - //! Changes game speed void CRobotMain::SetSpeed(float speed) { + speed = Math::Clamp(speed, MIN_SPEED, MAX_SPEED); + m_app->SetSimulationSpeed(speed); UpdateSpeedLabel(); } @@ -5855,7 +5979,7 @@ void CRobotMain::CreateCodeBattleInterface() 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); + float textHeight = m_engine->GetText()->GetHeight(Gfx::FONT_COMMON, Gfx::FONT_SIZE_SMALL); //window ddim.x = 100.0f/640.0f; @@ -5876,12 +6000,12 @@ void CRobotMain::CreateCodeBattleInterface() //viewpoint selection section ddim.x = 40.0f/640.0f; ddim.y = 50.0f/640.0f; - for(unsigned int i = 0; iCreateButton(pos,ddim, 13, EventType(EVENT_VIEWPOINT0 + i)); + pw->CreateButton(pos, ddim, m_viewpoints[i].button, EventType(EVENT_VIEWPOINT0 + i)); } //start/camera button @@ -5962,32 +6086,19 @@ void CRobotMain::UpdateCodeBattleInterface() Ui::CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW6)); assert(pw != nullptr); - std::set teams = GetAllTeams(); - std::vector sortedTeams(teams.begin(), teams.end()); - if(m_scoreboard->GetSortType() == SortType::SORT_POINTS) - { - std::sort(sortedTeams.begin(), sortedTeams.end(), [this](int teamA, int teamB) - { - if (m_scoreboard->GetScore(teamA).points > m_scoreboard->GetScore(teamB).points) return true; //Team A have more points than B? - if (m_scoreboard->GetScore(teamA).points < m_scoreboard->GetScore(teamB).points) return false; //Team A have less points than B? - - if (m_scoreboard->GetScore(teamA).time < m_scoreboard->GetScore(teamB).time) return true; //Team A scored faster than B? - else return false; //Team A scored slower than B? - }); - } int i = 0; - for (int team : sortedTeams) + for (std::pair team : m_scoreboard->GetSortedScores()) { Ui::CControl* pl; pl = pw->SearchControl(static_cast(EVENT_SCOREBOARD+2*i+0)); assert(pl != nullptr); - pl->SetName(GetTeamName(team)); + pl->SetName(GetTeamName(team.first)); pl = pw->SearchControl(static_cast(EVENT_SCOREBOARD+2*i+1)); assert(pl != nullptr); - pl->SetName(StrUtils::ToString(m_scoreboard->GetScore(team).points)); + pl->SetName(StrUtils::ToString(team.second.points)); i++; } diff --git a/src/level/robotmain.h b/src/level/robotmain.h index 1e19d514..2b4c7b03 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -152,8 +152,9 @@ struct MinMax struct Viewpoint { - Math::Vector eye; - Math::Vector look; + Math::Vector eye{}; + Math::Vector look{}; + int button = 13; // 13 is the camera button }; const int SATCOM_HUSTON = 0; @@ -307,8 +308,8 @@ public: void SaveAllScript(); void SaveOneScript(CObject *obj); - bool SaveFileStack(CObject *obj, FILE *file, int objRank); - bool ReadFileStack(CObject *obj, FILE *file, int objRank); + bool SaveFileStack(CObject *obj, std::ostream &ostr); + bool ReadFileStack(CObject *obj, std::istream &istr); //! Return list of scripts to load to robot created in BotFactory std::vector GetNewScriptNames(ObjectType type); @@ -672,6 +673,8 @@ protected: //! If true, the mission ends immediately after completing the requirements without requiring SpaceShip takeoff bool m_endTakeImmediat = false; long m_endTakeResearch = 0; + float m_endTakeTimeout = -1.0f; + bool m_endTakeTeamImmediateWin = false; float m_endTakeWinDelay = 0.0f; float m_endTakeLostDelay = 0.0f; //! Set to true for teams that have already finished diff --git a/src/level/scene_conditions.cpp b/src/level/scene_conditions.cpp index 3ab32dac..263ee399 100644 --- a/src/level/scene_conditions.cpp +++ b/src/level/scene_conditions.cpp @@ -112,6 +112,18 @@ bool CObjectCondition::CheckForObject(CObject* obj) return false; } +int CObjectCondition::CountObjects() +{ + int nb = 0; + for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) + { + if (!obj->GetActive()) continue; + if (!CheckForObject(obj)) continue; + nb ++; + } + return nb; +} + void CSceneCondition::Read(CLevelParserLine* line) { CObjectCondition::Read(line); @@ -124,18 +136,6 @@ void CSceneCondition::Read(CLevelParserLine* line) this->max = line->GetParam("max")->AsInt(9999); } -int CSceneCondition::CountObjects() -{ - int nb = 0; - for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) - { - if (!obj->GetActive()) continue; - if (!CheckForObject(obj)) continue; - nb ++; - } - return nb; -} - bool CSceneCondition::Check() { int nb = CountObjects(); diff --git a/src/level/scene_conditions.h b/src/level/scene_conditions.h index 412a45b3..218c668d 100644 --- a/src/level/scene_conditions.h +++ b/src/level/scene_conditions.h @@ -58,6 +58,9 @@ public: //! Checks if this condition is met bool CheckForObject(CObject* obj); + + //! Count all object matching the conditions + int CountObjects(); }; /** @@ -75,10 +78,6 @@ public: //! Checks if this condition is met bool Check(); - -protected: - //! Count all object matching the conditions - int CountObjects(); }; /** diff --git a/src/level/scoreboard.cpp b/src/level/scoreboard.cpp index bfadc4d0..3fa006cb 100644 --- a/src/level/scoreboard.cpp +++ b/src/level/scoreboard.cpp @@ -41,6 +41,14 @@ void CScoreboard::CScoreboardKillRule::Read(CLevelParserLine* line) { CScoreboardRule::Read(line); CObjectCondition::Read(line); + this->friendlyFire = line->GetParam("friendlyFire")->AsBool(false); +} + +void CScoreboard::CScoreboardObjectRule::Read(CLevelParserLine* line) +{ + CScoreboardRule::Read(line); + CObjectCondition::Read(line); + this->winTeam = line->GetParam("winTeam")->AsInt(); } void CScoreboard::CScoreboardEndTakeRule::Read(CLevelParserLine* line) @@ -55,6 +63,11 @@ void CScoreboard::AddKillRule(std::unique_ptr rule) m_rulesKill.push_back(std::move(rule)); } +void CScoreboard::AddObjectRule(std::unique_ptr rule) +{ + m_rulesObject.push_back(std::move(rule)); +} + void CScoreboard::AddEndTakeRule(std::unique_ptr rule) { m_rulesEndTake.push_back(std::move(rule)); @@ -70,11 +83,28 @@ void CScoreboard::ProcessKill(CObject* target, CObject* killer) killer->GetTeam() != 0 && rule->CheckForObject(target)) { + if (killer->GetTeam() == target->GetTeam() && !rule->friendlyFire) + continue; AddPoints(killer->GetTeam(), rule->score); } } } +void CScoreboard::UpdateObjectCount() +{ + for (auto& rule : m_rulesObject) + { + assert(rule->winTeam != 0); + int count = rule->CountObjects(); + int countDiff = count - rule->lastCount; + if (countDiff != 0) + { + rule->lastCount = count; + AddPoints(rule->winTeam, rule->score * countDiff); + } + } +} + void CScoreboard::ProcessEndTake(int team) { if (team == 0) return; @@ -103,7 +133,7 @@ void CScoreboard::AddPoints(int team, int points) m_score[team].time = main->GetGameTime(); } -Score CScoreboard::GetScore(int team) +CScoreboard::Score CScoreboard::GetScore(int team) { return m_score[team]; } @@ -113,12 +143,34 @@ void CScoreboard::SetScore(int team, int points) m_score[team].points = points; } -SortType CScoreboard::GetSortType() +CScoreboard::SortType CScoreboard::GetSortType() { - return m_sorttype; + return m_sortType; } void CScoreboard::SetSortType(SortType type) { - m_sorttype = type; + m_sortType = type; +} + +std::vector> CScoreboard::GetSortedScores() +{ + CRobotMain* main = CRobotMain::GetInstancePointer(); + std::set teams = main->GetAllTeams(); + std::vector> sortedTeams(teams.size()); + std::transform(teams.begin(), teams.end(), sortedTeams.begin(), [&](int team) + { + return *m_score.find(team); + }); + if (m_sortType == SortType::SORT_POINTS) + { + std::sort(sortedTeams.begin(), sortedTeams.end(), [&](std::pair teamA, std::pair teamB) + { + if (teamA.second.points > teamB.second.points) return true; // Team A have more points than B? + if (teamA.second.points < teamB.second.points) return false; // Team A have less points than B? + + return teamA.second.time < teamB.second.time; // Team A scored slower than B? + }); + } + return sortedTeams; } diff --git a/src/level/scoreboard.h b/src/level/scoreboard.h index c9be19fb..98f94b60 100644 --- a/src/level/scoreboard.h +++ b/src/level/scoreboard.h @@ -32,22 +32,6 @@ class CObject; -/** - * \struct Score - * \brief Struct containing score of individual team and additional variables to allow sorting teams through different criteria -*/ -struct Score -{ - int points = 0; //! Team score - float time = 0; //! Time when points were scored -}; - -enum class SortType -{ - SORT_ID, //Sort by team ID - SORT_POINTS, //Sort by points -}; - /** * \class CScoreboard * \brief Scoreboard used to score complex code battles @@ -64,12 +48,33 @@ enum class SortType * ScoreboardSortType sort=Name // sort teams alphabetically, another option is sort=Points, sorting teams in order of points * ScoreboardKillRule type=WheeledShooter team=1 score=500 // destruction of team 1's WheeledShooter gives 100 points to the team that destroyed it * ScoreboardKillRule type=TargetBot score=100 // destruction of TargetBot (any team) gives 100 points + * ScoreboardObjectRule pos=0.0;0.5 dist=5.0 type=Titanium winTeam=1 score=5 // each Titanium within 5 meters of 0;0 gives team 1 5 points, losing Titanium gives -5 * ScoreboardEndTakeRule score=1000 // completion of EndMissionTake objectives for any team results in 1000 points for that team * \endcode */ class CScoreboard { public: + /** + * \struct Score + * \brief Struct containing score of individual team and additional variables to allow sorting teams through different criteria + */ + struct Score + { + int points = 0; //!< Team score + float time = 0; //!< Time when points were scored + }; + + /** + * \enum SortType + * \brief Enum defining the scoreboard sorting criteria + */ + enum class SortType + { + SORT_ID, //!< Sort by team ID + SORT_POINTS, //!< Sort by points + }; + //! Creates the scoreboard //! The scoreboard exists only if enabled in level file CScoreboard() {}; @@ -98,10 +103,28 @@ public: class CScoreboardKillRule final : public CScoreboardRule, public CObjectCondition { public: + bool friendlyFire = false; + //! Read from line in scene file void Read(CLevelParserLine* line) override; }; + /** + * \class CScoreboardObjectRule + * \brief Scoreboard rule for counting objects + * \see CScoreboard::AddObjectRule() + */ + class CScoreboardObjectRule final : public CScoreboardRule, public CObjectCondition + { + public: + int winTeam = 0; + + //! Read from line in scene file + void Read(CLevelParserLine* line) override; + + int lastCount = 0; + }; + /** * \class CScoreboardEndTakeRule * \brief Scoreboard rule for EndMissionTake rewards @@ -120,6 +143,8 @@ public: public: //! Add ScoreboardKillRule void AddKillRule(std::unique_ptr rule); + //! Add ScoreboardObjectRule + void AddObjectRule(std::unique_ptr rule); //! Add ScoreboardEndTakeRule void AddEndTakeRule(std::unique_ptr rule); @@ -127,6 +152,8 @@ public: //! \param target The object that has just been destroyed //! \param killer The object that caused the destruction, can be null void ProcessKill(CObject* target, CObject* killer = nullptr); + //! Updates the object count rules + void UpdateObjectCount(); //! Called after EndTake contition has been met, used to handle ScoreboardEndTakeRule void ProcessEndTake(int team); @@ -137,10 +164,13 @@ public: SortType GetSortType(); void SetSortType(SortType type); + std::vector> GetSortedScores(); + private: std::vector> m_rulesKill = {}; + std::vector> m_rulesObject = {}; std::vector> m_rulesEndTake = {}; std::map m_score; int m_finishCounter = 0; - SortType m_sorttype = SortType::SORT_ID; + SortType m_sortType = SortType::SORT_ID; }; diff --git a/src/object/auto/autoportico.cpp b/src/object/auto/autoportico.cpp index 2a8bf372..5ef25c78 100644 --- a/src/object/auto/autoportico.cpp +++ b/src/object/auto/autoportico.cpp @@ -47,8 +47,8 @@ const float PORTICO_TIME_OPEN = 12.0f; -// Si progress=0, return a. -// Si progress=1, return b. +// if progress=0, return a. +// if progress=1, return b. static float Progress(float a, float b, float progress) { diff --git a/src/object/auto/autopowerplant.cpp b/src/object/auto/autopowerplant.cpp index 37b2d7d5..d7294b93 100644 --- a/src/object/auto/autopowerplant.cpp +++ b/src/object/auto/autopowerplant.cpp @@ -82,12 +82,14 @@ void CAutoPowerPlant::DeleteObject(bool all) CObject* cargo = SearchMetal(); if ( cargo != nullptr ) { + m_object->SetPower(nullptr); CObjectManager::GetInstancePointer()->DeleteObject(cargo); } cargo = SearchPower(); if ( cargo != nullptr ) { + m_object->SetPower(nullptr); CObjectManager::GetInstancePointer()->DeleteObject(cargo); } } diff --git a/src/object/auto/autopowerstation.cpp b/src/object/auto/autopowerstation.cpp index 5b90b6fa..667c8324 100644 --- a/src/object/auto/autopowerstation.cpp +++ b/src/object/auto/autopowerstation.cpp @@ -302,9 +302,7 @@ Error CAutoPowerStation::GetError() return ERR_OK; } - -// Crée toute l'interface lorsque l'objet est sélectionné . - +// Create the all interface when the object is selected. bool CAutoPowerStation::CreateInterface(bool bSelect) { Ui::CWindow* pw; diff --git a/src/object/auto/autoresearch.cpp b/src/object/auto/autoresearch.cpp index ccc24c85..a1c98b69 100644 --- a/src/object/auto/autoresearch.cpp +++ b/src/object/auto/autoresearch.cpp @@ -502,7 +502,7 @@ void CAutoResearch::FireStopUpdate(float progress, bool bLightOn) 4.7f, -8.2f, }; - if ( !bLightOn ) // �teint ? + if ( !bLightOn ) // light-off ? { for ( i=0 ; i<6 ; i++ ) { diff --git a/src/object/implementation/programmable_impl.cpp b/src/object/implementation/programmable_impl.cpp index 5e370bdb..34be6c59 100644 --- a/src/object/implementation/programmable_impl.cpp +++ b/src/object/implementation/programmable_impl.cpp @@ -143,24 +143,43 @@ bool CProgrammableObjectImpl::IsProgram() // Load a stack of script implementation from a file. -bool CProgrammableObjectImpl::ReadStack(FILE *file) +bool CProgrammableObjectImpl::ReadStack(std::istream &istr) { short op; - CBot::fRead(&op, sizeof(short), 1, file); + if (!CBot::ReadShort(istr, op)) return false; if ( op == 1 ) // run ? { - CBot::fRead(&op, sizeof(short), 1, file); // program rank + if (!CBot::ReadShort(istr, op)) return false; // program rank if ( op >= 0 ) { if (m_object->Implements(ObjectInterfaceType::ProgramStorage)) { - assert(op < static_cast(dynamic_cast(m_object)->GetProgramCount())); + int count = static_cast(dynamic_cast(m_object)->GetProgramCount()); + if (!(op < count)) + { + GetLogger()->Info("Object program count: %i\n", count); + GetLogger()->Error("Error in file: program index out of range: %i\n", op); + return false; + } + m_currentProgram = dynamic_cast(m_object)->GetProgram(op); - if ( !m_currentProgram->script->ReadStack(file) ) return false; + if (!m_currentProgram->script->ReadStack(istr)) + { + GetLogger()->Error("Restore state failed at program index: %i\n", op); + int errNum = m_currentProgram->script->GetError(); + if (errNum != 0) + { + std::string errStr; + m_currentProgram->script->GetError(errStr); + GetLogger()->Error("Program reports error: %i:(%s)\n", errNum, errStr.c_str()); + } + return false; + } } else { + GetLogger()->Error("Object is not a program storage object\n"); return false; } } @@ -171,7 +190,7 @@ bool CProgrammableObjectImpl::ReadStack(FILE *file) // Save the script implementation stack of a file. -bool CProgrammableObjectImpl::WriteStack(FILE *file) +bool CProgrammableObjectImpl::WriteStack(std::ostream &ostr) { short op; @@ -179,21 +198,25 @@ bool CProgrammableObjectImpl::WriteStack(FILE *file) m_currentProgram->script->IsRunning() ) { op = 1; // run - CBot::fWrite(&op, sizeof(short), 1, file); + if (!CBot::WriteShort(ostr, op)) return false; op = -1; if (m_object->Implements(ObjectInterfaceType::ProgramStorage)) { op = dynamic_cast(m_object)->GetProgramIndex(m_currentProgram); } - CBot::fWrite(&op, sizeof(short), 1, file); + if (!CBot::WriteShort(ostr, op)) return false; - return m_currentProgram->script->WriteStack(file); + if (!m_currentProgram->script->WriteStack(ostr)) + { + GetLogger()->Error("Save state failed at program index: %i\n", op); + return false; + } + return true; } op = 0; // stop - CBot::fWrite(&op, sizeof(short), 1, file); - return true; + return CBot::WriteShort(ostr, op); } diff --git a/src/object/implementation/programmable_impl.h b/src/object/implementation/programmable_impl.h index a0b78096..38b8be7c 100644 --- a/src/object/implementation/programmable_impl.h +++ b/src/object/implementation/programmable_impl.h @@ -58,8 +58,8 @@ public: Program* GetCurrentProgram() override; void StopProgram() override; - bool ReadStack(FILE *file) override; - bool WriteStack(FILE *file) override; + bool ReadStack(std::istream &istr) override; + bool WriteStack(std::ostream &ostr) override; void TraceRecordStart() override; void TraceRecordStop() override; diff --git a/src/object/interface/programmable_object.h b/src/object/interface/programmable_object.h index 05f1a92c..1ce0d5d4 100644 --- a/src/object/interface/programmable_object.h +++ b/src/object/interface/programmable_object.h @@ -53,9 +53,9 @@ public: virtual bool IsProgram() = 0; //! Save current execution status to file - virtual bool WriteStack(FILE *file) = 0; + virtual bool WriteStack(std::ostream &ostr) = 0; //! Read current execution status from file - virtual bool ReadStack(FILE *file) = 0; + virtual bool ReadStack(std::istream &istr) = 0; //! Start recording trace virtual void TraceRecordStart() = 0; diff --git a/src/object/object_manager.cpp b/src/object/object_manager.cpp index c8d8cef7..0b4daed9 100644 --- a/src/object/object_manager.cpp +++ b/src/object/object_manager.cpp @@ -71,7 +71,7 @@ bool CObjectManager::DeleteObject(CObject* instance) it->second.reset(); m_shouldCleanRemovedObjects = true; return true; - } + } else assert(false); return false; } diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index 80b65c4d..3ecbb0e8 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -284,13 +284,19 @@ void COldObject::DeleteObject(bool bAll) if (m_power != nullptr) { if (m_power->Implements(ObjectInterfaceType::Old)) + { + dynamic_cast(m_power)->SetTransporter(nullptr); dynamic_cast(m_power)->DeleteObject(bAll); + } m_power = nullptr; } if (m_cargo != nullptr) { if (m_cargo->Implements(ObjectInterfaceType::Old)) + { + dynamic_cast(m_cargo)->SetTransporter(nullptr); dynamic_cast(m_cargo)->DeleteObject(bAll); + } m_cargo = nullptr; } } @@ -684,6 +690,8 @@ void COldObject::SetType(ObjectType type) m_type = type; m_name = GetObjectName(m_type); + SetSelectable(IsSelectableByDefault(m_type)); + // TODO: Temporary hack if ( m_type == OBJECT_MOBILEfa || // WingedGrabber m_type == OBJECT_MOBILEfs || // WingedSniffer @@ -1089,6 +1097,10 @@ void COldObject::Read(CLevelParserLine* line) { SetRange(line->GetParam("range")->AsFloat(30.0f)); } + if (Implements(ObjectInterfaceType::Fragile)) + { + SetMagnifyDamage(line->GetParam("magnifyDamage")->AsFloat(1.0f)); // TODO: This is a temporary hack for now - CFragileObject doesn't have SetMagnifyDamage ~krzys_h + } if (Implements(ObjectInterfaceType::Shielded)) { SetShield(line->GetParam("shield")->AsFloat(1.0f)); diff --git a/src/object/task/taskgoto.h b/src/object/task/taskgoto.h index 296fec92..74de5e1c 100644 --- a/src/object/task/taskgoto.h +++ b/src/object/task/taskgoto.h @@ -147,7 +147,7 @@ protected: int m_bmTotal = 0; // number of points in m_bmPoints int m_bmIndex = 0; // index in m_bmPoints Math::Vector m_bmPoints[MAXPOINTS+2]; - char m_bmIter[MAXPOINTS+2] = {}; + signed char m_bmIter[MAXPOINTS+2] = {}; int m_bmIterCounter = 0; CObject* m_bmCargoObject = nullptr; float m_bmFinalMove = 0.0f; // final advance distance diff --git a/src/object/task/taskmanip.cpp b/src/object/task/taskmanip.cpp index 16615ebd..0f38171c 100644 --- a/src/object/task/taskmanip.cpp +++ b/src/object/task/taskmanip.cpp @@ -259,7 +259,7 @@ void CTaskManip::InitAngle() float energy = GetObjectEnergy(m_object); if ( energy == 0.0f ) { - m_speed *= 0.7f; // slower if more energy! + m_speed *= 0.7f; // slower if no more energy! } } diff --git a/src/object/task/tasktake.cpp b/src/object/task/tasktake.cpp index c67a7e56..e8a27021 100644 --- a/src/object/task/tasktake.cpp +++ b/src/object/task/tasktake.cpp @@ -419,7 +419,7 @@ bool CTaskTake::TransporterTakeObject() //? cargo = SearchTakeObject(angle, 1.5f, Math::PI*0.04f); float angle = 0.0f; CObject* cargo = SearchTakeObject(angle, 1.5f, Math::PI*0.15f); //OK 1.9 - if (cargo == nullptr) return false; // rien � prendre ? + if (cargo == nullptr) return false; // nothing to take ? assert(cargo->Implements(ObjectInterfaceType::Transportable)); m_cargoType = cargo->GetType(); diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index b97742c5..7e30a8e4 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -1196,7 +1196,7 @@ void CPhysics::EffectUpdate(float aTime, float rTime) type == OBJECT_MOBILEfc || type == OBJECT_MOBILEfi || type == OBJECT_MOBILEfs || - type == OBJECT_MOBILEft ) // fliyng? + type == OBJECT_MOBILEft ) // flying? { if ( m_bLand ) // on the ground? { diff --git a/src/script/cbottoken.cpp b/src/script/cbottoken.cpp index aae31402..5776b87f 100644 --- a/src/script/cbottoken.cpp +++ b/src/script/cbottoken.cpp @@ -240,8 +240,13 @@ std::string GetHelpFilename(const char *token) if ( strcmp(token, "continue" ) == 0 ) helpfile = "cbot/continue"; if ( strcmp(token, "return" ) == 0 ) helpfile = "cbot/return"; if ( strcmp(token, "sizeof" ) == 0 ) helpfile = "cbot/sizeof"; + if ( strcmp(token, "byte" ) == 0 ) helpfile = "cbot/byte"; + if ( strcmp(token, "short" ) == 0 ) helpfile = "cbot/short"; + if ( strcmp(token, "char" ) == 0 ) helpfile = "cbot/char"; if ( strcmp(token, "int" ) == 0 ) helpfile = "cbot/int"; + if ( strcmp(token, "long" ) == 0 ) helpfile = "cbot/long"; if ( strcmp(token, "float" ) == 0 ) helpfile = "cbot/float"; + if ( strcmp(token, "double" ) == 0 ) helpfile = "cbot/double"; if ( strcmp(token, "bool" ) == 0 ) helpfile = "cbot/bool"; if ( strcmp(token, "string" ) == 0 ) helpfile = "cbot/string"; if ( strcmp(token, "point" ) == 0 ) helpfile = "cbot/point"; @@ -376,6 +381,9 @@ std::string GetHelpFilename(const char *token) if ( strcmp(token, "synchronized" ) == 0 ) helpfile = "cbot/synchro"; if ( strcmp(token, "new" ) == 0 ) helpfile = "cbot/new"; if ( strcmp(token, "this" ) == 0 ) helpfile = "cbot/this"; + if ( strcmp(token, "switch" ) == 0 || + strcmp(token, "case" ) == 0 || + strcmp(token, "default" ) == 0 ) helpfile = "cbot/switch"; if (helpfile.empty()) return ""; @@ -389,8 +397,13 @@ std::string GetHelpFilename(const char *token) bool IsType(const char *token) { if ( strcmp(token, "void" ) == 0 ) return true; + if ( strcmp(token, "byte" ) == 0 ) return true; + if ( strcmp(token, "short" ) == 0 ) return true; + if ( strcmp(token, "char" ) == 0 ) return true; if ( strcmp(token, "int" ) == 0 ) return true; + if ( strcmp(token, "long" ) == 0 ) return true; if ( strcmp(token, "float" ) == 0 ) return true; + if ( strcmp(token, "double" ) == 0 ) return true; if ( strcmp(token, "bool" ) == 0 ) return true; if ( strcmp(token, "string" ) == 0 ) return true; if ( strcmp(token, "point" ) == 0 ) return true; @@ -495,11 +508,14 @@ bool IsFunction(const char *token) const char* GetHelpText(const char *token) { - if ( strcmp(token, "if" ) == 0 ) return "if ( condition ) { bloc }"; - if ( strcmp(token, "else" ) == 0 ) return "else { bloc }"; + if ( strcmp(token, "if" ) == 0 ) return "if ( condition ) { code }"; + if ( strcmp(token, "else" ) == 0 ) return "else { code }"; if ( strcmp(token, "for" ) == 0 ) return "for ( before ; condition ; end )"; - if ( strcmp(token, "while" ) == 0 ) return "while ( condition ) { bloc }"; - if ( strcmp(token, "do" ) == 0 ) return "do { bloc } while ( condition );"; + if ( strcmp(token, "while" ) == 0 ) return "while ( condition ) { code }"; + if ( strcmp(token, "do" ) == 0 ) return "do { code } while ( condition );"; + if ( strcmp(token, "switch" ) == 0 ) return "switch ( value ) { code }"; + if ( strcmp(token, "case" ) == 0 ) return "case label: { code }"; + if ( strcmp(token, "default" ) == 0 ) return "default: { code } "; if ( strcmp(token, "break" ) == 0 ) return "break;"; if ( strcmp(token, "continue" ) == 0 ) return "continue;"; if ( strcmp(token, "return" ) == 0 ) return "return;"; diff --git a/src/script/script.cpp b/src/script/script.cpp index a94e850f..0b5828aa 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -589,16 +589,17 @@ void CScript::UpdateList(Ui::CList* list) list->SetState(Ui::STATE_ENABLE); } -// Colorize a string literal with escape sequences also colored +// Colorize a string or character literal with escape sequences also colored static void HighlightString(Ui::CEdit* edit, const std::string& s, int start) { edit->SetFormat(start, start + 1, Gfx::FONT_HIGHLIGHT_STRING); - auto it = s.cbegin() + 1; + auto it = s.cbegin(); + char endQuote = *(it++); ++start; - while (it != s.cend() && *it != '\"') + while (it != s.cend() && *it != endQuote) { if (*(it++) != '\\') // not escape sequence { @@ -697,7 +698,7 @@ void CScript::ColorizeScript(Ui::CEdit* edit, int rangeStart, int rangeEnd) { color = Gfx::FONT_HIGHLIGHT_STRING; } - else if (type == CBot::TokenTypString) // string literals + else if (type == CBot::TokenTypString || type == CBot::TokenTypChar) // string literals and character literals { HighlightString(edit, token, cursor1); bt = bt->GetNext(); @@ -1032,16 +1033,16 @@ bool CScript::WriteScript(const char* filename) // Reads a stack of script by execution as a file. -bool CScript::ReadStack(FILE *file) +bool CScript::ReadStack(std::istream &istr) { int nb; - CBot::fRead(&nb, sizeof(int), 1, file); - CBot::fRead(&m_ipf, sizeof(int), 1, file); - CBot::fRead(&m_errMode, sizeof(int), 1, file); + if (!CBot::ReadInt(istr, nb)) return false; + if (!CBot::ReadInt(istr, m_ipf)) return false; + if (!CBot::ReadInt(istr, m_errMode)) return false; if (m_botProg == nullptr) return false; - if ( !m_botProg->RestoreState(file) ) return false; + if (!m_botProg->RestoreState(istr)) return false; m_bRun = true; m_bContinue = false; @@ -1050,16 +1051,16 @@ bool CScript::ReadStack(FILE *file) // Writes a stack of script by execution as a file. -bool CScript::WriteStack(FILE *file) +bool CScript::WriteStack(std::ostream &ostr) { int nb; nb = 2; - CBot::fWrite(&nb, sizeof(int), 1, file); - CBot::fWrite(&m_ipf, sizeof(int), 1, file); - CBot::fWrite(&m_errMode, sizeof(int), 1, file); + if (!CBot::WriteInt(ostr, nb)) return false; + if (!CBot::WriteInt(ostr, m_ipf)) return false; + if (!CBot::WriteInt(ostr, m_errMode)) return false; - return m_botProg->SaveState(file); + return m_botProg->SaveState(ostr); } diff --git a/src/script/script.h b/src/script/script.h index f0f473fb..bc64dc23 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -88,8 +88,8 @@ public: bool SendScript(const char* text); bool ReadScript(const char* filename); bool WriteScript(const char* filename); - bool ReadStack(FILE *file); - bool WriteStack(FILE *file); + bool ReadStack(std::istream &istr); + bool WriteStack(std::ostream &ostr); bool Compare(CScript* other); void SetFilename(const std::string &filename); diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index 902a3425..78ed5ebf 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -718,7 +718,7 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo } CObject* obj = CObjectManager::GetInstancePointer()->GetObjectById(rank); - if ( obj == nullptr ) + if ( obj == nullptr || (obj->Implements(ObjectInterfaceType::Old) && dynamic_cast(obj)->IsDying()) ) { return true; } @@ -3472,9 +3472,9 @@ void CScriptFunctions::uObject(CBotVar* botThis, void* user) pVar = pVar->GetNext(); // "orientation" pVar->SetValFloat(Math::NormAngle(2*Math::PI - pos.y)*180.0f/Math::PI); pVar = pVar->GetNext(); // "pitch" - pVar->SetValFloat(Math::NormAngle(pos.z)*180.0f/Math::PI); + pVar->SetValFloat((Math::NormAngle(pos.z + Math::PI) - Math::PI)*180.0f/Math::PI); pVar = pVar->GetNext(); // "roll" - pVar->SetValFloat(Math::NormAngle(pos.x)*180.0f/Math::PI); + pVar->SetValFloat((Math::NormAngle(pos.x + Math::PI) - Math::PI)*180.0f/Math::PI); // Updates the energy level of the object. pVar = pVar->GetNext(); // "energyLevel" diff --git a/src/ui/controls/button.cpp b/src/ui/controls/button.cpp index 4c1d3d99..706946b7 100644 --- a/src/ui/controls/button.cpp +++ b/src/ui/controls/button.cpp @@ -25,8 +25,6 @@ #include "graphics/engine/engine.h" -#include - namespace Ui { diff --git a/src/ui/controls/color.cpp b/src/ui/controls/color.cpp index faecb435..86a6dd45 100644 --- a/src/ui/controls/color.cpp +++ b/src/ui/controls/color.cpp @@ -121,9 +121,7 @@ bool CColor::EventProcess(const Event &event) return true; } - -// Dessine le bouton. - +// Draw the button. void CColor::Draw() { Gfx::CDevice* device; diff --git a/src/ui/controls/control.cpp b/src/ui/controls/control.cpp index 2013b612..588c136d 100644 --- a/src/ui/controls/control.cpp +++ b/src/ui/controls/control.cpp @@ -24,6 +24,7 @@ #include "common/restext.h" #include "common/settings.h" +#include "common/stringutils.h" #include "level/robotmain.h" @@ -43,7 +44,7 @@ CControl::CControl() m_eventType = EVENT_NULL; m_state = STATE_ENABLE|STATE_VISIBLE|STATE_GLINT; m_fontSize = Gfx::FONT_SIZE_SMALL; - m_fontType = Gfx::FONT_COLOBOT; + m_fontType = Gfx::FONT_COMMON; m_textAlign = Gfx::TEXT_ALIGN_CENTER; //instead m_justify m_bFocus = false; m_bCapture = false; @@ -517,23 +518,8 @@ void CControl::Draw() if ( m_state & STATE_DEAD ) return; - icon = m_icon; - if ( icon >= 128 ) - { - icon -= 128; - m_engine->SetTexture("textures/interface/button3.png"); - m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE); - } - else if ( icon >= 64 ) - { - icon -= 64; - m_engine->SetTexture("textures/interface/button2.png"); - m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE); - } - else - { - m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE); - } + icon = SetButtonTextureForIcon(m_icon); + m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE); if ( icon != -1 ) { DrawPart(icon, zoomInt, 0.0f); @@ -851,5 +837,13 @@ std::string CControl::GetResourceName(EventType eventType) return name; } +int CControl::SetButtonTextureForIcon(int icon) +{ + int iconIdx = icon%64; + int buttonFile = (icon/64) + 1; + m_engine->SetTexture("textures/interface/button" + StrUtils::ToString(buttonFile) + ".png"); + return iconIdx; +} + } diff --git a/src/ui/controls/control.h b/src/ui/controls/control.h index d3e6d5aa..a7166df8 100644 --- a/src/ui/controls/control.h +++ b/src/ui/controls/control.h @@ -116,6 +116,13 @@ protected: std::string GetResourceName(EventType eventType); + /** + * \brief Set texture in m_engine to correct buttonX.png for given icon + * \param icon Icon to draw + * \return Index inside the selected texture of the icon to draw + */ + int SetButtonTextureForIcon(int icon); + protected: Gfx::CEngine* m_engine; Gfx::CParticle* m_particle; diff --git a/src/ui/controls/edit.cpp b/src/ui/controls/edit.cpp index b666b070..2fa9e8ab 100644 --- a/src/ui/controls/edit.cpp +++ b/src/ui/controls/edit.cpp @@ -109,7 +109,7 @@ CEdit::CEdit() { m_len = 0; - m_fontType = Gfx::FONT_COURIER; + m_fontType = Gfx::FONT_STUDIO; m_bEdit = true; m_bHilite = true; m_bInsideScroll = true; @@ -1326,13 +1326,13 @@ void CEdit::SetText(const std::string& text, bool bNew) if ( text[i+1] == 'n' ) // normal ? { font &= ~Gfx::FONT_MASK_FONT; - font |= Gfx::FONT_COLOBOT; + font |= Gfx::FONT_COMMON; i += 2; } else if ( text[i+1] == 'c' ) // cbot ? { font &= ~Gfx::FONT_MASK_FONT; - font |= Gfx::FONT_COURIER; + font |= Gfx::FONT_STUDIO; i += 2; } else if ( text[i+1] == 'b' ) // big title ? @@ -1522,7 +1522,7 @@ bool CEdit::ReadText(std::string filename) if ( m_bSoluce || !bInSoluce ) { font &= ~Gfx::FONT_MASK_FONT; - font |= Gfx::FONT_COLOBOT; + font |= Gfx::FONT_COMMON; inCbot = false; } i += 3; @@ -1532,7 +1532,7 @@ bool CEdit::ReadText(std::string filename) if ( m_bSoluce || !bInSoluce ) { font &= ~Gfx::FONT_MASK_FONT; - font |= Gfx::FONT_COURIER; + font |= Gfx::FONT_STUDIO; if (!inCbot) { if (inCbotBackground) @@ -1636,7 +1636,7 @@ bool CEdit::ReadText(std::string filename) //? iWidth = m_lineHeight*RetValueParam(buffer.data()+i+7, 1); iWidth = static_cast(GetValueParam(buffer.data()+i+7, 1)); - iWidth *= m_engine->GetText()->GetHeight(Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL); + iWidth *= m_engine->GetText()->GetHeight(Gfx::FONT_COMMON, Gfx::FONT_SIZE_SMALL); iLines = GetValueParam(buffer.data()+i+7, 2); // A part of image per line of text. @@ -2540,6 +2540,8 @@ bool CEdit::Paste() { char c; char* text; + int iTabToInsert=0; + int iTmp; //temp for tab space equivalant insertion if ( !m_bEdit ) { @@ -2554,20 +2556,36 @@ bool CEdit::Paste() } UndoMemorize(OPERUNDO_SPEC); - for ( unsigned int i = 0; i < strlen(text); i++ ) + for (unsigned int i = 0; iGetEditIndentValue()*iTabToInsert; iTmp>0; --iTmp) + InsertOne(' '); + iTabToInsert=0; } InsertOne(c); } - + if (0=m_len || '\n'!=m_text[m_cursor1])) + for (iTmp=m_engine->GetEditIndentValue() ; iTmp>0; --iTmp) + InsertOne(' '); SDL_free(text); Justif(); ColumnFix(); @@ -2872,7 +2890,7 @@ int CEdit::IndentTabCount() return nb; } -// Adds or removes qq tabs. +// Adds or removes some tabs. void CEdit::IndentTabAdjust(int number) { diff --git a/src/ui/controls/interface.cpp b/src/ui/controls/interface.cpp index 050ce193..cabe38f1 100644 --- a/src/ui/controls/interface.cpp +++ b/src/ui/controls/interface.cpp @@ -194,8 +194,7 @@ CEdit* CInterface::CreateEdit(Math::Point pos, Math::Point dim, int icon, EventT return CreateControl(pos, dim, icon, eventMsg); } -// Creates a new pave editable. - +// Creates a new editable area. CEditValue* CInterface::CreateEditValue(Math::Point pos, Math::Point dim, int icon, EventType eventMsg) { CEditValue* ev = CreateControl(pos, dim, icon, eventMsg); diff --git a/src/ui/controls/shortcut.cpp b/src/ui/controls/shortcut.cpp index d85132d1..7d3ddd6d 100644 --- a/src/ui/controls/shortcut.cpp +++ b/src/ui/controls/shortcut.cpp @@ -123,21 +123,7 @@ void CShortcut::Draw() DrawVertex(icon, 0.95f); } - icon = m_icon; - if ( icon >= 128 ) - { - icon -= 128; - m_engine->SetTexture("textures/interface/button3.png"); - } - else if ( icon >= 64 ) - { - icon -= 64; - m_engine->SetTexture("textures/interface/button2.png"); - } - else - { - m_engine->SetTexture("textures/interface/button1.png"); - } + icon = SetButtonTextureForIcon(m_icon); if (m_icon == 58) { m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE); diff --git a/src/ui/debug_menu.cpp b/src/ui/debug_menu.cpp index 28caab22..52f5efeb 100644 --- a/src/ui/debug_menu.cpp +++ b/src/ui/debug_menu.cpp @@ -65,7 +65,7 @@ void CDebugMenu::ToggleInterface() { CreateInterface(); CLabel* pl = m_interface->CreateLabel(Math::Point(0.0f, 0.9f), Math::Point(1.0f, 0.1f), -1, EVENT_LABEL19, "??"); - pl->SetFontType(Gfx::FONT_COURIER); + pl->SetFontType(Gfx::FONT_STUDIO); } else { diff --git a/src/ui/debug_menu.h b/src/ui/debug_menu.h index e3ee0933..ecc6f81e 100644 --- a/src/ui/debug_menu.h +++ b/src/ui/debug_menu.h @@ -39,7 +39,7 @@ class CInterface; /** * \class CDebugMenu - * \brief Handles debug menu (F11) + * \brief Handles debug menu (F10) * * There should always be only one instance of this class for each associated CRobotMain class. */ diff --git a/src/ui/displayinfo.cpp b/src/ui/displayinfo.cpp index 5d66b099..b1e6220e 100644 --- a/src/ui/displayinfo.cpp +++ b/src/ui/displayinfo.cpp @@ -383,7 +383,7 @@ void CDisplayInfo::StartDisplayInfo(std::string filename, int index, bool bSoluc edit->SetState(STATE_SHADOW); edit->SetMultiFont(true); edit->SetMaxChar(10000); - edit->SetFontType(Gfx::FONT_COLOBOT); + edit->SetFontType(Gfx::FONT_SATCOM); edit->SetSoluceMode(bSoluce); edit->ReadText(filename.c_str()); edit->HyperHome(filename.c_str()); diff --git a/src/ui/displaytext.cpp b/src/ui/displaytext.cpp index c2c90cfb..6bd8dcf7 100644 --- a/src/ui/displaytext.cpp +++ b/src/ui/displaytext.cpp @@ -197,7 +197,7 @@ void CDisplayText::DisplayText(const char *text, Math::Vector goal, float height } hBox = 0.045f; - hLine = m_engine->GetText()->GetHeight(Gfx::FONT_COLOBOT, FONTSIZE); + hLine = m_engine->GetText()->GetHeight(Gfx::FONT_COMMON, FONTSIZE); nLine = 0; for ( i=0 ; iCreateLabel(pos, ddim, -1, EVENT_DIALOG_LABEL, text); - pl->SetFontType(Gfx::FONT_COLOBOT_BOLD); + pl->SetFontType(Gfx::FONT_COMMON_BOLD); //TODO: Add \n support in CLabel pos.y -= ddim.y; pl = pw->CreateLabel(pos, ddim, -1, EVENT_DIALOG_LABEL1, details); diff --git a/src/ui/screen/screen.cpp b/src/ui/screen/screen.cpp index 181bf756..a5d8fbb0 100644 --- a/src/ui/screen/screen.cpp +++ b/src/ui/screen/screen.cpp @@ -71,7 +71,7 @@ void CScreen::CreateVersionDisplay() ddim.x = 90.0f/640.0f; ddim.y = 10.0f/480.0f; CLabel* pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, COLOBOT_VERSION_DISPLAY); - pl->SetFontType(Gfx::FONT_COURIER); + pl->SetFontType(Gfx::FONT_STUDIO); pl->SetFontSize(9.0f); } } diff --git a/src/ui/screen/screen_io.cpp b/src/ui/screen/screen_io.cpp index 06db0339..d3df8fdb 100644 --- a/src/ui/screen/screen_io.cpp +++ b/src/ui/screen/screen_io.cpp @@ -58,7 +58,7 @@ void CScreenIO::IOReadName() CEdit* pe; std::string resume; char line[100]; - char name[100]; + std::string name; time_t now; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); @@ -81,10 +81,10 @@ void CScreenIO::IOReadName() time(&now); strftime(line, 99, "%y.%m.%d %H:%M", localtime(&now)); - sprintf(name, "%s - %s %d", line, resume.c_str(), m_main->GetLevelRank()); + name = StrUtils::Format("%s - %s %d", line, resume.c_str(), m_main->GetLevelRank()); pe->SetText(name); - pe->SetCursor(strlen(name), 0); + pe->SetCursor(name.length(), 0); m_interface->SetFocus(pe); } diff --git a/src/ui/screen/screen_io_write.cpp b/src/ui/screen/screen_io_write.cpp index 126c69a2..b39a2227 100644 --- a/src/ui/screen/screen_io_write.cpp +++ b/src/ui/screen/screen_io_write.cpp @@ -85,7 +85,7 @@ void CScreenIOWrite::CreateInterface() ddim.y = 18.0f/480.0f; pe = pw->CreateEdit(pos, ddim, 0, EVENT_INTERFACE_IONAME); pe->SetState(STATE_SHADOW); - pe->SetFontType(Gfx::FONT_COLOBOT); + pe->SetFontType(Gfx::FONT_COMMON); pe->SetMaxChar(35); IOReadName(); diff --git a/src/ui/screen/screen_main_menu.cpp b/src/ui/screen/screen_main_menu.cpp index 76b50710..4ad270dc 100644 --- a/src/ui/screen/screen_main_menu.cpp +++ b/src/ui/screen/screen_main_menu.cpp @@ -159,7 +159,7 @@ void CScreenMainMenu::CreateInterface() pg->SetState(STATE_SHADOW); pos.y -= 5.0f/480.0f; pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, "TerranovaTeam"); - pl->SetFontType(Gfx::FONT_COURIER); + pl->SetFontType(Gfx::FONT_STUDIO); pl->SetFontSize(Gfx::FONT_SIZE_SMALL); // SatCom button diff --git a/src/ui/screen/screen_quit.cpp b/src/ui/screen/screen_quit.cpp index 5bfa93b5..0928c6bc 100644 --- a/src/ui/screen/screen_quit.cpp +++ b/src/ui/screen/screen_quit.cpp @@ -61,7 +61,7 @@ void CScreenQuit::CreateInterface() pe->SetGenericMode(true); pe->SetEditCap(false); pe->SetHighlightCap(false); - pe->SetFontType(Gfx::FONT_COURIER); + pe->SetFontType(Gfx::FONT_STUDIO); pe->SetFontSize(Gfx::FONT_SIZE_SMALL); pe->ReadText(std::string("help/") + m_app->GetLanguageChar() + std::string("/authors.txt")); @@ -71,13 +71,13 @@ void CScreenQuit::CreateInterface() ddim.y = 16.0f/480.0f; GetResource(RES_TEXT, RT_GENERIC_DEV1, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, name); - pl->SetFontType(Gfx::FONT_COURIER); + pl->SetFontType(Gfx::FONT_STUDIO); pl->SetFontSize(Gfx::FONT_SIZE_SMALL); pos.y = 13.0f/480.0f; GetResource(RES_TEXT, RT_GENERIC_DEV2, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL2, name); - pl->SetFontType(Gfx::FONT_COURIER); + pl->SetFontType(Gfx::FONT_STUDIO); pl->SetFontSize(Gfx::FONT_SIZE_SMALL); pos.x = 355.0f/640.0f; @@ -86,13 +86,13 @@ void CScreenQuit::CreateInterface() ddim.y = 16.0f/480.0f; GetResource(RES_TEXT, RT_GENERIC_EDIT1, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL3, name); - pl->SetFontType(Gfx::FONT_COURIER); + pl->SetFontType(Gfx::FONT_STUDIO); pl->SetFontSize(Gfx::FONT_SIZE_SMALL); pos.y = 13.0f/480.0f; GetResource(RES_TEXT, RT_GENERIC_EDIT2, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL4, name); - pl->SetFontType(Gfx::FONT_COURIER); + pl->SetFontType(Gfx::FONT_STUDIO); pl->SetFontSize(Gfx::FONT_SIZE_SMALL); pos.x = 306.0f/640.0f; diff --git a/src/ui/screen/screen_setup_display.cpp b/src/ui/screen/screen_setup_display.cpp index bf31baa6..d015a58c 100644 --- a/src/ui/screen/screen_setup_display.cpp +++ b/src/ui/screen/screen_setup_display.cpp @@ -101,6 +101,36 @@ void CScreenSetupDisplay::CreateInterface() pc->SetState(STATE_SHADOW); pc->SetState(STATE_CHECK, m_setupFull); + pos.x = ox+sx*10; + pos.y = oy+sy*6.75f; + ddim.x = dim.x*6; + ddim.y = dim.y*1; + GetResource(RES_EVENT, EVENT_INTERFACE_VSYNC, name); + pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL2, name); + pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); + + pos.x = ox+sx*10; + pos.y = oy+sy*5.2f; + ddim.x = dim.x*6; + ddim.y = dim.y*2; + pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_VSYNC); + pli->SetState(STATE_SHADOW); + pli->SetItemName(0, "Off"); + pli->SetItemName(1, "Adaptive"); + pli->SetItemName(2, "On"); + switch(m_engine->GetVSync()) + { + case -1: //Adaptive? + pli->SetSelect(1); + break; + case 0: //Off? + pli->SetSelect(0); + break; + case 1: //On? + pli->SetSelect(2); + break; + } + ddim.x = dim.x*6; ddim.y = dim.y*1; pos.x = ox+sx*10; @@ -117,6 +147,7 @@ bool CScreenSetupDisplay::EventProcess(const Event &event) CWindow* pw; CCheck* pc; CButton* pb; + CList* pl; switch( event.type ) { @@ -153,6 +184,27 @@ bool CScreenSetupDisplay::EventProcess(const Event &event) UpdateApply(); break; + case EVENT_INTERFACE_VSYNC: + pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if ( pw == nullptr ) break; + pl = static_cast(pw->SearchControl(EVENT_INTERFACE_VSYNC)); + if (pl == nullptr ) break; + switch(pl->GetSelect()) + { + case 0: //Off? + m_engine->SetVSync(0); + break; + case 1: //Adaptive? + m_engine->SetVSync(-1); + break; + case 2: //On? + m_engine->SetVSync(1); + break; + } + ChangeDisplay(); + UpdateApply(); + break; + default: return true; } diff --git a/src/ui/screen/screen_setup_game.cpp b/src/ui/screen/screen_setup_game.cpp index cb4af8f4..a076ab59 100644 --- a/src/ui/screen/screen_setup_game.cpp +++ b/src/ui/screen/screen_setup_game.cpp @@ -149,6 +149,7 @@ void CScreenSetupGame::CreateInterface() pli->SetItemName(1+LANGUAGE_GERMAN, "German"); pli->SetItemName(1+LANGUAGE_POLISH, "Polish"); pli->SetItemName(1+LANGUAGE_RUSSIAN, "Russian"); + pli->SetItemName(1+LANGUAGE_PORTUGUESE_BRAZILIAN, "Brazilian Portuguese"); UpdateSetupButtons(); } diff --git a/src/ui/studio.cpp b/src/ui/studio.cpp index 6f2a1978..a7fc690d 100644 --- a/src/ui/studio.cpp +++ b/src/ui/studio.cpp @@ -133,7 +133,7 @@ bool CStudio::EventProcess(const Event &event) m_event->AddEvent(Event(EVENT_STUDIO_OK)); } - if ( event.type == EVENT_STUDIO_EDIT ) // text modifief? + if ( event.type == EVENT_STUDIO_EDIT ) // text modified? { ColorizeScript(edit); } @@ -627,7 +627,7 @@ void CStudio::StartEditScript(CScript *script, std::string name, Program* progra edit->SetState(STATE_SHADOW); edit->SetInsideScroll(false); //? if ( m_bRunning ) edit->SetEdit(false); - edit->SetFontType(Gfx::FONT_COURIER); + edit->SetFontType(Gfx::FONT_STUDIO); edit->SetFontStretch(1.0f); edit->SetDisplaySpec(true); edit->SetAutoIndent(m_engine->GetEditIndentMode()); @@ -639,7 +639,7 @@ void CStudio::StartEditScript(CScript *script, std::string name, Program* progra list = pw->CreateList(pos, dim, 1, EVENT_STUDIO_LIST, 1.2f); list->SetState(STATE_SHADOW); - list->SetFontType(Gfx::FONT_COURIER); + list->SetFontType(Gfx::FONT_STUDIO); list->SetSelectCap(false); list->SetFontSize(Gfx::FONT_SIZE_SMALL*0.85f); //? list->SetFontStretch(1.0f); diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index cc3261b8..78009ffc 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -22,6 +22,9 @@ #include #include +extern bool g_cbotTestSaveState; +bool g_cbotTestSaveState = false; + using namespace CBot; class CBotUT : public testing::Test @@ -197,6 +200,23 @@ private: return ss.str(); } + static void TestSaveAndRestore(CBotProgram* program) + { + std::stringstream sstr(""); + // save + if (!program->SaveState(sstr)) + throw CBotTestFail("CBotProgram::SaveState Failed"); + + if (!CBotClass::SaveStaticState(sstr)) + throw CBotTestFail("CBotClass::SaveStaticState Failed"); + // restore + if (!program->RestoreState(sstr)) + throw CBotTestFail("CBotProgram::RestoreState Failed"); + + if (!CBotClass::RestoreStaticState(sstr)) + throw CBotTestFail("CBotClass::RestoreStaticState Failed"); + } + protected: std::unique_ptr ExecuteTest(const std::string& code, CBotError expectedError = CBotNoErr) { @@ -231,7 +251,17 @@ protected: try { program->Start(test); - while (!program->Run()); + if (g_cbotTestSaveState) + { + while (!program->Run(nullptr, 0)) // save/restore at each step + { + TestSaveAndRestore(program.get()); + } + } + else + { + while (!program->Run(nullptr, 0)); // execute in step mode + } program->GetError(error, cursor1, cursor2); if (error != expectedRuntimeError) { @@ -575,6 +605,127 @@ TEST_F(CBotUT, VarImplicitCast) ); } +TEST_F(CBotUT, IntegerMathNearLimits_Issue993) +{ + ExecuteTest( + "extern void Test_Issue993() {\n" + " ASSERT(-2147483600 * 1 == -2147483600);\n" + " ASSERT( 2147483600 * 1 == 2147483600);\n" + " ASSERT( 2147483646 * 1 == 2147483646);\n" + " ASSERT( 2147483646 * -1 == -2147483646);\n" + " ASSERT( 2147483000 * -1 == -2147483000);\n" + " ASSERT( 2147483000 * 1 == 2147483000);\n" + "}\n" + ); +} + +TEST_F(CBotUT, BinaryLiterals) +{ + ExecuteTest( + "extern void TestBinaryLiterals() {\n" + " ASSERT( 8 == 0b00001000);\n" + " ASSERT( 12 == 0b00001100);\n" + " ASSERT( 16 == 0b00010000);\n" + " ASSERT( 24 == 0b00011000);\n" + " ASSERT( 32 == 0b00100000);\n" + " ASSERT( 48 == 0b00110000);\n" + " ASSERT( 64 == 0b01000000);\n" + " ASSERT( 96 == 0b01100000);\n" + " ASSERT(128 == 0b10000000);\n" + " ASSERT(192 == 0b11000000);\n" + " ASSERT(256 == 0b100000000);\n" + " ASSERT(384 == 0b110000000);\n" + " ASSERT(512 == 0b1000000000);\n" + "}\n" + ); +} + +TEST_F(CBotUT, TestSwitchCase) +{ + ExecuteTest( + "extern void Test_Switch_Case() {\n" + " int n = 0, c = 0;\n" + " for (int i = -9; i < 11; ++i) {\n" + " switch (i) {\n" + " case -9: n = -9; ++c; break;\n" + " case -8: n = -8; ++c; break;\n" + " case -7: n = -7; ++c; break;\n" + " case -6: n = -6; ++c; break;\n" + " case -5: n = -5; ++c; break;\n" + " case -4: n = -4; ++c; break;\n" + " case -3: n = -3; ++c; break;\n" + " case -2: n = -2; ++c; break;\n" + " case -1: n = -1; ++c; break;\n" + " case 0: n = 0; ++c; break;\n" + " case 1: n = 1; ++c; break;\n" + " case 2: n = 2; ++c; break;\n" + " case 3: n = 3; ++c; break;\n" + " case 4: n = 4; ++c; break;\n" + " case 5: n = 5; ++c; break;\n" + " case 6: n = 6; ++c; break;\n" + " case 7: n = 7; ++c; break;\n" + " case 8: n = 8; ++c; break;\n" + " case 9: n = 9; ++c; break;\n" + " default: n = 10; ++c; break;\n" + " }\n" + " ASSERT(n == i);\n" + " }\n" + " ASSERT(n == 10);\n" + " ASSERT(c == 20);\n" + "}\n" + "extern void Test_Case_With_Math() {\n" + " int n = 0, c = 0;\n" + " for (int i = -9; i < 11; ++i) {\n" + " switch (i * 10) {\n" + " case -9*10: n = -90; ++c; break;\n" + " case -8*10: n = -80; ++c; break;\n" + " case -7*10: n = -70; ++c; break;\n" + " case -6*10: n = -60; ++c; break;\n" + " case -5*10: n = -50; ++c; break;\n" + " case -4*10: n = -40; ++c; break;\n" + " case -3*10: n = -30; ++c; break;\n" + " case -2*10: n = -20; ++c; break;\n" + " case -1*10: n = -10; ++c; break;\n" + " case 0*10: n = 0; ++c; break;\n" + " case 1*10: n = 10; ++c; break;\n" + " case 2*10: n = 20; ++c; break;\n" + " case 3*10: n = 30; ++c; break;\n" + " case 4*10: n = 40; ++c; break;\n" + " case 5*10: n = 50; ++c; break;\n" + " case 6*10: n = 60; ++c; break;\n" + " case 7*10: n = 70; ++c; break;\n" + " case 8*10: n = 80; ++c; break;\n" + " case 9*10: n = 90; ++c; break;\n" + " default: n = 100; ++c; break;\n" + " }\n" + " ASSERT(n == i * 10);\n" + " }\n" + " ASSERT(n == 100);\n" + " ASSERT(c == 20);\n" + "}\n" + ); + + ExecuteTest( + "extern void Duplicate_Case() {\n" + " switch(0) {\n" + " case 1000:\n" + " case 10*100:\n" + " }\n" + "}\n", + CBotErrRedefCase + ); + + ExecuteTest( + "extern void Duplicate_Default() {\n" + " switch(0) {\n" + " default:\n" + " default:\n" + " }\n" + "}\n", + CBotErrRedefCase + ); +} + TEST_F(CBotUT, ToString) { ExecuteTest( @@ -1708,6 +1859,107 @@ TEST_F(CBotUT, StringFunctions) ); } +TEST_F(CBotUT, LiteralCharacters) +{ + ExecuteTest( + "extern void TestCharValue()\n" + "{\n" + " ASSERT('A' == 65);\n" + " ASSERT('B' == 66);\n" + " ASSERT('C' == 67);\n" + " ASSERT('\\a' == 0x07);\n" + " ASSERT('\\b' == 0x08);\n" + " ASSERT('\\t' == 0x09);\n" + " ASSERT('\\n' == 0x0A);\n" + " ASSERT('\\v' == 0x0B);\n" + " ASSERT('\\f' == 0x0C);\n" + " ASSERT('\\r' == 0x0D);\n" + " ASSERT('\\\"' == 0x22);\n" + " ASSERT('\\\'' == 0x27);\n" + " ASSERT('\\\\' == 0x5C);\n" + "}\n" + "extern void TestCharUnicodeEscape()\n" + "{\n" + " ASSERT('\\u0007' == '\\a');\n" + " ASSERT('\\u0008' == '\\b');\n" + " ASSERT('\\u0009' == '\\t');\n" + " ASSERT('\\u000A' == '\\n');\n" + " ASSERT('\\u000B' == '\\v');\n" + " ASSERT('\\u000C' == '\\f');\n" + " ASSERT('\\u000D' == '\\r');\n" + " ASSERT('\\u0022' == '\\\"');\n" + " ASSERT('\\u0027' == '\\\'');\n" + " ASSERT('\\u005C' == '\\\\');\n" + "}\n" + "extern void AssignCharToString_ToUTF_8()\n" + "{\n" + " string test = '\\u00A9';\n" + " test += '\\u00AE';\n" + " ASSERT(test == \"\\xC2\\xA9\\xC2\\xAE\");\n" + "}\n" + "extern void AddCharToString_ToUTF_8()\n" + "{\n" + " ASSERT(\"\" + 'A' + 'B' + 'C' == \"ABC\");\n" + " ASSERT(\"\" + '\\u00A9' == \"\\xC2\\xA9\");\n" + " ASSERT(\"\" + '\\u00AE' == \"\\xC2\\xAE\");\n" + " ASSERT(\"\" + '\\u262E' == \"\\xE2\\x98\\xAE\");\n" + " ASSERT(\"\" + '\\u262F' == \"\\xE2\\x98\\xAF\");\n" + " ASSERT(\"\" + '\\U0001F60E' == \"\\xF0\\x9F\\x98\\x8E\");\n" + " ASSERT(\"\" + '\\U0001F61C' == \"\\xF0\\x9F\\x98\\x9C\");\n" + " ASSERT(\"\" + '\\U0001F6E0' == \"\\xF0\\x9F\\x9B\\xA0\");\n" + " ASSERT(\"\" + '\\U0010FFFF' == \"\\xF4\\x8F\\xBF\\xBF\");\n" + "}\n" + ); + + ExecuteTest( + "extern void MissingEndQuote()\n" + "{\n" + " '\n" + "}\n", + CBotErrEndQuote + ); + + ExecuteTest( + "extern void MissingEndQuote()\n" + "{\n" + " 'a\n" + "}\n", + CBotErrEndQuote + ); + + ExecuteTest( + "extern void EmptyQuotes()\n" + "{\n" + " '';\n" + "}\n", + CBotErrCharEmpty + ); + + ExecuteTest( + "extern void UnknownEscapeSequence()\n" + "{\n" + " '\\p';\n" + "}\n", + CBotErrBadEscape + ); + + ExecuteTest( + "extern void MissingHexDigits()\n" + "{\n" + " '\\u';\n" + "}\n", + CBotErrHexDigits + ); + + ExecuteTest( + "extern void BadUnicodeCharacterName()\n" + "{\n" + " '\\U00110000';\n" + "}\n", + CBotErrUnicodeName + ); +} + TEST_F(CBotUT, TestNANParam_Issue642) { ExecuteTest( diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index c21fb600..cd606397 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -63,3 +63,9 @@ add_test( COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/colobot_ut WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) + +# GoogleTest isn't compatible with -Wsuggest-override -Werror: +# see https://github.com/google/googletest/issues/1063 +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) + target_compile_options(colobot_ut PRIVATE "-Wno-suggest-override") +endif() diff --git a/test/unit/main.cpp b/test/unit/main.cpp index 91d640de..8bed282c 100644 --- a/test/unit/main.cpp +++ b/test/unit/main.cpp @@ -21,11 +21,21 @@ #include +extern bool g_cbotTestSaveState; + int main(int argc, char* argv[]) { CLogger logger; ::testing::InitGoogleTest(&argc, argv); + // parse arguments not removed by InitGoogleTest + for (int i = 1; i < argc; ++i) + { + std::string arg(argv[i]); + if (arg == "--CBotUT_TestSaveState") + g_cbotTestSaveState = true; + } + return RUN_ALL_TESTS(); } diff --git a/tools/release.py b/tools/release.py index 6ab155af..3797fe90 100755 --- a/tools/release.py +++ b/tools/release.py @@ -25,6 +25,16 @@ import sys import subprocess import io +version_override = None +if len(sys.argv) > 1: + m = re.match(r'^(.*?)\.(.*?)\.(.*)$', sys.argv[1]) + if m is None: + print('\033[1;31m[!] Unable to parse version override argument\033[0m') + sys.exit(1) + version_override = (m.group(1), m.group(2), m.group(3)) + print('\033[1;34m[*] Version override: '+('%s.%s.%s' % version_override)+'\033[0m') + + try: git_root = subprocess.check_output(['git', 'rev-parse', '--show-toplevel']).strip() except subprocess.CalledProcessError: @@ -63,18 +73,25 @@ codename = None data = open('CMakeLists.txt', 'r').readlines() for i in range(len(data)): - m = re.match(r'^set\(COLOBOT_VERSION_(MAJOR|MINOR|REVISION)( +)([0-9]+)\)$', data[i]) + m = re.match(r'^set\(COLOBOT_VERSION_(MAJOR|MINOR|REVISION)( +)([0-9]+(\.[0-9]+)?)\)$', data[i]) if m: - x = int(m.group(3)) + x = m.group(3) if m.group(1) == 'MAJOR': + if version_override is not None: + x = version_override[0] major = x elif m.group(1) == 'MINOR': + if version_override is not None: + x = version_override[1] minor = x elif m.group(1) == 'REVISION': - # Increase revision number - x += 1 + if version_override is not None: + x = version_override[2] + else: + # Increase revision number + revision = str(int(x) + 1) revision = x - data[i] = 'set(COLOBOT_VERSION_'+m.group(1)+m.group(2)+str(x)+')\n' + data[i] = 'set(COLOBOT_VERSION_'+m.group(1)+m.group(2)+x+')\n' m = re.match(r'^(#?)set\(COLOBOT_VERSION_(UNRELEASED|RELEASE_CODENAME)( +)"(.+)"\)$', data[i]) if m: @@ -84,8 +101,8 @@ for i in range(len(data)): data[i] = ('#' if comment else '')+'set(COLOBOT_VERSION_'+m.group(2)+m.group(3)+'"'+m.group(4)+'")\n' subprocess.check_call(['git', 'checkout', 'master']) -version = '%d.%d.%d%s' % (major, minor, revision, codename) -version_human = '%s %d.%d.%d' % (codename.strip('-'), major, minor, revision) +version = '%s.%s.%s%s' % (major, minor, revision, codename) +version_human = '%s %s.%s.%s' % (codename.strip('-'), major, minor, revision) print('\033[1;32m[+] Building version '+version+'\033[0m') print('\033[1;34m[*] Merge data...\033[0m')