From 5b2b632de35faf8d6edb42995e0f16b9b1c4036b Mon Sep 17 00:00:00 2001
From: Fiftytwo <emxx52@gmail.com>
Date: Fri, 13 Jul 2018 00:03:20 +0200
Subject: [PATCH] Add TargetBot research; make it fully operational

---
 src/common/event.cpp                 |  6 ++++--
 src/common/event.h                   |  2 ++
 src/common/restext.cpp               |  4 +++-
 src/level/parser/parserparam.cpp     |  1 +
 src/level/research_type.h            |  3 ++-
 src/level/robotmain.cpp              |  1 +
 src/object/auto/autofactory.cpp      |  4 ++++
 src/object/auto/autolabo.cpp         | 29 ++++++++++++++++++++--------
 src/object/auto/autopowerstation.cpp |  1 +
 src/object/motion/motiontoto.cpp     |  1 +
 src/object/old_object.cpp            |  5 +++--
 src/script/scriptfunc.cpp            |  1 +
 src/ui/mainshort.cpp                 |  1 +
 13 files changed, 45 insertions(+), 14 deletions(-)

diff --git a/src/common/event.cpp b/src/common/event.cpp
index b79e8b2d..00d9ea44 100644
--- a/src/common/event.cpp
+++ b/src/common/event.cpp
@@ -432,6 +432,7 @@ void InitializeEventTypeTexts()
     EVENT_TYPE_TEXT[EVENT_OBJECT_FACTORYrr]  = "EVENT_OBJECT_FACTORYrr";
     EVENT_TYPE_TEXT[EVENT_OBJECT_FACTORYrs]  = "EVENT_OBJECT_FACTORYrs";
     EVENT_TYPE_TEXT[EVENT_OBJECT_FACTORYsa]  = "EVENT_OBJECT_FACTORYsa";
+    EVENT_TYPE_TEXT[EVENT_OBJECT_FACTORYtg]  = "EVENT_OBJECT_FACTORYtg";
     EVENT_TYPE_TEXT[EVENT_OBJECT_SEARCH]     = "EVENT_OBJECT_SEARCH";
     EVENT_TYPE_TEXT[EVENT_OBJECT_TERRAFORM]  = "EVENT_OBJECT_TERRAFORM";
     EVENT_TYPE_TEXT[EVENT_OBJECT_FIRE]       = "EVENT_OBJECT_FIRE";
@@ -527,8 +528,9 @@ void InitializeEventTypeTexts()
     EVENT_TYPE_TEXT[EVENT_CODE_BATTLE_START] = "EVENT_CODE_BATTLE_START";
     EVENT_TYPE_TEXT[EVENT_CODE_BATTLE_SPECTATOR] = "EVENT_CODE_BATTLE_SPECTATOR";
     
-    EVENT_TYPE_TEXT[EVENT_OBJECT_RBUILDER]       = "EVENT_OBJECT_RBUILDER";
-    EVENT_TYPE_TEXT[EVENT_OBJECT_BUILD]       = "EVENT_OBJECT_BUILD";
+    EVENT_TYPE_TEXT[EVENT_OBJECT_RBUILDER]   = "EVENT_OBJECT_RBUILDER";
+    EVENT_TYPE_TEXT[EVENT_OBJECT_BUILD]      = "EVENT_OBJECT_BUILD";
+    EVENT_TYPE_TEXT[EVENT_OBJECT_RTARGET]    = "EVENT_OBJECT_RTARGET";
 }
 
 std::string ParseEventType(EventType eventType)
diff --git a/src/common/event.h b/src/common/event.h
index 4cb2a75e..f592b327 100644
--- a/src/common/event.h
+++ b/src/common/event.h
@@ -496,6 +496,7 @@ enum EventType
     EVENT_OBJECT_FACTORYtb  = 1102,
     EVENT_OBJECT_FACTORYfb  = 1103,
     EVENT_OBJECT_FACTORYib  = 1104,
+    EVENT_OBJECT_FACTORYtg  = 1105,
     EVENT_OBJECT_SEARCH     = 1200,
     EVENT_OBJECT_TERRAFORM  = 1201,
     EVENT_OBJECT_FIRE       = 1202,
