[Kde-games-devel] KDE/kdegames

Nicolas Roffet nicolas-kde at roffet.com
Fri Jul 6 19:05:23 CEST 2007


SVN commit 684464 by roffet:

I added a new class in libkdegames: "KGameDifficulty".

In many games, the player can select and change the difficulty level. Until now, this is rewritten from scatch in every single game and it's not uniform. With KGameDifficulty, it should be easier and more consistant.
Features:
 - The class uses the standard icon "games-difficult.png".
 - It's possible to use between 1 and 8 "standard" appelations for the levels (like "Easy", "Medium", "Hard", ...) or to customize them (and have more) if needed.
 - The class can ask the player to confirm, if he wants to start a new game to change the difficulty level, so that the game itself doesn't need to care much about this.
 - It's possible to defined a custom difficulty level (with a configuration dialog that has to be implemented in every game).

The class is in a 1st draf state. It's working, but not yet full documented and wihout D-pointer yet. 
We should also discuss if it's OK to select the difficulty level in the menu bar and / or in the toolbar. Or if we also want a independant widget for this, that could be placed in the status bar for instance, like in bovo right now.
We should also include the menu item "Game difficulty" in the standard UI RC file of kdelibs. Before that, it has to be explicit added in the UI RC file of every game using this class.
So, please give some feedback. :)

(I spoke with Johann about this change at the aKademy.)

I fixed also KBlackBox to use this class now. It's the first game to use it as a proof of concept. (And in KBlackBox it's better to have predefined difficulty levels, so the player doesn't have to configure the number of balls and the grid size like before).
If the feedback is good, I would be glad to fix the other games.

CCMAIL:kde-games-devel at kde.org

 M  +12 -5     kblackbox/kbbgamedoc.cpp  
 M  +3 -0      kblackbox/kbbgamedoc.h  
 M  +92 -102   kblackbox/kbbmainwindow.cpp  
 M  +15 -13    kblackbox/kbbmainwindow.h  
 M  +7 -3      kblackbox/kblackbox.kcfg  
 M  +2 -2      kblackbox/kblackboxui.rc  
 M  +2 -0      libkdegames/CMakeLists.txt  
 A             libkdegames/kgamedifficulty.cpp   [License: LGPL (v2+)]
 A             libkdegames/kgamedifficulty.h   [License: LGPL (v2+)]


