/* * 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 #include // QT includes #include #include #include #include #include // KDE includes #include #include #include #include #include #include #include #include #include // own includes #include "betbox.h" #include "kpaint.h" #include "optionsdlg.h" #include "newgamedlg.h" #include "player.h" #include "playerbox.h" #include "version.h" #include "kpoker.h" #include "defines.h" // ================================================================ // Class PokerGame PokerGame::PokerGame(KRandomSequence *random) : m_deck(random) { // We don't need to save if we just started. m_isDirty = false; // Some defaults. m_type = SinglePlayer; } PokerGame::~PokerGame() { m_activePlayers.clear(); m_removedPlayers.clear(); } void PokerGame::dealCards(PokerPlayer *player, bool skip[]) { CardValue card; for (int i = 0; i < PokerHandSize; i++) { if (skip[i]) continue; card = m_deck.getTopCard(); player->takeCard(i, card); } } void PokerGame::activatePlayer(PokerPlayer *player) { if (!m_activePlayers.contains(player)) { m_activePlayers.append(player); m_removedPlayers.remove(player); } } void PokerGame::inactivatePlayer(PokerPlayer *player) { if (m_activePlayers.contains(player)) { m_activePlayers.remove(player); m_removedPlayers.append(player); } } void PokerGame::newGame(PokerGameType type, int numPlayers, PokerPlayer *players, int minBet, int maxBet) { m_type = type; // Store the players. These are never changed in the current implementation. m_numPlayers = numPlayers; m_players = players; setBettingLimits(minBet, maxBet); setState(StateStartRound); // Initiate player arrays. Make all players active from the start. m_activePlayers.clear(); m_removedPlayers.clear(); for (unsigned int i = 0; i < m_numPlayers; i++) m_activePlayers.append(&m_players[i]); // Inform players how much they may bet. for (unsigned int i = 0; i < m_activePlayers.count(); i++) m_activePlayers.at(i)->setBetDefaults(m_minBet, m_maxBet); } void PokerGame::newRound() { // Reset the pot to zero. m_pot = 0; // Collect the cards and shuffle them. m_deck.reset(); m_deck.shuffle(); // Clear the list of active and removed players. m_activePlayers.clear(); m_removedPlayers.clear(); } // ================================================================ // Global variables CardImages *cardImages; // ================================================================ // Class kpok kpok::kpok(TQWidget *parent, const char *name) : TQWidget(parent, name), m_game(&m_random) { TQString version; m_random.setSeed(0); // This class owns the players. Create them here. // Currently we always allocate two - one human and one computer. m_numPlayers = 2; // FIXME: Hard coded!! m_players = new PokerPlayer[m_numPlayers]; // Initialize the first one to human... m_players[0].setHuman(); m_players[0].setName(i18n("You")); // ...and the rest to computer players. for (int unsigned i = 1; i < m_numPlayers; i++) m_players[i].setName(TQString("Computer %1").arg(i-1)); lastHandText = ""; version = kapp->caption() + " " + KPOKER_VERSION; setCaption( version ); mOptions = 0; playerBox = 0; adjust = false; initWindow(); // FIXME: Change this name!!! initSound(); if (!readEntriesAndInitPoker()) exit(0); } kpok::~kpok() { if (mOptions != 0) { if (m_numPlayers > 1) m_game.setBettingLimits(mOptions->getMinBet(), mOptions->getMaxBet()); drawDelay = mOptions->getDrawDelay(); // cashPerRound = mOptions->getCashPerRound(); // NOT(!) configurable } TDEConfig* conf = kapp->config(); conf->setGroup("General"); conf->writeEntry("MinBet", m_game.getMinBet()); conf->writeEntry("MaxBet", m_game.getMaxBet()); // conf->writeEntry("CashPerRound", cashPerRound); conf->writeEntry("DrawDelay", drawDelay); delete[] m_players; for (unsigned int i = 0; i < m_numPlayers; i++) delete playerBox[i]; delete[] playerBox; delete mOptions; } // Init the main window and load the configuration and card images. // // Only called by kpok::kpok() once. void kpok::initWindow() { m_blinking = true; m_blinkStat = 0; m_blinkingBox = 0; // General font stuff. Define myFixedFont and wonFont. TQFont myFixedFont; myFixedFont.setPointSize(12); TQFont wonFont; wonFont.setPointSize(14); wonFont.setBold(true); topLayout = new TQVBoxLayout(this, BORDER); TQVBoxLayout* topInputLayout = new TQVBoxLayout; topLayout->addLayout(topInputLayout); TQHBoxLayout* betLayout = new TQHBoxLayout; inputLayout = new TQHBoxLayout; inputLayout->addLayout(betLayout); topInputLayout->addLayout(inputLayout); // The draw button drawButton = new TQPushButton(this); drawButton->setText(i18n("&Deal")); connect(drawButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(drawClick())); inputLayout->addWidget(drawButton); inputLayout->addStretch(1); // The waving text TQFont waveFont; waveFont.setPointSize(16); waveFont.setBold(true); TQFontMetrics tmp(waveFont); // The widget where the winner is announced. mWonWidget = new TQWidget(this); inputLayout->addWidget(mWonWidget, 2); mWonWidget->setMinimumHeight(50); //FIXME hardcoded value for the wave mWonWidget->setMinimumWidth(tmp.width(i18n("You won %1").arg(TDEGlobal::locale()->formatMoney(100))) + 20); // workaround for width problem in wave TQHBoxLayout* wonLayout = new TQHBoxLayout(mWonWidget); wonLayout->setAutoAdd(true); wonLabel = new TQLabel(mWonWidget); wonLabel->setFont(wonFont); wonLabel->setAlignment(AlignCenter); wonLabel->hide(); inputLayout->addStretch(1); // The pot view potLabel = new TQLabel(this); potLabel->setFont(myFixedFont); potLabel->setFrameStyle(TQFrame::WinPanel | TQFrame::Sunken); inputLayout->addWidget(potLabel, 0, AlignCenter); // Label widget in the lower left. clickToHold = new TQLabel(this); clickToHold->hide(); // Timers blinkTimer = new TQTimer(this); connect( blinkTimer, TQT_SIGNAL(timeout()), TQT_SLOT(bTimerEvent()) ); waveTimer = new TQTimer(this); connect( waveTimer, TQT_SIGNAL(timeout()), TQT_SLOT(waveTimerEvent()) ); drawTimer = new TQTimer(this); connect (drawTimer, TQT_SIGNAL(timeout()), TQT_SLOT(drawCardsEvent()) ); // and now the betUp/Down Buttons betBox = new BetBox(this, 0); betLayout->addWidget(betBox); connect(betBox, TQT_SIGNAL(betChanged(int)), this, TQT_SLOT(betChange(int))); connect(betBox, TQT_SIGNAL(betAdjusted()), this, TQT_SLOT(adjustBet())); connect(betBox, TQT_SIGNAL(fold()), this, TQT_SLOT(out())); // some tips TQToolTip::add(drawButton, i18n("Continue the round")); TQToolTip::add(potLabel, i18n("The current pot")); // Load all cards into pixmaps first -> in the constructor. cardImages = new CardImages(this, 0); // The configuration TDEConfig* conf = kapp->config(); conf->setGroup("General"); // Load the card deck. if (conf->readBoolEntry("RandomDeck", true)) { cardImages->loadDeck(KCardDialog::getRandomDeck()); } else { cardImages->loadDeck(conf->readPathEntry("DeckPath", KCardDialog::getDefaultDeck())); } if (conf->readBoolEntry("RandomCardDir", true)) { cardImages->loadCards(KCardDialog::getRandomCardDir()); } else { cardImages->loadCards(conf->readPathEntry("CardPath", KCardDialog::getDefaultCardDir())); } } // Start a new complete game (not a round). void kpok::newGame() { NewGameDlg* newGameDlg; // Get a "New Game" dialog. lastHandText = ""; newGameDlg = new NewGameDlg(this); newGameDlg->hideReadingFromConfig(); if (newGameDlg->exec()) { stopBlinking(); stopDrawing(); stopWave(); // Delete the old values. for (unsigned int i = 0; i < m_numPlayers; i++) delete playerBox[i]; delete[] playerBox;// necessary? int numPlayers = newGameDlg->getPlayers(); // Most things will be done in initPoker. initPoker(numPlayers); // Set/show the name and money of all players. for (unsigned int i = 0; i < m_numPlayers; i++) { m_players[i].setName(newGameDlg->name(i)); playerBox[i]->showName(); m_players[i].setCash((newGameDlg->money() >= m_game.getMinBet()) ? newGameDlg->money() : START_MONEY); m_game.setDirty(); } // Show the money for all players and the pot. paintCash(); // Activate the Draw button. drawButton->setText(i18n("&Deal")); drawButton->setEnabled(true); } delete newGameDlg; } void kpok::newRound() { bool onePlayerGame = false; m_game.newRound(); playerBox[0]->setHeldEnabled(false); if (m_numPlayers == 1) onePlayerGame = true; readOptions(); // maybe some options have changed so check em if (m_players[0].getCash() < m_game.getMinBet()) noMoney(); else { for (unsigned int i = 0; i < m_numPlayers; i++) { if (m_players[i].getCash() >= m_game.getMinBet()) m_game.activatePlayer(&m_players[i]); else removePlayerFromRound(&m_players[i]); } } if (m_game.getNumActivePlayers() == 1 && m_game.getType() != SinglePlayer) switchToOnePlayerRules(); m_blinkingBox = 0; wonLabel->hide(); stopBlinking(); stopWave(); for (int i = 0; i < m_game.getNumActivePlayers(); i++) m_game.getActivePlayer(i)->newRound(); // We are beginning a new round so every card is available. drawAllDecks(); playerBox[0]->showHelds(false); // Deal first cards of the round bool skip[PokerHandSize]; for (int i = 0; i < PokerHandSize; i++) skip[i] = false; for (int i = 0; i < m_game.getNumActivePlayers(); i++) drawCards(m_game.getActivePlayer(i), skip); if (m_game.getNumActivePlayers() > 1) { findHumanPlayer()->changeBet(m_game.getMinBet()); m_game.bet(m_game.getMinBet()); betBox->show(); } else { m_game.getActivePlayer(0)->changeBet(cashPerRound); betBox->hide(); } paintCash(); drawTimer->start(drawDelay, TRUE); } void kpok::bet() { // The players will bet, now. Player 1 (the human one ;-)) has // already bet using the betBox ALL players (except player 1 who has // already had) will get a chance to raise the value if nobody // raises further that player will not get another chance, else he // will. bool raised = false; int oldMustBet = 0; if (m_game.getState() == StateBet2) oldMustBet = currentMustBet; if (m_game.getState() == StateBet1 || m_game.getState() == StateBet2) { // The betting has just begun. This can be either the first or // the second betting phase (state == StateBet1 or StateBet2). // FIXME: These state names must be changed! // Find out how much the other players must bet. currentMustBet = findHumanPlayer()->getCurrentBet(); // First bet as usual. for (int i = 0; i < m_game.getNumActivePlayers(); i++) { PokerPlayer *player = m_game.getActivePlayer(i); int playerBet = 0; if (player->getHuman()) continue; if (m_game.getState() == StateBet1) // first bet phase playerBet = player->bet(currentMustBet); else if (m_game.getState() == StateBet2) // 2nd bet phase playerBet = player->raise(currentMustBet); if (playerBet < currentMustBet) { removePlayerFromRound(player); // FIXME: This should be bet from the beginning! if (m_game.getState() == StateBet1) m_game.bet(m_game.getMinBet()); i--; } else { // The player is seeing or has raised. if (playerBet > currentMustBet) raised = true; currentMustBet = playerBet; m_game.bet(currentMustBet - oldMustBet); } } } else if (m_game.getState() == StateRaise1 || m_game.getState() == StateRaise2) { // The bet has been raised. paintCash(); for (int i = 0; i < m_game.getNumActivePlayers(); i++) { PokerPlayer *player = m_game.getActivePlayer(i); // human player if (player->getCurrentBet() < currentMustBet && player->getHuman()) { removePlayerFromRound(player); i--; } } } paintCash(); oldBet_raise = findHumanPlayer()->getCurrentBet(); // used by out() only if (m_game.getState() == StateBet1 || m_game.getState() == StateBet2) { if (raised) { if (m_game.getState() == StateBet1) m_game.setState(StateRaise1); else m_game.setState(StateRaise2); if (adjust) adjustBet(); else out(); // not necessary betBox->setEnabled(true); betBox->beginRaise(); if (adjust) emit statusBarMessage(i18n("Clicking on draw means you adjust your bet")); else emit statusBarMessage(i18n("Clicking on draw means you are out")); } else { if (m_game.getState() == StateBet1) m_game.setState(StateExchangeCards); else m_game.setState(StateSee); } } else if (m_game.getState() == StateRaise1 && !raised) { emit clearStatusBar(); // weWillAdjustLabel->hide(); betBox->stopRaise(); m_game.setState(StateExchangeCards); } else if (m_game.getState() == StateRaise2 && !raised) { emit clearStatusBar(); // weWillAdjustLabel->hide(); betBox->stopRaise(); m_game.setState(StateSee); } // Check if player 1 is out -> for players > 2 // TODO: maybe if (!m_activePlayers.contains(humanPlayer)) // {exchangeCards(); bet(); displayerWinner_computer();return;} // don't continue game if player 1 is alone // TODO: port to players > 2 // this is ONLY working for players <= 2 if (m_game.getNumInactivePlayers() >= 1 && m_game.getNumActivePlayers() == 1) displayWinner_Computer(m_game.getActivePlayer(0), true); } void kpok::out() { // weWillAdjustLabel->hide(); emit clearStatusBar(); m_game.bet(oldBet_raise - findHumanPlayer()->getCurrentBet()); findHumanPlayer()->changeBet(oldBet_raise - findHumanPlayer()->getCurrentBet()); paintCash(); // Go to next state immediately. (Previously we told the user to // click the action button.) drawClick(); //drawButton->setText(i18n("&End Round")); } void kpok::adjustBet() { emit clearStatusBar(); betChange(currentMustBet - findHumanPlayer()->getCurrentBet()); paintCash(); } // Initiate for a completely new game (not a round). // // This is called from newGame(), readEntriesAndInitPoker(), loadGame(). // void kpok::initPoker(unsigned int numPlayers) { m_numPlayers = numPlayers; // Tell the game about the players also. PokerGameType gametype = (numPlayers == 1) ? SinglePlayer : MultiPlayer; // Read some defaults. kapp->config()->setGroup("General"); int minBet = kapp->config()->readNumEntry("MinBet", MIN_BET); int maxBet = kapp->config()->readNumEntry("MaxBet", MAX_BET); // Start a new poker game using the data found out above. m_game.newGame(gametype, m_numPlayers, m_players, minBet, maxBet); // Not (yet) configurable cashPerRound = CASH_PER_ROUND; drawDelay = kapp->config()->readNumEntry("DrawDelay", DRAWDELAY); m_blinkingBox = 0; currentMustBet = m_game.getMinBet(); // --- Graphics --- // Make all labels / boxes / cardwidgets for every player. playerBox = new PlayerBox *[numPlayers]; for (int unsigned i = 0; i < numPlayers; i++) { playerBox[i] = new PlayerBox(i == 0, this); playerBox[i]->setPlayer(&m_players[i]); if (i == 0) topLayout->insertWidget(0, playerBox[i]); else topLayout->addWidget(playerBox[i]); playerBox[i]->showName(); // If it has been deleted and created again it hasn't be shown // correctly - hiding and re-showing solves the problem. playerBox[i]->hide(); playerBox[i]->show(); } // Connects for player 1 // // FIXME: Make CardWidget::toggleHeld() work. playerBox[0]->activateToggleHeld(); connect(playerBox[0], TQT_SIGNAL(toggleHeld()), this, TQT_SLOT(toggleHeld())); // hide some things playerBox[0]->showHelds(false); wonLabel->hide(); emit showClickToHold(false); // Different meaning of the status for single and multi player games. if (m_game.getNumActivePlayers() > 1) { setHand(i18n("Nobody"), false); betBox->show(); betBox->setEnabled(false); potLabel->show(); } else { setHand(i18n("Nothing")); betBox->hide(); potLabel->hide(); playerBox[0]->singlePlayerGame(cashPerRound); } // Some final inits. drawStat = 0; waveActive = 0; fCount = 0; // Finally clear the pot and show the decks/cash - in one word: begin :-) m_game.clearPot(); drawAllDecks(); for (unsigned int i = 0; i < m_numPlayers; i++) { playerBox[i]->repaintCard(); } paintCash(); playerBox[0]->setHeldEnabled(false); } void kpok::paintCash() { for (unsigned int i = 0; i < m_numPlayers; i++) { playerBox[i]->showCash(); } potLabel->setText(i18n("Pot: %1").arg(TDEGlobal::locale()->formatMoney(m_game.getPot()))); } void kpok::updateLHLabel() { if (!lastHandText.isEmpty()) setHand(lastHandText); else if (m_game.getNumActivePlayers() > 1) setHand(i18n("Nobody"), false); else setHand(i18n("Nothing")); } void kpok::setHand(const TQString& newHand, bool lastHand) { emit changeLastHand(newHand, lastHand); lastHandText = newHand; } void kpok::toggleHeld() { if (m_game.getState() == StateBet1 || m_game.getState() == StateRaise1) playSound("hold.wav"); } void kpok::drawClick() { if (!drawButton->isEnabled()) return; // If this is the start of a new round, then deal new cards. if (m_game.getState() == StateStartRound) { drawButton->setEnabled(false); betBox->setEnabled(false); newRound(); } else if (m_game.getState() == StateBet1) { // bet emit showClickToHold(false); bet(); if (m_game.getState() == StateExchangeCards) {// should be set in bet() drawClick(); } } else if (m_game.getState() == StateRaise1) { // continue bet bet(); if (m_game.getState() == StateExchangeCards) {// should be set in bet() drawClick(); } } else if (m_game.getState() == StateExchangeCards) { // exchange cards drawButton->setEnabled(false); playerBox[0]->setHeldEnabled(false); betBox->setEnabled(false); bool skip[PokerHandSize]; for (int i = 0; i < PokerHandSize; i++) skip[i] = false; for (int i = 0; i < m_game.getNumActivePlayers(); i++) { if (!m_game.getActivePlayer(i)->getHuman()) m_game.getActivePlayer(i)->exchangeCards(skip); else { for (int i = 0; i < PokerHandSize; i++) { skip[i] = playerBox[0]->getHeld(i); if (!skip[i]) playerBox[0]->paintDeck(i); } } drawCards(m_game.getActivePlayer(i), skip); } if (playerBox[0]->getHeld(0)) drawTimer->start(0, TRUE); else drawTimer->start(drawDelay, TRUE); } else if (m_game.getState() == StateBet2) { // raise setBetButtonEnabled(false); bet(); if (m_game.getState() == StateSee)//should be set in bet()->if no one has raised drawClick(); } else if (m_game.getState() == StateRaise2) { bet(); if (m_game.getState() == StateSee) drawClick(); } else if (m_game.getState() == StateSee) winner(); } void kpok::drawCards(PokerPlayer* p, bool skip[]) { m_game.dealCards(p, skip); } void kpok::displayWinner_Computer(PokerPlayer* winner, bool othersPassed) { // Determine the box that contains the winner. for (unsigned int i = 0; i < m_numPlayers; i++) { if (&m_players[i] == winner) m_blinkingBox = i; } // Give the pot to the winner. winner->setCash(winner->getCash() + m_game.getPot()); m_game.setDirty(); // Generate a string with winner info and show it. TQString label; if (winner->getHuman()) label = i18n("You won %1").arg(TDEGlobal::locale()->formatMoney(m_game.getPot())); else label = i18n("%1 won %2").arg(winner->getName()).arg(TDEGlobal::locale()->formatMoney(m_game.getPot())); wonLabel->setText(label); // Start the waving motion of the text. TQFont waveFont; waveFont.setBold(true); waveFont.setPointSize(16); TQFontMetrics tmp(waveFont); mWonWidget->setMinimumWidth(tmp.width(label) + 20); // Play a suitable sound. if (winner->getHuman()) { playSound("win.wav"); wonLabel->hide(); startWave(); } else { playSound("lose.wav"); wonLabel->show(); } m_game.clearPot(); m_game.setState(StateStartRound); drawButton->setEnabled(true); setHand(winner->getName(), false); paintCash(); // Only start blinking if player 1 is still in. if (m_game.isActivePlayer(&m_players[0]) && !othersPassed) startBlinking(); drawButton->setText(i18n("&Deal New Round")); } void kpok::showComputerCards() { // Don't show cards of 'out' players. for (int i = 0; i < m_game.getNumActivePlayers(); i++) { if (!m_game.getActivePlayer(i)->getHuman()){ playerBox[i]->paintCard(drawStat); //TODO change: if (i == 1) //TODO : CHANGE! playSound("cardflip.wav");//perhaps in playerbox or even in cardwidget } } if (drawStat == 4) { // just did last card drawButton->setEnabled(true); drawStat = 0; } else { // only inc drawStat if not done with displaying drawStat++; showComputerCards(); } } void kpok::setBetButtonEnabled(bool enabled) { betBox->setEnabled(enabled); } void kpok::drawCardsEvent() { if (!playerBox[0]->getHeld(drawStat)) { playerBox[0]->paintCard(drawStat); playSound("cardflip.wav");//maybe in playerbox or even in cardwidget } if (drawStat == 4) { // just did last card drawButton->setEnabled(true); betBox->setEnabled(true); drawStat = 0; if (m_game.getState() == StateExchangeCards) { if (m_game.getType() == SinglePlayer) result(); else { // Now give players the chance to raise. drawButton->setText(i18n("&See!")); m_game.setState(StateBet2); } } else if (m_game.getState() == StateStartRound) { playerBox[0]->setHeldEnabled(true); emit showClickToHold(true); //clickToHold->show(); //TODO: m_game.setState(StateBet1); drawButton->setText(i18n("&Draw New Cards")); } } else { // only inc drawStat if not done with displaying drawStat++; // look at next card and if it is held instantly call drawCardEvent again if (playerBox[0]->getHeld(drawStat)) drawTimer->start(0,TRUE); else drawTimer->start(drawDelay,TRUE); } } // Called to display the result in a single player game. void kpok::result() { int testResult = m_game.getActivePlayer(0)->testHand(); switch (testResult) { case Pair: if (m_game.getActivePlayer(0)->getHand().get_firstRank() < JACK) { displayWin(i18n("Nothing"), 0); break; } displayWin(i18n("One Pair"), 5); break; case TwoPairs: displayWin(i18n("Two Pairs"), 10); break; case ThreeOfAKind: displayWin(i18n("3 of a Kind"), 15); break; case Straight: displayWin(i18n("Straight"), 20); break; case Flush: displayWin(i18n("Flush"), 25); break; case FullHouse: displayWin(i18n("Full House"), 40); break; case FourOfAKind: displayWin(i18n("4 of a Kind"), 125); break; case StraightFlush: displayWin(i18n("Straight Flush"), 250); break; case RoyalFlush: displayWin(i18n("Royal Flush"), 2000); break; default: displayWin(i18n("Nothing"), 0); break; } startBlinking(); m_game.setState(StateStartRound); if (m_game.getActivePlayer(0)->getCash() < cashPerRound) noMoney(); } // Display winner and give money and so on. void kpok::winner() { PokerPlayer *winner; showComputerCards(); winner = m_game.getActivePlayer(0); for (int i = 1; i < m_game.getNumActivePlayers(); i++) { if (winner->getHand() < m_game.getActivePlayer(i)->getHand()) { //kdDebug() << "Hand 2 is better." << endl; winner = m_game.getActivePlayer(i); } else { //kdDebug() << "Hand 1 is better." << endl; } } displayWinner_Computer(winner, false); } void kpok::noMoney() { KMessageBox::sorry(0, i18n("You Lost"), i18n("Oops, you went bankrupt.\n" "Starting a new game.\n")); newGame(); } void kpok::startBlinking() { blinkTimer->start(650); } void kpok::stopBlinking() { blinkTimer->stop(); m_blinkStat = 1; m_blinkingBox = 0; } void kpok::startWave() { waveTimer->start(40); waveActive = true; } void kpok::stopWave() { waveTimer->stop(); fCount = -1; /* clear image */ repaint ( FALSE ); waveActive = false; } void kpok::stopDrawing() { drawTimer->stop(); } void kpok::waveTimerEvent() { fCount = (fCount + 1) & 15; repaint( FALSE ); } void kpok::bTimerEvent() { if (m_blinking) { if (m_blinkStat != 0) { playerBox[m_blinkingBox]->blinkOn(); m_blinkStat = 0; } else { playerBox[m_blinkingBox]->blinkOff(); m_blinkStat = 1; } } } void kpok::displayWin(const TQString& hand, int cashWon) { TQString buf; setHand(hand); m_game.getActivePlayer(0)->setCash(m_game.getActivePlayer(0)->getCash() + cashWon); m_game.setDirty(); paintCash(); if (cashWon) { playSound("win.wav"); buf = i18n("You won %1!").arg(TDEGlobal::locale()->formatMoney(cashWon)); } else { playSound("lose.wav"); buf = i18n("Game Over"); // locale } wonLabel->setText(buf); if (!cashWon) wonLabel->show(); else { wonLabel->hide(); startWave(); } drawButton->setText(i18n("&Deal New Round")); } void kpok::paintEvent( TQPaintEvent *) { /* NOTE: This was shamelessy stolen from the "hello world" example * coming with TQt Thanks to the TQt-Guys for doing such a cool * example 8-) */ if (!waveActive) { return; } TQString txt = wonLabel->text(); wonLabel->hide(); static int sin_tbl[16] = { 0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38}; if ( txt.isEmpty() ) { return; } TQFont wonFont; wonFont.setPointSize(18); wonFont.setBold(true); TQFontMetrics fm = TQFontMetrics(wonFont); int w = fm.width(txt) + 20; int h = fm.height() * 2; while (w > mWonWidget->width() && wonFont.pointSize() > 6) {// > 6 for emergency abort... wonFont.setPointSize(wonFont.pointSize() - 1); fm = TQFontMetrics(wonFont); w = fm.width(txt) + 20; h = fm.height() * 2; } int pmx = mWonWidget->width() / 2 - w / 2; int pmy = 0; // int pmy = (playerBox[0]->x() + playerBox[0]->height() + 10) - h / 4; TQPixmap pm( w, h ); pm.fill( mWonWidget, pmx, pmy ); if (fCount == -1) { /* clear area */ bitBlt( mWonWidget, pmx, pmy, &pm ); return; } TQPainter p; int x = 10; int y = h/2 + fm.descent(); unsigned int i = 0; p.begin( &pm ); p.setFont( wonFont ); p.setPen( TQColor(0,0,0) ); while ( i < txt.length() ) { int i16 = (fCount+i) & 15; p.drawText( x, y-sin_tbl[i16]*h/800, TQString(txt[i]), 1 ); x += fm.width( txt[i] ); i++; } p.end(); // 4: Copy the pixmap to the Hello widget bitBlt( mWonWidget, pmx, pmy, &pm ); } void kpok::drawAllDecks() { for (int i = 0; i < m_game.getNumActivePlayers(); i++) { for (int i2 = 0; i2 < PokerHandSize; i2++) { m_game.getActivePlayer(i)->takeCard(i2, 0); playerBox[i]->paintCard(i2); } } } void kpok::removePlayerFromRound(PokerPlayer* removePlayer) { removePlayer->setOut(true); m_game.inactivatePlayer(removePlayer); for (int i = 0; i < m_game.getNumPlayers(); i++) playerBox[i]->showCash(); } void kpok::switchToOnePlayerRules() { KMessageBox::information(0, i18n("You are the only player with money!\n" "Switching to one player rules..."), i18n("You Won")); // Hide all computer players. for (unsigned int i = 1; i < m_numPlayers; i++) { playerBox[i]->hide(); } m_game.setType(SinglePlayer); betBox->hide(); potLabel->hide(); playerBox[0]->singlePlayerGame(cashPerRound); setHand(i18n("Nothing")); } PokerPlayer* kpok::findHumanPlayer() { for (int i = 0; i < m_game.getNumActivePlayers(); i++) { if (m_game.getActivePlayer(i)->getHuman()) return m_game.getActivePlayer(i); } return m_game.getActivePlayer(0);//error } bool kpok::readEntriesAndInitPoker() { NewGameDlg *newGameDlg = NULL; TDEConfig *conf = kapp->config(); int numPlayers = DEFAULT_PLAYERS; conf->setGroup("NewGameDlg"); bool showNewGameDlg = conf->readBoolEntry("showNewGameDlgOnStartup", false); bool aborted = false; bool oldGame = false; if (showNewGameDlg) { newGameDlg = new NewGameDlg(this); if (!newGameDlg->exec()) return false; // exit game } if (!aborted && (!showNewGameDlg || showNewGameDlg && newGameDlg->readFromConfigFile())) { // Try starting an old game. //kdDebug() << "Trying to load old game" << endl; oldGame = loadGame(); if (oldGame) return true; } if (!aborted && showNewGameDlg && !oldGame) { // Don't use config file - just take the values from the dialog. // (This is also config - the dialog defaults are from config.) numPlayers = newGameDlg->getPlayers(); if (numPlayers <= 0) aborted = true; for (int i = 0; i < numPlayers; i++) { m_players[i].setName(newGameDlg->name(i)); m_players[i].setCash(newGameDlg->money()); m_game.setDirty(); } } initPoker(numPlayers); if (newGameDlg != 0) { delete newGameDlg; } return true; } void kpok::betChange(int betChange) { PokerPlayer* p = findHumanPlayer(); switch(m_game.getState()){ case StateBet1: if (p->getCurrentBet() + betChange >= m_game.getMinBet() && p->getCurrentBet() + betChange <= m_game.getMaxBet()) { // Bet at least getMinBet() but not more than getMaxBet(). if (p->changeBet(betChange)) m_game.bet(betChange); } break; case StateBet2: case StateRaise2: case StateRaise1: if (p->getCurrentBet() + betChange >= currentMustBet && p->getCurrentBet() + betChange <= currentMustBet + m_game.getMaxBet()) { if (p->changeBet(betChange)) m_game.bet(betChange); } break; default: break; } paintCash(); } void kpok::saveGame() { kapp->config()->setGroup("Save"); saveGame(kapp->config()); } void kpok::saveGame(TDEConfig* conf) { // kdWarning() << "save game" << endl; int players = m_game.getNumPlayers(); conf->writeEntry("players", players); conf->writeEntry("lastHandText", lastHandText); for (int i = 0; i < players; i++) { conf->writeEntry(TQString("Name_%1").arg(i), m_players[i].getName()); conf->writeEntry(TQString("Human_%1").arg(i), m_players[i].getHuman()); conf->writeEntry(TQString("Cash_%1").arg(i), m_players[i].getCash()); } m_game.clearDirty(); } void kpok::toggleSound() { setSound(!sound); } void kpok::toggleBlinking() { setBlinking(!m_blinking); } void kpok::toggleAdjust() { setAdjust(!adjust); } void kpok::slotPreferences() { if ( mOptions==0 ) mOptions = new OptionsDlg(this, 0, m_numPlayers); if (m_numPlayers > 1) mOptions->init(drawDelay, m_game.getMaxBet(), m_game.getMinBet()); else mOptions->init(drawDelay, cashPerRound); if (!mOptions->exec()) { delete mOptions; mOptions = 0; } } void kpok::setAdjust(bool ad) { adjust = ad; //update guessed money statusbar if we currently are in need of adjust if (m_game.getState() == StateRaise1 || m_game.getState() == StateRaise2) { if (adjust) adjustBet(); else out(); } } bool kpok::initSound() { sound = true; return true; } void kpok::playSound(const TQString &soundname) { if (sound) KAudioPlayer::play(locate("data", TQString("kpoker/sounds/")+soundname)); } void kpok::setSound(bool s) { sound = s; } void kpok::readOptions() { if (mOptions != 0) { if (m_numPlayers > 1) { m_game.setBettingLimits(mOptions->getMinBet(), mOptions->getMaxBet()); for (int i = 0; i < m_game.getNumActivePlayers(); i++) m_game.getActivePlayer(i)->setBetDefaults(m_game.getMinBet(), m_game.getMaxBet()); // inform players how much they may bet } drawDelay = mOptions->getDrawDelay(); // kdDebug() << cashPerRound << endl; // cashPerRound = mOptions->getCashPerRound(); // NOT(!) configurable delete mOptions; mOptions = 0; } } bool kpok::loadGame() { kapp->config()->setGroup("Save"); return loadGame(kapp->config()); } bool kpok::loadGame(TDEConfig* conf) { int numPlayers = DEFAULT_PLAYERS; // conf->setGroup("Save"); numPlayers = conf->readNumEntry("players", -1); if (numPlayers > 0) { for (int i = 0; i < numPlayers; i++) { TQString buf = conf->readEntry(TQString("Name_%1").arg(i), "Player"); m_players[i].setName(buf); bool human = conf->readBoolEntry(TQString("Human_%1").arg(i), false); if (human) m_players[i].setHuman(); // i == 0 int cash = conf->readNumEntry(TQString("Cash_%1").arg(i), START_MONEY); m_players[i].setCash(cash); m_game.setDirty(); } initPoker(numPlayers); // after initPoker because initPoker does a default initialization // of lastHandText conf->setGroup("Save"); lastHandText = conf->readEntry("lastHandText", ""); return true; } return false; } // These slots are called from keyboard shortcuts ('1'..'5') void kpok::exchangeCard1() { playerBox[0]->cardClicked(1); } void kpok::exchangeCard2() { playerBox[0]->cardClicked(2); } void kpok::exchangeCard3() { playerBox[0]->cardClicked(3); } void kpok::exchangeCard4() { playerBox[0]->cardClicked(4); } void kpok::exchangeCard5() { playerBox[0]->cardClicked(5); } // This slot is called when the user wants to change some aspect of // the card deck (front or back). // // FIXME: Maybe the slot should be moved to top.cpp instead and simply // call a setDeck() or setBack() method in kpok. void kpok::slotCardDeck() { kapp->config()->setGroup("General"); TQString deckPath = kapp->config()->readPathEntry("DeckPath", 0); TQString cardPath = kapp->config()->readPathEntry("CardPath", 0); bool randomDeck, randomCardDir; // Show the "Select Card Deck" dialog and load the images for the // selected deck, if any. if (KCardDialog::getCardDeck(deckPath, cardPath, this, KCardDialog::Both, &randomDeck, &randomCardDir) == TQDialog::Accepted) { // Load backside and front images. if (playerBox && m_blinking && (m_blinkStat == 0)) bTimerEvent(); cardImages->loadDeck(deckPath); cardImages->loadCards(cardPath); for (int i = 0; i < m_game.getNumActivePlayers(); i++) { playerBox[i]->repaintCard(); } // Save selected stuff in the configuration. kapp->config()->writePathEntry("DeckPath", deckPath); kapp->config()->writeEntry("RandomDeck", randomDeck); kapp->config()->writePathEntry("CardPath", cardPath); kapp->config()->writeEntry("RandomCardDir", randomCardDir); } } #include "kpoker.moc"