|
|
|
/*
|
|
|
|
* 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 <tqlayout.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kaction.h>
|
|
|
|
#include <kstdgameaction.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqlcdnumber.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 TQWidget( this, "m_view" );
|
|
|
|
setCentralWidget( m_view );
|
|
|
|
|
|
|
|
m_layout = new TQGridLayout( m_view, 1, 3 );
|
|
|
|
m_layout->setColStretch( 2, 1 );
|
|
|
|
|
|
|
|
TQVBoxLayout *infoLayout = new TQVBoxLayout;
|
|
|
|
m_layout->addLayout( infoLayout, 0, 1 );
|
|
|
|
|
|
|
|
TQLabel *label = new TQLabel( i18n("Level:"), m_view );
|
|
|
|
infoLayout->addWidget( label );
|
|
|
|
m_levelLCD = new TQLCDNumber( 5, m_view );
|
|
|
|
infoLayout->addWidget( m_levelLCD );
|
|
|
|
|
|
|
|
label = new TQLabel( i18n("Score:"), m_view );
|
|
|
|
infoLayout->addWidget( label );
|
|
|
|
m_scoreLCD = new TQLCDNumber( 5, m_view );
|
|
|
|
infoLayout->addWidget( m_scoreLCD );
|
|
|
|
|
|
|
|
infoLayout->addSpacing( 20 );
|
|
|
|
|
|
|
|
label = new TQLabel( i18n("Filled area:"), m_view );
|
|
|
|
infoLayout->addWidget( label );
|
|
|
|
m_percentLCD = new TQLCDNumber( 5, m_view );
|
|
|
|
infoLayout->addWidget( m_percentLCD );
|
|
|
|
|
|
|
|
label = new TQLabel( i18n("Lives:"), m_view );
|
|
|
|
infoLayout->addWidget( label );
|
|
|
|
m_lifesLCD = new TQLCDNumber( 5, m_view );
|
|
|
|
infoLayout->addWidget( m_lifesLCD );
|
|
|
|
|
|
|
|
label = new TQLabel( i18n("Time:"), m_view );
|
|
|
|
infoLayout->addWidget( label );
|
|
|
|
m_timeLCD = new TQLCDNumber( 5, m_view );
|
|
|
|
infoLayout->addWidget( m_timeLCD );
|
|
|
|
|
|
|
|
// create timers
|
|
|
|
m_nextLevelTimer = new TQTimer( this, "m_nextLevelTimer" );
|
|
|
|
connect( m_nextLevelTimer, TQT_SIGNAL(timeout()), TQT_TQOBJECT(this), TQT_SLOT(switchLevel()) );
|
|
|
|
|
|
|
|
m_gameOverTimer = new TQTimer( this, "m_gameOverTimer" );
|
|
|
|
connect( m_gameOverTimer, TQT_SIGNAL(timeout()), TQT_TQOBJECT(this), TQT_SLOT(gameOverNow()) );
|
|
|
|
|
|
|
|
m_timer = new TQTimer( this, "m_timer" );
|
|
|
|
connect( m_timer, TQT_SIGNAL(timeout()), TQT_TQOBJECT(this), TQT_SLOT(second()) );
|
|
|
|
|
|
|
|
// create demo game
|
|
|
|
createLevel( 1 );
|
|
|
|
statusBar()->message( i18n("Press %1 to start a game!")
|
|
|
|
.tqarg(m_newAction->shortcut().toString()) );
|
|
|
|
//m_gameWidget->display( i18n("Press <Space> to start a game!") );
|
|
|
|
|
|
|
|
setFocusPolicy(TQ_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( TQT_TQOBJECT(this), TQT_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(TQKeySequence(Key_Space)));
|
|
|
|
m_newAction->setShortcut(s);
|
|
|
|
|
|
|
|
KStdGameAction::quit(TQT_TQOBJECT(this), TQT_SLOT(close()), actionCollection() );
|
|
|
|
KStdGameAction::highscores(TQT_TQOBJECT(this), TQT_SLOT(showHighscore()), actionCollection() );
|
|
|
|
m_pauseButton = KStdGameAction::pause(TQT_TQOBJECT(this), TQT_SLOT(pauseGame()), actionCollection());
|
|
|
|
KStdGameAction::end(TQT_TQOBJECT(this), TQT_SLOT(closeGame()), actionCollection());
|
|
|
|
KStdGameAction::configureHighscores(TQT_TQOBJECT(this), TQT_SLOT(configureHighscores()),actionCollection());
|
|
|
|
|
|
|
|
new KAction( i18n("&Select Background Folder..."), 0, TQT_TQOBJECT(this), TQT_SLOT(selectBackground()),
|
|
|
|
actionCollection(), "background_select" );
|
|
|
|
m_backgroundShowAction =
|
|
|
|
new KToggleAction( i18n("Show &Backgrounds"), 0, TQT_TQOBJECT(this), TQT_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?"), TQString(), 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( TQString() );
|
|
|
|
startLevel();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Idle:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KJezzball::gameOver()
|
|
|
|
{
|
|
|
|
stopLevel();
|
|
|
|
m_gameOverTimer->start( 100, TRUE );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KJezzball::gameOverNow()
|
|
|
|
{
|
|
|
|
m_state = Idle;
|
|
|
|
|
|
|
|
TQString score;
|
|
|
|
score.setNum( m_game.score );
|
|
|
|
KMessageBox::information( this, i18n("Game Over! Score: %1").tqarg(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()
|
|
|
|
{
|
|
|
|
TQString 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 : TQPixmap() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPixmap KJezzball::getBackgroundPixmap()
|
|
|
|
{
|
|
|
|
// list directory
|
|
|
|
TQDir dir( m_backgroundDir, "*.png *.jpg", TQDir::Name|TQDir::IgnoreCase, TQDir::Files );
|
|
|
|
if ( !dir.exists() ) {
|
|
|
|
kdDebug(12008) << "Directory not found" << endl;
|
|
|
|
return TQPixmap();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dir.count() > 1)
|
|
|
|
{
|
|
|
|
// return random pixmap
|
|
|
|
int num = kapp->random() % dir.count();
|
|
|
|
return TQPixmap( dir.absFilePath( dir[num] ) );
|
|
|
|
}
|
|
|
|
else if (dir.count()==1)
|
|
|
|
{
|
|
|
|
return TQPixmap( dir.absFilePath(dir[0]) );
|
|
|
|
}
|
|
|
|
else return TQPixmap();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KJezzball::focusOutEvent( TQFocusEvent *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 ( TQFocusEvent *ev )
|
|
|
|
{
|
|
|
|
if ( m_state==Suspend )
|
|
|
|
{
|
|
|
|
startLevel();
|
|
|
|
m_state = Running;
|
|
|
|
statusBar()->clear();
|
|
|
|
m_pauseButton->setChecked(false);
|
|
|
|
//m_gameWidget->display( TQString() );
|
|
|
|
}
|
|
|
|
|
|
|
|
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 = TQPixmap();
|
|
|
|
|
|
|
|
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, TQT_SIGNAL(died()), TQT_TQOBJECT(this), TQT_SLOT(died()) );
|
|
|
|
connect( m_gameWidget, TQT_SIGNAL(newPercent(int)), TQT_TQOBJECT(this), TQT_SLOT(newPercent(int)) );
|
|
|
|
connect( m_soundAction, TQT_SIGNAL(toggled(bool)), m_gameWidget, TQT_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 );
|
|
|
|
|
|
|
|
TQString score;
|
|
|
|
score.setNum( m_level.score );
|
|
|
|
|
|
|
|
TQString level;
|
|
|
|
level.setNum( m_game.level );
|
|
|
|
|
|
|
|
TQString foo = TQString(
|
|
|
|
i18n("You have successfully cleared more than 75% of the board.\n") +
|
|
|
|
i18n("%1 points: 15 points per remaining life\n").tqarg(m_level.lifes*15) +
|
|
|
|
i18n("%1 points: Bonus\n").tqarg((m_gameWidget->percent()-75)*2*(m_game.level+5)) +
|
|
|
|
i18n("%1 points: Total score for this level\n").tqarg(score) +
|
|
|
|
i18n("On to level %1. Remember you get %2 lives this time!")).tqarg(m_game.level+1).tqarg(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!").tqarg(level).tqarg(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"
|