Computer.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "StdAfx.h"
  13. #include "LCDDrawing.h"
  14. #include "CompMessage.h"
  15. extern CGame *_pGame;
  16. static const FLOAT tmComputerFade = 1.0f; // how many seconds it takes computer to fade in/out
  17. static FLOAT fComputerFadeValue = 0.0f; // faded value of computer (0..1)
  18. static CTimerValue tvComputerLast;
  19. static CTimerValue _tvMessageAppear;
  20. static CPlayer *_ppenPlayer = NULL;
  21. extern FLOAT _fMsgAppearFade = 0.0f;
  22. extern FLOAT _fMsgAppearDelta = 0.0f;
  23. // player statistics are set here
  24. extern CTString _strStatsDetails = "";
  25. // mouse cursor position
  26. static PIX2D _vpixMouse;
  27. static PIX2D _vpixExternMouse;
  28. static PIX _pixSliderDragJ = -1;
  29. static PIX _iSliderDragLine = -1;
  30. static PIX _bSliderDragText = FALSE;
  31. // font metrics
  32. static PIX _pixCharSizeI = 1;
  33. static PIX _pixCharSizeJ = 1;
  34. static PIX _pixCharSize2I = 1;
  35. static PIX _pixCharSize2J = 1;
  36. static PIX _pixMarginI = 1;
  37. static PIX _pixMarginJ = 1;
  38. // general geometry data
  39. static FLOAT _fScaling = 1;
  40. static FLOAT _fScaling2 = 1;
  41. static PIX _pixSizeI=0;
  42. static PIX _pixSizeJ=0;
  43. static PIXaabbox2D _boxTitle;
  44. static PIXaabbox2D _boxExit;
  45. static PIXaabbox2D _boxMsgList;
  46. static PIXaabbox2D _boxMsgText;
  47. static PIXaabbox2D _boxMsgImage;
  48. static PIXaabbox2D _boxButton[CMT_COUNT];
  49. static INDEX _ctMessagesOnScreen = 5;
  50. static INDEX _ctTextLinesOnScreen = 20;
  51. static INDEX _ctTextCharsPerRow = 20;
  52. // position of the message list
  53. static INDEX _iFirstMessageOnScreen = -1;
  54. static INDEX _iWantedFirstMessageOnScreen = 0;
  55. static INDEX _iLastActiveMessage = -1;
  56. static INDEX _iActiveMessage = 0;
  57. // message type selected in the buttons list
  58. static enum CompMsgType _cmtCurrentType = (enum CompMsgType)-1;
  59. static enum CompMsgType _cmtWantedType = CMT_INFORMATION;
  60. // current scroll position of message text
  61. static INDEX _iTextLineOnScreen = 0;
  62. // message list cache for messages of current type
  63. static CStaticStackArray<CCompMessage> _acmMessages;
  64. // message image data
  65. static CTextureObject _toPicture;
  66. // text/graphics colors
  67. static COLOR _colLight;
  68. static COLOR _colMedium;
  69. static COLOR _colDark;
  70. static COLOR _colBoxes;
  71. static void SetFont1(CDrawPort *pdp)
  72. {
  73. pdp->SetFont(_pfdConsoleFont);
  74. pdp->SetTextScaling(_fScaling);
  75. pdp->SetTextAspect(1.0f);
  76. }
  77. static void SetFont2(CDrawPort *pdp)
  78. {
  79. pdp->SetFont(_pfdDisplayFont);
  80. pdp->SetTextScaling(_fScaling2);
  81. pdp->SetTextAspect(1.0f);
  82. }
  83. static COLOR MouseOverColor(const PIXaabbox2D &box, COLOR colNone,
  84. COLOR colOff, COLOR colOn)
  85. {
  86. if (box>=_vpixMouse) {
  87. return LCDBlinkingColor(colOff, colOn);
  88. } else {
  89. return colNone;
  90. }
  91. }
  92. static PIXaabbox2D GetMsgListBox(INDEX i)
  93. {
  94. PIX pixI0 = _boxMsgList.Min()(1)+_pixMarginI;
  95. PIX pixI1 = _boxMsgList.Max()(1)-_pixMarginI*3;
  96. PIX pixJ0 = _boxMsgList.Min()(2)+_pixMarginJ;
  97. PIX pixDJ = _pixCharSizeJ;
  98. return PIXaabbox2D(
  99. PIX2D(pixI0, pixJ0+pixDJ*i),
  100. PIX2D(pixI1, pixJ0+pixDJ*(i+1)-1));
  101. }
  102. static PIXaabbox2D GetSliderBox(INDEX iFirst, INDEX iVisible, INDEX iTotal,
  103. PIXaabbox2D boxFull)
  104. {
  105. FLOAT fSize = ClampUp(FLOAT(iVisible)/iTotal, 1.0f);
  106. PIX pixFull = boxFull.Size()(2);
  107. PIX pixSize = PIX(pixFull*fSize);
  108. pixSize = ClampDn(pixSize, boxFull.Size()(1));
  109. PIX pixTop = pixFull*(FLOAT(iFirst)/iTotal)+boxFull.Min()(2);
  110. PIX pixI0 = boxFull.Min()(1);
  111. PIX pixI1 = boxFull.Max()(1);
  112. return PIXaabbox2D(PIX2D(pixI0, pixTop), PIX2D(pixI1, pixTop+pixSize));
  113. }
  114. static INDEX SliderPixToIndex(PIX pixOffset, INDEX iVisible, INDEX iTotal, PIXaabbox2D boxFull)
  115. {
  116. FLOAT fSize = ClampUp(FLOAT(iVisible)/iTotal, 1.0f);
  117. PIX pixFull = boxFull.Size()(2);
  118. PIX pixSize = PIX(pixFull*fSize);
  119. if (pixSize>=boxFull.Size()(2)) {
  120. return 0;
  121. }
  122. return (iTotal*pixOffset)/pixFull;
  123. }
  124. static PIXaabbox2D GetTextSliderSpace(void)
  125. {
  126. PIX pixSizeI = _boxMsgText.Size()(1);
  127. PIX pixSizeJ = _boxMsgText.Size()(2);
  128. PIX pixSliderSizeI = _pixMarginI*2;
  129. if (pixSliderSizeI<5) {
  130. pixSliderSizeI=5;
  131. }
  132. return PIXaabbox2D(
  133. PIX2D(pixSizeI-pixSliderSizeI, _pixMarginJ*4),
  134. PIX2D(pixSizeI, pixSizeJ));
  135. }
  136. static PIXaabbox2D GetMsgSliderSpace(void)
  137. {
  138. PIX pixSizeI = _boxMsgList.Size()(1);
  139. PIX pixSizeJ = _boxMsgList.Size()(2);
  140. PIX pixSliderSizeI = _pixMarginI*2;
  141. if (pixSliderSizeI<5) {
  142. pixSliderSizeI=5;
  143. }
  144. return PIXaabbox2D(
  145. PIX2D(pixSizeI-pixSliderSizeI, 0),
  146. PIX2D(pixSizeI, pixSizeJ));
  147. }
  148. static PIXaabbox2D GetTextSliderBox(void)
  149. {
  150. if (_iActiveMessage>=_acmMessages.Count()) {
  151. return PIXaabbox2D();
  152. }
  153. INDEX ctTextLines = _acmMessages[_iActiveMessage].cm_ctFormattedLines;
  154. PIX pixSizeI = _boxMsgText.Size()(1);
  155. PIX pixSizeJ = _boxMsgText.Size()(2);
  156. return GetSliderBox(
  157. _iTextLineOnScreen, _ctTextLinesOnScreen, ctTextLines, GetTextSliderSpace());
  158. }
  159. static PIXaabbox2D GetMsgSliderBox(void)
  160. {
  161. INDEX ctLines = _acmMessages.Count();
  162. PIX pixSizeI = _boxMsgList.Size()(1);
  163. PIX pixSizeJ = _boxMsgList.Size()(2);
  164. return GetSliderBox(
  165. _iFirstMessageOnScreen, _ctMessagesOnScreen, ctLines, GetMsgSliderSpace());
  166. }
  167. // syncronize message list scrolling to show active message
  168. void SyncScrollWithActive(void)
  169. {
  170. if (_iActiveMessage<_iFirstMessageOnScreen) {
  171. _iWantedFirstMessageOnScreen = _iActiveMessage;
  172. }
  173. if (_iActiveMessage>_iFirstMessageOnScreen+_ctMessagesOnScreen-1) {
  174. _iWantedFirstMessageOnScreen = _iActiveMessage-_ctMessagesOnScreen+1;
  175. }
  176. }
  177. // select next unread message
  178. static void NextUnreadMessage(void)
  179. {
  180. INDEX i=_iActiveMessage;
  181. FOREVER {
  182. i++;
  183. if (i>=_acmMessages.Count()) {
  184. i = 0;
  185. }
  186. if (i==_iActiveMessage) {
  187. return;
  188. }
  189. if (!_acmMessages[i].cm_bRead) {
  190. _iActiveMessage = i;
  191. SyncScrollWithActive();
  192. return;
  193. }
  194. }
  195. }
  196. // select last unread message, or last message if all read
  197. void LastUnreadMessage(void)
  198. {
  199. BOOL bFound = FALSE;
  200. for(_iActiveMessage=_acmMessages.Count()-1; _iActiveMessage>=0; _iActiveMessage--) {
  201. if (!_acmMessages[_iActiveMessage].cm_bRead) {
  202. bFound = TRUE;
  203. break;
  204. }
  205. }
  206. if (!bFound) {
  207. _iActiveMessage = ClampDn<INDEX>(_acmMessages.Count()-1, 0);
  208. }
  209. SyncScrollWithActive();
  210. }
  211. // go to next/previous message
  212. void PrevMessage(void)
  213. {
  214. if (_iActiveMessage<_acmMessages.Count()==0) {
  215. return;
  216. }
  217. _iActiveMessage--;
  218. if (_iActiveMessage<0) {
  219. _iActiveMessage = 0;
  220. }
  221. SyncScrollWithActive();
  222. }
  223. void NextMessage(void)
  224. {
  225. if (_iActiveMessage<_acmMessages.Count()==0) {
  226. return;
  227. }
  228. _iActiveMessage++;
  229. if (_iActiveMessage>=_acmMessages.Count()) {
  230. _iActiveMessage = _acmMessages.Count()-1;
  231. }
  232. SyncScrollWithActive();
  233. }
  234. void MessagesUpDn(INDEX ctLines)
  235. {
  236. INDEX ctMessages = _acmMessages.Count();
  237. _iWantedFirstMessageOnScreen += ctLines;
  238. INDEX iMaxFirst = ClampDn(0L, ctMessages-_ctMessagesOnScreen);
  239. _iWantedFirstMessageOnScreen = Clamp(_iWantedFirstMessageOnScreen, 0L, iMaxFirst);
  240. _iActiveMessage = Clamp(_iActiveMessage,
  241. _iWantedFirstMessageOnScreen,
  242. _iWantedFirstMessageOnScreen+_ctMessagesOnScreen-1L);
  243. }
  244. void SelectMessage(INDEX i)
  245. {
  246. if (_acmMessages.Count()==0) {
  247. return;
  248. }
  249. _iActiveMessage = i;
  250. if (_iActiveMessage<0) {
  251. _iActiveMessage = 0;
  252. }
  253. if (_iActiveMessage>=_acmMessages.Count()) {
  254. _iActiveMessage = _acmMessages.Count()-1;
  255. }
  256. SyncScrollWithActive();
  257. }
  258. // scroll message text
  259. void MessageTextUp(INDEX ctLines)
  260. {
  261. _iTextLineOnScreen-=ctLines;
  262. if (_iTextLineOnScreen<0) {
  263. _iTextLineOnScreen = 0;
  264. }
  265. }
  266. void MessageTextDn(INDEX ctLines)
  267. {
  268. // if no message do nothing
  269. if (_iActiveMessage<_acmMessages.Count()==0) {
  270. return;
  271. }
  272. // find text lines count
  273. _acmMessages[_iActiveMessage].PrepareMessage(_ctTextCharsPerRow);
  274. INDEX ctTextLines = _acmMessages[_iActiveMessage].cm_ctFormattedLines;
  275. // calculate maximum value for first visible line
  276. INDEX iFirstLine = ctTextLines-_ctTextLinesOnScreen;
  277. if (iFirstLine<0) {
  278. iFirstLine = 0;
  279. }
  280. // increment
  281. _iTextLineOnScreen+=ctLines;
  282. if (_iTextLineOnScreen>iFirstLine) {
  283. _iTextLineOnScreen = iFirstLine;
  284. }
  285. }
  286. void MessageTextUpDn(INDEX ctLines)
  287. {
  288. if (ctLines>0) {
  289. MessageTextDn(ctLines);
  290. } else if (ctLines<0) {
  291. MessageTextUp(-ctLines);
  292. }
  293. }
  294. // mark current message as read
  295. void MarkCurrentRead(void)
  296. {
  297. if (_iActiveMessage>=_acmMessages.Count()) {
  298. return;
  299. }
  300. // if running in background
  301. if (_pGame->gm_csComputerState == CS_ONINBACKGROUND) {
  302. // do nothing
  303. return;
  304. }
  305. ASSERT(_ppenPlayer!=NULL);
  306. if (_ppenPlayer==NULL) {
  307. return;
  308. }
  309. // if already read
  310. if (_acmMessages[_iActiveMessage].cm_bRead) {
  311. // do nothing
  312. return;
  313. }
  314. // mark as read
  315. _ppenPlayer->m_ctUnreadMessages--;
  316. _acmMessages[_iActiveMessage].MarkRead();
  317. }
  318. // update scroll position for message list
  319. static void UpdateFirstOnScreen(void)
  320. {
  321. if (_iFirstMessageOnScreen==_iWantedFirstMessageOnScreen) {
  322. return;
  323. }
  324. _iFirstMessageOnScreen=_iWantedFirstMessageOnScreen;
  325. ASSERT(
  326. _iFirstMessageOnScreen>=0&&
  327. _iFirstMessageOnScreen<=_acmMessages.Count());
  328. _iFirstMessageOnScreen = Clamp(_iFirstMessageOnScreen, INDEX(0), _acmMessages.Count());
  329. // for each message
  330. for(INDEX i=0; i<_acmMessages.Count(); i++) {
  331. CCompMessage &cm = _acmMessages[i];
  332. // if on screen
  333. if (i>=_iWantedFirstMessageOnScreen
  334. &&i<_iWantedFirstMessageOnScreen+_ctMessagesOnScreen) {
  335. // load
  336. cm.PrepareMessage(_ctTextCharsPerRow);
  337. // if not on screen
  338. } else {
  339. // unload
  340. cm.UnprepareMessage();
  341. }
  342. }
  343. }
  344. // update current active message category
  345. static void UpdateType(BOOL bForce=FALSE)
  346. {
  347. if (_cmtCurrentType==_cmtWantedType && !bForce) {
  348. return;
  349. }
  350. // cleare message cache
  351. _acmMessages.Clear();
  352. // for each player's message
  353. CDynamicStackArray<CCompMessageID> &acmiMsgs = _ppenPlayer->m_acmiMessages;
  354. for(INDEX i=0; i<acmiMsgs.Count(); i++) {
  355. CCompMessageID &cmi = acmiMsgs[i];
  356. // if it is of given type
  357. if (cmi.cmi_cmtType == _cmtWantedType) {
  358. // add it to cache
  359. CCompMessage &cm = _acmMessages.Push();
  360. cm.SetMessage(&cmi);
  361. }
  362. }
  363. if (!bForce) {
  364. _cmtCurrentType=_cmtWantedType;
  365. _iFirstMessageOnScreen = -1;
  366. _iWantedFirstMessageOnScreen = 0;
  367. _iActiveMessage = 0;
  368. _iLastActiveMessage = -2;
  369. _iTextLineOnScreen = 0;
  370. LastUnreadMessage();
  371. UpdateFirstOnScreen();
  372. }
  373. }
  374. static void UpdateMessageAppearing(void)
  375. {
  376. if (_iLastActiveMessage!=_iActiveMessage) {
  377. _pShell->Execute("FreeUnusedStock();"); // make sure user doesn't overflow memory
  378. _iTextLineOnScreen = 0;
  379. _iLastActiveMessage=_iActiveMessage;
  380. _tvMessageAppear = _pTimer->GetHighPrecisionTimer();
  381. }
  382. CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
  383. _fMsgAppearDelta = (tvNow-_tvMessageAppear).GetSeconds();
  384. if (fComputerFadeValue<0.99f) {
  385. _tvMessageAppear = _pTimer->GetHighPrecisionTimer();
  386. _fMsgAppearDelta = 0.0f;
  387. }
  388. _fMsgAppearFade = Clamp(_fMsgAppearDelta/0.5f, 0.0f,1.0f);
  389. }
  390. // update screen geometry
  391. static void UpdateSize(CDrawPort *pdp)
  392. {
  393. // get screen size
  394. PIX pixSizeI = pdp->GetWidth();
  395. PIX pixSizeJ = pdp->GetHeight();
  396. // remember new size
  397. _pixSizeI = pixSizeI;
  398. _pixSizeJ = pixSizeJ;
  399. // determine scaling
  400. _fScaling = 1.0f;
  401. _fScaling2 = 1.0f;
  402. if (pixSizeJ<384) {
  403. _fScaling = 1.0f;
  404. _fScaling2 = pixSizeJ/480.0f;
  405. }
  406. // remember font size
  407. CFontData *pfd = _pfdConsoleFont;
  408. _pixCharSizeI = pfd->fd_pixCharWidth + pfd->fd_pixCharSpacing;
  409. _pixCharSizeJ = pfd->fd_pixCharHeight + pfd->fd_pixLineSpacing;
  410. _pixCharSize2I = _pixCharSizeI*_fScaling2;
  411. _pixCharSize2J = _pixCharSizeJ*_fScaling2;
  412. _pixCharSizeI = _pixCharSizeI*_fScaling;
  413. _pixCharSizeJ = _pixCharSizeJ*_fScaling;
  414. _pixMarginI = 5*_fScaling2;
  415. _pixMarginJ = 5*_fScaling2;
  416. PIX pixBoxMarginI = 10*_fScaling2;
  417. PIX pixBoxMarginJ = 10*_fScaling2;
  418. PIX pixJ0Dn = pixBoxMarginJ;
  419. PIX pixJ1Up = pixJ0Dn+_pixCharSize2J+_pixMarginI*2;
  420. PIX pixJ1Dn = pixJ1Up+pixBoxMarginJ;
  421. PIX pixJ2Up = pixJ1Dn+_pixCharSize2J*6*2+pixBoxMarginJ;
  422. PIX pixJ2Dn = pixJ2Up+pixBoxMarginJ;
  423. PIX pixJ3Up = _pixSizeJ-pixBoxMarginJ;
  424. PIX pixI0Rt = pixBoxMarginI;
  425. PIX pixI1Lt = pixI0Rt+_pixCharSize2I*20+pixBoxMarginI;
  426. PIX pixI1Rt = pixI1Lt+pixBoxMarginI;
  427. PIX pixI2Lt = _pixSizeI/2-pixBoxMarginI/2;
  428. PIX pixI2Rt = _pixSizeI/2+pixBoxMarginI/2;
  429. PIX pixI4Lt = _pixSizeI-pixBoxMarginI;
  430. PIX pixI3Rt = pixI4Lt-pixBoxMarginI*2-_pixCharSize2I*10;
  431. PIX pixI3Lt = pixI3Rt-pixBoxMarginI;
  432. // calculate box sizes
  433. _boxTitle = PIXaabbox2D( PIX2D(0, pixJ0Dn-1), PIX2D(pixI3Lt, pixJ1Up));
  434. _boxExit = PIXaabbox2D( PIX2D( pixI3Rt, pixJ0Dn-1), PIX2D(_pixSizeI, pixJ1Up));
  435. PIX pixD = 5;
  436. PIX pixH = (pixJ2Up-pixJ1Dn-pixD*(CMT_COUNT-1))/CMT_COUNT;
  437. INDEX i;
  438. for( i=0; i<CMT_COUNT; i++) {
  439. _boxButton[i] = PIXaabbox2D(
  440. PIX2D(0, pixJ1Dn+(pixH+pixD)*i),
  441. PIX2D(pixI1Lt, pixJ1Dn+(pixH+pixD)*i+pixH));
  442. }
  443. _boxMsgList = PIXaabbox2D( PIX2D(pixI1Rt, pixJ1Dn), PIX2D(pixI4Lt, pixJ2Up));
  444. if (GetSP()->sp_bCooperative) {
  445. _boxMsgText = PIXaabbox2D( PIX2D(pixI2Rt, pixJ2Dn), PIX2D(pixI4Lt, pixJ3Up));
  446. _boxMsgImage= PIXaabbox2D( PIX2D(pixI0Rt, pixJ2Dn), PIX2D(pixI2Lt, pixJ3Up));
  447. } else {
  448. _boxMsgText = PIXaabbox2D( PIX2D(pixI0Rt, pixJ2Dn), PIX2D(pixI4Lt, pixJ3Up));
  449. _boxMsgImage= PIXaabbox2D();
  450. }
  451. FLOAT fSlideSpeed = Max(_pixSizeI, _pixSizeJ*2L);
  452. FLOAT fGroup0 = ClampDn((1-fComputerFadeValue)*fSlideSpeed-_pixSizeJ, 0.0f);
  453. FLOAT fGroup1 = (1-fComputerFadeValue)*fSlideSpeed;
  454. // animate box positions
  455. _boxTitle -= PIX2D( fGroup1, 0);
  456. _boxExit += PIX2D( fGroup1, 0);
  457. for( i=0; i<CMT_COUNT; i++) {
  458. FLOAT fOffs = ClampDn(fGroup1-(CMT_COUNT-i)*_pixMarginJ*10, 0.0f);
  459. _boxButton[i] -= PIX2D(fOffs, 0);
  460. }
  461. _boxMsgList -= PIX2D(0, fGroup0);
  462. _boxMsgText += PIX2D(fGroup0, 0);
  463. _boxMsgImage+= PIX2D(0, fGroup0);
  464. _ctMessagesOnScreen = (_boxMsgList.Size()(2) - _pixMarginJ*2) / _pixCharSizeJ;
  465. _ctTextCharsPerRow = (_boxMsgText.Size()(1) - _pixMarginI*4) / _pixCharSizeI;
  466. _ctTextLinesOnScreen = (_boxMsgText.Size()(2) - _pixMarginJ*2 - _pixMarginJ*4) / _pixCharSizeJ;
  467. }
  468. static char *_astrButtonTexts[CMT_COUNT];
  469. // print message type buttons
  470. void PrintButton(CDrawPort *pdp, INDEX iButton)
  471. {
  472. CDrawPort dpButton(pdp, _boxButton[iButton]);
  473. if (!dpButton.Lock()) {
  474. return;
  475. }
  476. LCDSetDrawport(&dpButton);
  477. _pGame->LCDRenderCompGrid();
  478. LCDRenderClouds2();
  479. LCDScreenBoxOpenLeft(_colBoxes);
  480. SetFont2(&dpButton);
  481. // count messages
  482. INDEX ctTotal=0;
  483. INDEX ctRead=0;
  484. CDynamicStackArray<CCompMessageID> &acmiMsgs = _ppenPlayer->m_acmiMessages;
  485. {for(INDEX i=0; i<acmiMsgs.Count(); i++) {
  486. CCompMessageID &cmi = acmiMsgs[i];
  487. if (cmi.cmi_cmtType==iButton) {
  488. ctTotal++;
  489. if (cmi.cmi_bRead) {
  490. ctRead++;
  491. }
  492. }
  493. }}
  494. INDEX ctUnread = ctTotal-ctRead;
  495. // prepare color
  496. COLOR col = _colMedium;
  497. if (iButton==_cmtCurrentType) {
  498. col = _colLight;
  499. }
  500. col = MouseOverColor(_boxButton[iButton], col, _colDark, _colLight);
  501. // prepare string
  502. CTString str;
  503. if (ctUnread==0) {
  504. str = _astrButtonTexts[iButton];
  505. } else {
  506. str.PrintF("%s (%d)", _astrButtonTexts[iButton], ctUnread);
  507. }
  508. // print it
  509. dpButton.PutTextR( str, _boxButton[iButton].Size()(1)-_pixMarginI, _pixCharSize2J/2+1, col);
  510. dpButton.Unlock();
  511. }
  512. // print title
  513. void PrintTitle(CDrawPort *pdp)
  514. {
  515. SetFont2(pdp);
  516. CTString strTitle;
  517. strTitle.PrintF(TRANS("NETRICSA v2.01 - personal version for: %s"),
  518. _ppenPlayer->GetPlayerName());
  519. pdp->PutText( strTitle, _pixMarginI*3, _pixMarginJ-2*_fScaling2+1, _colMedium);
  520. }
  521. // print exit button
  522. void PrintExit(CDrawPort *pdp)
  523. {
  524. SetFont2(pdp);
  525. pdp->PutTextR( TRANS("Exit"), _boxExit.Size()(1)-_pixMarginI*3, _pixMarginJ-2*_fScaling2+1,
  526. MouseOverColor(_boxExit, _colMedium, _colDark, _colLight));
  527. }
  528. // print list of messages
  529. void PrintMessageList(CDrawPort *pdp)
  530. {
  531. PIX pixTextX = _pixMarginI;
  532. PIX pixYLine = _pixMarginJ;
  533. SetFont1(pdp);
  534. INDEX iFirst = _iFirstMessageOnScreen;
  535. INDEX iLast = Min(INDEX(_iFirstMessageOnScreen+_ctMessagesOnScreen), _acmMessages.Count())-1;
  536. if (iFirst>iLast) {
  537. pdp->PutText( TRANS("no messages"), pixTextX, pixYLine, _colDark);
  538. }
  539. for(INDEX i=iFirst; i<=iLast; i++) {
  540. COLOR col = _colMedium;
  541. if (_acmMessages[i].cm_bRead) {
  542. col = _colDark;
  543. }
  544. if (i==_iActiveMessage) {
  545. col = _colLight;
  546. }
  547. if (GetMsgListBox(i-_iFirstMessageOnScreen)>=_vpixMouse) {
  548. col = LCDBlinkingColor(_colLight, _colMedium);
  549. }
  550. pdp->PutText( _acmMessages[i].cm_strSubject, pixTextX, pixYLine, col);
  551. pixYLine+=_pixCharSizeJ;
  552. }
  553. PIXaabbox2D boxSliderSpace = GetMsgSliderSpace();
  554. LCDDrawBox(0,0,boxSliderSpace, _colBoxes);
  555. PIXaabbox2D boxSlider = GetMsgSliderBox();
  556. COLOR col = _colBoxes;
  557. PIXaabbox2D boxSliderTrans = boxSlider;
  558. boxSliderTrans+=_boxMsgList.Min();
  559. if (boxSliderTrans>=_vpixMouse) {
  560. col = LCDBlinkingColor(_colLight, _colDark);
  561. }
  562. pdp->Fill( boxSlider.Min()(1)+2, boxSlider.Min()(2)+2,
  563. boxSlider.Size()(1)-4, boxSlider.Size()(2)-4, col);
  564. }
  565. // print text of current message
  566. void PrintMessageText(CDrawPort *pdp)
  567. {
  568. if (_acmMessages.Count()==0 ||
  569. _iActiveMessage>=_acmMessages.Count()||
  570. fComputerFadeValue<0.99f) {
  571. return;
  572. }
  573. SetFont2(pdp);
  574. // print subject
  575. CTString strSubject0;
  576. CTString strSubject1;
  577. CTString strSubject2;
  578. //strSubject.PrintF("%g", _fMsgAppearFade);
  579. const char *strSubject = _acmMessages[_iActiveMessage].cm_strSubject;
  580. INDEX ctSubjectLen = strlen(strSubject);
  581. INDEX ctToPrint = int(_fMsgAppearDelta*20.0f);
  582. for (INDEX iChar=0; iChar<ctSubjectLen; iChar++) {
  583. char strChar[2];
  584. strChar[0] = strSubject[iChar];
  585. strChar[1] = 0;
  586. if (iChar>ctToPrint) {
  587. NOTHING;
  588. } else if (iChar==ctToPrint) {
  589. strSubject2+=strChar;
  590. } else if (iChar==ctToPrint-1) {
  591. strSubject1+=strChar;
  592. } else {
  593. strSubject0+=strChar;
  594. }
  595. }
  596. PIX pixWidth0 = pdp->GetTextWidth(strSubject0);
  597. PIX pixWidth1 = pdp->GetTextWidth(strSubject1);
  598. pdp->PutText(strSubject0, _pixMarginI, _pixMarginJ-1, _colMedium);
  599. pdp->PutText(strSubject1, _pixMarginI+pixWidth0, _pixMarginJ-1, LerpColor( _colLight, _colMedium, 0.5f));
  600. pdp->PutText(strSubject2, _pixMarginI+pixWidth0+pixWidth1, _pixMarginJ-1, _colLight);
  601. pdp->DrawLine(0, PIX(_pixMarginJ*4), _boxMsgText.Size()(1), PIX(_pixMarginJ*4), _colBoxes);
  602. // fill in fresh player statistics
  603. if (strncmp(_acmMessages[_iActiveMessage].cm_strText, "$STAT", 5)==0) {
  604. _ppenPlayer->GetStats(_strStatsDetails, CST_DETAIL, _ctTextCharsPerRow);
  605. _acmMessages[_iActiveMessage].cm_ctFormattedWidth = 0;
  606. }
  607. // format text
  608. _acmMessages[_iActiveMessage].PrepareMessage(_ctTextCharsPerRow);
  609. SetFont1(pdp);
  610. INDEX ctLineToPrint = int(_fMsgAppearDelta*20.0f);
  611. // print it
  612. PIX pixJ = _pixMarginJ*4;
  613. for (INDEX iLine = _iTextLineOnScreen;
  614. iLine<_iTextLineOnScreen+_ctTextLinesOnScreen;
  615. iLine++) {
  616. INDEX iPrintLine = iLine-_iTextLineOnScreen;
  617. if (iPrintLine>ctLineToPrint) {
  618. continue;
  619. }
  620. COLOR col = LerpColor( _colLight, _colMedium, Clamp( FLOAT(ctLineToPrint-iPrintLine)/3, 0.0f, 1.0f));
  621. pdp->PutText(_acmMessages[_iActiveMessage].GetLine(iLine),
  622. _pixMarginI, pixJ, col);
  623. pixJ+=_pixCharSizeJ;
  624. }
  625. PIXaabbox2D boxSliderSpace = GetTextSliderSpace();
  626. LCDDrawBox(0,0,boxSliderSpace, _colBoxes);
  627. PIXaabbox2D boxSlider = GetTextSliderBox();
  628. COLOR col = _colBoxes;
  629. PIXaabbox2D boxSliderTrans = boxSlider;
  630. boxSliderTrans+=_boxMsgText.Min();
  631. if (boxSliderTrans>=_vpixMouse) {
  632. col = LCDBlinkingColor(_colLight, _colDark);
  633. }
  634. pdp->Fill( boxSlider.Min()(1)+2, boxSlider.Min()(2)+2,
  635. boxSlider.Size()(1)-4, boxSlider.Size()(2)-4, col);
  636. }
  637. void RenderMessagePicture(CDrawPort *pdp)
  638. {
  639. CCompMessage &cm = _acmMessages[_iActiveMessage];
  640. // try to
  641. try {
  642. // load image
  643. _toPicture.SetData_t(cm.cm_fnmPicture);
  644. ((CTextureData*)_toPicture.GetData())->Force(TEX_CONSTANT);
  645. // if failed
  646. } catch(char *strError) {
  647. // report error
  648. CPrintF("Cannot load '%s':\n%s\n", (CTString&)cm.cm_fnmPicture, strError);
  649. // do nothing
  650. return;
  651. }
  652. // get image and box sizes
  653. PIX pixImgSizeI = _toPicture.GetWidth();
  654. PIX pixImgSizeJ = _toPicture.GetHeight();
  655. PIXaabbox2D boxPic(PIX2D(_pixMarginI, _pixMarginJ),
  656. PIX2D(_boxMsgImage.Size()(1)-_pixMarginI, _boxMsgImage.Size()(2)-_pixMarginJ));
  657. PIX pixBoxSizeI = boxPic.Size()(1);
  658. PIX pixBoxSizeJ = boxPic.Size()(2);
  659. PIX pixCenterI = _boxMsgImage.Size()(1)/2;
  660. PIX pixCenterJ = _boxMsgImage.Size()(2)/2;
  661. // find image stretch to fit in box
  662. FLOAT fStretch = Min(FLOAT(pixBoxSizeI)/pixImgSizeI, FLOAT(pixBoxSizeJ)/pixImgSizeJ);
  663. // draw the image
  664. pdp->PutTexture(&_toPicture,
  665. PIXaabbox2D(
  666. PIX2D(pixCenterI-pixImgSizeI*fStretch/2, pixCenterJ-pixImgSizeJ*fStretch/2),
  667. PIX2D(pixCenterI+pixImgSizeI*fStretch/2, pixCenterJ+pixImgSizeJ*fStretch/2)));
  668. }
  669. void RenderMessageStats(CDrawPort *pdp)
  670. {
  671. CSessionProperties *psp = (CSessionProperties *)_pNetwork->GetSessionProperties();
  672. ULONG ulLevelMask = psp->sp_ulLevelsMask;
  673. INDEX iLevel = -1;
  674. if (psp->sp_bCooperative) {
  675. extern void RenderMap( CDrawPort *pdp, ULONG ulLevelMask, CProgressHookInfo *pphi);
  676. if (pdp->Lock()) {
  677. // get sizes
  678. PIX pixSizeI = pdp->GetWidth();
  679. PIX pixSizeJ = pdp->GetHeight();
  680. // clear bcg
  681. pdp->Fill( 1, 1, pixSizeI-2, pixSizeJ-2, C_BLACK|CT_OPAQUE);
  682. // render the map if not fading
  683. COLOR colFade = LCDFadedColor(C_WHITE|255);
  684. if( (colFade&255) == 255) {
  685. RenderMap( pdp, ulLevelMask, NULL);
  686. }
  687. pdp->Unlock();
  688. }
  689. }
  690. }
  691. extern void RenderMessageModel(CDrawPort *pdp, const CTString &strModel);
  692. // draw image of current message
  693. void RenderMessageImage(CDrawPort *pdp)
  694. {
  695. if (!GetSP()->sp_bCooperative) {
  696. return;
  697. }
  698. // if no message
  699. if (_acmMessages.Count()==0 || fComputerFadeValue<0.99f) {
  700. // render empty
  701. LCDRenderClouds2();
  702. LCDScreenBox(_colBoxes);
  703. return;
  704. }
  705. CCompMessage &cm = _acmMessages[_iActiveMessage];
  706. if (cm.cm_itImage == CCompMessage::IT_STATISTICS) {
  707. _pGame->LCDRenderCompGrid();
  708. }
  709. LCDRenderClouds2();
  710. LCDScreenBox(_colBoxes);
  711. // if no image
  712. if (cm.cm_itImage == CCompMessage::IT_NONE) {
  713. // do nothing
  714. return;
  715. } else if (cm.cm_itImage == CCompMessage::IT_PICTURE) {
  716. RenderMessagePicture(pdp);
  717. } else if (cm.cm_itImage == CCompMessage::IT_STATISTICS) {
  718. RenderMessageStats(pdp);
  719. } else if (cm.cm_itImage == CCompMessage::IT_MODEL) {
  720. RenderMessageModel(pdp, cm.cm_strModel);
  721. } else {
  722. ASSERT(FALSE);
  723. }
  724. }
  725. // find first group with some unread message
  726. static BOOL FindGroupWithUnread(void)
  727. {
  728. CDynamicStackArray<CCompMessageID> &acmiMsgs = _ppenPlayer->m_acmiMessages;
  729. for(INDEX i=acmiMsgs.Count()-1; i>=0; i--) {
  730. CCompMessageID &cmi = acmiMsgs[i];
  731. // if it unread
  732. if (!cmi.cmi_bRead) {
  733. _cmtWantedType = cmi.cmi_cmtType;
  734. return TRUE;
  735. }
  736. }
  737. // if none found, select statistics
  738. _cmtWantedType = CMT_STATISTICS;
  739. return FALSE;
  740. }
  741. static void ComputerOn(void)
  742. {
  743. // init button names
  744. _astrButtonTexts[CMT_INFORMATION ] = TRANS("tactical data");
  745. _astrButtonTexts[CMT_BACKGROUND ] = TRANS("strategic data");
  746. _astrButtonTexts[CMT_WEAPONS ] = TRANS("weapons");
  747. _astrButtonTexts[CMT_ENEMIES ] = TRANS("enemies");
  748. _astrButtonTexts[CMT_STATISTICS ] = TRANS("statistics");
  749. _iFirstMessageOnScreen = -1;
  750. _iWantedFirstMessageOnScreen = 0;
  751. _iActiveMessage = 0;
  752. _cmtCurrentType = (enum CompMsgType)-1;
  753. _cmtWantedType = CMT_INFORMATION;
  754. _acmMessages.Clear();
  755. ASSERT(_ppenPlayer!=NULL);
  756. if (_ppenPlayer==NULL) {
  757. return;
  758. }
  759. // fill in player statistics
  760. _ppenPlayer->GetStats(_strStatsDetails, CST_DETAIL, _ctTextCharsPerRow);
  761. // if end of level
  762. if (_ppenPlayer->m_bEndOfLevel || _pNetwork->IsGameFinished()) {
  763. // select statistics
  764. _cmtWantedType = CMT_STATISTICS;
  765. // if not end of level
  766. } else {
  767. // find group with some unread messages
  768. FindGroupWithUnread();
  769. }
  770. }
  771. static void ComputerOff(void)
  772. {
  773. _acmMessages.Clear();
  774. _pShell->Execute("FreeUnusedStock();");
  775. }
  776. static void ExitRequested(void)
  777. {
  778. // if end of game
  779. if (_ppenPlayer!=NULL && _ppenPlayer->m_bEndOfGame || _pNetwork->IsGameFinished()) {
  780. // if in single player
  781. if (GetSP()->sp_bSinglePlayer) {
  782. // request app to show high score
  783. _pShell->Execute("sam_bMenuHiScore=1;");
  784. }
  785. // hard turn off
  786. _pGame->gm_csComputerState = CS_OFF;
  787. fComputerFadeValue = 0.0f;
  788. ComputerOff();
  789. cmp_ppenPlayer = NULL;
  790. // stop current game
  791. _pGame->StopGame();
  792. // if not end of level
  793. } else {
  794. // if can be rendered on second display
  795. if (cmp_ppenDHPlayer!=NULL) {
  796. // clear pressed keys
  797. _pInput->ClearInput();
  798. // just switch to background fast
  799. _pGame->gm_csComputerState = CS_ONINBACKGROUND;
  800. cmp_ppenPlayer = NULL;
  801. // if no second display
  802. } else {
  803. // start turning off
  804. _pGame->gm_csComputerState = CS_TURNINGOFF;
  805. }
  806. }
  807. // turn off end of level for player
  808. if (_ppenPlayer!=NULL) {
  809. _ppenPlayer->m_bEndOfLevel = FALSE;
  810. }
  811. }
  812. void CGame::ComputerMouseMove(PIX pixX, PIX pixY)
  813. {
  814. _vpixMouse(1) += pixX-_vpixExternMouse(1);
  815. _vpixMouse(2) += pixY-_vpixExternMouse(2);
  816. _vpixExternMouse(1) = pixX;
  817. _vpixExternMouse(2) = pixY;
  818. // if dragging
  819. if (_pixSliderDragJ>=0) {
  820. PIX pixDelta = _vpixMouse(2)-_pixSliderDragJ;
  821. if (_bSliderDragText) {
  822. if (_iActiveMessage<_acmMessages.Count()) {
  823. INDEX ctTextLines = _acmMessages[_iActiveMessage].cm_ctFormattedLines;
  824. INDEX iWantedLine = _iSliderDragLine+
  825. SliderPixToIndex(pixDelta, _ctTextLinesOnScreen, ctTextLines, GetTextSliderSpace());
  826. MessageTextUpDn(iWantedLine-_iTextLineOnScreen);
  827. }
  828. } else {
  829. INDEX ctLines = _acmMessages.Count();
  830. INDEX iWantedLine = _iSliderDragLine+
  831. SliderPixToIndex(pixDelta, _ctMessagesOnScreen, ctLines, GetMsgSliderSpace());
  832. MessagesUpDn(iWantedLine-_iFirstMessageOnScreen);
  833. }
  834. }
  835. }
  836. void CGame::ComputerKeyDown(MSG msg)
  837. {
  838. static BOOL bRDown = FALSE;
  839. // if computer is not active
  840. if (_pGame->gm_csComputerState!=CS_ON && _pGame->gm_csComputerState!=CS_TURNINGON) {
  841. // do nothing
  842. return;
  843. }
  844. // if escape pressed
  845. if (msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE) {
  846. ExitRequested();
  847. }
  848. // if right mouse pressed
  849. if (msg.message==WM_RBUTTONDOWN || msg.message==WM_RBUTTONDBLCLK) {
  850. bRDown = TRUE;
  851. }
  852. // if right mouse released
  853. if (bRDown && msg.message==WM_RBUTTONUP) {
  854. bRDown = FALSE;
  855. // mark current message as read
  856. MarkCurrentRead();
  857. // find a group with first unread message
  858. BOOL bHasUnread = FindGroupWithUnread();
  859. // if some
  860. if (bHasUnread) {
  861. // select first unread message in it
  862. NextUnreadMessage();
  863. } else {
  864. ExitRequested();
  865. }
  866. }
  867. if (msg.message==WM_KEYDOWN) {
  868. switch (msg.wParam) {
  869. // change message types on number keys
  870. case '1': _cmtWantedType = CMT_INFORMATION ; return;
  871. case '2': _cmtWantedType = CMT_WEAPONS ; return;
  872. case '3': _cmtWantedType = CMT_ENEMIES ; return;
  873. case '4': _cmtWantedType = CMT_BACKGROUND ; return;
  874. case '5': _cmtWantedType = CMT_STATISTICS ; return;
  875. // go to next unread
  876. case 'U':
  877. case VK_SPACE:
  878. NextUnreadMessage(); return;
  879. // scroll message list
  880. case 219: PrevMessage(); return;
  881. case 221: NextMessage(); return;
  882. // mark current message as read and go to next
  883. case VK_RETURN: MarkCurrentRead(); NextUnreadMessage(); return;
  884. // scroll message text
  885. case VK_UP: MessageTextUp(1); return;
  886. case VK_DOWN: MessageTextDn(1); return;
  887. case VK_PRIOR:MessageTextUp(_ctTextLinesOnScreen-1); return;
  888. case VK_NEXT: MessageTextDn(_ctTextLinesOnScreen-1); return;
  889. };
  890. }
  891. // if left mouse pressed
  892. if (msg.message==WM_LBUTTONDOWN || msg.message==WM_LBUTTONDBLCLK) {
  893. BOOL bOverMsgSlider = FALSE;
  894. // if over slider
  895. {PIXaabbox2D boxSlider = GetTextSliderBox();
  896. PIXaabbox2D boxSliderTrans = boxSlider;
  897. boxSliderTrans+=_boxMsgText.Min();
  898. if (boxSliderTrans>=_vpixMouse) {
  899. bOverMsgSlider = TRUE;
  900. // start dragging
  901. _bSliderDragText = TRUE;
  902. _pixSliderDragJ=_vpixMouse(2);
  903. _iSliderDragLine = _iTextLineOnScreen;
  904. }}
  905. // if over slider
  906. {PIXaabbox2D boxSlider = GetMsgSliderBox();
  907. PIXaabbox2D boxSliderTrans = boxSlider;
  908. boxSliderTrans+=_boxMsgList.Min();
  909. if (boxSliderTrans>=_vpixMouse) {
  910. // start dragging
  911. _bSliderDragText = FALSE;
  912. _pixSliderDragJ=_vpixMouse(2);
  913. _iSliderDragLine = _iFirstMessageOnScreen;
  914. }}
  915. // if over some button
  916. {for(INDEX i=0; i<CMT_COUNT; i++) {
  917. if (_boxButton[i]>=_vpixMouse) {
  918. // switch to that message type
  919. _cmtWantedType = (CompMsgType)i;
  920. }
  921. }}
  922. // if over some message
  923. {for(INDEX i=0; i<_ctMessagesOnScreen; i++) {
  924. if (GetMsgListBox(i)>=_vpixMouse && !bOverMsgSlider) {
  925. // switch to that message
  926. SelectMessage(_iFirstMessageOnScreen+i);
  927. }
  928. }}
  929. }
  930. // if left mouse released
  931. if (msg.message==WM_LBUTTONUP) {
  932. // stop dragging
  933. _pixSliderDragJ=-1;
  934. // if over exit
  935. if (_boxExit>=_vpixMouse) {
  936. // exit
  937. ExitRequested();
  938. }
  939. }
  940. }
  941. void CGame::ComputerRender(CDrawPort *pdp)
  942. {
  943. // if playing a demo
  944. if (_pNetwork->IsPlayingDemo()) {
  945. // never call computer
  946. cmp_ppenPlayer = NULL;
  947. }
  948. // disable netricsa for non-local players
  949. if (cmp_ppenPlayer!=NULL && !_pNetwork->IsPlayerLocal(cmp_ppenPlayer)) {
  950. cmp_ppenPlayer = NULL;
  951. }
  952. if (cmp_ppenDHPlayer!=NULL && !_pNetwork->IsPlayerLocal(cmp_ppenDHPlayer)) {
  953. cmp_ppenDHPlayer = NULL;
  954. }
  955. if (cmp_ppenDHPlayer!=NULL && !pdp->IsDualHead()) {
  956. cmp_ppenDHPlayer = NULL;
  957. }
  958. // initially - no player
  959. _ppenPlayer=NULL;
  960. // if player calls computer
  961. if (cmp_ppenPlayer!=NULL) {
  962. // use that player
  963. _ppenPlayer = cmp_ppenPlayer;
  964. // if computer is on in background
  965. if (_pGame->gm_csComputerState==CS_ONINBACKGROUND) {
  966. // just toggle to on
  967. _pGame->gm_csComputerState=CS_ON;
  968. // find group with some unread messages
  969. FindGroupWithUnread();
  970. // force reinit
  971. _cmtCurrentType = (enum CompMsgType)-1;
  972. }
  973. // if using dualhead to render computer on second display
  974. } else if (cmp_ppenDHPlayer!=NULL) {
  975. // use that player
  976. _ppenPlayer = cmp_ppenDHPlayer;
  977. // clear dualhead request - it has to be reinitialized every frame
  978. cmp_ppenDHPlayer = NULL;
  979. // if viewing statistics
  980. if (_cmtWantedType == CMT_STATISTICS) {
  981. // fill in fresh player statistics
  982. _ppenPlayer->GetStats(_strStatsDetails, CST_DETAIL, _ctTextCharsPerRow);
  983. // force updating
  984. UpdateType(TRUE);
  985. }
  986. // if computer is not on or on in background
  987. if (_pGame->gm_csComputerState!=CS_ON && _pGame->gm_csComputerState!=CS_ONINBACKGROUND) {
  988. // switch on fast
  989. ComputerOn();
  990. fComputerFadeValue = 1.0f;
  991. _pGame->gm_csComputerState = CS_ONINBACKGROUND;
  992. cmp_bInitialStart = FALSE; // end of eventual initial start
  993. }
  994. // if should update to new message
  995. if (cmp_bUpdateInBackground) {
  996. cmp_bUpdateInBackground = FALSE;
  997. FindGroupWithUnread();
  998. // force reinit
  999. _cmtCurrentType = (enum CompMsgType)-1;
  1000. }
  1001. }
  1002. // if no player
  1003. if (_ppenPlayer==NULL) {
  1004. // make sure computer is off
  1005. _pGame->gm_csComputerState=CS_OFF;
  1006. // do nothing more
  1007. return;
  1008. }
  1009. // if computer is not active
  1010. if (_pGame->gm_csComputerState==CS_OFF) {
  1011. // just remember time
  1012. tvComputerLast = _pTimer->GetHighPrecisionTimer();
  1013. // if a player wants computer
  1014. if (_ppenPlayer!=NULL) {
  1015. // start turning on
  1016. _pGame->gm_csComputerState=CS_TURNINGON;
  1017. ComputerOn();
  1018. } else {
  1019. return;
  1020. }
  1021. }
  1022. // calculate up-down speed to be independent of refresh speed
  1023. CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
  1024. CTimerValue tvDelta = tvNow - tvComputerLast;
  1025. tvComputerLast = tvNow;
  1026. FLOAT fFadeSpeed = (FLOAT)(tvDelta.GetSeconds() / tmComputerFade);
  1027. // if computer is dropping down
  1028. if( _pGame->gm_csComputerState==CS_TURNINGON) {
  1029. // move it down
  1030. fComputerFadeValue += fFadeSpeed;
  1031. // if finished moving
  1032. if( fComputerFadeValue>1.0f) {
  1033. // stop
  1034. fComputerFadeValue = 1.0f;
  1035. _pGame->gm_csComputerState = CS_ON;
  1036. cmp_bInitialStart = FALSE; // end of eventual initial start
  1037. }
  1038. }
  1039. // if computer is pulling up
  1040. if( _pGame->gm_csComputerState==CS_TURNINGOFF) {
  1041. // move it up
  1042. fComputerFadeValue -= fFadeSpeed;
  1043. // if finished moving
  1044. if( fComputerFadeValue<0.0f) {
  1045. // stop
  1046. fComputerFadeValue = 0.0f;
  1047. _pGame->gm_csComputerState = CS_OFF;
  1048. ComputerOff();
  1049. cmp_ppenPlayer = NULL;
  1050. // exit computer
  1051. return;
  1052. }
  1053. }
  1054. // safety check -> do not proceed if no player
  1055. if (_ppenPlayer==NULL) {
  1056. return;
  1057. }
  1058. // lock drawport
  1059. CDrawPort dpComp(pdp, FALSE);
  1060. if(!dpComp.Lock()) {
  1061. // do nothing
  1062. return;
  1063. }
  1064. // if in fullscreen
  1065. CDisplayMode dmCurrent;
  1066. _pGfx->GetCurrentDisplayMode(dmCurrent);
  1067. if (dmCurrent.IsFullScreen() && dmCurrent.IsDualHead()) {
  1068. // clamp mouse pointer
  1069. _vpixMouse(1) = Clamp(_vpixMouse(1), 0L, dpComp.GetWidth());
  1070. _vpixMouse(2) = Clamp(_vpixMouse(2), 0L, dpComp.GetHeight());
  1071. // if in window
  1072. } else {
  1073. // use same mouse pointer as windows
  1074. _vpixMouse = _vpixExternMouse;
  1075. // if dualhead
  1076. if (dpComp.dp_MinI>0) {
  1077. // offset by half screen
  1078. _vpixMouse(1) -= dpComp.GetWidth();
  1079. }
  1080. // if widescreen
  1081. if (dpComp.dp_MinJ>0) {
  1082. // offset by screen top
  1083. _vpixMouse(2) -= dpComp.dp_MinJ;
  1084. }
  1085. }
  1086. TIME tmOld = _pTimer->CurrentTick();
  1087. FLOAT fLerpOld = _pTimer->GetLerpFactor();
  1088. FLOAT fSec = tvNow.GetSeconds();
  1089. TIME tmTick = floor(fSec/_pTimer->TickQuantum)*_pTimer->TickQuantum;
  1090. FLOAT fLerp = (fSec-tmTick)/_pTimer->TickQuantum;
  1091. _pTimer->SetCurrentTick(tmTick);
  1092. _pTimer->SetLerp(fLerp);
  1093. LCDPrepare(1.0f);//ClampUp(fComputerFadeValue*10,1.0f));
  1094. LCDSetDrawport(&dpComp);
  1095. // if initial start
  1096. if (cmp_bInitialStart) {
  1097. // do not allow game to show through
  1098. dpComp.Fill(C_BLACK|255);
  1099. // if normal start
  1100. } else {
  1101. // fade over game view
  1102. dpComp.Fill(LCDFadedColor(C_BLACK|255));
  1103. }
  1104. dpComp.FillZBuffer(1.0f);
  1105. // update screen geometry
  1106. UpdateSize(&dpComp);
  1107. // update scroll positions
  1108. UpdateType();
  1109. UpdateFirstOnScreen();
  1110. // check for message change
  1111. UpdateMessageAppearing();
  1112. // mark current message as read
  1113. MarkCurrentRead();
  1114. // get current time and alpha value
  1115. FLOAT tmNow = (FLOAT)tvNow.GetSeconds();
  1116. ULONG ulA = NormFloatToByte(fComputerFadeValue);
  1117. _colLight = LCDFadedColor(C_WHITE|255);
  1118. _colMedium = LCDFadedColor(SE_COL_BLUE_LIGHT|255);
  1119. _colDark = LCDFadedColor(LerpColor(SE_COL_BLUE_DARK, SE_COL_BLUE_LIGHT, 0.5f)|255);
  1120. _colBoxes = LCDFadedColor(LerpColor(SE_COL_BLUE_DARK, SE_COL_BLUE_LIGHT, 0.5f)|255);
  1121. // background
  1122. LCDRenderCloudsForComp();
  1123. // dpComp.DrawLine( 0, pixSizeJ-1, pixSizeI, pixSizeJ-1, C_GREEN|ulA);
  1124. // all done
  1125. dpComp.Unlock();
  1126. // print title
  1127. CDrawPort dpTitle(&dpComp, _boxTitle);
  1128. if (dpTitle.Lock()) {
  1129. LCDSetDrawport(&dpTitle);
  1130. LCDRenderCompGrid();
  1131. LCDRenderClouds2();
  1132. LCDScreenBoxOpenLeft(_colBoxes);
  1133. PrintTitle(&dpTitle);
  1134. dpTitle.Unlock();
  1135. }
  1136. // print exit button
  1137. CDrawPort dpExit(&dpComp, _boxExit);
  1138. if (dpExit.Lock()) {
  1139. LCDSetDrawport(&dpExit);
  1140. LCDRenderCompGrid();
  1141. LCDRenderClouds2();
  1142. LCDScreenBoxOpenRight(_colBoxes);
  1143. PrintExit(&dpExit);
  1144. dpExit.Unlock();
  1145. }
  1146. // print buttons
  1147. for (INDEX i=0; i<CMT_COUNT; i++) {
  1148. PrintButton(&dpComp, i);
  1149. }
  1150. // print list of messages
  1151. CDrawPort dpMsgList(&dpComp, _boxMsgList);
  1152. if (dpMsgList.Lock()) {
  1153. LCDSetDrawport(&dpMsgList);
  1154. LCDRenderCompGrid();
  1155. LCDRenderClouds2();
  1156. LCDScreenBox(_colBoxes);
  1157. PrintMessageList(&dpMsgList);
  1158. dpMsgList.Unlock();
  1159. }
  1160. // print text of current message
  1161. CDrawPort dpMsgText(&dpComp, _boxMsgText);
  1162. if (dpMsgText.Lock()) {
  1163. LCDSetDrawport(&dpMsgText);
  1164. LCDRenderCompGrid();
  1165. LCDRenderClouds2();
  1166. LCDScreenBox(_colBoxes);
  1167. PrintMessageText(&dpMsgText);
  1168. dpMsgText.Unlock();
  1169. }
  1170. // draw image of current message
  1171. CDrawPort dpMsgImage(&dpComp, _boxMsgImage);
  1172. if (dpMsgImage.Lock()) {
  1173. LCDSetDrawport(&dpMsgImage);
  1174. RenderMessageImage(&dpMsgImage);
  1175. dpMsgImage.Unlock();
  1176. }
  1177. // render mouse pointer on top of everything else
  1178. if (_pGame->gm_csComputerState != CS_ONINBACKGROUND) {
  1179. if (dpComp.Lock()) {
  1180. LCDSetDrawport(&dpComp);
  1181. LCDDrawPointer(_vpixMouse(1), _vpixMouse(2));
  1182. dpComp.Unlock();
  1183. }
  1184. }
  1185. _pTimer->SetCurrentTick(tmOld);
  1186. _pTimer->SetLerp(fLerpOld);
  1187. }
  1188. void CGame::ComputerForceOff()
  1189. {
  1190. cmp_ppenPlayer=NULL;
  1191. cmp_ppenDHPlayer=NULL;
  1192. _pGame->gm_csComputerState = CS_OFF;
  1193. fComputerFadeValue = 0.0f;
  1194. _ppenPlayer = NULL;
  1195. }