/* * KAsteroids - Copyright (c) Martin R. Jones 1997 * * Part of the KDE project */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "settings.h" #include "toplevel.h" #include "ledmeter.h" #include "toplevel.moc" #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY #include #endif #include #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 #include Arts::SimpleSoundServer *soundServer = 0; #endif KAstTopLevel::KAstTopLevel() { TQWidget *mainWin = new TQWidget( this ); mainWin->setFixedSize(640, 480); view = new KAsteroidsView( mainWin ); connect( view, TQT_SIGNAL( shipKilled() ), TQT_SLOT( slotShipKilled() ) ); connect( view, TQT_SIGNAL( rockHit(int) ), TQT_SLOT( slotRockHit(int) ) ); connect( view, TQT_SIGNAL( rocksRemoved() ), TQT_SLOT( slotRocksRemoved() ) ); connect( view, TQT_SIGNAL( updateVitals() ), TQT_SLOT( slotUpdateVitals() ) ); TQVBoxLayout *vb = new TQVBoxLayout( mainWin ); TQHBoxLayout *hb = new TQHBoxLayout; TQHBoxLayout *hbd = new TQHBoxLayout; vb->addLayout( hb ); TQFont labelFont( TDEGlobalSettings::generalFont().family(), 24 ); TQColorGroup grp( darkGreen, black, TQColor( 128, 128, 128 ), TQColor( 64, 64, 64 ), black, darkGreen, black ); TQPalette pal( grp, grp, grp ); mainWin->setPalette( pal ); hb->addSpacing( 10 ); TQLabel *label; label = new TQLabel( i18n("Score"), mainWin ); label->setFont( labelFont ); label->setPalette( pal ); label->setFixedWidth( label->sizeHint().width() ); hb->addWidget( label ); scoreLCD = new TQLCDNumber( 6, mainWin ); scoreLCD->setFrameStyle( TQFrame::NoFrame ); scoreLCD->setSegmentStyle( TQLCDNumber::Flat ); scoreLCD->setFixedWidth( 150 ); scoreLCD->setPalette( pal ); hb->addWidget( scoreLCD ); hb->addStretch( 10 ); label = new TQLabel( i18n("Level"), mainWin ); label->setFont( labelFont ); label->setPalette( pal ); label->setFixedWidth( label->sizeHint().width() ); hb->addWidget( label ); levelLCD = new TQLCDNumber( 2, mainWin ); levelLCD->setFrameStyle( TQFrame::NoFrame ); levelLCD->setSegmentStyle( TQLCDNumber::Flat ); levelLCD->setFixedWidth( 70 ); levelLCD->setPalette( pal ); hb->addWidget( levelLCD ); hb->addStretch( 10 ); label = new TQLabel( i18n("Ships"), mainWin ); label->setFont( labelFont ); label->setFixedWidth( label->sizeHint().width() ); label->setPalette( pal ); hb->addWidget( label ); shipsLCD = new TQLCDNumber( 1, mainWin ); shipsLCD->setFrameStyle( TQFrame::NoFrame ); shipsLCD->setSegmentStyle( TQLCDNumber::Flat ); shipsLCD->setFixedWidth( 40 ); shipsLCD->setPalette( pal ); hb->addWidget( shipsLCD ); hb->addStrut( 30 ); TQFrame *sep = new TQFrame( mainWin ); sep->setMaximumHeight( 5 ); sep->setFrameStyle( TQFrame::HLine | TQFrame::Raised ); sep->setPalette( pal ); vb->addWidget( sep ); vb->addWidget( view, 10 ); // -- bottom layout: TQFrame *sep2 = new TQFrame( mainWin ); sep2->setMaximumHeight( 1 ); sep2->setFrameStyle( TQFrame::HLine | TQFrame::Raised ); sep2->setPalette( pal ); vb->addWidget( sep2, 1 ); vb->addLayout( hbd ); TQFont smallFont( TDEGlobalSettings::generalFont().family(), 14 ); hbd->addSpacing( 10 ); TQString sprites_prefix = TDEGlobal::dirs()->findResourceDir("sprite", "rock1/rock10000.png"); /* label = new TQLabel( i18n( "T" ), mainWin ); label->setFont( smallFont ); label->setFixedWidth( label->sizeHint().width() ); label->setPalette( pal ); hbd->addWidget( label ); teleportsLCD = new TQLCDNumber( 1, mainWin ); teleportsLCD->setFrameStyle( TQFrame::NoFrame ); teleportsLCD->setSegmentStyle( TQLCDNumber::Flat ); teleportsLCD->setPalette( pal ); teleportsLCD->setFixedHeight( 20 ); hbd->addWidget( teleportsLCD ); hbd->addSpacing( 10 ); */ TQPixmap pm( sprites_prefix + "powerups/brake.png" ); label = new TQLabel( mainWin ); label->setPixmap( pm ); label->setFixedWidth( label->sizeHint().width() ); label->setPalette( pal ); hbd->addWidget( label ); brakesLCD = new TQLCDNumber( 1, mainWin ); brakesLCD->setFrameStyle( TQFrame::NoFrame ); brakesLCD->setSegmentStyle( TQLCDNumber::Flat ); brakesLCD->setPalette( pal ); brakesLCD->setFixedHeight( 20 ); hbd->addWidget( brakesLCD ); hbd->addSpacing( 10 ); pm.load( sprites_prefix + "powerups/shield.png" ); label = new TQLabel( mainWin ); label->setPixmap( pm ); label->setFixedWidth( label->sizeHint().width() ); label->setPalette( pal ); hbd->addWidget( label ); shieldLCD = new TQLCDNumber( 1, mainWin ); shieldLCD->setFrameStyle( TQFrame::NoFrame ); shieldLCD->setSegmentStyle( TQLCDNumber::Flat ); shieldLCD->setPalette( pal ); shieldLCD->setFixedHeight( 20 ); hbd->addWidget( shieldLCD ); hbd->addSpacing( 10 ); pm.load( sprites_prefix + "powerups/shoot.png" ); label = new TQLabel( mainWin ); label->setPixmap( pm ); label->setFixedWidth( label->sizeHint().width() ); label->setPalette( pal ); hbd->addWidget( label ); shootLCD = new TQLCDNumber( 1, mainWin ); shootLCD->setFrameStyle( TQFrame::NoFrame ); shootLCD->setSegmentStyle( TQLCDNumber::Flat ); shootLCD->setPalette( pal ); shootLCD->setFixedHeight( 20 ); hbd->addWidget( shootLCD ); hbd->addStretch( 1 ); label = new TQLabel( i18n( "Fuel" ), mainWin ); label->setFont( smallFont ); label->setFixedWidth( label->sizeHint().width() + 10 ); label->setPalette( pal ); hbd->addWidget( label ); powerMeter = new KALedMeter( mainWin ); powerMeter->setFrameStyle( TQFrame::Box | TQFrame::Plain ); powerMeter->setRange( MAX_POWER_LEVEL ); powerMeter->addColorRange( 10, darkRed ); powerMeter->addColorRange( 20, TQColor(160, 96, 0) ); powerMeter->addColorRange( 70, darkGreen ); powerMeter->setCount( 40 ); powerMeter->setPalette( pal ); powerMeter->setFixedSize( 200, 12 ); hbd->addWidget( powerMeter ); initTDEAction(); setCentralWidget( mainWin ); setupGUI( TDEMainWindow::Save | Create ); setFocusPolicy( TQ_StrongFocus ); setFocus(); #ifdef KA_ENABLE_SOUND soundServer = new Arts::SimpleSoundServer( Arts::Reference("global:Arts_SimpleSoundServer") ); #endif loadSettings(); slotNewGame(); installEventFilter(this); } KAstTopLevel::~KAstTopLevel() { #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY XAutoRepeatOn( tqt_xdisplay() ); #endif soundDict.setAutoDelete(true); soundDict.clear(); #ifdef KA_ENABLE_SOUND delete soundServer; #endif } void KAstTopLevel::initTDEAction() { // game KStdGameAction::gameNew( TQT_TQOBJECT(this), TQT_SLOT( slotNewGame() ), actionCollection() ); KStdGameAction::highscores( TQT_TQOBJECT(this), TQT_SLOT( slotShowHighscores() ), actionCollection() ); KStdGameAction::pause( TQT_TQOBJECT(this), TQT_SLOT( slotPause() ), actionCollection() ); KStdGameAction::quit(TQT_TQOBJECT(this), TQT_SLOT( close() ), actionCollection()); // settings KStdAction::keyBindings(TQT_TQOBJECT(this), TQT_SLOT( slotKeyConfig() ), actionCollection()); KStdAction::preferences(TQT_TQOBJECT(this), TQT_SLOT( slotPref() ), actionCollection()); // keyboard-only actions keycodes.insert(Thrust, new TDEAction(i18n("Thrust"), TQt::Key_Up, 0, 0, actionCollection(), "Thrust")); keycodes.insert(RotateLeft, new TDEAction(i18n("Rotate Left"), TQt::Key_Left, 0, 0, actionCollection(), "RotateLeft")); keycodes.insert(RotateRight, new TDEAction(i18n("Rotate Right"), TQt::Key_Right, 0, 0, actionCollection(), "RotateRight")); keycodes.insert(Shoot, new TDEAction(i18n("Shoot"), TQt::Key_Space, 0, 0, actionCollection(), "Shoot")); // keycodes.insert(Teleport, new TDEAction(i18n("Teleport"), TQt::Key_Z, 0, 0, actionCollection(), "Teleport")); keycodes.insert(Brake, new TDEAction(i18n("Brake"), TQt::Key_X, 0, 0, actionCollection(), "Brake")); keycodes.insert(Shield, new TDEAction(i18n("Shield"), TQt::Key_S, 0, 0, actionCollection(), "Shield")); launchAction = new TDEAction(i18n("Launch"), TQt::Key_L, TQT_TQOBJECT(this), TQT_SLOT(slotLaunch()), actionCollection(), "Launch"); } void KAstTopLevel::loadSettings() { soundDict.insert("ShipDestroyed", new TQString( locate("sounds", Settings::soundShipDestroyed())) ); soundDict.insert("RockDestroyed", new TQString( 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; TQString *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 TQString *filename = soundDict[ snd ]; if (filename) { kdDebug(12012)<< "playing " << *filename << endl; if(!soundServer->isNull()) soundServer->play(filename->latin1()); } #endif } bool KAstTopLevel::eventFilter( TQObject* /* object */, TQEvent *event ) { TQKeyEvent *e = TQT_TQKEYEVENT(event); if (event->type() == TQEvent::AccelOverride) { if (processKeyPress(e)) return true; else return false; } else if (event->type() == TQEvent::KeyRelease) { if (processKeyRelease(e)) return true; else return false; } return false; } bool KAstTopLevel::processKeyPress( TQKeyEvent *event ) { KKey key(event); Action a = Invalid; TQMap::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( TQKeyEvent *event ) { KKey key(event); Action a = Invalid; TQMap::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( TQFocusEvent *e ) { view->pause( false ); #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY XAutoRepeatOff( tqt_xdisplay() ); #endif TDEMainWindow::focusInEvent(e); } void KAstTopLevel::focusOutEvent( TQFocusEvent *e ) { view->pause( true ); #if defined TQ_WS_X11 && ! defined K_WS_TQTONLY XAutoRepeatOn( tqt_xdisplay() ); #endif TDEMainWindow::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 TQ_WS_X11 && ! defined K_WS_TQTONLY XAutoRepeatOn( tqt_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 { TQTimer::singleShot(1000, TQT_TQOBJECT(this), TQT_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(TDEConfigDialog::showDialog("settings")) return; TDEConfigDialog *dialog = new TDEConfigDialog(this, "settings", Settings::self(), KDialogBase::Swallow); /* Make widget */ TQWidget *w = new TQWidget(0, "Settings"); TQVBoxLayout *page = new TQVBoxLayout( w, 11 ); TQHBoxLayout *hb = new TQHBoxLayout( page, 11 ); TQLabel *label = new TQLabel( i18n("Start new game with"), w ); TQSpinBox* sb = new TQSpinBox( 1, 5, 1, w, "kcfg_numShips" ); sb->setValue(3); TQLabel *lb = new TQLabel( i18n(" ships."), w ); TQSpacerItem* hspacer = new TQSpacerItem( 16, 20, TQSizePolicy::Minimum, TQSizePolicy::Expanding ); hb->addWidget(label); hb->addWidget(sb); hb->addWidget(lb); hb->addItem(hspacer); TQCheckBox *f1 = new TQCheckBox(i18n("Show highscores on Game Over"), w, "kcfg_showHiscores"); TQCheckBox *f2 = new TQCheckBox(i18n("Player can destroy Powerups"), w, "kcfg_canDestroyPowerups"); f2->setChecked(true); page->addWidget(f1); page->addWidget(f2); TQSpacerItem* spacer = new TQSpacerItem( 20, 16, TQSizePolicy::Minimum, TQSizePolicy::Expanding ); page->addItem( spacer ); /* Done */ dialog->addPage(w, i18n("General"), "package_settings"); connect(dialog, TQT_SIGNAL(settingsChanged()), TQT_TQOBJECT(this), TQT_SLOT(loadSettings())); dialog->show(); } void KAstTopLevel::slotShowHighscores() { KScoreDialog d(KScoreDialog::Name | KScoreDialog::Level | KScoreDialog::Score, this); d.exec(); } void KAstTopLevel::doStats() { TQString r; if ( view->shots() ) r = TDEGlobal::locale()->formatNumber(( (float)view->hits() / (float)view->shots() ) * 100, 2 ); else r = TDEGlobal::locale()->formatNumber( 0.0, 2 ); TQString 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. TDEToggleAction * act = (TDEToggleAction *)(sender()); act->setChecked(false); } void KAstTopLevel::slotLaunch() { if ( waitShip ) { view->newShip(); waitShip = false; view->hideText(); } }