explode.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. // explode.cpp
  19. // Project: Postal
  20. //
  21. // This module implements the CExplode weapon class which is an unguided
  22. // rocket missile.
  23. //
  24. //
  25. // History:
  26. // 01/17/97 BRH Started this weapon object.
  27. //
  28. // 01/23/97 BRH Updated the time to GetGameTime rather than using
  29. // real time.
  30. //
  31. // 02/04/97 JMI Changed LoadDib() call to Load() (which now supports
  32. // loading of DIBs).
  33. //
  34. // 02/06/97 BRH Added RAnimSprite animation of the explosion for now.
  35. // We are going to do an Alpha effect on the explosion, so
  36. // there are two animations, one of the image and one of
  37. // the Alpha information stored as a BMP8 animation. When
  38. // the Alpha effect is ready, we will pass a frame from
  39. // each animation to a function to draw it.
  40. //
  41. // 02/06/97 BRH Fixed problem with timer. Since all Explosion objects
  42. // are using the same resource managed animation, they cannot
  43. // use the animation timer, they have to do the timing
  44. // themselves.
  45. //
  46. // 02/07/97 BRH Changed the sprite from CSprite2 to CSpriteAlpha2 for
  47. // the Alpha Blit effect.
  48. //
  49. // 02/10/97 JMI rspReleaseResource() now takes a ptr to a ptr.
  50. //
  51. // 02/18/97 BRH Changed the explosion to use the Channel Animations
  52. // rather than the RAnimSprite animations.
  53. //
  54. // 02/19/97 BRH Empties the message queue in update so it doesn't fill up.
  55. // Also checks for collisions with other Characters and sends
  56. // them an explosion message.
  57. //
  58. // 02/23/97 BRH Explosion now checks for all things that it blew up, not
  59. // just the first thing in the list.
  60. //
  61. // 02/23/97 BRH Added Preload() function so that explosions are cached
  62. // by the resource manager before play begins.
  63. //
  64. // 02/24/97 BRH Added Map3Dto2D so that the explosions were mapping the Y
  65. // coordinate also, before they were assuming they were on the
  66. // ground so explosions in the air weren't working correctly.
  67. //
  68. // 02/24/97 JMI No longer sets the m_type member of the m_sprite b/c it
  69. // is set by m_sprite's constructor.
  70. //
  71. // 03/05/97 BRH Added center of and velocity of explosion to the explosion
  72. // message.
  73. //
  74. // 03/13/97 JMI Load now takes a version number.
  75. //
  76. // 03/17/97 JMI Now includes CSmash::Item in the things that can be
  77. // exploded.
  78. //
  79. // 04/10/97 BRH Updated this to work with the new multi layer attribute
  80. // maps.
  81. //
  82. // 04/20/97 BRH Added an additional parameter to Setup to allow the
  83. // explosion to use different animations. In this case we
  84. // want the standard explosion for rockets and barrels, and
  85. // a special one for the grenades. This will allow you to
  86. // pass a number to incicate which animation to use.
  87. //
  88. // 04/21/97 BRH Added second animation file and changed filename of second
  89. // asset to match.
  90. //
  91. // 04/23/97 JMI CExplode no longer puts it's m_smash in the smashatorium.
  92. // Now sends messages to Characters, Miscs, Barrels, and
  93. // Mines.
  94. //
  95. // 05/29/97 JMI Removed ASSERT on m_pRealm->m_pAttribMap which no longer
  96. // exists.
  97. //
  98. // 06/07/97 BRH Added smoke to the end of all explosions.
  99. //
  100. // 06/11/97 BRH Pass the shooter ID on through the explosion message.
  101. //
  102. // 06/18/97 BRH Changed over to using GetRandom()
  103. //
  104. // 06/26/97 BRH Added CSmash::AlmostDead bits to the explosion check
  105. // so that writhing guys can be blown up.
  106. //
  107. // 07/09/97 JMI Now uses m_pRealm->Make2dResPath() to get the fullpath
  108. // for 2D image components.
  109. //
  110. // 07/09/97 JMI Changed Preload() to take a pointer to the calling realm
  111. // as a parameter.
  112. //
  113. // 07/27/97 JMI Changed to use Z position (i.e., X/Z plane) instead of
  114. // Y2 position (i.e., viewing plane) position for draw
  115. // priority.
  116. //
  117. // 07/30/97 JMI Added m_u16ExceptID (an ID to except when sending
  118. // explosion messages).
  119. //
  120. // 08/15/97 BRH Fixed problem with stationary smoke which had been
  121. // started under ground.
  122. //
  123. // 08/28/97 BRH Now caches the grenade explosion animation as well in
  124. // its Preload function.
  125. //
  126. // 09/02/97 JMI Now targets CSmash::Sentry too.
  127. //
  128. // 09/03/97 JMI Now marks Civilian as a dont care bit.
  129. //
  130. ////////////////////////////////////////////////////////////////////////////////
  131. #define EXPLODE_CPP
  132. #include "RSPiX.h"
  133. #include <math.h>
  134. #include "explode.h"
  135. #include "dude.h"
  136. #include "game.h"
  137. #include "reality.h"
  138. #include "fire.h"
  139. ////////////////////////////////////////////////////////////////////////////////
  140. // Macros/types/etc.
  141. ////////////////////////////////////////////////////////////////////////////////
  142. //#define IMAGE_FILE "res\\explode.bmp"
  143. //#define ANIM_FILE "2d/explode.anm"
  144. //#define ALPHA_FILE "2d/explode_a.anm"
  145. // Minimum elapsed time (in milliseconds)
  146. //#define MIN_ELAPSED_TIME 10
  147. #define AA_FILE "explo.aan"
  148. #define GE_FILE "GExplo.aan"
  149. ////////////////////////////////////////////////////////////////////////////////
  150. // Variables/data
  151. ////////////////////////////////////////////////////////////////////////////////
  152. // These are default values -- actually values are set using the editor!
  153. // Let this auto-init to 0
  154. short CExplode::ms_sFileCount;
  155. short CExplode::ms_sBlastRadius = 30;
  156. short CExplode::ms_sProjectVelocity = 180;
  157. ////////////////////////////////////////////////////////////////////////////////
  158. // Load object (should call base class version!)
  159. ////////////////////////////////////////////////////////////////////////////////
  160. short CExplode::Load( // Returns 0 if successfull, non-zero otherwise
  161. RFile* pFile, // In: File to load from
  162. bool bEditMode, // In: True for edit mode, false otherwise
  163. short sFileCount, // In: File count (unique per file, never 0)
  164. ULONG ulFileVersion) // In: Version of file format to load.
  165. {
  166. short sResult = CThing::Load(pFile, bEditMode, sFileCount, ulFileVersion);
  167. if (sResult == 0)
  168. {
  169. // Load common data just once per file (not with each object)
  170. if (ms_sFileCount != sFileCount)
  171. {
  172. ms_sFileCount = sFileCount;
  173. // Load static data
  174. switch (ulFileVersion)
  175. {
  176. default:
  177. case 1:
  178. break;
  179. }
  180. }
  181. // Load instance data.
  182. switch (ulFileVersion)
  183. {
  184. default:
  185. case 1:
  186. break;
  187. }
  188. // Make sure there were no file errors or format errors . . .
  189. if (!pFile->Error() && sResult == 0)
  190. {
  191. // Get resources
  192. sResult = GetResources();
  193. }
  194. else
  195. {
  196. sResult = -1;
  197. TRACE("CExplode::Load(): Error reading from file!\n");
  198. }
  199. }
  200. else
  201. {
  202. TRACE("CExplode::Load(): CThing::Load() failed.\n");
  203. }
  204. return sResult;
  205. }
  206. ////////////////////////////////////////////////////////////////////////////////
  207. // Save object (should call base class version!)
  208. ////////////////////////////////////////////////////////////////////////////////
  209. short CExplode::Save( // Returns 0 if successfull, non-zero otherwise
  210. RFile* pFile, // In: File to save to
  211. short sFileCount) // In: File count (unique per file, never 0)
  212. {
  213. short sResult = CThing::Save(pFile, sFileCount);
  214. if (sResult == 0)
  215. {
  216. // Save common data just once per file (not with each object)
  217. if (ms_sFileCount != sFileCount)
  218. {
  219. ms_sFileCount = sFileCount;
  220. // Save static data
  221. }
  222. }
  223. else
  224. {
  225. TRACE("CExplode::Save(): CThing::Save() failed.\n");
  226. }
  227. return sResult;
  228. }
  229. ////////////////////////////////////////////////////////////////////////////////
  230. // Startup object
  231. ////////////////////////////////////////////////////////////////////////////////
  232. short CExplode::Startup(void) // Returns 0 if successfull, non-zero otherwise
  233. {
  234. return 0;
  235. }
  236. ////////////////////////////////////////////////////////////////////////////////
  237. // Shutdown object
  238. ////////////////////////////////////////////////////////////////////////////////
  239. short CExplode::Shutdown(void) // Returns 0 if successfull, non-zero otherwise
  240. {
  241. return 0;
  242. }
  243. ////////////////////////////////////////////////////////////////////////////////
  244. // Suspend object
  245. ////////////////////////////////////////////////////////////////////////////////
  246. void CExplode::Suspend(void)
  247. {
  248. m_sSuspend++;
  249. }
  250. ////////////////////////////////////////////////////////////////////////////////
  251. // Resume object
  252. ////////////////////////////////////////////////////////////////////////////////
  253. void CExplode::Resume(void)
  254. {
  255. m_sSuspend--;
  256. // If we're actually going to start updating again, we need to reset
  257. // the time so as to ignore any time that passed while we were suspended.
  258. // This method is far from precise, but I'm hoping it's good enough.
  259. if (m_sSuspend == 0)
  260. m_lPrevTime = m_pRealm->m_time.GetGameTime();
  261. }
  262. ////////////////////////////////////////////////////////////////////////////////
  263. // Update object
  264. ////////////////////////////////////////////////////////////////////////////////
  265. void CExplode::Update(void)
  266. {
  267. if (!m_sSuspend)
  268. {
  269. // Since we don't process any messages, empty the queue
  270. m_MessageQueue.Empty();
  271. // Get new time
  272. long lThisTime = m_pRealm->m_time.GetGameTime();
  273. if (m_lTimer < m_pAnimChannel->TotalTime())
  274. {
  275. m_lTimer += lThisTime - m_lPrevTime;
  276. m_lPrevTime = lThisTime;
  277. }
  278. else
  279. {
  280. short a;
  281. CFire* pSmoke;
  282. for (a = 0; a < 8; a++)
  283. {
  284. if (CThing::Construct(CThing::CFireID, m_pRealm, (CThing**) &pSmoke) == 0)
  285. pSmoke->Setup(m_dX - 4 + GetRandom() % 9, MAX(m_dY-20, 0.0), m_dZ - 4 + GetRandom() % 9, 4000, true, CFire::Smoke);
  286. }
  287. delete this;
  288. return;
  289. }
  290. }
  291. }
  292. ////////////////////////////////////////////////////////////////////////////////
  293. // Render object
  294. ////////////////////////////////////////////////////////////////////////////////
  295. void CExplode::Render(void)
  296. {
  297. CAlphaAnim* pAnim = (CAlphaAnim*) m_pAnimChannel->GetAtTime(m_lTimer);
  298. if (pAnim)
  299. {
  300. // No special flags
  301. m_sprite.m_sInFlags = 0; //CSprite::InXrayable;
  302. // Map from 3d to 2d coords
  303. // m_sprite.m_sX2 = m_dX + pAnim->m_sX;
  304. // m_sprite.m_sY2 = m_dZ + pAnim->m_sY;
  305. Map3Dto2D((short) (m_dX + pAnim->m_sX), (short) m_dY, (short) (m_dZ + pAnim->m_sY), &m_sprite.m_sX2, &m_sprite.m_sY2);
  306. // Priority is based on our Z position.
  307. m_sprite.m_sPriority = m_dZ;
  308. // Layer should be based on info we get from attribute map.
  309. m_sprite.m_sLayer = CRealm::GetLayerViaAttrib(m_pRealm->GetLayer((short) m_dX, (short) m_dZ));
  310. // Copy the color info and the alpha channel to the Alpha Sprite
  311. m_sprite.m_pImage = &(pAnim->m_imColor);
  312. m_sprite.m_pimAlpha = &(pAnim->m_pimAlphaArray[0]);
  313. // temp
  314. short sTemp = pAnim->m_sNumAlphas;
  315. // Update sprite in scene
  316. m_pRealm->m_scene.UpdateSprite(&m_sprite);
  317. }
  318. }
  319. ////////////////////////////////////////////////////////////////////////////////
  320. // Setup - Called by the object that is creating this explosion to set its
  321. // position and initial settings
  322. ////////////////////////////////////////////////////////////////////////////////
  323. short CExplode::Setup( // Returns 0 if successfull, non-zero otherwise
  324. short sX, // In: New x coord
  325. short sY, // In: New y coord
  326. short sZ, // In: New z coord
  327. U16 u16ShooterID, // In: Who is responsible for this explosion
  328. short sAnim) // In: Which animation to use
  329. {
  330. short sResult = 0;
  331. // Use specified position
  332. m_dX = (double)sX;
  333. m_dY = (double)sY;
  334. m_dZ = (double)sZ;
  335. m_lPrevTime = m_pRealm->m_time.GetGameTime();
  336. m_lTimer = 0;
  337. m_u16ShooterID = u16ShooterID;
  338. // Load resources
  339. sResult = GetResources(sAnim);
  340. // Update sphere.
  341. m_smash.m_sphere.sphere.X = m_dX;
  342. m_smash.m_sphere.sphere.Y = m_dY;
  343. m_smash.m_sphere.sphere.Z = m_dZ;
  344. m_smash.m_sphere.sphere.lRadius = ms_sBlastRadius;
  345. // Update the smash.
  346. ASSERT (m_pRealm != NULL);
  347. // m_pRealm->m_smashatorium.Update(&m_smash);
  348. m_smash.m_bits = 0;
  349. m_smash.m_pThing = this;
  350. // See who we blew up and send them a message
  351. CSmash* pSmashed = NULL;
  352. GameMessage msg;
  353. msg.msg_Explosion.eType = typeExplosion;
  354. msg.msg_Explosion.sPriority = 0;
  355. msg.msg_Explosion.sDamage = 100;
  356. msg.msg_Explosion.sX = (short) m_dX;
  357. msg.msg_Explosion.sY = (short) m_dY;
  358. msg.msg_Explosion.sZ = (short) m_dZ;
  359. msg.msg_Explosion.sVelocity = ms_sProjectVelocity;
  360. msg.msg_Explosion.u16ShooterID = m_u16ShooterID;
  361. m_pRealm->m_smashatorium.QuickCheckReset(
  362. &m_smash,
  363. CSmash::Character | CSmash::Misc | CSmash::Barrel | CSmash::Mine | CSmash::AlmostDead | CSmash::Sentry,
  364. CSmash::Good | CSmash::Bad | CSmash::Civilian,
  365. 0);
  366. while (m_pRealm->m_smashatorium.QuickCheckNext(&pSmashed))
  367. {
  368. ASSERT(pSmashed->m_pThing);
  369. // If not the excepted thing . . .
  370. if (pSmashed->m_pThing->GetInstanceID() != m_u16ExceptID)
  371. {
  372. SendThingMessage(&msg, pSmashed->m_pThing);
  373. }
  374. }
  375. return sResult;
  376. }
  377. ////////////////////////////////////////////////////////////////////////////////
  378. // Called by editor to init new object at specified position
  379. ////////////////////////////////////////////////////////////////////////////////
  380. short CExplode::EditNew( // Returns 0 if successfull, non-zero otherwise
  381. short sX, // In: New x coord
  382. short sY, // In: New y coord
  383. short sZ) // In: New z coord
  384. {
  385. short sResult = 0;
  386. // Use specified position
  387. m_dX = (double)sX;
  388. m_dY = (double)sY;
  389. m_dZ = (double)sZ;
  390. m_lTimer = m_pRealm->m_time.GetGameTime() + 1000;
  391. m_lPrevTime = m_pRealm->m_time.GetGameTime();
  392. // Load resources
  393. sResult = GetResources();
  394. return sResult;
  395. }
  396. ////////////////////////////////////////////////////////////////////////////////
  397. // Called by editor to modify object
  398. ////////////////////////////////////////////////////////////////////////////////
  399. short CExplode::EditModify(void)
  400. {
  401. return 0;
  402. }
  403. ////////////////////////////////////////////////////////////////////////////////
  404. // Called by editor to move object to specified position
  405. ////////////////////////////////////////////////////////////////////////////////
  406. short CExplode::EditMove( // Returns 0 if successfull, non-zero otherwise
  407. short sX, // In: New x coord
  408. short sY, // In: New y coord
  409. short sZ) // In: New z coord
  410. {
  411. m_dX = (double)sX;
  412. m_dY = (double)sY;
  413. m_dZ = (double)sZ;
  414. return 0;
  415. }
  416. ////////////////////////////////////////////////////////////////////////////////
  417. // Called by editor to update object
  418. ////////////////////////////////////////////////////////////////////////////////
  419. void CExplode::EditUpdate(void)
  420. {
  421. }
  422. ////////////////////////////////////////////////////////////////////////////////
  423. // Called by editor to render object
  424. ////////////////////////////////////////////////////////////////////////////////
  425. void CExplode::EditRender(void)
  426. {
  427. // In some cases, object's might need to do a special-case render in edit
  428. // mode because Startup() isn't called. In this case it doesn't matter, so
  429. // we can call the normal Render().
  430. Render();
  431. }
  432. ////////////////////////////////////////////////////////////////////////////////
  433. // Get all required resources
  434. ////////////////////////////////////////////////////////////////////////////////
  435. short CExplode::GetResources(short sAnim) // Returns 0 if successfull, non-zero otherwise
  436. {
  437. short sResult = 0;
  438. if (sAnim == 0)
  439. sResult = rspGetResource(&g_resmgrGame, m_pRealm->Make2dResPath(AA_FILE), &m_pAnimChannel, RFile::LittleEndian);
  440. else
  441. sResult = rspGetResource(&g_resmgrGame, m_pRealm->Make2dResPath(GE_FILE), &m_pAnimChannel, RFile::LittleEndian);
  442. if (sResult != 0)
  443. TRACE("CExplosion::GetResources - Error getting explosion animation\n");
  444. return sResult;
  445. }
  446. ////////////////////////////////////////////////////////////////////////////////
  447. // Free all resources
  448. ////////////////////////////////////////////////////////////////////////////////
  449. short CExplode::FreeResources(void) // Returns 0 if successfull, non-zero otherwise
  450. {
  451. rspReleaseResource(&g_resmgrGame, &m_pAnimChannel);
  452. return 0;
  453. }
  454. ////////////////////////////////////////////////////////////////////////////////
  455. // Preload - basically trick the resource manager into caching a CExplode
  456. // animation before play begins so that when an explosion occurs for
  457. // the first time, there won't be a delay.
  458. ////////////////////////////////////////////////////////////////////////////////
  459. short CExplode::Preload(
  460. CRealm* prealm) // In: Calling realm.
  461. {
  462. ChannelAA* pRes;
  463. short sResult = rspGetResource(&g_resmgrGame, prealm->Make2dResPath(AA_FILE), &pRes, RFile::LittleEndian);
  464. rspReleaseResource(&g_resmgrGame, &pRes);
  465. sResult = rspGetResource(&g_resmgrGame, prealm->Make2dResPath(GE_FILE), &pRes, RFile::LittleEndian);
  466. rspReleaseResource(&g_resmgrGame, &pRes);
  467. return sResult;
  468. }
  469. ////////////////////////////////////////////////////////////////////////////////
  470. // EOF
  471. ////////////////////////////////////////////////////////////////////////////////