SndRelay.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  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. // SndRelay.cpp
  19. // Project: Nostril (aka Postal)
  20. //
  21. // History:
  22. // 08/11/97 JMI Stole infrastructure from SoundThing.
  23. //
  24. // 08/11/97 JMI Now verifies that the parent ID is that of a CSoundThing
  25. // before using it. Don't know what would happen otherwise
  26. // but I'm sure it would suck.
  27. //
  28. // 09/27/99 JMI Eliminated boolean performance warnings.
  29. //
  30. //////////////////////////////////////////////////////////////////////////////
  31. //
  32. // This CThing-derived class will relay sound volumes based on
  33. // DistanceToVolume() (i.e., the distance to the ear (usually the local dude))
  34. // to the selected CSoundThing.
  35. //
  36. //////////////////////////////////////////////////////////////////////////////
  37. #define SNDRELAY_CPP
  38. #include "RSPiX.h"
  39. #include "SndRelay.h"
  40. #include "SoundThing.h"
  41. #include "game.h"
  42. // This class has its own GetRandom() to keep it from de-synching the game.
  43. #ifdef GetRandom
  44. #undef GetRandom
  45. #endif
  46. #ifdef GetRand
  47. #undef GetRand
  48. #endif
  49. ////////////////////////////////////////////////////////////////////////////////
  50. // Macros/types/etc.
  51. ////////////////////////////////////////////////////////////////////////////////
  52. #define IMAGE_FILE "soundSatellite.bmp"
  53. #define GUI_FILE_NAME "res/editor/SndRelay.gui"
  54. ////////////////////////////////////////////////////////////////////////////////
  55. // Class statics.
  56. ////////////////////////////////////////////////////////////////////////////////
  57. short CSndRelay::ms_sFileCount = 0; // File count.
  58. ////////////////////////////////////////////////////////////////////////////////
  59. // Load object (should call base class version!)
  60. ////////////////////////////////////////////////////////////////////////////////
  61. short CSndRelay::Load( // Returns 0 if successfull, non-zero otherwise
  62. RFile* pFile, // In: File to load from
  63. bool bEditMode, // In: True for edit mode, false otherwise
  64. short sFileCount, // In: File count (unique per file, never 0)
  65. ULONG ulFileVersion) // In: Version of file format to load.
  66. {
  67. short sResult = CThing::Load(pFile, bEditMode, sFileCount, ulFileVersion);
  68. if (sResult == 0)
  69. {
  70. // If new file . . .
  71. if (sFileCount != ms_sFileCount)
  72. {
  73. ms_sFileCount = sFileCount;
  74. // Do one time stuff.
  75. }
  76. switch (ulFileVersion)
  77. {
  78. default:
  79. case 44:
  80. case 43:
  81. case 42:
  82. case 41:
  83. case 40:
  84. case 39:
  85. case 38:
  86. case 37:
  87. case 36:
  88. case 35:
  89. case 34:
  90. case 33:
  91. case 32:
  92. case 31:
  93. case 30:
  94. case 29:
  95. case 28:
  96. case 27:
  97. case 26:
  98. case 25:
  99. case 24:
  100. case 23:
  101. case 22:
  102. case 21:
  103. case 20:
  104. case 19:
  105. case 18:
  106. case 17:
  107. case 16:
  108. case 15:
  109. case 14:
  110. case 13:
  111. case 12:
  112. case 11:
  113. case 10:
  114. case 9:
  115. case 8:
  116. case 7:
  117. case 6:
  118. case 5:
  119. case 4:
  120. case 3:
  121. case 2:
  122. case 1:
  123. pFile->Read(&m_dX);
  124. pFile->Read(&m_dY);
  125. pFile->Read(&m_dZ);
  126. long lBool;
  127. pFile->Read(&lBool);
  128. m_bInitiallyEnabled = lBool ? true : false;
  129. pFile->Read(&m_idParent);
  130. break;
  131. }
  132. // Make sure there were no file errors or format errors . . .
  133. if (!pFile->Error() && sResult == 0)
  134. {
  135. sResult = Init();
  136. }
  137. else
  138. {
  139. sResult = -1;
  140. TRACE("CSndRelay::Load(): Error reading from file!\n");
  141. }
  142. }
  143. return sResult;
  144. }
  145. ////////////////////////////////////////////////////////////////////////////////
  146. // Save object (should call base class version!)
  147. ////////////////////////////////////////////////////////////////////////////////
  148. short CSndRelay::Save( // Returns 0 if successfull, non-zero otherwise
  149. RFile* pFile, // In: File to save to
  150. short sFileCount) // In: File count (unique per file, never 0)
  151. {
  152. short sResult = CThing::Save(pFile, sFileCount);
  153. if (sResult == 0)
  154. {
  155. pFile->Write(m_dX);
  156. pFile->Write(m_dY);
  157. pFile->Write(m_dZ);
  158. pFile->Write((long)m_bInitiallyEnabled);
  159. pFile->Write(m_idParent);
  160. // Make sure there were no file errors
  161. sResult = pFile->Error();
  162. }
  163. return sResult;
  164. }
  165. ////////////////////////////////////////////////////////////////////////////////
  166. // Startup object
  167. ////////////////////////////////////////////////////////////////////////////////
  168. short CSndRelay::Startup(void) // Returns 0 if successfull, non-zero otherwise
  169. {
  170. return 0;
  171. }
  172. ////////////////////////////////////////////////////////////////////////////////
  173. // Shutdown object
  174. ////////////////////////////////////////////////////////////////////////////////
  175. short CSndRelay::Shutdown(void) // Returns 0 if successfull, non-zero otherwise
  176. {
  177. return 0;
  178. }
  179. ////////////////////////////////////////////////////////////////////////////////
  180. // Suspend object
  181. ////////////////////////////////////////////////////////////////////////////////
  182. void CSndRelay::Suspend(void)
  183. {
  184. m_sSuspend++;
  185. }
  186. ////////////////////////////////////////////////////////////////////////////////
  187. // Resume object
  188. ////////////////////////////////////////////////////////////////////////////////
  189. void CSndRelay::Resume(void)
  190. {
  191. m_sSuspend--;
  192. }
  193. ////////////////////////////////////////////////////////////////////////////////
  194. // Update object
  195. ////////////////////////////////////////////////////////////////////////////////
  196. void CSndRelay::Update(void)
  197. {
  198. if (!m_sSuspend)
  199. {
  200. // If enabled . . .
  201. if (m_bEnabled == true)
  202. {
  203. // Attempt to get ptr to our parent . . .
  204. CSoundThing* pst = NULL; // Safety.
  205. if (m_pRealm->m_idbank.GetThingByID((CThing**)&pst, m_idParent) == 0)
  206. {
  207. // Make sure this is what we think it is . . .
  208. if (pst->GetClassID() == CSoundThingID)
  209. {
  210. // Report volume based on our distance to the ear.
  211. pst->RelayVolume(DistanceToVolume(m_dX, m_dY, m_dZ, pst->m_lVolumeHalfLife) );
  212. }
  213. else
  214. {
  215. TRACE("Update(): ID %hu is not a \"SoundThing\", it is a \"%s\".\n",
  216. pst->GetClassID(),
  217. ms_aClassInfo[pst->GetClassID()].pszClassName);
  218. }
  219. }
  220. }
  221. // Process messages.
  222. ProcessMessages();
  223. switch (m_state)
  224. {
  225. case State_Happy:
  226. break;
  227. case State_Delete:
  228. // Banzai!
  229. delete this;
  230. return ;
  231. }
  232. }
  233. }
  234. ////////////////////////////////////////////////////////////////////////////////
  235. // Render object
  236. ////////////////////////////////////////////////////////////////////////////////
  237. void CSndRelay::Render(void)
  238. {
  239. }
  240. ////////////////////////////////////////////////////////////////////////////////
  241. // Called by editor to init new object at specified position
  242. ////////////////////////////////////////////////////////////////////////////////
  243. short CSndRelay::EditNew( // Returns 0 if successfull, non-zero otherwise
  244. short sX, // In: New x coord
  245. short sY, // In: New y coord
  246. short sZ) // In: New z coord
  247. {
  248. short sResult = 0;
  249. // Use specified position
  250. m_dX = (double)sX;
  251. m_dY = (double)sY;
  252. m_dZ = (double)sZ;
  253. sResult = EditModify();
  254. return sResult;
  255. }
  256. ////////////////////////////////////////////////////////////////////////////////
  257. // Helper function/macro for changing a GUIs text value.
  258. ////////////////////////////////////////////////////////////////////////////////
  259. inline void SetGuiItemVal( // Returns nothing.
  260. RGuiItem* pguiRoot, // In: GUI Root.
  261. long lId, // In: ID of item whose text we'll change.
  262. long lVal) // In: New value.
  263. {
  264. RGuiItem* pgui = pguiRoot->GetItemFromId(lId);
  265. if (pgui)
  266. {
  267. pgui->SetText("%ld", lVal);
  268. pgui->Compose();
  269. }
  270. }
  271. ////////////////////////////////////////////////////////////////////////////////
  272. // Callback from multibtn checkbox.
  273. ////////////////////////////////////////////////////////////////////////////////
  274. static void CheckEnableGuiCall( // Returns nothing.
  275. RGuiItem* pgui_pmb) // In: GUI pointer to the multi button that was
  276. // pressed.
  277. {
  278. ASSERT(pgui_pmb->m_type == RGuiItem::MultiBtn);
  279. RMultiBtn* pmb = (RMultiBtn*)pgui_pmb;
  280. // Show based on value stored in GUI.
  281. short sVisible = pmb->m_ulUserData;
  282. // If unchecked . . .
  283. if (pmb->m_sState == 1)
  284. {
  285. // Opposite show/hide state.
  286. sVisible = !sVisible;
  287. }
  288. RGuiItem* pguiLoopSettingsContainer = pmb->GetParent()->GetItemFromId(pmb->m_ulUserInstance);
  289. if (pguiLoopSettingsContainer)
  290. {
  291. pguiLoopSettingsContainer->SetVisible(sVisible);
  292. }
  293. }
  294. ////////////////////////////////////////////////////////////////////////////////
  295. // Called by editor to modify object
  296. ////////////////////////////////////////////////////////////////////////////////
  297. short CSndRelay::EditModify(void)
  298. {
  299. short sResult = 0;
  300. // Load gui dialog
  301. RGuiItem* pgui = RGuiItem::LoadInstantiate(FullPathVD(GUI_FILE_NAME));
  302. if (pgui != NULL)
  303. {
  304. // Init "ID" edit
  305. REdit* peditParentId = (REdit*)pgui->GetItemFromId(100);
  306. ASSERT(peditParentId != NULL);
  307. ASSERT(peditParentId->m_type == RGuiItem::Edit);
  308. if (m_idParent != CIdBank::IdNil)
  309. {
  310. peditParentId->SetText("%hu", m_idParent);
  311. }
  312. else
  313. {
  314. peditParentId->SetText("");
  315. }
  316. peditParentId->Compose();
  317. // Init "enable" push button
  318. RMultiBtn* pmbEnable = (RMultiBtn*)pgui->GetItemFromId(200);
  319. ASSERT(pmbEnable != NULL);
  320. pmbEnable->m_sState = (m_bInitiallyEnabled == true) ? 2 : 1;
  321. pmbEnable->Compose();
  322. // Run the dialog using this super-duper helper funciton
  323. if (DoGui(pgui) == 1)
  324. {
  325. // Get new values from dialog
  326. m_idParent = (U16)peditParentId->GetVal();
  327. if (m_idParent == 0)
  328. {
  329. m_idParent = CIdBank::IdNil;
  330. }
  331. m_bInitiallyEnabled = (pmbEnable->m_sState == 2) ? true : false;
  332. }
  333. else
  334. {
  335. sResult = 1;
  336. }
  337. // Done with GUI.
  338. delete pgui;
  339. }
  340. else
  341. {
  342. sResult = -1;
  343. }
  344. // If everything's okay, init using new values
  345. if (sResult == 0)
  346. sResult = Init();
  347. return sResult;
  348. }
  349. ////////////////////////////////////////////////////////////////////////////////
  350. // Called by editor to move object to specified position
  351. ////////////////////////////////////////////////////////////////////////////////
  352. short CSndRelay::EditMove( // Returns 0 if successfull, non-zero otherwise
  353. short sX, // In: New x coord
  354. short sY, // In: New y coord
  355. short sZ) // In: New z coord
  356. {
  357. m_dX = (double)sX;
  358. m_dY = (double)sY;
  359. m_dZ = (double)sZ;
  360. return 0;
  361. }
  362. ////////////////////////////////////////////////////////////////////////////////
  363. // Called by editor to get the clickable pos/area of an object in 2D.
  364. // (virtual (Overridden here)).
  365. ////////////////////////////////////////////////////////////////////////////////
  366. void CSndRelay::EditRect( // Returns nothiing.
  367. RRect* prc) // Out: Clickable pos/area of object.
  368. {
  369. Map3Dto2D(
  370. m_dX,
  371. m_dY,
  372. m_dZ,
  373. &(prc->sX),
  374. &(prc->sY) );
  375. prc->sW = 10; // Safety.
  376. prc->sH = 10; // Safety.
  377. if (m_sprite.m_pImage)
  378. {
  379. prc->sW = m_sprite.m_pImage->m_sWidth;
  380. prc->sH = m_sprite.m_pImage->m_sHeight;
  381. }
  382. prc->sX -= prc->sW / 2;
  383. prc->sY -= prc->sH;
  384. }
  385. ////////////////////////////////////////////////////////////////////////////////
  386. // Called by editor to get the hotspot of an object in 2D.
  387. // (virtual (Overridden here)).
  388. ////////////////////////////////////////////////////////////////////////////////
  389. void CSndRelay::EditHotSpot( // Returns nothiing.
  390. short* psX, // Out: X coord of 2D hotspot relative to
  391. // EditRect() pos.
  392. short* psY) // Out: Y coord of 2D hotspot relative to
  393. // EditRect() pos.
  394. {
  395. *psX = 5; // Safety.
  396. *psY = 5; // Safety.
  397. if (m_sprite.m_pImage)
  398. {
  399. *psX = m_sprite.m_pImage->m_sWidth / 2;
  400. *psY = m_sprite.m_pImage->m_sHeight;
  401. }
  402. }
  403. ////////////////////////////////////////////////////////////////////////////////
  404. // Called by editor to update object
  405. ////////////////////////////////////////////////////////////////////////////////
  406. void CSndRelay::EditUpdate(void)
  407. {
  408. }
  409. ////////////////////////////////////////////////////////////////////////////////
  410. // Called by editor to render object
  411. ////////////////////////////////////////////////////////////////////////////////
  412. void CSndRelay::EditRender(void)
  413. {
  414. // Setup simple, non-animating sprite
  415. m_sprite.m_sInFlags = 0;
  416. Map3Dto2D(
  417. m_dX,
  418. m_dY,
  419. m_dZ,
  420. &(m_sprite.m_sX2),
  421. &(m_sprite.m_sY2) );
  422. // Priority is based on bottom edge of sprite
  423. m_sprite.m_sPriority = m_dZ;
  424. // Center on image.
  425. m_sprite.m_sX2 -= m_sprite.m_pImage->m_sWidth / 2;
  426. m_sprite.m_sY2 -= m_sprite.m_pImage->m_sHeight;
  427. m_sprite.m_sLayer = CRealm::GetLayerViaAttrib(m_pRealm->GetLayer((short) m_dX, (short) m_dZ));
  428. // Update sprite in scene
  429. m_pRealm->m_scene.UpdateSprite(&m_sprite);
  430. }
  431. ////////////////////////////////////////////////////////////////////////////////
  432. // Init object
  433. ////////////////////////////////////////////////////////////////////////////////
  434. short CSndRelay::Init(void) // Returns 0 if successfull, non-zero otherwise
  435. {
  436. short sResult = 0;
  437. Kill();
  438. m_bEnabled = m_bInitiallyEnabled;
  439. if (m_sprite.m_pImage == 0)
  440. {
  441. sResult = rspGetResource(&g_resmgrGame, m_pRealm->Make2dResPath(IMAGE_FILE), &m_sprite.m_pImage);
  442. if (sResult == 0)
  443. {
  444. // This is a questionable action on a resource managed item, but it's
  445. // okay if EVERYONE wants it to be an FSPR8.
  446. if (m_sprite.m_pImage->Convert(RImage::FSPR8) != RImage::FSPR8)
  447. {
  448. sResult = -1;
  449. TRACE("CSndRelay::GetResource() - Couldn't convert to FSPR8\n");
  450. }
  451. }
  452. }
  453. return sResult;
  454. }
  455. ////////////////////////////////////////////////////////////////////////////////
  456. // Kill object
  457. ////////////////////////////////////////////////////////////////////////////////
  458. short CSndRelay::Kill(void) // Returns 0 if successfull, non-zero otherwise
  459. {
  460. if (m_sprite.m_pImage != 0)
  461. rspReleaseResource(&g_resmgrGame, &m_sprite.m_pImage);
  462. m_pRealm->m_scene.RemoveSprite(&m_sprite);
  463. return 0;
  464. }
  465. ////////////////////////////////////////////////////////////////////////////////
  466. // Process our message queue.
  467. ////////////////////////////////////////////////////////////////////////////////
  468. void CSndRelay::ProcessMessages(void)
  469. {
  470. // Check queue of messages.
  471. GameMessage msg;
  472. while (m_MessageQueue.DeQ(&msg) == true)
  473. {
  474. switch(msg.msg_Generic.eType)
  475. {
  476. case typeObjectDelete:
  477. m_state = State_Delete;
  478. break;
  479. }
  480. }
  481. }
  482. ////////////////////////////////////////////////////////////////////////////////
  483. // EOF
  484. ////////////////////////////////////////////////////////////////////////////////