TerrainRoads.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: TerrainRoads.cpp /////////////////////////////////////////////////////////////////////////
  24. // Author: Colin Day, December 2001
  25. // Desc: Terrain road/bridge descriptions
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLDUES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #define DEFINE_BODYDAMAGETYPE_NAMES
  30. #include "Common/INI.h"
  31. #include "GameClient/TerrainRoads.h"
  32. // PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
  33. TerrainRoadCollection *TheTerrainRoads = NULL;
  34. // PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
  35. UnsignedInt TerrainRoadCollection::m_idCounter = 0;
  36. //-------------------------------------------------------------------------------------------------
  37. //-------------------------------------------------------------------------------------------------
  38. const FieldParse TerrainRoadType::m_terrainRoadFieldParseTable[] =
  39. {
  40. { "Texture", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_texture ) },
  41. { "RoadWidth", INI::parseReal, NULL, offsetof( TerrainRoadType, m_roadWidth ) },
  42. { "RoadWidthInTexture", INI::parseReal, NULL, offsetof( TerrainRoadType, m_roadWidthInTexture ) },
  43. { NULL, NULL, NULL, 0 },
  44. };
  45. //-------------------------------------------------------------------------------------------------
  46. //-------------------------------------------------------------------------------------------------
  47. const FieldParse TerrainRoadType::m_terrainBridgeFieldParseTable[] =
  48. {
  49. { "BridgeScale", INI::parseReal, NULL, offsetof( TerrainRoadType, m_bridgeScale ) },
  50. { "ScaffoldObjectName", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_scaffoldObjectName ) },
  51. { "ScaffoldSupportObjectName", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_scaffoldSupportObjectName ) },
  52. { "RadarColor", INI::parseRGBColor, NULL, offsetof( TerrainRoadType, m_radarColor ) },
  53. { "TransitionEffectsHeight", INI::parseReal, NULL, offsetof( TerrainRoadType, m_transitionEffectsHeight ) },
  54. { "NumFXPerType", INI::parseInt, NULL, offsetof( TerrainRoadType, m_numFXPerType ) },
  55. { "BridgeModelName", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_bridgeModelName ) },
  56. { "Texture", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_texture ) },
  57. { "BridgeModelNameDamaged", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_bridgeModelNameDamaged ) },
  58. { "TextureDamaged", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_textureDamaged ) },
  59. { "BridgeModelNameReallyDamaged", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_bridgeModelNameReallyDamaged ) },
  60. { "TextureReallyDamaged", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_textureReallyDamaged ) },
  61. { "BridgeModelNameBroken", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_bridgeModelNameBroken ) },
  62. { "TextureBroken", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_textureBroken ) },
  63. { "TowerObjectNameFromLeft", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_towerObjectName[ BRIDGE_TOWER_FROM_LEFT ] ) },
  64. { "TowerObjectNameFromRight", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_towerObjectName[ BRIDGE_TOWER_FROM_RIGHT ] ) },
  65. { "TowerObjectNameToLeft", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_towerObjectName[ BRIDGE_TOWER_TO_LEFT ] ) },
  66. { "TowerObjectNameToRight", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_towerObjectName[ BRIDGE_TOWER_TO_RIGHT ] ) },
  67. { "DamagedToSound", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_damageToSoundString[ BODY_DAMAGED ] ) },
  68. { "RepairedToSound", INI::parseAsciiString, NULL, offsetof( TerrainRoadType, m_repairedToSoundString[ BODY_DAMAGED ] ) },
  69. { "TransitionToOCL", parseTransitionToOCL, NULL, NULL },
  70. { "TransitionToFX", parseTransitionToFX, NULL, NULL },
  71. { NULL, NULL, NULL, 0 },
  72. };
  73. // ------------------------------------------------------------------------------------------------
  74. /** In the form of
  75. * Label = Transition:<Damage|Repair> ToState:<BODYTYPE> EffectNum:<INT> OCL:<OCL NAME> */
  76. // ------------------------------------------------------------------------------------------------
  77. /*static*/ void TerrainRoadType::parseTransitionToOCL( INI *ini,
  78. void *instance,
  79. void *store,
  80. const void *userData )
  81. {
  82. const char *token;
  83. TerrainRoadType *theInstance = (TerrainRoadType *)instance;
  84. // which transition is this
  85. Bool damageTransition;
  86. token = ini->getNextSubToken( "Transition" );
  87. if( stricmp( token, "Damage" ) == 0 )
  88. damageTransition = TRUE;
  89. else if( stricmp( token, "Repair" ) == 0 )
  90. damageTransition = FALSE;
  91. else
  92. {
  93. DEBUG_CRASH(( "Expected Damage/Repair transition keyword\n" ));
  94. throw INI_INVALID_DATA;
  95. } // end else
  96. // get body damage state
  97. token = ini->getNextSubToken( "ToState" );
  98. BodyDamageType state = (BodyDamageType)ini->scanIndexList( token, TheBodyDamageTypeNames );
  99. // get effect num
  100. token = ini->getNextSubToken( "EffectNum" );
  101. Int effectNum = ini->scanInt( token );
  102. // make effectNum zero based
  103. --effectNum;
  104. // sanity check effect num
  105. if( effectNum < 0 || effectNum >= MAX_BRIDGE_BODY_FX )
  106. {
  107. DEBUG_CRASH(( "Effect number max on bridge transitions is '%d'\n", MAX_BRIDGE_BODY_FX ));
  108. throw INI_INVALID_DATA;
  109. } // end if
  110. // read the string
  111. token = ini->getNextSubToken( "OCL" );
  112. if( damageTransition )
  113. theInstance->friend_setDamageToOCLString( state, effectNum, AsciiString( token ) );
  114. else
  115. theInstance->friend_setRepairedToOCLString( state, effectNum, AsciiString( token ) );
  116. } // end parseTransitionToOCL
  117. // ------------------------------------------------------------------------------------------------
  118. /** In the form of
  119. * Label = Transition:<Damage|Repair> ToState:<BODYTYPE> EffectNum:<INT> FX:<FXLIST NAME> */
  120. // ------------------------------------------------------------------------------------------------
  121. /*static*/ void TerrainRoadType::parseTransitionToFX( INI *ini,
  122. void *instance,
  123. void *store,
  124. const void *userData )
  125. {
  126. const char *token;
  127. TerrainRoadType *theInstance = (TerrainRoadType *)instance;
  128. // which transition is this
  129. Bool damageTransition;
  130. token = ini->getNextSubToken( "Transition" );
  131. if( stricmp( token, "Damage" ) == 0 )
  132. damageTransition = TRUE;
  133. else if( stricmp( token, "Repair" ) == 0 )
  134. damageTransition = FALSE;
  135. else
  136. {
  137. DEBUG_CRASH(( "Expected Damage/Repair transition keyword\n" ));
  138. throw INI_INVALID_DATA;
  139. } // end else
  140. // get body damage state
  141. token = ini->getNextSubToken( "ToState" );
  142. BodyDamageType state = (BodyDamageType)ini->scanIndexList( token, TheBodyDamageTypeNames );
  143. // get effect num
  144. token = ini->getNextSubToken( "EffectNum" );
  145. Int effectNum = ini->scanInt( token );
  146. // make effectNum zero based
  147. --effectNum;
  148. // sanity check effect num
  149. if( effectNum < 0 || effectNum >= MAX_BRIDGE_BODY_FX )
  150. {
  151. DEBUG_CRASH(( "Effect number max on bridge transitions is '%d'\n", MAX_BRIDGE_BODY_FX ));
  152. throw INI_INVALID_DATA;
  153. } // end if
  154. // read the string
  155. token = ini->getNextSubToken( "FX" );
  156. if( damageTransition )
  157. theInstance->friend_setDamageToFXString( state, effectNum, AsciiString( token ) );
  158. else
  159. theInstance->friend_setRepairedToFXString( state, effectNum, AsciiString( token ) );
  160. } // end parseTransitionToFX
  161. //-------------------------------------------------------------------------------------------------
  162. //-------------------------------------------------------------------------------------------------
  163. TerrainRoadType::TerrainRoadType( void )
  164. {
  165. m_isBridge = FALSE;
  166. m_id = 0;
  167. m_next = NULL;
  168. m_roadWidth = 0.0f;
  169. m_roadWidthInTexture = 0.0f;
  170. m_bridgeScale = 1.0f;
  171. m_radarColor.red = 0.0f;
  172. m_radarColor.green = 0.0f;
  173. m_radarColor.blue = 0.0f;
  174. m_transitionEffectsHeight = 0.0f;
  175. m_numFXPerType = 0;
  176. } // end TerrainRoadType
  177. //-------------------------------------------------------------------------------------------------
  178. //-------------------------------------------------------------------------------------------------
  179. TerrainRoadType::~TerrainRoadType( void )
  180. {
  181. } // end ~TerrainRoadType
  182. ///////////////////////////////////////////////////////////////////////////////////////////////////
  183. ///////////////////////////////////////////////////////////////////////////////////////////////////
  184. ///////////////////////////////////////////////////////////////////////////////////////////////////
  185. //-------------------------------------------------------------------------------------------------
  186. //-------------------------------------------------------------------------------------------------
  187. TerrainRoadCollection::TerrainRoadCollection( void )
  188. {
  189. m_roadList = NULL;
  190. m_bridgeList = NULL;
  191. m_idCounter = 1; ///< MUST start this at 1.
  192. } // end TerrainRoadCollection
  193. //-------------------------------------------------------------------------------------------------
  194. //-------------------------------------------------------------------------------------------------
  195. TerrainRoadCollection::~TerrainRoadCollection( void )
  196. {
  197. TerrainRoadType *temp;
  198. // delete all roads in the list
  199. while( m_roadList )
  200. {
  201. // get next road
  202. temp = m_roadList->friend_getNext();
  203. // delete this road
  204. m_roadList->deleteInstance();
  205. // set the new head of the list
  206. m_roadList = temp;
  207. } // end while
  208. // delete all bridges in the list
  209. while( m_bridgeList )
  210. {
  211. // get next bridge
  212. temp = m_bridgeList->friend_getNext();
  213. // delete this bridge
  214. m_bridgeList->deleteInstance();
  215. // set the new head of the list
  216. m_bridgeList = temp;
  217. } // end while
  218. } // end ~TerrainRoadCollection
  219. //-------------------------------------------------------------------------------------------------
  220. /** Find road with matching name */
  221. //-------------------------------------------------------------------------------------------------
  222. TerrainRoadType *TerrainRoadCollection::findRoad( AsciiString name )
  223. {
  224. TerrainRoadType *road;
  225. for( road = m_roadList; road; road = nextRoad( road ) )
  226. {
  227. if( road->getName() == name )
  228. return road;
  229. } // end for road
  230. // not found
  231. return NULL;
  232. } // end findRoad
  233. //-------------------------------------------------------------------------------------------------
  234. /** Find bridge with matching name */
  235. //-------------------------------------------------------------------------------------------------
  236. TerrainRoadType *TerrainRoadCollection::findBridge( AsciiString name )
  237. {
  238. TerrainRoadType *bridge;
  239. for( bridge = m_bridgeList; bridge; bridge = nextBridge( bridge ) )
  240. {
  241. if( bridge->getName() == name )
  242. return bridge;
  243. } // end for bridge
  244. // not found
  245. return NULL;
  246. } // end findBridge
  247. //-------------------------------------------------------------------------------------------------
  248. /** Search the roads AND bridge lists for the name */
  249. //-------------------------------------------------------------------------------------------------
  250. TerrainRoadType *TerrainRoadCollection::findRoadOrBridge( AsciiString name )
  251. {
  252. TerrainRoadType *road = findRoad( name );
  253. if( road )
  254. return road;
  255. else
  256. return findBridge( name );
  257. } // end findRoadOrBridge
  258. //-------------------------------------------------------------------------------------------------
  259. /** Allocate a new road, set the name, and link to the road list */
  260. //-------------------------------------------------------------------------------------------------
  261. TerrainRoadType *TerrainRoadCollection::newRoad( AsciiString name )
  262. {
  263. TerrainRoadType *road = newInstance(TerrainRoadType);
  264. // assign the name
  265. road->friend_setName( name );
  266. // assign unique id
  267. road->friend_setID( m_idCounter++ );
  268. // is not a bridge
  269. road->friend_setBridge( FALSE );
  270. // set defaults from the default road
  271. TerrainRoadType *defaultRoad = findRoad( AsciiString( "DefaultRoad" ) );
  272. if( defaultRoad )
  273. {
  274. road->friend_setTexture( defaultRoad->getTexture() );
  275. road->friend_setRoadWidth( defaultRoad->getRoadWidth() );
  276. road->friend_setRoadWidthInTexture( defaultRoad->getRoadWidthInTexture() );
  277. } // end if
  278. // link to list
  279. road->friend_setNext( m_roadList );
  280. m_roadList = road;
  281. // return the new road
  282. return road;
  283. } // end newRoad
  284. //-------------------------------------------------------------------------------------------------
  285. /** Allocate a new bridge */
  286. //-------------------------------------------------------------------------------------------------
  287. TerrainRoadType *TerrainRoadCollection::newBridge( AsciiString name )
  288. {
  289. TerrainRoadType *bridge = newInstance(TerrainRoadType);
  290. // assign the name
  291. bridge->friend_setName( name );
  292. // assign unique id
  293. bridge->friend_setID( m_idCounter++ );
  294. // is a bridge
  295. bridge->friend_setBridge( TRUE );
  296. // set defaults from the default bridge
  297. TerrainRoadType *defaultBridge = findBridge( AsciiString( "DefaultBridge" ) );
  298. if( defaultBridge )
  299. {
  300. bridge->friend_setTexture( defaultBridge->getTexture() );
  301. bridge->friend_setBridgeScale( defaultBridge->getBridgeScale() );
  302. bridge->friend_setBridgeModelName( defaultBridge->getBridgeModel() );
  303. bridge->friend_setBridgeModelNameDamaged( defaultBridge->getBridgeModelNameDamaged() );
  304. bridge->friend_setBridgeModelNameReallyDamaged( defaultBridge->getBridgeModelNameReallyDamaged() );
  305. bridge->friend_setBridgeModelNameBroken( defaultBridge->getBridgeModelNameBroken() );
  306. bridge->friend_setTextureDamaged( defaultBridge->getTextureDamaged() );
  307. bridge->friend_setTextureReallyDamaged( defaultBridge->getTextureReallyDamaged() );
  308. bridge->friend_setTextureBroken( defaultBridge->getTextureBroken() );
  309. bridge->friend_setTransitionEffectsHeight( defaultBridge->getTransitionEffectsHeight() );
  310. bridge->friend_setNumFXPerType( defaultBridge->getNumFXPerType() );
  311. for( Int state = BODY_PRISTINE; state < BODYDAMAGETYPE_COUNT; state++ )
  312. {
  313. bridge->friend_setDamageToSoundString( (BodyDamageType)state, bridge->getDamageToSoundString( (BodyDamageType)state ) );
  314. bridge->friend_setRepairedToSoundString( (BodyDamageType)state, bridge->getRepairedToSoundString( (BodyDamageType)state ) );
  315. for( Int i = 0; i < MAX_BRIDGE_BODY_FX; i++ )
  316. {
  317. bridge->friend_setDamageToOCLString( (BodyDamageType)state, i, bridge->getDamageToOCLString( (BodyDamageType)state, i ) );
  318. bridge->friend_setDamageToFXString( (BodyDamageType)state, i, bridge->getDamageToOCLString( (BodyDamageType)state, i ) );
  319. bridge->friend_setRepairedToOCLString( (BodyDamageType)state, i, bridge->getDamageToOCLString( (BodyDamageType)state, i ) );
  320. bridge->friend_setRepairedToFXString( (BodyDamageType)state, i, bridge->getDamageToOCLString( (BodyDamageType)state, i ) );
  321. } // end for i
  322. } // end for
  323. } // end if
  324. // link to list
  325. bridge->friend_setNext( m_bridgeList );
  326. m_bridgeList = bridge;
  327. // return the new bridge
  328. return bridge;
  329. } // end newBridge
  330. //-------------------------------------------------------------------------------------------------
  331. /** Return next road in list */
  332. //-------------------------------------------------------------------------------------------------
  333. TerrainRoadType *TerrainRoadCollection::nextRoad( TerrainRoadType *road )
  334. {
  335. DEBUG_ASSERTCRASH( road->isBridge() == FALSE, ("nextRoad: road not a road\n") );
  336. return road->friend_getNext();
  337. } // end nextRoad
  338. //-------------------------------------------------------------------------------------------------
  339. /** Return next bridge in list */
  340. //-------------------------------------------------------------------------------------------------
  341. TerrainRoadType *TerrainRoadCollection::nextBridge( TerrainRoadType *bridge )
  342. {
  343. DEBUG_ASSERTCRASH( bridge->isBridge() == TRUE, ("nextBridge, bridge is not a bridge\n") );
  344. return bridge->friend_getNext();
  345. } // end nextBridge