diff options
Diffstat (limited to 'ktron/tron.cpp')
-rw-r--r-- | ktron/tron.cpp | 1654 |
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" + |