diff --git a/po/colobot.pot b/po/colobot.pot
index ecfc905a..770aca01 100644
--- a/po/colobot.pot
+++ b/po/colobot.pot
@@ -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 ""
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f939533f..c41139fe 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -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
diff --git a/src/common/global.h b/src/common/global.h
index 3d5998c8..17d6f143 100644
--- a/src/common/global.h
+++ b/src/common/global.h
@@ -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
diff --git a/src/common/restext.cpp b/src/common/restext.cpp
index f2291f7c..7b64995b 100644
--- a/src/common/restext.cpp
+++ b/src/common/restext.cpp
@@ -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");
diff --git a/src/object/auto/auto.cpp b/src/object/auto/auto.cpp
index e1ed9ea9..9c611229 100644
--- a/src/object/auto/auto.cpp
+++ b/src/object/auto/auto.cpp
@@ -107,7 +107,7 @@ void CAuto::Start(int param)
 
 Error CAuto::StartAction(int param)
 {
-    return ERR_GENERIC;
+    return ERR_UNKNOWN;
 }
 
 // Gete a type.
diff --git a/src/object/auto/autodestroyer.cpp b/src/object/auto/autodestroyer.cpp
index dcafffff..bd6bb6f6 100644
--- a/src/object/auto/autodestroyer.cpp
+++ b/src/object/auto/autodestroyer.cpp
@@ -103,7 +103,7 @@ Error CAutoDestroyer::StartAction(int param)
             m_bExplo   = false;
         }
         else
-            return ERR_GENERIC;
+            return ERR_UNKNOWN;
     }
     return ERR_OK;
 }
diff --git a/src/object/auto/autofactory.cpp b/src/object/auto/autofactory.cpp
index 55ed0f94..2c4b862d 100644
--- a/src/object/auto/autofactory.cpp
+++ b/src/object/auto/autofactory.cpp
@@ -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;
     }
 
diff --git a/src/object/auto/autolabo.cpp b/src/object/auto/autolabo.cpp
index 64d2f19b..9601358f 100644
--- a/src/object/auto/autolabo.cpp
+++ b/src/object/auto/autolabo.cpp
@@ -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;
     }
 
diff --git a/src/object/auto/autoresearch.cpp b/src/object/auto/autoresearch.cpp
index eaf0d8fa..8db14f17 100644
--- a/src/object/auto/autoresearch.cpp
+++ b/src/object/auto/autoresearch.cpp
@@ -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;
     }
 
diff --git a/src/object/implementation/power_container_impl.cpp b/src/object/implementation/power_container_impl.cpp
new file mode 100644
index 00000000..a8add3eb
--- /dev/null
+++ b/src/object/implementation/power_container_impl.cpp
@@ -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;
+}
diff --git a/src/object/implementation/power_container_impl.h b/src/object/implementation/power_container_impl.h
new file mode 100644
index 00000000..c7a537a6
--- /dev/null
+++ b/src/object/implementation/power_container_impl.h
@@ -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;
+};
diff --git a/src/object/implementation/programmable_impl.cpp b/src/object/implementation/programmable_impl.cpp
new file mode 100644
index 00000000..01b51bd6
--- /dev/null
+++ b/src/object/implementation/programmable_impl.cpp
@@ -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;
+}
diff --git a/src/object/implementation/programmable_impl.h b/src/object/implementation/programmable_impl.h
new file mode 100644
index 00000000..f80af53a
--- /dev/null
+++ b/src/object/implementation/programmable_impl.h
@@ -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;
+};
diff --git a/src/object/implementation/task_executor_impl.cpp b/src/object/implementation/task_executor_impl.cpp
new file mode 100644
index 00000000..11d3a2d5
--- /dev/null
+++ b/src/object/implementation/task_executor_impl.cpp
@@ -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;
+}
diff --git a/src/object/implementation/task_executor_impl.h b/src/object/implementation/task_executor_impl.h
new file mode 100644
index 00000000..2c206c94
--- /dev/null
+++ b/src/object/implementation/task_executor_impl.h
@@ -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;
+};
diff --git a/src/object/interface/programmable_object.h b/src/object/interface/programmable_object.h
index a2d0fceb..63c339e0 100644
--- a/src/object/interface/programmable_object.h
+++ b/src/object/interface/programmable_object.h
@@ -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;
 
