| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** 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/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // LookAtXlat.cpp
- // Translate raw input events into camera movement commands
- // Author: Michael S. Booth, April 2001
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "windows.h"
- #include "Common/GameType.h"
- #include "Common/MessageStream.h"
- #include "Common/Player.h"
- #include "Common/PlayerList.h"
- #include "Common/Recorder.h"
- #include "Common/StatsCollector.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/PartitionManager.h"
- #include "GameClient/Display.h"
- #include "GameClient/GameText.h"
- #include "GameClient/Mouse.h"
- #include "GameClient/Shell.h"
- #include "GameClient/GameClient.h"
- #include "GameClient/KeyDefs.h"
- #include "GameClient/View.h"
- #include "GameClient/Drawable.h"
- #include "GameClient/LookAtXlat.h"
- #include "GameLogic/Module/UpdateModule.h"
- #include "GameLogic/GameLogic.h"
- #include "Common/GlobalData.h" // for camera pitch angle only
- LookAtTranslator *TheLookAtTranslator = NULL;
- static enum
- {
- DIR_UP = 0,
- DIR_DOWN,
- DIR_LEFT,
- DIR_RIGHT
- };
- static Bool scrollDir[4] = { false, false, false, false };
- Int SCROLL_AMT = 100;
- static const Int edgeScrollSize = 3;
- static Mouse::MouseCursor prevCursor = Mouse::ARROW;
- //-----------------------------------------------------------------------------
- void LookAtTranslator::setScrolling(Int x)
- {
- if (!TheInGameUI->getInputEnabled())
- return;
- prevCursor = TheMouse->getMouseCursor();
- m_isScrolling = true;
- TheInGameUI->setScrolling( TRUE );
- TheTacticalView->setMouseLock( TRUE );
- m_scrollType = x;
- if(TheStatsCollector)
- TheStatsCollector->startScrollTime();
- }
- //-----------------------------------------------------------------------------
- void LookAtTranslator::stopScrolling( void )
- {
- m_isScrolling = false;
- TheInGameUI->setScrolling( FALSE );
- TheTacticalView->setMouseLock( FALSE );
- TheMouse->setCursor(prevCursor);
- m_scrollType = SCROLL_NONE;
-
- // if we have a stats collectore increment the stats
- if(TheStatsCollector)
- TheStatsCollector->endScrollTime();
- }
- //-----------------------------------------------------------------------------
- LookAtTranslator::LookAtTranslator() :
- m_isScrolling(false),
- m_isRotating(false),
- m_isPitching(false),
- m_isChangingFOV(false),
- m_timestamp(0),
- m_lastPlaneID(INVALID_DRAWABLE_ID),
- m_lastMouseMoveFrame(0),
- m_scrollType(SCROLL_NONE)
- {
- //Added By Sadullah Nader
- //Initializations misssing and needed
- m_anchor.x = m_anchor.y = 0;
- m_currentPos.x = m_currentPos.y = 0;
- m_originalAnchor.x = m_originalAnchor.y = 0;
- //
- DEBUG_ASSERTCRASH(!TheLookAtTranslator, ("Already have a LookAtTranslator - why do you need two?"));
- TheLookAtTranslator = this;
- }
- //-----------------------------------------------------------------------------
- LookAtTranslator::~LookAtTranslator()
- {
- if (TheLookAtTranslator == this)
- TheLookAtTranslator = NULL;
- }
- const ICoord2D* LookAtTranslator::getRMBScrollAnchor(void)
- {
- if (m_isScrolling && m_scrollType == SCROLL_RMB)
- {
- return &m_anchor;
- }
- return NULL;
- }
- Bool LookAtTranslator::hasMouseMovedRecently( void )
- {
- if (m_lastMouseMoveFrame > TheGameLogic->getFrame())
- m_lastMouseMoveFrame = 0; // reset for new game
- if (m_lastMouseMoveFrame + LOGICFRAMES_PER_SECOND < TheGameLogic->getFrame())
- return false;
- return true;
- }
- void LookAtTranslator::setCurrentPos( const ICoord2D& pos )
- {
- m_currentPos = pos;
- }
- //-----------------------------------------------------------------------------
- /**
- * The LookAt Translator is responsible for camera movements. It is directly responsible for
- * right mouse button scrolling, and CTRL-<F key> bookmarking. It also responds to certain
- * LOOKAT message on the message stream.
- */
- GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage *msg)
- {
- GameMessageDisposition disp = KEEP_MESSAGE;
- GameMessage::Type t = msg->getType();
- switch (t)
- {
- //-----------------------------------------------------------------------------
- case GameMessage::MSG_RAW_KEY_DOWN:
- case GameMessage::MSG_RAW_KEY_UP:
- {
- // get key and state from args
- UnsignedByte key = msg->getArgument( 0 )->integer;
- UnsignedByte state = msg->getArgument( 1 )->integer;
- Bool isPressed = !(BitTest( state, KEY_STATE_UP ));
-
- if (TheShell && TheShell->isShellActive())
- break;
- switch (key)
- {
- case KEY_UP:
- scrollDir[DIR_UP] = isPressed;
- break;
- case KEY_DOWN:
- scrollDir[DIR_DOWN] = isPressed;
- break;
- case KEY_LEFT:
- scrollDir[DIR_LEFT] = isPressed;
- break;
- case KEY_RIGHT:
- scrollDir[DIR_RIGHT] = isPressed;
- break;
- }
- if (TheInGameUI->isSelecting() || (m_isScrolling && m_scrollType != SCROLL_KEY))
- break;
- // see if we need to start/stop scrolling
- Int numDirs = 0;
- for (Int i=0; i<4; ++i)
- {
- if (scrollDir[i])
- numDirs++;
- }
- if (numDirs && !m_isScrolling)
- {
- setScrolling( SCROLL_KEY );
- }
- else if (!numDirs && m_isScrolling)
- {
- stopScrolling();
- }
- break;
- }
- //-----------------------------------------------------------------------------
- case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN:
- {
- m_lastMouseMoveFrame = TheGameLogic->getFrame();
- m_anchor = msg->getArgument( 0 )->pixel;
- m_currentPos = msg->getArgument( 0 )->pixel;
- if (!TheInGameUI->isSelecting() && !m_isScrolling)
- {
- setScrolling(SCROLL_RMB);
- }
- break;
- }
- //-----------------------------------------------------------------------------
- case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP:
- {
- m_lastMouseMoveFrame = TheGameLogic->getFrame();
- if (m_scrollType == SCROLL_RMB)
- {
- stopScrolling();
- }
- break;
- }
- //-----------------------------------------------------------------------------
- case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_DOWN:
- {
- m_lastMouseMoveFrame = TheGameLogic->getFrame();
- m_isRotating = true;
- m_anchor = msg->getArgument( 0 )->pixel;
- m_originalAnchor = msg->getArgument( 0 )->pixel;
- m_currentPos = msg->getArgument( 0 )->pixel;
- m_timestamp = TheGameClient->getFrame();
- break;
- }
- //-----------------------------------------------------------------------------
- case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_UP:
- {
- m_lastMouseMoveFrame = TheGameLogic->getFrame();
- const UnsignedInt CLICK_DURATION = 5;
- const UnsignedInt PIXEL_OFFSET = 5;
- m_isRotating = false;
- Int dx = m_currentPos.x-m_originalAnchor.x;
- if (dx<0) dx = -dx;
- Int dy = m_currentPos.y-m_originalAnchor.y;
- Bool didMove = dx>PIXEL_OFFSET || dy>PIXEL_OFFSET;
- // if middle button is "clicked", reset to "home" orientation
- if (!didMove && TheGameClient->getFrame() - m_timestamp < CLICK_DURATION)
- {
- TheTacticalView->setAngleAndPitchToDefault();
- TheTacticalView->setZoomToDefault();
- }
- break;
- }
- //-----------------------------------------------------------------------------
- case GameMessage::MSG_RAW_MOUSE_POSITION:
- {
- if (m_currentPos.x != msg->getArgument( 0 )->pixel.x || m_currentPos.y != msg->getArgument( 0 )->pixel.y)
- m_lastMouseMoveFrame = TheGameLogic->getFrame();
- m_currentPos = msg->getArgument( 0 )->pixel;
-
- UnsignedInt height = TheDisplay->getHeight();
- UnsignedInt width = TheDisplay->getWidth();
- if (TheInGameUI->getInputEnabled() == FALSE) {
- // We don't care how we're scrolling, just stop.
- if (m_isScrolling)
- stopScrolling();
- break;
- }
- if (!TheGlobalData->m_windowed)
- {
- if (m_isScrolling)
- {
- if ( m_scrollType == SCROLL_SCREENEDGE && (m_currentPos.x >= edgeScrollSize && m_currentPos.y >= edgeScrollSize && m_currentPos.y < height-edgeScrollSize && m_currentPos.x < width-edgeScrollSize) )
- {
- stopScrolling();
- }
- }
- else
- {
- if ( m_currentPos.x < edgeScrollSize || m_currentPos.y < edgeScrollSize || m_currentPos.y >= height-edgeScrollSize || m_currentPos.x >= width-edgeScrollSize )
- {
- setScrolling(SCROLL_SCREENEDGE);
- }
- }
- }
- // rotate the view
- if (m_isRotating)
- {
- const Real FACTOR = 0.01f;
- Real angle = FACTOR * (m_currentPos.x - m_anchor.x);
- TheTacticalView->setAngle( TheTacticalView->getAngle() + angle );
- m_anchor = msg->getArgument( 0 )->pixel;
- }
- // rotate the view up/down
- if (m_isPitching)
- {
- const Real FACTOR = 0.01f;
- Real angle = FACTOR * (m_currentPos.y - m_anchor.y);
- TheTacticalView->setPitch( TheTacticalView->getPitch() + angle );
- m_anchor = msg->getArgument( 0 )->pixel;
- }
- #if defined(_DEBUG) || defined(_INTERNAL)
- // adjust the field of view
- if (m_isChangingFOV)
- {
- const Real FACTOR = 0.01f;
- Real angle = FACTOR * (m_currentPos.y - m_anchor.y);
- TheTacticalView->setFieldOfView( TheTacticalView->getFieldOfView() + angle );
- m_anchor = msg->getArgument( 0 )->pixel;
- }
- #endif
- break;
- }
- //-----------------------------------------------------------------------------
- case GameMessage::MSG_RAW_MOUSE_WHEEL:
- {
- m_lastMouseMoveFrame = TheGameLogic->getFrame();
- Int spin = msg->getArgument( 1 )->integer;
- if (spin > 0)
- {
- for ( ; spin > 0; spin--)
- TheTacticalView->zoomIn();
- }
- else
- {
- for ( ;spin < 0; spin++ )
- TheTacticalView->zoomOut();
- }
- }
-
- //-----------------------------------------------------------------------------
- case GameMessage::MSG_META_OPTIONS:
- {
- // stop the scrolling
- stopScrolling();
- // let the message drop through, cause we need to process this message for
- // selection as well.
- break;
- }
- //-----------------------------------------------------------------------------
- case GameMessage::MSG_FRAME_TICK:
- {
- Coord2D offset = {0, 0};
- // If we've been forced to stop scrolling (script action?) then stop
- if (m_isScrolling && !TheInGameUI->isScrolling())
- {
- TheInGameUI->setScrollAmount(offset);
- stopScrolling();
- }
- else
- // scroll the view
- if (m_isScrolling)
- {
- switch (m_scrollType)
- {
- case SCROLL_RMB:
- {
- if (TheInGameUI->shouldMoveRMBScrollAnchor())
- {
- Int maxX = TheDisplay->getWidth()/2;
- Int maxY = TheDisplay->getHeight()/2;
- if (m_currentPos.x + maxX < m_anchor.x)
- m_anchor.x = m_currentPos.x + maxX;
- else if (m_currentPos.x - maxX > m_anchor.x)
- m_anchor.x = m_currentPos.x - maxX;
- if (m_currentPos.y + maxY < m_anchor.y)
- m_anchor.y = m_currentPos.y + maxY;
- else if (m_currentPos.y - maxY > m_anchor.y)
- m_anchor.y = m_currentPos.y - maxY;
- }
- offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * (m_currentPos.x - m_anchor.x);
- offset.y = TheGlobalData->m_verticalScrollSpeedFactor * (m_currentPos.y - m_anchor.y);
- Coord2D vec;
- vec.x = offset.x;
- vec.y = offset.y;
- vec.normalize();
- // Add in the window scroll amount as the minimum.
- offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * vec.x * sqr(TheGlobalData->m_keyboardScrollFactor);
- offset.y += TheGlobalData->m_verticalScrollSpeedFactor * vec.y * sqr(TheGlobalData->m_keyboardScrollFactor);
- }
- break;
- case SCROLL_KEY:
- {
- if (scrollDir[DIR_UP])
- {
- offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
- }
- if (scrollDir[DIR_DOWN])
- {
- offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
- }
- if (scrollDir[DIR_LEFT])
- {
- offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
- }
- if (scrollDir[DIR_RIGHT])
- {
- offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
- }
- }
- break;
- case SCROLL_SCREENEDGE:
- {
- UnsignedInt height = TheDisplay->getHeight();
- UnsignedInt width = TheDisplay->getWidth();
- if (m_currentPos.y < edgeScrollSize)
- {
- offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
- }
- if (m_currentPos.y >= height-edgeScrollSize)
- {
- offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
- }
- if (m_currentPos.x < edgeScrollSize)
- {
- offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
- }
- if (m_currentPos.x >= width-edgeScrollSize)
- {
- offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
- }
- }
- break;
- }
- TheInGameUI->setScrollAmount(offset);
- TheTacticalView->scrollBy( &offset );
- }
- else //not scrolling so reset amount
- TheInGameUI->setScrollAmount(offset);
- //if (TheGlobalData->m_saveCameraInReplay /*&& TheRecorder->getMode() != RECORDERMODETYPE_PLAYBACK *//**/&& (TheGameLogic->isInSinglePlayerGame() || TheGameLogic->isInSkirmishGame())/**/)
- //if (TheGlobalData->m_saveCameraInReplay && (TheGameLogic->isInMultiplayerGame() || TheGameLogic->isInSinglePlayerGame() || TheGameLogic->isInSkirmishGame()))
- if (TheGlobalData->m_saveCameraInReplay && (TheGameLogic->isInSinglePlayerGame() || TheGameLogic->isInSkirmishGame()))
- {
- ViewLocation currentView;
- TheTacticalView->getLocation(¤tView);
- GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_SET_REPLAY_CAMERA );
- msg->appendLocationArgument( currentView.m_pos );
- msg->appendRealArgument( currentView.m_angle );
- msg->appendRealArgument( currentView.m_pitch );
- msg->appendRealArgument( currentView.m_zoom );
- msg->appendIntegerArgument( (Int)TheMouse->getMouseCursor() );
- msg->appendPixelArgument( m_currentPos );
- }
- break;
- }
- // ------------------------------------------------------------------------
- #if defined(_DEBUG) || defined(_INTERNAL)
- case GameMessage::MSG_META_DEMO_BEGIN_ADJUST_PITCH:
- {
- DEBUG_ASSERTCRASH(!m_isPitching, ("hmm, mismatched m_isPitching"));
- m_isPitching = true;
- disp = DESTROY_MESSAGE;
- break;
- }
- #endif // #if defined(_DEBUG) || defined(_INTERNAL)
- // ------------------------------------------------------------------------
- #if defined(_DEBUG) || defined(_INTERNAL)
- case GameMessage::MSG_META_DEMO_END_ADJUST_PITCH:
- {
- DEBUG_ASSERTCRASH(m_isPitching, ("hmm, mismatched m_isPitching"));
- m_isPitching = false;
- disp = DESTROY_MESSAGE;
- break;
- }
- #endif // #if defined(_DEBUG) || defined(_INTERNAL)
- // ------------------------------------------------------------------------
- #if defined(_DEBUG) || defined(_INTERNAL)
- case GameMessage::MSG_META_DEMO_DESHROUD:
- {
- ThePartitionManager->revealMapForPlayerPermanently( ThePlayerList->getLocalPlayer()->getPlayerIndex() );
- break;
- }
- #endif // #if defined(_DEBUG) || defined(_INTERNAL)
- // ------------------------------------------------------------------------
- #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)
- case GameMessage::MSG_CHEAT_DESHROUD:
- {
- if (!TheGameLogic->isInMultiplayerGame())
- {
- ThePartitionManager->revealMapForPlayerPermanently( ThePlayerList->getLocalPlayer()->getPlayerIndex() );
- }
- break;
- }
- #endif // #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)
- // ------------------------------------------------------------------------
- #if defined(_DEBUG) || defined(_INTERNAL)
- case GameMessage::MSG_META_DEMO_ENSHROUD:
- {
- // Need to first undo the permanent Look laid down by DEMO_DESHROUD, then blast a shroud dollop.
- ThePartitionManager->undoRevealMapForPlayerPermanently( ThePlayerList->getLocalPlayer()->getPlayerIndex() );
- ThePartitionManager->shroudMapForPlayer( ThePlayerList->getLocalPlayer()->getPlayerIndex() );
- break;
- }
- #endif // #if defined(_DEBUG) || defined(_INTERNAL)
- // ------------------------------------------------------------------------
- #if defined(_DEBUG) || defined(_INTERNAL)
- case GameMessage::MSG_META_DEMO_BEGIN_ADJUST_FOV:
- {
- //DEBUG_ASSERTCRASH(!m_isChangingFOV, ("hmm, mismatched m_isChangingFOV"));
- m_isChangingFOV = true;
- m_anchor = m_currentPos;
- break;
- }
- #endif // #if defined(_DEBUG) || defined(_INTERNAL)
- // ------------------------------------------------------------------------
- #if defined(_DEBUG) || defined(_INTERNAL)
- case GameMessage::MSG_META_DEMO_END_ADJUST_FOV:
- {
- // DEBUG_ASSERTCRASH(m_isChangingFOV, ("hmm, mismatched m_isChangingFOV"));
- m_isChangingFOV = false;
- break;
- }
- #endif // #if defined(_DEBUG) || defined(_INTERNAL)
- //-----------------------------------------------------------------------------------------
- case GameMessage::MSG_META_SAVE_VIEW1:
- case GameMessage::MSG_META_SAVE_VIEW2:
- case GameMessage::MSG_META_SAVE_VIEW3:
- case GameMessage::MSG_META_SAVE_VIEW4:
- case GameMessage::MSG_META_SAVE_VIEW5:
- case GameMessage::MSG_META_SAVE_VIEW6:
- case GameMessage::MSG_META_SAVE_VIEW7:
- case GameMessage::MSG_META_SAVE_VIEW8:
- {
- Int slot = t - GameMessage::MSG_META_SAVE_VIEW1 + 1;
- if ( slot > 0 && slot <= MAX_VIEW_LOCS )
- {
- TheTacticalView->getLocation( &m_viewLocation[slot-1] );
- UnicodeString msg;
- msg.format( TheGameText->fetch( "GUI:BookmarkXSet" ), slot );
- TheInGameUI->message( msg );
- }
- disp = DESTROY_MESSAGE;
- break;
- }
- //-----------------------------------------------------------------------------------------
- case GameMessage::MSG_META_VIEW_VIEW1:
- case GameMessage::MSG_META_VIEW_VIEW2:
- case GameMessage::MSG_META_VIEW_VIEW3:
- case GameMessage::MSG_META_VIEW_VIEW4:
- case GameMessage::MSG_META_VIEW_VIEW5:
- case GameMessage::MSG_META_VIEW_VIEW6:
- case GameMessage::MSG_META_VIEW_VIEW7:
- case GameMessage::MSG_META_VIEW_VIEW8:
- {
- Int slot = t - GameMessage::MSG_META_VIEW_VIEW1 + 1;
- if ( slot > 0 && slot <= MAX_VIEW_LOCS )
- {
- TheTacticalView->setLocation( &m_viewLocation[slot-1] );
- }
- disp = DESTROY_MESSAGE;
- break;
- }
- //-----------------------------------------------------------------------------
- #if defined(_DEBUG) || defined(_INTERNAL)
- case GameMessage::MSG_META_DEMO_LOCK_CAMERA_TO_PLANES:
- {
- Drawable *first = NULL;
- if (m_lastPlaneID)
- first = TheGameClient->findDrawableByID( m_lastPlaneID );
- if (first == NULL)
- first = TheGameClient->firstDrawable();
- if (first)
- {
- Drawable *d = first;
- Bool done = false;
- while(!done)
- {
- // get next Drawable, wrapping around to head of list if necessary
- d = d->getNextDrawable();
- if (d == NULL)
- d = TheGameClient->firstDrawable();
- // if we've found an airborne object, lock onto it
- // "isAboveTerrain" only indicates that we are currently in the air, but that
- // could be the case if we are a buggy jumping a hill, or a unit being paradropped.
- // the right thing would be to look at the locomotors.
- // so this isn't really right, but will suffice for demo purposes.
- if (d->getObject() && d->getObject()->isAboveTerrain() )
- {
- Bool doLock = true;
- // but don't lock onto projectiles
- ProjectileUpdateInterface* pui = NULL;
- for (BehaviorModule** u = d->getObject()->getBehaviorModules(); *u; ++u)
- {
- if ((pui = (*u)->getProjectileUpdateInterface()) != NULL)
- {
- doLock = false;
- break;
- }
- }
- if (doLock)
- {
- TheTacticalView->setCameraLock( d->getObject()->getID() );
- m_lastPlaneID = d->getID();
- done = true;
- break;
- }
- } // if airborne found
- // if we're back to the first, quit
- if (d == first)
- break;
- } // while
- } // end plane lock
- disp = DESTROY_MESSAGE;
- break;
- }
- #endif // #if defined(_DEBUG) || defined(_INTERNAL)
- } // end switch
- return disp;
- } // end LookAtTranslator
- void LookAtTranslator::resetModes()
- {
- m_isScrolling = FALSE;
- m_isRotating = FALSE;
- m_isPitching = FALSE;
- m_isChangingFOV = FALSE;
- }
|