File indexing completed on 2024-10-13 03:43:41
0001 /* 0002 SPDX-FileCopyrightText: 2012 Ian Wadham <iandw.au@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 // TODO - Border tiles, display tiles. 0008 // TODO - Add attributes to theme: HasBorderTiles, HasDisplayTiles. 0009 0010 // KDEGames 0011 #include <KGameRenderedItem> 0012 #include <KGameThemeProvider> 0013 #include <KGameThemeSelector> 0014 // KF 0015 #include <KLocalizedString> 0016 0017 0018 #include "kgoldrunner_debug.h" 0019 #include "kgrglobals.h" 0020 #include "kgrthemetypes.h" 0021 #include "kgrrenderer.h" 0022 #include "kgrscene.h" 0023 0024 #include <cmath> 0025 0026 KGrRenderer::KGrRenderer (KGrScene * scene) 0027 : 0028 QObject (scene), 0029 m_scene (scene) 0030 { 0031 // Set up two theme providers: for the Set and the Actors. 0032 m_setProvider = new KGameThemeProvider("Theme", this); // Save config. 0033 m_actorsProvider = new KGameThemeProvider("", this); // Do not save. 0034 0035 // Find SVG files for the Set, i.e. tiles and backgrounds. 0036 const QMetaObject * setThemeClass = & KGrSetTheme::staticMetaObject; 0037 m_setProvider->discoverThemes (QStringLiteral ("themes"), 0038 QStringLiteral ("egypt"), setThemeClass); 0039 0040 // Find SVG files for the Actors, i.e. hero and enemies. 0041 const QMetaObject * actorsThemeClass = & KGrActorsTheme::staticMetaObject; 0042 m_actorsProvider->discoverThemes (QStringLiteral ("themes"), 0043 QStringLiteral ("egypt"), actorsThemeClass); 0044 0045 // Set up a dialog for selecting themes. 0046 m_themeSelector = new KGameThemeSelector (m_setProvider, 0047 KGameThemeSelector::DefaultBehavior, 0048 nullptr); // No parent: modeless dialog. 0049 0050 // Set up the renderer for the Set, i.e. tiles and backgrounds. 0051 m_setRenderer = new KGameRenderer (m_setProvider); 0052 m_setRenderer->setParent (this); 0053 m_setRenderer->setFrameSuffix (QStringLiteral("_%1")); 0054 m_setRenderer->setFrameBaseIndex (1); 0055 0056 // Set up the renderer for the Actors, i.e. hero and enemies. 0057 m_actorsRenderer = new KGameRenderer (m_actorsProvider); 0058 m_actorsRenderer->setParent (this); 0059 m_actorsRenderer->setFrameSuffix (QStringLiteral("_%1")); 0060 m_actorsRenderer->setFrameBaseIndex (1); 0061 0062 // Match the Actors SVG theme to the Set theme, whenever the theme changes. 0063 connect(m_setProvider, &KGameThemeProvider::currentThemeChanged, this, &KGrRenderer::currentThemeChanged); 0064 0065 // Match the starting SVG theme for the Actors to the one for the Set. 0066 matchThemes (m_setProvider->currentTheme()); 0067 } 0068 0069 KGrRenderer::~KGrRenderer() 0070 { 0071 delete m_themeSelector; 0072 } 0073 0074 void KGrRenderer::matchThemes (const KGameTheme * currentSetTheme) 0075 { 0076 // Start of game or change of theme: initialise the counts of pixmap keys. 0077 initPixmapKeys(); 0078 0079 const auto themes = m_actorsProvider->themes(); 0080 for (const KGameTheme * actorsTheme : themes) { 0081 if (actorsTheme->customData(QStringLiteral("Set")) == 0082 currentSetTheme->customData(QStringLiteral("Set"))) { 0083 m_actorsProvider->setCurrentTheme (actorsTheme); 0084 break; 0085 } 0086 } 0087 } 0088 0089 void KGrRenderer::currentThemeChanged (const KGameTheme* currentSetTheme) 0090 { 0091 //qCDebug(KGOLDRUNNER_LOG) << "KGrRenderer::currentThemeChanged()" << currentSetTheme->name(); 0092 0093 matchThemes (currentSetTheme); 0094 m_scene->changeTheme(); 0095 } 0096 0097 void KGrRenderer::selectTheme() 0098 { 0099 // Show the theme-selection dialog. 0100 m_themeSelector->showAsDialog (i18n("Theme Selector")); 0101 } 0102 0103 KGrRenderer::PixmapSpec KGrRenderer::keyTable [] = { 0104 {ENEMY, Actors, "enemy_1", "", -1, -2}, // For editor only. 0105 {HERO, Actors, "hero_1", "", -1, -2}, // For editor only. 0106 {CONCRETE, Set, "concrete", "-%1", 0, -2}, 0107 {BRICK, Set, "brick", "-%1", 0, -2}, 0108 {FBRICK, Set, "false_brick", "", -1, -2}, // For editor only. 0109 {HLADDER, Set, "hidden_ladder", "", -1, -2}, // For editor only. 0110 {LADDER, Set, "ladder", "-%1", 0, -2}, 0111 {NUGGET, Set, "gold", "-%1", 0, -2}, 0112 {BAR, Set, "bar", "-%1", 0, -2}, 0113 {BACKDROP, Set, "background", "%1", 0, -2}, 0114 {FREE, Set, "empty", "", -1, -2} // Must be last entry. 0115 }; 0116 0117 void KGrRenderer::initPixmapKeys() 0118 { 0119 // Set all pixmaps in keyTable[] as "not counted yet" (frameCount -2). 0120 int index = 0; 0121 do { 0122 keyTable[index].frameCount = -2; 0123 index++; 0124 } while (keyTable[index].picType != FREE); 0125 } 0126 0127 KGameRenderedItem * KGrRenderer::getTileItem 0128 (const char picType, KGameRenderedItem * currentTile) 0129 { 0130 if (currentTile) { 0131 // Remove the tile that was here before. 0132 m_scene->removeItem (currentTile); 0133 delete currentTile; 0134 } 0135 0136 int index; 0137 if ((picType == FREE) || ((index = findKeyTableIndex (picType)) < 0)) { 0138 return nullptr; // Empty place or missing type, so no KGameRenderedItem. 0139 } 0140 0141 // Get the pixmap key and use one of the two renderers to create the tile. 0142 QString key = getPixmapKey (index); 0143 KGameRenderedItem * tile = 0144 new KGameRenderedItem ((keyTable[index].picSource == Set) ? 0145 m_setRenderer : m_actorsRenderer, key); 0146 tile->setAcceptedMouseButtons (Qt::NoButton); 0147 m_scene->addItem (tile); 0148 return tile; 0149 } 0150 0151 KGrSprite * KGrRenderer::getSpriteItem (const char picType, const int tickTime) 0152 { 0153 int index = findKeyTableIndex (picType); 0154 if (index < 0) { 0155 return nullptr; // Missing type, so no KGrSprite item. 0156 } 0157 QString key = (picType == HERO) ? QStringLiteral("hero") : 0158 ((picType == ENEMY) ? QStringLiteral("enemy") : QStringLiteral("brick")); 0159 KGrSprite * sprite = new KGrSprite ((keyTable[index].picSource == Set) ? 0160 m_setRenderer : m_actorsRenderer, 0161 key, picType, tickTime); 0162 sprite->setAcceptedMouseButtons (Qt::NoButton); 0163 // We cannot add the sprite to the scene yet: it needs a frame and size. 0164 return sprite; 0165 } 0166 0167 KGameRenderedItem * KGrRenderer::getBackground 0168 (const int level, KGameRenderedItem * currentBackground) 0169 { 0170 if (currentBackground) { 0171 m_scene->removeItem (currentBackground); 0172 delete currentBackground; 0173 } 0174 0175 QString key = getBackgroundKey (level); 0176 KGameRenderedItem * background = new KGameRenderedItem (m_setRenderer, key); 0177 background->setAcceptedMouseButtons (Qt::NoButton); 0178 m_scene->addItem (background); 0179 0180 return background; 0181 } 0182 0183 KGameRenderedItem * KGrRenderer::getBorderItem 0184 (const QString &spriteKey, KGameRenderedItem * currentItem) 0185 { 0186 if (currentItem) { 0187 m_scene->removeItem (currentItem); 0188 delete currentItem; 0189 } 0190 0191 if (!hasBorder()) { 0192 return nullptr; 0193 } 0194 0195 KGameRenderedItem * item = new KGameRenderedItem (m_setRenderer, spriteKey); 0196 item->setAcceptedMouseButtons (Qt::NoButton); 0197 m_scene->addItem (item); 0198 return item; 0199 } 0200 0201 bool KGrRenderer::hasBorder() const 0202 { 0203 QString s = m_setRenderer->theme()->customData(QStringLiteral("DrawCanvasBorder"), QStringLiteral("0")); 0204 0205 if (s == QLatin1Char('1')) 0206 return true; 0207 else 0208 return false; 0209 } 0210 0211 QColor KGrRenderer::borderColor() const 0212 { 0213 QString s = m_setRenderer->theme()->customData(QStringLiteral("BorderColor"), QStringLiteral("#000000")); 0214 return QColor (s); 0215 } 0216 0217 QColor KGrRenderer::textColor() const 0218 { 0219 QString s = m_setRenderer->theme()->customData(QStringLiteral("TextColor"), QStringLiteral("#FFFFFF")); 0220 return QColor (s); 0221 } 0222 0223 QPixmap KGrRenderer::getPixmap (const char picType) 0224 { 0225 // Get the pixmap key and use one of the two renderers to create the tile. 0226 int index = findKeyTableIndex (picType); 0227 QString key = getPixmapKey (index); 0228 0229 if (keyTable[index].picSource == Set) 0230 return m_setRenderer->spritePixmap (key, m_scene->tileSize ()); 0231 else 0232 return m_actorsRenderer->spritePixmap (key, m_scene->tileSize ()); 0233 } 0234 0235 QString KGrRenderer::getPixmapKey (const int index) 0236 { 0237 QString pixmapKey; 0238 // int index = findKeyTableIndex (picType); 0239 int frameCount = (index < 0) ? -1 : keyTable[index].frameCount; 0240 if (frameCount > -1) { 0241 pixmapKey = QLatin1String(keyTable[index].picKey); // No suffix. 0242 if (frameCount > 0) { 0243 // Pick a random frame number and add it as a suffix. 0244 // Note: We are not worried about having a good seed for this. 0245 pixmapKey = pixmapKey + QLatin1String(keyTable[index].frameSuffix); 0246 pixmapKey = pixmapKey.arg (keyTable[index].frameBaseIndex + 0247 (rand() % frameCount)); 0248 } 0249 } 0250 return pixmapKey; 0251 } 0252 0253 QString KGrRenderer::getBackgroundKey (const int level) 0254 { 0255 QString pixmapKey; 0256 int index = findKeyTableIndex (BACKDROP); 0257 int frameCount = (index < 0) ? -1 : keyTable[index].frameCount; 0258 if (frameCount > -1) { 0259 pixmapKey = QLatin1String(keyTable[index].picKey); 0260 if (frameCount > 0) { 0261 // Cycle through available backgrounds as the game-level increases. 0262 pixmapKey = pixmapKey + QLatin1String(keyTable[index].frameSuffix); 0263 pixmapKey = pixmapKey.arg (level % frameCount); 0264 } 0265 } 0266 0267 //qCDebug(KGOLDRUNNER_LOG) << "BACKGROUND pixmap key" << pixmapKey; 0268 return pixmapKey; 0269 } 0270 0271 int KGrRenderer::findKeyTableIndex (const char picType) 0272 { 0273 int index = 0; 0274 while (true) { // Find ANY picType, including FREE. 0275 if (keyTable[index].picType == picType) { 0276 if (keyTable[index].frameCount == -2) { 0277 keyTable[index].frameCount = countFrames (index); 0278 } 0279 break; 0280 } 0281 else if (keyTable[index].picType == FREE) { 0282 index = -1; // Not found. 0283 break; 0284 } 0285 index++; 0286 } 0287 return index; 0288 } 0289 0290 int KGrRenderer::countFrames (const int index) 0291 { 0292 int count = -1; 0293 int frame = keyTable[index].frameBaseIndex; 0294 KGameRenderer * r = (keyTable[index].picSource == Set) ? m_setRenderer : 0295 m_actorsRenderer; 0296 if (r->spriteExists (QLatin1String(keyTable[index].picKey))) { 0297 count++; 0298 } 0299 0300 if ((count == 0) && (QLatin1String(keyTable[index].picKey) != QLatin1String("brick"))) { 0301 return count; 0302 } 0303 0304 if (frame < 0) { 0305 return count; // This element cannot have more than one frame. 0306 } 0307 0308 count = 0; 0309 QString pixmapKey = QLatin1String(keyTable[index].picKey) + 0310 QLatin1String(keyTable[index].frameSuffix); 0311 while (r->spriteExists (pixmapKey.arg (frame))) { 0312 count++; 0313 frame++; 0314 } 0315 0316 return count; 0317 } 0318 0319 #include "moc_kgrrenderer.cpp"