From 81c7d05d7c5f0c31597d775810fb5ab49ec3ea71 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 2 Nov 2016 21:42:23 +0100 Subject: [PATCH 01/93] Post-release 0.1.9-alpha --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f658d005..91a862c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,9 +16,9 @@ set(COLOBOT_VERSION_MINOR 1) set(COLOBOT_VERSION_REVISION 9) # 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) From c5b5435b4a36bdc74eb80f6c0c966753d6e73da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Fri, 4 Nov 2016 11:35:55 +0100 Subject: [PATCH 02/93] Added half-precision floating-point format implementation --- src/CMakeLists.txt | 2 + src/math/all.h | 1 + src/math/half.cpp | 116 +++++++++++++++++++++++++++++++++++++++++++++ src/math/half.h | 103 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 222 insertions(+) create mode 100644 src/math/half.cpp create mode 100644 src/math/half.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 957cb70d..dd549268 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -243,6 +243,8 @@ set(BASE_SOURCES math/const.h math/func.h math/geometry.h + math/half.cpp + math/half.h math/intpoint.h math/matrix.h math/point.h diff --git a/src/math/all.h b/src/math/all.h index 7137c61e..f56a56f5 100644 --- a/src/math/all.h +++ b/src/math/all.h @@ -28,6 +28,7 @@ #include "math/const.h" #include "math/func.h" #include "math/geometry.h" +#include "math/half.h" #include "math/matrix.h" #include "math/point.h" #include "math/vector.h" diff --git a/src/math/half.cpp b/src/math/half.cpp new file mode 100644 index 00000000..263a8e79 --- /dev/null +++ b/src/math/half.cpp @@ -0,0 +1,116 @@ +/* +* 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 "math/half.h" + +#include +#include +#include + +// Math module namespace +namespace Math +{ + +//! Converts float to half-float +uint16_t FloatToHalf(float value) +{ + uint16_t sign = (copysign(1.0f, value) > 0.0f ? 0x0000 : 0x8000); + + // Infinity + if (isinf(value)) + { + return sign | 0x7C00; + } + // NaN + else if (isnan(value)) + { + return sign | 0x7FFF; + } + + int exponent; + + float significand = fabs(frexp(value, &exponent)); + + // Exponent bias + exponent += 15; + + // Crosses upper boundary, clamp to infinity + if (exponent > 31) + { + return sign | 0x7C00; + } + // Crosses lower boundary, clamp to zero + else if (exponent <= 0) + { + return sign | 0x0000; + } + // Zero + else if (significand < 0.25f) + { + return sign | 0x0000; + } + + // Normal value + uint16_t mantissa = static_cast(ldexp(2 * significand - 1, 10)); + + uint16_t bits = sign | mantissa | ((exponent - 1) << 10); + + return bits; +} + +//! Converts half-float to float +float HaltToFloat(uint16_t value) +{ + int exponent = (value >> 10) & 0x001F; + int mantissa = (value >> 0) & 0x03FF; + + float result; + + // Zero + if ((exponent == 0) && (mantissa == 0)) + { + result = 0.0f; + } + // Subnormal + else if ((exponent == 0) && (mantissa != 0)) + { + result = ldexp(static_cast(mantissa), -24); + } + // Infinity + else if ((exponent == 31) && (mantissa == 0)) + { + result = std::numeric_limits::infinity(); + } + // NaN + else if ((exponent == 31) && (mantissa != 0)) + { + result = nanf(""); + } + // Normal number + else + { + result = ldexp(static_cast(mantissa | 0x0400), exponent - 25); + } + + float sign = ((value & 0x8000) == 0 ? 1.0f : -1.0f); + + return copysignf(result, sign); +} + +} // namespace Math diff --git a/src/math/half.h b/src/math/half.h new file mode 100644 index 00000000..a5e44f46 --- /dev/null +++ b/src/math/half.h @@ -0,0 +1,103 @@ +/* +* This file is part of the Colobot: Gold Edition source code +* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam +* http://epsitec.ch; http://colobot.info; http://github.com/colobot +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see http://gnu.org/licenses +*/ + +/** +* \file math/half.h +* \brief Implementation of half-precision floating point values. +*/ + +#pragma once + +#include + +// Math module namespace +namespace Math +{ + +//! Converts float to half-float binary representation +uint16_t FloatToHalf(float value); + +//! Converts half-float binary representation to float +float HaltToFloat(uint16_t value); + +/** +* \struct half +* \brief half-precision floating point type +* +* Represents a half-precision floating point value. +* Contains the required methods for converting to and from ints and floats. +* +* This type is for storage only. +* Conversion is expensive and should be avoided if possible. +*/ +struct half +{ + //! 16-bit binary representation of half-float + uint16_t bits; + + //! Default constructor + half() + : bits(0) + { + + } + + //! Copy constructor + half(const half& other) + : bits(other.bits) + { + + } + + //! Copy operator + half& operator=(const half& other) + { + bits = other.bits; + + return *this; + } + + //! Conversion constructor from int + explicit half(int value) + : bits(FloatToHalf(static_cast(value))) + { + + } + + //! Conversion constructor from float + explicit half(float value) + : bits(FloatToHalf(value)) + { + + } + + //! Conversion operator to int + explicit operator int() const + { + return static_cast(HaltToFloat(bits)); + } + + //! Conversion operator to float + explicit operator float() const + { + return HaltToFloat(bits); + } +}; + +} // namespace Math From ae3b2b8572b4ff0eac49f3a99aa38d9df855f7ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Fri, 4 Nov 2016 11:59:57 +0100 Subject: [PATCH 03/93] Added types and vertex format specification --- src/CMakeLists.txt | 1 + src/graphics/core/type.h | 59 ++++++++++++++++++++++++++++++++++++++ src/graphics/core/vertex.h | 54 ++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 src/graphics/core/type.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dd549268..78a12211 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -165,6 +165,7 @@ set(BASE_SOURCES graphics/core/nulldevice.cpp graphics/core/nulldevice.h graphics/core/texture.h + graphics/core/type.h graphics/core/vertex.h graphics/engine/camera.cpp graphics/engine/camera.h diff --git a/src/graphics/core/type.h b/src/graphics/core/type.h new file mode 100644 index 00000000..0c04747d --- /dev/null +++ b/src/graphics/core/type.h @@ -0,0 +1,59 @@ +/* +* This file is part of the Colobot: Gold Edition source code +* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam +* http://epsitec.ch; http://colobot.info; http://github.com/colobot +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see http://gnu.org/licenses +*/ + +/** +* \file graphics/core/type.h +* \brief Type support and conversion +*/ + +#pragma once + +// Graphics module namespace +namespace Gfx +{ + +/** +* \enum class Type +* \brief Value types for vertex attributes +*/ +enum class Type : unsigned char +{ + //! Unsigned byte (8-bit) + UBYTE = 0, + //! Signed byte (8-bit) + BYTE, + //! Unsigned short (16-bit) + USHORT, + //! Signed short (16-bit) + SHORT, + //! Unsigned int (32-bit) + UINT, + //! Signed int (32-bit) + INT, + //! Half precision floating-point (16-bit) + HALF, + //! Single precision floating-point (32-bit) + FLOAT, + //! Double precision floating-point (64-bit) + DOUBLE, +}; + +// TODO: functions for conversion between types + +} // namespace Gfx diff --git a/src/graphics/core/vertex.h b/src/graphics/core/vertex.h index 8357cc84..11f1ea48 100644 --- a/src/graphics/core/vertex.h +++ b/src/graphics/core/vertex.h @@ -26,11 +26,13 @@ #include "graphics/core/color.h" +#include "graphics/core/type.h" #include "math/point.h" #include "math/vector.h" #include +#include // Graphics module namespace @@ -38,6 +40,58 @@ namespace Gfx { +/** +* \struct VertexAttribute +* \brief Vertex attribute +* +* This structure contains parameters for a vertex attribute. +*/ +struct VertexAttribute +{ + //! true enables vertex attribute + bool enabled; + //! true means normalized value (integer types only) + bool normalized; + //! Number of elements in the vertex attribute. + //! Valid values are 1, 2, 3, and 4. Depends on specific attribute. + unsigned char size; + //! Type of values in vertex attribute + Type type; + //! Offset to the vertex attribute + int offset; + //! Stride of vertex attribute + int stride; + //! Default values used when attribute is disabled + float values[4]; +}; + +/** +* \struct VertexFormat +* \brief Vertex format +* +* This structure defines vertex formats for generic vertex arrays. +* +* It contains: +* - vertex coordinate specification +* - color specification +* - normal specification +* - texture coordinate 1 specification +* - texture coordinate 2 specification +*/ +struct VertexFormat +{ + //! Vertex coordinate + VertexAttribute vertex; + //! Color + VertexAttribute color; + //! Normal + VertexAttribute normal; + //! Texture coordinate 1 + VertexAttribute tex1; + //! Texture coordinate 2 + VertexAttribute tex2; +}; + /** * \struct Vertex * \brief Vertex of a primitive From 993d9e9ed63b1bf923a17141cc9c3abbd4f70f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Fri, 4 Nov 2016 14:13:16 +0100 Subject: [PATCH 04/93] Added rendering with generic vertex formats --- src/CMakeLists.txt | 1 + src/graphics/core/device.h | 13 +- src/graphics/core/nulldevice.cpp | 10 + src/graphics/core/nulldevice.h | 5 + src/graphics/core/texture.h | 41 --- src/graphics/core/type.cpp | 56 +++++ src/graphics/core/type.h | 3 + src/graphics/opengl/gl14device.cpp | 162 ++++++++++++ src/graphics/opengl/gl14device.h | 5 + src/graphics/opengl/gl21device.cpp | 156 ++++++++++++ src/graphics/opengl/gl21device.h | 5 + src/graphics/opengl/gl33device.cpp | 390 +++++++++++++++-------------- src/graphics/opengl/gl33device.h | 11 +- src/graphics/opengl/glutil.cpp | 19 ++ src/graphics/opengl/glutil.h | 2 + 15 files changed, 642 insertions(+), 237 deletions(-) create mode 100644 src/graphics/core/type.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 78a12211..117648f3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -165,6 +165,7 @@ set(BASE_SOURCES graphics/core/nulldevice.cpp graphics/core/nulldevice.h graphics/core/texture.h + graphics/core/type.cpp graphics/core/type.h graphics/core/vertex.h graphics/engine/camera.cpp diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h index b4e897db..f2aae7d3 100644 --- a/src/graphics/core/device.h +++ b/src/graphics/core/device.h @@ -26,6 +26,7 @@ #include "graphics/core/color.h" #include "graphics/core/texture.h" +#include "graphics/core/vertex.h" #include "math/intpoint.h" @@ -267,8 +268,10 @@ enum PrimitiveType PRIMITIVE_POINTS, PRIMITIVE_LINES, PRIMITIVE_LINE_STRIP, + PRIMITIVE_LINE_LOOP, PRIMITIVE_TRIANGLES, - PRIMITIVE_TRIANGLE_STRIP + PRIMITIVE_TRIANGLE_STRIP, + PRIMITIVE_TRIANGLE_FAN }; /** @@ -413,6 +416,14 @@ public: //! Sets only the texture wrap modes (for faster than thru stage params) virtual void SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) = 0; + //! Renders primitive composed of generic vertices + virtual void DrawPrimitive(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int vertexCount) = 0; + + //! Renders multiple primitives composed of generic vertices + virtual void DrawPrimitives(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int first[], int count[], int drawCount) = 0; + //! Renders primitive composed of vertices with single texture virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) = 0; diff --git a/src/graphics/core/nulldevice.cpp b/src/graphics/core/nulldevice.cpp index aba9f800..9abdb156 100644 --- a/src/graphics/core/nulldevice.cpp +++ b/src/graphics/core/nulldevice.cpp @@ -168,6 +168,16 @@ void CNullDevice::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i { } +void CNullDevice::DrawPrimitive(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int vertexCount) +{ +} + +void CNullDevice::DrawPrimitives(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int first[], int count[], int drawCount) +{ +} + void CNullDevice::DrawPrimitives(PrimitiveType type, const Vertex *vertices, int first[], int count[], int drawCount, Color color) { diff --git a/src/graphics/core/nulldevice.h b/src/graphics/core/nulldevice.h index 5721d920..39e3f995 100644 --- a/src/graphics/core/nulldevice.h +++ b/src/graphics/core/nulldevice.h @@ -81,6 +81,11 @@ public: void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; + void DrawPrimitive(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int vertexCount) override; + void DrawPrimitives(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int first[], int count[], int drawCount) override; + void DrawPrimitive(PrimitiveType type, const Vertex* vertices, int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; void DrawPrimitive(PrimitiveType type, const VertexTex2* vertices, int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; void DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) override; diff --git a/src/graphics/core/texture.h b/src/graphics/core/texture.h index 1ec8ef99..e092abb9 100644 --- a/src/graphics/core/texture.h +++ b/src/graphics/core/texture.h @@ -205,47 +205,6 @@ struct TextureStageParams } }; -/** -* \struct TexGenMode -* \brief Texture generation mode -*/ -enum TexGenMode -{ - //! No texture generation - TEX_GEN_NONE, - //! Object linear mode - TEX_GEN_OBJECT_LINEAR, - //! Eye linear mode - TEX_GEN_EYE_LINEAR, - //! Spherical mapping mode - TEX_GEN_SPHERE_MAP, - //! Normal mapping mode - TEX_GEN_NORMAL_MAP, - //! Reflection mapping mode - TEX_GEN_REFLECTION_MAP -}; - -/** -* \struct TextureGenerationParams -* \brief Parameters for texture coordinate generation -* -* These params define the generation of texture coordinate for given texture unit. -*/ -struct TextureGenerationParams -{ - struct Coord - { - TexGenMode mode = TEX_GEN_NONE; - float plane[4] = {}; - }; - Coord coords[4]; - - void LoadDefault() - { - *this = TextureGenerationParams(); - } -}; - /** * \struct Texture * \brief Info about a texture diff --git a/src/graphics/core/type.cpp b/src/graphics/core/type.cpp new file mode 100644 index 00000000..ddcd343d --- /dev/null +++ b/src/graphics/core/type.cpp @@ -0,0 +1,56 @@ +/* +* This file is part of the Colobot: Gold Edition source code +* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam +* http://epsitec.ch; http://colobot.info; http://github.com/colobot +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see http://gnu.org/licenses +*/ + +/** +* \file graphics/core/type.cpp +* \brief Type support and conversion +*/ + +#include "graphics/core/type.h" + +#include + +// Graphics module namespace +namespace Gfx +{ + +//! Returns size in bytes of given type +int GetTypeSize(Type type) +{ + switch (type) + { + case Type::BYTE: + case Type::UBYTE: + return 1; + case Type::SHORT: + case Type::USHORT: + case Type::HALF: + return 2; + case Type::INT: + case Type::UINT: + case Type::FLOAT: + return 4; + case Type::DOUBLE: + return 8; + default: + return 0; + } +} + +} // namespace Gfx diff --git a/src/graphics/core/type.h b/src/graphics/core/type.h index 0c04747d..4a49f582 100644 --- a/src/graphics/core/type.h +++ b/src/graphics/core/type.h @@ -54,6 +54,9 @@ enum class Type : unsigned char DOUBLE, }; +//! Returns size in bytes of given type +int GetTypeSize(Type type); + // TODO: functions for conversion between types } // namespace Gfx diff --git a/src/graphics/opengl/gl14device.cpp b/src/graphics/opengl/gl14device.cpp index 7b93aaff..35a7f0bc 100644 --- a/src/graphics/opengl/gl14device.cpp +++ b/src/graphics/opengl/gl14device.cpp @@ -1379,6 +1379,168 @@ void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i glDisableClientState(GL_COLOR_ARRAY); } +void CGL14Device::DrawPrimitive(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int vertexCount) +{ + const char *ptr = reinterpret_cast(vertices); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(format.vertex.size, + TransformType(format.vertex.type), + format.vertex.stride, + ptr + format.vertex.offset); + + if (format.color.enabled) + { + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(format.color.size, + TransformType(format.color.type), + format.color.stride, + ptr + format.color.offset); + } + else + glColor4fv(format.color.values); + + if (format.normal.enabled) + { + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(TransformType(format.normal.type), + format.normal.stride, + ptr + format.normal.offset); + } + else + glNormal3fv(format.normal.values); + + glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); + if (format.tex1.enabled) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(format.tex1.size, + TransformType(format.tex1.type), + format.tex1.stride, + ptr + format.tex1.offset); + } + else + glTexCoord2fv(format.tex1.values); + + glClientActiveTexture(GL_TEXTURE0 + m_remap[1]); + if (format.tex2.enabled) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(format.tex2.size, + TransformType(format.tex2.type), + format.tex2.stride, + ptr + format.tex2.offset); + } + else + glTexCoord2fv(format.tex2.values); + + glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); + + glDisableClientState(GL_VERTEX_ARRAY); + + if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY); + if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY); + + if (format.tex1.enabled) + { + glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if (format.tex2.enabled) + { + glClientActiveTexture(GL_TEXTURE0 + m_remap[1]); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } +} + +void CGL14Device::DrawPrimitives(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int first[], int count[], int drawCount) +{ + const char *ptr = reinterpret_cast(vertices); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(format.vertex.size, + TransformType(format.vertex.type), + format.vertex.stride, + ptr + format.vertex.offset); + + if (format.color.enabled) + { + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(format.color.size, + TransformType(format.color.type), + format.color.stride, + ptr + format.color.offset); + } + else + glColor4fv(format.color.values); + + if (format.normal.enabled) + { + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(TransformType(format.normal.type), + format.normal.stride, + ptr + format.normal.offset); + } + else + glNormal3fv(format.normal.values); + + glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); + if (format.tex1.enabled) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(format.tex1.size, + TransformType(format.tex1.type), + format.tex1.stride, + ptr + format.tex1.offset); + } + else + glTexCoord2fv(format.tex1.values); + + glClientActiveTexture(GL_TEXTURE0 + m_remap[1]); + if (format.tex2.enabled) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(format.tex2.size, + TransformType(format.tex2.type), + format.tex2.stride, + ptr + format.tex2.offset); + } + else + glTexCoord2fv(format.tex2.values); + + GLenum t = TranslateGfxPrimitive(type); + + if (m_multiDrawArrays) + { + glMultiDrawArrays(t, first, count, drawCount); + } + else + { + for (int i = 0; i < drawCount; i++) + glDrawArrays(t, first[i], count[i]); + } + + glDisableClientState(GL_VERTEX_ARRAY); + + if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY); + if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY); + + if (format.tex1.enabled) + { + glClientActiveTexture(GL_TEXTURE0 + m_remap[0]); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if (format.tex2.enabled) + { + glClientActiveTexture(GL_TEXTURE0 + m_remap[1]); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } +} + void CGL14Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, int first[], int count[], int drawCount, Color color) { diff --git a/src/graphics/opengl/gl14device.h b/src/graphics/opengl/gl14device.h index 96190394..39b4a122 100644 --- a/src/graphics/opengl/gl14device.h +++ b/src/graphics/opengl/gl14device.h @@ -119,6 +119,11 @@ public: void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; + virtual void DrawPrimitive(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int vertexCount) override; + virtual void DrawPrimitives(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int first[], int count[], int drawCount) override; + virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp index e1a96dbe..b38f6387 100644 --- a/src/graphics/opengl/gl21device.cpp +++ b/src/graphics/opengl/gl21device.cpp @@ -1196,6 +1196,162 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i glDisableClientState(GL_COLOR_ARRAY); } +void CGL21Device::DrawPrimitive(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int vertexCount) +{ + BindVBO(0); + + const char *ptr = reinterpret_cast(vertices); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(format.vertex.size, + TransformType(format.vertex.type), + format.vertex.stride, + ptr + format.vertex.offset); + + if (format.color.enabled) + { + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(format.color.size, + TransformType(format.color.type), + format.color.stride, + ptr + format.color.offset); + } + else + glColor4fv(format.color.values); + + if (format.normal.enabled) + { + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(TransformType(format.normal.type), + format.normal.stride, + ptr + format.normal.offset); + } + else + glNormal3fv(format.normal.values); + + glClientActiveTexture(GL_TEXTURE0); + if (format.tex1.enabled) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(format.tex1.size, + TransformType(format.tex1.type), + format.tex1.stride, + ptr + format.tex1.offset); + } + else + glTexCoord2fv(format.tex1.values); + + glClientActiveTexture(GL_TEXTURE1); + if (format.tex2.enabled) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(format.tex2.size, + TransformType(format.tex2.type), + format.tex2.stride, + ptr + format.tex2.offset); + } + else + glTexCoord2fv(format.tex2.values); + + glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); + + glDisableClientState(GL_VERTEX_ARRAY); + + if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY); + if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY); + + if (format.tex1.enabled) + { + glClientActiveTexture(GL_TEXTURE0); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if (format.tex2.enabled) + { + glClientActiveTexture(GL_TEXTURE1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } +} + +void CGL21Device::DrawPrimitives(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int first[], int count[], int drawCount) +{ + BindVBO(0); + + const char *ptr = reinterpret_cast(vertices); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(format.vertex.size, + TransformType(format.vertex.type), + format.vertex.stride, + ptr + format.vertex.offset); + + if (format.color.enabled) + { + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(format.color.size, + TransformType(format.color.type), + format.color.stride, + ptr + format.color.offset); + } + else + glColor4fv(format.color.values); + + if (format.normal.enabled) + { + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(TransformType(format.normal.type), + format.normal.stride, + ptr + format.normal.offset); + } + else + glNormal3fv(format.normal.values); + + glClientActiveTexture(GL_TEXTURE0); + if (format.tex1.enabled) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(format.tex1.size, + TransformType(format.tex1.type), + format.tex1.stride, + ptr + format.tex1.offset); + } + else + glTexCoord2fv(format.tex1.values); + + glClientActiveTexture(GL_TEXTURE1); + if (format.tex2.enabled) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(format.tex2.size, + TransformType(format.tex2.type), + format.tex2.stride, + ptr + format.tex2.offset); + } + else + glTexCoord2fv(format.tex2.values); + + glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); + + glDisableClientState(GL_VERTEX_ARRAY); + + if (format.color.enabled) glDisableClientState(GL_COLOR_ARRAY); + if (format.normal.enabled) glDisableClientState(GL_NORMAL_ARRAY); + + if (format.tex1.enabled) + { + glClientActiveTexture(GL_TEXTURE0); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if (format.tex2.enabled) + { + glClientActiveTexture(GL_TEXTURE1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } +} + void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, int first[], int count[], int drawCount, Color color) { diff --git a/src/graphics/opengl/gl21device.h b/src/graphics/opengl/gl21device.h index 20cf2156..e70d66c6 100644 --- a/src/graphics/opengl/gl21device.h +++ b/src/graphics/opengl/gl21device.h @@ -100,6 +100,11 @@ public: void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; + virtual void DrawPrimitive(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int vertexCount) override; + virtual void DrawPrimitives(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int first[], int count[], int drawCount) override; + virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp index df67e5c1..3d5ae713 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl/gl33device.cpp @@ -523,21 +523,18 @@ bool CGL33Device::Create() m_framebuffers["default"] = MakeUnique(framebufferParams); - // create dynamic buffers - for (int i = 0; i < 3; i++) - { - glGenVertexArrays(1, &m_dynamicBuffers[i].vao); + // create dynamic buffer + glGenVertexArrays(1, &m_dynamicBuffer.vao); - m_dynamicBuffers[i].size = 4 * 1024 * 1024; - m_dynamicBuffers[i].offset = 0; + m_dynamicBuffer.size = 4 * 1024 * 1024; + m_dynamicBuffer.offset = 0; - glGenBuffers(1, &m_dynamicBuffers[i].vbo); - glBindBuffer(GL_ARRAY_BUFFER, m_dynamicBuffers[i].vbo); - glBufferData(GL_ARRAY_BUFFER, m_dynamicBuffers[i].size, nullptr, GL_STREAM_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glGenBuffers(1, &m_dynamicBuffer.vbo); + glBindBuffer(GL_ARRAY_BUFFER, m_dynamicBuffer.vbo); + glBufferData(GL_ARRAY_BUFFER, m_dynamicBuffer.size, nullptr, GL_STREAM_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); - m_vboMemory += m_dynamicBuffers[i].size; - } + m_vboMemory += m_dynamicBuffer.size; GetLogger()->Info("CDevice created successfully\n"); @@ -563,13 +560,10 @@ void CGL33Device::Destroy() DestroyAllTextures(); // delete dynamic buffer - for (int i = 0; i < 3; i++) - { - glDeleteVertexArrays(1, &m_dynamicBuffers[i].vao); - glDeleteBuffers(1, &m_dynamicBuffers[i].vbo); + glDeleteVertexArrays(1, &m_dynamicBuffer.vao); + glDeleteBuffers(1, &m_dynamicBuffer.vbo); - m_vboMemory -= m_dynamicBuffers[i].size; - } + m_vboMemory -= m_dynamicBuffer.size; m_lights.clear(); m_lightsEnabled.clear(); @@ -1075,46 +1069,39 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int unsigned int size = vertexCount * sizeof(Vertex); - DynamicBuffer& buffer = m_dynamicBuffers[0]; + DynamicBuffer& buffer = m_dynamicBuffer; BindVAO(buffer.vao); BindVBO(buffer.vbo); unsigned int offset = UploadVertexData(buffer, vs, size); - // Start of the buffer, reinitialize binding state - if (offset == 0) - { - // Vertex coordinate - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), - reinterpret_cast(offsetof(Vertex, coord))); + // Vertex coordinate + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offset + offsetof(Vertex, coord))); - // Normal - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), - reinterpret_cast(offsetof(Vertex, normal))); - - // Color - glDisableVertexAttribArray(2); - - // Texture coordinate 0 - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), - reinterpret_cast(offsetof(Vertex, texCoord))); - - // Texture coordinate 1 - glDisableVertexAttribArray(4); - glVertexAttrib2f(4, 0.0f, 0.0f); - } + // Normal + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offset + offsetof(Vertex, normal))); + // Color + glDisableVertexAttribArray(2); glVertexAttrib4fv(2, color.Array()); + // Texture coordinate 0 + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offset + offsetof(Vertex, texCoord))); + + // Texture coordinate 1 + glDisableVertexAttribArray(4); + glVertexAttrib2f(4, 0.0f, 0.0f); + UpdateRenderingMode(); - int first = offset / sizeof(Vertex); - - glDrawArrays(TranslateGfxPrimitive(type), first, vertexCount); + glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); } void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, Color color) @@ -1123,46 +1110,40 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, unsigned int size = vertexCount * sizeof(VertexTex2); - DynamicBuffer& buffer = m_dynamicBuffers[1]; + DynamicBuffer& buffer = m_dynamicBuffer; BindVAO(buffer.vao); BindVBO(buffer.vbo); unsigned int offset = UploadVertexData(buffer, vs, size); - if (offset == 0) - { - // Vertex coordinate - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), - reinterpret_cast(offsetof(VertexTex2, coord))); + // Vertex coordinate + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), + reinterpret_cast(offset + offsetof(VertexTex2, coord))); - // Normal - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), - reinterpret_cast(offsetof(VertexTex2, normal))); - - // Color - glDisableVertexAttribArray(2); - - // Texture coordinate 0 - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), - reinterpret_cast(offsetof(VertexTex2, texCoord))); - - // Texture coordinate 1 - glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), - reinterpret_cast(offsetof(VertexTex2, texCoord2))); - } + // Normal + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), + reinterpret_cast(offset + offsetof(VertexTex2, normal))); + // Color + glDisableVertexAttribArray(2); glVertexAttrib4fv(2, color.Array()); + // Texture coordinate 0 + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), + reinterpret_cast(offset + offsetof(VertexTex2, texCoord))); + + // Texture coordinate 1 + glEnableVertexAttribArray(4); + glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), + reinterpret_cast(offset + offsetof(VertexTex2, texCoord2))); + UpdateRenderingMode(); - int first = offset / sizeof(VertexTex2); - - glDrawArrays(TranslateGfxPrimitive(type), first, vertexCount); + glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); } void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) @@ -1171,43 +1152,82 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i unsigned int size = vertexCount * sizeof(VertexCol); - DynamicBuffer& buffer = m_dynamicBuffers[2]; + DynamicBuffer& buffer = m_dynamicBuffer; BindVAO(buffer.vao); BindVBO(buffer.vbo); unsigned int offset = UploadVertexData(buffer, vs, size); - if (offset == 0) - { - // Vertex coordinate - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol), - reinterpret_cast(offsetof(VertexCol, coord))); + // Vertex coordinate + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol), + reinterpret_cast(offset + offsetof(VertexCol, coord))); - // Normal - glDisableVertexAttribArray(1); - glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f); + // Normal + glDisableVertexAttribArray(1); + glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f); - // Color - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol), - reinterpret_cast(offsetof(VertexCol, color))); + // Color + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol), + reinterpret_cast(offset + offsetof(VertexCol, color))); - // Texture coordinate 0 - glDisableVertexAttribArray(3); - glVertexAttrib2f(3, 0.0f, 0.0f); + // Texture coordinate 0 + glDisableVertexAttribArray(3); + glVertexAttrib2f(3, 0.0f, 0.0f); - // Texture coordinate 1 - glDisableVertexAttribArray(4); - glVertexAttrib2f(4, 0.0f, 0.0f); - } + // Texture coordinate 1 + glDisableVertexAttribArray(4); + glVertexAttrib2f(4, 0.0f, 0.0f); UpdateRenderingMode(); - int first = offset / sizeof(VertexCol); + glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); +} - glDrawArrays(TranslateGfxPrimitive(type), first, vertexCount); +void CGL33Device::DrawPrimitive(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int vertexCount) +{ + DynamicBuffer& buffer = m_dynamicBuffer; + + BindVAO(buffer.vao); + BindVBO(buffer.vbo); + + unsigned int offset = UploadVertexData(buffer, vertices, size); + + // Update vertex attribute bindings + UpdateVertexAttribute(0, format.vertex, offset); + UpdateVertexAttribute(1, format.normal, offset); + UpdateVertexAttribute(2, format.color, offset); + UpdateVertexAttribute(3, format.tex1, offset); + UpdateVertexAttribute(4, format.tex2, offset); + + UpdateRenderingMode(); + + glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); +} + +void CGL33Device::DrawPrimitives(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int first[], int count[], int drawCount) +{ + DynamicBuffer& buffer = m_dynamicBuffer; + + BindVAO(buffer.vao); + BindVBO(buffer.vbo); + + unsigned int offset = UploadVertexData(buffer, vertices, size); + + // Update vertex attribute bindings + UpdateVertexAttribute(0, format.vertex, offset); + UpdateVertexAttribute(1, format.normal, offset); + UpdateVertexAttribute(2, format.color, offset); + UpdateVertexAttribute(3, format.tex1, offset); + UpdateVertexAttribute(4, format.tex2, offset); + + UpdateRenderingMode(); + + glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); } void CGL33Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, @@ -1227,51 +1247,39 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, unsigned int size = vertexCount * sizeof(Vertex); - DynamicBuffer& buffer = m_dynamicBuffers[0]; + DynamicBuffer& buffer = m_dynamicBuffer; BindVAO(buffer.vao); BindVBO(buffer.vbo); unsigned int offset = UploadVertexData(buffer, vs, size); - if (offset == 0) - { - // Vertex coordinate - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), - reinterpret_cast(offsetof(Vertex, coord))); + // Vertex coordinate + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offset + offsetof(Vertex, coord))); - // Normal - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), - reinterpret_cast(offsetof(Vertex, normal))); - - // Color - glDisableVertexAttribArray(2); - - // Texture coordinate 0 - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), - reinterpret_cast(offsetof(Vertex, texCoord))); - - // Texture coordinate 1 - glDisableVertexAttribArray(4); - glVertexAttrib2f(4, 0.0f, 0.0f); - } + // Normal + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offset + offsetof(Vertex, normal))); + // Color + glDisableVertexAttribArray(2); glVertexAttrib4fv(2, color.Array()); + // Texture coordinate 0 + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offset + offsetof(Vertex, texCoord))); + + // Texture coordinate 1 + glDisableVertexAttribArray(4); + glVertexAttrib2f(4, 0.0f, 0.0f); + UpdateRenderingMode(); - int firstOffset = offset / sizeof(Vertex); - - for (int i = 0; i < drawCount; i++) - first[i] += firstOffset; - glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); - - for (int i = 0; i < drawCount; i++) - first[i] -= firstOffset; } void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, @@ -1291,52 +1299,40 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, unsigned int size = vertexCount * sizeof(VertexTex2); - DynamicBuffer& buffer = m_dynamicBuffers[1]; + DynamicBuffer& buffer = m_dynamicBuffer; BindVAO(buffer.vao); BindVBO(buffer.vbo); unsigned int offset = UploadVertexData(buffer, vs, size); - if (offset == 0) - { - // Vertex coordinate - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), - reinterpret_cast(offsetof(VertexTex2, coord))); + // Vertex coordinate + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), + reinterpret_cast(offset + offsetof(VertexTex2, coord))); - // Normal - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), - reinterpret_cast(offsetof(VertexTex2, normal))); - - // Color - glDisableVertexAttribArray(2); - - // Texture coordinate 0 - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), - reinterpret_cast(offsetof(VertexTex2, texCoord))); - - // Texture coordinate 1 - glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), - reinterpret_cast(offsetof(VertexTex2, texCoord2))); - } + // Normal + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), + reinterpret_cast(offset + offsetof(VertexTex2, normal))); + // Color + glDisableVertexAttribArray(2); glVertexAttrib4fv(2, color.Array()); + // Texture coordinate 0 + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), + reinterpret_cast(offset + offsetof(VertexTex2, texCoord))); + + // Texture coordinate 1 + glEnableVertexAttribArray(4); + glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), + reinterpret_cast(offset + offsetof(VertexTex2, texCoord2))); + UpdateRenderingMode(); - int firstOffset = offset / sizeof(VertexTex2); - - for (int i = 0; i < drawCount; i++) - first[i] += firstOffset; - glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); - - for (int i = 0; i < drawCount; i++) - first[i] -= firstOffset; } void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, @@ -1356,49 +1352,38 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, unsigned int size = vertexCount * sizeof(VertexCol); - DynamicBuffer& buffer = m_dynamicBuffers[2]; + DynamicBuffer& buffer = m_dynamicBuffer; BindVAO(buffer.vao); BindVBO(buffer.vbo); unsigned int offset = UploadVertexData(buffer, vs, size); - if (offset == 0) - { - // Vertex coordinate - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol), - reinterpret_cast(offsetof(VertexCol, coord))); + // Vertex coordinate + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexCol), + reinterpret_cast(offset + offsetof(VertexCol, coord))); - // Normal - glDisableVertexAttribArray(1); - glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f); + // Normal + glDisableVertexAttribArray(1); + glVertexAttrib3f(1, 0.0f, 0.0f, 1.0f); - // Color - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol), - reinterpret_cast(offsetof(VertexCol, color))); + // Color + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexCol), + reinterpret_cast(offset + offsetof(VertexCol, color))); - // Texture coordinate 0 - glDisableVertexAttribArray(3); - glVertexAttrib2f(3, 0.0f, 0.0f); + // Texture coordinate 0 + glDisableVertexAttribArray(3); + glVertexAttrib2f(3, 0.0f, 0.0f); - // Texture coordinate 1 - glDisableVertexAttribArray(4); - glVertexAttrib2f(4, 0.0f, 0.0f); - } + // Texture coordinate 1 + glDisableVertexAttribArray(4); + glVertexAttrib2f(4, 0.0f, 0.0f); UpdateRenderingMode(); - int firstOffset = offset / sizeof(VertexCol); - - for (int i = 0; i < drawCount; i++) - first[i] += firstOffset; - glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); - - for (int i = 0; i < drawCount; i++) - first[i] -= firstOffset; } unsigned int CGL33Device::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) @@ -2057,7 +2042,7 @@ inline void CGL33Device::BindVAO(GLuint vao) m_currentVAO = vao; } -unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, void* data, unsigned int size) +unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, const void* data, unsigned int size) { unsigned int nextOffset = buffer.offset + size; @@ -2080,7 +2065,7 @@ unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, void* data, un if (ptr != nullptr) { memcpy(ptr, data, size); - + glUnmapBuffer(GL_ARRAY_BUFFER); } // mapping failed, we must upload data with glBufferSubData @@ -2095,6 +2080,25 @@ unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, void* data, un return currentOffset; } +void CGL33Device::UpdateVertexAttribute(int index, const VertexAttribute &attribute, int offset) +{ + if (attribute.enabled) + { + glEnableVertexAttribArray(index); + glVertexAttribPointer(index, + attribute.size, + TranslateType(attribute.type), + attribute.normalized ? GL_TRUE : GL_FALSE, + attribute.stride, + reinterpret_cast(offset + attribute.offset)); + } + else + { + glDisableVertexAttribArray(index); + glVertexAttrib4fv(index, attribute.values); + } +} + bool CGL33Device::IsAnisotropySupported() { return m_capabilities.anisotropySupported; diff --git a/src/graphics/opengl/gl33device.h b/src/graphics/opengl/gl33device.h index a47fb999..dc17e98f 100644 --- a/src/graphics/opengl/gl33device.h +++ b/src/graphics/opengl/gl33device.h @@ -115,6 +115,11 @@ public: void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; + virtual void DrawPrimitive(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int vertexCount) override; + virtual void DrawPrimitives(PrimitiveType type, const void *vertices, + int size, const VertexFormat &format, int first[], int count[], int drawCount) override; + virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, @@ -202,7 +207,9 @@ private: inline void BindVAO(GLuint vao); //! Uploads data to dynamic buffer and returns offset to it - unsigned int UploadVertexData(DynamicBuffer& buffer, void* data, unsigned int size); + unsigned int UploadVertexData(DynamicBuffer& buffer, const void* data, unsigned int size); + + inline void UpdateVertexAttribute(int index, const VertexAttribute &attribute, int offset); private: //! Current config @@ -283,7 +290,7 @@ private: //! Shader program for shadow rendering GLuint m_shadowProgram = 0; - DynamicBuffer m_dynamicBuffers[3]; + DynamicBuffer m_dynamicBuffer; //! Current mode unsigned int m_mode = 0; diff --git a/src/graphics/opengl/glutil.cpp b/src/graphics/opengl/glutil.cpp index bd6ae886..66018213 100644 --- a/src/graphics/opengl/glutil.cpp +++ b/src/graphics/opengl/glutil.cpp @@ -335,8 +335,10 @@ GLenum TranslateGfxPrimitive(PrimitiveType type) case PRIMITIVE_POINTS: flag = GL_POINTS; break; case PRIMITIVE_LINES: flag = GL_LINES; break; case PRIMITIVE_LINE_STRIP: flag = GL_LINE_STRIP; break; + case PRIMITIVE_LINE_LOOP: flag = GL_LINE_LOOP; break; case PRIMITIVE_TRIANGLES: flag = GL_TRIANGLES; break; case PRIMITIVE_TRIANGLE_STRIP: flag = GL_TRIANGLE_STRIP; break; + case PRIMITIVE_TRIANGLE_FAN: flag = GL_TRIANGLE_FAN; break; default: assert(false); break; } return flag; @@ -441,6 +443,23 @@ GLenum TranslateTextureCoordinateGen(int index) return textureCoordGen[index]; } +GLenum TranslateType(Type type) +{ + switch (type) + { + case Type::BYTE: return GL_BYTE; + case Type::UBYTE: return GL_UNSIGNED_BYTE; + case Type::SHORT: return GL_SHORT; + case Type::USHORT: return GL_UNSIGNED_SHORT; + case Type::INT: return GL_INT; + case Type::UINT: return GL_UNSIGNED_INT; + case Type::HALF: return GL_HALF_FLOAT; + case Type::FLOAT: return GL_FLOAT; + case Type::DOUBLE: return GL_DOUBLE; + default: return 0; + } +} + std::string lastShaderError; std::string GetLastShaderError() diff --git a/src/graphics/opengl/glutil.h b/src/graphics/opengl/glutil.h index 2da4cf20..03450cad 100644 --- a/src/graphics/opengl/glutil.h +++ b/src/graphics/opengl/glutil.h @@ -93,6 +93,8 @@ GLenum TranslateTextureCoordinate(int index); GLenum TranslateTextureCoordinateGen(int index); +GLenum TranslateType(Type type); + std::string GetLastShaderError(); GLint LoadShader(GLint type, const char* filename); From 5aa5d91ecb278355a7f98541e12053f882a418e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Fri, 4 Nov 2016 18:34:49 +0100 Subject: [PATCH 05/93] Fix compilation errors in half.cpp --- src/math/half.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/math/half.cpp b/src/math/half.cpp index 263a8e79..4508218f 100644 --- a/src/math/half.cpp +++ b/src/math/half.cpp @@ -30,22 +30,22 @@ namespace Math //! Converts float to half-float uint16_t FloatToHalf(float value) { - uint16_t sign = (copysign(1.0f, value) > 0.0f ? 0x0000 : 0x8000); + uint16_t sign = (std::copysign(1.0f, value) > 0.0f ? 0x0000 : 0x8000); // Infinity - if (isinf(value)) + if (std::isinf(value)) { return sign | 0x7C00; } // NaN - else if (isnan(value)) + else if (std::isnan(value)) { return sign | 0x7FFF; } int exponent; - float significand = fabs(frexp(value, &exponent)); + float significand = std::fabs(std::frexp(value, &exponent)); // Exponent bias exponent += 15; @@ -67,7 +67,7 @@ uint16_t FloatToHalf(float value) } // Normal value - uint16_t mantissa = static_cast(ldexp(2 * significand - 1, 10)); + uint16_t mantissa = static_cast(std::ldexp(2 * significand - 1, 10)); uint16_t bits = sign | mantissa | ((exponent - 1) << 10); @@ -90,7 +90,7 @@ float HaltToFloat(uint16_t value) // Subnormal else if ((exponent == 0) && (mantissa != 0)) { - result = ldexp(static_cast(mantissa), -24); + result = std::ldexp(static_cast(mantissa), -24); } // Infinity else if ((exponent == 31) && (mantissa == 0)) @@ -100,17 +100,17 @@ float HaltToFloat(uint16_t value) // NaN else if ((exponent == 31) && (mantissa != 0)) { - result = nanf(""); + result = std::nanf(""); } // Normal number else { - result = ldexp(static_cast(mantissa | 0x0400), exponent - 25); + result = std::ldexp(static_cast(mantissa | 0x0400), exponent - 25); } float sign = ((value & 0x8000) == 0 ? 1.0f : -1.0f); - return copysignf(result, sign); + return std::copysignf(result, sign); } } // namespace Math From 3c71354b42057cb1e7b57fbdbc27c1905c56c968 Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 7 Nov 2016 21:08:02 +0100 Subject: [PATCH 06/93] Fix MSVC2015 compilation error --- src/ui/controls/edit.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/controls/edit.h b/src/ui/controls/edit.h index 4192a133..8beb1140 100644 --- a/src/ui/controls/edit.h +++ b/src/ui/controls/edit.h @@ -27,6 +27,7 @@ #include "ui/controls/control.h" +#include #include namespace Ui From 9fe85e280ad83b13f0500b03126c4f461b694b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Thu, 10 Nov 2016 12:34:30 +0100 Subject: [PATCH 07/93] Code simplification in CGL14Device --- src/graphics/opengl/gl14device.cpp | 176 +++++++++-------------------- src/graphics/opengl/gl14device.h | 8 ++ 2 files changed, 59 insertions(+), 125 deletions(-) diff --git a/src/graphics/opengl/gl14device.cpp b/src/graphics/opengl/gl14device.cpp index 35a7f0bc..39993f8d 100644 --- a/src/graphics/opengl/gl14device.cpp +++ b/src/graphics/opengl/gl14device.cpp @@ -258,11 +258,25 @@ bool CGL14Device::Create() { GetLogger()->Info("Core VBO supported\n", glMajor, glMinor); m_vertexBufferType = VBT_VBO_CORE; + + // Set function pointers + m_glGenBuffers = glGenBuffers; + m_glDeleteBuffers = glDeleteBuffers; + m_glBindBuffer = glBindBuffer; + m_glBufferData = glBufferData; + m_glBufferSubData = glBufferSubData; } else if (vboARB) // VBO ARB extension available { GetLogger()->Info("ARB VBO supported\n"); m_vertexBufferType = VBT_VBO_ARB; + + // Set function pointers + m_glGenBuffers = glGenBuffersARB; + m_glDeleteBuffers = glDeleteBuffersARB; + m_glBindBuffer = glBindBufferARB; + m_glBufferData = glBufferDataARB; + m_glBufferSubData = glBufferSubDataARB; } else // no VBO support { @@ -800,44 +814,22 @@ Texture CGL14Device::CreateDepthTexture(int width, int height, int depth) GLuint format = GL_DEPTH_COMPONENT; - if (m_shadowMappingSupport == SMS_CORE) + switch (depth) { - switch (depth) - { - case 16: - format = GL_DEPTH_COMPONENT16; - break; - case 24: - format = GL_DEPTH_COMPONENT24; - break; - case 32: - format = GL_DEPTH_COMPONENT32; - break; - } - - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + case 16: + format = GL_DEPTH_COMPONENT16; + break; + case 24: + format = GL_DEPTH_COMPONENT24; + break; + case 32: + format = GL_DEPTH_COMPONENT32; + break; } - else - { - switch (depth) - { - case 16: - format = GL_DEPTH_COMPONENT16_ARB; - break; - case 24: - format = GL_DEPTH_COMPONENT24_ARB; - break; - case 32: - format = GL_DEPTH_COMPONENT32_ARB; - break; - } - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); - } + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; @@ -1656,20 +1648,10 @@ unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const info.vertexCount = vertexCount; info.bufferId = 0; - if(m_vertexBufferType == VBT_VBO_CORE) - { - glGenBuffers(1, &info.bufferId); - glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - else - { - glGenBuffersARB(1, &info.bufferId); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } + m_glGenBuffers(1, &info.bufferId); + m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); m_vboObjects[id] = info; } @@ -1700,20 +1682,10 @@ unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const info.vertexCount = vertexCount; info.bufferId = 0; - if(m_vertexBufferType == VBT_VBO_CORE) - { - glGenBuffers(1, &info.bufferId); - glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - else - { - glGenBuffersARB(1, &info.bufferId); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } + m_glGenBuffers(1, &info.bufferId); + m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); m_vboObjects[id] = info; } @@ -1744,20 +1716,10 @@ unsigned int CGL14Device::CreateStaticBuffer(PrimitiveType primitiveType, const info.vertexCount = vertexCount; info.bufferId = 0; - if(m_vertexBufferType == VBT_VBO_CORE) - { - glGenBuffers(1, &info.bufferId); - glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - else - { - glGenBuffersARB(1, &info.bufferId); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } + m_glGenBuffers(1, &info.bufferId); + m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); m_vboObjects[id] = info; } @@ -1788,18 +1750,9 @@ void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit info.vertexType = VERTEX_TYPE_NORMAL; info.vertexCount = vertexCount; - if(m_vertexBufferType == VBT_VBO_CORE) - { - glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - else - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } + m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); } else { @@ -1824,18 +1777,9 @@ void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit info.vertexType = VERTEX_TYPE_TEX2; info.vertexCount = vertexCount; - if(m_vertexBufferType == VBT_VBO_CORE) - { - glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - else - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } + m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); } else { @@ -1860,18 +1804,9 @@ void CGL14Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit info.vertexType = VERTEX_TYPE_COL; info.vertexCount = vertexCount; - if(m_vertexBufferType == VBT_VBO_CORE) - { - glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - else - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, info.bufferId); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } + m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); } else { @@ -1891,10 +1826,7 @@ void CGL14Device::DrawStaticBuffer(unsigned int bufferId) if (it == m_vboObjects.end()) return; - if(m_vertexBufferType == VBT_VBO_CORE) - glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId); - else - glBindBufferARB(GL_ARRAY_BUFFER_ARB, (*it).second.bufferId); + m_glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId); if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) { @@ -1957,10 +1889,7 @@ void CGL14Device::DrawStaticBuffer(unsigned int bufferId) glDisableClientState(GL_COLOR_ARRAY); } - if(m_vertexBufferType == VBT_VBO_CORE) - glBindBuffer(GL_ARRAY_BUFFER, 0); - else - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + m_glBindBuffer(GL_ARRAY_BUFFER, 0); } else { @@ -1976,10 +1905,7 @@ void CGL14Device::DestroyStaticBuffer(unsigned int bufferId) if (it == m_vboObjects.end()) return; - if(m_vertexBufferType == VBT_VBO_CORE) - glDeleteBuffers(1, &(*it).second.bufferId); - else - glDeleteBuffersARB(1, &(*it).second.bufferId); + m_glDeleteBuffers(1, &(*it).second.bufferId); m_vboObjects.erase(it); } diff --git a/src/graphics/opengl/gl14device.h b/src/graphics/opengl/gl14device.h index 39b4a122..e0dba147 100644 --- a/src/graphics/opengl/gl14device.h +++ b/src/graphics/opengl/gl14device.h @@ -295,6 +295,14 @@ private: bool m_shadowMapping = false; //! true means that quality shadows are enabled bool m_shadowQuality = true; + + + //! Pointers to OpenGL functions + PFNGLGENBUFFERSPROC m_glGenBuffers; + PFNGLDELETEBUFFERSPROC m_glDeleteBuffers; + PFNGLBINDBUFFERPROC m_glBindBuffer; + PFNGLBUFFERDATAPROC m_glBufferData; + PFNGLBUFFERSUBDATAPROC m_glBufferSubData; }; From e7c41ae9e689a59ddfe48dd0e8395e9db59c7fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Thu, 10 Nov 2016 13:00:42 +0100 Subject: [PATCH 08/93] Correction in changing wrap mode in SetState --- src/graphics/engine/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 5c4a317a..21a5beb5 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -2194,7 +2194,7 @@ void CEngine::SetState(int state, const Color& color) m_device->SetTextureStageWrap(0, TEX_WRAP_REPEAT, TEX_WRAP_REPEAT); m_device->SetTextureStageWrap(1, TEX_WRAP_REPEAT, TEX_WRAP_REPEAT); } - else // if (state & ENG_RSTATE_CLAMP) or otherwise + else if (state & ENG_RSTATE_CLAMP) { m_device->SetTextureStageWrap(0, TEX_WRAP_CLAMP, TEX_WRAP_CLAMP); m_device->SetTextureStageWrap(1, TEX_WRAP_CLAMP, TEX_WRAP_CLAMP); From 1b074bd94dc495fe3bd971c14c774f4386f193ef Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 13:37:39 +0100 Subject: [PATCH 09/93] Fix crash on loading saves with produce()d objects (#765) Thanks @melex750! --- src/script/scriptfunc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index 7f6cb97b..1c1f985f 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -1393,6 +1393,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v CProgramStorageObject* programStorage = dynamic_cast(object); Program* program = programStorage->AddProgram(); programStorage->ReadProgram(program, name2.c_str()); + program->readOnly = true; program->filename = name; dynamic_cast(object)->RunProgram(program); } From 6e4764b97cc43c6f02f968c036940658d7d519ad Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 17:06:53 +0100 Subject: [PATCH 10/93] Fix GroundSpot blending, closes #846 --- src/graphics/engine/engine.cpp | 45 ++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 21a5beb5..b2aa631f 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -4262,15 +4262,15 @@ void CEngine::UpdateGroundSpotTextures() else intensity = Math::Point(ppx-cx, ppy-cy).Length()/dot; - Gfx::Color color; - color.r = Math::Norm(m_groundSpots[i].color.r+intensity); - color.g = Math::Norm(m_groundSpots[i].color.g+intensity); - color.b = Math::Norm(m_groundSpots[i].color.b+intensity); - ppx -= min.x; // on the texture ppy -= min.y; + Math::IntPoint pp(ppx, ppy); - shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color); + Gfx::Color color = shadowImg.GetPixel(pp); + color.r *= Math::Norm(m_groundSpots[i].color.r+intensity); + color.g *= Math::Norm(m_groundSpots[i].color.g+intensity); + color.b *= Math::Norm(m_groundSpots[i].color.b+intensity); + shadowImg.SetPixel(pp, color); } } } @@ -4298,12 +4298,13 @@ void CEngine::UpdateGroundSpotTextures() if (intensity < 0.0f) intensity = 0.0f; - Gfx::Color color; - color.r = Math::Norm(m_groundSpots[i].color.r+intensity); - color.g = Math::Norm(m_groundSpots[i].color.g+intensity); - color.b = Math::Norm(m_groundSpots[i].color.b+intensity); + Math::IntPoint pp(ix, iy); - shadowImg.SetPixel(Math::IntPoint(ix, iy), color); + Gfx::Color color = shadowImg.GetPixel(pp); + color.r *= Math::Norm(m_groundSpots[i].color.r+intensity); + color.g *= Math::Norm(m_groundSpots[i].color.g+intensity); + color.b *= Math::Norm(m_groundSpots[i].color.b+intensity); + shadowImg.SetPixel(pp, color); } } } @@ -4351,19 +4352,21 @@ void CEngine::UpdateGroundSpotTextures() int j = (ix+dot) + (iy+dot) * m_groundMark.dx; if (m_groundMark.table[j] == 1) // green ? { - Gfx::Color color; - color.r = Math::Norm(1.0f-intensity); - color.g = 1.0f; - color.b = Math::Norm(1.0f-intensity); - shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color); + Math::IntPoint pp(ppx, ppy); + Gfx::Color color = shadowImg.GetPixel(pp); + color.r *= Math::Norm(1.0f-intensity); + color.g *= 1.0f; + color.b *= Math::Norm(1.0f-intensity); + shadowImg.SetPixel(pp, color); } if (m_groundMark.table[j] == 2) // red ? { - Gfx::Color color; - color.r = 1.0f; - color.g = Math::Norm(1.0f-intensity); - color.b = Math::Norm(1.0f-intensity); - shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color); + Math::IntPoint pp(ppx, ppy); + Gfx::Color color = shadowImg.GetPixel(pp); + color.r *= 1.0f; + color.g *= Math::Norm(1.0f-intensity); + color.b *= Math::Norm(1.0f-intensity); + shadowImg.SetPixel(pp, color); } } } From 856ee9a0fe7ae60d0106ed70902241d30427270c Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 17:13:32 +0100 Subject: [PATCH 11/93] Don't allow whitespace player names, closes #840 --- src/level/player_profile.cpp | 2 +- src/ui/screen/screen_player_select.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/level/player_profile.cpp b/src/level/player_profile.cpp index d3603f1c..bedd76cd 100644 --- a/src/level/player_profile.cpp +++ b/src/level/player_profile.cpp @@ -133,7 +133,7 @@ std::string CPlayerProfile::GetLastName() { std::string name; - if(!GetConfigFile().GetStringProperty("Gamer", "LastName", name)) + if(!GetConfigFile().GetStringProperty("Gamer", "LastName", name) || name.empty()) GetResource(RES_TEXT, RT_NAME_DEFAULT, name); return name; diff --git a/src/ui/screen/screen_player_select.cpp b/src/ui/screen/screen_player_select.cpp index 4bcd139b..e3a9c2f3 100644 --- a/src/ui/screen/screen_player_select.cpp +++ b/src/ui/screen/screen_player_select.cpp @@ -40,6 +40,8 @@ #include "ui/controls/list.h" #include "ui/controls/window.h" +#include + namespace Ui { @@ -245,6 +247,7 @@ void CScreenPlayerSelect::UpdateNameControl() total = pl->GetTotal(); sel = pl->GetSelect(); name = pe->GetText(100); + boost::trim(name); pb = static_cast(pw->SearchControl(EVENT_INTERFACE_NDELETE)); if ( pb != nullptr ) @@ -379,6 +382,7 @@ bool CScreenPlayerSelect::NameCreate() std::string name; name = pe->GetText(100); + boost::trim(name); if ( name.empty() ) { m_sound->Play(SOUND_TZOING); From 3bac0aabd98d52eb2e5d33c8e192961f5f7368a1 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 17:26:37 +0100 Subject: [PATCH 12/93] Fix buffer overrun when rendering goto() debug texture, closes #841 --- src/graphics/engine/engine.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index b2aa631f..3110cd37 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -4404,6 +4404,9 @@ void CEngine::UpdateGroundSpotTextures() { int px = x / 4.0f / 254.0f * size.x; int py = y / 4.0f / 254.0f * size.y; + // This can happen because the shadow??.png textures have a 1 pixel margin around them + if (px < 0 || px >= size.x || py < 0 || py >= size.y) + continue; shadowImg.SetPixelInt(Math::IntPoint(x-min.x, y-min.y), m_displayGotoImage->GetPixelInt(Math::IntPoint(px, py))); } } From 8764d28e9e7d168e2b15245b75977b6141dec4b0 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 18:02:39 +0100 Subject: [PATCH 13/93] Remove remaining "this != nullptr" checks in CBOT, closes #828 --- CMakeLists.txt | 1 - src/CBot/CBotCStack.cpp | 2 +- src/CBot/CBotClass.cpp | 6 +- src/CBot/CBotInstr/CBotFunction.cpp | 49 ++++++++-------- src/CBot/CBotInstr/CBotFunction.h | 87 ++++++++++++++--------------- src/CBot/CBotStack.cpp | 6 +- 6 files changed, 76 insertions(+), 75 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 91a862c5..bc287243 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,7 +133,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") message(STATUS "Detected GCC version 4.7+") set(NORMAL_CXX_FLAGS "-std=gnu++11 -Wall -Wold-style-cast -pedantic-errors") - set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -fno-delete-null-pointer-checks") # Temporary hack, see #828 set(RELEASE_CXX_FLAGS "-O2") set(DEBUG_CXX_FLAGS "-g -O0") set(TEST_CXX_FLAGS "-pthread") diff --git a/src/CBot/CBotCStack.cpp b/src/CBot/CBotCStack.cpp index c8c01346..044a473e 100644 --- a/src/CBot/CBotCStack.cpp +++ b/src/CBot/CBotCStack.cpp @@ -350,7 +350,7 @@ CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nId val = m_prog->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this); if (val.GetType() < 0) { - val = m_prog->GetFunctions()->CompileCall(p->GetString(), ppVars, nIdent); + val = CBotFunction::CompileCall(m_prog->GetFunctions(), p->GetString(), ppVars, nIdent); if ( val.GetType() < 0 ) { // pVar = nullptr; // the error is not on a particular parameter diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index 8efc4af8..0eb86db0 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -331,7 +331,7 @@ CBotTypResult CBotClass::CompileMethode(const std::string& name, // find the methods declared by user - r = m_pMethod->CompileCall(name, ppParams, nIdent); + r = CBotFunction::CompileCall(m_pMethod, name, ppParams, nIdent); if ( r.Eq(CBotErrUndefCall) && m_parent != nullptr ) return m_parent->CompileMethode(name, pThis, ppParams, pStack, nIdent); return r; @@ -349,7 +349,7 @@ bool CBotClass::ExecuteMethode(long& nIdent, int ret = m_pCalls->DoCall(name, pThis, ppParams, pResult, pStack, pToken); if (ret>=0) return ret; - ret = m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, this); + ret = CBotFunction::DoCall(m_pMethod, nIdent, name, pThis, ppParams, pStack, pToken, this); if (ret >= 0) return ret; if (m_parent != nullptr) @@ -369,7 +369,7 @@ void CBotClass::RestoreMethode(long& nIdent, CBotClass* pClass = this; while (pClass != nullptr) { - bool ok = pClass->m_pMethod->RestoreCall(nIdent, name, pThis, ppParams, pStack, pClass); + bool ok = CBotFunction::RestoreCall(pClass->m_pMethod, nIdent, name, pThis, ppParams, pStack, pClass); if (ok) return; pClass = pClass->m_parent; } diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 0b1e05b5..2885f1a9 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -421,26 +421,27 @@ void CBotFunction::AddNext(CBotFunction* p) } //////////////////////////////////////////////////////////////////////////////// -CBotTypResult CBotFunction::CompileCall(const std::string& name, CBotVar** ppVars, long& nIdent) +CBotTypResult CBotFunction::CompileCall(CBotFunction* localFunctionList, const std::string &name, CBotVar** ppVars, long &nIdent) { - nIdent = 0; - CBotTypResult type; - -// CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type); - FindLocalOrPublic(nIdent, name, ppVars, type); + CBotTypResult type; + if (!FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type)) + { + // Reset the identifier to "not found" value + nIdent = 0; + } return type; } //////////////////////////////////////////////////////////////////////////////// -CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& name, CBotVar** ppVars, - CBotTypResult& TypeOrError, bool bPublic) +CBotFunction* CBotFunction::FindLocalOrPublic(CBotFunction* localFunctionList, long &nIdent, const std::string &name, + CBotVar** ppVars, CBotTypResult &TypeOrError, bool bPublic) { TypeOrError.SetType(CBotErrUndefCall); // no routine of the name CBotFunction* pt; if ( nIdent ) { - if ( this != nullptr ) for ( pt = this ; pt != nullptr ; pt = pt->m_next ) + if ( localFunctionList != nullptr ) for ( pt = localFunctionList ; pt != nullptr ; pt = pt->m_next ) { if ( pt->m_nFuncIdent == nIdent ) { @@ -464,9 +465,9 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n std::map funcMap; - if ( this != nullptr ) + if ( localFunctionList != nullptr ) { - for ( pt = this ; pt != nullptr ; pt = pt->m_next ) + for ( pt = localFunctionList ; pt != nullptr ; pt = pt->m_next ) { if ( pt->m_token.GetString() == name ) { @@ -610,12 +611,13 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n } //////////////////////////////////////////////////////////////////////////////// -int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken) +int CBotFunction::DoCall(CBotProgram* program, CBotFunction* localFunctionList, long &nIdent, const std::string &name, + CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken) { CBotTypResult type; CBotFunction* pt = nullptr; - pt = FindLocalOrPublic(nIdent, name, ppVars, type); + pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type); if ( pt != nullptr ) { @@ -634,7 +636,7 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars { if ( !pt->m_MasterClass.empty() ) { - CBotVar* pInstance = m_pProg->m_thisVar; + CBotVar* pInstance = program->m_thisVar; // make "this" known CBotVar* pThis ; if ( pInstance == nullptr ) @@ -670,7 +672,7 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars if ( !pStk3->GetRetVar( // puts the result on the stack pt->m_block->Execute(pStk3) )) // GetRetVar said if it is interrupted { - if ( !pStk3->IsOk() && pt->m_pProg != m_pProg ) + if ( !pStk3->IsOk() && pt->m_pProg != program ) { pStk3->SetPosError(pToken); // indicates the error on the procedure call } @@ -683,7 +685,8 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars } //////////////////////////////////////////////////////////////////////////////// -void CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar** ppVars, CBotStack* pStack) +void CBotFunction::RestoreCall(CBotFunction* localFunctionList, + long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack) { CBotTypResult type; CBotFunction* pt = nullptr; @@ -692,7 +695,7 @@ void CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar** // search function to return the ok identifier - pt = FindLocalOrPublic(nIdent, name, ppVars, type); + pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type); if ( pt != nullptr ) { @@ -740,13 +743,13 @@ void CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar** } //////////////////////////////////////////////////////////////////////////////// -int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, - CBotToken* pToken, CBotClass* pClass) +int CBotFunction::DoCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, + CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass) { CBotTypResult type; CBotProgram* pProgCurrent = pStack->GetProgram(); - CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false); + CBotFunction* pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type, false); if ( pt != nullptr ) { @@ -822,11 +825,11 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar* pThis, } //////////////////////////////////////////////////////////////////////////////// -bool CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar* pThis, CBotVar** ppVars, - CBotStack* pStack, CBotClass* pClass) +bool CBotFunction::RestoreCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, + CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass) { CBotTypResult type; - CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type); + CBotFunction* pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type); if ( pt != nullptr ) { diff --git a/src/CBot/CBotInstr/CBotFunction.h b/src/CBot/CBotInstr/CBotFunction.h index 76a02bc0..d2f766c7 100644 --- a/src/CBot/CBotInstr/CBotFunction.h +++ b/src/CBot/CBotInstr/CBotFunction.h @@ -98,33 +98,43 @@ public: void AddNext(CBotFunction* p); /*! - * \brief CompileCall - * \param name - * \param ppVars - * \param nIdent - * \return + * \brief Compile a function call + * + * See FindLocalOrPublic for more detailed explanation + * + * \param localFunctionList Linked list of local functions to search in, can be null + * \param name Name of the function + * \param ppVars List of function arguments + * \param nIdent[in, out] Unique identifier of the function + * \return Type returned by the function or error code + * \see FindLocalOrPublic */ - CBotTypResult CompileCall(const std::string& name, - CBotVar** ppVars, - long& nIdent); + static CBotTypResult CompileCall(CBotFunction* localFunctionList, + const std::string &name, CBotVar** ppVars, long &nIdent); /*! - * \brief FindLocalOrPublic Is a function according to its unique identifier - * if the identifier is not found, looking by name and parameters. - * \param nIdent - * \param name - * \param ppVars - * \param TypeOrError - * \param bPublic - * \return + * \brief Finds a local or public function + * + *

Finds a local or (if bPublic is true) public function to call + * + *

First, it looks for a function according to its unique identifier.
+ * If the identifier is not found, looks by name and parameters. + * + * \param localFunctionList Linked list of local functions to search in, can be null + * \param nIdent[in, out] Unique identifier of the function + * \param name Name of the function + * \param ppVars List of function arguments + * \param TypeOrError Type returned by the function or error code + * \param bPublic Whether to look in public functions or not + * \return Pointer to found CBotFunction instance, or nullptr in case of no match or ambiguity (see TypeOrError for error code) */ - CBotFunction* FindLocalOrPublic(long& nIdent, const std::string& name, - CBotVar** ppVars, - CBotTypResult& TypeOrError, - bool bPublic = true); + static CBotFunction* FindLocalOrPublic(CBotFunction* localFunctionList, long &nIdent, const std::string &name, + CBotVar** ppVars, CBotTypResult &TypeOrError, bool bPublic = true); /*! * \brief DoCall Fait un appel à une fonction. + * \param program + * \param localFunctionList * \param nIdent * \param name * \param ppVars @@ -133,27 +143,24 @@ public: * \return */ - int DoCall(long& nIdent, - const std::string& name, - CBotVar** ppVars, - CBotStack* pStack, - CBotToken* pToken); + static int DoCall(CBotProgram* program, CBotFunction* localFunctionList, long &nIdent, const std::string &name, + CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken); /*! * \brief RestoreCall + * \param localFunctionList * \param nIdent * \param name * \param ppVars * \param pStack */ - void RestoreCall(long& nIdent, - const std::string& name, - CBotVar** ppVars, - CBotStack* pStack); + static void RestoreCall(CBotFunction* localFunctionList, + long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack); /*! - * \brief DoCall Makes call of a method note: this is already on the stack, - * the pointer pThis is just to simplify. + * \brief DoCall Makes call of a method + * note: this is already on the stack, the pointer pThis is just to simplify. + * \param localFunctionList * \param nIdent * \param name * \param pThis @@ -163,16 +170,12 @@ public: * \param pClass * \return */ - int DoCall(long& nIdent, - const std::string& name, - CBotVar* pThis, - CBotVar** ppVars, - CBotStack* pStack, - CBotToken* pToken, - CBotClass* pClass); + static int DoCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, + CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass); /*! * \brief RestoreCall + * \param localFunctionList * \param nIdent * \param name * \param pThis @@ -181,12 +184,8 @@ public: * \param pClass * \return Returns true if the method call was restored. */ - bool RestoreCall(long& nIdent, - const std::string& name, - CBotVar* pThis, - CBotVar** ppVars, - CBotStack* pStack, - CBotClass* pClass); + static bool RestoreCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, + CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass); /*! * \brief CheckParam See if the "signature" of parameters is identical. diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index 94697b4a..c554d7ca 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -568,7 +568,7 @@ bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, con res = m_prog->GetExternalCalls()->DoCall(nullptr, nullptr, ppVar, this, rettype); if (res >= 0) return res; - res = m_prog->GetFunctions()->DoCall(nIdent, "", ppVar, this, token ); + res = CBotFunction::DoCall(m_prog, m_prog->GetFunctions(), nIdent, "", ppVar, this, token); if (res >= 0) return res; // if not found (recompile?) seeks by name @@ -577,7 +577,7 @@ bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, con res = m_prog->GetExternalCalls()->DoCall(token, nullptr, ppVar, this, rettype); if (res >= 0) return res; - res = m_prog->GetFunctions()->DoCall(nIdent, token->GetString(), ppVar, this, token ); + res = CBotFunction::DoCall(m_prog, m_prog->GetFunctions(), nIdent, token->GetString(), ppVar, this, token); if (res >= 0) return res; SetError(CBotErrUndefFunc, token); @@ -592,7 +592,7 @@ void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar) if (m_prog->GetExternalCalls()->RestoreCall(token, nullptr, ppVar, this)) return; - m_prog->GetFunctions()->RestoreCall(nIdent, token->GetString(), ppVar, this); + CBotFunction::RestoreCall(m_prog->GetFunctions(), nIdent, token->GetString(), ppVar, this); } //////////////////////////////////////////////////////////////////////////////// From 266b34d578cbbb8ed55c4e8ecdf9c9b195cd7756 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 18:16:12 +0100 Subject: [PATCH 14/93] Make CBotFunction implement CBotLinkedList --- src/CBot/CBotCStack.cpp | 2 +- src/CBot/CBotClass.cpp | 4 ++-- src/CBot/CBotDebug.cpp | 4 ++-- src/CBot/CBotInstr/CBotFunction.cpp | 21 ++------------------- src/CBot/CBotInstr/CBotFunction.h | 16 +++------------- src/CBot/CBotProgram.cpp | 6 +++--- 6 files changed, 13 insertions(+), 40 deletions(-) diff --git a/src/CBot/CBotCStack.cpp b/src/CBot/CBotCStack.cpp index 044a473e..ef3c4091 100644 --- a/src/CBot/CBotCStack.cpp +++ b/src/CBot/CBotCStack.cpp @@ -378,7 +378,7 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam) if ( pp->CheckParam( pParam ) ) return true; } - pp = pp->Next(); + pp = pp->GetNext(); } for (CBotFunction* pp : CBotFunction::m_publicFunctions) diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index 0eb86db0..bd956051 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -464,7 +464,7 @@ bool CBotClass::CheckCall(CBotProgram* program, CBotDefParam* pParam, CBotToken* if ( pp->CheckParam( pParam ) ) return true; } - pp = pp->Next(); + pp = pp->GetNext(); } return false; @@ -647,7 +647,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) while ( pf != nullptr ) // search by name and parameters { if (pf->GetName() == pp && pf->CheckParam( params )) break; - pf = pf->Next(); + pf = pf->GetNext(); } bool bConstructor = (pp == GetName()); diff --git a/src/CBot/CBotDebug.cpp b/src/CBot/CBotDebug.cpp index 652bd704..d71eac31 100644 --- a/src/CBot/CBotDebug.cpp +++ b/src/CBot/CBotDebug.cpp @@ -41,7 +41,7 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program) while (func != nullptr) { funcIdMap[func->m_nFuncIdent] = func; - func = func->Next(); + func = func->GetNext(); } std::set finished; @@ -123,7 +123,7 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program) prev = GetPointerAsString(func); } - func = func->Next(); + func = func->GetNext(); } ss << "}" << std::endl; diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 2885f1a9..2d92910a 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -46,7 +46,6 @@ CBotFunction::CBotFunction() { m_param = nullptr; // empty parameter list m_block = nullptr; // the instruction block - m_next = nullptr; // functions can be chained m_bPublic = false; // function not public m_bExtern = false; // function not extern m_pProg = nullptr; @@ -63,7 +62,6 @@ CBotFunction::~CBotFunction() { delete m_param; // empty parameter list delete m_block; // the instruction block - delete m_next; // remove public list if there is if (m_bPublic) @@ -411,15 +409,6 @@ void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInst m_block->RestoreState(pile2, true); } -//////////////////////////////////////////////////////////////////////////////// -void CBotFunction::AddNext(CBotFunction* p) -{ - CBotFunction* pp = this; - while (pp->m_next != nullptr) pp = pp->m_next; - - pp->m_next = p; -} - //////////////////////////////////////////////////////////////////////////////// CBotTypResult CBotFunction::CompileCall(CBotFunction* localFunctionList, const std::string &name, CBotVar** ppVars, long &nIdent) { @@ -441,7 +430,7 @@ CBotFunction* CBotFunction::FindLocalOrPublic(CBotFunction* localFunctionList, l if ( nIdent ) { - if ( localFunctionList != nullptr ) for ( pt = localFunctionList ; pt != nullptr ; pt = pt->m_next ) + if ( localFunctionList != nullptr ) for ( pt = localFunctionList ; pt != nullptr ; pt = pt->GetNext() ) { if ( pt->m_nFuncIdent == nIdent ) { @@ -467,7 +456,7 @@ CBotFunction* CBotFunction::FindLocalOrPublic(CBotFunction* localFunctionList, l if ( localFunctionList != nullptr ) { - for ( pt = localFunctionList ; pt != nullptr ; pt = pt->m_next ) + for ( pt = localFunctionList ; pt != nullptr ; pt = pt->GetNext() ) { if ( pt->m_token.GetString() == name ) { @@ -906,12 +895,6 @@ std::string CBotFunction::GetParams() return params; } -//////////////////////////////////////////////////////////////////////////////// -CBotFunction* CBotFunction::Next() -{ - return m_next; -} - //////////////////////////////////////////////////////////////////////////////// void CBotFunction::AddPublic(CBotFunction* func) { diff --git a/src/CBot/CBotInstr/CBotFunction.h b/src/CBot/CBotInstr/CBotFunction.h index d2f766c7..6a0180fd 100644 --- a/src/CBot/CBotInstr/CBotFunction.h +++ b/src/CBot/CBotInstr/CBotFunction.h @@ -39,7 +39,7 @@ namespace CBot * void classname::test() { ... } * \endcode */ -class CBotFunction : public CBotInstr +class CBotFunction : public CBotInstr, public CBotLinkedList { public: CBotFunction(); @@ -91,11 +91,8 @@ public: CBotStack* &pj, CBotVar* pInstance = nullptr); - /*! - * \brief AddNext - * \param p - */ - void AddNext(CBotFunction* p); + using CBotLinkedList::GetNext; + using CBotLinkedList::AddNext; /*! * \brief Compile a function call @@ -224,12 +221,6 @@ public: */ bool IsExtern(); - /*! - * \brief Next - * \return - */ - CBotFunction* Next(); - /*! * \brief GetPosition * \param start @@ -257,7 +248,6 @@ private: CBotDefParam* m_param; //! The instruction block. CBotInstr* m_block; - CBotFunction* m_next; //! If returns CBotTypClass. CBotToken m_retToken; //! Complete type of the result. diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index 17c5ec0a..6e8b6a69 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -132,7 +132,7 @@ bool CBotProgram::Compile(const std::string& program, std::vector& if (next->IsExtern()) functions.push_back(next->GetName()/* + next->GetParams()*/); if (next->IsPublic()) CBotFunction::AddPublic(next); next->m_pProg = this; // keeps pointers to the module - next = next->Next(); + next = next->GetNext(); } } @@ -157,7 +157,7 @@ bool CBotProgram::Start(const std::string& name) while (m_entryPoint != nullptr) { if (m_entryPoint->GetName() == name ) break; - m_entryPoint = m_entryPoint->m_next; + m_entryPoint = m_entryPoint->GetNext(); } if (m_entryPoint == nullptr) @@ -178,7 +178,7 @@ bool CBotProgram::GetPosition(const std::string& name, int& start, int& stop, CB while (p != nullptr) { if ( p->GetName() == name ) break; - p = p->m_next; + p = p->GetNext(); } if ( p == nullptr ) return false; From 191151eb7b4674d69a1d52d88c1261fd13d5a893 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 19:35:43 +0100 Subject: [PATCH 15/93] Refactor CBotClass and CBotFunction list to std::list --- src/CBot/CBotCStack.cpp | 4 +- src/CBot/CBotClass.cpp | 38 ++++------ src/CBot/CBotClass.h | 11 +-- src/CBot/CBotDebug.cpp | 8 +-- src/CBot/CBotInstr/CBotFunction.cpp | 106 +++++++++++++--------------- src/CBot/CBotInstr/CBotFunction.h | 12 ++-- src/CBot/CBotProgram.cpp | 92 +++++++++++------------- src/CBot/CBotProgram.h | 13 ++-- test/unit/CBot/CBot_test.cpp | 2 +- 9 files changed, 127 insertions(+), 159 deletions(-) diff --git a/src/CBot/CBotCStack.cpp b/src/CBot/CBotCStack.cpp index ef3c4091..a2f191d7 100644 --- a/src/CBot/CBotCStack.cpp +++ b/src/CBot/CBotCStack.cpp @@ -369,8 +369,7 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam) if ( m_prog->GetExternalCalls()->CheckCall(name) ) return true; - CBotFunction* pp = m_prog->GetFunctions(); - while ( pp != nullptr ) + for (CBotFunction* pp : m_prog->GetFunctions()) { if ( pToken->GetString() == pp->GetName() ) { @@ -378,7 +377,6 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam) if ( pp->CheckParam( pParam ) ) return true; } - pp = pp->GetNext(); } for (CBotFunction* pp : CBotFunction::m_publicFunctions) diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index bd956051..77998b3c 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -56,7 +56,6 @@ CBotClass::CBotClass(const std::string& name, m_name = name; m_pVar = nullptr; m_pCalls = nullptr; - m_pMethod = nullptr; m_rUpdate = nullptr; m_IsDef = true; m_bIntrinsic= bIntrinsic; @@ -72,7 +71,6 @@ CBotClass::~CBotClass() delete m_pVar; delete m_pCalls; - delete m_pMethod; } //////////////////////////////////////////////////////////////////////////////// @@ -98,14 +96,11 @@ void CBotClass::Purge() m_pVar = nullptr; delete m_pCalls; m_pCalls = nullptr; - delete m_pMethod; - m_pMethod = nullptr; + for (CBotFunction* f : m_pMethod) delete f; + m_pMethod.clear(); m_IsDef = false; m_nbVar = m_parent == nullptr ? 0 : m_parent->m_nbVar; - - if (m_next != nullptr) m_next->Purge(); - m_next = nullptr; // no longer belongs to this chain } //////////////////////////////////////////////////////////////////////////////// @@ -455,8 +450,7 @@ bool CBotClass::CheckCall(CBotProgram* program, CBotDefParam* pParam, CBotToken* if ( program->GetExternalCalls()->CheckCall(name) ) return true; - CBotFunction* pp = m_pMethod; - while ( pp != nullptr ) + for (CBotFunction* pp : m_pMethod) { if ( pToken->GetString() == pp->GetName() ) { @@ -464,7 +458,6 @@ bool CBotClass::CheckCall(CBotProgram* program, CBotDefParam* pParam, CBotToken* if ( pp->CheckParam( pParam ) ) return true; } - pp = pp->GetNext(); } return false; @@ -506,7 +499,7 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack) } } CBotClass* classe = (pOld == nullptr) ? new CBotClass(name, pPapa) : pOld; - classe->Purge(); // empty the old definitions // TODO: Doesn't this remove all classes of the current program? + classe->Purge(); // empty the old definitions classe->m_IsDef = false; // current definition classe->m_pOpenblk = p; @@ -536,9 +529,9 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack) } //////////////////////////////////////////////////////////////////////////////// -void CBotClass::DefineClasses(CBotClass* pClass, CBotCStack* pStack) +void CBotClass::DefineClasses(std::list pClassList, CBotCStack* pStack) { - while (pClass != nullptr) + for (CBotClass* pClass : pClassList) { CBotClass* pParent = pClass->m_parent; pClass->m_nbVar = (pParent == nullptr) ? 0 : pParent->m_nbVar; @@ -550,8 +543,6 @@ void CBotClass::DefineClasses(CBotClass* pClass, CBotCStack* pStack) } if (!pStack->IsOk()) return; - - pClass = pClass->GetNext(); } } @@ -627,28 +618,25 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) if ( !bSecond ) { p = pBase; - CBotFunction* f = - CBotFunction::Compile1(p, pStack, this); + CBotFunction* f = CBotFunction::Compile1(p, pStack, this); if ( f == nullptr ) return false; - if (m_pMethod == nullptr) m_pMethod = f; - else m_pMethod->AddNext(f); + m_pMethod.push_back(f); } else { // return a method precompiled in pass 1 - CBotFunction* pf = m_pMethod; 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 && pf->CheckParam( params )) break; - pf = pf->GetNext(); - } + std::list::iterator pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, ¶ms](CBotFunction* x) { + return x->GetName() == pp && x->CheckParam( params ); + }); + assert(pfIter != m_pMethod.end()); + CBotFunction* pf = *pfIter; bool bConstructor = (pp == GetName()); CBotCStack* pile = pStack->TokenStack(nullptr, true); diff --git a/src/CBot/CBotClass.h b/src/CBot/CBotClass.h index 2fc494dc..94ab341c 100644 --- a/src/CBot/CBotClass.h +++ b/src/CBot/CBotClass.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace CBot { @@ -102,7 +103,7 @@ class CBotCStack; * float y = var->GetValFloat(); * \endcode */ -class CBotClass : public CBotLinkedList +class CBotClass { public: /*! @@ -294,10 +295,10 @@ public: /*! * \brief DefineClasses Calls CompileDefItem for each class in a list * of classes, defining fields and pre-compiling methods. - * \param pClass List of classes + * \param pClassList List of classes * \param pStack */ - static void DefineClasses(CBotClass* pClass, CBotCStack* pStack); + static void DefineClasses(std::list pClassList, CBotCStack* pStack); /*! * \brief CompileDefItem @@ -389,8 +390,8 @@ private: CBotVar* m_pVar; //! Linked list of all class external calls CBotCallMethode* m_pCalls; - //! Linked list of all class methods - CBotFunction* m_pMethod; + //! List of all class methods + std::list m_pMethod{}; void (*m_rUpdate)(CBotVar* thisVar, void* user); CBotToken* m_pOpenblk; diff --git a/src/CBot/CBotDebug.cpp b/src/CBot/CBotDebug.cpp index d71eac31..db0c5591 100644 --- a/src/CBot/CBotDebug.cpp +++ b/src/CBot/CBotDebug.cpp @@ -36,9 +36,8 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program) std::stringstream ss; ss << "digraph {" << std::endl; - CBotFunction* func = program->GetFunctions(); std::map funcIdMap; - while (func != nullptr) + for (CBotFunction* func : program->GetFunctions()) { funcIdMap[func->m_nFuncIdent] = func; func = func->GetNext(); @@ -111,9 +110,8 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program) { DumpInstr(program->m_entryPoint); } - func = program->GetFunctions(); std::string prev = GetPointerAsString(program->m_entryPoint); - while (func != nullptr) + for (CBotFunction* func : program->GetFunctions()) { if (func != program->m_entryPoint) { @@ -122,8 +120,6 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program) //ss << prev << " -> " << GetPointerAsString(func) << " [style=invis]" << std::endl; prev = GetPointerAsString(func); } - - func = func->GetNext(); } ss << "}" << std::endl; diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 2d92910a..c8db69a9 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -410,7 +410,7 @@ void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInst } //////////////////////////////////////////////////////////////////////////////// -CBotTypResult CBotFunction::CompileCall(CBotFunction* localFunctionList, const std::string &name, CBotVar** ppVars, long &nIdent) +CBotTypResult CBotFunction::CompileCall(const std::list& localFunctionList, const std::string &name, CBotVar** ppVars, long &nIdent) { CBotTypResult type; if (!FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type)) @@ -422,17 +422,16 @@ CBotTypResult CBotFunction::CompileCall(CBotFunction* localFunctionList, const s } //////////////////////////////////////////////////////////////////////////////// -CBotFunction* CBotFunction::FindLocalOrPublic(CBotFunction* localFunctionList, long &nIdent, const std::string &name, +CBotFunction* CBotFunction::FindLocalOrPublic(const std::list& localFunctionList, long &nIdent, const std::string &name, CBotVar** ppVars, CBotTypResult &TypeOrError, bool bPublic) { TypeOrError.SetType(CBotErrUndefCall); // no routine of the name - CBotFunction* pt; if ( nIdent ) { - if ( localFunctionList != nullptr ) for ( pt = localFunctionList ; pt != nullptr ; pt = pt->GetNext() ) + for (CBotFunction* pt : localFunctionList) { - if ( pt->m_nFuncIdent == nIdent ) + if (pt->m_nFuncIdent == nIdent) { TypeOrError = pt->m_retTyp; return pt; @@ -454,62 +453,59 @@ CBotFunction* CBotFunction::FindLocalOrPublic(CBotFunction* localFunctionList, l std::map funcMap; - if ( localFunctionList != nullptr ) + for (CBotFunction* pt : localFunctionList) { - for ( pt = localFunctionList ; pt != nullptr ; pt = pt->GetNext() ) + if ( pt->m_token.GetString() == name ) { - if ( pt->m_token.GetString() == name ) + int i = 0; + int alpha = 0; // signature of parameters + // parameters are compatible? + CBotDefParam* pv = pt->m_param; // expected list of parameters + CBotVar* pw = ppVars[i++]; // provided list parameter + while ( pv != nullptr && pw != nullptr) { - int i = 0; - int alpha = 0; // signature of parameters - // parameters are compatible? - CBotDefParam* pv = pt->m_param; // expected list of parameters - CBotVar* pw = ppVars[i++]; // provided list parameter - while ( pv != nullptr && pw != nullptr) - { - CBotTypResult paramType = pv->GetTypResult(); - CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); + CBotTypResult paramType = pv->GetTypResult(); + CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); - if (!TypesCompatibles(paramType, argType)) - { - if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam); - break; - } + if (!TypesCompatibles(paramType, argType)) + { + if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam); + break; + } - if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer)) - { - CBotClass* c1 = paramType.GetClass(); - CBotClass* c2 = argType.GetClass(); - while (c2 != c1 && c2 != nullptr) // implicit cast - { - alpha += 10; - c2 = c2->GetParent(); - } - } - else - { - int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); - alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive! - } - pv = pv->GetNext(); - pw = ppVars[i++]; - } - if ( pw != nullptr ) + if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer)) { - if ( !funcMap.empty() ) continue; - if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam); - if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam); - continue; // too many parameters + CBotClass* c1 = paramType.GetClass(); + CBotClass* c2 = argType.GetClass(); + while (c2 != c1 && c2 != nullptr) // implicit cast + { + alpha += 10; + c2 = c2->GetParent(); + } } - if ( pv != nullptr ) + else { - if ( !funcMap.empty() ) continue; - if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam); - if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam); - continue; // not enough parameters + int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); + alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive! } - funcMap.insert( std::pair(pt, alpha) ); + pv = pv->GetNext(); + pw = ppVars[i++]; } + if ( pw != nullptr ) + { + if ( !funcMap.empty() ) continue; + if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam); + if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam); + continue; // too many parameters + } + if ( pv != nullptr ) + { + if ( !funcMap.empty() ) continue; + if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam); + if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam); + continue; // not enough parameters + } + funcMap.insert( std::pair(pt, alpha) ); } } @@ -600,7 +596,7 @@ CBotFunction* CBotFunction::FindLocalOrPublic(CBotFunction* localFunctionList, l } //////////////////////////////////////////////////////////////////////////////// -int CBotFunction::DoCall(CBotProgram* program, CBotFunction* localFunctionList, long &nIdent, const std::string &name, +int CBotFunction::DoCall(CBotProgram* program, const std::list& localFunctionList, long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken) { CBotTypResult type; @@ -674,7 +670,7 @@ int CBotFunction::DoCall(CBotProgram* program, CBotFunction* localFunctionList, } //////////////////////////////////////////////////////////////////////////////// -void CBotFunction::RestoreCall(CBotFunction* localFunctionList, +void CBotFunction::RestoreCall(const std::list& localFunctionList, long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack) { CBotTypResult type; @@ -732,7 +728,7 @@ void CBotFunction::RestoreCall(CBotFunction* localFunctionList, } //////////////////////////////////////////////////////////////////////////////// -int CBotFunction::DoCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, +int CBotFunction::DoCall(const std::list& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass) { CBotTypResult type; @@ -814,7 +810,7 @@ int CBotFunction::DoCall(CBotFunction* localFunctionList, long &nIdent, const st } //////////////////////////////////////////////////////////////////////////////// -bool CBotFunction::RestoreCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, +bool CBotFunction::RestoreCall(const std::list& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass) { CBotTypResult type; diff --git a/src/CBot/CBotInstr/CBotFunction.h b/src/CBot/CBotInstr/CBotFunction.h index 6a0180fd..32214960 100644 --- a/src/CBot/CBotInstr/CBotFunction.h +++ b/src/CBot/CBotInstr/CBotFunction.h @@ -106,7 +106,7 @@ public: * \return Type returned by the function or error code * \see FindLocalOrPublic */ - static CBotTypResult CompileCall(CBotFunction* localFunctionList, + static CBotTypResult CompileCall(const std::list& localFunctionList, const std::string &name, CBotVar** ppVars, long &nIdent); /*! @@ -125,7 +125,7 @@ public: * \param bPublic Whether to look in public functions or not * \return Pointer to found CBotFunction instance, or nullptr in case of no match or ambiguity (see TypeOrError for error code) */ - static CBotFunction* FindLocalOrPublic(CBotFunction* localFunctionList, long &nIdent, const std::string &name, + static CBotFunction* FindLocalOrPublic(const std::list& localFunctionList, long &nIdent, const std::string &name, CBotVar** ppVars, CBotTypResult &TypeOrError, bool bPublic = true); /*! @@ -140,7 +140,7 @@ public: * \return */ - static int DoCall(CBotProgram* program, CBotFunction* localFunctionList, long &nIdent, const std::string &name, + static int DoCall(CBotProgram* program, const std::list& localFunctionList, long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken); /*! @@ -151,7 +151,7 @@ public: * \param ppVars * \param pStack */ - static void RestoreCall(CBotFunction* localFunctionList, + static void RestoreCall(const std::list& localFunctionList, long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack); /*! @@ -167,7 +167,7 @@ public: * \param pClass * \return */ - static int DoCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, + static int DoCall(const std::list& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass); /*! @@ -181,7 +181,7 @@ public: * \param pClass * \return Returns true if the method call was restored. */ - static bool RestoreCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, + static bool RestoreCall(const std::list& localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass); /*! diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index 6e8b6a69..978c6410 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -30,6 +30,8 @@ #include "CBot/stdlib/stdlib.h" +#include + namespace CBot { @@ -47,27 +49,30 @@ CBotProgram::CBotProgram(CBotVar* thisVar) CBotProgram::~CBotProgram() { // delete m_classes; - if (m_classes != nullptr) m_classes->Purge(); - m_classes = nullptr; + for (CBotClass* c : m_classes) + c->Purge(); + m_classes.clear(); CBotClass::FreeLock(this); - delete m_functions; - if (m_stack != nullptr) m_stack->Delete(); + for (CBotFunction* f : m_functions) delete f; + m_functions.clear(); } -bool CBotProgram::Compile(const std::string& program, std::vector& functions, void* pUser) +bool CBotProgram::Compile(const std::string& program, std::vector& externFunctions, void* pUser) { // Cleanup the previously compiled program Stop(); -// delete m_classes; - if (m_classes != nullptr) m_classes->Purge(); // purge the old definitions of classes - // but without destroying the object - m_classes = nullptr; - delete m_functions; m_functions = nullptr; + for (CBotClass* c : m_classes) + c->Purge(); // purge the old definitions of classes + // but without destroying the object - functions.clear(); + m_classes.clear(); + for (CBotFunction* f : m_functions) delete f; + m_functions.clear(); + + externFunctions.clear(); m_error = CBotNoErr; // Step 1. Process the code into tokens @@ -88,15 +93,11 @@ bool CBotProgram::Compile(const std::string& program, std::vector& if ( p->GetType() == ID_CLASS || ( p->GetType() == ID_PUBLIC && p->GetNext()->GetType() == ID_CLASS )) { - CBotClass* nxt = CBotClass::Compile1(p, pStack.get()); - if (m_classes == nullptr ) m_classes = nxt; - else m_classes->AddNext(nxt); + m_classes.push_back(CBotClass::Compile1(p, pStack.get())); } else { - CBotFunction* next = CBotFunction::Compile1(p, pStack.get(), nullptr); - if (m_functions == nullptr ) m_functions = next; - else m_functions->AddNext(next); + m_functions.push_back(CBotFunction::Compile1(p, pStack.get(), nullptr)); } } @@ -106,17 +107,14 @@ bool CBotProgram::Compile(const std::string& program, std::vector& if ( !pStack->IsOk() ) { m_error = pStack->GetError(m_errorStart, m_errorEnd); - delete m_functions; - m_functions = nullptr; + for (CBotFunction* f : m_functions) delete f; + m_functions.clear(); return false; } // Step 3. Real compilation -// CBotFunction* temp = nullptr; - CBotFunction* next = m_functions; // rewind the list - + std::list::iterator next = m_functions.begin(); p = tokens.get()->GetNext(); // returns to the beginning - while ( pStack->IsOk() && p != nullptr && p->GetType() != 0 ) { if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking @@ -128,43 +126,37 @@ bool CBotProgram::Compile(const std::string& program, std::vector& } else { - CBotFunction::Compile(p, pStack.get(), next); - if (next->IsExtern()) functions.push_back(next->GetName()/* + next->GetParams()*/); - if (next->IsPublic()) CBotFunction::AddPublic(next); - next->m_pProg = this; // keeps pointers to the module - next = next->GetNext(); + CBotFunction::Compile(p, pStack.get(), *next); + if ((*next)->IsExtern()) externFunctions.push_back((*next)->GetName()/* + next->GetParams()*/); + if ((*next)->IsPublic()) CBotFunction::AddPublic(*next); + (*next)->m_pProg = this; // keeps pointers to the module + ++next; } } -// delete m_Prog; // the list of first pass -// m_Prog = temp; // list of the second pass - if ( !pStack->IsOk() ) { m_error = pStack->GetError(m_errorStart, m_errorEnd); - delete m_functions; - m_functions = nullptr; + for (CBotFunction* f : m_functions) delete f; + m_functions.clear(); } - return (m_functions != nullptr); + return !m_functions.empty(); } bool CBotProgram::Start(const std::string& name) { Stop(); - m_entryPoint = m_functions; - while (m_entryPoint != nullptr) - { - if (m_entryPoint->GetName() == name ) break; - m_entryPoint = m_entryPoint->GetNext(); - } - - if (m_entryPoint == nullptr) + auto it = std::find_if(m_functions.begin(), m_functions.end(), [&name](CBotFunction* x) { + return x->GetName() == name; + }); + if (it == m_functions.end()) { m_error = CBotErrNoRun; return false; } + m_entryPoint = *it; m_stack = CBotStack::AllocateStack(); m_stack->SetProgram(this); @@ -174,16 +166,12 @@ bool CBotProgram::Start(const std::string& name) bool CBotProgram::GetPosition(const std::string& name, int& start, int& stop, CBotGet modestart, CBotGet modestop) { - CBotFunction* p = m_functions; - while (p != nullptr) - { - if ( p->GetName() == name ) break; - p = p->GetNext(); - } + auto it = std::find_if(m_functions.begin(), m_functions.end(), [&name](CBotFunction* x) { + return x->GetName() == name; + }); + if (it == m_functions.end()) return false; - if ( p == nullptr ) return false; - - p->GetPosition(start, stop, modestart, modestop); + (*it)->GetPosition(start, stop, modestart, modestop); return true; } @@ -288,7 +276,7 @@ bool CBotProgram::GetError(CBotError& code, int& start, int& end, CBotProgram*& } //////////////////////////////////////////////////////////////////////////////// -CBotFunction* CBotProgram::GetFunctions() +const std::list& CBotProgram::GetFunctions() { return m_functions; } diff --git a/src/CBot/CBotProgram.h b/src/CBot/CBotProgram.h index 165defc1..d90fb0ef 100644 --- a/src/CBot/CBotProgram.h +++ b/src/CBot/CBotProgram.h @@ -23,6 +23,7 @@ #include "CBot/CBotEnums.h" #include +#include namespace CBot { @@ -124,12 +125,12 @@ public: * 3. Second pass - compiling definitions of all functions and classes * * \param program Code to compile - * \param[out] functions Returns the names of functions declared as extern + * \param[out] externFunctions Returns the names of functions declared as extern * \param pUser Optional pointer to be passed to compile function (see AddFunction()) * \return true if compilation is successful, false if an compilation error occurs * \see GetError() to retrieve the error */ - bool Compile(const std::string& program, std::vector& functions, void* pUser = nullptr); + bool Compile(const std::string& program, std::vector& externFunctions, void* pUser = nullptr); /** * \brief Returns the last error @@ -328,9 +329,9 @@ public: * * This list includes all the functions (not only extern) * - * \return Linked list of CBotFunction instances + * \return List of CBotFunction instances */ - CBotFunction* GetFunctions(); + const std::list& GetFunctions(); /** * \brief Returns static list of all registered external calls @@ -341,11 +342,11 @@ private: //! All external calls static CBotExternalCallList* m_externalCalls; //! All user-defined functions - CBotFunction* m_functions = nullptr; + std::list m_functions{}; //! The entry point function CBotFunction* m_entryPoint = nullptr; //! Classes defined in this program - CBotClass* m_classes = nullptr; + std::list m_classes{}; //! Execution stack CBotStack* m_stack = nullptr; //! "this" variable diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 797a674e..0dae25e0 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -1012,7 +1012,7 @@ TEST_F(CBotUT, ClassInheritanceAssignment) "public class BaseClass {}\n" "public class MidClass extends BaseClass {}\n" "public class SubClass extends MidClass {}\n" - "extern void ClassInheritanceVars()\n" + "extern void ClassInheritanceAssignment()\n" "{\n" " BaseClass bc = new MidClass();\n" " MidClass mc = bc;\n" From 35d60aaae58b88d314dbe2501b5ee415490a1b96 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 19:45:57 +0100 Subject: [PATCH 16/93] Remove remaining occurences of "this == nullptr" (#828) --- src/CBot/CBotProgram.cpp | 3 +-- src/CBot/CBotStack.cpp | 17 +++++++++++++---- src/CBot/CBotToken.cpp | 6 +++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index 978c6410..a303df6d 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -363,8 +363,7 @@ bool CBotProgram::RestoreState(FILE* pf) } // retrieves the stack from the memory - // uses a nullptr pointer (m_stack) but it's ok like that - // TODO: no it's not okay like that! but it looks like it doesn't get optimized out at least ~krzys_h + m_stack = CBotStack::AllocateStack(); if (!m_stack->RestoreState(pf, m_stack)) return false; m_stack->SetProgram(this); // bases for routines diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index c554d7ca..6afcc754 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -192,8 +192,18 @@ bool CBotStack::Return(CBotStack* pfils) m_var = pfils->m_var; // result transmitted pfils->m_var = nullptr; // not to destroy the variable - if (m_next != nullptr) m_next->Delete();m_next = nullptr; // releases the stack above - if (m_next2 != nullptr) m_next2->Delete();m_next2 = nullptr; // also the second stack (catch) + if (m_next != nullptr) + { + // releases the stack above + m_next->Delete(); + m_next = nullptr; + } + if (m_next2 != nullptr) + { + // also the second stack (catch) + m_next2->Delete(); + m_next2 = nullptr; + } return IsOk(); // interrupted if error } @@ -731,8 +741,7 @@ bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack) if (!ReadWord(pf, w)) return false; if ( w == 0 ) return true; // 0 - terminator - if ( this == nullptr ) pStack = AllocateStack(); - else pStack = AddStack(); + pStack = AddStack(); if ( w == 2 ) // 2 - m_next2 { diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp index 890c038a..28e6690c 100644 --- a/src/CBot/CBotToken.cpp +++ b/src/CBot/CBotToken.cpp @@ -199,7 +199,7 @@ const CBotToken& CBotToken::operator=(const CBotToken& src) //////////////////////////////////////////////////////////////////////////////// int CBotToken::GetType() { - if (this == nullptr) return 0; + assert(this != nullptr); if (m_type == TokenTypKeyWord) return m_keywordId; return m_type; } @@ -225,14 +225,14 @@ void CBotToken::SetString(const std::string& name) //////////////////////////////////////////////////////////////////////////////// int CBotToken::GetStart() { - if (this == nullptr) return -1; + assert(this != nullptr); return m_start; } //////////////////////////////////////////////////////////////////////////////// int CBotToken::GetEnd() { - if (this == nullptr) return -1; + assert(this != nullptr); return m_end; } From 6b7233c6aee5f7dc126cfbe444dc829032bc5519 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 19:47:59 +0100 Subject: [PATCH 17/93] Remove CBotLinkedList from CBotFunction Fixup for 191151eb7b4674d69a1d52d88c1261fd13d5a893 No idea how I managed to forget that --- src/CBot/CBotDebug.cpp | 1 - src/CBot/CBotInstr/CBotFunction.h | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/CBot/CBotDebug.cpp b/src/CBot/CBotDebug.cpp index db0c5591..c50bb302 100644 --- a/src/CBot/CBotDebug.cpp +++ b/src/CBot/CBotDebug.cpp @@ -40,7 +40,6 @@ void CBotDebug::DumpCompiledProgram(CBotProgram* program) for (CBotFunction* func : program->GetFunctions()) { funcIdMap[func->m_nFuncIdent] = func; - func = func->GetNext(); } std::set finished; diff --git a/src/CBot/CBotInstr/CBotFunction.h b/src/CBot/CBotInstr/CBotFunction.h index 32214960..66637b51 100644 --- a/src/CBot/CBotInstr/CBotFunction.h +++ b/src/CBot/CBotInstr/CBotFunction.h @@ -39,7 +39,7 @@ namespace CBot * void classname::test() { ... } * \endcode */ -class CBotFunction : public CBotInstr, public CBotLinkedList +class CBotFunction : public CBotInstr { public: CBotFunction(); @@ -91,9 +91,6 @@ public: CBotStack* &pj, CBotVar* pInstance = nullptr); - using CBotLinkedList::GetNext; - using CBotLinkedList::AddNext; - /*! * \brief Compile a function call * From 48f703282ea73c82db611a403d09edf8aee5dc79 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 21:49:27 +0100 Subject: [PATCH 18/93] Refactor CBotCallMethode -> CBotExternalCall --- src/CBot/CBotCallMethode.cpp | 113 ------------------------ src/CBot/CBotCallMethode.h | 88 ------------------ src/CBot/CBotClass.cpp | 58 ++++-------- src/CBot/CBotClass.h | 33 +++---- src/CBot/CBotExternalCall.cpp | 44 +++++++++ src/CBot/CBotExternalCall.h | 30 +++++++ src/CBot/CBotInstr/CBotDefClass.cpp | 12 +-- src/CBot/CBotInstr/CBotInstrMethode.cpp | 33 +------ src/CBot/CBotInstr/CBotNew.cpp | 12 +-- src/CBot/CBotVar/CBotVarClass.cpp | 5 +- src/CBot/CMakeLists.txt | 2 - 11 files changed, 117 insertions(+), 313 deletions(-) delete mode 100644 src/CBot/CBotCallMethode.cpp delete mode 100644 src/CBot/CBotCallMethode.h diff --git a/src/CBot/CBotCallMethode.cpp b/src/CBot/CBotCallMethode.cpp deleted file mode 100644 index 582ce7b5..00000000 --- a/src/CBot/CBotCallMethode.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam - * http://epsitec.ch; http://colobot.info; http://github.com/colobot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://gnu.org/licenses - */ - -#include "CBot/CBotCallMethode.h" - -#include "CBot/CBotUtils.h" -#include "CBot/CBotStack.h" -#include "CBot/CBotCStack.h" - -#include "CBot/CBotVar/CBotVar.h" - -namespace CBot -{ - - -//////////////////////////////////////////////////////////////////////////////// -CBotCallMethode::CBotCallMethode(const std::string& name, - bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user), - CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar)) -{ - m_name = name; - m_rExec = rExec; - m_rComp = rCompile; -} - -//////////////////////////////////////////////////////////////////////////////// -CBotCallMethode::~CBotCallMethode() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -CBotTypResult CBotCallMethode::CompileCall(const std::string& name, CBotVar* pThis, CBotVar** ppVar, - CBotCStack* pStack) -{ - CBotCallMethode* pt = this; - - while ( pt != nullptr ) - { - if ( pt->m_name == name ) - { - CBotVar* pVar = MakeListVars(ppVar, true); - CBotVar* pVar2 = pVar; - CBotTypResult r = pt->m_rComp(pThis, pVar2); - int ret = r.GetType(); - if ( ret > 20 ) - { - if (pVar2) pStack->SetError(static_cast(ret), pVar2->GetToken()); - } - delete pVar; - return r; - } - pt = pt->m_next; - } - return CBotTypResult(-1); -} - -//////////////////////////////////////////////////////////////////////////////// -int CBotCallMethode::DoCall(const std::string& name, CBotVar* pThis, CBotVar** ppVars, CBotVar*& pResult, - CBotStack* pStack, CBotToken* pToken) -{ - CBotCallMethode* pt = this; - - // search by name - - while ( pt != nullptr ) - { - if ( pt->m_name == name ) - { - // lists the parameters depending on the contents of the stack (pStackVar) - - CBotVar* pVar = MakeListVars(ppVars, true); - CBotVar* pVarToDelete = pVar; - - int Exception = 0; // TODO: Change this to CBotError - int res = pt->m_rExec(pThis, pVar, pResult, Exception, pStack->GetUserPtr()); - pStack->SetVar(pResult); - - if (res == false) - { - if (Exception!=0) - { -// pStack->SetError(Exception, pVar->GetToken()); - pStack->SetError(static_cast(Exception), pToken); - } - delete pVarToDelete; - return false; - } - delete pVarToDelete; - return true; - } - pt = pt->m_next; - } - - return -1; -} - -} // namespace CBot diff --git a/src/CBot/CBotCallMethode.h b/src/CBot/CBotCallMethode.h deleted file mode 100644 index 4d0e1678..00000000 --- a/src/CBot/CBotCallMethode.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam - * http://epsitec.ch; http://colobot.info; http://github.com/colobot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://gnu.org/licenses - */ - -#pragma once - -#include "CBot/CBotTypResult.h" -#include "CBot/CBotUtils.h" - -namespace CBot -{ - -class CBotVar; -class CBotCStack; -class CBotStack; -class CBotToken; - -/*! - * \brief The CBotCallMethode class Class managing the methods declared by - * AddFunction on a class. - */ -class CBotCallMethode : public CBotLinkedList -{ -public: - - /*! - * \brief CBotCallMethode - * \param name - * \param rExec - * \param rCompile - */ - CBotCallMethode(const std::string& name, - bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user), - CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar)); - - /*! - * \brief ~CBotCallMethode - */ - ~CBotCallMethode(); - - /*! - * \brief CompileCall Is acceptable by a call procedure name and given - * parameters. - * \param name - * \param pThis - * \param ppVars - * \param pStack - * \return - */ - CBotTypResult CompileCall(const std::string& name, CBotVar* pThis, CBotVar** ppVars, - CBotCStack* pStack); - - /*! - * \brief DoCall - * \param name - * \param pThis - * \param ppVars - * \param pResult - * \param pStack - * \param pFunc - * \return - */ - int DoCall(const std::string& name, CBotVar* pThis, CBotVar** ppVars, CBotVar*& pResult, - CBotStack* pStack, CBotToken* pFunc); - -private: - std::string m_name; - bool (*m_rExec) (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user); - CBotTypResult (*m_rComp) (CBotVar* pThis, CBotVar* &pVar); - friend class CBotClass; -}; - -} // namespace CBot diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index 77998b3c..d93d7f54 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -37,7 +37,6 @@ #include "CBot/CBotDefParam.h" #include "CBot/CBotUtils.h" #include "CBot/CBotFileUtils.h" -#include "CBot/CBotCallMethode.h" #include @@ -55,7 +54,7 @@ CBotClass::CBotClass(const std::string& name, m_parent = parent; m_name = name; m_pVar = nullptr; - m_pCalls = nullptr; + m_externalMethods = new CBotExternalCallList(); m_rUpdate = nullptr; m_IsDef = true; m_bIntrinsic= bIntrinsic; @@ -70,7 +69,7 @@ CBotClass::~CBotClass() m_publicClasses.erase(this); delete m_pVar; - delete m_pCalls; + delete m_externalMethods; } //////////////////////////////////////////////////////////////////////////////// @@ -94,8 +93,7 @@ void CBotClass::Purge() delete m_pVar; m_pVar = nullptr; - delete m_pCalls; - m_pCalls = nullptr; + m_externalMethods->Clear(); for (CBotFunction* f : m_pMethod) delete f; m_pMethod.clear(); m_IsDef = false; @@ -278,29 +276,7 @@ bool CBotClass::AddFunction(const std::string& name, bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user), CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar)) { - // stores pointers to the two functions - CBotCallMethode* p = m_pCalls; - CBotCallMethode* pp = nullptr; - - while ( p != nullptr ) - { - if ( name == p->m_name ) - { - if ( pp == nullptr ) m_pCalls = p->m_next; - else pp->m_next = p->m_next; - delete p; - break; - } - pp = p; - p = p->m_next; - } - - p = new CBotCallMethode(name, rExec, rCompile); - - if (m_pCalls == nullptr) m_pCalls = p; - else m_pCalls->AddNext(p); // added to the list - - return true; + return m_externalMethods->AddFunction(name, std::unique_ptr(new CBotExternalCallClass(rExec, rCompile))); } //////////////////////////////////////////////////////////////////////////////// @@ -311,22 +287,22 @@ bool CBotClass::SetUpdateFunc(void rUpdate(CBotVar* thisVar, void* user)) } //////////////////////////////////////////////////////////////////////////////// -CBotTypResult CBotClass::CompileMethode(const std::string& name, +CBotTypResult CBotClass::CompileMethode(CBotToken* name, CBotVar* pThis, CBotVar** ppParams, CBotCStack* pStack, - long& nIdent) + long &nIdent) { nIdent = 0; // forget the previous one if necessary // find the methods declared by AddFunction - CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack); + CBotTypResult r = m_externalMethods->CompileCall(name, pThis, ppParams, pStack); if ( r.GetType() >= 0) return r; // find the methods declared by user - r = CBotFunction::CompileCall(m_pMethod, name, ppParams, nIdent); + r = CBotFunction::CompileCall(m_pMethod, name->GetString(), ppParams, nIdent); if ( r.Eq(CBotErrUndefCall) && m_parent != nullptr ) return m_parent->CompileMethode(name, pThis, ppParams, pStack, nIdent); return r; @@ -334,37 +310,39 @@ CBotTypResult CBotClass::CompileMethode(const std::string& name, //////////////////////////////////////////////////////////////////////////////// bool CBotClass::ExecuteMethode(long& nIdent, - const std::string& name, CBotVar* pThis, CBotVar** ppParams, - CBotVar*& pResult, + CBotTypResult pResultType, CBotStack*& pStack, CBotToken* pToken) { - int ret = m_pCalls->DoCall(name, pThis, ppParams, pResult, pStack, pToken); - if (ret>=0) return ret; + int ret = m_externalMethods->DoCall(pToken, pThis, ppParams, pStack, pResultType); + if (ret >= 0) return ret; - ret = CBotFunction::DoCall(m_pMethod, nIdent, name, pThis, ppParams, pStack, pToken, this); + ret = CBotFunction::DoCall(m_pMethod, nIdent, pToken->GetString(), pThis, ppParams, pStack, pToken, this); if (ret >= 0) return ret; if (m_parent != nullptr) { - ret = m_parent->ExecuteMethode(nIdent, name, pThis, ppParams, pResult, pStack, pToken); + ret = m_parent->ExecuteMethode(nIdent, pThis, ppParams, pResultType, pStack, pToken); } return ret; } //////////////////////////////////////////////////////////////////////////////// void CBotClass::RestoreMethode(long& nIdent, - const std::string& name, + CBotToken* name, CBotVar* pThis, CBotVar** ppParams, CBotStack*& pStack) { + if (m_externalMethods->RestoreCall(name, pThis, ppParams, pStack)) + return; + CBotClass* pClass = this; while (pClass != nullptr) { - bool ok = CBotFunction::RestoreCall(pClass->m_pMethod, nIdent, name, pThis, ppParams, pStack, pClass); + bool ok = CBotFunction::RestoreCall(pClass->m_pMethod, nIdent, name->GetString(), pThis, ppParams, pStack, pClass); if (ok) return; pClass = pClass->m_parent; } diff --git a/src/CBot/CBotClass.h b/src/CBot/CBotClass.h index 94ab341c..10bb83ca 100644 --- a/src/CBot/CBotClass.h +++ b/src/CBot/CBotClass.h @@ -38,6 +38,7 @@ class CBotStack; class CBotDefParam; class CBotToken; class CBotCStack; +class CBotExternalCallList; /** * \brief A CBot class definition @@ -134,13 +135,8 @@ public: bool intrinsic = false); /*! - * \brief AddFunction This call allows to add as external new method - * used by the objects of this class. See (**) at end of this file for - * more details. - * \param name - * \param rExec - * \param rCompile - * \return + * \brief Add a function that can be called from CBot + * \see CBotProgram::AddFunction */ bool AddFunction(const std::string& name, bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user), @@ -235,11 +231,11 @@ public: * \param nIdent * \return */ - CBotTypResult CompileMethode(const std::string& name, + CBotTypResult CompileMethode(CBotToken* name, CBotVar* pThis, CBotVar** ppParams, CBotCStack* pStack, - long& nIdent); + long &nIdent); /*! * \brief ExecuteMethode Executes a method. @@ -247,18 +243,13 @@ public: * \param name * \param pThis * \param ppParams - * \param pResult + * \param pResultType * \param pStack * \param pToken * \return */ - bool ExecuteMethode(long& nIdent, - const std::string& name, - CBotVar* pThis, - CBotVar** ppParams, - CBotVar*& pResult, - CBotStack*& pStack, - CBotToken* pToken); + bool ExecuteMethode(long &nIdent, CBotVar* pThis, CBotVar** ppParams, CBotTypResult pResultType, + CBotStack*&pStack, CBotToken* pToken); /*! * \brief RestoreMethode Restored the execution stack. @@ -268,11 +259,11 @@ public: * \param ppParams * \param pStack */ - void RestoreMethode(long& nIdent, - const std::string& name, + void RestoreMethode(long &nIdent, + CBotToken* name, CBotVar* pThis, CBotVar** ppParams, - CBotStack*& pStack); + CBotStack*&pStack); /*! * \brief Compile Compiles a class declared by the user. @@ -389,7 +380,7 @@ private: //! Linked list of all class fields CBotVar* m_pVar; //! Linked list of all class external calls - CBotCallMethode* m_pCalls; + CBotExternalCallList* m_externalMethods; //! List of all class methods std::list m_pMethod{}; void (*m_rUpdate)(CBotVar* thisVar, void* user); diff --git a/src/CBot/CBotExternalCall.cpp b/src/CBot/CBotExternalCall.cpp index dcf7222b..be7aa676 100644 --- a/src/CBot/CBotExternalCall.cpp +++ b/src/CBot/CBotExternalCall.cpp @@ -168,4 +168,48 @@ bool CBotExternalCallDefault::Run(CBotVar* thisVar, CBotStack* pStack) return true; } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +CBotExternalCallClass::CBotExternalCallClass(RuntimeFunc rExec, CompileFunc rCompile) +{ + m_rExec = rExec; + m_rComp = rCompile; +} + +CBotExternalCallClass::~CBotExternalCallClass() +{ +} + +CBotTypResult CBotExternalCallClass::Compile(CBotVar* thisVar, CBotVar* args, void* user) +{ + return m_rComp(thisVar, args); +} + +bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack) +{ + if (pStack->IsCallFinished()) return true; + CBotStack* pile = pStack->AddStackExternalCall(this); + CBotVar* args = pile->GetVar(); + + CBotStack* pile2 = pile->AddStack(); + + CBotVar* result = pile2->GetVar(); + + int exception = CBotNoErr; // TODO: Change to CBotError + bool res = m_rExec(thisVar, args, result, exception, pStack->GetUserPtr()); + + if (!res) + { + if (exception != CBotNoErr) + { + pStack->SetError(static_cast(exception)); + } + return false; + } + + if (result != nullptr) pStack->SetCopyVar(result); + + return true; +} + } diff --git a/src/CBot/CBotExternalCall.h b/src/CBot/CBotExternalCall.h index 5bef80ab..5432aad1 100644 --- a/src/CBot/CBotExternalCall.h +++ b/src/CBot/CBotExternalCall.h @@ -105,6 +105,36 @@ private: CompileFunc m_rComp; }; +/** + * \brief Implementation of CBot external call for class methods, using compilation and runtime functions + */ +class CBotExternalCallClass : public CBotExternalCall +{ +public: + typedef bool (*RuntimeFunc)(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user); + typedef CBotTypResult (*CompileFunc)(CBotVar* pThis, CBotVar*& pVar); + + /** + * \brief Constructor + * \param rExec Runtime function + * \param rCompile Compilation function + * \see CBotProgram::AddFunction() + */ + CBotExternalCallClass(RuntimeFunc rExec, CompileFunc rCompile); + + /** + * \brief Destructor + */ + virtual ~CBotExternalCallClass(); + + virtual CBotTypResult Compile(CBotVar* thisVar, CBotVar* args, void* user) override; + virtual bool Run(CBotVar* thisVar, CBotStack* pStack) override; + +private: + RuntimeFunc m_rExec; + CompileFunc m_rComp; +}; + /** * \brief Class for mangaging CBot external calls diff --git a/src/CBot/CBotInstr/CBotDefClass.cpp b/src/CBot/CBotInstr/CBotDefClass.cpp index cd73d9cc..3fe832e5 100644 --- a/src/CBot/CBotInstr/CBotDefClass.cpp +++ b/src/CBot/CBotInstr/CBotDefClass.cpp @@ -131,7 +131,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p { // the constructor is there? // std::string noname; - CBotTypResult r = pClass->CompileMethode(pClass->GetName(), var, ppVars, pStk, inst->m_nMethodeIdent); + CBotTypResult r = pClass->CompileMethode(&token, var, ppVars, pStk, inst->m_nMethodeIdent); delete pStk->TokenStack(); // releases the supplement stack int typ = r.GetType(); @@ -369,11 +369,7 @@ bool CBotDefClass::Execute(CBotStack* &pj) ppVars[i] = nullptr; // creates a variable for the result - CBotVar* pResult = nullptr; // constructor still void - - if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GetName(), - pThis, ppVars, - pResult, pile2, GetToken())) return false; // interrupt + if ( !pClass->ExecuteMethode(m_nMethodeIdent, pThis, ppVars, CBotTypResult(CBotTypVoid), pile2, GetToken())) return false; // interrupt pThis->SetInit(CBotVar::InitType::DEF); pThis->ConstructorSet(); // indicates that the constructor has been called @@ -483,9 +479,7 @@ void CBotDefClass::RestoreState(CBotStack* &pj, bool bMain) ppVars[i] = nullptr; // creates a variable for the result -// CBotVar* pResult = nullptr; // constructor still void - - pClass->RestoreMethode(m_nMethodeIdent, pClass->GetName(), pThis, ppVars, pile2); + pClass->RestoreMethode(m_nMethodeIdent, pt, pThis, ppVars, pile2); return; } } diff --git a/src/CBot/CBotInstr/CBotInstrMethode.cpp b/src/CBot/CBotInstr/CBotInstrMethode.cpp index bf4ec41e..3a41802c 100644 --- a/src/CBot/CBotInstr/CBotInstrMethode.cpp +++ b/src/CBot/CBotInstr/CBotInstrMethode.cpp @@ -67,8 +67,7 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* inst->m_thisIdent = var->GetUniqNum(); CBotClass* pClass = var->GetClass(); // pointer to the class inst->m_className = pClass->GetName(); // name of the class - CBotTypResult r = pClass->CompileMethode(inst->m_methodName, var, ppVars, - pStack, inst->m_MethodeIdent); + CBotTypResult r = pClass->CompileMethode(pp, var, ppVars, pStack, inst->m_MethodeIdent); delete pStack->TokenStack(); // release parameters on the stack inst->m_typRes = r; @@ -176,18 +175,7 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre else pClass = pThis->GetClass(); - CBotVar* pResult = nullptr; - if (m_typRes.GetType() > 0) pResult = CBotVar::Create("", m_typRes); - if (m_typRes.Eq(CBotTypClass)) - { - pResult->SetClass(m_typRes.GetClass()); - } - CBotVar* pRes = pResult; - - if ( !pClass->ExecuteMethode(m_MethodeIdent, m_methodName, - pThis, ppVars, - pResult, pile2, GetToken())) return false; - if (pRes != pResult) delete pRes; + if ( !pClass->ExecuteMethode(m_MethodeIdent, pThis, ppVars, m_typRes, pile2, GetToken())) return false; if (m_exprRetVar != nullptr) // .func().member { @@ -264,8 +252,7 @@ void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain) // CBotVar* pRes = pResult; - pClass->RestoreMethode(m_MethodeIdent, m_methodName, - pThis, ppVars, pile2); + pClass->RestoreMethode(m_MethodeIdent, &m_token, pThis, ppVars, pile2); } //////////////////////////////////////////////////////////////////////////////// @@ -316,24 +303,12 @@ bool CBotInstrMethode::Execute(CBotStack* &pj) else pClass = pThis->GetClass(); - CBotVar* pResult = nullptr; - if (m_typRes.GetType()>0) pResult = CBotVar::Create("", m_typRes); - if (m_typRes.Eq(CBotTypClass)) - { - pResult->SetClass(m_typRes.GetClass()); - } - CBotVar* pRes = pResult; - - if ( !pClass->ExecuteMethode(m_MethodeIdent, m_methodName, - pThis, ppVars, - pResult, pile2, GetToken())) return false; // interupted + if ( !pClass->ExecuteMethode(m_MethodeIdent, pThis, ppVars, m_typRes, pile2, GetToken())) return false; // interupted // set the new value of this in place of the old variable CBotVar* old = pile1->FindVar(m_token, false); old->Copy(pThis, false); - if (pRes != pResult) delete pRes; - return pj->Return(pile2); // release the entire stack } diff --git a/src/CBot/CBotInstr/CBotNew.cpp b/src/CBot/CBotInstr/CBotNew.cpp index e7d973c9..ddd50c69 100644 --- a/src/CBot/CBotInstr/CBotNew.cpp +++ b/src/CBot/CBotInstr/CBotNew.cpp @@ -83,7 +83,7 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack) if (!pStk->IsOk()) goto error; // constructor exist? - CBotTypResult r = pClass->CompileMethode(pClass->GetName(), pVar, ppVars, pStk, inst->m_nMethodeIdent); + CBotTypResult r = pClass->CompileMethode(&inst->m_vartoken, pVar, ppVars, pStk, inst->m_nMethodeIdent); delete pStk->TokenStack(); // release extra stack int typ = r.GetType(); @@ -197,12 +197,7 @@ bool CBotNew::Execute(CBotStack* &pj) } ppVars[i] = nullptr; - // create a variable for the result - CBotVar* pResult = nullptr; // constructos still void - - if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GetName(), - pThis, ppVars, - pResult, pile2, GetToken())) return false; // interrupt + if ( !pClass->ExecuteMethode(m_nMethodeIdent, pThis, ppVars, CBotTypResult(CBotTypVoid), pile2, GetToken())) return false; // interrupt pThis->ConstructorSet(); // indicates that the constructor has been called } @@ -284,8 +279,7 @@ void CBotNew::RestoreState(CBotStack* &pj, bool bMain) } ppVars[i] = nullptr; - pClass->RestoreMethode(m_nMethodeIdent, m_vartoken.GetString(), pThis, - ppVars, pile2) ; // interrupt here! + pClass->RestoreMethode(m_nMethodeIdent, &m_vartoken, pThis, ppVars, pile2); // interrupt here! } } diff --git a/src/CBot/CBotVar/CBotVarClass.cpp b/src/CBot/CBotVar/CBotVarClass.cpp index 4da99b2d..de3d274f 100644 --- a/src/CBot/CBotVar/CBotVarClass.cpp +++ b/src/CBot/CBotVar/CBotVarClass.cpp @@ -394,12 +394,13 @@ void CBotVarClass::DecrementUse() CBotVar* pThis = CBotVar::Create("this", CBotTypNullPointer); pThis->SetPointer(this); - CBotVar* pResult = nullptr; std::string nom = std::string("~") + m_pClass->GetName(); long ident = 0; - while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, nom, pThis, ppVars, pResult, pile, nullptr)) ; // waits for the end + CBotToken token(nom); // TODO + + while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, pThis, ppVars, CBotTypResult(CBotTypVoid), pile, &token)) ; // waits for the end pile->ResetError(err, start,end); diff --git a/src/CBot/CMakeLists.txt b/src/CBot/CMakeLists.txt index 6ac4d130..dcb39e1a 100644 --- a/src/CBot/CMakeLists.txt +++ b/src/CBot/CMakeLists.txt @@ -2,8 +2,6 @@ set(SOURCES CBot.h CBotCStack.cpp CBotCStack.h - CBotCallMethode.cpp - CBotCallMethode.h CBotClass.cpp CBotClass.h CBotDebug.cpp From b49fbf0cd6ada33a3e0a5850bd8b7b82efd76502 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 22:58:39 +0100 Subject: [PATCH 19/93] Another this==nullptr fix (#828) --- src/CBot/CBotDefParam.cpp | 1 + src/CBot/CBotInstr/CBotFunction.cpp | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp index d73c02e0..ff4acf1f 100644 --- a/src/CBot/CBotDefParam.cpp +++ b/src/CBot/CBotDefParam.cpp @@ -104,6 +104,7 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) { int i = 0; + assert(this != nullptr); CBotDefParam* p = this; while ( p != nullptr ) diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index c8db69a9..f86153f5 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -334,7 +334,10 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) if ( pile->GetState() == 0 ) { - if ( !m_param->Execute(ppVars, pile) ) return false; // define parameters + if (m_param != nullptr) + { + if ( !m_param->Execute(ppVars, pile) ) return false; // define parameters + } pile->IncState(); } @@ -647,7 +650,10 @@ int CBotFunction::DoCall(CBotProgram* program, const std::list& l } // initializes the variables as parameters - pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted + if (pt->m_param != nullptr) + { + pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted + } pStk1->IncState(); } @@ -766,7 +772,10 @@ int CBotFunction::DoCall(const std::list& localFunctionList, long pStk->AddVar(psuper); } // initializes the variables as parameters - pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted + if (pt->m_param != nullptr) + { + pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted + } pStk->IncState(); } From 7190c8518e1814685bce91f336d2bda5f1b6514a Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 11 Nov 2016 23:07:22 +0100 Subject: [PATCH 20/93] Fix destructors not being called when program execution ended, closes #859 --- src/CBot/CBotProgram.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index a303df6d..65d373a2 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -200,16 +200,16 @@ bool CBotProgram::Run(void* pUser, int timer) } // completed on a mistake? - if (!ok && !m_stack->IsOk()) + if (ok || !m_stack->IsOk()) { m_error = m_stack->GetError(m_errorStart, m_errorEnd); m_stack->Delete(); m_stack = nullptr; CBotClass::FreeLock(this); + m_entryPoint = nullptr; return true; // execution is finished! } - if ( ok ) m_entryPoint = nullptr; // more function in execution return ok; } From be9dba478832e89c3a1fed1617993314c81e6081 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sat, 26 Nov 2016 13:01:43 +0100 Subject: [PATCH 21/93] Jenkinsfile: Automatically discard old artifacts --- Jenkinsfile | 2 ++ data | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 926f4e2e..ccd147b7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,5 @@ +properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '30', artifactNumToKeepStr: '20']]]) + node('master') { stage 'Pull changes' checkout scm diff --git a/data b/data index f96cf394..3b99a621 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit f96cf394a327210ac9e40d68d68963f25633f758 +Subproject commit 3b99a62185c4aba3c6c7507dfbbbcf5bcbce3ba2 From 88c6818cfdd64cca6c2633942ba02a0c63907413 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sat, 26 Nov 2016 13:48:12 +0100 Subject: [PATCH 22/93] Fix code style issues --- src/CBot/CBotClass.cpp | 3 ++- src/CBot/CBotInstr/CBotInstrUtils.h | 2 +- src/CBot/CBotProgram.cpp | 8 ++----- src/CBot/stdlib/FileFunctions.cpp | 34 ++++++++++++--------------- src/app/app.cpp | 6 +++-- src/common/system/system.cpp | 4 ++-- src/graphics/core/type.cpp | 34 +++++++++++++-------------- src/graphics/core/type.h | 34 +++++++++++++-------------- src/graphics/core/vertex.h | 24 +++++++++---------- src/graphics/engine/text.cpp | 30 ++++++++++++------------ src/graphics/opengl/gl14device.h | 10 ++++---- src/graphics/opengl/gl33device.cpp | 2 +- src/math/half.cpp | 34 +++++++++++++-------------- src/math/half.h | 36 +++++++++++++++-------------- 14 files changed, 129 insertions(+), 132 deletions(-) diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index d93d7f54..579dda03 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -610,7 +610,8 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) CBotDefParam* params = CBotDefParam::Compile(p, pStk ); delete pStk; p = ppp; - std::list::iterator pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, ¶ms](CBotFunction* x) { + std::list::iterator pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, ¶ms](CBotFunction* x) + { return x->GetName() == pp && x->CheckParam( params ); }); assert(pfIter != m_pMethod.end()); diff --git a/src/CBot/CBotInstr/CBotInstrUtils.h b/src/CBot/CBotInstr/CBotInstrUtils.h index b5302883..0177e09c 100644 --- a/src/CBot/CBotInstr/CBotInstrUtils.h +++ b/src/CBot/CBotInstr/CBotInstrUtils.h @@ -45,7 +45,7 @@ CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars); * For assignment or compound assignment operations (it's reversed): * see CBotReturn::Compile & CBotExpression::Compile - * TypeCompatible( valueType, varType, opType ) + * TypeCompatible( valueType, varType, opType ) * \param type1 * \param type2 * \param op diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index 65d373a2..fdb36eb8 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -148,9 +148,7 @@ bool CBotProgram::Start(const std::string& name) { Stop(); - auto it = std::find_if(m_functions.begin(), m_functions.end(), [&name](CBotFunction* x) { - return x->GetName() == name; - }); + auto it = std::find_if(m_functions.begin(), m_functions.end(), [&name](CBotFunction* x) { return x->GetName() == name; }); if (it == m_functions.end()) { m_error = CBotErrNoRun; @@ -166,9 +164,7 @@ bool CBotProgram::Start(const std::string& name) bool CBotProgram::GetPosition(const std::string& name, int& start, int& stop, CBotGet modestart, CBotGet modestop) { - auto it = std::find_if(m_functions.begin(), m_functions.end(), [&name](CBotFunction* x) { - return x->GetName() == name; - }); + auto it = std::find_if(m_functions.begin(), m_functions.end(), [&name](CBotFunction* x) { return x->GetName() == name; }); if (it == m_functions.end()) return false; (*it)->GetPosition(start, stop, modestart, modestop); diff --git a/src/CBot/stdlib/FileFunctions.cpp b/src/CBot/stdlib/FileFunctions.cpp index 4f2f6134..57d778ad 100644 --- a/src/CBot/stdlib/FileFunctions.cpp +++ b/src/CBot/stdlib/FileFunctions.cpp @@ -38,7 +38,7 @@ int g_nextFileId = 1; bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception) { - std::string mode; + CBotFileAccessHandler::OpenMode openMode = CBotFileAccessHandler::OpenMode::Read; // must be a character string if ( pVar->GetType() != CBotTypString ) { Exception = CBotErrBadString; return false; } @@ -50,8 +50,11 @@ bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exc if ( pVar != nullptr ) { // recover mode - mode = pVar->GetValString(); - if ( mode != "r" && mode != "w" && mode != "a" ) { Exception = CBotErrBadParam; return false; } + std::string mode = pVar->GetValString(); + if ( mode == "r" ) openMode = CBotFileAccessHandler::OpenMode::Read; + else if ( mode == "w" ) openMode = CBotFileAccessHandler::OpenMode::Write; + else if ( mode == "a" ) openMode = CBotFileAccessHandler::OpenMode::Append; + else { Exception = CBotErrBadParam; return false; } // no third parameter if ( pVar->GetNext() != nullptr ) { Exception = CBotErrOverParam; return false; } @@ -66,27 +69,20 @@ bool FileClassOpenFile(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exc // which must not be initialized if ( pVar->IsDefined()) { Exception = CBotErrFileOpen; return false; } - if ( !mode.empty() ) - { - // opens the requested file - assert(g_fileHandler != nullptr); + // opens the requested file + assert(g_fileHandler != nullptr); - CBotFileAccessHandler::OpenMode openMode; - if ( mode == "r" ) openMode = CBotFileAccessHandler::OpenMode::Read; - else if ( mode == "w" ) openMode = CBotFileAccessHandler::OpenMode::Write; - else if ( mode == "a" ) openMode = CBotFileAccessHandler::OpenMode::Append; + std::unique_ptr file = g_fileHandler->OpenFile(filename, openMode); - std::unique_ptr file = g_fileHandler->OpenFile(filename, openMode); + if (!file->Opened()) { Exception = CBotErrFileOpen; return false; } - if (!file->Opened()) { Exception = CBotErrFileOpen; return false; } + int fileHandle = g_nextFileId++; + g_files[fileHandle] = std::move(file); - int fileHandle = g_nextFileId++; - g_files[fileHandle] = std::move(file); + // save the file handle + pVar = pThis->GetItem("handle"); + pVar->SetValInt(fileHandle); - // save the file handle - pVar = pThis->GetItem("handle"); - pVar->SetValInt(fileHandle); - } return true; } diff --git a/src/app/app.cpp b/src/app/app.cpp index 4ab6440e..806a17c7 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -674,7 +674,8 @@ bool CApplication::Create() // Create the robot application. m_controller = MakeUnique(); - CThread musicLoadThread([this]() { + CThread musicLoadThread([this]() + { GetLogger()->Debug("Cache sounds...\n"); SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp(); m_systemUtils->GetCurrentTimeStamp(musicLoadStart); @@ -685,7 +686,8 @@ bool CApplication::Create() m_systemUtils->GetCurrentTimeStamp(musicLoadEnd); float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC); GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime); - }, "Sound loading thread"); + }, + "Sound loading thread"); musicLoadThread.Start(); if (m_runSceneCategory == LevelCategory::Max) diff --git a/src/common/system/system.cpp b/src/common/system/system.cpp index ce594ea7..ff4ad7c5 100644 --- a/src/common/system/system.cpp +++ b/src/common/system/system.cpp @@ -22,6 +22,8 @@ #include "common/config.h" +#include "common/make_unique.h" + #if defined(PLATFORM_WINDOWS) #include "common/system/system_windows.h" #elif defined(PLATFORM_LINUX) @@ -32,8 +34,6 @@ #include "common/system/system_other.h" #endif -#include "common/make_unique.h" - #include #include #include diff --git a/src/graphics/core/type.cpp b/src/graphics/core/type.cpp index ddcd343d..38dc9f52 100644 --- a/src/graphics/core/type.cpp +++ b/src/graphics/core/type.cpp @@ -1,21 +1,21 @@ /* -* 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 -*/ + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ /** * \file graphics/core/type.cpp diff --git a/src/graphics/core/type.h b/src/graphics/core/type.h index 4a49f582..2d493459 100644 --- a/src/graphics/core/type.h +++ b/src/graphics/core/type.h @@ -1,21 +1,21 @@ /* -* 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 -*/ + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ /** * \file graphics/core/type.h diff --git a/src/graphics/core/vertex.h b/src/graphics/core/vertex.h index 11f1ea48..254c8d3d 100644 --- a/src/graphics/core/vertex.h +++ b/src/graphics/core/vertex.h @@ -49,20 +49,20 @@ namespace Gfx struct VertexAttribute { //! true enables vertex attribute - bool enabled; + bool enabled = false; //! true means normalized value (integer types only) - bool normalized; + bool normalized = false; //! Number of elements in the vertex attribute. //! Valid values are 1, 2, 3, and 4. Depends on specific attribute. - unsigned char size; + unsigned char size = 0; //! Type of values in vertex attribute - Type type; + Type type = Type::UBYTE; //! Offset to the vertex attribute - int offset; + int offset = 0; //! Stride of vertex attribute - int stride; + int stride = 0; //! Default values used when attribute is disabled - float values[4]; + float values[4] = {0.0f, 0.0f, 0.0f, 0.0f}; }; /** @@ -81,15 +81,15 @@ struct VertexAttribute struct VertexFormat { //! Vertex coordinate - VertexAttribute vertex; + VertexAttribute vertex{}; //! Color - VertexAttribute color; + VertexAttribute color{}; //! Normal - VertexAttribute normal; + VertexAttribute normal{}; //! Texture coordinate 1 - VertexAttribute tex1; + VertexAttribute tex1{}; //! Texture coordinate 2 - VertexAttribute tex2; + VertexAttribute tex2{}; }; /** diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index aece13e9..53bd7f6a 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -643,37 +643,37 @@ UTF8Char CText::TranslateSpecialChar(int specialChar) case CHAR_NEWLINE: // Unicode: U+21B2 - ch.c1 = 0xE2; - ch.c2 = 0x86; - ch.c3 = 0xB2; + ch.c1 = static_cast(0xE2); + ch.c2 = static_cast(0x86); + ch.c3 = static_cast(0xB2); break; case CHAR_DOT: // Unicode: U+23C5 - ch.c1 = 0xE2; - ch.c2 = 0x8F; - ch.c3 = 0x85; + ch.c1 = static_cast(0xE2); + ch.c2 = static_cast(0x8F); + ch.c3 = static_cast(0x85); break; case CHAR_SQUARE: // Unicode: U+25FD - ch.c1 = 0xE2; - ch.c2 = 0x97; - ch.c3 = 0xBD; + ch.c1 = static_cast(0xE2); + ch.c2 = static_cast(0x97); + ch.c3 = static_cast(0xBD); break; case CHAR_SKIP_RIGHT: // Unicode: U+25B6 - ch.c1 = 0xE2; - ch.c2 = 0x96; - ch.c3 = 0xB6; + ch.c1 = static_cast(0xE2); + ch.c2 = static_cast(0x96); + ch.c3 = static_cast(0xB6); break; case CHAR_SKIP_LEFT: // Unicode: U+25C0 - ch.c1 = 0xE2; - ch.c2 = 0x97; - ch.c3 = 0x80; + ch.c1 = static_cast(0xE2); + ch.c2 = static_cast(0x97); + ch.c3 = static_cast(0x80); break; default: diff --git a/src/graphics/opengl/gl14device.h b/src/graphics/opengl/gl14device.h index e0dba147..4106b841 100644 --- a/src/graphics/opengl/gl14device.h +++ b/src/graphics/opengl/gl14device.h @@ -298,11 +298,11 @@ private: //! Pointers to OpenGL functions - PFNGLGENBUFFERSPROC m_glGenBuffers; - PFNGLDELETEBUFFERSPROC m_glDeleteBuffers; - PFNGLBINDBUFFERPROC m_glBindBuffer; - PFNGLBUFFERDATAPROC m_glBufferData; - PFNGLBUFFERSUBDATAPROC m_glBufferSubData; + PFNGLGENBUFFERSPROC m_glGenBuffers = nullptr; + PFNGLDELETEBUFFERSPROC m_glDeleteBuffers = nullptr; + PFNGLBINDBUFFERPROC m_glBindBuffer = nullptr; + PFNGLBUFFERDATAPROC m_glBufferData = nullptr; + PFNGLBUFFERSUBDATAPROC m_glBufferSubData = nullptr; }; diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp index 3d5ae713..3ea93e45 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl/gl33device.cpp @@ -2065,7 +2065,7 @@ unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, const void* da if (ptr != nullptr) { memcpy(ptr, data, size); - + glUnmapBuffer(GL_ARRAY_BUFFER); } // mapping failed, we must upload data with glBufferSubData diff --git a/src/math/half.cpp b/src/math/half.cpp index 4508218f..d1339a43 100644 --- a/src/math/half.cpp +++ b/src/math/half.cpp @@ -1,21 +1,21 @@ /* -* 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 -*/ + * 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 "math/half.h" diff --git a/src/math/half.h b/src/math/half.h index a5e44f46..a9d80d91 100644 --- a/src/math/half.h +++ b/src/math/half.h @@ -1,21 +1,21 @@ /* -* 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 -*/ + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ /** * \file math/half.h @@ -36,6 +36,7 @@ uint16_t FloatToHalf(float value); //! Converts half-float binary representation to float float HaltToFloat(uint16_t value); +//@colobot-lint-exclude ClassNamingRule /** * \struct half * \brief half-precision floating point type @@ -99,5 +100,6 @@ struct half return HaltToFloat(bits); } }; +//@end-colobot-lint-exclude } // namespace Math From eb2a1857dc9db7ded613027045c4e78781ec1bca Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sun, 4 Dec 2016 16:07:41 +0100 Subject: [PATCH 23/93] Fix goto() with multiple objects at the exact same position (#732) --- src/object/task/taskgoto.cpp | 44 +++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/object/task/taskgoto.cpp b/src/object/task/taskgoto.cpp index de37d1a1..0da2de49 100644 --- a/src/object/task/taskgoto.cpp +++ b/src/object/task/taskgoto.cpp @@ -1072,7 +1072,49 @@ Error CTaskGoto::IsEnded() CObject* CTaskGoto::SearchTarget(Math::Vector pos, float margin) { - return CObjectManager::GetInstancePointer()->FindNearest(nullptr, pos, OBJECT_NULL, margin/g_unit); + //return CObjectManager::GetInstancePointer()->FindNearest(nullptr, pos, OBJECT_NULL, margin/g_unit); + + /* + * TODO: FindNearest() can't be used here. Reverted to code from before 4fef3af9ef1fbe61a0c4c3f5c176f56257428efb + * + * The reason is that in the case of multiple objects being placed at the same position, + * this function needs to return the last one in order of creation. FindNearest() does the opposite. + * + * Whoever designed goto() so that it has to guess which object the user wants based only on position - thanks + * for making it so confusing :/ + * + * This works well enough assuming that portable objects from the level file are always created after the objects + * they are placed on, for example BlackBox is created after GoalArea, TitaniumOre is created after Converter etc. + * This is probably required anyway to prevent them from sinking into the ground. + * + * User-created objects don't make a difference because there is no way you can place them precisely enough + * for floats to compare with ==. + * + * See issue #732 + */ + + CObject *pBest; + Math::Vector oPos; + float dist, min; + + pBest = 0; + min = 1000000.0f; + for ( CObject* pObj : CObjectManager::GetInstancePointer()->GetAllObjects() ) + { + if ( !pObj->GetActive() ) continue; + if ( IsObjectBeingTransported(pObj) ) continue; // object transtorted? + + oPos = pObj->GetPosition(); + dist = Math::DistanceProjected(pos, oPos); + + if ( dist <= margin && dist <= min ) + { + min = dist; + pBest = pObj; + } + } + + return pBest; } // Adjusts the target as a function of the object. From 5dc38f15262b96a7b14290cd93e341b82a55d83f Mon Sep 17 00:00:00 2001 From: tomangelo2 Date: Mon, 5 Dec 2016 14:16:11 +0100 Subject: [PATCH 24/93] Objects outside BuildType list cannot be build anymore Fix issue #863 --- src/level/robotmain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index cfb98b4e..b1be1192 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -5638,7 +5638,7 @@ bool CRobotMain::IsBuildingEnabled(ObjectType type) if(type == OBJECT_PARA) return IsBuildingEnabled(BUILD_PARA); if(type == OBJECT_DESTROYER) return IsBuildingEnabled(BUILD_DESTROYER); - return true; + return false; } bool CRobotMain::IsResearchEnabled(ResearchType type) From 8ce8b2fff3dce8f9407d7d1966d878c8c321c7d1 Mon Sep 17 00:00:00 2001 From: Martin Quinson Date: Fri, 2 Dec 2016 15:34:53 +0100 Subject: [PATCH 25/93] update french translation --- po/fr.po | 54 +++++++++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/po/fr.po b/po/fr.po index 9fb7a344..7eb4e407 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1,11 +1,12 @@ # Didier Raboud , 2012, 2015, 2016. +# Martin Quinson , 2016 msgid "" msgstr "" "Project-Id-Version: Colobot 0.1.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: DATE\n" -"PO-Revision-Date: 2016-03-25 15:01+0100\n" -"Last-Translator: Didier Raboud \n" +"PO-Revision-Date: 2016-12-02 15:31+0100\n" +"Last-Translator: Martin Quinson \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -79,10 +80,10 @@ msgid "Already carrying something" msgstr "Porte déjà quelque chose" msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)" -msgstr "" +msgstr "Mode caméra alternatif\\Déplacements latéraux au lieu des rotations (pour la caméra libre)" msgid "Ambiguous call to overloaded function" -msgstr "" +msgstr "Appel ambigu à une fonction surchargée" msgid "Analysis already performed" msgstr "Analyse déjà effectuée" @@ -294,21 +295,17 @@ msgstr "Défilement dans les bords\\Défilement lorsque la souris touche les bor msgid "Camera closer\\Moves the camera forward" msgstr "Caméra plus proche\\Avance la caméra" -#, fuzzy msgid "Camera down\\Turns the camera down" -msgstr "Caméra plus proche\\Avance la caméra" +msgstr "Baisser caméra\\Baisse la caméra" -#, fuzzy msgid "Camera left\\Turns the camera left" -msgstr "Caméra plus proche\\Avance la caméra" +msgstr "Caméra à gauche\\Tourne la caméra vers la gauche" -#, fuzzy msgid "Camera right\\Turns the camera right" -msgstr "Tourner à droite\\Moteur à droite" +msgstr "Caméra à droite\\Tourne la caméra vers la droite" -#, fuzzy msgid "Camera up\\Turns the camera up" -msgstr "Caméra (\\key camera;)" +msgstr "Lever caméra\\Monte la caméra" msgid "Can not produce not researched object" msgstr "Impossible de créer un objet n'ayant pas été recherché" @@ -519,7 +516,7 @@ msgid "Explosive" msgstr "Explosif" msgid "Expression expected after =" -msgstr "" +msgstr "Expression attendue après =" msgid "Extend shield (\\key action;)" msgstr "Déploie le bouclier (\\key action;)" @@ -730,7 +727,7 @@ msgid "Internal error - tell the developers" msgstr "Erreur interne - contacter les développeurs" msgid "Invert\\Invert values on this axis" -msgstr "" +msgstr "Inversion\\Inverse les valeurs sur cet axe" msgid "Jet temperature" msgstr "Température du réacteur" @@ -1024,10 +1021,10 @@ msgid "Paste (Ctrl+V)" msgstr "Coller (Ctrl+V)" msgid "Pause blur\\Blur the background on the pause screen" -msgstr "" +msgstr "Flouter les pauses\\Floute le fond de l'écran de pause" msgid "Pause in background\\Pause the game when the window is unfocused" -msgstr "" +msgstr "Pause en arrière-plan\\Met le jeu en pause quand la fenêtre n'a plus le focus" msgid "Pause/continue" msgstr "Pause/continuer" @@ -1219,16 +1216,16 @@ msgid "Resolution:" msgstr "Résolutions :" msgid "Resources" -msgstr "" +msgstr "Ressources" msgid "Restart\\Restart the mission from the beginning" msgstr "Recommencer\\Recommencer la mission au début" msgid "Restoring CBot execution state" -msgstr "" +msgstr "Restaurer l'état d'exécution CBOT" msgid "Restoring saved objects" -msgstr "" +msgstr "Restaurer des objets sauvés" msgid "Return to start" msgstr "Remet au départ" @@ -1677,24 +1674,24 @@ 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 +#, c-format msgid "You cannot use \"%s\" in this exercise (used: %d)" -msgstr "Interdit dans cet exercice" +msgstr "Vous ne pouvez pas utiliser «%s» dans cet exercice (utilisé : %d)" msgid "You found a usable object" msgstr "Vous avez trouvé un objet utilisable" -#, fuzzy, c-format +#, c-format msgid "You have to use \"%1$s\" at least once in this exercise (used: %2$d)" msgid_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" +msgstr[0] "Vous devez utiliser «%1$s» au moins une fois dans cet exercice (utilisé %2$d fois)" +msgstr[1] "Vous devez utiliser «%1$s» au moins %3$d fois dans cet exercice (utilisé %2$d fois)" -#, fuzzy, c-format +#, c-format msgid "You have to use \"%1$s\" at most once in this exercise (used: %2$d)" msgid_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" +msgstr[0] "Vous devez utiliser «%1$s» au plus une fois dans cet exercice (utilisé %2$d fois)" +msgstr[1] "Vous devez utiliser «%1$s» au plus %3$d fois dans cet exercice (utilisé %2$d fois)" msgid "You must get on the spaceship to take off" msgstr "Vous devez embarquer pour pouvoir décoller" @@ -1864,9 +1861,8 @@ msgstr "epsitec.com" #~ msgid "Developed by :" #~ msgstr "Développé par :" -#, fuzzy #~ msgid "Do you want to quit Colobot: Gold Edition?" -#~ msgstr "Voulez-vous quitter COLOBOT ?" +#~ msgstr "Voulez-vous quitter Colobot: Édition Gold ?" #~ msgid "Exit film\\Film at the exit of exercises" #~ msgstr "Retour animé\\Retour animé dans les exercices" From f0550383d176dd9c499e7a5fef1d00ba62c3fc51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D1=83=D1=80=D0=BE=D0=B2=20=D0=A4=D1=91=D0=B4?= =?UTF-8?q?=D0=BE=D1=80?= Date: Thu, 3 Nov 2016 18:43:40 +0300 Subject: [PATCH 26/93] Add missing russian translations (#852) --- po/ru.po | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/po/ru.po b/po/ru.po index a6c1a61f..553a4c7e 100644 --- a/po/ru.po +++ b/po/ru.po @@ -85,7 +85,7 @@ msgid "Alternative camera mode\\Move sideways instead of rotating (in free camer msgstr "Альтернативный режим камеры\\Движение в стороны вместо поворачивания (в режиме свободной камеры)" msgid "Ambiguous call to overloaded function" -msgstr "" +msgstr "Странный вызов перегруженной функции" msgid "Analysis already performed" msgstr "Анализ уже выполнен" @@ -370,10 +370,10 @@ msgid "Closing bracket missing" msgstr "Закрывающая скобка отсутствует" msgid "Code battles" -msgstr "" +msgstr "Битвы роботов" msgid "Code battles\\Program your robot to be the best of them all!" -msgstr "Code battles\\Запрограммируйте собственного робота чтобы быть лучшим среди них!" +msgstr "Битвы роботов\\Запрограммируйте собственного робота чтобы быть лучшим среди них!" msgid "Colobot rules!" msgstr "Правила игры!" @@ -817,7 +817,7 @@ msgid "Lunar Roving Vehicle" msgstr "Луноход" msgid "MSAA\\Multisample anti-aliasing" -msgstr "" +msgstr "MSAA\\Улучшенная фильтрация" msgid "Maximize" msgstr "Развернуть" @@ -826,7 +826,7 @@ msgid "Minimize" msgstr "Свернуть" msgid "Mipmap level\\Mipmap level" -msgstr "" +msgstr "Уровень уменьшающей фильтрации\\Уровень уменьшающей фильтрации" msgid "Mission name" msgstr "Название миссии" @@ -1230,13 +1230,13 @@ msgid "Resolution:" msgstr "Разрешение:" msgid "Resources" -msgstr "" +msgstr "Ресурсы" msgid "Restart\\Restart the mission from the beginning" msgstr "Заново\\Начать данную миссию с начала" msgid "Restoring CBot execution state" -msgstr "" +msgstr "Восстановление состояния CBot" msgid "Restoring saved objects" msgstr "Восстановить сохранённые объекты" From e325efa447ecff282ad59515f58b119325c0be07 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 27 Dec 2016 13:23:41 +0100 Subject: [PATCH 27/93] Fix crash after precompiling a CBot class with errors (#881) --- src/CBot/CBotClass.h | 13 +++++++++---- src/CBot/CBotInstr/CBotFunction.h | 15 ++++++++++----- src/CBot/CBotProgram.cpp | 8 ++++++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/CBot/CBotClass.h b/src/CBot/CBotClass.h index 10bb83ca..68b61cc6 100644 --- a/src/CBot/CBotClass.h +++ b/src/CBot/CBotClass.h @@ -275,10 +275,15 @@ public: CBotCStack* pStack); /*! - * \brief Compile1 - * \param p - * \param pStack - * \return + * \brief Pre-compile a new class + * \param p[in, out] Pointer to first token of the class, will be updated to point to first token after the class definition + * \param pStack Compile stack + * + * This function is used to find the beginning and end of class definition. + * + * If any errors in the code are detected, this function will set the error on compile stack and return nullptr. + * + * \return Precompiled class, or nullptr in case of error */ static CBotClass* Compile1(CBotToken* &p, CBotCStack* pStack); diff --git a/src/CBot/CBotInstr/CBotFunction.h b/src/CBot/CBotInstr/CBotFunction.h index 66637b51..bab5e2bb 100644 --- a/src/CBot/CBotInstr/CBotFunction.h +++ b/src/CBot/CBotInstr/CBotFunction.h @@ -60,11 +60,16 @@ public: bool bLocal = true); /*! - * \brief Compile1 Pre-compile a new function. - * \param p - * \param pStack - * \param pClass - * \return + * \brief Pre-compile a new function + * \param p[in, out] Pointer to first token of the function, will be updated to point to first token after the function definition + * \param pStack Compile stack + * \param pClass If this is a class method, pointer to class this function is part of, otherwise nullptr + * + * This function is used to find the beginning and end of function definition. + * + * If any errors in the code are detected, this function will set the error on compile stack and return nullptr. + * + * \return Precompiled function, or nullptr in case of error */ static CBotFunction* Compile1(CBotToken* &p, CBotCStack* pStack, diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index fdb36eb8..dce62198 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -93,11 +93,15 @@ bool CBotProgram::Compile(const std::string& program, std::vector& if ( p->GetType() == ID_CLASS || ( p->GetType() == ID_PUBLIC && p->GetNext()->GetType() == ID_CLASS )) { - m_classes.push_back(CBotClass::Compile1(p, pStack.get())); + CBotClass* newclass = CBotClass::Compile1(p, pStack.get()); + if (newclass != nullptr) + m_classes.push_back(newclass); } else { - m_functions.push_back(CBotFunction::Compile1(p, pStack.get(), nullptr)); + CBotFunction* newfunc = CBotFunction::Compile1(p, pStack.get(), nullptr); + if (newfunc != nullptr) + m_functions.push_back(newfunc); } } From b6cda6cd4c0393e758df44707966c8d0f75c0633 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 27 Dec 2016 13:36:46 +0100 Subject: [PATCH 28/93] Add error when object is busy (#871) --- po/colobot.pot | 3 +++ po/de.po | 3 +++ po/fr.po | 3 +++ po/pl.po | 3 +++ po/ru.po | 3 +++ src/common/error.h | 1 + src/common/restext.cpp | 1 + src/object/auto/autodestroyer.cpp | 2 +- src/object/auto/autofactory.cpp | 2 +- src/object/auto/autolabo.cpp | 2 +- src/object/auto/autoresearch.cpp | 2 +- 11 files changed, 21 insertions(+), 4 deletions(-) diff --git a/po/colobot.pot b/po/colobot.pot index 1f183eea..a1446763 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -1346,6 +1346,9 @@ msgstr "" msgid "Unknown command" msgstr "" +msgid "This object is currently busy" +msgstr "" + msgid "Impossible when flying" msgstr "" diff --git a/po/de.po b/po/de.po index 05a31006..653fa662 100644 --- a/po/de.po +++ b/po/de.po @@ -1507,6 +1507,9 @@ msgstr "Dieses Label existiert nicht" msgid "This menu is for userlevels from mods, but you didn't install any" msgstr "" +msgid "This object is currently busy" +msgstr "" + msgid "This object is not a member of a class" msgstr "Das Objekt ist nicht eine Instanz einer Klasse" diff --git a/po/fr.po b/po/fr.po index 7eb4e407..6f432671 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1479,6 +1479,9 @@ 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é." +msgid "This object is currently busy" +msgstr "" + msgid "This object is not a member of a class" msgstr "L'objet n'est pas une instance d'une classe" diff --git a/po/pl.po b/po/pl.po index d9cde920..f17c8176 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1481,6 +1481,9 @@ 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" +msgid "This object is currently busy" +msgstr "Ten objekt jest obecnie zajęty" + msgid "This object is not a member of a class" msgstr "Ten obiekt nie jest członkiem klasy" diff --git a/po/ru.po b/po/ru.po index 553a4c7e..70727694 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1495,6 +1495,9 @@ msgstr "Эта метка не существует" msgid "This menu is for userlevels from mods, but you didn't install any" msgstr "Это меню для пользовательских уровней из модов, но вы ни одного не уставили" +msgid "This object is currently busy" +msgstr "" + msgid "This object is not a member of a class" msgstr "Этот объект не член класса" diff --git a/src/common/error.h b/src/common/error.h index d1bdac2a..1ba77b1d 100644 --- a/src/common/error.h +++ b/src/common/error.h @@ -31,6 +31,7 @@ enum Error ERR_CONTINUE = 2, //! < continues ERR_STOP = 3, //! < stops ERR_CMD = 4, //! < unknown command + ERR_OBJ_BUSY = 5, //! < object is busy ERR_MANIP_FLY = 101, //! < impossible in flight ERR_MANIP_BUSY = 102, //! < taking: hands already occupied ERR_MANIP_NIL = 103, //! < taking: nothing has to take diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 859a61f9..5cd6c91a 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -563,6 +563,7 @@ void InitializeRestext() stringsErr[ERR_UNKNOWN] = TR("Internal error - tell the developers"); stringsErr[ERR_CMD] = TR("Unknown command"); + stringsErr[ERR_OBJ_BUSY] = TR("This object is currently busy"); stringsErr[ERR_MANIP_FLY] = TR("Impossible when flying"); stringsErr[ERR_MANIP_BUSY] = TR("Already carrying something"); stringsErr[ERR_MANIP_NIL] = TR("Nothing to grab"); diff --git a/src/object/auto/autodestroyer.cpp b/src/object/auto/autodestroyer.cpp index 84333f07..deb77ff7 100644 --- a/src/object/auto/autodestroyer.cpp +++ b/src/object/auto/autodestroyer.cpp @@ -107,7 +107,7 @@ Error CAutoDestroyer::StartAction(int param) m_bExplo = false; } else - return ERR_UNKNOWN; + return ERR_OBJ_BUSY; } return ERR_OK; } diff --git a/src/object/auto/autofactory.cpp b/src/object/auto/autofactory.cpp index 17337975..b48e7cf6 100644 --- a/src/object/auto/autofactory.cpp +++ b/src/object/auto/autofactory.cpp @@ -129,7 +129,7 @@ Error CAutoFactory::StartAction(int param) { if ( m_phase != AFP_WAIT ) { - return ERR_OK; + return ERR_OBJ_BUSY; } m_type = type; diff --git a/src/object/auto/autolabo.cpp b/src/object/auto/autolabo.cpp index 0fb087d5..1cbcbc24 100644 --- a/src/object/auto/autolabo.cpp +++ b/src/object/auto/autolabo.cpp @@ -121,7 +121,7 @@ Error CAutoLabo::StartAction(int param) { if ( m_phase != ALAP_WAIT ) { - return ERR_UNKNOWN; + return ERR_OBJ_BUSY; } m_research = static_cast(param); diff --git a/src/object/auto/autoresearch.cpp b/src/object/auto/autoresearch.cpp index 2303d7c9..32380de4 100644 --- a/src/object/auto/autoresearch.cpp +++ b/src/object/auto/autoresearch.cpp @@ -104,7 +104,7 @@ Error CAutoResearch::StartAction(int param) { if ( m_phase != ALP_WAIT ) { - return ERR_UNKNOWN; + return ERR_OBJ_BUSY; } m_research = static_cast(param); From 8d52e27c2b827eb43351b6b2339829fa0824b1dd Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 27 Dec 2016 14:58:41 +0100 Subject: [PATCH 29/93] Add coordinates under cursor overlay and copy function (#868) --- src/common/event.h | 2 +- src/ui/debug_menu.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++- src/ui/debug_menu.h | 31 ++++++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/common/event.h b/src/common/event.h index 315a4b5b..c67b7c3d 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -172,7 +172,7 @@ enum EventType EVENT_LABEL16 = 106, EVENT_LABEL17 = 107, EVENT_LABEL18 = 108, - EVENT_LABEL19 = 109, + EVENT_LABEL19 = 109, // cursor position overlay EVENT_LIST0 = 110, EVENT_LIST1 = 111, diff --git a/src/ui/debug_menu.cpp b/src/ui/debug_menu.cpp index 10aa9397..1510e2bb 100644 --- a/src/ui/debug_menu.cpp +++ b/src/ui/debug_menu.cpp @@ -20,6 +20,9 @@ #include "ui/debug_menu.h" #include "common/event.h" +#include "common/stringutils.h" + +#include "app/app.h" #include "graphics/engine/lightning.h" #include "graphics/engine/terrain.h" @@ -34,8 +37,11 @@ #include "ui/controls/button.h" #include "ui/controls/check.h" #include "ui/controls/interface.h" +#include "ui/controls/label.h" #include "ui/controls/window.h" +#include + namespace Ui { @@ -55,10 +61,17 @@ CDebugMenu::~CDebugMenu() void CDebugMenu::ToggleInterface() { - if (m_interface->SearchControl(EVENT_WINDOW7) == nullptr) + if (!IsActive()) + { CreateInterface(); + CLabel* pl = m_interface->CreateLabel(Math::Point(0.0f, 0.9f), Math::Point(1.0f, 0.1f), -1, EVENT_LABEL19, "??"); + pl->SetFontType(Gfx::FONT_COURIER); + } else + { + m_interface->DeleteControl(EVENT_LABEL19); DestroyInterface(); + } } const Math::Point dim = Math::Point(33.0f/640.0f, 33.0f/480.0f); @@ -359,6 +372,18 @@ bool CDebugMenu::EventProcess(const Event &event) } break; + case EVENT_FRAME: + HandleFrameUpdate(event); + break; + + case EVENT_KEY_DOWN: + if (event.GetData()->key == KEY(c) && (event.kmodState & KMOD_CTRL) != 0) + { + if (IsActive()) + { + return !HandleCopy(event.mousePos); + } + } default: break; @@ -427,4 +452,38 @@ bool CDebugMenu::HandleTeleport(Math::Point mousePos) return true; } +void CDebugMenu::HandleFrameUpdate(const Event &event) +{ + std::string str = "-"; + Math::Vector pos; + int obj; + if ((obj = m_engine->DetectObject(event.mousePos, pos, true)) != -1) + str = StrUtils::Format("pos=% 3.2f; % 3.2f height=% 3.2f objId=% 4d", pos.x, pos.z, pos.y, obj); + + CLabel* pl = static_cast(m_interface->SearchControl(EVENT_LABEL19)); + if (pl == nullptr) return; + pl->SetName(str.c_str()); +} + +bool CDebugMenu::HandleCopy(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; + } + + std::string str = StrUtils::Format("pos=%.2f;%.2f", pos.x, pos.z); + + GetLogger()->Debug("%s\n", str.c_str()); + SDL_SetClipboardText(str.c_str()); + return true; +} + +bool CDebugMenu::IsActive() +{ + return m_interface->SearchControl(EVENT_WINDOW7) != nullptr; +} + } diff --git a/src/ui/debug_menu.h b/src/ui/debug_menu.h index a45623ac..67e183fd 100644 --- a/src/ui/debug_menu.h +++ b/src/ui/debug_menu.h @@ -37,24 +37,55 @@ namespace Ui { class CInterface; +/** + * \class CDebugMenu + * \brief Handles debug menu (F11) + * + * There should always be only one instance of this class for each associated CRobotMain class. + */ class CDebugMenu { public: + //! Creates the CDebugMenu instance CDebugMenu(CRobotMain* main, Gfx::CEngine* engine, CObjectManager* objMan, CSoundInterface* sound); + //! Destroys the CDebugMenu instance + //! \note Does not clean up the interface, should be called only when CRobotMain is destroyed virtual ~CDebugMenu(); + //! Toggle the debug interface void ToggleInterface(); + //! Check if the debug interface is open + bool IsActive(); + + //! Event processing bool EventProcess(const Event& event); protected: + //! Create the main page of debug interface void CreateInterface(); + //! Create the spawn object interface void CreateSpawnInterface(); + //! Update controls in the debug interface void UpdateInterface(); + //! Destroy the debug interface window void DestroyInterface(); + //! Handle frame update + //! This is used to update the cursor coordinates overlay + void HandleFrameUpdate(const Event &event); + + //! Handle spawning a new object at mouse position + //! \return true on success, false on error bool HandleSpawnObject(ObjectType type, Math::Point mousePos); + //! Handle lightning at position + //! \return true on success, false on error bool HandleLightning(Math::Point mousePos); + //! Handle teleport to position + //! \return true on success, false on error bool HandleTeleport(Math::Point mousePos); + //! Handle ctrl+c (copy coordinates under cursor to clipboard) + //! \return true on success, false on error + bool HandleCopy(Math::Point mousePos); protected: CRobotMain* m_main; From 5722fdb163b92ce38f613215bfdfdf39966d7e3d Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 27 Dec 2016 15:21:49 +0100 Subject: [PATCH 30/93] Fix bug (?) related to lost cutscenes This was here since the original game, probably unused but I fixed it anyway --- src/level/robotmain.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index b1be1192..0918d339 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -2589,7 +2589,7 @@ bool CRobotMain::EventFrame(const Event &event) if (m_lostDelay <= 0.0f) { if (m_movieLock) - m_winDelay = 1.0f; + m_lostDelay = 1.0f; else m_eventQueue->AddEvent(Event(EVENT_LOST)); } @@ -5054,7 +5054,6 @@ Error CRobotMain::CheckEndMission(bool frame) Error result = ProcessEndMissionTake(); if (result != ERR_MISSION_NOTERM) return result; } - // Take action depending on m_missionResult if (m_missionResult == INFO_LOSTq) From f33ffaf18b57f98e2bbc83ad0452e036b4929041 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 27 Dec 2016 15:32:38 +0100 Subject: [PATCH 31/93] Fix mission end before astronaut death scene is finished (#848) --- src/object/old_object.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index c8937423..1f2f6e29 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -2654,7 +2654,10 @@ bool COldObject::IsDying() bool COldObject::GetActive() { - return !GetLock() && !(Implements(ObjectInterfaceType::Destroyable) && IsDying()) && !m_bFlat; + // Dying astronaut (m_dying == DeathType::Dead) should be treated as active + // This is for EndMissionTake to not detect him as actually dead until the animation is finished + + return !GetLock() && !(Implements(ObjectInterfaceType::Destroyable) && IsDying() && GetDying() != DeathType::Dead) && !m_bFlat; } bool COldObject::GetDetectable() From 17511ddb6a10456a4e5e5b2ad5bd6f5a4b20377a Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 27 Dec 2016 15:54:52 +0100 Subject: [PATCH 32/93] Fix some code style --- src/object/task/taskgoto.cpp | 12 ++++-------- src/ui/debug_menu.cpp | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/object/task/taskgoto.cpp b/src/object/task/taskgoto.cpp index 0da2de49..5d6cd475 100644 --- a/src/object/task/taskgoto.cpp +++ b/src/object/task/taskgoto.cpp @@ -1093,19 +1093,15 @@ CObject* CTaskGoto::SearchTarget(Math::Vector pos, float margin) * See issue #732 */ - CObject *pBest; - Math::Vector oPos; - float dist, min; - - pBest = 0; - min = 1000000.0f; + CObject* pBest = nullptr; + float min = 1000000.0f; for ( CObject* pObj : CObjectManager::GetInstancePointer()->GetAllObjects() ) { if ( !pObj->GetActive() ) continue; if ( IsObjectBeingTransported(pObj) ) continue; // object transtorted? - oPos = pObj->GetPosition(); - dist = Math::DistanceProjected(pos, oPos); + Math::Vector oPos = pObj->GetPosition(); + float dist = Math::DistanceProjected(pos, oPos); if ( dist <= margin && dist <= min ) { diff --git a/src/ui/debug_menu.cpp b/src/ui/debug_menu.cpp index 1510e2bb..a6eb6f63 100644 --- a/src/ui/debug_menu.cpp +++ b/src/ui/debug_menu.cpp @@ -19,11 +19,11 @@ #include "ui/debug_menu.h" +#include "app/app.h" + #include "common/event.h" #include "common/stringutils.h" -#include "app/app.h" - #include "graphics/engine/lightning.h" #include "graphics/engine/terrain.h" From 6a382830a95a36a2e643193729433ddba266c420 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 27 Dec 2016 22:20:58 +0100 Subject: [PATCH 33/93] Allow selectinsect to select other objects with selectable=0 --- src/level/robotmain.cpp | 38 +++++++++----------------------------- src/level/robotmain.h | 3 --- src/ui/controls/target.cpp | 2 +- 3 files changed, 10 insertions(+), 33 deletions(-) diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 0918d339..aa8ae91a 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -1851,7 +1851,8 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError) if (m_movieLock || m_editLock) return false; if (m_movie->IsExist()) return false; - if (obj != nullptr && !IsSelectable(obj)) return false; + if (obj != nullptr && + (!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast(obj)->GetSelectable() || m_selectInsect))) return false; if (m_missionType == MISSION_CODE_BATTLE && m_codeBattleStarted && m_codeBattleSpectator) { @@ -1944,7 +1945,7 @@ CObject* CRobotMain::SearchNearest(Math::Vector pos, CObject* exclu) for (CObject* obj : m_objMan->GetAllObjects()) { if (obj == exclu) continue; - if (!IsSelectable(obj)) continue; + if (!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast(obj)->GetSelectable() || m_selectInsect)) continue; ObjectType type = obj->GetType(); if (type == OBJECT_TOTO) continue; @@ -2019,30 +2020,6 @@ CObject* CRobotMain::DetectObject(Math::Point pos) return nullptr; } -//! Indicates whether an object is selectable -// TODO: Refactor this, calling CControllableObject::GetSelectable should always be enough -bool CRobotMain::IsSelectable(CObject* obj) -{ - if (obj->GetType() == OBJECT_TOTO) return true; - if (!obj->Implements(ObjectInterfaceType::Controllable)) return false; - - if (!m_selectInsect) - { - // TODO: Some function in CControllableObject - if ( obj->GetType() == OBJECT_MOTHER || - obj->GetType() == OBJECT_ANT || - obj->GetType() == OBJECT_SPIDER || - obj->GetType() == OBJECT_BEE || - obj->GetType() == OBJECT_WORM || - obj->GetType() == OBJECT_MOBILEtg ) - { - return false; - } - } - - return dynamic_cast(obj)->GetSelectable(); -} - //! Deletes the selected object bool CRobotMain::DestroySelectedObject() @@ -2136,10 +2113,13 @@ void CRobotMain::HiliteObject(Math::Point pos) } } - if (IsSelectable(obj)) + if (obj->Implements(ObjectInterfaceType::Controllable) && (dynamic_cast(obj)->GetSelectable() || m_selectInsect)) { - assert(obj->Implements(ObjectInterfaceType::Controllable)); - dynamic_cast(obj)->SetHighlight(true); + if (dynamic_cast(obj)->GetSelectable()) + { + // Don't highlight objects that would not be selectable without selectinsect + dynamic_cast(obj)->SetHighlight(true); + } m_map->SetHighlight(obj); m_short->SetHighlight(obj); m_hilite = true; diff --git a/src/level/robotmain.h b/src/level/robotmain.h index 18649c0e..54d15abc 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -364,10 +364,7 @@ public: void StartDetectEffect(COldObject* object, CObject* target); - bool IsSelectable(CObject* obj); - void SetDebugCrashSpheres(bool draw); - bool GetDebugCrashSpheres(); protected: diff --git a/src/ui/controls/target.cpp b/src/ui/controls/target.cpp index 9ba4f4e0..c90c2051 100644 --- a/src/ui/controls/target.cpp +++ b/src/ui/controls/target.cpp @@ -149,7 +149,7 @@ CObject* CTarget::DetectFriendObject(Math::Point pos) if ( !target->GetDetectable() ) continue; if ( target->GetProxyActivate() ) continue; if ( target->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(target)->GetSelect() ) continue; - if ( !m_main->IsSelectable(target) ) continue; + if ( target->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast(target)->GetSelectable() ) continue; if (!target->Implements(ObjectInterfaceType::Old)) continue; // TODO: To be removed after COldObjectInterface is gone From 46aa6fc907c7c0fc1fea7963e55caed6245f2574 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 27 Dec 2016 23:38:57 +0100 Subject: [PATCH 34/93] Some CRobotMain cleanup * improved documentation * renamed cheat variables to include the word "cheat" to make it clearer what they do * removed some useless members --- Doxyfile.in | 2 +- src/common/error.h | 168 ++++++------- src/level/robotmain.cpp | 159 ++++--------- src/level/robotmain.h | 177 +++++++++++--- src/object/auto/autofactory.cpp | 6 +- src/object/motion/motiontoto.cpp | 67 +++--- src/object/motion/motiontoto.h | 2 - src/object/object_type.h | 392 +++++++++++++++---------------- src/ui/mainshort.cpp | 4 +- 9 files changed, 499 insertions(+), 478 deletions(-) diff --git a/Doxyfile.in b/Doxyfile.in index c621ae33..5b0d31f7 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -351,7 +351,7 @@ IDL_PROPERTY_SUPPORT = YES # all members of a group must be documented explicitly. # The default value is: NO. -DISTRIBUTE_GROUP_DOC = NO +DISTRIBUTE_GROUP_DOC = YES # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that diff --git a/src/common/error.h b/src/common/error.h index 1ba77b1d..d3ae49f7 100644 --- a/src/common/error.h +++ b/src/common/error.h @@ -19,6 +19,10 @@ #pragma once +/** + * \file common/error.h + * \brief Definition of the Error enum + */ /** * \enum Error @@ -26,88 +30,88 @@ */ enum Error { - ERR_OK = 0, //! < ok - ERR_UNKNOWN = 1, //! < any error - ERR_CONTINUE = 2, //! < continues - ERR_STOP = 3, //! < stops - ERR_CMD = 4, //! < unknown command - ERR_OBJ_BUSY = 5, //! < object is busy - ERR_MANIP_FLY = 101, //! < impossible in flight - ERR_MANIP_BUSY = 102, //! < taking: hands already occupied - ERR_MANIP_NIL = 103, //! < taking: nothing has to take - ERR_MANIP_MOTOR = 105, //! < busy: impossible to move - ERR_MANIP_OCC = 106, //! < busy: location already occupied - ERR_MANIP_RADIO = 108, //! < impossible because radioactive - ERR_MANIP_WATER = 109, //! < not possible under water - ERR_MANIP_EMPTY = 110, //! < nothing to deposit - ERR_BUILD_FLY = 120, //! < not possible in flight - ERR_BUILD_WATER = 121, //! < not possible under water - ERR_BUILD_METALAWAY = 123, //! < lack of metal (too far) - ERR_BUILD_METALNEAR = 124, //! < lack of metal (too close) - ERR_BUILD_METALINEX = 125, //! < lack of metal - ERR_BUILD_FLAT = 126, //! < not enough flat ground - ERR_BUILD_FLATLIT = 127, //! < not enough flat ground space - ERR_BUILD_BUSY = 128, //! < location occupied - ERR_BUILD_BASE = 129, //! < too close to the rocket - ERR_BUILD_NARROW = 130, //! < buildings too close - ERR_BUILD_MOTOR = 131, //! < built: not possible in movement - ERR_BUILD_DISABLED = 132, //! < built: can not produce this object in this mission - ERR_BUILD_RESEARCH = 133, //! < built: can not produce not researched object - ERR_SEARCH_FLY = 140, //! < not possible in flight - ERR_SEARCH_MOTOR = 142, //! < impossible in movement - ERR_TERRA_ENERGY = 151, //! < not enough energy - ERR_FIRE_ENERGY = 161, //! < not enough energy - ERR_RECOVER_ENERGY = 171, //! < not enough energy - ERR_RECOVER_NULL = 172, //! < lack of ruin - ERR_CONVERT_EMPTY = 180, //! < no stone was transformed - ERR_SHIELD_ENERGY = 191, //! < not enough energy - ERR_MOVE_IMPOSSIBLE = 200, //! < move impossible - ERR_GOTO_IMPOSSIBLE = 210, //! < goto impossible - ERR_GOTO_ITER = 211, //! < goto too complicated - ERR_GOTO_BUSY = 212, //! < goto destination occupied - ERR_DERRICK_NULL = 300, //! < no ore underground - ERR_STATION_NULL = 301, //! < no energy underground - ERR_TOWER_POWER = 310, //! < no battery - ERR_TOWER_ENERGY = 311, //! < more energy - ERR_RESEARCH_POWER = 320, //! < no battery - ERR_RESEARCH_ENERGY = 321, //! < more energy - ERR_RESEARCH_TYPE = 322, //! < the wrong type of battery - ERR_RESEARCH_ALREADY = 323, //! < research already done - ERR_ENERGY_NULL = 330, //! < no energy underground - ERR_ENERGY_LOW = 331, //! < not enough energy - ERR_ENERGY_EMPTY = 332, //! < lack of metal - ERR_ENERGY_BAD = 333, //! < transforms only the metal - ERR_BASE_DLOCK = 340, //! < doors locked - ERR_BASE_DHUMAN = 341, //! < you must be on spaceship - ERR_LABO_NULL = 350, //! < nothing to analyze - ERR_LABO_BAD = 351, //! < analyzes only organic ball - ERR_LABO_ALREADY = 352, //! < analysis already made - ERR_NUCLEAR_EMPTY = 362, //! < lack of uranium - ERR_NUCLEAR_BAD = 363, //! < transforms only uranium - ERR_FACTORY_NULL = 370, //! < no metal - ERR_FACTORY_NEAR = 371, //! < vehicle too close - ERR_INFO_NULL = 390, //! < no information terminal - ERR_VEH_VIRUS = 400, //! < vehicle infected by a virus - ERR_BAT_VIRUS = 401, //! < building infected by a virus - ERR_DESTROY_NOTFOUND = 410, //! < not found anything to destroy - ERR_WRONG_OBJ = 420, //! < inappropriate vehicle - ERR_VEH_POWER = 500, //! < no battery - ERR_VEH_ENERGY = 501, //! < more energy - ERR_FLAG_FLY = 510, //! < impossible in flight - ERR_FLAG_WATER = 511, //! < impossible during swimming - ERR_FLAG_MOTOR = 512, //! < impossible in movement - ERR_FLAG_BUSY = 513, //! < taking: already creating flag - ERR_FLAG_CREATE = 514, //! < too many flags - ERR_FLAG_PROXY = 515, //! < too close - ERR_FLAG_DELETE = 516, //! < nothing to remove - ERR_MISSION_NOTERM = 600, //! < Mission not completed - ERR_DELETEMOBILE = 700, //! < vehicle destroyed - ERR_DELETEBUILDING = 701, //! < building destroyed - ERR_ENEMY_OBJECT = 703, //! < can't control enemy object - ERR_OBLIGATORYTOKEN = 800, //! < compulsory instruction missing - ERR_PROHIBITEDTOKEN = 801, //! < instruction prohibited - ERR_AIM_IMPOSSIBLE = 900, //! < cannot aim at specified angle(s) - ERR_WRONG_BOT = 910, //! < inappropriate bot + ERR_OK = 0, //!< ok + ERR_UNKNOWN = 1, //!< any error + ERR_CONTINUE = 2, //!< continues + ERR_STOP = 3, //!< stops + ERR_CMD = 4, //!< unknown command + ERR_OBJ_BUSY = 5, //!< object is busy + ERR_MANIP_FLY = 101, //!< impossible in flight + ERR_MANIP_BUSY = 102, //!< taking: hands already occupied + ERR_MANIP_NIL = 103, //!< taking: nothing has to take + ERR_MANIP_MOTOR = 105, //!< busy: impossible to move + ERR_MANIP_OCC = 106, //!< busy: location already occupied + ERR_MANIP_RADIO = 108, //!< impossible because radioactive + ERR_MANIP_WATER = 109, //!< not possible under water + ERR_MANIP_EMPTY = 110, //!< nothing to deposit + ERR_BUILD_FLY = 120, //!< not possible in flight + ERR_BUILD_WATER = 121, //!< not possible under water + ERR_BUILD_METALAWAY = 123, //!< lack of metal (too far) + ERR_BUILD_METALNEAR = 124, //!< lack of metal (too close) + ERR_BUILD_METALINEX = 125, //!< lack of metal + ERR_BUILD_FLAT = 126, //!< not enough flat ground + ERR_BUILD_FLATLIT = 127, //!< not enough flat ground space + ERR_BUILD_BUSY = 128, //!< location occupied + ERR_BUILD_BASE = 129, //!< too close to the rocket + ERR_BUILD_NARROW = 130, //!< buildings too close + ERR_BUILD_MOTOR = 131, //!< built: not possible in movement + ERR_BUILD_DISABLED = 132, //!< built: can not produce this object in this mission + ERR_BUILD_RESEARCH = 133, //!< built: can not produce not researched object + ERR_SEARCH_FLY = 140, //!< not possible in flight + ERR_SEARCH_MOTOR = 142, //!< impossible in movement + ERR_TERRA_ENERGY = 151, //!< not enough energy + ERR_FIRE_ENERGY = 161, //!< not enough energy + ERR_RECOVER_ENERGY = 171, //!< not enough energy + ERR_RECOVER_NULL = 172, //!< lack of ruin + ERR_CONVERT_EMPTY = 180, //!< no stone was transformed + ERR_SHIELD_ENERGY = 191, //!< not enough energy + ERR_MOVE_IMPOSSIBLE = 200, //!< move impossible + ERR_GOTO_IMPOSSIBLE = 210, //!< goto impossible + ERR_GOTO_ITER = 211, //!< goto too complicated + ERR_GOTO_BUSY = 212, //!< goto destination occupied + ERR_DERRICK_NULL = 300, //!< no ore underground + ERR_STATION_NULL = 301, //!< no energy underground + ERR_TOWER_POWER = 310, //!< no battery + ERR_TOWER_ENERGY = 311, //!< more energy + ERR_RESEARCH_POWER = 320, //!< no battery + ERR_RESEARCH_ENERGY = 321, //!< more energy + ERR_RESEARCH_TYPE = 322, //!< the wrong type of battery + ERR_RESEARCH_ALREADY = 323, //!< research already done + ERR_ENERGY_NULL = 330, //!< no energy underground + ERR_ENERGY_LOW = 331, //!< not enough energy + ERR_ENERGY_EMPTY = 332, //!< lack of metal + ERR_ENERGY_BAD = 333, //!< transforms only the metal + ERR_BASE_DLOCK = 340, //!< doors locked + ERR_BASE_DHUMAN = 341, //!< you must be on spaceship + ERR_LABO_NULL = 350, //!< nothing to analyze + ERR_LABO_BAD = 351, //!< analyzes only organic ball + ERR_LABO_ALREADY = 352, //!< analysis already made + ERR_NUCLEAR_EMPTY = 362, //!< lack of uranium + ERR_NUCLEAR_BAD = 363, //!< transforms only uranium + ERR_FACTORY_NULL = 370, //!< no metal + ERR_FACTORY_NEAR = 371, //!< vehicle too close + ERR_INFO_NULL = 390, //!< no information terminal + ERR_VEH_VIRUS = 400, //!< vehicle infected by a virus + ERR_BAT_VIRUS = 401, //!< building infected by a virus + ERR_DESTROY_NOTFOUND = 410, //!< not found anything to destroy + ERR_WRONG_OBJ = 420, //!< inappropriate vehicle + ERR_VEH_POWER = 500, //!< no battery + ERR_VEH_ENERGY = 501, //!< more energy + ERR_FLAG_FLY = 510, //!< impossible in flight + ERR_FLAG_WATER = 511, //!< impossible during swimming + ERR_FLAG_MOTOR = 512, //!< impossible in movement + ERR_FLAG_BUSY = 513, //!< taking: already creating flag + ERR_FLAG_CREATE = 514, //!< too many flags + ERR_FLAG_PROXY = 515, //!< too close + ERR_FLAG_DELETE = 516, //!< nothing to remove + ERR_MISSION_NOTERM = 600, //!< Mission not completed + ERR_DELETEMOBILE = 700, //!< vehicle destroyed + ERR_DELETEBUILDING = 701, //!< building destroyed + ERR_ENEMY_OBJECT = 703, //!< can't control enemy object + ERR_OBLIGATORYTOKEN = 800, //!< compulsory instruction missing + ERR_PROHIBITEDTOKEN = 801, //!< instruction prohibited + ERR_AIM_IMPOSSIBLE = 900, //!< cannot aim at specified angle(s) + ERR_WRONG_BOT = 910, //!< inappropriate bot INFO_FIRST = 10000, //! < first information INFO_BUILD = 10001, //! < construction builded diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index aa8ae91a..80e9ce06 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -202,8 +202,8 @@ CRobotMain::CRobotMain() m_editLock = false; m_editFull = false; m_hilite = false; - m_selectInsect = false; - m_showSoluce = false; + m_cheatSelectInsect = false; + m_cheatShowSoluce = false; m_codeBattleInit = false; m_codeBattleStarted = false; @@ -211,14 +211,14 @@ CRobotMain::CRobotMain() m_teamNames.clear(); #if DEV_BUILD - m_showAll = true; // for development + m_cheatAllMission = true; // for development #else - m_showAll = false; + m_cheatAllMission = false; #endif m_cheatRadar = false; m_fixScene = false; - m_trainerPilot = false; + m_cheatTrainerPilot = false; m_friendAim = false; m_resetCreate = false; m_shortCut = true; @@ -451,7 +451,7 @@ void CRobotMain::ChangePhase(Phase phase) m_lightning->Flush(); m_planet->Flush(); m_interface->Flush(); - FlushNewScriptName(); + m_newScriptName.clear(); m_sound->SetListener(Math::Vector(0.0f, 0.0f, 0.0f), Math::Vector(0.0f, 0.0f, 1.0f)); m_sound->StopAll(); m_camera->SetType(Gfx::CAM_TYPE_NULL); @@ -922,7 +922,7 @@ bool CRobotMain::ProcessEvent(Event &event) } if (data->slot == INPUT_SLOT_HUMAN) { - SelectHuman(); + SelectObject(SearchHuman()); } if (data->slot == INPUT_SLOT_NEXT && ((event.kmodState & KEY_MOD(CTRL)) != 0)) { @@ -1159,7 +1159,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd) if (cmd == "trainerpilot") { - m_trainerPilot = !m_trainerPilot; + m_cheatTrainerPilot = !m_cheatTrainerPilot; return; } @@ -1410,20 +1410,20 @@ void CRobotMain::ExecuteCmd(const std::string& cmd) if (cmd == "selectinsect") { - m_selectInsect = !m_selectInsect; + m_cheatSelectInsect = !m_cheatSelectInsect; return; } if (cmd == "showsoluce") { - m_showSoluce = !m_showSoluce; + m_cheatShowSoluce = !m_cheatShowSoluce; m_ui->ShowSoluceUpdate(); return; } if (cmd == "allmission") { - m_showAll = !m_showAll; + m_cheatAllMission = !m_cheatAllMission; m_ui->AllMissionUpdate(); return; } @@ -1763,20 +1763,17 @@ void CRobotMain::StopDisplayVisit() -//! Updates all the shortcuts void CRobotMain::UpdateShortcuts() { m_short->UpdateShortcuts(); } -//! Returns the object that default was select after the creation of a scene CObject* CRobotMain::GetSelectObject() { if (m_selectObject != nullptr) return m_selectObject; return SearchHuman(); } -//! Deselects everything, and returns the object that was selected CObject* CRobotMain::DeselectAll() { CObject* prev = nullptr; @@ -1833,17 +1830,8 @@ void CRobotMain::SelectOneObject(CObject* obj, bool displayError) { m_camera->SetType(Gfx::CAM_TYPE_BACK); } - - CObject* toto = SearchToto(); - if (toto != nullptr) - { - assert(toto->Implements(ObjectInterfaceType::Movable)); - CMotionToto* mt = static_cast(dynamic_cast(toto)->GetMotion()); - mt->SetLinkType(type); - } } -//! Selects the object aimed by the mouse bool CRobotMain::SelectObject(CObject* obj, bool displayError) { if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT) @@ -1852,7 +1840,7 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError) if (m_movieLock || m_editLock) return false; if (m_movie->IsExist()) return false; if (obj != nullptr && - (!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast(obj)->GetSelectable() || m_selectInsect))) return false; + (!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast(obj)->GetSelectable() || m_cheatSelectInsect))) return false; if (m_missionType == MISSION_CODE_BATTLE && m_codeBattleStarted && m_codeBattleSpectator) { @@ -1883,7 +1871,6 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError) return true; } -//! Deselects the selected object bool CRobotMain::DeselectObject() { DeselectAll(); @@ -1919,49 +1906,11 @@ void CRobotMain::DeleteAllObjects() m_objMan->DeleteAllObjects(); } -//! Selects the human -void CRobotMain::SelectHuman() -{ - SelectObject(SearchHuman()); -} - -//! Returns the object human CObject* CRobotMain::SearchHuman() { return m_objMan->FindNearest(nullptr, OBJECT_HUMAN); } -//! Returns the object toto -CObject* CRobotMain::SearchToto() -{ - return m_objMan->FindNearest(nullptr, OBJECT_TOTO); -} - -//! Returns the nearest selectable object from a given position -CObject* CRobotMain::SearchNearest(Math::Vector pos, CObject* exclu) -{ - float min = 100000.0f; - CObject* best = nullptr; - for (CObject* obj : m_objMan->GetAllObjects()) - { - if (obj == exclu) continue; - if (!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast(obj)->GetSelectable() || m_selectInsect)) continue; - - ObjectType type = obj->GetType(); - if (type == OBJECT_TOTO) continue; - - Math::Vector oPos = obj->GetPosition(); - float dist = Math::DistanceProjected(oPos, pos); - if (dist < min) - { - min = dist; - best = obj; - } - } - return best; -} - -//! Returns the selected object CObject* CRobotMain::GetSelect() { for (CObject* obj : m_objMan->GetAllObjects()) @@ -2113,7 +2062,7 @@ void CRobotMain::HiliteObject(Math::Point pos) } } - if (obj->Implements(ObjectInterfaceType::Controllable) && (dynamic_cast(obj)->GetSelectable() || m_selectInsect)) + if (obj->Implements(ObjectInterfaceType::Controllable) && (dynamic_cast(obj)->GetSelectable() || m_cheatSelectInsect)) { if (dynamic_cast(obj)->GetSelectable()) { @@ -2652,7 +2601,6 @@ bool CRobotMain::EventObject(const Event &event) -//! Load the scene for the character void CRobotMain::ScenePerso() { DeleteAllObjects(); // removes all the current 3D Scene @@ -3629,7 +3577,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) if (line->GetCommand() == "NewScript" && !resetObject) { - AddNewScriptName(line->GetParam("type")->AsObjectType(OBJECT_NULL), const_cast(line->GetParam("name")->AsPath("ai").c_str())); + m_newScriptName.push_back(NewScriptName(line->GetParam("type")->AsObjectType(OBJECT_NULL), const_cast(line->GetParam("name")->AsPath("ai").c_str()))); continue; } @@ -3950,15 +3898,17 @@ void CRobotMain::ChangeColor() } //! Calculates the distance to the nearest object -float CRobotMain::SearchNearestObject(Math::Vector center, CObject *exclu) +namespace +{ +float SearchNearestObject(CObjectManager* objMan, Math::Vector center, CObject* exclu) { float min = 100000.0f; - for (CObject* obj : m_objMan->GetAllObjects()) + for (CObject* obj : objMan->GetAllObjects()) { if (!obj->GetDetectable()) continue; // inactive? if (IsObjectBeingTransported(obj)) continue; - if (obj == exclu) continue; + if (obj == exclu) continue; ObjectType type = obj->GetType(); @@ -3968,35 +3918,36 @@ float CRobotMain::SearchNearestObject(Math::Vector center, CObject *exclu) if (oPos.x != center.x || oPos.z != center.z) { - float dist = Math::Distance(center, oPos)-80.0f; + float dist = Math::Distance(center, oPos) - 80.0f; if (dist < 0.0f) dist = 0.0f; min = Math::Min(min, dist); continue; } } - if (type == OBJECT_STATION || - type == OBJECT_REPAIR || + if (type == OBJECT_STATION || + type == OBJECT_REPAIR || type == OBJECT_DESTROYER) { Math::Vector oPos = obj->GetPosition(); - float dist = Math::Distance(center, oPos)-8.0f; + float dist = Math::Distance(center, oPos) - 8.0f; if (dist < 0.0f) dist = 0.0f; min = Math::Min(min, dist); } - for (const auto& crashSphere : obj->GetAllCrashSpheres()) + for (const auto &crashSphere : obj->GetAllCrashSpheres()) { Math::Vector oPos = crashSphere.sphere.pos; float oRadius = crashSphere.sphere.radius; - float dist = Math::Distance(center, oPos)-oRadius; + float dist = Math::Distance(center, oPos) - oRadius; if (dist < 0.0f) dist = 0.0f; min = Math::Min(min, dist); } } return min; } +} //! Calculates a free space bool CRobotMain::FreeSpace(Math::Vector ¢er, float minRadius, float maxRadius, @@ -4018,7 +3969,7 @@ bool CRobotMain::FreeSpace(Math::Vector ¢er, float minRadius, float maxRadiu pos.z = p.y; pos.y = 0.0f; m_terrain->AdjustToFloor(pos, true); - float dist = SearchNearestObject(pos, exclu); + float dist = SearchNearestObject(m_objMan.get(), pos, exclu); if (dist >= space) { float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f); @@ -4047,7 +3998,7 @@ bool CRobotMain::FreeSpace(Math::Vector ¢er, float minRadius, float maxRadiu pos.z = p.y; pos.y = 0.0f; m_terrain->AdjustToFloor(pos, true); - float dist = SearchNearestObject(pos, exclu); + float dist = SearchNearestObject(m_objMan.get(), pos, exclu); if (dist >= space) { float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f); @@ -4083,7 +4034,7 @@ bool CRobotMain::FlatFreeSpace(Math::Vector ¢er, float minFlat, float minRad pos.z = p.y; pos.y = 0.0f; m_terrain->AdjustToFloor(pos, true); - float dist = SearchNearestObject(pos, exclu); + float dist = SearchNearestObject(m_objMan.get(), pos, exclu); if (dist >= space) { float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f); @@ -4116,7 +4067,7 @@ bool CRobotMain::FlatFreeSpace(Math::Vector ¢er, float minFlat, float minRad pos.z = p.y; pos.y = 0.0f; m_terrain->AdjustToFloor(pos, true); - float dist = SearchNearestObject(pos, exclu); + float dist = SearchNearestObject(m_objMan.get(), pos, exclu); if (dist >= space) { float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f); @@ -4140,7 +4091,7 @@ bool CRobotMain::FlatFreeSpace(Math::Vector ¢er, float minFlat, float minRad float CRobotMain::GetFlatZoneRadius(Math::Vector center, float maxRadius, CObject *exclu) { - float dist = SearchNearestObject(center, exclu); + float dist = SearchNearestObject(m_objMan.get(), center, exclu); if (dist == 0.0f) return 0.0f; if (dist < maxRadius) maxRadius = dist; @@ -4412,36 +4363,19 @@ bool CRobotMain::ReadFileStack(CObject *obj, FILE *file, int objRank) return programmable->ReadStack(file); } - -//! Empty the list -void CRobotMain::FlushNewScriptName() +std::vector CRobotMain::GetNewScriptNames(ObjectType type) { - m_newScriptName.clear(); -} - -//! Adds a script name -void CRobotMain::AddNewScriptName(ObjectType type, const std::string& name) -{ - NewScriptName newscript; - newscript.type = type; - newscript.name = name; - m_newScriptName.push_back(newscript); -} - -//! Seeks a script name for a given type -std::string CRobotMain::GetNewScriptName(ObjectType type, int rank) -{ - for (unsigned int i = 0; i < m_newScriptName.size(); i++) + std::vector names; + for (const auto& newScript : m_newScriptName) { - if (m_newScriptName[i].type == type || - m_newScriptName[i].type == OBJECT_NULL ) + if (newScript.type == type || + newScript.type == OBJECT_NULL ) { - if (rank == 0) return m_newScriptName[i].name; - else rank --; + names.push_back(newScript.name); } } - return ""; + return names; } @@ -5114,7 +5048,7 @@ const std::map& CRobotMain::GetObligatoryTokenList() //! Indicates whether it is possible to control a driving robot bool CRobotMain::GetTrainerPilot() { - return m_trainerPilot; + return m_cheatTrainerPilot; } //! Indicates whether the scene is fixed, without interaction @@ -5137,7 +5071,7 @@ const std::string& CRobotMain::GetScriptFile() bool CRobotMain::GetShowSoluce() { - return m_showSoluce; + return m_cheatShowSoluce; } bool CRobotMain::GetSceneSoluce() @@ -5148,7 +5082,7 @@ bool CRobotMain::GetSceneSoluce() bool CRobotMain::GetShowAll() { - return m_showAll; + return m_cheatAllMission; } bool CRobotMain::GetRadar() @@ -5272,7 +5206,6 @@ void CRobotMain::UpdateSpeedLabel() } -//! Creates interface shortcuts to the units bool CRobotMain::CreateShortcuts() { if (m_phase != PHASE_SIMUL) return false; @@ -5662,11 +5595,6 @@ Error CRobotMain::CanBuildError(ObjectType type, int team) return ERR_OK; } -bool CRobotMain::CanBuild(ObjectType type, int team) -{ - return CanBuildError(type, team) == ERR_OK; -} - Error CRobotMain::CanFactoryError(ObjectType type, int team) { ToolType tool = GetToolFromObject(type); @@ -5690,11 +5618,6 @@ Error CRobotMain::CanFactoryError(ObjectType type, int team) return ERR_OK; } -bool CRobotMain::CanFactory(ObjectType type, int team) -{ - return CanFactoryError(type, team) == ERR_OK; -} - void CRobotMain::PushToSelectionHistory(CObject* obj) { if (!m_selectionHistory.empty() && m_selectionHistory.back() == obj) diff --git a/src/level/robotmain.h b/src/level/robotmain.h index 54d15abc..346e8fc4 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -120,6 +120,8 @@ struct NewScriptName { ObjectType type = OBJECT_NULL; std::string name = ""; + + NewScriptName(ObjectType type, const std::string& name) : type(type), name(name) {} }; @@ -156,6 +158,17 @@ const int SATCOM_PROG = 4; const int SATCOM_SOLUCE = 5; const int SATCOM_MAX = 6; +/** + * \brief Main class managing the game world + * + * This is the main class of the whole game engine. It's main job is to manage main parts of the gameplay, + * like loading levels and checking for win conditions, but it's also a place where all things that don't fit + * elsewhere have landed. + * + * \todo In the future, it would be nice to refactor this class to remove as much unrelated stuff as possible + * + * \nosubgrouping + */ class CRobotMain : public CSingleton { public: @@ -168,11 +181,16 @@ public: Ui::CDisplayText* GetDisplayText(); CPauseManager* GetPauseManager(); + /** + * \name Phase management + */ + //@{ void ChangePhase(Phase phase); bool ProcessEvent(Event &event); Phase GetPhase(); + //@} - bool CreateShortcuts(); + //! Load the scene for apperance customization void ScenePerso(); void SetMovieLock(bool lock); @@ -187,16 +205,32 @@ public: void SetFriendAim(bool friendAim); bool GetFriendAim(); + //! \name Simulation speed management + //@{ void SetSpeed(float speed); float GetSpeed(); + //@} + //! \brief Create the shortcuts at the top of the screen, if they should be visible + //! \see CMainShort::CreateShortcuts + bool CreateShortcuts(); + //! \brief Update the shortcuts at the top of the screen + //! \see CMainShort::UpdateShortcuts void UpdateShortcuts(); - void SelectHuman(); + //! Find the astronaut (::OBJECT_HUMAN) object CObject* SearchHuman(); - CObject* SearchToto(); - CObject* SearchNearest(Math::Vector pos, CObject* exclu); + /** + * \brief Select an object + * \param obj Object to select + * \param displayError If true and the object is currently in error state, automatically display the error message + * + * \note This function automatically adds objects to selection history (see PushToSelectionHistory()) + */ bool SelectObject(CObject* obj, bool displayError=true); + //! Return the object that was selected at the start of the scene CObject* GetSelectObject(); + //! Deselect currently selected object + //! \return Object that was deselected CObject* DeselectAll(); void ResetObject(); @@ -251,9 +285,10 @@ public: void ClearInterface(); void ChangeColor(); - float SearchNearestObject(Math::Vector center, CObject *exclu); bool FreeSpace(Math::Vector ¢er, float minRadius, float maxRadius, float space, CObject *exclu); bool FlatFreeSpace(Math::Vector ¢er, float minFlat, float minRadius, float maxRadius, float space, CObject *exclu); + //! \name In-world indicators + //@{ float GetFlatZoneRadius(Math::Vector center, float maxRadius, CObject *exclu); void HideDropZone(CObject* metal); void ShowDropZone(CObject* metal, CObject* transporter); @@ -262,28 +297,34 @@ public: float radius, float duration=SHOWLIMITTIME); void StartShowLimit(); void FrameShowLimit(float rTime); + //@} void SaveAllScript(); void SaveOneScript(CObject *obj); bool SaveFileStack(CObject *obj, FILE *file, int objRank); bool ReadFileStack(CObject *obj, FILE *file, int objRank); - void FlushNewScriptName(); - void AddNewScriptName(ObjectType type, const std::string& name); - std::string GetNewScriptName(ObjectType type, int rank); + //! Return list of scripts to load to robot created in BotFactory + std::vector GetNewScriptNames(ObjectType type); void SelectPlayer(std::string playerName); CPlayerProfile* GetPlayerProfile(); + /** + * \name Saved game read/write + */ + //@{ bool IOIsBusy(); bool IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, const std::string& info, bool emergencySave = false); void IOWriteSceneFinished(); CObject* IOReadScene(std::string filename, std::string filecbot); void IOWriteObject(CLevelParserLine *line, CObject* obj, const std::string& programDir, int objRank); CObject* IOReadObject(CLevelParserLine *line, const std::string& programDir, const std::string& objCounterText, float objectProgress, int objRank = -1); + //@} int CreateSpot(Math::Vector pos, Gfx::Color color); + //! Find the currently selected object CObject* GetSelect(); void DisplayError(Error err, CObject* pObj, float time=10.0f); @@ -298,12 +339,17 @@ public: void StartMissionTimer(); + /** + * \name Autosave management + */ + //@{ void SetAutosave(bool enable); bool GetAutosave(); void SetAutosaveInterval(int interval); int GetAutosaveInterval(); void SetAutosaveSlots(int slots); int GetAutosaveSlots(); + //@} //! Enable mode where completing mission closes the game void SetExitAfterMission(bool exit); @@ -311,49 +357,97 @@ public: //! Returns true if player can interact with things manually bool CanPlayerInteract(); + /** + * \name Team definition management + */ + //@{ //! Returns team name for the given team id const std::string& GetTeamName(int id); //! Returns true if team-specific colored texture is available bool IsTeamColorDefined(int id); + //@} - //! Get/set enabled buildings + /** + * \name EnableBuild/EnableResearch/DoneResearch + * Management of enabled buildings, enabled researches, and completed researches + */ //@{ + /** + * \brief Get enabled buildings + * \return Bitmask of BuildType values + */ int GetEnableBuild(); + /** + * \brief Set enabled buildings + * \param enableBuild Bitmask of BuildType values + */ void SetEnableBuild(int enableBuild); - //@} - //! Get/set enabled researches - //@{ - int GetEnableResearch(); - void SetEnableResearch(int enableResearch); - //@} - //! Get/set done researches - //@{ - int GetDoneResearch(int team); - void SetDoneResearch(int doneResearch, int team); - //@} - //! Returns true if the given building is enabled - //@{ + /** + * \brief Get enabled researches + * \return Bitmask of ResearchType values + */ + int GetEnableResearch(); + /** + * \brief Set enabled researches + * \param enableResearch Bitmask of ResearchType values + */ + void SetEnableResearch(int enableResearch); + /** + * \brief Get done researches + * \param team Team to get researches for + * \return Bitmask of ResearchType values + */ + int GetDoneResearch(int team = 0); + /** + * \brief Set done researches + * \param doneResearch Bitmask of ResearchType values + * \param team Team to set researches for + */ + void SetDoneResearch(int doneResearch, int team = 0); + + //! \brief Check if the given building is enabled bool IsBuildingEnabled(BuildType type); + //! \brief Check if the given building is enabled bool IsBuildingEnabled(ObjectType type); - //@} - //! Returns true if the given research is enabled + //! \brief Check if the given research is enabled bool IsResearchEnabled(ResearchType type); - //! Returns true if the given research is done + //! \brief Check if the given research is done bool IsResearchDone(ResearchType type, int team); - //! Marks research as done + //! \brief Mark given research as done void MarkResearchDone(ResearchType type, int team); - //! Retruns true if all requirements to build this object are met (EnableBuild + DoneResearch) - //@{ - bool CanBuild(ObjectType type, int team); + /** + * \brief Check if all requirements to build this object are met (EnableBuild + DoneResearch) + * \return true if the building can be built, false otherwise + * \see CanBuildError() for a version which returns a specific reason for the build being denied + */ + inline bool CanBuild(ObjectType type, int team) + { + return CanBuildError(type, team) == ERR_OK; + } + /** + * \brief Check if all requirements to build this object are met (EnableBuild + DoneResearch) + * \return One of Error values - ::ERR_OK if the building can be built, ::ERR_BUILD_DISABLED or ::ERR_BUILD_RESEARCH otherwise + * \see CanBuild() for a version which returns a boolean + */ Error CanBuildError(ObjectType type, int team); - //@} - //! Retruns true if all requirements to create this object in BotFactory are met (DoneResearch) - //@{ - bool CanFactory(ObjectType type, int team); + /** + * \brief Check if all requirements to build this object in BotFactory are met (DoneResearch) + * \return true if the robot can be built, false otherwise + * \see CanFactoryError() for a version which returns a specific reason for the build being denied + */ + inline bool CanFactory(ObjectType type, int team) + { + return CanFactoryError(type, team) == ERR_OK; + } + /** + * \brief Check if all requirements to build this object in BotFactory are met (DoneResearch) + * \return One of Error values - ::ERR_OK if the robot can be built, ::ERR_BUILD_DISABLED or ::ERR_BUILD_RESEARCH otherwise + * \see CanFactory() for a version which returns a boolean + */ Error CanFactoryError(ObjectType type, int team); //@} @@ -364,7 +458,9 @@ public: void StartDetectEffect(COldObject* object, CObject* target); + //! Enable crash sphere debug rendering void SetDebugCrashSpheres(bool draw); + //! Check if crash sphere debug rendering is enabled bool GetDebugCrashSpheres(); protected: @@ -388,8 +484,11 @@ protected: CObject* DetectObject(Math::Point pos); void ChangeCamera(); void AbortMovie(); + //! \brief Select an object, without deselecting the previous one void SelectOneObject(CObject* obj, bool displayError=true); void HelpObject(); + //! \brief Switch to previous object + //! \see PopFromSelectionHistory() bool DeselectObject(); void DeleteAllObjects(); void UpdateInfoText(); @@ -405,9 +504,13 @@ protected: void PushToSelectionHistory(CObject* obj); CObject* PopFromSelectionHistory(); + //! \name Code battle interface + //@{ void CreateCodeBattleInterface(); void DestroyCodeBattleInterface(); void SetCodeBattleSpectatorMode(bool mode); + //@} + void UpdateDebugCrashSpheres(); @@ -469,9 +572,9 @@ protected: ActivePause* m_freePhotoPause = nullptr; bool m_cmdEdit = false; ActivePause* m_cmdEditPause = nullptr; - bool m_selectInsect = false; - bool m_showSoluce = false; - bool m_showAll = false; + bool m_cheatSelectInsect = false; + bool m_cheatShowSoluce = false; + bool m_cheatAllMission = false; bool m_cheatRadar = false; bool m_shortCut = false; std::string m_audioTrack; @@ -493,7 +596,7 @@ protected: bool m_editLock = false; // edition in progress? bool m_editFull = false; // edition in full screen? bool m_hilite = false; - bool m_trainerPilot = false; // remote trainer? + bool m_cheatTrainerPilot = false; // remote trainer? bool m_friendAim = false; bool m_resetCreate = false; bool m_mapShow = false; diff --git a/src/object/auto/autofactory.cpp b/src/object/auto/autofactory.cpp index b48e7cf6..7dfc280d 100644 --- a/src/object/auto/autofactory.cpp +++ b/src/object/auto/autofactory.cpp @@ -664,11 +664,9 @@ bool CAutoFactory::CreateVehicle() if (vehicle->Implements(ObjectInterfaceType::ProgramStorage)) { CProgramStorageObject* programStorage = dynamic_cast(vehicle); - for ( int i=0 ; ; i++ ) + for (const std::string& name : m_main->GetNewScriptNames(m_type)) { - std::string name = m_main->GetNewScriptName(m_type, i); - if (name.empty()) break; - Program* prog = programStorage->GetOrAddProgram(i); + Program* prog = programStorage->AddProgram(); programStorage->ReadProgram(prog, InjectLevelPathsForCurrentLevel(name)); prog->readOnly = true; prog->filename = name; diff --git a/src/object/motion/motiontoto.cpp b/src/object/motion/motiontoto.cpp index 18db7471..7f1a608b 100644 --- a/src/object/motion/motiontoto.cpp +++ b/src/object/motion/motiontoto.cpp @@ -57,7 +57,6 @@ CMotionToto::CMotionToto(COldObject* object) : CMotion(object) m_blinkTime = 0.0f; m_blinkProgress = -1.0f; m_lastMotorParticle = 0.0f; - m_type = OBJECT_NULL; m_mousePos = Math::Point(0.0f, 0.0f); } @@ -325,36 +324,39 @@ bool CMotionToto::EventFrame(const Event &event) distance = 30.0f-progress*18.0f; // remoteness shift = 18.0f-progress*11.0f; // shift is left verti = 10.0f-progress* 8.0f; // shift at the top + + CObject* selected = m_main->GetSelect(); + ObjectType type = selected != nullptr ? selected->GetType() : OBJECT_NULL; if ( m_actionType == -1 && - (m_type == OBJECT_HUMAN || - m_type == OBJECT_TECH || - m_type == OBJECT_MOBILEwa || - m_type == OBJECT_MOBILEta || - m_type == OBJECT_MOBILEfa || - m_type == OBJECT_MOBILEia || - m_type == OBJECT_MOBILEwc || - m_type == OBJECT_MOBILEtc || - m_type == OBJECT_MOBILEfc || - m_type == OBJECT_MOBILEic || - m_type == OBJECT_MOBILEwi || - m_type == OBJECT_MOBILEti || - m_type == OBJECT_MOBILEfi || - m_type == OBJECT_MOBILEii || - m_type == OBJECT_MOBILEws || - m_type == OBJECT_MOBILEts || - m_type == OBJECT_MOBILEfs || - m_type == OBJECT_MOBILEis || - m_type == OBJECT_MOBILErt || - m_type == OBJECT_MOBILErc || - m_type == OBJECT_MOBILErr || - m_type == OBJECT_MOBILErs || - m_type == OBJECT_MOBILEsa || - m_type == OBJECT_MOBILEwt || - m_type == OBJECT_MOBILEtt || - m_type == OBJECT_MOBILEft || - m_type == OBJECT_MOBILEit || - m_type == OBJECT_MOBILEdr ) ) // vehicle? + (type == OBJECT_HUMAN || + type == OBJECT_TECH || + type == OBJECT_MOBILEwa || + type == OBJECT_MOBILEta || + type == OBJECT_MOBILEfa || + type == OBJECT_MOBILEia || + type == OBJECT_MOBILEwc || + type == OBJECT_MOBILEtc || + type == OBJECT_MOBILEfc || + type == OBJECT_MOBILEic || + type == OBJECT_MOBILEwi || + type == OBJECT_MOBILEti || + type == OBJECT_MOBILEfi || + type == OBJECT_MOBILEii || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEts || + type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEis || + type == OBJECT_MOBILErt || + type == OBJECT_MOBILErc || + type == OBJECT_MOBILErr || + type == OBJECT_MOBILErs || + type == OBJECT_MOBILEsa || + type == OBJECT_MOBILEwt || + type == OBJECT_MOBILEtt || + type == OBJECT_MOBILEft || + type == OBJECT_MOBILEit || + type == OBJECT_MOBILEdr ) ) // vehicle? { m_clownTime += event.rTime; if ( m_clownTime >= m_clownDelay ) @@ -832,10 +834,3 @@ Error CMotionToto::SetAction(int action, float time) return ERR_OK; } - -// Specifies the type of the object is attached to toto. - -void CMotionToto::SetLinkType(ObjectType type) -{ - m_type = type; -} diff --git a/src/object/motion/motiontoto.h b/src/object/motion/motiontoto.h index 1e97c03a..fe907308 100644 --- a/src/object/motion/motiontoto.h +++ b/src/object/motion/motiontoto.h @@ -43,7 +43,6 @@ public: void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager) override; bool EventProcess(const Event &event) override; Error SetAction(int action, float time=0.2f) override; - void SetLinkType(ObjectType type); void StartDisplayInfo(); void StopDisplayInfo(); @@ -65,6 +64,5 @@ protected: float m_blinkTime; float m_blinkProgress; int m_soundChannel; - ObjectType m_type; Math::Point m_mousePos; }; diff --git a/src/object/object_type.h b/src/object/object_type.h index 7467ff3e..11d5763d 100644 --- a/src/object/object_type.h +++ b/src/object/object_type.h @@ -33,203 +33,203 @@ enum ObjectType { OBJECT_NULL = 0, - OBJECT_PORTICO = 2, //! < Portico - OBJECT_BASE = 3, //! < SpaceShip - OBJECT_DERRICK = 4, //! < Derrick - OBJECT_FACTORY = 5, //! < BotFactory - OBJECT_STATION = 6, //! < PowerStation - OBJECT_CONVERT = 7, //! < Converter - OBJECT_REPAIR = 8, //! < RepairStation - OBJECT_TOWER = 9, //! < DefenseTower - OBJECT_NEST = 10, //! < AlienNest - OBJECT_RESEARCH = 11, //! < ResearchCenter - OBJECT_RADAR = 12, //! < RadarStation - OBJECT_ENERGY = 13, //! < PowerPlant - OBJECT_LABO = 14, //! < AutoLab - OBJECT_NUCLEAR = 15, //! < NuclearPlant - OBJECT_START = 16, //! < StartArea - OBJECT_END = 17, //! < EndArea - OBJECT_INFO = 18, //! < ExchangePost - OBJECT_PARA = 19, //! < PowerCaptor - OBJECT_TARGET1 = 20, //! < Target1 (gate) - OBJECT_TARGET2 = 21, //! < Target2 (center) - OBJECT_SAFE = 22, //! < Vault - OBJECT_HUSTON = 23, //! < Houston - OBJECT_DESTROYER = 24, //! < Destroyer - OBJECT_STONE = 31, //! < TitaniumOre - OBJECT_URANIUM = 32, //! < UraniumOre - OBJECT_METAL = 33, //! < Titanium - OBJECT_POWER = 34, //! < PowerCell - OBJECT_ATOMIC = 35, //! < NuclearCell - OBJECT_BULLET = 36, //! < OrgaMatter - OBJECT_BBOX = 37, //! < BlackBox - OBJECT_TNT = 38, //! < TNT - OBJECT_MARKPOWER = 50, //! < PowerSpot - OBJECT_MARKSTONE = 51, //! < TitaniumSpot - OBJECT_MARKURANIUM = 52, //! < UraniumSpot - OBJECT_MARKKEYa = 53, //! < KeyASpot - OBJECT_MARKKEYb = 54, //! < KeyBSpot - OBJECT_MARKKEYc = 55, //! < KeyCSpot - OBJECT_MARKKEYd = 56, //! < KeyDSpot - OBJECT_BOMB = 60, //! < Mine - OBJECT_WINFIRE = 61, //! < Firework - OBJECT_SHOW = 62, //! < arrow above object (Visit) - OBJECT_BAG = 63, //! < Bag - OBJECT_PLANT0 = 70, //! < Greenery0 - OBJECT_PLANT1 = 71, //! < Greenery1 - OBJECT_PLANT2 = 72, //! < Greenery2 - OBJECT_PLANT3 = 73, //! < Greenery3 - OBJECT_PLANT4 = 74, //! < Greenery4 - OBJECT_PLANT5 = 75, //! < Greenery5 - OBJECT_PLANT6 = 76, //! < Greenery6 - OBJECT_PLANT7 = 77, //! < Greenery7 - OBJECT_PLANT8 = 78, //! < Greenery8 - OBJECT_PLANT9 = 79, //! < Greenery9 - OBJECT_PLANT10 = 80, //! < Greenery10 - OBJECT_PLANT11 = 81, //! < Greenery11 - OBJECT_PLANT12 = 82, //! < Greenery12 - OBJECT_PLANT13 = 83, //! < Greenery13 - OBJECT_PLANT14 = 84, //! < Greenery14 - OBJECT_PLANT15 = 85, //! < Greenery15 - OBJECT_PLANT16 = 86, //! < Greenery16 - OBJECT_PLANT17 = 87, //! < Greenery17 - OBJECT_PLANT18 = 88, //! < Greenery18 - OBJECT_PLANT19 = 89, //! < Greenery19 - OBJECT_TREE0 = 90, //! < Tree0 - OBJECT_TREE1 = 91, //! < Tree1 - OBJECT_TREE2 = 92, //! < Tree2 - OBJECT_TREE3 = 93, //! < Tree3 - OBJECT_TREE4 = 94, //! < Tree4 - OBJECT_TREE5 = 95, //! < Tree5 - OBJECT_MOBILEwt = 100, //! < PracticeBot - OBJECT_MOBILEtt = 101, //! < track-trainer (unused) - OBJECT_MOBILEft = 102, //! < fly-trainer (unused) - OBJECT_MOBILEit = 103, //! < insect-trainer (unused) - OBJECT_MOBILEwa = 110, //! < WheeledGrabber - OBJECT_MOBILEta = 111, //! < TrackedGrabber - OBJECT_MOBILEfa = 112, //! < WingedGrabber - OBJECT_MOBILEia = 113, //! < LeggedGrabber - OBJECT_MOBILEwc = 120, //! < WheeledShooter - OBJECT_MOBILEtc = 121, //! < TrackedShooter - OBJECT_MOBILEfc = 122, //! < WingedShooter - OBJECT_MOBILEic = 123, //! < LeggedShooter - OBJECT_MOBILEwi = 130, //! < WheeledOrgaShooter - OBJECT_MOBILEti = 131, //! < TrackedOrgaShooter - OBJECT_MOBILEfi = 132, //! < WingedOrgaShooter - OBJECT_MOBILEii = 133, //! < LeggedOrgaShooter - OBJECT_MOBILEws = 140, //! < WheeledSniffer - OBJECT_MOBILEts = 141, //! < TrackedSniffer - OBJECT_MOBILEfs = 142, //! < WingedSniffer - OBJECT_MOBILEis = 143, //! < LeggedSniffer - OBJECT_MOBILErt = 200, //! < Thumper - OBJECT_MOBILErc = 201, //! < PhazerShooter - OBJECT_MOBILErr = 202, //! < Recycler - OBJECT_MOBILErs = 203, //! < Shielder - OBJECT_MOBILEsa = 210, //! < Subber - OBJECT_MOBILEtg = 211, //! < TargetBot - OBJECT_MOBILEdr = 212, //! < Scribbler - OBJECT_CONTROLLER = 213, //! < MissionController - OBJECT_WAYPOINT = 250, //! < WayPoint - OBJECT_FLAGb = 260, //! < BlueFlag - OBJECT_FLAGr = 261, //! < RedFlag - OBJECT_FLAGg = 262, //! < GreenFlag - OBJECT_FLAGy = 263, //! < YellowFlag - OBJECT_FLAGv = 264, //! < VioletFlag - OBJECT_KEYa = 270, //! < KeyA - OBJECT_KEYb = 271, //! < KeyB - OBJECT_KEYc = 272, //! < KeyC - OBJECT_KEYd = 273, //! < KeyD - OBJECT_HUMAN = 300, //! < Me - OBJECT_TOTO = 301, //! < Robby (toto) - OBJECT_TECH = 302, //! < Tech - OBJECT_BARRIER0 = 400, //! < Barrier0 - OBJECT_BARRIER1 = 401, //! < Barrier1 - OBJECT_BARRIER2 = 402, //! < Barrier2 - OBJECT_BARRIER3 = 403, //! < Barrier3 - OBJECT_MOTHER = 500, //! < AlienQueen - OBJECT_EGG = 501, //! < AlienEgg - OBJECT_ANT = 502, //! < AlienAnt - OBJECT_SPIDER = 503, //! < AlienSpider - OBJECT_BEE = 504, //! < AlienWasp - OBJECT_WORM = 505, //! < AlienWorm - OBJECT_RUINmobilew1 = 600, //! < WreckBotw1 - OBJECT_RUINmobilew2 = 601, //! < WreckBotw2 - OBJECT_RUINmobilet1 = 602, //! < WreckBott1 - OBJECT_RUINmobilet2 = 603, //! < WreckBott2 - OBJECT_RUINmobiler1 = 604, //! < WreckBotr1 - OBJECT_RUINmobiler2 = 605, //! < WreckBotr2 - OBJECT_RUINfactory = 606, //! < RuinBotFactory - OBJECT_RUINdoor = 607, //! < RuinDoor - OBJECT_RUINsupport = 608, //! < RuinSupport - OBJECT_RUINradar = 609, //! < RuinRadar - OBJECT_RUINconvert = 610, //! < RuinConvert - OBJECT_RUINbase = 611, //! < RuinBaseCamp - OBJECT_RUINhead = 612, //! < RuinHeadCamp - OBJECT_TEEN0 = 620, //! < Teen0 - OBJECT_TEEN1 = 621, //! < Teen1 - OBJECT_TEEN2 = 622, //! < Teen2 - OBJECT_TEEN3 = 623, //! < Teen3 - OBJECT_TEEN4 = 624, //! < Teen4 - OBJECT_TEEN5 = 625, //! < Teen5 - OBJECT_TEEN6 = 626, //! < Teen6 - OBJECT_TEEN7 = 627, //! < Teen7 - OBJECT_TEEN8 = 628, //! < Teen8 - OBJECT_TEEN9 = 629, //! < Teen9 - OBJECT_TEEN10 = 630, //! < Teen10 - OBJECT_TEEN11 = 631, //! < Teen11 - OBJECT_TEEN12 = 632, //! < Teen12 - OBJECT_TEEN13 = 633, //! < Teen13 - OBJECT_TEEN14 = 634, //! < Teen14 - OBJECT_TEEN15 = 635, //! < Teen15 - OBJECT_TEEN16 = 636, //! < Teen16 - OBJECT_TEEN17 = 637, //! < Teen17 - OBJECT_TEEN18 = 638, //! < Teen18 - OBJECT_TEEN19 = 639, //! < Teen19 - OBJECT_TEEN20 = 640, //! < Teen20 - OBJECT_TEEN21 = 641, //! < Teen21 - OBJECT_TEEN22 = 642, //! < Teen22 - OBJECT_TEEN23 = 643, //! < Teen23 - OBJECT_TEEN24 = 644, //! < Teen24 - OBJECT_TEEN25 = 645, //! < Teen25 - OBJECT_TEEN26 = 646, //! < Teen26 - OBJECT_TEEN27 = 647, //! < Teen27 - OBJECT_TEEN28 = 648, //! < Teen28 - OBJECT_TEEN29 = 649, //! < Teen29 - OBJECT_TEEN30 = 650, //! < Teen30 - OBJECT_TEEN31 = 651, //! < Teen31 - OBJECT_TEEN32 = 652, //! < Teen32 - OBJECT_TEEN33 = 653, //! < Teen33 - OBJECT_TEEN34 = 654, //! < Stone (Teen34) - OBJECT_TEEN35 = 655, //! < Teen35 - OBJECT_TEEN36 = 656, //! < Teen36 - OBJECT_TEEN37 = 657, //! < Teen37 - OBJECT_TEEN38 = 658, //! < Teen38 - OBJECT_TEEN39 = 659, //! < Teen39 - OBJECT_TEEN40 = 660, //! < Teen40 - OBJECT_TEEN41 = 661, //! < Teen41 - OBJECT_TEEN42 = 662, //! < Teen42 - OBJECT_TEEN43 = 663, //! < Teen43 - OBJECT_TEEN44 = 664, //! < Teen44 - OBJECT_QUARTZ0 = 700, //! < Quartz0 - OBJECT_QUARTZ1 = 701, //! < Quartz1 - OBJECT_QUARTZ2 = 702, //! < Quartz2 - OBJECT_QUARTZ3 = 703, //! < Quartz3 - OBJECT_ROOT0 = 710, //! < MegaStalk0 - OBJECT_ROOT1 = 711, //! < MegaStalk1 - OBJECT_ROOT2 = 712, //! < MegaStalk2 - OBJECT_ROOT3 = 713, //! < MegaStalk3 - OBJECT_ROOT4 = 714, //! < MegaStalk4 - OBJECT_ROOT5 = 715, //! < MegaStalk5 - OBJECT_MUSHROOM1 = 731, //! < Mushroom1 - OBJECT_MUSHROOM2 = 732, //! < Mushroom2 - OBJECT_APOLLO1 = 900, //! < ApolloLEM - OBJECT_APOLLO2 = 901, //! < ApolloJeep - OBJECT_APOLLO3 = 902, //! < ApolloFlag - OBJECT_APOLLO4 = 903, //! < ApolloModule - OBJECT_APOLLO5 = 904, //! < ApolloAntenna - OBJECT_HOME1 = 910, //! < Home + OBJECT_PORTICO = 2, //!< Portico + OBJECT_BASE = 3, //!< SpaceShip + OBJECT_DERRICK = 4, //!< Derrick + OBJECT_FACTORY = 5, //!< BotFactory + OBJECT_STATION = 6, //!< PowerStation + OBJECT_CONVERT = 7, //!< Converter + OBJECT_REPAIR = 8, //!< RepairStation + OBJECT_TOWER = 9, //!< DefenseTower + OBJECT_NEST = 10, //!< AlienNest + OBJECT_RESEARCH = 11, //!< ResearchCenter + OBJECT_RADAR = 12, //!< RadarStation + OBJECT_ENERGY = 13, //!< PowerPlant + OBJECT_LABO = 14, //!< AutoLab + OBJECT_NUCLEAR = 15, //!< NuclearPlant + OBJECT_START = 16, //!< StartArea + OBJECT_END = 17, //!< EndArea + OBJECT_INFO = 18, //!< ExchangePost + OBJECT_PARA = 19, //!< PowerCaptor + OBJECT_TARGET1 = 20, //!< Target1 (gate) + OBJECT_TARGET2 = 21, //!< Target2 (center) + OBJECT_SAFE = 22, //!< Vault + OBJECT_HUSTON = 23, //!< Houston + OBJECT_DESTROYER = 24, //!< Destroyer + OBJECT_STONE = 31, //!< TitaniumOre + OBJECT_URANIUM = 32, //!< UraniumOre + OBJECT_METAL = 33, //!< Titanium + OBJECT_POWER = 34, //!< PowerCell + OBJECT_ATOMIC = 35, //!< NuclearCell + OBJECT_BULLET = 36, //!< OrgaMatter + OBJECT_BBOX = 37, //!< BlackBox + OBJECT_TNT = 38, //!< TNT + OBJECT_MARKPOWER = 50, //!< PowerSpot + OBJECT_MARKSTONE = 51, //!< TitaniumSpot + OBJECT_MARKURANIUM = 52, //!< UraniumSpot + OBJECT_MARKKEYa = 53, //!< KeyASpot + OBJECT_MARKKEYb = 54, //!< KeyBSpot + OBJECT_MARKKEYc = 55, //!< KeyCSpot + OBJECT_MARKKEYd = 56, //!< KeyDSpot + OBJECT_BOMB = 60, //!< Mine + OBJECT_WINFIRE = 61, //!< Firework + OBJECT_SHOW = 62, //!< arrow above object (Visit) + OBJECT_BAG = 63, //!< Bag + OBJECT_PLANT0 = 70, //!< Greenery0 + OBJECT_PLANT1 = 71, //!< Greenery1 + OBJECT_PLANT2 = 72, //!< Greenery2 + OBJECT_PLANT3 = 73, //!< Greenery3 + OBJECT_PLANT4 = 74, //!< Greenery4 + OBJECT_PLANT5 = 75, //!< Greenery5 + OBJECT_PLANT6 = 76, //!< Greenery6 + OBJECT_PLANT7 = 77, //!< Greenery7 + OBJECT_PLANT8 = 78, //!< Greenery8 + OBJECT_PLANT9 = 79, //!< Greenery9 + OBJECT_PLANT10 = 80, //!< Greenery10 + OBJECT_PLANT11 = 81, //!< Greenery11 + OBJECT_PLANT12 = 82, //!< Greenery12 + OBJECT_PLANT13 = 83, //!< Greenery13 + OBJECT_PLANT14 = 84, //!< Greenery14 + OBJECT_PLANT15 = 85, //!< Greenery15 + OBJECT_PLANT16 = 86, //!< Greenery16 + OBJECT_PLANT17 = 87, //!< Greenery17 + OBJECT_PLANT18 = 88, //!< Greenery18 + OBJECT_PLANT19 = 89, //!< Greenery19 + OBJECT_TREE0 = 90, //!< Tree0 + OBJECT_TREE1 = 91, //!< Tree1 + OBJECT_TREE2 = 92, //!< Tree2 + OBJECT_TREE3 = 93, //!< Tree3 + OBJECT_TREE4 = 94, //!< Tree4 + OBJECT_TREE5 = 95, //!< Tree5 + OBJECT_MOBILEwt = 100, //!< PracticeBot + OBJECT_MOBILEtt = 101, //!< track-trainer (unused) + OBJECT_MOBILEft = 102, //!< fly-trainer (unused) + OBJECT_MOBILEit = 103, //!< insect-trainer (unused) + OBJECT_MOBILEwa = 110, //!< WheeledGrabber + OBJECT_MOBILEta = 111, //!< TrackedGrabber + OBJECT_MOBILEfa = 112, //!< WingedGrabber + OBJECT_MOBILEia = 113, //!< LeggedGrabber + OBJECT_MOBILEwc = 120, //!< WheeledShooter + OBJECT_MOBILEtc = 121, //!< TrackedShooter + OBJECT_MOBILEfc = 122, //!< WingedShooter + OBJECT_MOBILEic = 123, //!< LeggedShooter + OBJECT_MOBILEwi = 130, //!< WheeledOrgaShooter + OBJECT_MOBILEti = 131, //!< TrackedOrgaShooter + OBJECT_MOBILEfi = 132, //!< WingedOrgaShooter + OBJECT_MOBILEii = 133, //!< LeggedOrgaShooter + OBJECT_MOBILEws = 140, //!< WheeledSniffer + OBJECT_MOBILEts = 141, //!< TrackedSniffer + OBJECT_MOBILEfs = 142, //!< WingedSniffer + OBJECT_MOBILEis = 143, //!< LeggedSniffer + OBJECT_MOBILErt = 200, //!< Thumper + OBJECT_MOBILErc = 201, //!< PhazerShooter + OBJECT_MOBILErr = 202, //!< Recycler + OBJECT_MOBILErs = 203, //!< Shielder + OBJECT_MOBILEsa = 210, //!< Subber + OBJECT_MOBILEtg = 211, //!< TargetBot + OBJECT_MOBILEdr = 212, //!< Scribbler + OBJECT_CONTROLLER = 213, //!< MissionController + OBJECT_WAYPOINT = 250, //!< WayPoint + OBJECT_FLAGb = 260, //!< BlueFlag + OBJECT_FLAGr = 261, //!< RedFlag + OBJECT_FLAGg = 262, //!< GreenFlag + OBJECT_FLAGy = 263, //!< YellowFlag + OBJECT_FLAGv = 264, //!< VioletFlag + OBJECT_KEYa = 270, //!< KeyA + OBJECT_KEYb = 271, //!< KeyB + OBJECT_KEYc = 272, //!< KeyC + OBJECT_KEYd = 273, //!< KeyD + OBJECT_HUMAN = 300, //!< Me + OBJECT_TOTO = 301, //!< Robby (toto) + OBJECT_TECH = 302, //!< Tech + OBJECT_BARRIER0 = 400, //!< Barrier0 + OBJECT_BARRIER1 = 401, //!< Barrier1 + OBJECT_BARRIER2 = 402, //!< Barrier2 + OBJECT_BARRIER3 = 403, //!< Barrier3 + OBJECT_MOTHER = 500, //!< AlienQueen + OBJECT_EGG = 501, //!< AlienEgg + OBJECT_ANT = 502, //!< AlienAnt + OBJECT_SPIDER = 503, //!< AlienSpider + OBJECT_BEE = 504, //!< AlienWasp + OBJECT_WORM = 505, //!< AlienWorm + OBJECT_RUINmobilew1 = 600, //!< WreckBotw1 + OBJECT_RUINmobilew2 = 601, //!< WreckBotw2 + OBJECT_RUINmobilet1 = 602, //!< WreckBott1 + OBJECT_RUINmobilet2 = 603, //!< WreckBott2 + OBJECT_RUINmobiler1 = 604, //!< WreckBotr1 + OBJECT_RUINmobiler2 = 605, //!< WreckBotr2 + OBJECT_RUINfactory = 606, //!< RuinBotFactory + OBJECT_RUINdoor = 607, //!< RuinDoor + OBJECT_RUINsupport = 608, //!< RuinSupport + OBJECT_RUINradar = 609, //!< RuinRadar + OBJECT_RUINconvert = 610, //!< RuinConvert + OBJECT_RUINbase = 611, //!< RuinBaseCamp + OBJECT_RUINhead = 612, //!< RuinHeadCamp + OBJECT_TEEN0 = 620, //!< Teen0 + OBJECT_TEEN1 = 621, //!< Teen1 + OBJECT_TEEN2 = 622, //!< Teen2 + OBJECT_TEEN3 = 623, //!< Teen3 + OBJECT_TEEN4 = 624, //!< Teen4 + OBJECT_TEEN5 = 625, //!< Teen5 + OBJECT_TEEN6 = 626, //!< Teen6 + OBJECT_TEEN7 = 627, //!< Teen7 + OBJECT_TEEN8 = 628, //!< Teen8 + OBJECT_TEEN9 = 629, //!< Teen9 + OBJECT_TEEN10 = 630, //!< Teen10 + OBJECT_TEEN11 = 631, //!< Teen11 + OBJECT_TEEN12 = 632, //!< Teen12 + OBJECT_TEEN13 = 633, //!< Teen13 + OBJECT_TEEN14 = 634, //!< Teen14 + OBJECT_TEEN15 = 635, //!< Teen15 + OBJECT_TEEN16 = 636, //!< Teen16 + OBJECT_TEEN17 = 637, //!< Teen17 + OBJECT_TEEN18 = 638, //!< Teen18 + OBJECT_TEEN19 = 639, //!< Teen19 + OBJECT_TEEN20 = 640, //!< Teen20 + OBJECT_TEEN21 = 641, //!< Teen21 + OBJECT_TEEN22 = 642, //!< Teen22 + OBJECT_TEEN23 = 643, //!< Teen23 + OBJECT_TEEN24 = 644, //!< Teen24 + OBJECT_TEEN25 = 645, //!< Teen25 + OBJECT_TEEN26 = 646, //!< Teen26 + OBJECT_TEEN27 = 647, //!< Teen27 + OBJECT_TEEN28 = 648, //!< Teen28 + OBJECT_TEEN29 = 649, //!< Teen29 + OBJECT_TEEN30 = 650, //!< Teen30 + OBJECT_TEEN31 = 651, //!< Teen31 + OBJECT_TEEN32 = 652, //!< Teen32 + OBJECT_TEEN33 = 653, //!< Teen33 + OBJECT_TEEN34 = 654, //!< Stone (Teen34) + OBJECT_TEEN35 = 655, //!< Teen35 + OBJECT_TEEN36 = 656, //!< Teen36 + OBJECT_TEEN37 = 657, //!< Teen37 + OBJECT_TEEN38 = 658, //!< Teen38 + OBJECT_TEEN39 = 659, //!< Teen39 + OBJECT_TEEN40 = 660, //!< Teen40 + OBJECT_TEEN41 = 661, //!< Teen41 + OBJECT_TEEN42 = 662, //!< Teen42 + OBJECT_TEEN43 = 663, //!< Teen43 + OBJECT_TEEN44 = 664, //!< Teen44 + OBJECT_QUARTZ0 = 700, //!< Quartz0 + OBJECT_QUARTZ1 = 701, //!< Quartz1 + OBJECT_QUARTZ2 = 702, //!< Quartz2 + OBJECT_QUARTZ3 = 703, //!< Quartz3 + OBJECT_ROOT0 = 710, //!< MegaStalk0 + OBJECT_ROOT1 = 711, //!< MegaStalk1 + OBJECT_ROOT2 = 712, //!< MegaStalk2 + OBJECT_ROOT3 = 713, //!< MegaStalk3 + OBJECT_ROOT4 = 714, //!< MegaStalk4 + OBJECT_ROOT5 = 715, //!< MegaStalk5 + OBJECT_MUSHROOM1 = 731, //!< Mushroom1 + OBJECT_MUSHROOM2 = 732, //!< Mushroom2 + OBJECT_APOLLO1 = 900, //!< ApolloLEM + OBJECT_APOLLO2 = 901, //!< ApolloJeep + OBJECT_APOLLO3 = 902, //!< ApolloFlag + OBJECT_APOLLO4 = 903, //!< ApolloModule + OBJECT_APOLLO5 = 904, //!< ApolloAntenna + OBJECT_HOME1 = 910, //!< Home - OBJECT_MAX = 1000 //! < number of values + OBJECT_MAX = 1000 //!< number of values }; struct ObjectTypeHash diff --git a/src/ui/mainshort.cpp b/src/ui/mainshort.cpp index 0ec5f8a5..d9fffa26 100644 --- a/src/ui/mainshort.cpp +++ b/src/ui/mainshort.cpp @@ -280,9 +280,9 @@ void CMainShort::SelectNext() CObject* pPrev = m_main->DeselectAll(); - if(m_shortcuts.size() == 0) + if (m_shortcuts.size() == 0) { - m_main->SelectHuman(); + m_main->SelectObject(m_main->SearchHuman()); return; } From 7bb3245092e574d88a32cd6764ad1b4fa263c634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Sun, 1 Jan 2017 17:16:54 +0100 Subject: [PATCH 35/93] Optimizations and changes in OpenGL 3.3 device. * Limited number of lights to 4 * Only directional lights * Per-pixel lighting * Improved dynamic shadows a bit * Optimized texture changes --- src/graphics/opengl/gl33device.cpp | 184 ++++++++++-------- src/graphics/opengl/gl33device.h | 12 +- src/graphics/opengl/glutil.h | 2 + .../opengl/shaders/gl33/fs_normal.glsl | 70 ++++++- .../opengl/shaders/gl33/vs_normal.glsl | 72 +------ 5 files changed, 177 insertions(+), 163 deletions(-) diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp index 3ea93e45..74853713 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl/gl33device.cpp @@ -233,7 +233,7 @@ bool CGL33Device::Create() glViewport(0, 0, m_config.size.x, m_config.size.y); // this is set in shader - m_capabilities.maxLights = 8; + m_capabilities.maxLights = 4; m_lights = std::vector(m_capabilities.maxLights, Light()); m_lightsEnabled = std::vector(m_capabilities.maxLights, false); @@ -381,14 +381,14 @@ bool CGL33Device::Create() uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor"); - uni.lightingEnabled = glGetUniformLocation(m_normalProgram, "uni_LightingEnabled"); + uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount"); uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_AmbientColor"); uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_DiffuseColor"); uni.specularColor = glGetUniformLocation(m_normalProgram, "uni_SpecularColor"); GLchar name[64]; - for (int i = 0; i < 8; i++) + for (int i = 0; i < m_capabilities.maxLights; i++) { LightLocations &light = uni.lights[i]; @@ -440,12 +440,9 @@ bool CGL33Device::Create() glUniform1f(uni.shadowColor, 0.5f); glUniform1i(uni.alphaTestEnabled, 0); - glUniform1f(uni.alphaReference, 1.0f); + glUniform1f(uni.alphaReference, 0.5f); - glUniform1i(uni.lightingEnabled, 0); - - for (int i = 0; i < 8; i++) - glUniform1i(uni.lights[i].enabled, 0); + glUniform1i(uni.lightCount, 0); } // Obtain uniform locations for interface program @@ -637,7 +634,9 @@ void CGL33Device::SetRenderMode(RenderMode mode) m_uni = &m_uniforms[m_mode]; - UpdateRenderingMode(); + UpdateTextureState(0); + UpdateTextureState(1); + UpdateTextureState(2); } void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix) @@ -708,23 +707,7 @@ void CGL33Device::SetLight(int index, const Light &light) m_lights[index] = light; - LightLocations &uni = m_uni->lights[index]; - - glUniform4fv(uni.ambient, 1, light.ambient.Array()); - glUniform4fv(uni.diffuse, 1, light.diffuse.Array()); - glUniform4fv(uni.specular, 1, light.specular.Array()); - glUniform3f(uni.attenuation, light.attenuation0, light.attenuation1, light.attenuation2); - - if (light.type == LIGHT_DIRECTIONAL) - { - glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f); - } - else - { - glUniform4f(uni.position, light.position.x, light.position.y, light.position.z, 1.0f); - } - - // TODO: add spotlight params + m_updateLights = true; } void CGL33Device::SetLightEnabled(int index, bool enabled) @@ -734,7 +717,7 @@ void CGL33Device::SetLightEnabled(int index, bool enabled) m_lightsEnabled[index] = enabled; - glUniform1i(m_uni->lights[index].enabled, enabled ? 1 : 0); + m_updateLights = true; } /** If image is invalid, returns invalid texture. @@ -769,10 +752,9 @@ Texture CGL33Device::CreateTexture(ImageData *data, const TextureCreateParams &p result.originalSize = result.size; - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &result.id); - glBindTexture(GL_TEXTURE_2D, result.id); + + BindTexture(m_freeTexture, result.id); // Set texture parameters GLint minF = GL_NEAREST, magF = GL_NEAREST; @@ -835,9 +817,6 @@ Texture CGL33Device::CreateTexture(ImageData *data, const TextureCreateParams &p m_allTextures.insert(result); - // Restore the previous state of 1st stage - glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); - return result; } @@ -849,10 +828,9 @@ Texture CGL33Device::CreateDepthTexture(int width, int height, int depth) result.size.x = width; result.size.y = height; - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &result.id); - glBindTexture(GL_TEXTURE_2D, result.id); + + BindTexture(m_freeTexture, result.id); GLuint format = GL_DEPTH_COMPONENT; @@ -881,16 +859,14 @@ Texture CGL33Device::CreateDepthTexture(int width, int height, int depth) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); - glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); - return result; } void CGL33Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format) { - glActiveTexture(GL_TEXTURE0); + if (texture.id == 0) return; - glBindTexture(GL_TEXTURE_2D, texture.id); + BindTexture(m_freeTexture, texture.id); PreparedTextureData texData = PrepareTextureData(data, format); @@ -945,18 +921,16 @@ void CGL33Device::SetTexture(int index, const Texture &texture) { assert(index >= 0 && index < static_cast( m_currentTextures.size() )); - bool same = m_currentTextures[index].id == texture.id; + if (m_currentTextures[index].id == texture.id) + return; + + BindTexture(index, texture.id); m_currentTextures[index] = texture; // remember the new value - if (same) - return; // nothing to do - - glActiveTexture(GL_TEXTURE0 + index); - glBindTexture(GL_TEXTURE_2D, texture.id); - // Params need to be updated for the new bound texture UpdateTextureParams(index); + UpdateTextureState(index); } void CGL33Device::SetTexture(int index, unsigned int textureId) @@ -966,27 +940,25 @@ void CGL33Device::SetTexture(int index, unsigned int textureId) if (m_currentTextures[index].id == textureId) return; // nothing to do - m_currentTextures[index].id = textureId; + BindTexture(index, textureId); - glActiveTexture(GL_TEXTURE0 + index); - glBindTexture(GL_TEXTURE_2D, textureId); + m_currentTextures[index].id = textureId; // Params need to be updated for the new bound texture UpdateTextureParams(index); + UpdateTextureState(index); } void CGL33Device::SetTextureEnabled(int index, bool enabled) { assert(index >= 0 && index < static_cast( m_currentTextures.size() )); - bool same = m_texturesEnabled[index] == enabled; + if (m_texturesEnabled[index] == enabled) + return; m_texturesEnabled[index] = enabled; - if (same) - return; // nothing to do - - UpdateRenderingMode(); + UpdateTextureState(index); } /** @@ -1065,6 +1037,8 @@ void CGL33Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode void CGL33Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, Color color) { + if (m_updateLights) UpdateLights(); + Vertex* vs = const_cast(vertices); unsigned int size = vertexCount * sizeof(Vertex); @@ -1099,13 +1073,13 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int glDisableVertexAttribArray(4); glVertexAttrib2f(4, 0.0f, 0.0f); - UpdateRenderingMode(); - glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); } void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, Color color) { + if (m_updateLights) UpdateLights(); + VertexTex2* vs = const_cast(vertices); unsigned int size = vertexCount * sizeof(VertexTex2); @@ -1141,13 +1115,13 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), reinterpret_cast(offset + offsetof(VertexTex2, texCoord2))); - UpdateRenderingMode(); - glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); } void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) { + if (m_updateLights) UpdateLights(); + VertexCol* vs = const_cast(vertices); unsigned int size = vertexCount * sizeof(VertexCol); @@ -1181,14 +1155,14 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i glDisableVertexAttribArray(4); glVertexAttrib2f(4, 0.0f, 0.0f); - UpdateRenderingMode(); - glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); } void CGL33Device::DrawPrimitive(PrimitiveType type, const void *vertices, int size, const VertexFormat &format, int vertexCount) { + if (m_updateLights) UpdateLights(); + DynamicBuffer& buffer = m_dynamicBuffer; BindVAO(buffer.vao); @@ -1203,14 +1177,14 @@ void CGL33Device::DrawPrimitive(PrimitiveType type, const void *vertices, UpdateVertexAttribute(3, format.tex1, offset); UpdateVertexAttribute(4, format.tex2, offset); - UpdateRenderingMode(); - glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); } void CGL33Device::DrawPrimitives(PrimitiveType type, const void *vertices, int size, const VertexFormat &format, int first[], int count[], int drawCount) { + if (m_updateLights) UpdateLights(); + DynamicBuffer& buffer = m_dynamicBuffer; BindVAO(buffer.vao); @@ -1225,14 +1199,14 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const void *vertices, UpdateVertexAttribute(3, format.tex1, offset); UpdateVertexAttribute(4, format.tex2, offset); - UpdateRenderingMode(); - glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); } void CGL33Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, int first[], int count[], int drawCount, Color color) { + if (m_updateLights) UpdateLights(); + Vertex* vs = const_cast(vertices); int vertexCount = 0; @@ -1277,14 +1251,14 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, glDisableVertexAttribArray(4); glVertexAttrib2f(4, 0.0f, 0.0f); - UpdateRenderingMode(); - glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); } void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, int first[], int count[], int drawCount, Color color) { + if (m_updateLights) UpdateLights(); + VertexTex2* vs = const_cast(vertices); int vertexCount = 0; @@ -1330,14 +1304,14 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(VertexTex2), reinterpret_cast(offset + offsetof(VertexTex2, texCoord2))); - UpdateRenderingMode(); - glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); } void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, int first[], int count[], int drawCount) { + if (m_updateLights) UpdateLights(); + VertexCol* vs = const_cast(vertices); int vertexCount = 0; @@ -1381,8 +1355,6 @@ void CGL33Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, glDisableVertexAttribArray(4); glVertexAttrib2f(4, 0.0f, 0.0f); - UpdateRenderingMode(); - glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); } @@ -1701,14 +1673,14 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit void CGL33Device::DrawStaticBuffer(unsigned int bufferId) { + if (m_updateLights) UpdateLights(); + auto it = m_vboObjects.find(bufferId); if (it == m_vboObjects.end()) return; VertexBufferInfo &info = (*it).second; - UpdateRenderingMode(); - BindVAO(info.vao); GLenum mode = TranslateGfxPrimitive(info.primitiveType); @@ -1836,7 +1808,9 @@ void CGL33Device::SetRenderState(RenderState state, bool enabled) { m_lighting = enabled; - glUniform1i(m_uni->lightingEnabled, enabled ? 1 : 0); + m_updateLights = true; + + //glUniform1i(m_uni->lightingEnabled, enabled ? 1 : 0); return; } @@ -1962,13 +1936,9 @@ void CGL33Device::CopyFramebufferToTexture(Texture& texture, int xOffset, int yO { if (texture.id == 0) return; - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture.id); + BindTexture(m_freeTexture, texture.id); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height); - - // Restore previous texture - glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); } std::unique_ptr CGL33Device::GetFrameBufferPixels() const @@ -2014,16 +1984,52 @@ void CGL33Device::DeleteFramebuffer(std::string name) } } -void CGL33Device::UpdateRenderingMode() +inline void CGL33Device::UpdateTextureState(int index) { - bool enabled = m_texturesEnabled[0] && m_currentTextures[0].id != 0; - glUniform1i(m_uni->textureEnabled[0], enabled ? 1 : 0); + bool enabled = m_texturesEnabled[index] && (m_currentTextures[index].id != 0); + glUniform1i(m_uni->textureEnabled[index], enabled ? 1 : 0); +} - enabled = m_texturesEnabled[1] && m_currentTextures[1].id != 0; - glUniform1i(m_uni->textureEnabled[1], enabled ? 1 : 0); +void CGL33Device::UpdateLights() +{ + m_updateLights = false; - enabled = m_texturesEnabled[2] && m_currentTextures[2].id != 0; - glUniform1i(m_uni->textureEnabled[2], enabled ? 1 : 0); + // If not in normal rendering mode, return immediately + if (m_mode != 0) return; + + // Lighting enabled + if (m_lighting) + { + int index = 0; + + // Iterate all lights + for (unsigned int i = 0; i < m_lights.size(); i++) + { + // If disabled, ignore and continue + if (!m_lightsEnabled[i]) continue; + + // If not directional, ignore and continue + if (m_lights[i].type != LIGHT_DIRECTIONAL) continue; + + Light &light = m_lights[i]; + LightLocations &uni = m_uni->lights[index]; + + glUniform4fv(uni.ambient, 1, light.ambient.Array()); + glUniform4fv(uni.diffuse, 1, light.diffuse.Array()); + glUniform4fv(uni.specular, 1, light.specular.Array()); + + glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f); + + index++; + } + + glUniform1i(m_uni->lightCount, index); + } + // Lighting disabled + else + { + glUniform1i(m_uni->lightCount, 0); + } } inline void CGL33Device::BindVBO(GLuint vbo) @@ -2042,6 +2048,12 @@ inline void CGL33Device::BindVAO(GLuint vao) m_currentVAO = vao; } +inline void CGL33Device::BindTexture(int index, GLuint texture) +{ + glActiveTexture(GL_TEXTURE0 + index); + glBindTexture(GL_TEXTURE_2D, texture); +} + unsigned int CGL33Device::UploadVertexData(DynamicBuffer& buffer, const void* data, unsigned int size) { unsigned int nextOffset = buffer.offset + size; diff --git a/src/graphics/opengl/gl33device.h b/src/graphics/opengl/gl33device.h index dc17e98f..12764b6f 100644 --- a/src/graphics/opengl/gl33device.h +++ b/src/graphics/opengl/gl33device.h @@ -198,13 +198,17 @@ public: private: //! Updates the texture params for given texture stage void UpdateTextureParams(int index); - //! Updates rendering mode - void UpdateRenderingMode(); + //! Updates texture state + inline void UpdateTextureState(int index); + //! Update light parameters + void UpdateLights(); //! Binds VBO inline void BindVBO(GLuint vbo); //! Binds VAO inline void BindVAO(GLuint vao); + //! Binds texture + inline void BindTexture(int index, GLuint texture); //! Uploads data to dynamic buffer and returns offset to it unsigned int UploadVertexData(DynamicBuffer& buffer, const void* data, unsigned int size); @@ -233,6 +237,8 @@ private: //! Whether lighting is enabled bool m_lighting = false; + //! true means that light update is needed + bool m_updateLights = false; //! Current lights std::vector m_lights; //! Current lights enable status @@ -247,6 +253,8 @@ private: //! Set of all created textures std::set m_allTextures; + //! Free texture unit + const int m_freeTexture = 3; //! Type of vertex structure enum VertexType diff --git a/src/graphics/opengl/glutil.h b/src/graphics/opengl/glutil.h index 03450cad..4b66d50b 100644 --- a/src/graphics/opengl/glutil.h +++ b/src/graphics/opengl/glutil.h @@ -196,6 +196,8 @@ struct UniformLocations //! true enables lighting GLint lightingEnabled = -1; + // Number of enabled lights + GLint lightCount = -1; //! Ambient color GLint ambientColor = -1; //! Diffuse color diff --git a/src/graphics/opengl/shaders/gl33/fs_normal.glsl b/src/graphics/opengl/shaders/gl33/fs_normal.glsl index 200aadef..2827d7a2 100644 --- a/src/graphics/opengl/shaders/gl33/fs_normal.glsl +++ b/src/graphics/opengl/shaders/gl33/fs_normal.glsl @@ -20,6 +20,8 @@ // FRAGMENT SHADER - NORMAL MODE #version 330 core +#define CONFIG_QUALITY_SHADOWS 1 + uniform sampler2D uni_PrimaryTexture; uniform sampler2D uni_SecondaryTexture; uniform sampler2DShadow uni_ShadowTexture; @@ -37,11 +39,27 @@ uniform float uni_ShadowColor; uniform bool uni_AlphaTestEnabled; uniform float uni_AlphaReference; +struct LightParams +{ + vec4 Position; + vec4 Ambient; + vec4 Diffuse; + vec4 Specular; +}; + +uniform vec4 uni_AmbientColor; +uniform vec4 uni_DiffuseColor; +uniform vec4 uni_SpecularColor; + +uniform int uni_LightCount; +uniform LightParams uni_Light[4]; + in VertexData { vec4 Color; vec2 TexCoord0; vec2 TexCoord1; + vec3 Normal; vec4 ShadowCoord; vec4 LightColor; float Distance; @@ -53,6 +71,53 @@ void main() { vec4 color = data.Color; + if (uni_LightCount > 0) + { + vec4 ambient = vec4(0.0f); + vec4 diffuse = vec4(0.0f); + vec4 specular = vec4(0.0f); + + vec3 normal = normalize(data.Normal); + + for (int i = 0; i < uni_LightCount; i++) + { + vec3 lightDirection = uni_Light[i].Position.xyz; + + vec3 reflectDirection = -reflect(lightDirection, normal); + + ambient += uni_Light[i].Ambient; + diffuse += clamp(dot(normal, lightDirection), 0.0f, 1.0f) + * uni_Light[i].Diffuse; + specular += clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f) + * uni_Light[i].Specular; + } + + float shadow = 1.0f; + + if (uni_ShadowTextureEnabled) + { +#ifdef CONFIG_QUALITY_SHADOWS + float offset = 0.00025f; + + float value = (1.0f / 5.0f) * (texture(uni_ShadowTexture, data.ShadowCoord.xyz) + + texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3( offset, 0.0f, 0.0f)) + + texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3(-offset, 0.0f, 0.0f)) + + texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3( 0.0f, offset, 0.0f)) + + texture(uni_ShadowTexture, data.ShadowCoord.xyz + vec3( 0.0f, -offset, 0.0f))); + + shadow = mix(uni_ShadowColor, 1.0f, value); +#else + shadow = mix(uni_ShadowColor, 1.0f, texture(uni_ShadowTexture, data.ShadowCoord.xyz)); +#endif + } + + vec4 result = uni_AmbientColor * ambient + + uni_DiffuseColor * diffuse * shadow + + uni_SpecularColor * specular * shadow; + + color = vec4(min(vec3(1.0f), result.rgb), 1.0f); + } + if (uni_PrimaryTextureEnabled) { color = color * texture(uni_PrimaryTexture, data.TexCoord0); @@ -63,11 +128,6 @@ void main() color = color * texture(uni_SecondaryTexture, data.TexCoord1); } - if (uni_ShadowTextureEnabled) - { - color = color * mix(uni_ShadowColor, 1.0f, texture(uni_ShadowTexture, data.ShadowCoord.xyz)); - } - if (uni_FogEnabled) { float interpolate = (data.Distance - uni_FogRange.x) / (uni_FogRange.y - uni_FogRange.x); diff --git a/src/graphics/opengl/shaders/gl33/vs_normal.glsl b/src/graphics/opengl/shaders/gl33/vs_normal.glsl index 2c1b5bc6..aeed3c60 100644 --- a/src/graphics/opengl/shaders/gl33/vs_normal.glsl +++ b/src/graphics/opengl/shaders/gl33/vs_normal.glsl @@ -20,24 +20,6 @@ // VERTEX SHADER - NORMAL MODE #version 330 core -struct LightParams -{ - bool Enabled; - vec4 Position; - vec4 Ambient; - vec4 Diffuse; - vec4 Specular; - float Shininess; - vec3 Attenuation; -}; - -uniform vec4 uni_AmbientColor; -uniform vec4 uni_DiffuseColor; -uniform vec4 uni_SpecularColor; - -uniform bool uni_LightingEnabled; -uniform LightParams uni_Light[8]; - uniform mat4 uni_ProjectionMatrix; uniform mat4 uni_ViewMatrix; uniform mat4 uni_ModelMatrix; @@ -55,6 +37,7 @@ out VertexData vec4 Color; vec2 TexCoord0; vec2 TexCoord1; + vec3 Normal; vec4 ShadowCoord; vec4 LightColor; float Distance; @@ -70,58 +53,7 @@ void main() data.Color = in_Color; data.TexCoord0 = in_TexCoord0; data.TexCoord1 = in_TexCoord1; + data.Normal = normalize((uni_NormalMatrix * vec4(in_Normal, 0.0f)).xyz); data.ShadowCoord = vec4(shadowCoord.xyz / shadowCoord.w, 1.0f); data.Distance = abs(eyeSpace.z); - - vec4 color = in_Color; - - if (uni_LightingEnabled) - { - vec4 ambient = vec4(0.0f); - vec4 diffuse = vec4(0.0f); - vec4 specular = vec4(0.0f); - - vec3 normal = normalize((uni_NormalMatrix * vec4(in_Normal, 0.0f)).xyz); - - for(int i=0; i<8; i++) - { - if(uni_Light[i].Enabled) - { - vec3 lightDirection = vec3(0.0f); - float atten; - - // Directional light - if(uni_Light[i].Position[3] == 0.0f) - { - lightDirection = uni_Light[i].Position.xyz; - atten = 1.0f; - } - // Point light - else - { - vec3 lightDirection = normalize(uni_Light[i].Position.xyz - position.xyz); - float dist = distance(uni_Light[i].Position.xyz, position.xyz); - - atten = 1.0f / (uni_Light[i].Attenuation.x - + uni_Light[i].Attenuation.y * dist - + uni_Light[i].Attenuation.z * dist * dist); - } - - vec3 reflectDirection = -reflect(lightDirection, normal); - - ambient += uni_Light[i].Ambient; - diffuse += atten * clamp(dot(normal, lightDirection), 0.0f, 1.0f) * uni_Light[i].Diffuse; - specular += atten * clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f) * uni_Light[i].Specular; - } - } - - vec4 result = uni_AmbientColor * ambient - + uni_DiffuseColor * diffuse - + uni_SpecularColor * specular; - - color.rgb = min(vec3(1.0f), result.rgb); - color.a = 1.0f; //min(1.0f, 1.0f); - - data.Color = color; - } } From 7b3b257580b655a8c4958eca1daf6ab3d5193f28 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Mon, 2 Jan 2017 14:54:38 +0100 Subject: [PATCH 36/93] Fix code style --- src/object/motion/motiontoto.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/object/motion/motiontoto.cpp b/src/object/motion/motiontoto.cpp index 7f1a608b..c0a2296a 100644 --- a/src/object/motion/motiontoto.cpp +++ b/src/object/motion/motiontoto.cpp @@ -324,7 +324,7 @@ bool CMotionToto::EventFrame(const Event &event) distance = 30.0f-progress*18.0f; // remoteness shift = 18.0f-progress*11.0f; // shift is left verti = 10.0f-progress* 8.0f; // shift at the top - + CObject* selected = m_main->GetSelect(); ObjectType type = selected != nullptr ? selected->GetType() : OBJECT_NULL; From 9bdd83771e0e081ecf3be1384c7b1bb197ad4165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Mon, 2 Jan 2017 16:35:40 +0100 Subject: [PATCH 37/93] Optimizations and changes in OpenGL 2.1 device. * Limited number of lights to 4 * Only directional lights * Per-pixel lighting * Improved dynamic shadows a bit --- src/graphics/opengl/gl21device.cpp | 149 ++++++++++-------- src/graphics/opengl/gl21device.h | 10 +- src/graphics/opengl/glutil.h | 2 - .../opengl/shaders/gl21/fs_normal.glsl | 81 ++++++++-- .../opengl/shaders/gl21/vs_normal.glsl | 95 +---------- 5 files changed, 164 insertions(+), 173 deletions(-) diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp index b38f6387..48467668 100644 --- a/src/graphics/opengl/gl21device.cpp +++ b/src/graphics/opengl/gl21device.cpp @@ -242,7 +242,7 @@ bool CGL21Device::Create() glViewport(0, 0, m_config.size.x, m_config.size.y); // this is set in shader - int numLights = 8; + int numLights = 4; m_lights = std::vector(numLights, Light()); m_lightsEnabled = std::vector (numLights, false); @@ -408,7 +408,7 @@ bool CGL21Device::Create() uni.fogColor = glGetUniformLocation(m_normalProgram, "uni_FogColor"); uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor"); - uni.lightingEnabled = glGetUniformLocation(m_normalProgram, "uni_LightingEnabled"); + uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount"); uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_Material.ambient"); uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_Material.diffuse"); @@ -417,12 +417,6 @@ bool CGL21Device::Create() GLchar name[64]; for (int i = 0; i < 8; i++) { - sprintf(name, "uni_Light[%d].Enabled", i); - uni.lights[i].enabled = glGetUniformLocation(m_normalProgram, name); - - sprintf(name, "uni_Light[%d].Type", i); - uni.lights[i].type = glGetUniformLocation(m_normalProgram, name); - sprintf(name, "uni_Light[%d].Position", i); uni.lights[i].position = glGetUniformLocation(m_normalProgram, name); @@ -434,18 +428,6 @@ bool CGL21Device::Create() sprintf(name, "uni_Light[%d].Specular", i); uni.lights[i].specular = glGetUniformLocation(m_normalProgram, name); - - sprintf(name, "uni_Light[%d].Attenuation", i); - uni.lights[i].attenuation = glGetUniformLocation(m_normalProgram, name); - - sprintf(name, "uni_Light[%d].SpotDirection", i); - uni.lights[i].spotDirection = glGetUniformLocation(m_normalProgram, name); - - sprintf(name, "uni_Light[%d].Exponent", i); - uni.lights[i].spotExponent = glGetUniformLocation(m_normalProgram, name); - - sprintf(name, "uni_Light[%d].SpotCutoff", i); - uni.lights[i].spotCutoff = glGetUniformLocation(m_normalProgram, name); } // Set default uniform values @@ -476,10 +458,7 @@ bool CGL21Device::Create() glUniform1f(uni.shadowColor, 0.5f); - glUniform1i(uni.lightingEnabled, 0); - - for (int i = 0; i < 8; i++) - glUniform1i(uni.lights[i].enabled, 0); + glUniform1i(uni.lightCount, 0); } // Obtain uniform locations from interface rendering program and initialize them @@ -594,6 +573,7 @@ void CGL21Device::ConfigChanged(const DeviceConfig& newConfig) // Reset state m_lighting = false; + m_updateLights = true; glViewport(0, 0, m_config.size.x, m_config.size.y); @@ -721,36 +701,7 @@ void CGL21Device::SetLight(int index, const Light &light) m_lights[index] = light; - LightLocations &loc = m_uniforms[m_mode].lights[index]; - - glUniform4fv(loc.ambient, 1, light.ambient.Array()); - glUniform4fv(loc.diffuse, 1, light.diffuse.Array()); - glUniform4fv(loc.specular, 1, light.specular.Array()); - glUniform3f(loc.attenuation, light.attenuation0, light.attenuation1, light.attenuation2); - - if (light.type == LIGHT_DIRECTIONAL) - { - glUniform1i(loc.type, 1); - glUniform4f(loc.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f); - } - else if (light.type == LIGHT_POINT) - { - glUniform1i(loc.type, 2); - glUniform4f(loc.position, light.position.x, light.position.y, light.position.z, 1.0f); - - glUniform3f(loc.spotDirection, 0.0f, 1.0f, 0.0f); - glUniform1f(loc.spotCutoff, -1.0f); - glUniform1f(loc.spotExponent, 1.0f); - } - else if (light.type == LIGHT_SPOT) - { - glUniform1i(loc.type, 3); - glUniform4f(loc.position, light.position.x, light.position.y, light.position.z, 1.0f); - - glUniform3f(loc.spotDirection, -light.direction.x, -light.direction.y, -light.direction.z); - glUniform1f(loc.spotCutoff, std::cos(light.spotAngle)); - glUniform1f(loc.spotExponent, light.spotIntensity); - } + m_updateLights = true; } void CGL21Device::SetLightEnabled(int index, bool enabled) @@ -760,7 +711,7 @@ void CGL21Device::SetLightEnabled(int index, bool enabled) m_lightsEnabled[index] = enabled; - glUniform1i(m_uniforms[m_mode].lights[index].enabled, enabled ? 1 : 0); + m_updateLights = true; } /** If image is invalid, returns invalid texture. @@ -798,12 +749,13 @@ Texture CGL21Device::CreateTexture(ImageData *data, const TextureCreateParams &p result.originalSize = result.size; - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_2D); - glGenTextures(1, &result.id); + + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, result.id); + glEnable(GL_TEXTURE_2D); + // Set texture parameters GLint minF = GL_NEAREST, magF = GL_NEAREST; int mipmapLevel = 1; @@ -991,7 +943,7 @@ void CGL21Device::SetTexture(int index, const Texture &texture) glBindTexture(GL_TEXTURE_2D, texture.id); // Params need to be updated for the new bound texture - UpdateTextureStatus(); + UpdateTextureState(index); UpdateTextureParams(index); } @@ -1009,7 +961,7 @@ void CGL21Device::SetTexture(int index, unsigned int textureId) glBindTexture(GL_TEXTURE_2D, textureId); // Params need to be updated for the new bound texture - UpdateTextureStatus(); + UpdateTextureState(index); UpdateTextureParams(index); } @@ -1024,15 +976,54 @@ void CGL21Device::SetTextureEnabled(int index, bool enabled) if (same) return; // nothing to do - UpdateTextureStatus(); + UpdateTextureState(index); } -void CGL21Device::UpdateTextureStatus() +void CGL21Device::UpdateTextureState(int index) { - for (int i = 0; i < 3; i++) + bool enabled = m_texturesEnabled[index] && (m_currentTextures[index].id != 0); + glUniform1i(m_uniforms[m_mode].textureEnabled[index], enabled ? 1 : 0); +} + +void CGL21Device::UpdateLights() +{ + m_updateLights = false; + + // If not in normal rendering mode, return immediately + if (m_mode != 0) return; + + // Lighting enabled + if (m_lighting) { - bool enabled = m_texturesEnabled[i] && (m_currentTextures[i].id != 0); - glUniform1i(m_uniforms[m_mode].textureEnabled[i], enabled ? 1 : 0); + int index = 0; + + // Iterate all lights + for (unsigned int i = 0; i < m_lights.size(); i++) + { + // If disabled, ignore and continue + if (!m_lightsEnabled[i]) continue; + + // If not directional, ignore and continue + if (m_lights[i].type != LIGHT_DIRECTIONAL) continue; + + Light &light = m_lights[i]; + LightLocations &uni = m_uniforms[m_mode].lights[index]; + + glUniform4fv(uni.ambient, 1, light.ambient.Array()); + glUniform4fv(uni.diffuse, 1, light.diffuse.Array()); + glUniform4fv(uni.specular, 1, light.specular.Array()); + + glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f); + + index++; + } + + glUniform1i(m_uniforms[m_mode].lightCount, index); + } + // Lighting disabled + else + { + glUniform1i(m_uniforms[m_mode].lightCount, 0); } } @@ -1044,6 +1035,12 @@ inline void CGL21Device::BindVBO(GLuint vbo) m_currentVBO = vbo; } +inline void CGL21Device::BindTexture(int index, GLuint texture) +{ + glActiveTexture(GL_TEXTURE0 + index); + glBindTexture(GL_TEXTURE_2D, texture); +} + /** Sets the texture parameters for the given texture stage. If the given texture was not set (bound) yet, nothing happens. @@ -1121,6 +1118,8 @@ void CGL21Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, Color color) { + if (m_updateLights) UpdateLights(); + BindVBO(0); Vertex* vs = const_cast(vertices); @@ -1148,6 +1147,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, Color color) { + if (m_updateLights) UpdateLights(); + BindVBO(0); VertexTex2* vs = const_cast(vertices); @@ -1180,6 +1181,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) { + if (m_updateLights) UpdateLights(); + BindVBO(0); VertexCol* vs = const_cast(vertices); @@ -1199,6 +1202,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i void CGL21Device::DrawPrimitive(PrimitiveType type, const void *vertices, int size, const VertexFormat &format, int vertexCount) { + if (m_updateLights) UpdateLights(); + BindVBO(0); const char *ptr = reinterpret_cast(vertices); @@ -1277,6 +1282,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const void *vertices, void CGL21Device::DrawPrimitives(PrimitiveType type, const void *vertices, int size, const VertexFormat &format, int first[], int count[], int drawCount) { + if (m_updateLights) UpdateLights(); + BindVBO(0); const char *ptr = reinterpret_cast(vertices); @@ -1355,6 +1362,8 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const void *vertices, void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, int first[], int count[], int drawCount, Color color) { + if (m_updateLights) UpdateLights(); + BindVBO(0); Vertex* vs = const_cast(vertices); @@ -1381,6 +1390,8 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, int first[], int count[], int drawCount, Color color) { + if (m_updateLights) UpdateLights(); + BindVBO(0); VertexTex2* vs = const_cast(vertices); @@ -1414,6 +1425,8 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, int first[], int count[], int drawCount) { + if (m_updateLights) UpdateLights(); + BindVBO(0); VertexCol* vs = const_cast(vertices); @@ -1574,6 +1587,8 @@ void CGL21Device::DrawStaticBuffer(unsigned int bufferId) if (it == m_vboObjects.end()) return; + if (m_updateLights) UpdateLights(); + BindVBO((*it).second.bufferId); if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) @@ -1741,9 +1756,11 @@ void CGL21Device::SetRenderState(RenderState state, bool enabled) } else if (state == RENDER_STATE_LIGHTING) { + if (m_lighting == enabled) return; + m_lighting = enabled; - glUniform1i(m_uniforms[m_mode].lightingEnabled, enabled ? 1 : 0); + m_updateLights = true; return; } diff --git a/src/graphics/opengl/gl21device.h b/src/graphics/opengl/gl21device.h index e70d66c6..9a2bea7e 100644 --- a/src/graphics/opengl/gl21device.h +++ b/src/graphics/opengl/gl21device.h @@ -183,10 +183,14 @@ public: private: //! Updates the texture params for given texture stage void UpdateTextureParams(int index); - //! Updates texture status - void UpdateTextureStatus(); + //! Updates texture state + void UpdateTextureState(int index); + //! Update light parameters + void UpdateLights(); //! Binds VBO inline void BindVBO(GLuint vbo); + //! Binds texture + inline void BindTexture(int index, GLuint texture); private: //! Current config @@ -208,6 +212,8 @@ private: //! Whether lighting is enabled bool m_lighting = false; + //! true means that lights need to be updated + bool m_updateLights = false; //! Current lights std::vector m_lights; //! Current lights enable status diff --git a/src/graphics/opengl/glutil.h b/src/graphics/opengl/glutil.h index 4b66d50b..f6b0f16f 100644 --- a/src/graphics/opengl/glutil.h +++ b/src/graphics/opengl/glutil.h @@ -194,8 +194,6 @@ struct UniformLocations //! Shadow color GLint shadowColor = -1; - //! true enables lighting - GLint lightingEnabled = -1; // Number of enabled lights GLint lightCount = -1; //! Ambient color diff --git a/src/graphics/opengl/shaders/gl21/fs_normal.glsl b/src/graphics/opengl/shaders/gl21/fs_normal.glsl index fdf59ac2..d21bc9cf 100644 --- a/src/graphics/opengl/shaders/gl21/fs_normal.glsl +++ b/src/graphics/opengl/shaders/gl21/fs_normal.glsl @@ -19,6 +19,8 @@ // FRAGMENT SHADER - NORMAL MODE #version 120 +#define CONFIG_QUALITY_SHADOWS 1 + uniform sampler2D uni_PrimaryTexture; uniform sampler2D uni_SecondaryTexture; uniform sampler2DShadow uni_ShadowTexture; @@ -34,6 +36,26 @@ uniform vec4 uni_FogColor; uniform float uni_ShadowColor; +struct LightParams +{ + vec4 Position; + vec4 Ambient; + vec4 Diffuse; + vec4 Specular; +}; + +struct Material +{ + vec4 ambient; + vec4 diffuse; + vec4 specular; +}; + +uniform Material uni_Material; + +uniform int uni_LightCount; +uniform LightParams uni_Light[4]; + varying float pass_Distance; varying vec4 pass_Color; varying vec3 pass_Normal; @@ -47,6 +69,55 @@ void main() { vec4 color = pass_Color; + if (uni_LightCount > 0) + { + vec4 ambient = vec4(0.0f); + vec4 diffuse = vec4(0.0f); + vec4 specular = vec4(0.0f); + + vec3 normal = normalize(pass_Normal); + + for (int i = 0; i < uni_LightCount; i++) + { + LightParams light = uni_Light[i]; + + vec3 lightDirection = light.Position.xyz; + vec3 reflectDirection = -reflect(lightDirection, normal); + + float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f); + float specularComponent = clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f); + + ambient += light.Ambient; + diffuse += diffuseComponent * light.Diffuse; + specular += specularComponent * light.Specular; + } + + float shadow = 1.0f; + + if (uni_TextureEnabled[2]) + { +#ifdef CONFIG_QUALITY_SHADOWS + float offset = 0.00025f; + + float value = (1.0f / 5.0f) * (shadow2D(uni_ShadowTexture, pass_TexCoord2).x + + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( offset, 0.0f, 0.0f)).x + + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3(-offset, 0.0f, 0.0f)).x + + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, offset, 0.0f)).x + + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, -offset, 0.0f)).x); + + shadow = mix(uni_ShadowColor, 1.0f, value); +#else + shadow = mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, pass_TexCoord2).x); +#endif + } + + vec4 result = ambient * uni_Material.ambient + + diffuse * uni_Material.diffuse * shadow + + specular * uni_Material.specular * shadow; + + color = clamp(vec4(result.rgb, 1.0f), 0.0f, 1.0f); + } + if (uni_TextureEnabled[0]) { color = color * texture2D(uni_PrimaryTexture, pass_TexCoord0); @@ -57,16 +128,6 @@ void main() color = color * texture2D(uni_SecondaryTexture, pass_TexCoord1); } - if (uni_TextureEnabled[2]) - { - vec3 normal = pass_Normal * (2.0f * gl_Color.x - 1.0f); - - if (dot(normal, const_LightDirection) < 0.0f) - color.rgb *= uni_ShadowColor; - else - color.rgb *= mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, pass_TexCoord2).x); - } - if (uni_FogEnabled) { float interpolate = (pass_Distance - uni_FogRange.x) / (uni_FogRange.y - uni_FogRange.x); diff --git a/src/graphics/opengl/shaders/gl21/vs_normal.glsl b/src/graphics/opengl/shaders/gl21/vs_normal.glsl index 117f09b5..9195cd20 100644 --- a/src/graphics/opengl/shaders/gl21/vs_normal.glsl +++ b/src/graphics/opengl/shaders/gl21/vs_normal.glsl @@ -25,33 +25,6 @@ uniform mat4 uni_ModelMatrix; uniform mat4 uni_ShadowMatrix; uniform mat4 uni_NormalMatrix; -struct LightParams -{ - bool Enabled; - int Type; - vec4 Position; - vec4 Ambient; - vec4 Diffuse; - vec4 Specular; - float Shininess; - vec3 Attenuation; - vec3 SpotDirection; - float SpotCutoff; - float SpotExponent; -}; - -struct Material -{ - vec4 ambient; - vec4 diffuse; - vec4 specular; -}; - -uniform Material uni_Material; - -uniform bool uni_LightingEnabled; -uniform LightParams uni_Light[8]; - varying float pass_Distance; varying vec4 pass_Color; varying vec3 pass_Normal; @@ -65,75 +38,11 @@ void main() vec4 eyeSpace = uni_ViewMatrix * position; vec4 shadowCoord = uni_ShadowMatrix * position; - vec4 color = gl_Color; - - vec3 normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz); - - if (uni_LightingEnabled) - { - vec4 ambient = vec4(0.0f); - vec4 diffuse = vec4(0.0f); - vec4 specular = vec4(0.0f); - - for (int i = 0; i < 8; i++) - { - if (uni_Light[i].Enabled) - { - LightParams light = uni_Light[i]; - - vec3 lightDirection = light.Position.xyz; - float atten = 1.0f; - - if (light.Position.w > 0.5f) - { - float dist = distance(light.Position.xyz, position.xyz); - - float atten = 1.0f / dot(light.Attenuation, - vec3(1.0f, dist, dist * dist)); - - lightDirection = normalize(light.Position.xyz - position.xyz); - } - - float spot = 1.0f; - - if (light.SpotCutoff > 0.0f) - { - float cone = dot(light.SpotDirection, lightDirection); - - if (cone > light.SpotCutoff) - { - spot = pow(cone, light.SpotExponent); - } - else - { - continue; - } - } - - vec3 reflectDirection = -reflect(lightDirection, normal); - - float component = atten * spot; - float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f); - float specularComponent = clamp(pow(dot(normal, lightDirection + reflectDirection), light.Shininess), 0.0f, 1.0f); - - ambient += component * light.Ambient * uni_Material.ambient; - diffuse += component * diffuseComponent * light.Diffuse * uni_Material.diffuse; - specular += component * specularComponent * light.Specular * uni_Material.specular; - } - } - - vec4 result = ambient + diffuse + specular; - - color = clamp(vec4(result.rgb, uni_Material.diffuse), 0.0f, 1.0f); - } - gl_Position = uni_ProjectionMatrix * eyeSpace; - gl_FrontColor = vec4(1.0f); - gl_BackColor = vec4(0.0f); + pass_Color = gl_Color; + pass_Normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz); pass_Distance = abs(eyeSpace.z / eyeSpace.w); - pass_Color = color; - pass_Normal = normal; pass_TexCoord0 = gl_MultiTexCoord0.st; pass_TexCoord1 = gl_MultiTexCoord1.st; pass_TexCoord2 = shadowCoord.xyz / shadowCoord.w; From 6ec13017ebae1bf5864ee208d44e4ed66b7c48aa Mon Sep 17 00:00:00 2001 From: piotrwalkusz1 Date: Mon, 2 Jan 2017 18:43:19 +0100 Subject: [PATCH 38/93] Fix apperance camera position, closes #802 (#880) --- src/graphics/engine/engine.cpp | 5 ++++ src/graphics/engine/engine.h | 2 ++ src/ui/screen/screen_apperance.cpp | 45 +++++++++++++++++++++++++----- src/ui/screen/screen_apperance.h | 3 ++ 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 3110cd37..768897fe 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -3087,6 +3087,11 @@ const Math::Matrix& CEngine::GetMatView() return m_matView; } +const Math::Matrix& CEngine::GetMatProj() +{ + return m_matProj; +} + Math::Vector CEngine::GetEyePt() { return m_eyePt; diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index e1dadf4d..834de1e3 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -1135,6 +1135,8 @@ public: //! Returns the view matrix const Math::Matrix& GetMatView(); + //! Returns the projection matrix + const Math::Matrix& GetMatProj(); //! Returns the camera center point TEST_VIRTUAL Math::Vector GetEyePt(); //! Returns the camera target point diff --git a/src/ui/screen/screen_apperance.cpp b/src/ui/screen/screen_apperance.cpp index 3e8cdd0d..7ca200f1 100644 --- a/src/ui/screen/screen_apperance.cpp +++ b/src/ui/screen/screen_apperance.cpp @@ -28,6 +28,8 @@ #include "level/player_profile.h" #include "level/robotmain.h" +#include "math/geometry.h" + #include "ui/controls/button.h" #include "ui/controls/color.h" #include "ui/controls/interface.h" @@ -331,6 +333,10 @@ bool CScreenApperance::EventProcess(const Event &event) break; } + case EVENT_UPDINTERFACE: + CameraPerso(); + break; + case EVENT_INTERFACE_PHEAD: m_apperanceTab = 0; UpdatePerso(); @@ -617,18 +623,13 @@ void CScreenApperance::UpdatePerso() void CScreenApperance::CameraPerso() { - Gfx::CCamera* camera = m_main->GetCamera(); - - camera->SetType(Gfx::CAM_TYPE_SCRIPT); if ( m_apperanceTab == 0 ) { - camera->SetScriptCamera(Math::Vector(6.0f, 0.0f, 0.0f), - Math::Vector(0.0f, 0.2f, 1.5f)); + SetCamera(0.325f, -0.15f, 5.0f); } else { - camera->SetScriptCamera(Math::Vector(18.0f, 0.0f, 4.5f), - Math::Vector(0.0f, 1.6f, 4.5f)); + SetCamera(0.325f, 0.3f, 18.0f); } } @@ -696,4 +697,34 @@ void CScreenApperance::ColorPerso() else apperance.colorBand = color; } +void CScreenApperance::SetCamera(float x, float y, float cameraDistance) +{ + Gfx::CCamera* camera = m_main->GetCamera(); + Gfx::CEngine* engine = Gfx::CEngine::GetInstancePointer(); + + camera->SetType(Gfx::CAM_TYPE_SCRIPT); + + Math::Vector p2D(x, y, cameraDistance); + Math::Vector p3D; + Math::Matrix matView; + Math::Matrix matProj = engine->GetMatProj(); + + Math::LoadViewMatrix(matView, Math::Vector(0.0f, 0.0f, -cameraDistance), + Math::Vector(0.0f, 0.0f, 0.0f), + Math::Vector(0.0f, 0.0f, 1.0f)); + + p2D.x = p2D.x * 2.0f - 1.0f; // [0..1] -> [-1..1] + p2D.y = p2D.y * 2.0f - 1.0f; + + p3D.x = p2D.x * p2D.z / matProj.Get(1,1); + p3D.y = p2D.y * p2D.z / matProj.Get(2,2); + p3D.z = p2D.z; + + p3D = Math::Transform(matView.Inverse(), p3D); + p3D = -p3D; + + camera->SetScriptCamera(Math::Vector(cameraDistance, p3D.y, p3D.x), + Math::Vector(0.0f, p3D.y, p3D.x)); +} + } // namespace Ui diff --git a/src/ui/screen/screen_apperance.h b/src/ui/screen/screen_apperance.h index 1aa6c8ac..b5faf08d 100644 --- a/src/ui/screen/screen_apperance.h +++ b/src/ui/screen/screen_apperance.h @@ -40,6 +40,9 @@ protected: void FixPerso(int rank, int index); void ColorPerso(); + //! Move camera in that way that astronaut's origin is in (x, y) point on window + void SetCamera(float x, float y, float cameraDistance); + protected: int m_apperanceTab; // perso: tab selected float m_apperanceAngle; // perso: angle of presentation From 8a0c7279dc518438fcfd3b8543140edc66386f9c Mon Sep 17 00:00:00 2001 From: Smok94 Date: Mon, 2 Jan 2017 20:23:19 +0100 Subject: [PATCH 39/93] Command history for cheat console, closes #316 (PR #869) Adds console command history. Browsable by up and down arrow keys. --- src/level/robotmain.cpp | 49 +++++++++++++++++++++++++++++++++++++++++ src/level/robotmain.h | 12 ++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 80e9ce06..2797e3d3 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -763,6 +763,7 @@ bool CRobotMain::ProcessEvent(Event &event) m_interface->SetFocus(pe); if (m_phase == PHASE_SIMUL) m_cmdEditPause = m_pause->ActivatePause(PAUSE_ENGINE); m_cmdEdit = true; + m_commandHistoryIndex = -1; // no element selected in command history } return false; } @@ -777,6 +778,28 @@ bool CRobotMain::ProcessEvent(Event &event) } } + // Browse forward command history with UP key + if (event.type == EVENT_KEY_DOWN && + event.GetData()->key == KEY(UP) && m_cmdEdit) + { + Ui::CEdit* pe = static_cast(m_interface->SearchControl(EVENT_CMD)); + if (pe == nullptr) return false; + std::string cmd = GetNextFromCommandHistory(); + if (!cmd.empty()) pe->SetText(cmd); + return false; + } + + // Browse backward command history with DOWN key + if (event.type == EVENT_KEY_DOWN && + event.GetData()->key == KEY(DOWN) && m_cmdEdit) + { + Ui::CEdit* pe = static_cast(m_interface->SearchControl(EVENT_CMD)); + if (pe == nullptr) return false; + std::string cmd = GetPreviousFromCommandHistory(); + if (!cmd.empty()) pe->SetText(cmd); + return false; + } + if (event.type == EVENT_KEY_DOWN && event.GetData()->key == KEY(RETURN) && m_cmdEdit) { @@ -793,6 +816,7 @@ bool CRobotMain::ProcessEvent(Event &event) m_cmdEditPause = nullptr; } ExecuteCmd(cmd); + PushToCommandHistory(cmd); m_cmdEdit = false; return false; } @@ -5768,3 +5792,28 @@ bool CRobotMain::GetDebugCrashSpheres() { return m_debugCrashSpheres; } + +void CRobotMain::PushToCommandHistory(std::string str) +{ + if (!m_commandHistory.empty() && m_commandHistory.front() == str) // already in history + return; + + m_commandHistory.push_front(str); + + if (m_commandHistory.size() > 50) // to avoid infinite growth + m_commandHistory.pop_back(); +} + +std::string CRobotMain::GetNextFromCommandHistory() +{ + if (m_commandHistory.empty() || static_cast(m_commandHistory.size()) <= m_commandHistoryIndex + 1) // no next element + return ""; + return m_commandHistory[++m_commandHistoryIndex]; +} + +std::string CRobotMain::GetPreviousFromCommandHistory() +{ + if (m_commandHistory.empty() || m_commandHistoryIndex < 1) // first or none element selected + return ""; + return m_commandHistory[--m_commandHistoryIndex]; +} diff --git a/src/level/robotmain.h b/src/level/robotmain.h index 346e8fc4..dad1bed0 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -513,6 +513,13 @@ protected: void UpdateDebugCrashSpheres(); + //! Adds element to the beginning of command history + void PushToCommandHistory(std::string obj); + //! Returns next/previous element from command history and updates index + //@{ + std::string GetNextFromCommandHistory(); + std::string GetPreviousFromCommandHistory(); + //@} protected: CApplication* m_app = nullptr; @@ -685,4 +692,9 @@ protected: std::deque m_selectionHistory; bool m_debugCrashSpheres; + + //! Cheat console command history + std::deque m_commandHistory; + //! Index of currently selected element in command history + int m_commandHistoryIndex; }; From d7fae300b9639acd3ae33e1756aaa34d290e1b1b Mon Sep 17 00:00:00 2001 From: piotrwalkusz1 Date: Sun, 15 Jan 2017 20:28:52 +0100 Subject: [PATCH 40/93] Fix crash on class redefinition, closes #703 (#890) --- src/CBot/CBotClass.cpp | 6 +++--- src/CBot/CBotProgram.cpp | 10 ++++++++++ src/CBot/CBotProgram.h | 6 ++++++ test/unit/CBot/CBot_test.cpp | 24 ++++++++++++++++++++++-- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index 579dda03..13fb8379 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -455,7 +455,8 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack) std::string name = p->GetString(); CBotClass* pOld = CBotClass::Find(name); - if ( pOld != nullptr && pOld->m_IsDef ) + if ( (pOld != nullptr && pOld->m_IsDef) || /* public class exists in different program */ + pStack->GetProgram()->ClassExists(name)) /* class exists in this program */ { pStack->SetError( CBotErrRedefClass, p ); return nullptr; @@ -489,14 +490,13 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack) } int level = 1; - do // skip over the definition + while (level > 0 && p != nullptr) { int type = p->GetType(); p = p->GetNext(); if (type == ID_OPBLK) level++; if (type == ID_CLBLK) level--; } - while (level > 0 && p != nullptr); if (level > 0) pStack->SetError(CBotErrCloseBlock, classe->m_pOpenblk); diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index dce62198..32813de1 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -281,6 +281,16 @@ const std::list& CBotProgram::GetFunctions() return m_functions; } +bool CBotProgram::ClassExists(std::string name) +{ + for (CBotClass* p : m_classes) + { + if ( p->GetName() == name ) return true; + } + + return false; +} + //////////////////////////////////////////////////////////////////////////////// CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser ) { diff --git a/src/CBot/CBotProgram.h b/src/CBot/CBotProgram.h index d90fb0ef..4a64b562 100644 --- a/src/CBot/CBotProgram.h +++ b/src/CBot/CBotProgram.h @@ -333,6 +333,12 @@ public: */ const std::list& GetFunctions(); + /** + * \brief Check if class with that name was created in this program + * \return True if class was defined in this program, otherwise, false + */ + bool ClassExists(std::string name); + /** * \brief Returns static list of all registered external calls */ diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 0dae25e0..6cf28413 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -932,8 +932,19 @@ TEST_F(CBotUT, ClassMethodRedefined) ); } -// TODO: Not only doesn't work but segfaults -TEST_F(CBotUT, DISABLED_ClassRedefined) +TEST_F(CBotUT, ClassRedefinedInDifferentPrograms) +{ + auto publicProgram = ExecuteTest( + "public class TestClass {}\n" + ); + + ExecuteTest( + "public class TestClass {}\n", + CBotErrRedefClass + ); +} + +TEST_F(CBotUT, ClassRedefinedInOneProgram) { ExecuteTest( "public class TestClass {}\n" @@ -942,6 +953,15 @@ TEST_F(CBotUT, DISABLED_ClassRedefined) ); } +TEST_F(CBotUT, ClassMissingCloseBlock) +{ + ExecuteTest( + "public class Something\n" + "{\n", + CBotErrCloseBlock + ); +} + // TODO: NOOOOOO!!! Nononononono :/ TEST_F(CBotUT, DISABLED_PublicClasses) { From 8fc015144467ef299c2fba83996cdc2bcef0455b Mon Sep 17 00:00:00 2001 From: melex750 Date: Mon, 16 Jan 2017 11:38:34 -0500 Subject: [PATCH 41/93] Fix increment and decrement syntax --- src/CBot/CBotInstr/CBotExprVar.cpp | 8 +++-- src/CBot/CBotInstr/CBotExprVar.h | 11 +++--- src/CBot/CBotInstr/CBotFieldExpr.cpp | 5 ++- src/CBot/CBotInstr/CBotFieldExpr.h | 7 ++-- src/CBot/CBotInstr/CBotLeftExpr.cpp | 5 ++- src/CBot/CBotInstr/CBotParExpr.cpp | 29 +++++++-------- test/unit/CBot/CBot_test.cpp | 53 ++++++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 35 deletions(-) diff --git a/src/CBot/CBotInstr/CBotExprVar.cpp b/src/CBot/CBotInstr/CBotExprVar.cpp index a15c9c9a..ed77d8ac 100644 --- a/src/CBot/CBotInstr/CBotExprVar.cpp +++ b/src/CBot/CBotInstr/CBotExprVar.cpp @@ -44,7 +44,7 @@ CBotExprVar::~CBotExprVar() } //////////////////////////////////////////////////////////////////////////////// -CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::ProtectionLevel privat) +CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, bool bCheckReadOnly) { // CBotToken* pDebut = p; CBotCStack* pStk = pStack->TokenStack(); @@ -67,7 +67,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot if (ident > 0 && ident < 9000) { - if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, privat)) + if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, bCheckReadOnly)) { pStk->SetError(CBotErrPrivate, p); goto err; @@ -122,6 +122,8 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot { if (p->GetNext()->GetType() == ID_OPENPAR) // a method call? { + if (bCheckReadOnly) goto err; // don't allow increment a method call "++" + CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var); if (!pStk->IsOk()) goto err; inst->AddNext3(i); // added after @@ -137,7 +139,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot if (var != nullptr) { i->SetUniqNum(var->GetUniqNum()); - if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, privat)) + if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, bCheckReadOnly)) { pStk->SetError(CBotErrPrivate, pp); goto err; diff --git a/src/CBot/CBotInstr/CBotExprVar.h b/src/CBot/CBotInstr/CBotExprVar.h index 9cf68991..2f2e69ab 100644 --- a/src/CBot/CBotInstr/CBotExprVar.h +++ b/src/CBot/CBotInstr/CBotExprVar.h @@ -40,14 +40,13 @@ public: ~CBotExprVar(); /*! - * \brief Compile - * \param p - * \param pStack - * \param privat + * \brief Compile an expression of a variable, possibly chained with index operators and/or dot operators + * \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression + * \param pStack Current compilation stack frame + * \param bCheckReadOnly True for operations that would modify the value of the variable * \return */ - static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack, - CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected); + static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack, bool bCheckReadOnly = false); /*! * \brief CompileMethode diff --git a/src/CBot/CBotInstr/CBotFieldExpr.cpp b/src/CBot/CBotInstr/CBotFieldExpr.cpp index 09ac5f8e..04635a1a 100644 --- a/src/CBot/CBotInstr/CBotFieldExpr.cpp +++ b/src/CBot/CBotInstr/CBotFieldExpr.cpp @@ -135,12 +135,11 @@ std::string CBotFieldExpr::GetDebugData() } //////////////////////////////////////////////////////////////////////////////// -bool CBotFieldExpr::CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, - CBotVar::ProtectionLevel privat) +bool CBotFieldExpr::CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool bCheckReadOnly) { CBotVar::ProtectionLevel varPriv = pVar->GetPrivate(); - if (privat == CBotVar::ProtectionLevel::ReadOnly && varPriv == privat) + if (bCheckReadOnly && varPriv == CBotVar::ProtectionLevel::ReadOnly) return true; if (varPriv == CBotVar::ProtectionLevel::Public) return false; diff --git a/src/CBot/CBotInstr/CBotFieldExpr.h b/src/CBot/CBotInstr/CBotFieldExpr.h index 67ab2f05..5f093bd7 100644 --- a/src/CBot/CBotInstr/CBotFieldExpr.h +++ b/src/CBot/CBotInstr/CBotFieldExpr.h @@ -72,13 +72,12 @@ public: * This function doesn't set the error flag itself. * * \param pStack Current compilation stack frame - * \param pPrev Class instance which variable to check is part of, or nullptr if not part of a class + * \param pPrev Class instance which variable to check is part of, or nullptr when compiler inserts 'this.' before * \param pVar Variable to check - * \param privat CBotVar::ProtectionLevel::ReadOnly if requesting read-only access, anything else otherwise + * \param bCheckReadOnly True for operations that would modify the value of the variable * \return true if pVar is inaccessible in the current context, false if access should be allowed */ - static bool CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, - CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected); + static bool CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool bCheckReadOnly = false); protected: virtual const std::string GetDebugName() override { return "CBotFieldExpr"; } diff --git a/src/CBot/CBotInstr/CBotLeftExpr.cpp b/src/CBot/CBotInstr/CBotLeftExpr.cpp index 4678ff8e..4c4400a9 100644 --- a/src/CBot/CBotInstr/CBotLeftExpr.cpp +++ b/src/CBot/CBotInstr/CBotLeftExpr.cpp @@ -64,7 +64,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack) inst->m_nIdent = var->GetUniqNum(); if (inst->m_nIdent > 0 && inst->m_nIdent < 9000) { - if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, CBotVar::ProtectionLevel::ReadOnly)) + if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, true)) { pStk->SetError(CBotErrPrivate, p); goto err; @@ -128,8 +128,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack) var = var->GetItem(p->GetString()); // get item correspondent if (var != nullptr) { - if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, - CBotVar::ProtectionLevel::ReadOnly)) + if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, true)) { pStk->SetError(CBotErrPrivate, pp); goto err; diff --git a/src/CBot/CBotInstr/CBotParExpr.cpp b/src/CBot/CBotInstr/CBotParExpr.cpp index 714e68e4..a32363fb 100644 --- a/src/CBot/CBotInstr/CBotParExpr.cpp +++ b/src/CBot/CBotInstr/CBotParExpr.cpp @@ -90,17 +90,16 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) // post incremented or decremented? if (IsOfType(p, ID_INC, ID_DEC)) { + // recompile the variable for read-only + delete inst; + p = pvar; + inst = CBotExprVar::Compile(p, pStk, true); if (pStk->GetType() >= CBotTypBoolean) { pStk->SetError(CBotErrBadType1, pp); delete inst; return pStack->Return(nullptr, pStk); } - - // recompile the variable for read-only - delete inst; - p = pvar; - inst = CBotExprVar::Compile(p, pStk, CBotVar::ProtectionLevel::ReadOnly); p = p->GetNext(); CBotPostIncExpr* i = new CBotPostIncExpr(); @@ -115,24 +114,22 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) CBotToken* pp = p; if (IsOfType(p, ID_INC, ID_DEC)) { - CBotPreIncExpr* i = new CBotPreIncExpr(); - i->SetToken(pp); - if (p->GetType() == TokenTypVar) { - if (nullptr != (i->m_instr = CBotExprVar::Compile(p, pStk, CBotVar::ProtectionLevel::ReadOnly))) + if (nullptr != (inst = CBotExprVar::Compile(p, pStk, true))) { - if (pStk->GetType() >= CBotTypBoolean) + if (pStk->GetType() < CBotTypBoolean) // a number ? { - pStk->SetError(CBotErrBadType1, pp); - delete inst; - return pStack->Return(nullptr, pStk); + CBotPreIncExpr* i = new CBotPreIncExpr(); + i->SetToken(pp); + i->m_instr = inst; + return pStack->Return(i, pStk); } - return pStack->Return(i, pStk); + delete inst; } - delete i; - return pStack->Return(nullptr, pStk); } + pStk->SetError(CBotErrBadType1, pp); + return pStack->Return(nullptr, pStk); } // is it a number or DefineNum? diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 6cf28413..e456261b 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -2073,3 +2073,56 @@ TEST_F(CBotUT, ClassTestPrivateMember) CBotErrPrivate ); } + +TEST_F(CBotUT, IncrementDecrementSyntax) +{ + auto publicProgram = ExecuteTest( + "public class TestClass {\n" + " int GetInt() { return 1; }\n" + "}\n" + "extern void TestIncrementDecrement()\n" + "{\n" + " int i = 1;\n" + " ASSERT(2 == ++i);\n" + " ASSERT(2 == i++);\n" + " ASSERT(3 == i );\n" + " ASSERT(2 == --i);\n" + " ASSERT(2 == i--);\n" + " ASSERT(1 == i );\n" + "}\n" + ); + + ExecuteTest( + "extern void PreIncrementMethodCall()\n" + "{\n" + " TestClass tc();\n" + " ++tc.GetInt();\n" + "}\n", + CBotErrBadType1 + ); + + ExecuteTest( + "extern void PostIncrementMethodCall()\n" + "{\n" + " TestClass tc();\n" + " tc.GetInt()++;\n" + "}\n", + CBotErrBadType1 + ); + + ExecuteTest( + "extern void BadPreIncrementEmpty()\n" + "{\n" + " ++;\n" + "}\n", + CBotErrBadType1 + ); + + ExecuteTest( + "extern void BadPreIncrementNotAVar()\n" + "{\n" + " ++123;\n" + "}\n", + CBotErrBadType1 + ); +} From 64bc1f1afb0eb00cbd403fe1fbc21bf2e4b84a74 Mon Sep 17 00:00:00 2001 From: melex750 Date: Mon, 16 Jan 2017 12:34:18 -0500 Subject: [PATCH 42/93] Fix constructor/destructor and field syntax --- po/colobot.pot | 3 ++ po/de.po | 3 ++ po/fr.po | 3 ++ po/pl.po | 3 ++ po/ru.po | 3 ++ src/CBot/CBotClass.cpp | 83 +++++++++++++++++++---------- src/CBot/CBotClass.h | 7 +++ src/CBot/CBotEnums.h | 1 + src/CBot/CBotInstr/CBotFunction.cpp | 34 +++++++++++- src/common/restext.cpp | 1 + test/unit/CBot/CBot_test.cpp | 59 ++++++++++++++++++-- 11 files changed, 167 insertions(+), 33 deletions(-) diff --git a/po/colobot.pot b/po/colobot.pot index a1446763..fd5c3de4 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -1736,6 +1736,9 @@ msgstr "" msgid "Ambiguous call to overloaded function" msgstr "" +msgid "Function needs return type \"void\"" +msgstr "" + msgid "Dividing by zero" msgstr "" diff --git a/po/de.po b/po/de.po index 653fa662..e4c105af 100644 --- a/po/de.po +++ b/po/de.po @@ -616,6 +616,9 @@ msgstr "Diese Funktion gibt es schon" msgid "Function name missing" msgstr "Hier muss der Name der Funktion stehen" +msgid "Function needs return type \"void\"" +msgstr "" + msgid "Game speed" msgstr "Spielgeschwindigkeit" diff --git a/po/fr.po b/po/fr.po index 6f432671..905a0163 100644 --- a/po/fr.po +++ b/po/fr.po @@ -603,6 +603,9 @@ msgstr "Cette fonction existe déjà" msgid "Function name missing" msgstr "Nom de la fonction attendu" +msgid "Function needs return type \"void\"" +msgstr "" + msgid "Game speed" msgstr "Vitesse du jeu" diff --git a/po/pl.po b/po/pl.po index f17c8176..cd9f37c8 100644 --- a/po/pl.po +++ b/po/pl.po @@ -605,6 +605,9 @@ msgstr "Funkcja już istnieje" msgid "Function name missing" msgstr "Brakująca nazwa funkcji" +msgid "Function needs return type \"void\"" +msgstr "" + msgid "Game speed" msgstr "Prędkość gry" diff --git a/po/ru.po b/po/ru.po index 70727694..233cb300 100644 --- a/po/ru.po +++ b/po/ru.po @@ -612,6 +612,9 @@ msgstr "Функция уже существует" msgid "Function name missing" msgstr "Имя функции отсутствует" +msgid "Function needs return type \"void\"" +msgstr "" + msgid "Game speed" msgstr "Скорость игры" diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index 13fb8379..127d6d34 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -248,6 +248,19 @@ CBotVar* CBotClass::GetItemRef(int nIdent) return nullptr; } +//////////////////////////////////////////////////////////////////////////////// +bool CBotClass::CheckVar(const std::string &name) +{ + CBotVar* p = m_pVar; + + while ( p != nullptr ) + { + if ( p->GetName() == name ) return true; + p = p->GetNext(); + } + return false; +} + //////////////////////////////////////////////////////////////////////////////// bool CBotClass::IsIntrinsic() { @@ -556,6 +569,8 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) while (pStack->IsOk()) { CBotTypResult type2 = CBotTypResult(type); // reset type after comma + CBotToken* varToken = p; + std::string pp = p->GetString(); if ( IsOfType(p, ID_NOT) ) { @@ -564,33 +579,6 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) if (IsOfType(p, TokenTypVar)) { - CBotInstr* limites = nullptr; - while ( IsOfType( p, ID_OPBRK ) ) // a table? - { - CBotInstr* i = nullptr; - pStack->SetStartError( p->GetStart() ); - if ( p->GetType() != ID_CLBRK ) - { - i = CBotExpression::Compile( p, pStack ); // expression for the value - if (i == nullptr || pStack->GetType() != CBotTypInt) // must be a number - { - pStack->SetError(CBotErrBadIndex, p->GetStart()); - return false; - } - } - else - i = new CBotEmpty(); // special if not a formula - - type2 = CBotTypResult(CBotTypArrayPointer, type2); - - if (limites == nullptr) limites = i; - else limites->AddNext3(i); - - if (IsOfType(p, ID_CLBRK)) continue; - pStack->SetError(CBotErrCloseIndex, p->GetStart()); - return false; - } - if ( p->GetType() == ID_OPENPAR ) { if ( !bSecond ) @@ -673,12 +661,51 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) } // definition of an element - if (type2.Eq(0)) + if (type.Eq(0)) { pStack->SetError(CBotErrNoTerminator, p); return false; } + if (pp[0] == '~' || pp == GetName()) // bad variable name + { + pStack->SetError(CBotErrNoVar, varToken); + return false; + } + + if (!bSecond && CheckVar(pp)) // variable already exists + { + pStack->SetError(CBotErrRedefVar, varToken); + return false; + } + + CBotInstr* limites = nullptr; + while ( IsOfType( p, ID_OPBRK ) ) // an array + { + CBotInstr* i = nullptr; + pStack->SetStartError( p->GetStart() ); + if ( p->GetType() != ID_CLBRK ) + { + i = CBotExpression::Compile( p, pStack ); // expression for the value + if (i == nullptr || pStack->GetType() != CBotTypInt) // must be a number + { + pStack->SetError(CBotErrBadIndex, p->GetStart()); + return false; + } + } + else + i = new CBotEmpty(); // special if not a formula + + type2 = CBotTypResult(CBotTypArrayPointer, type2); + + if (limites == nullptr) limites = i; + else limites->AddNext3(i); + + if (IsOfType(p, ID_CLBRK)) continue; + pStack->SetError(CBotErrCloseIndex, p->GetStart()); + return false; + } + CBotInstr* i = nullptr; if ( IsOfType(p, ID_ASS ) ) { diff --git a/src/CBot/CBotClass.h b/src/CBot/CBotClass.h index 68b61cc6..503c62db 100644 --- a/src/CBot/CBotClass.h +++ b/src/CBot/CBotClass.h @@ -221,6 +221,13 @@ public: */ CBotVar* GetItemRef(int nIdent); + /*! + * \brief Check whether a variable is already defined in a class + * \param name Name of the variable + * \return True if a variable is defined in the class + */ + bool CheckVar(const std::string &name); + /*! * \brief CompileMethode Compiles a method associated with an instance of * class the method can be declared by the user or AddFunction. diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h index da0dbea7..b7453e59 100644 --- a/src/CBot/CBotEnums.h +++ b/src/CBot/CBotEnums.h @@ -237,6 +237,7 @@ enum CBotError : int CBotErrNoPublic = 5042, //!< missing word "public" CBotErrNoExpression = 5043, //!< expression expected after = CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function + CBotErrFuncNotVoid = 5045, //!< function needs return type "void" // Runtime errors CBotErrZeroDiv = 6000, //!< division by zero diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index f86153f5..7852c7ef 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -165,6 +165,7 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct if ( IsOfType(p, ID_NOT) ) { CBotToken d(std::string("~") + p->GetString()); + d.SetPos(pp->GetStart(), p->GetEnd()); func->m_token = d; } @@ -268,6 +269,7 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas if ( IsOfType(p, ID_NOT) ) { CBotToken d(std::string("~") + p->GetString()); + d.SetPos(pp->GetStart(), p->GetEnd()); func->m_token = d; } @@ -289,10 +291,40 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas if (!IsOfType(p, TokenTypVar)) goto bad; } - func->m_param = CBotDefParam::Compile(p, pStk ); + + CBotToken* openPar = p; + func->m_param = CBotDefParam::Compile(p, pStk); // compile parameters + + if (pStk->IsOk() && pClass != nullptr) // method in a class + { + // check if a constructor has return type void + if (func->GetName() == pClass->GetName() && !func->m_retTyp.Eq(CBotTypVoid)) + { + pp = &(func->m_retToken); + pStk->SetError(CBotErrFuncNotVoid, pp); + } + + if (pStk->IsOk() && pp->GetString() == "~") // destructor + { + // check destructor name + if (func->GetName() != ("~" + pClass->GetName())) + pStk->SetError(CBotErrNoFunc, pp); + // confirm no parameters + if (pStk->IsOk() && func->m_param != nullptr) + pStk->SetError(CBotErrClosePar, openPar->GetNext()); + // must return void + if (pStk->IsOk() && !func->m_retTyp.Eq(CBotTypVoid)) + { + pp = &(func->m_retToken); + pStk->SetError(CBotErrFuncNotVoid, pp); + } + } + } + if (pStk->IsOk()) { // looks if the function exists elsewhere + pp = &(func->m_token); if (( pClass != nullptr || !pStack->CheckCall(pp, func->m_param)) && ( pClass == nullptr || !pClass->CheckCall(pStack->GetProgram(), func->m_param, pp)) ) { diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 5cd6c91a..789c68a4 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -719,6 +719,7 @@ void InitializeRestext() stringsCbot[CBot::CBotErrNoPublic] = TR("Public required"); stringsCbot[CBot::CBotErrNoExpression] = TR("Expression expected after ="); stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function"); + stringsCbot[CBot::CBotErrFuncNotVoid] = TR("Function needs return type \"void\""); stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero"); stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized"); diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index e456261b..ca9ff919 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -867,14 +867,13 @@ TEST_F(CBotUT, ClassNullPointer) ); } -// TODO: This doesn't work -TEST_F(CBotUT, DISABLED_ClassDestructorNaming) +TEST_F(CBotUT, ClassDestructorNaming) { ExecuteTest( "public class TestClass {\n" " public void ~SomethingElse() {}\n" "}\n", - static_cast(-1) // TODO: no error for that + CBotErrNoFunc ); ExecuteTest( "public class SomethingElse {\n" @@ -882,7 +881,26 @@ TEST_F(CBotUT, DISABLED_ClassDestructorNaming) "public class TestClass2 {\n" " public void ~SomethingElse() {}\n" "}\n", - static_cast(-1) // TODO: no error for that + CBotErrNoFunc + ); +} + +TEST_F(CBotUT, ClassDestructorSyntax) +{ + ExecuteTest( + "public class TestClass {\n" + " void ~TestClass(int i) {}\n" + "}\n" + "extern void DestructorNoParams() {}\n", + CBotErrClosePar + ); + + ExecuteTest( + "public class TestClass {\n" + " int ~TestClass() {}\n" + "}\n" + "extern void DestructorReturnTypeVoid() {}\n", + CBotErrFuncNotVoid ); } @@ -930,6 +948,39 @@ TEST_F(CBotUT, ClassMethodRedefined) "}\n", CBotErrRedefFunc ); + + ExecuteTest( + "public class TestClass {\n" + " void ~TestClass() {}\n" + " void ~TestClass() {}\n" + "}\n", + CBotErrRedefFunc + ); +} + +TEST_F(CBotUT, ClassFieldNaming) +{ + ExecuteTest( + "public class TestClass {\n" + " int ~i = 1;\n" + "}\n", + CBotErrNoVar + ); + + ExecuteTest( + "public class TestClass {\n" + " int TestClass = 1;\n" + "}\n", + CBotErrNoVar + ); + + ExecuteTest( + "public class TestClass {\n" + " int i = 1;\n" + " int i = 2;\n" + "}\n", + CBotErrRedefVar + ); } TEST_F(CBotUT, ClassRedefinedInDifferentPrograms) From 8e54f7ca9c32ed3fa599a9171ad046ecace9f67f Mon Sep 17 00:00:00 2001 From: melex750 Date: Mon, 16 Jan 2017 13:00:01 -0500 Subject: [PATCH 43/93] Fix memory leaks in CBOT engine --- src/CBot/CBotClass.cpp | 16 +++++++++++----- src/CBot/CBotInstr/CBotDefClass.cpp | 5 ++++- src/CBot/CBotInstr/CBotFunction.cpp | 1 + src/CBot/CBotInstr/CBotInstrCall.cpp | 2 ++ src/CBot/CBotInstr/CBotInstrMethode.cpp | 2 ++ src/CBot/CBotInstr/CBotNew.cpp | 3 +++ src/CBot/CBotStack.cpp | 4 ++-- src/CBot/CBotTypResult.cpp | 7 ++++++- src/CBot/CBotVar/CBotVar.cpp | 3 +++ 9 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index 127d6d34..c19cbf4b 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -83,7 +83,11 @@ CBotClass* CBotClass::Create(const std::string& name, //////////////////////////////////////////////////////////////////////////////// void CBotClass::ClearPublic() { - m_publicClasses.clear(); + while ( !m_publicClasses.empty() ) + { + auto it = m_publicClasses.begin(); + delete *it; // calling destructor removes the class from the list + } } //////////////////////////////////////////////////////////////////////////////// @@ -593,17 +597,16 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) else { // return a method precompiled in pass 1 - CBotToken* ppp = p; CBotCStack* pStk = pStack->TokenStack(nullptr, true); CBotDefParam* params = CBotDefParam::Compile(p, pStk ); delete pStk; - p = ppp; std::list::iterator pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, ¶ms](CBotFunction* x) { return x->GetName() == pp && x->CheckParam( params ); }); assert(pfIter != m_pMethod.end()); CBotFunction* pf = *pfIter; + delete params; bool bConstructor = (pp == GetName()); CBotCStack* pile = pStack->TokenStack(nullptr, true); @@ -690,7 +693,6 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) if (i == nullptr || pStack->GetType() != CBotTypInt) // must be a number { pStack->SetError(CBotErrBadIndex, p->GetStart()); - return false; } } else @@ -701,8 +703,9 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) if (limites == nullptr) limites = i; else limites->AddNext3(i); - if (IsOfType(p, ID_CLBRK)) continue; + if (pStack->IsOk() && IsOfType(p, ID_CLBRK)) continue; pStack->SetError(CBotErrCloseIndex, p->GetStart()); + delete limites; return false; } @@ -775,7 +778,10 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) } } else + { delete i; + delete limites; + } if ( IsOfType(p, ID_COMMA) ) continue; if ( IsOfType(p, ID_SEP) ) break; diff --git a/src/CBot/CBotInstr/CBotDefClass.cpp b/src/CBot/CBotInstr/CBotDefClass.cpp index 3fe832e5..bd885e10 100644 --- a/src/CBot/CBotInstr/CBotDefClass.cpp +++ b/src/CBot/CBotInstr/CBotDefClass.cpp @@ -51,6 +51,9 @@ CBotDefClass::CBotDefClass() //////////////////////////////////////////////////////////////////////////////// CBotDefClass::~CBotDefClass() { + delete m_parameters; + delete m_exprRetVar; + delete m_expr; delete m_var; } @@ -246,9 +249,9 @@ bool CBotDefClass::Execute(CBotStack* &pj) if (m_exprRetVar != nullptr) // Class c().method(); { - if (pile->IfStep()) return false; if (pile->GetState() == 4) { + if (pile->IfStep()) return false; CBotStack* pile3 = pile->AddStack(); if (!m_exprRetVar->Execute(pile3)) return false; pile3->SetVar(nullptr); diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 7852c7ef..ddbd3667 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -185,6 +185,7 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct } func->m_openpar = *p; + delete func->m_param; func->m_param = CBotDefParam::Compile(p, pStk ); func->m_closepar = *(p->GetPrev()); if (pStk->IsOk()) diff --git a/src/CBot/CBotInstr/CBotInstrCall.cpp b/src/CBot/CBotInstr/CBotInstrCall.cpp index 6b45bb52..86e37f72 100644 --- a/src/CBot/CBotInstr/CBotInstrCall.cpp +++ b/src/CBot/CBotInstr/CBotInstrCall.cpp @@ -36,6 +36,7 @@ namespace CBot CBotInstrCall::CBotInstrCall() { m_parameters = nullptr; + m_exprRetVar = nullptr; m_nFuncIdent = 0; } @@ -43,6 +44,7 @@ CBotInstrCall::CBotInstrCall() CBotInstrCall::~CBotInstrCall() { delete m_parameters; + delete m_exprRetVar; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/CBot/CBotInstr/CBotInstrMethode.cpp b/src/CBot/CBotInstr/CBotInstrMethode.cpp index 3a41802c..f4cda036 100644 --- a/src/CBot/CBotInstr/CBotInstrMethode.cpp +++ b/src/CBot/CBotInstr/CBotInstrMethode.cpp @@ -36,6 +36,7 @@ namespace CBot CBotInstrMethode::CBotInstrMethode() { m_parameters = nullptr; + m_exprRetVar = nullptr; m_MethodeIdent = 0; } @@ -43,6 +44,7 @@ CBotInstrMethode::CBotInstrMethode() CBotInstrMethode::~CBotInstrMethode() { delete m_parameters; + delete m_exprRetVar; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/CBot/CBotInstr/CBotNew.cpp b/src/CBot/CBotInstr/CBotNew.cpp index ddd50c69..9fab3824 100644 --- a/src/CBot/CBotInstr/CBotNew.cpp +++ b/src/CBot/CBotInstr/CBotNew.cpp @@ -36,12 +36,15 @@ namespace CBot CBotNew::CBotNew() { m_parameters = nullptr; + m_exprRetVar = nullptr; m_nMethodeIdent = 0; } //////////////////////////////////////////////////////////////////////////////// CBotNew::~CBotNew() { + delete m_parameters; + delete m_exprRetVar; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index 6afcc754..70ec5631 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -737,11 +737,11 @@ bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack) { unsigned short w; - pStack = nullptr; + if (pStack != this) pStack = nullptr; if (!ReadWord(pf, w)) return false; if ( w == 0 ) return true; // 0 - terminator - pStack = AddStack(); + if (pStack == nullptr) pStack = AddStack(); if ( w == 2 ) // 2 - m_next2 { diff --git a/src/CBot/CBotTypResult.cpp b/src/CBot/CBotTypResult.cpp index 46d42eef..d7005c2a 100644 --- a/src/CBot/CBotTypResult.cpp +++ b/src/CBot/CBotTypResult.cpp @@ -167,11 +167,16 @@ CBotTypResult& CBotTypResult::operator=(const CBotTypResult& src) m_type = src.m_type; m_limite = src.m_limite; m_class = src.m_class; - m_next = nullptr; if (src.m_next != nullptr ) { + delete m_next; m_next = new CBotTypResult(*src.m_next); } + else + { + delete m_next; + m_next = nullptr; + } return *this; } diff --git a/src/CBot/CBotVar/CBotVar.cpp b/src/CBot/CBotVar/CBotVar.cpp index 4e88cd69..7ea659f5 100644 --- a/src/CBot/CBotVar/CBotVar.cpp +++ b/src/CBot/CBotVar/CBotVar.cpp @@ -22,6 +22,7 @@ #include "CBot/CBotStack.h" +#include "CBot/CBotInstr/CBotInstr.h" #include "CBot/CBotVar/CBotVarArray.h" #include "CBot/CBotVar/CBotVarPointer.h" #include "CBot/CBotVar/CBotVarClass.h" @@ -70,6 +71,8 @@ CBotVar::CBotVar(const CBotToken &name) : CBotVar() CBotVar::~CBotVar( ) { delete m_token; + delete m_InitExpr; + delete m_LimExpr; } //////////////////////////////////////////////////////////////////////////////// From 2ff8251a811b6da93062bb885b8978afade0ef12 Mon Sep 17 00:00:00 2001 From: melex750 Date: Tue, 24 Jan 2017 13:47:00 -0500 Subject: [PATCH 44/93] Fix game crashing with syntax errors --- po/colobot.pot | 3 + po/de.po | 3 + po/fr.po | 3 + po/pl.po | 3 + po/ru.po | 3 + src/CBot/CBotClass.cpp | 25 ++++---- src/CBot/CBotDefParam.cpp | 10 ++-- src/CBot/CBotEnums.h | 1 + src/CBot/CBotInstr/CBotFunction.cpp | 15 +++-- src/CBot/CBotInstr/CBotListInstr.cpp | 2 +- src/CBot/CBotToken.cpp | 7 +++ src/common/restext.cpp | 1 + test/unit/CBot/CBotToken_test.cpp | 2 +- test/unit/CBot/CBot_test.cpp | 90 ++++++++++++++++++++++++++++ 14 files changed, 144 insertions(+), 24 deletions(-) diff --git a/po/colobot.pot b/po/colobot.pot index fd5c3de4..04eda131 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -1739,6 +1739,9 @@ msgstr "" msgid "Function needs return type \"void\"" msgstr "" +msgid "Class name expected" +msgstr "" + msgid "Dividing by zero" msgstr "" diff --git a/po/de.po b/po/de.po index e4c105af..440febf5 100644 --- a/po/de.po +++ b/po/de.po @@ -356,6 +356,9 @@ msgstr "" msgid "Checkpoint" msgstr "Checkpoint" +msgid "Class name expected" +msgstr "" + msgid "Climb\\Increases the power of the jet" msgstr "Steigen\\Leistung des Triebwerks steigern" diff --git a/po/fr.po b/po/fr.po index 905a0163..98c75496 100644 --- a/po/fr.po +++ b/po/fr.po @@ -346,6 +346,9 @@ msgstr "Console de triche\\Montre la console de triche" msgid "Checkpoint" msgstr "Indicateur" +msgid "Class name expected" +msgstr "" + msgid "Climb\\Increases the power of the jet" msgstr "Monter\\Augmenter la puissance du réacteur" diff --git a/po/pl.po b/po/pl.po index cd9f37c8..f298098a 100644 --- a/po/pl.po +++ b/po/pl.po @@ -348,6 +348,9 @@ msgstr "Konsola komend\\Pokaż konsolę komend" msgid "Checkpoint" msgstr "Punkt kontrolny" +msgid "Class name expected" +msgstr "" + msgid "Climb\\Increases the power of the jet" msgstr "W górę\\Zwiększa moc silnika" diff --git a/po/ru.po b/po/ru.po index 233cb300..4042a185 100644 --- a/po/ru.po +++ b/po/ru.po @@ -353,6 +353,9 @@ msgstr "Консоль чит-кодов\\Показать консоль для msgid "Checkpoint" msgstr "Контрольная точка" +msgid "Class name expected" +msgstr "" + msgid "Climb\\Increases the power of the jet" msgstr "Взлет и подъем\\Увеличивает мощность реактивного двигателя" diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index c19cbf4b..d787eb73 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -471,26 +471,27 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack) std::string name = p->GetString(); - CBotClass* pOld = CBotClass::Find(name); - if ( (pOld != nullptr && pOld->m_IsDef) || /* public class exists in different program */ - pStack->GetProgram()->ClassExists(name)) /* class exists in this program */ - { - pStack->SetError( CBotErrRedefClass, p ); - return nullptr; - } - // a name of the class is there? if (IsOfType(p, TokenTypVar)) { + CBotClass* pOld = CBotClass::Find(name); + if ((pOld != nullptr && pOld->m_IsDef) || /* public class exists in different program */ + pStack->GetProgram()->ClassExists(name)) /* class exists in this program */ + { + pStack->SetError(CBotErrRedefClass, p->GetPrev()); + return nullptr; + } + CBotClass* pPapa = nullptr; if ( IsOfType( p, ID_EXTENDS ) ) { std::string name = p->GetString(); pPapa = CBotClass::Find(name); + CBotToken* pp = p; if (!IsOfType(p, TokenTypVar) || pPapa == nullptr ) { - pStack->SetError( CBotErrNotClass, p ); + pStack->SetError(CBotErrNoClassName, pp); return nullptr; } } @@ -519,6 +520,9 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack) if (pStack->IsOk()) return classe; } + else + pStack->SetError(CBotErrNoClassName, p); + pStack->SetError(CBotErrNoTerminator, p); return nullptr; } @@ -810,10 +814,11 @@ CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack) // TODO: Not sure how correct is that - I have no idea how the precompilation (Compile1 method) works ~krzys_h std::string name = p->GetString(); CBotClass* pPapa = CBotClass::Find(name); + CBotToken* pp = p; if (!IsOfType(p, TokenTypVar) || pPapa == nullptr) { - pStack->SetError( CBotErrNotClass, p ); + pStack->SetError(CBotErrNoClassName, pp); return nullptr; } pOld->m_parent = pPapa; diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp index ff4acf1f..e66c8622 100644 --- a/src/CBot/CBotDefParam.cpp +++ b/src/CBot/CBotDefParam.cpp @@ -52,7 +52,7 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) { CBotDefParam* list = nullptr; - while (!IsOfType(p, ID_CLOSEPAR)) + if (!IsOfType(p, ID_CLOSEPAR)) while (true) { CBotDefParam* param = new CBotDefParam(); if (list == nullptr) list = param; @@ -85,10 +85,12 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) var->SetUniqNum(param->m_nIdent); pStack->AddVar(var); // place on the stack - if (IsOfType(p, ID_COMMA) || p->GetType() == ID_CLOSEPAR) - continue; + if (IsOfType(p, ID_COMMA)) continue; + if (IsOfType(p, ID_CLOSEPAR)) break; + + pStack->SetError(CBotErrClosePar, p->GetStart()); } - pStack->SetError(CBotErrClosePar, p->GetStart()); + pStack->SetError(CBotErrNoVar, p->GetStart()); } pStack->SetError(CBotErrNoType, p); delete list; diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h index b7453e59..a34c9e7c 100644 --- a/src/CBot/CBotEnums.h +++ b/src/CBot/CBotEnums.h @@ -238,6 +238,7 @@ enum CBotError : int CBotErrNoExpression = 5043, //!< expression expected after = CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function CBotErrFuncNotVoid = 5045, //!< function needs return type "void" + CBotErrNoClassName = 5046, //!< class name expected // Runtime errors CBotErrZeroDiv = 6000, //!< division by zero diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index ddbd3667..f08ddd9e 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -177,7 +177,11 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct func->m_MasterClass = pp->GetString(); func->m_classToken = *pp; CBotClass* pClass = CBotClass::Find(pp); - if ( pClass == nullptr ) goto bad; + if ( pClass == nullptr ) + { + pStk->SetError(CBotErrNoClassName, pp); + goto bad; + } // pp = p; func->m_token = *p; @@ -280,13 +284,8 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class { func->m_MasterClass = pp->GetString(); - CBotClass* pClass = CBotClass::Find(pp); - if ( pClass == nullptr ) - { - pStk->SetError(CBotErrNotClass, pp); - goto bad; - } - + // existence of the class is checked + // later in CBotFunction::Compile() pp = p; func->m_token = *p; if (!IsOfType(p, TokenTypVar)) goto bad; diff --git a/src/CBot/CBotInstr/CBotListInstr.cpp b/src/CBot/CBotInstr/CBotListInstr.cpp index 58413a42..0ae396f5 100644 --- a/src/CBot/CBotInstr/CBotListInstr.cpp +++ b/src/CBot/CBotInstr/CBotListInstr.cpp @@ -52,7 +52,7 @@ CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal if (IsOfType(p, ID_SEP)) continue; // empty statement ignored if (p->GetType() == ID_CLBLK) break; - if (IsOfType(p, 0)) + if (p->GetType() == TokenTypNone) { pStack->SetError(CBotErrCloseBlock, p->GetStart()); delete inst; diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp index 28e6690c..e10901eb 100644 --- a/src/CBot/CBotToken.cpp +++ b/src/CBot/CBotToken.cpp @@ -439,6 +439,13 @@ std::unique_ptr CBotToken::CompileTokens(const std::string& program) pp = p; } + // terminator token + nxt = new CBotToken(); + nxt->m_type = TokenTypNone; + nxt->m_end = nxt->m_start = pos; + prv->m_next = nxt; + nxt->m_prev = prv; + return std::unique_ptr(tokenbase); } diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 789c68a4..93bab6c7 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -720,6 +720,7 @@ void InitializeRestext() stringsCbot[CBot::CBotErrNoExpression] = TR("Expression expected after ="); stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function"); stringsCbot[CBot::CBotErrFuncNotVoid] = TR("Function needs return type \"void\""); + stringsCbot[CBot::CBotErrNoClassName] = TR("Class name expected"); stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero"); stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized"); diff --git a/test/unit/CBot/CBotToken_test.cpp b/test/unit/CBot/CBotToken_test.cpp index b51ca93e..a36841a5 100644 --- a/test/unit/CBot/CBotToken_test.cpp +++ b/test/unit/CBot/CBotToken_test.cpp @@ -60,7 +60,7 @@ protected: ASSERT_EQ(token->GetType(), correct.type) << "type mismatch at token #" << (i+1); i++; } - while((token = token->GetNext()) != nullptr); + while((token = token->GetNext()) != nullptr && !IsOfType(token, TokenTypNone)); ASSERT_EQ(i, data.size()) << "not enough tokens processed"; } }; diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index ca9ff919..71455e28 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -298,6 +298,96 @@ TEST_F(CBotUT, EmptyTest) ); } +TEST_F(CBotUT, FunctionCompileErrors) +{ + ExecuteTest( + "public", + CBotErrNoType + ); + + ExecuteTest( + "extern", + CBotErrNoType + ); + + ExecuteTest( + "public void", + CBotErrNoFunc + ); + + ExecuteTest( + "extern void", + CBotErrNoFunc + ); + + ExecuteTest( + "extern void MissingParameterType(", + CBotErrNoType + ); + + ExecuteTest( + "extern void MissingParamName(int", + CBotErrNoVar + ); + + ExecuteTest( + "extern void MissingCloseParen(int i", + CBotErrClosePar + ); + + ExecuteTest( + "extern void ParamTrailingComma(int i, ) {\n" + "}\n", + CBotErrNoType + ); + + ExecuteTest( + "extern void MissingOpenBlock(int i)", + CBotErrOpenBlock + ); + + ExecuteTest( + "extern void MissingCloseBlock()\n" + "{\n", + CBotErrCloseBlock + ); + +} + +TEST_F(CBotUT, ClassCompileErrors) +{ + ExecuteTest( + "public class", + CBotErrNoClassName + ); + + ExecuteTest( + "public class 1234", + CBotErrNoClassName + ); + + ExecuteTest( + "public class TestClass", + CBotErrOpenBlock + ); + + ExecuteTest( + "public class TestClass\n" + "{\n", + CBotErrCloseBlock + ); + + ExecuteTest( + "public class TestClass extends", + CBotErrNoClassName + ); + + ExecuteTest( + "public class TestClass extends 1234", + CBotErrNoClassName + ); +} + TEST_F(CBotUT, DivideByZero) { ExecuteTest( From baba6081b34f1c5a1fcf80ce75ec8e419e45973e Mon Sep 17 00:00:00 2001 From: melex750 Date: Tue, 24 Jan 2017 14:41:22 -0500 Subject: [PATCH 45/93] Add checking for return statements in functions issue #30 --- po/colobot.pot | 3 ++ po/de.po | 3 ++ po/fr.po | 3 ++ po/pl.po | 3 ++ po/ru.po | 3 ++ src/CBot/CBotEnums.h | 1 + src/CBot/CBotInstr/CBotFunction.cpp | 12 +++++++ src/CBot/CBotInstr/CBotFunction.h | 6 ++++ src/CBot/CBotInstr/CBotIf.cpp | 9 ++++++ src/CBot/CBotInstr/CBotIf.h | 8 +++++ src/CBot/CBotInstr/CBotInstr.cpp | 7 +++++ src/CBot/CBotInstr/CBotInstr.h | 6 ++++ src/CBot/CBotInstr/CBotListInstr.cpp | 6 ++++ src/CBot/CBotInstr/CBotListInstr.h | 7 +++++ src/CBot/CBotInstr/CBotReturn.cpp | 5 +++ src/CBot/CBotInstr/CBotReturn.h | 6 ++++ src/common/restext.cpp | 1 + test/unit/CBot/CBot_test.cpp | 47 ++++++++++++++++++++++++++-- 18 files changed, 133 insertions(+), 3 deletions(-) diff --git a/po/colobot.pot b/po/colobot.pot index 04eda131..72b447ac 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -1742,6 +1742,9 @@ msgstr "" msgid "Class name expected" msgstr "" +msgid "Non-void function needs \"return;\"" +msgstr "" + msgid "Dividing by zero" msgstr "" diff --git a/po/de.po b/po/de.po index 440febf5..cdcc3f39 100644 --- a/po/de.po +++ b/po/de.po @@ -942,6 +942,9 @@ msgstr "Kein konvertierbares Platin" msgid "No userlevels installed!" msgstr "" +msgid "Non-void function needs \"return;\"" +msgstr "" + msgid "Normal size" msgstr "Normale Größe" diff --git a/po/fr.po b/po/fr.po index 98c75496..71b45fb2 100644 --- a/po/fr.po +++ b/po/fr.po @@ -924,6 +924,9 @@ msgstr "Pas d'uranium à transformer" msgid "No userlevels installed!" msgstr "Pas de niveaux spéciaux installés !" +msgid "Non-void function needs \"return;\"" +msgstr "" + msgid "Normal size" msgstr "Taille normale" diff --git a/po/pl.po b/po/pl.po index f298098a..19b0f2b7 100644 --- a/po/pl.po +++ b/po/pl.po @@ -926,6 +926,9 @@ msgstr "Brak uranu do przetworzenia" msgid "No userlevels installed!" msgstr "Brak zainstalowanych poziomów użytkownika!" +msgid "Non-void function needs \"return;\"" +msgstr "" + msgid "Normal size" msgstr "Normalna wielkość" diff --git a/po/ru.po b/po/ru.po index 4042a185..c8ed6048 100644 --- a/po/ru.po +++ b/po/ru.po @@ -935,6 +935,9 @@ msgstr "Нет урана для преобразования" msgid "No userlevels installed!" msgstr "Не установленны пользовательские уровни!" +msgid "Non-void function needs \"return;\"" +msgstr "" + msgid "Normal size" msgstr "Нормальный размер" diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h index a34c9e7c..22022c77 100644 --- a/src/CBot/CBotEnums.h +++ b/src/CBot/CBotEnums.h @@ -239,6 +239,7 @@ enum CBotError : int CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function CBotErrFuncNotVoid = 5045, //!< function needs return type "void" CBotErrNoClassName = 5046, //!< class name expected + CBotErrNoReturn = 5047, //!< non-void function needs "return;" // Runtime errors CBotErrZeroDiv = 6000, //!< division by zero diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index f08ddd9e..78d55fb5 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -228,6 +228,12 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct func->m_closeblk = (p != nullptr && p->GetPrev() != nullptr) ? *(p->GetPrev()) : CBotToken(); if ( pStk->IsOk() ) { + if (!func->m_retTyp.Eq(CBotTypVoid) && !func->HasReturn()) + { + int errPos = func->m_closeblk.GetStart(); + pStk->ResetError(CBotErrNoReturn, errPos, errPos); + goto bad; + } return pStack->ReturnFunc(func, pStk); } } @@ -938,6 +944,12 @@ void CBotFunction::AddPublic(CBotFunction* func) m_publicFunctions.insert(func); } +bool CBotFunction::HasReturn() +{ + if (m_block != nullptr) return m_block->HasReturn(); + return false; +} + std::string CBotFunction::GetDebugData() { std::stringstream ss; diff --git a/src/CBot/CBotInstr/CBotFunction.h b/src/CBot/CBotInstr/CBotFunction.h index bab5e2bb..a23e2fd5 100644 --- a/src/CBot/CBotInstr/CBotFunction.h +++ b/src/CBot/CBotInstr/CBotFunction.h @@ -235,6 +235,12 @@ public: CBotGet modestart, CBotGet modestop); + /*! + * \brief Check if the function has a return statment that will execute. + * \return true if a return statment was found. + */ + bool HasReturn() override; + protected: virtual const std::string GetDebugName() override { return "CBotFunction"; } virtual std::string GetDebugData() override; diff --git a/src/CBot/CBotInstr/CBotIf.cpp b/src/CBot/CBotInstr/CBotIf.cpp index c0a1d1ee..92da9b48 100644 --- a/src/CBot/CBotInstr/CBotIf.cpp +++ b/src/CBot/CBotInstr/CBotIf.cpp @@ -163,6 +163,15 @@ void CBotIf :: RestoreState(CBotStack* &pj, bool bMain) } } +bool CBotIf::HasReturn() +{ + if (m_block != nullptr && m_blockElse != nullptr) + { + if (m_block->HasReturn() && m_blockElse->HasReturn()) return true; + } + return CBotInstr::HasReturn(); // check next block or instruction +} + std::map CBotIf::GetDebugLinks() { auto links = CBotInstr::GetDebugLinks(); diff --git a/src/CBot/CBotInstr/CBotIf.h b/src/CBot/CBotInstr/CBotIf.h index 94b2d257..3df400e1 100644 --- a/src/CBot/CBotInstr/CBotIf.h +++ b/src/CBot/CBotInstr/CBotIf.h @@ -56,6 +56,14 @@ public: */ void RestoreState(CBotStack* &pj, bool bMain) override; + /** + * \brief Check 'if' and 'else' for return statements. + * Returns true when 'if' and 'else' have return statements, + * if not, the next block or instruction is checked. + * \return true if a return statement is found. + */ + bool HasReturn() override; + protected: virtual const std::string GetDebugName() override { return "CBotIf"; } virtual std::map GetDebugLinks() override; diff --git a/src/CBot/CBotInstr/CBotInstr.cpp b/src/CBot/CBotInstr/CBotInstr.cpp index 2ae04233..1d30f673 100644 --- a/src/CBot/CBotInstr/CBotInstr.cpp +++ b/src/CBot/CBotInstr/CBotInstr.cpp @@ -359,6 +359,13 @@ CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypRes return nullptr; } +bool CBotInstr::HasReturn() +{ + assert(this != nullptr); + if (m_next != nullptr) return m_next->HasReturn(); + return false; // end of the list +} + std::map CBotInstr::GetDebugLinks() { return { diff --git a/src/CBot/CBotInstr/CBotInstr.h b/src/CBot/CBotInstr/CBotInstr.h index ab991366..a96550db 100644 --- a/src/CBot/CBotInstr/CBotInstr.h +++ b/src/CBot/CBotInstr/CBotInstr.h @@ -281,6 +281,12 @@ public: */ static bool ChkLvl(const std::string& label, int type); + /** + * \brief Check a list of instructions for a return statement. + * \return true if a return statement was found. + */ + virtual bool HasReturn(); + protected: friend class CBotDebug; /** diff --git a/src/CBot/CBotInstr/CBotListInstr.cpp b/src/CBot/CBotInstr/CBotListInstr.cpp index 0ae396f5..bcbd3bba 100644 --- a/src/CBot/CBotInstr/CBotListInstr.cpp +++ b/src/CBot/CBotInstr/CBotListInstr.cpp @@ -117,6 +117,12 @@ void CBotListInstr::RestoreState(CBotStack* &pj, bool bMain) if (p != nullptr) p->RestoreState(pile, true); } +bool CBotListInstr::HasReturn() +{ + if (m_instr != nullptr && m_instr->HasReturn()) return true; + return CBotInstr::HasReturn(); // check next block or instruction +} + std::map CBotListInstr::GetDebugLinks() { auto links = CBotInstr::GetDebugLinks(); diff --git a/src/CBot/CBotInstr/CBotListInstr.h b/src/CBot/CBotInstr/CBotListInstr.h index e0923e04..659784f6 100644 --- a/src/CBot/CBotInstr/CBotListInstr.h +++ b/src/CBot/CBotInstr/CBotListInstr.h @@ -56,6 +56,13 @@ public: */ void RestoreState(CBotStack* &pj, bool bMain) override; + /** + * \brief Check this block of instructions for a return statement. + * If not found, the next block or instruction is checked. + * \return true if a return statement was found. + */ + bool HasReturn() override; + protected: virtual const std::string GetDebugName() override { return "CBotListInstr"; } virtual std::map GetDebugLinks() override; diff --git a/src/CBot/CBotInstr/CBotReturn.cpp b/src/CBot/CBotInstr/CBotReturn.cpp index acbd3d8e..5979989e 100644 --- a/src/CBot/CBotInstr/CBotReturn.cpp +++ b/src/CBot/CBotInstr/CBotReturn.cpp @@ -111,6 +111,11 @@ void CBotReturn::RestoreState(CBotStack* &pj, bool bMain) } } +bool CBotReturn::HasReturn() +{ + return true; +} + std::map CBotReturn::GetDebugLinks() { auto links = CBotInstr::GetDebugLinks(); diff --git a/src/CBot/CBotInstr/CBotReturn.h b/src/CBot/CBotInstr/CBotReturn.h index 237571a3..9d14a3e9 100644 --- a/src/CBot/CBotInstr/CBotReturn.h +++ b/src/CBot/CBotInstr/CBotReturn.h @@ -55,6 +55,12 @@ public: */ void RestoreState(CBotStack* &pj, bool bMain) override; + /*! + * \brief Always returns true. + * \return true to signal a return statment has been found. + */ + bool HasReturn() override; + protected: virtual const std::string GetDebugName() override { return "CBotReturn"; } virtual std::map GetDebugLinks() override; diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 93bab6c7..5d1f012f 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -721,6 +721,7 @@ void InitializeRestext() stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function"); stringsCbot[CBot::CBotErrFuncNotVoid] = TR("Function needs return type \"void\""); stringsCbot[CBot::CBotErrNoClassName] = TR("Class name expected"); + stringsCbot[CBot::CBotErrNoReturn] = TR("Non-void function needs \"return;\""); stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero"); stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized"); diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 71455e28..1d02b8a0 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -801,8 +801,7 @@ TEST_F(CBotUT, FunctionBadReturn) ); } -// TODO: Doesn't work -TEST_F(CBotUT, DISABLED_FunctionNoReturn) +TEST_F(CBotUT, FunctionNoReturn) { ExecuteTest( "int func()\n" @@ -812,7 +811,49 @@ TEST_F(CBotUT, DISABLED_FunctionNoReturn) "{\n" " func();\n" "}\n", - static_cast(-1) // TODO: no error for that + CBotErrNoReturn + ); + + ExecuteTest( + "int FuncDoesNotReturnAValue()\n" + "{\n" + " if (false) return 1;\n" + " while (false) return 1;\n" + " if (true) ; else return 1;\n" + " do { break; return 1; } while (false);\n" + " do { continue; return 1; } while (false);\n" + "}\n", + CBotErrNoReturn + ); + + ExecuteTest( + "int FuncHasReturn()\n" + "{\n" + " return 1;\n" + "}\n" + "int BlockHasReturn()\n" + "{\n" + " {\n" + " {\n" + " }\n" + " return 2;\n" + " }\n" + "}\n" + "int IfElseHasReturn()\n" + "{\n" + " if (false) {\n" + " return 3;\n" + " } else {\n" + " if (false) return 3;\n" + " else return 3;\n" + " }\n" + "}\n" + "extern void Test()\n" + "{\n" + " ASSERT(1 == FuncHasReturn());\n" + " ASSERT(2 == BlockHasReturn());\n" + " ASSERT(3 == IfElseHasReturn());\n" + "}\n" ); } From 92a8c48953460a9b7aaf05e3bb3153f6451753a7 Mon Sep 17 00:00:00 2001 From: melex750 Date: Tue, 24 Jan 2017 15:19:03 -0500 Subject: [PATCH 46/93] Add syntax for parameters with default values Also fixes #642 --- po/colobot.pot | 3 ++ po/de.po | 3 ++ po/fr.po | 3 ++ po/pl.po | 3 ++ po/ru.po | 3 ++ src/CBot/CBotDefParam.cpp | 74 ++++++++++++++++++++++---- src/CBot/CBotDefParam.h | 9 ++++ src/CBot/CBotEnums.h | 1 + src/CBot/CBotInstr/CBotFunction.cpp | 32 +++++++++-- src/CBot/CBotInstr/CBotNew.cpp | 2 +- src/CBot/CBotInstr/CBotParExpr.cpp | 10 ++++ src/CBot/CBotInstr/CBotParExpr.h | 8 +++ src/common/restext.cpp | 1 + test/unit/CBot/CBot_test.cpp | 82 ++++++++++++++++++++++++++++- 14 files changed, 218 insertions(+), 16 deletions(-) diff --git a/po/colobot.pot b/po/colobot.pot index 72b447ac..30a4c1c8 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -1745,6 +1745,9 @@ msgstr "" msgid "Non-void function needs \"return;\"" msgstr "" +msgid "This parameter needs a default value" +msgstr "" + msgid "Dividing by zero" msgstr "" diff --git a/po/de.po b/po/de.po index cdcc3f39..255608e3 100644 --- a/po/de.po +++ b/po/de.po @@ -1522,6 +1522,9 @@ msgstr "" msgid "This object is not a member of a class" msgstr "Das Objekt ist nicht eine Instanz einer Klasse" +msgid "This parameter needs a default value" +msgstr "" + msgid "This program is read-only, clone it to edit" msgstr "" diff --git a/po/fr.po b/po/fr.po index 71b45fb2..818948a0 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1494,6 +1494,9 @@ msgstr "" msgid "This object is not a member of a class" msgstr "L'objet n'est pas une instance d'une classe" +msgid "This parameter needs a default value" +msgstr "" + msgid "This program is read-only, clone it to edit" msgstr "Ce programme est en lecture-seule, le dupliquer pour pouvoir l'éditer" diff --git a/po/pl.po b/po/pl.po index 19b0f2b7..aaa50b8a 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1496,6 +1496,9 @@ msgstr "Ten objekt jest obecnie zajęty" msgid "This object is not a member of a class" msgstr "Ten obiekt nie jest członkiem klasy" +msgid "This parameter needs a default value" +msgstr "" + msgid "This program is read-only, clone it to edit" msgstr "Ten program jest tylko do odczytu, skopiuj go, aby edytować" diff --git a/po/ru.po b/po/ru.po index c8ed6048..f479b47e 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1510,6 +1510,9 @@ msgstr "" msgid "This object is not a member of a class" msgstr "Этот объект не член класса" +msgid "This parameter needs a default value" +msgstr "" + msgid "This program is read-only, clone it to edit" msgstr "Эта программа только для чтения, для редактирования клонируйте её" diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp index e66c8622..8b54f5a1 100644 --- a/src/CBot/CBotDefParam.cpp +++ b/src/CBot/CBotDefParam.cpp @@ -19,6 +19,9 @@ #include "CBot/CBotDefParam.h" +#include "CBot/CBotInstr/CBotInstrUtils.h" +#include "CBot/CBotInstr/CBotParExpr.h" + #include "CBot/CBotUtils.h" #include "CBot/CBotCStack.h" @@ -33,11 +36,13 @@ namespace CBot CBotDefParam::CBotDefParam() { m_nIdent = 0; + m_expr = nullptr; } //////////////////////////////////////////////////////////////////////////////// CBotDefParam::~CBotDefParam() { + delete m_expr; } //////////////////////////////////////////////////////////////////////////////// @@ -51,6 +56,7 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) if (IsOfType(p, ID_OPENPAR)) { CBotDefParam* list = nullptr; + bool prevHasDefault = false; if (!IsOfType(p, ID_CLOSEPAR)) while (true) { @@ -77,6 +83,26 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) break; } + if (IsOfType(p, ID_ASS)) // default value assignment + { + CBotCStack* pStk = pStack->TokenStack(nullptr, true); + if (nullptr != (param->m_expr = CBotParExpr::CompileLitExpr(p, pStk))) + { + CBotTypResult valueType = pStk->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); + + if (!TypesCompatibles(type, valueType)) + pStack->SetError(CBotErrBadType1, p->GetPrev()); + + prevHasDefault = true; + } + else pStack->SetError(CBotErrNoExpression, p); + delete pStk; + } + else + if (prevHasDefault) pStack->SetError(CBotErrDefaultValue, p->GetPrev()); + + if (!pStack->IsOk()) break; + if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody); CBotVar* var = CBotVar::Create(pp->GetString(), type); // creates the variable // if ( pClass ) var->SetClass(pClass); @@ -109,40 +135,63 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) assert(this != nullptr); CBotDefParam* p = this; + bool useDefault = false; + while ( p != nullptr ) { // creates a local variable on the stack CBotVar* newvar = CBotVar::Create(p->m_token.GetString(), p->m_type); + CBotVar* pVar = nullptr; + CBotStack* pile = nullptr; // stack for default expression + + if (useDefault || (ppVars == nullptr || ppVars[i] == nullptr)) + { + assert(p->m_expr != nullptr); + + pile = pj->AddStack(); + useDefault = true; + + while (pile->IsOk() && !p->m_expr->Execute(pile)); + if (!pile->IsOk()) return pj->Return(pile); // return the error + + pVar = pile->GetVar(); + } + else + pVar = ppVars[i]; + // serves to make the transformation of types: - if ( ppVars != nullptr && ppVars[i] != nullptr ) + if ((useDefault && pVar != nullptr) || + (ppVars != nullptr && pVar != nullptr)) { switch (p->m_type.GetType()) { case CBotTypInt: - newvar->SetValInt(ppVars[i]->GetValInt()); + newvar->SetValInt(pVar->GetValInt()); + newvar->SetInit(pVar->GetInit()); // copy nan break; case CBotTypFloat: - newvar->SetValFloat(ppVars[i]->GetValFloat()); + newvar->SetValFloat(pVar->GetValFloat()); + newvar->SetInit(pVar->GetInit()); // copy nan break; case CBotTypString: - newvar->SetValString(ppVars[i]->GetValString()); + newvar->SetValString(pVar->GetValString()); break; case CBotTypBoolean: - newvar->SetValInt(ppVars[i]->GetValInt()); + newvar->SetValInt(pVar->GetValInt()); break; case CBotTypIntrinsic: - (static_cast(newvar))->Copy(ppVars[i], false); + (static_cast(newvar))->Copy(pVar, false); break; case CBotTypPointer: { - newvar->SetPointer(ppVars[i]->GetPointer()); + newvar->SetPointer(pVar->GetPointer()); newvar->SetType(p->m_type); // keep pointer type } break; case CBotTypArrayPointer: { - newvar->SetPointer(ppVars[i]->GetPointer()); + newvar->SetPointer(pVar->GetPointer()); } break; default: @@ -152,12 +201,19 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) newvar->SetUniqNum(p->m_nIdent); pj->AddVar(newvar); // add a variable p = p->m_next; - i++; + if (!useDefault) i++; + if (pile != nullptr) pile->Delete(); } return true; } +//////////////////////////////////////////////////////////////////////////////// +bool CBotDefParam::HasDefault() +{ + return (m_expr != nullptr); +} + //////////////////////////////////////////////////////////////////////////////// void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain) { diff --git a/src/CBot/CBotDefParam.h b/src/CBot/CBotDefParam.h index c23855db..bc9d9d0a 100644 --- a/src/CBot/CBotDefParam.h +++ b/src/CBot/CBotDefParam.h @@ -63,6 +63,12 @@ public: */ bool Execute(CBotVar** ppVars, CBotStack* &pj); + /*! + * \brief Check if this parameter has a default value expression. + * \return true if the parameter was compiled with a default value. + */ + bool HasDefault(); + /*! * \brief RestoreState * \param pj @@ -96,6 +102,9 @@ private: //! Type of paramteter. CBotTypResult m_type; long m_nIdent; + + //! Default value expression for the parameter. + CBotInstr* m_expr; }; } // namespace CBot diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h index 22022c77..f98d4e96 100644 --- a/src/CBot/CBotEnums.h +++ b/src/CBot/CBotEnums.h @@ -240,6 +240,7 @@ enum CBotError : int CBotErrFuncNotVoid = 5045, //!< function needs return type "void" CBotErrNoClassName = 5046, //!< class name expected CBotErrNoReturn = 5047, //!< non-void function needs "return;" + CBotErrDefaultValue = 5048, //!< this parameter needs a default value // Runtime errors CBotErrZeroDiv = 6000, //!< division by zero diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 78d55fb5..0f6a9800 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -503,8 +503,13 @@ CBotFunction* CBotFunction::FindLocalOrPublic(const std::list& lo // parameters are compatible? CBotDefParam* pv = pt->m_param; // expected list of parameters CBotVar* pw = ppVars[i++]; // provided list parameter - while ( pv != nullptr && pw != nullptr) + while ( pv != nullptr && (pw != nullptr || pv->HasDefault()) ) { + if (pw == nullptr) // end of arguments + { + pv = pv->GetNext(); + continue; // skip params with default values + } CBotTypResult paramType = pv->GetTypResult(); CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); @@ -561,8 +566,13 @@ CBotFunction* CBotFunction::FindLocalOrPublic(const std::list& lo // parameters sont-ils compatibles ? CBotDefParam* pv = pt->m_param; // list of expected parameters CBotVar* pw = ppVars[i++]; // list of provided parameters - while ( pv != nullptr && pw != nullptr) + while ( pv != nullptr && (pw != nullptr || pv->HasDefault()) ) { + if (pw == nullptr) // end of arguments + { + pv = pv->GetNext(); + continue; // skip params with default values + } CBotTypResult paramType = pv->GetTypResult(); CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); @@ -690,7 +700,14 @@ int CBotFunction::DoCall(CBotProgram* program, const std::list& l // initializes the variables as parameters if (pt->m_param != nullptr) { - pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted + if (!pt->m_param->Execute(ppVars, pStk3)) // interupts only if error on a default value + { + if ( pt->m_pProg != program ) + { + pStk3->SetPosError(pToken); // indicates the error on the procedure call + } + return pStack->Return(pStk3); + } } pStk1->IncState(); @@ -812,7 +829,14 @@ int CBotFunction::DoCall(const std::list& localFunctionList, long // initializes the variables as parameters if (pt->m_param != nullptr) { - pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted + if (!pt->m_param->Execute(ppVars, pStk3)) // interupts only if error on a default value + { + if ( pt->m_pProg != pProgCurrent ) + { + pStk3->SetPosError(pToken); // indicates the error on the procedure call + } + return pStack->Return(pStk3); + } } pStk->IncState(); } diff --git a/src/CBot/CBotInstr/CBotNew.cpp b/src/CBot/CBotInstr/CBotNew.cpp index 9fab3824..1c84dc53 100644 --- a/src/CBot/CBotInstr/CBotNew.cpp +++ b/src/CBot/CBotInstr/CBotNew.cpp @@ -200,7 +200,7 @@ bool CBotNew::Execute(CBotStack* &pj) } ppVars[i] = nullptr; - if ( !pClass->ExecuteMethode(m_nMethodeIdent, pThis, ppVars, CBotTypResult(CBotTypVoid), pile2, GetToken())) return false; // interrupt + if ( !pClass->ExecuteMethode(m_nMethodeIdent, pThis, ppVars, CBotTypResult(CBotTypVoid), pile2, &m_vartoken)) return false; // interrupt pThis->ConstructorSet(); // indicates that the constructor has been called } diff --git a/src/CBot/CBotInstr/CBotParExpr.cpp b/src/CBot/CBotInstr/CBotParExpr.cpp index a32363fb..b0c2f1c1 100644 --- a/src/CBot/CBotInstr/CBotParExpr.cpp +++ b/src/CBot/CBotInstr/CBotParExpr.cpp @@ -132,6 +132,16 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) return pStack->Return(nullptr, pStk); } + return CompileLitExpr(p, pStack); +} + +//////////////////////////////////////////////////////////////////////////////// +CBotInstr* CBotParExpr::CompileLitExpr(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + CBotToken* pp = p; + // is it a number or DefineNum? if (p->GetType() == TokenTypNum || p->GetType() == TokenTypDef ) diff --git a/src/CBot/CBotInstr/CBotParExpr.h b/src/CBot/CBotInstr/CBotParExpr.h index cd92467b..0bcdd0e1 100644 --- a/src/CBot/CBotInstr/CBotParExpr.h +++ b/src/CBot/CBotInstr/CBotParExpr.h @@ -54,6 +54,14 @@ public: */ static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + /*! + * \brief Compile a literal expression ("string", number, true, false, null, nan, new) + * \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression + * \param pStack Current compilation stack frame + * \return The compiled instruction or nullptr on error + */ + static CBotInstr* CompileLitExpr(CBotToken* &p, CBotCStack* pStack); + private: CBotParExpr() = delete; CBotParExpr(const CBotParExpr&) = delete; diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 5d1f012f..035389b4 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -722,6 +722,7 @@ void InitializeRestext() stringsCbot[CBot::CBotErrFuncNotVoid] = TR("Function needs return type \"void\""); stringsCbot[CBot::CBotErrNoClassName] = TR("Class name expected"); stringsCbot[CBot::CBotErrNoReturn] = TR("Non-void function needs \"return;\""); + stringsCbot[CBot::CBotErrDefaultValue] = TR("This parameter needs a default value"); stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero"); stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized"); diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 1d02b8a0..2f8bb503 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -1594,11 +1594,12 @@ TEST_F(CBotUT, StringFunctions) ); } -TEST_F(CBotUT, DISABLED_TestNANParam_Issue642) +TEST_F(CBotUT, TestNANParam_Issue642) { ExecuteTest( "float test(float x) {\n" - " return x;\n" + " ASSERT(x == nan);\n" + " return x;\n" "}\n" "extern void TestNANParam() {\n" " ASSERT(nan == nan);\n" // TODO: Shouldn't it be nan != nan ?? @@ -2308,3 +2309,80 @@ TEST_F(CBotUT, IncrementDecrementSyntax) CBotErrBadType1 ); } + +TEST_F(CBotUT, ParametersWithDefaultValues) +{ + ExecuteTest( + "extern void ParametersWithDefaultValues() {\n" + " ASSERT(true == Test());\n" + " ASSERT(true == Test(1));\n" + " ASSERT(true == Test(1, 2));\n" + "}\n" + "bool Test(int i = 1, float f = 2.0) {\n" + " return (i == 1) && (f == 2.0);\n" + "}\n" + ); + + ExecuteTest( + "extern void NotUsingDefaultValues() {\n" + " ASSERT(true == Test(2, 4.0));\n" + "}\n" + "bool Test(int i = 1, float f = 2.0) {\n" + " return (i == 2) && (f == 4.0);\n" + "}\n" + ); + + ExecuteTest( + "extern void NextParamNeedsDefaultValue() {\n" + "}\n" + "void Test(int i = 1, float f) {}\n" + "\n", + CBotErrDefaultValue + ); + + ExecuteTest( + "extern void ParamMissingExpression() {\n" + "}\n" + "void Test(int i = 1, float f = ) {}\n" + "\n", + CBotErrNoExpression + ); + + ExecuteTest( + "extern void ParamDefaultBadType() {\n" + "}\n" + "void Test(int i = 1, float f = null) {}\n" + "\n", + CBotErrBadType1 + ); + + ExecuteTest( + "extern void DefaultValuesAmbiguousCall() {\n" + " Test();\n" + "}\n" + "void Test(int i = 1) {}\n" + "void Test(float f = 2.0) {}\n" + "\n", + CBotErrAmbiguousCall + ); + + ExecuteTest( + "extern void AmbiguousCallOneDefault() {\n" + " Test(1);\n" + "}\n" + "void Test(int i, float f = 2) {}\n" + "void Test(int i) {}\n" + "\n", + CBotErrAmbiguousCall + ); + + ExecuteTest( + "extern void DifferentNumberOfDefaultValues() {\n" + " Test(1, 2.0);\n" + "}\n" + "void Test(int i, float f = 2.0) {}\n" + "void Test(int i, float f = 2.0, int ii = 1) {}\n" + "\n", + CBotErrAmbiguousCall + ); +} From 7fadf7bad54b2c5211d057cc7edb61e12e8045e8 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sat, 28 Jan 2017 12:53:28 +0100 Subject: [PATCH 47/93] Fix aliens being selectable by default (#900) Broken in 6a382830a95a36a2e643193729433ddba266c420 This change also allows you to make selectable insects with selectable=1 in scene file --- src/object/old_object.cpp | 16 +++++++++++++++- src/object/old_object.h | 6 ++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index 1f2f6e29..c7200c8e 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -1041,7 +1041,7 @@ void COldObject::Read(CLevelParserLine* line) SetAnimateOnReset(line->GetParam("reset")->AsBool(false)); if (Implements(ObjectInterfaceType::Controllable)) { - SetSelectable(line->GetParam("selectable")->AsBool(true)); + SetSelectable(line->GetParam("selectable")->AsBool(IsSelectableByDefault(m_type))); } if (Implements(ObjectInterfaceType::JetFlying)) { @@ -3174,3 +3174,17 @@ float COldObject::GetLightningHitProbability() } return 0.0f; } + +bool COldObject::IsSelectableByDefault(ObjectType type) +{ + if ( type == OBJECT_MOTHER || + type == OBJECT_ANT || + type == OBJECT_SPIDER || + type == OBJECT_BEE || + type == OBJECT_WORM || + type == OBJECT_MOBILEtg ) + { + return false; + } + return true; +} diff --git a/src/object/old_object.h b/src/object/old_object.h index 5b85c286..ff96fcfe 100644 --- a/src/object/old_object.h +++ b/src/object/old_object.h @@ -302,6 +302,12 @@ protected: void TransformCrashSphere(Math::Sphere &crashSphere) override; void TransformCameraCollisionSphere(Math::Sphere& collisionSphere) override; + /** + * \brief Check if given object type should be selectable by default + * \note This is a default value for the selectable= parameter and can still be overriden in the scene file or using the \a selectinsect cheat + */ + static bool IsSelectableByDefault(ObjectType type); + protected: Gfx::CEngine* m_engine; Gfx::CLightManager* m_lightMan; From 9eae1e151d3d68ee06396c430ddaf300634200ac Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sat, 28 Jan 2017 12:56:42 +0100 Subject: [PATCH 48/93] Fix Shooter target getting stuck on not selectable objects (#900) --- src/ui/controls/target.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/controls/target.cpp b/src/ui/controls/target.cpp index c90c2051..dd18bd38 100644 --- a/src/ui/controls/target.cpp +++ b/src/ui/controls/target.cpp @@ -149,7 +149,7 @@ CObject* CTarget::DetectFriendObject(Math::Point pos) if ( !target->GetDetectable() ) continue; if ( target->GetProxyActivate() ) continue; if ( target->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(target)->GetSelect() ) continue; - if ( target->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast(target)->GetSelectable() ) continue; + if ( !target->Implements(ObjectInterfaceType::Controllable) || !dynamic_cast(target)->GetSelectable() ) continue; if (!target->Implements(ObjectInterfaceType::Old)) continue; // TODO: To be removed after COldObjectInterface is gone From 992ca7e8420cff4bcc294967a4acf90dd3c293cd Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sun, 12 Feb 2017 12:24:17 +0100 Subject: [PATCH 49/93] Update data submodule --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 3b99a621..0a550209 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 3b99a62185c4aba3c6c7507dfbbbcf5bcbce3ba2 +Subproject commit 0a5502096365ce667fb4b7c2a8cba8ad6b259eec From 3934eec9020152156a99361524d6a96f4c5f7bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=91=D0=B5=D0=BD?= =?UTF-8?q?=D1=8C=D0=BA=D0=BE=D0=B2=D1=81=D0=BA=D0=B8=D0=B9?= Date: Wed, 15 Feb 2017 20:19:40 +0400 Subject: [PATCH 50/93] Remove a dead link The wiki is dead now. See https://github.com/colobot/colobot/commit/c03d8beb8bc501f5c660ed843b1205d23484e6d4 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index be44f545..c7d4a9a5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This is official repository for the open-source Colobot: Gold Edition project de The source code contained here was released by Epsitec -- the original creator of the game -- on open source (GPLv3) license. The code was given and the rights granted specifically to ICC community in March 2012. Since then, we have been developing the game further. -More information for developers (in English) can be found on the [developer wiki](http://colobot.info/wiki/dev/) or [our forum](http://colobot.info/forum/). However, the freshest source of information is our IRC channels (see below). +More information for developers (in English) can be found on [our forum](http://colobot.info/forum/). However, the freshest source of information is our IRC channels (see below). This repository contains only the source code of the project. The game requires also data files which are now provided as git submodule and are hosted in [separate repository](https://github.com/colobot/colobot-data). From 588bf30b94c375676a02ee46b68b291e7792c531 Mon Sep 17 00:00:00 2001 From: tomangelo2 Date: Thu, 2 Mar 2017 23:01:55 +0100 Subject: [PATCH 51/93] Fixed some functions doesn't returning 0 if no error Fix issue #917 --- src/script/scriptfunc.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index 1c1f985f..e93d5fac 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -413,9 +413,9 @@ bool CScriptFunctions::rDestroy(CBotVar* thisclass, CBotVar* var, CBotVar* resul else err = ERR_WRONG_OBJ; + result->SetValInt(err); // indicates the error or ok if ( err != ERR_OK ) { - result->SetValInt(err); // return error if ( script->m_errMode == ERM_STOP ) { exception = err; @@ -506,9 +506,9 @@ bool CScriptFunctions::rFactory(CBotVar* thisclass, CBotVar* var, CBotVar* resul else err = ERR_WRONG_OBJ; + result->SetValInt(err); // indicates the error or ok if ( err != ERR_OK ) { - result->SetValInt(err); // return error if ( script->m_errMode == ERM_STOP ) { exception = err; @@ -581,9 +581,9 @@ bool CScriptFunctions::rResearch(CBotVar* thisclass, CBotVar* var, CBotVar* resu else err = ERR_WRONG_OBJ; + result->SetValInt(err); // indicates the error or ok if ( err != ERR_OK ) { - result->SetValInt(err); // return error if( script->m_errMode == ERM_STOP ) { exception = err; @@ -591,7 +591,7 @@ bool CScriptFunctions::rResearch(CBotVar* thisclass, CBotVar* var, CBotVar* resu } return true; } - + return true; } @@ -621,9 +621,9 @@ bool CScriptFunctions::rTakeOff(CBotVar* thisclass, CBotVar* var, CBotVar* resul else err = ERR_WRONG_OBJ; + result->SetValInt(err); // indicates the error or ok if ( err != ERR_OK ) { - result->SetValInt(err); // return error if ( script->m_errMode == ERM_STOP ) { exception = err; @@ -1229,10 +1229,9 @@ bool CScriptFunctions::rBuild(CBotVar* var, CBotVar* result, int& exception, voi } } } - + result->SetValInt(err); // indicates the error or ok if ( err != ERR_OK ) { - result->SetValInt(err); // return error if ( script->m_errMode == ERM_STOP ) { exception = err; @@ -2379,11 +2378,10 @@ bool CScriptFunctions::rFire(CBotVar* var, CBotVar* result, int& exception, void if ( delay < 0.0f ) delay = -delay; err = script->m_taskExecutor->StartTaskFire(delay); } - + result->SetValInt(err); // indicates the error or ok if ( err != ERR_OK ) { script->m_taskExecutor->StopForegroundTask(); - result->SetValInt(err); // shows the error return true; } } From b032dad578cdaf07d77f0bf52520a15984bb88a9 Mon Sep 17 00:00:00 2001 From: melex750 Date: Fri, 3 Mar 2017 01:09:09 -0500 Subject: [PATCH 52/93] Fix execution of default arguments --- src/CBot/CBotDefParam.cpp | 38 +++++++--- src/CBot/CBotInstr/CBotFunction.cpp | 108 +++++++++++++++++++++------- 2 files changed, 111 insertions(+), 35 deletions(-) diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp index 8b54f5a1..b3a11a60 100644 --- a/src/CBot/CBotDefParam.cpp +++ b/src/CBot/CBotDefParam.cpp @@ -136,30 +136,38 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) CBotDefParam* p = this; bool useDefault = false; + CBotStack* pile = pj->AddStack(); while ( p != nullptr ) { - // creates a local variable on the stack - CBotVar* newvar = CBotVar::Create(p->m_token.GetString(), p->m_type); + pile = pile->AddStack(); + if (pile->GetState() == 1) // already done? + { + if (ppVars != nullptr && ppVars[i] != nullptr) ++i; + p = p->m_next; + continue; // next param + } CBotVar* pVar = nullptr; - CBotStack* pile = nullptr; // stack for default expression if (useDefault || (ppVars == nullptr || ppVars[i] == nullptr)) { assert(p->m_expr != nullptr); - pile = pj->AddStack(); useDefault = true; - while (pile->IsOk() && !p->m_expr->Execute(pile)); - if (!pile->IsOk()) return pj->Return(pile); // return the error + if (!p->m_expr->Execute(pile)) return false; // interupt here pVar = pile->GetVar(); } else pVar = ppVars[i]; + pile->SetState(1); // mark this param done + + // creates a local variable on the stack + CBotVar* newvar = CBotVar::Create(p->m_token.GetString(), p->m_type); + // serves to make the transformation of types: if ((useDefault && pVar != nullptr) || (ppVars != nullptr && pVar != nullptr)) @@ -202,7 +210,6 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) pj->AddVar(newvar); // add a variable p = p->m_next; if (!useDefault) i++; - if (pile != nullptr) pile->Delete(); } return true; @@ -217,14 +224,27 @@ bool CBotDefParam::HasDefault() //////////////////////////////////////////////////////////////////////////////// void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain) { -// int i = 0; + assert(this != nullptr); CBotDefParam* p = this; + CBotStack* pile = nullptr; + if (bMain) pile = pj->RestoreStack(); + while ( p != nullptr ) { + if (bMain && pile != nullptr) + { + pile = pile->RestoreStack(); + if (pile != nullptr && pile->GetState() == 0) + { + assert(p->m_expr != nullptr); + p->m_expr->RestoreState(pile, true); + return; + } + } // creates a local variable on the stack CBotVar* var = pj->FindVar(p->m_token.GetString()); - var->SetUniqNum(p->m_nIdent); + if (var != nullptr) var->SetUniqNum(p->m_nIdent); p = p->m_next; } } diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 0f6a9800..c24f9861 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -370,11 +370,18 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) pile->SetProgram(m_pProg); // bases for routines + if ( pile->IfStep() ) return false; + if ( pile->GetState() == 0 ) { if (m_param != nullptr) { + // stack for parameters and default args + CBotStack* pile3b = pile->AddStack(); + pile3b->SetState(1); + if ( !m_param->Execute(ppVars, pile) ) return false; // define parameters + pile3b->Delete(); // done with param stack } pile->IncState(); } @@ -408,8 +415,6 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) pile->IncState(); } - if ( pile->IfStep() ) return false; - if ( !m_block->Execute(pile) ) { if ( pile->GetError() < 0 ) @@ -438,7 +443,22 @@ void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInst pile2->Delete(); } - m_param->RestoreState(pile2, true); // parameters + if ( pile->GetState() == 0 ) + { + if (m_param != nullptr) + { + CBotStack* pile3b = pile2->RestoreStack(); + + if (pile3b != nullptr && pile3b->GetState() == 1) + m_param->RestoreState(pile2, true); // restore executing default arguments + else + m_param->RestoreState(pile2, false); // restore parameter IDs + } + return; + } + + if (m_param != nullptr) + m_param->RestoreState(pile2, false); // restore parameter IDs if ( !m_MasterClass.empty() ) { @@ -670,7 +690,10 @@ int CBotFunction::DoCall(CBotProgram* program, const std::list& l if ( pStk1->GetState() == 0 ) { - if ( !pt->m_MasterClass.empty() ) + // stack for parameters and default args + CBotStack* pStk3b = pStk3->AddStack(); + + if (pStk3b->GetState() == 0 && !pt->m_MasterClass.empty()) { CBotVar* pInstance = program->m_thisVar; // make "this" known @@ -696,20 +719,21 @@ int CBotFunction::DoCall(CBotProgram* program, const std::list& l pThis->SetUniqNum(-2); pStk1->AddVar(pThis); } + pStk3b->SetState(1); // set 'this' was created // initializes the variables as parameters if (pt->m_param != nullptr) { - if (!pt->m_param->Execute(ppVars, pStk3)) // interupts only if error on a default value + if (!pt->m_param->Execute(ppVars, pStk3)) // interupt here { - if ( pt->m_pProg != program ) + if (!pStk3->IsOk() && pt->m_pProg != program) { pStk3->SetPosError(pToken); // indicates the error on the procedure call } - return pStack->Return(pStk3); + return false; } } - + pStk3b->Delete(); // done with param stack pStk1->IncState(); } @@ -778,12 +802,21 @@ void CBotFunction::RestoreCall(const std::list& localFunctionList if ( pStk1->GetState() == 0 ) { - pt->m_param->RestoreState(pStk3, true); + if (pt->m_param != nullptr) + { + CBotStack* pStk3b = pStk3->RestoreStack(); + + if (pStk3b != nullptr && pStk3b->GetState() == 1) + pt->m_param->RestoreState(pStk3, true); // restore executing default arguments + else + pt->m_param->RestoreState(pStk3, false); // restore parameter IDs + } return; } // initializes the variables as parameters - pt->m_param->RestoreState(pStk3, false); + if (pt->m_param != nullptr) + pt->m_param->RestoreState(pStk3, false); // restore parameter IDs pt->m_block->RestoreState(pStk3, true); } } @@ -811,33 +844,42 @@ int CBotFunction::DoCall(const std::list& localFunctionList, long if ( pStk->GetState() == 0 ) { - // sets the variable "this" on the stack - CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer); - pthis->Copy(pThis, false); - pthis->SetUniqNum(-2); // special value - pStk->AddVar(pthis); + // stack for parameters and default args + CBotStack* pStk3b = pStk3->AddStack(); - CBotClass* pClass = pThis->GetClass()->GetParent(); - if ( pClass ) + if (pStk3b->GetState() == 0) { - // sets the variable "super" on the stack - CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer); - psuper->Copy(pThis, false); // in fact identical to "this" - psuper->SetUniqNum(-3); // special value - pStk->AddVar(psuper); + // sets the variable "this" on the stack + CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer); + pthis->Copy(pThis, false); + pthis->SetUniqNum(-2); // special value + pStk->AddVar(pthis); + + CBotClass* pClass = pThis->GetClass()->GetParent(); + if ( pClass ) + { + // sets the variable "super" on the stack + CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer); + psuper->Copy(pThis, false); // in fact identical to "this" + psuper->SetUniqNum(-3); // special value + pStk->AddVar(psuper); + } } + pStk3b->SetState(1); // set 'this' was created + // initializes the variables as parameters if (pt->m_param != nullptr) { - if (!pt->m_param->Execute(ppVars, pStk3)) // interupts only if error on a default value + if (!pt->m_param->Execute(ppVars, pStk3)) // interupt here { - if ( pt->m_pProg != pProgCurrent ) + if (!pStk3->IsOk() && pt->m_pProg != pProgCurrent) { pStk3->SetPosError(pToken); // indicates the error on the procedure call } - return pStack->Return(pStk3); + return false; } } + pStk3b->Delete(); // done with param stack pStk->IncState(); } @@ -905,7 +947,21 @@ bool CBotFunction::RestoreCall(const std::list& localFunctionList CBotStack* pStk3 = pStk->RestoreStack(nullptr); // to set parameters passed if ( pStk3 == nullptr ) return true; - pt->m_param->RestoreState(pStk3, true); // parameters + if ( pStk->GetState() == 0 ) + { + if (pt->m_param != nullptr) + { + CBotStack* pStk3b = pStk3->RestoreStack(); + if (pStk3b != nullptr && pStk3b->GetState() == 1) + pt->m_param->RestoreState(pStk3, true); // restore executing default arguments + else + pt->m_param->RestoreState(pStk3, false); // restore parameter IDs + } + return true; + } + + if (pt->m_param != nullptr) + pt->m_param->RestoreState(pStk3, false); // restore parameter IDs if ( pStk->GetState() > 1 && // latching is effective? pt->m_bSynchro ) From f80db9e8fb3fa01e0f2c9d13db21a8d023353abd Mon Sep 17 00:00:00 2001 From: melex750 Date: Fri, 3 Mar 2017 02:11:10 -0500 Subject: [PATCH 53/93] Fix using negative numbers in default arguments Issue #919 --- src/CBot/CBotInstr/CBotExprUnaire.cpp | 7 +++++-- src/CBot/CBotInstr/CBotExprUnaire.h | 11 ++++++----- src/CBot/CBotInstr/CBotParExpr.cpp | 7 ++++++- test/unit/CBot/CBot_test.cpp | 16 ++++++++++++++++ 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/CBot/CBotInstr/CBotExprUnaire.cpp b/src/CBot/CBotInstr/CBotExprUnaire.cpp index 0080a468..e4d1ec3f 100644 --- a/src/CBot/CBotInstr/CBotExprUnaire.cpp +++ b/src/CBot/CBotInstr/CBotExprUnaire.cpp @@ -41,7 +41,7 @@ CBotExprUnaire::~CBotExprUnaire() } //////////////////////////////////////////////////////////////////////////////// -CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack) +CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral) { int op = p->GetType(); CBotToken* pp = p; @@ -52,7 +52,10 @@ CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack) CBotExprUnaire* inst = new CBotExprUnaire(); inst->SetToken(pp); - if (nullptr != (inst->m_expr = CBotParExpr::Compile(p, pStk ))) + if (!bLiteral) inst->m_expr = CBotParExpr::Compile(p, pStk); + else inst->m_expr = CBotParExpr::CompileLitExpr(p, pStk); + + if (inst->m_expr != nullptr) { if (op == ID_ADD && pStk->GetType() < CBotTypBoolean) // only with the number return pStack->Return(inst, pStk); diff --git a/src/CBot/CBotInstr/CBotExprUnaire.h b/src/CBot/CBotInstr/CBotExprUnaire.h index e7e58c74..b15d2552 100644 --- a/src/CBot/CBotInstr/CBotExprUnaire.h +++ b/src/CBot/CBotInstr/CBotExprUnaire.h @@ -34,12 +34,13 @@ public: ~CBotExprUnaire(); /*! - * \brief Compile - * \param p - * \param pStack - * \return + * \brief Compile an expression with a unary operator + * \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression + * \param pStack Current compilation stack frame + * \param bLiteral If true, compiles only literal expressions Ex: ~11, -4.0, !false, not true + * \return The compiled instruction or nullptr */ - static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral = false); /*! * \brief Execute diff --git a/src/CBot/CBotInstr/CBotParExpr.cpp b/src/CBot/CBotInstr/CBotParExpr.cpp index b0c2f1c1..0a608c32 100644 --- a/src/CBot/CBotInstr/CBotParExpr.cpp +++ b/src/CBot/CBotInstr/CBotParExpr.cpp @@ -132,7 +132,7 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) return pStack->Return(nullptr, pStk); } - return CompileLitExpr(p, pStack); + return CBotParExpr::CompileLitExpr(p, pStack); } //////////////////////////////////////////////////////////////////////////////// @@ -142,6 +142,11 @@ CBotInstr* CBotParExpr::CompileLitExpr(CBotToken* &p, CBotCStack* pStack) CBotToken* pp = p; + // is this a unary operation? + CBotInstr* inst = CBotExprUnaire::Compile(p, pStk, true); + if (inst != nullptr || !pStk->IsOk()) + return pStack->Return(inst, pStk); + // is it a number or DefineNum? if (p->GetType() == TokenTypNum || p->GetType() == TokenTypDef ) diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 2f8bb503..5d3b72c3 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -2385,4 +2385,20 @@ TEST_F(CBotUT, ParametersWithDefaultValues) "\n", CBotErrAmbiguousCall ); + + ExecuteTest( + "extern void DefaultValueUnaryExpression() {\n" + " TestNumbers();\n" + " TestBool();\n" + "}\n" + "void TestNumbers(int i = -1, float f = -1, int ii = ~1) {\n" + " ASSERT(i == -1);\n" + " ASSERT(f == -1.0);\n" + " ASSERT(ii == ~1);\n" + "}\n" + "void TestBool(bool b = !false, bool b2 = not false) {\n" + " ASSERT(true == b);\n" + " ASSERT(true == b2);\n" + "}\n" + ); } From fda58a60087d4fc39e6332a053df6c7680804994 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sat, 29 Apr 2017 13:05:11 +0200 Subject: [PATCH 54/93] Change bullet collision logic to allow for collisions with non-damageable objects For now, you have to add bulletWall=true to objects you want bullets to collide with. It's ugly but will work for now. This is needed mostly for compatibility with exercises which use barriers to block movement but not bullets. I also made the collision checks run more often because otherwise the bullets would sometimes miss the objects (but only visually) --- src/graphics/engine/particle.cpp | 50 +++++++++++++++++++++----------- src/object/object.h | 5 ++++ src/object/old_object.cpp | 15 ++++++++++ src/object/old_object.h | 5 ++++ 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp index 5aaf45fa..9297a6cd 100644 --- a/src/graphics/engine/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -952,9 +952,8 @@ void CParticle::FrameParticle(float rTime) { CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); m_particle[i].goal = m_particle[i].pos; - if (object != nullptr) + if (object != nullptr && object->Implements(ObjectInterfaceType::Damageable)) { - assert(object->Implements(ObjectInterfaceType::Damageable)); dynamic_cast(object)->DamageObject(DamageType::Phazer, 0.002f); } @@ -1107,7 +1106,7 @@ void CParticle::FrameParticle(float rTime) continue; } - if (m_particle[i].testTime >= 0.1f) + if (m_particle[i].testTime >= 0.05f) { m_particle[i].testTime = 0.0f; @@ -1156,8 +1155,10 @@ void CParticle::FrameParticle(float rTime) m_particle[i].goal = m_particle[i].pos; if (object != nullptr) { - assert(object->Implements(ObjectInterfaceType::Damageable)); - dynamic_cast(object)->DamageObject(DamageType::Fire, 0.002f); + if (object->Implements(ObjectInterfaceType::Damageable)) + { + dynamic_cast(object)->DamageObject(DamageType::Fire, 0.001f); + } m_exploGunCounter++; @@ -1215,7 +1216,7 @@ void CParticle::FrameParticle(float rTime) continue; } - if (m_particle[i].testTime >= 0.2f) + if (m_particle[i].testTime >= 0.1f) { m_particle[i].testTime = 0.0f; CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); @@ -1238,8 +1239,10 @@ void CParticle::FrameParticle(float rTime) if (object->GetType() != OBJECT_HUMAN) Play(SOUND_TOUCH, m_particle[i].pos, 1.0f); - assert(object->Implements(ObjectInterfaceType::Damageable)); - dynamic_cast(object)->DamageObject(DamageType::Organic, 0.2f); // starts explosion + if (object->Implements(ObjectInterfaceType::Damageable)) + { + dynamic_cast(object)->DamageObject(DamageType::Organic, 0.1f); // starts explosion + } } } } @@ -1261,7 +1264,7 @@ void CParticle::FrameParticle(float rTime) continue; } - if (m_particle[i].testTime >= 0.2f) + if (m_particle[i].testTime >= 0.1f) { m_particle[i].testTime = 0.0f; CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); @@ -1281,8 +1284,10 @@ void CParticle::FrameParticle(float rTime) } else { - assert(object->Implements(ObjectInterfaceType::Damageable)); - dynamic_cast(object)->DamageObject(DamageType::Fire); // starts explosion + if (object->Implements(ObjectInterfaceType::Damageable)) + { + dynamic_cast(object)->DamageObject(DamageType::Fire); // starts explosion + } } } } @@ -1301,7 +1306,7 @@ void CParticle::FrameParticle(float rTime) continue; } - if (m_particle[i].testTime >= 0.1f) + if (m_particle[i].testTime >= 0.05f) { m_particle[i].testTime = 0.0f; @@ -1338,8 +1343,10 @@ void CParticle::FrameParticle(float rTime) m_particle[i].goal = m_particle[i].pos; if (object != nullptr) { - assert(object->Implements(ObjectInterfaceType::Damageable)); - dynamic_cast(object)->DamageObject(DamageType::Organic, 0.002f); + if (object->Implements(ObjectInterfaceType::Damageable)) + { + dynamic_cast(object)->DamageObject(DamageType::Organic, 0.0005f); + } m_exploGunCounter ++; @@ -3502,6 +3509,7 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos, box2.z += min; CObject* best = nullptr; + float best_dist = std::numeric_limits::infinity(); bool shield = false; for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) { @@ -3535,7 +3543,7 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos, { continue; } - if (!obj->Implements(ObjectInterfaceType::Damageable)) continue; + if (!obj->Implements(ObjectInterfaceType::Damageable) && !obj->IsBulletWall()) continue; Math::Vector oPos = obj->GetPosition(); @@ -3563,8 +3571,12 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos, // Test the center of the object, which is necessary for objects // that have no sphere in the center (station). float dist = Math::Distance(oPos, pos)-4.0f; - if (dist < min) + float obj_dist = Math::Distance(old, oPos); + if (dist < min && obj_dist < best_dist) + { best = obj; + best_dist = obj_dist; + } for (const auto& crashSphere : obj->GetAllCrashSpheres()) { @@ -3577,8 +3589,12 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos, Math::Vector p = Math::Projection(old, pos, oPos); float ddist = Math::Distance(p, oPos)-oRadius; - if (ddist < min) + float obj_dist = Math::Distance(old, oPos); + if (ddist < min && obj_dist < best_dist) + { best = obj; + best_dist = obj_dist; + } } } diff --git a/src/object/object.h b/src/object/object.h index 960d753e..4fcfe686 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -206,6 +206,11 @@ public: //! Is this object detectable (not dead and not underground)? virtual bool GetDetectable() { return true; } + //! Returns true if this object can collide with bullets even though it's not damageable itself + //! This is useful to make Barriers protect from bullets + //! \todo It will work like this for now but later I'd like to refactor this to something more manageable ~krzys_h + virtual bool IsBulletWall() { return false; } + protected: //! Transform crash sphere by object's world matrix virtual void TransformCrashSphere(Math::Sphere& crashSphere) = 0; diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index c7200c8e..5c67ee44 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -940,6 +940,9 @@ void COldObject::Write(CLevelParserLine* line) if ( GetCameraLock() ) line->AddParam("cameraLock", MakeUnique(GetCameraLock())); + if ( IsBulletWall() ) + line->AddParam("bulletWall", MakeUnique(IsBulletWall())); + if ( GetEnergyLevel() != 0.0f ) line->AddParam("energy", MakeUnique(GetEnergyLevel())); @@ -1035,6 +1038,8 @@ void COldObject::Read(CLevelParserLine* line) if (line->GetParam("pyro")->IsDefined()) m_engine->GetPyroManager()->Create(line->GetParam("pyro")->AsPyroType(), this); + SetBulletWall(line->GetParam("bulletWall")->AsBool(false)); + SetProxyActivate(line->GetParam("proxyActivate")->AsBool(false)); SetProxyDistance(line->GetParam("proxyDistance")->AsFloat(15.0f)*g_unit); SetCollisions(line->GetParam("clip")->AsBool(true)); @@ -3188,3 +3193,13 @@ bool COldObject::IsSelectableByDefault(ObjectType type) } return true; } + +void COldObject::SetBulletWall(bool bulletWall) +{ + m_bulletWall = bulletWall; +} + +bool COldObject::IsBulletWall() +{ + return m_bulletWall; +} diff --git a/src/object/old_object.h b/src/object/old_object.h index ff96fcfe..b000ac62 100644 --- a/src/object/old_object.h +++ b/src/object/old_object.h @@ -288,6 +288,9 @@ public: float GetLightningHitProbability() override; + void SetBulletWall(bool bulletWall); + bool IsBulletWall() override; + protected: bool EventFrame(const Event &event); void VirusFrame(float rTime); @@ -376,4 +379,6 @@ protected: bool m_traceDown; TraceColor m_traceColor; float m_traceWidth; + + bool m_bulletWall = false; }; From 6cd72543c4865903f980469ac8c34cd6ae633ad9 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sat, 29 Apr 2017 13:18:01 +0200 Subject: [PATCH 55/93] Fix amount of damage from OrgaShooters I messed it up in previous commit, 0.002/2 is 0.001 not 0.0005 :P --- data | 2 +- src/graphics/engine/particle.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data b/data index 0a550209..3b99a621 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 0a5502096365ce667fb4b7c2a8cba8ad6b259eec +Subproject commit 3b99a62185c4aba3c6c7507dfbbbcf5bcbce3ba2 diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp index 9297a6cd..6bd310e8 100644 --- a/src/graphics/engine/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -1345,7 +1345,7 @@ void CParticle::FrameParticle(float rTime) { if (object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Organic, 0.0005f); + dynamic_cast(object)->DamageObject(DamageType::Organic, 0.001f); } m_exploGunCounter ++; From 880f31a7c66927420537aeecd546e8da0562a237 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 17 May 2017 18:22:27 +0200 Subject: [PATCH 56/93] Add basics of scoreboard implementation; better support for multiple teams --- src/CMakeLists.txt | 2 + src/graphics/engine/lightning.cpp | 2 +- src/graphics/engine/particle.cpp | 12 +- src/graphics/engine/pyro.cpp | 2 + src/level/robotmain.cpp | 82 +++++++++++- src/level/robotmain.h | 11 ++ src/level/scene_conditions.cpp | 149 ++++++++++++---------- src/level/scene_conditions.h | 23 +++- src/level/scoreboard.cpp | 94 ++++++++++++++ src/level/scoreboard.h | 120 +++++++++++++++++ src/object/interface/damageable_object.h | 4 +- src/object/interface/destroyable_object.h | 3 +- src/object/object_manager.cpp | 4 +- src/object/object_manager.h | 3 +- src/object/old_object.cpp | 19 ++- src/object/old_object.h | 4 +- src/physics/physics.cpp | 5 + 17 files changed, 442 insertions(+), 97 deletions(-) create mode 100644 src/level/scoreboard.cpp create mode 100644 src/level/scoreboard.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 117648f3..e0857506 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -241,6 +241,8 @@ set(BASE_SOURCES level/robotmain.h level/scene_conditions.cpp level/scene_conditions.h + level/scoreboard.cpp + level/scoreboard.h math/all.h math/const.h math/func.h diff --git a/src/graphics/engine/lightning.cpp b/src/graphics/engine/lightning.cpp index 18192fe5..190f5db8 100644 --- a/src/graphics/engine/lightning.cpp +++ b/src/graphics/engine/lightning.cpp @@ -131,7 +131,7 @@ bool CLightning::EventFrame(const Event &event) else { assert(obj->Implements(ObjectInterfaceType::Destroyable)); - dynamic_cast(obj)->DamageObject(DamageType::Lightning); + dynamic_cast(obj)->DamageObject(DamageType::Lightning, std::numeric_limits::infinity()); } } diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp index 6bd310e8..e63a8c6a 100644 --- a/src/graphics/engine/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -954,7 +954,7 @@ void CParticle::FrameParticle(float rTime) m_particle[i].goal = m_particle[i].pos; if (object != nullptr && object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Phazer, 0.002f); + dynamic_cast(object)->DamageObject(DamageType::Phazer, 0.002f, m_particle[i].objFather); } m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); @@ -1157,7 +1157,7 @@ void CParticle::FrameParticle(float rTime) { if (object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Fire, 0.001f); + dynamic_cast(object)->DamageObject(DamageType::Fire, 0.001f, m_particle[i].objFather); } m_exploGunCounter++; @@ -1241,7 +1241,7 @@ void CParticle::FrameParticle(float rTime) if (object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Organic, 0.1f); // starts explosion + dynamic_cast(object)->DamageObject(DamageType::Organic, 0.1f, m_particle[i].objFather); // starts explosion } } } @@ -1286,7 +1286,7 @@ void CParticle::FrameParticle(float rTime) { if (object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Fire); // starts explosion + dynamic_cast(object)->DamageObject(DamageType::Fire, std::numeric_limits::infinity(), m_particle[i].objFather); // starts explosion } } } @@ -1345,7 +1345,7 @@ void CParticle::FrameParticle(float rTime) { if (object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Organic, 0.001f); + dynamic_cast(object)->DamageObject(DamageType::Organic, 0.001f, m_particle[i].objFather); } m_exploGunCounter ++; @@ -2423,7 +2423,7 @@ void CParticle::FrameParticle(float rTime) if (object != nullptr) { assert(object->Implements(ObjectInterfaceType::Damageable)); - dynamic_cast(object)->DamageObject(DamageType::Tower); + dynamic_cast(object)->DamageObject(DamageType::Tower, std::numeric_limits::infinity(), m_particle[i].objFather); } } diff --git a/src/graphics/engine/pyro.cpp b/src/graphics/engine/pyro.cpp index 8ac406e8..6f3961af 100644 --- a/src/graphics/engine/pyro.cpp +++ b/src/graphics/engine/pyro.cpp @@ -2296,6 +2296,7 @@ void CPyro::FallProgress(float rTime) if (floor) // reaches the ground? { assert(m_object->Implements(ObjectInterfaceType::Destroyable)); + // TODO: implement "killer"? dynamic_cast(m_object)->DestroyObject(DestructionType::Explosion); } } @@ -2319,6 +2320,7 @@ void CPyro::FallProgress(float rTime) else { assert(m_object->Implements(ObjectInterfaceType::Destroyable)); + // TODO: implement "killer"? dynamic_cast(m_object)->DestroyObject(DestructionType::Explosion); } } diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 2797e3d3..b723b58c 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -55,6 +55,7 @@ #include "level/mainmovie.h" #include "level/player_profile.h" #include "level/scene_conditions.h" +#include "level/scoreboard.h" #include "level/parser/parser.h" @@ -2518,7 +2519,7 @@ bool CRobotMain::EventFrame(const Event &event) if (m_phase == PHASE_SIMUL) { - if (!m_editLock) + if (!m_editLock && !m_engine->GetPause()) { CheckEndMission(true); UpdateAudio(true); @@ -2695,6 +2696,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_endTakeResearch = 0; m_endTakeWinDelay = 2.0f; m_endTakeLostDelay = 2.0f; + m_teamFinished.clear(); + m_scoreboard.reset(); m_globalMagnifyDamage = 1.0f; m_obligatoryTokens.clear(); m_mapShow = true; @@ -3552,6 +3555,34 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) continue; } + if (line->GetCommand() == "Scoreboard" && !resetObject) + { + if (line->GetParam("enable")->AsBool(false)) + { + // Create the scoreboard + m_scoreboard = MakeUnique(); + } + continue; + } + if (line->GetCommand() == "ScoreboardKillRule" && !resetObject) + { + if (!m_scoreboard) + throw CLevelParserException("ScoreboardKillRule encountered but scoreboard is not enabled"); + auto rule = MakeUnique(); + rule->Read(line.get()); + m_scoreboard->AddKillRule(std::move(rule)); + continue; + } + if (line->GetCommand() == "ScoreboardEndTakeRule" && !resetObject) + { + if (!m_scoreboard) + throw CLevelParserException("ScoreboardEndTakeRule encountered but scoreboard is not enabled"); + auto rule = MakeUnique(); + rule->Read(line.get()); + m_scoreboard->AddEndTakeRule(std::move(rule)); + continue; + } + if (line->GetCommand() == "ObligatoryToken" && !resetObject) { std::string token = line->GetParam("text")->AsString(); @@ -4909,7 +4940,7 @@ Error CRobotMain::ProcessEndMissionTake() int team = it.first; if (team == 0) continue; usesTeamConditions = true; - if (!m_objMan->TeamExists(team)) continue; + if (m_teamFinished[team]) continue; teamCount++; } @@ -4924,8 +4955,32 @@ Error CRobotMain::ProcessEndMissionTake() if (teamCount == 0) { - GetLogger()->Info("All teams died, mission ended with failure\n"); - m_missionResult = INFO_LOST; + GetLogger()->Info("All teams died, mission ended\n"); + if (m_scoreboard) + { + std::string details = ""; + for (auto it : teams) + { + int team = it.first; + if (team == 0) continue; + details += "Team "+boost::lexical_cast(team)+": "+boost::lexical_cast(m_scoreboard->GetScore(team))+" points\n"; + } + m_ui->GetDialog()->StartInformation( + "Results", + "The battle has ended", + details, + false, true, + [&]() { + ChangePhase(PHASE_WIN); + } + ); + m_endTakeWinDelay = 0.0f; + m_missionResult = ERR_OK; + } + else + { + m_missionResult = INFO_LOST; + } } else { @@ -4933,7 +4988,7 @@ Error CRobotMain::ProcessEndMissionTake() { int team = it.first; if (team == 0) continue; - if (!m_objMan->TeamExists(team)) continue; + if (m_teamFinished[team]) continue; Error result = ProcessEndMissionTakeForGroup(it.second); if (result == INFO_LOST || result == INFO_LOSTq) @@ -4944,10 +4999,12 @@ Error CRobotMain::ProcessEndMissionTake() m_displayText->SetEnable(false); // To prevent "bot destroyed" messages m_objMan->DestroyTeam(team); m_displayText->SetEnable(true); + + m_teamFinished[team] = true; } else if (result == ERR_OK) { - if (m_winDelay == 0.0f) + /*if (m_winDelay == 0.0f) { GetLogger()->Info("Team %d won\n", team); @@ -4963,7 +5020,13 @@ Error CRobotMain::ProcessEndMissionTake() m_displayText->SetEnable(false); } m_missionResult = ERR_OK; - return ERR_OK; + return ERR_OK;*/ + GetLogger()->Info("Team %d finished\n", team); + m_displayText->DisplayText(("<<< Team "+boost::lexical_cast(team)+" finished >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f)); + if (m_scoreboard) + m_scoreboard->ProcessEndTake(team); + m_objMan->DestroyTeam(team, DestructionType::Win); + m_teamFinished[team] = true; } } } @@ -5817,3 +5880,8 @@ std::string CRobotMain::GetPreviousFromCommandHistory() return ""; return m_commandHistory[--m_commandHistoryIndex]; } + +CScoreboard* CRobotMain::GetScoreboard() +{ + return m_scoreboard.get(); +} diff --git a/src/level/robotmain.h b/src/level/robotmain.h index dad1bed0..6bde5f6b 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -87,6 +87,7 @@ class CInput; class CObjectManager; class CSceneEndCondition; class CAudioChangeCondition; +class CScoreboard; class CPlayerProfile; class CSettings; class COldObject; @@ -307,6 +308,10 @@ public: //! Return list of scripts to load to robot created in BotFactory std::vector GetNewScriptNames(ObjectType type); + //! Return the scoreboard manager + //! Note: this may return nullptr if the scoreboard is not enabled! + CScoreboard* GetScoreboard(); + void SelectPlayer(std::string playerName); CPlayerProfile* GetPlayerProfile(); @@ -655,9 +660,15 @@ protected: long m_endTakeResearch = 0; float m_endTakeWinDelay = 0.0f; float m_endTakeLostDelay = 0.0f; + //! Set to true for teams that have already finished + std::map m_teamFinished; std::vector> m_audioChange; + //! The scoreboard + //! If the scoreboard is not enabled for this level, this will be null + std::unique_ptr m_scoreboard; + std::map m_obligatoryTokens; //! Enabled buildings diff --git a/src/level/scene_conditions.cpp b/src/level/scene_conditions.cpp index e475dee9..d4ed1bfc 100644 --- a/src/level/scene_conditions.cpp +++ b/src/level/scene_conditions.cpp @@ -29,11 +29,13 @@ #include "object/interface/powered_object.h" #include "object/interface/transportable_object.h" +#include -void CSceneCondition::Read(CLevelParserLine* line) + +void CObjectCondition::Read(CLevelParserLine* line) { this->pos = line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit; - this->dist = line->GetParam("dist")->AsFloat(8.0f)*g_unit; + this->dist = line->GetParam("dist")->AsFloat(std::numeric_limits::infinity())*g_unit; this->type = line->GetParam("type")->AsObjectType(OBJECT_NULL); this->powermin = line->GetParam("powermin")->AsFloat(-1); this->powermax = line->GetParam("powermax")->AsFloat(100); @@ -41,6 +43,82 @@ void CSceneCondition::Read(CLevelParserLine* line) this->drive = line->GetParam("drive")->AsDriveType(DriveType::Other); this->countTransported = line->GetParam("countTransported")->AsBool(true); this->team = line->GetParam("team")->AsInt(0); +} + +bool CObjectCondition::CheckForObject(CObject* obj) +{ + if (!this->countTransported) + { + if (IsObjectBeingTransported(obj)) return false; + } + + ObjectType type = obj->GetType(); + + ToolType tool = GetToolFromObject(type); + DriveType drive = GetDriveFromObject(type); + if (this->tool != ToolType::Other && + tool != this->tool) + return false; + + if (this->drive != DriveType::Other && + drive != this->drive) + return false; + + if (this->tool == ToolType::Other && + this->drive == DriveType::Other && + type != this->type && + this->type != OBJECT_NULL) + return false; + + if ((this->team > 0 && obj->GetTeam() != this->team) || + (this->team < 0 && (obj->GetTeam() == -(this->team) || obj->GetTeam() == 0))) + return false; + + float energyLevel = -1; + CPowerContainerObject* power = nullptr; + if (obj->Implements(ObjectInterfaceType::PowerContainer)) + { + power = dynamic_cast(obj); + } + else if (obj->Implements(ObjectInterfaceType::Powered)) + { + CObject* powerObj = dynamic_cast(obj)->GetPower(); + if(powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer)) + { + power = dynamic_cast(powerObj); + } + } + + if (power != nullptr) + { + energyLevel = power->GetEnergy(); + if (power->GetCapacity() > 1.0f) energyLevel *= 10; // TODO: Who designed it like that ?!?! + } + if (energyLevel < this->powermin || energyLevel > this->powermax) return false; + + Math::Vector oPos; + if (IsObjectBeingTransported(obj)) + oPos = dynamic_cast(obj)->GetTransporter()->GetPosition(); + else + oPos = obj->GetPosition(); + oPos.y = 0.0f; + + Math::Vector bPos = this->pos; + bPos.y = 0.0f; + + if (Math::DistanceProjected(oPos, bPos) <= this->dist) + return true; + + return false; +} + +void CSceneCondition::Read(CLevelParserLine* line) +{ + CObjectCondition::Read(line); + + // Scene conditions STILL use a different default value + // See issue #759 + this->dist = line->GetParam("dist")->AsFloat(8.0f)*g_unit; this->min = line->GetParam("min")->AsInt(1); this->max = line->GetParam("max")->AsInt(9999); @@ -48,74 +126,12 @@ void CSceneCondition::Read(CLevelParserLine* line) int CSceneCondition::CountObjects() { - Math::Vector bPos = this->pos; - bPos.y = 0.0f; - - Math::Vector oPos; - int nb = 0; for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects()) { if (!obj->GetActive()) continue; - - if (!this->countTransported) - { - if (IsObjectBeingTransported(obj)) continue; - } - - ObjectType type = obj->GetType(); - - ToolType tool = GetToolFromObject(type); - DriveType drive = GetDriveFromObject(type); - if (this->tool != ToolType::Other && - tool != this->tool) - continue; - - if (this->drive != DriveType::Other && - drive != this->drive) - continue; - - if (this->tool == ToolType::Other && - this->drive == DriveType::Other && - type != this->type && - this->type != OBJECT_NULL) - continue; - - if ((this->team > 0 && obj->GetTeam() != this->team) || - (this->team < 0 && (obj->GetTeam() == -(this->team) || obj->GetTeam() == 0))) - continue; - - float energyLevel = -1; - CPowerContainerObject* power = nullptr; - if (obj->Implements(ObjectInterfaceType::PowerContainer)) - { - power = dynamic_cast(obj); - } - else if (obj->Implements(ObjectInterfaceType::Powered)) - { - CObject* powerObj = dynamic_cast(obj)->GetPower(); - if(powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer)) - { - power = dynamic_cast(powerObj); - } - } - - if (power != nullptr) - { - energyLevel = power->GetEnergy(); - if (power->GetCapacity() > 1.0f) energyLevel *= 10; // TODO: Who designed it like that ?!?! - } - if (energyLevel < this->powermin || energyLevel > this->powermax) continue; - - if (IsObjectBeingTransported(obj)) - oPos = dynamic_cast(obj)->GetTransporter()->GetPosition(); - else - oPos = obj->GetPosition(); - - oPos.y = 0.0f; - - if (Math::DistanceProjected(oPos, bPos) <= this->dist) - nb ++; + if (!CheckForObject(obj)) continue; + nb ++; } return nb; } @@ -126,7 +142,6 @@ bool CSceneCondition::Check() return nb >= this->min && nb <= this->max; } - void CSceneEndCondition::Read(CLevelParserLine* line) { CSceneCondition::Read(line); diff --git a/src/level/scene_conditions.h b/src/level/scene_conditions.h index 258cc7ef..721c486c 100644 --- a/src/level/scene_conditions.h +++ b/src/level/scene_conditions.h @@ -34,12 +34,13 @@ #include "object/tool_type.h" class CLevelParserLine; +class CObject; /** - * \class CSceneCondition - * \brief Base scene condition structure + * \class CObjectCondition + * \brief Base object condition structure */ -class CSceneCondition +class CObjectCondition { public: Math::Vector pos = Math::Vector(0.0f, 0.0f, 0.0f)*g_unit; @@ -52,11 +53,25 @@ public: bool countTransported = true; int team = 0; + //! Read from line in scene file + virtual void Read(CLevelParserLine* line); + + //! Checks if this condition is met + bool CheckForObject(CObject* obj); +}; + +/** + * \class CSceneCondition + * \brief Base scene condition structure + */ +class CSceneCondition : public CObjectCondition +{ +public: int min = 1; // wins if > int max = 9999; // wins if < //! Read from line in scene file - virtual void Read(CLevelParserLine* line); + void Read(CLevelParserLine* line) override; //! Checks if this condition is met bool Check(); diff --git a/src/level/scoreboard.cpp b/src/level/scoreboard.cpp new file mode 100644 index 00000000..7208dd49 --- /dev/null +++ b/src/level/scoreboard.cpp @@ -0,0 +1,94 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2017, 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 "level/scoreboard.h" + +#include "level/parser/parserline.h" + +#include "level/robotmain.h" + +#include "object/object.h" + +#include "ui/displaytext.h" + +#include + +void CScoreboard::CScoreboardRule::Read(CLevelParserLine* line) +{ + this->score = line->GetParam("score")->AsInt(); +} + +void CScoreboard::CScoreboardKillRule::Read(CLevelParserLine* line) +{ + CScoreboardRule::Read(line); + CObjectCondition::Read(line); +} + +void CScoreboard::CScoreboardEndTakeRule::Read(CLevelParserLine* line) +{ + CScoreboardRule::Read(line); + this->team = line->GetParam("team")->AsInt(0); +} + +void CScoreboard::AddKillRule(std::unique_ptr rule) +{ + m_rulesKill.push_back(std::move(rule)); +} + +void CScoreboard::AddEndTakeRule(std::unique_ptr rule) +{ + m_rulesEndTake.push_back(std::move(rule)); +} + +void CScoreboard::ProcessKill(CObject* target, CObject* killer) +{ + if (killer == nullptr) return; + if (killer->GetTeam() == 0) return; + for (auto& rule : m_rulesKill) + { + if ((rule->team == killer->GetTeam() || rule->team == 0) && + rule->CheckForObject(target)) + { + AddPoints(killer->GetTeam(), rule->score); + } + } +} + +void CScoreboard::ProcessEndTake(int team) +{ + for (auto& rule : m_rulesEndTake) + { + if (rule->team == team || rule->team == 0) + { + AddPoints(team, rule->score); + } + } +} + +void CScoreboard::AddPoints(int team, int points) +{ + GetLogger()->Info("Team %d earned %d points\n", team, points); + CRobotMain::GetInstancePointer()->GetDisplayText()->DisplayText(("<<< Team "+boost::lexical_cast(team)+" recieved "+boost::lexical_cast(points)+" points! >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_WARNING); + m_score[team] += points; +} + +int CScoreboard::GetScore(int team) +{ + return m_score[team]; +} diff --git a/src/level/scoreboard.h b/src/level/scoreboard.h new file mode 100644 index 00000000..c0c2512b --- /dev/null +++ b/src/level/scoreboard.h @@ -0,0 +1,120 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2017, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +/** + * \file level/scoreboard.h + * \brief Code responsible for managing the scoreboard used to score complex code battles + */ + +#pragma once + +#include "level/scene_conditions.h" + +#include +#include +#include + +class CObject; + +/** + * \class CScoreboard + * \brief Scoreboard used to score complex code battles + * + * \todo This is pretty much a work-in-progress hack for Diversity. Be wary of possible API changes. + * + * \todo Proper documentation + * + * \see CRobotMain::GetScoreboard() + * + * \section example Usage example + * \code{.scene} + * Scoreboard enable=true // enable the scoreboard + * ScoreboardKillRule type=WheeledShooter team=1 score=500 // destruction of team 1's WheeledShooter gives 100 points to the team that destroyed it + * ScoreboardKillRule type=TargetBot score=100 // destruction of TargetBot (any team) gives 100 points + * ScoreboardEndTakeRule score=1000 // completion of EndMissionTake objectives for any team results in 1000 points for that team + * \endcode + */ +class CScoreboard +{ +public: + //! Creates the scoreboard + //! The scoreboard exists only if enabled in level file + CScoreboard() {}; + //! Destroys the scoreboard + ~CScoreboard() {}; + +public: + /** + * \class CScoreboardRule + * \brief Base class for scoreboard rules + */ + class CScoreboardRule + { + public: + int score = 0; + + //! Read from line in scene file + virtual void Read(CLevelParserLine* line); + }; + + /** + * \class CScoreboardKillRule + * \brief Scoreboard rule for destroying other objects + * \see CScoreboard::AddKillRule() + */ + class CScoreboardKillRule : public CScoreboardRule, public CObjectCondition + { + public: + //! Read from line in scene file + void Read(CLevelParserLine* line) override; + }; + + /** + * \class CScoreboardEndTakeRule + * \brief Scoreboard rule for EndMissionTake rewards + * \see CScoreboard::AddEndTakeRule() + */ + class CScoreboardEndTakeRule : public CScoreboardRule + { + public: + int team = 0; + + //! Read from line in scene file + void Read(CLevelParserLine* line) override; + }; + +public: + void AddKillRule(std::unique_ptr rule); + void AddEndTakeRule(std::unique_ptr rule); + + //! Called after an object is destroyed by another object + //! \param target The object that has just been destroyed + //! \param killer The object that caused the destruction, can be null + void ProcessKill(CObject* target, CObject* killer = nullptr); + //! Called after EndTake contition has been met, used to handle ScoreboardEndTakeRule + void ProcessEndTake(int team); + + void AddPoints(int team, int points); + int GetScore(int team); + +private: + std::vector> m_rulesKill = {}; + std::vector> m_rulesEndTake = {}; + std::map m_score; +}; \ No newline at end of file diff --git a/src/object/interface/damageable_object.h b/src/object/interface/damageable_object.h index 27b35ca7..0813a286 100644 --- a/src/object/interface/damageable_object.h +++ b/src/object/interface/damageable_object.h @@ -23,6 +23,8 @@ #include +class CObject; + /** * \enum DamageType * \brief Type of damage, for use in CDamageableObject::DamageObject @@ -56,5 +58,5 @@ public: //! Damage the object, with the given force. Returns true if the object has been fully destroyed (assuming the object is destroyable, of course). If force == infinity, destroy immediately (this is the default value) /** NOTE: You should never assume that after this function exits, the object is destroyed, unless it returns true. Even if you specify force = infinity, if may still sometimes decide not to destroy the object. */ - virtual bool DamageObject(DamageType type, float force = std::numeric_limits::infinity()) = 0; + virtual bool DamageObject(DamageType type, float force = std::numeric_limits::infinity(), CObject* killer = nullptr) = 0; }; diff --git a/src/object/interface/destroyable_object.h b/src/object/interface/destroyable_object.h index d3e6ee02..48f4736b 100644 --- a/src/object/interface/destroyable_object.h +++ b/src/object/interface/destroyable_object.h @@ -32,6 +32,7 @@ enum class DestructionType ExplosionWater = 2, //!< explosion underwater Burn = 3, //!< burning Drowned = 4, //!< drowned (only for Me) + Win = 5, //!< used when removing objects from a team that won }; /** @@ -65,7 +66,7 @@ public: //! Destroy the object immediately. Use this only if you are 100% sure this is what you want, because object with magnifyDamage=0 should be able to bypass all damage. It's recommended to use CDamageableObject::DamageObject() instead. /** NOTE: After this function exits, you can assume the object has been definetly destroyed */ - virtual void DestroyObject(DestructionType type) = 0; + virtual void DestroyObject(DestructionType type, CObject* killer = nullptr) = 0; //! Returns the distance modifier for CLightning, used to modify hit probability. Value in range [0..1], where 0 is never and 1 is normal probability virtual float GetLightningHitProbability() = 0; diff --git a/src/object/object_manager.cpp b/src/object/object_manager.cpp index a903a3a4..9483936a 100644 --- a/src/object/object_manager.cpp +++ b/src/object/object_manager.cpp @@ -199,7 +199,7 @@ bool CObjectManager::TeamExists(int team) return false; } -void CObjectManager::DestroyTeam(int team) +void CObjectManager::DestroyTeam(int team, DestructionType destructionType) { assert(team != 0); @@ -209,7 +209,7 @@ void CObjectManager::DestroyTeam(int team) { if (object->Implements(ObjectInterfaceType::Destroyable)) { - dynamic_cast(object)->DestroyObject(DestructionType::Explosion); + dynamic_cast(object)->DestroyObject(destructionType); } else { diff --git a/src/object/object_manager.h b/src/object/object_manager.h index 8a4cbd6e..73ae0015 100644 --- a/src/object/object_manager.h +++ b/src/object/object_manager.h @@ -32,6 +32,7 @@ #include "object/object_create_params.h" #include "object/object_interface_type.h" #include "object/object_type.h" +#include "object/interface/destroyable_object.h" #include #include @@ -180,7 +181,7 @@ public: //! Destroy all objects of team // TODO: This should be probably moved to separate class - void DestroyTeam(int team); + void DestroyTeam(int team, DestructionType destructionType = DestructionType::Explosion); //! Counts all objects implementing given interface int CountObjectsImplementing(ObjectInterfaceType interface); diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index 5c67ee44..fb510d8d 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -34,6 +34,7 @@ #include "graphics/engine/terrain.h" #include "level/robotmain.h" +#include "level/scoreboard.h" #include "level/parser/parserexceptions.h" #include "level/parser/parserline.h" @@ -335,7 +336,7 @@ void COldObject::Simplify() } -bool COldObject::DamageObject(DamageType type, float force) +bool COldObject::DamageObject(DamageType type, float force, CObject* killer) { assert(Implements(ObjectInterfaceType::Damageable)); assert(!Implements(ObjectInterfaceType::Destroyable) || Implements(ObjectInterfaceType::Shielded) || Implements(ObjectInterfaceType::Fragile)); @@ -355,7 +356,7 @@ bool COldObject::DamageObject(DamageType type, float force) { if ( m_type == OBJECT_BOMB && type != DamageType::Explosive ) return false; // Mine can't be destroyed by shooting - DestroyObject(DestructionType::Explosion); + DestroyObject(DestructionType::Explosion, killer); return true; } @@ -400,11 +401,11 @@ bool COldObject::DamageObject(DamageType type, float force) { if (type == DamageType::Fire) { - DestroyObject(DestructionType::Burn); + DestroyObject(DestructionType::Burn, killer); } else { - DestroyObject(DestructionType::Explosion); + DestroyObject(DestructionType::Explosion, killer); } return true; } @@ -425,7 +426,7 @@ bool COldObject::DamageObject(DamageType type, float force) return false; } -void COldObject::DestroyObject(DestructionType type) +void COldObject::DestroyObject(DestructionType type, CObject* killer) { assert(Implements(ObjectInterfaceType::Destroyable)); @@ -522,6 +523,10 @@ void COldObject::DestroyObject(DestructionType type) { pyroType = Gfx::PT_DEADW; } + else if ( type == DestructionType::Win ) + { + pyroType = Gfx::PT_WPCHECK; + } assert(pyroType != Gfx::PT_NULL); m_engine->GetPyroManager()->Create(pyroType, this); @@ -539,6 +544,10 @@ void COldObject::DestroyObject(DestructionType type) } m_main->RemoveFromSelectionHistory(this); + CScoreboard* scoreboard = m_main->GetScoreboard(); + if (scoreboard) + scoreboard->ProcessKill(this, killer); + m_team = 0; // Back to neutral on destruction if ( m_botVar != nullptr ) diff --git a/src/object/old_object.h b/src/object/old_object.h index b000ac62..bc2d0b0a 100644 --- a/src/object/old_object.h +++ b/src/object/old_object.h @@ -110,8 +110,8 @@ public: void Simplify() override; - bool DamageObject(DamageType type, float force = std::numeric_limits::infinity()) override; - void DestroyObject(DestructionType type) override; + bool DamageObject(DamageType type, float force = std::numeric_limits::infinity(), CObject* killer = nullptr) override; + void DestroyObject(DestructionType type, CObject* killer = nullptr) override; bool EventProcess(const Event& event) override; void UpdateMapping(); diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 8fcc08c3..6125a699 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -2701,6 +2701,7 @@ bool CPhysics::ExploOther(ObjectType iType, if ( force > destructionForce ) { + // TODO: implement "killer"? dynamic_cast(pObj)->DamageObject(damageType); } } @@ -2726,6 +2727,7 @@ bool CPhysics::ExploOther(ObjectType iType, oType == OBJECT_HUSTON ) // building? { assert(pObj->Implements(ObjectInterfaceType::Damageable)); + // TODO: implement "killer"? dynamic_cast(pObj)->DamageObject(DamageType::Collision, force/400.0f); } @@ -2756,6 +2758,7 @@ bool CPhysics::ExploOther(ObjectType iType, oType == OBJECT_MOBILEit ) // vehicle? { assert(pObj->Implements(ObjectInterfaceType::Damageable)); + // TODO: implement "killer"? dynamic_cast(pObj)->DamageObject(DamageType::Collision, force/200.0f); } } @@ -2780,6 +2783,7 @@ int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force) if ( force > destructionForce && destructionForce >= 0.0f ) { + // TODO: implement "killer"? dynamic_cast(m_object)->DamageObject(DamageType::Explosive); return 2; } @@ -2860,6 +2864,7 @@ int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force) force /= 200.0f; } + // TODO: implement "killer"? if ( dynamic_cast(m_object)->DamageObject(DamageType::Collision, force) ) return 2; } } From cf7c19ef62b3b3ecb18bff505ed5b299ad47584d Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 17 May 2017 19:00:40 +0200 Subject: [PATCH 57/93] Make teams and scoreboard translatable --- po/colobot.pot | 22 ++++++++++++++++++++++ po/de.po | 22 ++++++++++++++++++++++ po/fr.po | 22 ++++++++++++++++++++++ po/pl.po | 22 ++++++++++++++++++++++ po/ru.po | 22 ++++++++++++++++++++++ src/common/error.h | 3 +++ src/common/restext.cpp | 7 +++++++ src/common/restext.h | 4 ++++ src/level/robotmain.cpp | 22 +++++++++++++++++----- src/level/scoreboard.cpp | 11 ++++++++++- 10 files changed, 151 insertions(+), 6 deletions(-) diff --git a/po/colobot.pot b/po/colobot.pot index 30a4c1c8..5a04df82 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -260,6 +260,16 @@ msgstr "" msgid "Generating" msgstr "" +msgid "Results" +msgstr "" + +msgid "The battle has ended" +msgstr "" + +#, c-format +msgid "%s: %d pts" +msgstr "" + msgid "Cancel" msgstr "" @@ -1601,6 +1611,18 @@ msgstr "" msgid "Press \\key help; to read instructions on your SatCom" msgstr "" +#, c-format +msgid "<<< Team %s finished! >>>" +msgstr "" + +#, c-format +msgid "<<< Team %s lost! >>>" +msgstr "" + +#, c-format +msgid "<<< Team %s recieved %d points >>>" +msgstr "" + msgid "Opening bracket missing" msgstr "" diff --git a/po/de.po b/po/de.po index 255608e3..8b1be9f4 100644 --- a/po/de.po +++ b/po/de.po @@ -29,6 +29,10 @@ msgstr "Es fehlt eine offene eckige Klammer \" [ \"" msgid "\" ] \" missing" msgstr "Es fehlt eine geschlossene eckige Klammer \" ] \"" +#, c-format +msgid "%s: %d pts" +msgstr "" + msgid "..behind" msgstr "..hinten" @@ -50,6 +54,18 @@ msgstr "<< Zurück \\Zurück zum Hauptmenü" msgid "<<< Sorry; mission failed >>>" msgstr "<<< Mission gescheitert >>>" +#, c-format +msgid "<<< Team %s finished! >>>" +msgstr "" + +#, c-format +msgid "<<< Team %s lost! >>>" +msgstr "" + +#, c-format +msgid "<<< Team %s recieved %d points >>>" +msgstr "" + msgid "<<< Well done; mission accomplished >>>" msgstr "<<< Bravo, Mission vollendet >>>" @@ -1258,6 +1274,9 @@ msgstr "" msgid "Restoring saved objects" msgstr "" +msgid "Results" +msgstr "" + msgid "Return to start" msgstr "Alles zurücksetzen" @@ -1486,6 +1505,9 @@ msgstr "" msgid "Textures" msgstr "" +msgid "The battle has ended" +msgstr "" + msgid "The expression must return a boolean value" msgstr "Der Ausdruck muss einen boolschen Wert ergeben" diff --git a/po/fr.po b/po/fr.po index 818948a0..ea65fcbd 100644 --- a/po/fr.po +++ b/po/fr.po @@ -25,6 +25,10 @@ msgstr "\" [ \" attendu" msgid "\" ] \" missing" msgstr "\" ] \" attendu" +#, c-format +msgid "%s: %d pts" +msgstr "" + msgid "..behind" msgstr "..derrière" @@ -46,6 +50,18 @@ msgstr "<< Retour \\Retour au niveau précédent" msgid "<<< Sorry; mission failed >>>" msgstr "<<< Désolé; mission échouée >>>" +#, c-format +msgid "<<< Team %s finished! >>>" +msgstr "" + +#, c-format +msgid "<<< Team %s lost! >>>" +msgstr "" + +#, c-format +msgid "<<< Team %s recieved %d points >>>" +msgstr "" + msgid "<<< Well done; mission accomplished >>>" msgstr "<<< Bravo; mission terminée >>>" @@ -1236,6 +1252,9 @@ msgstr "Restaurer l'état d'exécution CBOT" msgid "Restoring saved objects" msgstr "Restaurer des objets sauvés" +msgid "Results" +msgstr "" + msgid "Return to start" msgstr "Remet au départ" @@ -1458,6 +1477,9 @@ msgstr "Filtrage de textures\\Filtrage de textures" msgid "Textures" msgstr "Textures" +msgid "The battle has ended" +msgstr "" + msgid "The expression must return a boolean value" msgstr "L'expression doit ętre un boolean" diff --git a/po/pl.po b/po/pl.po index aaa50b8a..699a4287 100644 --- a/po/pl.po +++ b/po/pl.po @@ -27,6 +27,10 @@ msgstr "Oczekiwane \" [ \"" msgid "\" ] \" missing" msgstr "Brak \" ] \"" +#, c-format +msgid "%s: %d pts" +msgstr "%s: %d pkt" + msgid "..behind" msgstr "..za" @@ -48,6 +52,18 @@ msgstr "<< Wstecz \\Wraca do poprzedniego ekranu" msgid "<<< Sorry; mission failed >>>" msgstr "<<< Niestety, misja nie powiodła się >>>" +#, c-format +msgid "<<< Team %s finished! >>>" +msgstr "<<< Drużyna %s zakończyła rozgrywkę! >>>" + +#, c-format +msgid "<<< Team %s lost! >>>" +msgstr "<<< Drużyna %s odpadła! >>>" + +#, c-format +msgid "<<< Team %s recieved %d points >>>" +msgstr "<<< Drużyna %s zdobyła %d punktów >>>" + msgid "<<< Well done; mission accomplished >>>" msgstr "<<< Dobra robota, misja wypełniona >>>" @@ -1238,6 +1254,9 @@ msgstr "Przywracanie stanu CBot" msgid "Restoring saved objects" msgstr "Przywracanie obiektów" +msgid "Results" +msgstr "Wyniki" + msgid "Return to start" msgstr "Powrót do początku" @@ -1460,6 +1479,9 @@ msgstr "Filtrowanie tekstur\\Filtrowanie tekstur" msgid "Textures" msgstr "Tekstury" +msgid "The battle has ended" +msgstr "Bitwa zakończyła się" + msgid "The expression must return a boolean value" msgstr "Wyrażenie musi zwrócić wartość logiczną" diff --git a/po/ru.po b/po/ru.po index f479b47e..531a06bc 100644 --- a/po/ru.po +++ b/po/ru.po @@ -27,6 +27,10 @@ msgstr "Ожидалось \" [ \"" msgid "\" ] \" missing" msgstr "Отсутствует \"]\" " +#, c-format +msgid "%s: %d pts" +msgstr "" + msgid "..behind" msgstr "Сзади" @@ -48,6 +52,18 @@ msgstr "<< Назад \\Вернуться на предыдущую стран msgid "<<< Sorry; mission failed >>>" msgstr "<<< Миссия провалена >>>" +#, c-format +msgid "<<< Team %s finished! >>>" +msgstr "" + +#, c-format +msgid "<<< Team %s lost! >>>" +msgstr "" + +#, c-format +msgid "<<< Team %s recieved %d points >>>" +msgstr "" + msgid "<<< Well done; mission accomplished >>>" msgstr "<<< Отлично, миссия выполнена >>>" @@ -1250,6 +1266,9 @@ msgstr "Восстановление состояния CBot" msgid "Restoring saved objects" msgstr "Восстановить сохранённые объекты" +msgid "Results" +msgstr "" + msgid "Return to start" msgstr "Вернуться в начало" @@ -1474,6 +1493,9 @@ msgstr "Фильтрация текстур\\Фильтрация текстур msgid "Textures" msgstr "Текстуры" +msgid "The battle has ended" +msgstr "" + msgid "The expression must return a boolean value" msgstr "Выражение должно возвращать логическое значение" diff --git a/src/common/error.h b/src/common/error.h index d3ae49f7..7522c01a 100644 --- a/src/common/error.h +++ b/src/common/error.h @@ -147,6 +147,9 @@ enum Error INFO_DELETEWORM = 10103, //! < insect killed INFO_DELETESPIDER = 10104, //! < insect killed INFO_BEGINSATCOM = 10105, //! < use your SatCom + INFO_TEAM_FINISH = 10110, + INFO_TEAM_DEAD = 10111, + INFO_TEAM_SCORE = 10112, ERR_MAX //! < number of values }; diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 035389b4..0eec9f7d 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -143,6 +143,10 @@ void InitializeRestext() stringsText[RT_LOADING_TERRAIN_TEX] = TR("Textures"); stringsText[RT_LOADING_TERRAIN_GEN] = TR("Generating"); + stringsText[RT_SCOREBOARD_RESULTS] = TR("Results"); + stringsText[RT_SCOREBOARD_RESULTS_TEXT]= TR("The battle has ended"); + stringsText[RT_SCOREBOARD_RESULTS_LINE]= TR("%s: %d pts"); + stringsEvent[EVENT_BUTTON_OK] = TR("OK"); @@ -671,6 +675,9 @@ void InitializeRestext() stringsErr[INFO_DELETEWORM] = TR("Worm fatally wounded"); stringsErr[INFO_DELETESPIDER] = TR("Spider fatally wounded"); stringsErr[INFO_BEGINSATCOM] = TR("Press \\key help; to read instructions on your SatCom"); + stringsErr[INFO_TEAM_FINISH] = TR("<<< Team %s finished! >>>"); + stringsErr[INFO_TEAM_DEAD] = TR("<<< Team %s lost! >>>"); + stringsErr[INFO_TEAM_SCORE] = TR("<<< Team %s recieved %d points >>>"); diff --git a/src/common/restext.h b/src/common/restext.h index b875f1c4..3c0af1a0 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -140,6 +140,10 @@ enum ResTextType RT_LOADING_TERRAIN_TEX = 222, RT_LOADING_TERRAIN_GEN = 223, + RT_SCOREBOARD_RESULTS = 230, + RT_SCOREBOARD_RESULTS_TEXT= 231, + RT_SCOREBOARD_RESULTS_LINE= 232, + RT_MAX //! < number of values }; diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index b723b58c..6530311d 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -4958,16 +4958,22 @@ Error CRobotMain::ProcessEndMissionTake() GetLogger()->Info("All teams died, mission ended\n"); if (m_scoreboard) { + std::string title, text, details_line; + GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS, title); + GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_TEXT, text); + GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_LINE, details_line); std::string details = ""; for (auto it : teams) { int team = it.first; if (team == 0) continue; - details += "Team "+boost::lexical_cast(team)+": "+boost::lexical_cast(m_scoreboard->GetScore(team))+" points\n"; + if (!details.empty()) + details += ", "; + details += StrUtils::Format(details_line.c_str(), GetTeamName(team).c_str(), m_scoreboard->GetScore(team)); } m_ui->GetDialog()->StartInformation( - "Results", - "The battle has ended", + title, + text, details, false, true, [&]() { @@ -4994,7 +5000,10 @@ Error CRobotMain::ProcessEndMissionTake() 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); + std::string text; + GetResource(RES_ERR, INFO_TEAM_DEAD, text); + text = StrUtils::Format(text.c_str(), GetTeamName(team).c_str()); + m_displayText->DisplayText(text.c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_ERROR); m_displayText->SetEnable(false); // To prevent "bot destroyed" messages m_objMan->DestroyTeam(team); @@ -5022,7 +5031,10 @@ Error CRobotMain::ProcessEndMissionTake() m_missionResult = ERR_OK; return ERR_OK;*/ GetLogger()->Info("Team %d finished\n", team); - m_displayText->DisplayText(("<<< Team "+boost::lexical_cast(team)+" finished >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f)); + std::string text; + GetResource(RES_ERR, INFO_TEAM_FINISH, text); + text = StrUtils::Format(text.c_str(), GetTeamName(team).c_str()); + m_displayText->DisplayText(text.c_str(), Math::Vector(0.0f,0.0f,0.0f)); if (m_scoreboard) m_scoreboard->ProcessEndTake(team); m_objMan->DestroyTeam(team, DestructionType::Win); diff --git a/src/level/scoreboard.cpp b/src/level/scoreboard.cpp index 7208dd49..bb78aae1 100644 --- a/src/level/scoreboard.cpp +++ b/src/level/scoreboard.cpp @@ -19,6 +19,9 @@ #include "level/scoreboard.h" +#include "common/restext.h" +#include "common/stringutils.h" + #include "level/parser/parserline.h" #include "level/robotmain.h" @@ -84,7 +87,13 @@ void CScoreboard::ProcessEndTake(int team) void CScoreboard::AddPoints(int team, int points) { GetLogger()->Info("Team %d earned %d points\n", team, points); - CRobotMain::GetInstancePointer()->GetDisplayText()->DisplayText(("<<< Team "+boost::lexical_cast(team)+" recieved "+boost::lexical_cast(points)+" points! >>>").c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_WARNING); + + CRobotMain* main = CRobotMain::GetInstancePointer(); + std::string text; + GetResource(RES_ERR, INFO_TEAM_SCORE, text); + text = StrUtils::Format(text.c_str(), main->GetTeamName(team).c_str(), points); + main->GetDisplayText()->DisplayText(text.c_str(), Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 10.0f, Ui::TT_WARNING); + m_score[team] += points; } From f6cc629054f0c1a4627304b9b52044323a42f451 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Thu, 18 May 2017 18:32:22 +0200 Subject: [PATCH 58/93] Log correct terrain relief resolution --- src/graphics/engine/terrain.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/graphics/engine/terrain.cpp b/src/graphics/engine/terrain.cpp index 7ff24172..8467b86d 100644 --- a/src/graphics/engine/terrain.cpp +++ b/src/graphics/engine/terrain.cpp @@ -229,7 +229,7 @@ bool CTerrain::LoadResources(const std::string& fileName) if ( (data->surface->w != size) || (data->surface->h != size) ) { - GetLogger()->Error("Invalid resource file\n"); + GetLogger()->Error("Invalid resource file! Expected %dx%d\n", size, size); return false; } @@ -311,10 +311,11 @@ bool CTerrain::LoadRelief(const std::string &fileName, float scaleRelief, ImageData *data = img.GetData(); int size = (m_mosaicCount*m_brickCount)+1; + GetLogger()->Debug("Expected relief size for current terrain configuration is %dx%d\n", size, size); if ( (data->surface->w != size) || (data->surface->h != size) ) { - GetLogger()->Error("Invalid relief file!\n"); + GetLogger()->Error("Invalid relief file! Expected %dx%d\n", size, size); return false; } From 6bebbb3f7011cbf9fcd42cb24fd7f39e52015e05 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Thu, 18 May 2017 19:03:19 +0200 Subject: [PATCH 59/93] Fix sky rendering artifact --- src/graphics/engine/cloud.cpp | 2 -- src/graphics/engine/engine.cpp | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/graphics/engine/cloud.cpp b/src/graphics/engine/cloud.cpp index 110f39b9..20cd6aa4 100644 --- a/src/graphics/engine/cloud.cpp +++ b/src/graphics/engine/cloud.cpp @@ -234,8 +234,6 @@ void CCloud::Create(const std::string& fileName, m_lines.clear(); for (int y = 0; y < m_brickCount; y++) CreateLine(0, y, m_brickCount); - - return; } void CCloud::Flush() diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 768897fe..943491b6 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -3266,7 +3266,9 @@ void CEngine::Draw3DScene() m_device->SetTransform(TRANSFORM_PROJECTION, m_matProj); m_device->SetTransform(TRANSFORM_VIEW, m_matView); - m_water->DrawBack(); // draws water background + // TODO: This causes a rendering artifact and I can't see anything that breaks if you just comment it out + // So I'll just leave it like that for now ~krzys_h + //m_water->DrawBack(); // draws water background CProfiler::StartPerformanceCounter(PCNT_RENDER_TERRAIN); From 327eafddb7f1d20cf16f4f9ba9a08dde368cdc8d Mon Sep 17 00:00:00 2001 From: krzys-h Date: Thu, 18 May 2017 20:39:32 +0200 Subject: [PATCH 60/93] Add order= parameter for ScoreboardEndTakeRule --- src/level/scoreboard.cpp | 5 ++++- src/level/scoreboard.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/level/scoreboard.cpp b/src/level/scoreboard.cpp index bb78aae1..dc86eeed 100644 --- a/src/level/scoreboard.cpp +++ b/src/level/scoreboard.cpp @@ -47,6 +47,7 @@ void CScoreboard::CScoreboardEndTakeRule::Read(CLevelParserLine* line) { CScoreboardRule::Read(line); this->team = line->GetParam("team")->AsInt(0); + this->order = line->GetParam("order")->AsInt(0); } void CScoreboard::AddKillRule(std::unique_ptr rule) @@ -75,9 +76,11 @@ void CScoreboard::ProcessKill(CObject* target, CObject* killer) void CScoreboard::ProcessEndTake(int team) { + m_finishCounter++; for (auto& rule : m_rulesEndTake) { - if (rule->team == team || rule->team == 0) + if ((rule->team == team || rule->team == 0) && + (rule->order == m_finishCounter || rule->order == 0)) { AddPoints(team, rule->score); } diff --git a/src/level/scoreboard.h b/src/level/scoreboard.h index c0c2512b..17aa98ec 100644 --- a/src/level/scoreboard.h +++ b/src/level/scoreboard.h @@ -94,6 +94,7 @@ public: { public: int team = 0; + int order = 0; //! Read from line in scene file void Read(CLevelParserLine* line) override; @@ -117,4 +118,5 @@ private: std::vector> m_rulesKill = {}; std::vector> m_rulesEndTake = {}; std::map m_score; + int m_finishCounter = 0; }; \ No newline at end of file From 8948da0612766234c673a3585325de3ef80b44f6 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 19 May 2017 15:33:44 +0200 Subject: [PATCH 61/93] Add Barricade objects --- data | 2 +- src/level/parser/parserparam.cpp | 4 +++ src/object/object_factory.cpp | 44 ++++++++++++++++++++++++++++++++ src/object/object_manager.cpp | 4 ++- src/object/object_type.h | 2 ++ src/object/old_object.cpp | 12 ++++++++- src/object/old_object.h | 6 +++++ 7 files changed, 71 insertions(+), 3 deletions(-) diff --git a/data b/data index 3b99a621..41c03fda 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 3b99a62185c4aba3c6c7507dfbbbcf5bcbce3ba2 +Subproject commit 41c03fda84e6eab6cd105fffd77a26cde4c1fe12 diff --git a/src/level/parser/parserparam.cpp b/src/level/parser/parserparam.cpp index fb3c82f7..37773efa 100644 --- a/src/level/parser/parserparam.cpp +++ b/src/level/parser/parserparam.cpp @@ -467,6 +467,8 @@ ObjectType CLevelParserParam::ToObjectType(std::string value) if (value == "Barrier1" ) return OBJECT_BARRIER1; if (value == "Barrier2" ) return OBJECT_BARRIER2; if (value == "Barrier3" ) return OBJECT_BARRIER3; + if (value == "Barricade0" ) return OBJECT_BARRICADE0; + if (value == "Barricade1" ) return OBJECT_BARRICADE1; if (value == "Teen0" ) return OBJECT_TEEN0; if (value == "Teen1" ) return OBJECT_TEEN1; if (value == "Teen2" ) return OBJECT_TEEN2; @@ -662,6 +664,8 @@ const std::string CLevelParserParam::FromObjectType(ObjectType value) if (value == OBJECT_BARRIER1 ) return "Barrier1"; if (value == OBJECT_BARRIER2 ) return "Barrier2"; if (value == OBJECT_BARRIER3 ) return "Barrier3"; + if (value == OBJECT_BARRICADE0 ) return "Barricade0"; + if (value == OBJECT_BARRICADE1 ) return "Barricade1"; if (value == OBJECT_TEEN0 ) return "Teen0"; if (value == OBJECT_TEEN1 ) return "Teen1"; if (value == OBJECT_TEEN2 ) return "Teen2"; diff --git a/src/object/object_factory.cpp b/src/object/object_factory.cpp index 76e9d59d..0b16e171 100644 --- a/src/object/object_factory.cpp +++ b/src/object/object_factory.cpp @@ -149,6 +149,8 @@ CObjectUPtr CObjectFactory::CreateObject(const ObjectCreateParams& params) case OBJECT_BARRIER1: case OBJECT_BARRIER2: case OBJECT_BARRIER3: + case OBJECT_BARRICADE0: + case OBJECT_BARRICADE1: return CreateBarrier(params); case OBJECT_PLANT0: @@ -579,6 +581,48 @@ CObjectUPtr CObjectFactory::CreateBarrier(const ObjectCreateParams& params) obj->CreateShadowCircle(10.0f, 0.5f, Gfx::ENG_SHADOW_WORM); } + if ( type == OBJECT_BARRICADE0 ) + { + int rank = m_engine->CreateObject(); + m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_FIX); + obj->SetObjectRank(0, rank); + m_oldModelManager->AddModelReference("barricade0.mod", false, rank, obj->GetTeam()); + obj->SetPosition(pos); + obj->SetRotationY(angle); + + obj->AddCrashSphere(CrashSphere(Math::Vector( 3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector( 0.0f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector(-3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector( 3.5f, 6.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector( 0.0f, 6.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector(-3.5f, 6.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + + obj->CreateShadowCircle(6.0f, 0.5f, Gfx::ENG_SHADOW_WORM); + } + + if ( type == OBJECT_BARRICADE1 ) + { + int rank = m_engine->CreateObject(); + m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_FIX); + obj->SetObjectRank(0, rank); + m_oldModelManager->AddModelReference("barricade1.mod", false, rank, obj->GetTeam()); + obj->SetPosition(pos); + obj->SetRotationY(angle); + + obj->AddCrashSphere(CrashSphere(Math::Vector( 8.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector( 3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector( 0.0f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector(-3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector(-8.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector( 8.5f, 6.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector( 3.5f, 6.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector( 0.0f, 6.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector(-3.5f, 6.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + obj->AddCrashSphere(CrashSphere(Math::Vector(-8.5f, 6.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f)); + + obj->CreateShadowCircle(12.0f, 0.5f, Gfx::ENG_SHADOW_WORM); + } + pos = obj->GetPosition(); obj->SetPosition(pos); // to display the shadows immediately diff --git a/src/object/object_manager.cpp b/src/object/object_manager.cpp index 9483936a..a33a89fc 100644 --- a/src/object/object_manager.cpp +++ b/src/object/object_manager.cpp @@ -311,7 +311,9 @@ std::vector CObjectManager::RadarAll(CObject* pThis, Math::Vector this } if ( oType == OBJECT_BARRIER2 || - oType == OBJECT_BARRIER3 ) // barriers? + oType == OBJECT_BARRIER3 || + oType == OBJECT_BARRICADE0 || + oType == OBJECT_BARRICADE1 ) // barriers? { oType = OBJECT_BARRIER1; // any barrier } diff --git a/src/object/object_type.h b/src/object/object_type.h index 11d5763d..88c9587c 100644 --- a/src/object/object_type.h +++ b/src/object/object_type.h @@ -146,6 +146,8 @@ enum ObjectType OBJECT_BARRIER1 = 401, //!< Barrier1 OBJECT_BARRIER2 = 402, //!< Barrier2 OBJECT_BARRIER3 = 403, //!< Barrier3 + OBJECT_BARRICADE0 = 410, //!< Barricade0 + OBJECT_BARRICADE1 = 411, //!< Barricade1 OBJECT_MOTHER = 500, //!< AlienQueen OBJECT_EGG = 501, //!< AlienEgg OBJECT_ANT = 502, //!< AlienAnt diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index fb510d8d..0930f025 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -1047,7 +1047,7 @@ void COldObject::Read(CLevelParserLine* line) if (line->GetParam("pyro")->IsDefined()) m_engine->GetPyroManager()->Create(line->GetParam("pyro")->AsPyroType(), this); - SetBulletWall(line->GetParam("bulletWall")->AsBool(false)); + SetBulletWall(line->GetParam("bulletWall")->AsBool(IsBulletWallByDefault(m_type))); SetProxyActivate(line->GetParam("proxyActivate")->AsBool(false)); SetProxyDistance(line->GetParam("proxyDistance")->AsFloat(15.0f)*g_unit); @@ -3212,3 +3212,13 @@ bool COldObject::IsBulletWall() { return m_bulletWall; } + +bool COldObject::IsBulletWallByDefault(ObjectType type) +{ + if ( type == OBJECT_BARRICADE0 || + type == OBJECT_BARRICADE1 ) + { + return true; + } + return false; +} diff --git a/src/object/old_object.h b/src/object/old_object.h index bc2d0b0a..697e05db 100644 --- a/src/object/old_object.h +++ b/src/object/old_object.h @@ -311,6 +311,12 @@ protected: */ static bool IsSelectableByDefault(ObjectType type); + /** + * \brief Check if given object type should have bulletWall enabled by default + * \note This is a default value for the bulletWall= parameter and can still be overriden in the scene file + */ + static bool IsBulletWallByDefault(ObjectType type); + protected: Gfx::CEngine* m_engine; Gfx::CLightManager* m_lightMan; From b3ea687d327c3779601e2724f31c276e002581e4 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 19 May 2017 20:15:13 +0200 Subject: [PATCH 62/93] Minor documentation fixes --- Doxyfile.in | 2 +- src/common/resources/outputstream.h | 4 ++-- src/common/resources/outputstreambuffer.h | 2 +- src/level/scoreboard.h | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Doxyfile.in b/Doxyfile.in index 5b0d31f7..178001f3 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -993,7 +993,7 @@ USE_HTAGS = NO # See also: Section \class. # The default value is: YES. -VERBATIM_HEADERS = YES +VERBATIM_HEADERS = NO # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the diff --git a/src/common/resources/outputstream.h b/src/common/resources/outputstream.h index c1ac33d4..1aeaf740 100644 --- a/src/common/resources/outputstream.h +++ b/src/common/resources/outputstream.h @@ -39,7 +39,7 @@ public: /** Construct and Open Stream for writing * * \param filename - * \param Mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file + * \param mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file * */ COutputStream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out); @@ -48,7 +48,7 @@ public: /** Open Stream for writing * * \param filename - * \param Mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file + * \param mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file * */ void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out); diff --git a/src/common/resources/outputstreambuffer.h b/src/common/resources/outputstreambuffer.h index fb7fa538..0945b303 100644 --- a/src/common/resources/outputstreambuffer.h +++ b/src/common/resources/outputstreambuffer.h @@ -38,7 +38,7 @@ public: /** Open Stream Buffer for writing * * \param filename - * \param Mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file + * \param mode one of: std::ios_base::out - Open for writing, std::ios_base::app - Append to file * */ void open(const std::string &filename, std::ios_base::openmode mode); diff --git a/src/level/scoreboard.h b/src/level/scoreboard.h index 17aa98ec..6768a595 100644 --- a/src/level/scoreboard.h +++ b/src/level/scoreboard.h @@ -101,7 +101,9 @@ public: }; public: + //! Add ScoreboardKillRule void AddKillRule(std::unique_ptr rule); + //! Add ScoreboardEndTakeRule void AddEndTakeRule(std::unique_ptr rule); //! Called after an object is destroyed by another object From c68f5e276f88d81cf2f455172f5bc9e20ed74ca8 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 19 May 2017 21:11:43 +0200 Subject: [PATCH 63/93] Add live scoreboard display --- src/common/event.h | 3 ++ src/level/robotmain.cpp | 98 ++++++++++++++++++++++++++++++++--------- src/level/robotmain.h | 6 +++ 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/src/common/event.h b/src/common/event.h index c67b7c3d..ba9a905e 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -187,6 +187,9 @@ enum EventType EVENT_LOADING = 120, + EVENT_SCOREBOARD = 130, + EVENT_SCOREBOARD_MAX = 169, + EVENT_TOOLTIP = 200, EVENT_DIALOG_OK = 300, diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 6530311d..3cd13e16 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -2569,6 +2569,8 @@ bool CRobotMain::EventFrame(const Event &event) m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE)); } + + UpdateCodeBattleInterface(); } return true; @@ -4929,31 +4931,23 @@ Error CRobotMain::ProcessEndMissionTakeForGroup(std::vector Error CRobotMain::ProcessEndMissionTake() { // Sort end conditions by teams - std::map> teams; + std::map> teamsEndTake; for (std::unique_ptr& endTake : m_endTake) - teams[endTake->winTeam].push_back(endTake.get()); + teamsEndTake[endTake->winTeam].push_back(endTake.get()); - int teamCount = 0; - bool usesTeamConditions = false; - for (auto it : teams) - { - int team = it.first; - if (team == 0) continue; - usesTeamConditions = true; - if (m_teamFinished[team]) continue; - teamCount++; - } + // This is just a smart way to check if we have any map values other than 0 defined + bool usesTeamConditions = teamsEndTake.size() > teamsEndTake.count(0); if (!usesTeamConditions) { - m_missionResult = ProcessEndMissionTakeForGroup(teams[0]); + m_missionResult = ProcessEndMissionTakeForGroup(teamsEndTake[0]); } else { // Special handling for teams m_missionResult = ERR_MISSION_NOTERM; - if (teamCount == 0) + if (GetAllActiveTeams().empty()) { GetLogger()->Info("All teams died, mission ended\n"); if (m_scoreboard) @@ -4963,10 +4957,8 @@ Error CRobotMain::ProcessEndMissionTake() GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_TEXT, text); GetResource(RES_TEXT, RT_SCOREBOARD_RESULTS_LINE, details_line); std::string details = ""; - for (auto it : teams) + for (int team : GetAllTeams()) { - int team = it.first; - if (team == 0) continue; if (!details.empty()) details += ", "; details += StrUtils::Format(details_line.c_str(), GetTeamName(team).c_str(), m_scoreboard->GetScore(team)); @@ -4990,7 +4982,7 @@ Error CRobotMain::ProcessEndMissionTake() } else { - for (auto it : teams) + for (auto it : teamsEndTake) { int team = it.first; if (team == 0) continue; @@ -5792,12 +5784,16 @@ void CRobotMain::StartDetectEffect(COldObject* object, CObject* target) void CRobotMain::CreateCodeBattleInterface() { - if(m_phase == PHASE_SIMUL) + if (m_phase == PHASE_SIMUL) { Math::Point pos, ddim; + int numTeams = m_scoreboard ? GetAllTeams().size() : 0; + assert(numTeams < EVENT_SCOREBOARD_MAX-EVENT_SCOREBOARD+1); + float textHeight = m_engine->GetText()->GetAscent(Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL); + ddim.x = 100.0f/640.0f; - ddim.y = 100.0f/480.0f; + ddim.y = 100.0f/480.0f + numTeams * textHeight; pos.x = 540.0f/640.0f; pos.y = 100.0f/480.0f; Ui::CWindow* pw = m_interface->CreateWindows(pos, ddim, 3, EVENT_WINDOW6); @@ -5805,7 +5801,7 @@ void CRobotMain::CreateCodeBattleInterface() ddim.x = 100.0f/640.0f; ddim.y = 16.0f/480.0f; pos.x = 540.0f/640.0f; - pos.y = 178.0f/480.0f; + pos.y = 178.0f/480.0f + numTeams * textHeight; pw->CreateLabel(pos, ddim, 0, EVENT_LABEL0, "Code battle"); float titleBarSize = (11.0f/64.0f); // this is from the texture @@ -5821,9 +5817,47 @@ void CRobotMain::CreateCodeBattleInterface() { pw->CreateButton(pos, ddim, 13, EVENT_CODE_BATTLE_SPECTATOR); } + + pos.y += ddim.y; + ddim.y = textHeight; + for (int i = 0; i < numTeams; i++) + { + Ui::CLabel* pl; + pl = pw->CreateLabel(pos, ddim, 0, static_cast(EVENT_SCOREBOARD+2*(numTeams-i-1)+0), "XXXXX"); + pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); + pl = pw->CreateLabel(pos, ddim, 0, static_cast(EVENT_SCOREBOARD+2*(numTeams-i-1)+1), "???"); + pl->SetTextAlign(Gfx::TEXT_ALIGN_RIGHT); + pos.y += ddim.y; + } } } +void CRobotMain::UpdateCodeBattleInterface() +{ + assert(GetMissionType() == MISSION_CODE_BATTLE); + if (!m_scoreboard) return; + + Ui::CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW6)); + assert(pw != nullptr); + + int i = 0; + for (int team : GetAllTeams()) + { + Ui::CLabel* pl; + + pl = static_cast(pw->SearchControl(static_cast(EVENT_SCOREBOARD+2*i+0))); + assert(pl != nullptr); + pl->SetName(GetTeamName(team)); + + pl = static_cast(pw->SearchControl(static_cast(EVENT_SCOREBOARD+2*i+1))); + assert(pl != nullptr); + pl->SetName(StrUtils::ToString(m_scoreboard->GetScore(team))); + + i++; + } + +} + void CRobotMain::DestroyCodeBattleInterface() { m_interface->DeleteControl(EVENT_WINDOW6); @@ -5897,3 +5931,25 @@ CScoreboard* CRobotMain::GetScoreboard() { return m_scoreboard.get(); } + +std::set CRobotMain::GetAllTeams() +{ + std::set teams = GetAllActiveTeams(); + for(auto& it : m_teamFinished) + { + teams.insert(it.first); + } + return teams; +} + +std::set CRobotMain::GetAllActiveTeams() +{ + std::set teams; + for (CObject* obj : m_objMan->GetAllObjects()) + { + int team = obj->GetTeam(); + if (team == 0) continue; + teams.insert(team); + } + return teams; +} diff --git a/src/level/robotmain.h b/src/level/robotmain.h index 6bde5f6b..b1e69c97 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -468,6 +468,11 @@ public: //! Check if crash sphere debug rendering is enabled bool GetDebugCrashSpheres(); + //! Returns a set of all team IDs in the current level + std::set GetAllTeams(); + //! Returns a set of all team IDs in the current level that are still active + std::set GetAllActiveTeams(); + protected: bool EventFrame(const Event &event); bool EventObject(const Event &event); @@ -512,6 +517,7 @@ protected: //! \name Code battle interface //@{ void CreateCodeBattleInterface(); + void UpdateCodeBattleInterface(); void DestroyCodeBattleInterface(); void SetCodeBattleSpectatorMode(bool mode); //@} From 681d5203e5c407c02e8a0bb1595396e865018a5f Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 19 May 2017 21:23:14 +0200 Subject: [PATCH 64/93] Make code battle start button header translatable --- po/colobot.pot | 3 +++ po/de.po | 3 +++ po/fr.po | 4 ++++ po/pl.po | 3 +++ po/ru.po | 4 ++++ src/common/event.h | 2 ++ src/common/restext.cpp | 2 ++ src/level/robotmain.cpp | 4 +++- 8 files changed, 24 insertions(+), 1 deletion(-) diff --git a/po/colobot.pot b/po/colobot.pot index 5a04df82..4aee2bc0 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -270,6 +270,9 @@ msgstr "" msgid "%s: %d pts" msgstr "" +msgid "Code battle" +msgstr "" + msgid "Cancel" msgstr "" diff --git a/po/de.po b/po/de.po index 8b1be9f4..392ff91d 100644 --- a/po/de.po +++ b/po/de.po @@ -391,6 +391,9 @@ msgstr "Schließen" msgid "Closing bracket missing" msgstr "Es fehlt eine geschlossene Klammer \")\"" +msgid "Code battle" +msgstr "" + msgid "Code battles" msgstr "" diff --git a/po/fr.po b/po/fr.po index ea65fcbd..2de5e5ab 100644 --- a/po/fr.po +++ b/po/fr.po @@ -380,6 +380,10 @@ msgstr "Fermer" msgid "Closing bracket missing" msgstr "Il manque une parenthèse fermante" +#, fuzzy +msgid "Code battle" +msgstr "Batailles de code" + msgid "Code battles" msgstr "Batailles de code" diff --git a/po/pl.po b/po/pl.po index 699a4287..2995e516 100644 --- a/po/pl.po +++ b/po/pl.po @@ -382,6 +382,9 @@ msgstr "Zamknij" msgid "Closing bracket missing" msgstr "Brak nawiasu zamykającego" +msgid "Code battle" +msgstr "Programobitwa" + msgid "Code battles" msgstr "Programobitwy" diff --git a/po/ru.po b/po/ru.po index 531a06bc..b460b77a 100644 --- a/po/ru.po +++ b/po/ru.po @@ -388,6 +388,10 @@ msgstr "Закрыть" msgid "Closing bracket missing" msgstr "Закрывающая скобка отсутствует" +#, fuzzy +msgid "Code battle" +msgstr "Битвы роботов" + msgid "Code battles" msgstr "Битвы роботов" diff --git a/src/common/event.h b/src/common/event.h index ba9a905e..27ab1141 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -187,6 +187,8 @@ enum EventType EVENT_LOADING = 120, + EVENT_LABEL_CODE_BATTLE = 121, + EVENT_SCOREBOARD = 130, EVENT_SCOREBOARD_MAX = 169, diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 0eec9f7d..87812d66 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -149,6 +149,8 @@ void InitializeRestext() + stringsEvent[EVENT_LABEL_CODE_BATTLE] = TR("Code battle"); + stringsEvent[EVENT_BUTTON_OK] = TR("OK"); stringsEvent[EVENT_BUTTON_CANCEL] = TR("Cancel"); stringsEvent[EVENT_BUTTON_NEXT] = TR("Next"); diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 3cd13e16..4bcec60e 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -5802,7 +5802,9 @@ void CRobotMain::CreateCodeBattleInterface() ddim.y = 16.0f/480.0f; pos.x = 540.0f/640.0f; pos.y = 178.0f/480.0f + numTeams * textHeight; - pw->CreateLabel(pos, ddim, 0, EVENT_LABEL0, "Code battle"); + std::string text; + GetResource(RES_EVENT, EVENT_LABEL_CODE_BATTLE, text); + pw->CreateLabel(pos, ddim, 0, EVENT_LABEL_CODE_BATTLE, text); float titleBarSize = (11.0f/64.0f); // this is from the texture ddim.x = 80.0f/640.0f; From 47a8f70f0fbf4d4f984da3a595851b89c732ff54 Mon Sep 17 00:00:00 2001 From: tomangelo2 Date: Sat, 20 May 2017 20:41:30 +0200 Subject: [PATCH 65/93] Display warning if there is not enough energy to shoot Fix issue #949 --- src/script/scriptfunc.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index e93d5fac..ee9bc305 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -2382,6 +2382,11 @@ bool CScriptFunctions::rFire(CBotVar* var, CBotVar* result, int& exception, void if ( err != ERR_OK ) { script->m_taskExecutor->StopForegroundTask(); + if ( script->m_errMode == ERM_STOP ) + { + exception = err; + return false; + } return true; } } From 4bb05b32f53c00c79ee42d28d642ecf9107e91e3 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sun, 21 May 2017 20:19:55 +0200 Subject: [PATCH 66/93] Jenkinsfile: Update deprecated 'stage' syntax --- Jenkinsfile | 99 ++++++++++++++++++++++++++++------------------------- data | 2 +- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index ccd147b7..7b93de4a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,52 +1,57 @@ +#!/usr/bin/env groovy properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '30', artifactNumToKeepStr: '20']]]) 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 - ''' + stage('Pull changes') { + checkout scm } - 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]]]) -} + 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/data b/data index 41c03fda..b325c533 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 41c03fda84e6eab6cd105fffd77a26cde4c1fe12 +Subproject commit b325c53316b0b4ac7fe69597bff69499bee0ef6a From 92eb202d5d2327fa6c9a039435171a69d882a210 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sun, 21 May 2017 20:38:11 +0200 Subject: [PATCH 67/93] Jenkinsfile: Automatically clean workspace after building pull requests --- Jenkinsfile | 6 ++++++ data | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 7b93de4a..8676dbe1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -54,4 +54,10 @@ node('master') { } step([$class: 'XUnitBuilder', testTimeMargin: '3000', thresholdMode: 1, thresholds: [[$class: 'FailedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '0'], [$class: 'SkippedThreshold', failureNewThreshold: '', failureThreshold: '', unstableNewThreshold: '', unstableThreshold: '']], tools: [[$class: 'GoogleTestType', deleteOutputFiles: true, failIfNotNew: true, pattern: 'build/linux/gtestresults.xml', skipNoTestFiles: false, stopProcessingIfError: true]]]) } + + // Clean workspace after building pull requests + // to save disk space on the Jenkins host + if (env.BRANCH_NAME.startsWith('PR-')) { + cleanWs() + } } diff --git a/data b/data index b325c533..4df6d989 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit b325c53316b0b4ac7fe69597bff69499bee0ef6a +Subproject commit 4df6d989881d6b00944fbcbe6141f6426dc04e40 From 44d18b77becd775765403efa07a01c101ce4c4ed Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sun, 21 May 2017 20:40:03 +0200 Subject: [PATCH 68/93] Jenkinsfile: Don't keep artifacts for old PR builds --- Jenkinsfile | 6 +++++- data | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8676dbe1..2d1b76cf 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,9 @@ #!/usr/bin/env groovy -properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '30', artifactNumToKeepStr: '20']]]) +if (env.BRANCH_NAME.startsWith('PR-')) { + properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactNumToKeepStr: '1']]]) +} else { + properties([[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', artifactDaysToKeepStr: '30', artifactNumToKeepStr: '20']]]) +} node('master') { stage('Pull changes') { diff --git a/data b/data index 4df6d989..d54f880e 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 4df6d989881d6b00944fbcbe6141f6426dc04e40 +Subproject commit d54f880e5e8cab3d815f6ad1e5312e7159980180 From 7b328fbfc3252133ff7838317fa8629059026e51 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sun, 21 May 2017 21:45:43 +0200 Subject: [PATCH 69/93] Make UraniumOre not destroyable, closes #777 This was likely a mistake during object interface refactoring --- src/object/old_object.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index 0930f025..dbbb3890 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -355,6 +355,7 @@ bool COldObject::DamageObject(DamageType type, float force, CObject* killer) else if ( Implements(ObjectInterfaceType::Fragile) ) { if ( m_type == OBJECT_BOMB && type != DamageType::Explosive ) return false; // Mine can't be destroyed by shooting + if ( m_type == OBJECT_URANIUM ) return false; // UraniumOre is not destroyable (see #777) DestroyObject(DestructionType::Explosion, killer); return true; From a0e5cc25e136a57cda05fb58610a7fb6957b6659 Mon Sep 17 00:00:00 2001 From: MatiRg Date: Mon, 22 May 2017 10:57:30 +0200 Subject: [PATCH 70/93] Allow ctrl + backspace in the editor. (#839) --- src/ui/controls/edit.cpp | 79 +++++++++++++++++++++++++++++++++++++++- src/ui/controls/edit.h | 1 + 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/ui/controls/edit.cpp b/src/ui/controls/edit.cpp index f453c8fd..af04d93d 100644 --- a/src/ui/controls/edit.cpp +++ b/src/ui/controls/edit.cpp @@ -84,7 +84,17 @@ bool IsSep(int character) return !IsWord(character); } +bool IsBreaker(char c) +{ + return ( c == '.' || c == '{' || c == '}' || + c == ';' || c == ':' || c == '[' || c == ']' || + c == '(' || c == ')' || c == '=' || c == '"' || c == '\'' ); +} +bool IsDelimiter(char c) +{ + return IsSpace( c ) || IsBreaker( c ); +} //! Object's constructor. CEdit::CEdit() @@ -449,6 +459,19 @@ bool CEdit::EventProcess(const Event &event) return true; } + if ( data->key == KEY(BACKSPACE) && bControl ) + { + DeleteWord(-1); + SendModifEvent(); + return true; + } + if ( data->key == KEY(DELETE) && bControl ) + { + DeleteWord(1); + SendModifEvent(); + return true; + } + if ( data->key == KEY(RETURN) && !bControl ) { Insert('\n'); @@ -2744,8 +2767,62 @@ void CEdit::DeleteOne(int dir) } m_len -= hole; m_cursor2 = m_cursor1; -} +} +// Delete word + +void CEdit::DeleteWord(int dir) +{ + if ( !m_bEdit ) return; + + if ( dir < 0 ) + { + if ( m_cursor1 > 0) m_cursor2 = --m_cursor1; + else m_cursor2 = m_cursor1; + + if ( IsBreaker(m_text[m_cursor1]) ) + { + Delete(1); + return; + } + else ++m_cursor1; + + while ( m_cursor1 < m_len && !IsDelimiter(m_text[m_cursor1]) ) ++m_cursor1; + + while ( m_cursor2 > 0 && IsSpace(m_text[m_cursor2]) ) --m_cursor2; + + if ( !IsDelimiter(m_text[m_cursor2]) ) + { + while ( m_cursor2 > 0 && !IsDelimiter(m_text[m_cursor2]) ) --m_cursor2; + if ( IsBreaker(m_text[m_cursor2]) ) ++m_cursor2; + } + + Delete(-1); + } + else + { + m_cursor2 = m_cursor1; + + while ( m_cursor1 < m_len && IsSpace(m_text[m_cursor1]) ) ++m_cursor1; + + if ( IsBreaker(m_text[m_cursor1]) ) + { + ++m_cursor1; + Delete(1); + return; + } + + while ( m_cursor1 < m_len && !IsDelimiter(m_text[m_cursor1]) ) ++m_cursor1; + + if ( !IsDelimiter(m_text[m_cursor2]) ) + { + while ( m_cursor2 > 0 && !IsDelimiter(m_text[m_cursor2]) ) --m_cursor2; + if ( IsBreaker(m_text[m_cursor2]) ) ++m_cursor2; + } + + Delete(-1); + } +} // Calculates the indentation level of brackets {and}. diff --git a/src/ui/controls/edit.h b/src/ui/controls/edit.h index 8beb1140..380fbf5e 100644 --- a/src/ui/controls/edit.h +++ b/src/ui/controls/edit.h @@ -207,6 +207,7 @@ protected: void InsertOne(char character); void Delete(int dir); void DeleteOne(int dir); + void DeleteWord(int dir); int IndentCompute(); int IndentTabCount(); void IndentTabAdjust(int number); From df12f87b47f9811e6ed2cf1aa15031576d8ed7dc Mon Sep 17 00:00:00 2001 From: DavivaD Date: Mon, 22 May 2017 10:01:36 +0100 Subject: [PATCH 71/93] Implement damage alarm (#916) Implements part of #320 --- src/sound/sound_type.cpp | 3 ++- src/sound/sound_type.h | 1 + src/ui/object_interface.cpp | 22 ++++++++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/sound/sound_type.cpp b/src/sound/sound_type.cpp index 5eb4c53e..964782d2 100644 --- a/src/sound/sound_type.cpp +++ b/src/sound/sound_type.cpp @@ -109,7 +109,8 @@ const std::unordered_map SOUND_STRINGS = {"mushroom", SOUND_MUSHROOM}, {"firep", SOUND_FIREp}, {"explog1", SOUND_EXPLOg1}, - {"explog2", SOUND_EXPLOg2} + {"explog2", SOUND_EXPLOg2}, + {"alarms", SOUND_ALARMs} }; } // anonymous namespace diff --git a/src/sound/sound_type.h b/src/sound/sound_type.h index 360708dd..6985622f 100644 --- a/src/sound/sound_type.h +++ b/src/sound/sound_type.h @@ -116,6 +116,7 @@ enum SoundType SOUND_EXPLOg1 = 79, /*!< ShooterBots damaging objects. */ SOUND_EXPLOg2 = 80, /*!< OrgaShooterBots damaging objects. */ SOUND_MOTORd = 81, /*!< Scribbler/ToyBot engine. */ + SOUND_ALARMs = 82, /*!< Bot shield alarm. */ SOUND_MAX /** number of items in enum */ }; diff --git a/src/ui/object_interface.cpp b/src/ui/object_interface.cpp index a435c825..c819540a 100644 --- a/src/ui/object_interface.cpp +++ b/src/ui/object_interface.cpp @@ -1484,7 +1484,25 @@ void CObjectInterface::UpdateInterface(float rTime) if ( pg != nullptr ) { assert(m_object->Implements(ObjectInterfaceType::Shielded)); - pg->SetLevel(dynamic_cast(m_object)->GetShield()); + icon = 3; // orange/gray + float shield = dynamic_cast(m_object)->GetShield(); + + if ( shield < 0.4f && shield != 0.0f) // low but not zero? + { + if ( m_lastAlarmTime >= 0.8f ) // blinks? + { + shield = 1.0f; + icon = 2; // red + } + if ( m_lastAlarmTime >= 1.0f ) + { + m_sound->Play(SOUND_ALARMs, 0.5f); // beep-beep + m_lastAlarmTime = 0.0f; + } + } + + pg->SetLevel(shield); + pg->SetIcon(icon); } pg = static_cast< CGauge* >(pw->SearchControl(EVENT_OBJECT_GRANGE)); @@ -1494,7 +1512,7 @@ void CObjectInterface::UpdateInterface(float rTime) icon = 2; // blue/red range = dynamic_cast(m_object)->GetReactorRange(); - if ( range < 0.2f && range != 0.0f && !m_physics->GetLand() ) + if ( range < 0.2f && range != 0.0f && !m_physics->GetLand() ) // low but not zero/landed? { if ( Math::Mod(m_time, 0.5f) >= 0.2f ) // blinks? { From 24460ea979c693b0247fc21b4673e07af01a519f Mon Sep 17 00:00:00 2001 From: krzys-h Date: Mon, 22 May 2017 11:04:44 +0200 Subject: [PATCH 72/93] Update data submodule --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index d54f880e..1dc4ce70 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit d54f880e5e8cab3d815f6ad1e5312e7159980180 +Subproject commit 1dc4ce709c1f56a081c6bd90c04892234a2fb96d From 5055c5de11db91c5db7ca93d5c0e8dd77429fbaa Mon Sep 17 00:00:00 2001 From: Ceeee Date: Fri, 28 Oct 2016 21:33:42 +0200 Subject: [PATCH 73/93] Updating German locale (#849) Filled open gaps and tried to clarify some instances (native speaker) --- po/de.po | 252 +++++++++++++++++++++++++++---------------------------- 1 file changed, 124 insertions(+), 128 deletions(-) diff --git a/po/de.po b/po/de.po index 392ff91d..02277956 100644 --- a/po/de.po +++ b/po/de.po @@ -1,21 +1,21 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. +# Chris , 2016. msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: DATE\n" -"PO-Revision-Date: 2014-07-28 09:27+0200\n" -"Last-Translator: krzys_h \n" -"Language-Team: LANGUAGE \n" +"PO-Revision-Date: 2016-10-28 21:29+0200\n" +"Last-Translator: Chris \n" +"Language-Team: Colobot: Gold Edition freelancer\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Pootle 2.5.1.1\n" +"X-Generator: Virtaal 0.7.1\n" "X-Language: de_DE\n" "X-Source-Language: en_US\n" "X-POOTLE-MTIME: 1406536037.000000\n" @@ -46,7 +46,7 @@ msgid "1) First click on the key you want to redefine." msgstr "1) Klicken Sie auf die neu zu definierende Taste." msgid "2) Then press the key you want to use instead." -msgstr "2) Drücken Sie auf die neue Taste." +msgstr "2) Drücken Sie auf die neu zu verwendende Taste." msgid "<< Back \\Back to the previous screen" msgstr "<< Zurück \\Zurück zum Hauptmenü" @@ -73,7 +73,7 @@ msgid "A label must be followed by \"for\"; \"while\"; \"do\" or \"switch\"" msgstr "Ein Label kann nur vor den Anweisungen \"for\", \"while\", \"do\" oder \"switch\" vorkommen" msgid "A variable can not be declared twice" -msgstr "Eine Variable wird zum zweiten Mal deklariert" +msgstr "Eine Variable darf nicht zwei Mal deklariert werden" msgid "Abort\\Abort the current mission" msgstr "Abbrechen\\Mission abbrechen" @@ -88,7 +88,7 @@ msgid "Access to solutions\\Show program \"4: Solution\" in the exercises" msgstr "Lösung zugänglich\\Die Lösung ist im Programmslot \"4: Lösung\" zugänglich" msgid "Add new program" -msgstr "" +msgstr "Neues Programm hinzufügen" msgid "Alien Queen" msgstr "Insektenkönigin" @@ -101,6 +101,8 @@ msgstr "Trägt schon etwas" msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)" msgstr "" +"Alternativer Kameramodus\\Seitwärts bewegen statt rotieren (bei freier " +"Kamera)" msgid "Ambiguous call to overloaded function" msgstr "" @@ -115,7 +117,7 @@ msgid "Analyzes only organic matter" msgstr "Analysiert nur Orgastoff" msgid "Anisotropy level\\Anisotropy level" -msgstr "" +msgstr "Anisotropie-Level\\Anisotropie-Level" msgid "Ant" msgstr "Ameise" @@ -127,7 +129,7 @@ msgid "Appearance\\Choose your appearance" msgstr "Aussehen\\Erscheinungsbild des Astronauten einstellen" msgid "Apply changes\\Activates the changed settings" -msgstr "Änderungen ausführen\\Getätigte Einstellungen ausführen" +msgstr "Änderungen anwenden\\Getätigte Einstellungen anwenden" msgid "Appropriate constructor missing" msgstr "Es gibt keinen geeigneten Konstruktor" @@ -143,19 +145,22 @@ msgstr "Automatisches Einrücken\\Beim Bearbeiten der Programme" msgid "Autosave interval\\How often your game will autosave" msgstr "" +"Auto-Speichern Zeitintervall\\Wie oft das Spiel automatisch abgespeichert " +"wird" msgid "Autosave slots\\How many autosave slots you'll have" msgstr "" +"Auto-Speicherplätze\\Wie viele Plätze zum automatischen Speichern zur " +"Verfügung stehen" msgid "Autosave\\Enables autosave" -msgstr "" +msgstr "Auto-Speichern\\Aktiviert die automatische Speicherung" msgid "Back" msgstr "Vorherg. Seite" -#, fuzzy msgid "Background sound:\\Volume of audio tracks" -msgstr "Geräuschkulisse:\\Lautstärke der Soundtracks der CD" +msgstr "Hintergrundgeräusche:\\Lautstärke der Soundtracks" msgid "Backward (\\key down;)" msgstr "Rückwärts (\\key down;)" @@ -173,7 +178,7 @@ msgid "Black box" msgstr "Flugschreiber" msgid "Blood\\Display blood when the astronaut is hit" -msgstr "" +msgstr "Blut\\Blut anzeigen, wenn der Astronaut verletzt wird" msgid "Blue" msgstr "Blau" @@ -310,28 +315,25 @@ msgstr "Kamera (\\key camera;)" 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" +msgstr "" +"Kamerabewegung am Bildschirmrand\\Die Kamera dreht wenn die Maus den rechten " +"oder linken Rand erreicht" msgid "Camera closer\\Moves the camera forward" msgstr "Kamera näher\\Bewegung der Kamera vorwärts" -#, fuzzy msgid "Camera down\\Turns the camera down" -msgstr "Kamera näher\\Bewegung der Kamera vorwärts" +msgstr "Kamera ab\\Bewegt die Kamera abwärts" -#, fuzzy msgid "Camera left\\Turns the camera left" -msgstr "Kamera näher\\Bewegung der Kamera vorwärts" +msgstr "Kamera links\\Schwenkt die Kamera nach links" -#, fuzzy msgid "Camera right\\Turns the camera right" -msgstr "Drehung nach rechts\\Steuer rechts" +msgstr "Kamera rechts\\Schwenkt die Kamera nach rechts" -#, fuzzy msgid "Camera up\\Turns the camera up" -msgstr "Kamera (\\key camera;)" +msgstr "Kamera auf\\Bewegt die Kamera aufwärts" msgid "Can not produce not researched object" msgstr "Das erforschte Objekt kann nicht produziert werden" @@ -349,13 +351,13 @@ msgid "Cancel\\Cancel all changes" msgstr "Abbrechen\\Editor schließen" msgid "Challenges" -msgstr "Challenges" +msgstr "Herausforderungen" msgid "Challenges in the chapter:" -msgstr "Liste der Challenges des Kapitels:" +msgstr "Herausforderungen in diesem Kapitel:" msgid "Challenges\\Programming challenges" -msgstr "Challenges\\Herausforderungen" +msgstr "Herausforderungen\\Programmieraufgaben" msgid "Change camera\\Switches between onboard camera and following camera" msgstr "Andere Kamera\\Sichtpunkt einstellen" @@ -367,10 +369,10 @@ msgid "Chapters:" msgstr "Liste der Kapitel:" msgid "Cheat console\\Show cheat console" -msgstr "" +msgstr "Mogel-Konsole\\Zeige die Mogel-Konsole" msgid "Checkpoint" -msgstr "Checkpoint" +msgstr "Kontrollstelle" msgid "Class name expected" msgstr "" @@ -379,11 +381,10 @@ msgid "Climb\\Increases the power of the jet" msgstr "Steigen\\Leistung des Triebwerks steigern" msgid "Clone program" -msgstr "" +msgstr "Programm duplizieren" -#, fuzzy msgid "Clone selected program" -msgstr "Gewähltes Programm bearbeiten" +msgstr "Gewähltes Programm duplizieren" msgid "Close" msgstr "Schließen" @@ -395,10 +396,10 @@ msgid "Code battle" msgstr "" msgid "Code battles" -msgstr "" +msgstr "Programmierschlacht" msgid "Code battles\\Program your robot to be the best of them all!" -msgstr "" +msgstr "Programmierschlacht\\Schreibe das Programm für den besten Roboter!" msgid "Colobot rules!" msgstr "Colobot ist wunderbar!" @@ -407,7 +408,7 @@ msgid "Colobot: Gold Edition" msgstr "Colobot: Gold Edition" msgid "Command line" -msgstr "Befehleingabe" +msgstr "Befehlseingabe" msgid "Compilation ok (0 errors)" msgstr "Kompilieren OK (0 Fehler)" @@ -425,7 +426,7 @@ msgid "Controls\\Keyboard, joystick and mouse settings" msgstr "Steuerung\\Auswahl der Tasten" msgid "Converts ore to titanium" -msgstr "Konverter Erz-Titan" +msgstr "Konvertiert Erz in Titan" msgid "Copy" msgstr "Kopieren" @@ -436,12 +437,11 @@ msgstr "Kopieren (Ctrl+C)" msgid "Current mission saved" msgstr "Mission gespeichert" -#, fuzzy msgid "Custom levels:" -msgstr "Userlevels:" +msgstr "Benutzerdefinierte Level:" msgid "Custom levels\\Levels from mods created by the users" -msgstr "" +msgstr "Benutzerdefinierte Level\\Level die von anderen Spieler erstellt wurden" msgid "Customize your appearance" msgstr "Aussehen einstellen" @@ -452,9 +452,8 @@ msgstr "Ausschneiden (Ctrl+X)" msgid "Defense tower" msgstr "Geschützturm" -#, fuzzy msgid "Delete mark" -msgstr "Zerstören" +msgstr "Markierung entfernen" msgid "Delete player\\Deletes the player from the list" msgstr "Spieler löschen\\Löscht den Spieler aus der Liste" @@ -481,7 +480,7 @@ msgid "Device\\Driver and resolution settings" msgstr "Bildschirm\\Driver und Bildschirmauflösung" msgid "Dividing by zero" -msgstr "Teilung durch Null" +msgstr "Division durch Null" msgid "Do you really want to destroy the selected building?" msgstr "Wollen Sie das angewählte Gebäude wirklich zerstören ?" @@ -506,10 +505,10 @@ msgid "Dynamic lighting\\Mobile light sources" msgstr "Dynamische Beleuchtung\\Dynamische Beleuchtung" msgid "Dynamic shadows ++\\Dynamic shadows + self shadowing" -msgstr "" +msgstr "Dynamische Schatten ++\\Dynamische Schatten + Eigenschatten" msgid "Dynamic shadows\\Beautiful shadows!" -msgstr "" +msgstr "Dynamische Schatten\\Hübsche Schatten!" msgid "Edit the selected program" msgstr "Gewähltes Programm bearbeiten" @@ -551,7 +550,7 @@ msgid "Explosive" msgstr "Sprengstoff" msgid "Expression expected after =" -msgstr "" +msgstr "Nach = wird ein Ausdruck erwartet" msgid "Extend shield (\\key action;)" msgstr "Schutzschild ausfahren (\\key action;)" @@ -578,7 +577,7 @@ msgid "Fixed mine" msgstr "Landmine" msgid "Flat ground not large enough" -msgstr "Ebener Boden nicht groß genug" +msgstr "Ebene Fläche nicht groß genug" msgid "Fog\\Fog" msgstr "Nebel\\Nebelschwaden" @@ -591,7 +590,7 @@ msgid "Folder: %s" msgstr "Ordner: %s" msgid "Font size" -msgstr "Zeichengröße" +msgstr "Schriftgröße" msgid "Forward" msgstr "Nächste Seite" @@ -621,13 +620,13 @@ msgid "Found key D (site for derrick)" msgstr "Markierung für vergrabenen Schlüssel D" msgid "Free game" -msgstr "Freestyle" +msgstr "Freies Spiel" 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" +msgstr "Freies Spiel\\Freies Spielen ohne vorgegebenes Ziel" msgid "Full screen\\Full screen or window mode" msgstr "Vollbildschirm\\Vollbildschirm oder Fenster" @@ -651,10 +650,10 @@ msgid "Gantry crane" msgstr "Träger" msgid "Generating" -msgstr "" +msgstr "Generieren" msgid "Gold Edition development by:" -msgstr "Goldausgabe Entwicklung von:" +msgstr "Gold-Edition entwickelt von:" msgid "Goto: destination occupied" msgstr "Ziel ist schon besetzt" @@ -666,7 +665,7 @@ msgid "Grab or drop (\\key action;)" msgstr "Nehmen oder hinlegen (\\key action;)" msgid "Graphics\\Graphics settings" -msgstr "Grafik\\Grafische Einstellungen" +msgstr "Grafik\\Grafik-Einstellungen" msgid "Green" msgstr "Grün" @@ -687,7 +686,7 @@ msgid "Help about selected object" msgstr "Anweisungen über das ausgewählte Objekt" msgid "Help balloons\\Explain the function of the buttons" -msgstr "Hilfsblasen\\Hilfsblasen" +msgstr "Hilfeblasen\\Hilfeblasen" msgid "Highest\\Highest graphic quality (lowest frame rate)" msgstr "Max.\\Beste Qualität (niedriges Framerate)" @@ -722,9 +721,8 @@ msgstr "Roboter ungeeignet" msgid "Inappropriate cell type" msgstr "Falscher Batterietyp" -#, fuzzy msgid "Inappropriate object" -msgstr "Roboter ungeeignet" +msgstr "Objekt ungeeignet" msgid "Incorrect index type" msgstr "Falscher Typ für einen Index" @@ -763,10 +761,10 @@ msgid "Instructions\\Shows the instructions for the current mission" msgstr "Anweisungen\\Anweisungen für die Mission oder Übung" msgid "Internal error - tell the developers" -msgstr "Interner Fehler - Benachrichtige die Entwickler" +msgstr "Interner Fehler - Benachrichtige bitte die Entwickler" msgid "Invert\\Invert values on this axis" -msgstr "" +msgstr "Invertieren\\Die Werte dieser Achse invertieren" msgid "Jet temperature" msgstr "Triebwerktemperatur" @@ -826,39 +824,37 @@ msgid "Load\\Loads the selected mission" msgstr "Laden\\Öffnet eine gespeicherte Mission" msgid "Loading basic level settings" -msgstr "" +msgstr "Lade Level-Grundeinstellungen" -#, fuzzy msgid "Loading finished!" -msgstr "Programm beendet" +msgstr "Laden beendet!" msgid "Loading music" -msgstr "" +msgstr "Lade Musik" -#, fuzzy msgid "Loading objects" -msgstr "Liste der Objekte" +msgstr "Lade Objekte" msgid "Loading terrain" -msgstr "" +msgstr "Lade Gelände" msgid "Lowest\\Minimum graphic quality (highest frame rate)" msgstr "Min.\\Minimale Qualität (großes Framerate)" msgid "Lunar Roving Vehicle" -msgstr "Lunar Roving Vehicle" +msgstr "Mondlandefahrzeug" msgid "MSAA\\Multisample anti-aliasing" -msgstr "" +msgstr "MSAA\\Multisample anti-aliasing" msgid "Maximize" msgstr "Großes Fenster" msgid "Minimize" -msgstr "Reduzieren" +msgstr "Verkleinern" msgid "Mipmap level\\Mipmap level" -msgstr "" +msgstr "Mipmap-Level\\Mipmap-Level" msgid "Mission name" msgstr "Name der Mission" @@ -878,13 +874,11 @@ msgstr "Umkehr X\\Umkehr der Kameradrehung X-Achse" msgid "Mouse inversion Y\\Inversion of the scrolling direction on the Y axis" msgstr "Umkehr Y\\Umkehr der Kameradrehung Y-Achse" -#, fuzzy msgid "Move selected program down" -msgstr "Gewähltes Programm bearbeiten" +msgstr "Gewähltes Programm nach unten" -#, fuzzy msgid "Move selected program up" -msgstr "Gewähltes Programm bearbeiten" +msgstr "Gewähltes Programm nach oben" msgid "Mute\\No sound" msgstr "Kein Ton\\Keine Geräusche und Geräuschkulisse" @@ -914,7 +908,7 @@ msgid "Next object\\Selects the next object" msgstr "Nächstes auswählen\\Nächstes Objekt auswählen" msgid "No" -msgstr "" +msgstr "Nein" msgid "No energy in the subsoil" msgstr "Kein unterirdisches Energievorkommen" @@ -926,10 +920,10 @@ msgid "No function running" msgstr "Keine Funktion wird ausgeführt" msgid "No function with this name accepts this kind of parameter" -msgstr "Keine Funktion mit diesem Namen verträgt Parameter diesen Typs" +msgstr "Keine Funktion mit diesem Namen akzeptiert Parameter diesen Typs" msgid "No function with this name accepts this number of parameters" -msgstr "Keine Funktion mit diesem Namen verträgt diese Anzahl Parameter" +msgstr "Keine Funktion mit diesem Namen akzeptiert diese Anzahl Parameter" msgid "No information exchange post within range" msgstr "Kein Infoserver in Reichweite" @@ -959,7 +953,7 @@ msgid "No uranium to transform" msgstr "Kein konvertierbares Platin" msgid "No userlevels installed!" -msgstr "" +msgstr "Keine benutzerdefinierten Level vorhanden" msgid "Non-void function needs \"return;\"" msgstr "" @@ -1040,7 +1034,7 @@ msgid "Opening bracket missing" msgstr "Es fehlt eine offene Klammer \"(\"" msgid "Operation impossible with value \"nan\"" -msgstr "Operation mit dem Wert \"nan\"" +msgstr "Operation mit dem Wert \"nan\" nicht möglich" msgid "Options" msgstr "Einstellungen" @@ -1067,16 +1061,18 @@ msgid "Paste (Ctrl+V)" msgstr "Einfügen (Ctrl+V)" msgid "Pause blur\\Blur the background on the pause screen" -msgstr "" +msgstr "Pausen-Unschärfe\\Während der Pause den Hintergrund unscharf zeichnen" msgid "Pause in background\\Pause the game when the window is unfocused" msgstr "" +"Pausieren im Hintergrund\\Spiel anhalten,enn das Spielfenster im Hintergrund " +"ist" msgid "Pause/continue" msgstr "Pause/Weitermachen" msgid "Pause\\Pause the game without opening menu" -msgstr "" +msgstr "Pause\\Spiel pausieren, ohne das Menü zu öffnen" msgid "Phazer shooter" msgstr "Phazershooter" @@ -1121,10 +1117,10 @@ msgid "Player" msgstr "Spieler" msgid "Player name" -msgstr "Name " +msgstr "Spielername " msgid "Player's name" -msgstr "Name " +msgstr "Name des Spielers" msgid "Power cell" msgstr "Elektrolytische Batterie" @@ -1145,7 +1141,7 @@ msgid "Press \\key help; to read instructions on your SatCom" msgstr "Beziehen Sie sich auf Ihren SatCom, indem Sie auf \\key help; drücken" msgid "Previous" -msgstr "Vorherg" +msgstr "Vorherg." msgid "Previous object\\Selects the previous object" msgstr "Vorherg. Auswahl\\Das vorhergehende Objekt auswählen" @@ -1160,11 +1156,10 @@ msgid "Private\\Private folder" msgstr "Privat\\Privater Ordner" msgid "Processing level file" -msgstr "" +msgstr "Verarbeite Level-Datei" -#, fuzzy msgid "Program cloned" -msgstr "Programm beendet" +msgstr "Programm dupliziert" msgid "Program editor" msgstr "Programmeditor" @@ -1200,7 +1195,7 @@ msgid "Quake at explosions\\The screen shakes at explosions" msgstr "Beben bei Explosionen\\Die Kamera bebt bei Explosionen" msgid "Quit\\Quit Colobot: Gold Edition" -msgstr "" +msgstr "Beenden\\Colobot: Gold Edition schließen" msgid "Quit\\Quit the current mission or exercise" msgstr "Mission verlassen\\Eine Mission oder Übung verlassen" @@ -1235,11 +1230,9 @@ msgstr "Überreste einer Apollo-Mission" msgid "Remove a flag" msgstr "Sammelt die Fahne ein" -#, fuzzy msgid "Remove selected program" -msgstr "Gewähltes Programm bearbeiten" +msgstr "Gewähltes Programm entfernen" -#, fuzzy msgid "Render distance\\Maximum visibility" msgstr "Sichtweite\\Maximale Sichtweite" @@ -1255,9 +1248,8 @@ msgstr "Forschungsprogramm schon ausgeführt" msgid "Research program completed" msgstr "Forschungsprogramm abgeschlossen" -#, fuzzy msgid "Reserved keyword of CBOT language" -msgstr "Dieses Wort ist reserviert" +msgstr "Reserviertes Schlüsselwort in der CBOT Sprache" msgid "Resolution" msgstr "Auflösung" @@ -1266,16 +1258,16 @@ msgid "Resolution:" msgstr "Auflösung:" msgid "Resources" -msgstr "" +msgstr "Ressourcen" msgid "Restart\\Restart the mission from the beginning" msgstr "Neu anfangen\\Die Mission von vorne anfangen" msgid "Restoring CBot execution state" -msgstr "" +msgstr "CBOT Ausführungsstatus wiederherstellen" msgid "Restoring saved objects" -msgstr "" +msgstr "Gespeicherte Objekte wiederherstellen" msgid "Results" msgstr "" @@ -1347,10 +1339,10 @@ msgid "Semicolon terminator missing" msgstr "Es fehlt ein Strichpunkt \";\" am Ende der Anweisung" msgid "Shadow resolution\\Higher means better range and quality, but slower" -msgstr "" +msgstr "Schatten-Auflösung\\Höher heißt bessere Qualität, aber langsamer" msgid "Shield level" -msgstr "Schäden" +msgstr "Schildstärke" msgid "Shield radius" msgstr "Reichweite Schutzschild" @@ -1376,9 +1368,8 @@ msgstr "Zeigt die Lösung" msgid "Sign \" : \" missing" msgstr "Es fehlt ein Doppelpunkt \" : \"" -#, fuzzy msgid "Simple shadows\\Shadows spots on the ground" -msgstr "Schatten\\Schlagschatten auf dem Boden" +msgstr "Einfacher Schatten\\Schlagschatten auf dem Boden" msgid "Size 1" msgstr "Größe 1" @@ -1411,11 +1402,10 @@ msgid "Spaceship" msgstr "Raumschiff" msgid "Spaceship ruin" -msgstr "Raumschiffruine" +msgstr "Raumschiffswrack" -#, fuzzy msgid "Speed 0.5x\\Half speed" -msgstr "Geschwindigkeit 1.0x\\Normale Spielgeschwindigkeit" +msgstr "Geschwindigkeit 0.5x\\Halbe Spielgeschwindigkeit" msgid "Speed 1.0x\\Normal speed" msgstr "Geschwindigkeit 1.0x\\Normale Spielgeschwindigkeit" @@ -1426,17 +1416,14 @@ msgstr "Geschwindigkeit 1.5x\\Spielgeschwindigkeit anderthalb Mal schneller" msgid "Speed 2.0x\\Double speed" msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell" -#, fuzzy msgid "Speed 3.0x\\Triple speed" -msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell" +msgstr "Geschwindigkeit 3.0x\\Dreifache Spielgeschwindigkeit" -#, fuzzy msgid "Speed 4.0x\\Quadruple speed" -msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell" +msgstr "Geschwindigkeit 4.0x\\Vierfache Spielgeschwindigkeit" -#, fuzzy msgid "Speed 6.0x\\Sextuple speed" -msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell" +msgstr "Geschwindigkeit 6.0x\\Sechsfache Spielgeschwindigkeit" msgid "Spider" msgstr "Spinne" @@ -1459,12 +1446,11 @@ msgstr "Standard\\Standardfarben einsetzen" msgid "Start" msgstr "Startfläche" -#, fuzzy msgid "Starting..." -msgstr "Startfläche" +msgstr "Starte..." msgid "Still working ..." -msgstr "Prozess im Gang ..." +msgstr "Verarbeitung ..." msgid "String missing" msgstr "Hier wird eine Zeichenkette erwartet" @@ -1500,13 +1486,13 @@ msgid "Target bot" msgstr "Mobile Zielscheibe" msgid "Terrain relief" -msgstr "" +msgstr "Geländestruktur" msgid "Texture filtering\\Texture filtering" -msgstr "" +msgstr "Texturfilterung\\Texturfilterung" msgid "Textures" -msgstr "" +msgstr "Texturen" msgid "The battle has ended" msgstr "" @@ -1530,7 +1516,7 @@ msgid "This class does not exist" msgstr "Diese Klasse existiert nicht" msgid "This is example code that cannot be run directly" -msgstr "" +msgstr "Das ist ein Beispiel Programm, das nicht direkt ausgeführt werden kann" msgid "This is not a member of this class" msgstr "Dieses Element gibt es nicht in dieser Klasse" @@ -1540,6 +1526,8 @@ msgstr "Dieses Label existiert nicht" msgid "This menu is for userlevels from mods, but you didn't install any" msgstr "" +"Dieses Menü ist für nachinstallierte Benutzer-Level, aber Du hast keine " +"installiert" msgid "This object is currently busy" msgstr "" @@ -1551,7 +1539,7 @@ msgid "This parameter needs a default value" msgstr "" msgid "This program is read-only, clone it to edit" -msgstr "" +msgstr "Dieses Programm ist schreibgeschützt. Dupliziere es zum Bearbeiten" msgid "Thump (\\key action;)" msgstr "Stampfen (\\key action;)" @@ -1629,10 +1617,10 @@ msgid "Type declaration missing" msgstr "Hier muss ein Variablentyp stehen" msgid "Unable to control enemy objects" -msgstr "" +msgstr "Feindliches Objekt kann nicht gesteuert werden" msgid "Undo (Ctrl+Z)" -msgstr "Widerrufen (Ctrl+Z)" +msgstr "Rückgängig (Ctrl+Z)" msgid "Unit" msgstr "Einheit" @@ -1731,7 +1719,7 @@ msgid "Yellow flag" msgstr "Gelbe Fahne" msgid "Yes" -msgstr "" +msgstr "Ja" msgid "You can fly with the keys (\\key gup;) and (\\key gdown;)" msgstr "Sie können jetzt mit den Tasten \\key gup; und \\key gdown; fliegen" @@ -1742,27 +1730,35 @@ 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 +#, c-format msgid "You cannot use \"%s\" in this exercise (used: %d)" -msgstr "In dieser Übung verboten" +msgstr "\"%s\" kann in dieser Übung nicht verwendet werden (benutzt: %d)" msgid "You found a usable object" msgstr "Sie haben ein brauchbares Objekt gefunden" -#, fuzzy, c-format +#, c-format msgid "You have to use \"%1$s\" at least once in this exercise (used: %2$d)" msgid_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" +msgstr[0] "" +"In dieser Übung \"%1$s\" muß mindestens einmal verwendet werden (benutzt: %" +"2$d)" +msgstr[1] "" +"In dieser Übung muß \"%1$s\" mindestes %3$d Mal verwendet werden (benutzt: %" +"2$d)" -#, fuzzy, c-format +#, c-format msgid "You have to use \"%1$s\" at most once in this exercise (used: %2$d)" msgid_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" +msgstr[0] "" +"In dieser Übung darf \"%1$s\" höchstens einmal verwendet werden (benutzt: %" +"2$d)" +msgstr[1] "" +"In dieser Übung darf \"%1$s\" höchstens %3$d Mal verwendet werden (benutzt: %" +"2$d)" msgid "You must get on the spaceship to take off" -msgstr "Gehen Sie an Bord, bevor Sie abheben" +msgstr "Begib Dich an Bord, bevor Du abhebst" msgid "Zoom mini-map" msgstr "Zoom Minikarte" @@ -1813,7 +1809,7 @@ msgid "\\Red flags" msgstr "\\Rote Fahne" msgid "\\Return to Colobot: Gold Edition" -msgstr "" +msgstr "\\Zurück zu Colobot: Gold-Edition" msgid "\\SatCom on standby" msgstr "\\SatCom in Standby" From 11d950221b5868011644c256422f901ddcfb2bd8 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 22 May 2017 10:10:35 +0100 Subject: [PATCH 74/93] Fix all compiler warnings and enable -Werror (#955) This removes all compilation warnings on: * g++ 4.7.4, 4.8.5, 4.9.4, 5.4.1, 6.3.0, 7.0.1-svn246759 * clang++ 3.9.1, 4.0.0, 5.0.0-svn303007 --- CMakeLists.txt | 4 ++-- src/CBot/CBotClass.cpp | 3 --- src/CBot/CBotDefParam.cpp | 1 - src/CBot/CBotInstr/CBotExprVar.h | 2 ++ src/CBot/CBotInstr/CBotFunction.h | 4 ++++ src/CBot/CBotInstr/CBotInstr.cpp | 1 - src/CBot/CBotInstr/CBotLeftExpr.h | 4 ++++ src/CBot/CBotProgram.cpp | 2 +- src/CBot/CBotStack.cpp | 8 +++----- src/CBot/CBotToken.cpp | 3 --- src/CBot/CBotVar/CBotVarString.h | 4 ++-- src/CBot/stdlib/StringFunctions.cpp | 10 ++++++++-- src/app/app.h | 2 ++ src/app/input.h | 2 ++ src/app/pathman.h | 2 ++ src/app/signal_handlers.cpp | 2 +- src/common/config_file.h | 2 ++ src/common/logger.h | 2 ++ src/common/settings.h | 2 ++ src/graphics/engine/engine.h | 2 ++ src/level/robotmain.h | 2 ++ src/object/object_manager.h | 2 ++ src/script/scriptfunc.cpp | 8 ++++---- 23 files changed, 49 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc287243..8f2ca843 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,7 +132,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") message(STATUS "Detected GCC version 4.7+") - set(NORMAL_CXX_FLAGS "-std=gnu++11 -Wall -Wold-style-cast -pedantic-errors") + set(NORMAL_CXX_FLAGS "-std=gnu++11 -Wall -Werror -Wold-style-cast -pedantic-errors") set(RELEASE_CXX_FLAGS "-O2") set(DEBUG_CXX_FLAGS "-g -O0") set(TEST_CXX_FLAGS "-pthread") @@ -144,7 +144,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") message(STATUS "Detected Clang version 3.1+") - set(NORMAL_CXX_FLAGS "-std=c++11 -Wall -Wold-style-cast -pedantic-errors") + set(NORMAL_CXX_FLAGS "-std=c++11 -Wall -Werror -Wold-style-cast -pedantic-errors") set(RELEASE_CXX_FLAGS "-O2") set(DEBUG_CXX_FLAGS "-g -O0") set(TEST_CXX_FLAGS "-pthread") diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index d787eb73..ef220943 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -93,8 +93,6 @@ void CBotClass::ClearPublic() //////////////////////////////////////////////////////////////////////////////// void CBotClass::Purge() { - assert ( this != nullptr ); - delete m_pVar; m_pVar = nullptr; m_externalMethods->Clear(); @@ -202,7 +200,6 @@ std::string CBotClass::GetName() //////////////////////////////////////////////////////////////////////////////// CBotClass* CBotClass::GetParent() { - assert ( this != nullptr ); return m_parent; } diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp index b3a11a60..074f025d 100644 --- a/src/CBot/CBotDefParam.cpp +++ b/src/CBot/CBotDefParam.cpp @@ -132,7 +132,6 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) { int i = 0; - assert(this != nullptr); CBotDefParam* p = this; bool useDefault = false; diff --git a/src/CBot/CBotInstr/CBotExprVar.h b/src/CBot/CBotInstr/CBotExprVar.h index 2f2e69ab..d9b857cb 100644 --- a/src/CBot/CBotInstr/CBotExprVar.h +++ b/src/CBot/CBotInstr/CBotExprVar.h @@ -80,6 +80,8 @@ public: */ bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep); + using CBotInstr::ExecuteVar; + /*! * \brief RestoreStateVar Fetch variable at runtime. * \param pj diff --git a/src/CBot/CBotInstr/CBotFunction.h b/src/CBot/CBotInstr/CBotFunction.h index a23e2fd5..1f25474f 100644 --- a/src/CBot/CBotInstr/CBotFunction.h +++ b/src/CBot/CBotInstr/CBotFunction.h @@ -86,6 +86,8 @@ public: CBotStack* &pj, CBotVar* pInstance = nullptr); + using CBotInstr::Execute; + /*! * \brief RestoreState * \param ppVars @@ -96,6 +98,8 @@ public: CBotStack* &pj, CBotVar* pInstance = nullptr); + using CBotInstr::RestoreState; + /*! * \brief Compile a function call * diff --git a/src/CBot/CBotInstr/CBotInstr.cpp b/src/CBot/CBotInstr/CBotInstr.cpp index 1d30f673..69bb9025 100644 --- a/src/CBot/CBotInstr/CBotInstr.cpp +++ b/src/CBot/CBotInstr/CBotInstr.cpp @@ -361,7 +361,6 @@ CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypRes bool CBotInstr::HasReturn() { - assert(this != nullptr); if (m_next != nullptr) return m_next->HasReturn(); return false; // end of the list } diff --git a/src/CBot/CBotInstr/CBotLeftExpr.h b/src/CBot/CBotInstr/CBotLeftExpr.h index 7acea068..4cffe46e 100644 --- a/src/CBot/CBotInstr/CBotLeftExpr.h +++ b/src/CBot/CBotInstr/CBotLeftExpr.h @@ -61,6 +61,8 @@ public: */ bool Execute(CBotStack* &pStack, CBotStack* array); + using CBotInstr::Execute; + /*! * \brief ExecuteVar Fetch a variable during compilation. * \param pVar @@ -69,6 +71,8 @@ public: */ bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) override; + using CBotInstr::ExecuteVar; + /*! * \brief ExecuteVar Fetch the variable at runtume. * \param pVar diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index 32813de1..a3a216a2 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -302,7 +302,7 @@ CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser ) bool rSizeOf( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) { - if ( pVar == nullptr ) return CBotErrLowParam; + if ( pVar == nullptr ) { ex = CBotErrLowParam; return true; } int i = 0; pVar = pVar->GetItemList(); diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index 70ec5631..57aa4290 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -82,8 +82,6 @@ CBotStack* CBotStack::AllocateStack() //////////////////////////////////////////////////////////////////////////////// void CBotStack::Delete() { - assert ( this != nullptr ); - if (m_next != nullptr) m_next->Delete(); if (m_next2 != nullptr) m_next2->Delete(); @@ -270,7 +268,7 @@ bool CBotStack::IfStep() bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name) { if ( m_error>=0 ) return false; // normal output - if ( m_error==-3 ) return false; // normal output (return current) + if ( m_error==CBotError(-3) ) return false; // normal output (return current) if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name)) return false; // it's not for me @@ -283,7 +281,7 @@ bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name) //////////////////////////////////////////////////////////////////////////////// bool CBotStack::IfContinue(int state, const std::string& name) { - if ( m_error != -2 ) return false; + if ( m_error != CBotError(-2) ) return false; if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name)) return false; // it's not for me @@ -311,7 +309,7 @@ void CBotStack::SetBreak(int val, const std::string& name) //////////////////////////////////////////////////////////////////////////////// bool CBotStack::GetRetVar(bool bRet) { - if (m_error == -3) + if (m_error == CBotError(-3)) { if ( m_var ) delete m_var; m_var = m_retvar; diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp index e10901eb..d9e33ffd 100644 --- a/src/CBot/CBotToken.cpp +++ b/src/CBot/CBotToken.cpp @@ -199,7 +199,6 @@ const CBotToken& CBotToken::operator=(const CBotToken& src) //////////////////////////////////////////////////////////////////////////////// int CBotToken::GetType() { - assert(this != nullptr); if (m_type == TokenTypKeyWord) return m_keywordId; return m_type; } @@ -225,14 +224,12 @@ void CBotToken::SetString(const std::string& name) //////////////////////////////////////////////////////////////////////////////// int CBotToken::GetStart() { - assert(this != nullptr); return m_start; } //////////////////////////////////////////////////////////////////////////////// int CBotToken::GetEnd() { - assert(this != nullptr); return m_end; } diff --git a/src/CBot/CBotVar/CBotVarString.h b/src/CBot/CBotVar/CBotVarString.h index 162264d2..28d3018d 100644 --- a/src/CBot/CBotVar/CBotVarString.h +++ b/src/CBot/CBotVar/CBotVarString.h @@ -48,12 +48,12 @@ public: SetValString(ToString(val)); } - int GetValInt() + int GetValInt() override { return FromString(GetValString()); } - float GetValFloat() + float GetValFloat() override { return FromString(GetValString()); } diff --git a/src/CBot/stdlib/StringFunctions.cpp b/src/CBot/stdlib/StringFunctions.cpp index c50c39d4..77a359cb 100644 --- a/src/CBot/stdlib/StringFunctions.cpp +++ b/src/CBot/stdlib/StringFunctions.cpp @@ -225,8 +225,14 @@ bool rStrFind( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) // puts the result on the stack std::size_t res = s.find(s2); - pResult->SetValInt( res != std::string::npos ? res : -1 ); - if ( res < 0 ) pResult->SetInit( CBotVar::InitType::IS_NAN ); + if (res != std::string::npos) + { + pResult->SetValInt(res); + } + else + { + pResult->SetInit(CBotVar::InitType::IS_NAN); + } return true; } diff --git a/src/app/app.h b/src/app/app.h index b6702907..1b3b3a21 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -404,3 +404,5 @@ protected: //! Static buffer for putenv locale static char m_languageLocale[50]; }; + +template<> CApplication* CSingleton::m_instance; diff --git a/src/app/input.h b/src/app/input.h index 15cdc98d..2b8617eb 100644 --- a/src/app/input.h +++ b/src/app/input.h @@ -161,3 +161,5 @@ private: std::map m_keyTable; }; + +template<> CInput* CSingleton::m_instance; diff --git a/src/app/pathman.h b/src/app/pathman.h index 059c81fe..87fa4493 100644 --- a/src/app/pathman.h +++ b/src/app/pathman.h @@ -67,3 +67,5 @@ private: //! Save path std::string m_savePath; }; + +template<> CPathManager* CSingleton::m_instance; diff --git a/src/app/signal_handlers.cpp b/src/app/signal_handlers.cpp index 223d7db8..b08a0a22 100644 --- a/src/app/signal_handlers.cpp +++ b/src/app/signal_handlers.cpp @@ -46,7 +46,7 @@ void CSignalHandlers::Init(CSystemUtils* systemUtils) void CSignalHandlers::SignalHandler(int sig) { - std::string signalStr = StrUtils::ToString(signal); + std::string signalStr = StrUtils::ToString(sig); switch(sig) { case SIGSEGV: signalStr = "SIGSEGV, segmentation fault"; break; diff --git a/src/common/config_file.h b/src/common/config_file.h index 0ed8e19f..9acc5aee 100644 --- a/src/common/config_file.h +++ b/src/common/config_file.h @@ -112,3 +112,5 @@ inline CConfigFile & GetConfigFile() { return CConfigFile::GetInstance(); } + +template<> CConfigFile* CSingleton::m_instance; diff --git a/src/common/logger.h b/src/common/logger.h index e0a935d4..e49fbd33 100644 --- a/src/common/logger.h +++ b/src/common/logger.h @@ -136,3 +136,5 @@ inline CLogger* GetLogger() { return CLogger::GetInstancePointer(); } + +template<> CLogger* CSingleton::m_instance; diff --git a/src/common/settings.h b/src/common/settings.h index 4e9b7620..cb236601 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -105,3 +105,5 @@ protected: Language m_language; }; + +template<> CSettings* CSingleton::m_instance; diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 834de1e3..687bbafb 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -1490,3 +1490,5 @@ protected: } // namespace Gfx + +template<> Gfx::CEngine* CSingleton::m_instance; diff --git a/src/level/robotmain.h b/src/level/robotmain.h index b1e69c97..a683e206 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -715,3 +715,5 @@ protected: //! Index of currently selected element in command history int m_commandHistoryIndex; }; + +template<> CRobotMain* CSingleton::m_instance; diff --git a/src/object/object_manager.h b/src/object/object_manager.h index 73ae0015..2a02d24e 100644 --- a/src/object/object_manager.h +++ b/src/object/object_manager.h @@ -311,3 +311,5 @@ private: int m_activeObjectIterators; bool m_shouldCleanRemovedObjects; }; + +template<> CObjectManager* CSingleton::m_instance; diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index ee9bc305..6a264b02 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -413,7 +413,7 @@ bool CScriptFunctions::rDestroy(CBotVar* thisclass, CBotVar* var, CBotVar* resul else err = ERR_WRONG_OBJ; - result->SetValInt(err); // indicates the error or ok + result->SetValInt(err); // indicates the error or ok if ( err != ERR_OK ) { if ( script->m_errMode == ERM_STOP ) @@ -506,7 +506,7 @@ bool CScriptFunctions::rFactory(CBotVar* thisclass, CBotVar* var, CBotVar* resul else err = ERR_WRONG_OBJ; - result->SetValInt(err); // indicates the error or ok + result->SetValInt(err); // indicates the error or ok if ( err != ERR_OK ) { if ( script->m_errMode == ERM_STOP ) @@ -581,7 +581,7 @@ bool CScriptFunctions::rResearch(CBotVar* thisclass, CBotVar* var, CBotVar* resu else err = ERR_WRONG_OBJ; - result->SetValInt(err); // indicates the error or ok + result->SetValInt(err); // indicates the error or ok if ( err != ERR_OK ) { if( script->m_errMode == ERM_STOP ) @@ -621,7 +621,7 @@ bool CScriptFunctions::rTakeOff(CBotVar* thisclass, CBotVar* var, CBotVar* resul else err = ERR_WRONG_OBJ; - result->SetValInt(err); // indicates the error or ok + result->SetValInt(err); // indicates the error or ok if ( err != ERR_OK ) { if ( script->m_errMode == ERM_STOP ) From 108551c199bb22784073fc74f53efc863689f6fc Mon Sep 17 00:00:00 2001 From: krzys-h Date: Mon, 22 May 2017 11:11:42 +0200 Subject: [PATCH 75/93] Fix @tomangelo2's code style see 47a8f70f0fbf4d4f984da3a595851b89c732ff54 --- src/script/scriptfunc.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index 6a264b02..c0b639de 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -2382,11 +2382,11 @@ bool CScriptFunctions::rFire(CBotVar* var, CBotVar* result, int& exception, void if ( err != ERR_OK ) { script->m_taskExecutor->StopForegroundTask(); - if ( script->m_errMode == ERM_STOP ) - { - exception = err; - return false; - } + if ( script->m_errMode == ERM_STOP ) + { + exception = err; + return false; + } return true; } } From 417301ff061e4ed6b74e4c360f6878e6d0d5cb39 Mon Sep 17 00:00:00 2001 From: MatiRg Date: Tue, 23 May 2017 18:57:41 +0200 Subject: [PATCH 76/93] Fix rendering glasses in FPP camera, closes #775 (#959) --- src/object/motion/motionhuman.cpp | 21 +++++++++++++++++---- src/object/motion/motionhuman.h | 1 + 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/object/motion/motionhuman.cpp b/src/object/motion/motionhuman.cpp index cd70d450..99469a90 100644 --- a/src/object/motion/motionhuman.cpp +++ b/src/object/motion/motionhuman.cpp @@ -71,6 +71,7 @@ CMotionHuman::CMotionHuman(COldObject* object) m_time = 0.0f; m_tired = 0.0f; m_bDisplayPerso = false; + m_glassesRank = -1; } // Object's constructor. @@ -198,12 +199,12 @@ void CMotionHuman::Create(Math::Vector pos, float angle, ObjectType type, glasses = m_main->GetGamerGlasses(); if ( glasses != 0 && type == OBJECT_HUMAN ) { - rank = m_engine->CreateObject(); - m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); - m_object->SetObjectRank(15, rank); + m_glassesRank = m_engine->CreateObject(); + m_engine->SetObjectType(m_glassesRank, Gfx::ENG_OBJTYPE_DESCENDANT); + m_object->SetObjectRank(15, m_glassesRank); m_object->SetObjectParent(15, 1); sprintf(filename, "human2g%d.mod", glasses); - modelManager->AddModelReference(filename, false, rank); + modelManager->AddModelReference(filename, false, m_glassesRank); } // Creates the right arm. @@ -652,6 +653,18 @@ bool CMotionHuman::EventFrame(const Event &event) m_object->SetCirVibration(Math::Vector(0.0f, m_main->GetPersoAngle()+0.2f, 0.0f)); } + if ( m_glassesRank != -1 ) + { + if ( m_camera->GetType() == Gfx::CAM_TYPE_ONBOARD ) + { + m_engine->SetObjectDrawWorld(m_glassesRank, false); + } + else + { + m_engine->SetObjectDrawWorld(m_glassesRank, true); + } + } + bSwim = m_physics->GetSwim(); rot = m_physics->GetCirMotionY(MO_MOTSPEED); diff --git a/src/object/motion/motionhuman.h b/src/object/motion/motionhuman.h index e0bb981c..9449ed2b 100644 --- a/src/object/motion/motionhuman.h +++ b/src/object/motion/motionhuman.h @@ -91,4 +91,5 @@ protected: float m_time; float m_tired; bool m_bDisplayPerso; + int m_glassesRank; }; From aa1a946336673f80224095512a6b71891e00c1e3 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 23 May 2017 19:02:17 +0200 Subject: [PATCH 77/93] Make deprecation warnings not an error, see #958 --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f2ca843..e3e28781 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,6 +133,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") message(STATUS "Detected GCC version 4.7+") set(NORMAL_CXX_FLAGS "-std=gnu++11 -Wall -Werror -Wold-style-cast -pedantic-errors") + set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -Wno-error=deprecated-declarations") # updated version of physfs is not available on some platforms so we keep using deprecated functions, see #958 set(RELEASE_CXX_FLAGS "-O2") set(DEBUG_CXX_FLAGS "-g -O0") set(TEST_CXX_FLAGS "-pthread") @@ -145,6 +146,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") message(STATUS "Detected Clang version 3.1+") set(NORMAL_CXX_FLAGS "-std=c++11 -Wall -Werror -Wold-style-cast -pedantic-errors") + set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -Wno-error=deprecated-declarations") # updated version of physfs is not available on some platforms so we keep using deprecated functions, see #958 set(RELEASE_CXX_FLAGS "-O2") set(DEBUG_CXX_FLAGS "-g -O0") set(TEST_CXX_FLAGS "-pthread") From 2d7911f1553a2511c144460e37a45447a32e69d3 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 23 May 2017 20:19:47 +0200 Subject: [PATCH 78/93] Fix delete() in CBot not destroying PowerCells properly --- src/graphics/engine/pyro.cpp | 3 +++ src/script/scriptfunc.cpp | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/graphics/engine/pyro.cpp b/src/graphics/engine/pyro.cpp index 6f3961af..5bc9f76d 100644 --- a/src/graphics/engine/pyro.cpp +++ b/src/graphics/engine/pyro.cpp @@ -2157,6 +2157,9 @@ bool CPyro::BurnIsKeepPart(int part) void CPyro::BurnTerminate() { + if (m_object == nullptr) + return; + if (m_type == PT_BURNO) // organic object is burning? { DeleteObject(true, true); // removes the insect diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index c0b639de..5fc97564 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -682,6 +682,16 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo } else { + if (obj->Implements(ObjectInterfaceType::Old)) + { + COldObject* oldobj = dynamic_cast(obj); + if (oldobj->GetPower() != nullptr) + CObjectManager::GetInstancePointer()->DeleteObject(oldobj->GetPower()); + if (oldobj->GetCargo() != nullptr) + CObjectManager::GetInstancePointer()->DeleteObject(oldobj->GetCargo()); + oldobj->SetPower(nullptr); + oldobj->SetCargo(nullptr); + } CObjectManager::GetInstancePointer()->DeleteObject(obj); } } From 904b7e580b596aaf0171ab9b7dcf8ccae48f4713 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 23 May 2017 20:20:46 +0200 Subject: [PATCH 79/93] Prevent giving scoreboard points to team 0 --- src/level/scoreboard.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/level/scoreboard.cpp b/src/level/scoreboard.cpp index dc86eeed..0f388c69 100644 --- a/src/level/scoreboard.cpp +++ b/src/level/scoreboard.cpp @@ -67,6 +67,7 @@ void CScoreboard::ProcessKill(CObject* target, CObject* killer) for (auto& rule : m_rulesKill) { if ((rule->team == killer->GetTeam() || rule->team == 0) && + killer->GetTeam() != 0 && rule->CheckForObject(target)) { AddPoints(killer->GetTeam(), rule->score); @@ -76,6 +77,7 @@ void CScoreboard::ProcessKill(CObject* target, CObject* killer) void CScoreboard::ProcessEndTake(int team) { + if (team == 0) return; m_finishCounter++; for (auto& rule : m_rulesEndTake) { From 648dfd75c43666c667662afe7cb412de1ae029f4 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 23 May 2017 20:31:55 +0200 Subject: [PATCH 80/93] Fix handling of particle 'father' objects when they are destroyed --- src/graphics/engine/particle.cpp | 20 ++++++++++++++++++++ src/graphics/engine/particle.h | 3 +++ src/object/old_object.cpp | 1 + 3 files changed, 24 insertions(+) diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp index e63a8c6a..f5c254e3 100644 --- a/src/graphics/engine/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -3740,4 +3740,24 @@ Color CParticle::GetFogColor(Math::Vector pos) return result; } +void CParticle::CutObjectLink(CObject* obj) +{ + for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++) + { + if (!m_particle[i].used) continue; + + if (m_particle[i].objLink == obj) + { + // If the object this particle's coordinates are linked to doesn't exist anymore, remove the particle + DeleteRank(i); + } + + if (m_particle[i].objFather == obj) + { + // If the object that spawned this partcle doesn't exist anymore, remove the link + m_particle[i].objFather = nullptr; + } + } +} + } // namespace Gfx diff --git a/src/graphics/engine/particle.h b/src/graphics/engine/particle.h index 03707a9c..08dfc432 100644 --- a/src/graphics/engine/particle.h +++ b/src/graphics/engine/particle.h @@ -291,6 +291,9 @@ public: //! Draws all the particles void DrawParticle(int sheet); + //! Indicates that the object binds to the particle no longer exists, without deleting it + void CutObjectLink(CObject* obj); + protected: //! Removes a particle of given rank void DeleteRank(int rank); diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index dbbb3890..9655ad7b 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -203,6 +203,7 @@ void COldObject::DeleteObject(bool bAll) if ( !bAll ) { m_engine->GetPyroManager()->CutObjectLink(this); + m_particle->CutObjectLink(this); if ( m_bSelect ) { From 004106eb19a835e5e5aeb88fb6c0f3f58265fad1 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 23 May 2017 20:47:03 +0200 Subject: [PATCH 81/93] Don't limit types of objects visible on minimap with fixed image --- src/ui/controls/map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/controls/map.cpp b/src/ui/controls/map.cpp index 9bc35b91..e1062096 100644 --- a/src/ui/controls/map.cpp +++ b/src/ui/controls/map.cpp @@ -1281,7 +1281,7 @@ void CMap::UpdateObject(CObject* pObj) if ( color == MAPCOLOR_NULL ) return; - if (!m_fixImage.empty() && !m_bDebug) // map with still image? + /*if (!m_fixImage.empty() && !m_bDebug) // map with still image? { if ( (type == OBJECT_TEEN28 || type == OBJECT_TEEN34 ) && @@ -1290,7 +1290,7 @@ void CMap::UpdateObject(CObject* pObj) if ( type != OBJECT_TEEN28 && type != OBJECT_TEEN34 && color != MAPCOLOR_MOVE ) return; - } + }*/ if ( pObj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(pObj)->GetSelect() ) { From 149d1f8156fce3579d278c0516ad1f75e0182679 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 23 May 2017 20:51:37 +0200 Subject: [PATCH 82/93] Fix aliens not appearing on the minimap, closes #901 --- src/ui/controls/map.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ui/controls/map.cpp b/src/ui/controls/map.cpp index e1062096..b22453c5 100644 --- a/src/ui/controls/map.cpp +++ b/src/ui/controls/map.cpp @@ -1164,12 +1164,20 @@ void CMap::UpdateObject(CObject* pObj) if ( !m_bEnable ) return; if ( m_totalFix >= m_totalMove ) return; // full table? + type = pObj->GetType(); if ( !pObj->GetDetectable() ) return; - if ( pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast(pObj)->GetSelectable() ) return; + if ( type != OBJECT_MOTHER && + type != OBJECT_ANT && + type != OBJECT_SPIDER && + type != OBJECT_BEE && + type != OBJECT_WORM && + type != OBJECT_MOBILEtg ) + { + if (pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast(pObj)->GetSelectable()) return; + } if ( pObj->GetProxyActivate() ) return; if (IsObjectBeingTransported(pObj)) return; - type = pObj->GetType(); pos = pObj->GetPosition(); dir = -(pObj->GetRotationY()+Math::PI/2.0f); From d8b0bd4df828d0ca7798602b3e3eef32b668766a Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 23 May 2017 22:02:00 +0200 Subject: [PATCH 83/93] Make TargetBots explode when they run into something --- src/physics/physics.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 6125a699..1e801d11 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -2688,18 +2688,19 @@ bool CPhysics::ExploOther(ObjectType iType, { JostleObject(pObj, 1.0f); // shakes the object - if (pObj->Implements(ObjectInterfaceType::Fragile)) + if (pObj->Implements(ObjectInterfaceType::Damageable)) { // TODO: CFragileObject::GetDestructionForce (I can't do this now because you can't inherit both in COldObject ~krzys_h) DamageType damageType = DamageType::Collision; - float destructionForce = 50.0f; // Titanium, PowerCell, NuclearCell, default + float destructionForce = pObj->Implements(ObjectInterfaceType::Fragile) ? 50.0f : -1.0f; // Titanium, PowerCell, NuclearCell, default if (pObj->GetType() == OBJECT_STONE ) { destructionForce = 25.0f; } // TitaniumOre if (pObj->GetType() == OBJECT_URANIUM ) { destructionForce = 25.0f; } // UraniumOre - if (pObj->GetType() == OBJECT_MOBILEtg) { destructionForce = 10.0f; damageType = DamageType::Explosive; } // TargetBot + if (pObj->GetType() == OBJECT_MOBILEtg) { destructionForce = 10.0f; damageType = DamageType::Explosive; } // TargetBot (something running into it) + if (iType == OBJECT_MOBILEtg) { destructionForce = 10.0f; damageType = DamageType::Explosive; } // TargetBot (it running into something) if (pObj->GetType() == OBJECT_TNT ) { destructionForce = 10.0f; damageType = DamageType::Explosive; } // TNT if (pObj->GetType() == OBJECT_BOMB ) { destructionForce = 0.0f; damageType = DamageType::Explosive; } // Mine - if ( force > destructionForce ) + if ( force > destructionForce && destructionForce >= 0.0f ) { // TODO: implement "killer"? dynamic_cast(pObj)->DamageObject(damageType); @@ -2778,7 +2779,8 @@ int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force) // TODO: CExplosiveObject? derrives from CFragileObject float destructionForce = -1.0f; // minimal force required to destroy an object using this explosive, default: not explosive if ( oType == OBJECT_TNT ) destructionForce = 10.0f; // TNT - if ( oType == OBJECT_MOBILEtg ) destructionForce = 10.0f; // TargetBot + if ( oType == OBJECT_MOBILEtg ) destructionForce = 10.0f; // TargetBot (something running into it) + if ( iType == OBJECT_MOBILEtg ) destructionForce = 10.0f; // TargetBot (it running into something) if ( oType == OBJECT_BOMB ) destructionForce = 0.0f; // Mine if ( force > destructionForce && destructionForce >= 0.0f ) From 5d4dfd8cb56066bd170e39adaff6e995a1646806 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 23 May 2017 22:25:01 +0200 Subject: [PATCH 84/93] Fix scoreboard points sometimes being added multiple times --- src/object/old_object.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index 9655ad7b..2178d326 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -530,6 +530,7 @@ void COldObject::DestroyObject(DestructionType type, CObject* killer) pyroType = Gfx::PT_WPCHECK; } assert(pyroType != Gfx::PT_NULL); + SetDying(DeathType::Exploding); m_engine->GetPyroManager()->Create(pyroType, this); if ( Implements(ObjectInterfaceType::Programmable) ) From 935b789d020b9f646a2d0a11b95b04dca72d97e9 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 24 May 2017 10:45:31 +0200 Subject: [PATCH 85/93] Fix alien animations after 5d4dfd8cb56066bd170e39adaff6e995a1646806 --- src/object/old_object.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index 2178d326..dbe92b32 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -530,7 +530,12 @@ void COldObject::DestroyObject(DestructionType type, CObject* killer) pyroType = Gfx::PT_WPCHECK; } assert(pyroType != Gfx::PT_NULL); - SetDying(DeathType::Exploding); + if (pyroType == Gfx::PT_FRAGT || + pyroType == Gfx::PT_FRAGO || + pyroType == Gfx::PT_FRAGW) + { + SetDying(DeathType::Exploding); + } m_engine->GetPyroManager()->Create(pyroType, this); if ( Implements(ObjectInterfaceType::Programmable) ) From f60108f367cd6f44b3565d23ac6aa7feaddf1400 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 24 May 2017 10:50:43 +0200 Subject: [PATCH 86/93] Prevent enforcement of ObligatoryToken for level controller scripts --- src/level/robotmain.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 4bcec60e..7f4181f1 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -3322,6 +3322,9 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) assert(m_controller->Implements(ObjectInterfaceType::Programmable)); assert(m_controller->Implements(ObjectInterfaceType::ProgramStorage)); + assert(m_controller->Implements(ObjectInterfaceType::Old)); + dynamic_cast(m_controller)->SetCheckToken(false); + if (line->GetParam("script")->IsDefined()) { CProgramStorageObject* programStorage = dynamic_cast(m_controller); From 08d87fa9757a05b66325b9ea77123d098143ddbd Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 24 May 2017 12:39:05 +0200 Subject: [PATCH 87/93] Make initial scoreboard values editable --- src/app/app.cpp | 5 ++-- src/app/app.h | 5 +++- src/level/robotmain.cpp | 59 ++++++++++++++++++++++++++++++++++------ src/level/robotmain.h | 1 + src/level/scoreboard.cpp | 5 ++++ src/level/scoreboard.h | 1 + src/ui/controls/edit.cpp | 31 +++++++++++++-------- 7 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index 806a17c7..f019ccc0 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -1854,9 +1854,10 @@ bool CApplication::GetSceneTestMode() return m_sceneTest; } -void CApplication::SetTextInput(bool textInputEnabled) +void CApplication::SetTextInput(bool textInputEnabled, int id) { - if (textInputEnabled) + m_textInputEnabled[id] = textInputEnabled; + if (std::any_of(m_textInputEnabled.begin(), m_textInputEnabled.end(), [](std::pair v) { return v.second; })) { SDL_StartTextInput(); } diff --git a/src/app/app.h b/src/app/app.h index 1b3b3a21..ac8769c7 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -35,6 +35,7 @@ #include #include +#include class CEventQueue; @@ -245,7 +246,7 @@ public: //! Enable/disable text input, this toggles the on-screen keyboard on some platforms /** This also allows for writing in CJK languages (not tested!), see https://wiki.libsdl.org/Tutorials/TextInput for detailed explanation */ - void SetTextInput(bool textInputEnabled); + void SetTextInput(bool textInputEnabled, int id); //! Moves (warps) the mouse cursor to the specified position (in interface coords) void MoveMouse(Math::Point pos); @@ -403,6 +404,8 @@ protected: //! Static buffer for putenv locale static char m_languageLocale[50]; + + std::map m_textInputEnabled; }; template<> CApplication* CSingleton::m_instance; diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 7f4181f1..30f55e3c 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -2563,6 +2563,7 @@ bool CRobotMain::EventFrame(const Event &event) if (!m_codeBattleStarted && m_userPause == nullptr) { m_codeBattleStarted = true; + ApplyCodeBattleInterface(); CreateCodeBattleInterface(); SetCodeBattleSpectatorMode(true); @@ -5793,7 +5794,7 @@ void CRobotMain::CreateCodeBattleInterface() int numTeams = m_scoreboard ? GetAllTeams().size() : 0; assert(numTeams < EVENT_SCOREBOARD_MAX-EVENT_SCOREBOARD+1); - float textHeight = m_engine->GetText()->GetAscent(Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL); + float textHeight = m_engine->GetText()->GetHeight(Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL); ddim.x = 100.0f/640.0f; ddim.y = 100.0f/480.0f + numTeams * textHeight; @@ -5825,18 +5826,59 @@ void CRobotMain::CreateCodeBattleInterface() pos.y += ddim.y; ddim.y = textHeight; - for (int i = 0; i < numTeams; i++) + int i = 0; + auto teams = GetAllTeams(); + for (auto it = teams.rbegin(); it != teams.rend(); ++it) { - Ui::CLabel* pl; - pl = pw->CreateLabel(pos, ddim, 0, static_cast(EVENT_SCOREBOARD+2*(numTeams-i-1)+0), "XXXXX"); + int team = *it; + Ui::CControl* pl; + ddim.x = 55.0f/640.0f; + pl = m_codeBattleStarted + ? static_cast(pw->CreateLabel(pos, ddim, 0, static_cast(EVENT_SCOREBOARD+2*(numTeams-i-1)+0), "XXXXX")) + : static_cast(pw->CreateEdit( pos, ddim, 0, static_cast(EVENT_SCOREBOARD+2*(numTeams-i-1)+0))); pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); - pl = pw->CreateLabel(pos, ddim, 0, static_cast(EVENT_SCOREBOARD+2*(numTeams-i-1)+1), "???"); + pl->SetFontSize(m_codeBattleStarted ? Gfx::FONT_SIZE_SMALL : Gfx::FONT_SIZE_SMALL*0.75f); + m_codeBattleStarted ? pl->SetName(GetTeamName(team)) : static_cast(pl)->SetText(GetTeamName(team)); + pos.x += 57.5f/640.0f; + ddim.x = 22.5f/640.0f; + pl = m_codeBattleStarted + ? static_cast(pw->CreateLabel(pos, ddim, 0, static_cast(EVENT_SCOREBOARD+2*(numTeams-i-1)+1), "???")) + : static_cast(pw->CreateEdit( pos, ddim, 0, static_cast(EVENT_SCOREBOARD+2*(numTeams-i-1)+1))); pl->SetTextAlign(Gfx::TEXT_ALIGN_RIGHT); + pl->SetFontSize(m_codeBattleStarted ? Gfx::FONT_SIZE_SMALL : Gfx::FONT_SIZE_SMALL*0.75f); + m_codeBattleStarted ? pl->SetName(StrUtils::ToString(m_scoreboard->GetScore(team))) : static_cast(pl)->SetText(StrUtils::ToString(m_scoreboard->GetScore(team))); + pos.x -= 57.5f/640.0f; pos.y += ddim.y; + i++; } } } +void CRobotMain::ApplyCodeBattleInterface() +{ + assert(GetMissionType() == MISSION_CODE_BATTLE); + if (!m_scoreboard) return; + + Ui::CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW6)); + assert(pw != nullptr); + + int i = 0; + for (int team : GetAllTeams()) + { + Ui::CEdit* pl; + + pl = static_cast(pw->SearchControl(static_cast(EVENT_SCOREBOARD+2*i+0))); + assert(pl != nullptr); + m_teamNames[team] = pl->GetText(pl->GetTextLength()); + + pl = static_cast(pw->SearchControl(static_cast(EVENT_SCOREBOARD+2*i+1))); + assert(pl != nullptr); + m_scoreboard->SetScore(team, StrUtils::FromString(pl->GetText(pl->GetTextLength()))); + + i++; + } +} + void CRobotMain::UpdateCodeBattleInterface() { assert(GetMissionType() == MISSION_CODE_BATTLE); @@ -5848,19 +5890,18 @@ void CRobotMain::UpdateCodeBattleInterface() int i = 0; for (int team : GetAllTeams()) { - Ui::CLabel* pl; + Ui::CControl* pl; - pl = static_cast(pw->SearchControl(static_cast(EVENT_SCOREBOARD+2*i+0))); + pl = pw->SearchControl(static_cast(EVENT_SCOREBOARD+2*i+0)); assert(pl != nullptr); pl->SetName(GetTeamName(team)); - pl = static_cast(pw->SearchControl(static_cast(EVENT_SCOREBOARD+2*i+1))); + pl = pw->SearchControl(static_cast(EVENT_SCOREBOARD+2*i+1)); assert(pl != nullptr); pl->SetName(StrUtils::ToString(m_scoreboard->GetScore(team))); i++; } - } void CRobotMain::DestroyCodeBattleInterface() diff --git a/src/level/robotmain.h b/src/level/robotmain.h index a683e206..d4e18525 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -518,6 +518,7 @@ protected: //@{ void CreateCodeBattleInterface(); void UpdateCodeBattleInterface(); + void ApplyCodeBattleInterface(); void DestroyCodeBattleInterface(); void SetCodeBattleSpectatorMode(bool mode); //@} diff --git a/src/level/scoreboard.cpp b/src/level/scoreboard.cpp index 0f388c69..7e4b5b04 100644 --- a/src/level/scoreboard.cpp +++ b/src/level/scoreboard.cpp @@ -106,3 +106,8 @@ int CScoreboard::GetScore(int team) { return m_score[team]; } + +void CScoreboard::SetScore(int team, int points) +{ + m_score[team] = points; +} diff --git a/src/level/scoreboard.h b/src/level/scoreboard.h index 6768a595..58a5acb5 100644 --- a/src/level/scoreboard.h +++ b/src/level/scoreboard.h @@ -115,6 +115,7 @@ public: void AddPoints(int team, int points); int GetScore(int team); + void SetScore(int team, int score); private: std::vector> m_rulesKill = {}; diff --git a/src/ui/controls/edit.cpp b/src/ui/controls/edit.cpp index af04d93d..1269284d 100644 --- a/src/ui/controls/edit.cpp +++ b/src/ui/controls/edit.cpp @@ -94,7 +94,7 @@ bool IsBreaker(char c) bool IsDelimiter(char c) { return IsSpace( c ) || IsBreaker( c ); -} +} //! Object's constructor. CEdit::CEdit() @@ -148,7 +148,7 @@ CEdit::~CEdit() if (m_bFocus) { - CApplication::GetInstancePointer()->SetTextInput(false); + CApplication::GetInstancePointer()->SetTextInput(false, EVENT_OBJECT_PEN3); } } @@ -520,13 +520,20 @@ bool CEdit::EventProcess(const Event &event) MouseClick(event.mousePos); if ( m_bEdit || m_bHilite ) m_bCapture = true; } - m_bFocus = true; - UpdateFocus(); + + if (!m_bFocus) + { + m_bFocus = true; + UpdateFocus(); + } } else { - m_bFocus = false; - UpdateFocus(); + if (m_bFocus) + { + m_bFocus = false; + UpdateFocus(); + } } } @@ -730,7 +737,7 @@ int CEdit::MouseDetect(Math::Point mouse) if ( i >= m_lineFirst+m_lineVisible ) break; - pos.x = m_pos.x+(10.0f/640.0f); + pos.x = m_pos.x+(7.5f/640.0f)*(m_fontSize/Gfx::FONT_SIZE_SMALL); if ( m_bAutoIndent ) { pos.x += indentLength*m_lineIndent[i]; @@ -945,7 +952,7 @@ void CEdit::Draw() if ( i >= m_lineFirst+m_lineVisible ) break; - pos.x = m_pos.x+(10.0f/640.0f); + pos.x = m_pos.x+(7.5f/640.0f)*(m_fontSize/Gfx::FONT_SIZE_SMALL); if ( m_bAutoIndent ) { const char *s = "\t"; // line | dotted @@ -1107,7 +1114,7 @@ void CEdit::Draw() { if ( i == m_lineTotal-1 || m_cursor1 < m_lineOffset[i+1] ) { - pos.x = m_pos.x+(10.0f/640.0f); + pos.x = m_pos.x+(7.5f/640.0f)*(m_fontSize/Gfx::FONT_SIZE_SMALL); if ( m_bAutoIndent ) { pos.x += indentLength*m_lineIndent[i]; @@ -2767,7 +2774,7 @@ void CEdit::DeleteOne(int dir) } m_len -= hole; m_cursor2 = m_cursor1; -} +} // Delete word @@ -3003,7 +3010,7 @@ void CEdit::Justif() { bDual = false; - width = m_dim.x-(10.0f/640.0f)*2.0f-(m_bMulti?MARGX*2.0f+SCROLL_WIDTH:0.0f); + width = m_dim.x-(7.5f/640.0f)*(m_fontSize/Gfx::FONT_SIZE_SMALL)*2.0f-(m_bMulti?MARGX*2.0f+SCROLL_WIDTH:0.0f); if ( m_bAutoIndent ) { width -= indentLength*m_lineIndent[m_lineTotal-1]; @@ -3276,7 +3283,7 @@ void CEdit::SetFocus(CControl* control) void CEdit::UpdateFocus() { - CApplication::GetInstancePointer()->SetTextInput(m_bFocus); + CApplication::GetInstancePointer()->SetTextInput(m_bFocus, m_eventType); } } From 7216d8d12efb70ab1885d0854fd46dcc84eece23 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 24 May 2017 12:42:37 +0200 Subject: [PATCH 88/93] Fix crash after exiting a code battle --- src/level/robotmain.cpp | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 30f55e3c..6159652e 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -2548,30 +2548,30 @@ bool CRobotMain::EventFrame(const Event &event) m_eventQueue->AddEvent(Event(EVENT_LOST)); } } - } - if (GetMissionType() == MISSION_CODE_BATTLE) - { - if (!m_codeBattleInit) + if (GetMissionType() == MISSION_CODE_BATTLE) { - // NOTE: It's important to do this AFTER the first update event finished processing - // because otherwise all robot parts are misplaced - m_userPause = m_pause->ActivatePause(PAUSE_ENGINE); - m_codeBattleInit = true; // Will start on resume + if (!m_codeBattleInit) + { + // NOTE: It's important to do this AFTER the first update event finished processing + // because otherwise all robot parts are misplaced + m_userPause = m_pause->ActivatePause(PAUSE_ENGINE); + m_codeBattleInit = true; // Will start on resume + } + + if (!m_codeBattleStarted && m_userPause == nullptr) + { + m_codeBattleStarted = true; + ApplyCodeBattleInterface(); + CreateCodeBattleInterface(); + + SetCodeBattleSpectatorMode(true); + + m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE)); + } + + UpdateCodeBattleInterface(); } - - if (!m_codeBattleStarted && m_userPause == nullptr) - { - m_codeBattleStarted = true; - ApplyCodeBattleInterface(); - CreateCodeBattleInterface(); - - SetCodeBattleSpectatorMode(true); - - m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE)); - } - - UpdateCodeBattleInterface(); } return true; From 1f477bbc86c36fb93e0b831ea6852aa0f44ee8a7 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 24 May 2017 12:46:30 +0200 Subject: [PATCH 89/93] Fix error in edit.cpp in 08d87fa9757a05b66325b9ea77123d098143ddbd --- src/ui/controls/edit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/controls/edit.cpp b/src/ui/controls/edit.cpp index 1269284d..7d08b260 100644 --- a/src/ui/controls/edit.cpp +++ b/src/ui/controls/edit.cpp @@ -148,7 +148,7 @@ CEdit::~CEdit() if (m_bFocus) { - CApplication::GetInstancePointer()->SetTextInput(false, EVENT_OBJECT_PEN3); + CApplication::GetInstancePointer()->SetTextInput(false, m_eventType); } } From 6c8ec467258431c1b66c9727523de709c886dcf7 Mon Sep 17 00:00:00 2001 From: RaptorParkowsky Date: Wed, 24 May 2017 13:43:51 +0200 Subject: [PATCH 90/93] Update data submodule --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 1dc4ce70..cd81b57a 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 1dc4ce709c1f56a081c6bd90c04892234a2fb96d +Subproject commit cd81b57ae95d5a045244de7192f6263b87615c54 From 28081bfd3ec1e1e15a00cd7260734280dd85cbc9 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 24 May 2017 13:58:57 +0200 Subject: [PATCH 91/93] Fix clang builds see #955 --- src/CBot/CBotDefParam.cpp | 1 - test/unit/CBot/CBot_test.cpp | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp index 074f025d..b99503f7 100644 --- a/src/CBot/CBotDefParam.cpp +++ b/src/CBot/CBotDefParam.cpp @@ -223,7 +223,6 @@ bool CBotDefParam::HasDefault() //////////////////////////////////////////////////////////////////////////////// void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain) { - assert(this != nullptr); CBotDefParam* p = this; CBotStack* pile = nullptr; diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 5d3b72c3..9e264e1e 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -216,15 +216,15 @@ protected: if (error != CBotNoErr) { ADD_FAILURE() << "Compile error - " << error << " (" << cursor1 << "-" << (cursor2 >= 0 ? cursor2 : cursor1) << ")" << std::endl << GetFormattedLineInfo(code, cursor1); // TODO: Error messages are on Colobot side - return std::move(program); + return program; } else { ADD_FAILURE() << "No compile error, expected " << expectedCompileError; // TODO: Error messages are on Colobot side - return std::move(program); + return program; } } - if (expectedCompileError != CBotNoErr) return std::move(program); + if (expectedCompileError != CBotNoErr) return program; for (const std::string& test : tests) { @@ -285,7 +285,7 @@ protected: ADD_FAILURE() << ss.str(); } } - return std::move(program); // Take it if you want, destroy on exit otherwise + return program; // Take it if you want, destroy on exit otherwise } }; From 02aa281d305dbc106f7044e97e6bc3ae0aeae9eb Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 24 May 2017 13:59:20 +0200 Subject: [PATCH 92/93] Remove unnecessary m_instance declarations They don't do anything at all in gcc and clang, but cause compile errors in MSVC see #955 --- src/app/app.h | 2 -- src/app/input.h | 2 -- src/app/pathman.h | 2 -- src/common/config_file.h | 2 -- src/common/logger.h | 2 -- src/common/settings.h | 2 -- src/graphics/engine/engine.h | 2 -- src/level/robotmain.h | 2 -- src/object/object_manager.h | 2 -- 9 files changed, 18 deletions(-) diff --git a/src/app/app.h b/src/app/app.h index ac8769c7..20721e24 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -407,5 +407,3 @@ protected: std::map m_textInputEnabled; }; - -template<> CApplication* CSingleton::m_instance; diff --git a/src/app/input.h b/src/app/input.h index 2b8617eb..15cdc98d 100644 --- a/src/app/input.h +++ b/src/app/input.h @@ -161,5 +161,3 @@ private: std::map m_keyTable; }; - -template<> CInput* CSingleton::m_instance; diff --git a/src/app/pathman.h b/src/app/pathman.h index 87fa4493..059c81fe 100644 --- a/src/app/pathman.h +++ b/src/app/pathman.h @@ -67,5 +67,3 @@ private: //! Save path std::string m_savePath; }; - -template<> CPathManager* CSingleton::m_instance; diff --git a/src/common/config_file.h b/src/common/config_file.h index 9acc5aee..0ed8e19f 100644 --- a/src/common/config_file.h +++ b/src/common/config_file.h @@ -112,5 +112,3 @@ inline CConfigFile & GetConfigFile() { return CConfigFile::GetInstance(); } - -template<> CConfigFile* CSingleton::m_instance; diff --git a/src/common/logger.h b/src/common/logger.h index e49fbd33..e0a935d4 100644 --- a/src/common/logger.h +++ b/src/common/logger.h @@ -136,5 +136,3 @@ inline CLogger* GetLogger() { return CLogger::GetInstancePointer(); } - -template<> CLogger* CSingleton::m_instance; diff --git a/src/common/settings.h b/src/common/settings.h index cb236601..4e9b7620 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -105,5 +105,3 @@ protected: Language m_language; }; - -template<> CSettings* CSingleton::m_instance; diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 687bbafb..834de1e3 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -1490,5 +1490,3 @@ protected: } // namespace Gfx - -template<> Gfx::CEngine* CSingleton::m_instance; diff --git a/src/level/robotmain.h b/src/level/robotmain.h index d4e18525..fee753f0 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -716,5 +716,3 @@ protected: //! Index of currently selected element in command history int m_commandHistoryIndex; }; - -template<> CRobotMain* CSingleton::m_instance; diff --git a/src/object/object_manager.h b/src/object/object_manager.h index 2a02d24e..73ae0015 100644 --- a/src/object/object_manager.h +++ b/src/object/object_manager.h @@ -311,5 +311,3 @@ private: int m_activeObjectIterators; bool m_shouldCleanRemovedObjects; }; - -template<> CObjectManager* CSingleton::m_instance; From 8269f791738c92008d66103e91a724df00938e22 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 24 May 2017 14:33:34 +0200 Subject: [PATCH 93/93] Update data submodule --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index cd81b57a..2794fd57 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit cd81b57ae95d5a045244de7192f6263b87615c54 +Subproject commit 2794fd57c32412d4c9103d20c1ec0c888e1e97a0