@@ -600,6 +601,7 @@ enum EventType
     
     EVENT_OBJECT_RBUILDER       = 2300,
     EVENT_OBJECT_BUILD          = 2301,
+    EVENT_OBJECT_RTARGET        = 2302,
 
     //! Maximum value of standard events
     EVENT_STD_MAX,
diff --git a/src/common/restext.cpp b/src/common/restext.cpp
index ab43b630..bd1e20b5 100644
--- a/src/common/restext.cpp
+++ b/src/common/restext.cpp
@@ -366,6 +366,7 @@ void InitializeRestext()
     stringsEvent[EVENT_OBJECT_FACTORYrr]    = TR("Build a recycler");
     stringsEvent[EVENT_OBJECT_FACTORYrs]    = TR("Build a shielder");
     stringsEvent[EVENT_OBJECT_FACTORYsa]    = TR("Build a subber");
+    stringsEvent[EVENT_OBJECT_FACTORYtg]    = TR("Build a target bot");
     stringsEvent[EVENT_OBJECT_RTANK]        = TR("Run research program for tracked bots");
     stringsEvent[EVENT_OBJECT_RFLY]         = TR("Run research program for winged bots");
     stringsEvent[EVENT_OBJECT_RTHUMP]       = TR("Run research program for thumper");
@@ -377,6 +378,7 @@ void InitializeRestext()
     stringsEvent[EVENT_OBJECT_RiPAW]        = TR("Run research program for legged bots");
     stringsEvent[EVENT_OBJECT_RiGUN]        = TR("Run research program for orga shooter");
     stringsEvent[EVENT_OBJECT_RBUILDER]     = TR("Run research program for builder");
+    stringsEvent[EVENT_OBJECT_RTARGET]      = TR("Run research program for target bot");
     stringsEvent[EVENT_OBJECT_RESET]        = TR("Return to start");
     stringsEvent[EVENT_OBJECT_SEARCH]       = TR("Sniff (\\key action;)");
     stringsEvent[EVENT_OBJECT_TERRAFORM]    = TR("Thump (\\key action;)");
@@ -626,7 +628,7 @@ void InitializeRestext()
     stringsErr[ERR_BASE_DLOCK]      = TR("Doors blocked by a robot or another object");
     stringsErr[ERR_BASE_DHUMAN]     = TR("You must get on the spaceship to take off");
     stringsErr[ERR_LABO_NULL]       = TR("Nothing to analyze");
-    stringsErr[ERR_LABO_BAD]        = TR("Analyzes only organic matter");
+    stringsErr[ERR_LABO_BAD]        = TR("Inappropriate sample");
     stringsErr[ERR_LABO_ALREADY]    = TR("Analysis already performed");
     stringsErr[ERR_NUCLEAR_EMPTY]   = TR("No uranium to transform");
     stringsErr[ERR_NUCLEAR_BAD]     = TR("Transforms only uranium");
diff --git a/src/level/parser/parserparam.cpp b/src/level/parser/parserparam.cpp
index 9a671976..f2663343 100644
--- a/src/level/parser/parserparam.cpp
+++ b/src/level/parser/parserparam.cpp
@@ -916,6 +916,7 @@ int CLevelParserParam::ToResearchFlag(std::string value)
     if (value == "SUBBER"  ) return RESEARCH_SUBM;
     if (value == "SNIFFER" ) return RESEARCH_SNIFFER;
     if (value == "BUILDER" ) return RESEARCH_BUILDER;
+    if (value == "TARGET"  ) return RESEARCH_TARGET;
     return Cast<int>(value, "researchflag");
 }
 
diff --git a/src/level/research_type.h b/src/level/research_type.h
index 01256ff5..c2393173 100644
--- a/src/level/research_type.h
+++ b/src/level/research_type.h
@@ -39,5 +39,6 @@ enum ResearchType
     RESEARCH_RECYCLER   = (1<<10),      //! < recycler
     RESEARCH_SUBM       = (1<<11),      //! < submarine
     RESEARCH_SNIFFER    = (1<<12),      //! < sniffer
