cover.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /*
  2. ** Command & Conquer Renegade(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. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Combat/cover.cpp $*
  25. * *
  26. * $Author:: Byon_g $*
  27. * *
  28. * $Modtime:: 4/17/01 11:44a $*
  29. * *
  30. * $Revision:: 7 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "cover.h"
  36. #include "debug.h"
  37. #include "chunkio.h"
  38. #include "saveload.h"
  39. #include "crandom.h"
  40. /*
  41. **
  42. */
  43. DynamicVectorClass<CoverEntryClass *> CoverManager::CoverPositions;
  44. /*
  45. **
  46. */
  47. void CoverManager::Init( void )
  48. {
  49. }
  50. void CoverManager::Shutdown( void )
  51. {
  52. Remove_All();
  53. }
  54. /*
  55. **
  56. */
  57. enum {
  58. CHUNKID_COVER_ENTRY = 524001203,
  59. };
  60. bool CoverManager::Save( ChunkSaveClass & csave )
  61. {
  62. for ( int index = 0; index < CoverPositions.Count(); index++ ) {
  63. csave.Begin_Chunk( CHUNKID_COVER_ENTRY );
  64. CoverPositions[index]->Save( csave );
  65. csave.End_Chunk();
  66. }
  67. return true;
  68. }
  69. bool CoverManager::Load( ChunkLoadClass & cload )
  70. {
  71. WWASSERT( CoverPositions.Count() == 0 );
  72. while (cload.Open_Chunk()) {
  73. switch(cload.Cur_Chunk_ID()) {
  74. case CHUNKID_COVER_ENTRY:
  75. {
  76. CoverEntryClass * cover = NEW_REF( CoverEntryClass, () );
  77. cover->Load( cload );
  78. Add_Entry( cover );
  79. cover->Release_Ref();
  80. break;
  81. }
  82. default:
  83. Debug_Say(( "Unrecognized CombatSaveLoad chunkID\n" ));
  84. break;
  85. }
  86. cload.Close_Chunk();
  87. }
  88. return true;
  89. }
  90. /*
  91. **
  92. */
  93. void CoverManager::Add_Entry( CoverEntryClass * entry )
  94. {
  95. if ( entry != NULL ) {
  96. entry->Add_Ref();
  97. CoverPositions.Add( entry );
  98. }
  99. }
  100. void CoverManager::Remove_Entry( CoverEntryClass * entry )
  101. {
  102. if ( entry != NULL ) {
  103. CoverPositions.Delete( entry );
  104. entry->Release_Ref();
  105. }
  106. }
  107. void CoverManager::Remove_All( void )
  108. {
  109. while ( CoverPositions.Count() ) {
  110. CoverPositions[0]->Release_Ref();
  111. CoverPositions.Delete( 0 );
  112. }
  113. }
  114. /*
  115. **
  116. */
  117. CoverEntryClass * CoverManager::Request_Cover( const Vector3 & cur_pos, const Vector3 & danger, float max_dist )
  118. {
  119. // Find a cover spot, not in use, within max_dist, that blocks from danger
  120. int best_index = -1;
  121. int best_dist = max_dist;
  122. for ( int index = 0; index < CoverPositions.Count(); index++ ) {
  123. CoverEntryClass * cover = CoverPositions[ index ];
  124. if ( cover->Get_In_Use() ) {
  125. continue; // Already in use
  126. }
  127. Vector3 range_vector = cur_pos - cover->Get_Transform().Get_Translation();
  128. float dist = range_vector.Length();
  129. if ( dist > max_dist ) {
  130. continue; // Too far away
  131. }
  132. if ( !Is_Cover_Safe( cover, danger ) ) {
  133. continue; // Does not provide cover
  134. }
  135. if ( best_dist < dist ) {
  136. continue; // Already ahave a better one
  137. }
  138. if ( best_index != -1 ) {
  139. if ( FreeRandom.Get_Int() & 1 ) {
  140. continue;
  141. }
  142. }
  143. best_index = index;
  144. best_dist = dist;
  145. }
  146. if ( best_index != -1 ) {
  147. // Debug_Say(( "Chose cover # %d\n", best_index ));
  148. CoverPositions[ best_index ]->Set_In_Use( true );
  149. return CoverPositions[best_index];
  150. }
  151. return NULL;
  152. }
  153. void CoverManager::Release_Cover( CoverEntryClass * entry )
  154. {
  155. WWASSERT( entry->Get_In_Use() );
  156. entry->Set_In_Use( false );
  157. }
  158. bool CoverManager::Is_Cover_Safe( CoverEntryClass * cover, const Vector3 & danger )
  159. {
  160. WWASSERT( cover );
  161. Vector3 danger_local;
  162. Matrix3D::Inverse_Transform_Vector( cover->Get_Transform(), danger, &danger_local );
  163. if ( danger_local.X < WWMath::Fabs(danger_local.Y) ) {
  164. return false;
  165. }
  166. return true;
  167. }
  168. /*
  169. **
  170. */
  171. enum {
  172. CHUNKID_VARIABLES = 524001323,
  173. MICROCHUNKID_TRANSFORM = 1,
  174. MICROCHUNKID_CROUCH,
  175. MICROCHUNKID_IN_USE,
  176. MICROCHUNKID_ATTACK_POSITION,
  177. MICROCHUNKID_REMAP_PTR,
  178. };
  179. bool CoverEntryClass::Save( ChunkSaveClass & csave )
  180. {
  181. CoverEntryClass * me = this;
  182. csave.Begin_Chunk( CHUNKID_VARIABLES );
  183. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TRANSFORM, Transform );
  184. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CROUCH, Crouch );
  185. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_IN_USE, InUse );
  186. for ( int i = 0; i < AttackPositionList.Count(); i++ ) {
  187. Vector3 pos = AttackPositionList[i];
  188. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_ATTACK_POSITION, pos );
  189. }
  190. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_REMAP_PTR, me );
  191. csave.End_Chunk();
  192. return true;
  193. }
  194. bool CoverEntryClass::Load( ChunkLoadClass & cload )
  195. {
  196. WWASSERT( AttackPositionList.Count() == 0 );
  197. CoverEntryClass * old_me = NULL;
  198. while (cload.Open_Chunk()) {
  199. switch(cload.Cur_Chunk_ID()) {
  200. case CHUNKID_VARIABLES:
  201. while (cload.Open_Micro_Chunk()) {
  202. switch(cload.Cur_Micro_Chunk_ID()) {
  203. READ_MICRO_CHUNK( cload, MICROCHUNKID_TRANSFORM, Transform );
  204. READ_MICRO_CHUNK( cload, MICROCHUNKID_CROUCH, Crouch );
  205. READ_MICRO_CHUNK( cload, MICROCHUNKID_IN_USE, InUse );
  206. case MICROCHUNKID_ATTACK_POSITION:
  207. {
  208. Vector3 pos;
  209. cload.Read(&pos,sizeof(pos));
  210. AttackPositionList.Add( pos );
  211. break;
  212. }
  213. READ_MICRO_CHUNK( cload, MICROCHUNKID_REMAP_PTR, old_me );
  214. default:
  215. Debug_Say(( "Unrecognized CoverEntry Variable chunkID %d\n", cload.Cur_Micro_Chunk_ID() ));
  216. break;
  217. }
  218. cload.Close_Micro_Chunk();
  219. }
  220. break;
  221. default:
  222. Debug_Say(( "Unrecognized CoverEntry chunkID\n" ));
  223. break;
  224. }
  225. cload.Close_Chunk();
  226. }
  227. // publish my remap pair
  228. WWASSERT(old_me != NULL);
  229. if (old_me != NULL) {
  230. SaveLoadSystemClass::Register_Pointer( old_me, this );
  231. }
  232. return true;
  233. }
  234. Vector3 CoverEntryClass::Get_Attack_Position( Vector3 & enemy_pos )
  235. {
  236. // Find a cover position that will allow attack of enemy_pos (not yet)
  237. // default to cover spot
  238. Vector3 pos = Transform.Get_Translation();
  239. if ( AttackPositionList.Count() ) {
  240. int index = FreeRandom.Get_Int( AttackPositionList.Count() );
  241. pos = AttackPositionList[index];
  242. }
  243. return pos;
  244. }