From 858b1e35aed8b3a37f138138910327f7259d1251 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Wed, 3 Oct 2012 00:29:59 +0200 Subject: [PATCH 01/14] Spot light angle fix --- src/graphics/core/light.h | 4 ++-- src/graphics/opengl/gldevice.cpp | 2 +- src/object/object.cpp | 4 ++-- src/object/task/taskbuild.cpp | 3 +-- src/object/task/taskshield.cpp | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/graphics/core/light.h b/src/graphics/core/light.h index 35f37e64..28733c1d 100644 --- a/src/graphics/core/light.h +++ b/src/graphics/core/light.h @@ -68,7 +68,7 @@ struct Light float attenuation1; //! Quadratic attenuation factor float attenuation2; - //! Angle of spotlight cone (0-90 degrees) + //! Angle of spotlight cone (0-PI/2 radians) float spotAngle; //! Intensity of spotlight (0 = uniform; 128 = most intense) @@ -91,7 +91,7 @@ struct Light direction = Math::Vector(0.0f, 0.0f, 1.0f); attenuation0 = 1.0f; attenuation1 = attenuation2 = 0.0f; - spotAngle = 90.0f; + spotAngle = Math::PI/2.0f; spotIntensity = 0.0f; } }; diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp index dbf91c71..7bfd8436 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gldevice.cpp @@ -305,7 +305,7 @@ void CGLDevice::SetLight(int index, const Light &light) if (light.type == LIGHT_SPOT) { - glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, light.spotAngle); + glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, light.spotAngle * Math::RAD_TO_DEG); glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, light.spotIntensity); } else diff --git a/src/object/object.cpp b/src/object/object.cpp index ec8b3c5a..77a7c250 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -2264,7 +2264,7 @@ bool CObject::CreateShadowLight(float height, Gfx::Color color) light.attenuation0 = 1.0f; light.attenuation1 = 0.0f; light.attenuation2 = 0.0f; - light.spotAngle = 90; + light.spotAngle = 90.0f*Math::PI/180.0f; m_shadowLight = m_lightMan->CreateLight(); if ( m_shadowLight == -1 ) return false; @@ -2307,7 +2307,7 @@ bool CObject::CreateEffectLight(float height, Gfx::Color color) light.attenuation0 = 1.0f; light.attenuation1 = 0.0f; light.attenuation2 = 0.0f; - light.spotAngle = 90; + light.spotAngle = 90.0f*Math::PI/180.0f; m_effectLight = m_lightMan->CreateLight(); if ( m_effectLight == -1 ) return false; diff --git a/src/object/task/taskbuild.cpp b/src/object/task/taskbuild.cpp index 469e9cb7..d82874c8 100644 --- a/src/object/task/taskbuild.cpp +++ b/src/object/task/taskbuild.cpp @@ -153,8 +153,7 @@ void CTaskBuild::CreateLight() light.attenuation0 = 1.0f; light.attenuation1 = 0.0f; light.attenuation2 = 0.0f; - //TODO Is this value correct - light.spotAngle = 90; + light.spotAngle = 90.0f*Math::PI/180.0f; m_lightMan->SetLight(m_lightRank[i], light); color.r = -1.0f; diff --git a/src/object/task/taskshield.cpp b/src/object/task/taskshield.cpp index 682bcb18..93afd621 100644 --- a/src/object/task/taskshield.cpp +++ b/src/object/task/taskshield.cpp @@ -499,7 +499,7 @@ bool CTaskShield::CreateLight(Math::Vector pos) light.attenuation0 = 1.0f; light.attenuation1 = 0.0f; light.attenuation2 = 0.0f; - light.spotAngle = 90; + light.spotAngle = 90.0f*Math::PI/180.0f; m_effectLight = m_lightMan->CreateLight(); if ( m_effectLight == -1 ) return false; From 703f03f31622b357b0951d5a631a987cb888aa25 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Wed, 3 Oct 2012 00:30:17 +0200 Subject: [PATCH 02/14] CPyro rewrite --- src/graphics/engine/pyro.cpp | 2323 +++++++++++++++++++++++++++++++++- src/graphics/engine/pyro.h | 105 +- 2 files changed, 2319 insertions(+), 109 deletions(-) diff --git a/src/graphics/engine/pyro.cpp b/src/graphics/engine/pyro.cpp index 04568aee..978471b0 100644 --- a/src/graphics/engine/pyro.cpp +++ b/src/graphics/engine/pyro.cpp @@ -20,6 +20,17 @@ #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/robotmain.h" +#include "object/motion/motionhuman.h" + +#include "ui/displaytext.h" + // Graphics module namespace namespace Gfx { @@ -27,158 +38,2350 @@ namespace Gfx { CPyro::CPyro(CInstanceManager* iMan) { - GetLogger()->Trace("CParticle::CPyro() stub!\n"); - // TODO! + m_iMan = iMan; + m_iMan->AddInstance(CLASS_PYRO, this, 100); + + m_engine = static_cast(m_iMan->SearchInstance(CLASS_ENGINE)); + m_terrain = static_cast(m_iMan->SearchInstance(CLASS_TERRAIN)); + m_camera = static_cast(m_iMan->SearchInstance(CLASS_CAMERA)); + m_particle = static_cast(m_iMan->SearchInstance(CLASS_PARTICULE)); + m_lightMan = static_cast(m_iMan->SearchInstance(CLASS_LIGHT)); + m_displayText = static_cast(m_iMan->SearchInstance(CLASS_DISPLAYTEXT)); + m_main = static_cast(m_iMan->SearchInstance(CLASS_MAIN)); + m_sound = static_cast(m_iMan->SearchInstance(CLASS_SOUND)); + m_object = 0; + + m_progress = 0.0f; + m_speed = 0.0f; + m_lightRank = -1; + m_soundChannel = -1; + LightOperFlush(); } CPyro::~CPyro() { - GetLogger()->Trace("CPyro::~CPyro() stub!"); - // TODO! + m_iMan->DeleteInstance(CLASS_PYRO, this); } -void CPyro::DeleteObject(bool all) +void CPyro::DeleteObject() { - GetLogger()->Trace("CPyro::DeleteObject() stub!"); - // TODO! + if ( m_lightRank != -1 ) + { + m_lightMan->DeleteLight(m_lightRank); + m_lightRank = -1; + } } -bool CPyro::Create(PyroType type, CObject* pObj, float force) +bool CPyro::Create(PyroType type, CObject* obj, float force) { - GetLogger()->Trace("CPyro::Create() stub!"); - // TODO! + 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(0); + + DisplayError(type, obj); // displays eventual messages + + int i = 0; + // Copies all spheres of the object. + for (; i < 50; i++) + { + if ( !obj->GetCrashSphere(i, m_crashSpherePos[i], m_crashSphereRadius[i]) ) break; + } + m_crashSphereUsed = i; + + // 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; + + if ( oType == OBJECT_TEEN28 || + oType == OBJECT_TEEN31 ) + { + m_pos.y = pos.y+1.0f; + } + + // Seeking the position of the battery. + CObject* power = obj->GetPower(); + if ( power == nullptr ) + { + m_power = false; + } + else + { + m_power = true; + pos = power->GetPosition(0); + 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 ) + { + Sound 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_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_object->SetPosition(0, m_object->GetResetPosition()); + m_object->SetAngle(0, m_object->GetResetAngle()); + m_object->SetZoom(0, 0.0f); + } + 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) || + (m_type == PT_EXPLOT && oType == OBJECT_TEEN28 ) || + (m_type == PT_EXPLOT && oType == OBJECT_TEEN31 ) ) + { + 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(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(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(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(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) { - GetLogger()->Trace("CPyro::EventProcess() stub!\n"); - // TODO! + 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 != 0) + { + Math::Vector pos = m_object->GetPosition(0); + 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_crashSphereUsed > 0 ) + { + int i = rand()%m_crashSphereUsed; + Math::Vector pos = m_crashSpherePos[i]; + pos.x += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + pos.z += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + Math::Vector speed; + speed.x = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.z = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.y = Math::Rand()*m_crashSphereRadius[i]*1.0f; + Math::Point dim; + dim.x = Math::Rand()*m_crashSphereRadius[i]*0.5f+m_crashSphereRadius[i]*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_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_type == PT_SHOTM && + m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time ) + { + m_lastParticle = m_time; + + int r = static_cast(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_crashSphereUsed > 0 ) + { + int i = rand()%m_crashSphereUsed; + Math::Vector pos = m_crashSpherePos[i]; + pos.x += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + pos.z += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + Math::Vector speed; + speed.x = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.z = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.y = Math::Rand()*m_crashSphereRadius[i]*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); + } + + Math::Vector angle = m_object->GetAngle(0); + 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(0, 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); + } + + Math::Vector angle = m_object->GetAngle(0); + 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); + } + + Math::Vector angle = m_object->GetAngle(0); + 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); + } + + Math::Vector angle = m_object->GetResetAngle(); + m_object->SetAngleY(0, angle.y-powf((1.0f-m_progress)*5.0f, 2.0f)); + m_object->SetZoom(0, m_progress); + } + + if ( m_type == PT_FINDING ) + { + if ( m_object != 0 && + 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 != 0 ) + { + 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(0); + 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(0); + 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(0); + 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 ) + { + if ( m_lastParticle+m_engine->ParticleAdapt(0.05f) <= m_time ) + { + m_lastParticle = m_time; + + Math::Vector pos = m_object->GetPosition(0); + 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(PARTITRACK7+rand()%4), + 3.0f, 20.0f, 1.0f, 0.4f); + } + } + + if ( m_type == PT_LOST ) + { + if ( m_lastParticle+m_engine->ParticleAdapt(0.10f) <= m_time ) + { + m_lastParticle = m_time; + + Math::Vector pos = m_object->GetPosition(0); + 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() { - GetLogger()->Trace("CPyro::IsEnded() stub!\n"); - // TODO! - return ERR_OK; + // 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->SetPosition(0, m_object->GetResetPosition()); + m_object->SetAngle(0, m_object->GetResetAngle()); + 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* pObj) +void CPyro::CutObjectLink(CObject* obj) { - GetLogger()->Trace("CPyro::CutObjectLink() stub!\n"); - // TODO! + if (m_object == obj) + m_object = nullptr; } -void CPyro::DisplayError(PyroType type, CObject* pObj) +void CPyro::DisplayError(PyroType type, CObject* obj) { - GetLogger()->Trace("CPyro::DisplayError() stub!\n"); - // TODO! + 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_displayText->DisplayError(err, obj->GetPosition(0), 5.0f); + return; + } + + if ( err != ERR_OK ) + { + m_displayText->DisplayError(err, obj); + } + } } -bool CPyro::CreateLight(Math::Vector pos, float height) +void CPyro::CreateLight(Math::Vector pos, float height) { - GetLogger()->Trace("CPyro::CreateLight() stub!\n"); - // TODO! - return true; + if (!m_engine->GetLightMode()) return; + + m_lightHeight = height; + + Gfx::Light light; + light.type = LIGHT_SPOT; + light.position.x = pos.x; + light.position.y = pos.y+height; + light.position.z = pos.z; + light.direction.x = 0.0f; + light.direction.y = -1.0f; // against the bottom + light.direction.z = 0.0f; + 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) { - GetLogger()->Trace("CPyro::DeleteObject() stub!\n"); - // TODO! + if (m_object == nullptr) return; + + if (m_object->GetResetCap() == RESET_MOVE) // resettable object? + { + m_object->SetEnable(false); // object cache and inactive + Math::Vector pos = m_object->GetPosition(0); + pos.y = -100.0f; + m_object->SetPosition(0, pos); + return; + } + + ObjectType type = m_object->GetType(); + if ( secondary && + type != OBJECT_FACTORY && + type != OBJECT_NUCLEAR && + type != OBJECT_ENERGY ) + { + CObject* sub = m_object->GetPower(); + if ( sub != 0 ) + { + sub->DeleteObject(); // removes the battery + delete sub; + m_object->SetPower(0); + } + + sub = m_object->GetFret(); + if ( sub != 0 ) + { + sub->DeleteObject(); // removes the object transported + delete sub; + m_object->SetFret(nullptr); + } + } + + if (primary) + { + CObject* truck = m_object->GetTruck(); + if ( truck != 0 ) // object carries? + { + if (truck->GetPower() == m_object) + truck->SetPower(nullptr); + + if (truck->GetFret() == m_object) + truck->SetFret(nullptr); + } + + CObject* sub = m_object; + sub->DeleteObject(); // removes the object (*) + delete sub; + m_object = nullptr; + } } -void CPyro::CreateTriangle(CObject* pObj, ObjectType oType, int part) +void CPyro::CreateTriangle(CObject* obj, ObjectType oType, int part) { - GetLogger()->Trace("CPyro::CreateTriangle() stub!\n"); - // TODO! + int objRank = obj->GetObjectRank(part); + if (objRank == -1) return; + + float min = 0.0f; + float max = m_engine->GetLimitLOD(0); + 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; + if ( oType == OBJECT_MOBILEtg ) percent = 0.50f; + if ( oType == OBJECT_TEEN28 ) percent = 0.75f; + if ( oType == OBJECT_MOTHER ) max = 1000000.0f; + if ( oType == OBJECT_TEEN28 ) max = 1000000.0f; + if ( oType == OBJECT_TEEN31 ) max = 1000000.0f; + + std::vector buffer; + total = m_engine->GetPartialTriangles(objRank, min, max, 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() { - GetLogger()->Trace("CPyro::ExploStart() stub!\n"); - // TODO! + m_burnType = m_object->GetType(); + + Math::Vector oPos = m_object->GetPosition(0); + m_burnFall = m_terrain->GetHeightToFloor(oPos, true); + + m_object->Simplify(); + m_object->SetLock(true); // ruin not usable yet + m_object->SetExplo(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; + m_engine->ChangeSecondTexture(objRank, "dirty04.tga"); + + Math::Vector pos = m_object->GetPosition(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("dirty04.png"); + + DeleteObject(false, true); // destroys the object transported + the battery } void CPyro::ExploTerminate() { - GetLogger()->Trace("CPyro::ExploTerminate() stub!\n"); - // TODO! + DeleteObject(true, false); // removes the main object } void CPyro::BurnStart() { - GetLogger()->Trace("CPyro::BurnStart() stub!\n"); - // TODO! + m_burnType = m_object->GetType(); + + Math::Vector oPos = m_object->GetPosition(0); + 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; + m_engine->ChangeSecondTexture(objRank, "dirty04.png"); + } + m_engine->LoadTexture("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 if ( m_burnType == OBJECT_TEEN31 ) // basket? + { + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.8f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*0.2f; + } + 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) { - GetLogger()->Trace("CPyro::BurnAddPart() stub!\n"); - // TODO! + int i = m_burnPartTotal; + m_burnPart[i].part = part; + m_burnPart[i].initialPos = m_object->GetPosition(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() { - GetLogger()->Trace("CPyro::BurnProgress() stub!\n"); - // TODO! + if ( m_burnType == OBJECT_TEEN31 ) // basket? + { + m_object->SetZoomY(0, 1.0f-m_progress*0.5f); // slight flattening + } + + 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; + } + m_object->SetPosition(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); + } + + CObject* sub = m_object->GetPower(); + if (sub != nullptr) // is there a battery? + sub->SetZoomY(0, 1.0f - m_progress); // complete flattening } bool CPyro::BurnIsKeepPart(int part) { - GetLogger()->Trace("CPyro::BurnIsKeepPart() stub!\n"); - // TODO! - return true; + int i = 0; + while (m_burnKeepPart[i] != -1) + { + if (part == m_burnKeepPart[i++]) return true; // must keep + } + return false; // must destroy } void CPyro::BurnTerminate() { - GetLogger()->Trace("CPyro::BurnTerminate() stub!\n"); - // TODO! + 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() { - GetLogger()->Trace("CPyro::FallStart() stub!\n"); - // TODO! + m_object->SetBurn(true); // usable + + Math::Vector pos = m_object->GetPosition(0); + m_fallFloor = m_terrain->GetFloorLevel(pos); + m_fallSpeed = 0.0f; + m_fallBulletTime = 0.0f; + m_fallEnding = false; } CObject* CPyro::FallSearchBeeExplo() { - GetLogger()->Trace("CPyro::FallSearchBeeExplo() stub!\n"); - // TODO! + Math::Vector iPos; + float iRadius; + m_object->GetCrashSphere(0, iPos, iRadius); + + for (int i = 0; i < 1000000; i++) + { + CObject* pObj = static_cast(m_iMan->SearchInstance(CLASS_OBJECT, i)); + if ( pObj == 0 ) break; + + ObjectType oType = pObj->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 ( pObj->GetTruck() != 0 ) continue; // object transported? + + Math::Vector oPos = pObj->GetPosition(0); + + float distance; + + float shieldRadius = pObj->GetShieldRadius(); + if ( shieldRadius > 0.0f ) + { + distance = Math::Distance(oPos, iPos); + if (distance <= shieldRadius) return pObj; + } + + if ( oType == OBJECT_BASE ) + { + distance = Math::Distance(oPos, iPos); + if (distance < 25.0f) return pObj; + } + + // Test the center of the object, which is necessary for objects + // that have no sphere in the center (station). + distance = Math::Distance(oPos, iPos)-4.0f; + if (distance < 5.0f) return pObj; + + // Test with all spheres of the object. + Math::Vector ooPos; + float ooRadius; + int j = 0; + while (pObj->GetCrashSphere(j++, ooPos, ooRadius)) + { + distance = Math::Distance(ooPos, iPos); + if (distance <= iRadius+ooRadius) + { + return pObj; + } + } + } + return nullptr; } void CPyro::FallProgress(float rTime) { - GetLogger()->Trace("CPyro::FallProgress() stub!\n"); - // TODO! + if (m_object == nullptr) return; + + m_fallSpeed += rTime*50.0f; // v2 = v1 + a*dt + Math::Vector pos; + pos = m_object->GetPosition(0); + 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(0, 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->ExploObject(EXPLO_BOUM, 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->ExploObject(EXPLO_BOUM, 1.0f)) // start explosion + { + DeleteObject(true, true); // removes the ball + } + else + { + m_object->ExploObject(EXPLO_BOUM, 0.0f); // start explosion + } + } + } + + if (floor || obj != nullptr) + { + m_fallEnding = true; + } + } + } } Error CPyro::FallIsEnded() { - GetLogger()->Trace("CPyro::FallIsEnded() stub!\n"); - // TODO! - return ERR_OK; + if (m_fallEnding || m_object == 0) return ERR_STOP; + + Math::Vector pos = m_object->GetPosition(0); + 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() { - GetLogger()->Trace("CPyro::LightOperFlush() stub!\n"); - // TODO! + m_lightOperTotal = 0; } void CPyro::LightOperAdd(float progress, float intensity, float r, float g, float b) { - GetLogger()->Trace("CPyro::LightOperAdd() stub!\n"); - // TODO! + 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) { - GetLogger()->Trace("CPyro::LightOperFrame() stub!\n"); - // TODO! + for (int i = 0; i < m_lightOperTotal; i++) + { + if ( m_progress < m_lightOper[i].progress ) + { + 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; + } + } } diff --git a/src/graphics/engine/pyro.h b/src/graphics/engine/pyro.h index d91b0497..916cae26 100644 --- a/src/graphics/engine/pyro.h +++ b/src/graphics/engine/pyro.h @@ -33,10 +33,13 @@ class CInstanceManager; class CObject; -class CDisplayText; class CRobotMain; class CSoundInterface; +namespace Ui { +class CDisplayText; +} + // Graphics module namespace namespace Gfx { @@ -48,33 +51,37 @@ class CParticle; class CLight; +/** + * \enum PyroType + * \brief Type of pyro effect + */ enum PyroType { PT_NULL = 0, - PT_FRAGT = 1, // fragmentation of technical object - PT_FRAGO = 2, // fragmentation of organic object - PT_FRAGW = 4, // fragmentation of object under water - PT_EXPLOT = 5, // explosion of technical object - PT_EXPLOO = 6, // explosion of organic object - PT_EXPLOW = 8, // explosion of object under water - PT_SHOTT = 9, // hit technical object - PT_SHOTH = 10, // hit human - PT_SHOTM = 11, // hit queen - PT_SHOTW = 12, // hit under water - PT_EGG = 13, // break the egg - PT_BURNT = 14, // burning of technical object - PT_BURNO = 15, // burning of organic object - PT_SPIDER = 16, // spider explosion - PT_FALL = 17, // cargo falling - PT_WPCHECK = 18, // indicator reaches - PT_FLCREATE = 19, // flag create - PT_FLDELETE = 20, // flag destroy - PT_RESET = 21, // reset position of the object - PT_WIN = 22, // fireworks - PT_LOST = 23, // black smoke - PT_DEADG = 24, // shooting death - PT_DEADW = 25, // drowning death - PT_FINDING = 26, // object discovered + PT_FRAGT = 1, //! < fragmentation of technical object + PT_FRAGO = 2, //! < fragmentation of organic object + PT_FRAGW = 4, //! < fragmentation of object under water + PT_EXPLOT = 5, //! < explosion of technical object + PT_EXPLOO = 6, //! < explosion of organic object + PT_EXPLOW = 8, //! < explosion of object under water + PT_SHOTT = 9, //! < hit technical object + PT_SHOTH = 10, //! < hit human + PT_SHOTM = 11, //! < hit queen + PT_SHOTW = 12, //! < hit under water + PT_EGG = 13, //! < break the egg + PT_BURNT = 14, //! < burning of technical object + PT_BURNO = 15, //! < burning of organic object + PT_SPIDER = 16, //! < spider explosion + PT_FALL = 17, //! < cargo falling + PT_WPCHECK = 18, //! < indicator reaches + PT_FLCREATE = 19, //! < flag create + PT_FLDELETE = 20, //! < flag destroy + PT_RESET = 21, //! < reset position of the object + PT_WIN = 22, //! < fireworks + PT_LOST = 23, //! < black smoke + PT_DEADG = 24, //! < shooting death + PT_DEADW = 25, //! < drowning death + PT_FINDING = 26, //! < object discovered }; @@ -89,8 +96,8 @@ struct PyroBurnPart struct PyroLightOper { - float progress; - float intensity; + float progress; + float intensity; Color color; }; @@ -107,18 +114,18 @@ public: CPyro(CInstanceManager* iMan); ~CPyro(); - void DeleteObject(bool all=false); - bool Create(PyroType type, CObject* pObj, float force=1.0f); - bool EventProcess(const Event &event); + void DeleteObject(); + bool Create(PyroType type, CObject* obj, float force=1.0f); + bool EventProcess(const Event& event); Error IsEnded(); - void CutObjectLink(CObject* pObj); + void CutObjectLink(CObject* obj); protected: - void DisplayError(PyroType type, CObject* pObj); - bool CreateLight(Math::Vector pos, float height); + void DisplayError(PyroType type, CObject* obj); + void CreateLight(Math::Vector pos, float height); void DeleteObject(bool primary, bool secondary); - void CreateTriangle(CObject* pObj, ObjectType oType, int part); + void CreateTriangle(CObject* obj, ObjectType type, int part); void ExploStart(); void ExploTerminate(); @@ -139,38 +146,38 @@ protected: void LightOperFrame(float rTime); protected: - CInstanceManager* m_iMan; - CEngine* m_engine; - CTerrain* m_terrain; - CCamera* m_camera; - CParticle* m_particule; - CLightManager* m_lightMan; - CObject* m_object; - CDisplayText* m_displayText; - CRobotMain* m_main; - CSoundInterface* m_sound; + CInstanceManager* m_iMan; + CEngine* m_engine; + CTerrain* m_terrain; + CCamera* m_camera; + CParticle* m_particle; + CLightManager* m_lightMan; + CObject* m_object; + Ui::CDisplayText* m_displayText; + CRobotMain* m_main; + CSoundInterface* m_sound; Math::Vector m_pos; // center of the effect Math::Vector m_posPower; // center of the battery bool m_power; // battery exists? - PyroType m_type; + PyroType m_type; float m_force; float m_size; float m_progress; float m_speed; float m_time; - float m_lastParticule; - float m_lastParticuleSmoke; + float m_lastParticle; + float m_lastParticleSmoke; int m_soundChannel; int m_lightRank; int m_lightOperTotal; - PyroLightOper m_lightOper[10]; + PyroLightOper m_lightOper[10]; float m_lightHeight; ObjectType m_burnType; int m_burnPartTotal; - PyroBurnPart m_burnPart[10]; + PyroBurnPart m_burnPart[10]; int m_burnKeepPart[10]; float m_burnFall; From 37302a2504811bf410b2485dbf65d5dedd8ba164 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Fri, 5 Oct 2012 15:26:24 +0200 Subject: [PATCH 03/14] CLightning rewrite --- src/graphics/engine/lightning.cpp | 375 +++++++++++++++++++++++++++--- src/graphics/engine/lightning.h | 58 +++-- src/object/object.cpp | 4 +- 3 files changed, 387 insertions(+), 50 deletions(-) diff --git a/src/graphics/engine/lightning.cpp b/src/graphics/engine/lightning.cpp index 1b9cbf10..337d5787 100644 --- a/src/graphics/engine/lightning.cpp +++ b/src/graphics/engine/lightning.cpp @@ -19,6 +19,17 @@ #include "graphics/engine/lightning.h" #include "common/logger.h" +#include "common/iman.h" + +#include "graphics/core/device.h" +#include "graphics/engine/camera.h" +#include "graphics/engine/terrain.h" + +#include "object/object.h" + +#include "object/auto/autopara.h" + +#include "math/geometry.h" // Graphics module namespace @@ -27,68 +38,380 @@ namespace Gfx { CLightning::CLightning(CInstanceManager* iMan, CEngine* engine) { - GetLogger()->Trace("CLightning::CLightning() stub!\n"); - // TODO! + m_iMan = iMan; + m_iMan->AddInstance(CLASS_BLITZ, this); + + m_engine = engine; + m_terrain = nullptr; + m_camera = nullptr; + m_sound = nullptr; + + Flush(); } CLightning::~CLightning() { - GetLogger()->Trace("CLightning::~CLightning() stub!\n"); - // TODO! } void CLightning::Flush() { - GetLogger()->Trace("CLightning::Flush() stub!\n"); - // TODO! + m_lightningExists = false; + m_phase = LP_WAIT; + m_speed = 0.0f; + m_progress = 0.0f; + + for (int i = 0; i < FLASH_SEGMENTS; i++) + { + m_shift[i] = Math::Point(0.0f, 0.0f); + m_width[i] = 1.0f; + } } bool CLightning::EventProcess(const Event &event) { - GetLogger()->Trace("CLightning::EventProcess() stub!\n"); - // TODO! + if (event.type == EVENT_FRAME) + return EventFrame(event); + + return true; +} + +bool CLightning::EventFrame(const Event &event) +{ + if (m_engine->GetPause()) return true; + if (m_engine->GetMovieLock()) return true; + + m_progress += event.rTime*m_speed; + + if (m_phase == LP_WAIT) + { + if (m_progress >= 1.0f) + { + + m_pos.x = (Math::Rand()-0.5f)*(3200.0f-200.0f); + m_pos.z = (Math::Rand()-0.5f)*(3200.0f-200.0f); + m_pos.y = 0.0f; + + CObject* obj = SearchObject(m_pos); + if (obj == nullptr) + { + m_terrain->AdjustToFloor(m_pos, true); + } + else + { + m_pos = obj->GetPosition(0); + m_terrain->AdjustToFloor(m_pos, true); + + ObjectType type = obj->GetType(); + if (type == OBJECT_BASE) + { + m_pos.y += 120.0f; // top of the rocket + } + else if (type == OBJECT_PARA) + { + CAutoPara* automat = dynamic_cast(obj->GetAuto()); + if (automat != nullptr) + automat->StartLightning(); + + m_pos.y += 67.0f; // top of lightning rod + } + else + { + obj->ExploObject(EXPLO_BOUM, 1.0f); + } + } + + Math::Vector eye = m_engine->GetEyePt(); + float dist = Math::Distance(m_pos, eye); + float deep = m_engine->GetDeepView(); + + if (dist < deep) + { + Math::Vector pos = eye+((m_pos-eye)*0.2f); // like so close! + m_sound->Play(SOUND_BLITZ, pos); + + m_camera->StartOver(CAM_OVER_EFFECT_LIGHTNING, m_pos, 1.0f); + + m_phase = LP_FLASH; + m_progress = 0.0f; + m_speed = 1.0f; + } + } + } + + if (m_phase == LP_FLASH) + { + if (m_progress < 1.0f) + { + float max = 5.0f; + for (int i = 0; i < FLASH_SEGMENTS; i++) + { + max += 0.4f; + + m_shift[i].x += (Math::Rand()-0.5f)*max*2.0f; + if ( m_shift[i].x < -max ) m_shift[i].x = -max; + if ( m_shift[i].x > max ) m_shift[i].x = max; + + m_shift[i].y += (Math::Rand()-0.5f)*max*2.0f; + if ( m_shift[i].y < -max ) m_shift[i].y = -max; + if ( m_shift[i].y > max ) m_shift[i].y = max; + + m_width[i] += (Math::Rand()-0.5f)*2.0f; + if ( m_width[i] < 1.0f ) m_width[i] = 1.0f; + if ( m_width[i] > 6.0f ) m_width[i] = 6.0f; + } + m_shift[0].x = 0.0f; + m_shift[0].y = 0.0f; + m_width[0] = 0.0f; + } + else + { + m_phase = LP_WAIT; + m_progress = 0.0f; + m_speed = 1.0f / (1.0f+Math::Rand()*m_delay); + } + } + return true; } bool CLightning::Create(float sleep, float delay, float magnetic) { - GetLogger()->Trace("CLightning::Create() stub!\n"); - // TODO! - return true; + m_lightningExists = true; + if (sleep < 1.0f) sleep = 1.0f; + m_sleep = sleep; + m_delay = delay; + m_magnetic = magnetic; + + m_phase = LP_WAIT; + m_progress = 0.0f; + m_speed = 1.0f / m_sleep; + + if (m_terrain == nullptr) + m_terrain = static_cast(m_iMan->SearchInstance(CLASS_TERRAIN)); + + if (m_camera == nullptr) + m_camera = static_cast(m_iMan->SearchInstance(CLASS_CAMERA)); + + if (m_sound == nullptr) + m_sound = static_cast(m_iMan->SearchInstance(CLASS_SOUND)); + + return false; } bool CLightning::GetStatus(float &sleep, float &delay, float &magnetic, float &progress) { - GetLogger()->Trace("CLightning::GetStatus() stub!\n"); - // TODO! + if (! m_lightningExists) return false; + + sleep = m_sleep; + delay = m_delay; + magnetic = m_magnetic; + progress = m_progress; + return true; } bool CLightning::SetStatus(float sleep, float delay, float magnetic, float progress) { - GetLogger()->Trace("CLightning::SetStatus() stub!\n"); - // TODO! + m_lightningExists = true; + + m_sleep = sleep; + m_delay = delay; + m_magnetic = magnetic; + m_progress = progress; + m_phase = LP_WAIT; + m_speed = 1.0f/m_sleep; + return true; } void CLightning::Draw() { - GetLogger()->Trace("CLightning::Draw() stub!\n"); - // TODO! -} + if (!m_lightningExists) return; + if (m_phase != LP_FLASH) return; -bool CLightning::EventFrame(const Event &event) -{ - GetLogger()->Trace("CLightning::EventFrame() stub!\n"); - // TODO! - return true; + CDevice* device = m_engine->GetDevice(); + + Math::Matrix mat; + mat.LoadIdentity(); + device->SetTransform(TRANSFORM_WORLD, mat); + + m_engine->SetTexture("effect00.png"); + m_engine->SetState(ENG_RSTATE_TTEXTURE_BLACK); + + Math::Point texInf; + texInf.x = 64.5f/256.0f; + texInf.y = 33.0f/256.0f; + Math::Point texSup; + texSup.x = 95.5f/256.0f; + texSup.y = 34.0f/256.0f; // blank + + Math::Vector p1 = m_pos; + Math::Vector eye = m_engine->GetEyePt(); + float a = Math::RotateAngle(eye.x-p1.x, eye.z-p1.z); + Math::Vector n = Math::Normalize(p1-eye); + + Math::Vector corner[4]; + Vertex vertex[4]; + + for (int i = 0; i < FLASH_SEGMENTS-1; i++) + { + Math::Vector p2 = p1; + p2.y += 8.0f+0.2f*i; + + Math::Point rot; + + Math::Vector p = p1; + p.x += m_width[i]; + rot = Math::RotatePoint(Math::Point(p1.x, p1.z), a+Math::PI/2.0f, Math::Point(p.x, p.z)); + corner[0].x = rot.x+m_shift[i].x; + corner[0].y = p1.y; + corner[0].z = rot.y+m_shift[i].y; + rot = Math::RotatePoint(Math::Point(p1.x, p1.z), a-Math::PI/2.0f, Math::Point(p.x, p.z)); + corner[1].x = rot.x+m_shift[i].x; + corner[1].y = p1.y; + corner[1].z = rot.y+m_shift[i].y; + + p = p2; + p.x += m_width[i+1]; + rot = Math::RotatePoint(Math::Point(p2.x, p2.z), a+Math::PI/2.0f, Math::Point(p.x, p.z)); + corner[2].x = rot.x+m_shift[i+1].x; + corner[2].y = p2.y; + corner[2].z = rot.y+m_shift[i+1].y; + rot = Math::RotatePoint(Math::Point(p2.x, p2.z), a-Math::PI/2.0f, Math::Point(p.x, p.z)); + corner[3].x = rot.x+m_shift[i+1].x; + corner[3].y = p2.y; + corner[3].z = rot.y+m_shift[i+1].y; + + if (p2.y < p1.y) + { + vertex[0] = Vertex(corner[1], n, Math::Point(texSup.x, texSup.y)); + vertex[1] = Vertex(corner[0], n, Math::Point(texInf.x, texSup.y)); + vertex[2] = Vertex(corner[3], n, Math::Point(texSup.x, texInf.y)); + vertex[3] = Vertex(corner[2], n, Math::Point(texInf.x, texInf.y)); + } + else + { + vertex[0] = Vertex(corner[0], n, Math::Point(texSup.x, texSup.y)); + vertex[1] = Vertex(corner[1], n, Math::Point(texInf.x, texSup.y)); + vertex[2] = Vertex(corner[2], n, Math::Point(texSup.x, texInf.y)); + vertex[3] = Vertex(corner[3], n, Math::Point(texInf.x, texInf.y)); + } + + device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); + m_engine->AddStatisticTriangle(2); + + p1 = p2; + } } CObject* CLightning::SearchObject(Math::Vector pos) { - GetLogger()->Trace("CLightning::SearchObject() stub!\n"); - // TODO! - return nullptr; + // Lightning conductors + std::vector paraObj; + paraObj.reserve(100); + std::vector paraObjPos; + paraObjPos.reserve(100); + + // Seeking the object closest to the point of impact of lightning. + CObject* bestObj = 0; + float min = 100000.0f; + for (int i = 0; i < 1000000; i++) + { + CObject* obj = static_cast( m_iMan->SearchInstance(CLASS_OBJECT, i) ); + if (obj == nullptr) break; + + if (!obj->GetActif()) continue; // inactive object? + if (obj->GetTruck() != nullptr) continue; // object transported? + + ObjectType type = obj->GetType(); + if ( type == OBJECT_BASE || + type == OBJECT_PARA ) // building a lightning effect? + { + paraObj.push_back(obj); + paraObjPos.push_back(obj->GetPosition(0)); + } + + float detect = 0.0f; + if ( type == OBJECT_BASE || + type == OBJECT_DERRICK || + type == OBJECT_FACTORY || + type == OBJECT_REPAIR || + type == OBJECT_DESTROYER|| + type == OBJECT_STATION || + type == OBJECT_CONVERT || + type == OBJECT_TOWER || + type == OBJECT_RESEARCH || + type == OBJECT_RADAR || + type == OBJECT_INFO || + type == OBJECT_ENERGY || + type == OBJECT_LABO || + type == OBJECT_NUCLEAR || + type == OBJECT_PARA || + type == OBJECT_SAFE || + type == OBJECT_HUSTON ) + { + detect = m_magnetic; + } + if ( type == OBJECT_METAL || + type == OBJECT_POWER || + type == OBJECT_ATOMIC ) + { + detect = m_magnetic*0.3f; + } + if ( type == OBJECT_MOBILEfa || + type == OBJECT_MOBILEta || + type == OBJECT_MOBILEwa || + type == OBJECT_MOBILEia || + type == OBJECT_MOBILEfc || + type == OBJECT_MOBILEtc || + type == OBJECT_MOBILEwc || + type == OBJECT_MOBILEic || + type == OBJECT_MOBILEfi || + type == OBJECT_MOBILEti || + type == OBJECT_MOBILEwi || + type == OBJECT_MOBILEii || + type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEts || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEis || + type == OBJECT_MOBILErt || + type == OBJECT_MOBILErc || + type == OBJECT_MOBILErr || + type == OBJECT_MOBILErs || + type == OBJECT_MOBILEsa || + type == OBJECT_MOBILEft || + type == OBJECT_MOBILEtt || + type == OBJECT_MOBILEwt || + type == OBJECT_MOBILEit || + type == OBJECT_MOBILEdr ) + { + detect = m_magnetic*0.5f; + } + if (detect == 0.0f) continue; + + Math::Vector oPos = obj->GetPosition(0); + float dist = Math::DistanceProjected(oPos, pos); + if (dist > detect) continue; + if (dist < min) + { + min = dist; + bestObj = obj; + } + } + + if (bestObj == nullptr) + return nullptr; // nothing found + + // Under the protection of a lightning conductor? + Math::Vector oPos = bestObj->GetPosition(0); + for (int i = paraObj.size()-1; i >= 0; i--) + { + float dist = Math::DistanceProjected(oPos, paraObjPos[i]); + if (dist <= LTNG_PROTECTION_RADIUS) + return paraObj[i]; + } + + return bestObj; } diff --git a/src/graphics/engine/lightning.h b/src/graphics/engine/lightning.h index d873c64f..b21f6812 100644 --- a/src/graphics/engine/lightning.h +++ b/src/graphics/engine/lightning.h @@ -30,7 +30,7 @@ class CInstanceManager; class CObject; -class CSound; +class CSoundInterface; // Graphics module namespace @@ -40,21 +40,15 @@ class CEngine; class CTerrain; class CCamera; +//! Radius of lightning protection +const float LTNG_PROTECTION_RADIUS = 200.0f; -const float BLITZPARA = 200.0f; // radius of lightning protection -const short BLITZMAX = 50; - -enum BlitzPhase -{ - BPH_WAIT, - BPH_BLITZ, -}; /** * \class CLightning * \brief Lightning effect renderer * - * Functions are only stubs for now. + * TODO: documentation */ class CLightning { @@ -62,35 +56,55 @@ public: CLightning(CInstanceManager* iMan, CEngine* engine); ~CLightning(); - void Flush(); - bool EventProcess(const Event &event); + //! Triggers lightning bool Create(float sleep, float delay, float magnetic); + + //! Removes lightning + void Flush(); + + //! Gives the status of lightning bool GetStatus(float &sleep, float &delay, float &magnetic, float &progress); + //! Specifies the status of lightning bool SetStatus(float sleep, float delay, float magnetic, float progress); + + //! Management of an event + bool EventProcess(const Event &event); + + //! Draws lightning void Draw(); protected: + //! Updates lightning bool EventFrame(const Event &event); + //! Seeks for the object closest to the lightning CObject* SearchObject(Math::Vector pos); protected: - CInstanceManager* m_iMan; - CEngine* m_engine; - CTerrain* m_terrain; - CCamera* m_camera; - CSound* m_sound; + CInstanceManager* m_iMan; + CEngine* m_engine; + CTerrain* m_terrain; + CCamera* m_camera; + CSoundInterface* m_sound; - bool m_bBlitzExist; + bool m_lightningExists; float m_sleep; float m_delay; float m_magnetic; - BlitzPhase m_phase; - float m_time; + float m_speed; float m_progress; Math::Vector m_pos; - Math::Point m_shift[BLITZMAX]; - float m_width[BLITZMAX]; + + enum LightningPhase + { + LP_WAIT, + LP_FLASH, + }; + LightningPhase m_phase; + + static const short FLASH_SEGMENTS = 50; + Math::Point m_shift[FLASH_SEGMENTS]; + float m_width[FLASH_SEGMENTS]; }; diff --git a/src/object/object.cpp b/src/object/object.cpp index 77a7c250..5a1631f3 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -2995,7 +2995,7 @@ bool CObject::CreateBuilding(Math::Vector pos, float angle, float height, m_character.posPower = Math::Vector(5.0f, 3.0f, 0.0f); CreateShadowCircle(6.0f, 1.0f); - m_showLimitRadius = Gfx::BLITZPARA; + m_showLimitRadius = Gfx::LTNG_PROTECTION_RADIUS; } if ( m_type == OBJECT_NUCLEAR ) @@ -3048,7 +3048,7 @@ bool CObject::CreateBuilding(Math::Vector pos, float angle, float height, SetGlobalSphere(Math::Vector(0.0f, 10.0f, 0.0f), 20.0f); CreateShadowCircle(21.0f, 1.0f); - m_showLimitRadius = Gfx::BLITZPARA; + m_showLimitRadius = Gfx::LTNG_PROTECTION_RADIUS; } if ( m_type == OBJECT_SAFE ) From ff99b74b25c34b721f507da18b0b6d26a41b670a Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Fri, 5 Oct 2012 18:59:03 +0200 Subject: [PATCH 04/14] Some CPyro docs --- src/graphics/engine/pyro.h | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/graphics/engine/pyro.h b/src/graphics/engine/pyro.h index 916cae26..0204070c 100644 --- a/src/graphics/engine/pyro.h +++ b/src/graphics/engine/pyro.h @@ -106,7 +106,7 @@ struct PyroLightOper * \class CPyro * \brief Fire effect renderer * - * Functions are only stubs for now. + * TODO: documentation */ class CPyro { @@ -114,35 +114,63 @@ public: CPyro(CInstanceManager* iMan); ~CPyro(); - void DeleteObject(); + //! Creates pyrotechnic effect bool Create(PyroType type, CObject* obj, float force=1.0f); - bool EventProcess(const Event& event); + //! Destroys the object + void DeleteObject(); + + //! Indicates whether the pyrotechnic effect is complete Error IsEnded(); + + //! Indicates that the object binds to the effect no longer exists, without deleting it void CutObjectLink(CObject* obj); + //! Management of an event + bool EventProcess(const Event& event); + protected: + //! Displays the error or eventual information + //! Information can be linked to the destruction of an insect, a vehicle or building void DisplayError(PyroType type, CObject* obj); + + //! Creates light to accompany a pyrotechnic effect void CreateLight(Math::Vector pos, float height); + //! Removes the binding to a pyrotechnic effect void DeleteObject(bool primary, bool secondary); + //! Creates an explosion with triangular form of particles void CreateTriangle(CObject* obj, ObjectType type, int part); + //! Starts the explosion of a vehicle void ExploStart(); + //! Ends the explosion of a vehicle void ExploTerminate(); + //! Starts a vehicle fire void BurnStart(); + //! Adds a part move void BurnAddPart(int part, Math::Vector pos, Math::Vector angle); + //! Advances of a vehicle fire void BurnProgress(); + //! Indicates whether a part should be retained bool BurnIsKeepPart(int part); + //! Ends the fire of an insect or a vehicle void BurnTerminate(); + //! Start of an object freight falling void FallStart(); + //! Seeks an object to explode by the falling ball of bees CObject* FallSearchBeeExplo(); + //! Fall of an object's freight void FallProgress(float rTime); + //! Indicates whether the fall is over Error FallIsEnded(); + //! Empty the table of operations of animation of light void LightOperFlush(); + //! Adds an animation operation of the light void LightOperAdd(float progress, float intensity, float r, float g, float b); + //! Updates the associated light void LightOperFrame(float rTime); protected: From 6fdaf5de46b8ab29cfb67d49661a63fff5a6995a Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Fri, 5 Oct 2012 18:59:49 +0200 Subject: [PATCH 05/14] CParticle rewrite --- src/graphics/core/color.h | 8 + src/graphics/engine/engine.cpp | 1 + src/graphics/engine/engine.h | 3 - src/graphics/engine/particle.cpp | 3978 ++++++++++++++++++++++++++++-- src/graphics/engine/particle.h | 353 +-- 5 files changed, 4000 insertions(+), 343 deletions(-) diff --git a/src/graphics/core/color.h b/src/graphics/core/color.h index 0bec7e93..7cbd1750 100644 --- a/src/graphics/core/color.h +++ b/src/graphics/core/color.h @@ -107,6 +107,14 @@ inline IntColor ColorToIntColor(Color color) static_cast(color.a * 255.0f)); } +inline Color IntensityToColor(float intensity) +{ + if (intensity <= 0.0f) return Color(0.0f, 0.0f, 0.0f, 0.0f); + if (intensity >= 1.0f) return Color(1.0f, 1.0f, 1.0f, 1.0f); + + return Color(intensity, intensity, intensity, intensity); +} + /** * \struct ColorHSV * \brief HSV color diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index f3eb1dca..3365b24d 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -272,6 +272,7 @@ bool CEngine::Create() m_planet = new CPlanet(m_iMan, this); m_lightMan->SetDevice(m_device); + m_particle->SetDevice(m_device); m_text->SetDevice(m_device); if (! m_text->Create()) diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 14a40dbc..27f01736 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -961,9 +961,6 @@ public: bool GetFog(); //@} - //! Indicates whether it is possible to give a color SetState - bool GetStateColor(); - //@{ //! Management of the global mode of secondary texturing void SetSecondTexture(int texNum); diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp index 9d3d0840..acc40df0 100644 --- a/src/graphics/engine/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -20,289 +20,3897 @@ #include "common/logger.h" +#include "graphics/core/device.h" +#include "graphics/engine/engine.h" +#include "graphics/engine/terrain.h" +#include "graphics/engine/water.h" + +#include "math/geometry.h" + +#include "object/object.h" +#include "object/robotmain.h" + +#include + // Graphics module namespace namespace Gfx { -CParticle::CParticle(CInstanceManager* iMan, CEngine* engine) +const float FOG_HSUP = 10.0f; +const float FOG_HINF = 100.0f; + + + + +//! Check if an object can be destroyed, but is not an enemy +bool IsSoft(ObjectType type) { - GetLogger()->Trace("CParticle::CParticle() stub!\n"); - // TODO! + return ( type == OBJECT_HUMAN || + type == OBJECT_MOBILEfa || + type == OBJECT_MOBILEta || + type == OBJECT_MOBILEwa || + type == OBJECT_MOBILEia || + type == OBJECT_MOBILEfc || + type == OBJECT_MOBILEtc || + type == OBJECT_MOBILEwc || + type == OBJECT_MOBILEic || + type == OBJECT_MOBILEfi || + type == OBJECT_MOBILEti || + type == OBJECT_MOBILEwi || + type == OBJECT_MOBILEii || + type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEts || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEis || + type == OBJECT_MOBILErt || + type == OBJECT_MOBILErc || + type == OBJECT_MOBILErr || + type == OBJECT_MOBILErs || + type == OBJECT_MOBILEsa || + type == OBJECT_MOBILEft || + type == OBJECT_MOBILEtt || + type == OBJECT_MOBILEwt || + type == OBJECT_MOBILEit || + type == OBJECT_MOBILEdr || // robot? + type == OBJECT_METAL || + type == OBJECT_POWER || + type == OBJECT_ATOMIC || // cargo? + type == OBJECT_DERRICK || + type == OBJECT_STATION || + type == OBJECT_FACTORY || + type == OBJECT_REPAIR || + type == OBJECT_DESTROYER|| + type == OBJECT_CONVERT || + type == OBJECT_TOWER || + type == OBJECT_RESEARCH || + type == OBJECT_RADAR || + type == OBJECT_INFO || + type == OBJECT_ENERGY || + type == OBJECT_LABO || + type == OBJECT_NUCLEAR || + type == OBJECT_PARA ); // building? +} + +//! Check if an object is a destroyable enemy +bool IsAlien(ObjectType type) +{ + return ( type == OBJECT_ANT || + type == OBJECT_SPIDER || + type == OBJECT_BEE || + type == OBJECT_WORM || + type == OBJECT_MOTHER || + type == OBJECT_NEST || + type == OBJECT_BULLET || + type == OBJECT_EGG || + type == OBJECT_MOBILEtg || + type == OBJECT_TEEN28 || + type == OBJECT_TEEN31 ); +} + +//! Returns the damping factor for friendly fire +float GetDecay(ObjectType type) +{ + if (IsSoft(type)) return 0.2f; + return 1.0f; +} + + + +CParticle::CParticle(CInstanceManager *iMan, CEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_PARTICULE, this); + + m_device = nullptr; + m_engine = engine; + m_main = nullptr; + m_terrain = nullptr; + m_water = nullptr; + m_sound = nullptr; + m_uniqueStamp = 0; + m_exploGunCounter = 0; + m_lastTimeGunDel = 0.0f; + m_absTime = 0.0f; + + FlushParticle(); } CParticle::~CParticle() { - GetLogger()->Trace("CParticle::~CParticle() stub!\n"); - // TODO! + m_iMan->DeleteInstance(CLASS_PARTICULE, this); } void CParticle::SetDevice(CDevice* device) { - GetLogger()->Trace("CParticle::SetDevice() stub!\n"); - // TODO! + m_device = device; } void CParticle::FlushParticle() { - GetLogger()->Trace("CParticle::FlushParticle() stub!\n"); - // TODO! + for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++) + m_particle[i].used = false; + + for (int i = 0; i < MAXPARTITYPE; i++) + { + for (int j = 0; j < SH_MAX; j++) + { + m_totalInterface[i][j] = 0; + } + } + + for (int i = 0; i < MAXTRACK; i++) + m_track[i].used = false; + + m_wheelTraceTotal = 0; + m_wheelTraceIndex = 0; + + for (int i = 0; i < SH_MAX; i++) + m_frameUpdate[i] = true; + + m_fogTotal = 0; + m_exploGunCounter = 0; } void CParticle::FlushParticle(int sheet) { - GetLogger()->Trace("CParticle::FlushParticle() stub!\n"); - // TODO! + for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++) + { + if (!m_particle[i].used) continue; + if (m_particle[i].sheet != sheet) continue; + + m_particle[i].used = false; + } + + for (int i = 0; i < MAXPARTITYPE; i++) + m_totalInterface[i][sheet] = 0; + + for (int i = 0; i < MAXTRACK; i++) + m_track[i].used = false; + + if (sheet == SH_WORLD) + { + m_wheelTraceTotal = 0; + m_wheelTraceIndex = 0; + } } + +//! Returns file name of the effect effectNN.png, with NN = number +void NameParticle(std::string &name, int num) +{ + if (num == 1) name = "effect00.png"; + else if (num == 2) name = "effect01.png"; + else if (num == 3) name = "effect02.png"; + else if (num == 4) name = "text.png"; + else name = ""; +} + +/** Returns the channel of the particle created or -1 on error. */ int CParticle::CreateParticle(Math::Vector pos, Math::Vector speed, Math::Point dim, - ParticleType type, float duration, float mass, - float windSensitivity, int sheet) + ParticleType type, + float duration, float mass, + float windSensitivity, int sheet) { - GetLogger()->Trace("CParticle::CreateParticle() stub!\n"); - // TODO! - return 0; + if (m_main == nullptr) + m_main = static_cast(m_iMan->SearchInstance(CLASS_MAIN)); + + int t = -1; + if ( type == PARTIEXPLOT || + type == PARTIEXPLOO || + type == PARTIMOTOR || + type == PARTIBLITZ || + type == PARTICRASH || + type == PARTIVAPOR || + type == PARTIGAS || + type == PARTIBASE || + type == PARTIFIRE || + type == PARTIFIREZ || + type == PARTIBLUE || + type == PARTIROOT || + type == PARTIRECOVER || + type == PARTIEJECT || + type == PARTISCRAPS || + type == PARTIGUN2 || + type == PARTIGUN3 || + type == PARTIGUN4 || + type == PARTIQUEUE || + type == PARTIORGANIC1 || + type == PARTIORGANIC2 || + type == PARTIFLAME || + type == PARTIBUBBLE || + type == PARTIERROR || + type == PARTIWARNING || + type == PARTIINFO || + type == PARTISPHERE1 || + type == PARTISPHERE2 || + type == PARTISPHERE4 || + type == PARTISPHERE5 || + type == PARTISPHERE6 || + type == PARTIPLOUF0 || + type == PARTITRACK1 || + type == PARTITRACK2 || + type == PARTITRACK3 || + type == PARTITRACK4 || + type == PARTITRACK5 || + type == PARTITRACK6 || + type == PARTITRACK7 || + type == PARTITRACK8 || + type == PARTITRACK9 || + type == PARTITRACK10 || + type == PARTITRACK11 || + type == PARTITRACK12 || + type == PARTILENS1 || + type == PARTILENS2 || + type == PARTILENS3 || + type == PARTILENS4 || + type == PARTIGFLAT || + type == PARTIDROP || + type == PARTIWATER || + type == PARTILIMIT1 || + type == PARTILIMIT2 || + type == PARTILIMIT3 || + type == PARTILIMIT4 || + type == PARTIEXPLOG1 || + type == PARTIEXPLOG2 ) + { + t = 1; // effect00 + } + if ( type == PARTIGLINT || + type == PARTIGLINTb || + type == PARTIGLINTr || + type == PARTITOTO || + type == PARTISELY || + type == PARTISELR || + type == PARTIQUARTZ || + type == PARTIGUNDEL || + type == PARTICONTROL || + type == PARTISHOW || + type == PARTICHOC || + type == PARTIFOG4 || + type == PARTIFOG5 || + type == PARTIFOG6 || + type == PARTIFOG7 ) + { + t = 2; // effect01 + } + if ( type == PARTIGUN1 || + type == PARTIFLIC || + type == PARTISPHERE0 || + type == PARTISPHERE3 || + type == PARTIFOG0 || + type == PARTIFOG1 || + type == PARTIFOG2 || + type == PARTIFOG3 ) + { + t = 3; // effect02 + } + if ( type == PARTISMOKE1 || + type == PARTISMOKE2 || + type == PARTISMOKE3 || + type == PARTIBLOOD || + type == PARTIBLOODM || + type == PARTIVIRUS1 || + type == PARTIVIRUS2 || + type == PARTIVIRUS3 || + type == PARTIVIRUS4 || + type == PARTIVIRUS5 || + type == PARTIVIRUS6 || + type == PARTIVIRUS7 || + type == PARTIVIRUS8 || + type == PARTIVIRUS9 || + type == PARTIVIRUS10 ) + { + t = 4; // text (D3DSTATETTw) + } + if (t >= MAXPARTITYPE) return -1; + if (t == -1) return -1; + + for (int j = 0; j < MAXPARTICULE; j++) + { + int i = MAXPARTICULE*t+j; + + if (! m_particle[i].used) + { + memset(&m_particle[i], 0, sizeof(Particle)); + m_particle[i].used = true; + m_particle[i].ray = false; + m_particle[i].uniqueStamp = m_uniqueStamp++; + m_particle[i].sheet = sheet; + m_particle[i].mass = mass; + m_particle[i].duration = duration; + m_particle[i].pos = pos; + m_particle[i].goal = pos; + m_particle[i].speed = speed; + m_particle[i].windSensitivity = windSensitivity; + m_particle[i].dim = dim; + m_particle[i].zoom = 1.0f; + m_particle[i].angle = 0.0f; + m_particle[i].intensity = 1.0f; + m_particle[i].type = type; + m_particle[i].phase = PARPHSTART; + m_particle[i].texSup.x = 0.0f; + m_particle[i].texSup.y = 0.0f; + m_particle[i].texInf.x = 0.0f; + m_particle[i].texInf.y = 0.0f; + m_particle[i].time = 0.0f; + m_particle[i].phaseTime = 0.0f; + m_particle[i].testTime = 0.0f; + m_particle[i].objLink = 0; + m_particle[i].objFather = 0; + m_particle[i].trackRank = -1; + + m_totalInterface[t][sheet] ++; + + if ( type == PARTIEXPLOT || + type == PARTIEXPLOO ) + { + m_particle[i].angle = Math::Rand()*Math::PI*2.0f; + } + + if ( type == PARTIGUN1 || + type == PARTIGUN4 ) + { + m_particle[i].testTime = 1.0f; // impact immediately + } + + if ( type >= PARTIFOG0 && + type <= PARTIFOG9 ) + { + if (m_fogTotal < MAXPARTIFOG) + m_fog[m_fogTotal++] = i; + } + + return i | ((m_particle[i].uniqueStamp&0xffff)<<16); + } + } + + return -1; } -int CParticle::CreateFrag(Math::Vector pos, Math::Vector speed, EngineTriangle *triangle, +/** Returns the channel of the particle created or -1 on error */ +int CParticle::CreateFrag(Math::Vector pos, Math::Vector speed, + EngineTriangle *triangle, + ParticleType type, + float duration, float mass, + float windSensitivity, int sheet) +{ + int t = 0; + for (int j = 0; j < MAXPARTICULE; j++) + { + int i = MAXPARTICULE*t+j; + + if (!m_particle[i].used) + { + memset(&m_particle[i], 0, sizeof(Particle)); + m_particle[i].used = true; + m_particle[i].ray = false; + m_particle[i].uniqueStamp = m_uniqueStamp++; + m_particle[i].sheet = sheet; + m_particle[i].mass = mass; + m_particle[i].duration = duration; + m_particle[i].pos = pos; + m_particle[i].goal = pos; + m_particle[i].speed = speed; + m_particle[i].windSensitivity = windSensitivity; + m_particle[i].zoom = 1.0f; + m_particle[i].angle = 0.0f; + m_particle[i].intensity = 1.0f; + m_particle[i].type = type; + m_particle[i].phase = PARPHSTART; + m_particle[i].texSup.x = 0.0f; + m_particle[i].texSup.y = 0.0f; + m_particle[i].texInf.x = 0.0f; + m_particle[i].texInf.y = 0.0f; + m_particle[i].time = 0.0f; + m_particle[i].phaseTime = 0.0f; + m_particle[i].testTime = 0.0f; + m_particle[i].objLink = 0; + m_particle[i].objFather = 0; + m_particle[i].trackRank = -1; + m_triangle[i] = *triangle; + + m_totalInterface[t][sheet] ++; + + Math::Vector p1; + p1.x = m_triangle[i].triangle[0].coord.x; + p1.y = m_triangle[i].triangle[0].coord.y; + p1.z = m_triangle[i].triangle[0].coord.z; + + Math::Vector p2; + p2.x = m_triangle[i].triangle[1].coord.x; + p2.y = m_triangle[i].triangle[1].coord.y; + p2.z = m_triangle[i].triangle[1].coord.z; + + Math::Vector p3; + p3.x = m_triangle[i].triangle[2].coord.x; + p3.y = m_triangle[i].triangle[2].coord.y; + p3.z = m_triangle[i].triangle[2].coord.z; + + float l1 = Math::Distance(p1, p2); + float l2 = Math::Distance(p2, p3); + float l3 = Math::Distance(p3, p1); + float dx = fabs(Math::Min(l1, l2, l3))*0.5f; + float dy = fabs(Math::Max(l1, l2, l3))*0.5f; + p1 = Math::Vector(-dx, dy, 0.0f); + p2 = Math::Vector( dx, dy, 0.0f); + p3 = Math::Vector(-dx, -dy, 0.0f); + + m_triangle[i].triangle[0].coord.x = p1.x; + m_triangle[i].triangle[0].coord.y = p1.y; + m_triangle[i].triangle[0].coord.z = p1.z; + + m_triangle[i].triangle[1].coord.x = p2.x; + m_triangle[i].triangle[1].coord.y = p2.y; + m_triangle[i].triangle[1].coord.z = p2.z; + + m_triangle[i].triangle[2].coord.x = p3.x; + m_triangle[i].triangle[2].coord.y = p3.y; + m_triangle[i].triangle[2].coord.z = p3.z; + + Math::Vector n(0.0f, 0.0f, -1.0f); + + m_triangle[i].triangle[0].normal.x = n.x; + m_triangle[i].triangle[0].normal.y = n.y; + m_triangle[i].triangle[0].normal.z = n.z; + + m_triangle[i].triangle[1].normal.x = n.x; + m_triangle[i].triangle[1].normal.y = n.y; + m_triangle[i].triangle[1].normal.z = n.z; + + m_triangle[i].triangle[2].normal.x = n.x; + m_triangle[i].triangle[2].normal.y = n.y; + m_triangle[i].triangle[2].normal.z = n.z; + + if (type == PARTIFRAG) + m_particle[i].angle = Math::Rand()*Math::PI*2.0f; + + return i | ((m_particle[i].uniqueStamp&0xffff)<<16); + } + } + + return -1; +} + + +/** Returns the channel of the particle created or -1 on error */ +int CParticle::CreatePart(Math::Vector pos, Math::Vector speed, + ParticleType type, + float duration, float mass, float weight, + float windSensitivity, int sheet) +{ + int t = 0; + for (int j = 0; j < MAXPARTICULE; j++) + { + int i = MAXPARTICULE*t+j; + + if (!m_particle[i].used) + { + memset(&m_particle[i], 0, sizeof(Particle)); + m_particle[i].used = true; + m_particle[i].ray = false; + m_particle[i].uniqueStamp = m_uniqueStamp++; + m_particle[i].sheet = sheet; + m_particle[i].mass = mass; + m_particle[i].weight = weight; + m_particle[i].duration = duration; + m_particle[i].pos = pos; + m_particle[i].goal = pos; + m_particle[i].speed = speed; + m_particle[i].windSensitivity = windSensitivity; + m_particle[i].zoom = 1.0f; + m_particle[i].angle = 0.0f; + m_particle[i].intensity = 1.0f; + m_particle[i].type = type; + m_particle[i].phase = PARPHSTART; + m_particle[i].texSup.x = 0.0f; + m_particle[i].texSup.y = 0.0f; + m_particle[i].texInf.x = 0.0f; + m_particle[i].texInf.y = 0.0f; + m_particle[i].time = 0.0f; + m_particle[i].phaseTime = 0.0f; + m_particle[i].testTime = 0.0f; + m_particle[i].trackRank = -1; + + m_totalInterface[t][sheet] ++; + + return i | ((m_particle[i].uniqueStamp&0xffff)<<16); + } + } + + return -1; +} + +/** Returns the channel of the particle created or -1 on error */ +int CParticle::CreateRay(Math::Vector pos, Math::Vector goal, + ParticleType type, Math::Point dim, + float duration, int sheet) +{ + int t = -1; + if ( type == PARTIRAY1 || + type == PARTIRAY2 || + type == PARTIRAY3 || + type == PARTIRAY4 ) + { + t = 3; // effect02 + } + if (t >= MAXPARTITYPE) return -1; + if (t == -1) return -1; + + for (int j = 0; j < MAXPARTICULE; j++) + { + int i = MAXPARTICULE*t+j; + + if (!m_particle[i].used) + { + memset(&m_particle[i], 0, sizeof(Particle)); + m_particle[i].used = true; + m_particle[i].ray = true; + m_particle[i].uniqueStamp = m_uniqueStamp++; + m_particle[i].sheet = sheet; + m_particle[i].mass = 0.0f; + m_particle[i].duration = duration; + m_particle[i].pos = pos; + m_particle[i].goal = goal; + m_particle[i].speed = Math::Vector(0.0f, 0.0f, 0.0f); + m_particle[i].windSensitivity = 0.0f; + m_particle[i].dim = dim; + m_particle[i].zoom = 1.0f; + m_particle[i].angle = 0.0f; + m_particle[i].intensity = 1.0f; + m_particle[i].type = type; + m_particle[i].phase = PARPHSTART; + m_particle[i].texSup.x = 0.0f; + m_particle[i].texSup.y = 0.0f; + m_particle[i].texInf.x = 0.0f; + m_particle[i].texInf.y = 0.0f; + m_particle[i].time = 0.0f; + m_particle[i].phaseTime = 0.0f; + m_particle[i].testTime = 0.0f; + m_particle[i].objLink = 0; + m_particle[i].objFather = 0; + m_particle[i].trackRank = -1; + + m_totalInterface[t][sheet] ++; + + return i | ((m_particle[i].uniqueStamp&0xffff)<<16); + } + } + + return -1; +} + +/** "length" is the length of the tail of drag (in seconds)! */ +int CParticle::CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, float duration, float mass, - float windSensitivity, int sheet) + float length, float width) { - GetLogger()->Trace("CParticle::CreateFrag() stub!\n"); - // TODO! - return 0; + // Creates the normal particle. + int channel = CreateParticle(pos, speed, dim, type, duration, mass, 0.0f, 0); + if (channel == -1) return -1; + + // Seeks a streak free. + for (int i = 0; i < MAXTRACK; i++) + { + if (!m_track[i].used) // free? + { + int rank = channel; + if (!CheckChannel(rank)) return -1; + m_particle[rank].trackRank = i; + + m_track[i].used = true; + m_track[i].step = (length/duration) / MAXTRACKLEN; + m_track[i].last = 0.0f; + m_track[i].intensity = 1.0f; + m_track[i].width = width; + m_track[i].posUsed = 1; + m_track[i].head = 0; + m_track[i].pos[0] = pos; + break; + } + } + + return channel; } -int CParticle::CreatePart(Math::Vector pos, Math::Vector speed, ParticleType type, - float duration, float mass, float weight, - float windSensitivity, int sheet) +void CParticle::CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, + const Math::Vector &p3, const Math::Vector &p4, + ParticleType type) { - GetLogger()->Trace("CParticle::CreatePart() stub!\n"); - // TODO! - return 0; + int max = MAXWHEELTRACE; + int i = m_wheelTraceIndex++; + if (m_wheelTraceIndex > max) m_wheelTraceIndex = 0; + + m_wheelTrace[i].type = type; + m_wheelTrace[i].pos[0] = p1; // ul + m_wheelTrace[i].pos[1] = p2; // dl + m_wheelTrace[i].pos[2] = p3; // ur + m_wheelTrace[i].pos[3] = p4; // dr + m_wheelTrace[i].startTime = m_absTime; + + if (m_terrain == nullptr) + m_terrain = static_cast(m_iMan->SearchInstance(CLASS_TERRAIN)); + + m_terrain->AdjustToFloor(m_wheelTrace[i].pos[0]); + m_wheelTrace[i].pos[0].y += 0.2f; // just above the ground + + m_terrain->AdjustToFloor(m_wheelTrace[i].pos[1]); + m_wheelTrace[i].pos[1].y += 0.2f; // just above the ground + + m_terrain->AdjustToFloor(m_wheelTrace[i].pos[2]); + m_wheelTrace[i].pos[2].y += 0.2f; // just above the ground + + m_terrain->AdjustToFloor(m_wheelTrace[i].pos[3]); + m_wheelTrace[i].pos[3].y += 0.2f; // just above the ground + + if (m_wheelTraceTotal < max) + m_wheelTraceTotal++; + else + m_wheelTraceTotal = max; } -int CParticle::CreateRay(Math::Vector pos, Math::Vector goal, ParticleType type, Math::Point dim, - float duration, int sheet) -{ - GetLogger()->Trace("CParticle::CreateRay() stub!\n"); - // TODO! - return 0; -} -int CParticle::CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, - float duration, float mass, float length, float width) -{ - GetLogger()->Trace("CParticle::CreateTrack() stub!\n"); - // TODO! - return 0; -} -void CParticle::CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3, - const Math::Vector &p4, ParticleType type) +/** Adapts the channel so it can be used as an offset in m_particle */ +bool CParticle::CheckChannel(int &channel) { - GetLogger()->Trace("CParticle::CreateWheelTrace() stub!\n"); - // TODO! -} + int uniqueStamp = (channel>>16)&0xffff; + channel &= 0xffff; -void CParticle::DeleteParticle(ParticleType type) -{ - GetLogger()->Trace("CParticle::DeleteParticle() stub!\n"); - // TODO! -} + if (channel < 0) return false; + if (channel >= MAXPARTICULE*MAXPARTITYPE) return false; -void CParticle::DeleteParticle(int channel) -{ - GetLogger()->Trace("CParticle::DeleteParticle() stub!\n"); - // TODO! -} + if (!m_particle[channel].used) + { + GetLogger()->Error("CheckChannel used=false !\n"); + return false; + } -void CParticle::SetObjectLink(int channel, CObject *object) -{ - GetLogger()->Trace("CParticle::SetObjectLink() stub!\n"); - // TODO! -} + if (m_particle[channel].uniqueStamp != uniqueStamp) + { + GetLogger()->Error("CheckChannel uniqueStamp !\n"); + return false; + } -void CParticle::SetObjectFather(int channel, CObject *object) -{ - GetLogger()->Trace("CParticle::SetObjectFather() stub!\n"); - // TODO! -} - -void CParticle::SetPosition(int channel, Math::Vector pos) -{ - GetLogger()->Trace("CParticle::SetPosition() stub!\n"); - // TODO! -} - -void CParticle::SetDimension(int channel, Math::Point dim) -{ - GetLogger()->Trace("CParticle::SetDimension() stub!\n"); - // TODO! -} - -void CParticle::SetZoom(int channel, float zoom) -{ - GetLogger()->Trace("CParticle::SetZoom() stub!\n"); - // TODO! -} - -void CParticle::SetAngle(int channel, float angle) -{ - GetLogger()->Trace("CParticle::SetAngle() stub!\n"); - // TODO! -} - -void CParticle::SetIntensity(int channel, float intensity) -{ - GetLogger()->Trace("CParticle::SetIntensity() stub!\n"); - // TODO! -} - -void CParticle::SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity) -{ - GetLogger()->Trace("CParticle::SetParam() stub!\n"); - // TODO! -} - -void CParticle::SetPhase(int channel, ParticlePhase phase, float duration) -{ - GetLogger()->Trace("CParticle::SetPhase() stub!\n"); - // TODO! -} - -bool CParticle::GetPosition(int channel, Math::Vector &pos) -{ - GetLogger()->Trace("CParticle::GetPosition() stub!\n"); - // TODO! - return true; -} - -Color CParticle::GetFogColor(Math::Vector pos) -{ - GetLogger()->Trace("CParticle::GetFogColor() stub!\n"); - // TODO! - return Color(); -} - -void CParticle::SetFrameUpdate(int sheet, bool update) -{ - GetLogger()->Trace("CParticle::SetFrameUpdate() stub!\n"); - // TODO! -} - -void CParticle::FrameParticle(float rTime) -{ - GetLogger()->Trace("CParticle::FrameParticle() stub!\n"); - // TODO! -} - -void CParticle::DrawParticle(int sheet) -{ - GetLogger()->Trace("CParticle::DrawParticle() stub!\n"); - // TODO! -} - -bool CParticle::WriteWheelTrace(const char *filename, int width, int height, Math::Vector dl, Math::Vector ur) -{ - GetLogger()->Trace("CParticle::WriteWheelTrace() stub!\n"); - // TODO! return true; } void CParticle::DeleteRank(int rank) { - GetLogger()->Trace("CParticle::DeleteRank() stub!\n"); - // TODO! + if (m_totalInterface[rank/MAXPARTICULE][m_particle[rank].sheet] > 0) + m_totalInterface[rank/MAXPARTICULE][m_particle[rank].sheet]--; + + int i = m_particle[rank].trackRank; + if (i != -1) // drag associated? + m_track[i].used = false; // frees the drag + + m_particle[rank].used = false; } -bool CParticle::CheckChannel(int &channel) +void CParticle::DeleteParticle(ParticleType type) { - GetLogger()->Trace("CParticle::CheckChannel() stub!\n"); - // TODO! + for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++) + { + if (!m_particle[i].used) continue; + if (m_particle[i].type != type) continue; + + DeleteRank(i); + } +} + +void CParticle::DeleteParticle(int channel) +{ + if (!CheckChannel(channel)) return; + + if (m_totalInterface[channel/MAXPARTICULE][m_particle[channel].sheet] > 0 ) + m_totalInterface[channel/MAXPARTICULE][m_particle[channel].sheet]--; + + int i = m_particle[channel].trackRank; + if (i != -1) // drag associated? + m_track[i].used = false; // frees the drag + + m_particle[channel].used = false; +} + +void CParticle::SetObjectLink(int channel, CObject *object) +{ + if (!CheckChannel(channel)) return; + m_particle[channel].objLink = object; +} + +void CParticle::SetObjectFather(int channel, CObject *object) +{ + if (!CheckChannel(channel)) return; + m_particle[channel].objFather = object; +} + +void CParticle::SetPosition(int channel, Math::Vector pos) +{ + if (!CheckChannel(channel)) return; + m_particle[channel].pos = pos; +} + +void CParticle::SetDimension(int channel, Math::Point dim) +{ + if (!CheckChannel(channel)) return; + m_particle[channel].dim = dim; +} + +void CParticle::SetZoom(int channel, float zoom) +{ + if (!CheckChannel(channel)) return; + m_particle[channel].zoom = zoom; +} + +void CParticle::SetAngle(int channel, float angle) +{ + if (!CheckChannel(channel)) return; + m_particle[channel].angle = angle; +} + +void CParticle::SetIntensity(int channel, float intensity) +{ + if (!CheckChannel(channel)) return; + m_particle[channel].intensity = intensity; +} + +void CParticle::SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, + float angle, float intensity) +{ + if (!CheckChannel(channel)) return; + m_particle[channel].pos = pos; + m_particle[channel].dim = dim; + m_particle[channel].zoom = zoom; + m_particle[channel].angle = angle; + m_particle[channel].intensity = intensity; +} + +void CParticle::SetPhase(int channel, ParticlePhase phase, float duration) +{ + if (!CheckChannel(channel)) return; + m_particle[channel].phase = phase; + m_particle[channel].duration = duration; + m_particle[channel].phaseTime = m_particle[channel].time; +} + +bool CParticle::GetPosition(int channel, Math::Vector &pos) +{ + if (!CheckChannel(channel)) return false; + pos = m_particle[channel].pos; return true; } +void CParticle::SetFrameUpdate(int sheet, bool update) +{ + m_frameUpdate[sheet] = update; +} + +void CParticle::FrameParticle(float rTime) +{ + if (m_main == nullptr) + m_main = static_cast(m_iMan->SearchInstance(CLASS_MAIN)); + + bool pause = (m_engine->GetPause() && !m_main->GetInfoLock()); + + if (m_terrain == nullptr) + m_terrain = static_cast(m_iMan->SearchInstance(CLASS_TERRAIN)); + + if (m_water == nullptr) + m_water = static_cast(m_iMan->SearchInstance(CLASS_WATER)); + + if (!pause) + { + m_lastTimeGunDel += rTime; + m_absTime += rTime; + } + + Math::Vector wind = m_terrain->GetWind(); + Math::Vector eye = m_engine->GetEyePt(); + + Math::Point ts, ti; + Math::Vector pos; + + for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++) + { + if (!m_particle[i].used) continue; + if (!m_frameUpdate[m_particle[i].sheet]) continue; + + if (m_particle[i].type != PARTISHOW) + { + if (pause && m_particle[i].sheet != SH_INTERFACE) continue; + } + + if (m_particle[i].type != PARTIQUARTZ) + m_particle[i].pos += m_particle[i].speed*rTime; + + if (m_particle[i].sheet == SH_WORLD) + { + float h = rTime*m_particle[i].windSensitivity*Math::Rand()*2.0f; + m_particle[i].pos += wind*h; + } + + float progress = (m_particle[i].time-m_particle[i].phaseTime)/m_particle[i].duration; + + // Manages the particles with mass that bounce. + if ( m_particle[i].mass != 0.0f && + m_particle[i].type != PARTIQUARTZ ) + { + m_particle[i].speed.y -= m_particle[i].mass*rTime; + + float h; + if (m_particle[i].sheet == SH_INTERFACE) + h = 0.0f; + else + h = m_terrain->GetFloorLevel(m_particle[i].pos, true); + + h += m_particle[i].dim.y*0.75f; + if (m_particle[i].pos.y < h) // impact with the ground? + { + if ( m_particle[i].type == PARTIPART && + m_particle[i].weight > 3.0f && // heavy enough? + m_particle[i].bounce < 3 ) + { + float amplitude = m_particle[i].weight*0.1f; + amplitude *= 1.0f-0.3f*m_particle[i].bounce; + if (amplitude > 1.0f) amplitude = 1.0f; + if (amplitude > 0.0f) + { + Play(SOUND_BOUM, m_particle[i].pos, amplitude); + } + } + + if (m_particle[i].bounce < 3) + { + m_particle[i].pos.y = h; + m_particle[i].speed.y *= -0.4f; + m_particle[i].speed.x *= 0.4f; + m_particle[i].speed.z *= 0.4f; + m_particle[i].bounce ++; // more impact + } + else // disappears after 3 bounces? + { + if ( m_particle[i].pos.y < h-10.0f || + m_particle[i].time >= 20.0f ) + { + DeleteRank(i); + continue; + } + } + } + } + + // Manages drag associated. + int r = m_particle[i].trackRank; + if (r != -1) // drag exists? + { + if (TrackMove(r, m_particle[i].pos, progress)) + { + DeleteRank(i); + continue; + } + + m_track[r].drawParticle = (progress < 1.0f); + } + + if (m_particle[i].type == PARTITRACK1) // explosion technique? + { + m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); + + ts.x = 0.375f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTITRACK2) // spray blue? + { + m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); + + ts.x = 0.500f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTITRACK3) // spider? + { + m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); + + ts.x = 0.500f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTITRACK4) // insect explosion? + { + m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); + + ts.x = 0.625f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTITRACK5) // derrick? + { + m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); + + ts.x = 0.750f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTITRACK6) // reset in/out? + { + ts.x = 0.0f; + ts.y = 0.0f; + ti.x = 0.0f; + ti.y = 0.0f; + } + + if ( m_particle[i].type == PARTITRACK7 || // win-1 ? + m_particle[i].type == PARTITRACK8 || // win-2 ? + m_particle[i].type == PARTITRACK9 || // win-3 ? + m_particle[i].type == PARTITRACK10 ) // win-4 ? + { + m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); + + ts.x = 0.25f*(m_particle[i].type-PARTITRACK7); + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTITRACK11) // phazer shot? + { + CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); + m_particle[i].goal = m_particle[i].pos; + if (object != nullptr) + { + if (object->GetType() == OBJECT_MOTHER) + object->ExploObject(EXPLO_BOUM, 0.1f); + else + object->ExploObject(EXPLO_BOUM, 0.0f, GetDecay(object->GetType())); + } + + m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); + + ts.x = 0.375f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTITRACK12) // drag reactor? + { + m_particle[i].zoom = 1.0f; + + ts.x = 0.375f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIMOTOR) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-progress; + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.000f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIBLITZ) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-progress; + m_particle[i].angle = Math::Rand()*Math::PI*2.0f; + + ts.x = 0.125f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTICRASH) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress < 0.25f) + m_particle[i].zoom = progress/0.25f; + else + m_particle[i].intensity = 1.0f-(progress-0.25f)/0.75f; + + ts.x = 0.000f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIVAPOR) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].intensity = 1.0f-progress; + m_particle[i].zoom = 1.0f+progress*3.0f; + + ts.x = 0.000f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIGAS) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-progress; + + ts.x = 0.375f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIBASE) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f+progress*7.0f; + m_particle[i].intensity = powf(1.0f-progress, 3.0f); + + ts.x = 0.375f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particle[i].type == PARTIFIRE || + m_particle[i].type == PARTIFIREZ ) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (m_particle[i].type == PARTIFIRE) + m_particle[i].zoom = 1.0f-progress; + else + m_particle[i].zoom = progress; + + ts.x = 0.500f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIGUN1) // fireball shot? + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (m_particle[i].testTime >= 0.1f) + { + m_particle[i].testTime = 0.0f; + + if (m_terrain->GetHeightToFloor(m_particle[i].pos, true) < -2.0f) + { + m_exploGunCounter++; + + if (m_exploGunCounter % 2 == 0) + { + pos = m_particle[i].goal; + m_terrain->AdjustToFloor(pos, true); + Math::Vector speed; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 0.0f; + Math::Point dim; + dim.x = Math::Rand()*6.0f+6.0f; + dim.y = dim.x; + float duration = Math::Rand()*1.0f+1.0f; + float mass = 0.0f; + CreateParticle(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); + + pos.y += 1.0f; + int total = static_cast(2.0f*m_engine->GetParticleDensity()); + for (int j = 0; j < total; j++) + { + speed.x = (Math::Rand()-0.5f)*20.0f; + speed.z = (Math::Rand()-0.5f)*20.0f; + speed.y = Math::Rand()*20.0f; + dim.x = 1.0f; + dim.y = dim.x; + duration = Math::Rand()*1.0f+1.0f; + mass = Math::Rand()*10.0f+15.0f; + CreateParticle(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); + } + } + + if (m_exploGunCounter % 4 == 0) + Play(SOUND_EXPLOg1, pos, 0.5f); + + DeleteRank(i); + continue; + } + + CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); + m_particle[i].goal = m_particle[i].pos; + if (object != nullptr) + { + object->ExploObject(EXPLO_BURN, 0.0f, GetDecay(object->GetType())); + + m_exploGunCounter++; + + if (m_exploGunCounter % 2 == 0) + { + pos = m_particle[i].pos; + Math::Vector speed; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 0.0f; + Math::Point dim; + dim.x = Math::Rand()*6.0f+6.0f; + dim.y = dim.x; + float duration = Math::Rand()*1.0f+1.0f; + float mass = 0.0f; + CreateParticle(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); + + pos.y += 1.0f; + int total = static_cast(2.0f*m_engine->GetParticleDensity()); + for (int j = 0; j < total; j++) + { + speed.x = (Math::Rand()-0.5f)*20.0f; + speed.z = (Math::Rand()-0.5f)*20.0f; + speed.y = Math::Rand()*20.0f; + dim.x = 1.0f; + dim.y = dim.x; + duration = Math::Rand()*1.0f+1.0f; + mass = Math::Rand()*10.0f+15.0f; + CreateParticle(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); + } + } + + if (m_exploGunCounter % 4 == 0) + Play(SOUND_EXPLOg1, pos, 0.5f); + + DeleteRank(i); + continue; + } + } + + m_particle[i].angle -= rTime*Math::PI*8.0f; + m_particle[i].zoom = 1.0f-progress; + + ts.x = 0.00f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIGUN2) // ant shot? + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (m_particle[i].testTime >= 0.2f) + { + m_particle[i].testTime = 0.0f; + CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); + m_particle[i].goal = m_particle[i].pos; + if (object != nullptr) + { + if (object->GetShieldRadius() > 0.0f) // protected by shield? + { + CreateParticle(m_particle[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); + if (m_lastTimeGunDel > 0.2f) + { + m_lastTimeGunDel = 0.0f; + Play(SOUND_GUNDEL, m_particle[i].pos, 1.0f); + } + DeleteRank(i); + continue; + } + else + { + if (object->GetType() != OBJECT_HUMAN) + Play(SOUND_TOUCH, m_particle[i].pos, 1.0f); + + object->ExploObject(EXPLO_BOUM, 0.0f); // starts explosion + } + } + } + + m_particle[i].angle = Math::Rand()*Math::PI*2.0f; + m_particle[i].zoom = 1.0f-progress; + + ts.x = 0.125f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIGUN3) // spider suicides? + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (m_particle[i].testTime >= 0.2f) + { + m_particle[i].testTime = 0.0f; + CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); + m_particle[i].goal = m_particle[i].pos; + if (object != nullptr) + { + if (object->GetShieldRadius() > 0.0f) + { + CreateParticle(m_particle[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); + if (m_lastTimeGunDel > 0.2f) + { + m_lastTimeGunDel = 0.0f; + Play(SOUND_GUNDEL, m_particle[i].pos, 1.0f); + } + DeleteRank(i); + continue; + } + else + { + object->ExploObject(EXPLO_BURN, 1.0f); // starts explosion + } + } + } + + ts.x = 0.500f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIGUN4) // orgaball shot? + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (m_particle[i].testTime >= 0.1f) + { + m_particle[i].testTime = 0.0f; + + if (m_terrain->GetHeightToFloor(m_particle[i].pos, true) < -2.0f) + { + m_exploGunCounter ++; + + if (m_exploGunCounter % 2 == 0) + { + pos = m_particle[i].goal; + m_terrain->AdjustToFloor(pos, true); + Math::Vector speed; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 0.0f; + Math::Point dim; + dim.x = Math::Rand()*4.0f+2.0f; + dim.y = dim.x; + float duration = Math::Rand()*0.7f+0.7f; + float mass = 0.0f; + CreateParticle(pos, speed, dim, PARTIEXPLOG2, duration, mass, 1.0f); + } + + if (m_exploGunCounter % 4 == 0) + { + Play(SOUND_EXPLOg2, pos, 0.5f); + } + + DeleteRank(i); + continue; + } + + CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); + m_particle[i].goal = m_particle[i].pos; + if (object != nullptr) + { + object->ExploObject(EXPLO_BOUM, 0.0f, GetDecay(object->GetType())); + + m_exploGunCounter ++; + + if (m_exploGunCounter % 2 == 0) + { + pos = m_particle[i].pos; + Math::Vector speed; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 0.0f; + Math::Point dim; + dim.x = Math::Rand()*4.0f+2.0f; + dim.y = dim.x; + float duration = Math::Rand()*0.7f+0.7f; + float mass = 0.0f; + CreateParticle(pos, speed, dim, PARTIEXPLOG2, duration, mass, 1.0f); + } + + if (m_exploGunCounter % 4 == 0) + Play(SOUND_EXPLOg2, pos, 0.5f); + + DeleteRank(i); + continue; + } + } + + m_particle[i].angle = Math::Rand()*Math::PI*2.0f; + m_particle[i].zoom = 1.0f-progress; + + ts.x = 0.125f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIFLIC) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 0.1f+progress; + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.00f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTISHOW) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress < 0.5f) m_particle[i].intensity = progress/0.5f; + else m_particle[i].intensity = 2.0f-progress/0.5f; + m_particle[i].zoom = 1.0f-progress*0.8f; + m_particle[i].angle -= rTime*Math::PI*0.5f; + + ts.x = 0.50f; + ts.y = 0.00f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTICHOC) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 0.1f+progress; + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.50f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIGFLAT) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 0.1f+progress; + m_particle[i].intensity = 1.0f-progress; + m_particle[i].angle -= rTime*Math::PI*2.0f; + + ts.x = 0.00f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTILIMIT1) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f; + m_particle[i].intensity = 1.0f; + + ts.x = 0.000f; + ts.y = 0.125f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + if (m_particle[i].type == PARTILIMIT2) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f; + m_particle[i].intensity = 1.0f; + + ts.x = 0.375f; + ts.y = 0.125f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + if (m_particle[i].type == PARTILIMIT3) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f; + m_particle[i].intensity = 1.0f; + + ts.x = 0.500f; + ts.y = 0.125f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIFOG0) + { + m_particle[i].zoom = progress; + m_particle[i].intensity = 0.3f+sinf(progress)*0.15f; + m_particle[i].angle += rTime*0.05f; + + ts.x = 0.25f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + if (m_particle[i].type == PARTIFOG1) + { + m_particle[i].zoom = progress; + m_particle[i].intensity = 0.3f+sinf(progress)*0.15f; + m_particle[i].angle -= rTime*0.07f; + + ts.x = 0.25f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIFOG2) + { + m_particle[i].zoom = progress; + m_particle[i].intensity = 0.6f+sinf(progress)*0.15f; + m_particle[i].angle += rTime*0.05f; + + ts.x = 0.75f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + if (m_particle[i].type == PARTIFOG3) + { + m_particle[i].zoom = progress; + m_particle[i].intensity = 0.6f+sinf(progress)*0.15f; + m_particle[i].angle -= rTime*0.07f; + + ts.x = 0.75f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIFOG4) + { + m_particle[i].zoom = progress; + m_particle[i].intensity = 0.5f+sinf(progress)*0.2f; + m_particle[i].angle += rTime*0.05f; + + ts.x = 0.00f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + if (m_particle[i].type == PARTIFOG5) + { + m_particle[i].zoom = progress; + m_particle[i].intensity = 0.5f+sinf(progress)*0.2f; + m_particle[i].angle -= rTime*0.07f; + + ts.x = 0.00f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIFOG6) + { + m_particle[i].zoom = progress; + m_particle[i].intensity = 0.5f+sinf(progress)*0.2f; + m_particle[i].angle += rTime*0.05f; + + ts.x = 0.50f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + if (m_particle[i].type == PARTIFOG7) + { + m_particle[i].zoom = progress; + m_particle[i].intensity = 0.5f+sinf(progress)*0.2f; + m_particle[i].angle -= rTime*0.07f; + + ts.x = 0.50f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + // Decreases the intensity if the camera + // is almost at the same height (fog was eye level). + if ( m_particle[i].type >= PARTIFOG0 && + m_particle[i].type <= PARTIFOG9 ) + { + float h = 10.0f; + + if ( m_particle[i].pos.y >= eye.y && + m_particle[i].pos.y < eye.y+h ) + { + m_particle[i].intensity *= (m_particle[i].pos.y-eye.y)/h; + } + if ( m_particle[i].pos.y > eye.y-h && + m_particle[i].pos.y < eye.y ) + { + m_particle[i].intensity *= (eye.y-m_particle[i].pos.y)/h; + } + } + + if ( m_particle[i].type == PARTIEXPLOT || + m_particle[i].type == PARTIEXPLOO ) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-progress/2.0f; + m_particle[i].intensity = 1.0f-progress; + + if (m_particle[i].type == PARTIEXPLOT) ts.x = 0.750f; + else ts.x = 0.875f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIEXPLOG1) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.375f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + if (m_particle[i].type == PARTIEXPLOG2) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.625f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIFLAME) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-progress/2.0f; + if (progress < 0.5f) + { + m_particle[i].intensity = progress/0.5f; + } + else + { + m_particle[i].intensity = 2.0f-progress/0.5f; + } + + ts.x = 0.750f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIBUBBLE) + { + if ( progress >= 1.0f || + m_particle[i].pos.y >= m_water->GetLevel() ) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-progress/2.0f; + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.250f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particle[i].type == PARTISMOKE1 || + m_particle[i].type == PARTISMOKE2 || + m_particle[i].type == PARTISMOKE3 ) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress < 0.25f) + { + m_particle[i].zoom = progress/0.25f; + } + else + { + m_particle[i].intensity = 1.0f-(progress-0.25f)/0.75f; + } + + ts.x = 0.500f+0.125f*(m_particle[i].type-PARTISMOKE1); + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIBLOOD) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.750f+(rand()%2)*0.125f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIBLOODM) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.875f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particle[i].type == PARTIVIRUS1 || + m_particle[i].type == PARTIVIRUS2 || + m_particle[i].type == PARTIVIRUS3 || + m_particle[i].type == PARTIVIRUS4 || + m_particle[i].type == PARTIVIRUS5 || + m_particle[i].type == PARTIVIRUS6 || + m_particle[i].type == PARTIVIRUS7 || + m_particle[i].type == PARTIVIRUS8 || + m_particle[i].type == PARTIVIRUS9 || + m_particle[i].type == PARTIVIRUS10 ) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress < 0.25f) + m_particle[i].zoom = progress/0.25f; + else + m_particle[i].intensity = 1.0f-(progress-0.25f)/0.75f; + + m_particle[i].angle += rTime*Math::PI*1.0f; + + if (m_particle[i].type == PARTIVIRUS1) // A ? + { + ts.x = 0.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 10.0f/256.0f; ti.y = 30.0f/256.0f; + } + if (m_particle[i].type == PARTIVIRUS2) // C ? + { + ts.x = 19.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 28.0f/256.0f; ti.y = 30.0f/256.0f; + } + if (m_particle[i].type == PARTIVIRUS3) // E ? + { + ts.x = 36.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 45.0f/256.0f; ti.y = 30.0f/256.0f; + } + if (m_particle[i].type == PARTIVIRUS4) // N ? + { + ts.x = 110.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 120.0f/256.0f; ti.y = 30.0f/256.0f; + } + if (m_particle[i].type == PARTIVIRUS5) // R ? + { + ts.x = 148.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 158.0f/256.0f; ti.y = 30.0f/256.0f; + } + if (m_particle[i].type == PARTIVIRUS6) // T ? + { + ts.x = 166.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 175.0f/256.0f; ti.y = 30.0f/256.0f; + } + if (m_particle[i].type == PARTIVIRUS7) // 0 ? + { + ts.x = 90.0f/256.0f; ts.y = 2.0f/256.0f; + ti.x = 98.0f/256.0f; ti.y = 13.0f/256.0f; + } + if (m_particle[i].type == PARTIVIRUS8) // 2 ? + { + ts.x = 103.0f/256.0f; ts.y = 2.0f/256.0f; + ti.x = 111.0f/256.0f; ti.y = 13.0f/256.0f; + } + if (m_particle[i].type == PARTIVIRUS9) // 5 ? + { + ts.x = 125.0f/256.0f; ts.y = 2.0f/256.0f; + ti.x = 132.0f/256.0f; ti.y = 13.0f/256.0f; + } + if (m_particle[i].type == PARTIVIRUS10) // 9 ? + { + ts.x = 153.0f/256.0f; ts.y = 2.0f/256.0f; + ti.x = 161.0f/256.0f; ti.y = 13.0f/256.0f; + } + } + + if (m_particle[i].type == PARTIBLUE) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-progress; + + ts.x = 0.625f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIROOT) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress < 0.25f) + { + m_particle[i].zoom = progress/0.25f; + } + else + { + m_particle[i].intensity = 1.0f-(progress-0.25f)/0.75f; + } + + ts.x = 0.000f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIRECOVER) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress < 0.25f) + { + m_particle[i].zoom = progress/0.25f; + } + else + { + m_particle[i].intensity = 1.0f-(progress-0.25f)/0.75f; + } + + ts.x = 0.875f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIEJECT) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f+powf(progress, 2.0f)*5.0f; + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.625f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTISCRAPS) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-progress; + + ts.x = 0.625f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIFRAG) + { + m_particle[i].angle += rTime*Math::PI*0.5f; + + ts.x = 0.0f; + ts.y = 0.0f; + ti.x = 0.0f; + ti.y = 0.0f; + } + + if (m_particle[i].type == PARTIPART) + { + ts.x = 0.0f; + ts.y = 0.0f; + ti.x = 0.0f; + ti.y = 0.0f; + } + + if (m_particle[i].type == PARTIQUEUE) + { + if (m_particle[i].testTime >= 0.05f) + { + m_particle[i].testTime = 0.0f; + + pos = m_particle[i].pos; + Math::Vector speed = Math::Vector(0.0f, 0.0f, 0.0f); + Math::Point dim; + dim.x = 1.0f*(Math::Rand()*0.8f+0.6f); + dim.y = dim.x; + CreateParticle(pos, speed, dim, PARTIGAS, 0.5f); + } + + ts.x = 0.375f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIORGANIC1) + { + if (progress >= 1.0f) + { + DeleteRank(i); + + pos = m_particle[i].pos; + Math::Point dim; + dim.x = m_particle[i].dim.x/4.0f; + dim.y = dim.x; + float duration = m_particle[i].duration; + float mass = m_particle[i].mass; + int total = static_cast((10.0f*m_engine->GetParticleDensity())); + for (int j = 0; j < total; j++) + { + Math::Vector speed; + speed.x = (Math::Rand()-0.5f)*20.0f; + speed.y = (Math::Rand()-0.5f)*20.0f; + speed.z = (Math::Rand()-0.5f)*20.0f; + CreateParticle(pos, speed, dim, PARTIORGANIC2, duration, mass); + } + total = static_cast((5.0f*m_engine->GetParticleDensity())); + for (int j = 0; j < total; j++) + { + Math::Vector speed; + speed.x = (Math::Rand()-0.5f)*20.0f; + speed.y = (Math::Rand()-0.5f)*20.0f; + speed.z = (Math::Rand()-0.5f)*20.0f; + duration *= Math::Rand()+0.8f; + CreateTrack(pos, speed, dim, PARTITRACK4, duration, mass, duration*0.2f, dim.x*2.0f); + } + continue; + } + + m_particle[i].zoom = (m_particle[i].time-m_particle[i].duration); + + ts.x = 0.125f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIORGANIC2) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); + + ts.x = 0.125f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIGLINT) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress > 0.5f) + m_particle[i].zoom = 1.0f-(progress-0.5f)*2.0f; + + m_particle[i].angle = m_particle[i].time*Math::PI; + + ts.x = 0.75f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIGLINTb) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress > 0.5f) + m_particle[i].zoom = 1.0f-(progress-0.5f)*2.0f; + + m_particle[i].angle = m_particle[i].time*Math::PI; + + ts.x = 0.75f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIGLINTr) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress > 0.5f) + m_particle[i].zoom = 1.0f-(progress-0.5f)*2.0f; + + m_particle[i].angle = m_particle[i].time*Math::PI; + + ts.x = 0.75f; + ts.y = 0.00f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particle[i].type >= PARTILENS1 && + m_particle[i].type <= PARTILENS4 ) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress < 0.5f) + m_particle[i].zoom = progress*2.0f; + else + m_particle[i].intensity = 1.0f-(progress-0.5f)*2.0f; + + ts.x = 0.25f*(m_particle[i].type-PARTILENS1); + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTICONTROL) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress < 0.3f) + { + m_particle[i].zoom = progress/0.3f; + } + else + { + m_particle[i].zoom = 1.0f; + m_particle[i].intensity = 1.0f-(progress-0.3f)/0.7f; + } + + ts.x = 0.00f; + ts.y = 0.00f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIGUNDEL) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress > 0.5f) + m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration/2.0f); + + m_particle[i].angle = m_particle[i].time*Math::PI; + + ts.x = 0.75f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIQUARTZ) + { + if (progress >= 1.0f) + { + m_particle[i].time = 0.0f; + m_particle[i].duration = 0.5f+Math::Rand()*2.0f; + m_particle[i].pos.x = m_particle[i].speed.x + (Math::Rand()-0.5f)*m_particle[i].mass; + m_particle[i].pos.y = m_particle[i].speed.y + (Math::Rand()-0.5f)*m_particle[i].mass; + m_particle[i].pos.z = m_particle[i].speed.z + (Math::Rand()-0.5f)*m_particle[i].mass; + m_particle[i].dim.x = 0.5f+Math::Rand()*1.5f; + m_particle[i].dim.y = m_particle[i].dim.x; + progress = 0.0f; + } + + if (progress < 0.2f) + { + m_particle[i].zoom = progress/0.2f; + m_particle[i].intensity = 1.0f; + } + else + { + m_particle[i].zoom = 1.0f; + m_particle[i].intensity = 1.0f-(progress-0.2f)/0.8f; + } + + ts.x = 0.25f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTITOTO) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-progress; + if (progress < 0.15f) + m_particle[i].intensity = progress/0.15f; + else + m_particle[i].intensity = 1.0f-(progress-0.15f)/0.85f; + + m_particle[i].intensity *= 0.5f; + + ts.x = 0.25f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIERROR) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = progress*1.0f; + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.500f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIWARNING) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = progress*1.0f; + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.875f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIINFO) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = progress*1.0f; + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.750f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTISELY) + { + ts.x = 0.75f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + if (m_particle[i].type == PARTISELR) + { + ts.x = 0.75f; + ts.y = 0.00f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTISPHERE0) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = progress*m_particle[i].dim.x; + + if (progress < 0.65f) + m_particle[i].intensity = progress/0.65f; + else + m_particle[i].intensity = 1.0f-(progress-0.65f)/0.35f; + + m_particle[i].intensity *= 0.5f; + + ts.x = 0.50f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTISPHERE1) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress < 0.30f) + m_particle[i].intensity = progress/0.30f; + else + m_particle[i].intensity = 1.0f-(progress-0.30f)/0.70f; + + m_particle[i].zoom = progress*m_particle[i].dim.x; + m_particle[i].angle = m_particle[i].time*Math::PI*2.0f; + + ts.x = 0.000f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTISPHERE2) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (progress < 0.20f) + m_particle[i].intensity = 1.0f; + else + m_particle[i].intensity = 1.0f-(progress-0.20f)/0.80f; + + m_particle[i].zoom = progress*m_particle[i].dim.x; + m_particle[i].angle = m_particle[i].time*Math::PI*2.0f; + + ts.x = 0.125f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTISPHERE3) + { + if (m_particle[i].phase == PARPHEND && + progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (m_particle[i].phase == PARPHSTART) + { + m_particle[i].intensity = progress; + if (m_particle[i].intensity > 1.0f) + m_particle[i].intensity = 1.0f; + } + + if (m_particle[i].phase == PARPHEND) + m_particle[i].intensity = 1.0f-progress; + + m_particle[i].zoom = m_particle[i].dim.x; + m_particle[i].angle = m_particle[i].time*Math::PI*0.2f; + + ts.x = 0.25f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTISPHERE4) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = progress*m_particle[i].dim.x; + + if (progress < 0.65 ) + m_particle[i].intensity = progress/0.65f; + else + m_particle[i].intensity = 1.0f-(progress-0.65f)/0.35f; + + m_particle[i].intensity *= 0.5f; + + ts.x = 0.125f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTISPHERE5) + { + m_particle[i].intensity = 0.7f+sinf(progress)*0.3f; + m_particle[i].zoom = m_particle[i].dim.x*(1.0f+sinf(progress*0.7f)*0.01f); + m_particle[i].angle = m_particle[i].time*Math::PI*0.2f; + + ts.x = 0.25f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTISPHERE6) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = (1.0f-progress)*m_particle[i].dim.x; + m_particle[i].intensity = progress*0.5f; + + ts.x = 0.125f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIPLOUF0) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = progress; + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.50f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIDROP) + { + if (progress >= 1.0f || + m_particle[i].pos.y < m_water->GetLevel()) + { + DeleteRank(i); + continue; + } + + m_particle[i].zoom = 1.0f-progress; + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.750f; + ts.y = 0.500f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIWATER) + { + if (progress >= 1.0f || + m_particle[i].pos.y < m_water->GetLevel()) + { + DeleteRank(i); + continue; + } + + m_particle[i].intensity = 1.0f-progress; + + ts.x = 0.125f; + ts.y = 0.125f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if (m_particle[i].type == PARTIRAY1) // rayon tour ? + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + if (m_particle[i].testTime >= 0.2f) + { + m_particle[i].testTime = 0.0f; + CObject* object = SearchObjectRay(m_particle[i].pos, m_particle[i].goal, + m_particle[i].type, m_particle[i].objFather); + if (object != nullptr) + object->ExploObject(EXPLO_BOUM, 0.0f); + } + + ts.x = 0.00f; + ts.y = 0.00f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if (m_particle[i].type == PARTIRAY2 || + m_particle[i].type == PARTIRAY3) + { + if (progress >= 1.0f) + { + DeleteRank(i); + continue; + } + + ts.x = 0.00f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + float dp = (1.0f/256.0f)/2.0f; + m_particle[i].texSup.x = ts.x+dp; + m_particle[i].texSup.y = ts.y+dp; + m_particle[i].texInf.x = ti.x-dp; + m_particle[i].texInf.y = ti.y-dp; + m_particle[i].time += rTime; + m_particle[i].testTime += rTime; + } +} + +bool CParticle::TrackMove(int i, Math::Vector pos, float progress) +{ + if (i < 0 || i >= MAXTRACK) return true; + if (! m_track[i].used) return true; + + if (progress < 1.0f) // particle exists? + { + int h = m_track[i].head; + + Math::Vector last; + + if ( m_track[i].posUsed == 1 || + m_track[i].last+m_track[i].step <= progress ) + { + m_track[i].last = progress; + last = m_track[i].pos[h]; + h ++; + if (h == MAXTRACKLEN) h = 0; + if (m_track[i].posUsed < MAXTRACKLEN) m_track[i].posUsed++; + } + else + { + int hh = h-1; + if (hh < 0) hh = MAXTRACKLEN-1; + last = m_track[i].pos[hh]; + } + m_track[i].pos[h] = pos; + m_track[i].len[h] = Math::Distance(pos, last); + + m_track[i].head = h; + + m_track[i].intensity = 1.0f-progress; + } + else // slow death of the track ? + { + m_track[i].intensity = 0.0f; + } + + return (m_track[i].intensity <= 0.0f); +} + +void CParticle::TrackDraw(int i, ParticleType type) +{ + // Calculates the total length memorized. + float lTotal = 0.0f; + int h = m_track[i].head; + for (int counter = 0; counter < m_track[i].posUsed-1; counter++) + { + lTotal += m_track[i].len[h]; + h--; + if (h < 0) h = MAXTRACKLEN-1; + } + + Math::Matrix mat; + mat.LoadIdentity(); + m_device->SetTransform(TRANSFORM_WORLD, mat); + + Math::Point texInf, texSup; + + if (type == PARTITRACK1) // explosion technique? + { + texInf.x = 64.5f/256.0f; + texInf.y = 21.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 22.0f/256.0f; // orange + } + if (type == PARTITRACK2) // blue spray? + { + texInf.x = 64.5f/256.0f; + texInf.y = 13.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 14.0f/256.0f; // blue + } + if (type == PARTITRACK3) // spider? + { + texInf.x = 64.5f/256.0f; + texInf.y = 5.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 6.0f/256.0f; // brown + } + if (type == PARTITRACK4) // insect explosion? + { + texInf.x = 64.5f/256.0f; + texInf.y = 9.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 10.0f/256.0f; // dark green + } + if (type == PARTITRACK5) // derrick? + { + texInf.x = 64.5f/256.0f; + texInf.y = 29.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 30.0f/256.0f; // dark brown + } + if (type == PARTITRACK6) // reset in/out? + { + texInf.x = 64.5f/256.0f; + texInf.y = 17.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 18.0f/256.0f; // cyan + } + if (type == PARTITRACK7) // win-1? + { + texInf.x = 64.5f/256.0f; + texInf.y = 41.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 42.0f/256.0f; // orange + } + if (type == PARTITRACK8) // win-2? + { + texInf.x = 64.5f/256.0f; + texInf.y = 45.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 46.0f/256.0f; // yellow + } + if (type == PARTITRACK9) // win-3? + { + texInf.x = 64.5f/256.0f; + texInf.y = 49.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 50.0f/256.0f; // red + } + if (type == PARTITRACK10) // win-4? + { + texInf.x = 64.5f/256.0f; + texInf.y = 53.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 54.0f/256.0f; // violet + } + if (type == PARTITRACK11) // phazer shot? + { + texInf.x = 64.5f/256.0f; + texInf.y = 21.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 22.0f/256.0f; // orange + } + if (type == PARTITRACK12) // drag reactor? + { + texInf.x = 64.5f/256.0f; + texInf.y = 21.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 22.0f/256.0f; // orange + } + + h = m_track[i].head; + Math::Vector p1 = m_track[i].pos[h]; + float f1 = m_track[i].intensity; + + Math::Vector eye = m_engine->GetEyePt(); + float a = Math::RotateAngle(eye.x-p1.x, eye.z-p1.z); + + Vertex vertex[4]; + Math::Vector corner[4]; + + for (int counter = 0; counter < m_track[i].posUsed-1; counter++) + { + float f2 = f1-(m_track[i].len[h]/lTotal); + if (f2 < 0.0f) f2 = 0.0f; + + h --; + if (h < 0) h = MAXTRACKLEN-1; + + Math::Vector p2 = m_track[i].pos[h]; + + Math::Vector n = Normalize(p1-eye); + + Math::Vector p; + Math::Point rot; + + p = p1; + p.x += f1*m_track[i].width; + rot = Math::RotatePoint(Math::Point(p1.x, p1.z), a+Math::PI/2.0f, Math::Point(p.x, p.z)); + corner[0].x = rot.x; + corner[0].y = p1.y; + corner[0].z = rot.y; + rot = Math::RotatePoint(Math::Point(p1.x, p1.z), a-Math::PI/2.0f, Math::Point(p.x, p.z)); + corner[1].x = rot.x; + corner[1].y = p1.y; + corner[1].z = rot.y; + + p = p2; + p.x += f2*m_track[i].width; + rot = Math::RotatePoint(Math::Point(p2.x, p2.z), a+Math::PI/2.0f, Math::Point(p.x, p.z)); + corner[2].x = rot.x; + corner[2].y = p2.y; + corner[2].z = rot.y; + rot = Math::RotatePoint(Math::Point(p2.x, p2.z), a-Math::PI/2.0f, Math::Point(p.x, p.z)); + corner[3].x = rot.x; + corner[3].y = p2.y; + corner[3].z = rot.y; + + if (p2.y < p1.y) + { + vertex[0] = Vertex(corner[1], n, Math::Point(texSup.x, texSup.y)); + vertex[1] = Vertex(corner[0], n, Math::Point(texInf.x, texSup.y)); + vertex[2] = Vertex(corner[3], n, Math::Point(texSup.x, texInf.y)); + vertex[3] = Vertex(corner[2], n, Math::Point(texInf.x, texInf.y)); + } + else + { + vertex[0] = Vertex(corner[0], n, Math::Point(texSup.x, texSup.y)); + vertex[1] = Vertex(corner[1], n, Math::Point(texInf.x, texSup.y)); + vertex[2] = Vertex(corner[2], n, Math::Point(texSup.x, texInf.y)); + vertex[3] = Vertex(corner[3], n, Math::Point(texInf.x, texInf.y)); + } + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); + m_engine->AddStatisticTriangle(2); + + if (f2 < 0.0f) break; + f1 = f2; + p1 = p2; + } +} + void CParticle::DrawParticleTriangle(int i) { - GetLogger()->Trace("CParticle::DrawParticleTriangle() stub!\n"); - // TODO! + if (m_particle[i].zoom == 0.0f) return; + + Math::Vector eye = m_engine->GetEyePt(); + Math::Vector pos = m_particle[i].pos; + + CObject* object = m_particle[i].objLink; + if (object != nullptr) + pos += object->GetPosition(0); + + Math::Vector angle; + angle.x = -Math::RotateAngle(Math::DistanceProjected(pos, eye), pos.y-eye.y); + angle.y = Math::RotateAngle(pos.z-eye.z, pos.x-eye.x); + angle.z = m_particle[i].angle; + + Math::Matrix mat; + Math::LoadRotationXZYMatrix(mat, angle); + mat.Set(1, 4, pos.x); + mat.Set(2, 4, pos.y); + mat.Set(3, 4, pos.z); + m_device->SetTransform(TRANSFORM_WORLD, mat); + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLES, m_triangle[i].triangle, 3); + m_engine->AddStatisticTriangle(1); } void CParticle::DrawParticleNorm(int i) { - GetLogger()->Trace("CParticle::DrawParticleNorm() stub!\n"); - // TODO! + float zoom = m_particle[i].zoom; + + if (zoom == 0.0f) return; + if (m_particle[i].intensity == 0.0f) return; + + + Math::Vector corner[4]; + Vertex vertex[4]; + + if (m_particle[i].sheet == SH_INTERFACE) + { + Math::Vector pos = m_particle[i].pos; + + Math::Vector n(0.0f, 0.0f, -1.0f); + + Math::Point dim; + dim.x = m_particle[i].dim.x * zoom; + dim.y = m_particle[i].dim.y * zoom; + + corner[0].x = pos.x+dim.x; + corner[0].y = pos.y+dim.y; + corner[0].z = 0.0f; + + corner[1].x = pos.x-dim.x; + corner[1].y = pos.y+dim.y; + corner[1].z = 0.0f; + + corner[2].x = pos.x+dim.x; + corner[2].y = pos.y-dim.y; + corner[2].z = 0.0f; + + corner[3].x = pos.x-dim.x; + corner[3].y = pos.y-dim.y; + corner[3].z = 0.0f; + + vertex[0] = Vertex(corner[1], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texSup.y)); + vertex[1] = Vertex(corner[0], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texSup.y)); + vertex[2] = Vertex(corner[3], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texInf.y)); + vertex[3] = Vertex(corner[2], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texInf.y)); + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); + m_engine->AddStatisticTriangle(2); + } + else + { + Math::Vector eye = m_engine->GetEyePt(); + Math::Vector pos = m_particle[i].pos; + + CObject* object = m_particle[i].objLink; + if (object != nullptr) + pos += object->GetPosition(0); + + Math::Vector angle; + angle.x = -Math::RotateAngle(Math::DistanceProjected(pos, eye), pos.y-eye.y); + angle.y = Math::RotateAngle(pos.z-eye.z, pos.x-eye.x); + angle.z = m_particle[i].angle; + + Math::Matrix mat; + Math::LoadRotationXZYMatrix(mat, angle); + mat.Set(1, 4, pos.x); + mat.Set(2, 4, pos.y); + mat.Set(3, 4, pos.z); + m_device->SetTransform(TRANSFORM_WORLD, mat); + + Math::Vector n(0.0f, 0.0f, -1.0f); + + Math::Point dim; + dim.x = m_particle[i].dim.x * zoom; + dim.y = m_particle[i].dim.y * zoom; + + corner[0].x = dim.x; + corner[0].y = dim.y; + corner[0].z = 0.0f; + + corner[1].x = -dim.x; + corner[1].y = dim.y; + corner[1].z = 0.0f; + + corner[2].x = dim.x; + corner[2].y = -dim.y; + corner[2].z = 0.0f; + + corner[3].x = -dim.x; + corner[3].y = -dim.y; + corner[3].z = 0.0f; + + vertex[0] = Vertex(corner[1], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texSup.y)); + vertex[1] = Vertex(corner[0], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texSup.y)); + vertex[2] = Vertex(corner[3], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texInf.y)); + vertex[3] = Vertex(corner[2], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texInf.y)); + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); + m_engine->AddStatisticTriangle(2); + } } void CParticle::DrawParticleFlat(int i) { - GetLogger()->Trace("CParticle::DrawParticleFlat() stub!\n"); - // TODO! + if (m_particle[i].zoom == 0.0f) return; + if (m_particle[i].intensity == 0.0f) return; + + Math::Vector pos = m_particle[i].pos; + + CObject* object = m_particle[i].objLink; + if (object != nullptr) + pos += object->GetPosition(0); + + Math::Vector angle; + angle.x = Math::PI/2.0f; + angle.y = 0.0f; + angle.z = m_particle[i].angle; + + if (m_engine->GetRankView() == 1) // underwater? + pos.y -= 1.0f; + + Math::Vector eye = m_engine->GetEyePt(); + if (pos.y > eye.y) // seen from below? + angle.x = -Math::PI/2.0f; + + Math::Matrix mat; + Math::LoadRotationXZYMatrix(mat, angle); + mat.Set(1, 4, pos.x); + mat.Set(2, 4, pos.y); + mat.Set(3, 4, pos.z); + m_device->SetTransform(TRANSFORM_WORLD, mat); + + Math::Vector n(0.0f, 0.0f, -1.0f); + + Math::Point dim; + dim.x = m_particle[i].dim.x * m_particle[i].zoom; + dim.y = m_particle[i].dim.y * m_particle[i].zoom; + + Math::Vector corner[4]; + corner[0].x = dim.x; + corner[0].y = dim.y; + corner[0].z = 0.0f; + + corner[1].x = -dim.x; + corner[1].y = dim.y; + corner[1].z = 0.0f; + + corner[2].x = dim.x; + corner[2].y = -dim.y; + corner[2].z = 0.0f; + + corner[3].x = -dim.x; + corner[3].y = -dim.y; + corner[3].z = 0.0f; + + Vertex vertex[4]; + vertex[0] = Vertex(corner[1], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texSup.y)); + vertex[1] = Vertex(corner[0], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texSup.y)); + vertex[2] = Vertex(corner[3], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texInf.y)); + vertex[3] = Vertex(corner[2], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texInf.y)); + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); + m_engine->AddStatisticTriangle(2); } void CParticle::DrawParticleFog(int i) { - GetLogger()->Trace("CParticle::DrawParticleFog() stub!\n"); - // TODO! + if (!m_engine->GetFog()) return; + if (m_particle[i].intensity == 0.0f) return; + + Math::Vector pos = m_particle[i].pos; + + Math::Point dim; + dim.x = m_particle[i].dim.x; + dim.y = m_particle[i].dim.y; + + Math::Point zoom; + + if ( m_particle[i].type == PARTIFOG0 || + m_particle[i].type == PARTIFOG2 || + m_particle[i].type == PARTIFOG4 || + m_particle[i].type == PARTIFOG6 ) + { + zoom.x = 1.0f+sinf(m_particle[i].zoom*2.0f)/6.0f; + zoom.y = 1.0f+cosf(m_particle[i].zoom*2.7f)/6.0f; + } + if ( m_particle[i].type == PARTIFOG1 || + m_particle[i].type == PARTIFOG3 || + m_particle[i].type == PARTIFOG5 || + m_particle[i].type == PARTIFOG7 ) + { + zoom.x = 1.0f+sinf(m_particle[i].zoom*3.0f)/6.0f; + zoom.y = 1.0f+cosf(m_particle[i].zoom*3.7f)/6.0f; + } + + dim.x *= zoom.x; + dim.y *= zoom.y; + + CObject* object = m_particle[i].objLink; + if (object != nullptr) + pos += object->GetPosition(0); + + Math::Vector angle; + angle.x = Math::PI/2.0f; + angle.y = 0.0f; + angle.z = m_particle[i].angle; + + if (m_engine->GetRankView() == 1) // underwater? + pos.y -= 1.0f; + + Math::Vector eye = m_engine->GetEyePt(); + if (pos.y > eye.y) // seen from below? + angle.x = -Math::PI/2.0f; + + Math::Matrix mat; + Math::LoadRotationXZYMatrix(mat, angle); + mat.Set(1, 4, pos.x); + mat.Set(2, 4, pos.y); + mat.Set(3, 4, pos.z); + m_device->SetTransform(TRANSFORM_WORLD, mat); + + Math::Vector n(0.0f, 0.0f, -1.0f); + + Math::Vector corner[4]; + + corner[0].x = dim.x; + corner[0].y = dim.y; + corner[0].z = 0.0f; + + corner[1].x = -dim.x; + corner[1].y = dim.y; + corner[1].z = 0.0f; + + corner[2].x = dim.x; + corner[2].y = -dim.y; + corner[2].z = 0.0f; + + corner[3].x = -dim.x; + corner[3].y = -dim.y; + corner[3].z = 0.0f; + + Vertex vertex[4]; + + vertex[0] = Vertex(corner[1], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texSup.y)); + vertex[1] = Vertex(corner[0], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texSup.y)); + vertex[2] = Vertex(corner[3], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texInf.y)); + vertex[3] = Vertex(corner[2], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texInf.y)); + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); + m_engine->AddStatisticTriangle(2); } void CParticle::DrawParticleRay(int i) { - GetLogger()->Trace("CParticle::DrawParticleRay() stub!\n"); - // TODO! + if (m_particle[i].zoom == 0.0f) return; + if (m_particle[i].intensity == 0.0f) return; + + Math::Vector eye = m_engine->GetEyePt(); + Math::Vector pos = m_particle[i].pos; + Math::Vector goal = m_particle[i].goal; + + CObject* object = m_particle[i].objLink; + if (object != nullptr) + pos += object->GetPosition(0); + + float a = Math::RotateAngle(Math::Point(pos.x,pos.z), Math::Point(goal.x,goal.z), Math::Point(eye.x,eye.z)); + bool left = (a < Math::PI); + + Math::Vector proj = Math::Projection(pos, goal, eye); + Math::Vector angle; + angle.x = -Math::RotateAngle(Math::DistanceProjected(proj, eye), proj.y-eye.y); + angle.y = Math::RotateAngle(pos.z-goal.z, pos.x-goal.x)+Math::PI/2.0f; + angle.z = -Math::RotateAngle(Math::DistanceProjected(pos, goal), pos.y-goal.y); + if (left) angle.x = -angle.x; + + Math::Matrix mat; + Math::LoadRotationZXYMatrix(mat, angle); + mat.Set(1, 4, pos.x); + mat.Set(2, 4, pos.y); + mat.Set(3, 4, pos.z); + m_device->SetTransform(TRANSFORM_WORLD, mat); + + Math::Vector n(0.0f, 0.0f, left ? 1.0f : -1.0f); + + Math::Point dim; + dim.x = m_particle[i].dim.x * m_particle[i].zoom; + dim.y = m_particle[i].dim.y * m_particle[i].zoom; + + if (left) dim.y = -dim.y; + + float len = Math::Distance(pos, goal); + float adv = 0.0f; + + int step = static_cast((len/(dim.x*2.0f))+1); + + float vario1, vario2; + + if (step == 1) + { + vario1 = 1.0f; + vario2 = 1.0f; + } + else + { + vario1 = 0.0f; + vario2 = 2.0f; + } + + int first, last; + + if (m_particle[i].type == PARTIRAY2) + { + first = 0; + last = step; + vario1 = 0.0f; + vario2 = 0.0f; + } + else if (m_particle[i].type == PARTIRAY3) + { + if (m_particle[i].time < m_particle[i].duration*0.40f) + { + float prop = m_particle[i].time / (m_particle[i].duration*0.40f); + first = 0; + last = static_cast(prop*step); + } + else if (m_particle[i].time < m_particle[i].duration*0.60f) + { + first = 0; + last = step; + } + else + { + float prop = (m_particle[i].time-m_particle[i].duration*0.60f) / (m_particle[i].duration*0.40f); + first = static_cast(prop*step); + last = step; + } + } + else + { + if (m_particle[i].time < m_particle[i].duration*0.50f) + { + float prop = m_particle[i].time / (m_particle[i].duration*0.50f); + first = 0; + last = static_cast(prop*step); + } + else if (m_particle[i].time < m_particle[i].duration*0.75f) + { + first = 0; + last = step; + } + else + { + float prop = (m_particle[i].time-m_particle[i].duration*0.75f) / (m_particle[i].duration*0.25f); + first = static_cast(prop*step); + last = step; + } + } + + Math::Vector corner[4]; + + corner[0].x = adv; + corner[2].x = adv; + corner[0].y = dim.y; + corner[2].y = -dim.y; + corner[0].z = (Math::Rand()-0.5f)*vario1; + corner[1].z = (Math::Rand()-0.5f)*vario1; + corner[2].z = (Math::Rand()-0.5f)*vario1; + corner[3].z = (Math::Rand()-0.5f)*vario1; + + Vertex vertex[4]; + + for (int rank = 0; rank < step; rank++) + { + corner[1].x = corner[0].x; + corner[3].x = corner[2].x; + corner[0].x = adv+dim.x*2.0f+(Math::Rand()-0.5f)*vario2; + corner[2].x = adv+dim.x*2.0f+(Math::Rand()-0.5f)*vario2; + + corner[1].y = corner[0].y; + corner[3].y = corner[2].y; + corner[0].y = dim.y+(Math::Rand()-0.5f)*vario2; + corner[2].y = -dim.y+(Math::Rand()-0.5f)*vario2; + + if (rank >= first && rank <= last) + { + Math::Point texInf = m_particle[i].texInf; + Math::Point texSup = m_particle[i].texSup; + + int r = rand() % 16; + texInf.x += 0.25f*(r/4); + texSup.x += 0.25f*(r/4); + if (r % 2 < 1 && adv > 0.0f && m_particle[i].type != PARTIRAY1) + Math::Swap(texInf.x, texSup.x); + + if (r % 4 < 2) + Math::Swap(texInf.y, texSup.y); + + vertex[0] = Vertex(corner[1], n, Math::Point(texSup.x, texSup.y)); + vertex[1] = Vertex(corner[0], n, Math::Point(texInf.x, texSup.y)); + vertex[2] = Vertex(corner[3], n, Math::Point(texSup.x, texInf.y)); + vertex[3] = Vertex(corner[2], n, Math::Point(texInf.x, texInf.y)); + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); + m_engine->AddStatisticTriangle(2); + } + adv += dim.x*2.0f; + } } void CParticle::DrawParticleSphere(int i) { - GetLogger()->Trace("CParticle::DrawParticleSphere() stub!\n"); - // TODO! + float zoom = m_particle[i].zoom; + + if (zoom == 0.0f) return; + + m_engine->SetState(ENG_RSTATE_TTEXTURE_BLACK | ENG_RSTATE_2FACE | ENG_RSTATE_WRAP, + IntensityToColor(m_particle[i].intensity)); + + Math::Matrix mat; + mat.LoadIdentity(); + mat.Set(1, 1, zoom); + mat.Set(2, 2, zoom); + mat.Set(3, 3, zoom); + mat.Set(1, 4, m_particle[i].pos.x); + mat.Set(2, 4, m_particle[i].pos.y); + mat.Set(3, 4, m_particle[i].pos.z); + + if (m_particle[i].angle != 0.0f) + { + Math::Vector angle; + angle.x = m_particle[i].angle*0.4f; + angle.y = m_particle[i].angle*1.0f; + angle.z = m_particle[i].angle*0.7f; + Math::Matrix rot; + Math::LoadRotationZXYMatrix(rot, angle); + mat = Math::MultiplyMatrices(rot, mat); + } + + m_device->SetTransform(TRANSFORM_WORLD, mat); + + Math::Point ts, ti; + ts.x = m_particle[i].texSup.x; + ts.y = m_particle[i].texSup.y; + ti.x = m_particle[i].texInf.x; + ti.y = m_particle[i].texInf.y; + + int numRings, numSegments; + + // Choose a tesselation level. + if ( m_particle[i].type == PARTISPHERE3 || + m_particle[i].type == PARTISPHERE5 ) + { + numRings = 16; + numSegments = 16; + } + else + { + numRings = 8; + numSegments = 10; + } + + // Establish constants used in sphere generation. + float deltaRingAngle = Math::PI/numRings; + float deltaSegAngle = 2.0f*Math::PI/numSegments; + + Vertex vertex[2*16*(16+1)]; + + // Generate the group of rings for the sphere. + int j = 0; + for (int ring = 0; ring < numRings; ring++) + { + float r0 = sinf((ring+0)*deltaRingAngle); + float r1 = sinf((ring+1)*deltaRingAngle); + + Math::Vector v0, v1; + + v0.y = cosf((ring+0)*deltaRingAngle); + v1.y = cosf((ring+1)*deltaRingAngle); + + float tv0 = (ring+0)/static_cast(numRings); + float tv1 = (ring+1)/static_cast(numRings); + tv0 = ts.y+(ti.y-ts.y)*tv0; + tv1 = ts.y+(ti.y-ts.y)*tv1; + + // Generate the group of segments for the current ring. + for (int seg = 0; seg < numSegments+1; seg++) + { + v0.x = r0*sinf(seg*deltaSegAngle); + v0.z = r0*cosf(seg*deltaSegAngle); + v1.x = r1*sinf(seg*deltaSegAngle); + v1.z = r1*cosf(seg*deltaSegAngle); + + // Add two vertices to the strip which makes up the sphere. + float tu0 = (static_cast(seg))/numSegments; + tu0 = ts.x+(ti.x-ts.x)*tu0; + float tu1 = tu0; + + vertex[j++] = Vertex(v0, v0, Math::Point(tu0, tv0)); + vertex[j++] = Vertex(v1, v1, Math::Point(tu1, tv1)); + } + } + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, j); + m_engine->AddStatisticTriangle(j); + + m_engine->SetState(ENG_RSTATE_TTEXTURE_BLACK, IntensityToColor(m_particle[i].intensity)); +} + +//! Returns the height depending on the progress +float ProgressCylinder(float progress) +{ + if (progress < 0.5f) + return 1.0f - (powf(1.0f-progress*2.0f, 2.0f)); + else + return 1.0f - (powf(progress*2.0f-1.0f, 2.0f)); } void CParticle::DrawParticleCylinder(int i) { - GetLogger()->Trace("CParticle::DrawParticleCylinder() stub!\n"); - // TODO! + float progress = m_particle[i].zoom; + float zoom = m_particle[i].dim.x; + float diam = m_particle[i].dim.y; + if (progress >= 1.0f || zoom == 0.0f) return; + + m_engine->SetState(ENG_RSTATE_TTEXTURE_BLACK | ENG_RSTATE_2FACE | ENG_RSTATE_WRAP, + IntensityToColor(m_particle[i].intensity)); + + Math::Matrix mat; + mat.LoadIdentity(); + mat.Set(1, 1, zoom); + mat.Set(2, 2, zoom); + mat.Set(3, 3, zoom); + mat.Set(1, 4, m_particle[i].pos.x); + mat.Set(2, 4, m_particle[i].pos.y); + mat.Set(3, 4, m_particle[i].pos.z); + m_device->SetTransform(TRANSFORM_WORLD, mat); + + Math::Point ts, ti; + ts.x = m_particle[i].texSup.x; + ts.y = m_particle[i].texSup.y; + ti.x = m_particle[i].texInf.x; + ti.y = m_particle[i].texInf.y; + + int numRings = 5; + int numSegments = 10; + float deltaSegAngle = 2.0f*Math::PI/numSegments; + + float h[6] = { 0.0f }; + float d[6] = { 0.0f }; + + if (m_particle[i].type == PARTIPLOUF0) + { + float p1 = progress; // front + float p2 = powf(progress, 5.0f); // back + + for (int ring = 0; ring <= numRings; ring++) + { + float pp = p2+(p1-p2)*(static_cast(ring)/numRings); + d[ring] = diam/zoom+pp*2.0f; + h[ring] = ProgressCylinder(pp); + } + } + + Vertex vertex[2*5*(10+1)]; + + int j = 0; + for (int ring = 0; ring < numRings; ring++) + { + Math::Vector v0, v1; + + float r0 = 1.0f*d[ring+0]; // radius at the base + float r1 = 1.0f*d[ring+1]; // radius at the top + + v0.y = 1.0f*h[ring+0]; // bottom + v1.y = 1.0f*h[ring+1]; // top + + float tv0 = 1.0f-(ring+0)*(1.0f/numRings); + float tv1 = 1.0f-(ring+1)*(1.0f/numRings); + tv0 = ts.y+(ti.y-ts.y)*tv0; + tv1 = ts.y+(ti.y-ts.y)*tv1; + + for (int seg = 0; seg < numSegments+1; seg++) + { + v0.x = r0*sinf(seg*deltaSegAngle); + v0.z = r0*cosf(seg*deltaSegAngle); + v1.x = r1*sinf(seg*deltaSegAngle); + v1.z = r1*cosf(seg*deltaSegAngle); + + float tu0 = (seg % 2) ? 0.0f : 1.0f; + tu0 = ts.x+(ti.x-ts.x)*tu0; + float tu1 = tu0; + + vertex[j++] = Vertex(v0, v0, Math::Point(tu0, tv0)); + vertex[j++] = Vertex(v1, v1, Math::Point(tu1, tv1)); + } + } + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, j); + m_engine->AddStatisticTriangle(j); + + m_engine->SetState(ENG_RSTATE_TTEXTURE_BLACK, IntensityToColor(m_particle[i].intensity)); } void CParticle::DrawParticleWheel(int i) { - GetLogger()->Trace("CParticle::DrawParticleWheel() stub!\n"); - // TODO! + float dist = Math::DistanceProjected(m_engine->GetEyePt(), m_wheelTrace[i].pos[0]); + if (dist > 300.0f) return; + + Math::Vector pos[4]; + pos[0] = m_wheelTrace[i].pos[0]; + pos[1] = m_wheelTrace[i].pos[1]; + pos[2] = m_wheelTrace[i].pos[2]; + pos[3] = m_wheelTrace[i].pos[3]; + + Math::Point ts; + + if (m_wheelTrace[i].type == PARTITRACE0) // white ground track? + { + ts.x = 8.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE1) // black ground track? + { + ts.x = 0.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE2) // gray ground track? + { + ts.x = 0.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE3) // light gray ground track? + { + ts.x = 8.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE4) // red ground track? + { + ts.x = 32.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE5) // pink ground track? + { + ts.x = 40.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE6) // violet ground track? + { + ts.x = 32.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE7) // orange ground track? + { + ts.x = 40.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE8) // yellow ground track? + { + ts.x = 16.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE9) // beige ground track? + { + ts.x = 24.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE10) // brown ground track? + { + ts.x = 16.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE11) // skin ground track? + { + ts.x = 24.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE12) // green ground track? + { + ts.x = 48.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE13) // light green ground track? + { + ts.x = 56.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE14) // blue ground track? + { + ts.x = 48.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE15) // light blue ground track? + { + ts.x = 56.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE16) // black arrow ground track? + { + ts.x = 160.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if (m_wheelTrace[i].type == PARTITRACE17) // red arrow ground track? + { + ts.x = 176.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else + { + return; + } + + Math::Point ti; + + if ( m_wheelTrace[i].type == PARTITRACE16 || + m_wheelTrace[i].type == PARTITRACE17 ) + { + ti.x = ts.x+16.0f/256.0f; + ti.y = ts.y+16.0f/256.0f; + } + else + { + ti.x = ts.x+8.0f/256.0f; + ti.y = ts.y+8.0f/256.0f; + } + + float dp = (1.0f/256.0f)/2.0f; + ts.x = ts.x+dp; + ts.y = ts.y+dp; + ti.x = ti.x-dp; + ti.y = ti.y-dp; + + Math::Vector n(0.0f, 1.0f, 0.0f); + + Vertex vertex[4]; + vertex[0] = Vertex(pos[0], n, Math::Point(ts.x, ts.y)); + vertex[1] = Vertex(pos[1], n, Math::Point(ti.x, ts.y)); + vertex[2] = Vertex(pos[2], n, Math::Point(ts.x, ti.y)); + vertex[3] = Vertex(pos[3], n, Math::Point(ti.x, ti.y)); + + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); + m_engine->AddStatisticTriangle(2); } -CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos, ParticleType type, CObject *father) +void CParticle::DrawParticle(int sheet) { - GetLogger()->Trace("CParticle::SearchObjectGun() stub!\n"); - // TODO! - return nullptr; + // Draw the basic particles of triangles. + if (m_totalInterface[0][sheet] > 0) + { + for (int i = 0; i < MAXPARTICULE; i++) + { + if (!m_particle[i].used) continue; + if (m_particle[i].sheet != sheet) continue; + if (m_particle[i].type == PARTIPART) continue; + + m_engine->SetTexture(m_triangle[i].tex1Name); + m_engine->SetMaterial(m_triangle[i].material); + m_engine->SetState(m_triangle[i].state); + DrawParticleTriangle(i); + } + } + + Material mat; + mat.diffuse.r = 1.0f; + mat.diffuse.g = 1.0f; + mat.diffuse.b = 1.0f; // white + mat.ambient.r = 0.5f; + mat.ambient.g = 0.5f; + mat.ambient.b = 0.5f; + m_engine->SetMaterial(mat); + + // Draw tire marks. + if (m_wheelTraceTotal > 0 && sheet == SH_WORLD) + { + m_engine->SetTexture("text.png"); + m_engine->SetState(ENG_RSTATE_TTEXTURE_WHITE); + Math::Matrix mat; + mat.LoadIdentity(); + m_device->SetTransform(TRANSFORM_WORLD, mat); + + for (int i = 0; i < m_wheelTraceTotal; i++) + DrawParticleWheel(i); + } + + for (int t = MAXPARTITYPE-1; t >= 1; t--) // black behind! + { + if (m_totalInterface[t][sheet] == 0) continue; + + bool loadTexture = false; + + int state; + if (t == 4) state = ENG_RSTATE_TTEXTURE_WHITE; // text.png + else state = ENG_RSTATE_TTEXTURE_BLACK; // effect[00..02].png + m_engine->SetState(state); + + for (int j = 0; j < MAXPARTICULE; j++) + { + int i = MAXPARTICULE*t+j; + if (!m_particle[i].used) continue; + if (m_particle[i].sheet != sheet) continue; + + if (!loadTexture) + { + std::string name; + NameParticle(name, t); + m_engine->SetTexture(name); + loadTexture = true; + } + + int r = m_particle[i].trackRank; + if (r != -1) + { + m_engine->SetState(state); + TrackDraw(r, m_particle[i].type); // draws the drag + if (!m_track[r].drawParticle) continue; + } + + m_engine->SetState(state, IntensityToColor(m_particle[i].intensity)); + + if (m_particle[i].ray) // ray? + { + DrawParticleRay(i); + } + else if ( m_particle[i].type == PARTIFLIC || // circle in the water? + m_particle[i].type == PARTISHOW || + m_particle[i].type == PARTICHOC || + m_particle[i].type == PARTIGFLAT ) + { + DrawParticleFlat(i); + } + else if ( m_particle[i].type >= PARTIFOG0 && + m_particle[i].type <= PARTIFOG9 ) + { + DrawParticleFog(i); + } + else if ( m_particle[i].type >= PARTISPHERE0 && + m_particle[i].type <= PARTISPHERE9 ) // sphere? + { + DrawParticleSphere(i); + } + else if ( m_particle[i].type >= PARTIPLOUF0 && + m_particle[i].type <= PARTIPLOUF4 ) // cylinder? + { + DrawParticleCylinder(i); + } + else // normal? + { + DrawParticleNorm(i); + } + } + } } -CObject* CParticle::SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticleType type, CObject *father) +CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos, + ParticleType type, CObject *father) { - GetLogger()->Trace("CParticle::SearchObjectRay() stub!\n"); - // TODO! + if (m_main->GetMovieLock()) return nullptr; // current movie? + + bool himself = m_main->GetHimselfDamage(); + + float min = 5.0f; + if (type == PARTIGUN2) min = 2.0f; // shooting insect? + if (type == PARTIGUN3) min = 3.0f; // suiciding spider? + + Math::Vector box1 = old; + Math::Vector box2 = pos; + if (box1.x > box2.x) Math::Swap(box1.x, box2.x); // box1 < box2 + if (box1.y > box2.y) Math::Swap(box1.y, box2.y); + if (box1.z > box2.z) Math::Swap(box1.z, box2.z); + box1.x -= min; + box1.y -= min; + box1.z -= min; + box2.x += min; + box2.y += min; + box2.z += min; + + CObject* best = 0; + bool shield = false; + for (int i = 0; i < 1000000; i++) + { + CObject* obj = static_cast(m_iMan->SearchInstance(CLASS_OBJECT, i)); + if (obj == 0) break; + + if (!obj->GetActif()) continue; // inactive? + if (obj == father) continue; + + ObjectType oType = obj->GetType(); + + if (oType == OBJECT_TOTO) continue; + + if (type == PARTIGUN1) // fireball shooting? + { + if (oType == OBJECT_MOTHER) continue; + if (himself) // damage is oneself? + { + if ( !IsAlien(oType) && + !IsSoft(oType) ) continue; + } + else // damage only to enemies? + { + if (!IsAlien(oType)) continue; + } + } + else if (type == PARTIGUN2) // shooting insect? + { + if (!IsSoft(oType)) continue; + } + else if (type == PARTIGUN3) // suiciding spider? + { + if (!IsSoft(oType)) continue; + } + else if (type == PARTIGUN4) // orgaball shooting? + { + if (oType == OBJECT_MOTHER) continue; + if (himself) // damage is oneself? + { + if ( !IsAlien(oType) && + !IsSoft(oType) ) continue; + } + else // damage only to enemies? + { + if (!IsAlien(oType)) continue; + } + } + else if (type == PARTITRACK11) // phazer shooting? + { + if (himself) // damage is oneself? + { + if ( !IsAlien(oType) && + !IsSoft(oType) ) continue; + } + else // damage only to enemies? + { + if (!IsAlien(oType)) continue; + } + } + else + { + continue; + } + + Math::Vector oPos = obj->GetPosition(0); + + if ( type == PARTIGUN2 || // shooting insect? + type == PARTIGUN3 ) // suiciding spider? + { + // Test if the ball is entered into the sphere of a shield. + float shieldRadius = obj->GetShieldRadius(); + if (shieldRadius > 0.0f) + { + float dist = Math::Distance(oPos, pos); + if (dist <= shieldRadius) + { + best = obj; + shield = true; + } + } + } + if (shield) continue; + + // Test the center of the object, which is necessary for objects + // that have no sphere in the center (station). + float dist = Math::Distance(oPos, pos)-4.0f; + if (dist < min) + best = obj; + + // Test with all spheres of the object. + int j = 0; + float oRadius; + while (obj->GetCrashSphere(j++, oPos, oRadius)) + { + if ( oPos.x+oRadius < box1.x || oPos.x-oRadius > box2.x || // outside the box? + oPos.y+oRadius < box1.y || oPos.y-oRadius > box2.y || + oPos.z+oRadius < box1.z || oPos.z-oRadius > box2.z ) continue; + + Math::Vector p = Math::Projection(old, pos, oPos); + float ddist = Math::Distance(p, oPos)-oRadius; + if (ddist < min) + best = obj; + } + } + + return best; +} + +CObject* CParticle::SearchObjectRay(Math::Vector pos, Math::Vector goal, + ParticleType type, CObject *father) +{ + if (m_main->GetMovieLock()) return nullptr; // current movie? + + float min = 10.0f; + + Math::Vector box1 = pos; + Math::Vector box2 = goal; + if (box1.x > box2.x) Math::Swap(box1.x, box2.x); // box1 < box2 + if (box1.y > box2.y) Math::Swap(box1.y, box2.y); + if (box1.z > box2.z) Math::Swap(box1.z, box2.z); + box1.x -= min; + box1.y -= min; + box1.z -= min; + box2.x += min; + box2.y += min; + box2.z += min; + + for (int i = 0; i < 1000000; i++) + { + CObject* obj = static_cast( m_iMan->SearchInstance(CLASS_OBJECT, i) ); + if (obj == nullptr) break; + + if (!obj->GetActif()) continue; // inactive? + if (obj == father) continue; + + ObjectType oType = obj->GetType(); + + if (oType == OBJECT_TOTO) continue; + + if ( type == PARTIRAY1 && + oType != OBJECT_MOBILEtg && + oType != OBJECT_TEEN28 && + oType != OBJECT_TEEN31 && + oType != OBJECT_ANT && + oType != OBJECT_SPIDER && + oType != OBJECT_BEE && + oType != OBJECT_WORM && + oType != OBJECT_MOTHER && + oType != OBJECT_NEST ) continue; + + Math::Vector oPos = obj->GetPosition(0); + + if ( oPos.x < box1.x || oPos.x > box2.x || // outside the box? + oPos.y < box1.y || oPos.y > box2.y || + oPos.z < box1.z || oPos.z > box2.z ) continue; + + Math::Vector p = Math::Projection(pos, goal, oPos); + float dist = Math::Distance(p, oPos); + if (dist < min) return obj; + } + return nullptr; } void CParticle::Play(Sound sound, Math::Vector pos, float amplitude) { - GetLogger()->Trace("CParticle::Play() stub!\n"); - // TODO! + if (m_sound == nullptr) + m_sound = static_cast(m_iMan->SearchInstance(CLASS_SOUND)); + + m_sound->Play(sound, pos, amplitude); } -bool CParticle::TrackMove(int i, Math::Vector pos, float progress) +Color CParticle::GetFogColor(Math::Vector pos) { - GetLogger()->Trace("CParticle::TrackMove() stub!\n"); - // TODO! + Color result; + result.r = 0.0f; + result.g = 0.0f; + result.b = 0.0f; + result.a = 0.0f; + + for (int fog = 0; fog < m_fogTotal; fog++) + { + int i = m_fog[fog]; // i = rank of the particle + + if (pos.y >= m_particle[i].pos.y+FOG_HSUP) continue; + if (pos.y <= m_particle[i].pos.y-FOG_HINF) continue; + + float dist = Math::DistanceProjected(pos, m_particle[i].pos); + if (dist >= m_particle[i].dim.x*1.5f) continue; + + // Calculates the horizontal distance. + float factor = 1.0f-powf(dist/(m_particle[i].dim.x*1.5f), 4.0f); + + // Calculates the vertical distance. + if (pos.y > m_particle[i].pos.y) + factor *= 1.0f-(pos.y-m_particle[i].pos.y)/FOG_HSUP; + else + factor *= 1.0f-(m_particle[i].pos.y-pos.y)/FOG_HINF; + + factor *= 0.3f; + + Color color; + + if ( m_particle[i].type == PARTIFOG0 || + m_particle[i].type == PARTIFOG1 ) // blue? + { + color.r = 0.0f; + color.g = 0.5f; + color.b = 1.0f; + } + else if ( m_particle[i].type == PARTIFOG2 || + m_particle[i].type == PARTIFOG3 ) // red? + { + color.r = 2.0f; + color.g = 1.0f; + color.b = 0.0f; + } + else if ( m_particle[i].type == PARTIFOG4 || + m_particle[i].type == PARTIFOG5 ) // white? + { + color.r = 1.0f; + color.g = 1.0f; + color.b = 1.0f; + } + else if ( m_particle[i].type == PARTIFOG6 || + m_particle[i].type == PARTIFOG7 ) // yellow? + { + color.r = 0.8f; + color.g = 1.0f; + color.b = 0.4f; + } + else + { + color.r = 0.0f; + color.g = 0.0f; + color.b = 0.0f; + } + + result.r += color.r*factor; + result.g += color.g*factor; + result.b += color.b*factor; + } + + if (result.r > 0.6f) result.r = 0.6f; + if (result.g > 0.6f) result.g = 0.6f; + if (result.b > 0.6f) result.b = 0.6f; + + return result; +} + +bool CParticle::WriteWheelTrace(const char *filename, int width, int height, + Math::Vector dl, Math::Vector ur) +{ + // TODO: stub! + GetLogger()->Trace("CParticle::WriteWheelTrace(): stub!\n"); return true; } -void CParticle::TrackDraw(int i, ParticleType type) -{ - GetLogger()->Trace("CParticle::TrackDraw() stub!\n"); - // TODO! -} - - } // namespace Gfx diff --git a/src/graphics/engine/particle.h b/src/graphics/engine/particle.h index 33a5c1be..d03b3fcb 100644 --- a/src/graphics/engine/particle.h +++ b/src/graphics/engine/particle.h @@ -17,7 +17,7 @@ /** * \file graphics/engine/particle.h - * \brief Particle rendering - CParticle class (aka particule) + * \brief Particle rendering - CParticle class (aka particle) */ #pragma once @@ -46,7 +46,7 @@ const short MAXWHEELTRACE = 1000; const short SH_WORLD = 0; // particle in the world in the interface const short SH_FRONT = 1; // particle in the world on the interface -const short SH_INTERFACE = 2; // particle in the interface +const short SH_INTERFACE = 2; // particle in the interface const short SH_MAX = 3; // type == 0 -> triangles @@ -58,145 +58,145 @@ const short SH_MAX = 3; enum ParticleType { - PARTIEXPLOT = 1, // technology explosion - PARTIEXPLOO = 2, // organic explosion - PARTIMOTOR = 3, // the engine exhaust gas - PARTIGLINT = 4, // reflection - PARTIBLITZ = 5, // lightning recharging battery - PARTICRASH = 6, // dust after fall - PARTIGAS = 7, // gas from the reactor - PARTIFIRE = 9, // fireball shrinks - PARTIFIREZ = 10, // fireball grows - PARTIBLUE = 11, // blue ball - PARTISELY = 12, // yellow selection - PARTISELR = 13, // red selection - PARTIGUN1 = 18, // a bullet (fireball) - PARTIGUN2 = 19, // bullet 2 (ant) - PARTIGUN3 = 20, // bullet 3 (spider) - PARTIGUN4 = 21, // bullet 4 (orgaball) - PARTIFRAG = 22, // triangular fragment - PARTIQUEUE = 23, // inflamed tail - PARTIORGANIC1 = 24, // organic ball mother - PARTIORGANIC2 = 25, // organic ball daughter - PARTISMOKE1 = 26, // black smoke - PARTISMOKE2 = 27, // black smoke - PARTISMOKE3 = 28, // black smoke - PARTISMOKE4 = 29, // black smoke - PARTIBLOOD = 30, // human blood - PARTIBLOODM = 31, // blood laying - PARTIVAPOR = 32, // steam - PARTIVIRUS1 = 33, // virus 1 - PARTIVIRUS2 = 34, // virus 2 - PARTIVIRUS3 = 35, // virus 3 - PARTIVIRUS4 = 36, // virus 4 - PARTIVIRUS5 = 37, // virus 5 - PARTIVIRUS6 = 38, // virus 6 - PARTIVIRUS7 = 39, // virus 7 - PARTIVIRUS8 = 40, // virus 8 - PARTIVIRUS9 = 41, // virus 9 - PARTIVIRUS10 = 42, // virus 10 - PARTIRAY1 = 43, // ray 1 (turn) - PARTIRAY2 = 44, // ray 2 (electric arc) - PARTIRAY3 = 45, // ray 3 - PARTIRAY4 = 46, // ray 4 - PARTIFLAME = 47, // flame - PARTIBUBBLE = 48, // bubble - PARTIFLIC = 49, // circles in the water - PARTIEJECT = 50, // ejection from the reactor - PARTISCRAPS = 51, // waste from the reactor - PARTITOTO = 52, // reactor of tot - PARTIERROR = 53, // toto says no - PARTIWARNING = 54, // foo says blah - PARTIINFO = 54, // toto says yes - PARTIQUARTZ = 55, // reflection crystal - PARTISPHERE0 = 56, // explosion sphere - PARTISPHERE1 = 57, // energy sphere - PARTISPHERE2 = 58, // analysis sphere - PARTISPHERE3 = 59, // shield sphere - PARTISPHERE4 = 60, // information sphere (emit) - PARTISPHERE5 = 61, // botanical sphere (gravity root) - PARTISPHERE6 = 62, // information sphere (receive) - PARTISPHERE7 = 63, // sphere - PARTISPHERE8 = 64, // sphere - PARTISPHERE9 = 65, // sphere - PARTIGUNDEL = 66, // bullet destroyed by shield - PARTIPART = 67, // object part - PARTITRACK1 = 68, // drag 1 - PARTITRACK2 = 69, // drag 2 - PARTITRACK3 = 70, // drag 3 - PARTITRACK4 = 71, // drag 4 - PARTITRACK5 = 72, // drag 5 - PARTITRACK6 = 73, // drag 6 - PARTITRACK7 = 74, // drag 7 - PARTITRACK8 = 75, // drag 8 - PARTITRACK9 = 76, // drag 9 - PARTITRACK10 = 77, // drag 10 - PARTITRACK11 = 78, // drag 11 - PARTITRACK12 = 79, // drag 12 - PARTITRACK13 = 80, // drag 13 - PARTITRACK14 = 81, // drag 14 - PARTITRACK15 = 82, // drag 15 - PARTITRACK16 = 83, // drag 16 - PARTITRACK17 = 84, // drag 17 - PARTITRACK18 = 85, // drag 18 - PARTITRACK19 = 86, // drag 19 - PARTITRACK20 = 87, // drag 20 - PARTIGLINTb = 88, // blue reflection - PARTIGLINTr = 89, // red reflection - PARTILENS1 = 90, // brilliance 1 (orange) - PARTILENS2 = 91, // brilliance 2 (yellow) - PARTILENS3 = 92, // brilliance 3 (red) - PARTILENS4 = 93, // brilliance 4 (violet) - PARTICONTROL = 94, // reflection on button - PARTISHOW = 95, // shows a place - PARTICHOC = 96, // shock wave - PARTIGFLAT = 97, // shows if the ground is flat - PARTIRECOVER = 98, // blue ball recycler - PARTIROOT = 100, // gravity root smoke - PARTIPLOUF0 = 101, // splash - PARTIPLOUF1 = 102, // splash - PARTIPLOUF2 = 103, // splash - PARTIPLOUF3 = 104, // splash - PARTIPLOUF4 = 105, // splash - PARTIDROP = 106, // drop - PARTIFOG0 = 107, // fog 0 - PARTIFOG1 = 108, // fog 1 - PARTIFOG2 = 109, // fog 2 - PARTIFOG3 = 110, // fog 3 - PARTIFOG4 = 111, // fog 4 - PARTIFOG5 = 112, // fog 5 - PARTIFOG6 = 113, // fog 6 - PARTIFOG7 = 114, // fog 7 - PARTIFOG8 = 115, // fog 8 - PARTIFOG9 = 116, // fog 9 - PARTILIMIT1 = 117, // shows the limits 1 - PARTILIMIT2 = 118, // shows the limits 2 - PARTILIMIT3 = 119, // shows the limits 3 - PARTILIMIT4 = 120, // shows the limits 4 - PARTIWATER = 121, // drop of water - PARTIEXPLOG1 = 122, // ball explosion 1 - PARTIEXPLOG2 = 123, // ball explosion 2 - PARTIBASE = 124, // gases of spaceship - PARTITRACE0 = 140, // trace - PARTITRACE1 = 141, // trace - PARTITRACE2 = 142, // trace - PARTITRACE3 = 143, // trace - PARTITRACE4 = 144, // trace - PARTITRACE5 = 145, // trace - PARTITRACE6 = 146, // trace - PARTITRACE7 = 147, // trace - PARTITRACE8 = 148, // trace - PARTITRACE9 = 149, // trace - PARTITRACE10 = 150, // trace - PARTITRACE11 = 151, // trace - PARTITRACE12 = 152, // trace - PARTITRACE13 = 153, // trace - PARTITRACE14 = 154, // trace - PARTITRACE15 = 155, // trace - PARTITRACE16 = 156, // trace - PARTITRACE17 = 157, // trace - PARTITRACE18 = 158, // trace - PARTITRACE19 = 159, // trace + PARTIEXPLOT = 1, //! < technology explosion + PARTIEXPLOO = 2, //! < organic explosion + PARTIMOTOR = 3, //! < the engine exhaust gas + PARTIGLINT = 4, //! < reflection + PARTIBLITZ = 5, //! < lightning recharging battery + PARTICRASH = 6, //! < dust after fall + PARTIGAS = 7, //! < gas from the reactor + PARTIFIRE = 9, //! < fireball shrinks + PARTIFIREZ = 10, //! < fireball grows + PARTIBLUE = 11, //! < blue ball + PARTISELY = 12, //! < yellow selection + PARTISELR = 13, //! < red selection + PARTIGUN1 = 18, //! < a bullet (fireball) + PARTIGUN2 = 19, //! < bullet 2 (ant) + PARTIGUN3 = 20, //! < bullet 3 (spider) + PARTIGUN4 = 21, //! < bullet 4 (orgaball) + PARTIFRAG = 22, //! < triangular fragment + PARTIQUEUE = 23, //! < inflamed tail + PARTIORGANIC1 = 24, //! < organic ball mother + PARTIORGANIC2 = 25, //! < organic ball daughter + PARTISMOKE1 = 26, //! < black smoke + PARTISMOKE2 = 27, //! < black smoke + PARTISMOKE3 = 28, //! < black smoke + PARTISMOKE4 = 29, //! < black smoke + PARTIBLOOD = 30, //! < human blood + PARTIBLOODM = 31, //! < blood laying + PARTIVAPOR = 32, //! < steam + PARTIVIRUS1 = 33, //! < virus 1 + PARTIVIRUS2 = 34, //! < virus 2 + PARTIVIRUS3 = 35, //! < virus 3 + PARTIVIRUS4 = 36, //! < virus 4 + PARTIVIRUS5 = 37, //! < virus 5 + PARTIVIRUS6 = 38, //! < virus 6 + PARTIVIRUS7 = 39, //! < virus 7 + PARTIVIRUS8 = 40, //! < virus 8 + PARTIVIRUS9 = 41, //! < virus 9 + PARTIVIRUS10 = 42, //! < virus 10 + PARTIRAY1 = 43, //! < ray 1 (turn) + PARTIRAY2 = 44, //! < ray 2 (electric arc) + PARTIRAY3 = 45, //! < ray 3 + PARTIRAY4 = 46, //! < ray 4 + PARTIFLAME = 47, //! < flame + PARTIBUBBLE = 48, //! < bubble + PARTIFLIC = 49, //! < circles in the water + PARTIEJECT = 50, //! < ejection from the reactor + PARTISCRAPS = 51, //! < waste from the reactor + PARTITOTO = 52, //! < reactor of tot + PARTIERROR = 53, //! < toto says no + PARTIWARNING = 54, //! < foo says blah + PARTIINFO = 54, //! < toto says yes + PARTIQUARTZ = 55, //! < reflection crystal + PARTISPHERE0 = 56, //! < explosion sphere + PARTISPHERE1 = 57, //! < energy sphere + PARTISPHERE2 = 58, //! < analysis sphere + PARTISPHERE3 = 59, //! < shield sphere + PARTISPHERE4 = 60, //! < information sphere (emit) + PARTISPHERE5 = 61, //! < botanical sphere (gravity root) + PARTISPHERE6 = 62, //! < information sphere (receive) + PARTISPHERE7 = 63, //! < sphere + PARTISPHERE8 = 64, //! < sphere + PARTISPHERE9 = 65, //! < sphere + PARTIGUNDEL = 66, //! < bullet destroyed by shield + PARTIPART = 67, //! < object part + PARTITRACK1 = 68, //! < drag 1 + PARTITRACK2 = 69, //! < drag 2 + PARTITRACK3 = 70, //! < drag 3 + PARTITRACK4 = 71, //! < drag 4 + PARTITRACK5 = 72, //! < drag 5 + PARTITRACK6 = 73, //! < drag 6 + PARTITRACK7 = 74, //! < drag 7 + PARTITRACK8 = 75, //! < drag 8 + PARTITRACK9 = 76, //! < drag 9 + PARTITRACK10 = 77, //! < drag 10 + PARTITRACK11 = 78, //! < drag 11 + PARTITRACK12 = 79, //! < drag 12 + PARTITRACK13 = 80, //! < drag 13 + PARTITRACK14 = 81, //! < drag 14 + PARTITRACK15 = 82, //! < drag 15 + PARTITRACK16 = 83, //! < drag 16 + PARTITRACK17 = 84, //! < drag 17 + PARTITRACK18 = 85, //! < drag 18 + PARTITRACK19 = 86, //! < drag 19 + PARTITRACK20 = 87, //! < drag 20 + PARTIGLINTb = 88, //! < blue reflection + PARTIGLINTr = 89, //! < red reflection + PARTILENS1 = 90, //! < brilliance 1 (orange) + PARTILENS2 = 91, //! < brilliance 2 (yellow) + PARTILENS3 = 92, //! < brilliance 3 (red) + PARTILENS4 = 93, //! < brilliance 4 (violet) + PARTICONTROL = 94, //! < reflection on button + PARTISHOW = 95, //! < shows a place + PARTICHOC = 96, //! < shock wave + PARTIGFLAT = 97, //! < shows if the ground is flat + PARTIRECOVER = 98, //! < blue ball recycler + PARTIROOT = 100, //! < gravity root smoke + PARTIPLOUF0 = 101, //! < splash + PARTIPLOUF1 = 102, //! < splash + PARTIPLOUF2 = 103, //! < splash + PARTIPLOUF3 = 104, //! < splash + PARTIPLOUF4 = 105, //! < splash + PARTIDROP = 106, //! < drop + PARTIFOG0 = 107, //! < fog 0 + PARTIFOG1 = 108, //! < fog 1 + PARTIFOG2 = 109, //! < fog 2 + PARTIFOG3 = 110, //! < fog 3 + PARTIFOG4 = 111, //! < fog 4 + PARTIFOG5 = 112, //! < fog 5 + PARTIFOG6 = 113, //! < fog 6 + PARTIFOG7 = 114, //! < fog 7 + PARTIFOG8 = 115, //! < fog 8 + PARTIFOG9 = 116, //! < fog 9 + PARTILIMIT1 = 117, //! < shows the limits 1 + PARTILIMIT2 = 118, //! < shows the limits 2 + PARTILIMIT3 = 119, //! < shows the limits 3 + PARTILIMIT4 = 120, //! < shows the limits 4 + PARTIWATER = 121, //! < drop of water + PARTIEXPLOG1 = 122, //! < ball explosion 1 + PARTIEXPLOG2 = 123, //! < ball explosion 2 + PARTIBASE = 124, //! < gases of spaceship + PARTITRACE0 = 140, //! < trace + PARTITRACE1 = 141, //! < trace + PARTITRACE2 = 142, //! < trace + PARTITRACE3 = 143, //! < trace + PARTITRACE4 = 144, //! < trace + PARTITRACE5 = 145, //! < trace + PARTITRACE6 = 146, //! < trace + PARTITRACE7 = 147, //! < trace + PARTITRACE8 = 148, //! < trace + PARTITRACE9 = 149, //! < trace + PARTITRACE10 = 150, //! < trace + PARTITRACE11 = 151, //! < trace + PARTITRACE12 = 152, //! < trace + PARTITRACE13 = 153, //! < trace + PARTITRACE14 = 154, //! < trace + PARTITRACE15 = 155, //! < trace + PARTITRACE16 = 156, //! < trace + PARTITRACE17 = 157, //! < trace + PARTITRACE18 = 158, //! < trace + PARTITRACE19 = 159, //! < trace }; enum ParticlePhase @@ -262,7 +262,7 @@ struct WheelTrace * \class CParticle * \brief Particle engine * - * Functions are only stubs for now. + * TODO: documentation */ class CParticle { @@ -270,28 +270,49 @@ public: CParticle(CInstanceManager* iMan, CEngine* engine); ~CParticle(); + //! Sets the device to use void SetDevice(CDevice* device); + //! Removes all particles void FlushParticle(); + + //! Removes all particles of a sheet void FlushParticle(int sheet); + + //! Creates a new particle int CreateParticle(Math::Vector pos, Math::Vector speed, Math::Point dim, - ParticleType type, float duration=1.0f, float mass=0.0f, - float windSensitivity=1.0f, int sheet=0); - int CreateFrag(Math::Vector pos, Math::Vector speed, EngineTriangle *triangle, - ParticleType type, float duration=1.0f, float mass=0.0f, - float windSensitivity=1.0f, int sheet=0); + ParticleType type, float duration = 1.0f, float mass = 0.0f, + float windSensitivity = 1.0f, int sheet = 0); + + //! Creates a new triangular particle (debris) + int CreateFrag(Math::Vector pos, Math::Vector speed, EngineTriangle* triangle, + ParticleType type, float duration = 1.0f, float mass = 0.0f, + float windSensitivity = 1.0f, int sheet = 0); + + //! Creates a new particle being a part of object int CreatePart(Math::Vector pos, Math::Vector speed, ParticleType type, - float duration=1.0f, float mass=0.0f, float weight=0.0f, - float windSensitivity=1.0f, int sheet=0); + float duration = 1.0f, float mass = 0.0f, float weight = 0.0f, + float windSensitivity = 1.0f, int sheet = 0); + + //! Creates a new linear particle (radius) int CreateRay(Math::Vector pos, Math::Vector goal, ParticleType type, Math::Point dim, - float duration=1.0f, int sheet=0); + float duration = 1.0f, int sheet = 0); + + //! Creates a particle with a trail int CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, - float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f); + float duration = 1.0f, float mass = 0.0f, float length = 10.0f, float width = 1.0f); + + //! Creates a tire mark void CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3, const Math::Vector &p4, ParticleType type); + + //! Removes all particles of a given type void DeleteParticle(ParticleType type); + //! Removes all particles of a given channel void DeleteParticle(int channel); + //! Specifies the object to which the particle is bound void SetObjectLink(int channel, CObject *object); + //! Specifies the parent object that created the particle void SetObjectFather(int channel, CObject *object); void SetPosition(int channel, Math::Vector pos); void SetDimension(int channel, Math::Point dim); @@ -300,31 +321,53 @@ public: void SetIntensity(int channel, float intensity); void SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity); void SetPhase(int channel, ParticlePhase phase, float duration); + + //! Returns the position of the particle bool GetPosition(int channel, Math::Vector &pos); - Color GetFogColor(Math::Vector pos); + //! Returns the color if you're in the fog or black if you're not + Color GetFogColor(Math::Vector pos); + //! Indicates whether a sheet is updated or not void SetFrameUpdate(int sheet, bool update); + //! Updates all the particles. void FrameParticle(float rTime); + //! Draws all the particles void DrawParticle(int sheet); + //! Writes a file containing all the tire tracks bool WriteWheelTrace(const char *filename, int width, int height, Math::Vector dl, Math::Vector ur); protected: + //! Removes a particle of given rank void DeleteRank(int rank); + //! Check a channel number bool CheckChannel(int &channel); + //! Draws a triangular particle void DrawParticleTriangle(int i); + //! Draw a normal particle void DrawParticleNorm(int i); + //! Draw a particle flat (horizontal) void DrawParticleFlat(int i); + //! Draw a particle to a flat sheet of fog void DrawParticleFog(int i); + //! Draw a particle in the form of radius void DrawParticleRay(int i); + //! Draws a spherical particle void DrawParticleSphere(int i); + //! Draws a cylindrical particle void DrawParticleCylinder(int i); + //! Draws a tire mark void DrawParticleWheel(int i); + //! Seeks if an object collided with a bullet CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, ParticleType type, CObject *father); + //! Seeks if an object collided with a ray CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticleType type, CObject *father); + //! Sounded one void Play(Sound sound, Math::Vector pos, float amplitude); + //! Moves a drag; returns true if the drag is finished bool TrackMove(int i, Math::Vector pos, float progress); + //! Draws a drag void TrackDraw(int i, ParticleType type); protected: @@ -336,12 +379,12 @@ protected: CRobotMain* m_main; CSoundInterface* m_sound; - Particle m_particule[MAXPARTICULE*MAXPARTITYPE]; + Particle m_particle[MAXPARTICULE*MAXPARTITYPE]; EngineTriangle m_triangle[MAXPARTICULE]; // triangle if PartiType == 0 - Track m_track[MAXTRACK]; + Track m_track[MAXTRACK]; int m_wheelTraceTotal; int m_wheelTraceIndex; - WheelTrace m_wheelTrace[MAXWHEELTRACE]; + WheelTrace m_wheelTrace[MAXWHEELTRACE]; int m_totalInterface[MAXPARTITYPE][SH_MAX]; bool m_frameUpdate[SH_MAX]; int m_fogTotal; From b5a7708f992d6b51790a574bbaced5a06012f459 Mon Sep 17 00:00:00 2001 From: adiblol Date: Fri, 5 Oct 2012 20:37:20 +0200 Subject: [PATCH 06/14] Refactoring: changed UNIT to g_unit in CRobotMain class --- src/object/robotmain.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp index 226bd575..82eac2ba 100644 --- a/src/object/robotmain.cpp +++ b/src/object/robotmain.cpp @@ -730,7 +730,7 @@ CRobotMain::CRobotMain(CInstanceManager* iMan, CApplication* app) g_build = 0; g_researchDone = 0; // no research done g_researchEnable = 0; - g_unit = 4.0f; + g_unit = UNIT; m_gamerName[0] = 0; /* TODO: profile @@ -3889,8 +3889,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) if (Cmd(line, "DeepView") && !resetObject) { - m_engine->SetDeepView(OpFloat(line, "air", 500.0f)*UNIT, 0, true); - m_engine->SetDeepView(OpFloat(line, "water", 100.0f)*UNIT, 1, true); + m_engine->SetDeepView(OpFloat(line, "air", 500.0f)*g_unit, 0, true); + m_engine->SetDeepView(OpFloat(line, "water", 100.0f)*g_unit, 1, true); } if (Cmd(line, "FogStart") && !resetObject) @@ -3951,7 +3951,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_terrain->Generate(OpInt(line, "mosaic", 20), OpInt(line, "brick", 3), OpFloat(line, "size", 20.0f), - OpFloat(line, "vision", 500.0f)*UNIT, + OpFloat(line, "vision", 500.0f)*g_unit, OpInt(line, "depth", 2), OpFloat(line, "hard", 0.5f)); } @@ -3983,7 +3983,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) name, OpColor(line, "diffuse", Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), OpColor(line, "ambient", Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), - OpFloat(line, "level", 100.0f)*UNIT, + OpFloat(line, "level", 100.0f)*g_unit, OpFloat(line, "glint", 1.0f), pos); m_colorNewWater = OpColor(line, "color", m_colorRefWater); @@ -3999,14 +3999,14 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_cloud->Create(name, OpColor(line, "diffuse", Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), OpColor(line, "ambient", Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)), - OpFloat(line, "level", 500.0f) * UNIT); + OpFloat(line, "level", 500.0f) * g_unit); } if (Cmd(line, "TerrainBlitz") && !resetObject) { m_lightning->Create(OpFloat(line, "sleep", 0.0f), OpFloat(line, "delay", 3.0f), - OpFloat(line, "magnetic", 50.0f) * UNIT); + OpFloat(line, "magnetic", 50.0f) * g_unit); } if (Cmd(line, "TerrainInitTextures") && !resetObject) @@ -4059,8 +4059,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) } m_terrain->GenerateMaterials(id, - OpFloat(line, "min", 0.0f)*UNIT, - OpFloat(line, "max", 100.0f)*UNIT, + OpFloat(line, "min", 0.0f)*g_unit, + OpFloat(line, "max", 100.0f)*g_unit, OpFloat(line, "slope", 5.0f), OpFloat(line, "freq", 100.0f), OpPos(line, "center")*g_unit, From 602273e04a16a1ab0fe5fa977f229b51bad48ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Fri, 5 Oct 2012 22:05:49 +0200 Subject: [PATCH 07/14] Modified .gitignore file to make git status output clearer --- .gitignore | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 86157a03..4f78a85c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,19 @@ # Ignore the documentation folder /doc -# Ignore the CMake build files -/CMakeFiles -/CMakeCache.txt -/cmake_install.cmake -/Makefile +# We don't want anyone to checkin /data folder +/data +# Ignore local data +/colobot.ini +/savegame + +# Ignore the CMake build files +CMakeFiles +CMakeCache.txt +cmake_install.cmake +Makefile +/install_manifest.txt +/Testing +/CTestTestfile.cmake +/src/CBot/tests/CBot_console/bin/ From b7667cef3566fa45805e3ae1e7fc6c214e9126c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Fri, 5 Oct 2012 22:07:58 +0200 Subject: [PATCH 08/14] Added "make install" target. --- CMakeLists.txt | 2 ++ src/CBot/CMakeLists.txt | 2 ++ src/CMakeLists.txt | 2 ++ 3 files changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 13532502..660c79fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,3 +131,5 @@ endif() # Subdirectory with sources add_subdirectory(src bin) + +INSTALL_FILES(/share/games/colobot ../data) diff --git a/src/CBot/CMakeLists.txt b/src/CBot/CMakeLists.txt index 9f5b9872..271f2ce6 100644 --- a/src/CBot/CMakeLists.txt +++ b/src/CBot/CMakeLists.txt @@ -17,3 +17,5 @@ if(${CBOT_STATIC}) else() add_library(CBot SHARED ${SOURCES}) endif() + +INSTALL_TARGETS(/lib CBot) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a7f1c96d..c8372b00 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -192,3 +192,5 @@ link_directories(${CMAKE_CURRENT_SOURCE_DIR}/CBot) add_executable(colobot ${SOURCES}) target_link_libraries(colobot ${LIBS}) + +INSTALL_TARGETS(/games colobot) From b68c903747ebe54955e8141fc1d56091839c8fee Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Fri, 5 Oct 2012 22:34:22 +0200 Subject: [PATCH 09/14] Disabled window resize --- src/graphics/core/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h index ba5af6e6..b6dd138c 100644 --- a/src/graphics/core/device.h +++ b/src/graphics/core/device.h @@ -72,7 +72,7 @@ struct DeviceConfig size = Math::IntPoint(800, 600); bpp = 32; fullScreen = false; - resizeable = true; + resizeable = false; doubleBuf = true; noFrame = false; } From ec32b1df35f49e8f785bd2de0306719825b2be57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Fri, 5 Oct 2012 23:25:54 +0200 Subject: [PATCH 10/14] Commented out profile_test --- src/common/test/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/test/CMakeLists.txt b/src/common/test/CMakeLists.txt index 79368624..ccbb739b 100644 --- a/src/common/test/CMakeLists.txt +++ b/src/common/test/CMakeLists.txt @@ -14,7 +14,7 @@ ${GTEST_DIR}/include add_executable(image_test ../image.cpp image_test.cpp) target_link_libraries(image_test ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${PNG_LIBRARIES}) -add_executable(profile_test ../profile.cpp ../logger.cpp profile_test.cpp) -target_link_libraries(profile_test gtest ${Boost_LIBRARIES}) +#add_executable(profile_test ../profile.cpp ../logger.cpp profile_test.cpp) +#target_link_libraries(profile_test gtest ${Boost_LIBRARIES}) -add_test(profile_test ./profile_test) +#add_test(profile_test ./profile_test) From 7818d5d0963f6e57540b1abdf83408ea6009c296 Mon Sep 17 00:00:00 2001 From: adiblol Date: Sat, 6 Oct 2012 23:35:27 +0200 Subject: [PATCH 11/14] Setting speed now works. Added ability to set 4x and 8x using "speed4" and "speed8" cheat codes respectively. --- src/object/robotmain.cpp | 28 +++++++++++++++++++++++----- src/object/robotmain.h | 1 + 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp index 82eac2ba..1a8c9346 100644 --- a/src/object/robotmain.cpp +++ b/src/object/robotmain.cpp @@ -1956,6 +1956,17 @@ void CRobotMain::ExecuteCmd(char *cmd) return; } + if (strcmp(cmd, "speed4") == 0) { + SetSpeed(4.0f); + UpdateSpeedLabel(); + return; + } + if (strcmp(cmd, "speed8") == 0) { + SetSpeed(8.0f); + UpdateSpeedLabel(); + return; + } + if (m_phase == PHASE_SIMUL) m_displayText->DisplayError(ERR_CMD, Math::Vector(0.0f,0.0f,0.0f)); } @@ -6615,9 +6626,20 @@ void CRobotMain::ChangePause(bool pause) //! Changes game speed void CRobotMain::SetSpeed(float speed) { - // TODO: m_app->SetSimulationSpeed(speed); + m_app->SetSimulationSpeed(speed); + UpdateSpeedLabel(); +} +float CRobotMain::GetSpeed() +{ + return m_app->GetSimulationSpeed(); +} + +void CRobotMain::UpdateSpeedLabel() +{ Ui::CButton* pb = dynamic_cast(m_interface->SearchControl(EVENT_SPEED)); + float speed = m_app->GetSimulationSpeed(); + if (pb != nullptr) { if (speed == 1.0f) @@ -6632,11 +6654,7 @@ void CRobotMain::SetSpeed(float speed) pb->SetState(Ui::STATE_VISIBLE); } } -} -float CRobotMain::GetSpeed() -{ - return m_app->GetSimulationSpeed(); } diff --git a/src/object/robotmain.h b/src/object/robotmain.h index 70fbc8df..dddd6d4e 100644 --- a/src/object/robotmain.h +++ b/src/object/robotmain.h @@ -383,6 +383,7 @@ protected: void StopDisplayVisit(); void ExecuteCmd(char *cmd); bool TestGadgetQuantity(int rank); + void UpdateSpeedLabel(); protected: CInstanceManager* m_iMan; From 70dae8796e96b309d95f220dfb083ed81261ceb6 Mon Sep 17 00:00:00 2001 From: adiblol Date: Sun, 7 Oct 2012 00:09:50 +0200 Subject: [PATCH 12/14] Fixed stupid coding mistake in CBotString.cpp --- src/CBot/CBotString.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CBot/CBotString.cpp b/src/CBot/CBotString.cpp index 6f481277..4795b637 100644 --- a/src/CBot/CBotString.cpp +++ b/src/CBot/CBotString.cpp @@ -100,7 +100,7 @@ const std::map CBotString::s_keywordString = {ID_DEC, "--"}, {ID_LO, "<"}, {ID_HI, ">"}, - {ID_LS, "<<"}, + {ID_LS, "<="}, {ID_HS, ">="}, {ID_EQ, "=="}, {ID_NE, "!="}, From 97f44035f1b3ebd2681236c23f14c4d3ea7f09ac Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Sun, 7 Oct 2012 00:46:46 +0200 Subject: [PATCH 13/14] Changing and saving input bindings --- src/app/app.h | 2 +- src/common/restext.cpp | 6 +- src/object/brain.cpp | 4 +- src/object/robotmain.cpp | 210 +++++++++++++++++++-------------------- src/object/robotmain.h | 10 +- src/script/script.cpp | 1 + src/ui/edit.cpp | 4 +- src/ui/key.cpp | 169 ++++++++++++++----------------- src/ui/key.h | 45 +++++---- src/ui/maindialog.cpp | 112 ++++++++------------- src/ui/mainshort.cpp | 2 +- src/ui/mainshort.h | 2 +- src/ui/studio.cpp | 4 +- 13 files changed, 267 insertions(+), 304 deletions(-) diff --git a/src/app/app.h b/src/app/app.h index e887a63f..32f03f83 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -38,7 +38,7 @@ class CInstanceManager; -class CEvent; +class CEventQueue; class CRobotMain; class CSoundInterface; diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 0f33f52b..9a3d964c 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -105,7 +105,7 @@ static void PutKeyName(char* dst, const char* src) { if ( SearchKey(src+s+5, key) ) { - res = CRobotMain::GetInstancePointer()->GetInputBinding(key).key; + res = CRobotMain::GetInstancePointer()->GetInputBinding(key).primary; if (res != KEY_INVALID) { if ( GetResource(RES_KEY, res, name) ) @@ -172,7 +172,9 @@ static const char* GetResourceBase(ResType type, int num) case RES_KEY: - if (num == VIRTUAL_KMOD_CTRL) + if (num == KEY_INVALID) + return ""; + else if (num == VIRTUAL_KMOD_CTRL) return "Ctrl"; else if (num == VIRTUAL_KMOD_SHIFT) return "Shift"; diff --git a/src/object/brain.cpp b/src/object/brain.cpp index 7b580d7b..54039037 100644 --- a/src/object/brain.cpp +++ b/src/object/brain.cpp @@ -203,8 +203,8 @@ bool CBrain::EventProcess(const Event &event) action = EVENT_NULL; if ( event.type == EVENT_KEY_DOWN && - (event.key.key == m_main->GetInputBinding(INPUT_SLOT_ACTION).key || - event.key.key == m_main->GetInputBinding(INPUT_SLOT_ACTION).joy ) && + (event.key.key == m_main->GetInputBinding(INPUT_SLOT_ACTION).primary || + event.key.key == m_main->GetInputBinding(INPUT_SLOT_ACTION).secondary ) && !m_main->GetEditLock() ) { pw = static_cast< Ui::CWindow* >(m_interface->SearchControl(EVENT_WINDOW0)); diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp index 1a8c9346..954d6767 100644 --- a/src/object/robotmain.cpp +++ b/src/object/robotmain.cpp @@ -878,7 +878,7 @@ void CRobotMain::SetDefaultInputBindings() { for (int i = 0; i < INPUT_SLOT_MAX; i++) { - m_inputBindings[i].key = m_inputBindings[i].joy = KEY_INVALID; + m_inputBindings[i].primary = m_inputBindings[i].secondary = KEY_INVALID; } for (int i = 0; i < JOY_AXIS_SLOT_MAX; i++) @@ -887,34 +887,34 @@ void CRobotMain::SetDefaultInputBindings() m_joyAxisBindings[i].invert = false; } - m_inputBindings[INPUT_SLOT_LEFT ].key = KEY(LEFT); - m_inputBindings[INPUT_SLOT_RIGHT ].key = KEY(RIGHT); - m_inputBindings[INPUT_SLOT_UP ].key = KEY(UP); - m_inputBindings[INPUT_SLOT_DOWN ].key = KEY(DOWN); - m_inputBindings[INPUT_SLOT_GUP ].key = VIRTUAL_KMOD(SHIFT); - m_inputBindings[INPUT_SLOT_GDOWN ].key = VIRTUAL_KMOD(CTRL); - m_inputBindings[INPUT_SLOT_CAMERA ].key = KEY(SPACE); - m_inputBindings[INPUT_SLOT_CAMERA ].joy = VIRTUAL_JOY(2); - m_inputBindings[INPUT_SLOT_DESEL ].key = KEY(KP0); - m_inputBindings[INPUT_SLOT_DESEL ].joy = VIRTUAL_JOY(6); - m_inputBindings[INPUT_SLOT_ACTION ].key = KEY(RETURN); - m_inputBindings[INPUT_SLOT_ACTION ].joy = VIRTUAL_JOY(1); - m_inputBindings[INPUT_SLOT_NEAR ].key = KEY(KP_PLUS); - m_inputBindings[INPUT_SLOT_NEAR ].joy = VIRTUAL_JOY(5); - m_inputBindings[INPUT_SLOT_AWAY ].key = KEY(KP_MINUS); - m_inputBindings[INPUT_SLOT_AWAY ].joy = VIRTUAL_JOY(4); - m_inputBindings[INPUT_SLOT_NEXT ].key = KEY(TAB); - m_inputBindings[INPUT_SLOT_NEXT ].joy = VIRTUAL_JOY(3); - m_inputBindings[INPUT_SLOT_HUMAN ].key = KEY(HOME); - m_inputBindings[INPUT_SLOT_HUMAN ].joy = VIRTUAL_JOY(7); - m_inputBindings[INPUT_SLOT_QUIT ].key = KEY(ESCAPE); - m_inputBindings[INPUT_SLOT_HELP ].key = KEY(F1); - m_inputBindings[INPUT_SLOT_PROG ].key = KEY(F2); - m_inputBindings[INPUT_SLOT_CBOT ].key = KEY(F3); - m_inputBindings[INPUT_SLOT_VISIT ].key = KEY(KP_PERIOD); - m_inputBindings[INPUT_SLOT_SPEED10].key = KEY(F4); - m_inputBindings[INPUT_SLOT_SPEED15].key = KEY(F5); - m_inputBindings[INPUT_SLOT_SPEED20].key = KEY(F6); + m_inputBindings[INPUT_SLOT_LEFT ].primary = KEY(LEFT); + m_inputBindings[INPUT_SLOT_RIGHT ].primary = KEY(RIGHT); + m_inputBindings[INPUT_SLOT_UP ].primary = KEY(UP); + m_inputBindings[INPUT_SLOT_DOWN ].primary = KEY(DOWN); + m_inputBindings[INPUT_SLOT_GUP ].primary = VIRTUAL_KMOD(SHIFT); + m_inputBindings[INPUT_SLOT_GDOWN ].primary = VIRTUAL_KMOD(CTRL); + m_inputBindings[INPUT_SLOT_CAMERA ].primary = KEY(SPACE); + m_inputBindings[INPUT_SLOT_CAMERA ].secondary = VIRTUAL_JOY(2); + m_inputBindings[INPUT_SLOT_DESEL ].primary = KEY(KP0); + m_inputBindings[INPUT_SLOT_DESEL ].secondary = VIRTUAL_JOY(6); + m_inputBindings[INPUT_SLOT_ACTION ].primary = KEY(RETURN); + m_inputBindings[INPUT_SLOT_ACTION ].secondary = VIRTUAL_JOY(1); + m_inputBindings[INPUT_SLOT_NEAR ].primary = KEY(KP_PLUS); + m_inputBindings[INPUT_SLOT_NEAR ].secondary = VIRTUAL_JOY(5); + m_inputBindings[INPUT_SLOT_AWAY ].primary = KEY(KP_MINUS); + m_inputBindings[INPUT_SLOT_AWAY ].secondary = VIRTUAL_JOY(4); + m_inputBindings[INPUT_SLOT_NEXT ].primary = KEY(TAB); + m_inputBindings[INPUT_SLOT_NEXT ].secondary = VIRTUAL_JOY(3); + m_inputBindings[INPUT_SLOT_HUMAN ].primary = KEY(HOME); + m_inputBindings[INPUT_SLOT_HUMAN ].secondary = VIRTUAL_JOY(7); + m_inputBindings[INPUT_SLOT_QUIT ].primary = KEY(ESCAPE); + m_inputBindings[INPUT_SLOT_HELP ].primary = KEY(F1); + m_inputBindings[INPUT_SLOT_PROG ].primary = KEY(F2); + m_inputBindings[INPUT_SLOT_CBOT ].primary = KEY(F3); + m_inputBindings[INPUT_SLOT_VISIT ].primary = KEY(KP_PERIOD); + m_inputBindings[INPUT_SLOT_SPEED10].primary = KEY(F4); + m_inputBindings[INPUT_SLOT_SPEED15].primary = KEY(F5); + m_inputBindings[INPUT_SLOT_SPEED20].primary = KEY(F6); m_joyAxisBindings[JOY_AXIS_SLOT_X].axis = 0; m_joyAxisBindings[JOY_AXIS_SLOT_Y].axis = 1; @@ -1214,33 +1214,33 @@ bool CRobotMain::EventProcess(Event &event) if (event.type == EVENT_KEY_DOWN) { - if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).key) m_keyMotion.y = 1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).joy) m_keyMotion.y = 1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).key) m_keyMotion.y = -1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).joy) m_keyMotion.y = -1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).key) m_keyMotion.x = -1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).joy) m_keyMotion.x = -1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).key) m_keyMotion.x = 1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).joy) m_keyMotion.x = 1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).key) m_keyMotion.z = 1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).joy) m_keyMotion.z = 1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).key) m_keyMotion.z = -1.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).joy) m_keyMotion.z = -1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).primary) m_keyMotion.y = 1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).secondary) m_keyMotion.y = 1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).primary) m_keyMotion.y = -1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).secondary) m_keyMotion.y = -1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).primary) m_keyMotion.x = -1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).secondary) m_keyMotion.x = -1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).primary) m_keyMotion.x = 1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).secondary) m_keyMotion.x = 1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).primary) m_keyMotion.z = 1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).secondary) m_keyMotion.z = 1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).primary) m_keyMotion.z = -1.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).secondary) m_keyMotion.z = -1.0f; } else if (event.type == EVENT_KEY_UP) { - if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).key) m_keyMotion.y = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).joy) m_keyMotion.y = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).key) m_keyMotion.y = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).joy) m_keyMotion.y = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).key) m_keyMotion.x = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).joy) m_keyMotion.x = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).key) m_keyMotion.x = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).joy) m_keyMotion.x = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).key) m_keyMotion.z = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).joy) m_keyMotion.z = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).key) m_keyMotion.z = 0.0f; - if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).joy) m_keyMotion.z = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).primary) m_keyMotion.y = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).secondary) m_keyMotion.y = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).primary) m_keyMotion.y = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).secondary) m_keyMotion.y = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).primary) m_keyMotion.x = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).secondary) m_keyMotion.x = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).primary) m_keyMotion.x = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).secondary) m_keyMotion.x = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).primary) m_keyMotion.z = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).secondary) m_keyMotion.z = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).primary) m_keyMotion.z = 0.0f; + if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).secondary) m_keyMotion.z = 0.0f; } else if (event.type == EVENT_JOY_AXIS) { @@ -1356,10 +1356,10 @@ bool CRobotMain::EventProcess(Event &event) if (event.type == EVENT_KEY_DOWN) { - if (event.key.key == GetInputBinding(INPUT_SLOT_HELP).key || - event.key.key == GetInputBinding(INPUT_SLOT_HELP).joy || - event.key.key == GetInputBinding(INPUT_SLOT_PROG).key || - event.key.key == GetInputBinding(INPUT_SLOT_PROG).joy || + if (event.key.key == GetInputBinding(INPUT_SLOT_HELP).primary || + event.key.key == GetInputBinding(INPUT_SLOT_HELP).secondary || + event.key.key == GetInputBinding(INPUT_SLOT_PROG).primary || + event.key.key == GetInputBinding(INPUT_SLOT_PROG).secondary || event.key.key == KEY(ESCAPE)) { StopDisplayInfo(); @@ -1394,14 +1394,14 @@ bool CRobotMain::EventProcess(Event &event) } if (m_editLock) // current edition? { - if (event.key.key == GetInputBinding(INPUT_SLOT_HELP).key || - event.key.key == GetInputBinding(INPUT_SLOT_HELP).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_HELP).primary || + event.key.key == GetInputBinding(INPUT_SLOT_HELP).secondary) { StartDisplayInfo(SATCOM_HUSTON, false); return false; } - if (event.key.key == GetInputBinding(INPUT_SLOT_PROG).key || - event.key.key == GetInputBinding(INPUT_SLOT_PROG).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_PROG).primary || + event.key.key == GetInputBinding(INPUT_SLOT_PROG).secondary) { StartDisplayInfo(SATCOM_PROG, false); return false; @@ -1410,8 +1410,8 @@ bool CRobotMain::EventProcess(Event &event) } if (m_movieLock) // current movie? { - if (event.key.key == GetInputBinding(INPUT_SLOT_QUIT).key || - event.key.key == GetInputBinding(INPUT_SLOT_QUIT).joy || + if (event.key.key == GetInputBinding(INPUT_SLOT_QUIT).primary || + event.key.key == GetInputBinding(INPUT_SLOT_QUIT).secondary || event.key.key == KEY(ESCAPE)) { AbortMovie(); @@ -1420,21 +1420,21 @@ bool CRobotMain::EventProcess(Event &event) } if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT) { - if (event.key.key == GetInputBinding(INPUT_SLOT_VISIT).key || - event.key.key == GetInputBinding(INPUT_SLOT_VISIT).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_VISIT).primary || + event.key.key == GetInputBinding(INPUT_SLOT_VISIT).secondary) { StartDisplayVisit(EVENT_NULL); } - if (event.key.key == GetInputBinding(INPUT_SLOT_QUIT).key || - event.key.key == GetInputBinding(INPUT_SLOT_QUIT).joy || + if (event.key.key == GetInputBinding(INPUT_SLOT_QUIT).primary || + event.key.key == GetInputBinding(INPUT_SLOT_QUIT).secondary || event.key.key == KEY(ESCAPE)) { StopDisplayVisit(); } return false; } - if (event.key.key == GetInputBinding(INPUT_SLOT_QUIT).key || - event.key.key == GetInputBinding(INPUT_SLOT_QUIT).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_QUIT).primary || + event.key.key == GetInputBinding(INPUT_SLOT_QUIT).secondary) { if (m_movie->IsExist()) StartDisplayInfo(SATCOM_HUSTON, false); @@ -1454,55 +1454,55 @@ bool CRobotMain::EventProcess(Event &event) ChangePause(!m_engine->GetPause()); } } - if (event.key.key == GetInputBinding(INPUT_SLOT_CAMERA).key || - event.key.key == GetInputBinding(INPUT_SLOT_CAMERA).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_CAMERA).primary || + event.key.key == GetInputBinding(INPUT_SLOT_CAMERA).secondary) { ChangeCamera(); } - if (event.key.key == GetInputBinding(INPUT_SLOT_DESEL).key || - event.key.key == GetInputBinding(INPUT_SLOT_DESEL).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_DESEL).primary || + event.key.key == GetInputBinding(INPUT_SLOT_DESEL).secondary) { if (m_shortCut) DeselectObject(); } - if (event.key.key == GetInputBinding(INPUT_SLOT_HUMAN).key || - event.key.key == GetInputBinding(INPUT_SLOT_HUMAN).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_HUMAN).primary || + event.key.key == GetInputBinding(INPUT_SLOT_HUMAN).secondary) { SelectHuman(); } - if (event.key.key == GetInputBinding(INPUT_SLOT_NEXT).key || - event.key.key == GetInputBinding(INPUT_SLOT_NEXT).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_NEXT).primary || + event.key.key == GetInputBinding(INPUT_SLOT_NEXT).secondary) { if (m_shortCut) m_short->SelectNext(); } - if (event.key.key == GetInputBinding(INPUT_SLOT_HELP).key || - event.key.key == GetInputBinding(INPUT_SLOT_HELP).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_HELP).primary || + event.key.key == GetInputBinding(INPUT_SLOT_HELP).secondary) { StartDisplayInfo(SATCOM_HUSTON, true); } - if (event.key.key == GetInputBinding(INPUT_SLOT_PROG).key || - event.key.key == GetInputBinding(INPUT_SLOT_PROG).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_PROG).primary || + event.key.key == GetInputBinding(INPUT_SLOT_PROG).secondary) { StartDisplayInfo(SATCOM_PROG, true); } - if (event.key.key == GetInputBinding(INPUT_SLOT_VISIT).key || - event.key.key == GetInputBinding(INPUT_SLOT_VISIT).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_VISIT).primary || + event.key.key == GetInputBinding(INPUT_SLOT_VISIT).secondary) { StartDisplayVisit(EVENT_NULL); } - if (event.key.key == GetInputBinding(INPUT_SLOT_SPEED10).key || - event.key.key == GetInputBinding(INPUT_SLOT_SPEED10).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_SPEED10).primary || + event.key.key == GetInputBinding(INPUT_SLOT_SPEED10).secondary) { SetSpeed(1.0f); } - if (event.key.key == GetInputBinding(INPUT_SLOT_SPEED15).key || - event.key.key == GetInputBinding(INPUT_SLOT_SPEED15).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_SPEED15).primary || + event.key.key == GetInputBinding(INPUT_SLOT_SPEED15).secondary) { SetSpeed(1.5f); } - if (event.key.key == GetInputBinding(INPUT_SLOT_SPEED20).key || - event.key.key == GetInputBinding(INPUT_SLOT_SPEED20).joy) + if (event.key.key == GetInputBinding(INPUT_SLOT_SPEED20).primary || + event.key.key == GetInputBinding(INPUT_SLOT_SPEED20).secondary) { SetSpeed(2.0f); } @@ -3109,26 +3109,26 @@ void CRobotMain::KeyCamera(EventType type, unsigned int key) if (type == EVENT_KEY_UP) { - if (key == GetInputBinding(INPUT_SLOT_LEFT).key || - key == GetInputBinding(INPUT_SLOT_LEFT).joy) + if (key == GetInputBinding(INPUT_SLOT_LEFT).primary || + key == GetInputBinding(INPUT_SLOT_LEFT).secondary) { m_cameraPan = 0.0f; } - if (key == GetInputBinding(INPUT_SLOT_RIGHT).key || - key == GetInputBinding(INPUT_SLOT_RIGHT).joy) + if (key == GetInputBinding(INPUT_SLOT_RIGHT).primary || + key == GetInputBinding(INPUT_SLOT_RIGHT).secondary) { m_cameraPan = 0.0f; } - if (key == GetInputBinding(INPUT_SLOT_UP).key || - key == GetInputBinding(INPUT_SLOT_UP).joy) + if (key == GetInputBinding(INPUT_SLOT_UP).primary || + key == GetInputBinding(INPUT_SLOT_UP).secondary) { m_cameraZoom = 0.0f; } - if (key == GetInputBinding(INPUT_SLOT_DOWN).key || - key == GetInputBinding(INPUT_SLOT_DOWN).joy) + if (key == GetInputBinding(INPUT_SLOT_DOWN).primary || + key == GetInputBinding(INPUT_SLOT_DOWN).secondary) { m_cameraZoom = 0.0f; } @@ -3144,26 +3144,26 @@ void CRobotMain::KeyCamera(EventType type, unsigned int key) if (type == EVENT_KEY_DOWN) { - if (key == GetInputBinding(INPUT_SLOT_LEFT).key || - key == GetInputBinding(INPUT_SLOT_LEFT).joy) + if (key == GetInputBinding(INPUT_SLOT_LEFT).primary || + key == GetInputBinding(INPUT_SLOT_LEFT).secondary) { m_cameraPan = -1.0f; } - if (key == GetInputBinding(INPUT_SLOT_RIGHT).key || - key == GetInputBinding(INPUT_SLOT_RIGHT).joy) + if (key == GetInputBinding(INPUT_SLOT_RIGHT).primary || + key == GetInputBinding(INPUT_SLOT_RIGHT).secondary) { m_cameraPan = 1.0f; } - if (key == GetInputBinding(INPUT_SLOT_UP).key || - key == GetInputBinding(INPUT_SLOT_UP).joy) + if (key == GetInputBinding(INPUT_SLOT_UP).primary || + key == GetInputBinding(INPUT_SLOT_UP).secondary) { m_cameraZoom = -1.0f; } - if (key == GetInputBinding(INPUT_SLOT_DOWN).key || - key == GetInputBinding(INPUT_SLOT_DOWN).joy) + if (key == GetInputBinding(INPUT_SLOT_DOWN).primary || + key == GetInputBinding(INPUT_SLOT_DOWN).secondary) { m_cameraZoom = 1.0f; } diff --git a/src/object/robotmain.h b/src/object/robotmain.h index dddd6d4e..e475c438 100644 --- a/src/object/robotmain.h +++ b/src/object/robotmain.h @@ -148,12 +148,12 @@ const int SATCOM_MAX = 6; */ struct InputBinding { - //! Keyboard binding code (can be regular or virtual) - unsigned int key; - //! Joystick binding code (virtual) - unsigned int joy; + //! Primary and secondary bindings + //! Can be regular key, virtual key or virtual joystick button + unsigned int primary, secondary; - InputBinding() : key(KEY_INVALID), joy(KEY_INVALID) {} + InputBinding(unsigned int p = KEY_INVALID, unsigned int s = KEY_INVALID) + : primary(p), secondary(s) {} }; /** diff --git a/src/script/script.cpp b/src/script/script.cpp index 2d76ad3f..face9b74 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -19,6 +19,7 @@ #include "script/script.h" +#include "app/app.h" #include "common/global.h" #include "common/iman.h" #include "common/restext.h" diff --git a/src/ui/edit.cpp b/src/ui/edit.cpp index ca53a7a4..45e564d7 100644 --- a/src/ui/edit.cpp +++ b/src/ui/edit.cpp @@ -1796,7 +1796,7 @@ bool CEdit::ReadText(const char *filename, int addSize) if ( SearchKey(buffer+i+5, slot) ) { CRobotMain* main = CRobotMain::GetInstancePointer(); - res = main->GetInputBinding(slot).key; + res = main->GetInputBinding(slot).primary; if ( res != 0 ) { if ( GetResource(RES_KEY, res, iName) ) @@ -1815,7 +1815,7 @@ bool CEdit::ReadText(const char *filename, int addSize) m_format[j] = font; j ++; - res = main->GetInputBinding(slot).joy; + res = main->GetInputBinding(slot).secondary; if ( res != 0 ) { if ( GetResource(RES_KEY, res, iName) ) diff --git a/src/ui/key.cpp b/src/ui/key.cpp index 26d99acb..9a761270 100644 --- a/src/ui/key.cpp +++ b/src/ui/key.cpp @@ -15,65 +15,48 @@ // * You should have received a copy of the GNU General Public License // * along with this program. If not, see http://www.gnu.org/licenses/. -// key.cpp - - #include "ui/key.h" -#include +#include "common/global.h" + +#include namespace Ui { -void GetKeyName(char *name, int key) + +void GetKeyName(char* name, unsigned int key) { - if ( !GetResource(RES_KEY, key, name) ) { - if (isalnum(key)) { - name[0] = key; - name[1] = 0; - } - else { - sprintf(name, "Code %d", key); - } - } + if (!GetResource(RES_KEY, key, name)) + sprintf(name, "Code %d", key); } -// Object's constructor. - CKey::CKey() : CControl() { - m_key[0] = 0; - m_key[1] = 0; - m_bCatch = false; + m_catch = false; - m_app = CApplication::GetInstancePointer(); + m_robotMain = CRobotMain::GetInstancePointer(); } -// Object's destructor. - CKey::~CKey() { + m_robotMain = nullptr; } - -// Creates a new button. - bool CKey::Create(Math::Point pos, Math::Point dim, int icon, EventType eventMsg) { - char name[100]; if (eventMsg == EVENT_NULL) eventMsg = GetUniqueEventType(); CControl::Create(pos, dim, icon, eventMsg); + + char name[100]; GetResource(RES_EVENT, eventMsg, name); SetName(std::string(name)); return true; } - -// Management of an event. - bool CKey::EventProcess(const Event &event) { if (m_state & STATE_DEAD) @@ -81,24 +64,31 @@ bool CKey::EventProcess(const Event &event) CControl::EventProcess(event); - if (event.type == EVENT_MOUSE_BUTTON_DOWN) { + if (event.type == EVENT_MOUSE_BUTTON_DOWN) + { if (event.mouseButton.button == MOUSE_BUTTON_LEFT) // left - m_bCatch = Detect(event.mousePos); + m_catch = Detect(event.mousePos); } - if (event.type == EVENT_KEY_DOWN && m_bCatch) { - m_bCatch = false; + if (event.type == EVENT_KEY_DOWN && m_catch) + { + m_catch = false; - if ( TestKey(event.key.key) ) { // impossible ? + if (TestKey(event.key.key)) // impossible ? + { m_sound->Play(SOUND_TZOING); - } else { - // TODO: test for virtual, joystick, etc. - if ( event.key.key == m_key[0] || event.key.key == m_key[1] ) { - m_key[0] = event.key.key; - m_key[1] = 0; - } else { - m_key[1] = m_key[0]; - m_key[0] = event.key.key; + } + else + { + if (event.key.key == m_binding.primary || event.key.key == m_binding.secondary) + { + m_binding.secondary = KEY_INVALID; + m_binding.primary = event.key.key; + } + else + { + m_binding.secondary = m_binding.primary; + m_binding.primary = event.key.key; } m_sound->Play(SOUND_CLICK); @@ -112,96 +102,88 @@ bool CKey::EventProcess(const Event &event) return true; } - -// Seeks when a key is already used. - -bool CKey::TestKey(int key) +bool CKey::TestKey(unsigned int key) { - if ( key == KEY(PAUSE) || key == KEY(PRINT) ) return true; // blocked key + if (key == KEY(PAUSE) || key == KEY(PRINT)) return true; // blocked key - /* TODO: input bindings - for (int i = 0; i < 20; i++) { - for (int j = 0; j < 2; j++) { - if (key == m_app->GetKey(i, j) ) // key used? - m_app->SetKey(i, j, 0); // nothing! - } + for (int i = 0; i < INPUT_SLOT_MAX; i++) + { + InputSlot slot = static_cast(i); + InputBinding b = m_robotMain->GetInputBinding(slot); + if (key == b.primary || key == b.secondary) + m_robotMain->SetInputBinding(slot, InputBinding()); // nothing! - if ( m_app->GetKey(i, 0) == 0 ) { // first free option? - m_app->SetKey(i, 0, m_app->GetKey(i, 1)); // shift - m_app->SetKey(i, 1, 0); - } - } */ + if (b.primary == KEY_INVALID) // first free option? + m_robotMain->SetInputBinding(slot, InputBinding(b.secondary, b.primary)); // shift + } return false; // not used } - -// Draws button. - void CKey::Draw() { - Math::Point iDim, pos; - float zoomExt, zoomInt, h; - int icon; - char text[100]; - - if ( (m_state & STATE_VISIBLE) == 0 ) + if ((m_state & STATE_VISIBLE) == 0) return; - iDim = m_dim; + Math::Point iDim = m_dim; m_dim.x = 200.0f/640.0f; - if ( m_state & STATE_SHADOW ) + if (m_state & STATE_SHADOW) DrawShadow(m_pos, m_dim); m_engine->SetTexture("button1.png"); m_engine->SetState(Gfx::ENG_RSTATE_NORMAL); // was D3DSTATENORMAL - zoomExt = 1.00f; - zoomInt = 0.95f; + float zoomExt = 1.00f; + float zoomInt = 0.95f; - icon = 2; - if ( m_key[0] == 0 && m_key[1] == 0 ) // no shortcut? + int icon = 2; + if (m_binding.primary == KEY_INVALID && m_binding.secondary == KEY_INVALID) // no shortcut? icon = 3; - if ( m_state & STATE_DEFAULT ) { + if (m_state & STATE_DEFAULT) + { DrawPart(23, 1.3f, 0.0f); zoomExt *= 1.15f; zoomInt *= 1.15f; } - if ( m_state & STATE_HILIGHT ) + if (m_state & STATE_HILIGHT) icon = 1; - if ( m_state & STATE_CHECK ) + if (m_state & STATE_CHECK) icon = 0; - if ( m_state & STATE_PRESS ) { + if (m_state & STATE_PRESS) + { icon = 3; zoomInt *= 0.9f; } - if ( (m_state & STATE_ENABLE) == 0 ) + if ((m_state & STATE_ENABLE) == 0) icon = 7; - if ( m_state & STATE_DEAD ) + if (m_state & STATE_DEAD) icon = 17; - if ( m_bCatch ) + if (m_catch) icon = 23; DrawPart(icon, zoomExt, 8.0f / 256.0f); // draws the button - h = m_engine->GetText()->GetHeight(m_fontType, m_fontSize) / 2.0f; + float h = m_engine->GetText()->GetHeight(m_fontType, m_fontSize) / 2.0f; - GetKeyName(text, m_key[0]); - if ( m_key[1] != 0 ) { + char text[100]; + GetKeyName(text, m_binding.primary); + if (m_binding.secondary != KEY_INVALID) + { GetResource(RES_TEXT, RT_KEY_OR, text+strlen(text)); - GetKeyName(text+strlen(text), m_key[1]); + GetKeyName(text+strlen(text), m_binding.secondary); } + Math::Point pos; pos.x = m_pos.x + m_dim.x * 0.5f; pos.y = m_pos.y + m_dim.y * 0.5f; pos.y -= h; @@ -209,7 +191,7 @@ void CKey::Draw() m_dim = iDim; - if ( m_state & STATE_DEAD ) + if (m_state & STATE_DEAD) return; // Draws the name. @@ -219,20 +201,15 @@ void CKey::Draw() m_engine->GetText()->DrawText(std::string(m_name), m_fontType, m_fontSize, pos, m_dim.x, Gfx::TEXT_ALIGN_LEFT, 0); } - - -void CKey::SetKey(int option, int key) +void CKey::SetBinding(InputBinding b) { - if ( option < 0 || option > 1 ) return; - - m_key[option] = key; + m_binding = b; } -int CKey::GetKey(int option) +InputBinding CKey::GetBinding() { - if ( option < 0 || option > 1 ) return 0; - - return m_key[option]; + return m_binding; } -} + +} // namespace Ui diff --git a/src/ui/key.h b/src/ui/key.h index 1943f611..2332c9b8 100644 --- a/src/ui/key.h +++ b/src/ui/key.h @@ -15,13 +15,13 @@ // * You should have received a copy of the GNU General Public License // * along with this program. If not, see http://www.gnu.org/licenses/. -// key.h +/** + * \file ui/key.h + * \brief Key slot control + */ #pragma once -#include -#include - #include "ui/control.h" #include "common/iman.h" @@ -29,33 +29,40 @@ #include "common/restext.h" #include "common/key.h" -#include "app/app.h" namespace Ui { class CKey : public CControl { - public: - CKey(); - virtual ~CKey(); +public: + CKey(); + virtual ~CKey(); - bool Create(Math::Point pos, Math::Point dim, int icon, EventType eventMsg); - bool EventProcess(const Event &event); + //! Creates a new key slot button + bool Create(Math::Point pos, Math::Point dim, int icon, EventType eventMsg); + //! Management of an event + bool EventProcess(const Event &event); - void Draw(); + //! Draws button + void Draw(); - void SetKey(int option, int key); - int GetKey(int option); + //! Management of binding + //@{ + void SetBinding(InputBinding b); + InputBinding GetBinding(); + //@} - protected: - bool TestKey(int key); +protected: + //! Checks if a key is already used + bool TestKey(unsigned int key); - unsigned int m_key[2]; - bool m_bCatch; +protected: + CRobotMain* m_robotMain; - CApplication *m_app; + InputBinding m_binding; + bool m_catch; }; -} +} // namespace Ui diff --git a/src/ui/maindialog.cpp b/src/ui/maindialog.cpp index d7295eb5..21a2c504 100644 --- a/src/ui/maindialog.cpp +++ b/src/ui/maindialog.cpp @@ -5476,7 +5476,6 @@ void CMainDialog::SetupMemorize() { float fValue; int iValue, i, j; - char key[500]; char num[10]; GetProfile().SetLocalProfileString("Directory", "scene", m_sceneDir); @@ -5518,21 +5517,16 @@ void CMainDialog::SetupMemorize() // GetProfile()->SetLocalProfileInt("Setup", "UseJoystick", m_engine->GetJoystick()); // GetProfile()->SetLocalProfileInt("Setup", "MidiVolume", m_sound->GetMidiVolume()); - // key[0] = 0; - // for ( i=0 ; i<100 ; i++ ) - // { - // if ( m_engine->GetKey(i, 0) == 0 ) break; + std::stringstream key; + for (int i = 0; i < INPUT_SLOT_MAX; i++) + { + InputBinding b = m_main->GetInputBinding(static_cast(i)); - // for ( j=0 ; j<2 ; j++ ) - // { - // iValue = m_engine->GetKey(i, j); - // sprintf(num, "%d%c", iValue, j==0?'+':' '); - // strcat(key, num); - // } - // } + key << b.primary << " "; + key << b.secondary << " "; + } - /* TODO: profile - SetLocalProfileString("Setup", "KeyMap", key); */ + GetProfile().SetLocalProfileString("Setup", "KeyMap", key.str()); #if _NET if ( m_accessEnable ) @@ -5556,9 +5550,8 @@ void CMainDialog::SetupMemorize() void CMainDialog::SetupRecall() { float fValue; - int iValue, i, j; + int iValue; std::string key; - char* p; if ( GetProfile().GetLocalProfileString("Directory", "scene", key) ) { @@ -5747,22 +5740,18 @@ void CMainDialog::SetupRecall() m_engine->SetEditIndentValue(iValue); } - // if ( GetLocalProfileString("Setup", "KeyMap", key, 500) ) - // { - // p = key; - // for ( i=0 ; i<100 ; i++ ) - // { - // if ( p[0] == 0 ) break; - - // for ( j=0 ; j<2 ; j++ ) - // { - // sscanf(p, "%d", &iValue); - // m_engine->SetKey(i, j, iValue); - // while ( *p >= '0' && *p <= '9' ) p++; - // while ( *p == ' ' || *p == '+' ) p++; - // } - // } - // } + if (GetProfile().GetLocalProfileString("Setup", "KeyMap", key)) + { + std::stringstream skey; + skey.str(key); + for (int i = 0; i < INPUT_SLOT_MAX; i++) + { + InputBinding b; + skey >> b.primary; + skey >> b.secondary; + m_main->SetInputBinding(static_cast(i), b); + } + } #if _NET if ( m_accessEnable ) @@ -5837,7 +5826,7 @@ void CMainDialog::ChangeSetupQuality(int quality) // Redefinable keys: -static int key_table[KEY_TOTAL] = +static InputSlot key_table[KEY_TOTAL] = { INPUT_SLOT_LEFT, INPUT_SLOT_RIGHT, @@ -5891,37 +5880,30 @@ static EventType key_event[KEY_TOTAL] = void CMainDialog::UpdateKey() { - CWindow* pw; - CScroll* ps; - CKey* pk; - Math::Point pos, dim; - int first, i; + CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if (pw == nullptr) return; - pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); - if ( pw == 0 ) return; + CScroll* ps = static_cast(pw->SearchControl(EVENT_INTERFACE_KSCROLL)); + if (ps == nullptr) return; - ps = static_cast(pw->SearchControl(EVENT_INTERFACE_KSCROLL)); - if ( ps == 0 ) return; + int first = static_cast(ps->GetVisibleValue()*(KEY_TOTAL-KEY_VISIBLE)); - first = static_cast(ps->GetVisibleValue()*(KEY_TOTAL-KEY_VISIBLE)); - - for ( i=0 ; iDeleteControl(key_event[i]); - } + Math::Point dim; dim.x = 400.0f/640.0f; dim.y = 20.0f/480.0f; + Math::Point pos; pos.x = 110.0f/640.0f; pos.y = 168.0f/480.0f + dim.y*(KEY_VISIBLE-1); - for ( i=0 ; iCreateKey(pos, dim, -1, key_event[first+i]); - pk = static_cast(pw->SearchControl(key_event[first+i])); - if ( pk == 0 ) break; - /* TODO: set input bindings - pk->SetKey(0, m_engine->GetKey(key_table[first+i], 0)); - pk->SetKey(1, m_engine->GetKey(key_table[first+i], 1)); */ + CKey* pk = static_cast(pw->SearchControl(key_event[first+i])); + if (pk == nullptr) break; + + pk->SetBinding(m_main->GetInputBinding(key_table[first+i])); pos.y -= dim.y; } } @@ -5930,26 +5912,20 @@ void CMainDialog::UpdateKey() void CMainDialog::ChangeKey(EventType event) { - CWindow* pw; - CScroll* ps; - CKey* pk; - int i; + CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if (pw == nullptr) return; - pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); - if ( pw == 0 ) return; + CScroll* ps = static_cast(pw->SearchControl(EVENT_INTERFACE_KSCROLL)); + if (ps == nullptr) return; - ps = static_cast(pw->SearchControl(EVENT_INTERFACE_KSCROLL)); - if ( ps == 0 ) return; - - for ( i=0 ; i(pw->SearchControl(key_event[i])); - if ( pk == 0 ) break; - /* TODO: set key binding - m_engine->SetKey(key_table[i], 0, pk->GetKey(0)); - m_engine->SetKey(key_table[i], 1, pk->GetKey(1)); */ + CKey* pk = static_cast(pw->SearchControl(key_event[i])); + if (pk == nullptr) break; + + m_main->SetInputBinding(key_table[i], pk->GetBinding()); } } } diff --git a/src/ui/mainshort.cpp b/src/ui/mainshort.cpp index ac6d7fc4..55b9612f 100644 --- a/src/ui/mainshort.cpp +++ b/src/ui/mainshort.cpp @@ -30,7 +30,7 @@ CMainShort::CMainShort() m_iMan->AddInstance(CLASS_SHORT, this); m_interface = static_cast(m_iMan->SearchInstance(CLASS_INTERFACE)); - m_event = static_cast(m_iMan->SearchInstance(CLASS_EVENT)); + m_event = static_cast(m_iMan->SearchInstance(CLASS_EVENT)); m_engine = static_cast(m_iMan->SearchInstance(CLASS_ENGINE)); m_main = static_cast(m_iMan->SearchInstance(CLASS_MAIN)); diff --git a/src/ui/mainshort.h b/src/ui/mainshort.h index e97bdcc3..0912e687 100644 --- a/src/ui/mainshort.h +++ b/src/ui/mainshort.h @@ -47,7 +47,7 @@ class CMainShort protected: CInstanceManager* m_iMan; - CEvent* m_event; + CEventQueue* m_event; Gfx::CEngine* m_engine; CInterface* m_interface; CRobotMain* m_main; diff --git a/src/ui/studio.cpp b/src/ui/studio.cpp index a581baa4..2f58c958 100644 --- a/src/ui/studio.cpp +++ b/src/ui/studio.cpp @@ -241,8 +241,8 @@ bool CStudio::EventProcess(const Event &event) if ( event.type == EVENT_KEY_DOWN ) { - if ( event.key.key == m_main->GetInputBinding(INPUT_SLOT_CBOT).key || - event.key.key == m_main->GetInputBinding(INPUT_SLOT_CBOT).joy ) + if ( event.key.key == m_main->GetInputBinding(INPUT_SLOT_CBOT).primary || + event.key.key == m_main->GetInputBinding(INPUT_SLOT_CBOT).secondary ) { if ( m_helpFilename.length() > 0 ) { From dfe21c5a9c2ebf3df0f445014588bcce0387d699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Mon, 8 Oct 2012 21:50:38 +0200 Subject: [PATCH 14/14] Removed Gfx:: from license notice (introduced in 8ad15c0e) --- src/ui/maindialog.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ui/maindialog.cpp b/src/ui/maindialog.cpp index 21a2c504..5136a415 100644 --- a/src/ui/maindialog.cpp +++ b/src/ui/maindialog.cpp @@ -8,7 +8,7 @@ // * // * 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 Gfx::PARTICULAR PURPOSE. See the +// * 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 @@ -6779,4 +6779,3 @@ bool CMainDialog::NextMission() } // namespace Ui -