--- trunk/KDE/kdegames/kblackbox/kbbgamedoc.cpp #684463:684464
@@ -48,13 +48,13 @@
 
 KBBGameDoc::KBBGameDoc(KBBMainWindow *parent, KBBTutorial* tutorial) : QObject(parent)
 {
-	m_gameReallyStarted = false;
+	setRunning(false);
 	m_columns = 1;
 	m_rows = 1;
 	m_tutorial = tutorial;
 	
 	random.setSeed(0);
-		
+	
 	m_balls = new KBBBallsOnBoard(this, m_columns, m_rows);
 	m_ballsPlaced = new KBBBallsOnBoard(this, m_columns, m_rows);
 	connect(m_ballsPlaced, SIGNAL(changes()), parent, SLOT(updateStats()));
@@ -75,7 +75,7 @@
 void KBBGameDoc::gameOver()
 {
 	// Clear
-	m_gameReallyStarted = false;
+	setRunning(false);
 	
 	// Compute final score
 	setScore( score + 5*m_ballsPlaced->numberOfBallsNotIn(m_balls) );
@@ -146,7 +146,7 @@
 		setScore( score + 2);
 	
 	if (!m_tutorial->isVisible())
-		m_gameReallyStarted = true;
+		setRunning(true);
 	emit updateStats();
 
 	return outgoingBorderPosition;
@@ -175,7 +175,7 @@
 	m_rows = rows;
 
 	// Clear
-	m_gameReallyStarted = false;
+	setRunning(false);
 	m_ballsPlaced->newBoard(m_columns, m_rows);
 	setScore(0);
 
@@ -183,6 +183,13 @@
 }
 
 
+void KBBGameDoc::setRunning(const bool r)
+{
+	m_gameReallyStarted = r;
+	emit running(r);
+}
+
+
 void KBBGameDoc::setScore( int n )
 {
 	score = n;
--- trunk/KDE/kdegames/kblackbox/kbbgamedoc.h #684463:684464
@@ -142,10 +142,13 @@
 
 
 	signals:
+		void running(bool);
 		void updateStats();
 
 
 	private:
+		void setRunning(bool r);
+
 		/**
 		 * @brief Sets the score value
 		 *
--- trunk/KDE/kdegames/kblackbox/kbbmainwindow.cpp #684463:684464
@@ -37,11 +37,11 @@
 
 
 #include <kactioncollection.h>
+#include <kgamedifficulty.h>
 #include <kgamepopupitem.h>
 #include <kglobal.h>
 #include <klocale.h>
 #include <kmessagebox.h>
-#include <kselectaction.h>
 #include <kstandarddirs.h>
 #include <kstandardgameaction.h>
 #include <kstatusbar.h>
@@ -116,29 +116,14 @@
 
 	// Move
 	m_solveAction = KStandardGameAction::solve(this, SLOT(solve()), actionCollection());
-	
-	// Settings
-	m_sizeAction = new KSelectAction( i18n("&Size"), this);
-	actionCollection()->addAction("options_size", m_sizeAction);
-	connect(m_sizeAction, SIGNAL(triggered(int)), this, SLOT(slotSize(int)));
-	QStringList list;
-	list.append(i18n("  8 x  8 "));
-	list.append(i18n(" 10 x 10 "));
-	list.append(i18n(" 12 x 12 "));
-	list.append(i18n(" 18 x 12 "));
-	m_sizeAction->setItems(list);
-	
-	m_ballsAction = new KSelectAction( i18n("&Balls"), this);
-	actionCollection()->addAction("options_balls", m_ballsAction);
-	connect(m_ballsAction, SIGNAL(triggered(int)), this, SLOT(slotBalls(int)));
-	list.clear();
-	list.append(i18n("4 balls"));
-	list.append(i18n("6 balls"));
-	list.append(i18n("8 balls"));
-	list.append(i18n("10 balls"));
-	m_ballsAction->setItems(list);
-	
-	
+
+
+	m_difficulty = new KGameDifficulty(this, true, 8);
+// TODO	m_difficulty->addCustomLevel();
+	connect(m_gameDoc, SIGNAL(running(bool)), m_difficulty, SLOT(setRunning(bool)));
+	connect(m_difficulty, SIGNAL(levelChanged(int)), this, SLOT(levelChanged(int)));
+
+
 	// Keyboard only
 	QAction* action = actionCollection()->addAction( "move_down" );
 	action->setText( i18n("Move Down") );
@@ -175,28 +160,22 @@
 	connect(action, SIGNAL(triggered(bool)), m_gameWidget, SLOT(keyboardSpace()));
 	action->setShortcut(Qt::Key_Space);
 	addAction(action);
-	
-	//Read configuration options
-	m_ballNumber = KBBPrefs::balls();
-	const int menuNumber[4] = {4, 6, 8, 10};
-	for (int i=0; i<4; i++)
-		if (menuNumber[i]==m_ballNumber)
-			m_ballsAction->setCurrentItem(i);
-	
-	m_columns = KBBPrefs::columns();
-	m_rows = KBBPrefs::rows();
-	const int menuSizeColumns[4] = {8, 10, 12, 18};
-	const int menuSizeRows[4] = {8, 10, 12, 12};
-	for (int i=0; i<4; i++)
-		if ((menuSizeColumns[i]==m_columns) && (menuSizeRows[i]==m_rows))
-			m_sizeAction->setCurrentItem(i);
-	
-	
+
+
 	// Status bar
 	statusBar()->insertItem(i18n("Run: yesno"), SRUN);
 	statusBar()->insertItem(i18n("Size: 00 x 00"), SSIZE);
-	
-	
+
+
+	//Read configuration options
+	m_customBallNumber = KBBPrefs::balls();
+	m_customColumns = KBBPrefs::columns();
+	m_customRows = KBBPrefs::rows();
+
+	m_level = KBBPrefs::level();
+	m_difficulty->setLevel(m_level);
+
+
 	newGame();
 	setupGUI();
 }
@@ -234,53 +213,69 @@
 }
 
 
+void KBBMainWindow::levelChanged(const int level)
+{
+	m_level = level;
+	KBBPrefs::setLevel(m_level);
+	switch(m_level) {
+		case 0:
+			m_ballNumber = 2;
+			m_columns = 5;
+			m_rows = 5;
+			break;
+		case 1:
+			m_ballNumber = 3;
+			m_columns = 6;
+			m_rows = 6;
+			break;
+		case 2:
+			m_ballNumber = 4;
+			m_columns = 8;
+			m_rows = 8;
+			break;
+		case 3:
+			m_ballNumber = 6;
+			m_columns = 10;
+			m_rows = 10;
+			break;
+		case 4:
+			m_ballNumber = 8;
+			m_columns = 12;
+			m_rows = 12;
+			break;
+		case 5:
+			m_ballNumber = 10;
+			m_columns = 14;
+			m_rows = 10;
+			break;
+		case 6:
+			m_ballNumber = 10;
+			m_columns = 18;
+			m_rows = 12;
+			break;
+		case 7:
+			m_ballNumber = 24;
+			m_columns = 20;
+			m_rows = 14;
+			break;
+	}
 
+	startGame(m_ballNumber, m_columns, m_rows, m_sandboxMode);
+}
+
+
+
 //
 // Private slots
 //
 
 void KBBMainWindow::newGame()
 {
-	startGame(m_ballNumber, m_columns, m_rows, false);
+	if (mayAbortGame())
+		startGame(m_ballNumber, m_columns, m_rows, false);
 }
 
 
-void KBBMainWindow::slotBalls(int selection)
-{
-	const int ARRAY_SIZE = 4;
-	const int newNumber[ARRAY_SIZE] = {4, 6, 8, 10};
-	
-	if (m_ballNumber != newNumber[selection]) {
-		if (startGame(newNumber[selection], m_columns, m_rows, m_sandboxMode))
-			KBBPrefs::setBalls(newNumber[selection]);
-		else {
-			for (int i=0; i<ARRAY_SIZE; i++)
-				if (newNumber[i]==m_ballNumber)
-					m_ballsAction->setCurrentItem(i);
-		}
-	}
-}
-
-
-void KBBMainWindow::slotSize(int selection)
-{
-	const int ARRAY_SIZE = 4;
-	const int newSizesColumns[ARRAY_SIZE] = {8, 10, 12, 18};
-	const int newSizesRows[ARRAY_SIZE] = {8, 10, 12, 12};
-
-	if ((newSizesColumns[selection] != m_columns) || (newSizesRows[selection] != m_rows)) {
-		if (startGame(m_ballNumber, newSizesColumns[selection], newSizesRows[selection], m_sandboxMode)) {
-			KBBPrefs::setColumns(m_columns);
-			KBBPrefs::setRows(m_rows);
-		} else {
-			for (int i=0; i<ARRAY_SIZE; i++)
-				if ((newSizesColumns[i]==m_columns) && (newSizesRows[i]==m_rows))
-					m_sizeAction->setCurrentItem(i);
-		}
-	}
-}
-
-
 void KBBMainWindow::solve()
 {
 	if (m_tutorial->isVisible() && !m_tutorial->maySolve()) {
@@ -312,7 +307,8 @@
 
 void KBBMainWindow::startSandbox()
 {
-	startGame(m_ballNumber, m_columns, m_rows, true);
+	if (mayAbortGame())
+		startGame(m_ballNumber, m_columns, m_rows, true);
 }
 
 
@@ -338,36 +334,30 @@
 	bool mayAbort = true;
 
 	if (m_gameDoc->gameReallyStarted())
-		mayAbort = ( KMessageBox::warningContinueCancel(0, i18n("This will be the end of the current game!"), QString(), KGuiItem(i18n("End Game"))) == KMessageBox::Continue );
+		mayAbort = ( KMessageBox::warningContinueCancel(0, i18n("This will be the end of the current game!"), QString(), KGuiItem(i18n("End game"))) == KMessageBox::Continue );
 
 	return mayAbort;
 }
 
 
-bool KBBMainWindow::startGame(const int newBallNumber, const int newColumnNumber, const int newRowNumber, const bool sandboxMode)
+void KBBMainWindow::startGame(const int newBallNumber, const int newColumnNumber, const int newRowNumber, const bool sandboxMode)
 {
-	bool start = mayAbortGame();
+	m_running = true;
+	m_ballNumber = newBallNumber;
+	m_columns = newColumnNumber;
+	m_rows = newRowNumber;
+	m_sandboxMode = sandboxMode;
 
-	if (start) {
-		m_running = true;
-		m_ballNumber = newBallNumber;
-		m_columns = newColumnNumber;
-		m_rows = newRowNumber;
-		m_sandboxMode = sandboxMode;
+	m_solveAction->setEnabled(true);
+	m_tutorial->hide();
+	m_gameDoc->newGame(m_ballNumber, m_columns, m_rows);
+	m_gameWidget->newGame(m_columns, m_rows);
+	if (m_sandboxMode)
+		m_gameWidget->solve(true);
 
-		m_solveAction->setEnabled(true);
-		m_tutorial->hide();
-		m_gameDoc->newGame(m_ballNumber, m_columns, m_rows);
-		m_gameWidget->newGame(m_columns, m_rows);
-		if (m_sandboxMode)
-			m_gameWidget->solve(true);
+	m_infoWidget->setGameParameters(m_ballNumber, m_ballNumber*3);
 
-		m_infoWidget->setGameParameters(m_ballNumber, m_ballNumber*3);
-
-		updateStats();
-	}
-
-	return start;
+	updateStats();
 }
 
 
--- trunk/KDE/kdegames/kblackbox/kbbmainwindow.h #684463:684464
@@ -37,7 +37,7 @@
 class QWidget;
 
 
-class KSelectAction;
+class KGameDifficulty;
 class KToggleAction;
 #include <kxmlguiwindow.h>
 
@@ -69,16 +69,18 @@
 		 */
 		void updateStats();
 
+		/**
+		 * @brief Player changed the level
+		 */
+		void levelChanged(const int level);
 
+
 	private slots:
 		/**
 		 * @brief Start a new game.
 		 */
 		void newGame();
 
-		void slotSize(int selection);
-		void slotBalls(int selection);
-
 		/**
 		 * @brief Ends the current game
 		 *
@@ -113,19 +115,12 @@
 		bool mayAbortGame();
 
 		/**
-		 * @brief Start a new game afer user confirmation (if needed).
-		 *
-		 * If the game is running and really started, the user has to confirm the end of the game.
-		 * If the game is not running or running but not really started, the game may end and a new game may start without user confirmation.
-		 *
-		 * @return if a new game started or not
+		 * @brief Start a new game.
 		 */
-		bool startGame(const int newBallNumber, const int newColumnNumber, const int newRowNumber, const bool newSandboxModeMode);
+		void startGame(const int newBallNumber, const int newColumnNumber, const int newRowNumber, const bool newSandboxModeMode);
 
 
 		// Actions
-		KSelectAction *m_ballsAction;
-		KSelectAction *m_sizeAction;
 		QAction *m_solveAction;
 
 
@@ -140,11 +135,18 @@
 		KBBScalableGraphicWidget* m_gameWidget;
 
 
+		// Custom difficulty level
+		int m_customBallNumber;
+		int m_customColumns;
+		int m_customRows;
+
 		// Various member variables
 		int m_ballNumber;
 		QWidget* m_centralWidget;
 		int m_columns;
+		KGameDifficulty* m_difficulty;
 		KBBInfoWidget* m_infoWidget;
+		int m_level;
 		int m_rows;
 		bool m_running;
 		bool m_sandboxMode;
--- trunk/KDE/kdegames/kblackbox/kblackbox.kcfg #684463:684464
@@ -10,16 +10,20 @@
       <default></default>
     </entry>
     <entry name="balls" type="Int">
-      <label>Number of balls</label>
+      <label>Number of balls for custom difficulty level</label>
       <default>4</default>
     </entry>
     <entry name="columns" type="Int">
-      <label>Number of columns of the board</label>
+      <label>Number of columns of the board for custom difficulty level</label>
       <default>8</default>
     </entry>
     <entry name="rows" type="Int">
-      <label>Number of rows of the board</label>
+      <label>Number of rows of the board for custom difficuty level</label>
       <default>8</default>
     </entry>
+    <entry name="level" type="Int">
+      <label>Difficulty level</label>
+      <default>3</default>
+    </entry>
   </group>
 </kcfg>
--- trunk/KDE/kdegames/kblackbox/kblackboxui.rc #684463:684464
@@ -9,13 +9,13 @@
 		</Menu>
 		<Menu name="settings">
 			<text>&amp;Settings</text>
-			<Action name="options_size" />
-			<Action name="options_balls" />
+			<Action name="game_difficulty" />
 		</Menu>
 	</MenuBar>
 	<ToolBar name="mainToolBar">
 		<text>Main Toolbar</text>
 		<Action name="game_new" />
+		<Action name="game_difficulty" />
 		<Action name="game_tutorial" />
 		<Separator />
 		<Action name="move_solve" />
--- trunk/KDE/kdegames/libkdegames/CMakeLists.txt #684463:684464
@@ -69,6 +69,7 @@
     kgametheme.cpp
     kgamethemeselector.cpp
     kstandardgameaction.cpp
+    kgamedifficulty.cpp
 )
 
 kde4_automoc(${kdegames_LIB_SRCS})
@@ -106,5 +107,6 @@
     kgameclock.h
     kgametheme.h
     kgamethemeselector.h
+    kgamedifficulty.h
     DESTINATION ${INCLUDE_INSTALL_DIR})
 


More information about the kde-games-devel mailing list