/*
	Rogue Trader.
	Copyright (c) 2007, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################
//
//
// Class Name:   GameObject_Ship
// Purpose:      Class that describes a ship. Contains functions relevant to
//               ship objects.
//
//
//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

#include "GameObject_Ship.h"

//------------------------------------------------------------------------------
// Constant initialisation
//------------------------------------------------------------------------------

const float      GameObject_Ship::EXPLOSION_TIME                        = 0.5f;     // time the ship explosion lasts for in seconds
const float      GameObject_Ship::EXPLOSION_SCALE                       = 6.0f;     // scale of the ship explosion
const float      GameObject_Ship::ENGINE_PARTICLE_INTERVAL              = 0.02f;    // amount of time in seconds between bursts of particles coming from the engine
const float      GameObject_Ship::ENGINE_PARTICLE_TIME1                 = 0.2f;     // engine particle live time 1
const float      GameObject_Ship::ENGINE_PARTICLE_TIME2                 = 0.3f;     // engine particle live time 2
const float      GameObject_Ship::ENGINE_PARTICLE_COLOR1_R              = 0.5f;     // engine particle color: red
const float      GameObject_Ship::ENGINE_PARTICLE_COLOR1_G              = 1.0f;     // engine particle color: green
const float      GameObject_Ship::ENGINE_PARTICLE_COLOR1_B              = 1.0f;     // engine particle color: blue
const float      GameObject_Ship::ENGINE_PARTICLE_COLOR2_R              = 0.2f;     // engine particle color: red
const float      GameObject_Ship::ENGINE_PARTICLE_COLOR2_G              = 0.2f;     // engine particle color: green
const float      GameObject_Ship::ENGINE_PARTICLE_COLOR2_B              = 1.0f;     // engine particle color: blue
const float      GameObject_Ship::ENGINE_PARTICLE_SIZE1                 = 8.0f;     // the size of engine particles
const float      GameObject_Ship::ENGINE_PARTICLE_SIZE2                 = 12.0f;    // the size of engine particles
const float      GameObject_Ship::ENGINE_PARTICLE_DIR_RANDOMNESS        = 0.05f;    // amount of variation from ships velocity direction particles can go
const float      GameObject_Ship::ENGINE_PARTICLE_VEL_RANDOMNESS        = 0.03f;    // amount of variation from ships velocity amount particles can have
const float      GameObject_Ship::ENGINE_PARTICLE_CONST_VEL_RANDOMNESS  = 50.0f;    // amount of random variation in particle velocity to apply, regardless of ships speed
const unsigned   GameObject_Ship::ENGINE_PARTICLE_COUNT                 = 24;		// number of particles to create in an engine particle stream
const float      GameObject_Ship::ENGINE_NOISE_DISTANCE                 = 96000.0f; // distance from which the ships engines can be heard
const float      GameObject_Ship::ENGINE_NOISE_MIN_PITCH                = 0.7f;     // minimum pitch of the ships engines
const float      GameObject_Ship::ENGINE_NOISE_MAX_PITCH                = 1.01f;    // maximum pitch of the ships engines

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::GameObject_Ship()
Purpose:  Ship constructor. Constructs the ship object with parameters given.
Params:   as per commented
Returns:  n/a

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

GameObject_Ship::GameObject_Ship
(
    float       pos_x,                  // initial position: x
    float       pos_y,                  // initial position: y
    float       pos_z,                  // initial position: z
    float       cost,                   // cost of the ship
    float       health,                 // amount of damage the ship can take.
    float       maxSpeed,               // maximum speed of the ship
    float       acceleration,           // amount of acceleration the ship has. higher values mean more resposive handling.
    float       mass,                   // mass of the object
    float       hyperspaceRange,        // distance the ship can travel in light years. each sector is a square light year in size
    unsigned    cargoCapacity,          // the amount of goods units the ship can hold
    unsigned    maxMissiles,            // maximum number of missiles the ship can have
    unsigned    maxEmpBombs,            // maximum number of emp bombs the ship can have
    float       laserStrenght,          // ships's laser strenght
    float       laserCoolingAmount,     // ships's laser cooling amount
    float       laserColorR,            // ships's laser color: red
    float       laserColorG,            // ships's laser color: green
    float       laserColorB,            // ships's laser color: blue
    float       laserStartX,            // Where in ship coordinates (X) the ships laser starts firing from
    float       laserStartY,            // Where in ship coordinates (Y) the ships laser starts firing from
    float       laserStartZ,            // Where in ship coordinates (Z) the ships laser starts firing from
    float       particleSpawnX,         // Where to start spawing particles at: x in ship coordinates
    float       particleSpawnY,         // Where to start spawing particles at: y in ship coordinates
    float       particleSpawnZ,         // Where to start spawing particles at: z in ship coordinates
    float       cameraCockpitX,         // Where in ship coordinates (X) the cockpit view of the camera is located
    float       cameraCockpitY,         // Where in ship coordinates (Y) the cockpit view of the camera is located
    float       cameraCockpitZ,         // Where in ship coordinates (Z) the cockpit view of the camera is located
    Mesh    *   mesh                    // ships's mesh.
)
:
MovingGameObject
(
    pos_x ,
    pos_y ,
    pos_z ,
    mesh
)
,
laser
(
    laserStrenght,
    laserCoolingAmount ,
    laserColorR,
    laserColorG,
    laserColorB
)
{
    // Set the ships attributes:

    this->cost              = cost;
    this->health            = health;
    this->maximumHealth     = health;
    this->maxSpeed          = maxSpeed;
    this->acceleration      = acceleration;
    this->hyperspaceRange   = hyperspaceRange;
    this->cargoCapacity     = cargoCapacity;
    this->maxMissiles       = maxMissiles;
    this->maxEmpBombs       = maxEmpBombs;
    this->mass              = mass;
    this->laserStartX       = laserStartX;
    this->laserStartY       = laserStartY;
    this->laserStartZ       = laserStartZ;
    this->particleSpawnX    = particleSpawnX;
    this->particleSpawnY    = particleSpawnY;
    this->particleSpawnZ    = particleSpawnZ;
    this->cameraCockpitX    = cameraCockpitX;
    this->cameraCockpitY    = cameraCockpitY;
    this->cameraCockpitZ    = cameraCockpitZ;

    // Save the maximum velocity of the ship to zero initially. ship will stay stationary

    this->maxVelocity = 0;

    // Set the ship as not being indestructable:

    this->indestructable = false;

    // Set the time till the ship creates another set of engine particles to 0

    this->timeToEngineParticles = 0;

    // Set the ship as having fuel for a hyperspace jump

    this->hasHyperspaceFuel = true;

    // Set the current missile bay to the left missile bay (true):

    useLeftMissileBay = true;

    // Set the current number of missiles the ship has to zero

    this->numMissiles = 0;

    // Set the current number of emp bombs the ship has to zero

    this->numEmpBombs = 0;

    // Clear the sound ID of the ships engine noise

    shipEngineSoundID = 0;
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::~GameObject_Ship()
Purpose:  Ship destructor. Creates an explosion in the scene the ship is in
Params:   n/a
Returns:  n/a

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

GameObject_Ship::~GameObject_Ship()
{
    //--------------------------------------------------------------------------
    // Get the mesh and scene the object has:
    //--------------------------------------------------------------------------

    GameScene  * scene = (GameScene*) getScene();
    const Mesh * mesh  = getMesh();

    //--------------------------------------------------------------------------
    // Stop all noises created by the ship
    //--------------------------------------------------------------------------

    if ( scene )
    {
        // Cool the ships laser: this stops any playing laser noise

        laser.cool( scene , 0.01f );

        // Stop the ships engine noise:

        scene->deleteSound(shipEngineSoundID);
    }

    //--------------------------------------------------------------------------
    // If the object is not techically dead then do not create explosion: it has
    // been removed from game by some other means other than being killed by player
    //--------------------------------------------------------------------------

    if ( health > 0 ) return;

    //--------------------------------------------------------------------------
    // If either the scene or mesh do not exist then abort
    //--------------------------------------------------------------------------

    if ( scene == 0 || mesh == 0 ) return;

    //--------------------------------------------------------------------------
    // Create the explosion:
    //--------------------------------------------------------------------------

    // Make the explosion at the ships position and with the size of the meshes bounding sphere:

    scene->addObject
    (
        new GameObject_Explosion
        (
            getPosX(),
            getPosY(),
            getPosZ(),
            mesh->getSphereRadius() * EXPLOSION_SCALE,
            EXPLOSION_TIME
        )
    );
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::onSceneEnter()
Purpose:  On scene enter event for the ship. spawns the ships engine noise.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::onSceneEnter()
{
    // Get the ships scene

    GameScene * scene = (GameScene*) getScene();

    // Create the ships engine noise

    if ( scene )
    {
        // Get the ships current velocity:

        float velocity = getVelocityAmount();

        // Get the velocity as a percentage of max velocity

        float p = velocity / this->getMaxSpeed();

        // Make sure percent isn't greater than 100%

        if ( p > 1 ) p = 1;

        // Calculate engine sound freqeuncy from this:

        float soundFreq = p * ENGINE_NOISE_MAX_PITCH + ( 1.0f - p ) * ENGINE_NOISE_MIN_PITCH;

        // Create the engine sound

        shipEngineSoundID = scene->addSound
        (
            SoundManager::getSndShipEngine(),       // sound to play
            getPosX(),                              // position of sound
            getPosY(),                              // position of sound
            getPosZ(),                              // position of sound
            ENGINE_NOISE_DISTANCE,                  // distance sound can be heard from
            soundFreq,                              // frequency of sound
            true
        );
    }
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::onSceneRemove()
Purpose:  On scene remove event for the ship. stops the ships engine and laser noise.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::onSceneRemove()
{
    // Get the ships scene

    GameScene * scene = (GameScene*) getScene();

    // Stop all ship noises

    if ( scene )
    {
        // Cool the ships laser: this stops any playing laser noise

        laser.cool( scene , 0.01f );

        // Stop the ships engine noise:

        scene->deleteSound(shipEngineSoundID);
    }
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::setNumMissiles()
Purpose:  Sets the number of missiles the ship has. does not allow over the maximum
          amount of missiles.
Params:   number of missiles to give the ship
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::setNumMissiles( unsigned numMissiles )
{
    // Make sure the number of missiles is not over the maximum

    if ( numMissiles > this->maxMissiles ) numMissiles = this->maxMissiles;

    // Set the number of missiles:

    this->numMissiles = numMissiles;
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::setNumEmpBombs()
Purpose:  Sets the number of emp bombs the ship has. does not allow over the maximum
          amount of emp bombs.
Params:   number of emp bombs to give the ship
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::setNumEmpBombs( unsigned numEmpBombs )
{
    // Make sure the number of emp bombs is not over the maximum

    if ( numEmpBombs > this->maxEmpBombs ) numEmpBombs = this->maxMissiles;

    // Set the number of emp bombs:

    this->numEmpBombs = numEmpBombs;
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::accelerate()
Purpose:  Increases/decreases ships maximum velocity by given amount. Does not
          allow for reverse velocity however and keeps the ships maximum velocity
          within the limits defined by the maxSpeed of the ship.
Params:   amount to increase / decrease maximum speed by
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::accelerate( float amount )
{
    // Change the maximum velocity by the given amount:

    maxVelocity += amount;

    // If max velocity is negative then make 0:

    if ( maxVelocity < 0 ) maxVelocity = 0;

    // If max velocity is above maximum allowed ship speed then clamp:

    if ( maxVelocity > maxSpeed ) maxVelocity = maxSpeed;
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::onFrame()
Purpose:  On frame event for the ship. Spawns engine particles at regular intervals.
Params:   time the last frame took in seconds
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::onFrame( float frameTime )
{
    // Save the time of the last frame

    lastFrameTime = frameTime;

    //--------------------------------------------------------------------------
    // Update ships engine noise position
    //--------------------------------------------------------------------------

    // Get the scene the ship is a part of and interpret as a game scene:

    GameScene * scene = (GameScene*) getScene();

    // Abort if the scene is null

    if ( scene == 0 ) return;

    // update the position of the ships engine noise in the scene:

    scene->updateSoundPosition
    (
        shipEngineSoundID,
        getPosX(),
        getPosY(),
        getPosZ()
    );

    //--------------------------------------------------------------------------
    // Update ships engine noise frequency
    //--------------------------------------------------------------------------

    // Get the ships current velocity:

    float velocity = getVelocityAmount();

    // Get the velocity as a percentage of max velocity

    float p = velocity / this->getMaxSpeed();

    // Make sure percent isn't greater than 100%

    if ( p > 1 ) p = 1;

    // Calculate engine sound freqeuncy from this:

    float soundFreq = p * ENGINE_NOISE_MAX_PITCH + ( 1.0f - p ) * ENGINE_NOISE_MIN_PITCH;

    // Set the new velocity of the ships engine noise

    scene->updateSoundFrequency( shipEngineSoundID , soundFreq );
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::spawnEngineParticles()
Purpose:  Creates engine particles behind the ship every so often.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::spawnEngineParticles()
{
    //--------------------------------------------------------------------------
    // Get the GameObjecScene the ship belongs to, and assume that in actual
    // fact it is of the derived 'GameScene' type:
    //--------------------------------------------------------------------------

    GameScene * scene = (GameScene*)getScene();

    //--------------------------------------------------------------------------
    // If the scene is null then abort
    //--------------------------------------------------------------------------

    if ( scene == 0 ) return;

    //--------------------------------------------------------------------------
    // If the object is not visible then abort
    //--------------------------------------------------------------------------

    if ( isVisible() == false ) return;

    //--------------------------------------------------------------------------
    // Now see if it is time to spawn another particle set:
    //--------------------------------------------------------------------------

    if ( timeToEngineParticles <= 0 )
    {
        //----------------------------------------------------------------------
        // Decide on engine particle speed
        //----------------------------------------------------------------------

        // Get the speed that the ship is currently moving at

        float moveSpeed1 = mlLenght3d(velocity);

        // Get a random fraction of this move speed to vary it by

        float random = moveSpeed1 * mlRandomFloat() * ENGINE_PARTICLE_VEL_RANDOMNESS;

        // Now vary the first move speed:

        moveSpeed1 -= random;

        // Now make a second move speed, varying it randomnly by constant velocity randomness

        float moveSpeed2 = moveSpeed1 - mlRandomFloat() * ENGINE_PARTICLE_CONST_VEL_RANDOMNESS;

        //----------------------------------------------------------------------
        // Decide on engine particle directions
        //----------------------------------------------------------------------

        // Get two copies of the velocity vector and normalise

        float velocityDir1[3] =
        {
            velocity[0],
            velocity[1],
            velocity[2],
        };

        // Only normalise it if there is a velocity direction, otherwise pick
        // a new random direction and normalise:

        if ( velocityDir1[0] != 0 || velocityDir1[1] != 0 || velocityDir1[2] != 0 )
        {
            // Have a veloctity direction: normalise

            mlNormalise3d(velocityDir1);
        }
        else
        {
            // Don't have a velocity direction: make one up

            velocityDir1[0] = mlRandomFloat() - 0.5f;
            velocityDir1[1] = mlRandomFloat() - 0.5f;
            velocityDir1[2] = mlRandomFloat() - 0.5f;

            // Normalise this direction

            mlNormalise3d(velocityDir1);
        }

        float velocityDir2[3] =
        {
            velocityDir1[0],
            velocityDir1[1],
            velocityDir1[2],
        };

        // Now randomly vary these directions

        velocityDir1[0] += mlRandomFloat() * ENGINE_PARTICLE_DIR_RANDOMNESS * 2 - ENGINE_PARTICLE_DIR_RANDOMNESS;
        velocityDir1[1] += mlRandomFloat() * ENGINE_PARTICLE_DIR_RANDOMNESS * 2 - ENGINE_PARTICLE_DIR_RANDOMNESS;
        velocityDir1[2] += mlRandomFloat() * ENGINE_PARTICLE_DIR_RANDOMNESS * 2 - ENGINE_PARTICLE_DIR_RANDOMNESS;

        velocityDir2[0] += mlRandomFloat() * ENGINE_PARTICLE_DIR_RANDOMNESS * 2 - ENGINE_PARTICLE_DIR_RANDOMNESS;
        velocityDir2[1] += mlRandomFloat() * ENGINE_PARTICLE_DIR_RANDOMNESS * 2 - ENGINE_PARTICLE_DIR_RANDOMNESS;
        velocityDir2[2] += mlRandomFloat() * ENGINE_PARTICLE_DIR_RANDOMNESS * 2 - ENGINE_PARTICLE_DIR_RANDOMNESS;

        //----------------------------------------------------------------------
        // Decide on particles position
        //----------------------------------------------------------------------

        // Get the ships orientation matrix;

        float orientation[9]; getOrientationMatrix(orientation);

        // Decide on the particle position based on ship position and particle spawn point in ship coordinates

        float particlePosition[3] =
        {
            getPosX(),
            getPosY(),
            getPosZ()
        };

        particlePosition[0] += orientation[0] * particleSpawnX;
        particlePosition[1] += orientation[1] * particleSpawnX;
        particlePosition[2] += orientation[2] * particleSpawnX;

        particlePosition[0] += orientation[3] * particleSpawnY;
        particlePosition[1] += orientation[4] * particleSpawnY;
        particlePosition[2] += orientation[5] * particleSpawnY;

        particlePosition[0] += orientation[6] * particleSpawnZ;
        particlePosition[1] += orientation[7] * particleSpawnZ;
        particlePosition[2] += orientation[8] * particleSpawnZ;

        //----------------------------------------------------------------------
        // Spawn the engine particles
        //----------------------------------------------------------------------

        scene->createStream
        (
            particlePosition[0],
            particlePosition[1],
            particlePosition[2],
            ENGINE_PARTICLE_COLOR1_R,
            ENGINE_PARTICLE_COLOR1_G,
            ENGINE_PARTICLE_COLOR1_B,
            ENGINE_PARTICLE_COLOR2_R,
            ENGINE_PARTICLE_COLOR2_G,
            ENGINE_PARTICLE_COLOR2_B,
            ENGINE_PARTICLE_SIZE1,
            ENGINE_PARTICLE_SIZE2,
            moveSpeed1,
            moveSpeed2,
            velocityDir1[0],
            velocityDir1[1],
            velocityDir1[2],
            velocityDir2[0],
            velocityDir2[1],
            velocityDir2[2],
            ENGINE_PARTICLE_TIME1,
            ENGINE_PARTICLE_TIME2,
            ENGINE_PARTICLE_COUNT
        );

        //----------------------------------------------------------------------
        // Set time to next particle as engine particle interval
        //----------------------------------------------------------------------

        timeToEngineParticles = ENGINE_PARTICLE_INTERVAL;
    }
    else
    {
        //----------------------------------------------------------------------
        // Not time to make a particle: decrease the amount of time left
        // to make a particle by the frame time:
        //----------------------------------------------------------------------

        timeToEngineParticles -= lastFrameTime;
    }
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::onDraw()
Purpose:  On draw event for the ship. Draws the ships laser beam if it is firing
Params:   camera the scene is being viewed from
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::onDraw( Camera * camera )
{
    //--------------------------------------------------------------------------
    // Spawn engine particles for the ship: but only do it if the camera is not
    // following this ship or is following it and wants it drawn:
    //--------------------------------------------------------------------------

    if ( camera->showFollowObject() || camera->getFollowObject() != this )
    {
        spawnEngineParticles();
    }

    //--------------------------------------------------------------------------
    // Draw the ships laser beam: will do nothing if the laser is not firing:
    //--------------------------------------------------------------------------

    laser.draw(camera);
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::fireLasers()
Purpose:  Fires the ships lasers
Params:   time the last frame took in seconds
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::fireLasers( float frameTime )
{
    //--------------------------------------------------------------------------
    // Get the ships orientation matrix
    //--------------------------------------------------------------------------

    float orientation[9]; getOrientationMatrix(orientation);

    //--------------------------------------------------------------------------
    // Get the ships position:
    //--------------------------------------------------------------------------

    float position[3]; getPosition(position);

    //--------------------------------------------------------------------------
    // Figure out the position where the laser should start firing from:
    // This takes into account the position of the ship and point at which the
    // lasers start firing from in ship coordinates:
    //--------------------------------------------------------------------------

    float start[3] =
    {
        position[0],
        position[1],
        position[2]
    };

    start[0] += orientation[0] * laserStartX;
    start[1] += orientation[1] * laserStartX;
    start[2] += orientation[2] * laserStartX;

    start[0] += orientation[3] * laserStartY;
    start[1] += orientation[4] * laserStartY;
    start[2] += orientation[5] * laserStartY;

    start[0] += orientation[6] * laserStartZ;
    start[1] += orientation[7] * laserStartZ;
    start[2] += orientation[8] * laserStartZ;

    //--------------------------------------------------------------------------
    // Fire ship lasers in ships forward direction:
    //--------------------------------------------------------------------------

    laser.fire
    (
        (GameScene*)(getScene()),   // scene the ship is a part of: laser will be fired in this scene
        this,                       // firing object
        frameTime,                  // time of the last frame in seconds
        start[0],                   // origin of laser beam: x
        start[1],                   // origin of laser beam: y
        start[2],                   // origin of laser beam: z
        orientation[6],             // direction of laser beam: x
        orientation[7],             // direction of laser beam: y
        orientation[8]              // direction of laser beam: z
    );
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::fireLasers()
Purpose:  Fires the ships lasers but randomly varies the direction a little
Params:   time the last frame took in seconds
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::fireLasers( float frameTime , float randomness )
{
    //--------------------------------------------------------------------------
    // Get the ships orientation matrix
    //--------------------------------------------------------------------------

    float orientation[9]; getOrientationMatrix(orientation);

    //--------------------------------------------------------------------------
    // Get the ships position:
    //--------------------------------------------------------------------------

    float position[3]; getPosition(position);

    //--------------------------------------------------------------------------
    // Get the ships forward vector
    //--------------------------------------------------------------------------

    float forward[3]; getAxisZ(forward);

    //--------------------------------------------------------------------------
    // Randomly vary the forward vector:
    //--------------------------------------------------------------------------

    float rand1 = mlRandomFloat() * randomness; if ( mlRandomInt() & 1 ) rand1 *= -1;
    float rand2 = mlRandomFloat() * randomness; if ( mlRandomInt() & 1 ) rand2 *= -1;
    float rand3 = mlRandomFloat() * randomness; if ( mlRandomInt() & 1 ) rand3 *= -1;

    forward[0] += rand1;
    forward[1] += rand2;
    forward[2] += rand3;

    //--------------------------------------------------------------------------
    // Figure out the position where the laser should start firing from:
    // This takes into account the position of the ship and point at which the
    // lasers start firing from in ship coordinates:
    //--------------------------------------------------------------------------

    float start[3] =
    {
        position[0],
        position[1],
        position[2]
    };

    start[0] += orientation[0] * laserStartX;
    start[1] += orientation[1] * laserStartX;
    start[2] += orientation[2] * laserStartX;

    start[0] += orientation[3] * laserStartY;
    start[1] += orientation[4] * laserStartY;
    start[2] += orientation[5] * laserStartY;

    start[0] += orientation[6] * laserStartZ;
    start[1] += orientation[7] * laserStartZ;
    start[2] += orientation[8] * laserStartZ;

    //--------------------------------------------------------------------------
    // Fire ship lasers in ships forward direction which has been randomnly adjusted:
    //--------------------------------------------------------------------------

    laser.fire
    (
        (GameScene*)(getScene()),   // scene the ship is a part of: laser will be fired in this scene
        this,                       // firing object
        frameTime,                  // time of the last frame in seconds
        start[0],                   // origin of laser beam: x
        start[1],                   // origin of laser beam: y
        start[2],                   // origin of laser beam: z
        forward[0],                 // direction of laser beam: x
        forward[1],                 // direction of laser beam: y
        forward[2]                  // direction of laser beam: z
    );
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::coolLasers()
Purpose:  Cools the ships lasers
Params:   time the last frame took in seconds
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::coolLasers( float frameTime )
{
    // Cool down the lasers

    laser.cool( (GameScene*)(getScene()) , frameTime );
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::resetLaserHeat()
Purpose:  Sets the heat of the ships lasers to zero
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::resetLaserHeat()
{
    // Reset the lasers heat

    laser.resetCurrentHeat();
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::fireMissile()
Purpose:  Fires a ships missile at the selected target.
Params:   Target to fire at.
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::fireMissile( GameObject * target )
{
    // Abort if the ship is not in a game object scene or if target is null or if ship has no missiles:

    if ( getScene() == 0 || target == 0 || numMissiles == 0 ) return;

    // Decrement the number of missiles the ship has

    numMissiles--;

    // Get the x axis (right) vector of the ship:

    float xaxis[3]; this->getAxisX(xaxis);

    // Get a vector which will give the offset from the ships position along the right to spawn the missile:

    float missileOffset[3] =
    {
        xaxis[0] * this->getMesh()->getSphereRadius(),
        xaxis[1] * this->getMesh()->getSphereRadius(),
        xaxis[2] * this->getMesh()->getSphereRadius()
    };

    // Create a missile and add it into the game scene: fire from either the left or right of the ship

    GameObject_Missile * missile;

    if ( useLeftMissileBay )
    {
        missile = new GameObject_Missile
        (
            this->getPosX() + missileOffset[0],
            this->getPosY() + missileOffset[1],
            this->getPosZ() + missileOffset[2],
            this,
            target
        );
    }
    else
    {
        missile = new GameObject_Missile
        (
            this->getPosX() - missileOffset[0],
            this->getPosY() - missileOffset[1],
            this->getPosZ() - missileOffset[2],
            this,
            target
        );
    }

    // Change the misile bay used for firing the next missile

    useLeftMissileBay = ! useLeftMissileBay;

    // Set the velocity of the missile to that of the ship

    missile->setVelocity(this->velocity);

    // Add the missile into the game scene

    this->getScene()->addObject(missile);
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GameObject_Ship::deployEmp()
Purpose:  Deploys an emp bomb for the ship.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GameObject_Ship::deployEmp()
{
    // Get the scene the ship is in:

    GameObjectScene * scene = this->getScene();

    // If the scene is null then abort:

    if ( scene == 0 ) return;

    // Abort if the ship has no more emp bombs:

    if ( numEmpBombs == 0  ) return;

    // Otherwise decrement the number of emp bombs:

    numEmpBombs--;

    // Create an emp bomb:

    GameObject_Emp * emp = new GameObject_Emp(this);

    // Add it into the scene:

    scene->addObject(emp);
}
