colobot/src/graphics/engine/pyro.cpp

2415 lines
73 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsiteс.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/engine/pyro.h"
#include "app/app.h"
#include "common/logger.h"
#include "graphics/engine/lightman.h"
#include "graphics/engine/particle.h"
#include "graphics/engine/terrain.h"
#include "math/geometry.h"
#include "object/old_object.h"
#include "object/object_manager.h"
#include "object/robotmain.h"
#include "object/motion/motionhuman.h"
// Graphics module namespace
namespace Gfx {
CPyro::CPyro()
{
m_engine = CEngine::GetInstancePointer();
m_main = CRobotMain::GetInstancePointer();
m_terrain = m_main->GetTerrain();
m_camera = m_main->GetCamera();
m_particle = m_engine->GetParticle();
m_lightMan = m_engine->GetLightManager();
m_sound = CApplication::GetInstancePointer()->GetSound();
m_object = nullptr;
m_progress = 0.0f;
m_speed = 0.0f;
m_lightRank = -1;
m_soundChannel = -1;
LightOperFlush();
m_resetAngle = 0.0f;
}
CPyro::~CPyro()
{
}
void CPyro::DeleteObject()
{
if ( m_lightRank != -1 )
{
m_lightMan->DeleteLight(m_lightRank);
m_lightRank = -1;
}
}
bool CPyro::Create(PyroType type, CObject* obj, float force)
{
m_object = obj;
m_force = force;
ObjectType oType = obj->GetType();
int objRank = obj->GetObjectRank(0);
if (objRank == -1) return false;
Math::Vector min, max;
m_engine->GetObjectBBox(objRank, min, max);
Math::Vector pos = obj->GetPosition();
DisplayError(type, obj); // displays eventual messages
for (const auto& crashSphere : obj->GetAllCrashSpheres())
{
m_crashSpheres.push_back(crashSphere.sphere);
}
// Calculates the size of the effect.
if ( oType == OBJECT_ANT ||
oType == OBJECT_BEE ||
oType == OBJECT_WORM ||
oType == OBJECT_SPIDER )
{
m_size = 40.0f;
}
else
{
m_size = Math::Distance(min, max)*2.0f;
if ( m_size < 4.0f ) m_size = 4.0f;
if ( m_size > 80.0f ) m_size = 80.0f;
}
if ( oType == OBJECT_TNT ||
oType == OBJECT_BOMB )
{
m_size *= 2.0f;
}
m_pos = pos+(min+max)/2.0f;
m_type = type;
m_progress = 0.0f;
m_speed = 1.0f/20.0f; m_time = 0.0f;
m_lastParticle = 0.0f;
m_lastParticleSmoke = 0.0f;
m_lightRank = -1;
// Seeking the position of the battery.
CObject* power = nullptr;
if (obj->Implements(ObjectInterfaceType::Powered))
power = dynamic_cast<CPoweredObject*>(obj)->GetPower();
if (power == nullptr)
{
m_power = false;
}
else
{
m_power = true;
pos = power->GetPosition();
pos.y += 1.0f;
Math::Matrix* mat = obj->GetWorldMatrix(0);
m_posPower = Math::Transform(*mat, pos);
}
if ( oType == OBJECT_POWER ||
oType == OBJECT_ATOMIC ||
oType == OBJECT_URANIUM ||
oType == OBJECT_TNT ||
oType == OBJECT_BOMB )
{
m_power = true;
m_posPower = m_pos;
m_posPower.y += 1.0f;
m_pos = m_posPower;
}
if ( oType == OBJECT_STATION )
{
m_power = true;
Math::Matrix* mat = obj->GetWorldMatrix(0);
m_posPower = Math::Transform(*mat, Math::Vector(-15.0f, 7.0f, 0.0f));
m_pos = m_posPower;
}
if ( oType == OBJECT_ENERGY )
{
m_power = true;
Math::Matrix* mat = obj->GetWorldMatrix(0);
m_posPower = Math::Transform(*mat, Math::Vector(-7.0f, 6.0f, 0.0f));
m_pos = m_posPower;
}
if ( oType == OBJECT_NUCLEAR )
{
m_power = true;
m_posPower = m_pos;
}
if ( oType == OBJECT_PARA )
{
m_power = true;
m_posPower = m_pos;
}
if ( oType == OBJECT_SCRAP4 ||
oType == OBJECT_SCRAP5 ) // plastic material?
{
m_power = true;
m_posPower = m_pos;
}
// Plays the sound of a pyrotechnic effect.
if ( type == PT_FRAGT ||
type == PT_FRAGW ||
type == PT_EXPLOT ||
type == PT_EXPLOW )
{
SoundType sound;
if ( m_power )
{
sound = SOUND_EXPLOp;
}
else
{
sound = SOUND_EXPLO;
}
if ( oType == OBJECT_STONE ||
oType == OBJECT_METAL ||
oType == OBJECT_BULLET ||
oType == OBJECT_BBOX ||
oType == OBJECT_KEYa ||
oType == OBJECT_KEYb ||
oType == OBJECT_KEYc ||
oType == OBJECT_KEYd )
{
sound = SOUND_EXPLOl;
}
if ( oType == OBJECT_URANIUM ||
oType == OBJECT_POWER ||
oType == OBJECT_ATOMIC ||
oType == OBJECT_TNT ||
oType == OBJECT_BOMB )
{
sound = SOUND_EXPLOlp;
}
m_sound->Play(sound, m_pos);
}
if ( type == PT_FRAGO ||
type == PT_EXPLOO ||
type == PT_SPIDER ||
type == PT_SHOTM )
{
m_sound->Play(SOUND_EXPLOi, m_pos);
}
if ( type == PT_BURNT ||
type == PT_BURNO )
{
m_soundChannel = m_sound->Play(SOUND_BURN, m_pos, 1.0f, 1.0f, true);
m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 12.0f, SOPER_CONTINUE);
m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 5.0f, SOPER_STOP);
}
if ( type == PT_BURNO )
{
m_sound->Play(SOUND_DEADi, m_pos);
m_sound->Play(SOUND_DEADi, m_engine->GetEyePt());
}
if ( type == PT_EGG )
{
m_sound->Play(SOUND_EGG, m_pos);
}
if ( type == PT_WPCHECK ||
type == PT_FLCREATE ||
type == PT_FLDELETE )
{
m_sound->Play(SOUND_WAYPOINT, m_pos);
}
if ( oType == OBJECT_HUMAN )
{
if ( type == PT_DEADG )
{
m_sound->Play(SOUND_DEADg, m_pos);
}
if ( type == PT_DEADW )
{
m_sound->Play(SOUND_DEADw, m_pos);
}
if ( type == PT_SHOTH && m_object->GetSelect() )
{
m_sound->Play(SOUND_AIE, m_pos);
m_sound->Play(SOUND_AIE, m_engine->GetEyePt());
}
}
if ( m_type == PT_FRAGT ||
m_type == PT_FRAGO ||
m_type == PT_FRAGW )
{
m_engine->DeleteShadow(m_object->GetObjectRank(0));
}
if ( m_type == PT_DEADG )
{
m_object->SetDead(true);
CMotion* motion = m_object->GetMotion();
if (motion != nullptr)
motion->SetAction(MHS_DEADg, 1.0f);
m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 1.5f);
m_camera->StartOver(CAM_OVER_EFFECT_FADEOUT_WHITE, m_pos, 1.0f);
m_speed = 1.0f/10.0f;
return true;
}
if ( m_type == PT_DEADW )
{
m_object->SetDead(true);
CMotion* motion = m_object->GetMotion();
if ( motion != nullptr )
{
motion->SetAction(MHS_DEADw, 4.0f);
}
m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 3.0f);
m_camera->StartOver(CAM_OVER_EFFECT_FADEOUT_BLACK, m_pos, 1.0f);
m_speed = 1.0f/10.0f;
return true;
}
if ( m_type == PT_SHOTT ||
m_type == PT_SHOTM )
{
m_camera->StartEffect(CAM_EFFECT_SHOT, m_pos, force);
m_speed = 1.0f/1.0f;
return true;
}
if ( m_type == PT_SHOTH )
{
if ( m_camera->GetBlood() && m_object->GetSelect() )
{
m_camera->StartOver(CAM_OVER_EFFECT_BLOOD, m_pos, force);
}
m_speed = 1.0f/0.2f;
return true;
}
if ( m_type == PT_SHOTW )
{
m_speed = 1.0f/1.0f;
}
if ( m_type == PT_BURNT )
{
BurnStart();
}
if ( m_type == PT_WPCHECK )
{
m_speed = 1.0f/8.0f;
m_object->SetEnable(false); // object more functional
}
if ( m_type == PT_FLCREATE )
{
m_speed = 1.0f/2.0f;
}
if ( m_type == PT_FLDELETE )
{
m_speed = 1.0f/2.0f;
m_object->SetEnable(false); // object more functional
}
if ( m_type == PT_RESET )
{
m_speed = 1.0f/2.0f;
m_resetAngle = m_object->GetAngleY(0);
}
if ( m_type == PT_FINDING )
{
float limit = (m_size-1.0f)/4.0f;
if (limit > 8.0f) limit = 8.0f;
if (oType == OBJECT_APOLLO2) limit = 2.0f;
m_speed = 1.0f/limit;
}
if ( m_type == PT_EXPLOT ||
m_type == PT_EXPLOO ||
m_type == PT_EXPLOW )
{
CreateTriangle(obj, oType, 0);
m_engine->DeleteShadow(m_object->GetObjectRank(0));
ExploStart();
}
if ( m_type == PT_FALL )
{
FallStart();
return true;
}
if ( m_type == PT_BURNT ||
m_type == PT_BURNO )
{
m_speed = 1.0f/15.0f;
LightOperAdd(0.00f, 0.0f, 2.0f, 1.0f, 0.0f); // red-orange
LightOperAdd(0.30f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray
LightOperAdd(0.80f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray
LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray
CreateLight(m_pos, 40.0f);
return true;
}
if ( m_type == PT_SPIDER )
{
m_speed = 1.0f/15.0f;
pos = Math::Vector(-3.0f, 2.0f, 0.0f);
Math::Matrix* mat = obj->GetWorldMatrix(0);
m_pos = Math::Transform(*mat, pos);
m_engine->DeleteShadow(m_object->GetObjectRank(0));
}
if ( m_type != PT_EGG &&
m_type != PT_WIN &&
m_type != PT_LOST )
{
float h = 40.0f;
if ( m_type == PT_FRAGO ||
m_type == PT_EXPLOO )
{
LightOperAdd(0.00f, 0.0f, -1.0f, -0.5f, -1.0f); // dark green
LightOperAdd(0.05f, 1.0f, -1.0f, -0.5f, -1.0f); // dark green
LightOperAdd(1.00f, 0.0f, -1.0f, -0.5f, -1.0f); // dark green
}
else if ( m_type == PT_FRAGT ||
m_type == PT_EXPLOT )
{
LightOperAdd(0.00f, 1.0f, 4.0f, 4.0f, 2.0f); // yellow
LightOperAdd(0.02f, 1.0f, 4.0f, 2.0f, 0.0f); // red-orange
LightOperAdd(0.16f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray
LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray
h = m_size*2.0f;
}
else if ( m_type == PT_SPIDER )
{
LightOperAdd(0.00f, 0.0f, -0.5f, -1.0f, -1.0f); // dark red
LightOperAdd(0.05f, 1.0f, -0.5f, -1.0f, -1.0f); // dark red
LightOperAdd(1.00f, 0.0f, -0.5f, -1.0f, -1.0f); // dark red
}
else if ( m_type == PT_FRAGW ||
m_type == PT_EXPLOW ||
m_type == PT_SHOTW )
{
LightOperAdd(0.00f, 0.0f, -0.5f, -0.5f, -1.0f); // dark yellow
LightOperAdd(0.05f, 1.0f, -0.5f, -0.5f, -1.0f); // dark yellow
LightOperAdd(1.00f, 0.0f, -0.5f, -0.5f, -1.0f); // dark yellow
}
else if ( m_type == PT_WPCHECK ||
m_type == PT_FLCREATE ||
m_type == PT_FLDELETE ||
m_type == PT_RESET ||
m_type == PT_FINDING )
{
LightOperAdd(0.00f, 1.0f, 4.0f, 4.0f, 2.0f); // yellow
LightOperAdd(1.00f, 0.0f, 4.0f, 4.0f, 2.0f); // yellow
}
else
{
LightOperAdd(0.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray
LightOperAdd(0.05f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray
LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray
}
CreateLight(m_pos, h);
if ( m_type != PT_SHOTW &&
m_type != PT_WPCHECK &&
m_type != PT_FLCREATE &&
m_type != PT_FLDELETE &&
m_type != PT_RESET &&
m_type != PT_FINDING )
{
m_camera->StartEffect(CAM_EFFECT_EXPLO, m_pos, force);
}
}
if ( m_type == PT_SHOTW ) return true;
// Generates the triangles of the explosion.
if ( m_type == PT_FRAGT ||
m_type == PT_FRAGO ||
m_type == PT_FRAGW ||
m_type == PT_SPIDER ||
m_type == PT_EGG ||
(m_type == PT_EXPLOT && oType == OBJECT_MOBILEtg) )
{
for (int part = 0; part < OBJECTMAXPART; part++)
{
CreateTriangle(obj, oType, part);
}
}
if ( m_type == PT_FRAGT ||
m_type == PT_EXPLOT )
{
if ( m_power )
{
int total = static_cast<int>(10.0f*m_engine->GetParticleDensity());
if ( oType == OBJECT_TNT ||
oType == OBJECT_BOMB ) total *= 3;
for (int i = 0; i < total; i++)
{
pos = m_posPower;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*30.0f;
speed.z = (Math::Rand()-0.5f)*30.0f;
speed.y = Math::Rand()*30.0f;
Math::Point dim;
dim.x = 1.0f;
dim.y = dim.x;
float duration = Math::Rand()*3.0f+2.0f;
float mass = Math::Rand()*10.0f+15.0f;
m_particle->CreateTrack(pos, speed, dim, PARTITRACK1,
duration, mass, Math::Rand()+0.7f, 1.0f);
}
}
if (m_size > 10.0f) // large enough (freight excluded)?
{
if (m_power)
{
pos = m_posPower;
}
else
{
pos = m_pos;
m_terrain->AdjustToFloor(pos);
pos.y += 1.0f;
}
Math::Point dim;
dim.x = m_size*0.4f;
dim.y = dim.x;
m_particle->CreateParticle(pos, Math::Vector(0.0f,0.0f,0.0f), dim, PARTISPHERE0, 2.0f, 0.0f, 0.0f);
}
}
if ( m_type == PT_FRAGO ||
m_type == PT_EXPLOO )
{
int total = static_cast<int>(10.0f*m_engine->GetParticleDensity());
for (int i = 0; i < total; i++)
{
pos = m_pos;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*30.0f;
speed.z = (Math::Rand()-0.5f)*30.0f;
speed.y = Math::Rand()*50.0f;
Math::Point dim;
dim.x = 1.0f;
dim.y = dim.x;
float duration = Math::Rand()*1.0f+0.8f;
float mass = Math::Rand()*10.0f+15.0f;
m_particle->CreateParticle(pos, speed, dim, PARTIORGANIC1,
duration, mass);
}
total = static_cast<int>(5.0f*m_engine->GetParticleDensity());
for (int i = 0; i < total; i++)
{
pos = m_pos;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*30.0f;
speed.z = (Math::Rand()-0.5f)*30.0f;
speed.y = Math::Rand()*50.0f;
Math::Point dim;
dim.x = 1.0f;
dim.y = dim.x;
float duration = Math::Rand()*2.0f+1.4f;
float mass = Math::Rand()*10.0f+15.0f;
m_particle->CreateTrack(pos, speed, dim, PARTITRACK4,
duration, mass, duration*0.5f, dim.x*2.0f);
}
}
if ( m_type == PT_SPIDER )
{
for (int i = 0; i < 50; i++)
{
pos = m_pos;
pos.x += (Math::Rand()-0.5f)*3.0f;
pos.z += (Math::Rand()-0.5f)*3.0f;
pos.y += (Math::Rand()-0.5f)*2.0f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*24.0f;
speed.z = (Math::Rand()-0.5f)*24.0f;
speed.y = 10.0f+Math::Rand()*10.0f;
Math::Point dim;
dim.x = 1.0f;
dim.y = dim.x;
int channel = m_particle->CreateParticle(pos, speed, dim, PARTIGUN3, 2.0f+Math::Rand()*2.0f, 10.0f);
m_particle->SetObjectFather(channel, obj);
}
int total = static_cast<int>(10.0f*m_engine->GetParticleDensity());
for (int i = 0; i < total; i++)
{
pos = m_pos;
pos.x += (Math::Rand()-0.5f)*3.0f;
pos.z += (Math::Rand()-0.5f)*3.0f;
pos.y += (Math::Rand()-0.5f)*2.0f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*24.0f;
speed.z = (Math::Rand()-0.5f)*24.0f;
speed.y = 7.0f+Math::Rand()*7.0f;
Math::Point dim;
dim.x = 1.0f;
dim.y = dim.x;
m_particle->CreateTrack(pos, speed, dim, PARTITRACK3,
2.0f+Math::Rand()*2.0f, 10.0f, 2.0f, 0.6f);
}
}
if ( type == PT_FRAGT ||
type == PT_FRAGW ||
type == PT_EXPLOT ||
type == PT_EXPLOW )
{
if (m_size > 10.0f || m_power)
{
pos = m_pos;
Math::Vector speed(0.0f, 0.0f, 0.0f);
Math::Point dim;
dim.x = m_size;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTICHOC, 2.0f);
}
}
return true;
}
bool CPyro::EventProcess(const Event &event)
{
if (event.type != EVENT_FRAME) return true;
if (m_engine->GetPause()) return true;
m_time += event.rTime;
m_progress += event.rTime*m_speed;
if (m_soundChannel != -1 && m_object != nullptr)
{
Math::Vector pos = m_object->GetPosition();
m_sound->Position(m_soundChannel, pos);
if (m_lightRank != -1)
{
pos.y += m_lightHeight;
m_lightMan->SetLightPos(m_lightRank, pos);
}
}
if ( m_type == PT_SHOTT &&
m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
if (m_crashSpheres.size() > 0)
{
int i = rand() % m_crashSpheres.size();
Math::Vector pos = m_crashSpheres[i].pos;
float radius = m_crashSpheres[i].radius;
pos.x += (Math::Rand()-0.5f)*radius*2.0f;
pos.z += (Math::Rand()-0.5f)*radius*2.0f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*radius*0.5f;
speed.z = (Math::Rand()-0.5f)*radius*0.5f;
speed.y = Math::Rand()*radius*1.0f;
Math::Point dim;
dim.x = Math::Rand()*radius*0.5f+radius*0.75f*m_force;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTISMOKE1, 3.0f);
}
else
{
Math::Vector pos = m_pos;
pos.x += (Math::Rand()-0.5f)*m_size*0.3f;
pos.z += (Math::Rand()-0.5f)*m_size*0.3f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*m_size*0.1f;
speed.z = (Math::Rand()-0.5f)*m_size*0.1f;
speed.y = Math::Rand()*m_size*0.2f;
Math::Point dim;
dim.x = Math::Rand()*m_size/10.0f+m_size/10.0f*m_force;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTISMOKE1, 3.0f);
}
}
if ( m_camera->GetBlood() && m_type == PT_SHOTH &&
m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
for (int i = 0; i < 10; i++)
{
Math::Vector pos = m_pos;
pos.x += (Math::Rand()-0.5f)*m_size*0.2f;
pos.z += (Math::Rand()-0.5f)*m_size*0.2f;
pos.y += (Math::Rand()-0.5f)*m_size*0.5f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*5.0f;
speed.z = (Math::Rand()-0.5f)*5.0f;
speed.y = Math::Rand()*1.0f;
Math::Point dim;
dim.x = 1.0f;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIBLOOD, Math::Rand()*3.0f+3.0f, Math::Rand()*10.0f+15.0f, 0.5f);
}
}
if ( m_camera->GetBlood() && m_type == PT_SHOTM &&
m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
int r = static_cast<int>(10.0f*m_engine->GetParticleDensity());
for (int i = 0; i < r; i++)
{
Math::Vector pos = m_pos;
pos.x += (Math::Rand()-0.5f)*20.0f;
pos.z += (Math::Rand()-0.5f)*20.0f;
pos.y += 8.0f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*40.0f;
speed.z = (Math::Rand()-0.5f)*40.0f;
speed.y = Math::Rand()*40.0f;
Math::Point dim;
dim.x = Math::Rand()*8.0f+8.0f*m_force;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIBLOODM, 2.0f, 50.0f, 0.0f);
}
}
if ( m_type == PT_SHOTW &&
m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
if (m_crashSpheres.size() > 0)
{
int i = rand() % m_crashSpheres.size();
Math::Vector pos = m_crashSpheres[i].pos;
float radius = m_crashSpheres[i].radius;
pos.x += (Math::Rand()-0.5f)*radius*2.0f;
pos.z += (Math::Rand()-0.5f)*radius*2.0f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*radius*0.5f;
speed.z = (Math::Rand()-0.5f)*radius*0.5f;
speed.y = Math::Rand()*radius*1.0f;
Math::Point dim;
dim.x = 1.0f*m_force;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
}
else
{
Math::Vector pos = m_pos;
pos.x += (Math::Rand()-0.5f)*m_size*0.3f;
pos.z += (Math::Rand()-0.5f)*m_size*0.3f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*m_size*0.1f;
speed.z = (Math::Rand()-0.5f)*m_size*0.1f;
speed.y = Math::Rand()*m_size*0.2f;
Math::Point dim;
dim.x = 1.0f*m_force;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
}
}
if ( m_type == PT_SHOTW &&
m_lastParticleSmoke+m_engine->ParticleAdapt(0.10f) <= m_time )
{
m_lastParticleSmoke = m_time;
Math::Vector pos = m_pos;
pos.y -= 2.0f;
pos.x += (Math::Rand()-0.5f)*4.0f;
pos.z += (Math::Rand()-0.5f)*4.0f;
Math::Vector speed;
speed.x = 0.0f;
speed.z = 0.0f;
speed.y = 10.0f+Math::Rand()*10.0f;
Math::Point dim;
dim.x = Math::Rand()*2.5f+2.0f*m_force;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTICRASH, 4.0f);
}
if ( (m_type == PT_FRAGT || m_type == PT_EXPLOT) &&
m_progress < 0.05f &&
m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
Math::Vector pos = m_pos;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*m_size*1.0f;
speed.z = (Math::Rand()-0.5f)*m_size*1.0f;
speed.y = Math::Rand()*m_size*0.50f;
Math::Point dim;
dim.x = Math::Rand()*m_size/5.0f+m_size/5.0f;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIEXPLOT);
}
if ( (m_type == PT_FRAGT || m_type == PT_EXPLOT) &&
m_progress < 0.10f &&
m_lastParticleSmoke+m_engine->ParticleAdapt(0.10f) <= m_time )
{
m_lastParticleSmoke = m_time;
Math::Point dim;
dim.x = Math::Rand()*m_size/3.0f+m_size/3.0f;
dim.y = dim.x;
Math::Vector pos = m_pos;
pos.x += (Math::Rand()-0.5f)*m_size*0.5f;
pos.z += (Math::Rand()-0.5f)*m_size*0.5f;
m_terrain->AdjustToFloor(pos);
Math::Vector speed;
speed.x = 0.0f;
speed.z = 0.0f;
speed.y = -dim.x/2.0f/4.0f;
pos.y += dim.x/2.0f;
ParticleType type;
int r = rand()%2;
if (r == 0) type = PARTISMOKE1;
if (r == 1) type = PARTISMOKE2;
m_particle->CreateParticle(pos, speed, dim, type, 6.0f);
}
if ( (m_type == PT_FRAGO || m_type == PT_EXPLOO) &&
m_progress < 0.03f &&
m_lastParticle+m_engine->ParticleAdapt(0.1f) <= m_time )
{
m_lastParticle = m_time;
Math::Vector pos = m_pos;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*m_size*2.0f;
speed.z = (Math::Rand()-0.5f)*m_size*2.0f;
speed.y = Math::Rand()*m_size*1.0f;
Math::Point dim;
dim.x = Math::Rand()*m_size/2.0f+m_size/2.0f;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIEXPLOO);
}
if ( (m_type == PT_FRAGW || m_type == PT_EXPLOW) &&
m_progress < 0.05f &&
m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
Math::Vector pos = m_pos;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*m_size*1.0f;
speed.z = (Math::Rand()-0.5f)*m_size*1.0f;
speed.y = Math::Rand()*m_size*0.50f;
Math::Point dim;
dim.x = 1.0f;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
}
if ( (m_type == PT_FRAGW || m_type == PT_EXPLOW) &&
m_progress < 0.25f &&
m_lastParticleSmoke+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticleSmoke = m_time;
Math::Vector pos = m_pos;
pos.y -= 2.0f;
pos.x += (Math::Rand()-0.5f)*4.0f;
pos.z += (Math::Rand()-0.5f)*4.0f;
Math::Vector speed;
speed.x = 0.0f;
speed.z = 0.0f;
speed.y = 4.0f+Math::Rand()*4.0f;
Math::Point dim;
dim.x = Math::Rand()*2.5f+2.0f;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTICRASH, 4.0f);
}
if ( m_type == PT_WPCHECK )
{
float factor;
if (m_progress < 0.25f)
factor = 0.0f;
else
factor = powf((m_progress-0.25f)/0.75f, 2.0f)*30.0f;
if ( m_progress < 0.85f &&
m_lastParticle+m_engine->ParticleAdapt(0.10f) <= m_time )
{
m_lastParticle = m_time;
Math::Vector pos = m_pos;
pos.y += factor;
pos.x += (Math::Rand()-0.5f)*3.0f;
pos.z += (Math::Rand()-0.5f)*3.0f;
Math::Vector speed;
speed.x = 0.0f;
speed.z = 0.0f;
speed.y = 5.0f+Math::Rand()*5.0f;
Math::Point dim;
dim.x = Math::Rand()*1.5f+1.5f;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIGLINT, 2.0f);
}
if(m_object != nullptr)
{
Math::Vector angle = m_object->GetRotation();
angle.y = m_progress*20.0f;
angle.x = sinf(m_progress*49.0f)*0.3f;
angle.z = sinf(m_progress*47.0f)*0.2f;
m_object->SetAngle(0, angle);
Math::Vector pos = m_pos;
pos.y += factor;
m_object->SetPosition(pos);
if ( m_progress > 0.85f )
{
m_object->SetZoom(0, 1.0f-(m_progress-0.85f)/0.15f);
}
}
}
if ( m_type == PT_FLCREATE )
{
if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
Math::Vector pos = m_pos;
m_terrain->AdjustToFloor(pos);
pos.x += (Math::Rand()-0.5f)*1.0f;
pos.z += (Math::Rand()-0.5f)*1.0f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*2.0f;
speed.z = (Math::Rand()-0.5f)*2.0f;
speed.y = 2.0f+Math::Rand()*2.0f;
Math::Point dim;
dim.x = (Math::Rand()*1.0f+1.0f)*(0.2f+m_progress*0.8f);
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.0f);
}
if(m_object != nullptr)
{
Math::Vector angle = m_object->GetRotation();
angle.x = sinf(m_progress*49.0f)*0.3f*(1.0f-m_progress);
angle.z = sinf(m_progress*47.0f)*0.2f*(1.0f-m_progress);
m_object->SetAngle(0, angle);
m_object->SetZoom(0, m_progress);
}
}
if ( m_type == PT_FLDELETE )
{
if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
Math::Vector pos = m_pos;
m_terrain->AdjustToFloor(pos);
pos.x += (Math::Rand()-0.5f)*1.0f;
pos.z += (Math::Rand()-0.5f)*1.0f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*2.0f;
speed.z = (Math::Rand()-0.5f)*2.0f;
speed.y = 2.0f+Math::Rand()*2.0f;
Math::Point dim;
dim.x = (Math::Rand()*1.0f+1.0f)*(0.2f+m_progress*0.8f);
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.5f);
}
if(m_object != nullptr)
{
Math::Vector angle = m_object->GetRotation();
angle.y = m_progress*20.0f;
angle.x = sinf(m_progress*49.0f)*0.3f;
angle.z = sinf(m_progress*47.0f)*0.2f;
m_object->SetAngle(0, angle);
m_object->SetZoom(0, 1.0f-m_progress);
}
}
if ( m_type == PT_RESET )
{
if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
Math::Vector pos = m_pos;
pos.x += (Math::Rand()-0.5f)*5.0f;
pos.z += (Math::Rand()-0.5f)*5.0f;
Math::Vector speed;
speed.x = 0.0f;
speed.z = 0.0f;
speed.y = 5.0f+Math::Rand()*5.0f;
Math::Point dim;
dim.x = Math::Rand()*2.0f+2.0f;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIGLINTb, 2.0f);
pos = m_pos;
speed.x = (Math::Rand()-0.5f)*20.0f;
speed.z = (Math::Rand()-0.5f)*20.0f;
speed.y = Math::Rand()*10.0f;
speed *= 0.5f+m_progress*0.5f;
dim.x = 0.6f;
dim.y = dim.x;
pos.y += dim.y;
float duration = Math::Rand()*1.5f+1.5f;
m_particle->CreateTrack(pos, speed, dim, PARTITRACK6,
duration, 0.0f,
duration*0.9f, 0.7f);
}
if(m_object != nullptr)
{
float angle = m_resetAngle;
m_object->SetAngleY(0, angle-powf((1.0f-m_progress)*5.0f, 2.0f));
m_object->SetZoom(0, m_progress);
}
}
if ( m_type == PT_FINDING )
{
if ( m_object != nullptr &&
m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
float factor = m_size*0.3f;
if (m_object->GetType() == OBJECT_SAFE) factor *= 1.3f;
if (factor > 40.0f) factor = 40.0f;
Math::Vector pos = m_pos;
m_terrain->AdjustToFloor(pos);
pos.x += (Math::Rand()-0.5f)*factor;
pos.z += (Math::Rand()-0.5f)*factor;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*2.0f;
speed.z = (Math::Rand()-0.5f)*2.0f;
speed.y = 4.0f+Math::Rand()*4.0f;
Math::Point dim;
dim.x = (Math::Rand()*3.0f+3.0f)*(1.0f-m_progress*0.9f);
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.5f);
}
}
if ( (m_type == PT_BURNT || m_type == PT_BURNO) &&
m_object != nullptr )
{
if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
float factor = m_size/25.0f; // 1 = standard size
Math::Vector pos = m_object->GetPosition();
pos.y -= m_object->GetCharacter()->height;
pos.x += (Math::Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor;
pos.z += (Math::Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor;
Math::Vector speed;
speed.x = 0.0f;
speed.z = 0.0f;
speed.y = 0.0f;
Math::Point dim;
dim.x = (Math::Rand()*2.5f+1.0f)*factor;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f);
pos = m_object->GetPosition();
pos.y -= m_object->GetCharacter()->height;
pos.x += (Math::Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor;
pos.z += (Math::Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor;
speed.x = 0.0f;
speed.z = 0.0f;
speed.y = (Math::Rand()*5.0f*m_progress+3.0f)*factor;
dim.x = (Math::Rand()*2.0f+1.0f)*factor;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f);
pos = m_object->GetPosition();
pos.y -= 2.0f;
pos.x += (Math::Rand()-0.5f)*5.0f*factor;
pos.z += (Math::Rand()-0.5f)*5.0f*factor;
speed.x = 0.0f;
speed.z = 0.0f;
speed.y = (6.0f+Math::Rand()*6.0f+m_progress*6.0f)*factor;
dim.x = (Math::Rand()*1.5f+1.0f+m_progress*3.0f)*factor;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTISMOKE3, 4.0f);
}
if ( m_type == PT_BURNT )
{
BurnProgress();
}
else
{
Math::Vector speed;
speed.y = 0.0f;
speed.x = (Math::Rand()-0.5f)*m_progress*1.0f;
speed.z = (Math::Rand()-0.5f)*m_progress*1.0f;
if ( m_progress > 0.8f )
{
float prog = (m_progress-0.8f)/0.2f; // 0..1
speed.y = -prog*6.0f; // sinks into the ground
m_object->SetZoom(0, 1.0f-prog*0.5f);
}
m_object->SetLinVibration(speed);
}
}
if ( m_type == PT_WIN &&
m_object != nullptr )
{
if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time )
{
m_lastParticle = m_time;
Math::Vector pos = m_object->GetPosition();
pos.y += 1.5f;
Math::Vector speed;
speed.x = (Math::Rand()-0.5f)*10.0f;
speed.z = (Math::Rand()-0.5f)*10.0f;
speed.y = 8.0f+Math::Rand()*8.0f;
Math::Point dim;
dim.x = Math::Rand()*0.2f+0.2f;
dim.y = dim.x;
m_particle->CreateTrack(pos, speed, dim,
static_cast<ParticleType>(PARTITRACK7+rand()%4),
3.0f, 20.0f, 1.0f, 0.4f);
}
}
if ( m_type == PT_LOST &&
m_object != nullptr )
{
if ( m_lastParticle+m_engine->ParticleAdapt(0.10f) <= m_time )
{
m_lastParticle = m_time;
Math::Vector pos = m_object->GetPosition();
pos.y -= 2.0f;
pos.x += (Math::Rand()-0.5f)*10.0f;
pos.z += (Math::Rand()-0.5f)*10.0f;
Math::Vector speed;
speed.x = 0.0f;
speed.z = 0.0f;
speed.y = 1.0f+Math::Rand()*1.0f;
Math::Point dim;
dim.x = Math::Rand()*1.0f+1.0f;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, PARTISMOKE1, 8.0f, 0.0f, 0.0f);
}
}
if (m_type == PT_FALL)
FallProgress(event.rTime);
if (m_lightRank != -1)
LightOperFrame(event.rTime);
return true;
}
Error CPyro::IsEnded()
{
// Destroys the object that exploded.
//It should not be destroyed at the end of the Create,
//because it is sometimes the object itself that makes the Create:
// pyro->Create(PT_FRAGT, this);
if ( m_type == PT_FRAGT ||
m_type == PT_FRAGO ||
m_type == PT_FRAGW ||
m_type == PT_SPIDER ||
m_type == PT_EGG )
{
DeleteObject(true, true);
}
if ( m_type == PT_FALL ) // freight which grave?
{
return FallIsEnded();
}
if ( m_type == PT_WIN ||
m_type == PT_LOST )
{
return ERR_CONTINUE;
}
// End of the pyrotechnic effect?
if ( m_progress < 1.0f ) return ERR_CONTINUE;
if ( m_type == PT_EXPLOT ||
m_type == PT_EXPLOO ||
m_type == PT_EXPLOW ) // explosion?
{
ExploTerminate();
}
if ( m_type == PT_BURNT ||
m_type == PT_BURNO ) // burning?
{
BurnTerminate();
}
if ( m_type == PT_WPCHECK ||
m_type == PT_FLDELETE )
{
DeleteObject(true, true);
}
if ( m_type == PT_FLCREATE )
{
m_object->SetAngleX(0, 0.0f);
m_object->SetAngleZ(0, 0.0f);
m_object->SetZoom(0, 1.0f);
}
if ( m_type == PT_RESET )
{
m_object->SetAngleY(0, m_resetAngle);
m_object->SetZoom(0, 1.0f);
}
if ( m_lightRank != -1 )
{
m_lightMan->DeleteLight(m_lightRank);
m_lightRank = -1;
}
return ERR_STOP;
}
void CPyro::CutObjectLink(CObject* obj)
{
if (m_object == obj)
m_object = nullptr;
}
void CPyro::DisplayError(PyroType type, CObject* obj)
{
ObjectType oType = obj->GetType();
if ( type == PT_FRAGT ||
type == PT_FRAGO ||
type == PT_FRAGW ||
type == PT_EXPLOT ||
type == PT_EXPLOO ||
type == PT_EXPLOW ||
type == PT_BURNT ||
type == PT_BURNO )
{
Error err = ERR_OK;
if ( oType == OBJECT_MOTHER ) err = INFO_DELETEMOTHER;
if ( oType == OBJECT_ANT ) err = INFO_DELETEANT;
if ( oType == OBJECT_BEE ) err = INFO_DELETEBEE;
if ( oType == OBJECT_WORM ) err = INFO_DELETEWORM;
if ( oType == OBJECT_SPIDER ) err = INFO_DELETESPIDER;
if ( oType == OBJECT_MOBILEwa ||
oType == OBJECT_MOBILEta ||
oType == OBJECT_MOBILEfa ||
oType == OBJECT_MOBILEia ||
oType == OBJECT_MOBILEwc ||
oType == OBJECT_MOBILEtc ||
oType == OBJECT_MOBILEfc ||
oType == OBJECT_MOBILEic ||
oType == OBJECT_MOBILEwi ||
oType == OBJECT_MOBILEti ||
oType == OBJECT_MOBILEfi ||
oType == OBJECT_MOBILEii ||
oType == OBJECT_MOBILEws ||
oType == OBJECT_MOBILEts ||
oType == OBJECT_MOBILEfs ||
oType == OBJECT_MOBILEis ||
oType == OBJECT_MOBILErt ||
oType == OBJECT_MOBILErc ||
oType == OBJECT_MOBILErr ||
oType == OBJECT_MOBILErs ||
oType == OBJECT_MOBILEsa ||
oType == OBJECT_MOBILEwt ||
oType == OBJECT_MOBILEtt ||
oType == OBJECT_MOBILEft ||
oType == OBJECT_MOBILEit ||
oType == OBJECT_MOBILEdr )
{
err = ERR_DELETEMOBILE;
}
if ( oType == OBJECT_DERRICK ||
oType == OBJECT_FACTORY ||
oType == OBJECT_STATION ||
oType == OBJECT_CONVERT ||
oType == OBJECT_REPAIR ||
oType == OBJECT_DESTROYER||
oType == OBJECT_TOWER ||
oType == OBJECT_RESEARCH ||
oType == OBJECT_RADAR ||
oType == OBJECT_INFO ||
oType == OBJECT_ENERGY ||
oType == OBJECT_LABO ||
oType == OBJECT_NUCLEAR ||
oType == OBJECT_PARA ||
oType == OBJECT_SAFE ||
oType == OBJECT_HUSTON ||
oType == OBJECT_START ||
oType == OBJECT_END )
{
err = ERR_DELETEBUILDING;
m_main->DisplayError(err, obj->GetPosition(), 5.0f);
return;
}
if ( err != ERR_OK )
{
m_main->DisplayError(err, obj);
}
}
}
void CPyro::CreateLight(Math::Vector pos, float height)
{
if (!m_engine->GetLightMode()) return;
m_lightHeight = height;
Gfx::Light light;
light.type = LIGHT_SPOT;
light.ambient = Gfx::Color(0.0f, 0.0f, 0.0f);
light.position = Math::Vector(pos.x, pos.y+height, pos.z);
light.direction = Math::Vector(0.0f, -1.0f, 0.0f); // against the bottom
light.spotIntensity = 1.0f;
light.attenuation0 = 1.0f;
light.attenuation1 = 0.0f;
light.attenuation2 = 0.0f;
light.spotAngle = Math::PI/4.0f;
m_lightRank = m_lightMan->CreateLight();
m_lightMan->SetLight(m_lightRank, light);
m_lightMan->SetLightIntensity(m_lightRank, 0.0f);
// Only illuminates the objects on the ground.
m_lightMan->SetLightIncludeType(m_lightRank, ENG_OBJTYPE_TERRAIN);
}
void CPyro::DeleteObject(bool primary, bool secondary)
{
if (m_object == nullptr) return;
ObjectType type = m_object->GetType();
if ( secondary &&
type != OBJECT_FACTORY &&
type != OBJECT_NUCLEAR &&
type != OBJECT_ENERGY )
{
if (m_object->Implements(ObjectInterfaceType::Powered))
{
CPoweredObject* poweredObject = dynamic_cast<CPoweredObject*>(m_object);
CObject* sub = poweredObject->GetPower();
if (sub != nullptr)
{
CObjectManager::GetInstancePointer()->DeleteObject(sub);
poweredObject->SetPower(nullptr);
}
}
if (m_object->Implements(ObjectInterfaceType::Carrier))
{
CCarrierObject* carrierObject = dynamic_cast<CCarrierObject*>(m_object);
CObject* sub = carrierObject->GetCargo();
if (sub != nullptr)
{
CObjectManager::GetInstancePointer()->DeleteObject(sub);
carrierObject->SetCargo(nullptr);
}
}
}
if (primary)
{
if (m_object->Implements(ObjectInterfaceType::Transportable))
{
// TODO: this should be handled in the object's destructor
CObject* transporter = dynamic_cast<CTransportableObject*>(m_object)->GetTransporter();
if (transporter != nullptr)
{
if (transporter->Implements(ObjectInterfaceType::Powered))
{
CPoweredObject* powered = dynamic_cast<CPoweredObject*>(transporter);
if (powered->GetPower() == m_object)
powered->SetPower(nullptr);
}
if (transporter->Implements(ObjectInterfaceType::Carrier))
{
CCarrierObject* carrier = dynamic_cast<CCarrierObject*>(transporter);
if (carrier->GetCargo() == m_object)
carrier->SetCargo(nullptr);
}
}
}
CObjectManager::GetInstancePointer()->DeleteObject(m_object);
m_object = nullptr;
}
}
void CPyro::CreateTriangle(CObject* obj, ObjectType oType, int part)
{
int objRank = obj->GetObjectRank(part);
if (objRank == -1) return;
int total = m_engine->GetObjectTotalTriangles(objRank);
float percent = 0.10f;
if (total < 50) percent = 0.25f;
if (total < 20) percent = 0.50f;
if (m_type == PT_EGG) percent = 0.30f;
if (oType == OBJECT_POWER ||
oType == OBJECT_ATOMIC ||
oType == OBJECT_URANIUM ||
oType == OBJECT_TNT ||
oType == OBJECT_BOMB )
{
percent = 0.75f;
}
else if (oType == OBJECT_MOBILEtg)
{
percent = 0.50f;
}
std::vector<EngineTriangle> buffer;
total = m_engine->GetPartialTriangles(objRank, percent, 100, buffer);
for (int i = 0; i < total; i++)
{
Math::Vector p1, p2, p3;
p1.x = buffer[i].triangle[0].coord.x;
p1.y = buffer[i].triangle[0].coord.y;
p1.z = buffer[i].triangle[0].coord.z;
p2.x = buffer[i].triangle[1].coord.x;
p2.y = buffer[i].triangle[1].coord.y;
p2.z = buffer[i].triangle[1].coord.z;
p3.x = buffer[i].triangle[2].coord.x;
p3.y = buffer[i].triangle[2].coord.y;
p3.z = buffer[i].triangle[2].coord.z;
float h;
h = Math::Distance(p1, p2);
if ( h > 5.0f )
{
p2.x = p1.x+((p2.x-p1.x)*5.0f/h);
p2.y = p1.y+((p2.y-p1.y)*5.0f/h);
p2.z = p1.z+((p2.z-p1.z)*5.0f/h);
}
h = Math::Distance(p2, p3);
if ( h > 5.0f )
{
p3.x = p2.x+((p3.x-p2.x)*5.0f/h);
p3.y = p2.y+((p3.y-p2.y)*5.0f/h);
p3.z = p2.z+((p3.z-p2.z)*5.0f/h);
}
h = Math::Distance(p3, p1);
if ( h > 5.0f )
{
p1.x = p3.x+((p1.x-p3.x)*5.0f/h);
p1.y = p3.y+((p1.y-p3.y)*5.0f/h);
p1.z = p3.z+((p1.z-p3.z)*5.0f/h);
}
buffer[i].triangle[0].coord.x = p1.x;
buffer[i].triangle[0].coord.y = p1.y;
buffer[i].triangle[0].coord.z = p1.z;
buffer[i].triangle[1].coord.x = p2.x;
buffer[i].triangle[1].coord.y = p2.y;
buffer[i].triangle[1].coord.z = p2.z;
buffer[i].triangle[2].coord.x = p3.x;
buffer[i].triangle[2].coord.y = p3.y;
buffer[i].triangle[2].coord.z = p3.z;
Math::Vector offset;
offset.x = (buffer[i].triangle[0].coord.x+buffer[i].triangle[1].coord.x+buffer[i].triangle[2].coord.x)/3.0f;
offset.y = (buffer[i].triangle[0].coord.y+buffer[i].triangle[1].coord.y+buffer[i].triangle[2].coord.y)/3.0f;
offset.z = (buffer[i].triangle[0].coord.z+buffer[i].triangle[1].coord.z+buffer[i].triangle[2].coord.z)/3.0f;
buffer[i].triangle[0].coord.x -= offset.x;
buffer[i].triangle[1].coord.x -= offset.x;
buffer[i].triangle[2].coord.x -= offset.x;
buffer[i].triangle[0].coord.y -= offset.y;
buffer[i].triangle[1].coord.y -= offset.y;
buffer[i].triangle[2].coord.y -= offset.y;
buffer[i].triangle[0].coord.z -= offset.z;
buffer[i].triangle[1].coord.z -= offset.z;
buffer[i].triangle[2].coord.z -= offset.z;
Math::Vector speed;
float mass;
Math::Matrix* mat = obj->GetWorldMatrix(part);
Math::Vector pos = Math::Transform(*mat, offset);
if ( m_type == PT_EGG )
{
speed.x = (Math::Rand()-0.5f)*10.0f;
speed.z = (Math::Rand()-0.5f)*10.0f;
speed.y = Math::Rand()*15.0f;
mass = Math::Rand()*20.0f+20.0f;
}
else if ( m_type == PT_SPIDER )
{
speed.x = (Math::Rand()-0.5f)*10.0f;
speed.z = (Math::Rand()-0.5f)*10.0f;
speed.y = Math::Rand()*20.0f;
mass = Math::Rand()*10.0f+15.0f;
}
else
{
speed.x = (Math::Rand()-0.5f)*30.0f;
speed.z = (Math::Rand()-0.5f)*30.0f;
speed.y = Math::Rand()*30.0f;
mass = Math::Rand()*10.0f+15.0f;
}
if ( oType == OBJECT_STONE ) speed *= 0.5f;
if ( oType == OBJECT_URANIUM ) speed *= 0.4f;
float duration = Math::Rand()*3.0f+3.0f;
m_particle->CreateFrag(pos, speed, &buffer[i], PARTIFRAG,
duration, mass, 0.5f);
}
}
void CPyro::ExploStart()
{
m_burnType = m_object->GetType();
Math::Vector oPos = m_object->GetPosition();
m_burnFall = m_terrain->GetHeightToFloor(oPos, true);
m_object->Simplify();
m_object->SetLock(true); // ruin not usable yet
m_object->SetExploding(true); // being destroyed
m_object->FlatParent();
if ( m_object->GetSelect() )
{
m_object->SetSelect(false); // deselects the object
m_camera->SetType(CAM_TYPE_EXPLO);
m_main->DeselectAll();
}
m_object->DeleteDeselList(m_object);
for (int i = 0; i < OBJECTMAXPART; i++)
{
int objRank = m_object->GetObjectRank(i);
if (objRank == -1) continue;
// TODO: refactor later to material change
int oldBaseObjRank = m_engine->GetObjectBaseRank(objRank);
if (oldBaseObjRank != -1)
{
int newBaseObjRank = m_engine->CreateBaseObject();
m_engine->CopyBaseObject(oldBaseObjRank, newBaseObjRank);
m_engine->SetObjectBaseRank(objRank, newBaseObjRank);
m_engine->ChangeSecondTexture(objRank, "dirty04.png");
}
// TODO: temporary hack (hopefully)
assert(m_object->Implements(ObjectInterfaceType::Old));
Math::Vector pos = dynamic_cast<COldObject*>(m_object)->GetPartPosition(i);
Math::Vector speed;
float weight;
if (i == 0) // main part?
{
weight = 0.0f;
speed.y = -1.0f;
speed.x = 0.0f;
speed.z = 0.0f;
}
else
{
Math::Vector min, max;
m_engine->GetObjectBBox(objRank, min, max);
weight = Math::Distance(min, max); // weight according to size!
speed.y = 10.0f+Math::Rand()*20.0f;
speed.x = (Math::Rand()-0.5f)*20.0f;
speed.z = (Math::Rand()-0.5f)*20.0f;
}
int channel = m_particle->CreatePart(pos, speed, PARTIPART, 10.0f, 20.0f, weight, 0.5f);
if (channel != -1)
m_object->SetMasterParticle(i, channel);
}
m_engine->LoadTexture("textures/dirty04.png");
DeleteObject(false, true); // destroys the object transported + the battery
}
void CPyro::ExploTerminate()
{
DeleteObject(true, false); // removes the main object
}
void CPyro::BurnStart()
{
m_burnType = m_object->GetType();
Math::Vector oPos = m_object->GetPosition();
m_burnFall = m_terrain->GetHeightToFloor(oPos, true);
m_object->Simplify();
m_object->SetLock(true); // ruin not usable yet
if ( m_object->GetSelect() )
{
m_object->SetSelect(false); // deselects the object
m_camera->SetType(CAM_TYPE_EXPLO);
m_main->DeselectAll();
}
m_object->DeleteDeselList(m_object);
for (int i = 0; i < OBJECTMAXPART; i++)
{
int objRank = m_object->GetObjectRank(i);
if (objRank == -1) continue;
// TODO: refactor later to material change
int oldBaseObjRank = m_engine->GetObjectBaseRank(objRank);
if (oldBaseObjRank != -1)
{
int newBaseObjRank = m_engine->CreateBaseObject();
m_engine->CopyBaseObject(oldBaseObjRank, newBaseObjRank);
m_engine->SetObjectBaseRank(objRank, newBaseObjRank);
m_engine->ChangeSecondTexture(objRank, "dirty04.png");
}
}
m_engine->LoadTexture("textures/dirty04.png");
m_burnPartTotal = 0;
Math::Vector pos, angle;
if ( m_burnType == OBJECT_DERRICK ||
m_burnType == OBJECT_FACTORY ||
m_burnType == OBJECT_REPAIR ||
m_burnType == OBJECT_DESTROYER||
m_burnType == OBJECT_CONVERT ||
m_burnType == OBJECT_TOWER ||
m_burnType == OBJECT_RESEARCH ||
m_burnType == OBJECT_ENERGY ||
m_burnType == OBJECT_LABO )
{
pos.x = 0.0f;
pos.y = -(4.0f+Math::Rand()*4.0f);
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.4f;
angle.y = 0.0f;
angle.z = (Math::Rand()-0.5f)*0.4f;
}
else if ( m_burnType == OBJECT_STATION ||
m_burnType == OBJECT_RADAR ||
m_burnType == OBJECT_INFO )
{
pos.x = 0.0f;
pos.y = -(1.0f+Math::Rand()*1.0f);
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.2f;
angle.y = 0.0f;
angle.z = (Math::Rand()-0.5f)*0.2f;
}
else if ( m_burnType == OBJECT_NUCLEAR )
{
pos.x = 0.0f;
pos.y = -(10.0f+Math::Rand()*10.0f);
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.4f;
angle.y = 0.0f;
angle.z = (Math::Rand()-0.5f)*0.4f;
}
else if ( m_burnType == OBJECT_PARA )
{
pos.x = 0.0f;
pos.y = -(10.0f+Math::Rand()*10.0f);
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.4f;
angle.y = 0.0f;
angle.z = (Math::Rand()-0.5f)*0.4f;
}
else if ( m_burnType == OBJECT_SAFE )
{
pos.x = 0.0f;
pos.y = -(10.0f+Math::Rand()*10.0f);
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.4f;
angle.y = 0.0f;
angle.z = (Math::Rand()-0.5f)*0.4f;
}
else if ( m_burnType == OBJECT_HUSTON )
{
pos.x = 0.0f;
pos.y = -(10.0f+Math::Rand()*10.0f);
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.4f;
angle.y = 0.0f;
angle.z = (Math::Rand()-0.5f)*0.4f;
}
else if ( m_burnType == OBJECT_MOBILEwa ||
m_burnType == OBJECT_MOBILEwc ||
m_burnType == OBJECT_MOBILEwi ||
m_burnType == OBJECT_MOBILEws ||
m_burnType == OBJECT_MOBILEwt )
{
pos.x = 0.0f;
pos.y = -(0.5f+Math::Rand()*1.0f);
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.8f;
angle.y = 0.0f;
angle.z = (Math::Rand()-0.5f)*0.4f;
}
else
{
pos.x = 0.0f;
pos.y = -(2.0f+Math::Rand()*2.0f);
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.8f;
angle.y = 0.0f;
angle.z = (Math::Rand()-0.5f)*0.8f;
}
BurnAddPart(0, pos, angle); // movement of the main part
m_burnKeepPart[0] = -1; // nothing to keep
if ( m_burnType == OBJECT_DERRICK )
{
pos.x = 0.0f;
pos.y = -40.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the drill
}
if ( m_burnType == OBJECT_REPAIR )
{
pos.x = 0.0f;
pos.y = -12.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.2f;
angle.y = (Math::Rand()-0.5f)*0.2f;
angle.z = -90.0f*Math::PI/180.0f;
BurnAddPart(1, pos, angle); // down the sensor
}
if ( m_burnType == OBJECT_DESTROYER )
{
pos.x = 0.0f;
pos.y = -12.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.2f;
angle.y = (Math::Rand()-0.5f)*0.2f;
angle.z = -90.0f*Math::PI/180.0f;
BurnAddPart(1, pos, angle); // down the sensor
}
if ( m_burnType == OBJECT_CONVERT )
{
pos.x = 0.0f;
pos.y = -200.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.5f;
angle.y = (Math::Rand()-0.5f)*0.5f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the cover
BurnAddPart(2, pos, angle);
BurnAddPart(3, pos, angle);
}
if ( m_burnType == OBJECT_TOWER )
{
pos.x = 0.0f;
pos.y = -7.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.4f;
angle.y = (Math::Rand()-0.5f)*0.4f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the cannon
}
if ( m_burnType == OBJECT_RESEARCH )
{
pos.x = 0.0f;
pos.y = -7.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.2f;
angle.y = (Math::Rand()-0.5f)*0.2f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the anemometer
}
if ( m_burnType == OBJECT_RADAR )
{
pos.x = 0.0f;
pos.y = -14.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.4f;
angle.y = (Math::Rand()-0.5f)*0.4f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the radar
BurnAddPart(2, pos, angle);
}
if ( m_burnType == OBJECT_INFO )
{
pos.x = 0.0f;
pos.y = -14.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.4f;
angle.y = (Math::Rand()-0.5f)*0.4f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the information terminal
BurnAddPart(2, pos, angle);
}
if ( m_burnType == OBJECT_LABO )
{
pos.x = 0.0f;
pos.y = -12.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the arm
}
if ( m_burnType == OBJECT_NUCLEAR )
{
pos.x = 0.0f;
pos.y = 0.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = -135.0f*Math::PI/180.0f;
BurnAddPart(1, pos, angle); // down the cover
}
if ( m_burnType == OBJECT_MOBILEfa ||
m_burnType == OBJECT_MOBILEta ||
m_burnType == OBJECT_MOBILEwa ||
m_burnType == OBJECT_MOBILEia )
{
pos.x = 2.0f;
pos.y = -5.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.2f;
angle.y = (Math::Rand()-0.5f)*0.2f;
angle.z = 40.0f*Math::PI/180.0f;
BurnAddPart(1, pos, angle); // down the arm
}
if ( m_burnType == OBJECT_MOBILEfs ||
m_burnType == OBJECT_MOBILEts ||
m_burnType == OBJECT_MOBILEws ||
m_burnType == OBJECT_MOBILEis )
{
pos.x = 0.0f;
pos.y = -7.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.2f;
angle.y = (Math::Rand()-0.5f)*0.2f;
angle.z = 50.0f*Math::PI/180.0f;
BurnAddPart(1, pos, angle); // down the sensor
}
if ( m_burnType == OBJECT_MOBILEfc ||
m_burnType == OBJECT_MOBILEtc ||
m_burnType == OBJECT_MOBILEwc ||
m_burnType == OBJECT_MOBILEic )
{
pos.x = -1.5f;
pos.y = -5.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.2f;
angle.y = (Math::Rand()-0.5f)*0.2f;
angle.z = -25.0f*Math::PI/180.0f;
BurnAddPart(1, pos, angle); // down the cannon
}
if ( m_burnType == OBJECT_MOBILEfi ||
m_burnType == OBJECT_MOBILEti ||
m_burnType == OBJECT_MOBILEwi ||
m_burnType == OBJECT_MOBILEii )
{
pos.x = -1.5f;
pos.y = -5.0f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*0.2f;
angle.y = (Math::Rand()-0.5f)*0.2f;
angle.z = -25.0f*Math::PI/180.0f;
BurnAddPart(1, pos, angle); // down the insect-cannon
}
if ( m_burnType == OBJECT_MOBILErt ||
m_burnType == OBJECT_MOBILErc )
{
pos.x = 0.0f;
pos.y = -10.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the holder
pos.x = 0.0f;
pos.y = -10.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = 0.0f;
BurnAddPart(2, pos, angle); // down the pestle/cannon
}
if ( m_burnType == OBJECT_MOBILErr )
{
pos.x = 0.0f;
pos.y = -10.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the holder
pos.x = 0.0f;
pos.y = 0.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = -Math::PI/2.0f;
BurnAddPart(4, pos, angle);
pos.x = 0.0f;
pos.y = 0.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = Math::PI/2.5f;
BurnAddPart(2, pos, angle);
}
if ( m_burnType == OBJECT_MOBILErs )
{
pos.x = 0.0f;
pos.y = -10.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the holder
pos.x = 0.0f;
pos.y = -5.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = 0.0f;
BurnAddPart(2, pos, angle);
pos.x = 0.0f;
pos.y = -5.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = 0.0f;
BurnAddPart(3, pos, angle);
}
if ( m_burnType == OBJECT_MOBILEsa )
{
pos.x = 0.0f;
pos.y = -10.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = 0.0f;
BurnAddPart(1, pos, angle); // down the holder
}
if ( m_burnType == OBJECT_MOBILEwa ||
m_burnType == OBJECT_MOBILEwc ||
m_burnType == OBJECT_MOBILEwi ||
m_burnType == OBJECT_MOBILEws ||
m_burnType == OBJECT_MOBILEwt ) // wheels?
{
int i = 0;
for (; i < 4; i++)
{
pos.x = 0.0f;
pos.y = Math::Rand()*0.5f;
pos.z = 0.0f;
angle.x = (Math::Rand()-0.5f)*Math::PI/2.0f;
angle.y = (Math::Rand()-0.5f)*Math::PI/2.0f;
angle.z = 0.0f;
BurnAddPart(6+i, pos, angle); // wheel
m_burnKeepPart[i] = 6+i; // we keep the wheels
}
m_burnKeepPart[i] = -1;
}
if ( m_burnType == OBJECT_MOBILEta ||
m_burnType == OBJECT_MOBILEtc ||
m_burnType == OBJECT_MOBILEti ||
m_burnType == OBJECT_MOBILEts ||
m_burnType == OBJECT_MOBILErt ||
m_burnType == OBJECT_MOBILErc ||
m_burnType == OBJECT_MOBILErr ||
m_burnType == OBJECT_MOBILErs ||
m_burnType == OBJECT_MOBILEsa ||
m_burnType == OBJECT_MOBILEdr ) // caterpillars?
{
pos.x = 0.0f;
pos.y = -4.0f;
pos.z = 2.0f;
angle.x = (Math::Rand()-0.5f)*20.0f*Math::PI/180.0f;
angle.y = (Math::Rand()-0.5f)*10.0f*Math::PI/180.0f;
angle.z = (Math::Rand()-0.5f)*30.0f*Math::PI/180.0f;
BurnAddPart(6, pos, angle); // down the right caterpillar
pos.x = 0.0f;
pos.y = -4.0f;
pos.z = -2.0f;
angle.x = (Math::Rand()-0.5f)*20.0f*Math::PI/180.0f;
angle.y = (Math::Rand()-0.5f)*10.0f*Math::PI/180.0f;
angle.z = (Math::Rand()-0.5f)*30.0f*Math::PI/180.0f;
BurnAddPart(7, pos, angle); // down the left caterpillar
}
if ( m_burnType == OBJECT_MOBILEfa ||
m_burnType == OBJECT_MOBILEfc ||
m_burnType == OBJECT_MOBILEfi ||
m_burnType == OBJECT_MOBILEfs ||
m_burnType == OBJECT_MOBILEft ) // flying?
{
int i = 0;
for (; i<3; i++)
{
pos.x = 0.0f;
pos.y = -3.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = 0.0f;
angle.z = (Math::Rand()-0.5f)*Math::PI/2.0f;
BurnAddPart(6+i, pos, angle); // foot
}
m_burnKeepPart[i] = -1;
}
if ( m_burnType == OBJECT_MOBILEia ||
m_burnType == OBJECT_MOBILEic ||
m_burnType == OBJECT_MOBILEii ||
m_burnType == OBJECT_MOBILEis ) // legs?
{
for (int i = 0; i < 6; i++)
{
pos.x = 0.0f;
pos.y = -3.0f;
pos.z = 0.0f;
angle.x = 0.0f;
angle.y = (Math::Rand()-0.5f)*Math::PI/4.0f;
angle.z = (Math::Rand()-0.5f)*Math::PI/4.0f;
BurnAddPart(6+i, pos, angle); // leg
}
}
}
void CPyro::BurnAddPart(int part, Math::Vector pos, Math::Vector angle)
{
int i = m_burnPartTotal;
m_burnPart[i].part = part;
// TODO: temporary hack (hopefully)
assert(m_object->Implements(ObjectInterfaceType::Old));
m_burnPart[i].initialPos = dynamic_cast<COldObject*>(m_object)->GetPartPosition(part);
m_burnPart[i].finalPos = m_burnPart[i].initialPos+pos;
m_burnPart[i].initialAngle = m_object->GetAngle(part);
m_burnPart[i].finalAngle = m_burnPart[i].initialAngle+angle;
m_burnPartTotal++;
}
void CPyro::BurnProgress()
{
for (int i = 0; i < m_burnPartTotal; i++)
{
Math::Vector pos = m_burnPart[i].initialPos + m_progress*(m_burnPart[i].finalPos-m_burnPart[i].initialPos);
if ( i == 0 && m_burnFall > 0.0f )
{
float h = powf(m_progress, 2.0f)*1000.0f;
if ( h > m_burnFall ) h = m_burnFall;
pos.y -= h;
}
// TODO: temporary hack (hopefully)
assert(m_object->Implements(ObjectInterfaceType::Old));
dynamic_cast<COldObject*>(m_object)->SetPartPosition(m_burnPart[i].part, pos);
pos = m_burnPart[i].initialAngle + m_progress*(m_burnPart[i].finalAngle-m_burnPart[i].initialAngle);
m_object->SetAngle(m_burnPart[i].part, pos);
}
if (m_object->Implements(ObjectInterfaceType::Powered))
{
CObject* sub = dynamic_cast<CPoweredObject*>(m_object)->GetPower();
if (sub != nullptr) // is there a battery?
sub->SetZoomY(0, 1.0f - m_progress); // complete flattening
}
}
bool CPyro::BurnIsKeepPart(int part)
{
int i = 0;
while (m_burnKeepPart[i] != -1)
{
if (part == m_burnKeepPart[i++]) return true; // must keep
}
return false; // must destroy
}
void CPyro::BurnTerminate()
{
if (m_type == PT_BURNO) // organic object is burning?
{
DeleteObject(true, true); // removes the insect
return;
}
for (int i = 1; i < OBJECTMAXPART; i++)
{
int objRank = m_object->GetObjectRank(i);
if (objRank == -1) continue;
if (BurnIsKeepPart(i)) continue;
m_object->DeletePart(i);
}
DeleteObject(false, true); // destroys the object transported + the battery
if ( m_burnType == OBJECT_DERRICK ||
m_burnType == OBJECT_STATION ||
m_burnType == OBJECT_FACTORY ||
m_burnType == OBJECT_REPAIR ||
m_burnType == OBJECT_DESTROYER||
m_burnType == OBJECT_CONVERT ||
m_burnType == OBJECT_TOWER ||
m_burnType == OBJECT_RESEARCH ||
m_burnType == OBJECT_RADAR ||
m_burnType == OBJECT_INFO ||
m_burnType == OBJECT_ENERGY ||
m_burnType == OBJECT_LABO ||
m_burnType == OBJECT_NUCLEAR ||
m_burnType == OBJECT_PARA ||
m_burnType == OBJECT_SAFE ||
m_burnType == OBJECT_HUSTON ||
m_burnType == OBJECT_START ||
m_burnType == OBJECT_END )
{
m_object->SetType(OBJECT_RUINfactory); // others become a ruin
m_object->SetLock(false);
}
else
{
m_object->SetType(OBJECT_RUINmobilew1); // others become a ruin
m_object->SetLock(false);
}
m_object->SetBurn(false); // ruin usable (c-e-d. recoverable)
}
void CPyro::FallStart()
{
m_object->SetBurn(true); // usable
Math::Vector pos = m_object->GetPosition();
m_fallFloor = m_terrain->GetFloorLevel(pos);
m_fallSpeed = 0.0f;
m_fallBulletTime = 0.0f;
m_fallEnding = false;
}
CObject* CPyro::FallSearchBeeExplo()
{
auto bulletCrashSphere = m_object->GetFirstCrashSphere();
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
{
ObjectType oType = obj->GetType();
if ( oType != OBJECT_HUMAN &&
oType != OBJECT_MOBILEfa &&
oType != OBJECT_MOBILEta &&
oType != OBJECT_MOBILEwa &&
oType != OBJECT_MOBILEia &&
oType != OBJECT_MOBILEfc &&
oType != OBJECT_MOBILEtc &&
oType != OBJECT_MOBILEwc &&
oType != OBJECT_MOBILEic &&
oType != OBJECT_MOBILEfi &&
oType != OBJECT_MOBILEti &&
oType != OBJECT_MOBILEwi &&
oType != OBJECT_MOBILEii &&
oType != OBJECT_MOBILEfs &&
oType != OBJECT_MOBILEts &&
oType != OBJECT_MOBILEws &&
oType != OBJECT_MOBILEis &&
oType != OBJECT_MOBILErt &&
oType != OBJECT_MOBILErc &&
oType != OBJECT_MOBILErr &&
oType != OBJECT_MOBILErs &&
oType != OBJECT_MOBILEsa &&
oType != OBJECT_MOBILEtg &&
oType != OBJECT_MOBILEft &&
oType != OBJECT_MOBILEtt &&
oType != OBJECT_MOBILEwt &&
oType != OBJECT_MOBILEit &&
oType != OBJECT_MOBILEdr &&
oType != OBJECT_BASE &&
oType != OBJECT_DERRICK &&
oType != OBJECT_STATION &&
oType != OBJECT_FACTORY &&
oType != OBJECT_REPAIR &&
oType != OBJECT_DESTROYER&&
oType != OBJECT_CONVERT &&
oType != OBJECT_TOWER &&
oType != OBJECT_RESEARCH &&
oType != OBJECT_RADAR &&
oType != OBJECT_INFO &&
oType != OBJECT_ENERGY &&
oType != OBJECT_LABO &&
oType != OBJECT_NUCLEAR &&
oType != OBJECT_PARA &&
oType != OBJECT_SAFE &&
oType != OBJECT_HUSTON &&
oType != OBJECT_METAL &&
oType != OBJECT_POWER &&
oType != OBJECT_ATOMIC ) continue;
if (IsObjectBeingTransported(obj)) continue;
Math::Vector oPos = obj->GetPosition();
float shieldRadius = obj->GetShieldRadius();
if ( shieldRadius > 0.0f )
{
float distance = Math::Distance(oPos, bulletCrashSphere.sphere.pos);
if (distance <= shieldRadius)
return obj;
}
if ( oType == OBJECT_BASE )
{
float distance = Math::Distance(oPos, bulletCrashSphere.sphere.pos);
if (distance < 25.0f)
return obj;
}
// Test the center of the object, which is necessary for objects
// that have no sphere in the center (station).
float distance = Math::Distance(oPos, bulletCrashSphere.sphere.pos)-4.0f;
if (distance < 5.0f)
return obj;
// Test with all spheres of the object.
for (const auto& objCrashSphere : obj->GetAllCrashSpheres())
{
if (Math::DistanceBetweenSpheres(objCrashSphere.sphere, bulletCrashSphere.sphere) <= 0.0f)
{
return obj;
}
}
}
return nullptr;
}
void CPyro::FallProgress(float rTime)
{
if (m_object == nullptr) return;
m_fallSpeed += rTime*50.0f; // v2 = v1 + a*dt
Math::Vector pos;
pos = m_object->GetPosition();
pos.y -= m_fallSpeed*rTime; // dd -= v2*dt
bool floor = false;
if (pos.y <= m_fallFloor) // below the ground level?
{
pos.y = m_fallFloor;
floor = true;
}
m_object->SetPosition(pos);
if (m_object->GetType() == OBJECT_BULLET)
{
m_fallBulletTime += rTime;
if (m_fallBulletTime > 0.2f || floor)
{
m_fallBulletTime = 0.0f;
CObject* obj = FallSearchBeeExplo();
if (obj == nullptr)
{
if (floor) // reaches the ground?
{
m_object->ExplodeObject(ExplosionType::Bang, 0.0f); // start explosion
}
}
else
{
if (obj->GetShieldRadius() > 0.0f) // protected by shield?
{
m_particle->CreateParticle(pos, Math::Vector(0.0f, 0.0f, 0.0f),
Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f, 0.0f, 0.0f);
m_sound->Play(SOUND_GUNDEL);
DeleteObject(true, true); // removes the ball
}
else
{
if (obj->ExplodeObject(ExplosionType::Bang, 1.0f)) // start explosion
{
DeleteObject(true, true); // removes the ball
}
else
{
m_object->ExplodeObject(ExplosionType::Bang, 0.0f); // start explosion
}
}
}
if (floor || obj != nullptr)
{
m_fallEnding = true;
}
}
}
}
Error CPyro::FallIsEnded()
{
if (m_fallEnding || m_object == 0) return ERR_STOP;
Math::Vector pos = m_object->GetPosition();
if (pos.y > m_fallFloor) return ERR_CONTINUE;
m_sound->Play(SOUND_BOUM, pos);
m_object->SetBurn(false); // usable again
return ERR_STOP;
}
void CPyro::LightOperFlush()
{
m_lightOperTotal = 0;
}
void CPyro::LightOperAdd(float progress, float intensity, float r, float g, float b)
{
int i = m_lightOperTotal;
m_lightOper[i].progress = progress;
m_lightOper[i].intensity = intensity;
m_lightOper[i].color.r = r;
m_lightOper[i].color.g = g;
m_lightOper[i].color.b = b;
m_lightOperTotal++;
}
void CPyro::LightOperFrame(float rTime)
{
for (int i = 0; i < m_lightOperTotal; i++)
{
if ( m_progress < m_lightOper[i].progress )
{
assert(i > 0); // TODO: if assert fails, fix the code
float progress = (m_progress-m_lightOper[i-1].progress) / (m_lightOper[i].progress-m_lightOper[i-1].progress);
float intensity = m_lightOper[i-1].intensity + (m_lightOper[i].intensity-m_lightOper[i-1].intensity)*progress;
Gfx::Color color;
color.r = m_lightOper[i-1].color.r + (m_lightOper[i].color.r-m_lightOper[i-1].color.r)*progress;
color.g = m_lightOper[i-1].color.g + (m_lightOper[i].color.g-m_lightOper[i-1].color.g)*progress;
color.b = m_lightOper[i-1].color.b + (m_lightOper[i].color.b-m_lightOper[i-1].color.b)*progress;
m_lightMan->SetLightIntensity(m_lightRank, intensity);
m_lightMan->SetLightColor(m_lightRank, color);
break;
}
}
}
} // namespace Gfx