Moved common interface implementations to separate classes

Additionaly, merged all "inappropariate bot" errors into one and renamed ERR_GENERIC -> ERR_UNKNOWN
master
krzys-h 2015-08-12 16:54:44 +02:00
parent 63d83185b5
commit f7d2f501bb
34 changed files with 1114 additions and 855 deletions

View File

@ -1400,9 +1400,6 @@ msgstr ""
msgid "Unknown command"
msgstr ""
msgid "Inappropriate bot"
msgstr ""
msgid "Impossible when flying"
msgstr ""
@ -1597,6 +1594,9 @@ msgstr ""
msgid "Do not use in this exercise"
msgstr ""
msgid "Inappropriate bot"
msgstr ""
msgid "Building completed"
msgstr ""

View File

@ -150,6 +150,9 @@ set(BASE_SOURCES
object/auto/autopowerstation.cpp
object/auto/autotower.cpp
object/drive_type.cpp
object/implementation/power_container_impl.cpp
object/implementation/programmable_impl.cpp
object/implementation/task_executor_impl.cpp
object/level/parser.cpp
object/level/parserexceptions.cpp
object/level/parserline.cpp

View File

@ -32,11 +32,10 @@
enum Error
{
ERR_OK = 0, //! < ok
ERR_GENERIC = 1, //! < any error
ERR_UNKNOWN = 1, //! < any error
ERR_CONTINUE = 2, //! < continues
ERR_STOP = 3, //! < stops
ERR_CMD = 4, //! < unknown command
ERR_MANIP_VEH = 100, //! < inappropriate vehicle
ERR_MANIP_FLY = 101, //! < impossible in flight
ERR_MANIP_BUSY = 102, //! < taking: hands already occupied
ERR_MANIP_NIL = 103, //! < taking: nothing has to take
@ -61,21 +60,16 @@ enum Error
ERR_BUILD_DISABLED = 132, //! < built: can not produce this object in this mission
ERR_BUILD_RESEARCH = 133, //! < built: can not produce not researched object
ERR_SEARCH_FLY = 140, //! < not possible in flight
ERR_SEARCH_VEH = 141, //! < inappropriate vehicle
ERR_SEARCH_MOTOR = 142, //! < impossible in movement
ERR_TERRA_VEH = 150, //! < inappropriate vehicle
ERR_TERRA_ENERGY = 151, //! < not enough energy
ERR_TERRA_FLOOR = 152, //! < inappropriate ground
ERR_TERRA_BUILDING = 153, //! < building too close
ERR_TERRA_OBJECT = 154, //! < object too close
ERR_FIRE_VEH = 160, //! < inappropriate vehicle
ERR_FIRE_ENERGY = 161, //! < not enough energy
ERR_FIRE_FLY = 162, //! < not possible in flight
ERR_RECOVER_VEH = 170, //! < inappropriate vehicle
ERR_RECOVER_ENERGY = 171, //! < not enough energy
ERR_RECOVER_NULL = 172, //! < lack of ruin
ERR_CONVERT_EMPTY = 180, //! < no stone was transformed
ERR_SHIELD_VEH = 190, //! < inappropriate vehicle
ERR_SHIELD_ENERGY = 191, //! < not enough energy
ERR_MOVE_IMPOSSIBLE = 200, //! < move impossible
ERR_FIND_IMPOSSIBLE = 201, //! < find impossible
@ -128,6 +122,7 @@ enum Error
ERR_OBLIGATORYTOKEN = 800, //! < compulsory instruction missing
ERR_PROHIBITEDTOKEN = 801, //! < instruction prohibited
ERR_AIM_IMPOSSIBLE = 900, //! < cannot aim at specified angle(s)
ERR_WRONG_BOT = 910, //! < inappropriate bot
INFO_FIRST = 10000, //! < first information
INFO_BUILD = 10001, //! < construction builded

View File

@ -581,9 +581,8 @@ void InitializeRestext()
stringsErr[ERR_GENERIC] = TR("Internal error - tell the developers");
stringsErr[ERR_UNKNOWN] = TR("Internal error - tell the developers");
stringsErr[ERR_CMD] = TR("Unknown command");
stringsErr[ERR_MANIP_VEH] = TR("Inappropriate bot");
stringsErr[ERR_MANIP_FLY] = TR("Impossible when flying");
stringsErr[ERR_MANIP_BUSY] = TR("Already carrying something");
stringsErr[ERR_MANIP_NIL] = TR("Nothing to grab");
@ -608,24 +607,19 @@ void InitializeRestext()
stringsErr[ERR_SEARCH_FLY] = TR("Impossible when flying");
stringsErr[ERR_BUILD_DISABLED] = TR("Can not produce this object in this mission");
stringsErr[ERR_BUILD_RESEARCH] = TR("Can not produce not researched object");
stringsErr[ERR_SEARCH_VEH] = TR("Inappropriate bot");
stringsErr[ERR_SEARCH_MOTOR] = TR("Impossible when moving");
stringsErr[ERR_TERRA_VEH] = TR("Inappropriate bot");
stringsErr[ERR_TERRA_ENERGY] = TR("Not enough energy");
stringsErr[ERR_TERRA_FLOOR] = TR("Ground inappropriate");
stringsErr[ERR_TERRA_BUILDING] = TR("Building too close");
stringsErr[ERR_TERRA_OBJECT] = TR("Object too close");
stringsErr[ERR_RECOVER_VEH] = TR("Inappropriate bot");
stringsErr[ERR_RECOVER_ENERGY] = TR("Not enough energy");
stringsErr[ERR_RECOVER_NULL] = TR("Nothing to recycle");
stringsErr[ERR_SHIELD_VEH] = TR("Inappropriate bot");
stringsErr[ERR_SHIELD_ENERGY] = TR("No more energy");
stringsErr[ERR_MOVE_IMPOSSIBLE] = TR("Error in instruction move");
stringsErr[ERR_FIND_IMPOSSIBLE] = TR("Object not found");
stringsErr[ERR_GOTO_IMPOSSIBLE] = TR("Goto: inaccessible destination");
stringsErr[ERR_GOTO_ITER] = TR("Goto: inaccessible destination");
stringsErr[ERR_GOTO_BUSY] = TR("Goto: destination occupied");
stringsErr[ERR_FIRE_VEH] = TR("Inappropriate bot");
stringsErr[ERR_FIRE_ENERGY] = TR("Not enough energy");
stringsErr[ERR_FIRE_FLY] = TR("Impossible when flying");
stringsErr[ERR_CONVERT_EMPTY] = TR("No titanium ore to convert");
@ -674,6 +668,7 @@ void InitializeRestext()
stringsErr[ERR_ENEMY_OBJECT] = TR("Unable to control enemy objects");
stringsErr[ERR_OBLIGATORYTOKEN] = TR("\"%s\" missing in this exercise");
stringsErr[ERR_PROHIBITEDTOKEN] = TR("Do not use in this exercise");
stringsErr[ERR_WRONG_BOT] = TR("Inappropriate bot");
stringsErr[INFO_BUILD] = TR("Building completed");
stringsErr[INFO_CONVERT] = TR("Titanium available");

View File

@ -107,7 +107,7 @@ void CAuto::Start(int param)
Error CAuto::StartAction(int param)
{
return ERR_GENERIC;
return ERR_UNKNOWN;
}
// Gete a type.

View File

@ -103,7 +103,7 @@ Error CAutoDestroyer::StartAction(int param)
m_bExplo = false;
}
else
return ERR_GENERIC;
return ERR_UNKNOWN;
}
return ERR_OK;
}

View File

@ -153,7 +153,7 @@ Error CAutoFactory::StartAction(int param)
m_speed = 1.0f/3.0f;
return ERR_OK;
}
return ERR_GENERIC;
return ERR_UNKNOWN;
}
@ -219,10 +219,10 @@ bool CAutoFactory::EventProcess(const Event &event)
type = ObjectTypeFromFactoryButton(event.type);
Error err = StartAction(type);
if( err != ERR_OK && err != ERR_GENERIC )
if( err != ERR_OK && err != ERR_UNKNOWN )
m_main->DisplayError(err, m_object);
if( err != ERR_GENERIC )
if( err != ERR_UNKNOWN )
return false;
}

