450 lines
16 KiB
C++
450 lines
16 KiB
C++
/*
|
|
* 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/motionqueen.h"
|
|
|
|
#include "app/app.h"
|
|
|
|
#include "graphics/engine/engine.h"
|
|
#include "graphics/engine/oldmodelmanager.h"
|
|
|
|
#include "math/func.h"
|
|
|
|
#include "object/old_object.h"
|
|
|
|
#include "physics/physics.h"
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
const float START_TIME = 1000.0f; // beginning of the relative time
|
|
|
|
|
|
|
|
// Object's constructor.
|
|
|
|
CMotionQueen::CMotionQueen(COldObject* object)
|
|
: CMotion(object),
|
|
m_armAngles()
|
|
{
|
|
m_armMember = START_TIME;
|
|
m_armTimeAbs = START_TIME;
|
|
m_armTimeMarch = START_TIME;
|
|
}
|
|
|
|
// Object's destructor.
|
|
|
|
CMotionQueen::~CMotionQueen()
|
|
{
|
|
}
|
|
|
|
|
|
// Removes an object.
|
|
|
|
void CMotionQueen::DeleteObject(bool bAll)
|
|
{
|
|
}
|
|
|
|
|
|
// Creates a vehicle traveling any lands on the ground.
|
|
|
|
void CMotionQueen::Create(glm::vec3 pos, float angle, ObjectType type,
|
|
float power, Gfx::COldModelManager* modelManager)
|
|
{
|
|
int rank;
|
|
|
|
m_object->SetType(type);
|
|
|
|
// Creates main base.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_VEHICLE); // this is a moving object
|
|
m_object->SetObjectRank(0, rank);
|
|
modelManager->AddModelReference("mother1", false, rank);
|
|
m_object->SetPosition(pos);
|
|
m_object->SetRotationY(angle);
|
|
|
|
// A vehicle must have a obligatory collision
|
|
//with a sphere of center (0, y, 0) (see GetCrashSphere).
|
|
m_object->AddCrashSphere(CrashSphere(glm::vec3(0.0f, 0.0f, 0.0f), 20.0f, SOUND_BOUM, 0.20f));
|
|
m_object->SetCameraCollisionSphere(Math::Sphere(glm::vec3(-2.0f, 10.0f, 0.0f), 25.0f));
|
|
|
|
// Creates the head.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(1, rank);
|
|
m_object->SetObjectParent(1, 0);
|
|
modelManager->AddModelReference("mother2", false, rank);
|
|
m_object->SetPartPosition(1, glm::vec3(16.0f, 3.0f, 0.0f));
|
|
|
|
// Creates a right-back leg.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(2, rank);
|
|
m_object->SetObjectParent(2, 0);
|
|
modelManager->AddModelReference("mother3", false, rank);
|
|
m_object->SetPartPosition(2, glm::vec3(-5.0f, -1.0f, -12.0f));
|
|
|
|
// Creates a right-back foot.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(3, rank);
|
|
m_object->SetObjectParent(3, 2);
|
|
modelManager->AddModelReference("mother4", false, rank);
|
|
m_object->SetPartPosition(3, glm::vec3(0.0f, 0.0f, -8.5f));
|
|
|
|
// Creates a middle-right leg.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(4, rank);
|
|
m_object->SetObjectParent(4, 0);
|
|
modelManager->AddModelReference("mother3", false, rank);
|
|
m_object->SetPartPosition(4, glm::vec3(3.5f, -1.0f, -12.0f));
|
|
|
|
// Creates a middle-right foot.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(5, rank);
|
|
m_object->SetObjectParent(5, 4);
|
|
modelManager->AddModelReference("mother4", false, rank);
|
|
m_object->SetPartPosition(5, glm::vec3(0.0f, 0.0f, -8.5f));
|
|
|
|
// Creates a right-front leg.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(6, rank);
|
|
m_object->SetObjectParent(6, 0);
|
|
modelManager->AddModelReference("mother3", false, rank);
|
|
m_object->SetPartPosition(6, glm::vec3(10.0f, -1.0f, -10.0f));
|
|
|
|
// Creates a right-front foot.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(7, rank);
|
|
m_object->SetObjectParent(7, 6);
|
|
modelManager->AddModelReference("mother4", false, rank);
|
|
m_object->SetPartPosition(7, glm::vec3(0.0f, 0.0f, -8.5f));
|
|
|
|
// Creates a left-back leg.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(8, rank);
|
|
m_object->SetObjectParent(8, 0);
|
|
modelManager->AddModelReference("mother3", false, rank);
|
|
m_object->SetPartPosition(8, glm::vec3(-5.0f, -1.0f, 12.0f));
|
|
m_object->SetPartRotationY(8, Math::PI);
|
|
|
|
// Creates a left-back foot.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(9, rank);
|
|
m_object->SetObjectParent(9, 8);
|
|
modelManager->AddModelReference("mother4", false, rank);
|
|
m_object->SetPartPosition(9, glm::vec3(0.0f, 0.0f, -8.5f));
|
|
|
|
// Creates a middle-left leg.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(10, rank);
|
|
m_object->SetObjectParent(10, 0);
|
|
modelManager->AddModelReference("mother3", false, rank);
|
|
m_object->SetPartPosition(10, glm::vec3(3.5f, -1.0f, 12.0f));
|
|
m_object->SetPartRotationY(10, Math::PI);
|
|
|
|
// Creates a middle-left foot.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(11, rank);
|
|
m_object->SetObjectParent(11, 10);
|
|
modelManager->AddModelReference("mother4", false, rank);
|
|
m_object->SetPartPosition(11, glm::vec3(0.0f, 0.0f, -8.5f));
|
|
|
|
// Creates a left-front leg.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(12, rank);
|
|
m_object->SetObjectParent(12, 0);
|
|
modelManager->AddModelReference("mother3", false, rank);
|
|
m_object->SetPartPosition(12, glm::vec3(10.0f, -1.0f, 10.0f));
|
|
m_object->SetPartRotationY(12, Math::PI);
|
|
|
|
// Creates a left-front foot.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(13, rank);
|
|
m_object->SetObjectParent(13, 12);
|
|
modelManager->AddModelReference("mother4", false, rank);
|
|
m_object->SetPartPosition(13, glm::vec3(0.0f, 0.0f, -8.5f));
|
|
|
|
// Creates the right antenna.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(14, rank);
|
|
m_object->SetObjectParent(14, 1);
|
|
modelManager->AddModelReference("mother5", false, rank);
|
|
m_object->SetPartPosition(14, glm::vec3(6.0f, 1.0f, -2.5f));
|
|
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(15, rank);
|
|
m_object->SetObjectParent(15, 14);
|
|
modelManager->AddModelReference("mother6", false, rank);
|
|
m_object->SetPartPosition(15, glm::vec3(8.0f, 0.0f, 0.0f));
|
|
|
|
// Creates the left antenna.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(16, rank);
|
|
m_object->SetObjectParent(16, 1);
|
|
modelManager->AddModelReference("mother5", false, rank);
|
|
m_object->SetPartPosition(16, glm::vec3(6.0f, 1.0f, 2.5f));
|
|
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(17, rank);
|
|
m_object->SetObjectParent(17, 16);
|
|
modelManager->AddModelReference("mother6", false, rank);
|
|
m_object->SetPartPosition(17, glm::vec3(8.0f, 0.0f, 0.0f));
|
|
|
|
// Creates the right claw.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(18, rank);
|
|
m_object->SetObjectParent(18, 1);
|
|
modelManager->AddModelReference("mother7", false, rank);
|
|
m_object->SetPartPosition(18, glm::vec3(-4.0f, -3.5f, -8.0f));
|
|
m_object->SetPartScaleX(18, 1.2f);
|
|
|
|
// Creates the left claw.
|
|
rank = m_engine->CreateObject(m_object);
|
|
m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT);
|
|
m_object->SetObjectRank(19, rank);
|
|
m_object->SetObjectParent(19, 1);
|
|
modelManager->AddModelReference("mother7", true, rank);
|
|
m_object->SetPartPosition(19, glm::vec3(-4.0f, -3.5f, 8.0f));
|
|
m_object->SetPartScaleX(19, 1.2f);
|
|
|
|
m_object->CreateShadowCircle(18.0f, 0.8f);
|
|
|
|
CreatePhysics();
|
|
m_object->SetFloorHeight(0.0f);
|
|
|
|
pos = m_object->GetPosition();
|
|
m_object->SetPosition(pos); // to display the shadows immediately
|
|
|
|
m_engine->LoadAllTextures();
|
|
}
|
|
|
|
// Creates the physics of the object.
|
|
|
|
void CMotionQueen::CreatePhysics()
|
|
{
|
|
Character* character;
|
|
int i;
|
|
|
|
int member[] =
|
|
{
|
|
// x1,y1,z1, x2,y2,z2, x3,y3,z3, // in the air:
|
|
30,30,10, 35,-15,10, 35,-35,10, // t0: legs 1..3
|
|
-80,-45,-35, -115,-40,-35, -90,10,-55, // t0: feet 1..3
|
|
0,0,0, 0,0,0, 0,0,0, // t0: unused
|
|
// on the ground:
|
|
15,-5,10, 10,-30,10, 5,-50,10, // t1: legs 1..3
|
|
-90,-15,-15, -110,-55,-35, -75,-75,-30, // t1: feet 1..3
|
|
0,0,0, 0,0,0, 0,0,0, // t1: unused
|
|
// on the ground back:
|
|
0,40,10, 5,5,10, 0,-15,10, // t2: legs 1..3
|
|
-45,0,-55, -65,10,-50, -125,-85,-45, // t2: feet 1..3
|
|
0,0,0, 0,0,0, 0,0,0, // t2: unused
|
|
};
|
|
|
|
character = m_object->GetCharacter();
|
|
character->wheelFront = 10.0f;
|
|
character->wheelBack = 10.0f;
|
|
character->wheelLeft = 20.0f;
|
|
character->wheelRight = 20.0f;
|
|
character->height = 3.0f;
|
|
|
|
m_physics->SetLinMotionX(MO_ADVSPEED, 8.0f);
|
|
m_physics->SetLinMotionX(MO_RECSPEED, 8.0f);
|
|
m_physics->SetLinMotionX(MO_ADVACCEL, 10.0f);
|
|
m_physics->SetLinMotionX(MO_RECACCEL, 10.0f);
|
|
m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
|
|
m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
|
|
m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
|
|
m_physics->SetLinMotionX(MO_TERFORCE, 30.0f);
|
|
m_physics->SetLinMotionZ(MO_TERFORCE, 20.0f);
|
|
m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
|
|
|
|
m_physics->SetCirMotionY(MO_ADVSPEED, 0.1f*Math::PI);
|
|
m_physics->SetCirMotionY(MO_RECSPEED, 0.1f*Math::PI);
|
|
m_physics->SetCirMotionY(MO_ADVACCEL, 10.0f);
|
|
m_physics->SetCirMotionY(MO_RECACCEL, 10.0f);
|
|
m_physics->SetCirMotionY(MO_STOACCEL, 20.0f);
|
|
|
|
for ( i=0 ; i<3*3*3*3 ; i++ )
|
|
{
|
|
m_armAngles[i] = member[i];
|
|
}
|
|
}
|
|
|
|
|
|
// Management of an event.
|
|
|
|
bool CMotionQueen::EventProcess(const Event &event)
|
|
{
|
|
CMotion::EventProcess(event);
|
|
|
|
if ( event.type == EVENT_FRAME )
|
|
{
|
|
return EventFrame(event);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Management of an event.
|
|
|
|
bool CMotionQueen::EventFrame(const Event &event)
|
|
{
|
|
glm::vec3 dir;
|
|
float s, a, prog;
|
|
int i, st, nd;
|
|
bool bStop;
|
|
|
|
if ( m_engine->GetPause() ) return true;
|
|
if ( !m_engine->IsVisiblePoint(m_object->GetPosition()) ) return true;
|
|
|
|
s = m_physics->GetLinMotionX(MO_MOTSPEED)*1.5f;
|
|
a = fabs(m_physics->GetCirMotionY(MO_MOTSPEED)*26.0f);
|
|
|
|
if ( s == 0.0f && a != 0.0f ) a *= 1.5f;
|
|
|
|
m_armTimeAbs += event.rTime;
|
|
m_armTimeMarch += (s)*event.rTime*0.05f;
|
|
m_armMember += (s+a)*event.rTime*0.05f;
|
|
|
|
bStop = ( a == 0.0f && s == 0.0f ); // stop?
|
|
|
|
if ( bStop )
|
|
{
|
|
prog = Math::Mod(m_armTimeAbs, 2.0f)/10.0f;
|
|
a = Math::Mod(m_armMember, 1.0f);
|
|
a = (prog-a)*event.rTime*1.0f; // stop position just pleasantly
|
|
m_armMember += a;
|
|
}
|
|
|
|
for ( i=0 ; i<6 ; i++ ) // the six legs
|
|
{
|
|
if ( i < 3 ) prog = Math::Mod(m_armMember+(2.0f-(i%3))*0.33f+0.0f, 1.0f);
|
|
else prog = Math::Mod(m_armMember+(2.0f-(i%3))*0.33f+0.3f, 1.0f);
|
|
if ( prog < 0.33f ) // t0..t1 ?
|
|
{
|
|
prog = prog/0.33f; // 0..1
|
|
st = 0; // index start
|
|
nd = 1; // index end
|
|
}
|
|
else if ( prog < 0.67f ) // t1..t2 ?
|
|
{
|
|
prog = (prog-0.33f)/0.33f; // 0..1
|
|
st = 1; // index start
|
|
nd = 2; // index end
|
|
}
|
|
else // t2..t0 ?
|
|
{
|
|
prog = (prog-0.67f)/0.33f; // 0..1
|
|
st = 2; // index start
|
|
nd = 0; // index end
|
|
}
|
|
st = st*27+(i%3)*3;
|
|
nd = nd*27+(i%3)*3;
|
|
if ( i < 3 ) // right leg (1..3) ?
|
|
{
|
|
m_object->SetPartRotationX(2+2*i+0, Math::PropAngle(m_armAngles[st+ 0], m_armAngles[nd+ 0], prog));
|
|
m_object->SetPartRotationY(2+2*i+0, Math::PropAngle(m_armAngles[st+ 1], m_armAngles[nd+ 1], prog));
|
|
m_object->SetPartRotationZ(2+2*i+0, Math::PropAngle(m_armAngles[st+ 2], m_armAngles[nd+ 2], prog));
|
|
m_object->SetPartRotationX(2+2*i+1, Math::PropAngle(m_armAngles[st+ 9], m_armAngles[nd+ 9], prog));
|
|
m_object->SetPartRotationY(2+2*i+1, Math::PropAngle(m_armAngles[st+10], m_armAngles[nd+10], prog));
|
|
m_object->SetPartRotationZ(2+2*i+1, Math::PropAngle(m_armAngles[st+11], m_armAngles[nd+11], prog));
|
|
}
|
|
else // left leg (4..6) ?
|
|
{
|
|
m_object->SetPartRotationX(2+2*i+0, Math::PropAngle( m_armAngles[st+ 0], m_armAngles[nd+ 0], prog));
|
|
m_object->SetPartRotationY(2+2*i+0, Math::PropAngle(180-m_armAngles[st+ 1], 180-m_armAngles[nd+ 1], prog));
|
|
m_object->SetPartRotationZ(2+2*i+0, Math::PropAngle( -m_armAngles[st+ 2], -m_armAngles[nd+ 2], prog));
|
|
m_object->SetPartRotationX(2+2*i+1, Math::PropAngle( m_armAngles[st+ 9], m_armAngles[nd+ 9], prog));
|
|
m_object->SetPartRotationY(2+2*i+1, Math::PropAngle( -m_armAngles[st+10], -m_armAngles[nd+10], prog));
|
|
m_object->SetPartRotationZ(2+2*i+1, Math::PropAngle( -m_armAngles[st+11], -m_armAngles[nd+11], prog));
|
|
}
|
|
}
|
|
|
|
assert(m_object->Implements(ObjectInterfaceType::Destroyable));
|
|
if ( !bStop && !dynamic_cast<CDestroyableObject*>(m_object)->IsDying() )
|
|
{
|
|
a = Math::Mod(m_armTimeMarch, 1.0f);
|
|
if ( a < 0.5f ) a = -1.0f+4.0f*a; // -1..1
|
|
else a = 3.0f-4.0f*a; // 1..-1
|
|
dir.x = sinf(a)*0.03f;
|
|
|
|
s = Math::Mod(m_armTimeMarch/2.0f, 1.0f);
|
|
if ( s < 0.5f ) s = -1.0f+4.0f*s; // -1..1
|
|
else s = 3.0f-4.0f*s; // 1..-1
|
|
dir.z = sinf(s)*0.05f;
|
|
|
|
dir.y = 0.0f;
|
|
m_object->SetTilt(dir);
|
|
|
|
a = Math::Mod(m_armMember-0.1f, 1.0f);
|
|
if ( a < 0.33f )
|
|
{
|
|
dir.y = -(1.0f-(a/0.33f))*0.3f;
|
|
}
|
|
else if ( a < 0.67f )
|
|
{
|
|
dir.y = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
dir.y = -(a-0.67f)/0.33f*0.3f;
|
|
}
|
|
dir.x = 0.0f;
|
|
dir.z = 0.0f;
|
|
m_object->SetLinVibration(dir);
|
|
}
|
|
|
|
m_object->SetPartRotationZ(1, sinf(m_armTimeAbs*0.5f)*0.20f); // head
|
|
m_object->SetPartRotationX(1, sinf(m_armTimeAbs*0.6f)*0.10f); // head
|
|
m_object->SetPartRotationY(1, sinf(m_armTimeAbs*0.7f)*0.20f); // head
|
|
|
|
m_object->SetPartRotationZ(14, 0.50f);
|
|
m_object->SetPartRotationZ(16, 0.50f);
|
|
m_object->SetPartRotationY(14, 0.80f+sinf(m_armTimeAbs*1.1f)*0.53f); // right antenna
|
|
m_object->SetPartRotationY(15, 0.70f-sinf(m_armTimeAbs*1.7f)*0.43f);
|
|
m_object->SetPartRotationY(16, -0.80f+sinf(m_armTimeAbs*0.9f)*0.53f); // left antenna
|
|
m_object->SetPartRotationY(17, -0.70f-sinf(m_armTimeAbs*1.3f)*0.43f);
|
|
|
|
m_object->SetPartRotationY(18, sinf(m_armTimeAbs*1.1f)*0.20f); // right claw
|
|
m_object->SetPartRotationZ(18, -0.20f);
|
|
m_object->SetPartRotationY(19, sinf(m_armTimeAbs*0.9f)*0.20f); // left claw
|
|
m_object->SetPartRotationZ(19, -0.20f);
|
|
|
|
return true;
|
|
}
|