probeigc.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. /*
  2. ** Copyright (C) 1996, 1997 Microsoft Corporation. All Rights Reserved.
  3. **
  4. ** File: probeIGC.cpp
  5. **
  6. ** Author:
  7. **
  8. ** Description:
  9. ** Implementation of the CprobeIGC class. This file was initially created by
  10. ** the ATL wizard for the core object.
  11. **
  12. ** History:
  13. */
  14. // probeIGC.cpp : Implementation of CprobeIGC
  15. #include "pch.h"
  16. #include "probeIGC.h"
  17. const float c_deceleration = 10.0f;
  18. /////////////////////////////////////////////////////////////////////////////
  19. // CprobeIGC
  20. CprobeIGC::CprobeIGC(void)
  21. :
  22. m_probeType(NULL),
  23. m_fraction(1.0f),
  24. m_projectileType(NULL),
  25. m_bCreateNow (false)
  26. {
  27. }
  28. CprobeIGC::~CprobeIGC(void)
  29. {
  30. assert (m_projectileType == NULL);
  31. }
  32. HRESULT CprobeIGC::Initialize(ImissionIGC* pMission, Time now, const void* data, int dataSize)
  33. {
  34. assert (pMission);
  35. m_pMission = pMission;
  36. ZRetailAssert (data && (dataSize > sizeof(DataProbeBase)));
  37. {
  38. DataProbeBase* dataProbeBase = (DataProbeBase*)data;
  39. if ((dataProbeBase->exportF) &&
  40. ((DataProbeExport*)dataProbeBase)->createNow)
  41. {
  42. m_time0 = now;
  43. }
  44. else
  45. {
  46. m_time0 = pMission->GetIgcSite()->ClientTimeFromServerTime(dataProbeBase->time0);
  47. }
  48. TmodelIGC<IprobeIGC>::Initialize(pMission, now, data, dataSize);
  49. IshipIGC* pshipLauncher;
  50. IsideIGC* pside;
  51. IclusterIGC* pcluster;
  52. if (dataProbeBase->exportF)
  53. {
  54. assert (dataSize == sizeof(DataProbeExport));
  55. DataProbeExport* dataProbeExport = (DataProbeExport*)dataProbeBase;
  56. m_probeType = (IprobeTypeIGC*)(pMission->GetExpendableType(dataProbeExport->probetypeID));
  57. pside = pMission->GetSide(dataProbeExport->sideID);
  58. pcluster = pMission->GetCluster(dataProbeExport->clusterID);
  59. pshipLauncher = pside->GetShip(dataProbeExport->shipID);
  60. if (m_probeType->HasCapability(c_eabmShootOnlyTarget))
  61. m_target = pMission->GetModel(dataProbeExport->otTarget, dataProbeExport->oidTarget);
  62. }
  63. else
  64. {
  65. assert (dataSize == sizeof(DataProbeIGC));
  66. DataProbeIGC* dataProbe = (DataProbeIGC*)dataProbeBase;
  67. m_probeType = dataProbe->pprobetype;
  68. pside = dataProbe->pside;
  69. pcluster = dataProbe->pcluster;
  70. pshipLauncher = dataProbe->pship;
  71. if (m_probeType->HasCapability(c_eabmShootOnlyTarget))
  72. m_target = dataProbe->pmodelTarget;
  73. }
  74. assert (m_probeType);
  75. assert (m_probeType->GetObjectType() == OT_probeType);
  76. m_probeType->AddRef();
  77. m_ammo = m_probeType->GetAmmo();
  78. DataProbeTypeIGC* dataProbeType = (DataProbeTypeIGC*)(m_probeType->GetData());
  79. m_projectileType = m_probeType->GetProjectileType();
  80. if (m_projectileType)
  81. {
  82. m_projectileType->AddRef();
  83. m_bSeenByAll = false;
  84. if (pshipLauncher && (dataProbeType->launcherDef.price == 0))
  85. m_launcher = pshipLauncher;
  86. }
  87. assert (pcluster);
  88. //Load the model for the probe
  89. assert (iswalpha(dataProbeType->modelName[0]));
  90. HRESULT hr = Load(0, dataProbeType->modelName,
  91. dataProbeType->textureName,
  92. dataProbeType->iconName,
  93. c_mtDamagable | c_mtHitable | c_mtStatic | c_mtSeenBySide | c_mtPredictable | c_mtScanner);
  94. assert (SUCCEEDED(hr));
  95. SetRadius(dataProbeType->radius);
  96. SetSignature(dataProbeType->signature);
  97. SetSide(pside);
  98. SetSecondaryName(dataProbeType->launcherDef.name);
  99. {
  100. //Parts get a random orientation
  101. Vector v = Vector::RandomDirection();
  102. Orientation o(v);
  103. SetOrientation(o);
  104. }
  105. //lifespan == 0 => immortal probe that can hit until it gets terminated on the next update; this is bad
  106. assert (dataProbeType->lifespan > 0.0f);
  107. m_timeExpire = m_time0 + dataProbeType->lifespan;
  108. assert (m_timeExpire != m_time0);
  109. m_nextFire = m_time0 + (m_probeType->HasCapability(c_eabmQuickReady)
  110. ? 5.0f //5 second delay
  111. : 30.0f); //30 second delay before we start to shoot
  112. assert (GetSide());
  113. SetMass(0.0f);
  114. m_probeID = dataProbeBase->probeID;
  115. SetPosition(dataProbeBase->p0);
  116. SetCluster(pcluster);
  117. pMission->AddProbe(this);
  118. if ((dataProbeType->dtRipcord >= 0.0f) && ((GetMyLastUpdate() - m_time0) >= dataProbeType->dtRipcord))
  119. {
  120. pMission->GetIgcSite()->ActivateTeleportProbe(this);
  121. }
  122. }
  123. return S_OK;
  124. }
  125. void CprobeIGC::Terminate(void)
  126. {
  127. AddRef();
  128. DataProbeTypeIGC* dataProbeType = (DataProbeTypeIGC*)(m_probeType->GetData());
  129. if (dataProbeType->dtRipcord >= 0.0f)
  130. {
  131. GetMyMission()->GetIgcSite()->DestroyTeleportProbe(this);
  132. }
  133. if (m_projectileType)
  134. {
  135. m_projectileType->Release();
  136. m_projectileType = NULL;
  137. }
  138. m_launcher = NULL;
  139. m_target = NULL;
  140. GetCluster()->GetClusterSite()->AddExplosion(GetPosition(), GetRadius(), c_etProbe);
  141. GetMyMission()->DeleteProbe(this);
  142. TmodelIGC<IprobeIGC>::Terminate();
  143. if (m_probeType)
  144. {
  145. m_probeType->Release();
  146. m_probeType = NULL;
  147. }
  148. Release();
  149. }
  150. inline void CprobeIGC::ValidTarget(ImodelIGC* pmodel,
  151. IsideIGC* pside,
  152. const Vector& myPosition,
  153. float dtUpdate,
  154. float accuracy,
  155. float speed,
  156. float lifespan,
  157. ObjectType type,
  158. ImodelIGC** ppmodelMin,
  159. float* pdistance2Min,
  160. Vector* pdirectionMin)
  161. {
  162. //to something that does not include observers, then the check can be removed.
  163. if (pmodel->GetSide() != pside)
  164. {
  165. ModelAttributes ma = pmodel->GetAttributes();
  166. if ((((ma & c_mtStatic) && pmodel->SeenBySide(pside)) || InScannerRange(pmodel)) &&
  167. (ma & c_mtDamagable) &&
  168. ((type != OT_ship) || !((IshipIGC*)pmodel)->GetBaseHullType()->HasCapability(c_habmLifepod)))
  169. {
  170. //Is it a contender?
  171. const Vector& hisVelocity = pmodel->GetVelocity();
  172. Vector dp = pmodel->GetPosition() -
  173. myPosition +
  174. (hisVelocity * dtUpdate);
  175. float distance2 = dp.LengthSquared();
  176. if (distance2 < *pdistance2Min)
  177. {
  178. Vector direction;
  179. float t = solveForImpact(dp,
  180. accuracy * hisVelocity,
  181. speed, pmodel->GetRadius(),
  182. &direction);
  183. if (t <= lifespan)
  184. {
  185. *ppmodelMin = pmodel;
  186. *pdistance2Min = distance2;
  187. *pdirectionMin = direction;
  188. }
  189. }
  190. }
  191. }
  192. }
  193. inline void CprobeIGC::GetTarget(const ModelListIGC* models,
  194. IsideIGC* pside,
  195. const Vector& myPosition,
  196. float dtUpdate,
  197. float accuracy,
  198. float speed,
  199. float lifespan,
  200. ObjectType type,
  201. ImodelIGC** ppmodelMin,
  202. float* pdistance2Min,
  203. Vector* pdirectionMin)
  204. {
  205. for (ModelLinkIGC* l = models->first(); (l != NULL); l = l->next())
  206. {
  207. ImodelIGC* pmodel = l->data();
  208. assert (pmodel->GetObjectType() == type);
  209. ValidTarget(pmodel,
  210. pside,
  211. myPosition,
  212. dtUpdate,
  213. accuracy,
  214. speed,
  215. lifespan,
  216. type,
  217. ppmodelMin,
  218. pdistance2Min,
  219. pdirectionMin);
  220. }
  221. }
  222. void CprobeIGC::Update(Time now)
  223. {
  224. if (now >= m_timeExpire)
  225. GetMyMission()->GetIgcSite()->KillProbeEvent(this);
  226. else
  227. {
  228. {
  229. float dt = m_probeType->GetRipcordDelay();
  230. if (dt >= 0.0f)
  231. {
  232. Time timeActivate = m_time0 + dt;
  233. if ((GetMyLastUpdate() < timeActivate) &&
  234. (now >= timeActivate))
  235. {
  236. GetMyMission()->GetIgcSite()->ActivateTeleportProbe(this);
  237. }
  238. }
  239. }
  240. if (m_projectileType)
  241. {
  242. if (m_nextFire < now)
  243. {
  244. IclusterIGC* pcluster = GetCluster();
  245. assert (pcluster);
  246. //We'll be able to take a shot
  247. float lifespan = GetProjectileLifespan();
  248. IsideIGC* pside = GetSide();
  249. const Vector& myPosition = GetPosition();
  250. float speed = m_projectileType->GetSpeed();
  251. if (m_ammo != 0)
  252. speed *= GetSide()->GetGlobalAttributeSet().GetAttribute(c_gaSpeedAmmo);
  253. float accuracy = GetAccuracy();
  254. float dtimeBurst = GetDtBurst();
  255. float dispersion = m_probeType->GetDispersion();
  256. Time lastUpdate = GetMyLastUpdate();
  257. if (m_nextFire < lastUpdate)
  258. m_nextFire = lastUpdate;
  259. assert (m_nextFire <= now);
  260. TmodelIGC<IprobeIGC>::Update(now);
  261. float dtUpdate = m_nextFire - lastUpdate;
  262. //If we have a target ... find the closest enemy ship who is a valid target
  263. ExpendableAbilityBitMask eabm = m_probeType->GetCapabilities();
  264. float distance2Min = speed * lifespan / 1.2f;
  265. distance2Min *= distance2Min;
  266. Vector directionMin;
  267. ImodelIGC* pmodelTarget = NULL;
  268. if (eabm & c_eabmShootOnlyTarget)
  269. {
  270. if (m_target && (m_target->GetCluster() == pcluster))
  271. {
  272. ObjectType type = m_target->GetObjectType();
  273. ValidTarget((type == OT_ship) ? ((IshipIGC*)(ImodelIGC*)m_target)->GetSourceShip() : m_target,
  274. pside, myPosition, dtUpdate, accuracy, speed, lifespan, type,
  275. &pmodelTarget, &distance2Min, &directionMin);
  276. }
  277. }
  278. else
  279. {
  280. if (eabm & c_eabmShootShips)
  281. {
  282. //Threats to stations get highest priority
  283. GetTarget((const ModelListIGC*)(pcluster->GetShips()),
  284. pside, myPosition, dtUpdate, accuracy, speed, lifespan, OT_ship,
  285. &pmodelTarget, &distance2Min, &directionMin);
  286. }
  287. if (eabm & c_eabmShootMissiles)
  288. {
  289. GetTarget((const ModelListIGC*)(pcluster->GetMissiles()),
  290. pside, myPosition, dtUpdate, accuracy, speed, lifespan, OT_missile,
  291. &pmodelTarget, &distance2Min, &directionMin);
  292. }
  293. if (eabm & c_eabmShootStations)
  294. {
  295. GetTarget((const ModelListIGC*)(pcluster->GetStations()),
  296. pside, myPosition, dtUpdate, accuracy, speed, lifespan, OT_station,
  297. &pmodelTarget, &distance2Min, &directionMin);
  298. }
  299. }
  300. if (pmodelTarget)
  301. {
  302. if (m_launcher && (m_launcher->GetMission() != GetMyMission()))
  303. m_launcher = NULL;
  304. //It is going to shoot ... make it visible to everyone in the sector
  305. if (!m_bSeenByAll)
  306. {
  307. m_bSeenByAll = true;
  308. for (SideLinkIGC* psl = m_pMission->GetSides()->first();
  309. (psl != NULL);
  310. psl = psl->next())
  311. {
  312. IsideIGC* psideOther = psl->data();
  313. if (!SeenBySide(psideOther))
  314. {
  315. //Does this side have any scanners in the sector?
  316. ClusterSite* pcs = pcluster->GetClusterSite();
  317. const ScannerListIGC* psl = pcs->GetScanners(psideOther->GetObjectID());
  318. if (psl->n() != 0)
  319. SetSideVisibility(psideOther, true);
  320. else
  321. m_bSeenByAll = false;
  322. }
  323. }
  324. }
  325. //We have a target ... fire along directionMin (modulo dispersion)
  326. Orientation o = GetOrientation();
  327. o.TurnTo(directionMin);
  328. SetOrientation(o);
  329. Vector position = myPosition + m_probeType->GetEmissionPt() * o;
  330. DataProjectileIGC dataProjectile;
  331. dataProjectile.projectileTypeID = m_projectileType->GetObjectID();
  332. short nShots = 0;
  333. do
  334. {
  335. //Permute the "forward" direction slightly by a random amount
  336. dataProjectile.forward = directionMin;
  337. if (dispersion != 0.0f)
  338. {
  339. float r = random(0.0f, dispersion);
  340. float a = random(0.0f, 2.0f * pi);
  341. dataProjectile.forward += (r * cos(a)) * o.GetRight();
  342. dataProjectile.forward += (r * sin(a)) * o.GetUp();
  343. dataProjectile.forward.SetNormalize();
  344. }
  345. //We never move, so skip all the velocity calculations
  346. dataProjectile.velocity = speed * dataProjectile.forward;
  347. dataProjectile.lifespan = lifespan;
  348. IprojectileIGC* p = (IprojectileIGC*)(m_pMission->CreateObject(m_nextFire, OT_projectile,
  349. &dataProjectile, sizeof(dataProjectile)));
  350. assert (p);
  351. {
  352. p->SetLauncher(m_launcher ? ((ImodelIGC*)m_launcher) : ((ImodelIGC*)this));
  353. p->SetPosition(position);
  354. p->SetCluster(pcluster);
  355. p->Release();
  356. }
  357. nShots++;
  358. m_nextFire += dtimeBurst;
  359. }
  360. while (m_nextFire < now);
  361. if (m_ammo > 0)
  362. {
  363. m_ammo -= nShots;
  364. if (m_ammo <= 0)
  365. {
  366. m_ammo = 0;
  367. GetMyMission()->GetIgcSite()->KillProbeEvent(this);
  368. }
  369. }
  370. }
  371. else
  372. {
  373. //No shots this cycle
  374. m_nextFire = now;
  375. }
  376. }
  377. }
  378. TmodelIGC<IprobeIGC>::Update(now);
  379. }
  380. }
  381. int CprobeIGC::Export(void* data) const
  382. {
  383. if (data)
  384. {
  385. DataProbeExport* pdme = (DataProbeExport*)data;
  386. pdme->p0 = GetPosition();
  387. pdme->time0 = m_time0;
  388. pdme->probeID = GetObjectID();
  389. pdme->exportF = true;
  390. pdme->clusterID = GetCluster()->GetObjectID();
  391. pdme->probetypeID = m_probeType->GetObjectID();
  392. pdme->sideID = GetSide()->GetObjectID();
  393. pdme->shipID = m_launcher ? m_launcher->GetObjectID() : NA;
  394. if (m_target)
  395. {
  396. pdme->otTarget = m_target->GetObjectType();
  397. pdme->oidTarget = m_target->GetObjectID();
  398. }
  399. else
  400. {
  401. pdme->otTarget = NA;
  402. pdme->oidTarget = NA;
  403. }
  404. pdme->createNow = m_bCreateNow;
  405. }
  406. return sizeof(DataProbeExport);
  407. }