#include #include #include #include #include "8ball.h" #include "interface.h" #include "physics.h" #include "utility.h" #include "team.h" #include "player.h" #include "global.h" const unsigned int BILLIARDS_COUNT = 15; K_EXPORT_COMPONENT_FACTORY( libkue8ball, EightBallFactory ) TQObject *EightBallFactory::createObject (TQObject *parent, const char* name, const char* classname, const TQStringList &args = TQStringList() ) { Q_UNUSED(args); if (classname != TQString("KueRulesEngine")) return 0; return new EightBall(parent, name); } EightBall::EightBall(TQObject *parent, const char *name) : KueRulesEngine(parent, name) { KueUtility::layoutTable(); KueUtility::layoutPockets(); KueUtility::layoutBilliards(KueUtility::Triangle); // Reset our state (NOTE: anyone see anything missing?) _game_called = GAME_UNCALLED; _current_team = 0; _first_hit = -1; _first_sunk = -1; _scratch = false; _broke = false; _current_player = KueGlobal::teams()->at(_current_team)->nextPlayer(); } EightBall::~EightBall() { } void EightBall::start() { cuePlaced(); } void EightBall::billiardSunk(unsigned int ball, unsigned int /* pocket */) { // Called when the physics engine sinks a billiard // Somebody must win the game if the 8ball is sunk, the question is who if (ballIsMagic(ball)) { if (onlyMagicLeft(_current_team)) { // It was our only ball left, we win playerWins(_current_team); } else { // We messed up real bad playerWins(!_current_team); } } // Have we sunk nothing yet? Or ist the cue ball? if ((ownsBall(!_current_team, ball)) || ballIsCue(ball)) { // Oops, we shouldn't have sunk that... scratch! _scratch = true; } else if (_first_sunk == -1) { // Ah, it's all good... _first_sunk = ball; } } void EightBall::billiardHit(unsigned int ball1, unsigned int ball2) { // Is this our first hit? if (_first_hit == -1) { // Count the one that isn't the cue ball ;) if (ballIsCue(ball1)) { _first_hit = ball2; _broke = true; } else if (ballIsCue(ball2)) { _first_hit = ball1; _broke = true; } } } void EightBall::motionStopped() { // The physics engine has finished its job, turn it off to save CPU time KueGlobal::physics()->stop(); // Did we hit a ball? And did we own that ball? if ((_first_hit == -1) || ownsBall(!_current_team, _first_hit)) { // Nope, scratch _scratch = true; } // Did we hit a magic ball first when there are other balls left? if ((!onlyMagicLeft(_current_team)) && ballIsMagic(_first_hit)) { // Scratch! _scratch = true; } // We downright lose if we scratch on the 8-ball (HA!) if (onlyMagicLeft(_current_team) && _scratch) { playerWins(!_current_team); return; } // We lose our turn if the shot was a scratch, or we sunk nothing if ((_scratch) || (_first_sunk == -1)) { if (_current_team == 0) _current_team = 1; else _current_team = 0; _current_player = KueGlobal::teams()->at(_current_team)->nextPlayer(); } if (_first_sunk != -1) { if (_game_called == GAME_UNCALLED) { if (_current_team) { _game_called = (ballIsSolid(_first_sunk) ? GAME_PLAYER1_STRIPES : GAME_PLAYER1_SOLIDS); } else { _game_called = (ballIsSolid(_first_sunk) ? GAME_PLAYER1_SOLIDS : GAME_PLAYER1_STRIPES); } } } // Reset our shot state _first_hit = -1; _first_sunk = -1; // Did we scratch? if (_scratch) { // Create the cue ball again KueBilliard cue( KueGlobal::physics()->fieldWidth() / 4.0, KueGlobal::physics()->fieldHeight() / 2.0, KueUtility::defaultBilliardRadius() ); if (_broke) { // We scratched, the cue ball goes back home emit(showMessage(placeCueBallMessage())); _current_player->placeBilliard( 0, cue, KueGlobal::physics()->fieldWidth() / 4.0, this, TQ_SLOT(cuePlaced()) ); } else { KueGlobal::physics()->insertBilliard(0, cue); cuePlaced(); } } else { emit(showMessage(startShotMessage())); // The cue ball stays where it is, go right to the shot _current_player->takeShot(0, false, this, TQ_SLOT(shotTaken())); } } // Is a ball solid? bool EightBall::ballIsSolid(unsigned int number) { return ((number > 0) && (number < 8)); } // Is a ball 'magic' (8 ball)? bool EightBall::ballIsMagic(unsigned int number) { return (number == 8); } // Is a ball striped? bool EightBall::ballIsStripe(unsigned int number) { return (number > 8); } // Is a ball the cue ball (ball 0) bool EightBall::ballIsCue(unsigned int number) { return (number == 0); } // Does the given player only have the 8 ball left to sink? bool EightBall::onlyMagicLeft(int player) { // It's impossible if the game is uncalled (any game with a sunk ball is called) if (_game_called == GAME_UNCALLED) return false; // Check all the billiards belonging to the player for (unsigned int x = 1;x < BILLIARDS_COUNT;x++) { // Does the player own it, and does it still exist if (ownsBall(player, x) && KueGlobal::physics()->billiards()[x]) { // So apparently there is more than magic left return false; } } // Nope, only magic return true; } void EightBall::playerWins(int player) { Q_UNUSED(player); TQString message; // Announce the winner message = i18n("%1 wins!").arg(_current_player->name()); // Show the message emit(showMessage(message)); // Tell the rest of the game about the stunning victory emit(gameOver(message)); } // Does the player own the given ball bool EightBall::ownsBall(int player, unsigned int ball) { // Until the game is called, nobody owns anything if (_game_called == GAME_UNCALLED) { return false; } // And nobody ever owns the 8 ball if (ballIsMagic(ball)) return false; if (player) { return (_game_called == GAME_PLAYER1_STRIPES) ? ballIsSolid(ball) : ballIsStripe(ball); } else { return (_game_called == GAME_PLAYER1_STRIPES) ? ballIsStripe(ball) : ballIsSolid(ball); } } TQString EightBall::startShotMessage() { TQString message; // What type of shot is this? if (_broke) message = i18n("%1's shot").arg(_current_player->name()); else message = i18n("%1's break shot").arg(_current_player->name()); message = message + " " + sideString(); return message; } TQString EightBall::placeCueBallMessage() { TQString message; // Tell the user what is going on message = i18n("%1 placing cue ball").arg(_current_player->name()); message = message + " " + sideString(); return message; } TQString EightBall::sideString() { if (_game_called == GAME_UNCALLED) return ""; if (_current_team) return (_game_called == GAME_PLAYER1_STRIPES) ? i18n("(solids)") : i18n("(stripes)"); else return (_game_called == GAME_PLAYER1_STRIPES) ? i18n("(stripes)") : i18n("(solids)"); } void EightBall::cuePlaced() { // Tell the interface code to start the shot emit(showMessage(startShotMessage())); _current_player->takeShot(0, true, this, TQ_SLOT(shotTaken())); } void EightBall::shotTaken() { // Start the physics engine KueGlobal::physics()->start(); // Reset the shot-related variables _scratch = false; _first_hit = -1; _first_sunk = -1; } #include "8ball.moc"