View File

@ -120,7 +120,7 @@ Error CAutoLabo::StartAction(int param)
{
if ( m_phase != ALAP_WAIT )
{
return ERR_GENERIC;
return ERR_UNKNOWN;
}
m_research = static_cast<ResearchType>(param);
@ -175,14 +175,14 @@ bool CAutoLabo::EventProcess(const Event &event)
if ( m_object->GetSelect() ) // center selected?
{
Error err = ERR_GENERIC;
Error err = ERR_UNKNOWN;
if ( event.type == EVENT_OBJECT_RiPAW ) err = StartAction(RESEARCH_iPAW);
if ( event.type == EVENT_OBJECT_RiGUN ) err = StartAction(RESEARCH_iGUN);
if( err != ERR_OK && err != ERR_GENERIC )
if( err != ERR_OK && err != ERR_UNKNOWN )
m_main->DisplayError(err, m_object);
if( err != ERR_GENERIC )
if( err != ERR_UNKNOWN )
return false;
}

View File

@ -101,7 +101,7 @@ Error CAutoResearch::StartAction(int param)
{
if ( m_phase != ALP_WAIT )
{
return ERR_GENERIC;
return ERR_UNKNOWN;
}
m_research = static_cast<ResearchType>(param);
@ -167,7 +167,7 @@ bool CAutoResearch::EventProcess(const Event &event)
if ( m_object->GetSelect() ) // center selected?
{
Error err = ERR_GENERIC;
Error err = ERR_UNKNOWN;
if ( event.type == EVENT_OBJECT_RTANK ) err = StartAction(RESEARCH_TANK);
if ( event.type == EVENT_OBJECT_RFLY ) err = StartAction(RESEARCH_FLY);
if ( event.type == EVENT_OBJECT_RTHUMP ) err = StartAction(RESEARCH_THUMP);
@ -177,10 +177,10 @@ bool CAutoResearch::EventProcess(const Event &event)
if ( event.type == EVENT_OBJECT_RSHIELD ) err = StartAction(RESEARCH_SHIELD);
if ( event.type == EVENT_OBJECT_RATOMIC ) err = StartAction(RESEARCH_ATOMIC);
if( err != ERR_OK && err != ERR_GENERIC )
if( err != ERR_OK && err != ERR_UNKNOWN )
m_main->DisplayError(err, m_object);
if( err != ERR_GENERIC )
if( err != ERR_UNKNOWN )
return false;
}

View File

@ -0,0 +1,38 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsiteс.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/power_container_impl.h"
CPowerContainerObjectImpl::CPowerContainerObjectImpl(ObjectInterfaceTypes& types, CObject* object)
: CPowerContainerObject(types)
, m_energyLevel(1.0f)
{}
CPowerContainerObjectImpl::~CPowerContainerObjectImpl()
{}
void CPowerContainerObjectImpl::SetEnergyLevel(float level)
{
m_energyLevel = level;
}
float CPowerContainerObjectImpl::GetEnergyLevel()
{
return m_energyLevel;
}

View File

@ -0,0 +1,37 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsiteс.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "object/interface/power_container_object.h"
class CObject;
class CPowerContainerObjectImpl : public CPowerContainerObject
{
public:
explicit CPowerContainerObjectImpl(ObjectInterfaceTypes& types, CObject* object);
virtual ~CPowerContainerObjectImpl();
void SetEnergyLevel(float level) override;
float GetEnergyLevel() override;
private:
float m_energyLevel;
};

View File

@ -0,0 +1,622 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsiteс.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 "math/all.h"
#include "object/object.h"
#include "object/old_object.h"
#include "object/robotmain.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 <algorithm>
#include <iomanip>
CProgrammableObjectImpl::CProgrammableObjectImpl(ObjectInterfaceTypes& types, CObject* object)
: CProgrammableObject(types)
, m_object(object)
, m_activity(true)
, m_cmdLine()
, m_program()
, m_currentProgram(nullptr)
, m_activeVirus(false)
, m_scriptRun(nullptr)
, m_soluceName("")
, m_traceRecord(false)
{
assert(m_object != nullptr);
assert(m_object->Implements(ObjectInterfaceType::TaskExecutor));
}
CProgrammableObjectImpl::~CProgrammableObjectImpl()
{}
bool CProgrammableObjectImpl::EventProcess(const Event &event)
{
if (event.type == EVENT_FRAME)
{
if ( m_object->GetRuin() && IsProgram() )
{
StopProgram();
}
if ( GetActivity() )
{
if ( IsProgram() ) // current program?
{
if ( m_currentProgram->script->Continue() )
{
StopProgram();
}
}
if ( m_traceRecord ) // registration of the design in progress?
{
TraceRecordFrame();
}
}
}
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<CControllableObject*>(m_object)->GetTrainer())
CRobotMain::GetInstancePointer()->StartMissionTimer();
}
}
void CProgrammableObjectImpl::StopProgram()
{
if ( m_currentProgram != nullptr )
{
m_currentProgram->script->Stop();
}
m_currentProgram = nullptr;
m_object->UpdateInterface();
}
bool CProgrammableObjectImpl::IsProgram()
{
return m_currentProgram != nullptr;
}
// Introduces a virus into a program.
// Returns true if it was inserted.
bool CProgrammableObjectImpl::IntroduceVirus()
{
if(m_program.size() == 0) return false;
for ( int i=0 ; i<50 ; i++ )
{
int programIndex = rand() % m_program.size();
if ( m_program[programIndex]->script->IntroduceVirus() ) // tries to introduce
{
m_activeVirus = true; // active virus
return true;
}
}
return false;
}
// Active Virus indicates that the object is contaminated. Unlike ch'tites (??? - Programerus)
// letters which automatically disappear after a while,
// ActiveVirus does not disappear after you edit the program
// (Even if the virus is not fixed).
void CProgrammableObjectImpl::SetActiveVirus(bool bActive)
{
m_activeVirus = bActive;
if ( !m_activeVirus ) // virus disabled?
{
m_object->SetVirusMode(false); // chtites (??? - Programerus) letters also
}
}
bool CProgrammableObjectImpl::GetActiveVirus()
{
return m_activeVirus;
}
Program* CProgrammableObjectImpl::AddProgram()
{
assert(m_object->Implements(ObjectInterfaceType::Old)); //TODO
auto program = MakeUnique<Program>();
program->script = MakeUnique<CScript>(dynamic_cast<COldObject*>(this));
program->readOnly = false;
program->runnable = true;
Program* prog = program.get();
AddProgram(std::move(program));
return prog;
}
void CProgrammableObjectImpl::AddProgram(std::unique_ptr<Program> program)
{
m_program.push_back(std::move(program));
m_object->UpdateInterface();
}
void CProgrammableObjectImpl::RemoveProgram(Program* program)
{
if(m_currentProgram == program)
{
StopProgram();
}
m_program.erase(
std::remove_if(m_program.begin(), m_program.end(),
[program](std::unique_ptr<Program>& prog) { return prog.get() == program; }),
m_program.end());
m_object->UpdateInterface();
}
Program* CProgrammableObjectImpl::CloneProgram(Program* program)
{
Program* newprog = AddProgram();
// TODO: Is there any reason CScript doesn't have a function to get the program code directly?
Ui::CEdit* edit = new Ui::CEdit();
edit->SetMaxChar(Ui::EDITSTUDIOMAX);
program->script->PutScript(edit, "");
newprog->script->GetScript(edit);
delete edit;
return newprog;
}
std::vector<std::unique_ptr<Program>>& CProgrammableObjectImpl::GetPrograms()
{
return m_program;
}
int CProgrammableObjectImpl::GetProgramCount()
{
return static_cast<int>(m_program.size());
}
int CProgrammableObjectImpl::GetProgramIndex(Program* program)
{
for(unsigned int i = 0; i < m_program.size(); i++)
{
if(m_program[i].get() == program)
{
return i;
}
}
return -1;
}
int CProgrammableObjectImpl::GetProgram()
{
if(m_currentProgram == nullptr)
return -1;
for(unsigned int i = 0; i < m_program.size(); i++)
{
if(m_program[i].get() == m_currentProgram)
{
return i;
}
}
return -1;
}
Program* CProgrammableObjectImpl::GetProgram(int index)
{
if(index < 0 || index >= static_cast<int>(m_program.size()))
return nullptr;
return m_program[index].get();
}
Program* CProgrammableObjectImpl::GetOrAddProgram(int index)
{
if(index < 0)
return nullptr;
if(index < static_cast<int>(m_program.size()))
return m_program[index].get();
for(int i = m_program.size(); i < index; i++)
{
AddProgram();
}
return AddProgram();
}
// Name management scripts to load.
void CProgrammableObjectImpl::SetScriptRun(Program* program)
{
m_scriptRun = program;
}
Program* CProgrammableObjectImpl::GetScriptRun()
{
return m_scriptRun;
}
void CProgrammableObjectImpl::SetSoluceName(const std::string& name)
{
m_soluceName = name;
}
const std::string& CProgrammableObjectImpl::GetSoluceName()
{
return m_soluceName;
}
// Load a script solution, in the first free script.
// If there is already an identical script, nothing is loaded.
bool CProgrammableObjectImpl::ReadSoluce(const std::string& filename)
{
Program* prog = AddProgram();
if ( !ReadProgram(prog, filename) ) return false; // load solution
prog->readOnly = true;
for(unsigned int i = 0; i < m_program.size(); i++)
{
if(m_program[i].get() == prog) continue;
//TODO: This is bad. It's very sensitive to things like \n vs \r\n etc.
if ( m_program[i]->script->Compare(prog->script.get()) ) // the same already?
{
m_program[i]->readOnly = true; // Mark is as read-only
RemoveProgram(prog);
return false;
}
}
return true;
}
// Load a script with a text file.
bool CProgrammableObjectImpl::ReadProgram(Program* program, const std::string& filename)
{
if ( program->script->ReadScript(filename.c_str()) ) return true;
return false;
}
// Indicates whether a program is compiled correctly.
bool CProgrammableObjectImpl::GetCompile(Program* program)
{
return program->script->GetCompile();
}
// Saves a script in a text file.
bool CProgrammableObjectImpl::WriteProgram(Program* program, const std::string& filename)
{
if ( program->script->WriteScript(filename.c_str()) ) return true;
return false;
}
// Load a stack of script implementation from a file.
bool CProgrammableObjectImpl::ReadStack(FILE *file)
{
short op;
fRead(&op, sizeof(short), 1, file);
if ( op == 1 ) // run ?
{
fRead(&op, sizeof(short), 1, file); // program rank
if ( op >= 0 )
{
assert(op < static_cast<int>(m_program.size()));
//TODO: m_selScript = op;
if ( !m_program[op]->script->ReadStack(file) ) return false;
}
}
return true;
}
// Save the script implementation stack of a file.
bool CProgrammableObjectImpl::WriteStack(FILE *file)
{
short op;
if ( m_currentProgram != nullptr && // current program?
m_currentProgram->script->IsRunning() )
{
op = 1; // run
fWrite(&op, sizeof(short), 1, file);
op = GetProgram();
fWrite(&op, sizeof(short), 1, file);
return m_currentProgram->script->WriteStack(file);
}
op = 0; // stop
fWrite(&op, sizeof(short), 1, file);
return true;
}
const int MAXTRACERECORD = 1000;
// Start of registration of the design.
void CProgrammableObjectImpl::TraceRecordStart()
{
if (m_traceRecord)
{
TraceRecordStop();
}
assert(m_object->Implements(ObjectInterfaceType::Old)); // TODO
CMotionVehicle* motionVehicle = dynamic_cast<CMotionVehicle*>(dynamic_cast<COldObjectInterface*>(m_object)->GetMotion());
assert(motionVehicle != nullptr);
m_traceRecord = true;
m_traceOper = TO_STOP;
m_tracePos = m_object->GetPosition();
m_traceAngle = m_object->GetRotationY();
if ( motionVehicle->GetTraceDown() ) // pencil down?
{
m_traceColor = motionVehicle->GetTraceColor();
}
else // pen up?
{
m_traceColor = TraceColor::Default;
}
m_traceRecordBuffer = MakeUniqueArray<TraceRecord>(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::Old)); // TODO
CMotionVehicle* motionVehicle = dynamic_cast<CMotionVehicle*>(dynamic_cast<COldObjectInterface*>(m_object)->GetMotion());
assert(motionVehicle != nullptr);
CPhysics* physics = dynamic_cast<COldObjectInterface*>(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 ( motionVehicle->GetTraceDown() ) // pencil down?
{
color = motionVehicle->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<float>(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 ; i<m_traceRecordIndex ; i++ )
{
curOper = m_traceRecordBuffer[i].oper;
curParam = m_traceRecordBuffer[i].param;
if ( curOper == lastOper )
{
if ( curOper == TO_PEN )
{
lastParam = curParam;
}
else
{
lastParam += curParam;
}
}
else
{
TraceRecordPut(buffer, lastOper, lastParam);
lastOper = curOper;
lastParam = curParam;
}
}
TraceRecordPut(buffer, lastOper, lastParam);
m_traceRecordBuffer.reset();
buffer << "}\n";
Program* prog = 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<int>(param) << ");\n";
}
if ( oper == TO_PEN )
{
TraceColor color = static_cast<TraceColor>(static_cast<int>(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<float>& CProgrammableObjectImpl::GetCmdLine()
{
return m_cmdLine;
}

View File

@ -0,0 +1,130 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsiteс.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "object/interface/interactive_object.h"
#include "object/interface/programmable_object.h"
#include "object/trace_color.h"
#include "math/vector.h"
#include <sstream>
class CObject;
enum TraceOper
{
TO_STOP = 0, // stop
TO_ADVANCE = 1, // advance
TO_RECEDE = 2, // back
TO_TURN = 3, // rotate
TO_PEN = 4, // color change
};
struct TraceRecord
{
TraceOper oper;
float param;
};
class CProgrammableObjectImpl : public CProgrammableObject
{
public:
explicit CProgrammableObjectImpl(ObjectInterfaceTypes& types, CObject* object);
virtual ~CProgrammableObjectImpl();
bool EventProcess(const Event& event);
bool IsProgram() override;
void RunProgram(Program* program) override;
int GetProgram() override;
void StopProgram() override;
bool IntroduceVirus() override;
void SetActiveVirus(bool bActive) override;
bool GetActiveVirus() override;
void SetScriptRun(Program* rank) override;
Program* GetScriptRun() override;
void SetSoluceName(const std::string& name) override;
const std::string& GetSoluceName() override;
bool ReadSoluce(const std::string& filename) override;
bool ReadProgram(Program* program, const std::string& filename) override;
bool GetCompile(Program* program) override;
bool WriteProgram(Program* program, const std::string& filename) override;
bool ReadStack(FILE *file) override;
bool WriteStack(FILE *file) override;
Program* AddProgram() override;
void AddProgram(std::unique_ptr<Program> program) override;
void RemoveProgram(Program* program) override;
Program* CloneProgram(Program* program) override;
std::vector<std::unique_ptr<Program>>& GetPrograms() override;
int GetProgramCount() override;
Program* GetProgram(int index) override;
Program* GetOrAddProgram(int index) override;
int GetProgramIndex(Program* program) override;
void TraceRecordStart() override;
void TraceRecordStop() override;
bool IsTraceRecord() override;
void SetActivity(bool bMode) override;
bool GetActivity() override;
void SetCmdLine(unsigned int rank, float value);
float GetCmdLine(unsigned int rank) override;
std::vector<float>& GetCmdLine();
private:
//! Save current status to recording buffer
void TraceRecordFrame();
//! Save this operation to recording buffer
bool TraceRecordOper(TraceOper oper, float param);
//! Convert this recording operation to CBot instruction
bool TraceRecordPut(std::stringstream& buffer, TraceOper oper, float param);
private:
CObject* m_object;
private:
bool m_activity;
std::vector<float> m_cmdLine;
std::vector<std::unique_ptr<Program>> m_program;
Program* m_currentProgram;
bool m_activeVirus;
Program* m_scriptRun;
std::string m_soluceName;
bool m_traceRecord;
TraceOper m_traceOper;
Math::Vector m_tracePos;
float m_traceAngle;
TraceColor m_traceColor;
int m_traceRecordIndex;
std::unique_ptr<TraceRecord[]> m_traceRecordBuffer;
};

View File

@ -0,0 +1,120 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsiteс.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/task_executor_impl.h"
#include "object/object.h"
#include "object/task/taskmanager.h"
CTaskExecutorObjectImpl::CTaskExecutorObjectImpl(ObjectInterfaceTypes& types, CObject* object)
: CTaskExecutorObject(types)
, m_object(object)
{}
CTaskExecutorObjectImpl::~CTaskExecutorObjectImpl()
{}
bool CTaskExecutorObjectImpl::EventProcess(const Event &event)
{
// NOTE: This function CAN'T BE CALLED BETWEEN CTaskManager::EventProcess AND CScriptFunctions::Process, otherwise weird stuff may happen to scripts (they'll be stuck executing the same task over and over again)
EndedTask();
if ( m_foregroundTask != nullptr )
{
m_foregroundTask->EventProcess(event);
}
if ( m_backgroundTask != nullptr )
{
m_backgroundTask->EventProcess(event);
}
return true;
}
bool CTaskExecutorObjectImpl::IsForegroundTask()
{
return m_foregroundTask != nullptr;
}
bool CTaskExecutorObjectImpl::IsBackgroundTask()
{
return m_backgroundTask != nullptr;
}
CTaskManager* CTaskExecutorObjectImpl::GetForegroundTask()
{
return m_foregroundTask.get();
}
CTaskManager* CTaskExecutorObjectImpl::GetBackgroundTask()
{
return m_backgroundTask.get();
}
// Stops the current task.
void CTaskExecutorObjectImpl::StopForegroundTask()
{
if (m_foregroundTask != nullptr)
{
m_foregroundTask->Abort();
m_foregroundTask.reset();
}
}
// Stops the current secondary task.
void CTaskExecutorObjectImpl::StopBackgroundTask()
{
if (m_backgroundTask != nullptr)
{
m_backgroundTask->Abort();
m_backgroundTask.reset();
}
}
// Completes the task when the time came.
Error CTaskExecutorObjectImpl::EndedTask()
{
if (m_backgroundTask != nullptr) // current task?
{
Error err = m_backgroundTask->IsEnded();
if ( err != ERR_CONTINUE ) // job ended?
{
m_backgroundTask.reset();
m_object->UpdateInterface();
}
}
if (m_foregroundTask != nullptr) // current task?
{
Error err = m_foregroundTask->IsEnded();
if ( err != ERR_CONTINUE ) // job ended?
{
m_foregroundTask.reset();
m_object->UpdateInterface();
}
return err;
}
return ERR_STOP;
}

View File

@ -0,0 +1,77 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsiteс.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "object/interface/task_executor_object.h"
#include <memory>
class CObject;
class CTaskManager;
class CTaskExecutorObjectImpl : public CTaskExecutorObject
{
public:
explicit CTaskExecutorObjectImpl(ObjectInterfaceTypes& types, CObject* object);
virtual ~CTaskExecutorObjectImpl();
bool EventProcess(const Event& event);
bool IsForegroundTask() override;
bool IsBackgroundTask() override;
CTaskManager* GetForegroundTask() override;
CTaskManager* GetBackgroundTask() override;
void StopForegroundTask() override;
void StopBackgroundTask() override;
Error StartTaskTake() { return ERR_WRONG_BOT; }
Error StartTaskManip(TaskManipOrder order, TaskManipArm arm) { return ERR_WRONG_BOT; }
Error StartTaskFlag(TaskFlagOrder order, int rank) { return ERR_WRONG_BOT; }
Error StartTaskBuild(ObjectType type) { return ERR_WRONG_BOT; }
Error StartTaskSearch() { return ERR_WRONG_BOT; }
Error StartTaskDeleteMark() { return ERR_WRONG_BOT; }
Error StartTaskTerraform() { return ERR_WRONG_BOT; }
Error StartTaskRecover() { return ERR_WRONG_BOT; }
Error StartTaskFire(float delay) { return ERR_WRONG_BOT; }
Error StartTaskFireAnt(Math::Vector impact) { return ERR_WRONG_BOT; }
Error StartTaskSpiderExplo() { return ERR_WRONG_BOT; }
Error StartTaskPen(bool down, TraceColor color = TraceColor::Default) { return ERR_WRONG_BOT; }
Error StartTaskWait(float time) { return ERR_UNKNOWN; }
Error StartTaskAdvance(float length) { return ERR_UNKNOWN; }
Error StartTaskTurn(float angle) { return ERR_UNKNOWN; }
Error StartTaskGoto(Math::Vector pos, float altitude, TaskGotoGoal goalMode, TaskGotoCrash crashMode) { return ERR_UNKNOWN; }
Error StartTaskInfo(const char *name, float value, float power, bool bSend) { return ERR_UNKNOWN; }
Error StartTaskShield(TaskShieldMode mode, float delay = 1000.0f) { return ERR_WRONG_BOT; }
Error StartTaskGunGoal(float dirV, float dirH) { return ERR_WRONG_BOT; }
private:
Error EndedTask();
protected:
std::unique_ptr<CTaskManager> m_foregroundTask;
std::unique_ptr<CTaskManager> m_backgroundTask;
private:
CObject* m_object;
};

View File

@ -61,13 +61,13 @@ public:
virtual void SetScriptRun(Program* rank) = 0;
virtual Program* GetScriptRun() = 0;
virtual void SetSoluceName(char *name) = 0;
virtual char* GetSoluceName() = 0;
virtual void SetSoluceName(const std::string& name) = 0;
virtual const std::string& GetSoluceName() = 0;
virtual bool ReadSoluce(char* filename) = 0;
virtual bool ReadProgram(Program* program, const char* filename) = 0;
virtual bool ReadSoluce(const std::string& filename) = 0;
virtual bool ReadProgram(Program* program, const std::string& filename) = 0;
virtual bool GetCompile(Program* program) = 0;
virtual bool WriteProgram(Program* program, const char* filename) = 0;
virtual bool WriteProgram(Program* program, const std::string& filename) = 0;
virtual bool ReadStack(FILE *file) = 0;
virtual bool WriteStack(FILE *file) = 0;

View File

@ -83,6 +83,9 @@ public:
//! Reads object properties from line in level file
virtual void Read(CLevelParserLine* line) = 0;
//! Updates all interface controls
virtual void UpdateInterface() {};
//! Check if object implements the given type of interface
inline bool Implements(ObjectInterfaceType type) const
{

View File

@ -86,8 +86,6 @@ static float debug_arm2 = 0.0f;
static float debug_arm3 = 0.0f;
#endif
const int MAXTRACERECORD = 1000;
// Object's constructor.
@ -95,14 +93,14 @@ COldObject::COldObject(int id)
: CObject(id, OBJECT_NULL)
, CInteractiveObject(m_implementedInterfaces)
, CTransportableObject(m_implementedInterfaces)
, CTaskExecutorObject(m_implementedInterfaces)
, CProgrammableObject(m_implementedInterfaces)
, CTaskExecutorObjectImpl(m_implementedInterfaces, this)
, CProgrammableObjectImpl(m_implementedInterfaces, this)
, CJostleableObject(m_implementedInterfaces)
, CCarrierObject(m_implementedInterfaces)
, CPoweredObject(m_implementedInterfaces)
, CMovableObject(m_implementedInterfaces)
, CControllableObject(m_implementedInterfaces)
, CPowerContainerObject(m_implementedInterfaces)
, CPowerContainerObjectImpl(m_implementedInterfaces, this)
{
// A bit of a hack since we don't have subclasses yet, set externally in SetProgrammable()
m_implementedInterfaces[static_cast<int>(ObjectInterfaceType::Programmable)] = false;
@ -132,7 +130,6 @@ COldObject::COldObject(int id)
m_cargo = 0;
m_transporter = 0;
m_transporterLink = 0;
m_energy = 1.0f;
m_shield = 1.0f;
m_range = 0.0f;
m_transparency = 0.0f;
@ -185,22 +182,11 @@ COldObject::COldObject(int id)
m_partiSel[i] = -1;
}
m_cmdLine.clear();
m_activity = true;
m_currentProgram = nullptr;
m_bActiveVirus = false;
m_time = 0.0f;
m_burnTime = 0.0f;
m_buttonAxe = EVENT_NULL;
m_scriptRun = nullptr;
m_soluceName[0] = 0;
m_traceRecord = false;
DeleteAllCrashSpheres();
}
@ -806,7 +792,7 @@ void COldObject::Write(CLevelParserLine* line)
// Sets the parameters of the command line.
CLevelParserParamVec cmdline;
for(float value : m_cmdLine)
for(float value : GetCmdLine())
{
cmdline.push_back(MakeUnique<CLevelParserParam>(value));
}
@ -820,7 +806,7 @@ void COldObject::Write(CLevelParserLine* line)
if ( Implements(ObjectInterfaceType::Programmable) )
{
line->AddParam("bVirusActive", MakeUnique<CLevelParserParam>(m_bActiveVirus));
line->AddParam("bVirusActive", MakeUnique<CLevelParserParam>(GetActiveVirus()));
}
if ( Implements(ObjectInterfaceType::TaskExecutor) )
@ -891,7 +877,7 @@ void COldObject::Read(CLevelParserLine* line)
if (Implements(ObjectInterfaceType::Programmable))
{
m_bActiveVirus = line->GetParam("bVirusActive")->AsBool(false);
SetActiveVirus(line->GetParam("bVirusActive")->AsBool(false));
}
if (Implements(ObjectInterfaceType::TaskExecutor))
@ -1382,29 +1368,6 @@ float COldObject::GetInfoReturn()
return m_infoReturn;
}
void COldObject::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 COldObject::GetCmdLine(unsigned int rank)
{
if ( rank >= m_cmdLine.size() ) return 0.0f;
return m_cmdLine[rank];
}
// Returns matrices of an object portion.
@ -1735,10 +1698,10 @@ void COldObject::FlatParent()
void COldObject::UpdateEnergyMapping()
{
if (Math::IsEqual(m_energy, m_lastEnergy, 0.01f))
if (Math::IsEqual(GetEnergyLevel(), m_lastEnergy, 0.01f))
return;
m_lastEnergy = m_energy;
m_lastEnergy = GetEnergyLevel();
Gfx::Material mat;
mat.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f); // white
@ -1763,7 +1726,7 @@ void COldObject::UpdateEnergyMapping()
b = 3.0f; // dimensions of the battery (according to y)
}
float i = 0.50f+0.25f*m_energy; // origin
float i = 0.50f+0.25f*GetEnergyLevel(); // origin
float s = i+0.25f; // width
float au = (s-i)/(b-a);
@ -1822,15 +1785,8 @@ bool COldObject::EventProcess(const Event &event)
#endif
}
if ( m_foregroundTask != nullptr )
{
m_foregroundTask->EventProcess(event);
}
if ( m_backgroundTask != nullptr )
{
m_backgroundTask->EventProcess(event);
}
// NOTE: This should be called befoce CProgrammableObjectImpl::EventProcess, see the other note inside this function
if (!CTaskExecutorObjectImpl::EventProcess(event)) return true;
if ( m_physics != nullptr )
{
@ -1848,14 +1804,6 @@ bool COldObject::EventProcess(const Event &event)
}
}
if (Implements(ObjectInterfaceType::Programmable))
{
if ( GetRuin() && m_currentProgram != nullptr )
{
StopProgram();
}
}
if (Implements(ObjectInterfaceType::Movable) && m_physics != nullptr)
{
bool deselectedStop = !GetSelect();
@ -1990,6 +1938,8 @@ bool COldObject::EventProcess(const Event &event)
if (!m_motion->EventProcess(event)) return false;
}
if (!CProgrammableObjectImpl::EventProcess(event)) return true;
if ( event.type == EVENT_FRAME )
{
return EventFrame(event);
@ -2025,28 +1975,6 @@ bool COldObject::EventFrame(const Event &event)
UpdateTransformObject();
UpdateSelectParticle();
if (Implements(ObjectInterfaceType::Programmable))
{
if ( GetActivity() )
{
if ( m_currentProgram != nullptr ) // current program?
{
if ( m_currentProgram->script->Continue() )
{
StopProgram();
}
}
if ( m_traceRecord ) // registration of the design in progress?
{
TraceRecordFrame();
}
}
}
// NOTE: This MUST be called AFTER CScriptFunctions::Process, otherwise weird stuff may happen to scripts
EndedTask();
return true;
}
@ -2292,25 +2220,6 @@ float COldObject::GetAbsTime()
}
// Management of energy contained in a battery.
// Single subject possesses the battery energy, but not the vehicle that carries the battery!
void COldObject::SetEnergyLevel(float level)
{
if ( level < 0.0f ) level = 0.0f;
if ( level > 1.0f ) level = 1.0f;
m_energy = level;
}
float COldObject::GetEnergyLevel()
{
if ( m_type != OBJECT_POWER &&
m_type != OBJECT_ATOMIC &&
m_type != OBJECT_STATION &&
m_type != OBJECT_ENERGY ) return 0.0f;
return m_energy;
}
float COldObject::GetCapacity()
{
return m_type == OBJECT_ATOMIC ? 10.0f : 1.0f;
@ -3310,603 +3219,25 @@ Error COldObject::StartTaskGunGoal(float dirV, float dirH)
return err;
}
// Indicates whether the object is busy with a task.
bool COldObject::IsForegroundTask()
{
return (m_foregroundTask.get() != nullptr);
}
bool COldObject::IsBackgroundTask()
{
return (m_backgroundTask.get() != nullptr);
}
CTaskManager* COldObject::GetForegroundTask()
{
return m_foregroundTask.get();
}
CTaskManager* COldObject::GetBackgroundTask()
{
return m_backgroundTask.get();
}
// Stops the current task.
void COldObject::StopForegroundTask()
{
if (m_foregroundTask != nullptr)
{
m_foregroundTask->Abort();
m_foregroundTask.reset();
}
}
// Stops the current secondary task.
void COldObject::StopBackgroundTask()
{
if (m_backgroundTask != nullptr)
{
m_backgroundTask->Abort();
m_backgroundTask.reset();
}
}
// Completes the task when the time came.
Error COldObject::EndedTask()
{
if (m_backgroundTask.get() != nullptr) // current task?
{
Error err = m_backgroundTask->IsEnded();
if ( err != ERR_CONTINUE ) // job ended?
{
m_backgroundTask.reset();
UpdateInterface();
}
}
if (m_foregroundTask.get() != nullptr) // current task?
{
Error err = m_foregroundTask->IsEnded();
if ( err != ERR_CONTINUE ) // job ended?
{
m_foregroundTask.reset();
UpdateInterface();
}
return err;
}
return ERR_STOP;
}
// Management of the activity of an object.
void COldObject::SetActivity(bool activity)
{
m_activity = activity;
}
bool COldObject::GetActivity()
{
return m_activity;
}
void COldObject::UpdateInterface()
{
if (m_objectInterface != nullptr && GetSelect())
{
m_objectInterface->UpdateInterface();
}
CreateSelectParticle();
m_main->UpdateShortcuts();
}
// Stops the running program.
void COldObject::StopProgram()
{
StopForegroundTask();
if ( m_type == OBJECT_HUMAN ||
m_type == OBJECT_TECH ) return;
if ( m_currentProgram != nullptr )
{
m_currentProgram->script->Stop();
}
m_currentProgram = nullptr;
CProgrammableObjectImpl::StopProgram();
//TODO: I don't want CProgrammableObjectImpl to depend on motion and physics, refactor this somehow
m_physics->SetMotorSpeedX(0.0f);
m_physics->SetMotorSpeedY(0.0f);
m_physics->SetMotorSpeedZ(0.0f);
m_motion->SetAction(-1);
UpdateInterface();
m_main->UpdateShortcuts();
CreateSelectParticle();
}
// Introduces a virus into a program.
// Returns true if it was inserted.
bool COldObject::IntroduceVirus()
{
if(m_program.size() == 0) return false;
for ( int i=0 ; i<50 ; i++ )
{
int j = rand()%m_program.size();
if ( m_program[j]->script->IntroduceVirus() ) // tries to introduce
{
m_bActiveVirus = true; // active virus
return true;
}
}
return false;
}
// Active Virus indicates that the object is contaminated. Unlike ch'tites (??? - Programerus)
// letters which automatically disappear after a while,
// ActiveVirus does not disappear after you edit the program
// (Even if the virus is not fixed).
void COldObject::SetActiveVirus(bool bActive)
{
m_bActiveVirus = bActive;
if ( !m_bActiveVirus ) // virus disabled?
{
SetVirusMode(false); // chtites (??? - Programerus) letters also
}
}
bool COldObject::GetActiveVirus()
{
return m_bActiveVirus;
}
// Indicates whether a program is running.
bool COldObject::IsProgram()
{
return m_currentProgram != nullptr;
}
// Starts a program.
void COldObject::RunProgram(Program* program)
{
if ( program->script->Run() )
{
m_currentProgram = program; // start new program
UpdateInterface();
CreateSelectParticle();
m_main->UpdateShortcuts();
if(GetTrainer())
m_main->StartMissionTimer();
}
}
// Returns the current program.
int COldObject::GetProgram()
{
if(m_currentProgram == nullptr)
return -1;
for(unsigned int i = 0; i < m_program.size(); i++)
{
if(m_program[i].get() == m_currentProgram)
{
return i;
}
}
return -1;
}
// Name management scripts to load.
void COldObject::SetScriptRun(Program* program)
{
m_scriptRun = program;
}
Program* COldObject::GetScriptRun()
{
return m_scriptRun;
}
void COldObject::SetSoluceName(char *name)
{
strcpy(m_soluceName, name);
}
char* COldObject::GetSoluceName()
{
return m_soluceName;
}
// Load a script solution, in the first free script.
// If there is already an identical script, nothing is loaded.
bool COldObject::ReadSoluce(char* filename)
{
Program* prog = AddProgram();
if ( !ReadProgram(prog, filename) ) return false; // load solution
prog->readOnly = true;
for(unsigned int i = 0; i < m_program.size(); i++)
{
if(m_program[i].get() == prog) continue;
//TODO: This is bad. It's very sensitive to things like \n vs \r\n etc.
if ( m_program[i]->script->Compare(prog->script.get()) ) // the same already?
{
m_program[i]->readOnly = true; // Mark is as read-only
RemoveProgram(prog);
return false;
}
}
return true;
}
// Load a script with a text file.
bool COldObject::ReadProgram(Program* program, const char* filename)
{
if ( program->script->ReadScript(filename) ) return true;
return false;
}
// Indicates whether a program is compiled correctly.
bool COldObject::GetCompile(Program* program)
{
return program->script->GetCompile();
}
// Saves a script in a text file.
bool COldObject::WriteProgram(Program* program, const char* filename)
{
if ( program->script->WriteScript(filename) ) return true;
return false;
}
// Load a stack of script implementation from a file.
bool COldObject::ReadStack(FILE *file)
{
short op;
fRead(&op, sizeof(short), 1, file);
if ( op == 1 ) // run ?
{
fRead(&op, sizeof(short), 1, file); // program rank
if ( op >= 0 )
{
assert(op < static_cast<int>(m_program.size())); //TODO: is it good?
//TODO: m_selScript = op;
if ( !m_program[op]->script->ReadStack(file) ) return false;
}
}
return true;
}
// Save the script implementation stack of a file.
bool COldObject::WriteStack(FILE *file)
{
short op;
if ( m_currentProgram != nullptr && // current program?
m_currentProgram->script->IsRunning() )
{
op = 1; // run
fWrite(&op, sizeof(short), 1, file);
op = GetProgram();
fWrite(&op, sizeof(short), 1, file);
return m_currentProgram->script->WriteStack(file);
}
op = 0; // stop
fWrite(&op, sizeof(short), 1, file);
return true;
}
// Start of registration of the design.
void COldObject::TraceRecordStart()
{
if (m_traceRecord)
{
TraceRecordStop();
}
CMotionVehicle* motionVehicle = dynamic_cast<CMotionVehicle*>(m_motion.get());
assert(motionVehicle != nullptr);
m_traceRecord = true;
m_traceOper = TO_STOP;
m_tracePos = GetPosition();
m_traceAngle = GetRotationY();
if ( motionVehicle->GetTraceDown() ) // pencil down?
{
m_traceColor = motionVehicle->GetTraceColor();
}
else // pen up?
{
m_traceColor = TraceColor::Default;
}
m_traceRecordBuffer = MakeUniqueArray<TraceRecord>(MAXTRACERECORD);
m_traceRecordIndex = 0;
}
// Saving the current drawing.
void COldObject::TraceRecordFrame()
{
TraceOper oper = TO_STOP;
Math::Vector pos;
float angle, len, speed;
CMotionVehicle* motionVehicle = dynamic_cast<CMotionVehicle*>(m_motion.get());
assert(motionVehicle != nullptr);
speed = m_physics->GetLinMotionX(MO_REASPEED);
if ( speed > 0.0f ) oper = TO_ADVANCE;
if ( speed < 0.0f ) oper = TO_RECEDE;
speed = m_physics->GetCirMotionY(MO_REASPEED);
if ( speed != 0.0f ) oper = TO_TURN;
TraceColor color = TraceColor::Default;
if ( motionVehicle->GetTraceDown() ) // pencil down?
{
color = motionVehicle->GetTraceColor();
}
if ( oper != m_traceOper ||
color != m_traceColor )
{
if ( m_traceOper == TO_ADVANCE ||
m_traceOper == TO_RECEDE )
{
pos = GetPosition();
len = Math::DistanceProjected(pos, m_tracePos);
TraceRecordOper(m_traceOper, len);
}
if ( m_traceOper == TO_TURN )
{
angle = GetRotationY()-m_traceAngle;
TraceRecordOper(m_traceOper, angle);
}
if ( color != m_traceColor )
{
TraceRecordOper(TO_PEN, static_cast<float>(color));
}
m_traceOper = oper;
m_tracePos = GetPosition();
m_traceAngle = GetRotationY();
m_traceColor = color;
}
}
// End of the registration of the design. Program generates the CBOT.
void COldObject::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 ; i<m_traceRecordIndex ; i++ )
{
curOper = m_traceRecordBuffer[i].oper;
curParam = m_traceRecordBuffer[i].param;
if ( curOper == lastOper )
{
if ( curOper == TO_PEN )
{
lastParam = curParam;
}
else
{
lastParam += curParam;
}
}
else
{
TraceRecordPut(buffer, lastOper, lastParam);
lastOper = curOper;
lastParam = curParam;
}
}
TraceRecordPut(buffer, lastOper, lastParam);
m_traceRecordBuffer.reset();
buffer << "}\n";
Program* prog = AddProgram();
prog->script->SendScript(buffer.str().c_str());
}
// Saves an instruction CBOT.
bool COldObject::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 COldObject::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<int>(param) << ");\n";
}
if ( oper == TO_PEN )
{
TraceColor color = static_cast<TraceColor>(static_cast<int>(param));
if ( color == TraceColor::Default )
buffer << "\tpenup();\n";
else
buffer << "\tpendown(" << TraceColorName(color) << ");\n";
}
return true;
}
bool COldObject::IsTraceRecord()
{
return m_traceRecord;
}
Program* COldObject::AddProgram()
{
auto program = MakeUnique<Program>();
program->script = MakeUnique<CScript>(this);
program->readOnly = false;
program->runnable = true;
Program* prog = program.get();
AddProgram(std::move(program));
return prog;
}
void COldObject::AddProgram(std::unique_ptr<Program> program)
{
m_program.push_back(std::move(program));
UpdateInterface();
}
void COldObject::RemoveProgram(Program* program)
{
if(m_currentProgram == program)
{
StopProgram();
}
m_program.erase(
std::remove_if(m_program.begin(), m_program.end(),
[program](std::unique_ptr<Program>& prog) { return prog.get() == program; }),
m_program.end());
}
Program* COldObject::CloneProgram(Program* program)
{
Program* newprog = AddProgram();
// TODO: Is there any reason CScript doesn't have a function to get the program code directly?
Ui::CEdit* edit = new Ui::CEdit();
edit->SetMaxChar(Ui::EDITSTUDIOMAX);
program->script->PutScript(edit, "");
newprog->script->GetScript(edit);
delete edit;
return newprog;
}
std::vector<std::unique_ptr<Program>>& COldObject::GetPrograms()
{
return m_program;
}
int COldObject::GetProgramCount()
{
return static_cast<int>(m_program.size());
}
int COldObject::GetProgramIndex(Program* program)
{
for(unsigned int i = 0; i < m_program.size(); i++)
{
if(m_program[i].get() == program)
{
return i;
}
}
return -1;
}
Program* COldObject::GetProgram(int index)
{
if(index < 0 || index >= static_cast<int>(m_program.size()))
return nullptr;
return m_program[index].get();
}
Program* COldObject::GetOrAddProgram(int index)
{
if(index < 0)
return nullptr;
if(index < static_cast<int>(m_program.size()))
return m_program[index].get();
for(int i = m_program.size(); i < index; i++)
{
AddProgram();
}
return AddProgram();
}

