/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsiteс.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://gnu.org/licenses */ #include "object/motion/motiontoto.h" #include "app/app.h" #include "math/geometry.h" #include "graphics/engine/modelmanager.h" #include "graphics/engine/terrain.h" #include "graphics/engine/water.h" #include "object/robotmain.h" #include const float START_TIME = 1000.0f; // beginning of the relative time // Object's constructor. CMotionToto::CMotionToto(CObject* object) : CMotion(object) { m_time = 0.0f; m_bDisplayInfo = false; m_bQuickPos = false; m_bStartAction = false; m_speedAction = 20.0f; m_soundChannel = -1; m_clownRadius = 0.0f; m_clownDelay = 0.0f; m_clownTime = 0.0f; m_blinkTime = 0.0f; m_blinkProgress = -1.0f; m_lastMotorParticle = 0.0f; m_type = OBJECT_NULL; m_mousePos = Math::Point(0.0f, 0.0f); } // Object's destructor. CMotionToto::~CMotionToto() { } // Removes an object. void CMotionToto::DeleteObject(bool bAll) { if ( m_soundChannel != -1 ) { m_sound->Stop(m_soundChannel); m_soundChannel = -1; } } // Creates a vehicle traveling any lands on the ground. bool CMotionToto::Create(Math::Vector pos, float angle, ObjectType type, float power) { Gfx::CModelManager* modelManager = Gfx::CModelManager::GetInstancePointer(); int rank; m_object->SetType(type); // Creates the head. rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_VEHICLE); // this is a moving object m_object->SetObjectRank(0, rank); modelManager->AddModelReference("toto1.mod", false, rank); m_object->SetPosition(0, pos); m_object->SetAngleY(0, angle); // Creates mouth. rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); m_object->SetObjectRank(1, rank); m_object->SetObjectParent(1, 0); modelManager->AddModelReference("toto2.mod", false, rank); m_object->SetPosition(1, Math::Vector(1.00f, 0.17f, 0.00f)); // Creates the left eye. rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); m_object->SetObjectRank(2, rank); m_object->SetObjectParent(2, 0); modelManager->AddModelReference("toto3.mod", true, rank); m_object->SetPosition(2, Math::Vector(0.85f, 1.04f, 0.25f)); m_object->SetAngleY(2, -20.0f*Math::PI/180.0f); // Creates the right eye. rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); m_object->SetObjectRank(3, rank); m_object->SetObjectParent(3, 0); modelManager->AddModelReference("toto3.mod", false, rank); m_object->SetPosition(3, Math::Vector(0.85f, 1.04f, -0.25f)); m_object->SetAngleY(3, 20.0f*Math::PI/180.0f); // Creates left antenna. rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); m_object->SetObjectRank(4, rank); m_object->SetObjectParent(4, 0); modelManager->AddModelReference("toto4.mod", false, rank); m_object->SetPosition(4, Math::Vector(0.0f, 1.9f, 0.3f)); m_object->SetAngleX(4, 30.0f*Math::PI/180.0f); rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); m_object->SetObjectRank(5, rank); m_object->SetObjectParent(5, 4); modelManager->AddModelReference("toto4.mod", false, rank); m_object->SetPosition(5, Math::Vector(0.0f, 0.67f, 0.0f)); m_object->SetAngleX(5, 30.0f*Math::PI/180.0f); rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); m_object->SetObjectRank(6, rank); m_object->SetObjectParent(6, 5); modelManager->AddModelReference("toto5.mod", false, rank); m_object->SetPosition(6, Math::Vector(0.0f, 0.70f, 0.0f)); m_object->SetAngleX(6, 30.0f*Math::PI/180.0f); // Creates right antenna. rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); m_object->SetObjectRank(7, rank); m_object->SetObjectParent(7, 0); modelManager->AddModelReference("toto4.mod", false, rank); m_object->SetPosition(7, Math::Vector(0.0f, 1.9f, -0.3f)); m_object->SetAngleX(7, -30.0f*Math::PI/180.0f); rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); m_object->SetObjectRank(8, rank); m_object->SetObjectParent(8, 7); modelManager->AddModelReference("toto4.mod", false, rank); m_object->SetPosition(8, Math::Vector(0.0f, 0.67f, 0.0f)); m_object->SetAngleX(8, -30.0f*Math::PI/180.0f); rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); m_object->SetObjectRank(9, rank); m_object->SetObjectParent(9, 8); modelManager->AddModelReference("toto5.mod", false, rank); m_object->SetPosition(9, Math::Vector(0.0f, 0.70f, 0.0f)); m_object->SetAngleX(9, -30.0f*Math::PI/180.0f); m_object->SetZoom(0, 0.5f); // is little m_object->SetFloorHeight(0.0f); pos = m_object->GetPosition(0); m_object->SetPosition(0, pos); // to display the shadows immediately m_engine->LoadAllTextures(); return true; } // Beginning of the display of informations, with foo in the left margin. void CMotionToto::StartDisplayInfo() { return; //? m_bDisplayInfo = true; m_actionType = -1; m_actionTime = 0.0f; m_progress = 0.0f; m_object->SetAngleY(0, 0.0f); m_mousePos = Math::Point(0.5f, 0.5f); } // End of the display of informations. void CMotionToto::StopDisplayInfo() { m_bDisplayInfo = false; m_bQuickPos = true; } // Getes the position of the mouse. void CMotionToto::SetMousePos(Math::Point pos) { m_mousePos = pos; } // Management of an event. bool CMotionToto::EventProcess(const Event &event) { CMotion::EventProcess(event); if ( event.type == EVENT_FRAME ) { return EventFrame(event); } return true; } // Management of an event. bool CMotionToto::EventFrame(const Event &event) { Math::Matrix* mat; Math::Vector eye, lookat, dir, perp, nPos, aPos, pos, speed; Math::Vector vibLin, vibCir, dirSpeed, aAntenna; Math::Point dim; Math::IntPoint wDim; Gfx::ParticleType type; float progress, focus, distance, shift, verti, level, zoom; float aAngle, nAngle, mAngle, angle, linSpeed, cirSpeed; int sheet, i, r; bool bHidden; if ( m_engine->GetPause() && !m_main->GetInfoLock() ) return true; if ( m_bDisplayInfo ) // "looks" mouse? { bHidden = false; } else { bHidden = false; if ( m_main->GetMovieLock() ) // current movie? { bHidden = true; } if ( !m_engine->GetTotoMode() ) { if ( !m_main->GetEditLock() ) // current edition? { bHidden = true; } } } if ( bHidden ) { nPos = m_object->GetPosition(0); m_terrain->AdjustToFloor(nPos, true); nPos.y -= 100.0f; // hidden under the ground! m_object->SetPosition(0, nPos); return true; } m_time += event.rTime; m_blinkTime -= event.rTime; progress = 0.0f; if ( m_actionType != -1 ) // current action? { if ( m_progress < 0.15f ) { progress = m_progress/0.15f; } else if ( m_progress < 0.85f ) { progress = 1.0f; } else { progress = (1.0f-m_progress)/0.15f; } } if ( m_progress >= 1.0f ) { m_actionType = -1; // action ended m_actionTime = 0.0f; m_progress = 0.0f; m_clownTime = 0.0f; m_clownDelay = 0.0f; } focus = m_engine->GetFocus(); eye = m_engine->GetEyePt(); lookat = m_engine->GetLookatPt(); vibLin = Math::Vector(0.0f, 0.0f, 0.0f); vibCir = Math::Vector(0.0f, 0.0f, 0.0f); aAntenna = Math::Vector(0.0f, 0.0f, 0.0f); aAntenna.x += 30.0f*Math::PI/180.0f; // Calculates the new position. if ( m_bDisplayInfo ) { wDim = m_engine->GetWindowSize(); nPos.x = -4.0f*(static_cast< float >(wDim.x)/static_cast< float >(wDim.y))/(640.0f/480.0f); nPos.y = -0.5f; nPos.z = 7.0f; // in the left margin linSpeed = 0.0f; } else { #if 0 distance = 30.0f-progress*24.5f; // remoteness shift = 18.0f-progress*15.4f; // shift is left verti = 10.0f-progress* 9.6f; // shift at the top #else distance = 30.0f-progress*18.0f; // remoteness shift = 18.0f-progress*11.0f; // shift is left verti = 10.0f-progress* 8.0f; // shift at the top #endif if ( m_actionType == -1 && (m_type == OBJECT_HUMAN || m_type == OBJECT_TECH || m_type == OBJECT_MOBILEwa || m_type == OBJECT_MOBILEta || m_type == OBJECT_MOBILEfa || m_type == OBJECT_MOBILEia || m_type == OBJECT_MOBILEwc || m_type == OBJECT_MOBILEtc || m_type == OBJECT_MOBILEfc || m_type == OBJECT_MOBILEic || m_type == OBJECT_MOBILEwi || m_type == OBJECT_MOBILEti || m_type == OBJECT_MOBILEfi || m_type == OBJECT_MOBILEii || m_type == OBJECT_MOBILEws || m_type == OBJECT_MOBILEts || m_type == OBJECT_MOBILEfs || m_type == OBJECT_MOBILEis || m_type == OBJECT_MOBILErt || m_type == OBJECT_MOBILErc || m_type == OBJECT_MOBILErr || m_type == OBJECT_MOBILErs || m_type == OBJECT_MOBILEsa || m_type == OBJECT_MOBILEwt || m_type == OBJECT_MOBILEtt || m_type == OBJECT_MOBILEft || m_type == OBJECT_MOBILEit || m_type == OBJECT_MOBILEdr ) ) // vehicle? { m_clownTime += event.rTime; if ( m_clownTime >= m_clownDelay ) { if ( rand()%10 < 2 ) { m_clownRadius = 2.0f+Math::Rand()*10.0f; //? m_clownDelay = m_clownRadius/(2.0f+Math::Rand()*2.0f); m_clownDelay = 1.5f+Math::Rand()*1.0f; } else { m_clownRadius = 0.0f; m_clownDelay = 2.0f+Math::Rand()*2.0f; } pos = m_object->GetPosition(0); if ( pos.y < m_water->GetLevel() ) // underwater? { m_clownRadius /= 1.5f; m_clownDelay *= 2.0f; } m_clownTime = 0.0f; } else { distance -= m_clownRadius*sinf(m_clownTime*Math::PI*2.0f/m_clownDelay); shift -= m_clownRadius-m_clownRadius*cosf(m_clownTime*Math::PI*2.0f/m_clownDelay); } verti += (18.0f-shift)*0.2f; } distance /= focus; //? shift *= focus; verti /= focus; dir = Normalize(lookat-eye); nPos = eye + dir*distance; perp.x = -dir.z; perp.y = dir.y; perp.z = dir.x; nPos = nPos + perp*shift; nPos.y += verti; if ( m_bQuickPos ) // immediately in place? { m_bQuickPos = false; linSpeed = 0.0f; } else { aPos = m_object->GetPosition(0); if ( m_actionType == -1 ) { level = 4.0f; } else { if ( m_bStartAction ) { m_bStartAction = false; m_speedAction = Math::Distance(nPos, aPos)/15.0f; if ( m_speedAction < 20.0f ) m_speedAction = 20.0f; } level = m_speedAction; } if ( level > 1.0f/event.rTime ) level = 1.0f/event.rTime; nPos = aPos + (nPos-aPos)*event.rTime*level; // progression aPos -> nPos linSpeed = Math::DistanceProjected(nPos, aPos)/event.rTime; dirSpeed = (nPos-aPos)/event.rTime; nPos.y -= linSpeed*0.015f*(1.0f-progress); // at ground level if moving fast } } // Calculate the new angle. nAngle = Math::NormAngle(Math::RotateAngle(eye.x-lookat.x, lookat.z-eye.z)-0.9f); if ( linSpeed == 0.0f || m_actionType != -1 ) { mAngle = nAngle; } else { mAngle = Math::NormAngle(Math::RotateAngle(dirSpeed.x, -dirSpeed.z)); } level = Math::Min(linSpeed*0.1f, 1.0f); nAngle = nAngle*(1.0f-level) + mAngle*level; aAngle = Math::NormAngle(m_object->GetAngleY(0)); if ( nAngle < aAngle ) { if ( nAngle+Math::PI*2.0f-aAngle < aAngle-nAngle ) nAngle += Math::PI*2.0f; } else { if ( aAngle+Math::PI*2.0f-nAngle < nAngle-aAngle ) aAngle += Math::PI*2.0f; } nAngle = aAngle + (nAngle-aAngle)*event.rTime*4.0f; // Leans quotes if running. cirSpeed = (aAngle-nAngle)/event.rTime; angle = cirSpeed*0.3f*(1.0f-progress); if ( angle > 0.7f ) angle = 0.7f; if ( angle < -0.7f ) angle = -0.7f; vibCir.x += angle*1.5f; aAntenna.x += fabs(angle)*0.8f; // deviates // Leans forward so quickly advance. angle = linSpeed*0.10f*(1.0f-progress); if ( angle > 1.0f ) angle = 1.0f; vibCir.z -= angle/2.0f; // leans forward aAntenna.z -= angle; // leans forward // Calculates the residual motion. #if 1 vibLin.y += (sinf(m_time*2.00f)*0.5f+ sinf(m_time*2.11f)*0.2f)*(1.0f-progress); vibCir.z += sinf(m_time*Math::PI* 2.01f)*(Math::PI/ 75.0f)+ sinf(m_time*Math::PI* 2.51f)*(Math::PI/100.0f)+ sinf(m_time*Math::PI*19.01f)*(Math::PI/200.0f); vibCir.x += sinf(m_time*Math::PI* 2.03f)*(Math::PI/ 75.0f)+ sinf(m_time*Math::PI* 2.52f)*(Math::PI/100.0f)+ sinf(m_time*Math::PI*19.53f)*(Math::PI/200.0f); vibCir.y += (sinf(m_time*Math::PI* 1.07f)*(Math::PI/ 10.0f)+ sinf(m_time*Math::PI* 1.19f)*(Math::PI/ 17.0f)+ sinf(m_time*Math::PI* 1.57f)*(Math::PI/ 31.0f))*(1.0f-progress); #endif // Calculates the animations in action. if ( m_actionType == MT_ERROR ) // no-no? { vibCir.y += progress*sinf(m_progress*Math::PI*11.0f)*1.0f; vibCir.z -= progress*0.5f; // leans forward aAntenna.x -= progress*0.4f; // narrows aAntenna.z += progress*1.0f; // leaning back } if ( m_actionType == MT_WARNING ) // warning? { vibCir.x += progress*sinf(m_progress*Math::PI*17.0f)*0.5f; aAntenna.x += progress*sinf(m_progress*Math::PI*17.0f)*0.5f; // deviates aAntenna.z += progress*cosf(m_progress*Math::PI*17.0f)*0.5f; // turns } if ( m_actionType == MT_INFO ) // yes-yes? { vibCir.z += progress*sinf(m_progress*Math::PI*19.0f)*0.7f; aAntenna.x -= progress*0.2f; // narrows aAntenna.z -= progress*cosf(m_progress*Math::PI*19.0f)*0.9f; // turns } if ( m_actionType == MT_MESSAGE ) // message? { vibCir.x += progress*sinf(m_progress*Math::PI*15.0f)*0.3f; vibCir.z += progress*cosf(m_progress*Math::PI*15.0f)*0.3f; aAntenna.x -= progress*0.4f; // narrows aAntenna.z -= progress*cosf(m_progress*Math::PI*19.0f)*0.8f; } // Initialize the object. if ( m_bDisplayInfo ) // "looks" mouse? { if ( m_mousePos.x < 0.15f ) { progress = 1.0f-m_mousePos.x/0.15f; vibCir.y += progress*Math::PI/2.0f; } else { progress = (m_mousePos.x-0.15f)/0.85f; vibCir.y -= progress*Math::PI/3.0f; } angle = Math::RotateAngle(m_mousePos.x-0.1f, m_mousePos.y-0.5f-vibLin.y*0.2f); if ( angle < Math::PI ) { if ( angle > Math::PI*0.5f ) angle = Math::PI-angle; if ( angle > Math::PI*0.3f ) angle = Math::PI*0.3f; vibCir.z += angle; } else { angle = Math::PI*2.0f-angle; if ( angle > Math::PI*0.5f ) angle = Math::PI-angle; if ( angle > Math::PI*0.3f ) angle = Math::PI*0.3f; vibCir.z -= angle; } } else { nPos.y += vibLin.y; level = m_terrain->GetFloorLevel(nPos); if ( nPos.y < level+2.0f ) { nPos.y = level+2.0f; // just above the ground } nPos.y -= vibLin.y; } m_object->SetPosition(0, nPos); m_object->SetAngleY(0, nAngle); SetLinVibration(vibLin); SetCirVibration(vibCir); // Calculates the residual movement of the antennas. pos = aAntenna*0.40f; pos.x += sinf(m_time*Math::PI*2.07f)*(Math::PI/50.0f)+ sinf(m_time*Math::PI*2.59f)*(Math::PI/70.0f)+ sinf(m_time*Math::PI*2.67f)*(Math::PI/90.0f); pos.y += sinf(m_time*Math::PI*2.22f)*(Math::PI/50.0f)+ sinf(m_time*Math::PI*2.36f)*(Math::PI/70.0f)+ sinf(m_time*Math::PI*3.01f)*(Math::PI/90.0f); pos.z += sinf(m_time*Math::PI*2.11f)*(Math::PI/50.0f)+ sinf(m_time*Math::PI*2.83f)*(Math::PI/70.0f)+ sinf(m_time*Math::PI*3.09f)*(Math::PI/90.0f); m_object->SetAngle(4, pos); // left antenna m_object->SetAngle(5, pos); // left antenna m_object->SetAngle(6, pos); // left antenna pos = aAntenna*0.40f; pos.x = -pos.x; pos.x += sinf(m_time*Math::PI*2.33f)*(Math::PI/50.0f)+ sinf(m_time*Math::PI*2.19f)*(Math::PI/70.0f)+ sinf(m_time*Math::PI*2.07f)*(Math::PI/90.0f); pos.y += sinf(m_time*Math::PI*2.44f)*(Math::PI/50.0f)+ sinf(m_time*Math::PI*2.77f)*(Math::PI/70.0f)+ sinf(m_time*Math::PI*3.22f)*(Math::PI/90.0f); pos.z += sinf(m_time*Math::PI*2.05f)*(Math::PI/50.0f)+ sinf(m_time*Math::PI*2.38f)*(Math::PI/70.0f)+ sinf(m_time*Math::PI*2.79f)*(Math::PI/90.0f); m_object->SetAngle(7, pos); // right antenna m_object->SetAngle(8, pos); // right antenna m_object->SetAngle(9, pos); // right antenna // Movement of the mouth. if ( m_actionType == MT_ERROR ) // no-no? { m_object->SetAngleX(1, 0.0f); m_object->SetAngleZ(1, 0.2f+sinf(m_time*10.0f)*0.2f); m_object->SetZoomY(1, 2.0f+sinf(m_time*10.0f)); m_object->SetZoomZ(1, 1.0f); } else if ( m_actionType == MT_WARNING ) // warning? { m_object->SetAngleX(1, 15.0f*Math::PI/180.0f); m_object->SetAngleZ(1, 0.0f); m_object->SetZoomY(1, 1.0f); m_object->SetZoomZ(1, 1.0f); } else if ( m_actionType == MT_INFO ) // yes-yes? { m_object->SetAngleX(1, 0.0f); m_object->SetAngleZ(1, 0.0f); m_object->SetZoomY(1, 1.0f); m_object->SetZoomZ(1, 0.7f+sinf(m_time*10.0f)*0.3f); } else if ( m_actionType == MT_MESSAGE ) // message? { m_object->SetAngleX(1, 0.0f); m_object->SetAngleZ(1, 0.0f); m_object->SetZoomY(1, 1.0f); m_object->SetZoomZ(1, 0.8f+sinf(m_time*7.0f)*0.2f); } else { m_object->SetAngleX(1, 0.0f); m_object->SetAngleZ(1, 0.0f); m_object->SetZoomY(1, 1.0f); m_object->SetZoomZ(1, 1.0f); } // Eye blinking management. if ( m_blinkTime <= 0.0f && m_blinkProgress == -1.0f ) { m_blinkProgress = 0.0f; } if ( m_blinkProgress >= 0.0f ) { m_blinkProgress += event.rTime*3.2f; if ( m_blinkProgress < 1.0f ) { if ( m_blinkProgress < 0.5f ) zoom = m_blinkProgress/0.5f; else zoom = 2.0f-m_blinkProgress/0.5f; m_object->SetZoomY(2, 1.0f-zoom*0.9f); m_object->SetZoomY(3, 1.0f-zoom*0.9f); } else { m_blinkProgress = -1.0f; m_blinkTime = 0.1f+Math::Rand()*4.0f; m_object->SetZoomY(2, 1.0f); m_object->SetZoomY(3, 1.0f); } } if ( m_actionType == MT_ERROR ) // no-no? { m_object->SetAngleX(2, -30.0f*Math::PI/180.0f); m_object->SetAngleX(3, 30.0f*Math::PI/180.0f); } else if ( m_actionType == MT_WARNING ) // warning? { m_object->SetAngleX(2, -15.0f*Math::PI/180.0f); m_object->SetAngleX(3, 15.0f*Math::PI/180.0f); } else if ( m_actionType == MT_INFO ) // yes-yes? { m_object->SetAngleX(2, 40.0f*Math::PI/180.0f); m_object->SetAngleX(3, -40.0f*Math::PI/180.0f); } else if ( m_actionType == MT_MESSAGE ) // message? { m_object->SetAngleX(2, 20.0f*Math::PI/180.0f); m_object->SetAngleX(3, -20.0f*Math::PI/180.0f); } else { m_object->SetAngleX(2, 0.0f); m_object->SetAngleX(3, 0.0f); } mat = m_object->GetWorldMatrix(0); // must be done every time! // Generates particles. if ( m_time-m_lastMotorParticle >= m_engine->ParticleAdapt(0.05f) ) { m_lastMotorParticle = m_time; if ( m_bDisplayInfo ) sheet = Gfx::SH_FRONT; else sheet = Gfx::SH_WORLD; pos = m_object->GetPosition(0); if ( !m_bDisplayInfo && pos.y < m_water->GetLevel() ) // underwater? { float t = Math::Mod(m_time, 3.5f); if ( t >= 2.2f || ( t >= 1.2f && t <= 1.4f ) ) // breathe? { pos = Math::Vector(1.0f, 0.2f, 0.0f); pos.z += (Math::Rand()-0.5f)*0.5f; speed = pos; speed.y += 5.0f+Math::Rand()*5.0f; speed.x += Math::Rand()*2.0f; speed.z += (Math::Rand()-0.5f)*2.0f; pos = Transform(*mat, pos); speed = Transform(*mat, speed)-pos; dim.x = 0.12f; dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIBUBBLE, 3.0f, 0.0f, 0.0f); } } else // out of water? { pos = Math::Vector(0.0f, -0.5f, 0.0f); pos.z += (Math::Rand()-0.5f)*0.5f; speed = pos; speed.y -= (1.5f+Math::Rand()*1.5f) + vibLin.y; speed.x += (Math::Rand()-0.5f)*2.0f; speed.z += (Math::Rand()-0.5f)*2.0f; // mat = m_object->GetWorldMatrix(0); pos = Transform(*mat, pos); speed = Transform(*mat, speed)-pos; dim.x = (Math::Rand()*0.4f+0.4f)*(1.0f+Math::Min(linSpeed*0.1f, 5.0f)); dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTITOTO, 1.0f+Math::Rand()*1.0f, 0.0f, 1.0f, sheet); } if ( m_actionType != -1 && // current action? m_progress <= 0.85f ) { pos.x = (Math::Rand()-0.5f)*1.0f; pos.y = (Math::Rand()-0.5f)*1.0f+3.5f; pos.z = (Math::Rand()-0.5f)*1.0f; pos = Transform(*mat, pos); speed = Math::Vector(0.0f, 0.0f, 0.0f); dim.x = (Math::Rand()*0.3f+0.3f); dim.y = dim.x; if ( m_actionType == MT_ERROR ) type = Gfx::PARTIERROR; if ( m_actionType == MT_WARNING ) type = Gfx::PARTIWARNING; if ( m_actionType == MT_INFO ) type = Gfx::PARTIINFO; if ( m_actionType == MT_MESSAGE ) type = Gfx::PARTIWARNING; m_particle->CreateParticle(pos, speed, dim, type, 0.5f+Math::Rand()*0.5f, 0.0f, 1.0f, sheet); pos.x = 0.50f+(Math::Rand()-0.5f)*0.80f; pos.y = 0.86f+(Math::Rand()-0.5f)*0.08f; pos.z = 0.00f; dim.x = (Math::Rand()*0.04f+0.04f); dim.y = dim.x/0.75f; m_particle->CreateParticle(pos, speed, dim, type, 0.5f+Math::Rand()*0.5f, 0.0f, 1.0f, Gfx::SH_INTERFACE); } //? if ( m_bDisplayInfo && m_main->GetGlint() ) if ( false ) { pos.x = (Math::Rand()-0.5f)*1.4f; pos.y = (Math::Rand()-0.5f)*1.4f+3.5f; pos.z = (Math::Rand()-0.5f)*1.4f; pos = Transform(*mat, pos); speed = Math::Vector(0.0f, 0.0f, 0.0f); dim.x = (Math::Rand()*0.5f+0.5f); dim.y = dim.x; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIERROR, 0.5f+Math::Rand()*0.5f, 0.0f, 1.0f, sheet); for ( i=0 ; i<10 ; i++ ) { pos.x = 0.60f+(Math::Rand()-0.5f)*0.76f; pos.y = 0.47f+(Math::Rand()-0.5f)*0.90f; pos.z = 0.00f; r = rand()%4; if ( r == 0 ) pos.x = 0.21f; // the left edge else if ( r == 1 ) pos.x = 0.98f; // the right edge else if ( r == 2 ) pos.y = 0.02f; // on the lower edge else pos.y = 0.92f; // on the upper edge dim.x = (Math::Rand()*0.02f+0.02f); dim.y = dim.x/0.75f; m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIERROR, 0.5f+Math::Rand()*0.5f, 0.0f, 1.0f, Gfx::SH_INTERFACE); } } } // Move the sound. if ( m_soundChannel != -1 ) { if ( !m_sound->Position(m_soundChannel, m_object->GetPosition(0)) ) { m_soundChannel = -1; } } return true; } // Starts an action. Error CMotionToto::SetAction(int action, float time) { Sound sound; CMotion::SetAction(action, time); m_bStartAction = true; sound = SOUND_CLICK; if ( action == MT_ERROR ) sound = SOUND_ERROR; if ( action == MT_WARNING ) sound = SOUND_WARNING; if ( action == MT_INFO ) sound = SOUND_INFO; if ( action == MT_MESSAGE ) sound = SOUND_MESSAGE; if ( sound != SOUND_CLICK ) { m_soundChannel = m_sound->Play(sound, m_object->GetPosition(0)); } return ERR_OK; } // Specifies the type of the object is attached to toto. void CMotionToto::SetLinkType(ObjectType type) { m_type = type; }