1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "sherlock/tattoo/tattoo_darts.h"
24 #include "sherlock/tattoo/tattoo_fixed_text.h"
25 #include "sherlock/tattoo/tattoo.h"
26
27 namespace Sherlock {
28
29 namespace Tattoo {
30
31 enum {
32 DART_COLOR_FORE = 5,
33 PLAYER_COLOR = 11,
34 DART_BAR_FORE = 208
35 };
36
37 static const int STATUS_INFO_X = 430;
38 static const int STATUS_INFO_Y = 50;
39 static const int STATUS_INFO_WIDTH = 205;
40 static const int STATUS_INFO_HEIGHT = 330;
41 static const int STATUS2_INFO_X = 510;
42 static const int STATUS2_X_ADD = STATUS2_INFO_X - STATUS_INFO_X;
43 static const int DART_BAR_VX = 10;
44 static const int DART_HEIGHT_Y = 121;
45 static const int DART_BAR_SIZE = 150;
46 static const int DARTBOARD_LEFT = 73;
47 static const int DARTBOARD_TOP = 68;
48 static const int DARTBOARD_WIDTH = 257;
49 static const int DARTBOARD_HEIGHT = 256;
50 static const int DARTBOARD_TOTALX = DARTBOARD_WIDTH * 120 / 100;
51 static const int DARTBOARD_TOTALY = DARTBOARD_HEIGHT * 120 / 100;
52 static const int DARTBOARD_TOTALTOP = DARTBOARD_TOP - DARTBOARD_WIDTH / 10;
53 static const int DARTBOARD_TOTALLEFT = DARTBOARD_LEFT - DARTBOARD_HEIGHT / 10;
54 static const int CRICKET_VALUE[7] = { 20, 19, 18, 17, 16, 15, 25 };
55
Darts(SherlockEngine * vm)56 Darts::Darts(SherlockEngine *vm) : _vm(vm) {
57 _gameType = GAME_301;
58 _hand1 = _hand2 = nullptr;
59 _dartGraphics = nullptr;
60 _dartsLeft = nullptr;
61 _dartMap = nullptr;
62 _dartBoard = nullptr;
63 Common::fill(&_cricketScore[0][0], &_cricketScore[0][7], 0);
64 Common::fill(&_cricketScore[1][0], &_cricketScore[1][7], 0);
65 _score1 = _score2 = 0;
66 _roundNum = 0;
67 _roundScore = 0;
68 _level = 0;
69 _oldDartButtons = false;
70 _handX = 0;
71 _compPlay = 1;
72 _escapePressed = false;
73 _spacing = 0;
74 }
75
playDarts(GameType gameType)76 void Darts::playDarts(GameType gameType) {
77 Events &events = *_vm->_events;
78 Scene &scene = *_vm->_scene;
79 Screen &screen = *_vm->_screen;
80 int oldFontType = screen.fontNumber();
81 int playerNum = 0;
82 int lastDart;
83 int numHits = 0;
84 bool gameOver = false;
85 bool done = false;
86
87 // Set the game mode
88 _gameType = gameType;
89
90 screen.setFont(7);
91 _spacing = screen.fontHeight() + 2;
92
93 // Load dart graphics and initialize values
94 loadDarts();
95 initDarts();
96 events.hideCursor();
97
98 while (!done && !_vm->shouldQuit()) {
99 int roundStart, score;
100 roundStart = score = (playerNum == 0) ? _score1 : _score2;
101
102 showNames(playerNum);
103 showStatus(playerNum);
104 _roundScore = 0;
105
106 for (int idx = 0; idx < 3 && !_vm->shouldQuit(); ++idx) {
107 if (_compPlay == 1)
108 lastDart = throwDart(idx + 1, playerNum * 2); /* Throw one dart */
109 else
110 if (_compPlay == 2)
111 lastDart = throwDart(idx + 1, playerNum + 1); /* Throw one dart */
112 else
113 lastDart = throwDart(idx + 1, 0); /* Throw one dart */
114
115 if (_gameType == GAME_301) {
116 score -= lastDart;
117 _roundScore += lastDart;
118 } else {
119 numHits = lastDart >> 16;
120 if (numHits == 0)
121 numHits = 1;
122 if (numHits > 3)
123 numHits = 3;
124
125 lastDart = lastDart & 0xffff;
126 updateCricketScore(playerNum, lastDart, numHits);
127 score = (playerNum == 0) ? _score1 : _score2;
128 }
129
130 // Special case for ScummVM: I'm making pressing Escape to exit out of the Darts game as a way to skip
131 // it entirely if you don't want to play all the way through it
132 if (_escapePressed) {
133 gameOver = true;
134 done = true;
135 playerNum = 0;
136 }
137
138
139 if (_gameType == GAME_301) {
140 if (playerNum == 0)
141 _score1 = score;
142 else
143 _score2 = score;
144
145 if (score == 0)
146 // Someone won
147 gameOver = true;
148 } else {
149 // check for cricket game over
150 bool allClosed = true;
151
152 for (int y = 0; y < 7; y++) {
153 if (_cricketScore[playerNum][y] < 3)
154 allClosed = false;
155 }
156
157 if (allClosed) {
158 int nOtherScore = (playerNum == 0) ? _score2 : _score1;
159 if (score >= nOtherScore)
160 gameOver = true;
161 }
162 }
163
164 // Show scores
165 showStatus(playerNum);
166 screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1),
167 Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
168 screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, FIXED(DartsCurrentDart), idx + 1);
169
170 if (_gameType == GAME_301) {
171 // "Scored x points"
172 Common::String scoredPoints;
173
174 // original treated 1 point and multiple points the same. Wrote "Scored 1 points"
175 if (lastDart == 1) {
176 scoredPoints = Common::String::format(FIXED(DartsScoredPoint), lastDart);
177 } else {
178 scoredPoints = Common::String::format(FIXED(DartsScoredPoints), lastDart);
179 }
180
181 screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", scoredPoints.c_str());
182 } else {
183 Common::String hitText;
184
185 if (lastDart != 25) {
186 // Regular hit
187 switch (numHits) {
188 case 1: // "Hit a X"
189 hitText = Common::String::format(FIXED(DartsHitSingle), lastDart);
190 break;
191 case 2: // "Hit double X"
192 hitText = Common::String::format(FIXED(DartsHitDouble), lastDart);
193 break;
194 case 3: // "Hit triple X"
195 hitText = Common::String::format(FIXED(DartsHitTriple), lastDart);
196 break;
197 default:
198 break;
199 }
200 } else {
201 // Bullseye
202 switch (numHits) {
203 case 1:
204 hitText = Common::String(FIXED(DartsHitSingleBullseye));
205 break;
206 case 2:
207 hitText = Common::String(FIXED(DartsHitDoubleBullseye));
208 break;
209 case 3:
210 hitText = Common::String(FIXED(DartsHitTripleBullseye));
211 break;
212 default:
213 break;
214 }
215 }
216 screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", hitText.c_str());
217 }
218
219 if (score != 0 && playerNum == 0 && !gameOver)
220 screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 3), 0,
221 "%s", FIXED(DartsPressKey));
222
223 if (gameOver) {
224 screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 3),
225 0, "%s", FIXED(DartsGameOver));
226 if (playerNum == 0) {
227 screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 4), 0,
228 FIXED(DartsWins), FIXED(DartsPlayerHolmes));
229 _vm->setFlagsDirect(531);
230 } else {
231 screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 4), 0,
232 FIXED(DartsWins), _opponent.c_str());
233 _vm->setFlagsDirect(530);
234 }
235
236 screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 5), 0,
237 "%s", FIXED(DartsPressKey));
238
239 done = true;
240 idx = 10;
241 } else if (_gameType == GAME_301 && score < 0) {
242 screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 2), 0,
243 "%s!", FIXED(DartsBusted));
244
245 // End turn
246 idx = 10;
247 score = roundStart;
248 if (playerNum == 0)
249 _score1 = score;
250 else
251 _score2 = score;
252 }
253
254 // Clear keyboard events
255 events.clearEvents();
256
257 if ((playerNum == 0 && _compPlay == 1) || _compPlay == 0 || done) {
258 if (_escapePressed) {
259 done = true;
260 break;
261 }
262 // Wait for keypress
263 do {
264 events.pollEventsAndWait();
265 events.setButtonState();
266 } while (!_vm->shouldQuit() && !events.kbHit() && !events._pressed);
267 } else {
268 events.wait(40);
269 }
270
271 // Clears the status part of the board
272 screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1),
273 Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
274 screen.SHblitFrom(screen._backBuffer1);
275 }
276
277 playerNum ^= 1;
278 if (!playerNum)
279 ++_roundNum;
280
281 if (!done) {
282 screen._backBuffer2.SHblitFrom((*_dartBoard)[0], Common::Point(0, 0));
283 screen._backBuffer1.SHblitFrom(screen._backBuffer2);
284 screen.SHblitFrom(screen._backBuffer2);
285 }
286 }
287
288 // Wait for a keypress
289 do {
290 events.pollEventsAndWait();
291 events.setButtonState();
292 } while (!_vm->shouldQuit() && !events.kbHit() && !events._pressed);
293 events.clearEvents();
294
295 closeDarts();
296 screen.fadeToBlack();
297 screen.setFont(oldFontType);
298
299 // Flag to return to the Billard's Academy scene
300 scene._goToScene = 26;
301 }
302
initDarts()303 void Darts::initDarts() {
304 _dartInfo = Common::Rect(430, 245, 430 + 205, 245 + 150);
305 _escapePressed = false;
306
307 if (_gameType == GAME_CRICKET) {
308 _dartInfo = Common::Rect(430, 245, 430 + 205, 245 + 150);
309 }
310
311 Common::fill(&_cricketScore[0][0], &_cricketScore[0][7], 0);
312 Common::fill(&_cricketScore[1][0], &_cricketScore[1][7], 0);
313
314 switch (_gameType) {
315 case GAME_501:
316 _score1 = _score2 = 501;
317 _gameType = GAME_301;
318 break;
319
320 case GAME_301:
321 _score1 = _score2 = 301;
322 break;
323
324 default:
325 // Cricket
326 _score1 = _score2 = 0;
327 break;
328 }
329
330 _roundNum = 1;
331
332 if (_level == 9) {
333 // No computer players
334 _compPlay = 0;
335 _level = 0;
336 } else if (_level == 8) {
337 _level = _vm->getRandomNumber(3);
338 _compPlay = 2;
339 } else {
340 // Check for opponent flags
341 for (int idx = 0; idx < 4; ++idx) {
342 if (_vm->readFlags(314 + idx))
343 _level = idx;
344 }
345 }
346
347 _opponent = FIXED(DartsPlayerJock);
348 }
349
loadDarts()350 void Darts::loadDarts() {
351 Resources &res = *_vm->_res;
352 Screen &screen = *_vm->_screen;
353 byte palette[PALETTE_SIZE];
354
355 // Load images
356 _hand1 = new ImageFile("hand1.vgs");
357 _hand2 = new ImageFile("hand2.vgs");
358 _dartGraphics = new ImageFile("darts.vgs");
359 _dartsLeft = new ImageFile("DartsLft.vgs");
360 _dartMap = new ImageFile("DartMap.vgs");
361 _dartBoard = new ImageFile("DartBd.vgs");
362
363 // Load and set the palette
364 Common::SeekableReadStream *stream = res.load("DartBd.pal");
365 stream->read(palette, PALETTE_SIZE);
366 screen.translatePalette(palette);
367 screen.setPalette(palette);
368 delete stream;
369
370 // Load the initial background
371 screen._backBuffer1.SHblitFrom((*_dartBoard)[0], Common::Point(0, 0));
372 screen._backBuffer2.SHblitFrom(screen._backBuffer1);
373 screen.SHblitFrom(screen._backBuffer1);
374 }
375
closeDarts()376 void Darts::closeDarts() {
377 delete _dartBoard;
378 delete _dartsLeft;
379 delete _dartGraphics;
380 delete _dartMap;
381 delete _hand1;
382 delete _hand2;
383 }
384
showNames(int playerNum)385 void Darts::showNames(int playerNum) {
386 Screen &screen = *_vm->_screen;
387 byte color;
388
389 color = playerNum == 0 ? PLAYER_COLOR : DART_COLOR_FORE;
390 screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y), 0, "%s", FIXED(DartsPlayerHolmes));
391 screen._backBuffer1.fillRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + _spacing + 1,
392 STATUS_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
393 screen.fillRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + _spacing + 1,
394 STATUS_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
395
396 color = playerNum == 1 ? PLAYER_COLOR : DART_COLOR_FORE;
397 screen.print(Common::Point(STATUS2_INFO_X, STATUS_INFO_Y), 0, "%s", _opponent.c_str());
398 screen._backBuffer1.fillRect(Common::Rect(STATUS2_INFO_X, STATUS_INFO_Y + _spacing + 1,
399 STATUS2_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
400 screen.fillRect(Common::Rect(STATUS2_INFO_X, STATUS_INFO_Y + _spacing + 1,
401 STATUS2_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
402
403 screen._backBuffer2.SHblitFrom(screen._backBuffer1);
404 }
405
showStatus(int playerNum)406 void Darts::showStatus(int playerNum) {
407 Screen &screen = *_vm->_screen;
408 const char *const CRICKET_SCORE_NAME[7] = { "20", "19", "18", "17", "16", "15", FIXED(DartsBull) };
409
410 screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10),
411 Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, STATUS_INFO_X + STATUS_INFO_WIDTH,
412 STATUS_INFO_Y + STATUS_INFO_HEIGHT - 10));
413 screen.print(Common::Point(STATUS_INFO_X + 30, STATUS_INFO_Y + _spacing + 4), 0, "%d", _score1);
414
415 screen.print(Common::Point(STATUS2_INFO_X + 30, STATUS_INFO_Y + _spacing + 4), 0, "%d", _score2);
416
417 int temp = (_gameType == GAME_CRICKET) ? STATUS_INFO_Y + 10 * _spacing + 5 : STATUS_INFO_Y + 55;
418
419 // "Round: x"
420 Common::String dartsRoundStatus = Common::String::format(FIXED(DartsCurrentRound), _roundNum);
421 screen.print(Common::Point(STATUS_INFO_X, temp), 0, "%s", dartsRoundStatus.c_str());
422
423 if (_gameType == GAME_301) {
424 // "Turn Total: x"
425 Common::String dartsTotalPoints = Common::String::format(FIXED(DartsCurrentTotalPoints), _roundScore);
426 screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 75), 0, "%s", dartsTotalPoints.c_str());
427 } else {
428 // Show cricket scores
429 for (int x = 0; x < 7; ++x) {
430 screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 40 + x * _spacing), 0, "%s:", CRICKET_SCORE_NAME[x]);
431
432 for (int y = 0; y < 2; ++y) {
433 switch (CRICKET_SCORE_NAME[y][x]) {
434 case 1:
435 screen.print(Common::Point(STATUS_INFO_X + 38 + y*STATUS2_X_ADD, STATUS_INFO_Y + 40 + x * _spacing), 0, "/");
436 break;
437 case 2:
438 screen.print(Common::Point(STATUS_INFO_X + 38 + y*STATUS2_X_ADD, STATUS_INFO_Y + 40 + x * _spacing), 0, "X");
439 break;
440 case 3:
441 screen.print(Common::Point(STATUS_INFO_X + 38 + y * STATUS2_X_ADD - 1, STATUS_INFO_Y + 40 + x * _spacing), 0, "X");
442 screen.print(Common::Point(STATUS_INFO_X + 37 + y * STATUS2_X_ADD, STATUS_INFO_Y + 40 + x * _spacing), 0, "O");
443 break;
444 default:
445 break;
446 }
447 }
448 }
449 }
450
451 screen.SHblitFrom(screen._backBuffer1, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10),
452 Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, STATUS_INFO_X + STATUS_INFO_WIDTH,
453 STATUS_INFO_Y + STATUS_INFO_HEIGHT - 10));
454 }
455
erasePowerBars()456 void Darts::erasePowerBars() {
457 Screen &screen = *_vm->_screen;
458
459 // Erase the old power bars and replace them with empty ones
460 screen._backBuffer1.fillRect(Common::Rect(DART_BAR_VX, DART_HEIGHT_Y, DART_BAR_VX + 9, DART_HEIGHT_Y + DART_BAR_SIZE), 0);
461 screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[0], Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1));
462 screen.slamArea(DART_BAR_VX - 1, DART_HEIGHT_Y - 1, 10, DART_BAR_SIZE + 2);
463 }
464
dartHit()465 bool Darts::dartHit() {
466 Events &events = *_vm->_events;
467 events.pollEvents();
468 events.setButtonState();
469
470 // Keyboard check
471 if (events.kbHit()) {
472 if (events.getKey().keycode == Common::KEYCODE_ESCAPE)
473 _escapePressed = true;
474
475 events.clearEvents();
476 return true;
477 }
478
479 bool result = events._pressed && !_oldDartButtons;
480 _oldDartButtons = events._pressed;
481 return result;
482 }
483
doPowerBar(const Common::Point & pt,byte color,int goToPower,int orientation)484 int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, int orientation) {
485 Events &events = *_vm->_events;
486 Screen &screen = *_vm->_screen;
487 int idx = 0;
488
489 events.clearEvents();
490 events.delay(100);
491
492 while (!_vm->shouldQuit() && idx < DART_BAR_SIZE) {
493 if ((goToPower - 1) == idx)
494 break;
495 else if (goToPower == 0) {
496 if (dartHit())
497 break;
498 }
499
500 screen._backBuffer1.hLine(pt.x, pt.y + DART_BAR_SIZE- 1 - idx, pt.x + 8, color);
501 screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[0], Common::Point(pt.x - 1, pt.y - 1));
502 screen.slamArea(pt.x, pt.y + DART_BAR_SIZE - 1 - idx, 8, 2);
503
504 if (!(idx % 8))
505 events.wait(1);
506
507 ++idx;
508 }
509
510 return MIN(idx * 100 / DART_BAR_SIZE, 100);
511 }
512
drawHand(int goToPower,int computer)513 int Darts::drawHand(int goToPower, int computer) {
514 Events &events = *_vm->_events;
515 Screen &screen = *_vm->_screen;
516 const int HAND_OFFSET[2] = { 72, 44 };
517 ImageFile *hands;
518 int hand;
519
520 goToPower = (goToPower * DARTBOARD_WIDTH) / 150;
521
522 if (!computer) {
523 hand = 0;
524 hands = _hand1;
525 } else {
526 hand = 1;
527 hands = _hand2;
528 }
529
530 _handSize.x = (*hands)[0]._offset.x + (*hands)[0]._width;
531 _handSize.y = (*hands)[0]._offset.y + (*hands)[0]._height;
532
533 // Clear keyboard buffer
534 events.clearEvents();
535 events.delay(100);
536
537 Common::Point pt(DARTBOARD_LEFT - HAND_OFFSET[hand], SHERLOCK_SCREEN_HEIGHT - _handSize.y);
538 int x = 0;
539
540 while (!_vm->shouldQuit() && x < DARTBOARD_WIDTH) {
541 if (computer && x >= (goToPower - 1))
542 break;
543 else if (goToPower == 0) {
544 if (dartHit())
545 break;
546 }
547
548 screen._backBuffer1.SHtransBlitFrom((*hands)[0], pt);
549 screen.slamArea(pt.x - 1, pt.y, _handSize.x + 1, _handSize.y);
550 screen.restoreBackground(Common::Rect(pt.x, pt.y, pt.x + _handSize.x, pt.y + _handSize.y));
551
552 if (!(x % 8))
553 events.wait(1);
554
555 ++x;
556 ++pt.x;
557 }
558
559 _handX = pt.x - 1;
560
561 return MIN(x * 100 / DARTBOARD_WIDTH, 100);
562 }
563
convertFromScreenToScoreCoords(const Common::Point & pt) const564 Common::Point Darts::convertFromScreenToScoreCoords(const Common::Point &pt) const {
565 return Common::Point(CLIP((int)pt.x, 0, DARTBOARD_WIDTH), CLIP((int)pt.y, 0, DARTBOARD_HEIGHT));
566 }
567
dartScore(const Common::Point & pt)568 int Darts::dartScore(const Common::Point &pt) {
569 Common::Point pos(pt.x - DARTBOARD_LEFT, pt.y - DARTBOARD_TOP);
570 if (pos.x < 0 || pos.y < 0)
571 return 0;
572 int score;
573
574 if (pos.x < DARTBOARD_WIDTH && pos.y < DARTBOARD_HEIGHT) {
575 pos = convertFromScreenToScoreCoords(pos);
576 score = *(const byte *)(*_dartMap)[0]._frame.getBasePtr(pos.x, pos.y);
577
578 if (_gameType == GAME_301) {
579 if (score >= 100) {
580 if (score <= 120)
581 // Hit a double
582 score = (score - 100) * 2;
583 else
584 // Hit a triple
585 score = (score - 120) * 3;
586 }
587 } else if (score >= 100) {
588 if (score >= 120)
589 // Hit a double
590 score = (2 << 16) + (score - 100);
591 else
592 // Hit a triple
593 score = (3 << 16) + (score - 120);
594 }
595 } else {
596 score = 0;
597 }
598
599 return score;
600 }
601
drawDartThrow(const Common::Point & dartPos,int computer)602 void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
603 Events &events = *_vm->_events;
604 Screen &screen = *_vm->_screen;
605 int cx, cy;
606 int xSize = 0, ySize = 0, oldxSize = 0, oldySize = 0;
607 int handOCx = 0, handOCy = 0;
608 int ocx = 0, ocy = 0;
609 int handOldxSize, handOldySize;
610 int delta = 9;
611 int dartNum;
612 int hddy;
613 Common::Point drawPos, oldDrawPos;
614
615 // Draw the animation of the hand throwing the dart first
616 // See which hand animation to use
617 ImageFile &hands = !computer ? *_hand1 : *_hand2;
618 int numFrames = !computer ? 14 : 13;
619
620 oldxSize = oldySize = handOldxSize = handOldySize = 1;
621 cx = dartPos.x;
622 cy = SHERLOCK_SCREEN_HEIGHT - _handSize.y - 20;
623
624 hddy = (cy - dartPos.y) / (numFrames - 7);
625 hddy += 2;
626 hddy = hddy * 10 / 8;
627 if (dartPos.y > 275)
628 hddy += 3;
629
630 for (int idx = 0; idx < numFrames; ++idx) {
631 _handSize.x = hands[idx]._offset.x + hands[idx]._width;
632 _handSize.y = hands[idx]._offset.y + hands[idx]._height;
633 int handCy = SHERLOCK_SCREEN_HEIGHT - _handSize.y;
634
635 screen._backBuffer1.SHtransBlitFrom(hands[idx], Common::Point(_handX, handCy));
636 screen.slamArea(_handX, handCy, _handSize.x + 1, _handSize.y);
637 screen.slamArea(handOCx, handOCy, handOldxSize, handOldySize);
638 screen.restoreBackground(Common::Rect(_handX, handCy, _handX + _handSize.x, handCy + _handSize.y));
639
640 handOCx = _handX;
641 handOCy = handCy;
642 handOldxSize = _handSize.x;
643 handOldySize = _handSize.y;
644
645 if (idx > 6) {
646 dartNum = idx - 6;
647 if (computer)
648 dartNum += 19;
649
650 xSize = (*_dartGraphics)[dartNum]._width;
651 ySize = (*_dartGraphics)[dartNum]._height;
652
653 ocx = drawPos.x = cx - (*_dartGraphics)[dartNum]._width / 2;
654 ocy = drawPos.y = cy - (*_dartGraphics)[dartNum]._height;
655
656 // Draw dart
657 screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], drawPos);
658
659 if (drawPos.x < 0) {
660 xSize += drawPos.x;
661 if (xSize < 0)
662 xSize = 1;
663 drawPos.x = 0;
664 }
665
666 if (drawPos.y < 0) {
667 ySize += drawPos.y;
668 if (ySize < 0)
669 ySize = 1;
670 drawPos.y = 0;
671 }
672
673 // Flush the drawn dart to the screen
674 screen.slamArea(drawPos.x, drawPos.y, xSize, ySize);
675 if (oldDrawPos.x != -1)
676 // Flush the erased dart area
677 screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize);
678
679 screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y),
680 Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize));
681
682 oldDrawPos.x = drawPos.x;
683 oldDrawPos.y = drawPos.y;
684 oldxSize = xSize;
685 oldySize = ySize;
686
687 cy -= hddy;
688 }
689
690 events.wait(1);
691 }
692
693 // Clear the last little bit of the hand from the screen
694 screen.slamArea(handOCx, handOCy, handOldxSize, handOldySize);
695
696 // Erase the old dart
697 if (oldDrawPos.x != -1)
698 screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize);
699
700 screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y),
701 Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize));
702
703 cx = dartPos.x;
704 cy = dartPos.y + 2;
705 oldDrawPos.x = oldDrawPos.y = -1;
706
707 for (int idx = 5; idx <= 23; ++idx) {
708 dartNum = idx - 4;
709 if (computer)
710 dartNum += 19;
711
712 if (idx < 14)
713 cy -= delta--;
714 else
715 if (idx == 14)
716 delta = 1;
717 if (idx > 14)
718 cy += delta++;
719
720 xSize = (*_dartGraphics)[dartNum]._width;
721 ySize = (*_dartGraphics)[dartNum]._height;
722
723 ocx = drawPos.x = cx - (*_dartGraphics)[dartNum]._width / 2;
724 ocy = drawPos.y = cy - (*_dartGraphics)[dartNum]._height;
725
726 screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], Common::Point(drawPos.x, drawPos.y));
727
728 if (drawPos.x < 0) {
729 xSize += drawPos.x;
730 if (xSize < 0)
731 xSize = 1;
732 drawPos.x = 0;
733 }
734
735 if (drawPos.y < 0) {
736 ySize += drawPos.y;
737 if (ySize < 0)
738 ySize = 1;
739 drawPos.y = 0;
740 }
741
742 // flush the dart
743 screen.slamArea(drawPos.x, drawPos.y, xSize, ySize);
744 if (oldDrawPos.x != -1)
745 screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize);
746
747 if (idx != 23)
748 screen._backBuffer1.SHblitFrom(screen._backBuffer2, drawPos,
749 Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize)); // erase dart
750
751 events.wait(1);
752
753 oldDrawPos = drawPos;
754 oldxSize = xSize;
755 oldySize = ySize;
756 }
757
758 dartNum = 19;
759 if (computer)
760 dartNum += 19;
761 xSize = (*_dartGraphics)[dartNum]._width;
762 ySize = (*_dartGraphics)[dartNum]._height;
763
764 // Draw final dart on the board
765 screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy));
766 screen._backBuffer2.SHtransBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy));
767 screen.slamArea(ocx, ocy, xSize, ySize);
768 }
769
findNumberOnBoard(int aim,Common::Point & pt)770 int Darts::findNumberOnBoard(int aim, Common::Point &pt) {
771 ImageFrame &img = (*_dartMap)[0];
772
773 if ((aim > 20) && ((aim != 25) && (aim != 50))) {
774 if ((aim <= 40) && ((aim & 1) == 0)) {
775 aim /= 2;
776 aim += 100;
777 } else {
778 aim /= 3;
779 aim += 120;
780 }
781 }
782
783 bool done = false;
784 for (int y = 0; y < img._width && !done; ++y) {
785 for (int x = 0; x < img._height && !done; ++x) {
786 byte score = *(const byte *)img._frame.getBasePtr(x, y);
787
788 if (score == aim) {
789 // Found a match. Aim at non-double/triple numbers whenever possible.
790 // ie. Aim at 18 instead of triple 6 or double 9
791 done = true;
792
793 if (aim < 21) {
794 pt.x = x + 10;
795 pt.y = y + 10;
796
797 score = *(const byte *)img._frame.getBasePtr(x, y);
798 if (score != aim)
799 done = false;
800 } else {
801 // Aiming at double or triple
802 pt.x = x + 3;
803 pt.y = y + 3;
804 }
805 }
806 }
807 }
808
809 pt = convertFromScreenToScoreCoords(pt);
810
811 if (aim == 3)
812 pt.y += 30;
813 if (aim == 17)
814 pt.y += 10;
815
816 if (aim == 15) {
817 pt.y += 5;
818 pt.x += 5;
819 }
820
821 pt.y = DARTBOARD_HEIGHT - pt.y;
822 return done;
823 }
824
getComputerNumber(int playerNum,Common::Point & targetPos)825 void Darts::getComputerNumber(int playerNum, Common::Point &targetPos) {
826 int score;
827 int aim = 0;
828 Common::Point pt;
829 bool shootBull = false;
830
831 score = (playerNum == 0) ? _score1 : _score2;
832
833 if (_gameType == GAME_301) {
834 // Try to hit number
835 aim = score;
836 if(score > 60)
837 shootBull = true;
838 } else {
839 bool cricketaimset = false;
840 if (_cricketScore[playerNum][6] < 3) {
841 // shoot at bull first
842 aim = CRICKET_VALUE[6];
843 cricketaimset = true;
844 } else {
845 // Now check and shoot in this order: 20,19,18,17,16,15
846 for (int idx = 0; idx < 7; ++idx) {
847 if (_cricketScore[playerNum][idx] < 3) {
848 aim = CRICKET_VALUE[idx];
849 cricketaimset = true;
850 break;
851 }
852 }
853 }
854
855 if (!cricketaimset) {
856 // Everything is closed
857 // just in case we don't get set in loop below, which should never happen
858 aim = 14;
859 for (int idx = 0; idx < 7; ++idx) {
860 if (_cricketScore[playerNum^1][idx] < 3) {
861 // Opponent has this open
862 aim = CRICKET_VALUE[idx];
863
864 if (idx == 6)
865 shootBull = true;
866 }
867 }
868 }
869 }
870
871 if (shootBull) {
872 // Aim at bulls eye
873 targetPos.x = targetPos.y = 75;
874
875 if (_level <= 1) {
876 if (_vm->getRandomNumber(1) == 1) {
877 targetPos.x += (_vm->getRandomNumber(20)-10);
878 targetPos.y += (_vm->getRandomNumber(20)-10);
879 }
880 }
881 } else {
882 // Loop in case number does not exist on board
883 bool done = false;
884 do {
885 done = findNumberOnBoard(aim, pt);
886 --aim;
887 } while (!done);
888
889 pt.x += DARTBOARD_TOTALLEFT * 70 / 100;
890 pt.y += DARTBOARD_TOTALTOP * 70 / 100;
891
892 // old * 3/2
893 targetPos.x = pt.x * 100 / DARTBOARD_TOTALX * 3 / 2;
894 targetPos.y = pt.y * 100 / DARTBOARD_TOTALY * 3 / 2;
895 }
896
897 // the higher the level, the more accurate the throw
898 int v = _vm->getRandomNumber(9);
899 v += _level * 2;
900
901 if (v <= 2) {
902 targetPos.x += _vm->getRandomNumber(70) - 35;
903 targetPos.y += _vm->getRandomNumber(70) - 35;
904 } else if (v <= 4) {
905 targetPos.x += _vm->getRandomNumber(50) - 25;
906 targetPos.y += _vm->getRandomNumber(50) - 25;
907 } else if (v <= 6) {
908 targetPos.x += _vm->getRandomNumber(30) - 15;
909 targetPos.y += _vm->getRandomNumber(30) - 15;
910 } else if (v <= 8) {
911 targetPos.x += _vm->getRandomNumber(20) -10;
912 targetPos.y += _vm->getRandomNumber(20) -10;
913 } else if (v <= 10) {
914 targetPos.x += _vm->getRandomNumber(11) - 5;
915 targetPos.y += _vm->getRandomNumber(11) - 5;
916 }
917
918 if (targetPos.x < 1)
919 targetPos.x = 1;
920 if (targetPos.y < 1)
921 targetPos.y = 1;
922 }
923
throwDart(int dartNum,int computer)924 int Darts::throwDart(int dartNum, int computer) {
925 Events &events = *_vm->_events;
926 Screen &screen = *_vm->_screen;
927 int height;
928 int horiz;
929 Common::Point targetPos;
930 Common::String temp;
931
932 /* clear keyboard buffer */
933 events.clearEvents();
934
935 erasePowerBars();
936
937 // "Dart # x"
938 Common::String currentDart = Common::String::format(FIXED(DartsCurrentDart), dartNum);
939 screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, "%s", currentDart.c_str());
940
941 drawDartsLeft(dartNum, computer);
942
943 if (!computer) {
944 screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", FIXED(DartsStartPressKey1));
945 screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 2), 0, "%s", FIXED(DartsStartPressKey2));
946 }
947
948 if (!computer) {
949 // Wait for a hit
950 while (!dartHit() && !_vm->shouldQuit())
951 events.wait(1);
952 if (_escapePressed)
953 return 0;
954 } else {
955 events.wait(1);
956 }
957
958 drawDartsLeft(dartNum + 1, computer);
959 screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1),
960 Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
961 screen.SHblitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1),
962 Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
963
964 if (computer) {
965 getComputerNumber(computer - 1, targetPos);
966 } else {
967 // Keyboard control
968 targetPos = Common::Point(0, 0);
969 }
970
971 horiz = drawHand(targetPos.x, computer);
972 if (_escapePressed)
973 return 0;
974
975 height = doPowerBar(Common::Point(DART_BAR_VX, DART_HEIGHT_Y), DART_BAR_FORE, targetPos.y, 1);
976 if (_escapePressed)
977 return 0;
978
979 // Invert height
980 height = 101 - height;
981
982 // Copy power bars to the secondary back buffer
983 screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1),
984 Common::Rect(DART_BAR_VX - 1, DART_HEIGHT_Y - 1, DART_BAR_VX - 1 + 10,
985 DART_HEIGHT_Y - 1 + DART_BAR_SIZE + 2));
986
987 Common::Point dartPos(DARTBOARD_TOTALLEFT + horiz*DARTBOARD_TOTALX / 100,
988 DARTBOARD_TOTALTOP + height * DARTBOARD_TOTALY / 100);
989
990 dartPos.x += 2 - _vm->getRandomNumber(4);
991 dartPos.y += 2 - _vm->getRandomNumber(4);
992
993 drawDartThrow(dartPos, computer);
994 return dartScore(dartPos);
995 }
996
doCricketScoreHits(int player,int scoreIndex,int numHits)997 void Darts::doCricketScoreHits(int player, int scoreIndex, int numHits) {
998 while (numHits--) {
999 if (_cricketScore[player][scoreIndex] < 3)
1000 _cricketScore[player][scoreIndex]++;
1001 else if (_cricketScore[player ^ 1][scoreIndex] < 3) {
1002 if (player == 0)
1003 _score1 += CRICKET_VALUE[scoreIndex];
1004 else
1005 _score2 += CRICKET_VALUE[scoreIndex];
1006 }
1007 }
1008 }
1009
updateCricketScore(int player,int dartVal,int multiplier)1010 void Darts::updateCricketScore(int player, int dartVal, int multiplier) {
1011 if (dartVal < 15)
1012 return;
1013
1014 if (dartVal <= 20)
1015 doCricketScoreHits(player, 20 - dartVal, multiplier);
1016 else if (dartVal == 25)
1017 doCricketScoreHits(player, 6, multiplier);
1018 }
1019
drawDartsLeft(int dartNum,int computer)1020 void Darts::drawDartsLeft(int dartNum, int computer) {
1021 Screen &screen = *_vm->_screen;
1022 const int DART_X1[3] = { 391, 451, 507 };
1023 const int DART_Y1[3] = { 373, 373, 373 };
1024 const int DART_X2[3] = { 393, 441, 502 };
1025 const int DART_Y2[3] = { 373, 373, 373 };
1026
1027 screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(DART_X1[0], DART_Y1[0]),
1028 Common::Rect(DART_X1[0], DART_Y1[0], SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
1029
1030 for (int idx = 2; idx >= dartNum - 1; --idx) {
1031 if (computer)
1032 screen._backBuffer1.SHtransBlitFrom((*_dartsLeft)[idx + 3], Common::Point(DART_X2[idx], DART_Y2[idx]));
1033 else
1034 screen._backBuffer1.SHtransBlitFrom((*_dartsLeft)[idx], Common::Point(DART_X1[idx], DART_Y1[idx]));
1035 }
1036
1037 screen.slamArea(DART_X1[0], DART_Y1[0], SHERLOCK_SCREEN_WIDTH - DART_X1[0], SHERLOCK_SCREEN_HEIGHT - DART_Y1[0]);
1038 }
1039
1040 } // End of namespace Tattoo
1041
1042 } // End of namespace Sherlock
1043