View File

@ -37,6 +37,10 @@
#include "object/interface/task_executor_object.h"
#include "object/interface/transportable_object.h"
#include "object/implementation/power_container_impl.h"
#include "object/implementation/programmable_impl.h"
#include "object/implementation/task_executor_impl.h"
// The father of all parts must always be the part number zero!
const int OBJECTMAXPART = 40;
@ -58,21 +62,6 @@ struct ObjectPart
Math::Matrix matWorld;
};
enum TraceOper
{
TO_STOP = 0, // stop
TO_ADVANCE = 1, // advance
TO_RECEDE = 2, // back
TO_TURN = 3, // rotate
TO_PEN = 4, // color change
};
struct TraceRecord
{
TraceOper oper;
float param;
};
namespace Ui
{
class CObjectInterface;
@ -82,14 +71,14 @@ class CObjectInterface;
class COldObject : public CObject,
public CInteractiveObject,
public CTransportableObject,
public CTaskExecutorObject,
public CProgrammableObject,
public CTaskExecutorObjectImpl,
public CProgrammableObjectImpl,
public CJostleableObject,
public CCarrierObject,
public CPoweredObject,
public CMovableObject,
public CControllableObject,
public CPowerContainerObject
public CPowerContainerObjectImpl
{
friend class CObjectFactory;
friend class CObjectManager;
@ -185,9 +174,6 @@ public:
CObject* GetTransporter() override;
void SetTransporterPart(int part) override;
void SetCmdLine(unsigned int rank, float value);
float GetCmdLine(unsigned int rank) override;
Math::Matrix* GetRotateMatrix(int part);
Math::Matrix* GetWorldMatrix(int part) override;
@ -199,9 +185,6 @@ public:
float GetAbsTime();
void SetEnergyLevel(float level) override;
float GetEnergyLevel() override;
float GetCapacity() override;
bool IsRechargeable() override;
@ -238,9 +221,6 @@ public:
void SetSelectable(bool bMode);
bool GetSelectable() override;
void SetActivity(bool activity) override;
bool GetActivity() override;
void SetVisible(bool bVisible);
void SetCheckToken(bool bMode);
@ -318,54 +298,10 @@ public:
Error StartTaskShield(TaskShieldMode mode, float delay = 1000.0f) override;
Error StartTaskGunGoal(float dirV, float dirH) override;
bool IsForegroundTask() override;
bool IsBackgroundTask() override;
CTaskManager* GetForegroundTask() override;
CTaskManager* GetBackgroundTask() override;
void StopForegroundTask() override;
void StopBackgroundTask() override;
void UpdateInterface() override;
void UpdateInterface();
bool IsProgram() override;
void RunProgram(Program* program) override;
int GetProgram() override;
void StopProgram() override;
bool IntroduceVirus() override;
void SetActiveVirus(bool bActive) override;
bool GetActiveVirus() override;
void SetScriptRun(Program* rank) override;
Program* GetScriptRun() override;
void SetSoluceName(char *name) override;
char* GetSoluceName() override;
bool ReadSoluce(char* filename) override;
bool ReadProgram(Program* program, const char* filename) override;
bool GetCompile(Program* program) override;
bool WriteProgram(Program* program, const char* filename) override;
bool ReadStack(FILE *file) override;
bool WriteStack(FILE *file) override;
Program* AddProgram() override;
void AddProgram(std::unique_ptr<Program> program) override;
void RemoveProgram(Program* program) override;
Program* CloneProgram(Program* program) override;
std::vector<std::unique_ptr<Program>>& GetPrograms() override;
int GetProgramCount() override;
Program* GetProgram(int index) override;
Program* GetOrAddProgram(int index) override;
int GetProgramIndex(Program* program) override;
//! Start recording trace
void TraceRecordStart() override;
//! Stop recording trace and generate CBot program
void TraceRecordStop() override;
//! Returns true if trace recording is in progress
bool IsTraceRecord() override;
protected:
bool EventFrame(const Event &event);
void VirusFrame(float rTime);
@ -382,13 +318,6 @@ protected:
Error EndedTask();
//! Save current status to recording buffer
void TraceRecordFrame();
//! Save this operation to recording buffer
bool TraceRecordOper(TraceOper oper, float param);
//! Convert this recording operation to CBot instruction
bool TraceRecordPut(std::stringstream& buffer, TraceOper oper, float param);
protected:
Gfx::CEngine* m_engine;
Gfx::CLightManager* m_lightMan;
@ -417,7 +346,6 @@ protected:
CObject* m_cargo; // object transported
CObject* m_transporter; // object with the latter
int m_transporterLink; // part
float m_energy; // energy contained (if battery)
float m_lastEnergy;
float m_shield; // shield
float m_range; // flight range
@ -462,30 +390,8 @@ protected:
float m_infoReturn;
std::vector<float> m_cmdLine;
bool m_activity;
std::unique_ptr<CTaskManager> m_foregroundTask;
std::unique_ptr<CTaskManager> m_backgroundTask;
std::vector<std::unique_ptr<Program>> m_program;
Program* m_currentProgram;
bool m_bActiveVirus;
Program* m_scriptRun;
char m_soluceName[50];
EventType m_buttonAxe;
float m_time;
float m_burnTime;
bool m_traceRecord;
TraceOper m_traceOper;
Math::Vector m_tracePos;
float m_traceAngle;
TraceColor m_traceColor;
int m_traceRecordIndex;
std::unique_ptr<TraceRecord[]> m_traceRecordBuffer;
};

View File

@ -3710,7 +3710,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
if (soluce && oldObj->Implements(ObjectInterfaceType::Programmable) && line->GetParam("soluce")->IsDefined())
dynamic_cast<CProgrammableObject*>(oldObj)
->SetSoluceName(const_cast<char*>(line->GetParam("soluce")->AsPath("ai").c_str()));
->SetSoluceName(line->GetParam("soluce")->AsPath("ai"));
if (line->GetParam("reset")->AsBool(false))
oldObj->SetAnimateOnReset(true);
@ -4717,8 +4717,8 @@ void CRobotMain::CompileScript(bool soluce)
if (soluce)
{
char* name = programmable->GetSoluceName();
if (name[0] != 0)
std::string name = programmable->GetSoluceName();
if (!name.empty())
{
programmable->ReadSoluce(name); // load solution
}

View File

@ -646,7 +646,7 @@ Error CTaskBuild::FlatFloor()
if ( m_type == OBJECT_PARA ) radius = 20.0f;
if ( m_type == OBJECT_INFO ) radius = 5.0f;
if ( m_type == OBJECT_DESTROYER) radius = 20.0f;
//if ( radius == 0.0f ) return ERR_GENERIC;
//if ( radius == 0.0f ) return ERR_UNKNOWN;
center = m_metal->GetPosition();
angle = m_terrain->GetFineSlope(center);

View File

@ -287,7 +287,7 @@ Error CTaskFire::Start(float delay)
type != OBJECT_MOBILEti &&
type != OBJECT_MOBILEwi &&
type != OBJECT_MOBILEii &&
type != OBJECT_MOBILErc ) return ERR_FIRE_VEH;
type != OBJECT_MOBILErc ) return ERR_WRONG_BOT;
//? if ( !m_physics->GetLand() ) return ERR_FIRE_FLY;

