// * This file is part of the COLOBOT source code // * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch // * // * 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://www.gnu.org/licenses/. // motionworm.cpp #include #include "object/motion/motionworm.h" #include "old/modfile.h" #include "old/particule.h" #include "old/terrain.h" #include "math/geometry.h" #include "physics/physics.h" const float START_TIME = 1000.0f; // beginning of the relative time const float TIME_UPDOWN = 2.0f; // time for up / down const float DOWN_ALTITUDE = 3.0f; // underground distance const int WORM_PART = 7; // number of parts of a worm // Object's constructor. CMotionWorm::CMotionWorm(CInstanceManager* iMan, CObject* object) : CMotion(iMan, object) { m_timeUp = 18.0f; m_timeDown = 18.0f; m_armMember = START_TIME; m_armTimeAbs = START_TIME; m_armTimeMarch = START_TIME; m_armTimeAction = START_TIME; m_armTimeIndex = 0; m_armPartIndex = 0; m_armMemberIndex = 0; m_armLinSpeed = 0.0f; m_armCirSpeed = 0.0f; m_armLastAction = -1; m_specAction = -1; m_lastParticule = 0.0f; m_bArmStop = false; } // Object's destructor. CMotionWorm::~CMotionWorm() { } // Removes an object. void CMotionWorm::DeleteObject(bool bAll) { } // Creates a vehicle traveling any lands on the ground. bool CMotionWorm::Create(Math::Vector pos, float angle, ObjectType type, float power) { CModFile* pModFile; int rank, i; float px; if ( m_engine->RetRestCreate() < 2+WORM_PART+1 ) return false; pModFile = new CModFile(m_iMan); m_object->SetType(type); // Creates the main base. rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, TYPEVEHICULE); // this is a moving object m_object->SetObjectRank(0, rank); pModFile->ReadModel("objects\\worm0.mod"); // there is no purpose! pModFile->CreateEngineObject(rank); m_object->SetPosition(0, pos); m_object->SetAngleY(0, angle); // A vehicle must have a obligatory collision with a sphere of center (0, y, 0) (see GetCrashSphere). m_object->CreateCrashSphere(Math::Vector(0.0f, 0.0f, 0.0f), 4.0f, SOUND_BOUM, 0.20f); m_object->SetGlobalSphere(Math::Vector(0.0f, 0.0f, 0.0f), 5.0f); px = 1.0f+WORM_PART/2; // Creates the head. rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, TYPEDESCENDANT); m_object->SetObjectRank(1, rank); m_object->SetObjectParent(1, 0); pModFile->ReadModel("objects\\worm1.mod"); pModFile->CreateEngineObject(rank); m_object->SetPosition(1, Math::Vector(px, 0.0f, 0.0f)); px -= 1.0f; // Creates the body. for ( i=0 ; iCreateObject(); m_engine->SetObjectType(rank, TYPEDESCENDANT); m_object->SetObjectRank(2+i, rank); m_object->SetObjectParent(2+i, 0); pModFile->ReadModel("objects\\worm2.mod"); pModFile->CreateEngineObject(rank); m_object->SetPosition(2+i, Math::Vector(px, 0.0f, 0.0f)); px -= 1.0f; } // Creates the tail. rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, TYPEDESCENDANT); m_object->SetObjectRank(2+WORM_PART, rank); m_object->SetObjectParent(2+WORM_PART, 0); pModFile->ReadModel("objects\\worm3.mod"); pModFile->CreateEngineObject(rank); m_object->SetPosition(2+WORM_PART, Math::Vector(px, 0.0f, 0.0f)); m_object->CreateShadowCircle(0.0f, 1.0f, D3DSHADOWWORM); CreatePhysics(); m_object->SetFloorHeight(0.0f); pos = m_object->RetPosition(0); m_object->SetPosition(0, pos); // to display the shadows immediately m_engine->LoadAllTexture(); delete pModFile; return true; } // Creates the physics of the object. void CMotionWorm::CreatePhysics() { Character* character; m_physics->SetType(TYPE_ROLLING); character = m_object->RetCharacter(); character->wheelFront = 10.0f; character->wheelBack = 10.0f; character->wheelLeft = 2.0f; character->wheelRight = 2.0f; character->height = -0.2f; m_physics->SetLinMotionX(MO_ADVSPEED, 3.0f); m_physics->SetLinMotionX(MO_RECSPEED, 3.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, 5.0f); m_physics->SetLinMotionZ(MO_TERFORCE, 5.0f); m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f); m_physics->SetCirMotionY(MO_ADVSPEED, 0.2f*Math::PI); m_physics->SetCirMotionY(MO_RECSPEED, 0.2f*Math::PI); m_physics->SetCirMotionY(MO_ADVACCEL, 10.0f); m_physics->SetCirMotionY(MO_RECACCEL, 10.0f); m_physics->SetCirMotionY(MO_STOACCEL, 20.0f); } // Specifies a special parameter. bool CMotionWorm::SetParam(int rank, float value) { if ( rank == 0 ) { m_timeDown = value; return true; } if ( rank == 1 ) { m_timeUp = value; return true; } return false; } float CMotionWorm::RetParam(int rank) { if ( rank == 0 ) return m_timeDown; if ( rank == 1 ) return m_timeUp; return 0.0f; } // Management of an event. bool CMotionWorm::EventProcess(const Event &event) { CMotion::EventProcess(event); if ( event.event == EVENT_FRAME ) { return EventFrame(event); } if ( event.event == EVENT_KEYDOWN ) { } return true; } // Management of an event. bool CMotionWorm::EventFrame(const Event &event) { Math::Matrix* mat; Math::Vector pos, p, angle, speed; Math::Point center, pp, dim; float height[WORM_PART+2]; float floor, a, s, px, curve, phase, h, zoom, radius; int i, under; if ( m_engine->RetPause() ) return true; s = m_physics->RetLinMotionX(MO_MOTSPEED)/m_physics->RetLinMotionX(MO_ADVSPEED); a = m_physics->RetCirMotionY(MO_MOTSPEED)/m_physics->RetCirMotionY(MO_ADVSPEED); if ( s == 0.0f && a != 0.0f ) s = a; m_armLinSpeed += (s-m_armLinSpeed)*event.rTime*3.0f; m_armCirSpeed += (a-m_armCirSpeed)*event.rTime*1.5f; m_armTimeAbs += event.rTime; m_armTimeMarch += event.rTime*m_armLinSpeed; under = 0; // no piece under the ground for ( i=0 ; iRetBurn() ) // is burning? { h = 0.0f; // remains on earth } h += 0.3f; height[i] = h; } m_object->SetVisible(under!=WORM_PART+2); if ( !m_engine->IsVisiblePoint(m_object->RetPosition(0)) ) return true; pos = m_object->RetPosition(0); floor = m_terrain->RetFloorLevel(pos, true); mat = m_object->RetWorldMatrix(0); px = 1.0f+WORM_PART/2; for ( i=0 ; iSetObjectShadowRadius(m_object->RetObjectRank(0), radius); pos.x = px+ sinf(m_armTimeMarch*4.0f+0.5f*i)*0.6f; pos.y = height[i]+sinf(m_armTimeMarch*4.0f+0.5f*i)*0.2f*m_armLinSpeed; pos.y += sinf(m_armTimeAbs *1.3f+0.2f*i)*0.1f; pos.z = sinf(m_armTimeAbs *2.0f+0.7f*i)*0.2f; curve = ((float)i-(WORM_PART+2)/2)*m_armCirSpeed*0.1f; center.x = 0.0f; center.y = 0.0f; pp.x = pos.x; pp.y = pos.z; pp = Math::RotatePoint(center, curve, pp); pos.x = pp.x; pos.z = pp.y; p = Transform(*mat, pos); pos.y += m_terrain->RetFloorLevel(p, true)-floor; m_object->SetPosition(i+1, pos); zoom = Math::Mod(m_armTimeAbs*0.5f+100.0f-i*0.1f, 2.0f); if ( zoom > 1.0f ) zoom = 2.0f-zoom; zoom *= 1.6f; if ( zoom < 1.0f ) zoom = 1.0f; m_object->SetZoomY(i+1, 0.2f+zoom*0.8f); m_object->SetZoomZ(i+1, zoom); if ( height[i] >= -1.0f && height[i] < -0.2f && m_lastParticule+m_engine->ParticuleAdapt(0.2f) <= m_armTimeMarch ) { m_lastParticule = m_armTimeMarch; pos = p; pos.y += -height[i]; pos.x += (Math::Rand()-0.5f)*4.0f; pos.z += (Math::Rand()-0.5f)*4.0f; speed = Math::Vector(0.0f, 0.0f, 0.0f); dim.x = Math::Rand()*2.0f+1.5f; dim.y = dim.x; m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f); } px -= 1.0f; } for ( i=0 ; iRetPosition(i+2); pos -= m_object->RetPosition(i+1); angle.z = -Math::RotateAngle(Math::Point(pos.x, pos.z).Length(), pos.y); angle.y = Math::PI-Math::RotateAngle(pos.x, pos.z); angle.x = 0.0f; m_object->SetAngle(i+1, angle); if ( i == WORM_PART ) { m_object->SetAngle(i+2, angle); } } return true; }