File indexing completed on 2024-04-28 07:51:54

0001 /*
0002     This file is part of the KDE project "KLines"
0003 
0004     SPDX-FileCopyrightText: 2006 Dmitry Suzdalev <dimsuz@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #ifndef KL_SCENE_H
0010 #define KL_SCENE_H
0011 
0012 #include <QGraphicsScene>
0013 #include <QRandomGenerator>
0014 
0015 #include "commondefs.h"
0016 
0017 static const int FIELD_SIZE=9;
0018 
0019 class KLinesAnimator;
0020 class BallItem;
0021 class PreviewItem;
0022 class QGraphicsRectItem;
0023 class KGamePopupItem;
0024 
0025 /**
0026  *  Displays and drives the game
0027  */
0028 class KLinesScene : public QGraphicsScene
0029 {
0030     Q_OBJECT
0031 public:
0032     explicit KLinesScene( QObject *parent );
0033     ~KLinesScene() override;
0034     /**
0035      *  Resizes scene
0036      */
0037     void resizeScene( int width, int height );
0038     /**
0039      *  Brings in next three balls to scene
0040      */
0041     void nextThreeBalls();
0042     /**
0043      *  Show/Hide the preview zone
0044      */
0045     void setPreviewZoneVisible( bool visible );
0046     /**
0047      *  This score points will be added as an additional bonus to
0048      *  every score resulted from ball erasing event.
0049      *  For example 1 score point is added if the game is played with
0050      *  hidden preview widget.
0051      *  By default no bonus is added.
0052      */
0053     void setBonusScorePoints( int points ) { m_bonusScore = points; }
0054     /**
0055      *  Returns colors of the 3 balls in the next turn
0056      */
0057     QList<BallColor> nextColors() const { return m_nextColors; }
0058     /**
0059      *  Returns ballitem in field position pos or 0 if there
0060      *  is no item there
0061      */
0062     BallItem* ballAt( FieldPos pos ) { return m_field[pos.x][pos.y]; }
0063     /**
0064      * Overloaded above function
0065      */
0066     BallItem* ballAt( int x, int y ) { return m_field[x][y]; }
0067     /**
0068      *  Field coords to pixel coords
0069      */
0070     inline QPointF fieldToPix(FieldPos fpos) const
0071     {
0072         return QPointF( m_playFieldRect.x() + m_playFieldBorderSize + fpos.x*m_cellSize,
0073                         m_playFieldRect.y() + m_playFieldBorderSize + fpos.y*m_cellSize );
0074     }
0075     /**
0076      *  Pixel coords to field coords
0077      */
0078     inline FieldPos pixToField( QPointF p ) const
0079     {
0080         return FieldPos(static_cast<int>(( p.x()-m_playFieldRect.x()-m_playFieldBorderSize )/m_cellSize),
0081                         static_cast<int>(( p.y()-m_playFieldRect.y()-m_playFieldBorderSize )/m_cellSize));
0082     }
0083 public Q_SLOTS:
0084     /**
0085      *  Starts new game
0086      */
0087     void startNewGame();
0088     /**
0089      * Ends game
0090      */
0091     void endGame();
0092     /**
0093      *  Ends current and starts next turn explicitly
0094      */
0095     void endTurn();
0096     /**
0097      *  Undoes one move
0098      */
0099     void undo();
0100     /**
0101      *  Moves keyboard-playing focus rect to the left
0102      */
0103     void moveFocusLeft();
0104     /**
0105      *  Moves keyboard-playing focus rect to the right
0106      */
0107     void moveFocusRight();
0108     /**
0109      *  Moves keyboard-playing focus rect to the up
0110      */
0111     void moveFocusUp();
0112     /**
0113      *  Moves keyboard-playing focus rect to the down
0114      */
0115     void moveFocusDown();
0116     /**
0117      *  Takes corresponding action on cell under focus rect
0118      */
0119     void cellSelected();
0120 Q_SIGNALS:
0121     void scoreChanged(int);
0122     void stateChanged(const QString &);
0123     void gameOver(int);
0124 private Q_SLOTS:
0125     void moveAnimFinished();
0126     void removeAnimFinished();
0127     void bornAnimFinished();
0128 private:
0129     /**
0130      *  Creates a ball and places it in random free cell
0131      *  @param c color of the ball
0132      *  @return ball placed
0133      */
0134     BallItem* randomlyPlaceBall(BallColor c);
0135     /**
0136      *  Searches for 5 or more balls in a row and deletes them from field
0137      */
0138     void searchAndErase();
0139     /**
0140      *  This function takes one of two actions:
0141      *  If there's a ball at fpos, it will be selected.
0142      *  Otherwise if the cell at fpos is empty and there's
0143      *  a selected ball in some other cell it will be moved to fpos
0144      *  (if the move is possible, of course)
0145      */
0146     void selectOrMove(FieldPos fpos );
0147     /**
0148      *  Saves game state information to be used during undo
0149      */
0150     void saveUndoInfo();
0151     /** Does some actions upon game over. Called from various places where
0152      * it is clear that game is now over. emits gameOver(int) signal
0153      */
0154     void gameOverHandler();
0155 
0156     void drawBackground( QPainter*, const QRectF& ) override;
0157     void mousePressEvent( QGraphicsSceneMouseEvent* ) override;
0158 
0159     /**
0160      *  This array represents the play field.
0161      *  Each cell holds the pointer to BallItem
0162      *  or 0 if there's no ball in that cell
0163      */
0164     BallItem* m_field[FIELD_SIZE][FIELD_SIZE];
0165     /**
0166      *  Used to start game animations
0167      *  This object knows how to do some ball animations
0168      */
0169     KLinesAnimator* m_animator;
0170     /**
0171      * We need random numbers in this game
0172      */
0173     QRandomGenerator m_randomSeq;
0174     /**
0175      * Area of playfield (with border included - if any exists in theme)
0176      */
0177     QRect m_playFieldRect;
0178     /**
0179      * Size of a playfield border.
0180      * Equals 0 if there's no border element in current theme
0181      */
0182     int m_playFieldBorderSize;
0183 
0184     /**
0185      *  Position of selected ball (-1,-1) if none
0186      */
0187     FieldPos m_selPos;
0188     /**
0189      *  Number of free cells in the field
0190      */
0191     int m_numFreeCells;
0192     /**
0193      *  Current game score
0194      */
0195     int m_score;
0196     /**
0197      *  Bonus points added to score upon ball erasing
0198      *  @see setBonusScorePoints()
0199      */
0200     int m_bonusScore;
0201     /**
0202      *  Cell size in pixels
0203      */
0204     int m_cellSize;
0205     /**
0206      *  Is true if preview zone is visible
0207      */
0208     bool m_previewZoneVisible;
0209     /**
0210      *  Varable which is needed for little trick (tm).
0211      *  Read more about it in removeAnimFinished() slot
0212      */
0213     bool m_placeBalls;
0214     /**
0215      *  Items pending for removal after remove-anim finishes
0216      */
0217     QList<BallItem*> m_itemsToDelete;
0218     /**
0219      *  Colors of the next turn's balls
0220      */
0221     QList<BallColor> m_nextColors;
0222     /**
0223      *  Keyboard-playing focus indication
0224      */
0225     QGraphicsRectItem *m_focusItem;
0226     /**
0227      *  Item which displays next balls preview
0228      */
0229     PreviewItem *m_previewItem;
0230     /**
0231      * Item to show popup messages to user
0232      */
0233     KGamePopupItem *m_popupItem;
0234     /**
0235      *  Struct for holding game state - used on undos
0236      */
0237     struct UndoInfo
0238     {
0239         int numFreeCells;
0240         int score;
0241         QList<BallColor> nextColors;
0242         BallColor fcolors[FIELD_SIZE][FIELD_SIZE];
0243     };
0244     /**
0245      *  Holds game state for undo.
0246      *  It is saved before every new turn
0247      */
0248     UndoInfo m_undoInfo;
0249     bool m_gameOver;
0250 };
0251 
0252 #endif