View File

@ -92,13 +92,13 @@ Error CTaskFireAnt::Start(Math::Vector impact)
m_impact = impact;
m_bError = true; // operation impossible
if ( !m_physics->GetLand() ) return ERR_FIRE_VEH;
if ( !m_physics->GetLand() ) return ERR_WRONG_BOT;
type = m_object->GetType();
if ( type != OBJECT_ANT ) return ERR_FIRE_VEH;
if ( type != OBJECT_ANT ) return ERR_WRONG_BOT;
// Insect on its back?
if ( m_object->GetFixed() ) return ERR_FIRE_VEH;
if ( m_object->GetFixed() ) return ERR_WRONG_BOT;
m_physics->SetMotorSpeed(Math::Vector(0.0f, 0.0f, 0.0f));

View File

@ -936,7 +936,7 @@ Error CTaskGoto::IsEnded()
{
m_physics->SetMotorSpeedX(0.0f); // stops the advance
m_physics->SetMotorSpeedZ(0.0f); // stops the rotation
m_error = ERR_GENERIC;
m_error = ERR_UNKNOWN;
return m_error;
}
if ( m_time >= 1.0f )

View File

@ -183,7 +183,7 @@ Error CTaskManager::StartTaskShield(TaskShieldMode mode, float delay)
{
return (static_cast<CTaskShield*>(m_task))->Start(mode, delay);
}
return ERR_GENERIC;
return ERR_UNKNOWN;
}
// Shoots.
@ -233,7 +233,7 @@ bool CTaskManager::EventProcess(const Event &event)
Error CTaskManager::IsEnded()
{
if ( m_task == 0 ) return ERR_GENERIC;
if ( m_task == 0 ) return ERR_UNKNOWN;
return m_task->IsEnded();
}

