band.cpp 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685
  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. // band.cpp
  19. // Project: Postal
  20. //
  21. // This module implements the marching band member.
  22. //
  23. // History:
  24. // 03/04/97 BRH Started this file.
  25. //
  26. // 03/05/97 BRH Implemented the functionality of this class in this
  27. // function and in the base class CCharacter. This uses
  28. // many of the default base class functions for motion, states
  29. // etc. Currently has the logic to follow the parade route
  30. // and simple after Parade mingling. Also reacts to
  31. // shot, fire and explosions. Still need to add panic
  32. // mode and panic message sending.
  33. //
  34. // 03/06/97 BRH Fixed panic message so it won't interrupt dying. Also
  35. // Use AlignToBouy function to set the direction to bouy
  36. // and to periodically readjust the alighment to the bouy.
  37. //
  38. // 03/06/97 JMI Upgraded to current rspMod360 usage.
  39. // Was commented out, but just in case it ever gets re-
  40. // instated.
  41. //
  42. // 03/07/97 BRH Added dialog box to select starting bouy and also
  43. // saves and loads that bouy ID.
  44. //
  45. // 03/13/97 JMI Load now takes a version number.
  46. //
  47. // 03/18/97 JMI Now saves and loads child ID.
  48. // Render() now checks for child item and, if present, updates
  49. // its transform via the band member's rigid body transform.
  50. // EditModify() now allows one to select type of child.
  51. // OnExplosionMsg() now detaches child items.
  52. //
  53. // 03/18/97 JMI Load() was ignoring versions 2 and 3. Fixed.
  54. //
  55. // 03/18/97 JMI OnDead() now drops current child instrument.
  56. //
  57. // 03/18/97 JMI Update() was calling CCharacter::OnDead() bypassing the
  58. // CBand::OnDead() override.
  59. //
  60. // 03/19/97 BRH Added a check to the OnPanicMsg to make sure that the
  61. // bouy chosen exists before getting its position.
  62. //
  63. // 03/27/97 JMI Now you cannot create a CBand when there is no bouy.
  64. //
  65. // 04/10/97 BRH Changed it to work with the new multi layer attribute maps.
  66. //
  67. // 04/16/97 BRH Changed references to the realm's list of CThings to use
  68. // the new non-STL method.
  69. //
  70. // 04/29/97 JMI Now, in Render(), the band guy has safer interaction with
  71. // his child instrument which, also, does not keep him from
  72. // having a weapon, like it did before.
  73. //
  74. // 05/12/97 BRH Added the randomness to the falling down dead state so
  75. // when you kill the marchers they don't all fall the same
  76. // direction.
  77. //
  78. // 05/26/97 BRH Added avoidance of obstacles.
  79. //
  80. // 05/27/97 BRH Fixed problem in Panic where no random bouy was being
  81. // selected.
  82. //
  83. // 05/29/97 JMI Changed instance of REALM_ATTR_FLOOR_MASK to
  84. // REALM_ATTR_NOT_WALKABLE.
  85. //
  86. // 06/03/97 BRH Changed the mingle so they walk around a lot more. Added
  87. // screaming sound effects when they panic so that they aren't
  88. // totally silent as they run around. Also changed the song
  89. // to be played internally rather than using a sound thing
  90. // object.
  91. //
  92. // 06/04/97 JMI Now aborts ms_pBandSongSound, if not NULL, in destructor.
  93. // Also, added ms_bDonePlaying so marchers know when to not
  94. // restart ms_pBandSongSound.
  95. //
  96. // 06/05/97 JMI Changed m_sHitPoints to m_stockpile.m_sHitPoints to
  97. // accommodate new m_stockpile in base class, CThing3d (which
  98. // used to contain the m_sHitPoints).
  99. //
  100. // 06/08/97 JMI Added override for WhileDying() and WhileShot(). In which
  101. // we make sure to drop child items with some random
  102. // rotation velocity and our direction and velocity.
  103. // Also, OnExplosionMsg() now passes the message on to the
  104. // child item immediately after dropping it.
  105. //
  106. // 06/10/97 BRH Added message passing to CDemon for all band members.
  107. //
  108. // 06/16/97 BRH Added more sound effects for the band members.
  109. //
  110. // 06/17/97 JMI Added NULL in call to PlaySample() corresponding to new
  111. // param.
  112. //
  113. // 06/17/97 JMI Converted all occurrences of rand() to GetRand() and
  114. // srand() to SeedRand().
  115. //
  116. // 06/24/97 JMI Added some LOG() calls for the synchronization log
  117. // mechanism.
  118. //
  119. // 06/25/97 JMI Now calls PrepareShadow() in Init() which loads and sets up
  120. // a shadow sprite.
  121. //
  122. // 06/30/97 MJR Replaced SAFE_GUI_REF with new GuiItem.h-defined macro.
  123. //
  124. // 06/30/97 BRH Changed most of the PlaySample calls to PlaySampleThenPurge
  125. // to save memory.
  126. //
  127. // 07/01/97 JMI Replaced GetFloorMapValue() with GetHeightAndNoWalk() call.
  128. //
  129. // 07/01/97 JMI Now passes rigid body transform to DetachChild().
  130. //
  131. // 07/08/97 BRH Renamed some of the bandguy's animations since the
  132. // filenames were too long for the delicate MacOS.
  133. //
  134. // 07/09/97 JMI Removed unused 2D res name macros.
  135. //
  136. // 07/17/97 JMI Changed ms_pBandSongSound to ms_siBandSongInstance.
  137. // Now uses new SampleMaster interface for volume and play
  138. // instance reference.
  139. //
  140. // 07/18/97 JMI Got rid of bogus immitation PlaySample functions.
  141. // Now there is one PlaySample() function. Also, you now
  142. // MUST specify a category and you don't have to specify a
  143. // SoundInstance ptr to specify a volume.
  144. //
  145. // 07/31/97 BRH Changed destination bouy from always being 1 to an editable
  146. // item in the EditModify dialog box.
  147. //
  148. // 08/12/97 JMI Now one band member maintains the volume for the band
  149. // sample.
  150. //
  151. // 08/26/97 BRH Added a few more voices to the list.
  152. //
  153. // 09/03/97 JMI Replaced Good Smash bit with Civilian.
  154. //
  155. // 09/24/97 BRH Band members will not appear for the non US version. This
  156. // needs to be tested with the new project setup once
  157. // the band is moved into the localized projects.
  158. //
  159. // 10/03/97 JMI Now includes CompileOptions.h so it knows what US is when
  160. // comparing to LOCALE.
  161. //
  162. // 10/14/97 JMI Added GetInstanceID() as parameter to LOG() calls.
  163. //
  164. // 09/27/99 JMI Changed to allow band mebmers only in any locale
  165. // satisfying the CompilerOptions macro VIOLENT_LOCALE.
  166. //
  167. ////////////////////////////////////////////////////////////////////////////////
  168. #define BAND_CPP
  169. #include "RSPiX.h"
  170. #include <math.h>
  171. #include "band.h"
  172. #include "SampleMaster.h"
  173. #include "item3d.h"
  174. #include "CompileOptions.h"
  175. ////////////////////////////////////////////////////////////////////////////////
  176. // Macros/types/etc.
  177. ////////////////////////////////////////////////////////////////////////////////
  178. #define BRIGHTNESS_PER_LIGHT_ATTRIBUTE 15
  179. #define NUM_ELEMENTS(a) (sizeof(a) / sizeof(a[0]) )
  180. // Notification message lParm1's.
  181. #define BLOOD_POOL_DONE_NOTIFICATION 1 // Blood pool is done animating.
  182. // Random amount the blood splat can adjust.
  183. #define BLOOD_SPLAT_SWAY 10
  184. // Gets a random between -range / 2 and range / 2.
  185. #define RAND_SWAY(sway) ((GetRand() % sway) - sway / 2)
  186. #define GUI_ID_OK 1
  187. #define BAND_SONG_HALF_LIFE 500
  188. ////////////////////////////////////////////////////////////////////////////////
  189. // Variables/data
  190. ////////////////////////////////////////////////////////////////////////////////
  191. double CBand::ms_dCloseToBouy = 6*6;
  192. double CBand::ms_dMingleBouyDist = 15*15;
  193. double CBand::ms_dExplosionVelocity = 180.0;
  194. double CBand::ms_dMaxMarchVel = 30.0;
  195. double CBand::ms_dMaxRunVel = 80.0;
  196. long CBand::ms_lMingleTime = 400;
  197. short CBand::ms_sStartingHitPoints = 100;
  198. SampleMaster::SoundInstance CBand::ms_siBandSongInstance = 0;
  199. U16 CBand::ms_idBandLeader = CIdBank::IdNil; // The person who adjusts the band sound
  200. // volume or IdNil.
  201. // Let this auto-init to 0
  202. short CBand::ms_sFileCount;
  203. // This value indicates whether the marchers have stopped playing in this level.
  204. bool CBand::ms_bDonePlaying = false;
  205. /// Standing Animation Files
  206. // An array of pointers to resource names (one for each channel of the animation)
  207. static char* ms_apszStandResNames[] =
  208. {
  209. "3d/bandg_stand.sop",
  210. "3d/bandg_stand.mesh",
  211. "3d/bandg_stand.tex",
  212. "3d/bandg_stand.hot",
  213. "3d/bandg_stand.bounds",
  214. "3d/bandg_stand.floor",
  215. "3d/bandg_stand_instrument.trans",
  216. NULL
  217. };
  218. /// Running Animation Files
  219. // An array of pointers to resource names (one for each channel of the animation)
  220. static char* ms_apszRunResNames[] =
  221. {
  222. "3d/bandg_run.sop",
  223. "3d/bandg_run.mesh",
  224. "3d/bandg_run.tex",
  225. "3d/bandg_run.hot",
  226. "3d/bandg_run.bounds",
  227. "3d/bandg_run.floor",
  228. "3d/bandg_run_instrument.trans",
  229. NULL
  230. };
  231. /// Throwing Animation Files
  232. // An array of pointers to resource names (one for each channel of the animation)
  233. static char* ms_apszMarchResNames[] =
  234. {
  235. "3d/bandg_march.sop",
  236. "3d/bandg_march.mesh",
  237. "3d/bandg_march.tex",
  238. "3d/bandg_march.hot",
  239. "3d/bandg_march.bounds",
  240. "3d/bandg_march.floor",
  241. "3d/bandg_march_instrument.trans",
  242. NULL
  243. };
  244. // Shot Animation Files
  245. // An array of pointers to resource names (one for each channel of the animation)
  246. static char* ms_apszShotResNames[] =
  247. {
  248. "3d/bandg_shot.sop",
  249. "3d/bandg_shot.mesh",
  250. "3d/bandg_shot.tex",
  251. "3d/bandg_shot.hot",
  252. "3d/bandg_shot.bounds",
  253. "3d/bandg_shot.floor",
  254. "3d/bandg_shot_instrument.trans",
  255. NULL
  256. };
  257. /// Blown up Animation Files
  258. // An array of pointers to resource names (one for each channel of the animation)
  259. static char* ms_apszBlownupResNames[] =
  260. {
  261. "3d/bandg_blownup.sop",
  262. "3d/bandg_blownup.mesh",
  263. "3d/bandg_blownup.tex",
  264. "3d/bandg_blownup.hot",
  265. "3d/bandg_blownup.bounds",
  266. "3d/bandg_blownup.floor",
  267. "3d/bandg_blownup_instrument.trans",
  268. NULL
  269. };
  270. /// OnFire Animation Files
  271. // An array of pointers to resource names (one for each channel of the animation)
  272. static char* ms_apszOnFireResNames[] =
  273. {
  274. "3d/bandg_onfire.sop",
  275. "3d/bandg_onfire.mesh",
  276. "3d/bandg_onfire.tex",
  277. "3d/bandg_onfire.hot",
  278. "3d/bandg_onfire.bounds",
  279. "3d/bandg_onfire.floor",
  280. "3d/bandg_onfire_instrument.trans",
  281. NULL
  282. };
  283. // These are the points that are checked on the attribute map relative to his origin
  284. static RP3d ms_apt3dAttribCheck[] =
  285. {
  286. {-6, 0, -6},
  287. { 0, 0, -6},
  288. { 6, 0, -6},
  289. {-6, 0, 6},
  290. { 0, 0, 6},
  291. { 6, 0, 6},
  292. };
  293. ////////////////////////////////////////////////////////////////////////////////
  294. // Load object (should call base class version!)
  295. ////////////////////////////////////////////////////////////////////////////////
  296. short CBand::Load( // Returns 0 if successfull, non-zero otherwise
  297. RFile* pFile, // In: File to load from
  298. bool bEditMode, // In: True for edit mode, false otherwise
  299. short sFileCount, // In: File count (unique per file, never 0)
  300. ULONG ulFileVersion) // In: Version of file format to load.
  301. {
  302. short sResult = 0;
  303. // Call the base class load to get the instance ID, position, motion etc.
  304. sResult = CDoofus::Load(pFile, bEditMode, sFileCount, ulFileVersion);
  305. if (sResult == 0)
  306. {
  307. // Load common data just once per file (not with each object)
  308. if (ms_sFileCount != sFileCount)
  309. {
  310. ms_sFileCount = sFileCount;
  311. // Load static data
  312. switch (ulFileVersion)
  313. {
  314. default:
  315. case 1:
  316. break;
  317. }
  318. // Clear this so we know no one has paniced yet.
  319. // Note that, if no band members are loaded (i.e., they are all
  320. // created during play (maybe via a dispenser, although dispensers
  321. // use load) ), this won't get reset.
  322. ms_bDonePlaying = false;
  323. }
  324. // Load Rocket Man specific data
  325. switch (ulFileVersion)
  326. {
  327. default:
  328. case 37:
  329. pFile->Read(&m_ucDestBouyID);
  330. pFile->Read(&m_idChildItem);
  331. pFile->Read(&m_eWeaponType);
  332. pFile->Read(&m_ucNextBouyID);
  333. break;
  334. case 36:
  335. case 35:
  336. case 34:
  337. case 33:
  338. case 32:
  339. case 31:
  340. case 30:
  341. case 29:
  342. case 28:
  343. case 27:
  344. case 26:
  345. case 25:
  346. case 24:
  347. case 23:
  348. case 22:
  349. case 21:
  350. case 20:
  351. case 19:
  352. case 18:
  353. case 17:
  354. case 16:
  355. case 15:
  356. case 14:
  357. case 13:
  358. case 12:
  359. case 11:
  360. case 10:
  361. case 9:
  362. case 8:
  363. case 7:
  364. case 6:
  365. case 5:
  366. case 4:
  367. pFile->Read(&m_idChildItem);
  368. pFile->Read(&m_eWeaponType);
  369. pFile->Read(&m_ucNextBouyID);
  370. break;
  371. case 3:
  372. case 2:
  373. case 1:
  374. pFile->Read(&m_eWeaponType);
  375. pFile->Read(&m_ucNextBouyID);
  376. break;
  377. }
  378. // Make sure there were no file errors or format errors . . .
  379. if (!pFile->Error() && sResult == 0)
  380. {
  381. // Get resources
  382. sResult = GetResources();
  383. }
  384. else
  385. {
  386. sResult = -1;
  387. TRACE("CBand::Load(): Error reading from file!\n");
  388. }
  389. }
  390. else
  391. {
  392. TRACE("CGrenader::Load(): CDoofus::Load() failed.\n");
  393. }
  394. return sResult;
  395. }
  396. ////////////////////////////////////////////////////////////////////////////////
  397. // Save object (should call base class version!)
  398. ////////////////////////////////////////////////////////////////////////////////
  399. short CBand::Save( // Returns 0 if successfull, non-zero otherwise
  400. RFile* pFile, // In: File to save to
  401. short sFileCount) // In: File count (unique per file, never 0)
  402. {
  403. short sResult = SUCCESS;
  404. // Call the base class save to save the instance ID, position etc.
  405. CDoofus::Save(pFile, sFileCount);
  406. // Save common data just once per file (not with each object)
  407. if (ms_sFileCount != sFileCount)
  408. {
  409. ms_sFileCount = sFileCount;
  410. // Save static data
  411. }
  412. // Save band member specific data
  413. pFile->Write(&m_ucDestBouyID);
  414. pFile->Write(&m_idChildItem);
  415. pFile->Write(&m_eWeaponType);
  416. pFile->Write(&m_ucNextBouyID);
  417. if (!pFile->Error())
  418. {
  419. sResult = SUCCESS;
  420. }
  421. else
  422. {
  423. TRACE("CBand::Save() - Error writing to file\n");
  424. sResult = -1;
  425. }
  426. return sResult;
  427. }
  428. ////////////////////////////////////////////////////////////////////////////////
  429. // Init - Call this after the resources are in place
  430. ////////////////////////////////////////////////////////////////////////////////
  431. short CBand::Init(void)
  432. {
  433. short sResult = 0;
  434. // Prepare shadow (get resources and setup sprite).
  435. sResult = PrepareShadow();
  436. // Init position, rotation and velocity
  437. m_dVel = 0.0;
  438. m_dRot = 0.0;
  439. m_lPrevTime = m_pRealm->m_time.GetGameTime();
  440. m_state = CCharacter::State_Idle;
  441. m_lTimer = m_pRealm->m_time.GetGameTime() + 500;
  442. m_sBrightness = 0; // Default brightness
  443. m_smash.m_bits = CSmash::Civilian | CSmash::Character;
  444. m_smash.m_pThing = this;
  445. m_lAnimTime = 0;
  446. m_panimCur = &m_animMarch;
  447. m_stockpile.m_sHitPoints = ms_sStartingHitPoints;
  448. // Set them facing their first bouy so they are lined up ready to march
  449. // m_ucDestBouyID = 1; // This is the end of the parade route bouy
  450. // m_ucNextBouyID = m_pNavNet->FindNearestBouy(m_dX, m_dZ);
  451. m_pNextBouy = m_pNavNet->GetBouy(m_ucNextBouyID);
  452. // ASSERT(m_pNextBouy != NULL);
  453. if (m_pNextBouy != NULL)
  454. {
  455. m_sNextX = m_pNextBouy->GetX();
  456. m_sNextZ = m_pNextBouy->GetZ();
  457. // m_dRot = rspATan(m_dZ - m_sNextZ, m_sNextX - m_dX);
  458. AlignToBouy();
  459. }
  460. else
  461. {
  462. TRACE("Init(): Where's the dang, blam, dangin, blamin, BOUY?!\n");
  463. sResult = -1;
  464. }
  465. m_state = CCharacter::State_March;
  466. m_dAcc = 150;
  467. return sResult;
  468. }
  469. ////////////////////////////////////////////////////////////////////////////////
  470. // Startup object
  471. ////////////////////////////////////////////////////////////////////////////////
  472. short CBand::Startup(void) // Returns 0 if successfull, non-zero otherwise
  473. {
  474. // If not a violent locale . . .
  475. #if !VIOLENT_LOCALE
  476. // We must kill band members in these countries b/c of their lack of tolerance.
  477. delete this;
  478. return 0;
  479. #else
  480. // Set the current height, previous time, and Nav Net by calling the
  481. // base class startup
  482. CDoofus::Startup();
  483. // Init other stuff
  484. return Init();
  485. #endif
  486. }
  487. ////////////////////////////////////////////////////////////////////////////////
  488. // Update object
  489. ////////////////////////////////////////////////////////////////////////////////
  490. void CBand::Update(void)
  491. {
  492. short sHeight = m_sPrevHeight;
  493. double dNewX;
  494. double dNewY;
  495. double dNewZ;
  496. double dX;
  497. double dZ;
  498. double dStartX;
  499. double dStartZ;
  500. long lThisTime;
  501. long lTimeDifference;
  502. CThing* pDemon = NULL;
  503. if (!m_sSuspend)
  504. {
  505. // Get new time
  506. lThisTime = m_pRealm->m_time.GetGameTime();
  507. lTimeDifference = lThisTime - m_lPrevTime;
  508. // Calculate elapsed time in seconds
  509. double dSeconds = (double)(lThisTime - m_lPrevTime) / 1000.0;
  510. // Check for new messages that may change the state
  511. ProcessMessages();
  512. // Increment animation time
  513. m_lAnimTime += lTimeDifference;
  514. // Check the current state
  515. switch (m_state)
  516. {
  517. //-----------------------------------------------------------------------
  518. // March - follow the parade route until you get to the end
  519. //-----------------------------------------------------------------------
  520. case State_March:
  521. // The first guy should start the song, if we are not done playing music . . .
  522. if (ms_siBandSongInstance == 0 && ms_bDonePlaying == false)
  523. {
  524. PlaySample( // Returns nothing.
  525. // Does not fail.
  526. g_smidParadeSong, // In: Identifier of sample you want played.
  527. SampleMaster::Unspecified, // In: Sound Volume Category for user adjustment
  528. 255, // In: Initial Sound Volume (0 - 255)
  529. &ms_siBandSongInstance, // Out: Handle for adjusting sound volume
  530. NULL, // Out: Sample duration in ms, if not NULL.
  531. 0, // In: Where to loop back to in milliseconds.
  532. // -1 indicates no looping (unless m_sLoop is
  533. // explicitly set).
  534. -1, // In: Where to loop back from in milliseconds.
  535. // In: If less than 1, the end + lLoopEndTime is used.
  536. false); // In: Call ReleaseAndPurge rather than Release after playing
  537. // Make this guy the band leader.
  538. ms_idBandLeader = GetInstanceID();
  539. }
  540. // If I am the band leader . . .
  541. if (ms_idBandLeader == GetInstanceID() )
  542. {
  543. // If the band song is running . . .
  544. if (ms_siBandSongInstance != 0)
  545. {
  546. // Adjust the sound volume. This doesn't need to be exact. So
  547. // his previous position will be fine.
  548. SetInstanceVolume(
  549. ms_siBandSongInstance,
  550. DistanceToVolume(m_dX, m_dY, m_dZ, BAND_SONG_HALF_LIFE) );
  551. }
  552. }
  553. // Check distance to target bouy
  554. dX = m_dX - m_sNextX;
  555. dZ = m_dZ - m_sNextZ;
  556. if ((dX*dX + dZ*dZ) < ms_dCloseToBouy)
  557. {
  558. // Set next bouy, x, z, and rotation
  559. m_ucNextBouyID = m_pNextBouy->NextRouteNode(m_ucDestBouyID);
  560. if (m_ucNextBouyID == 0)
  561. {
  562. // Note that we're done playing music.
  563. ms_bDonePlaying = true;
  564. m_lTimer = lThisTime;
  565. m_state = State_Wait;
  566. // At the end of the parade, end the song
  567. if (ms_siBandSongInstance != 0)
  568. {
  569. AbortSample(ms_siBandSongInstance);
  570. ms_siBandSongInstance = 0;
  571. ms_bDonePlaying = true;
  572. }
  573. }
  574. else
  575. {
  576. m_pNextBouy = m_pNavNet->GetBouy(m_ucNextBouyID);
  577. m_sNextX = m_pNextBouy->GetX();
  578. m_sNextZ = m_pNextBouy->GetZ();
  579. // m_dRot = rspATan(m_dZ - m_sNextZ, m_sNextX - m_dX);
  580. AlignToBouy();
  581. }
  582. }
  583. // Move towards the bouy
  584. AlignToBouy();
  585. UpdateVelocities(dSeconds, ms_dMaxMarchVel, ms_dMaxMarchVel);
  586. GetNewPosition(&dNewX, &dNewY, &dNewZ, dSeconds);
  587. if (MakeValidPosition(&dNewX, &dNewY, &dNewZ, 10) == true)
  588. {
  589. // Update Values /////////////////////////////////////////////////////////
  590. m_dX = dNewX;
  591. m_dY = dNewY;
  592. m_dZ = dNewZ;
  593. UpdateFirePosition();
  594. }
  595. else
  596. {
  597. // Restore Values ////////////////////////////////////////////////////////
  598. m_dVel -= m_dDeltaVel;
  599. }
  600. break;
  601. //-----------------------------------------------------------------------
  602. // Wait - stand around for a while
  603. //-----------------------------------------------------------------------
  604. case State_Wait:
  605. // See if its time to go yet
  606. if (lThisTime > m_lTimer)
  607. {
  608. m_state = State_Mingle;
  609. m_ucDestBouyID = SelectRandomBouy();
  610. m_ucNextBouyID = m_pNavNet->FindNearestBouy(m_dX, m_dZ);
  611. m_pNextBouy = m_pNavNet->GetBouy(m_ucNextBouyID);
  612. m_lTimer = lThisTime + ms_lMingleTime;
  613. if (m_ucDestBouyID == 0 || m_pNextBouy == NULL)
  614. {
  615. m_state = State_Wait;
  616. }
  617. else
  618. {
  619. m_ucNextBouyID = m_pNextBouy->NextRouteNode(m_ucDestBouyID);
  620. m_pNextBouy = m_pNavNet->GetBouy(m_ucNextBouyID);
  621. if (m_pNextBouy != NULL)
  622. {
  623. m_sNextX = m_pNextBouy->GetX();
  624. m_sNextZ = m_pNextBouy->GetZ();
  625. // m_dRot = rspATan(m_dZ - m_sNextZ, m_sNextX - m_dX);
  626. AlignToBouy();
  627. m_dAcc = 150;
  628. m_state = State_Mingle;
  629. }
  630. else
  631. m_state = State_Wait;
  632. }
  633. }
  634. break;
  635. //-----------------------------------------------------------------------
  636. // Mingle - Mingle around at the park after the parade
  637. //-----------------------------------------------------------------------
  638. /*
  639. case State_Mingle:
  640. // Check distance to target bouy
  641. dX = m_dX - m_sNextX;
  642. dZ = m_dZ - m_sNextZ;
  643. if ((dX*dX + dZ*dZ) < ms_dMingleBouyDist)
  644. {
  645. m_lTimer = lThisTime + ms_lMingleTime;
  646. m_state = State_Wait;
  647. }
  648. // Move towards the bouy
  649. AlignToBouy();
  650. UpdateVelocities(dSeconds, ms_dMaxMarchVel, ms_dMaxMarchVel);
  651. GetNewPosition(&dNewX, &dNewY, &dNewZ, dSeconds);
  652. if (MakeValidPosition(&dNewX, &dNewY, &dNewZ, 10) == true)
  653. {
  654. // Update Values /////////////////////////////////////////////////////////
  655. m_dX = dNewX;
  656. m_dY = dNewY;
  657. m_dZ = dNewZ;
  658. UpdateFirePosition();
  659. }
  660. else
  661. {
  662. // Restore Values ////////////////////////////////////////////////////////
  663. m_dVel -= m_dDeltaVel;
  664. }
  665. break;
  666. */
  667. //-----------------------------------------------------------------------
  668. // Panic - Pick a random bouy and run to it. When you are there, pick
  669. // a different random bouy and run to it.
  670. //-----------------------------------------------------------------------
  671. case State_Panic:
  672. case State_Mingle:
  673. // Check distance to target bouy
  674. dStartX = m_dX;
  675. dStartZ = m_dZ;
  676. dX = m_dX - m_sNextX;
  677. dZ = m_dZ - m_sNextZ;
  678. // BEGIN TEMP.
  679. LOG(dX, GetInstanceID() );
  680. LOG(dZ, GetInstanceID() );
  681. LOG(m_dX, GetInstanceID() );
  682. LOG(m_dZ, GetInstanceID() );
  683. LOG(m_sNextX, GetInstanceID() );
  684. LOG(m_sNextZ, GetInstanceID() );
  685. // END TEMP.
  686. if ((dX*dX + dZ*dZ) < ms_dCloseToBouy)
  687. {
  688. // Set next bouy, x, z, and rotation
  689. m_ucNextBouyID = m_pNextBouy->NextRouteNode(m_ucDestBouyID);
  690. // BEGIN TEMP.
  691. LOG(m_pNextBouy->m_ucID, GetInstanceID() );
  692. LOG(m_ucDestBouyID, GetInstanceID() );
  693. LOG(m_ucNextBouyID, GetInstanceID() );
  694. // END TEMP.
  695. if (m_ucNextBouyID == 0 || m_ucNextBouyID == 255)
  696. {
  697. if (m_panimCur != &m_animRun)
  698. m_panimCur = &m_animRun;
  699. m_ucDestBouyID = SelectRandomBouy();
  700. m_ucNextBouyID = m_pNextBouy->NextRouteNode(m_ucDestBouyID);
  701. m_sNextX = m_pNextBouy->GetX();
  702. m_sNextZ = m_pNextBouy->GetZ();
  703. AlignToBouy();
  704. // BEGIN TEMP.
  705. LOG(m_ucDestBouyID, GetInstanceID() );
  706. LOG(m_ucNextBouyID, GetInstanceID() );
  707. LOG(m_sNextX, GetInstanceID() );
  708. LOG(m_sNextZ, GetInstanceID() );
  709. // END TEMP.
  710. m_sRotateDir = GetRand() % 2;
  711. if (m_state == State_Mingle)
  712. {
  713. m_state = State_Wait;
  714. m_lTimer = lThisTime + ms_lMingleTime;
  715. }
  716. else
  717. {
  718. short sRandom = GetRand() % 16;
  719. switch (sRandom)
  720. {
  721. case 0:
  722. PlaySample(g_smidSteveAhFire, SampleMaster::Voices);
  723. break;
  724. case 1:
  725. PlaySample(g_smidBlownupFemaleYell, SampleMaster::Voices);
  726. break;
  727. case 2:
  728. PlaySample(g_smidCarynScream, SampleMaster::Voices);
  729. break;
  730. case 3:
  731. PlaySample(g_smidTinaScream1, SampleMaster::Voices);
  732. break;
  733. case 4:
  734. PlaySample(g_smidPaulAhah, SampleMaster::Voices);
  735. break;
  736. case 5:
  737. PlaySample(g_smidTinaOhMyGod, SampleMaster::Voices);
  738. break;
  739. case 6:
  740. PlaySample(g_smidAndreaHesPostal, SampleMaster::Voices);
  741. break;
  742. case 7:
  743. PlaySample(g_smidAndreaHesManiac, SampleMaster::Voices);
  744. break;
  745. case 8:
  746. PlaySample(g_smidCelinaRun, SampleMaster::Voices);
  747. break;
  748. case 9:
  749. PlaySample(g_smidPaulCantFeelLegs, SampleMaster::Voices);
  750. break;
  751. case 10:
  752. PlaySample(g_smidAndreaYell, SampleMaster::Voices);
  753. break;
  754. case 11:
  755. PlaySample(g_smidSteveWaFire, SampleMaster::Voices);
  756. break;
  757. case 12:
  758. PlaySample(g_smidRandyCantFeelLegs, SampleMaster::Voices);
  759. break;
  760. case 13:
  761. PlaySample(g_smidSteveMyEyes, SampleMaster::Voices);
  762. break;
  763. case 14:
  764. PlaySample(g_smidSteveMyLeg, SampleMaster::Voices);
  765. break;
  766. case 15:
  767. PlaySample(g_smidSteveCantSeeAny, SampleMaster::Voices);
  768. break;
  769. }
  770. }
  771. }
  772. else
  773. {
  774. m_pNextBouy = m_pNavNet->GetBouy(m_ucNextBouyID);
  775. if (m_pNextBouy != NULL)
  776. {
  777. m_sNextX = m_pNextBouy->GetX();
  778. m_sNextZ = m_pNextBouy->GetZ();
  779. AlignToBouy();
  780. }
  781. }
  782. }
  783. if (lThisTime > m_lAlignTimer)
  784. AlignToBouy();
  785. // Move towards the bouy
  786. // DeluxeUpdatePosVel();
  787. if (m_state == State_Mingle)
  788. UpdateVelocities(dSeconds, ms_dMaxMarchVel, ms_dMaxMarchVel);
  789. else
  790. UpdateVelocities(dSeconds, ms_dMaxRunVel, ms_dMaxRunVel);
  791. GetNewPosition(&dNewX, &dNewY, &dNewZ, dSeconds);
  792. // Get height and 'no walk' status at new position.
  793. bool bNoWalk;
  794. sHeight = m_pRealm->GetHeightAndNoWalk(dNewX, dNewY, &bNoWalk);
  795. // If too big a height difference or completely not walkable . . .
  796. if (bNoWalk == true
  797. || (sHeight - dNewY > 10) )// && m_bAboveTerrain == false && m_dExtHorzVel == 0.0))
  798. {
  799. m_ucDestBouyID = SelectRandomBouy();
  800. m_ucNextBouyID = m_pNavNet->FindNearestBouy(m_dX, m_dZ);
  801. m_sNextX = m_pNextBouy->GetX();
  802. m_sNextZ = m_pNextBouy->GetZ();
  803. m_lAlignTimer = lThisTime + 3000;
  804. AlignToBouy();
  805. }
  806. if (MakeValidPosition(&dNewX, &dNewY, &dNewZ, 10) == true)
  807. {
  808. // Update Values /////////////////////////////////////////////////////////
  809. m_dX = dNewX;
  810. m_dY = dNewY;
  811. m_dZ = dNewZ;
  812. UpdateFirePosition();
  813. }
  814. else
  815. {
  816. // Restore Values ////////////////////////////////////////////////////////
  817. m_dVel -= m_dDeltaVel;
  818. m_ucDestBouyID = SelectRandomBouy();
  819. m_ucNextBouyID = m_pNavNet->FindNearestBouy(m_dX, m_dZ);
  820. m_sNextX = m_pNextBouy->GetX();
  821. m_sNextZ = m_pNextBouy->GetZ();
  822. m_lAlignTimer = lThisTime + 3000;
  823. m_dRot = rspMod360(m_dRot + 20);
  824. }
  825. // If not moving when you are trying to, rotate
  826. if (m_dX == dStartX && m_dZ == dStartZ)
  827. {
  828. if (m_sRotateDir)
  829. m_dAnimRot = m_dRot = rspMod360(m_dRot + 20);
  830. else
  831. m_dAnimRot = m_dRot = rspMod360(m_dRot - 20);
  832. }
  833. else
  834. {
  835. m_sRotateDir = GetRand() % 2;
  836. }
  837. break;
  838. //-----------------------------------------------------------------------
  839. // Burning - Run around on fire until dead
  840. //-----------------------------------------------------------------------
  841. case State_Burning:
  842. if (!WhileBurning())
  843. {
  844. m_state = State_Die;
  845. m_lAnimTime = 0;
  846. m_panimCur = &m_animShot;
  847. // Fall down in a more random direction.
  848. m_dRot = rspMod360(m_dRot - 90 + (GetRand() % 180));
  849. }
  850. break;
  851. //-----------------------------------------------------------------------
  852. // Blown Up - Do motion into the air until you hit the ground again
  853. //-----------------------------------------------------------------------
  854. case State_BlownUp:
  855. if (!WhileBlownUp())
  856. m_state = State_Dead;
  857. else
  858. UpdateFirePosition();
  859. break;
  860. //-----------------------------------------------------------------------
  861. // Shot - Dies in one shot
  862. //-----------------------------------------------------------------------
  863. case State_Shot:
  864. if (!WhileShot())
  865. {
  866. m_state = State_Die;
  867. m_dRot = rspMod360(m_dRot - 90 + (GetRand() % 180));
  868. }
  869. break;
  870. //-----------------------------------------------------------------------
  871. // Die - run die animation until done, the you are dead
  872. //-----------------------------------------------------------------------
  873. case State_Die:
  874. if (!WhileDying())
  875. m_state = State_Dead;
  876. else
  877. UpdateFirePosition();
  878. break;
  879. //-----------------------------------------------------------------------
  880. // Dead - paste yourself in the background and delete yourself
  881. //-----------------------------------------------------------------------
  882. case State_Dead:
  883. GameMessage msg;
  884. msg.msg_Death.eType = typeDeath;
  885. msg.msg_Death.sPriority = 0;
  886. pDemon = m_pRealm->m_aclassHeads[CThing::CDemonID].GetNext();
  887. if (pDemon)
  888. SendThingMessage(&msg, pDemon);
  889. OnDead();
  890. delete this;
  891. return;
  892. break;
  893. }
  894. m_smash.m_sphere.sphere.X = m_dX;
  895. // Fudge center of sphere as half way up the dude.
  896. // Doesn't work if dude's feet leave the origin.
  897. m_smash.m_sphere.sphere.Y = m_dY + m_sprite.m_sRadius;
  898. m_smash.m_sphere.sphere.Z = m_dZ;
  899. m_smash.m_sphere.sphere.lRadius = m_sprite.m_sRadius;
  900. // Update the smash.
  901. m_pRealm->m_smashatorium.Update(&m_smash);
  902. // Save height for next time
  903. m_sPrevHeight = sHeight;
  904. // Save time for next time
  905. m_lPrevTime = lThisTime;
  906. }
  907. }
  908. ////////////////////////////////////////////////////////////////////////////////
  909. // Render object
  910. ////////////////////////////////////////////////////////////////////////////////
  911. void CBand::Render(void)
  912. {
  913. // Call base class.
  914. CDoofus::Render();
  915. // Update child, if any . . .
  916. if (m_idChildItem != CIdBank::IdNil)
  917. {
  918. CItem3d* pitem;
  919. if (m_pRealm->m_idbank.GetThingByID((CThing**)&pitem, m_idChildItem) == 0)
  920. {
  921. // Set transform from our rigid body transfanimation for the child
  922. // sprite.
  923. pitem->m_sprite.m_ptrans = (RTransform*) m_panimCur->m_ptransRigid->GetAtTime(m_lAnimTime);
  924. // If the item is not our child . . .
  925. if (pitem->m_sprite.m_psprParent != &m_sprite)
  926. {
  927. // Make it so.
  928. m_sprite.AddChild( &(pitem->m_sprite) );
  929. }
  930. }
  931. else // Safety:
  932. {
  933. // Item is gone.
  934. m_idChildItem = CIdBank::IdNil;
  935. }
  936. }
  937. }
  938. ////////////////////////////////////////////////////////////////////////////////
  939. // Called by editor to init new object at specified position
  940. ////////////////////////////////////////////////////////////////////////////////
  941. short CBand::EditNew( // Returns 0 if successfull, non-zero otherwise
  942. short sX, // In: New x coord
  943. short sY, // In: New y coord
  944. short sZ) // In: New z coord
  945. {
  946. short sResult = 0;
  947. // Call the base class to place the item.
  948. sResult = CDoofus::EditNew(sX, sY, sZ);
  949. if (sResult == SUCCESS)
  950. {
  951. // Load resources
  952. sResult = GetResources();
  953. if (sResult == SUCCESS)
  954. {
  955. sResult = Init();
  956. }
  957. }
  958. return sResult;
  959. }
  960. ////////////////////////////////////////////////////////////////////////////////
  961. // EditModify - Show dialog box for selecting starting bouy
  962. ////////////////////////////////////////////////////////////////////////////////
  963. short CBand::EditModify(void)
  964. {
  965. short sResult = 0;
  966. RGuiItem* pGui = RGuiItem::LoadInstantiate(FullPathVD("res/editor/band.gui"));
  967. if (pGui)
  968. {
  969. RGuiItem* pguiStartBouy = pGui->GetItemFromId(10);
  970. RGuiItem* pguiDestBouy = pGui->GetItemFromId(11);
  971. if (pguiStartBouy)
  972. {
  973. RSP_SAFE_GUI_REF_VOID(pguiStartBouy, SetText("%d", m_ucNextBouyID));
  974. RSP_SAFE_GUI_REF((REdit*) pguiStartBouy, m_sCaretPos = strlen(pguiStartBouy->m_szText));
  975. RSP_SAFE_GUI_REF_VOID(pguiStartBouy, Compose());
  976. RSP_SAFE_GUI_REF_VOID(pguiDestBouy, SetText("%d", m_ucDestBouyID));
  977. RSP_SAFE_GUI_REF((REdit*) pguiDestBouy, m_sCaretPos = strlen(pguiDestBouy->m_szText));
  978. RSP_SAFE_GUI_REF_VOID(pguiDestBouy, Compose());
  979. CItem3d::ItemType itChild = CItem3d::None;
  980. // If there's currently a child . . .
  981. CItem3d* pitem = NULL;
  982. if (m_pRealm->m_idbank.GetThingByID((CThing**)&pitem, m_idChildItem) == 0)
  983. {
  984. // Get the type.
  985. itChild = pitem->m_type;
  986. }
  987. RListBox* plbChildTypes = (RListBox*)pGui->GetItemFromId(3);
  988. if (plbChildTypes != NULL)
  989. {
  990. ASSERT(plbChildTypes->m_type == RGuiItem::ListBox);
  991. // Add all built-in 3D Item types.
  992. short i;
  993. RGuiItem* pguiItem;
  994. for (i = CItem3d::None; i < CItem3d::NumTypes; i++)
  995. {
  996. // Don't allow Custom . . .
  997. if (i != CItem3d::Custom)
  998. {
  999. pguiItem = plbChildTypes->AddString(CItem3d::ms_apszKnownAnimDescriptions[i]);
  1000. if (pguiItem != NULL)
  1001. {
  1002. // Set item number.
  1003. pguiItem->m_ulUserData = i;
  1004. // If this item is the current item type . . .
  1005. if (i == itChild)
  1006. {
  1007. plbChildTypes->SetSel(pguiItem);
  1008. }
  1009. }
  1010. }
  1011. }
  1012. plbChildTypes->AdjustContents();
  1013. }
  1014. if (DoGui(pGui) == GUI_ID_OK)
  1015. {
  1016. m_ucNextBouyID = RSP_SAFE_GUI_REF(pguiStartBouy, GetVal());
  1017. m_ucDestBouyID = RSP_SAFE_GUI_REF(pguiDestBouy, GetVal());
  1018. if (plbChildTypes != NULL)
  1019. {
  1020. RGuiItem* pguiSel = plbChildTypes->GetSel();
  1021. if (pguiSel != NULL)
  1022. {
  1023. itChild = (CItem3d::ItemType)pguiSel->m_ulUserData;
  1024. }
  1025. else
  1026. {
  1027. // None.
  1028. itChild = CItem3d::None;
  1029. }
  1030. if (pitem != NULL)
  1031. {
  1032. // If it is not of the new type . . .
  1033. if (pitem->m_type != itChild)
  1034. {
  1035. // Disable item.
  1036. DetachChild(
  1037. &m_idChildItem,
  1038. (RTransform*) m_panimCur->m_ptransRigid->GetAtTime(m_lAnimTime) );
  1039. // Be gone.
  1040. delete pitem;
  1041. pitem = NULL;
  1042. }
  1043. }
  1044. // If there is no child item . . .
  1045. if (pitem == NULL)
  1046. {
  1047. // If a child is desired . . .
  1048. if (itChild != CItem3d::None)
  1049. {
  1050. // Have one.
  1051. if (ConstructWithID(CItem3dID, m_pRealm, (CThing**)&pitem) == 0)
  1052. {
  1053. // Remember who our child is.
  1054. m_idChildItem = pitem->GetInstanceID();
  1055. // Setup the child.
  1056. pitem->Setup(0, 0, 0, itChild, NULL, m_u16InstanceId);
  1057. }
  1058. else
  1059. {
  1060. TRACE("EditModify(): ConstructWithID failed for CItem3d.\n");
  1061. }
  1062. }
  1063. }
  1064. }
  1065. }
  1066. else
  1067. {
  1068. // User Abort
  1069. sResult = 1;
  1070. }
  1071. }
  1072. }
  1073. delete pGui;
  1074. return sResult;
  1075. }
  1076. ////////////////////////////////////////////////////////////////////////////////
  1077. // Get all required resources
  1078. ////////////////////////////////////////////////////////////////////////////////
  1079. short CBand::GetResources(void) // Returns 0 if successfull, non-zero otherwise
  1080. {
  1081. short sResult = 0;
  1082. sResult = m_animRun.Get(ms_apszRunResNames, RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1083. if (sResult == 0)
  1084. {
  1085. sResult = m_animStand.Get(ms_apszStandResNames, RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1086. if (sResult == 0)
  1087. {
  1088. sResult = m_animMarch.Get(ms_apszMarchResNames, RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1089. if (sResult == 0)
  1090. {
  1091. sResult = m_animShot.Get(ms_apszShotResNames);
  1092. if (sResult == 0)
  1093. {
  1094. sResult = m_animBlownup.Get(ms_apszBlownupResNames);
  1095. if (sResult == 0)
  1096. {
  1097. sResult = m_animOnFire.Get(ms_apszOnFireResNames, RChannel_LoopAtStart | RChannel_LoopAtEnd);
  1098. if (sResult == 0)
  1099. {
  1100. // Add more anim gets here if necessary
  1101. }
  1102. else
  1103. {
  1104. TRACE("CBand::GetResources - Failed to open 3D on fire animation\n");
  1105. }
  1106. }
  1107. else
  1108. {
  1109. TRACE("CBand::GetResources - Failed to open 3D blownup animation\n");
  1110. }
  1111. }
  1112. else
  1113. {
  1114. TRACE("CBand::GetResources - Failed to open 3D shot animation\n");
  1115. }
  1116. }
  1117. else
  1118. {
  1119. TRACE("CBand::GetResources - Failed to open 3D march animation\n");
  1120. }
  1121. }
  1122. else
  1123. {
  1124. TRACE("CBand::GetResources - Failed to open 3D stand animation\n");
  1125. }
  1126. }
  1127. else
  1128. {
  1129. TRACE("CBand::GetResources - Failed to open 3D run animation\n");
  1130. }
  1131. return sResult;
  1132. }
  1133. ////////////////////////////////////////////////////////////////////////////////
  1134. // Free all resources
  1135. ////////////////////////////////////////////////////////////////////////////////
  1136. short CBand::FreeResources(void) // Returns 0 if successfull, non-zero otherwise
  1137. {
  1138. m_animRun.Release();
  1139. m_animStand.Release();
  1140. m_animMarch.Release();
  1141. m_animShot.Release();
  1142. m_animBlownup.Release();
  1143. m_animOnFire.Release();
  1144. return 0;
  1145. }
  1146. ////////////////////////////////////////////////////////////////////////////////
  1147. // ProcessMessages - Similar to the base class version but handles a few more
  1148. ////////////////////////////////////////////////////////////////////////////////
  1149. void CBand::ProcessMessages(void)
  1150. {
  1151. // Check queue of messages.
  1152. GameMessage msg;
  1153. while (m_MessageQueue.DeQ(&msg) == true)
  1154. {
  1155. ProcessMessage(&msg);
  1156. switch(msg.msg_Generic.eType)
  1157. {
  1158. case typePanic:
  1159. OnPanicMsg(&(msg.msg_Panic));
  1160. break;
  1161. }
  1162. }
  1163. }
  1164. ////////////////////////////////////////////////////////////////////////////////
  1165. // Message handlers
  1166. ////////////////////////////////////////////////////////////////////////////////
  1167. ////////////////////////////////////////////////////////////////////////////////
  1168. // Shot Message
  1169. ////////////////////////////////////////////////////////////////////////////////
  1170. void CBand::OnShotMsg(Shot_Message* pMessage)
  1171. {
  1172. if (m_state != State_BlownUp &&
  1173. m_state != State_Shot &&
  1174. m_state != State_Die &&
  1175. m_state != State_Dead)
  1176. {
  1177. CCharacter::OnShotMsg(pMessage);
  1178. // Start shot animation if he hasn't already.
  1179. m_lAnimTime = 0;
  1180. m_panimCur = &m_animShot;
  1181. switch (GetRand() % 8)
  1182. {
  1183. case 0:
  1184. PlaySample(g_smidAmyMyEyes, SampleMaster::Voices);
  1185. break;
  1186. case 1:
  1187. PlaySample(g_smidAndreaMyLeg, SampleMaster::Voices);
  1188. break;
  1189. case 2:
  1190. PlaySample(g_smidBillGrunt, SampleMaster::Voices);
  1191. break;
  1192. case 3:
  1193. PlaySample(g_smidMikeGrunt, SampleMaster::Voices);
  1194. break;
  1195. case 4:
  1196. PlaySample(g_smidPaulCantFeelLegs, SampleMaster::Voices);
  1197. break;
  1198. case 5:
  1199. PlaySample(g_smidRandyHuu, SampleMaster::Voices);
  1200. break;
  1201. case 6:
  1202. PlaySample(g_smidRandyUg, SampleMaster::Voices);
  1203. break;
  1204. case 7:
  1205. PlaySample(g_smidSteveUrl, SampleMaster::Voices);
  1206. break;
  1207. }
  1208. m_state = State_Shot;
  1209. // Dies in one shot
  1210. m_stockpile.m_sHitPoints =0;
  1211. AlertBand();
  1212. }
  1213. }
  1214. ////////////////////////////////////////////////////////////////////////////////
  1215. // Explosion message
  1216. ////////////////////////////////////////////////////////////////////////////////
  1217. void CBand::OnExplosionMsg(Explosion_Message* pMessage)
  1218. {
  1219. if (m_state != State_BlownUp)
  1220. {
  1221. CCharacter::OnExplosionMsg(pMessage);
  1222. // Drop item, if we have one still.
  1223. CThing3d* pthing3d = DetachChild(
  1224. &m_idChildItem,
  1225. (RTransform*) m_panimCur->m_ptransRigid->GetAtTime(m_lAnimTime) );
  1226. // If we got something back . . .
  1227. if (pthing3d != NULL)
  1228. {
  1229. // Let it know about the explosion.
  1230. GameMessage msg;
  1231. msg.msg_Explosion = *pMessage;
  1232. SendThingMessage(&msg, pthing3d);
  1233. }
  1234. // Explosion kills the guy
  1235. m_stockpile.m_sHitPoints = 0;
  1236. m_state = State_BlownUp;
  1237. m_lAnimTime = 0;
  1238. m_panimCur = &m_animBlownup;
  1239. switch (GetRand() % 8)
  1240. {
  1241. case 0:
  1242. PlaySample(g_smidBlownupFemaleYell, SampleMaster::Voices);
  1243. break;
  1244. case 1:
  1245. PlaySample(g_smidCarynScream, SampleMaster::Voices);
  1246. break;
  1247. case 2:
  1248. PlaySample(g_smidTinaScream1, SampleMaster::Voices);
  1249. break;
  1250. case 3:
  1251. PlaySample(g_smidPaulAhah, SampleMaster::Voices);
  1252. break;
  1253. case 4:
  1254. PlaySample(g_smidScottYell1, SampleMaster::Voices);
  1255. break;
  1256. case 5:
  1257. PlaySample(g_smidScottYell2, SampleMaster::Voices);
  1258. break;
  1259. case 6:
  1260. PlaySample(g_smidMikeOhh, SampleMaster::Voices);
  1261. break;
  1262. case 7:
  1263. PlaySample(g_smidSteveAhBlowup, SampleMaster::Voices);
  1264. break;
  1265. }
  1266. AlertBand();
  1267. GameMessage msg;
  1268. msg.msg_Explosion.eType = typeExplosion;
  1269. msg.msg_Explosion.sPriority = 0;
  1270. CThing* pDemon = m_pRealm->m_aclassHeads[CThing::CDemonID].GetNext();
  1271. if (pDemon)
  1272. SendThingMessage(&msg, pDemon);
  1273. }
  1274. }
  1275. ////////////////////////////////////////////////////////////////////////////////
  1276. // Burning message
  1277. ////////////////////////////////////////////////////////////////////////////////
  1278. void CBand::OnBurnMsg(Burn_Message* pMessage)
  1279. {
  1280. UnlockAchievement(ACHIEVEMENT_FIREBOMB_THE_BAND);
  1281. CCharacter::OnBurnMsg(pMessage);
  1282. m_stockpile.m_sHitPoints -= pMessage->sDamage;
  1283. if (m_state != State_Burning &&
  1284. m_state != State_BlownUp &&
  1285. m_state != State_Die &&
  1286. m_state != State_Dead)
  1287. {
  1288. m_state = State_Burning;
  1289. m_panimCur = &m_animOnFire;
  1290. m_lAnimTime = 0;
  1291. switch (GetRand() % 8)
  1292. {
  1293. case 0:
  1294. PlaySample(g_smidAmyScream, SampleMaster::Voices);
  1295. break;
  1296. case 1:
  1297. PlaySample(g_smidTinaScream2, SampleMaster::Voices);
  1298. break;
  1299. case 2:
  1300. PlaySample(g_smidTinaScream3, SampleMaster::Voices);
  1301. break;
  1302. case 3:
  1303. PlaySample(g_smidMikeAhh, SampleMaster::Voices);
  1304. break;
  1305. case 4:
  1306. PlaySample(g_smidSteveAhFire, SampleMaster::Voices);
  1307. break;
  1308. case 5:
  1309. PlaySample(g_smidSteveWaFire, SampleMaster::Voices);
  1310. break;
  1311. case 6:
  1312. PlaySample(g_smidAndreaHelp, SampleMaster::Voices);
  1313. break;
  1314. case 7:
  1315. PlaySample(g_smidCarynScream, SampleMaster::Voices);
  1316. break;
  1317. }
  1318. AlertBand();
  1319. GameMessage msg;
  1320. msg.msg_Burn.eType = typeBurn;
  1321. msg.msg_Burn.sPriority = 0;
  1322. CThing* pDemon = m_pRealm->m_aclassHeads[CThing::CDemonID].GetNext();
  1323. if (pDemon)
  1324. SendThingMessage(&msg, pDemon);
  1325. }
  1326. }
  1327. ////////////////////////////////////////////////////////////////////////////////
  1328. // Panic message
  1329. ////////////////////////////////////////////////////////////////////////////////
  1330. void CBand::OnPanicMsg(Panic_Message* pMessage)
  1331. {
  1332. if (m_state != State_Die &&
  1333. m_state != State_Dead &&
  1334. m_state != State_BlownUp &&
  1335. m_state != State_Shot &&
  1336. m_state != State_Burning &&
  1337. m_state != State_Panic)
  1338. {
  1339. m_state = State_Panic;
  1340. m_panimCur = &m_animOnFire;
  1341. m_lAnimTime = GetRand() % m_panimCur->m_psops->TotalTime();
  1342. // Pick a random bouy to run to
  1343. m_ucDestBouyID = SelectRandomBouy();
  1344. m_ucNextBouyID = m_pNavNet->FindNearestBouy(m_dX, m_dZ);
  1345. m_pNextBouy = m_pNavNet->GetBouy(m_ucNextBouyID);
  1346. if (m_pNextBouy)
  1347. {
  1348. m_sNextX = m_pNextBouy->GetX();
  1349. m_sNextZ = m_pNextBouy->GetZ();
  1350. AlignToBouy();
  1351. }
  1352. short sRandom = GetRand() % 6;
  1353. switch (sRandom)
  1354. {
  1355. case 0:
  1356. PlaySample(g_smidScottYell1, SampleMaster::Voices);
  1357. break;
  1358. case 1:
  1359. PlaySample(g_smidBlownupFemaleYell, SampleMaster::Voices);
  1360. break;
  1361. case 2:
  1362. PlaySample(g_smidTinaScream1, SampleMaster::Voices);
  1363. break;
  1364. default:
  1365. break;
  1366. }
  1367. }
  1368. }
  1369. ////////////////////////////////////////////////////////////////////////////////
  1370. // AlertBand
  1371. ////////////////////////////////////////////////////////////////////////////////
  1372. void CBand::AlertBand(void)
  1373. {
  1374. CThing* pThing;
  1375. GameMessage msg;
  1376. GameMessage msgStopSound;
  1377. msgStopSound.msg_ObjectDelete.eType = typeObjectDelete;
  1378. msgStopSound.msg_ObjectDelete.sPriority = 0;
  1379. msg.msg_Panic.eType = typePanic;
  1380. msg.msg_Panic.sPriority = 0;
  1381. msg.msg_Panic.sX = (short) m_dX;
  1382. msg.msg_Panic.sY = (short) m_dY;
  1383. msg.msg_Panic.sZ = (short) m_dZ;
  1384. CListNode<CThing>* pNext = m_pRealm->m_aclassHeads[CThing::CBandID].m_pnNext;
  1385. while (pNext->m_powner != NULL)
  1386. {
  1387. pThing = pNext->m_powner;
  1388. if (pThing != this)
  1389. SendThingMessage(&msg, pThing);
  1390. pNext = pNext->m_pnNext;
  1391. }
  1392. if (ms_siBandSongInstance != 0)
  1393. {
  1394. AbortSample(ms_siBandSongInstance);
  1395. ms_siBandSongInstance = 0;
  1396. ms_bDonePlaying = true;
  1397. }
  1398. }
  1399. ////////////////////////////////////////////////////////////////////////////////
  1400. // Implements basic one-time functionality for each time State_Dead is
  1401. // entered.
  1402. ////////////////////////////////////////////////////////////////////////////////
  1403. void CBand::OnDead(void)
  1404. {
  1405. // Drop item. This does nothing if we've already dropped it.
  1406. DropItem();
  1407. // Call base class.
  1408. CDoofus::OnDead();
  1409. }
  1410. ////////////////////////////////////////////////////////////////////////////////
  1411. // Implements basic functionality while dying and returns true
  1412. // until the state is completed.
  1413. // (virtual -- Overriden here)
  1414. ////////////////////////////////////////////////////////////////////////////////
  1415. bool CBand::WhileDying(void) // Returns true until state is complete.
  1416. {
  1417. // Drop item. This does nothing if we've already dropped it.
  1418. DropItem();
  1419. // Call base class.
  1420. return CDoofus::WhileDying();
  1421. }
  1422. ////////////////////////////////////////////////////////////////////////////////
  1423. // Implements basic functionality while being shot and returns true
  1424. // until the state is completed.
  1425. // (virtual -- Overriden here)
  1426. ////////////////////////////////////////////////////////////////////////////////
  1427. bool CBand::WhileShot(void) // Returns true until state is complete.
  1428. {
  1429. // Drop item. This does nothing if we've already dropped it.
  1430. DropItem();
  1431. // Call base class.
  1432. return CDoofus::WhileShot();
  1433. }
  1434. ////////////////////////////////////////////////////////////////////////////////
  1435. // Drop item and apply appropriate forces.
  1436. ////////////////////////////////////////////////////////////////////////////////
  1437. void CBand::DropItem(void) // Returns nothing.
  1438. {
  1439. // If we still have the child item . . .
  1440. if (m_idChildItem != CIdBank::IdNil)
  1441. {
  1442. // Drop it.
  1443. CThing3d* pthing3d = DetachChild(
  1444. &m_idChildItem,
  1445. (RTransform*) m_panimCur->m_ptransRigid->GetAtTime(m_lAnimTime) );
  1446. // If we got something back . . .
  1447. if (pthing3d != NULL)
  1448. {
  1449. // Send it spinning.
  1450. pthing3d->m_dExtRotVelY = GetRand() % 720;
  1451. pthing3d->m_dExtRotVelZ = GetRand() % 720;
  1452. // Send it forward (from our perspective)
  1453. // with our current velocity.
  1454. pthing3d->m_dExtHorzRot = m_dRot;
  1455. pthing3d->m_dExtHorzVel = m_dVel;
  1456. // ... and air drag.
  1457. if (pthing3d->m_dExtHorzVel > 0.0)
  1458. {
  1459. pthing3d->m_dExtHorzDrag = -ms_dDefaultAirDrag;
  1460. }
  1461. else if (pthing3d->m_dExtHorzVel < 0.0)
  1462. {
  1463. pthing3d->m_dExtHorzDrag = ms_dDefaultAirDrag;
  1464. }
  1465. // Similar enough to blown up.
  1466. pthing3d->m_state = State_BlownUp;
  1467. }
  1468. }
  1469. }
  1470. ////////////////////////////////////////////////////////////////////////////////
  1471. // EOF
  1472. ////////////////////////////////////////////////////////////////////////////////