/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsitec.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://gnu.org/licenses */ #include "object/implementation/programmable_impl.h" #include "CBot/CBot.h" #include "common/global.h" #include "common/profiler.h" #include "level/robotmain.h" #include "math/all.h" #include "object/object.h" #include "object/old_object.h" #include "object/interface/controllable_object.h" #include "object/interface/task_executor_object.h" #include "object/motion/motion.h" #include "object/motion/motionvehicle.h" #include "physics/physics.h" #include "script/script.h" #include "ui/controls/edit.h" #include #include CProgrammableObjectImpl::CProgrammableObjectImpl(ObjectInterfaceTypes& types, CObject* object) : CProgrammableObject(types), m_object(object), m_activity(true), m_cmdLine(), m_currentProgram(nullptr), m_traceRecord(false), m_traceOper(TO_STOP), m_traceAngle(0.0f), m_traceColor(TraceColor::Default), m_traceRecordIndex(0) { //assert(m_object->Implements(ObjectInterfaceType::TaskExecutor)); } CProgrammableObjectImpl::~CProgrammableObjectImpl() {} bool CProgrammableObjectImpl::EventProcess(const Event &event) { if (event.type == EVENT_FRAME) { if ( m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(*m_object).IsDying() && IsProgram() ) { StopProgram(); } if ( GetActivity() ) { CProfiler::StartPerformanceCounter(PCNT_UPDATE_CBOT); if ( IsProgram() ) // current program? { if ( m_currentProgram->script->Continue() ) { StopProgram(); } } if ( m_traceRecord ) // registration of the design in progress? { TraceRecordFrame(); } CProfiler::StopPerformanceCounter(PCNT_UPDATE_CBOT); } } return true; } void CProgrammableObjectImpl::SetActivity(bool activity) { m_activity = activity; } bool CProgrammableObjectImpl::GetActivity() { return m_activity; } void CProgrammableObjectImpl::RunProgram(Program* program) { if ( program->script->Run() ) { m_currentProgram = program; // start new program m_object->UpdateInterface(); if (m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(*m_object).GetTrainer()) CRobotMain::GetInstancePointer()->StartMissionTimer(); } } void CProgrammableObjectImpl::StopProgram() { if ( m_currentProgram != nullptr ) { m_currentProgram->script->Stop(); } m_currentProgram = nullptr; m_object->UpdateInterface(); } Program* CProgrammableObjectImpl::GetCurrentProgram() { return m_currentProgram; } bool CProgrammableObjectImpl::IsProgram() { return m_currentProgram != nullptr; } // Load a stack of script implementation from a file. bool CProgrammableObjectImpl::ReadStack(std::istream &istr) { short op; if (!CBot::ReadShort(istr, op)) return false; if ( op == 1 ) // run ? { if (!CBot::ReadShort(istr, op)) return false; // program rank if ( op >= 0 ) { if (m_object->Implements(ObjectInterfaceType::ProgramStorage)) { int count = static_cast(dynamic_cast(*m_object).GetProgramCount()); if (!(op < count)) { GetLogger()->Info("Object program count: %i\n", count); GetLogger()->Error("Error in file: program index out of range: %i\n", op); return false; } m_currentProgram = dynamic_cast(*m_object).GetProgram(op); if (!m_currentProgram->script->ReadStack(istr)) { GetLogger()->Error("Restore state failed at program index: %i\n", op); int errNum = m_currentProgram->script->GetError(); if (errNum != 0) { std::string errStr; m_currentProgram->script->GetError(errStr); GetLogger()->Error("Program reports error: %i:(%s)\n", errNum, errStr.c_str()); } return false; } } else { GetLogger()->Error("Object is not a program storage object\n"); return false; } } } return true; } // Save the script implementation stack of a file. bool CProgrammableObjectImpl::WriteStack(std::ostream &ostr) { short op; if ( m_currentProgram != nullptr && // current program? m_currentProgram->script->IsRunning() ) { op = 1; // run if (!CBot::WriteShort(ostr, op)) return false; op = -1; if (m_object->Implements(ObjectInterfaceType::ProgramStorage)) { op = dynamic_cast(*m_object).GetProgramIndex(m_currentProgram); } if (!CBot::WriteShort(ostr, op)) return false; if (!m_currentProgram->script->WriteStack(ostr)) { GetLogger()->Error("Save state failed at program index: %i\n", op); return false; } return true; } op = 0; // stop return CBot::WriteShort(ostr, op); } const int MAXTRACERECORD = 1000; // Start of registration of the design. void CProgrammableObjectImpl::TraceRecordStart() { if (m_traceRecord) { TraceRecordStop(); } assert(m_object->Implements(ObjectInterfaceType::TraceDrawing)); CTraceDrawingObject* traceDrawing = dynamic_cast(m_object); m_traceRecord = true; m_traceOper = TO_STOP; m_tracePos = m_object->GetPosition(); m_traceAngle = m_object->GetRotationY(); if ( traceDrawing->GetTraceDown() ) // pencil down? { m_traceColor = traceDrawing->GetTraceColor(); } else // pen up? { m_traceColor = TraceColor::Default; } m_traceRecordBuffer = MakeUniqueArray(MAXTRACERECORD); m_traceRecordIndex = 0; } // Saving the current drawing. void CProgrammableObjectImpl::TraceRecordFrame() { TraceOper oper = TO_STOP; Math::Vector pos; float angle, len, speed; assert(m_object->Implements(ObjectInterfaceType::TraceDrawing)); CTraceDrawingObject* traceDrawing = dynamic_cast(m_object); CPhysics* physics = dynamic_cast(*m_object).GetPhysics(); speed = physics->GetLinMotionX(MO_REASPEED); if ( speed > 0.0f ) oper = TO_ADVANCE; if ( speed < 0.0f ) oper = TO_RECEDE; speed = physics->GetCirMotionY(MO_REASPEED); if ( speed != 0.0f ) oper = TO_TURN; TraceColor color = TraceColor::Default; if ( traceDrawing->GetTraceDown() ) // pencil down? { color = traceDrawing->GetTraceColor(); } if ( oper != m_traceOper || color != m_traceColor ) { if ( m_traceOper == TO_ADVANCE || m_traceOper == TO_RECEDE ) { pos = m_object->GetPosition(); len = Math::DistanceProjected(pos, m_tracePos); TraceRecordOper(m_traceOper, len); } if ( m_traceOper == TO_TURN ) { angle = m_object->GetRotationY()-m_traceAngle; TraceRecordOper(m_traceOper, angle); } if ( color != m_traceColor ) { TraceRecordOper(TO_PEN, static_cast(color)); } m_traceOper = oper; m_tracePos = m_object->GetPosition(); m_traceAngle = m_object->GetRotationY(); m_traceColor = color; } } // End of the registration of the design. Program generates the CBOT. void CProgrammableObjectImpl::TraceRecordStop() { TraceOper lastOper, curOper; float lastParam, curParam; m_traceRecord = false; std::stringstream buffer; buffer << "extern void object::AutoDraw()\n{\n"; lastOper = TO_STOP; lastParam = 0.0f; for ( int i=0 ; iImplements(ObjectInterfaceType::ProgramStorage)); Program* prog = dynamic_cast(*m_object).AddProgram(); prog->script->SendScript(buffer.str().c_str()); } // Saves an instruction CBOT. bool CProgrammableObjectImpl::TraceRecordOper(TraceOper oper, float param) { int i; i = m_traceRecordIndex; if ( i >= MAXTRACERECORD ) return false; m_traceRecordBuffer[i].oper = oper; m_traceRecordBuffer[i].param = param; m_traceRecordIndex = i+1; return true; } // Generates an instruction CBOT. bool CProgrammableObjectImpl::TraceRecordPut(std::stringstream& buffer, TraceOper oper, float param) { if ( oper == TO_ADVANCE ) { param /= g_unit; buffer << "\tmove(" << std::fixed << std::setprecision(1) << param << ");\n"; } if ( oper == TO_RECEDE ) { param /= g_unit; buffer << "\tmove(-" << std::fixed << std::setprecision(1) << param << ");\n"; } if ( oper == TO_TURN ) { param = -param*180.0f/Math::PI; buffer << "\tturn(" << static_cast(param) << ");\n"; } if ( oper == TO_PEN ) { TraceColor color = static_cast(static_cast(param)); if ( color == TraceColor::Default ) buffer << "\tpenup();\n"; else buffer << "\tpendown(" << TraceColorName(color) << ");\n"; } return true; } bool CProgrammableObjectImpl::IsTraceRecord() { return m_traceRecord; } void CProgrammableObjectImpl::SetCmdLine(unsigned int rank, float value) { if (rank == m_cmdLine.size()) { m_cmdLine.push_back(value); } else if (rank < m_cmdLine.size()) { m_cmdLine[rank] = value; } else { // should never happen assert(false); } } float CProgrammableObjectImpl::GetCmdLine(unsigned int rank) { if ( rank >= m_cmdLine.size() ) return 0.0f; return m_cmdLine[rank]; } std::vector& CProgrammableObjectImpl::GetCmdLine() { return m_cmdLine; }