colobot/src/physics/physics.cpp

3895 lines
123 KiB
C++
Raw Normal View History

/*
* 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 "graphics/engine/camera.h"
#include "graphics/engine/engine.h"
2012-09-10 21:29:38 +00:00
#include "graphics/engine/lightman.h"
#include "graphics/engine/pyro_manager.h"
2012-09-10 21:29:38 +00:00
#include "graphics/engine/terrain.h"
#include "graphics/engine/water.h"
#include "math/geometry.h"
#include "object/brain.h"
#include "object/object_manager.h"
#include "object/robotmain.h"
#include "object/motion/motion.h"
#include "object/motion/motionvehicle.h"
#include "object/motion/motionhuman.h"
#include "object/task/task.h"
2014-11-10 13:16:32 +00:00
#include "object/level/parserline.h"
#include "object/level/parserparam.h"
#include "object/old_object.h"
2015-07-10 20:13:39 +00:00
#include "object/interface/carrier_object.h"
2015-07-10 20:11:22 +00:00
#include "object/interface/jostleable_object.h"
2015-07-10 21:47:59 +00:00
#include "object/interface/powered_object.h"
2015-07-10 17:03:27 +00:00
#include "object/interface/transportable_object.h"
const float LANDING_SPEED = 3.0f;
const float LANDING_ACCEL = 5.0f;
const float LANDING_ACCELh = 1.5f;
// Object's constructor.
CPhysics::CPhysics(COldObject* 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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
}
// 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;
}
2012-09-10 21:29:38 +00:00
PhysicsType CPhysics::GetType()
{
return m_type;
}
// Saves all parameters of the object.
2014-11-10 13:16:32 +00:00
bool CPhysics::Write(CLevelParserLine* line)
{
line->AddParam("motor", CLevelParserParamUPtr{new CLevelParserParam(m_motorSpeed)});
if ( m_type == TYPE_FLYING )
{
line->AddParam("reactorRange", CLevelParserParamUPtr{new CLevelParserParam(GetReactorRange())});
line->AddParam("land", CLevelParserParamUPtr{new CLevelParserParam(GetLand())});
}
return true;
}
// Restores all parameters of the object.
2014-11-10 16:15:34 +00:00
bool CPhysics::Read(CLevelParserLine* line)
{
2014-11-10 16:15:34 +00:00
m_motorSpeed = line->GetParam("motor")->AsPoint();
if ( m_type == TYPE_FLYING )
{
2014-11-10 16:15:34 +00:00
SetReactorRange(line->GetParam("reactorRange")->AsFloat());
SetLand(line->GetParam("land")->AsBool());
}
return true;
}
// Management of the force of gravity.
void CPhysics::SetGravity(float value)
{
m_gravity = value;
}
2012-09-10 21:29:38 +00:00
float CPhysics::GetGravity()
{
return m_gravity;
}
// Returns the height above the ground.
2012-09-10 21:29:38 +00:00
float CPhysics::GetFloorHeight()
{
return m_floorHeight;
}
// Managing the state of the engine.
void CPhysics::SetMotor(bool bState)
{
int light;
m_bMotor = bState;
2012-09-10 21:29:38 +00:00
light = m_object->GetShadowLight();
if ( light != -1 )
{
2012-09-10 21:29:38 +00:00
m_lightMan->SetLightIntensity(light, m_bMotor?1.0f:0.0f);
m_lightMan->SetLightIntensitySpeed(light, 3.0f);
}
}
2012-09-10 21:29:38 +00:00
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
}
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
bool CPhysics::GetSwim()
{
return m_bSwim;
}
// Indicates whether a collision occurred.
void CPhysics::SetCollision(bool bCollision)
{
m_bCollision = bCollision;
}
2012-09-10 21:29:38 +00:00
bool CPhysics::GetCollision()
{
return m_bCollision;
}
// Indicates whether the influence of soil is activated or not.
void CPhysics::SetFreeze(bool bFreeze)
{
m_bFreeze = bFreeze;
}
2012-09-10 21:29:38 +00:00
bool CPhysics::GetFreeze()
{
return m_bFreeze;
}
// Returns the range of the reactor.
void CPhysics::SetReactorRange(float range)
{
m_reactorRange = range;
}
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
Math::Vector CPhysics::GetMotorSpeed()
{
return m_motorSpeed;
}
2012-09-10 21:29:38 +00:00
float CPhysics::GetMotorSpeedX()
{
return m_motorSpeed.x;
}
2012-09-10 21:29:38 +00:00
float CPhysics::GetMotorSpeedY()
{
return m_motorSpeed.y;
}
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
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
2012-09-10 21:29:38 +00:00
float CPhysics::GetLinStopLength(PhysicsMode sMode, PhysicsMode aMode)
{
float speed, accel;
2012-09-10 21:29:38 +00:00
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.
2012-09-10 21:29:38 +00:00
float CPhysics::GetCirStopLength()
{
2012-06-26 21:01:17 +00:00
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.
2012-09-10 21:29:38 +00:00
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.
2012-09-10 21:29:38 +00:00
float CPhysics::GetLinTimeLength(float dist, float dir)
{
float accel, decel, dps;
if ( dir > 0.0f )
{
2012-09-10 21:29:38 +00:00
accel = GetLinStopLength(MO_ADVSPEED, MO_ADVACCEL);
decel = GetLinStopLength(MO_ADVSPEED, MO_STOACCEL);
}
else
{
2012-09-10 21:29:38 +00:00
accel = GetLinStopLength(MO_RECSPEED, MO_RECACCEL);
decel = GetLinStopLength(MO_RECSPEED, MO_STOACCEL);
}
2012-09-10 21:29:38 +00:00
dps = GetLinMaxLength(dir);
return (dist+accel+decel)/dps;
}
// Returns the length for a forward travel some distance, taking into account the accelerations / decelerations.
2012-09-10 21:29:38 +00:00
float CPhysics::GetLinLength(float dist)
{
float accDist, desDist;
if ( dist > 0.0f )
{
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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)
{
2012-09-10 21:29:38 +00:00
if ( !m_object->GetEnable() ) return true;
if ( m_brain != 0 )
{
m_brain->EventProcess(event);
}
2012-09-10 21:29:38 +00:00
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;
2015-07-10 21:47:59 +00:00
CObject* power = nullptr;
Math::Vector pos, motorSpeed;
float energy, speed, factor, h;
2012-09-10 21:29:38 +00:00
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;
2013-12-26 19:37:39 +00:00
motorSpeed = m_motorSpeed;
if ( type == OBJECT_MOTHER ||
type == OBJECT_ANT ||
type == OBJECT_SPIDER ||
type == OBJECT_BEE ||
type == OBJECT_WORM ||
type == OBJECT_APOLLO2 ||
2013-04-29 15:26:32 +00:00
type == OBJECT_MOBILEdr ||
type == OBJECT_CONTROLLER)
{
2015-07-10 21:47:59 +00:00
power = nullptr;
}
else if ( type == OBJECT_HUMAN ||
type == OBJECT_TECH )
{
2015-07-10 21:47:59 +00:00
power = nullptr;
2015-07-10 20:13:39 +00:00
if (IsObjectCarryingCargo(m_object)&& // carries something?
!m_bFreeze )
{
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;
2015-07-10 20:13:39 +00:00
if (IsObjectCarryingCargo(m_object)) // 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
{
2015-07-10 21:47:59 +00:00
if (m_object->Implements(ObjectInterfaceType::Powered))
{
2015-07-10 21:47:59 +00:00
power = dynamic_cast<CPoweredObject*>(m_object)->GetPower(); // searches for the object battery uses
if ( power == nullptr || power->GetEnergy() == 0.0f ) // no battery or flat?
{
2015-07-10 21:47:59 +00:00
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);
}
}
}
2012-09-10 21:29:38 +00:00
if ( m_object->GetDead() ) // dead man?
{
motorSpeed.x = 0.0f;
motorSpeed.z = 0.0f;
2012-09-10 21:29:38 +00:00
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();
2012-09-10 21:29:38 +00:00
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 &&
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
if ( m_bLowLevel && m_object->GetSelect() ) // beep cool?
{
m_sound->Play(SOUND_INFO, m_object->GetPosition(), 1.0f, 2.0f);
m_bLowLevel = false;
}
}
m_bObstacle = false;
}
else // in flight?
{
2012-09-10 21:29:38 +00:00
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();
}
}
2012-09-10 21:29:38 +00:00
//? 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();
2012-09-10 21:29:38 +00:00
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(pos);
}
}
if ( m_type == TYPE_ROLLING )
{
if ( motorSpeed.x == 0.0f &&
motorSpeed.z == 0.0f )
{
SetMotor(false);
}
else
{
SetMotor(true);
}
}
2015-07-10 21:47:59 +00:00
if ( power != nullptr ) // battery transported?
{
factor = 1.0f;
if ( type == OBJECT_MOBILEia ||
type == OBJECT_MOBILEis ||
type == OBJECT_MOBILEic ||
type == OBJECT_MOBILEii ) factor = 0.5f;
2012-09-10 21:29:38 +00:00
factor /= power->GetCapacity();
2012-09-10 21:29:38 +00:00
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()) ) return;
2012-09-10 21:29:38 +00:00
type = m_object->GetType();
character = m_object->GetCharacter();
bOnBoard = false;
2012-09-10 21:29:38 +00:00
if ( m_object->GetSelect() &&
m_camera->GetType() == Gfx::CAM_TYPE_ONBOARD )
{
bOnBoard = true;
}
2012-09-10 21:29:38 +00:00
vibLin = m_motion->GetLinVibration();
vibCir = m_motion->GetCirVibration();
incl = m_motion->GetTilt();
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->SetTilt(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->SetTilt(incl);
}
else
{
m_motion->SetLinVibration(Math::Vector(0.0f, 0.0f, 0.0f));
2012-09-10 21:29:38 +00:00
//? m_motion->SetCirVibration(Math::Vector(0.0f, 0.0f, 0.0f));
//? m_motion->SetTilt(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->SetTilt(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->SetTilt(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->SetTilt(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->SetTilt(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;
2012-09-10 21:29:38 +00:00
if ( m_engine->GetPause() ) return true;
m_time += event.rTime;
m_timeUnderWater += event.rTime;
m_soundTimeJostle += event.rTime;
2012-09-10 21:29:38 +00:00
type = m_object->GetType();
2012-09-10 21:29:38 +00:00
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();
iAngle = angle = m_object->GetRotation();
// Accelerate is the descent, brake is the ascent.
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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
2012-09-10 21:29:38 +00:00
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
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
m_terrain->AdjustToStandardBounds(newpos);
if ( m_type == TYPE_FLYING && !m_bLand )
{
2012-09-10 21:29:38 +00:00
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->SetRotation(newangle);
}
if ( newpos.x != pos.x ||
newpos.y != pos.y ||
newpos.z != pos.z )
{
m_object->SetPosition(newpos);
}
2012-09-10 21:29:38 +00:00
MotorParticle(m_time, event.rTime);
SoundMotor(event.rTime);
if ( m_bLand && m_fallingHeight != 0.0f ) // if fell
{
float force = (m_fallingHeight - m_object->GetPosition().y) * m_fallDamageFraction;
m_object->ExplodeObject(ExplosionType::Bang, force);
m_fallingHeight = 0.0f;
}
m_bForceUpdate = false;
return true;
}
// Starts or stops the engine sounds.
void CPhysics::SoundMotor(float rTime)
{
ObjectType type;
m_lastSoundInsect -= rTime;
2012-09-10 21:29:38 +00:00
type = m_object->GetType();
if ( type == OBJECT_MOTHER )
{
if ( m_lastSoundInsect <= 0.0f && m_object->GetActive() )
{
m_sound->Play(SOUND_INSECTm, m_object->GetPosition());
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 )
{
2012-09-10 21:29:38 +00:00
if ( m_object->GetBurn() ||
m_object->GetFixed() )
{
if ( m_lastSoundInsect <= 0.0f )
{
m_sound->Play(SOUND_INSECTa, m_object->GetPosition(), 1.0f, 1.5f+Math::Rand()*0.5f);
m_lastSoundInsect = 0.4f+Math::Rand()*0.6f;
}
}
else if ( m_object->GetActive() )
{
if ( m_lastSoundInsect <= 0.0f )
{
m_sound->Play(SOUND_INSECTa, m_object->GetPosition());
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->GetActive() )
{
if ( m_lastSoundInsect <= 0.0f )
{
m_sound->Play(SOUND_INSECTb, m_object->GetPosition());
if ( m_bMotor ) m_lastSoundInsect = 0.4f+Math::Rand()*2.5f;
else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f;
}
}
2012-09-10 21:29:38 +00:00
else if ( m_object->GetBurn() )
{
if ( m_lastSoundInsect <= 0.0f )
{
m_sound->Play(SOUND_INSECTb, m_object->GetPosition(), 1.0f, 1.5f+Math::Rand()*0.5f);
m_lastSoundInsect = 0.3f+Math::Rand()*0.5f;
}
}
}
else if ( type == OBJECT_WORM )
{
if ( m_object->GetActive() )
{
if ( m_lastSoundInsect <= 0.0f )
{
m_sound->Play(SOUND_INSECTw, m_object->GetPosition());
if ( m_bMotor ) m_lastSoundInsect = 0.4f+Math::Rand()*2.5f;
else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f;
}
}
2012-09-10 21:29:38 +00:00
else if ( m_object->GetBurn() )
{
if ( m_lastSoundInsect <= 0.0f )
{
m_sound->Play(SOUND_INSECTw, m_object->GetPosition(), 1.0f, 1.5f+Math::Rand()*0.5f);
m_lastSoundInsect = 0.2f+Math::Rand()*0.2f;
}
}
}
else if ( type == OBJECT_SPIDER )
{
2012-09-10 21:29:38 +00:00
if ( m_object->GetBurn() ||
m_object->GetFixed() )
{
if ( m_lastSoundInsect <= 0.0f )
{
m_sound->Play(SOUND_INSECTs, m_object->GetPosition(), 1.0f, 1.5f+Math::Rand()*0.5f);
m_lastSoundInsect = 0.4f+Math::Rand()*0.6f;
}
}
else if ( m_object->GetActive() )
{
if ( m_lastSoundInsect <= 0.0f )
{
m_sound->Play(SOUND_INSECTs, m_object->GetPosition());
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->GetActive() )
{
SoundMotorFull(rTime, type); // full diet
}
else
{
2015-07-10 21:47:59 +00:00
float energy = GetObjectEnergy(m_object);
2012-09-10 21:29:38 +00:00
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->GetActive() && !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;
2012-09-10 21:29:38 +00:00
level = m_water->GetLevel();
if ( level == 0.0f ) return; // no water?
2015-07-10 17:03:27 +00:00
if (IsObjectBeingTransported(m_object)) return;
// Management of flames into the lava.
pos = m_object->GetPosition();
2012-09-10 21:29:38 +00:00
if ( m_water->GetLava() &&
pos.y-m_object->GetCharacter()->height <= level )
{
2012-09-10 21:29:38 +00:00
if ( m_lastFlameParticle+m_engine->ParticleAdapt(0.05f) <= aTime )
{
2012-09-10 21:29:38 +00:00
m_lastFlameParticle = aTime;
pos = m_object->GetPosition();
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;
2012-09-10 21:29:38 +00:00
m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIFLAME, 2.0f, 0.0f, 0.2f);
pos = m_object->GetPosition();
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;
2012-09-10 21:29:38 +00:00
m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISMOKE3, 4.0f);
}
}
2012-06-26 21:01:17 +00:00
pos = m_object->GetPosition();
2012-09-10 21:29:38 +00:00
if ( pos.y >= m_water->GetLevel(m_object) ) return; // out of water?
2012-09-10 21:29:38 +00:00
type = m_object->GetType();
if ( type == OBJECT_TOTO ) return;
if ( type == OBJECT_NULL ) return;
if ( !m_object->GetActive() ) return;
2012-09-10 21:29:38 +00:00
if ( m_water->GetLava() ||
(type == OBJECT_HUMAN &&
2012-09-10 21:29:38 +00:00
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->ExplodeObject(ExplosionType::Water, 1.0f); // starts explosion
}
}
// Sounds the engine at full power.
void CPhysics::SoundMotorFull(float rTime, ObjectType type)
{
SoundType 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.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());
}
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;
}
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
if ( m_object->GetToy() ) freq = 1.0f;
if ( m_soundChannel == -1 )
{
m_soundChannel = m_sound->Play(sound, m_object->GetPosition(), 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());
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;
SoundType 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;
}
2012-09-10 21:29:38 +00:00
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.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());
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(), amplitude);
m_sound->Play(SOUND_PSHHH, m_object->GetPosition(), 1.0f);
m_soundTimePshhh = 4.0f+4.0f*Math::Rand();
2012-09-10 21:29:38 +00:00
max = static_cast<int>(10.0f*m_engine->GetParticleDensity());
for ( i=0 ; i<max ; i++ )
{
pos = Math::Vector(-5.0f, 2.0f, 0.0f);
pos.x += Math::Rand()*4.0f;
pos.z += (Math::Rand()-0.5f)*2.0f;
speed = pos;
speed.x -= Math::Rand()*4.0f;
speed.y -= Math::Rand()*3.0f;
speed.z += (Math::Rand()-0.5f)*6.0f;
2012-06-26 21:01:17 +00:00
2012-09-10 21:29:38 +00:00
mat = m_object->GetWorldMatrix(0);
pos = Transform(*mat, pos);
speed = Transform(*mat, speed)-pos;
dim.x = Math::Rand()*1.0f+1.0f;
dim.y = dim.x;
2012-09-10 21:29:38 +00:00
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)
{
SoundType 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.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());
}
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(), 1.0f, freq);
m_camera->StartEffect(Gfx::CAM_EFFECT_PET, m_object->GetPosition(), 1.0f);
for ( i=0 ; i<5 ; i++ )
{
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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
{
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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)
{
2015-07-10 21:47:59 +00:00
float energy = GetObjectEnergy(m_object);
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.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());
}
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;
2012-09-10 21:29:38 +00:00
bool bSlopingTerrain;
2012-09-10 21:29:38 +00:00
type = m_object->GetType();
character = m_object->GetCharacter();
2012-09-10 21:29:38 +00:00
level = m_water->GetLevel(m_object);
SetSwim( pos.y < level );
2012-09-10 21:29:38 +00:00
m_floorLevel = m_terrain->GetFloorLevel(pos); // height above the ground
h = pos.y-m_floorLevel;
h -= character->height;
m_floorHeight = h;
2012-09-10 21:29:38 +00:00
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);
2012-09-10 21:29:38 +00:00
freq = 0.5f+m_terrain->GetHardness(pos)*2.5f;
m_sound->Play(SOUND_BOUM, pos, volume, freq);
m_soundTimeBoum = aTime;
}
//? pos = m_object->GetPosition(); // 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);
2012-09-10 21:29:38 +00:00
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);
2012-09-10 21:29:38 +00:00
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?
{
CMotionVehicle* motionVehicle = dynamic_cast<CMotionVehicle*>(m_motion);
if (motionVehicle != nullptr && motionVehicle->GetTraceDown())
{
WheelParticle(motionVehicle->GetTraceColor(), motionVehicle->GetTraceWidth()*g_unit);
}
else
{
2015-07-14 11:42:47 +00:00
WheelParticle(TraceColor::Default, 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;
2012-09-10 21:29:38 +00:00
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);
2012-09-10 21:29:38 +00:00
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);
2012-09-10 21:29:38 +00:00
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);
2012-09-10 21:29:38 +00:00
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);
2012-09-10 21:29:38 +00:00
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)
{
2012-09-10 21:29:38 +00:00
CPhysics* ph;
Math::Matrix matRotate;
Math::Vector iPos, oAngle, oSpeed;
float distance, force, volume;
int colType;
2012-09-10 21:29:38 +00:00
ObjectType iType, oType;
2012-09-10 21:29:38 +00:00
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.
2015-07-10 21:57:06 +00:00
if (m_object->GetCrashSphereCount() < 1)
return 0;
auto firstCrashSphere = m_object->GetFirstCrashSphere();
Math::Vector iiPos = firstCrashSphere.sphere.pos;
float iRad = firstCrashSphere.sphere.radius;
iPos = iiPos + (pos - m_object->GetPosition());
2012-09-10 21:29:38 +00:00
iType = m_object->GetType();
for (CObject* pObj : CObjectManager::GetInstancePointer()->GetAllObjects())
{
if ( pObj == m_object ) continue; // yourself?
2015-07-10 17:03:27 +00:00
if (IsObjectBeingTransported(pObj)) continue;
2012-09-10 21:29:38 +00:00
if ( !pObj->GetEnable() ) continue; // inactive?
if ( pObj->GetRuin() ) continue; // is burning or exploding?
if ( pObj->GetDead() ) continue; // dead man?
2012-09-10 21:29:38 +00:00
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;
2015-07-10 20:11:22 +00:00
if (pObj->Implements(ObjectInterfaceType::Jostleable))
{
2015-07-10 20:11:22 +00:00
JostleObject(dynamic_cast<CJostleableObject*>(pObj), iPos, iRad);
}
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 ) ||
2014-01-11 22:42:45 +00:00
(oType >= OBJECT_MUSHROOM1 && oType <= OBJECT_MUSHROOM2) ) continue;
}
if ( oType == OBJECT_WAYPOINT &&
2012-09-10 21:29:38 +00:00
pObj->GetEnable() &&
m_object->GetTrainer() ) // driving vehicle?
{
Math::Vector oPos = pObj->GetPosition();
distance = Math::DistanceProjected(oPos, iPos);
if ( distance < 4.0f )
{
m_sound->Play(SOUND_WAYPOINT, m_object->GetPosition());
m_engine->GetPyroManager()->Create(Gfx::PT_WPCHECK, pObj);
}
}
if ( oType == OBJECT_TARGET2 )
{
Math::Vector oPos = pObj->GetPosition();
distance = Math::Distance(oPos, iPos);
if ( distance < 10.0f*1.5f )
{
m_sound->Play(SOUND_WAYPOINT, m_object->GetPosition());
m_engine->GetPyroManager()->Create(Gfx::PT_WPCHECK, pObj);
}
}
for (const auto& crashSphere : pObj->GetAllCrashSpheres())
{
Math::Vector oPos = crashSphere.sphere.pos;
float oRad = crashSphere.sphere.radius;
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;
if (crashSphere.sound != SOUND_CLICK)
{
force = fabs(m_linMotion.realSpeed.x);
force *= crashSphere.hardness*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 *= crashSphere.hardness;
volume = fabs(force*0.05f);
if ( volume > 1.0f ) volume = 1.0f;
if ( crashSphere.sound != SOUND_CLICK )
{
m_sound->Play(crashSphere.sound, m_object->GetPosition(), volume);
}
if ( iType == OBJECT_HUMAN && volume > 0.5f )
{
m_sound->Play(SOUND_AIE, m_object->GetPosition(), 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;
}
2012-09-10 21:29:38 +00:00
ph = pObj->GetPhysics();
if ( ph != 0 )
{
oAngle = pObj->GetRotation();
oSpeed = Normalize(oPos-iPos)*force;
Math::LoadRotationXZYMatrix(matRotate, -oAngle);
oSpeed = Transform(matRotate, oSpeed);
2012-09-10 21:29:38 +00:00
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),
2012-06-26 21:01:17 +00:00
// 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.
2015-07-10 20:11:22 +00:00
bool CPhysics::JostleObject(CJostleableObject* pObj, Math::Vector iPos, float iRad)
{
2015-07-10 20:11:22 +00:00
Math::Sphere jostlingSphere = pObj->GetJostlingSphere();
2015-07-10 20:11:22 +00:00
float distance = Math::Distance(jostlingSphere.pos, iPos);
if ( distance >= iRad+jostlingSphere.radius) return false;
2015-07-10 20:11:22 +00:00
float d = (iRad+jostlingSphere.radius)/2.0f;
float f = (distance-d)/d; // 0 = off, 1 = near
if ( f < 0.0f ) f = 0.0f;
if ( f > 1.0f ) f = 1.0f;
2015-07-10 20:11:22 +00:00
Math::Vector speed = m_linMotion.realSpeed;
speed.y = 0.0f;
2015-07-10 20:11:22 +00:00
float 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)
{
2015-07-10 20:11:22 +00:00
if (! pObj->Implements(ObjectInterfaceType::Jostleable))
return false;
2015-07-10 20:11:22 +00:00
CJostleableObject* jostleableObject = dynamic_cast<CJostleableObject*>(pObj);
if ( m_soundTimeJostle >= 0.20f )
{
m_soundTimeJostle = 0.0f;
m_sound->Play(SOUND_JOSTLE, pObj->GetPosition(), force);
}
2015-07-10 20:11:22 +00:00
return jostleableObject->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)
{
2012-09-10 21:29:38 +00:00
if ( !pObj->GetEnable() ) return true;
JostleObject(pObj, 1.0f); // shakes the object
if ( force > 50.0f &&
(oType == OBJECT_FRET ||
oType == OBJECT_METAL ) )
{
m_engine->GetPyroManager()->Create(Gfx::PT_EXPLOT, pObj); // total destruction
}
if ( force > 50.0f &&
(oType == OBJECT_POWER ||
oType == OBJECT_ATOMIC ) )
{
m_engine->GetPyroManager()->Create(Gfx::PT_FRAGT, pObj); // total destruction
}
if ( force > 25.0f &&
(oType == OBJECT_STONE ||
oType == OBJECT_URANIUM ) )
{
m_engine->GetPyroManager()->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->ExplodeObject(ExplosionType::Bang, 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->ExplodeObject(ExplosionType::Bang, force/200.0f);
}
if ( force > 10.0f &&
(oType == OBJECT_MOBILEtg ||
oType == OBJECT_TNT ) )
{
m_engine->GetPyroManager()->Create(Gfx::PT_FRAGT, pObj); // total destruction
}
if ( force > 0.0f &&
oType == OBJECT_BOMB )
{
m_engine->GetPyroManager()->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)
{
if ( force > 10.0f &&
(oType == OBJECT_TNT ||
oType == OBJECT_MOBILEtg ) )
{
Gfx::PyroType type;
2012-09-10 21:29:38 +00:00
if ( iType == OBJECT_HUMAN ) type = Gfx::PT_DEADG;
else type = Gfx::PT_EXPLOT;
m_engine->GetPyroManager()->Create(type, m_object); // total destruction
return 2;
}
if ( force > 0.0f &&
oType == OBJECT_BOMB )
{
Gfx::PyroType type;
if ( iType == OBJECT_HUMAN )
{
2012-09-10 21:29:38 +00:00
type = Gfx::PT_DEADG;
}
else if ( iType == OBJECT_ANT ||
iType == OBJECT_SPIDER ||
iType == OBJECT_BEE )
{
2012-09-10 21:29:38 +00:00
type = Gfx::PT_EXPLOO;
}
else
{
2012-09-10 21:29:38 +00:00
type = Gfx::PT_EXPLOT;
}
m_engine->GetPyroManager()->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->ExplodeObject(ExplosionType::Bang, force) ) return 2;
}
return 1;
}
// Makes the particles evolve.
2012-09-10 21:29:38 +00:00
void CPhysics::FrameParticle(float aTime, float rTime)
{
Math::Vector pos;
2015-07-10 21:47:59 +00:00
/*float intensity;*/
int effectLight;
//bool bFlash;
2012-09-10 21:29:38 +00:00
m_restBreakParticle -= rTime;
if ( aTime-m_lastPowerParticle < m_engine->ParticleAdapt(0.05f) ) return;
m_lastPowerParticle = aTime;
//bFlash = false;
2015-07-10 21:47:59 +00:00
float energy = GetObjectEnergy(m_object);
if ( energy != m_lastEnergy ) // change the energy level?
{
if ( energy > m_lastEnergy ) // recharge?
{
2012-09-10 21:29:38 +00:00
PowerParticle(1.0f, false);
//bFlash = true;
}
if ( energy == 0.0f || m_lastEnergy == 0.0f )
{
2012-09-10 21:29:38 +00:00
m_restBreakParticle = 2.5f; // particles for 2.5s
}
m_lastEnergy = energy;
}
2012-09-10 21:29:38 +00:00
if ( m_restBreakParticle > 0.0f )
{
2012-09-10 21:29:38 +00:00
PowerParticle(m_restBreakParticle/2.5f, (energy == 0));
//bFlash = true;
}
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
m_lightMan->SetLightIntensity(effectLight, intensity);
m_lightMan->SetLightIntensitySpeed(effectLight, 10000.0f);
}
else
{*/
2012-09-10 21:29:38 +00:00
m_lightMan->SetLightIntensity(effectLight, 0.0f);
/*}*/
}
}
// Generates some particles after a recharge.
2012-09-10 21:29:38 +00:00
void CPhysics::PowerParticle(float factor, bool bBreak)
{
Character* character;
Math::Matrix* mat;
Math::Vector pos, ppos, eye, speed;
Math::Point dim;
bool bCarryPower;
bCarryPower = false;
2015-07-10 20:13:39 +00:00
if (m_object->Implements(ObjectInterfaceType::Carrier))
{
2015-07-10 20:13:39 +00:00
CObject* cargo = dynamic_cast<CCarrierObject*>(m_object)->GetCargo();
if ( cargo != nullptr && cargo->GetType() == OBJECT_POWER &&
m_object->GetPartRotationZ(1) == ARM_STOCK_ANGLE1 )
2015-07-10 20:13:39 +00:00
{
bCarryPower = true; // carries a battery
}
}
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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
2012-09-10 21:29:38 +00:00
void CPhysics::CrashParticle(float crash)
{
Math::Vector pos, ppos, speed;
Math::Point dim;
2012-09-10 21:29:38 +00:00
float len;
int i, max;
if ( crash < 0.2f ) return;
pos = m_object->GetPosition();
2012-09-10 21:29:38 +00:00
m_camera->StartEffect(Gfx::CAM_EFFECT_CRASH, pos, crash);
//? max = (int)(crash*50.0f);
2012-09-10 21:29:38 +00:00
max = static_cast<int>(crash*10.0f*m_engine->GetParticleDensity());
for ( i=0 ; i<max ; i++ )
{
ppos.x = pos.x + (Math::Rand()-0.5f)*15.0f*crash;
ppos.z = pos.z + (Math::Rand()-0.5f)*15.0f*crash;
ppos.y = pos.y + Math::Rand()*4.0f;
len = 1.0f-(Math::Distance(ppos, pos)/(15.0f+5.0f));
if ( len <= 0.0f ) continue;
speed.x = (ppos.x-pos.x)*0.1f;
speed.z = (ppos.z-pos.z)*0.1f;
speed.y = -2.0f;
dim.x = 2.0f+crash*5.0f*len;
dim.y = dim.x;
2012-09-10 21:29:38 +00:00
m_particle->CreateParticle(ppos, speed, dim, Gfx::PARTICRASH, 2.0f);
}
}
// Generates some exhaust gas particle.
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
if ( m_object->GetToy() ) return;
2012-09-10 21:29:38 +00:00
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?
{
2012-09-10 21:29:38 +00:00
if ( aTime-m_lastUnderParticle >= m_engine->ParticleAdapt(0.05f) )
{
2012-09-10 21:29:38 +00:00
m_lastUnderParticle = aTime;
2012-09-10 21:29:38 +00:00
nb = static_cast<int>(20.0f-(20.0f/delay)*m_timeUnderWater);
for ( i=0 ; i<nb ; i++ )
{
pos = m_object->GetPosition();
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;
2012-09-10 21:29:38 +00:00
m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIBUBBLE, 3.0f, 0.0f, 0.0f);
}
}
}
2012-09-10 21:29:38 +00:00
level = m_water->GetLevel();
pos = m_object->GetPosition();
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 &&
2012-09-10 21:29:38 +00:00
!m_water->GetLava() ) // drops on leaving the water?
{
2012-09-10 21:29:38 +00:00
if ( aTime-m_lastUnderParticle >= m_engine->ParticleAdapt(0.05f) )
{
2012-09-10 21:29:38 +00:00
m_lastUnderParticle = aTime;
2012-09-10 21:29:38 +00:00
nb = static_cast<int>(8.0f*m_absorbWater);
for ( i=0 ; i<nb ; i++ )
{
pos = m_object->GetPosition();
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;
2012-09-10 21:29:38 +00:00
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 &&
2012-09-10 21:29:38 +00:00
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?
{
2012-09-10 21:29:38 +00:00
m_lastSlideParticle = aTime;
2012-09-10 21:29:38 +00:00
mat = m_object->GetWorldMatrix(0);
pos.x = (Math::Rand()-0.5f)*1.0f;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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?
{
2012-09-10 21:29:38 +00:00
if ( aTime-m_lastSlideParticle >= m_engine->ParticleAdapt(0.05f) )
{
h = fabs(m_linMotion.motorSpeed.x-m_linMotion.realSpeed.x);
if ( h > 5.0f )
{
2012-09-10 21:29:38 +00:00
m_lastSlideParticle = aTime;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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?
{
2012-09-10 21:29:38 +00:00
if ( aTime-m_lastSlideParticle >= m_engine->ParticleAdapt(0.05f) )
{
h = fabs(m_linMotion.motorSpeed.x-m_linMotion.realSpeed.x);
if ( h > 5.0f )
{
2012-09-10 21:29:38 +00:00
m_lastSlideParticle = aTime;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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 ||
2012-09-10 21:29:38 +00:00
aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.05f) ) return;
m_lastMotorParticle = aTime;
pos = Math::Vector(-1.6f, -0.5f, 0.0f);
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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
}
}
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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->GetRotationY();
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIEJECT);
}
}
else // in flight?
{
if ( !m_bMotor || m_reactorRange == 0.0f ) return;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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->GetRotationY();
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;
2012-09-10 21:29:38 +00:00
m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIEJECT, 0.5f, 10.0f);
#endif
}
}
if ( (type == OBJECT_HUMAN || type == OBJECT_TECH) && m_bSwim )
{
2012-09-10 21:29:38 +00:00
if ( !m_object->GetDead() )
{
h = Math::Mod(aTime, 5.0f);
if ( h < 3.5f && ( h < 1.5f || h > 1.6f ) ) return;
}
2012-09-10 21:29:38 +00:00
if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.06f) ) return;
m_lastMotorParticle = aTime;
pos = Math::Vector(0.0f, 3.0f, 0.0f);
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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.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;
2012-09-10 21:29:38 +00:00
if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.06f) ) return;
m_lastMotorParticle = aTime;
pos = Math::Vector(0.0f, 3.0f, 0.0f);
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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.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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIMOTOR, 2.0f);
}
else
{
if ( !m_bMotor ) return;
2012-09-10 21:29:38 +00:00
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;
2012-06-26 21:01:17 +00:00
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIMOTOR, 2.0f);
}
}
}
// Generates some particles after falling into the water.
2012-09-10 21:29:38 +00:00
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;
2012-09-10 21:29:38 +00:00
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 &&
2012-09-10 21:29:38 +00:00
aTime-m_lastPloufParticle >= 1.0f )
{
2012-09-10 21:29:38 +00:00
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();
2012-09-10 21:29:38 +00:00
pos.y = m_water->GetLevel()-1.0f;
dim.x = 2.0f*force; // height
dim.y = diam; // diameter
2012-09-10 21:29:38 +00:00
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);
2012-09-10 21:29:38 +00:00
nb = static_cast<int>(force*50.0f*m_engine->GetParticleDensity());
for ( i=0 ; i<nb ; i++ )
{
ppos = pos;
ppos.x += (Math::Rand()-0.5f)*4.0f;
ppos.z += (Math::Rand()-0.5f)*4.0f;
ppos.y += 0.6f;
speed.x = (Math::Rand()-0.5f)*12.0f*force;
speed.z = (Math::Rand()-0.5f)*12.0f*force;
speed.y = 6.0f+Math::Rand()*6.0f*force;
dim.x = 0.5f;
dim.y = dim.x;
2012-09-10 21:29:38 +00:00
m_particle->CreateParticle(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".
2012-09-10 21:29:38 +00:00
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;
}
2012-09-10 21:29:38 +00:00
m_engine->ParticleAdapt(delay);
2012-09-10 21:29:38 +00:00
if ( aTime-m_lastWaterParticle < delay ) return;
m_lastWaterParticle = aTime;
force = (advance+turn)*0.16f;
if ( force < 0.001f ) return;
pos = m_object->GetPosition();
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;
2012-09-10 21:29:38 +00:00
m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIFLIC, 3.0f, 0.0f, 0.0f);
}
// Creates the trace under the robot.
2015-07-14 11:42:47 +00:00
void CPhysics::WheelParticle(TraceColor color, float width)
{
Math::Matrix* mat;
Math::Vector goal1, goal2, wheel1, wheel2;
2012-09-10 21:29:38 +00:00
Gfx::ParticleType parti;
float dist1, dist2, step;
2012-09-10 21:29:38 +00:00
mat = m_object->GetWorldMatrix(0);
// Draw a trace on the ground.
2015-07-14 11:42:47 +00:00
if ( color != TraceColor::Default )
{
2015-07-14 11:42:47 +00:00
parti = static_cast<Gfx::ParticleType>(Gfx::PARTITRACE0+static_cast<int>(color));
step = 2.0f;
2015-07-14 11:42:47 +00:00
if ( static_cast<int>(color) >= static_cast<int>(TraceColor::RedArrow) ) step = 4.0f; // arrow?
2012-09-10 21:29:38 +00:00
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);
2012-09-10 21:29:38 +00:00
if ( !m_bWheelParticleBrake )
{
2012-09-10 21:29:38 +00:00
m_wheelParticlePos[0] = goal1;
m_wheelParticlePos[1] = goal2;
}
while ( true )
{
2012-09-10 21:29:38 +00:00
dist1 = Math::Distance(m_wheelParticlePos[0], goal1);
if ( dist1 < step ) break;
2012-09-10 21:29:38 +00:00
dist2 = Math::Distance(m_wheelParticlePos[1], goal2);
2012-09-10 21:29:38 +00:00
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 )
{
2012-09-10 21:29:38 +00:00
m_particle->CreateWheelTrace(m_wheelParticlePos[0], m_wheelParticlePos[1], wheel1, wheel2, parti);
}
else
{
2012-09-10 21:29:38 +00:00
m_particle->CreateWheelTrace(m_wheelParticlePos[1], m_wheelParticlePos[0], wheel2, wheel1, parti);
}
2012-09-10 21:29:38 +00:00
m_wheelParticlePos[0] = wheel1;
m_wheelParticlePos[1] = wheel2;
}
2012-09-10 21:29:38 +00:00
m_bWheelParticleBrake = true;
}
else
{
2012-09-10 21:29:38 +00:00
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.
2012-09-10 21:29:38 +00:00
Error CPhysics::GetError()
{
2015-07-10 21:47:59 +00:00
ObjectType 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;
2012-06-26 21:01:17 +00:00
2012-09-10 21:29:38 +00:00
if ( m_brain != 0 && m_brain->GetActiveVirus() )
{
return ERR_VEH_VIRUS;
}
2015-07-10 21:47:59 +00:00
if (m_object->Implements(ObjectInterfaceType::Powered))
{
2015-07-10 21:47:59 +00:00
CObject* power = dynamic_cast<CPoweredObject*>(m_object)->GetPower(); // searches for the object battery used
if (power == nullptr)
{
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().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;
}