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/ksnake/rattler.cpp

693 lines
13 KiB

/**
* Copyright Michel Filippi <mfilippi@sade.rhein-main.de>
* Robert Williams
* Andrew Chant <andrew.chant@utoronto.ca>
* André Luiz dos Santos <andre@netvision.com.br>
* Benjamin Meyer <ben+ksnake@meyerhome.net>
*
* This file is part of the ksnake package
*
* 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 library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "rattler.h"
#include <tqtimer.h>
#include <tqlabel.h>
#include <tdeapplication.h>
#include <kstdgameaction.h>
#include <kdebug.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <tqbitarray.h>
#include <kstandarddirs.h>
#include "level.h"
#include "basket.h"
#include "settings.h"
TQBitArray gameState(5);
TQLabel *label = 0;
int speed[4] = { 130, 95, 55, 40 };
Rattler::Rattler( TQWidget *parent, const char *name )
: TQWidget( parent, name )
{
setFocusPolicy(TQ_StrongFocus);
numBalls = Settings::balls();
ballsAI = Settings::ballsAI();
numSnakes = Settings::computerSnakes();
snakesAI = Settings::snakesAI();
skill = Settings::skill();
room = Settings::startingRoom();
board = new Board(35*35);
level = new Level(board);
pix = new PixServer(board);
basket = new Basket(board, pix);
samy = new SamySnake(board, pix);
computerSnakes = new TQPtrList<CompuSnake>;
computerSnakes->setAutoDelete( true );
balls = new TQPtrList<Ball>;
balls->setAutoDelete( true );
connect( samy, TQT_SIGNAL(closeGate(int)), this, TQT_SLOT(closeGate(int)));
connect( samy, TQT_SIGNAL(score(bool, int)), this, TQT_SLOT(scoring(bool,int)));
connect( samy, TQT_SIGNAL(goingOut()), this, TQT_SLOT(speedUp()));
connect( basket, TQT_SIGNAL(openGate()), this, TQT_SLOT(openGate()));
gameState.fill(false);
gameState.setBit(Demo);
timerCount = 0;
TQTimer::singleShot( 2000, this, TQT_SLOT(demo()) ); // Why wait?
backgroundPixmaps =
TDEGlobal::dirs()->findAllResources("appdata", "backgrounds/*.png");
}
Rattler::~Rattler()
{
delete level;
delete balls;
delete computerSnakes;
delete basket;
delete samy;
delete pix;
delete board;
}
/**
* One of the settings changed, load our settings
*/
void Rattler::loadSettings(){
setBalls(Settings::balls());
setBallsAI(Settings::ballsAI());
setCompuSnakes(Settings::computerSnakes());
setSnakesAI(Settings::snakesAI());
setSkill(Settings::skill());
setRoom(Settings::startingRoom());
reloadRoomPixmap();
}
void Rattler::paintEvent( TQPaintEvent *e)
{
TQRect rect = e->rect();
if (rect.isEmpty())
return;
TQPixmap levelPix = pix->levelPix();
basket->repaint(true);
bitBlt(this, rect.x(), rect.y(),
&levelPix, rect.x(), rect.y(), rect.width(), rect.height());
}
void Rattler::timerEvent( TQTimerEvent * )
{
timerCount++;
if ( !leaving ) // advance progressBar unless Samy
emit advance(); // is going out
for (CompuSnake *c = computerSnakes->first(); c != 0; c = computerSnakes->next()){
if(c) {
c->nextMove();
c->repaint(false);
}
}
for (Ball *b = balls->first(); b != 0; b = balls->next()){
if (b) {
b->nextMove();
b->repaint();
}
}
samyState state = ok;
if(!gameState.testBit(Demo))
{
state = samy->nextMove(direction);
samy->repaint( false );
}
basket->repaint( false);
if (state == ko)
newTry();
else if (state == out)
levelUp();
TQPixmap levelPix = pix->levelPix();
bitBlt(this, 0, 0, &levelPix, 0, 0, rect().width(), rect().height());
}
void Rattler::keyPressEvent( TQKeyEvent *k )
{
if (gameState.testBit(Paused))
return;
KKey key(k);
if(actionCollection->action("Pl1Up")->shortcut().contains(key))
direction = N;
else if(actionCollection->action("Pl1Down")->shortcut().contains(key))
direction = S;
else if(actionCollection->action("Pl1Right")->shortcut().contains(key))
direction = E;
else if(actionCollection->action("Pl1Left")->shortcut().contains(key))
direction = W;
else if ((k->key() == Key_Return) ||
(k->key() == Key_Enter) || (k->key() == Key_Space)) {
if (!gameState.testBit(Demo)) {
k->ignore();
return;
}
restart();
}
else {
k->ignore();
return;
}
k->accept();
}
void Rattler::mousePressEvent( TQMouseEvent *e )
{
if (gameState.testBit(Paused))
return;
uint button = e->button();
if (button == Qt::RightButton)
{
switch (direction)
{
case N: direction=E;
break;
case E: direction=S;
break;
case S: direction=W;
break;
case W: direction=N;
break;
}
e->accept();
}
else if (button == Qt::LeftButton)
{
switch (direction)
{
case N: direction=W;
break;
case E: direction=N;
break;
case S: direction=E;
break;
case W: direction=S;
break;
}
e->accept();
}
else
e->ignore();
}
void Rattler::closeGate(int i)
{
board->set(i, brick);
pix->restore(i);
}
void Rattler::openGate()
{
board->set(NORTH_GATE, empty);
pix->erase(NORTH_GATE);
}
void Rattler::scoring(bool win, int i)
{
Fruits fruit = basket->eaten(i);
if (gameState.testBit(Demo))
win = true;
int p = 0;
switch (fruit) {
case Red:
if (win) {
if (!timerHasRunOut)
p = 1 + skill*2;
else p = 1;
}
else p = -2;
break;
case Golden:
if (win) {
if (!timerHasRunOut)
p = 2 + (skill*2) + (numSnakes*2) + (numBalls+2);
else p = 2;
}
else p = -5;
break;
default:
break;
}
score(p);
}
void Rattler::score(int p)
{
points += p;
points = (points < 0 ? 0 : points);
emit setPoints(points);
while (points > check*50) {
check++;
if (trys < 7 && !gameState.testBit(Demo))
emit setTrys(++trys);
}
}
void Rattler::killedComputerSnake()
{
if (!gameState.testBit(Demo))
score(20);
}
void Rattler::pause()
{
if (gameState.testBit(Init))
return;
if (gameState.testBit(Playing)) {
gameState.toggleBit(Playing);
gameState.setBit(Paused);
stop();
TDEAction* tempPauseAction = KStdGameAction::pause();
label = new TQLabel(this);
label->setFont( TQFont( "Times", 14, TQFont::Bold ) );
label->setText(i18n("Game Paused\n Press %1 to resume\n")
.arg(tempPauseAction->shortcutText()));
label->setAlignment( AlignCenter );
label->setFrameStyle( TQFrame::Panel | TQFrame::Raised );
label->setGeometry(182, 206, 198, 80);
label->show();
delete tempPauseAction;
//emit togglePaused();
}
else if (gameState.testBit(Paused)) {
gameState.toggleBit(Paused);
gameState.setBit(Playing);
start();
cleanLabel();
//emit togglePaused();
}
}
void Rattler::cleanLabel()
{
if (label) {
delete label;
label = 0;
}
}
void Rattler::restartDemo()
{
if (!gameState.testBit(Demo))
return;
int r = 50000+ (kapp->random() % 30000);
TQTimer::singleShot( r, this, TQT_SLOT(restartDemo()) );
stop();
level->create(Intro);
pix->initRoomPixmap();
init(false);
repaint();
start();
}
void Rattler::demo()
{
static bool first_time = true;
if(gameState.testBit(Init) || gameState.testBit(Playing))
return;
stop();
TQTimer::singleShot( 60000, this, TQT_SLOT(restartDemo()) );
gameState.fill(false);
gameState.setBit(Init);
gameState.setBit(Demo);
resetFlags();
if(!first_time) {
level->create(Intro);
pix->initRoomPixmap();
}
repaint(rect(), false);
init(false);
run();
first_time = false;
}
void Rattler::restart()
{
if (gameState.testBit(Init))
return;
stop();
if (gameState.testBit(Paused) || gameState.testBit(Playing)) {
switch( KMessageBox::questionYesNo( this,
i18n("A game is already started.\n"
"Start a new one?\n"), i18n("Snake Race"), i18n("Start New"), i18n("Keep Playing"))) {
case KMessageBox::No:
if (!gameState.testBit(Paused))
start();
return;
break;
case KMessageBox::Yes:
;
}
}
gameState.fill(false);
gameState.setBit(Init);
gameState.setBit(Playing);
resetFlags();
level->setLevel(room);
level->create(Banner);
pix->initRoomPixmap();
cleanLabel();
repaint();
TQTimer::singleShot( 2000, this, TQT_SLOT(showRoom()) );
}
void Rattler::newTry()
{
stop();
if(trys==0) {
gameState.fill(false);
gameState.setBit(Over);
level->create(GameOver);
pix->initRoomPixmap();
repaint();
TQTimer::singleShot( 5000, this, TQT_SLOT(demo()) );
emit setScore(points);
return;
}
--trys;
gameState.fill(false);
gameState.setBit(Init);
gameState.setBit(Playing);
level->create(Room);
pix->initRoomPixmap();
init(true);
repaint();
TQTimer::singleShot( 1000, this, TQT_SLOT(run()) );
}
void Rattler::levelUp()
{
stop();
gameState.fill(false);
gameState.setBit(Init);
gameState.setBit(Playing);
score (2*(level->getLevel())+(2*numSnakes)+(2*numBalls)+(2*skill));
level->nextLevel();
level->create(Banner);
pix->initRoomPixmap();
repaint();
TQTimer::singleShot( 2000, this, TQT_SLOT(showRoom()) );
}
/* this slot is called by the progressBar when value() == 0
or by a compuSnake wich manages to exit */
void Rattler::restartTimer()
{
timerHasRunOut = true;
timerCount = 0;
emit rewind();
if ( board->isEmpty(NORTH_GATE) )
closeGate(NORTH_GATE);
basket->newApples();
}
void Rattler::speedUp()
{
leaving = true;
stop();
start( 30 );
}
void Rattler::resetFlags()
{
trys = 2;
check = 1;
points = 0;
}
void Rattler::showRoom()
{
level->create(Room);
pix->initRoomPixmap();
init(true);
repaint();
TQTimer::singleShot( 1000, this, TQT_SLOT(run()) );
}
void Rattler::init(bool play)
{
leaving = false;
timerHasRunOut = false;
timerCount = 0;
emit rewind();
emit setTrys(trys);
emit setPoints(points);
basket->clear();
basket->newApples();
restartBalls(play);
restartComputerSnakes(play);
if(play)
samy->init();
}
void Rattler::run()
{
direction = N;
gameState.toggleBit(Init);
start();
}
void Rattler::start()
{
gameTimer = startTimer( speed [skill] );
}
void Rattler::start(int t)
{
gameTimer = startTimer(t);
}
void Rattler::stop()
{
TQT_TQOBJECT(this)->killTimers();
}
void Rattler::restartComputerSnakes(bool play)
{
if( !computerSnakes->isEmpty())
computerSnakes->clear();
int i = (play == false && numSnakes == 0 ? 1 : numSnakes);
for (int x = 0; x < i; x++) {
CompuSnake *as;
switch(snakesAI) {
default: // random.
as = new CompuSnake(board, pix);
break;
case 1: // eater.
as = new EaterCompuSnake(board, pix);
break;
case 2: // killer.
as = new KillerCompuSnake(board, pix);
break;
}
connect( as, TQT_SIGNAL(closeGate(int)), this, TQT_SLOT(closeGate(int)));
connect( as, TQT_SIGNAL(restartTimer()), this, TQT_SLOT(restartTimer()));
connect( as, TQT_SIGNAL(score(bool, int)), this, TQT_SLOT(scoring(bool,int)));
connect( as, TQT_SIGNAL(killed()), this, TQT_SLOT(killedComputerSnake()));
computerSnakes->append(as);
}
}
void Rattler::restartBalls(bool play)
{
if( !balls->isEmpty())
balls->clear();
int i = (play == false && numBalls == 0 ? 1 : numBalls);
for (int x = 0; x < i; x++) {
Ball *b;
switch(ballsAI) {
default: // default.
b = new Ball(board, pix);
break;
case 1: // dumb.
b = new DumbKillerBall(board, pix);
break;
case 2: // smart.
b = new KillerBall(board, pix);
break;
}
balls->append(b);
}
}
void Rattler::setBalls(int newNumBalls)
{
numBalls = balls->count();
if (!(gameState.testBit(Playing) || gameState.testBit(Demo)) || numBalls == newNumBalls)
return;
while ( newNumBalls > numBalls) {
Ball *b = new Ball(board, pix);
balls->append(b);
numBalls++;
}
while (newNumBalls < numBalls) {
Ball *b = balls->getLast();
b->zero();
balls->removeLast();
numBalls--;
}
}
void Rattler::setBallsAI(int i)
{
ballsAI = i;
}
void Rattler::resizeEvent( TQResizeEvent * )
{
pix->initPixmaps();
pix->initBrickPixmap();
pix->initbackPixmaps();
pix->initRoomPixmap();
}
void Rattler::setCompuSnakes(int i)
{
CompuSnake *cs;
numSnakes = i;
int count = computerSnakes->count();
if (gameState.testBit(Playing) || gameState.testBit(Demo)) {
if ( i > count) {
while ( i > count) {
CompuSnake *as;
switch(snakesAI) {
default: // random.
as = new CompuSnake(board, pix);
break;
case 1: // eater.
as = new EaterCompuSnake(board, pix);
break;
case 2: // killer.
as = new KillerCompuSnake(board, pix);
break;
}
connect( as, TQT_SIGNAL(closeGate(int)), this, TQT_SLOT(closeGate(int)));
connect( as, TQT_SIGNAL(restartTimer()), this, TQT_SLOT(restartTimer()));
connect( as, TQT_SIGNAL(score(bool, int)), this, TQT_SLOT(scoring(bool,int)));
connect( as, TQT_SIGNAL(killed()), this, TQT_SLOT(killedComputerSnake()));
computerSnakes->append(as);
i--;
}
}
else if (i < count) {
while (i < count) {
cs = computerSnakes->getLast();
cs->zero();
computerSnakes->removeLast();
i++;
}
}
}
}
void Rattler::setSnakesAI(int i)
{
snakesAI = i;
}
void Rattler::setSkill(int i)
{
skill = i;
if (gameState.testBit(Playing) || gameState.testBit(Demo)) {
stop();
start();
}
}
void Rattler::setRoom(int i)
{
room = i;
}
void Rattler::reloadRoomPixmap()
{
pix->initbackPixmaps();
pix->initRoomPixmap();
demo();
}
#include "rattler.moc"