-    RESEARCH_BUILDER    = (1<<13)       //! < builder
+    RESEARCH_BUILDER    = (1<<13),      //! < builder
+    RESEARCH_TARGET     = (1<<14)       //! < target bot
 };
diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp
index ca287087..610a5705 100644
--- a/src/level/robotmain.cpp
+++ b/src/level/robotmain.cpp
@@ -5741,6 +5741,7 @@ Error CRobotMain::CanFactoryError(ObjectType type, int team)
     if (type == OBJECT_MOBILErr          && !IsResearchDone(RESEARCH_RECYCLER, team)) return ERR_BUILD_RESEARCH;
     if (type == OBJECT_MOBILErs          && !IsResearchDone(RESEARCH_SHIELD,   team)) return ERR_BUILD_RESEARCH;
     if (type == OBJECT_MOBILEsa          && !IsResearchDone(RESEARCH_SUBM,     team)) return ERR_BUILD_DISABLED; // Can be only researched manually in Scene file
+    if (type == OBJECT_MOBILEtg          && !IsResearchDone(RESEARCH_TARGET,   team)) return ERR_BUILD_RESEARCH;
 
     return ERR_OK;
 }
diff --git a/src/object/auto/autofactory.cpp b/src/object/auto/autofactory.cpp
index fa91ff88..0ccb8cc2 100644
--- a/src/object/auto/autofactory.cpp
+++ b/src/object/auto/autofactory.cpp
@@ -195,6 +195,7 @@ ObjectType ObjectTypeFromFactoryButton(EventType eventType)
     if ( eventType == EVENT_OBJECT_FACTORYrr )  return OBJECT_MOBILErr;
     if ( eventType == EVENT_OBJECT_FACTORYrs )  return OBJECT_MOBILErs;
     if ( eventType == EVENT_OBJECT_FACTORYsa )  return OBJECT_MOBILEsa;
+    if ( eventType == EVENT_OBJECT_FACTORYtg )  return OBJECT_MOBILEtg;
 
     return OBJECT_NULL;
 }
@@ -798,6 +799,8 @@ bool CAutoFactory::CreateInterface(bool bSelect)
         pos.x = ox+sx*0.0f;
         pos.y = oy+sy*2.7f;
         pw->CreateButton(pos, dim, 128+21, EVENT_OBJECT_FACTORYsa);
+        pos.x += dim.x;
+        pw->CreateButton(pos, dim, 128+45, EVENT_OBJECT_FACTORYtg);
     }
     
     pos.x = ox+sx*0.0f;
@@ -847,6 +850,7 @@ void CAutoFactory::UpdateInterface()
     UpdateButton(pw, EVENT_OBJECT_FACTORYrr, m_bBusy);
     UpdateButton(pw, EVENT_OBJECT_FACTORYrs, m_bBusy);
     UpdateButton(pw, EVENT_OBJECT_FACTORYsa, m_bBusy);
+    UpdateButton(pw, EVENT_OBJECT_FACTORYtg, m_bBusy);
 }
 
 // Updates the status of one interface button.
diff --git a/src/object/auto/autolabo.cpp b/src/object/auto/autolabo.cpp
index f39ba837..383484cd 100644
--- a/src/object/auto/autolabo.cpp
+++ b/src/object/auto/autolabo.cpp
@@ -136,7 +136,11 @@ Error CAutoLabo::StartAction(int param)
     {
         return ERR_LABO_NULL;
     }
-    if ( power->GetType() != OBJECT_BULLET )
+    if ( m_research != RESEARCH_TARGET && power->GetType() != OBJECT_BULLET )
+    {
+        return ERR_LABO_BAD;
+    }
+    if ( m_research == RESEARCH_TARGET && power->GetType() != OBJECT_TNT )
     {
         return ERR_LABO_BAD;
     }
