/*
 * This file is part of the Colobot: Gold Edition source code
 * Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
 * http://epsitec.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 "object/motion/motionhuman.h"

#include "app/app.h"

#include "graphics/engine/oldmodelmanager.h"
#include "graphics/engine/terrain.h"
#include "graphics/engine/water.h"

#include "level/robotmain.h"

#include "math/geometry.h"

#include "object/object_manager.h"
#include "object/old_object.h"

#include "physics/physics.h"

#include "sound/sound.h"


#include <stdio.h>



const int ADJUST_ACTION = (3*3*3*3*MH_SPEC+3*3*3*MHS_SATCOM);

const float START_TIME = 1000.0f;       // beginning of the relative time



// Object's constructor.

CMotionHuman::CMotionHuman(COldObject* object)
    : CMotion(object),
      m_armAngles()
{
    m_partiReactor   = -1;
    m_armMember      = START_TIME;
    m_armTimeAbs     = START_TIME;
    m_armTimeAction  = START_TIME;
    m_armTimeSwim    = START_TIME;
    m_armTimeIndex   = 0;
    m_armPartIndex   = 0;
    m_armMemberIndex = 0;
    m_armLastAction  = -1;
    m_bArmStop = false;
    m_lastSoundMarch = 0.0f;
    m_lastSoundHhh = 0.0f;
    m_time = 0.0f;
    m_tired = 0.0f;
    m_bDisplayPerso = false;
    m_glassesRank = -1;
}

// Object's constructor.

CMotionHuman::~CMotionHuman()
{
}


// Removes an object.

void CMotionHuman::DeleteObject(bool bAll)
{
    if ( m_partiReactor != -1 )
    {
        m_particle->DeleteParticle(m_partiReactor);
        m_partiReactor = -1;
    }
}


// Starts an action.

Error CMotionHuman::SetAction(int action, float time)
{
    CMotion::SetAction(action, time);
    m_time = 0.0f;
    return ERR_OK;
}


// Creates cosmonaut on the ground.

void CMotionHuman::Create(Math::Vector pos, float angle, ObjectType type,
                          float power, Gfx::COldModelManager* modelManager)
{
    char        filename[100];
    int         rank, option, face, glasses;

    m_object->SetType(type);
    option = m_object->GetOption();

    if ( m_main->GetGamerOnlyHead() )
    {
        rank = m_engine->CreateObject();
        m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_VEHICLE);  // this is a moving object
        m_object->SetObjectRank(0, rank);
        face = m_main->GetGamerFace();
        sprintf(filename, "human2h%d.mod", face+1);
        modelManager->AddModelReference(filename, false, rank);

        glasses = m_main->GetGamerGlasses();
        if ( glasses != 0 )
        {
            rank = m_engine->CreateObject();
            m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
            m_object->SetObjectRank(1, rank);
            m_object->SetObjectParent(1, 0);
            sprintf(filename, "human2g%d.mod", glasses);
            modelManager->AddModelReference(filename, false, rank);
        }

        CreatePhysics(type);
        m_object->SetFloorHeight(0.0f);

        m_engine->LoadAllTextures();

        return;
    }

    // Creates the main base.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_VEHICLE);  // this is a moving object
    m_object->SetObjectRank(0, rank);

    if (option == 0)  // head in helmet?
        modelManager->AddModelReference("human1c.mod", false, rank);
    else if (option == 1)  // head without helmet?
        modelManager->AddModelReference("human1h.mod", false, rank);
    else if (option == 2)  // without a backpack?
        modelManager->AddModelReference("human1v.mod", false, rank);

    m_object->SetPosition(pos);
    m_object->SetRotationY(angle);

    // A vehicle must have an obligatory collision with a sphere of center (0, y, 0) (see GetCrashSphere).
    m_object->AddCrashSphere(CrashSphere(Math::Vector(0.0f, 0.0f, 0.0f), 2.0f, SOUND_AIE, 0.20f));
    m_object->SetCameraCollisionSphere(Math::Sphere(Math::Vector(0.0f, 1.0f, 0.0f), 4.0f));

    // Creates the head.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(1, rank);
    m_object->SetObjectParent(1, 0);

    if ( type == OBJECT_HUMAN )
    {
        if (option == 0)  // head in helmet?
        {
            face = m_main->GetGamerFace();
            sprintf(filename, "human2c%d.mod", face+1);
            modelManager->AddModelReference(filename, false, rank);
        }
        else if (option == 1 ||  // head without helmet?
                 option == 2)    // without a backpack?
        {
            face = m_main->GetGamerFace();
            sprintf(filename, "human2h%d.mod", face+1);
            modelManager->AddModelReference(filename, false, rank);
        }
    }
    else if (type == OBJECT_TECH)
    {
        modelManager->AddModelReference("human2t.mod", false, rank);
    }

    m_object->SetPartPosition(1, Math::Vector(0.0f, 2.7f, 0.0f));
    if (option == 1 ||  // head without helmet?
        option == 2)    // without a backpack?
    {
        m_object->SetPartScale(1, Math::Vector(1.0f, 1.05f, 1.0f));
    }

    // Creates the glasses.
    glasses = m_main->GetGamerGlasses();
    if ( glasses != 0 && type == OBJECT_HUMAN )
    {
        m_glassesRank = m_engine->CreateObject();
        m_engine->SetObjectType(m_glassesRank, Gfx::ENG_OBJTYPE_DESCENDANT);
        m_object->SetObjectRank(15, m_glassesRank);
        m_object->SetObjectParent(15, 1);
        sprintf(filename, "human2g%d.mod", glasses);
        modelManager->AddModelReference(filename, false, m_glassesRank);
    }

    // Creates the right arm.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(2, rank);
    m_object->SetObjectParent(2, 0);
    modelManager->AddModelReference("human3.mod", false, rank);
    m_object->SetPartPosition(2, Math::Vector(0.0f, 2.3f, -1.2f));
    m_object->SetPartRotation(2, Math::Vector(90.0f*Math::PI/180.0f, 90.0f*Math::PI/180.0f, -50.0f*Math::PI/180.0f));

    // Creates the right forearm.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(3, rank);
    m_object->SetObjectParent(3, 2);
    modelManager->AddModelReference("human4r.mod", false, rank);
    m_object->SetPartPosition(3, Math::Vector(1.3f, 0.0f, 0.0f));
    m_object->SetPartRotation(3, Math::Vector(0.0f*Math::PI/180.0f, -20.0f*Math::PI/180.0f, 0.0f*Math::PI/180.0f));

    // Creates right hand.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(4, rank);
    m_object->SetObjectParent(4, 3);
    modelManager->AddModelReference("human5.mod", false, rank);
    m_object->SetPartPosition(4, Math::Vector(1.2f, 0.0f, 0.0f));

    // Creates the right thigh.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(5, rank);
    m_object->SetObjectParent(5, 0);
    modelManager->AddModelReference("human6.mod", false, rank);
    m_object->SetPartPosition(5, Math::Vector(0.0f, 0.0f, -0.7f));
    m_object->SetPartRotation(5, Math::Vector(10.0f*Math::PI/180.0f, 0.0f*Math::PI/180.0f, 5.0f*Math::PI/180.0f));

    // Creates the right leg.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(6, rank);
    m_object->SetObjectParent(6, 5);
    modelManager->AddModelReference("human7.mod", false, rank);
    m_object->SetPartPosition(6, Math::Vector(0.0f, -1.5f, 0.0f));
    m_object->SetPartRotation(6, Math::Vector(0.0f*Math::PI/180.0f, 0.0f*Math::PI/180.0f, -10.0f*Math::PI/180.0f));

    // Creates the right foot.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(7, rank);
    m_object->SetObjectParent(7, 6);
    modelManager->AddModelReference("human8.mod", false, rank);
    m_object->SetPartPosition(7, Math::Vector(0.0f, -1.5f, 0.0f));
    m_object->SetPartRotation(7, Math::Vector(-10.0f*Math::PI/180.0f, 5.0f*Math::PI/180.0f, 5.0f*Math::PI/180.0f));

    // Creates the left arm.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(8, rank);
    m_object->SetObjectParent(8, 0);
    modelManager->AddModelReference("human3.mod", true, rank);
    m_object->SetPartPosition(8, Math::Vector(0.0f, 2.3f, 1.2f));
    m_object->SetPartRotation(8, Math::Vector(-90.0f*Math::PI/180.0f, -90.0f*Math::PI/180.0f, -50.0f*Math::PI/180.0f));

    // Creates the left forearm.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(9, rank);
    m_object->SetObjectParent(9, 8);
    modelManager->AddModelReference("human4l.mod", true, rank);
    m_object->SetPartPosition(9, Math::Vector(1.3f, 0.0f, 0.0f));
    m_object->SetPartRotation(9, Math::Vector(0.0f*Math::PI/180.0f, 20.0f*Math::PI/180.0f, 0.0f*Math::PI/180.0f));

    // Creates left hand.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(10, rank);
    m_object->SetObjectParent(10, 9);
    modelManager->AddModelReference("human5.mod", true, rank);
    m_object->SetPartPosition(10, Math::Vector(1.2f, 0.0f, 0.0f));

    // Creates the left thigh.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(11, rank);
    m_object->SetObjectParent(11, 0);
    modelManager->AddModelReference("human6.mod", true, rank);
    m_object->SetPartPosition(11, Math::Vector(0.0f, 0.0f, 0.7f));
    m_object->SetPartRotation(11, Math::Vector(-10.0f*Math::PI/180.0f, 0.0f*Math::PI/180.0f, 5.0f*Math::PI/180.0f));

    // Creates the left leg.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(12, rank);
    m_object->SetObjectParent(12, 11);
    modelManager->AddModelReference("human7.mod", true, rank);
    m_object->SetPartPosition(12, Math::Vector(0.0f, -1.5f, 0.0f));
    m_object->SetPartRotation(12, Math::Vector(0.0f*Math::PI/180.0f, 0.0f*Math::PI/180.0f, -10.0f*Math::PI/180.0f));

    // Creates the left foot.
    rank = m_engine->CreateObject();
    m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
    m_object->SetObjectRank(13, rank);
    m_object->SetObjectParent(13, 12);
    modelManager->AddModelReference("human8.mod", true, rank);
    m_object->SetPartPosition(13, Math::Vector(0.0f, -1.5f, 0.0f));
    m_object->SetPartRotation(13, Math::Vector(10.0f*Math::PI/180.0f, -5.0f*Math::PI/180.0f, 5.0f*Math::PI/180.0f));

    // Creates the neutron gun.
    if ( option != 2 && !m_main->GetPlusExplorer())  // with backpack?
    {
        rank = m_engine->CreateObject();
        m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
        m_object->SetObjectRank(14, rank);
        m_object->SetObjectParent(14, 0);
        modelManager->AddModelReference("human9.mod", false, rank);
        m_object->SetPartPosition(14, Math::Vector(-1.5f, 0.3f, -1.35f));
        m_object->SetPartRotationZ(14, Math::PI);
    }

    m_object->CreateShadowCircle(2.0f, 0.8f);

    CreatePhysics(type);
    m_object->SetFloorHeight(0.0f);

    pos = m_object->GetPosition();
    m_object->SetPosition(pos);  // to display the shadows immediately

    m_engine->LoadAllTextures();
}

// Creates the physical object.

void CMotionHuman::CreatePhysics(ObjectType type)
{
    Character*  character;
    int         i;

    int member_march[] =
    {
    //  x1,y1,z1,   x2,y2,z2,   x3,y3,z3,   // in the air:
        90,90,-50,  10,0,55,    0,0,0,      // t0: arms/thighs/-
        0,-20,0,    -5,0,-110,  0,0,0,      // t0: forearm/legs/-
        0,0,0,      -5,0,40,    0,0,0,      // t0: hands/feet/-
                                            // on the ground:
        125,115,-45,    10,0,50,    0,0,0,      // t1: arms/thighs/-
        0,-20,0,    -5,0,-15,   0,0,0,      // t1: forearm/legs/-
        0,0,0,      -5,0,0,     0,0,0,      // t1: hands/feet/-
                                            // on the ground back:
        25,55,-40,  10,0,-15,   0,0,0,      // t2: arms/thighs/-
        30,-50,40,  -5,0,-55,   0,0,0,      // t2: forearm/legs/-
        0,0,0,      -5,0,25,    0,0,0,      // t2: hands/feet/-
    };

    int member_march_take[] =
    {
    //  x1,y1,z1,   x2,y2,z2,   x3,y3,z3,   // in the air:
        15,50,-50,  10,0,55,    0,0,0,      // t0: arms/thighs/-
        45,-70,10,  -5,0,-110,  0,0,0,      // t0: forearm/legs/-
        -10,25,0,   -5,0,40,    0,0,0,      // t0: hands/feet/-
                                            // on the ground:
        15,50,-55,  10,0,50,    0,0,0,      // t1: arms/thighs/-
        45,-70,10,  -5,0,-15,   0,0,0,      // t1: forearm/legs/-
        -10,25,0,   -5,0,0,     0,0,0,      // t1: hands/feet/-
                                            // on the ground back:
        15,50,-45,  10,0,-15,   0,0,0,      // t2: arms/thighs/-
        45,-70,10,  -5,0,-55,   0,0,0,      // t2: forearm/legs/-
        -10,25,0,   -5,0,45,    0,0,0,      // t2: hands/feet/-
    };

    int member_turn[] =
    {
    //  x1,y1,z1,   x2,y2,z2,   x3,y3,z3,   // in the air:
        90,90,-50,  10,0,30,    0,0,0,      // t0: arms/thighs/-
        0,-20,0,    -5,0,-60,   0,0,0,      // t0: forearm/legs/-
        0,0,0,      -5,0,30,    0,0,0,      // t0: hands/feet/-
                                            // on the ground:
        90,110,-45, 10,0,0,     0,0,0,      // t1: arms/thighs/-
        0,-20,0,    -5,5,0,     0,0,0,      // t1: forearm/legs/-
        0,0,0,      -5,10,0,    0,0,0,      // t1: hands/feet/-
                                            // on the ground back:
        90,70,-45,  10,0,0,     0,0,0,      // t2: arms/thighs/-
        0,-20,10,   -5,-5,0,    0,0,0,      // t2: forearm/legs/-
        0,0,0,      -5,-10,0,   0,0,0,      // t2: hands/feet/-
    };

    int member_stop[] =
    {
    //  x1,y1,z1,   x2,y2,z2,   x3,y3,z3,
        90,90,-50,  10,0,5,     0,0,0,      // arms/thighs/-
        0,-20,0,    0,0,-10,    0,0,0,      // forearm/legs/-
        0,0,0,      -10,5,5,    0,0,0,      // hands/feet/-
                                            //
        90,90,-55,  10,0,5,     0,0,0,      // arms/thighs/-
        0,-15,0,    0,0,-10,    0,0,0,      // forearm/legs/-
        0,0,0,      -10,5,5,    0,0,0,      // hands/feet/-
                                            //
        90,90,-60,  10,0,5,     0,0,0,      // arms/thighs/-
        0,-10,0,    0,0,-10,    0,0,0,      // forearm/legs/-
        0,0,0,      -10,5,5,    0,0,0,      // hands/feet/-
    };

    int member_fly[] =
    {
    //  x1,y1,z1,   x2,y2,z2,   x3,y3,z3,
        -5,90,-60,  20,5,-25,   0,0,0,      // arms/thighs/-
        85,-40,-25, 10,0,-30,   0,0,0,      // forearm/legs/-
        40,10,25,   0,15,0,     0,0,0,      // hands/feet/-
                                            //
        -15,90,-40, 20,5,-35,   0,0,0,      // arms/thighs/-
        85,-40,-25, 10,0,-40,   0,0,0,      // forearm/legs/-
        45,5,20,    0,15,0,     0,0,0,      // hands/feet/-
                                            //
        -25,90,-50, 20,5,-20,   0,0,0,      // arms/thighs/-
        85,-40,-25, 10,0,-10,   0,0,0,      // forearm/legs/-
        30,15,25,   0,15,0,     0,0,0,      // hands/feet/-
    };

    int member_swim[] =
    {
    //  x1,y1,z1,   x2,y2,z2,   x3,y3,z3,
        130,-70,200,    10,20,55,   0,0,0,      // arms/thighs/-
        115,-125,0, -5,0,-110,  0,0,0,      // forearm/legs/-
        0,0,0,      -5,10,-5,   0,0,0,      // hands/feet/-
                                            //
        130,-95,115,55,5,5,     0,0,0,      // arms/thighs/-
        75,-50,25,  -5,0,-15,   0,0,0,      // forearm/legs/-
        0,0,0,      -5,5,-30,   0,0,0,      // hands/feet/-
                                            //
        130,-100,220,5,0,0,     0,0,0,      // arms/thighs/-
        150,5,0,    -5,0,-15,   0,0,0,      // forearm/legs/-
        0,0,0,      -5,30,-20,  0,0,0,      // hands/feet/-
    };

    int member_spec[] =
    {
    //  x1,y1,z1,   x2,y2,z2,   x3,y3,z3,   // shooting:
        65,5,-20,   10,0,40,    0,0,0,      // s0: arms/thighs/-
        -50,-30,50, 0,0,-70,    0,0,0,      // s0: forearm/legs/-
        0,50,0,     -10,0,35,   0,0,0,      // s0: hands/feet/-
                                            // takes weapon:
        160,135,-20,10,0,5,     0,0,0,      // s1: arms/thighs/-
        10,-60,40,  0,0,-10,    0,0,0,      // s1: forearm/legs/-
        0,-5,-25,   -10,5,5,    0,0,0,      // s1: hands/feet/-
                                            // carries earth:
        25,40,-40,  10,0,60,    0,0,0,      // s2: arms/thighs/-
        0,-45,0,    0,0,-120,   0,0,0,      // s2: forearm/legs/-
        0,15,5,     -10,0,70,   0,0,0,      // s2: hands/feet/-
                                            // carries in front:
        25,20,5,    10,0,55,    0,0,0,      // s3: arms/thighs/-
        -15,-30,10, 0,0,-110,   0,0,0,      // s3: forearm/legs/-
        0,0,0,      -10,0,65,   0,0,0,      // s3: hands/feet/-
                                            // carries vertically:
        -30,15,-5,  10,0,15,    0,0,0,      // s4: arms/thighs/-
        0,-15,15,   0,0,-30,    0,0,0,      // s4: forearm/legs/-
        35,0,-15,   -10,0,25,   0,0,0,      // s4: hands/feet/-
                                            // rises:
        15,50,-50,  10,0,5,     0,0,0,      // s5: arms/thighs/-
        45,-70,10,  0,0,-10,    0,0,0,      // s5: forearm/legs/-
        -10,25,0,   -10,5,5,    0,0,0,      // s5: hands/feet/-
                                            // wins:
        90,90,-30,  20,0,5,     0,0,0,      // s6: arms/thighs/-
        0,-90,0,    -10,0,-10,  0,0,0,      // s6: forearm/legs/-
        0,25,0,     -10,5,5,    0,0,0,      // s6: hands/feet/-
                                            // lose:
        -70,45,35,  10,0,40,    0,0,0,      // s7: arms/thighs/-
        15,-95,-5,  0,0,-70,    0,0,0,      // s7: forearm/legs/-
        0,0,0,      -10,0,35,   0,0,0,      // s7: hands/feet/-
                                            // shooting death (falls):
        90,90,-50,  10,0,5,     0,0,0,      // s8: arms/thighs/-
        0,-20,0,    0,0,-10,    0,0,0,      // s8: forearm/legs/-
        0,0,0,      -10,5,5,    0,0,0,      // s8: hands/feet/-
                                            // shooting death (knees):
        110,105,-5, 10,0,25,    0,0,0,      // s9: arms/thighs/-
        0,-40,20,   0,0,-120,   0,0,0,      // s9: forearm/legs/-
        0,0,0,      -10,5,5,    0,0,0,      // s9: hands/feet/-
                                            // shooting death (knees):
        110,120,-25,    10,0,25,    0,0,0,      // s10: arms/thighs/-
        0,-40,20,   0,0,-120,   0,0,0,      // s10: forearm/legs/-
        0,0,0,      -10,5,5,    0,0,0,      // s10: hands/feet/-
                                            // shooting death (face down):
        110,100,-25,    25,0,10,    0,0,0,      // s11: arms/thighs/-
        0,-40,20,   0,0,-25,    0,0,0,      // s11: forearm/legs/-
        0,0,0,      -10,5,5,    0,0,0,      // s11: hands/feet/-
                                            // shooting death (face down):
        110,100,-25,    25,0,10,    0,0,0,      // s12: arms/thighs/-
        0,-40,20,   0,0,-25,    0,0,0,      // s12: forearm/legs/-
        0,0,0,      -10,5,5,    0,0,0,      // s12: hands/feet/-
                                            // drowned:
        110,100,-25,    25,0,10,    0,0,0,      // s13: arms/thighs/-
        0,-40,20,   0,0,-25,    0,0,0,      // s13: forearm/legs/-
        0,0,0,      -10,5,5,    0,0,0,      // s13: hands/feet/-
                                            // puts / removes flag:
        85,45,-50,  10,0,60,    0,0,0,      // s14: arms/thighs/-
        -60,15,65,  0,0,-105,   0,0,0,      // s14: forearm/legs/-
        0,10,0,     -10,0,60,   0,0,0,      // s14: hands/feet/-
                                            // reads SatCom:
        70,30,-20,  10,0,5,     0,0,0,      // s15: arms/thighs/-
        115,-65,60, 0,0,-10,    0,0,0,      // s15: forearm/legs/-
        0,20,0,     -10,5,5,    0,0,0,      // s15: hands/feet/-
    };

    character = m_object->GetCharacter();
    character->wheelFront = 4.0f;
    character->wheelBack  = 4.0f;
    character->wheelLeft  = 4.0f;
    character->wheelRight = 4.0f;
    character->height     = 3.5f;

    if ( type == OBJECT_HUMAN )
    {
        m_physics->SetLinMotionX(MO_ADVSPEED, 50.0f);
        m_physics->SetLinMotionX(MO_RECSPEED, 35.0f);
        m_physics->SetLinMotionX(MO_ADVACCEL, 20.0f);
        m_physics->SetLinMotionX(MO_RECACCEL, 20.0f);
        m_physics->SetLinMotionX(MO_STOACCEL, 20.0f);
        m_physics->SetLinMotionX(MO_TERSLIDE,  5.0f);
        m_physics->SetLinMotionZ(MO_TERSLIDE,  5.0f);
        m_physics->SetLinMotionX(MO_TERFORCE, 70.0f);
        m_physics->SetLinMotionZ(MO_TERFORCE, 40.0f);
        m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
        m_physics->SetLinMotionY(MO_ADVSPEED, 60.0f);
        m_physics->SetLinMotionY(MO_RECSPEED, 60.0f);
        m_physics->SetLinMotionY(MO_ADVACCEL, 20.0f);
        m_physics->SetLinMotionY(MO_RECACCEL, 50.0f);
        m_physics->SetLinMotionY(MO_STOACCEL, 50.0f);

        m_physics->SetCirMotionY(MO_ADVSPEED,  0.8f*Math::PI);
        m_physics->SetCirMotionY(MO_RECSPEED,  0.8f*Math::PI);
        m_physics->SetCirMotionY(MO_ADVACCEL,  6.0f);
        m_physics->SetCirMotionY(MO_RECACCEL,  6.0f);
        m_physics->SetCirMotionY(MO_STOACCEL,  4.0f);
    }
    else
    {
        m_physics->SetLinMotionX(MO_ADVSPEED, 40.0f);
        m_physics->SetLinMotionX(MO_RECSPEED, 15.0f);
        m_physics->SetLinMotionX(MO_ADVACCEL,  8.0f);
        m_physics->SetLinMotionX(MO_RECACCEL,  8.0f);
        m_physics->SetLinMotionX(MO_STOACCEL,  8.0f);
        m_physics->SetLinMotionX(MO_TERSLIDE,  5.0f);
        m_physics->SetLinMotionZ(MO_TERSLIDE,  5.0f);
        m_physics->SetLinMotionX(MO_TERFORCE, 50.0f);
        m_physics->SetLinMotionZ(MO_TERFORCE, 50.0f);
        m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
        m_physics->SetLinMotionY(MO_ADVSPEED, 60.0f);
        m_physics->SetLinMotionY(MO_RECSPEED, 60.0f);
        m_physics->SetLinMotionY(MO_ADVACCEL, 20.0f);
        m_physics->SetLinMotionY(MO_RECACCEL, 50.0f);
        m_physics->SetLinMotionY(MO_STOACCEL, 50.0f);

        m_physics->SetCirMotionY(MO_ADVSPEED,  0.6f*Math::PI);
        m_physics->SetCirMotionY(MO_RECSPEED,  0.6f*Math::PI);
        m_physics->SetCirMotionY(MO_ADVACCEL,  4.0f);
        m_physics->SetCirMotionY(MO_RECACCEL,  4.0f);
        m_physics->SetCirMotionY(MO_STOACCEL,  3.0f);
    }

    for ( i=0 ; i<3*3*3*3 ; i++ )
    {
        m_armAngles[3*3*3*3*MH_MARCH+i] = member_march[i];
    }
    for ( i=0 ; i<3*3*3*3 ; i++ )
    {
        m_armAngles[3*3*3*3*MH_MARCHTAKE+i] = member_march_take[i];
    }
    for ( i=0 ; i<3*3*3*3 ; i++ )
    {
        m_armAngles[3*3*3*3*MH_TURN+i] = member_turn[i];
    }
    for ( i=0 ; i<3*3*3*3 ; i++ )
    {
        m_armAngles[3*3*3*3*MH_STOP+i] = member_stop[i];
    }
    for ( i=0 ; i<3*3*3*3 ; i++ )
    {
        m_armAngles[3*3*3*3*MH_FLY+i] = member_fly[i];
    }
    for ( i=0 ; i<3*3*3*3 ; i++ )
    {
        m_armAngles[3*3*3*3*MH_SWIM+i] = member_swim[i];
    }
    for ( i=0 ; i<3*3*3*16 ; i++ )
    {
        m_armAngles[3*3*3*3*MH_SPEC+i] = member_spec[i];
    }
}


// Management of an event.

bool CMotionHuman::EventProcess(const Event &event)
{
    CMotion::EventProcess(event);

    if ( event.type == EVENT_FRAME )
    {
        return EventFrame(event);
    }

    return true;
}

// Management of an event.

bool CMotionHuman::EventFrame(const Event &event)
{
    Math::Matrix*   mat;
    Math::Vector    dir, actual, pos, speed, pf;
    Math::Point     center, dim, p2;
    float       s, a, prog, rTime[2], lTime[2], time, rot, hr, hl;
    float       al, ar, af;
    float       tSt[9], tNd[9];
    float       aa, bb, deadFactor = 0.0f, level;
    int         i, ii, st, nd, action, legAction, armAction;
    bool        bOnBoard, bSwim;

    if ( m_engine->GetPause() )
    {
        if ( m_actionType == MHS_SATCOM )
        {
            m_progress += event.rTime*m_actionTime;
        }
        else
        {
            return true;
        }
    }

    bOnBoard = false;
    if ( m_object->GetSelect() &&
         m_camera->GetType() == Gfx::CAM_TYPE_ONBOARD )
    {
        bOnBoard = true;
    }

    if ( m_bDisplayPerso && m_main->GetGamerOnlyHead() )
    {
        m_time += event.rTime;
        m_object->SetLinVibration(Math::Vector(0.0f, -0.55f, 0.0f));
        m_object->SetCirVibration(Math::Vector(0.0f, m_main->GetPersoAngle(), 0.0f));
        return true;
    }
    if ( m_bDisplayPerso )
    {
        m_object->SetCirVibration(Math::Vector(0.0f, m_main->GetPersoAngle()+0.2f, 0.0f));
    }

    if ( m_glassesRank != -1 )
    {
        if ( m_camera->GetType() == Gfx::CAM_TYPE_ONBOARD )
        {
            m_engine->SetObjectDrawWorld(m_glassesRank, false);
        }
        else
        {
            m_engine->SetObjectDrawWorld(m_glassesRank, true);
        }
    }

    bSwim = m_physics->GetSwim();

    rot = m_physics->GetCirMotionY(MO_MOTSPEED);
    a = m_physics->GetLinMotionX(MO_REASPEED);
    s = m_physics->GetLinMotionX(MO_MOTSPEED)*0.2f;
    if ( fabs(a) > fabs(s) )  s = a;  // the highest value
    a = m_physics->GetLinMotionX(MO_TERSPEED);
    if ( a < 0.0f )  // rises?
    {
        a += m_physics->GetLinMotionX(MO_TERSLIDE);
        if ( a < 0.0f )  s -= a;
    }
    if ( a > 0.0f )  // falls?
    {
        a -= m_physics->GetLinMotionX(MO_TERSLIDE);
        if ( a > 0.0f )  s -= a;
    }
    s *= 2.0f;
    a = fabs(rot*12.0f);

    if ( !m_physics->GetLand() && !bSwim )  // in flight?
    {
        s = 0.0f;
    }

    if (IsObjectCarryingCargo(m_object))  // carries something?
    {
        s *= 1.3f;
    }

    m_time += event.rTime;
    m_armTimeAbs += event.rTime;
    m_armTimeAction += event.rTime;
    m_armMember += s*event.rTime*0.05f;

    // Fatigue management when short.
    if ( m_physics->GetLand() && s != 0.0f )  // on the ground?
    {
        m_tired += event.rTime*0.1f;
        if ( m_tired > 1.0f )
        {
            m_tired = 1.0f;
            if ( m_lastSoundHhh > 3.0f )  m_lastSoundHhh = 0.5f;
        }
    }
    else
    {
        m_tired -= event.rTime*0.2f;
        if ( m_tired < 0.0f )  m_tired = 0.0f;
    }

    if ( bSwim )  // swims?
    {
        s += fabs(m_physics->GetLinMotionY(MO_REASPEED)*2.0f);
        a *= 2.0f;
        m_armTimeSwim += Math::Min(Math::Max(s,a,3.0f),15.0f)*event.rTime*0.05f;
    }

    prog = 0.0f;

    if ( m_physics->GetLand() )  // on the ground?
    {
        if ( s == 0.0f && a == 0.0f )
        {
            action = MH_STOP;  // stop
            rTime[0] = rTime[1] = m_armTimeAbs*0.21f;
            lTime[0] = lTime[1] = m_armTimeAbs*0.25f;
            m_armMember = START_TIME;
        }
        else
        {
            if ( s == 0.0f )
            {
                action = MH_TURN;  // turn
                rTime[0] = rTime[1] = m_armTimeAbs;
                lTime[0] = lTime[1] = m_armTimeAbs+0.5f;
                if ( rot < 0.0f )
                {
                    rTime[1] = 1000000.0f-rTime[1];
                }
                else
                {
                    lTime[1] = 1000000.0f-lTime[1];
                }
                m_armMember = START_TIME;
            }
            else
            {
                action = MH_MARCH;  // walking
                if (IsObjectCarryingCargo(m_object))  action = MH_MARCHTAKE;  // take walking
                rTime[0] = rTime[1] = m_armMember;
                lTime[0] = lTime[1] = m_armMember+0.5f;
            }
        }
        if ( bSwim )
        {
            rTime[0] *= 0.6f;
            rTime[1] *= 0.6f;
            lTime[0] = rTime[0]+0.5f;
            lTime[1] = rTime[1]+0.5f;
        }
    }
    else
    {
        if ( bSwim )
        {
            action = MH_SWIM;  // swim
            rTime[0] = rTime[1] = m_armTimeSwim;
            lTime[0] = lTime[1] = m_armTimeSwim;
        }
        else
        {
            action = MH_FLY;  // fly
            rTime[0] = rTime[1] = m_armTimeAbs*0.30f;
            lTime[0] = lTime[1] = m_armTimeAbs*0.31f;
            m_armMember = START_TIME;
        }
    }

    if ( action != m_armLastAction )
    {
        m_armLastAction = action;
        m_armTimeAction = 0.0f;
    }

    armAction = action;
    legAction = action;

    if (IsObjectCarryingCargo(m_object))  // carries something?
    {
        armAction = MH_MARCHTAKE;  // take walking
    }

    if ( m_physics->GetLand() )  // on the ground?
    {
        a = m_object->GetRotationY();
        pos = m_object->GetPosition();
        m_terrain->AdjustToFloor(pos);

        pf.x = pos.x+cosf(a+Math::PI*1.5f)*0.7f;
        pf.y = pos.y;
        pf.z = pos.z-sinf(a+Math::PI*1.5f)*0.7f;
        m_terrain->AdjustToFloor(pf);
        al = atanf((pf.y-pos.y)/0.7f);  // angle for left leg

        pf = pos;
        pf.x = pos.x+cosf(a+Math::PI*0.5f)*0.7f;
        pf.y = pos.y;
        pf.z = pos.z-sinf(a+Math::PI*0.5f)*0.7f;
        m_terrain->AdjustToFloor(pf);
        ar = atanf((pf.y-pos.y)/0.7f);  // angle to right leg

        pf.x = pos.x+cosf(a+Math::PI)*0.3f;
        pf.y = pos.y;
        pf.z = pos.z-sinf(a+Math::PI)*0.3f;
        m_terrain->AdjustToFloor(pf);
        af = atanf((pf.y-pos.y)/0.3f);  // angle for feet
    }
    else
    {
        al = 0.0f;
        ar = 0.0f;
        af = 0.0f;
    }

    for ( i=0 ; i<4 ; i++ )  // 4 members
    {
        if ( m_bArmStop )  // focus?
        {
            st = ADJUST_ACTION + (i%2)*3;
            nd = st;
            time = 100.0f;
            m_armTimeAction = 0.0f;
        }
        else if ( m_actionType != -1 )  // special action in progress?
        {
            st = 3*3*3*3*MH_SPEC + 3*3*3*m_actionType + (i%2)*3;
            nd = st;
            time = event.rTime*m_actionTime;
            m_armTimeAction = 0.0f;
        }
        else
        {
            if ( i < 2 )  prog = Math::Mod(rTime[i%2], 1.0f);
            else          prog = Math::Mod(lTime[i%2], 1.0f);
            if ( prog < 0.25f )  // t0..t1 ?
            {
                prog = prog/0.25f;  // 0..1
                st = 0;  // index start
                nd = 1;  // index end
            }
            else if ( prog < 0.75f )  // t1..t2 ?
            {
                prog = (prog-0.25f)/0.50f;  // 0..1
                st = 1;  // index start
                nd = 2;  // index end
            }
            else    // t2..t0 ?
            {
                prog = (prog-0.75f)/0.25f;  // 0..1
                st = 2;  // index start
                nd = 0;  // index end
            }
            if ( i%2 == 0 )  // arm?
            {
                st = 3*3*3*3*armAction + st*3*3*3 + (i%2)*3;
                nd = 3*3*3*3*armAction + nd*3*3*3 + (i%2)*3;
            }
            else    // leg?
            {
                st = 3*3*3*3*legAction + st*3*3*3 + (i%2)*3;
                nd = 3*3*3*3*legAction + nd*3*3*3 + (i%2)*3;
            }

            // Less soft ...
            time = event.rTime*(5.0f+Math::Min(m_armTimeAction*50.0f, 100.0f));
            if ( bSwim )  time *= 0.25f;
        }

        tSt[0] = m_armAngles[st+ 0];  // x
        tSt[1] = m_armAngles[st+ 1];  // y
        tSt[2] = m_armAngles[st+ 2];  // z
        tSt[3] = m_armAngles[st+ 9];  // x
        tSt[4] = m_armAngles[st+10];  // y
        tSt[5] = m_armAngles[st+11];  // z
        tSt[6] = m_armAngles[st+18];  // x
        tSt[7] = m_armAngles[st+19];  // y
        tSt[8] = m_armAngles[st+20];  // z

        tNd[0] = m_armAngles[nd+ 0];  // x
        tNd[1] = m_armAngles[nd+ 1];  // y
        tNd[2] = m_armAngles[nd+ 2];  // z
        tNd[3] = m_armAngles[nd+ 9];  // x
        tNd[4] = m_armAngles[nd+10];  // y
        tNd[5] = m_armAngles[nd+11];  // z
        tNd[6] = m_armAngles[nd+18];  // x
        tNd[7] = m_armAngles[nd+19];  // y
        tNd[8] = m_armAngles[nd+20];  // z

        aa = 0.5f;
        if ( i%2 == 0 )  // arm?
        {
            if (! IsObjectCarryingCargo(m_object))
            {
                aa = 2.0f;  // moves a lot
            }
            else
            {
                aa = 0.0f;  // immobile
            }
        }

        if ( i < 2 )  // left?
        {
            bb = sinf(m_time*1.1f)*aa;  tSt[0] += bb;  tNd[0] += bb;
            bb = sinf(m_time*1.0f)*aa;  tSt[1] += bb;  tNd[1] += bb;
            bb = sinf(m_time*1.2f)*aa;  tSt[2] += bb;  tNd[2] += bb;
            bb = sinf(m_time*2.5f)*aa;  tSt[3] += bb;  tNd[3] += bb;
            bb = sinf(m_time*2.0f)*aa;  tSt[4] += bb;  tNd[4] += bb;
            bb = sinf(m_time*3.8f)*aa;  tSt[5] += bb;  tNd[5] += bb;
            bb = sinf(m_time*3.0f)*aa;  tSt[6] += bb;  tNd[6] += bb;
            bb = sinf(m_time*2.3f)*aa;  tSt[7] += bb;  tNd[7] += bb;
            bb = sinf(m_time*4.0f)*aa;  tSt[8] += bb;  tNd[8] += bb;
        }
        else    // right?
        {
            bb = sinf(m_time*0.9f)*aa;  tSt[0] += bb;  tNd[0] += bb;
            bb = sinf(m_time*1.2f)*aa;  tSt[1] += bb;  tNd[1] += bb;
            bb = sinf(m_time*1.4f)*aa;  tSt[2] += bb;  tNd[2] += bb;
            bb = sinf(m_time*2.9f)*aa;  tSt[3] += bb;  tNd[3] += bb;
            bb = sinf(m_time*1.4f)*aa;  tSt[4] += bb;  tNd[4] += bb;
            bb = sinf(m_time*3.1f)*aa;  tSt[5] += bb;  tNd[5] += bb;
            bb = sinf(m_time*3.7f)*aa;  tSt[6] += bb;  tNd[6] += bb;
            bb = sinf(m_time*2.0f)*aa;  tSt[7] += bb;  tNd[7] += bb;
            bb = sinf(m_time*3.1f)*aa;  tSt[8] += bb;  tNd[8] += bb;
        }

        if ( i%2 == 1           &&  // leg?
             m_actionType == -1 )   // no special action?
        {
            if ( i == 1 )  // right leg?
            {
                ii = 5;
                a = ar*0.25f;
            }
            else
            {
                ii = 11;
                a = al*0.25f;
            }
            if ( a < -0.2f )  a = -0.2f;
            if ( a >  0.2f )  a =  0.2f;

            pos = m_object->GetPartPosition(ii+0);
            pos.y = 0.0f+a;
            m_object->SetPartPosition(ii+0, pos);  // lengthens / shortcuts thigh

            pos = m_object->GetPartPosition(ii+1);
            pos.y = -1.5f+a;
            m_object->SetPartPosition(ii+1, pos);  // lengthens / shortcuts leg

            pos = m_object->GetPartPosition(ii+2);
            pos.y = -1.5f+a;
            m_object->SetPartPosition(ii+2, pos);  // lengthens / shortcuts foot

            if ( i == 1 )  // right leg?
            {
                aa = (ar*180.0f/Math::PI*0.5f);
            }
            else    // left leg?
            {
                aa = (al*180.0f/Math::PI*0.5f);
            }
            tSt[6] += aa;
            tNd[6] += aa;  // increases the angle X of the foot

            if ( i == 1 )  // right leg?
            {
                aa = (ar*180.0f/Math::PI);
            }
            else    // left leg?
            {
                aa = (al*180.0f/Math::PI);
            }
            if ( aa <  0.0f )  aa =  0.0f;
            if ( aa > 30.0f )  aa = 30.0f;

            tSt[2] += aa;
            tNd[2] += aa;    // increases the angle Z of the thigh
            tSt[5] -= aa*2;
            tNd[5] -= aa*2;  // increases the angle Z of the leg
            tSt[8] += aa;
            tNd[8] += aa;    // increases the angle Z of the foot

            aa = (af*180.0f/Math::PI)*0.7f;
            if ( aa < -30.0f )  aa = -30.0f;
            if ( aa >  30.0f )  aa =  30.0f;

            tSt[8] -= aa;
            tNd[8] -= aa;    // increases the angle Z of the foot
        }

        if ( m_actionType == MHS_DEADw )   // drowned?
        {
            if ( m_progress < 0.5f )
            {
                deadFactor = m_progress/0.5f;
            }
            else
            {
                deadFactor = 1.0f-(m_progress-0.5f)/0.5f;
            }
            if ( deadFactor < 0.0f )  deadFactor = 0.0f;
            if ( deadFactor > 1.0f )  deadFactor = 1.0f;

            for ( ii=0 ; ii<9 ; ii++ )
            {
                tSt[ii] += Math::Rand()*20.0f*deadFactor;
                tNd[ii] = tSt[ii];
            }
            time = 100.0f;
        }

        if ( i < 2 )  // right member (0..1) ?
        {
            m_object->SetPartRotationX(2+3*i+0, Math::Smooth(m_object->GetPartRotationX(2+3*i+0), Math::PropAngle(tSt[0], tNd[0], prog), time));
            m_object->SetPartRotationY(2+3*i+0, Math::Smooth(m_object->GetPartRotationY(2+3*i+0), Math::PropAngle(tSt[1], tNd[1], prog), time));
            m_object->SetPartRotationZ(2+3*i+0, Math::Smooth(m_object->GetPartRotationZ(2+3*i+0), Math::PropAngle(tSt[2], tNd[2], prog), time));
            m_object->SetPartRotationX(2+3*i+1, Math::Smooth(m_object->GetPartRotationX(2+3*i+1), Math::PropAngle(tSt[3], tNd[3], prog), time));
            m_object->SetPartRotationY(2+3*i+1, Math::Smooth(m_object->GetPartRotationY(2+3*i+1), Math::PropAngle(tSt[4], tNd[4], prog), time));
            m_object->SetPartRotationZ(2+3*i+1, Math::Smooth(m_object->GetPartRotationZ(2+3*i+1), Math::PropAngle(tSt[5], tNd[5], prog), time));
            m_object->SetPartRotationX(2+3*i+2, Math::Smooth(m_object->GetPartRotationX(2+3*i+2), Math::PropAngle(tSt[6], tNd[6], prog), time));
            m_object->SetPartRotationY(2+3*i+2, Math::Smooth(m_object->GetPartRotationY(2+3*i+2), Math::PropAngle(tSt[7], tNd[7], prog), time));
            m_object->SetPartRotationZ(2+3*i+2, Math::Smooth(m_object->GetPartRotationZ(2+3*i+2), Math::PropAngle(tSt[8], tNd[8], prog), time));
        }
        else    // left member (2..3) ?
        {
            m_object->SetPartRotationX(2+3*i+0, Math::Smooth(m_object->GetPartRotationX(2+3*i+0), Math::PropAngle(-tSt[0], -tNd[0], prog), time));
            m_object->SetPartRotationY(2+3*i+0, Math::Smooth(m_object->GetPartRotationY(2+3*i+0), Math::PropAngle(-tSt[1], -tNd[1], prog), time));
            m_object->SetPartRotationZ(2+3*i+0, Math::Smooth(m_object->GetPartRotationZ(2+3*i+0), Math::PropAngle( tSt[2],  tNd[2], prog), time));
            m_object->SetPartRotationX(2+3*i+1, Math::Smooth(m_object->GetPartRotationX(2+3*i+1), Math::PropAngle(-tSt[3], -tNd[3], prog), time));
            m_object->SetPartRotationY(2+3*i+1, Math::Smooth(m_object->GetPartRotationY(2+3*i+1), Math::PropAngle(-tSt[4], -tNd[4], prog), time));
            m_object->SetPartRotationZ(2+3*i+1, Math::Smooth(m_object->GetPartRotationZ(2+3*i+1), Math::PropAngle( tSt[5],  tNd[5], prog), time));
            m_object->SetPartRotationX(2+3*i+2, Math::Smooth(m_object->GetPartRotationX(2+3*i+2), Math::PropAngle(-tSt[6], -tNd[6], prog), time));
            m_object->SetPartRotationY(2+3*i+2, Math::Smooth(m_object->GetPartRotationY(2+3*i+2), Math::PropAngle(-tSt[7], -tNd[7], prog), time));
            m_object->SetPartRotationZ(2+3*i+2, Math::Smooth(m_object->GetPartRotationZ(2+3*i+2), Math::PropAngle( tSt[8],  tNd[8], prog), time));
        }
    }

    // calculates the height lowering as a function
    // of the position of the legs.
    hr = 1.5f*(1.0f-cosf(m_object->GetPartRotationZ(5))) +
         1.5f*(1.0f-cosf(m_object->GetPartRotationZ(5)+m_object->GetPartRotationZ(6)));
    a = 1.0f*sinf(m_object->GetPartRotationZ(5)+m_object->GetPartRotationZ(6)+m_object->GetPartRotationZ(7));
    if ( a < 0.0f )  hr += a;

    hl = 1.5f*(1.0f-cosf(m_object->GetPartRotationZ(11))) +
         1.5f*(1.0f-cosf(m_object->GetPartRotationZ(11)+m_object->GetPartRotationZ(12)));
    a = 1.0f*sinf(m_object->GetPartRotationZ(11)+m_object->GetPartRotationZ(12)+m_object->GetPartRotationZ(13));
    if ( a < 0.0f )  hl += a;

    hr = Math::Min(hr, hl);

    if ( m_actionType == MHS_FIRE )  // shooting?
    {
        time = event.rTime*m_actionTime;

        dir.x = (Math::Rand()-0.5f)/8.0f;
        dir.z = (Math::Rand()-0.5f)/8.0f;
        dir.y = -0.5f;  // slightly lower
        actual = m_object->GetLinVibration();
        dir.x = Math::Smooth(actual.x, dir.x, time);
//?     dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.y = -hr;
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetLinVibration(dir);

        dir.x = 0.0f;
        dir.y = (Math::Rand()-0.5f)/3.0f;
        dir.z = -0.1f;  // slightly leaning forward
        actual = m_object->GetTilt();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetTilt(dir);
    }
    else if ( m_actionType == MHS_TAKE      ||  // carrying?
              m_actionType == MHS_TAKEOTHER )   // flag?
    {
        time = event.rTime*m_actionTime*2.0f;

        dir.x = 0.0f;
        dir.z = 0.0f;
        dir.y = -1.5f;  // slightly lower
        actual = m_object->GetLinVibration();
        dir.x = Math::Smooth(actual.x, dir.x, time);
//?     dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.y = -hr;
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetLinVibration(dir);

        dir.x = 0.0f;
        dir.y = 0.0f;
        dir.z = -0.2f;
        actual = m_object->GetTilt();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetTilt(dir);
    }
    else if ( m_actionType == MHS_TAKEHIGH )   // carrying?
    {
        time = event.rTime*m_actionTime*2.0f;

        dir.x = 0.4f;  // slightly forward
        dir.z = 0.0f;
        dir.y = 0.0f;
        actual = m_object->GetLinVibration();
        dir.x = Math::Smooth(actual.x, dir.x, time);
//?     dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.y = -hr;
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetLinVibration(dir);

        dir.x = 0.0f;
        dir.y = 0.0f;
        dir.z = -0.2f;
        actual = m_object->GetTilt();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetTilt(dir);
    }
    else if ( m_actionType == MHS_FLAG )   // flag?
    {
        time = event.rTime*m_actionTime*2.0f;

        dir.x = 0.0f;
        dir.z = 0.0f;
        dir.y = -2.0f;  // slightly lower
        actual = m_object->GetLinVibration();
        dir.x = Math::Smooth(actual.x, dir.x, time);
//?     dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.y = -hr;
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetLinVibration(dir);

        dir.x = 0.0f;
        dir.y = 0.0f;
        dir.z = -0.4f;
        actual = m_object->GetTilt();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetTilt(dir);
    }
    else if ( m_actionType == MHS_DEADg )   // shooting death (falls)?
    {
        if ( m_physics->GetLand() )  // on the ground?
        {
            SetAction(MHS_DEADg1, 0.5f);  // knees
        }
    }
    else if ( m_actionType == MHS_DEADg1 )   // shooting death (knees)?
    {
        prog = m_progress;
        if ( prog >= 1.0f )
        {
            prog = 1.0f;

            for ( i=0 ; i<10 ; i++ )
            {
                pos = m_object->GetPosition();
                pos.x += (Math::Rand()-0.5f)*4.0f;
                pos.z += (Math::Rand()-0.5f)*4.0f;
                m_terrain->AdjustToFloor(pos);
                speed = Math::Vector(0.0f, 0.0f, 0.0f);
                dim.x = 1.2f+Math::Rand()*1.2f;
                dim.y = dim.x;
                m_particle->CreateParticle(pos, speed, dim, Gfx::PARTICRASH, 2.0f, 0.0f, 0.0f);
            }
            m_sound->Play(SOUND_BOUMv, m_object->GetPosition());

            SetAction(MHS_DEADg2, 1.0f);  // expects knees
        }

        time = 100.0f;

        dir.x = 0.0f;
        dir.z = 0.0f;
        dir.y = -1.5f*prog;
        actual = m_object->GetLinVibration();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetLinVibration(dir);

        dir.x = 0.0f;
        dir.y = 0.0f;
        dir.z = -(20.0f*Math::PI/180.0f)*prog;
        actual = m_object->GetTilt();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetTilt(dir);
    }
    else if ( m_actionType == MHS_DEADg2 )   // shooting death (knees)?
    {
        if ( m_progress >= 1.0f )
        {
            SetAction(MHS_DEADg3, 1.0f);  // face down
        }

        time = 100.0f;

        dir.x = 0.0f;
        dir.z = 0.0f;
        dir.y = -1.5f;
        actual = m_object->GetLinVibration();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetLinVibration(dir);

        dir.x = 0.0f;
        dir.y = 0.0f;
        dir.z = -(20.0f*Math::PI/180.0f);
        actual = m_object->GetTilt();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetTilt(dir);
    }
    else if ( m_actionType == MHS_DEADg3 )   // shooting death (face down)?
    {
        prog = m_progress;
        if ( prog >= 1.0f )
        {
            prog = 1.0f;

            for ( i=0 ; i<20 ; i++ )
            {
                pos = m_object->GetPosition();
                pos.x += (Math::Rand()-0.5f)*8.0f;
                pos.z += (Math::Rand()-0.5f)*8.0f;
                m_terrain->AdjustToFloor(pos);
                speed = Math::Vector(0.0f, 0.0f, 0.0f);
                dim.x = 2.0f+Math::Rand()*1.5f;
                dim.y = dim.x;
                m_particle->CreateParticle(pos, speed, dim, Gfx::PARTICRASH, 2.0f, 0.0f, 0.0f);
            }
            m_sound->Play(SOUND_BOUMv, m_object->GetPosition());

            SetAction(MHS_DEADg4, 3.0f);  // expects face down
        }

        time = 100.0f;
        prog = powf(prog, 3.0f);

        dir.y = -(1.5f+1.5f*prog);
        dir.x = 0.0f;
        dir.z = 0.0f;
        actual = m_object->GetLinVibration();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetLinVibration(dir);

        dir.z = -((20.0f*Math::PI/180.0f)+(70.0f*Math::PI/180.0f)*prog);
        dir.x = 0.0f;
        dir.y = 0.0f;
        actual = m_object->GetTilt();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetTilt(dir);
    }
    else if ( m_actionType == MHS_DEADg4 )   // shooting death (face down)?
    {
        if ( m_progress >= 1.0f )
        {
            CObjectManager::GetInstancePointer()->DeleteObject(m_object);
            return false;
        }

        time = 100.0f;

        dir.y = -(1.5f+1.5f);
        dir.x = 0.0f;
        dir.z = 0.0f;
        actual = m_object->GetLinVibration();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetLinVibration(dir);

        dir.z = -((20.0f*Math::PI/180.0f)+(70.0f*Math::PI/180.0f));
        dir.x = 0.0f;
        dir.y = 0.0f;
        actual = m_object->GetTilt();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetTilt(dir);
    }
    else if ( m_actionType == MHS_DEADw )   // drowned?
    {
        pos = m_object->GetPosition();
        level = m_water->GetLevel()-0.5f;
        if ( pos.y < level )
        {
            pos.y += 4.0f*event.rTime;  // back to the surface
            if ( pos.y > level )  pos.y = level;
            m_object->SetPosition(pos);
        }
        if ( pos.y > level )
        {
            pos.y -= 10.0f*event.rTime;  // down quickly
            if ( pos.y < level )  pos.y = level;
            m_object->SetPosition(pos);
        }

        prog = m_progress;
        if ( prog >= 1.0f )
        {
            prog = 1.0f;
            if ( pos.y >= level )
            {
                CObjectManager::GetInstancePointer()->DeleteObject(m_object);
                return false;
            }
        }

        prog *= 2.0f;
        if ( prog > 1.0f )  prog = 1.0f;

        time = 100.0f;

        dir.z = -(90.0f*Math::PI/180.0f)*prog;
        dir.x = Math::Rand()*0.3f*deadFactor;
        dir.y = Math::Rand()*0.3f*deadFactor;
        actual = m_object->GetTilt();
        dir.x = Math::Smooth(actual.x, dir.x, time);
        dir.y = Math::Smooth(actual.y, dir.y, time);
        dir.z = Math::Smooth(actual.z, dir.z, time);
        m_object->SetTilt(dir);

        m_object->SetCirVibration(Math::Vector(0.0f, 0.0f, 0.0f));
    }
    else if ( m_actionType == MHS_LOST )   // lost?
    {
        time = m_time;
        if ( time < 10.0f )  time *= time/10.0f;  // starts slowly

        dir.x = time*2.0f;
        dir.y = sinf(m_time*0.8f)*0.8f;
        dir.z = sinf(m_time*0.6f)*0.5f;
        m_object->SetTilt(dir);
        SetTilt(dir);

//?     dir.x = -(sinf(time*0.05f+Math::PI*1.5f)+1.0f)*100.0f;
        // original code: Math::Min(time/30.0f) (?) changed to time/30.0f
        dir.x = -(powf(time/30.0f, 4.0f))*1000.0f;  // from the distance
        dir.y = 0.0f;
        dir.z = 0.0f;
        m_object->SetLinVibration(dir);
        SetLinVibration(dir);

        mat = m_object->GetWorldMatrix(0);
        pos = Math::Vector(0.5f, 3.7f, 0.0f);
        pos.x += (Math::Rand()-0.5f)*1.0f;
        pos.y += (Math::Rand()-0.5f)*1.0f;
        pos.z += (Math::Rand()-0.5f)*1.0f;
        pos = Transform(*mat, pos);
        speed.x = (Math::Rand()-0.5f)*0.5f;
        speed.y = (Math::Rand()-0.5f)*0.5f;
        speed.z = (Math::Rand()-0.5f)*0.5f;
        dim.x = 0.5f+Math::Rand()*0.5f;
        dim.y = dim.x;
        m_particle->CreateParticle(pos, speed, dim, Gfx::PARTILENS1, 5.0f, 0.0f, 0.0f);
    }
    else if ( m_actionType == MHS_SATCOM )  // look at the SatCom?
    {
        SetCirVibration(Math::Vector(0.0f, 0.0f, 0.0f));
        SetLinVibration(Math::Vector(0.0f, 0.0f, 0.0f));
        SetTilt(Math::Vector(0.0f, 0.0f, 0.0f));
    }
    else
    {
        if ( m_physics->GetLand() )  // on the ground?
        {
            time = event.rTime*8.0f;
            if ( bSwim )  time *= 0.25f;

            if ( action == MH_MARCH )   // walking?
            {
                dir.x = sinf(Math::Mod(rTime[0]+0.5f, 1.0f)*Math::PI*2.0f)*0.10f;
                dir.y = sinf(Math::Mod(rTime[0]+0.6f, 1.0f)*Math::PI*2.0f)*0.20f;
                s = m_physics->GetLinMotionX(MO_REASPEED)*0.03f;
            }
            else if ( action == MH_MARCHTAKE )   // takes walking?
            {
                dir.x = sinf(Math::Mod(rTime[0]+0.5f, 1.0f)*Math::PI*2.0f)*0.10f;
                dir.y = sinf(Math::Mod(rTime[0]+0.6f, 1.0f)*Math::PI*2.0f)*0.15f;
                s = m_physics->GetLinMotionX(MO_REASPEED)*0.02f;
            }
            else
            {
                dir.x = 0.0f;
                dir.y = 0.0f;
                s = m_physics->GetLinMotionX(MO_REASPEED)*0.03f;
            }

            if ( s < 0.0f )  s *= 0.5f;
            dir.z = -s*0.7f;

            actual = m_object->GetTilt();
            dir.x = Math::Smooth(actual.x, dir.x, time);
            dir.y = Math::Smooth(actual.y, dir.y, time);
            dir.z = Math::Smooth(actual.z, dir.z, time);
            if ( bOnBoard )  dir *= 0.3f;
            m_object->SetTilt(dir);
            SetTilt(dir);

            if ( action == MH_MARCH )   // walking?
            {
                p2.x = 0.0f;
                p2.y = sinf(Math::Mod(rTime[0]+0.5f, 1.0f)*Math::PI*2.0f)*0.5f;
                p2 = Math::RotatePoint(-m_object->GetRotationY(), p2);
                dir.x = p2.x;
                dir.z = p2.y;
                dir.y = sinf(Math::Mod(rTime[0]*2.0f, 1.0f)*Math::PI*2.0f)*0.3f;
            }
            else if ( action == MH_MARCHTAKE )   // takes walking?
            {
                p2.x = 0.0f;
                p2.y = sinf(Math::Mod(rTime[0]+0.5f, 1.0f)*Math::PI*2.0f)*0.25f;
                p2 = Math::RotatePoint(-m_object->GetRotationY(), p2);
                dir.x = p2.x;
                dir.z = p2.y;
                dir.y = sinf(Math::Mod(rTime[0]*2.0f, 1.0f)*Math::PI*2.0f)*0.05f-0.3f;
            }
            else
            {
                dir.x = 0.0f;
                dir.z = 0.0f;
                dir.y = 0.0f;
            }

            actual = m_object->GetLinVibration();
            dir.x = Math::Smooth(actual.x, dir.x, time);
            if ( action == MH_MARCHTAKE )  // takes walking?
            {
                dir.y = -hr;
            }
            else
            {
                s = Math::Min(m_armTimeAction, 1.0f);
                dir.y = Math::Smooth(actual.y, dir.y, time)*s;
                dir.y += -hr*(1.0f-s);
            }
            dir.z = Math::Smooth(actual.z, dir.z, time);
            if ( bOnBoard )  dir *= 0.3f;
            m_object->SetLinVibration(dir);

            dir.x = 0.0f;
            dir.z = 0.0f;
            dir.y = 0.0f;
            SetCirVibration(dir);
        }
    }

    // Management of the head.
    if ( m_actionType == MHS_TAKE ||  // takes?
         m_actionType == MHS_FLAG )   // takes?
    {
        m_object->SetPartRotationZ(1, Math::Smooth(m_object->GetPartRotationZ(1), sinf(m_armTimeAbs*1.0f)*0.2f-0.6f, event.rTime*5.0f));
        m_object->SetPartRotationX(1, sinf(m_armTimeAbs*1.1f)*0.1f);
        m_object->SetPartRotationY(1, Math::Smooth(m_object->GetPartRotationY(1), sinf(m_armTimeAbs*1.3f)*0.2f+rot*0.3f, event.rTime*5.0f));
    }
    else if ( m_actionType == MHS_TAKEOTHER ||  // takes?
              m_actionType == MHS_TAKEHIGH  )   // takes?
    {
        m_object->SetPartRotationZ(1, Math::Smooth(m_object->GetPartRotationZ(1), sinf(m_armTimeAbs*1.0f)*0.2f-0.3f, event.rTime*5.0f));
        m_object->SetPartRotationX(1, sinf(m_armTimeAbs*1.1f)*0.1f);
        m_object->SetPartRotationY(1, Math::Smooth(m_object->GetPartRotationY(1), sinf(m_armTimeAbs*1.3f)*0.2f+rot*0.3f, event.rTime*5.0f));
    }
    else if ( m_actionType == MHS_WIN )   // win
    {
        float   factor = 0.6f+(sinf(m_armTimeAbs*0.5f)*0.40f);
        m_object->SetPartRotationZ(1, sinf(m_armTimeAbs*5.0f)*0.20f*factor);
        m_object->SetPartRotationX(1, sinf(m_armTimeAbs*0.6f)*0.10f);
        m_object->SetPartRotationY(1, sinf(m_armTimeAbs*1.5f)*0.15f);
    }
    else if ( m_actionType == MHS_LOST )   // lost?
    {
        float   factor = 0.6f+(sinf(m_armTimeAbs*0.5f)*0.40f);
        m_object->SetPartRotationZ(1, sinf(m_armTimeAbs*0.6f)*0.10f);
        m_object->SetPartRotationX(1, sinf(m_armTimeAbs*0.7f)*0.10f);
        m_object->SetPartRotationY(1, sinf(m_armTimeAbs*3.0f)*0.30f*factor);
    }
    else if ( m_object->Implements(ObjectInterfaceType::Destroyable) && !dynamic_cast<CDestroyableObject*>(m_object)->IsDying() )  // dead?
    {
        m_object->SetPartRotationZ(1, Math::Smooth(m_object->GetPartRotationZ(1), sinf(m_armTimeAbs*1.0f)*0.2f, event.rTime*5.0f));
        m_object->SetPartRotationX(1, sinf(m_armTimeAbs*1.1f)*0.1f);
        m_object->SetPartRotationY(1, Math::Smooth(m_object->GetPartRotationY(1), sinf(m_armTimeAbs*1.3f)*0.2f+rot*0.3f, event.rTime*5.0f));
    }

    if ( bOnBoard )
    {
        m_object->SetPartRotationZ(1, 0.0f);
        m_object->SetPartRotationX(1, 0.0f);
        m_object->SetPartRotationY(1, 0.0f);
    }

    // Steps sound effects.
    if ( legAction == MH_MARCH     ||
         legAction == MH_MARCHTAKE )
    {
        SoundType   sound[2];
        float   synchro, volume[2], freq[2], hard;

        float speedX = m_physics->GetLinMotionX(MO_REASPEED);

        if (IsObjectCarryingCargo(m_object))
        {
            if ( speedX > 0.0f )  synchro = 0.15f;  // synchro forward
            else                 synchro = 0.35f;  // synchro backward
        }
        else
        {
            if ( speedX > 0.0f )  synchro = 0.21f;  // synchro forward
            else                 synchro = 0.29f;  // synchro backward
        }
        time = rTime[1]+synchro;

        if ( fabs(m_lastSoundMarch-time) > 0.4f &&
             Math::Mod(time, 0.5f) < 0.1f )
        {
            volume[0] = 0.5f;
            freq[0] = 1.0f;
            if (IsObjectCarryingCargo(m_object))
            {
//?             volume[0] *= 2.0f;
                freq[0] = 0.7f;
            }
            volume[1] = volume[0];
            freq[1] = freq[0];
            sound[0] = SOUND_NONE;
            sound[1] = SOUND_NONE;

            pos = m_object->GetPosition();

            level = m_water->GetLevel();
            if ( pos.y <= level+3.0f )  // underwater?
            {
                sound[0] = SOUND_STEPw;
            }
            else
            {
                hard = m_terrain->GetHardness(pos);

                if ( hard >= 0.875 )
                {
                    sound[0] = SOUND_STEPm;  // metal
                }
                else
                {
                    hard /= 0.875;
                    sound[0] = SOUND_STEPs;  // smooth
                    sound[1] = SOUND_STEPh;  // hard

                    volume[0] *= 1.0f-hard;
                    volume[1] *= hard;
                    if ( hard < 0.5f )
                    {
                        volume[0] *= 1.0f+hard*2.0f;
                        volume[1] *= 1.0f+hard*2.0f;
                    }
                    else
                    {
                        volume[0] *= 3.0f-hard*2.0f;
                        volume[1] *= 3.0f-hard*2.0f;
                    }
                    freq[0] *= 1.0f+hard;
                    freq[1] *= 0.5f+hard;
                }
            }

            if ( sound[0] != SOUND_NONE )
            {
                m_sound->Play(sound[0], pos, volume[0], freq[0]);
            }
            if ( sound[1] != SOUND_NONE )
            {
                m_sound->Play(sound[1], pos, volume[1], freq[1]);
            }
            m_lastSoundMarch = time;
        }
    }

    if ( legAction == MH_SWIM )
    {
        time = rTime[0]+0.5f;

        if ( fabs(m_lastSoundMarch-time) > 0.9f &&
             Math::Mod(time, 1.0f) < 0.1f )
        {
            m_sound->Play(SOUND_SWIM, m_object->GetPosition(), 0.5f);
            m_lastSoundMarch = time;
        }
    }

    m_lastSoundHhh -= event.rTime;
    if ( m_lastSoundHhh <= 0.0f &&
         m_object->GetSelect()  &&
         m_object->GetOption() == 0 )  // helmet?
    {
        m_sound->Play(SOUND_HUMAN1, m_object->GetPosition(), (0.5f+m_tired*0.2f));
        m_lastSoundHhh = (4.0f-m_tired*2.5f)+(4.0f-m_tired*2.5f)*Math::Rand();
    }

    return true;
}


// Management of the display mode when customizing the personal.

void CMotionHuman::StartDisplayPerso()
{
    m_bDisplayPerso = true;
}

void CMotionHuman::StopDisplayPerso()
{
    m_bDisplayPerso = false;
}
