FireOCLAfterWeaponCooldownUpdate.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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: FireOCLAfterWeaponCooldownUpdate.cpp //////////////////////////////////////////////////////////////////////
  24. // Author: Kris Morness, September 2002
  25. // Desc: This system tracks the objects status with regards to firing, and whenever the object stops
  26. // firing, and all the conditions are met, then it'll create the specified OCL.
  27. ///////////////////////////////////////////////////////////////////////////////////////////////////
  28. // USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
  29. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  30. #define DEFINE_WEAPONSLOTTYPE_NAMES //TheWeaponSlotTypeNamesLookupList
  31. #include "Common/Player.h"
  32. #include "Common/ThingTemplate.h"
  33. #include "Common/Xfer.h"
  34. #include "GameClient/Drawable.h"
  35. #include "GameClient/InGameUI.h"
  36. #include "GameLogic/GameLogic.h"
  37. #include "GameLogic/Object.h"
  38. #include "GameLogic/ObjectCreationList.h"
  39. #include "GameLogic/Weapon.h"
  40. #include "GameLogic/Weaponset.h"
  41. #include "GameLogic/Module/FireOCLAfterWeaponCooldownUpdate.h"
  42. #include "GameLogic/Module/LifetimeUpdate.h"
  43. #include "GameLogic/Module/AIUpdate.h"
  44. #include "GameLogic/Module/BodyModule.h"
  45. //-------------------------------------------------------------------------------------------------
  46. FireOCLAfterWeaponCooldownUpdateModuleData::FireOCLAfterWeaponCooldownUpdateModuleData()
  47. {
  48. m_weaponSlot = PRIMARY_WEAPON;
  49. m_minShotsRequired = 1;
  50. m_oclLifetimePerSecond = 1000;
  51. m_oclMaxFrames = 1000;
  52. m_ocl = NULL;
  53. }
  54. //-------------------------------------------------------------------------------------------------
  55. void FireOCLAfterWeaponCooldownUpdateModuleData::buildFieldParse(MultiIniFieldParse& p)
  56. {
  57. UpdateModuleData::buildFieldParse(p);
  58. static const FieldParse dataFieldParse[] =
  59. {
  60. { "WeaponSlot", INI::parseLookupList, TheWeaponSlotTypeNamesLookupList, offsetof( FireOCLAfterWeaponCooldownUpdateModuleData, m_weaponSlot ) },
  61. { "OCL", INI::parseObjectCreationList, NULL, offsetof( FireOCLAfterWeaponCooldownUpdateModuleData, m_ocl ) },
  62. { "MinShotsToCreateOCL", INI::parseUnsignedInt, NULL, offsetof( FireOCLAfterWeaponCooldownUpdateModuleData, m_minShotsRequired ) },
  63. { "OCLLifetimePerSecond", INI::parseUnsignedInt, NULL, offsetof( FireOCLAfterWeaponCooldownUpdateModuleData, m_oclLifetimePerSecond ) },
  64. { "OCLLifetimeMaxCap", INI::parseDurationUnsignedInt, NULL, offsetof( FireOCLAfterWeaponCooldownUpdateModuleData, m_oclMaxFrames ) },
  65. { 0, 0, 0, 0 }
  66. };
  67. p.add(dataFieldParse);
  68. p.add(UpgradeMuxData::getFieldParse(), offsetof( FireOCLAfterWeaponCooldownUpdateModuleData, m_upgradeMuxData ));
  69. }
  70. //-------------------------------------------------------------------------------------------------
  71. FireOCLAfterWeaponCooldownUpdate::FireOCLAfterWeaponCooldownUpdate( Thing *thing, const ModuleData *moduleData ) : UpdateModule( thing, moduleData )
  72. {
  73. m_valid = false;
  74. resetStats();
  75. }
  76. //-------------------------------------------------------------------------------------------------
  77. //-------------------------------------------------------------------------------------------------
  78. FireOCLAfterWeaponCooldownUpdate::~FireOCLAfterWeaponCooldownUpdate( void )
  79. {
  80. }
  81. //-------------------------------------------------------------------------------------------------
  82. UpdateSleepTime FireOCLAfterWeaponCooldownUpdate::update( void )
  83. {
  84. const FireOCLAfterWeaponCooldownUpdateModuleData* data = getFireOCLAfterWeaponCooldownUpdateModuleData();
  85. Int64 activation, conflicting;
  86. getUpgradeActivationMasks( activation, conflicting );
  87. Bool validThisFrame = true;
  88. Bool validToFireOCL = true;
  89. Object *obj = getObject();
  90. //Get current weapon
  91. Weapon *weapon = obj->getCurrentWeapon();
  92. if( weapon )
  93. {
  94. if( weapon->getWeaponSlot() != data->m_weaponSlot )
  95. {
  96. //Not the right weapon slot -- it's possible we switched weapons in which case it's
  97. //possible to fire the OCL.
  98. validThisFrame = false;
  99. }
  100. }
  101. else
  102. {
  103. //No weapon selected -- possible to switch off weapons, possible to have just
  104. //finished firing our weapon.
  105. validThisFrame = false;
  106. }
  107. Int64 objectMask = obj->getObjectCompletedUpgradeMask();
  108. Int64 playerMask = obj->getControllingPlayer()->getCompletedUpgradeMask();
  109. Int64 maskToCheck = playerMask | objectMask;
  110. if( validThisFrame && !testUpgradeConditions( maskToCheck ) )
  111. {
  112. //Can't use this period if this object doesn't have any of the upgrades
  113. validThisFrame = false;
  114. validToFireOCL = false;
  115. }
  116. UnsignedInt now = TheGameLogic->getFrame();
  117. if( validThisFrame )
  118. {
  119. if( weapon->getLastShotFrame() == now - 1 )
  120. {
  121. m_consecutiveShots++;
  122. if( m_consecutiveShots == 1 )
  123. {
  124. //Our first shot -- so record the frame number so we can easily calculate the
  125. //time we've been firing!
  126. m_startFrame = now;
  127. }
  128. }
  129. else if( weapon->getPossibleNextShotFrame() < now )
  130. {
  131. //Means we could have shot but didn't!
  132. if( data->m_minShotsRequired <= m_consecutiveShots )
  133. {
  134. //We have fired enough shots to create the OCL.
  135. fireOCL();
  136. }
  137. }
  138. }
  139. else if( validToFireOCL )
  140. {
  141. //We've stopped being valid -- which means we may have stopped firing our weapon.
  142. Weapon *weapon = obj->getWeaponInWeaponSlot( data->m_weaponSlot );
  143. if( weapon && data->m_minShotsRequired <= m_consecutiveShots )
  144. {
  145. //We switched weapons! Fire OCL!
  146. fireOCL();
  147. }
  148. }
  149. if( validThisFrame != m_valid )
  150. {
  151. //There has been a validity change, so reset all values!
  152. m_valid = validThisFrame;
  153. resetStats();
  154. }
  155. return UPDATE_SLEEP_NONE;
  156. }
  157. //-------------------------------------------------------------------------------------------------
  158. void FireOCLAfterWeaponCooldownUpdate::resetStats()
  159. {
  160. m_consecutiveShots = 0;
  161. m_startFrame = 0;
  162. }
  163. //-------------------------------------------------------------------------------------------------
  164. void FireOCLAfterWeaponCooldownUpdate::fireOCL()
  165. {
  166. const FireOCLAfterWeaponCooldownUpdateModuleData* data = getFireOCLAfterWeaponCooldownUpdateModuleData();
  167. Object *obj = getObject();
  168. //Calculate the lifetime of the OCL.
  169. UnsignedInt now = TheGameLogic->getFrame();
  170. Real seconds = (now - m_startFrame) * SECONDS_PER_LOGICFRAME_REAL;
  171. seconds *= data->m_oclLifetimePerSecond * 0.001f;
  172. UnsignedInt oclFrames = (UnsignedInt)(seconds * LOGICFRAMES_PER_SECOND);
  173. oclFrames = MIN( oclFrames, data->m_oclMaxFrames );
  174. ObjectCreationList::create( data->m_ocl, obj, obj, oclFrames );
  175. resetStats();
  176. }
  177. // ------------------------------------------------------------------------------------------------
  178. /** CRC */
  179. // ------------------------------------------------------------------------------------------------
  180. void FireOCLAfterWeaponCooldownUpdate::crc( Xfer *xfer )
  181. {
  182. // extend base class
  183. UpdateModule::crc( xfer );
  184. // extend base class
  185. UpgradeMux::upgradeMuxCRC( xfer );
  186. } // end crc
  187. // ------------------------------------------------------------------------------------------------
  188. /** Xfer method
  189. * Version Info:
  190. * 1: Initial version */
  191. // ------------------------------------------------------------------------------------------------
  192. void FireOCLAfterWeaponCooldownUpdate::xfer( Xfer *xfer )
  193. {
  194. // version
  195. XferVersion currentVersion = 1;
  196. XferVersion version = currentVersion;
  197. xfer->xferVersion( &version, currentVersion );
  198. // extend base class
  199. UpdateModule::xfer( xfer );
  200. // extend base class
  201. UpgradeMux::upgradeMuxXfer( xfer );
  202. // valid
  203. xfer->xferBool( &m_valid );
  204. // consecutive shots
  205. xfer->xferUnsignedInt( &m_consecutiveShots );
  206. // start frame
  207. xfer->xferUnsignedInt( &m_startFrame );
  208. } // end xfer
  209. // ------------------------------------------------------------------------------------------------
  210. /** Load post process */
  211. // ------------------------------------------------------------------------------------------------
  212. void FireOCLAfterWeaponCooldownUpdate::loadPostProcess( void )
  213. {
  214. // extend base class
  215. UpdateModule::loadPostProcess();
  216. // extend base class
  217. UpgradeMux::upgradeMuxLoadPostProcess();
  218. } // end loadPostProcess