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 "graphics/engine/pyro.h"
22
23 #include "app/app.h"
24
25 #include "common/logger.h"
26
27 #include "graphics/engine/lightman.h"
28 #include "graphics/engine/particle.h"
29 #include "graphics/engine/terrain.h"
30
31 #include "level/robotmain.h"
32
33 #include "math/geometry.h"
34
35 #include "object/object_manager.h"
36 #include "object/old_object.h"
37
38 #include "object/motion/motionhuman.h"
39
40 #include "object/subclass/shielder.h"
41
42 #include "sound/sound.h"
43
44
45 // Graphics module namespace
46 namespace Gfx
47 {
48
49
CPyro()50 CPyro::CPyro()
51 {
52 m_engine = CEngine::GetInstancePointer();
53 m_main = CRobotMain::GetInstancePointer();
54 m_terrain = m_main->GetTerrain();
55 m_camera = m_main->GetCamera();
56 m_particle = m_engine->GetParticle();
57 m_lightMan = m_engine->GetLightManager();
58 m_sound = CApplication::GetInstancePointer()->GetSound();
59 }
60
~CPyro()61 CPyro::~CPyro()
62 {
63 }
64
DeleteObject()65 void CPyro::DeleteObject()
66 {
67 if ( m_lightRank != -1 )
68 {
69 m_lightMan->DeleteLight(m_lightRank);
70 m_lightRank = -1;
71 }
72 }
73
Create(PyroType type,CObject * obj,float force)74 bool CPyro::Create(PyroType type, CObject* obj, float force)
75 {
76 m_object = obj;
77 m_force = force;
78
79 ObjectType oType = obj->GetType();
80 int objRank = obj->GetObjectRank(0);
81 if (objRank == -1) return false;
82
83 Math::Vector min, max;
84 m_engine->GetObjectBBox(objRank, min, max);
85 Math::Vector pos = obj->GetPosition();
86
87 DisplayError(type, obj); // displays eventual messages
88
89 for (const auto& crashSphere : obj->GetAllCrashSpheres())
90 {
91 m_crashSpheres.push_back(crashSphere.sphere);
92 }
93
94 // Calculates the size of the effect.
95 if ( oType == OBJECT_ANT ||
96 oType == OBJECT_BEE ||
97 oType == OBJECT_WORM ||
98 oType == OBJECT_SPIDER )
99 {
100 m_size = 40.0f;
101 }
102 else
103 {
104 m_size = Math::Distance(min, max)*2.0f;
105 if ( m_size < 4.0f ) m_size = 4.0f;
106 if ( m_size > 80.0f ) m_size = 80.0f;
107 }
108 if ( oType == OBJECT_TNT ||
109 oType == OBJECT_BOMB )
110 {
111 m_size *= 2.0f;
112 }
113
114 m_pos = pos+(min+max)/2.0f;
115 m_type = type;
116 m_progress = 0.0f;
117 m_speed = 1.0f/20.0f; m_time = 0.0f;
118 m_lastParticle = 0.0f;
119 m_lastParticleSmoke = 0.0f;
120 m_lightRank = -1;
121
122 if ( oType == OBJECT_TEEN28 ||
123 oType == OBJECT_TEEN31 )
124 {
125 m_pos.y = pos.y+1.0f;
126 }
127
128 // Seeking the position of the battery.
129
130 CObject* power = nullptr;
131 if (obj->Implements(ObjectInterfaceType::Powered))
132 power = dynamic_cast<CPoweredObject&>(*obj).GetPower();
133
134 if (power == nullptr)
135 {
136 m_power = false;
137 }
138 else
139 {
140 m_power = true;
141 pos = power->GetPosition();
142 pos.y += 1.0f;
143 Math::Matrix* mat = obj->GetWorldMatrix(0);
144 m_posPower = Math::Transform(*mat, pos);
145 }
146
147 if ( oType == OBJECT_POWER ||
148 oType == OBJECT_ATOMIC ||
149 oType == OBJECT_URANIUM ||
150 oType == OBJECT_TNT ||
151 oType == OBJECT_BOMB )
152 {
153 m_power = true;
154 m_posPower = m_pos;
155 m_posPower.y += 1.0f;
156 m_pos = m_posPower;
157 }
158 if ( oType == OBJECT_STATION )
159 {
160 m_power = true;
161 Math::Matrix* mat = obj->GetWorldMatrix(0);
162 m_posPower = Math::Transform(*mat, Math::Vector(-15.0f, 7.0f, 0.0f));
163 m_pos = m_posPower;
164 }
165 if ( oType == OBJECT_ENERGY )
166 {
167 m_power = true;
168 Math::Matrix* mat = obj->GetWorldMatrix(0);
169 m_posPower = Math::Transform(*mat, Math::Vector(-7.0f, 6.0f, 0.0f));
170 m_pos = m_posPower;
171 }
172 if ( oType == OBJECT_NUCLEAR )
173 {
174 m_power = true;
175 m_posPower = m_pos;
176 }
177 if ( oType == OBJECT_PARA )
178 {
179 m_power = true;
180 m_posPower = m_pos;
181 }
182
183 // Plays the sound of a pyrotechnic effect.
184 if ( type == PT_FRAGT ||
185 type == PT_FRAGW ||
186 type == PT_EXPLOT ||
187 type == PT_EXPLOW )
188 {
189 SoundType sound;
190 if ( m_power )
191 {
192 sound = SOUND_EXPLOp;
193 }
194 else
195 {
196 sound = SOUND_EXPLO;
197 }
198 if ( oType == OBJECT_STONE ||
199 oType == OBJECT_METAL ||
200 oType == OBJECT_BULLET ||
201 oType == OBJECT_BBOX ||
202 oType == OBJECT_KEYa ||
203 oType == OBJECT_KEYb ||
204 oType == OBJECT_KEYc ||
205 oType == OBJECT_KEYd )
206 {
207 sound = SOUND_EXPLOl;
208 }
209 if ( oType == OBJECT_URANIUM ||
210 oType == OBJECT_POWER ||
211 oType == OBJECT_ATOMIC ||
212 oType == OBJECT_TNT ||
213 oType == OBJECT_BOMB )
214 {
215 sound = SOUND_EXPLOlp;
216 }
217 m_sound->Play(sound, m_pos);
218 }
219 if ( type == PT_FRAGO ||
220 type == PT_EXPLOO ||
221 type == PT_SPIDER ||
222 type == PT_SHOTM )
223 {
224 m_sound->Play(SOUND_EXPLOi, m_pos);
225 }
226 if ( type == PT_FRAGV )
227 {
228 m_sound->Play(SOUND_BOUMv, m_pos);
229 }
230 if ( type == PT_BURNT ||
231 type == PT_BURNO )
232 {
233 m_soundChannel = m_sound->Play(SOUND_BURN, m_pos, 1.0f, 1.0f, true);
234 m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 12.0f, SOPER_CONTINUE);
235 m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 5.0f, SOPER_STOP);
236 }
237 if ( type == PT_BURNO )
238 {
239 m_sound->Play(SOUND_DEADi, m_pos);
240 m_sound->Play(SOUND_DEADi, m_engine->GetEyePt());
241 }
242 if ( type == PT_EGG )
243 {
244 m_sound->Play(SOUND_EGG, m_pos);
245 }
246 if ( type == PT_WPCHECK ||
247 type == PT_FLCREATE ||
248 type == PT_FLDELETE )
249 {
250 m_sound->Play(SOUND_WAYPOINT, m_pos);
251 }
252 if ( oType == OBJECT_HUMAN )
253 {
254 if ( type == PT_DEADG )
255 {
256 m_sound->Play(SOUND_DEADg, m_pos);
257 }
258 if ( type == PT_DEADW )
259 {
260 m_sound->Play(SOUND_DEADw, m_pos);
261 }
262 assert(m_object->Implements(ObjectInterfaceType::Controllable));
263 if ( type == PT_SHOTH && dynamic_cast<CControllableObject&>(*m_object).GetSelect() )
264 {
265 m_sound->Play(SOUND_AIE, m_pos);
266 m_sound->Play(SOUND_AIE, m_engine->GetEyePt());
267 }
268 }
269
270 if ( m_type == PT_FRAGT ||
271 m_type == PT_FRAGO ||
272 m_type == PT_FRAGW ||
273 m_type == PT_FRAGV )
274 {
275 m_engine->DeleteShadowSpot(m_object->GetObjectRank(0));
276 }
277
278 if ( m_type == PT_DEADG )
279 {
280 assert(m_object->Implements(ObjectInterfaceType::Destroyable));
281 dynamic_cast<CDestroyableObject&>(*m_object).SetDying(DeathType::Dead);
282
283 assert(obj->Implements(ObjectInterfaceType::Movable));
284 dynamic_cast<CMovableObject&>(*obj).GetMotion()->SetAction(MHS_DEADg, 1.0f);
285
286 m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 1.5f);
287 m_camera->StartOver(CAM_OVER_EFFECT_FADEOUT_WHITE, m_pos, 1.0f);
288 m_speed = 1.0f/10.0f;
289 return true;
290 }
291 if ( m_type == PT_DEADW )
292 {
293 assert(m_object->Implements(ObjectInterfaceType::Destroyable));
294 dynamic_cast<CDestroyableObject&>(*m_object).SetDying(DeathType::Dead);
295
296 assert(obj->Implements(ObjectInterfaceType::Movable));
297 dynamic_cast<CMovableObject&>(*obj).GetMotion()->SetAction(MHS_DEADw, 1.0f);
298
299 m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 3.0f);
300 m_camera->StartOver(CAM_OVER_EFFECT_FADEOUT_BLACK, m_pos, 1.0f);
301 m_speed = 1.0f/10.0f;
302 return true;
303 }
304
305 if ( m_type == PT_SHOTT ||
306 m_type == PT_SHOTM )
307 {
308 m_camera->StartEffect(CAM_EFFECT_SHOT, m_pos, force);
309 m_speed = 1.0f/1.0f;
310 return true;
311 }
312 if ( m_type == PT_SHOTH )
313 {
314 assert(m_object->Implements(ObjectInterfaceType::Controllable));
315 if ( m_camera->GetBlood() && dynamic_cast<CControllableObject&>(*m_object).GetSelect() )
316 {
317 m_camera->StartOver(CAM_OVER_EFFECT_BLOOD, m_pos, force);
318 }
319 m_speed = 1.0f/0.2f;
320 return true;
321 }
322
323 if ( m_type == PT_SHOTW )
324 {
325 m_speed = 1.0f/1.0f;
326 }
327
328 if ( m_type == PT_BURNT )
329 {
330 BurnStart();
331 }
332
333 if ( m_type == PT_WPCHECK )
334 {
335 m_speed = 1.0f/8.0f;
336 m_object->SetLock(true); // object more functional
337 }
338 if ( m_type == PT_FLCREATE )
339 {
340 m_speed = 1.0f/2.0f;
341 }
342 if ( m_type == PT_FLDELETE )
343 {
344 m_speed = 1.0f/2.0f;
345 m_object->SetLock(true); // object more functional
346 }
347 if ( m_type == PT_RESET )
348 {
349 m_speed = 1.0f/2.0f;
350 m_resetAngle = m_object->GetRotationY();
351 }
352 if ( m_type == PT_FINDING )
353 {
354 float limit = (m_size-1.0f)/4.0f;
355 if (limit > 8.0f) limit = 8.0f;
356 if (oType == OBJECT_APOLLO2) limit = 2.0f;
357 m_speed = 1.0f/limit;
358 }
359 if ( m_type == PT_SQUASH )
360 {
361 m_speed = 1.0f/2.0f;
362 m_object->SetLock(true);
363 }
364
365
366 if ( m_type == PT_EXPLOT ||
367 m_type == PT_EXPLOO ||
368 m_type == PT_EXPLOW )
369 {
370 CreateTriangle(obj, oType, 0);
371 m_engine->DeleteShadowSpot(m_object->GetObjectRank(0));
372 ExploStart();
373 }
374
375 if ( m_type == PT_FALL )
376 {
377 FallStart();
378 return true;
379 }
380
381 if ( m_type == PT_BURNT ||
382 m_type == PT_BURNO )
383 {
384 m_speed = 1.0f/15.0f;
385
386 LightOperAdd(0.00f, 0.0f, 2.0f, 1.0f, 0.0f); // red-orange
387 LightOperAdd(0.30f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray
388 LightOperAdd(0.80f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray
389 LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray
390 CreateLight(m_pos, 40.0f);
391 return true;
392 }
393
394 if ( m_type == PT_SPIDER )
395 {
396 m_speed = 1.0f/15.0f;
397
398 pos = Math::Vector(-3.0f, 2.0f, 0.0f);
399 Math::Matrix* mat = obj->GetWorldMatrix(0);
400 m_pos = Math::Transform(*mat, pos);
401
402 m_engine->DeleteShadowSpot(m_object->GetObjectRank(0));
403 }
404
405 if ( m_type != PT_FRAGV &&
406 m_type != PT_EGG &&
407 m_type != PT_WIN &&
408 m_type != PT_LOST &&
409 m_type != PT_SQUASH)
410 {
411 float h = 40.0f;
412 if ( m_type == PT_FRAGO ||
413 m_type == PT_EXPLOO )
414 {
415 LightOperAdd(0.00f, 0.0f, -1.0f, -0.5f, -1.0f); // dark green
416 LightOperAdd(0.05f, 1.0f, -1.0f, -0.5f, -1.0f); // dark green
417 LightOperAdd(1.00f, 0.0f, -1.0f, -0.5f, -1.0f); // dark green
418 }
419 else if ( m_type == PT_FRAGT ||
420 m_type == PT_EXPLOT )
421 {
422 LightOperAdd(0.00f, 1.0f, 4.0f, 4.0f, 2.0f); // yellow
423 LightOperAdd(0.02f, 1.0f, 4.0f, 2.0f, 0.0f); // red-orange
424 LightOperAdd(0.16f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray
425 LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray
426 h = m_size*2.0f;
427 }
428 else if ( m_type == PT_SPIDER )
429 {
430 LightOperAdd(0.00f, 0.0f, -0.5f, -1.0f, -1.0f); // dark red
431 LightOperAdd(0.05f, 1.0f, -0.5f, -1.0f, -1.0f); // dark red
432 LightOperAdd(1.00f, 0.0f, -0.5f, -1.0f, -1.0f); // dark red
433 }
434 else if ( m_type == PT_FRAGW ||
435 m_type == PT_EXPLOW ||
436 m_type == PT_SHOTW )
437 {
438 LightOperAdd(0.00f, 0.0f, -0.5f, -0.5f, -1.0f); // dark yellow
439 LightOperAdd(0.05f, 1.0f, -0.5f, -0.5f, -1.0f); // dark yellow
440 LightOperAdd(1.00f, 0.0f, -0.5f, -0.5f, -1.0f); // dark yellow
441 }
442 else if ( m_type == PT_WPCHECK ||
443 m_type == PT_FLCREATE ||
444 m_type == PT_FLDELETE ||
445 m_type == PT_RESET ||
446 m_type == PT_FINDING )
447 {
448 LightOperAdd(0.00f, 1.0f, 4.0f, 4.0f, 2.0f); // yellow
449 LightOperAdd(1.00f, 0.0f, 4.0f, 4.0f, 2.0f); // yellow
450 }
451 else
452 {
453 LightOperAdd(0.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray
454 LightOperAdd(0.05f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray
455 LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray
456 }
457 CreateLight(m_pos, h);
458
459 if ( m_type != PT_SHOTW &&
460 m_type != PT_WPCHECK &&
461 m_type != PT_FLCREATE &&
462 m_type != PT_FLDELETE &&
463 m_type != PT_RESET &&
464 m_type != PT_FINDING &&
465 m_type != PT_SQUASH )
466 {
467 m_camera->StartEffect(CAM_EFFECT_EXPLO, m_pos, force);
468 }
469 }
470
471 if ( m_type == PT_SHOTW ) return true;
472
473 // Generates the triangles of the explosion.
474 if ( m_type == PT_FRAGT ||
475 m_type == PT_FRAGO ||
476 m_type == PT_FRAGW ||
477 m_type == PT_FRAGV ||
478 m_type == PT_SPIDER ||
479 m_type == PT_EGG ||
480 (m_type == PT_EXPLOT && oType == OBJECT_MOBILEtg) ||
481 (m_type == PT_EXPLOT && oType == OBJECT_TEEN28 ) ||
482 (m_type == PT_EXPLOT && oType == OBJECT_TEEN31 ) )
483 {
484 for (int part = 0; part < OBJECTMAXPART; part++)
485 {
486 CreateTriangle(obj, oType, part);
487 }
488 }
489
490 if ( m_type == PT_FRAGT ||
491 m_type == PT_EXPLOT )
492 {
493 if ( m_power )
494 {
495 int total = static_cast<int>(10.0f*m_engine->GetParticleDensity());
496 if ( oType == OBJECT_TNT ||
497 oType == OBJECT_BOMB ) total *= 3;
498 for (int i = 0; i < total; i++)
499 {
500 pos = m_posPower;
501 Math::Vector speed;
502 speed.x = (Math::Rand()-0.5f)*30.0f;
503 speed.z = (Math::Rand()-0.5f)*30.0f;
504 speed.y = Math::Rand()*30.0f;
505 Math::Point dim;
506 dim.x = 1.0f;
507 dim.y = dim.x;
508 float duration = Math::Rand()*3.0f+2.0f;
509 float mass = Math::Rand()*10.0f+15.0f;
510 m_particle->CreateTrack(pos, speed, dim, PARTITRACK1,
511 duration, mass, Math::Rand()+0.7f, 1.0f);
512 }
513 }
514
515 if (m_size > 10.0f) // large enough (freight excluded)?
516 {
517 if (m_power)
518 {
519 pos = m_posPower;
520 }
521 else
522 {
523 pos = m_pos;
524 m_terrain->AdjustToFloor(pos);
525 pos.y += 1.0f;
526 }
527 Math::Point dim;
528 dim.x = m_size*0.4f;
529 dim.y = dim.x;
530 m_particle->CreateParticle(pos, Math::Vector(0.0f,0.0f,0.0f), dim, PARTISPHERE0, 2.0f, 0.0f, 0.0f);
531 }
532 }
533
534 if ( m_type == PT_FRAGO ||
535 m_type == PT_EXPLOO )
536 {
537 int total = static_cast<int>(10.0f*m_engine->GetParticleDensity());
538 for (int i = 0; i < total; i++)
539 {
540 pos = m_pos;
541 Math::Vector speed;
542 speed.x = (Math::Rand()-0.5f)*30.0f;
543 speed.z = (Math::Rand()-0.5f)*30.0f;
544 speed.y = Math::Rand()*50.0f;
545 Math::Point dim;
546 dim.x = 1.0f;
547 dim.y = dim.x;
548 float duration = Math::Rand()*1.0f+0.8f;
549 float mass = Math::Rand()*10.0f+15.0f;
550 m_particle->CreateParticle(pos, speed, dim, PARTIORGANIC1,
551 duration, mass);
552 }
553 total = static_cast<int>(5.0f*m_engine->GetParticleDensity());
554 for (int i = 0; i < total; i++)
555 {
556 pos = m_pos;
557 Math::Vector speed;
558 speed.x = (Math::Rand()-0.5f)*30.0f;
559 speed.z = (Math::Rand()-0.5f)*30.0f;
560 speed.y = Math::Rand()*50.0f;
561 Math::Point dim;
562 dim.x = 1.0f;
563 dim.y = dim.x;
564 float duration = Math::Rand()*2.0f+1.4f;
565 float mass = Math::Rand()*10.0f+15.0f;
566 m_particle->CreateTrack(pos, speed, dim, PARTITRACK4,
567 duration, mass, duration*0.5f, dim.x*2.0f);
568 }
569 }
570
571 if ( m_type == PT_SPIDER )
572 {
573 for (int i = 0; i < 50; i++)
574 {
575 pos = m_pos;
576 pos.x += (Math::Rand()-0.5f)*3.0f;
577 pos.z += (Math::Rand()-0.5f)*3.0f;
578 pos.y += (Math::Rand()-0.5f)*2.0f;
579 Math::Vector speed;
580 speed.x = (Math::Rand()-0.5f)*24.0f;
581 speed.z = (Math::Rand()-0.5f)*24.0f;
582 speed.y = 10.0f+Math::Rand()*10.0f;
583 Math::Point dim;
584 dim.x = 1.0f;
585 dim.y = dim.x;
586 int channel = m_particle->CreateParticle(pos, speed, dim, PARTIGUN3, 2.0f+Math::Rand()*2.0f, 10.0f);
587 m_particle->SetObjectFather(channel, obj);
588 }
589 int total = static_cast<int>(10.0f*m_engine->GetParticleDensity());
590 for (int i = 0; i < total; i++)
591 {
592 pos = m_pos;
593 pos.x += (Math::Rand()-0.5f)*3.0f;
594 pos.z += (Math::Rand()-0.5f)*3.0f;
595 pos.y += (Math::Rand()-0.5f)*2.0f;
596 Math::Vector speed;
597 speed.x = (Math::Rand()-0.5f)*24.0f;
598 speed.z = (Math::Rand()-0.5f)*24.0f;
599 speed.y = 7.0f+Math::Rand()*7.0f;
600 Math::Point dim;
601 dim.x = 1.0f;
602 dim.y = dim.x;
603 m_particle->CreateTrack(pos, speed, dim, PARTITRACK3,
604 2.0f+Math::Rand()*2.0f, 10.0f, 2.0f, 0.6f);
605 }
606 }
607
608 if ( type == PT_FRAGT ||
609 type == PT_FRAGW ||
610 type == PT_EXPLOT ||
611 type == PT_EXPLOW )
612 {
613 if (m_size > 10.0f || m_power)
614 {
615 pos = m_pos;
616 Math::Vector speed(0.0f, 0.0f, 0.0f);
617 Math::Point dim;
618 dim.x = m_size;
619 dim.y = dim.x;
620 m_particle->CreateParticle(pos, speed, dim, PARTICHOC, 2.0f);
621 }
622 }
623
624 return true;
625 }
626
EventProcess(const Event & event)627 bool CPyro::EventProcess(const Event &event)
628 {
629 if (event.type != EVENT_FRAME) return true;
630 if (m_engine->GetPause()) return true;
631
632 m_time += event.rTime;
633 m_progress += event.rTime*m_speed;
634
635 if (m_soundChannel != -1 && m_object != nullptr)
636 {
637 Math::Vector pos = m_object->GetPosition();
638 m_sound->Position(m_soundChannel, pos);
639
640 if (m_lightRank != -1)
641 {
642 pos.y += m_lightHeight;
643 m_lightMan->SetLightPos(m_lightRank, pos);
644 }
645 }
646
647 if ( m_type == PT_SHOTT &&
648 m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
649 {
650 m_lastParticle = m_time;
651
652 if (m_crashSpheres.size() > 0)
653 {
654 int i = rand() % m_crashSpheres.size();
655 Math::Vector pos = m_crashSpheres[i].pos;
656 float radius = m_crashSpheres[i].radius;
657 pos.x += (Math::Rand()-0.5f)*radius*2.0f;
658 pos.z += (Math::Rand()-0.5f)*radius*2.0f;
659 Math::Vector speed;
660 speed.x = (Math::Rand()-0.5f)*radius*0.5f;
661 speed.z = (Math::Rand()-0.5f)*radius*0.5f;
662 speed.y = Math::Rand()*radius*1.0f;
663 Math::Point dim;
664 dim.x = Math::Rand()*radius*0.5f+radius*0.75f*m_force;
665 dim.y = dim.x;
666 m_particle->CreateParticle(pos, speed, dim, PARTISMOKE1, 3.0f);
667 }
668 else
669 {
670 Math::Vector pos = m_pos;
671 pos.x += (Math::Rand()-0.5f)*m_size*0.3f;
672 pos.z += (Math::Rand()-0.5f)*m_size*0.3f;
673 Math::Vector speed;
674 speed.x = (Math::Rand()-0.5f)*m_size*0.1f;
675 speed.z = (Math::Rand()-0.5f)*m_size*0.1f;
676 speed.y = Math::Rand()*m_size*0.2f;
677 Math::Point dim;
678 dim.x = Math::Rand()*m_size/10.0f+m_size/10.0f*m_force;
679 dim.y = dim.x;
680 m_particle->CreateParticle(pos, speed, dim, PARTISMOKE1, 3.0f);
681 }
682 }
683
684 if ( m_camera->GetBlood() && m_type == PT_SHOTH &&
685 m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
686 {
687 m_lastParticle = m_time;
688
689 for (int i = 0; i < 10; i++)
690 {
691 Math::Vector pos = m_pos;
692 pos.x += (Math::Rand()-0.5f)*m_size*0.2f;
693 pos.z += (Math::Rand()-0.5f)*m_size*0.2f;
694 pos.y += (Math::Rand()-0.5f)*m_size*0.5f;
695 Math::Vector speed;
696 speed.x = (Math::Rand()-0.5f)*5.0f;
697 speed.z = (Math::Rand()-0.5f)*5.0f;
698 speed.y = Math::Rand()*1.0f;
699 Math::Point dim;
700 dim.x = 1.0f;
701 dim.y = dim.x;
702 m_particle->CreateParticle(pos, speed, dim, PARTIBLOOD, Math::Rand()*3.0f+3.0f, Math::Rand()*10.0f+15.0f, 0.5f);
703 }
704 }
705
706 if ( m_camera->GetBlood() && m_type == PT_SHOTM &&
707 m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
708 {
709 m_lastParticle = m_time;
710
711 int r = static_cast<int>(10.0f*m_engine->GetParticleDensity());
712 for (int i = 0; i < r; i++)
713 {
714 Math::Vector pos = m_pos;
715 pos.x += (Math::Rand()-0.5f)*20.0f;
716 pos.z += (Math::Rand()-0.5f)*20.0f;
717 pos.y += 8.0f;
718 Math::Vector speed;
719 speed.x = (Math::Rand()-0.5f)*40.0f;
720 speed.z = (Math::Rand()-0.5f)*40.0f;
721 speed.y = Math::Rand()*40.0f;
722 Math::Point dim;
723 dim.x = Math::Rand()*8.0f+8.0f*m_force;
724 dim.y = dim.x;
725
726 m_particle->CreateParticle(pos, speed, dim, PARTIBLOODM, 2.0f, 50.0f, 0.0f);
727 }
728 }
729
730 if ( m_type == PT_SHOTW &&
731 m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
732 {
733 m_lastParticle = m_time;
734
735 if (m_crashSpheres.size() > 0)
736 {
737 int i = rand() % m_crashSpheres.size();
738 Math::Vector pos = m_crashSpheres[i].pos;
739 float radius = m_crashSpheres[i].radius;
740 pos.x += (Math::Rand()-0.5f)*radius*2.0f;
741 pos.z += (Math::Rand()-0.5f)*radius*2.0f;
742 Math::Vector speed;
743 speed.x = (Math::Rand()-0.5f)*radius*0.5f;
744 speed.z = (Math::Rand()-0.5f)*radius*0.5f;
745 speed.y = Math::Rand()*radius*1.0f;
746 Math::Point dim;
747 dim.x = 1.0f*m_force;
748 dim.y = dim.x;
749 m_particle->CreateParticle(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
750 }
751 else
752 {
753 Math::Vector pos = m_pos;
754 pos.x += (Math::Rand()-0.5f)*m_size*0.3f;
755 pos.z += (Math::Rand()-0.5f)*m_size*0.3f;
756 Math::Vector speed;
757 speed.x = (Math::Rand()-0.5f)*m_size*0.1f;
758 speed.z = (Math::Rand()-0.5f)*m_size*0.1f;
759 speed.y = Math::Rand()*m_size*0.2f;
760 Math::Point dim;
761 dim.x = 1.0f*m_force;
762 dim.y = dim.x;
763 m_particle->CreateParticle(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
764 }
765 }
766
767 if ( m_type == PT_SHOTW &&
768 m_lastParticleSmoke+m_engine->ParticleAdapt(0.10f) <= m_time )
769 {
770 m_lastParticleSmoke = m_time;
771
772 Math::Vector pos = m_pos;
773 pos.y -= 2.0f;
774 pos.x += (Math::Rand()-0.5f)*4.0f;
775 pos.z += (Math::Rand()-0.5f)*4.0f;
776 Math::Vector speed;
777 speed.x = 0.0f;
778 speed.z = 0.0f;
779 speed.y = 10.0f+Math::Rand()*10.0f;
780 Math::Point dim;
781 dim.x = Math::Rand()*2.5f+2.0f*m_force;
782 dim.y = dim.x;
783 m_particle->CreateParticle(pos, speed, dim, PARTICRASH, 4.0f);
784 }
785
786 if ( (m_type == PT_FRAGT || m_type == PT_EXPLOT) &&
787 m_progress < 0.05f &&
788 m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
789 {
790 m_lastParticle = m_time;
791
792 Math::Vector pos = m_pos;
793 Math::Vector speed;
794 speed.x = (Math::Rand()-0.5f)*m_size*1.0f;
795 speed.z = (Math::Rand()-0.5f)*m_size*1.0f;
796 speed.y = Math::Rand()*m_size*0.50f;
797 Math::Point dim;
798 dim.x = Math::Rand()*m_size/5.0f+m_size/5.0f;
799 dim.y = dim.x;
800
801 m_particle->CreateParticle(pos, speed, dim, PARTIEXPLOT);
802 }
803
804 if ( (m_type == PT_FRAGT || m_type == PT_EXPLOT) &&
805 m_progress < 0.10f &&
806 m_lastParticleSmoke+m_engine->ParticleAdapt(0.10f) <= m_time )
807 {
808 m_lastParticleSmoke = m_time;
809
810 Math::Point dim;
811 dim.x = Math::Rand()*m_size/3.0f+m_size/3.0f;
812 dim.y = dim.x;
813 Math::Vector pos = m_pos;
814 pos.x += (Math::Rand()-0.5f)*m_size*0.5f;
815 pos.z += (Math::Rand()-0.5f)*m_size*0.5f;
816 m_terrain->AdjustToFloor(pos);
817 Math::Vector speed;
818 speed.x = 0.0f;
819 speed.z = 0.0f;
820 speed.y = -dim.x/2.0f/4.0f;
821 pos.y += dim.x/2.0f;
822
823 ParticleType type;
824 int r = rand()%2;
825 if (r == 0) type = PARTISMOKE1;
826 if (r == 1) type = PARTISMOKE2;
827 m_particle->CreateParticle(pos, speed, dim, type, 6.0f);
828 }
829
830 if ( (m_type == PT_FRAGO || m_type == PT_EXPLOO) &&
831 m_progress < 0.03f &&
832 m_lastParticle+m_engine->ParticleAdapt(0.1f) <= m_time )
833 {
834 m_lastParticle = m_time;
835
836 Math::Vector pos = m_pos;
837 Math::Vector speed;
838 speed.x = (Math::Rand()-0.5f)*m_size*2.0f;
839 speed.z = (Math::Rand()-0.5f)*m_size*2.0f;
840 speed.y = Math::Rand()*m_size*1.0f;
841 Math::Point dim;
842 dim.x = Math::Rand()*m_size/2.0f+m_size/2.0f;
843 dim.y = dim.x;
844
845 m_particle->CreateParticle(pos, speed, dim, PARTIEXPLOO);
846 }
847
848 if ( (m_type == PT_FRAGW || m_type == PT_EXPLOW) &&
849 m_progress < 0.05f &&
850 m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
851 {
852 m_lastParticle = m_time;
853
854 Math::Vector pos = m_pos;
855 Math::Vector speed;
856 speed.x = (Math::Rand()-0.5f)*m_size*1.0f;
857 speed.z = (Math::Rand()-0.5f)*m_size*1.0f;
858 speed.y = Math::Rand()*m_size*0.50f;
859 Math::Point dim;
860 dim.x = 1.0f;
861 dim.y = dim.x;
862
863 m_particle->CreateParticle(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
864 }
865
866 if ( (m_type == PT_FRAGW || m_type == PT_EXPLOW) &&
867 m_progress < 0.25f &&
868 m_lastParticleSmoke+m_engine->ParticleAdapt(0.05f) <= m_time )
869 {
870 m_lastParticleSmoke = m_time;
871
872 Math::Vector pos = m_pos;
873 pos.y -= 2.0f;
874 pos.x += (Math::Rand()-0.5f)*4.0f;
875 pos.z += (Math::Rand()-0.5f)*4.0f;
876 Math::Vector speed;
877 speed.x = 0.0f;
878 speed.z = 0.0f;
879 speed.y = 4.0f+Math::Rand()*4.0f;
880 Math::Point dim;
881 dim.x = Math::Rand()*2.5f+2.0f;
882 dim.y = dim.x;
883 m_particle->CreateParticle(pos, speed, dim, PARTICRASH, 4.0f);
884 }
885
886 if ( m_type == PT_WPCHECK )
887 {
888 float factor;
889 if (m_progress < 0.25f)
890 factor = 0.0f;
891 else
892 factor = powf((m_progress-0.25f)/0.75f, 2.0f)*30.0f;
893
894 if ( m_progress < 0.85f &&
895 m_lastParticle+m_engine->ParticleAdapt(0.10f) <= m_time )
896 {
897 m_lastParticle = m_time;
898
899 Math::Vector pos = m_pos;
900 pos.y += factor;
901 pos.x += (Math::Rand()-0.5f)*3.0f;
902 pos.z += (Math::Rand()-0.5f)*3.0f;
903 Math::Vector speed;
904 speed.x = 0.0f;
905 speed.z = 0.0f;
906 speed.y = 5.0f+Math::Rand()*5.0f;
907 Math::Point dim;
908 dim.x = Math::Rand()*1.5f+1.5f;
909 dim.y = dim.x;
910 m_particle->CreateParticle(pos, speed, dim, PARTIGLINT, 2.0f);
911 }
912
913 if(m_object != nullptr)
914 {
915 Math::Vector angle = m_object->GetRotation();
916 angle.y = m_progress*20.0f;
917 angle.x = sinf(m_progress*49.0f)*0.3f;
918 angle.z = sinf(m_progress*47.0f)*0.2f;
919 m_object->SetRotation(angle);
920
921 Math::Vector pos = m_pos;
922 pos.y += factor;
923 m_object->SetPosition(pos);
924
925 if ( m_progress > 0.85f )
926 {
927 m_object->SetScale(1.0f-(m_progress-0.85f)/0.15f);
928 }
929 }
930 }
931
932 if ( m_type == PT_FLCREATE )
933 {
934 if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
935 {
936 m_lastParticle = m_time;
937
938 Math::Vector pos = m_pos;
939 m_terrain->AdjustToFloor(pos);
940 pos.x += (Math::Rand()-0.5f)*1.0f;
941 pos.z += (Math::Rand()-0.5f)*1.0f;
942 Math::Vector speed;
943 speed.x = (Math::Rand()-0.5f)*2.0f;
944 speed.z = (Math::Rand()-0.5f)*2.0f;
945 speed.y = 2.0f+Math::Rand()*2.0f;
946 Math::Point dim;
947 dim.x = (Math::Rand()*1.0f+1.0f)*(0.2f+m_progress*0.8f);
948 dim.y = dim.x;
949 m_particle->CreateParticle(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.0f);
950 }
951
952 if(m_object != nullptr)
953 {
954 Math::Vector angle = m_object->GetRotation();
955 angle.x = sinf(m_progress*49.0f)*0.3f*(1.0f-m_progress);
956 angle.z = sinf(m_progress*47.0f)*0.2f*(1.0f-m_progress);
957 m_object->SetRotation(angle);
958
959 m_object->SetScale(m_progress);
960 }
961 }
962
963 if ( m_type == PT_FLDELETE )
964 {
965 if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
966 {
967 m_lastParticle = m_time;
968
969 Math::Vector pos = m_pos;
970 m_terrain->AdjustToFloor(pos);
971 pos.x += (Math::Rand()-0.5f)*1.0f;
972 pos.z += (Math::Rand()-0.5f)*1.0f;
973 Math::Vector speed;
974 speed.x = (Math::Rand()-0.5f)*2.0f;
975 speed.z = (Math::Rand()-0.5f)*2.0f;
976 speed.y = 2.0f+Math::Rand()*2.0f;
977 Math::Point dim;
978 dim.x = (Math::Rand()*1.0f+1.0f)*(0.2f+m_progress*0.8f);
979 dim.y = dim.x;
980 m_particle->CreateParticle(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.5f);
981 }
982
983 if(m_object != nullptr)
984 {
985 Math::Vector angle = m_object->GetRotation();
986 angle.y = m_progress*20.0f;
987 angle.x = sinf(m_progress*49.0f)*0.3f;
988 angle.z = sinf(m_progress*47.0f)*0.2f;
989 m_object->SetRotation(angle);
990
991 m_object->SetScale(1.0f-m_progress);
992 }
993 }
994
995 if ( m_type == PT_RESET )
996 {
997 if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
998 {
999 m_lastParticle = m_time;
1000
1001 Math::Vector pos = m_pos;
1002 pos.x += (Math::Rand()-0.5f)*5.0f;
1003 pos.z += (Math::Rand()-0.5f)*5.0f;
1004 Math::Vector speed;
1005 speed.x = 0.0f;
1006 speed.z = 0.0f;
1007 speed.y = 5.0f+Math::Rand()*5.0f;
1008 Math::Point dim;
1009 dim.x = Math::Rand()*2.0f+2.0f;
1010 dim.y = dim.x;
1011 m_particle->CreateParticle(pos, speed, dim, PARTIGLINTb, 2.0f);
1012
1013 pos = m_pos;
1014 speed.x = (Math::Rand()-0.5f)*20.0f;
1015 speed.z = (Math::Rand()-0.5f)*20.0f;
1016 speed.y = Math::Rand()*10.0f;
1017 speed *= 0.5f+m_progress*0.5f;
1018 dim.x = 0.6f;
1019 dim.y = dim.x;
1020 pos.y += dim.y;
1021 float duration = Math::Rand()*1.5f+1.5f;
1022 m_particle->CreateTrack(pos, speed, dim, PARTITRACK6,
1023 duration, 0.0f,
1024 duration*0.9f, 0.7f);
1025 }
1026
1027 if(m_object != nullptr)
1028 {
1029 float angle = m_resetAngle;
1030 m_object->SetRotationY(angle-powf((1.0f-m_progress)*5.0f, 2.0f));
1031 m_object->SetScale(m_progress);
1032 }
1033 }
1034
1035 if ( m_type == PT_FINDING )
1036 {
1037 if ( m_object != nullptr &&
1038 m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
1039 {
1040 m_lastParticle = m_time;
1041
1042 float factor = m_size*0.3f;
1043 if (m_object->GetType() == OBJECT_SAFE) factor *= 1.3f;
1044 if (factor > 40.0f) factor = 40.0f;
1045 Math::Vector pos = m_pos;
1046 m_terrain->AdjustToFloor(pos);
1047 pos.x += (Math::Rand()-0.5f)*factor;
1048 pos.z += (Math::Rand()-0.5f)*factor;
1049 Math::Vector speed;
1050 speed.x = (Math::Rand()-0.5f)*2.0f;
1051 speed.z = (Math::Rand()-0.5f)*2.0f;
1052 speed.y = 4.0f+Math::Rand()*4.0f;
1053 Math::Point dim;
1054 dim.x = (Math::Rand()*3.0f+3.0f)*(1.0f-m_progress*0.9f);
1055 dim.y = dim.x;
1056 m_particle->CreateParticle(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.5f);
1057 }
1058 }
1059
1060 if ( m_type == PT_SQUASH && m_object != nullptr )
1061 {
1062 m_object->SetScaleY(1.0f-sinf(m_progress)*0.5f);
1063 }
1064
1065 if ( (m_type == PT_BURNT || m_type == PT_BURNO) &&
1066 m_object != nullptr )
1067 {
1068 if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
1069 {
1070 m_lastParticle = m_time;
1071
1072 float factor = m_size/25.0f; // 1 = standard size
1073
1074 Math::Vector pos = m_object->GetPosition();
1075 pos.y -= m_object->GetCharacter()->height;
1076 pos.x += (Math::Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor;
1077 pos.z += (Math::Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor;
1078 Math::Vector speed;
1079 speed.x = 0.0f;
1080 speed.z = 0.0f;
1081 speed.y = 0.0f;
1082 Math::Point dim;
1083 dim.x = (Math::Rand()*2.5f+1.0f)*factor;
1084 dim.y = dim.x;
1085 m_particle->CreateParticle(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f);
1086
1087 pos = m_object->GetPosition();
1088 pos.y -= m_object->GetCharacter()->height;
1089 pos.x += (Math::Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor;
1090 pos.z += (Math::Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor;
1091 speed.x = 0.0f;
1092 speed.z = 0.0f;
1093 speed.y = (Math::Rand()*5.0f*m_progress+3.0f)*factor;
1094 dim.x = (Math::Rand()*2.0f+1.0f)*factor;
1095 dim.y = dim.x;
1096 m_particle->CreateParticle(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f);
1097
1098 pos = m_object->GetPosition();
1099 pos.y -= 2.0f;
1100 pos.x += (Math::Rand()-0.5f)*5.0f*factor;
1101 pos.z += (Math::Rand()-0.5f)*5.0f*factor;
1102 speed.x = 0.0f;
1103 speed.z = 0.0f;
1104 speed.y = (6.0f+Math::Rand()*6.0f+m_progress*6.0f)*factor;
1105 dim.x = (Math::Rand()*1.5f+1.0f+m_progress*3.0f)*factor;
1106 dim.y = dim.x;
1107 m_particle->CreateParticle(pos, speed, dim, PARTISMOKE3, 4.0f);
1108 }
1109
1110 if ( m_type == PT_BURNT )
1111 {
1112 BurnProgress();
1113 }
1114 else
1115 {
1116 Math::Vector speed;
1117 speed.y = 0.0f;
1118 speed.x = (Math::Rand()-0.5f)*m_progress*1.0f;
1119 speed.z = (Math::Rand()-0.5f)*m_progress*1.0f;
1120 if ( m_progress > 0.8f )
1121 {
1122 float prog = (m_progress-0.8f)/0.2f; // 0..1
1123 speed.y = -prog*6.0f; // sinks into the ground
1124 m_object->SetScale(1.0f-prog*0.5f);
1125 }
1126 m_object->SetLinVibration(speed);
1127 }
1128 }
1129
1130 if ( m_type == PT_WIN &&
1131 m_object != nullptr )
1132 {
1133 if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
1134 {
1135 m_lastParticle = m_time;
1136
1137 Math::Vector pos = m_object->GetPosition();
1138 pos.y += 1.5f;
1139 Math::Vector speed;
1140 speed.x = (Math::Rand()-0.5f)*10.0f;
1141 speed.z = (Math::Rand()-0.5f)*10.0f;
1142 speed.y = 8.0f+Math::Rand()*8.0f;
1143 Math::Point dim;
1144 dim.x = Math::Rand()*0.2f+0.2f;
1145 dim.y = dim.x;
1146 m_particle->CreateTrack(pos, speed, dim,
1147 static_cast<ParticleType>(PARTITRACK7+rand()%4),
1148 3.0f, 20.0f, 1.0f, 0.4f);
1149 }
1150 }
1151
1152 if ( m_type == PT_LOST &&
1153 m_object != nullptr )
1154 {
1155 if ( m_lastParticle+m_engine->ParticleAdapt(0.10f) <= m_time )
1156 {
1157 m_lastParticle = m_time;
1158
1159 Math::Vector pos = m_object->GetPosition();
1160 pos.y -= 2.0f;
1161 pos.x += (Math::Rand()-0.5f)*10.0f;
1162 pos.z += (Math::Rand()-0.5f)*10.0f;
1163 Math::Vector speed;
1164 speed.x = 0.0f;
1165 speed.z = 0.0f;
1166 speed.y = 1.0f+Math::Rand()*1.0f;
1167 Math::Point dim;
1168 dim.x = Math::Rand()*1.0f+1.0f;
1169 dim.y = dim.x;
1170 m_particle->CreateParticle(pos, speed, dim, PARTISMOKE1, 8.0f, 0.0f, 0.0f);
1171 }
1172 }
1173
1174 if (m_type == PT_FALL)
1175 FallProgress(event.rTime);
1176
1177 if (m_lightRank != -1)
1178 LightOperFrame(event.rTime);
1179
1180 return true;
1181 }
1182
IsEnded()1183 Error CPyro::IsEnded()
1184 {
1185 // Destroys the object that exploded.
1186 //It should not be destroyed at the end of the Create,
1187 //because it is sometimes the object itself that makes the Create:
1188 // pyro->Create(PT_FRAGT, this);
1189 if ( m_type == PT_FRAGT ||
1190 m_type == PT_FRAGO ||
1191 m_type == PT_FRAGW ||
1192 m_type == PT_FRAGV ||
1193 m_type == PT_SPIDER ||
1194 m_type == PT_EGG )
1195 {
1196 DeleteObject(true, true);
1197 }
1198
1199 if ( m_type == PT_FALL ) // freight which grave?
1200 {
1201 return FallIsEnded();
1202 }
1203
1204 if ( m_type == PT_WIN ||
1205 m_type == PT_LOST )
1206 {
1207 return ERR_CONTINUE;
1208 }
1209
1210 // End of the pyrotechnic effect?
1211 if ( m_progress < 1.0f ) return ERR_CONTINUE;
1212
1213 if ( m_type == PT_EXPLOT ||
1214 m_type == PT_EXPLOO ||
1215 m_type == PT_EXPLOW ) // explosion?
1216 {
1217 ExploTerminate();
1218 }
1219
1220 if ( m_type == PT_BURNT ||
1221 m_type == PT_BURNO ) // burning?
1222 {
1223 BurnTerminate();
1224 }
1225
1226 if ( m_type == PT_WPCHECK ||
1227 m_type == PT_FLDELETE )
1228 {
1229 DeleteObject(true, true);
1230 }
1231
1232 if ( m_type == PT_FLCREATE )
1233 {
1234 m_object->SetRotationX(0.0f);
1235 m_object->SetRotationZ(0.0f);
1236 m_object->SetScale(1.0f);
1237 }
1238
1239 if ( m_type == PT_RESET )
1240 {
1241 m_object->SetRotationY(m_resetAngle);
1242 m_object->SetScale(1.0f);
1243 }
1244
1245 if ( m_type == PT_SQUASH )
1246 {
1247 m_object->SetType(OBJECT_PLANT19);
1248 }
1249
1250 if ( m_lightRank != -1 )
1251 {
1252 m_lightMan->DeleteLight(m_lightRank);
1253 m_lightRank = -1;
1254 }
1255
1256 return ERR_STOP;
1257 }
1258
CutObjectLink(CObject * obj)1259 void CPyro::CutObjectLink(CObject* obj)
1260 {
1261 if (m_object == obj)
1262 m_object = nullptr;
1263 }
1264
DisplayError(PyroType type,CObject * obj)1265 void CPyro::DisplayError(PyroType type, CObject* obj)
1266 {
1267 ObjectType oType = obj->GetType();
1268
1269 if ( type == PT_FRAGT ||
1270 type == PT_FRAGO ||
1271 type == PT_FRAGW ||
1272 type == PT_EXPLOT ||
1273 type == PT_EXPLOO ||
1274 type == PT_EXPLOW ||
1275 type == PT_BURNT ||
1276 type == PT_BURNO )
1277 {
1278 Error err = ERR_OK;
1279 if ( oType == OBJECT_MOTHER ) err = INFO_DELETEMOTHER;
1280 if ( oType == OBJECT_ANT ) err = INFO_DELETEANT;
1281 if ( oType == OBJECT_BEE ) err = INFO_DELETEBEE;
1282 if ( oType == OBJECT_WORM ) err = INFO_DELETEWORM;
1283 if ( oType == OBJECT_SPIDER ) err = INFO_DELETESPIDER;
1284
1285 if ( oType == OBJECT_MOBILEwa ||
1286 oType == OBJECT_MOBILEta ||
1287 oType == OBJECT_MOBILEfa ||
1288 oType == OBJECT_MOBILEia ||
1289 oType == OBJECT_MOBILEwb ||
1290 oType == OBJECT_MOBILEtb ||
1291 oType == OBJECT_MOBILEfb ||
1292 oType == OBJECT_MOBILEib ||
1293 oType == OBJECT_MOBILEwc ||
1294 oType == OBJECT_MOBILEtc ||
1295 oType == OBJECT_MOBILEfc ||
1296 oType == OBJECT_MOBILEic ||
1297 oType == OBJECT_MOBILEwi ||
1298 oType == OBJECT_MOBILEti ||
1299 oType == OBJECT_MOBILEfi ||
1300 oType == OBJECT_MOBILEii ||
1301 oType == OBJECT_MOBILEws ||
1302 oType == OBJECT_MOBILEts ||
1303 oType == OBJECT_MOBILEfs ||
1304 oType == OBJECT_MOBILEis ||
1305 oType == OBJECT_MOBILErt ||
1306 oType == OBJECT_MOBILErc ||
1307 oType == OBJECT_MOBILErr ||
1308 oType == OBJECT_MOBILErs ||
1309 oType == OBJECT_MOBILEsa ||
1310 oType == OBJECT_MOBILEwt ||
1311 oType == OBJECT_MOBILEtt ||
1312 oType == OBJECT_MOBILEft ||
1313 oType == OBJECT_MOBILEit ||
1314 oType == OBJECT_MOBILErp ||
1315 oType == OBJECT_MOBILEst ||
1316 oType == OBJECT_MOBILEdr )
1317 {
1318 err = ERR_DELETEMOBILE;
1319 }
1320
1321 if ( oType == OBJECT_DERRICK ||
1322 oType == OBJECT_FACTORY ||
1323 oType == OBJECT_STATION ||
1324 oType == OBJECT_CONVERT ||
1325 oType == OBJECT_REPAIR ||
1326 oType == OBJECT_DESTROYER||
1327 oType == OBJECT_TOWER ||
1328 oType == OBJECT_RESEARCH ||
1329 oType == OBJECT_RADAR ||
1330 oType == OBJECT_INFO ||
1331 oType == OBJECT_ENERGY ||
1332 oType == OBJECT_LABO ||
1333 oType == OBJECT_NUCLEAR ||
1334 oType == OBJECT_PARA ||
1335 oType == OBJECT_SAFE ||
1336 oType == OBJECT_HUSTON ||
1337 oType == OBJECT_START ||
1338 oType == OBJECT_END )
1339 {
1340 err = ERR_DELETEBUILDING;
1341 m_main->DisplayError(err, obj->GetPosition(), 5.0f);
1342 return;
1343 }
1344
1345 if ( err != ERR_OK )
1346 {
1347 m_main->DisplayError(err, obj);
1348 }
1349 }
1350 }
1351
CreateLight(Math::Vector pos,float height)1352 void CPyro::CreateLight(Math::Vector pos, float height)
1353 {
1354 if (!m_engine->GetLightMode()) return;
1355
1356 m_lightHeight = height;
1357
1358 Gfx::Light light;
1359 light.type = LIGHT_SPOT;
1360 light.ambient = Gfx::Color(0.0f, 0.0f, 0.0f);
1361 light.position = Math::Vector(pos.x, pos.y+height, pos.z);
1362 light.direction = Math::Vector(0.0f, -1.0f, 0.0f); // against the bottom
1363 light.spotIntensity = 1.0f;
1364 light.attenuation0 = 1.0f;
1365 light.attenuation1 = 0.0f;
1366 light.attenuation2 = 0.0f;
1367 light.spotAngle = Math::PI/4.0f;
1368
1369 m_lightRank = m_lightMan->CreateLight();
1370
1371 m_lightMan->SetLight(m_lightRank, light);
1372 m_lightMan->SetLightIntensity(m_lightRank, 0.0f);
1373
1374 // Only illuminates the objects on the ground.
1375 m_lightMan->SetLightIncludeType(m_lightRank, ENG_OBJTYPE_TERRAIN);
1376 }
1377
DeleteObject(bool primary,bool secondary)1378 void CPyro::DeleteObject(bool primary, bool secondary)
1379 {
1380 if (m_object == nullptr) return;
1381
1382 ObjectType type = m_object->GetType();
1383 if ( secondary &&
1384 type != OBJECT_FACTORY &&
1385 type != OBJECT_NUCLEAR &&
1386 type != OBJECT_ENERGY )
1387 {
1388 if (m_object->Implements(ObjectInterfaceType::Powered))
1389 {
1390 CPoweredObject* poweredObject = dynamic_cast<CPoweredObject*>(m_object);
1391 CObject* sub = poweredObject->GetPower();
1392 if (sub != nullptr)
1393 {
1394 CObjectManager::GetInstancePointer()->DeleteObject(sub);
1395 poweredObject->SetPower(nullptr);
1396 }
1397 }
1398
1399 if (m_object->Implements(ObjectInterfaceType::Carrier))
1400 {
1401 CCarrierObject* carrierObject = dynamic_cast<CCarrierObject*>(m_object);
1402 CObject* sub = carrierObject->GetCargo();
1403 if (sub != nullptr)
1404 {
1405 CObjectManager::GetInstancePointer()->DeleteObject(sub);
1406 carrierObject->SetCargo(nullptr);
1407 }
1408 }
1409 }
1410
1411 if (primary)
1412 {
1413 if (m_object->Implements(ObjectInterfaceType::Transportable))
1414 {
1415 // TODO: this should be handled in the object's destructor
1416 CObject* transporter = dynamic_cast<CTransportableObject&>(*m_object).GetTransporter();
1417 if (transporter != nullptr)
1418 {
1419 if (transporter->Implements(ObjectInterfaceType::Powered))
1420 {
1421 CPoweredObject* powered = dynamic_cast<CPoweredObject*>(transporter);
1422 if (powered->GetPower() == m_object)
1423 powered->SetPower(nullptr);
1424 }
1425
1426 if (transporter->Implements(ObjectInterfaceType::Carrier))
1427 {
1428 CCarrierObject* carrier = dynamic_cast<CCarrierObject*>(transporter);
1429 if (carrier->GetCargo() == m_object)
1430 carrier->SetCargo(nullptr);
1431 }
1432 }
1433 }
1434
1435 CObjectManager::GetInstancePointer()->DeleteObject(m_object);
1436 m_object = nullptr;
1437 }
1438 }
1439
CreateTriangle(CObject * obj,ObjectType oType,int part)1440 void CPyro::CreateTriangle(CObject* obj, ObjectType oType, int part)
1441 {
1442 int objRank = obj->GetObjectRank(part);
1443 if (objRank == -1) return;
1444
1445
1446 int total = m_engine->GetObjectTotalTriangles(objRank);
1447
1448 float percent = 0.10f;
1449 if (total < 50) percent = 0.25f;
1450 if (total < 20) percent = 0.50f;
1451
1452 if ( m_type == PT_FRAGV || m_type == PT_EGG )
1453 {
1454 percent = 0.30f;
1455 }
1456
1457 if (oType == OBJECT_POWER ||
1458 oType == OBJECT_ATOMIC ||
1459 oType == OBJECT_URANIUM ||
1460 oType == OBJECT_TNT ||
1461 oType == OBJECT_BOMB ||
1462 oType == OBJECT_TEEN28)
1463 {
1464 percent = 0.75f;
1465 }
1466 else if (oType == OBJECT_MOBILEtg)
1467 {
1468 percent = 0.50f;
1469 }
1470
1471 std::vector<EngineTriangle> buffer;
1472 total = m_engine->GetPartialTriangles(objRank, percent, 100, buffer);
1473
1474 for (int i = 0; i < total; i++)
1475 {
1476 Math::Vector p1, p2, p3;
1477
1478 p1.x = buffer[i].triangle[0].coord.x;
1479 p1.y = buffer[i].triangle[0].coord.y;
1480 p1.z = buffer[i].triangle[0].coord.z;
1481 p2.x = buffer[i].triangle[1].coord.x;
1482 p2.y = buffer[i].triangle[1].coord.y;
1483 p2.z = buffer[i].triangle[1].coord.z;
1484 p3.x = buffer[i].triangle[2].coord.x;
1485 p3.y = buffer[i].triangle[2].coord.y;
1486 p3.z = buffer[i].triangle[2].coord.z;
1487
1488 float h;
1489
1490 h = Math::Distance(p1, p2);
1491 if ( h > 5.0f )
1492 {
1493 p2.x = p1.x+((p2.x-p1.x)*5.0f/h);
1494 p2.y = p1.y+((p2.y-p1.y)*5.0f/h);
1495 p2.z = p1.z+((p2.z-p1.z)*5.0f/h);
1496 }
1497
1498 h = Math::Distance(p2, p3);
1499 if ( h > 5.0f )
1500 {
1501 p3.x = p2.x+((p3.x-p2.x)*5.0f/h);
1502 p3.y = p2.y+((p3.y-p2.y)*5.0f/h);
1503 p3.z = p2.z+((p3.z-p2.z)*5.0f/h);
1504 }
1505
1506 h = Math::Distance(p3, p1);
1507 if ( h > 5.0f )
1508 {
1509 p1.x = p3.x+((p1.x-p3.x)*5.0f/h);
1510 p1.y = p3.y+((p1.y-p3.y)*5.0f/h);
1511 p1.z = p3.z+((p1.z-p3.z)*5.0f/h);
1512 }
1513
1514 buffer[i].triangle[0].coord.x = p1.x;
1515 buffer[i].triangle[0].coord.y = p1.y;
1516 buffer[i].triangle[0].coord.z = p1.z;
1517 buffer[i].triangle[1].coord.x = p2.x;
1518 buffer[i].triangle[1].coord.y = p2.y;
1519 buffer[i].triangle[1].coord.z = p2.z;
1520 buffer[i].triangle[2].coord.x = p3.x;
1521 buffer[i].triangle[2].coord.y = p3.y;
1522 buffer[i].triangle[2].coord.z = p3.z;
1523
1524 Math::Vector offset;
1525 offset.x = (buffer[i].triangle[0].coord.x+buffer[i].triangle[1].coord.x+buffer[i].triangle[2].coord.x)/3.0f;
1526 offset.y = (buffer[i].triangle[0].coord.y+buffer[i].triangle[1].coord.y+buffer[i].triangle[2].coord.y)/3.0f;
1527 offset.z = (buffer[i].triangle[0].coord.z+buffer[i].triangle[1].coord.z+buffer[i].triangle[2].coord.z)/3.0f;
1528
1529 buffer[i].triangle[0].coord.x -= offset.x;
1530 buffer[i].triangle[1].coord.x -= offset.x;
1531 buffer[i].triangle[2].coord.x -= offset.x;
1532
1533 buffer[i].triangle[0].coord.y -= offset.y;
1534 buffer[i].triangle[1].coord.y -= offset.y;
1535 buffer[i].triangle[2].coord.y -= offset.y;
1536
1537 buffer[i].triangle[0].coord.z -= offset.z;
1538 buffer[i].triangle[1].coord.z -= offset.z;
1539 buffer[i].triangle[2].coord.z -= offset.z;
1540
1541 Math::Vector speed;
1542 float mass;
1543
1544 Math::Matrix* mat = obj->GetWorldMatrix(part);
1545 Math::Vector pos = Math::Transform(*mat, offset);
1546 if ( m_type == PT_FRAGV || m_type == PT_EGG )
1547 {
1548 speed.x = (Math::Rand()-0.5f)*10.0f;
1549 speed.z = (Math::Rand()-0.5f)*10.0f;
1550 speed.y = Math::Rand()*15.0f;
1551 mass = Math::Rand()*20.0f+20.0f;
1552 }
1553 else if ( m_type == PT_SPIDER )
1554 {
1555 speed.x = (Math::Rand()-0.5f)*10.0f;
1556 speed.z = (Math::Rand()-0.5f)*10.0f;
1557 speed.y = Math::Rand()*20.0f;
1558 mass = Math::Rand()*10.0f+15.0f;
1559 }
1560 else
1561 {
1562 speed.x = (Math::Rand()-0.5f)*30.0f;
1563 speed.z = (Math::Rand()-0.5f)*30.0f;
1564 speed.y = Math::Rand()*30.0f;
1565 mass = Math::Rand()*10.0f+15.0f;
1566 }
1567 if ( oType == OBJECT_STONE ) speed *= 0.5f;
1568 if ( oType == OBJECT_URANIUM ) speed *= 0.4f;
1569 float duration = Math::Rand()*3.0f+3.0f;
1570 m_particle->CreateFrag(pos, speed, &buffer[i], PARTIFRAG,
1571 duration, mass, 0.5f);
1572 }
1573 }
1574
ExploStart()1575 void CPyro::ExploStart()
1576 {
1577 m_burnType = m_object->GetType();
1578
1579 Math::Vector oPos = m_object->GetPosition();
1580 m_burnFall = m_terrain->GetHeightToFloor(oPos, true);
1581
1582 m_object->Simplify();
1583 m_object->SetLock(true); // ruin not usable yet
1584 assert(m_object->Implements(ObjectInterfaceType::Destroyable));
1585 dynamic_cast<CDestroyableObject&>(*m_object).SetDying(DeathType::Exploding); // being destroyed
1586 m_object->FlatParent();
1587
1588 if ( m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject&>(*m_object).GetSelect() )
1589 {
1590 dynamic_cast<CControllableObject&>(*m_object).SetSelect(false); // deselects the object
1591 m_camera->SetType(CAM_TYPE_EXPLO);
1592 m_main->DeselectAll();
1593 }
1594 m_main->RemoveFromSelectionHistory(m_object);
1595
1596 for (int i = 0; i < OBJECTMAXPART; i++)
1597 {
1598 int objRank = m_object->GetObjectRank(i);
1599 if (objRank == -1) continue;
1600
1601 // TODO: refactor later to material change
1602 int oldBaseObjRank = m_engine->GetObjectBaseRank(objRank);
1603 if (oldBaseObjRank != -1)
1604 {
1605 int newBaseObjRank = m_engine->CreateBaseObject();
1606 m_engine->CopyBaseObject(oldBaseObjRank, newBaseObjRank);
1607 m_engine->SetObjectBaseRank(objRank, newBaseObjRank);
1608
1609 m_engine->ChangeSecondTexture(objRank, "dirty04.png");
1610 }
1611
1612 // TODO: temporary hack (hopefully)
1613 assert(m_object->Implements(ObjectInterfaceType::Old));
1614 Math::Vector pos = dynamic_cast<COldObject&>(*m_object).GetPartPosition(i);
1615
1616 Math::Vector speed;
1617 float weight;
1618
1619 if (i == 0) // main part?
1620 {
1621 weight = 0.0f;
1622
1623 speed.y = -1.0f;
1624 speed.x = 0.0f;
1625 speed.z = 0.0f;
1626 }
1627 else
1628 {
1629 Math::Vector min, max;
1630 m_engine->GetObjectBBox(objRank, min, max);
1631 weight = Math::Distance(min, max); // weight according to size!
1632
1633 speed.y = 10.0f+Math::Rand()*20.0f;
1634 speed.x = (Math::Rand()-0.5f)*20.0f;
1635 speed.z = (Math::Rand()-0.5f)*20.0f;
1636 }
1637
1638 int channel = m_particle->CreatePart(pos, speed, PARTIPART, 10.0f, 20.0f, weight, 0.5f);
1639 if (channel != -1)
1640 m_object->SetMasterParticle(i, channel);
1641 }
1642 m_engine->LoadTexture("textures/dirty04.png");
1643
1644 DeleteObject(false, true); // destroys the object transported + the battery
1645 }
ExploTerminate()1646 void CPyro::ExploTerminate()
1647 {
1648 DeleteObject(true, false); // removes the main object
1649 }
1650
BurnStart()1651 void CPyro::BurnStart()
1652 {
1653 m_burnType = m_object->GetType();
1654
1655 Math::Vector oPos = m_object->GetPosition();
1656 m_burnFall = m_terrain->GetHeightToFloor(oPos, true);
1657
1658 m_object->Simplify();
1659 m_object->SetLock(true); // ruin not usable yet
1660
1661 if ( m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject&>(*m_object).GetSelect() )
1662 {
1663 dynamic_cast<CControllableObject&>(*m_object).SetSelect(false); // deselects the object
1664 m_camera->SetType(CAM_TYPE_EXPLO);
1665 m_main->DeselectAll();
1666 }
1667 m_main->RemoveFromSelectionHistory(m_object);
1668
1669 for (int i = 0; i < OBJECTMAXPART; i++)
1670 {
1671 int objRank = m_object->GetObjectRank(i);
1672 if (objRank == -1) continue;
1673
1674 // TODO: refactor later to material change
1675 int oldBaseObjRank = m_engine->GetObjectBaseRank(objRank);
1676 if (oldBaseObjRank != -1)
1677 {
1678 int newBaseObjRank = m_engine->CreateBaseObject();
1679 m_engine->CopyBaseObject(oldBaseObjRank, newBaseObjRank);
1680 m_engine->SetObjectBaseRank(objRank, newBaseObjRank);
1681
1682 m_engine->ChangeSecondTexture(objRank, "dirty04.png");
1683 }
1684 }
1685 m_engine->LoadTexture("textures/dirty04.png");
1686
1687 m_burnPartTotal = 0;
1688
1689 Math::Vector pos, angle;
1690
1691 if ( m_burnType == OBJECT_DERRICK ||
1692 m_burnType == OBJECT_FACTORY ||
1693 m_burnType == OBJECT_REPAIR ||
1694 m_burnType == OBJECT_DESTROYER||
1695 m_burnType == OBJECT_CONVERT ||
1696 m_burnType == OBJECT_TOWER ||
1697 m_burnType == OBJECT_RESEARCH ||
1698 m_burnType == OBJECT_ENERGY ||
1699 m_burnType == OBJECT_LABO )
1700 {
1701 pos.x = 0.0f;
1702 pos.y = -(4.0f+Math::Rand()*4.0f);
1703 pos.z = 0.0f;
1704 angle.x = (Math::Rand()-0.5f)*0.4f;
1705 angle.y = 0.0f;
1706 angle.z = (Math::Rand()-0.5f)*0.4f;
1707 }
1708 else if ( m_burnType == OBJECT_STATION ||
1709 m_burnType == OBJECT_RADAR ||
1710 m_burnType == OBJECT_INFO )
1711 {
1712 pos.x = 0.0f;
1713 pos.y = -(1.0f+Math::Rand()*1.0f);
1714 pos.z = 0.0f;
1715 angle.x = (Math::Rand()-0.5f)*0.2f;
1716 angle.y = 0.0f;
1717 angle.z = (Math::Rand()-0.5f)*0.2f;
1718 }
1719 else if ( m_burnType == OBJECT_NUCLEAR )
1720 {
1721 pos.x = 0.0f;
1722 pos.y = -(10.0f+Math::Rand()*10.0f);
1723 pos.z = 0.0f;
1724 angle.x = (Math::Rand()-0.5f)*0.4f;
1725 angle.y = 0.0f;
1726 angle.z = (Math::Rand()-0.5f)*0.4f;
1727 }
1728 else if ( m_burnType == OBJECT_PARA )
1729 {
1730 pos.x = 0.0f;
1731 pos.y = -(10.0f+Math::Rand()*10.0f);
1732 pos.z = 0.0f;
1733 angle.x = (Math::Rand()-0.5f)*0.4f;
1734 angle.y = 0.0f;
1735 angle.z = (Math::Rand()-0.5f)*0.4f;
1736 }
1737 else if ( m_burnType == OBJECT_SAFE )
1738 {
1739 pos.x = 0.0f;
1740 pos.y = -(10.0f+Math::Rand()*10.0f);
1741 pos.z = 0.0f;
1742 angle.x = (Math::Rand()-0.5f)*0.4f;
1743 angle.y = 0.0f;
1744 angle.z = (Math::Rand()-0.5f)*0.4f;
1745 }
1746 else if ( m_burnType == OBJECT_HUSTON )
1747 {
1748 pos.x = 0.0f;
1749 pos.y = -(10.0f+Math::Rand()*10.0f);
1750 pos.z = 0.0f;
1751 angle.x = (Math::Rand()-0.5f)*0.4f;
1752 angle.y = 0.0f;
1753 angle.z = (Math::Rand()-0.5f)*0.4f;
1754 }
1755 else if ( m_burnType == OBJECT_MOBILEwa ||
1756 m_burnType == OBJECT_MOBILEwb ||
1757 m_burnType == OBJECT_MOBILEwc ||
1758 m_burnType == OBJECT_MOBILEwi ||
1759 m_burnType == OBJECT_MOBILEws ||
1760 m_burnType == OBJECT_MOBILEwt )
1761 {
1762 pos.x = 0.0f;
1763 pos.y = -(0.5f+Math::Rand()*1.0f);
1764 pos.z = 0.0f;
1765 angle.x = (Math::Rand()-0.5f)*0.8f;
1766 angle.y = 0.0f;
1767 angle.z = (Math::Rand()-0.5f)*0.4f;
1768 }
1769 else if ( m_burnType == OBJECT_TEEN31 ) // basket?
1770 {
1771 pos.x = 0.0f;
1772 pos.y = 0.0f;
1773 pos.z = 0.0f;
1774 angle.x = (Math::Rand()-0.5f)*0.8f;
1775 angle.y = 0.0f;
1776 angle.z = (Math::Rand()-0.5f)*0.2f;
1777 }
1778 else
1779 {
1780 pos.x = 0.0f;
1781 pos.y = -(2.0f+Math::Rand()*2.0f);
1782 pos.z = 0.0f;
1783 angle.x = (Math::Rand()-0.5f)*0.8f;
1784 angle.y = 0.0f;
1785 angle.z = (Math::Rand()-0.5f)*0.8f;
1786 }
1787 BurnAddPart(0, pos, angle); // movement of the main part
1788
1789 m_burnKeepPart[0] = -1; // nothing to keep
1790
1791 if ( m_burnType == OBJECT_DERRICK )
1792 {
1793 pos.x = 0.0f;
1794 pos.y = -40.0f;
1795 pos.z = 0.0f;
1796 angle.x = 0.0f;
1797 angle.y = 0.0f;
1798 angle.z = 0.0f;
1799 BurnAddPart(1, pos, angle); // down the drill
1800 }
1801
1802 if ( m_burnType == OBJECT_REPAIR )
1803 {
1804 pos.x = 0.0f;
1805 pos.y = -12.0f;
1806 pos.z = 0.0f;
1807 angle.x = (Math::Rand()-0.5f)*0.2f;
1808 angle.y = (Math::Rand()-0.5f)*0.2f;
1809 angle.z = -90.0f*Math::PI/180.0f;
1810 BurnAddPart(1, pos, angle); // down the sensor
1811 }
1812
1813 if ( m_burnType == OBJECT_DESTROYER )
1814 {
1815 pos.x = 0.0f;
1816 pos.y = -12.0f;
1817 pos.z = 0.0f;
1818 angle.x = (Math::Rand()-0.5f)*0.2f;
1819 angle.y = (Math::Rand()-0.5f)*0.2f;
1820 angle.z = -90.0f*Math::PI/180.0f;
1821 BurnAddPart(1, pos, angle); // down the sensor
1822 }
1823
1824 if ( m_burnType == OBJECT_CONVERT )
1825 {
1826 pos.x = 0.0f;
1827 pos.y = -200.0f;
1828 pos.z = 0.0f;
1829 angle.x = (Math::Rand()-0.5f)*0.5f;
1830 angle.y = (Math::Rand()-0.5f)*0.5f;
1831 angle.z = 0.0f;
1832 BurnAddPart(1, pos, angle); // down the cover
1833 BurnAddPart(2, pos, angle);
1834 BurnAddPart(3, pos, angle);
1835 }
1836
1837 if ( m_burnType == OBJECT_TOWER )
1838 {
1839 pos.x = 0.0f;
1840 pos.y = -7.0f;
1841 pos.z = 0.0f;
1842 angle.x = (Math::Rand()-0.5f)*0.4f;
1843 angle.y = (Math::Rand()-0.5f)*0.4f;
1844 angle.z = 0.0f;
1845 BurnAddPart(1, pos, angle); // down the cannon
1846 }
1847
1848 if ( m_burnType == OBJECT_RESEARCH )
1849 {
1850 pos.x = 0.0f;
1851 pos.y = -7.0f;
1852 pos.z = 0.0f;
1853 angle.x = (Math::Rand()-0.5f)*0.2f;
1854 angle.y = (Math::Rand()-0.5f)*0.2f;
1855 angle.z = 0.0f;
1856 BurnAddPart(1, pos, angle); // down the anemometer
1857 }
1858
1859 if ( m_burnType == OBJECT_RADAR )
1860 {
1861 pos.x = 0.0f;
1862 pos.y = -14.0f;
1863 pos.z = 0.0f;
1864 angle.x = (Math::Rand()-0.5f)*0.4f;
1865 angle.y = (Math::Rand()-0.5f)*0.4f;
1866 angle.z = 0.0f;
1867 BurnAddPart(1, pos, angle); // down the radar
1868 BurnAddPart(2, pos, angle);
1869 }
1870
1871 if ( m_burnType == OBJECT_INFO )
1872 {
1873 pos.x = 0.0f;
1874 pos.y = -14.0f;
1875 pos.z = 0.0f;
1876 angle.x = (Math::Rand()-0.5f)*0.4f;
1877 angle.y = (Math::Rand()-0.5f)*0.4f;
1878 angle.z = 0.0f;
1879 BurnAddPart(1, pos, angle); // down the information terminal
1880 BurnAddPart(2, pos, angle);
1881 }
1882
1883 if ( m_burnType == OBJECT_LABO )
1884 {
1885 pos.x = 0.0f;
1886 pos.y = -12.0f;
1887 pos.z = 0.0f;
1888 angle.x = 0.0f;
1889 angle.y = 0.0f;
1890 angle.z = 0.0f;
1891 BurnAddPart(1, pos, angle); // down the arm
1892 }
1893
1894 if ( m_burnType == OBJECT_NUCLEAR )
1895 {
1896 pos.x = 0.0f;
1897 pos.y = 0.0f;
1898 pos.z = 0.0f;
1899 angle.x = 0.0f;
1900 angle.y = 0.0f;
1901 angle.z = -135.0f*Math::PI/180.0f;
1902 BurnAddPart(1, pos, angle); // down the cover
1903 }
1904
1905 if ( m_burnType == OBJECT_MOBILEfa ||
1906 m_burnType == OBJECT_MOBILEta ||
1907 m_burnType == OBJECT_MOBILEwa ||
1908 m_burnType == OBJECT_MOBILEia )
1909 {
1910 pos.x = 2.0f;
1911 pos.y = -5.0f;
1912 pos.z = 0.0f;
1913 angle.x = (Math::Rand()-0.5f)*0.2f;
1914 angle.y = (Math::Rand()-0.5f)*0.2f;
1915 angle.z = 40.0f*Math::PI/180.0f;
1916 BurnAddPart(1, pos, angle); // down the arm
1917 }
1918
1919 if ( m_burnType == OBJECT_MOBILEfs ||
1920 m_burnType == OBJECT_MOBILEts ||
1921 m_burnType == OBJECT_MOBILEws ||
1922 m_burnType == OBJECT_MOBILEis )
1923 {
1924 pos.x = 0.0f;
1925 pos.y = -7.0f;
1926 pos.z = 0.0f;
1927 angle.x = (Math::Rand()-0.5f)*0.2f;
1928 angle.y = (Math::Rand()-0.5f)*0.2f;
1929 angle.z = 50.0f*Math::PI/180.0f;
1930 BurnAddPart(1, pos, angle); // down the sensor
1931 }
1932
1933 if ( m_burnType == OBJECT_MOBILEfc ||
1934 m_burnType == OBJECT_MOBILEtc ||
1935 m_burnType == OBJECT_MOBILEwc ||
1936 m_burnType == OBJECT_MOBILEic )
1937 {
1938 pos.x = -1.5f;
1939 pos.y = -5.0f;
1940 pos.z = 0.0f;
1941 angle.x = (Math::Rand()-0.5f)*0.2f;
1942 angle.y = (Math::Rand()-0.5f)*0.2f;
1943 angle.z = -25.0f*Math::PI/180.0f;
1944 BurnAddPart(1, pos, angle); // down the cannon
1945 }
1946
1947 if ( m_burnType == OBJECT_MOBILEfi ||
1948 m_burnType == OBJECT_MOBILEti ||
1949 m_burnType == OBJECT_MOBILEwi ||
1950 m_burnType == OBJECT_MOBILEii )
1951 {
1952 pos.x = -1.5f;
1953 pos.y = -5.0f;
1954 pos.z = 0.0f;
1955 angle.x = (Math::Rand()-0.5f)*0.2f;
1956 angle.y = (Math::Rand()-0.5f)*0.2f;
1957 angle.z = -25.0f*Math::PI/180.0f;
1958 BurnAddPart(1, pos, angle); // down the insect-cannon
1959 }
1960
1961 if ( m_burnType == OBJECT_MOBILEfb ||
1962 m_burnType == OBJECT_MOBILEtb ||
1963 m_burnType == OBJECT_MOBILEwb ||
1964 m_burnType == OBJECT_MOBILEib )
1965 {
1966 pos.x = -1.5f;
1967 pos.y = -5.0f;
1968 pos.z = 0.0f;
1969 angle.x = (Math::Rand()-0.5f)*0.2f;
1970 angle.y = (Math::Rand()-0.5f)*0.2f;
1971 angle.z = -25.0f*Math::PI/180.0f;
1972 BurnAddPart(1, pos, angle); // down the neutron gun
1973 }
1974
1975 if ( m_burnType == OBJECT_MOBILErt ||
1976 m_burnType == OBJECT_MOBILErc )
1977 {
1978 pos.x = 0.0f;
1979 pos.y = -10.0f;
1980 pos.z = 0.0f;
1981 angle.x = 0.0f;
1982 angle.y = 0.0f;
1983 angle.z = 0.0f;
1984 BurnAddPart(1, pos, angle); // down the holder
1985
1986 pos.x = 0.0f;
1987 pos.y = -10.0f;
1988 pos.z = 0.0f;
1989 angle.x = 0.0f;
1990 angle.y = 0.0f;
1991 angle.z = 0.0f;
1992 BurnAddPart(2, pos, angle); // down the pestle/cannon
1993 }
1994
1995 if ( m_burnType == OBJECT_MOBILErr )
1996 {
1997 pos.x = 0.0f;
1998 pos.y = -10.0f;
1999 pos.z = 0.0f;
2000 angle.x = 0.0f;
2001 angle.y = 0.0f;
2002 angle.z = 0.0f;
2003 BurnAddPart(1, pos, angle); // down the holder
2004
2005 pos.x = 0.0f;
2006 pos.y = 0.0f;
2007 pos.z = 0.0f;
2008 angle.x = 0.0f;
2009 angle.y = 0.0f;
2010 angle.z = -Math::PI/2.0f;
2011 BurnAddPart(4, pos, angle);
2012
2013 pos.x = 0.0f;
2014 pos.y = 0.0f;
2015 pos.z = 0.0f;
2016 angle.x = 0.0f;
2017 angle.y = 0.0f;
2018 angle.z = Math::PI/2.5f;
2019 BurnAddPart(2, pos, angle);
2020 }
2021
2022 if ( m_burnType == OBJECT_MOBILErs )
2023 {
2024 pos.x = 0.0f;
2025 pos.y = -10.0f;
2026 pos.z = 0.0f;
2027 angle.x = 0.0f;
2028 angle.y = 0.0f;
2029 angle.z = 0.0f;
2030 BurnAddPart(1, pos, angle); // down the holder
2031
2032 pos.x = 0.0f;
2033 pos.y = -5.0f;
2034 pos.z = 0.0f;
2035 angle.x = 0.0f;
2036 angle.y = 0.0f;
2037 angle.z = 0.0f;
2038 BurnAddPart(2, pos, angle);
2039
2040 pos.x = 0.0f;
2041 pos.y = -5.0f;
2042 pos.z = 0.0f;
2043 angle.x = 0.0f;
2044 angle.y = 0.0f;
2045 angle.z = 0.0f;
2046 BurnAddPart(3, pos, angle);
2047 }
2048
2049 if ( m_burnType == OBJECT_MOBILEsa )
2050 {
2051 pos.x = 0.0f;
2052 pos.y = -10.0f;
2053 pos.z = 0.0f;
2054 angle.x = 0.0f;
2055 angle.y = 0.0f;
2056 angle.z = 0.0f;
2057 BurnAddPart(1, pos, angle); // down the holder
2058 }
2059
2060 if ( m_burnType == OBJECT_MOBILEwa ||
2061 m_burnType == OBJECT_MOBILEwb ||
2062 m_burnType == OBJECT_MOBILEwc ||
2063 m_burnType == OBJECT_MOBILEwi ||
2064 m_burnType == OBJECT_MOBILEws ||
2065 m_burnType == OBJECT_MOBILEwt ) // wheels?
2066 {
2067 int i = 0;
2068 for (; i < 4; i++)
2069 {
2070 pos.x = 0.0f;
2071 pos.y = Math::Rand()*0.5f;
2072 pos.z = 0.0f;
2073 angle.x = (Math::Rand()-0.5f)*Math::PI/2.0f;
2074 angle.y = (Math::Rand()-0.5f)*Math::PI/2.0f;
2075 angle.z = 0.0f;
2076 BurnAddPart(6+i, pos, angle); // wheel
2077
2078 m_burnKeepPart[i] = 6+i; // we keep the wheels
2079 }
2080 m_burnKeepPart[i] = -1;
2081 }
2082
2083 if ( m_burnType == OBJECT_MOBILEta ||
2084 m_burnType == OBJECT_MOBILEtb ||
2085 m_burnType == OBJECT_MOBILEtc ||
2086 m_burnType == OBJECT_MOBILEti ||
2087 m_burnType == OBJECT_MOBILEts ||
2088 m_burnType == OBJECT_MOBILEtt ||
2089 m_burnType == OBJECT_MOBILErt ||
2090 m_burnType == OBJECT_MOBILErc ||
2091 m_burnType == OBJECT_MOBILErr ||
2092 m_burnType == OBJECT_MOBILErs ||
2093 m_burnType == OBJECT_MOBILErp ||
2094 m_burnType == OBJECT_MOBILEsa ||
2095 m_burnType == OBJECT_MOBILEst ||
2096 m_burnType == OBJECT_MOBILEdr ) // caterpillars?
2097 {
2098 pos.x = 0.0f;
2099 pos.y = -4.0f;
2100 pos.z = 2.0f;
2101 angle.x = (Math::Rand()-0.5f)*20.0f*Math::PI/180.0f;
2102 angle.y = (Math::Rand()-0.5f)*10.0f*Math::PI/180.0f;
2103 angle.z = (Math::Rand()-0.5f)*30.0f*Math::PI/180.0f;
2104 BurnAddPart(6, pos, angle); // down the right caterpillar
2105
2106 pos.x = 0.0f;
2107 pos.y = -4.0f;
2108 pos.z = -2.0f;
2109 angle.x = (Math::Rand()-0.5f)*20.0f*Math::PI/180.0f;
2110 angle.y = (Math::Rand()-0.5f)*10.0f*Math::PI/180.0f;
2111 angle.z = (Math::Rand()-0.5f)*30.0f*Math::PI/180.0f;
2112 BurnAddPart(7, pos, angle); // down the left caterpillar
2113 }
2114
2115 if ( m_burnType == OBJECT_MOBILEfa ||
2116 m_burnType == OBJECT_MOBILEfb ||
2117 m_burnType == OBJECT_MOBILEfc ||
2118 m_burnType == OBJECT_MOBILEfi ||
2119 m_burnType == OBJECT_MOBILEfs ||
2120 m_burnType == OBJECT_MOBILEft ) // flying?
2121 {
2122 int i = 0;
2123 for (; i<3; i++)
2124 {
2125 pos.x = 0.0f;
2126 pos.y = -3.0f;
2127 pos.z = 0.0f;
2128 angle.x = 0.0f;
2129 angle.y = 0.0f;
2130 angle.z = (Math::Rand()-0.5f)*Math::PI/2.0f;
2131 BurnAddPart(6+i, pos, angle); // foot
2132 }
2133 m_burnKeepPart[i] = -1;
2134 }
2135
2136 if ( m_burnType == OBJECT_MOBILEia ||
2137 m_burnType == OBJECT_MOBILEib ||
2138 m_burnType == OBJECT_MOBILEic ||
2139 m_burnType == OBJECT_MOBILEii ||
2140 m_burnType == OBJECT_MOBILEis ||
2141 m_burnType == OBJECT_MOBILEit ) // legs?
2142 {
2143 for (int i = 0; i < 6; i++)
2144 {
2145 pos.x = 0.0f;
2146 pos.y = -3.0f;
2147 pos.z = 0.0f;
2148 angle.x = 0.0f;
2149 angle.y = (Math::Rand()-0.5f)*Math::PI/4.0f;
2150 angle.z = (Math::Rand()-0.5f)*Math::PI/4.0f;
2151 BurnAddPart(6+i, pos, angle); // leg
2152 }
2153 }
2154 }
2155
BurnAddPart(int part,Math::Vector pos,Math::Vector angle)2156 void CPyro::BurnAddPart(int part, Math::Vector pos, Math::Vector angle)
2157 {
2158 // TODO: temporary hack (hopefully)
2159 assert(m_object->Implements(ObjectInterfaceType::Old));
2160 COldObject* oldObj = dynamic_cast<COldObject*>(m_object);
2161
2162 int i = m_burnPartTotal;
2163 m_burnPart[i].part = part;
2164 m_burnPart[i].initialPos = oldObj->GetPartPosition(part);
2165 m_burnPart[i].finalPos = m_burnPart[i].initialPos+pos;
2166 m_burnPart[i].initialAngle = oldObj->GetPartRotation(part);
2167 m_burnPart[i].finalAngle = m_burnPart[i].initialAngle+angle;
2168
2169 m_burnPartTotal++;
2170 }
2171
BurnProgress()2172 void CPyro::BurnProgress()
2173 {
2174 if ( m_burnType == OBJECT_TEEN31 ) // basket?
2175 {
2176 m_object->SetScaleY(1.0f-m_progress*0.5f); // slight flattening
2177 }
2178
2179 for (int i = 0; i < m_burnPartTotal; i++)
2180 {
2181 Math::Vector pos = m_burnPart[i].initialPos + m_progress*(m_burnPart[i].finalPos-m_burnPart[i].initialPos);
2182 if ( i == 0 && m_burnFall > 0.0f )
2183 {
2184 float h = powf(m_progress, 2.0f)*1000.0f;
2185 if ( h > m_burnFall ) h = m_burnFall;
2186 pos.y -= h;
2187 }
2188
2189 // TODO: temporary hack (hopefully)
2190 assert(m_object->Implements(ObjectInterfaceType::Old));
2191 COldObject* oldObj = dynamic_cast<COldObject*>(m_object);
2192
2193 oldObj->SetPartPosition(m_burnPart[i].part, pos);
2194
2195 pos = m_burnPart[i].initialAngle + m_progress*(m_burnPart[i].finalAngle-m_burnPart[i].initialAngle);
2196 oldObj->SetPartRotation(m_burnPart[i].part, pos);
2197 }
2198
2199 if (m_object->Implements(ObjectInterfaceType::Powered))
2200 {
2201 CObject* sub = dynamic_cast<CPoweredObject&>(*m_object).GetPower();
2202 if (sub != nullptr) // is there a battery?
2203 sub->SetScaleY(1.0f - m_progress); // complete flattening
2204 }
2205 }
2206
BurnIsKeepPart(int part)2207 bool CPyro::BurnIsKeepPart(int part)
2208 {
2209 int i = 0;
2210 while (m_burnKeepPart[i] != -1)
2211 {
2212 if (part == m_burnKeepPart[i++]) return true; // must keep
2213 }
2214 return false; // must destroy
2215 }
2216
BurnTerminate()2217 void CPyro::BurnTerminate()
2218 {
2219 if (m_object == nullptr)
2220 return;
2221
2222 if (m_type == PT_BURNO) // organic object is burning?
2223 {
2224 DeleteObject(true, true); // removes the insect
2225 return;
2226 }
2227
2228 for (int i = 1; i < OBJECTMAXPART; i++)
2229 {
2230 int objRank = m_object->GetObjectRank(i);
2231 if (objRank == -1) continue;
2232 if (BurnIsKeepPart(i)) continue;
2233
2234 m_object->DeletePart(i);
2235 }
2236
2237 DeleteObject(false, true); // destroys the object transported + the battery
2238
2239 if ( m_burnType == OBJECT_DERRICK ||
2240 m_burnType == OBJECT_STATION ||
2241 m_burnType == OBJECT_FACTORY ||
2242 m_burnType == OBJECT_REPAIR ||
2243 m_burnType == OBJECT_DESTROYER||
2244 m_burnType == OBJECT_CONVERT ||
2245 m_burnType == OBJECT_TOWER ||
2246 m_burnType == OBJECT_RESEARCH ||
2247 m_burnType == OBJECT_RADAR ||
2248 m_burnType == OBJECT_INFO ||
2249 m_burnType == OBJECT_ENERGY ||
2250 m_burnType == OBJECT_LABO ||
2251 m_burnType == OBJECT_NUCLEAR ||
2252 m_burnType == OBJECT_PARA ||
2253 m_burnType == OBJECT_SAFE ||
2254 m_burnType == OBJECT_HUSTON ||
2255 m_burnType == OBJECT_START ||
2256 m_burnType == OBJECT_END )
2257 {
2258 m_object->SetType(OBJECT_RUINfactory); // Ruin
2259 }
2260 else
2261 {
2262 m_object->SetType(OBJECT_RUINmobilew1); // Wreck (recoverable by Recycler)
2263 }
2264 dynamic_cast<CDestroyableObject*>(m_object)->SetDying(DeathType::Alive);
2265 m_object->SetLock(false);
2266 }
2267
FallStart()2268 void CPyro::FallStart()
2269 {
2270 m_object->SetLock(true); // usable
2271
2272 Math::Vector pos = m_object->GetPosition();
2273 m_fallFloor = m_terrain->GetFloorLevel(pos);
2274 m_fallSpeed = 0.0f;
2275 m_fallBulletTime = 0.0f;
2276 m_fallEnding = false;
2277 }
2278
FallSearchBeeExplo()2279 CObject* CPyro::FallSearchBeeExplo()
2280 {
2281 auto bulletCrashSphere = m_object->GetFirstCrashSphere();
2282
2283 for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
2284 {
2285 if (obj == m_object) continue;
2286 if (obj->GetType() == OBJECT_BEE) continue;
2287 if ( !obj->Implements(ObjectInterfaceType::Destroyable) ) continue;
2288
2289 if (IsObjectBeingTransported(obj)) continue;
2290
2291 Math::Vector oPos = obj->GetPosition();
2292
2293 if (obj->GetType() == OBJECT_MOBILErs)
2294 {
2295 float shieldRadius = dynamic_cast<CShielder&>(*obj).GetActiveShieldRadius();
2296 if ( shieldRadius > 0.0f )
2297 {
2298 float distance = Math::Distance(oPos, bulletCrashSphere.sphere.pos);
2299 if (distance <= shieldRadius)
2300 return obj;
2301 }
2302 }
2303
2304 if ( obj->GetType() == OBJECT_BASE )
2305 {
2306 float distance = Math::Distance(oPos, bulletCrashSphere.sphere.pos);
2307 if (distance < 25.0f)
2308 return obj;
2309 }
2310
2311 // Test the center of the object, which is necessary for objects
2312 // that have no sphere in the center (station).
2313 float distance = Math::Distance(oPos, bulletCrashSphere.sphere.pos)-4.0f;
2314 if (distance < 5.0f)
2315 return obj;
2316
2317 // Test with all spheres of the object.
2318 for (const auto& objCrashSphere : obj->GetAllCrashSpheres())
2319 {
2320 if (Math::DistanceBetweenSpheres(objCrashSphere.sphere, bulletCrashSphere.sphere) <= 0.0f)
2321 {
2322 return obj;
2323 }
2324 }
2325 }
2326
2327 return nullptr;
2328 }
2329
FallProgress(float rTime)2330 void CPyro::FallProgress(float rTime)
2331 {
2332 if (m_object == nullptr) return;
2333
2334 m_fallSpeed += rTime*50.0f; // v2 = v1 + a*dt
2335 Math::Vector pos;
2336 pos = m_object->GetPosition();
2337 pos.y -= m_fallSpeed*rTime; // dd -= v2*dt
2338
2339 bool floor = false;
2340
2341 if (pos.y <= m_fallFloor) // below the ground level?
2342 {
2343 pos.y = m_fallFloor;
2344 floor = true;
2345 }
2346 m_object->SetPosition(pos);
2347
2348 if (m_object->GetType() == OBJECT_BULLET)
2349 {
2350 m_fallBulletTime += rTime;
2351
2352 if (m_fallBulletTime > 0.2f || floor)
2353 {
2354 m_fallBulletTime = 0.0f;
2355
2356 CObject* obj = FallSearchBeeExplo();
2357 if (obj == nullptr)
2358 {
2359 if (floor) // reaches the ground?
2360 {
2361 assert(m_object->Implements(ObjectInterfaceType::Destroyable));
2362 // TODO: implement "killer"?
2363 dynamic_cast<CDestroyableObject&>(*m_object).DestroyObject(DestructionType::Explosion);
2364 }
2365 }
2366 else
2367 {
2368 if (obj->GetType() == OBJECT_MOBILErs && dynamic_cast<CShielder&>(*obj).GetActiveShieldRadius() > 0.0f) // protected by shield?
2369 {
2370 m_particle->CreateParticle(pos, Math::Vector(0.0f, 0.0f, 0.0f),
2371 Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f, 0.0f, 0.0f);
2372 m_sound->Play(SOUND_GUNDEL);
2373
2374 DeleteObject(true, true); // removes the ball
2375 }
2376 else
2377 {
2378 assert(obj->Implements(ObjectInterfaceType::Damageable));
2379 if (dynamic_cast<CDamageableObject&>(*obj).DamageObject(DamageType::FallingObject))
2380 {
2381 DeleteObject(true, true); // removes the ball
2382 }
2383 else
2384 {
2385 assert(m_object->Implements(ObjectInterfaceType::Destroyable));
2386 // TODO: implement "killer"?
2387 dynamic_cast<CDestroyableObject&>(*m_object).DestroyObject(DestructionType::Explosion);
2388 }
2389 }
2390 }
2391
2392 if (floor || obj != nullptr)
2393 {
2394 m_fallEnding = true;
2395 }
2396 }
2397 }
2398 }
2399
FallIsEnded()2400 Error CPyro::FallIsEnded()
2401 {
2402 if (m_fallEnding || m_object == nullptr) return ERR_STOP;
2403
2404 Math::Vector pos = m_object->GetPosition();
2405 if (pos.y > m_fallFloor) return ERR_CONTINUE;
2406
2407 m_sound->Play(SOUND_BOUM, pos);
2408 m_object->SetLock(false); // usable again
2409
2410 return ERR_STOP;
2411 }
2412
LightOperFlush()2413 void CPyro::LightOperFlush()
2414 {
2415 m_lightOper.clear();
2416 }
2417
LightOperAdd(float progress,float intensity,float r,float g,float b)2418 void CPyro::LightOperAdd(float progress, float intensity, float r, float g, float b)
2419 {
2420 PyroLightOper lightOper;
2421
2422 lightOper.progress = progress;
2423 lightOper.intensity = intensity;
2424 lightOper.color.r = r;
2425 lightOper.color.g = g;
2426 lightOper.color.b = b;
2427
2428 m_lightOper.push_back(lightOper);
2429 }
2430
LightOperFrame(float rTime)2431 void CPyro::LightOperFrame(float rTime)
2432 {
2433 for (std::size_t i = 1; i < m_lightOper.size(); i++)
2434 {
2435 if ( m_progress < m_lightOper[i].progress )
2436 {
2437 float progress = (m_progress-m_lightOper[i-1].progress) / (m_lightOper[i].progress-m_lightOper[i-1].progress);
2438
2439 float intensity = m_lightOper[i-1].intensity + (m_lightOper[i].intensity-m_lightOper[i-1].intensity)*progress;
2440 Gfx::Color color;
2441 color.r = m_lightOper[i-1].color.r + (m_lightOper[i].color.r-m_lightOper[i-1].color.r)*progress;
2442 color.g = m_lightOper[i-1].color.g + (m_lightOper[i].color.g-m_lightOper[i-1].color.g)*progress;
2443 color.b = m_lightOper[i-1].color.b + (m_lightOper[i].color.b-m_lightOper[i-1].color.b)*progress;
2444
2445 m_lightMan->SetLightIntensity(m_lightRank, intensity);
2446 m_lightMan->SetLightColor(m_lightRank, color);
2447 break;
2448 }
2449 }
2450 }
2451
2452
2453 } // namespace Gfx
2454