weaponIGC.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*
  2. ** Copyright (C) 1996, 1997 Microsoft Corporation. All Rights Reserved.
  3. **
  4. ** File: weaponIGC.cpp
  5. **
  6. ** Author:
  7. **
  8. ** Description:
  9. ** Implementation of the CweaponIGC class. This file was initially created by
  10. ** the ATL wizard for the weapon object.
  11. **
  12. ** History:
  13. */
  14. // weaponIGC.cpp : Implementation of CweaponIGC
  15. #include "pch.h"
  16. #include "weaponIGC.h"
  17. /////////////////////////////////////////////////////////////////////////////
  18. // CweaponIGC
  19. CweaponIGC::CweaponIGC(void)
  20. :
  21. m_partType(NULL),
  22. m_projectileType(NULL),
  23. m_ship(NULL),
  24. m_pshipGunner(NULL),
  25. m_fActive(false),
  26. m_fFiringShot(false),
  27. m_fFiringBurst(false),
  28. m_mountID(c_mountNA)
  29. {
  30. }
  31. HRESULT CweaponIGC::Initialize(ImissionIGC* pMission, Time now, const void* data, int dataSize)
  32. {
  33. assert (pMission);
  34. m_pMission = pMission;
  35. ZRetailAssert (data && (dataSize == sizeof(DataPartIGC)));
  36. {
  37. m_partType = ((DataPartIGC*)data)->partType;
  38. assert (m_partType);
  39. m_partType->AddRef();
  40. m_typeData = (const DataWeaponTypeIGC*)m_partType->GetData();
  41. m_projectileType = m_pMission->GetProjectileType(m_typeData->projectileTypeID);
  42. ZRetailAssert (m_projectileType);
  43. m_projectileType->AddRef();
  44. }
  45. return S_OK;
  46. }
  47. void CweaponIGC::Terminate(void)
  48. {
  49. AddRef();
  50. if (m_pshipGunner)
  51. {
  52. SetGunner(NULL);
  53. }
  54. SetShip(NULL, NA);
  55. if (m_partType)
  56. {
  57. m_partType->Release();
  58. m_partType = NULL;
  59. }
  60. if (m_projectileType)
  61. {
  62. m_projectileType->Release();
  63. m_projectileType = NULL;
  64. }
  65. Release();
  66. }
  67. void CweaponIGC::SetShip(IshipIGC* newVal, Mount mount)
  68. {
  69. //There may be only a single reference to this part ... so make sure the part
  70. //does not get deleted midway through things
  71. AddRef();
  72. if (m_ship)
  73. {
  74. m_ship->DeletePart(this);
  75. m_ship->Release();
  76. }
  77. assert (m_mountID == c_mountNA);
  78. m_ship = newVal;
  79. if (m_ship)
  80. {
  81. m_ship->AddRef();
  82. m_ship->AddPart(this);
  83. SetMountID(mount);
  84. }
  85. Release();
  86. }
  87. void CweaponIGC::SetMountID(Mount newVal)
  88. {
  89. assert (m_ship);
  90. if (newVal != m_mountID)
  91. {
  92. Deactivate();
  93. if (m_pshipGunner)
  94. SetGunner(NULL);
  95. m_ship->MountPart(this, newVal, &m_mountID);
  96. if (newVal >= 0)
  97. {
  98. //Get the corresponding hardpoint: we know one exists because the
  99. //ship allowed the part to be mounted.
  100. const IhullTypeIGC* pht = m_ship->GetBaseHullType();
  101. assert (pht);
  102. m_pposition = &(pht->GetWeaponPosition(newVal));
  103. m_porientation = &(pht->GetWeaponOrientation(newVal));
  104. //Is there a turret gunner in this position (who does not have a gun)
  105. {
  106. for (ShipLinkIGC* psl = m_ship->GetChildShips()->first(); (psl != NULL); psl = psl->next())
  107. {
  108. IshipIGC* pship = psl->data();
  109. if (pship->GetTurretID() == newVal)
  110. {
  111. SetGunner(pship);
  112. break;
  113. }
  114. }
  115. }
  116. }
  117. }
  118. }
  119. void CweaponIGC::FireWeapon(Time now)
  120. {
  121. assert (m_mountID >= 0);
  122. assert (m_ship);
  123. bool fFiredShot = false;
  124. if (m_fActive && (m_nextFire < now))
  125. {
  126. Time lastUpdate = m_ship->GetLastUpdate();
  127. //Never fire retroactively.
  128. if (m_nextFire < lastUpdate)
  129. m_nextFire = lastUpdate;
  130. bool fSelected = fIsWeaponSelected();
  131. float energy = m_ship->GetEnergy(); //the energy the ship would have at "now"
  132. if (energy >= m_typeData->energyPerShot)
  133. {
  134. //We'd be able to fire before now and would have enough energy at now to fire, so ...
  135. float rechargeRate = m_ship->GetHullType()->GetRechargeRate();
  136. float energyDeficit = (m_nextFire - now) * //this is how much we are in the hole because we
  137. rechargeRate; //are shooting sooner than "now" (must be < 0)
  138. short ammo = m_ship->GetAmmo();
  139. if ((ammo > 0) || (m_typeData->cAmmoPerShot == 0))
  140. {
  141. // we are firing at least once this frame
  142. fFiredShot = true;
  143. m_pMission->GetIgcSite()->PlayFFEffect(effectFire, m_pshipGunner ? m_pshipGunner : m_ship);
  144. //Get the stuff that won't change between shots
  145. IclusterIGC* cluster = m_ship->GetCluster();
  146. assert (cluster);
  147. const Orientation& shipOrientation = m_ship->GetOrientation();
  148. //Orientation orientationBfr;
  149. const Orientation* pMyOrientation;
  150. if (m_pshipGunner)
  151. {
  152. /*
  153. orientationBfr = m_pshipGunner->GetOrientation() * (*m_porientation * shipOrientation);
  154. pMyOrientation = &orientationBfr;
  155. */
  156. pMyOrientation = &(m_pshipGunner->GetOrientation());
  157. }
  158. else
  159. {
  160. pMyOrientation = &shipOrientation;
  161. }
  162. //This is how much energy deficit recovers between shots
  163. float dtimeBurst = GetDtBurst();
  164. float recharge = rechargeRate * dtimeBurst;
  165. const Vector& myVelocity = m_ship->GetVelocity();
  166. Vector myPosition = m_ship->GetPosition() + *m_pposition * shipOrientation; //*pMyOrientation;
  167. /*
  168. m_ship->GetThingSite()->AddMuzzleFlare(
  169. m_emissionPt,
  170. min(dtimeBurst * 0.5f, 0.05f)
  171. );
  172. */
  173. DataProjectileIGC dataProjectile;
  174. dataProjectile.projectileTypeID = m_projectileType->GetObjectID();
  175. float lifespan = GetLifespan();
  176. float speed = m_projectileType->GetSpeed();
  177. if (m_typeData->cAmmoPerShot)
  178. speed *= m_ship->GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaSpeedAmmo);
  179. bool absoluteF = m_projectileType->GetAbsoluteF();
  180. const Vector* ppositionTarget;
  181. const Vector* pvelocityTarget;
  182. ImodelIGC* ptarget = NULL;
  183. if (m_projectileType->GetBlastPower() != 0.0f)
  184. {
  185. if (m_pshipGunner)
  186. ptarget = m_pshipGunner->GetCommandTarget(c_cmdCurrent);
  187. else
  188. ptarget = m_ship->GetCommandTarget(c_cmdCurrent);
  189. if (ptarget)
  190. {
  191. if ((ptarget->GetCluster() == cluster) && m_ship->CanSee(ptarget))
  192. {
  193. ppositionTarget = &(ptarget->GetPosition());
  194. pvelocityTarget = &(ptarget->GetVelocity());
  195. }
  196. else
  197. ptarget = NULL;
  198. }
  199. }
  200. int nShots = fSelected ? 10 : 0; //Only allow a single shot if the weapon is no longer selected
  201. do
  202. {
  203. if (energy + energyDeficit < m_typeData->energyPerShot)
  204. {
  205. //We don't have enough energy to fire at our prefered time ... so wait until we do.
  206. m_nextFire += (m_typeData->energyPerShot - (energy + energyDeficit)) / rechargeRate;
  207. }
  208. //Permute the "forward" direction slightly by a random amount
  209. dataProjectile.forward = pMyOrientation->GetForward();
  210. if (m_typeData->dispersion != 0.0f)
  211. {
  212. float r = random(0.0f, m_typeData->dispersion);
  213. float a = random(0.0f, 2.0f * pi);
  214. dataProjectile.forward += (r * cos(a)) * pMyOrientation->GetRight();
  215. dataProjectile.forward += (r * sin(a)) * pMyOrientation->GetUp();
  216. dataProjectile.forward.SetNormalize();
  217. }
  218. dataProjectile.velocity = speed * dataProjectile.forward;
  219. if (!absoluteF)
  220. dataProjectile.velocity += myVelocity;
  221. Vector position = myPosition + myVelocity * (m_nextFire - lastUpdate);
  222. dataProjectile.lifespan = lifespan;
  223. if (ptarget)
  224. {
  225. Vector dV = *pvelocityTarget - dataProjectile.velocity;
  226. float dV2 = dV.LengthSquared();
  227. if (dV2 != 0.0f)
  228. {
  229. Vector dP = position - *ppositionTarget; //reverse so time has right sense
  230. dataProjectile.lifespan = (dV * dP) / dV2;
  231. if (dataProjectile.lifespan > lifespan)
  232. dataProjectile.lifespan = lifespan;
  233. else if (dataProjectile.lifespan < 0.1f)
  234. dataProjectile.lifespan = 0.1f; //Don't let it explode in our face
  235. }
  236. }
  237. IprojectileIGC* p = (IprojectileIGC*)(m_pMission->CreateObject(m_nextFire, OT_projectile,
  238. &dataProjectile, sizeof(dataProjectile)));
  239. if (p)
  240. {
  241. if (m_pshipGunner)
  242. p->SetGunner(m_pshipGunner);
  243. else
  244. p->SetLauncher(m_ship);
  245. p->SetPosition(position);
  246. p->SetCluster(cluster);
  247. p->Release();
  248. }
  249. energyDeficit += rechargeRate * dtimeBurst;
  250. energy -= m_typeData->energyPerShot;
  251. ammo -= m_typeData->cAmmoPerShot;
  252. m_nextFire += dtimeBurst;
  253. }
  254. while ((nShots-- > 0) &&
  255. (m_nextFire < now) &&
  256. (energy + energyDeficit >= m_typeData->energyPerShot) &&
  257. (ammo > 0));
  258. m_ship->SetAmmo(ammo > 0 ? ammo : 0);
  259. if ((ammo == 0) && (m_typeData->cAmmoPerShot != 0))
  260. fSelected = false;
  261. m_ship->SetEnergy(energy);
  262. }
  263. }
  264. if (!fSelected)
  265. Deactivate();
  266. }
  267. // if we fired a shot, keep track of it (note - stored localy because the
  268. // call to deactivate (above) clears the member variable).
  269. m_fFiringShot = fFiredShot;
  270. // if we are still firing and have the energy and ammo for the next shot,
  271. // assume we are firing a burst.
  272. if ((m_ship->GetEnergy() >= m_typeData->energyPerShot)
  273. && (m_ship->GetAmmo() >= m_typeData->cAmmoPerShot)
  274. && (m_fFiringBurst || (m_fActive && m_fFiringShot)) // a burst starts with a shot
  275. )
  276. {
  277. m_fFiringBurst = true;
  278. }
  279. else
  280. {
  281. m_fFiringBurst = false;
  282. }
  283. }