You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/ktron/tron.cpp

1655 lines
42 KiB

/****************************************************************************
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 <tqtimer.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(TQWidget *tqparent,const char *name)
: TQWidget(tqparent,name)
{
pixmap=0;
playfield=0;
beginHint=false;
lookForward=15;
random.setSeed(0);
setFocusPolicy(TQ_StrongFocus);
setBackgroundMode(NoBackground);
gameBlocked=false;
rectSize=10;
timer = new TQTimer(this,"timer");
loadSettings();
connect(timer, TQT_SIGNAL(timeout()), TQT_SLOT(doMove()));
TQTimer::singleShot(15000, this,TQT_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();
tqrepaint();
}
// Backgroundimage
setBackgroundPix(NULL);
if(Settings::backgroundImageChoice()){
KURL url ( Settings::backgroundImage() );
if(!url.isEmpty()){
TQString tmpFile;
KIO::NetAccess::download(url, tmpFile, this);
TQPixmap pix(tmpFile);
if(!pix.isNull()){
setBackgroundPix(pix);
} else {
TQString msg=i18n("Wasn't able to load wallpaper\n%1");
msg=msg.tqarg(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 TQMemArray<int>[fieldWidth];
for(int i=0;i<fieldWidth;i++)
playfield[i].resize(fieldHeight);
pixmap=new TQPixmap(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();
TQTimer::singleShot(15000,this,TQT_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();
}
tqrepaint();
emit gameEnds(player);
if(isComputer(Both))
{
TQTimer::singleShot(1000,this,TQT_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());
}
TQPainter p;
p.begin(pixmap);
// alle Pixel pr<70>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
TQColor light=tqparentWidget()->tqcolorGroup().midlight();
TQColor dark=tqparentWidget()->tqcolorGroup().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()
{
TQPainter 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(TQPainter & 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
TQColor 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(TQPixmap pix)
{
bgPix=pix;
if(pixmap!=0){
updatePixmap();
// most pictures have colors, that you can read white text
setPalette(TQColor("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))
TQTimer::singleShot(1000,this,TQT_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(TQPaintEvent *e)
{
bitBlt(this,e->rect().topLeft(),pixmap,e->rect());
// if game is paused, print message
if(gamePaused)
{
TQString message=i18n("Game paused");
TQPainter p(this);
TQFontMetrics 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)
{
TQString message=i18n("Crash!");
TQPainter 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)
{
TQString 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(TQResizeEvent *)
{
createNewPlayfield();
reset();
}
void Tron::keyPressEvent(TQKeyEvent *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(TQKeyEvent * 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(TQFocusEvent *)
{
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;
tqrepaint();
}
}
}
// doMove() is called from TQTimer
void Tron::doMove()
{
int i;
for(i=0;i<2;i++)
{
// <20>berpr<70>fen, ob Acceleratortaste gedr<64>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;
TQTimer::singleShot(1000,this,TQT_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;
TQTimer::singleShot(1000,this,TQT_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"