/* -*-c++-*- * Delta3D Open Source Game and Simulation Engine * Copyright (C) 2006, Alion Science and Technology, BMH Operation * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * William E. Johnson II */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using dtCore::RefPtr; const std::string InputComponent::NAME = "InputComponent"; InputComponent::InputComponent(const std::string& name) : dtGame::BaseInputComponent(name) , mCurrentState(&GameState::STATE_UNKNOWN) , mPlayer(NULL) , mMotionModel(NULL) , mBellSound(NULL) , mDebriefSound(NULL) , mWalkSound(NULL) , mRunSound(NULL) , mCrouchSound(NULL) , mCurrentIntersectedItem(NULL) , mRadius(0.1f) , mTheta(0.10f) , mK(0.40f) , mTasksSetup(false) { } InputComponent::~InputComponent() { } void InputComponent::ProcessMessage(const dtGame::Message& message) { if (message.GetMessageType() == MessageType::GAME_STATE_CHANGED) { mCurrentState = &(static_cast(message)).GetNewState(); if (*mCurrentState == GameState::STATE_MENU) { OnMenu(); } else if (*mCurrentState == GameState::STATE_INTRO) { GetGameManager()->ChangeMap("IntroMap"); } else if (*mCurrentState == GameState::STATE_RUNNING) { GetGameManager()->ChangeMap("GameMap"); } else if (*mCurrentState == GameState::STATE_DEBRIEF) { OnDebrief(); } else { LOG_ERROR("Received a state changed message of: " + mCurrentState->GetName()); } } else if (message.GetMessageType() == dtGame::MessageType::INFO_MAP_LOADED) { // New map was loaded, we now need to find the player actor // Also need to emancipate the camera from its soon to be // invalid parent GetGameManager()->GetApplication().GetCamera()->SetParent(NULL); mPlayer = NULL; IsActorInGameMap(mPlayer); mPlayer->AddChild(GetGameManager()->GetApplication().GetCamera()); if (*mCurrentState == GameState::STATE_INTRO) { OnIntro(); } else if (*mCurrentState == GameState::STATE_RUNNING) { OnGame(); } } else if (message.GetMessageType() == MessageType::ITEM_INTERSECTED) { if (!message.GetAboutActorId().ToString().empty()) { mCurrentIntersectedItem = dynamic_cast(GetGameManager()->FindGameActorById(message.GetAboutActorId())->GetActor()); } else { mCurrentIntersectedItem = NULL; } } else if (message.GetMessageType() == dtGame::MessageType::TICK_LOCAL) { if (*mCurrentState == GameState::STATE_RUNNING) { ProcessTasks(); } } else if (message.GetMessageType() == MessageType::HELP_WINDOW_OPENED) { mMotionModel->SetTarget(NULL); } else if (message.GetMessageType() == MessageType::HELP_WINDOW_CLOSED) { mMotionModel->SetTarget(mPlayer); } } void InputComponent::OnIntro() { if (mMotionModel != NULL) { mMotionModel->SetTarget(NULL); } // Turn off the scene light and use the light maps/shadow maps dtCore::Camera& camera = *GetGameManager()->GetApplication().GetCamera(); GetGameManager()->GetApplication().GetView()->GetOsgViewerView()->setLightingMode(osg::View::NO_LIGHT); osg::StateSet* globalState = camera.GetOSGCamera()->getOrCreateStateSet(); globalState->setMode(GL_LIGHTING, osg::StateAttribute::OFF); std::vector proxies; GetGameManager()->GetAllGameActors(proxies); FlySequenceActor* fsa = NULL; IsActorInGameMap(fsa, false); if (fsa == NULL) { LOG_ALWAYS("Failed to find the fly sequence actor in the intro map. Skipping intro"); SendGameStateChangedMessage(GameState::STATE_INTRO, GameState::STATE_RUNNING); } fsa->SetPlayerActor(*mPlayer); fsa->StartFlying(); } void InputComponent::OnGame() { GetGameManager()->GetApplication().GetMouse()->SetPosition(0.f, 0.f); GameLevelActor* gla = NULL; IsActorInGameMap(gla); gla->SetCollisionMesh(); dtCore::Transform xform; mPlayer->GetTransform(xform); if (!mMotionModel.valid()) { osg::Vec3 pos; xform.GetTranslation(pos); mMotionModel = new dtCore::CollisionMotionModel(pos.z(), mRadius, mK, mTheta, &GetGameManager()->GetScene(), GetGameManager()->GetApplication().GetKeyboard(), GetGameManager()->GetApplication().GetMouse()); mMotionModel->SetUseMouseButtons(false); mMotionModel->SetCanJump(false); } mMotionModel->SetTarget(mPlayer); // Turn off the scene light and use the light maps/shadow maps dtCore::Camera& camera = *GetGameManager()->GetApplication().GetCamera(); GetGameManager()->GetApplication().GetView()->GetOsgViewerView()->setLightingMode(osg::View::NO_LIGHT); osg::StateSet* globalState = camera.GetOSGCamera()->getOrCreateStateSet(); globalState->setMode(GL_LIGHTING, osg::StateAttribute::OFF); SetupTasks(); if (mBellSound == NULL) { mBellSound = dtAudio::AudioManager::GetInstance().NewSound(); } mBellSound->LoadFile("Sounds/bellAndAnnouncement.wav"); mBellSound->Play(); if (mWalkSound == NULL) { mWalkSound = dtAudio::AudioManager::GetInstance().NewSound(); } mWalkSound->LoadFile("Sounds/walk.wav"); if (mRunSound == NULL) { mRunSound = dtAudio::AudioManager::GetInstance().NewSound(); } mRunSound->LoadFile("Sounds/running.wav"); if (mCrouchSound == NULL) { mCrouchSound = dtAudio::AudioManager::GetInstance().NewSound(); } mCrouchSound->LoadFile("Sounds/walkingCrouched.wav"); } void InputComponent::OnDebrief() { StopSounds(); if (mMotionModel != NULL) { mMotionModel->SetTarget(NULL); } if (mDebriefSound == NULL) { mDebriefSound = dtAudio::AudioManager::GetInstance().NewSound(); } mDebriefSound->LoadFile("Sounds/anchorsAweigh.wav"); mDebriefSound->Play(); } void InputComponent::OnMenu() { StopSounds(); if (mMotionModel != NULL) { mMotionModel->SetTarget(NULL); } } bool InputComponent::HandleKeyPressed(const dtCore::Keyboard* keyboard, int key) { bool handled = true; bool isGameRunning = (*mCurrentState == GameState::STATE_RUNNING); switch (key) { case 'w': case 'a': case 's': case 'd': { if (isGameRunning) { // We are crouched if (mPlayer->IsCrouched()) { // Get the crouched height of the player and update the motion model dtCore::Transform xform; mPlayer->GetTransform(xform); mMotionModel->SetMaximumWalkSpeed(0.5f); osg::Vec3 pos; xform.GetTranslation(pos); UpdateCollider(pos.z()); mCrouchSound->Play(); } else { dtABC::Application& app = GetGameManager()->GetApplication(); // Run if (app.GetKeyboard()->GetKeyState(osgGA::GUIEventAdapter::KEY_Shift_L)) { mMotionModel->SetMaximumWalkSpeed(6.0f); mRunSound->Play(); } // Walk else { dtCore::Transform xform; mPlayer->GetTransform(xform); mMotionModel->SetMaximumWalkSpeed(2.0f); osg::Vec3 pos; xform.GetTranslation(pos); UpdateCollider(pos.z()); mWalkSound->Play(); } } } } break; case 'f': { if (isGameRunning) { if (mCurrentIntersectedItem != NULL) { // If it is collectable, pick it up // Else, activate it if (mCurrentIntersectedItem->IsCollectable()) { mPlayer->AddItemToInventory(*mCurrentIntersectedItem); } else { // Special case. The hatch actor can be opened or closed if (dynamic_cast(mCurrentIntersectedItem) != NULL) { mCurrentIntersectedItem->Activate(!mCurrentIntersectedItem->IsActivated()); } else { mCurrentIntersectedItem->Activate(true); } } } } } break; case 'm': { if (isGameRunning) { SendGameStateChangedMessage(*mCurrentState, GameState::STATE_DEBRIEF); } } break; /*case 'c': { if (isGameRunning) { mPlayer->SetIsCrouched(!mPlayer->IsCrouched()); } } break;*/ case '[': { if (isGameRunning) { mPlayer->UpdateSelectedItem(true); } } break; case ']': { if (isGameRunning) { mPlayer->UpdateSelectedItem(false); } } break; case '8': { dtCore::Transform playerXform; mPlayer->GetTransform(playerXform); osg::Vec3 pos; playerXform.GetTranslation(pos); std::cout << "Player pos is: " << pos << '\n'; } break; case '9': { dtCore::Transform playerXform; mPlayer->GetTransform(playerXform); osg::Vec3 hpr; playerXform.GetRotation(hpr); std::cout << "Player rotation is: " << hpr << '\n'; } break; case 'n': { if (*mCurrentState == GameState::STATE_INTRO) { SendGameStateChangedMessage(GameState::STATE_INTRO, GameState::STATE_RUNNING); } else { handled = false; } } break; case osgGA::GUIEventAdapter::KEY_F1: { if (isGameRunning) { RefPtr msg = GetGameManager()->GetMessageFactory().CreateMessage(MessageType::HELP_WINDOW_OPENED); GetGameManager()->SendMessage(*msg); } } break; case osgGA::GUIEventAdapter::KEY_Escape: { if (isGameRunning) { SendGameStateChangedMessage(GameState::STATE_RUNNING, GameState::STATE_MENU); } else { handled = false; } } break; default: { handled = false; } break; } return handled; } bool InputComponent::HandleKeyReleased(const dtCore::Keyboard* keyboard, int key) { bool handled = true; switch (key) { case 'w': case 'a': case 's': case 'd': { if (*mCurrentState == GameState::STATE_RUNNING) { if (mCrouchSound != NULL && mCrouchSound->IsPlaying()) { mCrouchSound->Stop(); } if (mWalkSound != NULL && mWalkSound->IsPlaying()) { mWalkSound->Stop(); } if (mRunSound != NULL && mRunSound->IsPlaying()) { mRunSound->Stop(); } } default: handled = false; break; } break; } return handled; } bool InputComponent::HandleButtonPressed(const dtCore::Mouse* mouse, dtCore::Mouse::MouseButton button) { bool handled = true; switch (button) { case dtCore::Mouse::LeftButton: { if (*mCurrentState == GameState::STATE_RUNNING) { if (mPlayer->GetCurrentItem() != NULL) { // Unlike the other game items, the fire hose only stays activated // while the mouse key is down. The other items stay activated until // the mouse is clicked again. if (dynamic_cast(mPlayer->GetCurrentItem()) != NULL) { mPlayer->UseSelectedItem(true); } else { mPlayer->UseSelectedItem(!mPlayer->GetCurrentItem()->IsActivated()); } } } } break; default: handled = false; break; } return handled; } bool InputComponent::HandleButtonReleased(const dtCore::Mouse* mouse, dtCore::Mouse::MouseButton button) { bool handled = true; switch (button) { case dtCore::Mouse::LeftButton: { if (*mCurrentState == GameState::STATE_RUNNING) { // Unlike the other game items, the fire hose only stays activated // while the mouse key is down. The other items stay activated until // the mouse is clicked again. if (mPlayer->GetCurrentItem() != NULL) { if (dynamic_cast(mPlayer->GetCurrentItem()) != NULL) { mPlayer->UseSelectedItem(false); } } } } break; default: handled = false; break; } return handled; } void InputComponent::OnAddedToGM() { dtGame::BaseInputComponent::OnAddedToGM(); } void InputComponent::UpdateCollider(float newHeight) { //mMotionModel->GetFPSCollider().SetDimensions(newHeight, mRadius, mK, mTheta); } void InputComponent::SendGameStateChangedMessage(GameState& oldState, GameState& newState) { RefPtr msg = GetGameManager()->GetMessageFactory().CreateMessage(MessageType::GAME_STATE_CHANGED); GameStateChangedMessage& gscm = static_cast(*msg); gscm.SetOldState(oldState); gscm.SetNewState(newState); LOG_ALWAYS("Changing game state to: " + newState.GetName()); GetGameManager()->SendMessage(gscm); } void InputComponent::StopSounds() { if (mBellSound != NULL && mBellSound->IsPlaying()) { mBellSound->Stop(); } if (mDebriefSound != NULL && mDebriefSound->IsPlaying()) { mDebriefSound->Stop(); } if (mWalkSound != NULL && mWalkSound->IsPlaying()) { mWalkSound->Stop(); } if (mRunSound != NULL && mRunSound->IsPlaying()) { mRunSound->Stop(); } if (mCrouchSound != NULL && mCrouchSound->IsPlaying()) { mCrouchSound->Stop(); } if (mPlayer != NULL) { mPlayer->StopAllSounds(); } } void InputComponent::SetupTasks() { dtGame::GameManager& mgr = *GetGameManager(); std::vector proxies; ///////////////////////// Mission Task ///////////////////////////////////// mgr.FindActorsByName("TaskRootMission", proxies); mMission = dynamic_cast(proxies[0]); proxies.clear(); mTasksSetup = true; } void InputComponent::ProcessTasks() { if (!mTasksSetup) { return; } // Mission completed? if (mMission->GetScore() == mMission->GetPassingScore()) { RefPtr msg = GetGameManager()->GetMessageFactory().CreateMessage(MessageType::MISSION_COMPLETE); msg->SetAboutActorId(mMission->GetId()); GetGameManager()->SendMessage(*msg); return; } // Mission failed? // Process the subtasks std::vector tasks; mMission->GetAllSubTasks(tasks); for (unsigned int i = 0; i < tasks.size(); i++) { // Ensure this subtask isn't another parent task const dtActors::TaskActorOrderedProxy* orderedTask = dynamic_cast(tasks[i]); if (orderedTask != NULL) { const dtActors::TaskActorProxy* failedTask = orderedTask->GetFailingTaskProxy(); // Failure if (failedTask != NULL) { const dtActors::TaskActorOrderedProxy* failedOrderedTask = dynamic_cast(failedTask); if (failedOrderedTask != NULL) { const dtActors::TaskActorProxy* failedChildTask = failedOrderedTask->GetFailingTaskProxy(); if (failedChildTask != NULL) { RefPtr msg = GetGameManager()->GetMessageFactory().CreateMessage(MessageType::MISSION_FAILED); msg->SetAboutActorId(failedChildTask->GetId()); GetGameManager()->SendMessage(*msg); } } else { RefPtr msg = GetGameManager()->GetMessageFactory().CreateMessage(MessageType::MISSION_FAILED); msg->SetAboutActorId(failedTask->GetId()); GetGameManager()->SendMessage(*msg); } } } } } void InputComponent::OnRemovedFromGM() { //assuming this is our cue to clean up after ourself dtAudio::AudioManager &mgr = dtAudio::AudioManager::GetInstance(); if (mBellSound != NULL) { mgr.FreeSound(mBellSound); } if (mDebriefSound != NULL) { mgr.FreeSound(mDebriefSound); } if (mWalkSound != NULL) { mgr.FreeSound(mWalkSound); } if (mRunSound != NULL) { mgr.FreeSound(mRunSound); } if (mCrouchSound != NULL) { mgr.FreeSound(mCrouchSound); } }