SVN_SILENT made messages (.desktop file)
[kdegames.git] / kspaceduel / mainview.cpp
bloba616faccfe494fb4ec7df11f61f6b2c1ae5988fe
1 /*
2 Copyright (C) 1998-2001 Andreas Zehender <az@azweb.de>
3 Copyright (C) 2006-2007 Dirk Rathlev <dirkrathlev@gmx.de>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "mainview.h"
22 #include <math.h>
24 #include <QAbstractEventDispatcher>
25 #include <QBrush>
26 #include <QGraphicsSimpleTextItem>
27 #include <QKeyEvent>
28 #include <QResizeEvent>
29 #include <QTimerEvent>
31 #include <kaction.h>
32 #include <kactioncollection.h>
33 #include <kglobalsettings.h>
34 #include <klocale.h>
35 #include <kstandarddirs.h>
36 #include <ktoggleaction.h>
37 #include <kconfiggroup.h>
39 #include <KSvgRenderer>
41 #include "ai.h"
42 #include "options.h"
44 KToggleAction *MyMainView::pauseAction = 0;
46 static struct
48 int id;
49 const char *path;
51 kspd_animations [] =
53 { ID_EXPLOSION, "explos%1"},
54 { ID_MINE1, "mine_red%1"},
55 { ID_MINE2, "mine_blue%1"},
56 { ID_MINEEXPLO, "mineex%1"},
57 { 0, 0}
60 MyMainView::MyMainView(QWidget *parent)
61 :QWidget(parent),
62 field(this),//0,0,DEF_WIDTH,DEF_HEIGHT),
63 view(&field,this)
65 int i,p;
66 setMinimumSize(600,400);
67 random.setSeed(0);
68 QPixmap backgr(KStandardDirs::locate("appdata", MV_BACKGROUND));
70 field.setBackgroundBrush(QBrush(backgr));
71 view.setCacheMode(QGraphicsView::CacheBackground);
73 setFocusPolicy(Qt::StrongFocus);
74 // FIXME: is this needed anymore?
75 //view.setResizePolicy(Q3ScrollView::AutoOne);
76 view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
77 view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
78 view.setFrameStyle(QFrame::NoFrame);
80 for(p=0;p<2;p++)
82 for(i=0;i<PlayerKeyNum;i++)
83 playerKeyPressed[p][i]=false;
84 bulletShot[p]=false;
85 minePut[p]=false;
88 svgrender = new KSvgRenderer(KStandardDirs::locate("appdata", MV_SVG_FILE));
90 sun=new SunSprite(svgrender, MV_SUN);
91 field.addItem(sun);
92 sun->setPos(QPointF(width()/2-1-(sun->width()/2),
93 height()/2-1-(sun->height()/2)));
95 powerupelements[0] = MV_POWERMINE;
96 powerupelements[1] = MV_POWERBULLET;
97 powerupelements[2] = MV_POWERSHIELD;
98 powerupelements[3] = MV_POWERENERGY;
100 ship[0]=new ShipSprite(svgrender, MV_SHIP1, 0);
101 ship[1]=new ShipSprite(svgrender, MV_SHIP2, 1);
102 field.addItem(ship[0]);
103 field.addItem(ship[1]);
105 readSprites();
107 for(i=0;i<2;i++)
109 // ship[i]->setBoundsAction(QwRealMobileSprite::Wrap);
110 ship[i]->hide();
111 bullets[i]=new QList<BulletSprite*>;
112 mines[i]=new QList<MineSprite*>;
116 waitForStart=false;
117 textSprite=0;
118 readConfig();
121 MyMainView::~MyMainView()
123 int i;
124 QAbstractEventDispatcher::instance()->unregisterTimers(this);
126 for(i=0;i<2;i++)
128 delete ai[i];
129 qDeleteAll(*mines[i]);
130 delete mines[i];
131 qDeleteAll(*bullets[i]);
132 delete bullets[i];
135 qDeleteAll(powerups);
136 powerups.clear();
138 qDeleteAll(explosions);
139 explosions.clear();
141 writeConfig();
142 delete svgrender;
145 void MyMainView::setActionCollection(KActionCollection *a)
147 actionCollection = a;
150 /* Assumes that there are no gaps between animation frames. ie 1,2,3 will only have frames 1&2
151 recognized. It also assumes that there is at least one frame. */
152 // FIXME: Add Check for existence of first frame
153 // TODO: Add support for missing frames (ie 1,2,5)
154 bool MyMainView::readSprites()
156 int i = 0;
157 while ( kspd_animations[i].id )
159 QList<QString> anim;
160 short frame = 0;
161 QString element = kspd_animations[i].path;
162 QString elem = element.arg(frame, 2, 10, QLatin1Char('0'));
165 anim.append(elem);
166 frame++;
167 elem = element.arg(frame, 2, 10, QLatin1Char('0'));
168 } while ( svgrender->elementExists(elem) );
169 animation.insert( kspd_animations[i].id, anim );
170 i++;
173 // FIXME: Perform test!
174 return true;
177 void MyMainView::readConfig()
179 KConfigGroup game(KGlobal::config(), "Game");
180 int i;
182 customConfig.gamespeed=game.readEntry("gamespeed",
183 predefinedConfig[0].gamespeed);
185 customConfig.gravity=
186 game.readEntry("gravity",predefinedConfig[0].gravity);
187 customConfig.acc=
188 game.readEntry("acceleration",predefinedConfig[0].acc);
189 customConfig.bulletDamage=
190 game.readEntry("bulletDamage",predefinedConfig[0].bulletDamage);
191 customConfig.bulletLifeTime=
192 game.readEntry("bulletLifeTime",predefinedConfig[0].bulletLifeTime);
193 customConfig.bulletReloadTime=
194 game.readEntry("bulletReloadTime",predefinedConfig[0].bulletReloadTime);
195 customConfig.mineDamage=
196 game.readEntry("mineDamage",predefinedConfig[0].mineDamage);
197 customConfig.shipDamage=
198 game.readEntry("shipDamage",predefinedConfig[0].shipDamage);
199 customConfig.maxBullets=
200 game.readEntry("maxBullets",predefinedConfig[0].maxBullets);
201 customConfig.maxMines=
202 game.readEntry("maxMines",predefinedConfig[0].maxMines);
203 customConfig.mineReloadTime=
204 game.readEntry("mineReloadTime",predefinedConfig[0].mineReloadTime);
205 customConfig.rotationSpeed=
206 game.readEntry("rotationSpeed",predefinedConfig[0].rotationSpeed);
207 customConfig.shotSpeed=
208 game.readEntry("shotSpeed",predefinedConfig[0].shotSpeed);
209 customConfig.energyNeed=
210 game.readEntry("accEnergyNeed",predefinedConfig[0].energyNeed);
211 customConfig.rotationEnergyNeed=
212 game.readEntry("rotationEnergyNeed",predefinedConfig[0].rotationEnergyNeed);
213 customConfig.sunEnergy=
214 game.readEntry("sunEnergy",predefinedConfig[0].sunEnergy);
215 customConfig.mineActivateTime=
216 game.readEntry("mineActivateTime",predefinedConfig[0].mineActivateTime);
217 customConfig.mineFuel=
218 game.readEntry("mineFuel",predefinedConfig[0].mineFuel);
219 customConfig.shotEnergyNeed=
220 game.readEntry("shotEnergyNeed",predefinedConfig[0].shotEnergyNeed);
221 customConfig.mineEnergyNeed=
222 game.readEntry("mineEnergyNeed",predefinedConfig[0].mineEnergyNeed);
223 customConfig.startPosX=
224 game.readEntry("startPosX",predefinedConfig[0].startPosX);
225 customConfig.startPosY=
226 game.readEntry("startPosY",predefinedConfig[0].startPosY);
227 customConfig.startVelX=
228 game.readEntry("startVelX",predefinedConfig[0].startVelX);
229 customConfig.startVelY=
230 game.readEntry("startVelY",predefinedConfig[0].startVelY);
231 customConfig.powerupLifeTime=
232 game.readEntry("powerupLifeTime",predefinedConfig[0].powerupLifeTime);
233 customConfig.powerupRefreshTime=
234 game.readEntry("powerupRefreshTime",predefinedConfig[0].powerupRefreshTime);
235 customConfig.powerupShieldAmount=
236 game.readEntry("powerupShieldAmount",
237 predefinedConfig[0].powerupShieldAmount);
238 customConfig.powerupEnergyAmount=
239 game.readEntry("powerupEnergyAmount",
240 predefinedConfig[0].powerupEnergyAmount);
242 if(Options::lastConfig() < predefinedConfigNum)
243 config=modifyConfig(predefinedConfig[Options::lastConfig()]);
244 else
245 config=modifyConfig(customConfig);
247 for(i=0;i<2;i++)
248 ai[i]=new Ai(i,ship,bullets,mines,&config);
251 void MyMainView::writeConfig()
253 KConfigGroup game(KGlobal::config(), "Game");
255 game.writeEntry("gravity",customConfig.gravity);
256 game.writeEntry("acceleration",customConfig.acc);
257 game.writeEntry("bulletDamage",customConfig.bulletDamage);
258 game.writeEntry("bulletLifeTime",customConfig.bulletLifeTime);
259 game.writeEntry("bulletReloadTime",customConfig.bulletReloadTime);
260 game.writeEntry("mineDamage",customConfig.mineDamage);
261 game.writeEntry("shipDamage",customConfig.shipDamage);
262 game.writeEntry("maxBullets",customConfig.maxBullets);
263 game.writeEntry("maxMines",customConfig.maxMines);
264 game.writeEntry("rotationSpeed",customConfig.rotationSpeed);
265 game.writeEntry("shotSpeed",customConfig.shotSpeed);
266 game.writeEntry("accEnergyNeed",customConfig.energyNeed);
267 game.writeEntry("rotationEnergyNeed",customConfig.rotationEnergyNeed);
268 game.writeEntry("sunEnergy",customConfig.sunEnergy);
269 game.writeEntry("mineActivateTime",customConfig.mineActivateTime);
270 game.writeEntry("mineReloadTime",customConfig.mineReloadTime);
271 game.writeEntry("mineFuel",customConfig.mineFuel);
272 game.writeEntry("shotEnergyNeed",customConfig.shotEnergyNeed);
273 game.writeEntry("mineEnergyNeed",customConfig.mineEnergyNeed);
275 game.writeEntry("startPosX",customConfig.startPosX);
276 game.writeEntry("startPosY",customConfig.startPosY);
277 game.writeEntry("startVelX",customConfig.startVelX);
278 game.writeEntry("startVelY",customConfig.startVelY);
280 game.writeEntry("powerupLifeTime",customConfig.powerupLifeTime);
281 game.writeEntry("powerupRefreshTime",customConfig.powerupRefreshTime);
282 game.writeEntry("powerupShieldAmount",customConfig.powerupShieldAmount);
283 game.writeEntry("powerupEnergyAmount",customConfig.powerupEnergyAmount);
286 SConfig MyMainView::modifyConfig(SConfig conf)
288 SConfig newConfig=conf;
289 newConfig.gamespeed*=Options::refreshTime()/33.0;
290 newConfig.acc*=newConfig.gamespeed;
291 newConfig.rotationSpeed*=newConfig.gamespeed*M_PI/ROTNUM*4;
292 newConfig.energyNeed*=newConfig.gamespeed;
293 newConfig.rotationEnergyNeed*=newConfig.gamespeed;
294 newConfig.mineActivateTime*=newConfig.gamespeed;
296 return newConfig;
299 void MyMainView::keyPressEvent(QKeyEvent *ev)
301 // if-statement kept for historical reasons, maybe not needed anymore
302 if ( ((gameEnd>0.0) || (gameEnd<=-2.0)) && (!waitForStart) )
304 if(actionCollection->action("P1KeyLeft")->shortcuts().contains(ev->key()))
305 playerKeyPressed[0][PlayerKeyLeft]=true;
306 else if(actionCollection->action("P2KeyLeft")->shortcuts().contains(ev->key()))
307 playerKeyPressed[1][PlayerKeyLeft]=true;
309 else if(actionCollection->action("P1KeyRight")->shortcuts().contains(ev->key()))
310 playerKeyPressed[0][PlayerKeyRight]=true;
311 else if(actionCollection->action("P2KeyRight")->shortcuts().contains(ev->key()))
312 playerKeyPressed[1][PlayerKeyRight]=true;
314 else if(actionCollection->action("P1KeyAcc")->shortcuts().contains(ev->key()))
315 playerKeyPressed[0][PlayerKeyAcc]=true;
316 else if(actionCollection->action("P2KeyAcc")->shortcuts().contains(ev->key()))
317 playerKeyPressed[1][PlayerKeyAcc]=true;
319 else if(actionCollection->action("P1Shot")->shortcuts().contains(ev->key()))
320 playerKeyPressed[0][PlayerKeyShot]=true;
321 else if(actionCollection->action("P2Shot")->shortcuts().contains(ev->key()))
322 playerKeyPressed[1][PlayerKeyShot]=true;
324 else if(actionCollection->action("P1Mine")->shortcuts().contains(ev->key()))
325 playerKeyPressed[0][PlayerKeyMine]=true;
326 else if(actionCollection->action("P2Mine")->shortcuts().contains(ev->key()))
327 playerKeyPressed[1][PlayerKeyMine]=true;
328 else
329 ev->ignore();
333 void MyMainView::keyReleaseEvent(QKeyEvent *ev)
335 if(actionCollection->action("P1KeyLeft")->shortcuts().contains(ev->key()))
336 playerKeyPressed[0][PlayerKeyLeft]=false;
337 else if(actionCollection->action("P2KeyLeft")->shortcuts().contains(ev->key()))
338 playerKeyPressed[1][PlayerKeyLeft]=false;
340 else if(actionCollection->action("P1KeyRight")->shortcuts().contains(ev->key()))
341 playerKeyPressed[0][PlayerKeyRight]=false;
342 else if(actionCollection->action("P2KeyRight")->shortcuts().contains(ev->key()))
343 playerKeyPressed[1][PlayerKeyRight]=false;
345 else if(actionCollection->action("P1KeyAcc")->shortcuts().contains(ev->key()))
346 playerKeyPressed[0][PlayerKeyAcc]=false;
347 else if(actionCollection->action("P2KeyAcc")->shortcuts().contains(ev->key()))
348 playerKeyPressed[1][PlayerKeyAcc]=false;
350 else if(actionCollection->action("P1Shot")->shortcuts().contains(ev->key()))
351 playerKeyPressed[0][PlayerKeyShot]=false;
352 else if(actionCollection->action("P2Shot")->shortcuts().contains(ev->key()))
353 playerKeyPressed[1][PlayerKeyShot]=false;
355 else if(actionCollection->action("P1Mine")->shortcuts().contains(ev->key()))
356 playerKeyPressed[0][PlayerKeyMine]=false;
357 else if(actionCollection->action("P2Mine")->shortcuts().contains(ev->key()))
358 playerKeyPressed[1][PlayerKeyMine]=false;
359 else
360 ev->ignore();
363 void MyMainView::pause()
365 if( !waitForStart )
367 pauseAction->setChecked( true );
369 waitForStart=true;
370 QAbstractEventDispatcher::instance()->unregisterTimers(this);
371 emit setStatusText(i18n(" paused "), IDS_PAUSE);
375 void MyMainView::resume()
377 waitForStart=false;
378 timerID=startTimer(Options::refreshTime());
379 emit(setStatusText("",IDS_PAUSE));
380 emit(setStatusText("",IDS_MAIN));
383 void MyMainView::start( )
385 if( ( gameEnd <= 0.0 ) && ( gameEnd > -2.0 ) )
387 newRound( );
389 else if( waitForStart )
391 waitForStart = false;
392 timerID=startTimer(Options::refreshTime());
393 emit(setStatusText("",IDS_PAUSE));
394 emit(setStatusText("",IDS_MAIN));
395 pauseAction->setEnabled( true );
396 pauseAction->setChecked( false );
400 void MyMainView::stop()
402 pauseAction->setEnabled( false );
403 pauseAction->setChecked( false );
405 QAbstractEventDispatcher::instance()->unregisterTimers(this);
406 waitForStart = true;
409 void MyMainView::togglePause( )
411 if( waitForStart )
412 resume( );
413 else
414 pause( );
417 void MyMainView::resizeEvent(QResizeEvent *event)
419 double mx,my;
420 int i,current;
421 int listsize; // used for caching QtList::size()
423 mx=(event->size().width()-event->oldSize().width())/2.0;
424 my=(event->size().height()-event->oldSize().height())/2.0;
425 QWidget::resizeEvent(event);
426 view.resize(width(),height());
427 field.setSceneRect(0, 0, width(),height());
429 // printf("%d %d\n",field.width(),field.height());
431 sun->setPos(QPointF(width()/2-1-(sun->width()/2),
432 height()/2-1-(sun->height()/2)));
434 for(i=0;i<2;i++)
436 // ship[i]->adoptSpritefieldBounds();
437 ship[i]->moveBy(mx,my);
439 listsize = mines[i]->size();
440 for (current=0; current<listsize; current++)
442 // mine->adoptSpritefieldBounds();
443 mines[i]->value(current)->moveBy(mx,my);
446 listsize = bullets[i]->size();
447 for (current=0; current<listsize; current++)
449 // bullet->adoptSpritefieldBounds();
450 bullets[i]->value(current)->moveBy(mx,my);
453 if(textSprite)
454 textSprite->moveBy((int)mx,(int)my);
456 listsize = powerups.size();
457 for (current=0; current<listsize; current++)
459 powerups[current]->moveBy(mx,my);
463 void MyMainView::newRound()
465 double mx,my;
466 int i;
468 timeToNextPowerup=random.getDouble() * config.powerupRefreshTime;
469 qDeleteAll(powerups);
470 powerups.clear();
472 QAbstractEventDispatcher::instance()->unregisterTimers(this);
473 mx=width()/2.0;
474 my=height()/2.0;
475 ship[0]->setPos(QPointF(mx+config.startPosX-(ship[0]->width()/2),
476 my+config.startPosY-(ship[0]->height()/2)));
477 ship[0]->setRotation(0.0);
479 ship[1]->setPos(QPointF(mx-config.startPosX-(ship[1]->width()/2),
480 my-config.startPosY-(ship[1]->height()/2)));
481 ship[1]->setRotation(M_PI);
483 ship[0]->setVelocity(config.startVelX,config.startVelY);
484 ship[1]->setVelocity(-config.startVelX,-config.startVelY);
485 for(i=0;i<2;i++)
487 ship[i]->show();
488 ship[i]->setEnergy(MAX_ENERGY);
489 ship[i]->setHitPoints(Options::startHitPoints(i));
490 ship[i]->stop(false);
491 ship[i]->setExplosion(-1);
492 emit(energy(i,(int)ship[i]->getEnergy()));
493 emit(hitPoints(i,ship[i]->getHitPoints()));
494 bulletShot[i]=false;
495 qDeleteAll(*bullets[i]);
496 bullets[i]->clear();
498 qDeleteAll(*mines[i]);
499 mines[i]->clear();
501 ship[i]->mine(0.0);
502 ship[i]->bullet(0.0);
503 ship[i]->setBulletPowerups(0);
504 ship[i]->setMinePowerups(0);
506 ai[i]->newRound();
508 qDeleteAll(explosions);
509 explosions.clear();
510 gameEnd=-10.0;
511 for(i=0;i<PlayerKeyNum;i++)
513 playerKeyPressed[0][i]=false;
514 playerKeyPressed[1][i]=false;
516 if(textSprite)
518 textSprite->hide();
519 delete textSprite;
520 textSprite=0;
522 //field.update();
524 QString str = i18n("Press %1 to start",
525 KShortcut(GAME_START_SHORTCUT).primary().toString(QKeySequence::NativeText));
526 emit(setStatusText(str,IDS_MAIN));
527 emit(setStatusText( "", IDS_PAUSE ));
528 stop( );
531 void MyMainView::newGame()
533 int i;
534 for(i=0;i<2;i++)
536 ship[i]->setWins(0);
537 emit(wins(i,0));
539 newRound();
542 void MyMainView::timerEvent(QTimerEvent *event)
544 unsigned w;
545 int i;
546 bool stopped = false;
548 if(event->timerId()==timerID)
550 QAbstractEventDispatcher::instance()->unregisterTimers(this);
551 if(gameEnd>0.0)
553 gameEnd-=1.0;
554 if(gameEnd<=0.0)
556 stopped = true;
557 if(textSprite)
559 textSprite->hide();
560 delete textSprite;
561 textSprite=0;
563 textSprite=new QGraphicsSimpleTextItem(0,&field);
564 // FIXME
565 // textSprite->setTextFlags(Qt::AlignCenter);
566 textSprite->setBrush(QBrush(QColor(255,160,0)));
567 textSprite->setFont(QFont(KGlobalSettings::generalFont().family(),14));
568 textSprite->show( );
569 if(ship[0]->getHitPoints()==0)
571 if(ship[1]->getHitPoints()==0)
572 textSprite->setText(i18n("draw round"));
573 else
575 textSprite->setText(i18n("blue player won the round"));
576 w=ship[1]->getWins()+1;
577 ship[1]->setWins(w);
578 emit(wins(1,w));
581 else
583 textSprite->setText(i18n("red player won the round"));
584 w=ship[0]->getWins()+1;
585 ship[0]->setWins(w);
586 emit(wins(0,w));
588 // must do this after setting text, because length is unknown until now
589 textSprite->setPos(QPointF((width()-textSprite->boundingRect().width()) / 2,height()/2-90));
591 QString str = i18n("Press %1 for new round",
592 KShortcut(GAME_START_SHORTCUT).primary().toString(QKeySequence::NativeText));
593 emit(setStatusText(str,IDS_MAIN));
594 stop( );
598 if( !stopped )
600 for(i=0;i<2;i++)
601 if(Options::playerIsAi(i)&&(ship[i]->getHitPoints()>0))
602 ai[i]->think();
604 moveMines();
605 moveBullets();
606 moveExplosions();
607 moveShips();
608 calculatePowerups();
609 collisions();
610 timerID=startTimer(Options::refreshTime());
612 //field.update();
616 void MyMainView::moveShips()
618 int i,nf,olde;
619 double nx,ny,en,nr;
620 BulletSprite *bullet;
621 MineSprite *mine;
624 for(i=0;i<2;i++)
626 bool playerIsAi = Options::playerIsAi(i);
627 olde=(int)ship[i]->getEnergy();
628 if(ship[i]->getHitPoints()==0)
630 ship[i]->forward(config.gamespeed);
631 ship[i]->calculateGravityAndEnergy(config.gravity,config.sunEnergy,
632 config.gamespeed);
634 else
636 ship[i]->calculateGravityAndEnergy(config.gravity,config.sunEnergy,
637 config.gamespeed);
640 if(!playerIsAi&&playerKeyPressed[i][PlayerKeyRight]
641 || playerIsAi&&ai[i]->rotateRight())
642 ship[i]->rotateRight(config.rotationEnergyNeed,
643 config.rotationSpeed);
645 if(!playerIsAi&&playerKeyPressed[i][PlayerKeyLeft]
646 || playerIsAi&&ai[i]->rotateLeft())
647 ship[i]->rotateLeft(config.rotationEnergyNeed,
648 config.rotationSpeed);
650 en=ship[i]->getEnergy();
651 nr=ship[i]->getRotation();
653 nf = 0;
654 nx=cos(nr);
655 ny=sin(nr);
656 if ( ((!playerIsAi && playerKeyPressed[i][PlayerKeyAcc])
657 || playerIsAi&&ai[i]->accelerate())
658 && (en>config.energyNeed) )
660 en-=config.energyNeed;
661 ship[i]->setVelocity(ship[i]->xVelocity()+nx*config.acc,
662 ship[i]->yVelocity()-ny*config.acc);
664 // limit speed to avoid "tunneling" through other objects
665 // FIXME: find a more elegant way
666 if (ship[i]->xVelocity()*ship[i]->xVelocity()+
667 ship[i]->yVelocity()*ship[i]->yVelocity() > MAX_VELOCITY*MAX_VELOCITY)
669 double alpha;
670 alpha = fabs(atan(ship[i]->yVelocity()/ship[i]->xVelocity()));
671 ship[i]->setVelocity(MAX_VELOCITY*cos(alpha)*fabs(ship[i]->xVelocity())/ship[i]->xVelocity(),
672 MAX_VELOCITY*sin(alpha)*fabs(ship[i]->yVelocity())/ship[i]->yVelocity());
675 if(en>MAX_ENERGY)
676 en=MAX_ENERGY;
678 ship[i]->forward(config.gamespeed);
680 //Bullets and Mines
681 if(!playerIsAi&&playerKeyPressed[i][PlayerKeyShot]
682 ||playerIsAi&&ai[i]->shootBullet())
684 if((en>config.shotEnergyNeed) && (!ship[i]->reloadsBullet()))
686 if(bullets[i]->count() <
687 (config.maxBullets+ship[i]->getBulletPowerups()))
689 ship[i]->bullet(config.bulletReloadTime);
690 en-=config.shotEnergyNeed;
691 if(i)
692 bullet=new BulletSprite(svgrender, MV_BULLET2, i,
693 config.bulletLifeTime);
694 else
695 bullet=new BulletSprite(svgrender, MV_BULLET1, i,
696 config.bulletLifeTime);
697 field.addItem(bullet);
698 QPointF p;
699 p = ship[i]->mapToScene(ship[i]->center());
700 bullet->setPos(QPointF(p.x()+nx*SHOTDIST,p.y()-ny*SHOTDIST));
701 bullet->setVelocity(ship[i]->xVelocity()+nx*config.shotSpeed,
702 ship[i]->yVelocity()-ny*config.shotSpeed);
703 // bullet->setBoundsAction(QwRealMobileSprite::Wrap);
704 bullet->show();
705 bullets[i]->append(bullet);
709 if(!Options::playerIsAi(i)&&playerKeyPressed[i][PlayerKeyMine]
710 || Options::playerIsAi(i)&&ai[i]->layMine())
712 if((en>config.mineEnergyNeed) && (!ship[i]->reloadsMine()))
714 if(mines[i]->count() <
715 (config.maxMines+ship[i]->getMinePowerups()))
717 ship[i]->mine(config.mineReloadTime);
718 en-=config.mineEnergyNeed;
719 if (i==0)
720 mine=new MineSprite(svgrender,animation[ID_MINE1],animation[ID_MINEEXPLO],i,
721 config.mineActivateTime,config.mineFuel);
722 else
723 mine=new MineSprite(svgrender,animation[ID_MINE2],animation[ID_MINEEXPLO],i,
724 config.mineActivateTime,config.mineFuel);
725 field.addItem(mine);
726 QPointF p;
727 mine->setPos(ship[i]->mapToScene(ship[i]->center()));
728 // move mine to center
729 mine->moveBy(-mine->center().x(),-mine->center().y());
730 mine->setVelocity(0,0);
731 //mine->setBoundsAction(QwRealMobileSprite::Wrap);
732 mine->show();
733 mines[i]->append(mine);
737 ship[i]->setEnergy(en);
738 if(olde!=(int)en)
739 emit(energy(i,(int)en));
744 void MyMainView::moveMines()
746 int i;
747 MineSprite* mine;
748 int p;
749 int listsize; // used for caching QtList::size()
751 for(p=0;p<2;p++)
753 i=0;
754 listsize = mines[p]->size();
755 while (i<listsize)
757 mine = mines[p]->value(i);
758 mine->calculateGravity(config.gravity,config.gamespeed);
759 mine->forward(config.gamespeed);
760 if(mine->over())
762 mine->hide();
763 mines[p]->removeAt(i);
764 delete mine;
765 listsize--;
767 else
768 i++;
773 void MyMainView::moveBullets()
775 int i,j;
776 BulletSprite *sp;
777 int listsize; // used for caching QtList::size()
779 for(i=0;i<2;i++)
781 j=0;
782 listsize = bullets[i]->size();
783 while (j<listsize)
785 sp = bullets[i]->value(j);
786 sp->calculateGravity(config.gravity,config.gamespeed);
787 sp->forward(config.gamespeed);
788 if(sp->timeOut())
790 sp->hide();
791 bullets[i]->removeAll(sp);
792 listsize--;
794 else
795 j++;
800 void MyMainView::moveExplosions()
802 int i=0;
803 ExplosionSprite *ex;
804 int listsize; // used for caching QtList::size()
805 listsize = explosions.size();
806 while (i<listsize)
808 ex = explosions[i];
809 ex->forward(config.gamespeed);
810 if(ex->isOver())
812 explosions.removeAt(i);
813 delete ex;
814 listsize--;
816 else
817 i++;
821 void MyMainView::calculatePowerups()
823 int i=0;
824 PowerupSprite *sp;
825 int listsize; // used for caching QtList::size()
826 listsize = powerups.size();
827 while (i<listsize)
829 sp = powerups[i];
830 sp->setLifetime(sp->getLifetime()-config.gamespeed);
831 if (sp->getLifetime()<0)
833 powerups.removeAt(i);
834 delete sp;
835 listsize--;
837 else
838 i++;
840 timeToNextPowerup-=config.gamespeed;
841 if(timeToNextPowerup<0)
843 int type,x,y;
844 timeToNextPowerup= random.getDouble() * config.powerupRefreshTime;
845 type= random.getLong(PowerupSprite::PowerupNum);
846 sp=new PowerupSprite(svgrender,powerupelements[type],type,
847 config.powerupLifeTime);
848 field.addItem(sp);
851 x = random.getLong(width()-40)+20;
852 y = random.getLong(height()-40)+20;
854 while(((x-width()/2)*(x-width()/2)+(y-height()/2)*(y-height()/2))<(50*50));
855 sp->setPos(QPointF(x,y));
856 powerups.append(sp);
857 sp->show();
861 void MyMainView::collisions()
863 int pl,hp,op,oldhp[2],ohp;
864 QList<QGraphicsItem *> unexact;
865 QGraphicsItem *sprite;
866 BulletSprite *bullet;
867 MineSprite *mine;
868 ExplosionSprite *expl;
869 ShipSprite *s;
870 PowerupSprite *power;
871 QList<QGraphicsItem *> hitlist;
872 double ndx[2],ndy[2];
873 double en;
874 int i;
875 int listsize; // used for caching QtList::size()
877 for(pl=0;pl<2;pl++)
879 if(!ship[pl]->isStopped())
881 unexact.clear();
882 unexact = ship[pl]->collidingItems(Qt::IntersectsItemBoundingRect);
883 oldhp[pl]=hp=ship[pl]->getHitPoints();
884 hitlist.clear();
885 foreach (sprite, unexact)
887 if((sprite->type()!=S_EXPLOSION)
888 && !((sprite->type()!=S_SUN)&&(ship[pl]->getHitPoints()==0)))
889 if(ship[pl]->collidesWithItem(sprite,Qt::IntersectsItemShape))
890 if(!hitlist.contains(sprite))
891 hitlist.append(sprite);
894 foreach (sprite, hitlist)
896 switch(sprite->type())
898 case S_SUN:
899 hp=0;
900 ship[pl]->stop();
901 break;
902 case S_BULLET:
903 bullet=(BulletSprite *)sprite;
904 bullet->hide();
905 //bullets[bullet->getPlayerNumber()]->removeRef(bullet);
906 bullets[bullet->getPlayerNumber()]->removeAll(bullet);
907 delete bullet;
908 hp-=config.bulletDamage;
909 break;
910 case S_SHIP:
911 s=(ShipSprite*)sprite;
912 ohp=s->getHitPoints();
913 if(ohp>0)
915 s->setHitPoints(ohp-hp-config.shipDamage);
916 emit(hitPoints(s->getPlayerNumber(),s->getHitPoints()));
917 ndx[0]=((1-EPSILON)*ship[0]->xVelocity()+(1+EPSILON)*ship[1]->xVelocity())/2.0;
918 ndy[0]=((1-EPSILON)*ship[0]->yVelocity()+(1+EPSILON)*ship[1]->yVelocity())/2.0;
919 ndx[1]=((1-EPSILON)*ship[1]->xVelocity()+(1+EPSILON)*ship[0]->xVelocity())/2.0;
920 ndy[1]=((1-EPSILON)*ship[1]->yVelocity()+(1+EPSILON)*ship[0]->yVelocity())/2.0;
921 ship[0]->setVelocity(ndx[0],ndy[0]);
922 ship[1]->setVelocity(ndx[1],ndy[1]);
923 hp-=ohp+config.shipDamage;
925 break;
926 case S_MINE:
927 mine=(MineSprite *)sprite;
928 if(mine->isActive()&& !mine->explodes())
930 mine->explode();
931 ndx[0]=(ship[pl]->xVelocity()+0.3*mine->xVelocity())/1.3;
932 ndy[0]=(ship[pl]->yVelocity()+0.3*mine->yVelocity())/1.3;
933 ship[pl]->setVelocity(ndx[0],ndy[0]);
934 mine->setVelocity(ndx[0],ndy[0]);
935 hp-=config.mineDamage;
937 break;
938 case S_POWERUP:
939 power=(PowerupSprite *)sprite;
940 switch(power->getType())
942 case PowerupSprite::PowerupShield:
943 hp+=config.powerupShieldAmount;
944 break;
945 case PowerupSprite::PowerupEnergy:
946 en=ship[pl]->getEnergy()+config.powerupEnergyAmount;
947 if(en>MAX_ENERGY)
948 en=MAX_ENERGY;
949 ship[pl]->setEnergy(en);
950 break;
951 case PowerupSprite::PowerupMine:
952 ship[pl]->setMinePowerups(
953 ship[pl]->getMinePowerups()+1);
954 break;
955 case PowerupSprite::PowerupBullet:
956 ship[pl]->setBulletPowerups(
957 ship[pl]->getMinePowerups()+1);
958 break;
960 power->hide();
961 powerups.removeAll(power);
962 delete power;
963 break;
966 if(hp>MAX_HP)
967 hp=MAX_HP;
968 ship[pl]->setHitPoints(hp);
971 listsize = mines[pl]->size();
972 for (i=0; i<listsize; i++)
974 mine = mines[pl]->value(i);
975 if(!mine->explodes())
977 unexact.clear();
978 unexact=mine->collidingItems(Qt::IntersectsItemBoundingRect);
979 hitlist.clear();
980 foreach (sprite, unexact)
982 if(sprite->type()==S_BULLET)
983 if(mine->collidesWithItem(sprite))
984 if(!hitlist.contains(sprite))
985 hitlist.append(sprite);
987 if(hitlist.count()>0)
989 mine->explode();
990 foreach (QGraphicsItem *item, hitlist)
992 // FIXME: why does it crash with qgraphicsitem_cast?
993 bullet = static_cast<BulletSprite*>(item);// qgraphicsitem_cast<BulletSprite*>(item);
994 // bullets[bullet->getPlayerNumber()]->removeRef(bullet);
995 bullets[bullet->getPlayerNumber()]->removeAll(bullet);
996 delete bullet;
1003 hitlist.clear();
1004 unexact.clear();
1005 unexact=sun->collidingItems(Qt::IntersectsItemBoundingRect);
1006 foreach (sprite, unexact)
1008 switch(sprite->type())
1010 case S_BULLET:
1011 if(sun->collidesWithItem(sprite))
1012 if(!hitlist.contains(sprite))
1013 hitlist.append(sprite);
1014 break;
1015 case S_MINE:
1016 if(!((MobileSprite*)sprite)->isStopped())
1017 if(sun->collidesWithItem(sprite))
1018 if(!hitlist.contains(sprite))
1019 hitlist.append(sprite);
1020 break;
1024 foreach (sprite, hitlist)
1026 switch(sprite->type())
1028 case S_BULLET:
1029 bullet=(BulletSprite *)sprite;
1030 bullet->hide();
1031 bullets[bullet->getPlayerNumber()]->removeAll(bullet);
1032 delete bullet;
1033 break;
1034 case S_MINE:
1035 mine=(MineSprite*)sprite;
1036 mine->stop();
1037 if(!mine->explodes())
1038 mine->explode();
1039 break;
1044 for(pl=0;pl<2;pl++)
1046 hp=ship[pl]->getHitPoints();
1047 if(hp!=oldhp[pl])
1048 emit(hitPoints(pl,hp));
1049 if((hp==0)&&(ship[pl]->getExplosion()<0))
1051 op=(pl+1)%2;
1052 ship[pl]->setExplosion((int)(EXPLOSION_TIME/config.gamespeed));
1053 expl = new ExplosionSprite(svgrender,animation[ID_EXPLOSION],ship[pl]);
1054 field.addItem(expl);
1055 expl->show();
1056 explosions.append(expl);
1057 gameEnd=Options::timeAfterKill()/config.gamespeed;
1062 void MyMainView::gameSetup()
1064 if(!waitForStart)
1065 pause();
1067 if (KConfigDialog::showDialog("settings"))
1068 return;
1070 SettingsDialog *settings=new SettingsDialog(&customConfig,this,"settings");
1071 connect(settings, SIGNAL(settingsUpdated()),this,SLOT(closeSettings()));
1072 settings->show();
1075 void MyMainView::closeSettings(){
1076 if(Options::lastConfig()<predefinedConfigNum)
1077 config=modifyConfig(predefinedConfig[Options::lastConfig()]);
1078 else
1079 config=modifyConfig(customConfig);
1082 void MyMainView::focusOutEvent (QFocusEvent * /*event*/)
1084 /* FIXME: ugly hack, I think
1085 it's maybe better to declare something like QMyScene:public QGraphicsScene and process input there */
1086 setFocus(Qt::OtherFocusReason);
1089 #include "mainview.moc"