File indexing completed on 2024-04-14 03:59:51
0001 /* 0002 SPDX-FileCopyrightText: 2012 Christian Krippendorf <Coding@Christian-Krippendorf.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 // own 0008 #include "gamescene.h" 0009 0010 // Qt 0011 #include <QGraphicsSceneMouseEvent> 0012 #include <QList> 0013 0014 // KMahjongg 0015 #include "gamedata.h" 0016 #include "gameitem.h" 0017 #include "gameview.h" 0018 #include "kmahjongglayout.h" 0019 #include "gamebackground.h" 0020 #include "gameremovedtiles.h" 0021 0022 0023 GameScene::GameScene(QObject * parent) 0024 : QGraphicsScene(parent) 0025 , m_pFirstSelectedItem(nullptr) 0026 , m_pSecondSelectedItem(nullptr) 0027 , m_gameBackground(nullptr) 0028 , m_gameRemovedTiles(nullptr) 0029 { 0030 initializeGameItemsArray(); 0031 } 0032 0033 GameScene::~GameScene() 0034 { 0035 } 0036 0037 void GameScene::clearGameItems() 0038 { 0039 // Remove all GameItem objects and DON'T remove GameBackground object. 0040 QList<QGraphicsItem*> items = QGraphicsScene::items(); 0041 for (int i = 0; i < items.size(); i++) { 0042 GameItem *gameItem = dynamic_cast<GameItem*>(items.at(i)); 0043 if (gameItem != nullptr) { 0044 QGraphicsScene::removeItem(gameItem); 0045 } 0046 } 0047 initializeGameItemsArray(); 0048 0049 m_pFirstSelectedItem = nullptr; 0050 m_pSecondSelectedItem = nullptr; 0051 } 0052 0053 void GameScene::clear() 0054 { 0055 QGraphicsScene::clear(); 0056 initializeGameItemsArray(); 0057 0058 m_pFirstSelectedItem = nullptr; 0059 m_pSecondSelectedItem = nullptr; 0060 } 0061 0062 void GameScene::initializeGameItemsArray() 0063 { 0064 // initialize all array pointers with nullptr. 0065 for (int i = 0; i < BOARD_WIDTH; ++i) { 0066 for (int j = 0; j < BOARD_HEIGHT; ++j) { 0067 for (int k = 0; k < BOARD_DEPTH; ++k) { 0068 m_pGameItemsArray[i][j][k] = nullptr; 0069 } 0070 } 0071 } 0072 } 0073 0074 void GameScene::setRemovedTilesItem(GameRemovedTiles * gameRemovedTiles) 0075 { 0076 // If a removedtiles object already exist, delete it from scene 0077 if (m_gameRemovedTiles != nullptr) { 0078 QGraphicsScene::removeItem(m_gameRemovedTiles); 0079 } 0080 0081 m_gameRemovedTiles = gameRemovedTiles; 0082 QGraphicsScene::addItem(gameRemovedTiles); 0083 } 0084 0085 void GameScene::setBackgroundItem(GameBackground * gameBackground) 0086 { 0087 // If a background exist, delete it from scene 0088 if (m_gameBackground != nullptr) { 0089 QGraphicsScene::removeItem(m_gameBackground); 0090 } 0091 0092 m_gameBackground = gameBackground; 0093 QGraphicsScene::addItem(gameBackground); 0094 } 0095 0096 void GameScene::addItem(GameItem * gameItem) 0097 { 0098 QGraphicsScene::addItem(gameItem); 0099 0100 // Add the item to the position array. 0101 addItemToPositionArray(gameItem); 0102 } 0103 0104 void GameScene::removeItem(GameItem * gameItem) 0105 { 0106 USHORT x = gameItem->getGridPosX(); 0107 USHORT y = gameItem->getGridPosY(); 0108 USHORT z = gameItem->getGridPosZ(); 0109 m_pGameItemsArray[x][y][z] = nullptr; 0110 0111 QGraphicsScene::removeItem(gameItem); 0112 } 0113 0114 void GameScene::removeItem(POSITION const & stItemPos) 0115 { 0116 GameItem * gameItem = m_pGameItemsArray[stItemPos.x][stItemPos.y][stItemPos.z]; 0117 0118 if (gameItem != nullptr) { 0119 removeItem(gameItem); 0120 } 0121 } 0122 0123 void GameScene::addItemToPositionArray(GameItem * const gameItem) 0124 { 0125 // Take a look, if the place is already taken. 0126 USHORT x = gameItem->getGridPosX(); 0127 USHORT y = gameItem->getGridPosY(); 0128 USHORT z = gameItem->getGridPosZ(); 0129 if (m_pGameItemsArray[x][y][z] == nullptr) { 0130 m_pGameItemsArray[x][y][z] = gameItem; 0131 } 0132 } 0133 0134 GameItem * GameScene::getItemOnGridPos(int x, int y, int z) 0135 { 0136 // Test for range 0137 if ((x < 0 || x > BOARD_WIDTH - 1) || (y < 0 || y > BOARD_HEIGHT - 1) || (z < 0 || z > BOARD_DEPTH - 1)) { 0138 return nullptr; 0139 } 0140 0141 return m_pGameItemsArray[x][y][z]; 0142 } 0143 0144 GameItem * GameScene::getItemOnGridPos(POSITION & stItemPos) 0145 { 0146 return getItemOnGridPos(stItemPos.x, stItemPos.y, stItemPos.z); 0147 } 0148 0149 bool GameScene::isItemOnGridPos(int x, int y, int z) const 0150 { 0151 // Test for range 0152 if ((x < 0 || x > BOARD_WIDTH - 1) || (y < 0 || y > BOARD_HEIGHT - 1) || (z < 0 || z > BOARD_DEPTH - 1)) { 0153 return false; 0154 } 0155 0156 return !(m_pGameItemsArray[x][y][z] == nullptr); 0157 } 0158 0159 QList<GameItem *> GameScene::selectedItems() const 0160 { 0161 QList<QGraphicsItem *> originalList = QGraphicsScene::selectedItems(); 0162 QList<GameItem *> tmpList; 0163 0164 tmpList.reserve(originalList.size()); 0165 for (int i = 0; i < originalList.size(); ++i) { 0166 tmpList.append(dynamic_cast<GameItem *>(originalList.at(i))); 0167 } 0168 0169 return tmpList; 0170 } 0171 0172 QList<GameItem *> GameScene::items() const 0173 { 0174 QList<QGraphicsItem *> originalList = QGraphicsScene::items(); 0175 QList<GameItem *> tmpList; 0176 0177 tmpList.reserve(originalList.size()); 0178 for (int i = 0; i < originalList.size(); ++i) { 0179 GameItem * gameItem = dynamic_cast<GameItem *>(originalList.at(i)); 0180 if (gameItem != nullptr) { 0181 tmpList.append(gameItem); 0182 } 0183 } 0184 0185 return tmpList; 0186 } 0187 0188 bool GameScene::isSelectable(const GameItem * const gameItem) const 0189 { 0190 USHORT x = gameItem->getGridPosX(); 0191 USHORT y = gameItem->getGridPosY(); 0192 USHORT z = gameItem->getGridPosZ(); 0193 0194 // Test for items above... 0195 0196 // We need one layer above. 0197 ++z; 0198 0199 for (int i = x - 1; i <= x + 1; ++i) { 0200 for (int j = y - 1; j <= y + 1; ++j) { 0201 // If there is a stone on the position, the item is not selectable. 0202 if (isItemOnGridPos(i, j, z)) { 0203 return false; 0204 } 0205 } 0206 } 0207 0208 // Test for items beside... 0209 0210 // Go back to the layer of the item. 0211 --z; 0212 0213 bool sideFree = true; 0214 for (int i = x - 2; i <= x + 2; i += 4) { 0215 for (int j = y - 1; j <= y + 1; ++j) { 0216 // If there is one item on the side, it is no longer free. 0217 if (isItemOnGridPos(i, j, z)) { 0218 sideFree = false; 0219 } 0220 } 0221 0222 // If a side is free the item is selectable. 0223 if (sideFree == true) { 0224 return true; 0225 } else { 0226 sideFree = true; 0227 } 0228 } 0229 0230 return false; 0231 } 0232 0233 void GameScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent) 0234 { 0235 // Swallow this event. A double-click causes a mousePressEvent() AND a 0236 // mouseDoubleClickEvent(). The second event could cause a tile that is 0237 // NOT removable to become selected (by default), allowing it to be removed 0238 // illegally (ie. it has a tile on each side or is half under another tile). 0239 mouseEvent->accept(); // Double-click ==> single-click in KMahjongg. 0240 } 0241 0242 void GameScene::mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent) 0243 { 0244 // N.B. Event occurs when there is a click OR double-click with ANY button. 0245 GameItem * gameItem = dynamic_cast<GameItem *>( 0246 itemAt(mouseEvent->scenePos().x(), 0247 mouseEvent->scenePos().y(), QTransform()) 0248 ); 0249 0250 // An item was clicked. 0251 if (gameItem != nullptr) { 0252 // If we click on a shadow of the actual item, we have to correct the 0253 // clicking position, in order to simulate a transparent shadow. 0254 if (gameItem->isShadow(mouseEvent->scenePos() - gameItem->pos())) { 0255 gameItem = dynamic_cast<GameItem *>( 0256 itemAt(mouseEvent->scenePos().x() + gameItem->getShadowDeltaX(), 0257 mouseEvent->scenePos().y() + gameItem->getShadowDeltaY(), 0258 QTransform()) 0259 ); 0260 } 0261 } 0262 0263 // No item was clicked. 0264 if (gameItem == nullptr) { 0265 Q_EMIT clearSelectedTile(); 0266 mouseEvent->ignore(); 0267 return; 0268 } 0269 0270 // If the item is selectable go on with selection. 0271 if (isSelectable(gameItem)) { 0272 clearSelection(); 0273 gameItem->setSelected(true); 0274 mouseEvent->accept(); 0275 } else { 0276 Q_EMIT clearSelectedTile(); 0277 } 0278 } 0279 0280 void GameScene::wheelEvent(QGraphicsSceneWheelEvent * mouseEvent) 0281 { 0282 if (mouseEvent->delta() < 0) { 0283 Q_EMIT rotateCW(); 0284 } else { 0285 Q_EMIT rotateCCW(); 0286 } 0287 } 0288 0289 #include "moc_gamescene.cpp"