@@ -177,6 +181,7 @@ bool CAutoLabo::EventProcess(const Event &event)
     if ( m_object->GetSelect() )  // center selected?
     {
         Error err = ERR_UNKNOWN;
+        if ( event.type == EVENT_OBJECT_RTARGET ) err = StartAction(RESEARCH_TARGET);
         if ( event.type == EVENT_OBJECT_RiPAW   ) err = StartAction(RESEARCH_iPAW);
         if ( event.type == EVENT_OBJECT_RiGUN   ) err = StartAction(RESEARCH_iGUN);
 
@@ -455,7 +460,7 @@ Error CAutoLabo::GetError()
     CObject* obj = m_object->GetPower();
     if (obj == nullptr)  return ERR_LABO_NULL;
     ObjectType type = obj->GetType();
-    if ( type != OBJECT_BULLET )  return ERR_LABO_BAD;
+    if ( type != OBJECT_BULLET && type != OBJECT_TNT )  return ERR_LABO_BAD;
 
     return ERR_OK;
 }
@@ -484,6 +489,10 @@ bool CAutoLabo::CreateInterface(bool bSelect)
     sy = 33.0f/480.0f;
     if( !m_object->GetTrainer() )
     {
+        pos.x = ox+sx*6.0f;
+        pos.y = oy+sy*0.5f;
+        pw->CreateButton(pos, dim, 192+8, EVENT_OBJECT_RTARGET);
+        
         pos.x = ox+sx*7.0f;
         pos.y = oy+sy*0.5f;
         pw->CreateButton(pos, dim, 64+45, EVENT_OBJECT_RiPAW);
@@ -517,14 +526,17 @@ void CAutoLabo::UpdateInterface()
     pw = static_cast< Ui::CWindow* >(m_interface->SearchControl(EVENT_WINDOW0));
     if ( pw == nullptr )  return;
 
-    DeadInterface(pw, EVENT_OBJECT_RiPAW, m_main->IsResearchEnabled(RESEARCH_iPAW));
-    DeadInterface(pw, EVENT_OBJECT_RiGUN, m_main->IsResearchEnabled(RESEARCH_iGUN));
+    DeadInterface(pw, EVENT_OBJECT_RTARGET, m_main->IsResearchEnabled(RESEARCH_TARGET));
+    DeadInterface(pw, EVENT_OBJECT_RiPAW,   m_main->IsResearchEnabled(RESEARCH_iPAW));
+    DeadInterface(pw, EVENT_OBJECT_RiGUN,   m_main->IsResearchEnabled(RESEARCH_iGUN));
 
+    OkayButton(pw, EVENT_OBJECT_RTARGET);
     OkayButton(pw, EVENT_OBJECT_RiPAW);
     OkayButton(pw, EVENT_OBJECT_RiGUN);
 
-    VisibleInterface(pw, EVENT_OBJECT_RiPAW, !m_bBusy);
-    VisibleInterface(pw, EVENT_OBJECT_RiGUN, !m_bBusy);
+    VisibleInterface(pw, EVENT_OBJECT_RTARGET, !m_bBusy);
+    VisibleInterface(pw, EVENT_OBJECT_RiPAW,   !m_bBusy);
+    VisibleInterface(pw, EVENT_OBJECT_RiGUN,   !m_bBusy);
 }
 
 // Indicates the research conducted for a button.
@@ -544,8 +556,9 @@ void CAutoLabo::OkayButton(Ui::CWindow *pw, EventType event)
 
 bool CAutoLabo::TestResearch(EventType event)
 {
-    if ( event == EVENT_OBJECT_RiPAW )  return m_main->IsResearchDone(RESEARCH_iPAW, m_object->GetTeam());
-    if ( event == EVENT_OBJECT_RiGUN )  return m_main->IsResearchDone(RESEARCH_iGUN, m_object->GetTeam());
+    if ( event == EVENT_OBJECT_RTARGET )  return m_main->IsResearchDone(RESEARCH_TARGET, m_object->GetTeam());
+    if ( event == EVENT_OBJECT_RiPAW   )  return m_main->IsResearchDone(RESEARCH_iPAW, m_object->GetTeam());
+    if ( event == EVENT_OBJECT_RiGUN   )  return m_main->IsResearchDone(RESEARCH_iGUN, m_object->GetTeam());
 
     return m_main;
 }
