File indexing completed on 2023-09-24 04:19:10
0001 /* 0002 SPDX-FileCopyrightText: 1998-2001 Andreas Zehender <az@azweb.de> 0003 SPDX-FileCopyrightText: 2006-2007 Dirk Rathlev <dirkrathlev@gmx.de> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "mainview.h" 0009 #include "ai.h" 0010 #include "options.h" 0011 0012 #include <KActionCollection> 0013 #include <KConfigGroup> 0014 #include <KLocalizedString> 0015 #include <KSharedConfig> 0016 #include <KToggleAction> 0017 0018 #include <QAbstractEventDispatcher> 0019 #include <QBrush> 0020 #include <QFontDatabase> 0021 #include <QGraphicsSimpleTextItem> 0022 #include <QKeyEvent> 0023 #include <QKeySequence> 0024 #include <QResizeEvent> 0025 #include <QSvgRenderer> 0026 #include <QStandardPaths> 0027 0028 #include <math.h> 0029 0030 KToggleAction *MyMainView::pauseAction = nullptr; 0031 0032 static struct 0033 { 0034 int id; 0035 const char *path; 0036 } 0037 kspd_animations [] = 0038 { 0039 { ID_EXPLOSION, "explos%1"}, 0040 { ID_MINE1, "mine_red%1"}, 0041 { ID_MINE2, "mine_blue%1"}, 0042 { ID_MINEEXPLO, "mineex%1"}, 0043 { 0, nullptr} 0044 }; 0045 0046 MyMainView::MyMainView(QWidget *parent) 0047 :QWidget(parent), 0048 field(this),//0,0,DEF_WIDTH,DEF_HEIGHT), 0049 view(&field,this) 0050 { 0051 int i,p; 0052 setMinimumSize(600,400); 0053 random.seed(QRandomGenerator::global()->generate()); 0054 QPixmap backgr(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral(MV_BACKGROUND))); 0055 0056 field.setBackgroundBrush(QBrush(backgr)); 0057 view.setCacheMode(QGraphicsView::CacheBackground); 0058 0059 setFocusPolicy(Qt::StrongFocus); 0060 // FIXME: is this needed anymore? 0061 //view.setResizePolicy(Q3ScrollView::AutoOne); 0062 view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0063 view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0064 view.setFrameStyle(QFrame::NoFrame); 0065 0066 for(p=0;p<2;++p) 0067 { 0068 for(i=0;i<PlayerKeyNum;++i) 0069 playerKeyPressed[p][i]=false; 0070 bulletShot[p]=false; 0071 minePut[p]=false; 0072 } 0073 0074 svgrender = new QSvgRenderer(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral(MV_SVG_FILE))); 0075 0076 sun=new SunSprite(svgrender,QStringLiteral( MV_SUN )); 0077 field.addItem(sun); 0078 sun->setPos(QPointF(width()/2-1-(sun->width()/2), 0079 height()/2-1-(sun->height()/2))); 0080 0081 powerupelements[0] = QStringLiteral( MV_POWERMINE ); 0082 powerupelements[1] = QStringLiteral( MV_POWERBULLET ); 0083 powerupelements[2] = QStringLiteral( MV_POWERSHIELD ); 0084 powerupelements[3] = QStringLiteral( MV_POWERENERGY ); 0085 0086 ship[0]=new ShipSprite(svgrender, QStringLiteral( MV_SHIP1 ), 0); 0087 ship[1]=new ShipSprite(svgrender, QStringLiteral( MV_SHIP2 ), 1); 0088 field.addItem(ship[0]); 0089 field.addItem(ship[1]); 0090 0091 readSprites(); 0092 0093 for(i=0;i<2;++i) 0094 { 0095 // ship[i]->setBoundsAction(QwRealMobileSprite::Wrap); 0096 ship[i]->hide(); 0097 bullets[i]=new QList<BulletSprite*>; 0098 mines[i]=new QList<MineSprite*>; 0099 0100 } 0101 0102 waitForStart=false; 0103 textSprite = nullptr; 0104 readConfig(); 0105 } 0106 0107 MyMainView::~MyMainView() 0108 { 0109 int i; 0110 QAbstractEventDispatcher::instance()->unregisterTimers(this); 0111 0112 for(i=0;i<2;i++) 0113 { 0114 delete ai[i]; 0115 qDeleteAll(*mines[i]); 0116 delete mines[i]; 0117 qDeleteAll(*bullets[i]); 0118 delete bullets[i]; 0119 } 0120 0121 qDeleteAll(powerups); 0122 powerups.clear(); 0123 0124 qDeleteAll(explosions); 0125 explosions.clear(); 0126 0127 writeConfig(); 0128 delete svgrender; 0129 } 0130 0131 void MyMainView::setActionCollection(KActionCollection *a) 0132 { 0133 actionCollection = a; 0134 } 0135 0136 /* Assumes that there are no gaps between animation frames. ie 1,2,3 will only have frames 1&2 0137 recognized. It also assumes that there is at least one frame. */ 0138 // FIXME: Add Check for existence of first frame 0139 // TODO: Add support for missing frames (ie 1,2,5) 0140 bool MyMainView::readSprites() 0141 { 0142 int i = 0; 0143 while ( kspd_animations[i].id ) 0144 { 0145 QList<QString> anim; 0146 short frame = 0; 0147 QString element =QLatin1String( kspd_animations[i].path ); 0148 QString elem = element.arg(frame, 2, 10, QLatin1Char('0')); 0149 do 0150 { 0151 anim.append(elem); 0152 frame++; 0153 elem = element.arg(frame, 2, 10, QLatin1Char('0')); 0154 } while ( svgrender->elementExists(elem) ); 0155 animation.insert( kspd_animations[i].id, anim ); 0156 i++; 0157 } 0158 0159 // FIXME: Perform test! 0160 return true; 0161 } 0162 0163 void MyMainView::readConfig() 0164 { 0165 KConfigGroup game(KSharedConfig::openConfig(), "Game"); 0166 int i; 0167 0168 customConfig.gamespeed=game.readEntry("gamespeed", 0169 predefinedConfig[0].gamespeed); 0170 0171 customConfig.gravity= 0172 game.readEntry("gravity",predefinedConfig[0].gravity); 0173 customConfig.acc= 0174 game.readEntry("acceleration",predefinedConfig[0].acc); 0175 customConfig.bulletDamage= 0176 game.readEntry("bulletDamage",predefinedConfig[0].bulletDamage); 0177 customConfig.bulletLifeTime= 0178 game.readEntry("bulletLifeTime",predefinedConfig[0].bulletLifeTime); 0179 customConfig.bulletReloadTime= 0180 game.readEntry("bulletReloadTime",predefinedConfig[0].bulletReloadTime); 0181 customConfig.mineDamage= 0182 game.readEntry("mineDamage",predefinedConfig[0].mineDamage); 0183 customConfig.shipDamage= 0184 game.readEntry("shipDamage",predefinedConfig[0].shipDamage); 0185 customConfig.maxBullets= 0186 game.readEntry("maxBullets",predefinedConfig[0].maxBullets); 0187 customConfig.maxMines= 0188 game.readEntry("maxMines",predefinedConfig[0].maxMines); 0189 customConfig.mineReloadTime= 0190 game.readEntry("mineReloadTime",predefinedConfig[0].mineReloadTime); 0191 customConfig.rotationSpeed= 0192 game.readEntry("rotationSpeed",predefinedConfig[0].rotationSpeed); 0193 customConfig.shotSpeed= 0194 game.readEntry("shotSpeed",predefinedConfig[0].shotSpeed); 0195 customConfig.energyNeed= 0196 game.readEntry("accEnergyNeed",predefinedConfig[0].energyNeed); 0197 customConfig.rotationEnergyNeed= 0198 game.readEntry("rotationEnergyNeed",predefinedConfig[0].rotationEnergyNeed); 0199 customConfig.sunEnergy= 0200 game.readEntry("sunEnergy",predefinedConfig[0].sunEnergy); 0201 customConfig.mineActivateTime= 0202 game.readEntry("mineActivateTime",predefinedConfig[0].mineActivateTime); 0203 customConfig.mineFuel= 0204 game.readEntry("mineFuel",predefinedConfig[0].mineFuel); 0205 customConfig.shotEnergyNeed= 0206 game.readEntry("shotEnergyNeed",predefinedConfig[0].shotEnergyNeed); 0207 customConfig.mineEnergyNeed= 0208 game.readEntry("mineEnergyNeed",predefinedConfig[0].mineEnergyNeed); 0209 customConfig.startPosX= 0210 game.readEntry("startPosX",predefinedConfig[0].startPosX); 0211 customConfig.startPosY= 0212 game.readEntry("startPosY",predefinedConfig[0].startPosY); 0213 customConfig.startVelX= 0214 game.readEntry("startVelX",predefinedConfig[0].startVelX); 0215 customConfig.startVelY= 0216 game.readEntry("startVelY",predefinedConfig[0].startVelY); 0217 customConfig.powerupLifeTime= 0218 game.readEntry("powerupLifeTime",predefinedConfig[0].powerupLifeTime); 0219 customConfig.powerupRefreshTime= 0220 game.readEntry("powerupRefreshTime",predefinedConfig[0].powerupRefreshTime); 0221 customConfig.powerupShieldAmount= 0222 game.readEntry("powerupShieldAmount", 0223 predefinedConfig[0].powerupShieldAmount); 0224 customConfig.powerupEnergyAmount= 0225 game.readEntry("powerupEnergyAmount", 0226 predefinedConfig[0].powerupEnergyAmount); 0227 0228 if(Options::lastConfig() < predefinedConfigNum) 0229 config=modifyConfig(predefinedConfig[Options::lastConfig()]); 0230 else 0231 config=modifyConfig(customConfig); 0232 0233 for(i=0;i<2;++i) 0234 ai[i]=new Ai(i,ship,bullets,mines,&config); 0235 } 0236 0237 void MyMainView::writeConfig() 0238 { 0239 KConfigGroup game(KSharedConfig::openConfig(), "Game"); 0240 0241 game.writeEntry("gravity",customConfig.gravity); 0242 game.writeEntry("acceleration",customConfig.acc); 0243 game.writeEntry("bulletDamage",customConfig.bulletDamage); 0244 game.writeEntry("bulletLifeTime",customConfig.bulletLifeTime); 0245 game.writeEntry("bulletReloadTime",customConfig.bulletReloadTime); 0246 game.writeEntry("mineDamage",customConfig.mineDamage); 0247 game.writeEntry("shipDamage",customConfig.shipDamage); 0248 game.writeEntry("maxBullets",customConfig.maxBullets); 0249 game.writeEntry("maxMines",customConfig.maxMines); 0250 game.writeEntry("rotationSpeed",customConfig.rotationSpeed); 0251 game.writeEntry("shotSpeed",customConfig.shotSpeed); 0252 game.writeEntry("accEnergyNeed",customConfig.energyNeed); 0253 game.writeEntry("rotationEnergyNeed",customConfig.rotationEnergyNeed); 0254 game.writeEntry("sunEnergy",customConfig.sunEnergy); 0255 game.writeEntry("mineActivateTime",customConfig.mineActivateTime); 0256 game.writeEntry("mineReloadTime",customConfig.mineReloadTime); 0257 game.writeEntry("mineFuel",customConfig.mineFuel); 0258 game.writeEntry("shotEnergyNeed",customConfig.shotEnergyNeed); 0259 game.writeEntry("mineEnergyNeed",customConfig.mineEnergyNeed); 0260 0261 game.writeEntry("startPosX",customConfig.startPosX); 0262 game.writeEntry("startPosY",customConfig.startPosY); 0263 game.writeEntry("startVelX",customConfig.startVelX); 0264 game.writeEntry("startVelY",customConfig.startVelY); 0265 0266 game.writeEntry("powerupLifeTime",customConfig.powerupLifeTime); 0267 game.writeEntry("powerupRefreshTime",customConfig.powerupRefreshTime); 0268 game.writeEntry("powerupShieldAmount",customConfig.powerupShieldAmount); 0269 game.writeEntry("powerupEnergyAmount",customConfig.powerupEnergyAmount); 0270 } 0271 0272 SConfig MyMainView::modifyConfig(const SConfig &conf) 0273 { 0274 SConfig newConfig=conf; 0275 newConfig.gamespeed*=Options::refreshTime()/33.0; 0276 newConfig.acc*=newConfig.gamespeed; 0277 newConfig.rotationSpeed*=newConfig.gamespeed*M_PI/ROTNUM*4; 0278 newConfig.energyNeed*=newConfig.gamespeed; 0279 newConfig.rotationEnergyNeed*=newConfig.gamespeed; 0280 newConfig.mineActivateTime*=newConfig.gamespeed; 0281 0282 return newConfig; 0283 } 0284 0285 void MyMainView::keyPressEvent(QKeyEvent *ev) 0286 { 0287 // if-statement kept for historical reasons, maybe not needed anymore 0288 if ( ((gameEnd>0.0) || (gameEnd<=-2.0)) && (!waitForStart) ) 0289 { 0290 if(actionCollection->action(QStringLiteral( "P1KeyLeft" ))->shortcuts().contains(ev->key())) 0291 playerKeyPressed[0][PlayerKeyLeft]=true; 0292 else if(actionCollection->action(QStringLiteral( "P2KeyLeft" ))->shortcuts().contains(ev->key())) 0293 playerKeyPressed[1][PlayerKeyLeft]=true; 0294 0295 else if(actionCollection->action(QStringLiteral( "P1KeyRight" ))->shortcuts().contains(ev->key())) 0296 playerKeyPressed[0][PlayerKeyRight]=true; 0297 else if(actionCollection->action(QStringLiteral( "P2KeyRight" ))->shortcuts().contains(ev->key())) 0298 playerKeyPressed[1][PlayerKeyRight]=true; 0299 0300 else if(actionCollection->action(QStringLiteral( "P1KeyAcc" ))->shortcuts().contains(ev->key())) 0301 playerKeyPressed[0][PlayerKeyAcc]=true; 0302 else if(actionCollection->action(QStringLiteral( "P2KeyAcc" ))->shortcuts().contains(ev->key())) 0303 playerKeyPressed[1][PlayerKeyAcc]=true; 0304 0305 else if(actionCollection->action(QStringLiteral( "P1Shot" ))->shortcuts().contains(ev->key())) 0306 playerKeyPressed[0][PlayerKeyShot]=true; 0307 else if(actionCollection->action(QStringLiteral( "P2Shot" ))->shortcuts().contains(ev->key())) 0308 playerKeyPressed[1][PlayerKeyShot]=true; 0309 0310 else if(actionCollection->action(QStringLiteral( "P1Mine" ))->shortcuts().contains(ev->key())) 0311 playerKeyPressed[0][PlayerKeyMine]=true; 0312 else if(actionCollection->action(QStringLiteral( "P2Mine" ))->shortcuts().contains(ev->key())) 0313 playerKeyPressed[1][PlayerKeyMine]=true; 0314 else 0315 ev->ignore(); 0316 } 0317 } 0318 0319 void MyMainView::keyReleaseEvent(QKeyEvent *ev) 0320 { 0321 if(actionCollection->action(QStringLiteral( "P1KeyLeft" ))->shortcuts().contains(ev->key())) 0322 playerKeyPressed[0][PlayerKeyLeft]=false; 0323 else if(actionCollection->action(QStringLiteral( "P2KeyLeft" ))->shortcuts().contains(ev->key())) 0324 playerKeyPressed[1][PlayerKeyLeft]=false; 0325 0326 else if(actionCollection->action(QStringLiteral( "P1KeyRight" ))->shortcuts().contains(ev->key())) 0327 playerKeyPressed[0][PlayerKeyRight]=false; 0328 else if(actionCollection->action(QStringLiteral( "P2KeyRight" ))->shortcuts().contains(ev->key())) 0329 playerKeyPressed[1][PlayerKeyRight]=false; 0330 0331 else if(actionCollection->action(QStringLiteral( "P1KeyAcc" ))->shortcuts().contains(ev->key())) 0332 playerKeyPressed[0][PlayerKeyAcc]=false; 0333 else if(actionCollection->action(QStringLiteral( "P2KeyAcc" ))->shortcuts().contains(ev->key())) 0334 playerKeyPressed[1][PlayerKeyAcc]=false; 0335 0336 else if(actionCollection->action(QStringLiteral( "P1Shot" ))->shortcuts().contains(ev->key())) 0337 playerKeyPressed[0][PlayerKeyShot]=false; 0338 else if(actionCollection->action(QStringLiteral( "P2Shot" ))->shortcuts().contains(ev->key())) 0339 playerKeyPressed[1][PlayerKeyShot]=false; 0340 0341 else if(actionCollection->action(QStringLiteral( "P1Mine" ))->shortcuts().contains(ev->key())) 0342 playerKeyPressed[0][PlayerKeyMine]=false; 0343 else if(actionCollection->action(QStringLiteral( "P2Mine" ))->shortcuts().contains(ev->key())) 0344 playerKeyPressed[1][PlayerKeyMine]=false; 0345 else 0346 ev->ignore(); 0347 } 0348 0349 void MyMainView::pause() 0350 { 0351 if( !waitForStart ) 0352 { 0353 pauseAction->setChecked( true ); 0354 0355 waitForStart=true; 0356 QAbstractEventDispatcher::instance()->unregisterTimers(this); 0357 Q_EMIT setStatusText(i18n(" paused "), IDS_PAUSE); 0358 } 0359 } 0360 0361 void MyMainView::resume() 0362 { 0363 waitForStart=false; 0364 timerID=startTimer(Options::refreshTime()); 0365 Q_EMIT setStatusText(QLatin1String( "" ),IDS_PAUSE); 0366 Q_EMIT setStatusText(QLatin1String( "" ),IDS_MAIN); 0367 } 0368 0369 void MyMainView::start( ) 0370 { 0371 if( ( gameEnd <= 0.0 ) && ( gameEnd > -2.0 ) ) 0372 { 0373 newRound( ); 0374 } 0375 else if( waitForStart ) 0376 { 0377 waitForStart = false; 0378 timerID=startTimer(Options::refreshTime()); 0379 Q_EMIT setStatusText(QLatin1String( "" ),IDS_PAUSE); 0380 Q_EMIT setStatusText(QLatin1String( "" ),IDS_MAIN); 0381 pauseAction->setEnabled( true ); 0382 pauseAction->setChecked( false ); 0383 } 0384 } 0385 0386 void MyMainView::stop() 0387 { 0388 pauseAction->setEnabled( false ); 0389 pauseAction->setChecked( false ); 0390 0391 QAbstractEventDispatcher::instance()->unregisterTimers(this); 0392 waitForStart = true; 0393 } 0394 0395 void MyMainView::togglePause( ) 0396 { 0397 if( waitForStart ) 0398 resume( ); 0399 else 0400 pause( ); 0401 } 0402 0403 void MyMainView::resizeEvent(QResizeEvent *event) 0404 { 0405 double mx,my; 0406 int i,current; 0407 int listsize; // used for caching QtList::size() 0408 0409 mx=(event->size().width()-event->oldSize().width())/2.0; 0410 my=(event->size().height()-event->oldSize().height())/2.0; 0411 QWidget::resizeEvent(event); 0412 view.resize(width(),height()); 0413 field.setSceneRect(0, 0, width(),height()); 0414 0415 // printf("%d %d\n",field.width(),field.height()); 0416 0417 sun->setPos(QPointF(width()/2-1-(sun->width()/2), 0418 height()/2-1-(sun->height()/2))); 0419 0420 for(i=0;i<2;++i) 0421 { 0422 // ship[i]->adoptSpritefieldBounds(); 0423 ship[i]->moveBy(mx,my); 0424 0425 listsize = mines[i]->size(); 0426 for (current=0; current<listsize; ++current) 0427 { 0428 // mine->adoptSpritefieldBounds(); 0429 mines[i]->value(current)->moveBy(mx,my); 0430 } 0431 0432 listsize = bullets[i]->size(); 0433 for (current=0; current<listsize; ++current) 0434 { 0435 // bullet->adoptSpritefieldBounds(); 0436 bullets[i]->value(current)->moveBy(mx,my); 0437 } 0438 } 0439 if(textSprite) 0440 textSprite->moveBy((int)mx,(int)my); 0441 0442 listsize = powerups.size(); 0443 for (current=0; current<listsize; ++current) 0444 { 0445 powerups[current]->moveBy(mx,my); 0446 } 0447 } 0448 0449 void MyMainView::newRound() 0450 { 0451 double mx,my; 0452 int i; 0453 0454 timeToNextPowerup=random.bounded(config.powerupRefreshTime); 0455 qDeleteAll(powerups); 0456 powerups.clear(); 0457 0458 QAbstractEventDispatcher::instance()->unregisterTimers(this); 0459 mx=width()/2.0; 0460 my=height()/2.0; 0461 ship[0]->setPos(QPointF(mx+config.startPosX-(ship[0]->width()/2), 0462 my+config.startPosY-(ship[0]->height()/2))); 0463 ship[0]->setRotation(0.0); 0464 0465 ship[1]->setPos(QPointF(mx-config.startPosX-(ship[1]->width()/2), 0466 my-config.startPosY-(ship[1]->height()/2))); 0467 ship[1]->setRotation(M_PI); 0468 0469 ship[0]->setVelocity(config.startVelX,config.startVelY); 0470 ship[1]->setVelocity(-config.startVelX,-config.startVelY); 0471 for(i=0;i<2;++i) 0472 { 0473 ship[i]->show(); 0474 ship[i]->setEnergy(MAX_ENERGY); 0475 ship[i]->setHitPoints(Options::startHitPoints(i)); 0476 ship[i]->stop(false); 0477 ship[i]->setExplosion(-1); 0478 Q_EMIT energy(i,(int)ship[i]->getEnergy()); 0479 Q_EMIT hitPoints(i,ship[i]->getHitPoints()); 0480 bulletShot[i]=false; 0481 qDeleteAll(*bullets[i]); 0482 bullets[i]->clear(); 0483 0484 qDeleteAll(*mines[i]); 0485 mines[i]->clear(); 0486 0487 ship[i]->mine(0.0); 0488 ship[i]->bullet(0.0); 0489 ship[i]->setBulletPowerups(0); 0490 ship[i]->setMinePowerups(0); 0491 0492 ai[i]->newRound(); 0493 } 0494 qDeleteAll(explosions); 0495 explosions.clear(); 0496 gameEnd=-10.0; 0497 for(i=0;i<PlayerKeyNum;++i) 0498 { 0499 playerKeyPressed[0][i]=false; 0500 playerKeyPressed[1][i]=false; 0501 } 0502 if(textSprite) 0503 { 0504 textSprite->hide(); 0505 delete textSprite; 0506 textSprite = nullptr; 0507 } 0508 //field.update(); 0509 0510 QString str = i18n("Press %1 to start", 0511 actionCollection->action(QStringLiteral("game_start"))->shortcut().toString(QKeySequence::NativeText)); 0512 Q_EMIT setStatusText(str,IDS_MAIN); 0513 Q_EMIT setStatusText( QLatin1String( "" ), IDS_PAUSE ); 0514 stop( ); 0515 } 0516 0517 void MyMainView::newGame() 0518 { 0519 int i; 0520 for(i=0;i<2;i++) 0521 { 0522 ship[i]->setWins(0); 0523 Q_EMIT wins(i,0); 0524 } 0525 newRound(); 0526 } 0527 0528 void MyMainView::timerEvent(QTimerEvent *event) 0529 { 0530 unsigned w; 0531 int i; 0532 bool stopped = false; 0533 0534 if(event->timerId()==timerID) 0535 { 0536 QAbstractEventDispatcher::instance()->unregisterTimers(this); 0537 if(gameEnd>0.0) 0538 { 0539 gameEnd-=1.0; 0540 if(gameEnd<=0.0) 0541 { 0542 stopped = true; 0543 if(textSprite) 0544 { 0545 textSprite->hide(); 0546 delete textSprite; 0547 textSprite = nullptr; 0548 } 0549 textSprite = new QGraphicsSimpleTextItem(nullptr); 0550 field.addItem(textSprite); 0551 // FIXME 0552 // textSprite->setTextFlags(Qt::AlignCenter); 0553 textSprite->setBrush(QBrush(QColor(255,160,0))); 0554 textSprite->setFont(QFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont).family(),14)); 0555 textSprite->show( ); 0556 if(ship[0]->getHitPoints()==0) 0557 { 0558 if(ship[1]->getHitPoints()==0) 0559 textSprite->setText(i18n("draw round")); 0560 else 0561 { 0562 textSprite->setText(i18n("blue player won the round")); 0563 w=ship[1]->getWins()+1; 0564 ship[1]->setWins(w); 0565 Q_EMIT wins(1,w); 0566 } 0567 } 0568 else 0569 { 0570 textSprite->setText(i18n("red player won the round")); 0571 w=ship[0]->getWins()+1; 0572 ship[0]->setWins(w); 0573 Q_EMIT wins(0,w); 0574 } 0575 // must do this after setting text, because length is unknown until now 0576 textSprite->setPos(QPointF((width()-textSprite->boundingRect().width()) / 2,height()/2-90)); 0577 0578 QString str = i18n("Press %1 for new round", 0579 actionCollection->action(QStringLiteral("game_start"))->shortcut().toString(QKeySequence::NativeText)); 0580 Q_EMIT setStatusText(str,IDS_MAIN); 0581 stop( ); 0582 } 0583 } 0584 0585 if( !stopped ) 0586 { 0587 for(i=0;i<2;++i) 0588 if(Options::playerIsAi(i)&&(ship[i]->getHitPoints()>0)) 0589 ai[i]->think(); 0590 0591 moveMines(); 0592 moveBullets(); 0593 moveExplosions(); 0594 moveShips(); 0595 calculatePowerups(); 0596 collisions(); 0597 timerID=startTimer(Options::refreshTime()); 0598 } 0599 //field.update(); 0600 } 0601 } 0602 0603 void MyMainView::moveShips() 0604 { 0605 int i,olde; 0606 double nx,ny,en,nr; 0607 BulletSprite *bullet; 0608 MineSprite *mine; 0609 0610 0611 for(i=0;i<2;++i) 0612 { 0613 bool playerIsAi = Options::playerIsAi(i); 0614 olde=(int)ship[i]->getEnergy(); 0615 if(ship[i]->getHitPoints()==0) 0616 { 0617 ship[i]->forward(config.gamespeed); 0618 ship[i]->calculateGravityAndEnergy(config.gravity,config.sunEnergy, 0619 config.gamespeed); 0620 } 0621 else 0622 { 0623 ship[i]->calculateGravityAndEnergy(config.gravity,config.sunEnergy, 0624 config.gamespeed); 0625 0626 0627 if ((!playerIsAi && playerKeyPressed[i][PlayerKeyRight]) || 0628 (playerIsAi && ai[i]->rotateRight())) 0629 ship[i]->rotateRight(config.rotationEnergyNeed, 0630 config.rotationSpeed); 0631 0632 if ((!playerIsAi && playerKeyPressed[i][PlayerKeyLeft]) || 0633 (playerIsAi && ai[i]->rotateLeft())) 0634 ship[i]->rotateLeft(config.rotationEnergyNeed, 0635 config.rotationSpeed); 0636 0637 en=ship[i]->getEnergy(); 0638 nr=ship[i]->getRotation(); 0639 0640 nx=cos(nr); 0641 ny=sin(nr); 0642 if (((!playerIsAi && playerKeyPressed[i][PlayerKeyAcc]) || 0643 (playerIsAi && ai[i]->accelerate())) 0644 && (en>config.energyNeed) ) 0645 { 0646 en-=config.energyNeed; 0647 ship[i]->setVelocity(ship[i]->xVelocity()+nx*config.acc, 0648 ship[i]->yVelocity()-ny*config.acc); 0649 0650 // limit speed to avoid "tunneling" through other objects 0651 // FIXME: find a more elegant way 0652 if (ship[i]->xVelocity()*ship[i]->xVelocity()+ 0653 ship[i]->yVelocity()*ship[i]->yVelocity() > MAX_VELOCITY*MAX_VELOCITY) 0654 { 0655 double alpha; 0656 alpha = fabs(atan(ship[i]->yVelocity()/ship[i]->xVelocity())); 0657 ship[i]->setVelocity(MAX_VELOCITY*cos(alpha)*fabs(ship[i]->xVelocity())/ship[i]->xVelocity(), 0658 MAX_VELOCITY*sin(alpha)*fabs(ship[i]->yVelocity())/ship[i]->yVelocity()); 0659 } 0660 } 0661 if(en>MAX_ENERGY) 0662 en=MAX_ENERGY; 0663 0664 ship[i]->forward(config.gamespeed); 0665 0666 //Bullets and Mines 0667 if ((!playerIsAi && playerKeyPressed[i][PlayerKeyShot]) || 0668 (playerIsAi && ai[i]->shootBullet())) 0669 { 0670 if((en>config.shotEnergyNeed) && (!ship[i]->reloadsBullet())) 0671 { 0672 if(bullets[i]->count() < 0673 (static_cast<int>(config.maxBullets) + ship[i]->getBulletPowerups())) 0674 { 0675 ship[i]->bullet(config.bulletReloadTime); 0676 en-=config.shotEnergyNeed; 0677 if(i) 0678 bullet=new BulletSprite(svgrender, QStringLiteral( MV_BULLET2 ), i, 0679 config.bulletLifeTime); 0680 else 0681 bullet=new BulletSprite(svgrender, QStringLiteral( MV_BULLET1 ), i, 0682 config.bulletLifeTime); 0683 field.addItem(bullet); 0684 QPointF p; 0685 p = ship[i]->mapToScene(ship[i]->center()); 0686 bullet->setPos(QPointF(p.x()+nx*SHOTDIST,p.y()-ny*SHOTDIST)); 0687 bullet->setVelocity(ship[i]->xVelocity()+nx*config.shotSpeed, 0688 ship[i]->yVelocity()-ny*config.shotSpeed); 0689 // bullet->setBoundsAction(QwRealMobileSprite::Wrap); 0690 bullet->show(); 0691 bullets[i]->append(bullet); 0692 } 0693 } 0694 } 0695 if ((!Options::playerIsAi(i) && playerKeyPressed[i][PlayerKeyMine]) || 0696 (Options::playerIsAi(i) && ai[i]->layMine())) 0697 { 0698 if((en>config.mineEnergyNeed) && (!ship[i]->reloadsMine())) 0699 { 0700 if(mines[i]->count() < 0701 (static_cast<int>(config.maxMines) + ship[i]->getMinePowerups())) 0702 { 0703 ship[i]->mine(config.mineReloadTime); 0704 en-=config.mineEnergyNeed; 0705 if (i==0) 0706 mine=new MineSprite(svgrender,animation[ID_MINE1],animation[ID_MINEEXPLO],i, 0707 config.mineActivateTime,config.mineFuel); 0708 else 0709 mine=new MineSprite(svgrender,animation[ID_MINE2],animation[ID_MINEEXPLO],i, 0710 config.mineActivateTime,config.mineFuel); 0711 field.addItem(mine); 0712 mine->setPos(ship[i]->mapToScene(ship[i]->center())); 0713 // move mine to center 0714 mine->moveBy(-mine->center().x(),-mine->center().y()); 0715 mine->setVelocity(0,0); 0716 //mine->setBoundsAction(QwRealMobileSprite::Wrap); 0717 mine->show(); 0718 mines[i]->append(mine); 0719 } 0720 } 0721 } 0722 ship[i]->setEnergy(en); 0723 if(olde!=(int)en) 0724 Q_EMIT energy(i,(int)en); 0725 } 0726 } 0727 } 0728 0729 void MyMainView::moveMines() 0730 { 0731 int i; 0732 MineSprite* mine; 0733 int p; 0734 int listsize; // used for caching QtList::size() 0735 0736 for(p=0;p<2;p++) 0737 { 0738 i=0; 0739 listsize = mines[p]->size(); 0740 while (i<listsize) 0741 { 0742 mine = mines[p]->value(i); 0743 mine->calculateGravity(config.gravity,config.gamespeed); 0744 mine->forward(config.gamespeed); 0745 if(mine->over()) 0746 { 0747 mine->hide(); 0748 mines[p]->removeAt(i); 0749 delete mine; 0750 listsize--; 0751 } 0752 else 0753 i++; 0754 } 0755 } 0756 } 0757 0758 void MyMainView::moveBullets() 0759 { 0760 int i,j; 0761 BulletSprite *sp; 0762 int listsize; // used for caching QtList::size() 0763 0764 for(i=0;i<2;i++) 0765 { 0766 j=0; 0767 listsize = bullets[i]->size(); 0768 while (j<listsize) 0769 { 0770 sp = bullets[i]->value(j); 0771 sp->calculateGravity(config.gravity,config.gamespeed); 0772 sp->forward(config.gamespeed); 0773 if(sp->timeOut()) 0774 { 0775 sp->hide(); 0776 bullets[i]->removeAll(sp); 0777 listsize--; 0778 } 0779 else 0780 j++; 0781 } 0782 } 0783 } 0784 0785 void MyMainView::moveExplosions() 0786 { 0787 int i=0; 0788 ExplosionSprite *ex; 0789 int listsize; // used for caching QtList::size() 0790 listsize = explosions.size(); 0791 while (i<listsize) 0792 { 0793 ex = explosions[i]; 0794 ex->forward(config.gamespeed); 0795 if(ex->isOver()) 0796 { 0797 explosions.removeAt(i); 0798 delete ex; 0799 listsize--; 0800 } 0801 else 0802 i++; 0803 } 0804 } 0805 0806 void MyMainView::calculatePowerups() 0807 { 0808 int i=0; 0809 PowerupSprite *sp; 0810 int listsize; // used for caching QtList::size() 0811 listsize = powerups.size(); 0812 while (i<listsize) 0813 { 0814 sp = powerups[i]; 0815 sp->setLifetime(sp->getLifetime()-config.gamespeed); 0816 if (sp->getLifetime()<0) 0817 { 0818 powerups.removeAt(i); 0819 delete sp; 0820 listsize--; 0821 } 0822 else 0823 i++; 0824 } 0825 timeToNextPowerup-=config.gamespeed; 0826 if(timeToNextPowerup<0) 0827 { 0828 int type,x,y; 0829 timeToNextPowerup= random.bounded(config.powerupRefreshTime); 0830 type= random.bounded(PowerupSprite::PowerupNum); 0831 sp=new PowerupSprite(svgrender,powerupelements[type],type, 0832 config.powerupLifeTime); 0833 field.addItem(sp); 0834 do 0835 { 0836 x = random.bounded(width()-40)+20; 0837 y = random.bounded(height()-40)+20; 0838 } 0839 while(((x-width()/2)*(x-width()/2)+(y-height()/2)*(y-height()/2))<(50*50)); 0840 sp->setPos(QPointF(x,y)); 0841 powerups.append(sp); 0842 sp->show(); 0843 } 0844 } 0845 0846 void MyMainView::collisions() 0847 { 0848 int pl,hp,oldhp[2],ohp; 0849 QList<QGraphicsItem *> unexact; 0850 BulletSprite *bullet; 0851 MineSprite *mine; 0852 ExplosionSprite *expl; 0853 ShipSprite *s; 0854 PowerupSprite *power; 0855 QList<QGraphicsItem *> hitlist; 0856 double ndx[2],ndy[2]; 0857 double en; 0858 int i; 0859 int listsize; // used for caching QtList::size() 0860 0861 for(pl=0;pl<2;++pl) 0862 { 0863 if(!ship[pl]->isStopped()) 0864 { 0865 unexact.clear(); 0866 unexact = ship[pl]->collidingItems(Qt::IntersectsItemBoundingRect); 0867 oldhp[pl]=hp=ship[pl]->getHitPoints(); 0868 hitlist.clear(); 0869 for (QGraphicsItem *sprite : std::as_const(unexact)) { 0870 if((sprite->type()!=S_EXPLOSION) 0871 && !((sprite->type()!=S_SUN)&&(ship[pl]->getHitPoints()==0))) 0872 if(ship[pl]->collidesWithItem(sprite,Qt::IntersectsItemShape)) 0873 if(!hitlist.contains(sprite)) 0874 hitlist.append(sprite); 0875 } 0876 0877 for (QGraphicsItem *sprite : std::as_const(hitlist)) { 0878 switch(sprite->type()) 0879 { 0880 case S_SUN: 0881 hp=0; 0882 ship[pl]->stop(); 0883 break; 0884 case S_BULLET: 0885 bullet=(BulletSprite *)sprite; 0886 bullet->hide(); 0887 //bullets[bullet->getPlayerNumber()]->removeRef(bullet); 0888 bullets[bullet->getPlayerNumber()]->removeAll(bullet); 0889 delete bullet; 0890 hp-=config.bulletDamage; 0891 break; 0892 case S_SHIP: 0893 s=(ShipSprite*)sprite; 0894 ohp=s->getHitPoints(); 0895 if(ohp>0) 0896 { 0897 s->setHitPoints(ohp-hp-config.shipDamage); 0898 Q_EMIT hitPoints(s->getPlayerNumber(),s->getHitPoints()); 0899 ndx[0]=((1-EPSILON)*ship[0]->xVelocity()+(1+EPSILON)*ship[1]->xVelocity())/2.0; 0900 ndy[0]=((1-EPSILON)*ship[0]->yVelocity()+(1+EPSILON)*ship[1]->yVelocity())/2.0; 0901 ndx[1]=((1-EPSILON)*ship[1]->xVelocity()+(1+EPSILON)*ship[0]->xVelocity())/2.0; 0902 ndy[1]=((1-EPSILON)*ship[1]->yVelocity()+(1+EPSILON)*ship[0]->yVelocity())/2.0; 0903 ship[0]->setVelocity(ndx[0],ndy[0]); 0904 ship[1]->setVelocity(ndx[1],ndy[1]); 0905 hp-=ohp+config.shipDamage; 0906 } 0907 break; 0908 case S_MINE: 0909 mine=(MineSprite *)sprite; 0910 if(mine->isActive()&& !mine->explodes()) 0911 { 0912 mine->explode(); 0913 ndx[0]=(ship[pl]->xVelocity()+0.3*mine->xVelocity())/1.3; 0914 ndy[0]=(ship[pl]->yVelocity()+0.3*mine->yVelocity())/1.3; 0915 ship[pl]->setVelocity(ndx[0],ndy[0]); 0916 mine->setVelocity(ndx[0],ndy[0]); 0917 hp-=config.mineDamage; 0918 } 0919 break; 0920 case S_POWERUP: 0921 power=(PowerupSprite *)sprite; 0922 switch(power->getType()) 0923 { 0924 case PowerupSprite::PowerupShield: 0925 hp+=config.powerupShieldAmount; 0926 break; 0927 case PowerupSprite::PowerupEnergy: 0928 en=ship[pl]->getEnergy()+config.powerupEnergyAmount; 0929 if(en>MAX_ENERGY) 0930 en=MAX_ENERGY; 0931 ship[pl]->setEnergy(en); 0932 break; 0933 case PowerupSprite::PowerupMine: 0934 ship[pl]->setMinePowerups( 0935 ship[pl]->getMinePowerups()+1); 0936 break; 0937 case PowerupSprite::PowerupBullet: 0938 ship[pl]->setBulletPowerups( 0939 ship[pl]->getMinePowerups()+1); 0940 break; 0941 } 0942 power->hide(); 0943 powerups.removeAll(power); 0944 delete power; 0945 break; 0946 } 0947 } 0948 if(hp>MAX_HP) 0949 hp=MAX_HP; 0950 ship[pl]->setHitPoints(hp); 0951 } 0952 0953 listsize = mines[pl]->size(); 0954 for (i=0; i<listsize; ++i) 0955 { 0956 mine = mines[pl]->value(i); 0957 if(!mine->explodes()) 0958 { 0959 unexact.clear(); 0960 unexact=mine->collidingItems(Qt::IntersectsItemBoundingRect); 0961 hitlist.clear(); 0962 for (QGraphicsItem *sprite : std::as_const(unexact)) { 0963 if(sprite->type()==S_BULLET) 0964 if(mine->collidesWithItem(sprite)) 0965 if(!hitlist.contains(sprite)) 0966 hitlist.append(sprite); 0967 } 0968 if(!hitlist.isEmpty()) 0969 { 0970 mine->explode(); 0971 for (QGraphicsItem *item : std::as_const(hitlist)) { 0972 // FIXME: why does it crash with qgraphicsitem_cast? 0973 bullet = static_cast<BulletSprite*>(item);// qgraphicsitem_cast<BulletSprite*>(item); 0974 // bullets[bullet->getPlayerNumber()]->removeRef(bullet); 0975 bullets[bullet->getPlayerNumber()]->removeAll(bullet); 0976 delete bullet; 0977 } 0978 } 0979 } 0980 } 0981 } 0982 0983 hitlist.clear(); 0984 unexact.clear(); 0985 unexact=sun->collidingItems(Qt::IntersectsItemBoundingRect); 0986 for (QGraphicsItem *sprite : std::as_const(unexact)) { 0987 switch(sprite->type()) 0988 { 0989 case S_BULLET: 0990 if(sun->collidesWithItem(sprite)) 0991 if(!hitlist.contains(sprite)) 0992 hitlist.append(sprite); 0993 break; 0994 case S_MINE: 0995 if(!((MobileSprite*)sprite)->isStopped()) 0996 if(sun->collidesWithItem(sprite)) 0997 if(!hitlist.contains(sprite)) 0998 hitlist.append(sprite); 0999 break; 1000 } 1001 } 1002 1003 for (QGraphicsItem *sprite : std::as_const(hitlist)) { 1004 switch(sprite->type()) 1005 { 1006 case S_BULLET: 1007 bullet=(BulletSprite *)sprite; 1008 bullet->hide(); 1009 bullets[bullet->getPlayerNumber()]->removeAll(bullet); 1010 delete bullet; 1011 break; 1012 case S_MINE: 1013 mine=(MineSprite*)sprite; 1014 mine->stop(); 1015 if(!mine->explodes()) 1016 mine->explode(); 1017 break; 1018 } 1019 } 1020 1021 1022 for(pl=0;pl<2;++pl) 1023 { 1024 hp=ship[pl]->getHitPoints(); 1025 if(hp!=oldhp[pl]) 1026 Q_EMIT hitPoints(pl,hp); 1027 if((hp==0)&&(ship[pl]->getExplosion()<0)) 1028 { 1029 ship[pl]->setExplosion((int)(EXPLOSION_TIME/config.gamespeed)); 1030 expl = new ExplosionSprite(svgrender,animation[ID_EXPLOSION],ship[pl]); 1031 field.addItem(expl); 1032 expl->show(); 1033 explosions.append(expl); 1034 gameEnd=Options::timeAfterKill()/config.gamespeed; 1035 } 1036 } 1037 } 1038 1039 void MyMainView::gameSetup() 1040 { 1041 if(!waitForStart) 1042 pause(); 1043 1044 if (KConfigDialog::showDialog( QStringLiteral( "settings" ))) 1045 return; 1046 1047 SettingsDialog *settings=new SettingsDialog(&customConfig,this,"settings"); 1048 connect(settings, &SettingsDialog::settingsUpdated, this, &MyMainView::closeSettings); 1049 settings->show(); 1050 } 1051 1052 void MyMainView::closeSettings(){ 1053 if(Options::lastConfig()<predefinedConfigNum) 1054 config=modifyConfig(predefinedConfig[Options::lastConfig()]); 1055 else 1056 config=modifyConfig(customConfig); 1057 } 1058 1059 void MyMainView::focusOutEvent (QFocusEvent * /*event*/) 1060 { 1061 /* FIXME: ugly hack, I think 1062 it's maybe better to declare something like QMyScene:public QGraphicsScene and process input there */ 1063 setFocus(Qt::OtherFocusReason); 1064 } 1065 1066 #include "moc_mainview.cpp"