PageRenderTime 28ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 1ms

/src/game/minicomputer.cpp

https://code.google.com/
C++ | 1995 lines | 1696 code | 214 blank | 85 comment | 210 complexity | 7afedf25f82ee21a1d4f6210c40c5531 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0
  1. // Copyright (C) 1997, 1999-2001, 2008 Nathan Lamont
  2. // Copyright (C) 2008-2012 The Antares Authors
  3. //
  4. // This file is part of Antares, a tactical space combat game.
  5. //
  6. // Antares is free software: you can redistribute it and/or modify it
  7. // under the terms of the Lesser GNU General Public License as published
  8. // by the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // Antares is distributed in the hope that it will be useful, but
  12. // WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. // Lesser General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Lesser General Public
  17. // License along with Antares. If not, see http://www.gnu.org/licenses/
  18. #include "game/minicomputer.hpp"
  19. #include <algorithm>
  20. #include <sfz/sfz.hpp>
  21. #include "config/keys.hpp"
  22. #include "data/string-list.hpp"
  23. #include "drawing/color.hpp"
  24. #include "drawing/pix-table.hpp"
  25. #include "drawing/shapes.hpp"
  26. #include "drawing/sprite-handling.hpp"
  27. #include "drawing/text.hpp"
  28. #include "game/admiral.hpp"
  29. #include "game/globals.hpp"
  30. #include "game/instruments.hpp"
  31. #include "game/messages.hpp"
  32. #include "game/player-ship.hpp"
  33. #include "game/scenario-maker.hpp"
  34. #include "game/space-object.hpp"
  35. #include "game/starfield.hpp"
  36. #include "math/fixed.hpp"
  37. #include "sound/fx.hpp"
  38. #include "video/driver.hpp"
  39. using sfz::Bytes;
  40. using sfz::Rune;
  41. using sfz::String;
  42. using sfz::StringSlice;
  43. using sfz::bin;
  44. using sfz::scoped_array;
  45. using sfz::string_to_int;
  46. using std::max;
  47. namespace macroman = sfz::macroman;
  48. namespace antares {
  49. miniComputerDataType *gMiniScreenData = NULL;
  50. namespace {
  51. const int32_t kMiniScreenCharWidth = 25;
  52. const int32_t kMiniScreenLeft = 12;
  53. const int32_t kMiniScreenTop = 320;
  54. const int32_t kMiniScreenRight = 121;
  55. const int32_t kMiniScreenBottom = 440;
  56. const int32_t kMiniScreenWidth = kMiniScreenRight - kMiniScreenLeft;
  57. const int32_t kMiniScreenLeftBuffer = 3;
  58. const int32_t kMiniScreenCharHeight = 10; // height of the screen in characters
  59. const int32_t kMiniScreenTrueLineNum = kMiniScreenCharHeight + 2;
  60. const int32_t kButBoxLeft = 16;
  61. const int32_t kButBoxTop = 450;
  62. const int32_t kButBoxRight = 114;
  63. const int32_t kButBoxBottom = 475;
  64. const int32_t kMiniScreenNoLineSelected = -1;
  65. const int16_t kMiniScreenStringID = 3000;
  66. const int16_t kMiniDataStringID = 3001;
  67. const uint8_t kMiniScreenColor = GREEN;
  68. const uint8_t kMiniButColor = AQUA;
  69. const Rune kMiniScreenSpecChar = '\\';
  70. const Rune kEndLineChar = 'x';
  71. const Rune kUnderlineEndLineChar = 'u';
  72. const Rune kIntoButtonChar = 'I';
  73. const Rune kOutOfButtonChar = 'O';
  74. const Rune kSelectableLineChar = 'S';
  75. const int32_t kNoLineButton = -1;
  76. const int32_t kInLineButton = kCompAcceptKeyNum;
  77. const int32_t kOutLineButton = kCompCancelKeyNum;
  78. enum {
  79. kMainMiniScreen = 1,
  80. kBuildMiniScreen = 2,
  81. kSpecialMiniScreen = 3,
  82. kMessageMiniScreen = 4,
  83. kStatusMiniScreen = 5,
  84. };
  85. enum {
  86. kMainMiniBuild = 1,
  87. kMainMiniSpecial = 2,
  88. kMainMiniMessage = 3,
  89. kMainMiniStatus = 4,
  90. };
  91. const int32_t kBuildScreenFirstTypeLine = 2;
  92. const int32_t kBuildScreenWhereNameLine = 1;
  93. enum {
  94. kSpecialMiniTransfer = 1,
  95. kSpecialMiniHold = 2,
  96. kSpecialMiniGoToMe = 3,
  97. kSpecialMiniFire1 = 4,
  98. kSpecialMiniFire2 = 5,
  99. kSpecialMiniFireSpecial = 6,
  100. };
  101. enum {
  102. kMessageMiniNext = 1,
  103. kMessageMiniPrevious = 2,
  104. kMessageMiniLast = 3,
  105. };
  106. const int32_t kStatusMiniScreenFirstLine = 1;
  107. enum {
  108. kNoStatusData = -1, // no status for this line
  109. kPlainTextStatus = 0,
  110. kTrueFalseCondition = 1, // 0 = F, 1 = T, use condition not score
  111. kIntegerValue = 2, // interpret score as int
  112. kSmallFixedValue = 3, // interpret score as fixed
  113. kIntegerMinusValue = 4, // value - designated score
  114. kSmallFixedMinusValue = 5, // small fixed - designated score
  115. kMaxStatusTypeValue = kSmallFixedMinusValue,
  116. };
  117. const int32_t kMiniComputerPollTime = 60;
  118. const int32_t kMiniObjectDataNum = 2;
  119. const int32_t kMiniSelectObjectNum = 0;
  120. const int32_t kMiniSelectTop = 180;
  121. const int32_t kMiniIconHeight = 22;
  122. const int32_t kMiniIconWidth = 24;
  123. const int32_t kMiniIconLeft = (kMiniScreenLeft + 2);
  124. const int32_t kMiniHealthLeft = (kMiniIconLeft + kMiniIconWidth + 2);
  125. const int32_t kMiniBarWidth = 11;
  126. const int32_t kMiniBarHeight = 18;
  127. const int32_t kMiniEnergyLeft = (kMiniHealthLeft + kMiniBarWidth + 2);
  128. const int32_t kMiniRightColumnLeft = 57;
  129. const int32_t kMiniWeapon1LineNum = 2;
  130. const int32_t kMiniWeapon2LineNum = 3;
  131. const int32_t kMiniWeapon3LineNum = 1;
  132. const int32_t kMiniNameLineNum = 1;
  133. const int32_t kMiniDestLineNum = 4;
  134. const int32_t kMiniTargetObjectNum = 1;
  135. const int32_t kMiniTargetTop = 252;
  136. const int32_t kMiniAmmoTop = 161;
  137. const int32_t kMiniAmmoBottom = 170;
  138. const int32_t kMiniAmmoSingleWidth = 21;
  139. const int32_t kMiniAmmoLeftOne = 27;
  140. const int32_t kMiniAmmoLeftTwo = 64;
  141. const int32_t kMiniAmmoLeftSpecial = 100;
  142. const int32_t kMiniAmmoTextHBuffer = 2;
  143. inline void mPlayBeep3() {
  144. PlayVolumeSound(kComputerBeep3, kMediumVolume, kMediumPersistence, kLowPrioritySound);
  145. }
  146. inline void mPlayBeepBad() {
  147. PlayVolumeSound(kWarningTone, kMediumVolume, kMediumPersistence, kLowPrioritySound);
  148. }
  149. const int32_t kMaxShipBuffer = 40;
  150. void pad_to(String& s, size_t width) {
  151. if (s.size() < width) {
  152. String result;
  153. result.append((width - s.size()) / 2, ' ');
  154. result.append(s);
  155. result.append((1 + width - s.size()) / 2, ' ');
  156. swap(result, s);
  157. }
  158. }
  159. const int32_t MiniIconMacLineTop() {
  160. return computer_font->height * 2;
  161. }
  162. Rect mini_screen_line_bounds(long mtop, long mlinenum, long mleft, long mright) {
  163. Rect mbounds;
  164. mbounds.left = kMiniScreenLeft + mleft;
  165. mbounds.top = mtop + mlinenum * computer_font->height;
  166. mbounds.right = kMiniScreenLeft + mright;
  167. mbounds.bottom = mbounds.top + computer_font->height;
  168. return mbounds;
  169. }
  170. inline long mGetLineNumFromV(long mV) {
  171. return (((mV) - (kMiniScreenTop + globals()->gInstrumentTop)) / computer_font->height);
  172. }
  173. // for copying the fields of a space object relevant to the miniscreens:
  174. inline void mCopyMiniSpaceObject(
  175. spaceObjectType& mdestobject, const spaceObjectType& msourceobject) {
  176. (mdestobject).id = (msourceobject).id;
  177. (mdestobject).beamType = (msourceobject).beamType;
  178. (mdestobject).pulseType = (msourceobject).pulseType;
  179. (mdestobject).specialType = (msourceobject).specialType;
  180. (mdestobject).destinationLocation.h = (msourceobject).destinationLocation.h;
  181. (mdestobject).destinationLocation.v = (msourceobject).destinationLocation.v;
  182. (mdestobject).destinationObject = (msourceobject).destinationObject;
  183. (mdestobject).destObjectPtr = (msourceobject).destObjectPtr;
  184. (mdestobject).health = (msourceobject).health;
  185. (mdestobject).energy = (msourceobject).energy;
  186. (mdestobject).whichBaseObject = (msourceobject).whichBaseObject;
  187. (mdestobject).pixResID = (msourceobject).pixResID;
  188. (mdestobject).attributes = (msourceobject).attributes;
  189. (mdestobject).location = (msourceobject).location;
  190. (mdestobject).owner = (msourceobject).owner;
  191. (mdestobject).nextFarObject = (msourceobject).nextFarObject;
  192. (mdestobject).distanceGrid = (msourceobject).distanceGrid;
  193. (mdestobject).nextNearObject = (msourceobject).nextNearObject;
  194. (mdestobject).collisionGrid = (msourceobject).collisionGrid;
  195. (mdestobject).remoteFriendStrength = (msourceobject).remoteFriendStrength;
  196. (mdestobject).remoteFoeStrength = (msourceobject).remoteFoeStrength;
  197. (mdestobject).escortStrength = (msourceobject).escortStrength;
  198. (mdestobject).baseType = (msourceobject).baseType;
  199. }
  200. inline void mCopyBlankLineString(miniScreenLineType* mline, StringSlice mstring) {
  201. mline->string.assign(mstring);
  202. if (mline->string.size() > kMiniScreenCharWidth) {
  203. mline->string.resize(kMiniScreenCharWidth);
  204. }
  205. }
  206. inline spaceObjectType* mGetMiniObjectPtr(long mwhich) {
  207. return globals()->gMiniScreenData.objectData.get() + mwhich;
  208. }
  209. } // namespace
  210. void MiniComputerSetStatusStrings( void);
  211. long MiniComputerGetStatusValue( long);
  212. void MiniComputerMakeStatusString(int32_t which_line, String& string);
  213. void MiniScreenInit() {
  214. globals()->gMiniScreenData.selectLine = kMiniScreenNoLineSelected;
  215. globals()->gMiniScreenData.currentScreen = kMainMiniScreen;
  216. globals()->gMiniScreenData.pollTime = 0;
  217. globals()->gMiniScreenData.buildTimeBarValue = -1;
  218. globals()->gMiniScreenData.clickLine = kMiniScreenNoLineSelected;
  219. globals()->gMiniScreenData.lineData.reset(new miniScreenLineType[kMiniScreenTrueLineNum]);
  220. globals()->gMiniScreenData.objectData.reset(new spaceObjectType[kMiniObjectDataNum]);
  221. ClearMiniScreenLines();
  222. ClearMiniObjectData();
  223. }
  224. void MiniScreenCleanup() {
  225. globals()->gMiniScreenData.lineData.reset();
  226. globals()->gMiniScreenData.objectData.reset();
  227. }
  228. #pragma mark -
  229. void SetMiniScreenStatusStrList(short strID) {
  230. DisposeMiniScreenStatusStrList();
  231. if (strID > 0) {
  232. globals()->gMissionStatusStrList.reset(new StringList(strID));
  233. }
  234. }
  235. void DisposeMiniScreenStatusStrList( void) {
  236. globals()->gMissionStatusStrList.reset();
  237. }
  238. void ClearMiniScreenLines() {
  239. miniScreenLineType* c = globals()->gMiniScreenData.lineData.get();
  240. for (int32_t b = 0; b < kMiniScreenTrueLineNum; b++) {
  241. c->string.clear();
  242. c->hiliteLeft = c->hiliteRight = 0;
  243. c->whichButton = kNoLineButton;
  244. c->selectable = cannotSelect;
  245. c->underline = false;
  246. c->lineKind = plainLineKind;
  247. c->sourceData = NULL;
  248. c++;
  249. }
  250. }
  251. void ClearMiniObjectData( void)
  252. {
  253. spaceObjectType *o;
  254. o = mGetMiniObjectPtr( kMiniSelectObjectNum);
  255. o->id = -1;
  256. o->beamType = -1;
  257. o->pulseType = -1;
  258. o->specialType = -1;
  259. o->destinationLocation.h = o->destinationLocation.v = -1;
  260. o->destinationObject = -1;
  261. o->destObjectPtr = NULL;
  262. o->health = 0;
  263. o->energy = 0;
  264. o->whichBaseObject = -1;
  265. o->pixResID = -1;
  266. o->attributes = 0;
  267. o->baseType = NULL;
  268. o = mGetMiniObjectPtr( kMiniTargetObjectNum);
  269. o->id = -1;
  270. o->beamType = -1;
  271. o->pulseType = -1;
  272. o->specialType = -1;
  273. o->destinationLocation.h = o->destinationLocation.v = -1;
  274. o->destinationObject = -1;
  275. o->destObjectPtr = NULL;
  276. o->health = 0;
  277. o->energy = 0;
  278. o->whichBaseObject = -1;
  279. o->pixResID = -1;
  280. o->attributes = 0;
  281. o->baseType = NULL;
  282. globals()->gMiniScreenData.buildTimeBarValue = -1;
  283. globals()->gMiniScreenData.pollTime = 0;
  284. }
  285. void draw_mini_screen() {
  286. Rect mRect;
  287. Rect lRect, cRect;
  288. miniScreenLineType *c;
  289. RgbColor color, lightcolor, darkcolor, textcolor;
  290. unsigned char lineColor = kMiniScreenColor;
  291. long count, lineCorrect = 0;
  292. lRect = Rect(kMiniScreenLeft, kMiniScreenTop + globals()->gInstrumentTop, kMiniScreenRight,
  293. kMiniScreenBottom + globals()->gInstrumentTop);
  294. color = GetRGBTranslateColorShade(kMiniScreenColor, DARKEST);
  295. cRect = lRect;
  296. VideoDriver::driver()->fill_rect(cRect, color);
  297. mRect.left = kMiniScreenLeft;
  298. mRect.top = kMiniScreenTop + globals()->gInstrumentTop;
  299. mRect.right = kMiniScreenRight;
  300. mRect.bottom = kMiniScreenBottom + globals()->gInstrumentTop;
  301. c = globals()->gMiniScreenData.lineData.get();
  302. for ( count = 0; count < kMiniScreenTrueLineNum; count++)
  303. {
  304. if ( count == kMiniScreenCharHeight)
  305. {
  306. lRect.left = mRect.left = kButBoxLeft;
  307. lRect.top = mRect.top = kButBoxTop + globals()->gInstrumentTop;
  308. lRect.right = mRect.right = kButBoxRight;
  309. lRect.bottom = mRect.bottom = kButBoxBottom + globals()->gInstrumentTop;
  310. color = GetRGBTranslateColorShade(kMiniButColor, DARKEST);
  311. cRect = lRect;
  312. VideoDriver::driver()->fill_rect(cRect, color);
  313. lineCorrect = -kMiniScreenCharHeight;
  314. lineColor = kMiniButColor;
  315. }
  316. if ( c->underline)
  317. {
  318. const RgbColor color = GetRGBTranslateColorShade(lineColor, MEDIUM);
  319. int32_t y = mRect.top + (count + lineCorrect) * computer_font->height
  320. + computer_font->ascent;
  321. VideoDriver::driver()->draw_line(
  322. Point(mRect.left, y), Point(mRect.right - 2, y), color);
  323. }
  324. if ( c->hiliteLeft < c->hiliteRight)
  325. {
  326. if ( c->selectable == selectDim)
  327. textcolor = GetRGBTranslateColorShade(lineColor, VERY_DARK);
  328. else
  329. textcolor = GetRGBTranslateColorShade(lineColor, VERY_LIGHT);
  330. switch( c->lineKind)
  331. {
  332. case plainLineKind:
  333. if ( c->hiliteRight > c->hiliteLeft)
  334. {
  335. cRect.left = c->hiliteLeft;
  336. cRect.top = mRect.top + (( count + lineCorrect) * ( computer_font->height /* * 2 */));
  337. cRect.right = c->hiliteRight;
  338. cRect.bottom = cRect.top + computer_font->height /* * 2 */;
  339. // color = GetTranslateColorShade( lineColor, DARK);
  340. color = GetRGBTranslateColorShade(lineColor, DARK);
  341. lightcolor = GetRGBTranslateColorShade(lineColor, MEDIUM);
  342. darkcolor = GetRGBTranslateColorShade(lineColor, DARKER);
  343. draw_shaded_rect(cRect, color, lightcolor, darkcolor);
  344. }
  345. break;
  346. case buttonOffLineKind:
  347. cRect.left = c->hiliteLeft - 2;
  348. cRect.top = lRect.top + (( count + lineCorrect) * ( computer_font->height /* * 2 */));
  349. cRect.right = c->hiliteRight + 2;
  350. cRect.bottom = cRect.top + computer_font->height /* * 2 */;
  351. color = GetRGBTranslateColorShade(lineColor, MEDIUM);
  352. lightcolor = GetRGBTranslateColorShade(lineColor, LIGHT);
  353. darkcolor = GetRGBTranslateColorShade(lineColor, DARK);
  354. draw_shaded_rect(cRect, color, lightcolor, darkcolor);
  355. break;
  356. case buttonOnLineKind:
  357. cRect.left = c->hiliteLeft - 2;
  358. cRect.top = lRect.top + (( count + lineCorrect) * ( computer_font->height /* * 2 */));
  359. cRect.right = lRect.right; //c->hiliteRight + 2;
  360. cRect.bottom = cRect.top + computer_font->height /* * 2 */;
  361. color = GetRGBTranslateColorShade(lineColor, LIGHT);
  362. lightcolor = GetRGBTranslateColorShade(lineColor, VERY_LIGHT);
  363. darkcolor = GetRGBTranslateColorShade(lineColor, MEDIUM);
  364. draw_shaded_rect(cRect, color, lightcolor, darkcolor);
  365. textcolor = RgbColor::kBlack;
  366. break;
  367. }
  368. } else
  369. {
  370. if ( c->selectable == selectDim)
  371. textcolor = GetRGBTranslateColorShade(lineColor, MEDIUM);
  372. else
  373. textcolor = GetRGBTranslateColorShade(lineColor, VERY_LIGHT);
  374. }
  375. computer_font->draw_sprite(
  376. Point(
  377. mRect.left + kMiniScreenLeftBuffer,
  378. mRect.top + (count + lineCorrect) * computer_font->height + computer_font->ascent),
  379. c->string, textcolor);
  380. c++;
  381. }
  382. draw_mini_ship_data(*mGetMiniObjectPtr(kMiniSelectObjectNum), YELLOW, kMiniSelectTop, kMiniSelectObjectNum + 1);
  383. draw_mini_ship_data(*mGetMiniObjectPtr(kMiniTargetObjectNum), SKY_BLUE, kMiniTargetTop, kMiniTargetObjectNum + 1);
  384. }
  385. void MakeMiniScreenFromIndString(short whichString) {
  386. Rect mRect(kMiniScreenLeft, kMiniScreenTop, kMiniScreenRight, kMiniScreenBottom);
  387. mRect.offset(0, globals()->gInstrumentTop);
  388. ClearMiniScreenLines();
  389. globals()->gMiniScreenData.currentScreen = whichString;
  390. globals()->gMiniScreenData.selectLine = kMiniScreenNoLineSelected;
  391. StringList string_list(kMiniScreenStringID);
  392. StringSlice string = string_list.at(whichString - 1);
  393. miniScreenLineType* const line_begin = globals()->gMiniScreenData.lineData.get();
  394. miniScreenLineType* const line_switch = line_begin + kMiniScreenCharHeight;
  395. miniScreenLineType* const line_end = line_begin + kMiniScreenTrueLineNum;
  396. miniScreenLineType* line = line_begin;
  397. bool escape = false;
  398. SFZ_FOREACH(Rune r, string, {
  399. if (escape) {
  400. escape = false;
  401. switch (r) {
  402. case kUnderlineEndLineChar:
  403. line->underline = true;
  404. // fall through.
  405. case kEndLineChar:
  406. ++line;
  407. if (line == line_end) {
  408. return;
  409. } else if (line == line_switch) {
  410. mRect = Rect(kButBoxLeft, kButBoxTop, kButBoxRight, kButBoxBottom);
  411. mRect.offset(0, globals()->gInstrumentTop);
  412. }
  413. break;
  414. case kSelectableLineChar:
  415. line->selectable = selectable;
  416. if (globals()->gMiniScreenData.selectLine == kMiniScreenNoLineSelected) {
  417. globals()->gMiniScreenData.selectLine = line - line_begin;
  418. line->hiliteLeft = mRect.left;
  419. line->hiliteRight = mRect.right;
  420. }
  421. break;
  422. case kIntoButtonChar:
  423. {
  424. line->lineKind = buttonOffLineKind;
  425. line->whichButton = kInLineButton;
  426. line->hiliteLeft
  427. = mRect.left + kMiniScreenLeftBuffer
  428. + computer_font->logicalWidth * line->string.size();
  429. sfz::String key_name;
  430. GetKeyNumName(Preferences::preferences()->key(kCompAcceptKeyNum), &key_name);
  431. pad_to(key_name, kKeyNameLength);
  432. line->string.append(key_name);
  433. line->hiliteRight
  434. = mRect.left + kMiniScreenLeftBuffer
  435. + computer_font->logicalWidth * line->string.size() - 1;
  436. }
  437. break;
  438. case kOutOfButtonChar:
  439. {
  440. line->lineKind = buttonOffLineKind;
  441. line->whichButton = kOutLineButton;
  442. line->hiliteLeft
  443. = mRect.left + kMiniScreenLeftBuffer
  444. + computer_font->logicalWidth * line->string.size();
  445. sfz::String key_name;
  446. GetKeyNumName(
  447. Preferences::preferences()->key(kCompCancelKeyNum), &key_name);
  448. pad_to(key_name, kKeyNameLength);
  449. line->string.append(key_name);
  450. line->hiliteRight
  451. = mRect.left + kMiniScreenLeftBuffer
  452. + computer_font->logicalWidth * line->string.size() - 1;
  453. }
  454. break;
  455. case kMiniScreenSpecChar:
  456. line->string.append(1, kMiniScreenSpecChar);
  457. break;
  458. }
  459. } else if (r == kMiniScreenSpecChar) {
  460. escape = true;
  461. } else {
  462. line->string.append(1, r);
  463. }
  464. while (line->string.size() > kMiniScreenCharWidth) {
  465. String excess(line->string.slice(kMiniScreenCharWidth));
  466. line->string.resize(kMiniScreenCharWidth);
  467. ++line;
  468. if (line == line_end) {
  469. return;
  470. } else if (line == line_switch) {
  471. mRect = Rect(kButBoxLeft, kButBoxTop, kButBoxRight, kButBoxBottom);
  472. mRect.offset(0, globals()->gInstrumentTop);
  473. }
  474. line->string.assign(excess);
  475. }
  476. });
  477. }
  478. void MiniComputerHandleKeys( unsigned long theseKeys, unsigned long lastKeys)
  479. {
  480. miniScreenLineType *line;
  481. long count, scrap;
  482. Rect mRect;
  483. if (( theseKeys | lastKeys) & kCompAcceptKey)
  484. {
  485. // find out which line, if any, contains this button
  486. line = globals()->gMiniScreenData.lineData.get();
  487. count = 0;
  488. while (( line->whichButton !=kInLineButton) && ( count < kMiniScreenTrueLineNum))
  489. {
  490. count++;
  491. line++;
  492. }
  493. // hilite/unhilite this button
  494. if ( count < kMiniScreenTrueLineNum)
  495. {
  496. if (( theseKeys & kCompAcceptKey) && ( line->lineKind != buttonOnLineKind))
  497. {
  498. line->lineKind = buttonOnLineKind;
  499. mPlayBeep3();
  500. } else if ((!( theseKeys & kCompAcceptKey)) && ( line->lineKind != buttonOffLineKind))
  501. {
  502. line->lineKind = buttonOffLineKind;
  503. MiniComputerDoAccept();
  504. }
  505. }
  506. }
  507. if (( theseKeys | lastKeys) & kCompCancelKey)
  508. {
  509. // find out which line, if any, contains this button
  510. line = globals()->gMiniScreenData.lineData.get();
  511. count = 0;
  512. while (( line->whichButton !=kOutLineButton) && ( count < kMiniScreenTrueLineNum))
  513. {
  514. count++;
  515. line++;
  516. }
  517. if ( count < kMiniScreenCharHeight)
  518. {
  519. mRect = Rect(kMiniScreenLeft, kMiniScreenTop + globals()->gInstrumentTop, kMiniScreenRight,
  520. kMiniScreenBottom + globals()->gInstrumentTop);
  521. } else
  522. {
  523. mRect = Rect(kButBoxLeft, kButBoxTop + globals()->gInstrumentTop, kButBoxRight,
  524. kButBoxBottom + globals()->gInstrumentTop);
  525. }
  526. // hilite/unhilite this button
  527. if ( count < kMiniScreenTrueLineNum)
  528. {
  529. if (( theseKeys & kCompCancelKey) && ( line->lineKind != buttonOnLineKind))
  530. {
  531. line->lineKind = buttonOnLineKind;
  532. mPlayBeep3();
  533. } else if ((!( theseKeys & kCompCancelKey)) && ( line->lineKind != buttonOffLineKind))
  534. {
  535. line->lineKind = buttonOffLineKind;
  536. MiniComputerDoCancel();
  537. }
  538. }
  539. }
  540. if (( theseKeys & kCompUpKey) && ( !(lastKeys & kCompUpKey)) && ( globals()->gMiniScreenData.selectLine !=
  541. kMiniScreenNoLineSelected))
  542. {
  543. scrap = globals()->gMiniScreenData.selectLine;
  544. line = globals()->gMiniScreenData.lineData.get() + globals()->gMiniScreenData.selectLine;
  545. line->hiliteLeft = line->hiliteRight = 0;
  546. do
  547. {
  548. line--;
  549. globals()->gMiniScreenData.selectLine--;
  550. if ( globals()->gMiniScreenData.selectLine < 0)
  551. {
  552. globals()->gMiniScreenData.selectLine = kMiniScreenTrueLineNum - 1;
  553. line = globals()->gMiniScreenData.lineData.get() + kMiniScreenTrueLineNum - 1L;
  554. }
  555. } while ( line->selectable == cannotSelect);
  556. if ( globals()->gMiniScreenData.selectLine < kMiniScreenCharHeight)
  557. {
  558. mRect = Rect(kMiniScreenLeft, kMiniScreenTop + globals()->gInstrumentTop, kMiniScreenRight,
  559. kMiniScreenBottom + globals()->gInstrumentTop);
  560. } else
  561. {
  562. mRect = Rect(kButBoxLeft, kButBoxTop + globals()->gInstrumentTop, kButBoxRight,
  563. kButBoxBottom + globals()->gInstrumentTop);
  564. }
  565. line->hiliteLeft = mRect.left;
  566. line->hiliteRight = mRect.right;
  567. }
  568. if (( theseKeys & kCompDownKey) && ( !(lastKeys & kCompDownKey)) && ( globals()->gMiniScreenData.selectLine !=
  569. kMiniScreenNoLineSelected))
  570. {
  571. scrap = globals()->gMiniScreenData.selectLine;
  572. line = globals()->gMiniScreenData.lineData.get() + globals()->gMiniScreenData.selectLine;
  573. line->hiliteLeft = line->hiliteRight = 0;
  574. do
  575. {
  576. line++;
  577. globals()->gMiniScreenData.selectLine++;
  578. if ( globals()->gMiniScreenData.selectLine >= kMiniScreenTrueLineNum)
  579. {
  580. globals()->gMiniScreenData.selectLine = 0;
  581. line = globals()->gMiniScreenData.lineData.get();
  582. }
  583. } while ( line->selectable == cannotSelect);
  584. if ( globals()->gMiniScreenData.selectLine < kMiniScreenCharHeight)
  585. {
  586. mRect = Rect(kMiniScreenLeft, kMiniScreenTop + globals()->gInstrumentTop, kMiniScreenRight,
  587. kMiniScreenBottom + globals()->gInstrumentTop);
  588. } else
  589. {
  590. mRect = Rect(kButBoxLeft, kButBoxTop + globals()->gInstrumentTop, kButBoxRight,
  591. kButBoxBottom + globals()->gInstrumentTop);
  592. }
  593. line->hiliteLeft = mRect.left;
  594. line->hiliteRight = mRect.right;
  595. }
  596. }
  597. void MiniComputerHandleNull( long unitsToDo)
  598. {
  599. destBalanceType *buildAtObject = NULL;
  600. long count;
  601. spaceObjectType *realObject = NULL, *myObject = NULL, newObject;
  602. globals()->gMiniScreenData.pollTime += unitsToDo;
  603. if ( globals()->gMiniScreenData.pollTime > kMiniComputerPollTime)
  604. {
  605. globals()->gMiniScreenData.pollTime = 0;
  606. UpdateMiniScreenLines();
  607. // handle control/command/selected object
  608. myObject = mGetMiniObjectPtr( kMiniSelectObjectNum);
  609. count = GetAdmiralConsiderObject( globals()->gPlayerAdmiralNumber);
  610. if ( count >= 0)
  611. {
  612. realObject = gSpaceObjectData.get() + count;
  613. mCopyMiniSpaceObject( newObject, *realObject);
  614. } else
  615. {
  616. newObject.id = -1;
  617. newObject.beamType = -1;
  618. newObject.pulseType = -1;
  619. newObject.specialType = -1;
  620. newObject.destinationLocation.h = newObject.destinationLocation.v = -1;
  621. newObject.destinationObject = -1;
  622. newObject.destObjectPtr = NULL;
  623. newObject.health = 0;
  624. newObject.energy = 0;
  625. newObject.whichBaseObject = -1;
  626. newObject.pixResID = -1;
  627. newObject.attributes = 0;
  628. newObject.baseType = NULL;
  629. }
  630. mCopyMiniSpaceObject(*myObject, newObject);
  631. myObject = mGetMiniObjectPtr( kMiniTargetObjectNum);
  632. count = GetAdmiralDestinationObject( globals()->gPlayerAdmiralNumber);
  633. if ( count >= 0)
  634. {
  635. realObject = gSpaceObjectData.get() + count;
  636. mCopyMiniSpaceObject( newObject, *realObject);
  637. } else
  638. {
  639. newObject.id = -1;
  640. newObject.beamType = -1;
  641. newObject.pulseType = -1;
  642. newObject.specialType = -1;
  643. newObject.destinationLocation.h = newObject.destinationLocation.v = -1;
  644. newObject.destinationObject = -1;
  645. newObject.destObjectPtr = NULL;
  646. newObject.health = 0;
  647. newObject.energy = 0;
  648. newObject.whichBaseObject = -1;
  649. newObject.pixResID = -1;
  650. newObject.attributes = 0;
  651. newObject.baseType = NULL;
  652. }
  653. mCopyMiniSpaceObject(*myObject, newObject);
  654. int build_at = GetAdmiralBuildAtObject(globals()->gPlayerAdmiralNumber);
  655. if (build_at >= 0) {
  656. buildAtObject = mGetDestObjectBalancePtr(build_at);
  657. if (buildAtObject->totalBuildTime > 0) {
  658. int progress = buildAtObject->buildTime * kMiniBuildTimeHeight;
  659. progress /= buildAtObject->totalBuildTime;
  660. globals()->gMiniScreenData.buildTimeBarValue = progress;
  661. } else {
  662. globals()->gMiniScreenData.buildTimeBarValue = 0;
  663. }
  664. } else {
  665. globals()->gMiniScreenData.buildTimeBarValue = -1;
  666. }
  667. }
  668. }
  669. // only for updating volitile lines--doesn't draw whole screen!
  670. void UpdateMiniScreenLines( void)
  671. {
  672. admiralType *admiral = NULL;
  673. miniScreenLineType *line = NULL;
  674. baseObjectType *buildObject = NULL;
  675. long lineNum, count;
  676. Rect mRect;
  677. mRect = Rect(kMiniScreenLeft, kMiniScreenTop + globals()->gInstrumentTop, kMiniScreenRight,
  678. kMiniScreenBottom + globals()->gInstrumentTop);
  679. switch( globals()->gMiniScreenData.currentScreen)
  680. {
  681. case kBuildMiniScreen:
  682. admiral = globals()->gAdmiralData.get() + globals()->gPlayerAdmiralNumber;
  683. line = globals()->gMiniScreenData.lineData.get() +
  684. kBuildScreenWhereNameLine;
  685. if ( line->value !=
  686. GetAdmiralBuildAtObject( globals()->gPlayerAdmiralNumber))
  687. {
  688. if ( globals()->gMiniScreenData.selectLine !=
  689. kMiniScreenNoLineSelected)
  690. {
  691. line = globals()->gMiniScreenData.lineData.get()
  692. + globals()->gMiniScreenData.selectLine;
  693. line->hiliteLeft = line->hiliteRight = 0;
  694. globals()->gMiniScreenData.selectLine =
  695. kMiniScreenNoLineSelected;
  696. }
  697. MiniComputerSetBuildStrings();
  698. } else if ( GetAdmiralBuildAtObject( globals()->gPlayerAdmiralNumber)
  699. >= 0)
  700. {
  701. line = globals()->gMiniScreenData.lineData.get() + kBuildScreenFirstTypeLine;
  702. lineNum = kBuildScreenFirstTypeLine;
  703. for ( count = 0; count < kMaxShipCanBuild; count++)
  704. {
  705. buildObject = line->sourceData;
  706. if ( buildObject != NULL)
  707. {
  708. if ( buildObject->price > mFixedToLong(admiral->cash))
  709. {
  710. if ( line->selectable != selectDim)
  711. {
  712. line->selectable = selectDim;
  713. }
  714. } else
  715. {
  716. if (line->selectable != selectable)
  717. {
  718. if ( globals()->gMiniScreenData.selectLine ==
  719. kMiniScreenNoLineSelected)
  720. {
  721. globals()->gMiniScreenData.selectLine =
  722. lineNum;
  723. line->hiliteLeft = mRect.left;
  724. line->hiliteRight = mRect.right;
  725. }
  726. line->selectable = selectable;
  727. }
  728. }
  729. }
  730. line++;
  731. lineNum++;
  732. }
  733. }
  734. break;
  735. case kStatusMiniScreen:
  736. for ( count = kStatusMiniScreenFirstLine; count <
  737. kMiniScreenCharHeight; count++)
  738. {
  739. line =
  740. globals()->gMiniScreenData.lineData.get() +
  741. count;
  742. lineNum = MiniComputerGetStatusValue( count);
  743. if ( line->value != lineNum)
  744. {
  745. line->value = lineNum;
  746. MiniComputerMakeStatusString(count, line->string);
  747. }
  748. }
  749. break;
  750. }
  751. }
  752. static void draw_player_ammo_in_rect(int32_t value, int8_t hue, const Rect& rect) {
  753. if (value >= 0) {
  754. const RgbColor text_color = GetRGBTranslateColorShade(hue, VERY_LIGHT);
  755. const char digits[] = {
  756. ((value % 1000) / 100) + '0',
  757. ((value % 100) / 10) + '0',
  758. (value % 10) + '0',
  759. '\0',
  760. };
  761. Point origin(rect.left + kMiniAmmoTextHBuffer, rect.bottom - 1);
  762. computer_font->draw_sprite(origin, digits, text_color);
  763. }
  764. }
  765. void draw_player_ammo(int32_t ammo_one, int32_t ammo_two, int32_t ammo_special) {
  766. Rect clip(0, kMiniAmmoTop, kMiniAmmoSingleWidth, kMiniAmmoBottom);
  767. clip.offset(0, globals()->gInstrumentTop);
  768. clip.offset(kMiniAmmoLeftOne - clip.left, 0);
  769. draw_player_ammo_in_rect(ammo_one, RED, clip);
  770. clip.offset(kMiniAmmoLeftTwo - clip.left, 0);
  771. draw_player_ammo_in_rect(ammo_two, PALE_GREEN, clip);
  772. clip.offset(kMiniAmmoLeftSpecial - clip.left, 0);
  773. draw_player_ammo_in_rect(ammo_special, ORANGE, clip);
  774. }
  775. void draw_mini_ship_data(
  776. const spaceObjectType& newObject, unsigned char headerColor,
  777. short screenTop, short whichString) {
  778. Rect lRect = mini_screen_line_bounds(screenTop + globals()->gInstrumentTop, 0, 0, kMiniScreenWidth);
  779. RgbColor color = GetRGBTranslateColorShade(headerColor, LIGHT);
  780. RgbColor lightcolor = GetRGBTranslateColorShade(headerColor, VERY_LIGHT);
  781. RgbColor darkcolor = GetRGBTranslateColorShade(headerColor, MEDIUM);
  782. draw_shaded_rect(lRect, color, lightcolor, darkcolor);
  783. String text(StringList(kMiniDataStringID).at(whichString - 1));
  784. computer_font->draw_sprite(
  785. Point(lRect.left + kMiniScreenLeftBuffer, lRect.top + computer_font->ascent),
  786. text, RgbColor::kBlack);
  787. if (newObject.attributes & kIsDestination) {
  788. lRect = mini_screen_line_bounds(screenTop + globals()->gInstrumentTop, kMiniNameLineNum, 0, kMiniScreenWidth);
  789. // get the color for writing the name
  790. color = GetRGBTranslateColorShade(PALE_GREEN, VERY_LIGHT);
  791. // move to the 1st line in the selection miniscreen
  792. String text(GetDestBalanceName(newObject.destinationObject));
  793. computer_font->draw_sprite(
  794. Point(lRect.left + kMiniScreenLeftBuffer, lRect.top + computer_font->ascent),
  795. text, color);
  796. } else {
  797. lRect = mini_screen_line_bounds(screenTop + globals()->gInstrumentTop, kMiniNameLineNum, 0, kMiniScreenWidth);
  798. if (newObject.whichBaseObject >= 0) {
  799. // get the color for writing the name
  800. color = GetRGBTranslateColorShade(PALE_GREEN, VERY_LIGHT);
  801. // move to the 1st line in the selection miniscreen, write the name
  802. String text(StringList(kSpaceObjectShortNameResID).at(newObject.whichBaseObject));
  803. computer_font->draw_sprite(
  804. Point(lRect.left + kMiniScreenLeftBuffer, lRect.top + computer_font->ascent),
  805. text, color);
  806. }
  807. }
  808. // set the rect for drawing the "icon" of the object type
  809. Rect dRect;
  810. dRect.left = kMiniIconLeft;
  811. dRect.top = screenTop + globals()->gInstrumentTop + MiniIconMacLineTop();
  812. dRect.right = kMiniScreenLeft + kMiniIconWidth;
  813. dRect.bottom = dRect.top + kMiniIconHeight;
  814. if ((newObject.whichBaseObject >= 0) && (newObject.pixResID >= 0)) {
  815. NatePixTable* pixTable = GetPixTable(newObject.pixResID);
  816. if (pixTable != NULL) {
  817. short whichShape;
  818. if (newObject.attributes & kIsSelfAnimated) {
  819. whichShape = more_evil_fixed_to_long(newObject.baseType->frame.animation.firstShape);
  820. } else {
  821. whichShape = 0;
  822. }
  823. // get the picture data
  824. const NatePixTable::Frame& frame = pixTable->at(whichShape);
  825. Rect rect(0, 0, frame.width(), frame.height());
  826. int32_t max_dimension = max(frame.width(), frame.height());
  827. if (max_dimension > kMiniIconHeight) {
  828. rect.right = (rect.right * (kMiniIconHeight - 4)) / max_dimension;
  829. rect.bottom = (rect.bottom * (kMiniIconHeight - 4)) / max_dimension;
  830. }
  831. rect.center_in(dRect);
  832. frame.sprite().draw(rect);
  833. }
  834. }
  835. color = GetRGBTranslateColorShade(PALE_GREEN, MEDIUM);
  836. draw_vbracket(dRect, color);
  837. if (newObject.baseType != NULL) {
  838. if ((newObject.baseType->health > 0) && (newObject.health > 0)) {
  839. Rect dRect;
  840. dRect.left = kMiniHealthLeft;
  841. dRect.top = screenTop + globals()->gInstrumentTop + MiniIconMacLineTop();
  842. dRect.right = dRect.left + kMiniBarWidth;
  843. dRect.bottom = dRect.top + kMiniIconHeight;
  844. uint32_t tlong = newObject.health * kMiniBarHeight;
  845. tlong /= newObject.baseType->health;
  846. color = GetRGBTranslateColorShade(SKY_BLUE, DARK);
  847. lRect.left = dRect.left + 2;
  848. lRect.top = dRect.top + 2;
  849. lRect.right = dRect.right - 2;
  850. lRect.bottom = dRect.bottom - 2 - tlong;
  851. VideoDriver::driver()->fill_rect(lRect, color);
  852. color = GetRGBTranslateColorShade(SKY_BLUE, LIGHT);
  853. lRect.top = dRect.bottom - 2 - tlong;
  854. lRect.bottom = dRect.bottom - 2;
  855. VideoDriver::driver()->fill_rect(lRect, color);
  856. color = GetRGBTranslateColorShade(SKY_BLUE, MEDIUM);
  857. draw_vbracket(dRect, color);
  858. }
  859. }
  860. if (newObject.baseType != NULL) {
  861. if ((newObject.baseType->energy > 0) && (newObject.energy > 0)) {
  862. Rect dRect;
  863. dRect.left = kMiniEnergyLeft;
  864. dRect.top = screenTop + globals()->gInstrumentTop + MiniIconMacLineTop();
  865. dRect.right = dRect.left + kMiniBarWidth;
  866. dRect.bottom = dRect.top + kMiniIconHeight;
  867. uint32_t tlong = newObject.energy * kMiniBarHeight;
  868. tlong /= newObject.baseType->energy;
  869. color = GetRGBTranslateColorShade(YELLOW, DARK);
  870. lRect.left = dRect.left + 2;
  871. lRect.top = dRect.top + 2;
  872. lRect.right = dRect.right - 2;
  873. lRect.bottom = dRect.bottom - 2 - tlong;
  874. VideoDriver::driver()->fill_rect(lRect, color);
  875. color = GetRGBTranslateColorShade(YELLOW, LIGHT);
  876. lRect.top = dRect.bottom - 2 - tlong;
  877. lRect.bottom = dRect.bottom - 2;
  878. VideoDriver::driver()->fill_rect(lRect, color);
  879. color = GetRGBTranslateColorShade(YELLOW, MEDIUM);
  880. draw_vbracket(dRect, color);
  881. }
  882. }
  883. lRect = mini_screen_line_bounds(screenTop + globals()->gInstrumentTop, kMiniWeapon1LineNum, kMiniRightColumnLeft, kMiniScreenWidth);
  884. // get the color for writing the name
  885. color = GetRGBTranslateColorShade(PALE_GREEN, VERY_LIGHT);
  886. // move to the 1st line in the selection miniscreen, write the name
  887. if (newObject.beamType >= 0) {
  888. String text(StringList(kSpaceObjectShortNameResID).at(newObject.beamType));
  889. computer_font->draw_sprite(
  890. Point(lRect.left, lRect.top + computer_font->ascent), text, color);
  891. }
  892. lRect = mini_screen_line_bounds(screenTop + globals()->gInstrumentTop, kMiniWeapon2LineNum, kMiniRightColumnLeft, kMiniScreenWidth);
  893. // get the color for writing the name
  894. color = GetRGBTranslateColorShade(PALE_GREEN, VERY_LIGHT);
  895. // move to the 1st line in the selection miniscreen, write the name
  896. if (newObject.pulseType >= 0) {
  897. String text(StringList(kSpaceObjectShortNameResID).at(newObject.pulseType));
  898. computer_font->draw_sprite(
  899. Point(lRect.left, lRect.top + computer_font->ascent), text, color);
  900. }
  901. // Don't show special weapons of destination objects.
  902. if (!(newObject.attributes & kIsDestination)) {
  903. lRect = mini_screen_line_bounds(screenTop + globals()->gInstrumentTop, kMiniWeapon3LineNum, kMiniRightColumnLeft, kMiniScreenWidth);
  904. // get the color for writing the name
  905. color = GetRGBTranslateColorShade(PALE_GREEN, VERY_LIGHT);
  906. // move to the 1st line in the selection miniscreen, write the name
  907. if (newObject.specialType >= 0) {
  908. String text(StringList(kSpaceObjectShortNameResID).at(newObject.specialType));
  909. computer_font->draw_sprite(
  910. Point(lRect.left, lRect.top + computer_font->ascent), text, color);
  911. }
  912. }
  913. lRect = mini_screen_line_bounds(screenTop + globals()->gInstrumentTop, kMiniDestLineNum, 0, kMiniScreenWidth);
  914. // write the name
  915. if (newObject.destinationObject >= 0) {
  916. if (newObject.destObjectPtr != NULL) {
  917. spaceObjectType* dObject = newObject.destObjectPtr;
  918. // get the color for writing the name
  919. if (dObject->owner == globals()->gPlayerAdmiralNumber) {
  920. color = GetRGBTranslateColorShade(GREEN, VERY_LIGHT);
  921. } else {
  922. color = GetRGBTranslateColorShade(RED, VERY_LIGHT);
  923. }
  924. if (dObject->attributes & kIsDestination) {
  925. String text(GetDestBalanceName(dObject->destinationObject));
  926. computer_font->draw_sprite(
  927. Point(lRect.left, lRect.top + computer_font->ascent), text, color);
  928. } else {
  929. String text(StringList(kSpaceObjectNameResID).at(dObject->whichBaseObject));
  930. computer_font->draw_sprite(
  931. Point(lRect.left, lRect.top + computer_font->ascent), text, color);
  932. }
  933. }
  934. }
  935. }
  936. void MiniComputerDoAccept( void)
  937. {
  938. if (true) { // TODO(sfiera): if non-networked.
  939. MiniComputerExecute( globals()->gMiniScreenData.currentScreen,
  940. globals()->gMiniScreenData.selectLine, globals()->gPlayerAdmiralNumber);
  941. } else {
  942. #ifdef NETSPROCKET_AVAILABLE
  943. if ( !SendMenuMessage( globals()->gGameTime + gNetLatency, globals()->gMiniScreenData.currentScreen,
  944. globals()->gMiniScreenData.selectLine))
  945. StopNetworking();
  946. #endif NETSPROCKET_AVAILABLE
  947. }
  948. }
  949. void MiniComputerExecute( long whichPage, long whichLine, long whichAdmiral)
  950. {
  951. spaceObjectType *anObject, *anotherObject;
  952. long l;
  953. switch ( whichPage)
  954. {
  955. case kMainMiniScreen:
  956. if ( whichAdmiral == globals()->gPlayerAdmiralNumber)
  957. {
  958. switch ( whichLine)
  959. {
  960. case kMainMiniBuild:
  961. MakeMiniScreenFromIndString( kBuildMiniScreen);
  962. MiniComputerSetBuildStrings();
  963. break;
  964. case kMainMiniSpecial:
  965. MakeMiniScreenFromIndString( kSpecialMiniScreen);
  966. break;
  967. case kMainMiniMessage:
  968. MakeMiniScreenFromIndString( kMessageMiniScreen);
  969. break;
  970. case kMainMiniStatus:
  971. MakeMiniScreenFromIndString( kStatusMiniScreen);
  972. MiniComputerSetStatusStrings();
  973. break;
  974. default:
  975. break;
  976. }
  977. }
  978. break;
  979. case kBuildMiniScreen:
  980. if ( globals()->keyMask & kComputerBuildMenu) return;
  981. if ( whichLine != kMiniScreenNoLineSelected)
  982. {
  983. if ( CountObjectsOfBaseType( -1, -1) <
  984. (kMaxSpaceObject - kMaxShipBuffer))
  985. {
  986. if (AdmiralScheduleBuild( whichAdmiral,
  987. whichLine - kBuildScreenFirstTypeLine) == false)
  988. {
  989. if ( whichAdmiral == globals()->gPlayerAdmiralNumber)
  990. mPlayBeepBad();
  991. }
  992. } else
  993. {
  994. if ( whichAdmiral == globals()->gPlayerAdmiralNumber)
  995. {
  996. SetStatusString("Maximum number of ships built", ORANGE);
  997. }
  998. }
  999. }
  1000. break;
  1001. case kSpecialMiniScreen:
  1002. if ( globals()->keyMask & kComputerSpecialMenu) return;
  1003. switch ( whichLine)
  1004. {
  1005. case kSpecialMiniTransfer:
  1006. l = GetAdmiralConsiderObject( whichAdmiral);
  1007. anObject = GetAdmiralFlagship( whichAdmiral);
  1008. if ( anObject != NULL)
  1009. {
  1010. if ( l != kNoShip)
  1011. {
  1012. anotherObject = gSpaceObjectData.get() + l;
  1013. if (( anotherObject->active != kObjectInUse) ||
  1014. ( !(anotherObject->attributes & kCanThink)) ||
  1015. ( anotherObject->attributes & kStaticDestination)
  1016. || ( anotherObject->owner != anObject->owner) ||
  1017. (!(anotherObject->attributes & kCanAcceptDestination))
  1018. || ( !(anotherObject->attributes & kCanBeDestination))
  1019. || ( anObject->active != kObjectInUse))
  1020. {
  1021. if ( whichAdmiral == globals()->gPlayerAdmiralNumber)
  1022. mPlayBeepBad();
  1023. } else
  1024. {
  1025. ChangePlayerShipNumber( whichAdmiral, l);
  1026. }
  1027. } else
  1028. {
  1029. PlayerShipBodyExpire( anObject, false);
  1030. }
  1031. }
  1032. break;
  1033. case kSpecialMiniFire1:
  1034. l = GetAdmiralConsiderObject( whichAdmiral);
  1035. if (( l != kNoShip))
  1036. {
  1037. anObject = gSpaceObjectData.get() + l;
  1038. if (( anObject->active) &&
  1039. (anObject->attributes & ( kCanAcceptDestination)))
  1040. {
  1041. anObject->keysDown |= kOneKey | kManualOverrideFlag;
  1042. }
  1043. }
  1044. break;
  1045. case kSpecialMiniFire2:
  1046. l = GetAdmiralConsiderObject( whichAdmiral);
  1047. if (( l != kNoShip))
  1048. {
  1049. anObject = gSpaceObjectData.get() + l;
  1050. if (( anObject->active) &&
  1051. (anObject->attributes & ( kCanAcceptDestination)))
  1052. {
  1053. anObject->keysDown |= kTwoKey | kManualOverrideFlag;
  1054. }
  1055. }
  1056. break;
  1057. case kSpecialMiniFireSpecial:
  1058. l = GetAdmiralConsiderObject( whichAdmiral);
  1059. if (( l != kNoShip))
  1060. {
  1061. anObject = gSpaceObjectData.get() + l;
  1062. if (( anObject->active) &&
  1063. (anObject->attributes & ( kCanAcceptDestination)))
  1064. {
  1065. anObject->keysDown |= kEnterKey | kManualOverrideFlag;
  1066. }
  1067. }
  1068. break;
  1069. case kSpecialMiniHold:
  1070. l = GetAdmiralConsiderObject( whichAdmiral);
  1071. if (( l != kNoShip))
  1072. {
  1073. anObject = gSpaceObjectData.get() + l;
  1074. SetObjectLocationDestination( anObject, &(anObject->location));
  1075. }
  1076. break;
  1077. case kSpecialMiniGoToMe:
  1078. l = GetAdmiralConsiderObject( whichAdmiral);
  1079. if (( l != kNoShip))
  1080. {
  1081. anObject = gSpaceObjectData.get() + l;
  1082. anotherObject = GetAdmiralFlagship( whichAdmiral);
  1083. SetObjectLocationDestination( anObject, &(anotherObject->location));
  1084. }
  1085. break;
  1086. default:
  1087. break;
  1088. }
  1089. break;
  1090. case kMessageMiniScreen:
  1091. if ( globals()->keyMask & kComputerMessageMenu) return;
  1092. if ( whichAdmiral == globals()->gPlayerAdmiralNumber)
  1093. {
  1094. switch ( whichLine)
  1095. {
  1096. case kMessageMiniNext:
  1097. AdvanceCurrentLongMessage();
  1098. break;
  1099. case kMessageMiniLast:
  1100. ReplayLastLongMessage();
  1101. break;
  1102. case kMessageMiniPrevious:
  1103. PreviousCurrentLongMessage();
  1104. break;
  1105. default:
  1106. break;
  1107. }
  1108. }
  1109. break;
  1110. default:
  1111. break;
  1112. }
  1113. }
  1114. void MiniComputerDoCancel( void)
  1115. {
  1116. switch ( globals()->gMiniScreenData.currentScreen)
  1117. {
  1118. case kBuildMiniScreen:
  1119. case kSpecialMiniScreen:
  1120. case kMessageMiniScreen:
  1121. case kStatusMiniScreen:
  1122. MakeMiniScreenFromIndString( kMainMiniScreen);
  1123. break;
  1124. default:
  1125. break;
  1126. }
  1127. }
  1128. void MiniComputerSetBuildStrings( void) // sets the ship type strings for the build screen
  1129. // also sets up the values = base object num
  1130. {
  1131. baseObjectType *buildObject = NULL;
  1132. admiralType *admiral = NULL;
  1133. destBalanceType *buildAtObject = NULL;
  1134. miniScreenLineType *line = NULL;
  1135. long count, baseNum, lineNum, buildAtObjectNum;
  1136. Rect mRect;
  1137. mRect = Rect(kMiniScreenLeft, kMiniScreenTop + globals()->gInstrumentTop, kMiniScreenRight,
  1138. kMiniScreenBottom + globals()->gInstrumentTop);
  1139. globals()->gMiniScreenData.selectLine = kMiniScreenNoLineSelected;
  1140. if ( globals()->gMiniScreenData.currentScreen == kBuildMiniScreen)
  1141. {
  1142. admiral = globals()->gAdmiralData.get() + globals()->gPlayerAdmiralNumber;
  1143. line = globals()->gMiniScreenData.lineData.get() +
  1144. kBuildScreenWhereNameLine;
  1145. buildAtObjectNum =
  1146. GetAdmiralBuildAtObject( globals()->gPlayerAdmiralNumber);
  1147. line->value = buildAtObjectNum;
  1148. if ( buildAtObjectNum >= 0)
  1149. {
  1150. buildAtObject = mGetDestObjectBalancePtr( buildAtObjectNum);
  1151. mCopyBlankLineString( line, buildAtObject->name);
  1152. line = globals()->gMiniScreenData.lineData.get() + kBuildScreenFirstTypeLine;
  1153. lineNum = kBuildScreenFirstTypeLine;
  1154. for ( count = 0; count < kMaxShipCanBuild; count++)
  1155. {
  1156. mGetBaseObjectFromClassRace( buildObject, baseNum, buildAtObject->canBuildType[count], admiral->race);
  1157. line->value = baseNum;
  1158. line->sourceData = buildObject;
  1159. if ( buildObject != NULL)
  1160. {
  1161. mCopyBlankLineString(line, StringList(kSpaceObjectNameResID).at(baseNum));
  1162. if ( buildObject->price > mFixedToLong(admiral->cash))
  1163. line->selectable = selectDim;
  1164. else line->selectable = selectable;
  1165. if ( globals()->gMiniScreenData.selectLine == kMiniScreenNoLineSelected)
  1166. {
  1167. globals()->gMiniScreenData.selectLine = lineNum;
  1168. line->hiliteLeft = mRect.left;
  1169. line->hiliteRight = mRect.right;
  1170. }
  1171. } else
  1172. {
  1173. line->string.clear();
  1174. line->selectable = cannotSelect;
  1175. if ( globals()->gMiniScreenData.selectLine == (count + kBuildScreenFirstTypeLine))
  1176. {
  1177. line->hiliteLeft = line->hiliteRight = 0;
  1178. globals()->gMiniScreenData.selectLine++;
  1179. }
  1180. line->value = -1;
  1181. }
  1182. lineNum++;
  1183. line++;
  1184. }
  1185. line = globals()->gMiniScreenData.lineData.get() + globals()->gMiniScreenData.selectLine;
  1186. if ( line->selectable == cannotSelect)
  1187. globals()->gMiniScreenData.selectLine =
  1188. kMiniScreenNoLineSelected;
  1189. } else
  1190. {
  1191. globals()->gMiniScreenData.selectLine = kMiniScreenNoLineSelected;
  1192. line =
  1193. globals()->gMiniScreenData.lineData.get() +
  1194. kBuildScreenFirstTypeLine;
  1195. for ( count = 0; count < kMaxShipCanBuild; count++)
  1196. {
  1197. line->string.clear();
  1198. line->selectable = cannotSelect;
  1199. line->hiliteLeft = line->hiliteRight = 0;
  1200. line++;
  1201. }
  1202. }
  1203. }
  1204. }
  1205. // MiniComputerGetPriceOfCurrentSelection:
  1206. // If the Build Menu is up, returns the price of the currently selected
  1207. // ship, regardless of whether or not it is affordable.
  1208. //
  1209. // If the selection is not legal, or the current Menu is not the Build Menu,
  1210. // returns 0
  1211. long MiniComputerGetPriceOfCurrentSelection( void)
  1212. {
  1213. miniScreenLineType *line = NULL;
  1214. baseObjectType *buildObject = NULL;
  1215. if (( globals()->gMiniScreenData.currentScreen != kBuildMiniScreen) ||
  1216. ( globals()->gMiniScreenData.selectLine == kMiniScreenNoLineSelected))
  1217. return (0);
  1218. line = globals()->gMiniScreenData.lineData.get() +
  1219. globals()->gMiniScreenData.selectLine;
  1220. if ( line->value < 0) return( 0);
  1221. buildObject = mGetBaseObjectPtr( line->value);
  1222. if ( buildObject->price < 0) return( 0);
  1223. return( mLongToFixed(buildObject->price));
  1224. }
  1225. void MiniComputerSetStatusStrings() {
  1226. // the strings must be in this format:
  1227. // type\number\player\negativevalue\falsestring\truestring\basestring\poststring
  1228. //
  1229. // where type = 0...5
  1230. //
  1231. // number = which score/condition #
  1232. //
  1233. // player = which player score (if any); -1 = you, -2 = first not you
  1234. // ( 0 if you're player 1, 1 if you're player 0)
  1235. //
  1236. // negative value = value to use for kIntegerMinusValue or kSmallFixedMinusValue
  1237. //
  1238. // falsestring = string to use if false
  1239. //
  1240. // truestring = string to use if true
  1241. //
  1242. // basestring = first part of string
  1243. //
  1244. // for example, the string 1\0\\0\0\N\Y\SHIP DESTROYED:
  1245. // would result in the status line SHIP DESTROYED, based on condition 0;
  1246. // if false, line reads SHIP DESTROYED: N, and if true SHIP DESTROYED: Y
  1247. //
  1248. // example #2, string 2\1\0\10\\\Samples Left:
  1249. // would result in the status line "Samples Left: " + score 1 of player 0
  1250. // so if player 0's score 1 was 3, the line would read:
  1251. // Samples Left: 7
  1252. //
  1253. miniScreenLineType *line;
  1254. if (globals()->gMissionStatusStrList.get() == NULL) {
  1255. for (int count = kStatusMiniScreenFirstLine; count < kMiniScreenCharHeight; count++) {
  1256. line = globals()->gMiniScreenData.lineData.get() + count;
  1257. line->statusType = kNoStatusData;
  1258. line->value = -1;
  1259. line->string.clear();
  1260. }
  1261. return;
  1262. }
  1263. for (int count = kStatusMiniScreenFirstLine; count < kMiniScreenCharHeight; count++) {
  1264. line = globals()->gMiniScreenData.lineData.get() + count;
  1265. if (implicit_cast<size_t>(count - kStatusMiniScreenFirstLine) <
  1266. globals()->gMissionStatusStrList->size()) {
  1267. // we have some data for this line to interpret
  1268. StringSlice sourceString =
  1269. globals()->gMissionStatusStrList->at(count - kStatusMiniScreenFirstLine);
  1270. if (sourceString.at(0) == '_') {
  1271. line->underline = true;
  1272. sourceString = sourceString.slice(1);
  1273. }
  1274. if (sourceString.at(0) == '-') {
  1275. // - = abbreviated string, just plain text
  1276. line->statusType = kPlainTextStatus;
  1277. line->value = 0;
  1278. line->string.assign(sourceString.slice(1));
  1279. } else {
  1280. //////////////////////////////////////////////
  1281. // get status type
  1282. StringSlice status_type_string;
  1283. if (partition(status_type_string, "\\", sourceString)) {
  1284. int32_t value;
  1285. if (string_to_int<int32_t>(status_type_string, value)) {
  1286. if ((0 <= value) && (value <= kMaxStatusTypeValue)) {
  1287. line->statusType = value;
  1288. }
  1289. }
  1290. }
  1291. //////////////////////////////////////////////
  1292. // get score/condition number
  1293. StringSlice score_condition_string;
  1294. if (partition(score_condition_string, "\\", sourceString)) {
  1295. int32_t value;
  1296. if (string_to_int<int32_t>(score_condition_string, value)) {
  1297. line->whichStatus = value;
  1298. }
  1299. }
  1300. //////////////////////////////////////////////
  1301. // get player number
  1302. StringSlice player_number_string;
  1303. if (partition(player_number_string, "\\", sourceString)) {
  1304. int32_t value;
  1305. if (string_to_int<int32_t>(player_number_string, value)) {
  1306. line->statusPlayer = value;
  1307. }
  1308. }
  1309. //////////////////////////////////////////////
  1310. // get negative value
  1311. StringSlice negative_value_string;
  1312. if (partition(negative_value_string, "\\", sourceString)) {
  1313. int32_t value;
  1314. if (string_to_int<int32_t>(negative_value_string, value)) {
  1315. line->negativeValue = value;
  1316. }
  1317. }
  1318. //////////////////////////////////////////////
  1319. // get falseString
  1320. StringSlice status_false_string;
  1321. if (partition(status_false_string, "\\", sourceString)) {
  1322. line->statusFalse.assign(status_false_string);
  1323. }
  1324. //////////////////////////////////////////////
  1325. // get trueString
  1326. StringSlice status_true_string;
  1327. if (partition(status_true_string, "\\", sourceString)) {
  1328. line->statusTrue.assign(status_true_string);
  1329. }
  1330. //////////////////////////////////////////////
  1331. // get statusString
  1332. StringSlice status_string;
  1333. if (partition(status_string, "\\", sourceString)) {
  1334. line->statusString.assign(status_string);
  1335. }
  1336. //////////////////////////////////////////////
  1337. // get postString
  1338. line->postString.assign(sourceString);
  1339. line->value = MiniComputerGetStatusValue( count);
  1340. MiniComputerMakeStatusString(count, line->string);
  1341. }
  1342. } else {
  1343. line->statusType = kNoStatusData;
  1344. line->value = -1;
  1345. line->string.clear();
  1346. }
  1347. }
  1348. }
  1349. void MiniComputerMakeStatusString(int32_t which_line, String& string) {
  1350. string.clear();
  1351. const miniScreenLineType& line = globals()->gMiniScreenData.lineData[which_line];
  1352. if (line.statusType == kNoStatusData) {
  1353. return;
  1354. }
  1355. print(string, line.statusString);
  1356. switch (line.statusType) {
  1357. case kTrueFalseCondition:
  1358. if (line.value == 1) {
  1359. print(string, line.statusTrue);
  1360. } else {
  1361. print(string, line.statusFalse);
  1362. }
  1363. break;
  1364. case kIntegerValue:
  1365. case kIntegerMinusValue:
  1366. print(string, line.value);
  1367. break;
  1368. case kSmallFixedValue:
  1369. case kSmallFixedMinusValue:
  1370. print(string, fixed(line.value));
  1371. break;
  1372. }
  1373. if (line.statusType != kPlainTextStatus) {
  1374. print(string, line.postString);
  1375. }
  1376. }
  1377. long MiniComputerGetStatusValue( long whichLine)
  1378. {
  1379. miniScreenLineType *line;
  1380. line = globals()->gMiniScreenData.lineData.get() +
  1381. whichLine;
  1382. if ( line->statusType == kNoStatusData)
  1383. return( -1);
  1384. switch ( line->statusType)
  1385. {
  1386. case kPlainTextStatus:
  1387. return( 0);
  1388. break;
  1389. case kTrueFalseCondition:
  1390. if (gThisScenario->condition(line->whichStatus)->true_yet()) {
  1391. return 1;
  1392. } else {
  1393. return 0;
  1394. }
  1395. break;
  1396. case kIntegerValue:
  1397. case kSmallFixedValue:
  1398. return( GetAdmiralScore( GetRealAdmiralNumber( line->statusPlayer),
  1399. line->whichStatus));
  1400. break;
  1401. case kIntegerMinusValue:
  1402. case kSmallFixedMinusValue:
  1403. return( line->negativeValue - GetAdmiralScore(
  1404. GetRealAdmiralNumber( line->statusPlayer), line->whichStatus));
  1405. break;
  1406. default:
  1407. return( 0);
  1408. break;
  1409. }
  1410. }
  1411. void MiniComputerHandleClick( Point where)
  1412. {
  1413. Rect mRect;
  1414. long lineNum, scrap, inLineButtonLine = -1, outLineButtonLine = -1;
  1415. miniScreenLineType *line;
  1416. line = globals()->gMiniScreenData.lineData.get();
  1417. scrap = 0;
  1418. while ( scrap < kMiniScreenTrueLineNum)
  1419. {
  1420. if ( line->whichButton == kInLineButton) inLineButtonLine = scrap;
  1421. else if ( line->whichButton == kOutLineButton) outLineButtonLine = scrap;
  1422. scrap++;
  1423. line++;
  1424. }
  1425. mRect = Rect(kButBoxLeft, kButBoxTop + globals()->gInstrumentTop, kButBoxRight,
  1426. kButBoxBottom + globals()->gInstrumentTop);
  1427. // if click is in button screen
  1428. if (mRect.contains(where)) {
  1429. lineNum = (( where.v - ( kButBoxTop + globals()->gInstrumentTop)) / computer_font->height) + kMiniScreenCharHeight;
  1430. globals()->gMiniScreenData.clickLine = lineNum;
  1431. line = globals()->gMiniScreenData.lineData.get() + lineNum;
  1432. if ( line->whichButton == kInLineButton)
  1433. {
  1434. if ( line->lineKind != buttonOnLineKind)
  1435. {
  1436. line->lineKind = buttonOnLineKind;
  1437. mPlayBeep3();
  1438. }
  1439. if ( outLineButtonLine >= 0)
  1440. {
  1441. line = globals()->gMiniScreenData.lineData.get() +
  1442. outLineButtonLine;
  1443. if ( line->lineKind != buttonOffLineKind)
  1444. {
  1445. line->lineKind = buttonOffLineKind;
  1446. }
  1447. }
  1448. } else if ( line->whichButton == kOutLineButton)
  1449. {
  1450. if ( line->lineKind != buttonOnLineKind)
  1451. {
  1452. line->lineKind = buttonOnLineKind;
  1453. mPlayBeep3();
  1454. }
  1455. if ( inLineButtonLine >= 0)
  1456. {
  1457. line = globals()->gMiniScreenData.lineData.get() + inLineButtonLine;
  1458. if ( line->lineKind != buttonOffLineKind)
  1459. {
  1460. line->lineKind = buttonOffLineKind;
  1461. }
  1462. }
  1463. }
  1464. } else
  1465. {
  1466. // make sure both buttons are off
  1467. if ( inLineButtonLine >= 0)
  1468. {
  1469. line = globals()->gMiniScreenData.lineData.get() + inLineButtonLine;
  1470. if ( line->lineKind != buttonOffLineKind)
  1471. {
  1472. line->lineKind = buttonOffLineKind;
  1473. }
  1474. }
  1475. if ( outLineButtonLine >= 0)
  1476. {
  1477. line = globals()->gMiniScreenData.lineData.get() + outLineButtonLine;
  1478. if ( line->lineKind != buttonOffLineKind)
  1479. {
  1480. line->lineKind = buttonOffLineKind;
  1481. }
  1482. }
  1483. mRect = Rect(kMiniScreenLeft, kMiniScreenTop + globals()->gInstrumentTop, kMiniScreenRight,
  1484. kMiniScreenBottom + globals()->gInstrumentTop);
  1485. // if click is in main menu screen
  1486. if (mRect.contains(where)) {
  1487. if ( globals()->gMiniScreenData.selectLine !=
  1488. kMiniScreenNoLineSelected)
  1489. {
  1490. line = globals()->gMiniScreenData.lineData.get() +
  1491. globals()->gMiniScreenData.selectLine;
  1492. line->hiliteLeft = line->hiliteRight = 0;
  1493. }
  1494. lineNum = mGetLineNumFromV(where.v);
  1495. globals()->gMiniScreenData.clickLine = lineNum;
  1496. line = globals()->gMiniScreenData.lineData.get() + lineNum;
  1497. if (( line->selectable == selectable) || (line->selectable == selectDim))
  1498. {
  1499. globals()->gMiniScreenData.selectLine = lineNum;
  1500. line = globals()->gMiniScreenData.lineData.get() +
  1501. globals()->gMiniScreenData.selectLine;
  1502. line->hiliteLeft = mRect.left;
  1503. line->hiliteRight = mRect.right;
  1504. }
  1505. } else globals()->gMiniScreenData.clickLine = kMiniScreenNoLineSelected;
  1506. }
  1507. }
  1508. void MiniComputerHandleDoubleClick( Point where)
  1509. {
  1510. Rect mRect;
  1511. long lineNum, scrap, inLineButtonLine = -1, outLineButtonLine = -1;
  1512. miniScreenLineType *line;
  1513. line = globals()->gMiniScreenData.lineData.get();
  1514. scrap = 0;
  1515. while ( scrap < kMiniScreenTrueLineNum)
  1516. {
  1517. if ( line->whichButton == kInLineButton) inLineButtonLine = scrap;
  1518. else if ( line->whichButton == kOutLineButton) outLineButtonLine = scrap;
  1519. scrap++;
  1520. line++;
  1521. }
  1522. mRect = Rect(kButBoxLeft, kButBoxTop + globals()->gInstrumentTop, kButBoxRight,
  1523. kButBoxBottom + globals()->gInstrumentTop);
  1524. // if click is in button screen
  1525. if (mRect.contains(where)) {
  1526. lineNum = (( where.v - ( kButBoxTop + globals()->gInstrumentTop)) / computer_font->height) + kMiniScreenCharHeight;
  1527. line = globals()->gMiniScreenData.lineData.get() + lineNum;
  1528. if ( line->whichButton == kInLineButton)
  1529. {
  1530. if ( line->lineKind != buttonOnLineKind)
  1531. {
  1532. line->lineKind = buttonOnLineKind;
  1533. mPlayBeep3();
  1534. }
  1535. if ( outLineButtonLine >= 0)
  1536. {
  1537. line = globals()->gMiniScreenData.lineData.get() + outLineButtonLine;
  1538. if ( line->lineKind != buttonOffLineKind)
  1539. {
  1540. line->lineKind = buttonOffLineKind;
  1541. }
  1542. }
  1543. } else if ( line->whichButton == kOutLineButton)
  1544. {
  1545. if ( line->lineKind != buttonOnLineKind)
  1546. {
  1547. line->lineKind = buttonOnLineKind;
  1548. mPlayBeep3();
  1549. }
  1550. if ( inLineButtonLine >= 0)
  1551. {
  1552. line = globals()->gMiniScreenData.lineData.get() + inLineButtonLine;
  1553. if ( line->lineKind != buttonOffLineKind)
  1554. {
  1555. line->lineKind = buttonOffLineKind;
  1556. }
  1557. }
  1558. }
  1559. } else
  1560. {
  1561. // make sure both buttons are off
  1562. if ( inLineButtonLine >= 0)
  1563. {
  1564. line = globals()->gMiniScreenData.lineData.get() + inLineButtonLine;
  1565. if ( line->lineKind != buttonOffLineKind)
  1566. {
  1567. line->lineKind = buttonOffLineKind;
  1568. }
  1569. }
  1570. if ( outLineButtonLine >= 0)
  1571. {
  1572. line = globals()->gMiniScreenData.lineData.get() + outLineButtonLine;
  1573. if ( line->lineKind != buttonOffLineKind)
  1574. {
  1575. line->lineKind = buttonOffLineKind;
  1576. }
  1577. }
  1578. mRect = Rect(kMiniScreenLeft, kMiniScreenTop + globals()->gInstrumentTop, kMiniScreenRight,
  1579. kMiniScreenBottom + globals()->gInstrumentTop);
  1580. // if click is in main menu screen
  1581. if (mRect.contains(where)) {
  1582. lineNum = mGetLineNumFromV(where.v);
  1583. if ( lineNum == globals()->gMiniScreenData.selectLine)
  1584. {
  1585. mPlayBeep3();
  1586. MiniComputerDoAccept();
  1587. } else
  1588. {
  1589. if ( globals()->gMiniScreenData.selectLine !=
  1590. kMiniScreenNoLineSelected)
  1591. {
  1592. line = globals()->gMiniScreenData.lineData.get() + globals()->gMiniScreenData.selectLine;
  1593. line->hiliteLeft = line->hiliteRight = 0;
  1594. }
  1595. lineNum = mGetLineNumFromV(where.v);
  1596. line = globals()->gMiniScreenData.lineData.get() + lineNum;
  1597. if (( line->selectable == selectable) || (line->selectable == selectDim))
  1598. {
  1599. globals()->gMiniScreenData.selectLine = lineNum;
  1600. line = globals()->gMiniScreenData.lineData.get() + globals()->gMiniScreenData.selectLine;
  1601. line->hiliteLeft = mRect.left;
  1602. line->hiliteRight = mRect.right;
  1603. }
  1604. }
  1605. }
  1606. }
  1607. }
  1608. void MiniComputerHandleMouseUp( Point where)
  1609. {
  1610. Rect mRect;
  1611. long lineNum, scrap, inLineButtonLine = -1, outLineButtonLine = -1;
  1612. miniScreenLineType *line;
  1613. line = globals()->gMiniScreenData.lineData.get();
  1614. scrap = 0;
  1615. while ( scrap < kMiniScreenTrueLineNum)
  1616. {
  1617. if ( line->whichButton == kInLineButton) inLineButtonLine = scrap;
  1618. else if ( line->whichButton == kOutLineButton) outLineButtonLine = scrap;
  1619. scrap++;
  1620. line++;
  1621. }
  1622. mRect = Rect(kButBoxLeft, kButBoxTop + globals()->gInstrumentTop, kButBoxRight,
  1623. kButBoxBottom + globals()->gInstrumentTop);
  1624. // if click is in button screen
  1625. if (mRect.contains(where)) {
  1626. lineNum = (( where.v - ( kButBoxTop + globals()->gInstrumentTop)) / computer_font->height) + kMiniScreenCharHeight;
  1627. line = globals()->gMiniScreenData.lineData.get() + lineNum;
  1628. if ( line->whichButton == kInLineButton)
  1629. {
  1630. if ( line->lineKind == buttonOnLineKind)
  1631. {
  1632. line->lineKind = buttonOffLineKind;
  1633. MiniComputerDoAccept();
  1634. }
  1635. } else if ( line->whichButton == kOutLineButton)
  1636. {
  1637. if ( line->lineKind == buttonOnLineKind)
  1638. {
  1639. line->lineKind = buttonOffLineKind;
  1640. MiniComputerDoCancel();
  1641. }
  1642. }
  1643. }
  1644. }
  1645. void MiniComputerHandleMouseStillDown( Point where)
  1646. {
  1647. Rect mRect;
  1648. long lineNum, scrap, inLineButtonLine = -1, outLineButtonLine = -1;
  1649. miniScreenLineType *line;
  1650. line = globals()->gMiniScreenData.lineData.get();
  1651. scrap = 0;
  1652. while ( scrap < kMiniScreenTrueLineNum)
  1653. {
  1654. if ( line->whichButton == kInLineButton) inLineButtonLine = scrap;
  1655. else if ( line->whichButton == kOutLineButton) outLineButtonLine = scrap;
  1656. scrap++;
  1657. line++;
  1658. }
  1659. mRect = Rect(kButBoxLeft, kButBoxTop + globals()->gInstrumentTop, kButBoxRight,
  1660. kButBoxBottom + globals()->gInstrumentTop);
  1661. // if click is in button screen
  1662. if (mRect.contains(where)) {
  1663. lineNum = (( where.v - ( kButBoxTop + globals()->gInstrumentTop)) / computer_font->height) + kMiniScreenCharHeight;
  1664. line = globals()->gMiniScreenData.lineData.get() + lineNum;
  1665. if (( line->whichButton == kInLineButton) &&
  1666. ( lineNum == globals()->gMiniScreenData.clickLine))
  1667. {
  1668. if ( line->lineKind != buttonOnLineKind)
  1669. {
  1670. line->lineKind = buttonOnLineKind;
  1671. }
  1672. } else if (( line->whichButton == kOutLineButton) &&
  1673. ( lineNum == globals()->gMiniScreenData.clickLine))
  1674. {
  1675. if ( line->lineKind != buttonOnLineKind)
  1676. {
  1677. line->lineKind = buttonOnLineKind;
  1678. }
  1679. } else ( lineNum = -1);
  1680. } else lineNum = -1;
  1681. if ( lineNum == -1)
  1682. {
  1683. line = globals()->gMiniScreenData.lineData.get() + inLineButtonLine;
  1684. if ( line->lineKind == buttonOnLineKind)
  1685. {
  1686. line->lineKind = buttonOffLineKind;
  1687. }
  1688. line = globals()->gMiniScreenData.lineData.get() + outLineButtonLine;
  1689. if ( line->lineKind == buttonOnLineKind)
  1690. {
  1691. line->lineKind = buttonOffLineKind;
  1692. }
  1693. }
  1694. }
  1695. // for ambrosia tutorial, a horrific hack
  1696. void MiniComputer_SetScreenAndLineHack( long whichScreen, long whichLine)
  1697. {
  1698. Point w;
  1699. switch ( whichScreen)
  1700. {
  1701. case kBuildMiniScreen:
  1702. MakeMiniScreenFromIndString( kBuildMiniScreen);
  1703. MiniComputerSetBuildStrings();
  1704. break;
  1705. case kSpecialMiniScreen:
  1706. MakeMiniScreenFromIndString( kSpecialMiniScreen);
  1707. break;
  1708. case kMessageMiniScreen:
  1709. MakeMiniScreenFromIndString( kMessageMiniScreen);
  1710. break;
  1711. case kStatusMiniScreen:
  1712. MakeMiniScreenFromIndString( kStatusMiniScreen);
  1713. MiniComputerSetStatusStrings();
  1714. break;
  1715. default:
  1716. MakeMiniScreenFromIndString( kMainMiniScreen);
  1717. break;
  1718. }
  1719. w.v = (whichLine * computer_font->height) + ( kMiniScreenTop +
  1720. globals()->gInstrumentTop);
  1721. w.h = kMiniScreenLeft + 5;
  1722. MiniComputerHandleClick( w); // what an atrocious hack! oh well
  1723. }
  1724. } // namespace antares