diff --git a/src/object/auto/autopowerstation.cpp b/src/object/auto/autopowerstation.cpp
index 3b245d7e..2671bdc7 100644
--- a/src/object/auto/autopowerstation.cpp
+++ b/src/object/auto/autopowerstation.cpp
@@ -278,6 +278,7 @@ CObject* CAutoPowerStation::SearchVehicle()
              type != OBJECT_MOBILEtt &&
              type != OBJECT_MOBILEwt &&
              type != OBJECT_MOBILEit &&
+             type != OBJECT_MOBILEtg &&
              type != OBJECT_MOBILEdr )  continue;
 
         Math::Vector oPos = obj->GetPosition();
diff --git a/src/object/motion/motiontoto.cpp b/src/object/motion/motiontoto.cpp
index 8c22c2ea..7dbed435 100644
--- a/src/object/motion/motiontoto.cpp
+++ b/src/object/motion/motiontoto.cpp
@@ -360,6 +360,7 @@ bool CMotionToto::EventFrame(const Event &event)
               type == OBJECT_MOBILEtt ||
               type == OBJECT_MOBILEft ||
               type == OBJECT_MOBILEit ||
+              type == OBJECT_MOBILEtg ||
               type == OBJECT_MOBILEdr ) )  // vehicle?
         {
             m_clownTime += event.rTime;
diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp
index 99b471e1..d9a681a4 100644
--- a/src/object/old_object.cpp
+++ b/src/object/old_object.cpp
@@ -890,6 +890,7 @@ void COldObject::SetType(ObjectType type)
         m_type == OBJECT_MOBILEtt ||
         m_type == OBJECT_MOBILEwt ||
         m_type == OBJECT_MOBILEit ||
+        m_type == OBJECT_MOBILEtg ||
         m_type == OBJECT_MOBILEdr ||
         m_type == OBJECT_APOLLO2  ||
         m_type == OBJECT_BASE     ||
@@ -3254,6 +3255,7 @@ float COldObject::GetLightningHitProbability()
          m_type == OBJECT_MOBILEtt ||
          m_type == OBJECT_MOBILEwt ||
          m_type == OBJECT_MOBILEit ||
+         m_type == OBJECT_MOBILEtg ||
          m_type == OBJECT_MOBILEdr )  // robot?
     {
         return 0.5f;
@@ -3267,8 +3269,7 @@ bool COldObject::IsSelectableByDefault(ObjectType type)
          type == OBJECT_ANT      ||
          type == OBJECT_SPIDER   ||
          type == OBJECT_BEE      ||
-         type == OBJECT_WORM     ||
-         type == OBJECT_MOBILEtg )
+         type == OBJECT_WORM     )
     {
         return false;
     }
diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp
index e73b583d..9d00f031 100644
--- a/src/script/scriptfunc.cpp
+++ b/src/script/scriptfunc.cpp
@@ -3311,6 +3311,7 @@ void CScriptFunctions::Init()
     CBotProgram::DefineNum("ResearchSubber",        RESEARCH_SUBM);
     CBotProgram::DefineNum("ResearchSniffer",       RESEARCH_SNIFFER);
     CBotProgram::DefineNum("ResearchBuilder",       RESEARCH_BUILDER);
+    CBotProgram::DefineNum("ResearchTarget",        RESEARCH_TARGET);
 
     CBotProgram::DefineNum("PolskiPortalColobota", 1337);
 
diff --git a/src/ui/mainshort.cpp b/src/ui/mainshort.cpp
index 8766d1af..cf9101b1 100644
--- a/src/ui/mainshort.cpp
+++ b/src/ui/mainshort.cpp
@@ -238,6 +238,7 @@ int CMainShort::GetShortcutIcon(ObjectType type)
             case OBJECT_MOBILEtt:   icon =  5; break;
             case OBJECT_MOBILEwt:   icon = 30; break;
             case OBJECT_MOBILEit:   icon =  7; break;
+            case OBJECT_MOBILEtg:   icon = 45; break;
             case OBJECT_MOBILEdr:   icon = 48; break;
             case OBJECT_APOLLO2:    icon = 49; break;
             default:                return -1;