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 
21 #include "object/auto/automush.h"
22 
23 #include "common/make_unique.h"
24 
25 #include "level/parser/parserline.h"
26 #include "level/parser/parserparam.h"
27 
28 #include "object/object_manager.h"
29 #include "object/old_object.h"
30 
31 #include "sound/sound.h"
32 
33 
34 // Object's constructor.
35 
CAutoMush(COldObject * object)36 CAutoMush::CAutoMush(COldObject* object) : CAuto(object)
37 {
38     Init();
39 }
40 
41 // Object's destructor.
42 
~CAutoMush()43 CAutoMush::~CAutoMush()
44 {
45 }
46 
47 
48 // Destroys the object.
49 
DeleteObject(bool bAll)50 void CAutoMush::DeleteObject(bool bAll)
51 {
52     CAuto::DeleteObject(bAll);
53 }
54 
55 
56 // Initialize the object.
57 
Init()58 void CAutoMush::Init()
59 {
60     m_phase    = AMP_WAIT;
61     m_progress = 0.0f;
62     m_speed    = 1.0f/4.0f;
63 
64     m_time     = 0.0f;
65     m_lastParticle = 0.0f;
66 }
67 
68 
69 // Management of an event.
70 
EventProcess(const Event & event)71 bool CAutoMush::EventProcess(const Event &event)
72 {
73     Math::Vector    pos, speed, dir;
74     Math::Point     dim;
75     float       factor, zoom, size, angle;
76     int         i, channel;
77 
78     CAuto::EventProcess(event);
79 
80     if ( m_engine->GetPause() )  return true;
81     if ( event.type != EVENT_FRAME )  return true;
82 
83     m_progress += event.rTime*m_speed;
84 
85     factor = 0.0f;
86     size = 1.0f;
87 
88     if ( m_phase == AMP_WAIT )
89     {
90         if ( m_progress >= 1.0f )
91         {
92             if ( !SearchTarget() )
93             {
94                 m_phase    = AMP_WAIT;
95                 m_progress = 0.0f;
96                 m_speed    = 1.0f/(2.0f+Math::Rand()*2.0f);
97             }
98             else
99             {
100                 m_phase    = AMP_SNIF;
101                 m_progress = 0.0f;
102                 m_speed    = 1.0f/1.5f;
103             }
104         }
105     }
106 
107     if ( m_phase == AMP_SNIF )
108     {
109         if ( m_progress < 1.0f )
110         {
111             factor = m_progress;
112         }
113         else
114         {
115             m_phase    = AMP_ZOOM;
116             m_progress = 0.0f;
117             m_speed    = 1.0f/1.0f;
118         }
119     }
120 
121     if ( m_phase == AMP_ZOOM )
122     {
123         if ( m_progress < 1.0f )
124         {
125             factor = 1.0f;
126             size = 1.0f+m_progress*0.3f;
127         }
128         else
129         {
130             m_sound->Play(SOUND_MUSHROOM, m_object->GetPosition());
131 
132             m_phase    = AMP_FIRE;
133             m_progress = 0.0f;
134             m_speed    = 1.0f/1.0f;
135         }
136     }
137 
138     if ( m_phase == AMP_FIRE )
139     {
140         if ( m_progress < 1.0f )
141         {
142             factor = 1.0f-m_progress;
143             size = 1.0f+(1.0f-m_progress)*0.3f;
144 
145             if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
146             {
147                 m_lastParticle = m_time;
148 
149                 for ( i=0 ; i<10 ; i++ )
150                 {
151                     pos = m_object->GetPosition();
152                     pos.y += 5.0f;
153                     speed.x = (Math::Rand()-0.5f)*200.0f;
154                     speed.z = (Math::Rand()-0.5f)*200.0f;
155                     speed.y = -(20.0f+Math::Rand()*20.0f);
156                     dim.x = 1.0f;
157                     dim.y = dim.x;
158                     channel = m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIGUN2, 2.0f, 100.0f, 0.0f);
159                     m_particle->SetObjectFather(channel, m_object);
160                 }
161             }
162         }
163         else
164         {
165             m_phase    = AMP_SMOKE;
166             m_progress = 0.0f;
167             m_speed    = 1.0f/2.0f;
168         }
169     }
170 
171     if ( m_phase == AMP_SMOKE )
172     {
173         if ( m_progress < 1.0f )
174         {
175             if ( m_lastParticle+m_engine->ParticleAdapt(0.10f) <= m_time )
176             {
177                 m_lastParticle = m_time;
178 
179                 pos = m_object->GetPosition();
180                 pos.y += 5.0f;
181                 speed.x = (Math::Rand()-0.5f)*4.0f;
182                 speed.z = (Math::Rand()-0.5f)*4.0f;
183                 speed.y = -(0.5f+Math::Rand()*0.5f);
184                 dim.x = Math::Rand()*2.5f+2.0f;
185                 dim.y = dim.x;
186                 m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISMOKE3, 4.0f, 0.0f, 0.0f);
187             }
188         }
189         else
190         {
191             m_phase    = AMP_WAIT;
192             m_progress = 0.0f;
193             m_speed    = 1.0f/(2.0f+Math::Rand()*2.0f);
194         }
195     }
196 
197     if ( factor != 0.0f || size != 1.0f )
198     {
199         dir.x = sinf(m_time*Math::PI*4.0f);
200         dir.z = cosf(m_time*Math::PI*4.0f);
201 
202         angle = sinf(m_time*10.0f)*factor*0.04f;
203         m_object->SetRotationX(angle*dir.z);
204         m_object->SetRotationZ(angle*dir.x);
205 
206         zoom = 1.0f+sinf(m_time*8.0f)*factor*0.06f;
207         m_object->SetScaleX(zoom*size);
208         zoom = 1.0f+sinf(m_time*5.0f)*factor*0.06f;
209         m_object->SetScaleY(zoom*size);
210         zoom = 1.0f+sinf(m_time*7.0f)*factor*0.06f;
211         m_object->SetScaleZ(zoom*size);
212     }
213     else
214     {
215         m_object->SetRotationX(0.0f);
216         m_object->SetRotationZ(0.0f);
217         m_object->SetScale(Math::Vector(1.0f, 1.0f, 1.0f));
218     }
219 
220     return true;
221 }
222 
223 
224 // Seeking a nearby target.
225 
SearchTarget()226 bool CAutoMush::SearchTarget()
227 {
228     Math::Vector iPos = m_object->GetPosition();
229 
230     for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
231     {
232         if ( obj->GetLock() )  continue;
233 
234         ObjectType type = obj->GetType();
235         if ( type != OBJECT_MOBILEfa &&
236              type != OBJECT_MOBILEta &&
237              type != OBJECT_MOBILEwa &&
238              type != OBJECT_MOBILEia &&
239              type != OBJECT_MOBILEfb &&
240              type != OBJECT_MOBILEtb &&
241              type != OBJECT_MOBILEwb &&
242              type != OBJECT_MOBILEib &&
243              type != OBJECT_MOBILEfc &&
244              type != OBJECT_MOBILEtc &&
245              type != OBJECT_MOBILEwc &&
246              type != OBJECT_MOBILEic &&
247              type != OBJECT_MOBILEfi &&
248              type != OBJECT_MOBILEti &&
249              type != OBJECT_MOBILEwi &&
250              type != OBJECT_MOBILEii &&
251              type != OBJECT_MOBILEfs &&
252              type != OBJECT_MOBILEts &&
253              type != OBJECT_MOBILEws &&
254              type != OBJECT_MOBILEis &&
255              type != OBJECT_MOBILErt &&
256              type != OBJECT_MOBILErc &&
257              type != OBJECT_MOBILErr &&
258              type != OBJECT_MOBILErs &&
259              type != OBJECT_MOBILEsa &&
260              type != OBJECT_MOBILEtg &&
261              type != OBJECT_MOBILEft &&
262              type != OBJECT_MOBILEtt &&
263              type != OBJECT_MOBILEwt &&
264              type != OBJECT_MOBILEit &&
265              type != OBJECT_MOBILErp &&
266              type != OBJECT_MOBILEst &&
267              type != OBJECT_MOBILEdr &&
268              type != OBJECT_DERRICK  &&
269              type != OBJECT_STATION  &&
270              type != OBJECT_FACTORY  &&
271              type != OBJECT_REPAIR   &&
272              type != OBJECT_DESTROYER&&
273              type != OBJECT_CONVERT  &&
274              type != OBJECT_TOWER    &&
275              type != OBJECT_RESEARCH &&
276              type != OBJECT_RADAR    &&
277              type != OBJECT_INFO     &&
278              type != OBJECT_ENERGY   &&
279              type != OBJECT_LABO     &&
280              type != OBJECT_NUCLEAR  &&
281              type != OBJECT_PARA     &&
282              type != OBJECT_HUMAN    )  continue;
283 
284        Math::Vector oPos = obj->GetPosition();
285         float dist = Math::Distance(oPos, iPos);
286         if ( dist < 50.0f )  return true;
287     }
288 
289     return false;
290 }
291 
292 
293 // Returns an error due the state of the automation.
294 
GetError()295 Error CAutoMush::GetError()
296 {
297     return ERR_OK;
298 }
299 
300 
301 // Saves all parameters of the controller.
302 
Write(CLevelParserLine * line)303 bool CAutoMush::Write(CLevelParserLine* line)
304 {
305     if ( m_phase == AMP_WAIT )  return false;
306 
307     line->AddParam("aExist", MakeUnique<CLevelParserParam>(true));
308     CAuto::Write(line);
309     line->AddParam("aPhase", MakeUnique<CLevelParserParam>(static_cast<int>(m_phase)));
310     line->AddParam("aProgress", MakeUnique<CLevelParserParam>(m_progress));
311     line->AddParam("aSpeed", MakeUnique<CLevelParserParam>(m_speed));
312 
313     return true;
314 }
315 
316 // Restores all parameters of the controller.
317 
Read(CLevelParserLine * line)318 bool CAutoMush::Read(CLevelParserLine* line)
319 {
320     if ( !line->GetParam("aExist")->AsBool(false) )  return false;
321 
322     CAuto::Read(line);
323     m_phase = static_cast< AutoMushPhase >(line->GetParam("aPhase")->AsInt(AMP_WAIT));
324     m_progress = line->GetParam("aProgress")->AsFloat(0.0f);
325     m_speed = line->GetParam("aSpeed")->AsFloat(1.0f);
326 
327     m_lastParticle = 0.0f;
328 
329     return true;
330 }
331