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/autofactory.h"
22
23 #include "common/make_unique.h"
24
25 #include "level/robotmain.h"
26
27 #include "level/parser/parser.h"
28 #include "level/parser/parserline.h"
29 #include "level/parser/parserparam.h"
30
31 #include "math/geometry.h"
32
33 #include "object/object_create_params.h"
34 #include "object/object_manager.h"
35 #include "object/old_object.h"
36
37 #include "object/interface/program_storage_object.h"
38 #include "object/interface/programmable_object.h"
39 #include "object/interface/transportable_object.h"
40
41 #include "physics/physics.h"
42
43 #include "script/script.h"
44
45 #include "sound/sound.h"
46
47 #include "ui/controls/interface.h"
48 #include "ui/controls/window.h"
49
50
51 #include <boost/regex.hpp>
52
53
54
55 // Object's constructor.
56
CAutoFactory(COldObject * object)57 CAutoFactory::CAutoFactory(COldObject* object) : CAuto(object)
58 {
59 Init();
60 m_type = OBJECT_MOBILEws;
61 m_phase = AFP_WAIT; // paused until the first Init ()
62 m_channelSound = -1;
63 }
64
65 // Object's destructor.
66
~CAutoFactory()67 CAutoFactory::~CAutoFactory()
68 {
69 }
70
71
72 // Destroys the object.
73
DeleteObject(bool all)74 void CAutoFactory::DeleteObject(bool all)
75 {
76 if ( !all )
77 {
78 CObject* cargo = SearchCargo(); // transform metal?
79 if ( cargo != nullptr )
80 {
81 CObjectManager::GetInstancePointer()->DeleteObject(cargo);
82 }
83
84 CObject* vehicle = SearchVehicle();
85 if ( vehicle != nullptr )
86 {
87 CObjectManager::GetInstancePointer()->DeleteObject(vehicle);
88 }
89 }
90
91 if ( m_channelSound != -1 )
92 {
93 m_sound->FlushEnvelope(m_channelSound);
94 m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 1.0f, SOPER_STOP);
95 m_channelSound = -1;
96 }
97
98 CAuto::DeleteObject(all);
99 }
100
101
102 // Initialize the object.
103
Init()104 void CAutoFactory::Init()
105 {
106 m_phase = AFP_WAIT;
107 m_progress = 0.0f;
108 m_speed = 1.0f/2.0f;
109
110 m_time = 0.0f;
111 m_lastParticle = 0.0f;
112
113 m_cargoPos = m_object->GetPosition();
114
115 m_program = "";
116
117 CAuto::Init();
118 }
119
120
121 // Starts an action
122
StartAction(int param)123 Error CAutoFactory::StartAction(int param)
124 {
125 CObject* cargo;
126 ObjectType type = static_cast<ObjectType>(param);
127
128 if ( type != OBJECT_NULL )
129 {
130 if ( m_phase != AFP_WAIT )
131 {
132 return ERR_OBJ_BUSY;
133 }
134
135 m_type = type;
136
137 cargo = SearchCargo(); // transform metal?
138 if ( cargo == nullptr )
139 {
140 return ERR_FACTORY_NULL;
141 }
142 if ( NearestVehicle() )
143 {
144 return ERR_FACTORY_NEAR;
145 }
146
147 m_program = "";
148 SetBusy(true);
149 InitProgressTotal(3.0f+2.0f+15.0f+2.0f+3.0f);
150 UpdateInterface();
151
152 cargo->SetLock(true); // usable metal
153 SoundManip(3.0f, 1.0f, 0.5f);
154
155 m_phase = AFP_CLOSE_S;
156 m_progress = 0.0f;
157 m_speed = 1.0f/3.0f;
158 return ERR_OK;
159 }
160 return ERR_UNKNOWN;
161 }
162
163
164 // Sets program for created robot
165
SetProgram(const std::string & program)166 void CAutoFactory::SetProgram(const std::string& program)
167 {
168 m_program = program;
169 }
170
ObjectTypeFromFactoryButton(EventType eventType)171 static ObjectType ObjectTypeFromFactoryButton(EventType eventType)
172 {
173 if ( eventType == EVENT_OBJECT_FACTORYwa ) return OBJECT_MOBILEwa;
174 if ( eventType == EVENT_OBJECT_FACTORYta ) return OBJECT_MOBILEta;
175 if ( eventType == EVENT_OBJECT_FACTORYfa ) return OBJECT_MOBILEfa;
176 if ( eventType == EVENT_OBJECT_FACTORYia ) return OBJECT_MOBILEia;
177 if ( eventType == EVENT_OBJECT_FACTORYws ) return OBJECT_MOBILEws;
178 if ( eventType == EVENT_OBJECT_FACTORYts ) return OBJECT_MOBILEts;
179 if ( eventType == EVENT_OBJECT_FACTORYfs ) return OBJECT_MOBILEfs;
180 if ( eventType == EVENT_OBJECT_FACTORYis ) return OBJECT_MOBILEis;
181 if ( eventType == EVENT_OBJECT_FACTORYwc ) return OBJECT_MOBILEwc;
182 if ( eventType == EVENT_OBJECT_FACTORYtc ) return OBJECT_MOBILEtc;
183 if ( eventType == EVENT_OBJECT_FACTORYfc ) return OBJECT_MOBILEfc;
184 if ( eventType == EVENT_OBJECT_FACTORYic ) return OBJECT_MOBILEic;
185 if ( eventType == EVENT_OBJECT_FACTORYwi ) return OBJECT_MOBILEwi;
186 if ( eventType == EVENT_OBJECT_FACTORYti ) return OBJECT_MOBILEti;
187 if ( eventType == EVENT_OBJECT_FACTORYfi ) return OBJECT_MOBILEfi;
188 if ( eventType == EVENT_OBJECT_FACTORYii ) return OBJECT_MOBILEii;
189 if ( eventType == EVENT_OBJECT_FACTORYwb ) return OBJECT_MOBILEwb;
190 if ( eventType == EVENT_OBJECT_FACTORYtb ) return OBJECT_MOBILEtb;
191 if ( eventType == EVENT_OBJECT_FACTORYfb ) return OBJECT_MOBILEfb;
192 if ( eventType == EVENT_OBJECT_FACTORYib ) return OBJECT_MOBILEib;
193 if ( eventType == EVENT_OBJECT_FACTORYrt ) return OBJECT_MOBILErt;
194 if ( eventType == EVENT_OBJECT_FACTORYrc ) return OBJECT_MOBILErc;
195 if ( eventType == EVENT_OBJECT_FACTORYrr ) return OBJECT_MOBILErr;
196 if ( eventType == EVENT_OBJECT_FACTORYrs ) return OBJECT_MOBILErs;
197 if ( eventType == EVENT_OBJECT_FACTORYsa ) return OBJECT_MOBILEsa;
198 if ( eventType == EVENT_OBJECT_FACTORYtg ) return OBJECT_MOBILEtg;
199
200 return OBJECT_NULL;
201 }
202
203 // Management of an event.
204
EventProcess(const Event & event)205 bool CAutoFactory::EventProcess(const Event &event)
206 {
207 ObjectType type;
208 CObject* cargo;
209 CObject* vehicle;
210 Math::Matrix* mat;
211 CPhysics* physics;
212 Math::Vector pos, speed;
213 Math::Point dim;
214 float zoom, angle, prog;
215 int i;
216
217 CAuto::EventProcess(event);
218
219 if ( m_engine->GetPause() ) return true;
220
221 if ( m_object->GetSelect() ) // factory selected?
222 {
223 if ( event.type == EVENT_UPDINTERFACE )
224 {
225 CreateInterface(true);
226 }
227
228 type = ObjectTypeFromFactoryButton(event.type);
229
230 Error err = StartAction(type);
231 if( err != ERR_OK && err != ERR_UNKNOWN )
232 m_main->DisplayError(err, m_object);
233
234 if( err != ERR_UNKNOWN )
235 return false;
236 }
237
238 if ( event.type != EVENT_FRAME ) return true;
239
240 m_progress += event.rTime*m_speed;
241 EventProgress(event.rTime);
242
243 if ( m_phase == AFP_WAIT )
244 {
245 if ( m_progress >= 1.0f )
246 {
247 m_phase = AFP_WAIT; // still waiting ...
248 m_progress = 0.0f;
249 m_speed = 1.0f/2.0f;
250 }
251 }
252
253 if ( m_phase == AFP_CLOSE_S )
254 {
255 if ( m_progress < 1.0f )
256 {
257 for ( i=0 ; i<9 ; i++ )
258 {
259 zoom = 0.30f+(m_progress-0.5f+i/16.0f)*2.0f*0.70f;
260 if ( zoom < 0.30f ) zoom = 0.30f;
261 if ( zoom > 1.00f ) zoom = 1.00f;
262 m_object->SetPartScaleZ( 1+i, zoom);
263 m_object->SetPartScaleZ(10+i, zoom);
264 }
265 }
266 else
267 {
268 for ( i=0 ; i<9 ; i++ )
269 {
270 m_object->SetPartScaleZ( 1+i, 1.0f);
271 m_object->SetPartScaleZ(10+i, 1.0f);
272 }
273
274 SoundManip(2.0f, 1.0f, 1.2f);
275
276 m_phase = AFP_CLOSE_T;
277 m_progress = 0.0f;
278 m_speed = 1.0f/2.0f;
279 }
280 }
281
282 if ( m_phase == AFP_CLOSE_T )
283 {
284 if ( m_progress < 1.0f )
285 {
286 for ( i=0 ; i<9 ; i++ )
287 {
288 angle = -m_progress*(Math::PI/2.0f)+Math::PI/2.0f;
289 m_object->SetPartRotationZ( 1+i, angle);
290 m_object->SetPartRotationZ(10+i, -angle);
291 }
292 }
293 else
294 {
295 for ( i=0 ; i<9 ; i++ )
296 {
297 m_object->SetPartRotationZ( 1+i, 0.0f);
298 m_object->SetPartRotationZ(10+i, 0.0f);
299 }
300
301 m_channelSound = m_sound->Play(SOUND_FACTORY, m_object->GetPosition(), 0.0f, 1.0f, true);
302 m_sound->AddEnvelope(m_channelSound, 1.0f, 1.0f, 2.0f, SOPER_CONTINUE);
303 m_sound->AddEnvelope(m_channelSound, 1.0f, 1.0f, 11.0f, SOPER_CONTINUE);
304 m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 2.0f, SOPER_STOP);
305
306 m_phase = AFP_BUILD;
307 m_progress = 0.0f;
308 m_speed = 1.0f/15.0f;
309 }
310 }
311
312 if ( m_phase == AFP_BUILD )
313 {
314 if ( m_progress == 0.0f )
315 {
316 if ( !CreateVehicle() )
317 {
318 cargo = SearchCargo(); // transform metal?
319 if ( cargo != nullptr )
320 {
321 cargo->SetLock(false); // metal usable again
322 }
323
324 if ( m_channelSound != -1 )
325 {
326 m_sound->FlushEnvelope(m_channelSound);
327 m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 1.0f, SOPER_STOP);
328 m_channelSound = -1;
329 }
330
331 m_phase = AFP_OPEN_T;
332 m_progress = 0.0f;
333 m_speed = 1.0f/2.0f;
334 return true;
335 }
336 }
337
338 if ( m_progress < 1.0f )
339 {
340 if ( m_type == OBJECT_MOBILErt ||
341 m_type == OBJECT_MOBILErc ||
342 m_type == OBJECT_MOBILErr ||
343 m_type == OBJECT_MOBILErs )
344 {
345 prog = 1.0f-m_progress*1.5f;
346 if ( prog < 0.0f ) prog = 0.0f;
347 }
348 else
349 {
350 prog = 1.0f-m_progress;
351 }
352 angle = powf(prog*10.0f, 2.0f)+m_object->GetRotationY();
353
354 vehicle = SearchVehicle();
355 if ( vehicle != nullptr )
356 {
357 vehicle->SetRotationY(angle+Math::PI);
358 vehicle->SetScale(m_progress);
359 }
360
361 cargo = SearchCargo(); // transform metal?
362 if ( cargo != nullptr )
363 {
364 cargo->SetScale(1.0f-m_progress);
365 }
366
367 if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
368 {
369 m_lastParticle = m_time;
370
371 mat = m_object->GetWorldMatrix(0);
372 pos = Math::Vector(-12.0f, 20.0f, -4.0f); // position of chimney
373 pos = Math::Transform(*mat, pos);
374 pos.y += 2.0f;
375 pos.x += (Math::Rand()-0.5f)*2.0f;
376 pos.z += (Math::Rand()-0.5f)*2.0f;
377 speed.x = 0.0f;
378 speed.z = 0.0f;
379 speed.y = 6.0f+Math::Rand()*6.0f;
380 dim.x = Math::Rand()*1.5f+1.0f;
381 dim.y = dim.x;
382 m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISMOKE3, 4.0f);
383 }
384 }
385 else
386 {
387 m_main->DisplayError(INFO_FACTORY, m_object);
388 SoundManip(2.0f, 1.0f, 1.2f);
389
390 cargo = SearchCargo(); // transform metal?
391 if ( cargo != nullptr )
392 {
393 CObjectManager::GetInstancePointer()->DeleteObject(cargo);
394 }
395
396 vehicle = SearchVehicle();
397 if ( vehicle != nullptr )
398 {
399 assert(vehicle->Implements(ObjectInterfaceType::Movable));
400 physics = dynamic_cast<CMovableObject&>(*vehicle).GetPhysics();
401 physics->SetFreeze(false); // can move
402
403 vehicle->SetLock(false); // vehicle useable
404 vehicle->SetRotationY(m_object->GetRotationY()+Math::PI);
405 vehicle->SetScale(1.0f);
406
407 if ( !m_program.empty() )
408 {
409 if (vehicle->Implements(ObjectInterfaceType::Programmable) && vehicle->Implements(ObjectInterfaceType::ProgramStorage))
410 {
411 Program* program = dynamic_cast<CProgramStorageObject&>(*vehicle).AddProgram();
412
413 if (boost::regex_match(m_program, boost::regex("[A-Za-z0-9_]+"))) // Public function name?
414 {
415 std::string code = "extern void object::Start_"+m_program+"()\n{\n\t\n\t//Automatically generated by object.factory()\n\t"+m_program+"();\n\t\n}\n";
416 program->script->SendScript(code.c_str());
417 }
418 else if (boost::regex_match(m_program, boost::regex(".*\\.txt"))) // File name (with .txt extension)?
419 {
420 program->script->ReadScript(m_program.c_str());
421 }
422 else // Program code?
423 {
424 program->script->SendScript(m_program.c_str());
425 }
426
427 dynamic_cast<CProgrammableObject&>(*vehicle).RunProgram(program);
428 }
429 }
430 }
431
432 m_main->CreateShortcuts();
433
434 m_phase = AFP_OPEN_T;
435 m_progress = 0.0f;
436 m_speed = 1.0f/2.0f;
437 }
438 }
439
440 if ( m_phase == AFP_OPEN_T )
441 {
442 if ( m_progress < 1.0f )
443 {
444 for ( i=0 ; i<9 ; i++ )
445 {
446 angle = -(1.0f-m_progress)*(Math::PI/2.0f)+Math::PI/2.0f;
447 m_object->SetPartRotationZ( 1+i, angle);
448 m_object->SetPartRotationZ(10+i, -angle);
449 }
450
451 if ( m_lastParticle+m_engine->ParticleAdapt(0.1f) <= m_time )
452 {
453 m_lastParticle = m_time;
454
455 pos = m_cargoPos;
456 pos.x += (Math::Rand()-0.5f)*10.0f;
457 pos.z += (Math::Rand()-0.5f)*10.0f;
458 pos.y += Math::Rand()*10.0f;
459 speed = Math::Vector(0.0f, 0.0f, 0.0f);
460 dim.x = 2.0f;
461 dim.y = dim.x;
462 m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIGLINT, 2.0f, 0.0f, 0.0f);
463 }
464 }
465 else
466 {
467 for ( i=0 ; i<9 ; i++ )
468 {
469 m_object->SetPartRotationZ( 1+i, Math::PI/2.0f);
470 m_object->SetPartRotationZ(10+i, -Math::PI/2.0f);
471 }
472
473 SoundManip(3.0f, 1.0f, 0.5f);
474
475 m_phase = AFP_OPEN_S;
476 m_progress = 0.0f;
477 m_speed = 1.0f/3.0f;
478 }
479 }
480
481 if ( m_phase == AFP_OPEN_S )
482 {
483 if ( m_progress < 1.0f )
484 {
485 for ( i=0 ; i<9 ; i++ )
486 {
487 zoom = 0.30f+((1.0f-m_progress)-0.5f+i/16.0f)*2.0f*0.70f;
488 if ( zoom < 0.30f ) zoom = 0.30f;
489 if ( zoom > 1.00f ) zoom = 1.00f;
490 m_object->SetPartScaleZ( 1+i, zoom);
491 m_object->SetPartScaleZ(10+i, zoom);
492 }
493
494 if ( m_lastParticle+m_engine->ParticleAdapt(0.1f) <= m_time )
495 {
496 m_lastParticle = m_time;
497
498 pos = m_cargoPos;
499 pos.x += (Math::Rand()-0.5f)*10.0f;
500 pos.z += (Math::Rand()-0.5f)*10.0f;
501 pos.y += Math::Rand()*10.0f;
502 speed = Math::Vector(0.0f, 0.0f, 0.0f);
503 dim.x = 2.0f;
504 dim.y = dim.x;
505 m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIGLINT, 2.0f, 0.0f, 0.0f);
506 }
507 }
508 else
509 {
510 for ( i=0 ; i<9 ; i++ )
511 {
512 m_object->SetPartScaleZ( 1+i, 0.30f);
513 m_object->SetPartScaleZ(10+i, 0.30f);
514 }
515
516 SetBusy(false);
517 UpdateInterface();
518
519 m_phase = AFP_WAIT;
520 m_progress = 0.0f;
521 m_speed = 1.0f/2.0f;
522 }
523 }
524
525 return true;
526 }
527
528
529 // Saves all parameters of the controller.
530
Write(CLevelParserLine * line)531 bool CAutoFactory::Write(CLevelParserLine* line)
532 {
533 if ( m_phase == AFP_WAIT ) return false;
534
535 line->AddParam("aExist", MakeUnique<CLevelParserParam>(true));
536 CAuto::Write(line);
537 line->AddParam("aPhase", MakeUnique<CLevelParserParam>(static_cast<int>(m_phase)));
538 line->AddParam("aProgress", MakeUnique<CLevelParserParam>(m_progress));
539 line->AddParam("aSpeed", MakeUnique<CLevelParserParam>(m_speed));
540
541 return true;
542 }
543
544 // Restores all parameters of the controller
545
Read(CLevelParserLine * line)546 bool CAutoFactory::Read(CLevelParserLine* line)
547 {
548 if ( !line->GetParam("aExist")->AsBool(false) ) return false;
549
550 CAuto::Read(line);
551 m_phase = static_cast< AutoFactoryPhase >(line->GetParam("aPhase")->AsInt(AFP_WAIT));
552 m_progress = line->GetParam("aProgress")->AsFloat(0.0f);
553 m_speed = line->GetParam("aSpeed")->AsFloat(1.0f);
554
555 m_lastParticle = 0.0f;
556 m_cargoPos = m_object->GetPosition();
557
558 return true;
559 }
560
561
562 //Seeks the cargo.
563
SearchCargo()564 CObject* CAutoFactory::SearchCargo()
565 {
566 for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
567 {
568 ObjectType type = obj->GetType();
569 if ( type != OBJECT_METAL ) continue;
570 if (IsObjectBeingTransported(obj)) continue;
571
572 Math::Vector oPos = obj->GetPosition();
573 float dist = Math::Distance(oPos, m_cargoPos);
574
575 if ( dist < 8.0f ) return obj;
576 }
577
578 return nullptr;
579 }
580
581 // Search if a vehicle is too close.
582
NearestVehicle()583 bool CAutoFactory::NearestVehicle()
584 {
585 Math::Vector cPos = m_object->GetPosition();
586
587 for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
588 {
589 ObjectType type = obj->GetType();
590 if ( type != OBJECT_HUMAN &&
591 type != OBJECT_MOBILEfa &&
592 type != OBJECT_MOBILEta &&
593 type != OBJECT_MOBILEwa &&
594 type != OBJECT_MOBILEia &&
595 type != OBJECT_MOBILEfb &&
596 type != OBJECT_MOBILEtb &&
597 type != OBJECT_MOBILEwb &&
598 type != OBJECT_MOBILEib &&
599 type != OBJECT_MOBILEfc &&
600 type != OBJECT_MOBILEtc &&
601 type != OBJECT_MOBILEwc &&
602 type != OBJECT_MOBILEic &&
603 type != OBJECT_MOBILEfi &&
604 type != OBJECT_MOBILEti &&
605 type != OBJECT_MOBILEwi &&
606 type != OBJECT_MOBILEii &&
607 type != OBJECT_MOBILEfs &&
608 type != OBJECT_MOBILEts &&
609 type != OBJECT_MOBILEws &&
610 type != OBJECT_MOBILEis &&
611 type != OBJECT_MOBILErt &&
612 type != OBJECT_MOBILErc &&
613 type != OBJECT_MOBILErr &&
614 type != OBJECT_MOBILErs &&
615 type != OBJECT_MOBILEsa &&
616 type != OBJECT_MOBILEtg &&
617 type != OBJECT_MOBILEft &&
618 type != OBJECT_MOBILEtt &&
619 type != OBJECT_MOBILEwt &&
620 type != OBJECT_MOBILEit &&
621 type != OBJECT_MOBILErp &&
622 type != OBJECT_MOBILEst &&
623 type != OBJECT_MOBILEdr &&
624 type != OBJECT_MOTHER &&
625 type != OBJECT_ANT &&
626 type != OBJECT_SPIDER &&
627 type != OBJECT_BEE &&
628 type != OBJECT_WORM ) continue;
629
630 if (obj->GetCrashSphereCount() == 0) continue;
631
632 auto crashSphere = obj->GetFirstCrashSphere();
633 if (Math::DistanceToSphere(cPos, crashSphere.sphere) < 10.0f)
634 return true;
635 }
636
637 return false;
638 }
639
640
641 // Creates a vehicle.
642
CreateVehicle()643 bool CAutoFactory::CreateVehicle()
644 {
645 float angle = m_object->GetRotationY();
646
647 Math::Vector pos;
648 if ( m_type == OBJECT_MOBILErt ||
649 m_type == OBJECT_MOBILErc ||
650 m_type == OBJECT_MOBILErr ||
651 m_type == OBJECT_MOBILErs )
652 {
653 pos = Math::Vector(2.0f, 0.0f, 0.0f);
654 }
655 else
656 {
657 pos = Math::Vector(4.0f, 0.0f, 0.0f);
658 }
659 Math::Matrix* mat = m_object->GetWorldMatrix(0);
660 pos = Transform(*mat, pos);
661
662 ObjectCreateParams params;
663 params.pos = pos;
664 params.angle = angle;
665 params.type = m_type;
666 params.team = m_object->GetTeam();
667 params.trainer = m_object->GetTrainer();
668 CObject* vehicle = CObjectManager::GetInstancePointer()->CreateObject(params);
669
670 vehicle->SetLock(true); // not usable
671
672 assert(vehicle->Implements(ObjectInterfaceType::Movable));
673 CPhysics* physics = dynamic_cast<CMovableObject&>(*vehicle).GetPhysics();
674 physics->SetFreeze(true); // it doesn't move
675
676 if (vehicle->Implements(ObjectInterfaceType::ProgramStorage))
677 {
678 CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(vehicle);
679 for (const std::string& name : m_main->GetNewScriptNames(m_type))
680 {
681 Program* prog = programStorage->AddProgram();
682 programStorage->ReadProgram(prog, InjectLevelPathsForCurrentLevel(name, "ai"));
683 prog->readOnly = true;
684 prog->filename = name;
685 }
686 }
687
688 return true;
689 }
690
691 // Seeking the vehicle during manufacture.
692
SearchVehicle()693 CObject* CAutoFactory::SearchVehicle()
694 {
695 for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
696 {
697 if ( !obj->GetLock() ) continue;
698
699 ObjectType type = obj->GetType();
700 if ( type != m_type ) continue;
701 if (IsObjectBeingTransported(obj)) continue;
702
703 Math::Vector oPos = obj->GetPosition();
704 float dist = Math::Distance(oPos, m_cargoPos);
705
706 if ( dist < 8.0f ) return obj;
707 }
708
709 return nullptr;
710 }
711
712 // Creates all the interface when the object is selected.
713
CreateInterface(bool bSelect)714 bool CAutoFactory::CreateInterface(bool bSelect)
715 {
716 Ui::CWindow* pw;
717 Math::Point pos, dim, ddim;
718 float ox, oy, sx, sy;
719
720 CAuto::CreateInterface(bSelect);
721
722 if ( !bSelect ) return true;
723
724 pw = static_cast< Ui::CWindow* >(m_interface->SearchControl(EVENT_WINDOW0));
725 if ( pw == nullptr ) return false;
726
727 dim.x = 33.0f/640.0f;
728 dim.y = 33.0f/480.0f;
729 ox = 3.0f/640.0f;
730 oy = 3.0f/480.0f;
731 sx = 33.0f/640.0f;
732 sy = 33.0f/480.0f;
733 if( !m_object->GetTrainer() )
734 {
735 pos.x = 0.0f;
736 pos.y = oy+sy*2.6f;
737 ddim.x = 138.0f/640.0f;
738 ddim.y = 258.0f/480.0f;
739 pw->CreateGroup(pos, ddim, 6, EVENT_WINDOW3);
740
741 pos.x = ox+sx*0.0f;
742 pos.y = oy+sy*9.3f;
743 pw->CreateButton(pos, dim, 128+9, EVENT_OBJECT_FACTORYwa);
744 pos.x += dim.x;
745 pw->CreateButton(pos, dim, 128+10, EVENT_OBJECT_FACTORYta);
746 pos.x += dim.x;
747 pw->CreateButton(pos, dim, 128+11, EVENT_OBJECT_FACTORYfa);
748 pos.x += dim.x;
749 pw->CreateButton(pos, dim, 128+22, EVENT_OBJECT_FACTORYia);
750
751 pos.x = ox+sx*0.0f;
752 pos.y = oy+sy*8.2f;
753 pw->CreateButton(pos, dim, 128+12, EVENT_OBJECT_FACTORYws);
754 pos.x += dim.x;
755 pw->CreateButton(pos, dim, 128+13, EVENT_OBJECT_FACTORYts);
756 pos.x += dim.x;
757 pw->CreateButton(pos, dim, 128+14, EVENT_OBJECT_FACTORYfs);
758 pos.x += dim.x;
759 pw->CreateButton(pos, dim, 128+24, EVENT_OBJECT_FACTORYis);
760
761 pos.x = ox+sx*0.0f;
762 pos.y = oy+sy*7.1f;
763 pw->CreateButton(pos, dim, 128+15, EVENT_OBJECT_FACTORYwc);
764 pos.x += dim.x;
765 pw->CreateButton(pos, dim, 128+16, EVENT_OBJECT_FACTORYtc);
766 pos.x += dim.x;
767 pw->CreateButton(pos, dim, 128+17, EVENT_OBJECT_FACTORYfc);
768 pos.x += dim.x;
769 pw->CreateButton(pos, dim, 128+23, EVENT_OBJECT_FACTORYic);
770
771 pos.x = ox+sx*0.0f;
772 pos.y = oy+sy*6.0f;
773 pw->CreateButton(pos, dim, 128+25, EVENT_OBJECT_FACTORYwi);
774 pos.x += dim.x;
775 pw->CreateButton(pos, dim, 128+26, EVENT_OBJECT_FACTORYti);
776 pos.x += dim.x;
777 pw->CreateButton(pos, dim, 128+27, EVENT_OBJECT_FACTORYfi);
778 pos.x += dim.x;
779 pw->CreateButton(pos, dim, 128+28, EVENT_OBJECT_FACTORYii);
780
781 pos.x = ox+sx*0.0f;
782 pos.y = oy+sy*4.9f;
783 pw->CreateButton(pos, dim, 192+0, EVENT_OBJECT_FACTORYwb);
784 pos.x += dim.x;
785 pw->CreateButton(pos, dim, 192+1, EVENT_OBJECT_FACTORYtb);
786 pos.x += dim.x;
787 pw->CreateButton(pos, dim, 192+2, EVENT_OBJECT_FACTORYfb);
788 pos.x += dim.x;
789 pw->CreateButton(pos, dim, 192+3, EVENT_OBJECT_FACTORYib);
790
791 pos.x = ox+sx*0.0f;
792 pos.y = oy+sy*3.8f;
793 pw->CreateButton(pos, dim, 128+18, EVENT_OBJECT_FACTORYrt);
794 pos.x += dim.x;
795 pw->CreateButton(pos, dim, 128+19, EVENT_OBJECT_FACTORYrc);
796 pos.x += dim.x;
797 pw->CreateButton(pos, dim, 128+20, EVENT_OBJECT_FACTORYrr);
798 pos.x += dim.x;
799 pw->CreateButton(pos, dim, 128+29, EVENT_OBJECT_FACTORYrs);
800
801 pos.x = ox+sx*0.0f;
802 pos.y = oy+sy*2.7f;
803 pw->CreateButton(pos, dim, 128+21, EVENT_OBJECT_FACTORYsa);
804 pos.x += dim.x;
805 pw->CreateButton(pos, dim, 128+45, EVENT_OBJECT_FACTORYtg);
806 }
807
808 pos.x = ox+sx*0.0f;
809 pos.y = oy+sy*0;
810 ddim.x = 66.0f/640.0f;
811 ddim.y = 66.0f/480.0f;
812 pw->CreateGroup(pos, ddim, 101, EVENT_OBJECT_TYPE);
813
814 UpdateInterface();
815 return true;
816 }
817
818 // Updates the status of all interface buttons.
819
UpdateInterface()820 void CAutoFactory::UpdateInterface()
821 {
822 Ui::CWindow* pw;
823
824 if ( !m_object->GetSelect() ) return;
825
826 CAuto::UpdateInterface();
827
828 pw = static_cast< Ui::CWindow* >(m_interface->SearchControl(EVENT_WINDOW0));
829
830 UpdateButton(pw, EVENT_OBJECT_FACTORYwa, m_bBusy);
831 UpdateButton(pw, EVENT_OBJECT_FACTORYta, m_bBusy);
832 UpdateButton(pw, EVENT_OBJECT_FACTORYfa, m_bBusy);
833 UpdateButton(pw, EVENT_OBJECT_FACTORYia, m_bBusy);
834 UpdateButton(pw, EVENT_OBJECT_FACTORYws, m_bBusy);
835 UpdateButton(pw, EVENT_OBJECT_FACTORYts, m_bBusy);
836 UpdateButton(pw, EVENT_OBJECT_FACTORYfs, m_bBusy);
837 UpdateButton(pw, EVENT_OBJECT_FACTORYis, m_bBusy);
838 UpdateButton(pw, EVENT_OBJECT_FACTORYwc, m_bBusy);
839 UpdateButton(pw, EVENT_OBJECT_FACTORYtc, m_bBusy);
840 UpdateButton(pw, EVENT_OBJECT_FACTORYfc, m_bBusy);
841 UpdateButton(pw, EVENT_OBJECT_FACTORYic, m_bBusy);
842 UpdateButton(pw, EVENT_OBJECT_FACTORYwi, m_bBusy);
843 UpdateButton(pw, EVENT_OBJECT_FACTORYti, m_bBusy);
844 UpdateButton(pw, EVENT_OBJECT_FACTORYfi, m_bBusy);
845 UpdateButton(pw, EVENT_OBJECT_FACTORYii, m_bBusy);
846 UpdateButton(pw, EVENT_OBJECT_FACTORYwb, m_bBusy);
847 UpdateButton(pw, EVENT_OBJECT_FACTORYtb, m_bBusy);
848 UpdateButton(pw, EVENT_OBJECT_FACTORYfb, m_bBusy);
849 UpdateButton(pw, EVENT_OBJECT_FACTORYib, m_bBusy);
850 UpdateButton(pw, EVENT_OBJECT_FACTORYrt, m_bBusy);
851 UpdateButton(pw, EVENT_OBJECT_FACTORYrc, m_bBusy);
852 UpdateButton(pw, EVENT_OBJECT_FACTORYrr, m_bBusy);
853 UpdateButton(pw, EVENT_OBJECT_FACTORYrs, m_bBusy);
854 UpdateButton(pw, EVENT_OBJECT_FACTORYsa, m_bBusy);
855 UpdateButton(pw, EVENT_OBJECT_FACTORYtg, m_bBusy);
856 }
857
858 // Updates the status of one interface button.
859
UpdateButton(Ui::CWindow * pw,EventType event,bool bBusy)860 void CAutoFactory::UpdateButton(Ui::CWindow *pw, EventType event, bool bBusy)
861 {
862 EnableInterface(pw, event, !bBusy);
863 DeadInterface(pw, event, m_main->CanFactory(ObjectTypeFromFactoryButton(event), m_object->GetTeam()));
864 }
865
866 // Plays the sound of the manipulator arm.
867
SoundManip(float time,float amplitude,float frequency)868 void CAutoFactory::SoundManip(float time, float amplitude, float frequency)
869 {
870 int i;
871
872 i = m_sound->Play(SOUND_MANIP, m_object->GetPosition(), 0.0f, 0.3f*frequency, true);
873 m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, 0.1f, SOPER_CONTINUE);
874 m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, time-0.1f, SOPER_CONTINUE);
875 m_sound->AddEnvelope(i, 0.0f, 0.3f*frequency, 0.1f, SOPER_STOP);
876 }
877