View File

@ -308,7 +308,7 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
if ( m_arm != TMA_FFRONT &&
m_arm != TMA_FBACK &&
m_arm != TMA_POWER &&
m_arm != TMA_GRAB ) return ERR_MANIP_VEH;
m_arm != TMA_GRAB ) return ERR_WRONG_BOT;
m_physics->SetMotorSpeed(Math::Vector(0.0f, 0.0f, 0.0f));
@ -374,7 +374,7 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
type != OBJECT_MOBILEta &&
type != OBJECT_MOBILEwa &&
type != OBJECT_MOBILEia &&
type != OBJECT_MOBILEsa ) return ERR_MANIP_VEH;
type != OBJECT_MOBILEsa ) return ERR_WRONG_BOT;
if ( m_bSubm ) // submarine?
{

View File

@ -139,7 +139,7 @@ Error CTaskPen::Start(bool bDown, TraceColor color)
m_bError = true; // operation impossible
type = m_object->GetType();
if ( type != OBJECT_MOBILEdr ) return ERR_FIRE_VEH;
if ( type != OBJECT_MOBILEdr ) return ERR_WRONG_BOT;
m_bError = false; // ok

View File

@ -180,10 +180,10 @@ bool CTaskRecover::EventProcess(const Event &event)
Error CTaskRecover::Start()
{
m_bError = true; // operation impossible
if ( !m_physics->GetLand() ) return ERR_RECOVER_VEH;
if ( !m_physics->GetLand() ) return ERR_WRONG_BOT;
ObjectType type = m_object->GetType();
if ( type != OBJECT_MOBILErr ) return ERR_RECOVER_VEH;
if ( type != OBJECT_MOBILErr ) return ERR_WRONG_BOT;
assert(m_object->Implements(ObjectInterfaceType::Powered));
CObject* power = dynamic_cast<CPoweredObject*>(m_object)->GetPower();

View File

@ -140,7 +140,7 @@ Error CTaskSearch::Start()
if ( type != OBJECT_MOBILEfs &&
type != OBJECT_MOBILEts &&
type != OBJECT_MOBILEws &&
type != OBJECT_MOBILEis ) return ERR_SEARCH_VEH;
type != OBJECT_MOBILEis ) return ERR_WRONG_BOT;
m_hand = TSH_DOWN;
m_phase = TSP_DOWN;

View File

@ -287,10 +287,10 @@ Error CTaskShield::Start(TaskShieldMode mode, float delay)
}
ObjectType type = m_object->GetType();
if ( type != OBJECT_MOBILErs ) return ERR_SHIELD_VEH;
if ( type != OBJECT_MOBILErs ) return ERR_WRONG_BOT;
m_bError = true; // operation impossible
if ( !m_physics->GetLand() ) return ERR_SHIELD_VEH;
if ( !m_physics->GetLand() ) return ERR_WRONG_BOT;
CObject* power = m_object->GetPower();
if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) return ERR_SHIELD_ENERGY;

