mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-16 06:39:17 +00:00
968 lines
26 KiB
C++
968 lines
26 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "sherlock/tattoo/tattoo_darts.h"
|
|
#include "sherlock/tattoo/tattoo_fixed_text.h"
|
|
#include "sherlock/tattoo/tattoo.h"
|
|
|
|
namespace Sherlock {
|
|
|
|
namespace Tattoo {
|
|
|
|
enum {
|
|
DART_COLOR_FORE = 5,
|
|
PLAYER_COLOR = 11
|
|
};
|
|
|
|
static const int STATUS_INFO_X = 430;
|
|
static const int STATUS_INFO_Y = 50;
|
|
static const int STATUS_INFO_WIDTH = 205;
|
|
static const int STATUS_INFO_HEIGHT = 330;
|
|
static const int STATUS2_INFO_X = 510;
|
|
static const int STATUS2_X_ADD = STATUS2_INFO_X - STATUS_INFO_X;
|
|
static const int DART_BAR_VX = 10;
|
|
static const int DART_HEIGHT_Y = 121;
|
|
static const int DART_BAR_SIZE = 150;
|
|
static const int DARTBOARD_LEFT = 73;
|
|
static const int DARTBOARD_TOP = 68;
|
|
static const int DARTBOARD_WIDTH = 257;
|
|
static const int DARTBOARD_HEIGHT = 256;
|
|
static const int DARTBOARD_TOTALX = DARTBOARD_WIDTH * 120 / 100;
|
|
static const int DARTBOARD_TOTALY = DARTBOARD_HEIGHT * 120 / 100;
|
|
static const int DARTBOARD_TOTALTOP = DARTBOARD_TOP - DARTBOARD_WIDTH / 10;
|
|
static const int DARTBOARD_TOTALLEFT = DARTBOARD_LEFT - DARTBOARD_HEIGHT / 10;
|
|
static const int CRICKET_VALUE[7] = { 20, 19, 18, 17, 16, 15, 25 };
|
|
|
|
Darts::Darts(SherlockEngine *vm) : _vm(vm) {
|
|
_gameType = GAME_301;
|
|
_hand1 = _hand2 = nullptr;
|
|
_dartGraphics = nullptr;
|
|
_dartsLeft = nullptr;
|
|
_dartMap = nullptr;
|
|
_dartBoard = nullptr;
|
|
Common::fill(&_cricketScore[0][0], &_cricketScore[0][7], 0);
|
|
Common::fill(&_cricketScore[1][0], &_cricketScore[1][7], 0);
|
|
_score1 = _score2 = 0;
|
|
_roundNum = 0;
|
|
_roundScore = 0;
|
|
_level = 0;
|
|
_oldDartButtons = false;
|
|
_handX = 0;
|
|
_compPlay = 1;
|
|
}
|
|
|
|
void Darts::playDarts(GameType gameType) {
|
|
Events &events = *_vm->_events;
|
|
Screen &screen = *_vm->_screen;
|
|
int oldFontType = screen.fontNumber();
|
|
int playerNum = 0;
|
|
int roundStart, score;
|
|
int lastDart;
|
|
int numHits = 0;
|
|
bool gameOver = false;
|
|
bool done = false;
|
|
const char *const NUM_HITS_STR[3] = { "a", FIXED(Double), FIXED(Triple) };
|
|
|
|
screen.setFont(7);
|
|
_spacing = screen.fontHeight() + 2;
|
|
|
|
while (!_vm->shouldQuit()) {
|
|
roundStart = score = (playerNum == 0) ? _score1 : _score2;
|
|
|
|
showNames(playerNum);
|
|
showStatus(playerNum);
|
|
_roundScore = 0;
|
|
|
|
for (int idx = 0; idx < 3; ++idx) {
|
|
if (_compPlay == 1)
|
|
lastDart = throwDart(idx + 1, playerNum * 2); /* Throw one dart */
|
|
else
|
|
if (_compPlay == 2)
|
|
lastDart = throwDart(idx + 1, playerNum + 1); /* Throw one dart */
|
|
else
|
|
lastDart = throwDart(idx + 1, 0); /* Throw one dart */
|
|
|
|
if (_gameType == GAME_301) {
|
|
score -= lastDart;
|
|
_roundScore += lastDart;
|
|
} else {
|
|
numHits = lastDart >> 16;
|
|
if (numHits == 0)
|
|
numHits = 1;
|
|
if (numHits > 3)
|
|
numHits = 3;
|
|
|
|
lastDart = lastDart & 0xffff;
|
|
updateCricketScore(playerNum, lastDart, numHits);
|
|
score = (playerNum == 0) ? _score1 : _score2;
|
|
}
|
|
|
|
if (_gameType == GAME_301) {
|
|
if (playerNum == 0)
|
|
_score1 = score;
|
|
else
|
|
_score2 = score;
|
|
|
|
if (score == 0)
|
|
// Someone won
|
|
gameOver = true;
|
|
} else {
|
|
// check for cricket game over
|
|
bool allClosed = true;
|
|
int nOtherScore;
|
|
|
|
for (int y = 0; y < 7; y++) {
|
|
if (_cricketScore[playerNum][y] < 3)
|
|
allClosed = false;
|
|
}
|
|
|
|
if (allClosed) {
|
|
nOtherScore = (playerNum == 0) ? _score2 : _score1;
|
|
if (score >= nOtherScore)
|
|
gameOver = true;
|
|
}
|
|
}
|
|
|
|
// Show scores
|
|
showStatus(playerNum);
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1),
|
|
Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, "%s # %d", FIXED(Dart), idx + 1);
|
|
|
|
if (_gameType == GAME_301) {
|
|
if (_vm->getLanguage() == Common::FR_FRA)
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0,
|
|
"%s %s: %d", FIXED(Scored), FIXED(Points), lastDart);
|
|
else
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0,
|
|
"%s %d %s", FIXED(Scored), lastDart, FIXED(Points));
|
|
} else {
|
|
if (lastDart != 25)
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0,
|
|
"%s %s %d", FIXED(Hit), NUM_HITS_STR[numHits - 1], lastDart);
|
|
else
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0,
|
|
"%s %s %s", FIXED(Hit), NUM_HITS_STR[numHits - 1], FIXED(Bullseye));
|
|
}
|
|
|
|
if (score != 0 && playerNum == 0 && !gameOver)
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 3), 0,
|
|
"%s", FIXED(PressAKey));
|
|
|
|
if (gameOver) {
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 3),
|
|
0, "%s", FIXED(GameOver));
|
|
if (playerNum == 0) {
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 4), 0,
|
|
"%s %s", FIXED(Holmes), FIXED(Wins));
|
|
_vm->setFlagsDirect(531);
|
|
} else {
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 4), 0,
|
|
"%s %s!", _opponent.c_str(), FIXED(Wins));
|
|
_vm->setFlagsDirect(530);
|
|
}
|
|
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 5), 0,
|
|
"%s", FIXED(PressAKey));
|
|
|
|
done = true;
|
|
idx = 10;
|
|
} else if (_gameType == GAME_301 && score < 0) {
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 2), 0,
|
|
"%s!", FIXED(Busted));
|
|
|
|
// End turn
|
|
idx = 10;
|
|
score = roundStart;
|
|
if (playerNum == 0)
|
|
_score1 = score;
|
|
else
|
|
_score2 = score;
|
|
}
|
|
|
|
// Clear keyboard events
|
|
events.clearEvents();
|
|
|
|
if ((playerNum == 0 && _compPlay == 1) || _compPlay == 0 || done) {
|
|
if (events.kbHit()) {
|
|
Common::KeyState keyState = events.getKey();
|
|
if (keyState.keycode == Common::KEYCODE_ESCAPE) {
|
|
done = true;
|
|
idx = 10;
|
|
}
|
|
}
|
|
} else {
|
|
events.wait(20);
|
|
}
|
|
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1),
|
|
Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
|
|
screen.blitFrom(screen._backBuffer1);
|
|
}
|
|
|
|
playerNum ^= 1;
|
|
if (!playerNum)
|
|
++_roundNum;
|
|
|
|
if (!done) {
|
|
screen._backBuffer2.blitFrom((*_dartBoard)[0], Common::Point(0, 0));
|
|
screen._backBuffer1.blitFrom(screen._backBuffer2);
|
|
screen.blitFrom(screen._backBuffer2);
|
|
}
|
|
}
|
|
|
|
closeDarts();
|
|
screen.fadeToBlack();
|
|
screen.setFont(oldFontType);
|
|
}
|
|
|
|
void Darts::initDarts() {
|
|
_dartInfo = Common::Rect(430, 50, 430 + 205, 50 + 330);
|
|
|
|
if (_gameType == GAME_CRICKET) {
|
|
_dartInfo = Common::Rect(430, 245, 430 + 205, 245 + 150);
|
|
}
|
|
|
|
Common::fill(&_cricketScore[0][0], &_cricketScore[0][7], 0);
|
|
Common::fill(&_cricketScore[1][0], &_cricketScore[1][7], 0);
|
|
|
|
switch (_gameType) {
|
|
case GAME_501:
|
|
_score1 = _score2 = 501;
|
|
_gameType = GAME_301;
|
|
break;
|
|
|
|
case GAME_301:
|
|
_score1 = _score2 = 301;
|
|
break;
|
|
|
|
default:
|
|
// Cricket
|
|
_score1 = _score2 = 0;
|
|
break;
|
|
}
|
|
|
|
_roundNum = 1;
|
|
|
|
if (_level == 9) {
|
|
// No computer players
|
|
_compPlay = 0;
|
|
_level = 0;
|
|
} else if (_level == 8) {
|
|
_level = _vm->getRandomNumber(3);
|
|
_compPlay = 2;
|
|
} else {
|
|
// Check for opponent flags
|
|
for (int idx = 0; idx < 4; ++idx) {
|
|
if (_vm->readFlags(314 + idx))
|
|
_level = idx;
|
|
}
|
|
}
|
|
|
|
_opponent = FIXED(Jock);
|
|
}
|
|
|
|
void Darts::loadDarts() {
|
|
Resources &res = *_vm->_res;
|
|
Screen &screen = *_vm->_screen;
|
|
byte palette[PALETTE_SIZE];
|
|
|
|
// Load images
|
|
_hand1 = new ImageFile("hand1.vgs");
|
|
_hand2 = new ImageFile("hand2.vgs");
|
|
_dartGraphics = new ImageFile("darts.vgs");
|
|
_dartsLeft = new ImageFile("DartsLft.vgs");
|
|
_dartMap = new ImageFile("DartMap.vgs");
|
|
_dartBoard = new ImageFile("DartBd.vgs");
|
|
|
|
// Load and set the palette
|
|
Common::SeekableReadStream *stream = res.load("DartBoard.pal");
|
|
stream->read(palette, PALETTE_SIZE);
|
|
screen.translatePalette(palette);
|
|
screen.setPalette(palette);
|
|
delete stream;
|
|
|
|
// Load the initial background
|
|
screen._backBuffer1.blitFrom((*_dartBoard)[0], Common::Point(0, 0));
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1);
|
|
screen.blitFrom(screen._backBuffer1);
|
|
}
|
|
|
|
void Darts::closeDarts() {
|
|
delete _dartBoard;
|
|
delete _dartsLeft;
|
|
delete _dartGraphics;
|
|
delete _dartMap;
|
|
delete _hand1;
|
|
delete _hand2;
|
|
}
|
|
|
|
void Darts::showNames(int playerNum) {
|
|
Screen &screen = *_vm->_screen;
|
|
byte color;
|
|
|
|
color = playerNum == 0 ? PLAYER_COLOR : DART_COLOR_FORE;
|
|
screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y), 0, "%s", FIXED(Holmes));
|
|
screen._backBuffer1.fillRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + _spacing + 1,
|
|
STATUS_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
|
|
screen.fillRect(Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + _spacing + 1,
|
|
STATUS_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
|
|
|
|
color = playerNum == 1 ? PLAYER_COLOR : DART_COLOR_FORE;
|
|
screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y), 0, "%s", _opponent.c_str());
|
|
screen._backBuffer1.fillRect(Common::Rect(STATUS2_INFO_X, STATUS_INFO_Y + _spacing + 1,
|
|
STATUS2_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
|
|
screen.fillRect(Common::Rect(STATUS2_INFO_X, STATUS_INFO_Y + _spacing + 1,
|
|
STATUS2_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
|
|
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1);
|
|
}
|
|
|
|
void Darts::showStatus(int playerNum) {
|
|
Screen &screen = *_vm->_screen;
|
|
const char *const CRICKET_SCORE_NAME[7] = { "20", "19", "18", "17", "16", "15", FIXED(Bull) };
|
|
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10),
|
|
Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, STATUS_INFO_X + STATUS_INFO_WIDTH,
|
|
STATUS_INFO_Y + STATUS_INFO_HEIGHT - 10));
|
|
screen.print(Common::Point(STATUS_INFO_X + 30, STATUS_INFO_Y + _spacing + 4), 0, "%d", _score1);
|
|
|
|
screen.print(Common::Point(STATUS2_INFO_X + 30, STATUS_INFO_Y + _spacing + 4), 0, "%d", _score2);
|
|
|
|
int temp = (_gameType == GAME_CRICKET) ? STATUS_INFO_Y + 10 * _spacing + 5 : STATUS_INFO_Y + 55;
|
|
screen.print(Common::Point(STATUS_INFO_X, temp), 0, "%s: %d", FIXED(Round), _roundNum);
|
|
|
|
if (_gameType == GAME_301) {
|
|
screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 75), 0, "%s: %d", FIXED(TurnTotal), _roundScore);
|
|
} else {
|
|
// Show cricket scores
|
|
for (int x = 0; x < 7; ++x) {
|
|
screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 40 + x * _spacing), 0, "%s:", CRICKET_SCORE_NAME[x]);
|
|
|
|
for (int y = 0; y < 2; ++y) {
|
|
switch (CRICKET_SCORE_NAME[y][x]) {
|
|
case 1:
|
|
screen.print(Common::Point(STATUS_INFO_X + 38 + y*STATUS2_X_ADD, STATUS_INFO_Y + 40 + x * _spacing), 0, "/");
|
|
break;
|
|
case 2:
|
|
screen.print(Common::Point(STATUS_INFO_X + 38 + y*STATUS2_X_ADD, STATUS_INFO_Y + 40 + x * _spacing), 0, "X");
|
|
break;
|
|
case 3:
|
|
screen.print(Common::Point(STATUS_INFO_X + 38 + y * STATUS2_X_ADD - 1, STATUS_INFO_Y + 40 + x * _spacing), 0, "X");
|
|
screen.print(Common::Point(STATUS_INFO_X + 37 + y * STATUS2_X_ADD, STATUS_INFO_Y + 40 + x * _spacing), 0, "O");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
screen.blitFrom(screen._backBuffer1, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10),
|
|
Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, STATUS_INFO_X + STATUS_INFO_WIDTH,
|
|
STATUS_INFO_Y + STATUS_INFO_HEIGHT - 10));
|
|
}
|
|
|
|
void Darts::erasePowerBars() {
|
|
Screen &screen = *_vm->_screen;
|
|
|
|
// Erase the old power bars and replace them with empty ones
|
|
screen.fillRect(Common::Rect(DART_BAR_VX, DART_HEIGHT_Y, DART_BAR_VX + 9, DART_HEIGHT_Y + DART_BAR_SIZE), 0);
|
|
screen._backBuffer1.transBlitFrom((*_dartGraphics)[0], Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1));
|
|
screen.slamArea(DART_BAR_VX - 1, DART_HEIGHT_Y - 1, 10, DART_BAR_SIZE + 2);
|
|
}
|
|
|
|
bool Darts::dartHit() {
|
|
Events &events = *_vm->_events;
|
|
events.pollEventsAndWait();
|
|
|
|
// Keyboard check
|
|
if (events.kbHit()) {
|
|
events.clearEvents();
|
|
return true;
|
|
}
|
|
|
|
bool result = events._pressed && !_oldDartButtons;
|
|
_oldDartButtons = events._pressed;
|
|
return result;
|
|
}
|
|
|
|
int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, int orientation) {
|
|
Events &events = *_vm->_events;
|
|
Screen &screen = *_vm->_screen;
|
|
int x = 0;
|
|
|
|
events.clearEvents();
|
|
events.delay(100);
|
|
|
|
while (!_vm->shouldQuit()) {
|
|
if (x >= DART_BAR_SIZE)
|
|
break;
|
|
|
|
if ((goToPower - 1) == x)
|
|
break;
|
|
else if (goToPower == 0) {
|
|
if (dartHit())
|
|
break;
|
|
}
|
|
|
|
screen._backBuffer1.fillRect(Common::Rect(pt.x, pt.y + DART_BAR_SIZE - 1 - x,
|
|
pt.x + 8, pt.y + DART_BAR_SIZE - 2 - x), color);
|
|
screen._backBuffer1.transBlitFrom((*_dartGraphics)[0], Common::Point(pt.x - 1, pt.y - 1));
|
|
screen.slamArea(pt.x, pt.y + DART_BAR_SIZE - 1 - x, 8, 2);
|
|
|
|
if (!(x % 8))
|
|
events.wait(1);
|
|
|
|
x += 1;
|
|
}
|
|
|
|
return MIN(x * 100 / DART_BAR_SIZE, 100);
|
|
}
|
|
|
|
int Darts::drawHand(int goToPower, int computer) {
|
|
Events &events = *_vm->_events;
|
|
Screen &screen = *_vm->_screen;
|
|
const int HAND_OFFSET[2] = { 72, 44 };
|
|
ImageFile *hands;
|
|
int hand;
|
|
|
|
goToPower = (goToPower * DARTBOARD_WIDTH) / 150;
|
|
|
|
if (!computer) {
|
|
hand = 0;
|
|
hands = _hand1;
|
|
} else {
|
|
hand = 1;
|
|
hands = _hand2;
|
|
}
|
|
|
|
_handSize.x = (*hands)[0]._offset.x + (*hands)[0]._width;
|
|
_handSize.y = (*hands)[0]._offset.y + (*hands)[0]._height;
|
|
|
|
// Clear keyboard buffer
|
|
events.clearEvents();
|
|
events.delay(100);
|
|
|
|
Common::Point pt(DARTBOARD_LEFT - HAND_OFFSET[hand], SHERLOCK_SCREEN_HEIGHT - _handSize.y);
|
|
int x = 0;
|
|
|
|
while (!_vm->shouldQuit()) {
|
|
if (x >= DARTBOARD_WIDTH)
|
|
break;
|
|
|
|
if ((goToPower - 1) == x)
|
|
break;
|
|
else if (goToPower == 0) {
|
|
if (dartHit())
|
|
break;
|
|
}
|
|
|
|
screen._backBuffer1.transBlitFrom((*hands)[0], pt);
|
|
screen.slamArea(pt.x - 1, pt.y, _handSize.x + 1, _handSize.y);
|
|
screen.restoreBackground(Common::Rect(pt.x, pt.y, pt.x + _handSize.x, pt.y + _handSize.y));
|
|
|
|
if (!(x % 8))
|
|
events.wait(1);
|
|
|
|
++x;
|
|
++pt.x;
|
|
}
|
|
|
|
_handX = pt.x - 1;
|
|
|
|
return MIN(x * 100 / DARTBOARD_WIDTH, 100);
|
|
}
|
|
|
|
Common::Point Darts::convertFromScreenToScoreCoords(const Common::Point &pt) const {
|
|
return Common::Point(CLIP((int)pt.x, 0, DARTBOARD_WIDTH), CLIP((int)pt.y, 0, DARTBOARD_HEIGHT));
|
|
}
|
|
|
|
int Darts::dartScore(const Common::Point &pt) {
|
|
Common::Point pos(pt.x - DARTBOARD_LEFT, pt.y - DARTBOARD_TOP);
|
|
if (pos.x < 0 || pos.y < 0)
|
|
return 0;
|
|
int score;
|
|
|
|
if (pos.x < DARTBOARD_WIDTH && pos.y < DARTBOARD_HEIGHT) {
|
|
pos = convertFromScreenToScoreCoords(pos);
|
|
score = *(const byte *)(*_dartMap)[0]._frame.getBasePtr(pos.x, pos.y);
|
|
|
|
if (_gameType == GAME_301) {
|
|
if (score >= 100) {
|
|
if (score <= 120)
|
|
// Hit a double
|
|
score = (score - 100) * 2;
|
|
else
|
|
// Hit a triple
|
|
score = (score - 120) * 3;
|
|
}
|
|
} else if (score >= 100) {
|
|
if (score >= 120)
|
|
// Hit a double
|
|
score = (2 << 16) + (score - 100);
|
|
else
|
|
// Hit a triple
|
|
score = (3 << 16) + (score - 120);
|
|
}
|
|
} else {
|
|
score = 0;
|
|
}
|
|
|
|
return score;
|
|
}
|
|
|
|
void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
|
|
Events &events = *_vm->_events;
|
|
Screen &screen = *_vm->_screen;
|
|
int cx, cy;
|
|
int handCy;
|
|
int drawX = 0, drawY = 0, oldDrawX = 0, oldDrawY = 0;
|
|
int xSize = 0, ySize = 0, oldxSize = 0, oldySize = 0;
|
|
int handOCx, handOCy;
|
|
int ocx, ocy;
|
|
int handOldxSize, handOldySize;
|
|
int delta = 9;
|
|
int dartNum;
|
|
int hddy;
|
|
|
|
// Draw the animation of the hand throwing the dart first
|
|
// See which hand animation to use
|
|
ImageFile &hands = !computer ? *_hand1 : *_hand2;
|
|
int numFrames = !computer ? 14 : 13;
|
|
|
|
ocx = ocy = handOCx = handOCy = 0;
|
|
oldxSize = oldySize = handOldxSize = handOldySize = 1;
|
|
cx = dartPos.x;
|
|
cy = SHERLOCK_SCREEN_HEIGHT - _handSize.y - 20;
|
|
|
|
hddy = (cy - dartPos.y) / (numFrames - 7);
|
|
hddy += 2;
|
|
hddy = hddy * 10 / 8;
|
|
if (dartPos.y > 275)
|
|
hddy += 3;
|
|
|
|
for (int idx = 0; idx < numFrames; ++idx) {
|
|
_handSize.x = hands[idx]._offset.x + hands[idx]._width;
|
|
_handSize.y = hands[idx]._offset.y + hands[idx]._height;
|
|
handCy = SHERLOCK_SCREEN_HEIGHT - _handSize.y;
|
|
|
|
screen._backBuffer1.transBlitFrom(hands[idx], Common::Point(_handX, handCy));
|
|
screen.slamArea(_handX, handCy, _handSize.x + 1, _handSize.y);
|
|
screen.slamArea(handOCx, handOCy, handOldxSize, handOldySize);
|
|
screen.restoreBackground(Common::Rect(_handX, handCy, _handX + _handSize.x, handCy + _handSize.y));
|
|
|
|
handOCx = _handX;
|
|
handOCy = handCy;
|
|
handOldxSize = _handSize.x;
|
|
handOldySize = _handSize.y;
|
|
|
|
if (idx > 6) {
|
|
dartNum = idx - 6;
|
|
if (computer)
|
|
dartNum += 19;
|
|
|
|
xSize = (*_dartGraphics)[dartNum]._width;
|
|
ySize = (*_dartGraphics)[dartNum]._height;
|
|
|
|
ocx = drawX = cx - (*_dartGraphics)[dartNum]._width / 2;
|
|
ocy = drawY = cy - (*_dartGraphics)[dartNum]._height;
|
|
|
|
// Draw dart
|
|
screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], dartPos);
|
|
|
|
if (drawX < 0) {
|
|
xSize += drawX;
|
|
if (xSize < 0)
|
|
xSize = 1;
|
|
drawX = 0;
|
|
}
|
|
|
|
if (drawY < 0) {
|
|
ySize += drawY;
|
|
if (ySize < 0)
|
|
ySize = 1;
|
|
drawY = 0;
|
|
}
|
|
|
|
// Flush the drawn dart to the screen
|
|
screen.slamArea(drawX, drawY, xSize, ySize);
|
|
if (oldDrawX != -1)
|
|
// Flush the erased dart area
|
|
screen.slamArea(oldDrawX, oldDrawY, oldxSize, oldySize);
|
|
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(drawX, drawY),
|
|
Common::Rect(drawX, drawY, drawX + xSize, drawY + ySize));
|
|
|
|
oldDrawX = drawX;
|
|
oldDrawY = drawY;
|
|
oldxSize = xSize;
|
|
oldySize = ySize;
|
|
|
|
cy -= hddy;
|
|
}
|
|
|
|
events.wait(1);
|
|
}
|
|
|
|
// Clear the last little bit of the hand from the screen
|
|
screen.slamArea(handOCx, handOCy, handOldxSize, handOldySize);
|
|
|
|
// Erase the old dart
|
|
if (oldDrawX != -1)
|
|
screen.slamArea(oldDrawX, oldDrawY, oldxSize, oldySize);
|
|
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(drawX, drawY),
|
|
Common::Rect(drawX, drawY, drawX + xSize, drawY + ySize));
|
|
|
|
cx = dartPos.x;
|
|
cy = dartPos.y + 2;
|
|
oldDrawX = oldDrawY = -1;
|
|
|
|
for (int idx = 5; idx <= 23; ++idx) {
|
|
dartNum = idx - 4;
|
|
if (computer)
|
|
dartNum += 19;
|
|
|
|
if (idx < 14)
|
|
cy -= delta--;
|
|
else
|
|
if (idx == 14)
|
|
delta = 1;
|
|
if (idx > 14)
|
|
cy += delta++;
|
|
|
|
xSize = (*_dartGraphics)[dartNum]._width;
|
|
ySize = (*_dartGraphics)[dartNum]._height;
|
|
|
|
ocx = drawX = cx - (*_dartGraphics)[dartNum]._width / 2;
|
|
ocy = drawY = cy - (*_dartGraphics)[dartNum]._height;
|
|
|
|
screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(drawX, drawY));
|
|
|
|
if (drawX < 0) {
|
|
xSize += drawX;
|
|
if (xSize < 0)
|
|
xSize = 1;
|
|
drawX = 0;
|
|
}
|
|
|
|
if (drawY < 0) {
|
|
ySize += drawY;
|
|
if (ySize < 0)
|
|
ySize = 1;
|
|
drawY = 0;
|
|
}
|
|
|
|
// flush the dart
|
|
screen.slamArea(drawX, drawY, xSize, ySize);
|
|
if (oldDrawX != -1)
|
|
screen.slamArea(oldDrawX, oldDrawY, oldxSize, oldySize);
|
|
|
|
if (idx != 23)
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(drawX, drawY),
|
|
Common::Rect(drawX, drawY, drawX + xSize, drawY + ySize)); // erase dart
|
|
|
|
events.wait(1);
|
|
|
|
oldDrawX = drawX;
|
|
oldDrawY = drawY;
|
|
oldxSize = xSize;
|
|
oldySize = ySize;
|
|
}
|
|
|
|
dartNum = 19;
|
|
if (computer)
|
|
dartNum += 19;
|
|
xSize = (*_dartGraphics)[dartNum]._width;
|
|
ySize = (*_dartGraphics)[dartNum]._height;
|
|
|
|
// Draw final dart on the board
|
|
screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy));
|
|
screen._backBuffer2.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy));
|
|
screen.slamArea(ocx, ocy, xSize, ySize);
|
|
}
|
|
|
|
int Darts::findNumberOnBoard(int aim, Common::Point &pt) {
|
|
ImageFrame &img = (*_dartMap)[0];
|
|
|
|
if ((aim > 20) && ((aim != 25) && (aim != 50))) {
|
|
if ((aim <= 40) && ((aim & 1) == 0)) {
|
|
aim /= 2;
|
|
aim += 100;
|
|
} else {
|
|
aim /= 3;
|
|
aim += 120;
|
|
}
|
|
}
|
|
|
|
bool done = false;
|
|
for (int y = 0; y < img._width && !done; ++y) {
|
|
for (int x = 0; x < img._height && !done; ++x) {
|
|
byte score = *(const byte *)img._frame.getBasePtr(x, y);
|
|
|
|
if (score == aim) {
|
|
// Found a match. Aim at non-double/triple numbers whenever possible.
|
|
// ie. Aim at 18 instead of triple 6 or double 9
|
|
done = true;
|
|
|
|
if (aim < 21) {
|
|
pt.x = x + 10;
|
|
pt.y = y + 10;
|
|
|
|
score = *(const byte *)img._frame.getBasePtr(x, y);
|
|
if (score != aim)
|
|
done = false;
|
|
} else {
|
|
// Aiming at double or triple
|
|
pt.x = x + 3;
|
|
pt.y = y + 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pt = convertFromScreenToScoreCoords(pt);
|
|
|
|
if (aim == 3)
|
|
pt.y += 30;
|
|
if (aim == 17)
|
|
pt.y += 10;
|
|
|
|
if (aim == 15) {
|
|
pt.y += 5;
|
|
pt.x += 5;
|
|
}
|
|
|
|
pt.y = DARTBOARD_HEIGHT - pt.y;
|
|
return done;
|
|
}
|
|
|
|
void Darts::getComputerNumber(int playerNum, Common::Point &targetPos) {
|
|
int score;
|
|
int aim = 0;
|
|
Common::Point pt;
|
|
bool done = false;
|
|
int cricketaimset = false;
|
|
bool shootBull = false;
|
|
|
|
score = (playerNum == 0) ? _score1 : _score2;
|
|
|
|
if (_gameType == GAME_301) {
|
|
// Try to hit number
|
|
aim = score;
|
|
if(score > 60)
|
|
shootBull = true;
|
|
} else {
|
|
if (_cricketScore[playerNum][6] < 3) {
|
|
// shoot at bull first
|
|
aim = CRICKET_VALUE[6];
|
|
cricketaimset = true;
|
|
} else {
|
|
// Now check and shoot in this order: 20,19,18,17,16,15
|
|
for (int idx = 0; idx < 7; ++idx) {
|
|
if (_cricketScore[playerNum][idx] < 3) {
|
|
aim = CRICKET_VALUE[idx];
|
|
cricketaimset = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!cricketaimset) {
|
|
// Everything is closed
|
|
// just in case we don't get set in loop below, which should never happen
|
|
aim = 14;
|
|
for (int idx = 0; idx < 7; ++idx) {
|
|
if (_cricketScore[playerNum^1][idx] < 3) {
|
|
// Opponent has this open
|
|
aim = CRICKET_VALUE[idx];
|
|
|
|
if (idx == 6)
|
|
shootBull = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (shootBull) {
|
|
// Aim at bulls eye
|
|
targetPos.x = targetPos.y = 75;
|
|
|
|
if (_level <= 1) {
|
|
if (_vm->getRandomNumber(1) == 1) {
|
|
targetPos.x += (_vm->getRandomNumber(20)-10);
|
|
targetPos.y += (_vm->getRandomNumber(20)-10);
|
|
}
|
|
}
|
|
} else {
|
|
// Loop in case number does not exist on board
|
|
do {
|
|
done = findNumberOnBoard(aim, pt);
|
|
--aim;
|
|
} while (!done);
|
|
|
|
pt.x += DARTBOARD_TOTALLEFT * 70 / 100;
|
|
pt.y += DARTBOARD_TOTALTOP * 70 / 100;
|
|
|
|
// old * 3/2
|
|
targetPos.x = pt.x * 100 / DARTBOARD_TOTALX * 3 / 2;
|
|
targetPos.y = pt.y * 100 / DARTBOARD_TOTALY * 3 / 2;
|
|
}
|
|
|
|
// the higher the level, the more accurate the throw
|
|
int v = _vm->getRandomNumber(9);
|
|
v += _level * 2;
|
|
|
|
if (v <= 2) {
|
|
targetPos.x += _vm->getRandomNumber(70) - 35;
|
|
targetPos.y += _vm->getRandomNumber(70) - 35;
|
|
} else if (v <= 4) {
|
|
targetPos.x += _vm->getRandomNumber(50) - 25;
|
|
targetPos.y += _vm->getRandomNumber(50) - 25;
|
|
} else if (v <= 6) {
|
|
targetPos.x += _vm->getRandomNumber(30) - 15;
|
|
targetPos.y += _vm->getRandomNumber(30) - 15;
|
|
} else if (v <= 8) {
|
|
targetPos.x += _vm->getRandomNumber(20) -10;
|
|
targetPos.y += _vm->getRandomNumber(20) -10;
|
|
} else if (v <= 10) {
|
|
targetPos.x += _vm->getRandomNumber(11) - 5;
|
|
targetPos.y += _vm->getRandomNumber(11) - 5;
|
|
}
|
|
|
|
if (targetPos.x < 1)
|
|
targetPos.x = 1;
|
|
if (targetPos.y < 1)
|
|
targetPos.y = 1;
|
|
}
|
|
|
|
int Darts::throwDart(int dartNum, int computer) {
|
|
Events &events = *_vm->_events;
|
|
Screen &screen = *_vm->_screen;
|
|
int height;
|
|
int horiz;
|
|
Common::Point targetPos;
|
|
Common::String temp;
|
|
|
|
/* clear keyboard buffer */
|
|
events.clearEvents();
|
|
|
|
erasePowerBars();
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, "%s # %d", FIXED(Dart), dartNum);
|
|
|
|
drawDartsLeft(dartNum, computer);
|
|
|
|
if (!computer) {
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", FIXED(HitAKey));
|
|
screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing * 2), 0, "%s", FIXED(ToStart));
|
|
}
|
|
|
|
if (!computer) {
|
|
// Wait for a hit
|
|
while (!dartHit())
|
|
;
|
|
} else {
|
|
events.wait(1);
|
|
}
|
|
|
|
drawDartsLeft(dartNum + 1, computer);
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1),
|
|
Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
|
|
screen.blitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1),
|
|
Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
|
|
|
|
if (computer) {
|
|
getComputerNumber(computer - 1, targetPos);
|
|
} else {
|
|
// Keyboard control
|
|
targetPos = Common::Point(0, 0);
|
|
}
|
|
|
|
horiz = drawHand(targetPos.x, computer);
|
|
height = doPowerBar(Common::Point(DART_BAR_VX, DART_HEIGHT_Y), DART_COLOR_FORE, targetPos.y, 1);
|
|
|
|
// Invert height
|
|
height = 101 - height;
|
|
|
|
// Copy power bars to the secondary back buffer
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1),
|
|
Common::Rect(DART_BAR_VX - 1, DART_HEIGHT_Y - 1, DART_BAR_VX - 1 + 10,
|
|
DART_HEIGHT_Y - 1 + DART_BAR_SIZE + 2));
|
|
|
|
Common::Point dartPos(DARTBOARD_TOTALLEFT + horiz*DARTBOARD_TOTALX / 100,
|
|
DARTBOARD_TOTALTOP + height * DARTBOARD_TOTALY / 100);
|
|
|
|
dartPos.x += 2 - _vm->getRandomNumber(4);
|
|
dartPos.y += 2 - _vm->getRandomNumber(4);
|
|
|
|
drawDartThrow(dartPos, computer);
|
|
return dartScore(dartPos);
|
|
}
|
|
|
|
void Darts::doCricketScoreHits(int player, int scoreIndex, int numHits) {
|
|
while (numHits--) {
|
|
if (_cricketScore[player][scoreIndex] < 3)
|
|
_cricketScore[player][scoreIndex]++;
|
|
else if (_cricketScore[player ^ 1][scoreIndex] < 3) {
|
|
if (player == 0)
|
|
_score1 += CRICKET_VALUE[scoreIndex];
|
|
else
|
|
_score2 += CRICKET_VALUE[scoreIndex];
|
|
}
|
|
}
|
|
}
|
|
|
|
void Darts::updateCricketScore(int player, int dartVal, int multiplier) {
|
|
if (dartVal < 15)
|
|
return;
|
|
|
|
if (dartVal <= 20)
|
|
doCricketScoreHits(player, 20 - dartVal, multiplier);
|
|
else if (dartVal == 25)
|
|
doCricketScoreHits(player, 6, multiplier);
|
|
}
|
|
|
|
void Darts::drawDartsLeft(int dartNum, int computer) {
|
|
Screen &screen = *_vm->_screen;
|
|
const int DART_X1[3] = { 391, 451, 507 };
|
|
const int DART_Y1[3] = { 373, 373, 373 };
|
|
const int DART_X2[3] = { 393, 441, 502 };
|
|
const int DART_Y2[3] = { 373, 373, 373 };
|
|
|
|
screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(DART_X1[0], DART_Y1[0]),
|
|
Common::Rect(DART_X1[0], DART_Y1[0], SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
|
|
|
|
for (int idx = 2; idx >= dartNum - 1; --idx) {
|
|
if (computer)
|
|
screen._backBuffer1.transBlitFrom((*_dartsLeft)[idx + 3], Common::Point(DART_X2[idx], DART_Y2[idx]));
|
|
else
|
|
screen._backBuffer1.transBlitFrom((*_dartsLeft)[idx], Common::Point(DART_X1[idx], DART_Y1[idx]));
|
|
}
|
|
|
|
screen.slamArea(DART_X1[0], DART_Y1[0], SHERLOCK_SCREEN_WIDTH - DART_X1[0], SHERLOCK_SCREEN_HEIGHT - DART_Y1[0]);
|
|
}
|
|
|
|
} // End of namespace Tattoo
|
|
|
|
} // End of namespace Sherlock
|