summaryrefslogtreecommitdiffstats
path: root/kbounce/kbounce.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kbounce/kbounce.cpp')
-rw-r--r--kbounce/kbounce.cpp491
1 files changed, 491 insertions, 0 deletions
diff --git a/kbounce/kbounce.cpp b/kbounce/kbounce.cpp
new file mode 100644
index 00000000..eab691b8
--- /dev/null
+++ b/kbounce/kbounce.cpp
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License,Life 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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 <qlayout.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kstdgameaction.h>
+#include <qtimer.h>
+#include <qlcdnumber.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kstatusbar.h>
+#include <khighscore.h>
+#include <kexthighscore.h>
+
+#include "kbounce.h"
+#include "game.h"
+
+KJezzball::KJezzball()
+ : m_gameWidget( 0 )
+{
+ // setup variables
+ m_game.level = 1;
+ m_game.score = 0;
+ m_state = Idle;
+
+ KConfig *config = kapp->config();
+ m_backgroundDir = config->readPathEntry( "BackgroundDir" );
+ m_showBackground = config->readBoolEntry( "ShowBackground", false );
+
+ statusBar();
+ initXMLUI();
+
+ m_soundAction -> setChecked((config->readBoolEntry( "PlaySounds", true )));
+
+ // create widgets
+ m_view = new QWidget( this, "m_view" );
+ setCentralWidget( m_view );
+
+ m_layout = new QGridLayout( m_view, 1, 3 );
+ m_layout->setColStretch( 2, 1 );
+
+ QVBoxLayout *infoLayout = new QVBoxLayout;
+ m_layout->addLayout( infoLayout, 0, 1 );
+
+ QLabel *label = new QLabel( i18n("Level:"), m_view );
+ infoLayout->addWidget( label );
+ m_levelLCD = new QLCDNumber( 5, m_view );
+ infoLayout->addWidget( m_levelLCD );
+
+ label = new QLabel( i18n("Score:"), m_view );
+ infoLayout->addWidget( label );
+ m_scoreLCD = new QLCDNumber( 5, m_view );
+ infoLayout->addWidget( m_scoreLCD );
+
+ infoLayout->addSpacing( 20 );
+
+ label = new QLabel( i18n("Filled area:"), m_view );
+ infoLayout->addWidget( label );
+ m_percentLCD = new QLCDNumber( 5, m_view );
+ infoLayout->addWidget( m_percentLCD );
+
+ label = new QLabel( i18n("Lives:"), m_view );
+ infoLayout->addWidget( label );
+ m_lifesLCD = new QLCDNumber( 5, m_view );
+ infoLayout->addWidget( m_lifesLCD );
+
+ label = new QLabel( i18n("Time:"), m_view );
+ infoLayout->addWidget( label );
+ m_timeLCD = new QLCDNumber( 5, m_view );
+ infoLayout->addWidget( m_timeLCD );
+
+ // create timers
+ m_nextLevelTimer = new QTimer( this, "m_nextLevelTimer" );
+ connect( m_nextLevelTimer, SIGNAL(timeout()), this, SLOT(switchLevel()) );
+
+ m_gameOverTimer = new QTimer( this, "m_gameOverTimer" );
+ connect( m_gameOverTimer, SIGNAL(timeout()), this, SLOT(gameOverNow()) );
+
+ m_timer = new QTimer( this, "m_timer" );
+ connect( m_timer, SIGNAL(timeout()), this, SLOT(second()) );
+
+ // create demo game
+ createLevel( 1 );
+ statusBar()->message( i18n("Press %1 to start a game!")
+ .arg(m_newAction->shortcut().toString()) );
+ //m_gameWidget->display( i18n("Press <Space> to start a game!") );
+
+ setFocusPolicy(QWidget::StrongFocus);
+ setFocus();
+ setupGUI();
+}
+
+KJezzball::~KJezzball()
+{
+ KConfig *config = kapp->config();
+ config->writeEntry( "PlaySounds", m_soundAction->isChecked() );
+}
+
+/**
+ * create the action events create the gui.
+ */
+void KJezzball::initXMLUI()
+{
+ m_newAction = KStdGameAction::gameNew( this, SLOT(newGame()), actionCollection() );
+ // AB: originally KBounce/KJezzball used Space for new game - but Ctrl+N is
+ // default. We solve this by providing space as an alternative key
+ KShortcut s = m_newAction->shortcut();
+ s.append(KKeySequence(QKeySequence(Key_Space)));
+ m_newAction->setShortcut(s);
+
+ KStdGameAction::quit(this, SLOT(close()), actionCollection() );
+ KStdGameAction::highscores(this, SLOT(showHighscore()), actionCollection() );
+ m_pauseButton = KStdGameAction::pause(this, SLOT(pauseGame()), actionCollection());
+ KStdGameAction::end(this, SLOT(closeGame()), actionCollection());
+ KStdGameAction::configureHighscores(this, SLOT(configureHighscores()),actionCollection());
+
+ new KAction( i18n("&Select Background Folder..."), 0, this, SLOT(selectBackground()),
+ actionCollection(), "background_select" );
+ m_backgroundShowAction =
+ new KToggleAction( i18n("Show &Backgrounds"), 0, this, SLOT(showBackground()),
+ actionCollection(), "background_show" );
+ m_backgroundShowAction->setCheckedState(i18n("Hide &Backgrounds"));
+ m_backgroundShowAction->setEnabled( !m_backgroundDir.isEmpty() );
+ m_backgroundShowAction->setChecked( m_showBackground );
+
+ m_soundAction = new KToggleAction( i18n("&Play Sounds"), 0, 0, 0, actionCollection(), "toggle_sound");
+}
+
+void KJezzball::newGame()
+{
+ // Check for running game
+ closeGame();
+ if ( m_state==Idle )
+ {
+ // untoggles the pause button in case it was toggled
+ m_pauseButton->setChecked(false);
+
+ // update displays
+ m_game.level = 1;
+ m_game.score = 0;
+
+ m_levelLCD->display( m_game.level );
+ m_scoreLCD->display( m_game.score );
+
+ statusBar()->clear();
+
+ // start new game
+ m_state = Running;
+
+ createLevel( m_game.level );
+ startLevel();
+ }
+}
+
+void KJezzball::closeGame()
+{
+ if ( m_state!=Idle )
+ {
+ int old_state = m_state;
+ if (old_state == Running)
+ pauseGame();
+ int ret = KMessageBox::questionYesNo( this, i18n("Do you really want to close the running game?"), QString::null, KStdGuiItem::close(), KStdGuiItem::cancel() );
+ if ( ret==KMessageBox::Yes )
+ {
+ stopLevel();
+ m_state = Idle;
+ highscore();
+ }
+ else if (old_state == Running)
+ {
+ pauseGame(); // Unpause
+ }
+ }
+}
+
+void KJezzball::pauseGame()
+{
+ switch ( m_state )
+ {
+ case Running:
+ m_state = Paused;
+ statusBar()->message(i18n("Game paused.") );
+ //m_gameWidget->display( i18n("Game paused. Press P to continue!") );
+ stopLevel();
+ break;
+
+ case Paused:
+ case Suspend:
+ m_state = Running;
+ statusBar()->clear();
+ //m_gameWidget->display( QString::null );
+ startLevel();
+ break;
+
+ case Idle:
+ break;
+ }
+}
+
+void KJezzball::gameOver()
+{
+ stopLevel();
+ m_gameOverTimer->start( 100, TRUE );
+}
+
+
+void KJezzball::gameOverNow()
+{
+ m_state = Idle;
+
+ QString score;
+ score.setNum( m_game.score );
+ KMessageBox::information( this, i18n("Game Over! Score: %1").arg(score) );
+ statusBar()->message( i18n("Game over. Press <Space> for a new game") );
+ //m_gameWidget->display( i18n("Game over. Press <Space> for a new game!") );
+ highscore();
+}
+
+/**
+ * Bring up the standard kde high score configure dialog.
+ */
+void KJezzball::configureHighscores()
+{
+ KExtHighscore::configure(this);
+}
+
+/**
+ * Bring up the standard kde high score dialog.
+ */
+void KJezzball::showHighscore()
+{
+ KExtHighscore::show(this);
+}
+
+/**
+ * Select a background image.
+ */
+void KJezzball::selectBackground()
+{
+ QString path = KFileDialog::getExistingDirectory( m_backgroundDir, this,
+ i18n("Select Background Image Folder") );
+ if ( !path.isEmpty() && path!=m_backgroundDir ) {
+ m_backgroundDir = path;
+
+ // enable action
+ m_backgroundShowAction->setEnabled(true);
+
+ // save settings
+ KConfig *config = kapp->config();
+ config->writePathEntry( "BackgroundDir", m_backgroundDir );
+ config->sync();
+
+ // apply background setting
+ if ( m_showBackground ) {
+ if ( m_background.width()==0 )
+ m_background = getBackgroundPixmap();
+
+ m_gameWidget->setBackground( m_background );
+ }
+ else{
+ KMessageBox::information( this, i18n("You may now turn on background images."));
+ }
+ }
+}
+
+void KJezzball::showBackground()
+{
+ bool show = m_backgroundShowAction->isChecked();
+ if ( show!=m_showBackground ) {
+
+ m_showBackground = show;
+
+ // save setting
+ KConfig *config = kapp->config();
+ config->writeEntry( "ShowBackground", m_showBackground );
+ config->sync();
+
+ // update field
+ if ( m_showBackground ) {
+ if ( m_background.width()==0 )
+ m_background = getBackgroundPixmap();
+ }
+
+ m_gameWidget->setBackground( m_showBackground ? m_background : QPixmap() );
+ }
+}
+
+QPixmap KJezzball::getBackgroundPixmap()
+{
+ // list directory
+ QDir dir( m_backgroundDir, "*.png *.jpg", QDir::Name|QDir::IgnoreCase, QDir::Files );
+ if ( !dir.exists() ) {
+ kdDebug(12008) << "Directory not found" << endl;
+ return QPixmap();
+ }
+
+ if (dir.count() > 1)
+ {
+ // return random pixmap
+ int num = kapp->random() % dir.count();
+ return QPixmap( dir.absFilePath( dir[num] ) );
+ }
+ else if (dir.count()==1)
+ {
+ return QPixmap( dir.absFilePath(dir[0]) );
+ }
+ else return QPixmap();
+}
+
+void KJezzball::focusOutEvent( QFocusEvent *ev )
+{
+ if ( m_state==Running )
+ {
+ stopLevel();
+ m_state = Suspend;
+ m_pauseButton->setChecked(true);
+ statusBar()->message( i18n("Game suspended") );
+ // m_gameWidget->display( i18n("Game suspended") );
+ }
+
+ KMainWindow::focusOutEvent( ev );
+}
+
+void KJezzball::focusInEvent ( QFocusEvent *ev )
+{
+ if ( m_state==Suspend )
+ {
+ startLevel();
+ m_state = Running;
+ statusBar()->clear();
+ m_pauseButton->setChecked(false);
+ //m_gameWidget->display( QString::null );
+ }
+
+ KMainWindow::focusInEvent( ev );
+}
+
+void KJezzball::second()
+{
+ m_level.time--;
+ m_timeLCD->display( m_level.time );
+ if ( m_level.time<=0 )
+ {
+ JezzGame::playSound( "timeout.au" );
+ gameOver();
+ } else
+ if ( m_level.time<=30 )
+ JezzGame::playSound( "seconds.au" );
+}
+
+void KJezzball::died()
+{
+ kdDebug(12008) << "died" << endl;
+ m_level.lifes--;
+ m_lifesLCD->display( m_level.lifes );
+ if ( m_level.lifes==0 ) gameOver();
+}
+
+void KJezzball::newPercent( int percent )
+{
+ m_percentLCD->display( percent );
+ if ( percent>=75 )
+ {
+ m_level.score = m_level.lifes*15 + (percent-75)*2*(m_game.level+5);
+ nextLevel();
+ }
+}
+
+void KJezzball::createLevel( int level )
+{
+ // destroy old game
+ if ( m_gameWidget ) delete m_gameWidget;
+
+ // create new game widget
+ if ( m_showBackground )
+ m_background = getBackgroundPixmap();
+ else
+ m_background = QPixmap();
+
+ m_gameWidget = new JezzGame( m_background, level+1, m_view, "m_gameWidget" );
+ m_gameWidget->setSound(m_soundAction->isChecked());
+
+ m_gameWidget->show();
+ m_layout->addWidget( m_gameWidget, 0, 0 );
+ connect( m_gameWidget, SIGNAL(died()), this, SLOT(died()) );
+ connect( m_gameWidget, SIGNAL(newPercent(int)), this, SLOT(newPercent(int)) );
+ connect( m_soundAction, SIGNAL(toggled(bool)), m_gameWidget, SLOT(setSound(bool)) );
+
+ // update displays
+ m_level.lifes = level+1;
+ m_lifesLCD->display( m_level.lifes );
+ m_percentLCD->display( 0 );
+
+ m_level.time = (level+2)*30;
+ m_timeLCD->display( m_level.time );
+
+ m_level.score = 0;
+}
+
+void KJezzball::startLevel()
+{
+ if ( m_gameWidget )
+ {
+ m_timer->start( 1000 );
+ m_gameWidget->start();
+ }
+}
+
+void KJezzball::stopLevel()
+{
+ if ( m_gameWidget )
+ {
+ m_gameWidget->stop();
+ m_timer->stop();
+ }
+}
+
+void KJezzball::nextLevel()
+{
+ stopLevel();
+ m_nextLevelTimer->start( 100, TRUE );
+}
+
+void KJezzball::switchLevel()
+{
+ m_game.score += m_level.score;
+
+ // make sure the LCD provides enough digits for the score
+ // (fixes #96841)
+ int numDigits=0;
+ int temp_score = m_game.score;
+ for ( ; temp_score > 0; ++numDigits ) temp_score /= 10;
+ if ( numDigits < 5 ) numDigits = 5; // set numDigits to at least 5, otherwise it does not look well
+
+ m_scoreLCD->setNumDigits( numDigits );
+ m_scoreLCD->display( m_game.score );
+
+ QString score;
+ score.setNum( m_level.score );
+
+ QString level;
+ level.setNum( m_game.level );
+
+QString foo = QString(
+i18n("You have successfully cleared more than 75% of the board.\n") +
+i18n("%1 points: 15 points per remaining life\n").arg(m_level.lifes*15) +
+i18n("%1 points: Bonus\n").arg((m_gameWidget->percent()-75)*2*(m_game.level+5)) +
+i18n("%1 points: Total score for this level\n").arg(score) +
+i18n("On to level %1. Remember you get %2 lives this time!")).arg(m_game.level+1).arg(m_game.level+2);
+
+ KMessageBox::information( this,foo );
+
+
+ // KMessageBox::information( this, i18n("You've completed level %1 with "
+ // "a score of %2.\nGet ready for the next one!").arg(level).arg(score));
+
+ m_game.level++;
+ m_levelLCD->display( m_game.level );
+
+ createLevel( m_game.level );
+ startLevel();
+}
+
+
+void KJezzball::highscore()
+{
+ KExtHighscore::Score score(KExtHighscore::Won);
+ score.setScore(m_game.score);
+ score.setData("level", m_game.level);
+ KExtHighscore::submitScore(score, this);
+}
+
+#include "kbounce.moc"