ostrich.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999
  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. // ostrich.cpp
  19. // Project: Postal
  20. //
  21. // This module implements the ostrich.
  22. //
  23. // History:
  24. //
  25. // 05/09/97 BRH Started the ostrich from the band member logic.
  26. //
  27. // 05/22/97 BRH Render skips the Doofus render and goes right to the
  28. // Character render since its not using the m_dAnimRot.
  29. //
  30. // 05/26/97 BRH Changed the call to OnDead to the Doofus version
  31. // rather than the Character version.
  32. //
  33. // 05/29/97 JMI Changed instance of REALM_ATTR_FLOOR_MASK to
  34. // REALM_ATTR_NOT_WALKABLE.
  35. //
  36. // 06/05/97 JMI Changed m_sHitPoints to m_stockpile.m_sHitPoints to
  37. // accommodate new m_stockpile in base class, CThing3d (which
  38. // used to contain the m_sHitPoints).
  39. //
  40. // 06/18/97 BRH Changed over to using GetRandom()
  41. //
  42. // 06/25/97 JMI Now calls PrepareShadow() in Init() which loads and sets up
  43. // a shadow sprite.
  44. //
  45. // 06/30/97 MJR Replaced SAFE_GUI_REF with new GuiItem.h-defined macro.
  46. //
  47. // 06/30/97 BRH Cached the sound samples in static portion of Load
  48. // function so that the sound effects will be ready
  49. // whenever this item is used on a level.
  50. //
  51. // 07/01/97 JMI Replaced GetFloorMapValue() with GetHeightAndNoWalk() call.
  52. //
  53. // 07/09/97 JMI Now uses m_pRealm->Make2dResPath() to get the fullpath
  54. // for 2D image components.
  55. //
  56. // 07/12/97 BRH Changed panic motion to the same as the base class, but
  57. // it still didn't fix the problem of them going through the
  58. // wall of the train car on the farm level. Also increased
  59. // their hit points, and made them not die in one shot.
  60. //
  61. // 07/18/97 JMI Got rid of bogus immitation PlaySample functions.
  62. // Now there is one PlaySample() function. Also, you now
  63. // MUST specify a category and you don't have to specify a
  64. // SoundInstance ptr to specify a volume.
  65. //
  66. // 07/21/97 BRH Changed the burning state so that the ostrich will burn
  67. // longer.
  68. //
  69. // 08/06/97 BRH Changed smash bits to zero when dying starts so that things
  70. // won't hit him as he falls slowly, and so you can shoot
  71. // past him. Also allows the shot animation restart when shot
  72. // to get a little more reaction since his shot animation
  73. // is so long.
  74. //
  75. // 08/10/97 JMI Commented out the code that deleted all the sound things in
  76. // a realm when the ostriches paniced.
  77. //
  78. // 08/12/97 BRH Set the flag for victim rather than hostile so that
  79. // the score will display the correct numbers of each
  80. // type.
  81. //
  82. // 09/03/97 JMI Replaced Good Smash bit with Civilian.
  83. //
  84. // 09/03/97 BRH Put in the real ostrich sounds.
  85. //
  86. // 09/04/97 BRH Added ostrich dying sound.
  87. //
  88. ////////////////////////////////////////////////////////////////////////////////
  89. #define OSTRICH_CPP
  90. #include "RSPiX.h"
  91. #include <math.h>
  92. #include "ostrich.h"
  93. #include "SampleMaster.h"
  94. #include "item3d.h"
  95. ////////////////////////////////////////////////////////////////////////////////
  96. // Macros/types/etc.
  97. ////////////////////////////////////////////////////////////////////////////////
  98. #define BRIGHTNESS_PER_LIGHT_ATTRIBUTE 15
  99. #define NUM_ELEMENTS(a) (sizeof(a) / sizeof(a[0]) )
  100. // Notification message lParm1's.
  101. #define BLOOD_POOL_DONE_NOTIFICATION 1 // Blood pool is done animating.
  102. // Random amount the blood splat can adjust.
  103. #define BLOOD_SPLAT_SWAY 10
  104. // Gets a random between -range / 2 and range / 2.
  105. #define RAND_SWAY(sway) ((GetRandom() % sway) - sway / 2)
  106. #define GUI_ID_OK 1
  107. ////////////////////////////////////////////////////////////////////////////////
  108. // Variables/data
  109. ////////////////////////////////////////////////////////////////////////////////
  110. double COstrich::ms_dExplosionVelocity = 180.0;
  111. double COstrich::ms_dMaxMarchVel = 30.0;
  112. double COstrich::ms_dMaxRunVel = 80.0;
  113. long COstrich::ms_lStateChangeTime = 10000;
  114. short COstrich::ms_sStartingHitPoints = 100;
  115. // Let this auto-init to 0
  116. short COstrich::ms_sFileCount;
  117. /// Standing Animation Files
  118. // An array of pointers to resource names (one for each channel of the animation)
  119. static char* ms_apszStandResNames[] =
  120. {
  121. "3d/ostrich_stand.sop",
  122. "3d/ostrich_stand.mesh",
  123. "3d/ostrich_stand.tex",
  124. "3d/ostrich_stand.hot",
  125. "3d/ostrich_stand.bounds",
  126. "3d/ostrich_stand.floor",
  127. NULL,
  128. NULL
  129. };
  130. /// Running Animation Files
  131. // An array of pointers to resource names (one for each channel of the animation)
  132. static char* ms_apszRunResNames[] =
  133. {
  134. "3d/ostrich_run.sop",
  135. "3d/ostrich_run.mesh",
  136. "3d/ostrich_run.tex",
  137. "3d/ostrich_run.hot",
  138. "3d/ostrich_run.bounds",
  139. "3d/ostrich_run.floor",
  140. NULL,
  141. NULL
  142. };
  143. /// Throwing Animation Files
  144. // An array of pointers to resource names (one for each channel of the animation)
  145. static char* ms_apszWalkResNames[] =
  146. {
  147. "3d/ostrich_walk.sop",
  148. "3d/ostrich_walk.mesh",
  149. "3d/ostrich_walk.tex",
  150. "3d/ostrich_walk.hot",
  151. "3d/ostrich_walk.bounds",
  152. "3d/ostrich_walk.floor",
  153. NULL,
  154. NULL
  155. };
  156. // Shot Animation Files
  157. // An array of pointers to resource names (one for each channel of the animation)
  158. static char* ms_apszShotResNames[] =
  159. {
  160. "3d/ostrich_shot.sop",
  161. "3d/ostrich_shot.mesh",
  162. "3d/ostrich_shot.tex",
  163. "3d/ostrich_shot.hot",
  164. "3d/ostrich_shot.bounds",
  165. "3d/ostrich_shot.floor",
  166. NULL,
  167. NULL
  168. };
  169. /// Blown up Animation Files
  170. // An array of pointers to resource names (one for each channel of the animation)
  171. static char* ms_apszBlownupResNames[] =
  172. {
  173. "3d/ostrich_blownup.sop",
  174. "3d/ostrich_blownup.mesh",
  175. "3d/ostrich_blownup.tex",
  176. "3d/ostrich_blownup.hot",
  177. "3d/ostrich_blownup.bounds",
  178. "3d/ostrich_blownup.floor",
  179. NULL,
  180. NULL
  181. };
  182. /// Hide Animation Files
  183. // An array of pointers to resource names (one for each channel of the animation)
  184. static char* ms_apszHideResNames[] =
  185. {
  186. "3d/ostrich_hide.sop",
  187. "3d/ostrich_hide.mesh",
  188. "3d/ostrich_hide.tex",
  189. "3d/ostrich_hide.hot",
  190. "3d/ostrich_hide.bounds",
  191. "3d/ostrich_hide.floor",
  192. NULL,
  193. NULL
  194. };
  195. /// Die Animation files
  196. // An array of pointers to resource names (one for each channel of the animation)
  197. static char* ms_apszDieResNames[] =
  198. {
  199. "3d/ostrich_die.sop",
  200. "3d/ostrich_die.mesh",
  201. "3d/ostrich_die.tex",
  202. "3d/ostrich_die.hot",
  203. "3d/ostrich_die.bounds",
  204. "3d/ostrich_die.floor",
  205. NULL,
  206. NULL
  207. };
  208. // These are the points that are checked on the attribute map relative to his origin
  209. static RP3d ms_apt3dAttribCheck[] =
  210. {
  211. {-6, 0, -6},
  212. { 0, 0, -6},
  213. { 6, 0, -6},
  214. {-6, 0, 6},
  215. { 0, 0, 6},
  216. { 6, 0, 6},
  217. };
  218. ////////////////////////////////////////////////////////////////////////////////
  219. // Load object (should call base class version!)
  220. ////////////////////////////////////////////////////////////////////////////////
  221. short COstrich::Load( // Returns 0 if successfull, non-zero otherwise
  222. RFile* pFile, // In: File to load from
  223. bool bEditMode, // In: True for edit mode, false otherwise
  224. short sFileCount, // In: File count (unique per file, never 0)
  225. ULONG ulFileVersion) // In: Version of file format to load.
  226. {
  227. short sResult = 0;
  228. // Call the base class load to get the instance ID, position, motion etc.
  229. sResult = CDoofus::Load(pFile, bEditMode, sFileCount, ulFileVersion);
  230. if (sResult == 0)
  231. {
  232. // Load common data just once per file (not with each object)
  233. if (ms_sFileCount != sFileCount)
  234. {
  235. ms_sFileCount = sFileCount;
  236. // Load static data
  237. switch (ulFileVersion)
  238. {
  239. default:
  240. case 1:
  241. CacheSample(g_smidOstrichShot);
  242. CacheSample(g_smidOstrichBurning);
  243. CacheSample(g_smidOstrichBlownup);
  244. CacheSample(g_smidOstrichDie);
  245. break;
  246. }
  247. }
  248. // Load Rocket Man specific data
  249. switch (ulFileVersion)
  250. {
  251. default:
  252. case 4:
  253. case 3:
  254. case 2:
  255. case 1:
  256. break;
  257. }
  258. // Make sure there were no file errors or format errors . . .
  259. if (!pFile->Error() && sResult == 0)
  260. {
  261. // Get resources
  262. sResult = GetResources();
  263. }
  264. else
  265. {
  266. sResult = -1;
  267. TRACE("COstrich::Load(): Error reading from file!\n");
  268. }
  269. }
  270. else
  271. {
  272. TRACE("CGrenader::Load(): CDoofus::Load() failed.\n");
  273. }
  274. return sResult;
  275. }
  276. ////////////////////////////////////////////////////////////////////////////////
  277. // Save object (should call base class version!)
  278. ////////////////////////////////////////////////////////////////////////////////
  279. short COstrich::Save( // Returns 0 if successfull, non-zero otherwise
  280. RFile* pFile, // In: File to save to
  281. short sFileCount) // In: File count (unique per file, never 0)
  282. {
  283. short sResult = SUCCESS;
  284. // Call the base class save to save the instance ID, position etc.
  285. CDoofus::Save(pFile, sFileCount);
  286. // Save common data just once per file (not with each object)
  287. if (ms_sFileCount != sFileCount)
  288. {
  289. ms_sFileCount = sFileCount;
  290. // Save static data
  291. }
  292. if (!pFile->Error())
  293. {
  294. sResult = SUCCESS;
  295. }
  296. else
  297. {
  298. TRACE("COstrich::Save() - Error writing to file\n");
  299. sResult = -1;
  300. }
  301. return sResult;
  302. }
  303. ////////////////////////////////////////////////////////////////////////////////
  304. // Init - Call this after the resources are in place
  305. ////////////////////////////////////////////////////////////////////////////////
  306. short COstrich::Init(void)
  307. {
  308. short sResult = 0;
  309. // Prepare shadow (get resources and setup sprite).
  310. sResult = PrepareShadow();
  311. // Init position, rotation and velocity
  312. m_dVel = 0.0;
  313. m_dRot = rspMod360(GetRandom());
  314. m_lPrevTime = m_pRealm->m_time.GetGameTime();
  315. m_state = CCharacter::State_Idle;
  316. m_lTimer = m_pRealm->m_time.GetGameTime() + 500;
  317. m_sBrightness = 0; // Default brightness
  318. m_smash.m_bits = CSmash::Civilian | CSmash::Character;
  319. m_smash.m_pThing = this;
  320. m_lAnimTime = 0;
  321. m_panimCur = &m_animStand;
  322. m_lTimer = m_pRealm->m_time.GetGameTime();
  323. m_stockpile.m_sHitPoints = ms_sStartingHitPoints;
  324. m_state = CCharacter::State_Stand;
  325. m_dAcc = 150;
  326. return sResult;
  327. }
  328. ////////////////////////////////////////////////////////////////////////////////
  329. // Startup object
  330. ////////////////////////////////////////////////////////////////////////////////
  331. short COstrich::Startup(void) // Returns 0 if successfull, non-zero otherwise
  332. {
  333. // Register this as a victim rather than a hostile.
  334. m_bCivilian = true;
  335. // Set the current height, previous time, and Nav Net by calling the
  336. // base class startup
  337. CDoofus::Startup();
  338. // Init other stuff
  339. return Init();
  340. }
  341. ////////////////////////////////////////////////////////////////////////////////
  342. // Update object
  343. ////////////////////////////////////////////////////////////////////////////////
  344. void COstrich::Update(void)
  345. {
  346. short sHeight = m_sPrevHeight;
  347. double dNewX;
  348. double dNewY;
  349. double dNewZ;
  350. double dX;
  351. double dZ;
  352. long lThisTime;
  353. long lTimeDifference;
  354. if (!m_sSuspend)
  355. {
  356. // Get new time
  357. lThisTime = m_pRealm->m_time.GetGameTime();
  358. lTimeDifference = lThisTime - m_lPrevTime;
  359. // Calculate elapsed time in seconds
  360. double dSeconds = (double)(lThisTime - m_lPrevTime) / 1000.0;
  361. // Check for new messages that may change the state
  362. ProcessMessages();
  363. // Increment animation time
  364. m_lAnimTime += lTimeDifference;
  365. // Check the current state
  366. switch (m_state)
  367. {
  368. //-----------------------------------------------------------------------
  369. // Stand or Hide - Either one waits in the current position for the
  370. // random timer to expire.
  371. //-----------------------------------------------------------------------
  372. case State_Stand:
  373. case State_Hide:
  374. if (lThisTime > m_lTimer)
  375. ChangeRandomState();
  376. break;
  377. //-----------------------------------------------------------------------
  378. // Walk - Walk around a bit
  379. //-----------------------------------------------------------------------
  380. case State_Walk:
  381. if (lThisTime > m_lTimer)
  382. {
  383. ChangeRandomState();
  384. }
  385. else
  386. {
  387. dX = m_dX;
  388. dZ = m_dZ;
  389. m_dAcc = ms_dAccUser;
  390. UpdateVelocities(dSeconds, ms_dMaxMarchVel, ms_dMaxMarchVel);
  391. GetNewPosition(&dNewX, &dNewY, &dNewZ, dSeconds);
  392. if (MakeValidPosition(&dNewX, &dNewY, &dNewZ, 10) == true)
  393. {
  394. // Update Values /////////////////////////////////////////////////////////
  395. m_dX = dNewX;
  396. m_dY = dNewY;
  397. m_dZ = dNewZ;
  398. UpdateFirePosition();
  399. }
  400. else
  401. {
  402. // Restore Values ////////////////////////////////////////////////////////
  403. m_dVel -= m_dDeltaVel;
  404. }
  405. // If he didn't move at all, then turn him so he will
  406. // avoid the wall
  407. if (dX == m_dX && dZ == m_dZ)
  408. {
  409. // Turn to avoid wall next time
  410. if (m_sRotDirection == 0)
  411. m_dRot = rspMod360(m_dRot - 20);
  412. else
  413. m_dRot = rspMod360(m_dRot + 20);
  414. }
  415. }
  416. break;
  417. //-----------------------------------------------------------------------
  418. // Panic - Pick a random bouy and run to it. When you are there, pick
  419. // a different random bouy and run to it.
  420. //-----------------------------------------------------------------------
  421. case State_Panic:
  422. dX = m_dX;
  423. dZ = m_dZ;
  424. DeluxeUpdatePosVel(dSeconds);
  425. /*
  426. m_dAcc = ms_dAccUser;
  427. UpdateVelocities(dSeconds, ms_dMaxRunVel, ms_dMaxRunVel);
  428. GetNewPosition(&dNewX, &dNewY, &dNewZ, dSeconds);
  429. // Get height and 'no walk' status at new position.
  430. bool bNoWalk;
  431. sHeight = m_pRealm->GetHeightAndNoWalk(dNewX, dNewY, &bNoWalk);
  432. // If too big a height difference or completely not walkable . . .
  433. if (bNoWalk == true
  434. || (sHeight - dNewY > 10) )// && m_bAboveTerrain == false && m_dExtHorzVel == 0.0))
  435. {
  436. TRACE("****** - loose ostrish\n");
  437. // Move like smoke
  438. }
  439. if (MakeValidPosition(&dNewX, &dNewY, &dNewZ, 10) == true)
  440. {
  441. // Update Values /////////////////////////////////////////////////////////
  442. m_dX = dNewX;
  443. m_dY = dNewY;
  444. m_dZ = dNewZ;
  445. UpdateFirePosition();
  446. }
  447. else
  448. {
  449. // Restore Values ////////////////////////////////////////////////////////
  450. m_dVel -= m_dDeltaVel;
  451. }
  452. */
  453. // If he didn't move at all, then turn him so he will
  454. // avoid the wall
  455. if (dX == m_dX && dZ == m_dZ)
  456. {
  457. // Turn to avoid wall next time
  458. if (m_sRotDirection == 0)
  459. m_dRot = rspMod360(m_dRot - 20);
  460. else
  461. m_dRot = rspMod360(m_dRot + 20);
  462. }
  463. break;
  464. //-----------------------------------------------------------------------
  465. // Burning - Run around on fire until dead
  466. //-----------------------------------------------------------------------
  467. case State_Burning:
  468. if (!CCharacter::WhileBurning())
  469. {
  470. if (m_stockpile.m_sHitPoints <= 0)
  471. {
  472. m_state = State_Die;
  473. m_lAnimTime = 0;
  474. m_panimCur = &m_animDie;
  475. PlaySample(
  476. g_smidOstrichDie,
  477. SampleMaster::Voices);
  478. }
  479. else
  480. {
  481. m_state = State_Panic;
  482. }
  483. }
  484. break;
  485. //-----------------------------------------------------------------------
  486. // Blown Up - Do motion into the air until you hit the ground again
  487. //-----------------------------------------------------------------------
  488. case State_BlownUp:
  489. if (!CCharacter::WhileBlownUp())
  490. m_state = State_Dead;
  491. else
  492. UpdateFirePosition();
  493. break;
  494. //-----------------------------------------------------------------------
  495. // Shot - Dies in one shot
  496. //-----------------------------------------------------------------------
  497. case State_Shot:
  498. if (!CCharacter::WhileShot())
  499. {
  500. if (m_stockpile.m_sHitPoints <= 0)
  501. {
  502. m_state = State_Die;
  503. m_panimCur = &m_animDie;
  504. m_lAnimTime = 0;
  505. PlaySample(
  506. g_smidOstrichDie,
  507. SampleMaster::Voices);
  508. }
  509. else
  510. {
  511. m_state = State_Panic;
  512. m_panimCur = &m_animRun;
  513. m_lAnimTime = 0;
  514. }
  515. }
  516. break;
  517. //-----------------------------------------------------------------------
  518. // Die - run die animation until done, the you are dead
  519. //-----------------------------------------------------------------------
  520. case State_Die:
  521. m_smash.m_bits = 0;
  522. if (!CCharacter::WhileDying())
  523. m_state = State_Dead;
  524. else
  525. UpdateFirePosition();
  526. break;
  527. //-----------------------------------------------------------------------
  528. // Dead - paste yourself in the background and delete yourself
  529. //-----------------------------------------------------------------------
  530. case State_Dead:
  531. OnDead();
  532. delete this;
  533. return;
  534. break;
  535. }
  536. m_smash.m_sphere.sphere.X = m_dX;
  537. // Fudge center of sphere as half way up the dude.
  538. // Doesn't work if dude's feet leave the origin.
  539. m_smash.m_sphere.sphere.Y = m_dY + m_sprite.m_sRadius;
  540. m_smash.m_sphere.sphere.Z = m_dZ;
  541. m_smash.m_sphere.sphere.lRadius = m_sprite.m_sRadius;
  542. // Update the smash.
  543. m_pRealm->m_smashatorium.Update(&m_smash);
  544. // Save height for next time
  545. m_sPrevHeight = sHeight;
  546. // Save time for next time
  547. m_lPrevTime = lThisTime;
  548. }
  549. }
  550. ////////////////////////////////////////////////////////////////////////////////
  551. // Render object
  552. ////////////////////////////////////////////////////////////////////////////////
  553. void COstrich::Render(void)
  554. {
  555. // Call base class.
  556. CCharacter::Render();
  557. }
  558. ////////////////////////////////////////////////////////////////////////////////
  559. // Called by editor to init new object at specified position
  560. ////////////////////////////////////////////////////////////////////////////////
  561. short COstrich::EditNew( // Returns 0 if successfull, non-zero otherwise
  562. short sX, // In: New x coord
  563. short sY, // In: New y coord
  564. short sZ) // In: New z coord
  565. {
  566. short sResult = 0;
  567. // Call the base class to place the item.
  568. sResult = CDoofus::EditNew(sX, sY, sZ);
  569. if (sResult == SUCCESS)
  570. {
  571. // Load resources
  572. sResult = GetResources();
  573. if (sResult == SUCCESS)
  574. {
  575. sResult = Init();
  576. }
  577. }
  578. return sResult;
  579. }
  580. ////////////////////////////////////////////////////////////////////////////////
  581. // EditModify - Show dialog box for selecting starting bouy
  582. ////////////////////////////////////////////////////////////////////////////////
  583. short COstrich::EditModify(void)
  584. {
  585. return 0;
  586. }
  587. ////////////////////////////////////////////////////////////////////////////////
  588. // Get all required resources
  589. ////////////////////////////////////////////////////////////////////////////////
  590. short COstrich::GetResources(void) // Returns 0 if successfull, non-zero otherwise
  591. {
  592. short sResult = 0;
  593. sResult = m_animRun.Get(ms_apszRunResNames, RChannel_LoopAtStart | RChannel_LoopAtEnd);
  594. if (sResult == 0)
  595. {
  596. sResult = m_animStand.Get(ms_apszStandResNames, RChannel_LoopAtStart | RChannel_LoopAtEnd);
  597. if (sResult == 0)
  598. {
  599. sResult = m_animWalk.Get(ms_apszWalkResNames, RChannel_LoopAtStart | RChannel_LoopAtEnd);
  600. if (sResult == 0)
  601. {
  602. sResult = m_animShot.Get(ms_apszShotResNames);
  603. if (sResult == 0)
  604. {
  605. sResult = m_animBlownup.Get(ms_apszBlownupResNames);
  606. if (sResult == 0)
  607. {
  608. sResult = m_animHide.Get(ms_apszHideResNames);
  609. if (sResult == 0)
  610. {
  611. sResult = m_animDie.Get(ms_apszDieResNames);
  612. if (sResult == 0)
  613. {
  614. // Add more anim gets here if necessary
  615. }
  616. else
  617. {
  618. TRACE("COstrich::GetResources - Failed to open 3D die animation\n");
  619. }
  620. }
  621. else
  622. {
  623. TRACE("COstrich::GetResources - Failed to open 3D hide animation\n");
  624. }
  625. }
  626. else
  627. {
  628. TRACE("COstrich::GetResources - Failed to open 3D blownup animation\n");
  629. }
  630. }
  631. else
  632. {
  633. TRACE("COstrich::GetResources - Failed to open 3D shot animation\n");
  634. }
  635. }
  636. else
  637. {
  638. TRACE("COstrich::GetResources - Failed to open 3D walk animation\n");
  639. }
  640. }
  641. else
  642. {
  643. TRACE("COstrich::GetResources - Failed to open 3D stand animation\n");
  644. }
  645. }
  646. else
  647. {
  648. TRACE("COstrich::GetResources - Failed to open 3D run animation\n");
  649. }
  650. return sResult;
  651. }
  652. ////////////////////////////////////////////////////////////////////////////////
  653. // Free all resources
  654. ////////////////////////////////////////////////////////////////////////////////
  655. short COstrich::FreeResources(void) // Returns 0 if successfull, non-zero otherwise
  656. {
  657. m_animRun.Release();
  658. m_animStand.Release();
  659. m_animWalk.Release();
  660. m_animShot.Release();
  661. m_animBlownup.Release();
  662. m_animHide.Release();
  663. m_animDie.Release();
  664. return 0;
  665. }
  666. ////////////////////////////////////////////////////////////////////////////////
  667. // ProcessMessages - Similar to the base class version but handles a few more
  668. ////////////////////////////////////////////////////////////////////////////////
  669. void COstrich::ProcessMessages(void)
  670. {
  671. // Check queue of messages.
  672. GameMessage msg;
  673. while (m_MessageQueue.DeQ(&msg) == true)
  674. {
  675. ProcessMessage(&msg);
  676. switch(msg.msg_Generic.eType)
  677. {
  678. case typePanic:
  679. OnPanicMsg(&(msg.msg_Panic));
  680. break;
  681. }
  682. }
  683. }
  684. ////////////////////////////////////////////////////////////////////////////////
  685. // Message handlers
  686. ////////////////////////////////////////////////////////////////////////////////
  687. ////////////////////////////////////////////////////////////////////////////////
  688. // Shot Message
  689. ////////////////////////////////////////////////////////////////////////////////
  690. void COstrich::OnShotMsg(Shot_Message* pMessage)
  691. {
  692. UnlockAchievement(ACHIEVEMENT_FIGHT_AN_OSTRICH);
  693. m_stockpile.m_sHitPoints -= pMessage->sDamage;
  694. if (m_state != State_BlownUp &&
  695. // m_state != State_Shot &&
  696. m_state != State_Die &&
  697. m_state != State_Dead)
  698. {
  699. CCharacter::OnShotMsg(pMessage);
  700. // Restart the animation even if he is shot,
  701. m_lAnimTime = 0;
  702. m_panimCur = &m_animShot;
  703. if (m_state != State_Shot)
  704. {
  705. PlaySample(
  706. g_smidOstrichShot,
  707. SampleMaster::Voices);
  708. m_state = State_Shot;
  709. AlertFlock();
  710. }
  711. }
  712. }
  713. ////////////////////////////////////////////////////////////////////////////////
  714. // Explosion message
  715. ////////////////////////////////////////////////////////////////////////////////
  716. void COstrich::OnExplosionMsg(Explosion_Message* pMessage)
  717. {
  718. if (m_state != State_BlownUp)
  719. {
  720. UnlockAchievement(ACHIEVEMENT_FIGHT_AN_OSTRICH);
  721. CCharacter::OnExplosionMsg(pMessage);
  722. // Explosion kills the guy
  723. m_stockpile.m_sHitPoints = 0;
  724. // m_dExtVertVel = ms_dExplosionVelocity;
  725. m_state = State_BlownUp;
  726. m_lAnimTime = 0;
  727. m_panimCur = &m_animBlownup;
  728. PlaySample(
  729. g_smidOstrichBlownup,
  730. SampleMaster::Voices);
  731. AlertFlock();
  732. }
  733. }
  734. ////////////////////////////////////////////////////////////////////////////////
  735. // Burning message
  736. ////////////////////////////////////////////////////////////////////////////////
  737. void COstrich::OnBurnMsg(Burn_Message* pMessage)
  738. {
  739. UnlockAchievement(ACHIEVEMENT_FIGHT_AN_OSTRICH);
  740. CCharacter::OnBurnMsg(pMessage);
  741. m_stockpile.m_sHitPoints -= MAX(pMessage->sDamage / 4, 1);
  742. if (m_state != State_Burning &&
  743. m_state != State_BlownUp &&
  744. m_state != State_Die &&
  745. m_state != State_Dead)
  746. {
  747. m_state = State_Burning;
  748. m_panimCur = &m_animRun;
  749. m_lAnimTime = 0;
  750. PlaySample(
  751. g_smidOstrichBurning,
  752. SampleMaster::Voices);
  753. AlertFlock();
  754. }
  755. }
  756. ////////////////////////////////////////////////////////////////////////////////
  757. // Panic message
  758. ////////////////////////////////////////////////////////////////////////////////
  759. void COstrich::OnPanicMsg(Panic_Message* pMessage)
  760. {
  761. if (m_state != State_Die &&
  762. m_state != State_Dead &&
  763. m_state != State_BlownUp &&
  764. m_state != State_Shot &&
  765. m_state != State_Burning &&
  766. m_state != State_Panic &&
  767. m_state != State_Hide)
  768. {
  769. m_state = State_Panic;
  770. m_panimCur = &m_animRun;
  771. m_lAnimTime = GetRandom() % m_panimCur->m_psops->TotalTime();
  772. }
  773. }
  774. ////////////////////////////////////////////////////////////////////////////////
  775. // AlertFlock
  776. ////////////////////////////////////////////////////////////////////////////////
  777. void COstrich::AlertFlock(void)
  778. {
  779. // CThing::Things::iterator iNext;
  780. CThing* pThing;
  781. GameMessage msg;
  782. // GameMessage msgStopSound;
  783. // msgStopSound.msg_ObjectDelete.eType = typeObjectDelete;
  784. // msgStopSound.msg_ObjectDelete.sPriority = 0;
  785. msg.msg_Panic.eType = typePanic;
  786. msg.msg_Panic.sPriority = 0;
  787. msg.msg_Panic.sX = (short) m_dX;
  788. msg.msg_Panic.sY = (short) m_dY;
  789. msg.msg_Panic.sZ = (short) m_dZ;
  790. CListNode<CThing>* pNext = m_pRealm->m_everythingHead.m_pnNext;
  791. while (pNext->m_powner != NULL)
  792. {
  793. pThing = pNext->m_powner;
  794. if (pThing->GetClassID() == COstrichID && pThing != this)
  795. SendThingMessage(&msg, pThing);
  796. // else if (pThing->GetClassID() == CSoundThingID)
  797. // SendThingMessage(&msgStopSound, pThing);
  798. pNext = pNext->m_pnNext;
  799. }
  800. }
  801. ////////////////////////////////////////////////////////////////////////////////
  802. // Implements basic one-time functionality for each time State_Dead is
  803. // entered.
  804. ////////////////////////////////////////////////////////////////////////////////
  805. void COstrich::OnDead(void)
  806. {
  807. // Call base class.
  808. CDoofus::OnDead();
  809. }
  810. ////////////////////////////////////////////////////////////////////////////////
  811. // ChangeRandomState - Choose among the 3 normal states, stand, hide or walk
  812. ////////////////////////////////////////////////////////////////////////////////
  813. void COstrich::ChangeRandomState(void)
  814. {
  815. short sMod;
  816. m_lTimer = m_pRealm->m_time.GetGameTime() + ms_lStateChangeTime + GetRandom() % 5000;
  817. sMod = m_lTimer % 3;
  818. m_dRot = rspMod360(m_dRot - 10 + (GetRandom() % 20));
  819. m_sRotDirection = m_lTimer % 2;
  820. switch (sMod)
  821. {
  822. case 0:
  823. m_state = State_Hide;
  824. if (m_panimCur != &m_animHide)
  825. {
  826. m_panimCur = &m_animHide;
  827. m_lAnimTime = 0;
  828. }
  829. break;
  830. case 1:
  831. m_state = State_Stand;
  832. if (m_panimCur != &m_animStand)
  833. {
  834. m_panimCur = &m_animStand;
  835. m_lAnimTime = 0;
  836. }
  837. break;
  838. case 2:
  839. m_state = State_Walk;
  840. if (m_panimCur != &m_animWalk)
  841. {
  842. m_panimCur = &m_animWalk;
  843. m_lAnimTime = 0;
  844. }
  845. break;
  846. default:
  847. break;
  848. }
  849. }
  850. ////////////////////////////////////////////////////////////////////////////////
  851. // EOF
  852. ////////////////////////////////////////////////////////////////////////////////