diff --git a/CMakeLists.txt b/CMakeLists.txt index e57e73a7..dd412fb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,9 +16,9 @@ set(COLOBOT_VERSION_MINOR 1) set(COLOBOT_VERSION_REVISION 7b) # Used on official releases -set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha") +#set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha") # Used on unreleased, development builds -#set(COLOBOT_VERSION_UNRELEASED "+alpha") +set(COLOBOT_VERSION_UNRELEASED "+alpha") # Append git characteristics to version if(DEFINED COLOBOT_VERSION_UNRELEASED) @@ -64,6 +64,7 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES "Windows") # Platform-dependent implementation of system.h set(SYSTEM_CPP_MODULE "system_windows.cpp") + set(SYSTEM_H_MODULE "system_windows.h") elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") message(STATUS "Build for Linux system") set(PLATFORM_WINDOWS 0) @@ -74,6 +75,7 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") # Platform-dependent implementation of system.h set(SYSTEM_CPP_MODULE "system_linux.cpp") + set(SYSTEM_H_MODULE "system_linux.h") elseif("${CMAKE_SYSTEM_NAME}" MATCHES "kFreeBSD" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "GNU") message(STATUS "Build for kFreeBSD system") set(PLATFORM_WINDOWS 0) @@ -84,6 +86,7 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "kFreeBSD" OR "${CMAKE_SYSTEM_NAME}" STREQ # Platform-dependent implementation of system.h set(SYSTEM_CPP_MODULE "system_other.cpp") + set(SYSTEM_H_MODULE "system_other.h") elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin") message(STATUS "Build for Mac OSX system") set(PLATFORM_WINDOWS 0) @@ -94,6 +97,9 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin") # 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) else() message(STATUS "Build for other system") set(PLATFORM_WINDOWS 0) @@ -104,6 +110,7 @@ else() # Platform-dependent implementation of system.h set(SYSTEM_CPP_MODULE "system_other.cpp") + set(SYSTEM_H_MODULE "system_other.h") endif() diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..926f4e2e --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,50 @@ +node('master') { + stage 'Pull changes' + checkout scm + + stage 'Build Windows' + sh 'mkdir -p build/windows' + dir('build/windows') { + sh ''' + cmake \ + -DCMAKE_INSTALL_PREFIX=/install \ + -DCMAKE_TOOLCHAIN_FILE=/opt/mxe/usr/i686-w64-mingw32.static/share/cmake/mxe-conf.cmake \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo -DDEV_BUILD=1 -DPORTABLE=1 -DTOOLS=1 -DTESTS=0 ../.. + make + rm -rf install + DESTDIR=. make install + ''' + } + sh 'rm -f windows-debug.zip' + zip zipFile: 'windows-debug.zip', archive: true, dir: 'build/windows/install' + + stage 'Build Linux' + sh 'mkdir -p build/linux' + dir('build/linux') { + sh ''' + cmake \ + -DCMAKE_INSTALL_PREFIX=/install -DCOLOBOT_INSTALL_BIN_DIR=/install -DCOLOBOT_INSTALL_LIB_DIR=/install -DCOLOBOT_INSTALL_DATA_DIR=/install/data -DCOLOBOT_INSTALL_I18N_DIR=/install/lang -DCMAKE_SKIP_INSTALL_RPATH=ON \ + -DBOOST_STATIC=ON -DGLEW_STATIC=ON -DGLEW_LIBRARY=/usr/lib64/libGLEW.a \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo -DDEV_BUILD=1 -DPORTABLE=1 -DTOOLS=1 -DTESTS=1 -DDESKTOP=0 ../.. + make + rm -rf install + DESTDIR=. make install + patchelf --set-rpath '.' install/colobot + ''' + } + sh 'rm -f linux-debug.zip' + zip zipFile: 'linux-debug.zip', archive: true, dir: 'build/linux/install' + + stage 'Doxygen' + dir('build/linux') { + sh 'make doc' + } + publishHTML target: [$class: 'HtmlPublisherTarget', reportName: 'Doxygen', reportDir: 'build/linux/doc/html', reportFiles: 'index.html'] + + stage 'Run tests' + dir('build/linux') { + sh './colobot_ut --gtest_output=xml:gtestresults.xml || true' + } + step([$class: 'XUnitBuilder', testTimeMargin: '3000', thresholdMode: 1, thresholds: [[$class: 'FailedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '0'], [$class: 'SkippedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '']], tools: [[$class: 'GoogleTestType', deleteOutputFiles: true, failIfNotNew: true, pattern: 'build/linux/gtestresults.xml', skipNoTestFiles: false, stopProcessingIfError: true]]]) +} + diff --git a/cmake/FindGettext.cmake b/cmake/FindGettext.cmake deleted file mode 100644 index ca1150e4..00000000 --- a/cmake/FindGettext.cmake +++ /dev/null @@ -1,218 +0,0 @@ -## -# Patched version of original CMake module -# Added variable GETTEXT_INSTALL_PREFIX to optionally override installation path of resulting translations -## - -# - Find GNU gettext tools -# This module looks for the GNU gettext tools. This module defines the -# following values: -# GETTEXT_MSGMERGE_EXECUTABLE: the full path to the msgmerge tool. -# GETTEXT_MSGFMT_EXECUTABLE: the full path to the msgfmt tool. -# GETTEXT_FOUND: True if gettext has been found. -# GETTEXT_VERSION_STRING: the version of gettext found (since CMake 2.8.8) -# -# Additionally it provides the following macros: -# GETTEXT_CREATE_TRANSLATIONS ( outputFile [ALL] file1 ... fileN ) -# This will create a target "translations" which will convert the -# given input po files into the binary output mo file. If the -# ALL option is used, the translations will also be created when -# building the default target. -# GETTEXT_PROCESS_POT( [ALL] [INSTALL_DESTINATION ] LANGUAGES ... ) -# Process the given pot file to mo files. -# If INSTALL_DESTINATION is given then automatically install rules will be created, -# the language subdirectory will be taken into account (by default use share/locale/). -# If ALL is specified, the pot file is processed when building the all traget. -# It creates a custom target "potfile". -# GETTEXT_PROCESS_PO_FILES( [ALL] [INSTALL_DESTINATION ] PO_FILES ... ) -# Process the given po files to mo files for the given language. -# If INSTALL_DESTINATION is given then automatically install rules will be created, -# the language subdirectory will be taken into account (by default use share/locale/). -# If ALL is specified, the po files are processed when building the all traget. -# It creates a custom target "pofiles". - -#============================================================================= -# Copyright 2007-2009 Kitware, Inc. -# Copyright 2007 Alexander Neundorf -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -find_program(GETTEXT_MSGMERGE_EXECUTABLE msgmerge) - -find_program(GETTEXT_MSGFMT_EXECUTABLE msgfmt) - -if(GETTEXT_MSGMERGE_EXECUTABLE) - execute_process(COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --version - OUTPUT_VARIABLE gettext_version - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (gettext_version MATCHES "^msgmerge \\(.*\\) [0-9]") - string(REGEX REPLACE "^msgmerge \\([^\\)]*\\) ([0-9\\.]+[^ \n]*).*" "\\1" GETTEXT_VERSION_STRING "${gettext_version}") - endif() - unset(gettext_version) -endif() - -set(GETTEXT_INSTALL_PREFIX share/locale) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Gettext - REQUIRED_VARS GETTEXT_MSGMERGE_EXECUTABLE GETTEXT_MSGFMT_EXECUTABLE - VERSION_VAR GETTEXT_VERSION_STRING) - -include(CMakeParseArguments) - -function(_GETTEXT_GET_UNIQUE_TARGET_NAME _name _unique_name) - set(propertyName "_GETTEXT_UNIQUE_COUNTER_${_name}") - get_property(currentCounter GLOBAL PROPERTY "${propertyName}") - if(NOT currentCounter) - set(currentCounter 1) - endif() - set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE) - math(EXPR currentCounter "${currentCounter} + 1") - set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} ) -endfunction() - -macro(GETTEXT_CREATE_TRANSLATIONS _potFile _firstPoFileArg) - # make it a real variable, so we can modify it here - set(_firstPoFile "${_firstPoFileArg}") - - set(_gmoFiles) - get_filename_component(_potName ${_potFile} NAME) - string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName}) - get_filename_component(_absPotFile ${_potFile} ABSOLUTE) - - set(_addToAll) - if(${_firstPoFile} STREQUAL "ALL") - set(_addToAll "ALL") - set(_firstPoFile) - endif() - - foreach (_currentPoFile ${_firstPoFile} ${ARGN}) - get_filename_component(_absFile ${_currentPoFile} ABSOLUTE) - get_filename_component(_abs_PATH ${_absFile} PATH) - get_filename_component(_lang ${_absFile} NAME_WE) - set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo) - - add_custom_command( - OUTPUT ${_gmoFile} - COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_absFile} ${_absPotFile} - COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_absFile} - DEPENDS ${_absPotFile} ${_absFile} - ) - - install(FILES ${_gmoFile} DESTINATION ${GETTEXT_INSTALL_PREFIX}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo) - set(_gmoFiles ${_gmoFiles} ${_gmoFile}) - - endforeach () - - if(NOT TARGET translations) - add_custom_target(translations) - endif() - - _GETTEXT_GET_UNIQUE_TARGET_NAME(translations uniqueTargetName) - - add_custom_target(${uniqueTargetName} ${_addToAll} DEPENDS ${_gmoFiles}) - - add_dependencies(translations ${uniqueTargetName}) - -endmacro() - - -function(GETTEXT_PROCESS_POT_FILE _potFile) - set(_gmoFiles) - set(_options ALL) - set(_oneValueArgs INSTALL_DESTINATION) - set(_multiValueArgs LANGUAGES) - - CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - - get_filename_component(_potName ${_potFile} NAME) - string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName}) - get_filename_component(_absPotFile ${_potFile} ABSOLUTE) - - foreach (_lang ${_parsedArguments_LANGUAGES}) - set(_poFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.po") - set(_gmoFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo") - - add_custom_command( - OUTPUT "${_poFile}" - COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_poFile} ${_absPotFile} - DEPENDS ${_absPotFile} - ) - - add_custom_command( - OUTPUT "${_gmoFile}" - COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_poFile} - DEPENDS ${_absPotFile} ${_poFile} - ) - - if(_parsedArguments_INSTALL_DESTINATION) - install(FILES ${_gmoFile} DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo) - endif() - list(APPEND _gmoFiles ${_gmoFile}) - endforeach () - - if(NOT TARGET potfiles) - add_custom_target(potfiles) - endif() - - _GETTEXT_GET_UNIQUE_TARGET_NAME( potfiles uniqueTargetName) - - if(_parsedArguments_ALL) - add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles}) - else() - add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles}) - endif() - - add_dependencies(potfiles ${uniqueTargetName}) - -endfunction() - - -function(GETTEXT_PROCESS_PO_FILES _lang) - set(_options ALL) - set(_oneValueArgs INSTALL_DESTINATION) - set(_multiValueArgs PO_FILES) - set(_gmoFiles) - - CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - - foreach(_current_PO_FILE ${_parsedArguments_PO_FILES}) - get_filename_component(_name ${_current_PO_FILE} NAME) - string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _basename ${_name}) - set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo) - add_custom_command(OUTPUT ${_gmoFile} - COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_current_PO_FILE} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - DEPENDS ${_current_PO_FILE} - ) - - if(_parsedArguments_INSTALL_DESTINATION) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES/ RENAME ${_basename}.mo) - endif() - list(APPEND _gmoFiles ${_gmoFile}) - endforeach() - - - if(NOT TARGET pofiles) - add_custom_target(pofiles) - endif() - - _GETTEXT_GET_UNIQUE_TARGET_NAME( pofiles uniqueTargetName) - - if(_parsedArguments_ALL) - add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles}) - else() - add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles}) - endif() - - add_dependencies(pofiles ${uniqueTargetName}) - -endfunction() diff --git a/data b/data index 90654ddf..0a55d94b 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 90654ddfedb385d90d10db702264aa3c69c6afad +Subproject commit 0a55d94b4e8a80b6873cf6c3f86d9438deed7c84 diff --git a/desktop/CMakeLists.txt b/desktop/CMakeLists.txt index 93113adc..dcca3b77 100644 --- a/desktop/CMakeLists.txt +++ b/desktop/CMakeLists.txt @@ -1,38 +1,56 @@ cmake_minimum_required(VERSION 2.8) -set(COLOBOT_ICON_FILE colobot.svg) +set(COLOBOT_ICON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/colobot.svg) # Render SVG icon in various sizes find_program(RSVG_CONVERT rsvg-convert) -if(RSVG_CONVERT AND (PLATFORM_GNU OR PLATFORM_MACOSX)) - add_custom_target(png-icons ALL) - foreach(PNGSIZE 512 256 128 48 32 16) +if(NOT RSVG_CONVERT) + message(WARNING "rsvg-convert not found; desktop icons will not be generated") +endif() + +find_program(XMLSTARLET xmlstarlet) +if(NOT XMLSTARLET) + message(WARNING "xmlstarlet not found; desktop icons will not be generated") +endif() + +if(RSVG_CONVERT AND XMLSTARLET AND (PLATFORM_GNU OR PLATFORM_MACOSX)) + add_custom_target(png-icons ALL DEPENDS ${COLOBOT_ICON_FILE}) + + foreach(PNG_SIZE 512 256 128 48 32 16) + # Using xmlstarlet to edit SVG file is a workaround for rsvg-convert bug (see: https://bugzilla.gnome.org/show_bug.cgi?id=762115) add_custom_command( - OUTPUT ${PNGSIZE}/colobot.png - COMMAND mkdir -p ${PNGSIZE} - COMMAND ${RSVG_CONVERT} -w ${PNGSIZE} -h ${PNGSIZE} ${CMAKE_CURRENT_SOURCE_DIR}/${COLOBOT_ICON_FILE} > ${PNGSIZE}/colobot.png + OUTPUT ${PNG_SIZE}/colobot.png + COMMAND mkdir -p ${PNG_SIZE} + COMMAND ${XMLSTARLET} ed -u /*/@width -v ${PNG_SIZE} -u /*/@height -v ${PNG_SIZE} ${COLOBOT_ICON_FILE} > ${PNG_SIZE}/colobot.svg + COMMAND ${RSVG_CONVERT} ${PNG_SIZE}/colobot.svg -o ${PNG_SIZE}/colobot.png ) - add_custom_target(png-icon-${PNGSIZE} ALL DEPENDS ${PNGSIZE}/colobot.png) - add_dependencies(png-icons png-icon-${PNGSIZE}) + add_custom_target(png-icon-${PNG_SIZE} ALL DEPENDS ${PNG_SIZE}/colobot.png) + add_dependencies(png-icons png-icon-${PNG_SIZE}) if(PLATFORM_GNU) install( - FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNGSIZE}/colobot.png - DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/${PNGSIZE}x${PNGSIZE}/apps/ + FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNG_SIZE}/colobot.png + DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/${PNG_SIZE}x${PNG_SIZE}/apps/ ) endif() # Prepare the ICNS icon generation - list(APPEND ICNS_SRCS "${PNGSIZE}/colobot.png") + list(APPEND ICNS_SRCS "${PNG_SIZE}/colobot.png") endforeach() - + # Pack icon for Mac OS - find_program(PNG2ICNS png2icns) - if(PNG2ICNS AND PLATFORM_MACOSX) - add_custom_command(OUTPUT Colobot.icns - COMMAND ${PNG2ICNS} Colobot.icns ${ICNS_SRCS} - DEPENDS png-icons - ) - add_custom_target(icns-icon ALL DEPENDS Colobot.icns) + if(PLATFORM_MACOSX) + find_program(PNG2ICNS png2icns) + if(NOT PNG2ICNS) + message(WARNING "png2icns not found; icns file will not be generated") + endif() + + if(PNG2ICNS) + add_custom_command(OUTPUT Colobot.icns + COMMAND ${PNG2ICNS} Colobot.icns ${ICNS_SRCS} + DEPENDS png-icons + ) + add_custom_target(icns-icon ALL DEPENDS Colobot.icns) + endif() endif() endif() @@ -54,12 +72,16 @@ if(PLATFORM_GNU) # Install Icon install( - FILES ${CMAKE_CURRENT_SOURCE_DIR}/${COLOBOT_ICON_FILE} + 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 @@ -70,6 +92,10 @@ if(PLATFORM_GNU) # Create manpage from pod-formatted file find_program(POD2MAN pod2man) + if(NOT POD2MAN) + message(WARNING "pod2man not found; manpage will not be generated") + endif() + if(POD2MAN) set(COLOBOT_MANPAGE_SECTION 6) diff --git a/desktop/colobot.ini b/desktop/colobot.ini index 27193df7..0cba2158 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++" diff --git a/desktop/colobot.svg b/desktop/colobot.svg index c514d6ba..cb3ca353 100644 --- a/desktop/colobot.svg +++ b/desktop/colobot.svg @@ -12,6 +12,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="32" height="32" + viewBox="0 0 32 32" id="svg2" version="1.1" inkscape:version="0.48.4 r9939" diff --git a/desktop/create_desktop_file.sh b/desktop/create_desktop_file.sh index 8f3d15b6..a41299f3 100755 --- a/desktop/create_desktop_file.sh +++ b/desktop/create_desktop_file.sh @@ -10,7 +10,7 @@ cat colobot.desktop.in linguas=$([ ! -d lang ] || ( cd lang ; ls)); -for type in Name GenericName Comment; do +for type in Name GenericName Comment Keywords; do egrep "^$type=" $fname | sed -e "s/^$type=\"\(.*\)\"$/$type=\1/g" for l in $linguas; do egrep "^$type=" lang/$l/$fname | sed -e "s/^$type=\"\(.*\)\"$/$type[$l]=\1/g" diff --git a/desktop/po/colobot-desktop.pot b/desktop/po/colobot-desktop.pot index 4fbbee34..52e6e1a8 100644 --- a/desktop/po/colobot-desktop.pot +++ b/desktop/po/colobot-desktop.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2016-03-25 19:24+0100\n" +"POT-Creation-Date: 2016-03-30 13:45+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -34,6 +34,12 @@ msgstr "" msgid "Colonize with bots" msgstr "" +#. type: Keywords= +#: colobot.ini:4 +#, no-wrap +msgid "robots;3d;space;astronaut;java;c++" +msgstr "" + #. type: =head1 #: colobot.pod:3 msgid "NAME" diff --git a/desktop/po/fr.po b/desktop/po/fr.po index 01b73ce3..5032271f 100644 --- a/desktop/po/fr.po +++ b/desktop/po/fr.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: colobot 0.1.7\n" -"POT-Creation-Date: 2016-03-25 19:24+0100\n" -"PO-Revision-Date: 2016-03-25 21:13+0100\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" "Language: fr\n" "MIME-Version: 1.0\n" @@ -34,6 +34,12 @@ msgstr "Apprentissage de la programmation par le jeu" msgid "Colonize with bots" 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++" + #. type: =head1 #: colobot.pod:3 msgid "NAME" diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt index 3550e7c3..6a5d7073 100644 --- a/po/CMakeLists.txt +++ b/po/CMakeLists.txt @@ -4,11 +4,14 @@ find_package(Gettext REQUIRED) set(_potFile colobot.pot) +# Extract translations + find_program(XGETTEXT_CMD xgettext) add_custom_command(OUTPUT ${_potFile} - COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/app/app.cpp --output=${_potFile} - COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/common/restext.cpp --output=${_potFile} --join-existing --keyword=TR --no-location + COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/app/app.cpp --output=${_potFile} --no-wrap + COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/common/restext.cpp --output=${_potFile} --no-wrap --join-existing --no-location --keyword=TR + COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/script/script.cpp --output=${_potFile} --no-wrap --join-existing --no-location COMMAND sed -i -e "s|^\\(\"POT-Creation-Date:\\).*$|\\1 DATE\\\\n\"|" ${_potFile} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -18,6 +21,30 @@ add_custom_command(OUTPUT ${_potFile} add_custom_target(update-pot DEPENDS ${_potFile}) +# Generate translations + file(GLOB _poFiles *.po) -set(GETTEXT_INSTALL_PREFIX ${COLOBOT_INSTALL_I18N_DIR}) -gettext_create_translations(${_potFile} ALL ${_poFiles}) + +set(_gmoFiles) +get_filename_component(_potName ${_potFile} NAME) +string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName}) +get_filename_component(_absPotFile ${_potFile} ABSOLUTE) + +foreach (_currentPoFile ${_poFiles}) + get_filename_component(_absFile ${_currentPoFile} ABSOLUTE) + get_filename_component(_abs_PATH ${_absFile} PATH) + get_filename_component(_lang ${_absFile} NAME_WE) + set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo) + + add_custom_command( + OUTPUT ${_gmoFile} + COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --no-wrap --update --backup=none -s ${_absFile} ${_absPotFile} + COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} --check-format -o ${_gmoFile} ${_absFile} + DEPENDS ${_absPotFile} ${_absFile} + ) + + install(FILES ${_gmoFile} DESTINATION ${COLOBOT_INSTALL_I18N_DIR}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo) + set(_gmoFiles ${_gmoFiles} ${_gmoFile}) +endforeach() + +add_custom_target(translations ALL DEPENDS ${_gmoFiles}) diff --git a/po/colobot.pot b/po/colobot.pot index 1c4e61ef..91bfcdbd 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -16,6 +16,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" msgid "Colobot rules!" msgstr "" @@ -83,34 +84,34 @@ msgstr "" msgid "Load a saved mission" msgstr "" -msgid " Chapters:" +msgid "Chapters:" msgstr "" -msgid " Planets:" +msgid "Planets:" msgstr "" -msgid " Custom levels:" +msgid "Custom levels:" msgstr "" -msgid " Levels in this chapter:" +msgid "Levels in this chapter:" msgstr "" -msgid " Exercises in the chapter:" +msgid "Exercises in the chapter:" msgstr "" -msgid " Challenges in the chapter:" +msgid "Challenges in the chapter:" msgstr "" -msgid " Missions on this planet:" +msgid "Missions on this planet:" msgstr "" -msgid " Free game on this planet:" +msgid "Free game on this planet:" msgstr "" -msgid " Summary:" +msgid "Summary:" msgstr "" -msgid " Resolution:" +msgid "Resolution:" msgstr "" msgid "1) First click on the key you want to redefine." @@ -144,7 +145,7 @@ msgid "Do you really want to destroy the selected building?" msgstr "" #, c-format -msgid "Do you want to delete %s's saved games? " +msgid "Do you want to delete %s's saved games?" msgstr "" msgid "Yes" @@ -298,7 +299,7 @@ msgstr "" msgid "Restart\\Restart the mission from the beginning" msgstr "" -msgid "Save\\Save the current mission " +msgid "Save\\Save the current mission" msgstr "" msgid "Load\\Load a saved mission" @@ -358,6 +359,9 @@ msgstr "" msgid "Render distance\\Maximum visibility" msgstr "" +msgid "Pause blur\\Blur the background on the pause screen" +msgstr "" + msgid "Particles in the interface\\Steam clouds and sparks in the interface" msgstr "" @@ -370,9 +374,7 @@ msgstr "" msgid "Film sequences\\Films before and after the missions" msgstr "" -msgid "" -"Camera border scrolling\\Scrolling when the mouse touches right or left " -"border" +msgid "Camera border scrolling\\Scrolling when the mouse touches right or left border" msgstr "" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" @@ -459,8 +461,19 @@ msgstr "" msgid "Previous object\\Selects the previous object" msgstr "" -msgid "" -"Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" +msgid "Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" +msgstr "" + +msgid "Camera left\\Turns the camera left" +msgstr "" + +msgid "Camera right\\Turns the camera right" +msgstr "" + +msgid "Camera up\\Turns the camera up" +msgstr "" + +msgid "Camera down\\Turns the camera down" msgstr "" msgid "Camera closer\\Moves the camera forward" @@ -469,6 +482,9 @@ msgstr "" msgid "Camera back\\Moves the camera backward" msgstr "" +msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)" +msgstr "" + msgid "Next object\\Selects the next object" msgstr "" @@ -508,12 +524,6 @@ msgstr "" msgid "Speed 6.0x\\Sextuple speed" msgstr "" -msgid "Camera up\\Increase camera angle while visiting message origin" -msgstr "" - -msgid "Camera down\\Decrease camera angle while visiting message origin" -msgstr "" - msgid "Pause\\Pause the game without opening menu" msgstr "" @@ -523,7 +533,7 @@ msgstr "" msgid "Sound effects:\\Volume of engines, voice, shooting, etc." msgstr "" -msgid "Background sound :\\Volume of audio tracks" +msgid "Background sound:\\Volume of audio tracks" msgstr "" msgid "Lowest\\Minimum graphic quality (highest frame rate)" @@ -541,8 +551,7 @@ msgstr "" msgid "Normal\\Normal sound volume" msgstr "" -msgid "" -"Access to solution\\Shows the solution (detailed instructions for missions)" +msgid "Access to solution\\Shows the solution (detailed instructions for missions)" msgstr "" msgid "Invert\\Invert values on this axis" @@ -611,13 +620,13 @@ msgstr "" msgid "\\Face 1" msgstr "" -msgid "\\Face 4" +msgid "\\Face 2" msgstr "" msgid "\\Face 3" msgstr "" -msgid "\\Face 2" +msgid "\\Face 4" msgstr "" msgid "\\No eyeglasses" @@ -920,18 +929,6 @@ msgstr "" msgid "Camera (\\key camera;)" msgstr "" -msgid "Camera to left" -msgstr "" - -msgid "Camera to right" -msgstr "" - -msgid "Camera nearest" -msgstr "" - -msgid "Camera awayest" -msgstr "" - msgid "Help about selected object" msgstr "" @@ -1043,22 +1040,22 @@ msgstr "" msgid "Clone program" msgstr "" -msgid "Open (Ctrl+o)" +msgid "Open (Ctrl+O)" msgstr "" -msgid "Save (Ctrl+s)" +msgid "Save (Ctrl+S)" msgstr "" -msgid "Undo (Ctrl+z)" +msgid "Undo (Ctrl+Z)" msgstr "" -msgid "Cut (Ctrl+x)" +msgid "Cut (Ctrl+X)" msgstr "" -msgid "Copy (Ctrl+c)" +msgid "Copy (Ctrl+C)" msgstr "" -msgid "Paste (Ctrl+v)" +msgid "Paste (Ctrl+V)" msgstr "" msgid "Font size" @@ -1067,7 +1064,7 @@ msgstr "" msgid "Instructions (\\key help;)" msgstr "" -msgid "Programming help (\\key prog;)" +msgid "Programming help (\\key prog;)" msgstr "" msgid "Compile" @@ -1448,10 +1445,10 @@ msgstr "" msgid "Transforms only titanium" msgstr "" -msgid "Doors blocked by a robot or another object " +msgid "Doors blocked by a robot or another object" msgstr "" -msgid "You must get on the spaceship to take off " +msgid "You must get on the spaceship to take off" msgstr "" msgid "Nothing to analyze" @@ -1505,8 +1502,7 @@ msgstr "" msgid "Inappropriate object" msgstr "" -msgid "" -"The mission is not accomplished yet (press \\key help; for more details)" +msgid "The mission is not accomplished yet (press \\key help; for more details)" msgstr "" msgid "Bot destroyed" @@ -1518,13 +1514,6 @@ msgstr "" msgid "Unable to control enemy objects" msgstr "" -#, c-format -msgid "\"%s\" missing in this exercise" -msgstr "" - -msgid "Do not use in this exercise" -msgstr "" - msgid "Inappropriate bot" msgstr "" @@ -1537,7 +1526,7 @@ msgstr "" msgid "Research program completed" msgstr "" -msgid "Plans for tracked robots available " +msgid "Plans for tracked robots available" msgstr "" msgid "You can fly with the keys (\\key gup;) and (\\key gdown;)" @@ -1612,7 +1601,7 @@ msgstr "" msgid "Opening bracket missing" msgstr "" -msgid "Closing bracket missing " +msgid "Closing bracket missing" msgstr "" msgid "The expression must return a boolean value" @@ -1636,10 +1625,10 @@ msgstr "" msgid "End of block missing" msgstr "" -msgid "Instruction \"else\" without corresponding \"if\" " +msgid "Instruction \"else\" without corresponding \"if\"" msgstr "" -msgid "Opening brace missing " +msgid "Opening brace missing" msgstr "" msgid "Wrong type for the assignment" @@ -1648,7 +1637,7 @@ msgstr "" msgid "A variable can not be declared twice" msgstr "" -msgid "The types of the two operands are incompatible " +msgid "The types of the two operands are incompatible" msgstr "" msgid "Unknown function" @@ -1693,7 +1682,7 @@ msgstr "" msgid "Function already exists" msgstr "" -msgid "Parameters missing " +msgid "Parameters missing" msgstr "" msgid "No function with this name accepts this kind of parameter" @@ -1738,6 +1727,9 @@ msgstr "" msgid "Public required" msgstr "" +msgid "Expression expected after =" +msgstr "" + msgid "Dividing by zero" msgstr "" @@ -1747,7 +1739,7 @@ msgstr "" msgid "Negative value rejected by \"throw\"" msgstr "" -msgid "The function returned no value " +msgid "The function returned no value" msgstr "" msgid "No function running" @@ -1788,3 +1780,19 @@ msgstr "" msgid "Button %1" msgstr "" + +#, 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] "" +msgstr[1] "" + +#, c-format +msgid "You cannot use \"%s\" in this exercise (used: %d)" +msgstr "" + +#, 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] "" +msgstr[1] "" diff --git a/po/de.po b/po/de.po index d008dfa3..be31b511 100644 --- a/po/de.po +++ b/po/de.po @@ -20,38 +20,6 @@ msgstr "" "X-Source-Language: en_US\n" "X-POOTLE-MTIME: 1406536037.000000\n" -msgid " Challenges in the chapter:" -msgstr " Liste der Challenges des Kapitels:" - -msgid " Chapters:" -msgstr " Liste der Kapitel:" - -#, fuzzy -msgid " Custom levels:" -msgstr " Userlevels:" - -msgid " Exercises in the chapter:" -msgstr " Liste der Übungen des Kapitels:" - -msgid " Free game on this planet:" -msgstr " Liste der freien Levels des Planeten:" - -#, fuzzy -msgid " Levels in this chapter:" -msgstr " Liste der Übungen des Kapitels:" - -msgid " Missions on this planet:" -msgstr " Liste der Missionen des Planeten:" - -msgid " Planets:" -msgstr " Liste der Planeten:" - -msgid " Resolution:" -msgstr " Auflösung:" - -msgid " Summary:" -msgstr " Zusammenfassung:" - msgid " or " msgstr " oder " @@ -61,10 +29,6 @@ msgstr "Es fehlt eine offene eckige Klammer \" [ \"" msgid "\" ] \" missing" msgstr "Es fehlt eine geschlossene eckige Klammer \" ] \"" -#, c-format -msgid "\"%s\" missing in this exercise" -msgstr "Es fehlt \"%s\" in Ihrem Programm" - msgid "..behind" msgstr "..hinten" @@ -90,9 +54,7 @@ msgid "<<< Well done; mission accomplished >>>" msgstr "<<< Bravo, Mission vollendet >>>" msgid "A label must be followed by \"for\"; \"while\"; \"do\" or \"switch\"" -msgstr "" -"Ein Label kann nur vor den Anweisungen \"for\", \"while\", \"do\" oder " -"\"switch\" vorkommen" +msgstr "Ein Label kann nur vor den Anweisungen \"for\", \"while\", \"do\" oder \"switch\" vorkommen" msgid "A variable can not be declared twice" msgstr "Eine Variable wird zum zweiten Mal deklariert" @@ -103,13 +65,11 @@ msgstr "Abbrechen\\Mission abbrechen" msgid "Access beyond array limit" msgstr "Zugriff im Array außerhalb der Grenzen" -msgid "" -"Access to solution\\Shows the solution (detailed instructions for missions)" +msgid "Access to solution\\Shows the solution (detailed instructions for missions)" msgstr "Zeigt die Lösung\\Zeigt nach 3mal Scheitern die Lösung" msgid "Access to solutions\\Show program \"4: Solution\" in the exercises" -msgstr "" -"Lösung zugänglich\\Die Lösung ist im Programmslot \"4: Lösung\" zugänglich" +msgstr "Lösung zugänglich\\Die Lösung ist im Programmslot \"4: Lösung\" zugänglich" msgid "Add new program" msgstr "" @@ -123,6 +83,9 @@ msgstr "Insektenkönigin tödlich verwundet" msgid "Already carrying something" msgstr "Trägt schon etwas" +msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)" +msgstr "" + msgid "Analysis already performed" msgstr "Analyse schon durchgeführt" @@ -172,7 +135,7 @@ msgid "Back" msgstr "Vorherg. Seite" #, fuzzy -msgid "Background sound :\\Volume of audio tracks" +msgid "Background sound:\\Volume of audio tracks" msgstr "Geräuschkulisse:\\Lautstärke der Soundtracks der CD" msgid "Backward (\\key down;)" @@ -325,36 +288,31 @@ msgstr "Die aufgerufene Funktion existiert nicht" msgid "Camera (\\key camera;)" msgstr "Kamera (\\key camera;)" -msgid "Camera awayest" -msgstr "Kamera weiter weg" - msgid "Camera back\\Moves the camera backward" msgstr "Kamera weiter\\Bewegung der Kamera rückwärts" #, fuzzy -msgid "" -"Camera border scrolling\\Scrolling when the mouse touches right or left " -"border" -msgstr "" -"Kameradrehung mit der Maus\\Die Kamera dreht wenn die Maus den Rand erreicht" +msgid "Camera border scrolling\\Scrolling when the mouse touches right or left border" +msgstr "Kameradrehung mit der Maus\\Die Kamera dreht wenn die Maus den Rand erreicht" msgid "Camera closer\\Moves the camera forward" msgstr "Kamera näher\\Bewegung der Kamera vorwärts" -msgid "Camera down\\Decrease camera angle while visiting message origin" -msgstr "" +#, fuzzy +msgid "Camera down\\Turns the camera down" +msgstr "Kamera näher\\Bewegung der Kamera vorwärts" -msgid "Camera nearest" -msgstr "Kamera näher" +#, fuzzy +msgid "Camera left\\Turns the camera left" +msgstr "Kamera näher\\Bewegung der Kamera vorwärts" -msgid "Camera to left" -msgstr "Kamera links" +#, fuzzy +msgid "Camera right\\Turns the camera right" +msgstr "Drehung nach rechts\\Steuer rechts" -msgid "Camera to right" -msgstr "Kamera rechts" - -msgid "Camera up\\Increase camera angle while visiting message origin" -msgstr "" +#, fuzzy +msgid "Camera up\\Turns the camera up" +msgstr "Kamera (\\key camera;)" msgid "Can not produce not researched object" msgstr "Das erforschte Objekt kann nicht produziert werden" @@ -374,6 +332,9 @@ msgstr "Abbrechen\\Editor schließen" msgid "Challenges" msgstr "Challenges" +msgid "Challenges in the chapter:" +msgstr "Liste der Challenges des Kapitels:" + msgid "Challenges\\Programming challenges" msgstr "Challenges\\Herausforderungen" @@ -383,6 +344,9 @@ msgstr "Andere Kamera\\Sichtpunkt einstellen" msgid "Change player\\Change player" msgstr "Anderer Spieler\\Spielername ändern" +msgid "Chapters:" +msgstr "Liste der Kapitel:" + msgid "Cheat console\\Show cheat console" msgstr "" @@ -402,7 +366,7 @@ msgstr "Gewähltes Programm bearbeiten" msgid "Close" msgstr "Schließen" -msgid "Closing bracket missing " +msgid "Closing bracket missing" msgstr "Es fehlt eine geschlossene Klammer \")\"" msgid "Code battles" @@ -414,9 +378,8 @@ msgstr "" msgid "Colobot rules!" msgstr "Colobot ist wunderbar!" -#, fuzzy msgid "Colobot: Gold Edition" -msgstr "COLOBOT: Gold Edition" +msgstr "Colobot: Gold Edition" msgid "Command line" msgstr "Befehleingabe" @@ -442,20 +405,24 @@ msgstr "Konverter Erz-Titan" msgid "Copy" msgstr "Kopieren" -msgid "Copy (Ctrl+c)" -msgstr "Kopieren (Ctrl+c)" +msgid "Copy (Ctrl+C)" +msgstr "Kopieren (Ctrl+C)" msgid "Current mission saved" msgstr "Mission gespeichert" +#, fuzzy +msgid "Custom levels:" +msgstr "Userlevels:" + msgid "Custom levels\\Levels from mods created by the users" msgstr "" msgid "Customize your appearance" msgstr "Aussehen einstellen" -msgid "Cut (Ctrl+x)" -msgstr "Ausschneiden (Ctrl+x)" +msgid "Cut (Ctrl+X)" +msgstr "Ausschneiden (Ctrl+X)" msgid "Defense tower" msgstr "Geschützturm" @@ -491,17 +458,14 @@ msgstr "Bildschirm\\Driver und Bildschirmauflösung" msgid "Dividing by zero" msgstr "Teilung durch Null" -msgid "Do not use in this exercise" -msgstr "In dieser Übung verboten" - msgid "Do you really want to destroy the selected building?" msgstr "Wollen Sie das angewählte Gebäude wirklich zerstören ?" #, c-format -msgid "Do you want to delete %s's saved games? " +msgid "Do you want to delete %s's saved games?" msgstr "Wollen Sie die gespeicherten Missionen von %s löschen ?" -msgid "Doors blocked by a robot or another object " +msgid "Doors blocked by a robot or another object" msgstr "Die Türen werden von einem Gegenstand blockiert" msgid "Down (\\key gdown;)" @@ -549,6 +513,9 @@ msgstr "Gewähltes Programm ausführen" msgid "Execute/stop" msgstr "Start/Stop" +msgid "Exercises in the chapter:" +msgstr "Liste der Übungen des Kapitels:" + msgid "Exercises\\Programming exercises" msgstr "Programmieren\\Programmierübungen" @@ -558,6 +525,9 @@ msgstr "Explodieren (\\key action;)" msgid "Explosive" msgstr "Sprengstoff" +msgid "Expression expected after =" +msgstr "" + msgid "Extend shield (\\key action;)" msgstr "Schutzschild ausfahren (\\key action;)" @@ -628,6 +598,9 @@ msgstr "Markierung für vergrabenen Schlüssel D" msgid "Free game" msgstr "Freestyle" +msgid "Free game on this planet:" +msgstr "Liste der freien Levels des Planeten:" + msgid "Free game\\Free game without a specific goal" msgstr "Freestyle\\Freies Spielen ohne vorgegebenes Ziel" @@ -743,7 +716,7 @@ msgstr "Es fehlt eine Anweisung \"case\"" msgid "Instruction \"case\" outside a block \"switch\"" msgstr "Anweisung \"case\" ohne vorhergehende Anweisung \"switch\"" -msgid "Instruction \"else\" without corresponding \"if\" " +msgid "Instruction \"else\" without corresponding \"if\"" msgstr "Anweisung \"else\" ohne vorhergehende Anweisung \"if\"" msgid "Instructions (\\key help;)" @@ -803,6 +776,9 @@ msgstr "Shooter" msgid "Legged sniffer" msgstr "Schnüffler" +msgid "Levels in this chapter:" +msgstr "Liste der Übungen des Kapitels:" + msgid "Lightning conductor" msgstr "Blitzableiter" @@ -862,6 +838,9 @@ msgstr "Name der Mission" msgid "Missions" msgstr "Missionen" +msgid "Missions on this planet:" +msgstr "Liste der Missionen des Planeten:" + msgid "Missions\\Select mission" msgstr "Missionen\\Aufbruch ins Weltall" @@ -1020,10 +999,10 @@ msgstr "Ein Schritt" msgid "Open" msgstr "Öffnen" -msgid "Open (Ctrl+o)" -msgstr "Öffnen (Ctrl+o)" +msgid "Open (Ctrl+O)" +msgstr "Öffnen (Ctrl+O)" -msgid "Opening brace missing " +msgid "Opening brace missing" msgstr "Es fehlt eine offene geschweifte Klammer\"{\"" msgid "Opening bracket missing" @@ -1047,14 +1026,17 @@ msgstr "Ort der Meldung\\Zeigt den Ort, von dem die letzte Meldung stammt" msgid "Original game developed by:" msgstr "Ursprünglichen Spiel entwickelt von:" -msgid "Parameters missing " +msgid "Parameters missing" msgstr "Nicht genug Parameter" msgid "Particles in the interface\\Steam clouds and sparks in the interface" msgstr "Partikel in den Menüs\\Funken und Sterne in den Menüs" -msgid "Paste (Ctrl+v)" -msgstr "Einfügen (Ctrl+v)" +msgid "Paste (Ctrl+V)" +msgstr "Einfügen (Ctrl+V)" + +msgid "Pause blur\\Blur the background on the pause screen" +msgstr "" msgid "Pause in background\\Pause the game when the window is unfocused" msgstr "" @@ -1074,6 +1056,9 @@ msgstr "Ansicht der Mission" msgid "Place occupied" msgstr "Stelle schon besetzt" +msgid "Planets:" +msgstr "Liste der Planeten:" + msgid "Plans for defense tower available" msgstr "Errichtung eines Geschützturms möglich" @@ -1092,7 +1077,7 @@ msgstr "Herstellung eines Shooters möglich" msgid "Plans for thumper available" msgstr "Herstellung eines Stampfers möglich" -msgid "Plans for tracked robots available " +msgid "Plans for tracked robots available" msgstr "Herstellung eines Roboters mit Kettenantrieb möglich" msgid "Plant a flag" @@ -1165,7 +1150,7 @@ msgstr "Programmieren" msgid "Programming help" msgstr "Hilfe über Programmieren" -msgid "Programming help (\\key prog;)" +msgid "Programming help (\\key prog;)" msgstr "Hilfe über Programmieren (\\key prog;)" msgid "Programming help\\Gives more detailed help with programming" @@ -1246,6 +1231,9 @@ msgstr "Dieses Wort ist reserviert" msgid "Resolution" msgstr "Auflösung" +msgid "Resolution:" +msgstr "Auflösung:" + msgid "Resources" msgstr "" @@ -1306,13 +1294,13 @@ msgstr "Satellitenbericht" msgid "Save" msgstr "Speichern" -msgid "Save (Ctrl+s)" -msgstr "Speichern (Ctrl+s)" +msgid "Save (Ctrl+S)" +msgstr "Speichern (Ctrl+S)" msgid "Save the current mission" msgstr "Aktuelle Mission speichern" -msgid "Save\\Save the current mission " +msgid "Save\\Save the current mission" msgstr "Speichern\\Aktuelle Mission speichern" msgid "Save\\Saves the current mission" @@ -1425,8 +1413,7 @@ msgstr "Spinne tödlich verwundet" msgid "Stack overflow" msgstr "Stack overflow" -msgid "" -"Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" +msgid "Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" msgstr "Standardhandlung\\Führt die Standardhandlung des Roboters aus" msgid "Standard controls\\Standard key functions" @@ -1460,6 +1447,9 @@ msgstr "Farbe des Anzugs:" msgid "Suit\\Astronaut suit" msgstr "Anzug\\Raumfahrtanzug" +msgid "Summary:" +msgstr "Zusammenfassung:" + msgid "Survival kit" msgstr "Überlebenskit" @@ -1487,16 +1477,13 @@ msgstr "" msgid "The expression must return a boolean value" msgstr "Der Ausdruck muss einen boolschen Wert ergeben" -msgid "The function returned no value " +msgid "The function returned no value" msgstr "Die Funktion hat kein Ergebnis zurückgegeben" -msgid "" -"The mission is not accomplished yet (press \\key help; for more details)" -msgstr "" -"Mission noch nicht beendet (Drücken Sie auf \\key help; für weitere " -"Informationen)" +msgid "The mission is not accomplished yet (press \\key help; for more details)" +msgstr "Mission noch nicht beendet (Drücken Sie auf \\key help; für weitere Informationen)" -msgid "The types of the two operands are incompatible " +msgid "The types of the two operands are incompatible" msgstr "Die zwei Operanden sind nicht kompatibel" msgid "This class already exists" @@ -1601,8 +1588,8 @@ msgstr "Hier muss ein Variablentyp stehen" msgid "Unable to control enemy objects" msgstr "" -msgid "Undo (Ctrl+z)" -msgstr "Widerrufen (Ctrl+z)" +msgid "Undo (Ctrl+Z)" +msgstr "Widerrufen (Ctrl+Z)" msgid "Unit" msgstr "Einheit" @@ -1712,10 +1699,26 @@ msgstr "Sie können keinen radioaktiven Gegenstand tragen" msgid "You can not carry an object under water" msgstr "Sie können unter Wasser nichts tragen" +#, fuzzy, c-format +msgid "You cannot use \"%s\" in this exercise (used: %d)" +msgstr "In dieser Übung verboten" + msgid "You found a usable object" msgstr "Sie haben ein brauchbares Objekt gefunden" -msgid "You must get on the spaceship to take off " +#, fuzzy, 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] "In dieser Übung verboten" +msgstr[1] "In dieser Übung verboten" + +#, fuzzy, 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] "In dieser Übung verboten" +msgstr[1] "In dieser Übung verboten" + +msgid "You must get on the spaceship to take off" msgstr "Gehen Sie an Bord, bevor Sie abheben" msgid "Zoom mini-map" @@ -1815,11 +1818,10 @@ msgid "\\Yellow flags" msgstr "\\Gelbe Fahne" msgid "colobot.info" -msgstr "" +msgstr "colobot.info" -#, fuzzy msgid "epsitec.com" -msgstr "www.epsitec.com" +msgstr "epsitec.com" #~ msgid " " #~ msgstr " " @@ -1830,6 +1832,9 @@ msgstr "www.epsitec.com" #~ msgid " Missions on this level:" #~ msgstr " Missionen des Userlevels:" +#~ msgid "\"%s\" missing in this exercise" +#~ msgstr "Es fehlt \"%s\" in Ihrem Programm" + #~ msgid "3D sound\\3D positioning of the sound" #~ msgstr "3D-Geräusche\\Orten der Geräusche im Raum" @@ -1839,6 +1844,18 @@ msgstr "www.epsitec.com" #~ msgid "COLOBOT" #~ msgstr "COLOBOT" +#~ msgid "Camera awayest" +#~ msgstr "Kamera weiter weg" + +#~ msgid "Camera nearest" +#~ msgstr "Kamera näher" + +#~ msgid "Camera to left" +#~ msgstr "Kamera links" + +#~ msgid "Camera to right" +#~ msgstr "Kamera rechts" + #~ msgid "Can not create this; there are too many objects" #~ msgstr "Kein neues Objekt kann erstellt werden (zu viele vorhanden)" @@ -1921,9 +1938,7 @@ msgstr "www.epsitec.com" #~ msgid "Textures\\Quality of textures " #~ msgstr "Qualität der Texturen\\Qualität der Anzeige" -#~ msgid "" -#~ "The list is only available if a \\l;radar station\\u object\\radar; is " -#~ "working.\n" +#~ msgid "The list is only available if a \\l;radar station\\u object\\radar; is working.\n" #~ msgstr "Die Liste ist ohne \\l;Radar\\u object\\radar; nicht verfügbar.\n" #~ msgid "Use a joystick\\Joystick or keyboard" diff --git a/po/fr.po b/po/fr.po index 5db35d47..996fc6fb 100644 --- a/po/fr.po +++ b/po/fr.po @@ -15,36 +15,6 @@ msgstr "" "X-Language: fr_FR\n" "X-Source-Language: en_US\n" -msgid " Challenges in the chapter:" -msgstr " Liste des défis du chapitre :" - -msgid " Chapters:" -msgstr " Liste des chapitres :" - -msgid " Custom levels:" -msgstr " Niveaux spéciaux :" - -msgid " Exercises in the chapter:" -msgstr " Liste des exercices du chapitre :" - -msgid " Free game on this planet:" -msgstr " Liste des jeux libres du chapitre :" - -msgid " Levels in this chapter:" -msgstr " Liste des niveaux du chapitre :" - -msgid " Missions on this planet:" -msgstr " Liste des missions du chapitre :" - -msgid " Planets:" -msgstr " Liste des planètes :" - -msgid " Resolution:" -msgstr " Résolutions :" - -msgid " Summary:" -msgstr " Résumé :" - msgid " or " msgstr " ou " @@ -54,10 +24,6 @@ msgstr "\" [ \" attendu" msgid "\" ] \" missing" msgstr "\" ] \" attendu" -#, c-format -msgid "\"%s\" missing in this exercise" -msgstr "Il manque \"%s\" dans le programme" - msgid "..behind" msgstr "..derrière" @@ -83,9 +49,7 @@ msgid "<<< Well done; mission accomplished >>>" msgstr "<<< Bravo; mission terminée >>>" msgid "A label must be followed by \"for\"; \"while\"; \"do\" or \"switch\"" -msgstr "" -"Un label ne peut se placer que devant un \"for\"; un \"while\"; un \"do\" ou " -"un \"switch\"" +msgstr "Un label ne peut se placer que devant un \"for\"; un \"while\"; un \"do\" ou un \"switch\"" msgid "A variable can not be declared twice" msgstr "Redéfinition d'une variable" @@ -96,8 +60,7 @@ msgstr "Abandonner\\Abandonner la mission en cours" msgid "Access beyond array limit" msgstr "Accès hors du tableau" -msgid "" -"Access to solution\\Shows the solution (detailed instructions for missions)" +msgid "Access to solution\\Shows the solution (detailed instructions for missions)" msgstr "Accès à la solution\\Donne la solution" msgid "Access to solutions\\Show program \"4: Solution\" in the exercises" @@ -115,6 +78,9 @@ msgstr "Pondeuse mortellement touchée" msgid "Already carrying something" msgstr "Porte déjà quelque chose" +msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)" +msgstr "" + msgid "Analysis already performed" msgstr "Analyse déjà effectuée" @@ -152,9 +118,7 @@ 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 "" -"Intervalle d'auto-sauvegarde\\À quels intervalles les parties vont-t-elles " -"êtres sauvegardées automatiquement" +msgstr "Intervalle d'auto-sauvegarde\\À quels intervalles 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" @@ -165,7 +129,7 @@ msgstr "Auto-sauvegarde\\Active l'auto-sauvegarde" msgid "Back" msgstr "Page précédente" -msgid "Background sound :\\Volume of audio tracks" +msgid "Background sound:\\Volume of audio tracks" msgstr "Fond sonore :\\Volume des pistes audio" msgid "Backward (\\key down;)" @@ -318,40 +282,30 @@ msgstr "Appel d'une fonction inexistante" msgid "Camera (\\key camera;)" msgstr "Caméra (\\key camera;)" -msgid "Camera awayest" -msgstr "Caméra plus loin" - msgid "Camera back\\Moves the camera backward" msgstr "Caméra plus loin\\Recule la caméra" -msgid "" -"Camera border scrolling\\Scrolling when the mouse touches right or left " -"border" -msgstr "" -"Défilement dans les bords\\Défilement lorsque la souris touche les bords " -"gauche ou droite" +msgid "Camera border scrolling\\Scrolling when the mouse touches right or left border" +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" -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" +#, fuzzy +msgid "Camera down\\Turns the camera down" +msgstr "Caméra plus proche\\Avance la caméra" -msgid "Camera nearest" -msgstr "Caméra plus proche" +#, fuzzy +msgid "Camera left\\Turns the camera left" +msgstr "Caméra plus proche\\Avance la caméra" -msgid "Camera to left" -msgstr "Caméra à gauche" +#, fuzzy +msgid "Camera right\\Turns the camera right" +msgstr "Tourner à droite\\Moteur à droite" -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" +#, fuzzy +msgid "Camera up\\Turns the camera up" +msgstr "Caméra (\\key camera;)" msgid "Can not produce not researched object" msgstr "Impossible de créer un objet n'ayant pas été recherché" @@ -371,6 +325,9 @@ msgstr "Annuler\\Annuler toutes les modifications" msgid "Challenges" msgstr "Défis" +msgid "Challenges in the chapter:" +msgstr "Liste des défis du chapitre :" + msgid "Challenges\\Programming challenges" msgstr "Défis\\Défis de programmation" @@ -380,6 +337,9 @@ msgstr "Changement de caméra\\Autre de point de vue" msgid "Change player\\Change player" msgstr "Autre joueur\\Choix du nom du joueur" +msgid "Chapters:" +msgstr "Liste des chapitres :" + msgid "Cheat console\\Show cheat console" msgstr "Console de triche\\Montre la console de triche" @@ -398,15 +358,14 @@ msgstr "Dupliquer le programme sélectionné" msgid "Close" msgstr "Fermer" -msgid "Closing bracket missing " +msgid "Closing bracket missing" msgstr "Il manque une parenthèse fermante" msgid "Code battles" msgstr "Batailles de code" msgid "Code battles\\Program your robot to be the best of them all!" -msgstr "" -"Batailles de code\\Programmez votre robot pour être le meilleur entre tous!" +msgstr "Batailles de code\\Programmez votre robot pour être le meilleur entre tous!" msgid "Colobot rules!" msgstr "Colobot est super!" @@ -438,20 +397,23 @@ msgstr "Conversion minerai en titanium" msgid "Copy" msgstr "Copier" -msgid "Copy (Ctrl+c)" -msgstr "Copier (Ctrl+c)" +msgid "Copy (Ctrl+C)" +msgstr "Copier (Ctrl+C)" msgid "Current mission saved" msgstr "Enregistrement effectué" +msgid "Custom levels:" +msgstr "Niveaux spéciaux :" + msgid "Custom levels\\Levels from mods created by the users" msgstr "Niveaux spéciaux\\Niveaux importés ou personnalisés" msgid "Customize your appearance" msgstr "Personnalisation de votre apparence" -msgid "Cut (Ctrl+x)" -msgstr "Couper (Ctrl+x)" +msgid "Cut (Ctrl+X)" +msgstr "Couper (Ctrl+X)" msgid "Defense tower" msgstr "Tour de défense" @@ -486,17 +448,14 @@ msgstr "Affichage\\Pilote et résolution d'affichage" msgid "Dividing by zero" msgstr "Division par zéro" -msgid "Do not use in this exercise" -msgstr "Interdit dans cet exercice" - msgid "Do you really want to destroy the selected building?" msgstr "Voulez-vous vraiment détruire le bâtiment sélectionné ?" #, c-format -msgid "Do you want to delete %s's saved games? " +msgid "Do you want to delete %s's saved games?" msgstr "Voulez-vous détruire les sauvegardes de %s ?" -msgid "Doors blocked by a robot or another object " +msgid "Doors blocked by a robot or another object" msgstr "Portes bloquées par un robot ou un objet" msgid "Down (\\key gdown;)" @@ -544,6 +503,9 @@ msgstr "Exécute le programme sélectionné" msgid "Execute/stop" msgstr "Démarrer/stopper" +msgid "Exercises in the chapter:" +msgstr "Liste des exercices du chapitre :" + msgid "Exercises\\Programming exercises" msgstr "Programmation\\Exercices de programmation" @@ -553,6 +515,9 @@ msgstr "Exploser (\\key action;)" msgid "Explosive" msgstr "Explosif" +msgid "Expression expected after =" +msgstr "" + msgid "Extend shield (\\key action;)" msgstr "Déploie le bouclier (\\key action;)" @@ -623,6 +588,9 @@ msgstr "Emplacement pour derrick (clé D)" msgid "Free game" msgstr "Jeu libre" +msgid "Free game on this planet:" +msgstr "Liste des jeux libres du chapitre :" + msgid "Free game\\Free game without a specific goal" msgstr "Jeu libre\\Jeu libre sans but précis" @@ -737,7 +705,7 @@ msgstr "Manque une instruction \"case\"" msgid "Instruction \"case\" outside a block \"switch\"" msgstr "Instruction \"case\" hors d'un bloc \"switch\"" -msgid "Instruction \"else\" without corresponding \"if\" " +msgid "Instruction \"else\" without corresponding \"if\"" msgstr "Instruction \"else\" sans \"if\" correspondant" msgid "Instructions (\\key help;)" @@ -797,6 +765,9 @@ msgstr "Robot shooter" msgid "Legged sniffer" msgstr "Robot renifleur" +msgid "Levels in this chapter:" +msgstr "Liste des niveaux du chapitre :" + msgid "Lightning conductor" msgstr "Paratonnerre" @@ -854,16 +825,17 @@ msgstr "Nom de la mission" msgid "Missions" msgstr "Missions" +msgid "Missions on this planet:" +msgstr "Liste des missions du chapitre :" + msgid "Missions\\Select mission" msgstr "Missions\\La grande aventure" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" -msgstr "" -"Inversion souris X\\Inversion de la rotation lorsque la souris touche un bord" +msgstr "Inversion souris X\\Inversion de la rotation lorsque la souris touche un bord" msgid "Mouse inversion Y\\Inversion of the scrolling direction on the Y axis" -msgstr "" -"Inversion souris Y\\Inversion de la rotation lorsque la souris touche un bord" +msgstr "Inversion souris Y\\Inversion de la rotation lorsque la souris touche un bord" msgid "Move selected program down" msgstr "Déplace le programme sélectionné vers le bas" @@ -1012,10 +984,10 @@ msgstr "Un pas" msgid "Open" msgstr "Ouvrir" -msgid "Open (Ctrl+o)" -msgstr "Ouvrir (Ctrl+o)" +msgid "Open (Ctrl+O)" +msgstr "Ouvrir (Ctrl+O)" -msgid "Opening brace missing " +msgid "Opening brace missing" msgstr "Début d'un bloc attendu" msgid "Opening bracket missing" @@ -1039,14 +1011,17 @@ msgstr "Montrer le lieu d'un message\\Montrer le lieu du dernier message" msgid "Original game developed by:" msgstr "Jeu Original développé par :" -msgid "Parameters missing " +msgid "Parameters missing" msgstr "Pas assez de paramètres" msgid "Particles in the interface\\Steam clouds and sparks in the interface" msgstr "Particules dans l'interface\\Pluie de particules" -msgid "Paste (Ctrl+v)" -msgstr "Coller (Ctrl+v)" +msgid "Paste (Ctrl+V)" +msgstr "Coller (Ctrl+V)" + +msgid "Pause blur\\Blur the background on the pause screen" +msgstr "" msgid "Pause in background\\Pause the game when the window is unfocused" msgstr "" @@ -1066,6 +1041,9 @@ msgstr "Vue de la mission" msgid "Place occupied" msgstr "Emplacement occupé" +msgid "Planets:" +msgstr "Liste des planètes :" + msgid "Plans for defense tower available" msgstr "Construction d'une tour de défense possible" @@ -1084,7 +1062,7 @@ msgstr "Fabrication de robots shooter possible" msgid "Plans for thumper available" msgstr "Fabrication d'un robot secoueur possible" -msgid "Plans for tracked robots available " +msgid "Plans for tracked robots available" msgstr "Fabrication d'un robot à chenilles possible" msgid "Plant a flag" @@ -1156,7 +1134,7 @@ msgstr "Programmation" msgid "Programming help" msgstr "Aide à la programmation" -msgid "Programming help (\\key prog;)" +msgid "Programming help (\\key prog;)" msgstr "Aide à la programmation (\\key prog;)" msgid "Programming help\\Gives more detailed help with programming" @@ -1234,6 +1212,9 @@ msgstr "Ce mot est réservé" msgid "Resolution" msgstr "Résolution" +msgid "Resolution:" +msgstr "Résolutions :" + msgid "Resources" msgstr "" @@ -1294,13 +1275,13 @@ msgstr "Rapport du satellite" msgid "Save" msgstr "Enregistrer" -msgid "Save (Ctrl+s)" -msgstr "Enregistrer (Ctrl+s)" +msgid "Save (Ctrl+S)" +msgstr "Enregistrer (Ctrl+S)" msgid "Save the current mission" msgstr "Enregistrement de la mission en cours" -msgid "Save\\Save the current mission " +msgid "Save\\Save the current mission" msgstr "Enregistrer\\Enregistrer la mission en cours" msgid "Save\\Saves the current mission" @@ -1313,9 +1294,7 @@ msgid "Semicolon terminator missing" msgstr "Terminateur point-virgule non trouvé" msgid "Shadow resolution\\Higher means better range and quality, but slower" -msgstr "" -"Résolution des ombres\\Plus grand implique une meilleure qulité et " -"amplitude, mais plus lent" +msgstr "Résolution des ombres\\Plus grand implique une meilleure qulité et amplitude, mais plus lent" msgid "Shield level" msgstr "Niveau du bouclier" @@ -1410,8 +1389,7 @@ msgstr "Araignée mortellement touchée" msgid "Stack overflow" msgstr "Débordement de la pile" -msgid "" -"Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" +msgid "Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" msgstr "Action standard\\Action du bouton avec le cadre rouge" msgid "Standard controls\\Standard key functions" @@ -1444,6 +1422,9 @@ msgstr "Couleur de la combinaison :" msgid "Suit\\Astronaut suit" msgstr "Corps\\Combinaison" +msgid "Summary:" +msgstr "Résumé :" + msgid "Survival kit" msgstr "Sac de survie" @@ -1471,15 +1452,13 @@ msgstr "Textures" msgid "The expression must return a boolean value" msgstr "L'expression doit ętre un boolean" -msgid "The function returned no value " +msgid "The function returned no value" msgstr "La fonction n'a pas retourné de résultat" -msgid "" -"The mission is not accomplished yet (press \\key help; for more details)" -msgstr "" -"La misssion n'est pas terminée (appuyez sur \\key help; pour plus de détails)" +msgid "The mission is not accomplished yet (press \\key help; for more details)" +msgstr "La misssion n'est pas terminée (appuyez sur \\key help; pour plus de détails)" -msgid "The types of the two operands are incompatible " +msgid "The types of the two operands are incompatible" msgstr "Les deux opérandes ne sont pas de types compatibles" msgid "This class already exists" @@ -1498,9 +1477,7 @@ msgid "This label does not exist" msgstr "Cette étiquette n'existe pas" msgid "This menu is for userlevels from mods, but you didn't install any" -msgstr "" -"Ce menu donne accès aux niveaux spéciaux (importés ou personnalisés), mais " -"aucun n'est installé." +msgstr "Ce menu donne accès aux niveaux spéciaux (importés ou personnalisés), mais aucun n'est installé." msgid "This object is not a member of a class" msgstr "L'objet n'est pas une instance d'une classe" @@ -1586,8 +1563,8 @@ msgstr "Déclaration de type attendu" msgid "Unable to control enemy objects" msgstr "Impossible de contrôler les objets ennemis" -msgid "Undo (Ctrl+z)" -msgstr "Annuler (Ctrl+z)" +msgid "Undo (Ctrl+Z)" +msgstr "Annuler (Ctrl+Z)" msgid "Unit" msgstr "Unité" @@ -1689,8 +1666,7 @@ msgid "Yes" msgstr "Oui" msgid "You can fly with the keys (\\key gup;) and (\\key gdown;)" -msgstr "" -"Il est possible de voler avec les touches (\\key gup;) et (\\key gdown;)" +msgstr "Il est possible de voler avec les touches (\\key gup;) et (\\key gdown;)" msgid "You can not carry a radioactive object" msgstr "Vous ne pouvez pas transporter un objet radioactif" @@ -1698,10 +1674,26 @@ msgstr "Vous ne pouvez pas transporter un objet radioactif" msgid "You can not carry an object under water" msgstr "Vous ne pouvez pas transporter un objet sous l'eau" +#, fuzzy, c-format +msgid "You cannot use \"%s\" in this exercise (used: %d)" +msgstr "Interdit dans cet exercice" + msgid "You found a usable object" msgstr "Vous avez trouvé un objet utilisable" -msgid "You must get on the spaceship to take off " +#, fuzzy, 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] "Interdit dans cet exercice" +msgstr[1] "Interdit dans cet exercice" + +#, fuzzy, 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] "Interdit dans cet exercice" +msgstr[1] "Interdit dans cet exercice" + +msgid "You must get on the spaceship to take off" msgstr "Vous devez embarquer pour pouvoir décoller" msgid "Zoom mini-map" @@ -1815,6 +1807,9 @@ msgstr "epsitec.com" #~ 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" @@ -1824,6 +1819,24 @@ msgstr "epsitec.com" #~ 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" @@ -1909,9 +1922,7 @@ msgstr "epsitec.com" #~ 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" +#~ 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" diff --git a/po/pl.po b/po/pl.po index b4f079c2..1b0dc6d4 100644 --- a/po/pl.po +++ b/po/pl.po @@ -14,42 +14,9 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " -"|| n%100>=20) ? 1 : 2);\n" -"X-Generator: Pootle 2.5.1.1\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Language: pl_PL\n" "X-Source-Language: en_US\n" -"X-POOTLE-MTIME: 1405002617.000000\n" - -msgid " Challenges in the chapter:" -msgstr " Wyzwania w tym rozdziale:" - -msgid " Chapters:" -msgstr " Rozdziały:" - -msgid " Custom levels:" -msgstr " Własne poziomy:" - -msgid " Exercises in the chapter:" -msgstr " Ćwiczenia w tym rozdziale:" - -msgid " Free game on this planet:" -msgstr " Swobodna gra na tej planecie:" - -msgid " Levels in this chapter:" -msgstr " Poziomy w tym rozdziale:" - -msgid " Missions on this planet:" -msgstr " Misje na tej planecie:" - -msgid " Planets:" -msgstr " Planety:" - -msgid " Resolution:" -msgstr " Rozdzielczość:" - -msgid " Summary:" -msgstr " Streszczenie:" msgid " or " msgstr " lub " @@ -60,10 +27,6 @@ msgstr "Oczekiwane \" [ \"" msgid "\" ] \" missing" msgstr "Brak \" ] \"" -#, c-format -msgid "\"%s\" missing in this exercise" -msgstr "Brakuje \"%s\" w tym ćwiczeniu" - msgid "..behind" msgstr "..za" @@ -100,11 +63,8 @@ msgstr "Przerwij\\Przerywa bieżącą misję" msgid "Access beyond array limit" msgstr "Dostęp poza tablicę" -msgid "" -"Access to solution\\Shows the solution (detailed instructions for missions)" -msgstr "" -"Dostęp do rozwiązania\\Pokazuje rozwiązanie (szczegółowe instrukcje " -"dotyczące misji)" +msgid "Access to solution\\Shows the solution (detailed instructions for missions)" +msgstr "Dostęp do rozwiązania\\Pokazuje rozwiązanie (szczegółowe instrukcje dotyczące misji)" msgid "Access to solutions\\Show program \"4: Solution\" in the exercises" msgstr "Accčs aux solutions\\Programme \"4: Solution\" dans les exercices" @@ -121,6 +81,9 @@ msgstr "Królowa Obcych została zabita" msgid "Already carrying something" msgstr "Nie można nieść więcej przedmiotów" +msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)" +msgstr "Alternatywny tryb kamery\\Poruszaj na boki zamiast obracać (w kamerze swobodnej)" + msgid "Analysis already performed" msgstr "Analiza została już wykonana" @@ -158,14 +121,10 @@ msgid "Automatic indent\\When program editing" msgstr "Automatyczne wcięcia\\Automatyczne wcięcia podczas edycji programu" msgid "Autosave interval\\How often your game will autosave" -msgstr "" -"Częstotliwość autozapisu\\Jak często gra będzie automatycznie zapisywać twój " -"postęp" +msgstr "Częstotliwość autozapisu\\Jak często gra będzie automatycznie zapisywać twój postęp" msgid "Autosave slots\\How many autosave slots you'll have" -msgstr "" -"Sloty autozapisów\\Określa ile slotów na automatyczne zapisy będzie " -"dostępnych" +msgstr "Sloty autozapisów\\Określa ile slotów na automatyczne zapisy będzie dostępnych" msgid "Autosave\\Enables autosave" msgstr "Autozapis\\Włącza automatyczny zapis" @@ -173,8 +132,8 @@ msgstr "Autozapis\\Włącza automatyczny zapis" msgid "Back" msgstr "Wstecz" -msgid "Background sound :\\Volume of audio tracks" -msgstr "Muzyka w tle :\\Głośność ścieżek dźwiękowych" +msgid "Background sound:\\Volume of audio tracks" +msgstr "Muzyka w tle:\\Głośność ścieżek dźwiękowych" msgid "Backward (\\key down;)" msgstr "Cofnij (\\key down;)" @@ -186,9 +145,7 @@ msgid "Bad argument for \"new\"" msgstr "Zły argument dla funkcji \"new\"" msgid "Big indent\\Indent 2 or 4 spaces per level defined by braces" -msgstr "" -"Duże wcięcie\\2 lub 4 spacje wcięcia na każdy poziom zdefiniowany przez " -"klamry" +msgstr "Duże wcięcie\\2 lub 4 spacje wcięcia na każdy poziom zdefiniowany przez klamry" msgid "Black box" msgstr "Czarna skrzynka" @@ -328,36 +285,26 @@ msgstr "Odwołanie do nieznanej funkcji" msgid "Camera (\\key camera;)" msgstr "Kamera (\\key camera;)" -msgid "Camera awayest" -msgstr "Camera awayest" - msgid "Camera back\\Moves the camera backward" msgstr "Kamera dalej\\Oddala kamerę" -msgid "" -"Camera border scrolling\\Scrolling when the mouse touches right or left " -"border" -msgstr "" -"Przewijanie kamery przy krawędzi\\Ekran jest przewijany gdy mysz dotknie " -"prawej lub lewej jego krawędzi" +msgid "Camera border scrolling\\Scrolling when the mouse touches right or left border" +msgstr "Przewijanie kamery przy krawędzi\\Ekran jest przewijany gdy mysz dotknie prawej lub lewej jego krawędzi" msgid "Camera closer\\Moves the camera forward" msgstr "Kamera bliżej\\Przybliża kamerę" -msgid "Camera down\\Decrease camera angle while visiting message origin" -msgstr "Kamera w dół\\Opuść kamerę podczas sprawdzania źródła wiadomości" +msgid "Camera down\\Turns the camera down" +msgstr "Kamera w dół\\Obraca kamerę w dół" -msgid "Camera nearest" -msgstr "Camera nearest" +msgid "Camera left\\Turns the camera left" +msgstr "Kamera w lewo\\Obraca kamerę w lewo" -msgid "Camera to left" -msgstr "Camera to left" +msgid "Camera right\\Turns the camera right" +msgstr "Kamera w prawo\\Obróć kamerę w prawo" -msgid "Camera to right" -msgstr "Camera to right" - -msgid "Camera up\\Increase camera angle while visiting message origin" -msgstr "Kamera w górę\\Podnieś kamerę podczas sprawdzania źródła wiadomości" +msgid "Camera up\\Turns the camera up" +msgstr "Kamera w górę\\Obróć kamerę w górę" msgid "Can not produce not researched object" msgstr "Nie można wyprodukować nie wynalezionego obiektu" @@ -377,6 +324,9 @@ msgstr "Anuluj\\Pomija wszystkie zmiany" msgid "Challenges" msgstr "Wyzwania" +msgid "Challenges in the chapter:" +msgstr "Wyzwania w tym rozdziale:" + msgid "Challenges\\Programming challenges" msgstr "Wyzwania\\Wyzwania programistyczne" @@ -386,6 +336,9 @@ msgstr "Zmień kamerę\\Przełącza pomiędzy kamerą pokładową i śledzącą" msgid "Change player\\Change player" msgstr "Zmień gracza\\Zmień gracza" +msgid "Chapters:" +msgstr "Rozdziały:" + msgid "Cheat console\\Show cheat console" msgstr "Konsola komend\\Pokaż konsolę komend" @@ -404,15 +357,14 @@ msgstr "Skopiuj zaznaczony program" msgid "Close" msgstr "Zamknij" -msgid "Closing bracket missing " +msgid "Closing bracket missing" msgstr "Brak nawiasu zamykającego" msgid "Code battles" msgstr "Programobitwy" msgid "Code battles\\Program your robot to be the best of them all!" -msgstr "" -"Programobitwy\\Zaprogramuj swego robota by był najlepszy ze wszystkich!" +msgstr "Programobitwy\\Zaprogramuj swego robota by był najlepszy ze wszystkich!" msgid "Colobot rules!" msgstr "Colobot rządzi!" @@ -444,19 +396,22 @@ msgstr "Przetop rudę na tytan" msgid "Copy" msgstr "Kopiuj" -msgid "Copy (Ctrl+c)" +msgid "Copy (Ctrl+C)" msgstr "Kopiuj (Ctrl+C)" msgid "Current mission saved" msgstr "Bieżąca misja zapisana" +msgid "Custom levels:" +msgstr "Własne poziomy:" + msgid "Custom levels\\Levels from mods created by the users" msgstr "Własne poziomy\\Poziomy z modyfikacji stworzonych przez użytkowników" msgid "Customize your appearance" msgstr "Dostosuj wygląd" -msgid "Cut (Ctrl+x)" +msgid "Cut (Ctrl+X)" msgstr "Wytnij (Ctrl+X)" msgid "Defense tower" @@ -492,18 +447,15 @@ msgstr "Urządzenie\\Ustawienia sterownika i rozdzielczości" msgid "Dividing by zero" msgstr "Dzielenie przez zero" -msgid "Do not use in this exercise" -msgstr "Do not use in this exercise" - msgid "Do you really want to destroy the selected building?" msgstr "Czy na pewno chcesz zniszczyć zaznaczony budynek?" #, c-format -msgid "Do you want to delete %s's saved games? " -msgstr "Czy na pewno chcesz skasować zapisane gry gracza %s? " +msgid "Do you want to delete %s's saved games?" +msgstr "Czy na pewno chcesz skasować zapisane gry gracza %s?" -msgid "Doors blocked by a robot or another object " -msgstr "Drzwi zablokowane przez robota lub inny obiekt " +msgid "Doors blocked by a robot or another object" +msgstr "Drzwi zablokowane przez robota lub inny obiekt" msgid "Down (\\key gdown;)" msgstr "Dół (\\key gdown;)" @@ -550,6 +502,9 @@ msgstr "Wykonaj zaznaczony program" msgid "Execute/stop" msgstr "Wykonaj/Zatrzymaj" +msgid "Exercises in the chapter:" +msgstr "Ćwiczenia w tym rozdziale:" + msgid "Exercises\\Programming exercises" msgstr "Ćwiczenia\\Ćwiczenia programistyczne" @@ -559,6 +514,9 @@ msgstr "Wysadź (\\key action;)" msgid "Explosive" msgstr "Materiały wybuchowe" +msgid "Expression expected after =" +msgstr "Oczekiwano wyrażenia po =" + msgid "Extend shield (\\key action;)" msgstr "Rozszerz osłonę (\\key action;)" @@ -629,6 +587,9 @@ msgstr "Znaleziono klucz D (miejsce na kopalnię)" msgid "Free game" msgstr "Swobodna gra" +msgid "Free game on this planet:" +msgstr "Swobodna gra na tej planecie:" + msgid "Free game\\Free game without a specific goal" msgstr "Swobodna gra\\Swobodna gra bez konkretnych celów" @@ -690,8 +651,7 @@ msgid "Help balloons\\Explain the function of the buttons" msgstr "Dymki pomocy\\Wyjaśnia funkcje przycisków" msgid "Highest\\Highest graphic quality (lowest frame rate)" -msgstr "" -"Najwyższa\\Maksymalna jakość grafiki (najniższa częstotliwość odświeżania)" +msgstr "Najwyższa\\Maksymalna jakość grafiki (najniższa częstotliwość odświeżania)" msgid "Home" msgstr "Początek" @@ -744,8 +704,8 @@ msgstr "Brak polecenia \"case" msgid "Instruction \"case\" outside a block \"switch\"" msgstr "Polecenie \"case\" na zewnątrz bloku \"switch\"" -msgid "Instruction \"else\" without corresponding \"if\" " -msgstr "Polecenie \"else\" bez wystąpienia \"if\" " +msgid "Instruction \"else\" without corresponding \"if\"" +msgstr "Polecenie \"else\" bez wystąpienia \"if\"" msgid "Instructions (\\key help;)" msgstr "Rozkazy (\\key help;)" @@ -804,6 +764,9 @@ msgstr "Działo na nogach" msgid "Legged sniffer" msgstr "Szperacz na nogach" +msgid "Levels in this chapter:" +msgstr "Poziomy w tym rozdziale:" + msgid "Lightning conductor" msgstr "Odgromnik" @@ -838,8 +801,7 @@ msgid "Loading terrain" msgstr "Wczytywanie terenu" msgid "Lowest\\Minimum graphic quality (highest frame rate)" -msgstr "" -"Najniższa\\Minimalna jakość grafiki (najwyższa częstotliwość odświeżania)" +msgstr "Najniższa\\Minimalna jakość grafiki (najwyższa częstotliwość odświeżania)" msgid "Lunar Roving Vehicle" msgstr "Pojazd Księżycowy" @@ -862,6 +824,9 @@ msgstr "Nazwa misji" msgid "Missions" msgstr "Misje" +msgid "Missions on this planet:" +msgstr "Misje na tej planecie:" + msgid "Missions\\Select mission" msgstr "Misje\\Wybierz misję" @@ -1018,10 +983,10 @@ msgstr "Jeden krok" msgid "Open" msgstr "Otwórz" -msgid "Open (Ctrl+o)" +msgid "Open (Ctrl+O)" msgstr "Otwórz (Ctrl+O)" -msgid "Opening brace missing " +msgid "Opening brace missing" msgstr "Brak klamry otwierającej" msgid "Opening bracket missing" @@ -1040,21 +1005,23 @@ msgid "Organic matter" msgstr "Materia organiczna" msgid "Origin of last message\\Shows where the last message was sent from" -msgstr "" -"Miejsce nadania wiadomości\\Pokazuje skąd została wysłana ostatnia wiadomość" +msgstr "Miejsce nadania wiadomości\\Pokazuje skąd została wysłana ostatnia wiadomość" msgid "Original game developed by:" msgstr "Twórcy oryginalnej gry:" -msgid "Parameters missing " +msgid "Parameters missing" msgstr "Brak wymaganego parametru" msgid "Particles in the interface\\Steam clouds and sparks in the interface" msgstr "Cząstki w interfejsie\\Para i iskry z silników w interfejsie" -msgid "Paste (Ctrl+v)" +msgid "Paste (Ctrl+V)" msgstr "Wklej (Ctrl+V)" +msgid "Pause blur\\Blur the background on the pause screen" +msgstr "" + msgid "Pause in background\\Pause the game when the window is unfocused" msgstr "Wstrzymaj w tle\\Wstrzymaj grę gdy okno stanie się nieaktywne" @@ -1073,6 +1040,9 @@ msgstr "Fotografia" msgid "Place occupied" msgstr "Miejsce zajęte" +msgid "Planets:" +msgstr "Planety:" + msgid "Plans for defense tower available" msgstr "Dostępne plany wieży obronnej" @@ -1091,7 +1061,7 @@ msgstr "Dostępne plany działa" msgid "Plans for thumper available" msgstr "Dostępne plany robota uderzacza" -msgid "Plans for tracked robots available " +msgid "Plans for tracked robots available" msgstr "Dostępne plany tranporterów na gąsienicach" msgid "Plant a flag" @@ -1125,8 +1095,7 @@ msgid "Practice bot" msgstr "Robot treningowy" msgid "Press \\key help; to read instructions on your SatCom" -msgstr "" -"Naciśnij klawisz \\key help; aby wyświetlić rozkazy na przekaźniku SatCom" +msgstr "Naciśnij klawisz \\key help; aby wyświetlić rozkazy na przekaźniku SatCom" msgid "Previous" msgstr "Poprzedni" @@ -1164,8 +1133,8 @@ msgstr "Ćwiczenia programistyczne" msgid "Programming help" msgstr "Podręcznik programowania" -msgid "Programming help (\\key prog;)" -msgstr "Podręcznik programowania (\\key prog;)" +msgid "Programming help (\\key prog;)" +msgstr "Podręcznik programowania (\\key prog;)" msgid "Programming help\\Gives more detailed help with programming" msgstr "Podręcznik programowania\\Dostarcza szczegółową pomoc w programowaniu" @@ -1242,6 +1211,9 @@ msgstr "Słowo zarezerwowane języka CBOT" msgid "Resolution" msgstr "Rozdzielczość" +msgid "Resolution:" +msgstr "Rozdzielczość:" + msgid "Resources" msgstr "Zasoby" @@ -1302,13 +1274,13 @@ msgstr "Raport z satelity" msgid "Save" msgstr "Zapisz" -msgid "Save (Ctrl+s)" +msgid "Save (Ctrl+S)" msgstr "Zapisz (Ctrl+S)" msgid "Save the current mission" msgstr "Zapisz bieżącą misję" -msgid "Save\\Save the current mission " +msgid "Save\\Save the current mission" msgstr "Zapisz\\Zapisuje bieżącą misję" msgid "Save\\Saves the current mission" @@ -1321,9 +1293,7 @@ msgid "Semicolon terminator missing" msgstr "Brak średnika na końcu wiersza" msgid "Shadow resolution\\Higher means better range and quality, but slower" -msgstr "" -"Rozdzielczość cieni\\Wyższa wartość oznacza wyższy zasięg i jakość, ale jest " -"wolniejsza" +msgstr "Rozdzielczość cieni\\Wyższa wartość oznacza wyższy zasięg i jakość, ale jest wolniejsza" msgid "Shield level" msgstr "Poziom osłony" @@ -1418,11 +1388,8 @@ msgstr "Pająk śmiertelnie raniony" msgid "Stack overflow" msgstr "Przepełnienie stosu" -msgid "" -"Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" -msgstr "" -"Standardowa akcja\\Standardowa akcja robota (podnieś/upuść, strzelaj, " -"szukaj, itp.)" +msgid "Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" +msgstr "Standardowa akcja\\Standardowa akcja robota (podnieś/upuść, strzelaj, szukaj, itp.)" msgid "Standard controls\\Standard key functions" msgstr "Standardowa kontrola\\Standardowe klawisze funkcyjne" @@ -1454,6 +1421,9 @@ msgstr "Kolor skafandra:" msgid "Suit\\Astronaut suit" msgstr "Skafander\\Skafander astronauty" +msgid "Summary:" +msgstr "Streszczenie:" + msgid "Survival kit" msgstr "Zestaw przetrwania" @@ -1481,14 +1451,13 @@ msgstr "Tekstury" msgid "The expression must return a boolean value" msgstr "Wyrażenie musi zwrócić wartość logiczną" -msgid "The function returned no value " -msgstr "Funkcja nie zwróciła żadnej wartości " +msgid "The function returned no value" +msgstr "Funkcja nie zwróciła żadnej wartości" -msgid "" -"The mission is not accomplished yet (press \\key help; for more details)" +msgid "The mission is not accomplished yet (press \\key help; for more details)" msgstr "Misja nie jest wypełniona (naciśnij \\key help; aby uzyskać szczegóły)" -msgid "The types of the two operands are incompatible " +msgid "The types of the two operands are incompatible" msgstr "Niezgodne typy operatorów" msgid "This class already exists" @@ -1507,9 +1476,7 @@ msgid "This label does not exist" msgstr "Taka etykieta nie istnieje" msgid "This menu is for userlevels from mods, but you didn't install any" -msgstr "" -"To menu jest przeznaczone na poziomy użytkownika z modyfikacji, ale żadne " -"nie są zainstalowane" +msgstr "To menu jest przeznaczone na poziomy użytkownika z modyfikacji, ale żadne nie są zainstalowane" msgid "This object is not a member of a class" msgstr "Ten obiekt nie jest członkiem klasy" @@ -1595,7 +1562,7 @@ msgstr "Brak deklaracji typu" msgid "Unable to control enemy objects" msgstr "Nie można kontrolować wrogich obiektów" -msgid "Undo (Ctrl+z)" +msgid "Undo (Ctrl+Z)" msgstr "Cofnij (Ctrl+Z)" msgid "Unit" @@ -1706,10 +1673,28 @@ msgstr "Nie możesz przenosić przedmiotów radioaktywnych" msgid "You can not carry an object under water" msgstr "Nie możesz przenosić przedmiotów pod wodą" +#, c-format +msgid "You cannot use \"%s\" in this exercise (used: %d)" +msgstr "Nie możesz użyć \"%s\" w tym ćwiczeniu (użyto: %d)" + msgid "You found a usable object" msgstr "Znaleziono użyteczny przedmiot" -msgid "You must get on the spaceship to take off " +#, 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] "Musisz użyć \"%1$s\" przynajmniej raz w tym ćwiczeniu (użyto: %2$d)" +msgstr[1] "Musisz użyć \"%1$s\" przynajmniej %3$d razy w tym ćwiczeniu (użyto: %2$d)" +msgstr[2] "Musisz użyć \"%1$s\" przynajmniej %3$d razy w tym ćwiczeniu (użyto: %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] "Możesz użyć \"%1$s\" najwyżej raz w tym ćwiczeniu (użyto: %2$d)" +msgstr[1] "Możesz użyć \"%1$s\" najwyżej %3$d razy w tym ćwiczeniu (użyto: %2$d)" +msgstr[2] "Możesz użyć \"%1$s\" najwyżej %3$d razy w tym ćwiczeniu (użyto: %2$d)" + +msgid "You must get on the spaceship to take off" msgstr "Musisz być na statku kosmicznym aby nim odlecieć" msgid "Zoom mini-map" @@ -1817,12 +1802,33 @@ msgstr "epsitec.com" #~ msgid " Drivers:" #~ msgstr " Sterowniki:" +#~ msgid "\"%s\" missing in this exercise" +#~ msgstr "Brakuje \"%s\" w tym ćwiczeniu" + #~ msgid "3D sound\\3D positioning of the sound" #~ msgstr "Dźwięk 3D\\Przestrzenne pozycjonowanie dźwięków" #~ msgid "Building too close" #~ msgstr "Budynek za blisko" +#~ msgid "Camera awayest" +#~ msgstr "Camera awayest" + +#~ msgid "Camera down\\Decrease camera angle while visiting message origin" +#~ msgstr "Kamera w dół\\Opuść kamerę podczas sprawdzania źródła wiadomości" + +#~ msgid "Camera nearest" +#~ msgstr "Camera nearest" + +#~ msgid "Camera to left" +#~ msgstr "Camera to left" + +#~ msgid "Camera to right" +#~ msgstr "Camera to right" + +#~ msgid "Camera up\\Increase camera angle while visiting message origin" +#~ msgstr "Kamera w górę\\Podnieś kamerę podczas sprawdzania źródła wiadomości" + #~ msgid "Can not create this; there are too many objects" #~ msgstr "Nie można tego utworzyć, za dużo obiektów" @@ -1844,6 +1850,9 @@ msgstr "epsitec.com" #~ msgid "Details\\Visual quality of 3D objects" #~ msgstr "Szczegóły\\Jakość wizualna obiektów 3D" +#~ msgid "Do not use in this exercise" +#~ msgstr "Do not use in this exercise" + #~ msgid "Do you want to quit Colobot: Gold Edition?" #~ msgstr "Czy na pewno chcesz opuścić grę Colobot: Gold Edition?" @@ -1857,8 +1866,7 @@ msgstr "epsitec.com" #~ msgstr "Nieodpowiedni teren" #~ msgid "Key word help\\More detailed help about key words" -#~ msgstr "" -#~ "Pomoc dot. słów kluczowych\\Dokładniejsza pomoc na temat słów kluczowych" +#~ msgstr "Pomoc dot. słów kluczowych\\Dokładniejsza pomoc na temat słów kluczowych" #~ msgid "Loading programs" #~ msgstr "Wczytywanie programów" @@ -1876,8 +1884,7 @@ msgstr "epsitec.com" #~ msgstr "Wciąż za mało energii" #~ msgid "Num of decorative objects\\Number of purely ornamental objects" -#~ msgstr "" -#~ "Ilość elementów dekoracyjnych \\Ilość elementów czysto dekoracyjnych" +#~ msgstr "Ilość elementów dekoracyjnych \\Ilość elementów czysto dekoracyjnych" #~ msgid "Object not found" #~ msgstr "Obiekt nieznany" @@ -1903,12 +1910,8 @@ msgstr "epsitec.com" #~ msgid "Textures\\Quality of textures " #~ msgstr "Tekstury\\Jakość tekstur " -#~ msgid "" -#~ "The list is only available if a \\l;radar station\\u object\\radar; is " -#~ "working.\n" -#~ msgstr "" -#~ "Lista jest dostępna jedynie gdy działa \\l;stacja radarowa\\u object" -#~ "\\radar;.\n" +#~ msgid "The list is only available if a \\l;radar station\\u object\\radar; is working.\n" +#~ msgstr "Lista jest dostępna jedynie gdy działa \\l;stacja radarowa\\u object\\radar;.\n" #~ msgid "Use a joystick\\Joystick or keyboard" #~ msgstr "Używaj joysticka\\Joystick lub klawiatura" diff --git a/po/ru.po b/po/ru.po index 16f252e3..539ed447 100644 --- a/po/ru.po +++ b/po/ru.po @@ -18,38 +18,6 @@ msgstr "" "X-Language: ru_RU\n" "X-Source-Language: en_US\n" -msgid " Challenges in the chapter:" -msgstr " Задачи к главе:" - -msgid " Chapters:" -msgstr " Разделы:" - -#, fuzzy -msgid " Custom levels:" -msgstr " Пользовательские уровни:" - -msgid " Exercises in the chapter:" -msgstr " Упражнения в разделе:" - -msgid " Free game on this planet:" -msgstr " Свободная игра на этой планете:" - -#, fuzzy -msgid " Levels in this chapter:" -msgstr " Упражнения в разделе:" - -msgid " Missions on this planet:" -msgstr "Миссии на этой планете:" - -msgid " Planets:" -msgstr " Планеты:" - -msgid " Resolution:" -msgstr " Разрешение:" - -msgid " Summary:" -msgstr " Итог:" - msgid " or " msgstr " или " @@ -59,10 +27,6 @@ msgstr "Ожидалось \" [ \"" msgid "\" ] \" missing" msgstr "Отсутствует \"]\" " -#, c-format -msgid "\"%s\" missing in this exercise" -msgstr "\"%s\" отсутствует в этом упражнении" - msgid "..behind" msgstr "Сзади" @@ -99,8 +63,7 @@ msgstr "Выход\\Прервать текущую миссию" msgid "Access beyond array limit" msgstr "Доступ к массиву за предел" -msgid "" -"Access to solution\\Shows the solution (detailed instructions for missions)" +msgid "Access to solution\\Shows the solution (detailed instructions for missions)" msgstr "Доступ к решению\\Показывает решение (подробные инструкции для миссий)" msgid "Access to solutions\\Show program \"4: Solution\" in the exercises" @@ -118,6 +81,9 @@ msgstr "Королева чужих убита" msgid "Already carrying something" msgstr "Уже что-то несу" +msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)" +msgstr "" + msgid "Analysis already performed" msgstr "Анализ уже выполнен" @@ -167,7 +133,7 @@ msgid "Back" msgstr "Назад" #, fuzzy -msgid "Background sound :\\Volume of audio tracks" +msgid "Background sound:\\Volume of audio tracks" msgstr "Фоновый звук:\\Громкость звуковых дорожек на CD" msgid "Backward (\\key down;)" @@ -320,35 +286,31 @@ msgstr "Вызов неизвестной функции" msgid "Camera (\\key camera;)" msgstr "Камера (\\key camera;)" -msgid "Camera awayest" -msgstr "Отдалить камеру" - msgid "Camera back\\Moves the camera backward" msgstr "Отдалить камеру\\Перемещение камеры назад" #, fuzzy -msgid "" -"Camera border scrolling\\Scrolling when the mouse touches right or left " -"border" +msgid "Camera border scrolling\\Scrolling when the mouse touches right or left border" msgstr "Прокрутка\\Прокрутка, когда указатель мыши касается граней экрана" msgid "Camera closer\\Moves the camera forward" msgstr "Приблизать камеру\\Перемещение камеры вперед" -msgid "Camera down\\Decrease camera angle while visiting message origin" -msgstr "" +#, fuzzy +msgid "Camera down\\Turns the camera down" +msgstr "Приблизать камеру\\Перемещение камеры вперед" -msgid "Camera nearest" -msgstr "Приблизить камеру" +#, fuzzy +msgid "Camera left\\Turns the camera left" +msgstr "Приблизать камеру\\Перемещение камеры вперед" -msgid "Camera to left" -msgstr "Камеру влево" +#, fuzzy +msgid "Camera right\\Turns the camera right" +msgstr "Повернуть налево\\Поворот налево" -msgid "Camera to right" -msgstr "Камеру вправо" - -msgid "Camera up\\Increase camera angle while visiting message origin" -msgstr "" +#, fuzzy +msgid "Camera up\\Turns the camera up" +msgstr "Камера (\\key camera;)" msgid "Can not produce not researched object" msgstr "" @@ -368,6 +330,9 @@ msgstr "Отмена\\Отменить все изменения" msgid "Challenges" msgstr "Задания" +msgid "Challenges in the chapter:" +msgstr "Задачи к главе:" + msgid "Challenges\\Programming challenges" msgstr "Задания\\Практика программирования" @@ -377,6 +342,9 @@ msgstr "Изменить вид\\Переключение между борто msgid "Change player\\Change player" msgstr "Новый игрок\\Выберите имя для игрока" +msgid "Chapters:" +msgstr "Разделы:" + msgid "Cheat console\\Show cheat console" msgstr "" @@ -396,7 +364,7 @@ msgstr "Изменить выбранную программу" msgid "Close" msgstr "Закрыть" -msgid "Closing bracket missing " +msgid "Closing bracket missing" msgstr "Закрывающая скобка отсутствует" msgid "Code battles" @@ -435,19 +403,22 @@ msgstr "Преобразует руду в титан" msgid "Copy" msgstr "Копировать" -msgid "Copy (Ctrl+c)" +msgid "Copy (Ctrl+C)" msgstr "Копировать (Ctrl+C)" msgid "Current mission saved" msgstr "Текущая миссия сохранена" +msgid "Custom levels:" +msgstr "Пользовательские уровни:" + msgid "Custom levels\\Levels from mods created by the users" msgstr "" msgid "Customize your appearance" msgstr "Настроить свой внешний вид" -msgid "Cut (Ctrl+x)" +msgid "Cut (Ctrl+X)" msgstr "Вырезать (Ctrl+X)" msgid "Defense tower" @@ -484,17 +455,14 @@ msgstr "Устройство\\Драйвер и настройки разреш msgid "Dividing by zero" msgstr "Деление на ноль (запрещено!)" -msgid "Do not use in this exercise" -msgstr "Не используй в этом упражнении" - msgid "Do you really want to destroy the selected building?" msgstr "Вы действительно хотите уничтожить выбранное здание?" #, c-format -msgid "Do you want to delete %s's saved games? " +msgid "Do you want to delete %s's saved games?" msgstr "Вы действительно хотите удалить сохраненные игры игрока %s?" -msgid "Doors blocked by a robot or another object " +msgid "Doors blocked by a robot or another object" msgstr "Двери заблокированы роботом или другим объектом" msgid "Down (\\key gdown;)" @@ -542,6 +510,9 @@ msgstr "Выполнить выбранную программу" msgid "Execute/stop" msgstr "Выполнить/стоп" +msgid "Exercises in the chapter:" +msgstr "Упражнения в разделе:" + msgid "Exercises\\Programming exercises" msgstr "Упражнения\\Упражнения по программированию" @@ -551,6 +522,9 @@ msgstr "" msgid "Explosive" msgstr "Взрывчатка" +msgid "Expression expected after =" +msgstr "" + msgid "Extend shield (\\key action;)" msgstr "Поднять щит (\\key action;)" @@ -621,6 +595,9 @@ msgstr "Найден ключ D (место для буровой вышки)" msgid "Free game" msgstr "Свободная игра" +msgid "Free game on this planet:" +msgstr "Свободная игра на этой планете:" + msgid "Free game\\Free game without a specific goal" msgstr "Свобод. игра\\Игра без четкой цели" @@ -735,7 +712,7 @@ msgstr "Отсутствует инструкция \"case\"" msgid "Instruction \"case\" outside a block \"switch\"" msgstr "Инструкция \"case\" вне блока \"switch\" " -msgid "Instruction \"else\" without corresponding \"if\" " +msgid "Instruction \"else\" without corresponding \"if\"" msgstr "Инструкция \"else\" без \"if\" " msgid "Instructions (\\key help;)" @@ -795,6 +772,9 @@ msgstr "Шагающий стрелок" msgid "Legged sniffer" msgstr "Шагающий искатель" +msgid "Levels in this chapter:" +msgstr "Упражнения в разделе:" + msgid "Lightning conductor" msgstr "Громоотвод" @@ -854,6 +834,9 @@ msgstr "Название миссии" msgid "Missions" msgstr "Миссии" +msgid "Missions on this planet:" +msgstr "Миссии на этой планете:" + msgid "Missions\\Select mission" msgstr "Миссии\\Выбор миссии" @@ -1012,11 +995,11 @@ msgstr "Один шаг" msgid "Open" msgstr "Открыть" -msgid "Open (Ctrl+o)" -msgstr "Открыть (Ctrl+o)" +msgid "Open (Ctrl+O)" +msgstr "Открыть (Ctrl+O)" -msgid "Opening brace missing " -msgstr "Открывающая скобка отсутствует " +msgid "Opening brace missing" +msgstr "Открывающая скобка отсутствует" msgid "Opening bracket missing" msgstr "Открывающая скобка отсутствует" @@ -1034,22 +1017,23 @@ msgid "Organic matter" msgstr "Органическое вещество" msgid "Origin of last message\\Shows where the last message was sent from" -msgstr "" -"Источник сообщения\\Показывает место, откуда было отправлено последнеее " -"сообщение" +msgstr "Источник сообщения\\Показывает место, откуда было отправлено последнеее сообщение" msgid "Original game developed by:" msgstr "Оригинальная игра была разработана:" -msgid "Parameters missing " -msgstr "Отсутствуют параметры " +msgid "Parameters missing" +msgstr "Отсутствуют параметры" msgid "Particles in the interface\\Steam clouds and sparks in the interface" msgstr "Частицы в интерфейсе меню\\Пар из труб и искры в интерфейсе меню" -msgid "Paste (Ctrl+v)" +msgid "Paste (Ctrl+V)" msgstr "Вставить (Ctrl+V)" +msgid "Pause blur\\Blur the background on the pause screen" +msgstr "" + msgid "Pause in background\\Pause the game when the window is unfocused" msgstr "" @@ -1068,6 +1052,9 @@ msgstr "Фотография" msgid "Place occupied" msgstr "Место занято" +msgid "Planets:" +msgstr "Планеты:" + msgid "Plans for defense tower available" msgstr "Доступны схемы защитной башни" @@ -1086,8 +1073,8 @@ msgstr "Доступны схемы стрелка" msgid "Plans for thumper available" msgstr "Доступны схемы ударника" -msgid "Plans for tracked robots available " -msgstr "Доступны схемы гусеничных роботов " +msgid "Plans for tracked robots available" +msgstr "Доступны схемы гусеничных роботов" msgid "Plant a flag" msgstr "Установить флаг" @@ -1159,12 +1146,11 @@ msgstr "Упражнения" msgid "Programming help" msgstr "Помощь в программировании" -msgid "Programming help (\\key prog;)" +msgid "Programming help (\\key prog;)" msgstr "Помощь в программировании (\\key prog;)" msgid "Programming help\\Gives more detailed help with programming" -msgstr "" -"Помощь в программировании\\Дает более детальную помощь в программировании" +msgstr "Помощь в программировании\\Дает более детальную помощь в программировании" msgid "Programs dispatched by Houston" msgstr "Программы переданные с Хьюстона" @@ -1240,6 +1226,9 @@ msgstr "Резервное ключевое слово языка CBOT" msgid "Resolution" msgstr "Разрешение" +msgid "Resolution:" +msgstr "Разрешение:" + msgid "Resources" msgstr "" @@ -1300,13 +1289,13 @@ msgstr "Спутниковый отчет" msgid "Save" msgstr "Сохранить" -msgid "Save (Ctrl+s)" -msgstr "Сохранить (Ctrl+s)" +msgid "Save (Ctrl+S)" +msgstr "Сохранить (Ctrl+S)" msgid "Save the current mission" msgstr "Сохранить" -msgid "Save\\Save the current mission " +msgid "Save\\Save the current mission" msgstr "Сохранить\\Сохранить текущую миссию" msgid "Save\\Saves the current mission" @@ -1415,11 +1404,8 @@ msgstr "Паук смертельно ранен" msgid "Stack overflow" msgstr "Переполнение стека" -msgid "" -"Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" -msgstr "" -"Стандартное действие\\Стандартное действие бота (брать/взять, стрелять, " -"искать и т.д.)" +msgid "Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)" +msgstr "Стандартное действие\\Стандартное действие бота (брать/взять, стрелять, искать и т.д.)" msgid "Standard controls\\Standard key functions" msgstr "Стандартное управление\\Сделать управление по умолчанию" @@ -1452,6 +1438,9 @@ msgstr "Костюм:" msgid "Suit\\Astronaut suit" msgstr "Костюм\\Костюм астронавта" +msgid "Summary:" +msgstr "Итог:" + msgid "Survival kit" msgstr "Аптечка" @@ -1479,15 +1468,13 @@ msgstr "" msgid "The expression must return a boolean value" msgstr "Выражение должно возвращать логическое значение" -msgid "The function returned no value " +msgid "The function returned no value" msgstr "Функция не возвратила значения" -msgid "" -"The mission is not accomplished yet (press \\key help; for more details)" -msgstr "" -"Миссия еще не выполнена (нажмите \\key help; для более подробной информации)" +msgid "The mission is not accomplished yet (press \\key help; for more details)" +msgstr "Миссия еще не выполнена (нажмите \\key help; для более подробной информации)" -msgid "The types of the two operands are incompatible " +msgid "The types of the two operands are incompatible" msgstr "Типы операндов несовместимы" msgid "This class already exists" @@ -1592,7 +1579,7 @@ msgstr "Не задан тип" msgid "Unable to control enemy objects" msgstr "" -msgid "Undo (Ctrl+z)" +msgid "Undo (Ctrl+Z)" msgstr "Отмена (Ctrl+Z)" msgid "Unit" @@ -1703,10 +1690,26 @@ msgstr "Вы не можете нести радиоактивные объек msgid "You can not carry an object under water" msgstr "Вы не можете нести объекты под водой" +#, fuzzy, c-format +msgid "You cannot use \"%s\" in this exercise (used: %d)" +msgstr "Не используй в этом упражнении" + msgid "You found a usable object" msgstr "Вы нашли рабочий объект" -msgid "You must get on the spaceship to take off " +#, fuzzy, 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] "Не используй в этом упражнении" +msgstr[1] "Не используй в этом упражнении" + +#, fuzzy, 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] "Не используй в этом упражнении" +msgstr[1] "Не используй в этом упражнении" + +msgid "You must get on the spaceship to take off" msgstr "Вы должны быть на борту корабля, чтобы взлететь" msgid "Zoom mini-map" @@ -1806,11 +1809,10 @@ msgid "\\Yellow flags" msgstr "\\Желтый флаг" msgid "colobot.info" -msgstr "" +msgstr "colobot.info" -#, fuzzy msgid "epsitec.com" -msgstr "www.epsitec.com" +msgstr "epsitec.com" #~ msgid " " #~ msgstr " " @@ -1821,6 +1823,9 @@ msgstr "www.epsitec.com" #~ msgid " Missions on this level:" #~ msgstr " Миссии на этом уровне:" +#~ msgid "\"%s\" missing in this exercise" +#~ msgstr "\"%s\" отсутствует в этом упражнении" + #~ msgid "3D sound\\3D positioning of the sound" #~ msgstr "3D-звук\\Стерео звук" @@ -1830,6 +1835,18 @@ msgstr "www.epsitec.com" #~ msgid "COLOBOT" #~ msgstr "КОЛОБОТ" +#~ msgid "Camera awayest" +#~ msgstr "Отдалить камеру" + +#~ msgid "Camera nearest" +#~ msgstr "Приблизить камеру" + +#~ msgid "Camera to left" +#~ msgstr "Камеру влево" + +#~ msgid "Camera to right" +#~ msgstr "Камеру вправо" + #~ msgid "Can not create this; there are too many objects" #~ msgstr "Не удается это создать, слишком много объектов" @@ -1912,11 +1929,8 @@ msgstr "www.epsitec.com" #~ msgid "Textures\\Quality of textures " #~ msgstr "Текстуры\\Качество текстур " -#~ msgid "" -#~ "The list is only available if a \\l;radar station\\u object\\radar; is " -#~ "working.\n" -#~ msgstr "" -#~ "Список доступен только если \\l;radar station\\u object\\radar; работают\n" +#~ msgid "The list is only available if a \\l;radar station\\u object\\radar; is working.\n" +#~ msgstr "Список доступен только если \\l;radar station\\u object\\radar; работают\n" #~ msgid "Use a joystick\\Joystick or keyboard" #~ msgstr "Использовать джойстик\\Джойстик или клавиатура" diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index d5007d83..70c72ef5 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -19,8 +19,10 @@ #include "CBot/CBotClass.h" +#include "CBot/CBotInstr/CBotInstrUtils.h" #include "CBot/CBotInstr/CBotNew.h" #include "CBot/CBotInstr/CBotLeftExprVar.h" +#include "CBot/CBotInstr/CBotExprLitNull.h" #include "CBot/CBotInstr/CBotTwoOpExpr.h" #include "CBot/CBotInstr/CBotFunction.h" #include "CBot/CBotInstr/CBotExpression.h" @@ -32,6 +34,7 @@ #include "CBot/CBotExternalCall.h" #include "CBot/CBotStack.h" #include "CBot/CBotCStack.h" +#include "CBot/CBotDefParam.h" #include "CBot/CBotUtils.h" #include "CBot/CBotFileUtils.h" #include "CBot/CBotCallMethode.h" @@ -549,6 +552,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) while (pStack->IsOk()) { + CBotTypResult type2 = CBotTypResult(type); // reset type after comma std::string pp = p->GetString(); if ( IsOfType(p, ID_NOT) ) { @@ -561,29 +565,27 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) while ( IsOfType( p, ID_OPBRK ) ) // a table? { CBotInstr* i = nullptr; - + pStack->SetStartError( p->GetStart() ); if ( p->GetType() != ID_CLBRK ) + { i = CBotExpression::Compile( p, pStack ); // expression for the value + if (i == nullptr || pStack->GetType() != CBotTypInt) // must be a number + { + pStack->SetError(CBotErrBadIndex, p->GetStart()); + return false; + } + } else i = new CBotEmpty(); // special if not a formula - type = CBotTypResult(CBotTypArrayPointer, type); - - if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) ) - { - pStack->SetError(CBotErrCloseIndex, p->GetStart()); - return false; - } - -/* CBotVar* pv = pStack->GetVar(); - if ( pv->GetType()>= CBotTypBoolean ) - { - pStack->SetError(CBotErrBadType1, p->GetStart()); - return false; - }*/ + type2 = CBotTypResult(CBotTypArrayPointer, type2); if (limites == nullptr) limites = i; else limites->AddNext3(i); + + if (IsOfType(p, ID_CLBRK)) continue; + pStack->SetError(CBotErrCloseIndex, p->GetStart()); + return false; } if ( p->GetType() == ID_OPENPAR ) @@ -604,9 +606,14 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) // return a method precompiled in pass 1 CBotFunction* pf = m_pMethod; CBotFunction* prev = nullptr; - while ( pf != nullptr ) + CBotToken* ppp = p; + CBotCStack* pStk = pStack->TokenStack(nullptr, true); + CBotDefParam* params = CBotDefParam::Compile(p, pStk ); + delete pStk; + p = ppp; + while ( pf != nullptr ) // search by name and parameters { - if (pf->GetName() == pp) break; + if (pf->GetName() == pp && pf->CheckParam( params )) break; prev = pf; pf = pf->Next(); } @@ -672,7 +679,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) } // definition of an element - if (type.Eq(0)) + if (type2.Eq(0)) { pStack->SetError(CBotErrNoTerminator, p); return false; @@ -681,22 +688,47 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) CBotInstr* i = nullptr; if ( IsOfType(p, ID_ASS ) ) { - if ( type.Eq(CBotTypArrayPointer) ) + pStack->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) { - i = CBotListArray::Compile(p, pStack, type.GetTypElem()); + pStack->SetError(CBotErrNoExpression, p->GetStart()); + return false; + } + if ( type2.Eq(CBotTypArrayPointer) ) + { + if ( nullptr == (i = CBotListArray::Compile(p, pStack, type2.GetTypElem())) ) + { + if (pStack->IsOk()) + { + i = CBotTwoOpExpr::Compile(p, pStack); + if (i == nullptr || !pStack->GetTypResult().Compare(type2)) + { + pStack->SetError(CBotErrBadType1, p->GetStart()); + return false; + } + } + } } else { // it has an assignmet to calculate i = CBotTwoOpExpr::Compile(p, pStack); + + if ( !(type.Eq(CBotTypPointer) && pStack->GetTypResult().Eq(CBotTypNullPointer)) && + !TypesCompatibles( type2, pStack->GetTypResult()) ) + { + pStack->SetError(CBotErrBadType1, p->GetStart()); + return false; + } } if ( !pStack->IsOk() ) return false; } + else if ( type2.Eq(CBotTypArrayPointer) ) i = new CBotExprLitNull(); if ( !bSecond ) { - CBotVar* pv = CBotVar::Create(pp, type); + CBotVar* pv = CBotVar::Create(pp, type2); pv -> SetStatic( bStatic ); pv -> SetPrivate( mProtect ); @@ -709,8 +741,15 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) if ( pv->IsStatic() && pv->m_InitExpr != nullptr ) { CBotStack* pile = CBotStack::AllocateStack(); // independent stack - while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer - pv->SetVal( pile->GetVar() ) ; + if ( type2.Eq(CBotTypArrayPointer) ) + { + while(pile->IsOk() && !pv->m_InitExpr->Execute(pile, pv)); + } + else + { + while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer + pv->SetVal( pile->GetVar() ) ; + } pile->Delete(); } } diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h index 475648a3..24e0095b 100644 --- a/src/CBot/CBotEnums.h +++ b/src/CBot/CBotEnums.h @@ -235,6 +235,7 @@ enum CBotError : int CBotErrBadIndex = 5040, //!< wrong index type "[ false ]" CBotErrPrivate = 5041, //!< protected item CBotErrNoPublic = 5042, //!< missing word "public" + CBotErrNoExpression = 5043, //!< expression expected after = // Runtime errors CBotErrZeroDiv = 6000, //!< division by zero diff --git a/src/CBot/CBotInstr/CBotDefArray.cpp b/src/CBot/CBotInstr/CBotDefArray.cpp index 2cb05aa0..c1995d92 100644 --- a/src/CBot/CBotInstr/CBotDefArray.cpp +++ b/src/CBot/CBotInstr/CBotDefArray.cpp @@ -72,19 +72,26 @@ CBotInstr* CBotDefArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResul CBotInstr* i; while (IsOfType(p, ID_OPBRK)) { + pStk->SetStartError(p->GetStart()); if (p->GetType() != ID_CLBRK) - i = CBotExpression::Compile(p, pStk); // expression for the value + { + i = CBotExpression::Compile(p, pStk); // expression for the value + if (i == nullptr || pStk->GetType() != CBotTypInt) // must be a number + { + pStk->SetError(CBotErrBadIndex, p->GetStart()); + goto error; + } + } else i = new CBotEmpty(); // if no special formula inst->AddNext3b(i); // construct a list type = CBotTypResult(CBotTypArrayPointer, type); - if (!pStk->IsOk() || !IsOfType(p, ID_CLBRK )) - { - pStk->SetError(CBotErrCloseIndex, p->GetStart()); - goto error; - } + if (IsOfType(p, ID_CLBRK)) continue; + + pStk->SetError(CBotErrCloseIndex, p->GetStart()); + goto error; } CBotVar* var = CBotVar::Create(*vartoken, type); // create an instance @@ -96,17 +103,32 @@ CBotInstr* CBotDefArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResul if (IsOfType(p, ID_ASS)) // with an assignment { - if ((inst->m_listass = CBotTwoOpExpr::Compile(p, pStk)) != nullptr) + pStk->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) { - if (!pStk->GetTypResult().Compare(type)) // compatible type ? + pStk->SetError(CBotErrNoExpression, p->GetPrev()); + goto error; + } + if ( nullptr == (inst->m_listass = CBotListArray::Compile(p, pStk, type.GetTypElem())) ) + { + if (pStk->IsOk()) { - pStk->SetError(CBotErrBadType1, p->GetStart()); - goto error; + inst->m_listass = CBotTwoOpExpr::Compile(p, pStk); + if (inst->m_listass == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ? + { + pStk->SetError(CBotErrBadType1, p->GetStart()); + goto error; + } } } - else + + if (pStk->IsOk()) while (true) // mark initialized { - inst->m_listass = CBotListArray::Compile(p, pStk, type.GetTypElem()); + var = var->GetItem(0, true); + if (var == nullptr) break; + if (var->GetType() == CBotTypArrayPointer) continue; + if (var->GetType() <= CBotTypString) var->SetInit(CBotVar::InitType::DEF); + break; } } diff --git a/src/CBot/CBotInstr/CBotDefBoolean.cpp b/src/CBot/CBotInstr/CBotDefBoolean.cpp index bcac0722..e89bdc83 100644 --- a/src/CBot/CBotInstr/CBotDefBoolean.cpp +++ b/src/CBot/CBotInstr/CBotDefBoolean.cpp @@ -82,16 +82,17 @@ CBotInstr* CBotDefBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, inst = static_cast(CBotDefArray::Compile(p, pStk, CBotTypBoolean)); - if (!pStk->IsOk() ) - { - pStk->SetError(CBotErrCloseIndex, p->GetStart()); - goto error; - } goto suite; // no assignment, variable already created } if (IsOfType(p, ID_ASS)) { + pStk->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) + { + pStk->SetError(CBotErrNoExpression, p->GetStart()); + goto error; + } if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) { goto error; @@ -109,7 +110,7 @@ CBotInstr* CBotDefBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, (static_cast(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); pStack->AddVar(var); suite: - if (IsOfType(p, ID_COMMA)) + if (pStk->IsOk() && IsOfType(p, ID_COMMA)) { if (nullptr != ( inst->m_next2b = CBotDefBoolean::Compile(p, pStk, true, noskip))) { diff --git a/src/CBot/CBotInstr/CBotDefClass.cpp b/src/CBot/CBotInstr/CBotDefClass.cpp index 39ac6afa..f7ea77a6 100644 --- a/src/CBot/CBotInstr/CBotDefClass.cpp +++ b/src/CBot/CBotInstr/CBotDefClass.cpp @@ -101,11 +101,6 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p inst = static_cast(CBotDefArray::Compile(p, pStk, type )); - if (!pStk->IsOk() ) - { - pStk->SetError(CBotErrCloseIndex, p->GetStart()); - goto error; - } goto suite; // no assignment, variable already created } @@ -159,12 +154,19 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p if (IsOfType(p, ID_ASS)) // with a assignment? { + pStk->SetStartError(p->GetStart()); if (inst->m_hasParams) { pStk->SetError(CBotErrNoTerminator, p->GetStart()); goto error; } + if ( IsOfType(p, ID_SEP) ) + { + pStk->SetError(CBotErrNoExpression, p->GetStart()); + goto error; + } + if ( nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) ) { goto error; @@ -200,7 +202,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p var->SetInit(CBotVar::InitType::IS_POINTER); // marks the pointer as init } suite: - if (IsOfType(p, ID_COMMA)) // several chained definitions + if (pStk->IsOk() && IsOfType(p, ID_COMMA)) // several chained definitions { if ( nullptr != ( inst->m_next = CBotDefClass::Compile(p, pStk, pClass) )) // compiles the following { @@ -208,7 +210,7 @@ suite: } } - if (IsOfType(p, ID_SEP)) // complete instruction + if (!pStk->IsOk() || IsOfType(p, ID_SEP)) // complete instruction { return pStack->Return(inst, pStk); } diff --git a/src/CBot/CBotInstr/CBotDefFloat.cpp b/src/CBot/CBotInstr/CBotDefFloat.cpp index 9a99662f..17466581 100644 --- a/src/CBot/CBotInstr/CBotDefFloat.cpp +++ b/src/CBot/CBotInstr/CBotDefFloat.cpp @@ -81,16 +81,17 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b p = vartoken; inst = static_cast(CBotDefArray::Compile(p, pStk, CBotTypFloat)); - if (!pStk->IsOk() ) - { - pStk->SetError(CBotErrCloseIndex, p->GetStart()); - goto error; - } goto suite; // no assignment, variable already created } if (IsOfType(p, ID_ASS)) { + pStk->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) + { + pStk->SetError(CBotErrNoExpression, p->GetStart()); + goto error; + } if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) { goto error; @@ -108,7 +109,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b (static_cast(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); pStack->AddVar(var); suite: - if (IsOfType(p, ID_COMMA)) + if (pStk->IsOk() && IsOfType(p, ID_COMMA)) { if (nullptr != ( inst->m_next2b = CBotDefFloat::Compile(p, pStk, true, noskip))) { diff --git a/src/CBot/CBotInstr/CBotDefInt.cpp b/src/CBot/CBotInstr/CBotDefInt.cpp index 360eb22b..4e946e9b 100644 --- a/src/CBot/CBotInstr/CBotDefInt.cpp +++ b/src/CBot/CBotInstr/CBotDefInt.cpp @@ -84,25 +84,18 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, CBotTypInt); - if (!pStk->IsOk() ) - { - pStk->SetError(CBotErrCloseIndex, p->GetStart()); - goto error; - } - - if (IsOfType(p, ID_COMMA)) // several definition chained - { - if (nullptr != ( inst2->m_next2b = CBotDefInt::Compile(p, pStk, true, noskip))) // compile the next one - { - return pStack->Return(inst2, pStk); - } - } inst = static_cast(inst2); goto suite; // no assignment, variable already created } if (IsOfType(p, ID_ASS)) // with an assignment? { + pStk->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) + { + pStk->SetError(CBotErrNoExpression, p->GetStart()); + goto error; + } if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) { goto error; @@ -121,15 +114,15 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo (static_cast(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); pStack->AddVar(var); // place it on the stack } - - if (IsOfType(p, ID_COMMA)) // chained several definitions +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 { return pStack->Return(inst, pStk); } } -suite: + if (noskip || IsOfType(p, ID_SEP)) // instruction is completed { return pStack->Return(inst, pStk); diff --git a/src/CBot/CBotInstr/CBotDefString.cpp b/src/CBot/CBotInstr/CBotDefString.cpp index c878a84c..9bf2eebe 100644 --- a/src/CBot/CBotInstr/CBotDefString.cpp +++ b/src/CBot/CBotInstr/CBotDefString.cpp @@ -20,6 +20,7 @@ #include "CBot/CBotInstr/CBotDefString.h" #include "CBot/CBotInstr/CBotLeftExprVar.h" +#include "CBot/CBotInstr/CBotDefArray.h" #include "CBot/CBotInstr/CBotTwoOpExpr.h" #include "CBot/CBotStack.h" @@ -61,6 +62,7 @@ CBotInstr* CBotDefString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, inst->m_expr = nullptr; CBotToken* vartoken = p; + CBotVar* var = nullptr; inst->SetToken(vartoken); if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) @@ -73,8 +75,27 @@ CBotInstr* CBotDefString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, goto error; } + if (IsOfType(p, ID_OPBRK)) + { + delete inst; // type is not CBotDefString + p = vartoken; // returns the variable name + + // compiles an array declaration + + CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, CBotTypString); + + inst = static_cast(inst2); + goto suite; // no assignment, variable already created + } + if (IsOfType(p, ID_ASS)) { + pStk->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) + { + pStk->SetError(CBotErrNoExpression, p->GetStart()); + goto error; + } if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) { goto error; @@ -86,13 +107,13 @@ CBotInstr* CBotDefString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, }*/ } - CBotVar* var = CBotVar::Create(*vartoken, CBotTypString); + var = CBotVar::Create(*vartoken, CBotTypString); var->SetInit(inst->m_expr != nullptr ? CBotVar::InitType::DEF : CBotVar::InitType::UNDEF); var->SetUniqNum( (static_cast(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); pStack->AddVar(var); - - if (IsOfType(p, ID_COMMA)) +suite: + if (pStk->IsOk() && IsOfType(p, ID_COMMA)) { if (nullptr != ( inst->m_next2b = CBotDefString::Compile(p, pStk, true, noskip))) { diff --git a/src/CBot/CBotInstr/CBotExpression.cpp b/src/CBot/CBotInstr/CBotExpression.cpp index cb7f3dfc..c98deca5 100644 --- a/src/CBot/CBotInstr/CBotExpression.cpp +++ b/src/CBot/CBotInstr/CBotExpression.cpp @@ -71,6 +71,13 @@ CBotInstr* CBotExpression::Compile(CBotToken* &p, CBotCStack* pStack) return nullptr; } + if ( p->GetType() == ID_SEP ) + { + pStack->SetError(CBotErrNoExpression, p); + delete inst; + return nullptr; + } + inst->m_rightop = CBotExpression::Compile(p, pStack); if (inst->m_rightop == nullptr) { @@ -118,13 +125,13 @@ CBotInstr* CBotExpression::Compile(CBotToken* &p, CBotCStack* pStack) break; case ID_ASSADD: if (type2.Eq(CBotTypBoolean) || - type2.Eq(CBotTypPointer) ) type2 = -1; // numbers and strings + type2.GetType() > CBotTypString ) type2.SetType(-1); // numbers and strings break; case ID_ASSSUB: case ID_ASSMUL: case ID_ASSDIV: case ID_ASSMODULO: - if (type2.GetType() >= CBotTypBoolean) type2 = -1; // numbers only + if (type2.GetType() >= CBotTypBoolean) type2.SetType(-1); // numbers only break; } @@ -179,6 +186,18 @@ bool CBotExpression::Execute(CBotStack* &pj) if ( pile2->GetState()==0) { if (m_rightop && !m_rightop->Execute(pile2)) return false; // initial value // interrupted? + if (m_rightop) + { + CBotVar* var = pile1->GetVar(); + CBotVar* value = pile2->GetVar(); + if (var->GetType() == CBotTypString && value->GetType() != CBotTypString) + { + CBotVar* newVal = CBotVar::Create("", var->GetTypResult()); + value->Update(pj->GetUserPtr()); + newVal->SetValString(value->GetValString()); + pile2->SetVar(newVal); + } + } pile2->IncState(); } diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 4c016d3b..4c15a416 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -840,8 +840,8 @@ bool CBotFunction::CheckParam(CBotDefParam* pParam) CBotDefParam* pp = m_param; while ( pp != nullptr && pParam != nullptr ) { - CBotTypResult type1 = pp->GetType(); - CBotTypResult type2 = pParam->GetType(); + CBotTypResult type1 = pp->GetTypResult(); + CBotTypResult type2 = pParam->GetTypResult(); if ( !type1.Compare(type2) ) return false; pp = pp->GetNext(); pParam = pParam->GetNext(); diff --git a/src/CBot/CBotInstr/CBotInstrMethode.cpp b/src/CBot/CBotInstr/CBotInstrMethode.cpp index 52a58cca..3bdf8492 100644 --- a/src/CBot/CBotInstr/CBotInstrMethode.cpp +++ b/src/CBot/CBotInstr/CBotInstrMethode.cpp @@ -103,6 +103,7 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre if (pVar->GetPointer() == nullptr) { pj->SetError(CBotErrNull, prevToken); + return pj->Return(pile1); } if (pile1->IfStep()) return false; @@ -119,7 +120,7 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre pThis->SetName("this"); pThis->SetUniqNum(-2); - pile1->AddVar(pThis); + pile1->SetVar(pThis); pile1->IncState(); } int i = 0; @@ -144,7 +145,7 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre ppVars[i] = nullptr; CBotClass* pClass = CBotClass::Find(m_className); - CBotVar* pThis = pile1->FindVar(-2, false); + CBotVar* pThis = pile1->GetVar(); CBotVar* pResult = nullptr; if (m_typRes.GetType() > 0) pResult = CBotVar::Create("", m_typRes); if (m_typRes.Eq(CBotTypClass)) @@ -174,7 +175,10 @@ void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain) CBotStack* pile2 = pile1->RestoreStack(); // and for the parameters coming if (pile2 == nullptr) return; - CBotVar* pThis = pile1->FindVar("this"); + CBotVar* pThis = pile1->GetVar(); + + assert(pThis != nullptr); // see fix for issues #256 & #436 + pThis->SetUniqNum(-2); int i = 0; @@ -226,7 +230,7 @@ bool CBotInstrMethode::Execute(CBotStack* &pj) // Test.Action (Test = Other); // Action must act on the value before test = Other! pThis->SetName("this"); - pile1->AddVar(pThis); + pile1->SetVar(pThis); pile1->IncState(); } int i = 0; @@ -250,7 +254,7 @@ bool CBotInstrMethode::Execute(CBotStack* &pj) ppVars[i] = nullptr; CBotClass* pClass = CBotClass::Find(m_className); - CBotVar* pThis = pile1->FindVar("this"); + CBotVar* pThis = pile1->GetVar(); CBotVar* pResult = nullptr; if (m_typRes.GetType()>0) pResult = CBotVar::Create("", m_typRes); if (m_typRes.Eq(CBotTypClass)) diff --git a/src/CBot/CBotInstr/CBotInstrUtils.cpp b/src/CBot/CBotInstr/CBotInstrUtils.cpp index 05de1a47..bbe80b27 100644 --- a/src/CBot/CBotInstr/CBotInstrUtils.cpp +++ b/src/CBot/CBotInstr/CBotInstrUtils.cpp @@ -97,9 +97,9 @@ bool TypeCompatible(CBotTypResult& type1, CBotTypResult& type2, int op) if (max == 99) return false; // result is void? // special case for strin concatenation - if (op == ID_ADD && max >= CBotTypString) return true; - if (op == ID_ASSADD && max >= CBotTypString) return true; - if (op == ID_ASS && t1 == CBotTypString) return true; + if (op == ID_ADD && t1 == CBotTypString) return true; + if (op == ID_ASSADD && t2 == CBotTypString) return true; + if (op == ID_ASS && t2 == CBotTypString) return true; if (max >= CBotTypBoolean) { diff --git a/src/CBot/CBotInstr/CBotInstrUtils.h b/src/CBot/CBotInstr/CBotInstrUtils.h index a609988d..b5302883 100644 --- a/src/CBot/CBotInstr/CBotInstrUtils.h +++ b/src/CBot/CBotInstr/CBotInstrUtils.h @@ -39,7 +39,13 @@ CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars); /*! * \brief TypeCompatible Check if two results are consistent to make an - * operation. + * operation. TypeCompatible is used in two ways: + * For non-assignment operations: see CBotTwoOpExpr::Compile + * TypeCompatible( leftType, rightType, opType ) + + * For assignment or compound assignment operations (it's reversed): + * see CBotReturn::Compile & CBotExpression::Compile + * TypeCompatible( valueType, varType, opType ) * \param type1 * \param type2 * \param op diff --git a/src/CBot/CBotInstr/CBotLeftExprVar.cpp b/src/CBot/CBotInstr/CBotLeftExprVar.cpp index 848d16a8..4394fc43 100644 --- a/src/CBot/CBotInstr/CBotLeftExprVar.cpp +++ b/src/CBot/CBotInstr/CBotLeftExprVar.cpp @@ -64,6 +64,12 @@ bool CBotLeftExprVar::Execute(CBotStack* &pj) CBotVar* var2 = pj->GetVar(); // Initial value on the stack if (var2 != nullptr) { + if (m_typevar.Eq(CBotTypString) && var2->GetType() != CBotTypString) + { + var2->Update(pj->GetUserPtr()); + var1->SetValString(var2->GetValString()); + return true; + } var1->SetVal(var2); // Set the value } diff --git a/src/CBot/CBotInstr/CBotListArray.cpp b/src/CBot/CBotInstr/CBotListArray.cpp index 20a34e6e..89cbb79a 100644 --- a/src/CBot/CBotInstr/CBotListArray.cpp +++ b/src/CBot/CBotInstr/CBotListArray.cpp @@ -51,12 +51,13 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu CBotToken* pp = p; - if (IsOfType( p, ID_NULL )) + if (IsOfType( p, ID_NULL ) || (IsOfType(p, ID_OPBLK) && IsOfType(p, ID_CLBLK))) { CBotInstr* inst = new CBotExprLitNull(); inst->SetToken(pp); return pStack->Return(inst, pStk); // ok with empty element } + p = pp; CBotListArray* inst = new CBotListArray(); @@ -65,25 +66,45 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu // each element takes the one after the other if (type.Eq( CBotTypArrayPointer )) { - type = type.GetTypElem(); - pStk->SetStartError(p->GetStart()); - if (nullptr == ( inst->m_expr = CBotListArray::Compile( p, pStk, type ) )) + if (nullptr == ( inst->m_expr = CBotListArray::Compile( p, pStk, type.GetTypElem() ) )) { - goto error; + if (pStk->IsOk()) + { + inst->m_expr = CBotTwoOpExpr::Compile(p, pStk); + if (inst->m_expr == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ? + { + pStk->SetError(CBotErrBadType1, p->GetStart()); + goto error; + } + } } while (IsOfType( p, ID_COMMA )) // other elements? { pStk->SetStartError(p->GetStart()); - CBotInstr* i = CBotListArray::Compile(p, pStk, type); - if (nullptr == i) + CBotInstr* i = nullptr; + if (nullptr == ( i = CBotListArray::Compile(p, pStk, type.GetTypElem() ) )) { - goto error; + if (pStk->IsOk()) + { + i = CBotTwoOpExpr::Compile(p, pStk); + if (i == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ? + { + pStk->SetError(CBotErrBadType1, p->GetStart()); + goto error; + } + } } - inst->m_expr->AddNext3(i); + inst->m_expr->AddNext3b(i); + + if ( p->GetType() == ID_COMMA ) continue; + if ( p->GetType() == ID_CLBLK ) break; + + pStk->SetError(CBotErrClosePar, p); + goto error; } } else @@ -93,9 +114,10 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu { goto error; } - CBotVar* pv = pStk->GetVar(); // result of the expression - if (pv == nullptr || !TypesCompatibles( type, pv->GetTypResult())) // compatible type? + CBotTypResult valType = pStk->GetTypResult(); + + if (!TypeCompatible(valType, type, ID_ASS) ) { pStk->SetError(CBotErrBadType1, p->GetStart()); goto error; @@ -111,14 +133,20 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu goto error; } - CBotVar* pv = pStk->GetVar(); // result of the expression + CBotTypResult valType = pStk->GetTypResult(); - if (pv == nullptr || !TypesCompatibles( type, pv->GetTypResult())) // compatible type? + if (!TypeCompatible(valType, type, ID_ASS) ) { pStk->SetError(CBotErrBadType1, p->GetStart()); goto error; } - inst->m_expr->AddNext3(i); + inst->m_expr->AddNext3b(i); + + if (p->GetType() == ID_COMMA) continue; + if (p->GetType() == ID_CLBLK) break; + + pStk->SetError(CBotErrClosePar, p); + goto error; } } @@ -146,7 +174,7 @@ bool CBotListArray::Execute(CBotStack* &pj, CBotVar* pVar) int n = 0; - for (; p != nullptr ; n++, p = p->GetNext3()) + for (; p != nullptr ; n++, p = p->GetNext3b()) { if (pile1->GetState() > n) continue; @@ -178,7 +206,7 @@ void CBotListArray::RestoreState(CBotStack* &pj, bool bMain) int state = pile->GetState(); - while(state-- > 0) p = p->GetNext3() ; + while(state-- > 0) p = p->GetNext3b() ; p->RestoreState(pile, bMain); // size calculation //interrupted! } diff --git a/src/CBot/CBotInstr/CBotListArray.h b/src/CBot/CBotInstr/CBotListArray.h index c5f800b0..18d6b567 100644 --- a/src/CBot/CBotInstr/CBotListArray.h +++ b/src/CBot/CBotInstr/CBotListArray.h @@ -62,7 +62,7 @@ protected: virtual std::map GetDebugLinks() override; private: - //! An expression for an element others are linked with CBotInstr :: m_next3; + //! An expression for an element others are linked with CBotInstr :: m_next3b; CBotInstr* m_expr; }; diff --git a/src/CBot/CBotInstr/CBotNew.cpp b/src/CBot/CBotInstr/CBotNew.cpp index 7da8e417..a302b394 100644 --- a/src/CBot/CBotInstr/CBotNew.cpp +++ b/src/CBot/CBotInstr/CBotNew.cpp @@ -50,7 +50,11 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack) if (!IsOfType(p, ID_NEW)) return nullptr; // verifies that the token is a class name - if (p->GetType() != TokenTypVar) return nullptr; + if (p->GetType() != TokenTypVar) + { + pStack->SetError(CBotErrBadNew, p); + return nullptr; + } CBotClass* pClass = CBotClass::Find(p); if (pClass == nullptr) diff --git a/src/CBot/CBotInstr/CBotTwoOpExpr.cpp b/src/CBot/CBotInstr/CBotTwoOpExpr.cpp index 23e11531..41321032 100644 --- a/src/CBot/CBotInstr/CBotTwoOpExpr.cpp +++ b/src/CBot/CBotInstr/CBotTwoOpExpr.cpp @@ -214,6 +214,13 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera type2 = pStk->GetTypResult(); // what kind of results? + if ( type1.Eq(99) || type2.Eq(99) ) // operand is void + { + pStack->SetError(CBotErrBadType2, &inst->m_token); + delete inst; + return nullptr; + } + // what kind of result? int TypeRes = std::max( type1.GetType(CBotTypResult::GetTypeMode::NULL_AS_POINTER), type2.GetType(CBotTypResult::GetTypeMode::NULL_AS_POINTER) ); if (typeOp == ID_ADD && type1.Eq(CBotTypString)) @@ -267,7 +274,7 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera return pStack->Return(nullptr, pStk); } - if ( TypeRes != CBotTypString ) + if ( TypeRes != CBotTypString ) // keep string conversion TypeRes = std::max(type1.GetType(), type2.GetType()); inst = i; } @@ -370,7 +377,9 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack) // what kind of result? int TypeRes = std::max(type1.GetType(), type2.GetType()); - if ( GetTokenType() == ID_ADD && type1.Eq(CBotTypString) ) + // see "any type convertible chain" in compile method + if ( GetTokenType() == ID_ADD && + (type1.Eq(CBotTypString) || type2.Eq(CBotTypString)) ) { TypeRes = CBotTypString; } @@ -397,7 +406,8 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack) CBotVar* result = CBotVar::Create("", TypeRes); // creates a variable to perform the calculation in the appropriate type - TypeRes = std::max(type1.GetType(), type2.GetType()); + if ( TypeRes != CBotTypString ) // keep string conversion + TypeRes = std::max(type1.GetType(), type2.GetType()); if ( GetTokenType() == ID_ADD && type1.Eq(CBotTypString) ) { diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index dde36bb4..d0284ea2 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -214,6 +214,7 @@ bool CBotProgram::Run(void* pUser, int timer) m_error = m_stack->GetError(m_errorStart, m_errorEnd); m_stack->Delete(); m_stack = nullptr; + CBotClass::FreeLock(this); return true; // execution is finished! } @@ -226,6 +227,7 @@ void CBotProgram::Stop() m_stack->Delete(); m_stack = nullptr; m_entryPoint = nullptr; + CBotClass::FreeLock(this); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/CBot/CBotProgram.h b/src/CBot/CBotProgram.h index 2b477bda..9f5cdc00 100644 --- a/src/CBot/CBotProgram.h +++ b/src/CBot/CBotProgram.h @@ -143,7 +143,7 @@ public: * \param[out] code Error code * \param[out] start Starting position in the code string of this error * \param[out] end Ending position in the code string of this error - * \return false if no error has occured + * \return false if no error has occurred */ bool GetError(CBotError& code, int& start, int& end); @@ -153,7 +153,7 @@ public: * \param[out] start Starting position in the code string of this error * \param[out] end Ending position in the code string of this error * \param[out] pProg Program that caused the error (TODO: This always returns "this"... what?) - * \return false if no error has occured + * \return false if no error has occurred */ bool GetError(CBotError& code, int& start, int& end, CBotProgram*& pProg); diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index 746976b0..3170fb72 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -805,6 +805,8 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) CBotToken token(name, std::string()); + bool isClass = false; + switch (w) { case CBotTypInt: @@ -826,6 +828,7 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) // returns an intrinsic object or element of an array case CBotTypIntrinsic: + isClass = true; case CBotTypArrayBody: { CBotTypResult r; @@ -843,6 +846,17 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) if ( !RestoreState(pf, (static_cast(pNew))->m_pVar)) return false; pNew->SetIdent(id); + if (isClass && p == nullptr) // set id for each item in this instance + { + CBotVar* pVars = pNew->GetItemList(); + long itemId = 1; + while (pVars != nullptr) + { + pVars->m_ident = itemId++; + pVars = pVars->GetNext(); + } + } + if ( p != nullptr ) { delete pNew; diff --git a/src/CBot/CBotStack.h b/src/CBot/CBotStack.h index 1d7c7884..6cd8e567 100644 --- a/src/CBot/CBotStack.h +++ b/src/CBot/CBotStack.h @@ -105,7 +105,7 @@ public: /** * \brief Check if there was an error - * \return false if an error occured + * \return false if an error occurred * \see GetError() */ bool IsOk() diff --git a/src/CBot/CBotVar/CBotVar.cpp b/src/CBot/CBotVar/CBotVar.cpp index 8876ded2..4e88cd69 100644 --- a/src/CBot/CBotVar/CBotVar.cpp +++ b/src/CBot/CBotVar/CBotVar.cpp @@ -61,6 +61,11 @@ CBotVar::CBotVar( ) m_mPrivate = ProtectionLevel::Public; } +CBotVar::CBotVar(const CBotToken &name) : CBotVar() +{ + m_token = new CBotToken(name); +} + //////////////////////////////////////////////////////////////////////////////// CBotVar::~CBotVar( ) { @@ -698,7 +703,16 @@ void CBotVar::Dec() //////////////////////////////////////////////////////////////////////////////// void CBotVar::Copy(CBotVar* pSrc, bool bName) { - assert(0); + if (bName) *m_token = *pSrc->m_token; + m_type = pSrc->m_type; + m_binit = pSrc->m_binit; +//- m_bStatic = pSrc->m_bStatic; + m_next = nullptr; + m_pMyThis = nullptr;//p->m_pMyThis; + m_pUserPtr = pSrc->m_pUserPtr; + + // keeps indentificator the same (by default) + if (m_ident == 0) m_ident = pSrc->m_ident; } //////////////////////////////////////////////////////////////////////////////// @@ -727,4 +741,39 @@ CBotClass* CBotVar::GetClass() return nullptr; } +CBotVar::operator int() +{ + return GetValInt(); +} + +CBotVar::operator float() +{ + return GetValFloat(); +} + +CBotVar::operator std::string() +{ + return GetValString(); +} + +void CBotVar::operator=(const CBotVar &var) +{ + SetVal(const_cast(&var)); +} + +void CBotVar::operator=(int x) +{ + SetValInt(x); +} + +void CBotVar::operator=(float x) +{ + SetValFloat(x); +} + +void CBotVar::operator=(const std::string &x) +{ + SetValString(x); +} + } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVar.h b/src/CBot/CBotVar/CBotVar.h index a4563b4b..7babb7d1 100644 --- a/src/CBot/CBotVar/CBotVar.h +++ b/src/CBot/CBotVar/CBotVar.h @@ -50,6 +50,11 @@ public: */ CBotVar(); + /** + * \brief Constructor. Do not call directly, use CBotVar::Create() + */ + CBotVar(const CBotToken& name); + /** * \brief Destructor. Do not call directly, use CBotVar::Destroy() */ @@ -439,6 +444,14 @@ public: */ //@{ + operator int(); + operator float(); + operator std::string(); + void operator=(const CBotVar& var); + void operator=(int x); + void operator=(float x); + void operator=(const std::string &x); + /** * \brief Set the value * \param var Another variable to copy value from diff --git a/src/CBot/CBotVar/CBotVarBoolean.cpp b/src/CBot/CBotVar/CBotVarBoolean.cpp index 3a40772a..c9a9b52e 100644 --- a/src/CBot/CBotVar/CBotVarBoolean.cpp +++ b/src/CBot/CBotVar/CBotVarBoolean.cpp @@ -19,137 +19,27 @@ #include "CBot/CBotVar/CBotVarBoolean.h" -#include "CBot/CBotEnums.h" -#include "CBot/CBotUtils.h" - -#include "CBot/CBotToken.h" - namespace CBot { -//////////////////////////////////////////////////////////////////////////////// -CBotVarBoolean::CBotVarBoolean(const CBotToken& name) -{ - m_token = new CBotToken(name); - m_next = nullptr; - m_pMyThis = nullptr; - m_pUserPtr = nullptr; - m_InitExpr = nullptr; - m_LimExpr = nullptr; - m_type = CBotTypBoolean; - m_binit = InitType::UNDEF; - m_bStatic = false; - m_mPrivate = ProtectionLevel::Public; - m_val = 0; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarBoolean::Copy(CBotVar* pSrc, bool bName) -{ - CBotVarBoolean* p = static_cast(pSrc); - - if (bName) *m_token = *p->m_token; - m_type = p->m_type; - m_val = p->m_val; - m_binit = p->m_binit; -//- m_bStatic = p->m_bStatic; - m_next = nullptr; - m_pMyThis = nullptr;//p->m_pMyThis; - m_pUserPtr = p->m_pUserPtr; - - // keeps indentificator the same (by default) - if (m_ident == 0 ) m_ident = p->m_ident; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarBoolean::SetValInt(int val, const std::string& s) -{ - m_val = static_cast(val); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarBoolean::SetValFloat(float val) -{ - m_val = static_cast(val); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -int CBotVarBoolean::GetValInt() -{ - return m_val; -} - -//////////////////////////////////////////////////////////////////////////////// -float CBotVarBoolean::GetValFloat() -{ - return static_cast(m_val); -} - -//////////////////////////////////////////////////////////////////////////////// -std::string CBotVarBoolean::GetValString() -{ - std::string ret; - - std::string res; - - if ( m_binit == CBotVar::InitType::UNDEF ) - { - res = LoadString(TX_UNDEF); - return res; - } - if ( m_binit == CBotVar::InitType::IS_NAN ) - { - res = LoadString(TX_NAN); - return res; - } - - ret = LoadString( m_val > 0 ? ID_TRUE : ID_FALSE ); - return ret; -} - -//////////////////////////////////////////////////////////////////////////////// void CBotVarBoolean::And(CBotVar* left, CBotVar* right) { - m_val = left->GetValInt() && right->GetValInt(); - m_binit = CBotVar::InitType::DEF; + SetValInt(left->GetValInt() && right->GetValInt()); } - -//////////////////////////////////////////////////////////////////////////////// void CBotVarBoolean::Or(CBotVar* left, CBotVar* right) { - m_val = left->GetValInt() || right->GetValInt(); - m_binit = CBotVar::InitType::DEF; + SetValInt(left->GetValInt() || right->GetValInt()); } - -//////////////////////////////////////////////////////////////////////////////// void CBotVarBoolean::XOr(CBotVar* left, CBotVar* right) { - m_val = left->GetValInt() ^ right->GetValInt(); - m_binit = CBotVar::InitType::DEF; + SetValInt(left->GetValInt() ^ right->GetValInt()); } - -//////////////////////////////////////////////////////////////////////////////// void CBotVarBoolean::Not() { - m_val = m_val ? false : true ; + SetValInt(!GetValInt()); } -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarBoolean::Eq(CBotVar* left, CBotVar* right) -{ - return left->GetValInt() == right->GetValInt(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarBoolean::Ne(CBotVar* left, CBotVar* right) -{ - return left->GetValInt() != right->GetValInt(); -} - -//////////////////////////////////////////////////////////////////////////////// bool CBotVarBoolean::Save1State(FILE* pf) { return WriteWord(pf, m_val); // the value of the variable diff --git a/src/CBot/CBotVar/CBotVarBoolean.h b/src/CBot/CBotVar/CBotVarBoolean.h index 6fee80ae..34f627bc 100644 --- a/src/CBot/CBotVar/CBotVarBoolean.h +++ b/src/CBot/CBotVar/CBotVarBoolean.h @@ -19,7 +19,7 @@ #pragma once -#include "CBot/CBotVar/CBotVar.h" +#include "CBot/CBotVar/CBotVarValue.h" namespace CBot { @@ -27,35 +27,17 @@ namespace CBot /** * \brief CBotVar subclass for managing boolean values (::CBotTypBoolean) */ -class CBotVarBoolean : public CBotVar +class CBotVarBoolean : public CBotVarNumberBase { public: - /** - * \brief Constructor. Do not call directly, use CBotVar::Create() - */ - CBotVarBoolean(const CBotToken& name); - - void SetValInt(int val, const std::string& s = nullptr) override; - void SetValFloat(float val) override; - int GetValInt() override; - float GetValFloat() override; - std::string GetValString() override; - - void Copy(CBotVar* pSrc, bool bName = true) override; + CBotVarBoolean(const CBotToken &name) : CBotVarNumberBase(name) {} void And(CBotVar* left, CBotVar* right) override; void Or(CBotVar* left, CBotVar* right) override; void XOr(CBotVar* left, CBotVar* right) override; void Not() override; - bool Eq(CBotVar* left, CBotVar* right) override; - bool Ne(CBotVar* left, CBotVar* right) override; - bool Save1State(FILE* pf) override; - -private: - //! The value. - bool m_val; }; } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarClass.cpp b/src/CBot/CBotVar/CBotVarClass.cpp index 919b43a6..08acffbe 100644 --- a/src/CBot/CBotVar/CBotVarClass.cpp +++ b/src/CBot/CBotVar/CBotVarClass.cpp @@ -343,10 +343,12 @@ std::string CBotVarClass::GetValString() res += " ("; } } + + res += " )"; } else { - res = "( "; + res = "{ "; CBotVar* pv = m_pVar; while ( pv != nullptr ) @@ -355,9 +357,10 @@ std::string CBotVarClass::GetValString() if ( pv->GetNext() != nullptr ) res += ", "; pv = pv->GetNext(); } + + res += " }"; } - res += " )"; return res; } diff --git a/src/CBot/CBotVar/CBotVarFloat.cpp b/src/CBot/CBotVar/CBotVarFloat.cpp index ca178a3a..ae90966a 100644 --- a/src/CBot/CBotVar/CBotVarFloat.cpp +++ b/src/CBot/CBotVar/CBotVarFloat.cpp @@ -19,205 +19,9 @@ #include "CBot/CBotVar/CBotVarFloat.h" -#include "CBot/CBotEnums.h" -#include "CBot/CBotToken.h" - -#include "CBot/CBotUtils.h" - -#include - namespace CBot { -//////////////////////////////////////////////////////////////////////////////// -CBotVarFloat::CBotVarFloat(const CBotToken& name) -{ - m_token = new CBotToken(name); - m_next = nullptr; - m_pMyThis = nullptr; - m_pUserPtr = nullptr; - m_InitExpr = nullptr; - m_LimExpr = nullptr; - m_type = CBotTypFloat; - m_binit = InitType::UNDEF; - m_bStatic = false; - m_mPrivate = ProtectionLevel::Public; - - m_val = 0; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarFloat::Copy(CBotVar* pSrc, bool bName) -{ - CBotVarFloat* p = static_cast(pSrc); - - if (bName) *m_token = *p->m_token; - m_type = p->m_type; - m_val = p->m_val; - m_binit = p->m_binit; -//- m_bStatic = p->m_bStatic; - m_next = nullptr; - m_pMyThis = nullptr;//p->m_pMyThis; - m_pUserPtr = p->m_pUserPtr; - - // keeps indentificator the same (by default) - if (m_ident == 0 ) m_ident = p->m_ident; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarFloat::SetValInt(int val, const std::string& s) -{ - m_val = static_cast(val); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarFloat::SetValFloat(float val) -{ - m_val = val; - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -int CBotVarFloat::GetValInt() -{ - return static_cast(m_val); -} - -//////////////////////////////////////////////////////////////////////////////// -float CBotVarFloat::GetValFloat() -{ - return m_val; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string CBotVarFloat::GetValString() -{ - std::string res; - - if ( m_binit == CBotVar::InitType::UNDEF ) - { - return LoadString(TX_UNDEF); - } - if ( m_binit == CBotVar::InitType::IS_NAN ) - { - return LoadString(TX_NAN); - } - - char buffer[300]; - sprintf(buffer, "%.2f", m_val); - res = buffer; - - return res; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarFloat::Mul(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValFloat() * right->GetValFloat(); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarFloat::Power(CBotVar* left, CBotVar* right) -{ - m_val = static_cast(pow( left->GetValFloat() , right->GetValFloat() )); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -CBotError CBotVarFloat::Div(CBotVar* left, CBotVar* right) -{ - float r = right->GetValFloat(); - if ( r != 0 ) - { - m_val = left->GetValFloat() / r; - m_binit = CBotVar::InitType::DEF; - } - return ( r == 0 ? CBotErrZeroDiv : CBotNoErr ); -} - -//////////////////////////////////////////////////////////////////////////////// -CBotError CBotVarFloat::Modulo(CBotVar* left, CBotVar* right) -{ - float r = right->GetValFloat(); - if ( r != 0 ) - { - m_val = static_cast(fmod( left->GetValFloat() , r )); - m_binit = CBotVar::InitType::DEF; - } - return ( r == 0 ? CBotErrZeroDiv : CBotNoErr ); -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarFloat::Add(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValFloat() + right->GetValFloat(); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarFloat::Sub(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValFloat() - right->GetValFloat(); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarFloat::Neg() -{ - m_val = -m_val; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarFloat::Inc() -{ - m_val++; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarFloat::Dec() -{ - m_val--; -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarFloat::Lo(CBotVar* left, CBotVar* right) -{ - return left->GetValFloat() < right->GetValFloat(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarFloat::Hi(CBotVar* left, CBotVar* right) -{ - return left->GetValFloat() > right->GetValFloat(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarFloat::Ls(CBotVar* left, CBotVar* right) -{ - return left->GetValFloat() <= right->GetValFloat(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarFloat::Hs(CBotVar* left, CBotVar* right) -{ - return left->GetValFloat() >= right->GetValFloat(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarFloat::Eq(CBotVar* left, CBotVar* right) -{ - return left->GetValFloat() == right->GetValFloat(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarFloat::Ne(CBotVar* left, CBotVar* right) -{ - return left->GetValFloat() != right->GetValFloat(); -} - -//////////////////////////////////////////////////////////////////////////////// bool CBotVarFloat::Save1State(FILE* pf) { return WriteFloat(pf, m_val); // the value of the variable diff --git a/src/CBot/CBotVar/CBotVarFloat.h b/src/CBot/CBotVar/CBotVarFloat.h index 0e294867..84324e60 100644 --- a/src/CBot/CBotVar/CBotVarFloat.h +++ b/src/CBot/CBotVar/CBotVarFloat.h @@ -19,7 +19,7 @@ #pragma once -#include "CBot/CBotVar/CBotVar.h" +#include "CBot/CBotVar/CBotVarValue.h" namespace CBot { @@ -27,45 +27,12 @@ namespace CBot /** * \brief CBotVar subclass for managing float values (::CBotTypFloat) */ -class CBotVarFloat : public CBotVar +class CBotVarFloat : public CBotVarNumber { public: - /** - * \brief Constructor. Do not call directly, use CBotVar::Create() - */ - CBotVarFloat(const CBotToken& name); - - void SetValInt(int val, const std::string& s = nullptr) override; - void SetValFloat(float val) override; - int GetValInt() override; - float GetValFloat() override; - std::string GetValString() override; - - void Copy(CBotVar* pSrc, bool bName = true) override; - - void Add(CBotVar* left, CBotVar* right) override; - void Sub(CBotVar* left, CBotVar* right) override; - void Mul(CBotVar* left, CBotVar* right) override; - CBotError Div(CBotVar* left, CBotVar* right) override; - CBotError Modulo(CBotVar* left, CBotVar* right) override; - void Power(CBotVar* left, CBotVar* right) override; - - bool Lo(CBotVar* left, CBotVar* right) override; - bool Hi(CBotVar* left, CBotVar* right) override; - bool Ls(CBotVar* left, CBotVar* right) override; - bool Hs(CBotVar* left, CBotVar* right) override; - bool Eq(CBotVar* left, CBotVar* right) override; - bool Ne(CBotVar* left, CBotVar* right) override; - - void Neg() override; - void Inc() override; - void Dec() override; + CBotVarFloat(const CBotToken &name) : CBotVarNumber(name) {} bool Save1State(FILE* pf) override; - -private: - //! The value. - float m_val; }; } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarInt.cpp b/src/CBot/CBotVar/CBotVarInt.cpp index 00704903..29715c9b 100644 --- a/src/CBot/CBotVar/CBotVarInt.cpp +++ b/src/CBot/CBotVar/CBotVarInt.cpp @@ -19,276 +19,93 @@ #include "CBot/CBotVar/CBotVarInt.h" -#include "CBot/CBotEnums.h" -#include "CBot/CBotToken.h" -#include "CBot/CBotUtils.h" - -#include - namespace CBot { -//////////////////////////////////////////////////////////////////////////////// -CBotVarInt::CBotVarInt(const CBotToken& name) -{ - m_token = new CBotToken(name); - m_next = nullptr; - m_pMyThis = nullptr; - m_pUserPtr = nullptr; - m_InitExpr = nullptr; - m_LimExpr = nullptr; - m_type = CBotTypInt; - m_binit = InitType::UNDEF; - m_bStatic = false; - m_mPrivate = ProtectionLevel::Public; - - m_val = 0; -} - -//////////////////////////////////////////////////////////////////////////////// void CBotVarInt::Copy(CBotVar* pSrc, bool bName) { - CBotVarInt* p = static_cast(pSrc); - - if ( bName) *m_token = *p->m_token; - m_type = p->m_type; - m_val = p->m_val; - m_binit = p->m_binit; - m_pMyThis = nullptr; - m_pUserPtr = p->m_pUserPtr; - - // identificator is the same (by défaut) - if (m_ident == 0 ) m_ident = p->m_ident; - - m_defnum = p->m_defnum; + CBotVarNumber::Copy(pSrc, bName); + CBotVarInt* p = static_cast(pSrc); + m_defnum = p->m_defnum; } -//////////////////////////////////////////////////////////////////////////////// void CBotVarInt::SetValInt(int val, const std::string& defnum) { - m_val = val; - m_binit = CBotVar::InitType::DEF; + CBotVarNumber::SetValInt(val, defnum); m_defnum = defnum; } -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::SetValFloat(float val) -{ - m_val = static_cast(val); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -int CBotVarInt::GetValInt() -{ - return m_val; -} - -//////////////////////////////////////////////////////////////////////////////// -float CBotVarInt::GetValFloat() -{ - return static_cast(m_val); -} - -//////////////////////////////////////////////////////////////////////////////// std::string CBotVarInt::GetValString() { - if ( !m_defnum.empty() ) return m_defnum; - - std::string res; - - if ( m_binit == CBotVar::InitType::UNDEF ) - { - return LoadString(TX_UNDEF); - } - - if ( m_binit == CBotVar::InitType::IS_NAN ) - { - return LoadString(TX_NAN); - } - - char buffer[300]; - sprintf(buffer, "%d", m_val); - res = buffer; - - return res; + if (!m_defnum.empty()) return m_defnum; + return CBotVarValue::GetValString(); } -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::Mul(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValInt() * right->GetValInt(); - m_binit = CBotVar::InitType::DEF; -} -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::Power(CBotVar* left, CBotVar* right) -{ - m_val = static_cast( pow( static_cast(left->GetValInt()) , static_cast(right->GetValInt()) )); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -CBotError CBotVarInt::Div(CBotVar* left, CBotVar* right) -{ - int r = right->GetValInt(); - if ( r != 0 ) - { - m_val = left->GetValInt() / r; - m_binit = CBotVar::InitType::DEF; - } - return ( r == 0 ? CBotErrZeroDiv : CBotNoErr ); -} - -//////////////////////////////////////////////////////////////////////////////// -CBotError CBotVarInt::Modulo(CBotVar* left, CBotVar* right) -{ - int r = right->GetValInt(); - if ( r != 0 ) - { - m_val = left->GetValInt() % r; - m_binit = CBotVar::InitType::DEF; - } - return ( r == 0 ? CBotErrZeroDiv : CBotNoErr ); -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::Add(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValInt() + right->GetValInt(); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::Sub(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValInt() - right->GetValInt(); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::XOr(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValInt() ^ right->GetValInt(); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::And(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValInt() & right->GetValInt(); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::Or(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValInt() | right->GetValInt(); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::SL(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValInt() << right->GetValInt(); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::ASR(CBotVar* left, CBotVar* right) -{ - m_val = left->GetValInt() >> right->GetValInt(); - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::SR(CBotVar* left, CBotVar* right) -{ - int source = left->GetValInt(); - int shift = right->GetValInt(); - if (shift>=1) source &= 0x7fffffff; - m_val = source >> shift; - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// void CBotVarInt::Neg() { - m_val = -m_val; + CBotVarNumber::Neg(); + m_defnum.empty(); +} +void CBotVarInt::Inc() +{ + CBotVarNumber::Inc(); + m_defnum.empty(); +} +void CBotVarInt::Dec() +{ + CBotVarNumber::Dec(); + m_defnum.empty(); +} + +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); } -//////////////////////////////////////////////////////////////////////////////// void CBotVarInt::Not() { m_val = ~m_val; } -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::Inc() -{ - m_val++; - m_defnum.empty(); -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarInt::Dec() -{ - m_val--; - m_defnum.empty(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarInt::Lo(CBotVar* left, CBotVar* right) -{ - return left->GetValInt() < right->GetValInt(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarInt::Hi(CBotVar* left, CBotVar* right) -{ - return left->GetValInt() > right->GetValInt(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarInt::Ls(CBotVar* left, CBotVar* right) -{ - return left->GetValInt() <= right->GetValInt(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarInt::Hs(CBotVar* left, CBotVar* right) -{ - return left->GetValInt() >= right->GetValInt(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarInt::Eq(CBotVar* left, CBotVar* right) -{ - return left->GetValInt() == right->GetValInt(); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarInt::Ne(CBotVar* left, CBotVar* right) -{ - return left->GetValInt() != right->GetValInt(); -} - -//////////////////////////////////////////////////////////////////////////////// bool CBotVarInt::Save0State(FILE* pf) { - if ( !m_defnum.empty() ) + if (!m_defnum.empty()) { - if(!WriteWord(pf, 200 )) return false; // special marker - if(!WriteString(pf, m_defnum)) return false; // name of the value + if(!WriteWord(pf, 200)) return false; // special marker + if(!WriteString(pf, m_defnum)) return false; } return CBotVar::Save0State(pf); } -//////////////////////////////////////////////////////////////////////////////// bool CBotVarInt::Save1State(FILE* pf) { - return WriteWord(pf, m_val); // the value of the variable + return WriteWord(pf, m_val); } } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarInt.h b/src/CBot/CBotVar/CBotVarInt.h index 8d7d4f97..32d0af0b 100644 --- a/src/CBot/CBotVar/CBotVarInt.h +++ b/src/CBot/CBotVar/CBotVarInt.h @@ -19,7 +19,7 @@ #pragma once -#include "CBot/CBotVar/CBotVar.h" +#include "CBot/CBotVar/CBotVarValue.h" namespace CBot { @@ -27,35 +27,19 @@ namespace CBot /** * \brief CBotVar subclass for managing integer values (::CBotTypInt) */ -class CBotVarInt : public CBotVar +class CBotVarInt : public CBotVarNumber { public: - /** - * \brief Constructor. Do not call directly, use CBotVar::Create() - */ - CBotVarInt(const CBotToken& name); + CBotVarInt(const CBotToken &name) : CBotVarNumber(name) {} void SetValInt(int val, const std::string& s = "") override; - void SetValFloat(float val) override; - int GetValInt() override; - float GetValFloat() override; std::string GetValString() override; void Copy(CBotVar* pSrc, bool bName = true) override; - void Add(CBotVar* left, CBotVar* right) override; - void Sub(CBotVar* left, CBotVar* right) override; - void Mul(CBotVar* left, CBotVar* right) override; - CBotError Div(CBotVar* left, CBotVar* right) override; - CBotError Modulo(CBotVar* left, CBotVar* right) override; - void Power(CBotVar* left, CBotVar* right) override; - - bool Lo(CBotVar* left, CBotVar* right) override; - bool Hi(CBotVar* left, CBotVar* right) override; - bool Ls(CBotVar* left, CBotVar* right) override; - bool Hs(CBotVar* left, CBotVar* right) override; - bool Eq(CBotVar* left, CBotVar* right) override; - bool Ne(CBotVar* left, CBotVar* right) override; + void Neg() override; + void Inc() override; + void Dec() override; void XOr(CBotVar* left, CBotVar* right) override; void Or(CBotVar* left, CBotVar* right) override; @@ -66,16 +50,10 @@ public: void SR(CBotVar* left, CBotVar* right) override; void ASR(CBotVar* left, CBotVar* right) override; - void Neg() override; - void Inc() override; - void Dec() override; - bool Save0State(FILE* pf) override; bool Save1State(FILE* pf) override; -private: - //! The value. - int m_val; +protected: //! The name if given by DefineNum. std::string m_defnum; friend class CBotVar; diff --git a/src/CBot/CBotVar/CBotVarString.cpp b/src/CBot/CBotVar/CBotVarString.cpp index 653badf6..a5f3bba6 100644 --- a/src/CBot/CBotVar/CBotVarString.cpp +++ b/src/CBot/CBotVar/CBotVarString.cpp @@ -19,117 +19,27 @@ #include "CBot/CBotVar/CBotVarString.h" -#include "CBot/CBotEnums.h" -#include "CBot/CBotToken.h" -#include "CBot/CBotUtils.h" - namespace CBot { -//////////////////////////////////////////////////////////////////////////////// -CBotVarString::CBotVarString(const CBotToken& name) -{ - m_token = new CBotToken(name); - m_next = nullptr; - m_pMyThis = nullptr; - m_pUserPtr = nullptr; - m_InitExpr = nullptr; - m_LimExpr = nullptr; - m_type = CBotTypString; - m_binit = InitType::UNDEF; - m_bStatic = false; - m_mPrivate = ProtectionLevel::Public; - - m_val.clear(); -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarString::Copy(CBotVar* pSrc, bool bName) -{ - CBotVarString* p = static_cast(pSrc); - - if (bName) *m_token = *p->m_token; - m_type = p->m_type; - m_val = p->m_val; - m_binit = p->m_binit; -//- m_bStatic = p->m_bStatic; - m_next = nullptr; - m_pMyThis = nullptr;//p->m_pMyThis; - m_pUserPtr = p->m_pUserPtr; - - // keeps indentificator the same (by default) - if (m_ident == 0 ) m_ident = p->m_ident; -} - -//////////////////////////////////////////////////////////////////////////////// -void CBotVarString::SetValString(const std::string& val) -{ - m_val = val; - m_binit = CBotVar::InitType::DEF; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string CBotVarString::GetValString() -{ - if ( m_binit == CBotVar::InitType::UNDEF ) - { - return LoadString(TX_UNDEF); - } - if ( m_binit == CBotVar::InitType::IS_NAN ) - { - return LoadString(TX_NAN); - } - - return m_val; -} - -//////////////////////////////////////////////////////////////////////////////// void CBotVarString::Add(CBotVar* left, CBotVar* right) { - m_val = left->GetValString() + right->GetValString(); - m_binit = CBotVar::InitType::DEF; + SetValString(left->GetValString() + right->GetValString()); } -//////////////////////////////////////////////////////////////////////////////// bool CBotVarString::Eq(CBotVar* left, CBotVar* right) { - return (left->GetValString() == right->GetValString()); + return left->GetValString() == right->GetValString(); } -//////////////////////////////////////////////////////////////////////////////// bool CBotVarString::Ne(CBotVar* left, CBotVar* right) { - return (left->GetValString() != right->GetValString()); + return left->GetValString() != right->GetValString(); } -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarString::Lo(CBotVar* left, CBotVar* right) -{ - return (left->GetValString() == right->GetValString()); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarString::Hi(CBotVar* left, CBotVar* right) -{ - return (left->GetValString() == right->GetValString()); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarString::Ls(CBotVar* left, CBotVar* right) -{ - return (left->GetValString() == right->GetValString()); -} - -//////////////////////////////////////////////////////////////////////////////// -bool CBotVarString::Hs(CBotVar* left, CBotVar* right) -{ - return (left->GetValString() == right->GetValString()); -} - -//////////////////////////////////////////////////////////////////////////////// bool CBotVarString::Save1State(FILE* pf) { - return WriteString(pf, m_val); // the value of the variable + return WriteString(pf, m_val); } } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarString.h b/src/CBot/CBotVar/CBotVarString.h index 136294e5..162264d2 100644 --- a/src/CBot/CBotVar/CBotVarString.h +++ b/src/CBot/CBotVar/CBotVarString.h @@ -19,7 +19,7 @@ #pragma once -#include "CBot/CBotVar/CBotVar.h" +#include "CBot/CBotVar/CBotVarValue.h" namespace CBot { @@ -27,33 +27,61 @@ namespace CBot /** * \brief CBotVar subclass for managing string values (::CBotTypString) */ -class CBotVarString : public CBotVar +class CBotVarString : public CBotVarValue { public: - /** - * \brief Constructor. Do not call directly, use CBotVar::Create() - */ - CBotVarString(const CBotToken& name); + CBotVarString(const CBotToken &name) : CBotVarValue(name) {} - void SetValString(const std::string& val) override; - std::string GetValString() override; + void SetValString(const std::string& val) override + { + m_val = val; + m_binit = CBotVar::InitType::DEF; + } - void Copy(CBotVar* pSrc, bool bName = true) override; + void SetValInt(int val, const std::string& s = "") override + { + SetValString(ToString(val)); + } + + void SetValFloat(float val) override + { + SetValString(ToString(val)); + } + + int GetValInt() + { + return FromString(GetValString()); + } + + float GetValFloat() + { + return FromString(GetValString()); + } void Add(CBotVar* left, CBotVar* right) override; - bool Lo(CBotVar* left, CBotVar* right) override; - bool Hi(CBotVar* left, CBotVar* right) override; - bool Ls(CBotVar* left, CBotVar* right) override; - bool Hs(CBotVar* left, CBotVar* right) override; bool Eq(CBotVar* left, CBotVar* right) override; bool Ne(CBotVar* left, CBotVar* right) override; bool Save1State(FILE* pf) override; private: - //! The value. - std::string m_val; + template + static std::string ToString(T val) + { + std::ostringstream ss; + ss << val; + return ss.str(); + } + + template + static T FromString(std::string val) + { + std::istringstream ss(val); + T v; + ss >> v; + return v; + } }; } // namespace CBot diff --git a/src/CBot/CBotVar/CBotVarValue.h b/src/CBot/CBotVar/CBotVarValue.h new file mode 100644 index 00000000..3fd15286 --- /dev/null +++ b/src/CBot/CBotVar/CBotVarValue.h @@ -0,0 +1,196 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include "CBot/CBotVar/CBotVar.h" + +#include "CBot/CBotEnums.h" +#include "CBot/CBotToken.h" + +#include +#include + + +namespace CBot +{ + +/** + * \brief A variable holding a simple value (bool, int, float, string) + */ +template +class CBotVarValue : public CBotVar +{ +public: + /** + * \brief Constructor. Do not call directly, use CBotVar::Create() + */ + CBotVarValue(const CBotToken& name) : CBotVar(name) + { + m_type = type; + } + + void Copy(CBotVar* pSrc, bool bName = true) override + { + CBotVar::Copy(pSrc, bName); + + CBotVarValue* p = static_cast(pSrc); + m_val = p->m_val; + } + + + void SetValString(const std::string& val) override + { + std::istringstream s(val); + s >> m_val; + m_binit = CBotVar::InitType::DEF; + } + + 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); + + std::ostringstream s; + s << m_val; + return s.str(); + } + +protected: + //! The value + T m_val; +}; + +/** + * \brief A number based variable (bool, int, float) + */ +template +class CBotVarNumberBase : public CBotVarValue +{ +public: + CBotVarNumberBase(const CBotToken &name) : CBotVarValue(name) {} + + void SetValInt(int val, const std::string &s = "") override + { + this->m_val = static_cast(val); + this->m_binit = CBotVar::InitType::DEF; + } + + void SetValFloat(float val) override + { + this->m_val = static_cast(val); + this->m_binit = CBotVar::InitType::DEF; + } + + int GetValInt() override + { + return static_cast(this->m_val); + } + + float GetValFloat() override + { + return static_cast(this->m_val); + } + + + bool Eq(CBotVar* left, CBotVar* right) override + { + return left->GetValFloat() == right->GetValFloat(); + } + bool Ne(CBotVar* left, CBotVar* right) override + { + return left->GetValFloat() != right->GetValFloat(); + } +}; + +/** + * \brief A number variable (int, float) + */ +template +class CBotVarNumber : public CBotVarNumberBase +{ +public: + CBotVarNumber(const CBotToken &name) : CBotVarNumberBase(name) {} + + void Mul(CBotVar* left, CBotVar* right) override + { + this->SetValFloat(left->GetValFloat() * right->GetValFloat()); + } + void Power(CBotVar* left, CBotVar* right) override + { + this->SetValFloat(pow(left->GetValFloat(), right->GetValFloat())); + } + CBotError Div(CBotVar* left, CBotVar* right) override + { + float r = right->GetValFloat(); + if (r == 0) return CBotErrZeroDiv; + this->SetValFloat(left->GetValFloat() / 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)); + return CBotNoErr; + } + void Add(CBotVar* left, CBotVar* right) override + { + this->SetValFloat(left->GetValFloat() + right->GetValFloat()); + } + void Sub(CBotVar* left, CBotVar* right) override + { + this->SetValFloat(left->GetValFloat() - right->GetValFloat()); + } + + void Neg() override + { + this->m_val = - this->m_val; + } + void Inc() override + { + this->m_val++; + } + void Dec() override + { + this->m_val--; + } + + bool Lo(CBotVar* left, CBotVar* right) override + { + return left->GetValFloat() < right->GetValFloat(); + } + bool Hi(CBotVar* left, CBotVar* right) override + { + return left->GetValFloat() > right->GetValFloat(); + } + bool Ls(CBotVar* left, CBotVar* right) override + { + return left->GetValFloat() <= right->GetValFloat(); + } + bool Hs(CBotVar* left, CBotVar* right) override + { + return left->GetValFloat() >= right->GetValFloat(); + } +}; + +} + diff --git a/src/CBot/CMakeLists.txt b/src/CBot/CMakeLists.txt index 1f17e6bb..b77d0bbc 100644 --- a/src/CBot/CMakeLists.txt +++ b/src/CBot/CMakeLists.txt @@ -1,75 +1,149 @@ set(SOURCES - CBotCallMethode.cpp - CBotClass.cpp + CBot.h CBotCStack.cpp + CBotCStack.h + CBotCallMethode.cpp + CBotCallMethode.h + CBotClass.cpp + CBotClass.h CBotDebug.cpp + CBotDebug.h CBotDefParam.cpp + CBotDefParam.h + CBotDefines.h + CBotEnums.h CBotExternalCall.cpp + CBotExternalCall.h CBotFileUtils.cpp - CBotProgram.cpp - CBotStack.cpp - CBotToken.cpp - CBotTypResult.cpp - CBotUtils.cpp + CBotFileUtils.h CBotInstr/CBotBlock.cpp + CBotInstr/CBotBlock.h CBotInstr/CBotBoolExpr.cpp + CBotInstr/CBotBoolExpr.h CBotInstr/CBotBreak.cpp + CBotInstr/CBotBreak.h CBotInstr/CBotCase.cpp + CBotInstr/CBotCase.h CBotInstr/CBotCatch.cpp + CBotInstr/CBotCatch.h CBotInstr/CBotCondition.cpp + CBotInstr/CBotCondition.h CBotInstr/CBotDefArray.cpp + CBotInstr/CBotDefArray.h CBotInstr/CBotDefBoolean.cpp + CBotInstr/CBotDefBoolean.h CBotInstr/CBotDefClass.cpp + CBotInstr/CBotDefClass.h CBotInstr/CBotDefFloat.cpp + CBotInstr/CBotDefFloat.h CBotInstr/CBotDefInt.cpp + CBotInstr/CBotDefInt.h CBotInstr/CBotDefString.cpp + CBotInstr/CBotDefString.h CBotInstr/CBotDo.cpp + CBotInstr/CBotDo.h CBotInstr/CBotEmpty.cpp - CBotInstr/CBotExpression.cpp + CBotInstr/CBotEmpty.h CBotInstr/CBotExprLitBool.cpp + CBotInstr/CBotExprLitBool.h CBotInstr/CBotExprLitNan.cpp + CBotInstr/CBotExprLitNan.h CBotInstr/CBotExprLitNull.cpp + CBotInstr/CBotExprLitNull.h CBotInstr/CBotExprLitNum.cpp + CBotInstr/CBotExprLitNum.h CBotInstr/CBotExprLitString.cpp + CBotInstr/CBotExprLitString.h CBotInstr/CBotExprUnaire.cpp + CBotInstr/CBotExprUnaire.h CBotInstr/CBotExprVar.cpp + CBotInstr/CBotExprVar.h + CBotInstr/CBotExpression.cpp + CBotInstr/CBotExpression.h CBotInstr/CBotFieldExpr.cpp + CBotInstr/CBotFieldExpr.h CBotInstr/CBotFor.cpp + CBotInstr/CBotFor.h CBotInstr/CBotFunction.cpp + CBotInstr/CBotFunction.h CBotInstr/CBotIf.cpp + CBotInstr/CBotIf.h CBotInstr/CBotIndexExpr.cpp - CBotInstr/CBotInstrCall.cpp + CBotInstr/CBotIndexExpr.h CBotInstr/CBotInstr.cpp + CBotInstr/CBotInstr.h + CBotInstr/CBotInstrCall.cpp + CBotInstr/CBotInstrCall.h CBotInstr/CBotInstrMethode.cpp + CBotInstr/CBotInstrMethode.h CBotInstr/CBotInstrUtils.cpp + CBotInstr/CBotInstrUtils.h CBotInstr/CBotLeftExpr.cpp + CBotInstr/CBotLeftExpr.h CBotInstr/CBotLeftExprVar.cpp + CBotInstr/CBotLeftExprVar.h CBotInstr/CBotListArray.cpp + CBotInstr/CBotListArray.h CBotInstr/CBotListExpression.cpp + CBotInstr/CBotListExpression.h CBotInstr/CBotListInstr.cpp + CBotInstr/CBotListInstr.h CBotInstr/CBotLogicExpr.cpp + CBotInstr/CBotLogicExpr.h CBotInstr/CBotNew.cpp + CBotInstr/CBotNew.h CBotInstr/CBotParExpr.cpp + CBotInstr/CBotParExpr.h CBotInstr/CBotPostIncExpr.cpp + CBotInstr/CBotPostIncExpr.h CBotInstr/CBotPreIncExpr.cpp + CBotInstr/CBotPreIncExpr.h CBotInstr/CBotReturn.cpp + CBotInstr/CBotReturn.h CBotInstr/CBotSwitch.cpp + CBotInstr/CBotSwitch.h CBotInstr/CBotThrow.cpp + CBotInstr/CBotThrow.h CBotInstr/CBotTry.cpp + CBotInstr/CBotTry.h CBotInstr/CBotTwoOpExpr.cpp + CBotInstr/CBotTwoOpExpr.h CBotInstr/CBotWhile.cpp - CBotVar/CBotVarArray.cpp - CBotVar/CBotVarBoolean.cpp - CBotVar/CBotVarClass.cpp + CBotInstr/CBotWhile.h + CBotProgram.cpp + CBotProgram.h + CBotStack.cpp + CBotStack.h + CBotToken.cpp + CBotToken.h + CBotTypResult.cpp + CBotTypResult.h + CBotUtils.cpp + CBotUtils.h CBotVar/CBotVar.cpp + CBotVar/CBotVar.h + CBotVar/CBotVarValue.h + CBotVar/CBotVarArray.cpp + CBotVar/CBotVarArray.h + CBotVar/CBotVarBoolean.cpp + CBotVar/CBotVarBoolean.h + CBotVar/CBotVarClass.cpp + CBotVar/CBotVarClass.h CBotVar/CBotVarFloat.cpp + CBotVar/CBotVarFloat.h CBotVar/CBotVarInt.cpp + CBotVar/CBotVarInt.h CBotVar/CBotVarPointer.cpp + CBotVar/CBotVarPointer.h CBotVar/CBotVarString.cpp + CBotVar/CBotVarString.h stdlib/Compilation.cpp + stdlib/Compilation.h stdlib/FileFunctions.cpp stdlib/MathFunctions.cpp stdlib/StringFunctions.cpp + stdlib/stdlib.h + stdlib/stdlib_public.h ) # Includes @@ -90,3 +164,4 @@ else() RUNTIME DESTINATION ${COLOBOT_INSTALL_BIN_DIR}) endif() +group_sources("${SOURCES}" "Source Files") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f0012b1f..bc6f12ad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,15 @@ set(CMAKE_CXX_FLAGS "${COLOBOT_CXX_FLAGS} ${MXE_CFLAGS}") set(CMAKE_CXX_FLAGS_RELEASE ${COLOBOT_CXX_FLAGS_RELEASE}) set(CMAKE_CXX_FLAGS_DEBUG ${COLOBOT_CXX_FLAGS_DEBUG}) +# Groups source files for IDE project +macro(group_sources SOURCES GROUP_ROOT) + foreach(SOURCE_FILE ${SOURCES}) + get_filename_component(GROUP "${SOURCE_FILE}" PATH) + string(REPLACE "/" "\\" GROUP "${GROUP}") + set(GROUP "${GROUP_ROOT}\\${GROUP}") + source_group("${GROUP}" FILES "${SOURCE_FILE}") + endforeach() +endmacro() # Subdirectories @@ -64,6 +73,10 @@ if(OPENAL_SOUND) sound/oalsound/buffer.cpp sound/oalsound/channel.cpp sound/oalsound/check.cpp + sound/oalsound/alsound.h + sound/oalsound/buffer.h + sound/oalsound/channel.h + sound/oalsound/check.h ) endif() @@ -75,195 +88,439 @@ endif() # Source files set(BASE_SOURCES - app/app.cpp - app/controller.cpp - app/input.cpp - app/pausemanager.cpp - app/signal_handlers.cpp - app/system.cpp - app/${SYSTEM_CPP_MODULE} - app/system_other.cpp - common/config_file.cpp - common/event.cpp - common/image.cpp - common/key.cpp - common/language.cpp - common/logger.cpp - common/misc.cpp - common/pathman.cpp - common/regex_utils.cpp - common/resources/inputstream.cpp - common/resources/inputstreambuffer.cpp - common/resources/outputstream.cpp - common/resources/outputstreambuffer.cpp - common/resources/resourcemanager.cpp - common/resources/sdl_file_wrapper.cpp - common/resources/sdl_memory_wrapper.cpp - common/resources/sndfile_wrapper.cpp - common/restext.cpp - common/settings.cpp - common/stringutils.cpp - graphics/core/color.cpp - graphics/core/framebuffer.cpp - graphics/core/nulldevice.cpp - graphics/engine/camera.cpp - graphics/engine/cloud.cpp - graphics/engine/engine.cpp - graphics/engine/lightman.cpp - graphics/engine/lightning.cpp - graphics/engine/oldmodelmanager.cpp - graphics/engine/particle.cpp - graphics/engine/planet.cpp - graphics/engine/pyro.cpp - graphics/engine/pyro_manager.cpp - graphics/engine/terrain.cpp - graphics/engine/text.cpp - graphics/engine/water.cpp - graphics/opengl/gl21device.cpp - graphics/opengl/gl33device.cpp - graphics/opengl/gldevice.cpp - graphics/opengl/glframebuffer.cpp - graphics/opengl/glutil.cpp - graphics/model/model.cpp - graphics/model/model_input.cpp - graphics/model/model_manager.cpp - graphics/model/model_mesh.cpp - graphics/model/model_output.cpp - level/level_category.cpp - level/mainmovie.cpp - level/player_profile.cpp - level/robotmain.cpp - level/scene_conditions.cpp - level/parser/parser.cpp - level/parser/parserexceptions.cpp - level/parser/parserline.cpp - level/parser/parserparam.cpp - object/auto/auto.cpp - object/auto/autobase.cpp - object/auto/autoconvert.cpp - object/auto/autoderrick.cpp - object/auto/autodestroyer.cpp - object/auto/autoegg.cpp - object/auto/autopowerplant.cpp - object/auto/autofactory.cpp - object/auto/autoflag.cpp - object/auto/autohouston.cpp - object/auto/autojostle.cpp - object/auto/autokid.cpp - object/auto/autolabo.cpp - object/auto/automush.cpp - object/auto/autonest.cpp - object/auto/autonuclearplant.cpp - object/auto/autopowercaptor.cpp - object/auto/autoportico.cpp - object/auto/autoradar.cpp - object/auto/autorepair.cpp - object/auto/autoresearch.cpp - object/auto/autoroot.cpp - object/auto/autovault.cpp - object/auto/autopowerstation.cpp - object/auto/autotower.cpp - object/drive_type.cpp - object/interface/trace_drawing_object.cpp - object/implementation/power_container_impl.cpp - object/implementation/programmable_impl.cpp - object/implementation/program_storage_impl.cpp - object/implementation/task_executor_impl.cpp - object/motion/motion.cpp - object/motion/motionant.cpp - object/motion/motionbee.cpp - object/motion/motionlevelcontroller.cpp - object/motion/motionhuman.cpp - object/motion/motionqueen.cpp - object/motion/motionspider.cpp - object/motion/motiontoto.cpp - object/motion/motionvehicle.cpp - object/motion/motionworm.cpp - object/object.cpp - object/object_factory.cpp - object/object_manager.cpp - object/old_object.cpp - object/old_object_interface.cpp - object/task/task.cpp - object/task/taskadvance.cpp - object/task/taskbuild.cpp - object/task/taskdeletemark.cpp - object/task/taskfire.cpp - object/task/taskfireant.cpp - object/task/taskflag.cpp - object/task/taskgoto.cpp - object/task/taskgungoal.cpp - object/task/taskinfo.cpp - object/task/taskmanip.cpp - object/task/taskpen.cpp - object/task/taskrecover.cpp - object/task/tasksearch.cpp - object/task/taskshield.cpp - object/task/taskspiderexplo.cpp - object/task/tasktake.cpp - object/task/taskterraform.cpp - object/task/taskturn.cpp - object/task/taskwait.cpp - object/tool_type.cpp - object/subclass/base_alien.cpp - object/subclass/base_building.cpp - object/subclass/base_robot.cpp - object/subclass/base_vehicle.cpp - object/subclass/exchange_post.cpp - object/subclass/shielder.cpp - object/subclass/static_object.cpp - physics/physics.cpp - script/cbottoken.cpp - script/script.cpp - script/scriptfunc.cpp - sound/sound.cpp - sound/sound_type.cpp - ui/displayinfo.cpp - ui/displaytext.cpp - ui/object_interface.cpp - ui/maindialog.cpp - ui/mainmap.cpp - ui/mainshort.cpp - ui/mainui.cpp - ui/studio.cpp - ui/controls/button.cpp - ui/controls/check.cpp - ui/controls/color.cpp - ui/controls/control.cpp - ui/controls/edit.cpp - ui/controls/editvalue.cpp - ui/controls/enumslider.cpp - ui/controls/gauge.cpp - ui/controls/group.cpp - ui/controls/image.cpp - ui/controls/interface.cpp - ui/controls/key.cpp - ui/controls/label.cpp - ui/controls/list.cpp - ui/controls/map.cpp - ui/controls/scroll.cpp - ui/controls/shortcut.cpp - ui/controls/slider.cpp - ui/controls/target.cpp - ui/controls/window.cpp - ui/screen/screen.cpp - ui/screen/screen_apperance.cpp - ui/screen/screen_io.cpp - ui/screen/screen_io_read.cpp - ui/screen/screen_io_write.cpp - ui/screen/screen_level_list.cpp - ui/screen/screen_loading.cpp - ui/screen/screen_main_menu.cpp - ui/screen/screen_player_select.cpp - ui/screen/screen_quit.cpp - ui/screen/screen_setup.cpp - ui/screen/screen_setup_controls.cpp - ui/screen/screen_setup_display.cpp - ui/screen/screen_setup_game.cpp - ui/screen/screen_setup_graphics.cpp - ui/screen/screen_setup_sound.cpp - ui/screen/screen_welcome.cpp ${OPENAL_SRC} + app/${SYSTEM_CPP_MODULE} + app/${SYSTEM_H_MODULE} + app/app.cpp + app/app.h + app/controller.cpp + app/controller.h + app/input.cpp + app/input.h + app/pathman.cpp + app/pathman.h + app/pausemanager.cpp + app/pausemanager.h + app/signal_handlers.cpp + app/signal_handlers.h + app/system.cpp + app/system.h + app/system_other.cpp + app/system_other.h + common/config_file.cpp + common/config_file.h + common/error.h + common/event.cpp + common/event.h + common/global.h + common/image.cpp + common/image.h + common/ioutils.h + common/key.cpp + common/key.h + common/language.cpp + common/language.h + common/logger.cpp + common/logger.h + common/make_unique.h + common/regex_utils.cpp + common/regex_utils.h + common/resources/inputstream.cpp + common/resources/inputstream.h + common/resources/inputstreambuffer.cpp + common/resources/inputstreambuffer.h + common/resources/outputstream.cpp + common/resources/outputstream.h + common/resources/outputstreambuffer.cpp + common/resources/outputstreambuffer.h + common/resources/resourcemanager.cpp + common/resources/resourcemanager.h + common/resources/sdl_file_wrapper.cpp + common/resources/sdl_file_wrapper.h + common/resources/sdl_memory_wrapper.cpp + common/resources/sdl_memory_wrapper.h + common/resources/sndfile_wrapper.cpp + common/resources/sndfile_wrapper.h + common/restext.cpp + common/restext.h + common/settings.cpp + common/settings.h + common/singleton.h + common/stringutils.cpp + common/stringutils.h + common/thread/resource_owning_thread.h + common/thread/sdl_cond_wrapper.h + common/thread/sdl_mutex_wrapper.h + graphics/core/color.cpp + graphics/core/color.h + graphics/core/device.h + graphics/core/framebuffer.cpp + graphics/core/framebuffer.h + graphics/core/light.h + graphics/core/material.h + graphics/core/nulldevice.cpp + graphics/core/nulldevice.h + graphics/core/texture.h + graphics/core/vertex.h + graphics/engine/camera.cpp + graphics/engine/camera.h + graphics/engine/cloud.cpp + graphics/engine/cloud.h + graphics/engine/engine.cpp + graphics/engine/engine.h + graphics/engine/lightman.cpp + graphics/engine/lightman.h + graphics/engine/lightning.cpp + graphics/engine/lightning.h + graphics/engine/oldmodelmanager.cpp + graphics/engine/oldmodelmanager.h + graphics/engine/particle.cpp + graphics/engine/particle.h + graphics/engine/planet.cpp + graphics/engine/planet.h + graphics/engine/pyro.cpp + graphics/engine/pyro.h + graphics/engine/pyro_manager.cpp + graphics/engine/pyro_manager.h + graphics/engine/pyro_type.h + graphics/engine/terrain.cpp + graphics/engine/terrain.h + graphics/engine/text.cpp + graphics/engine/text.h + graphics/engine/water.cpp + graphics/engine/water.h + graphics/model/model.cpp + graphics/model/model.h + graphics/model/model_crash_sphere.h + graphics/model/model_format.h + graphics/model/model_input.cpp + graphics/model/model_input.h + graphics/model/model_io_exception.h + graphics/model/model_io_structs.h + graphics/model/model_manager.cpp + graphics/model/model_manager.h + graphics/model/model_mesh.cpp + graphics/model/model_mesh.h + graphics/model/model_output.cpp + graphics/model/model_output.h + graphics/model/model_shadow_spot.h + graphics/model/model_triangle.h + graphics/opengl/gl14device.cpp + graphics/opengl/gl14device.h + graphics/opengl/gl21device.cpp + graphics/opengl/gl21device.h + graphics/opengl/gl33device.cpp + graphics/opengl/gl33device.h + graphics/opengl/glframebuffer.cpp + graphics/opengl/glframebuffer.h + graphics/opengl/glutil.cpp + graphics/opengl/glutil.h + level/build_type.h + level/level_category.cpp + level/level_category.h + level/mainmovie.cpp + level/mainmovie.h + level/parser/parser.cpp + level/parser/parser.h + level/parser/parserexceptions.cpp + level/parser/parserexceptions.h + level/parser/parserline.cpp + level/parser/parserline.h + level/parser/parserparam.cpp + level/parser/parserparam.h + level/player_profile.cpp + level/player_profile.h + level/research_type.h + level/robotmain.cpp + level/robotmain.h + level/scene_conditions.cpp + level/scene_conditions.h + math/all.h + math/const.h + math/func.h + math/geometry.h + math/intpoint.h + math/matrix.h + math/point.h + math/sphere.h + math/vector.h + object/auto/auto.cpp + object/auto/auto.h + object/auto/autobase.cpp + object/auto/autobase.h + object/auto/autoconvert.cpp + object/auto/autoconvert.h + object/auto/autoderrick.cpp + object/auto/autoderrick.h + object/auto/autodestroyer.cpp + object/auto/autodestroyer.h + object/auto/autoegg.cpp + object/auto/autoegg.h + object/auto/autofactory.cpp + object/auto/autofactory.h + object/auto/autoflag.cpp + object/auto/autoflag.h + object/auto/autohouston.cpp + object/auto/autohouston.h + object/auto/autojostle.cpp + object/auto/autojostle.h + object/auto/autokid.cpp + object/auto/autokid.h + object/auto/autolabo.cpp + object/auto/autolabo.h + object/auto/automush.cpp + object/auto/automush.h + object/auto/autonest.cpp + object/auto/autonest.h + object/auto/autonuclearplant.cpp + object/auto/autonuclearplant.h + object/auto/autoportico.cpp + object/auto/autoportico.h + object/auto/autopowercaptor.cpp + object/auto/autopowercaptor.h + object/auto/autopowerplant.cpp + object/auto/autopowerplant.h + object/auto/autopowerstation.cpp + object/auto/autopowerstation.h + object/auto/autoradar.cpp + object/auto/autoradar.h + object/auto/autorepair.cpp + object/auto/autorepair.h + object/auto/autoresearch.cpp + object/auto/autoresearch.h + object/auto/autoroot.cpp + object/auto/autoroot.h + object/auto/autotower.cpp + object/auto/autotower.h + object/auto/autovault.cpp + object/auto/autovault.h + object/crash_sphere.h + object/drive_type.cpp + object/drive_type.h + object/implementation/power_container_impl.cpp + object/implementation/power_container_impl.h + object/implementation/program_storage_impl.cpp + object/implementation/program_storage_impl.h + object/implementation/programmable_impl.cpp + object/implementation/programmable_impl.h + object/implementation/task_executor_impl.cpp + object/implementation/task_executor_impl.h + object/interface/carrier_object.h + object/interface/controllable_object.h + object/interface/damageable_object.h + object/interface/destroyable_object.h + object/interface/flying_object.h + object/interface/fragile_object.h + object/interface/interactive_object.h + object/interface/jet_flying_object.h + object/interface/jostleable_object.h + object/interface/movable_object.h + object/interface/power_container_object.h + object/interface/powered_object.h + object/interface/program_storage_object.h + object/interface/programmable_object.h + object/interface/ranged_object.h + object/interface/shielded_auto_regen_object.h + object/interface/shielded_object.h + object/interface/task_executor_object.h + object/interface/trace_drawing_object.cpp + object/interface/trace_drawing_object.h + object/interface/transportable_object.h + object/mission_type.h + object/motion/motion.cpp + object/motion/motion.h + object/motion/motionant.cpp + object/motion/motionant.h + object/motion/motionbee.cpp + object/motion/motionbee.h + object/motion/motionhuman.cpp + object/motion/motionhuman.h + object/motion/motionlevelcontroller.cpp + object/motion/motionlevelcontroller.h + object/motion/motionqueen.cpp + object/motion/motionqueen.h + object/motion/motionspider.cpp + object/motion/motionspider.h + object/motion/motiontoto.cpp + object/motion/motiontoto.h + object/motion/motionvehicle.cpp + object/motion/motionvehicle.h + object/motion/motionworm.cpp + object/motion/motionworm.h + object/object.cpp + object/object.h + object/object_create_exception.h + object/object_create_params.h + object/object_factory.cpp + object/object_factory.h + object/object_interface_type.h + object/object_manager.cpp + object/object_manager.h + object/object_type.h + object/old_object.cpp + object/old_object.h + object/old_object_interface.cpp + object/old_object_interface.h + object/subclass/base_alien.cpp + object/subclass/base_alien.h + object/subclass/base_building.cpp + object/subclass/base_building.h + object/subclass/base_robot.cpp + object/subclass/base_robot.h + object/subclass/base_vehicle.cpp + object/subclass/base_vehicle.h + object/subclass/exchange_post.cpp + object/subclass/exchange_post.h + object/subclass/shielder.cpp + object/subclass/shielder.h + object/subclass/static_object.cpp + object/subclass/static_object.h + object/task/task.cpp + object/task/task.h + object/task/taskadvance.cpp + object/task/taskadvance.h + object/task/taskbuild.cpp + object/task/taskbuild.h + object/task/taskdeletemark.cpp + object/task/taskdeletemark.h + object/task/taskfire.cpp + object/task/taskfire.h + object/task/taskfireant.cpp + object/task/taskfireant.h + object/task/taskflag.cpp + object/task/taskflag.h + object/task/taskgoto.cpp + object/task/taskgoto.h + object/task/taskgungoal.cpp + object/task/taskgungoal.h + object/task/taskinfo.cpp + object/task/taskinfo.h + object/task/taskmanip.cpp + object/task/taskmanip.h + object/task/taskpen.cpp + object/task/taskpen.h + object/task/taskrecover.cpp + object/task/taskrecover.h + object/task/tasksearch.cpp + object/task/tasksearch.h + object/task/taskshield.cpp + object/task/taskshield.h + object/task/taskspiderexplo.cpp + object/task/taskspiderexplo.h + object/task/tasktake.cpp + object/task/tasktake.h + object/task/taskterraform.cpp + object/task/taskterraform.h + object/task/taskturn.cpp + object/task/taskturn.h + object/task/taskwait.cpp + object/task/taskwait.h + object/tool_type.cpp + object/tool_type.h + physics/physics.cpp + physics/physics.h + script/cbottoken.cpp + script/cbottoken.h + script/script.cpp + script/script.h + script/scriptfunc.cpp + script/scriptfunc.h + sound/sound.cpp + sound/sound.h + sound/sound_type.cpp + sound/sound_type.h + ui/controls/button.cpp + ui/controls/button.h + ui/controls/check.cpp + ui/controls/check.h + ui/controls/color.cpp + ui/controls/color.h + ui/controls/control.cpp + ui/controls/control.h + ui/controls/edit.cpp + ui/controls/edit.h + ui/controls/editvalue.cpp + ui/controls/editvalue.h + ui/controls/enumslider.cpp + ui/controls/enumslider.h + ui/controls/gauge.cpp + ui/controls/gauge.h + ui/controls/group.cpp + ui/controls/group.h + ui/controls/image.cpp + ui/controls/image.h + ui/controls/interface.cpp + ui/controls/interface.h + ui/controls/key.cpp + ui/controls/key.h + ui/controls/label.cpp + ui/controls/label.h + ui/controls/list.cpp + ui/controls/list.h + ui/controls/map.cpp + ui/controls/map.h + ui/controls/scroll.cpp + ui/controls/scroll.h + ui/controls/shortcut.cpp + ui/controls/shortcut.h + ui/controls/slider.cpp + ui/controls/slider.h + ui/controls/target.cpp + ui/controls/target.h + ui/controls/window.cpp + ui/controls/window.h + ui/debug_menu.cpp + ui/debug_menu.h + ui/displayinfo.cpp + ui/displayinfo.h + ui/displaytext.cpp + ui/displaytext.h + ui/maindialog.cpp + ui/maindialog.h + ui/mainmap.cpp + ui/mainmap.h + ui/mainshort.cpp + ui/mainshort.h + ui/mainui.cpp + ui/mainui.h + ui/object_interface.cpp + ui/object_interface.h + ui/screen/screen.cpp + ui/screen/screen.h + ui/screen/screen_apperance.cpp + ui/screen/screen_apperance.h + ui/screen/screen_io.cpp + ui/screen/screen_io.h + ui/screen/screen_io_read.cpp + ui/screen/screen_io_read.h + ui/screen/screen_io_write.cpp + ui/screen/screen_io_write.h + ui/screen/screen_level_list.cpp + ui/screen/screen_level_list.h + ui/screen/screen_loading.cpp + ui/screen/screen_loading.h + ui/screen/screen_main_menu.cpp + ui/screen/screen_main_menu.h + ui/screen/screen_player_select.cpp + ui/screen/screen_player_select.h + ui/screen/screen_quit.cpp + ui/screen/screen_quit.h + ui/screen/screen_setup.cpp + ui/screen/screen_setup.h + ui/screen/screen_setup_controls.cpp + ui/screen/screen_setup_controls.h + ui/screen/screen_setup_display.cpp + ui/screen/screen_setup_display.h + ui/screen/screen_setup_game.cpp + ui/screen/screen_setup_game.h + ui/screen/screen_setup_graphics.cpp + ui/screen/screen_setup_graphics.h + ui/screen/screen_setup_sound.cpp + ui/screen/screen_setup_sound.h + ui/screen/screen_welcome.cpp + ui/screen/screen_welcome.h + ui/studio.cpp + ui/studio.h ) set(MAIN_SOURCES @@ -271,7 +528,6 @@ set(MAIN_SOURCES ${RES_FILES} ) - # Libraries set(LIBS CBot @@ -341,3 +597,5 @@ endif() if(COLOBOT_LINT_BUILD) add_fake_header_sources("src") endif() + +group_sources("${BASE_SOURCES}" "Source Files") diff --git a/src/app/app.cpp b/src/app/app.cpp index 5547c453..d34532f7 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -21,6 +21,7 @@ #include "app/controller.h" #include "app/input.h" +#include "app/pathman.h" #include "app/system.h" #include "common/config_file.h" @@ -28,7 +29,6 @@ #include "common/key.h" #include "common/logger.h" #include "common/make_unique.h" -#include "common/pathman.h" #include "common/stringutils.h" #include "common/version.h" @@ -42,11 +42,11 @@ #include "object/object_manager.h" +#include "sound/sound.h" #ifdef OPENAL_SOUND #include "sound/oalsound/alsound.h" #endif -#include #include #include @@ -833,7 +833,7 @@ bool CApplication::ChangeVideoConfig(const Gfx::DeviceConfig &newConfig) m_device->ConfigChanged(m_deviceConfig); - m_engine->ResetAfterVideoConfigChanged(); + m_eventQueue->AddEvent(Event(EVENT_RESOLUTION_CHANGED)); return true; } @@ -1812,13 +1812,17 @@ void CApplication::SetLanguage(Language language) char* defaultLocale = setlocale(LC_ALL, ""); // Load system locale GetLogger()->Debug("Default system locale: %s\n", defaultLocale); + if (!locale.empty()) // Override system locale? + { + setlocale(LC_ALL, locale.c_str()); + } setlocale(LC_NUMERIC, "C"); // Force numeric locale to "C" (fixes decimal point problems) - char* systemLocale = setlocale(LC_ALL, nullptr); // Get current locale configuration - GetLogger()->Debug("Setting locale: %s\n", systemLocale); + std::string systemLocale = setlocale(LC_ALL, nullptr); // Get current locale configuration + GetLogger()->Debug("Setting locale: %s\n", systemLocale.c_str()); // Update C++ locale try { - std::locale::global(std::locale(systemLocale)); + std::locale::global(std::locale(systemLocale.c_str())); } catch (...) { diff --git a/src/app/input.cpp b/src/app/input.cpp index ca7aff46..87cedf34 100644 --- a/src/app/input.cpp +++ b/src/app/input.cpp @@ -30,6 +30,7 @@ #include #include +#include template<> CInput* CSingleton::m_instance = nullptr; @@ -48,8 +49,13 @@ CInput::CInput() { INPUT_SLOT_CAMERA, "camera" }, { INPUT_SLOT_DESEL, "desel" }, { INPUT_SLOT_ACTION, "action" }, - { INPUT_SLOT_NEAR, "near" }, - { INPUT_SLOT_AWAY, "away" }, + { INPUT_SLOT_CAM_LEFT, "cleft" }, + { INPUT_SLOT_CAM_RIGHT,"cright" }, + { INPUT_SLOT_CAM_UP, "cup" }, + { INPUT_SLOT_CAM_DOWN, "cdown" }, + { INPUT_SLOT_CAM_NEAR, "near" }, + { INPUT_SLOT_CAM_AWAY, "away" }, + { INPUT_SLOT_CAM_ALT, "camalt" }, { INPUT_SLOT_NEXT, "next" }, { INPUT_SLOT_HUMAN, "human" }, { INPUT_SLOT_QUIT, "quit" }, @@ -63,13 +69,10 @@ CInput::CInput() { INPUT_SLOT_SPEED30, "speed30" }, { INPUT_SLOT_SPEED40, "speed40" }, { INPUT_SLOT_SPEED60, "speed60" }, - { INPUT_SLOT_CAMERA_UP, "camup" }, - { INPUT_SLOT_CAMERA_DOWN, "camdown" }, - { INPUT_SLOT_PAUSE, "pause" }, - { INPUT_SLOT_CMDLINE, "cmdline" }, + { INPUT_SLOT_PAUSE, "pause" }, + { INPUT_SLOT_CMDLINE, "cmdline" }, }; - m_kmodState = 0; m_mousePos = Math::Point(); m_mouseButtonsState = 0; std::fill_n(m_keyPresses, static_cast(INPUT_SLOT_MAX), false); @@ -80,13 +83,6 @@ CInput::CInput() void CInput::EventProcess(Event& event) { - if (event.type == EVENT_KEY_DOWN || - event.type == EVENT_KEY_UP) - { - // Use the occasion to update kmods - m_kmodState = event.kmodState; - } - // Use the occasion to update mouse button state if (event.type == EVENT_MOUSE_BUTTON_DOWN) { @@ -107,7 +103,7 @@ void CInput::EventProcess(Event& event) data->slot = FindBinding(data->key); } - event.kmodState = m_kmodState; + event.kmodState = SDL_GetModState(); event.mousePos = m_mousePos; event.mouseButtonsState = m_mouseButtonsState; @@ -134,12 +130,12 @@ void CInput::EventProcess(Event& event) if (data->slot == INPUT_SLOT_GUP ) m_keyMotion.z = 1.0f; if (data->slot == INPUT_SLOT_GDOWN) m_keyMotion.z = -1.0f; - if (data->slot == INPUT_SLOT_CAMERA_UP ) m_cameraKeyMotion.z = 1.0f; - if (data->slot == INPUT_SLOT_CAMERA_DOWN) m_cameraKeyMotion.z = -1.0f; - if (data->key == KEY(KP_4) ) m_cameraKeyMotion.x = -1.0f; - if (data->key == KEY(KP_6) ) m_cameraKeyMotion.x = 1.0f; - if (data->key == KEY(KP_8) ) m_cameraKeyMotion.y = 1.0f; - if (data->key == KEY(KP_2) ) m_cameraKeyMotion.y = -1.0f; + if (data->slot == INPUT_SLOT_CAM_LEFT ) m_cameraKeyMotion.x = -1.0f; + if (data->slot == INPUT_SLOT_CAM_RIGHT) m_cameraKeyMotion.x = 1.0f; + if (data->slot == INPUT_SLOT_CAM_UP ) m_cameraKeyMotion.y = 1.0f; + if (data->slot == INPUT_SLOT_CAM_DOWN ) m_cameraKeyMotion.y = -1.0f; + if (data->slot == INPUT_SLOT_CAM_NEAR ) m_cameraKeyMotion.z = -1.0f; + if (data->slot == INPUT_SLOT_CAM_AWAY ) m_cameraKeyMotion.z = 1.0f; } else if (event.type == EVENT_KEY_UP) { @@ -152,12 +148,12 @@ void CInput::EventProcess(Event& event) if (data->slot == INPUT_SLOT_GUP ) m_keyMotion.z = 0.0f; if (data->slot == INPUT_SLOT_GDOWN) m_keyMotion.z = 0.0f; - if (data->slot == INPUT_SLOT_CAMERA_UP ) m_cameraKeyMotion.z = 0.0f; - if (data->slot == INPUT_SLOT_CAMERA_DOWN) m_cameraKeyMotion.z = 0.0f; - if (data->key == KEY(KP_4) ) m_cameraKeyMotion.x = 0.0f; - if (data->key == KEY(KP_6) ) m_cameraKeyMotion.x = 0.0f; - if (data->key == KEY(KP_8) ) m_cameraKeyMotion.y = 0.0f; - if (data->key == KEY(KP_2) ) m_cameraKeyMotion.y = 0.0f; + if (data->slot == INPUT_SLOT_CAM_LEFT ) m_cameraKeyMotion.x = 0.0f; + if (data->slot == INPUT_SLOT_CAM_RIGHT) m_cameraKeyMotion.x = 0.0f; + if (data->slot == INPUT_SLOT_CAM_UP ) m_cameraKeyMotion.y = 0.0f; + if (data->slot == INPUT_SLOT_CAM_DOWN ) m_cameraKeyMotion.y = 0.0f; + if (data->slot == INPUT_SLOT_CAM_NEAR ) m_cameraKeyMotion.z = 0.0f; + if (data->slot == INPUT_SLOT_CAM_AWAY ) m_cameraKeyMotion.z = 0.0f; } else if (event.type == EVENT_JOY_AXIS) { @@ -183,10 +179,31 @@ void CInput::EventProcess(Event& event) if (GetJoyAxisBinding(JOY_AXIS_SLOT_Z).invert) m_joyMotion.z *= -1.0f; } + + if (data->axis == GetJoyAxisBinding(JOY_AXIS_SLOT_CAM_X).axis) + { + m_joyMotionCam.x = -Math::Neutral(data->value / 32768.0f, m_joystickDeadzone); + if (GetJoyAxisBinding(JOY_AXIS_SLOT_CAM_X).invert) + m_joyMotionCam.x *= -1.0f; + } + + if (data->axis == GetJoyAxisBinding(JOY_AXIS_SLOT_CAM_Y).axis) + { + m_joyMotionCam.y = -Math::Neutral(data->value / 32768.0f, m_joystickDeadzone); + if (GetJoyAxisBinding(JOY_AXIS_SLOT_CAM_Y).invert) + m_joyMotionCam.y *= -1.0f; + } + + if (data->axis == GetJoyAxisBinding(JOY_AXIS_SLOT_CAM_Z).axis) + { + m_joyMotionCam.z = -Math::Neutral(data->value / 32768.0f, m_joystickDeadzone); + if (GetJoyAxisBinding(JOY_AXIS_SLOT_CAM_Z).invert) + m_joyMotionCam.z *= -1.0f; + } } event.motionInput = Math::Clamp(m_joyMotion + m_keyMotion, Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector(1.0f, 1.0f, 1.0f)); - event.cameraInput = m_cameraKeyMotion; + event.cameraInput = Math::Clamp(m_joyMotionCam + m_cameraKeyMotion, Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector(1.0f, 1.0f, 1.0f)); } void CInput::MouseMove(Math::IntPoint pos) @@ -194,16 +211,6 @@ void CInput::MouseMove(Math::IntPoint pos) m_mousePos = Gfx::CEngine::GetInstancePointer()->WindowToInterfaceCoords(pos); } -int CInput::GetKmods() const -{ - return m_kmodState; -} - -bool CInput::GetKmodState(int kmod) const -{ - return (m_kmodState & kmod) != 0; -} - bool CInput::GetKeyState(InputSlot key) const { return m_keyPresses[key]; @@ -217,10 +224,10 @@ bool CInput::GetMouseButtonState(int index) const void CInput::ResetKeyStates() { GetLogger()->Trace("Reset key states\n"); - m_kmodState = 0; m_keyMotion = Math::Vector(0.0f, 0.0f, 0.0f); m_joyMotion = Math::Vector(0.0f, 0.0f, 0.0f); m_cameraKeyMotion = Math::Vector(0.0f, 0.0f, 0.0f); + m_joyMotionCam = Math::Vector(0.0f, 0.0f, 0.0f); for(int i=0; iSetStringProperty("Keybindings", "_Version", "SDL2"); + GetConfigFile().SetStringProperty("Keybindings", "_Version", "SDL2"); for (int i = 0; i < INPUT_SLOT_MAX; i++) { InputBinding b = GetInputBinding(static_cast(i)); @@ -341,30 +354,30 @@ void CInput::SaveKeyBindings() key.str(""); key << b.primary << " " << b.secondary; - CConfigFile::GetInstancePointer()->SetStringProperty("Keybindings", m_keyTable[static_cast(i)], key.str()); + GetConfigFile().SetStringProperty("Keybindings", m_keyTable[static_cast(i)], key.str()); } for (int i = 0; i < JOY_AXIS_SLOT_MAX; i++) { JoyAxisBinding b = GetJoyAxisBinding(static_cast(i)); - CConfigFile::GetInstancePointer()->SetIntProperty("Setup", "JoystickAxisBinding"+boost::lexical_cast(i), b.axis); - CConfigFile::GetInstancePointer()->SetIntProperty("Setup", "JoystickAxisInvert"+boost::lexical_cast(i), b.invert); + GetConfigFile().SetIntProperty("Setup", "JoystickAxisBinding"+boost::lexical_cast(i), b.axis); + GetConfigFile().SetIntProperty("Setup", "JoystickAxisInvert"+boost::lexical_cast(i), b.invert); } - CConfigFile::GetInstancePointer()->SetFloatProperty("Setup", "JoystickDeadzone", GetJoystickDeadzone()); + GetConfigFile().SetFloatProperty("Setup", "JoystickDeadzone", GetJoystickDeadzone()); } void CInput::LoadKeyBindings() { std::stringstream skey; std::string keys; - if (CConfigFile::GetInstancePointer()->GetStringProperty("Keybindings", "_Version", keys) && keys == "SDL2") // Keybindings from SDL1.2 are incompatible with SDL2 !! + if (GetConfigFile().GetStringProperty("Keybindings", "_Version", keys) && keys == "SDL2") // Keybindings from SDL1.2 are incompatible with SDL2 !! { for (int i = 0; i < INPUT_SLOT_MAX; i++) { InputBinding b; - if (!CConfigFile::GetInstancePointer()->GetStringProperty("Keybindings", m_keyTable[static_cast(i)], keys)) + if (!GetConfigFile().GetStringProperty("Keybindings", m_keyTable[static_cast(i)], keys)) continue; skey.clear(); skey.str(keys); @@ -380,17 +393,17 @@ void CInput::LoadKeyBindings() { JoyAxisBinding b; - if (!CConfigFile::GetInstancePointer()->GetIntProperty("Setup", "JoystickAxisBinding"+boost::lexical_cast(i), b.axis)) + if (!GetConfigFile().GetIntProperty("Setup", "JoystickAxisBinding"+boost::lexical_cast(i), b.axis)) continue; int x = 0; - CConfigFile::GetInstancePointer()->GetIntProperty("Setup", "JoystickAxisInvert"+boost::lexical_cast(i), x); // If doesn't exist, use default (0) + GetConfigFile().GetIntProperty("Setup", "JoystickAxisInvert"+boost::lexical_cast(i), x); // If doesn't exist, use default (0) b.invert = (x != 0); SetJoyAxisBinding(static_cast(i), b); } float deadzone; - if (CConfigFile::GetInstancePointer()->GetFloatProperty("Setup", "JoystickDeadzone", deadzone)) + if (GetConfigFile().GetFloatProperty("Setup", "JoystickDeadzone", deadzone)) SetJoystickDeadzone(deadzone); } diff --git a/src/app/input.h b/src/app/input.h index e9203880..15cdc98d 100644 --- a/src/app/input.h +++ b/src/app/input.h @@ -81,12 +81,6 @@ public: void MouseMove(Math::IntPoint pos); - //! Returns the current key modifiers - int GetKmods() const; - - //! Returns whether the given kmod is active - bool GetKmodState(int kmod) const; - //! Returns whether the key is pressed bool GetKeyState(InputSlot key) const; @@ -140,8 +134,6 @@ public: //@} private: - //! Current state of key modifiers (bitmask of SDLMod) - unsigned int m_kmodState; //! Current state of keys bool m_keyPresses[INPUT_SLOT_MAX]; @@ -156,6 +148,8 @@ private: Math::Vector m_keyMotion; //! Motion vector set by joystick axes Math::Vector m_joyMotion; + //! Camera motion vector set by joystick axes + Math::Vector m_joyMotionCam; //! Camera controls on the numpad Math::Vector m_cameraKeyMotion; diff --git a/src/common/pathman.cpp b/src/app/pathman.cpp similarity index 98% rename from src/common/pathman.cpp rename to src/app/pathman.cpp index 44e2d345..8f862110 100644 --- a/src/common/pathman.cpp +++ b/src/app/pathman.cpp @@ -18,7 +18,7 @@ */ -#include "common/pathman.h" +#include "app/pathman.h" #include "common/config.h" @@ -145,6 +145,7 @@ void CPathManager::InitPaths() void CPathManager::LoadModsFromDir(const std::string &dir) { + GetLogger()->Trace("Looking for mods in '%s' ...\n", dir.c_str()); try { #if PLATFORM_WINDOWS diff --git a/src/common/pathman.h b/src/app/pathman.h similarity index 98% rename from src/common/pathman.h rename to src/app/pathman.h index 9c5ed609..059c81fe 100644 --- a/src/common/pathman.h +++ b/src/app/pathman.h @@ -18,7 +18,7 @@ */ /** - * \file common/pathman.h + * \file app/pathman.h * \brief Class for managing data/lang/save paths */ diff --git a/src/app/pausemanager.cpp b/src/app/pausemanager.cpp index ead940ab..69bc487b 100644 --- a/src/app/pausemanager.cpp +++ b/src/app/pausemanager.cpp @@ -26,6 +26,7 @@ #include "level/robotmain.h" #include +#include struct ActivePause { @@ -41,6 +42,17 @@ struct ActivePause PauseMusic music; }; +std::string GetPauseName(PauseType type) +{ + std::vector x; + if ((type & PAUSE_ENGINE) != 0) x.push_back("engine"); + if ((type & PAUSE_HIDE_SHORTCUTS) != 0) x.push_back("hide_shortcuts"); + if ((type & PAUSE_PHOTO) != 0) x.push_back("photo"); + if ((type & PAUSE_OBJECT_UPDATES) != 0) x.push_back("object_updates"); + if ((type & PAUSE_MUTE_SOUND) != 0) x.push_back("mute_sound"); + if ((type & PAUSE_CAMERA) != 0) x.push_back("camera"); + return boost::algorithm::join(x, "|"); +} CPauseManager::CPauseManager() { @@ -52,7 +64,7 @@ CPauseManager::~CPauseManager() ActivePause* CPauseManager::ActivatePause(PauseType type, PauseMusic music) { - //GetLogger()->Debug("Activated pause mode - %s\n", GetPauseName(type).c_str()); + GetLogger()->Debug("Activated pause mode - %s\n", GetPauseName(type).c_str()); auto pause = MakeUnique(type, music); ActivePause* ptr = pause.get(); m_activePause.push_back(std::move(pause)); @@ -63,7 +75,7 @@ ActivePause* CPauseManager::ActivatePause(PauseType type, PauseMusic music) void CPauseManager::DeactivatePause(ActivePause* pause) { if (pause == nullptr) return; - //GetLogger()->Debug("Deactivated pause mode - %s\n", GetPauseName(pause->type).c_str()); + GetLogger()->Debug("Deactivated pause mode - %s\n", GetPauseName(pause->type).c_str()); auto it = std::remove_if( m_activePause.begin(), m_activePause.end(), [&](const std::unique_ptr& x) { return x.get() == pause; } diff --git a/src/app/pausemanager.h b/src/app/pausemanager.h index 478d1156..d76baf87 100644 --- a/src/app/pausemanager.h +++ b/src/app/pausemanager.h @@ -40,6 +40,7 @@ enum PauseType PAUSE_PHOTO = (1<<2), //!< photo mode, TODO: remove PAUSE_OBJECT_UPDATES = (1<<3), //!< do not send events to objects PAUSE_MUTE_SOUND = (1<<4), //!< mute sound + PAUSE_CAMERA = (1<<5), //!< freeze camera }; inline PauseType& operator|=(PauseType& a, const PauseType& b) { diff --git a/src/app/signal_handlers.cpp b/src/app/signal_handlers.cpp index 1f29dc61..87dbb4ac 100644 --- a/src/app/signal_handlers.cpp +++ b/src/app/signal_handlers.cpp @@ -124,7 +124,7 @@ void CSignalHandlers::ReportError(const std::string& errorMessage) } std::stringstream msg; - msg << "Unhandled exception occured!" << std::endl; + msg << "Unhandled exception occurred!" << std::endl; msg << "==============================" << std::endl; msg << errorMessage << std::endl; msg << "==============================" << std::endl; @@ -162,7 +162,7 @@ void CSignalHandlers::ReportError(const std::string& errorMessage) std::cerr << std::endl << msg.str() << std::endl; - m_systemUtils->SystemDialog(SDT_ERROR, "Unhandled exception occured!", msg.str()); + m_systemUtils->SystemDialog(SDT_ERROR, "Unhandled exception occurred!", msg.str()); if (canSave && !triedSaving) { diff --git a/src/common/config_file.h b/src/common/config_file.h index 02a000c8..0ed8e19f 100644 --- a/src/common/config_file.h +++ b/src/common/config_file.h @@ -107,8 +107,8 @@ private: bool m_loaded; }; -//! Global function to get profile instance +//! Global function to get config file instance inline CConfigFile & GetConfigFile() { - return *CConfigFile::GetInstancePointer(); + return CConfigFile::GetInstance(); } diff --git a/src/common/event.cpp b/src/common/event.cpp index ccd7fe8a..10d1ae9f 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -68,6 +68,8 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_UPDINTERFACE] = "EVENT_UPDINTERFACE"; + EVENT_TYPE_TEXT[EVENT_RESOLUTION_CHANGED]= "EVENT_RESOLUTION_CHANGED"; + EVENT_TYPE_TEXT[EVENT_RELOAD_TEXTURES] = "EVENT_RELOAD_TEXTURES"; EVENT_TYPE_TEXT[EVENT_WIN] = "EVENT_WIN"; EVENT_TYPE_TEXT[EVENT_LOST] = "EVENT_LOST"; @@ -249,13 +251,19 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK]= "EVENT_INTERFACE_JOYSTICK"; EVENT_TYPE_TEXT[EVENT_INTERFACE_SOLUCE] = "EVENT_INTERFACE_SOLUCE"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_DEADZONE]= "EVENT_INTERFACE_JOYSTICK_DEADZONE"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_X]= "EVENT_INTERFACE_JOYSTICK_X"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_Y]= "EVENT_INTERFACE_JOYSTICK_Y"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_Z]= "EVENT_INTERFACE_JOYSTICK_Z"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_X]= "EVENT_INTERFACE_JOYSTICK_CAM_X"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Y]= "EVENT_INTERFACE_JOYSTICK_CAM_Y"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Z]= "EVENT_INTERFACE_JOYSTICK_CAM_Z"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_X_INVERT]= "EVENT_INTERFACE_JOYSTICK_X_INVERT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_Y_INVERT]= "EVENT_INTERFACE_JOYSTICK_Y_INVERT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_Z_INVERT]= "EVENT_INTERFACE_JOYSTICK_Z_INVERT"; - EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_DEADZONE]= "EVENT_INTERFACE_JOYSTICK_DEADZONE"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTl] = "EVENT_INTERFACE_GLINTl"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTr] = "EVENT_INTERFACE_GLINTr"; @@ -472,10 +480,6 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_OBJECT_CAMERA] = "EVENT_OBJECT_CAMERA"; EVENT_TYPE_TEXT[EVENT_OBJECT_HELP] = "EVENT_OBJECT_HELP"; EVENT_TYPE_TEXT[EVENT_OBJECT_SOLUCE] = "EVENT_OBJECT_SOLUCE"; - EVENT_TYPE_TEXT[EVENT_OBJECT_CAMERAleft] = "EVENT_OBJECT_CAMERAleft"; - EVENT_TYPE_TEXT[EVENT_OBJECT_CAMERAright]= "EVENT_OBJECT_CAMERAright"; - EVENT_TYPE_TEXT[EVENT_OBJECT_CAMERAnear] = "EVENT_OBJECT_CAMERAnear"; - EVENT_TYPE_TEXT[EVENT_OBJECT_CAMERAaway] = "EVENT_OBJECT_CAMERAaway"; EVENT_TYPE_TEXT[EVENT_OBJECT_SHORTCUT_MODE] = "EVENT_OBJECT_SHORTCUT_MODE"; EVENT_TYPE_TEXT[EVENT_OBJECT_MOVIELOCK] = "EVENT_OBJECT_MOVIELOCK"; EVENT_TYPE_TEXT[EVENT_OBJECT_EDITLOCK] = "EVENT_OBJECT_EDITLOCK"; diff --git a/src/common/event.h b/src/common/event.h index 50fb0c98..315a4b5b 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -95,6 +95,10 @@ enum EventType //! Event sent on user quit request EVENT_QUIT = 20, EVENT_UPDINTERFACE = 21, + //! Event sent on resolution change + EVENT_RESOLUTION_CHANGED = 22, + //! Event sent when textures have to be reloaded + EVENT_RELOAD_TEXTURES = 23, EVENT_WIN = 30, EVENT_LOST = 31, @@ -145,7 +149,7 @@ enum EventType EVENT_WINDOW4 = 84, //!< CDisplayInfo EVENT_WINDOW5 = 85, //!< all menu windows EVENT_WINDOW6 = 86, //!< code battle interface - EVENT_WINDOW7 = 87, //!< (unused) + EVENT_WINDOW7 = 87, //!< debug interface EVENT_WINDOW8 = 88, //!< (unused) EVENT_WINDOW9 = 89, //!< CMainDialog and CStudio file selector @@ -233,6 +237,7 @@ enum EventType EVENT_INTERFACE_LIGHT = 457, EVENT_INTERFACE_PARTI = 458, EVENT_INTERFACE_CLIP = 459, + EVENT_INTERFACE_PAUSE_BLUR = 460, EVENT_INTERFACE_RAIN = 462, EVENT_INTERFACE_GLINT = 463, EVENT_INTERFACE_TOOLTIP = 464, @@ -280,24 +285,30 @@ enum EventType EVENT_INTERFACE_JOYSTICK= 560, EVENT_INTERFACE_SOLUCE = 561, - EVENT_INTERFACE_JOYSTICK_X = 562, - EVENT_INTERFACE_JOYSTICK_Y = 563, - EVENT_INTERFACE_JOYSTICK_Z = 564, - EVENT_INTERFACE_JOYSTICK_X_INVERT = 565, - EVENT_INTERFACE_JOYSTICK_Y_INVERT = 566, - EVENT_INTERFACE_JOYSTICK_Z_INVERT = 567, - EVENT_INTERFACE_JOYSTICK_DEADZONE = 568, + EVENT_INTERFACE_JOYSTICK_DEADZONE = 562, + EVENT_INTERFACE_JOYSTICK_X = 563, + EVENT_INTERFACE_JOYSTICK_Y = 564, + EVENT_INTERFACE_JOYSTICK_Z = 565, + EVENT_INTERFACE_JOYSTICK_CAM_X = 566, + EVENT_INTERFACE_JOYSTICK_CAM_Y = 567, + EVENT_INTERFACE_JOYSTICK_CAM_Z = 568, + EVENT_INTERFACE_JOYSTICK_X_INVERT = 569, + EVENT_INTERFACE_JOYSTICK_Y_INVERT = 570, + EVENT_INTERFACE_JOYSTICK_Z_INVERT = 571, + EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT = 572, + EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT = 573, + EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT = 574, - EVENT_INTERFACE_GLINTl = 570, - EVENT_INTERFACE_GLINTr = 571, - EVENT_INTERFACE_GLINTu = 572, - EVENT_INTERFACE_GLINTb = 573, + EVENT_INTERFACE_GLINTl = 590, + EVENT_INTERFACE_GLINTr = 591, + EVENT_INTERFACE_GLINTu = 592, + EVENT_INTERFACE_GLINTb = 593, - EVENT_INTERFACE_NEDIT = 580, - EVENT_INTERFACE_NLIST = 581, - EVENT_INTERFACE_NOK = 582, - EVENT_INTERFACE_NDELETE = 584, - EVENT_INTERFACE_NLABEL = 585, + EVENT_INTERFACE_NEDIT = 595, + EVENT_INTERFACE_NLIST = 596, + EVENT_INTERFACE_NOK = 597, + EVENT_INTERFACE_NDELETE = 598, + EVENT_INTERFACE_NLABEL = 599, EVENT_INTERFACE_IOWRITE = 600, EVENT_INTERFACE_IOREAD = 601, @@ -376,6 +387,31 @@ enum EventType EVENT_CMD = 800, EVENT_SPEED = 801, + EVENT_DBG_STATS = 850, + EVENT_DBG_SPAWN_OBJ = 851, + EVENT_DBG_TELEPORT = 852, + EVENT_DBG_LIGHTNING = 853, + EVENT_DBG_RESOURCES = 854, + EVENT_DBG_GOTO = 855, + EVENT_DBG_CRASHSPHERES = 856, + EVENT_DBG_LIGHTS = 857, + EVENT_DBG_LIGHTS_DUMP = 858, + + EVENT_SPAWN_CANCEL = 860, + EVENT_SPAWN_ME = 861, + EVENT_SPAWN_WHEELEDGRABBER = 862, + EVENT_SPAWN_WHEELEDSHOOTER = 863, + EVENT_SPAWN_PHAZERSHOOTER = 864, + EVENT_SPAWN_BOTFACTORY = 865, + EVENT_SPAWN_CONVERTER = 866, + EVENT_SPAWN_DERRICK = 867, + EVENT_SPAWN_POWERSTATION= 868, + EVENT_SPAWN_TITANIUM = 869, + EVENT_SPAWN_TITANIUMORE = 870, + EVENT_SPAWN_URANIUMORE = 871, + EVENT_SPAWN_POWERCELL = 872, + EVENT_SPAWN_NUCLEARCELL = 873, + EVENT_HYPER_PREV = 900, EVENT_HYPER_NEXT = 901, EVENT_HYPER_HOME = 902, diff --git a/src/common/key.h b/src/common/key.h index 4f089ec6..d249860c 100644 --- a/src/common/key.h +++ b/src/common/key.h @@ -87,8 +87,13 @@ enum InputSlot INPUT_SLOT_CAMERA, INPUT_SLOT_DESEL, INPUT_SLOT_ACTION, - INPUT_SLOT_NEAR, - INPUT_SLOT_AWAY, + INPUT_SLOT_CAM_LEFT, + INPUT_SLOT_CAM_RIGHT, + INPUT_SLOT_CAM_UP, + INPUT_SLOT_CAM_DOWN, + INPUT_SLOT_CAM_NEAR, + INPUT_SLOT_CAM_AWAY, + INPUT_SLOT_CAM_ALT, INPUT_SLOT_NEXT, INPUT_SLOT_HUMAN, INPUT_SLOT_QUIT, @@ -102,8 +107,6 @@ enum InputSlot INPUT_SLOT_SPEED30, INPUT_SLOT_SPEED40, INPUT_SLOT_SPEED60, - INPUT_SLOT_CAMERA_UP, - INPUT_SLOT_CAMERA_DOWN, INPUT_SLOT_PAUSE, INPUT_SLOT_CMDLINE, @@ -119,6 +122,9 @@ enum JoyAxisSlot JOY_AXIS_SLOT_X, JOY_AXIS_SLOT_Y, JOY_AXIS_SLOT_Z, + JOY_AXIS_SLOT_CAM_X, + JOY_AXIS_SLOT_CAM_Y, + JOY_AXIS_SLOT_CAM_Z, JOY_AXIS_SLOT_MAX }; diff --git a/src/common/misc.cpp b/src/common/misc.cpp deleted file mode 100644 index e96f58ed..00000000 --- a/src/common/misc.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam - * http://epsitec.ch; http://colobot.info; http://github.com/colobot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://gnu.org/licenses - */ - - -#include "common/misc.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -// Returns a non-accented letter. - -char GetNoAccent(char letter) -{ - /* - if ( letter < 0 ) - { - if ( letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' ) return 'a'; - - if ( letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' ) return 'e'; - - if ( letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' ) return 'i'; - - if ( letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' ) return 'o'; - - if ( letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' ) return 'u'; - - if ( letter == '�' ) return 'c'; - - if ( letter == '�' ) return 'n'; - - if ( letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' ) return 'A'; - - if ( letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' ) return 'E'; - - if ( letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' ) return 'I'; - - if ( letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' ) return 'O'; - - if ( letter == '�' || - letter == '�' || - letter == '�' || - letter == '�' ) return 'U'; - - if ( letter == '�' ) return 'C'; - - if ( letter == '�' ) return 'N'; - }*/ - - return letter; -} - -// Returns an uppercase letter. - -char GetToUpper(char letter) -{ - /*if ( letter < 0 ) - { - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - }*/ - - return toupper(letter); -} - -// Returns a lowercase letter. - -char GetToLower(char letter) -{ - /*if ( letter < 0 ) - { - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - - if ( letter == '�' ) return '�'; - }*/ - - return tolower(letter); -} - - -// Converting time to string. - -void TimeToAscii(time_t time, char *buffer) -{ - struct tm when; - int year; - - when = *localtime(&time); - year = when.tm_year+1900; - if ( year < 2000 ) year -= 1900; - else year -= 2000; - char format[10]; - int hour; - - hour = when.tm_hour; // 0..23 - if ( hour < 12 ) // morning? - { - strcpy(format, "am"); - } - else // afternoon? - { - strcpy(format, "pm"); - hour -= 12; // 0..11 - } - if ( hour == 0 ) hour = 12; - - sprintf(buffer, "%.2d.%.2d.%.2d %.2d:%.2d %s", - when.tm_mon+1, when.tm_mday, year, - hour, when.tm_min, format); -} - -// Converting time to string. - -void TimeToAsciiClean(time_t time, char *buffer) -{ - struct tm when; - int year; - - when = *localtime(&time); - year = when.tm_year+1900; - if ( year < 2000 ) year -= 1900; - else year -= 2000; - - sprintf(buffer, "%.2d%.2d%.2d%.2d%.2d", - year, when.tm_mon+1, when.tm_mday, - when.tm_hour, when.tm_min); -} - -std::string TimeFormat(float time) -{ - int minutes = floor(time/60); - double time2 = fmod(time, 60); - double seconds; - double fraction = modf(time2, &seconds)*100; - std::ostringstream sstream; - sstream << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << floor(seconds) << "." << std::setfill('0') << std::setw(2) << floor(fraction); - return sstream.str(); -} - - -// Adds an extension to file, if doesn't already one. - -void AddExt(char* filename, const char* ext) -{ - if ( strchr(filename, '.') != nullptr ) return; // already an extension? - strcat(filename, ext); -} - -int GetCurrentTimestamp() -{ - return std::chrono::seconds(std::time(nullptr)).count(); -} diff --git a/src/common/misc.h b/src/common/misc.h deleted file mode 100644 index d2927815..00000000 --- a/src/common/misc.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam - * http://epsitec.ch; http://colobot.info; http://github.com/colobot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://gnu.org/licenses - */ - - -#pragma once - - -#include -#include - - -// TODO: rewrite/refactor or remove - -extern char GetNoAccent(char letter); -extern char GetToUpper(char letter); -extern char GetToLower(char letter); - -extern void TimeToAscii(time_t time, char *buffer); -extern void TimeToAsciiClean(time_t time, char *buffer); -extern std::string TimeFormat(float time); - -extern void AddExt(char* filename, const char* ext); - -extern int GetCurrentTimestamp(); diff --git a/src/common/resources/resourcemanager.cpp b/src/common/resources/resourcemanager.cpp index 94326a9f..3ed0dee6 100644 --- a/src/common/resources/resourcemanager.cpp +++ b/src/common/resources/resourcemanager.cpp @@ -31,11 +31,8 @@ #include -#include #include -namespace fs = boost::filesystem; - CResourceManager::CResourceManager(const char *argv0) { @@ -152,27 +149,17 @@ bool CResourceManager::CreateDirectory(const std::string& directory) return false; } -//TODO: Don't use boost::filesystem here bool CResourceManager::RemoveDirectory(const std::string& directory) { if (PHYSFS_isInit()) { - bool success = true; - std::string writeDir = PHYSFS_getWriteDir(); - try + std::string path = CleanPath(directory); + for (auto file : ListFiles(path)) { - std::string path = writeDir + "/" + CleanPath(directory); - #if PLATFORM_WINDOWS - fs::remove_all(CSystemUtilsWindows::UTF8_Decode(path)); - #else - fs::remove_all(path); - #endif + if (PHYSFS_delete((path + "/" + file).c_str()) == 0) + return false; } - catch (std::exception&) - { - success = false; - } - return success; + return PHYSFS_delete(path.c_str()) != 0; } return false; } @@ -241,32 +228,6 @@ long long CResourceManager::GetLastModificationTime(const std::string& filename) return -1; } -//TODO: Don't use boost::filesystem. Why doesn't PHYSFS have this? -bool CResourceManager::Move(const std::string& from, const std::string& to) -{ - if (PHYSFS_isInit()) - { - bool success = true; - std::string writeDir = PHYSFS_getWriteDir(); - try - { - std::string path_from = writeDir + "/" + CleanPath(from); - std::string path_to = writeDir + "/" + CleanPath(to); - #if PLATFORM_WINDOWS - fs::rename(CSystemUtilsWindows::UTF8_Decode(path_from), CSystemUtilsWindows::UTF8_Decode(path_to)); - #else - fs::rename(path_from, path_to); - #endif - } - catch (std::exception&) - { - success = false; - } - return success; - } - return false; -} - bool CResourceManager::Remove(const std::string& filename) { if (PHYSFS_isInit()) diff --git a/src/common/resources/resourcemanager.h b/src/common/resources/resourcemanager.h index b21ad267..61f85b38 100644 --- a/src/common/resources/resourcemanager.h +++ b/src/common/resources/resourcemanager.h @@ -66,8 +66,6 @@ public: //! Returns last modification date as timestamp static long long GetLastModificationTime(const std::string &filename); - //! Move file/directory - static bool Move(const std::string &from, const std::string &to); //! Remove file static bool Remove(const std::string& filename); }; diff --git a/src/common/restext.cpp b/src/common/restext.cpp index c1cd857f..9770c32a 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -75,17 +75,17 @@ void InitializeRestext() stringsText[RT_TITLE_WRITE] = TR("Save the current mission"); stringsText[RT_TITLE_READ] = TR("Load a saved mission"); - stringsText[RT_PLAY_CHAP_CHAPTERS] = TR(" Chapters:"); - stringsText[RT_PLAY_CHAP_PLANETS] = TR(" Planets:"); - stringsText[RT_PLAY_CHAP_USERLVL] = TR(" Custom levels:"); - stringsText[RT_PLAY_LIST_LEVELS] = TR(" Levels in this chapter:"); - stringsText[RT_PLAY_LIST_EXERCISES] = TR(" Exercises in the chapter:"); - stringsText[RT_PLAY_LIST_CHALLENGES] = TR(" Challenges in the chapter:"); - stringsText[RT_PLAY_LIST_MISSIONS] = TR(" Missions on this planet:"); - stringsText[RT_PLAY_LIST_FREEGAME] = TR(" Free game on this planet:"); - stringsText[RT_PLAY_RESUME] = TR(" Summary:"); + stringsText[RT_PLAY_CHAP_CHAPTERS] = TR("Chapters:"); + stringsText[RT_PLAY_CHAP_PLANETS] = TR("Planets:"); + stringsText[RT_PLAY_CHAP_USERLVL] = TR("Custom levels:"); + stringsText[RT_PLAY_LIST_LEVELS] = TR("Levels in this chapter:"); + stringsText[RT_PLAY_LIST_EXERCISES] = TR("Exercises in the chapter:"); + stringsText[RT_PLAY_LIST_CHALLENGES] = TR("Challenges in the chapter:"); + stringsText[RT_PLAY_LIST_MISSIONS] = TR("Missions on this planet:"); + stringsText[RT_PLAY_LIST_FREEGAME] = TR("Free game on this planet:"); + stringsText[RT_PLAY_RESUME] = TR("Summary:"); - stringsText[RT_SETUP_MODE] = TR(" Resolution:"); + stringsText[RT_SETUP_MODE] = TR("Resolution:"); stringsText[RT_SETUP_KEY1] = TR("1) First click on the key you want to redefine."); stringsText[RT_SETUP_KEY2] = TR("2) Then press the key you want to use instead."); @@ -98,7 +98,7 @@ void InitializeRestext() stringsText[RT_DIALOG_ABORT] = TR("Abort\\Abort the current mission"); stringsText[RT_DIALOG_CONTINUE] = TR("Continue\\Continue the current mission"); stringsText[RT_DIALOG_DELOBJ] = TR("Do you really want to destroy the selected building?"); - stringsText[RT_DIALOG_DELGAME] = TR("Do you want to delete %s's saved games? "); + stringsText[RT_DIALOG_DELGAME] = TR("Do you want to delete %s's saved games?"); stringsText[RT_DIALOG_YES] = TR("Yes"); stringsText[RT_DIALOG_NO] = TR("No"); stringsText[RT_DIALOG_LOADING] = TR("LOADING"); @@ -163,7 +163,7 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_NAME] = TR("Change player\\Change player"); stringsEvent[EVENT_INTERFACE_SETUP] = TR("Options\\Preferences"); stringsEvent[EVENT_INTERFACE_AGAIN] = TR("Restart\\Restart the mission from the beginning"); - stringsEvent[EVENT_INTERFACE_WRITE] = TR("Save\\Save the current mission "); + stringsEvent[EVENT_INTERFACE_WRITE] = TR("Save\\Save the current mission"); stringsEvent[EVENT_INTERFACE_READ] = TR("Load\\Load a saved mission"); stringsEvent[EVENT_INTERFACE_ABORT] = TR("\\Return to Colobot: Gold Edition"); stringsEvent[EVENT_INTERFACE_QUIT] = TR("Quit\\Quit Colobot: Gold Edition"); @@ -184,6 +184,7 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_LIGHT] = TR("Dynamic lighting\\Mobile light sources"); stringsEvent[EVENT_INTERFACE_PARTI] = TR("Number of particles\\Explosions, dust, reflections, etc."); stringsEvent[EVENT_INTERFACE_CLIP] = TR("Render distance\\Maximum visibility"); + stringsEvent[EVENT_INTERFACE_PAUSE_BLUR]= TR("Pause blur\\Blur the background on the pause screen"); stringsEvent[EVENT_INTERFACE_RAIN] = TR("Particles in the interface\\Steam clouds and sparks in the interface"); stringsEvent[EVENT_INTERFACE_GLINT] = TR("Reflections on the buttons \\Shiny buttons"); stringsEvent[EVENT_INTERFACE_TOOLTIP] = TR("Help balloons\\Explain the function of the buttons"); @@ -220,8 +221,13 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CAMERA] = TR("Change camera\\Switches between onboard camera and following camera"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_DESEL] = TR("Previous object\\Selects the previous object"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_ACTION] = TR("Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)"); - stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_NEAR] = TR("Camera closer\\Moves the camera forward"); - stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_AWAY] = TR("Camera back\\Moves the camera backward"); + stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CAM_LEFT] = TR("Camera left\\Turns the camera left"); + stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CAM_RIGHT] = TR("Camera right\\Turns the camera right"); + stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CAM_UP] = TR("Camera up\\Turns the camera up"); + stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CAM_DOWN] = TR("Camera down\\Turns the camera down"); + stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CAM_NEAR] = TR("Camera closer\\Moves the camera forward"); + stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CAM_AWAY] = TR("Camera back\\Moves the camera backward"); + stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CAM_ALT] = TR("Alternative camera mode\\Move sideways instead of rotating (in free camera)"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_NEXT] = TR("Next object\\Selects the next object"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_HUMAN] = TR("Select the astronaut\\Selects the astronaut"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_QUIT] = TR("Quit\\Quit the current mission or exercise"); @@ -235,13 +241,11 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED30] = TR("Speed 3.0x\\Triple speed"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED40] = TR("Speed 4.0x\\Quadruple speed"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED60] = TR("Speed 6.0x\\Sextuple speed"); - stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CAMERA_UP] = TR("Camera up\\Increase camera angle while visiting message origin"); - stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CAMERA_DOWN] = TR("Camera down\\Decrease camera angle while visiting message origin"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_PAUSE] = TR("Pause\\Pause the game without opening menu"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CMDLINE] = TR("Cheat console\\Show cheat console"); stringsEvent[EVENT_INTERFACE_VOLSOUND] = TR("Sound effects:\\Volume of engines, voice, shooting, etc."); - stringsEvent[EVENT_INTERFACE_VOLMUSIC] = TR("Background sound :\\Volume of audio tracks"); + stringsEvent[EVENT_INTERFACE_VOLMUSIC] = TR("Background sound:\\Volume of audio tracks"); stringsEvent[EVENT_INTERFACE_MIN] = TR("Lowest\\Minimum graphic quality (highest frame rate)"); stringsEvent[EVENT_INTERFACE_NORM] = TR("Normal\\Normal graphic quality"); @@ -254,6 +258,9 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_JOYSTICK_X_INVERT] = TR("Invert\\Invert values on this axis"); stringsEvent[EVENT_INTERFACE_JOYSTICK_Y_INVERT] = TR("Invert\\Invert values on this axis"); stringsEvent[EVENT_INTERFACE_JOYSTICK_Z_INVERT] = TR("Invert\\Invert values on this axis"); + stringsEvent[EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT] = TR("Invert\\Invert values on this axis"); + stringsEvent[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT] = TR("Invert\\Invert values on this axis"); + stringsEvent[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT] = TR("Invert\\Invert values on this axis"); stringsEvent[EVENT_INTERFACE_NEDIT] = TR("\\New player name"); stringsEvent[EVENT_INTERFACE_NOK] = TR("OK\\Choose the selected player"); @@ -283,9 +290,9 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_PCGb] = TR("Green"); stringsEvent[EVENT_INTERFACE_PCBb] = TR("Blue"); stringsEvent[EVENT_INTERFACE_PFACE1] = TR("\\Face 1"); - stringsEvent[EVENT_INTERFACE_PFACE2] = TR("\\Face 4"); + stringsEvent[EVENT_INTERFACE_PFACE2] = TR("\\Face 2"); stringsEvent[EVENT_INTERFACE_PFACE3] = TR("\\Face 3"); - stringsEvent[EVENT_INTERFACE_PFACE4] = TR("\\Face 2"); + stringsEvent[EVENT_INTERFACE_PFACE4] = TR("\\Face 4"); stringsEvent[EVENT_INTERFACE_PGLASS0] = TR("\\No eyeglasses"); stringsEvent[EVENT_INTERFACE_PGLASS1] = TR("\\Eyeglasses 1"); stringsEvent[EVENT_INTERFACE_PGLASS2] = TR("\\Eyeglasses 2"); @@ -388,10 +395,6 @@ void InitializeRestext() stringsEvent[EVENT_OBJECT_GINFO] = TR("Transmitted information"); stringsEvent[EVENT_OBJECT_MAPZOOM] = TR("Zoom mini-map"); stringsEvent[EVENT_OBJECT_CAMERA] = TR("Camera (\\key camera;)"); - stringsEvent[EVENT_OBJECT_CAMERAleft] = TR("Camera to left"); - stringsEvent[EVENT_OBJECT_CAMERAright] = TR("Camera to right"); - stringsEvent[EVENT_OBJECT_CAMERAnear] = TR("Camera nearest"); - stringsEvent[EVENT_OBJECT_CAMERAaway] = TR("Camera awayest"); stringsEvent[EVENT_OBJECT_HELP] = TR("Help about selected object"); stringsEvent[EVENT_OBJECT_SOLUCE] = TR("Show the solution"); stringsEvent[EVENT_OBJECT_SHORTCUT_MODE]= TR("Switch bots <-> buildings"); @@ -436,15 +439,15 @@ void InitializeRestext() stringsEvent[EVENT_STUDIO_CANCEL] = TR("Cancel\\Cancel all changes"); stringsEvent[EVENT_STUDIO_CLONE] = TR("Clone program"); stringsEvent[EVENT_STUDIO_NEW] = TR("New"); - stringsEvent[EVENT_STUDIO_OPEN] = TR("Open (Ctrl+o)"); - stringsEvent[EVENT_STUDIO_SAVE] = TR("Save (Ctrl+s)"); - stringsEvent[EVENT_STUDIO_UNDO] = TR("Undo (Ctrl+z)"); - stringsEvent[EVENT_STUDIO_CUT] = TR("Cut (Ctrl+x)"); - stringsEvent[EVENT_STUDIO_COPY] = TR("Copy (Ctrl+c)"); - stringsEvent[EVENT_STUDIO_PASTE] = TR("Paste (Ctrl+v)"); + stringsEvent[EVENT_STUDIO_OPEN] = TR("Open (Ctrl+O)"); + stringsEvent[EVENT_STUDIO_SAVE] = TR("Save (Ctrl+S)"); + stringsEvent[EVENT_STUDIO_UNDO] = TR("Undo (Ctrl+Z)"); + stringsEvent[EVENT_STUDIO_CUT] = TR("Cut (Ctrl+X)"); + stringsEvent[EVENT_STUDIO_COPY] = TR("Copy (Ctrl+C)"); + stringsEvent[EVENT_STUDIO_PASTE] = TR("Paste (Ctrl+V)"); stringsEvent[EVENT_STUDIO_SIZE] = TR("Font size"); stringsEvent[EVENT_STUDIO_TOOL] = TR("Instructions (\\key help;)"); - stringsEvent[EVENT_STUDIO_HELP] = TR("Programming help (\\key prog;)"); + stringsEvent[EVENT_STUDIO_HELP] = TR("Programming help (\\key prog;)"); stringsEvent[EVENT_STUDIO_COMPILE] = TR("Compile"); stringsEvent[EVENT_STUDIO_RUN] = TR("Execute/stop"); stringsEvent[EVENT_STUDIO_REALTIME] = TR("Pause/continue"); @@ -605,8 +608,8 @@ void InitializeRestext() stringsErr[ERR_ENERGY_LOW] = TR("Not enough energy yet"); stringsErr[ERR_ENERGY_EMPTY] = TR("No titanium to transform"); stringsErr[ERR_ENERGY_BAD] = TR("Transforms only titanium"); - stringsErr[ERR_BASE_DLOCK] = TR("Doors blocked by a robot or another object "); - stringsErr[ERR_BASE_DHUMAN] = TR("You must get on the spaceship to take off "); + stringsErr[ERR_BASE_DLOCK] = TR("Doors blocked by a robot or another object"); + stringsErr[ERR_BASE_DHUMAN] = TR("You must get on the spaceship to take off"); stringsErr[ERR_LABO_NULL] = TR("Nothing to analyze"); stringsErr[ERR_LABO_BAD] = TR("Analyzes only organic matter"); stringsErr[ERR_LABO_ALREADY] = TR("Analysis already performed"); @@ -632,14 +635,12 @@ void InitializeRestext() stringsErr[ERR_DELETEMOBILE] = TR("Bot destroyed"); stringsErr[ERR_DELETEBUILDING] = TR("Building destroyed"); stringsErr[ERR_ENEMY_OBJECT] = TR("Unable to control enemy objects"); - stringsErr[ERR_OBLIGATORYTOKEN] = TR("\"%s\" missing in this exercise"); - stringsErr[ERR_PROHIBITEDTOKEN] = TR("Do not use in this exercise"); stringsErr[ERR_WRONG_BOT] = TR("Inappropriate bot"); stringsErr[INFO_BUILD] = TR("Building completed"); stringsErr[INFO_CONVERT] = TR("Titanium available"); stringsErr[INFO_RESEARCH] = TR("Research program completed"); - stringsErr[INFO_RESEARCHTANK] = TR("Plans for tracked robots available "); + stringsErr[INFO_RESEARCHTANK] = TR("Plans for tracked robots available"); stringsErr[INFO_RESEARCHFLY] = TR("You can fly with the keys (\\key gup;) and (\\key gdown;)"); stringsErr[INFO_RESEARCHTHUMP] = TR("Plans for thumper available"); stringsErr[INFO_RESEARCHCANON] = TR("Plans for shooter available"); @@ -673,7 +674,7 @@ void InitializeRestext() stringsCbot[CBot::CBotErrOpenPar] = TR("Opening bracket missing"); - stringsCbot[CBot::CBotErrClosePar] = TR("Closing bracket missing "); + stringsCbot[CBot::CBotErrClosePar] = TR("Closing bracket missing"); stringsCbot[CBot::CBotErrNotBoolean] = TR("The expression must return a boolean value"); stringsCbot[CBot::CBotErrUndefVar] = TR("Variable not declared"); stringsCbot[CBot::CBotErrBadLeft] = TR("Assignment impossible"); @@ -681,11 +682,11 @@ void InitializeRestext() stringsCbot[CBot::CBotErrCaseOut] = TR("Instruction \"case\" outside a block \"switch\""); stringsCbot[CBot::CBotErrNoEnd] = TR("Instructions after the final closing brace"); stringsCbot[CBot::CBotErrCloseBlock] = TR("End of block missing"); - stringsCbot[CBot::CBotErrElseWhitoutIf] = TR("Instruction \"else\" without corresponding \"if\" "); - stringsCbot[CBot::CBotErrOpenBlock] = TR("Opening brace missing "); + stringsCbot[CBot::CBotErrElseWhitoutIf] = TR("Instruction \"else\" without corresponding \"if\""); + stringsCbot[CBot::CBotErrOpenBlock] = TR("Opening brace missing"); stringsCbot[CBot::CBotErrBadType1] = TR("Wrong type for the assignment"); stringsCbot[CBot::CBotErrRedefVar] = TR("A variable can not be declared twice"); - stringsCbot[CBot::CBotErrBadType2] = TR("The types of the two operands are incompatible "); + stringsCbot[CBot::CBotErrBadType2] = TR("The types of the two operands are incompatible"); stringsCbot[CBot::CBotErrUndefCall] = TR("Unknown function"); stringsCbot[CBot::CBotErrNoDoubleDots] = TR("Sign \" : \" missing"); stringsCbot[CBot::CBotErrNoWhile] = TR("Keyword \"while\" missing"); @@ -700,7 +701,7 @@ void InitializeRestext() stringsCbot[CBot::CBotErrNoFunc] = TR("Function name missing"); stringsCbot[CBot::CBotErrOverParam] = TR("Too many parameters"); stringsCbot[CBot::CBotErrRedefFunc] = TR("Function already exists"); - stringsCbot[CBot::CBotErrLowParam] = TR("Parameters missing "); + stringsCbot[CBot::CBotErrLowParam] = TR("Parameters missing"); stringsCbot[CBot::CBotErrBadParam] = TR("No function with this name accepts this kind of parameter"); stringsCbot[CBot::CBotErrNbParam] = TR("No function with this name accepts this number of parameters"); stringsCbot[CBot::CBotErrUndefItem] = TR("This is not a member of this class"); @@ -715,11 +716,12 @@ void InitializeRestext() stringsCbot[CBot::CBotErrBadIndex] = TR("Incorrect index type"); stringsCbot[CBot::CBotErrPrivate] = TR("Private element"); stringsCbot[CBot::CBotErrNoPublic] = TR("Public required"); + stringsCbot[CBot::CBotErrNoExpression] = TR("Expression expected after ="); stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero"); stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized"); stringsCbot[CBot::CBotErrBadThrow] = TR("Negative value rejected by \"throw\""); - stringsCbot[CBot::CBotErrNoRetVal] = TR("The function returned no value "); + stringsCbot[CBot::CBotErrNoRetVal] = TR("The function returned no value"); stringsCbot[CBot::CBotErrNoRun] = TR("No function running"); stringsCbot[CBot::CBotErrUndefFunc] = TR("Calling an unknown function"); stringsCbot[CBot::CBotErrNotClass] = TR("This class does not exist"); diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 2b67ef1d..4519b079 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -98,6 +98,7 @@ void CSettings::SaveSettings() GetConfigFile().SetIntProperty("Setup", "MusicVolume", sound->GetMusicVolume()); GetConfigFile().SetBoolProperty("Setup", "EditIndentMode", engine->GetEditIndentMode()); GetConfigFile().SetIntProperty("Setup", "EditIndentValue", engine->GetEditIndentValue()); + GetConfigFile().SetBoolProperty("Setup", "PauseBlur", engine->GetPauseBlurEnabled()); GetConfigFile().SetIntProperty("Setup", "MipmapLevel", engine->GetTextureMipmapLevel()); GetConfigFile().SetIntProperty("Setup", "Anisotropy", engine->GetTextureAnisotropyLevel()); @@ -229,6 +230,9 @@ void CSettings::LoadSettings() if (GetConfigFile().GetIntProperty("Setup", "EditIndentValue", iValue)) engine->SetEditIndentValue(iValue); + if (GetConfigFile().GetBoolProperty("Setup", "PauseBlur", bValue)) + engine->SetPauseBlurEnabled(bValue); + if (GetConfigFile().GetIntProperty("Setup", "MipmapLevel", iValue)) engine->SetTextureMipmapLevel(iValue); diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h index 2b5f4a60..b4e897db 100644 --- a/src/graphics/core/device.h +++ b/src/graphics/core/device.h @@ -413,9 +413,6 @@ public: //! Sets only the texture wrap modes (for faster than thru stage params) virtual void SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) = 0; - //! Sets the texture coordinate generation mode for given texture unit - virtual void SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) = 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/nulldevice.cpp b/src/graphics/core/nulldevice.cpp index 5ab4ec08..aba9f800 100644 --- a/src/graphics/core/nulldevice.cpp +++ b/src/graphics/core/nulldevice.cpp @@ -27,9 +27,6 @@ namespace Gfx CNullDevice::CNullDevice() { - m_matrix = Math::Matrix(); - m_material = Material(); - m_light = Light(); } CNullDevice::~CNullDevice() @@ -157,10 +154,6 @@ void CNullDevice::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode { } -void CNullDevice::SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) -{ -} - void CNullDevice::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, Color color) { diff --git a/src/graphics/core/nulldevice.h b/src/graphics/core/nulldevice.h index 68f2effc..5721d920 100644 --- a/src/graphics/core/nulldevice.h +++ b/src/graphics/core/nulldevice.h @@ -17,11 +17,6 @@ * along with this program. If not, see http://gnu.org/licenses */ -/** - * \file graphics/core/device.h - * \brief Abstract graphics device - CDevice class and related structs/enums - */ - #pragma once #include "graphics/core/device.h" @@ -38,7 +33,6 @@ namespace Gfx /** * \class CNullDevice * \brief Device implementation that doesn't render anything - * */ class CNullDevice : public CDevice { @@ -86,7 +80,6 @@ public: void SetTextureStageParams(int index, const TextureStageParams ¶ms) override; void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; - void SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) 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; @@ -160,11 +153,6 @@ public: int GetMaxTextureSize() override; bool IsFramebufferSupported() override; - -private: - Math::Matrix m_matrix; - Material m_material; - Light m_light; }; diff --git a/src/graphics/engine/camera.cpp b/src/graphics/engine/camera.cpp index 53613b6a..9f7fc40e 100644 --- a/src/graphics/engine/camera.cpp +++ b/src/graphics/engine/camera.cpp @@ -88,21 +88,20 @@ CCamera::CCamera() m_smooth = CAM_SMOOTH_NORM; m_cameraObj = nullptr; - m_eyeDistance = 10.0f; m_initDelay = 0.0f; m_actualEye = Math::Vector(0.0f, 0.0f, 0.0f); m_actualLookat = Math::Vector(0.0f, 0.0f, 0.0f); m_finalEye = Math::Vector(0.0f, 0.0f, 0.0f); m_finalLookat = Math::Vector(0.0f, 0.0f, 0.0f); - m_normEye = Math::Vector(0.0f, 0.0f, 0.0f); - m_normLookat = Math::Vector(0.0f, 0.0f, 0.0f); + m_prevEye = Math::Vector(0.0f, 0.0f, 0.0f); + m_prevLookat = Math::Vector(0.0f, 0.0f, 0.0f); m_focus = 1.0f; m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f); m_directionH = 0.0f; m_directionV = 0.0f; - m_heightEye = 20.0f; + m_heightEye = 40.0f; m_heightLookat = 0.0f; m_speed = 2.0f; @@ -110,7 +109,6 @@ CCamera::CCamera() m_backMin = 0.0f; m_addDirectionH = 0.0f; m_addDirectionV = 0.0f; - m_transparency = false; m_fixDist = 0.0f; m_fixDirectionH = 0.0f; @@ -122,10 +120,6 @@ CCamera::CCamera() m_visitType = CAM_TYPE_NULL; m_visitDirectionV = 0.0f; - m_editHeight = 40.0f; - - m_remotePan = 0.0f; - m_centeringPhase = CAM_PHASE_NULL; m_centeringAngleH = 0.0f; m_centeringAngleV = 0.0f; @@ -225,7 +219,6 @@ void CCamera::Init(Math::Vector eye, Math::Vector lookat, float delay) m_directionH = Math::RotateAngle(eye.x - lookat.x, eye.z - lookat.z) + Math::PI / 2.0f; m_directionV = -Math::RotateAngle(Math::DistanceProjected(eye, lookat), eye.y - lookat.y); - m_eyeDistance = 10.0f; m_heightLookat = 10.0f; m_backDist = 30.0f; m_backMin = 10.0f; @@ -242,7 +235,6 @@ void CCamera::Init(Math::Vector eye, Math::Vector lookat, float delay) m_scriptEye = m_actualEye; m_scriptLookat = m_actualLookat; m_focus = 1.00f; - m_remotePan = 0.0f; FlushEffect(); FlushOver(); @@ -262,9 +254,7 @@ CObject* CCamera::GetControllingObject() void CCamera::SetType(CameraType type) { - m_remotePan = 0.0f; - - if ( (m_type == CAM_TYPE_BACK) && m_transparency ) + if (m_type == CAM_TYPE_BACK) { for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) { @@ -274,27 +264,24 @@ void CCamera::SetType(CameraType type) SetTransparency(obj, 0.0f); // opaque object } } - m_transparency = false; - if (type == CAM_TYPE_INFO || - type == CAM_TYPE_VISIT) // xx -> info ? + if (type == CAM_TYPE_VISIT) // *** -> visit ? { - m_normEye = m_engine->GetEyePt(); - m_normLookat = m_engine->GetLookatPt(); + m_prevEye = m_engine->GetEyePt(); + m_prevLookat = m_engine->GetLookatPt(); m_engine->SetFocus(1.00f); // normal m_type = type; return; } - if (m_type == CAM_TYPE_INFO || - m_type == CAM_TYPE_VISIT) // info -> xx ? + if (m_type == CAM_TYPE_VISIT) // visit -> *** ? { m_engine->SetFocus(m_focus); // gives initial focus m_type = type; Math::Vector upVec = Math::Vector(0.0f, 1.0f, 0.0f); - SetViewParams(m_normEye, m_normLookat, upVec); + SetViewParams(m_prevEye, m_prevLookat, upVec); return; } @@ -390,70 +377,6 @@ CameraSmooth CCamera::GetSmooth() return m_smooth; } -void CCamera::SetDist(float dist) -{ - m_fixDist = dist; -} - -float CCamera::GetDist() -{ - return m_fixDist; -} - -void CCamera::SetFixDirectionH(float angle) -{ - m_fixDirectionH = angle; -} - -float CCamera::GetFixDirectionH() -{ - return m_fixDirectionH; -} - -void CCamera::SetFixDirectionV(float angle) -{ - m_fixDirectionV = angle; -} - -float CCamera::GetFixDirectionV() -{ - return m_fixDirectionV; -} - -void CCamera::SetRemotePan(float value) -{ - m_remotePan = value; -} - -float CCamera::GetRemotePan() -{ - return m_remotePan; -} - -void CCamera::SetRemoteZoom(float value) -{ - value = Math::Norm(value); - - if ( m_type == CAM_TYPE_BACK ) - m_backDist = m_backMin + (200.0f - m_backMin) * value; - - if ( m_type == CAM_TYPE_FIX || - m_type == CAM_TYPE_PLANE ) - m_fixDist = 10.0f + (200.0f - 10.0f) * value; -} - -float CCamera::GetRemoteZoom() -{ - if ( m_type == CAM_TYPE_BACK ) - return (m_backDist - m_backMin) / (200.0f - m_backMin); - - if ( m_type == CAM_TYPE_FIX || - m_type == CAM_TYPE_PLANE ) - return (m_fixDist - 10.0f) / (200.0f - 10.0f); - - return 0.0f; -} - void CCamera::StartVisit(Math::Vector goal, float dist) { m_visitType = m_type; @@ -528,8 +451,7 @@ bool CCamera::StopCentering(CObject *object, float time) void CCamera::AbortCentering() { - if (m_type == CAM_TYPE_INFO || - m_type == CAM_TYPE_VISIT ) + if (m_type == CAM_TYPE_VISIT ) return; if (m_centeringPhase == CAM_PHASE_NULL) @@ -566,8 +488,7 @@ void CCamera::StartEffect(CameraEffect effect, Math::Vector pos, float force) void CCamera::EffectFrame(const Event &event) { - if (m_type == CAM_TYPE_INFO || - m_type == CAM_TYPE_VISIT) + if (m_type == CAM_TYPE_VISIT) return; if (m_effectType == CAM_EFFECT_NULL) @@ -742,8 +663,7 @@ void CCamera::StartOver(CameraOverEffect effect, Math::Vector pos, float force) void CCamera::OverFrame(const Event &event) { - if (m_type == CAM_TYPE_INFO || - m_type == CAM_TYPE_VISIT) + if (m_type == CAM_TYPE_VISIT) return; if (m_overType == CAM_OVER_EFFECT_NULL) @@ -828,98 +748,74 @@ void CCamera::OverFrame(const Event &event) } } -void CCamera::FixCamera() +void CCamera::UpdateCameraAnimation(const Math::Vector &eyePt, + const Math::Vector &lookatPt, + float rTime) { - m_initDelay = 0.0f; - m_actualEye = m_finalEye = m_scriptEye; - m_actualLookat = m_finalLookat = m_scriptLookat; - SetViewTime(m_scriptEye, m_scriptLookat, 0.0f); -} - -void CCamera::SetViewTime(const Math::Vector &eyePt, - const Math::Vector &lookatPt, - float rTime) -{ - Math::Vector eye, lookat; - - if (m_type == CAM_TYPE_INFO) + if (m_initDelay > 0.0f) { - eye = eyePt; - lookat = lookatPt; + m_initDelay -= rTime; + if (m_initDelay < 0.0f) + m_initDelay = 0.0f; + rTime /= 1.0f+m_initDelay; + } + + m_finalEye = eyePt; + m_finalLookat = lookatPt; + IsCollision(m_finalEye, m_finalLookat); + + float prog = 0.0f; + float dist = Math::Distance(m_finalEye, m_actualEye); + + if (m_smooth == CAM_SMOOTH_NONE) prog = dist; + if (m_smooth == CAM_SMOOTH_NORM) prog = powf(dist, 1.5f) * rTime * 0.75f; + if (m_smooth == CAM_SMOOTH_HARD) prog = dist * rTime * 4.0f; + if (dist == 0.0f) + { + m_actualEye = m_finalEye; } else { - if (m_initDelay > 0.0f) - { - m_initDelay -= rTime; - if (m_initDelay < 0.0f) - m_initDelay = 0.0f; - rTime /= 1.0f+m_initDelay; - } - - eye = eyePt; - lookat = lookatPt; - if ( !IsCollision(eye, lookat) ) - { - m_finalEye = eye; - m_finalLookat = lookat; - } - - float prog = 0.0f; - float dist = Math::Distance(m_finalEye, m_actualEye); - - if (m_smooth == CAM_SMOOTH_NONE) prog = dist; - if (m_smooth == CAM_SMOOTH_NORM) prog = powf(dist, 1.5f) * rTime * 0.75f; - if (m_smooth == CAM_SMOOTH_HARD) prog = dist * rTime * 4.0f; - if (dist == 0.0f) - { - m_actualEye = m_finalEye; - } - else - { - if (prog > dist) - prog = dist; - m_actualEye = (m_finalEye - m_actualEye) / dist * prog + m_actualEye; - } - - dist = Math::Distance(m_finalLookat, m_actualLookat); - if ( m_smooth == CAM_SMOOTH_NONE ) prog = dist; - if ( m_smooth == CAM_SMOOTH_NORM ) prog = powf(dist, 1.5f) * rTime * 3.0f; - if ( m_smooth == CAM_SMOOTH_HARD ) prog = dist * rTime * 4.0f; - if ( dist == 0.0f ) - { - m_actualLookat = m_finalLookat; - } - else - { - if (prog > dist) - prog = dist; - m_actualLookat = (m_finalLookat - m_actualLookat) / dist * prog + m_actualLookat; - } - - eye = m_effectOffset+m_actualEye; - m_water->AdjustEye(eye); - - float h = m_terrain->GetFloorLevel(eye); - if (eye.y < h + 4.0f) - eye.y = h + 4.0f; - - lookat = m_effectOffset+m_actualLookat; + if (prog > dist) + prog = dist; + m_actualEye = (m_finalEye - m_actualEye) / dist * prog + m_actualEye; } - Math::Vector upVec = Math::Vector(0.0f, 1.0f, 0.0f); - SetViewParams(eye, lookat, upVec); + dist = Math::Distance(m_finalLookat, m_actualLookat); + if ( m_smooth == CAM_SMOOTH_NONE ) prog = dist; + if ( m_smooth == CAM_SMOOTH_NORM ) prog = powf(dist, 1.5f) * rTime * 3.0f; + if ( m_smooth == CAM_SMOOTH_HARD ) prog = dist * rTime * 4.0f; + if ( dist == 0.0f ) + { + m_actualLookat = m_finalLookat; + } + else + { + if (prog > dist) + prog = dist; + m_actualLookat = (m_finalLookat - m_actualLookat) / dist * prog + m_actualLookat; + } + + Math::Vector eye = m_effectOffset+m_actualEye; + m_water->AdjustEye(eye); + + float h = m_terrain->GetFloorLevel(eye); + if (eye.y < h + 4.0f) + eye.y = h + 4.0f; + + Math::Vector lookat = m_effectOffset+m_actualLookat; + + SetViewParams(eye, lookat); } -bool CCamera::IsCollision(Math::Vector &eye, Math::Vector lookat) +void CCamera::IsCollision(Math::Vector &eye, Math::Vector lookat) { - if (m_type == CAM_TYPE_BACK ) return IsCollisionBack(eye, lookat); - if (m_type == CAM_TYPE_FIX ) return IsCollisionFix (eye, lookat); - if (m_type == CAM_TYPE_PLANE) return IsCollisionFix (eye, lookat); - return false; + if (m_type == CAM_TYPE_BACK ) IsCollisionBack(); + if (m_type == CAM_TYPE_FIX ) IsCollisionFix (eye, lookat); + if (m_type == CAM_TYPE_PLANE) IsCollisionFix (eye, lookat); } -bool CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat) +void CCamera::IsCollisionBack() { ObjectType iType; if (m_cameraObj == nullptr) @@ -937,8 +833,6 @@ bool CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat) max.y = Math::Max(m_actualEye.y, m_actualLookat.y); max.z = Math::Max(m_actualEye.z, m_actualLookat.z); - m_transparency = false; - for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) { if (IsObjectBeingTransported(obj)) @@ -1005,12 +899,10 @@ bool CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat) if (len > del) continue; SetTransparency(obj, 1.0f); // transparent object - m_transparency = true; } - return false; } -bool CCamera::IsCollisionFix(Math::Vector &eye, Math::Vector lookat) +void CCamera::IsCollisionFix(Math::Vector &eye, Math::Vector lookat) { for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) { @@ -1045,248 +937,165 @@ bool CCamera::IsCollisionFix(Math::Vector &eye, Math::Vector lookat) dist = Math::Distance(eye, lookat); Math::Vector proj = Projection(eye, lookat, objPos); eye = (lookat - eye) * objRadius / dist + proj; - return false; + return; } } - return false; } bool CCamera::EventProcess(const Event &event) { - switch (event.type) + if (event.type == EVENT_MOUSE_MOVE) { - case EVENT_FRAME: - EventFrame(event); - break; + if (m_engine->GetMouseType() == ENG_MOUSE_SCROLLR || + m_engine->GetMouseType() == ENG_MOUSE_SCROLLL || + m_engine->GetMouseType() == ENG_MOUSE_SCROLLU || + m_engine->GetMouseType() == ENG_MOUSE_SCROLLD || + m_engine->GetMouseType() == ENG_MOUSE_MOVE ) + { + m_engine->SetMouseType(ENG_MOUSE_NORM); + } - case EVENT_MOUSE_BUTTON_DOWN: - case EVENT_MOUSE_BUTTON_UP: - EventMouseButton(event); - break; + if ((event.mouseButtonsState & MOUSE_BUTTON_RIGHT) != 0 || (event.mouseButtonsState & MOUSE_BUTTON_MIDDLE) != 0) + { + Math::Point newDelta = event.mousePos - m_mousePos; + if (m_cameraInvertX) + newDelta.x = -newDelta.x; + if (m_cameraInvertY) + newDelta.y = -newDelta.y; + m_mouseDelta += newDelta; - case EVENT_MOUSE_MOVE: - EventMouseMove(event); - break; + m_engine->SetMouseType(ENG_MOUSE_MOVE); + } - case EVENT_MOUSE_WHEEL: - EventMouseWheel(event); - break; + m_mouseDeltaEdge.LoadZero(); + if (m_oldCameraScroll) + { + if (event.mousePos.x < MOUSE_EDGE_MARGIN) + m_mouseDeltaEdge.x = event.mousePos.x / MOUSE_EDGE_MARGIN - 1.0f; + if (event.mousePos.x > 1.0f - MOUSE_EDGE_MARGIN) + m_mouseDeltaEdge.x = 1.0f - (1.0f - event.mousePos.x) / MOUSE_EDGE_MARGIN; + if (event.mousePos.y < MOUSE_EDGE_MARGIN) + m_mouseDeltaEdge.y = event.mousePos.y / MOUSE_EDGE_MARGIN - 1.0f; + if (event.mousePos.y > 1.0f - MOUSE_EDGE_MARGIN) + m_mouseDeltaEdge.y = 1.0f - (1.0f - event.mousePos.y) / MOUSE_EDGE_MARGIN; - default: - break; - } - return true; -} + if (m_type == CAM_TYPE_FREE || + m_type == CAM_TYPE_EDIT || + m_type == CAM_TYPE_BACK || + m_type == CAM_TYPE_FIX || + m_type == CAM_TYPE_PLANE || + m_type == CAM_TYPE_EXPLO ) + { + if (m_mouseDeltaEdge.x > 0.0f) + m_engine->SetMouseType(ENG_MOUSE_SCROLLR); + if (m_mouseDeltaEdge.x < 0.0f) + m_engine->SetMouseType(ENG_MOUSE_SCROLLL); + } + if (m_type == CAM_TYPE_FREE || + m_type == CAM_TYPE_EDIT ) + { + if (m_mouseDeltaEdge.y > 0.0f) + m_engine->SetMouseType(ENG_MOUSE_SCROLLU); + if (m_mouseDeltaEdge.y < 0.0f) + m_engine->SetMouseType(ENG_MOUSE_SCROLLD); + } -bool CCamera::EventMouseMove(const Event &event) -{ - if (m_engine->GetMouseType() == ENG_MOUSE_SCROLLR || - m_engine->GetMouseType() == ENG_MOUSE_SCROLLL || - m_engine->GetMouseType() == ENG_MOUSE_SCROLLU || - m_engine->GetMouseType() == ENG_MOUSE_SCROLLD || - m_engine->GetMouseType() == ENG_MOUSE_MOVE ) - { - m_engine->SetMouseType(ENG_MOUSE_NORM); + m_mouseDeltaEdge.x /= 2*Math::PI; + m_mouseDeltaEdge.y /= Math::PI; + } + + m_mousePos = event.mousePos; } - if ((event.mouseButtonsState & MOUSE_BUTTON_RIGHT) != 0 || (event.mouseButtonsState & MOUSE_BUTTON_MIDDLE) != 0) + if (event.type == EVENT_MOUSE_WHEEL) { - Math::Point newDelta = event.mousePos - m_mousePos; + auto dir = event.GetData()->y; + m_mouseWheelDelta -= dir; + } + + if (event.type == EVENT_MOUSE_BUTTON_DOWN || event.type == EVENT_MOUSE_BUTTON_UP) + { + if (event.GetData()->button == MOUSE_BUTTON_RIGHT || event.GetData()->button == MOUSE_BUTTON_MIDDLE) + { + if ((event.mouseButtonsState & MOUSE_BUTTON_RIGHT) != 0 || (event.mouseButtonsState & MOUSE_BUTTON_MIDDLE) != 0) + { + m_engine->SetMouseType(ENG_MOUSE_MOVE); + } + else + { + m_engine->SetMouseType(ENG_MOUSE_NORM); + } + } + } + + if (event.type == EVENT_FRAME && !m_freeze) + { + Math::Point newDelta = m_mouseDeltaEdge * m_speed * event.rTime; if (m_cameraInvertX) newDelta.x = -newDelta.x; if (m_cameraInvertY) newDelta.y = -newDelta.y; m_mouseDelta += newDelta; - m_engine->SetMouseType(ENG_MOUSE_MOVE); - } + EffectFrame(event); + OverFrame(event); - m_mouseDeltaEdge.LoadZero(); - if (m_oldCameraScroll) - { - if (event.mousePos.x < MOUSE_EDGE_MARGIN) - m_mouseDeltaEdge.x = event.mousePos.x / MOUSE_EDGE_MARGIN - 1.0f; - if (event.mousePos.x > 1.0f - MOUSE_EDGE_MARGIN) - m_mouseDeltaEdge.x = 1.0f - (1.0f - event.mousePos.x) / MOUSE_EDGE_MARGIN; - if (event.mousePos.y < MOUSE_EDGE_MARGIN) - m_mouseDeltaEdge.y = event.mousePos.y / MOUSE_EDGE_MARGIN - 1.0f; - if (event.mousePos.y > 1.0f - MOUSE_EDGE_MARGIN) - m_mouseDeltaEdge.y = 1.0f - (1.0f - event.mousePos.y) / MOUSE_EDGE_MARGIN; - - if (m_type == CAM_TYPE_FREE || - m_type == CAM_TYPE_EDIT || - m_type == CAM_TYPE_BACK || - m_type == CAM_TYPE_FIX || - m_type == CAM_TYPE_PLANE || - m_type == CAM_TYPE_EXPLO ) - { - if (m_mouseDeltaEdge.x > 0.0f) - m_engine->SetMouseType(ENG_MOUSE_SCROLLR); - if (m_mouseDeltaEdge.x < 0.0f) - m_engine->SetMouseType(ENG_MOUSE_SCROLLL); - } if (m_type == CAM_TYPE_FREE || - m_type == CAM_TYPE_EDIT ) - { - if (m_mouseDeltaEdge.y > 0.0f) - m_engine->SetMouseType(ENG_MOUSE_SCROLLU); - if (m_mouseDeltaEdge.y < 0.0f) - m_engine->SetMouseType(ENG_MOUSE_SCROLLD); - } + m_type == CAM_TYPE_EDIT) + return EventFrameFree(event, m_type != CAM_TYPE_EDIT); - m_mouseDeltaEdge.x /= 2*Math::PI; - m_mouseDeltaEdge.y /= Math::PI; + if (m_type == CAM_TYPE_BACK) + return EventFrameBack(event); + + if (m_type == CAM_TYPE_FIX || + m_type == CAM_TYPE_PLANE) + return EventFrameFix(event); + + if (m_type == CAM_TYPE_EXPLO) + return EventFrameExplo(event); + + if (m_type == CAM_TYPE_ONBOARD) + return EventFrameOnBoard(event); + + if (m_type == CAM_TYPE_SCRIPT) + return EventFrameScript(event); + + if (m_type == CAM_TYPE_VISIT) + return EventFrameVisit(event); } - - m_mousePos = event.mousePos; return true; } -void CCamera::EventMouseWheel(const Event &event) +bool CCamera::EventFrameFree(const Event &event, bool keysAllowed) { - auto dir = event.GetData()->y; - - if (m_type == CAM_TYPE_BACK) - { - m_backDist -= 8.0f*dir; - if (m_backDist < m_backMin) - m_backDist = m_backMin; - if (m_backDist > 200.0f) - m_backDist = 200.0f; - } - - if ( m_type == CAM_TYPE_FIX || - m_type == CAM_TYPE_PLANE ) - { - m_fixDist -= 8.0f*dir; - if (m_fixDist < 10.0f) - m_fixDist = 10.0f; - if (m_fixDist > 200.0f) - m_fixDist = 200.0f; - } - - if ( m_type == CAM_TYPE_VISIT ) - { - m_visitDist -= 8.0f*dir; - if (m_visitDist < 20.0f) - m_visitDist = 20.0f; - if (m_visitDist > 200.0f) - m_visitDist = 200.0f; - } -} - -void CCamera::EventMouseButton(const Event &event) -{ - if (event.GetData()->button == MOUSE_BUTTON_RIGHT || event.GetData()->button == MOUSE_BUTTON_MIDDLE) - { - if ((event.mouseButtonsState & MOUSE_BUTTON_RIGHT) != 0 || (event.mouseButtonsState & MOUSE_BUTTON_MIDDLE) != 0) - { - m_engine->SetMouseType(ENG_MOUSE_MOVE); - } - else - { - m_engine->SetMouseType(ENG_MOUSE_NORM); - } - } -} - -bool CCamera::EventFrame(const Event &event) -{ - Math::Point newDelta = m_mouseDeltaEdge * m_speed * event.rTime; - if (m_cameraInvertX) - newDelta.x = -newDelta.x; - if (m_cameraInvertY) - newDelta.y = -newDelta.y; - m_mouseDelta += newDelta; - - EffectFrame(event); - OverFrame(event); - - if (m_type == CAM_TYPE_FREE) - return EventFrameFree(event); - - if (m_type == CAM_TYPE_EDIT) - return EventFrameEdit(event); - - if (m_type == CAM_TYPE_DIALOG) - return EventFrameDialog(event); - - if (m_type == CAM_TYPE_BACK) - return EventFrameBack(event); - - if (m_type == CAM_TYPE_FIX || - m_type == CAM_TYPE_PLANE) - return EventFrameFix(event); - - if (m_type == CAM_TYPE_EXPLO) - return EventFrameExplo(event); - - if (m_type == CAM_TYPE_ONBOARD) - return EventFrameOnBoard(event); - - if (m_type == CAM_TYPE_SCRIPT) - return EventFrameScript(event); - - if (m_type == CAM_TYPE_INFO) - return EventFrameInfo(event); - - if (m_type == CAM_TYPE_VISIT) - return EventFrameVisit(event); - - return true; -} - -bool CCamera::EventFrameFree(const Event &event) -{ - Math::Vector cameraInput = event.cameraInput; - if (m_cameraObj == nullptr) - { - cameraInput = Math::Clamp(cameraInput + event.motionInput, Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector(1.0f, 1.0f, 1.0f)); - } + Math::Vector cameraMove = CalculateCameraMovement(event, keysAllowed); float factor = m_heightEye * 0.5f + 30.0f; + bool secondary = m_input->GetKeyState(INPUT_SLOT_CAM_ALT) || event.mouseButtonsState & MOUSE_BUTTON_MIDDLE; // TODO: make mouse button a keybinding - m_directionH -= m_mouseDelta.x * 2*Math::PI; - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDelta.y * factor * m_speed); - m_mouseDelta.LoadZero(); + // Forward/Backward + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -cameraMove.y * factor * 2); - // Up/Down - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, cameraInput.y * event.rTime * factor * m_speed); - - // Left/Right - if ( event.kmodState & KEY_MOD(CTRL) ) + // Left/Right (pan or rotate) + if (secondary) { - if ( cameraInput.x < 0.0f ) - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH + Math::PI / 2.0f, m_directionV, -cameraInput.x * event.rTime * factor * m_speed); - if ( cameraInput.x > 0.0f ) - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH - Math::PI / 2.0f, m_directionV, cameraInput.x * event.rTime * factor * m_speed); + if (cameraMove.x < 0.0f) + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH + Math::PI / 2.0f, m_directionV, -cameraMove.x * factor); + if (cameraMove.x > 0.0f) + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH - Math::PI / 2.0f, m_directionV, cameraMove.x * factor); } else { - m_directionH -= cameraInput.x * event.rTime * 0.7f * m_speed; + m_directionH -= cameraMove.x; } - // PageUp/PageDown - if ( m_input->GetKeyState(INPUT_SLOT_AWAY) ) - { - if (m_heightEye < 500.0f) - m_heightEye += event.rTime * factor * m_speed; - } - if ( m_input->GetKeyState(INPUT_SLOT_NEAR) ) - { - if (m_heightEye > -2.0f) - m_heightEye -= event.rTime * factor * m_speed; - } + // Up/Down (eye or lookat point) + if (secondary) + m_heightLookat -= cameraMove.z; + else + m_heightEye -= cameraMove.z; - - if ( m_input->GetKeyState(INPUT_SLOT_CAMERA_UP) ) - { - m_heightLookat += event.rTime * factor * m_speed; - } - if ( m_input->GetKeyState(INPUT_SLOT_CAMERA_DOWN) ) - { - m_heightLookat -= event.rTime * factor * m_speed; - } + m_heightEye = Math::Clamp(m_heightEye, -2.0f, 500.0f); m_terrain->AdjustToBounds(m_eyePt, 10.0f); @@ -1309,79 +1118,22 @@ bool CCamera::EventFrameFree(const Event &event) if (m_terrain->AdjustToFloor(lookatPt, true)) lookatPt.y += m_heightLookat; - SetViewTime(m_eyePt, lookatPt, event.rTime); + UpdateCameraAnimation(m_eyePt, lookatPt, event.rTime); return true; } -bool CCamera::EventFrameEdit(const Event &event) -{ - float factor = m_editHeight * 0.5f + 30.0f; - - m_directionH -= m_mouseDelta.x * 0.7f * 2*Math::PI; - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDelta.y * factor * m_speed); - - m_fixDirectionH += m_mouseDelta.x * 2*Math::PI; - m_fixDirectionH = Math::NormAngle(m_fixDirectionH); - - m_mouseDelta.LoadZero(); - - m_terrain->AdjustToBounds(m_eyePt, 10.0f); - - if (m_terrain->AdjustToFloor(m_eyePt, false)) - { - m_eyePt.y += m_editHeight; - - Math::Vector pos = m_eyePt; - if (m_terrain->AdjustToFloor(pos, false)) - { - pos.y += 2.0f; - if (m_eyePt.y < pos.y) - m_eyePt.y = pos.y; - } - - } - - Math::Vector lookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); - - if ( m_terrain->AdjustToFloor(lookatPt, true)) - lookatPt.y += m_heightLookat; - - SetViewTime(m_eyePt, lookatPt, event.rTime); - - return true; -} - -bool CCamera::EventFrameDialog(const Event &event) -{ - return true; -} - bool CCamera::EventFrameBack(const Event &event) { - ObjectType type; - if (m_cameraObj == nullptr) - type = OBJECT_NULL; - else - type = m_cameraObj->GetType(); + Math::Vector cameraMove = CalculateCameraMovement(event); + m_addDirectionH += cameraMove.x; + m_addDirectionV += cameraMove.y; + m_backDist += cameraMove.z; - // +/-. - if (m_input->GetKeyState(INPUT_SLOT_NEAR)) - { - m_backDist -= event.rTime * 30.0f * m_speed; - if (m_backDist < m_backMin) m_backDist = m_backMin; - } - if (m_input->GetKeyState(INPUT_SLOT_AWAY)) - { - m_backDist += event.rTime * 30.0f * m_speed; - if (m_backDist > 200.0f) m_backDist = 200.0f; - } - - m_addDirectionH -= m_mouseDelta.x * 2*Math::PI; m_addDirectionH = Math::NormAngle(m_addDirectionH); - if (m_mouseDelta.Length() > 0) - AbortCentering(); // special stops framing - m_mouseDelta.LoadZero(); + m_addDirectionV = Math::NormAngle(m_addDirectionV); + + m_backDist = Math::Clamp(m_backDist, m_backMin, 200.0f); // Increase the special framework float centeringH = 0.0f; @@ -1423,6 +1175,8 @@ bool CCamera::EventFrameBack(const Event &event) if (m_cameraObj != nullptr) { + ObjectType type = m_cameraObj->GetType(); + Math::Vector lookatPt = m_cameraObj->GetPosition(); if (type == OBJECT_BASE ) lookatPt.y += 40.0f; else if (type == OBJECT_HUMAN) lookatPt.y += 1.0f; @@ -1456,7 +1210,7 @@ bool CCamera::EventFrameBack(const Event &event) { h += Math::PI; // back } - h = Math::NormAngle(h)+m_remotePan; + h = Math::NormAngle(h); float v = 0.0f; //? h += m_centeringCurrentH; @@ -1491,7 +1245,7 @@ bool CCamera::EventFrameBack(const Event &event) m_eyePt = ExcludeTerrain(m_eyePt, lookatPt, h, v); m_eyePt = ExcludeObject(m_eyePt, lookatPt, h, v); - SetViewTime(m_eyePt, lookatPt, event.rTime); + UpdateCameraAnimation(m_eyePt, lookatPt, event.rTime); m_directionH = h + Math::PI / 2.0f; m_directionV = v; @@ -1502,36 +1256,21 @@ bool CCamera::EventFrameBack(const Event &event) bool CCamera::EventFrameFix(const Event &event) { - // +/-. - if (m_input->GetKeyState(INPUT_SLOT_NEAR)) - { - m_fixDist -= event.rTime * 30.0f * m_speed; - if (m_fixDist < 10.0f) m_fixDist = 10.0f; - } - if (m_input->GetKeyState(INPUT_SLOT_AWAY)) - { - m_fixDist += event.rTime * 30.0f * m_speed; - if (m_fixDist > 200.0f) m_fixDist = 200.0f; - } + Math::Vector cameraMove = CalculateCameraMovement(event); + m_fixDirectionH += cameraMove.x; + m_fixDirectionV += cameraMove.y; + m_fixDist += cameraMove.z; - m_fixDirectionH -= m_mouseDelta.x * 2*Math::PI; - if (m_mouseDelta.Length() > 0) - AbortCentering(); // special stops framing - m_mouseDelta.LoadZero(); - - // Left/Right - m_fixDirectionH += event.cameraInput.x * event.rTime * 0.7f * m_speed; m_fixDirectionH = Math::NormAngle(m_fixDirectionH); - // Up/Down - m_fixDirectionV -= event.cameraInput.y * event.rTime * 0.7f * m_speed; - m_fixDirectionV = Math::Min(Math::Max(m_fixDirectionV, -0.5*Math::PI), 0.25*Math::PI); + m_fixDirectionV = Math::Clamp(m_fixDirectionV, -0.5f*Math::PI, 0.25f*Math::PI); + m_fixDist = Math::Clamp(m_fixDist, 10.0f, 200.0f); if (m_cameraObj != nullptr) { Math::Vector lookatPt = m_cameraObj->GetPosition(); - float h = m_fixDirectionH + m_remotePan; + float h = m_fixDirectionH; float v = m_fixDirectionV; float d = m_fixDist; @@ -1540,7 +1279,7 @@ bool CCamera::EventFrameFix(const Event &event) m_eyePt = ExcludeTerrain(m_eyePt, lookatPt, h, v); m_eyePt = ExcludeObject(m_eyePt, lookatPt, h, v); - SetViewTime(m_eyePt, lookatPt, event.rTime); + UpdateCameraAnimation(m_eyePt, lookatPt, event.rTime); m_directionH = h + Math::PI / 2.0f; m_directionV = v; @@ -1551,8 +1290,9 @@ bool CCamera::EventFrameFix(const Event &event) bool CCamera::EventFrameExplo(const Event &event) { - m_directionH -= m_mouseDelta.x * 2*Math::PI; - m_mouseDelta.LoadZero(); + Math::Vector cameraMove = CalculateCameraMovement(event); + m_directionH += cameraMove.x; + m_directionH = Math::NormAngle(m_directionH); m_terrain->AdjustToBounds(m_eyePt, 10.0f); @@ -1575,7 +1315,7 @@ bool CCamera::EventFrameExplo(const Event &event) if (m_terrain->AdjustToFloor(lookatPt, true)) lookatPt.y += m_heightLookat; - SetViewTime(m_eyePt, lookatPt, event.rTime); + UpdateCameraAnimation(m_eyePt, lookatPt, event.rTime); return true; } @@ -1597,83 +1337,68 @@ bool CCamera::EventFrameOnBoard(const Event &event) return true; } -bool CCamera::EventFrameInfo(const Event &event) -{ - SetViewTime(Math::Vector(0.0f, 0.0f, 0.0f), - Math::Vector(0.0f, 0.0f, 1.0f), - event.rTime); - return true; -} - bool CCamera::EventFrameVisit(const Event &event) { m_visitTime += event.rTime; - // +/-. - if (m_input->GetKeyState(INPUT_SLOT_NEAR)) - { - m_visitDist -= event.rTime * 50.0f * m_speed; - if (m_visitDist < 20.0f) m_visitDist = 20.0f; - } - if (m_input->GetKeyState(INPUT_SLOT_AWAY)) - { - m_visitDist += event.rTime * 50.0f * m_speed; - if (m_visitDist > 200.0f) m_visitDist = 200.0f; - } + Math::Vector cameraMove = CalculateCameraMovement(event); - // PageUp/Down. - if (m_input->GetKeyState(INPUT_SLOT_CAMERA_UP)) - { - m_visitDirectionV -= event.rTime * 1.0f * m_speed; - if (m_visitDirectionV < -Math::PI * 0.40f) m_visitDirectionV = -Math::PI * 0.40f; - } - if (m_input->GetKeyState(INPUT_SLOT_CAMERA_DOWN)) - { - m_visitDirectionV += event.rTime * 1.0f * m_speed; - if (m_visitDirectionV > 0.0f ) m_visitDirectionV = 0.0f; - } + // ZoomIn/ZoomOut + m_visitDist += cameraMove.z; + m_visitDist = Math::Clamp(m_visitDist, 20.0f, 200.0f); - m_visitDist -= m_mouseDelta.y * 100.0f * m_speed; - m_mouseDelta.LoadZero(); - if (m_visitDist < 20.0f) m_visitDist = 20.0f; - if (m_visitDist > 200.0f) m_visitDist = 200.0f; + // Up/Down + m_visitDirectionV += cameraMove.y; + m_visitDirectionV = Math::Clamp(m_visitDirectionV, -Math::PI * 0.40f, 0.0f); float angleH = (m_visitTime / 10.0f) * (Math::PI * 2.0f); float angleV = m_visitDirectionV; Math::Vector eye = RotateView(m_visitGoal, angleH, angleV, m_visitDist); eye = ExcludeTerrain(eye, m_visitGoal, angleH, angleV); eye = ExcludeObject(eye, m_visitGoal, angleH, angleV); - SetViewTime(eye, m_visitGoal, event.rTime); + UpdateCameraAnimation(eye, m_visitGoal, event.rTime); return true; } bool CCamera::EventFrameScript(const Event &event) { - SetViewTime(m_scriptEye + m_effectOffset, - m_scriptLookat + m_effectOffset, event.rTime); + UpdateCameraAnimation(m_scriptEye + m_effectOffset, + m_scriptLookat + m_effectOffset, event.rTime); return true; } -void CCamera::SetScriptEye(Math::Vector eye) +void CCamera::SetScriptCameraAnimateEye(Math::Vector eye) { m_scriptEye = eye; } -void CCamera::SetScriptLookat(Math::Vector lookat) +void CCamera::SetScriptCameraAnimateLookat(Math::Vector lookat) { m_scriptLookat = lookat; } +void CCamera::SetScriptCamera(Math::Vector eye, Math::Vector lookat) +{ + SetScriptCameraAnimate(eye, lookat); + + m_initDelay = 0.0f; + m_actualEye = m_finalEye = m_scriptEye; + m_actualLookat = m_finalLookat = m_scriptLookat; +} + +void CCamera::SetScriptCameraAnimate(Math::Vector eye, Math::Vector lookat) +{ + m_scriptEye = eye; + m_scriptLookat = lookat; +} + void CCamera::SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, const Math::Vector &up) { - m_engine->SetViewParams(eye, lookat, up, m_eyeDistance); + m_engine->SetViewParams(eye, lookat, up); bool under = (eye.y < m_water->GetLevel()); // Is it underwater? - if (m_type == CAM_TYPE_INFO) - under = false; - m_engine->SetRankView(under ? 1 : 0); } @@ -1726,4 +1451,40 @@ void CCamera::SetCameraSpeed(float speed) m_speed = speed; } +Math::Vector CCamera::CalculateCameraMovement(const Event &event, bool keysAllowed) +{ + Math::Vector delta; + + delta.x += m_mouseDelta.x * 2*Math::PI; + delta.y -= m_mouseDelta.y * Math::PI; + m_mouseDelta.LoadZero(); + + delta.z += m_mouseWheelDelta * 8.0f; + m_mouseWheelDelta = 0.0f; + + if (keysAllowed) + { + delta.x += event.cameraInput.x * event.rTime * 0.5f * m_speed; + delta.y -= event.cameraInput.y * event.rTime * 0.5f * m_speed; + delta.z -= event.cameraInput.z * event.rTime * 20.0f * m_speed; + + if (m_cameraObj == nullptr) + { + delta.x += event.motionInput.x * event.rTime * 0.5f * m_speed; + delta.y -= event.motionInput.y * event.rTime * 0.5f * m_speed; + delta.z -= event.motionInput.z * event.rTime * 20.0f * m_speed; + } + } + + if (delta.Length() > 0) + AbortCentering(); // special stops framing + + return delta; +} + +void CCamera::SetFreeze(bool freeze) +{ + m_freeze = freeze; +} + } diff --git a/src/graphics/engine/camera.h b/src/graphics/engine/camera.h index f00332a0..83ac7afd 100644 --- a/src/graphics/engine/camera.h +++ b/src/graphics/engine/camera.h @@ -44,29 +44,25 @@ namespace Gfx enum CameraType { //! Undefined - CAM_TYPE_NULL = 0, - //! Free camera (? never in principle ?) - CAM_TYPE_FREE = 1, + CAM_TYPE_NULL = 0, + //! Free camera + CAM_TYPE_FREE, //! Camera while editing a program - CAM_TYPE_EDIT = 2, + CAM_TYPE_EDIT, //! Camera on board a robot - CAM_TYPE_ONBOARD = 3, + CAM_TYPE_ONBOARD, //! Camera behind a robot - CAM_TYPE_BACK = 4, + CAM_TYPE_BACK, //! Static camera following robot - CAM_TYPE_FIX = 5, + CAM_TYPE_FIX, //! Camera steady after explosion - CAM_TYPE_EXPLO = 6, - //! Camera during a film script - CAM_TYPE_SCRIPT = 7, - //! Camera for displaying information - CAM_TYPE_INFO = 8, - //! Visit instead of an error - CAM_TYPE_VISIT = 9, - //! Camera for dialog - CAM_TYPE_DIALOG = 10, + CAM_TYPE_EXPLO, + //! Camera during a cutscene + CAM_TYPE_SCRIPT, + //! Visit camera, rotates around given position + CAM_TYPE_VISIT, //! Static camera height - CAM_TYPE_PLANE = 11, + CAM_TYPE_PLANE, }; enum CameraSmooth @@ -93,15 +89,15 @@ enum CameraEffect CAM_EFFECT_NULL = 0, //! Digging in CAM_EFFECT_TERRAFORM = 1, - //! ? Vehicle driving is severely ? + //! Hard landing CAM_EFFECT_CRASH = 2, //! Explosion CAM_EFFECT_EXPLO = 3, - //! ? Not mortal shot ? + //! Shot by an enemy CAM_EFFECT_SHOT = 4, //! Vibration during construction CAM_EFFECT_VIBRATION = 5, - //! ? Spleen reactor ? + //! Overheated reactor CAM_EFFECT_PET = 6, }; @@ -126,7 +122,9 @@ enum CameraOverEffect \class CCamera \brief Camera moving in 3D scene - ... */ + This class manages everything related to animating the camera in 3D scene. + Calculated values are then passed to Gfx::CEngine. +*/ class CCamera { public: @@ -136,70 +134,83 @@ public: //! Management of an event bool EventProcess(const Event &event); - //! Initializes the camera + /** + * \brief Initializes the camera + * \param eye Initial eye position + * \param lookat Initial lookat position + * \param delay Time of the initial entry animation + */ void Init(Math::Vector eye, Math::Vector lookat, float delay); //! Sets the object controlling the camera void SetControllingObject(CObject* object); + //! Gets the object controlling the camera CObject* GetControllingObject(); //! Change the type of camera - void SetType(CameraType type); - CameraType GetType(); + void SetType(CameraType type); + //! Get the type of the camera + CameraType GetType(); - //! Management of the smoothing mode - void SetSmooth(CameraSmooth type); + //! Set smoothing mode + void SetSmooth(CameraSmooth type); + //! Get smoothing mode CameraSmooth GetSmooth(); - //! Management of the setback distance - void SetDist(float dist); - float GetDist(); - //! Manage angle mode CAM_TYPE_FIX - void SetFixDirectionH(float angle); - float GetFixDirectionH(); - void SetFixDirectionV(float angle); - float GetFixDirectionV(); - - //! Managing the triggering mode of the camera panning - void SetRemotePan(float value); - float GetRemotePan(); - - //! Management of the remote zoom (0 .. 1) of the camera - void SetRemoteZoom(float value); - float GetRemoteZoom(); - - //! Start with a tour round the camera - void StartVisit(Math::Vector goal, float dist); - //! Circular end of a visit with the camera - void StopVisit(); - - //! Returns the point of view of the camera + //! Returns the current point of view of the camera void GetCamera(Math::Vector &eye, Math::Vector &lookat); - //! Specifies a special movement of camera to frame action + //! \name Visit camera management (CAM_TYPE_VISIT) - camera in this mode shows a position, constantly rotating around it + //@{ + //! Start visit camera + void StartVisit(Math::Vector goal, float dist); + //! Stop visit camera + void StopVisit(); + //@} + + //! \name Camera "centering" - moves the camera to show some happening action (e.g. sniffer sniffing) + //@{ + //! Move camera to show happening action bool StartCentering(CObject *object, float angleH, float angleV, float dist, float time); - //! Ends a special movement of camera to frame action + //! Go back to normal position after showing some happening action bool StopCentering(CObject *object, float time); - //! Stop framing special in the current position + //! Abort centering animation in the current position void AbortCentering(); + //@} - //! Removes the special effect with the camera - void FlushEffect(); - //! Starts a special effect with the camera + //! \name Camera shake effects + //@{ + //! Starts a camera shake effect void StartEffect(CameraEffect effect, Math::Vector pos, float force); + //! Removes the camera shake effect + void FlushEffect(); + //@} - //! Removes the effect of superposition in the foreground - void FlushOver(); - //! Specifies the base color - void SetOverBaseColor(Color color); + //! \name Camera overlay effects + //@{ + //! Starts camera overlay effect void StartOver(CameraOverEffect effect, Math::Vector pos, float force); + //! Removes camera overlay effect + void FlushOver(); + //! Specifies camera overlay effect base color + void SetOverBaseColor(Color color); + //@} - //! Sets the soft movement of the camera - void FixCamera(); - void SetScriptEye(Math::Vector eye); - void SetScriptLookat(Math::Vector lookat); + //! \name Script camera - cutscenes controlled by external code + //@{ + //! Script camera: Set camera position + void SetScriptCamera(Math::Vector eye, Math::Vector lookat); + //! Script camera: Animate to given camera position + void SetScriptCameraAnimate(Math::Vector eye, Math::Vector lookat); + //! Script camera: Animate to given eye position + void SetScriptCameraAnimateEye(Math::Vector eye); + //! Script camera: Animate to given lookat position + void SetScriptCameraAnimateLookat(Math::Vector lookat); + //@} + //! \name Configuration settings + //@{ void SetEffect(bool enable); bool GetEffect(); void SetBlood(bool enable); @@ -210,59 +221,72 @@ public: bool GetCameraInvertX(); void SetCameraInvertY(bool invert); bool GetCameraInvertY(); + //@} + //! Temporarily freeze camera movement + void SetFreeze(bool freeze); + + //! Set camera speed void SetCameraSpeed(float speed); protected: - //! Changes the camera according to the mouse moved - bool EventMouseMove(const Event &event); - //! Mouse wheel operation - void EventMouseWheel(const Event &event); - //! Mouse button handling - void EventMouseButton(const Event &event); - //! Changes the camera according to the time elapsed - bool EventFrame(const Event &event); - //! Moves the point of view - bool EventFrameFree(const Event &event); - //! Moves the point of view - bool EventFrameEdit(const Event &event); - //! Moves the point of view - bool EventFrameDialog(const Event &event); - //! Moves the point of view + //! Advances the effect of the camera + void EffectFrame(const Event &event); + //! Advanced overlay effect in the foreground + void OverFrame(const Event &event); + + bool EventFrameFree(const Event &event, bool keysAllowed); bool EventFrameBack(const Event &event); - //! Moves the point of view bool EventFrameFix(const Event &event); - //! Moves the point of view bool EventFrameExplo(const Event &event); - //! Moves the point of view bool EventFrameOnBoard(const Event &event); - //! Moves the point of view - bool EventFrameInfo(const Event &event); - //! Moves the point of view bool EventFrameVisit(const Event &event); - //! Moves the point of view bool EventFrameScript(const Event &event); - //! Specifies the location and direction of view to the 3D engine - void SetViewTime(const Math::Vector &eyePt, const Math::Vector &lookatPt, float rTime); - //! Avoid the obstacles - bool IsCollision(Math::Vector &eye, Math::Vector lookat); - //! Avoid the obstacles - bool IsCollisionBack(Math::Vector &eye, Math::Vector lookat); - //! Avoid the obstacles - bool IsCollisionFix(Math::Vector &eye, Math::Vector lookat); + /** + * \brief Calculates camera animation and sends updated camera position to the 3D engine + * \param eyePt Eye point + * \param lookatPt Lookat point + * \param rTime Time since last time this function was called (used to calculate animation) + * \see SetViewParams + */ + void UpdateCameraAnimation(const Math::Vector &eyePt, const Math::Vector &lookatPt, float rTime); + + /** + * \brief Avoid the obstacles + * + * For CAM_TYPE_BACK: make obstacles transparent + * For CAM_TYPE_FIX or CAM_TYPE_PLANE: adjust eye not to hit the obstacles + * + * \param eye Eye position, may be adjusted + * \param lookat Lookat point + */ + void IsCollision(Math::Vector &eye, Math::Vector lookat); + //! Avoid the obstacles (CAM_TYPE_BACK) + void IsCollisionBack(); + //! Avoid the obstacles (CAM_TYPE_FIX or CAM_TYPE_PLANE) + void IsCollisionFix(Math::Vector &eye, Math::Vector lookat); //! Adjusts the camera not to enter the ground Math::Vector ExcludeTerrain(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV); //! Adjusts the camera not to enter an object Math::Vector ExcludeObject(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV); - //! Specifies the location and direction of view - void SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, const Math::Vector &up); - //! Advances the effect of the camera - void EffectFrame(const Event &event); - //! Advanced overlay effect in the foreground - void OverFrame(const Event &event); + /** + * \brief Updates the location and direction of the camera in the 3D engine + * \param eye Eye point + * \param lookat Lookat point + * \param up Up vector + * \see CEngine::SetViewParams + */ + void SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, const Math::Vector &up = Math::Vector(0.0f, 1.0f, 0.0f)); + + /** + * \brief Calculate camera movement (from user inputs) to apply + * \return Math::Vector where x, y represent respectively horizontal and vertical angle change in radians and z represents zoom (distance change) + * \remarks Should not be called more often than once every EVENT_FRAME + **/ + Math::Vector CalculateCameraMovement(const Event &event, bool keysAllowed = true); protected: CEngine* m_engine; @@ -276,12 +300,10 @@ protected: //! Type of smoothing CameraSmooth m_smooth; //! Object linked to the camera - CObject* m_cameraObj; + CObject* m_cameraObj; - //! Distance between the eyes - float m_eyeDistance; - //! Time of initial centering - float m_initDelay; + //! Remaining time of initial camera entry animation + float m_initDelay; //! Current eye Math::Vector m_actualEye; @@ -289,14 +311,14 @@ protected: Math::Vector m_actualLookat; //! Final eye Math::Vector m_finalEye; - //! Final aim + //! Final lookat Math::Vector m_finalLookat; - //! Normal eye - Math::Vector m_normEye; - //! Normal aim - Math::Vector m_normLookat; + //! Eye position at the moment of entering CAM_TYPE_INFO/CAM_TYPE_VISIT + Math::Vector m_prevEye; + //! Lookat position at the moment of entering CAM_TYPE_INFO/CAM_TYPE_VISIT + Math::Vector m_prevLookat; - float m_focus; + float m_focus; //! CAM_TYPE_FREE: eye Math::Vector m_eyePt; @@ -313,19 +335,18 @@ protected: //! CAM_TYPE_BACK: distance float m_backDist; - //! CAM_TYPE_BACK: distance minimal + //! CAM_TYPE_BACK: minimal distance float m_backMin; - //! CAM_TYPE_BACK: additional direction + //! CAM_TYPE_BACK: additional horizontal direction float m_addDirectionH; - //! CAM_TYPE_BACK: additional direction + //! CAM_TYPE_BACK: additional vertical direction float m_addDirectionV; - bool m_transparency; //! CAM_TYPE_FIX: distance float m_fixDist; - //! CAM_TYPE_FIX: direction + //! CAM_TYPE_FIX: horizontal direction float m_fixDirectionH; - //! CAM_TYPE_FIX: direction + //! CAM_TYPE_FIX: vertical direction float m_fixDirectionV; //! CAM_TYPE_VISIT: target position @@ -339,15 +360,14 @@ protected: //! CAM_TYPE_VISIT: direction float m_visitDirectionV; - //! CAM_TYPE_EDIT: height - float m_editHeight; - - float m_remotePan; - //! Last known mouse position, used to calculate change since last frame Math::Point m_mousePos = Math::Point(0.5f, 0.5f); + //! Change of mouse position since last frame Math::Point m_mouseDelta = Math::Point(0.0f, 0.0f); + //! Change of camera position caused by edge camera Math::Point m_mouseDeltaEdge = Math::Point(0.0f, 0.0f); + //! Change of mouse wheel since last frame + float m_mouseWheelDelta = 0.0f; CenteringPhase m_centeringPhase; float m_centeringAngleH; @@ -376,16 +396,17 @@ protected: Math::Vector m_scriptEye; Math::Vector m_scriptLookat; - //! Shocks if explosion? + //! Is camera frozen? + bool m_freeze = false; + + //! \name Configuration settings + //@{ bool m_effect; - //! Blood? bool m_blood; - //! Scroll in the edges? - bool m_oldCameraScroll; - //! X inversion in the edges? + bool m_oldCameraScroll; bool m_cameraInvertX; - //! Y inversion in the edges? bool m_cameraInvertY; + //@} }; diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index a66f8063..27d2db70 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -59,6 +59,7 @@ #include "ui/controls/interface.h" #include +#include #include template<> Gfx::CEngine* CSingleton::m_instance = nullptr; @@ -67,6 +68,60 @@ template<> Gfx::CEngine* CSingleton::m_instance = nullptr; namespace Gfx { +/** + * \struct EngineMouse + * \brief Information about mouse cursor + */ +struct EngineMouse +{ + //! Index of texture element for 1st image + int icon1; + //! Index of texture element for 2nd image + int icon2; + //! Shadow texture part + int iconShadow; + //! Mode to render 1st image in + EngineRenderState mode1; + //! Mode to render 2nd image in + EngineRenderState mode2; + //! Hot point + Math::IntPoint hotPoint; + + EngineMouse(int icon1 = -1, + int icon2 = -1, + int iconShadow = -1, + EngineRenderState mode1 = ENG_RSTATE_NORMAL, + EngineRenderState mode2 = ENG_RSTATE_NORMAL, + Math::IntPoint hotPoint = Math::IntPoint()) + : icon1(icon1) + , icon2(icon2) + , iconShadow(iconShadow) + , mode1(mode1) + , mode2(mode2) + , hotPoint(hotPoint) + {} +}; + +const Math::IntPoint MOUSE_SIZE(32, 32); +const std::map MOUSE_TYPES = { + {{ENG_MOUSE_NORM}, {EngineMouse( 0, 1, 32, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::IntPoint( 1, 1))}}, + {{ENG_MOUSE_WAIT}, {EngineMouse( 2, 3, 33, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::IntPoint( 8, 12))}}, + {{ENG_MOUSE_HAND}, {EngineMouse( 4, 5, 34, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::IntPoint( 7, 2))}}, + {{ENG_MOUSE_NO}, {EngineMouse( 6, 7, 35, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::IntPoint(10, 10))}}, + {{ENG_MOUSE_EDIT}, {EngineMouse( 8, 9, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint( 6, 10))}}, + {{ENG_MOUSE_CROSS}, {EngineMouse(10, 11, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint(10, 10))}}, + {{ENG_MOUSE_MOVEV}, {EngineMouse(12, 13, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint( 5, 11))}}, + {{ENG_MOUSE_MOVEH}, {EngineMouse(14, 15, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint(11, 5))}}, + {{ENG_MOUSE_MOVED}, {EngineMouse(16, 17, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint( 9, 9))}}, + {{ENG_MOUSE_MOVEI}, {EngineMouse(18, 19, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint( 9, 9))}}, + {{ENG_MOUSE_MOVE}, {EngineMouse(20, 21, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint(11, 11))}}, + {{ENG_MOUSE_TARGET}, {EngineMouse(22, 23, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint(15, 15))}}, + {{ENG_MOUSE_SCROLLL}, {EngineMouse(24, 25, 43, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint( 2, 9))}}, + {{ENG_MOUSE_SCROLLR}, {EngineMouse(26, 27, 44, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint(17, 9))}}, + {{ENG_MOUSE_SCROLLU}, {EngineMouse(28, 29, 45, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint( 9, 2))}}, + {{ENG_MOUSE_SCROLLD}, {EngineMouse(30, 31, 46, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::IntPoint( 9, 17))}}, +}; + CEngine::CEngine(CApplication *app, CSystemUtils* systemUtils) : m_app(app), m_systemUtils(systemUtils), @@ -74,8 +129,7 @@ CEngine::CEngine(CApplication *app, CSystemUtils* systemUtils) m_fogColor(), m_deepView(), m_fogStart(), - m_highlightRank(), - m_mice() + m_highlightRank() { m_device = nullptr; @@ -148,6 +202,7 @@ CEngine::CEngine(CApplication *app, CSystemUtils* systemUtils) m_editIndentMode = true; m_editIndentValue = 4; m_tracePrecision = 1.0f; + m_pauseBlurEnabled = true; m_updateGeometry = false; @@ -158,24 +213,6 @@ CEngine::CEngine(CApplication *app, CSystemUtils* systemUtils) m_debugLights = false; m_debugDumpLights = false; - m_mice[ENG_MOUSE_NORM] = EngineMouse( 0, 1, 32, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::Point( 1.0f, 1.0f)); - m_mice[ENG_MOUSE_WAIT] = EngineMouse( 2, 3, 33, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::Point( 8.0f, 12.0f)); - m_mice[ENG_MOUSE_HAND] = EngineMouse( 4, 5, 34, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::Point( 7.0f, 2.0f)); - m_mice[ENG_MOUSE_NO] = EngineMouse( 6, 7, 35, ENG_RSTATE_TTEXTURE_WHITE, ENG_RSTATE_TTEXTURE_BLACK, Math::Point(10.0f, 10.0f)); - m_mice[ENG_MOUSE_EDIT] = EngineMouse( 8, 9, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 6.0f, 10.0f)); - m_mice[ENG_MOUSE_CROSS] = EngineMouse(10, 11, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point(10.0f, 10.0f)); - m_mice[ENG_MOUSE_MOVEV] = EngineMouse(12, 13, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 5.0f, 11.0f)); - m_mice[ENG_MOUSE_MOVEH] = EngineMouse(14, 15, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point(11.0f, 5.0f)); - m_mice[ENG_MOUSE_MOVED] = EngineMouse(16, 17, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 9.0f, 9.0f)); - m_mice[ENG_MOUSE_MOVEI] = EngineMouse(18, 19, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 9.0f, 9.0f)); - m_mice[ENG_MOUSE_MOVE] = EngineMouse(20, 21, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point(11.0f, 11.0f)); - m_mice[ENG_MOUSE_TARGET] = EngineMouse(22, 23, -1, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point(15.0f, 15.0f)); - m_mice[ENG_MOUSE_SCROLLL] = EngineMouse(24, 25, 43, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 2.0f, 9.0f)); - m_mice[ENG_MOUSE_SCROLLR] = EngineMouse(26, 27, 44, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point(17.0f, 9.0f)); - m_mice[ENG_MOUSE_SCROLLU] = EngineMouse(28, 29, 45, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 9.0f, 2.0f)); - m_mice[ENG_MOUSE_SCROLLD] = EngineMouse(30, 31, 46, ENG_RSTATE_TTEXTURE_BLACK, ENG_RSTATE_TTEXTURE_WHITE, Math::Point( 9.0f, 17.0f)); - - m_mouseSize = Math::Point(0.04f, 0.04f * (800.0f / 600.0f)); m_mouseType = ENG_MOUSE_NORM; m_fpsCounter = 0; @@ -278,7 +315,6 @@ void CEngine::SetTerrain(CTerrain* terrain) bool CEngine::Create() { m_size = m_app->GetVideoConfig().size; - m_mouseSize = Math::Point(0.04f, 0.04f * (static_cast(m_size.x) / static_cast(m_size.y))); // Use the setters to set defaults, because they automatically disable what is not supported SetShadowMapping(m_shadowMapping); @@ -357,12 +393,9 @@ void CEngine::Destroy() void CEngine::ResetAfterVideoConfigChanged() { m_size = m_app->GetVideoConfig().size; - m_mouseSize = Math::Point(0.04f, 0.04f * (static_cast(m_size.x) / static_cast(m_size.y))); - - CRobotMain::GetInstancePointer()->ResetAfterVideoConfigChanged(); //TODO: Remove cross-reference to CRobotMain // Update the camera projection matrix for new aspect ratio - SetFocus(m_focus); + ApplyChange(); // This needs to be recreated on resolution change m_device->DeleteFramebuffer("multisample"); @@ -373,13 +406,26 @@ void CEngine::ReloadAllTextures() FlushTextureCache(); m_text->FlushCache(); - CRobotMain::GetInstancePointer()->ReloadAllTextures(); //TODO: Remove cross-reference to CRobotMain + m_app->GetEventQueue()->AddEvent(Event(EVENT_RELOAD_TEXTURES)); UpdateGroundSpotTextures(); - LoadAllTextures(); + // LoadAllTextures() is called from CRobotMain on EVENT_RELOAD_TEXTURES + // This is required because all dynamic textures need to be loaded first + + // recapture 3D scene + if (m_worldCaptured) + { + m_captureWorld = true; + m_worldCaptured = false; + } } bool CEngine::ProcessEvent(const Event &event) { + if (event.type == EVENT_RESOLUTION_CHANGED) + { + ResetAfterVideoConfigChanged(); + } + if (event.type == EVENT_KEY_DOWN) { auto data = event.GetData(); @@ -389,18 +435,6 @@ bool CEngine::ProcessEvent(const Event &event) m_showStats = !m_showStats; return false; } - - if (data->key == KEY(F11)) - { - m_debugLights = !m_debugLights; - return false; - } - - if (data->key == KEY(F10)) - { - m_debugDumpLights = true; - return false; - } } // By default, pass on all events @@ -1750,17 +1784,18 @@ bool CEngine::DetectBBox(int objRank, Math::Point mouse) mouse.y <= max.y ); } -int CEngine::DetectObject(Math::Point mouse) +int CEngine::DetectObject(Math::Point mouse, Math::Vector& targetPos, bool terrain) { float min = 1000000.0f; int nearest = -1; + Math::Vector pos; for (int objRank = 0; objRank < static_cast( m_objects.size() ); objRank++) { if (! m_objects[objRank].used) continue; - if (m_objects[objRank].type == ENG_OBJTYPE_TERRAIN) + if (m_objects[objRank].type == ENG_OBJTYPE_TERRAIN && !terrain) continue; if (! DetectBBox(objRank, mouse)) @@ -1789,10 +1824,11 @@ int CEngine::DetectObject(Math::Point mouse) for (int i = 0; i < static_cast( p3.vertices.size() ); i += 3) { float dist = 0.0f; - if (DetectTriangle(mouse, &p3.vertices[i], objRank, dist) && dist < min) + if (DetectTriangle(mouse, &p3.vertices[i], objRank, dist, pos) && dist < min) { min = dist; nearest = objRank; + targetPos = pos; } } } @@ -1801,10 +1837,11 @@ int CEngine::DetectObject(Math::Point mouse) for (int i = 0; i < static_cast( p3.vertices.size() ) - 2; i += 1) { float dist = 0.0f; - if (DetectTriangle(mouse, &p3.vertices[i], objRank, dist) && dist < min) + if (DetectTriangle(mouse, &p3.vertices[i], objRank, dist, pos) && dist < min) { min = dist; nearest = objRank; + targetPos = pos; } } } @@ -1815,7 +1852,7 @@ int CEngine::DetectObject(Math::Point mouse) return nearest; } -bool CEngine::DetectTriangle(Math::Point mouse, VertexTex2* triangle, int objRank, float& dist) +bool CEngine::DetectTriangle(Math::Point mouse, VertexTex2* triangle, int objRank, float& dist, Math::Vector& pos) { assert(objRank >= 0 && objRank < static_cast(m_objects.size())); @@ -1862,6 +1899,16 @@ bool CEngine::DetectTriangle(Math::Point mouse, VertexTex2* triangle, int objRan if (! Math::IsInsideTriangle(a, b, c, mouse)) return false; + Math::Vector a2 = Math::Transform(m_objects[objRank].transform, triangle[0].coord); + Math::Vector b2 = Math::Transform(m_objects[objRank].transform, triangle[1].coord); + Math::Vector c2 = Math::Transform(m_objects[objRank].transform, triangle[2].coord); + Math::Vector e = Math::Transform(m_matView.Inverse(), Math::Vector(0.0f, 0.0f, -1.0f)); + Math::Vector f = Math::Transform(m_matView.Inverse(), Math::Vector( + (mouse.x*2.0f-1.0f)*m_matProj.Inverse().Get(1,1), + (mouse.y*2.0f-1.0f)*m_matProj.Inverse().Get(2,2), + 0.0f)); + Math::Intersect(a2, b2, c2, e, f, pos); + dist = (p2D[0].z + p2D[1].z + p2D[2].z) / 3.0f; return true; } @@ -2178,8 +2225,7 @@ void CEngine::SetMaterial(const Material& mat) m_device->SetMaterial(mat); } -void CEngine::SetViewParams(const Math::Vector& eyePt, const Math::Vector& lookatPt, - const Math::Vector& upVec, float eyeDistance) +void CEngine::SetViewParams(const Math::Vector &eyePt, const Math::Vector &lookatPt, const Math::Vector &upVec) { m_eyePt = eyePt; m_lookatPt = lookatPt; @@ -2729,7 +2775,10 @@ float CEngine::GetDeepView(int rank) void CEngine::SetFogStart(float start, int rank) { - m_fogStart[rank] = start; + if (start < 0.0f) + m_fogStart[rank] = 0.0f; + else + m_fogStart[rank] = start; } float CEngine::GetFogStart(int rank) @@ -3021,6 +3070,16 @@ EngineMouseType CEngine::GetMouseType() return m_mouseType; } +void CEngine::SetPauseBlurEnabled(bool enable) +{ + m_pauseBlurEnabled = enable; +} + +bool CEngine::GetPauseBlurEnabled() +{ + return m_pauseBlurEnabled; +} + const Math::Matrix& CEngine::GetMatView() { return m_matView; @@ -3059,6 +3118,13 @@ void CEngine::UpdateMatProj() void CEngine::ApplyChange() { SetFocus(m_focus); + + // recapture 3D scene + if (m_worldCaptured) + { + m_captureWorld = true; + m_worldCaptured = false; + } } void CEngine::ClearDisplayCrashSpheres() @@ -3128,15 +3194,30 @@ void CEngine::Render() m_device->BeginScene(); - UseMSAA(true); + // use currently captured scene for world + if (m_worldCaptured && !m_captureWorld) + { + DrawCaptured3DScene(); + } + else + { + UseMSAA(true); - DrawBackground(); // draws the background + DrawBackground(); // draws the background + if (m_drawWorld) + Draw3DScene(); - if (m_drawWorld) - Draw3DScene(); + UseMSAA(false); - UseMSAA(false); + // marked to capture currently rendered world + if (m_captureWorld) + { + Capture3DScene(); + m_device->Clear(); + DrawCaptured3DScene(); + } + } m_app->StartPerformanceCounter(PCNT_RENDER_INTERFACE); DrawInterface(); @@ -3148,6 +3229,15 @@ void CEngine::Render() void CEngine::Draw3DScene() { + if (!m_worldCaptured) + { + if (m_capturedWorldTexture.Valid()) + { + m_device->DestroyTexture(m_capturedWorldTexture); + m_capturedWorldTexture = Texture(); + } + } + m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false); UpdateGroundSpotTextures(); @@ -3230,7 +3320,6 @@ void CEngine::Draw3DScene() if (!m_shadowMapping) DrawShadowSpots(); - m_app->StopPerformanceCounter(PCNT_RENDER_TERRAIN); // Draw other objects @@ -3374,6 +3463,21 @@ void CEngine::Draw3DScene() if (m_debugCrashSpheres) DrawCrashSpheres(); + if (m_debugGoto) + { + Math::Matrix worldMatrix; + worldMatrix.LoadIdentity(); + m_device->SetTransform(TRANSFORM_WORLD, worldMatrix); + + SetState(ENG_RSTATE_OPAQUE_COLOR); + + for (const auto& line : m_displayGoto) + { + m_device->DrawPrimitive(PRIMITIVE_LINE_STRIP, line.data(), line.size()); + } + } + m_displayGoto.clear(); + m_app->StartPerformanceCounter(PCNT_RENDER_PARTICLE); m_particle->DrawParticle(SH_WORLD); // draws the particles of the 3D world m_app->StopPerformanceCounter(PCNT_RENDER_PARTICLE); @@ -3387,6 +3491,143 @@ void CEngine::Draw3DScene() if (! m_overFront) DrawOverColor(); // draws the foreground color } +void CEngine::Capture3DScene() +{ + // destroy existing texture + if (m_capturedWorldTexture.Valid()) + { + m_device->DestroyTexture(m_capturedWorldTexture); + m_capturedWorldTexture = Texture(); + } + + // obtain pixels from screen + int width = m_size.x; + int height = m_size.y; + + auto pixels = m_device->GetFrameBufferPixels(); + unsigned char* data = reinterpret_cast(pixels->GetPixelsData()); + + // calculate 2nd mipmap + int newWidth = width / 4; + int newHeight = height / 4; + std::unique_ptr mipmap = MakeUniqueArray(4 * newWidth * newHeight); + + for (int x = 0; x < newWidth; x++) + { + for (int y = 0; y < newHeight; y++) + { + float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + int index = 4 * ((4 * x + i) + width * (4 * y + j)); + + for (int k = 0; k < 4; k++) + color[k] += data[index + k]; + } + } + + int index = 4 * (x + newWidth * y); + + for (int k = 0; k < 4; k++) + { + mipmap[index + k] = static_cast(color[k] * (1.0f / 16.0f)); + } + } + } + + // calculate Gaussian blur + std::unique_ptr blured = MakeUniqueArray(4 * newWidth * newHeight); + + float matrix[7][7] = + { + { 0.00000067f, 0.00002292f, 0.00019117f, 0.00038771f, 0.00019117f, 0.00002292f, 0.00000067f }, + { 0.00002292f, 0.00078634f, 0.00655965f, 0.01330373f, 0.00655965f, 0.00078633f, 0.00002292f }, + { 0.00019117f, 0.00655965f, 0.05472157f, 0.11098164f, 0.05472157f, 0.00655965f, 0.00019117f }, + { 0.00038771f, 0.01330373f, 0.11098164f, 0.22508352f, 0.11098164f, 0.01330373f, 0.00038771f }, + { 0.00019117f, 0.00655965f, 0.05472157f, 0.11098164f, 0.05472157f, 0.00655965f, 0.00019117f }, + { 0.00002292f, 0.00078633f, 0.00655965f, 0.01330373f, 0.00655965f, 0.00078633f, 0.00002292f }, + { 0.00000067f, 0.00002292f, 0.00019117f, 0.00038771f, 0.00019117f, 0.00002292f, 0.00000067f } + }; + + for (int x = 0; x < newWidth; x++) + { + for (int y = 0; y < newHeight; y++) + { + float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + for (int i = -3; i <= 3; i++) + { + for (int j = -3; j <= 3; j++) + { + int xp = Math::Clamp(x + i, 0, newWidth - 1); + int yp = Math::Clamp(y + j, 0, newHeight - 1); + + float weight = matrix[i + 3][j + 3]; + + int index = 4 * (newWidth * yp + xp); + + for (int k = 0; k < 4; k++) + color[k] += weight * mipmap[index + k]; + } + } + + int index = 4 * (newWidth * y + x); + + for (int k = 0; k < 4; k++) + { + float value = Math::Clamp(color[k], 0.0f, 255.0f); + blured[index + k] = static_cast(value); + } + } + } + + // create SDL surface and final texture + ImageData image; + image.surface = SDL_CreateRGBSurfaceFrom(blured.get(), newWidth, newHeight, 32, 0, 0, 0, 0, 0xFF000000); + + TextureCreateParams params; + params.filter = TEX_FILTER_BILINEAR; + params.format = TEX_IMG_RGBA; + params.mipmap = false; + + m_capturedWorldTexture = m_device->CreateTexture(&image, params); + + SDL_FreeSurface(image.surface); + + m_captureWorld = false; + m_worldCaptured = true; +} + +void CEngine::DrawCaptured3DScene() +{ + Math::Matrix identity; + + m_device->SetTransform(TRANSFORM_PROJECTION, identity); + m_device->SetTransform(TRANSFORM_VIEW, identity); + m_device->SetTransform(TRANSFORM_WORLD, identity); + + m_device->SetRenderState(RENDER_STATE_BLENDING, false); + m_device->SetRenderState(RENDER_STATE_CULLING, false); + + Vertex vertices[4]; + + vertices[0] = Vertex(Math::Vector(-1.0f, -1.0f, 0.0f), Math::Vector(0.0f, 1.0f, 0.0f), Math::Point(0.0f, 0.0f)); + vertices[1] = Vertex(Math::Vector(1.0f, -1.0f, 0.0f), Math::Vector(0.0f, 1.0f, 0.0f), Math::Point(1.0f, 0.0f)); + vertices[2] = Vertex(Math::Vector(-1.0f, 1.0f, 0.0f), Math::Vector(0.0f, 1.0f, 0.0f), Math::Point(0.0f, 1.0f)); + vertices[3] = Vertex(Math::Vector(1.0f, 1.0f, 0.0f), Math::Vector(0.0f, 1.0f, 0.0f), Math::Point(1.0f, 1.0f)); + + m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false); + + m_device->SetTexture(TEXTURE_PRIMARY, m_capturedWorldTexture); + m_device->SetTextureEnabled(TEXTURE_PRIMARY, true); + m_device->SetTextureEnabled(TEXTURE_SECONDARY, false); + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertices, 4); +} + void CEngine::DrawCrashSpheres() { Math::Matrix worldMatrix; @@ -3770,9 +4011,7 @@ void CEngine::DrawInterface() m_device->SetRenderState(RENDER_STATE_LIGHTING, false); m_device->SetRenderState(RENDER_STATE_FOG, false); - m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface); - m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface); - m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface); + SetInterfaceCoordinates(); // Force new state to disable lighting m_interfaceMode = true; @@ -3871,9 +4110,7 @@ void CEngine::DrawInterface() m_device->SetRenderMode(RENDER_MODE_INTERFACE); - m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface); - m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface); - m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface); + SetInterfaceCoordinates(); } // Draw foreground color @@ -3967,7 +4204,7 @@ void CEngine::UpdateGroundSpotTextures() set = true; } - if (clear || set) + if (clear || set || m_debugResources || m_displayGotoImage != nullptr) { CImage shadowImg(Math::IntPoint(256, 256)); shadowImg.Fill(Gfx::IntColor(255, 255, 255, 255)); @@ -4127,6 +4364,43 @@ void CEngine::UpdateGroundSpotTextures() } } + if (m_debugResources) + { + for (float x = min.x; x < max.x; x += 1.0f) + { + for (float y = min.y; y < max.y; y += 1.0f) + { + Math::Vector pos( + x / 4.0f / 254.0f * 3200.0f - 1600.0f, + 0.0f, + y / 4.0f / 254.0f * 3200.0f - 1600.0f + ); + TerrainRes res = m_terrain->GetResource(pos); + Math::IntPoint p(x-min.x, y-min.y); + if (res == TR_NULL) + { + shadowImg.SetPixel(p, Gfx::Color(0.5f, 0.5f, 0.5f)); + continue; + } + shadowImg.SetPixelInt(p, ResourceToColor(res)); + } + } + } + + if (m_displayGotoImage != nullptr) + { + Math::IntPoint size = m_displayGotoImage->GetSize(); + for (float x = min.x; x < max.x; x += 1.0f) + { + for (float y = min.y; y < max.y; y += 1.0f) + { + int px = x / 4.0f / 254.0f * size.x; + int py = y / 4.0f / 254.0f * size.y; + shadowImg.SetPixelInt(Math::IntPoint(x-min.x, y-min.y), m_displayGotoImage->GetPixelInt(Math::IntPoint(px, py))); + } + } + } + std::stringstream str; str << "textures/shadow" << std::setfill('0') << std::setw(2) << s << ".png"; std::string texName = str.str(); @@ -4592,8 +4866,8 @@ void CEngine::DrawOverColor() void CEngine::DrawHighlight() { Math::Point min, max; - min.x = 1000000.0f; - min.y = 1000000.0f; + min.x = 1000000.0f; + min.y = 1000000.0f; max.x = -1000000.0f; max.y = -1000000.0f; @@ -4610,10 +4884,10 @@ void CEngine::DrawHighlight() } } - if ( min.x == 1000000.0f || - min.y == 1000000.0f || - max.x == -1000000.0f || - max.y == -1000000.0f ) + if (min.x == 1000000.0f || + min.y == 1000000.0f || + max.x == -1000000.0f || + max.y == -1000000.0f) { m_highlight = false; // not highlighted } @@ -4624,7 +4898,7 @@ void CEngine::DrawHighlight() m_highlight = true; } - if (! m_highlight) + if (!m_highlight) return; Math::Point p1 = m_highlightP1; @@ -4640,8 +4914,8 @@ void CEngine::DrawHighlight() SetState(ENG_RSTATE_OPAQUE_COLOR); - float d = 0.5f+sinf(m_highlightTime*6.0f)*0.5f; - d *= (p2.x-p1.x)*0.1f; + float d = 0.5f + sinf(m_highlightTime * 6.0f) * 0.5f; + d *= (p2.x - p1.x) * 0.1f; p1.x += d; p1.y += d; p2.x -= d; @@ -4650,11 +4924,11 @@ void CEngine::DrawHighlight() Color color(1.0f, 1.0f, 0.0f); // yellow VertexCol line[3] = - { - VertexCol(Math::Vector(), color), - VertexCol(Math::Vector(), color), - VertexCol(Math::Vector(), color) - }; + { + VertexCol(Math::Vector(), color), + VertexCol(Math::Vector(), color), + VertexCol(Math::Vector(), color) + }; float dx = (p2.x - p1.x) / 5.0f; float dy = (p2.y - p1.y) / 5.0f; @@ -4686,6 +4960,8 @@ void CEngine::DrawMouse() if (mode != MOUSE_ENGINE && mode != MOUSE_BOTH) return; + SetWindowCoordinates(); + Material material; material.diffuse = Color(1.0f, 1.0f, 1.0f); material.ambient = Color(0.5f, 0.5f, 0.5f); @@ -4693,33 +4969,34 @@ void CEngine::DrawMouse() m_device->SetMaterial(material); m_device->SetTexture(0, m_miceTexture); - int index = static_cast(m_mouseType); + Math::Point mousePos = CInput::GetInstancePointer()->GetMousePos(); + Math::IntPoint pos(mousePos.x * m_size.x, m_size.y - mousePos.y * m_size.y); + pos.x -= MOUSE_TYPES.at(m_mouseType).hotPoint.x; + pos.y -= MOUSE_TYPES.at(m_mouseType).hotPoint.y; - Math::Point pos = CInput::GetInstancePointer()->GetMousePos(); - pos.x = pos.x - (m_mice[index].hotPoint.x * m_mouseSize.x) / 32.0f; - pos.y = pos.y - ((32.0f - m_mice[index].hotPoint.y) * m_mouseSize.y) / 32.0f; - - Math::Point shadowPos; - shadowPos.x = pos.x + (4.0f/800.0f); - shadowPos.y = pos.y - (3.0f/600.0f); + Math::IntPoint shadowPos; + shadowPos.x = pos.x + 4; + shadowPos.y = pos.y - 3; SetState(ENG_RSTATE_TCOLOR_WHITE); - DrawMouseSprite(shadowPos, m_mouseSize, m_mice[index].iconShadow); + DrawMouseSprite(shadowPos, MOUSE_SIZE, MOUSE_TYPES.at(m_mouseType).iconShadow); - SetState(m_mice[index].mode1); - DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon1); + SetState(MOUSE_TYPES.at(m_mouseType).mode1); + DrawMouseSprite(pos, MOUSE_SIZE, MOUSE_TYPES.at(m_mouseType).icon1); - SetState(m_mice[index].mode2); - DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon2); + SetState(MOUSE_TYPES.at(m_mouseType).mode2); + DrawMouseSprite(pos, MOUSE_SIZE, MOUSE_TYPES.at(m_mouseType).icon2); + + SetInterfaceCoordinates(); } -void CEngine::DrawMouseSprite(Math::Point pos, Math::Point size, int icon) +void CEngine::DrawMouseSprite(Math::IntPoint pos, Math::IntPoint size, int icon) { if (icon == -1) return; - Math::Point p1 = pos; - Math::Point p2 = p1 + size; + Math::IntPoint p1 = pos; + Math::IntPoint p2 = p1 + size; float u1 = (32.0f / 256.0f) * (icon % 8); float v1 = (32.0f / 256.0f) * (icon / 8); @@ -4736,10 +5013,10 @@ void CEngine::DrawMouseSprite(Math::Point pos, Math::Point size, int icon) Vertex vertex[4] = { - Vertex(Math::Vector(p1.x, p1.y, 0.0f), normal, Math::Point(u1, v2)), - Vertex(Math::Vector(p1.x, p2.y, 0.0f), normal, Math::Point(u1, v1)), - Vertex(Math::Vector(p2.x, p1.y, 0.0f), normal, Math::Point(u2, v2)), - Vertex(Math::Vector(p2.x, p2.y, 0.0f), normal, Math::Point(u2, v1)) + Vertex(Math::Vector(p1.x, p2.y, 0.0f), normal, Math::Point(u1, v2)), + Vertex(Math::Vector(p1.x, p1.y, 0.0f), normal, Math::Point(u1, v1)), + Vertex(Math::Vector(p2.x, p2.y, 0.0f), normal, Math::Point(u2, v2)), + Vertex(Math::Vector(p2.x, p1.y, 0.0f), normal, Math::Point(u2, v1)) }; m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); @@ -5075,4 +5352,94 @@ void CEngine::SetStaticMeshTransparency(int meshHandle, float value) SetObjectTransparency(objRank, value); } +void CEngine::SetDebugLights(bool debugLights) +{ + m_debugLights = debugLights; +} + +bool CEngine::GetDebugLights() +{ + return m_debugLights; +} + +void CEngine::DebugDumpLights() +{ + m_debugDumpLights = true; +} + +void CEngine::SetDebugResources(bool debugResources) +{ + m_debugResources = debugResources; + m_firstGroundSpot = true; // Force a refresh of ground spot textures + UpdateGroundSpotTextures(); +} + +bool CEngine::GetDebugResources() +{ + return m_debugResources; +} + +void CEngine::SetDebugGoto(bool debugGoto) +{ + m_debugGoto = debugGoto; + if (!m_debugGoto) + { + m_displayGotoImage.reset(); + } +} + +bool CEngine::GetDebugGoto() +{ + return m_debugGoto; +} + +void CEngine::AddDebugGotoLine(std::vector line) +{ + m_displayGoto.push_back(line); +} + +void CEngine::SetDebugGotoBitmap(std::unique_ptr debugImage) +{ + m_displayGotoImage = std::move(debugImage); + m_firstGroundSpot = true; // Force ground spot texture reload + UpdateGroundSpotTextures(); +} + +void CEngine::SetInterfaceCoordinates() +{ + m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface); + m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface); + m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface); +} + +void CEngine::EnablePauseBlur() +{ + if (!m_pauseBlurEnabled) return; + + m_captureWorld = true; + m_worldCaptured = false; +} + +void CEngine::DisablePauseBlur() +{ + m_captureWorld = false; + m_worldCaptured = false; +} + +void CEngine::SetWindowCoordinates() +{ + Math::Matrix matWorldWindow; + matWorldWindow.LoadIdentity(); + + Math::Matrix matViewWindow; + matViewWindow.LoadIdentity(); + + Math::Matrix matProjWindow; + Math::LoadOrthoProjectionMatrix(matProjWindow, 0.0f, m_size.x, m_size.y, 0.0f, -1.0f, 1.0f); + + m_device->SetTransform(TRANSFORM_VIEW, matViewWindow); + m_device->SetTransform(TRANSFORM_PROJECTION, matProjWindow); + m_device->SetTransform(TRANSFORM_WORLD, matWorldWindow); +} + } // namespace Gfx diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 5fc65a2c..e1dadf4d 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -482,40 +482,6 @@ enum EngineMouseType ENG_MOUSE_COUNT }; -/** - * \struct EngineMouse - * \brief Information about mouse cursor - */ -struct EngineMouse -{ - //! Index of texture element for 1st image - int icon1; - //! Index of texture element for 2nd image - int icon2; - //! Shadow texture part - int iconShadow; - //! Mode to render 1st image in - EngineRenderState mode1; - //! Mode to render 2nd image in - EngineRenderState mode2; - //! Hot point - Math::Point hotPoint; - - EngineMouse(int icon1 = -1, - int icon2 = -1, - int iconShadow = -1, - EngineRenderState mode1 = ENG_RSTATE_NORMAL, - EngineRenderState mode2 = ENG_RSTATE_NORMAL, - Math::Point hotPoint = Math::Point()) - : icon1(icon1) - , icon2(icon2) - , iconShadow(iconShadow) - , mode1(mode1) - , mode2(mode2) - , hotPoint(hotPoint) - {} -}; - /** * \class CEngine @@ -655,9 +621,6 @@ public: //! Frees all resources before exit void Destroy(); - //! Resets some states and flushes textures after device was changed (e.g. resoulution changed) - void ResetAfterVideoConfigChanged(); - //! Called once per frame, the call is the entry point for rendering void Render(); @@ -844,7 +807,7 @@ public: //! Detects the target object that is selected with the mouse /** Returns the rank of the object or -1. */ - int DetectObject(Math::Point mouse); + int DetectObject(Math::Point mouse, Math::Vector& targetPos, bool terrain = false); //! Creates a shadow for the given object void CreateShadowSpot(int objRank); @@ -904,8 +867,7 @@ public: void SetMaterial(const Material& mat); //! Specifies the location and direction of view - void SetViewParams(const Math::Vector& eyePt, const Math::Vector& lookatPt, - const Math::Vector& upVec, float eyeDistance); + void SetViewParams(const Math::Vector &eyePt, const Math::Vector &lookatPt, const Math::Vector &upVec); //! Loads texture, creating it if not already present Texture LoadTexture(const std::string& name); @@ -1165,6 +1127,12 @@ public: EngineMouseType GetMouseType(); //@} + //@{ + //! Management of pause blur + void SetPauseBlurEnabled(bool enable); + bool GetPauseBlurEnabled(); + //@} + //! Returns the view matrix const Math::Matrix& GetMatView(); //! Returns the camera center point @@ -1187,9 +1155,35 @@ public: void ClearDisplayCrashSpheres(); void AddDisplayCrashSpheres(const std::vector& crashSpheres); + void SetDebugLights(bool debugLights); + bool GetDebugLights(); + void DebugDumpLights(); + + void SetDebugResources(bool debugResources); + bool GetDebugResources(); + + void SetDebugGoto(bool debugGoto); + bool GetDebugGoto(); + void AddDebugGotoLine(std::vector line); + void SetDebugGotoBitmap(std::unique_ptr debugImage); + + void SetWindowCoordinates(); + void SetInterfaceCoordinates(); + + void EnablePauseBlur(); + void DisablePauseBlur(); + protected: + //! Resets some states and flushes textures after device was changed (e.g. resoulution changed) + /** Instead of calling this directly, send EVENT_RESOLUTION_CHANGED event **/ + void ResetAfterVideoConfigChanged(); + //! Prepares the interface for 3D scene void Draw3DScene(); + //! Capture the 3D scene for pause blur + void Capture3DScene(); + //! Draw the 3D scene capured for pause blur + void DrawCaptured3DScene(); //! Renders shadow map void RenderShadowMap(); //! Enables or disables shadow mapping @@ -1223,7 +1217,7 @@ protected: //! Draws the mouse cursor void DrawMouse(); //! Draw part of mouse cursor sprite - void DrawMouseSprite(Math::Point pos, Math::Point size, int icon); + void DrawMouseSprite(Math::IntPoint pos, Math::IntPoint size, int icon); //! Draw statistic texts void DrawStats(); //! Draw mission timer @@ -1249,7 +1243,7 @@ protected: bool GetBBox2D(int objRank, Math::Point& min, Math::Point& max); //! Detects whether the mouse is in a triangle. - bool DetectTriangle(Math::Point mouse, VertexTex2* triangle, int objRank, float& dist); + bool DetectTriangle(Math::Point mouse, VertexTex2* triangle, int objRank, float& dist, Math::Vector& pos); //! Transforms a 3D point (x, y, z) in 2D space (x, y, -) of the window /** The coordinated p2D.z gives the distance. */ @@ -1281,6 +1275,7 @@ protected: static void WriteScreenShotThread(std::unique_ptr data); //! Reloads all textures + /** This additionally sends EVENT_RELOAD_TEXTURES to reload all textures not maintained by CEngine **/ void ReloadAllTextures(); protected: @@ -1391,6 +1386,7 @@ protected: float m_terrainVision; bool m_backForce; float m_tracePrecision; + bool m_pauseBlurEnabled; bool m_dirty; bool m_fog; @@ -1448,12 +1444,8 @@ protected: * so are disabled for subsequent load calls. */ std::set m_texBlacklist; - //! Mouse cursor definitions - EngineMouse m_mice[ENG_MOUSE_COUNT]; //! Texture with mouse cursors Texture m_miceTexture; - //! Size of mouse cursor - Math::Point m_mouseSize; //! Type of mouse cursor EngineMouseType m_mouseType; @@ -1472,15 +1464,26 @@ protected: bool m_debugLights; bool m_debugDumpLights; bool m_debugCrashSpheres = false; + bool m_debugResources = false; + bool m_debugGoto = false; std::string m_timerText; std::unordered_map m_staticMeshBaseObjects; std::vector m_displayCrashSpheres; + std::vector> m_displayGoto; + std::unique_ptr m_displayGotoImage; //! Pause the animation updates bool m_pause = false; + + //! true means that current 3D scene was captured and is not to be rendered again + bool m_worldCaptured = false; + //! true means that currently rendered world is to be captured + bool m_captureWorld = false; + //! Texture with captured 3D world + Texture m_capturedWorldTexture; }; diff --git a/src/graphics/engine/lightning.cpp b/src/graphics/engine/lightning.cpp index 88b9d33b..18192fe5 100644 --- a/src/graphics/engine/lightning.cpp +++ b/src/graphics/engine/lightning.cpp @@ -82,16 +82,24 @@ bool CLightning::EventProcess(const Event &event) bool CLightning::EventFrame(const Event &event) { + if (m_terrain == nullptr) + m_terrain = CRobotMain::GetInstancePointer()->GetTerrain(); + + if (m_camera == nullptr) + m_camera = CRobotMain::GetInstancePointer()->GetCamera(); + + if (m_sound == nullptr) + m_sound = CApplication::GetInstancePointer()->GetSound(); + if (m_engine->GetPause()) return true; if (CRobotMain::GetInstancePointer()->GetMovieLock()) return true; m_progress += event.rTime*m_speed; - if (m_phase == LightningPhase::Wait) + if (m_phase == LightningPhase::Wait && m_lightningExists) { if (m_progress >= 1.0f) { - m_pos.x = (Math::Rand()-0.5f)*(3200.0f-200.0f); m_pos.z = (Math::Rand()-0.5f)*(3200.0f-200.0f); m_pos.y = 0.0f; @@ -127,21 +135,7 @@ bool CLightning::EventFrame(const Event &event) } } - Math::Vector eye = m_engine->GetEyePt(); - float dist = Math::Distance(m_pos, eye); - float deep = m_engine->GetDeepView(); - - if (dist < deep) - { - Math::Vector pos = eye+((m_pos-eye)*0.2f); // like so close! - m_sound->Play(SOUND_BLITZ, pos); - - m_camera->StartOver(CAM_OVER_EFFECT_LIGHTNING, m_pos, 1.0f); - - m_phase = LightningPhase::Flash; - m_progress = 0.0f; - m_speed = 1.0f; - } + StrikeAtPos(m_pos); } } @@ -193,15 +187,6 @@ bool CLightning::Create(float sleep, float delay, float magnetic) m_progress = 0.0f; m_speed = 1.0f / m_sleep; - if (m_terrain == nullptr) - m_terrain = CRobotMain::GetInstancePointer()->GetTerrain(); - - if (m_camera == nullptr) - m_camera = CRobotMain::GetInstancePointer()->GetCamera(); - - if (m_sound == nullptr) - m_sound = CApplication::GetInstancePointer()->GetSound(); - return false; } @@ -233,7 +218,6 @@ bool CLightning::SetStatus(float sleep, float delay, float magnetic, float progr void CLightning::Draw() { - if (!m_lightningExists) return; if (m_phase != LightningPhase::Flash) return; CDevice* device = m_engine->GetDevice(); @@ -368,4 +352,25 @@ CObject* CLightning::SearchObject(Math::Vector pos) } +void CLightning::StrikeAtPos(Math::Vector pos) +{ + m_pos = pos; + + Math::Vector eye = m_engine->GetEyePt(); + float dist = Math::Distance(m_pos, eye); + float deep = m_engine->GetDeepView(); + + if (dist < deep) + { + Math::Vector pos = eye+((m_pos-eye)*0.2f); // like so close! + m_sound->Play(SOUND_BLITZ, pos); + + m_camera->StartOver(CAM_OVER_EFFECT_LIGHTNING, m_pos, 1.0f); + + m_phase = LightningPhase::Flash; + m_progress = 0.0f; + m_speed = 1.0f; + } +} + } // namespace Gfx diff --git a/src/graphics/engine/lightning.h b/src/graphics/engine/lightning.h index 57cc6f58..505a7cf6 100644 --- a/src/graphics/engine/lightning.h +++ b/src/graphics/engine/lightning.h @@ -75,6 +75,9 @@ public: //! Draws lightning void Draw(); + //! Shoots lightning strike at given position + void StrikeAtPos(Math::Vector pos); + protected: //! Updates lightning bool EventFrame(const Event &event); diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp index 80e593b3..5f8b1601 100644 --- a/src/graphics/engine/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -581,7 +581,7 @@ int CParticle::CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim if (!m_track[i].used) // free? { int rank = channel; - if (!CheckChannel(rank)) return -1; + GetRankFromChannel(rank); m_particle[rank].trackRank = i; m_track[i].used = true; @@ -636,28 +636,27 @@ void CParticle::CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, -/** Adapts the channel so it can be used as an offset in m_particle */ -bool CParticle::CheckChannel(int &channel) +void CParticle::GetRankFromChannel(int &channel) { int uniqueStamp = (channel>>16)&0xffff; channel &= 0xffff; - if (channel < 0) return false; - if (channel >= MAXPARTICULE*MAXPARTITYPE) return false; + if (channel < 0 || channel >= MAXPARTICULE*MAXPARTITYPE) throw std::runtime_error("Tried to access invalid particle channel (invalid ID)"); + if (!m_particle[channel].used) throw std::runtime_error("Tried to access invalid particle channel (used=false)"); + if (m_particle[channel].uniqueStamp != uniqueStamp) throw std::runtime_error("Tried to access invalid particle channel (uniqueStamp changed)"); +} - if (!m_particle[channel].used) +bool CParticle::ParticleExists(int channel) +{ + try + { + GetRankFromChannel(channel); + return true; + } + catch (const std::runtime_error& e) { - GetLogger()->Error("CheckChannel used=false !\n"); return false; } - - if (m_particle[channel].uniqueStamp != uniqueStamp) - { - GetLogger()->Error("CheckChannel uniqueStamp !\n"); - return false; - } - - return true; } void CParticle::DeleteRank(int rank) @@ -685,7 +684,7 @@ void CParticle::DeleteParticle(ParticleType type) void CParticle::DeleteParticle(int channel) { - if (!CheckChannel(channel)) return; + GetRankFromChannel(channel); if (m_totalInterface[channel/MAXPARTICULE][m_particle[channel].sheet] > 0 ) m_totalInterface[channel/MAXPARTICULE][m_particle[channel].sheet]--; @@ -699,50 +698,50 @@ void CParticle::DeleteParticle(int channel) void CParticle::SetObjectLink(int channel, CObject *object) { - if (!CheckChannel(channel)) return; + GetRankFromChannel(channel); m_particle[channel].objLink = object; } void CParticle::SetObjectFather(int channel, CObject *object) { - if (!CheckChannel(channel)) return; + GetRankFromChannel(channel); m_particle[channel].objFather = object; } void CParticle::SetPosition(int channel, Math::Vector pos) { - if (!CheckChannel(channel)) return; + GetRankFromChannel(channel); m_particle[channel].pos = pos; } void CParticle::SetDimension(int channel, Math::Point dim) { - if (!CheckChannel(channel)) return; + GetRankFromChannel(channel); m_particle[channel].dim = dim; } void CParticle::SetZoom(int channel, float zoom) { - if (!CheckChannel(channel)) return; + GetRankFromChannel(channel); m_particle[channel].zoom = zoom; } void CParticle::SetAngle(int channel, float angle) { - if (!CheckChannel(channel)) return; + GetRankFromChannel(channel); m_particle[channel].angle = angle; } void CParticle::SetIntensity(int channel, float intensity) { - if (!CheckChannel(channel)) return; + GetRankFromChannel(channel); m_particle[channel].intensity = intensity; } void CParticle::SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity) { - if (!CheckChannel(channel)) return; + GetRankFromChannel(channel); m_particle[channel].pos = pos; m_particle[channel].dim = dim; m_particle[channel].zoom = zoom; @@ -752,17 +751,16 @@ void CParticle::SetParam(int channel, Math::Vector pos, Math::Point dim, float z void CParticle::SetPhase(int channel, ParticlePhase phase, float duration) { - if (!CheckChannel(channel)) return; + GetRankFromChannel(channel); m_particle[channel].phase = phase; m_particle[channel].duration = duration; m_particle[channel].phaseTime = m_particle[channel].time; } -bool CParticle::GetPosition(int channel, Math::Vector &pos) +Math::Vector CParticle::GetPosition(int channel) { - if (!CheckChannel(channel)) return false; - pos = m_particle[channel].pos; - return true; + GetRankFromChannel(channel); + return m_particle[channel].pos; } void CParticle::SetFrameUpdate(int sheet, bool update) @@ -3724,12 +3722,4 @@ Color CParticle::GetFogColor(Math::Vector pos) return result; } -bool CParticle::WriteWheelTrace(const char *filename, int width, int height, - Math::Vector dl, Math::Vector ur) -{ - // TODO: stub! - GetLogger()->Trace("CParticle::WriteWheelTrace(): stub!\n"); - return true; -} - } // namespace Gfx diff --git a/src/graphics/engine/particle.h b/src/graphics/engine/particle.h index 676a21b4..ec8d8820 100644 --- a/src/graphics/engine/particle.h +++ b/src/graphics/engine/particle.h @@ -162,9 +162,9 @@ enum ParticlePhase struct Particle { - bool used = false; // TRUE -> particle used + bool used = false; //!< true if this channel is used, false if not bool ray = false; // TRUE -> ray with goal - unsigned short uniqueStamp = 0; // unique mark + unsigned short uniqueStamp = 0; //!< unique marker added to particle channel ID to make sure this is still the same particle short sheet = 0; // sheet (0..n) ParticleType type = {}; // type PARTI* ParticlePhase phase = {}; // phase PARPH* @@ -279,7 +279,7 @@ public: void SetPhase(int channel, ParticlePhase phase, float duration); //! Returns the position of the particle - bool GetPosition(int channel, Math::Vector &pos); + Math::Vector GetPosition(int channel); //! Returns the color if you're in the fog or black if you're not Color GetFogColor(Math::Vector pos); @@ -291,14 +291,18 @@ public: //! Draws all the particles void DrawParticle(int sheet); - //! Writes a file containing all the tire tracks - bool WriteWheelTrace(const char *filename, int width, int height, Math::Vector dl, Math::Vector ur); + //! Checks if given particle channel still exists + bool ParticleExists(int channel); protected: //! Removes a particle of given rank void DeleteRank(int rank); - //! Check a channel number - bool CheckChannel(int &channel); + /** + * \brief Adapts the channel so it can be used as an offset in m_particle + * \param channel Channel number to process, will be modified to be index of particle in m_particle + * \throw std::runtime_error if this particle does not exist any more + **/ + void GetRankFromChannel(int &channel); //! Draws a triangular particle void DrawParticleTriangle(int i); //! Draw a normal particle diff --git a/src/graphics/engine/terrain.cpp b/src/graphics/engine/terrain.cpp index 8475a8a4..7ff24172 100644 --- a/src/graphics/engine/terrain.cpp +++ b/src/graphics/engine/terrain.cpp @@ -192,6 +192,22 @@ void CTerrain::AddMaterial(int id, const std::string& texName, const Math::Point } +// values from original bitmap palette +const std::map RESOURCE_PALETTE = { + {TR_STONE, Gfx::IntColor(255, 0, 0)}, + {TR_URANIUM, Gfx::IntColor(255, 255, 0)}, + {TR_POWER, Gfx::IntColor( 0, 255, 0)}, + {TR_KEY_A, Gfx::IntColor( 0, 204, 0)}, + {TR_KEY_B, Gfx::IntColor( 51, 204, 0)}, + {TR_KEY_C, Gfx::IntColor(102, 204, 0)}, + {TR_KEY_D, Gfx::IntColor(153, 204, 0)} +}; + +Gfx::IntColor ResourceToColor(TerrainRes res) +{ + return RESOURCE_PALETTE.at(res); +} + /** * The image must be 24 bits/pixel and grayscale and dx x dy in size * with dx = dy = (mosaic*brick)+1 */ @@ -224,21 +240,11 @@ bool CTerrain::LoadResources(const std::string& fileName) Gfx::IntColor pixel = img.GetPixelInt(Math::IntPoint(x, size - y - 1)); TerrainRes res = TR_NULL; - // values from original bitmap palette - if (pixel.r == 255 && pixel.g == 0 && pixel.b == 0) - res = TR_STONE; - else if (pixel.r == 255 && pixel.g == 255 && pixel.b == 0) - res = TR_URANIUM; - else if (pixel.r == 0 && pixel.g == 255 && pixel.b == 0) - res = TR_POWER; - else if (pixel.r == 0 && pixel.g == 204 && pixel.b == 0) - res = TR_KEY_A; - else if (pixel.r == 51 && pixel.g == 204 && pixel.b == 0) - res = TR_KEY_B; - else if (pixel.r == 102 && pixel.g == 204 && pixel.b == 0) - res = TR_KEY_C; - else if (pixel.r == 153 && pixel.g == 204 && pixel.b == 0) - res = TR_KEY_D; + for (const auto& it : RESOURCE_PALETTE) + { + if (pixel.r == it.second.r && pixel.g == it.second.g && pixel.b == it.second.b) + res = it.first; + } m_resources[x+size*y] = static_cast(res); } diff --git a/src/graphics/engine/terrain.h b/src/graphics/engine/terrain.h index 7f66f726..9a86b584 100644 --- a/src/graphics/engine/terrain.h +++ b/src/graphics/engine/terrain.h @@ -69,6 +69,8 @@ enum TerrainRes TR_KEY_D = 7 //@} }; +//! Converts TerrainRes to color +Gfx::IntColor ResourceToColor(TerrainRes res); /** * \class CTerrain diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index c1317f1e..aece13e9 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -214,7 +214,9 @@ void CText::DrawText(const std::string &text, std::vector::iterato pos.x -= sw; } - DrawString(text, format, end, size, pos, width, eol, color); + Math::IntPoint intPos = m_engine->InterfaceToWindowCoords(pos); + int intWidth = width * m_engine->GetWindowSize().x; + DrawString(text, format, end, size, intPos, intWidth, eol, color); } void CText::DrawText(const std::string &text, FontType font, @@ -236,7 +238,9 @@ void CText::DrawText(const std::string &text, FontType font, pos.x -= sw; } - DrawString(text, font, size, pos, width, eol, color); + Math::IntPoint intPos = m_engine->InterfaceToWindowCoords(pos); + int intWidth = width * m_engine->GetWindowSize().x; + DrawString(text, font, size, intPos, intWidth, eol, color); } void CText::SizeText(const std::string &text, std::vector::iterator format, @@ -322,6 +326,14 @@ float CText::GetHeight(FontType font, float size) return ifSize.y; } +int CText::GetHeightInt(FontType font, float size) +{ + assert(font != FONT_BUTTON); + + CachedFont* cf = GetOrOpenFont(font, size); + assert(cf != nullptr); + return TTF_FontHeight(cf->font); +} float CText::GetStringWidth(const std::string &text, std::vector::iterator format, @@ -416,6 +428,46 @@ float CText::GetCharWidth(UTF8Char ch, FontType font, float size, float offset) return charSize.x * width; } +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 width = height*(static_cast(windowSize.y)/windowSize.x); + return width; + } + + int width = 1; + if (ch.c1 < 32 && ch.c1 >= 0) + { + if (ch.c1 == '\t') + width = m_tabSize; + + // TODO: tab sizing at intervals? + + ch.c1 = ':'; + } + + CachedFont* cf = GetOrOpenFont(font, size); + assert(cf != nullptr); + + Math::IntPoint charSize; + auto it = cf->cache.find(ch); + if (it != cf->cache.end()) + { + charSize = (*it).second.charSize; + } + else + { + std::string text; + text.append({ch.c1, ch.c2, ch.c3}); + TTF_SizeUTF8(cf->font, text.c_str(), &charSize.x, &charSize.y); + } + + return charSize.x * width; +} + int CText::Justify(const std::string &text, std::vector::iterator format, std::vector::iterator end, @@ -636,11 +688,11 @@ UTF8Char CText::TranslateSpecialChar(int specialChar) void CText::DrawString(const std::string &text, std::vector::iterator format, std::vector::iterator end, - float size, Math::Point pos, float width, int eol, Color color) + float size, Math::IntPoint pos, int width, int eol, Color color) { m_engine->SetState(ENG_RSTATE_TEXT); - float start = pos.x; + int start = pos.x; unsigned int fmtIndex = 0; @@ -654,12 +706,12 @@ void CText::DrawString(const std::string &text, std::vector::itera UTF8Char ch = *it; - float offset = pos.x - start; - float cw = GetCharWidth(ch, font, size, offset); + int offset = pos.x - start; + int cw = GetCharWidthInt(ch, font, size, offset); if (offset + cw > width) // exceeds the maximum width? { ch = TranslateSpecialChar(CHAR_SKIP_RIGHT); - cw = GetCharWidth(ch, font, size, offset); + cw = GetCharWidthInt(ch, font, size, offset); pos.x = start + width - cw; color = Color(1.0f, 0.0f, 0.0f); DrawCharAndAdjustPos(ch, font, size, pos, color); @@ -668,43 +720,42 @@ void CText::DrawString(const std::string &text, std::vector::itera Color c = color; FontHighlight hl = static_cast(format[fmtIndex] & FONT_MASK_HIGHLIGHT); - if (hl != FONT_HIGHLIGHT_NONE) + if (hl == FONT_HIGHLIGHT_TOKEN) { - if (hl == FONT_HIGHLIGHT_TOKEN) - { - c = Color(0.490f, 0.380f, 0.165f, 1.0f); // #7D612A - } - else if (hl == FONT_HIGHLIGHT_TYPE) - { - c = Color(0.31f, 0.443f, 0.196f, 1.0f); // #4F7132 - } - else if (hl == FONT_HIGHLIGHT_CONST) - { - c = Color(0.882f, 0.176f, 0.176f, 1.0f); // #E12D2D - } - else if (hl == FONT_HIGHLIGHT_THIS) - { - c = Color(0.545f, 0.329f, 0.608f, 1.0f); // #8B549B - } - else if (hl == FONT_HIGHLIGHT_COMMENT) - { - c = Color(0.251f, 0.271f, 0.306f, 1.0f); // #40454E - } - else if (hl == FONT_HIGHLIGHT_KEYWORD) - { - c = Color(0.239f, 0.431f, 0.588f, 1.0f); // #3D6E96 - } - else if (hl == FONT_HIGHLIGHT_STRING) - { - c = Color(0.239f, 0.384f, 0.341f, 1.0f); // #3D6257 - } - else - { - Math::Point charSize; - charSize.x = GetCharWidth(ch, font, size, offset); - charSize.y = GetHeight(font, size); - DrawHighlight(hl, pos, charSize); - } + c = Color(0.490f, 0.380f, 0.165f, 1.0f); // #7D612A + } + else if (hl == FONT_HIGHLIGHT_TYPE) + { + c = Color(0.31f, 0.443f, 0.196f, 1.0f); // #4F7132 + } + else if (hl == FONT_HIGHLIGHT_CONST) + { + c = Color(0.882f, 0.176f, 0.176f, 1.0f); // #E12D2D + } + else if (hl == FONT_HIGHLIGHT_THIS) + { + c = Color(0.545f, 0.329f, 0.608f, 1.0f); // #8B549B + } + else if (hl == FONT_HIGHLIGHT_COMMENT) + { + c = Color(0.251f, 0.271f, 0.306f, 1.0f); // #40454E + } + else if (hl == FONT_HIGHLIGHT_KEYWORD) + { + c = Color(0.239f, 0.431f, 0.588f, 1.0f); // #3D6E96 + } + else if (hl == FONT_HIGHLIGHT_STRING) + { + c = Color(0.239f, 0.384f, 0.341f, 1.0f); // #3D6257 + } + + // draw highlight background or link underline + if (font != FONT_BUTTON) + { + Math::IntPoint charSize; + charSize.x = GetCharWidthInt(ch, font, size, offset); + charSize.y = GetHeightInt(font, size); + DrawHighlight(format[fmtIndex], pos, charSize); } DrawCharAndAdjustPos(ch, font, size, pos, c); @@ -788,7 +839,7 @@ void CText::StringToUTFCharList(const std::string &text, std::vector & } void CText::DrawString(const std::string &text, FontType font, - float size, Math::Point pos, float width, int eol, Color color) + float size, Math::IntPoint pos, int width, int eol, Color color) { assert(font != FONT_BUTTON); @@ -802,76 +853,73 @@ void CText::DrawString(const std::string &text, FontType font, } } -void CText::DrawHighlight(FontHighlight hl, Math::Point pos, Math::Point size) +void CText::DrawHighlight(FontMetaChar hl, Math::IntPoint pos, Math::IntPoint size) { // Gradient colors Color grad[4]; // TODO: switch to alpha factors - switch (hl) + if ((hl & FONT_MASK_LINK) != 0) { - case FONT_HIGHLIGHT_LINK: - grad[0] = grad[1] = grad[2] = grad[3] = Color(0.0f, 0.0f, 1.0f, 0.5f); - break; - - case FONT_HIGHLIGHT_KEY: - grad[0] = grad[1] = grad[2] = grad[3] = - Color(192.0f / 256.0f, 192.0f / 256.0f, 192.0f / 256.0f, 0.5f); - break; - - default: - return; + grad[0] = grad[1] = grad[2] = grad[3] = Color(0.0f, 0.0f, 1.0f, 0.5f); + } + else if ((hl & FONT_MASK_HIGHLIGHT) == FONT_HIGHLIGHT_KEY) + { + grad[0] = grad[1] = grad[2] = grad[3] = + Color(192.0f / 256.0f, 192.0f / 256.0f, 192.0f / 256.0f, 0.5f); + } + else + { + return; } Math::IntPoint vsize = m_engine->GetWindowSize(); float h = 0.0f; if (vsize.y <= 768.0f) // 1024x768 or less? - h = 1.01f / vsize.y; // 1 pixel + h = 1.01f; // 1 pixel else // more than 1024x768? - h = 2.0f / vsize.y; // 2 pixels + h = 2.0f; // 2 pixels Math::Point p1, p2; p1.x = pos.x; + p1.y = pos.y - size.y; p2.x = pos.x + size.x; + p2.y = pos.y; - if (hl == FONT_HIGHLIGHT_LINK) + if ((hl & FONT_MASK_LINK) != 0) { - p1.y = pos.y; - p2.y = pos.y + h; // just emphasized - } - else - { - p1.y = pos.y; - p2.y = pos.y + size.y; + p1.y = pos.y - h; // just emphasized } m_device->SetTextureEnabled(0, false); VertexCol quad[] = { - VertexCol(Math::Vector(p1.x, p1.y, 0.0f), grad[3]), - VertexCol(Math::Vector(p1.x, p2.y, 0.0f), grad[0]), - VertexCol(Math::Vector(p2.x, p1.y, 0.0f), grad[2]), - VertexCol(Math::Vector(p2.x, p2.y, 0.0f), grad[1]) + VertexCol(Math::Vector(p1.x, p2.y, 0.0f), grad[3]), + VertexCol(Math::Vector(p1.x, p1.y, 0.0f), grad[0]), + VertexCol(Math::Vector(p2.x, p2.y, 0.0f), grad[2]), + VertexCol(Math::Vector(p2.x, p1.y, 0.0f), grad[1]) }; + m_engine->SetWindowCoordinates(); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4); + m_engine->SetInterfaceCoordinates(); m_engine->AddStatisticTriangle(2); m_device->SetTextureEnabled(0, true); } -void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::Point &pos, Color color) +void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::IntPoint &pos, Color color) { - if(font == FONT_BUTTON) + if (font == FONT_BUTTON) { Math::IntPoint windowSize = m_engine->GetWindowSize(); - float height = GetHeight(FONT_COLOBOT, size); - float width = height*(static_cast(windowSize.y)/windowSize.x); + int height = GetHeightInt(FONT_COLOBOT, size); + int width = height * (static_cast(windowSize.y)/windowSize.x); - Math::Point p1(pos.x, pos.y); - Math::Point p2(pos.x + width, pos.y + height); + Math::IntPoint p1(pos.x, pos.y - height); + Math::IntPoint p2(pos.x + width, pos.y); Math::Vector n(0.0f, 0.0f, -1.0f); // normal @@ -909,13 +957,15 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::P Vertex quad[4] = { - Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(uv1.x, uv2.y)), - Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(uv1.x, uv1.y)), - Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(uv2.x, uv2.y)), - Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(uv2.x, uv1.y)) + Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(uv1.x, uv2.y)), + Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(uv1.x, uv1.y)), + Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(uv2.x, uv2.y)), + Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(uv2.x, uv1.y)) }; + m_engine->SetWindowCoordinates(); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4, color); + m_engine->SetInterfaceCoordinates(); m_engine->AddStatisticTriangle(2); pos.x += width; @@ -939,30 +989,31 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::P CharTexture tex = GetCharTexture(ch, font, size); - Math::Point charInterfaceSize = m_engine->WindowToInterfaceSize(tex.charSize); + Math::Point p1(pos.x, pos.y - tex.charSize.y); + Math::Point p2(pos.x + tex.charSize.x, pos.y); - Math::Point p1(pos.x, pos.y); - Math::Point p2(pos.x + charInterfaceSize.x, pos.y + charInterfaceSize.y); - - Math::Point texCoord1(static_cast(tex.charPos.x) / FONT_TEXTURE_SIZE.x, - static_cast(tex.charPos.y) / FONT_TEXTURE_SIZE.y); - Math::Point texCoord2(static_cast(tex.charPos.x + tex.charSize.x) / FONT_TEXTURE_SIZE.x, - static_cast(tex.charPos.y + tex.charSize.y) / FONT_TEXTURE_SIZE.y); + const float halfPixelMargin = 0.5f; + Math::Point texCoord1(static_cast(tex.charPos.x + halfPixelMargin) / FONT_TEXTURE_SIZE.x, + static_cast(tex.charPos.y + halfPixelMargin) / FONT_TEXTURE_SIZE.y); + Math::Point texCoord2(static_cast(tex.charPos.x + tex.charSize.x - halfPixelMargin) / FONT_TEXTURE_SIZE.x, + static_cast(tex.charPos.y + tex.charSize.y - halfPixelMargin) / FONT_TEXTURE_SIZE.y); Math::Vector n(0.0f, 0.0f, -1.0f); // normal Vertex quad[4] = { - Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(texCoord1.x, texCoord2.y)), - Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(texCoord1.x, texCoord1.y)), - Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(texCoord2.x, texCoord2.y)), - Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(texCoord2.x, texCoord1.y)) + Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(texCoord1.x, texCoord2.y)), + Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(texCoord1.x, texCoord1.y)), + Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(texCoord2.x, texCoord2.y)), + Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(texCoord2.x, texCoord1.y)) }; m_device->SetTexture(0, tex.id); + m_engine->SetWindowCoordinates(); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4, color); + m_engine->SetInterfaceCoordinates(); m_engine->AddStatisticTriangle(2); - pos.x += charInterfaceSize.x * width; + pos.x += tex.charSize.x * width; } } @@ -1061,8 +1112,9 @@ CharTexture CText::CreateCharTexture(UTF8Char ch, CachedFont* font) return texture; } - Math::IntPoint tileSize(Math::NextPowerOfTwo(textSurface->w), - Math::NextPowerOfTwo(textSurface->h)); + const int pixelMargin = 1; + Math::IntPoint tileSize(Math::Max(16, Math::NextPowerOfTwo(textSurface->w)) + pixelMargin, + Math::Max(16, Math::NextPowerOfTwo(textSurface->h)) + pixelMargin); FontTexture* fontTexture = GetOrCreateFontTexture(tileSize); @@ -1075,7 +1127,6 @@ CharTexture CText::CreateCharTexture(UTF8Char ch, CachedFont* font) texture.id = fontTexture->id; texture.charPos = GetNextTilePos(*fontTexture); texture.charSize = Math::IntPoint(textSurface->w, textSurface->h); - texture.tileSize = tileSize; ImageData imageData; imageData.surface = textSurface; diff --git a/src/graphics/engine/text.h b/src/graphics/engine/text.h index 962c755f..f6414c00 100644 --- a/src/graphics/engine/text.h +++ b/src/graphics/engine/text.h @@ -118,7 +118,6 @@ enum FontTitle enum FontHighlight { FONT_HIGHLIGHT_NONE = 0x00 << 6, - FONT_HIGHLIGHT_LINK = 0x01 << 6, //!< link underline FONT_HIGHLIGHT_TABLE = 0x02 << 6, //!< code background in SatCom FONT_HIGHLIGHT_KEY = 0x03 << 6, //!< background for keys in documentation in SatCom FONT_HIGHLIGHT_TOKEN = 0x04 << 6, //!< keywords in CBot scripts @@ -142,8 +141,10 @@ enum FontMask FONT_MASK_TITLE = 0x030, //! Mask for FontHighlight FONT_MASK_HIGHLIGHT = 0x3c0, + //! Mask for links + FONT_MASK_LINK = 0x400, //! Mask for image bit (TODO: not used?) - FONT_MASK_IMAGE = 0x400 + FONT_MASK_IMAGE = 0x800 }; @@ -193,7 +194,6 @@ struct CharTexture unsigned int id = 0; Math::IntPoint charPos; Math::IntPoint charSize; - Math::IntPoint tileSize; }; // Definition is private - in text.cpp @@ -282,6 +282,7 @@ public: float GetDescent(FontType font, float size); //! Returns the height font metric float GetHeight(FontType font, float size); + int GetHeightInt(FontType font, float size); //! Returns width of string (multi-format) TEST_VIRTUAL float GetStringWidth(const std::string& text, @@ -291,6 +292,7 @@ public: TEST_VIRTUAL float GetStringWidth(std::string text, FontType font, float size); //! Returns width of single character TEST_VIRTUAL float GetCharWidth(UTF8Char ch, FontType font, float size, float offset); + int GetCharWidthInt(UTF8Char ch, FontType font, float size, float offset); //! Justifies a line of text (multi-format) int Justify(const std::string &text, std::vector::iterator format, @@ -320,11 +322,11 @@ protected: void DrawString(const std::string &text, std::vector::iterator format, std::vector::iterator end, - float size, Math::Point pos, float width, int eol, Color color); + float size, Math::IntPoint pos, int width, int eol, Color color); void DrawString(const std::string &text, FontType font, - float size, Math::Point pos, float width, int eol, Color color); - void DrawHighlight(FontHighlight hl, Math::Point pos, Math::Point size); - void DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::Point &pos, Color color); + float size, Math::IntPoint pos, int width, int eol, Color color); + void DrawHighlight(FontMetaChar hl, Math::IntPoint pos, Math::IntPoint size); + void DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::IntPoint &pos, Color color); void StringToUTFCharList(const std::string &text, std::vector &chars); void StringToUTFCharList(const std::string &text, std::vector &chars, std::vector::iterator format, std::vector::iterator end); diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gl14device.cpp similarity index 91% rename from src/graphics/opengl/gldevice.cpp rename to src/graphics/opengl/gl14device.cpp index 95a96fea..7b93aaff 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gl14device.cpp @@ -18,7 +18,7 @@ */ -#include "graphics/opengl/gldevice.h" +#include "graphics/opengl/gl14device.h" #include "common/config.h" @@ -43,22 +43,22 @@ namespace Gfx { -CGLDevice::CGLDevice(const DeviceConfig &config) +CGL14Device::CGL14Device(const DeviceConfig &config) : m_config(config) {} -CGLDevice::~CGLDevice() +CGL14Device::~CGL14Device() { } -void CGLDevice::DebugHook() +void CGL14Device::DebugHook() { /* This function is only called here, so it can be used * as a breakpoint when debugging using gDEBugger */ glColor3i(0, 0, 0); } -void CGLDevice::DebugLights() +void CGL14Device::DebugLights() { Gfx::ColorHSV color(0.0, 1.0, 1.0); @@ -158,18 +158,18 @@ void CGLDevice::DebugLights() UpdateModelviewMatrix(); } -std::string CGLDevice::GetName() +std::string CGL14Device::GetName() { return std::string("OpenGL 1.4"); } -bool CGLDevice::Create() +bool CGL14Device::Create() { GetLogger()->Info("Creating CDevice - OpenGL 1.4\n"); if (!InitializeGLEW()) { - m_errorMessage = "An error occured while initializing GLEW."; + m_errorMessage = "An error occurred while initializing GLEW."; return false; } @@ -382,7 +382,7 @@ bool CGLDevice::Create() return true; } -void CGLDevice::Destroy() +void CGL14Device::Destroy() { // delete framebuffers for (auto& framebuffer : m_framebuffers) @@ -404,7 +404,7 @@ void CGLDevice::Destroy() m_textureStageParams.clear(); } -void CGLDevice::ConfigChanged(const DeviceConfig& newConfig) +void CGL14Device::ConfigChanged(const DeviceConfig& newConfig) { m_config = newConfig; @@ -423,7 +423,7 @@ void CGLDevice::ConfigChanged(const DeviceConfig& newConfig) m_framebuffers["default"] = MakeUnique(framebufferParams); } -void CGLDevice::BeginScene() +void CGL14Device::BeginScene() { Clear(); @@ -433,7 +433,7 @@ void CGLDevice::BeginScene() UpdateModelviewMatrix(); } -void CGLDevice::EndScene() +void CGL14Device::EndScene() { #ifdef DEV_BUILD int count = ClearGLErrors(); @@ -443,18 +443,18 @@ void CGLDevice::EndScene() #endif } -void CGLDevice::Clear() +void CGL14Device::Clear() { glDepthMask(GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void CGLDevice::SetRenderMode(RenderMode mode) +void CGL14Device::SetRenderMode(RenderMode mode) { // nothing is done } -void CGLDevice::SetTransform(TransformType type, const Math::Matrix &matrix) +void CGL14Device::SetTransform(TransformType type, const Math::Matrix &matrix) { if (type == TRANSFORM_WORLD) { @@ -492,7 +492,7 @@ void CGLDevice::SetTransform(TransformType type, const Math::Matrix &matrix) } } -void CGLDevice::UpdateModelviewMatrix() +void CGL14Device::UpdateModelviewMatrix() { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -507,7 +507,7 @@ void CGLDevice::UpdateModelviewMatrix() } } -void CGLDevice::SetMaterial(const Material &material) +void CGL14Device::SetMaterial(const Material &material) { m_material = material; @@ -516,12 +516,12 @@ void CGLDevice::SetMaterial(const Material &material) glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m_material.specular.Array()); } -int CGLDevice::GetMaxLightCount() +int CGL14Device::GetMaxLightCount() { return m_lights.size(); } -void CGLDevice::SetLight(int index, const Light &light) +void CGL14Device::SetLight(int index, const Light &light) { assert(index >= 0); assert(index < static_cast( m_lights.size() )); @@ -550,7 +550,7 @@ void CGLDevice::SetLight(int index, const Light &light) UpdateLightPosition(index); } -void CGLDevice::UpdateLightPosition(int index) +void CGL14Device::UpdateLightPosition(int index) { assert(index >= 0); assert(index < static_cast( m_lights.size() )); @@ -594,7 +594,7 @@ void CGLDevice::UpdateLightPosition(int index) glPopMatrix(); } -void CGLDevice::UpdateLightPositions() +void CGL14Device::UpdateLightPositions() { glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -653,7 +653,7 @@ void CGLDevice::UpdateLightPositions() glPopMatrix(); } -void CGLDevice::SetLightEnabled(int index, bool enabled) +void CGL14Device::SetLightEnabled(int index, bool enabled) { assert(index >= 0); assert(index < static_cast( m_lights.size() )); @@ -669,7 +669,7 @@ void CGLDevice::SetLightEnabled(int index, bool enabled) /** If image is invalid, returns invalid texture. Otherwise, returns pointer to new Texture struct. This struct must not be deleted in other way than through DeleteTexture() */ -Texture CGLDevice::CreateTexture(CImage *image, const TextureCreateParams ¶ms) +Texture CGL14Device::CreateTexture(CImage *image, const TextureCreateParams ¶ms) { ImageData *data = image->GetData(); if (data == nullptr) @@ -689,7 +689,7 @@ Texture CGLDevice::CreateTexture(CImage *image, const TextureCreateParams ¶m return tex; } -Texture CGLDevice::CreateTexture(ImageData *data, const TextureCreateParams ¶ms) +Texture CGL14Device::CreateTexture(ImageData *data, const TextureCreateParams ¶ms) { Texture result; @@ -778,7 +778,7 @@ Texture CGLDevice::CreateTexture(ImageData *data, const TextureCreateParams &par return result; } -Texture CGLDevice::CreateDepthTexture(int width, int height, int depth) +Texture CGL14Device::CreateDepthTexture(int width, int height, int depth) { Texture result; @@ -852,7 +852,7 @@ Texture CGLDevice::CreateDepthTexture(int width, int height, int depth) return result; } -void CGLDevice::UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format) +void CGL14Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format) { // Use & enable 1st texture stage glActiveTexture(GL_TEXTURE0 + m_remap[0]); @@ -872,7 +872,7 @@ void CGLDevice::UpdateTexture(const Texture& texture, Math::IntPoint offset, Ima SDL_FreeSurface(texData.convertedSurface); } -void CGLDevice::DestroyTexture(const Texture &texture) +void CGL14Device::DestroyTexture(const Texture &texture) { // Unbind the texture if in use anywhere for (int index = 0; index < static_cast( m_currentTextures.size() ); ++index) @@ -889,7 +889,7 @@ void CGLDevice::DestroyTexture(const Texture &texture) } } -void CGLDevice::DestroyAllTextures() +void CGL14Device::DestroyAllTextures() { // Unbind all texture stages for (int index = 0; index < static_cast( m_currentTextures.size() ); ++index) @@ -914,7 +914,7 @@ void CGLDevice::DestroyAllTextures() glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); } -int CGLDevice::GetMaxTextureStageCount() +int CGL14Device::GetMaxTextureStageCount() { return m_currentTextures.size(); } @@ -923,7 +923,7 @@ int CGLDevice::GetMaxTextureStageCount() If \a texture is invalid, unbinds the given texture. If valid, binds the texture and enables the given texture stage. The setting is remembered, even if texturing is disabled at the moment. */ -void CGLDevice::SetTexture(int index, const Texture &texture) +void CGL14Device::SetTexture(int index, const Texture &texture) { assert(index >= 0 && index < static_cast( m_currentTextures.size() )); @@ -942,7 +942,7 @@ void CGLDevice::SetTexture(int index, const Texture &texture) UpdateTextureParams(index); } -void CGLDevice::SetTexture(int index, unsigned int textureId) +void CGL14Device::SetTexture(int index, unsigned int textureId) { assert(index >= 0 && index < static_cast(m_currentTextures.size())); @@ -959,7 +959,7 @@ void CGLDevice::SetTexture(int index, unsigned int textureId) UpdateTextureParams(index); } -void CGLDevice::SetTextureEnabled(int index, bool enabled) +void CGL14Device::SetTextureEnabled(int index, bool enabled) { assert(index >= 0 && index < static_cast(m_currentTextures.size())); @@ -982,7 +982,7 @@ void CGLDevice::SetTextureEnabled(int index, bool enabled) Sets the texture parameters for the given texture stage. If the given texture was not set (bound) yet, nothing happens. The settings are remembered, even if texturing is disabled at the moment. */ -void CGLDevice::SetTextureStageParams(int index, const TextureStageParams ¶ms) +void CGL14Device::SetTextureStageParams(int index, const TextureStageParams ¶ms) { assert(index >= 0 && index < static_cast(m_currentTextures.size())); @@ -992,47 +992,7 @@ void CGLDevice::SetTextureStageParams(int index, const TextureStageParams ¶m UpdateTextureParams(index); } -void CGLDevice::SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) -{ - glActiveTexture(GL_TEXTURE0 + m_remap[index]); - - for (int i = 0; i < 4; i++) - { - GLuint texCoordGen = TranslateTextureCoordinateGen(i); - GLuint texCoord = TranslateTextureCoordinate(i); - - switch (params.coords[i].mode) - { - case TEX_GEN_NONE: - glDisable(texCoordGen); - break; - case TEX_GEN_OBJECT_LINEAR: - glEnable(texCoordGen); - glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGenfv(texCoord, GL_OBJECT_PLANE, params.coords[i].plane); - break; - case TEX_GEN_EYE_LINEAR: - glEnable(texCoordGen); - glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); - glTexGenfv(texCoord, GL_EYE_PLANE, params.coords[i].plane); - break; - case TEX_GEN_SPHERE_MAP: - glEnable(texCoordGen); - glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - break; - case TEX_GEN_NORMAL_MAP: - glEnable(texCoordGen); - glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP); - break; - case TEX_GEN_REFLECTION_MAP: - glEnable(texCoordGen); - glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); - break; - } - } -} - -void CGLDevice::UpdateTextureParams(int index) +void CGL14Device::UpdateTextureParams(int index) { assert(index >= 0 && index < static_cast(m_currentTextures.size())); @@ -1197,7 +1157,7 @@ after_tex_color: after_tex_operations: ; } -void CGLDevice::EnableShadows() +void CGL14Device::EnableShadows() { // already enabled if (m_shadowMapping) return; @@ -1292,7 +1252,7 @@ void CGLDevice::EnableShadows() m_shadowMapping = true; } -void CGLDevice::DisableShadows() +void CGL14Device::DisableShadows() { // already disabled if (!m_shadowMapping) return; @@ -1316,7 +1276,7 @@ void CGLDevice::DisableShadows() m_shadowMapping = false; } -void CGLDevice::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) +void CGL14Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) { assert(index >= 0 && index < static_cast( m_currentTextures.size() )); @@ -1347,7 +1307,7 @@ void CGLDevice::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wr else assert(false); } -void CGLDevice::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, +void CGL14Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, Color color) { Vertex* vs = const_cast(vertices); @@ -1371,7 +1331,7 @@ void CGLDevice::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int ve glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE0 } -void CGLDevice::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, +void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, Color color) { VertexTex2* vs = const_cast(vertices); @@ -1403,7 +1363,7 @@ void CGLDevice::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, in glDisableClientState(GL_TEXTURE_COORD_ARRAY); } -void CGLDevice::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) +void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) { VertexCol* vs = const_cast(vertices); @@ -1419,7 +1379,7 @@ void CGLDevice::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int glDisableClientState(GL_COLOR_ARRAY); } -void CGLDevice::DrawPrimitives(PrimitiveType type, const Vertex *vertices, +void CGL14Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, int first[], int count[], int drawCount, Color color) { Vertex* vs = const_cast(vertices); @@ -1453,7 +1413,7 @@ void CGLDevice::DrawPrimitives(PrimitiveType type, const Vertex *vertices, glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE0 } -void CGLDevice::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, +void CGL14Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, int first[], int count[], int drawCount, Color color) { VertexTex2* vs = const_cast(vertices); @@ -1494,7 +1454,7 @@ void CGLDevice::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, glDisableClientState(GL_TEXTURE_COORD_ARRAY); } -void CGLDevice::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, +void CGL14Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, int first[], int count[], int drawCount) { VertexCol* vs = const_cast(vertices); @@ -1521,7 +1481,7 @@ void CGLDevice::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, glDisableClientState(GL_COLOR_ARRAY); } -unsigned int CGLDevice::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) +unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) { unsigned int id = 0; if (m_vertexBufferType != VBT_DISPLAY_LIST) @@ -1565,7 +1525,7 @@ unsigned int CGLDevice::CreateStaticBuffer(PrimitiveType primitiveType, const Ve return id; } -unsigned int CGLDevice::CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) +unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) { unsigned int id = 0; if (m_vertexBufferType != VBT_DISPLAY_LIST) @@ -1609,7 +1569,7 @@ unsigned int CGLDevice::CreateStaticBuffer(PrimitiveType primitiveType, const Ve return id; } -unsigned int CGLDevice::CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) +unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) { unsigned int id = 0; if (m_vertexBufferType != VBT_DISPLAY_LIST) @@ -1653,7 +1613,7 @@ unsigned int CGLDevice::CreateStaticBuffer(PrimitiveType primitiveType, const Ve return id; } -void CGLDevice::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) +void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) { if (m_vertexBufferType != VBT_DISPLAY_LIST) { @@ -1689,7 +1649,7 @@ void CGLDevice::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiv } } -void CGLDevice::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) +void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) { if (m_vertexBufferType != VBT_DISPLAY_LIST) { @@ -1725,7 +1685,7 @@ void CGLDevice::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiv } } -void CGLDevice::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) +void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) { if (m_vertexBufferType != VBT_DISPLAY_LIST) { @@ -1761,7 +1721,7 @@ void CGLDevice::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiv } } -void CGLDevice::DrawStaticBuffer(unsigned int bufferId) +void CGL14Device::DrawStaticBuffer(unsigned int bufferId) { if (m_vertexBufferType != VBT_DISPLAY_LIST) { @@ -1846,7 +1806,7 @@ void CGLDevice::DrawStaticBuffer(unsigned int bufferId) } } -void CGLDevice::DestroyStaticBuffer(unsigned int bufferId) +void CGL14Device::DestroyStaticBuffer(unsigned int bufferId) { if (m_vertexBufferType != VBT_DISPLAY_LIST) { @@ -1869,7 +1829,7 @@ void CGLDevice::DestroyStaticBuffer(unsigned int bufferId) /* Based on libwine's implementation */ -int CGLDevice::ComputeSphereVisibility(const Math::Vector ¢er, float radius) +int CGL14Device::ComputeSphereVisibility(const Math::Vector ¢er, float radius) { if (m_combinedMatrixOutdated) { @@ -1948,12 +1908,12 @@ int CGLDevice::ComputeSphereVisibility(const Math::Vector ¢er, float radius) return result; } -void CGLDevice::SetViewport(int x, int y, int width, int height) +void CGL14Device::SetViewport(int x, int y, int width, int height) { glViewport(x, y, width, height); } -void CGLDevice::SetRenderState(RenderState state, bool enabled) +void CGL14Device::SetRenderState(RenderState state, bool enabled) { if (state == RENDER_STATE_DEPTH_WRITE) { @@ -2005,42 +1965,42 @@ void CGLDevice::SetRenderState(RenderState state, bool enabled) glDisable(flag); } -void CGLDevice::SetColorMask(bool red, bool green, bool blue, bool alpha) +void CGL14Device::SetColorMask(bool red, bool green, bool blue, bool alpha) { glColorMask(red, green, blue, alpha); } -void CGLDevice::SetDepthTestFunc(CompFunc func) +void CGL14Device::SetDepthTestFunc(CompFunc func) { glDepthFunc(TranslateGfxCompFunc(func)); } -void CGLDevice::SetDepthBias(float factor, float units) +void CGL14Device::SetDepthBias(float factor, float units) { glPolygonOffset(factor, units); } -void CGLDevice::SetAlphaTestFunc(CompFunc func, float refValue) +void CGL14Device::SetAlphaTestFunc(CompFunc func, float refValue) { glAlphaFunc(TranslateGfxCompFunc(func), refValue); } -void CGLDevice::SetBlendFunc(BlendFunc srcBlend, BlendFunc dstBlend) +void CGL14Device::SetBlendFunc(BlendFunc srcBlend, BlendFunc dstBlend) { glBlendFunc(TranslateGfxBlendFunc(srcBlend), TranslateGfxBlendFunc(dstBlend)); } -void CGLDevice::SetClearColor(const Color &color) +void CGL14Device::SetClearColor(const Color &color) { glClearColor(color.r, color.g, color.b, color.a); } -void CGLDevice::SetGlobalAmbient(const Color &color) +void CGL14Device::SetGlobalAmbient(const Color &color) { glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.Array()); } -void CGLDevice::SetFogParams(FogMode mode, const Color &color, float start, float end, float density) +void CGL14Device::SetFogParams(FogMode mode, const Color &color, float start, float end, float density) { if (mode == FOG_LINEAR) glFogi(GL_FOG_MODE, GL_LINEAR); else if (mode == FOG_EXP) glFogi(GL_FOG_MODE, GL_EXP); @@ -2053,7 +2013,7 @@ void CGLDevice::SetFogParams(FogMode mode, const Color &color, float start, floa glFogfv(GL_FOG_COLOR, color.Array()); } -void CGLDevice::SetCullMode(CullMode mode) +void CGL14Device::SetCullMode(CullMode mode) { // Cull clockwise back faces, so front face is the opposite // (assuming GL_CULL_FACE is GL_BACK) @@ -2062,19 +2022,19 @@ void CGLDevice::SetCullMode(CullMode mode) else assert(false); } -void CGLDevice::SetShadeModel(ShadeModel model) +void CGL14Device::SetShadeModel(ShadeModel model) { if (model == SHADE_FLAT) glShadeModel(GL_FLAT); else if (model == SHADE_SMOOTH) glShadeModel(GL_SMOOTH); else assert(false); } -void CGLDevice::SetShadowColor(float value) +void CGL14Device::SetShadowColor(float value) { // doesn't do anything because it can't } -void CGLDevice::SetFillMode(FillMode mode) +void CGL14Device::SetFillMode(FillMode mode) { if (mode == FILL_POINT) glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); else if (mode == FILL_LINES) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -2082,7 +2042,7 @@ void CGLDevice::SetFillMode(FillMode mode) else assert(false); } -void CGLDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) +void CGL14Device::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) { if (texture.id == 0) return; @@ -2096,12 +2056,12 @@ void CGLDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOff glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); } -std::unique_ptr CGLDevice::GetFrameBufferPixels() const +std::unique_ptr CGL14Device::GetFrameBufferPixels() const { return GetGLFrameBufferPixels(m_config.size); } -CFramebuffer* CGLDevice::GetFramebuffer(std::string name) +CFramebuffer* CGL14Device::GetFramebuffer(std::string name) { auto it = m_framebuffers.find(name); if (it == m_framebuffers.end()) @@ -2110,7 +2070,7 @@ CFramebuffer* CGLDevice::GetFramebuffer(std::string name) return it->second.get(); } -CFramebuffer* CGLDevice::CreateFramebuffer(std::string name, const FramebufferParams& params) +CFramebuffer* CGL14Device::CreateFramebuffer(std::string name, const FramebufferParams& params) { // existing framebuffer was found if (m_framebuffers.find(name) != m_framebuffers.end()) @@ -2134,7 +2094,7 @@ CFramebuffer* CGLDevice::CreateFramebuffer(std::string name, const FramebufferPa return framebufferPtr; } -void CGLDevice::DeleteFramebuffer(std::string name) +void CGL14Device::DeleteFramebuffer(std::string name) { // can't delete default framebuffer if (name == "default") return; @@ -2147,32 +2107,32 @@ void CGLDevice::DeleteFramebuffer(std::string name) } } -bool CGLDevice::IsAnisotropySupported() +bool CGL14Device::IsAnisotropySupported() { return m_capabilities.anisotropySupported; } -int CGLDevice::GetMaxAnisotropyLevel() +int CGL14Device::GetMaxAnisotropyLevel() { return m_capabilities.maxAnisotropy; } -int CGLDevice::GetMaxSamples() +int CGL14Device::GetMaxSamples() { return m_capabilities.maxSamples; } -bool CGLDevice::IsShadowMappingSupported() +bool CGL14Device::IsShadowMappingSupported() { return m_capabilities.shadowMappingSupported; } -int CGLDevice::GetMaxTextureSize() +int CGL14Device::GetMaxTextureSize() { return m_capabilities.maxTextureSize; } -bool CGLDevice::IsFramebufferSupported() +bool CGL14Device::IsFramebufferSupported() { return m_capabilities.framebufferSupported; } diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gl14device.h similarity index 96% rename from src/graphics/opengl/gldevice.h rename to src/graphics/opengl/gl14device.h index baaaa3b8..96190394 100644 --- a/src/graphics/opengl/gldevice.h +++ b/src/graphics/opengl/gl14device.h @@ -18,8 +18,8 @@ */ /** - * \file graphics/opengl/gldevice.h - * \brief OpenGL implementation - CGLDevice class + * \file graphics/opengl/gl14device.h + * \brief OpenGL implementation - CGL14Device class */ #pragma once @@ -62,21 +62,21 @@ enum ShadowMappingSupport }; /** - \class CGLDevice + \class CGL14Device \brief Implementation of CDevice interface in OpenGL Provides the concrete implementation of 3D device in OpenGL. This class should be initialized (by calling Initialize() ) only after setting the video mode by CApplication, once the OpenGL context is defined. - Because of that, CGLDeviceConfig is outside the CDevice class and must be set + Because of that, CGL14DeviceConfig is outside the CDevice class and must be set in CApplication. */ -class CGLDevice : public CDevice +class CGL14Device : public CDevice { public: - CGLDevice(const DeviceConfig &config); - virtual ~CGLDevice(); + CGL14Device(const DeviceConfig &config); + virtual ~CGL14Device(); void DebugHook() override; void DebugLights() override; @@ -118,7 +118,6 @@ public: void SetTextureStageParams(int index, const TextureStageParams ¶ms) override; void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; - void SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) override; virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp index 6f7051e3..e1a96dbe 100644 --- a/src/graphics/opengl/gl21device.cpp +++ b/src/graphics/opengl/gl21device.cpp @@ -174,7 +174,7 @@ bool CGL21Device::Create() if (!InitializeGLEW()) { - m_errorMessage = "An error occured while initializing GLEW."; + m_errorMessage = "An error occurred while initializing GLEW."; return false; } @@ -1058,48 +1058,6 @@ void CGL21Device::SetTextureStageParams(int index, const TextureStageParams &par UpdateTextureParams(index); } -void CGL21Device::SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) -{ - /* - glActiveTexture(GL_TEXTURE0 + index); - - for (int i = 0; i < 4; i++) - { - GLuint texCoordGen = TranslateTextureCoordinateGen(i); - GLuint texCoord = TranslateTextureCoordinate(i); - - switch (params.coords[i].mode) - { - case TEX_GEN_NONE: - glDisable(texCoordGen); - break; - case TEX_GEN_OBJECT_LINEAR: - glEnable(texCoordGen); - glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGenfv(texCoord, GL_OBJECT_PLANE, params.coords[i].plane); - break; - case TEX_GEN_EYE_LINEAR: - glEnable(texCoordGen); - glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); - glTexGenfv(texCoord, GL_EYE_PLANE, params.coords[i].plane); - break; - case TEX_GEN_SPHERE_MAP: - glEnable(texCoordGen); - glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - break; - case TEX_GEN_NORMAL_MAP: - glEnable(texCoordGen); - glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP); - break; - case TEX_GEN_REFLECTION_MAP: - glEnable(texCoordGen); - glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); - break; - } - } - // */ -} - void CGL21Device::UpdateTextureParams(int index) { assert(index >= 0 && index < static_cast( m_currentTextures.size() )); diff --git a/src/graphics/opengl/gl21device.h b/src/graphics/opengl/gl21device.h index 83627bfc..20cf2156 100644 --- a/src/graphics/opengl/gl21device.h +++ b/src/graphics/opengl/gl21device.h @@ -18,7 +18,7 @@ */ /** - * \file graphics/opengl/gldevice.h + * \file graphics/opengl/gl21device.h * \brief OpenGL implementation - CGL21Device class */ @@ -99,7 +99,6 @@ public: void SetTextureStageParams(int index, const TextureStageParams ¶ms) override; void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; - void SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) override; virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp index d02ff77a..df67e5c1 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl/gl33device.cpp @@ -173,7 +173,7 @@ bool CGL33Device::Create() if (!InitializeGLEW()) { - m_errorMessage = "An error occured while initializing GLEW."; + m_errorMessage = "An error occurred while initializing GLEW."; return false; } @@ -1009,11 +1009,6 @@ void CGL33Device::SetTextureStageParams(int index, const TextureStageParams &par UpdateTextureParams(index); } -void CGL33Device::SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) -{ - -} - void CGL33Device::UpdateTextureParams(int index) { assert(index >= 0 && index < static_cast( m_currentTextures.size() )); diff --git a/src/graphics/opengl/gl33device.h b/src/graphics/opengl/gl33device.h index 317c7b13..a47fb999 100644 --- a/src/graphics/opengl/gl33device.h +++ b/src/graphics/opengl/gl33device.h @@ -114,7 +114,6 @@ public: void SetTextureStageParams(int index, const TextureStageParams ¶ms) override; void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; - void SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) override; virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; diff --git a/src/graphics/opengl/glutil.cpp b/src/graphics/opengl/glutil.cpp index 95c1f24f..bd6ae886 100644 --- a/src/graphics/opengl/glutil.cpp +++ b/src/graphics/opengl/glutil.cpp @@ -23,9 +23,9 @@ #include "common/logger.h" #include "common/make_unique.h" +#include "graphics/opengl/gl14device.h" #include "graphics/opengl/gl21device.h" #include "graphics/opengl/gl33device.h" -#include "graphics/opengl/gldevice.h" #include #include @@ -71,9 +71,9 @@ FramebufferSupport DetectFramebufferSupport() std::unique_ptr CreateDevice(const DeviceConfig &config, const std::string& name) { - if (name == "default") return MakeUnique(config); - else if (name == "opengl") return MakeUnique(config); - else if (name == "gl14") return MakeUnique(config); + if (name == "default") return MakeUnique(config); + else if (name == "opengl") return MakeUnique(config); + else if (name == "gl14") return MakeUnique(config); else if (name == "gl21") return MakeUnique(config); else if (name == "gl33") return MakeUnique(config); else if (name == "auto") @@ -82,7 +82,7 @@ std::unique_ptr CreateDevice(const DeviceConfig &config, const std::str if (version >= 33) return MakeUnique(config); else if (version >= 21) return MakeUnique(config); - else return MakeUnique(config); + else return MakeUnique(config); } return nullptr; @@ -480,8 +480,8 @@ GLint LoadShader(GLint type, const char* filename) auto message = MakeUniqueArray(len + 1); glGetShaderInfoLog(shader, len + 1, nullptr, message.get()); - GetLogger()->Error("Shader compilation error occured!\n%s\n", message.get()); - lastShaderError = std::string("Shader compilation error occured!\n\n") + std::string(message.get()); + GetLogger()->Error("Shader compilation error occurred!\n%s\n", message.get()); + lastShaderError = std::string("Shader compilation error occurred!\n\n") + std::string(message.get()); glDeleteShader(shader); return 0; @@ -513,8 +513,8 @@ GLint LinkProgram(int count, GLint shaders[]) auto message = MakeUniqueArray(len + 1); glGetProgramInfoLog(program, len + 1, nullptr, message.get()); - GetLogger()->Error("Shader program linking error occured!\n%s\n", message.get()); - lastShaderError = std::string("Shader program linking error occured!\n\n") + std::string(message.get()); + GetLogger()->Error("Shader program linking error occurred!\n%s\n", message.get()); + lastShaderError = std::string("Shader program linking error occurred!\n\n") + std::string(message.get()); glDeleteProgram(program); diff --git a/src/level/level_category.cpp b/src/level/level_category.cpp index e2eab7df..c9274550 100644 --- a/src/level/level_category.cpp +++ b/src/level/level_category.cpp @@ -30,10 +30,6 @@ const std::map CATEGORY_DIR_MAP = { { LevelCategory::Challenges, "challenges" }, { LevelCategory::CodeBattles, "battles" }, { LevelCategory::CustomLevels, "custom" }, - - { LevelCategory::Win, "win" }, - { LevelCategory::Lost, "lost" }, - { LevelCategory::Perso, "perso" }, }; std::string GetLevelCategoryDir(LevelCategory category) diff --git a/src/level/level_category.h b/src/level/level_category.h index 1db6bccb..4001b674 100644 --- a/src/level/level_category.h +++ b/src/level/level_category.h @@ -30,11 +30,6 @@ enum class LevelCategory CodeBattles, CustomLevels, Max, - - // These are special types not runnable by the user - Win, - Lost, - Perso, }; std::string GetLevelCategoryDir(LevelCategory category); diff --git a/src/level/mainmovie.cpp b/src/level/mainmovie.cpp index 3bf37ebd..dc5f4cb0 100644 --- a/src/level/mainmovie.cpp +++ b/src/level/mainmovie.cpp @@ -95,9 +95,7 @@ bool CMainMovie::Start(MainMovieType type, float time) m_camera->GetCamera(m_initialEye, m_initialLookat); m_camera->SetType(Gfx::CAM_TYPE_SCRIPT); m_camera->SetSmooth(Gfx::CAM_SMOOTH_HARD); - m_camera->SetScriptEye(m_initialEye); - m_camera->SetScriptLookat(m_initialLookat); - m_camera->FixCamera(); + m_camera->SetScriptCamera(m_initialEye, m_initialLookat); mat = pObj->GetWorldMatrix(0); m_finalLookat[0] = Math::Transform(*mat, Math::Vector( 1.6f, 1.0f, 1.2f)); @@ -187,9 +185,7 @@ bool CMainMovie::EventProcess(const Event &event) eye = (finalEye-initialEye)*progress+initialEye; lookat = (finalLookat-initialLookat)*progress+initialLookat; - m_camera->SetScriptEye(eye); - m_camera->SetScriptLookat(lookat); -// m_camera->FixCamera(); + m_camera->SetScriptCameraAnimate(eye, lookat); } else { diff --git a/src/level/parser/parserparam.cpp b/src/level/parser/parserparam.cpp index 317d388b..fb3c82f7 100644 --- a/src/level/parser/parserparam.cpp +++ b/src/level/parser/parserparam.cpp @@ -530,7 +530,7 @@ ObjectType CLevelParserParam::ToObjectType(std::string value) if (value == "Me" ) return OBJECT_HUMAN; if (value == "Tech" ) return OBJECT_TECH; if (value == "MissionController" ) return OBJECT_CONTROLLER; - return static_cast(boost::lexical_cast(value)); + return static_cast(Cast(value, "object")); } const std::string CLevelParserParam::FromObjectType(ObjectType value) diff --git a/src/level/parser/parserparam.h b/src/level/parser/parserparam.h index f620d845..c72be4f0 100644 --- a/src/level/parser/parserparam.h +++ b/src/level/parser/parserparam.h @@ -123,7 +123,6 @@ public: bool IsDefined(); static const std::string FromObjectType(ObjectType value); - static ObjectType ToObjectType(std::string value); private: void ParseArray(); @@ -133,6 +132,7 @@ private: template T Cast(std::string requestedType); std::string ToPath(std::string path, const std::string defaultDir); + ObjectType ToObjectType(std::string value); DriveType ToDriveType(std::string value); ToolType ToToolType(std::string value); Gfx::WaterType ToWaterType(std::string value); diff --git a/src/level/player_profile.cpp b/src/level/player_profile.cpp index a34bfb50..d3603f1c 100644 --- a/src/level/player_profile.cpp +++ b/src/level/player_profile.cpp @@ -38,9 +38,9 @@ void PlayerApperance::DefPerso() this->colorCombi.r = 206.0f/256.0f; this->colorCombi.g = 206.0f/256.0f; this->colorCombi.b = 204.0f/256.0f; // ~white - this->colorBand.r = 255.0f/256.0f; - this->colorBand.g = 132.0f/256.0f; - this->colorBand.b = 1.0f/256.0f; // orange + this->colorBand.r = 255.0f / 256.0f; + this->colorBand.g = 132.0f / 256.0f; + this->colorBand.b = 1.0f / 256.0f; // orange if ( this->face == 0 ) // normal ? { @@ -52,23 +52,23 @@ void PlayerApperance::DefPerso() if ( this->face == 1 ) // bald ? { this->glasses = 0; - this->colorHair.r = 83.0f/256.0f; - this->colorHair.g = 64.0f/256.0f; - this->colorHair.b = 51.0f/256.0f; // brown + this->colorHair.r = 74.0f / 256.0f; + this->colorHair.g = 58.0f / 256.0f; + this->colorHair.b = 46.0f / 256.0f; // brown } if ( this->face == 2 ) // carlos ? { this->glasses = 1; - this->colorHair.r = 85.0f/256.0f; - this->colorHair.g = 48.0f/256.0f; + this->colorHair.r = 70.0f / 256.0f; + this->colorHair.g = 40.0f / 256.0f; this->colorHair.b = 9.0f/256.0f; // brown } - if ( this->face == 3 ) // blond ? + if ( this->face == 3 ) // blond ? -> ginger ? { this->glasses = 4; - this->colorHair.r = 255.0f/256.0f; - this->colorHair.g = 255.0f/256.0f; - this->colorHair.b = 181.0f/256.0f; // yellow + this->colorHair.r = 74.0f / 256.0f; + this->colorHair.g = 16.0f / 256.0f; + this->colorHair.b = 0.0f / 256.0f; // yellow, changed to ginger } this->colorHair.a = 0.0f; @@ -76,6 +76,37 @@ void PlayerApperance::DefPerso() this->colorBand.a = 0.0f; } +void PlayerApperance::DefHairColor() +{ + if (this->face == 0) // normal ? + { + this->colorHair.r = 90.0f / 256.0f; + this->colorHair.g = 95.0f / 256.0f; + this->colorHair.b = 85.0f / 256.0f; // black + } + if (this->face == 1) // bald ? + { + this->colorHair.r = 74.0f / 256.0f; + this->colorHair.g = 58.0f / 256.0f; + this->colorHair.b = 46.0f / 256.0f; // brown + } + if (this->face == 2) // carlos ? + { + this->colorHair.r = 70.0f / 256.0f; + this->colorHair.g = 40.0f / 256.0f; + this->colorHair.b = 9.0f / 256.0f; // brown + } + if (this->face == 3) // blond ? -> ginger ? + { + this->colorHair.r = 74.0f / 256.0f; + this->colorHair.g = 16.0f / 256.0f; + this->colorHair.b = 0.0f / 256.0f; // yellow, changed to ginger + } + + this->colorHair.a = 0.0f; +} + + CPlayerProfile::CPlayerProfile(std::string playerName) { m_playerName = playerName; diff --git a/src/level/player_profile.h b/src/level/player_profile.h index 63bbfd74..fc198cbe 100644 --- a/src/level/player_profile.h +++ b/src/level/player_profile.h @@ -42,6 +42,7 @@ struct PlayerApperance Gfx::Color colorBand; // strips color void DefPerso(); + void DefHairColor(); }; struct SavedScene diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 514d2181..75c12f8a 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -29,7 +29,6 @@ #include "common/event.h" #include "common/logger.h" #include "common/make_unique.h" -#include "common/misc.h" #include "common/restext.h" #include "common/settings.h" #include "common/stringutils.h" @@ -86,6 +85,7 @@ #include "sound/sound.h" +#include "ui/debug_menu.h" #include "ui/displayinfo.h" #include "ui/displaytext.h" #include "ui/maindialog.h" @@ -105,8 +105,10 @@ #include "ui/screen/screen_loading.h" +#include #include #include +#include #include @@ -116,6 +118,12 @@ const float UNIT = 4.0f; // default for g_unit float g_unit; // conversion factor +// 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 +const Gfx::Color COLOR_REF_GREEN = Gfx::Color(135.0f/256.0f, 170.0f/256.0f, 13.0f/256.0f); // green +const Gfx::Color COLOR_REF_WATER = Gfx::Color( 25.0f/256.0f, 255.0f/256.0f, 240.0f/256.0f); // cyan + template<> CRobotMain* CSingleton::m_instance = nullptr; @@ -156,6 +164,8 @@ CRobotMain::CRobotMain() m_modelManager.get(), m_particle); + m_debugMenu = MakeUnique(this, m_engine, m_objMan.get(), m_sound); + m_time = 0.0f; m_gameTime = 0.0f; m_gameTimeAbsolute = 0.0f; @@ -219,14 +229,10 @@ CRobotMain::CRobotMain() m_tooltipName.clear(); m_tooltipTime = 0.0f; - m_endingWinRank = 0; - m_endingLostRank = 0; m_winTerminate = false; m_globalMagnifyDamage = 1.0f; - m_exitAfterMission = false; - m_autosave = true; m_autosaveInterval = 5; m_autosaveSlots = 3; @@ -234,9 +240,6 @@ CRobotMain::CRobotMain() m_shotSaving = 0; - m_cameraPan = 0.0f; - m_cameraZoom = 0.0f; - m_build = 0; m_researchDone.clear(); // no research done m_researchDone[0] = 0; @@ -303,30 +306,6 @@ CPauseManager* CRobotMain::GetPauseManager() return m_pause.get(); } -void CRobotMain::ResetAfterVideoConfigChanged() -{ - // Recreate the interface (needed if the aspect ratio changes) - // TODO: This can sometimes cause unwanted side effects, like hidden windows reappearing. To be fixed during CEGUI refactoring. - m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE)); - CreateShortcuts(); -} - -void CRobotMain::ReloadAllTextures() -{ - if (m_phase == PHASE_SETUPds || - m_phase == PHASE_SETUPgs || - m_phase == PHASE_SETUPps || - m_phase == PHASE_SETUPcs || - m_phase == PHASE_SETUPss || - m_phase == PHASE_SIMUL || - m_phase == PHASE_WIN || - m_phase == PHASE_LOST) - { - ChangeColor(); - UpdateMap(); - } -} - std::string PhaseToString(Phase phase) { if (phase == PHASE_WELCOME1) return "PHASE_WELCOME1"; @@ -384,6 +363,13 @@ void CRobotMain::ChangePhase(Phase phase) bool resetWorld = false; if ((IsPhaseWithWorld(m_phase) || IsPhaseWithWorld(phase)) && !IsInSimulationConfigPhase(m_phase) && !IsInSimulationConfigPhase(phase)) { + if (IsPhaseWithWorld(m_phase) && !IsPhaseWithWorld(phase) && m_exitAfterMission) + { + GetLogger()->Info("Mission finished in single mission mode, exiting\n"); + m_eventQueue->AddEvent(Event(EVENT_QUIT)); + return; + } + GetLogger()->Info("Reseting world on phase change...\n"); resetWorld = true; } @@ -468,11 +454,9 @@ void CRobotMain::ChangePhase(Phase phase) FlushNewScriptName(); m_sound->SetListener(Math::Vector(0.0f, 0.0f, 0.0f), Math::Vector(0.0f, 0.0f, 1.0f)); m_sound->StopAll(); - m_camera->SetType(Gfx::CAM_TYPE_DIALOG); + m_camera->SetType(Gfx::CAM_TYPE_NULL); m_movie->Flush(); m_movieInfoIndex = -1; - m_cameraPan = 0.0f; - m_cameraZoom = 0.0f; m_shortCut = true; } ClearInterface(); @@ -573,21 +557,21 @@ void CRobotMain::ChangePhase(Phase phase) } catch (const std::runtime_error& e) { - LevelLoadingError("An error occured while trying to load a level", e); + LevelLoadingError("An error occurred while trying to load a level", e); } } if (m_phase == PHASE_WIN) { m_sound->StopAll(); - if (m_endingWinRank == -1) + if (m_endingWin.empty()) { ChangePhase(PHASE_LEVEL_LIST); } else { - m_winTerminate = (m_endingWinRank == 904); - SetLevel(LevelCategory::Win, 0, m_endingWinRank); + m_winTerminate = (m_endingWin.substr(m_endingWin.find_last_of("/")+1) == "win904.txt"); + m_levelFile = m_endingWin; try { CreateScene(false, true, false); // sets scene @@ -616,7 +600,7 @@ void CRobotMain::ChangePhase(Phase phase) } catch (const std::runtime_error& e) { - LevelLoadingError("An error occured while trying to load win scene", e); + LevelLoadingError("An error occurred while trying to load win scene", e); } } } @@ -624,14 +608,14 @@ void CRobotMain::ChangePhase(Phase phase) if (m_phase == PHASE_LOST) { m_sound->StopAll(); - if (m_endingLostRank == -1) + if (m_endingLost.empty()) { ChangePhase(PHASE_LEVEL_LIST); } else { m_winTerminate = false; - SetLevel(LevelCategory::Lost, 0, m_endingLostRank); + m_levelFile = m_endingLost; try { CreateScene(false, true, false); // sets scene @@ -646,7 +630,7 @@ void CRobotMain::ChangePhase(Phase phase) } catch (const std::runtime_error& e) { - LevelLoadingError("An error occured while trying to load lost scene", e); + LevelLoadingError("An error occurred while trying to load lost scene", e); } } } @@ -663,6 +647,12 @@ Phase CRobotMain::GetPhase() bool CRobotMain::ProcessEvent(Event &event) { if (!m_ui->EventProcess(event)) return false; + if (m_phase == PHASE_SIMUL) + { + if (!m_editFull) + m_camera->EventProcess(event); + } + if (!m_debugMenu->EventProcess(event)) return false; if (event.type == EVENT_FRAME) { @@ -683,7 +673,6 @@ bool CRobotMain::ProcessEvent(Event &event) } m_displayText->EventProcess(event); - RemoteCamera(m_cameraPan, m_cameraZoom, event.rTime); if (m_displayInfo != nullptr) // current edition? m_displayInfo->EventProcess(event); @@ -693,6 +682,24 @@ bool CRobotMain::ProcessEvent(Event &event) return EventFrame(event); } + if (event.type == EVENT_RELOAD_TEXTURES) + { + if (IsPhaseWithWorld(m_phase)) + { + ChangeColor(); + UpdateMap(); + } + m_engine->LoadAllTextures(); + } + + if (event.type == EVENT_RESOLUTION_CHANGED) + { + // Recreate the interface (needed if the aspect ratio changes) + // TODO: This can sometimes cause unwanted side effects, like hidden windows reappearing. To be fixed during CEGUI refactoring. + m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE)); + CreateShortcuts(); + } + if (event.type == EVENT_FOCUS_LOST) { GetLogger()->Trace("Window unfocused\n"); @@ -759,6 +766,15 @@ bool CRobotMain::ProcessEvent(Event &event) } return false; } + + if (IsPhaseWithWorld(m_phase)) + { + if (data->key == KEY(F11)) + { + m_debugMenu->ToggleInterface(); + return false; + } + } } if (event.type == EVENT_KEY_DOWN && @@ -826,22 +842,13 @@ bool CRobotMain::ProcessEvent(Event &event) // Simulation phase of the game if (m_phase == PHASE_SIMUL) { - if (!m_editFull) - m_camera->EventProcess(event); - switch (event.type) { case EVENT_KEY_DOWN: { auto data = event.GetData(); - KeyCamera(event.type, data->slot); HiliteClear(); - if (data->key == KEY(F11)) - { - m_particle->WriteWheelTrace("Savegame/t.png", 256, 256, Math::Vector(16.0f, 0.0f, -368.0f), Math::Vector(140.0f, 0.0f, -248.0f)); - return false; - } if (m_editLock) // current edition? { if (data->slot == INPUT_SLOT_HELP) @@ -987,13 +994,6 @@ bool CRobotMain::ProcessEvent(Event &event) break; } - case EVENT_KEY_UP: - { - auto data = event.GetData(); - KeyCamera(event.type, data->slot); - break; - } - case EVENT_MOUSE_BUTTON_DOWN: { if (event.GetData()->button != MOUSE_BUTTON_LEFT) // only left mouse button @@ -1020,14 +1020,6 @@ bool CRobotMain::ProcessEvent(Event &event) break; } - case EVENT_MOUSE_BUTTON_UP: - if (event.GetData()->button != MOUSE_BUTTON_LEFT) // only left mouse button - break; - - m_cameraPan = 0.0f; - m_cameraZoom = 0.0f; - break; - case EVENT_OBJECT_LIMIT: StartShowLimit(); break; @@ -1045,19 +1037,6 @@ bool CRobotMain::ProcessEvent(Event &event) ChangeCamera(); break; - case EVENT_OBJECT_CAMERAleft: - m_cameraPan = -1.0f; - break; - case EVENT_OBJECT_CAMERAright: - m_cameraPan = 1.0f; - break; - case EVENT_OBJECT_CAMERAnear: - m_cameraZoom = -1.0f; - break; - case EVENT_OBJECT_CAMERAaway: - m_cameraZoom = 1.0f; - break; - case EVENT_OBJECT_DELETE: m_ui->GetDialog()->StartQuestion( RT_DIALOG_DELOBJ, true, false, false, @@ -1163,25 +1142,25 @@ bool CRobotMain::ProcessEvent(Event &event) //! Executes a command -void CRobotMain::ExecuteCmd(char *cmd) +void CRobotMain::ExecuteCmd(const std::string& cmd) { - if (cmd[0] == 0) return; + if (cmd.empty()) return; if (m_phase == PHASE_SIMUL) { - if (strcmp(cmd, "winmission") == 0) + if (cmd == "winmission") m_eventQueue->AddEvent(Event(EVENT_WIN)); - if (strcmp(cmd, "lostmission") == 0) + if (cmd == "lostmission") m_eventQueue->AddEvent(Event(EVENT_LOST)); - if (strcmp(cmd, "trainerpilot") == 0) + if (cmd == "trainerpilot") { m_trainerPilot = !m_trainerPilot; return; } - if (strcmp(cmd, "fly") == 0) + if (cmd == "fly") { m_researchDone[0] |= RESEARCH_FLY; @@ -1189,7 +1168,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "allresearch") == 0) + if (cmd == "allresearch") { m_researchDone[0] = -1; // all research are done @@ -1197,7 +1176,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "allbuildings") == 0) + if (cmd == "allbuildings") { m_build = -1; // all buildings are available @@ -1205,7 +1184,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "all") == 0) + if (cmd == "all") { m_researchDone[0] = -1; // all research are done m_build = -1; // all buildings are available @@ -1214,31 +1193,34 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "nolimit") == 0) + if (cmd == "nolimit") { m_terrain->SetFlyingMaxHeight(280.0f); return; } - if (strcmp(cmd, "controller") == 0) + if (cmd == "controller") { - if (m_controller != nullptr) + if (m_controller == nullptr) { - // Don't use SelectObject because it checks if the object is selectable - if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT) - StopDisplayVisit(); - - CObject* prev = DeselectAll(); - if (prev != nullptr && prev != m_controller) - PushToSelectionHistory(prev); - - SelectOneObject(m_controller, true); - m_short->UpdateShortcuts(); + GetLogger()->Error("No LevelController on the map to select\n"); + return; } + + // Don't use SelectObject because it checks if the object is selectable + if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT) + StopDisplayVisit(); + + CObject* prev = DeselectAll(); + if (prev != nullptr && prev != m_controller) + PushToSelectionHistory(prev); + + SelectOneObject(m_controller, true); + m_short->UpdateShortcuts(); return; } - if (strcmp(cmd, "photo1") == 0) + if (cmd == "photo1") { if (m_freePhotoPause == nullptr) { @@ -1254,7 +1236,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "photo2") == 0) + if (cmd == "photo2") { if (m_freePhotoPause == nullptr) { @@ -1276,26 +1258,26 @@ void CRobotMain::ExecuteCmd(char *cmd) } int camtype; - if (sscanf(cmd, "camtype %d", &camtype) > 0) + if (sscanf(cmd.c_str(), "camtype %d", &camtype) > 0) { m_camera->SetType(static_cast(camtype)); return; } float camspeed; - if (sscanf(cmd, "camspeed %f", &camspeed) > 0) + if (sscanf(cmd.c_str(), "camspeed %f", &camspeed) > 0) { m_camera->SetCameraSpeed(camspeed); return; } - if (strcmp(cmd, "freecam") == 0) + if (cmd == "freecam") { m_camera->SetType(Gfx::CAM_TYPE_FREE); return; } - if (strcmp(cmd, "noclip") == 0) + if (cmd == "noclip") { CObject* object = GetSelect(); if (object != nullptr) @@ -1303,7 +1285,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "clip") == 0) + if (cmd == "clip") { CObject* object = GetSelect(); if (object != nullptr) @@ -1311,7 +1293,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "addhusky") == 0) + if (cmd == "addhusky") { CObject* object = GetSelect(); if (object != nullptr && object->Implements(ObjectInterfaceType::Shielded)) @@ -1319,7 +1301,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "addfreezer") == 0) + if (cmd == "addfreezer") { CObject* object = GetSelect(); if (object != nullptr && object->Implements(ObjectInterfaceType::JetFlying)) @@ -1327,7 +1309,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "\155\157\157") == 0) + if (cmd == "\155\157\157") { // VGhpcyBpcyBlYXN0ZXItZWdnIGFuZCBzbyBpdCBzaG91bGQgYmUgb2JmdXNjYXRlZCEgRG8gbm90 // IGNsZWFuLXVwIHRoaXMgY29kZSEK @@ -1341,7 +1323,7 @@ void CRobotMain::ExecuteCmd(char *cmd) GetLogger()->Info(" \x20\x20 \x7C\x7C\x20\x20\x20\x20 ||\n"); } - if (strcmp(cmd, "fullpower") == 0) + if (cmd == "fullpower") { CObject* object = GetSelect(); if (object != nullptr) @@ -1362,7 +1344,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "fullenergy") == 0) + if (cmd == "fullenergy") { CObject* object = GetSelect(); @@ -1378,7 +1360,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "fullshield") == 0) + if (cmd == "fullshield") { CObject* object = GetSelect(); if (object != nullptr && object->Implements(ObjectInterfaceType::Shielded)) @@ -1386,7 +1368,7 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "fullrange") == 0) + if (cmd == "fullrange") { CObject* object = GetSelect(); if (object != nullptr) @@ -1396,19 +1378,9 @@ void CRobotMain::ExecuteCmd(char *cmd) } return; } - if (strcmp(cmd, "debugcrashon") == 0) - { - m_debugCrashSpheres = true; - return; - } - if (strcmp(cmd, "debugcrashoff") == 0) - { - m_debugCrashSpheres = false; - return; - } } - if (strcmp(cmd, "debugmode") == 0) + if (cmd == "debugmode") { if (m_app->IsDebugModeActive(DEBUG_ALL)) { @@ -1421,46 +1393,46 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } - if (strcmp(cmd, "showstat") == 0) + if (cmd == "showstat") { m_engine->SetShowStats(!m_engine->GetShowStats()); return; } - if (strcmp(cmd, "invui") == 0) + if (cmd == "invui") { m_engine->SetRenderInterface(!m_engine->GetRenderInterface()); return; } - if (strcmp(cmd, "selectinsect") == 0) + if (cmd == "selectinsect") { m_selectInsect = !m_selectInsect; return; } - if (strcmp(cmd, "showsoluce") == 0) + if (cmd == "showsoluce") { m_showSoluce = !m_showSoluce; m_ui->ShowSoluceUpdate(); return; } - if (strcmp(cmd, "allmission") == 0) + if (cmd == "allmission") { m_showAll = !m_showAll; m_ui->AllMissionUpdate(); return; } - if (strcmp(cmd, "invradar") == 0) + if (cmd == "invradar") { m_cheatRadar = !m_cheatRadar; return; } float speed; - if (sscanf(cmd, "speed %f", &speed) > 0) + if (sscanf(cmd.c_str(), "speed %f", &speed) > 0) { SetSpeed(speed); UpdateSpeedLabel(); @@ -1582,9 +1554,13 @@ char* CRobotMain::GetDisplayInfoName(int index) //! Beginning of a dialogue during the game void CRobotMain::StartSuspend() { + if (m_suspend != nullptr) return; // already suspended + if (!IsPhaseWithWorld(m_phase)) return; + GetLogger()->Info("Start suspend\n"); + m_sound->MuteAll(true); ClearInterface(); - m_suspend = m_pause->ActivatePause(PAUSE_ENGINE|PAUSE_HIDE_SHORTCUTS|PAUSE_MUTE_SOUND); + m_suspend = m_pause->ActivatePause(PAUSE_ENGINE | PAUSE_HIDE_SHORTCUTS | PAUSE_MUTE_SOUND | PAUSE_CAMERA); m_engine->SetOverFront(false); // over flat behind CreateShortcuts(); @@ -1592,13 +1568,15 @@ void CRobotMain::StartSuspend() m_infoObject = DeselectAll(); // removes the control buttons m_displayText->HideText(true); - m_suspendInitCamera = m_camera->GetType(); - m_camera->SetType(Gfx::CAM_TYPE_DIALOG); + m_engine->EnablePauseBlur(); } //! End of dialogue during the game void CRobotMain::StopSuspend() { + if (m_suspend == nullptr) return; // not suspended + GetLogger()->Info("Stop suspend\n"); + m_sound->MuteAll(false); ClearInterface(); m_pause->DeactivatePause(m_suspend); @@ -1606,12 +1584,12 @@ void CRobotMain::StopSuspend() m_engine->SetOverFront(true); // over flat front CreateShortcuts(); - if(m_infoObject != nullptr) + if (m_infoObject != nullptr) SelectObject(m_infoObject, false); // gives the command buttons m_map->ShowMap(m_mapShow); m_displayText->HideText(false); - m_camera->SetType(m_suspendInitCamera); + m_engine->DisablePauseBlur(); } @@ -1627,6 +1605,12 @@ void CRobotMain::StartDisplayVisit(EventType event) { if (m_editLock) return; + if (m_visitPause) + { + m_pause->DeactivatePause(m_visitPause); + m_visitPause = nullptr; + } + Ui::CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW2)); if (pw == nullptr) return; @@ -1841,7 +1825,6 @@ void CRobotMain::SelectOneObject(CObject* obj, bool displayError) type == OBJECT_APOLLO2 ) { m_camera->SetType(dynamic_cast(obj)->GetCameraType()); - m_camera->SetDist(dynamic_cast(obj)->GetCameraDist()); } else { @@ -1989,7 +1972,8 @@ CObject* CRobotMain::GetSelect() //! Detects the object aimed by the mouse CObject* CRobotMain::DetectObject(Math::Point pos) { - int objRank = m_engine->DetectObject(pos); + Math::Vector p; + int objRank = m_engine->DetectObject(pos, p); for (CObject* obj : m_objMan->GetAllObjects()) { @@ -2259,7 +2243,9 @@ void CRobotMain::ChangeCamera() ObjectType oType = obj->GetType(); Gfx::CameraType type = controllableObj->GetCameraType(); - if ( oType != OBJECT_MOBILEfa && + if ( oType != OBJECT_HUMAN && + oType != OBJECT_TECH && + oType != OBJECT_MOBILEfa && oType != OBJECT_MOBILEta && oType != OBJECT_MOBILEwa && oType != OBJECT_MOBILEia && @@ -2310,84 +2296,6 @@ void CRobotMain::ChangeCamera() m_camera->SetType(type); } -//! Remote control the camera using the arrow keys -void CRobotMain::KeyCamera(EventType event, InputSlot key) -{ - if (event == EVENT_KEY_UP) - { - if (key == INPUT_SLOT_LEFT) - { - m_cameraPan = 0.0f; - } - - if (key == INPUT_SLOT_RIGHT) - { - m_cameraPan = 0.0f; - } - - if (key == INPUT_SLOT_UP) - { - m_cameraZoom = 0.0f; - } - - if (key == INPUT_SLOT_DOWN) - { - m_cameraZoom = 0.0f; - } - } - - if (m_phase != PHASE_SIMUL) return; - if (m_editLock) return; // current edition? - if (m_trainerPilot) return; - - CObject* obj = GetSelect(); - if (obj == nullptr) return; - assert(obj->Implements(ObjectInterfaceType::Controllable)); - if (!dynamic_cast(obj)->GetTrainer()) return; - - if (event == EVENT_KEY_DOWN) - { - if (key == INPUT_SLOT_LEFT) - { - m_cameraPan = -1.0f; - } - - if (key == INPUT_SLOT_RIGHT) - { - m_cameraPan = 1.0f; - } - - if (key == INPUT_SLOT_UP) - { - m_cameraZoom = -1.0f; - } - - if (key == INPUT_SLOT_DOWN) - { - m_cameraZoom = 1.0f; - } - } -} - -//! Panned with the camera if a button is pressed -void CRobotMain::RemoteCamera(float pan, float zoom, float rTime) -{ - if (pan != 0.0f) - { - float value = m_camera->GetRemotePan(); - value += pan*rTime*1.5f; - m_camera->SetRemotePan(value); - } - - if (zoom != 0.0f) - { - float value = m_camera->GetRemoteZoom(); - value += zoom*rTime*0.3f; - m_camera->SetRemoteZoom(value); - } -} - - //! Cancels the current movie void CRobotMain::AbortMovie() @@ -2404,6 +2312,16 @@ void CRobotMain::AbortMovie() } +std::string TimeFormat(float time) +{ + int minutes = static_cast(floor(time/60)); + double time2 = fmod(time, 60); + double seconds; + double fraction = modf(time2, &seconds)*100; + std::ostringstream sstream; + sstream << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << floor(seconds) << "." << std::setfill('0') << std::setw(2) << floor(fraction); + return sstream.str(); +} //! Updates the text information void CRobotMain::UpdateInfoText() @@ -2763,14 +2681,14 @@ void CRobotMain::ScenePerso() m_lightMan->FlushLights(); m_particle->FlushParticle(); - SetLevel(LevelCategory::Perso, 0, 0); + m_levelFile = "levels/other/perso000.txt"; try { CreateScene(false, true, false); // sets scene } catch (const std::runtime_error& e) { - LevelLoadingError("An error occured while trying to load apperance scene", e, PHASE_PLAYER_SELECT); + LevelLoadingError("An error occurred while trying to load apperance scene", e, PHASE_PLAYER_SELECT); } m_engine->SetDrawWorld(false); // does not draw anything on the interface @@ -2814,46 +2732,27 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_displayText->SetEnable(true); m_immediatSatCom = false; m_lockedSatCom = false; - m_endingWinRank = 0; - m_endingLostRank = 0; + m_endingWin = ""; + m_endingLost = ""; m_audioChange.clear(); m_endTake.clear(); + m_endTakeImmediat = false; m_endTakeResearch = 0; m_endTakeWinDelay = 2.0f; m_endTakeLostDelay = 2.0f; m_globalMagnifyDamage = 1.0f; - m_obligatoryTotal = 0; - m_prohibitedTotal = 0; + m_obligatoryTokens.clear(); m_mapShow = true; m_mapImage = false; m_mapFilename[0] = 0; m_controller = nullptr; - m_colorRefBot.r = 10.0f/256.0f; - m_colorRefBot.g = 166.0f/256.0f; - m_colorRefBot.b = 254.0f/256.0f; // blue - m_colorRefBot.a = 0.0f; m_colorNewBot.clear(); - m_colorNewBot[0] = m_colorRefBot; - - m_colorRefAlien.r = 135.0f/256.0f; - m_colorRefAlien.g = 170.0f/256.0f; - m_colorRefAlien.b = 13.0f/256.0f; // green - m_colorRefAlien.a = 0.0f; - m_colorNewAlien = m_colorRefAlien; - - m_colorRefGreen.r = 135.0f/256.0f; - m_colorRefGreen.g = 170.0f/256.0f; - m_colorRefGreen.b = 13.0f/256.0f; // green - m_colorRefGreen.a = 0.0f; - m_colorNewGreen = m_colorRefGreen; - - m_colorRefWater.r = 25.0f/256.0f; - m_colorRefWater.g = 255.0f/256.0f; - m_colorRefWater.b = 240.0f/256.0f; // cyan - m_colorRefWater.a = 0.0f; - m_colorNewWater = m_colorRefWater; + m_colorNewBot[0] = COLOR_REF_BOT; + m_colorNewAlien = COLOR_REF_ALIEN; + m_colorNewGreen = COLOR_REF_GREEN; + m_colorNewWater = COLOR_REF_WATER; m_engine->SetAmbientColor(Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f), 0); m_engine->SetAmbientColor(Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f), 1); @@ -2876,9 +2775,10 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_teamNames.clear(); m_missionResult = ERR_MISSION_NOTERM; + m_missionResultFromScript = false; } - //NOTE: Reset timer always, even when only resetting object positions + // NOTE: Reset timer always, even when only resetting object positions m_missionTimerEnabled = false; m_missionTimerStarted = false; m_missionTimer = 0.0f; @@ -2890,10 +2790,18 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) Gfx::Color backgroundCloudDown = Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f); bool backgroundFull = false; + auto LoadingWarning = [&](const std::string& message) + { + GetLogger()->Warn("%s\n", message.c_str()); + m_ui->GetDialog()->StartInformation("Level loading warning", "This level contains problems. It may stop working in future versions of the game.", message); + }; + try { m_ui->GetLoadingScreen()->SetProgress(0.05f, RT_LOADING_PROCESSING); - CLevelParser levelParser(m_levelCategory, m_levelChap, m_levelRank); + GetLogger()->Info("Loading level: %s\n", m_levelFile.c_str()); + CLevelParser levelParser(m_levelFile); + levelParser.SetLevelPaths(m_levelCategory, m_levelChap, m_levelRank); levelParser.Load(); int numObjects = levelParser.CountLines("CreateObject"); m_ui->GetLoadingScreen()->SetProgress(0.1f, RT_LOADING_LEVEL_SETTINGS); @@ -2901,11 +2809,6 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) int rankObj = 0; CObject* sel = nullptr; - /* - * NOTE: Moving frequently used lines to the top - * may speed up loading - */ - for (auto& line : levelParser.GetLines()) { if (line->GetCommand() == "Title" && !resetObject) @@ -2967,9 +2870,38 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) if (line->GetCommand() == "EndingFile" && !resetObject) { - // NOTE: The old default was 0, but I think -1 is more correct - 0 means "ending file 000", while -1 means "no ending file" - m_endingWinRank = line->GetParam("win")->AsInt(-1); - m_endingLostRank = line->GetParam("lost")->AsInt(-1); + auto Process = [&](const std::string& type) -> std::string + { + if (line->GetParam(type)->IsDefined()) + { + try + { + int rank = boost::lexical_cast(line->GetParam(type)->GetValue()); + if (rank >= 0) + { + // TODO: Fix default levels and add a future removal warning + GetLogger()->Warn("This level is using deprecated way of defining %1$s scene. Please change the %1$s= parameter in EndingFile from %2$d to \"levels/other/%1$s%2$03d.txt\".\n", type.c_str(), rank); + std::stringstream ss; + ss << "levels/other/" << type << std::setfill('0') << std::setw(3) << rank << ".txt"; + return ss.str(); + } + else + { + // TODO: Fix default levels and add a future removal warning + GetLogger()->Warn("This level is using deprecated way of defining %1$s scene. Please remove the %1$s= parameter in EndingFile.\n", type.c_str()); + return ""; + } + + } + catch (boost::bad_lexical_cast &e) + { + return line->GetParam(type)->AsPath("levels"); + } + } + return ""; + }; + m_endingWin = Process("win"); + m_endingLost = Process("lost"); continue; } @@ -3005,17 +2937,22 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) continue; } - if (line->GetCommand() == "AudioChange" && !resetObject && m_controller == nullptr) + if (line->GetCommand() == "AudioChange" && !resetObject) { auto audioChange = MakeUnique(); audioChange->Read(line.get()); m_ui->GetLoadingScreen()->SetProgress(0.15f, RT_LOADING_MUSIC, audioChange->music); m_sound->CacheMusic(audioChange->music); m_audioChange.push_back(std::move(audioChange)); + + if (!line->GetParam("pos")->IsDefined() || !line->GetParam("dist")->IsDefined()) + { + LoadingWarning("The defaults for pos= and dist= are going to change, specify them explicitly. See issue #759 (https://git.io/vVBzH)"); + } continue; } - if (line->GetCommand() == "Audio" && !resetObject && m_controller == nullptr) + if (line->GetCommand() == "Audio" && !resetObject) { if (line->GetParam("track")->IsDefined()) { @@ -3256,7 +3193,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) line->GetParam("level")->AsFloat(100.0f)*g_unit, line->GetParam("glint")->AsFloat(1.0f), pos); - m_colorNewWater = line->GetParam("color")->AsColor(m_colorRefWater); + m_colorNewWater = line->GetParam("color")->AsColor(COLOR_REF_WATER); m_colorShiftWater = line->GetParam("brightness")->AsFloat(0.0f); continue; } @@ -3416,6 +3353,11 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) if (line->GetCommand() == "LevelController" && m_sceneReadPath.empty()) { + if (m_controller != nullptr) + { + throw CLevelParserException("There can be only one LevelController in the level"); + } + m_controller = m_objMan->CreateObject(Math::Vector(0.0f, 0.0f, 0.0f), 0.0f, OBJECT_CONTROLLER); assert(m_controller->Implements(ObjectInterfaceType::Programmable)); assert(m_controller->Implements(ObjectInterfaceType::ProgramStorage)); @@ -3626,49 +3568,61 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) if (line->GetParam("fadeIn")->AsBool(false)) m_camera->StartOver(Gfx::CAM_OVER_EFFECT_FADEIN_WHITE, Math::Vector(0.0f, 0.0f, 0.0f), 1.0f); - - m_camera->SetFixDirectionH(line->GetParam("fixDirection")->AsFloat(0.25f)*Math::PI); continue; } - if (line->GetCommand() == "EndMissionTake" && !resetObject && m_controller == nullptr) + if (line->GetCommand() == "EndMissionTake" && !resetObject) { auto endTake = MakeUnique(); endTake->Read(line.get()); + if (endTake->immediat) + m_endTakeImmediat = true; m_endTake.push_back(std::move(endTake)); + + if (!line->GetParam("pos")->IsDefined() || !line->GetParam("dist")->IsDefined()) + { + LoadingWarning("The defaults for pos= and dist= are going to change, specify them explicitly. See issue #759 (https://git.io/vVBzH)"); + } continue; } - if (line->GetCommand() == "EndMissionDelay" && !resetObject && m_controller == nullptr) + if (line->GetCommand() == "EndMissionDelay" && !resetObject) { m_endTakeWinDelay = line->GetParam("win")->AsFloat(2.0f); m_endTakeLostDelay = line->GetParam("lost")->AsFloat(2.0f); continue; } - if (line->GetCommand() == "EndMissionResearch" && !resetObject && m_controller == nullptr) //TODO: Is this used anywhere? + if (line->GetCommand() == "EndMissionResearch" && !resetObject) // This is not used in any original Colobot levels, but we'll keep it for userlevel creators { m_endTakeResearch |= line->GetParam("type")->AsResearchFlag(); continue; } - if (line->GetCommand() == "ObligatoryToken" && !resetObject) //NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises? + if (line->GetCommand() == "ObligatoryToken" && !resetObject) { - int i = m_obligatoryTotal; - if (i < 100) //TODO: remove the limit + std::string token = line->GetParam("text")->AsString(); + if (!line->GetParam("min")->IsDefined() && !line->GetParam("max")->IsDefined()) + GetLogger()->Warn("ObligatoryToken without specifying min/max is provided only for backwards compatibility - instead, do this: ObligatoryToken text=\"%s\" min=1\n", token.c_str()); + if (m_obligatoryTokens.count(token)) + throw CLevelParserException("Incorrect ObligatoryToken specification - you cannot define a token twice"); + + m_obligatoryTokens[token].min = line->GetParam("min")->AsInt(line->GetParam("max")->IsDefined() ? -1 : 1); // BACKWARDS COMPATIBILITY: if neither min or max are defined, default to min=1 + m_obligatoryTokens[token].max = line->GetParam("max")->AsInt(-1); + if (m_obligatoryTokens[token].min >= 0 && m_obligatoryTokens[token].max >= 0 && m_obligatoryTokens[token].min > m_obligatoryTokens[token].max) { - strcpy(m_obligatoryToken[i], line->GetParam("text")->AsString().c_str()); - m_obligatoryTotal ++; + throw CLevelParserException("Incorrect ObligatoryToken specification - min cannot be greater than max"); } continue; } - if (line->GetCommand() == "ProhibitedToken" && !resetObject) //NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises? + if (line->GetCommand() == "ProhibitedToken" && !resetObject) // NOTE: Kept only for backwards compatibility { - int i = m_prohibitedTotal; - if (i < 100) //TODO: remove the limit - { - strcpy(m_prohibitedToken[i], line->GetParam("text")->AsString().c_str()); - m_prohibitedTotal ++; - } + std::string token = line->GetParam("text")->AsString(); + GetLogger()->Warn("ProhibitedToken is only provided for backwards compatibility - instead, do this: ObligatoryToken text=\"%s\" max=0\n", token.c_str()); + if (m_obligatoryTokens.count(token)) + throw CLevelParserException("Incorrect ObligatoryToken specification - you cannot define a token twice"); + + m_obligatoryTokens[token].min = -1; + m_obligatoryTokens[token].max = 0; continue; } @@ -3779,7 +3733,6 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) { Math::Vector pos = sel->GetPosition(); m_camera->Init(pos, pos, 0.0f); - m_camera->FixCamera(); SelectObject(sel); m_camera->SetControllingObject(sel); @@ -3958,26 +3911,26 @@ void CRobotMain::ChangeColor() // VehicleColor - for(auto it : m_colorNewBot) + for (auto it : m_colorNewBot) { int team = it.first; Gfx::Color newColor = it.second; std::string teamStr = StrUtils::ToString(team); if(team == 0) teamStr = ""; - m_engine->ChangeTextureColor("textures/objects/base1.png"+teamStr, "textures/objects/base1.png", m_colorRefBot, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); - m_engine->ChangeTextureColor("textures/objects/convert.png"+teamStr, "textures/objects/convert.png", m_colorRefBot, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); - m_engine->ChangeTextureColor("textures/objects/derrick.png"+teamStr, "textures/objects/derrick.png", m_colorRefBot, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); - m_engine->ChangeTextureColor("textures/objects/factory.png"+teamStr, "textures/objects/factory.png", m_colorRefBot, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); - m_engine->ChangeTextureColor("textures/objects/lemt.png"+teamStr, "textures/objects/lemt.png", m_colorRefBot, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); - m_engine->ChangeTextureColor("textures/objects/roller.png"+teamStr, "textures/objects/roller.png", m_colorRefBot, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); - m_engine->ChangeTextureColor("textures/objects/search.png"+teamStr, "textures/objects/search.png", m_colorRefBot, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); + m_engine->ChangeTextureColor("textures/objects/base1.png"+teamStr, "textures/objects/base1.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); + m_engine->ChangeTextureColor("textures/objects/convert.png"+teamStr, "textures/objects/convert.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); + m_engine->ChangeTextureColor("textures/objects/derrick.png"+teamStr, "textures/objects/derrick.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); + m_engine->ChangeTextureColor("textures/objects/factory.png"+teamStr, "textures/objects/factory.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); + m_engine->ChangeTextureColor("textures/objects/lemt.png"+teamStr, "textures/objects/lemt.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); + m_engine->ChangeTextureColor("textures/objects/roller.png"+teamStr, "textures/objects/roller.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); + m_engine->ChangeTextureColor("textures/objects/search.png"+teamStr, "textures/objects/search.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); exclu[0] = Math::Point( 0.0f/256.0f, 160.0f/256.0f); exclu[1] = Math::Point(256.0f/256.0f, 256.0f/256.0f); // pencils exclu[2] = Math::Point(0.0f, 0.0f); exclu[3] = Math::Point(0.0f, 0.0f); // terminator - m_engine->ChangeTextureColor("textures/objects/drawer.png"+teamStr, "textures/objects/drawer.png", m_colorRefBot, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, exclu, 0, true); + m_engine->ChangeTextureColor("textures/objects/drawer.png"+teamStr, "textures/objects/drawer.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, exclu, 0, true); exclu[0] = Math::Point(237.0f/256.0f, 176.0f/256.0f); exclu[1] = Math::Point(256.0f/256.0f, 220.0f/256.0f); // blue canister @@ -3985,7 +3938,7 @@ void CRobotMain::ChangeColor() exclu[3] = Math::Point(130.0f/256.0f, 214.0f/256.0f); // safe location exclu[4] = Math::Point(0.0f, 0.0f); exclu[5] = Math::Point(0.0f, 0.0f); // terminator - m_engine->ChangeTextureColor("textures/objects/subm.png"+teamStr, "textures/objects/subm.png", m_colorRefBot, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, exclu, 0, true); + m_engine->ChangeTextureColor("textures/objects/subm.png"+teamStr, "textures/objects/subm.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, exclu, 0, true); } // AlienColor @@ -3994,23 +3947,23 @@ void CRobotMain::ChangeColor() exclu[1] = Math::Point(256.0f/256.0f, 256.0f/256.0f); // SatCom exclu[2] = Math::Point(0.0f, 0.0f); exclu[3] = Math::Point(0.0f, 0.0f); // terminator - m_engine->ChangeTextureColor("textures/objects/ant.png", m_colorRefAlien, m_colorNewAlien, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti, exclu); - m_engine->ChangeTextureColor("textures/objects/mother.png", m_colorRefAlien, m_colorNewAlien, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti); + m_engine->ChangeTextureColor("textures/objects/ant.png", COLOR_REF_ALIEN, m_colorNewAlien, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti, exclu); + m_engine->ChangeTextureColor("textures/objects/mother.png", COLOR_REF_ALIEN, m_colorNewAlien, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti); // GreeneryColor - m_engine->ChangeTextureColor("textures/objects/plant.png", m_colorRefGreen, m_colorNewGreen, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti); + m_engine->ChangeTextureColor("textures/objects/plant.png", COLOR_REF_GREEN, m_colorNewGreen, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti); // water color // PARTIPLOUF0 and PARTIDROP : ts = Math::Point(0.500f, 0.500f); ti = Math::Point(0.875f, 0.750f); - m_engine->ChangeTextureColor("textures/effect00.png", m_colorRefWater, m_colorNewWater, colorRef2, colorNew2, 0.20f, -1.0f, ts, ti, nullptr, m_colorShiftWater, true); + m_engine->ChangeTextureColor("textures/effect00.png", COLOR_REF_WATER, m_colorNewWater, colorRef2, colorNew2, 0.20f, -1.0f, ts, ti, nullptr, m_colorShiftWater, true); // PARTIFLIC : ts = Math::Point(0.00f, 0.75f); ti = Math::Point(0.25f, 1.00f); - m_engine->ChangeTextureColor("textures/effect02.png", m_colorRefWater, m_colorNewWater, colorRef2, colorNew2, 0.20f, -1.0f, ts, ti, nullptr, m_colorShiftWater, true); + m_engine->ChangeTextureColor("textures/effect02.png", COLOR_REF_WATER, m_colorNewWater, colorRef2, colorNew2, 0.20f, -1.0f, ts, ti, nullptr, m_colorShiftWater, true); } //! Calculates the distance to the nearest object @@ -4535,33 +4488,6 @@ void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std:: if (obj->Implements(ObjectInterfaceType::Old)) { - COldObject* oldObj = dynamic_cast(obj); - - for (int i = 1; i < OBJECTMAXPART; i++) - { - if (oldObj->GetObjectRank(i) == -1) continue; - - Math::Vector pos = oldObj->GetPartPosition(i); - if (pos.x != 0.0f || pos.y != 0.0f || pos.z != 0.0f) - { - pos /= g_unit; - line->AddParam("p" + boost::lexical_cast(i), MakeUnique(pos)); - } - - Math::Vector rot = oldObj->GetPartRotation(i); - if (rot.x != 0.0f || rot.y != 0.0f || rot.z != 0.0f) - { - rot /= (Math::PI/180.0f); - line->AddParam("a" + boost::lexical_cast(i), MakeUnique(rot)); - } - - Math::Vector scale = oldObj->GetPartScale(i); - if (scale.x != 1.0f || scale.y != 1.0f || scale.z != 1.0f) - { - line->AddParam("z" + boost::lexical_cast(i), MakeUnique(scale)); - } - } - line->AddParam("option", MakeUnique(obj->GetOption())); } @@ -4582,7 +4508,7 @@ void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std:: if (obj->Implements(ObjectInterfaceType::ProgramStorage)) { CProgramStorageObject* programStorage = dynamic_cast(obj); - if(programStorage->GetProgramStorageIndex() >= 0) + if (programStorage->GetProgramStorageIndex() >= 0) { programStorage->SaveAllProgramsForSavedScene(line, programDir); } @@ -4634,7 +4560,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s line = MakeUnique("Created"); - line->AddParam("date", MakeUnique(GetCurrentTimestamp())); + line->AddParam("date", MakeUnique(static_cast(time(nullptr)))); levelParser.AddLine(std::move(line)); line = MakeUnique("Mission"); @@ -4778,32 +4704,8 @@ CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const std::string& pro if (obj->Implements(ObjectInterfaceType::Old)) { COldObject* oldObj = dynamic_cast(obj); - oldObj->SetPosition(line->GetParam("pos")->AsPoint() * g_unit); oldObj->SetRotation(line->GetParam("angle")->AsPoint() * Math::DEG_TO_RAD); - - for (int i = 1; i < OBJECTMAXPART; i++) - { - if (oldObj->GetObjectRank(i) == -1) continue; - - Math::Vector pos = line->GetParam(std::string("p")+boost::lexical_cast(i))->AsPoint(Math::Vector()); - if (pos.x != 0.0f || pos.y != 0.0f || pos.z != 0.0f) - { - oldObj->SetPartPosition(i, pos*g_unit); - } - - Math::Vector dir = line->GetParam(std::string("a")+boost::lexical_cast(i))->AsPoint(Math::Vector()); - if (dir.x != 0.0f || dir.y != 0.0f || dir.z != 0.0f) - { - oldObj->SetPartRotation(i, dir*(Math::PI/180.0f)); - } - - Math::Vector zoom = line->GetParam(std::string("z")+boost::lexical_cast(i))->AsPoint(Math::Vector()); - if (zoom.x != 0.0f || zoom.y != 0.0f || zoom.z != 0.0f) - { - oldObj->SetPartScale(i, zoom); - } - } } if (obj->GetType() == OBJECT_BASE) m_base = obj; @@ -4821,7 +4723,7 @@ CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const std::string& pro if (obj->Implements(ObjectInterfaceType::ProgramStorage)) { CProgramStorageObject* programStorage = dynamic_cast(obj); - if (!line->GetParam("programStorageIndex")->IsDefined()) // Backwards combatibility + if (!line->GetParam("programStorageIndex")->IsDefined()) // Backwards compatibility programStorage->SetProgramStorageIndex(objRank); programStorage->LoadAllProgramsForSavedScene(line, programDir); } @@ -4978,7 +4880,7 @@ void CRobotMain::ResetCreate() m_particle->FlushParticle(); m_terrain->FlushBuildingLevel(); - m_camera->SetType(Gfx::CAM_TYPE_DIALOG); + m_camera->SetType(Gfx::CAM_TYPE_NULL); try { @@ -4994,7 +4896,7 @@ void CRobotMain::ResetCreate() } catch (const std::runtime_error& e) { - LevelLoadingError("An error occured while trying to reset scene", e); + LevelLoadingError("An error occurred while trying to reset scene", e); } } @@ -5014,17 +4916,16 @@ void CRobotMain::UpdateAudio(bool frame) } } -void CRobotMain::SetEndMission(Error result, float delay) +//! Set mission result from LevelController script +void CRobotMain::SetMissionResultFromScript(Error result, float delay) { - if (m_controller != nullptr) - { - m_endTakeWinDelay = delay; - m_endTakeLostDelay = delay; - m_missionResult = result; - } + m_endTakeWinDelay = delay; + m_endTakeLostDelay = delay; + m_missionResult = result; + m_missionResultFromScript = true; } -Error CRobotMain::CheckEndMissionForGroup(std::vector& endTakes) +Error CRobotMain::ProcessEndMissionTakeForGroup(std::vector& endTakes) { Error finalResult = ERR_OK; bool hasWinningConditions = false; @@ -5051,106 +4952,109 @@ Error CRobotMain::CheckEndMissionForGroup(std::vector& endT return finalResult; } -//! Checks if the mission is over -Error CRobotMain::CheckEndMission(bool frame) +//! Process EndMissionTake commands, result is stored in m_missionResult +//! If return value is different than ERR_MISSION_NOTERM, assume the mission is finished and pass on the result +Error CRobotMain::ProcessEndMissionTake() { - bool isImmediat = false; - // Process EndMissionTake, unless we are using MissionController - if (m_controller == nullptr) + // Sort end conditions by teams + std::map> teams; + for (std::unique_ptr& endTake : m_endTake) + teams[endTake->winTeam].push_back(endTake.get()); + + int teamCount = 0; + bool usesTeamConditions = false; + for (auto it : teams) { - // Sort end conditions by teams - std::map> teams; - for (std::unique_ptr& endTake : m_endTake) - { - teams[endTake->winTeam].push_back(endTake.get()); - if(endTake->immediat) - isImmediat = true; - } + int team = it.first; + if (team == 0) continue; + usesTeamConditions = true; + if (!m_objMan->TeamExists(team)) continue; + teamCount++; + } - int teamCount = 0; - bool usesTeamConditions = false; - for (auto it : teams) - { - int team = it.first; - if(team == 0) continue; - usesTeamConditions = true; - if(!m_objMan->TeamExists(team)) continue; - teamCount++; - } + if (!usesTeamConditions) + { + m_missionResult = ProcessEndMissionTakeForGroup(teams[0]); + } + else + { + // Special handling for teams + m_missionResult = ERR_MISSION_NOTERM; - if (!usesTeamConditions) + if (teamCount == 0) { - m_missionResult = CheckEndMissionForGroup(teams[0]); + GetLogger()->Info("All teams died, mission ended with failure\n"); + m_missionResult = INFO_LOST; } else { - // Special handling for teams - m_missionResult = ERR_MISSION_NOTERM; + for (auto it : teams) + { + int team = it.first; + if (team == 0) continue; + if (!m_objMan->TeamExists(team)) continue; - if (teamCount == 0) - { - GetLogger()->Info("All teams died, mission ended with failure\n"); - m_missionResult = INFO_LOST; - } - else - { - for (auto it : teams) + Error result = ProcessEndMissionTakeForGroup(it.second); + if (result == INFO_LOST || result == INFO_LOSTq) { - int team = it.first; - if (team == 0) continue; - if (!m_objMan->TeamExists(team)) continue; + GetLogger()->Info("Team %d lost\n", team); + m_displayText->DisplayText(("<<< Team "+boost::lexical_cast(team)+" lost! >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_ERROR); - Error result = CheckEndMissionForGroup(it.second); - if (result == INFO_LOST || result == INFO_LOSTq) - { - GetLogger()->Info("Team %d lost\n", team); - m_displayText->DisplayText(("<<< Team "+boost::lexical_cast(team)+" lost! >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_ERROR); - - m_displayText->SetEnable(false); // To prevent "bot destroyed" messages - m_objMan->DestroyTeam(team); - m_displayText->SetEnable(true); - } - else if(result == ERR_OK) - { - if (m_winDelay == 0.0f) - { - GetLogger()->Info("Team %d won\n", team); - - m_displayText->DisplayText(("<<< Team "+boost::lexical_cast(team)+" won the game >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f)); - if (m_missionTimerEnabled && m_missionTimerStarted) - { - GetLogger()->Info("Mission time: %s\n", TimeFormat(m_missionTimer).c_str()); - m_displayText->DisplayText(("Time: " + TimeFormat(m_missionTimer)).c_str(), Math::Vector(0.0f,0.0f,0.0f)); - } - m_missionTimerEnabled = m_missionTimerStarted = false; - m_winDelay = m_endTakeWinDelay; // wins in two seconds - m_lostDelay = 0.0f; - if (m_exitAfterMission) - m_eventQueue->AddEvent(Event(EVENT_QUIT)); - m_displayText->SetEnable(false); - } - m_missionResult = ERR_OK; - return ERR_OK; - } + m_displayText->SetEnable(false); // To prevent "bot destroyed" messages + m_objMan->DestroyTeam(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])) + else if (result == ERR_OK) { - m_missionResult = ERR_MISSION_NOTERM; + if (m_winDelay == 0.0f) + { + GetLogger()->Info("Team %d won\n", team); + + m_displayText->DisplayText(("<<< Team "+boost::lexical_cast(team)+" won the game >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f)); + if (m_missionTimerEnabled && m_missionTimerStarted) + { + GetLogger()->Info("Mission time: %s\n", TimeFormat(m_missionTimer).c_str()); + m_displayText->DisplayText(("Time: " + TimeFormat(m_missionTimer)).c_str(), Math::Vector(0.0f,0.0f,0.0f)); + } + m_missionTimerEnabled = m_missionTimerStarted = false; + m_winDelay = m_endTakeWinDelay; // wins in two seconds + m_lostDelay = 0.0f; + m_displayText->SetEnable(false); + } + m_missionResult = ERR_OK; + return ERR_OK; } } } } + 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; + } + } + } + + return ERR_MISSION_NOTERM; +} + +//! Checks if the mission is over +Error CRobotMain::CheckEndMission(bool frame) +{ + // Process EndMissionTake, unless we are using LevelController script for processing ending conditions + if (!m_missionResultFromScript) + { + Error result = ProcessEndMissionTake(); + if (result != ERR_MISSION_NOTERM) return result; + } + // Take action depending on m_missionResult - if(m_missionResult == INFO_LOSTq) + if (m_missionResult == INFO_LOSTq) { if (m_lostDelay == 0.0f) { @@ -5159,12 +5063,10 @@ Error CRobotMain::CheckEndMission(bool frame) } m_missionTimerEnabled = m_missionTimerStarted = false; m_displayText->SetEnable(false); - if (m_exitAfterMission) - m_eventQueue->AddEvent(Event(EVENT_QUIT)); return INFO_LOSTq; } - if(m_missionResult == INFO_LOST) + if (m_missionResult == INFO_LOST) { if (m_lostDelay == 0.0f) { @@ -5174,8 +5076,6 @@ Error CRobotMain::CheckEndMission(bool frame) } m_missionTimerEnabled = m_missionTimerStarted = false; m_displayText->SetEnable(false); - if (m_exitAfterMission) - m_eventQueue->AddEvent(Event(EVENT_QUIT)); return INFO_LOST; } @@ -5187,14 +5087,12 @@ Error CRobotMain::CheckEndMission(bool frame) m_lostDelay = 0.0f; m_missionTimerEnabled = m_missionTimerStarted = false; m_displayText->SetEnable(false); - if (m_exitAfterMission) - m_eventQueue->AddEvent(Event(EVENT_QUIT)); return ERR_OK; // mission ended } if (frame) { - if(m_base != nullptr && !isImmediat) + if (m_base != nullptr && !m_endTakeImmediat) { assert(m_base->Implements(ObjectInterfaceType::Controllable)); if(dynamic_cast(m_base)->GetSelectable()) @@ -5214,8 +5112,6 @@ Error CRobotMain::CheckEndMission(bool frame) m_winDelay = m_endTakeWinDelay; // wins in two seconds m_lostDelay = 0.0f; } - if (m_exitAfterMission) - m_eventQueue->AddEvent(Event(EVENT_QUIT)); m_displayText->SetEnable(false); return ERR_OK; // mission ended } @@ -5227,41 +5123,12 @@ Error CRobotMain::CheckEndMission(bool frame) } -//! Returns the number of instructions required -int CRobotMain::GetObligatoryToken() +//! Returns the list instructions required in CBot program in level +const std::map& CRobotMain::GetObligatoryTokenList() { - return m_obligatoryTotal; + return m_obligatoryTokens; } -//! Returns the name of a required instruction -char* CRobotMain::GetObligatoryToken(int i) -{ - return m_obligatoryToken[i]; -} - -//! Checks if an instruction is part of the obligatory list -int CRobotMain::IsObligatoryToken(const char* token) -{ - for (int i = 0; i < m_obligatoryTotal; i++) - { - if (strcmp(token, m_obligatoryToken[i]) == 0) - return i; - } - return -1; -} - -//! Checks if an instruction is not part of the banned list -bool CRobotMain::IsProhibitedToken(const char* token) -{ - for (int i = 0; i < m_prohibitedTotal; i++) - { - if (strcmp(token, m_prohibitedToken[i]) == 0) - return false; - } - return true; -} - - //! Indicates whether it is possible to control a driving robot bool CRobotMain::GetTrainerPilot() { @@ -5348,9 +5215,11 @@ float CRobotMain::GetPersoAngle() void CRobotMain::SetLevel(LevelCategory cat, int chap, int rank) { + GetLogger()->Debug("Change level to %s %d %d\n", GetLevelCategoryDir(cat).c_str(), chap, rank); m_levelCategory = cat; m_levelChap = chap; m_levelRank = rank; + m_levelFile = CLevelParser::BuildScenePath(m_levelCategory, m_levelChap, m_levelRank); } LevelCategory CRobotMain::GetLevelCategory() @@ -5536,6 +5405,7 @@ void CRobotMain::StartMusic() void CRobotMain::UpdatePause(PauseType pause) { m_engine->SetPause(pause & PAUSE_ENGINE); + m_camera->SetFreeze(pause & PAUSE_CAMERA); m_sound->MuteAll(pause & PAUSE_MUTE_SOUND); CreateShortcuts(); if (pause != PAUSE_NONE) HiliteClear(); @@ -5613,7 +5483,6 @@ void CRobotMain::SetAutosave(bool enable) m_autosave = enable; m_autosaveLast = m_gameTimeAbsolute; - AutosaveRotate(false); } bool CRobotMain::GetAutosave() @@ -5639,7 +5508,6 @@ void CRobotMain::SetAutosaveSlots(int slots) if (m_autosaveSlots == slots) return; m_autosaveSlots = slots; - AutosaveRotate(false); } int CRobotMain::GetAutosaveSlots() @@ -5647,84 +5515,40 @@ int CRobotMain::GetAutosaveSlots() return m_autosaveSlots; } -int CRobotMain::AutosaveRotate(bool freeOne) +// Remove oldest saves with autosave prefix +void CRobotMain::AutosaveRotate() { if (m_playerProfile == nullptr) - return 0; + return; GetLogger()->Debug("Rotate autosaves...\n"); - // Find autosave dirs auto saveDirs = CResourceManager::ListDirectories(m_playerProfile->GetSaveDir()); - std::map autosaveDirs; - for (auto& dir : saveDirs) + const std::string autosavePrefix = "autosave"; + std::vector autosaves; + std::copy_if(saveDirs.begin(), saveDirs.end(), std::back_inserter(autosaves), [&](const std::string &save) { - try - { - const std::string autosavePrefix = "autosave"; - if (dir.substr(0, autosavePrefix.length()) == autosavePrefix) - { - int id = boost::lexical_cast(dir.substr(autosavePrefix.length())); - autosaveDirs[id] = m_playerProfile->GetSaveFile(dir); - } - } - catch (...) - { - GetLogger()->Info("Bad autosave found: %s\n", dir.c_str()); - // skip - } - } - if (autosaveDirs.size() == 0) return 1; + return save.substr(0, autosavePrefix.length()) == autosavePrefix; + }); - // Remove all but last m_autosaveSlots - std::map autosavesToKeep; - int last_id = autosaveDirs.rbegin()->first; - int count = 0; - int to_keep = m_autosaveSlots-(freeOne ? 1 : 0); - int new_last_id = Math::Min(autosaveDirs.size(), to_keep); - bool rotate = false; - for (int i = last_id; i > 0; i--) + std::sort(autosaves.begin(), autosaves.end(), std::less()); + for (int i = 0; i < static_cast(autosaves.size()) - m_autosaveSlots + 1; i++) { - if (autosaveDirs.count(i) > 0) - { - count++; - if (count > m_autosaveSlots-(freeOne ? 1 : 0) || !m_autosave) - { - GetLogger()->Trace("Remove %s\n", autosaveDirs[i].c_str()); - CResourceManager::RemoveDirectory(autosaveDirs[i]); - rotate = true; - } - else - { - GetLogger()->Trace("Keep %s\n", autosaveDirs[i].c_str()); - autosavesToKeep[new_last_id-count+1] = autosaveDirs[i]; - } - } + CResourceManager::RemoveDirectory(m_playerProfile->GetSaveDir() + "/" + autosaves[i]); } - - // Rename autosaves that we kept - if (rotate) - { - for (auto& save : autosavesToKeep) - { - std::string newDir = m_playerProfile->GetSaveFile("autosave" + boost::lexical_cast(save.first)); - GetLogger()->Trace("Rename %s -> %s\n", save.second.c_str(), newDir.c_str()); - CResourceManager::Move(save.second, newDir); - } - } - - return rotate ? count : count+1; } void CRobotMain::Autosave() { - int id = AutosaveRotate(true); + AutosaveRotate(); GetLogger()->Info("Autosave!\n"); - std::string dir = m_playerProfile->GetSaveFile("autosave" + boost::lexical_cast(id)); - char timestr[100]; - TimeToAscii(time(nullptr), timestr); - std::string info = std::string("[AUTOSAVE] ")+timestr; + char infostr[100]; + time_t now = time(nullptr); + strftime(timestr, 99, "%y%m%d%H%M%S", localtime(&now)); + strftime(infostr, 99, "%y.%m.%d %H:%M", localtime(&now)); + std::string info = std::string("[AUTOSAVE] ") + infostr; + std::string dir = m_playerProfile->GetSaveFile(std::string("autosave") + timestr); m_playerProfile->SaveScene(dir, info); } @@ -6010,9 +5834,6 @@ void CRobotMain::SetCodeBattleSpectatorMode(bool mode) m_codeBattleSpectator = mode; SelectObject(obj, false); // this uses code battle selection mode already - - if (mode) - m_camera->SetFixDirectionV(-0.25f*Math::PI); } void CRobotMain::UpdateDebugCrashSpheres() @@ -6032,3 +5853,13 @@ void CRobotMain::UpdateDebugCrashSpheres() } } } + +void CRobotMain::SetDebugCrashSpheres(bool draw) +{ + m_debugCrashSpheres = draw; +} + +bool CRobotMain::GetDebugCrashSpheres() +{ + return m_debugCrashSpheres; +} diff --git a/src/level/robotmain.h b/src/level/robotmain.h index 991c97ce..18649c0e 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -113,6 +113,7 @@ class CMainMap; class CInterface; class CDisplayText; class CDisplayInfo; +class CDebugMenu; } struct NewScriptName @@ -140,6 +141,12 @@ struct ShowLimit float time = 0.0f; }; +struct MinMax +{ + int min = -1; + int max = -1; +}; + const int SATCOM_HUSTON = 0; const int SATCOM_SAT = 1; @@ -161,9 +168,6 @@ public: Ui::CDisplayText* GetDisplayText(); CPauseManager* GetPauseManager(); - void ResetAfterVideoConfigChanged(); - void ReloadAllTextures(); - void ChangePhase(Phase phase); bool ProcessEvent(Event &event); Phase GetPhase(); @@ -197,13 +201,11 @@ public: void ResetObject(); void UpdateAudio(bool frame); - void SetEndMission(Error result, float delay); + void SetMissionResultFromScript(Error result, float delay); Error CheckEndMission(bool frame); - Error CheckEndMissionForGroup(std::vector& endTakes); - int GetObligatoryToken(); - char* GetObligatoryToken(int i); - int IsObligatoryToken(const char* token); - bool IsProhibitedToken(const char* token); + Error ProcessEndMissionTake(); + Error ProcessEndMissionTakeForGroup(std::vector& endTakes); + const std::map& GetObligatoryTokenList(); void UpdateMap(); bool GetShowMap(); @@ -364,6 +366,10 @@ public: bool IsSelectable(CObject* obj); + void SetDebugCrashSpheres(bool draw); + + bool GetDebugCrashSpheres(); + protected: bool EventFrame(const Event &event); bool EventObject(const Event &event); @@ -384,8 +390,6 @@ protected: void ClearTooltip(); CObject* DetectObject(Math::Point pos); void ChangeCamera(); - void RemoteCamera(float pan, float zoom, float rTime); - void KeyCamera(EventType event, InputSlot key); void AbortMovie(); void SelectOneObject(CObject* obj, bool displayError=true); void HelpObject(); @@ -395,10 +399,10 @@ protected: void StartDisplayVisit(EventType event); void FrameVisit(float rTime); void StopDisplayVisit(); - void ExecuteCmd(char *cmd); + void ExecuteCmd(const std::string& cmd); void UpdateSpeedLabel(); - int AutosaveRotate(bool freeOne); + void AutosaveRotate(); void Autosave(); bool DestroySelectedObject(); void PushToSelectionHistory(CObject* obj); @@ -435,6 +439,7 @@ protected: std::unique_ptr m_interface; std::unique_ptr m_displayInfo; std::unique_ptr m_displayText; + std::unique_ptr m_debugMenu; std::unique_ptr m_settings; //! Progress of loaded player @@ -451,6 +456,8 @@ protected: LevelCategory m_levelCategory; int m_levelChap = 0; int m_levelRank = 0; + //! if set, loads this file instead of building from category/chap/rank + std::string m_levelFile = ""; std::string m_sceneReadPath; float m_winDelay = 0.0f; @@ -497,7 +504,6 @@ protected: char m_mapFilename[100] = {}; ActivePause* m_suspend = nullptr; - Gfx::CameraType m_suspendInitCamera = Gfx::CAM_TYPE_NULL; Math::Point m_tooltipPos; std::string m_tooltipName; @@ -510,8 +516,8 @@ protected: std::string m_scriptName = ""; std::string m_scriptFile = ""; - int m_endingWinRank = 0; - int m_endingLostRank = 0; + std::string m_endingWin = ""; + std::string m_endingLost = ""; bool m_winTerminate = false; float m_globalMagnifyDamage = 0.0f; @@ -527,9 +533,6 @@ protected: std::vector m_newScriptName; - float m_cameraPan = 0.0f; - float m_cameraZoom = 0.0f; - EventType m_visitLast = EVENT_NULL; CObject* m_visitObject = nullptr; CObject* m_visitArrow = nullptr; @@ -540,16 +543,15 @@ protected: ActivePause* m_visitPause = nullptr; std::vector> m_endTake; + //! If true, the mission ends immediately after completing the requirements without requiring SpaceShip takeoff + bool m_endTakeImmediat = false; long m_endTakeResearch = 0; float m_endTakeWinDelay = 0.0f; float m_endTakeLostDelay = 0.0f; std::vector> m_audioChange; - int m_obligatoryTotal = 0; - char m_obligatoryToken[100][20] = {}; - int m_prohibitedTotal = 0; - char m_prohibitedToken[100][20] = {}; + std::map m_obligatoryTokens; //! Enabled buildings int m_build = 0; @@ -559,16 +561,14 @@ protected: std::map m_researchDone; Error m_missionResult = ERR_OK; + //! true if m_missionResult has been set by LevelController script, this disables normal EndMissionTake processing + bool m_missionResultFromScript = false; ShowLimit m_showLimit[MAXSHOWLIMIT]; - Gfx::Color m_colorRefBot; std::map m_colorNewBot; - Gfx::Color m_colorRefAlien; Gfx::Color m_colorNewAlien; - Gfx::Color m_colorRefGreen; Gfx::Color m_colorNewGreen; - Gfx::Color m_colorRefWater; Gfx::Color m_colorNewWater; float m_colorShiftWater = 0.0f; diff --git a/src/level/scene_conditions.h b/src/level/scene_conditions.h index 33a65088..258cc7ef 100644 --- a/src/level/scene_conditions.h +++ b/src/level/scene_conditions.h @@ -77,6 +77,7 @@ public: int lost = -1; // lost if <= + //! If this is true, the mission ends as soon as this requirement is met, without having to complete the others bool immediat = false; //! Read from line in scene file diff --git a/src/math/func.h b/src/math/func.h index 66ee974e..b206c89a 100644 --- a/src/math/func.h +++ b/src/math/func.h @@ -93,6 +93,15 @@ inline float Max(float a, float b, float c, float d, float e) return Math::Max( Math::Max(a, b), Math::Max(c, d), e ); } +//! Clamps the value to a range specified by min and max +template +inline T Clamp(T value, T min, T max) +{ + if (value < min) return min; + else if (value > max) return max; + else return value; +} + //! Returns the normalized value (0 .. 1) inline float Norm(float a) { diff --git a/src/math/intpoint.h b/src/math/intpoint.h index 876d9e54..470abf38 100644 --- a/src/math/intpoint.h +++ b/src/math/intpoint.h @@ -25,6 +25,8 @@ #pragma once #include +#include +#include // Math module namespace namespace Math @@ -59,6 +61,100 @@ struct IntPoint { return sqrtf(x*x + y*y); } + + //! Sets the zero point: (0,0) + inline void LoadZero() + { + x = y = 0.0f; + } + + //! Returns the struct cast to \c int* array; use with care! + inline int* Array() + { + return reinterpret_cast(this); + } + + //! Returns the struct cast to const int* array; use with care! + inline const int* Array() const + { + return reinterpret_cast(this); + } + + //! Returns the inverted point + inline IntPoint operator-() const + { + return IntPoint(-x, -y); + } + + //! Adds the given point + inline const IntPoint& operator+=(const IntPoint &right) + { + x += right.x; + y += right.y; + return *this; + } + + //! Adds two points + inline friend const IntPoint operator+(const IntPoint &left, const IntPoint &right) + { + return IntPoint(left.x + right.x, left.y + right.y); + } + + //! Subtracts the given point + inline const IntPoint& operator-=(const IntPoint &right) + { + x -= right.x; + y -= right.y; + return *this; + } + + //! Subtracts two points + inline friend const IntPoint operator-(const IntPoint &left, const IntPoint &right) + { + return IntPoint(left.x - right.x, left.y - right.y); + } + + //! Multiplies by given scalar + inline const IntPoint& operator*=(const float &right) + { + x *= right; + y *= right; + return *this; + } + + //! Multiplies point by scalar + inline friend const IntPoint operator*(const float &left, const IntPoint &right) + { + return IntPoint(left * right.x, left * right.y); + } + + //! Multiplies point by scalar + inline friend const IntPoint operator*(const IntPoint &left, const int &right) + { + return IntPoint(left.x * right, left.y * right); + } + + //! Divides by given scalar + inline const IntPoint& operator/=(const float &right) + { + x /= right; + y /= right; + return *this; + } + + //! Divides point by scalar + inline friend const IntPoint operator/(const IntPoint &left, const int &right) + { + return IntPoint(left.x / right, left.y / right); + } + + //! Returns a string "[x, y]" + inline std::string ToString() const + { + std::stringstream s; + s << "[" << x << ", " << y << "]"; + return s.str(); + } }; diff --git a/src/math/point.h b/src/math/point.h index 786e8202..cd568ac1 100644 --- a/src/math/point.h +++ b/src/math/point.h @@ -90,7 +90,7 @@ struct Point return sqrtf(x*x + y*y); } - //! Returns the inverted point + //! Returns the inverted point inline Point operator-() const { return Point(-x, -y); @@ -110,7 +110,7 @@ struct Point return Point(left.x + right.x, left.y + right.y); } - //! Subtracts the given vector + //! Subtracts the given point inline const Point& operator-=(const Point &right) { x -= right.x; diff --git a/src/object/auto/autobase.cpp b/src/object/auto/autobase.cpp index 0fd8c43c..3200c612 100644 --- a/src/object/auto/autobase.cpp +++ b/src/object/auto/autobase.cpp @@ -170,7 +170,6 @@ begin: { assert(pObj->Implements(ObjectInterfaceType::Controllable)); m_camera->SetType(dynamic_cast(pObj)->GetCameraType()); - m_camera->SetDist(dynamic_cast(pObj)->GetCameraDist()); } m_main->StartMusic(); @@ -203,18 +202,17 @@ begin: m_camera->SetType(Gfx::CAM_TYPE_SCRIPT); - pos = m_pos; - pos.x -= 150.0f; - m_terrain->AdjustToFloor(pos); - pos.y += 10.0f; - m_camera->SetScriptEye(pos); - m_posSound = pos; + Math::Vector eye = m_pos; + eye.x -= 150.0f; + m_terrain->AdjustToFloor(eye); + eye.y += 10.0f; - pos = m_object->GetPosition(); - pos.y += 300.0f+50.0f; - m_camera->SetScriptLookat(pos); + Math::Vector lookat = m_object->GetPosition(); + lookat.y += 300.0f+50.0f; + + m_camera->SetScriptCamera(eye, lookat); + m_posSound = eye; - m_camera->FixCamera(); m_engine->SetFocus(2.0f); m_engine->SetFogStart(0.9f); @@ -266,9 +264,8 @@ begin: pos.x += 1000.0f; pos.z -= 60.0f; pos.y += 80.0f; - m_camera->SetScriptEye(pos); m_posSound = pos; - m_camera->FixCamera(); + m_camera->SetScriptCamera(pos, Math::Vector(0.0f, 0.0f, 0.0f)); m_engine->SetFocus(1.0f); BeginTransit(); @@ -345,15 +342,15 @@ begin: vibCir *= Math::Min(1.0f, (1.0f-m_progress)*3.0f); m_object->SetCirVibration(vibCir); - pos = m_pos; - pos.x -= 150.0f; - m_terrain->AdjustToFloor(pos); - pos.y += 10.0f; - m_camera->SetScriptEye(pos); + Math::Vector eye = m_pos; + eye.x -= 150.0f; + m_terrain->AdjustToFloor(eye); + eye.y += 10.0f; - pos = m_object->GetPosition(); - pos.y += 50.0f; - m_camera->SetScriptLookat(pos); + Math::Vector lookat = m_object->GetPosition(); + lookat.y += 50.0f; + + m_camera->SetScriptCameraAnimate(eye, lookat); m_engine->SetFocus(1.0f+(1.0f-m_progress)); @@ -494,7 +491,7 @@ begin: m_terrain->AdjustToFloor(pos); pos.y += 10.0f; pos.y += m_progress*40.0f; - m_camera->SetScriptEye(pos); + m_camera->SetScriptCameraAnimateEye(pos); m_engine->SetFogStart(0.9f-(0.9f-m_fogStart)*m_progress); } @@ -556,7 +553,7 @@ begin: m_terrain->AdjustToFloor(pos); pos.y += 10.0f; pos.y += m_progress*40.0f; - m_camera->SetScriptEye(pos); + m_camera->SetScriptCameraAnimateEye(pos); m_engine->SetFogStart(0.9f-(0.9f-m_fogStart)*m_progress); } @@ -598,7 +595,6 @@ begin: { assert(pObj->Implements(ObjectInterfaceType::Controllable)); m_camera->SetType(dynamic_cast(pObj)->GetCameraType()); - m_camera->SetDist(dynamic_cast(pObj)->GetCameraDist()); } m_sound->Play(SOUND_BOUM, m_object->GetPosition()); m_soundChannel = -1; @@ -749,15 +745,15 @@ begin: vibCir.y = 0.0f; m_object->SetCirVibration(vibCir); - pos = m_pos; - pos.x -= 110.0f+m_progress*250.0f; - m_terrain->AdjustToFloor(pos); - pos.y += 10.0f; - m_camera->SetScriptEye(pos); + Math::Vector eye = m_pos; + eye.x -= 110.0f+m_progress*250.0f; + m_terrain->AdjustToFloor(eye); + eye.y += 10.0f; - pos = m_object->GetPosition(); - pos.y += 50.0f; - m_camera->SetScriptLookat(pos); + Math::Vector lookat = m_object->GetPosition(); + lookat.y += 50.0f; + + m_camera->SetScriptCameraAnimate(eye, lookat); m_engine->SetFocus(1.0f+m_progress); @@ -907,7 +903,7 @@ begin: pos.x += event.rTime*(2000.0f/BASE_TRANSIT_TIME); m_object->SetPosition(pos); pos.x += 60.0f; - m_camera->SetScriptLookat(pos); + m_camera->SetScriptCameraAnimateLookat(pos); } else { @@ -1129,7 +1125,6 @@ bool CAutoBase::Abort() { assert(pObj->Implements(ObjectInterfaceType::Controllable)); m_camera->SetType(dynamic_cast(pObj)->GetCameraType()); - m_camera->SetDist(dynamic_cast(pObj)->GetCameraDist()); } m_engine->SetFogStart(m_fogStart); @@ -1387,16 +1382,16 @@ Error CAutoBase::TakeOff(bool printMsg) m_camera->SetType(Gfx::CAM_TYPE_SCRIPT); - Math::Vector pos = m_pos; - pos.x -= 110.0f; - m_terrain->AdjustToFloor(pos); - pos.y += 10.0f; - m_camera->SetScriptEye(pos); - m_posSound = pos; + Math::Vector eye = m_pos; + eye.x -= 110.0f; + m_terrain->AdjustToFloor(eye); + eye.y += 10.0f; - pos = m_object->GetPosition(); - pos.y += 50.0f; - m_camera->SetScriptLookat(pos); + Math::Vector lookat = m_object->GetPosition(); + lookat.y += 50.0f; + + m_camera->SetScriptCameraAnimate(eye, lookat); + m_posSound = eye; m_engine->SetFocus(1.0f); diff --git a/src/object/auto/autohouston.cpp b/src/object/auto/autohouston.cpp index a73b2705..2853be89 100644 --- a/src/object/auto/autohouston.cpp +++ b/src/object/auto/autohouston.cpp @@ -17,9 +17,10 @@ * along with this program. If not, see http://gnu.org/licenses */ - #include "object/auto/autohouston.h" +#include "math/geometry.h" + #include "object/old_object.h" #include "ui/controls/interface.h" @@ -30,23 +31,19 @@ CAutoHouston::CAutoHouston(COldObject* object) : CAuto(object) { - Math::Vector pos; - int i; - - for ( i=0 ; iGetPosition(); m_lens[0].type = Gfx::PARTISELR; m_lens[1].type = Gfx::PARTISELR; m_lens[2].type = Gfx::PARTISELR; m_lens[3].type = Gfx::PARTISELR; - m_lens[0].pos = pos+Math::Vector(0.0f+13.0f, 34.0f, 30.0f ); - m_lens[1].pos = pos+Math::Vector(0.0f-13.0f, 34.0f, 30.0f ); - m_lens[2].pos = pos+Math::Vector(0.0f , 34.0f, 30.0f+13.0f); - m_lens[3].pos = pos+Math::Vector(0.0f , 34.0f, 30.0f-13.0f); + m_lens[0].pos = Math::Vector(0.0f+13.0f, 34.0f, 30.0f ); + m_lens[1].pos = Math::Vector(0.0f-13.0f, 34.0f, 30.0f ); + m_lens[2].pos = Math::Vector(0.0f , 34.0f, 30.0f+13.0f); + m_lens[3].pos = Math::Vector(0.0f , 34.0f, 30.0f-13.0f); m_lens[0].dim = 4.0f; m_lens[1].dim = 4.0f; m_lens[2].dim = 4.0f; @@ -60,49 +57,50 @@ CAutoHouston::CAutoHouston(COldObject* object) : CAuto(object) m_lens[2].off = 0.4f; m_lens[3].off = 0.4f; + int i = 4; + // Part under the radar. - i = 4; m_lens[i].type = Gfx::PARTISELR; - m_lens[i].pos = pos+Math::Vector(-7.0f, 9.9f, 40.1f); + m_lens[i].pos = Math::Vector(-7.0f, 9.9f, 40.1f); m_lens[i].dim = 1.8f; m_lens[i].total = 0.4f; m_lens[i].off = 0.2f; i ++; m_lens[i].type = Gfx::PARTISELY; - m_lens[i].pos = pos+Math::Vector(-7.0f, 7.2f, 34.8f); + m_lens[i].pos = Math::Vector(-7.0f, 7.2f, 34.8f); m_lens[i].dim = 0.4f; m_lens[i].total = 0.7f; m_lens[i].off = 0.3f; i ++; m_lens[i].type = Gfx::PARTISELY; - m_lens[i].pos = pos+Math::Vector(-7.0f, 6.5f, 34.3f); + m_lens[i].pos = Math::Vector(-7.0f, 6.5f, 34.3f); m_lens[i].dim = 0.4f; m_lens[i].total = 0.7f; m_lens[i].off = 0.3f; i ++; m_lens[i].type = Gfx::PARTISELR; - m_lens[i].pos = pos+Math::Vector(-7.0f, 6.5f, 33.4f); + m_lens[i].pos = Math::Vector(-7.0f, 6.5f, 33.4f); m_lens[i].dim = 0.4f; m_lens[i].total = 0.0f; m_lens[i].off = 0.0f; i ++; m_lens[i].type = Gfx::PARTISELR; - m_lens[i].pos = pos+Math::Vector(-7.0f, 6.5f, 33.0f); + m_lens[i].pos = Math::Vector(-7.0f, 6.5f, 33.0f); m_lens[i].dim = 0.4f; m_lens[i].total = 1.0f; m_lens[i].off = 0.5f; i ++; m_lens[i].type = Gfx::PARTISELY; - m_lens[i].pos = pos+Math::Vector(-7.0f, 8.5f, 14.0f); + m_lens[i].pos = Math::Vector(-7.0f, 8.5f, 14.0f); m_lens[i].dim = 1.2f; m_lens[i].total = 0.8f; m_lens[i].off = 0.2f; i ++; m_lens[i].type = Gfx::PARTISELR; - m_lens[i].pos = pos+Math::Vector(4.0f, 6.0f, 8.6f); + m_lens[i].pos = Math::Vector(4.0f, 6.0f, 8.6f); m_lens[i].dim = 1.0f; m_lens[i].total = 0.9f; m_lens[i].off = 0.7f; @@ -110,53 +108,53 @@ CAutoHouston::CAutoHouston(COldObject* object) : CAuto(object) // Part with three windows. m_lens[i].type = Gfx::PARTISELR; - m_lens[i].pos = pos+Math::Vector(-7.0f, 9.9f, -19.9f); + m_lens[i].pos = Math::Vector(-7.0f, 9.9f, -19.9f); m_lens[i].dim = 1.0f; m_lens[i].total = 0.6f; m_lens[i].off = 0.3f; i ++; m_lens[i].type = Gfx::PARTISELY; - m_lens[i].pos = pos+Math::Vector(-7.0f, 7.2f, 34.8f-60.0f); + m_lens[i].pos = Math::Vector(-7.0f, 7.2f, 34.8f-60.0f); m_lens[i].dim = 0.4f; m_lens[i].total = 0.7f; m_lens[i].off = 0.3f; i ++; m_lens[i].type = Gfx::PARTISELY; - m_lens[i].pos = pos+Math::Vector(-7.0f, 6.5f, 34.3f-60.0f); + m_lens[i].pos = Math::Vector(-7.0f, 6.5f, 34.3f-60.0f); m_lens[i].dim = 0.4f; m_lens[i].total = 0.0f; m_lens[i].off = 0.0f; i ++; m_lens[i].type = Gfx::PARTISELR; - m_lens[i].pos = pos+Math::Vector(-7.0f, 6.5f, 33.4f-60.0f); + m_lens[i].pos = Math::Vector(-7.0f, 6.5f, 33.4f-60.0f); m_lens[i].dim = 0.4f; m_lens[i].total = 0.6f; m_lens[i].off = 0.4f; i ++; m_lens[i].type = Gfx::PARTISELR; - m_lens[i].pos = pos+Math::Vector(-7.0f, 6.5f, 33.0f-60.0f); + m_lens[i].pos = Math::Vector(-7.0f, 6.5f, 33.0f-60.0f); m_lens[i].dim = 0.4f; m_lens[i].total = 0.8f; m_lens[i].off = 0.2f; i ++; m_lens[i].type = Gfx::PARTISELY; - m_lens[i].pos = pos+Math::Vector(-6.5f, 13.5f, -37.0f); + m_lens[i].pos = Math::Vector(-6.5f, 13.5f, -37.0f); m_lens[i].dim = 1.0f; m_lens[i].total = 0.0f; m_lens[i].off = 0.0f; i ++; m_lens[i].type = Gfx::PARTISELY; - m_lens[i].pos = pos+Math::Vector(-7.0f, 12.2f, -39.8f); + m_lens[i].pos = Math::Vector(-7.0f, 12.2f, -39.8f); m_lens[i].dim = 1.8f; m_lens[i].total = 1.5f; m_lens[i].off = 0.5f; i ++; m_lens[i].type = Gfx::PARTISELY; - m_lens[i].pos = pos+Math::Vector(-7.0f, 8.5f, -47.0f); + m_lens[i].pos = Math::Vector(-7.0f, 8.5f, -47.0f); m_lens[i].dim = 0.6f; m_lens[i].total = 0.7f; m_lens[i].off = 0.5f; @@ -204,15 +202,11 @@ void CAutoHouston::Start(int param) bool CAutoHouston::EventProcess(const Event &event) { - Math::Vector speed; - Math::Point dim; - float angle; - int i; - CAuto::EventProcess(event); if ( m_engine->GetPause() ) return true; + float angle; angle = -m_time*1.0f; m_object->SetPartRotationY(1, angle); // rotates the radar angle = sinf(m_time*4.0f)*0.3f; @@ -223,8 +217,7 @@ bool CAutoHouston::EventProcess(const Event &event) m_progress += event.rTime*m_speed; // Flashes the keys. - speed = Math::Vector(0.0f, 0.0f, 0.0f); - for ( i=0 ; iCreateParticle(m_lens[i].pos, speed, dim, m_lens[i].type, 1.0f, 0.0f, 0.0f); + + Math::Vector pos = m_lens[i].pos; + Math::RotatePoint(Math::Vector(0.0f, 0.0f, 0.0f), -m_object->GetRotationY(), 0.0f, pos); + + m_lens[i].parti = m_particle->CreateParticle(m_object->GetPosition()+pos, Math::Vector(0.0f, 0.0f, 0.0f), dim, m_lens[i].type, 1.0f, 0.0f, 0.0f); } } } diff --git a/src/object/auto/autolabo.cpp b/src/object/auto/autolabo.cpp index 45375ba8..0fb087d5 100644 --- a/src/object/auto/autolabo.cpp +++ b/src/object/auto/autolabo.cpp @@ -21,7 +21,6 @@ #include "object/auto/autolabo.h" #include "common/make_unique.h" -#include "common/misc.h" #include "level/robotmain.h" diff --git a/src/object/auto/autoportico.cpp b/src/object/auto/autoportico.cpp index b716dc54..042e7c31 100644 --- a/src/object/auto/autoportico.cpp +++ b/src/object/auto/autoportico.cpp @@ -164,19 +164,17 @@ bool CAutoPortico::EventProcess(const Event &event) m_camera->SetType(Gfx::CAM_TYPE_SCRIPT); - pos = m_startPos; - pos.x += -100.0f; - pos.y += 9.0f; - pos.z += -200.0f; - m_camera->SetScriptEye(pos); + Math::Vector eye = m_startPos; + eye.x += -100.0f; + eye.y += 9.0f; + eye.z += -200.0f; - pos = m_object->GetPosition(); - pos.x += 0.0f; - pos.y += 10.0f; - pos.z += -40.0f; - m_camera->SetScriptLookat(pos); + Math::Vector lookat = m_object->GetPosition(); + lookat.x += 0.0f; + lookat.y += 10.0f; + lookat.z += -40.0f; - m_camera->FixCamera(); + m_camera->SetScriptCamera(eye, lookat); } } @@ -329,23 +327,20 @@ bool CAutoPortico::EventProcess(const Event &event) if ( m_cameraProgress < 1.0f ) { - if ( m_cameraProgress < 0.5f ) - { - } - else + if ( m_cameraProgress >= 0.5f ) { pos = m_startPos; pos.x += -100.0f-(m_cameraProgress-0.5f)*1.0f*120.0f; pos.y += 9.0f; pos.z += -200.0f+(m_cameraProgress-0.5f)*1.0f*210.0f; - m_camera->SetScriptEye(pos); + m_camera->SetScriptCameraAnimateEye(pos); } pos = m_object->GetPosition(); pos.x += 0.0f; pos.y += 10.0f; pos.z += -40.0f; - m_camera->SetScriptLookat(pos); + m_camera->SetScriptCameraAnimateLookat(pos); } return true; diff --git a/src/object/auto/autotower.cpp b/src/object/auto/autotower.cpp index 23d8f2c0..ad436af7 100644 --- a/src/object/auto/autotower.cpp +++ b/src/object/auto/autotower.cpp @@ -271,12 +271,16 @@ CObject* CAutoTower::SearchTarget(Math::Vector &impact) CObject* best = nullptr; for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) { + int oTeam=obj->GetTeam(); + int myTeam=m_object->GetTeam(); ObjectType oType = obj->GetType(); if ( oType != OBJECT_MOTHER && oType != OBJECT_ANT && oType != OBJECT_SPIDER && oType != OBJECT_BEE && - oType != OBJECT_WORM ) continue; + oType != OBJECT_WORM && + (oTeam == myTeam || + oTeam == 0) ) continue; if ( !obj->GetDetectable() ) continue; // inactive? diff --git a/src/object/interface/controllable_object.h b/src/object/interface/controllable_object.h index 5a04c3fc..9d1aabde 100644 --- a/src/object/interface/controllable_object.h +++ b/src/object/interface/controllable_object.h @@ -58,10 +58,6 @@ public: virtual void SetCameraType(Gfx::CameraType type) = 0; //! Return camera type for this object virtual Gfx::CameraType GetCameraType() = 0; - //! Set camera distance for this object - virtual void SetCameraDist(float dist) = 0; - //! Return camera distance for this object - virtual float GetCameraDist() = 0; //! Disallow camera changes virtual void SetCameraLock(bool lock) = 0; //! Check if camera changes are disallowed diff --git a/src/object/object.cpp b/src/object/object.cpp index 44466012..6685dd3d 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -114,7 +114,8 @@ std::vector CObject::GetAllCrashSpheres() bool CObject::CanCollideWith(CObject* other) { ObjectType otherType = other->GetType(); - if (m_type == OBJECT_WORM) return otherType == OBJECT_WORM; + if (m_type == OBJECT_WORM) return false; + if (otherType == OBJECT_WORM) return false; if (m_type == OBJECT_MOTHER) { if (otherType == OBJECT_ANT) return false; diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index cfc2e11b..32861cca 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -150,7 +150,6 @@ COldObject::COldObject(int id) m_character.wheelRight = 1.0f; m_cameraType = Gfx::CAM_TYPE_BACK; - m_cameraDist = 50.0f; m_bCameraLock = false; for (int i=0 ; iGetParam("camera")->IsDefined()) SetCameraType(line->GetParam("camera")->AsCameraType()); - SetCameraDist(line->GetParam("cameraDist")->AsFloat(50.0f)); SetCameraLock(line->GetParam("cameraLock")->AsBool(false)); if (line->GetParam("pyro")->IsDefined()) @@ -2187,15 +2185,17 @@ void COldObject::PartiFrame(float rTime) channel = m_objectPart[i].masterParti; if ( channel == -1 ) continue; - if ( !m_particle->GetPosition(channel, pos) ) + if ( !m_particle->ParticleExists(channel) ) { m_objectPart[i].masterParti = -1; // particle no longer exists! continue; } + pos = m_particle->GetPosition(channel); + SetPartPosition(i, pos); - // Each song spins differently. + // Each part rotates differently switch( i%5 ) { case 0: factor = Math::Vector( 0.5f, 0.3f, 0.6f); break; @@ -2497,16 +2497,6 @@ Gfx::CameraType COldObject::GetCameraType() return m_cameraType; } -void COldObject::SetCameraDist(float dist) -{ - m_cameraDist = dist; -} - -float COldObject::GetCameraDist() -{ - return m_cameraDist; -} - void COldObject::SetCameraLock(bool lock) { m_bCameraLock = lock; @@ -2973,6 +2963,7 @@ void COldObject::UpdateSelectParticle() // Updates lens. for ( i=0 ; i<4 ; i++ ) { + if (m_partiSel[i] == -1) continue; pos[i] = Math::Transform(m_objectPart[0].matWorld, pos[i]); dim[i].y = dim[i].x; m_particle->SetParam(m_partiSel[i], pos[i], dim[i], zoom[i], angle, 1.0f); diff --git a/src/object/old_object.h b/src/object/old_object.h index 44a49e2d..60e8e8fa 100644 --- a/src/object/old_object.h +++ b/src/object/old_object.h @@ -55,9 +55,9 @@ const int OBJECTMAXPART = 40; struct ObjectPart { bool bUsed = false; - int object = -1; // number of the object in CEngine - int parentPart = -1; // number of father part - int masterParti = -1; // master canal of the particle + int object = -1; //!< identifier of the object in Gfx::CEngine + int parentPart = -1; //!< identifier of parent part + int masterParti = -1; //!< particle channel this part is connected to after explosion Math::Vector position; Math::Vector angle; Math::Vector zoom; @@ -218,8 +218,6 @@ public: void SetCameraType(Gfx::CameraType type) override; Gfx::CameraType GetCameraType() override; - void SetCameraDist(float dist) override; - float GetCameraDist() override; void SetCameraLock(bool lock) override; bool GetCameraLock() override; @@ -351,7 +349,6 @@ protected: float m_gunGoalV; float m_gunGoalH; Gfx::CameraType m_cameraType; - float m_cameraDist; bool m_bCameraLock; float m_magnifyDamage; diff --git a/src/object/task/taskgoto.cpp b/src/object/task/taskgoto.cpp index d7e36cd7..de37d1a1 100644 --- a/src/object/task/taskgoto.cpp +++ b/src/object/task/taskgoto.cpp @@ -22,6 +22,7 @@ #include "common/event.h" #include "common/global.h" +#include "common/image.h" #include "common/make_unique.h" #include "graphics/engine/terrain.h" @@ -65,6 +66,9 @@ CTaskGoto::CTaskGoto(COldObject* object) : CForegroundTask(object) CTaskGoto::~CTaskGoto() { BitmapClose(); + + if (m_engine->GetDebugGoto() && m_object->GetSelect()) + m_engine->SetDebugGotoBitmap(std::move(nullptr)); } @@ -77,9 +81,63 @@ bool CTaskGoto::EventProcess(const Event &event) float a, g, dist, linSpeed, cirSpeed, h, hh, factor, dir; Error ret; - if ( m_engine->GetPause() ) return true; if ( event.type != EVENT_FRAME ) return true; + if (m_engine->GetDebugGoto()) + { + auto AdjustPoint = [&](Math::Vector p) -> Math::Vector + { + m_terrain->AdjustToFloor(p); + p.y += 2.0f; + return p; + }; + + std::vector debugLine; + if (m_bmTotal > 0) + { + Gfx::Color color = Gfx::Color(0.0f, 1.0f, 0.0f); + for (int i = 0; i < m_bmTotal; i++) + { + if (i > m_bmIndex-1) + color = Gfx::Color(1.0f, 0.0f, 0.0f); + debugLine.push_back(Gfx::VertexCol(AdjustPoint(m_bmPoints[i]), color)); + } + m_engine->AddDebugGotoLine(debugLine); + debugLine.clear(); + } + Gfx::Color color = Gfx::Color(0.0f, 0.0f, 1.0f); + debugLine.push_back(Gfx::VertexCol(m_object->GetPosition(), color)); + debugLine.push_back(Gfx::VertexCol(AdjustPoint(m_bmTotal > 0 && m_bmIndex <= m_bmTotal && m_phase != TGP_BEAMSEARCH ? m_bmPoints[m_bmIndex] : m_goal), color)); + m_engine->AddDebugGotoLine(debugLine); + + if (m_object->GetSelect() && m_bmChanged) + { + if (m_bmArray != nullptr) + { + std::unique_ptr debugImage = MakeUnique(Math::IntPoint(m_bmSize, m_bmSize)); + debugImage->Fill(Gfx::IntColor(255, 255, 255, 255)); + for (int x = 0; x < m_bmSize; x++) + { + for (int y = 0; y < m_bmSize; y++) + { + bool a = BitmapTestDot(0, x, y); + bool b = BitmapTestDot(1, x, y); + if (a || b) + { + Gfx::Color c = Gfx::Color(0.0f, 0.0f, 0.0f, 1.0f); + if (b) c = Gfx::Color(0.0f, 0.0f, 1.0f, 1.0f); + debugImage->SetPixel(Math::IntPoint(x, y), c); + } + } + } + m_engine->SetDebugGotoBitmap(std::move(debugImage)); + } + m_bmChanged = false; + } + } + + if ( m_engine->GetPause() ) return true; + // Momentarily stationary object (ant on the back)? CBaseAlien* alien = dynamic_cast(m_object); if ( alien != nullptr && alien->GetFixed() ) @@ -1616,6 +1674,8 @@ Error CTaskGoto::BeamExplore(const Math::Vector &prevPos, const Math::Vector &cu iLar = 0; if ( i >= MAXPOINTS ) return ERR_GOTO_ITER; // too many recursions + m_bmTotal = i; + if ( m_bmIter[i] == -1 ) { m_bmIter[i] = 0; @@ -1970,6 +2030,7 @@ bool CTaskGoto::BitmapOpen() m_bmSize = static_cast(3200.0f/BM_DIM_STEP); m_bmArray = MakeUniqueArray(m_bmSize*m_bmSize/8*2); + m_bmChanged = true; m_bmOffset = m_bmSize/2; m_bmLine = m_bmSize/8; @@ -1987,6 +2048,7 @@ bool CTaskGoto::BitmapOpen() bool CTaskGoto::BitmapClose() { m_bmArray.reset(); + m_bmChanged = true; return true; } @@ -2043,6 +2105,7 @@ void CTaskGoto::BitmapSetDot(int rank, int x, int y) y < 0 || y >= m_bmSize ) return; m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] |= (1<= m_bmSize ) return; m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] &= ~(1<SetPartPosition(2, pos); + + pos.x = 0.0f; + pos.y = 1.0f+3.0f; + pos.z = 0.0f; + m_object->SetPartPosition(3, pos); + Math::Matrix* mat = m_object->GetWorldMatrix(0); - Math::Vector pos = Math::Vector(7.0f, 15.0f, 0.0f); + pos = Math::Vector(7.0f, 15.0f, 0.0f); pos = Transform(*mat, pos); // sphere position m_shieldPos = pos; diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index e4013bb9..8fcc08c3 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -1577,10 +1577,13 @@ bool CPhysics::EventFrame(const Event &event) if ( m_bLand && m_fallingHeight != 0.0f ) // if fell { - float force = (m_fallingHeight - m_object->GetPosition().y) * m_fallDamageFraction; - if (m_object->DamageObject(DamageType::Fall, force)) + if (m_object->Implements(ObjectInterfaceType::Damageable)) { - return false; // ugly hack, but works for 0.1.6 release :/ + float force = (m_fallingHeight - m_object->GetPosition().y) * m_fallDamageFraction; + if (m_object->DamageObject(DamageType::Fall, force)) + { + return false; // ugly hack, but works for 0.1.6 release :/ + } } m_fallingHeight = 0.0f; } diff --git a/src/script/script.cpp b/src/script/script.cpp index 3beac76e..ff4c04d2 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -44,6 +44,7 @@ #include "ui/controls/interface.h" #include "ui/controls/list.h" +#include const int CBOT_IPF = 100; // CBOT: default number of instructions / frame @@ -70,11 +71,8 @@ CScript::CScript(COldObject* object) m_bRun = false; m_bStepMode = false; m_bCompile = false; - m_title[0] = 0; - m_mainFunction[0] = 0; m_cursor1 = 0; m_cursor2 = 0; - m_filename[0] = 0; } // Object's destructor. @@ -159,49 +157,55 @@ bool CScript::CheckToken() if ( !m_object->GetCheckToken() ) return true; m_error = CBot::CBotNoErr; - m_title[0] = 0; - m_mainFunction[0] = 0; - m_token[0] = 0; + m_title.clear(); + m_mainFunction.clear(); + m_token.clear(); m_bCompile = false; - std::vector used(m_main->GetObligatoryToken(), false); + std::map used; + std::map cursor1; + std::map cursor2; auto tokens = CBot::CBotToken::CompileTokens(m_script.get()); CBot::CBotToken* bt = tokens.get(); while ( bt != nullptr ) { std::string token = bt->GetString(); - int cursor1 = bt->GetStart(); - int cursor2 = bt->GetEnd(); - int i = m_main->IsObligatoryToken(token.c_str()); - if ( i != -1 ) - { - used[i] = true; // token used - } + // Store only the last occurrence of the token + cursor1[token] = bt->GetStart(); + cursor2[token] = bt->GetEnd(); - if ( !m_main->IsProhibitedToken(token.c_str()) ) - { - m_error = static_cast(ERR_PROHIBITEDTOKEN); - m_cursor1 = cursor1; - m_cursor2 = cursor2; - strcpy(m_title, ""); - m_mainFunction[0] = 0; - return false; - } + used[token]++; bt = bt->GetNext(); } - // At least once every obligatory instruction? - for (unsigned int i = 0; i < used.size(); i++) + for (const auto& it : m_main->GetObligatoryTokenList()) { - if (!used[i]) // token not used? + Error error = ERR_OK; + int allowed = 0; + if (it.second.max >= 0 && used[it.first] > it.second.max) { - strcpy(m_token, m_main->GetObligatoryToken(i)); - m_error = static_cast(ERR_OBLIGATORYTOKEN); - strcpy(m_title, ""); - m_mainFunction[0] = 0; + error = ERR_PROHIBITEDTOKEN; + allowed = it.second.max; + m_cursor1 = cursor1[it.first]; + m_cursor2 = cursor2[it.first]; + } + if (it.second.min >= 0 && used[it.first] < it.second.min) + { + error = ERR_OBLIGATORYTOKEN; + allowed = it.second.min; + } + + if (error != ERR_OK) + { + m_token = it.first; + m_tokenUsed = used[it.first]; + m_tokenAllowed = allowed; + m_error = static_cast(error); + m_title = ""; + m_mainFunction.clear(); return false; } } @@ -214,14 +218,13 @@ bool CScript::CheckToken() bool CScript::Compile() { std::vector functionList; - int i; std::string p; m_error = CBot::CBotNoErr; m_cursor1 = 0; m_cursor2 = 0; - m_title[0] = 0; - m_mainFunction[0] = 0; + m_title.clear(); + m_mainFunction.clear(); m_bCompile = false; if ( IsEmpty() ) // program exist? @@ -239,33 +242,17 @@ bool CScript::Compile() { if (functionList.empty()) { - strcpy(m_title, ""); - m_mainFunction[0] = 0; + m_title = ""; + m_mainFunction.clear(); } else { - p = functionList[0]; - i = 0; - bool titleDone = false; - while ( true ) + m_mainFunction = functionList[0]; + m_title = m_mainFunction; + if (m_title.length() >= 20) { - if ( p[i] == 0 || p[i] == '(' ) break; - if ( i >= 20 && !titleDone ) - { - m_title[i+0] = '.'; - m_title[i+1] = '.'; - m_title[i+2] = '.'; - m_title[i+3] = 0; - titleDone = true; - } - if(!titleDone) - m_title[i] = p[i]; - m_mainFunction[i] = p[i]; - i ++; + m_title = m_title.substr(0, 20)+"..."; } - if(!titleDone) - m_title[i] = 0; - m_mainFunction[i] = p[i]; } m_bCompile = true; return true; @@ -283,8 +270,8 @@ bool CScript::Compile() { m_cursor1 = m_cursor2 = 0; } - strcpy(m_title, ""); - m_mainFunction[0] = 0; + m_title = ""; + m_mainFunction.clear(); return false; } } @@ -292,9 +279,9 @@ bool CScript::Compile() // Returns the title of the script. -void CScript::GetTitle(char* buffer) +const std::string& CScript::GetTitle() { - strcpy(buffer, m_title); + return m_title; } @@ -317,9 +304,9 @@ bool CScript::Run() { if (m_botProg == nullptr) return false; if ( m_script == nullptr || m_len == 0 ) return false; - if ( m_mainFunction[0] == 0 ) return false; + if ( m_mainFunction.empty() ) return false; - if ( !m_botProg->Start(m_mainFunction) ) return false; + if ( !m_botProg->Start(m_mainFunction.c_str()) ) return false; m_bRun = true; m_bContinue = false; @@ -788,13 +775,28 @@ void CScript::GetError(std::string& error) } else { - if ( m_error == static_cast(ERR_OBLIGATORYTOKEN) ) + if (m_error == static_cast(ERR_OBLIGATORYTOKEN)) { - std::string s; - GetResource(RES_ERR, m_error, s); - error = StrUtils::Format(s.c_str(), m_token); + error = StrUtils::Format(ngettext( + "You have to use \"%1$s\" at least once in this exercise (used: %2$d)", + "You have to use \"%1$s\" at least %3$d times in this exercise (used: %2$d)", + m_tokenAllowed), m_token.c_str(), m_tokenUsed, m_tokenAllowed); } - else if ( m_error < 1000 ) + else if (m_error == static_cast(ERR_PROHIBITEDTOKEN)) + { + if (m_tokenAllowed == 0) + { + error = StrUtils::Format(gettext("You cannot use \"%s\" in this exercise (used: %d)"), m_token.c_str(), m_tokenUsed); + } + else + { + error = StrUtils::Format(ngettext( + "You have to use \"%1$s\" at most once in this exercise (used: %2$d)", + "You have to use \"%1$s\" at most %3$d times in this exercise (used: %2$d)", + m_tokenAllowed), m_token.c_str(), m_tokenUsed, m_tokenAllowed); + } + } + else if (m_error < 1000) { GetResource(RES_ERR, m_error, error); } @@ -1018,12 +1020,12 @@ bool CScript::Compare(CScript* other) // Management of the file name when the script is saved. -void CScript::SetFilename(char *filename) +void CScript::SetFilename(const std::string& filename) { - strcpy(m_filename, filename); + m_filename = filename; } -char* CScript::GetFilename() +const std::string& CScript::GetFilename() { return m_filename; } diff --git a/src/script/script.h b/src/script/script.h index 50f279ef..deed0c6b 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -66,7 +66,7 @@ public: bool GetScript(Ui::CEdit* edit); bool GetCompile(); - void GetTitle(char* buffer); + const std::string& GetTitle(); void SetStepMode(bool bStep); bool GetStepMode(); @@ -92,8 +92,8 @@ public: bool WriteStack(FILE *file); bool Compare(CScript* other); - void SetFilename(char *filename); - char* GetFilename(); + void SetFilename(const std::string &filename); + const std::string& GetFilename(); protected: bool IsEmpty(); @@ -119,10 +119,11 @@ protected: bool m_bStepMode = false; // step by step bool m_bContinue = false; // external function to continue bool m_bCompile = false; // compilation ok? - char m_title[50] = {}; // script title - char m_mainFunction[50] = {}; - char m_filename[50] = {}; // file name - char m_token[50] = {}; // missing instruction + std::string m_title = ""; // script title + std::string m_mainFunction = ""; + std::string m_filename = ""; // file name + std::string m_token = ""; // missing instruction + int m_tokenUsed = 0, m_tokenAllowed = 0; CBot::CBotError m_error = CBot::CBotNoErr; // error (0=ok) int m_cursor1 = 0; int m_cursor2 = 0; diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index d072c79a..e4da1f16 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -204,7 +204,7 @@ bool CScriptFunctions::rEndMission(CBotVar* var, CBotVar* result, int& exception delay = var->GetValFloat(); - CRobotMain::GetInstancePointer()->SetEndMission(ended, delay); + CRobotMain::GetInstancePointer()->SetMissionResultFromScript(ended, delay); return true; } diff --git a/src/sound/oalsound/alsound.cpp b/src/sound/oalsound/alsound.cpp index 95b49a98..020bfbae 100644 --- a/src/sound/oalsound/alsound.cpp +++ b/src/sound/oalsound/alsound.cpp @@ -25,7 +25,6 @@ #include #include -#include CALSound::CALSound() : m_enabled(false), @@ -357,6 +356,7 @@ int CALSound::Play(SoundType sound, const Math::Vector &pos, float amplitude, fl chn->SetFrequency(frequency); chn->SetVolume(powf(amplitude * chn->GetVolumeAtrib(), 0.2f) * m_audioVolume); chn->SetLoop(loop); + chn->Mute(false); if (!chn->Play()) { @@ -586,11 +586,6 @@ bool CALSound::PlayMusic(const std::string &filename, bool repeat, float fadeTim if (m_music.find(filename) == m_music.end()) { GetLogger()->Debug("Music %s was not cached!\n", filename.c_str()); - /* TODO: if (!boost::filesystem::exists(filename)) - { - GetLogger()->Debug("Requested music %s was not found.\n", filename.c_str()); - return false; - } */ auto newBuffer = MakeUnique(); buffer = newBuffer.get(); diff --git a/src/sound/sound.cpp b/src/sound/sound.cpp index d22523f0..3640c585 100644 --- a/src/sound/sound.cpp +++ b/src/sound/sound.cpp @@ -27,8 +27,6 @@ #include #include -#include - CSoundInterface::CSoundInterface() { diff --git a/src/ui/controls/button.cpp b/src/ui/controls/button.cpp index 37d1ad2c..ece43a8d 100644 --- a/src/ui/controls/button.cpp +++ b/src/ui/controls/button.cpp @@ -21,7 +21,6 @@ #include "ui/controls/button.h" #include "common/event.h" -#include "common/misc.h" #include "common/restext.h" #include "graphics/engine/engine.h" diff --git a/src/ui/controls/check.cpp b/src/ui/controls/check.cpp index 80262433..b1b70b41 100644 --- a/src/ui/controls/check.cpp +++ b/src/ui/controls/check.cpp @@ -21,7 +21,6 @@ #include "ui/controls/check.h" #include "common/event.h" -#include "common/misc.h" #include "common/restext.h" #include "graphics/engine/engine.h" diff --git a/src/ui/controls/color.cpp b/src/ui/controls/color.cpp index b92598b3..2aec2a92 100644 --- a/src/ui/controls/color.cpp +++ b/src/ui/controls/color.cpp @@ -21,7 +21,6 @@ #include "ui/controls/color.h" #include "common/event.h" -#include "common/misc.h" #include "common/restext.h" #include "graphics/core/device.h" diff --git a/src/ui/controls/edit.cpp b/src/ui/controls/edit.cpp index 9cf9d330..c50f9796 100644 --- a/src/ui/controls/edit.cpp +++ b/src/ui/controls/edit.cpp @@ -27,7 +27,6 @@ #include "common/logger.h" #include "common/make_unique.h" -#include "common/misc.h" #include "common/resources/inputstream.h" #include "common/resources/outputstream.h" @@ -73,15 +72,9 @@ bool IsSpace(int character) //! Indicates whether a character is part of a word. -bool IsWord(int character) +bool IsWord(char c) { - char c; - - c = tolower(GetNoAccent(character)); - - return ( (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') || - c == '_' ); + return ( isalnum(c) || c == '_'); } //! Indicates whether a character is a word separator. @@ -255,7 +248,7 @@ bool CEdit::EventProcess(const Event &event) { auto data = event.GetData(); Scroll(m_lineFirst - data->y, true); - return true; + return false; } CControl::EventProcess(event); @@ -571,7 +564,7 @@ bool CEdit::IsLinkPos(Math::Point pos) if ( i == -1 ) return false; if ( i >= m_len ) return false; - if ( m_format.size() > static_cast(i) && ((m_format[i] & Gfx::FONT_MASK_HIGHLIGHT) == Gfx::FONT_HIGHLIGHT_LINK)) return true; // TODO + if ( m_format.size() > static_cast(i) && ((m_format[i] & Gfx::FONT_MASK_LINK) != 0)) return true; // TODO return false; } @@ -644,13 +637,13 @@ void CEdit::MouseRelease(Math::Point mouse) if ( !m_bEdit ) { if ( m_format.size() > 0 && i < m_len && m_cursor1 == m_cursor2 && - (m_format[i]&Gfx::FONT_MASK_HIGHLIGHT) == Gfx::FONT_HIGHLIGHT_LINK) //TODO + (m_format[i]&Gfx::FONT_MASK_LINK) != 0) //TODO { int rank = -1; for ( int j=0 ; j<=i ; j++ ) { - if ( (j == 0 || (m_format[j-1]&Gfx::FONT_MASK_HIGHLIGHT) != Gfx::FONT_HIGHLIGHT_LINK) && // TODO check if good - (m_format[j+0]&Gfx::FONT_MASK_HIGHLIGHT) == Gfx::FONT_HIGHLIGHT_LINK) // TODO + if ( (j == 0 || (m_format[j-1]&Gfx::FONT_MASK_LINK) == 0) && // TODO check if good + (m_format[j+0]&Gfx::FONT_MASK_LINK) != 0) // TODO { rank ++; } @@ -1134,25 +1127,41 @@ void CEdit::Draw() // Draw an image part. +std::string PrepareImageFilename(std::string name) +{ + std::string filename; + filename = name + ".png"; + filename = InjectLevelPathsForCurrentLevel(filename, "icons"); + boost::replace_all(filename, "\\", "/"); // TODO: Fix this in files + return filename; +} + void CEdit::DrawImage(Math::Point pos, std::string name, float width, float offset, float height, int nbLine) { Math::Point uv1, uv2, dim; float dp; - std::string filename; - filename = name + ".png"; - filename = InjectLevelPathsForCurrentLevel(filename, "icons"); - boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files - - m_engine->SetTexture(filename); m_engine->SetState(Gfx::ENG_RSTATE_NORMAL); + Gfx::TextureCreateParams params; + params.format = Gfx::TEX_IMG_AUTO; + params.filter = Gfx::TEX_FILTER_BILINEAR; + params.padToNearestPowerOfTwo = true; + Gfx::Texture tex = m_engine->LoadTexture(PrepareImageFilename(name), params); + + m_engine->SetTexture(tex); + uv1.x = 0.0f; uv2.x = 1.0f; uv1.y = offset; uv2.y = offset+height; + uv1.x *= static_cast(tex.originalSize.x) / static_cast(tex.size.x); + uv2.x *= static_cast(tex.originalSize.x) / static_cast(tex.size.x); + uv1.y *= static_cast(tex.originalSize.y) / static_cast(tex.size.y); + uv2.y *= static_cast(tex.originalSize.y) / static_cast(tex.size.y); + dp = 0.5f/256.0f; uv1.x += dp; uv1.y += dp; @@ -1422,21 +1431,10 @@ void CEdit::FreeImage() { for (auto& image : m_image) { - m_engine->DeleteTexture(image.name + ".png"); + m_engine->DeleteTexture(PrepareImageFilename(image.name)); } } -// Reads the texture of an image. - -void CEdit::LoadImage(std::string name) -{ - std::string filename; - filename = name + ".png"; - filename = InjectLevelPathsForCurrentLevel(filename, "icons"); - boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files - m_engine->LoadTexture(filename); -} - // Read from a text file. bool CEdit::ReadText(std::string filename, int addSize) @@ -1583,8 +1581,7 @@ bool CEdit::ReadText(std::string filename, int addSize) { if ( m_bSoluce || !bInSoluce ) { - font &= ~Gfx::FONT_MASK_HIGHLIGHT; - font |= Gfx::FONT_HIGHLIGHT_LINK; + font |= Gfx::FONT_MASK_LINK; } i += 3; } @@ -1604,7 +1601,7 @@ bool CEdit::ReadText(std::string filename, int addSize) link.name = GetNameParam(buffer.data()+i+3, 0); link.marker = GetNameParam(buffer.data()+i+3, 1); m_link.push_back(link); - font &= ~Gfx::FONT_MASK_HIGHLIGHT; + font &= ~Gfx::FONT_MASK_LINK; } i += strchr(buffer.data()+i, ';')-(buffer.data()+i)+1; } @@ -1639,7 +1636,6 @@ bool CEdit::ReadText(std::string filename, int addSize) iWidth = static_cast(GetValueParam(buffer.data()+i+7, 1)); iWidth *= m_engine->GetText()->GetHeight(Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL); iLines = GetValueParam(buffer.data()+i+7, 2); - LoadImage(std::string(iName)); // A part of image per line of text. for ( iCount=0 ; iCount c2 ) Math::Swap(c1, c2); // alwyas c1 <= c2 + if ( c1 > c2 ) Math::Swap(c1, c2); // always c1 <= c2 for ( i=c1 ; i(m_text[i]); - if ( bMaj ) character = GetToUpper(character); - else character = GetToLower(character); + if ( bMaj ) character = toupper(character); + else character = tolower(character); m_text[i] = character; } diff --git a/src/ui/controls/edit.h b/src/ui/controls/edit.h index 6418a19e..bb7b5e3c 100644 --- a/src/ui/controls/edit.h +++ b/src/ui/controls/edit.h @@ -201,7 +201,6 @@ protected: void DrawColor(Math::Point pos, Math::Point dim, Gfx::Color color); void FreeImage(); - void LoadImage(std::string name); void Scroll(int pos, bool bAdjustCursor); void Scroll(); void MoveChar(int move, bool bWord, bool bSelect); diff --git a/src/ui/controls/editvalue.cpp b/src/ui/controls/editvalue.cpp index d8e2af7f..21bb3d46 100644 --- a/src/ui/controls/editvalue.cpp +++ b/src/ui/controls/editvalue.cpp @@ -22,7 +22,6 @@ #include "common/event.h" #include "common/make_unique.h" -#include "common/misc.h" #include "level/robotmain.h" @@ -191,6 +190,7 @@ bool CEditValue::EventProcess(const Event &event) if ( value > m_maxValue ) value = m_maxValue; SetValue(value, true); HiliteValue(event); + return false; } return true; diff --git a/src/ui/controls/group.cpp b/src/ui/controls/group.cpp index b45b99dd..0f7c8c90 100644 --- a/src/ui/controls/group.cpp +++ b/src/ui/controls/group.cpp @@ -21,7 +21,6 @@ #include "ui/controls/group.h" #include "common/event.h" -#include "common/misc.h" #include "common/restext.h" #include "graphics/engine/engine.h" diff --git a/src/ui/controls/image.cpp b/src/ui/controls/image.cpp index 41b7a1e3..ea365b7f 100644 --- a/src/ui/controls/image.cpp +++ b/src/ui/controls/image.cpp @@ -21,7 +21,6 @@ #include "ui/controls/image.h" #include "common/event.h" -#include "common/misc.h" #include "common/restext.h" #include "graphics/engine/engine.h" diff --git a/src/ui/controls/list.cpp b/src/ui/controls/list.cpp index dc4de23e..88d36d94 100644 --- a/src/ui/controls/list.cpp +++ b/src/ui/controls/list.cpp @@ -288,7 +288,7 @@ bool CList::EventProcess(const Event &event) UpdateScroll(); UpdateButton(); - return true; + return false; } CControl::EventProcess(event); diff --git a/src/ui/controls/scroll.cpp b/src/ui/controls/scroll.cpp index e0205893..e47e561f 100644 --- a/src/ui/controls/scroll.cpp +++ b/src/ui/controls/scroll.cpp @@ -22,7 +22,6 @@ #include "common/event.h" #include "common/make_unique.h" -#include "common/misc.h" #include "graphics/engine/engine.h" @@ -292,6 +291,7 @@ bool CScroll::EventProcess(const Event &event) m_event->AddEvent(Event(m_buttonDown->GetEventType())); } } + return false; } return true; diff --git a/src/ui/controls/shortcut.cpp b/src/ui/controls/shortcut.cpp index 480da375..ef4f5439 100644 --- a/src/ui/controls/shortcut.cpp +++ b/src/ui/controls/shortcut.cpp @@ -21,7 +21,6 @@ #include "ui/controls/shortcut.h" #include "common/event.h" -#include "common/misc.h" #include "graphics/core/device.h" diff --git a/src/ui/controls/slider.cpp b/src/ui/controls/slider.cpp index eecb4724..a4926005 100644 --- a/src/ui/controls/slider.cpp +++ b/src/ui/controls/slider.cpp @@ -21,7 +21,6 @@ #include "ui/controls/slider.h" #include "common/event.h" -#include "common/misc.h" #include "common/stringutils.h" #include "graphics/engine/engine.h" @@ -357,6 +356,7 @@ bool CSlider::EventProcess(const Event &event) m_event->AddEvent(Event(m_buttonRight->GetEventType())); } } + return false; } return true; diff --git a/src/ui/controls/target.cpp b/src/ui/controls/target.cpp index b42116fc..9ba4f4e0 100644 --- a/src/ui/controls/target.cpp +++ b/src/ui/controls/target.cpp @@ -135,7 +135,8 @@ bool CTarget::GetTooltip(Math::Point pos, std::string &name) CObject* CTarget::DetectFriendObject(Math::Point pos) { - int objRank = m_engine->DetectObject(pos); + Math::Vector p; + int objRank = m_engine->DetectObject(pos, p); for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) { diff --git a/src/ui/debug_menu.cpp b/src/ui/debug_menu.cpp new file mode 100644 index 00000000..10aa9397 --- /dev/null +++ b/src/ui/debug_menu.cpp @@ -0,0 +1,430 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "ui/debug_menu.h" + +#include "common/event.h" + +#include "graphics/engine/lightning.h" +#include "graphics/engine/terrain.h" + +#include "level/robotmain.h" + +#include "object/object.h" +#include "object/object_manager.h" + +#include "sound/sound.h" + +#include "ui/controls/button.h" +#include "ui/controls/check.h" +#include "ui/controls/interface.h" +#include "ui/controls/window.h" + +namespace Ui +{ + +CDebugMenu::CDebugMenu(CRobotMain* main, Gfx::CEngine* engine, CObjectManager* objMan, CSoundInterface* sound) +{ + m_main = main; + m_interface = m_main->GetInterface(); + m_engine = engine; + m_objMan = objMan; + m_sound = sound; +} + +CDebugMenu::~CDebugMenu() +{ + +} + +void CDebugMenu::ToggleInterface() +{ + if (m_interface->SearchControl(EVENT_WINDOW7) == nullptr) + CreateInterface(); + else + DestroyInterface(); +} + +const Math::Point dim = Math::Point(33.0f/640.0f, 33.0f/480.0f); +const float ox = 3.0f/640.0f, oy = 3.0f/480.0f; +const float /*sx = 33.0f/640.0f,*/ sy = 33.0f/480.0f; + +void CDebugMenu::CreateInterface() +{ + CWindow* pw = m_interface->CreateWindows(Math::Point(), Math::Point(), 0, EVENT_WINDOW7); + Math::Point pos, ddim; + CCheck* pc; + CButton* pb; + + ddim.x = 4*dim.x+4*ox; + ddim.y = 222.0f/480.0f; + pos.x = 1.0f-ddim.x; + pos.y = oy+sy*3.0f; + pw->CreateGroup(pos, ddim, 6, EVENT_WINDOW7); + + ddim.x = ddim.x - 4*ox; + ddim.y = dim.y*0.5f; + pos.x += 2*ox; + pos.y = oy+sy*9.0f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_DBG_SPAWN_OBJ); + pb->SetName("Spawn object"); + pos.y -= ddim.y; + pb = pw->CreateButton(pos, ddim, -1, EVENT_DBG_TELEPORT); + pb->SetName("Teleport"); + pos.y -= ddim.y; + pb = pw->CreateButton(pos, ddim, -1, EVENT_DBG_LIGHTNING); + pb->SetName("Lightning"); + pos.y -= 0.048f; + pc = pw->CreateCheck(pos, ddim, -1, EVENT_DBG_STATS); + pc->SetName("Display stats"); + pos.y -= 0.048f; + pos.y -= 0.048f; + pc = pw->CreateCheck(pos, ddim, -1, EVENT_DBG_RESOURCES); + pc->SetName("Underground resources"); + pos.y -= 0.048f; + pc = pw->CreateCheck(pos, ddim, -1, EVENT_DBG_GOTO); + pc->SetName("Render goto() path"); + pos.y -= 0.048f; + pc = pw->CreateCheck(pos, ddim, -1, EVENT_DBG_CRASHSPHERES); + pc->SetName("Render crash spheres"); + pos.y -= 0.048f; + pc = pw->CreateCheck(pos, ddim, -1, EVENT_DBG_LIGHTS); + pc->SetName("Render dynamic lights"); + pos.y -= 0.048f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_DBG_LIGHTS_DUMP); + pb->SetName("Dump lights to log"); + + UpdateInterface(); +} + +void CDebugMenu::CreateSpawnInterface() +{ + CWindow* pw = m_interface->CreateWindows(Math::Point(), Math::Point(), 0, EVENT_WINDOW7); + Math::Point pos, ddim; + CButton* pb; + + ddim.x = 4*dim.x+4*ox; + ddim.y = 222.0f/480.0f; + pos.x = 1.0f-ddim.x; + pos.y = oy+sy*3.0f; + pw->CreateGroup(pos, ddim, 6, EVENT_WINDOW7); + + ddim.x = ddim.x - 4*ox; + ddim.y = dim.y*0.5f; + pos.x += 2*ox; + pos.y = oy+sy*9.0f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_SPAWN_CANCEL); + pb->SetName("Cancel"); + pos.y -= ddim.y; + + pos.y -= dim.y; + pw->CreateButton(pos, dim, 128+8, EVENT_SPAWN_ME); + pos.x += dim.x; + pw->CreateButton(pos, dim, 128+9, EVENT_SPAWN_WHEELEDGRABBER); + pos.x += dim.x; + pw->CreateButton(pos, dim, 128+15, EVENT_SPAWN_WHEELEDSHOOTER); + pos.x += dim.x; + pw->CreateButton(pos, dim, 128+19, EVENT_SPAWN_PHAZERSHOOTER); + pos.x -= 3*dim.x; + pos.y -= dim.y; + pw->CreateButton(pos, dim, 128+32, EVENT_SPAWN_BOTFACTORY); + pos.x += dim.x; + pw->CreateButton(pos, dim, 128+34, EVENT_SPAWN_CONVERTER); + pos.x += dim.x; + pw->CreateButton(pos, dim, 128+33, EVENT_SPAWN_DERRICK); + pos.x += dim.x; + pw->CreateButton(pos, dim, 128+36, EVENT_SPAWN_POWERSTATION); + pos.x -= 3*dim.x; + pos.y -= ddim.y; + pb = pw->CreateButton(pos, ddim, -1, EVENT_SPAWN_TITANIUM); + pb->SetName("Titanium"); + pos.y -= ddim.y; + pb = pw->CreateButton(pos, ddim, -1, EVENT_SPAWN_TITANIUMORE); + pb->SetName("TitaniumOre"); + pos.y -= ddim.y; + pb = pw->CreateButton(pos, ddim, -1, EVENT_SPAWN_URANIUMORE); + pb->SetName("UraniumOre"); + pos.y -= ddim.y; + pb = pw->CreateButton(pos, ddim, -1, EVENT_SPAWN_POWERCELL); + pb->SetName("PowerCell"); + pos.y -= ddim.y; + pb = pw->CreateButton(pos, ddim, -1, EVENT_SPAWN_NUCLEARCELL); + pb->SetName("NuclearCell"); +} + +const std::map SPAWN_TYPES = { + {EVENT_SPAWN_ME, OBJECT_HUMAN}, + {EVENT_SPAWN_WHEELEDGRABBER, OBJECT_MOBILEwa}, + {EVENT_SPAWN_WHEELEDSHOOTER, OBJECT_MOBILEwc}, + {EVENT_SPAWN_PHAZERSHOOTER, OBJECT_MOBILErc}, + {EVENT_SPAWN_BOTFACTORY, OBJECT_FACTORY}, + {EVENT_SPAWN_CONVERTER, OBJECT_CONVERT}, + {EVENT_SPAWN_DERRICK, OBJECT_DERRICK}, + {EVENT_SPAWN_POWERSTATION, OBJECT_STATION}, + {EVENT_SPAWN_TITANIUM, OBJECT_METAL}, + {EVENT_SPAWN_TITANIUMORE, OBJECT_STONE}, + {EVENT_SPAWN_URANIUMORE, OBJECT_URANIUM}, + {EVENT_SPAWN_POWERCELL, OBJECT_POWER}, + {EVENT_SPAWN_NUCLEARCELL, OBJECT_ATOMIC}, +}; + +void CDebugMenu::UpdateInterface() +{ + CCheck* pc; + CButton* pb; + + CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW7)); + if (pw == nullptr) return; + + + pb = static_cast(pw->SearchControl(EVENT_DBG_LIGHTNING)); + if (pb != nullptr) + { + pb->SetName(m_lightningActive ? "Disable lightning" : "Lightning"); + } + + pb = static_cast(pw->SearchControl(EVENT_DBG_TELEPORT)); + if (pb != nullptr) + { + pb->SetName(m_teleportActive ? "Abort teleport" : "Teleport"); + } + + pc = static_cast(pw->SearchControl(EVENT_DBG_STATS)); + if (pc != nullptr) + { + pc->SetState(STATE_CHECK, m_engine->GetShowStats()); + } + + pc = static_cast(pw->SearchControl(EVENT_DBG_RESOURCES)); + if (pc != nullptr) + { + pc->SetState(STATE_CHECK, m_engine->GetDebugResources()); + } + + pc = static_cast(pw->SearchControl(EVENT_DBG_GOTO)); + if (pc != nullptr) + { + pc->SetState(STATE_CHECK, m_engine->GetDebugGoto()); + } + + pc = static_cast(pw->SearchControl(EVENT_DBG_CRASHSPHERES)); + if (pc != nullptr) + { + pc->SetState(STATE_CHECK, m_main->GetDebugCrashSpheres()); + } + + pc = static_cast(pw->SearchControl(EVENT_DBG_LIGHTS)); + if (pc != nullptr) + { + pc->SetState(STATE_CHECK, m_engine->GetDebugLights()); + } + + for (const auto& it : SPAWN_TYPES) + { + pb = static_cast(pw->SearchControl(it.first)); + if (pb != nullptr) + { + pb->SetState(STATE_ENABLE, it.second != m_spawningType); + } + } +} + +void CDebugMenu::DestroyInterface() +{ + m_interface->DeleteControl(EVENT_WINDOW7); + m_spawningType = OBJECT_NULL; +} + +bool CDebugMenu::EventProcess(const Event &event) +{ + switch (event.type) + { + case EVENT_DBG_STATS: + m_engine->SetShowStats(!m_engine->GetShowStats()); + UpdateInterface(); + break; + + case EVENT_DBG_SPAWN_OBJ: + DestroyInterface(); + CreateSpawnInterface(); + break; + + case EVENT_DBG_TELEPORT: + if (!m_teleportActive) + { + if (m_main->GetSelect() != nullptr) + m_teleportActive = true; + else + m_sound->Play(SOUND_CLICK); + } + else + { + m_teleportActive = false; + } + UpdateInterface(); + break; + + case EVENT_DBG_LIGHTNING: + m_lightningActive = !m_lightningActive; + UpdateInterface(); + break; + + case EVENT_DBG_RESOURCES: + m_engine->SetDebugResources(!m_engine->GetDebugResources()); + UpdateInterface(); + break; + + case EVENT_DBG_GOTO: + m_engine->SetDebugGoto(!m_engine->GetDebugGoto()); + UpdateInterface(); + break; + + case EVENT_DBG_CRASHSPHERES: + m_main->SetDebugCrashSpheres(!m_main->GetDebugCrashSpheres()); + UpdateInterface(); + break; + + case EVENT_DBG_LIGHTS: + m_engine->SetDebugLights(!m_engine->GetDebugLights()); + UpdateInterface(); + break; + + case EVENT_DBG_LIGHTS_DUMP: + m_engine->DebugDumpLights(); + break; + + + case EVENT_SPAWN_CANCEL: + DestroyInterface(); + CreateInterface(); + break; + + case EVENT_SPAWN_ME: + case EVENT_SPAWN_WHEELEDGRABBER: + case EVENT_SPAWN_WHEELEDSHOOTER: + case EVENT_SPAWN_PHAZERSHOOTER: + case EVENT_SPAWN_BOTFACTORY: + case EVENT_SPAWN_CONVERTER: + case EVENT_SPAWN_DERRICK: + case EVENT_SPAWN_POWERSTATION: + case EVENT_SPAWN_TITANIUM: + case EVENT_SPAWN_TITANIUMORE: + case EVENT_SPAWN_URANIUMORE: + case EVENT_SPAWN_POWERCELL: + case EVENT_SPAWN_NUCLEARCELL: + m_spawningType = SPAWN_TYPES.at(event.type); + UpdateInterface(); + break; + + case EVENT_MOUSE_BUTTON_DOWN: + if (event.GetData()->button == MOUSE_BUTTON_LEFT) + { + if (m_lightningActive) + { + return !HandleLightning(event.mousePos); + } + + if (m_teleportActive) + { + return !HandleTeleport(event.mousePos); + } + + if (m_spawningType != OBJECT_NULL) + { + return !HandleSpawnObject(m_spawningType, event.mousePos); + } + } + break; + + case EVENT_MOUSE_MOVE: + if (m_spawningType != OBJECT_NULL || m_teleportActive || m_lightningActive) + { + return false; + } + break; + + + default: + break; + } + return true; +} + +bool CDebugMenu::HandleSpawnObject(ObjectType type, Math::Point mousePos) +{ + Math::Vector pos; + if (m_engine->DetectObject(mousePos, pos, true) == -1) + { + m_sound->Play(SOUND_CLICK, 1.0f, 0.5f); + return false; + } + + ObjectCreateParams params; + params.pos = pos; + params.type = type; + params.power = 100.0f; + m_objMan->CreateObject(params); + + // Update shortcuts in the upper-left corner + m_main->CreateShortcuts(); + + m_sound->Play(SOUND_RADAR, 2.0f, 1.5f); + + return true; +} + +bool CDebugMenu::HandleLightning(Math::Point mousePos) +{ + Math::Vector pos; + if (m_engine->DetectObject(mousePos, pos, true) == -1) + { + m_sound->Play(SOUND_CLICK, 1.0f, 0.5f); + return false; + } + + m_engine->GetLightning()->StrikeAtPos(pos); + + return true; +} + +bool CDebugMenu::HandleTeleport(Math::Point mousePos) +{ + CObject* select = m_main->GetSelect(); + + Math::Vector pos; + if (m_engine->DetectObject(mousePos, pos, true) == -1 || !m_engine->GetTerrain()->AdjustToFloor(pos) || select == nullptr) + { + m_sound->Play(SOUND_CLICK, 1.0f, 0.5f); + m_teleportActive = false; + UpdateInterface(); + return false; + } + + select->SetPosition(pos); + + m_sound->Play(SOUND_BUILD, 4.0f, 0.75f); + m_sound->Play(SOUND_BUILD, pos, 4.0f, 0.75f); + + m_teleportActive = false; + UpdateInterface(); + + return true; +} + +} diff --git a/src/ui/debug_menu.h b/src/ui/debug_menu.h new file mode 100644 index 00000000..a45623ac --- /dev/null +++ b/src/ui/debug_menu.h @@ -0,0 +1,71 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include "math/point.h" + +#include "object/object_type.h" + +class CRobotMain; +class CObjectManager; +class CSoundInterface; +struct Event; + +namespace Gfx +{ +class CEngine; +} + +namespace Ui +{ +class CInterface; + +class CDebugMenu +{ +public: + CDebugMenu(CRobotMain* main, Gfx::CEngine* engine, CObjectManager* objMan, CSoundInterface* sound); + virtual ~CDebugMenu(); + + void ToggleInterface(); + bool EventProcess(const Event& event); + +protected: + void CreateInterface(); + void CreateSpawnInterface(); + void UpdateInterface(); + void DestroyInterface(); + + bool HandleSpawnObject(ObjectType type, Math::Point mousePos); + bool HandleLightning(Math::Point mousePos); + bool HandleTeleport(Math::Point mousePos); + +protected: + CRobotMain* m_main; + CInterface* m_interface; + Gfx::CEngine* m_engine; + CObjectManager* m_objMan; + CSoundInterface* m_sound; + + ObjectType m_spawningType = OBJECT_NULL; + bool m_lightningActive = false; + bool m_teleportActive = false; +}; + +} diff --git a/src/ui/displayinfo.cpp b/src/ui/displayinfo.cpp index 0b9c1bd8..76aee701 100644 --- a/src/ui/displayinfo.cpp +++ b/src/ui/displayinfo.cpp @@ -23,7 +23,6 @@ #include "app/app.h" #include "app/pausemanager.h" -#include "common/misc.h" #include "common/restext.h" #include "common/settings.h" #include "common/stringutils.h" @@ -81,7 +80,6 @@ CDisplayInfo::CDisplayInfo() m_toto = nullptr; m_bSoluce = false; m_bEditLock = false; - m_infoCamera = Gfx::CAM_TYPE_NULL; m_index = -1; } @@ -363,9 +361,7 @@ void CDisplayInfo::StartDisplayInfo(std::string filename, int index, bool bSoluc m_main->SetEditLock(true, false); m_main->SetEditFull(false); - m_satcomPause = m_pause->ActivatePause(PAUSE_ENGINE|PAUSE_HIDE_SHORTCUTS|PAUSE_MUTE_SOUND, PAUSE_MUSIC_SATCOM); - m_infoCamera = m_camera->GetType(); - m_camera->SetType(Gfx::CAM_TYPE_INFO); + m_satcomPause = m_pause->ActivatePause(PAUSE_ENGINE|PAUSE_HIDE_SHORTCUTS|PAUSE_MUTE_SOUND|PAUSE_CAMERA, PAUSE_MUSIC_SATCOM); pw = static_cast(m_interface->SearchControl(EVENT_WINDOW6)); if (pw != nullptr) pw->ClearState(STATE_VISIBLE | STATE_ENABLE); @@ -834,7 +830,6 @@ void CDisplayInfo::StopDisplayInfo() } m_pause->DeactivatePause(m_satcomPause); m_satcomPause = nullptr; - m_camera->SetType(m_infoCamera); m_engine->SetDrawWorld(true); // draws all on the interface m_engine->SetDrawFront(false); // draws nothing on the interface diff --git a/src/ui/displayinfo.h b/src/ui/displayinfo.h index ff43b1eb..eea3b255 100644 --- a/src/ui/displayinfo.h +++ b/src/ui/displayinfo.h @@ -19,7 +19,7 @@ #pragma once -#include "graphics/engine/camera.h" +#include "math/point.h" #include @@ -32,6 +32,7 @@ struct Event; namespace Gfx { +class CCamera; class CEngine; class CParticle; class CLightManager; @@ -80,7 +81,6 @@ protected: bool m_bInfoMinimized; int m_index; - Gfx::CameraType m_infoCamera; Math::Point m_infoNormalPos; Math::Point m_infoNormalDim; Math::Point m_infoActualPos; diff --git a/src/ui/mainui.cpp b/src/ui/mainui.cpp index 2a60dae6..f373d692 100644 --- a/src/ui/mainui.cpp +++ b/src/ui/mainui.cpp @@ -148,7 +148,7 @@ CScreenSetup* CMainUserInterface::GetSetupScreen(Phase phase) void CMainUserInterface::ChangePhase(Phase phase) { - m_main->GetCamera()->SetType(Gfx::CAM_TYPE_DIALOG); + m_main->GetCamera()->SetType(Gfx::CAM_TYPE_NULL); m_engine->SetOverFront(false); m_engine->SetOverColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f), Gfx::ENG_RSTATE_TCOLOR_BLACK); // TODO: color ok? diff --git a/src/ui/object_interface.cpp b/src/ui/object_interface.cpp index 81a68006..44140059 100644 --- a/src/ui/object_interface.cpp +++ b/src/ui/object_interface.cpp @@ -1302,8 +1302,9 @@ bool CObjectInterface::CreateInterface(bool bSelect) pw->CreateButton(pos, ddim, 19, EVENT_OBJECT_HELP); } - if ( type != OBJECT_HUMAN && - type != OBJECT_TECH && +//camera button no more disabled for humans + if ( //type != OBJECT_HUMAN && + //type != OBJECT_TECH && !m_object->GetCameraLock() ) { //? if ( m_main->GetShowMap() ) @@ -1323,26 +1324,6 @@ bool CObjectInterface::CreateInterface(bool bSelect) } } - if ( m_object->GetToy() && !m_object->GetManual() ) - { - pos.x = ox+sx*9.0f; - pos.y = oy+sy*0; - pb = pw->CreateButton(pos, dim, 55, EVENT_OBJECT_CAMERAleft); - pb->SetImmediat(true); - pos.x = ox+sx*11.0f; - pos.y = oy+sy*0; - pb = pw->CreateButton(pos, dim, 48, EVENT_OBJECT_CAMERAright); - pb->SetImmediat(true); - pos.x = ox+sx*10.0f; - pos.y = oy+sy*1; - pb = pw->CreateButton(pos, dim, 49, EVENT_OBJECT_CAMERAnear); - pb->SetImmediat(true); - pos.x = ox+sx*10.0f; - pos.y = oy+sy*0; - pb = pw->CreateButton(pos, dim, 50, EVENT_OBJECT_CAMERAaway); - pb->SetImmediat(true); - } - pos.x = ox+sx*13.4f; pos.y = oy+sy*0; if ( m_object->GetTrainer() ) // Training? @@ -1396,29 +1377,33 @@ bool CObjectInterface::CreateInterface(bool bSelect) pt->ClearState(STATE_GLINT); } - ddim.x = 64.0f/640.0f; - ddim.y = 64.0f/480.0f; - pos.x = 30.0f/640.0f; - pos.y = 430.0f/480.0f-ddim.y; - pw->CreateGroup(pos, ddim, 13, EVENT_OBJECT_CORNERul); + if (type != OBJECT_HUMAN && + type != OBJECT_TECH) + { + ddim.x = 64.0f / 640.0f; + ddim.y = 64.0f / 480.0f; + pos.x = 30.0f / 640.0f; + pos.y = 430.0f / 480.0f - ddim.y; + pw->CreateGroup(pos, ddim, 13, EVENT_OBJECT_CORNERul); - ddim.x = 64.0f/640.0f; - ddim.y = 64.0f/480.0f; - pos.x = 610.0f/640.0f-ddim.x; - pos.y = 430.0f/480.0f-ddim.y; - pw->CreateGroup(pos, ddim, 14, EVENT_OBJECT_CORNERur); + ddim.x = 64.0f / 640.0f; + ddim.y = 64.0f / 480.0f; + pos.x = 610.0f / 640.0f - ddim.x; + pos.y = 430.0f / 480.0f - ddim.y; + pw->CreateGroup(pos, ddim, 14, EVENT_OBJECT_CORNERur); - ddim.x = 64.0f/640.0f; - ddim.y = 64.0f/480.0f; - pos.x = 30.0f/640.0f; - pos.y = 110.0f/480.0f; - pw->CreateGroup(pos, ddim, 15, EVENT_OBJECT_CORNERdl); + ddim.x = 64.0f / 640.0f; + ddim.y = 64.0f / 480.0f; + pos.x = 30.0f / 640.0f; + pos.y = 110.0f / 480.0f; + pw->CreateGroup(pos, ddim, 15, EVENT_OBJECT_CORNERdl); - ddim.x = 64.0f/640.0f; - ddim.y = 64.0f/480.0f; - pos.x = 610.0f/640.0f-ddim.x; - pos.y = 110.0f/480.0f; - pw->CreateGroup(pos, ddim, 16, EVENT_OBJECT_CORNERdr); + ddim.x = 64.0f / 640.0f; + ddim.y = 64.0f / 480.0f; + pos.x = 610.0f / 640.0f - ddim.x; + pos.y = 110.0f / 480.0f; + pw->CreateGroup(pos, ddim, 16, EVENT_OBJECT_CORNERdr); + } UpdateInterface(); m_lastUpdateTime = 0.0f; @@ -1618,7 +1603,6 @@ void CObjectInterface::UpdateInterface() CSlider* ps; CColor* pc; bool bFly, bRun; - char title[100]; if ( !m_object->GetSelect() ) return; @@ -1638,7 +1622,7 @@ void CObjectInterface::UpdateInterface() bool bProgEnable = !m_programmable->IsProgram() && m_main->CanPlayerInteract(); bool scriptSelected = m_selScript >= 0 && m_selScript < m_programStorage->GetProgramCount(); - EnableInterface(pw, EVENT_OBJECT_PROGEDIT, m_main->CanPlayerInteract() && scriptSelected && !m_programmable->IsTraceRecord()); + EnableInterface(pw, EVENT_OBJECT_PROGEDIT, scriptSelected && !m_programmable->IsTraceRecord()); EnableInterface(pw, EVENT_OBJECT_PROGLIST, bProgEnable && !m_programmable->IsTraceRecord()); EnableInterface(pw, EVENT_OBJECT_PROGADD, bProgEnable); EnableInterface(pw, EVENT_OBJECT_PROGREMOVE, bProgEnable && scriptSelected && !m_programStorage->GetProgram(m_selScript)->readOnly); @@ -1788,8 +1772,8 @@ void CObjectInterface::UpdateInterface() { if (m_programStorage->GetProgram(m_selScript)->runnable) { - m_programStorage->GetProgram(m_selScript)->script->GetTitle(title); - if ( title[0] != 0 ) + std::string title = m_programStorage->GetProgram(m_selScript)->script->GetTitle(); + if ( !title.empty() ) { bRun = true; } @@ -1938,7 +1922,6 @@ void CObjectInterface::UpdateScript(CWindow *pw) { CList* pl; char name[100]; - char title[100]; pl = static_cast< CList* >(pw->SearchControl(EVENT_OBJECT_PROGLIST)); if ( pl == nullptr ) return; @@ -1948,16 +1931,16 @@ void CObjectInterface::UpdateScript(CWindow *pw) { sprintf(name, "%d", i+1); - m_programStorage->GetProgram(i)->script->GetTitle(title); - if ( title[0] != 0 ) + std::string title = m_programStorage->GetProgram(i)->script->GetTitle(); + if ( !title.empty() ) { if(!m_programStorage->GetProgram(i)->readOnly) { - sprintf(name, "%d: %s", i+1, title); + sprintf(name, "%d: %s", i+1, title.c_str()); } else { - sprintf(name, "*%d: %s", i+1, title); + sprintf(name, "*%d: %s", i+1, title.c_str()); } } diff --git a/src/ui/screen/screen_apperance.cpp b/src/ui/screen/screen_apperance.cpp index 82c92266..3e8cdd0d 100644 --- a/src/ui/screen/screen_apperance.cpp +++ b/src/ui/screen/screen_apperance.cpp @@ -164,13 +164,13 @@ void CScreenApperance::CreateInterface() pb = pw->CreateButton(pos, ddim, 43, EVENT_INTERFACE_PFACE1); pb->SetState(STATE_SHADOW); pos.x += 50.0f/640.0f; - pb = pw->CreateButton(pos, ddim, 46, EVENT_INTERFACE_PFACE4); + pb = pw->CreateButton(pos, ddim, 44, EVENT_INTERFACE_PFACE2); pb->SetState(STATE_SHADOW); pos.x += 50.0f/640.0f; pb = pw->CreateButton(pos, ddim, 45, EVENT_INTERFACE_PFACE3); pb->SetState(STATE_SHADOW); pos.x += 50.0f/640.0f; - pb = pw->CreateButton(pos, ddim, 44, EVENT_INTERFACE_PFACE2); + pb = pw->CreateButton(pos, ddim, 46, EVENT_INTERFACE_PFACE4); pb->SetState(STATE_SHADOW); // Glasses @@ -349,6 +349,7 @@ bool CScreenApperance::EventProcess(const Event &event) case EVENT_INTERFACE_PFACE3: case EVENT_INTERFACE_PFACE4: apperance.face = event.type-EVENT_INTERFACE_PFACE1; + apperance.DefHairColor(); UpdatePerso(); m_main->ScenePerso(); break; @@ -618,21 +619,17 @@ void CScreenApperance::CameraPerso() { Gfx::CCamera* camera = m_main->GetCamera(); + camera->SetType(Gfx::CAM_TYPE_SCRIPT); if ( m_apperanceTab == 0 ) { -//? camera->Init(Math::Vector(4.0f, 0.0f, 0.0f), -//? Math::Vector(0.0f, 0.0f, 1.0f), 0.0f); - camera->Init(Math::Vector(6.0f, 0.0f, 0.0f), - Math::Vector(0.0f, 0.2f, 1.5f), 0.0f); + camera->SetScriptCamera(Math::Vector(6.0f, 0.0f, 0.0f), + Math::Vector(0.0f, 0.2f, 1.5f)); } else { - camera->Init(Math::Vector(18.0f, 0.0f, 4.5f), - Math::Vector(0.0f, 1.6f, 4.5f), 0.0f); + camera->SetScriptCamera(Math::Vector(18.0f, 0.0f, 4.5f), + Math::Vector(0.0f, 1.6f, 4.5f)); } - - camera->SetType(Gfx::CAM_TYPE_SCRIPT); - camera->FixCamera(); } // Sets a fixed color. diff --git a/src/ui/screen/screen_io.cpp b/src/ui/screen/screen_io.cpp index 749a6540..82db8d12 100644 --- a/src/ui/screen/screen_io.cpp +++ b/src/ui/screen/screen_io.cpp @@ -20,7 +20,6 @@ #include "ui/screen/screen_io.h" #include "common/logger.h" -#include "common/misc.h" #include "common/restext.h" #include "common/stringutils.h" @@ -81,7 +80,7 @@ void CScreenIO::IOReadName() } time(&now); - TimeToAsciiClean(now, line); + strftime(line, 99, "%y.%m.%d %H:%M", localtime(&now)); sprintf(name, "%s - %s %d", line, resume.c_str(), m_main->GetLevelRank()); pe->SetText(name); diff --git a/src/ui/screen/screen_level_list.cpp b/src/ui/screen/screen_level_list.cpp index ee91369d..38110358 100644 --- a/src/ui/screen/screen_level_list.cpp +++ b/src/ui/screen/screen_level_list.cpp @@ -47,7 +47,6 @@ namespace Ui CScreenLevelList::CScreenLevelList(CMainDialog* mainDialog) : m_dialog(mainDialog), m_category{}, - m_listCategory{}, m_sceneSoluce{false}, m_maxList{0}, m_accessChap{0} @@ -57,15 +56,6 @@ CScreenLevelList::CScreenLevelList(CMainDialog* mainDialog) void CScreenLevelList::SetLevelCategory(LevelCategory category) { m_category = category; - - if ( static_cast(m_category) >= static_cast(LevelCategory::Max) ) - { - m_category = m_listCategory; - } - else - { - m_listCategory = m_category; - } } void CScreenLevelList::CreateInterface() diff --git a/src/ui/screen/screen_level_list.h b/src/ui/screen/screen_level_list.h index 2073e546..b27f88c1 100644 --- a/src/ui/screen/screen_level_list.h +++ b/src/ui/screen/screen_level_list.h @@ -63,7 +63,6 @@ protected: Ui::CMainDialog* m_dialog; LevelCategory m_category; - LevelCategory m_listCategory; bool m_sceneSoluce; diff --git a/src/ui/screen/screen_main_menu.cpp b/src/ui/screen/screen_main_menu.cpp index fa016a3d..ea8a29c2 100644 --- a/src/ui/screen/screen_main_menu.cpp +++ b/src/ui/screen/screen_main_menu.cpp @@ -163,9 +163,11 @@ void CScreenMainMenu::CreateInterface() pl->SetFontSize(Gfx::FONT_SIZE_SMALL); // SatCom button - pos.x = ox+sx*4.4f; - pos.y = oy+sy*4.4f; - pb = pw->CreateButton(pos, dim, 128+60, EVENT_INTERFACE_SATCOM); + pos.x = ox+sx*4.3f; + pos.y = oy+sy*4.3f; + ddim.x = dim.x*1.2f; + ddim.y = dim.y*1.2f; + pb = pw->CreateButton(pos, ddim, 128+60, EVENT_INTERFACE_SATCOM); pb->SetState(STATE_SHADOW); SetBackground("textures/interface/interface.png"); diff --git a/src/ui/screen/screen_player_select.cpp b/src/ui/screen/screen_player_select.cpp index f4f30c9a..678f8286 100644 --- a/src/ui/screen/screen_player_select.cpp +++ b/src/ui/screen/screen_player_select.cpp @@ -22,7 +22,6 @@ #include "app/app.h" #include "common/logger.h" -#include "common/misc.h" #include "common/stringutils.h" #include "level/player_profile.h" @@ -371,9 +370,6 @@ bool CScreenPlayerSelect::NameCreate() { CWindow* pw; CEdit* pe; - char name[100]; - char c; - int len, i, j; GetLogger()->Info("Creating new player\n"); pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); @@ -381,6 +377,7 @@ bool CScreenPlayerSelect::NameCreate() pe = static_cast(pw->SearchControl(EVENT_INTERFACE_NEDIT)); if ( pe == nullptr ) return false; + char name[100]; pe->GetText(name, 100); if ( name[0] == 0 ) { @@ -388,30 +385,6 @@ bool CScreenPlayerSelect::NameCreate() return false; } - len = strlen(name); - j = 0; - for ( i=0 ; i= '0' && c <= '9') || - (c >= 'a' && c <= 'z') || - c == ' ' || - c == '-' || - c == '_' || - c == '.' || - c == ',' || - c == '\'' ) - { - name[j++] = name[i]; - } - } - name[j] = 0; - if ( j == 0 ) - { - m_sound->Play(SOUND_TZOING); - return false; - } - m_main->SelectPlayer(name); m_main->GetPlayerProfile()->Create(); diff --git a/src/ui/screen/screen_setup.cpp b/src/ui/screen/screen_setup.cpp index 4d5c5978..7f20eabe 100644 --- a/src/ui/screen/screen_setup.cpp +++ b/src/ui/screen/screen_setup.cpp @@ -153,7 +153,6 @@ bool CScreenSetup::EventProcess(const Event &event) (event.type == EVENT_KEY_DOWN && event.GetData()->key == KEY(ESCAPE)) ) { m_settings->SaveSettings(); - m_engine->ApplyChange(); m_main->ChangePhase(PHASE_MAIN_MENU); return false; } @@ -194,7 +193,6 @@ bool CScreenSetup::EventProcess(const Event &event) (event.type == EVENT_KEY_DOWN && event.GetData()->key == KEY(ESCAPE)) ) { m_settings->SaveSettings(); - m_engine->ApplyChange(); m_interface->DeleteControl(EVENT_WINDOW5); m_main->ChangePhase(PHASE_SIMUL); m_main->StopSuspend(); diff --git a/src/ui/screen/screen_setup_controls.cpp b/src/ui/screen/screen_setup_controls.cpp index bdb2c5c8..7aa39ebe 100644 --- a/src/ui/screen/screen_setup_controls.cpp +++ b/src/ui/screen/screen_setup_controls.cpp @@ -103,63 +103,40 @@ void CScreenSetupControls::CreateInterface() ddim.x = 160.0f/640.0f; ddim.y = 80.0f/480.0f; pos.x = 400.0f/640.0f; - pos.y = 213.0f/480.0f; + pos.y = 273.0f/480.0f; pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_JOYSTICK); pli->SetState(STATE_SHADOW); ddim.x = dim.x*1.5f; ddim.y = 18.0f/480.0f; - pos.y = 180.0f/480.0f; + pos.y = 240.0f/480.0f; - pos.y -= 5.0f/480.0f; - pos.x = 390.0f/640.0f; - pw->CreateLabel(pos, ddim, 0, EVENT_LABEL0, "X:"); - pos.y += 5.0f/480.0f; - pos.x = 422.0f/640.0f; - pev = pw->CreateEditValue(pos, ddim, 0, EVENT_INTERFACE_JOYSTICK_X); - pev->SetState(STATE_SHADOW); - pev->SetType(EVT_INT); - pev->SetMinValue(0); - pev->SetMaxValue(2); - pev->SetStepValue(1); - pev->SetValue(0); - pos.x = 480.0f/640.0f; - pc = pw->CreateCheck(pos, ddim, 0, EVENT_INTERFACE_JOYSTICK_X_INVERT); - pc->SetState(STATE_SHADOW); - - pos.y -= 20.0f/480.0f; - pos.x = 390.0f/640.0f; - pos.y -= 5.0f/480.0f; - pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, "Y:"); - pos.y += 5.0f/480.0f; - pos.x = 422.0f/640.0f; - pev = pw->CreateEditValue(pos, ddim, 0, EVENT_INTERFACE_JOYSTICK_Y); - pev->SetState(STATE_SHADOW); - pev->SetType(EVT_INT); - pev->SetMinValue(0); - pev->SetMaxValue(2); - pev->SetStepValue(1); - pev->SetValue(1); - pos.x = 480.0f/640.0f; - pc = pw->CreateCheck(pos, ddim, 0, EVENT_INTERFACE_JOYSTICK_Y_INVERT); - pc->SetState(STATE_SHADOW); - - pos.y -= 20.0f/480.0f; - pos.x = 390.0f/640.0f; - pos.y -= 5.0f/480.0f; - pw->CreateLabel(pos, ddim, 0, EVENT_LABEL2, "Z:"); - pos.y += 5.0f/480.0f; - pos.x = 422.0f/640.0f; - pev = pw->CreateEditValue(pos, ddim, 0, EVENT_INTERFACE_JOYSTICK_Z); - pev->SetState(STATE_SHADOW); - pev->SetType(EVT_INT); - pev->SetMinValue(0); - pev->SetMaxValue(2); - pev->SetStepValue(1); - pev->SetValue(2); - pos.x = 480.0f/640.0f; - pc = pw->CreateCheck(pos, ddim, 0, EVENT_INTERFACE_JOYSTICK_Z_INVERT); - pc->SetState(STATE_SHADOW); + auto CreateJoystickControls = [&](const std::string& label, EventType bindingControl, EventType invertControl) + { + pos.y -= 20.0f/480.0f; + pos.x = 390.0f/640.0f; + pos.y -= 5.0f/480.0f; + pw->CreateLabel(pos, ddim, 0, EVENT_LABEL0, label); + pos.y += 5.0f/480.0f; + pos.x = 442.0f/640.0f; + pev = pw->CreateEditValue(pos, ddim, 0, bindingControl); + pev->SetState(STATE_SHADOW); + pev->SetType(EVT_INT); + pev->SetMinValue(-1); + pev->SetMaxValue(2); + pev->SetStepValue(1); + pev->SetValue(1); + pos.x = 500.0f/640.0f; + pc = pw->CreateCheck(pos, ddim, 0, invertControl); + pc->SetState(STATE_SHADOW); + }; + pos.y += 15.0f/480.0f; + CreateJoystickControls("X:", EVENT_INTERFACE_JOYSTICK_X, EVENT_INTERFACE_JOYSTICK_X_INVERT); + CreateJoystickControls("Y:", EVENT_INTERFACE_JOYSTICK_Y, EVENT_INTERFACE_JOYSTICK_Y_INVERT); + CreateJoystickControls("Z:", EVENT_INTERFACE_JOYSTICK_Z, EVENT_INTERFACE_JOYSTICK_Z_INVERT); + CreateJoystickControls("CamX:", EVENT_INTERFACE_JOYSTICK_CAM_X, EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT); + CreateJoystickControls("CamY:", EVENT_INTERFACE_JOYSTICK_CAM_Y, EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT); + CreateJoystickControls("CamZ:", EVENT_INTERFACE_JOYSTICK_CAM_Z, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT); pos.y -= 25.0f/480.0f; pos.x = 420.0f/640.0f; @@ -203,6 +180,9 @@ bool CScreenSetupControls::EventProcess(const Event &event) case EVENT_INTERFACE_JOYSTICK_X_INVERT: case EVENT_INTERFACE_JOYSTICK_Y_INVERT: case EVENT_INTERFACE_JOYSTICK_Z_INVERT: + case EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT: + case EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT: + case EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT: ToggleJoystickInvert(event.type); ChangeSetupButtons(); UpdateSetupButtons(); @@ -212,6 +192,9 @@ bool CScreenSetupControls::EventProcess(const Event &event) case EVENT_INTERFACE_JOYSTICK_X: case EVENT_INTERFACE_JOYSTICK_Y: case EVENT_INTERFACE_JOYSTICK_Z: + case EVENT_INTERFACE_JOYSTICK_CAM_X: + case EVENT_INTERFACE_JOYSTICK_CAM_Y: + case EVENT_INTERFACE_JOYSTICK_CAM_Z: case EVENT_INTERFACE_JOYSTICK_DEADZONE: ChangeSetupButtons(); UpdateSetupButtons(); @@ -254,42 +237,28 @@ void CScreenSetupControls::ChangeSetupButtons() } } - if (nullptr != (pev = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_X)))) + auto HandleJoystickControls = [&](JoyAxisSlot joyAxis, EventType bindingControl, EventType invertControl) { - JoyAxisBinding binding = m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_X); - binding.axis = static_cast(round(pev->GetValue())); - m_input->SetJoyAxisBinding(JOY_AXIS_SLOT_X, binding); - } - if (nullptr != (pc = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_X_INVERT)))) - { - JoyAxisBinding binding = m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_X); - binding.invert = pc->TestState(STATE_CHECK); - m_input->SetJoyAxisBinding(JOY_AXIS_SLOT_X, binding); - } - if (nullptr != (pev = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_Y)))) - { - JoyAxisBinding binding = m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_Y); - binding.axis = static_cast(round(pev->GetValue())); - m_input->SetJoyAxisBinding(JOY_AXIS_SLOT_Y, binding); - } - if (nullptr != (pc = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_Y_INVERT)))) - { - JoyAxisBinding binding = m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_Y); - binding.invert = pc->TestState(STATE_CHECK); - m_input->SetJoyAxisBinding(JOY_AXIS_SLOT_Y, binding); - } - if (nullptr != (pev = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_Z)))) - { - JoyAxisBinding binding = m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_Z); - binding.axis = static_cast(round(pev->GetValue())); - m_input->SetJoyAxisBinding(JOY_AXIS_SLOT_Z, binding); - } - if (nullptr != (pc = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_Z_INVERT)))) - { - JoyAxisBinding binding = m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_Z); - binding.invert = pc->TestState(STATE_CHECK); - m_input->SetJoyAxisBinding(JOY_AXIS_SLOT_Z, binding); - } + if (nullptr != (pev = static_cast(pw->SearchControl(bindingControl)))) + { + JoyAxisBinding binding = m_input->GetJoyAxisBinding(joyAxis); + binding.axis = static_cast(round(pev->GetValue())); + m_input->SetJoyAxisBinding(joyAxis, binding); + } + if (nullptr != (pc = static_cast(pw->SearchControl(invertControl)))) + { + JoyAxisBinding binding = m_input->GetJoyAxisBinding(joyAxis); + binding.invert = pc->TestState(STATE_CHECK); + m_input->SetJoyAxisBinding(joyAxis, binding); + } + }; + HandleJoystickControls(JOY_AXIS_SLOT_X, EVENT_INTERFACE_JOYSTICK_X, EVENT_INTERFACE_JOYSTICK_X_INVERT); + HandleJoystickControls(JOY_AXIS_SLOT_Y, EVENT_INTERFACE_JOYSTICK_Y, EVENT_INTERFACE_JOYSTICK_Y_INVERT); + HandleJoystickControls(JOY_AXIS_SLOT_Z, EVENT_INTERFACE_JOYSTICK_Z, EVENT_INTERFACE_JOYSTICK_Z_INVERT); + HandleJoystickControls(JOY_AXIS_SLOT_CAM_X, EVENT_INTERFACE_JOYSTICK_CAM_X, EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT); + HandleJoystickControls(JOY_AXIS_SLOT_CAM_Y, EVENT_INTERFACE_JOYSTICK_CAM_Y, EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT); + HandleJoystickControls(JOY_AXIS_SLOT_CAM_Z, EVENT_INTERFACE_JOYSTICK_CAM_Z, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT); + if (nullptr != (pev = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_DEADZONE)))) { m_input->SetJoystickDeadzone(pev->GetValue()); @@ -332,39 +301,27 @@ void CScreenSetupControls::UpdateSetupButtons() pli->SetSelect(m_app->GetJoystickEnabled() ? m_app->GetJoystick().index + 1 : 0); } - if (nullptr != (pev = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_X)))) + auto HandleJoystickControls = [&](JoyAxisSlot joyAxis, EventType bindingControl, EventType invertControl) { - pev->SetState(STATE_ENABLE, m_app->GetJoystickEnabled()); - pev->SetMaxValue(m_app->GetJoystick().axisCount-1); - pev->SetValue(m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_X).axis); - } - if (nullptr != (pc = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_X_INVERT)))) - { - pc->SetState(STATE_ENABLE, m_app->GetJoystickEnabled()); - pc->SetState(STATE_CHECK, m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_X).invert); - } - if (nullptr != (pev = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_Y)))) - { - pev->SetState(STATE_ENABLE, m_app->GetJoystickEnabled()); - pev->SetMaxValue(m_app->GetJoystick().axisCount-1); - pev->SetValue(m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_Y).axis); - } - if (nullptr != (pc = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_Y_INVERT)))) - { - pc->SetState(STATE_ENABLE, m_app->GetJoystickEnabled()); - pc->SetState(STATE_CHECK, m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_Y).invert); - } - if (nullptr != (pev = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_Z)))) - { - pev->SetState(STATE_ENABLE, m_app->GetJoystickEnabled()); - pev->SetMaxValue(m_app->GetJoystick().axisCount-1); - pev->SetValue(m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_Z).axis); - } - if (nullptr != (pc = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_Z_INVERT)))) - { - pc->SetState(STATE_ENABLE, m_app->GetJoystickEnabled()); - pc->SetState(STATE_CHECK, m_input->GetJoyAxisBinding(JOY_AXIS_SLOT_Z).invert); - } + if (nullptr != (pev = static_cast(pw->SearchControl(bindingControl)))) + { + pev->SetState(STATE_ENABLE, m_app->GetJoystickEnabled()); + pev->SetMaxValue(m_app->GetJoystick().axisCount-1); + pev->SetValue(m_input->GetJoyAxisBinding(joyAxis).axis); + } + if (nullptr != (pc = static_cast(pw->SearchControl(invertControl)))) + { + pc->SetState(STATE_ENABLE, m_app->GetJoystickEnabled()); + pc->SetState(STATE_CHECK, m_input->GetJoyAxisBinding(joyAxis).invert); + } + }; + HandleJoystickControls(JOY_AXIS_SLOT_X, EVENT_INTERFACE_JOYSTICK_X, EVENT_INTERFACE_JOYSTICK_X_INVERT); + HandleJoystickControls(JOY_AXIS_SLOT_Y, EVENT_INTERFACE_JOYSTICK_Y, EVENT_INTERFACE_JOYSTICK_Y_INVERT); + HandleJoystickControls(JOY_AXIS_SLOT_Z, EVENT_INTERFACE_JOYSTICK_Z, EVENT_INTERFACE_JOYSTICK_Z_INVERT); + HandleJoystickControls(JOY_AXIS_SLOT_CAM_X, EVENT_INTERFACE_JOYSTICK_CAM_X, EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT); + HandleJoystickControls(JOY_AXIS_SLOT_CAM_Y, EVENT_INTERFACE_JOYSTICK_CAM_Y, EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT); + HandleJoystickControls(JOY_AXIS_SLOT_CAM_Z, EVENT_INTERFACE_JOYSTICK_CAM_Z, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT); + if (nullptr != (pev = static_cast(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_DEADZONE)))) { pev->SetState(STATE_ENABLE, m_app->GetJoystickEnabled()); diff --git a/src/ui/screen/screen_setup_graphics.cpp b/src/ui/screen/screen_setup_graphics.cpp index 83713b70..45808135 100644 --- a/src/ui/screen/screen_setup_graphics.cpp +++ b/src/ui/screen/screen_setup_graphics.cpp @@ -112,6 +112,9 @@ void CScreenSetupGraphics::CreateInterface() { pc->SetState(STATE_DEAD); } + pos.y -= 0.048f; + pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_PAUSE_BLUR); + pc->SetState(STATE_SHADOW); pos.x = ox+sx*8.5f; pos.y = 0.65f; @@ -248,8 +251,12 @@ bool CScreenSetupGraphics::EventProcess(const Event &event) switch( event.type ) { case EVENT_INTERFACE_PARTI: + ChangeSetupButtons(); + break; + case EVENT_INTERFACE_CLIP: ChangeSetupButtons(); + m_engine->ApplyChange(); break; case EVENT_INTERFACE_DIRTY: @@ -268,6 +275,11 @@ bool CScreenSetupGraphics::EventProcess(const Event &event) UpdateSetupButtons(); break; + case EVENT_INTERFACE_PAUSE_BLUR: + m_engine->SetPauseBlurEnabled(!m_engine->GetPauseBlurEnabled()); + UpdateSetupButtons(); + break; + case EVENT_INTERFACE_SHADOW_SPOTS: m_engine->SetShadowMapping(false); m_engine->SetShadowMappingQuality(false); @@ -359,6 +371,12 @@ void CScreenSetupGraphics::UpdateSetupButtons() pc->SetState(STATE_CHECK, m_engine->GetLightMode()); } + pc = static_cast(pw->SearchControl(EVENT_INTERFACE_PAUSE_BLUR)); + if ( pc != nullptr ) + { + pc->SetState(STATE_CHECK, m_engine->GetPauseBlurEnabled()); + } + pc = static_cast(pw->SearchControl(EVENT_INTERFACE_SHADOW_SPOTS)); if ( pc != nullptr ) { diff --git a/src/ui/studio.cpp b/src/ui/studio.cpp index 1b7da4ec..22268ecb 100644 --- a/src/ui/studio.cpp +++ b/src/ui/studio.cpp @@ -25,7 +25,6 @@ #include "common/event.h" #include "common/logger.h" -#include "common/misc.h" #include "common/settings.h" #include "common/resources/resourcemanager.h" @@ -63,6 +62,7 @@ #include "ui/controls/window.h" #include +#include namespace Ui @@ -425,15 +425,9 @@ bool CStudio::EventFrame(const Event &event) // Indicates whether a character is part of a word. -bool IsToken(int character) +bool IsToken(char c) { - char c; - - c = tolower(GetNoAccent(character)); - - return ( (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') || - c == '_' ); + return ( isalnum(c) || c == '_' ); } // Seeks if the cursor is on a keyword. @@ -1034,17 +1028,17 @@ void CStudio::UpdateButtons() button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_CLONE)); if ( button == nullptr ) return; - button->SetState(STATE_ENABLE, m_program->runnable && !m_bRunning); + button->SetState(STATE_ENABLE, m_main->CanPlayerInteract() && (m_program->runnable && !m_bRunning)); button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_COMPILE)); if ( button == nullptr ) return; - button->SetState(STATE_ENABLE, m_program->runnable && !m_bRunning); + button->SetState(STATE_ENABLE, m_main->CanPlayerInteract() && (m_program->runnable && !m_bRunning)); button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_RUN)); if ( button == nullptr ) return; button->SetIcon(m_bRunning?8:21); // stop/run - button->SetState(STATE_ENABLE, m_program->runnable || m_bRunning); + button->SetState(STATE_ENABLE, m_main->CanPlayerInteract() && (m_program->runnable || m_bRunning)); button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_REALTIME)); if ( button == nullptr ) return; @@ -1282,9 +1276,9 @@ void CStudio::AdjustDialog() { pli->SetPos(ppos); pli->SetDim(ddim); - pli->SetTabs(0, ddim.x-(50.0f+130.0f+16.0f)/640.0f); + pli->SetTabs(0, ddim.x-(50.0f+140.0f+16.0f)/640.0f); pli->SetTabs(1, 50.0f/640.0f, Gfx::TEXT_ALIGN_RIGHT); - pli->SetTabs(2, 130.0f/640.0f); + pli->SetTabs(2, 140.0f/640.0f); //? pli->ShowSelect(); } @@ -1575,7 +1569,7 @@ void CStudio::UpdateDialogList() CWindow* pw; CList* pl; int i = 0; - char time[100]; + char timestr[100]; pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW9)); if ( pw == nullptr ) return; @@ -1590,8 +1584,9 @@ void CStudio::UpdateDialogList() for (auto& prog : programs) { std::ostringstream temp; - TimeToAscii(CResourceManager::GetLastModificationTime(SearchDirectory(false) + prog), time); - temp << prog << '\t' << CResourceManager::GetFileSize(SearchDirectory(false) + prog) << " \t" << time; + time_t now = CResourceManager::GetLastModificationTime(SearchDirectory(false) + prog); + strftime(timestr, 99, "%x %X", localtime(&now)); + temp << prog << '\t' << CResourceManager::GetFileSize(SearchDirectory(false) + prog) << " \t" << timestr; pl->SetItemName(i++, temp.str().c_str()); } } diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index cd684a86..2d96d59e 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -441,8 +441,7 @@ TEST_F(CBotUT, VarDefinitions) } // TODO: I don't actually know what the exact rules should be, but it looks a bit wrong -// TODO: Current version of this code causes a failed assertion -TEST_F(CBotUT, DISABLED_VarImplicitCast) +TEST_F(CBotUT, VarImplicitCast) { ExecuteTest( "extern void ImplicitCast()\n" @@ -464,14 +463,50 @@ TEST_F(CBotUT, DISABLED_VarImplicitCast) "{\n" " string a = 2;\n" " ASSERT(a == \"2\");\n" - //" a = 3;\n" - //" ASSERT(a == \"3\");\n" + " a = 3;\n" + " ASSERT(a == \"3\");\n" " string b = 2.5;\n" " ASSERT(b == \"2.5\");\n" - //" b = 3.5;\n" - //" ASSERT(b == \"3.5\");\n" + " b = 3.5;\n" + " ASSERT(b == \"3.5\");\n" "}\n" ); + + ExecuteTest( + "string func()\n" + "{\n" + " return 5;\n" + "}\n" + "extern void ImplicitCastOnReturn()\n" + "{\n" + " string a = func();\n" + " ASSERT(a == \"5\");" + "}\n" + ); +} + +TEST_F(CBotUT, ToString) +{ + ExecuteTest( + "extern void ArrayToString()\n" + "{\n" + " int[] array = {2, 4, 6};\n" + " string arrayStr = \"\"+array;\n" + " ASSERT(arrayStr == \"{ 2, 4, 6 }\");\n" + "}\n" + ); + + ExecuteTest( + "public class Test { int a = 1337; }\n" + "extern void ClassToString()\n" + "{\n" + " Test test();\n" + " string testStr = \"\"+test;\n" + " ASSERT(testStr == \"Pointer to Test( a=1337 )\");\n" + "}\n" + ); + + // TODO: IntrinsicClassToString ? (e.g. point) } TEST_F(CBotUT, Arrays) @@ -524,8 +559,7 @@ TEST_F(CBotUT, Arrays) ); } -// TODO: BAD! WRONG! NOOOOO!!! :< -TEST_F(CBotUT, DISABLED_ArraysInClasses) +TEST_F(CBotUT, ArraysInClasses) { ExecuteTest( "public class TestClass {\n" @@ -533,9 +567,9 @@ TEST_F(CBotUT, DISABLED_ArraysInClasses) " private int test2[5];\n" " \n" " public void TestClass() {\n" - " ASSERT(sizeof(test) == 0);\n" // TODO: NOT INITIALIZED - " ASSERT(sizeof(this.test) == 0);\n" // TODO: NOT INITIALIZED - " ASSERT(test == null);\n" // TODO: Again, not sure // TODO: NOT INITIALIZED + " ASSERT(sizeof(test) == 0);\n" + " ASSERT(sizeof(this.test) == 0);\n" + " ASSERT(test == null);\n" // TODO: Again, not sure " test[0] = 5;\n" " this.test[1] = 5;\n" " ASSERT(sizeof(test) == 2);\n" @@ -648,10 +682,21 @@ TEST_F(CBotUT, FunctionRedefined) "}\n", CBotErrRedefFunc ); + + ExecuteTest( + "int func(int[] test)\n" + "{\n" + " return 1;\n" + "}\n" + "int func(int[] test)\n" + "{\n" + " return 2;\n" + "}\n", + CBotErrRedefFunc + ); } -// TODO: Doesn't work -TEST_F(CBotUT, DISABLED_FunctionBadReturn) +TEST_F(CBotUT, FunctionBadReturn) { ExecuteTest( "int func()\n" @@ -662,7 +707,7 @@ TEST_F(CBotUT, DISABLED_FunctionBadReturn) "{\n" " int a = func();\n" "}\n", - static_cast(-1) // TODO: no error for that + CBotErrBadType1 ); } @@ -763,6 +808,33 @@ TEST_F(CBotUT, ClassDestructor) ); } +TEST_F(CBotUT, ClassBadNew) +{ + ExecuteTest( + "public class AClass {};\n" + "extern void ClassBadNew()\n" + "{\n" + " AClass a = new \"abc\";\n" + "}\n", + CBotErrBadNew + ); +} + +TEST_F(CBotUT, ClassCallOnNull) +{ + ExecuteTest( + "public class AClass {\n" + " public void test() {}\n" + "};\n" + "extern void ClassCallOnNull()\n" + "{\n" + " AClass a = null;\n" + " a.test();\n" + "}\n", + CBotErrNull + ); +} + TEST_F(CBotUT, ClassNullPointer) { ExecuteTest( @@ -814,8 +886,7 @@ TEST_F(CBotUT, DISABLED_ClassDestructorNaming) ); } -// TODO: This doesn't work -TEST_F(CBotUT, DISABLED_ClassMethodOverloading) +TEST_F(CBotUT, ClassMethodOverloading) { ExecuteTest( "public class TestClass {\n" @@ -847,6 +918,18 @@ TEST_F(CBotUT, ClassMethodRedefined) "}\n", CBotErrRedefFunc ); + + ExecuteTest( + "public class TestClass {\n" + " public int test(int[] test) {\n" + " return 1;\n" + " }\n" + " public int test(int[] test) {\n" + " return 2;\n" + " }\n" + "}\n", + CBotErrRedefFunc + ); } // TODO: Not only doesn't work but segfaults @@ -887,8 +970,7 @@ TEST_F(CBotUT, DISABLED_PublicClasses) ); } -// TODO: This needs to be fixed -TEST_F(CBotUT, DISABLED_WeirdThisEarlyContextSwitch_Issue436) +TEST_F(CBotUT, ThisEarlyContextSwitch_Issue436) { ExecuteTest( "public class Something {\n" @@ -912,12 +994,11 @@ TEST_F(CBotUT, DISABLED_WeirdThisEarlyContextSwitch_Issue436) ); } -// TODO: Gets a failed assertion -TEST_F(CBotUT, DISABLED_BadStringAdd_Issue535) +TEST_F(CBotUT, ClassStringAdd_Issue535) { ExecuteTest( "public class TestClass {}\n" - "extern void BadStringAdd()\n" + "extern void ClassStringAdd()\n" "{\n" " TestClass t();\n" " string s = t + \"!\";\n" @@ -955,8 +1036,7 @@ TEST_F(CBotUT, DISABLED_StringAsArray) ); } -// TODO: doesn't work, see discussion in #737 -TEST_F(CBotUT, DISABLED_ArraysOfStrings) +TEST_F(CBotUT, ArraysOfStrings) { ExecuteTest( "extern void ArraysOfStrings()\n" @@ -1052,6 +1132,19 @@ TEST_F(CBotUT, TestArrayInitialization) "}\n", CBotErrOutArray ); + + ExecuteTest( + "extern void TestArrayInitializationWithVars() {\n" + " int x=1, y=2, z=3;\n" + " int i[] = { x, y, z };\n" + " ASSERT(i[0] == 1);\n" + " ASSERT(i[1] == 2);\n" + " ASSERT(i[2] == 3);\n" + " i[0] += 1;\n" + " ASSERT(i[0] == 2);\n" + " ASSERT(x == 1);\n" + "}\n" + ); } TEST_F(CBotUT, TestArrayFunctionReturn) @@ -1070,3 +1163,28 @@ TEST_F(CBotUT, TestArrayFunctionReturn) "}\n" ); } + +TEST_F(CBotUT, AccessMembersInParameters_Issue256) +{ + ExecuteTest( + "public class Test1 {\n" + " int x = 1337;\n" + "}\n" + "public class Test2 {\n" + " public bool test(int a) {\n" + " return a == 1337;\n" + " }\n" + "}\n" + "public class Test3 {\n" + " public Test1 test1 = new Test1();\n" + " public Test2 test2 = new Test2();\n" + " public void test() {\n" + " ASSERT(test2.test(test1.x));\n" + " }\n" + "}\n" + "extern void AccessMembersInParameters() {\n" + " Test3 t();\n" + " t.test();\n" + "}\n" + ); +} diff --git a/tools/check-levels.sh b/tools/check-levels.sh index c2778673..2d980b08 100755 --- a/tools/check-levels.sh +++ b/tools/check-levels.sh @@ -13,7 +13,7 @@ for category in $categories; do if [ ! -d /usr/local/share/games/colobot/levels/$category/chapter00$chapter/$level ]; then continue; fi level=`echo -n $level | cut -d . -f 1 | tail -c 3` echo $category$chapter$level - colobot -runscene $category$chapter$level -scenetest -loglevel warn -headless 2>&1 | grep -v --line-buffered "Colobot starting" | grep -v --line-buffered "Log level changed" | grep -v --line-buffered "Running scene" + colobot -runscene $category$chapter$level -scenetest -loglevel warn -headless 2>&1 | grep -vE --line-buffered "Colobot.*starting" | grep -v --line-buffered "Log level changed" | grep -v --line-buffered "Running scene" done done done