diff --git a/src/CBot/stdlib/MathFunctions.cpp b/src/CBot/stdlib/MathFunctions.cpp index b51d5748..ebe46545 100644 --- a/src/CBot/stdlib/MathFunctions.cpp +++ b/src/CBot/stdlib/MathFunctions.cpp @@ -144,13 +144,36 @@ bool rRand(CBotVar* var, CBotVar* result, int& exception, void* user) bool rAbs(CBotVar* var, CBotVar* result, int& exception, void* user) { - float value; + switch (result->GetType()) + { + case CBotTypDouble: + *result = fabs(var->GetValDouble()); + break; + case CBotTypFloat: + *result = fabs(var->GetValFloat()); + break; + case CBotTypLong: + *result = abs(var->GetValLong()); + break; + default: + *result = abs(var->GetValInt()); + break; + } - value = var->GetValFloat(); - result->SetValFloat(fabs(value)); return true; } +CBotTypResult cAbs(CBotVar* &var, void* user) +{ + if ( var == nullptr ) return CBotTypResult(CBotErrLowParam); + if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); + + CBotTypResult returnType(var->GetType()); + var = var->GetNext(); + if ( var != nullptr ) return CBotTypResult(CBotErrOverParam); + return returnType; +} + // Instruction "floor()" bool rFloor(CBotVar* var, CBotVar* result, int& exception, void* user) @@ -209,7 +232,7 @@ void InitMathFunctions() CBotProgram::AddFunction("sqrt", rSqrt, cOneFloat); CBotProgram::AddFunction("pow", rPow, cTwoFloat); CBotProgram::AddFunction("rand", rRand, cNull); - CBotProgram::AddFunction("abs", rAbs, cOneFloat); + CBotProgram::AddFunction("abs", rAbs, cAbs); CBotProgram::AddFunction("floor", rFloor, cOneFloat); CBotProgram::AddFunction("ceil", rCeil, cOneFloat); CBotProgram::AddFunction("round", rRound, cOneFloat); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index df752615..8dc9af86 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -420,6 +420,7 @@ set(BASE_SOURCES object/object_interface_type.h object/object_manager.cpp object/object_manager.h + object/object_type.cpp object/object_type.h object/old_object.cpp object/old_object.h diff --git a/src/app/app.cpp b/src/app/app.cpp index ecd8cc1b..ad5d02cb 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -1066,11 +1066,9 @@ int CApplication::Run() MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start - SystemTimeStamp *lastLoopTimeStamp = m_systemUtils->CreateTimeStamp(); + SystemTimeStamp *previousTimeStamp = m_systemUtils->CreateTimeStamp(); SystemTimeStamp *currentTimeStamp = m_systemUtils->CreateTimeStamp(); SystemTimeStamp *interpolatedTimeStamp = m_systemUtils->CreateTimeStamp(); - m_systemUtils->GetCurrentTimeStamp(lastLoopTimeStamp); - m_systemUtils->CopyTimeStamp(currentTimeStamp, lastLoopTimeStamp); while (true) { @@ -1174,11 +1172,11 @@ int CApplication::Run() // If game speed is increased then we do extra ticks per loop iteration to improve physics accuracy. int numTickSlices = static_cast(GetSimulationSpeed()); if(numTickSlices < 1) numTickSlices = 1; - m_systemUtils->CopyTimeStamp(lastLoopTimeStamp, currentTimeStamp); + m_systemUtils->CopyTimeStamp(previousTimeStamp, m_curTimeStamp); m_systemUtils->GetCurrentTimeStamp(currentTimeStamp); for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++) { - m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, lastLoopTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast(numTickSlices)); + m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast(numTickSlices)); Event event = CreateUpdateEvent(interpolatedTimeStamp); if (event.type != EVENT_NULL && m_controller != nullptr) { @@ -1209,7 +1207,7 @@ int CApplication::Run() } end: - m_systemUtils->DestroyTimeStamp(lastLoopTimeStamp); + m_systemUtils->DestroyTimeStamp(previousTimeStamp); m_systemUtils->DestroyTimeStamp(currentTimeStamp); m_systemUtils->DestroyTimeStamp(interpolatedTimeStamp); diff --git a/src/graphics/engine/oldmodelmanager.cpp b/src/graphics/engine/oldmodelmanager.cpp index ee155ce8..7207cc7b 100644 --- a/src/graphics/engine/oldmodelmanager.cpp +++ b/src/graphics/engine/oldmodelmanager.cpp @@ -57,7 +57,18 @@ bool COldModelManager::LoadModel(const std::string& fileName, bool mirrored, int if (!stream.is_open()) throw CModelIOException(std::string("Could not open file '") + fileName + "'"); - model = ModelInput::Read(stream, ModelFormat::Old); + std::string::size_type extension_index = fileName.find_last_of('.'); + if (extension_index == std::string::npos) + throw CModelIOException(std::string("Filename '") + fileName + "' has no extension"); + + std::string extension = fileName.substr(extension_index + 1); + + if (extension == "mod") + model = ModelInput::Read(stream, ModelFormat::Old); + else if (extension == "txt") + model = ModelInput::Read(stream, ModelFormat::Text); + else + throw CModelIOException(std::string("Filename '") + fileName + "' has unknown extension"); } catch (const CModelIOException& e) { diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index 0e47047f..fd946cca 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -210,7 +210,7 @@ bool CText::ReloadFonts() CFontLoader fontLoader; if (!fontLoader.Init()) { - GetLogger()->Warn("Error on parsing fonts config file: failed to open file\n"); + GetLogger()->Debug("Error on parsing fonts config file: failed to open file\n"); } // Backup previous fonts diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp index 2ca1aa4f..bd26d35b 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl/gl33device.cpp @@ -886,6 +886,8 @@ void CGL33Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, I glTexSubImage2D(GL_TEXTURE_2D, 0, offset.x, offset.y, texData.actualSurface->w, texData.actualSurface->h, texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels); + glGenerateMipmap(GL_TEXTURE_2D); + SDL_FreeSurface(texData.convertedSurface); } diff --git a/src/graphics/opengl/shaders/gl21/fs_normal.glsl b/src/graphics/opengl/shaders/gl21/fs_normal.glsl index 77402258..1aeffcbe 100644 --- a/src/graphics/opengl/shaders/gl21/fs_normal.glsl +++ b/src/graphics/opengl/shaders/gl21/fs_normal.glsl @@ -84,8 +84,8 @@ void main() { LightParams light = uni_Light[i]; - vec3 lightDirection = normalize(light.Position.xyz); - vec3 reflectAxis = normalize(lightDirection + camera); + vec3 lightDirection = light.Position.xyz; + vec3 reflectAxis = normalize(normalize(lightDirection) + camera); float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f); float specularComponent = pow(clamp(dot(normal, reflectAxis), 0.0f, 1.0f), 10.0f); diff --git a/src/graphics/opengl/shaders/gl33/fs_normal.glsl b/src/graphics/opengl/shaders/gl33/fs_normal.glsl index 7b498723..be58f4fd 100644 --- a/src/graphics/opengl/shaders/gl33/fs_normal.glsl +++ b/src/graphics/opengl/shaders/gl33/fs_normal.glsl @@ -83,8 +83,8 @@ void main() for (int i = 0; i < uni_LightCount; i++) { - vec3 lightDirection = normalize(uni_Light[i].Position.xyz); - vec3 reflectAxis = normalize(lightDirection + camera); + vec3 lightDirection = uni_Light[i].Position.xyz; + vec3 reflectAxis = normalize(normalize(lightDirection) + camera); ambient += uni_Light[i].Ambient; diffuse += clamp(dot(normal, lightDirection), 0.0f, 1.0f) diff --git a/src/object/object_type.cpp b/src/object/object_type.cpp new file mode 100644 index 00000000..ca452bc0 --- /dev/null +++ b/src/object/object_type.cpp @@ -0,0 +1,236 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "object/object_type.h" + +#include + +bool IsValidObjectTypeId(int id) +{ + static const std::unordered_set validIds{ + OBJECT_NULL, + OBJECT_PORTICO, + OBJECT_BASE, + OBJECT_DERRICK, + OBJECT_FACTORY, + OBJECT_STATION, + OBJECT_CONVERT, + OBJECT_REPAIR, + OBJECT_TOWER, + OBJECT_NEST, + OBJECT_RESEARCH, + OBJECT_RADAR, + OBJECT_ENERGY, + OBJECT_LABO, + OBJECT_NUCLEAR, + OBJECT_START, + OBJECT_END, + OBJECT_INFO, + OBJECT_PARA, + OBJECT_TARGET1, + OBJECT_TARGET2, + OBJECT_SAFE, + OBJECT_HUSTON, + OBJECT_DESTROYER, + OBJECT_STONE, + OBJECT_URANIUM, + OBJECT_METAL, + OBJECT_POWER, + OBJECT_ATOMIC, + OBJECT_BULLET, + OBJECT_BBOX, + OBJECT_TNT, + OBJECT_MARKPOWER, + OBJECT_MARKSTONE, + OBJECT_MARKURANIUM, + OBJECT_MARKKEYa, + OBJECT_MARKKEYb, + OBJECT_MARKKEYc, + OBJECT_MARKKEYd, + OBJECT_BOMB, + OBJECT_WINFIRE, + OBJECT_SHOW, + OBJECT_BAG, + OBJECT_PLANT0, + OBJECT_PLANT1, + OBJECT_PLANT2, + OBJECT_PLANT3, + OBJECT_PLANT4, + OBJECT_PLANT5, + OBJECT_PLANT6, + OBJECT_PLANT7, + OBJECT_PLANT8, + OBJECT_PLANT9, + OBJECT_PLANT10, + OBJECT_PLANT11, + OBJECT_PLANT12, + OBJECT_PLANT13, + OBJECT_PLANT14, + OBJECT_PLANT15, + OBJECT_PLANT16, + OBJECT_PLANT17, + OBJECT_PLANT18, + OBJECT_PLANT19, + OBJECT_TREE0, + OBJECT_TREE1, + OBJECT_TREE2, + OBJECT_TREE3, + OBJECT_TREE4, + OBJECT_TREE5, + OBJECT_MOBILEwt, + OBJECT_MOBILEtt, + OBJECT_MOBILEft, + OBJECT_MOBILEit, + OBJECT_MOBILErp, + OBJECT_MOBILEst, + OBJECT_MOBILEwa, + OBJECT_MOBILEta, + OBJECT_MOBILEfa, + OBJECT_MOBILEia, + OBJECT_MOBILEwc, + OBJECT_MOBILEtc, + OBJECT_MOBILEfc, + OBJECT_MOBILEic, + OBJECT_MOBILEwi, + OBJECT_MOBILEti, + OBJECT_MOBILEfi, + OBJECT_MOBILEii, + OBJECT_MOBILEws, + OBJECT_MOBILEts, + OBJECT_MOBILEfs, + OBJECT_MOBILEis, + OBJECT_MOBILErt, + OBJECT_MOBILErc, + OBJECT_MOBILErr, + OBJECT_MOBILErs, + OBJECT_MOBILEsa, + OBJECT_MOBILEtg, + OBJECT_MOBILEdr, + OBJECT_CONTROLLER, + OBJECT_MOBILEwb, + OBJECT_MOBILEtb, + OBJECT_MOBILEfb, + OBJECT_MOBILEib, + OBJECT_MOBILEpr, + OBJECT_WAYPOINT, + OBJECT_FLAGb, + OBJECT_FLAGr, + OBJECT_FLAGg, + OBJECT_FLAGy, + OBJECT_FLAGv, + OBJECT_KEYa, + OBJECT_KEYb, + OBJECT_KEYc, + OBJECT_KEYd, + OBJECT_HUMAN, + OBJECT_TOTO, + OBJECT_TECH, + OBJECT_BARRIER0, + OBJECT_BARRIER1, + OBJECT_BARRIER2, + OBJECT_BARRIER3, + OBJECT_BARRICADE0, + OBJECT_BARRICADE1, + OBJECT_MOTHER, + OBJECT_EGG, + OBJECT_ANT, + OBJECT_SPIDER, + OBJECT_BEE, + OBJECT_WORM, + OBJECT_RUINmobilew1, + OBJECT_RUINmobilew2, + OBJECT_RUINmobilet1, + OBJECT_RUINmobilet2, + OBJECT_RUINmobiler1, + OBJECT_RUINmobiler2, + OBJECT_RUINfactory, + OBJECT_RUINdoor, + OBJECT_RUINsupport, + OBJECT_RUINradar, + OBJECT_RUINconvert, + OBJECT_RUINbase, + OBJECT_RUINhead, + OBJECT_TEEN0, + OBJECT_TEEN1, + OBJECT_TEEN2, + OBJECT_TEEN3, + OBJECT_TEEN4, + OBJECT_TEEN5, + OBJECT_TEEN6, + OBJECT_TEEN7, + OBJECT_TEEN8, + OBJECT_TEEN9, + OBJECT_TEEN10, + OBJECT_TEEN11, + OBJECT_TEEN12, + OBJECT_TEEN13, + OBJECT_TEEN14, + OBJECT_TEEN15, + OBJECT_TEEN16, + OBJECT_TEEN17, + OBJECT_TEEN18, + OBJECT_TEEN19, + OBJECT_TEEN20, + OBJECT_TEEN21, + OBJECT_TEEN22, + OBJECT_TEEN23, + OBJECT_TEEN24, + OBJECT_TEEN25, + OBJECT_TEEN26, + OBJECT_TEEN27, + OBJECT_TEEN28, + OBJECT_TEEN29, + OBJECT_TEEN30, + OBJECT_TEEN31, + OBJECT_TEEN32, + OBJECT_TEEN33, + OBJECT_TEEN34, + OBJECT_TEEN35, + OBJECT_TEEN36, + OBJECT_TEEN37, + OBJECT_TEEN38, + OBJECT_TEEN39, + OBJECT_TEEN40, + OBJECT_TEEN41, + OBJECT_TEEN42, + OBJECT_TEEN43, + OBJECT_TEEN44, + OBJECT_QUARTZ0, + OBJECT_QUARTZ1, + OBJECT_QUARTZ2, + OBJECT_QUARTZ3, + OBJECT_ROOT0, + OBJECT_ROOT1, + OBJECT_ROOT2, + OBJECT_ROOT3, + OBJECT_ROOT4, + OBJECT_ROOT5, + OBJECT_MUSHROOM1, + OBJECT_MUSHROOM2, + OBJECT_APOLLO1, + OBJECT_APOLLO2, + OBJECT_APOLLO3, + OBJECT_APOLLO4, + OBJECT_APOLLO5, + OBJECT_HOME1, + + OBJECT_MAX + }; + return validIds.count(id); +} diff --git a/src/object/object_type.h b/src/object/object_type.h index d4a8f062..7f78e304 100644 --- a/src/object/object_type.h +++ b/src/object/object_type.h @@ -248,3 +248,5 @@ struct ObjectTypeHash return std::hash()(t); } }; + +bool IsValidObjectTypeId(int id); diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index cc2b2bda..7f09ed5e 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -734,6 +734,9 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo } else { + CScript* script = static_cast(user); + bool deleteSelf = (obj == script->m_object); + if ( exploType != DestructionType::NoEffect && obj->Implements(ObjectInterfaceType::Destroyable) ) { dynamic_cast(obj)->DestroyObject(static_cast(exploType)); @@ -752,12 +755,13 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo } CObjectManager::GetInstancePointer()->DeleteObject(obj); } + // Returning "false" here makes sure the program doesn't try to keep executing + // if the robot just destroyed itself using delete(this.id) + // See issue #925 + return !deleteSelf; } - // Returning "false" here makes sure the program doesn't try to keep executing if the robot just destroyed itself - // using delete(this.id) - // See issue #925 - return false; + return true; } static CBotTypResult compileSearch(CBotVar* &var, void* user, CBotTypResult returnValue) @@ -1565,7 +1569,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v { power = 1.0f; } - bool exists = !std::string(GetObjectName(type)).empty(); //The object type exists in object_type.h + bool exists = IsValidObjectTypeId(type) && type != OBJECT_NULL && type != OBJECT_MAX && type != OBJECT_MOBILEpr; if (exists) { object = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type, power); diff --git a/tools/blender-scripts.py b/tools/blender-scripts.py index d2273d67..b4104793 100644 --- a/tools/blender-scripts.py +++ b/tools/blender-scripts.py @@ -8,7 +8,7 @@ bl_info = { "name": "Colobot Model Format (.txt)", "author": "TerranovaTeam", - "version": (0, 0, 2), + "version": (0, 0, 3), "blender": (2, 6, 4), "location": "File > Export > Colobot (.txt)", "description": "Export Colobot Model Format (.txt)", @@ -35,7 +35,7 @@ FUZZY_TOLERANCE = 1e-5 class ColobotError(Exception): """Exception in I/O operations""" - def __init__(self, value): + def __init__(self, value, errcode=None): self.value = value def __str__(self): return repr(self.value) @@ -199,7 +199,8 @@ def write_colobot_model(filename, model): file.write('tex1 ' + t.mat.tex1 + '\n') file.write('tex2 ' + t.mat.tex2 + '\n') file.write('var_tex2 ' + ( 'Y' if t.mat.var_tex2 else 'N' + '\n' ) ) - file.write('lod_level ' + str(t.lod_level) + '\n') + if model.version == 1: + file.write('lod_level ' + str(t.lod_level) + '\n') file.write('state ' + str(t.mat.state) + '\n') file.write('\n') @@ -281,8 +282,8 @@ def read_colobot_model(filename): if (tokens[0] != 'version'): raise ColobotError("Invalid header", "version") model.version = int(tokens[1]) - if (model.version != 1): - raise ColobotError("Unknown model file version") + if (model.version != 1 and model.version != 2): + raise ColobotError("Unknown model file version "+str(model.version)) tokens, index = token_next_line(lines, index) if (tokens[0] != 'total_triangles'): @@ -329,10 +330,13 @@ def read_colobot_model(filename): raise ColobotError("Invalid triangle", "var_tex2") t.mat.var_tex2 = tokens[1] == 'Y' - tokens, index = token_next_line(lines, index) - if (tokens[0] != 'lod_level'): - raise ColobotError("Invalid triangle", "lod_level") - t.lod_level = int(tokens[1]) + if (model.version == 1): + tokens, index = token_next_line(lines, index) + if (tokens[0] != 'lod_level'): + raise ColobotError("Invalid triangle", "lod_level") + t.lod_level = int(tokens[1]) + else: + t.lod_level = 0 # constant tokens, index = token_next_line(lines, index) if (tokens[0] != 'state'): @@ -384,9 +388,9 @@ def append_obj_to_colobot_model(obj, model, scene, defaults): t.mat.specular[3] = mat.specular_alpha if (mat.texture_slots[0] != None): - t.tex1 = bpy.path.basename(mat.texture_slots[0].texture.image.filepath) + t.mat.tex1 = bpy.path.basename(mat.texture_slots[0].texture.image.filepath) if (mat.texture_slots[1] != None): - t.tex2 = bpy.path.basename(mat.texture_slots[1].texture.image.filepath) + t.mat.tex2 = bpy.path.basename(mat.texture_slots[1].texture.image.filepath) t.var_tex2 = mat.get('var_tex2', defaults['var_tex2']) t.state = mat.get('state', defaults['state']) @@ -589,7 +593,7 @@ class ExportColobotDialog(bpy.types.Operator): write_colobot_model(EXPORT_FILEPATH, model) except ColobotError as e: - self.report({'ERROR'}, e.args.join(": ")) + self.report({'ERROR'}, ": ".join(e.args)) return {'FINISHED'} self.report({'INFO'}, 'Export OK') @@ -665,7 +669,7 @@ class ImportColobotDialog(bpy.types.Operator): obj.layers = layers except ColobotError as e: - self.report({'ERROR'}, e.args.join(": ")) + self.report({'ERROR'}, ": ".join(e.args)) return {'FINISHED'} self.report({'INFO'}, 'Import OK')