/* ** 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. // // // //////////////////////////////////////////////////////////////////////////////// // MessageStream.cpp // Implementation of the message stream // Author: Michael S. Booth, February 2001 #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine #include "Common/MessageStream.h" #include "Common/Player.h" #include "Common/PlayerList.h" #include "Common/Recorder.h" #include "GameClient/InGameUI.h" #include "GameLogic/GameLogic.h" /// The singleton message stream for messages going to TheGameLogic MessageStream *TheMessageStream = NULL; CommandList *TheCommandList = NULL; #ifdef _INTERNAL // for occasional debugging... //#pragma optimize("", off) //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes") #endif //------------------------------------------------------------------------------------------------ // GameMessage // /** * Constructor */ GameMessage::GameMessage( GameMessage::Type type ) { m_playerIndex = ThePlayerList->getLocalPlayer()->getPlayerIndex(); m_type = type; m_argList = NULL; m_argTail = NULL; m_argCount = 0; m_list = 0; } /** * Destructor */ GameMessage::~GameMessage( ) { // free all arguments GameMessageArgument *arg, *nextArg; for( arg = m_argList; arg; arg=nextArg ) { nextArg = arg->m_next; arg->deleteInstance(); } // detach message from list if (m_list) m_list->removeMessage( this ); } /** * Return the given argument union. * @todo This should be a more list-like interface. Very inefficient. */ const GameMessageArgumentType *GameMessage::getArgument( Int argIndex ) const { static const GameMessageArgumentType junk = { 0 }; int i=0; for( GameMessageArgument *a = m_argList; a; a=a->m_next, i++ ) if (i == argIndex) return &a->m_data; DEBUG_CRASH(("argument not found")); return &junk; } /** * Return the given argument data type */ GameMessageArgumentDataType GameMessage::getArgumentDataType( Int argIndex ) { if (argIndex >= m_argCount) { return ARGUMENTDATATYPE_UNKNOWN; } int i=0; for (GameMessageArgument *a = m_argList; a && (i < argIndex); a=a->m_next, ++i ); if (a != NULL) { return a->m_type; } return ARGUMENTDATATYPE_UNKNOWN; } /** * Allocate a new argument, add it to the argument list, and increment the total arg count */ GameMessageArgument *GameMessage::allocArg( void ) { // allocate a new argument GameMessageArgument *arg = newInstance(GameMessageArgument); // add to end of argument list if (m_argTail) m_argTail->m_next = arg; else { m_argList = arg; m_argTail = arg; } arg->m_next = NULL; m_argTail = arg; m_argCount++; return arg; } /** * Append an integer argument */ void GameMessage::appendIntegerArgument( Int arg ) { GameMessageArgument *a = allocArg(); a->m_data.integer = arg; a->m_type = ARGUMENTDATATYPE_INTEGER; } void GameMessage::appendRealArgument( Real arg ) { GameMessageArgument *a = allocArg(); a->m_data.real = arg; a->m_type = ARGUMENTDATATYPE_REAL; } void GameMessage::appendBooleanArgument( Bool arg ) { GameMessageArgument *a = allocArg(); a->m_data.boolean = arg; a->m_type = ARGUMENTDATATYPE_BOOLEAN; } void GameMessage::appendObjectIDArgument( ObjectID arg ) { GameMessageArgument *a = allocArg(); a->m_data.objectID = arg; a->m_type = ARGUMENTDATATYPE_OBJECTID; } void GameMessage::appendDrawableIDArgument( DrawableID arg ) { GameMessageArgument *a = allocArg(); a->m_data.drawableID = arg; a->m_type = ARGUMENTDATATYPE_DRAWABLEID; } void GameMessage::appendTeamIDArgument( UnsignedInt arg ) { GameMessageArgument *a = allocArg(); a->m_data.teamID = arg; a->m_type = ARGUMENTDATATYPE_TEAMID; } void GameMessage::appendLocationArgument( const Coord3D& arg ) { GameMessageArgument *a = allocArg(); a->m_data.location = arg; a->m_type = ARGUMENTDATATYPE_LOCATION; } void GameMessage::appendPixelArgument( const ICoord2D& arg ) { GameMessageArgument *a = allocArg(); a->m_data.pixel = arg; a->m_type = ARGUMENTDATATYPE_PIXEL; } void GameMessage::appendPixelRegionArgument( const IRegion2D& arg ) { GameMessageArgument *a = allocArg(); a->m_data.pixelRegion = arg; a->m_type = ARGUMENTDATATYPE_PIXELREGION; } void GameMessage::appendTimestampArgument( UnsignedInt arg ) { GameMessageArgument *a = allocArg(); a->m_data.timestamp = arg; a->m_type = ARGUMENTDATATYPE_TIMESTAMP; } void GameMessage::appendWideCharArgument( const WideChar& arg ) { GameMessageArgument *a = allocArg(); a->m_data.wChar = arg; a->m_type = ARGUMENTDATATYPE_WIDECHAR; } AsciiString GameMessage::getCommandAsAsciiString( void ) { return getCommandTypeAsAsciiString(m_type); } AsciiString GameMessage::getCommandTypeAsAsciiString(GameMessage::Type t) { #define CHECK_IF(x) if (t == x) { return #x; } AsciiString commandName = "UnknownMessage"; if (t >= GameMessage::MSG_COUNT) { commandName = "Invalid command"; } CHECK_IF(MSG_INVALID) CHECK_IF(MSG_FRAME_TICK) CHECK_IF(MSG_RAW_MOUSE_BEGIN) CHECK_IF(MSG_RAW_MOUSE_POSITION) CHECK_IF(MSG_RAW_MOUSE_LEFT_BUTTON_DOWN) CHECK_IF(MSG_RAW_MOUSE_LEFT_DOUBLE_CLICK) CHECK_IF(MSG_RAW_MOUSE_LEFT_BUTTON_UP) CHECK_IF(MSG_RAW_MOUSE_LEFT_CLICK) CHECK_IF(MSG_RAW_MOUSE_LEFT_DRAG) CHECK_IF(MSG_RAW_MOUSE_MIDDLE_BUTTON_DOWN) CHECK_IF(MSG_RAW_MOUSE_MIDDLE_DOUBLE_CLICK) CHECK_IF(MSG_RAW_MOUSE_MIDDLE_BUTTON_UP) CHECK_IF(MSG_RAW_MOUSE_MIDDLE_DRAG) CHECK_IF(MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN) CHECK_IF(MSG_RAW_MOUSE_RIGHT_DOUBLE_CLICK) CHECK_IF(MSG_RAW_MOUSE_RIGHT_BUTTON_UP) CHECK_IF(MSG_RAW_MOUSE_RIGHT_DRAG) CHECK_IF(MSG_RAW_MOUSE_WHEEL) CHECK_IF(MSG_RAW_MOUSE_END) CHECK_IF(MSG_RAW_KEY_DOWN) CHECK_IF(MSG_RAW_KEY_UP) CHECK_IF(MSG_MOUSE_LEFT_CLICK) CHECK_IF(MSG_MOUSE_LEFT_DOUBLE_CLICK) CHECK_IF(MSG_MOUSE_MIDDLE_CLICK) CHECK_IF(MSG_MOUSE_MIDDLE_DOUBLE_CLICK) CHECK_IF(MSG_MOUSE_RIGHT_CLICK) CHECK_IF(MSG_MOUSE_RIGHT_DOUBLE_CLICK) CHECK_IF(MSG_CLEAR_GAME_DATA) CHECK_IF(MSG_NEW_GAME) CHECK_IF(MSG_BEGIN_META_MESSAGES) CHECK_IF(MSG_META_SAVE_VIEW1) CHECK_IF(MSG_META_SAVE_VIEW2) CHECK_IF(MSG_META_SAVE_VIEW3) CHECK_IF(MSG_META_SAVE_VIEW4) CHECK_IF(MSG_META_SAVE_VIEW5) CHECK_IF(MSG_META_SAVE_VIEW6) CHECK_IF(MSG_META_SAVE_VIEW7) CHECK_IF(MSG_META_SAVE_VIEW8) CHECK_IF(MSG_META_VIEW_VIEW1) CHECK_IF(MSG_META_VIEW_VIEW2) CHECK_IF(MSG_META_VIEW_VIEW3) CHECK_IF(MSG_META_VIEW_VIEW4) CHECK_IF(MSG_META_VIEW_VIEW5) CHECK_IF(MSG_META_VIEW_VIEW6) CHECK_IF(MSG_META_VIEW_VIEW7) CHECK_IF(MSG_META_VIEW_VIEW8) CHECK_IF(MSG_META_CREATE_TEAM0) CHECK_IF(MSG_META_CREATE_TEAM1) CHECK_IF(MSG_META_CREATE_TEAM2) CHECK_IF(MSG_META_CREATE_TEAM3) CHECK_IF(MSG_META_CREATE_TEAM4) CHECK_IF(MSG_META_CREATE_TEAM5) CHECK_IF(MSG_META_CREATE_TEAM6) CHECK_IF(MSG_META_CREATE_TEAM7) CHECK_IF(MSG_META_CREATE_TEAM8) CHECK_IF(MSG_META_CREATE_TEAM9) CHECK_IF(MSG_META_SELECT_TEAM0) CHECK_IF(MSG_META_SELECT_TEAM1) CHECK_IF(MSG_META_SELECT_TEAM2) CHECK_IF(MSG_META_SELECT_TEAM3) CHECK_IF(MSG_META_SELECT_TEAM4) CHECK_IF(MSG_META_SELECT_TEAM5) CHECK_IF(MSG_META_SELECT_TEAM6) CHECK_IF(MSG_META_SELECT_TEAM7) CHECK_IF(MSG_META_SELECT_TEAM8) CHECK_IF(MSG_META_SELECT_TEAM9) CHECK_IF(MSG_META_ADD_TEAM0) CHECK_IF(MSG_META_ADD_TEAM1) CHECK_IF(MSG_META_ADD_TEAM2) CHECK_IF(MSG_META_ADD_TEAM3) CHECK_IF(MSG_META_ADD_TEAM4) CHECK_IF(MSG_META_ADD_TEAM5) CHECK_IF(MSG_META_ADD_TEAM6) CHECK_IF(MSG_META_ADD_TEAM7) CHECK_IF(MSG_META_ADD_TEAM8) CHECK_IF(MSG_META_ADD_TEAM9) CHECK_IF(MSG_META_VIEW_TEAM0) CHECK_IF(MSG_META_VIEW_TEAM1) CHECK_IF(MSG_META_VIEW_TEAM2) CHECK_IF(MSG_META_VIEW_TEAM3) CHECK_IF(MSG_META_VIEW_TEAM4) CHECK_IF(MSG_META_VIEW_TEAM5) CHECK_IF(MSG_META_VIEW_TEAM6) CHECK_IF(MSG_META_VIEW_TEAM7) CHECK_IF(MSG_META_VIEW_TEAM8) CHECK_IF(MSG_META_VIEW_TEAM9) CHECK_IF(MSG_META_SELECT_MATCHING_UNITS) CHECK_IF(MSG_META_SELECT_NEXT_UNIT) CHECK_IF(MSG_META_SELECT_PREV_UNIT) CHECK_IF(MSG_META_SELECT_NEXT_WORKER) CHECK_IF(MSG_META_SELECT_PREV_WORKER) CHECK_IF(MSG_META_VIEW_COMMAND_CENTER) CHECK_IF(MSG_META_VIEW_LAST_RADAR_EVENT) CHECK_IF(MSG_META_SELECT_HERO) CHECK_IF(MSG_META_SELECT_ALL) CHECK_IF(MSG_META_SELECT_ALL_AIRCRAFT) CHECK_IF(MSG_META_SCATTER) CHECK_IF(MSG_META_STOP) CHECK_IF(MSG_META_DEPLOY) CHECK_IF(MSG_META_CREATE_FORMATION) CHECK_IF(MSG_META_FOLLOW) CHECK_IF(MSG_META_CHAT_PLAYERS) CHECK_IF(MSG_META_CHAT_ALLIES) CHECK_IF(MSG_META_CHAT_EVERYONE) CHECK_IF(MSG_META_DIPLOMACY) CHECK_IF(MSG_META_OPTIONS) #if defined(_DEBUG) || defined(_INTERNAL) CHECK_IF(MSG_META_HELP) #endif CHECK_IF(MSG_META_TOGGLE_LOWER_DETAILS) CHECK_IF(MSG_META_TOGGLE_CONTROL_BAR) CHECK_IF(MSG_META_BEGIN_PATH_BUILD) CHECK_IF(MSG_META_END_PATH_BUILD) CHECK_IF(MSG_META_BEGIN_FORCEATTACK) CHECK_IF(MSG_META_END_FORCEATTACK) CHECK_IF(MSG_META_BEGIN_FORCEMOVE) CHECK_IF(MSG_META_END_FORCEMOVE) CHECK_IF(MSG_META_BEGIN_WAYPOINTS) CHECK_IF(MSG_META_END_WAYPOINTS) CHECK_IF(MSG_META_BEGIN_PREFER_SELECTION) CHECK_IF(MSG_META_END_PREFER_SELECTION) CHECK_IF(MSG_META_TAKE_SCREENSHOT) CHECK_IF(MSG_META_ALL_CHEER) CHECK_IF(MSG_META_TOGGLE_ATTACKMOVE) CHECK_IF(MSG_META_BEGIN_CAMERA_ROTATE_LEFT) CHECK_IF(MSG_META_END_CAMERA_ROTATE_LEFT) CHECK_IF(MSG_META_BEGIN_CAMERA_ROTATE_RIGHT) CHECK_IF(MSG_META_END_CAMERA_ROTATE_RIGHT) CHECK_IF(MSG_META_BEGIN_CAMERA_ZOOM_IN) CHECK_IF(MSG_META_END_CAMERA_ZOOM_IN) CHECK_IF(MSG_META_BEGIN_CAMERA_ZOOM_OUT) CHECK_IF(MSG_META_END_CAMERA_ZOOM_OUT) CHECK_IF(MSG_META_CAMERA_RESET) CHECK_IF(MSG_META_TOGGLE_CAMERA_TRACKING_DRAWABLE) CHECK_IF(MSG_META_DEMO_INSTANT_QUIT) #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)//may be defined in GameCommon.h CHECK_IF(MSG_CHEAT_RUNSCRIPT1) CHECK_IF(MSG_CHEAT_RUNSCRIPT2) CHECK_IF(MSG_CHEAT_RUNSCRIPT3) CHECK_IF(MSG_CHEAT_RUNSCRIPT4) CHECK_IF(MSG_CHEAT_RUNSCRIPT5) CHECK_IF(MSG_CHEAT_RUNSCRIPT6) CHECK_IF(MSG_CHEAT_RUNSCRIPT7) CHECK_IF(MSG_CHEAT_RUNSCRIPT8) CHECK_IF(MSG_CHEAT_RUNSCRIPT9) CHECK_IF(MSG_CHEAT_TOGGLE_SPECIAL_POWER_DELAYS) CHECK_IF(MSG_CHEAT_SWITCH_TEAMS) CHECK_IF(MSG_CHEAT_KILL_SELECTION) CHECK_IF(MSG_CHEAT_TOGGLE_HAND_OF_GOD_MODE) CHECK_IF(MSG_CHEAT_INSTANT_BUILD) CHECK_IF(MSG_CHEAT_DESHROUD) CHECK_IF(MSG_CHEAT_ADD_CASH) CHECK_IF(MSG_CHEAT_GIVE_ALL_SCIENCES) CHECK_IF(MSG_CHEAT_GIVE_SCIENCEPURCHASEPOINTS) CHECK_IF(MSG_CHEAT_SHOW_HEALTH) CHECK_IF(MSG_CHEAT_TOGGLE_MESSAGE_TEXT) #endif CHECK_IF(MSG_META_TOGGLE_FAST_FORWARD_REPLAY) #if defined(_DEBUG) || defined(_INTERNAL) CHECK_IF(MSG_META_DEMO_TOGGLE_BEHIND_BUILDINGS) CHECK_IF(MSG_META_DEMO_TOGGLE_LETTERBOX) CHECK_IF(MSG_META_DEMO_TOGGLE_MESSAGE_TEXT) CHECK_IF(MSG_META_DEMO_LOD_DECREASE) CHECK_IF(MSG_META_DEMO_LOD_INCREASE) CHECK_IF(MSG_META_DEMO_TOGGLE_ZOOM_LOCK) CHECK_IF(MSG_META_DEMO_PLAY_CAMEO_MOVIE) CHECK_IF(MSG_META_DEMO_TOGGLE_SPECIAL_POWER_DELAYS) CHECK_IF(MSG_META_DEMO_BATTLE_CRY) CHECK_IF(MSG_META_DEMO_SWITCH_TEAMS) CHECK_IF(MSG_META_DEMO_SWITCH_TEAMS_BETWEEN_CHINA_USA) CHECK_IF(MSG_META_DEMO_TOGGLE_PARTICLEDEBUG) CHECK_IF(MSG_META_DEMO_TOGGLE_SHADOW_VOLUMES) CHECK_IF(MSG_META_DEMO_TOGGLE_FOGOFWAR) CHECK_IF(MSG_META_DEMO_KILL_ALL_ENEMIES) CHECK_IF(MSG_META_DEMO_KILL_SELECTION) CHECK_IF(MSG_META_DEMO_TOGGLE_HURT_ME_MODE) CHECK_IF(MSG_META_DEMO_TOGGLE_HAND_OF_GOD_MODE) CHECK_IF(MSG_META_DEMO_DEBUG_SELECTION) CHECK_IF(MSG_META_DEMO_LOCK_CAMERA_TO_SELECTION) CHECK_IF(MSG_META_DEMO_TOGGLE_SOUND) CHECK_IF(MSG_META_DEMO_TOGGLE_TRACKMARKS) CHECK_IF(MSG_META_DEMO_TOGGLE_WATERPLANE) CHECK_IF(MSG_META_DEMO_TIME_OF_DAY) CHECK_IF(MSG_META_DEMO_TOGGLE_MUSIC) CHECK_IF(MSG_META_DEMO_MUSIC_NEXT_TRACK) CHECK_IF(MSG_META_DEMO_MUSIC_PREV_TRACK) CHECK_IF(MSG_META_DEMO_NEXT_OBJECTIVE_MOVIE) CHECK_IF(MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE1) CHECK_IF(MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE2) CHECK_IF(MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE3) CHECK_IF(MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE4) CHECK_IF(MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE5) CHECK_IF(MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE6) CHECK_IF(MSG_META_DEMO_BEGIN_ADJUST_PITCH) CHECK_IF(MSG_META_DEMO_END_ADJUST_PITCH) CHECK_IF(MSG_META_DEMO_BEGIN_ADJUST_FOV) CHECK_IF(MSG_META_DEMO_END_ADJUST_FOV) CHECK_IF(MSG_META_DEMO_LOCK_CAMERA_TO_PLANES) CHECK_IF(MSG_META_DEMO_REMOVE_PREREQ) CHECK_IF(MSG_META_DEMO_INSTANT_BUILD) CHECK_IF(MSG_META_DEMO_FREE_BUILD) CHECK_IF(MSG_META_DEMO_RUNSCRIPT1) CHECK_IF(MSG_META_DEMO_RUNSCRIPT2) CHECK_IF(MSG_META_DEMO_RUNSCRIPT3) CHECK_IF(MSG_META_DEMO_RUNSCRIPT4) CHECK_IF(MSG_META_DEMO_RUNSCRIPT5) CHECK_IF(MSG_META_DEMO_RUNSCRIPT6) CHECK_IF(MSG_META_DEMO_RUNSCRIPT7) CHECK_IF(MSG_META_DEMO_RUNSCRIPT8) CHECK_IF(MSG_META_DEMO_RUNSCRIPT9) CHECK_IF(MSG_META_DEMO_ENSHROUD) CHECK_IF(MSG_META_DEMO_DESHROUD) CHECK_IF(MSG_META_DEBUG_SHOW_EXTENTS) CHECK_IF(MSG_META_DEBUG_SHOW_AUDIO_LOCATIONS) CHECK_IF(MSG_META_DEBUG_SHOW_HEALTH) CHECK_IF(MSG_META_DEBUG_GIVE_VETERANCY) CHECK_IF(MSG_META_DEBUG_TAKE_VETERANCY) CHECK_IF(MSG_META_DEMO_TOGGLE_AI_DEBUG) CHECK_IF(MSG_META_DEMO_TOGGLE_SUPPLY_CENTER_PLACEMENT) CHECK_IF(MSG_META_DEMO_TOGGLE_CAMERA_DEBUG) CHECK_IF(MSG_META_DEMO_TOGGLE_AVI) CHECK_IF(MSG_META_DEMO_TOGGLE_BW_VIEW) CHECK_IF(MSG_META_DEMO_TOGGLE_RED_VIEW) CHECK_IF(MSG_META_DEMO_TOGGLE_GREEN_VIEW) CHECK_IF(MSG_META_DEMO_TOGGLE_MOTION_BLUR_ZOOM) CHECK_IF(MSG_META_DEMO_TOGGLE_MILITARY_SUBTITLES) CHECK_IF(MSG_META_DEMO_ADD_CASH) #ifdef ALLOW_SURRENDER CHECK_IF(MSG_META_DEMO_TEST_SURRENDER) #endif CHECK_IF(MSG_META_DEMO_TOGGLE_RENDER) CHECK_IF(MSG_META_DEMO_KILL_AREA_SELECTION) CHECK_IF(MSG_META_DEMO_CYCLE_LOD_LEVEL) CHECK_IF(MSG_META_DEBUG_INCR_ANIM_SKATE_SPEED) CHECK_IF(MSG_META_DEBUG_DECR_ANIM_SKATE_SPEED) CHECK_IF(MSG_META_DEBUG_CYCLE_EXTENT_TYPE) CHECK_IF(MSG_META_DEBUG_INCREASE_EXTENT_MAJOR) CHECK_IF(MSG_META_DEBUG_INCREASE_EXTENT_MAJOR_BIG) CHECK_IF(MSG_META_DEBUG_DECREASE_EXTENT_MAJOR) CHECK_IF(MSG_META_DEBUG_DECREASE_EXTENT_MAJOR_BIG) CHECK_IF(MSG_META_DEBUG_INCREASE_EXTENT_MINOR) CHECK_IF(MSG_META_DEBUG_INCREASE_EXTENT_MINOR_BIG) CHECK_IF(MSG_META_DEBUG_DECREASE_EXTENT_MINOR) CHECK_IF(MSG_META_DEBUG_DECREASE_EXTENT_MINOR_BIG) CHECK_IF(MSG_META_DEBUG_INCREASE_EXTENT_HEIGHT) CHECK_IF(MSG_META_DEBUG_INCREASE_EXTENT_HEIGHT_BIG) CHECK_IF(MSG_META_DEBUG_DECREASE_EXTENT_HEIGHT) CHECK_IF(MSG_META_DEBUG_DECREASE_EXTENT_HEIGHT_BIG) CHECK_IF(MSG_META_DEBUG_VTUNE_ON) CHECK_IF(MSG_META_DEBUG_VTUNE_OFF) CHECK_IF(MSG_META_DEBUG_TOGGLE_FEATHER_WATER) CHECK_IF(MSG_META_DEBUG_DUMP_ASSETS) CHECK_IF(MSG_NO_DRAW) CHECK_IF(MSG_META_DEMO_TOGGLE_METRICS) CHECK_IF(MSG_META_DEMO_TOGGLE_PROJECTILEDEBUG) CHECK_IF(MSG_META_DEMO_TOGGLE_VISIONDEBUG) CHECK_IF(MSG_META_DEMO_TOGGLE_THREATDEBUG) CHECK_IF(MSG_META_DEMO_TOGGLE_CASHMAPDEBUG) CHECK_IF(MSG_META_DEMO_TOGGLE_GRAPHICALFRAMERATEBAR) CHECK_IF(MSG_META_DEMO_GIVE_ALL_SCIENCES) CHECK_IF(MSG_META_DEMO_GIVE_RANKLEVEL) CHECK_IF(MSG_META_DEMO_TAKE_RANKLEVEL) CHECK_IF(MSG_META_DEMO_GIVE_SCIENCEPURCHASEPOINTS) CHECK_IF(MSG_META_DEBUG_TOGGLE_NETWORK) CHECK_IF(MSG_META_DEBUG_DUMP_PLAYER_OBJECTS) CHECK_IF(MSG_META_DEBUG_DUMP_ALL_PLAYER_OBJECTS) CHECK_IF(MSG_META_DEBUG_OBJECT_ID_PERFORMANCE) CHECK_IF(MSG_META_DEBUG_DRAWABLE_ID_PERFORMANCE) CHECK_IF(MSG_META_DEBUG_SLEEPY_UPDATE_PERFORMANCE) CHECK_IF(MSG_META_DEBUG_WIN) CHECK_IF(MSG_META_DEMO_TOGGLE_DEBUG_STATS) #endif // defined(_DEBUG) || defined(_INTERNAL) #if defined(_INTERNAL) || defined(_DEBUG) CHECK_IF(MSG_META_DEMO_TOGGLE_AUDIODEBUG) #endif//defined(_INTERNAL) || defined(_DEBUG) #ifdef DUMP_PERF_STATS CHECK_IF(MSG_META_DEMO_PERFORM_STATISTICAL_DUMP) #endif//DUMP_PERF_STATS CHECK_IF(MSG_META_PLACE_BEACON) CHECK_IF(MSG_META_REMOVE_BEACON) CHECK_IF(MSG_END_META_MESSAGES) CHECK_IF(MSG_MOUSEOVER_DRAWABLE_HINT) CHECK_IF(MSG_MOUSEOVER_LOCATION_HINT) CHECK_IF(MSG_VALID_GUICOMMAND_HINT) CHECK_IF(MSG_INVALID_GUICOMMAND_HINT) CHECK_IF(MSG_AREA_SELECTION_HINT) CHECK_IF(MSG_DO_ATTACK_OBJECT_HINT) CHECK_IF(MSG_DO_ATTACK_OBJECT_AFTER_MOVING_HINT) CHECK_IF(MSG_DO_FORCE_ATTACK_OBJECT_HINT) CHECK_IF(MSG_DO_FORCE_ATTACK_GROUND_HINT) CHECK_IF(MSG_GET_REPAIRED_HINT) CHECK_IF(MSG_GET_HEALED_HINT) CHECK_IF(MSG_DO_REPAIR_HINT) CHECK_IF(MSG_RESUME_CONSTRUCTION_HINT) CHECK_IF(MSG_ENTER_HINT) CHECK_IF(MSG_DOCK_HINT) CHECK_IF(MSG_DO_MOVETO_HINT) CHECK_IF(MSG_DO_ATTACKMOVETO_HINT) CHECK_IF(MSG_ADD_WAYPOINT_HINT) CHECK_IF(MSG_HIJACK_HINT) CHECK_IF(MSG_SABOTAGE_HINT) CHECK_IF(MSG_FIREBOMB_HINT) CHECK_IF(MSG_CONVERT_TO_CARBOMB_HINT) CHECK_IF(MSG_CAPTUREBUILDING_HINT) CHECK_IF(MSG_HACK_HINT) #ifdef ALLOW_SURRENDER CHECK_IF(MSG_PICK_UP_PRISONER_HINT) #endif CHECK_IF(MSG_SNIPE_VEHICLE_HINT) CHECK_IF(MSG_DEFECTOR_HINT) CHECK_IF(MSG_SET_RALLY_POINT_HINT) CHECK_IF(MSG_DO_SALVAGE_HINT) CHECK_IF(MSG_DO_INVALID_HINT) CHECK_IF(MSG_BEGIN_NETWORK_MESSAGES) CHECK_IF(MSG_CREATE_SELECTED_GROUP) CHECK_IF(MSG_CREATE_SELECTED_GROUP_NO_SOUND) CHECK_IF(MSG_DESTROY_SELECTED_GROUP) CHECK_IF(MSG_REMOVE_FROM_SELECTED_GROUP) CHECK_IF(MSG_SELECTED_GROUP_COMMAND) CHECK_IF(MSG_CREATE_TEAM0) CHECK_IF(MSG_CREATE_TEAM1) CHECK_IF(MSG_CREATE_TEAM2) CHECK_IF(MSG_CREATE_TEAM3) CHECK_IF(MSG_CREATE_TEAM4) CHECK_IF(MSG_CREATE_TEAM5) CHECK_IF(MSG_CREATE_TEAM6) CHECK_IF(MSG_CREATE_TEAM7) CHECK_IF(MSG_CREATE_TEAM8) CHECK_IF(MSG_CREATE_TEAM9) CHECK_IF(MSG_SELECT_TEAM0) CHECK_IF(MSG_SELECT_TEAM1) CHECK_IF(MSG_SELECT_TEAM2) CHECK_IF(MSG_SELECT_TEAM3) CHECK_IF(MSG_SELECT_TEAM4) CHECK_IF(MSG_SELECT_TEAM5) CHECK_IF(MSG_SELECT_TEAM6) CHECK_IF(MSG_SELECT_TEAM7) CHECK_IF(MSG_SELECT_TEAM8) CHECK_IF(MSG_SELECT_TEAM9) CHECK_IF(MSG_ADD_TEAM0) CHECK_IF(MSG_ADD_TEAM1) CHECK_IF(MSG_ADD_TEAM2) CHECK_IF(MSG_ADD_TEAM3) CHECK_IF(MSG_ADD_TEAM4) CHECK_IF(MSG_ADD_TEAM5) CHECK_IF(MSG_ADD_TEAM6) CHECK_IF(MSG_ADD_TEAM7) CHECK_IF(MSG_ADD_TEAM8) CHECK_IF(MSG_ADD_TEAM9) CHECK_IF(MSG_DO_ATTACKSQUAD) CHECK_IF(MSG_DO_WEAPON) CHECK_IF(MSG_DO_WEAPON_AT_LOCATION) CHECK_IF(MSG_DO_WEAPON_AT_OBJECT) CHECK_IF(MSG_DO_SPECIAL_POWER) CHECK_IF(MSG_DO_SPECIAL_POWER_AT_LOCATION) CHECK_IF(MSG_DO_SPECIAL_POWER_AT_OBJECT) CHECK_IF(MSG_SET_RALLY_POINT) CHECK_IF(MSG_PURCHASE_SCIENCE) CHECK_IF(MSG_QUEUE_UPGRADE) CHECK_IF(MSG_CANCEL_UPGRADE) CHECK_IF(MSG_QUEUE_UNIT_CREATE) CHECK_IF(MSG_CANCEL_UNIT_CREATE) CHECK_IF(MSG_DOZER_CONSTRUCT) CHECK_IF(MSG_DOZER_CONSTRUCT_LINE) CHECK_IF(MSG_DOZER_CANCEL_CONSTRUCT) CHECK_IF(MSG_SELL) CHECK_IF(MSG_EXIT) CHECK_IF(MSG_EVACUATE) CHECK_IF(MSG_EXECUTE_RAILED_TRANSPORT) CHECK_IF(MSG_COMBATDROP_AT_LOCATION) CHECK_IF(MSG_COMBATDROP_AT_OBJECT) CHECK_IF(MSG_AREA_SELECTION) CHECK_IF(MSG_DO_ATTACK_OBJECT) CHECK_IF(MSG_DO_FORCE_ATTACK_OBJECT) CHECK_IF(MSG_DO_FORCE_ATTACK_GROUND) CHECK_IF(MSG_GET_REPAIRED) CHECK_IF(MSG_GET_HEALED) CHECK_IF(MSG_DO_REPAIR) CHECK_IF(MSG_RESUME_CONSTRUCTION) CHECK_IF(MSG_ENTER) CHECK_IF(MSG_DOCK) CHECK_IF(MSG_DO_MOVETO) CHECK_IF(MSG_DO_ATTACKMOVETO) CHECK_IF(MSG_DO_FORCEMOVETO) CHECK_IF(MSG_ADD_WAYPOINT) CHECK_IF(MSG_DO_GUARD_POSITION) CHECK_IF(MSG_DO_GUARD_OBJECT) CHECK_IF(MSG_DO_STOP) CHECK_IF(MSG_DO_SCATTER) CHECK_IF(MSG_INTERNET_HACK) CHECK_IF(MSG_DO_CHEER) #ifdef ALLOW_SURRENDER CHECK_IF(MSG_DO_SURRENDER) #endif CHECK_IF(MSG_TOGGLE_OVERCHARGE) #ifdef ALLOW_SURRENDER CHECK_IF(MSG_RETURN_TO_PRISON) #endif CHECK_IF(MSG_SWITCH_WEAPONS) CHECK_IF(MSG_CONVERT_TO_CARBOMB) CHECK_IF(MSG_CAPTUREBUILDING) CHECK_IF(MSG_DISABLEVEHICLE_HACK) CHECK_IF(MSG_STEALCASH_HACK) CHECK_IF(MSG_DISABLEBUILDING_HACK) CHECK_IF(MSG_SNIPE_VEHICLE) #ifdef ALLOW_SURRENDER CHECK_IF(MSG_PICK_UP_PRISONER) #endif CHECK_IF(MSG_DO_SALVAGE) CHECK_IF(MSG_CLEAR_INGAME_POPUP_MESSAGE) CHECK_IF(MSG_PLACE_BEACON) CHECK_IF(MSG_REMOVE_BEACON) CHECK_IF(MSG_SET_BEACON_TEXT) CHECK_IF(MSG_SET_REPLAY_CAMERA) CHECK_IF(MSG_SELF_DESTRUCT) CHECK_IF(MSG_CREATE_FORMATION) CHECK_IF(MSG_LOGIC_CRC) #if defined(_DEBUG) || defined(_INTERNAL) CHECK_IF(MSG_DEBUG_KILL_SELECTION) CHECK_IF(MSG_DEBUG_HURT_OBJECT) CHECK_IF(MSG_DEBUG_KILL_OBJECT) #endif CHECK_IF(MSG_END_NETWORK_MESSAGES) CHECK_IF(MSG_TIMESTAMP) CHECK_IF(MSG_OBJECT_CREATED) CHECK_IF(MSG_OBJECT_DESTROYED) CHECK_IF(MSG_OBJECT_POSITION) CHECK_IF(MSG_OBJECT_ORIENTATION) CHECK_IF(MSG_OBJECT_JOINED_TEAM) CHECK_IF(MSG_SET_MINE_CLEARING_DETAIL) CHECK_IF(MSG_ENABLE_RETALIATION_MODE) return commandName; } //------------------------------------------------------------------------------------------------ // GameMessageList // /** * Constructor */ GameMessageList::GameMessageList( void ) { m_firstMessage = 0; m_lastMessage = 0; } /** * Destructor */ GameMessageList::~GameMessageList() { // destroy all messages currently on the list GameMessage *msg, *nextMsg; for( msg = m_firstMessage; msg; msg = nextMsg ) { nextMsg = msg->next(); // set list ptr to null to avoid it trying to remove itself from the list // that we are in the process of nuking... msg->friend_setList(NULL); msg->deleteInstance(); } } /** * Append message to end of message list */ void GameMessageList::appendMessage( GameMessage *msg ) { msg->friend_setNext(NULL); if (m_lastMessage) { m_lastMessage->friend_setNext(msg); msg->friend_setPrev(m_lastMessage); m_lastMessage = msg; } else { // first message m_firstMessage = msg; m_lastMessage = msg; msg->friend_setPrev(NULL); } // note containment within message itself msg->friend_setList(this); } /** * Inserts the msg after messageToInsertAfter. */ void GameMessageList::insertMessage( GameMessage *msg, GameMessage *messageToInsertAfter ) { // First, set msg's next to be messageToInsertAfter's next. msg->friend_setNext(messageToInsertAfter->next()); // Next, set msg's prev to be messageToInsertAfter msg->friend_setPrev(messageToInsertAfter); // Now update the next message's prev to be msg if (msg->next()) msg->next()->friend_setPrev(msg); else // if the friend wasn't there, then messageToInsertAfter is the last message. Update it to be msg. m_lastMessage = msg; // Finally, update the messageToInsertAfter's next to be msg messageToInsertAfter->friend_setNext(msg); // note containment within the message itself msg->friend_setList(this); } /** * Remove given message from the list. */ void GameMessageList::removeMessage( GameMessage *msg ) { if (msg->next()) msg->next()->friend_setPrev(msg->prev()); else m_lastMessage = msg->prev(); if (msg->prev()) msg->prev()->friend_setNext(msg->next()); else m_firstMessage = msg->next(); msg->friend_setList(NULL); } /** * Return whether or not a message of the given type is in the message list */ Bool GameMessageList::containsMessageOfType( GameMessage::Type type ) { GameMessage *msg = getFirstMessage(); while (msg) { if (msg->getType() == type) { return true; } msg = msg->next(); } return false; } //------------------------------------------------------------------------------------------------ // MessageStream // /** * Constructor */ MessageStream::MessageStream( void ) { m_firstTranslator = 0; m_nextTranslatorID = 1; } /** * Destructor */ MessageStream::~MessageStream() { // destroy all translators TranslatorData *trans, *nextTrans; for( trans=m_firstTranslator; trans; trans=nextTrans ) { nextTrans = trans->m_next; delete trans; } } /** * Init */ void MessageStream::init( void ) { // extend GameMessageList::init(); } /** * Reset */ void MessageStream::reset( void ) { /// @todo Reset the MessageStream // extend GameMessageList::reset(); } /** * Update */ void MessageStream::update( void ) { // extend GameMessageList::update(); } /** * Create a new message of the given message type and append it * to this message stream. Return the message such that any data * associated with this message can be attached to it. */ GameMessage *MessageStream::appendMessage( GameMessage::Type type ) { GameMessage *msg = newInstance(GameMessage)( type ); // add message to list GameMessageList::appendMessage( msg ); return msg; } /** * Create a new message of the given message type and insert it * in the stream after messageToInsertAfter, which must not be NULL. */ GameMessage *MessageStream::insertMessage( GameMessage::Type type, GameMessage *messageToInsertAfter ) { GameMessage *msg = newInstance(GameMessage)(type); GameMessageList::insertMessage(msg, messageToInsertAfter); return msg; } /** * Attach the given Translator to the message stream, and return a * unique TranslatorID identifying it. * Translators are placed on a list, sorted by priority order. If two * Translators share a priority, they are kept in the same order they * were attached. */ TranslatorID MessageStream::attachTranslator( GameMessageTranslator *translator, UnsignedInt priority) { MessageStream::TranslatorData *newSS = NEW MessageStream::TranslatorData; MessageStream::TranslatorData *ss; newSS->m_translator = translator; newSS->m_priority = priority; newSS->m_id = m_nextTranslatorID++; if (m_firstTranslator == NULL) { // first Translator to be attached newSS->m_prev = NULL; newSS->m_next = NULL; m_firstTranslator = newSS; m_lastTranslator = newSS; return newSS->m_id; } // seach the Translator list for our priority location for( ss=m_firstTranslator; ss; ss=ss->m_next ) if (ss->m_priority > newSS->m_priority) break; if (ss) { // insert new Translator just BEFORE this one, // therefore, m_lastTranslator cannot be affected if (ss->m_prev) { ss->m_prev->m_next = newSS; newSS->m_prev = ss->m_prev; newSS->m_next = ss; ss->m_prev = newSS; } else { // insert at head of list newSS->m_prev = NULL; newSS->m_next = m_firstTranslator; m_firstTranslator->m_prev = newSS; m_firstTranslator = newSS; } } else { // append Translator to end of list m_lastTranslator->m_next = newSS; newSS->m_prev = m_lastTranslator; newSS->m_next = NULL; m_lastTranslator = newSS; } return newSS->m_id; } /** * Find a translator attached to this message stream given the ID */ GameMessageTranslator* MessageStream::findTranslator( TranslatorID id ) { MessageStream::TranslatorData *translatorData; for( translatorData = m_firstTranslator; translatorData; translatorData = translatorData->m_next ) { if( translatorData->m_id == id ) return translatorData->m_translator; } return NULL; } /** * Remove a previously attached translator. */ void MessageStream::removeTranslator( TranslatorID id ) { MessageStream::TranslatorData *ss; for( ss=m_firstTranslator; ss; ss=ss->m_next ) if (ss->m_id == id) { // found the translator - remove it if (ss->m_prev) ss->m_prev->m_next = ss->m_next; else m_firstTranslator = ss->m_next; if (ss->m_next) ss->m_next->m_prev = ss->m_prev; else m_lastTranslator = ss->m_prev; // delete the translator data delete ss; break; } } // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ #if defined(_DEBUG) || defined(_INTERNAL) Bool isInvalidDebugCommand( GameMessage::Type t ) { // see if this is something that should be prevented in multiplayer games // Don't reject this stuff in skirmish games. if (TheGameLogic && !TheGameLogic->isInSkirmishGame() && (TheRecorder && TheRecorder->isMultiplayer() && TheRecorder->getMode() == RECORDERMODETYPE_RECORD)) { switch (t) { case GameMessage::MSG_META_DEMO_SWITCH_TEAMS: case GameMessage::MSG_META_DEMO_SWITCH_TEAMS_BETWEEN_CHINA_USA: case GameMessage::MSG_META_DEMO_KILL_ALL_ENEMIES: case GameMessage::MSG_META_DEMO_KILL_SELECTION: case GameMessage::MSG_META_DEMO_TOGGLE_HURT_ME_MODE: case GameMessage::MSG_META_DEMO_TOGGLE_HAND_OF_GOD_MODE: case GameMessage::MSG_META_DEMO_TOGGLE_SPECIAL_POWER_DELAYS: case GameMessage::MSG_META_DEMO_TIME_OF_DAY: case GameMessage::MSG_META_DEMO_LOCK_CAMERA_TO_PLANES: case GameMessage::MSG_META_DEMO_REMOVE_PREREQ: case GameMessage::MSG_META_DEMO_INSTANT_BUILD: case GameMessage::MSG_META_DEMO_FREE_BUILD: 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: case GameMessage::MSG_META_DEMO_ENSHROUD: case GameMessage::MSG_META_DEMO_DESHROUD: case GameMessage::MSG_META_DEBUG_GIVE_VETERANCY: case GameMessage::MSG_META_DEBUG_TAKE_VETERANCY: //#pragma MESSAGE ("WARNING - DEBUG key in multiplayer!") case GameMessage::MSG_META_DEMO_ADD_CASH: case GameMessage::MSG_META_DEBUG_INCR_ANIM_SKATE_SPEED: case GameMessage::MSG_META_DEBUG_DECR_ANIM_SKATE_SPEED: case GameMessage::MSG_META_DEBUG_CYCLE_EXTENT_TYPE: case GameMessage::MSG_META_DEMO_TOGGLE_RENDER: case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MAJOR: case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MAJOR_BIG: case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MAJOR: case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MAJOR_BIG: case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MINOR: case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MINOR_BIG: case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MINOR: case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MINOR_BIG: case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_HEIGHT: case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_HEIGHT_BIG: case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_HEIGHT: case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_HEIGHT_BIG: case GameMessage::MSG_META_DEMO_KILL_AREA_SELECTION: case GameMessage::MSG_DEBUG_KILL_SELECTION: case GameMessage::MSG_DEBUG_HURT_OBJECT: case GameMessage::MSG_DEBUG_KILL_OBJECT: case GameMessage::MSG_META_DEMO_GIVE_SCIENCEPURCHASEPOINTS: case GameMessage::MSG_META_DEMO_GIVE_ALL_SCIENCES: case GameMessage::MSG_META_DEMO_GIVE_RANKLEVEL: case GameMessage::MSG_META_DEMO_TAKE_RANKLEVEL: case GameMessage::MSG_META_DEBUG_WIN: return true; } } return false; } #endif /** * Propagate messages thru attached Translators, invoking each Translator's * callback for each message in the stream. * Once all Translators have evaluated the message stream, all messages * in the stream are destroyed. */ void MessageStream::propagateMessages( void ) { MessageStream::TranslatorData *ss; GameMessage *msg, *next; // process each Translator for( ss=m_firstTranslator; ss; ss=ss->m_next ) { for( msg=m_firstMessage; msg; msg=next ) { if (ss->m_translator #if defined(_DEBUG) || defined(_INTERNAL) && !isInvalidDebugCommand(msg->getType()) #endif ) { GameMessageDisposition disp = ss->m_translator->translateGameMessage(msg); next = msg->next(); if (disp == DESTROY_MESSAGE) { msg->deleteInstance(); } } else { next = msg->next(); } } } // transfer all messages that reached the end of the stream to TheCommandList TheCommandList->appendMessageList( m_firstMessage ); // clear the stream m_firstMessage = NULL; m_lastMessage = NULL; } //------------------------------------------------------------------------------------------------ // CommandList // /** * Constructor */ CommandList::CommandList( void ) { } /** * Destructor */ CommandList::~CommandList() { destroyAllMessages(); } /** * Init */ void CommandList::init( void ) { // extend GameMessageList::init(); } /** * Destroy all messages on the list, and reset list to empty */ void CommandList::reset( void ) { // extend GameMessageList::reset(); // destroy all messages destroyAllMessages(); } /** * Update */ void CommandList::update( void ) { // extend GameMessageList::update(); } /** * Destroy all messages on the command list, this will get called from the * destructor and reset methods, DO NOT throw exceptions */ void CommandList::destroyAllMessages( void ) { GameMessage *msg, *next; for( msg=m_firstMessage; msg; msg=next ) { next = msg->next(); msg->deleteInstance(); } m_firstMessage = NULL; m_lastMessage = NULL; } /** * Adds messages to the end of TheCommandList. * Primarily used by TheMessageStream to put the final messages that reach the end of the * stream on TheCommandList. Since TheGameClient will update faster than TheNetwork * and TheGameLogic, messages will accumulate on this list. */ void CommandList::appendMessageList( GameMessage *list ) { GameMessage *msg, *next; for( msg = list; msg; msg = next ) { next = msg->next(); appendMessage( msg ); } } //----------------------------------------------------------------------------- /** * Given an "anchor" point and the current mouse position (dest), * construct a valid 2D bounding region. */ void buildRegion( const ICoord2D *anchor, const ICoord2D *dest, IRegion2D *region ) { // build rectangular region defined by the drag selection if (anchor->x < dest->x) { region->lo.x = anchor->x; region->hi.x = dest->x; } else { region->lo.x = dest->x; region->hi.x = anchor->x; } if (anchor->y < dest->y) { region->lo.y = anchor->y; region->hi.y = dest->y; } else { region->lo.y = dest->y; region->hi.y = anchor->y; } }