/* ** 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 . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // CommandXlat.cpp // Translate raw input events into tactical commands // Author: Michael S. Booth, February 2001 #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine #include "stdlib.h" // VC++ wants this here, or gives compile error... #include "Common/AudioAffect.h" #include "Common/ActionManager.h" #include "Common/GameAudio.h" #include "Common/GameEngine.h" #include "Common/GameType.h" #include "Common/GlobalData.h" #include "Common/MessageStream.h" #include "Common/MiscAudio.h" #include "Common/MultiplayerSettings.h" #include "Common/PerfTimer.h" #include "Common/Player.h" #include "Common/PlayerList.h" #include "Common/PlayerTemplate.h" #include "Common/Radar.h" #include "Common/Recorder.h" #include "Common/SpecialPower.h" #include "Common/StatsCollector.h" #include "Common/ThingTemplate.h" #include "Common/GameLOD.h" #include "GameClient/InGameUI.h" #include "GameClient/CommandXlat.h" #include "GameClient/DebugDisplay.h" #include "GameClient/Drawable.h" #include "GameClient/GameClient.h" #include "GameClient/GameWindowManager.h" #include "GameClient/GameText.h" #include "GameClient/ParticleSys.h" #include "GameClient/GUICallbacks.h" #include "GameClient/Shell.h" #include "GameClient/ControlBar.h" #include "GameClient/SelectionInfo.h" #include "GameClient/SelectionXlat.h" #include "GameLogic/Module/AIUpdate.h" #include "GameLogic/ExperienceTracker.h" #include "GameLogic/GameLogic.h" #include "GameLogic/Module/BodyModule.h" #include "GameLogic/Object.h" #include "GameLogic/PartitionManager.h" #include "GameLogic/ScriptEngine.h" #include "GameLogic/TerrainLogic.h" #include "GameLogic/GhostObject.h" #include "GameLogic/Weapon.h" #include "GameLogic/Module/SpawnBehavior.h" #include "GameLogic/Module/SpecialPowerModule.h" #include "Common/ThingFactory.h" #include "GameLogic/Module/ContainModule.h" #include "GameNetwork/NetworkInterface.h" #include "GameNetwork/GameInfo.h" #include "GameNetwork/GameSpyOverlay.h" #include "GameNetwork/GameSpy/BuddyThread.h" #ifdef _INTERNAL // for occasional debugging... //#pragma optimize("", off) //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes") #endif #define dont_ALLOW_ALT_F4 #if defined(_DEBUG) || defined(_INTERNAL) /*non-static*/ Real TheSkateDistOverride = 0.0f; void countObjects(Object *obj, void *userData) { Int *numObjects = (Int *)userData; if (!numObjects || !obj) return; DEBUG_LOG(("Looking at obj %d (%s) - isEffectivelyDead()==%d, isDestroyed==%d, numObjects==%d\n", obj->getID(), obj->getTemplate()->getName().str(), obj->isEffectivelyDead(), obj->isDestroyed(), *numObjects)); if (!obj->isEffectivelyDead() && !obj->isDestroyed() && !obj->isKindOf(KINDOF_INERT)) ++(*numObjects); } void printObjects(Object *obj, void *userData) { if (!obj) return; Bool isDead = obj->isEffectivelyDead() || obj->isDestroyed(); Bool isInert = obj->isKindOf(KINDOF_INERT); AsciiString statusStr = (isDead)?"Dead":(isInert)?"Inert":"Living"; AsciiString line; if (obj->getName().isEmpty()) line.format(" Obj#%d %s - (%g,%g) %s", obj->getID(), obj->getTemplate()->getName().str(), obj->getPosition()->x, obj->getPosition()->y, statusStr.str()); else line.format(" Obj#%d %s (%s) - (%g,%g) %s", obj->getID(), obj->getTemplate()->getName().str(), obj->getName().str(), obj->getPosition()->x, obj->getPosition()->y, statusStr.str()); TheScriptEngine->AppendDebugMessage(line, FALSE); } #endif static Bool isSystemMessage( const GameMessage *msg ); enum{ DROPPED_MAX_PARTICLE_COUNT = 1000}; static Bool canSelectionSalvage( const Object *targetObj) { if (!targetObj) { return FALSE; } if (!targetObj->isSalvageCrate()) { return FALSE; } const DrawableList *drawList = TheInGameUI->getAllSelectedDrawables(); for (DrawableListCIt cit = drawList->begin(); cit != drawList->end(); ++cit) { Drawable *draw = *cit; if (!draw) { continue; } Object *obj = draw->getObject(); if (!obj) { continue; } if (obj->isKindOf(KINDOF_SALVAGER)) { return TRUE; } } return FALSE; } //------------------------------------------------------------------------------------------------- static CanAttackResult canObjectForceAttack( Object *obj, const Object *victim, const Coord3D *pos ) { CanAttackResult result; result = obj->isAbleToAttack() ? ATTACKRESULT_POSSIBLE : ATTACKRESULT_NOT_POSSIBLE; if( result == ATTACKRESULT_NOT_POSSIBLE ) { return ATTACKRESULT_NOT_POSSIBLE; } if (victim) { result = obj->getAbleToAttackSpecificObject(ATTACK_NEW_TARGET_FORCED, victim, CMD_FROM_PLAYER ); //Special case -- objects with spawn weapons have to do different checks. Stinger site with stinger soldiers is //the catalyst example. if ( obj->isKindOf( KINDOF_SPAWNS_ARE_THE_WEAPONS ) ) { if( result != ATTACKRESULT_POSSIBLE && result != ATTACKRESULT_POSSIBLE_AFTER_MOVING ) { SpawnBehaviorInterface *spawnInterface = obj->getSpawnBehaviorInterface(); if( spawnInterface ) { //We found the spawn interface, now get the closest slave to the target. Object *slave = spawnInterface->getClosestSlave( victim->getPosition() ); if( slave ) { result = slave->getAbleToAttackSpecificObject( ATTACK_NEW_TARGET_FORCED, victim, CMD_FROM_PLAYER ); } } } else // oh dear me. The wierd case of a garrisoncontainer being a KINDOF_SPAWNS_ARE_THE_WEAPONS... the AmericaBuildingFirebase { ContainModuleInterface *contain = obj->getContain(); if ( contain ) { Object *rider = contain->getClosestRider( victim->getPosition() ); if ( rider ) { result = rider->getAbleToAttackSpecificObject( ATTACK_NEW_TARGET_FORCED, victim, CMD_FROM_PLAYER ); if( result != ATTACKRESULT_NOT_POSSIBLE ) return result; } } } } // end if spawnsRweapons return result; } else { //Almost every combat unit can force attack a position. The exceptions include stationary units //that try to force attack in a location beyond their reach (range, LOS, etc). if( pos ) { Object *testObj = obj; if( obj->isKindOf( KINDOF_IMMOBILE ) || obj->isKindOf( KINDOF_SPAWNS_ARE_THE_WEAPONS ) ) { SpawnBehaviorInterface *spawnInterface = obj->getSpawnBehaviorInterface(); if( spawnInterface ) { //We found the spawn interface, now get the closest slave to the target. Object *slave = spawnInterface->getClosestSlave( pos ); if( slave ) { testObj = slave; } } else { result = obj->getAbleToUseWeaponAgainstTarget( ATTACK_NEW_TARGET, NULL, pos, CMD_FROM_PLAYER ); if( result != ATTACKRESULT_POSSIBLE ) // oh dear me. The wierd case of a garrisoncontainer being a KINDOF_SPAWNS_ARE_THE_WEAPONS... the AmericaBuildingFirebase { ContainModuleInterface *contain = obj->getContain(); if ( contain ) { Object *rider = contain->getClosestRider( pos ); if ( rider ) testObj = rider; } } } } //Now evaluate the testObj again to see if it is capable of force attacking the pos. result = testObj->getAbleToUseWeaponAgainstTarget( ATTACK_NEW_TARGET, NULL, pos, CMD_FROM_PLAYER ); return result; } } return ATTACKRESULT_NOT_POSSIBLE; } //------------------------------------------------------------------------------------------------- static CanAttackResult canAnyForceAttack(const DrawableList *allSelected, const Object *victim, const Coord3D *pos ) { // check to make sure that allSelected can attack obj. for (DrawableListCIt cit = allSelected->begin(); cit != allSelected->end(); ++cit) { Drawable *draw = *cit; if (!draw) { continue; } Object *obj = draw->getObject(); if (!obj) { continue; } return canObjectForceAttack( obj, victim, pos ); } return ATTACKRESULT_NOT_POSSIBLE; } //------------------------------------------------------------------------------------------------- void pickAndPlayUnitVoiceResponse( const DrawableList *list, GameMessage::Type msgType, PickAndPlayInfo *info ) { if (!list) { return; } const AudioEventRTS* soundToPlayPtr = NULL; Object *objectWithSound = NULL; Bool skip = false; Object *target = NULL; if( info && info->m_drawTarget ) { target = info->m_drawTarget->getObject(); } //Now, loop through all the drawables (even if you find a match on the first. //The innards are responsible for "upgrading" a sound that is played based on //priorities. For example, the voice move or voice crush. Voice move gets set //when we have a null event -- but if any of the units can crush the specified //target, then it changes to VoiceCrush. for( DrawableListCIt it = list->begin(); it != list->end(); ++it ) { Object *obj = (*it)->getObject(); if (obj->isKindOf( KINDOF_IGNORED_IN_GUI )) continue; // Use the object instead of the drawable to get the thing template from. This way, we get the // sounds even if the thing is disguised as something else. (Ala bomb truck.) const ThingTemplate *templ = obj->getTemplate(); if (!templ) { return; } switch (msgType) { case GameMessage::MSG_DOCK: soundToPlayPtr = templ->getPerUnitSound("VoiceSupply"); objectWithSound = obj; skip = true; break; case GameMessage::MSG_SELECT_TEAM0: case GameMessage::MSG_SELECT_TEAM1: case GameMessage::MSG_SELECT_TEAM2: case GameMessage::MSG_SELECT_TEAM3: case GameMessage::MSG_SELECT_TEAM4: case GameMessage::MSG_SELECT_TEAM5: case GameMessage::MSG_SELECT_TEAM6: case GameMessage::MSG_SELECT_TEAM7: case GameMessage::MSG_SELECT_TEAM8: case GameMessage::MSG_SELECT_TEAM9: case GameMessage::MSG_CREATE_SELECTED_GROUP: soundToPlayPtr = templ->getVoiceSelect(); objectWithSound = obj; skip = true; break; case GameMessage::MSG_EVACUATE: soundToPlayPtr = templ->getPerUnitSound( "VoiceUnload" ); objectWithSound = obj; skip = true; break; case GameMessage::MSG_DO_REPAIR: soundToPlayPtr = templ->getPerUnitSound( "VoiceRepair" ); objectWithSound = obj; skip = true; break; #ifdef ALLOW_SURRENDER case GameMessage::MSG_PICK_UP_PRISONER: soundToPlayPtr = templ->getPerUnitSound( "VoicePickup" ); objectWithSound = obj; skip = true; break; #endif case GameMessage::MSG_COMBATDROP_AT_LOCATION: case GameMessage::MSG_COMBATDROP_AT_OBJECT: soundToPlayPtr = templ->getPerUnitSound( "VoiceCombatDrop" ); objectWithSound = obj; skip = true; break; case GameMessage::MSG_ENTER: if( target && target->isKindOf( KINDOF_HEAL_PAD ) ) { soundToPlayPtr = templ->getPerUnitSound( "VoiceGetHealed" ); } else if( target && target->isKindOf( KINDOF_STRUCTURE ) ) { if( obj->getRelationship( target ) == ENEMIES ) { //Saboteurs soundToPlayPtr = templ->getPerUnitSound( "VoiceEnterHostile" ); } else { soundToPlayPtr = templ->getPerUnitSound( "VoiceGarrison" ); } } // order matters: we want to know if I consider it to be an ally, not vice versa else if( target && obj->getRelationship(target) != ALLIES ) { soundToPlayPtr = templ->getPerUnitSound( "VoiceEnterHostile" ); } else { soundToPlayPtr = templ->getPerUnitSound( "VoiceEnter" ); } objectWithSound = obj; skip = true; break; case GameMessage::MSG_DO_MOVETO: case GameMessage::MSG_DO_ATTACKMOVETO: case GameMessage::MSG_GET_REPAIRED: case GameMessage::MSG_GET_HEALED: case GameMessage::MSG_DO_SALVAGE: { AIUpdateInterface *ai = obj->getAI(); if( ai ) { //This flag determines if the object has started moving yet... if not //it's a good initial check. Bool isEffectivelyMoving = ai->isMoving() || ai->isWaitingForPath(); if( TheInGameUI->isInWaypointMode() ) { if( isEffectivelyMoving ) { //Don't want to play the sound unless he's not moving! continue; } } //Default to voice move (it'll be selected if we can't find a crush case as we iterate //through the rest of the drawables) if( !soundToPlayPtr ) { soundToPlayPtr = templ->getVoiceMove(); objectWithSound = obj; } if( TheInGameUI->isInForceMoveToMode() && target ) { if( obj->canCrushOrSquish( target ) ) { //Change it to voice crush because we are intentionally trying to crush this! soundToPlayPtr = templ->getPerUnitSound( "VoiceCrush" ); objectWithSound = obj; skip = true; } } if (msgType == GameMessage::MSG_DO_SALVAGE) { const AudioEventRTS *tempSound = templ->getPerUnitSound( "VoiceSalvage" ); if (TheAudio->isValidAudioEvent(tempSound)) { soundToPlayPtr = tempSound; objectWithSound = obj; skip = true; } } // Special case for GLA worker to use a different set of move voices when he has received the worker shoes upgrade Player *player = obj->getControllingPlayer(); static const UpgradeTemplate *workerShoeTemplate = TheUpgradeCenter->findUpgrade( "Upgrade_GLAWorkerShoes" ); if (player && player->hasUpgradeComplete(workerShoeTemplate)) { if (obj->isKindOf(KINDOF_INFANTRY) && obj->isKindOf(KINDOF_DOZER) && obj->isKindOf(KINDOF_HARVESTER)) // Only Workers fit all 3 { soundToPlayPtr = templ->getPerUnitSound( "VoiceMoveUpgraded" ); objectWithSound = obj; skip = true; } } } break; } case GameMessage::MSG_RESUME_CONSTRUCTION: case GameMessage::MSG_DOZER_CONSTRUCT: case GameMessage::MSG_DOZER_CONSTRUCT_LINE: { soundToPlayPtr = templ->getPerUnitSound( "VoiceBuildResponse" ); objectWithSound = obj; skip = true; break; } case GameMessage::MSG_DO_FORCE_ATTACK_GROUND: { soundToPlayPtr = templ->getPerUnitSound( "VoiceBombard" ); objectWithSound = obj; skip = true; if (TheAudio->isValidAudioEvent(soundToPlayPtr)) { break; } else { // clear out the sound to play, and drop into the attack object logic. soundToPlayPtr = NULL; } } case GameMessage::MSG_SWITCH_WEAPONS: { if( info && info->m_weaponSlot ) { switch( *info->m_weaponSlot ) { case PRIMARY_WEAPON: soundToPlayPtr = templ->getPerUnitSound( "VoicePrimaryWeaponMode" ); break; case SECONDARY_WEAPON: soundToPlayPtr = templ->getPerUnitSound( "VoiceSecondaryWeaponMode" ); break; case TERTIARY_WEAPON: soundToPlayPtr = templ->getPerUnitSound( "VoiceTertiaryWeaponMode" ); break; } objectWithSound = obj; skip = true; } break; } case GameMessage::MSG_DO_FORCE_ATTACK_OBJECT: case GameMessage::MSG_DO_ATTACK_OBJECT: case GameMessage::MSG_DO_WEAPON_AT_OBJECT: { if( !soundToPlayPtr ) { //Low priority sounds -- only do this if uninitialized. if( info && info->m_air ) soundToPlayPtr = templ->getVoiceAttackAir(); else soundToPlayPtr = templ->getVoiceAttack(); objectWithSound = obj; } //Look for a specialty weapon fired via command button! Bool specialtyWeapon = FALSE; if( msgType == GameMessage::MSG_DO_WEAPON_AT_OBJECT ) { specialtyWeapon = TRUE; } Weapon *weapon = obj->getCurrentWeapon(); if( info && info->m_weaponSlot ) { weapon = obj->getWeaponInWeaponSlot( *info->m_weaponSlot ); } if( weapon ) { switch( weapon->getDamageType() ) { // this stays, even if ALLOW_SURRENDER is not defed, since flashbangs still use 'em case DAMAGE_SURRENDER: if( target && target->isKindOf( KINDOF_STRUCTURE ) ) { //We are attempting to take over a building with rangers and flashbangs! soundToPlayPtr = templ->getPerUnitSound( "VoiceClearBuilding" ); } else { //Special for subdue attacks. soundToPlayPtr = templ->getPerUnitSound( "VoiceSubdue" ); } objectWithSound = obj; skip = true; break; case DAMAGE_DISARM: //Special for mine clearing attacks. soundToPlayPtr = templ->getPerUnitSound( "VoiceDisarm" ); objectWithSound = obj; skip = true; break; case DAMAGE_KILLPILOT: if( specialtyWeapon ) { //Special for sniping vehicle pilots. soundToPlayPtr = templ->getPerUnitSound( "VoiceSnipePilot" ); objectWithSound = obj; skip = true; } break; case DAMAGE_MELEE: if( specialtyWeapon ) { //Special for stabbing soundToPlayPtr = templ->getPerUnitSound( "VoiceMelee" ); objectWithSound = obj; skip = true; } break; } } break; } case GameMessage::MSG_DO_WEAPON_AT_LOCATION: { if( !soundToPlayPtr ) { //Low priority sounds -- only do this if uninitialized. if( info && info->m_air ) soundToPlayPtr = templ->getVoiceAttackAir(); else soundToPlayPtr = templ->getVoiceAttack(); objectWithSound = obj; } //Check for possibility of a higher priority sound! Weapon *weapon = obj->getCurrentWeapon(); if( info && info->m_weaponSlot ) { weapon = obj->getWeaponInWeaponSlot( *info->m_weaponSlot ); } if( weapon ) { switch( weapon->getDamageType() ) { // this stays, even if ALLOW_SURRENDER is not defed, since flashbangs still use 'em case DAMAGE_SURRENDER: break; case DAMAGE_DISARM: //Special for mine clearing attacks. soundToPlayPtr = templ->getPerUnitSound( "VoiceDisarm" ); objectWithSound = obj; break; //these are specific to the guicommand based ground attacks, the toxin sprinkler and the firestorm wall thing //hence the additional check for it being a non-primary weapon case DAMAGE_FLAME: if (weapon->getWeaponSlot() != PRIMARY_WEAPON) { soundToPlayPtr = templ->getPerUnitSound( "VoiceFlameLocation" ); objectWithSound = obj; } break; case DAMAGE_POISON: if (weapon->getWeaponSlot() != PRIMARY_WEAPON) { soundToPlayPtr = templ->getPerUnitSound( "VoicePoisonLocation" ); objectWithSound = obj; } break; default: if( !weapon->getName().compare( "ComancheRocketPodWeapon" ) ) { //Special case for comanche rocket pods. soundToPlayPtr = templ->getPerUnitSound( "VoiceFireRocketPods" ); objectWithSound = obj; skip = true; } } } break; } case GameMessage::MSG_DO_GUARD_POSITION: case GameMessage::MSG_DO_GUARD_OBJECT: soundToPlayPtr = templ->getVoiceGuard(); objectWithSound = obj; skip = true; break; case GameMessage::MSG_DO_SPECIAL_POWER: case GameMessage::MSG_DO_SPECIAL_POWER_AT_LOCATION: case GameMessage::MSG_DO_SPECIAL_POWER_AT_OBJECT: { if( info && info->m_specialPowerType != SPECIAL_INVALID ) { SpecialPowerModuleInterface *spmInterface = obj->findSpecialPowerModuleInterface( info->m_specialPowerType ); if( spmInterface ) { objectWithSound = obj; soundToPlayPtr = &spmInterface->getInitiateSound(); skip = TRUE; } } break; } case GameMessage::MSG_INTERNET_HACK: objectWithSound = obj; soundToPlayPtr = templ->getPerUnitSound( "VoiceHackInternet" ); skip = TRUE; break; default: DEBUG_LOG(("Requested to add voice of message type %d, but don't know how - jkmcd\n", msgType)); break; } if( skip ) { //The unit sound doesn't have any sort of priority or special case, so simply play the first one that comes along. break; } }//next drawable in list if (!soundToPlayPtr) return; AudioEventRTS soundToPlay = *soundToPlayPtr; // to prevent voice stepping. if( objectWithSound ) { soundToPlay.setObjectID( objectWithSound->getID() ); TheAudio->addAudioEvent(&soundToPlay); // This seems really hacky, and MarkL admits that it is. However, we do this so that we // can "randomly" pick a different sound the next time, if we have 3 or more sounds. - jkmcd ((AudioEventRTS*)soundToPlayPtr)->setPlayingAudioIndex( soundToPlay.getPlayingAudioIndex() ); if( objectWithSound->testStatus( OBJECT_STATUS_IS_CARBOMB ) ) { //Additional sounds for terrorists in cars. switch (msgType) { case GameMessage::MSG_DO_FORCE_ATTACK_GROUND: case GameMessage::MSG_DO_FORCE_ATTACK_OBJECT: case GameMessage::MSG_DO_ATTACK_OBJECT: soundToPlay = TheAudio->getMiscAudio()->m_terroristInCarAttackVoice; soundToPlay.setObjectID( objectWithSound->getID() ); TheAudio->addAudioEvent(&soundToPlay); break; case GameMessage::MSG_DO_MOVETO: case GameMessage::MSG_DO_ATTACKMOVETO: case GameMessage::MSG_GET_REPAIRED: case GameMessage::MSG_GET_HEALED: case GameMessage::MSG_DO_SALVAGE: soundToPlay = TheAudio->getMiscAudio()->m_terroristInCarMoveVoice; soundToPlay.setObjectID( objectWithSound->getID() ); TheAudio->addAudioEvent(&soundToPlay); break; case GameMessage::MSG_SELECT_TEAM0: case GameMessage::MSG_SELECT_TEAM1: case GameMessage::MSG_SELECT_TEAM2: case GameMessage::MSG_SELECT_TEAM3: case GameMessage::MSG_SELECT_TEAM4: case GameMessage::MSG_SELECT_TEAM5: case GameMessage::MSG_SELECT_TEAM6: case GameMessage::MSG_SELECT_TEAM7: case GameMessage::MSG_SELECT_TEAM8: case GameMessage::MSG_SELECT_TEAM9: case GameMessage::MSG_CREATE_SELECTED_GROUP: soundToPlay = TheAudio->getMiscAudio()->m_terroristInCarSelectVoice; soundToPlay.setObjectID( objectWithSound->getID() ); TheAudio->addAudioEvent(&soundToPlay); break; } } } } //------------------------------------------------------------------------------------ /** * Find a suitable command center to view. */ struct CommandCenterLocator { Bool atLeastOne; Bool isCommandCenter; Int val; Coord3D loc; CommandCenterLocator() : atLeastOne(false), isCommandCenter(false), val(-1) { loc.zero(); } }; void findCommandCenterOrMostExpensiveBuilding(Object* obj, void* vccl) { if (!obj) { return; } CommandCenterLocator *ccl = (CommandCenterLocator*) vccl; // here's the deal. We want to get the first Command Center in the list. // Barring that, we want the most expensive structure we currently own. if (obj->isKindOf(KINDOF_COMMANDCENTER)) { ccl->isCommandCenter = true; ccl->loc = *obj->getPosition(); } else if (!ccl->isCommandCenter) { if (!obj->isKindOf(KINDOF_STRUCTURE)) { return; } Int costToBuild = obj->getTemplate()->calcCostToBuild(obj->getControllingPlayer()); if (costToBuild > ccl->val) { ccl->val = costToBuild; ccl->loc = *obj->getPosition(); } } ccl->atLeastOne = true; } static void viewCommandCenter( void ) { Player* localPlayer = ThePlayerList->getLocalPlayer(); if (!localPlayer) return; CommandCenterLocator ccl; localPlayer->iterateObjects(findCommandCenterOrMostExpensiveBuilding, &ccl); if (ccl.atLeastOne) { TheTacticalView->lookAt(&ccl.loc); } else { // @todo. Find their starting position and look at that instead? } } //----------------- Select and View Hero ----------------------------------- struct HeroHolder { Object *hero; }; void amIAHero(Object* obj, void* heroHolder) { if (!obj || ((HeroHolder*)heroHolder)->hero != NULL) { return; } if (obj->isKindOf( KINDOF_HERO )) { ((HeroHolder*)heroHolder)->hero = obj; } } static Object *iNeedAHero( void ) { Player* localPlayer = ThePlayerList->getLocalPlayer(); if (!localPlayer) return NULL; HeroHolder heroHolder; heroHolder.hero = NULL; localPlayer->iterateObjects(amIAHero, (void*)&heroHolder); return heroHolder.hero; } //------------------------------------------------------------------------------------ /** * Create DO_MOVE_TO messages for each selected object, instructing it to move to the given location. */ GameMessage::Type CommandTranslator::issueMoveToLocationCommand( const Coord3D *pos, Drawable *drawableInWay, CommandEvaluateType commandType ) { GameMessage::Type msgType = GameMessage::MSG_INVALID; Object *obj = drawableInWay ? drawableInWay->getObject() : NULL; Bool isForceAttackable = FALSE; if (obj) { isForceAttackable = obj->isKindOf(KINDOF_FORCEATTACKABLE); } if (m_teamExists) { if( TheInGameUI->isInWaypointMode() ) { msgType = GameMessage::MSG_ADD_WAYPOINT; } else if( TheInGameUI->isInAttackMoveToMode()) { msgType = GameMessage::MSG_DO_ATTACKMOVETO; } else if( TheInGameUI->isInForceMoveToMode() ) { msgType = GameMessage::MSG_DO_FORCEMOVETO; } else if( TheInGameUI->isInForceAttackMode() && isForceAttackable ) { msgType = GameMessage::MSG_DO_ATTACK_OBJECT; } else { msgType = GameMessage::MSG_DO_MOVETO; } if( commandType == DO_COMMAND ) { GameMessage *movemsg = TheMessageStream->appendMessage( msgType ); if (msgType == GameMessage::MSG_DO_ATTACK_OBJECT) movemsg->appendObjectIDArgument( obj->getID() ); else movemsg->appendLocationArgument( *pos ); } // end if } // only make sounds if we really did the command messages if( commandType == DO_COMMAND ) { PickAndPlayInfo info; info.m_drawTarget = drawableInWay; pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_MOVETO, &info ); } // end if if(TheStatsCollector) TheStatsCollector->incrementMoveCount(); // return the actual msg type used return msgType; } //------------------------------------------------------------------------------------ /// @todo Play attack command response sound on client-side to hide latency GameMessage::Type CommandTranslator::createAttackMessage( Drawable *draw, Drawable *other, CommandEvaluateType commandType ) { GameMessage::Type msgType = GameMessage::MSG_INVALID; // the drawable must have an object to be able to attack if( draw->getObject() == NULL ) return msgType; // the target must have an object to be attacked if( other->getObject() == NULL ) return msgType; // insert object attack command message into stream msgType = GameMessage::MSG_DO_ATTACK_OBJECT; // only make the message if we are really doing a command if( commandType == DO_COMMAND ) { GameMessage *attackmsg = TheMessageStream->appendMessage( msgType ); attackmsg->appendObjectIDArgument( other->getObject()->getID() ); // must pass object IDs to logic } // end if // return the message type created return msgType; } //------------------------------------------------------------------------------------ /** * Create DO_ATTACK_GROUND_OBJECT messages for each selected object, instructing it to attack the given enemy. * Return TRUE if any attacks actually occurred. */ GameMessage::Type CommandTranslator::issueAttackCommand( Drawable *target, CommandEvaluateType commandType, GUICommandType command ) { GameMessage::Type msgType = GameMessage::MSG_INVALID; if (target == NULL) return msgType; // you cannot attack an enemy that has no object representation Object *targetObj = target->getObject(); if( !targetObj ) return msgType; if( m_teamExists ) { //DEBUG_LOG(("issuing team-attack cmd against %s\n",enemy->getTemplate()->getName().str())); // insert team attack command message into stream switch( command ) { #ifdef ALLOW_SURRENDER case GUICOMMANDMODE_PICK_UP_PRISONER: msgType = GameMessage::MSG_PICK_UP_PRISONER; break; #endif case GUI_COMMAND_NONE: msgType = GameMessage::MSG_DO_ATTACK_OBJECT; break; default: DEBUG_ASSERTCRASH( 0, ("issueAttackCommand was passed in a GUICommandType type that isn't supported yet...") ); return msgType; } // only create the message if our command type is DO_COMMAND if( commandType == DO_COMMAND ) { GameMessage *attackMsg; attackMsg = TheMessageStream->appendMessage( msgType ); attackMsg->appendObjectIDArgument( targetObj->getID() ); // must pass target object ID to logic // if we have a stats collector, inrement the stats if(TheStatsCollector) TheStatsCollector->incrementAttackCount(); } // end if } else { DEBUG_LOG(("issuing NON-team-attack cmd against %s\n",target->getTemplate()->getName().str())); // send single attack command for selected drawable const DrawableList *selected = TheInGameUI->getAllSelectedDrawables(); // loop through all the selected drawables Drawable *draw; for( DrawableListCIt it = selected->begin(); it != selected->end(); ++it ) { draw = *it; msgType = createAttackMessage(draw, target, commandType ); } } // only make sounds if the command was for real if( commandType == DO_COMMAND ) { PickAndPlayInfo info; info.m_air = targetObj->isUsingAirborneLocomotor(); info.m_drawTarget = target; pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), msgType, &info ); } // end if // return the actual message type created return msgType; } //------------------------------------------------------------------------------------------------- GameMessage::Type CommandTranslator::issueSpecialPowerCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos, Object* ignoreSelObj ) { GameMessage::Type msgType = GameMessage::MSG_INVALID; if( !command || !command->getSpecialPowerTemplate()) { return msgType; } Drawable* sourceDraw = ignoreSelObj ? ignoreSelObj->getDrawable() : TheInGameUI->getFirstSelectedDrawable(); ObjectID specificSource = ignoreSelObj ? ignoreSelObj->getID() : INVALID_ID; if( BitTest( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) { // OBJECT BASED SPECIAL if (!command->isValidObjectTarget(sourceDraw, target)) return msgType; msgType = GameMessage::MSG_DO_SPECIAL_POWER_AT_OBJECT; if( commandType == DO_COMMAND ) { GameMessage *msg; msg = TheMessageStream->appendMessage( msgType ); msg->appendIntegerArgument( command->getSpecialPowerTemplate()->getID() ); msg->appendObjectIDArgument( target->getObject()->getID() ); msg->appendIntegerArgument( command->getOptions() ); msg->appendObjectIDArgument( specificSource ); // say something like " I think I'll put some dynamite on that there tank." PickAndPlayInfo info; info.m_drawTarget = target; info.m_specialPowerType = command->getSpecialPowerTemplate()->getSpecialPowerType(); pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), msgType, &info ); } } else if( BitTest( command->getOptions(), NEED_TARGET_POS ) ) { //LOCATION BASED SPECIAL msgType = GameMessage::MSG_DO_SPECIAL_POWER_AT_LOCATION; if( commandType == DO_COMMAND ) { GameMessage *msg; msg = TheMessageStream->appendMessage( msgType ); msg->appendIntegerArgument( command->getSpecialPowerTemplate()->getID() ); msg->appendLocationArgument( *pos ); msg->appendRealArgument( INVALID_ANGLE ); //We don't use the angle (unless we're using a construction special in PlaceEventTranslator). //Object in way.... some specials care, others don't ObjectID targetID = (target && target->getObject()) ? target->getObject()->getID() : INVALID_ID; msg->appendObjectIDArgument( targetID ); msg->appendIntegerArgument( command->getOptions() ); msg->appendObjectIDArgument( specificSource ); // say something like " I think I'll put a timed charge on the ground, here." PickAndPlayInfo info; info.m_drawTarget = target; info.m_specialPowerType = command->getSpecialPowerTemplate()->getSpecialPowerType(); pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), msgType, &info ); } } else { //NO TARGET SPECIAL msgType = GameMessage::MSG_DO_SPECIAL_POWER; if( commandType == DO_COMMAND ) { GameMessage *msg; msg = TheMessageStream->appendMessage( msgType ); msg->appendIntegerArgument( command->getSpecialPowerTemplate()->getID() ); msg->appendIntegerArgument( command->getOptions() ); msg->appendObjectIDArgument( specificSource ); // say something like " I think I'll set down my laptop and hack some cash from a bank in the Cayman Islands." PickAndPlayInfo info; info.m_drawTarget = target; info.m_specialPowerType = command->getSpecialPowerTemplate()->getSpecialPowerType(); pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), msgType, &info ); } } if( command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT && commandType == DO_COMMAND ) { Object *obj = sourceDraw->getObject(); SpecialPowerUpdateInterface *spUpdate = obj->findSpecialPowerWithOverridableDestination(); if( spUpdate ) { //Deselect the drawables before posting the selection message. TheInGameUI->deselectAllDrawables(); //Because we just launched a special power via shortcut, and the special power accepts input //from the player (particle uplink cannon, spectre gunship), simply select the object now. //-------------------- GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP_NO_SOUND ); // creating a new team so pass in true teamMsg->appendBooleanArgument( TRUE ); teamMsg->appendObjectIDArgument( obj->getID() ); TheInGameUI->selectDrawable( obj->getDrawable() ); } } return msgType; } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- GameMessage::Type CommandTranslator::issueCombatDropCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos ) { if( !command ) { return GameMessage::MSG_INVALID; } if( target != NULL && BitTest( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) { // OBJECT BASED SPECIAL if (!command->isValidObjectTarget(TheInGameUI->getFirstSelectedDrawable(), target)) return GameMessage::MSG_INVALID; GameMessage::Type msgType = GameMessage::MSG_COMBATDROP_AT_OBJECT; if( commandType == DO_COMMAND ) { GameMessage *msg = TheMessageStream->appendMessage( msgType ); ObjectID targetID = (target && target->getObject()) ? target->getObject()->getID() : INVALID_ID; msg->appendObjectIDArgument( targetID ); pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_COMBATDROP_AT_OBJECT ); } return msgType; } else if ( BitTest( command->getOptions(), NEED_TARGET_POS ) ) { GameMessage::Type msgType = GameMessage::MSG_COMBATDROP_AT_LOCATION; if( commandType == DO_COMMAND ) { GameMessage *msg = TheMessageStream->appendMessage( msgType ); msg->appendLocationArgument( *pos ); pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_COMBATDROP_AT_LOCATION ); } return msgType; } else { return GameMessage::MSG_INVALID; } } //------------------------------------------------------------------------------------------------- GameMessage::Type CommandTranslator::issueFireWeaponCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos ) { GameMessage::Type msgType = GameMessage::MSG_INVALID; if( !command ) { return msgType; } if( BitTest( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) { //OBJECT BASED FIRE WEAPON if (!target || !target->getObject()) return msgType; if (!command->isValidObjectTarget(TheInGameUI->getFirstSelectedDrawable(), target)) return msgType; if( BitTest( command->getOptions(), ATTACK_OBJECTS_POSITION ) ) { //Actually, you know what.... we want to attack the object's location instead. msgType = GameMessage::MSG_DO_WEAPON_AT_LOCATION; if( commandType == DO_COMMAND ) { GameMessage *msg; msg = TheMessageStream->appendMessage( msgType ); msg->appendIntegerArgument( command->getWeaponSlot() ); msg->appendLocationArgument( *pos ); msg->appendIntegerArgument( command->getMaxShotsToFire() ); //Object in way.... some location weapons care, others don't ObjectID targetID = (target && target->getObject()) ? target->getObject()->getID() : INVALID_ID; msg->appendObjectIDArgument( targetID ); } } else { msgType = GameMessage::MSG_DO_WEAPON_AT_OBJECT; if( commandType == DO_COMMAND ) { GameMessage *msg; msg = TheMessageStream->appendMessage( msgType ); msg->appendIntegerArgument( command->getWeaponSlot() ); ObjectID targetID = (target && target->getObject()) ? target->getObject()->getID() : INVALID_ID; msg->appendObjectIDArgument( targetID ); msg->appendIntegerArgument( command->getMaxShotsToFire() ); //play a unit specific sound? PickAndPlayInfo info; WeaponSlotType slot = command->getWeaponSlot(); info.m_weaponSlot = &slot; pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_WEAPON_AT_OBJECT, &info ); } } } else if( BitTest( command->getOptions(), NEED_TARGET_POS ) ) { //LOCATION BASED FIRE WEAPON msgType = GameMessage::MSG_DO_WEAPON_AT_LOCATION; if( commandType == DO_COMMAND ) { GameMessage *msg; msg = TheMessageStream->appendMessage( msgType ); msg->appendIntegerArgument( command->getWeaponSlot() ); msg->appendLocationArgument( *pos ); msg->appendIntegerArgument( command->getMaxShotsToFire() ); //Object in way.... some location weapons care, others don't ObjectID targetID = (target && target->getObject()) ? target->getObject()->getID() : INVALID_ID; msg->appendObjectIDArgument( targetID ); } } else { //NO TARGET WEAPON msgType = GameMessage::MSG_DO_WEAPON; if( commandType == DO_COMMAND ) { GameMessage *msg; msg = TheMessageStream->appendMessage( msgType ); DEBUG_ASSERTCRASH( (command->getSpecialPowerTemplate()), ("No Special Power Weapon here to 'do' with! ML")); msg->appendIntegerArgument( command->getSpecialPowerTemplate()->getID() ); } } return msgType; } //------------------------------------------------------------------------------------------------- GameMessage::Type CommandTranslator::createEnterMessage( Drawable *enter, CommandEvaluateType commandType ) { GameMessage::Type msgType = GameMessage::MSG_ENTER; // if we're just evaluating then get out of here without actually doing the action if( commandType == EVALUATE_ONLY ) return msgType; if (!enter || !enter->getObject()) return msgType; // sanity DEBUG_ASSERTCRASH( commandType == DO_COMMAND, ("createEnterMessage - commandType is not DO_COMMAND\n") ); if( m_teamExists ) { PickAndPlayInfo info; info.m_drawTarget = enter; pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), msgType, &info ); GameMessage *enterMsg = TheMessageStream->appendMessage( msgType ); enterMsg->appendObjectIDArgument( INVALID_ID ); // 0 means current "selection team" of this player enterMsg->appendObjectIDArgument( enter->getObject()->getID() ); } // end if else { DEBUG_CRASH(("Shouldn't get here. jkmcd")); } // return the type of the message used return msgType; } // end createEnterMessage //==================================================================================== CommandTranslator::CommandTranslator() : m_objective(0), m_teamExists(false), m_mouseRightDown(0), m_mouseRightUp(0) { m_mouseRightDragAnchor.x = 0; m_mouseRightDragAnchor.y = 0; m_mouseRightDragLift.x = 0; m_mouseRightDragLift.y = 0; } //==================================================================================== CommandTranslator::~CommandTranslator() { } //------------------------------------------------------------------------------------------------- GameMessage::Type CommandTranslator::evaluateForceAttack( Drawable *draw, const Coord3D *pos, CommandEvaluateType type ) { // evaluateForceAttack is used to determine whether or not we can force attack the // given target, and if we can, to issue the appropriate command. GameMessage::Type retVal = GameMessage::MSG_INVALID; if( !draw && !pos ) { return retVal; } const DrawableList *allSelected = TheInGameUI->getAllSelectedDrawables(); if( draw ) { Object *obj = draw ? draw->getObject() : NULL; if( !obj ) { return retVal; } CanAttackResult result = canAnyForceAttack( allSelected, obj, pos ); if( result == ATTACKRESULT_POSSIBLE || result == ATTACKRESULT_POSSIBLE_AFTER_MOVING ) { retVal = GameMessage::MSG_DO_FORCE_ATTACK_OBJECT; if( type == DO_COMMAND ) { pickAndPlayUnitVoiceResponse( allSelected, retVal ); GameMessage *newMsg = TheMessageStream->appendMessage( retVal ); newMsg->appendObjectIDArgument( obj->getID() ); } else if( type == DO_HINT ) { retVal = GameMessage::MSG_DO_FORCE_ATTACK_OBJECT_HINT; // Don't need the message back, cause there is nothing to append to it. TheMessageStream->appendMessage( retVal ); } } else if( result == ATTACKRESULT_INVALID_SHOT && type == DO_HINT ) { retVal = GameMessage::MSG_IMPOSSIBLE_ATTACK_HINT; TheMessageStream->appendMessage( retVal ); } } else if( pos ) { CanAttackResult result = canAnyForceAttack( allSelected, NULL, pos ); if( result == ATTACKRESULT_POSSIBLE || result == ATTACKRESULT_POSSIBLE_AFTER_MOVING ) { retVal = GameMessage::MSG_DO_FORCE_ATTACK_GROUND; if( type == DO_COMMAND ) { pickAndPlayUnitVoiceResponse( allSelected, retVal ); GameMessage *newMsg = TheMessageStream->appendMessage( retVal ); newMsg->appendLocationArgument( *pos ); } else if( type == DO_HINT ) { retVal = GameMessage::MSG_DO_FORCE_ATTACK_GROUND_HINT; // Don't need the message back, cause there is nothing to append to it. TheMessageStream->appendMessage( retVal ); } } else if( result == ATTACKRESULT_INVALID_SHOT && type == DO_HINT ) { retVal = GameMessage::MSG_IMPOSSIBLE_ATTACK_HINT; TheMessageStream->appendMessage( retVal ); } } return retVal; } // ------------------------------------------------------------------------------------------------ /** This method and the order of operations in the check here, determine what command would * actually happen (if type parameter == DO_COMMAND) if the user clicked on the drawable * 'draw'. If type == DO_HINT, then the user hasn't actually clicked, but has moused over * the drawable 'draw' and we want to generate a hint message as to what the actual * command would be if clicked * NOTE: draw can be NULL, in which case we give a hint for the location */ // ------------------------------------------------------------------------------------------------ GameMessage::Type CommandTranslator::evaluateContextCommand( Drawable *draw, const Coord3D *pos, CommandEvaluateType type ) { Object *obj = draw ? draw->getObject() : NULL; Drawable *drawableInWay = draw; //This piece of code is used to prevent interaction with unselectable objects or masked objects. When we //call this function, we typically pass in both a position and a drawable (if applicable), so if the //drawable is invalid... then convert it to a position to be evaluated instead. //Added: shrubberies are the exception for interactions... //Removed: GS Took out ObjectStatusUnselectable, since that status only prevents selection, not everything if( obj == NULL || obj->getStatusBits().test( OBJECT_STATUS_MASKED ) && !obj->isKindOf(KINDOF_SHRUBBERY) && !obj->isKindOf(KINDOF_FORCEATTACKABLE) ) { //Nulling out the draw and obj pointer will force the remainder of this code to evaluate //a position interaction. draw = NULL; obj = NULL; } // end if // If the thing is a mine, and is locally controlled, then we should issue a moveto to its location. if (obj && obj->isLocallyControlled() && obj->isKindOf(KINDOF_MINE)) { draw = NULL; obj = NULL; } if( TheInGameUI->isInForceMoveToMode() ) { //Nulling out the draw and obj pointer will force the remainder of this code to evaluate //a position interaction. draw = NULL; obj = NULL; } else if (TheInGameUI->isInForceAttackMode() ) { // setting the drawableInWay to draw will allow us to force attack in the issue move command // if there is a location to which we should attack. drawableInWay = draw; } GameMessage::Type msgType = GameMessage::MSG_INVALID; // Then we should determine if the game currently prefers selection events. If it does, then return // the invalid message. if (obj) { if (obj->isLocallyControlled() && TheInGameUI->isInPreferSelectionMode()) { return msgType; } } // Kris: Now that we can select non-controllable units/structures, don't allow any actions to be performed. const CommandButton *command = TheInGameUI->getGUICommand(); if( TheInGameUI->areSelectedObjectsControllable() || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT)) { GameMessage *hintMessage; if( TheInGameUI->isInWaypointMode() ) { //Override any *other* commands with waypoint commands. if( type == DO_COMMAND || type == EVALUATE_ONLY ) { if( TheTerrainLogic ) { msgType = issueMoveToLocationCommand( pos, draw, type ); } } else { msgType = GameMessage::MSG_ADD_WAYPOINT_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendLocationArgument( *pos ); } return msgType; } CanAttackResult result; if(command && (command->isContextCommand() || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT)) { if( obj && obj->isKindOf( KINDOF_SHRUBBERY ) && !BitTest( command->getOptions(), ALLOW_SHRUBBERY_TARGET ) ) { //If our object is a shrubbery, and we don't allow targetting it... then null it out. //Nulling out the draw and obj pointer will force the remainder of this code to evaluate //a position interaction. draw = NULL; obj = NULL; } if( obj && obj->isKindOf( KINDOF_MINE ) && !BitTest( command->getOptions(), ALLOW_MINE_TARGET ) ) { //If our object is a mine, and we don't allow targetting it... then null it out. //Nulling out the draw and obj pointer will force the remainder of this code to evaluate //a position interaction. draw = NULL; obj = NULL; } //Kris: September 27, 2002 //Added relationship tests to make sure we're not attempting a context-command on a restricted relationship. //This case prevents rebels from using tranq darts on allies. if( obj && BitTest( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) { Relationship relationship = ThePlayerList->getLocalPlayer()->getRelationship( obj->getTeam() ); switch( relationship ) { case ALLIES: if( !BitTest( command->getOptions(), NEED_TARGET_ALLY_OBJECT ) ) { draw = NULL; obj = NULL; } break; case ENEMIES: if( !BitTest( command->getOptions(), NEED_TARGET_ENEMY_OBJECT ) ) { draw = NULL; obj = NULL; } break; case NEUTRAL: if( !BitTest( command->getOptions(), NEED_TARGET_NEUTRAL_OBJECT ) ) { draw = NULL; obj = NULL; } break; } } Bool currentlyValid = FALSE; ObjectID objectID = obj ? obj->getID() : INVALID_ID; switch( command->getCommandType() ) { //Kris: June 06, 2002 //This is a GUI command button that triggers a mode. In any of these modes, only one specific action //can occur. If the mouse isn't over a valid target, then the conditions aren't met and the code will //cause an invalid version of the cursor to be shown -- and should the user click, the action won't take place. case GUICOMMANDMODE_CONVERT_TO_CARBOMB: currentlyValid = TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_CONVERT_OBJECT_TO_CARBOMB, obj, InGameUI::SELECTION_ANY ); break; case GUICOMMANDMODE_HIJACK_VEHICLE: currentlyValid = TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_HIJACK_VEHICLE, obj, InGameUI::SELECTION_ANY ); break; case GUICOMMANDMODE_SABOTAGE_BUILDING: currentlyValid = TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_SABOTAGE_BUILDING, obj, InGameUI::SELECTION_ANY ); break; #ifdef ALLOW_SURRENDER case GUICOMMANDMODE_PICK_UP_PRISONER: currentlyValid = TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_PICK_UP_PRISONER, obj, InGameUI::SELECTION_ANY ); break; #endif case GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT: { Object* unit = ThePlayerList->getLocalPlayer()->findMostReadyShortcutSpecialPowerOfType( command->getSpecialPowerTemplate()->getSpecialPowerType() ); if( unit ) currentlyValid = TheInGameUI->canSelectedObjectsDoSpecialPower( command, obj, pos, InGameUI::SELECTION_ANY, command->getOptions(), unit ); else currentlyValid = false; break; } case GUI_COMMAND_SPECIAL_POWER: currentlyValid = TheInGameUI->canSelectedObjectsDoSpecialPower( command, obj, pos, InGameUI::SELECTION_ANY, command->getOptions(), NULL ); break; case GUI_COMMAND_FIRE_WEAPON: currentlyValid = TheInGameUI->canSelectedObjectsEffectivelyUseWeapon( command, obj, pos, InGameUI::SELECTION_ANY ); break; case GUI_COMMAND_COMBATDROP: currentlyValid = !obj ? TRUE : TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_COMBATDROP_INTO, obj, InGameUI::SELECTION_ANY ); break; } if( currentlyValid ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { switch( command->getCommandType() ) { case GUICOMMANDMODE_CONVERT_TO_CARBOMB: case GUICOMMANDMODE_HIJACK_VEHICLE: case GUICOMMANDMODE_SABOTAGE_BUILDING: msgType = createEnterMessage( draw, type ); break; #ifdef ALLOW_SURRENDER case GUICOMMANDMODE_PICK_UP_PRISONER: msgType = issueAttackCommand( draw, type, command->getCommandType() ); break; #endif case GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT: { Object* unit = ThePlayerList->getLocalPlayer()->findMostReadyShortcutSpecialPowerOfType( command->getSpecialPowerTemplate()->getSpecialPowerType() ); if( unit ) msgType = issueSpecialPowerCommand( command, type, draw, pos, unit ); break; } case GUI_COMMAND_SPECIAL_POWER://lorenzen msgType = issueSpecialPowerCommand( command, type, draw, pos, NULL ); break; case GUI_COMMAND_FIRE_WEAPON: msgType = issueFireWeaponCommand( command, type, draw, pos ); break; case GUI_COMMAND_COMBATDROP: msgType = issueCombatDropCommand( command, type, draw, pos ); break; } // NULL out the GUI command if we're actually doing something if( type == DO_COMMAND ) { TheInGameUI->setGUICommand( NULL ); } } else { msgType = GameMessage::MSG_VALID_GUICOMMAND_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( objectID ); } } else // not currently valid { msgType = GameMessage::MSG_INVALID_GUICOMMAND_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( objectID ); } } // if a special power else if( command && (command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT_FROM_SHORTCUT) ) { //We're using the build placement interface to determine where to build our special power item. //Because of that, we only care about DO_COMMAND. The context evaluation and hint feedback system //is already taken care of. But what we need to do is trigger the special power to actually build //the object and reset the timer. if( type == DO_COMMAND ) { switch( command->getCommandType() ) { case GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT: { Object* unit = ThePlayerList->getLocalPlayer()->findMostReadyShortcutSpecialPowerOfType( command->getSpecialPowerTemplate()->getSpecialPowerType() ); if( unit ) msgType = issueSpecialPowerCommand( command, type, draw, pos, unit ); break; } case GUI_COMMAND_SPECIAL_POWER://lorenzen msgType = issueSpecialPowerCommand( command, type, draw, pos, NULL ); break; } } } // ******************************************************************************************** else if( TheInGameUI->canSelectedObjectsOverrideSpecialPowerDestination( pos, InGameUI::SELECTION_ANY, SPECIAL_INVALID ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // do the command msgType = GameMessage::MSG_DO_SPECIAL_POWER_OVERRIDE_DESTINATION; if( type == DO_COMMAND ) { GameMessage *gameMsg = TheMessageStream->appendMessage( msgType ); gameMsg->appendLocationArgument( *pos ); gameMsg->appendIntegerArgument( SPECIAL_INVALID ); gameMsg->appendObjectIDArgument( INVALID_ID ); // no specific source } // end if } // end if else { // generate a hint message msgType = GameMessage::MSG_DO_SPECIAL_POWER_OVERRIDE_DESTINATION_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); } // end else } // ******************************************************************************************** else if( draw && !TheInGameUI->isInForceAttackMode() && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_RESUME_CONSTRUCTION, obj, InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // do the command msgType = GameMessage::MSG_RESUME_CONSTRUCTION; if( type == DO_COMMAND ) { GameMessage *resumeMsg = TheMessageStream->appendMessage( msgType ); resumeMsg->appendObjectIDArgument( obj->getID() ); pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_RESUME_CONSTRUCTION ); } // end if } // end if else { // generate a hint message msgType = GameMessage::MSG_RESUME_CONSTRUCTION_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } // end else } // end else if // ******************************************************************************************** else if( draw && !TheInGameUI->isInForceAttackMode() && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_DOCK_AT, obj, InGameUI::SELECTION_ALL ) ) { // // The actual logic is simply to AIUpdate::dock with the target, the hint is the // only part that needs to be more specific. // if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // Give the dock command msgType = GameMessage::MSG_DOCK; if( type == DO_COMMAND ) { GameMessage *dockMsg = TheMessageStream->appendMessage( msgType ); dockMsg->appendObjectIDArgument( obj->getID() ); // only make sounds if we really did the command messages pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DOCK); } // end if } else { // make the hint msgType = GameMessage::MSG_DOCK_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } } // ******************************************************************************************** else if( draw && !TheInGameUI->isInForceAttackMode() && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_REPAIR_OBJECT, obj, InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // do the command msgType = GameMessage::MSG_DO_REPAIR; if( type == DO_COMMAND ) { GameMessage *healMsg = TheMessageStream->appendMessage( msgType ); healMsg->appendObjectIDArgument( obj->getID() ); pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_REPAIR ); } // end if } // end if else { // generate a hint message msgType = GameMessage::MSG_DO_REPAIR_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } // end else } // end else if // ******************************************************************************************** else if( draw && !TheInGameUI->isInForceAttackMode() && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_GET_REPAIRED_AT, obj, InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // do the command msgType = GameMessage::MSG_GET_REPAIRED; if( type == DO_COMMAND ) { GameMessage *healMsg = TheMessageStream->appendMessage( msgType ); healMsg->appendObjectIDArgument( obj->getID() ); pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_GET_REPAIRED ); } // end if } // end if else { // generate a hint message msgType = GameMessage::MSG_GET_REPAIRED_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } // end else } // end else if // ******************************************************************************************** else if( draw && !TheInGameUI->isInForceAttackMode() && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_GET_HEALED_AT, obj, InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // do the command msgType = GameMessage::MSG_GET_HEALED; if( type == DO_COMMAND ) { GameMessage *healMsg = TheMessageStream->appendMessage( msgType ); healMsg->appendObjectIDArgument( obj->getID() ); pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_GET_HEALED ); } // end if } // end if else { // generate hint message msgType = GameMessage::MSG_GET_HEALED_HINT; hintMessage = TheMessageStream->appendMessage( msgType); hintMessage->appendObjectIDArgument( obj->getID() ); } // end else } // end else if // ******************************************************************************************** else if( draw && draw->getObject() && !TheInGameUI->isInForceAttackMode() && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_HIJACK_VEHICLE, draw->getObject(), InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // Now, this just tricks the AI into making the hijacker run towards the target vehicle // I must add a test to keep him from actually entering an enemy vehicle (contained)... Lorenzen msgType = createEnterMessage( draw, type ); } // end if else { msgType = GameMessage::MSG_HIJACK_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( draw->getObject()->getID() ); } // end else } // end else if // ******************************************************************************************** else if( draw && !TheInGameUI->isInForceAttackMode() && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_CONVERT_OBJECT_TO_CARBOMB, obj, InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // issue the command (convert to carbomb is nearly identical to enter) msgType = createEnterMessage( draw, type ); } // end if else { msgType = GameMessage::MSG_CONVERT_TO_CARBOMB_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } // end else } // ******************************************************************************************** else if( draw && draw->getObject() && !TheInGameUI->isInForceAttackMode() && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_SABOTAGE_BUILDING, draw->getObject(), InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { msgType = createEnterMessage( draw, type ); } // end if else { msgType = GameMessage::MSG_SABOTAGE_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( draw->getObject()->getID() ); } // end else } // end else if // ******************************************************************************************** else if( draw && !TheInGameUI->isInForceAttackMode() && canSelectionSalvage(obj) ) { GameMessage *msg; if( type == DO_COMMAND || type == EVALUATE_ONLY ) { msgType = GameMessage::MSG_DO_SALVAGE; if (type == DO_COMMAND) { msg = TheMessageStream->appendMessage(msgType); msg->appendLocationArgument(*obj->getPosition()); pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), msgType); } } else { msgType = GameMessage::MSG_DO_SALVAGE_HINT; msg = TheMessageStream->appendMessage(msgType); msg->appendLocationArgument(*obj->getPosition()); } } // end else if // ******************************************************************************************** else if( draw && !TheInGameUI->isInForceAttackMode() && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_ENTER_OBJECT, obj, InGameUI::SELECTION_ANY, true ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // issue the command msgType = createEnterMessage( draw, type ); } // end if else { msgType = GameMessage::MSG_ENTER_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } // end else } // end else if // ******************************************************************************************** else if( draw && (result = TheInGameUI->getCanSelectedObjectsAttack( InGameUI::ACTIONTYPE_ATTACK_OBJECT, obj, InGameUI::SELECTION_ANY, TheInGameUI->isInForceAttackMode() )) == ATTACKRESULT_POSSIBLE ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // issue the attack order msgType = issueAttackCommand( draw, type ); } // end if else { // Generate an Attack hint msgType = GameMessage::MSG_DO_ATTACK_OBJECT_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } // end else } // end else if // ******************************************************************************************** else if( draw && result == ATTACKRESULT_POSSIBLE_AFTER_MOVING ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // issue the attack order msgType = issueAttackCommand( draw, type ); } // end if else { // Generate an Attack hint msgType = GameMessage::MSG_DO_ATTACK_OBJECT_AFTER_MOVING_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } // end else } // ******************************************************************************************** else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_CAPTURE_BUILDING, obj, InGameUI::SELECTION_ANY ) ) { //@TODO: Kris //PRELIMINARY CODE FOR HOOKING IN AUTO SPECIALS --- WILL BE REDONE! Object *source = TheInGameUI->getFirstSelectedDrawable()->getObject(); const CommandSet *set = TheControlBar->findCommandSet( source->getCommandSetString() ); if( set ) { for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ ) { // get command button const CommandButton *command = set->getCommandButton(i); if( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER ) { SpecialPowerType spType = command->getSpecialPowerTemplate()->getSpecialPowerType(); if( type == DO_COMMAND || type == EVALUATE_ONLY ) { if( spType == SPECIAL_BLACKLOTUS_CAPTURE_BUILDING || spType == SPECIAL_INFANTRY_CAPTURE_BUILDING ) { //Issue the capture building command msgType = issueSpecialPowerCommand( command, type, draw, pos, NULL ); break; } } else if( spType == SPECIAL_BLACKLOTUS_CAPTURE_BUILDING ) { //Issue the black lotus hack hint for capturing a building. msgType = GameMessage::MSG_HACK_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } else if( spType == SPECIAL_INFANTRY_CAPTURE_BUILDING ) { //Issue the infantry hint for capturing a building msgType = GameMessage::MSG_CAPTUREBUILDING_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } } } } } // end else if // ******************************************************************************************** else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_DISABLE_VEHICLE_VIA_HACKING, obj, InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { //@TODO: Kris //PRELIMINARY CODE FOR HOOKING IN AUTO SPECIALS --- WILL BE REDONE! Object *source = TheInGameUI->getFirstSelectedDrawable()->getObject(); const CommandSet *set = TheControlBar->findCommandSet( source->getCommandSetString() ); if( set ) { for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ ) { // get command button const CommandButton *command = set->getCommandButton(i); if( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER ) { SpecialPowerType spType = command->getSpecialPowerTemplate()->getSpecialPowerType(); if( spType == SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK ) { msgType = issueSpecialPowerCommand( command, type, draw, pos, NULL ); break; } } } } } else { msgType = GameMessage::MSG_HACK_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } } // end else if // ******************************************************************************************** else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_STEAL_CASH_VIA_HACKING, obj, InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { //@TODO: Kris //PRELIMINARY CODE FOR HOOKING IN AUTO SPECIALS --- WILL BE REDONE! Object *source = TheInGameUI->getFirstSelectedDrawable()->getObject(); const CommandSet *set = TheControlBar->findCommandSet( source->getCommandSetString() ); if( set ) { for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ ) { // get command button const CommandButton *command = set->getCommandButton(i); if( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER ) { SpecialPowerType spType = command->getSpecialPowerTemplate()->getSpecialPowerType(); if( spType == SPECIAL_BLACKLOTUS_STEAL_CASH_HACK ) { msgType = issueSpecialPowerCommand( command, type, draw, pos, NULL ); break; } } } } } // end if else { msgType = GameMessage::MSG_HACK_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } } // end else if // ******************************************************************************************** else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_DISABLE_BUILDING_VIA_HACKING, obj, InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { //@TODO: Kris //PRELIMINARY CODE FOR HOOKING IN AUTO SPECIALS --- WILL BE REDONE! Object *source = TheInGameUI->getFirstSelectedDrawable()->getObject(); const CommandSet *set = TheControlBar->findCommandSet( source->getCommandSetString() ); if( set ) { for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ ) { // get command button const CommandButton *command = set->getCommandButton(i); if( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER ) { SpecialPowerType spType = command->getSpecialPowerTemplate()->getSpecialPowerType(); if( spType == SPECIAL_HACKER_DISABLE_BUILDING ) { msgType = issueSpecialPowerCommand( command, type, draw, pos, NULL ); break; } } } } } // end if else { msgType = GameMessage::MSG_HACK_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } } // end else if #ifdef ALLOW_SURRENDER // ******************************************************************************************** else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_PICK_UP_PRISONER, obj, InGameUI::SELECTION_ANY ) ) { if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // issue the command msgType = issueAttackCommand( draw, type, GUICOMMANDMODE_PICK_UP_PRISONER ); } // end if else { msgType = GameMessage::MSG_PICK_UP_PRISONER_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendObjectIDArgument( obj->getID() ); } // end else } // end else if #endif // ******************************************************************************************** else if ( pos && !draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_SET_RALLY_POINT, NULL, InGameUI::SELECTION_ALL, FALSE )) { msgType = GameMessage::MSG_SET_RALLY_POINT; if (type == DO_COMMAND) { const DrawableList *allSelectedDrawables = TheInGameUI->getAllSelectedDrawables(); for (DrawableList::const_iterator it = allSelectedDrawables->begin(); it != allSelectedDrawables->end(); ++it) { Drawable *draw = (*it); if (draw && draw->getObject()) { GameMessage *newMsg = TheMessageStream->appendMessage(msgType); newMsg->appendObjectIDArgument(draw->getObject()->getID()); newMsg->appendLocationArgument(*pos); } } } else if (type == DO_HINT) { msgType = GameMessage::MSG_SET_RALLY_POINT_HINT; hintMessage = TheMessageStream->appendMessage(msgType); hintMessage->appendLocationArgument(*pos); } } // ******************************************************************************************** else if( draw && result == ATTACKRESULT_INVALID_SHOT ) { msgType = GameMessage::MSG_IMPOSSIBLE_ATTACK_HINT; hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendLocationArgument( *pos ); } // end else if // ******************************************************************************************** else { // // NOTE: If you change this command evaluation function in what it will do // if there is nothing picked ... you might want to edit the logic of the // selection translator in that you can only select objects if there is // no "interesting" command to do with the picked drawable ... which is determined // by what we return in this function by default // //Before we issue a move order or hint, check to see if we can even move there! Bool validQuickPath = FALSE; // Make sure to only to the check if the shroud is CLEARED. If it is fogged or shrouded, SKIP THE CHECK. jba [3/11/2003] if( ThePartitionManager->getShroudStatusForPlayer( ThePlayerList->getLocalPlayer()->getPlayerIndex(), pos ) != CELLSHROUD_CLEAR ) { //If it's in the shroud, pretend we can move there -- skip the check. validQuickPath = TRUE; } else { //Can we path there? const DrawableList *allSelectedDrawables = TheInGameUI->getAllSelectedDrawables(); for( DrawableList::const_iterator it = allSelectedDrawables->begin(); it != allSelectedDrawables->end(); ++it ) { Object *obj = (*it) ? (*it)->getObject() : NULL; AIUpdateInterface *ai = obj ? obj->getAI() : NULL; if( ai ) { if ( ai->isQuickPathAvailable( pos ) ) { validQuickPath = TRUE; break; } // Wait! there are some units that CAN moveTo positions that Quickpath will reject, // namely, Colonel Burton and the CombatBike. Both have CLIFF locomotors. // We must detect whether the position is valid for these, before just invalidating the cursor, // out of hand. if ( ai->hasLocomotorForSurface( LOCOMOTORSURFACE_CLIFF ) ) { if ( TheTerrainLogic->isCliffCell( pos->x, pos->y ) ) { validQuickPath = TRUE;// yeah, not really quick, but you know... break; } } } } } if( type == DO_COMMAND || type == EVALUATE_ONLY ) { // issue command // Note: If draw is valid, then its one of ours and we don't have something more specific // to do. Therefore, lets not issue a move command, and instead we'll return that there // wasn't a command for us to perform. if ( draw == NULL ) msgType = issueMoveToLocationCommand( pos, drawableInWay, type ); } // end if else { if( !validQuickPath ) { msgType = GameMessage::MSG_DO_INVALID_HINT; } else if( TheInGameUI->isInWaypointMode() ) { //Waypoint mode msgType = GameMessage::MSG_ADD_WAYPOINT_HINT; } else if( TheInGameUI->isInAttackMoveToMode() ) { //THIS CODE WILL NEVER EVER GET CALLED! -- it's a context command now (READ: rip code out) //Attack move msgType = GameMessage::MSG_DO_ATTACKMOVETO_HINT; } else { //Normal and forced move. msgType = GameMessage::MSG_DO_MOVETO_HINT; } hintMessage = TheMessageStream->appendMessage( msgType ); hintMessage->appendLocationArgument( *pos ); } // end else } // end else } // end if // return the message type return msgType; } // end evaluateContextCommand // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ //==================================================================================== /** * The Command Translator translates mouse events into object command messages * such as move_to, attack, etc. */ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage *msg) { GameMessage::Type t = msg->getType(); GameMessageDisposition disp = KEEP_MESSAGE; // We want to always be able to get to the options menu even during no input times and a clear game data message should always go through if (t != GameMessage::MSG_META_OPTIONS && t != GameMessage::MSG_CLEAR_GAME_DATA && !TheInGameUI->getInputEnabled() && !isSystemMessage(msg)) { return DESTROY_MESSAGE; } #if defined(_DEBUG) || defined(_INTERNAL) ExtentModType extentModType = EXTENTMOD_INVALID; Real extentModAmount = 0.0f; #endif switch (t) { //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_SELECT_MATCHING_UNITS: { TheInGameUI->selectUnitsMatchingCurrentSelection(); disp = DESTROY_MESSAGE; break; } //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_SELECT_NEXT_UNIT: { /* because list is prepended, iterate through backwards */ // if there is nothing on the screen, bail if( TheGameClient->firstDrawable() == NULL ) break; // if nothing is selected Drawable *temp; if( TheInGameUI->getSelectCount() == 0 ) { // get the last drawable for( temp = TheGameClient->firstDrawable(); temp->getNextDrawable() != NULL; temp = temp->getNextDrawable() ) { } // temp is the last drawable for( temp; temp != NULL; temp = temp->getPrevDrawable() ) { const Object *object = temp->getObject(); // if you've reached the end of the list, don't select anything if( !object ) { break; } else if( object && object->isMobile() && object->isLocallyControlled() && !object->isContained() && !object->isKindOf( KINDOF_NO_SELECT ) ) { // create a new group. GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); //New group or add to group? Passed in value is true if we are creating a new group. teamMsg->appendBooleanArgument( TRUE ); teamMsg->appendObjectIDArgument( object->getID() ); TheInGameUI->selectDrawable( temp ); // center on the unit TheTacticalView->lookAt(temp->getPosition()); break; } } } else { Drawable *newDrawable = NULL; Bool hack = FALSE; Drawable *selectedDrawable = TheInGameUI->getFirstSelectedDrawable(); Object *selectedObject = selectedDrawable->getObject(); if( selectedObject->isLocallyControlled() ) { // find the previous selectable drawable temp = selectedDrawable->getPrevDrawable(); //temp = selectedDrawable; for( ; temp != selectedDrawable; temp = temp->getPrevDrawable() ) { if( hack == TRUE ) { temp = temp->getNextDrawable(); hack = FALSE; } // if temp is null, set it to the last drawable and loop back to selected drawable if( temp == NULL ) { for(temp = selectedDrawable; temp->getNextDrawable() != NULL; temp = temp->getNextDrawable() ) { } hack = TRUE; } // else search for a previous selectable drawable else { const Object *tempObject = temp->getObject(); if( tempObject && tempObject->isMobile() && tempObject->isLocallyControlled() && !tempObject->isContained() && !tempObject->isKindOf( KINDOF_NO_SELECT ) ) { newDrawable = temp; break; //temp = selectedDrawable; // same as break } } } //if there is another selectable unit, select it if(newDrawable != NULL ) { //deselect other units TheInGameUI->deselectAllDrawables(); // create a new group. GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); //New group or add to group? Passed in value is true if we are creating a new group. teamMsg->appendBooleanArgument( TRUE ); teamMsg->appendObjectIDArgument( newDrawable->getObject()->getID() ); // select the unit TheInGameUI->selectDrawable( newDrawable ); // center on the unit TheTacticalView->lookAt(newDrawable->getPosition()); } } } disp = DESTROY_MESSAGE; break; } //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_SELECT_PREV_UNIT: { /* because list is prepended, iterate through forwards */ // if there is nothing on the screen, bail if( TheGameClient->firstDrawable() == NULL ) break; Drawable *temp; // if nothing is selected if( TheInGameUI->getSelectCount() == 0 ) { // get the first drawable temp = TheGameClient->firstDrawable(); for( temp; temp != NULL; temp = temp->getPrevDrawable() ) { const Object *object = temp->getObject(); // if you've reached the end of the list, don't select anything if( !object ) { break; } else if( object && object->isMobile() && object->isLocallyControlled() && !object->isContained() && !object->isKindOf( KINDOF_NO_SELECT ) ) { // create a new group. GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); //New group or add to group? Passed in value is true if we are creating a new group. teamMsg->appendBooleanArgument( TRUE ); teamMsg->appendObjectIDArgument( object->getID() ); TheInGameUI->selectDrawable( temp ); // center on the unit TheTacticalView->lookAt(temp->getPosition()); break; } } } else { Drawable *newDrawable = NULL; TheGameClient->getDrawableList(); Bool hack = FALSE; // takes care of when for loop skips firstdrawable Drawable *selectedDrawable = TheInGameUI->getFirstSelectedDrawable(); Object *selectedObject = selectedDrawable->getObject(); if( selectedObject->isLocallyControlled() ) { // find the next selectable drawable temp = selectedDrawable->getNextDrawable(); //temp = selectedDrawable; for( temp; temp != selectedDrawable; temp = temp->getNextDrawable() ) { if( hack == TRUE ) { temp = TheGameClient->firstDrawable(); hack = FALSE; if( temp == selectedDrawable ) { break; } } // if temp is null, set it to the first drawable and loop forward to selected drawable if( temp == NULL ) { temp = TheGameClient->firstDrawable(); hack = TRUE; const Object *tempObject = temp->getObject(); // must take case of this case here or else the loop will break without getting newDrawable if( tempObject && temp->getNextDrawable() == selectedDrawable && !temp->isSelected() && tempObject->isMobile() && tempObject->isLocallyControlled() && !tempObject->isContained() && !tempObject->isKindOf( KINDOF_NO_SELECT ) ) { newDrawable = temp; break; } } // else search for a next selectable drawable else { const Object *tempObject = temp->getObject(); if( tempObject && !temp->isSelected() && tempObject->isMobile() && tempObject->isLocallyControlled() && !tempObject->isContained() ) { newDrawable = temp; break; } } } //if there is another selectable unit, select it if(newDrawable != NULL ) { //deselect other units TheInGameUI->deselectAllDrawables(); // select the unit // create a new group. GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); //New group or add to group? Passed in value is true if we are creating a new group. teamMsg->appendBooleanArgument( TRUE ); teamMsg->appendObjectIDArgument( newDrawable->getObject()->getID() ); TheInGameUI->selectDrawable( newDrawable ); // center on the unit TheTacticalView->lookAt(newDrawable->getPosition()); } } } disp = DESTROY_MESSAGE; break; } // end select previous unit //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_SELECT_NEXT_WORKER: { /* because list is prepended, iterate through backwards */ // if there is nothing on the screen, bail if( TheGameClient->firstDrawable() == NULL ) break; Drawable *temp; // if nothing is selected if( TheInGameUI->getSelectCount() == 0 ) { // get the last drawable for( temp = TheGameClient->firstDrawable(); temp->getNextDrawable() != NULL; temp = temp->getNextDrawable() ) { } // temp is the last drawable for( temp; temp != NULL; temp = temp->getPrevDrawable() ) { const Object *object = temp->getObject(); // if you've reached the end of the list, don't select anything if( !object ) { break; } // make sure you select only workers else if( object && object->isLocallyControlled() && !object->isContained() && object->isKindOf(KINDOF_DOZER) ) { // create a new group. GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); //New group so pass in value true teamMsg->appendBooleanArgument( TRUE ); teamMsg->appendObjectIDArgument( object->getID() ); TheInGameUI->selectDrawable( temp ); // play the units sound AudioEventRTS soundEvent = *temp->getTemplate()->getVoiceSelect(); soundEvent.setObjectID(object->getID()); TheAudio->addAudioEvent( &soundEvent ); // center on the unit TheTacticalView->lookAt(temp->getPosition()); break; } } } else { Drawable *newDrawable = NULL; Bool hack = FALSE; Drawable *selectedDrawable = TheInGameUI->getFirstSelectedDrawable(); Object *selectedObject = selectedDrawable->getObject(); if( selectedObject->isLocallyControlled() ) { // find the previous selectable drawable temp = selectedDrawable->getPrevDrawable(); //temp = selectedDrawable; for( ; temp != selectedDrawable; temp = temp->getPrevDrawable() ) { if( hack == TRUE ) { temp = temp->getNextDrawable(); hack = FALSE; } // if temp is null, set it to the last drawable and loop back to selected drawable if( temp == NULL ) { for(temp = selectedDrawable; temp->getNextDrawable() != NULL; temp = temp->getNextDrawable() ) { } hack = TRUE; } // else search for a previous selectable drawable else { const Object *tempObject = temp->getObject(); if( tempObject && tempObject->isLocallyControlled() && !tempObject->isContained() && tempObject->isKindOf( KINDOF_DOZER ) ) { newDrawable = temp; break; //temp = selectedDrawable; // same as break } } } //if there is another selectable unit, select it if(newDrawable != NULL ) { //deselect other units TheInGameUI->deselectAllDrawables(); // select the unit // create a new group. GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); //New group so pass in value true teamMsg->appendBooleanArgument( TRUE ); teamMsg->appendObjectIDArgument( newDrawable->getObject()->getID() ); TheInGameUI->selectDrawable( newDrawable ); // center on the unit TheTacticalView->lookAt(newDrawable->getPosition()); } } } disp = DESTROY_MESSAGE; break; } // end select next worker //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_SELECT_PREV_WORKER: { /* because list is prepended, iterate through forwards */ // if there is nothing on the screen, bail if( TheGameClient->firstDrawable() == NULL ) break; Drawable *temp; // if nothing is selected if( TheInGameUI->getSelectCount() == 0 ) { // get the first drawable temp = TheGameClient->firstDrawable(); for( temp; temp != NULL; temp = temp->getPrevDrawable() ) { const Object *object = temp->getObject(); // if you've reached the end of the list, don't select anything if( !object ) { break; } else if( object && object->isMobile() && object->isLocallyControlled() && !object->isContained() && object->isKindOf( KINDOF_DOZER )) { // create a new group. GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); //New group or add to group? Passed in value is true if we are creating a new group. teamMsg->appendBooleanArgument( TRUE ); teamMsg->appendObjectIDArgument( object->getID() ); TheInGameUI->selectDrawable( temp ); // center on the unit TheTacticalView->lookAt(temp->getPosition()); break; } } } else { Drawable *newDrawable = NULL; TheGameClient->getDrawableList(); Bool hack = FALSE; // takes care of when for loop skips firstdrawable Drawable *selectedDrawable = TheInGameUI->getFirstSelectedDrawable(); Object *selectedObject = selectedDrawable->getObject(); if( selectedObject->isLocallyControlled() ) { // find the next selectable drawable temp = selectedDrawable->getNextDrawable(); //temp = selectedDrawable; for( temp; temp != selectedDrawable; temp = temp->getNextDrawable() ) { if( hack == TRUE ) { temp = TheGameClient->firstDrawable(); hack = FALSE; if( temp == selectedDrawable ) { break; } } // if temp is null, set it to the first drawable and loop forward to selected drawable if( temp == NULL ) { temp = TheGameClient->firstDrawable(); hack = TRUE; const Object *tempObject = temp->getObject(); // must take case of this case here or else the loop will break without getting newDrawable if( tempObject && temp->getNextDrawable() == selectedDrawable && !temp->isSelected() && tempObject->isMobile() && tempObject->isLocallyControlled() && !tempObject->isContained() ) { newDrawable = temp; break; } } // else search for a next selectable drawable else { const Object *tempObject = temp->getObject(); if( tempObject && !temp->isSelected() && tempObject->isMobile() && tempObject->isLocallyControlled() && !tempObject->isContained() && tempObject->isKindOf( KINDOF_DOZER ) ) { newDrawable = temp; break; } } } //if there is another selectable unit, select it if(newDrawable != NULL ) { //deselect other units TheInGameUI->deselectAllDrawables(); // select the unit // create a new group. GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); //New group so passed in value true teamMsg->appendBooleanArgument( TRUE ); teamMsg->appendObjectIDArgument( newDrawable->getObject()->getID() ); TheInGameUI->selectDrawable( newDrawable ); // center on the unit TheTacticalView->lookAt(newDrawable->getPosition()); } } } disp = DESTROY_MESSAGE; break; } // end select previous worker //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_SELECT_HERO: { // if there is nothing on the screen, bail if( TheGameClient->firstDrawable() == NULL ) break; Object *hero = iNeedAHero(); if ( hero == NULL ) break; if ( hero->isContained() ) hero = hero->getContainedBy(); Drawable *heroDraw = hero->getDrawable(); if ( heroDraw == NULL ) break; TheInGameUI->deselectAllDrawables(); // create a new group. GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); //New group so pass in value true teamMsg->appendBooleanArgument( TRUE ); teamMsg->appendObjectIDArgument( hero->getID() ); TheInGameUI->selectDrawable( heroDraw ); // center on the unit TheTacticalView->lookAt(heroDraw->getPosition()); disp = DESTROY_MESSAGE; break; } //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_VIEW_COMMAND_CENTER: viewCommandCenter(); disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_VIEW_LAST_RADAR_EVENT: { // Player *player = ThePlayerList->getLocalPlayer(); // if the local player has a radar, center on last event (if any) // Excuse me? You don't need radar for the spacebar. That's silly. // if( TheRadar->isRadarForced() || ( TheRadar->isRadarHidden() == false && player->hasRadar() ) ) { Coord3D lastEvent; if( TheRadar->getLastEventLoc( &lastEvent ) ) TheTacticalView->lookAt( &lastEvent ); } // end if disp = DESTROY_MESSAGE; break; } // end view last radar event //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_SELECT_ALL: case GameMessage::MSG_META_SELECT_ALL_AIRCRAFT: { KindOfMaskType requiredKindofs; KindOfMaskType disqualifyingKindofs; disqualifyingKindofs.set(KINDOF_DOZER); disqualifyingKindofs.set(KINDOF_HARVESTER); disqualifyingKindofs.set(KINDOF_IGNORES_SELECT_ALL); Bool selectAircraft = FALSE; if( t == GameMessage::MSG_META_SELECT_ALL_AIRCRAFT ) { requiredKindofs.set(KINDOF_AIRCRAFT); selectAircraft = TRUE; } //Kris: Patch 1.03. We need to deselect all the units if any of the units we have selected //are incompatible with the select all type we are triggering. This is a fix for the SCUDSTORM //exploit. const DrawableList *drawList = TheInGameUI->getAllSelectedDrawables(); Drawable *draw; for( DrawableListCIt it = drawList->begin(); it != drawList->end(); ++it ) { draw = *it; if( selectAircraft && (draw->isAnyKindOf( disqualifyingKindofs ) || !draw->isKindOf( KINDOF_AIRCRAFT )) ) { TheInGameUI->deselectAllDrawables(); break; } else if( !selectAircraft && (draw->isAnyKindOf( disqualifyingKindofs ) || draw->isKindOf( KINDOF_STRUCTURE )) ) { TheInGameUI->deselectAllDrawables(); break; } } TheInGameUI->selectAllUnitsByType(requiredKindofs, disqualifyingKindofs); disp = DESTROY_MESSAGE; break; /* TheInGameUI->deselectAllDrawables(); GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); // creating a new team so pass in true teamMsg->appendBooleanArgument( TRUE ); // just loop through all the drawables in the world Drawable *draw = TheGameClient->firstDrawable(); while( draw ) { const Object *object = draw->getObject(); //Only select the object if it is locally controlled and not contained by anything. KindOfMaskType disqualifyingKindofs; disqualifyingKindofs.set(KINDOF_DOZER); disqualifyingKindofs.set(KINDOF_HARVESTER); disqualifyingKindofs.set(KINDOF_IGNORES_SELECT_ALL); if( object && object->isMobile() && object->isLocallyControlled() && !object->isContained() && !object->isAnyKindOf( disqualifyingKindofs ) && !object->isEffectivelyDead() && object->isMassSelectable() ) { // enforce optional unit cap if (TheInGameUI->getMaxSelectCount() > 0 && TheInGameUI->getSelectCount() >= TheInGameUI->getMaxSelectCount()) { if ( !TheInGameUI->getDisplayedMaxWarning() ) { TheInGameUI->setDisplayedMaxWarning( TRUE ); UnicodeString msg; msg.format(TheGameText->fetch("GUI:MaxSelectionSize").str(), TheInGameUI->getMaxSelectCount()); TheInGameUI->message(msg); } } else { TheInGameUI->selectDrawable(draw); teamMsg->appendObjectIDArgument( draw->getObject()->getID() ); TheInGameUI->setDisplayedMaxWarning( FALSE ); } } draw = draw->getNextDrawable(); } if( TheInGameUI->getSelectCount() ) { UnicodeString message = TheGameText->fetch( "GUI:SelectedAcrossMap" ); TheInGameUI->message( message ); } disp = DESTROY_MESSAGE; break; */ } // end select all //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_SCATTER: // This message always works on the currently selected team TheMessageStream->appendMessage(GameMessage::MSG_DO_SCATTER); disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_STOP: // This message always works on the currently selected team TheMessageStream->appendMessage(GameMessage::MSG_DO_STOP); disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_CREATE_FORMATION: // This message always works on the currently selected team TheMessageStream->appendMessage(GameMessage::MSG_CREATE_FORMATION); disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEPLOY: #ifdef _DEBUG DEBUG_ASSERTCRASH(FALSE, ("unimplemented meta command MSG_META_DEPLOY !")); #endif /// @todo srj implement me disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_FOLLOW: #ifdef _DEBUG DEBUG_ASSERTCRASH(FALSE, ("unimplemented meta command MSG_META_FOLLOW !")); #endif /// @todo srj implement me disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- /* MDC - no such thing as chat to players right now - not until we have a diplomacy screen case GameMessage::MSG_META_CHAT_PLAYERS: if (TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInReplayGame()) { ToggleInGameChat(); SetInGameChatType( INGAME_CHAT_PLAYERS ); } disp = DESTROY_MESSAGE; break; */ //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_CHAT_ALLIES: if (TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInReplayGame()) { Player *localPlayer = ThePlayerList->getLocalPlayer(); if (localPlayer && localPlayer->isPlayerActive() || !TheGlobalData->m_netMinPlayers) { ToggleInGameChat(); SetInGameChatType( INGAME_CHAT_ALLIES ); } } disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_CHAT_EVERYONE: if (TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInReplayGame()) { Player *localPlayer = ThePlayerList->getLocalPlayer(); if (localPlayer && localPlayer->isPlayerActive() || !TheGlobalData->m_netMinPlayers) { ToggleInGameChat(); SetInGameChatType( INGAME_CHAT_EVERYONE ); } } disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DIPLOMACY: if (TheGameLogic->isInGame() && !TheGameLogic->isInShellGame()) { ToggleDiplomacy( FALSE ); } else if( TheShell && TheShell->isShellActive() && TheGameSpyBuddyMessageQueue) GameSpyToggleOverlay(GSOVERLAY_BUDDY); disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_PLACE_BEACON: if (TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInReplayGame() && ThePlayerList->getLocalPlayer()->isPlayerActive() && (TheGlobalData->m_netMinPlayers==0 || TheGameInfo->isMultiPlayer())) { Int count; const ThingTemplate *thing = TheThingFactory->findTemplate( ThePlayerList->getLocalPlayer()->getPlayerTemplate()->getBeaconTemplate() ); ThePlayerList->getLocalPlayer()->countObjectsByThingTemplate( 1, &thing, false, &count ); DEBUG_LOG(("MSG_META_PLACE_BEACON - Player already has %d beacons active\n", count)); if (count < TheMultiplayerSettings->getMaxBeaconsPerPlayer()) { const CommandButton *commandButton = TheControlBar->findCommandButton( "Command_PlaceBeacon" ); TheInGameUI->setGUICommand( commandButton ); } } disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_REMOVE_BEACON: if (TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInReplayGame()) { TheMessageStream->appendMessage( GameMessage::MSG_REMOVE_BEACON ); } disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_OPTIONS: ToggleQuitMenu(); disp = DESTROY_MESSAGE; break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_TOGGLE_LOWER_DETAILS: { if (TheGlobalData) { static Bool isLowDetails = FALSE; static Bool oldShadowVolumsValue = TRUE; static Bool oldLightMapValue = TRUE; static Bool oldCloudMap = TRUE; static Bool oldBehindBuildingMarkers = TRUE; static Int oldMaxParticleCount = 0; if(isLowDetails) { TheWritableGlobalData->m_useShadowVolumes = oldShadowVolumsValue; TheWritableGlobalData->m_useLightMap = oldLightMapValue; TheWritableGlobalData->m_useCloudMap = oldCloudMap; TheWritableGlobalData->m_maxParticleCount = oldMaxParticleCount; TheGameLogic->setShowBehindBuildingMarkers(oldBehindBuildingMarkers); if(TheInGameUI) TheInGameUI->message("GUI:ReturnGraphicsToPreviousSettings"); } else { oldShadowVolumsValue = TheGlobalData->m_useShadowVolumes; TheWritableGlobalData->m_useShadowVolumes = FALSE; oldLightMapValue = TheGlobalData->m_useLightMap; TheWritableGlobalData->m_useLightMap = FALSE; oldCloudMap = TheGlobalData->m_useCloudMap; TheWritableGlobalData->m_useCloudMap = FALSE; oldBehindBuildingMarkers = TheGameLogic->getShowBehindBuildingMarkers(); TheGameLogic->setShowBehindBuildingMarkers(FALSE); oldMaxParticleCount = TheGlobalData->m_maxParticleCount; TheWritableGlobalData->m_maxParticleCount = DROPPED_MAX_PARTICLE_COUNT; if(TheInGameUI) TheInGameUI->message("GUI:DetailsSetToLowest"); } } disp = DESTROY_MESSAGE; break; } //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_TOGGLE_CONTROL_BAR: { if(TheShell->isShellActive()) { WindowLayout *win = TheShell->top(); if(win) { win->hide(!win->isHidden()); } } else { if (!(TheRecorder && TheRecorder->getMode() == RECORDERMODETYPE_PLAYBACK)) { Bool hide = false; if (TheWindowManager) { Int id = (Int)TheNameKeyGenerator->nameToKey(AsciiString("ControlBar.wnd:ControlBarParent")); GameWindow *window = TheWindowManager->winGetWindowFromId(NULL, id); if (window) hide = !window->winIsHidden(); } ToggleControlBar(); } } disp = DESTROY_MESSAGE; break; } //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_TOGGLE_ATTACKMOVE: TheInGameUI->toggleAttackMoveToMode( ); break; case GameMessage::MSG_META_BEGIN_CAMERA_ROTATE_LEFT: DEBUG_ASSERTCRASH(!TheInGameUI->isCameraRotatingLeft(), ("Setting rotate camera left, but it's already set!")); TheInGameUI->setCameraRotateLeft( true ); break; case GameMessage::MSG_META_END_CAMERA_ROTATE_LEFT: DEBUG_ASSERTCRASH(TheInGameUI->isCameraRotatingLeft(), ("Clearing rotate camera left, but it's already clear!")); TheInGameUI->setCameraRotateLeft( false ); break; case GameMessage::MSG_META_BEGIN_CAMERA_ROTATE_RIGHT: DEBUG_ASSERTCRASH(!TheInGameUI->isCameraRotatingRight(), ("Setting rotate camera right, but it's already set!")); TheInGameUI->setCameraRotateRight( true ); break; case GameMessage::MSG_META_END_CAMERA_ROTATE_RIGHT: DEBUG_ASSERTCRASH(TheInGameUI->isCameraRotatingRight(), ("Clearing rotate camera right, but it's already clear!")); TheInGameUI->setCameraRotateRight( false ); break; case GameMessage::MSG_META_BEGIN_CAMERA_ZOOM_IN: DEBUG_ASSERTCRASH(!TheInGameUI->isCameraZoomingIn(), ("Setting zoom camera in, but it's already set!")); TheInGameUI->setCameraZoomIn( true ); break; case GameMessage::MSG_META_END_CAMERA_ZOOM_IN: DEBUG_ASSERTCRASH(TheInGameUI->isCameraZoomingIn(), ("Clearing zoom camera in, but it's already clear!")); TheInGameUI->setCameraZoomIn( false ); break; case GameMessage::MSG_META_BEGIN_CAMERA_ZOOM_OUT: DEBUG_ASSERTCRASH(!TheInGameUI->isCameraZoomingOut(), ("Setting zoom camera out, but it's already set!")); TheInGameUI->setCameraZoomOut( true ); break; case GameMessage::MSG_META_END_CAMERA_ZOOM_OUT: DEBUG_ASSERTCRASH(TheInGameUI->isCameraZoomingOut(), ("Clearing zoom camera out, but it's already clear!")); TheInGameUI->setCameraZoomOut( false ); break; case GameMessage::MSG_META_CAMERA_RESET: TheInGameUI->resetCamera(); break; case GameMessage::MSG_META_TOGGLE_CAMERA_TRACKING_DRAWABLE: TheInGameUI->setCameraTrackingDrawable( true ); break; //-------------------------------------------------------------------------------------- case GameMessage::MSG_META_TOGGLE_FAST_FORWARD_REPLAY: { if( TheGlobalData ) { #if !defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)//may be defined in GameCommon.h if (TheGameLogic->isInReplayGame()) #endif { TheWritableGlobalData->m_TiVOFastMode = 1 - TheGlobalData->m_TiVOFastMode; TheInGameUI->message( UnicodeString( L"m_TiVOFastMode: %s" ), TheGlobalData->m_TiVOFastMode ? L"ON" : L"OFF" ); } } // end if disp = DESTROY_MESSAGE; break; } // end toggle special power delays #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)//may be defined in GameCommon.h case GameMessage::MSG_CHEAT_RUNSCRIPT1: case GameMessage::MSG_CHEAT_RUNSCRIPT2: case GameMessage::MSG_CHEAT_RUNSCRIPT3: case GameMessage::MSG_CHEAT_RUNSCRIPT4: case GameMessage::MSG_CHEAT_RUNSCRIPT5: case GameMessage::MSG_CHEAT_RUNSCRIPT6: case GameMessage::MSG_CHEAT_RUNSCRIPT7: case GameMessage::MSG_CHEAT_RUNSCRIPT8: case GameMessage::MSG_CHEAT_RUNSCRIPT9: { if ( !TheGameLogic->isInMultiplayerGame() ) { if( TheScriptEngine ) { Int script = t - GameMessage::MSG_CHEAT_RUNSCRIPT1 + 1; AsciiString scriptName; scriptName.format("KEY_F%d", script); TheScriptEngine->runScript(scriptName); } disp = DESTROY_MESSAGE; } break; } //-------------------------------------------------------------------------------------- case GameMessage::MSG_CHEAT_TOGGLE_SPECIAL_POWER_DELAYS: { if ( !TheGameLogic->isInMultiplayerGame() ) { if( TheGlobalData ) { TheWritableGlobalData->m_specialPowerUsesDelay = 1 - TheGlobalData->m_specialPowerUsesDelay; TheInGameUI->message( UnicodeString( L"Special Power (Superweapon) Delay: %s" ), TheGlobalData->m_specialPowerUsesDelay ? L"ON" : L"OFF" ); } // end if disp = DESTROY_MESSAGE; } break; } // end toggle special power delays //-------------------------------------------------------------------------------------- case GameMessage::MSG_CHEAT_SWITCH_TEAMS: { if ( !TheGameLogic->isInMultiplayerGame() ) { if (TheGameLogic->isInGame()) { Int idx; for (Int i = 0; i < ThePlayerList->getPlayerCount(); i++) { if (ThePlayerList->getNthPlayer(i) == ThePlayerList->getLocalPlayer()) { idx = i; break; } } Int idxOrig = idx; do { ++idx; if (idx >= ThePlayerList->getPlayerCount()) idx = 0; if (idx == idxOrig) break; } while (ThePlayerList->getNthPlayer(idx) == ThePlayerList->getNeutralPlayer()); ThePlayerList->setLocalPlayer(ThePlayerList->getNthPlayer(idx)); TheInGameUI->deselectAllDrawables(); #ifdef DEBUG_FOG_MEMORY TheGhostObjectManager->setLocalPlayerIndex(idx); #endif ThePartitionManager->refreshShroudForLocalPlayer(); TheControlBar->initSpecialPowershortcutBar(ThePlayerList->getLocalPlayer()); TheControlBar->setControlBarSchemeByPlayer(ThePlayerList->getLocalPlayer()); TheGameClient->updateFakeDrawables(); } disp = DESTROY_MESSAGE; } break; } //-------------------------------------------------------------------------------------- case GameMessage::MSG_CHEAT_KILL_SELECTION: { if ( !TheGameLogic->isInMultiplayerGame() ) { // THIS CALLS THE STANDARD DEBUG MESSAGE, WHICH IS CALLED: TheMessageStream->appendMessage( GameMessage::MSG_DEBUG_KILL_SELECTION ); disp = DESTROY_MESSAGE; } break; } case GameMessage::MSG_CHEAT_INSTANT_BUILD: { if ( !TheGameLogic->isInMultiplayerGame() ) { // Doesn't make a valid network message Player *localPlayer = ThePlayerList->getLocalPlayer(); localPlayer->toggleInstantBuild(); disp = DESTROY_MESSAGE; } break; } case GameMessage::MSG_CHEAT_ADD_CASH: { if ( !TheGameLogic->isInMultiplayerGame() ) { Player *localPlayer = ThePlayerList->getLocalPlayer(); Money *money = localPlayer->getMoney(); money->deposit( 10000 ); } break; } case GameMessage::MSG_CHEAT_GIVE_ALL_SCIENCES: { if ( !TheGameLogic->isInMultiplayerGame() ) { Player *player = ThePlayerList->getLocalPlayer(); if (player) { // cheese festival: do NOT imitate this code. it is for debug purposes only. std::vector v = TheScienceStore->friend_getScienceNames(); for (int i = 0; i < v.size(); ++i) { ScienceType st = TheScienceStore->getScienceFromInternalName(v[i]); if (st != SCIENCE_INVALID && TheScienceStore->isScienceGrantable(st)) { player->grantScience(st); } } } TheInGameUI->message( UnicodeString( L"Granting all sciences!" )); disp = DESTROY_MESSAGE; } break; } case GameMessage::MSG_CHEAT_GIVE_SCIENCEPURCHASEPOINTS: { if ( !TheGameLogic->isInMultiplayerGame() ) { Player *player = ThePlayerList->getLocalPlayer(); if (player) player->addSciencePurchasePoints(1); TheInGameUI->message( UnicodeString( L"Adding a SciencePurchasePoint" )); disp = DESTROY_MESSAGE; } break; } case GameMessage::MSG_CHEAT_SHOW_HEALTH: { if ( !TheGameLogic->isInMultiplayerGame() ) { TheWritableGlobalData->m_showObjectHealth = 1 - TheGlobalData->m_showObjectHealth; TheInGameUI->message( UnicodeString( L"Object Health %s" ), TheGlobalData->m_showObjectHealth ? L"ON" : L"OFF" ); } break; } case GameMessage::MSG_CHEAT_TOGGLE_MESSAGE_TEXT: { if ( !TheGameLogic->isInMultiplayerGame() ) { // toggle the message state TheInGameUI->toggleMessages(); // when messages get turned on, display a message if( TheInGameUI->isMessagesOn() ) TheInGameUI->message( TheGameText->fetch( "GUI:MessagesOn" ) ); disp = DESTROY_MESSAGE; } break; } // end clear message text #endif //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_BEGIN_FORCEMOVE: DEBUG_ASSERTCRASH(!TheInGameUI->isInForceMoveToMode(), ("forceMoveToMode mismatch")); TheInGameUI->setForceMoveMode( true ); break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_END_FORCEMOVE: DEBUG_ASSERTCRASH(TheInGameUI->isInForceMoveToMode(), ("forceMoveToMode mismatch")); TheInGameUI->setForceMoveMode( false ); break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_BEGIN_WAYPOINTS: // DEBUG_ASSERTCRASH( !TheInGameUI->isInWaypointMode(), ("Setting m_waypointMode but it's already set!") ); TheInGameUI->setWaypointMode( true ); break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_BEGIN_PREFER_SELECTION: TheInGameUI->setPreferSelectionMode( true ); break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_END_PREFER_SELECTION: TheInGameUI->setPreferSelectionMode( false ); break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_END_WAYPOINTS: // DEBUG_ASSERTCRASH( TheInGameUI->isInWaypointMode(), ("Clearing m_waypointMode but it's already clear!") ); TheInGameUI->setWaypointMode( false ); break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_BEGIN_FORCEATTACK: TheInGameUI->setForceAttackMode( true ); break; //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_END_FORCEATTACK: TheInGameUI->setForceAttackMode( false ); break; // -------------------------------------------------------------------------------------------- case GameMessage::MSG_META_ALL_CHEER: { if ( TheGameLogic->isInMultiplayerGame() ) { TheAudio->addAudioEvent(&TheAudio->getMiscAudio()->m_allCheerSound); disp = DESTROY_MESSAGE; TheMessageStream->appendMessage( GameMessage::MSG_DO_CHEER ); } break; } // -------------------------------------------------------------------------------------------- case GameMessage::MSG_META_TAKE_SCREENSHOT: { if (TheDisplay) TheDisplay->takeScreenShot(); disp = DESTROY_MESSAGE; break; } // -------------------------------------------------------------------------------------------- case GameMessage::MSG_CREATE_SELECTED_GROUP: case GameMessage::MSG_SELECT_TEAM0: case GameMessage::MSG_SELECT_TEAM1: case GameMessage::MSG_SELECT_TEAM2: case GameMessage::MSG_SELECT_TEAM3: case GameMessage::MSG_SELECT_TEAM4: case GameMessage::MSG_SELECT_TEAM5: case GameMessage::MSG_SELECT_TEAM6: case GameMessage::MSG_SELECT_TEAM7: case GameMessage::MSG_SELECT_TEAM8: case GameMessage::MSG_SELECT_TEAM9: { // weed out unit responses for things we don't own. DrawableList listOfUnits = *TheInGameUI->getAllSelectedDrawables(); for (DrawableListIt it = listOfUnits.begin(); it != listOfUnits.end(); /* empty */) { Drawable *draw = *it; if (draw->getObject() && draw->getObject()->isLocallyControlled()) { // This thing can emit a unit response. ++it; continue; } else { // remove it. it = listOfUnits.erase(it); } } if (!listOfUnits.empty()) { pickAndPlayUnitVoiceResponse( &listOfUnits, GameMessage::MSG_CREATE_SELECTED_GROUP ); } m_teamExists = true; break; } // -------------------------------------------------------------------------------------------- case GameMessage::MSG_CREATE_SELECTED_GROUP_NO_SOUND: case GameMessage::MSG_ADD_TEAM0: case GameMessage::MSG_ADD_TEAM1: case GameMessage::MSG_ADD_TEAM2: case GameMessage::MSG_ADD_TEAM3: case GameMessage::MSG_ADD_TEAM4: case GameMessage::MSG_ADD_TEAM5: case GameMessage::MSG_ADD_TEAM6: case GameMessage::MSG_ADD_TEAM7: case GameMessage::MSG_ADD_TEAM8: case GameMessage::MSG_ADD_TEAM9: { m_teamExists = true; break; } // -------------------------------------------------------------------------------------------- case GameMessage::MSG_DESTROY_SELECTED_GROUP: { m_teamExists = false; break; } // -------------------------------------------------------------------------------------------- // An object is mouseover'd. A hint of a command may be generated if something is selected // -------------------------------------------------------------------------------------------- case GameMessage::MSG_MOUSEOVER_DRAWABLE_HINT: { const CommandButton *command = TheInGameUI->getGUICommand(); if( TheInGameUI->getSelectCount() > 0 || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT) ) // If something is selected { /// @todo This as well as the one in GameMessage::MSG_DRAWABLE_PICKED below should possibly have a generalized CanAttack instead of simply checking isEnemyOf Drawable *draw = TheGameClient->findDrawableByID( msg->getArgument( 0 )->drawableID ); if( draw ) { // // given the drawable that we have moused over, pretend that we have actually // "picked" that drawable, depending on what we have selected, our mode, // and what "picked" is we would do a command ... but here we only will generate // the hint message, *not* the actual command // if (TheInGameUI->isInForceAttackMode()) { evaluateForceAttack(draw, draw->getPosition(), DO_HINT ); } else { evaluateContextCommand( draw, draw->getPosition(), DO_HINT ); } // Do not eat this message, as it itself has another purpose in HintSpy } } } break; //----------------------------------------------------------------------------- // Terrain is mouseover'd. A hint of a command may be generated if something is selected // case GameMessage::MSG_MOUSEOVER_LOCATION_HINT: { Coord3D position = msg->getArgument( 0 )->location; // // This message occurs whenever the mouse cursor moves off of a drawable, in which // case we want to turn off the pick hint. // if (TheInGameUI->isInForceAttackMode()) { evaluateForceAttack( NULL, &position, DO_HINT ); } else { evaluateContextCommand( NULL, &position, DO_HINT ); } // Do not eat this message, as it will do something itself at HintSpy break; } // end case GameMessage::MSG_MOUSEOVER_LOCATION_HINT //----------------------------------------------------------------------------- case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN: { // There are two ways in which we can ignore this as a deselect: // 1) 2-D position on screen // 2) Time has exceeded the time which we allow for this to be a click. m_mouseRightDragAnchor = msg->getArgument( 0 )->pixel; m_mouseRightDown = (UnsignedInt) msg->getArgument( 2 )->integer; break; } //----------------------------------------------------------------------------- case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: { // register this event for determining if the click was fast or short enough not to be a drag m_mouseRightDragLift = msg->getArgument( 0 )->pixel; m_mouseRightUp = (UnsignedInt) msg->getArgument( 2 )->integer; //Kris: July 7, 2003. Added this code to deselect build placement mode when right clicked. This fixes //a bug where you couldn't cancel the sneak attack mode via right click. This only happened when you //didn't have anything selected which is possible via the shortcut bar. Normally, it would get deselected //via the deselect drawable code. if( TheMouse->isClick(&m_mouseRightDragAnchor, &m_mouseRightDragLift, m_mouseRightDown, m_mouseRightUp) ) { TheInGameUI->placeBuildAvailable( NULL, NULL ); } break; } //----------------------------------------------------------------------------- case GameMessage::MSG_MOUSE_RIGHT_DOUBLE_CLICK: { if( TheGlobalData->m_useAlternateMouse && TheGlobalData->m_doubleClickAttackMove ) { // create the message and append arguments for a guard location GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); Coord3D pos; TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); newMsg->appendLocationArgument(pos); newMsg->appendIntegerArgument(GUARDMODE_NORMAL); ThePlayerList->getLocalPlayer()->getAcademyStats()->recordDoubleClickAttackMoveOrderGiven(); TheInGameUI->triggerDoubleClickAttackMoveGuardHint(); break; } //intentional fall through } case GameMessage::MSG_MOUSE_RIGHT_CLICK: { // right click is only actioned here if we're in alternate mouse mode if (TheGlobalData->m_useAlternateMouse && TheMouse->isClick(&m_mouseRightDragAnchor, &m_mouseRightDragLift, m_mouseRightDown, m_mouseRightUp)) { Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); // NOTE: RIGHT_CLICK is not transmitted if AREA_SELECTION or DRAWABLE_PICKED occurs. // If we see this msg, no object was clicked on, therefore clicked on ground. // Issue move command to all currently selected objects. // sanity if( TheTacticalView == NULL ) break; // translate from screen coordinates to terrain coords Coord3D pos; TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); const CommandButton *command = TheInGameUI->getGUICommand(); Bool controllable = TheInGameUI->areSelectedObjectsControllable() || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT); if (isPoint && controllable) { UnsignedInt pickType = getPickTypesForContext( TheInGameUI->isInForceAttackMode() ); Drawable *draw = TheTacticalView->pickDrawable(&msg->getArgument(0)->pixelRegion.lo, TheInGameUI->isInForceAttackMode(), (PickType) pickType); if (TheInGameUI->isInForceAttackMode()) { evaluateForceAttack( draw, &pos, DO_COMMAND ); } else { evaluateContextCommand( draw, &pos, DO_COMMAND ); } disp = DESTROY_MESSAGE; TheInGameUI->clearAttackMoveToMode(); } } break; } //----------------------------------------------------------------------------- case GameMessage::MSG_MOUSE_LEFT_DOUBLE_CLICK: { if( !TheGlobalData->m_useAlternateMouse && TheGlobalData->m_doubleClickAttackMove ) { // create the message and append arguments for a guard location GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); Coord3D pos; TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); newMsg->appendLocationArgument(pos); newMsg->appendIntegerArgument(GUARDMODE_NORMAL); ThePlayerList->getLocalPlayer()->getAcademyStats()->recordDoubleClickAttackMoveOrderGiven(); TheInGameUI->triggerDoubleClickAttackMoveGuardHint(); break; } //intentional fall through } case GameMessage::MSG_MOUSE_LEFT_CLICK: { Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); // NOTE: LEFT_CLICK is not transmitted if AREA_SELECTION or DRAWABLE_PICKED occurs. // If we see this msg, no object was clicked on, therefore clicked on ground. // Issue move command to all currently selected objects. // sanity if( TheTacticalView == NULL ) break; // translate from screen coordinates to terrain coords Coord3D pos; TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); const CommandButton *command = TheInGameUI->getGUICommand(); // maintain this as the list of GUI button initiated commands that fire with left click in alt mouse mode Bool isFiringGUICommand = (command && (command->getCommandType() == GUI_COMMAND_SPECIAL_POWER || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT || command->getCommandType() == GUI_COMMAND_FIRE_WEAPON || command->getCommandType() == GUI_COMMAND_COMBATDROP || command->getCommandType() == GUICOMMANDMODE_HIJACK_VEHICLE || command->getCommandType() == GUICOMMANDMODE_CONVERT_TO_CARBOMB)); // in alternate mouse mode, this left click is only actioned here if we're firing a gui command if ((TheGlobalData->m_useAlternateMouse) && (! isFiringGUICommand)) break; Bool controllable = TheInGameUI->areSelectedObjectsControllable() || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT); if (isPoint && controllable) { UnsignedInt pickType = getPickTypesForContext( TheInGameUI->isInForceAttackMode() ); Drawable *draw = TheTacticalView->pickDrawable(&msg->getArgument(0)->pixelRegion.lo, TheInGameUI->isInForceAttackMode(), (PickType) pickType); if (TheInGameUI->isInForceAttackMode()) { evaluateForceAttack( draw, &pos, DO_COMMAND ); } else { evaluateContextCommand( draw, &pos, DO_COMMAND ); } disp = DESTROY_MESSAGE; TheInGameUI->clearAttackMoveToMode(); //issueMoveToLocationCommand( &pos, draw, DO_COMMAND ); } break; } // end case GameMessage::MSG_MOUSE_LEFT_CLICK #ifdef ALLOW_ALT_F4 case GameMessage::MSG_META_DEMO_INSTANT_QUIT: { if (TheGameLogic->isInGame()) { if (TheRecorder->getMode() == RECORDERMODETYPE_RECORD) { TheRecorder->stopRecording(); } TheGameLogic->clearGameData(); } TheGameEngine->setQuitting(TRUE); disp = DESTROY_MESSAGE; break; } #endif //------------------------------------------------------------------------------- DEMO MESSAGES #if defined(_DEBUG) || defined(_INTERNAL) //------------------------------------------------------------------------- BEGIN DEMO MESSAGES //------------------------------------------------------------------------- BEGIN DEMO MESSAGES //------------------------------------------------------------------------- BEGIN DEMO MESSAGES //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_SWITCH_TEAMS: { if (TheGameLogic->isInGame()) { Int idx; for (Int i = 0; i < ThePlayerList->getPlayerCount(); i++) { if (ThePlayerList->getNthPlayer(i) == ThePlayerList->getLocalPlayer()) { idx = i; break; } } Int idxOrig = idx; do { ++idx; if (idx >= ThePlayerList->getPlayerCount()) idx = 0; if (idx == idxOrig) { break; } } while (ThePlayerList->getNthPlayer(idx) == ThePlayerList->getNeutralPlayer()); ThePlayerList->setLocalPlayer(ThePlayerList->getNthPlayer(idx)); TheInGameUI->deselectAllDrawables(); #ifdef DEBUG_FOG_MEMORY TheGhostObjectManager->setLocalPlayerIndex(idx); #endif ThePartitionManager->refreshShroudForLocalPlayer(); TheControlBar->initSpecialPowershortcutBar(ThePlayerList->getLocalPlayer()); TheControlBar->setControlBarSchemeByPlayer(ThePlayerList->getLocalPlayer()); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_SWITCH_TEAMS_BETWEEN_CHINA_USA: { Player *p = ThePlayerList->getLocalPlayer(); AsciiString side; side.set(p->getSide()); if(side.compareNoCase("America") == 0) { for (Int i = 0; i < ThePlayerList->getPlayerCount(); i++) { Player *pt = ThePlayerList->getNthPlayer(i); if(pt->getSide().compareNoCase("China") == 0) { ThePlayerList->setLocalPlayer(pt); TheInGameUI->deselectAllDrawables(); ThePartitionManager->refreshShroudForLocalPlayer(); TheControlBar->setControlBarSchemeByPlayer(ThePlayerList->getLocalPlayer()); break; } } } if(side.compareNoCase("China") == 0) { for (Int i = 0; i < ThePlayerList->getPlayerCount(); i++) { Player *pt = ThePlayerList->getNthPlayer(i); if(pt->getSide().compareNoCase("America") == 0) { ThePlayerList->setLocalPlayer(pt); TheInGameUI->deselectAllDrawables(); ThePartitionManager->refreshShroudForLocalPlayer(); TheControlBar->setControlBarSchemeByPlayer(ThePlayerList->getLocalPlayer()); break; } } } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_LOD_DECREASE: { TheGameClient->adjustLOD(-1); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_LOD_INCREASE: { TheGameClient->adjustLOD(1); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_HELP: { // for demo, they don't want the help menu showing up. I left this as a block comment because we // might want to add back in the help menu at some point in time. /* if (TheWindowManager && TheNameKeyGenerator) { GameWindow *motd = TheWindowManager->winGetWindowFromId(NULL, (Int)TheNameKeyGenerator->nameToKey(AsciiString("MOTD.wnd:MOTD"))); if (motd) motd->winHide(!motd->winIsHidden()); }*/ disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_BEHIND_BUILDINGS: { if (TheGlobalData) { if(TheGameLogic->getShowBehindBuildingMarkers()) { TheGameLogic->setShowBehindBuildingMarkers(FALSE); TheInGameUI->message("GUI:ShowBehindBuildings"); } else { TheGameLogic->setShowBehindBuildingMarkers(TRUE); TheInGameUI->message("GUI:HideBehindBuildings"); } } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_LETTERBOX: { if(TheShell->isShellActive()) { WindowLayout *win = TheShell->top(); if(win) { win->hide(!win->isHidden()); } } else { Bool hide = false; if (TheWindowManager) { Int id = (Int)TheNameKeyGenerator->nameToKey(AsciiString("ControlBar.wnd:ControlBarParent")); GameWindow *window = TheWindowManager->winGetWindowFromId(NULL, id); if (window) hide = !window->winIsHidden(); } if (hide) HideControlBar(); else ShowControlBar(FALSE); TheDisplay->toggleLetterBox(); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_MESSAGE_TEXT: { // toggle the message state TheInGameUI->toggleMessages(); // when messages get turned on, display a message if( TheInGameUI->isMessagesOn() ) TheInGameUI->message( TheGameText->fetch( "GUI:MessagesOn" ) ); disp = DESTROY_MESSAGE; break; } // end clear message text //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_MOTION_BLUR_ZOOM: { Int mode; if ((mode=TheTacticalView->getViewFilterType()) == FT_VIEW_MOTION_BLUR_FILTER) { //mode already set, turn it off TheTacticalView->setViewFilterMode(FM_NULL_MODE); TheTacticalView->setViewFilter(FT_NULL_FILTER); } else { static Bool saturate = false; FilterModes mode = FM_VIEW_MB_IN_AND_OUT_ALPHA; if (saturate) { mode = FM_VIEW_MB_IN_AND_OUT_SATURATE; } if (TheTacticalView->getCameraLock()!=0) { mode = FM_VIEW_MB_PAN_ALPHA; } saturate = !saturate; Coord3D curpos; TheTacticalView->getPosition(&curpos); curpos.x += 200; curpos.y += 200; TheTacticalView->setViewFilterPos(&curpos); TheTacticalView->setViewFilterMode(mode); TheTacticalView->setViewFilter(FT_VIEW_MOTION_BLUR_FILTER); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_BW_VIEW: { //We're not testing BW mode anymore, so use this message for toggling wireframe mode. static mode=0; if (mode == 0) { //First turn on wireframe TheTacticalView->set3DWireFrameMode(TRUE); mode++; disp = DESTROY_MESSAGE; break; } if (mode == 1) { if ((TheTacticalView->getViewFilterType()) == FT_VIEW_CROSSFADE) { //mode already set, turn it off TheTacticalView->setViewFilterMode(FM_NULL_MODE); TheTacticalView->setViewFilter(FT_NULL_FILTER); TheTacticalView->setFadeParameters(0,-1); } else { TheScriptEngine->doFreezeTime(); //TheTacticalView->setViewFilterMode(FM_VIEW_CROSSFADE_CIRCLE); TheTacticalView->setViewFilterMode(FM_VIEW_CROSSFADE_FB_MASK); TheTacticalView->setViewFilter(FT_VIEW_CROSSFADE); TheTacticalView->setFadeParameters(60,-1); TheTacticalView->set3DWireFrameMode(FALSE); mode++; } } else if (mode == 2) { TheScriptEngine->doUnfreezeTime(); mode=0; //reset everything } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_RED_VIEW: { if ((TheTacticalView->getViewFilterType()) == FT_VIEW_BW_FILTER) { //mode already set, turn it off TheTacticalView->setViewFilterMode(FM_NULL_MODE); TheTacticalView->setViewFilter(FT_NULL_FILTER); TheTacticalView->setFadeParameters(30,-1); } else { TheTacticalView->setViewFilterMode(FM_VIEW_BW_RED_AND_WHITE); TheTacticalView->setViewFilter(FT_VIEW_BW_FILTER); TheTacticalView->setFadeParameters(30,1); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_GREEN_VIEW: { if ((TheTacticalView->getViewFilterType()) == FT_VIEW_BW_FILTER) { //mode already set, turn it off TheTacticalView->setViewFilterMode(FM_NULL_MODE); TheTacticalView->setViewFilter(FT_NULL_FILTER); TheTacticalView->setFadeParameters(30,-1); } else { TheTacticalView->setViewFilterMode(FM_VIEW_BW_GREEN_AND_WHITE); TheTacticalView->setViewFilter(FT_VIEW_BW_FILTER); TheTacticalView->setFadeParameters(30,1); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_CYCLE_LOD_LEVEL: { static Int level=DYNAMIC_GAME_LOD_VERY_HIGH; level--; if (level < DYNAMIC_GAME_LOD_LOW) level = DYNAMIC_GAME_LOD_VERY_HIGH; TheGameLODManager->setDynamicLODLevel((DynamicGameLODLevel)level); UnicodeString lodName; lodName.format(L"Dynamic Game Detail %hs",TheGameLODManager->getDynamicGameLODLevelName((DynamicGameLODLevel)level)); TheInGameUI->message(lodName); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_DUMP_ASSETS: { TheDisplay->dumpModelAssets("UsedMapAssets.txt"); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_SHADOW_VOLUMES: { TheWritableGlobalData->m_useShadowVolumes = !TheGlobalData->m_useShadowVolumes; TheWritableGlobalData->m_useShadowDecals = !TheGlobalData->m_useShadowDecals; disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_FOGOFWAR: { TheWritableGlobalData->m_fogOfWarOn = !TheGlobalData->m_fogOfWarOn; disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_KILL_SELECTION: { TheMessageStream->appendMessage( GameMessage::MSG_DEBUG_KILL_SELECTION ); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_KILL_ALL_ENEMIES: { for (Drawable *d = TheGameClient->firstDrawable(); d; d = d->getNextDrawable()) { Object* obj = d->getObject(); if (obj && obj->getControllingPlayer() && obj->getControllingPlayer()->getRelationship(ThePlayerList->getLocalPlayer()->getDefaultTeam()) == ENEMIES) { obj->kill(); } } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_GIVE_VETERANCY: case GameMessage::MSG_META_DEBUG_TAKE_VETERANCY: { if ( !TheGameLogic->isInMultiplayerGame() ) { const DrawableList *list = TheInGameUI->getAllSelectedDrawables(); for (DrawableListCIt it = list->begin(); it != list->end(); ++it) { Drawable *pDraw = *it; if (pDraw) { Object *pObject = pDraw->getObject(); if (pObject) { ExperienceTracker *et = pObject->getExperienceTracker(); if (et) { if (et->isTrainable()) { VeterancyLevel oldVet = et->getVeterancyLevel(); VeterancyLevel newVet = oldVet; if (t == GameMessage::MSG_META_DEBUG_GIVE_VETERANCY) { if (oldVet < LEVEL_LAST) { newVet = (VeterancyLevel)((Int)oldVet + 1); } } else { if (oldVet > LEVEL_FIRST) { newVet = (VeterancyLevel)((Int)oldVet - 1); } } et->setVeterancyLevel(newVet); } } } } } disp = DESTROY_MESSAGE; } break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_INCR_ANIM_SKATE_SPEED: { TheSkateDistOverride += 0.25f; TheInGameUI->message( UnicodeString( L"Skate Distance Override is now %f" ), TheSkateDistOverride ); break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_DECR_ANIM_SKATE_SPEED: { TheSkateDistOverride -= 0.25f; TheInGameUI->message( UnicodeString( L"Skate Distance Override is now %f" ), TheSkateDistOverride ); break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_CYCLE_EXTENT_TYPE: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_TYPE; if (!extentModAmount) extentModAmount = 1.0f; case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MAJOR: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MAJOR; if (!extentModAmount) extentModAmount = 1.0f; case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MAJOR_BIG: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MAJOR; if (!extentModAmount) extentModAmount = EXTENT_BIG_CHANGE; case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MAJOR: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MAJOR; if (!extentModAmount) extentModAmount = -1.0f; case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MAJOR_BIG: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MAJOR; if (!extentModAmount) extentModAmount = -EXTENT_BIG_CHANGE; case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MINOR: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MINOR; if (!extentModAmount) extentModAmount = 1.0f; case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MINOR_BIG: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MINOR; if (!extentModAmount) extentModAmount = EXTENT_BIG_CHANGE; case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MINOR: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MINOR; if (!extentModAmount) extentModAmount = -1.0f; case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MINOR_BIG: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MINOR; if (!extentModAmount) extentModAmount = -EXTENT_BIG_CHANGE; case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_HEIGHT: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_HEIGHT; if (!extentModAmount) extentModAmount = 1.0f; case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_HEIGHT_BIG: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_HEIGHT; if (!extentModAmount) extentModAmount = EXTENT_BIG_CHANGE; case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_HEIGHT: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_HEIGHT; if (!extentModAmount) extentModAmount = -1.0f; case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_HEIGHT_BIG: if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_HEIGHT; if (!extentModAmount) extentModAmount = -EXTENT_BIG_CHANGE; { const DrawableList *list = TheInGameUI->getAllSelectedDrawables(); for (DrawableListCIt it = list->begin(); it != list->end(); ++it) { Drawable *pDraw = *it; if (pDraw) { Object *pObject = pDraw->getObject(); if (pObject) { const GeometryInfo oldGeometry = pObject->getGeometryInfo(); GeometryInfo newGeometry = oldGeometry; newGeometry.tweakExtents(extentModType, extentModAmount); AsciiString msg; msg.format("Extent %s --> %s %d %g",oldGeometry.getDescriptiveString().str(), newGeometry.getDescriptiveString().str(), extentModType, extentModAmount); UnicodeString umsg; umsg.translate(msg); TheInGameUI->message(umsg); DEBUG_LOG(("%ls\n", msg.str())); pObject->setGeometryInfo( newGeometry ); } } } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_LOCK_CAMERA_TO_SELECTION: { ObjectID id = INVALID_ID; Drawable *d = NULL; for (d = TheGameClient->firstDrawable(); d; d = d->getNextDrawable()) { if (d->isSelected() && d->getObject()) { id = d->getObject()->getID(); break; } } if (id != 0 && TheTacticalView->getCameraLock() == id) { if (TheTacticalView->getCameraLockDrawable()) { id = INVALID_ID; // toggle it d=NULL; TheTacticalView->forceRedraw(); //reset camera to normal } } else { d = NULL; } TheTacticalView->setCameraLock(id); TheTacticalView->setCameraLockDrawable(d); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_SOUND: { if (TheAudio->isOn(AudioAffect_Sound)) { TheDisplay->stopMovie(); TheInGameUI->stopMovie(); TheAudio->setOn(false, AudioAffect_All); } else { TheAudio->setOn(true, AudioAffect_All); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_TRACKMARKS: { TheWritableGlobalData->m_makeTrackMarks = !TheGlobalData->m_makeTrackMarks; disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_WATERPLANE: { TheWritableGlobalData->m_useWaterPlane = !TheGlobalData->m_useWaterPlane; disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TIME_OF_DAY: { TimeOfDay tod = TimeOfDay((Int) TheGlobalData->m_timeOfDay + 1); if (tod >= TIME_OF_DAY_COUNT) tod = TIME_OF_DAY_FIRST; if (TheWritableGlobalData->setTimeOfDay(tod)) { TheGameClient->setTimeOfDay(TheGlobalData->m_timeOfDay); if (TheGlobalData->m_forceModelsToFollowTimeOfDay) { for (Object *obj = TheGameLogic->getFirstObject(); obj; obj = obj->getNextObject()) { Drawable* d = obj->getDrawable(); if (d) { // this just forces a refresh. ModelConditionFlags empty; d->clearAndSetModelConditionFlags(empty, empty); } } } } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_REMOVE_PREREQ: { // Doesn't make a valid network message Player *localPlayer = ThePlayerList->getLocalPlayer(); localPlayer->toggleIgnorePrereqs(); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_INSTANT_BUILD: { // Doesn't make a valid network message Player *localPlayer = ThePlayerList->getLocalPlayer(); localPlayer->toggleInstantBuild(); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_FREE_BUILD: { // Doesn't make a valid network message Player *localPlayer = ThePlayerList->getLocalPlayer(); localPlayer->toggleFreeBuild(); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_RENDER: { TheWritableGlobalData->m_disableRender = !TheGlobalData->m_disableRender; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_ADD_CASH: { if ( !TheGameLogic->isInMultiplayerGame() ) { Player *localPlayer = ThePlayerList->getLocalPlayer(); Money *money = localPlayer->getMoney(); money->deposit( 10000 ); } break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_RUNSCRIPT1: case GameMessage::MSG_META_DEMO_RUNSCRIPT2: case GameMessage::MSG_META_DEMO_RUNSCRIPT3: case GameMessage::MSG_META_DEMO_RUNSCRIPT4: case GameMessage::MSG_META_DEMO_RUNSCRIPT5: case GameMessage::MSG_META_DEMO_RUNSCRIPT6: case GameMessage::MSG_META_DEMO_RUNSCRIPT7: case GameMessage::MSG_META_DEMO_RUNSCRIPT8: case GameMessage::MSG_META_DEMO_RUNSCRIPT9: { if( TheScriptEngine ) { Int script = t - GameMessage::MSG_META_DEMO_RUNSCRIPT1 + 1; AsciiString scriptName; scriptName.format("KEY_F%d", script); TheScriptEngine->runScript(scriptName); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_KILL_AREA_SELECTION: { for( int i=1; igetArgumentCount(); i++ ) { Object *obj = TheGameLogic->findObjectByID( msg->getArgument( i )->objectID ); if( obj ) { obj->kill(); } } } break; //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE1: case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE2: case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE3: case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE4: case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE5: case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE6: case GameMessage::MSG_META_DEMO_NEXT_OBJECTIVE_MOVIE: { if (TheGameLogic->isInGame()) { if (t == GameMessage::MSG_META_DEMO_NEXT_OBJECTIVE_MOVIE) { m_objective++; if (m_objective > 6) m_objective = 1; } else { m_objective = t - GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE1 + 1; } AsciiString name; name.format("DemoObjective%02d", m_objective); TheInGameUI->playMovie(name); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_MILITARY_SUBTITLES: { TheInGameUI->militarySubtitle("MSG:Testing", 10000); // use some innocuous string disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_MUSIC: { if (TheAudio->isMusicPlaying()) { TheAudio->stopAudio(AudioAffect_Music); TheInGameUI->message( UnicodeString( L"Stopping Music" )); } else { TheAudio->resumeAudio(AudioAffect_Music); TheInGameUI->message( UnicodeString( L"Resuming Music" )); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_MUSIC_NEXT_TRACK: { TheAudio->nextMusicTrack(); UnicodeString ustr; ustr.format(L"Playing Track: %hs", TheAudio->getMusicTrackName().str()); TheInGameUI->message( ustr ); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_MUSIC_PREV_TRACK: { TheAudio->prevMusicTrack(); UnicodeString ustr; ustr.format(L"Playing Track: %hs", TheAudio->getMusicTrackName().str()); TheInGameUI->message( ustr ); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- #ifdef PERF_TIMERS case GameMessage::MSG_META_DEMO_TOGGLE_METRICS: { TheWritableGlobalData->m_showMetrics = !TheGlobalData->m_showMetrics; if (TheGlobalData->m_showMetrics) { TheDisplay->setDebugDisplayCallback(StatMetricsDisplay); } else { TheDisplay->setDebugDisplayCallback(NULL); } break; } #endif // #ifdef PERF_TIMERS //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_AI_DEBUG: { TheWritableGlobalData->m_debugAI = (AIDebugOptions)((Int)TheGlobalData->m_debugAI + 1); if (TheGlobalData->m_debugAI >= AI_DEBUG_END) TheWritableGlobalData->m_debugAI=AI_DEBUG_NONE; UnicodeString line; line.format(L"Level %d", TheGlobalData->m_debugAI); TheInGameUI->message( UnicodeString( L"Debug AI Mode is %s" ), TheGlobalData->m_debugAI ? line.str() : L"OFF" ); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_SUPPLY_CENTER_PLACEMENT: { TheWritableGlobalData->m_debugSupplyCenterPlacement = !TheWritableGlobalData->m_debugSupplyCenterPlacement; TheInGameUI->message( UnicodeString( L"Log SupplyCenter Placement is %s" ), TheGlobalData->m_debugSupplyCenterPlacement ? L"ON" : L"OFF" ); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_GIVE_SCIENCEPURCHASEPOINTS: { Player *player = ThePlayerList->getLocalPlayer(); if (player) player->addSciencePurchasePoints(1); TheInGameUI->message( UnicodeString( L"Adding a SciencePurchasePoint" )); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_GIVE_ALL_SCIENCES: { Player *player = ThePlayerList->getLocalPlayer(); if (player) { // cheese festival: do NOT imitate this code. it is for debug purposes only. std::vector v = TheScienceStore->friend_getScienceNames(); for (int i = 0; i < v.size(); ++i) { ScienceType st = TheScienceStore->getScienceFromInternalName(v[i]); if (st != SCIENCE_INVALID && TheScienceStore->isScienceGrantable(st)) { player->grantScience(st); } } } TheInGameUI->message( UnicodeString( L"Granting all sciences!" )); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_GIVE_RANKLEVEL: { Player *player = ThePlayerList->getLocalPlayer(); if (player) player->setRankLevel(player->getRankLevel() + 1); TheInGameUI->message( UnicodeString( L"Adding a RankLevel" )); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TAKE_RANKLEVEL: { Player *player = ThePlayerList->getLocalPlayer(); if (player) player->setRankLevel(player->getRankLevel() - 1); TheInGameUI->message( UnicodeString( L"Subtracting a RankLevel" )); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_CAMERA_DEBUG: { TheWritableGlobalData->m_debugCamera = !TheGlobalData->m_debugCamera; TheInGameUI->message( UnicodeString( L"Debug Camera Mode is %s" ), TheGlobalData->m_debugCamera ? L"On" : L"OFF" ); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_NO_DRAW: { TheWritableGlobalData->m_noDraw = REAL_TO_INT(pow(2, 32) - 1); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_DUMP_PLAYER_OBJECTS: case GameMessage::MSG_META_DEBUG_DUMP_ALL_PLAYER_OBJECTS: { AsciiString line; line.format("*******************************"); TheScriptEngine->AppendDebugMessage(line, FALSE); line.format("Dumping player object counts"); TheScriptEngine->AppendDebugMessage(line, FALSE); for (Int i=0; igetNthPlayer(i); if (!pPlayer || !pPlayer->getPlayerTemplate() || !pPlayer->getPlayerTemplate()->isPlayableSide()) continue; Int numObjects = 0; pPlayer->iterateObjects( countObjects, &numObjects ); line.format("Player %d (%ls) has %d non-dead objects", i, pPlayer->getPlayerDisplayName().str(), numObjects); TheScriptEngine->AppendDebugMessage(line, FALSE); if (numObjects && (numObjects <= 5 || t == GameMessage::MSG_META_DEBUG_DUMP_ALL_PLAYER_OBJECTS)) { line = "Objects are:"; TheScriptEngine->AppendDebugMessage(line, FALSE); pPlayer->iterateObjects( printObjects, NULL ); } } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_TOGGLE_NETWORK: { if (TheNetwork != NULL) { TheNetwork->toggleNetworkOn(); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_PARTICLEDEBUG: { if (TheDisplay->getDebugDisplayCallback() == ParticleSystemDebugDisplay) TheDisplay->setDebugDisplayCallback(NULL); else TheDisplay->setDebugDisplayCallback(ParticleSystemDebugDisplay); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_VISIONDEBUG: { TheWritableGlobalData->m_debugVisibility = !TheGlobalData->m_debugVisibility; TheInGameUI->message( UnicodeString( L"Debug Vision Mode is %s" ), TheGlobalData->m_debugVisibility? L"On" : L"OFF" ); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_PROJECTILEDEBUG: { TheWritableGlobalData->m_debugProjectilePath = !TheGlobalData->m_debugProjectilePath; TheInGameUI->message( UnicodeString( L"Debug Projectile Path Mode is %s" ), TheGlobalData->m_debugProjectilePath? L"On" : L"OFF" ); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_THREATDEBUG: { TheWritableGlobalData->m_debugThreatMap = !TheGlobalData->m_debugThreatMap; if (TheGlobalData->m_debugThreatMap) { TheWritableGlobalData->m_debugCashValueMap = false; } TheInGameUI->message( UnicodeString( L"Debug Threat Map is %s" ), TheGlobalData->m_debugThreatMap? L"On" : L"OFF" ); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_CASHMAPDEBUG: { TheWritableGlobalData->m_debugCashValueMap = !TheGlobalData->m_debugCashValueMap ; if (TheGlobalData->m_debugCashValueMap) { TheWritableGlobalData->m_debugThreatMap = false; } TheInGameUI->message( UnicodeString( L"Debug Cash Value Map is %s" ), TheGlobalData->m_debugCashValueMap? L"On" : L"OFF" ); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_GRAPHICALFRAMERATEBAR: { TheWritableGlobalData->m_debugShowGraphicalFramerate = !TheGlobalData->m_debugShowGraphicalFramerate; disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_SHOW_EXTENTS: TheWritableGlobalData->m_showCollisionExtents = 1 - TheGlobalData->m_showCollisionExtents; TheInGameUI->message( UnicodeString( L"Show Object Extents %s" ), TheGlobalData->m_showCollisionExtents ? L"ON" : L"OFF" ); break; //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_SHOW_AUDIO_LOCATIONS: TheWritableGlobalData->m_showAudioLocations = 1 - TheGlobalData->m_showAudioLocations; TheInGameUI->message( UnicodeString( L"Show AudioLocations %s" ), TheGlobalData->m_showAudioLocations ? L"ON" : L"OFF" ); break; //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_SHOW_HEALTH: { TheWritableGlobalData->m_showObjectHealth = 1 - TheGlobalData->m_showObjectHealth; TheInGameUI->message( UnicodeString( L"Object Health %s" ), TheGlobalData->m_showObjectHealth ? L"ON" : L"OFF" ); break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_PLAY_CAMEO_MOVIE: { if (TheGameLogic->isInGame()) { if(TheInGameUI->cameoVideoBuffer() == NULL) TheInGameUI->playCameoMovie("CameoMovie"); else TheInGameUI->stopCameoMovie(); } disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_ZOOM_LOCK: { if( TheTacticalView ) { TheTacticalView->setZoomLimited( !TheTacticalView->isZoomLimited() ); TheInGameUI->message( UnicodeString( L"Camera Zoom Limit: %s" ), TheTacticalView->isZoomLimited() ? L"ON" : L"OFF" ); } // end if disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //--------------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_SPECIAL_POWER_DELAYS: { if( TheGlobalData ) { TheWritableGlobalData->m_specialPowerUsesDelay = 1 - TheGlobalData->m_specialPowerUsesDelay; TheInGameUI->message( UnicodeString( L"Special Power (Superweapon) Delay: %s" ), TheGlobalData->m_specialPowerUsesDelay ? L"ON" : L"OFF" ); } // end if disp = DESTROY_MESSAGE; break; } // end toggle special power delays #ifdef ALLOW_SURRENDER //------------------------------------------------------------------------------- DEMO MESSAGES //--------------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TEST_SURRENDER: { GameMessage* msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_SURRENDER ); msg->appendObjectIDArgument(INVALID_ID); // zero means "surrender to anyone" msg->appendBooleanArgument(true); disp = DESTROY_MESSAGE; break; } #endif //------------------------------------------------------------------------------- DEMO MESSAGES // -------------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_BATTLE_CRY: { TheAudio->addAudioEvent(&TheAudio->getMiscAudio()->m_battleCrySound); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES // -------------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_AVI: { if (TheDisplay) TheDisplay->toggleMovieCapture(); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_VTUNE_ON: { TheScriptEngine->setEnableVTune(true); TheInGameUI->message( UnicodeString( L"VTune Gathering is ON" )); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES // -------------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_VTUNE_OFF: { TheScriptEngine->setEnableVTune(false); TheInGameUI->message( UnicodeString( L"VTune Gathering is OFF" )); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES // -------------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_TOGGLE_FEATHER_WATER: { //TheScriptEngine->setEnableVTune(false); //TheInGameUI->message( UnicodeString( L"VTune Gathering is OFF" )); --TheWritableGlobalData->m_featherWater; if (TheGlobalData->m_featherWater < 0) TheWritableGlobalData->m_featherWater = 5; disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_WIN: { TheScriptEngine->debugVictory(); TheInGameUI->message( UnicodeString( L"Instant Win" )); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_TOGGLE_DEBUG_STATS: { if (TheDisplay->getDebugDisplayCallback() == StatDebugDisplay) TheDisplay->setDebugDisplayCallback(NULL); else TheDisplay->setDebugDisplayCallback(StatDebugDisplay); disp = DESTROY_MESSAGE; break; } //------------------------------------------------------------------------DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_SLEEPY_UPDATE_PERFORMANCE: { TheInGameUI->message( UnicodeString(L"Number of Sleepy Modules: %d."), TheGameLogic->getNumberSleepyUpdates() ); break; } //------------------------------------------------------------------------DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_OBJECT_ID_PERFORMANCE: { static __int64 startTime64; static __int64 endTime64,freq64; QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); Int numberLookups = 10000; for( Int testindex = 1; testindex < numberLookups; testindex++ ) { Object *objPtr = TheGameLogic->findObjectByID((ObjectID)testindex); objPtr++; } QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); double timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); TheInGameUI->message( UnicodeString(L"Time to run %d ObjectID lookups is %f. Next index is %d."), numberLookups, timeToUpdate, (Int)TheGameLogic->getObjectIDCounter() ); QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); numberLookups = 100000; for( testindex = 1; testindex < numberLookups; testindex++ ) { Object *objPtr = TheGameLogic->findObjectByID((ObjectID)testindex); objPtr++; } QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); TheInGameUI->message( UnicodeString(L"Time to run %d ObjectID lookups is %f. Next index is %d."), numberLookups, timeToUpdate, (Int)TheGameLogic->getObjectIDCounter() ); QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); numberLookups = 1000000; for( testindex = 1; testindex < numberLookups; testindex++ ) { Object *objPtr = TheGameLogic->findObjectByID((ObjectID)testindex); objPtr++; } QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); TheInGameUI->message( UnicodeString(L"Time to run %d ObjectID lookups is %f. Next index is %d."), numberLookups, timeToUpdate, (Int)TheGameLogic->getObjectIDCounter() ); break; } //------------------------------------------------------------------------DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEBUG_DRAWABLE_ID_PERFORMANCE: { static __int64 startTime64; static __int64 endTime64,freq64; QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); Int numberLookups = 10000; for( Int testindex = 1; testindex < numberLookups; testindex++ ) { Drawable *drawPtr = TheGameClient->findDrawableByID((DrawableID)testindex); drawPtr++; } QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); double timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); TheInGameUI->message( UnicodeString(L"Time to run %d DrawableID lookups is %f. Next index is %d."), numberLookups, timeToUpdate, (Int)TheGameClient->getDrawableIDCounter() ); QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); numberLookups = 100000; for( testindex = 1; testindex < numberLookups; testindex++ ) { Drawable *drawPtr = TheGameClient->findDrawableByID((DrawableID)testindex); drawPtr++; } QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); TheInGameUI->message( UnicodeString(L"Time to run %d DrawableID lookups is %f. Next index is %d."), numberLookups, timeToUpdate, (Int)TheGameClient->getDrawableIDCounter() ); QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); numberLookups = 1000000; for( testindex = 1; testindex < numberLookups; testindex++ ) { Drawable *drawPtr = TheGameClient->findDrawableByID((DrawableID)testindex); drawPtr++; } QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); TheInGameUI->message( UnicodeString(L"Time to run %d DrawableID lookups is %f. Next index is %d."), numberLookups, timeToUpdate, (Int)TheGameClient->getDrawableIDCounter() ); break; } //--------------------------------------------------------------------------- END DEMO MESSAGES //--------------------------------------------------------------------------- END DEMO MESSAGES //--------------------------------------------------------------------------- END DEMO MESSAGES #endif // #if defined(_DEBUG) || defined(_INTERNAL) //------------------------------------------------------------------------DEMO MESSAGES //----------------------------------------------------------------------------------------- #if defined(_INTERNAL) || defined(_DEBUG) case GameMessage::MSG_META_DEMO_TOGGLE_AUDIODEBUG: { if (TheDisplay->getDebugDisplayCallback() == AudioDebugDisplay) TheDisplay->setDebugDisplayCallback(NULL); else TheDisplay->setDebugDisplayCallback(AudioDebugDisplay); disp = DESTROY_MESSAGE; break; } #endif//defined(_INTERNAL) || defined(_DEBUG) #ifdef DUMP_PERF_STATS //------------------------------------------------------------------------DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_PERFORM_STATISTICAL_DUMP: //Dump performance statistics for this frame. TheWritableGlobalData->m_dumpPerformanceStatistics = TRUE; TheInGameUI->message( UnicodeString( L"Statistics dump made on frame: %d" ), TheGameLogic->getFrame() ); break; #endif // DUMP_PERF_STATS } // end switch( msg->type ) return disp; } // end CommandTranslator static Bool isSystemMessage( const GameMessage *msg ) { if (!msg) { return false; } GameMessage::Type msgType = msg->getType(); switch (msgType) { case GameMessage::MSG_DESTROY_SELECTED_GROUP: case GameMessage::MSG_LOGIC_CRC: case GameMessage::MSG_SET_REPLAY_CAMERA: case GameMessage::MSG_FRAME_TICK: return TRUE; } return FALSE; }