projectileIGC.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. ** Copyright (C) 1996, 1997 Microsoft Corporation. All Rights Reserved.
  3. **
  4. ** File: projectileIGC.cpp
  5. **
  6. ** Author:
  7. **
  8. ** Description:
  9. ** Implementation of the CprojectileIGC class. This file was initially created by
  10. ** the ATL wizard for the core object.
  11. **
  12. ** This particular implementation of projectiles supports non-tracking missiles with
  13. ** a fixed run (time at which they expire).
  14. **
  15. ** History:
  16. */
  17. // projectileIGC.cpp : Implementation of CprojectileIGC
  18. #include "pch.h"
  19. #include "projectileIGC.h"
  20. /////////////////////////////////////////////////////////////////////////////
  21. // CprojectileIGC
  22. CprojectileIGC::CprojectileIGC(void)
  23. :
  24. m_launcher(NULL),
  25. m_projectileType(NULL),
  26. m_pExplosionData(NULL)
  27. {
  28. }
  29. CprojectileIGC::~CprojectileIGC(void)
  30. {
  31. }
  32. HRESULT CprojectileIGC::Initialize(ImissionIGC* pMission, Time now, const void* data, int dataSize)
  33. {
  34. TmodelIGC<IprojectileIGC>::Initialize(pMission, now, data, dataSize);
  35. ZRetailAssert (data && (dataSize == sizeof(DataProjectileIGC)));
  36. {
  37. DataProjectileIGC* dataProjectile = (DataProjectileIGC*)data;
  38. m_projectileType = pMission->GetProjectileType(dataProjectile->projectileTypeID);
  39. if (m_projectileType)
  40. {
  41. m_projectileType->AddRef();
  42. DataProjectileTypeIGC* dataProjectileType = (DataProjectileTypeIGC*)m_projectileType->GetData();
  43. assert (dataProjectileType);
  44. //Load the model for the projectile
  45. if (iswalpha(dataProjectileType->modelName[0]))
  46. {
  47. HRESULT hr = Load(0, dataProjectileType->modelName, dataProjectileType->textureName, NULL, c_mtCastRay | c_mtNotPickable);
  48. assert (SUCCEEDED(hr));
  49. SetRadius(dataProjectileType->radius);
  50. }
  51. else
  52. {
  53. HRESULT hr = LoadDecal(dataProjectileType->textureName, NULL,
  54. Color((float)dataProjectileType->color.r,
  55. (float)dataProjectileType->color.g,
  56. (float)dataProjectileType->color.b,
  57. (float)dataProjectileType->color.a),
  58. dataProjectileType->bDirectional,
  59. dataProjectileType->width,
  60. c_mtCastRay | c_mtNotPickable);
  61. assert (SUCCEEDED(hr));
  62. GetHitTest()->SetRadius(0.0f);
  63. GetThingSite()->SetRadius(dataProjectileType->radius);
  64. }
  65. //position set after being initialized
  66. SetVelocity(dataProjectile->velocity);
  67. {
  68. Orientation o(dataProjectile->forward);
  69. SetOrientation(o);
  70. }
  71. {
  72. Rotation r(dataProjectile->forward, dataProjectileType->rotation);
  73. SetRotation(r);
  74. }
  75. {
  76. HitTest* ht = GetHitTest();
  77. //lifespan == 0 => immortal projectile that can hit until it gets terminated on the next update; this is bad
  78. assert (dataProjectile->lifespan > 0.0f);
  79. ht->SetTimeStart(now);
  80. ht->SetTimeStop(m_timeExpire = now + dataProjectile->lifespan); //intentional assignment
  81. assert (m_timeExpire != now);
  82. }
  83. SetMass(0.0f);
  84. }
  85. }
  86. return S_OK;
  87. }
  88. void CprojectileIGC::Terminate(void)
  89. {
  90. AddRef();
  91. TmodelIGC<IprojectileIGC>::Terminate();
  92. if (m_launcher)
  93. {
  94. m_launcher->Release();
  95. m_launcher = NULL;
  96. }
  97. if (m_projectileType)
  98. {
  99. m_projectileType->Release();
  100. m_projectileType = NULL;
  101. }
  102. Release();
  103. }
  104. void CprojectileIGC::Update(Time now)
  105. {
  106. if (GetMyLastUpdate() >= m_timeExpire)
  107. Terminate();
  108. else
  109. {
  110. if (now >= m_timeExpire)
  111. {
  112. float p = m_projectileType->GetBlastPower();
  113. if (p != 0.0f)
  114. {
  115. m_pExplosionData = GetCluster()->CreateExplosion(m_projectileType->GetDamageType(),
  116. p * GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaDamageGuns),
  117. m_projectileType->GetBlastRadius(),
  118. c_etProjectile,
  119. m_timeExpire,
  120. GetPosition() +
  121. GetVelocity() * (m_timeExpire - GetMyLastUpdate()),
  122. m_launcher);
  123. }
  124. }
  125. TmodelIGC<IprojectileIGC>::Update(now);
  126. }
  127. }
  128. int CprojectileIGC::Export(void* data)
  129. {
  130. if (data)
  131. {
  132. DataProjectileIGC* dataProjectile = (DataProjectileIGC*)data;
  133. dataProjectile->projectileTypeID = m_projectileType->GetObjectID();
  134. dataProjectile->velocity = GetVelocity();
  135. dataProjectile->forward = GetOrientation().GetForward();
  136. }
  137. return sizeof(DataProjectileIGC);
  138. }
  139. void CprojectileIGC::HandleCollision(Time timeCollision,
  140. float tCollision,
  141. const CollisionEntry& entry,
  142. ImodelIGC* pModel)
  143. {
  144. if (pModel->GetObjectType() == OT_mine)
  145. {
  146. //Ignore collisions with minefields
  147. return;
  148. }
  149. //A projectile hit something other than a minefield
  150. bool fExplosion;
  151. Vector position1 = GetPosition() + GetVelocity() * tCollision;
  152. Vector position2 = pModel->GetPosition() + pModel->GetVelocity() * tCollision;
  153. DamageTypeID type = m_projectileType->GetDamageType();
  154. if (pModel->GetAttributes() & c_mtDamagable)
  155. {
  156. //The target can take damage
  157. IdamageIGC* pDamage = (IdamageIGC*)pModel;
  158. pModel->AddRef();
  159. DamageResult dr = pDamage->ReceiveDamage(type,
  160. m_projectileType->GetPower() * GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaDamageGuns),
  161. timeCollision,
  162. position2,
  163. position1,
  164. m_launcher);
  165. //No explosion because no hull damage, not visible or we killed it.
  166. fExplosion = (dr <= c_drHullDamage) && pModel->GetVisibleF() && (pModel->GetCluster() != NULL);
  167. pModel->Release();
  168. }
  169. else
  170. fExplosion = false;
  171. if (m_pExplosionData)
  172. {
  173. //This projectile would have exploded anyway -- change the explosion position & time.
  174. m_pExplosionData->time = timeCollision;
  175. m_pExplosionData->position = position1;
  176. }
  177. else
  178. {
  179. float p = m_projectileType->GetBlastPower();
  180. if (p != 0.0f)
  181. {
  182. //Area effect weapon: create an explosion (no matter what)
  183. GetCluster()->CreateExplosion(type,
  184. p,
  185. m_projectileType->GetBlastRadius(),
  186. c_etProjectile,
  187. timeCollision,
  188. position1,
  189. m_launcher);
  190. }
  191. else if (fExplosion && ((type & c_dmgidNoDebris) == 0))
  192. {
  193. Vector pos = position1 - position2;
  194. pModel->GetThingSite()->AddHullHit(pos,
  195. pos.Normalize());
  196. }
  197. }
  198. //In any case, kill the projectile
  199. Terminate();
  200. }