1 /*
2  * This file is part of the Colobot: Gold Edition source code
3  * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
4  * http://epsitec.ch; http://colobot.info; http://github.com/colobot
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see http://gnu.org/licenses
18  */
19 
20 #include "object/implementation/task_executor_impl.h"
21 
22 #include "object/object.h"
23 #include "object/old_object.h"
24 
25 #include "object/task/taskadvance.h"
26 #include "object/task/taskbuild.h"
27 #include "object/task/taskdeletemark.h"
28 #include "object/task/taskfire.h"
29 #include "object/task/taskfireant.h"
30 #include "object/task/taskgungoal.h"
31 #include "object/task/taskinfo.h"
32 #include "object/task/taskpen.h"
33 #include "object/task/taskrecover.h"
34 #include "object/task/tasksearch.h"
35 #include "object/task/taskspiderexplo.h"
36 #include "object/task/tasktake.h"
37 #include "object/task/taskterraform.h"
38 #include "object/task/taskturn.h"
39 #include "object/task/taskwait.h"
40 
CTaskExecutorObjectImpl(ObjectInterfaceTypes & types,CObject * object)41 CTaskExecutorObjectImpl::CTaskExecutorObjectImpl(ObjectInterfaceTypes& types, CObject* object)
42     : CTaskExecutorObject(types)
43     , m_object(object)
44 {}
45 
~CTaskExecutorObjectImpl()46 CTaskExecutorObjectImpl::~CTaskExecutorObjectImpl()
47 {}
48 
EventProcess(const Event & event)49 bool CTaskExecutorObjectImpl::EventProcess(const Event &event)
50 {
51     // NOTE: This function CAN'T BE CALLED BETWEEN CTask::EventProcess AND CScriptFunctions::Process, otherwise weird stuff may happen to scripts (they'll be stuck executing the same task over and over again)
52     EndedTask();
53 
54     if ( m_foregroundTask != nullptr )
55     {
56         m_foregroundTask->EventProcess(event);
57     }
58 
59     if ( m_backgroundTask != nullptr )
60     {
61         m_backgroundTask->EventProcess(event);
62     }
63 
64     return true;
65 }
66 
IsForegroundTask()67 bool CTaskExecutorObjectImpl::IsForegroundTask()
68 {
69     return m_foregroundTask != nullptr;
70 }
71 
IsBackgroundTask()72 bool CTaskExecutorObjectImpl::IsBackgroundTask()
73 {
74     return m_backgroundTask != nullptr;
75 }
76 
GetForegroundTask()77 CForegroundTask* CTaskExecutorObjectImpl::GetForegroundTask()
78 {
79     return m_foregroundTask.get();
80 }
81 
GetBackgroundTask()82 CBackgroundTask* CTaskExecutorObjectImpl::GetBackgroundTask()
83 {
84     return m_backgroundTask.get();
85 }
86 
87 // Stops the current task.
88 
StopForegroundTask()89 void CTaskExecutorObjectImpl::StopForegroundTask()
90 {
91     if (m_foregroundTask != nullptr)
92     {
93         m_foregroundTask->Abort();
94         m_foregroundTask.reset();
95     }
96 }
97 
98 // Stops the current secondary task.
99 
StopBackgroundTask()100 void CTaskExecutorObjectImpl::StopBackgroundTask()
101 {
102     if (m_backgroundTask != nullptr)
103     {
104         m_backgroundTask->Abort();
105         m_backgroundTask.reset();
106     }
107 }
108 
109 // Completes the task when the time came.
110 
EndedTask()111 Error CTaskExecutorObjectImpl::EndedTask()
112 {
113     if (m_backgroundTask != nullptr)  // current task?
114     {
115         Error err = m_backgroundTask->IsEnded();
116         if ( err != ERR_CONTINUE )  // job ended?
117         {
118             m_backgroundTask.reset();
119             m_object->UpdateInterface();
120         }
121     }
122 
123     if (m_foregroundTask != nullptr)  // current task?
124     {
125         Error err = m_foregroundTask->IsEnded();
126         if ( err != ERR_CONTINUE )  // job ended?
127         {
128             m_foregroundTask.reset();
129             m_object->UpdateInterface();
130         }
131         return err;
132     }
133 
134     return ERR_STOP;
135 }
136 
137 template<typename TaskType, typename... Args>
StartForegroundTask(Args &&...args)138 Error CTaskExecutorObjectImpl::StartForegroundTask(Args&&... args)
139 {
140     static_assert(std::is_base_of<CForegroundTask, TaskType>::value, "not a foreground task");
141 
142     StopForegroundTask();
143 
144     assert(m_object->Implements(ObjectInterfaceType::Old)); //TODO
145     std::unique_ptr<TaskType> task = MakeUnique<TaskType>(dynamic_cast<COldObject*>(m_object));
146     Error err = task->Start(std::forward<Args>(args)...);
147     if (err == ERR_OK)
148         m_foregroundTask = std::move(task);
149     m_object->UpdateInterface();
150     return err;
151 }
152 
153 template<typename TaskType, typename... Args>
StartBackgroundTask(Args &&...args)154 Error CTaskExecutorObjectImpl::StartBackgroundTask(Args&&... args)
155 {
156     static_assert(std::is_base_of<CBackgroundTask, TaskType>::value, "not a background task");
157 
158     Error err;
159     TaskType* task = dynamic_cast<TaskType*>(m_backgroundTask.get());
160     if (task != nullptr)
161     {
162         err = task->Start(std::forward<Args>(args)...);
163         if (err != ERR_OK)
164             m_backgroundTask.reset();
165     }
166     else
167     {
168         m_backgroundTask.reset(); // In case the old task was of a different type
169 
170         assert(m_object->Implements(ObjectInterfaceType::Old)); //TODO
171         std::unique_ptr<TaskType> newTask = MakeUnique<TaskType>(dynamic_cast<COldObject*>(m_object));
172         err = newTask->Start(std::forward<Args>(args)...);
173         if (err == ERR_OK)
174             m_backgroundTask = std::move(newTask);
175     }
176     m_object->UpdateInterface();
177     return err;
178 }
179 
StartTaskTake()180 Error CTaskExecutorObjectImpl::StartTaskTake()
181 {
182     return StartForegroundTask<CTaskTake>();
183 }
184 
StartTaskManip(TaskManipOrder order,TaskManipArm arm)185 Error CTaskExecutorObjectImpl::StartTaskManip(TaskManipOrder order, TaskManipArm arm)
186 {
187     return StartForegroundTask<CTaskManip>(order, arm);
188 }
189 
StartTaskFlag(TaskFlagOrder order,int rank)190 Error CTaskExecutorObjectImpl::StartTaskFlag(TaskFlagOrder order, int rank)
191 {
192     return StartForegroundTask<CTaskFlag>(order, rank);
193 }
194 
StartTaskBuild(ObjectType type)195 Error CTaskExecutorObjectImpl::StartTaskBuild(ObjectType type)
196 {
197     return StartForegroundTask<CTaskBuild>(type);
198 }
199 
StartTaskSearch()200 Error CTaskExecutorObjectImpl::StartTaskSearch()
201 {
202     return StartForegroundTask<CTaskSearch>();
203 }
204 
StartTaskDeleteMark()205 Error CTaskExecutorObjectImpl::StartTaskDeleteMark()
206 {
207     return StartForegroundTask<CTaskDeleteMark>();
208 }
209 
StartTaskTerraform()210 Error CTaskExecutorObjectImpl::StartTaskTerraform()
211 {
212     return StartForegroundTask<CTaskTerraform>();
213 }
214 
StartTaskRecover()215 Error CTaskExecutorObjectImpl::StartTaskRecover()
216 {
217     return StartForegroundTask<CTaskRecover>();
218 }
219 
StartTaskFire(float delay)220 Error CTaskExecutorObjectImpl::StartTaskFire(float delay)
221 {
222     return StartForegroundTask<CTaskFire>(delay);
223 }
224 
StartTaskFireAnt(Math::Vector impact)225 Error CTaskExecutorObjectImpl::StartTaskFireAnt(Math::Vector impact)
226 {
227     return StartForegroundTask<CTaskFireAnt>(impact);
228 }
229 
StartTaskSpiderExplo()230 Error CTaskExecutorObjectImpl::StartTaskSpiderExplo()
231 {
232     return StartForegroundTask<CTaskSpiderExplo>();
233 }
234 
StartTaskPen(bool down,TraceColor color)235 Error CTaskExecutorObjectImpl::StartTaskPen(bool down, TraceColor color)
236 {
237     return StartForegroundTask<CTaskPen>(down, color);
238 }
239 
240 
StartTaskWait(float time)241 Error CTaskExecutorObjectImpl::StartTaskWait(float time)
242 {
243     return StartForegroundTask<CTaskWait>(time);
244 }
245 
StartTaskAdvance(float length)246 Error CTaskExecutorObjectImpl::StartTaskAdvance(float length)
247 {
248     return StartForegroundTask<CTaskAdvance>(length);
249 }
250 
StartTaskTurn(float angle)251 Error CTaskExecutorObjectImpl::StartTaskTurn(float angle)
252 {
253     return StartForegroundTask<CTaskTurn>(angle);
254 }
255 
StartTaskGoto(Math::Vector pos,float altitude,TaskGotoGoal goalMode,TaskGotoCrash crashMode)256 Error CTaskExecutorObjectImpl::StartTaskGoto(Math::Vector pos, float altitude, TaskGotoGoal goalMode, TaskGotoCrash crashMode)
257 {
258     return StartForegroundTask<CTaskGoto>(pos, altitude, goalMode, crashMode);
259 }
260 
StartTaskInfo(const char * name,float value,float power,bool bSend)261 Error CTaskExecutorObjectImpl::StartTaskInfo(const char *name, float value, float power, bool bSend)
262 {
263     return StartForegroundTask<CTaskInfo>(name, value, power, bSend);
264 }
265 
266 
StartTaskShield(TaskShieldMode mode,float delay)267 Error CTaskExecutorObjectImpl::StartTaskShield(TaskShieldMode mode, float delay)
268 {
269     return StartBackgroundTask<CTaskShield>(mode, delay);
270 }
271 
StartTaskGunGoal(float dirV,float dirH)272 Error CTaskExecutorObjectImpl::StartTaskGunGoal(float dirV, float dirH)
273 {
274     return StartBackgroundTask<CTaskGunGoal>(dirV, dirH);
275 }
276