summaryrefslogtreecommitdiffstats
path: root/ktron/tron.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ktron/tron.cpp')
-rw-r--r--ktron/tron.cpp1654
1 files changed, 1654 insertions, 0 deletions
diff --git a/ktron/tron.cpp b/ktron/tron.cpp
new file mode 100644
index 00000000..494d96bc
--- /dev/null
+++ b/ktron/tron.cpp
@@ -0,0 +1,1654 @@
+/****************************************************************************
+ This file is part of the game 'KTron'
+
+ Copyright (C) 1998-2000 by Matthias Kiefer <matthias.kiefer@gmx.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ ***************************************************************************/
+// Background
+#include <kio/netaccess.h>
+#include <kmessagebox.h>
+
+// Normal class
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcolordialog.h>
+#include <kaction.h>
+
+#include "settings.h"
+#include "tron.h"
+
+#define TRON_FRAMESIZE 2
+
+/**
+ * init-functions
+ **/
+
+Tron::Tron(QWidget *parent,const char *name)
+ : QWidget(parent,name)
+{
+ pixmap=0;
+ playfield=0;
+ beginHint=false;
+ lookForward=15;
+
+ random.setSeed(0);
+
+ setFocusPolicy(QWidget::StrongFocus);
+ setBackgroundMode(NoBackground);
+
+ gameBlocked=false;
+ rectSize=10;
+
+ timer = new QTimer(this,"timer");
+ loadSettings();
+ connect(timer, SIGNAL(timeout()), SLOT(doMove()));
+ QTimer::singleShot(15000, this,SLOT(showBeginHint()));
+}
+
+void Tron::loadSettings(){
+ setPalette(Settings::color_Background());
+
+ // Size
+ int newSize = Settings::rectSize();
+ if(newSize!=rectSize){
+ rectSize=newSize;
+ createNewPlayfield();
+ }
+
+ reset();
+
+ // Velocity
+ setVelocity( Settings::velocity() );
+
+ // Style
+ if(pixmap){
+ updatePixmap();
+ repaint();
+ }
+
+ // Backgroundimage
+ setBackgroundPix(NULL);
+ if(Settings::backgroundImageChoice()){
+ KURL url ( Settings::backgroundImage() );
+ if(!url.isEmpty()){
+ QString tmpFile;
+ KIO::NetAccess::download(url, tmpFile, this);
+ QPixmap pix(tmpFile);
+ if(!pix.isNull()){
+ setBackgroundPix(pix);
+ } else {
+ QString msg=i18n("Wasn't able to load wallpaper\n%1");
+ msg=msg.arg(tmpFile);
+ KMessageBox::sorry(this, msg);
+ }
+ KIO::NetAccess::removeTempFile(tmpFile);
+ }
+ else setBackgroundPix(NULL);
+ }
+ setComputerplayer(One, Settings::computerplayer1());
+ setComputerplayer(Two, Settings::computerplayer2());
+}
+
+Tron::~Tron()
+{
+ if(playfield)
+ {
+ delete [] playfield;
+ }
+ if(pixmap)
+ delete pixmap;
+ delete timer;
+
+}
+
+void Tron::createNewPlayfield()
+{
+ if(playfield)
+ delete [] playfield;
+
+ if(pixmap)
+ delete pixmap;
+
+ // field size
+ fieldWidth=(width()-2*TRON_FRAMESIZE)/rectSize;
+ fieldHeight=(height()-2*TRON_FRAMESIZE)/rectSize;
+
+ // start positions
+ playfield=new QMemArray<int>[fieldWidth];
+ for(int i=0;i<fieldWidth;i++)
+ playfield[i].resize(fieldHeight);
+
+ pixmap=new QPixmap(size());
+ pixmap->fill(Settings::color_Background());
+
+ //int min=(fieldWidth<fieldHeight) ? fieldWidth : fieldHeight;
+ //lookForward=min/4;
+}
+
+void Tron::newGame()
+{
+ players[0].score=0;
+ players[1].score=0;
+ emit gameEnds(Nobody);
+ reset();
+
+ QTimer::singleShot(15000,this,SLOT(showBeginHint()));
+}
+
+void Tron::reset()
+{
+ gamePaused=false;
+ stopGame();
+
+ players[0].reset();
+ players[1].reset();
+
+ // If playfield exists, then clean it
+ // ans set start coordinates
+ if(playfield)
+ {
+ int i;
+ for(i=0;i<fieldWidth;i++)
+ playfield[i].fill(BACKGROUND);
+
+ // set start coordinates
+
+ players[0].setCoordinates(fieldWidth/3, fieldHeight/2);
+ players[1].setCoordinates(2*fieldWidth/3, fieldHeight/2);
+
+ playfield[players[0].xCoordinate][players[0].yCoordinate]=
+ PLAYER1 | TOP | BOTTOM | LEFT | RIGHT;
+ playfield[players[1].xCoordinate][players[1].yCoordinate]=
+ PLAYER2 | TOP | BOTTOM | LEFT | RIGHT;
+
+ updatePixmap();
+ update();
+ }
+
+ setFocus();
+
+ emit gameReset();
+}
+
+void Tron::computerStart()
+{
+ if(isComputer(Both))
+ {
+ reset();
+ startGame();
+ }
+}
+
+/* *************************************************************** **
+** ??? functions **
+** *************************************************************** */
+
+void Tron::startGame()
+{
+ gameEnded=false;
+ beginHint=false;
+ timer->start(velocity);
+}
+
+void Tron::stopGame()
+{
+ timer->stop();
+ gameEnded=true;
+ players[0].last_dir = Directions::None;
+ players[1].last_dir = Directions::None;
+}
+
+void Tron::togglePause() // pause or continue game
+{
+ if(!gameEnded)
+ {
+ if(gamePaused)
+ {
+ gamePaused=false;
+ update();
+ timer->start(velocity);
+ }
+ else
+ {
+ gamePaused=true;
+ timer->stop();
+ update();
+ }
+ }
+}
+
+void Tron::showWinner(Player player)
+{
+ int i,j;
+
+ if(player != Both && Settings::changeWinnerColor())
+ {
+ int winner;
+ int loser;
+ if(player==One)
+ {
+ winner=PLAYER1;
+ loser=PLAYER2;
+ }
+ else
+ {
+ winner=PLAYER2;
+ loser=PLAYER1;
+ }
+
+ for(i=0;i<fieldWidth;i++)
+ for(j=0;j<fieldHeight;j++)
+ {
+ if(playfield[i][j]!=BACKGROUND)
+ {
+ // change player
+ playfield[i][j] |= winner;
+ playfield[i][j] &= ~loser;
+ }
+ }
+
+ updatePixmap();
+ }
+
+ repaint();
+
+ emit gameEnds(player);
+
+ if(isComputer(Both))
+ {
+ QTimer::singleShot(1000,this,SLOT(computerStart()));
+ }
+}
+
+/* *************************************************************** **
+** paint functions **
+** *************************************************************** */
+
+void Tron::updatePixmap()
+{
+ int i,j;
+
+ if(!bgPix.isNull())
+ {
+ int pw=bgPix.width();
+ int ph=bgPix.height();
+ for (int x = 0; x <= width(); x+=pw)
+ for (int y = 0; y <= height(); y+=ph)
+ bitBlt(pixmap, x, y, &bgPix);
+ }
+ else
+ {
+ pixmap->fill(Settings::color_Background());
+ }
+
+ QPainter p;
+ p.begin(pixmap);
+
+ // alle Pixel prüfen und evt. zeichnen
+ for(i=0;i<fieldWidth;i++)
+ for(j=0;j<fieldHeight;j++)
+ {
+ if(playfield[i][j]!=BACKGROUND)
+ {
+ drawRect(p,i,j);
+ }
+ }
+
+ // draw frame
+ QColor light=parentWidget()->colorGroup().midlight();
+ QColor dark=parentWidget()->colorGroup().mid();
+
+ p.setPen(NoPen);
+ p.setBrush(light);
+ p.drawRect(width()-TRON_FRAMESIZE,0,TRON_FRAMESIZE,height());
+ p.drawRect(0,height()-TRON_FRAMESIZE,width(),TRON_FRAMESIZE);
+ p.setBrush(dark);
+ p.drawRect(0,0,width(),TRON_FRAMESIZE);
+ p.drawRect(0,0,TRON_FRAMESIZE,height());
+
+ p.end();
+}
+
+// draw new player rects
+void Tron::paintPlayers()
+{
+ QPainter p;
+ p.begin(this);
+ drawRect(p,players[0].xCoordinate,players[0].yCoordinate);
+ drawRect(p,players[1].xCoordinate,players[1].yCoordinate);
+ p.end();
+
+ p.begin(pixmap);
+ drawRect(p,players[0].xCoordinate,players[0].yCoordinate);
+ drawRect(p,players[1].xCoordinate,players[1].yCoordinate);
+ p.end();
+}
+
+void Tron::drawRect(QPainter & p, int x, int y)
+{
+ int xOffset=x*rectSize+(width()-fieldWidth*rectSize)/2;
+ int yOffset=y*rectSize+(height()-fieldHeight*rectSize)/2;
+
+ int type=playfield[x][y];
+
+ // find out which color to draw
+ QColor toDraw;
+ int player;
+ if(type&PLAYER1) // check player bit
+ {
+ toDraw=Settings::color_Player1();
+ player=0;
+ }
+ else if(type&PLAYER2)
+ {
+ toDraw=Settings::color_Player2();
+ player=1;
+ }
+ else
+ {
+ kdDebug() << "No player defined in Tron::drawRect(...)" << endl;
+ return;
+ }
+
+ switch(Settings::style())
+ {
+ case Settings::EnumStyle::Line:
+ p.setBrush(toDraw);
+ p.setPen(toDraw);
+ p.drawRect(xOffset,yOffset,rectSize,rectSize);
+ break;
+ case Settings::EnumStyle::OLine:
+ {
+ p.setBrush(toDraw);
+ p.setPen(toDraw);
+ p.drawRect(xOffset,yOffset,rectSize,rectSize);
+ p.setPen(toDraw.light());
+ if(type&TOP)
+ {
+ p.drawLine(xOffset,yOffset,xOffset+rectSize-1,yOffset);
+ }
+ if(type&LEFT)
+ {
+ p.drawLine(xOffset,yOffset,xOffset,yOffset+rectSize-1);
+ }
+ p.setPen(toDraw.dark());
+ if(type&RIGHT)
+ {
+ p.drawLine(xOffset+rectSize-1,yOffset,xOffset+rectSize-1,yOffset+rectSize-1);
+ }
+ if(type&BOTTOM)
+ {
+ p.drawLine(xOffset,yOffset+rectSize-1,xOffset+rectSize-1,yOffset+rectSize-1);
+ }
+
+ break;
+ }
+ case Settings::EnumStyle::Circle:
+ p.setBrush(toDraw);
+ p.setPen(toDraw);
+ p.drawEllipse(xOffset ,yOffset ,rectSize,rectSize);
+ break;
+ case Settings::EnumStyle::ORect:
+ p.setBrush(toDraw);
+ p.setPen(toDraw.light());
+ p.drawRect(xOffset,yOffset,rectSize,rectSize);
+ p.setPen(toDraw.dark());
+ p.drawLine(xOffset,yOffset+rectSize-1,xOffset+rectSize-1
+ ,yOffset+rectSize-1);
+ p.drawLine(xOffset+rectSize-1,yOffset,xOffset+rectSize-1,yOffset+rectSize-1);
+ break;
+ }
+}
+
+/* *************************************************************** **
+** config functions **
+** *************************************************************** */
+
+void Tron::setActionCollection(KActionCollection *a)
+{
+ actionCollection = a;
+}
+
+void Tron::setBackgroundPix(QPixmap pix)
+{
+ bgPix=pix;
+
+ if(pixmap!=0){
+ updatePixmap();
+ // most pictures have colors, that you can read white text
+ setPalette(QColor("black"));
+ }
+}
+
+void Tron::setVelocity(int newVel) // set new velocity
+{
+ velocity=(10-newVel)*15;
+
+ if(!gameEnded && !gamePaused)
+ timer->changeInterval(velocity);
+}
+
+void Tron::setComputerplayer(Player player, bool flag) {
+ if(player==One)
+ players[0].setComputer(flag);
+ else if(player==Two)
+ players[1].setComputer(flag);
+
+ if(isComputer(Both))
+ QTimer::singleShot(1000,this,SLOT(computerStart()));
+}
+
+bool Tron::isComputer(Player player)
+{
+ if(player==One)
+ return players[0].computer;
+ else if(player==Two)
+ return players[1].computer;
+ else if(player==Both)
+ {
+ if(players[0].computer && players[1].computer)
+ return true;
+ }
+
+ return false;
+}
+
+/* *************************************************************** **
+** moving functions **
+** *************************************************************** */
+
+bool Tron::crashed(int playerNr,int xInc, int yInc) const
+{
+ bool flag;
+ int newX=players[playerNr].xCoordinate+xInc;
+ int newY=players[playerNr].yCoordinate+yInc;
+
+ if(newX<0 || newY <0 || newX>=fieldWidth || newY>=fieldHeight)
+ flag=true;
+ else if(playfield[newX][newY] != BACKGROUND)
+ flag=true;
+ else flag=false;
+
+ return flag;
+}
+
+void Tron::switchDir(int playerNr,Directions::Direction newDirection)
+{
+ if(playerNr!=0 && playerNr != 1)
+ {
+ kdDebug() << "wrong playerNr" << endl;
+ return;
+ }
+
+ if (Settings::oppositeDirCrashes()==false)
+ {
+ if (newDirection==Directions::Up && players[playerNr].last_dir==Directions::Down)
+ return;
+ if (newDirection==Directions::Down && players[playerNr].last_dir==Directions::Up)
+ return;
+ if (newDirection==Directions::Left && players[playerNr].last_dir==Directions::Right)
+ return;
+ if (newDirection==Directions::Right && players[playerNr].last_dir==Directions::Left)
+ return;
+ }
+
+ players[playerNr].dir=newDirection;
+}
+
+void Tron::updateDirections(int playerNr)
+{
+ if(playerNr==-1 || playerNr==0)
+ {
+ int x=players[0].xCoordinate;
+ int y=players[0].yCoordinate;
+
+ // necessary for drawing the 3d-line
+ switch(players[0].dir)
+ {
+ // unset drawing flags in the moving direction
+ case Directions::Up:
+ {
+ playfield[x][y] &= (~TOP);
+ break;
+ }
+ case Directions::Down:
+ playfield[x][y] &= (~BOTTOM);
+ break;
+ case Directions::Right:
+ playfield[x][y] &= (~RIGHT);
+ break;
+ case Directions::Left:
+ playfield[x][y] &= (~LEFT);
+ break;
+ default:
+ break;
+ }
+ players[0].last_dir = players[0].dir;
+
+ }
+ if(playerNr==-1 || playerNr==1)
+ {
+ int x=players[1].xCoordinate;
+ int y=players[1].yCoordinate;
+
+ // necessary for drawing the 3d-line
+ switch(players[1].dir)
+ {
+ // unset drawing flags in the moving direction
+ case Directions::Up:
+ {
+ playfield[x][y] &= (~TOP);
+ break;
+ }
+ case Directions::Down:
+ playfield[x][y] &= (~BOTTOM);
+ break;
+ case Directions::Right:
+ playfield[x][y] &= (~RIGHT);
+ break;
+ case Directions::Left:
+ playfield[x][y] &= (~LEFT);
+ break;
+ default:
+ break;
+ }
+ players[1].last_dir = players[1].dir;
+
+ }
+
+ paintPlayers();
+}
+
+/* *************************************************************** **
+** Events **
+** *************************************************************** */
+
+void Tron::paintEvent(QPaintEvent *e)
+{
+ bitBlt(this,e->rect().topLeft(),pixmap,e->rect());
+
+ // if game is paused, print message
+ if(gamePaused)
+ {
+ QString message=i18n("Game paused");
+ QPainter p(this);
+ QFontMetrics fm=p.fontMetrics();
+ int w=fm.width(message);
+ p.drawText(width()/2-w/2,height()/2,message);
+ }
+
+ // If game ended, print "Crash!"
+ else if(gameEnded)
+ {
+ QString message=i18n("Crash!");
+ QPainter p(this);
+ int w=p.fontMetrics().width(message);
+ int h=p.fontMetrics().height();
+ for(int i=0;i<2;i++)
+ {
+ if(!players[i].alive)
+ {
+ int x=players[i].xCoordinate*rectSize;
+ int y=players[i].yCoordinate*rectSize;
+ while(x<0) x+=rectSize;
+ while(x+w>width()) x-=rectSize;
+ while(y-h<0) y+=rectSize;
+ while(y>height()) y-=rectSize;
+ p.drawText(x,y,message);
+ }
+ }
+
+ // draw begin hint
+ if(beginHint)
+ {
+ QString hint=i18n("Press any of your direction keys to start!");
+ int x=p.fontMetrics().width(hint);
+ x=(width()-x)/2;
+ int y=height()/2;
+
+ p.drawText(x,y,hint);
+ }
+ }
+}
+
+void Tron::resizeEvent(QResizeEvent *)
+{
+ createNewPlayfield();
+ reset();
+}
+
+void Tron::keyPressEvent(QKeyEvent *e)
+{
+ KKey key(e);
+ if(!players[1].computer)
+ {
+ if(actionCollection->action("Pl2Up")->shortcut().contains(key))
+ {
+ switchDir(1,Directions::Up);
+ players[1].keyPressed=true;
+ }
+ else if(actionCollection->action("Pl2Left")->shortcut().contains(key))
+ {
+ switchDir(1,Directions::Left);
+ players[1].keyPressed=true;
+ }
+ else if(actionCollection->action("Pl2Right")->shortcut().contains(key))
+ {
+ switchDir(1,Directions::Right);
+ players[1].keyPressed=true;
+ }
+ else if(actionCollection->action("Pl2Down")->shortcut().contains(key))
+ {
+ switchDir(1,Directions::Down);
+ players[1].keyPressed=true;
+ }
+ else if(actionCollection->action("Pl2Ac")->shortcut().contains(key))
+ {
+ if(!Settings::acceleratorBlocked())
+ players[1].accelerated=true;
+
+ }
+ }
+
+ if(!players[0].computer)
+ {
+ if(actionCollection->action("Pl1Left")->shortcut().contains(key))
+ {
+ switchDir(0,Directions::Left);
+ players[0].keyPressed=true;
+ }
+ else if(actionCollection->action("Pl1Right")->shortcut().contains(key))
+ {
+ switchDir(0,Directions::Right);
+ players[0].keyPressed=true;
+ }
+ else if(actionCollection->action("Pl1Up")->shortcut().contains(key))
+ {
+ switchDir(0,Directions::Up);
+ players[0].keyPressed=true;
+ }
+ else if(actionCollection->action("Pl1Down")->shortcut().contains(key))
+ {
+ switchDir(0,Directions::Down);
+ players[0].keyPressed=true;
+ }
+ else if(actionCollection->action("Pl1Ac")->shortcut().contains(key))
+ {
+ if(!Settings::acceleratorBlocked())
+ players[0].accelerated=true;
+ }
+ }
+
+ e->ignore(); // if key is unknown: ignore
+
+ // if both players press keys at the same time, start game...
+ if(gameEnded && !gameBlocked)
+ {
+ if(players[0].keyPressed && players[1].keyPressed)
+ {
+ reset();
+ startGame();
+ }
+ }
+ // ...or continue
+ else if(gamePaused)
+ {
+ if(players[0].keyPressed && players[1].keyPressed)
+ {
+ togglePause();
+ }
+ }
+}
+
+void Tron::keyReleaseEvent(QKeyEvent * e)
+{
+ KKey key(e);
+
+ if(!players[1].computer)
+ {
+ if(actionCollection->action("Pl2Ac")->shortcut().contains(key))
+ {
+ players[1].accelerated=false;
+ return;
+ }
+ else if(actionCollection->action("Pl2Left")->shortcut().contains(key))
+ {
+ players[1].keyPressed=false;
+ return;
+ }
+ else if(actionCollection->action("Pl2Right")->shortcut().contains(key))
+ {
+ players[1].keyPressed=false;
+ return;
+ }
+ else if(actionCollection->action("Pl2Up")->shortcut().contains(key))
+ {
+ players[1].keyPressed=false;
+ return;
+ }
+ else if(actionCollection->action("Pl2Down")->shortcut().contains(key))
+ {
+ players[1].keyPressed=false;
+ return;
+ }
+ }
+
+ if(!players[0].computer)
+ {
+ if(actionCollection->action("Pl1Left")->shortcut().contains(key))
+ {
+ players[0].keyPressed=false;
+ return;
+ }
+ else if(actionCollection->action("Pl1Right")->shortcut().contains(key))
+ {
+ players[0].keyPressed=false;
+ return;
+ }
+ else if(actionCollection->action("Pl1Up")->shortcut().contains(key))
+ {
+ players[0].keyPressed=false;
+ return;
+ }
+ else if(actionCollection->action("Pl1Down")->shortcut().contains(key))
+ {
+ players[0].keyPressed=false;
+ return;
+ }
+ else if(actionCollection->action("Pl1Ac")->shortcut().contains(key))
+ {
+ players[0].accelerated=false;
+ return;
+ }
+ }
+
+ e->ignore(); // if pressed key is unknown, ignore it
+
+}
+
+// if playingfield loses keyboard focus, pause game
+void Tron::focusOutEvent(QFocusEvent *)
+{
+ if(!gameEnded && !gamePaused)
+ {
+ togglePause();
+ }
+}
+
+/* *************************************************************** **
+** slots **
+** *************************************************************** */
+
+void Tron::unblockGame()
+{
+ gameBlocked=false;
+}
+
+void Tron::showBeginHint()
+{
+ if(gameEnded)
+ {
+ // show only at the beginning of a game
+ if(players[0].score==0 && players[1].score==0)
+ {
+ beginHint=true;
+ repaint();
+ }
+ }
+}
+
+// doMove() is called from QTimer
+void Tron::doMove()
+{
+ int i;
+ for(i=0;i<2;i++)
+ {
+ // Überprüfen, ob Acceleratortaste gedrückt wurde...
+ if(players[i].accelerated)
+ {
+ updateDirections(i);
+
+ int newType; // determine type of rect to set
+ if(i==0)
+ {
+ newType=PLAYER1;
+ }
+ else
+ {
+ newType=PLAYER2;
+ }
+ switch(players[i].dir)
+ {
+ case Directions::Up:
+ if(crashed(i,0,-1))
+ players[i].alive=false;
+ else
+ {
+ players[i].yCoordinate--;
+ newType|=(TOP | LEFT | RIGHT);
+ }
+ break;
+ case Directions::Down:
+ if(crashed(i,0,1))
+ players[i].alive=false;
+ else
+ {
+ players[i].yCoordinate++;
+ newType |= (BOTTOM | LEFT | RIGHT);
+ }
+ break;
+ case Directions::Left:
+ if(crashed(i,-1,0))
+ players[i].alive=false;
+ else
+ {
+ players[i].xCoordinate--;
+ newType |= (LEFT | TOP | BOTTOM);
+ }
+ break;
+ case Directions::Right:
+ if(crashed(i,1,0))
+ players[i].alive=false;
+ else
+ {
+ players[i].xCoordinate++;
+ newType |= (RIGHT | TOP | BOTTOM);
+ }
+ break;
+ default:
+ break;
+ }
+ if(players[i].alive)
+ playfield[players[i].xCoordinate][players[i].yCoordinate]=newType;
+ }
+ }
+
+ if(players[0].accelerated || players[1].accelerated)
+ {
+ /* player collision check */
+ if(!players[1].alive)
+ {
+ int xInc=0,yInc=0;
+ switch(players[1].dir)
+ {
+ case Directions::Left:
+ xInc = -1;
+ break;
+ case Directions::Right:
+ xInc = 1;
+ break;
+ case Directions::Up:
+ yInc = -1;
+ break;
+ case Directions::Down:
+ yInc = 1;
+ break;
+ default:
+ break;
+ }
+ if ((players[1].xCoordinate+xInc) == players[0].xCoordinate)
+ if ((players[1].yCoordinate+yInc) == players[0].yCoordinate)
+ {
+ players[0].alive=false;
+ }
+ }
+
+ paintPlayers();
+
+ // crashtest
+ if(!players[0].alive && !players[1].alive)
+ {
+ stopGame();
+ players[0].score++;
+ players[1].score++;
+ showWinner(Both);
+ }
+ else
+ {
+ for(i=0;i<2;i++)
+ {
+ if(!players[i].alive)
+ {
+ stopGame();
+ showWinner((i==0)? Two:One);
+ players[i].score++;
+ }
+ }
+ }
+
+
+ if(gameEnded)
+ {
+ //this is for waiting 0,5s before starting next game
+ gameBlocked=true;
+ QTimer::singleShot(1000,this,SLOT(unblockGame()));
+ return;
+ }
+ }
+
+ // neue Spielerstandorte festlegen
+ for(i=0;i<2;i++)
+ {
+ if(players[i].computer)
+ think(i);
+ }
+
+ updateDirections();
+
+ for(i=0;i<2;i++)
+ {
+ int newType;
+ if(i==0)
+ newType=PLAYER1;
+ else
+ newType=PLAYER2;
+
+ switch(players[i].dir)
+ {
+ case Directions::Up:
+ if(crashed(i,0,-1))
+ players[i].alive=false;
+ else
+ {
+ players[i].yCoordinate--;
+ newType |= (TOP | RIGHT | LEFT);
+ }
+ break;
+ case Directions::Down:
+ if(crashed(i,0,1))
+ players[i].alive=false;
+ else
+ {
+ players[i].yCoordinate++;
+ newType |= (BOTTOM | RIGHT | LEFT);
+ }
+ break;
+ case Directions::Left:
+ if(crashed(i,-1,0))
+ players[i].alive=false;
+ else
+ {
+ players[i].xCoordinate--;
+ newType |= (LEFT | TOP | BOTTOM);
+ }
+ break;
+ case Directions::Right:
+ if(crashed(i,1,0))
+ players[i].alive=false;
+ else
+ {
+ players[i].xCoordinate++;
+ newType |= (RIGHT | TOP | BOTTOM);
+ }
+ break;
+ default:
+ break;
+
+ }
+ if(players[i].alive)
+ playfield[players[i].xCoordinate][players[i].yCoordinate]=newType;
+ }
+
+ /* player collision check */
+ if(!players[1].alive)
+ {
+ int xInc=0,yInc=0;
+ switch(players[1].dir)
+ {
+ case Directions::Left:
+ xInc = -1; break;
+ case Directions::Right:
+ xInc = 1; break;
+ case Directions::Up:
+ yInc = -1; break;
+ case Directions::Down:
+ yInc = 1; break;
+ default:
+ break;
+ }
+ if ((players[1].xCoordinate+xInc) == players[0].xCoordinate)
+ if ((players[1].yCoordinate+yInc) == players[0].yCoordinate)
+ {
+ players[0].alive=false;
+ }
+ }
+
+ paintPlayers();
+
+ if(!players[0].alive && !players[1].alive)
+ {
+ stopGame();
+ players[0].score++;
+ players[1].score++;
+ showWinner(Both);
+ }
+ else
+ for(i=0;i<2;i++)
+ {
+ // crashtests
+ if(!players[i].alive)
+ {
+ stopGame();
+ showWinner((i==0)? Two:One);
+ players[i].score++;
+ }
+ }
+
+ if(gameEnded)
+ {
+ //this is for waiting 1s before starting next game
+ gameBlocked=true;
+ QTimer::singleShot(1000,this,SLOT(unblockGame()));
+ }
+
+}
+
+/* *************************************************************** **
+** algoritm for the computerplayer **
+** *************************************************************** */
+
+// This part is partly ported from
+// xtron-1.1 by Rhett D. Jacobs <rhett@hotel.canberra.edu.au>
+void Tron::think(int playerNr)
+{
+if(Settings::skill() != Settings::EnumSkill::Easy)
+{
+ int opponent=(playerNr==1)? 0 : 1;
+
+ // determines left and right side
+ Directions::Direction sides[2];
+ // increments for moving to the different sides
+ int flags[6]={0,0,0,0,0,0};
+ int index[2];
+ // distances to barrier
+ int dis_forward, dis_left, dis_right;
+
+ dis_forward = dis_left = dis_right = 1;
+
+
+ switch (players[playerNr].dir)
+ {
+ case Directions::Left:
+ //forward flags
+ flags[0] = -1;
+ flags[1] = 0;
+
+ //left flags
+ flags[2] = 0;
+ flags[3] = 1;
+
+ // right flags
+ flags[4] = 0;
+ flags[5] = -1;
+
+ //turns to either side
+ sides[0] = Directions::Down;
+ sides[1] = Directions::Up;
+ break;
+ case Directions::Right:
+ flags[0] = 1;
+ flags[1] = 0;
+ flags[2] = 0;
+ flags[3] = -1;
+ flags[4] = 0;
+ flags[5] = 1;
+ sides[0] = Directions::Up;
+ sides[1] = Directions::Down;
+ break;
+ case Directions::Up:
+ flags[0] = 0;
+ flags[1] = -1;
+ flags[2] = -1;
+ flags[3] = 0;
+ flags[4] = 1;
+ flags[5] = 0;
+ sides[0] = Directions::Left;
+ sides[1] = Directions::Right;
+ break;
+ case Directions::Down:
+ flags[0] = 0;
+ flags[1] = 1;
+ flags[2] = 1;
+ flags[3] = 0;
+ flags[4] = -1;
+ flags[5] = 0;
+ sides[0] = Directions::Right;
+ sides[1] = Directions::Left;
+ break;
+ default:
+ break;
+
+ }
+
+ // check forward
+ index[0] = players[playerNr].xCoordinate+flags[0];
+ index[1] = players[playerNr].yCoordinate+flags[1];
+ while (index[0] < fieldWidth && index[0] >= 0 &&
+ index[1] < fieldHeight && index[1] >= 0 &&
+ playfield[index[0]][index[1]] == BACKGROUND)
+ {
+ dis_forward++;
+ index[0] += flags[0];
+ index[1] += flags[1];
+ }
+
+ // check left
+ index[0] = players[playerNr].xCoordinate+flags[2];
+ index[1] = players[playerNr].yCoordinate+flags[3];
+ while (index[0] < fieldWidth && index[0] >= 0 &&
+ index[1] < fieldHeight && index[1] >= 0 &&
+ playfield[index[0]][index[1]] == BACKGROUND) {
+ dis_left++;
+ index[0] += flags[2];
+ index[1] += flags[3];
+ }
+
+ // check right
+ index[0] = players[playerNr].xCoordinate+flags[4];
+ index[1] = players[playerNr].yCoordinate+flags[5];
+ while (index[0] < fieldWidth && index[0] >= 0 &&
+ index[1] < fieldHeight && index[1] >= 0 &&
+ playfield[index[0]][index[1]] == BACKGROUND) {
+ dis_right++;
+ index[0] += flags[4];
+ index[1] += flags[5];
+ }
+
+ // distances to opponent
+ int hor_dis=0; // negative is opponent to the right
+ int vert_dis=0; // negative is opponent to the bottom
+ hor_dis=players[playerNr].xCoordinate-players[opponent].xCoordinate;
+ vert_dis=players[playerNr].yCoordinate-players[opponent].yCoordinate;
+
+ int opForwardDis=0; // negative is to the back
+ int opSideDis=0; // negative is to the left
+ bool opMovesOppositeDir=false;
+ bool opMovesSameDir=false;
+ bool opMovesRight=false;
+ bool opMovesLeft=false;
+
+ switch(players[playerNr].dir)
+ {
+ case Directions::Up:
+ opForwardDis=vert_dis;
+ opSideDis=-hor_dis;
+ if(players[opponent].dir==Directions::Down)
+ opMovesOppositeDir=true;
+ else if(players[opponent].dir==Directions::Up)
+ opMovesSameDir=true;
+ else if(players[opponent].dir==Directions::Left)
+ opMovesLeft=true;
+ else if(players[opponent].dir==Directions::Right)
+ opMovesRight=true;
+ break;
+ case Directions::Down:
+ opForwardDis=-vert_dis;
+ opSideDis=hor_dis;
+ if(players[opponent].dir==Directions::Up)
+ opMovesOppositeDir=true;
+ else if(players[opponent].dir==Directions::Down)
+ opMovesSameDir=true;
+ else if(players[opponent].dir==Directions::Left)
+ opMovesRight=true;
+ else if(players[opponent].dir==Directions::Right)
+ opMovesLeft=true;
+ break;
+ case Directions::Left:
+ opForwardDis=hor_dis;
+ opSideDis=vert_dis;
+ if(players[opponent].dir==Directions::Right)
+ opMovesOppositeDir=true;
+ else if(players[opponent].dir==Directions::Left)
+ opMovesSameDir=true;
+ else if(players[opponent].dir==Directions::Down)
+ opMovesLeft=true;
+ else if(players[opponent].dir==Directions::Up)
+ opMovesRight=true;
+ break;
+ case Directions::Right:
+ opForwardDis=-hor_dis;
+ opSideDis=-vert_dis;
+ if(players[opponent].dir==Directions::Left)
+ opMovesOppositeDir=true;
+ else if(players[opponent].dir==Directions::Right)
+ opMovesSameDir=true;
+ else if(players[opponent].dir==Directions::Up)
+ opMovesLeft=true;
+ else if(players[opponent].dir==Directions::Down)
+ opMovesRight=true;
+ break;
+ default:
+ break;
+
+ }
+
+ int doPercentage = 100;
+ switch(Settings::skill())
+ {
+ case Settings::EnumSkill::Easy:
+ // Never reached
+ break;
+
+ case Settings::EnumSkill::Medium:
+ doPercentage=5;
+ break;
+
+ case Settings::EnumSkill::Hard:
+ doPercentage=90;
+ break;
+ }
+
+ // if opponent moves the opposite direction as we
+ if(opMovesOppositeDir)
+ {
+ // if opponent is in front
+ if(opForwardDis>0)
+ {
+ // opponent is to the right and we have the chance to block the way
+ if(opSideDis>0 && opSideDis < opForwardDis && opSideDis < dis_right && opForwardDis < lookForward)
+ {
+ if ((int)random.getLong(100) <= doPercentage || dis_forward==1)
+ switchDir(playerNr,sides[1]); // turn right
+ }
+ // opponent is to the left and we have the chance to block the way
+ else if(opSideDis<0 && -opSideDis < opForwardDis && -opSideDis < dis_left && opForwardDis < lookForward)
+ {
+ if ((int)random.getLong(100) <= doPercentage || dis_forward==1)
+ switchDir(playerNr,sides[0]); // turn left
+ }
+ // if we can do nothing, go forward
+ else if(dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ }
+ // opponent is in back of us and moves away: do nothing
+ else if(dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ } // end if(opMovesOppositeDir)
+
+ else if(opMovesSameDir)
+ {
+ // if opponent is to the back
+ if(opForwardDis < 0)
+ {
+ // opponent is to the right and we have the chance to block the way
+ if(opSideDis>0 && opSideDis < -opForwardDis && opSideDis < dis_right)
+ {
+ if ((int)random.getLong(100) <= doPercentage || dis_forward==1)
+ switchDir(playerNr,sides[1]); // turn right
+ }
+ // opponent is to the left and we have the chance to block the way
+ else if(opSideDis<0 && -opSideDis < -opForwardDis && -opSideDis < dis_left)
+ {
+ if ((int)random.getLong(100) <= doPercentage || dis_forward==1)
+ switchDir(playerNr,sides[0]); // turn left
+ }
+ // if we can do nothing, go forward
+ else if(dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ }
+ // opponent is in front of us and moves away
+ else if(dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ } // end if(opMovesSameDir)
+
+ else if(opMovesRight)
+ {
+ // opponent is in front of us
+ if(opForwardDis>0)
+ {
+ // opponent is to the left
+ if(opSideDis < 0 && -opSideDis < opForwardDis && -opSideDis < dis_left)
+ {
+ if(opForwardDis < lookForward && dis_left > lookForward)
+ {
+ if ((int)random.getLong(100) <= doPercentage/2 || dis_forward==1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ else if(dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ }
+ // op is to the right and moves away, but maybe we can block him
+ else if(opSideDis>=0 && opSideDis < dis_right)
+ {
+ if(opForwardDis < lookForward && dis_right>lookForward)
+ {
+ if ((int)random.getLong(100) <= doPercentage/2 || dis_forward==1)
+ switchDir(playerNr,sides[1]); // turn right
+ }
+ else if(dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ }
+ else if(dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ }
+ // opponent is in the back of us
+ else
+ {
+ // opponent is right from us and we already blocked him
+ if(opSideDis>0 && opForwardDis < lookForward && opSideDis < dis_right)
+ {
+ if ((int)random.getLong(100) <= doPercentage/2 || dis_forward==1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ else if(dis_forward<lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ }
+ } // end if(opMovesRight)
+
+ else if(opMovesLeft)
+ {
+ // opponent is in front of us
+ if(opForwardDis>0)
+ {
+ // opponent is to the right, moves towards us and could block us
+ if(opSideDis > 0 && opSideDis < opForwardDis && opSideDis < dis_right)
+ {
+ if(opForwardDis < lookForward && dis_right>lookForward)
+ {
+ if ((int)random.getLong(100) <= doPercentage/2 || dis_forward==1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ else if(dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ }
+ // op is to the left and moves away, but maybe we can block him
+ else if(opSideDis<=0 && opSideDis < dis_left)
+ {
+ if(opForwardDis < lookForward && dis_left>lookForward)
+ {
+ if ((int)random.getLong(100) <= doPercentage/2 || dis_forward==1)
+ switchDir(playerNr,sides[0]); // turn left
+ }
+ else if(dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+
+ }
+ else if(dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ }
+ // opponent is in the back of us
+ else //if(opForwardDis<=0)
+ {
+ // opponent is left from us and we already blocked him
+ if(opSideDis<0 && opForwardDis < lookForward && -opSideDis < dis_left)
+ {
+ if ((int)random.getLong(100) <= doPercentage/2 || dis_forward==1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ else if(dis_forward<lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 1)
+ changeDirection(playerNr,dis_right,dis_left);
+ }
+ }
+ } // end if(opMovesLeft)
+
+}
+// This part is completely ported from
+// xtron-1.1 by Rhett D. Jacobs <rhett@hotel.canberra.edu.au>
+else // Settings::skill() == Settings::EnumSkill::Easy
+{
+ Directions::Direction sides[2];
+ int flags[6] = {0,0,0,0,0,0};
+ int index[2];
+ int dis_forward, dis_left, dis_right;
+
+ dis_forward = dis_left = dis_right = 1;
+
+ switch (players[playerNr].dir) {
+ case Directions::Left:
+
+ //forward flags
+ flags[0] = -1;
+ flags[1] = 0;
+
+ //left flags
+ flags[2] = 0;
+ flags[3] = 1;
+
+ // right flags
+ flags[4] = 0;
+ flags[5] = -1;
+
+ //turns to either side
+ sides[0] = Directions::Down;
+ sides[1] = Directions::Up;
+ break;
+ case Directions::Right:
+ flags[0] = 1;
+ flags[1] = 0;
+ flags[2] = 0;
+ flags[3] = -1;
+ flags[4] = 0;
+ flags[5] = 1;
+ sides[0] = Directions::Up;
+ sides[1] = Directions::Down;
+ break;
+ case Directions::Up:
+ flags[0] = 0;
+ flags[1] = -1;
+ flags[2] = -1;
+ flags[3] = 0;
+ flags[4] = 1;
+ flags[5] = 0;
+ sides[0] = Directions::Left;
+ sides[1] = Directions::Right;
+ break;
+ case Directions::Down:
+ flags[0] = 0;
+ flags[1] = 1;
+ flags[2] = 1;
+ flags[3] = 0;
+ flags[4] = -1;
+ flags[5] = 0;
+ sides[0] = Directions::Right;
+ sides[1] = Directions::Left;
+ break;
+ default:
+ break;
+ }
+
+ // check forward
+ index[0] = players[playerNr].xCoordinate+flags[0];
+ index[1] = players[playerNr].yCoordinate+flags[1];
+ while (index[0] < fieldWidth && index[0] >= 0 &&
+ index[1] < fieldHeight && index[1] >= 0 &&
+ playfield[index[0]][index[1]] == BACKGROUND) {
+ dis_forward++;
+ index[0] += flags[0];
+ index[1] += flags[1];
+ }
+
+ if (dis_forward < lookForward)
+ {
+ dis_forward = 100 - 100/dis_forward;
+
+ // check left
+ index[0] = players[playerNr].xCoordinate+flags[2];
+ index[1] = players[playerNr].yCoordinate+flags[3];
+ while (index[0] < fieldWidth && index[0] >= 0 &&
+ index[1] < fieldHeight && index[1] >= 0 &&
+ playfield[index[0]][index[1]] == BACKGROUND) {
+ dis_left++;
+ index[0] += flags[2];
+ index[1] += flags[3];
+ }
+
+ // check right
+ index[0] = players[playerNr].xCoordinate+flags[4];
+ index[1] = players[playerNr].yCoordinate+flags[5];
+ while (index[0] < fieldWidth && index[0] >= 0 &&
+ index[1] < fieldHeight && index[1] >= 0 &&
+ playfield[index[0]][index[1]] == BACKGROUND) {
+ dis_right++;
+ index[0] += flags[4];
+ index[1] += flags[5];
+ }
+ if(!(dis_left == 1 && dis_right == 1))
+ if ((int)random.getLong(100) >= dis_forward || dis_forward == 0) {
+
+ // change direction
+ if ((int)random.getLong(100) <= (100*dis_left)/(dis_left+dis_right))
+ if (dis_left != 1)
+
+ // turn to the left
+ switchDir(playerNr,sides[0]);
+ else
+
+ // turn to the right
+ switchDir(playerNr,sides[1]);
+ else
+ if (dis_right != 1)
+
+ // turn to the right
+ switchDir(playerNr,sides[1]);
+ else
+
+ // turn to the left
+ switchDir(playerNr,sides[0]);
+ }
+ }
+ }
+}
+
+void Tron::changeDirection(int playerNr,int dis_right,int dis_left)
+{
+ Directions::Direction currentDir=players[playerNr].dir;
+ Directions::Direction sides[2];
+ switch (currentDir)
+ {
+ case Directions::Left:
+ //turns to either side
+ sides[0] = Directions::Down;
+ sides[1] = Directions::Up;
+ break;
+ case Directions::Right:
+ sides[0] = Directions::Up;
+ sides[1] = Directions::Down;
+ break;
+ case Directions::Up:
+ sides[0] = Directions::Left;
+ sides[1] = Directions::Right;
+ break;
+ case Directions::Down:
+ sides[0] = Directions::Right;
+ sides[1] = Directions::Left;
+ break;
+ default:
+ break;
+
+ }
+
+ if(!(dis_left == 1 && dis_right == 1))
+ {
+ // change direction
+ if ((int)random.getLong(100) <= (100*dis_left)/(dis_left+dis_right))
+ {
+ if (dis_left != 1)
+ // turn to the left
+ switchDir(playerNr,sides[0]);
+ else
+ // turn to the right
+ switchDir(playerNr,sides[1]);
+ }
+ else
+ {
+ if (dis_right != 1)
+ // turn to the right
+ switchDir(playerNr,sides[1]);
+ else
+ // turn to the left
+ switchDir(playerNr,sides[0]);
+ }
+ }
+}
+
+#include "tron.moc"
+