toolbar.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  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. // toolbar.cpp
  19. // Project: Nostril (aka Postal)
  20. //
  21. // This module augments the CDude class, which used to be soley responsible for
  22. // updating player and weapon status. It currently graphically manages the
  23. // toolbars and sound reactions. (Still need to add sounds)
  24. ////////////////////////////////////////////////////////////////////////////////
  25. //
  26. // History:
  27. //
  28. // 08/06/97 JRD Started. Set bars to load in the realm
  29. //
  30. // 08/08/97 JRD Changed methodology to a proprietary data format and abandoning
  31. // attempts of a one to one interface with postal. Tollbar will
  32. // update an internal map of the weapon states based on events
  33. // passed.
  34. //
  35. // 08/08/97 JRD Completely revamped and finalized the class structure.
  36. // Added the first hook to draw the entire bar.
  37. // Added aliased functions to reduce header dependencies.
  38. // 08/09/97 JRD Added all functionality except a hook to refresh on event.
  39. //
  40. // 08/10/97 JRD Added two deferred update modes. One limits updates to a
  41. // given time interval, and the other only updates when a
  42. // change of value or state has occurred. All this occurs
  43. // without any interaction with the app.
  44. //
  45. // 08/10/97 JRD Added hook so powerup values resetting due to time would
  46. // be a valid draw event.
  47. //
  48. // 08/10/97 JRD Based on Steve Wik's opinion, I set health and vest to
  49. // show well over 100%. Since people liked it, it was actually
  50. // my opinion and I shall keep it.
  51. //
  52. // 08/10/97 JRD Added a dangerous cross file help to poor old score in order
  53. // to easily color map the top toolbar. Poor score. Set to Steve
  54. // colors. If you think their cool, then I too agreed with Steve.
  55. // If not, then Steve forced me to use them.
  56. //
  57. // 08/12/97 JRD Changed the class o the Mac can deal with it.
  58. //
  59. // 08/29/97 JRD Patched Render to not display amount of bullets.
  60. //
  61. // 09/27/99 JMI Eliminated boolean performance warnings.
  62. //
  63. ////////////////////////////////////////////////////////////////////////////////
  64. #include "RSPiX.h"
  65. #include "dude.h"
  66. #include "StockPile.h"
  67. #include "hood.h"
  68. #include "toolbar.h"
  69. #include "ORANGE/color/colormatch.h"
  70. #include "ORANGE/color/dithermatch.h"
  71. ////////////////////////////////////////////////////////////////////////////////
  72. // TOOLBAR Graphic parameters:
  73. ////////////////////////////////////////////////////////////////////////////////
  74. //=================== toolbar templates (loaded each level) ====================
  75. //===================== General Toolbar Parameters ===========================
  76. #define TB_BAR_X 0 // where to draw the entire bar
  77. #define TB_BAR_Y 440
  78. #define TB_TWEAK_FONT_Y -5
  79. #define TB_TWEAK_FONT_X -3
  80. #define TB_SMALL_FONT 11 // pixel height for ammo font
  81. #define TB_LARGE_FONT 15 // for health and armour
  82. #define TB_AMMOW_LOW 3 // ammo changes color as warning
  83. #define TB_MILLI_TO_LITE 3000 // after you get a powerup.
  84. //#ifdef MOBILE
  85. #if 1
  86. #define TB_MILLI_INTERVAL_TIME 100 //500ms lag is pretty annoying!
  87. #else
  88. #define TB_MILLI_INTERVAL_TIME 500 // maximum update rate, unless forced
  89. #endif
  90. extern int wideScreenWidth;
  91. extern RFont g_fontBig; // I hope this one is OK....
  92. typedef struct { UCHAR r; UCHAR g; UCHAR b; } MatchColor;
  93. MatchColor gmcSmallFont = { 255,255,0 }; // yellow
  94. MatchColor gmcLargeFont = { 255,255,0 }; // yellow
  95. MatchColor gmcWarningFont = { 255,0,0 }; // red
  96. MatchColor gmcAmmoGoneFont = { 96,0,0 }; // dark red
  97. MatchColor gmcAttentionFont = { 255,255,128 }; // saturated yellow
  98. //------------------ Top Bar:
  99. MatchColor gmcSolidScore = { 40,34,13 }; // saturated yellow
  100. MatchColor gmcShadowScore = { 138,123,65 }; // saturated yellow
  101. //MatchColor gmcShadowScore = { 119,102,60 }; // saturated yellow
  102. //MatchColor gmcSolidScore = { 0,0,255 }; // saturated yellow
  103. //MatchColor gmcShadowScore = { 255,0,0 }; // saturated yellow
  104. //------------------ So Score can access these:
  105. short gsStatusFontForeIndex = 251;
  106. short gsStatusFontBackIndex = 0;
  107. short gsStatusFontShadowIndex = 0;
  108. short gsStatusFontForeDeadIndex = 252;
  109. //=====================================================================
  110. //=========== INTERNAL VISUAL STOCKPILE CONTROLS ====================
  111. //=====================================================================
  112. // I am abandoning the previous idea of linking my own definition
  113. // of weapons and ammo to postal's, as they are too incompatible
  114. // for a direct interface. I am therefor switching to a proprietary one.
  115. // Local definition of a "WEAPON": Does NOT have an associated number
  116. // Local definition of an "AMMO": Has a number amount.
  117. // Proprietary formats:
  118. typedef enum
  119. {
  120. NotWeapon = 0,
  121. MachineGun,
  122. ShotGun,
  123. SprayCannon,
  124. MissileLauncher,
  125. NapalmLauncher,
  126. FlameThrower,
  127. NumberOfWeapons
  128. } ToolWeaponType;
  129. typedef enum
  130. {
  131. NotAmmo = 0,
  132. Health,
  133. KevlarVest,
  134. Bullets,
  135. Shells,
  136. Spray, // proprietary = Bullets
  137. Grenades,
  138. Rockets,
  139. HeatSeekers,// proprietary = Heatseekers
  140. Cocktails,
  141. Napalm,
  142. Fuel,
  143. ProximityMine, // all three alias to the same amount of mines!
  144. TimedMine,
  145. BouncingBettyMine,
  146. NumberOfAmmos
  147. } ToolAmmoType;
  148. // NOTE: The concept is that, in general, you select an AMMO, and the weapon
  149. // highlights dependently.
  150. //
  151. class CToolItem
  152. {
  153. public:
  154. //----------------------------------------------------------------------
  155. typedef enum { Uninitialized = 0, Weapon , Ammo } Type;
  156. typedef enum { Bar = 0, BarSel = 1, Full = 2, FullSel = 3 } State;
  157. typedef enum { Small = 0, Large } Size;
  158. //----------------------------------------------------------------------
  159. Type m_eType;
  160. bool m_bExists; // bar or full?
  161. bool m_bSelected; // selected or not?
  162. bool m_bTreasure; // found in a power up
  163. long m_lMilli; // relative time in milliseconds for timing stuff
  164. State m_eState; // short cut for applying state
  165. State m_ePrevState; // Stored for event triggering
  166. double m_dValue; // if ammo
  167. double m_dPrevValue; // if ammo
  168. double m_dLow; // value change
  169. Size m_eFontType; // for color and display
  170. RRect m_rImage; // location of icon, if applicable
  171. RRect m_rText; // location of text, if applicable
  172. //----------------------------------------------------------------------
  173. CToolItem* m_pWeapon; // Links to associated weapon
  174. CToolItem* m_pAmmo1; // Links to associated ammo for drawing order
  175. CToolItem* m_pAmmo2; // Links to associated ammo for drawing order
  176. //----------------------------------------------------------------------
  177. ToolWeaponType m_eWeaponType;
  178. ToolAmmoType m_eAmmoType;
  179. CDude::WeaponType m_eStockPile; // Postal app equivalent from Dude.h
  180. //----------------------------------------------------------------------
  181. static CToolItem* ms_aWeapons; // [NumberOfWeapons];
  182. static CToolItem* ms_aAmmo; //[NumberOfAmmos];
  183. static RFont* ms_pfntTool; // General font and print
  184. static RPrint ms_pntTool;
  185. static short ms_sSmallFontColor; // color index
  186. static short ms_sLargeFontColor;
  187. static short ms_sWarningColor;
  188. static short ms_sAmmoGoneColor;
  189. static short ms_sAttentionColor;
  190. static RImage* ms_pimCompositeBuffer;
  191. static RImage* ms_pimCompositeBufferScaled;
  192. static long ms_lLastTime;
  193. //----------------------------------------------------------------------
  194. CToolItem()
  195. {
  196. m_eType = Uninitialized;
  197. m_bExists = false;
  198. m_bSelected = false;
  199. m_bTreasure = false;
  200. m_lMilli = 0;
  201. m_eState = Bar;
  202. m_dValue = 0.0;
  203. m_dPrevValue = 0.0;
  204. m_dLow = 0;
  205. m_eFontType = Small;
  206. m_pWeapon = m_pAmmo1 = m_pAmmo2 = NULL;
  207. m_eWeaponType = NotWeapon;
  208. m_eAmmoType = NotAmmo;
  209. m_eStockPile = CDude::NoWeapon;
  210. }
  211. ~CToolItem()
  212. {
  213. }
  214. // This sets most members in a generic way for a weapon
  215. // It can add members if more differentiation is needed
  216. void ArrangeWeapon(
  217. ToolWeaponType eType,
  218. CDude::WeaponType eStock,
  219. const RRect &prImage,
  220. CToolItem* pAmmo1,
  221. CToolItem* pAmmo2 = NULL,
  222. CToolItem* pAmmo3 = NULL)
  223. {
  224. m_eWeaponType = eType;
  225. m_eStockPile = eStock;
  226. m_rImage = prImage;
  227. m_pWeapon = pAmmo1;
  228. m_pAmmo1 = pAmmo2;
  229. m_pAmmo2 = pAmmo3;
  230. //-------------------- Weapon specific:
  231. m_eType = Weapon;
  232. }
  233. void ArrangeAmmo(
  234. ToolAmmoType eType,
  235. CDude::WeaponType eStock,
  236. const RRect &prImage,
  237. short sTextX,
  238. short sTextY,
  239. CToolItem* pWeapon,
  240. Size eSize = Small)
  241. {
  242. m_eAmmoType = eType;
  243. m_eStockPile = eStock;
  244. m_rImage = prImage;
  245. m_pWeapon = pWeapon;
  246. m_rText.sX = sTextX;
  247. m_rText.sY = sTextY;
  248. m_eFontType = eSize;
  249. //-------------------- Weapon specific:
  250. m_eType = Ammo;
  251. m_dLow = 3.0; // General state for alert point
  252. }
  253. //=======================================================================
  254. static short Init(CHood* pHood) // do color matching & asset loading
  255. {
  256. // Use the current hood palette to color match the text indicies
  257. ms_sSmallFontColor = rspMatchColorRGB(
  258. gmcSmallFont.r,gmcSmallFont.g,gmcSmallFont.b,10,236,
  259. pHood->m_pimBackground->m_pPalette->Red(),
  260. pHood->m_pimBackground->m_pPalette->Green(),
  261. pHood->m_pimBackground->m_pPalette->Blue(),4);
  262. ms_sLargeFontColor = rspMatchColorRGB(
  263. gmcLargeFont.r,gmcLargeFont.g,gmcLargeFont.b,10,236,
  264. pHood->m_pimBackground->m_pPalette->Red(),
  265. pHood->m_pimBackground->m_pPalette->Green(),
  266. pHood->m_pimBackground->m_pPalette->Blue(),4);
  267. ms_sWarningColor = rspMatchColorRGB(
  268. gmcWarningFont.r,gmcWarningFont.g,gmcWarningFont.b,10,236,
  269. pHood->m_pimBackground->m_pPalette->Red(),
  270. pHood->m_pimBackground->m_pPalette->Green(),
  271. pHood->m_pimBackground->m_pPalette->Blue(),4);
  272. ms_sAmmoGoneColor = rspMatchColorRGB(
  273. gmcAmmoGoneFont.r,gmcAmmoGoneFont.g,gmcAmmoGoneFont.b,10,236,
  274. pHood->m_pimBackground->m_pPalette->Red(),
  275. pHood->m_pimBackground->m_pPalette->Green(),
  276. pHood->m_pimBackground->m_pPalette->Blue(),4);
  277. ms_sAttentionColor = rspMatchColorRGB(
  278. gmcAttentionFont.r,gmcAttentionFont.g,gmcAttentionFont.b,10,236,
  279. pHood->m_pimBackground->m_pPalette->Red(),
  280. pHood->m_pimBackground->m_pPalette->Green(),
  281. pHood->m_pimBackground->m_pPalette->Blue(),4);
  282. //----------------------------- Match Top bar stuff:
  283. gsStatusFontForeIndex = rspMatchColorRGB(
  284. gmcSolidScore.r,gmcSolidScore.g,gmcSolidScore.b,10,236,
  285. pHood->m_pimBackground->m_pPalette->Red(),
  286. pHood->m_pimBackground->m_pPalette->Green(),
  287. pHood->m_pimBackground->m_pPalette->Blue(),4);
  288. gsStatusFontShadowIndex = rspMatchColorRGB(
  289. gmcShadowScore.r,gmcShadowScore.g,gmcShadowScore.b,10,236,
  290. pHood->m_pimBackground->m_pPalette->Red(),
  291. pHood->m_pimBackground->m_pPalette->Green(),
  292. pHood->m_pimBackground->m_pPalette->Blue(),4);
  293. #if 0 // checking for palette errors:
  294. rspSetWindowColors();
  295. U8 r[256],g[256],b[256]; // for palette checking:
  296. rspGetPaletteEntries(0,256,r,g,b,1);
  297. short i;
  298. for (i=0;i < 256;i++)
  299. {
  300. if ( (*pHood->m_pimBackground->m_pPalette->Red(i) != r[i]) ||
  301. (*pHood->m_pimBackground->m_pPalette->Green(i) != g[i]) ||
  302. (*pHood->m_pimBackground->m_pPalette->Blue(i) != b[i]) )
  303. {
  304. TRACE("INDEX %d: POST(%d,%d,%d),WIN(%d,%d,%d)\n",i,
  305. (short)*pHood->m_pimBackground->m_pPalette->Red(i),
  306. (short)*pHood->m_pimBackground->m_pPalette->Green(i),
  307. (short)*pHood->m_pimBackground->m_pPalette->Blue(i),
  308. (short)r[i],(short)g[i],(short)b[i]
  309. );
  310. }
  311. }
  312. #endif
  313. ms_pfntTool = &g_fontBig;
  314. if (!ms_pimCompositeBuffer)
  315. {
  316. ms_pimCompositeBuffer = new RImage;
  317. ms_pimCompositeBuffer->CreateImage(
  318. pHood->m_pimEmptyBar->m_sWidth,
  319. pHood->m_pimEmptyBar->m_sHeight,
  320. RImage::BMP8);
  321. ms_pimCompositeBufferScaled = new RImage;
  322. ms_pimCompositeBufferScaled->CreateImage(
  323. wideScreenWidth, //HACK HACK
  324. pHood->m_pimEmptyBar->m_sHeight,
  325. RImage::BMP8);
  326. }
  327. ms_pntTool.SetFont(TB_SMALL_FONT,ms_pfntTool);
  328. ms_pntTool.SetDestination(ms_pimCompositeBuffer);
  329. // Set up the bar to a neutral background:
  330. rspBlit(pHood->m_pimEmptyBar,ms_pimCompositeBuffer,0,0,0,0,
  331. ms_pimCompositeBuffer->m_sWidth,
  332. ms_pimCompositeBuffer->m_sHeight);
  333. return SUCCESS;
  334. }
  335. // Assume the entire bar needs to be redrawn.
  336. static void RenderBar(CHood* pHood,RImage* pimDst,short sDstX,short sDstY)
  337. {
  338. // First Draw all the weapons...
  339. short i;
  340. RImage* pimPlane = NULL;
  341. // Set up the bar to a neutral background:
  342. rspBlit(pHood->m_pimEmptyBar,ms_pimCompositeBuffer,0,0,0,0,
  343. ms_pimCompositeBuffer->m_sWidth,
  344. ms_pimCompositeBuffer->m_sHeight);
  345. for (i = NotWeapon + 1; i < NumberOfWeapons; i++)
  346. {
  347. switch (ms_aWeapons[i].m_eState)
  348. {
  349. case Bar: pimPlane = pHood->m_pimEmptyBar; break;
  350. case BarSel: pimPlane = pHood->m_pimEmptyBarSelected; break;
  351. case Full: pimPlane = pHood->m_pimFullBar; break;
  352. case FullSel: pimPlane = pHood->m_pimFullBarSelected; break;
  353. }
  354. // copy the graphic:
  355. rspBlit(pimPlane,ms_pimCompositeBuffer,
  356. ms_aWeapons[i].m_rImage.sX,
  357. ms_aWeapons[i].m_rImage.sY,
  358. ms_aWeapons[i].m_rImage.sX,
  359. ms_aWeapons[i].m_rImage.sY,
  360. ms_aWeapons[i].m_rImage.sW,
  361. ms_aWeapons[i].m_rImage.sH);
  362. }
  363. // Then, draw all the ammo...
  364. for (i = NotAmmo + 1; i < NumberOfAmmos; i++)
  365. {
  366. switch (ms_aAmmo[i].m_eState)
  367. {
  368. case Bar: pimPlane = pHood->m_pimEmptyBar; break;
  369. case BarSel: pimPlane = pHood->m_pimEmptyBarSelected; break;
  370. case Full: pimPlane = pHood->m_pimFullBar; break;
  371. case FullSel: pimPlane = pHood->m_pimFullBarSelected; break;
  372. }
  373. if (ms_aAmmo[i].m_rImage.sW && ms_aAmmo[i].m_rImage.sH)
  374. rspBlit(pimPlane,ms_pimCompositeBuffer,
  375. ms_aAmmo[i].m_rImage.sX,
  376. ms_aAmmo[i].m_rImage.sY,
  377. ms_aAmmo[i].m_rImage.sX,
  378. ms_aAmmo[i].m_rImage.sY,
  379. ms_aAmmo[i].m_rImage.sW,
  380. ms_aAmmo[i].m_rImage.sH);
  381. }
  382. // Finally, print all the values...
  383. for (i = NotAmmo + 1; i < NumberOfAmmos; i++)
  384. {
  385. short sFontSize;
  386. short sFontColor;
  387. // choose the correct font.
  388. if (ms_aAmmo[i].m_eFontType == Small)
  389. {
  390. sFontSize = TB_SMALL_FONT;
  391. sFontColor = ms_sSmallFontColor;
  392. }
  393. else
  394. {
  395. sFontSize = TB_LARGE_FONT;
  396. sFontColor = ms_sLargeFontColor;
  397. }
  398. // Update the attention color time:
  399. if (ms_aAmmo[i].m_bTreasure)
  400. {
  401. if ( (rspGetMilliseconds() - ms_aAmmo[i].m_lMilli) >
  402. TB_MILLI_TO_LITE)
  403. {
  404. // no longer highlighted:
  405. ms_aAmmo[i].m_bTreasure = false;
  406. }
  407. }
  408. // check for special color conditions:
  409. if (ms_aAmmo[i].m_dValue <= 0.1) sFontColor = ms_sAmmoGoneColor;
  410. else if (ms_aAmmo[i].m_bTreasure) sFontColor = ms_sAttentionColor;
  411. else if (ms_aAmmo[i].m_dValue <= ms_aAmmo[i].m_dLow)
  412. sFontColor = ms_sWarningColor;
  413. // select the correct font and draw the amount:
  414. ms_pntTool.SetFont(sFontSize,ms_pfntTool);
  415. ms_pntTool.SetColor(sFontColor);
  416. if (i != Bullets) // nolonger print the amount of bullets...
  417. {
  418. ms_pntTool.print(ms_aAmmo[i].m_rText.sX,ms_aAmmo[i].m_rText.sY,
  419. "%3ld",long(ms_aAmmo[i].m_dValue));
  420. }
  421. }
  422. //Really nasty, scale the image incase its widescreen
  423. if (ms_pimCompositeBuffer->m_sWidth != ms_pimCompositeBufferScaled->m_sWidth)
  424. {
  425. float widthScale = (float)ms_pimCompositeBuffer->m_sWidth / (float)ms_pimCompositeBufferScaled->m_sWidth;
  426. for (int n=0;n<ms_pimCompositeBuffer->m_sHeight;n++)
  427. {
  428. for (int x=0;x<ms_pimCompositeBufferScaled->m_sWidth;x++)
  429. {
  430. UCHAR* dest = ms_pimCompositeBufferScaled->m_pData + n * ms_pimCompositeBufferScaled->m_lPitch + x;
  431. UCHAR* src = ms_pimCompositeBuffer->m_pData + n * ms_pimCompositeBuffer->m_lPitch + (int)((float)x * widthScale);
  432. *dest = *src;
  433. }
  434. //memcpy(ms_pimCompositeBufferScaled->m_pData + n * ms_pimCompositeBufferScaled->m_lPitch,
  435. // ms_pimCompositeBuffer->m_pData + n * ms_pimCompositeBuffer->m_lPitch,ms_pimCompositeBuffer->m_sWidth);
  436. }
  437. rspBlit(ms_pimCompositeBufferScaled,pimDst,0,0,sDstX,sDstY,
  438. ms_pimCompositeBufferScaled->m_sWidth,
  439. ms_pimCompositeBufferScaled->m_sHeight);
  440. }
  441. else //No scaling needed
  442. {
  443. // put into background
  444. rspBlit(ms_pimCompositeBuffer,pimDst,0,0,sDstX,sDstY,
  445. ms_pimCompositeBuffer->m_sWidth,
  446. ms_pimCompositeBuffer->m_sHeight);
  447. }
  448. }
  449. // Handle dude events, including graphical updates
  450. // Wil return true if a change of state has occurred
  451. static bool UpdateStatus(CDude* pDude)
  452. {
  453. // Fist, try to get all the status possible from the CDude:
  454. // Use the stockpile for most:
  455. short i;
  456. // Get the current values from the stockpile:
  457. // Because GetWeaponInfo goes by weapon to recieve ammo,
  458. // we need to check ammo directly:
  459. //==========================================================================
  460. // Save the old ammo amounts and ammo state:
  461. for (i = NotAmmo + 1; i < NumberOfAmmos; i++)
  462. {
  463. // do this to catch powerups or ammot changes:
  464. ms_aAmmo[i].m_dPrevValue = ms_aAmmo[i].m_dValue;
  465. ms_aAmmo[i].m_ePrevState = ms_aAmmo[i].m_eState;
  466. }
  467. // Save the states of all the weapons:
  468. for (i = NotWeapon + 1; i < NumberOfWeapons; i++)
  469. {
  470. // do this to catch powerups or ammot changes:
  471. ms_aWeapons[i].m_ePrevState = ms_aWeapons[i].m_eState;
  472. }
  473. //==========================================================================
  474. // Hit points must be translated into a percentage of the whole:
  475. ms_aAmmo[Health].m_dValue = double(pDude->m_stockpile.m_sHitPoints)*100/
  476. pDude->m_sOrigHitPoints;
  477. if ( (ms_aAmmo[Health].m_dValue > 0.0) && (ms_aAmmo[Health].m_dValue < 1.0) )
  478. {
  479. ms_aAmmo[Health].m_dValue = 1.0;
  480. }
  481. if (pDude->IsDead()) ms_aAmmo[Health].m_dValue = 0.0;
  482. ms_aAmmo[KevlarVest].m_dValue = double(pDude->m_stockpile.m_sKevlarLayers)/5.0;
  483. //if (ms_aAmmo[KevlarVest].m_dValue > 100.0) ms_aAmmo[KevlarVest].m_dValue = 100.0;
  484. ms_aAmmo[Bullets].m_dValue = pDude->m_stockpile.m_sNumBullets;
  485. ms_aAmmo[Shells].m_dValue = pDude->m_stockpile.m_sNumShells;
  486. ms_aAmmo[Spray].m_dValue = pDude->m_stockpile.m_sNumShells;
  487. ms_aAmmo[Grenades].m_dValue = pDude->m_stockpile.m_sNumGrenades;
  488. ms_aAmmo[Rockets].m_dValue = pDude->m_stockpile.m_sNumMissiles;
  489. ms_aAmmo[HeatSeekers].m_dValue = pDude->m_stockpile.m_sNumHeatseekers;
  490. ms_aAmmo[Cocktails].m_dValue = pDude->m_stockpile.m_sNumFireBombs;
  491. ms_aAmmo[Napalm].m_dValue = pDude->m_stockpile.m_sNumNapalms;
  492. ms_aAmmo[Fuel].m_dValue = double(pDude->m_stockpile.m_sNumFuel)/2.50;
  493. ms_aAmmo[ProximityMine].m_dValue = pDude->m_stockpile.m_sNumMines;
  494. ms_aAmmo[TimedMine].m_dValue = pDude->m_stockpile.m_sNumMines;
  495. ms_aAmmo[BouncingBettyMine].m_dValue = pDude->m_stockpile.m_sNumMines;
  496. // Which weapons do I have?
  497. ms_aWeapons[MachineGun].m_bExists = (pDude->m_stockpile.m_sMachineGun) ? true : false;
  498. ms_aWeapons[ShotGun].m_bExists = (pDude->m_stockpile.m_sShotGun) ? true : false;
  499. ms_aWeapons[SprayCannon].m_bExists = (pDude->m_stockpile.m_sSprayCannon) ? true : false;
  500. ms_aWeapons[MissileLauncher].m_bExists = (pDude->m_stockpile.m_sMissileLauncher) ? true : false;
  501. ms_aWeapons[NapalmLauncher].m_bExists = (pDude->m_stockpile.m_sNapalmLauncher) ? true : false;
  502. ms_aWeapons[FlameThrower].m_bExists = (pDude->m_stockpile.m_sFlameThrower) ? true : false;
  503. // Mark those ammos that have gone up
  504. for (i = NotAmmo + 1; i < NumberOfAmmos; i++)
  505. {
  506. // do this to catch powerups or ammot changes:
  507. if (ms_aAmmo[i].m_dPrevValue < ms_aAmmo[i].m_dValue)
  508. {
  509. ms_aAmmo[i].m_bTreasure = true;
  510. ms_aAmmo[i].m_lMilli = rspGetMilliseconds();
  511. }
  512. }
  513. // Note that throwing ammo exists if ammo is not zero
  514. for (i = NotAmmo + 1; i < NumberOfAmmos; i++)
  515. {
  516. ms_aAmmo[i].m_bExists = (ms_aAmmo[i].m_dValue > 0.01);
  517. ms_aAmmo[i].m_bSelected = FALSE; // initializing
  518. }
  519. // Clear out all selections:
  520. for (i = NotWeapon + 1; i < NumberOfWeapons; i++)
  521. {
  522. ms_aWeapons[i].m_bSelected = FALSE;
  523. }
  524. // Which weapon is currently selected?
  525. // (I guess this is a scheme)
  526. CDude::WeaponType CurWeapon = pDude->GetCurrentWeapon();
  527. switch (CurWeapon)
  528. {
  529. case CDude::SemiAutomatic:
  530. ms_aWeapons[MachineGun].m_bSelected = true;
  531. ms_aAmmo[Bullets].m_bSelected = true;
  532. break;
  533. case CDude::ShotGun:
  534. ms_aWeapons[ShotGun].m_bSelected = true;
  535. ms_aAmmo[Shells].m_bSelected = true;
  536. break;
  537. case CDude::SprayCannon:
  538. ms_aWeapons[SprayCannon].m_bSelected = true;
  539. ms_aAmmo[Spray].m_bSelected = true;
  540. break;
  541. case CDude::Grenade:
  542. ms_aAmmo[Grenades].m_bSelected = true;
  543. break;
  544. case CDude::Rocket:
  545. ms_aWeapons[MissileLauncher].m_bSelected = true;
  546. ms_aAmmo[Rockets].m_bSelected = true;
  547. break;
  548. case CDude::Heatseeker:
  549. ms_aWeapons[MissileLauncher].m_bSelected = true;
  550. ms_aAmmo[HeatSeekers].m_bSelected = true;
  551. break;
  552. case CDude::FireBomb:
  553. ms_aAmmo[Cocktails].m_bSelected = true;
  554. break;
  555. case CDude::Napalm:
  556. ms_aWeapons[NapalmLauncher].m_bSelected = true;
  557. ms_aAmmo[Napalm].m_bSelected = true;
  558. break;
  559. case CDude::FlameThrower:
  560. ms_aWeapons[FlameThrower].m_bSelected = true;
  561. ms_aAmmo[Fuel].m_bSelected = true;
  562. break;
  563. case CDude::ProximityMine:
  564. ms_aAmmo[ProximityMine].m_bSelected = true;
  565. break;
  566. case CDude::TimedMine:
  567. ms_aAmmo[TimedMine].m_bSelected = true;
  568. break;
  569. case CDude::BouncingBettyMine:
  570. ms_aAmmo[BouncingBettyMine].m_bSelected = true;
  571. break;
  572. case CDude::DeathWad:
  573. ms_aWeapons[MachineGun].m_bSelected = true;
  574. ms_aWeapons[ShotGun].m_bSelected = true;
  575. ms_aWeapons[SprayCannon].m_bSelected = true;
  576. ms_aWeapons[MissileLauncher].m_bSelected = true;
  577. ms_aWeapons[NapalmLauncher].m_bSelected = true;
  578. ms_aWeapons[FlameThrower].m_bSelected = true;
  579. ms_aAmmo[Bullets].m_bSelected = true;
  580. ms_aAmmo[Shells].m_bSelected = true;
  581. ms_aAmmo[Spray].m_bSelected = true;
  582. ms_aAmmo[Grenades].m_bSelected = true;
  583. ms_aAmmo[Rockets].m_bSelected = true;
  584. ms_aAmmo[HeatSeekers].m_bSelected = true;
  585. ms_aAmmo[Cocktails].m_bSelected = true;
  586. ms_aAmmo[Napalm].m_bSelected = true;
  587. ms_aAmmo[Fuel].m_bSelected = true;
  588. break;
  589. case CDude::DoubleBarrel:
  590. ms_aWeapons[ShotGun].m_bSelected = true;
  591. ms_aAmmo[Shells].m_bSelected = true;
  592. break;
  593. }
  594. // Light everything that would be selected by this "scheme"
  595. // Now set all the situation codes for drawing!
  596. for (i = NotAmmo + 1; i < NumberOfAmmos; i++)
  597. {
  598. if (!ms_aAmmo[i].m_bExists && !ms_aAmmo[i].m_bSelected)
  599. ms_aAmmo[i].m_eState = Bar;
  600. else if (!ms_aAmmo[i].m_bExists && ms_aAmmo[i].m_bSelected)
  601. ms_aAmmo[i].m_eState = BarSel;
  602. else if (ms_aAmmo[i].m_bExists && !ms_aAmmo[i].m_bSelected)
  603. ms_aAmmo[i].m_eState = Full;
  604. else if (ms_aAmmo[i].m_bExists && ms_aAmmo[i].m_bSelected)
  605. ms_aAmmo[i].m_eState = FullSel;
  606. }
  607. for (i = NotWeapon + 1; i < NumberOfWeapons; i++)
  608. {
  609. if (!ms_aWeapons[i].m_bExists && !ms_aWeapons[i].m_bSelected)
  610. ms_aWeapons[i].m_eState = Bar;
  611. else if (!ms_aWeapons[i].m_bExists && ms_aWeapons[i].m_bSelected)
  612. ms_aWeapons[i].m_eState = BarSel;
  613. else if (ms_aWeapons[i].m_bExists && !ms_aWeapons[i].m_bSelected)
  614. ms_aWeapons[i].m_eState = Full;
  615. else if (ms_aWeapons[i].m_bExists && ms_aWeapons[i].m_bSelected)
  616. ms_aWeapons[i].m_eState = FullSel;
  617. }
  618. //======================== CHECK FOR CHANGE IN AMMO OR STATUS:
  619. bool bChange = false;
  620. for (i = NotAmmo + 1; i < NumberOfAmmos; i++)
  621. {
  622. if (ms_aAmmo[i].m_eState != ms_aAmmo[i].m_ePrevState)
  623. {
  624. bChange = true;
  625. break;
  626. }
  627. if (ms_aAmmo[i].m_dValue != ms_aAmmo[i].m_dPrevValue)
  628. {
  629. bChange = true;
  630. break;
  631. }
  632. // This hook is when the tellow numbers become white.
  633. if (ms_aAmmo[i].m_bTreasure)
  634. {
  635. if ( (rspGetMilliseconds() - ms_aAmmo[i].m_lMilli) >
  636. TB_MILLI_TO_LITE)
  637. {
  638. // no longer highlighted:
  639. bChange = true;
  640. }
  641. }
  642. }
  643. if (bChange == false)
  644. {
  645. for (i = NotWeapon + 1; i < NumberOfWeapons; i++)
  646. {
  647. if (ms_aWeapons[i].m_eState != ms_aWeapons[i].m_ePrevState)
  648. {
  649. bChange = true;
  650. break;
  651. }
  652. }
  653. }
  654. return bChange;
  655. }
  656. };
  657. //----------------------------------------------------------------------
  658. // I am hoping that before any instance of a class
  659. // exists, that the staic members must also exist.
  660. CToolItem* CToolItem::ms_aWeapons = NULL;
  661. CToolItem* CToolItem::ms_aAmmo = NULL;
  662. RFont* CToolItem::ms_pfntTool = NULL; // General font and print
  663. RPrint CToolItem::ms_pntTool;
  664. short CToolItem::ms_sSmallFontColor = 255; // color index
  665. short CToolItem::ms_sLargeFontColor = 255;
  666. short CToolItem::ms_sWarningColor = 255;
  667. short CToolItem::ms_sAmmoGoneColor = 255;
  668. short CToolItem::ms_sAttentionColor = 255;
  669. RImage* CToolItem::ms_pimCompositeBuffer = NULL;
  670. RImage* CToolItem::ms_pimCompositeBufferScaled = NULL;
  671. long CToolItem::ms_lLastTime = 0;
  672. // Time to arrange the basic bar relationhips:
  673. class CInitToolBar
  674. {
  675. public:
  676. CInitToolBar()
  677. {
  678. // arrange the patterns of weapons and ammo:
  679. CToolItem::ms_aWeapons = new CToolItem[NumberOfWeapons];
  680. CToolItem::ms_aAmmo = new CToolItem[NumberOfAmmos];
  681. //************* WEAPONS **************
  682. CToolItem::ms_aWeapons[MachineGun].ArrangeWeapon(
  683. MachineGun,CDude::SemiAutomatic,
  684. RRect(123,443,48,23),
  685. &CToolItem::ms_aAmmo[Bullets]);
  686. CToolItem::ms_aWeapons[ShotGun].ArrangeWeapon(
  687. ShotGun,CDude::ShotGun,
  688. RRect(176,444,42,19),
  689. &CToolItem::ms_aAmmo[Shells]);
  690. CToolItem::ms_aWeapons[SprayCannon].ArrangeWeapon(
  691. SprayCannon,CDude::SprayCannon,
  692. RRect(221,442,44,22),
  693. &CToolItem::ms_aAmmo[Spray]);
  694. CToolItem::ms_aWeapons[MissileLauncher].ArrangeWeapon(
  695. MissileLauncher,CDude::Rocket,
  696. RRect(306,442,54,21),
  697. &CToolItem::ms_aAmmo[Rockets],
  698. &CToolItem::ms_aAmmo[HeatSeekers]); // double whammy
  699. CToolItem::ms_aWeapons[NapalmLauncher].ArrangeWeapon(
  700. NapalmLauncher,CDude::Napalm,
  701. RRect(413,441,49,23),
  702. &CToolItem::ms_aAmmo[Napalm]);
  703. CToolItem::ms_aWeapons[FlameThrower].ArrangeWeapon(
  704. FlameThrower,CDude::FlameThrower,
  705. RRect(464,442,52,22),
  706. &CToolItem::ms_aAmmo[Fuel]);
  707. //************** AMMO ****************
  708. CToolItem::ms_aAmmo[Health].ArrangeAmmo(
  709. Health,CDude::NoWeapon,
  710. RRect(0,440,58,40),
  711. 42,457,
  712. NULL,
  713. CToolItem::Large);
  714. CToolItem::ms_aAmmo[KevlarVest].ArrangeAmmo(
  715. KevlarVest,CDude::NoWeapon,
  716. RRect(61,445,35,34),
  717. 97,457,
  718. NULL,
  719. CToolItem::Large);
  720. //-------------------------------------
  721. CToolItem::ms_aAmmo[Bullets].ArrangeAmmo(
  722. Bullets,CDude::SemiAutomatic,
  723. RRect(129,461,16,16),
  724. 149,467,
  725. &CToolItem::ms_aWeapons[MachineGun],
  726. CToolItem::Small);
  727. CToolItem::ms_aAmmo[Shells].ArrangeAmmo(
  728. Shells,CDude::ShotGun,
  729. RRect(182,463,16,15),
  730. 202,467,
  731. &CToolItem::ms_aWeapons[ShotGun],
  732. CToolItem::Small);
  733. CToolItem::ms_aAmmo[Spray].ArrangeAmmo(
  734. Spray,CDude::SprayCannon,
  735. RRect(228,463,16,15),
  736. 247,467,
  737. &CToolItem::ms_aWeapons[SprayCannon],
  738. CToolItem::Small);
  739. CToolItem::ms_aAmmo[Grenades].ArrangeAmmo(
  740. Grenades,CDude::Grenade,
  741. RRect(272,443,19,23),
  742. 276,467,
  743. NULL,
  744. CToolItem::Small);
  745. CToolItem::ms_aAmmo[Rockets].ArrangeAmmo(
  746. Rockets,CDude::Rocket,
  747. RRect(295,462,24,17),
  748. 321,467,
  749. &CToolItem::ms_aWeapons[MissileLauncher],
  750. CToolItem::Small);
  751. CToolItem::ms_aAmmo[HeatSeekers].ArrangeAmmo(
  752. HeatSeekers,CDude::Heatseeker,
  753. RRect(337,464,26,13),
  754. 364,467,
  755. &CToolItem::ms_aWeapons[MissileLauncher],
  756. CToolItem::Small);
  757. CToolItem::ms_aAmmo[Cocktails].ArrangeAmmo(
  758. Cocktails,CDude::FireBomb,
  759. RRect(390,442,20,24),
  760. 394,467,
  761. NULL,
  762. CToolItem::Small);
  763. CToolItem::ms_aAmmo[Napalm].ArrangeAmmo(
  764. Napalm,CDude::Napalm,
  765. RRect(414,464,28,13),
  766. 447,466,
  767. &CToolItem::ms_aWeapons[NapalmLauncher],
  768. CToolItem::Small);
  769. CToolItem::ms_aAmmo[Fuel].ArrangeAmmo(
  770. Fuel,CDude::FlameThrower,
  771. RRect(476,465,14,13),
  772. 494,466,
  773. &CToolItem::ms_aWeapons[FlameThrower],
  774. CToolItem::Small);
  775. //----------------------------------------
  776. CToolItem::ms_aAmmo[ProximityMine].ArrangeAmmo(
  777. ProximityMine,CDude::ProximityMine,
  778. RRect(567,443,30,23),
  779. 575,467, // redundantly repeated
  780. NULL,
  781. CToolItem::Small);
  782. CToolItem::ms_aAmmo[TimedMine].ArrangeAmmo(
  783. TimedMine,CDude::TimedMine,
  784. RRect(599,443,30,26),
  785. 575,467, // redundantly repeated
  786. NULL,
  787. CToolItem::Small);
  788. CToolItem::ms_aAmmo[BouncingBettyMine].ArrangeAmmo(
  789. BouncingBettyMine,CDude::BouncingBettyMine,
  790. RRect(538,444,28,28),
  791. 575,467, // redundantly repeated
  792. NULL,
  793. CToolItem::Small);
  794. // Now, factor out the bar location from all the coordinates:
  795. short i;
  796. for (i = NotWeapon + 1; i < NumberOfWeapons; i++)
  797. {
  798. CToolItem::ms_aWeapons[i].m_rImage.sY -= TB_BAR_Y;
  799. CToolItem::ms_aWeapons[i].m_rText.sY -= TB_BAR_Y;
  800. CToolItem::ms_aWeapons[i].m_rText.sY += TB_TWEAK_FONT_Y;
  801. CToolItem::ms_aWeapons[i].m_rText.sX += TB_TWEAK_FONT_X;
  802. }
  803. for (i = NotAmmo + 1; i < NumberOfAmmos; i++)
  804. {
  805. CToolItem::ms_aAmmo[i].m_rImage.sY -= TB_BAR_Y;
  806. CToolItem::ms_aAmmo[i].m_rText.sY -= TB_BAR_Y;
  807. CToolItem::ms_aAmmo[i].m_rText.sY += TB_TWEAK_FONT_Y;
  808. CToolItem::ms_aAmmo[i].m_rText.sX += TB_TWEAK_FONT_X;
  809. }
  810. // Set differect "low" values for each item:
  811. CToolItem::ms_aAmmo[Health].m_dLow = 20.0;
  812. CToolItem::ms_aAmmo[KevlarVest].m_dLow = 9.0;
  813. CToolItem::ms_aAmmo[Shells].m_dLow = 3.0;
  814. CToolItem::ms_aAmmo[Spray].m_dLow = 15.0;
  815. CToolItem::ms_aAmmo[Grenades].m_dLow = 2.0;
  816. CToolItem::ms_aAmmo[Rockets].m_dLow = 2.0;
  817. CToolItem::ms_aAmmo[HeatSeekers].m_dLow = 2.0;
  818. CToolItem::ms_aAmmo[Cocktails].m_dLow = 2.0;
  819. CToolItem::ms_aAmmo[Napalm].m_dLow = 2.0;
  820. CToolItem::ms_aAmmo[Fuel].m_dLow = 10.0;
  821. CToolItem::ms_aAmmo[ProximityMine].m_dLow = 2.0;
  822. CToolItem::ms_aAmmo[BouncingBettyMine].m_dLow = 2.0;
  823. CToolItem::ms_aAmmo[TimedMine].m_dLow = 1.0;
  824. }
  825. ~CInitToolBar()
  826. {
  827. delete [] CToolItem::ms_aWeapons;
  828. delete [] CToolItem::ms_aAmmo;
  829. delete CToolItem::ms_pimCompositeBuffer;
  830. }
  831. } DoInitToolBar;
  832. /////////////////////////////////////////
  833. // aliased functions "for her pleasure."
  834. /////////////////////////////////////////
  835. short ToolBarInit(CHood* pHood)
  836. {
  837. return CToolItem::Init(pHood);
  838. }
  839. bool ToolBarRender(CHood* pHood,RImage* pimDst,short sDstX,short sDstY,
  840. CDude* pDude,bool bForceRender)
  841. {
  842. bool bRender = true;
  843. if (pDude == NULL)
  844. {
  845. TRACE("ToolBarRender: Dude doesn't exist!\n");
  846. return false;
  847. }
  848. // First check for minimum interval time:
  849. if (!bForceRender) // unless forced to render
  850. {
  851. if ( (rspGetMilliseconds() - CToolItem::ms_lLastTime)
  852. > TB_MILLI_INTERVAL_TIME)
  853. {
  854. CToolItem::ms_lLastTime = rspGetMilliseconds();
  855. // see if anything has truly changed - if not, don't update:
  856. bool bRender = false;
  857. bRender = CToolItem::UpdateStatus(pDude);
  858. if (bRender) CToolItem::RenderBar(pHood,pimDst,sDstX,sDstY);
  859. return bRender;
  860. }
  861. }
  862. else
  863. {
  864. // force the render
  865. CToolItem::UpdateStatus(pDude);
  866. CToolItem::RenderBar(pHood,pimDst,sDstX,sDstY); // don't care about update
  867. }
  868. return bRender;
  869. }
  870. ////////////////////////////////////////////////
  871. // Use events which change the state of the bar
  872. ////////////////////////////////////////////////