From 740036e430d98afe487313bb5be8c5e72968eb94 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 24 Sep 2014 22:54:26 +0200 Subject: [PATCH] New level parser Known issues: * TerrainLevel for some reason doesn't work * %lvl% is not yet implemented everywhere because of hardcoded directories in functions --- src/CMakeLists.txt | 4 + src/object/level/parser.cpp | 221 +++++ src/object/level/parser.h | 66 ++ src/object/level/parserexceptions.cpp | 40 + src/object/level/parserexceptions.h | 49 + src/object/level/parserline.cpp | 87 ++ src/object/level/parserline.h | 59 ++ src/object/level/parserparam.cpp | 930 ++++++++++++++++++ src/object/level/parserparam.h | 133 +++ src/object/robotmain.cpp | 1310 +++++++++++-------------- src/script/cmdtoken.cpp | 2 + src/script/script.cpp | 1 - 12 files changed, 2186 insertions(+), 716 deletions(-) create mode 100644 src/object/level/parser.cpp create mode 100644 src/object/level/parser.h create mode 100644 src/object/level/parserexceptions.cpp create mode 100644 src/object/level/parserexceptions.h create mode 100644 src/object/level/parserline.cpp create mode 100644 src/object/level/parserline.h create mode 100644 src/object/level/parserparam.cpp create mode 100644 src/object/level/parserparam.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e02a30b8..0440c5ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -122,6 +122,10 @@ object/auto/autosafe.cpp object/auto/autostation.cpp object/auto/autotower.cpp object/brain.cpp +object/level/parser.cpp +object/level/parserline.cpp +object/level/parserparam.cpp +object/level/parserexceptions.cpp object/mainmovie.cpp object/motion/motion.cpp object/motion/motionant.cpp diff --git a/src/object/level/parser.cpp b/src/object/level/parser.cpp new file mode 100644 index 00000000..89059d0c --- /dev/null +++ b/src/object/level/parser.cpp @@ -0,0 +1,221 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * 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://www.gnu.org/licenses/. + +#include "object/level/parser.h" + + +#include "app/app.h" + +#include "common/resources/inputstream.h" + +#include "object/level/parserexceptions.h" + +#include +#include +#include +#include + +#include +#include + +CLevelParser::CLevelParser() +{ + m_filename = ""; +} + +CLevelParser::CLevelParser(std::string filename) +{ + m_filename = filename; +} + +CLevelParser::CLevelParser(std::string category, int chapter, int rank) +{ + m_filename = BuildSceneName(category, chapter, rank); +} + +CLevelParser::~CLevelParser() +{ + for(auto line : m_lines) + { + delete line; + } +} + +std::string CLevelParser::BuildSceneName(std::string category, int chapter, int rank, bool sceneFile) +{ + std::ostringstream outstream; + if(category == "user") + { + //TODO: Change this to point user dir according to operating system + /*rankStream << std::setfill('0') << std::setw(2) << rank%100; + filename = m_userDir + "/" + m_userList[rank/100-1] + "/" + rankStream.str() + ".txt";*/ + assert(false); //TODO: Userlevel support + } + else if(category == "perso") + { + outstream << "levels/other/perso.txt"; + } + else if(category == "win" || category == "lost") + { + outstream << "levels/other/"; + outstream << category << std::setfill('0') << std::setw(3) << chapter*100+rank << ".txt"; + } + else + { + outstream << "levels/" << category << "/"; + outstream << "chapter" << std::setfill('0') << std::setw(3) << chapter; + if(rank == 000) + { + if(sceneFile) + { + outstream << "/chaptertitle.txt"; + } + } + else + { + outstream << "/level" << std::setfill('0') << std::setw(3) << rank; + if(sceneFile) + { + outstream << "/scene.txt"; + } + } + } + return outstream.str(); +} + +void CLevelParser::Load() +{ + CInputStream file; + file.open(m_filename); + if(!file.is_open()) + throw CLevelParserException("Failed to open file: "+m_filename); + + char lang = CApplication::GetInstancePointer()->GetLanguageChar(); + + std::string line; + int lineNumber = 0; + std::map translatableLines; + while(getline(file,line)) + { + lineNumber++; + + boost::replace_all(line, "\t", " "); // replace tab by space + + // ignore comments + std::size_t comment = line.find("//"); + if(comment != std::string::npos) + line = line.substr(0, comment); + + boost::algorithm::trim(line); + + std::size_t pos = line.find_first_of(" \t\n"); + std::string command = line.substr(0, pos); + if(pos != std::string::npos) { + line = line.substr(pos+1); + boost::algorithm::trim(line); + } else { + line = ""; + } + if(command.empty()) continue; + + CLevelParserLine* parserLine = new CLevelParserLine(lineNumber, command); + + std::string baseCommand = command; + if(command[command.length()-2] == '.') { + baseCommand = command.substr(0, command.length()-2); + if(command[command.length()-1] == 'E' && translatableLines[baseCommand] == nullptr) { + parserLine->SetCommand(baseCommand); + translatableLines[baseCommand] = parserLine; + } else if(command[command.length()-1] == lang) { + if(translatableLines[baseCommand] != nullptr) { + m_lines.erase(std::remove(m_lines.begin(), m_lines.end(), translatableLines[baseCommand]), m_lines.end()); + delete translatableLines[baseCommand]; + } + parserLine->SetCommand(baseCommand); + translatableLines[baseCommand] = parserLine; + } else { + delete parserLine; + continue; + } + } + + while(!line.empty()) { + pos = line.find_first_of("="); + std::string paramName = line.substr(0, pos); + boost::algorithm::trim(paramName); + line = line.substr(pos+1); + boost::algorithm::trim(line); + + if(line[0] == '\"') { + pos = line.find_first_of("\"", 1); + if(pos == std::string::npos) + throw CLevelParserException("Unclosed \" in "+m_filename+":"+std::to_string(lineNumber)); + } else if(line[0] == '\'') { + pos = line.find_first_of("'", 1); + if(pos == std::string::npos) + throw CLevelParserException("Unclosed ' in "+m_filename+":"+std::to_string(lineNumber)); + } else { + pos = line.find_first_of("="); + if(pos != std::string::npos) { + std::size_t pos2 = line.find_last_of(" \t\n", line.find_last_not_of(" \t\n", pos-1)); + if(pos2 != std::string::npos) + pos = pos2; + } else { + pos = line.length()-1; + } + } + std::string paramValue = line.substr(0, pos+1); + boost::algorithm::trim(paramValue); + + parserLine->AddParam(paramName, new CLevelParserParam(paramName, paramValue)); + + if(pos == std::string::npos) + break; + line = line.substr(pos+1); + boost::algorithm::trim(line); + } + + AddLine(parserLine); + } + + file.close(); +} + +void CLevelParser::Save(std::string filename) +{ + assert(false); //TODO +} + +const std::string& CLevelParser::GetFilename() +{ + return m_filename; +} + +std::vector CLevelParser::GetLines() +{ + return m_lines; +} + +void CLevelParser::AddLine(CLevelParserLine* line) +{ + line->SetLevel(this); + m_lines.push_back(line); +} + +CLevelParserLine* CLevelParser::Get(std::string command) +{ + assert(false); //TODO +} \ No newline at end of file diff --git a/src/object/level/parser.h b/src/object/level/parser.h new file mode 100644 index 00000000..3bae2ebd --- /dev/null +++ b/src/object/level/parser.h @@ -0,0 +1,66 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * 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://www.gnu.org/licenses/. + +/** + * \file object/level/parser.h + * \brief Parser for level files + */ + +#pragma once + +#include "object/level/parserline.h" +#include "object/level/parserparam.h" +#include "object/level/parserexceptions.h" + +#include +#include + +class CLevelParser +{ +public: + //! Create an empty level file + CLevelParser(); + //! Load level from file + CLevelParser(std::string filename); + //! Load given level + CLevelParser(std::string category, int chapter, int rank); + + ~CLevelParser(); + + //! Build level filename + static std::string BuildSceneName(std::string category, int chapter, int rank, bool sceneFile = true); + + //! Load file + void Load(); + //! Save file + void Save(std::string filename); + + //! Get filename + const std::string& GetFilename(); + + //! Get all lines from file + std::vector GetLines(); + //! Insert new line to file + void AddLine(CLevelParserLine* line); + + //! Find first line with given command + CLevelParserLine* Get(std::string command); + +private: + + std::string m_filename; + std::vector m_lines; +}; \ No newline at end of file diff --git a/src/object/level/parserexceptions.cpp b/src/object/level/parserexceptions.cpp new file mode 100644 index 00000000..d5c46201 --- /dev/null +++ b/src/object/level/parserexceptions.cpp @@ -0,0 +1,40 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * 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://www.gnu.org/licenses/. + +#include "object/level/parserexceptions.h" + + +#include "object/level/parser.h" + +CLevelParserException::CLevelParserException(std::string message) noexcept +{ + m_message = message; +} + +const char* CLevelParserException::what() const noexcept +{ + return m_message.c_str(); +} + +CLevelParserExceptionMissingParam::CLevelParserExceptionMissingParam(CLevelParserParam* thisParam) noexcept +: CLevelParserException("Missing required param "+thisParam->GetName()+" (in "+thisParam->GetLine()->GetLevel()->GetFilename()+":"+std::to_string(thisParam->GetLine()->GetLineNumber())+")") +{ +} + +CLevelParserExceptionBadParam::CLevelParserExceptionBadParam(CLevelParserParam* thisParam, std::string requestedType) noexcept +: CLevelParserException("Unable to parse '"+thisParam->GetValue()+"' as "+requestedType+" (param '"+thisParam->GetName()+"' in "+thisParam->GetLine()->GetLevel()->GetFilename()+":"+std::to_string(thisParam->GetLine()->GetLineNumber())+")") +{ +} \ No newline at end of file diff --git a/src/object/level/parserexceptions.h b/src/object/level/parserexceptions.h new file mode 100644 index 00000000..813467fb --- /dev/null +++ b/src/object/level/parserexceptions.h @@ -0,0 +1,49 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * 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://www.gnu.org/licenses/. + +/** + * \file object/level/parserexceptions.h + * \brief Exceptions that could be thrown in level parser + */ + +#pragma once + +#include +#include + +class CLevelParserParam; + +class CLevelParserException : public std::exception +{ +public: + CLevelParserException(std::string message) noexcept; + const char* what() const noexcept; + +protected: + std::string m_message; +}; + +class CLevelParserExceptionMissingParam : public CLevelParserException +{ +public: + CLevelParserExceptionMissingParam(CLevelParserParam* thisParam) noexcept; +}; + +class CLevelParserExceptionBadParam : public CLevelParserException +{ +public: + CLevelParserExceptionBadParam(CLevelParserParam* thisParam, std::string requestedType) noexcept; +}; \ No newline at end of file diff --git a/src/object/level/parserline.cpp b/src/object/level/parserline.cpp new file mode 100644 index 00000000..37f63972 --- /dev/null +++ b/src/object/level/parserline.cpp @@ -0,0 +1,87 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * 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://www.gnu.org/licenses/. + +#include "object/level/parserline.h" + + +#include "object/level/parser.h" +#include "common/logger.h" + +CLevelParserLine::CLevelParserLine(std::string command) +{ + m_command = command; + m_lineNumber = 0; +} + +CLevelParserLine::CLevelParserLine(int lineNumber, std::string command) +{ + m_command = command; + m_lineNumber = lineNumber; +} + +CLevelParserLine::~CLevelParserLine() +{ + for(auto param : m_params) + { + delete param.second; + } +} + +std::string CLevelParserLine::GetLine() +{ + assert(false); //TODO +} + +int CLevelParserLine::GetLineNumber() +{ + return m_lineNumber; +} + +CLevelParser* CLevelParserLine::GetLevel() +{ + return m_level; +} + +void CLevelParserLine::SetLevel(CLevelParser* level) +{ + m_level = level; +} + +std::string CLevelParserLine::GetCommand() +{ + return m_command; +} + +void CLevelParserLine::SetCommand(std::string command) +{ + m_command = command; +} + +CLevelParserParam* CLevelParserLine::GetParam(std::string name) +{ + if(m_params[name] == nullptr) { + CLevelParserParam* param = new CLevelParserParam(name, true); + param->SetLine(this); + m_params[name] = param; + } + return m_params[name]; +} + +void CLevelParserLine::AddParam(std::string name, CLevelParserParam* value) +{ + value->SetLine(this); + m_params[name] = value; +} \ No newline at end of file diff --git a/src/object/level/parserline.h b/src/object/level/parserline.h new file mode 100644 index 00000000..e8da34fb --- /dev/null +++ b/src/object/level/parserline.h @@ -0,0 +1,59 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * 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://www.gnu.org/licenses/. + +/** + * \file object/level/parserline.h + * \brief Class for one line from level file + */ + +#pragma once + +#include +#include + +class CLevelParser; +class CLevelParserParam; + +class CLevelParserLine +{ +public: + CLevelParserLine(int lineNumber, std::string command); + CLevelParserLine(std::string command); + ~CLevelParserLine(); + + //! Get line to be saved in level file + std::string GetLine(); + + //! Get line number + int GetLineNumber(); + + //! Get CLevelParser this line is part of + CLevelParser* GetLevel(); + //! Set CLevelParser this line is part of + void SetLevel(CLevelParser* level); + + std::string GetCommand(); + void SetCommand(std::string command); + + CLevelParserParam* GetParam(std::string name); + void AddParam(std::string name, CLevelParserParam* value); + +private: + CLevelParser* m_level; + int m_lineNumber; + std::string m_command; + std::map m_params; +}; \ No newline at end of file diff --git a/src/object/level/parserparam.cpp b/src/object/level/parserparam.cpp new file mode 100644 index 00000000..ec043b4a --- /dev/null +++ b/src/object/level/parserparam.cpp @@ -0,0 +1,930 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * 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://www.gnu.org/licenses/. + +#include "object/level/parserline.h" + + +#include "app/app.h" +#include "common/logger.h" +#include "object/level/parser.h" +#include "object/robotmain.h" + +#include +#include + +CLevelParserParam::CLevelParserParam(std::string name, std::string value) +{ + m_name = name; + m_value = value; + m_empty = false; +} + +CLevelParserParam::CLevelParserParam(std::string name, bool empty) +{ + assert(empty == true); // we need a second argument because we don't want to create param with value "name" + m_name = name; + m_value = ""; + m_empty = true; +} + +CLevelParserParam::~CLevelParserParam() +{ + for(auto& a : m_array) + delete a; +} + +void CLevelParserParam::SetLine(CLevelParserLine* line) +{ + m_line = line; +} + +CLevelParserLine* CLevelParserParam::GetLine() +{ + return m_line; +} + +std::string CLevelParserParam::GetName() +{ + return m_name; +} + +std::string CLevelParserParam::GetValue() +{ + return m_value; +} + +bool CLevelParserParam::IsDefined() +{ + return !m_empty; +} + +template +T CLevelParserParam::Cast(std::string value, std::string requestedType) +{ + try { + return boost::lexical_cast(value); + } + catch(...) + { + throw CLevelParserExceptionBadParam(this, requestedType); + } +} + +template +T CLevelParserParam::Cast(std::string requestedType) +{ + return Cast(m_value, requestedType); +} + + +int CLevelParserParam::AsInt() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return Cast("int"); +} + + +int CLevelParserParam::AsInt(int def) +{ + if(m_empty) + return def; + return AsInt(); +} + + +float CLevelParserParam::AsFloat() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return Cast("float"); +} + +float CLevelParserParam::AsFloat(float def) +{ + if(m_empty) + return def; + return AsFloat(); +} + + +std::string CLevelParserParam::AsString() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + if((m_value[0] == '\"' && m_value[m_value.length()-1] == '\"') || (m_value[0] == '\'' && m_value[m_value.length()-1] == '\'')) + { + return m_value.substr(1, m_value.length()-2); + } else { + throw CLevelParserExceptionBadParam(this, "string"); + } +} + +std::string CLevelParserParam::AsString(std::string def) +{ + if(m_empty) + return def; + return AsString(); +} + + +bool CLevelParserParam::AsBool() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + std::string value = m_value; + boost::to_lower(value); + if(value == "true") return true; + if(value == "false") return false; + return Cast("bool"); +} + +bool CLevelParserParam::AsBool(bool def) +{ + if(m_empty) + return def; + return AsBool(); +} + + +std::string CLevelParserParam::InjectLevelDir(std::string path, const std::string defaultDir) +{ + std::string newPath = path; + std::string lvlDir = CLevelParser::BuildSceneName(CRobotMain::GetInstancePointer()->GetSceneName(), CRobotMain::GetInstancePointer()->GetSceneRank()/100, CRobotMain::GetInstancePointer()->GetSceneRank()%100, false); + boost::replace_all(newPath, "%lvl%", lvlDir); + if(newPath == path) + { + newPath = defaultDir + (!defaultDir.empty() ? "/" : "") + newPath; + } else { + if(defaultDir == "") + throw CLevelParserException("TODO: Param "+m_name+" does not yet support %lvl%! :("); + } + //TODO: Fallback to English + std::string langStr(1, CApplication::GetInstancePointer()->GetLanguageChar()); + boost::replace_all(newPath, "%lng%", langStr); + return newPath; +} + +std::string CLevelParserParam::AsPath(const std::string defaultDir) +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + + return InjectLevelDir(AsString(), defaultDir); +} + +std::string CLevelParserParam::AsPath(const std::string defaultDir, std::string def) +{ + if(m_empty) + return InjectLevelDir(def, defaultDir); + + return InjectLevelDir(AsString(def), defaultDir); +} + + +Gfx::Color CLevelParserParam::AsColor() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + + ParseArray(); + + if(m_array.size() == 3) { //RGB + return Gfx::Color(m_array[0]->AsFloat(), m_array[1]->AsFloat(), m_array[2]->AsFloat()); + } else if(m_array.size() == 4) { //RGBA + return Gfx::Color(m_array[0]->AsFloat(), m_array[1]->AsFloat(), m_array[2]->AsFloat(), m_array[3]->AsFloat()); + } else { + throw CLevelParserExceptionBadParam(this, "color"); + } +} + +Gfx::Color CLevelParserParam::AsColor(Gfx::Color def) +{ + if(m_empty) + return def; + return AsColor(); +} + + +Math::Vector CLevelParserParam::AsPoint() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + + ParseArray(); + + if(m_array.size() == 2) { //XZ + return Math::Vector(m_array[0]->AsFloat(), 0.0f, m_array[1]->AsFloat()); + } else if(m_array.size() == 3) { //XYZ + return Math::Vector(m_array[0]->AsFloat(), m_array[1]->AsFloat(), m_array[2]->AsFloat()); + } else { + throw CLevelParserExceptionBadParam(this, "point"); + } +} + +Math::Vector CLevelParserParam::AsPoint(Math::Vector def) +{ + if(m_empty) + return def; + return AsPoint(); +} + + +ObjectType CLevelParserParam::ToObjectType(std::string value) +{ + if(value == "All" ) return OBJECT_NULL; + if(value == "Portico" ) return OBJECT_PORTICO; + if(value == "SpaceShip" ) return OBJECT_BASE; + if(value == "PracticeBot" ) return OBJECT_MOBILEwt; + if(value == "WingedGrabber" ) return OBJECT_MOBILEfa; + if(value == "TrackedGrabber" ) return OBJECT_MOBILEta; + if(value == "WheeledGrabber" ) return OBJECT_MOBILEwa; + if(value == "LeggedGrabber" ) return OBJECT_MOBILEia; + if(value == "WingedShooter" ) return OBJECT_MOBILEfc; + if(value == "TrackedShooter" ) return OBJECT_MOBILEtc; + if(value == "WheeledShooter" ) return OBJECT_MOBILEwc; + if(value == "LeggedShooter" ) return OBJECT_MOBILEic; + if(value == "WingedOrgaShooter" ) return OBJECT_MOBILEfi; + if(value == "TrackedOrgaShooter") return OBJECT_MOBILEti; + if(value == "WheeledOrgaShooter") return OBJECT_MOBILEwi; + if(value == "LeggedOrgaShooter" ) return OBJECT_MOBILEii; + if(value == "WingedSniffer" ) return OBJECT_MOBILEfs; + if(value == "TrackedSniffer" ) return OBJECT_MOBILEts; + if(value == "WheeledSniffer" ) return OBJECT_MOBILEws; + if(value == "LeggedSniffer" ) return OBJECT_MOBILEis; + if(value == "Thumper" ) return OBJECT_MOBILErt; + if(value == "PhazerShooter" ) return OBJECT_MOBILErc; + if(value == "Recycler" ) return OBJECT_MOBILErr; + if(value == "Shielder" ) return OBJECT_MOBILErs; + if(value == "Subber" ) return OBJECT_MOBILEsa; + if(value == "TargetBot" ) return OBJECT_MOBILEtg; + if(value == "Scribbler" ) return OBJECT_MOBILEdr; + if(value == "PowerSpot" ) return OBJECT_MARKPOWER; + if(value == "TitaniumSpot" ) return OBJECT_MARKSTONE; + if(value == "UraniumSpot" ) return OBJECT_MARKURANIUM; + if(value == "PlatinumSpot" ) return OBJECT_MARKURANIUM; + if(value == "KeyASpot" ) return OBJECT_MARKKEYa; + if(value == "KeyBSpot" ) return OBJECT_MARKKEYb; + if(value == "KeyCSpot" ) return OBJECT_MARKKEYc; + if(value == "KeyDSpot" ) return OBJECT_MARKKEYd; + if(value == "WayPoint" ) return OBJECT_WAYPOINT; + if(value == "BlueFlag" ) return OBJECT_FLAGb; + if(value == "RedFlag" ) return OBJECT_FLAGr; + if(value == "GreenFlag" ) return OBJECT_FLAGg; + if(value == "YellowFlag" ) return OBJECT_FLAGy; + if(value == "VioletFlag" ) return OBJECT_FLAGv; + if(value == "PowerCell" ) return OBJECT_POWER; + if(value == "FuelCellPlant" ) return OBJECT_NUCLEAR; + if(value == "FuelCell" ) return OBJECT_ATOMIC; + if(value == "NuclearCell" ) return OBJECT_ATOMIC; + if(value == "TitaniumOre" ) return OBJECT_STONE; + if(value == "UraniumOre" ) return OBJECT_URANIUM; + if(value == "PlatinumOre" ) return OBJECT_URANIUM; + if(value == "Titanium" ) return OBJECT_METAL; + if(value == "OrgaMatter" ) return OBJECT_BULLET; + if(value == "BlackBox" ) return OBJECT_BBOX; + if(value == "KeyA" ) return OBJECT_KEYa; + if(value == "KeyB" ) return OBJECT_KEYb; + if(value == "KeyC" ) return OBJECT_KEYc; + if(value == "KeyD" ) return OBJECT_KEYd; + if(value == "TNT" ) return OBJECT_TNT; + if(value == "Scrap1" ) return OBJECT_SCRAP1; + if(value == "Scrap2" ) return OBJECT_SCRAP2; + if(value == "Scrap3" ) return OBJECT_SCRAP3; + if(value == "Scrap4" ) return OBJECT_SCRAP4; + if(value == "Scrap5" ) return OBJECT_SCRAP5; + if(value == "Mine" ) return OBJECT_BOMB; + if(value == "Firework" ) return OBJECT_WINFIRE; + if(value == "Bag" ) return OBJECT_BAG; + if(value == "Greenery0" ) return OBJECT_PLANT0; + if(value == "Greenery1" ) return OBJECT_PLANT1; + if(value == "Greenery2" ) return OBJECT_PLANT2; + if(value == "Greenery3" ) return OBJECT_PLANT3; + if(value == "Greenery4" ) return OBJECT_PLANT4; + if(value == "Greenery5" ) return OBJECT_PLANT5; + if(value == "Greenery6" ) return OBJECT_PLANT6; + if(value == "Greenery7" ) return OBJECT_PLANT7; + if(value == "Greenery8" ) return OBJECT_PLANT8; + if(value == "Greenery9" ) return OBJECT_PLANT9; + if(value == "Greenery10" ) return OBJECT_PLANT10; + if(value == "Greenery11" ) return OBJECT_PLANT11; + if(value == "Greenery12" ) return OBJECT_PLANT12; + if(value == "Greenery13" ) return OBJECT_PLANT13; + if(value == "Greenery14" ) return OBJECT_PLANT14; + if(value == "Greenery15" ) return OBJECT_PLANT15; + if(value == "Greenery16" ) return OBJECT_PLANT16; + if(value == "Greenery17" ) return OBJECT_PLANT17; + if(value == "Greenery18" ) return OBJECT_PLANT18; + if(value == "Greenery19" ) return OBJECT_PLANT19; + if(value == "Tree0" ) return OBJECT_TREE0; + if(value == "Tree1" ) return OBJECT_TREE1; + if(value == "Tree2" ) return OBJECT_TREE2; + if(value == "Tree3" ) return OBJECT_TREE3; + if(value == "Tree4" ) return OBJECT_TREE4; + if(value == "Tree5" ) return OBJECT_TREE5; + if(value == "Mushroom1" ) return OBJECT_MUSHROOM1; + if(value == "Mushroom2" ) return OBJECT_MUSHROOM2; + if(value == "Home" ) return OBJECT_HOME1; + if(value == "Derrick" ) return OBJECT_DERRICK; + if(value == "BotFactory" ) return OBJECT_FACTORY; + if(value == "PowerStation" ) return OBJECT_STATION; + if(value == "Converter" ) return OBJECT_CONVERT; + if(value == "RepairCenter" ) return OBJECT_REPAIR; + if(value == "Destroyer" ) return OBJECT_DESTROYER; + if(value == "DefenseTower" ) return OBJECT_TOWER; + if(value == "AlienNest" ) return OBJECT_NEST; + if(value == "ResearchCenter" ) return OBJECT_RESEARCH; + if(value == "RadarStation" ) return OBJECT_RADAR; + if(value == "ExchangePost" ) return OBJECT_INFO; + if(value == "PowerPlant" ) return OBJECT_ENERGY; + if(value == "AutoLab" ) return OBJECT_LABO; + if(value == "NuclearPlant" ) return OBJECT_NUCLEAR; + if(value == "PowerCaptor" ) return OBJECT_PARA; + if(value == "Vault" ) return OBJECT_SAFE; + if(value == "Houston" ) return OBJECT_HUSTON; + if(value == "Target1" ) return OBJECT_TARGET1; + if(value == "Target2" ) return OBJECT_TARGET2; + if(value == "StartArea" ) return OBJECT_START; + if(value == "GoalArea" ) return OBJECT_END; + if(value == "AlienQueen" ) return OBJECT_MOTHER; + if(value == "AlienEgg" ) return OBJECT_EGG; + if(value == "AlienAnt" ) return OBJECT_ANT; + if(value == "AlienSpider" ) return OBJECT_SPIDER; + if(value == "AlienWasp" ) return OBJECT_BEE; + if(value == "AlienWorm" ) return OBJECT_WORM; + if(value == "WreckBotw1" ) return OBJECT_RUINmobilew1; + if(value == "WreckBotw2" ) return OBJECT_RUINmobilew2; + if(value == "WreckBott1" ) return OBJECT_RUINmobilet1; + if(value == "WreckBott2" ) return OBJECT_RUINmobilet2; + if(value == "WreckBotr1" ) return OBJECT_RUINmobiler1; + if(value == "WreckBotr2" ) return OBJECT_RUINmobiler2; + if(value == "RuinBotFactory" ) return OBJECT_RUINfactory; + if(value == "RuinDoor" ) return OBJECT_RUINdoor; + if(value == "RuinSupport" ) return OBJECT_RUINsupport; + if(value == "RuinRadar" ) return OBJECT_RUINradar; + if(value == "RuinConvert" ) return OBJECT_RUINconvert; + if(value == "RuinBaseCamp" ) return OBJECT_RUINbase; + if(value == "RuinHeadCamp" ) return OBJECT_RUINhead; + if(value == "Barrier0" ) return OBJECT_BARRIER0; + if(value == "Barrier1" ) return OBJECT_BARRIER1; + if(value == "Barrier2" ) return OBJECT_BARRIER2; + if(value == "Barrier3" ) return OBJECT_BARRIER3; + if(value == "Teen0" ) return OBJECT_TEEN0; + if(value == "Teen1" ) return OBJECT_TEEN1; + if(value == "Teen2" ) return OBJECT_TEEN2; + if(value == "Teen3" ) return OBJECT_TEEN3; + if(value == "Teen4" ) return OBJECT_TEEN4; + if(value == "Teen5" ) return OBJECT_TEEN5; + if(value == "Teen6" ) return OBJECT_TEEN6; + if(value == "Teen7" ) return OBJECT_TEEN7; + if(value == "Teen8" ) return OBJECT_TEEN8; + if(value == "Teen9" ) return OBJECT_TEEN9; + if(value == "Teen10" ) return OBJECT_TEEN10; + if(value == "Teen11" ) return OBJECT_TEEN11; + if(value == "Teen12" ) return OBJECT_TEEN12; + if(value == "Teen13" ) return OBJECT_TEEN13; + if(value == "Teen14" ) return OBJECT_TEEN14; + if(value == "Teen15" ) return OBJECT_TEEN15; + if(value == "Teen16" ) return OBJECT_TEEN16; + if(value == "Teen17" ) return OBJECT_TEEN17; + if(value == "Teen18" ) return OBJECT_TEEN18; + if(value == "Teen19" ) return OBJECT_TEEN19; + if(value == "Teen20" ) return OBJECT_TEEN20; + if(value == "Teen21" ) return OBJECT_TEEN21; + if(value == "Teen22" ) return OBJECT_TEEN22; + if(value == "Teen23" ) return OBJECT_TEEN23; + if(value == "Teen24" ) return OBJECT_TEEN24; + if(value == "Teen25" ) return OBJECT_TEEN25; + if(value == "Teen26" ) return OBJECT_TEEN26; + if(value == "Teen27" ) return OBJECT_TEEN27; + if(value == "Teen28" ) return OBJECT_TEEN28; + if(value == "Teen29" ) return OBJECT_TEEN29; + if(value == "Teen30" ) return OBJECT_TEEN30; + if(value == "Teen31" ) return OBJECT_TEEN31; + if(value == "Teen32" ) return OBJECT_TEEN32; + if(value == "Teen33" ) return OBJECT_TEEN33; + if(value == "Stone" ) return OBJECT_TEEN34; + if(value == "Teen35" ) return OBJECT_TEEN35; + if(value == "Teen36" ) return OBJECT_TEEN36; + if(value == "Teen37" ) return OBJECT_TEEN37; + if(value == "Teen38" ) return OBJECT_TEEN38; + if(value == "Teen39" ) return OBJECT_TEEN39; + if(value == "Teen40" ) return OBJECT_TEEN40; + if(value == "Teen41" ) return OBJECT_TEEN41; + if(value == "Teen42" ) return OBJECT_TEEN42; + if(value == "Teen43" ) return OBJECT_TEEN43; + if(value == "Teen44" ) return OBJECT_TEEN44; + if(value == "Quartz0" ) return OBJECT_QUARTZ0; + if(value == "Quartz1" ) return OBJECT_QUARTZ1; + if(value == "Quartz2" ) return OBJECT_QUARTZ2; + if(value == "Quartz3" ) return OBJECT_QUARTZ3; + if(value == "MegaStalk0" ) return OBJECT_ROOT0; + if(value == "MegaStalk1" ) return OBJECT_ROOT1; + if(value == "MegaStalk2" ) return OBJECT_ROOT2; + if(value == "MegaStalk3" ) return OBJECT_ROOT3; + if(value == "MegaStalk4" ) return OBJECT_ROOT4; + if(value == "MegaStalk5" ) return OBJECT_ROOT5; + if(value == "ApolloLEM" ) return OBJECT_APOLLO1; + if(value == "ApolloJeep" ) return OBJECT_APOLLO2; + if(value == "ApolloFlag" ) return OBJECT_APOLLO3; + if(value == "ApolloModule" ) return OBJECT_APOLLO4; + if(value == "ApolloAntenna" ) return OBJECT_APOLLO5; + if(value == "Me" ) return OBJECT_HUMAN; + if(value == "Tech" ) return OBJECT_TECH; + if(value == "MissionController" ) return OBJECT_CONTROLLER; + return static_cast(Cast(value, "object")); +} + +const std::string CLevelParserParam::FromObjectType(ObjectType value) +{ + if(value == OBJECT_PORTICO ) return "Portico"; + if(value == OBJECT_BASE ) return "SpaceShip"; + if(value == OBJECT_MOBILEwt ) return "PracticeBot"; + if(value == OBJECT_MOBILEfa ) return "WingedGrabber"; + if(value == OBJECT_MOBILEta ) return "TrackedGrabber"; + if(value == OBJECT_MOBILEwa ) return "WheeledGrabber"; + if(value == OBJECT_MOBILEia ) return "LeggedGrabber"; + if(value == OBJECT_MOBILEfc ) return "WingedShooter"; + if(value == OBJECT_MOBILEtc ) return "TrackedShooter"; + if(value == OBJECT_MOBILEwc ) return "WheeledShooter"; + if(value == OBJECT_MOBILEic ) return "LeggedShooter"; + if(value == OBJECT_MOBILEfi ) return "WingedOrgaShooter"; + if(value == OBJECT_MOBILEti ) return "TrackedOrgaShooter"; + if(value == OBJECT_MOBILEwi ) return "WheeledOrgaShooter"; + if(value == OBJECT_MOBILEii ) return "LeggedOrgaShooter"; + if(value == OBJECT_MOBILEfs ) return "WingedSniffer"; + if(value == OBJECT_MOBILEts ) return "TrackedSniffer"; + if(value == OBJECT_MOBILEws ) return "WheeledSniffer"; + if(value == OBJECT_MOBILEis ) return "LeggedSniffer"; + if(value == OBJECT_MOBILErt ) return "Thumper"; + if(value == OBJECT_MOBILErc ) return "PhazerShooter"; + if(value == OBJECT_MOBILErr ) return "Recycler"; + if(value == OBJECT_MOBILErs ) return "Shielder"; + if(value == OBJECT_MOBILEsa ) return "Subber"; + if(value == OBJECT_MOBILEtg ) return "TargetBot"; + if(value == OBJECT_MOBILEdr ) return "Scribbler"; + if(value == OBJECT_MARKPOWER ) return "PowerSpot"; + if(value == OBJECT_MARKSTONE ) return "TitaniumSpot"; + if(value == OBJECT_MARKURANIUM ) return "UraniumSpot"; + if(value == OBJECT_MARKKEYa ) return "KeyASpot"; + if(value == OBJECT_MARKKEYb ) return "KeyBSpot"; + if(value == OBJECT_MARKKEYc ) return "KeyCSpot"; + if(value == OBJECT_MARKKEYd ) return "KeyDSpot"; + if(value == OBJECT_WAYPOINT ) return "WayPoint"; + if(value == OBJECT_FLAGb ) return "BlueFlag"; + if(value == OBJECT_FLAGr ) return "RedFlag"; + if(value == OBJECT_FLAGg ) return "GreenFlag"; + if(value == OBJECT_FLAGy ) return "YellowFlag"; + if(value == OBJECT_FLAGv ) return "VioletFlag"; + if(value == OBJECT_POWER ) return "PowerCell"; + if(value == OBJECT_ATOMIC ) return "NuclearCell"; + if(value == OBJECT_STONE ) return "TitaniumOre"; + if(value == OBJECT_URANIUM ) return "UraniumOre"; + if(value == OBJECT_METAL ) return "Titanium"; + if(value == OBJECT_BULLET ) return "OrgaMatter"; + if(value == OBJECT_BBOX ) return "BlackBox"; + if(value == OBJECT_KEYa ) return "KeyA"; + if(value == OBJECT_KEYb ) return "KeyB"; + if(value == OBJECT_KEYc ) return "KeyC"; + if(value == OBJECT_KEYd ) return "KeyD"; + if(value == OBJECT_TNT ) return "TNT"; + if(value == OBJECT_SCRAP1 ) return "Scrap1"; + if(value == OBJECT_SCRAP2 ) return "Scrap2"; + if(value == OBJECT_SCRAP3 ) return "Scrap3"; + if(value == OBJECT_SCRAP4 ) return "Scrap4"; + if(value == OBJECT_SCRAP5 ) return "Scrap5"; + if(value == OBJECT_BOMB ) return "Mine"; + if(value == OBJECT_WINFIRE ) return "Firework"; + if(value == OBJECT_BAG ) return "Bag"; + if(value == OBJECT_PLANT0 ) return "Greenery0"; + if(value == OBJECT_PLANT1 ) return "Greenery1"; + if(value == OBJECT_PLANT2 ) return "Greenery2"; + if(value == OBJECT_PLANT3 ) return "Greenery3"; + if(value == OBJECT_PLANT4 ) return "Greenery4"; + if(value == OBJECT_PLANT5 ) return "Greenery5"; + if(value == OBJECT_PLANT6 ) return "Greenery6"; + if(value == OBJECT_PLANT7 ) return "Greenery7"; + if(value == OBJECT_PLANT8 ) return "Greenery8"; + if(value == OBJECT_PLANT9 ) return "Greenery9"; + if(value == OBJECT_PLANT10 ) return "Greenery10"; + if(value == OBJECT_PLANT11 ) return "Greenery11"; + if(value == OBJECT_PLANT12 ) return "Greenery12"; + if(value == OBJECT_PLANT13 ) return "Greenery13"; + if(value == OBJECT_PLANT14 ) return "Greenery14"; + if(value == OBJECT_PLANT15 ) return "Greenery15"; + if(value == OBJECT_PLANT16 ) return "Greenery16"; + if(value == OBJECT_PLANT17 ) return "Greenery17"; + if(value == OBJECT_PLANT18 ) return "Greenery18"; + if(value == OBJECT_PLANT19 ) return "Greenery19"; + if(value == OBJECT_TREE0 ) return "Tree0"; + if(value == OBJECT_TREE1 ) return "Tree1"; + if(value == OBJECT_TREE2 ) return "Tree2"; + if(value == OBJECT_TREE3 ) return "Tree3"; + if(value == OBJECT_TREE4 ) return "Tree4"; + if(value == OBJECT_TREE5 ) return "Tree5"; + if(value == OBJECT_MUSHROOM1 ) return "Mushroom1"; + if(value == OBJECT_MUSHROOM2 ) return "Mushroom2"; + if(value == OBJECT_HOME1 ) return "Home"; + if(value == OBJECT_DERRICK ) return "Derrick"; + if(value == OBJECT_FACTORY ) return "BotFactory"; + if(value == OBJECT_STATION ) return "PowerStation"; + if(value == OBJECT_CONVERT ) return "Converter"; + if(value == OBJECT_REPAIR ) return "RepairCenter"; + if(value == OBJECT_DESTROYER ) return "Destroyer"; + if(value == OBJECT_TOWER ) return "DefenseTower"; + if(value == OBJECT_NEST ) return "AlienNest"; + if(value == OBJECT_RESEARCH ) return "ResearchCenter"; + if(value == OBJECT_RADAR ) return "RadarStation"; + if(value == OBJECT_INFO ) return "ExchangePost"; + if(value == OBJECT_ENERGY ) return "PowerPlant"; + if(value == OBJECT_LABO ) return "AutoLab"; + if(value == OBJECT_NUCLEAR ) return "NuclearPlant"; + if(value == OBJECT_PARA ) return "PowerCaptor"; + if(value == OBJECT_SAFE ) return "Vault"; + if(value == OBJECT_HUSTON ) return "Houston"; + if(value == OBJECT_TARGET1 ) return "Target1"; + if(value == OBJECT_TARGET2 ) return "Target2"; + if(value == OBJECT_START ) return "StartArea"; + if(value == OBJECT_END ) return "GoalArea"; + if(value == OBJECT_MOTHER ) return "AlienQueen"; + if(value == OBJECT_EGG ) return "AlienEgg"; + if(value == OBJECT_ANT ) return "AlienAnt"; + if(value == OBJECT_SPIDER ) return "AlienSpider"; + if(value == OBJECT_BEE ) return "AlienWasp"; + if(value == OBJECT_WORM ) return "AlienWorm"; + if(value == OBJECT_RUINmobilew1) return "WreckBotw1"; + if(value == OBJECT_RUINmobilew2) return "WreckBotw2"; + if(value == OBJECT_RUINmobilet1) return "WreckBott1"; + if(value == OBJECT_RUINmobilet2) return "WreckBott2"; + if(value == OBJECT_RUINmobiler1) return "WreckBotr1"; + if(value == OBJECT_RUINmobiler2) return "WreckBotr2"; + if(value == OBJECT_RUINfactory ) return "RuinBotFactory"; + if(value == OBJECT_RUINdoor ) return "RuinDoor"; + if(value == OBJECT_RUINsupport ) return "RuinSupport"; + if(value == OBJECT_RUINradar ) return "RuinRadar"; + if(value == OBJECT_RUINconvert ) return "RuinConvert"; + if(value == OBJECT_RUINbase ) return "RuinBaseCamp"; + if(value == OBJECT_RUINhead ) return "RuinHeadCamp"; + if(value == OBJECT_BARRIER0 ) return "Barrier0"; + if(value == OBJECT_BARRIER1 ) return "Barrier1"; + if(value == OBJECT_BARRIER2 ) return "Barrier2"; + if(value == OBJECT_BARRIER3 ) return "Barrier3"; + if(value == OBJECT_TEEN0 ) return "Teen0"; + if(value == OBJECT_TEEN1 ) return "Teen1"; + if(value == OBJECT_TEEN2 ) return "Teen2"; + if(value == OBJECT_TEEN3 ) return "Teen3"; + if(value == OBJECT_TEEN4 ) return "Teen4"; + if(value == OBJECT_TEEN5 ) return "Teen5"; + if(value == OBJECT_TEEN6 ) return "Teen6"; + if(value == OBJECT_TEEN7 ) return "Teen7"; + if(value == OBJECT_TEEN8 ) return "Teen8"; + if(value == OBJECT_TEEN9 ) return "Teen9"; + if(value == OBJECT_TEEN10 ) return "Teen10"; + if(value == OBJECT_TEEN11 ) return "Teen11"; + if(value == OBJECT_TEEN12 ) return "Teen12"; + if(value == OBJECT_TEEN13 ) return "Teen13"; + if(value == OBJECT_TEEN14 ) return "Teen14"; + if(value == OBJECT_TEEN15 ) return "Teen15"; + if(value == OBJECT_TEEN16 ) return "Teen16"; + if(value == OBJECT_TEEN17 ) return "Teen17"; + if(value == OBJECT_TEEN18 ) return "Teen18"; + if(value == OBJECT_TEEN19 ) return "Teen19"; + if(value == OBJECT_TEEN20 ) return "Teen20"; + if(value == OBJECT_TEEN21 ) return "Teen21"; + if(value == OBJECT_TEEN22 ) return "Teen22"; + if(value == OBJECT_TEEN23 ) return "Teen23"; + if(value == OBJECT_TEEN24 ) return "Teen24"; + if(value == OBJECT_TEEN25 ) return "Teen25"; + if(value == OBJECT_TEEN26 ) return "Teen26"; + if(value == OBJECT_TEEN27 ) return "Teen27"; + if(value == OBJECT_TEEN28 ) return "Teen28"; + if(value == OBJECT_TEEN29 ) return "Teen29"; + if(value == OBJECT_TEEN30 ) return "Teen30"; + if(value == OBJECT_TEEN31 ) return "Teen31"; + if(value == OBJECT_TEEN32 ) return "Teen32"; + if(value == OBJECT_TEEN33 ) return "Teen33"; + if(value == OBJECT_TEEN34 ) return "Stone"; + if(value == OBJECT_TEEN35 ) return "Teen35"; + if(value == OBJECT_TEEN36 ) return "Teen36"; + if(value == OBJECT_TEEN37 ) return "Teen37"; + if(value == OBJECT_TEEN38 ) return "Teen38"; + if(value == OBJECT_TEEN39 ) return "Teen39"; + if(value == OBJECT_TEEN40 ) return "Teen40"; + if(value == OBJECT_TEEN41 ) return "Teen41"; + if(value == OBJECT_TEEN42 ) return "Teen42"; + if(value == OBJECT_TEEN43 ) return "Teen43"; + if(value == OBJECT_TEEN44 ) return "Teen44"; + if(value == OBJECT_QUARTZ0 ) return "Quartz0"; + if(value == OBJECT_QUARTZ1 ) return "Quartz1"; + if(value == OBJECT_QUARTZ2 ) return "Quartz2"; + if(value == OBJECT_QUARTZ3 ) return "Quartz3"; + if(value == OBJECT_ROOT0 ) return "MegaStalk0"; + if(value == OBJECT_ROOT1 ) return "MegaStalk1"; + if(value == OBJECT_ROOT2 ) return "MegaStalk2"; + if(value == OBJECT_ROOT3 ) return "MegaStalk3"; + if(value == OBJECT_ROOT4 ) return "MegaStalk4"; + if(value == OBJECT_ROOT5 ) return "MegaStalk5"; + if(value == OBJECT_APOLLO1 ) return "ApolloLEM"; + if(value == OBJECT_APOLLO2 ) return "ApolloJeep"; + if(value == OBJECT_APOLLO3 ) return "ApolloFlag"; + if(value == OBJECT_APOLLO4 ) return "ApolloModule"; + if(value == OBJECT_APOLLO5 ) return "ApolloAntenna"; + if(value == OBJECT_HUMAN ) return "Me"; + if(value == OBJECT_TECH ) return "Tech"; + if(value == OBJECT_CONTROLLER ) return "MissionController"; + return std::to_string(static_cast(value)); +} + +ObjectType CLevelParserParam::AsObjectType() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return ToObjectType(m_value); +} + +ObjectType CLevelParserParam::AsObjectType(ObjectType def) +{ + if(m_empty) + return def; + return AsObjectType(); +} + + +DriveType CLevelParserParam::ToDriveType(std::string value) +{ + if(value == "Wheeled") return DRIVE_WHEELED; + if(value == "Tracked") return DRIVE_TRACKED; + if(value == "Winged" ) return DRIVE_WINGED; + if(value == "Legged" ) return DRIVE_LEGGED; + if(value == "Other" ) return DRIVE_OTHER; + return static_cast(Cast(value, "drive")); +} + +DriveType CLevelParserParam::AsDriveType() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return ToDriveType(m_value); +} + +DriveType CLevelParserParam::AsDriveType(DriveType def) +{ + if(m_empty) + return def; + return AsDriveType(); +} + + +ToolType CLevelParserParam::ToToolType(std::string value) +{ + if(value == "Grabber" ) return TOOL_GRABBER; + if(value == "Shiffer" ) return TOOL_SNIFFER; + if(value == "Shooter" ) return TOOL_SHOOTER; + if(value == "OrgaShooter") return TOOL_ORGASHOOTER; + if(value == "Other" ) return TOOL_OTHER; + return static_cast(Cast(value, "tool")); +} + +ToolType CLevelParserParam::AsToolType() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return ToToolType(m_value); +} + +ToolType CLevelParserParam::AsToolType(ToolType def) +{ + if(m_empty) + return def; + return AsToolType(); +} + + +Gfx::WaterType CLevelParserParam::ToWaterType(std::string value) +{ + if(value == "NULL") return Gfx::WATER_NULL; + if(value == "TT" ) return Gfx::WATER_TT; + if(value == "TO" ) return Gfx::WATER_TO; + if(value == "CT" ) return Gfx::WATER_CT; + if(value == "CO" ) return Gfx::WATER_CO; + return static_cast(Cast(value, "watertype")); +} + +Gfx::WaterType CLevelParserParam::AsWaterType() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return ToWaterType(m_value); +} + +Gfx::WaterType CLevelParserParam::AsWaterType(Gfx::WaterType def) +{ + if(m_empty) + return def; + return AsWaterType(); +} + + +Gfx::EngineObjectType CLevelParserParam::ToTerrainType(std::string value) +{ + if(value == "Terrain") return Gfx::ENG_OBJTYPE_TERRAIN; + if(value == "Object" ) return Gfx::ENG_OBJTYPE_FIX; + if(value == "Quartz" ) return Gfx::ENG_OBJTYPE_QUARTZ; + if(value == "Metal" ) return Gfx::ENG_OBJTYPE_METAL; + return static_cast(Cast(value, "terraintype")); +} + +Gfx::EngineObjectType CLevelParserParam::AsTerrainType() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return ToTerrainType(m_value); +} + +Gfx::EngineObjectType CLevelParserParam::AsTerrainType(Gfx::EngineObjectType def) +{ + if(m_empty) + return def; + return AsTerrainType(); +} + + +int CLevelParserParam::ToBuildFlag(std::string value) +{ + if(value == "BotFactory" ) return BUILD_FACTORY; + if(value == "Derrick" ) return BUILD_DERRICK; + if(value == "Converter" ) return BUILD_CONVERT; + if(value == "RadarStation" ) return BUILD_RADAR; + if(value == "PowerPlant" ) return BUILD_ENERGY; + if(value == "NuclearPlant" ) return BUILD_NUCLEAR; + if(value == "FuelCellPlant" ) return BUILD_NUCLEAR; + if(value == "PowerStation" ) return BUILD_STATION; + if(value == "RepairCenter" ) return BUILD_REPAIR; + if(value == "DefenseTower" ) return BUILD_TOWER; + if(value == "ResearchCenter") return BUILD_RESEARCH; + if(value == "AutoLab" ) return BUILD_LABO; + if(value == "PowerCaptor" ) return BUILD_PARA; + if(value == "ExchangePost" ) return BUILD_INFO; + if(value == "Destroyer" ) return BUILD_DESTROYER; + if(value == "FlatGround" ) return BUILD_GFLAT; + if(value == "Flag" ) return BUILD_FLAG; + return Cast(value, "buildflag"); +} + +int CLevelParserParam::AsBuildFlag() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return ToBuildFlag(m_value); +} + +int CLevelParserParam::AsBuildFlag(int def) +{ + if(m_empty) + return def; + return AsBuildFlag(); +} + + +int CLevelParserParam::ToResearchFlag(std::string value) +{ + if(value == "TRACKER" ) return RESEARCH_TANK; + if(value == "WINGER" ) return RESEARCH_FLY; + if(value == "THUMPER" ) return RESEARCH_THUMP; + if(value == "SHOOTER" ) return RESEARCH_CANON; + if(value == "TOWER" ) return RESEARCH_TOWER; + if(value == "PHAZER" ) return RESEARCH_PHAZER; + if(value == "SHIELDER") return RESEARCH_SHIELD; + if(value == "ATOMIC" ) return RESEARCH_ATOMIC; + if(value == "iPAW" ) return RESEARCH_iPAW; + if(value == "iGUN" ) return RESEARCH_iGUN; + if(value == "RECYCLER") return RESEARCH_RECYCLER; + if(value == "SUBBER" ) return RESEARCH_SUBM; + if(value == "SNIFFER" ) return RESEARCH_SNIFFER; + return Cast(value, "researchflag"); +} + +int CLevelParserParam::AsResearchFlag() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return ToResearchFlag(m_value); +} + +int CLevelParserParam::AsResearchFlag(int def) +{ + if(m_empty) + return def; + return AsResearchFlag(); +} + + +Gfx::PyroType CLevelParserParam::ToPyroType(std::string value) +{ + if(value == "FRAGt" ) return Gfx::PT_FRAGT; + if(value == "FRAGo" ) return Gfx::PT_FRAGO; + if(value == "FRAGw" ) return Gfx::PT_FRAGW; + if(value == "EXPLOt") return Gfx::PT_EXPLOT; + if(value == "EXPLOo") return Gfx::PT_EXPLOO; + if(value == "EXPLOw") return Gfx::PT_EXPLOW; + if(value == "SHOTt" ) return Gfx::PT_SHOTT; + if(value == "SHOTh" ) return Gfx::PT_SHOTH; + if(value == "SHOTm" ) return Gfx::PT_SHOTM; + if(value == "SHOTw" ) return Gfx::PT_SHOTW; + if(value == "EGG" ) return Gfx::PT_EGG; + if(value == "BURNt" ) return Gfx::PT_BURNT; + if(value == "BURNo" ) return Gfx::PT_BURNO; + if(value == "SPIDER") return Gfx::PT_SPIDER; + if(value == "FALL" ) return Gfx::PT_FALL; + if(value == "RESET" ) return Gfx::PT_RESET; + if(value == "WIN" ) return Gfx::PT_WIN; + if(value == "LOST" ) return Gfx::PT_LOST; + return static_cast(Cast(value, "pyrotype")); +} + +Gfx::PyroType CLevelParserParam::AsPyroType() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return ToPyroType(m_value); +} + +Gfx::PyroType CLevelParserParam::AsPyroType(Gfx::PyroType def) +{ + if(m_empty) + return def; + return AsPyroType(); +} + + +Gfx::CameraType CLevelParserParam::ToCameraType(std::string value) +{ + if(value == "BACK" ) return Gfx::CAM_TYPE_BACK; + if(value == "PLANE" ) return Gfx::CAM_TYPE_PLANE; + if(value == "ONBOARD") return Gfx::CAM_TYPE_ONBOARD; + if(value == "FIX" ) return Gfx::CAM_TYPE_FIX; + return static_cast(Cast(value, "camera")); +} + +const std::string CLevelParserParam::FromCameraType(Gfx::CameraType value) +{ + if(value == Gfx::CAM_TYPE_ONBOARD) return "ONBOARD"; + if(value == Gfx::CAM_TYPE_FIX ) return "FIX"; + return std::to_string(static_cast(value)); +} + +Gfx::CameraType CLevelParserParam::AsCameraType() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + return ToCameraType(m_value); +} + +Gfx::CameraType CLevelParserParam::AsCameraType(Gfx::CameraType def) +{ + if(m_empty) + return def; + return AsCameraType(); +} + + +void CLevelParserParam::ParseArray() +{ + if(m_array.size() != 0) + return; + + std::vector values; + boost::split(values, m_value, boost::is_any_of(";")); + int i = 0; + for(auto& value : values) { + boost::algorithm::trim(value); + if(value.empty()) continue; + CLevelParserParam* param = new CLevelParserParam(m_name+"["+std::to_string(i)+"]", value); + param->SetLine(m_line); + m_array.push_back(param); + i++; + } +} + +const std::vector& CLevelParserParam::AsArray() +{ + if(m_empty) + throw CLevelParserExceptionMissingParam(this); + + ParseArray(); + + return m_array; +} \ No newline at end of file diff --git a/src/object/level/parserparam.h b/src/object/level/parserparam.h new file mode 100644 index 00000000..9d5ba99d --- /dev/null +++ b/src/object/level/parserparam.h @@ -0,0 +1,133 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * 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://www.gnu.org/licenses/. + +/** + * \file object/level/parserparam.h + * \brief Value of command argument in level file + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +class CLevelParserLine; + +class CLevelParserParam +{ +public: + //! Create param with given value + //@{ + CLevelParserParam(int value); + CLevelParserParam(float value); + CLevelParserParam(std::string value); + CLevelParserParam(bool value); + CLevelParserParam(Gfx::Color value); + CLevelParserParam(Math::Point value); + CLevelParserParam(ObjectType value); + CLevelParserParam(Gfx::CameraType value); + CLevelParserParam(const std::vector& value); + //@} + //! Create param from string + CLevelParserParam(std::string name, std::string value); + //! Create empty parser param + CLevelParserParam(std::string name, bool empty); + + ~CLevelParserParam(); + + //! Get value (throws exception if not found or unable to process) + //@{ + int AsInt(); + float AsFloat(); + std::string AsString(); + bool AsBool(); + std::string AsPath(const std::string defaultDir); + Gfx::Color AsColor(); + Math::Vector AsPoint(); + ObjectType AsObjectType(); + DriveType AsDriveType(); + ToolType AsToolType(); + Gfx::WaterType AsWaterType(); + Gfx::EngineObjectType AsTerrainType(); + int AsBuildFlag(); + int AsResearchFlag(); + Gfx::PyroType AsPyroType(); + Gfx::CameraType AsCameraType(); + const std::vector& AsArray(); + //@} + + //! Get value (returns default if not found, throws exception if unable to process) + //@{ + int AsInt(int def); + float AsFloat(float def); + std::string AsString(std::string def); + bool AsBool(bool def); + std::string AsPath(const std::string defaultDir, std::string def); + Gfx::Color AsColor(Gfx::Color def); + Math::Vector AsPoint(Math::Vector def); + ObjectType AsObjectType(ObjectType def); + DriveType AsDriveType(DriveType def); + ToolType AsToolType(ToolType def); + Gfx::WaterType AsWaterType(Gfx::WaterType def); + Gfx::EngineObjectType AsTerrainType(Gfx::EngineObjectType def); + int AsBuildFlag(int def); + int AsResearchFlag(int def); + Gfx::PyroType AsPyroType(Gfx::PyroType def); + Gfx::CameraType AsCameraType(Gfx::CameraType def); + //@} + + //! Set line this param is part of + void SetLine(CLevelParserLine* line); + //! Get line this param is part of + CLevelParserLine* GetLine(); + + std::string GetName(); + std::string GetValue(); + bool IsDefined(); + +private: + void ParseArray(); + + template T Cast(std::string value, std::string requestedType); + template T Cast(std::string requestedType); + + std::string InjectLevelDir(std::string path, const std::string defaultDir); + + ObjectType ToObjectType(std::string value); + DriveType ToDriveType(std::string value); + ToolType ToToolType(std::string value); + Gfx::WaterType ToWaterType(std::string value); + Gfx::EngineObjectType ToTerrainType(std::string value); + int ToBuildFlag(std::string value); + int ToResearchFlag(std::string value); + Gfx::PyroType ToPyroType(std::string value); + Gfx::CameraType ToCameraType(std::string value); + + const std::string FromObjectType(ObjectType value); + const std::string FromCameraType(Gfx::CameraType value); + +private: + CLevelParserLine* m_line; + bool m_empty; + std::string m_name; + std::string m_value; + std::vector m_array; +}; \ No newline at end of file diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp index 407a1ec3..ce7f8d01 100644 --- a/src/object/robotmain.cpp +++ b/src/object/robotmain.cpp @@ -58,6 +58,7 @@ #include "object/task/task.h" #include "object/task/taskbuild.h" #include "object/task/taskmanip.h" +#include "object/level/parser.h" #include "physics/physics.h" @@ -83,7 +84,7 @@ #include -#include +#include template<> CRobotMain* CSingleton::m_instance = nullptr; @@ -1208,18 +1209,27 @@ void CRobotMain::ChangePhase(Phase phase) bool loading = (m_dialog->GetSceneRead()[0] != 0); m_map->CreateMap(); - CreateScene(m_dialog->GetSceneSoluce(), false, false); // interactive scene - if (m_mapImage) - m_map->SetFixImage(m_mapFilename); + + try { + CreateScene(m_dialog->GetSceneSoluce(), false, false); // interactive scene + if (m_mapImage) + m_map->SetFixImage(m_mapFilename); - m_app->ResetTimeAfterLoading(); + m_app->ResetTimeAfterLoading(); - if (m_immediatSatCom && !loading && - m_infoFilename[SATCOM_HUSTON][0] != 0) - StartDisplayInfo(SATCOM_HUSTON, false); // shows the instructions + if (m_immediatSatCom && !loading && + m_infoFilename[SATCOM_HUSTON][0] != 0) + StartDisplayInfo(SATCOM_HUSTON, false); // shows the instructions - m_sound->StopMusic(0.0f); - if (!m_base || loading) StartMusic(); + m_sound->StopMusic(0.0f); + if (!m_base || loading) StartMusic(); + } + catch(const CLevelParserException& e) + { + CLogger::GetInstancePointer()->Error("An error occured while trying to load a level\n"); + CLogger::GetInstancePointer()->Error("%s\n", e.what()); + ChangePhase(PHASE_INIT); + } } if (m_phase == PHASE_WIN) @@ -1235,29 +1245,37 @@ void CRobotMain::ChangePhase(Phase phase) m_dialog->SetSceneName("win"); m_dialog->SetSceneRank(m_endingWinRank); - CreateScene(false, true, false); // sets scene + try { + CreateScene(false, true, false); // sets scene - pos.x = ox+sx*1; pos.y = oy+sy*1; - Math::Point ddim; - ddim.x = dim.x*2; ddim.y = dim.y*2; - m_interface->CreateButton(pos, ddim, 16, EVENT_BUTTON_OK); + pos.x = ox+sx*1; pos.y = oy+sy*1; + Math::Point ddim; + ddim.x = dim.x*2; ddim.y = dim.y*2; + m_interface->CreateButton(pos, ddim, 16, EVENT_BUTTON_OK); - if (m_winTerminate) - { - pos.x = ox+sx*3; pos.y = oy+sy*0.2f; - ddim.x = dim.x*15; ddim.y = dim.y*3.0f; - pe = m_interface->CreateEdit(pos, ddim, 0, EVENT_EDIT0); - pe->SetGenericMode(true); - pe->SetFontType(Gfx::FONT_COLOBOT); - pe->SetEditCap(false); - pe->SetHighlightCap(false); - pe->ReadText(std::string("help/") + m_app->GetLanguageChar() + std::string("/win.txt")); + if (m_winTerminate) + { + pos.x = ox+sx*3; pos.y = oy+sy*0.2f; + ddim.x = dim.x*15; ddim.y = dim.y*3.0f; + pe = m_interface->CreateEdit(pos, ddim, 0, EVENT_EDIT0); + pe->SetGenericMode(true); + pe->SetFontType(Gfx::FONT_COLOBOT); + pe->SetEditCap(false); + pe->SetHighlightCap(false); + pe->ReadText(std::string("help/") + m_app->GetLanguageChar() + std::string("/win.txt")); + } + else + { + m_displayText->DisplayError(INFO_WIN, Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f); + } + StartMusic(); } - else + catch(const CLevelParserException& e) { - m_displayText->DisplayError(INFO_WIN, Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f); + CLogger::GetInstancePointer()->Error("An error occured while trying to load win scene\n"); + CLogger::GetInstancePointer()->Error("%s\n", e.what()); + ChangePhase(PHASE_TERM); } - StartMusic(); } } @@ -1273,15 +1291,23 @@ void CRobotMain::ChangePhase(Phase phase) m_winTerminate = false; m_dialog->SetSceneName("lost"); m_dialog->SetSceneRank(m_endingLostRank); - CreateScene(false, true, false); // sets scene + try { + CreateScene(false, true, false); // sets scene - pos.x = ox+sx*1; pos.y = oy+sy*1; - Math::Point ddim; - ddim.x = dim.x*2; ddim.y = dim.y*2; - m_interface->CreateButton(pos, ddim, 16, EVENT_BUTTON_OK); - m_displayText->DisplayError(INFO_LOST, Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f); + pos.x = ox+sx*1; pos.y = oy+sy*1; + Math::Point ddim; + ddim.x = dim.x*2; ddim.y = dim.y*2; + m_interface->CreateButton(pos, ddim, 16, EVENT_BUTTON_OK); + m_displayText->DisplayError(INFO_LOST, Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f); - StartMusic(); + StartMusic(); + } + catch(const CLevelParserException& e) + { + CLogger::GetInstancePointer()->Error("An error occured while trying to load lost scene\n"); + CLogger::GetInstancePointer()->Error("%s\n", e.what()); + ChangePhase(PHASE_TERM); + } } } @@ -3819,7 +3845,14 @@ void CRobotMain::ScenePerso() m_dialog->SetSceneName("perso"); m_dialog->SetSceneRank(0); - CreateScene(false, true, false); // sets scene + try { + CreateScene(false, true, false); // sets scene + } + catch(const CLevelParserException& e) + { + CLogger::GetInstancePointer()->Error("An error occured while trying to load apperance scene\n"); + CLogger::GetInstancePointer()->Error("%s\n", e.what()); + } m_engine->SetDrawWorld(false); // does not draw anything on the interface m_engine->SetDrawFront(true); // draws on the human interface @@ -3924,27 +3957,9 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_missionResult = ERR_MISSION_NOTERM; } - - char line[500]; - char name[200]; - char dir[100]; - char op[100]; - char filename[500]; - int lineNum = 0; - - memset(line, 0, 500); - memset(name, 0, 200); - memset(dir, 0, 100); - memset(op, 0, 100); - memset(filename, 0, 500); - std::string tempLine; - m_dialog->BuildSceneName(tempLine, base, rank); - strcpy(filename, tempLine.c_str()); - CInputStream stream; - stream.open(filename); - - if (!stream.is_open()) return; + CLevelParser* level = new CLevelParser(base, rank/100, rank%100); + level->Load(); int rankObj = 0; int rankGadget = 0; @@ -3957,584 +3972,445 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) * may speed up loading */ - while (stream.getline(line, 500)) + for(auto& line : level->GetLines()) { - lineNum++; - for (int i = 0; i < 500; i++) + if (line->GetCommand() == "MissionFile" && !resetObject) { - if (line[i] == '\t' ) line[i] = ' '; // replace tab by space - if (line[i] == '/' && line[i+1] == '/') - { - line[i] = 0; - break; - } - } - - if (Cmd(line, "MissionFile") && !resetObject) { - m_version = OpInt(line, "version", 1); - continue; - } - - // TODO: Fallback to an non-localized entry - sprintf(op, "Title.%c", m_app->GetLanguageChar()); - if (Cmd(line, op) && !resetObject) - { - OpString(line, "text", m_title); + m_version = line->GetParam("version")->AsInt(1); continue; } - - sprintf(op, "Resume.%c", m_app->GetLanguageChar()); - if (Cmd(line, op) && !resetObject) + + if(line->GetCommand() == "Title" && !resetObject) { - OpString(line, "text", m_resume); + strcpy(m_title, line->GetParam("text")->AsString().c_str()); continue; } - - sprintf(op, "ScriptName.%c", m_app->GetLanguageChar()); - if (Cmd(line, op) && !resetObject) + + if(line->GetCommand() == "Resume" && !resetObject) { - OpString(line, "text", m_scriptName); + strcpy(m_resume, line->GetParam("text")->AsString().c_str()); continue; } - - static const boost::regex titleCmdRe("Title\\.[A-Z]"); - static const boost::regex resumeCmdRe("Resume\\.[A-Z]"); - static const boost::regex scriptNameCmdRe("ScriptName\\.[A-Z]"); - - if (boost::regex_match(GetCmd(line), titleCmdRe)) continue; // Ignore - if (boost::regex_match(GetCmd(line), resumeCmdRe)) continue; // Ignore - if (boost::regex_match(GetCmd(line), scriptNameCmdRe)) continue; // Ignore - - - if (Cmd(line, "ScriptFile") && !resetObject) + + if(line->GetCommand() == "ScriptName" && !resetObject) { - OpString(line, "name", m_scriptFile); + strcpy(m_scriptName, line->GetParam("text")->AsString().c_str()); continue; } - - if (Cmd(line, "Instructions") && !resetObject) + + if (line->GetCommand() == "ScriptFile" && !resetObject) { - OpString(line, "name", name); - std::string path = name; - InjectLevelDir(path, "help/%lng%"); - strcpy(m_infoFilename[SATCOM_HUSTON], path.c_str()); - - m_immediatSatCom = OpInt(line, "immediat", 0); - if (m_version >= 2) m_beginSatCom = m_lockedSatCom = OpInt(line, "lock", 0); + strcpy(m_scriptFile, line->GetParam("name")->AsString().c_str()); + continue; + } + + if (line->GetCommand() == "Instructions" && !resetObject) + { + strcpy(m_infoFilename[SATCOM_HUSTON], line->GetParam("name")->AsPath("help/%lng%").c_str()); + + m_immediatSatCom = line->GetParam("immediat")->AsBool(false); + if (m_version >= 2) m_beginSatCom = m_lockedSatCom = line->GetParam("lock")->AsBool(false); if (m_app->GetSceneTestMode()) m_immediatSatCom = false; continue; } - - if (Cmd(line, "Satellite") && !resetObject) + + if (line->GetCommand() == "Satellite" && !resetObject) { - OpString(line, "name", name); - std::string path = name; - InjectLevelDir(path, "help/%lng%"); - strcpy(m_infoFilename[SATCOM_SAT], path.c_str()); + strcpy(m_infoFilename[SATCOM_SAT], line->GetParam("name")->AsPath("help/%lng%").c_str()); continue; } - - if (Cmd(line, "Loading") && !resetObject) + + if (line->GetCommand() == "Loading" && !resetObject) { - OpString(line, "name", name); - std::string path = name; - InjectLevelDir(path, "help/%lng%"); - strcpy(m_infoFilename[SATCOM_LOADING], path.c_str()); + strcpy(m_infoFilename[SATCOM_LOADING], line->GetParam("name")->AsPath("help/%lng%").c_str()); continue; } - - if (Cmd(line, "HelpFile") && !resetObject) + + if (line->GetCommand() == "HelpFile" && !resetObject) { - OpString(line, "name", name); - std::string path = name; - InjectLevelDir(path, "help/%lng%"); - strcpy(m_infoFilename[SATCOM_PROG], path.c_str()); + strcpy(m_infoFilename[SATCOM_PROG], line->GetParam("name")->AsPath("help/%lng%").c_str()); continue; } - if (Cmd(line, "SoluceFile") && !resetObject) + if (line->GetCommand() == "SoluceFile" && !resetObject) { - OpString(line, "name", name); - std::string path = name; - InjectLevelDir(path, "help/%lng%"); - strcpy(m_infoFilename[SATCOM_SOLUCE], path.c_str()); + strcpy(m_infoFilename[SATCOM_SOLUCE], line->GetParam("name")->AsPath("help/%lng%").c_str()); continue; } - - if (Cmd(line, "EndingFile") && !resetObject) + + if (line->GetCommand() == "EndingFile" && !resetObject) { - m_endingWinRank = OpInt(line, "win", 0); - m_endingLostRank = OpInt(line, "lost", 0); + // NOTE: The old default was 0, but I think -1 is more correct - 0 means "ending file 000", while -1 means "no ending file" + m_endingWinRank = line->GetParam("win")->AsInt(-1); + m_endingLostRank = line->GetParam("lost")->AsInt(-1); continue; } - - if (Cmd(line, "MessageDelay") && !resetObject) + + if (line->GetCommand() == "MessageDelay" && !resetObject) { - m_displayText->SetDelay(OpFloat(line, "factor", 1.0f)); + m_displayText->SetDelay(line->GetParam("factor")->AsFloat()); continue; } - - if (Cmd(line, "CacheAudio") && !resetObject && m_version >= 2) + + if (line->GetCommand() == "CacheAudio" && !resetObject && m_version >= 2) { - OpString(line, "filename", name); - m_sound->CacheMusic(name); + m_sound->CacheMusic(line->GetParam("filename")->AsPath("").c_str()); //TODO: don't make this relative to music/ continue; } - - if (Cmd(line, "AudioChange") && !resetObject && m_version >= 2 && m_controller == nullptr) + + if (line->GetCommand() == "AudioChange" && !resetObject && m_version >= 2 && m_controller == nullptr) { int i = m_audioChangeTotal; if (i < 10) { - m_audioChange[i].pos = OpPos(line, "pos")*g_unit; - m_audioChange[i].dist = OpFloat(line, "dist", 1000.0f)*g_unit; - m_audioChange[i].type = OpTypeObject(line, "type", OBJECT_NULL); - m_audioChange[i].min = OpInt(line, "min", 1); - m_audioChange[i].max = OpInt(line, "max", 9999); - m_audioChange[i].powermin = OpFloat(line, "powermin", -1); - m_audioChange[i].powermax = OpFloat(line, "powermax", 100); - m_audioChange[i].tool = OpTool(line, "tool"); - m_audioChange[i].drive = OpDrive(line, "drive"); - OpString(line, "filename", m_audioChange[i].music); - m_audioChange[i].repeat = OpInt(line, "repeat", 1); + m_audioChange[i].pos = line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit; + m_audioChange[i].dist = line->GetParam("dist")->AsFloat(1000.0f)*g_unit; + m_audioChange[i].type = line->GetParam("type")->AsObjectType(OBJECT_NULL); + m_audioChange[i].min = line->GetParam("min")->AsInt(1); + m_audioChange[i].max = line->GetParam("max")->AsInt(9999); + m_audioChange[i].powermin = line->GetParam("powermin")->AsFloat(-1); + m_audioChange[i].powermax = line->GetParam("powermax")->AsFloat(100); + m_audioChange[i].tool = line->GetParam("tool")->AsToolType(TOOL_OTHER); + m_audioChange[i].drive = line->GetParam("drive")->AsDriveType(DRIVE_OTHER); + strcpy(m_audioChange[i].music, line->GetParam("filename")->AsPath("").c_str()); //TODO: don't make this relative to music/ + m_audioChange[i].repeat = line->GetParam("repeat")->AsBool(true); m_audioChange[i].changed = false; m_sound->CacheMusic(m_audioChange[i].music); m_audioChangeTotal ++; } continue; } - - if (Cmd(line, "Audio") && !resetObject && m_controller == nullptr) + + if (line->GetCommand() == "Audio" && !resetObject && m_controller == nullptr) { if (m_version < 2) { - int trackid = OpInt(line, "track", 0); + int trackid = line->GetParam("track")->AsInt(); if (trackid != 0) { std::stringstream filenameStr; filenameStr << "music" << std::setfill('0') << std::setw(3) << trackid << ".ogg"; m_audioTrack = filenameStr.str(); } - m_audioRepeat = OpInt(line, "repeat", 1); + m_audioRepeat = line->GetParam("repeat")->AsBool(true); } else { - char trackname[100]; + m_audioTrack = line->GetParam("main")->AsPath("", ""); //TODO: don't make this relative to music/ + m_audioRepeat = line->GetParam("mainRepeat")->AsBool(true); - OpString(line, "main", trackname); - m_audioTrack = trackname; - m_audioRepeat = OpInt(line, "mainRepeat", 1); + m_satcomTrack = line->GetParam("satcom")->AsPath("", ""); //TODO: don't make this relative to music/ + m_satcomRepeat = line->GetParam("satcomRepeat")->AsBool(true); - OpString(line, "satcom", trackname); - m_satcomTrack = trackname; - m_satcomRepeat = OpInt(line, "satcomRepeat", 1); - - OpString(line, "editor", trackname); - m_editorTrack = trackname; - m_editorRepeat = OpInt(line, "editorRepeat", 1); + m_editorTrack = line->GetParam("editor")->AsPath("", ""); //TODO: don't make this relative to music/ + m_editorRepeat = line->GetParam("editorRepeat")->AsBool(true); } if (m_audioTrack != "") m_sound->CacheMusic(m_audioTrack); if (m_satcomTrack != "") m_sound->CacheMusic(m_satcomTrack); if (m_editorTrack != "") m_sound->CacheMusic(m_editorTrack); continue; } - - if (Cmd(line, "AmbientColor") && !resetObject) + + if (line->GetCommand() == "AmbientColor" && !resetObject) { - m_engine->SetAmbientColor(OpColor(line, "air", Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 0); - m_engine->SetAmbientColor(OpColor(line, "water", Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 1); + m_engine->SetAmbientColor(line->GetParam("air")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 0); + m_engine->SetAmbientColor(line->GetParam("water")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 1); continue; } - - if (Cmd(line, "FogColor") && !resetObject) + + if (line->GetCommand() == "FogColor" && !resetObject) { - m_engine->SetFogColor(OpColor(line, "air", Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 0); - m_engine->SetFogColor(OpColor(line, "water", Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 1); + m_engine->SetFogColor(line->GetParam("air")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 0); + m_engine->SetFogColor(line->GetParam("water")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 1); continue; } - - if (Cmd(line, "VehicleColor") && !resetObject) + + if (line->GetCommand() == "VehicleColor" && !resetObject) { - m_colorNewBot = OpColor(line, "color", Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)); + m_colorNewBot = line->GetParam("color")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)); continue; } - - if (Cmd(line, "InsectColor") && !resetObject) + + if (line->GetCommand() == "InsectColor" && !resetObject) { - m_colorNewAlien = OpColor(line, "color", Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)); + m_colorNewAlien = line->GetParam("color")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)); continue; } - - if (Cmd(line, "GreeneryColor") && !resetObject) + + if (line->GetCommand() == "GreeneryColor" && !resetObject) { - m_colorNewGreen = OpColor(line, "color", Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)); + m_colorNewGreen = line->GetParam("color")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)); continue; } - - if (Cmd(line, "DeepView") && !resetObject) + + if (line->GetCommand() == "DeepView" && !resetObject) { - m_engine->SetDeepView(OpFloat(line, "air", 500.0f)*g_unit, 0, true); - m_engine->SetDeepView(OpFloat(line, "water", 100.0f)*g_unit, 1, true); + m_engine->SetDeepView(line->GetParam("air")->AsFloat(500.0f)*g_unit, 0, true); + m_engine->SetDeepView(line->GetParam("water")->AsFloat(100.0f)*g_unit, 1, true); continue; } - - if (Cmd(line, "FogStart") && !resetObject) + + if (line->GetCommand() == "FogStart" && !resetObject) { - m_engine->SetFogStart(OpFloat(line, "air", 0.5f), 0); - m_engine->SetFogStart(OpFloat(line, "water", 0.5f), 1); + m_engine->SetFogStart(line->GetParam("air")->AsFloat(0.5f), 0); + m_engine->SetFogStart(line->GetParam("water")->AsFloat(0.5f), 1); continue; } - - if (Cmd(line, "SecondTexture") && !resetObject) + + if (line->GetCommand() == "SecondTexture" && !resetObject) { - m_engine->SetSecondTexture(OpInt(line, "rank", 1)); + m_engine->SetSecondTexture(line->GetParam("rank")->AsInt()); continue; } - - if (Cmd(line, "Background") && !resetObject) + + if (line->GetCommand() == "Background" && !resetObject) { - OpString(line, "image", name); - m_engine->SetBackground(name, - OpColor(line, "up", Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)), - OpColor(line, "down", Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)), - OpColor(line, "cloudUp", Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)), - OpColor(line, "cloudDown", Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)), - OpInt(line, "full", 0)); + m_engine->SetBackground(line->GetParam("image")->AsPath("", "").c_str(), //TODO: don't make this relative to textures/ + line->GetParam("up")->AsColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)), + line->GetParam("down")->AsColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)), + line->GetParam("cloudUp")->AsColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)), + line->GetParam("cloudDown")->AsColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)), + line->GetParam("full")->AsBool(false)); continue; } - - if (Cmd(line, "Planet") && !resetObject) + + if (line->GetCommand() == "Planet" && !resetObject) { Math::Vector ppos, uv1, uv2; - - ppos = OpPos(line, "pos"); - uv1 = OpPos(line, "uv1"); - uv2 = OpPos(line, "uv2"); - OpString(line, "image", name); - m_planet->Create(OpInt(line, "mode", 0), + + ppos = line->GetParam("pos")->AsPoint(); + uv1 = line->GetParam("uv1")->AsPoint(); + uv2 = line->GetParam("uv2")->AsPoint(); + m_planet->Create(line->GetParam("mode")->AsInt(0), Math::Point(ppos.x, ppos.z), - OpFloat(line, "dim", 0.2f), - OpFloat(line, "speed", 0.0f), - OpFloat(line, "dir", 0.0f), - name, + line->GetParam("dim")->AsFloat(0.2f), + line->GetParam("speed")->AsFloat(0.0f), + line->GetParam("dir")->AsFloat(0.0f), + line->GetParam("image")->AsPath(""), //TODO: don't make this relative to textures/ Math::Point(uv1.x, uv1.z), Math::Point(uv2.x, uv2.z), - strstr(name, "planet") != nullptr // TODO: add transparent op or modify textures - ); + line->GetParam("image")->AsPath("").find("planet") != std::string::npos // TODO: add transparent op or modify textures + ); continue; } - - if (Cmd(line, "ForegroundName") && !resetObject) + + if (line->GetCommand() == "ForegroundName" && !resetObject) { - OpString(line, "image", name); - m_engine->SetForegroundName(name); + m_engine->SetForegroundName(line->GetParam("image")->AsPath("")); //TODO: don't make this relative to textures/ continue; } - - if (((m_version == 1 && Cmd(line, "Global")) || (m_version >= 2 && Cmd(line, "Mission"))) && !resetObject) + + if (((line->GetCommand() == "Global") || (m_version >= 2 && line->GetCommand() == "Mission")) && !resetObject) { - g_unit = OpFloat(line, "unitScale", 4.0f); - m_engine->SetTracePrecision(OpFloat(line, "traceQuality", 1.0f)); - m_shortCut = OpInt(line, "shortcut", 1); + g_unit = line->GetParam("unitScale")->AsFloat(4.0f); + m_engine->SetTracePrecision(line->GetParam("traceQuality")->AsFloat(1.0f)); + m_shortCut = line->GetParam("shortcut")->AsBool(true); if (m_version >= 2) { - m_retroStyle = OpInt(line, "retro", 0); + m_retroStyle = line->GetParam("retro")->AsBool(false); if (m_retroStyle) GetLogger()->Info("Retro mode enabled.\n"); } continue; } - - if (Cmd(line, "TerrainGenerate") && !resetObject) + + if (line->GetCommand() == "TerrainGenerate" && !resetObject) { - if (m_terrainCreate) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainGenerate after TerrainCreate\n", filename, lineNum); - continue; - } - - if (m_terrainInit) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainGenerate after TerrainInit\n", filename, lineNum); - continue; - } - - m_terrain->Generate(OpInt(line, "mosaic", 20), - OpInt(line, "brick", 3), - OpFloat(line, "size", 20.0f), - OpFloat(line, "vision", 500.0f)*g_unit, - OpInt(line, "depth", 2), - OpFloat(line, "hard", 0.5f)); - - m_terrainGenerate = true; - continue; - } - - if (Cmd(line, "TerrainWind") && !resetObject) - { - if (m_terrainCreate) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainWind after TerrainCreate\n", filename, lineNum); - continue; - } - - if (m_terrainInit) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainWind after TerrainInit\n", filename, lineNum); - continue; - } - - if (!m_terrainGenerate) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainWind before TerrainGenerate\n", filename, lineNum); - continue; - } - - m_terrain->SetWind(OpPos(line, "speed")); - continue; - } - - if (Cmd(line, "TerrainRelief") && !resetObject) - { - if (m_terrainCreate) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainRelief after TerrainCreate\n", filename, lineNum); - continue; - } - - if (m_terrainInit) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainRelief after TerrainInit\n", filename, lineNum); - continue; - } - - if (!m_terrainGenerate) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainRelief before TerrainGenerate\n", filename, lineNum); - continue; - } - - OpString(line, "image", name); - m_terrain->LoadRelief(std::string("textures/")+name, OpFloat(line, "factor", 1.0f), OpInt(line, "border", 1)); + m_terrain->Generate(line->GetParam("mosaic")->AsInt(20), + line->GetParam("brick")->AsInt(3), + line->GetParam("size")->AsFloat(20.0f), + line->GetParam("vision")->AsFloat(500.0f)*g_unit, + line->GetParam("depth")->AsInt(2), + line->GetParam("hard")->AsFloat(0.5f)); continue; } - if (Cmd(line, "TerrainRandomRelief") && !resetObject) + if (line->GetCommand() == "TerrainWind" && !resetObject) + { + m_terrain->SetWind(line->GetParam("speed")->AsPoint()); + continue; + } + + if (line->GetCommand() == "TerrainRelief" && !resetObject) + { + m_terrain->LoadRelief( + line->GetParam("image")->AsPath("textures"), + line->GetParam("factor")->AsFloat(1.0f), + line->GetParam("border")->AsBool(true)); + continue; + } + + if (line->GetCommand() == "TerrainRandomRelief" && !resetObject) { m_terrain->RandomizeRelief(); continue; } - - if (Cmd(line, "TerrainResource") && !resetObject) + + if (line->GetCommand() == "TerrainResource" && !resetObject) { - if (m_terrainCreate) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainResource after TerrainCreate\n", filename, lineNum); - continue; - } - - if (m_terrainInit) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainResource after TerrainInit\n", filename, lineNum); - continue; - } - - if (!m_terrainGenerate) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainResource before TerrainGenerate\n", filename, lineNum); - continue; - } - - OpString(line, "image", name); - m_terrain->LoadResources(std::string("textures/")+name); + m_terrain->LoadResources(line->GetParam("image")->AsPath("textures")); continue; } - - if (Cmd(line, "TerrainWater") && !resetObject) + + if (line->GetCommand() == "TerrainWater" && !resetObject) { - OpString(line, "image", name); Math::Vector pos; - pos.x = OpFloat(line, "moveX", 0.0f); - pos.y = OpFloat(line, "moveY", 0.0f); + pos.x = line->GetParam("moxeX")->AsFloat(0.0f); + pos.y = line->GetParam("moxeY")->AsFloat(0.0f); pos.z = pos.x; - m_water->Create(OpTypeWater(line, "air", Gfx::WATER_TT), - OpTypeWater(line, "water", Gfx::WATER_TT), - name, - OpColor(line, "diffuse", Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), - OpColor(line, "ambient", Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), - OpFloat(line, "level", 100.0f)*g_unit, - OpFloat(line, "glint", 1.0f), + m_water->Create(line->GetParam("air")->AsWaterType(Gfx::WATER_TT), + line->GetParam("water")->AsWaterType(Gfx::WATER_TT), + line->GetParam("image")->AsPath(""), //TODO: don't make this relative to textures/ + line->GetParam("diffuse")->AsColor(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), + line->GetParam("ambient")->AsColor(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), + line->GetParam("level")->AsFloat(100.0f)*g_unit, + line->GetParam("glint")->AsFloat(1.0f), pos); - m_colorNewWater = OpColor(line, "color", m_colorRefWater); - m_colorShiftWater = OpFloat(line, "brightness", 0.0f); + m_colorNewWater = line->GetParam("color")->AsColor(m_colorRefWater); + m_colorShiftWater = line->GetParam("brightness")->AsFloat(0.0f); continue; } - - if (Cmd(line, "TerrainLava") && !resetObject) + + if (line->GetCommand() == "TerrainLava" && !resetObject) { - m_water->SetLava(OpInt(line, "mode", 0)); + m_water->SetLava(line->GetParam("mode")->AsBool()); continue; } - - if (Cmd(line, "TerrainCloud") && !resetObject) + + if (line->GetCommand() == "TerrainCloud" && !resetObject) { - OpString(line, "image", name); - m_cloud->Create(name, - OpColor(line, "diffuse", Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), - OpColor(line, "ambient", Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), - OpFloat(line, "level", 500.0f) * g_unit); + m_cloud->Create(line->GetParam("image")->AsPath("", ""), //TODO: don't make this relative to textures/ + line->GetParam("diffuse")->AsColor(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), + line->GetParam("ambient")->AsColor(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), + line->GetParam("level")->AsFloat(500.0f)*g_unit); continue; } - - if (Cmd(line, "TerrainBlitz") && !resetObject) + + if (line->GetCommand() == "TerrainBlitz" && !resetObject) { - m_lightning->Create(OpFloat(line, "sleep", 0.0f), - OpFloat(line, "delay", 3.0f), - OpFloat(line, "magnetic", 50.0f) * g_unit); + m_lightning->Create(line->GetParam("sleep")->AsFloat(0.0f), + line->GetParam("delay")->AsFloat(3.0f), + line->GetParam("magnetic")->AsFloat(50.0f)*g_unit); continue; } - - if (Cmd(line, "TerrainInitTextures") && !resetObject) + + if (line->GetCommand() == "TerrainInitTextures" && !resetObject) { - if (m_terrainInit) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainInitTextures and TerrainInit at same time\n", filename, lineNum); - continue; + std::string name = line->GetParam("image")->AsPath(""); //TODO: don't make this relative to textures/ + if(name.find(".") == std::string::npos) + name += ".png"; + int dx = line->GetParam("dx")->AsInt(1); + int dy = line->GetParam("dy")->AsInt(1); + + int tt[100]; //TODO: I have no idea how TerrainInitTextures works, but maybe we shuld remove the limit to 100? + if(dx*dy > 100) + throw CLevelParserException("In TerrainInitTextures: dx*dy must be <100"); + if(line->GetParam("table")->IsDefined()) { + const std::vector& table = line->GetParam("table")->AsArray(); + + if(table.size() > dx*dy) + throw CLevelParserException("In TerrainInitTextures: table size must be dx*dy"); + + for (int i = 0; i < dx*dy; i++) + { + if(i >= table.size()) + { + tt[i] = 0; + } else { + tt[i] = table[i]->AsInt(); + } + } + } else { + for (int i = 0; i < dx*dy; i++) + { + tt[i] = 0; + } } - - OpString(line, "image", name); - AddExt(name, ".png"); - int dx = OpInt(line, "dx", 1); - int dy = OpInt(line, "dy", 1); - char* opTable = SearchOp(line, "table"); - int tt[100]; - for (int i = 0; i < dx*dy; i++) - tt[i] = GetInt(opTable, i, 0); - + + /*TODO: ??? if (strstr(name, "%user%") != 0) CopyFileListToTemp(name, tt, dx*dy); - - m_terrain->InitTextures(name, tt, dx, dy); - - m_terrainInitTextures = true; + */ + + m_terrain->InitTextures(name.c_str(), tt, dx, dy); continue; } - - if (Cmd(line, "TerrainInit") && !resetObject) + + if (line->GetCommand() == "TerrainInit" && !resetObject) { - if (m_terrainInitTextures) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainInit and TerrainInitTextures at same time\n", filename, lineNum); - continue; - } - - m_terrain->InitMaterials(OpInt(line, "id", 1)); + m_terrain->InitMaterials(line->GetParam("id")->AsInt(1)); m_terrainInit = true; continue; } - - if (Cmd(line, "TerrainMaterial") && !resetObject) + + if (line->GetCommand() == "TerrainMaterial" && !resetObject) { - if (m_terrainCreate) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainMaterial after TerrainCreate\n", filename, lineNum); - continue; - } - - if (m_terrainInit) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainMaterial after TerrainInit\n", filename, lineNum); - continue; - } - - if (m_terrainInitTextures) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainMaterial and TerrainInitTextures at same time\n", filename, lineNum); - continue; - } - - OpString(line, "image", name); - AddExt(name, ".png"); + std::string name = line->GetParam("image")->AsPath(""); //TODO: don't make this relative to textures/ + if(name.find(".") == std::string::npos) + name += ".png"; + /*TODO: ??? if (strstr(name, "%user%") != 0) { GetProfile().CopyFileToTemp(std::string(name)); } - - m_terrain->AddMaterial(OpInt(line, "id", 0), - name, - Math::Point(OpFloat(line, "u", 0.0f), - OpFloat(line, "v", 0.0f)), - OpInt(line, "up", 1), - OpInt(line, "right", 1), - OpInt(line, "down", 1), - OpInt(line, "left", 1), - OpFloat(line, "hard", 0.5f)); + */ + + m_terrain->AddMaterial(line->GetParam("id")->AsInt(0), + name.c_str(), + Math::Point(line->GetParam("u")->AsFloat(), + line->GetParam("v")->AsFloat()), + line->GetParam("up")->AsInt(), + line->GetParam("right")->AsInt(), + line->GetParam("down")->AsInt(), + line->GetParam("left")->AsInt(), + line->GetParam("hard")->AsFloat(0.5f)); continue; } - - if (Cmd(line, "TerrainLevel") && !resetObject) + + if (line->GetCommand() == "TerrainLevel" && !resetObject) { - if (m_terrainCreate) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainLevel after TerrainCreate\n", filename, lineNum); - continue; + int id[50]; //TODO: I have no idea how TerrainLevel works, but maybe we should remove the limit to 50? + if(line->GetParam("id")->IsDefined()) { + const std::vector& id_array = line->GetParam("id")->AsArray(); + + if(id_array.size() > 50) + throw CLevelParserException("In TerrainLevel: id array size must be < 50"); + + int i = 0; + while (i < 50) + { + id[i] = id_array[i]->AsInt(); + i++; + if(i >= id_array.size()) break; + } } - - if (!m_terrainInit) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainLevel before TerrainInit\n", filename, lineNum); - continue; - } - - if (m_terrainInitTextures) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainLevel and TerrainInitTextures at same time\n", filename, lineNum); - continue; - } - - if (!m_terrainGenerate) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): TerrainLevel before TerrainGenerate\n", filename, lineNum); - continue; - } - - char* opId = SearchOp(line, "id"); - int id[50]; - int i = 0; - while (i < 50) - { - id[i] = GetInt(opId, i, 0); - if (id[i++] == 0) break; - } - + m_terrain->GenerateMaterials(id, - OpFloat(line, "min", 0.0f)*g_unit, - OpFloat(line, "max", 100.0f)*g_unit, - OpFloat(line, "slope", 5.0f), - OpFloat(line, "freq", 100.0f), - OpPos(line, "center")*g_unit, - OpFloat(line, "radius", 0.0f)*g_unit); + line->GetParam("min")->AsFloat(0.0f)*g_unit, + line->GetParam("max")->AsFloat(100.0f)*g_unit, + line->GetParam("slope")->AsFloat(5.0f), + line->GetParam("freq")->AsFloat(100.0f), + line->GetParam("center")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit, + line->GetParam("radius")->AsFloat(0.0f)*g_unit); continue; } - - if (Cmd(line, "TerrainCreate") && !resetObject) + + if (line->GetCommand() == "TerrainCreate" && !resetObject) { m_terrain->CreateObjects(); - m_terrainCreate = true; continue; } - - if (Cmd(line, "BeginObject")) + + if (line->GetCommand() == "BeginObject") { InitEye(); SetMovieLock(false); - + if (read[0] != 0) // loading file ? sel = IOReadScene(read, stack); - - m_beginObject = true; + continue; } - - if (Cmd(line, "MissionController") && read[0] == 0 && m_version >= 2) + + if (line->GetCommand() == "MissionController" && read[0] == 0 && m_version >= 2) { m_controller = CObjectManager::GetInstancePointer()->CreateObject(Math::Vector(0.0f, 0.0f, 0.0f), 0.0f, OBJECT_CONTROLLER, 100.0f); m_controller->SetMagnifyDamage(100.0f); @@ -4542,48 +4418,42 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) CBrain* brain = m_controller->GetBrain(); if (brain != nullptr) { - OpString(line, "script", name); - if (name[0] != 0) - brain->SetScriptName(0, name); + std::string name = line->GetParam("script")->AsPath(""); //TODO: Don't make this relative to ai/ + if (!name.empty()) + brain->SetScriptName(0, const_cast(name.c_str())); brain->SetScriptRun(0); } continue; } - - if (Cmd(line, "CreateObject") && read[0] == 0) + + if (line->GetCommand() == "CreateObject" && read[0] == 0) { - if (!m_beginObject) - { - GetLogger()->Error("Syntax error in file '%s' (line %d): CreateObject before BeginObject\n", filename, lineNum); - continue; - } - - ObjectType type = OpTypeObject(line, "type", OBJECT_NULL); - - int gadget = OpInt(line, "gadget", -1); + ObjectType type = line->GetParam("type")->AsObjectType(); + + int gadget = line->GetParam("gadget")->AsInt(-1); if ( gadget == -1 ) { gadget = 0; if ( type == OBJECT_TECH || - (type >= OBJECT_PLANT0 && - type <= OBJECT_PLANT19 ) || - (type >= OBJECT_TREE0 && - type <= OBJECT_TREE5 ) || - (type >= OBJECT_TEEN0 && - type <= OBJECT_TEEN44 ) || - (type >= OBJECT_QUARTZ0 && - type <= OBJECT_QUARTZ3 ) || - (type >= OBJECT_ROOT0 && - type <= OBJECT_ROOT4 ) ) // not ROOT5! + (type >= OBJECT_PLANT0 && + type <= OBJECT_PLANT19 ) || + (type >= OBJECT_TREE0 && + type <= OBJECT_TREE5 ) || + (type >= OBJECT_TEEN0 && + type <= OBJECT_TEEN44 ) || + (type >= OBJECT_QUARTZ0 && + type <= OBJECT_QUARTZ3 ) || + (type >= OBJECT_ROOT0 && + type <= OBJECT_ROOT4 ) ) // not ROOT5! { if ( type != OBJECT_TEEN11 && // lamp? - type != OBJECT_TEEN12 && // coke? - type != OBJECT_TEEN20 && // wall? - type != OBJECT_TEEN21 && // wall? - type != OBJECT_TEEN22 && // wall? - type != OBJECT_TEEN26 && // lamp? - type != OBJECT_TEEN28 && // bottle? - type != OBJECT_TEEN34 ) // stone? + type != OBJECT_TEEN12 && // coke? + type != OBJECT_TEEN20 && // wall? + type != OBJECT_TEEN21 && // wall? + type != OBJECT_TEEN22 && // wall? + type != OBJECT_TEEN26 && // lamp? + type != OBJECT_TEEN28 && // bottle? + type != OBJECT_TEEN34 ) // stone? { gadget = 1; } @@ -4593,19 +4463,20 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) { if (!TestGadgetQuantity(rankGadget++)) continue; } - - Math::Vector pos = OpPos(line, "pos")*g_unit; - float dirAngle = OpFloat(line, "dir", 0.0f)*Math::PI; + + Math::Vector pos = line->GetParam("pos")->AsPoint()*g_unit; + float dirAngle = line->GetParam("dir")->AsFloat(0.0f)*Math::PI; bool trainer; CObject* obj = CObjectManager::GetInstancePointer()->CreateObject( - pos, dirAngle, - type, - OpFloat(line, "power", 1.0f), - OpFloat(line, "z", 1.0f), - OpFloat(line, "h", 0.0f), - trainer = OpInt(line, "trainer", 0), - OpInt(line, "toy", 0), - OpInt(line, "option", 0)); + pos, dirAngle, + type, + line->GetParam("power")->AsFloat(1.0f), + line->GetParam("z")->AsFloat(1.0f), + line->GetParam("h")->AsFloat(0.0f), + trainer = line->GetParam("trainer")->AsBool(false), + line->GetParam("toy")->AsBool(false), + line->GetParam("option")->AsInt(0) + ); if (m_fixScene && type == OBJECT_HUMAN) { @@ -4613,108 +4484,112 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) if (m_phase == PHASE_WIN ) motion->SetAction(MHS_WIN, 0.4f); if (m_phase == PHASE_LOST) motion->SetAction(MHS_LOST, 0.5f); } - + if (obj != nullptr) { obj->SetDefRank(rankObj); - + if (type == OBJECT_BASE) m_base = true; - - Gfx::CameraType cType = OpCamera(line, "camera"); + + Gfx::CameraType cType = line->GetParam("camera")->AsCameraType(Gfx::CAM_TYPE_NULL); if (cType != Gfx::CAM_TYPE_NULL) obj->SetCameraType(cType); - - obj->SetCameraDist(OpFloat(line, "cameraDist", 50.0f)); - obj->SetCameraLock(OpInt(line, "cameraLock", 0)); - - Gfx::PyroType pType = OpPyro(line, "pyro"); + + obj->SetCameraDist(line->GetParam("cameraDist")->AsFloat(50.0f)); + obj->SetCameraLock(line->GetParam("cameraLock")->AsBool(false)); + + Gfx::PyroType pType = line->GetParam("pyro")->AsPyroType(Gfx::PT_NULL); if (pType != Gfx::PT_NULL) { Gfx::CPyro* pyro = new Gfx::CPyro(); pyro->Create(pType, obj); } - + // Puts information in terminal (OBJECT_INFO). for (int i = 0; i < OBJECTMAXINFO; i++) { - sprintf(op, "info%d", i+1); - char text[100]; - OpString(line, op, text); - if (text[0] == 0) break; - char* p = strchr(text, '='); - if (p == 0) break; - *p = 0; + std::string op = "info"+std::to_string(i+1); + if(!line->GetParam(op)->IsDefined()) break; + std::string text = line->GetParam(op)->AsString(); + std::size_t p = text.find_first_of("="); + if(p == std::string::npos) + throw CLevelParserExceptionBadParam(line->GetParam(op), "info"); Info info; - strcpy(info.name, text); - sscanf(p+1, "%f", &info.value); + strcpy(info.name, text.substr(0, p).c_str()); + try { + info.value = boost::lexical_cast(text.substr(p+1).c_str()); + } + catch(...) + { + throw CLevelParserExceptionBadParam(line->GetParam(op), "info.value (float)"); + } obj->SetInfo(i, info); } - + // Sets the parameters of the command line. - char* p = SearchOp(line, "cmdline"); - for (int i = 0; i < OBJECTMAXCMDLINE; i++) - { - float value = GetFloat(p, i, NAN); - if (value == NAN) break; - obj->SetCmdLine(i, value); + if(line->GetParam("cmdline")->IsDefined()) { + const std::vector& cmdline = line->GetParam("cmdline")->AsArray(); + for (int i = 0; i < OBJECTMAXCMDLINE && i < cmdline.size(); i++) //TODO: get rid of the limit + { + obj->SetCmdLine(i, cmdline[i]->AsFloat()); + } } - - if (OpInt(line, "select", 0) == 1) + + if (line->GetParam("select")->AsBool(false)) { sel = obj; } - - bool selectable = OpInt(line, "selectable", 1); + + bool selectable = line->GetParam("selectable")->AsBool(true); obj->SetSelectable(selectable); - obj->SetIgnoreBuildCheck(OpInt(line, "ignoreBuildCheck", 0)); - obj->SetEnable(OpInt(line, "enable", 1)); - obj->SetProxyActivate(OpInt(line, "proxyActivate", 0)); - obj->SetProxyDistance(OpFloat(line, "proxyDistance", 15.0f)*g_unit); - obj->SetRange(OpFloat(line, "range", 30.0f)); - obj->SetShield(OpFloat(line, "shield", 1.0f)); - obj->SetMagnifyDamage(OpFloat(line, "magnifyDamage", 1.0f)); - obj->SetClip(OpInt(line, "clip", 1)); - obj->SetCheckToken(m_version >= 2 ? trainer || !selectable : OpInt(line, "checkToken", 1)); + obj->SetIgnoreBuildCheck(line->GetParam("ignoreBuildCheck")->AsBool(false)); + obj->SetEnable(line->GetParam("enable")->AsBool(true)); + obj->SetProxyActivate(line->GetParam("proxyActivate")->AsBool(false)); + if(line->GetParam("proxyActivate")->AsBool(false)) + obj->SetProxyDistance(line->GetParam("proxyDistance")->AsFloat()*g_unit); + obj->SetRange(line->GetParam("range")->AsFloat(30.0f)); + obj->SetShield(line->GetParam("shield")->AsFloat(1.0f)); + obj->SetMagnifyDamage(line->GetParam("magnifyDamage")->AsFloat(1.0f)); + obj->SetClip(line->GetParam("clip")->AsBool(true)); + obj->SetCheckToken(m_version >= 2 ? trainer || !selectable : line->GetParam("checkToken")->AsBool(true)); // SetManual will affect bot speed if (type == OBJECT_MOBILEdr) { - obj->SetManual(m_version >= 2 ? !trainer : OpInt(line, "manual", 0)); + obj->SetManual(m_version >= 2 ? !trainer : line->GetParam("manual")->AsBool(false)); } - + if (m_version >= 2) { - Math::Vector zoom = OpDir(line, "zoom"); + Math::Vector zoom = line->GetParam("zoom")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f)); if (zoom.x != 0.0f || zoom.y != 0.0f || zoom.z != 0.0f) obj->SetZoom(0, zoom); } - + + //TODO: I don't remember what this is used for CMotion* motion = obj->GetMotion(); - if (motion != nullptr) + if (motion != nullptr && line->GetParam("param")->IsDefined()) { - p = SearchOp(line, "param"); - for (int i = 0; i < 10; i++) + const std::vector& p = line->GetParam("param")->AsArray(); + for (int i = 0; i < 10 && i < p.size(); i++) { - float value; - value = GetFloat(p, i, NAN); - if (value == NAN) break; - motion->SetParam(i, value); + motion->SetParam(i, p[i]->AsFloat()); } } - + int run = -1; CBrain* brain = obj->GetBrain(); if (brain != nullptr) { for (int i = 0; i < 10; i++) { - sprintf(op, "script%d", i+1); // script1..script10 - OpString(line, op, name); - if (name[0] != 0) - brain->SetScriptName(i, name); - + std::string op = "script"+std::to_string(i+1); // script1..script10 + if(line->GetParam(op)->IsDefined()) { + brain->SetScriptName(i, const_cast(line->GetParam(op)->AsPath("").c_str())); //TODO: don't make this relative to ai/ + } + } - - int i = OpInt(line, "run", 0); + + int i = line->GetParam("run")->AsInt(0); if (i != 0) { run = i-1; @@ -4724,17 +4599,16 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) CAuto* automat = obj->GetAuto(); if (automat != nullptr) { - type = OpTypeObject(line, "autoType", OBJECT_NULL); + type = line->GetParam("autoType")->AsObjectType(OBJECT_NULL); automat->SetType(type); for (int i = 0; i < 5; i++) { - sprintf(op, "autoValue%d", i+1); // autoValue1..autoValue5 - automat->SetValue(i, OpFloat(line, op, 0.0f)); + std::string op = "autoValue"+std::to_string(i+1); // autoValue1..autoValue5 + automat->SetValue(i, line->GetParam(op)->AsFloat(0.0f)); } - OpString(line, "autoString", name); - automat->SetString(name); - - int i = OpInt(line, "run", -1); + automat->SetString(const_cast(line->GetParam("autoString")->AsString("").c_str())); + + int i = line->GetParam("run")->AsInt(-1); if (i != -1) { if (i != PARAM_FIXSCENE && @@ -4742,30 +4616,29 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) automat->Start(i); // starts the film } } - - OpString(line, "soluce", name); - if (soluce && brain != 0 && name[0] != 0) - brain->SetSoluceName(name); - + + if (soluce && brain != nullptr && line->GetParam("soluce")->IsDefined()) + brain->SetSoluceName(const_cast(line->GetParam("soluce")->AsString().c_str())); + obj->SetResetPosition(obj->GetPosition(0)); obj->SetResetAngle(obj->GetAngle(0)); obj->SetResetRun(run); - - if (OpInt(line, "reset", 0) == 1) + + if (line->GetParam("reset")->AsBool(false)) obj->SetResetCap(RESET_MOVE); } - + rankObj ++; continue; } - - if (Cmd(line, "CreateFog") && !resetObject) + + if (line->GetCommand() == "CreateFog" && !resetObject) { - Gfx::ParticleType type = static_cast((Gfx::PARTIFOG0+OpInt(line, "type", 0))); - Math::Vector pos = OpPos(line, "pos")*g_unit; - float height = OpFloat(line, "height", 1.0f)*g_unit; - float ddim = OpFloat(line, "dim", 50.0f)*g_unit; - float delay = OpFloat(line, "delay", 2.0f); + Gfx::ParticleType type = static_cast(Gfx::PARTIFOG0+(line->GetParam("type")->AsInt())); + Math::Vector pos = line->GetParam("pos")->AsPoint()*g_unit; + float height = line->GetParam("height")->AsFloat(1.0f)*g_unit; + float ddim = line->GetParam("dim")->AsFloat(50.0f)*g_unit; + float delay = line->GetParam("delay")->AsFloat(2.0f); m_terrain->AdjustToFloor(pos); pos.y += height; Math::Point dim; @@ -4774,149 +4647,150 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_particle->CreateParticle(pos, Math::Vector(0.0f, 0.0f, 0.0f), dim, type, delay, 0.0f, 0.0f); continue; } - - if (Cmd(line, "CreateLight") && !resetObject) + + if (line->GetCommand() == "CreateLight" && !resetObject) { Gfx::EngineObjectType type; - - int lightRank = CreateLight(OpDir(line, "dir"), - OpColor(line, "color", Gfx::Color(0.5f, 0.5f, 0.5f, 1.0f))); - - type = OpTypeTerrain(line, "type", Gfx::ENG_OBJTYPE_NULL); + + int lightRank = CreateLight(line->GetParam("dir")->AsPoint(), + line->GetParam("color")->AsColor(Gfx::Color(0.5f, 0.5f, 0.5f, 1.0f))); + + type = line->GetParam("type")->AsTerrainType(Gfx::ENG_OBJTYPE_NULL); + if (type == Gfx::ENG_OBJTYPE_TERRAIN) { m_lightMan->SetLightPriority(lightRank, Gfx::LIGHT_PRI_HIGHEST); m_lightMan->SetLightIncludeType(lightRank, Gfx::ENG_OBJTYPE_TERRAIN); } - + if (type == Gfx::ENG_OBJTYPE_QUARTZ) m_lightMan->SetLightIncludeType(lightRank, Gfx::ENG_OBJTYPE_QUARTZ); - + if (type == Gfx::ENG_OBJTYPE_METAL) m_lightMan->SetLightIncludeType(lightRank, Gfx::ENG_OBJTYPE_METAL); - + if (type == Gfx::ENG_OBJTYPE_FIX) m_lightMan->SetLightExcludeType(lightRank, Gfx::ENG_OBJTYPE_TERRAIN); - + continue; } - if (Cmd(line, "CreateSpot") && !resetObject) + if (line->GetCommand() == "CreateSpot" && !resetObject) { Gfx::EngineObjectType type; - - int rankLight = CreateSpot(OpDir(line, "pos")*g_unit, - OpColor(line, "color", Gfx::Color(0.5f, 0.5f, 0.5f, 1.0f))); - - type = OpTypeTerrain(line, "type", Gfx::ENG_OBJTYPE_NULL); + + int rankLight = CreateSpot(line->GetParam("pos")->AsPoint()*g_unit, + line->GetParam("color")->AsColor(Gfx::Color(0.5f, 0.5f, 0.5f, 1.0f))); + + type = line->GetParam("type")->AsTerrainType(Gfx::ENG_OBJTYPE_NULL); if (type == Gfx::ENG_OBJTYPE_TERRAIN) m_lightMan->SetLightIncludeType(rankLight, Gfx::ENG_OBJTYPE_TERRAIN); - + if (type == Gfx::ENG_OBJTYPE_QUARTZ) m_lightMan->SetLightIncludeType(rankLight, Gfx::ENG_OBJTYPE_QUARTZ); - + if (type == Gfx::ENG_OBJTYPE_METAL) m_lightMan->SetLightIncludeType(rankLight, Gfx::ENG_OBJTYPE_METAL); - + if (type == Gfx::ENG_OBJTYPE_FIX) m_lightMan->SetLightExcludeType(rankLight, Gfx::ENG_OBJTYPE_TERRAIN); - + continue; } - - if (Cmd(line, "GroundSpot") && !resetObject) + + if (line->GetCommand() == "GroundSpot" && !resetObject) { rank = m_engine->CreateGroundSpot(); if (rank != -1) { - m_engine->SetObjectGroundSpotPos(rank, OpPos(line, "pos")*g_unit); - m_engine->SetObjectGroundSpotRadius(rank, OpFloat(line, "radius", 10.0f)*g_unit); - m_engine->SetObjectGroundSpotColor(rank, OpColor(line, "color", Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f))); - m_engine->SetObjectGroundSpotSmooth(rank, OpFloat(line, "smooth", 1.0f)); - m_engine->SetObjectGroundSpotMinMax(rank, OpFloat(line, "min", 0.0f)*g_unit, - OpFloat(line, "max", 0.0f)*g_unit); + m_engine->SetObjectGroundSpotPos(rank, line->GetParam("pos")->AsPoint()*g_unit); + m_engine->SetObjectGroundSpotRadius(rank, line->GetParam("radius")->AsFloat(10.0f)*g_unit); + m_engine->SetObjectGroundSpotColor(rank, line->GetParam("color")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f))); + m_engine->SetObjectGroundSpotSmooth(rank, line->GetParam("smooth")->AsFloat(1.0f)); + m_engine->SetObjectGroundSpotMinMax(rank, line->GetParam("min")->AsFloat(0.0f)*g_unit, + line->GetParam("max")->AsFloat(0.0f)*g_unit); } continue; } - - if (Cmd(line, "WaterColor") && !resetObject) + + if (line->GetCommand() == "WaterColor" && !resetObject) { - m_engine->SetWaterAddColor(OpColor(line, "color", Gfx::Color(0.0f, 0.0f, 0.0f, 1.0f))); + m_engine->SetWaterAddColor(line->GetParam("color")->AsColor()); continue; } - - if (Cmd(line, "MapColor") && !resetObject) + + if (line->GetCommand() == "MapColor" && !resetObject) { - m_map->FloorColorMap(OpColor(line, "floor", Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), - OpColor(line, "water", Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f))); - m_mapShow = OpInt(line, "show", 1); + m_map->FloorColorMap(line->GetParam("floor")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), + line->GetParam("water")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f))); + m_mapShow = line->GetParam("show")->AsBool(true); m_map->ShowMap(m_mapShow); - m_map->SetToy(OpInt(line, "toyIcon", 0)); - m_mapImage = OpInt(line, "image", 0); + m_map->SetToy(line->GetParam("toyIcon")->AsBool(false)); + m_mapImage = line->GetParam("image")->AsBool(false); if (m_mapImage) { - Math::Vector offset; - OpString(line, "filename", m_mapFilename); - offset = OpPos(line, "offset"); - m_map->SetFixParam(OpFloat(line, "zoom", 1.0f), + Math::Vector offset; + strcpy(m_mapFilename, line->GetParam("filename")->AsPath("").c_str()); //TODO: don't make this relative to textures/ + offset = line->GetParam("offset")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f)); + m_map->SetFixParam(line->GetParam("zoom")->AsFloat(1.0f), offset.x, offset.z, - OpFloat(line, "angle", 0.0f)*Math::PI/180.0f, - OpInt(line, "mode", 0), - OpInt(line, "debug", 0)); + line->GetParam("angle")->AsFloat(0.0f)*Math::PI/180.0f, + line->GetParam("mode")->AsInt(0), + line->GetParam("debug")->AsBool(false)); } continue; } - - if (Cmd(line, "MapZoom") && !resetObject) + + if (line->GetCommand() == "MapZoom" && !resetObject) { - m_map->ZoomMap(OpFloat(line, "factor", 2.0f)); - m_map->MapEnable(OpInt(line, "enable", 1)); + m_map->ZoomMap(line->GetParam("factor")->AsFloat(2.0f)); + m_map->MapEnable(line->GetParam("enable")->AsBool(true)); continue; } - - if (Cmd(line, "MaxFlyingHeight") && !resetObject) + + if (line->GetCommand() == "MaxFlyingHeight" && !resetObject) { - m_terrain->SetFlyingMaxHeight(OpFloat(line, "max", 280.0f)*g_unit); + m_terrain->SetFlyingMaxHeight(line->GetParam("max")->AsFloat(280.0f)*g_unit); continue; } - - if (Cmd(line, "AddFlyingHeight") && !resetObject) + + if (line->GetCommand() == "AddFlyingHeight" && !resetObject) { - m_terrain->AddFlyingLimit(OpPos(line, "center")*g_unit, - OpFloat(line, "extRadius", 20.0f)*g_unit, - OpFloat(line, "intRadius", 10.0f)*g_unit, - OpFloat(line, "maxHeight", 200.0f)); + m_terrain->AddFlyingLimit(line->GetParam("center")->AsPoint()*g_unit, + line->GetParam("extRadius")->AsFloat(20.0f)*g_unit, + line->GetParam("intRadius")->AsFloat(10.0f)*g_unit, + line->GetParam("maxHeight")->AsFloat(200.0f)); continue; } - - if (Cmd(line, "Camera")) + + if (line->GetCommand() == "Camera") { - m_camera->Init(OpDir(line, "eye")*g_unit, - OpDir(line, "lookat")*g_unit, - resetObject?0.0f:OpFloat(line, "delay", 0.0f)); - - if (OpInt(line, "fadeIn", 0) == 1) + m_camera->Init(line->GetParam("eye")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit, + line->GetParam("lookat")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit, + resetObject ? 0.0f : line->GetParam("delay")->AsFloat(0.0f)); + + if (line->GetParam("fadeIn")->AsBool(false)) m_camera->StartOver(Gfx::CAM_OVER_EFFECT_FADEIN_WHITE, Math::Vector(0.0f, 0.0f, 0.0f), 1.0f); - - m_camera->SetFixDirection(OpFloat(line, "fixDirection", 0.25f)*Math::PI); + + m_camera->SetFixDirection(line->GetParam("fixDirection")->AsFloat(0.25f)*Math::PI); continue; } - - if (Cmd(line, "EndMissionTake") && !resetObject && m_controller == nullptr) + + if (line->GetCommand() == "EndMissionTake" && !resetObject && m_controller == nullptr) { int i = m_endTakeTotal; if (i < 10) { - m_endTake[i].pos = OpPos(line, "pos")*g_unit; - m_endTake[i].dist = OpFloat(line, "dist", (m_version < 2 ? 8.0f : 100.0f))*g_unit; - m_endTake[i].type = OpTypeObject(line, "type", OBJECT_NULL); - m_endTake[i].min = OpInt(line, "min", 1); - m_endTake[i].max = OpInt(line, "max", 9999); + m_endTake[i].pos = line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit; + m_endTake[i].dist = line->GetParam("dist")->AsFloat(m_version < 2 ? 8.0f : 100.0f)*g_unit; + m_endTake[i].type = line->GetParam("type")->AsObjectType(OBJECT_NULL); + m_endTake[i].min = line->GetParam("min")->AsInt(1); + m_endTake[i].max = line->GetParam("max")->AsInt(9999); if (m_version >= 2) { - m_endTake[i].powermin = OpFloat(line, "powermin", -1); - m_endTake[i].powermax = OpFloat(line, "powermax", 100); - m_endTake[i].tool = OpTool(line, "tool"); - m_endTake[i].drive = OpDrive(line, "drive"); + m_endTake[i].powermin = line->GetParam("powermin")->AsFloat(-1); + m_endTake[i].powermax = line->GetParam("powermax")->AsFloat(100); + m_endTake[i].tool = line->GetParam("tool")->AsToolType(TOOL_OTHER); + m_endTake[i].drive = line->GetParam("drive")->AsDriveType(DRIVE_OTHER); } else { @@ -4925,93 +4799,91 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_endTake[i].tool = TOOL_OTHER; m_endTake[i].drive = DRIVE_OTHER; } - m_endTake[i].lost = OpInt(line, "lost", -1); - m_endTake[i].immediat = OpInt(line, "immediat", 0); - OpString(line, "message", m_endTake[i].message); + m_endTake[i].lost = line->GetParam("lost")->AsInt(-1); + m_endTake[i].immediat = line->GetParam("immediat")->AsBool(false); + strcpy(m_endTake[i].message, line->GetParam("message")->AsString("").c_str()); //TODO: Really, ending mission on message()? Is this used anywhere? Do we need that? m_endTakeTotal ++; } continue; } - if (Cmd(line, "EndMissionDelay") && !resetObject && m_controller == nullptr) + if (line->GetCommand() == "EndMissionDelay" && !resetObject && m_controller == nullptr) { - m_endTakeWinDelay = OpFloat(line, "win", 2.0f); - m_endTakeLostDelay = OpFloat(line, "lost", 2.0f); + m_endTakeWinDelay = line->GetParam("win")->AsFloat(2.0f); + m_endTakeLostDelay = line->GetParam("lost")->AsFloat(2.0f); continue; } - if (Cmd(line, "EndMissionResearch") && !resetObject && m_controller == nullptr) + if (line->GetCommand() == "EndMissionResearch" && !resetObject && m_controller == nullptr) //TODO: Is this used anywhere? { - m_endTakeResearch |= OpResearch(line, "type"); + m_endTakeResearch |= line->GetParam("type")->AsResearchFlag(); continue; } - if (Cmd(line, "EndMissionNever") && !resetObject && m_controller == nullptr) + if (line->GetCommand() == "EndMissionNever" && !resetObject && m_controller == nullptr) { m_endTakeNever = true; continue; } - - if (Cmd(line, "ObligatoryToken") && !resetObject) + + if (line->GetCommand() == "ObligatoryToken" && !resetObject) //NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises? { int i = m_obligatoryTotal; - if (i < 100) + if (i < 100) //TODO: remove the limit { - OpString(line, "text", m_obligatoryToken[i]); + strcpy(m_obligatoryToken[i], line->GetParam("text")->AsString().c_str()); m_obligatoryTotal ++; } continue; } - - if (Cmd(line, "ProhibitedToken") && !resetObject) + + if (line->GetCommand() == "ProhibitedToken" && !resetObject) //NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises? { int i = m_prohibitedTotal; - if (i < 100) + if (i < 100) //TODO: remove the limit { - OpString(line, "text", m_prohibitedToken[i]); + strcpy(m_prohibitedToken[i], line->GetParam("text")->AsString().c_str()); m_prohibitedTotal ++; } continue; } - - if (Cmd(line, "EnableBuild") && !resetObject) + + if (line->GetCommand() == "EnableBuild" && !resetObject) { - g_build |= OpBuild(line, "type"); + g_build |= line->GetParam("type")->AsBuildFlag(); continue; } - - if (Cmd(line, "EnableResearch") && !resetObject) + + if (line->GetCommand() == "EnableResearch" && !resetObject) { - g_researchEnable |= OpResearch(line, "type"); + g_researchEnable |= line->GetParam("type")->AsResearchFlag(); continue; } - - if (Cmd(line, "DoneResearch") && read[0] == 0 && !resetObject) // not loading file? + + if (line->GetCommand() == "DoneResearch" && read[0] == 0 && !resetObject) // not loading file? { - g_researchDone |= OpResearch(line, "type"); + g_researchDone |= line->GetParam("type")->AsResearchFlag(); continue; } - - if (Cmd(line, "NewScript") && !resetObject) + + if (line->GetCommand() == "NewScript" && !resetObject) { - OpString(line, "name", name); - AddNewScriptName(OpTypeObject(line, "type", OBJECT_NULL), name); + char name[200]; + strcpy(name, line->GetParam("name")->AsPath("").c_str()); //TODO: don't make this relative to ai/ + AddNewScriptName(line->GetParam("type")->AsObjectType(OBJECT_NULL), name); continue; } - - if (line[0] == '\n') continue; // Ignore empty lines - if (line[0] == '\0') continue; // Ignore empty lines - if (read[0] != 0) continue; // Ignore when loading saved game - - GetLogger()->Error("Syntax error in file '%s' (line %d): Unknown command: %s", filename, lineNum, line); // Don't add \n at the end of log message - it's included in line variable + + if(read[0] != 0) continue; // ignore errors when loading saevd game (TODO: don't report ones that are just not loaded when loading saved game) + if(resetObject) continue; // ignore when reseting just objects (TODO: see above) + + throw CLevelParserException("Unknown command: '"+line->GetCommand()+"' in "+line->GetLevel()->GetFilename()+":"+std::to_string(line->GetLineNumber())); } - stream.close(); - if (read[0] == 0) CompileScript(soluce); // compiles all scripts - if (strcmp(base, "scene") == 0 && !resetObject) // mission? + if (strcmp(base, "missions") == 0 && !resetObject) // mission? WriteFreeParam(); - if (strcmp(base, "free") == 0 && !resetObject) // free play? + if (strcmp(base, "freemissions") == 0 && !resetObject) // free play? { g_researchDone = m_freeResearch; @@ -6541,20 +6413,28 @@ void CRobotMain::ResetCreate() m_camera->SetType(Gfx::CAM_TYPE_DIALOG); - CreateScene(m_dialog->GetSceneSoluce(), false, true); + try { + CreateScene(m_dialog->GetSceneSoluce(), false, true); - if (!GetNiceReset()) return; + if (!GetNiceReset()) return; - for (int i = 0; i < 1000000; i++) + for (int i = 0; i < 1000000; i++) + { + CObject* obj = static_cast(iMan->SearchInstance(CLASS_OBJECT, i)); + if (obj == nullptr) break; + + ResetCap cap = obj->GetResetCap(); + if (cap == RESET_NONE) continue; + + Gfx::CPyro* pyro = new Gfx::CPyro(); + pyro->Create(Gfx::PT_RESET, obj); + } + } + catch(const CLevelParserException& e) { - CObject* obj = static_cast(iMan->SearchInstance(CLASS_OBJECT, i)); - if (obj == nullptr) break; - - ResetCap cap = obj->GetResetCap(); - if (cap == RESET_NONE) continue; - - Gfx::CPyro* pyro = new Gfx::CPyro(); - pyro->Create(Gfx::PT_RESET, obj); + CLogger::GetInstancePointer()->Error("An error occured while trying to reset scene\n"); + CLogger::GetInstancePointer()->Error("%s\n", e.what()); + ChangePhase(PHASE_TERM); } } diff --git a/src/script/cmdtoken.cpp b/src/script/cmdtoken.cpp index 63935056..3a84bb3b 100644 --- a/src/script/cmdtoken.cpp +++ b/src/script/cmdtoken.cpp @@ -23,6 +23,8 @@ #include +// TODO: Remove these functions + // Skips spaces. diff --git a/src/script/script.cpp b/src/script/script.cpp index 578c07d5..605df71a 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -53,7 +53,6 @@ #include "ui/edit.h" #include "ui/list.h" #include "ui/displaytext.h" -#include #include