View File

@ -110,7 +110,7 @@ Error CTaskTake::Start()
ObjectType type = m_object->GetType();
if ( type != OBJECT_HUMAN &&
type != OBJECT_TECH ) return ERR_MANIP_VEH;
type != OBJECT_TECH ) return ERR_WRONG_BOT;
m_physics->SetMotorSpeed(Math::Vector(0.0f, 0.0f, 0.0f));

View File

@ -203,10 +203,10 @@ Error CTaskTerraform::Start()
ObjectType type;
m_bError = true; // operation impossible
if ( !m_physics->GetLand() ) return ERR_TERRA_VEH;
if ( !m_physics->GetLand() ) return ERR_WRONG_BOT;
type = m_object->GetType();
if ( type != OBJECT_MOBILErt ) return ERR_TERRA_VEH;
if ( type != OBJECT_MOBILErt ) return ERR_WRONG_BOT;
power = m_object->GetPower();
if ( power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer) ) return ERR_TERRA_ENERGY;

View File

@ -487,6 +487,8 @@ void CScript::Stop()
{
if ( !m_bRun ) return;
m_taskExecutor->StopForegroundTask();
if( m_botProg != 0 )
{
m_botProg->Stop();

View File

@ -718,8 +718,8 @@ bool CScriptFunctions::rFactory(CBotVar* thisclass, CBotVar* var, CBotVar* resul
CObject* factory = static_cast<CObject*>(thisclass->GetUserPtr());
if (factory == nullptr)
{
exception = ERR_GENERIC;
result->SetValInt(ERR_GENERIC);
exception = ERR_UNKNOWN;
result->SetValInt(ERR_UNKNOWN);
GetLogger()->Error("in object.factory() - factory is nullptr");
return false;
}
@ -736,8 +736,8 @@ bool CScriptFunctions::rFactory(CBotVar* thisclass, CBotVar* var, CBotVar* resul
CAutoFactory* automat = static_cast<CAutoFactory*>(factory->GetAuto());
if (automat == nullptr)
{
exception = ERR_GENERIC;
result->SetValInt(ERR_GENERIC);
exception = ERR_UNKNOWN;
result->SetValInt(ERR_UNKNOWN);
GetLogger()->Error("in object.factory() - automat is nullptr");
return false;
}
@ -752,7 +752,7 @@ bool CScriptFunctions::rFactory(CBotVar* thisclass, CBotVar* var, CBotVar* resul
if ( err == ERR_OK ) automat->SetProgram(program);
}
else
err = ERR_GENERIC;
err = ERR_UNKNOWN;
}
}
else
@ -824,7 +824,7 @@ bool CScriptFunctions::rResearch(CBotVar* thisclass, CBotVar* var, CBotVar* resu
err = automat->StartAction(type);
}
else
err = ERR_GENERIC;
err = ERR_UNKNOWN;
}
else
err = ERR_BUILD_DISABLED;
@ -1417,7 +1417,7 @@ bool CScriptFunctions::rBuild(CBotVar* var, CBotVar* result, int& exception, voi
oType != OBJECT_HUMAN &&
oType != OBJECT_TECH )
{
err = ERR_MANIP_VEH; // Wrong object
err = ERR_WRONG_BOT; // Wrong object
}
else
{
@ -2475,10 +2475,10 @@ bool CScriptFunctions::rShield(CBotVar* var, CBotVar* result, int& exception, vo
// only shielder can use shield()
if (pThis->GetType() != OBJECT_MOBILErs)
{
result->SetValInt(ERR_MANIP_VEH); // return error
result->SetValInt(ERR_WRONG_BOT); // return error
if (script->m_errMode == ERM_STOP)
{
exception = ERR_MANIP_VEH;
exception = ERR_WRONG_BOT;
return false;
}
return true;