diff --git a/src/object/object.h b/src/object/object.h
index ab7dd59d..8ded4949 100644
--- a/src/object/object.h
+++ b/src/object/object.h
@@ -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
     {
diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp
index 4b13d29e..78f27fb8 100644
--- a/src/object/old_object.cpp
+++ b/src/object/old_object.cpp
@@ -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();
 }
diff --git a/src/object/old_object.h b/src/object/old_object.h
index 59039d9b..23bd193b 100644
--- a/src/object/old_object.h
+++ b/src/object/old_object.h
@@ -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;
 };
diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp
index b18d7d99..d6a521e8 100644
--- a/src/object/robotmain.cpp
+++ b/src/object/robotmain.cpp
@@ -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
             }
diff --git a/src/object/task/taskbuild.cpp b/src/object/task/taskbuild.cpp
index 9270805b..b19efc3b 100644
--- a/src/object/task/taskbuild.cpp
+++ b/src/object/task/taskbuild.cpp
@@ -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);
diff --git a/src/object/task/taskfire.cpp b/src/object/task/taskfire.cpp
index 35542852..58fc5a9e 100644
--- a/src/object/task/taskfire.cpp
+++ b/src/object/task/taskfire.cpp
@@ -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;
 
diff --git a/src/object/task/taskfireant.cpp b/src/object/task/taskfireant.cpp
index 57ecd4e4..a52064e0 100644
--- a/src/object/task/taskfireant.cpp
+++ b/src/object/task/taskfireant.cpp
@@ -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));
 
diff --git a/src/object/task/taskgoto.cpp b/src/object/task/taskgoto.cpp
index 2b2d2e56..b9ae9374 100644
--- a/src/object/task/taskgoto.cpp
+++ b/src/object/task/taskgoto.cpp
@@ -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 )
diff --git a/src/object/task/taskmanager.cpp b/src/object/task/taskmanager.cpp
index 7357e975..311a0737 100644
--- a/src/object/task/taskmanager.cpp
+++ b/src/object/task/taskmanager.cpp
@@ -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();
 }
 
diff --git a/src/object/task/taskmanip.cpp b/src/object/task/taskmanip.cpp
index fe7ab92b..e3681760 100644
--- a/src/object/task/taskmanip.cpp
+++ b/src/object/task/taskmanip.cpp
@@ -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?
     {
diff --git a/src/object/task/taskpen.cpp b/src/object/task/taskpen.cpp
index a6b57664..7e9311b8 100644
--- a/src/object/task/taskpen.cpp
+++ b/src/object/task/taskpen.cpp
@@ -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
 
diff --git a/src/object/task/taskrecover.cpp b/src/object/task/taskrecover.cpp
index 956b1ec2..b712b8b0 100644
--- a/src/object/task/taskrecover.cpp
+++ b/src/object/task/taskrecover.cpp
@@ -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();
diff --git a/src/object/task/tasksearch.cpp b/src/object/task/tasksearch.cpp
index 35b78dab..968e1085 100644
--- a/src/object/task/tasksearch.cpp
+++ b/src/object/task/tasksearch.cpp
@@ -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;
diff --git a/src/object/task/taskshield.cpp b/src/object/task/taskshield.cpp
index 946ed23f..bc94adf2 100644
--- a/src/object/task/taskshield.cpp
+++ b/src/object/task/taskshield.cpp
@@ -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;
diff --git a/src/object/task/tasktake.cpp b/src/object/task/tasktake.cpp
index 2ba350c4..c2a40842 100644
--- a/src/object/task/tasktake.cpp
+++ b/src/object/task/tasktake.cpp
@@ -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));
 
diff --git a/src/object/task/taskterraform.cpp b/src/object/task/taskterraform.cpp
index a439ade0..df3e7f1b 100644
--- a/src/object/task/taskterraform.cpp
+++ b/src/object/task/taskterraform.cpp
@@ -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;
diff --git a/src/script/script.cpp b/src/script/script.cpp
index e66f8365..f3b783ab 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -487,6 +487,8 @@ void CScript::Stop()
 {
     if ( !m_bRun )  return;
 
+    m_taskExecutor->StopForegroundTask();
+
     if( m_botProg != 0 )
     {
         m_botProg->Stop();
diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp
index 54a2fe52..21e388cc 100644
--- a/src/script/scriptfunc.cpp
+++ b/src/script/scriptfunc.cpp
@@ -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;