summaryrefslogtreecommitdiffstats
path: root/kasteroids/toplevel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kasteroids/toplevel.cpp')
-rw-r--r--kasteroids/toplevel.cpp678
1 files changed, 678 insertions, 0 deletions
diff --git a/kasteroids/toplevel.cpp b/kasteroids/toplevel.cpp
new file mode 100644
index 00000000..a4286d2f
--- /dev/null
+++ b/kasteroids/toplevel.cpp
@@ -0,0 +1,678 @@
+/*
+ * KAsteroids - Copyright (c) Martin R. Jones 1997
+ *
+ * Part of the KDE project
+ */
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlcdnumber.h>
+#include <qspinbox.h>
+#include <qcheckbox.h>
+
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <kglobalsettings.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kkeydialog.h>
+#include <kaction.h>
+#include <kstdgameaction.h>
+#include <kaudioplayer.h>
+#include <kscoredialog.h>
+#include <kconfigdialog.h>
+
+#include "settings.h"
+#include "toplevel.h"
+#include "ledmeter.h"
+
+#include "toplevel.moc"
+
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+#include <X11/Xlib.h>
+#endif
+#include <fixx11h.h>
+
+#define SB_SCORE 1
+#define SB_LEVEL 2
+#define SB_SHIPS 3
+
+struct SLevel
+{
+ int nrocks;
+ double rockSpeed;
+};
+
+#define MAX_LEVELS 16
+
+SLevel levels[MAX_LEVELS] =
+{
+ { 1, 0.4 },
+ { 1, 0.6 },
+ { 2, 0.5 },
+ { 2, 0.7 },
+ { 2, 0.8 },
+ { 3, 0.6 },
+ { 3, 0.7 },
+ { 3, 0.8 },
+ { 4, 0.6 },
+ { 4, 0.7 },
+ { 4, 0.8 },
+ { 5, 0.7 },
+ { 5, 0.8 },
+ { 5, 0.9 },
+ { 5, 1.0 }
+};
+
+#ifdef KA_ENABLE_SOUND
+#include <arts/dispatcher.h>
+#include <arts/soundserver.h>
+
+Arts::SimpleSoundServer *soundServer = 0;
+#endif
+
+
+KAstTopLevel::KAstTopLevel()
+{
+ QWidget *mainWin = new QWidget( this );
+ mainWin->setFixedSize(640, 480);
+
+ view = new KAsteroidsView( mainWin );
+ connect( view, SIGNAL( shipKilled() ), SLOT( slotShipKilled() ) );
+ connect( view, SIGNAL( rockHit(int) ), SLOT( slotRockHit(int) ) );
+ connect( view, SIGNAL( rocksRemoved() ), SLOT( slotRocksRemoved() ) );
+ connect( view, SIGNAL( updateVitals() ), SLOT( slotUpdateVitals() ) );
+
+ QVBoxLayout *vb = new QVBoxLayout( mainWin );
+ QHBoxLayout *hb = new QHBoxLayout;
+ QHBoxLayout *hbd = new QHBoxLayout;
+ vb->addLayout( hb );
+
+ QFont labelFont( KGlobalSettings::generalFont().family(), 24 );
+ QColorGroup grp( darkGreen, black, QColor( 128, 128, 128 ),
+ QColor( 64, 64, 64 ), black, darkGreen, black );
+ QPalette pal( grp, grp, grp );
+
+ mainWin->setPalette( pal );
+
+ hb->addSpacing( 10 );
+
+ QLabel *label;
+ label = new QLabel( i18n("Score"), mainWin );
+ label->setFont( labelFont );
+ label->setPalette( pal );
+ label->setFixedWidth( label->sizeHint().width() );
+ hb->addWidget( label );
+
+ scoreLCD = new QLCDNumber( 6, mainWin );
+ scoreLCD->setFrameStyle( QFrame::NoFrame );
+ scoreLCD->setSegmentStyle( QLCDNumber::Flat );
+ scoreLCD->setFixedWidth( 150 );
+ scoreLCD->setPalette( pal );
+ hb->addWidget( scoreLCD );
+ hb->addStretch( 10 );
+
+ label = new QLabel( i18n("Level"), mainWin );
+ label->setFont( labelFont );
+ label->setPalette( pal );
+ label->setFixedWidth( label->sizeHint().width() );
+ hb->addWidget( label );
+
+ levelLCD = new QLCDNumber( 2, mainWin );
+ levelLCD->setFrameStyle( QFrame::NoFrame );
+ levelLCD->setSegmentStyle( QLCDNumber::Flat );
+ levelLCD->setFixedWidth( 70 );
+ levelLCD->setPalette( pal );
+ hb->addWidget( levelLCD );
+ hb->addStretch( 10 );
+
+ label = new QLabel( i18n("Ships"), mainWin );
+ label->setFont( labelFont );
+ label->setFixedWidth( label->sizeHint().width() );
+ label->setPalette( pal );
+ hb->addWidget( label );
+
+ shipsLCD = new QLCDNumber( 1, mainWin );
+ shipsLCD->setFrameStyle( QFrame::NoFrame );
+ shipsLCD->setSegmentStyle( QLCDNumber::Flat );
+ shipsLCD->setFixedWidth( 40 );
+ shipsLCD->setPalette( pal );
+ hb->addWidget( shipsLCD );
+
+ hb->addStrut( 30 );
+
+ QFrame *sep = new QFrame( mainWin );
+ sep->setMaximumHeight( 5 );
+ sep->setFrameStyle( QFrame::HLine | QFrame::Raised );
+ sep->setPalette( pal );
+
+ vb->addWidget( sep );
+
+ vb->addWidget( view, 10 );
+
+// -- bottom layout:
+ QFrame *sep2 = new QFrame( mainWin );
+ sep2->setMaximumHeight( 1 );
+ sep2->setFrameStyle( QFrame::HLine | QFrame::Raised );
+ sep2->setPalette( pal );
+ vb->addWidget( sep2, 1 );
+
+ vb->addLayout( hbd );
+
+ QFont smallFont( KGlobalSettings::generalFont().family(), 14 );
+ hbd->addSpacing( 10 );
+
+ QString sprites_prefix =
+ KGlobal::dirs()->findResourceDir("sprite", "rock1/rock10000.png");
+/*
+ label = new QLabel( i18n( "T" ), mainWin );
+ label->setFont( smallFont );
+ label->setFixedWidth( label->sizeHint().width() );
+ label->setPalette( pal );
+ hbd->addWidget( label );
+
+ teleportsLCD = new QLCDNumber( 1, mainWin );
+ teleportsLCD->setFrameStyle( QFrame::NoFrame );
+ teleportsLCD->setSegmentStyle( QLCDNumber::Flat );
+ teleportsLCD->setPalette( pal );
+ teleportsLCD->setFixedHeight( 20 );
+ hbd->addWidget( teleportsLCD );
+
+ hbd->addSpacing( 10 );
+*/
+ QPixmap pm( sprites_prefix + "powerups/brake.png" );
+ label = new QLabel( mainWin );
+ label->setPixmap( pm );
+ label->setFixedWidth( label->sizeHint().width() );
+ label->setPalette( pal );
+ hbd->addWidget( label );
+
+ brakesLCD = new QLCDNumber( 1, mainWin );
+ brakesLCD->setFrameStyle( QFrame::NoFrame );
+ brakesLCD->setSegmentStyle( QLCDNumber::Flat );
+ brakesLCD->setPalette( pal );
+ brakesLCD->setFixedHeight( 20 );
+ hbd->addWidget( brakesLCD );
+
+ hbd->addSpacing( 10 );
+
+ pm.load( sprites_prefix + "powerups/shield.png" );
+ label = new QLabel( mainWin );
+ label->setPixmap( pm );
+ label->setFixedWidth( label->sizeHint().width() );
+ label->setPalette( pal );
+ hbd->addWidget( label );
+
+ shieldLCD = new QLCDNumber( 1, mainWin );
+ shieldLCD->setFrameStyle( QFrame::NoFrame );
+ shieldLCD->setSegmentStyle( QLCDNumber::Flat );
+ shieldLCD->setPalette( pal );
+ shieldLCD->setFixedHeight( 20 );
+ hbd->addWidget( shieldLCD );
+
+ hbd->addSpacing( 10 );
+
+ pm.load( sprites_prefix + "powerups/shoot.png" );
+ label = new QLabel( mainWin );
+ label->setPixmap( pm );
+ label->setFixedWidth( label->sizeHint().width() );
+ label->setPalette( pal );
+ hbd->addWidget( label );
+
+ shootLCD = new QLCDNumber( 1, mainWin );
+ shootLCD->setFrameStyle( QFrame::NoFrame );
+ shootLCD->setSegmentStyle( QLCDNumber::Flat );
+ shootLCD->setPalette( pal );
+ shootLCD->setFixedHeight( 20 );
+ hbd->addWidget( shootLCD );
+
+ hbd->addStretch( 1 );
+
+ label = new QLabel( i18n( "Fuel" ), mainWin );
+ label->setFont( smallFont );
+ label->setFixedWidth( label->sizeHint().width() + 10 );
+ label->setPalette( pal );
+ hbd->addWidget( label );
+
+ powerMeter = new KALedMeter( mainWin );
+ powerMeter->setFrameStyle( QFrame::Box | QFrame::Plain );
+ powerMeter->setRange( MAX_POWER_LEVEL );
+ powerMeter->addColorRange( 10, darkRed );
+ powerMeter->addColorRange( 20, QColor(160, 96, 0) );
+ powerMeter->addColorRange( 70, darkGreen );
+ powerMeter->setCount( 40 );
+ powerMeter->setPalette( pal );
+ powerMeter->setFixedSize( 200, 12 );
+ hbd->addWidget( powerMeter );
+
+ initKAction();
+
+ setCentralWidget( mainWin );
+
+ setupGUI( KMainWindow::Save | Create );
+
+ setFocusPolicy( StrongFocus );
+ setFocus();
+
+#ifdef KA_ENABLE_SOUND
+ soundServer = new Arts::SimpleSoundServer(
+ Arts::Reference("global:Arts_SimpleSoundServer") );
+#endif
+
+ loadSettings();
+ slotNewGame();
+ installEventFilter(this);
+}
+
+KAstTopLevel::~KAstTopLevel()
+{
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+ XAutoRepeatOn( qt_xdisplay() );
+#endif
+ soundDict.setAutoDelete(true);
+ soundDict.clear();
+#ifdef KA_ENABLE_SOUND
+ delete soundServer;
+#endif
+}
+
+void KAstTopLevel::initKAction()
+{
+// game
+ KStdGameAction::gameNew( this, SLOT( slotNewGame() ), actionCollection() );
+ KStdGameAction::highscores( this, SLOT( slotShowHighscores() ), actionCollection() );
+ KStdGameAction::pause( this, SLOT( slotPause() ), actionCollection() );
+ KStdGameAction::quit(this, SLOT( close() ), actionCollection());
+
+// settings
+ KStdAction::keyBindings(this, SLOT( slotKeyConfig() ), actionCollection());
+ KStdAction::preferences(this, SLOT( slotPref() ), actionCollection());
+
+// keyboard-only actions
+ keycodes.insert(Thrust, new KAction(i18n("Thrust"), Qt::Key_Up, 0, 0, actionCollection(), "Thrust"));
+ keycodes.insert(RotateLeft, new KAction(i18n("Rotate Left"), Qt::Key_Left, 0, 0, actionCollection(), "RotateLeft"));
+ keycodes.insert(RotateRight, new KAction(i18n("Rotate Right"), Qt::Key_Right, 0, 0, actionCollection(), "RotateRight"));
+ keycodes.insert(Shoot, new KAction(i18n("Shoot"), Qt::Key_Space, 0, 0, actionCollection(), "Shoot"));
+// keycodes.insert(Teleport, new KAction(i18n("Teleport"), Qt::Key_Z, 0, 0, actionCollection(), "Teleport"));
+ keycodes.insert(Brake, new KAction(i18n("Brake"), Qt::Key_X, 0, 0, actionCollection(), "Brake"));
+ keycodes.insert(Shield, new KAction(i18n("Shield"), Qt::Key_S, 0, 0, actionCollection(), "Shield"));
+ launchAction = new KAction(i18n("Launch"), Qt::Key_L, this, SLOT(slotLaunch()), actionCollection(), "Launch");
+}
+
+
+void KAstTopLevel::loadSettings()
+{
+ soundDict.insert("ShipDestroyed",
+ new QString( locate("sounds", Settings::soundShipDestroyed())) );
+ soundDict.insert("RockDestroyed",
+ new QString( locate("sounds", Settings::soundRockDestroyed())) );
+
+ shipsRemain = Settings::numShips();
+}
+
+void KAstTopLevel::playSound( const char *snd )
+{
+// KAudioPlayer sometimes seem to be a little bit...slow
+// it takes a moment until the sound is played - maybe an arts problem
+// but it's a good temporary solution
+ if (!Settings::playSounds())
+ return;
+
+ QString *filename = soundDict[ snd ];
+ if (filename) {
+ KAudioPlayer::play(*filename);
+ }
+
+return; // remove this and the above when the sound below is working correctly
+#ifdef KA_ENABLE_SOUND
+ QString *filename = soundDict[ snd ];
+ if (filename) {
+ kdDebug(12012)<< "playing " << *filename << endl;
+ if(!soundServer->isNull()) soundServer->play(filename->latin1());
+ }
+#endif
+}
+
+bool KAstTopLevel::eventFilter( QObject* /* object */, QEvent *event )
+{
+ QKeyEvent *e = static_cast<QKeyEvent*>(event);
+ if (event->type() == QEvent::AccelOverride)
+ {
+ if (processKeyPress(e)) return true;
+ else return false;
+ }
+ else if (event->type() == QEvent::KeyRelease)
+ {
+ if (processKeyRelease(e)) return true;
+ else return false;
+ }
+ return false;
+}
+
+bool KAstTopLevel::processKeyPress( QKeyEvent *event )
+{
+ KKey key(event);
+ Action a = Invalid;
+ QMap<Action, KAction*>::Iterator it = keycodes.begin();
+ for (; it != keycodes.end(); ++it)
+ {
+ if ( (*it)->shortcut().contains(key) )
+ {
+ a = it.key();
+ break;
+ }
+ }
+ switch ( a )
+ {
+ case RotateLeft:
+ view->rotateLeft( true );
+ break;
+
+ case RotateRight:
+ view->rotateRight( true );
+ break;
+
+ case Thrust:
+ view->thrust( true );
+ break;
+
+ case Shoot:
+ if (gameOver)
+ slotNewGame();
+ else
+ view->shoot( true );
+ break;
+
+ case Shield:
+ view->setShield( true );
+ break;
+
+/* case Teleport:
+ view->teleport( true );
+ break;*/
+
+ case Brake:
+ view->brake( true );
+ break;
+
+ case Invalid:
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool KAstTopLevel::processKeyRelease( QKeyEvent *event )
+{
+ KKey key(event);
+ Action a = Invalid;
+ QMap<Action, KAction*>::Iterator it = keycodes.begin();
+ for (; it != keycodes.end(); ++it)
+ {
+ if ( (*it)->shortcut().contains(key) )
+ {
+ a = it.key();
+ break;
+ }
+ }
+ switch ( a )
+ {
+ case RotateLeft:
+ view->rotateLeft( false );
+ break;
+
+ case RotateRight:
+ view->rotateRight( false );
+ break;
+
+ case Thrust:
+ view->thrust( false );
+ break;
+
+ case Shoot:
+ view->shoot( false );
+ break;
+
+ case Brake:
+ view->brake( false );
+ break;
+
+ case Shield:
+ view->setShield( false );
+ break;
+
+/* case Teleport:
+ view->teleport( false );
+ break;*/
+
+ case Invalid:
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+void KAstTopLevel::focusInEvent( QFocusEvent *e )
+{
+ view->pause( false );
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+ XAutoRepeatOff( qt_xdisplay() );
+#endif
+ KMainWindow::focusInEvent(e);
+}
+
+void KAstTopLevel::focusOutEvent( QFocusEvent *e )
+{
+ view->pause( true );
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+ XAutoRepeatOn( qt_xdisplay() );
+#endif
+ KMainWindow::focusOutEvent(e);
+}
+
+void KAstTopLevel::slotNewGame()
+{
+ loadSettings();
+ score = 0;
+ scoreLCD->display( 0 );
+ level = 0;
+ levelLCD->display( level );
+ shipsLCD->display( shipsRemain-1 );
+ view->newGame();
+ view->setRockSpeed( levels[0].rockSpeed );
+ view->addRocks( levels[0].nrocks );
+ view->showText( i18n( "Press %1 to launch." )
+ .arg(launchAction->shortcut().seq(0).toString()),
+ yellow );
+ waitShip = true;
+ gameOver = false;
+}
+
+bool KAstTopLevel::queryExit()
+{
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+ XAutoRepeatOn( qt_xdisplay() );
+#endif
+ return true;
+}
+
+void KAstTopLevel::slotShipKilled()
+{
+ shipsRemain--;
+ shipsLCD->display( shipsRemain-1 );
+
+ playSound( "ShipDestroyed" );
+
+ if ( shipsRemain )
+ {
+ waitShip = true;
+ view->showText( i18n( "Ship Destroyed. Press %1 to launch.")
+ .arg(launchAction->shortcut().seq(0).toString()),
+ yellow );
+ }
+ else
+ {
+ view->showText( i18n("Game Over!"), red );
+ view->endGame();
+ doStats();
+ KScoreDialog d(KScoreDialog::Name | KScoreDialog::Level | KScoreDialog::Score, this);
+ KScoreDialog::FieldInfo scoreInfo;
+ scoreInfo[KScoreDialog::Level].setNum(level);
+
+ if (d.addScore(score, scoreInfo) || Settings::showHiscores())
+ {
+ // Show highscore and ask for name.
+ d.exec();
+ slotGameOver();
+ }
+ else
+ {
+ QTimer::singleShot(1000, this, SLOT(slotGameOver()));
+ }
+ }
+}
+
+void KAstTopLevel::slotGameOver()
+{
+ gameOver = true;
+}
+
+void KAstTopLevel::slotRockHit( int size )
+{
+ switch ( size )
+ {
+ case 0:
+ score += 10;
+ break;
+
+ case 1:
+ score += 20;
+ break;
+
+ default:
+ score += 40;
+ }
+
+ playSound( "RockDestroyed" );
+
+ scoreLCD->display( score );
+}
+
+void KAstTopLevel::slotRocksRemoved()
+{
+ level++;
+
+ if ( level >= MAX_LEVELS )
+ level = MAX_LEVELS - 1;
+
+ view->setRockSpeed( levels[level-1].rockSpeed );
+ view->addRocks( levels[level-1].nrocks );
+
+ levelLCD->display( level );
+}
+
+void KAstTopLevel::slotKeyConfig()
+{
+ KKeyDialog::configure( actionCollection(), this );
+ if ( waitShip ) view->showText( i18n( "Press %1 to launch." )
+ .arg(launchAction->shortcut().seq(0).toString()),
+ yellow, false );
+}
+
+void KAstTopLevel::slotPref()
+{
+ if(KConfigDialog::showDialog("settings"))
+ return;
+
+ KConfigDialog *dialog = new KConfigDialog(this, "settings", Settings::self(), KDialogBase::Swallow);
+
+ /* Make widget */
+ QWidget *w = new QWidget(0, "Settings");
+ QVBoxLayout *page = new QVBoxLayout( w, 11 );
+
+ QHBoxLayout *hb = new QHBoxLayout( page, 11 );
+ QLabel *label = new QLabel( i18n("Start new game with"), w );
+ QSpinBox* sb = new QSpinBox( 1, 5, 1, w, "kcfg_numShips" );
+ sb->setValue(3);
+ QLabel *lb = new QLabel( i18n(" ships."), w );
+ QSpacerItem* hspacer = new QSpacerItem( 16, 20, QSizePolicy::Minimum, QSizePolicy::Expanding );
+ hb->addWidget(label);
+ hb->addWidget(sb);
+ hb->addWidget(lb);
+ hb->addItem(hspacer);
+
+ QCheckBox *f1 = new QCheckBox(i18n("Show highscores on Game Over"), w, "kcfg_showHiscores");
+ QCheckBox *f2 = new QCheckBox(i18n("Player can destroy Powerups"), w, "kcfg_canDestroyPowerups");
+ f2->setChecked(true);
+ page->addWidget(f1);
+ page->addWidget(f2);
+ QSpacerItem* spacer = new QSpacerItem( 20, 16, QSizePolicy::Minimum, QSizePolicy::Expanding );
+ page->addItem( spacer );
+ /* Done */
+
+ dialog->addPage(w, i18n("General"), "package_settings");
+ connect(dialog, SIGNAL(settingsChanged()), this, SLOT(loadSettings()));
+ dialog->show();
+}
+
+void KAstTopLevel::slotShowHighscores()
+{
+ KScoreDialog d(KScoreDialog::Name | KScoreDialog::Level | KScoreDialog::Score, this);
+ d.exec();
+}
+
+void KAstTopLevel::doStats()
+{
+ QString r;
+ if ( view->shots() )
+ r = KGlobal::locale()->formatNumber(( (float)view->hits() /
+ (float)view->shots() ) * 100, 2 );
+ else
+ r = KGlobal::locale()->formatNumber( 0.0, 2 );
+
+ QString s = i18n( "Game Over\n\n"
+ "Shots fired:\t%1\n"
+ " Hit:\t%2\n"
+ " Missed:\t%3\n"
+ "Hit ratio:\t%4 %\t\t")
+ .arg(view->shots()).arg(view->hits())
+ .arg(view->shots() - view->hits())
+ .arg(r);
+
+ view->showText( s, green, FALSE );
+}
+
+void KAstTopLevel::slotUpdateVitals()
+{
+ brakesLCD->display( view->brakeCount() );
+ shieldLCD->display( view->shieldCount() );
+ shootLCD->display( view->shootCount() );
+// teleportsLCD->display( view->teleportCount() );
+ powerMeter->setValue( view->power() );
+}
+
+void KAstTopLevel::slotPause()
+{
+ KMessageBox::information( this,
+ i18n("KAsteroids is paused."),
+ i18n("Paused") );
+ //Hack (montel@kde.org)
+ //To create "pause" action we display a messagebox
+ //and we "play" when we close this messagebox
+ //so before this action was 'checked/uncheched'
+ //so I force to unchecked it when we close messagebox.
+ KToggleAction * act = (KToggleAction *)(sender());
+ act->setChecked(false);
+}
+
+void KAstTopLevel::slotLaunch()
+{
+ if ( waitShip )
+ {
+ view->newShip();
+ waitShip = false;
+ view->hideText();
+ }
+}