/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsiteс.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://gnu.org/licenses */ #include "physics/physics.h" #include "app/app.h" #include "common/event.h" #include "common/global.h" #include "common/iman.h" #include "graphics/engine/camera.h" #include "graphics/engine/engine.h" #include "graphics/engine/lightman.h" #include "graphics/engine/pyro.h" #include "graphics/engine/terrain.h" #include "graphics/engine/water.h" #include "math/geometry.h" #include "object/brain.h" #include "object/robotmain.h" #include "object/motion/motion.h" #include "object/motion/motionhuman.h" #include "object/task/task.h" #include "script/cmdtoken.h" #include #include const float LANDING_SPEED = 3.0f; const float LANDING_ACCEL = 5.0f; const float LANDING_ACCELh = 1.5f; // Object's constructor. CPhysics::CPhysics(CObject* object) { m_object = object; m_engine = Gfx::CEngine::GetInstancePointer(); m_lightMan = m_engine->GetLightManager(); m_particle = m_engine->GetParticle(); m_water = m_engine->GetWater(); m_terrain = CRobotMain::GetInstancePointer()->GetTerrain(); m_camera = CRobotMain::GetInstancePointer()->GetCamera(); m_sound = CApplication::GetInstancePointer()->GetSound(); m_brain = nullptr; m_motion = nullptr; m_type = TYPE_ROLLING; m_gravity = 9.81f; // default gravity m_time = 0.0f; m_timeUnderWater = 0.0f; m_motorSpeed = Math::Vector(0.0f, 0.0f, 0.0f); m_bMotor = false; m_bLand = true; // ground m_bSwim = false; // in air m_bCollision = false; m_bObstacle = false; m_repeatCollision = 0; m_linVibrationFactor = 1.0f; m_cirVibrationFactor = 1.0f; m_inclinaisonFactor = 1.0f; m_lastPowerParticle = 0.0f; m_lastSlideParticle = 0.0f; m_lastMotorParticle = 0.0f; m_lastWaterParticle = 0.0f; m_lastUnderParticle = 0.0f; m_lastPloufParticle = 0.0f; m_lastFlameParticle = 0.0f; m_bWheelParticleBrake = false; m_absorbWater = 0.0f; m_reactorTemperature = 0.0f; m_reactorRange = 1.0f; m_timeReactorFail = 0.0f; m_lastEnergy = 0.0f; m_lastSoundWater = 0.0f; m_lastSoundInsect = 0.0f; m_restBreakParticle = 0.0f; m_floorHeight = 0.0f; m_soundChannel = -1; m_soundChannelSlide = -1; m_soundTimePshhh = 0.0f; m_soundTimeJostle = 0.0f; m_soundTimeBoum = 0.0f; m_bSoundSlow = true; m_bFreeze = false; m_bForceUpdate = true; m_bLowLevel = false; m_fallingHeight = 0.0f; m_minFallingHeight = 20.0f; m_fallDamageFraction = 0.007f; memset(&m_linMotion, 0, sizeof(Motion)); memset(&m_cirMotion, 0,sizeof(Motion)); } // Object's destructor. CPhysics::~CPhysics() { } // Destroys the object. void CPhysics::DeleteObject(bool bAll) { if ( m_soundChannel != -1 ) { m_sound->FlushEnvelope(m_soundChannel); m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 0.3f, SOPER_STOP); m_soundChannel = -1; } if ( m_soundChannelSlide != -1 ) { m_sound->FlushEnvelope(m_soundChannelSlide); m_sound->AddEnvelope(m_soundChannelSlide, 0.0f, 1.0f, 0.3f, SOPER_STOP); m_soundChannelSlide = -1; } } void CPhysics::SetBrain(CBrain* brain) { m_brain = brain; } void CPhysics::SetMotion(CMotion* motion) { m_motion = motion; } // Management of the type. void CPhysics::SetType(PhysicsType type) { m_type = type; } PhysicsType CPhysics::GetType() { return m_type; } // Saves all parameters of the object. bool CPhysics::Write(char *line) { char name[100]; sprintf(name, " motor=%.2f;%.2f;%.2f", m_motorSpeed.x, m_motorSpeed.y, m_motorSpeed.z); strcat(line, name); if ( m_type == TYPE_FLYING ) { sprintf(name, " reactorRange=%.2f", GetReactorRange()); strcat(line, name); sprintf(name, " land=%d", GetLand()); strcat(line, name); } return true; } // Restores all parameters of the object. bool CPhysics::Read(char *line) { m_motorSpeed = OpDir(line, "motor"); if ( m_type == TYPE_FLYING ) { SetReactorRange(OpFloat(line, "reactorRange", 0.0f)); SetLand(OpInt(line, "land", 0)); } return true; } // Management of the force of gravity. void CPhysics::SetGravity(float value) { m_gravity = value; } float CPhysics::GetGravity() { return m_gravity; } // Returns the height above the ground. float CPhysics::GetFloorHeight() { return m_floorHeight; } // Managing the state of the engine. void CPhysics::SetMotor(bool bState) { int light; m_bMotor = bState; light = m_object->GetShadowLight(); if ( light != -1 ) { m_lightMan->SetLightIntensity(light, m_bMotor?1.0f:0.0f); m_lightMan->SetLightIntensitySpeed(light, 3.0f); } } bool CPhysics::GetMotor() { return m_bMotor; } // Management of the state in flight/ground. void CPhysics::SetLand(bool bState) { m_bLand = bState; SetMotor(!bState); // lights if you leave the reactor in flight } bool CPhysics::GetLand() { return m_bLand; } // Management of the state in air/water. void CPhysics::SetSwim(bool bState) { if ( !m_bSwim && bState ) // enters the water? { m_timeUnderWater = 0.0f; } m_bSwim = bState; } bool CPhysics::GetSwim() { return m_bSwim; } // Indicates whether a collision occurred. void CPhysics::SetCollision(bool bCollision) { m_bCollision = bCollision; } bool CPhysics::GetCollision() { return m_bCollision; } // Indicates whether the influence of soil is activated or not. void CPhysics::SetFreeze(bool bFreeze) { m_bFreeze = bFreeze; } bool CPhysics::GetFreeze() { return m_bFreeze; } // Returns the range of the reactor. void CPhysics::SetReactorRange(float range) { m_reactorRange = range; } float CPhysics::GetReactorRange() { return m_reactorRange; } // Specifies the engine speed. // x = forward/backward // y = up/down // z = turn void CPhysics::SetMotorSpeed(Math::Vector speed) { m_motorSpeed = speed; } // Specifies the engine speed for forward/backward. // +1 = forward // -1 = backward void CPhysics::SetMotorSpeedX(float speed) { m_motorSpeed.x = speed; } // Specifies the motor speed for up/down. // +1 = up // -1 = down void CPhysics::SetMotorSpeedY(float speed) { m_motorSpeed.y = speed; } // Specifies the speed of the motor to turn. // +1 = turn right(CW) // -1 = turn left(CCW) void CPhysics::SetMotorSpeedZ(float speed) { m_motorSpeed.z = speed; } Math::Vector CPhysics::GetMotorSpeed() { return m_motorSpeed; } float CPhysics::GetMotorSpeedX() { return m_motorSpeed.x; } float CPhysics::GetMotorSpeedY() { return m_motorSpeed.y; } float CPhysics::GetMotorSpeedZ() { return m_motorSpeed.z; } // Management of linear and angular velocities. // Specifies the speed parallel to the direction of travel. void CPhysics::SetLinMotion(PhysicsMode mode, Math::Vector value) { if ( mode == MO_ADVACCEL ) m_linMotion.advanceAccel = value; if ( mode == MO_RECACCEL ) m_linMotion.recedeAccel = value; if ( mode == MO_STOACCEL ) m_linMotion.stopAccel = value; if ( mode == MO_TERSPEED ) m_linMotion.terrainSpeed = value; if ( mode == MO_TERSLIDE ) m_linMotion.terrainSlide = value; if ( mode == MO_MOTACCEL ) m_linMotion.motorAccel = value; if ( mode == MO_TERFORCE ) m_linMotion.terrainForce = value; if ( mode == MO_ADVSPEED ) m_linMotion.advanceSpeed = value; if ( mode == MO_RECSPEED ) m_linMotion.recedeSpeed = value; if ( mode == MO_MOTSPEED ) m_linMotion.motorSpeed = value; if ( mode == MO_CURSPEED ) m_linMotion.currentSpeed = value; if ( mode == MO_REASPEED ) m_linMotion.realSpeed = value; } Math::Vector CPhysics::GetLinMotion(PhysicsMode mode) { if ( mode == MO_ADVACCEL ) return m_linMotion.advanceAccel; if ( mode == MO_RECACCEL ) return m_linMotion.recedeAccel; if ( mode == MO_STOACCEL ) return m_linMotion.stopAccel; if ( mode == MO_TERSPEED ) return m_linMotion.terrainSpeed; if ( mode == MO_TERSLIDE ) return m_linMotion.terrainSlide; if ( mode == MO_MOTACCEL ) return m_linMotion.motorAccel; if ( mode == MO_TERFORCE ) return m_linMotion.terrainForce; if ( mode == MO_ADVSPEED ) return m_linMotion.advanceSpeed; if ( mode == MO_RECSPEED ) return m_linMotion.recedeSpeed; if ( mode == MO_MOTSPEED ) return m_linMotion.motorSpeed; if ( mode == MO_CURSPEED ) return m_linMotion.currentSpeed; if ( mode == MO_REASPEED ) return m_linMotion.realSpeed; return Math::Vector(0.0f, 0.0f, 0.0f); } void CPhysics::SetLinMotionX(PhysicsMode mode, float value) { if ( mode == MO_ADVACCEL ) m_linMotion.advanceAccel.x = value; if ( mode == MO_RECACCEL ) m_linMotion.recedeAccel.x = value; if ( mode == MO_STOACCEL ) m_linMotion.stopAccel.x = value; if ( mode == MO_TERSPEED ) m_linMotion.terrainSpeed.x = value; if ( mode == MO_TERSLIDE ) m_linMotion.terrainSlide.x = value; if ( mode == MO_MOTACCEL ) m_linMotion.motorAccel.x = value; if ( mode == MO_TERFORCE ) m_linMotion.terrainForce.x = value; if ( mode == MO_ADVSPEED ) m_linMotion.advanceSpeed.x = value; if ( mode == MO_RECSPEED ) m_linMotion.recedeSpeed.x = value; if ( mode == MO_MOTSPEED ) m_linMotion.motorSpeed.x = value; if ( mode == MO_CURSPEED ) m_linMotion.currentSpeed.x = value; if ( mode == MO_REASPEED ) m_linMotion.realSpeed.x = value; } float CPhysics::GetLinMotionX(PhysicsMode mode) { if ( mode == MO_ADVACCEL ) return m_linMotion.advanceAccel.x; if ( mode == MO_RECACCEL ) return m_linMotion.recedeAccel.x; if ( mode == MO_STOACCEL ) return m_linMotion.stopAccel.x; if ( mode == MO_TERSPEED ) return m_linMotion.terrainSpeed.x; if ( mode == MO_TERSLIDE ) return m_linMotion.terrainSlide.x; if ( mode == MO_MOTACCEL ) return m_linMotion.motorAccel.x; if ( mode == MO_TERFORCE ) return m_linMotion.terrainForce.x; if ( mode == MO_ADVSPEED ) return m_linMotion.advanceSpeed.x; if ( mode == MO_RECSPEED ) return m_linMotion.recedeSpeed.x; if ( mode == MO_MOTSPEED ) return m_linMotion.motorSpeed.x; if ( mode == MO_CURSPEED ) return m_linMotion.currentSpeed.x; if ( mode == MO_REASPEED ) return m_linMotion.realSpeed.x; return 0.0f; } // Specifies the speed of elevation. void CPhysics::SetLinMotionY(PhysicsMode mode, float value) { if ( mode == MO_ADVACCEL ) m_linMotion.advanceAccel.y = value; if ( mode == MO_RECACCEL ) m_linMotion.recedeAccel.y = value; if ( mode == MO_STOACCEL ) m_linMotion.stopAccel.y = value; if ( mode == MO_TERSPEED ) m_linMotion.terrainSpeed.y = value; if ( mode == MO_TERSLIDE ) m_linMotion.terrainSlide.y = value; if ( mode == MO_MOTACCEL ) m_linMotion.motorAccel.y = value; if ( mode == MO_TERFORCE ) m_linMotion.terrainForce.y = value; if ( mode == MO_ADVSPEED ) m_linMotion.advanceSpeed.y = value; if ( mode == MO_RECSPEED ) m_linMotion.recedeSpeed.y = value; if ( mode == MO_MOTSPEED ) m_linMotion.motorSpeed.y = value; if ( mode == MO_CURSPEED ) m_linMotion.currentSpeed.y = value; if ( mode == MO_REASPEED ) m_linMotion.realSpeed.y = value; } float CPhysics::GetLinMotionY(PhysicsMode mode) { if ( mode == MO_ADVACCEL ) return m_linMotion.advanceAccel.y; if ( mode == MO_RECACCEL ) return m_linMotion.recedeAccel.y; if ( mode == MO_STOACCEL ) return m_linMotion.stopAccel.y; if ( mode == MO_TERSPEED ) return m_linMotion.terrainSpeed.y; if ( mode == MO_TERSLIDE ) return m_linMotion.terrainSlide.y; if ( mode == MO_MOTACCEL ) return m_linMotion.motorAccel.y; if ( mode == MO_TERFORCE ) return m_linMotion.terrainForce.y; if ( mode == MO_ADVSPEED ) return m_linMotion.advanceSpeed.y; if ( mode == MO_RECSPEED ) return m_linMotion.recedeSpeed.y; if ( mode == MO_MOTSPEED ) return m_linMotion.motorSpeed.y; if ( mode == MO_CURSPEED ) return m_linMotion.currentSpeed.y; if ( mode == MO_REASPEED ) return m_linMotion.realSpeed.y; return 0.0f; } // Specifies the velocity perpendicular to the direction of travel. void CPhysics::SetLinMotionZ(PhysicsMode mode, float value) { if ( mode == MO_ADVACCEL ) m_linMotion.advanceAccel.z = value; if ( mode == MO_RECACCEL ) m_linMotion.recedeAccel.z = value; if ( mode == MO_STOACCEL ) m_linMotion.stopAccel.z = value; if ( mode == MO_TERSPEED ) m_linMotion.terrainSpeed.z = value; if ( mode == MO_TERSLIDE ) m_linMotion.terrainSlide.z = value; if ( mode == MO_MOTACCEL ) m_linMotion.motorAccel.z = value; if ( mode == MO_TERFORCE ) m_linMotion.terrainForce.z = value; if ( mode == MO_ADVSPEED ) m_linMotion.advanceSpeed.z = value; if ( mode == MO_RECSPEED ) m_linMotion.recedeSpeed.z = value; if ( mode == MO_MOTSPEED ) m_linMotion.motorSpeed.z = value; if ( mode == MO_CURSPEED ) m_linMotion.currentSpeed.z = value; if ( mode == MO_REASPEED ) m_linMotion.realSpeed.z = value; } float CPhysics::GetLinMotionZ(PhysicsMode mode) { if ( mode == MO_ADVACCEL ) return m_linMotion.advanceAccel.z; if ( mode == MO_RECACCEL ) return m_linMotion.recedeAccel.z; if ( mode == MO_STOACCEL ) return m_linMotion.stopAccel.z; if ( mode == MO_TERSPEED ) return m_linMotion.terrainSpeed.z; if ( mode == MO_TERSLIDE ) return m_linMotion.terrainSlide.z; if ( mode == MO_MOTACCEL ) return m_linMotion.motorAccel.z; if ( mode == MO_TERFORCE ) return m_linMotion.terrainForce.z; if ( mode == MO_ADVSPEED ) return m_linMotion.advanceSpeed.z; if ( mode == MO_RECSPEED ) return m_linMotion.recedeSpeed.z; if ( mode == MO_MOTSPEED ) return m_linMotion.motorSpeed.z; if ( mode == MO_CURSPEED ) return m_linMotion.currentSpeed.z; if ( mode == MO_REASPEED ) return m_linMotion.realSpeed.z; return 0.0f; } // Specifies the rotation around the axis of walk. void CPhysics::SetCirMotion(PhysicsMode mode, Math::Vector value) { if ( mode == MO_ADVACCEL ) m_cirMotion.advanceAccel = value; if ( mode == MO_RECACCEL ) m_cirMotion.recedeAccel = value; if ( mode == MO_STOACCEL ) m_cirMotion.stopAccel = value; if ( mode == MO_TERSPEED ) m_cirMotion.terrainSpeed = value; if ( mode == MO_TERSLIDE ) m_cirMotion.terrainSlide = value; if ( mode == MO_MOTACCEL ) m_cirMotion.motorAccel = value; if ( mode == MO_TERFORCE ) m_cirMotion.terrainForce = value; if ( mode == MO_ADVSPEED ) m_cirMotion.advanceSpeed = value; if ( mode == MO_RECSPEED ) m_cirMotion.recedeSpeed = value; if ( mode == MO_MOTSPEED ) m_cirMotion.motorSpeed = value; if ( mode == MO_CURSPEED ) m_cirMotion.currentSpeed = value; if ( mode == MO_REASPEED ) m_cirMotion.realSpeed = value; } Math::Vector CPhysics::GetCirMotion(PhysicsMode mode) { if ( mode == MO_ADVACCEL ) return m_cirMotion.advanceAccel; if ( mode == MO_RECACCEL ) return m_cirMotion.recedeAccel; if ( mode == MO_STOACCEL ) return m_cirMotion.stopAccel; if ( mode == MO_TERSPEED ) return m_cirMotion.terrainSpeed; if ( mode == MO_TERSLIDE ) return m_cirMotion.terrainSlide; if ( mode == MO_MOTACCEL ) return m_cirMotion.motorAccel; if ( mode == MO_TERFORCE ) return m_cirMotion.terrainForce; if ( mode == MO_ADVSPEED ) return m_cirMotion.advanceSpeed; if ( mode == MO_RECSPEED ) return m_cirMotion.recedeSpeed; if ( mode == MO_MOTSPEED ) return m_cirMotion.motorSpeed; if ( mode == MO_CURSPEED ) return m_cirMotion.currentSpeed; if ( mode == MO_REASPEED ) return m_cirMotion.realSpeed; return Math::Vector(0.0f, 0.0f, 0.0f); } void CPhysics::SetCirMotionX(PhysicsMode mode, float value) { if ( mode == MO_ADVACCEL ) m_cirMotion.advanceAccel.x = value; if ( mode == MO_RECACCEL ) m_cirMotion.recedeAccel.x = value; if ( mode == MO_STOACCEL ) m_cirMotion.stopAccel.x = value; if ( mode == MO_TERSPEED ) m_cirMotion.terrainSpeed.x = value; if ( mode == MO_TERSLIDE ) m_cirMotion.terrainSlide.x = value; if ( mode == MO_MOTACCEL ) m_cirMotion.motorAccel.x = value; if ( mode == MO_TERFORCE ) m_cirMotion.terrainForce.x = value; if ( mode == MO_ADVSPEED ) m_cirMotion.advanceSpeed.x = value; if ( mode == MO_RECSPEED ) m_cirMotion.recedeSpeed.x = value; if ( mode == MO_MOTSPEED ) m_cirMotion.motorSpeed.x = value; if ( mode == MO_CURSPEED ) m_cirMotion.currentSpeed.x = value; if ( mode == MO_REASPEED ) m_cirMotion.realSpeed.x = value; } float CPhysics::GetCirMotionX(PhysicsMode mode) { if ( mode == MO_ADVACCEL ) return m_cirMotion.advanceAccel.x; if ( mode == MO_RECACCEL ) return m_cirMotion.recedeAccel.x; if ( mode == MO_STOACCEL ) return m_cirMotion.stopAccel.x; if ( mode == MO_TERSPEED ) return m_cirMotion.terrainSpeed.x; if ( mode == MO_TERSLIDE ) return m_cirMotion.terrainSlide.x; if ( mode == MO_MOTACCEL ) return m_cirMotion.motorAccel.x; if ( mode == MO_TERFORCE ) return m_cirMotion.terrainForce.x; if ( mode == MO_ADVSPEED ) return m_cirMotion.advanceSpeed.x; if ( mode == MO_RECSPEED ) return m_cirMotion.recedeSpeed.x; if ( mode == MO_MOTSPEED ) return m_cirMotion.motorSpeed.x; if ( mode == MO_CURSPEED ) return m_cirMotion.currentSpeed.x; if ( mode == MO_REASPEED ) return m_cirMotion.realSpeed.x; return 0.0f; } // Specifies the rotation direction. void CPhysics::SetCirMotionY(PhysicsMode mode, float value) { if ( mode == MO_ADVACCEL ) m_cirMotion.advanceAccel.y = value; if ( mode == MO_RECACCEL ) m_cirMotion.recedeAccel.y = value; if ( mode == MO_STOACCEL ) m_cirMotion.stopAccel.y = value; if ( mode == MO_TERSPEED ) m_cirMotion.terrainSpeed.y = value; if ( mode == MO_TERSLIDE ) m_cirMotion.terrainSlide.y = value; if ( mode == MO_MOTACCEL ) m_cirMotion.motorAccel.y = value; if ( mode == MO_TERFORCE ) m_cirMotion.terrainForce.y = value; if ( mode == MO_ADVSPEED ) m_cirMotion.advanceSpeed.y = value; if ( mode == MO_RECSPEED ) m_cirMotion.recedeSpeed.y = value; if ( mode == MO_MOTSPEED ) m_cirMotion.motorSpeed.y = value; if ( mode == MO_CURSPEED ) m_cirMotion.currentSpeed.y = value; if ( mode == MO_REASPEED ) m_cirMotion.realSpeed.y = value; } float CPhysics::GetCirMotionY(PhysicsMode mode) { if ( mode == MO_ADVACCEL ) return m_cirMotion.advanceAccel.y; if ( mode == MO_RECACCEL ) return m_cirMotion.recedeAccel.y; if ( mode == MO_STOACCEL ) return m_cirMotion.stopAccel.y; if ( mode == MO_TERSPEED ) return m_cirMotion.terrainSpeed.y; if ( mode == MO_TERSLIDE ) return m_cirMotion.terrainSlide.y; if ( mode == MO_MOTACCEL ) return m_cirMotion.motorAccel.y; if ( mode == MO_TERFORCE ) return m_cirMotion.terrainForce.y; if ( mode == MO_ADVSPEED ) return m_cirMotion.advanceSpeed.y; if ( mode == MO_RECSPEED ) return m_cirMotion.recedeSpeed.y; if ( mode == MO_MOTSPEED ) return m_cirMotion.motorSpeed.y; if ( mode == MO_CURSPEED ) return m_cirMotion.currentSpeed.y; if ( mode == MO_REASPEED ) return m_cirMotion.realSpeed.y; return 0.0f; } // Specifies the rotation up/down. void CPhysics::SetCirMotionZ(PhysicsMode mode, float value) { if ( mode == MO_ADVACCEL ) m_cirMotion.advanceAccel.z = value; if ( mode == MO_RECACCEL ) m_cirMotion.recedeAccel.z = value; if ( mode == MO_STOACCEL ) m_cirMotion.stopAccel.z = value; if ( mode == MO_TERSPEED ) m_cirMotion.terrainSpeed.z = value; if ( mode == MO_TERSLIDE ) m_cirMotion.terrainSlide.z = value; if ( mode == MO_MOTACCEL ) m_cirMotion.motorAccel.z = value; if ( mode == MO_TERFORCE ) m_cirMotion.terrainForce.z = value; if ( mode == MO_ADVSPEED ) m_cirMotion.advanceSpeed.z = value; if ( mode == MO_RECSPEED ) m_cirMotion.recedeSpeed.z = value; if ( mode == MO_MOTSPEED ) m_cirMotion.motorSpeed.z = value; if ( mode == MO_CURSPEED ) m_cirMotion.currentSpeed.z = value; if ( mode == MO_REASPEED ) m_cirMotion.realSpeed.z = value; } float CPhysics::GetCirMotionZ(PhysicsMode mode) { if ( mode == MO_ADVACCEL ) return m_cirMotion.advanceAccel.z; if ( mode == MO_RECACCEL ) return m_cirMotion.recedeAccel.z; if ( mode == MO_STOACCEL ) return m_cirMotion.stopAccel.z; if ( mode == MO_TERSPEED ) return m_cirMotion.terrainSpeed.z; if ( mode == MO_TERSLIDE ) return m_cirMotion.terrainSlide.z; if ( mode == MO_MOTACCEL ) return m_cirMotion.motorAccel.z; if ( mode == MO_TERFORCE ) return m_cirMotion.terrainForce.z; if ( mode == MO_ADVSPEED ) return m_cirMotion.advanceSpeed.z; if ( mode == MO_RECSPEED ) return m_cirMotion.recedeSpeed.z; if ( mode == MO_MOTSPEED ) return m_cirMotion.motorSpeed.z; if ( mode == MO_CURSPEED ) return m_cirMotion.currentSpeed.z; if ( mode == MO_REASPEED ) return m_cirMotion.realSpeed.z; return 0.0f; } // Returns the linear distance braking. // // v*v // d = ----- // 2a float CPhysics::GetLinStopLength(PhysicsMode sMode, PhysicsMode aMode) { float speed, accel; speed = GetLinMotionX(sMode); // MO_ADVSPEED/MO_RECSPEED accel = GetLinMotionX(aMode); // MO_ADVACCEL/MO_RECACCEL/MO_STOACCEL if ( m_type == TYPE_FLYING && m_bLand ) // flying on the ground? { speed /= LANDING_SPEED; accel *= LANDING_ACCEL; } return (speed*speed) / (accel*2.0f); } // Returns the angle of circular braking. float CPhysics::GetCirStopLength() { return m_cirMotion.advanceSpeed.y * m_cirMotion.advanceSpeed.y / m_cirMotion.stopAccel.y / 2.0f; } // Returns the length advanced into a second, on the ground, maximum speed. float CPhysics::GetLinMaxLength(float dir) { float dist; if ( dir > 0.0f ) dist = m_linMotion.advanceSpeed.x; else dist = m_linMotion.recedeSpeed.x; if ( m_type == TYPE_FLYING ) { dist /= 5.0f; } return dist; } // Returns the time needed to travel some distance. float CPhysics::GetLinTimeLength(float dist, float dir) { float accel, decel, dps; if ( dir > 0.0f ) { accel = GetLinStopLength(MO_ADVSPEED, MO_ADVACCEL); decel = GetLinStopLength(MO_ADVSPEED, MO_STOACCEL); } else { accel = GetLinStopLength(MO_RECSPEED, MO_RECACCEL); decel = GetLinStopLength(MO_RECSPEED, MO_STOACCEL); } dps = GetLinMaxLength(dir); return (dist+accel+decel)/dps; } // Returns the length for a forward travel some distance, taking into account the accelerations / decelerations. float CPhysics::GetLinLength(float dist) { float accDist, desDist; if ( dist > 0.0f ) { accDist = GetLinStopLength(MO_ADVSPEED, MO_ADVACCEL); desDist = GetLinStopLength(MO_ADVSPEED, MO_STOACCEL); if ( dist > accDist+desDist ) { return dist-desDist; } return dist*m_linMotion.stopAccel.x / (m_linMotion.advanceAccel.x+m_linMotion.stopAccel.x); } else { dist = -dist; accDist = GetLinStopLength(MO_RECSPEED, MO_RECACCEL); desDist = GetLinStopLength(MO_RECSPEED, MO_STOACCEL); if ( dist > accDist+desDist ) { return dist-desDist; } return dist*m_linMotion.stopAccel.x / (m_linMotion.recedeAccel.x+m_linMotion.stopAccel.x); } } // Management of an event. // Returns false if the object is destroyed. bool CPhysics::EventProcess(const Event &event) { if ( !m_object->GetEnable() ) return true; if ( m_brain != 0 ) { m_brain->EventProcess(event); } if ( event.type == EVENT_FRAME ) { return EventFrame(event); } return true; } // Updates instructions for the motor speed. void CPhysics::MotorUpdate(float aTime, float rTime) { ObjectType type; CObject* power; Math::Vector pos, motorSpeed; float energy, speed, factor, h; type = m_object->GetType(); if(std::isnan(m_motorSpeed.x)) m_motorSpeed.x = 0.f; if(std::isnan(m_motorSpeed.y)) m_motorSpeed.y = 0.f; if(std::isnan(m_motorSpeed.z)) m_motorSpeed.z = 0.f; motorSpeed = m_motorSpeed; if ( type == OBJECT_MOTHER || type == OBJECT_ANT || type == OBJECT_SPIDER || type == OBJECT_BEE || type == OBJECT_WORM || type == OBJECT_APOLLO2 || type == OBJECT_MOBILEdr || type == OBJECT_CONTROLLER) { power = 0; } else if ( type == OBJECT_HUMAN || type == OBJECT_TECH ) { power = 0; if ( m_object->GetFret() != 0 && // carries something? !m_object->GetCargo() ) { motorSpeed.x *= 0.7f; // forward more slowly motorSpeed.z *= 0.5f; motorSpeed.y = -1.0f; // grave } if ( m_bSwim ) { if ( m_bLand ) // deep in the water? { motorSpeed.x *= 0.4f; // forward more slowly motorSpeed.z *= 0.5f; motorSpeed.y *= 0.5f; if ( m_object->GetFret() != 0 ) // carries something? { motorSpeed.x *= 0.2f; motorSpeed.z *= 0.9f; motorSpeed.y *= 0.2f; } } else // swimming? { motorSpeed.x *= 0.2f; // forward more slowly motorSpeed.z *= 0.5f; motorSpeed.y *= 0.2f; } } } else { power = m_object->GetPower(); // searches for the object battery uses if ( power == 0 || power->GetEnergy() == 0.0f ) // no battery or flat? { motorSpeed.x = 0.0f; motorSpeed.z = 0.0f; if ( m_bFreeze || m_bLand ) { motorSpeed.y = 0.0f; // immobile } else { motorSpeed.y = -1.0f; // grave SetFalling(); } SetMotor(false); } } if ( m_object->GetDead() ) // dead man? { motorSpeed.x = 0.0f; motorSpeed.z = 0.0f; if ( m_motion->GetAction() == MHS_DEADw ) // drowned? { motorSpeed.y = 0.0f; // this is MHS_DEADw going back } else { motorSpeed.y = -1.0f; // grave } SetMotor(false); } if ( m_type == TYPE_FLYING && !m_bLand && motorSpeed.y > 0.0f ) { pos = m_object->GetPosition(0); h = m_terrain->GetFlyingLimit(pos, type==OBJECT_BEE); h += m_object->GetCharacter()->height; if ( pos.y > h-40.0f ) // almost at the top? { factor = 1.0f-(pos.y-(h-40.0f))/40.0f; if ( factor < -1.0f ) factor = -1.0f; if ( factor > 1.0f ) factor = 1.0f; motorSpeed.y *= factor; // limit the rate of rise } } if ( type != OBJECT_BEE && m_object->GetRange() > 0.0f ) // limited flight range? { if ( m_bLand || m_bSwim || m_bObstacle ) // on the ground or in the water? { factor = 1.0f; if ( m_bObstacle ) factor = 3.0f; // in order to leave! if ( m_bSwim ) factor = 3.0f; // cools faster in water m_reactorRange += rTime*(1.0f/5.0f)*factor; if ( m_reactorRange > 1.0f ) { m_reactorRange = 1.0f; if ( m_bLowLevel && m_object->GetSelect() ) // beep cool? { m_sound->Play(SOUND_INFO, m_object->GetPosition(0), 1.0f, 2.0f); m_bLowLevel = false; } } m_bObstacle = false; } else // in flight? { m_reactorRange -= rTime*(1.0f/m_object->GetRange()); if ( m_reactorRange < 0.0f ) m_reactorRange = 0.0f; if ( m_reactorRange < 0.5f ) m_bLowLevel = true; } if ( m_reactorRange == 0.0f ) // reactor tilt? { motorSpeed.y = -1.0f; // grave SetFalling(); } } //? MotorParticle(aTime); // Forward/backward. if ( motorSpeed.x > 0.0f ) { m_linMotion.motorAccel.x = m_linMotion.advanceAccel.x; m_linMotion.motorSpeed.x = m_linMotion.advanceSpeed.x * motorSpeed.x; } if ( motorSpeed.x < 0.0f ) { m_linMotion.motorAccel.x = m_linMotion.recedeAccel.x; m_linMotion.motorSpeed.x = m_linMotion.recedeSpeed.x * motorSpeed.x; } if ( motorSpeed.x == 0.0f ) { m_linMotion.motorAccel.x = m_linMotion.stopAccel.x; m_linMotion.motorSpeed.x = 0.0f; } // Up/down. if ( motorSpeed.y > 0.0f ) { m_linMotion.motorAccel.y = m_linMotion.advanceAccel.y; m_linMotion.motorSpeed.y = m_linMotion.advanceSpeed.y * motorSpeed.y; } if ( motorSpeed.y < 0.0f ) { m_linMotion.motorAccel.y = m_linMotion.recedeAccel.y; m_linMotion.motorSpeed.y = m_linMotion.recedeSpeed.y * motorSpeed.y; } if ( motorSpeed.y == 0.0f ) { m_linMotion.motorAccel.y = m_linMotion.stopAccel.y; m_linMotion.motorSpeed.y = 0.0f; } // Turn left/right. speed = motorSpeed.z; //? if ( motorSpeed.x < 0.0f ) speed = -speed; // reverse if running back if ( motorSpeed.z > 0.0f ) { m_cirMotion.motorAccel.y = m_cirMotion.advanceAccel.y; m_cirMotion.motorSpeed.y = m_cirMotion.advanceSpeed.y * speed; } if ( motorSpeed.z < 0.0f ) { m_cirMotion.motorAccel.y = m_cirMotion.recedeAccel.y; m_cirMotion.motorSpeed.y = m_cirMotion.recedeSpeed.y * speed; } if ( motorSpeed.z == 0.0f ) { m_cirMotion.motorAccel.y = m_cirMotion.stopAccel.y; m_cirMotion.motorSpeed.y = 0.0f; } if ( m_type == TYPE_FLYING && m_bLand ) // flying on the ground? { if ( type == OBJECT_HUMAN || type == OBJECT_TECH ) { factor = LANDING_ACCELh; } else { factor = LANDING_ACCEL; } m_linMotion.motorAccel.x = m_linMotion.stopAccel.x*factor; m_cirMotion.motorAccel.y = m_cirMotion.stopAccel.y*factor; pos = m_object->GetPosition(0); h = m_terrain->GetFlyingLimit(pos, type==OBJECT_BEE); h += m_object->GetCharacter()->height; if ( motorSpeed.y > 0.0f && m_reactorRange > 0.1f && pos.y < h ) { m_bLand = false; // take off SetMotor(true); pos.y += 0.05f; // small initial height (startup) m_object->SetPosition(0, pos); } } if ( m_type == TYPE_ROLLING ) { if ( motorSpeed.x == 0.0f && motorSpeed.z == 0.0f ) { SetMotor(false); } else { SetMotor(true); } } if ( power != 0 ) // battery transported? { factor = 1.0f; if ( type == OBJECT_MOBILEia || type == OBJECT_MOBILEis || type == OBJECT_MOBILEic || type == OBJECT_MOBILEii ) factor = 0.5f; factor /= power->GetCapacity(); energy = power->GetEnergy(); energy -= fabs(motorSpeed.x)*rTime*factor*0.005f; energy -= fabs(motorSpeed.z)*rTime*factor*0.005f; if ( m_type == TYPE_FLYING && motorSpeed.y > 0.0f ) { energy -= motorSpeed.y*rTime*factor*0.01f; } if ( energy < 0.0f ) energy = 0.0f; power->SetEnergy(energy); } } // Updates the effects of vibration and tilt. void CPhysics::EffectUpdate(float aTime, float rTime) { Character* character; Math::Vector vibLin, vibCir, incl; float speedLin, speedCir, accel; ObjectType type; bool bOnBoard; if ( !m_engine->IsVisiblePoint(m_object->GetPosition(0)) ) return; type = m_object->GetType(); character = m_object->GetCharacter(); bOnBoard = false; if ( m_object->GetSelect() && m_camera->GetType() == Gfx::CAM_TYPE_ONBOARD ) { bOnBoard = true; } vibLin = m_motion->GetLinVibration(); vibCir = m_motion->GetCirVibration(); incl = m_motion->GetInclinaison(); if ( type == OBJECT_HUMAN || // human? type == OBJECT_TECH ) { if ( !m_bLand && !m_bSwim ) // in flight? { vibLin.y = sinf(aTime*2.00f)*0.5f+ sinf(aTime*2.11f)*0.3f; vibCir.z = sinf(aTime*Math::PI* 2.01f)*(Math::PI/150.0f)+ sinf(aTime*Math::PI* 2.51f)*(Math::PI/200.0f)+ sinf(aTime*Math::PI*19.01f)*(Math::PI/400.0f); vibCir.x = sinf(aTime*Math::PI* 2.03f)*(Math::PI/150.0f)+ sinf(aTime*Math::PI* 2.52f)*(Math::PI/200.0f)+ sinf(aTime*Math::PI*19.53f)*(Math::PI/400.0f); speedLin = m_linMotion.realSpeed.x / m_linMotion.advanceSpeed.x; speedCir = m_cirMotion.realSpeed.y / m_cirMotion.advanceSpeed.y; incl.x = -speedLin*speedCir*0.5f; // looks if turn //? speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.5f; speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.2f; speedLin /= m_linMotion.advanceSpeed.x; m_linMotion.finalInclin.z = speedLin*1.4f; if ( incl.z < m_linMotion.finalInclin.z ) { incl.z += rTime*0.4f; if ( incl.z > m_linMotion.finalInclin.z ) { incl.z = m_linMotion.finalInclin.z; } } else if ( incl.z > m_linMotion.finalInclin.z ) { incl.z -= rTime*0.4f; if ( incl.z < m_linMotion.finalInclin.z ) { incl.z = m_linMotion.finalInclin.z; } } vibLin *= m_linVibrationFactor; vibCir *= m_cirVibrationFactor; incl *= m_inclinaisonFactor; m_motion->SetLinVibration(vibLin); m_motion->SetCirVibration(vibCir); m_motion->SetInclinaison(incl); } else if ( m_bSwim ) // swimming? { vibLin.y = sinf(aTime*2.00f)*0.5f+ sinf(aTime*2.11f)*0.3f; vibCir.z = sinf(aTime*Math::PI* 2.01f)*(Math::PI/150.0f)+ sinf(aTime*Math::PI* 2.51f)*(Math::PI/200.0f)+ //? sinf(aTime*Math::PI*19.01f)*(Math::PI/400.0f)-Math::PI/2.0f; sinf(aTime*Math::PI*19.01f)*(Math::PI/400.0f); vibCir.x = sinf(aTime*Math::PI* 2.03f)*(Math::PI/150.0f)+ sinf(aTime*Math::PI* 2.52f)*(Math::PI/200.0f)+ sinf(aTime*Math::PI*19.53f)*(Math::PI/400.0f); speedLin = m_linMotion.realSpeed.x / m_linMotion.advanceSpeed.x; speedCir = m_cirMotion.realSpeed.y / m_cirMotion.advanceSpeed.y; incl.x = -speedLin*speedCir*5.0f; // looks if turn //? speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.5f; speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.2f; speedLin /= m_linMotion.advanceSpeed.x; m_linMotion.finalInclin.z = speedLin*1.4f; if ( incl.z < m_linMotion.finalInclin.z ) { incl.z += rTime*0.4f; if ( incl.z > m_linMotion.finalInclin.z ) { incl.z = m_linMotion.finalInclin.z; } } else if ( incl.z > m_linMotion.finalInclin.z ) { incl.z -= rTime*0.4f; if ( incl.z < m_linMotion.finalInclin.z ) { incl.z = m_linMotion.finalInclin.z; } } if ( m_linMotion.realSpeed.y > 0.0f ) // up? { vibCir.z += m_linMotion.realSpeed.y*0.05f; } else // down? { vibCir.z += m_linMotion.realSpeed.y*0.12f; } vibCir.z -= Math::PI*0.4f; vibLin *= m_linVibrationFactor; vibCir *= m_cirVibrationFactor; incl *= m_inclinaisonFactor; m_motion->SetLinVibration(vibLin); m_motion->SetCirVibration(vibCir); m_motion->SetInclinaison(incl); } else { m_motion->SetLinVibration(Math::Vector(0.0f, 0.0f, 0.0f)); //? m_motion->SetCirVibration(Math::Vector(0.0f, 0.0f, 0.0f)); //? m_motion->SetInclinaison(Math::Vector(0.0f, 0.0f, 0.0f)); } } if ( type == OBJECT_MOBILEwa || type == OBJECT_MOBILEwc || type == OBJECT_MOBILEwi || type == OBJECT_MOBILEws || type == OBJECT_MOBILEwt || type == OBJECT_MOBILEtg || type == OBJECT_APOLLO2 ) // wheels? { speedLin = m_linMotion.realSpeed.x / m_linMotion.advanceSpeed.x; speedCir = m_cirMotion.realSpeed.y / m_cirMotion.advanceSpeed.y; incl.x = speedLin*speedCir*0.20f; // looks if turn if ( type == OBJECT_APOLLO2 ) incl.x *= 0.25f; speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x; speedLin /= m_linMotion.advanceSpeed.x; if ( speedLin > 1.0f ) speedLin = 1.0f; m_linMotion.finalInclin.z = -speedLin*0.30f; accel = (0.40f-fabs(incl.z))*4.0f; if ( incl.z < m_linMotion.finalInclin.z ) { incl.z += rTime*accel; if ( incl.z > m_linMotion.finalInclin.z ) { incl.z = m_linMotion.finalInclin.z; } } else if ( incl.z > m_linMotion.finalInclin.z ) { incl.z -= rTime*accel; if ( incl.z < m_linMotion.finalInclin.z ) { incl.z = m_linMotion.finalInclin.z; } } if ( bOnBoard ) incl.z *= 0.1f; if ( type == OBJECT_APOLLO2 ) incl.z *= 0.25f; m_object->SetInclinaison(incl); vibLin.x = 0.0f; vibLin.z = 0.0f; vibLin.y = fabs(character->wheelFront*sinf(incl.z))*0.8f + fabs(character->wheelRight*sinf(incl.x))*0.5f; m_motion->SetLinVibration(vibLin); } if ( type == OBJECT_MOBILEfa || type == OBJECT_MOBILEfc || type == OBJECT_MOBILEfi || type == OBJECT_MOBILEfs || type == OBJECT_MOBILEft ) // fliyng? { if ( m_bLand ) // on the ground? { m_motion->SetLinVibration(Math::Vector(0.0f, 0.0f, 0.0f)); m_motion->SetCirVibration(Math::Vector(0.0f, 0.0f, 0.0f)); m_motion->SetInclinaison(Math::Vector(0.0f, 0.0f, 0.0f)); } else // in flight? { vibLin.y = sinf(aTime*2.00f)*0.5f+ sinf(aTime*2.11f)*0.3f; vibCir.z = sinf(aTime*Math::PI* 2.01f)*(Math::PI/150.0f)+ sinf(aTime*Math::PI* 2.51f)*(Math::PI/200.0f)+ sinf(aTime*Math::PI*19.01f)*(Math::PI/400.0f); vibCir.x = sinf(aTime*Math::PI* 2.03f)*(Math::PI/150.0f)+ sinf(aTime*Math::PI* 2.52f)*(Math::PI/200.0f)+ sinf(aTime*Math::PI*19.53f)*(Math::PI/400.0f); if ( bOnBoard ) vibCir *= 0.4f; speedLin = m_linMotion.realSpeed.x / m_linMotion.advanceSpeed.x; speedCir = m_cirMotion.realSpeed.y / m_cirMotion.advanceSpeed.y; incl.x = -speedLin*speedCir*0.5f; // looks if turn //? speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.5f; speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.2f; speedLin /= m_linMotion.advanceSpeed.x; m_linMotion.finalInclin.z = speedLin*0.8f; if ( incl.z < m_linMotion.finalInclin.z ) { incl.z += rTime*0.4f; if ( incl.z > m_linMotion.finalInclin.z ) { incl.z = m_linMotion.finalInclin.z; } } else if ( incl.z > m_linMotion.finalInclin.z ) { incl.z -= rTime*0.4f; if ( incl.z < m_linMotion.finalInclin.z ) { incl.z = m_linMotion.finalInclin.z; } } //? if ( bOnBoard ) incl.z *= 0.5f; vibLin *= m_linVibrationFactor; vibCir *= m_cirVibrationFactor; incl *= m_inclinaisonFactor; m_motion->SetLinVibration(vibLin); m_motion->SetCirVibration(vibCir); m_motion->SetInclinaison(incl); } } if ( type == OBJECT_BEE ) // bee? { if ( !m_bLand ) // in flight? { vibLin.y = sinf(aTime*2.00f)*0.5f+ sinf(aTime*2.11f)*0.3f; vibCir.z = (Math::Rand()-0.5f)*0.1f+ sinf(aTime*Math::PI* 2.01f)*(Math::PI/150.0f)+ sinf(aTime*Math::PI* 2.51f)*(Math::PI/200.0f)+ sinf(aTime*Math::PI*19.01f)*(Math::PI/400.0f); vibCir.x = (Math::Rand()-0.5f)*0.1f+ sinf(aTime*Math::PI* 2.03f)*(Math::PI/150.0f)+ sinf(aTime*Math::PI* 2.52f)*(Math::PI/200.0f)+ sinf(aTime*Math::PI*19.53f)*(Math::PI/400.0f); speedLin = m_linMotion.realSpeed.x / m_linMotion.advanceSpeed.x; speedCir = m_cirMotion.realSpeed.y / m_cirMotion.advanceSpeed.y; incl.x = -speedLin*speedCir*1.5f; // looks if turn //? speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.5f; speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.2f; speedLin /= m_linMotion.advanceSpeed.x; m_linMotion.finalInclin.z = speedLin*1.4f; if ( incl.z < m_linMotion.finalInclin.z ) { incl.z += rTime*1.6f; if ( incl.z > m_linMotion.finalInclin.z ) { incl.z = m_linMotion.finalInclin.z; } } else if ( incl.z > m_linMotion.finalInclin.z ) { incl.z -= rTime*1.6f; if ( incl.z < m_linMotion.finalInclin.z ) { incl.z = m_linMotion.finalInclin.z; } } vibLin *= m_linVibrationFactor; vibCir *= m_cirVibrationFactor; incl *= m_inclinaisonFactor; m_motion->SetLinVibration(vibLin); m_motion->SetCirVibration(vibCir); m_motion->SetInclinaison(incl); } } } // Updates structure Motion. void CPhysics::UpdateMotionStruct(float rTime, Motion &motion) { float speed, motor; // Management for the coordinate x. speed = motion.currentSpeed.x; motor = motion.motorSpeed.x * m_inclinaisonFactor; if ( speed < motor ) { speed += rTime*motion.motorAccel.x; // accelerates if ( speed > motor ) { speed = motor; // does not exceed the speed } } if ( speed > motor ) { speed -= rTime*motion.motorAccel.x; // decelerates if ( speed < motor ) { speed = motor; // does not exceed the speed } } motion.currentSpeed.x = speed; motion.realSpeed.x = speed; if ( fabs(motion.terrainSpeed.x) > motion.terrainSlide.x ) { if ( motion.terrainSpeed.x > 0 ) { speed = motion.terrainSpeed.x - motion.terrainSlide.x; } else { speed = motion.terrainSpeed.x + motion.terrainSlide.x; } motion.realSpeed.x += speed; } // Management for the coordinate y. speed = motion.currentSpeed.y; motor = motion.motorSpeed.y; // unlimited speed! if ( speed < motor ) { speed += rTime*motion.motorAccel.y; // accelerates if ( speed > motor ) { speed = motor; // does not exceed the speed } } if ( speed > motor ) { speed -= rTime*motion.motorAccel.y; // decelerates if ( speed < motor ) { speed = motor; // does not exceed the speed } } motion.currentSpeed.y = speed; motion.realSpeed.y = speed; if ( fabs(motion.terrainSpeed.y) > motion.terrainSlide.y ) { if ( motion.terrainSpeed.y > 0 ) { speed = motion.terrainSpeed.y - motion.terrainSlide.y; } else { speed = motion.terrainSpeed.y + motion.terrainSlide.y; } motion.realSpeed.y += speed; } // Management for the coordinate z. speed = motion.currentSpeed.z; motor = motion.motorSpeed.z * m_inclinaisonFactor; if ( speed < motor ) { speed += rTime*motion.motorAccel.z; // accelerates if ( speed > motor ) { speed = motor; // does not exceed the speed } } if ( speed > motor ) { speed -= rTime*motion.motorAccel.z; // decelerates if ( speed < motor ) { speed = motor; // does not exceed the speed } } motion.currentSpeed.z = speed; motion.realSpeed.z = speed; if ( fabs(motion.terrainSpeed.z) > motion.terrainSlide.z ) { if ( motion.terrainSpeed.z > 0 ) { speed = motion.terrainSpeed.z - motion.terrainSlide.z; } else { speed = motion.terrainSpeed.z + motion.terrainSlide.z; } motion.realSpeed.z += speed; } } // Makes physics evolve as time elapsed. // Returns false if the object is destroyed. // // a: acceleration // v1: velocity at time t1 // v2: velocity at time t2 // dt: time elapsed since t1, then: dt = t2-t1 // dd: difference in distance (advance) // // v2 = v1 + a*dt // dd = v2*dt bool CPhysics::EventFrame(const Event &event) { ObjectType type; Math::Matrix objRotate, matRotate; Math::Vector iPos, iAngle, tAngle, pos, newpos, angle, newangle, n; float h, w; int i; if ( m_engine->GetPause() ) return true; m_time += event.rTime; m_timeUnderWater += event.rTime; m_soundTimeJostle += event.rTime; type = m_object->GetType(); FrameParticle(m_time, event.rTime); MotorUpdate(m_time, event.rTime); EffectUpdate(m_time, event.rTime); WaterFrame(m_time, event.rTime); iPos = pos = m_object->GetPosition(0); iAngle = angle = m_object->GetAngle(0); // Accelerate is the descent, brake is the ascent. if ( m_bFreeze || m_object->GetDead() ) { m_linMotion.terrainSpeed.x = 0.0f; m_linMotion.terrainSpeed.z = 0.0f; m_linMotion.terrainSpeed.y = 0.0f; } else { tAngle = angle; h = m_terrain->GetBuildingFactor(pos); if ( type == OBJECT_HUMAN || type == OBJECT_TECH ) { if ( m_linMotion.currentSpeed.x == 0.0f ) { h *= 0.5f; // immobile man -> slippage } FloorAngle(pos, tAngle); // calculates the angle with the ground } #if 1 if ( pos.y < m_water->GetLevel(m_object) ) // underwater? { h *= 0.5f; m_fallingHeight = 0.0f; // can't fall underwater } #endif //? m_linMotion.terrainSpeed.x = -tAngle.z*m_linMotion.terrainForce.x*h; //? m_linMotion.terrainSpeed.z = tAngle.x*m_linMotion.terrainForce.z*h; //? m_linMotion.terrainSpeed.x = -sinf(tAngle.z)*Math::PI*0.5f*m_linMotion.terrainForce.x*h; //? m_linMotion.terrainSpeed.z = sinf(tAngle.x)*Math::PI*0.5f*m_linMotion.terrainForce.z*h; m_linMotion.terrainSpeed.x = -tanf(tAngle.z)*0.9f*m_linMotion.terrainForce.x*h; m_linMotion.terrainSpeed.z = tanf(tAngle.x)*0.9f*m_linMotion.terrainForce.z*h; m_linMotion.terrainSpeed.y = 0.0f; // If the terrain is very steep, do not exaggerate! if ( m_linMotion.terrainSpeed.x > 50.0f ) m_linMotion.terrainSpeed.x = 20.0f; if ( m_linMotion.terrainSpeed.x < -50.0f ) m_linMotion.terrainSpeed.x = -20.0f; if ( m_linMotion.terrainSpeed.z > 50.0f ) m_linMotion.terrainSpeed.z = 20.0f; if ( m_linMotion.terrainSpeed.z < -50.0f ) m_linMotion.terrainSpeed.z = -20.0f; } if ( type == OBJECT_BEE && !m_bLand ) { h = m_floorLevel; // ground level w = m_water->GetLevel(m_object); if ( h < w ) h = w; h = pos.y-h-10.0f; // maximum height (*) if ( h < 0.0f ) h = 0.0f; m_linMotion.terrainSpeed.y = -h*2.5f; // is not above } // (*) High enough to pass over the tower defense (OBJECT_TOWER), // but not too much to pass under the cover of the ship (OBJECT_BASE)! UpdateMotionStruct(event.rTime, m_linMotion); UpdateMotionStruct(event.rTime, m_cirMotion); newangle = angle + event.rTime*m_cirMotion.realSpeed; Math::LoadRotationZXYMatrix(matRotate, newangle); newpos = event.rTime*m_linMotion.realSpeed; newpos = Transform(matRotate, newpos); newpos += pos; m_terrain->AdjustToStandardBounds(newpos); if ( m_type == TYPE_FLYING && !m_bLand ) { h = m_terrain->GetFlyingLimit(newpos, type==OBJECT_BEE); h += m_object->GetCharacter()->height; if ( newpos.y > h ) newpos.y = h; } if ( m_bForceUpdate || newpos.x != pos.x || newpos.y != pos.y || newpos.z != pos.z || newangle.x != angle.x || newangle.y != angle.y || newangle.z != angle.z ) { FloorAdapt(m_time, event.rTime, newpos, newangle); } if ( m_bForceUpdate || newpos.x != pos.x || newpos.y != pos.y || newpos.z != pos.z ) { i = ObjectAdapt(newpos, newangle); if ( i == 2 ) // object destroyed? { return false; } if ( i == 1 ) // immobile object? { newpos = iPos; // keeps the initial position, but accepts the rotation } } if ( newangle.x != angle.x || newangle.y != angle.y || newangle.z != angle.z ) { m_object->SetAngle(0, newangle); } if ( newpos.x != pos.x || newpos.y != pos.y || newpos.z != pos.z ) { m_object->SetPosition(0, newpos); } MotorParticle(m_time, event.rTime); SoundMotor(event.rTime); if ( m_bLand && m_fallingHeight != 0.0f ) // if fell { float force = (m_fallingHeight - m_object->GetPosition(0).y) * m_fallDamageFraction; m_object->ExploObject(EXPLO_BOUM, force); m_fallingHeight = 0.0f; } m_bForceUpdate = false; return true; } // Starts or stops the engine sounds. void CPhysics::SoundMotor(float rTime) { CObject* power; ObjectType type; float energy; m_lastSoundInsect -= rTime; type = m_object->GetType(); if ( type == OBJECT_MOTHER ) { if ( m_lastSoundInsect <= 0.0f && m_object->GetActif() ) { m_sound->Play(SOUND_INSECTm, m_object->GetPosition(0)); if ( m_bMotor ) m_lastSoundInsect = 0.4f+Math::Rand()*2.5f; else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f; } } else if ( type == OBJECT_ANT ) { if ( m_object->GetBurn() || m_object->GetFixed() ) { if ( m_lastSoundInsect <= 0.0f ) { m_sound->Play(SOUND_INSECTa, m_object->GetPosition(0), 1.0f, 1.5f+Math::Rand()*0.5f); m_lastSoundInsect = 0.4f+Math::Rand()*0.6f; } } else if ( m_object->GetActif() ) { if ( m_lastSoundInsect <= 0.0f ) { m_sound->Play(SOUND_INSECTa, m_object->GetPosition(0)); if ( m_bMotor ) m_lastSoundInsect = 0.4f+Math::Rand()*2.5f; else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f; } } } else if ( type == OBJECT_BEE ) { if ( m_object->GetActif() ) { if ( m_lastSoundInsect <= 0.0f ) { m_sound->Play(SOUND_INSECTb, m_object->GetPosition(0)); if ( m_bMotor ) m_lastSoundInsect = 0.4f+Math::Rand()*2.5f; else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f; } } else if ( m_object->GetBurn() ) { if ( m_lastSoundInsect <= 0.0f ) { m_sound->Play(SOUND_INSECTb, m_object->GetPosition(0), 1.0f, 1.5f+Math::Rand()*0.5f); m_lastSoundInsect = 0.3f+Math::Rand()*0.5f; } } } else if ( type == OBJECT_WORM ) { if ( m_object->GetActif() ) { if ( m_lastSoundInsect <= 0.0f ) { m_sound->Play(SOUND_INSECTw, m_object->GetPosition(0)); if ( m_bMotor ) m_lastSoundInsect = 0.4f+Math::Rand()*2.5f; else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f; } } else if ( m_object->GetBurn() ) { if ( m_lastSoundInsect <= 0.0f ) { m_sound->Play(SOUND_INSECTw, m_object->GetPosition(0), 1.0f, 1.5f+Math::Rand()*0.5f); m_lastSoundInsect = 0.2f+Math::Rand()*0.2f; } } } else if ( type == OBJECT_SPIDER ) { if ( m_object->GetBurn() || m_object->GetFixed() ) { if ( m_lastSoundInsect <= 0.0f ) { m_sound->Play(SOUND_INSECTs, m_object->GetPosition(0), 1.0f, 1.5f+Math::Rand()*0.5f); m_lastSoundInsect = 0.4f+Math::Rand()*0.6f; } } else if ( m_object->GetActif() ) { if ( m_lastSoundInsect <= 0.0f ) { m_sound->Play(SOUND_INSECTs, m_object->GetPosition(0)); if ( m_bMotor ) m_lastSoundInsect = 0.4f+Math::Rand()*2.5f; else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f; } } } else // vehicle? { if ( m_type == TYPE_ROLLING ) { if ( m_bMotor && m_object->GetActif() ) { SoundMotorFull(rTime, type); // full diet } else { energy = 0.0f; power = m_object->GetPower(); if ( power != 0 ) { energy = power->GetEnergy(); } if ( m_object->GetSelect() && energy != 0.0f ) { SoundMotorSlow(rTime, type); // in slow motion } else { SoundMotorStop(rTime, type); // to the stop } } } if ( m_type == TYPE_FLYING ) { if ( m_bMotor && !m_bSwim && m_object->GetActif() && !m_object->GetDead() ) { SoundReactorFull(rTime, type); // full diet } else { SoundReactorStop(rTime, type); // to the stop } } } } // Detonates the object if it is underwater. void CPhysics::WaterFrame(float aTime, float rTime) { ObjectType type; Math::Vector pos, speed; Math::Point dim; float level; level = m_water->GetLevel(); if ( level == 0.0f ) return; // no water? if ( m_object->GetTruck() != 0 ) return; // object transported? // Management of flames into the lava. pos = m_object->GetPosition(0); if ( m_water->GetLava() && pos.y-m_object->GetCharacter()->height <= level ) { if ( m_lastFlameParticle+m_engine->ParticleAdapt(0.05f) <= aTime ) { m_lastFlameParticle = aTime; pos = m_object->GetPosition(0); pos.x += (Math::Rand()-0.5f)*3.0f; pos.z += (Math::Rand()-0.5f)*3.0f; speed.x = 0.0f; speed.z = 0.0f; speed.y = Math::Rand()*5.0f+3.0f; dim.x = Math::Rand()*2.0f+1.0f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIFLAME, 2.0f, 0.0f, 0.2f); pos = m_object->GetPosition(0); pos.y -= 2.0f; pos.x += (Math::Rand()-0.5f)*5.0f; pos.z += (Math::Rand()-0.5f)*5.0f; speed.x = 0.0f; speed.z = 0.0f; speed.y = 6.0f+Math::Rand()*6.0f+6.0f; dim.x = Math::Rand()*1.5f+1.0f+3.0f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISMOKE3, 4.0f); } } pos = m_object->GetPosition(0); if ( pos.y >= m_water->GetLevel(m_object) ) return; // out of water? type = m_object->GetType(); if ( type == OBJECT_TOTO ) return; if ( type == OBJECT_NULL ) return; if ( !m_object->GetActif() ) return; if ( m_object->GetResetBusy() ) return; // reset in progress? if ( m_water->GetLava() || (type == OBJECT_HUMAN && m_object->GetOption() != 0 ) || // human without a helmet? 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_MOBILEft || type == OBJECT_MOBILEtt || type == OBJECT_MOBILEwt || type == OBJECT_MOBILEit || type == OBJECT_MOBILEdr || type == OBJECT_APOLLO2 ) // vehicle not underwater? { m_object->ExploObject(EXPLO_WATER, 1.0f); // starts explosion } } // Sounds the engine at full power. void CPhysics::SoundMotorFull(float rTime, ObjectType type) { Sound sound; float amplitude, time, freq; if ( type == OBJECT_MOBILEia || type == OBJECT_MOBILEic || type == OBJECT_MOBILEii || type == OBJECT_MOBILEis ) { if ( m_soundChannel == -1 ) { m_soundChannel = m_sound->Play(SOUND_MOTORi, m_object->GetPosition(0), 0.0f, 1.0f, true); m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 0.2f, SOPER_CONTINUE); m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 1.0f, SOPER_LOOP); } else { m_sound->Position(m_soundChannel, m_object->GetPosition(0)); } freq = 1.0f+m_linMotion.terrainSpeed.x/50.0f; if ( m_linMotion.realSpeed.x == 0.0f ) { freq -= fabs(m_cirMotion.realSpeed.y/3.0f); } else { freq -= fabs(m_cirMotion.realSpeed.y/4.0f); } m_sound->Frequency(m_soundChannel, freq); return; } if ( type == OBJECT_MOBILEsa ) { sound = SOUND_MOTORs; amplitude = 0.6f; time = 0.5f; } else if ( type == OBJECT_MOBILErt || type == OBJECT_MOBILErc || type == OBJECT_MOBILErr || type == OBJECT_MOBILErs ) { sound = SOUND_MOTORr; amplitude = 1.0f; time = 0.7f; } else if ( type == OBJECT_MOBILEta || type == OBJECT_MOBILEtc || type == OBJECT_MOBILEti || type == OBJECT_MOBILEts ) { sound = SOUND_MOTORt; amplitude = 1.0f; time = 0.5f; } else if ( type == OBJECT_APOLLO2 ) { sound = SOUND_MANIP; amplitude = 1.0f; time = 0.5f; } else { sound = SOUND_MOTORw; amplitude = 0.7f; time = 0.3f; } if ( m_object->GetToy() ) { sound = SOUND_NONE; //SOUND_MOTORd; amplitude = 1.0f; time = 0.1f; } freq = 0.75f+(fabs(m_motorSpeed.x)+fabs(m_motorSpeed.z))*0.25f; if ( freq > 1.0f ) freq = 1.0f; if ( m_object->GetToy() ) freq = 1.0f; if ( m_soundChannel == -1 ) { m_soundChannel = m_sound->Play(sound, m_object->GetPosition(0), 0.0f, 0.5f, true); m_sound->AddEnvelope(m_soundChannel, amplitude, freq, time, SOPER_CONTINUE); m_sound->AddEnvelope(m_soundChannel, amplitude, freq, 1.0f, SOPER_LOOP); } else { m_sound->Position(m_soundChannel, m_object->GetPosition(0)); if ( m_bSoundSlow ) // in slow motion? { m_sound->FlushEnvelope(m_soundChannel); m_sound->AddEnvelope(m_soundChannel, amplitude, freq, time, SOPER_CONTINUE); m_sound->AddEnvelope(m_soundChannel, amplitude, freq, 1.0f, SOPER_LOOP); m_bSoundSlow = false; } } freq *= 1.0f + m_linMotion.terrainSpeed.x/100.0f; freq *= 1.0f + fabs(m_cirMotion.realSpeed.y/20.0f); m_sound->Frequency(m_soundChannel, freq); m_soundTimePshhh -= rTime*2.0f; } // Sounds the engine idling. void CPhysics::SoundMotorSlow(float rTime, ObjectType type) { Math::Matrix* mat; Math::Vector pos, speed; Math::Point dim; Sound sound; float amplitude; int i, max; if ( type == OBJECT_MOBILEia || type == OBJECT_MOBILEic || type == OBJECT_MOBILEii || type == OBJECT_MOBILEis ) { if ( m_soundChannel != -1 ) // engine is running? { m_sound->FlushEnvelope(m_soundChannel); m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 0.3f, SOPER_STOP); m_soundChannel = -1; } return; } if ( type == OBJECT_MOBILEsa ) { sound = SOUND_MOTORs; amplitude = 0.4f; } else if ( type == OBJECT_MOBILErt || type == OBJECT_MOBILErc || type == OBJECT_MOBILErr || type == OBJECT_MOBILErs ) { sound = SOUND_MOTORr; amplitude = 0.9f; } else if ( type == OBJECT_MOBILEta || type == OBJECT_MOBILEtc || type == OBJECT_MOBILEti || type == OBJECT_MOBILEts ) { sound = SOUND_MOTORt; amplitude = 0.7f; } else if ( type == OBJECT_APOLLO2 ) { if ( m_soundChannel != -1 ) // engine is running? { m_sound->FlushEnvelope(m_soundChannel); m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.3f, SOPER_STOP); m_soundChannel = -1; } return; } else { sound = SOUND_MOTORw; amplitude = 0.3f; } if ( m_object->GetToy() ) { sound = SOUND_NONE; // SOUND_MOTORd; amplitude = 0.0f; } if ( m_soundChannel == -1 ) { m_soundChannel = m_sound->Play(sound, m_object->GetPosition(0), 0.0f, 0.25f, true); m_sound->AddEnvelope(m_soundChannel, amplitude, 0.5f, 0.2f, SOPER_CONTINUE); m_sound->AddEnvelope(m_soundChannel, amplitude, 0.5f, 1.0f, SOPER_LOOP); } else { m_sound->Position(m_soundChannel, m_object->GetPosition(0)); if ( !m_bSoundSlow ) // full power? { m_sound->FlushEnvelope(m_soundChannel); m_sound->AddEnvelope(m_soundChannel, amplitude, 0.5f, 0.3f, SOPER_CONTINUE); m_sound->AddEnvelope(m_soundChannel, amplitude, 0.5f, 1.0f, SOPER_LOOP); m_bSoundSlow = true; } } if ( type == OBJECT_MOBILErt || type == OBJECT_MOBILErc || type == OBJECT_MOBILErr || type == OBJECT_MOBILErs ) { m_soundTimePshhh -= rTime; if ( m_soundTimePshhh <= 0.0f ) { amplitude = 0.5f-m_soundTimePshhh*0.08f; if ( amplitude > 1.0f ) amplitude = 1.0f; //? m_sound->Play(SOUND_PSHHH, m_object->GetPosition(0), amplitude); m_sound->Play(SOUND_PSHHH, m_object->GetPosition(0), 1.0f); m_soundTimePshhh = 4.0f+4.0f*Math::Rand(); max = static_cast(10.0f*m_engine->GetParticleDensity()); for ( i=0 ; iGetWorldMatrix(0); pos = Transform(*mat, pos); speed = Transform(*mat, speed)-pos; dim.x = Math::Rand()*1.0f+1.0f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIMOTOR, 2.0f); } } } } // Sounds the engine not running. void CPhysics::SoundMotorStop(float rTime, ObjectType type) { if ( type == OBJECT_MOBILEia || type == OBJECT_MOBILEic || type == OBJECT_MOBILEii || type == OBJECT_MOBILEis ) { if ( m_soundChannel != -1 ) // engine is running? { m_sound->FlushEnvelope(m_soundChannel); m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 0.3f, SOPER_STOP); m_soundChannel = -1; } return; } if ( m_soundChannel != -1 ) // engine is running? { m_sound->FlushEnvelope(m_soundChannel); m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.3f, SOPER_STOP); m_soundChannel = -1; } m_soundTimePshhh -= rTime*2.0f; } // Sounds the reactor at full power. void CPhysics::SoundReactorFull(float rTime, ObjectType type) { Sound sound; Math::Matrix* mat; Math::Vector pos, speed; Math::Point dim; float freq; int i; if ( m_soundChannelSlide != -1 ) // slides? { m_sound->FlushEnvelope(m_soundChannelSlide); m_sound->AddEnvelope(m_soundChannelSlide, 0.0f, 1.0f, 0.3f, SOPER_STOP); m_soundChannelSlide = -1; } if ( m_reactorRange > 0.0f ) { if ( m_soundChannel == -1 ) { if ( type == OBJECT_HUMAN || type == OBJECT_TECH ) { sound = SOUND_FLYh; } else { sound = SOUND_FLY; } m_soundChannel = m_sound->Play(sound, m_object->GetPosition(0), 0.0f, 1.0f, true); m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 0.6f, SOPER_CONTINUE); m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 1.0f, SOPER_LOOP); } else { m_sound->Position(m_soundChannel, m_object->GetPosition(0)); } freq = 1.0f + m_linMotion.realSpeed.y/100.0f; freq *= 1.0f + fabs(m_cirMotion.realSpeed.y/5.0f); m_sound->Frequency(m_soundChannel, freq); } else { if ( m_soundChannel != -1 ) // engine is running? { m_sound->FlushEnvelope(m_soundChannel); m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP); m_soundChannel = -1; } if ( m_timeReactorFail <= m_time ) { freq = 1.0f+Math::Rand()*0.5f; m_sound->Play(SOUND_FLYf, m_object->GetPosition(0), 1.0f, freq); m_camera->StartEffect(Gfx::CAM_EFFECT_PET, m_object->GetPosition(0), 1.0f); for ( i=0 ; i<5 ; i++ ) { if ( m_object->GetType() == OBJECT_HUMAN || m_object->GetType() == OBJECT_TECH ) { pos = Math::Vector(-1.6f, -0.5f, 0.0f); } else { pos = Math::Vector(0.0f, -1.0f, 0.0f); } pos.x += (Math::Rand()-0.5f)*2.0f; pos.z += (Math::Rand()-0.5f)*2.0f; mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); speed.x = (Math::Rand()-0.5f)*5.0f; speed.z = (Math::Rand()-0.5f)*5.0f; speed.y = -(4.0f+Math::Rand()*4.0f); dim.x = (2.0f+Math::Rand()*1.0f); dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISMOKE1, 2.0f, 0.0f, 0.1f); } m_timeReactorFail = m_time+0.10f+Math::Rand()*0.30f; } else { if ( m_object->GetType() == OBJECT_HUMAN || m_object->GetType() == OBJECT_TECH ) { pos = Math::Vector(-1.6f, -0.5f, 0.0f); } else { pos = Math::Vector(0.0f, -1.0f, 0.0f); } pos.x += (Math::Rand()-0.5f)*1.0f; pos.z += (Math::Rand()-0.5f)*1.0f; mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); speed.x = (Math::Rand()-0.5f)*2.0f; speed.z = (Math::Rand()-0.5f)*2.0f; speed.y = -(4.0f+Math::Rand()*4.0f); dim.x = (0.7f+Math::Rand()*0.4f); dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISMOKE1, 2.0f, 0.0f, 0.1f); } } } // Sounds the reactor stopped. void CPhysics::SoundReactorStop(float rTime, ObjectType type) { CObject* power; float energy; energy = 0.0f; power = m_object->GetPower(); if ( power != 0 ) { energy = power->GetEnergy(); } if ( m_soundChannel != -1 ) // engine is running? { m_sound->FlushEnvelope(m_soundChannel); m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP); m_soundChannel = -1; } if ( type == OBJECT_HUMAN || type == OBJECT_TECH ) { if ( m_soundChannelSlide != -1 ) // slides? { m_sound->FlushEnvelope(m_soundChannelSlide); m_sound->AddEnvelope(m_soundChannelSlide, 0.0f, 1.0f, 0.3f, SOPER_STOP); m_soundChannelSlide = -1; } } else { if ( energy != 0.0f && (m_motorSpeed.x != 0.0f || // slides with small reactors in skates? m_cirMotion.realSpeed.y != 0.0f) ) { if ( m_soundChannelSlide == -1 ) { m_soundChannelSlide = m_sound->Play(SOUND_SLIDE, m_object->GetPosition(0), 0.0f, 1.0f, true); m_sound->AddEnvelope(m_soundChannelSlide, 0.5f, 1.0f, 0.3f, SOPER_CONTINUE); m_sound->AddEnvelope(m_soundChannelSlide, 0.5f, 1.0f, 1.0f, SOPER_LOOP); } m_sound->Position(m_soundChannelSlide, m_object->GetPosition(0)); } else { if ( m_soundChannelSlide != -1 ) // slides? { m_sound->FlushEnvelope(m_soundChannelSlide); m_sound->AddEnvelope(m_soundChannelSlide, 0.0f, 1.0f, 0.3f, SOPER_STOP); m_soundChannelSlide = -1; } } } } // Adapts the physics of the object based on the ground. void CPhysics::FloorAdapt(float aTime, float rTime, Math::Vector &pos, Math::Vector &angle) { Character* character; ObjectType type; Math::Vector norm; Math::Matrix matRotate; float level, h, f, a1, volume, freq, force; bool bSlopingTerrain; type = m_object->GetType(); character = m_object->GetCharacter(); level = m_water->GetLevel(m_object); SetSwim( pos.y < level ); m_floorLevel = m_terrain->GetFloorLevel(pos); // height above the ground h = pos.y-m_floorLevel; h -= character->height; m_floorHeight = h; WaterParticle(aTime, pos, type, m_floorLevel, fabs(m_linMotion.realSpeed.x), fabs(m_cirMotion.realSpeed.y*15.0f)); if ( m_type == TYPE_ROLLING ) { pos.y -= h; // plate to the ground immediately pos.y += character->height; m_floorHeight = 0.0f; } if ( m_type == TYPE_FLYING ) { bSlopingTerrain = false; // ground as possible to land if ( !m_bLand ) // in flight? { m_terrain->GetNormal(norm, pos); a1 = fabs(Math::RotateAngle(Math::Point(norm.x, norm.z).Length(), norm.y)); if ( a1 < (90.0f-55.0f)*Math::PI/180.0f ) // slope exceeds 55 degrees? { bSlopingTerrain = true; // very sloped ground if ( h < 4.0f ) // collision with the ground? { force = 5.0f+fabs(m_linMotion.realSpeed.x*0.3f)+ fabs(m_linMotion.realSpeed.y*0.3f); m_linMotion.currentSpeed = norm*force; Math::LoadRotationXZYMatrix(matRotate, -angle); m_linMotion.currentSpeed = Transform(matRotate, m_linMotion.currentSpeed); if ( aTime-m_soundTimeBoum > 0.5f ) { volume = fabs(m_linMotion.realSpeed.x*0.02f)+ fabs(m_linMotion.realSpeed.y*0.02f); freq = 0.5f+m_terrain->GetHardness(pos)*2.5f; m_sound->Play(SOUND_BOUM, pos, volume, freq); m_soundTimeBoum = aTime; } //? pos = m_object->GetPosition(0); // gives position before collision } } } if ( (h <= 0.0f || m_bLand) && !bSlopingTerrain ) // on the ground? { if ( !m_bLand ) // in flight? { volume = fabs(m_linMotion.realSpeed.y*0.02f); freq = 0.5f+m_terrain->GetHardness(pos)*2.5f; m_sound->Play(SOUND_BOUM, pos, volume, freq); } m_bLand = true; // on the ground? SetMotor(false); pos.y -= h; // plate to the ground immediately m_floorHeight = 0.0f; if ( h < 0.0f ) { f = fabs(m_linMotion.currentSpeed.y/m_linMotion.advanceSpeed.y); CrashParticle(f); } m_linMotion.currentSpeed.y = 0.0f; m_inclinaisonFactor = 1.0f/LANDING_SPEED; // slips a little to the ground m_linVibrationFactor = 0.0f; m_cirVibrationFactor = 0.0f; if ( type == OBJECT_HUMAN || type == OBJECT_TECH ) return; // always right } if ( h > 4.0f || bSlopingTerrain ) // meters above the ground? { if ( m_bSwim ) { m_linVibrationFactor = 1.0f; // vibrates a max m_cirVibrationFactor = 1.0f; } else { m_linVibrationFactor = 2.0f; // vibrates a large max m_cirVibrationFactor = 2.0f; } m_inclinaisonFactor = 1.0f; // Gives gently the horizontal. if ( angle.x > 0.0f ) { angle.x -= rTime*0.5f; if ( angle.x < 0.0f ) angle.x = 0.0f; } if ( angle.x < 0.0f ) { angle.x += rTime*0.5f; if ( angle.x > 0.0f ) angle.x = 0.0f; } if ( angle.z > 0.0f ) { angle.z -= rTime*0.5f; if ( angle.z < 0.0f ) angle.z = 0.0f; } if ( angle.z < 0.0f ) { angle.z += rTime*0.5f; if ( angle.z > 0.0f ) angle.z = 0.0f; } return; } } if ( m_floorHeight == 0.0f ) // ground plate? { if ( m_object->GetTraceDown() ) { WheelParticle(m_object->GetTraceColor(), m_object->GetTraceWidth()*g_unit); } else { WheelParticle(-1, 0.0f); } } if ( type == OBJECT_HUMAN || type == OBJECT_TECH || type == OBJECT_WORM ) return; // always right FloorAngle(pos, angle); // adjusts the angle at the ground if ( m_type == TYPE_FLYING && !m_bLand ) // flying in the air? { f = h/1.0f; if ( f < 0.0f ) f = 0.0f; if ( f > 1.0f ) f = 1.0f; m_linVibrationFactor = f; m_cirVibrationFactor = f; angle.z *= 1.0f-f; angle.x *= 1.0f-f; f = h/1.0f; if ( f < 0.0f ) f = 0.0f; if ( f > 1.0f ) f = 1.0f; m_inclinaisonFactor = f; } } // Calculates the angle of an object with the field. void CPhysics::FloorAngle(const Math::Vector &pos, Math::Vector &angle) { Character* character; Math::Vector pw, norm; float a1, a2; character = m_object->GetCharacter(); pw.x = pos.x+character->wheelFront*cosf(angle.y+Math::PI*0.0f); pw.y = pos.y; pw.z = pos.z-character->wheelFront*sinf(angle.y+Math::PI*0.0f); a1 = atanf(m_terrain->GetHeightToFloor(pw)/character->wheelFront); pw.x = pos.x+character->wheelBack*cosf(angle.y+Math::PI*1.0f); pw.y = pos.y; pw.z = pos.z-character->wheelBack*sinf(angle.y+Math::PI*1.0f); a2 = atanf(m_terrain->GetHeightToFloor(pw)/character->wheelBack); angle.z = (a2-a1)/2.0f; pw.x = pos.x+character->wheelLeft*cosf(angle.y+Math::PI*0.5f)*cosf(angle.z); pw.y = pos.y; pw.z = pos.z-character->wheelLeft*sinf(angle.y+Math::PI*0.5f)*cosf(angle.z); a1 = atanf(m_terrain->GetHeightToFloor(pw)/character->wheelLeft); pw.x = pos.x+character->wheelRight*cosf(angle.y+Math::PI*1.5f)*cosf(angle.z); pw.y = pos.y; pw.z = pos.z-character->wheelRight*sinf(angle.y+Math::PI*1.5f)*cosf(angle.z); a2 = atanf(m_terrain->GetHeightToFloor(pw)/character->wheelRight); angle.x = (a2-a1)/2.0f; } // Adapts the physics of the object in relation to other objects. // Returns 0 -> mobile object // Returns 1 -> immobile object (because collision) // Returns 2 -> destroyed object int CPhysics::ObjectAdapt(const Math::Vector &pos, const Math::Vector &angle) { CObject* pObj; Gfx::CPyro* pyro; CPhysics* ph; Math::Matrix matRotate; Math::Vector iPos, oPos, iiPos, oAngle, oSpeed; Sound sound; float iRad, oRad, distance, force, volume; int i, j, colType; ObjectType iType, oType; if ( m_object->GetRuin() ) return 0; // is burning or exploding? if ( !m_object->GetClip() ) return 0; // iiPos = sphere center is the old position. // iPos = sphere center has the new position. m_object->GetCrashSphere(0, iiPos, iRad); iPos = iiPos + (pos - m_object->GetPosition(0)); iType = m_object->GetType(); CInstanceManager* iMan = CInstanceManager::GetInstancePointer(); for ( i=0 ; i<1000000 ; i++ ) { pObj = static_cast(iMan->SearchInstance(CLASS_OBJECT, i)); if ( pObj == 0 ) break; if ( pObj == m_object ) continue; // yourself? if ( pObj->GetTruck() != 0 ) continue; // object transported? if ( !pObj->GetEnable() ) continue; // inactive? if ( pObj->GetRuin() ) continue; // is burning or exploding? if ( pObj->GetDead() ) continue; // dead man? oType = pObj->GetType(); if ( oType == OBJECT_NULL ) continue; if ( oType == OBJECT_TOTO ) continue; //? if ( iType == OBJECT_BEE && oType == OBJECT_BEE ) continue; if ( iType == OBJECT_WORM && oType != OBJECT_WORM ) continue; if ( iType != OBJECT_WORM && oType == OBJECT_WORM ) continue; if ( iType == OBJECT_MOTHER && oType == OBJECT_ANT ) continue; if ( iType == OBJECT_ANT && oType == OBJECT_MOTHER ) continue; if ( iType == OBJECT_MOTHER && oType == OBJECT_SPIDER ) continue; if ( iType == OBJECT_SPIDER && oType == OBJECT_MOTHER ) continue; if ( iType == OBJECT_MOTHER && oType == OBJECT_EGG ) continue; if ( iType == OBJECT_EGG && oType == OBJECT_MOTHER ) continue; pObj->GetJotlerSphere(oPos, oRad); if ( oRad > 0.0f ) { JostleObject(pObj, iPos, iRad, oPos, oRad); } if ( iType == OBJECT_MOTHER || iType == OBJECT_ANT || iType == OBJECT_SPIDER || iType == OBJECT_WORM || iType == OBJECT_BEE ) // insect? { if ( oType == OBJECT_STONE || oType == OBJECT_URANIUM || oType == OBJECT_METAL || oType == OBJECT_POWER || oType == OBJECT_ATOMIC || oType == OBJECT_BULLET || oType == OBJECT_BBOX || oType == OBJECT_KEYa || oType == OBJECT_KEYb || oType == OBJECT_KEYc || oType == OBJECT_KEYd || oType == OBJECT_TNT || (oType >= OBJECT_PLANT0 && oType <= OBJECT_PLANT19 ) || (oType >= OBJECT_MUSHROOM1 && oType <= OBJECT_MUSHROOM2) ) continue; } if ( oType == OBJECT_WAYPOINT && pObj->GetEnable() && !m_object->GetResetBusy() && m_object->GetTrainer() ) // driving vehicle? { oPos = pObj->GetPosition(0); distance = Math::DistanceProjected(oPos, iPos); if ( distance < 4.0f ) { m_sound->Play(SOUND_WAYPOINT, m_object->GetPosition(0)); pyro = new Gfx::CPyro(); pyro->Create(Gfx::PT_WPCHECK, pObj); } } if ( oType == OBJECT_TARGET2 ) { oPos = pObj->GetPosition(0); distance = Math::Distance(oPos, iPos); if ( distance < 10.0f*1.5f ) { m_sound->Play(SOUND_WAYPOINT, m_object->GetPosition(0)); pyro = new Gfx::CPyro(); pyro->Create(Gfx::PT_WPCHECK, pObj); } } j = 0; while ( pObj->GetCrashSphere(j++, oPos, oRad) ) { if ( iType == OBJECT_MOTHER && oRad <= 1.2f ) continue; if ( iType == OBJECT_ANT && oRad <= 1.2f ) continue; if ( iType == OBJECT_SPIDER && oRad <= 1.2f ) continue; if ( iType == OBJECT_BEE && oRad <= 1.2f ) continue; if ( iType == OBJECT_WORM && oRad <= 1.2f ) continue; distance = Math::Distance(oPos, iPos); if ( distance < iRad+oRad ) // collision? { distance = Math::Distance(oPos, iiPos); if ( distance >= iRad+oRad ) // view (*) { m_bCollision = true; m_bObstacle = true; sound = pObj->GetCrashSphereSound(j-1); if ( sound != SOUND_CLICK ) { force = fabs(m_linMotion.realSpeed.x); force *= pObj->GetCrashSphereHardness(j-1)*2.0f; if ( ExploOther(iType, pObj, oType, force) ) continue; colType = ExploHimself(iType, oType, force); if ( colType == 2 ) return 2; // destroyed? if ( colType == 0 ) continue; // ignores? } force = m_linMotion.realSpeed.Length(); force *= pObj->GetCrashSphereHardness(j-1); volume = fabs(force*0.05f); if ( volume > 1.0f ) volume = 1.0f; if ( sound != SOUND_CLICK ) { m_sound->Play(sound, m_object->GetPosition(0), volume); } if ( iType == OBJECT_HUMAN && volume > 0.5f ) { m_sound->Play(SOUND_AIE, m_object->GetPosition(0), volume); } if ( m_repeatCollision > 0 ) { force *= 0.5f*m_repeatCollision; if ( force > 20.0f ) force = 20.0f; } m_repeatCollision += 2; if ( m_repeatCollision > 10 ) { m_repeatCollision = 10; } m_linMotion.currentSpeed = Normalize(iPos-oPos)*force; Math::LoadRotationXZYMatrix(matRotate, -angle); m_linMotion.currentSpeed = Transform(matRotate, m_linMotion.currentSpeed); if ( m_type == TYPE_ROLLING ) { m_linMotion.currentSpeed.y = 0.0f; } ph = pObj->GetPhysics(); if ( ph != 0 ) { oAngle = pObj->GetAngle(0); oSpeed = Normalize(oPos-iPos)*force; Math::LoadRotationXZYMatrix(matRotate, -oAngle); oSpeed = Transform(matRotate, oSpeed); if ( ph->GetType() == TYPE_ROLLING ) { oSpeed.y = 0.0f; } ph->SetLinMotion(MO_CURSPEED, oSpeed); } return 1; } } } } if ( m_repeatCollision > 0 ) { m_repeatCollision --; } return 0; } // (*) Collision has the initial position (iiPos) and the new position (iPos), // the obstacle is not known. We can therefore pass through. // This is necessary when barriers found "in" a vehicle, not to block it definitely! // Shakes an object. bool CPhysics::JostleObject(CObject* pObj, Math::Vector iPos, float iRad, Math::Vector oPos, float oRad) { Math::Vector speed; float distance, force, d, f; distance = Math::Distance(oPos, iPos); if ( distance >= iRad+oRad ) return false; d = (iRad+oRad)/2.0f; f = (distance-d)/d; // 0 = off, 1 = near if ( f < 0.0f ) f = 0.0f; if ( f > 1.0f ) f = 1.0f; speed = m_linMotion.realSpeed; speed.y = 0.0f; force = speed.Length()*f*0.05f; if ( force > 1.0f ) force = 1.0f; if ( m_soundTimeJostle >= 0.20f ) { m_soundTimeJostle = 0.0f; m_sound->Play(SOUND_JOSTLE, iPos, force); } return pObj->JostleObject(force); } // Shakes forcing an object. bool CPhysics::JostleObject(CObject* pObj, float force) { Math::Vector oPos; float oRad; pObj->GetJotlerSphere(oPos, oRad); if ( oRad <= 0.0f ) return false; if ( m_soundTimeJostle >= 0.20f ) { m_soundTimeJostle = 0.0f; m_sound->Play(SOUND_JOSTLE, pObj->GetPosition(0), force); } return pObj->JostleObject(force); } // Effects of the explosion on the object buffers. // Returns true if we ignore this obstacle. bool CPhysics::ExploOther(ObjectType iType, CObject *pObj, ObjectType oType, float force) { Gfx::CPyro* pyro; if ( !pObj->GetEnable() ) return true; JostleObject(pObj, 1.0f); // shakes the object if ( force > 50.0f && (oType == OBJECT_FRET || oType == OBJECT_METAL ) ) { pyro = new Gfx::CPyro(); pyro->Create(Gfx::PT_EXPLOT, pObj); // total destruction } if ( force > 50.0f && (oType == OBJECT_POWER || oType == OBJECT_ATOMIC ) ) { pyro = new Gfx::CPyro(); pyro->Create(Gfx::PT_FRAGT, pObj); // total destruction } if ( force > 25.0f && (oType == OBJECT_STONE || oType == OBJECT_URANIUM ) ) { pyro = new Gfx::CPyro(); pyro->Create(Gfx::PT_FRAGT, pObj); // total destruction } if ( force > 25.0f && (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 ) ) // building? { pObj->ExploObject(EXPLO_BOUM, force/400.0f); } if ( force > 25.0f && (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 || oType == OBJECT_APOLLO2 ) ) // vehicle? { pObj->ExploObject(EXPLO_BOUM, force/200.0f); } if ( force > 10.0f && (oType == OBJECT_MOBILEtg || oType == OBJECT_TNT ) ) { pyro = new Gfx::CPyro(); pyro->Create(Gfx::PT_FRAGT, pObj); // total destruction } if ( force > 0.0f && oType == OBJECT_BOMB ) { pyro = new Gfx::CPyro(); pyro->Create(Gfx::PT_FRAGT, pObj); // total destruction } return false; } // Effects of the explosion on the object itself. // Returns 0 -> mobile object // Returns 1 -> immobile object // Returns 2 -> object destroyed int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force) { Gfx::PyroType type; Gfx::CPyro* pyro; if ( force > 10.0f && (oType == OBJECT_TNT || oType == OBJECT_MOBILEtg ) ) { if ( iType == OBJECT_HUMAN ) type = Gfx::PT_DEADG; else type = Gfx::PT_EXPLOT; pyro = new Gfx::CPyro(); pyro->Create(type, m_object); // total destruction return 2; } if ( force > 0.0f && oType == OBJECT_BOMB ) { if ( iType == OBJECT_HUMAN ) { type = Gfx::PT_DEADG; } else if ( iType == OBJECT_ANT || iType == OBJECT_SPIDER || iType == OBJECT_BEE ) { type = Gfx::PT_EXPLOO; } else { type = Gfx::PT_EXPLOT; } pyro = new Gfx::CPyro(); pyro->Create(type, m_object); // total destruction return 2; } if ( force > 25.0f && (iType == OBJECT_HUMAN || iType == OBJECT_MOBILEwa || iType == OBJECT_MOBILEta || iType == OBJECT_MOBILEfa || iType == OBJECT_MOBILEia || iType == OBJECT_MOBILEwc || iType == OBJECT_MOBILEtc || iType == OBJECT_MOBILEfc || iType == OBJECT_MOBILEic || iType == OBJECT_MOBILEwi || iType == OBJECT_MOBILEti || iType == OBJECT_MOBILEfi || iType == OBJECT_MOBILEii || iType == OBJECT_MOBILEws || iType == OBJECT_MOBILEts || iType == OBJECT_MOBILEfs || iType == OBJECT_MOBILEis || iType == OBJECT_MOBILErt || iType == OBJECT_MOBILErc || iType == OBJECT_MOBILErr || iType == OBJECT_MOBILErs || iType == OBJECT_MOBILEsa || iType == OBJECT_MOBILEwt || iType == OBJECT_MOBILEtt || iType == OBJECT_MOBILEft || iType == OBJECT_MOBILEit || iType == OBJECT_MOBILEdr || iType == OBJECT_APOLLO2 ) ) // vehicle? { 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 ) // building? { force /= 200.0f; } else if ( oType == OBJECT_MOTHER || oType == OBJECT_ANT || oType == OBJECT_SPIDER || oType == OBJECT_BEE || oType == OBJECT_WORM ) // insect? { force /= 400.0f; } else if ( oType == OBJECT_FRET || oType == OBJECT_STONE || oType == OBJECT_METAL ) { force /= 500.0f; } else if ( oType == OBJECT_URANIUM || oType == OBJECT_POWER || oType == OBJECT_ATOMIC ) { force /= 100.0f; } else { force /= 200.0f; } if ( m_object->ExploObject(EXPLO_BOUM, force) ) return 2; } return 1; } // Makes the particles evolve. void CPhysics::FrameParticle(float aTime, float rTime) { Math::Vector pos; CObject* power; float energy/*, intensity*/; int effectLight; //bool bFlash; m_restBreakParticle -= rTime; if ( aTime-m_lastPowerParticle < m_engine->ParticleAdapt(0.05f) ) return; m_lastPowerParticle = aTime; //bFlash = false; energy = 0.0f; power = m_object->GetPower(); if ( power != 0 ) { energy = power->GetEnergy(); } if ( energy != m_lastEnergy ) // change the energy level? { if ( energy > m_lastEnergy ) // recharge? { PowerParticle(1.0f, false); //bFlash = true; } if ( energy == 0.0f || m_lastEnergy == 0.0f ) { m_restBreakParticle = 2.5f; // particles for 2.5s } m_lastEnergy = energy; } if ( m_restBreakParticle > 0.0f ) { PowerParticle(m_restBreakParticle/2.5f, (energy == 0)); //bFlash = true; } effectLight = m_object->GetEffectLight(); if ( effectLight != -1 ) { /* * TODO: this is supposed to flash lights of robot without power, * but doesn't work correctly (e.g. beginning of scene201). * Commenting out for the time being. */ /*if ( bFlash ) { intensity = 0.0f; if ( Math::Rand() < 0.5f ) intensity = 1.0f; m_lightMan->SetLightIntensity(effectLight, intensity); m_lightMan->SetLightIntensitySpeed(effectLight, 10000.0f); } else {*/ m_lightMan->SetLightIntensity(effectLight, 0.0f); /*}*/ } } // Generates some particles after a recharge. void CPhysics::PowerParticle(float factor, bool bBreak) { Character* character; CObject* fret; Math::Matrix* mat; Math::Vector pos, ppos, eye, speed; Math::Point dim; bool bCarryPower; bCarryPower = false; fret = m_object->GetFret(); if ( fret != 0 && fret->GetType() == OBJECT_POWER && m_object->GetAngleZ(1) == ARM_STOCK_ANGLE1 ) { bCarryPower = true; // carries a battery } mat = m_object->GetWorldMatrix(0); character = m_object->GetCharacter(); pos = character->posPower; pos.x -= 0.3f; pos.y += 1.0f; // battery center position pos = Transform(*mat, pos); speed.x = (Math::Rand()-0.5f)*12.0f; speed.y = (Math::Rand()-0.5f)*12.0f; speed.z = (Math::Rand()-0.5f)*12.0f; ppos.x = pos.x; ppos.y = pos.y+(Math::Rand()-0.5f)*2.0f; ppos.z = pos.z; dim.x = 1.0f*factor; dim.y = 1.0f*factor; m_particle->CreateParticle(ppos, speed, dim, Gfx::PARTIBLITZ, 0.5f, 0.0f, 0.0f); if ( bCarryPower ) // carry a battery? { pos = Math::Vector(3.0f, 5.6f, 0.0f); // position of battery holder pos = Transform(*mat, pos); speed.x = (Math::Rand()-0.5f)*12.0f; speed.y = (Math::Rand()-0.5f)*12.0f; speed.z = (Math::Rand()-0.5f)*12.0f; ppos.x = pos.x; ppos.y = pos.y; ppos.z = pos.z+(Math::Rand()-0.5f)*2.0f; dim.x = 1.0f*factor; dim.y = 1.0f*factor; m_particle->CreateParticle(ppos, speed, dim, Gfx::PARTIBLITZ, 0.5f, 0.0f, 0.0f); } } // Generates some particles after a fall. // crash: 0=super soft, 1=big crash void CPhysics::CrashParticle(float crash) { Math::Vector pos, ppos, speed; Math::Point dim; float len; int i, max; if ( crash < 0.2f ) return; pos = m_object->GetPosition(0); m_camera->StartEffect(Gfx::CAM_EFFECT_CRASH, pos, crash); //? max = (int)(crash*50.0f); max = static_cast(crash*10.0f*m_engine->GetParticleDensity()); for ( i=0 ; iCreateParticle(ppos, speed, dim, Gfx::PARTICRASH, 2.0f); } } // Generates some exhaust gas particle. void CPhysics::MotorParticle(float aTime, float rTime) { Math::Matrix* mat; Math::Vector pos, speed; Math::Point dim; ObjectType type; Math::Point c, p; float h, a, delay, level; int r, i, nb; if ( m_object->GetToy() ) return; type = m_object->GetType(); if ( type == OBJECT_MOBILEia || type == OBJECT_MOBILEic || type == OBJECT_MOBILEii || type == OBJECT_MOBILEis || // legs? type == OBJECT_MOBILEdr || type == OBJECT_MOTHER || type == OBJECT_ANT || type == OBJECT_SPIDER || type == OBJECT_BEE || type == OBJECT_WORM || type == OBJECT_APOLLO2 ) return; if ( type == OBJECT_HUMAN ) delay = 3.0f; else delay = 8.0f; if ( m_bSwim && m_timeUnderWater < delay ) // bubbles when entering water? { if ( aTime-m_lastUnderParticle >= m_engine->ParticleAdapt(0.05f) ) { m_lastUnderParticle = aTime; nb = static_cast(20.0f-(20.0f/delay)*m_timeUnderWater); for ( i=0 ; iGetPosition(0); pos.x += (Math::Rand()-0.5f)*4.0f; pos.y += (Math::Rand()-0.5f)*4.0f; pos.z += (Math::Rand()-0.5f)*4.0f; speed.y = (Math::Rand()-0.5f)*8.0f+8.0f; speed.x = (Math::Rand()-0.5f)*0.2f; speed.z = (Math::Rand()-0.5f)*0.2f; dim.x = 0.06f+Math::Rand()*0.10f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIBUBBLE, 3.0f, 0.0f, 0.0f); } } } level = m_water->GetLevel(); pos = m_object->GetPosition(0); if ( type == OBJECT_HUMAN ) pos.y -= 2.0f; if ( pos.y < level ) // underwater? { m_absorbWater += rTime*(1.0f/2.0f); // gets wet if ( m_absorbWater > 1.0f ) m_absorbWater = 1.0f; } else // out of water? { m_absorbWater -= rTime*(1.0f/3.0f); // to dry if ( m_absorbWater < 0.0f ) m_absorbWater = 0.0f; } if ( pos.y >= level && m_absorbWater > 0.0f && !m_water->GetLava() ) // drops on leaving the water? { if ( aTime-m_lastUnderParticle >= m_engine->ParticleAdapt(0.05f) ) { m_lastUnderParticle = aTime; nb = static_cast(8.0f*m_absorbWater); for ( i=0 ; iGetPosition(0); if ( type == OBJECT_HUMAN ) pos.y -= Math::Rand()*2.0f; else pos.y += Math::Rand()*2.0f; pos.x += (Math::Rand()-0.5f)*2.0f; pos.z += (Math::Rand()-0.5f)*2.0f; speed.y = -((Math::Rand()-0.5f)*8.0f+8.0f); speed.x = 0.0f; speed.z = 0.0f; dim.x = 0.2f; dim.y = 0.2f; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIWATER, 2.0f, 0.0f, 1.0f); } } } if ( type == OBJECT_HUMAN || // human? type == OBJECT_TECH ) { if ( m_bLand && aTime-m_lastSlideParticle >= m_engine->ParticleAdapt(0.05f) ) { h = Math::Max(fabs(m_linMotion.terrainSpeed.x), fabs(m_linMotion.terrainSpeed.z)); if ( h > m_linMotion.terrainSlide.x+0.5f && m_linMotion.motorSpeed.x == 0.0f ) // slides a stop? { m_lastSlideParticle = aTime; mat = m_object->GetWorldMatrix(0); pos.x = (Math::Rand()-0.5f)*1.0f; pos.y = -m_object->GetCharacter()->height; pos.z = Math::Rand()*0.4f+1.0f; if ( rand()%2 == 0 ) pos.z = -pos.z; pos = Transform(*mat, pos); speed = Math::Vector(0.0f, 1.0f, 0.0f); dim.x = Math::Rand()*(h-5.0f)/2.0f+1.0f; if ( dim.x > 2.5f ) dim.x = 2.5f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTICRASH, 2.0f, 0.0f, 0.2f); } } } if ( type == OBJECT_MOBILEta || type == OBJECT_MOBILEtc || type == OBJECT_MOBILEti || type == OBJECT_MOBILEts ) // caterpillars? { if ( aTime-m_lastSlideParticle >= m_engine->ParticleAdapt(0.05f) ) { h = fabs(m_linMotion.motorSpeed.x-m_linMotion.realSpeed.x); if ( h > 5.0f ) { m_lastSlideParticle = aTime; mat = m_object->GetWorldMatrix(0); pos.x = (Math::Rand()-0.5f)*8.0f; pos.y = 0.0f; pos.z = Math::Rand()*2.0f+3.0f; if ( rand()%2 == 0 ) pos.z = -pos.z; pos = Transform(*mat, pos); speed = Math::Vector(0.0f, 0.0f, 0.0f); dim.x = Math::Rand()*(h-5.0f)/2.0f+1.0f; if ( dim.x > 3.0f ) dim.x = 3.0f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTICRASH, 2.0f, 0.0f, 0.2f); } } } if ( type == OBJECT_MOBILErt || type == OBJECT_MOBILErc || type == OBJECT_MOBILErr || type == OBJECT_MOBILErs ) // large caterpillars? { if ( aTime-m_lastSlideParticle >= m_engine->ParticleAdapt(0.05f) ) { h = fabs(m_linMotion.motorSpeed.x-m_linMotion.realSpeed.x); if ( h > 5.0f ) { m_lastSlideParticle = aTime; mat = m_object->GetWorldMatrix(0); pos.x = (Math::Rand()-0.5f)*9.0f; pos.y = 0.0f; pos.z = Math::Rand()*3.0f+3.0f; if ( rand()%2 == 0 ) pos.z = -pos.z; pos = Transform(*mat, pos); speed = Math::Vector(0.0f, 0.0f, 0.0f); dim.x = Math::Rand()*(h-5.0f)/2.0f+1.0f; if ( dim.x > 3.0f ) dim.x = 3.0f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTICRASH, 2.0f, 0.0f, 0.2f); } } } if ( (type == OBJECT_HUMAN || type == OBJECT_TECH) && !m_bSwim ) { if ( m_bLand ) // on the ground? { if ( m_reactorTemperature > 0.0f ) { m_reactorTemperature -= rTime*(1.0f/10.0f); // cooling if ( m_reactorTemperature < 0.0f ) { m_reactorTemperature = 0.0f; } } if ( m_reactorTemperature == 0.0f || aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.05f) ) return; m_lastMotorParticle = aTime; pos = Math::Vector(-1.6f, -0.5f, 0.0f); mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); speed.x = (Math::Rand()-0.5f)*0.6f; speed.z = (Math::Rand()-0.5f)*0.6f; speed.y = -(0.5f+Math::Rand()*0.3f)*(1.0f-m_reactorTemperature); dim.x = (1.0f+Math::Rand()*0.5f)*(0.2f+m_reactorTemperature*0.8f); dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISMOKE2, 3.0f, 0.0f, 0.1f); } else // in flight? { if ( !m_bMotor || m_reactorRange == 0.0f ) return; if ( m_reactorTemperature < 1.0f ) // not too hot? { m_reactorTemperature += rTime*(1.0f/4.0f); // heating if ( m_reactorTemperature > 1.0f ) { m_reactorTemperature = 1.0f; // but not too much } } if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.02f) ) return; m_lastMotorParticle = aTime; pos = Math::Vector(-1.6f, -1.0f, 0.0f); pos.x += (Math::Rand()-0.5f)*3.0f; pos.y += (Math::Rand()-0.5f)*1.5f; pos.z += (Math::Rand()-0.5f)*3.0f; mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); h = m_floorHeight; if ( h > 10.0f ) // high enough? { speed = Math::Vector(0.0f, -10.0f, 0.0f); // against the bottom } else { speed.y = 10.0f-2.0f*h - Math::Rand()*(10.0f-h); //against the top speed.x = (Math::Rand()-0.5f)*(5.0f-h)*1.0f; // horizontal (xz) speed.z = (Math::Rand()-0.5f)*(5.0f-h)*1.0f; } dim.x = 0.12f; dim.y = 0.12f; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISCRAPS, 2.0f, 10.0f); #if 1 pos = Math::Vector(-1.6f, -0.5f, 0.0f); pos = Transform(*mat, pos); speed.x = (Math::Rand()-0.5f)*1.0f; speed.z = (Math::Rand()-0.5f)*1.0f; speed.y = -(4.0f+Math::Rand()*3.0f); speed.x += m_linMotion.realSpeed.x*0.8f; speed.z -= m_linMotion.realSpeed.x*m_cirMotion.realSpeed.y*0.05f; if ( m_linMotion.realSpeed.y > 0.0f ) { speed.y += m_linMotion.realSpeed.y*0.5f; } else { speed.y += m_linMotion.realSpeed.y*1.2f; } a = m_object->GetAngleY(0); p.x = speed.x; p.y = speed.z; p = Math::RotatePoint(-a, p); speed.x = p.x; speed.z = p.y; dim.x = 0.4f+Math::Rand()*0.2f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIEJECT, 0.3f, 10.0f); #endif } } if ( (type == OBJECT_HUMAN || type == OBJECT_TECH) && m_bSwim ) { m_reactorTemperature = 0.0f; // reactor cold } if ( m_type == TYPE_FLYING && type != OBJECT_HUMAN && type != OBJECT_TECH && !m_bSwim ) { if ( m_bLand ) // on the ground? { if ( m_motorSpeed.x == 0.0f && // glide slope due to ground? m_cirMotion.realSpeed.y == 0.0f ) { h = Math::Max(fabs(m_linMotion.realSpeed.x), fabs(m_linMotion.realSpeed.z)); if ( h < 3.0f ) return; if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.2f) ) return; m_lastMotorParticle = aTime; r = rand()%3; if ( r == 0 ) pos = Math::Vector(-3.0f, 0.0f, -4.0f); if ( r == 1 ) pos = Math::Vector(-3.0f, 0.0f, 4.0f); if ( r == 2 ) pos = Math::Vector( 4.0f, 0.0f, 0.0f); pos.x += (Math::Rand()-0.5f)*2.0f; pos.z += (Math::Rand()-0.5f)*2.0f; mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); speed = Math::Vector(0.0f, 0.0f, 0.0f); dim.x = Math::Rand()*h/5.0f+2.0f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTICRASH, 2.0f); } else // glide with small reactors in skates? { if ( m_linMotion.realSpeed.x == 0.0f && m_cirMotion.realSpeed.y == 0.0f ) return; if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.02f) ) return; m_lastMotorParticle = aTime; r = rand()%3; if ( r == 0 ) pos = Math::Vector(-3.0f, 0.0f, -4.0f); if ( r == 1 ) pos = Math::Vector(-3.0f, 0.0f, 4.0f); if ( r == 2 ) pos = Math::Vector( 4.0f, 0.0f, 0.0f); pos.x += (Math::Rand()-0.5f)*1.0f; pos.z += (Math::Rand()-0.5f)*1.0f; mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); speed = Math::Vector(0.0f, 0.0f, 0.0f); dim.x = 1.0f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIEJECT); } } else // in flight? { if ( !m_bMotor || m_reactorRange == 0.0f ) return; if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.02f) ) return; m_lastMotorParticle = aTime; pos = Math::Vector(0.0f, -1.0f, 0.0f); pos.x += (Math::Rand()-0.5f)*6.0f; pos.y += (Math::Rand()-0.5f)*3.0f; pos.z += (Math::Rand()-0.5f)*6.0f; mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); h = m_floorHeight; if ( h > 10.0f ) // high enough? { speed = Math::Vector(0.0f, -10.0f, 0.0f); // against the bottom } else { speed.y = 10.0f-2.0f*h - Math::Rand()*(10.0f-h); // against the top speed.x = (Math::Rand()-0.5f)*(10.0f-h)*2.0f; // horizontal (xz) speed.z = (Math::Rand()-0.5f)*(10.0f-h)*2.0f; } dim.x = 0.2f; dim.y = 0.2f; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISCRAPS, 2.0f, 10.0f); #if 1 pos = Math::Vector(0.0f, 1.0f, 0.0f); pos = Transform(*mat, pos); speed.x = (Math::Rand()-0.5f)*1.0f; speed.z = (Math::Rand()-0.5f)*1.0f; speed.y = -(6.0f+Math::Rand()*4.5f); speed.x += m_linMotion.realSpeed.x*0.8f; speed.z -= m_linMotion.realSpeed.x*m_cirMotion.realSpeed.y*0.05f; if ( m_linMotion.realSpeed.y > 0.0f ) { speed.y += m_linMotion.realSpeed.y*0.5f; } else { speed.y += m_linMotion.realSpeed.y*1.2f; } a = m_object->GetAngleY(0); p.x = speed.x; p.y = speed.z; p = Math::RotatePoint(-a, p); speed.x = p.x; speed.z = p.y; dim.x = 0.7f+Math::Rand()*0.6f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIEJECT, 0.5f, 10.0f); #endif } } if ( (type == OBJECT_HUMAN || type == OBJECT_TECH) && m_bSwim ) { if ( !m_object->GetDead() ) { h = Math::Mod(aTime, 5.0f); if ( h < 3.5f && ( h < 1.5f || h > 1.6f ) ) return; } if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.06f) ) return; m_lastMotorParticle = aTime; pos = Math::Vector(0.0f, 3.0f, 0.0f); mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); pos.x += (Math::Rand()-0.5f)*1.0f; pos.z += (Math::Rand()-0.5f)*1.0f; speed.y = (Math::Rand()-0.5f)*8.0f+8.0f; speed.x = (Math::Rand()-0.5f)*0.2f; speed.z = (Math::Rand()-0.5f)*0.2f; dim.x = 0.2f; dim.y = 0.2f; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIBUBBLE, 3.0f, 0.0f, 0.0f); if ( aTime-m_lastSoundWater > 1.5f ) { m_lastSoundWater = aTime; m_sound->Play(SOUND_BLUP, m_object->GetPosition(0), 0.5f+Math::Rand()*0.5f); } } if ( type == OBJECT_MOBILEsa && m_bSwim ) { h = Math::Mod(aTime, 3.0f); if ( h < 1.5f && ( h < 0.5f || h > 0.9f ) ) return; if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.06f) ) return; m_lastMotorParticle = aTime; pos = Math::Vector(0.0f, 3.0f, 0.0f); mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); pos.x += (Math::Rand()-0.5f)*1.0f; pos.z += (Math::Rand()-0.5f)*1.0f; speed.y = (Math::Rand()-0.5f)*8.0f+8.0f; speed.x = (Math::Rand()-0.5f)*0.2f; speed.z = (Math::Rand()-0.5f)*0.2f; dim.x = 0.2f; dim.y = 0.2f; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIBUBBLE, 3.0f, 0.0f, 0.0f); if ( aTime-m_lastSoundWater > 1.5f ) { m_lastSoundWater = aTime; m_sound->Play(SOUND_BLUP, m_object->GetPosition(0), 0.5f+Math::Rand()*0.5f); } } if ( m_type == TYPE_ROLLING ) { if ( type == OBJECT_APOLLO2 ) return; // electric motors! if ( type == OBJECT_MOBILErt || type == OBJECT_MOBILErc || type == OBJECT_MOBILErr || type == OBJECT_MOBILErs ) { if ( !m_bMotor ) return; if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.1f) ) return; m_lastMotorParticle = aTime; pos = Math::Vector(-2.5f, 10.3f, -1.3f); pos.x += (Math::Rand()-0.5f)*1.0f; pos.z += (Math::Rand()-0.5f)*1.0f; mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); speed.x = (Math::Rand()-0.5f)*2.0f; speed.z = (Math::Rand()-0.5f)*2.0f; speed.y = 1.5f+Math::Rand()*1.0f; dim.x = Math::Rand()*0.6f+0.4f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIMOTOR, 2.0f); } else { if ( !m_bMotor ) return; if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.05f) ) return; m_lastMotorParticle = aTime; pos = Math::Vector(-3.4f, 1.8f, 0.5f); speed = pos; if ( m_linMotion.currentSpeed.x < 0.0f ) { speed.x += m_linMotion.currentSpeed.x*1.2f; } else if ( m_linMotion.currentSpeed.x > 0.0f ) { speed.x += 0.0f; } else { speed.x -= 3.0f; } speed.y -= 0.5f+Math::Rand()*2.0f; speed.z += (Math::Rand()-0.5f)*3.0f; mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); speed = Transform(*mat, speed)-pos; dim.x = Math::Rand()*0.4f+0.3f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIMOTOR, 2.0f); } } } // Generates some particles after falling into the water. void CPhysics::WaterParticle(float aTime, Math::Vector pos, ObjectType type, float floor, float advance, float turn) { Math::Vector ppos, speed; Math::Point dim; float delay, level, min, max, force, volume, diam; int i, nb; level = m_water->GetLevel(); if ( floor >= level ) return; if ( type == OBJECT_HUMAN || type == OBJECT_TECH ) { min = 3.0f; max = 3.0f; } else { min = 0.0f; max = 9.0f; } if ( pos.y+max < level || pos.y-min > level ) return; // Management of the particle "splash". if ( m_linMotion.realSpeed.y < -10.0f && aTime-m_lastPloufParticle >= 1.0f ) { m_lastPloufParticle = aTime; force = -m_linMotion.realSpeed.y/20.0f; // power according to speed drops if ( type == OBJECT_HUMAN || type == OBJECT_TECH ) { diam = 2.5f; } else { diam = 5.0f; force *= 1.3f; // a robot is heavier } pos = m_object->GetPosition(0); pos.y = m_water->GetLevel()-1.0f; dim.x = 2.0f*force; // height dim.y = diam; // diameter m_particle->CreateParticle(pos, Math::Vector(0.0f, 0.0f, 0.0f), dim, Gfx::PARTIPLOUF0, 1.4f, 0.0f, 0.0f); force = (0.5f+force*0.5f); nb = static_cast(force*50.0f*m_engine->GetParticleDensity()); for ( i=0 ; iCreateParticle(ppos, speed, dim, Gfx::PARTIDROP, 2.0f, 20.0f, 0.2f); } volume = fabs(m_linMotion.realSpeed.y*0.02f); if ( volume > 1.0f ) volume = 1.0f; m_sound->Play(SOUND_PLOUF, pos, volume); } // Management particles "cop". if ( m_water->GetLava() ) return; if ( advance == 0.0f && turn == 0.0f ) { turn = 10.0f; delay = 0.50f; } else if ( advance == 0.0f ) { delay = 0.24f; } else { delay = 0.06f; } m_engine->ParticleAdapt(delay); if ( aTime-m_lastWaterParticle < delay ) return; m_lastWaterParticle = aTime; force = (advance+turn)*0.16f; if ( force < 0.001f ) return; pos = m_object->GetPosition(0); pos.y = level+0.1f; if ( advance == 0 ) { pos.x += (Math::Rand()-0.5f)*10.0f; pos.z += (Math::Rand()-0.5f)*10.0f; } else { pos.x += (Math::Rand()-0.5f)*4.0f; pos.z += (Math::Rand()-0.5f)*4.0f; } speed.y = 0.0f; speed.x = 0.0f; speed.z = 0.0f; dim.x = Math::Min(Math::Rand()*force+force+1.0f, 10.0f); dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIFLIC, 3.0f, 0.0f, 0.0f); } // Creates the trace under the robot. void CPhysics::WheelParticle(int color, float width) { Math::Matrix* mat; Math::Vector goal1, goal2, wheel1, wheel2; Gfx::ParticleType parti; float dist1, dist2, step; mat = m_object->GetWorldMatrix(0); // Draw a trace on the ground. if ( color >= 0 && color <= 17 ) { parti = static_cast(Gfx::PARTITRACE0+color); step = 2.0f; if ( color >= 16 ) step = 4.0f; // arrow? step /= m_engine->GetTracePrecision(); goal1.x = step/2.0f; goal1.y = 0.0f; goal1.z = -width/2.0f; goal1 = Transform(*mat, goal1); goal2.x = step/2.0f; goal2.y = 0.0f; goal2.z = width/2.0f; goal2 = Transform(*mat, goal2); if ( !m_bWheelParticleBrake ) { m_wheelParticlePos[0] = goal1; m_wheelParticlePos[1] = goal2; } while ( true ) { dist1 = Math::Distance(m_wheelParticlePos[0], goal1); if ( dist1 < step ) break; dist2 = Math::Distance(m_wheelParticlePos[1], goal2); wheel1 = Math::SegmentPoint(m_wheelParticlePos[0], goal1, step); wheel2 = Math::SegmentPoint(m_wheelParticlePos[1], goal2, step*dist2/dist1); if ( m_linMotion.realSpeed.x >= 0.0f ) { m_particle->CreateWheelTrace(m_wheelParticlePos[0], m_wheelParticlePos[1], wheel1, wheel2, parti); } else { m_particle->CreateWheelTrace(m_wheelParticlePos[1], m_wheelParticlePos[0], wheel2, wheel1, parti); } m_wheelParticlePos[0] = wheel1; m_wheelParticlePos[1] = wheel2; } m_bWheelParticleBrake = true; } else { m_bWheelParticleBrake = false; } } // Creates the interface. void CPhysics::CreateInterface(bool bSelect) { if ( m_brain != 0 ) { m_brain->CreateInterface(bSelect); } } // Returns an error related to the general state. Error CPhysics::GetError() { ObjectType type; CObject* power; type = m_object->GetType(); if ( type == OBJECT_HUMAN || type == OBJECT_TECH || type == OBJECT_MOTHER || type == OBJECT_ANT || type == OBJECT_SPIDER || type == OBJECT_BEE || type == OBJECT_WORM || type == OBJECT_APOLLO2 || type == OBJECT_MOBILEdr ) return ERR_OK; if ( m_brain != 0 && m_brain->GetActiveVirus() ) { return ERR_VEH_VIRUS; } power = m_object->GetPower(); // searches for the object battery used if ( power == 0 ) { return ERR_VEH_POWER; } else { if ( power->GetEnergy() == 0.0f ) return ERR_VEH_ENERGY; } return ERR_OK; } void CPhysics::SetFalling() { if (m_fallingHeight == 0.0f && m_floorHeight >= m_minFallingHeight) m_fallingHeight = m_object->GetPosition(0).y; } float CPhysics::GetFallingHeight() { return m_fallingHeight; } void CPhysics::SetMinFallingHeight(float value) { if (value < 0.0f) return; m_minFallingHeight = value; } float CPhysics::GetMinFallingHeight() { return m_minFallingHeight; } void CPhysics::SetFallDamageFraction(float value) { if (value < 0.0f) return; m_fallDamageFraction = value; } float CPhysics::GetFallDamageFraction() { return m_fallDamageFraction; }