/***************************************************************************
                          gamefield.cpp  -  description
                             -------------------
    begin                : Tue Apr 4 2000
    copyright            : (C) 2000 by Frank von Daak
    email                : frank.fun@kpage.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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "gamefield.h"

#define WIDTH 800
#define HEIGHT 550

#define PREFIX kapp->kde_datadir() + "/kinsectizid/"

#define GNATKILL_IMAGE    "sprites/mueke/mueked-%d.ppm"
#define GNATKILL_MASK     "sprites/mueke/mueked-%d.pbm"
#define GNATKILL_FRAMES   10

#define TUXKILL_IMAGE    "sprites/dtux/dtux%d.ppm"
#define TUXKILL_MASK     "sprites/dtux/dtux%d.pbm"
#define TUXKILL_FRAMES  1

#define SHOT_WAV "sounds/shot.wav"
#define EMPTY_WAV "sounds/leer.wav"
#define LOAD_WAV "sounds/laden.wav"

#define MAG_IMAGE "sprites/maggot/magl-%d.ppm"
#define MAG_MASK "sprites/maggot/magl-%d.pbm"
#define MAG_FRAMES 29

#define TUX_IMAGE "sprites/tux/tuxl-%d.ppm"
#define TUX_MASK "sprites/tux/tuxl-%d.pbm"
#define TUX_FRAMES 12

#define REFRESH_DELAY  1

#define TEXT_SPEED     6

GameField::GameField(QWidget *parent, const char *name )
		 : QWidget(parent,name)
{
	fc = 0;
	ft = 0;
	shots = 0;
	shootWait = 100;
	hitSnd = new KAudio;
	started = false;
	rnd = 0;

    x=0;
    y=0;
    time_t t = time(&t);
	srand((unsigned int) t);
}

GameField::~GameField()
{
	delete(field);
	delete(view);
}

void GameField::setLevel(int lev)
{
	gnatSpeed = (lev/2)+2;
	switch ( random()%3 ){
		case 0:
			IMG_BACKGROUND = "sprites/background/bg.ppm";
			break;
		case 1:
			IMG_BACKGROUND = "sprites/background/bg2.ppm";
			break;
		case 2:
			IMG_BACKGROUND = "sprites/background/bg3.ppm";
			break;
		default:
			IMG_BACKGROUND = "sprites/background/bg.ppm";
			break;
	}

	L_MUEKE = "sprites/mueke/muekel-%d.ppm";
	L_MMASK = "sprites/mueke/muekel-%d.pbm";
	L_MFRAMES = 32;
	
	R_MUEKE = "sprites/mueke/mueker-%d.ppm";
	R_MMASK = "sprites/mueke/mueker-%d.pbm";
	R_MFRAMES = 32;

	L_BUCK = "sprites/buck/buckl-%d.ppm";
	L_BMASK = "sprites/buck/buckl-%d.pbm";
	L_BFRAMES = 24;

	R_BUCK = "sprites/buck/buckr-%d.ppm";
	R_BMASK = "sprites/buck/buckr-%d.pbm";
	R_BFRAMES = 24;

	field = new QwImageSpriteField( PREFIX + IMG_BACKGROUND,WIDTH,HEIGHT);
	view = new MyQwSpriteFieldView(field,this);

    textSprite = new QwTextSprite;
    pauseTextSprite = new QwTextSprite;

    readSprites();
    connect(view, SIGNAL(fire(int,int)), this, SLOT(shoot(int,int)));
    connect(view, SIGNAL(load()), this, SLOT(reloadGun()));
}

void GameField::showPause(bool paused)
{
	if ( paused ) {
		pauseTextSprite->setText( i18n("\tGame paused !\nPress P to continue...") );
		pauseTextSprite->setFont(QFont("helvetica", 24, QFont::Bold));
		pauseTextSprite->setColor( yellow );
		pauseTextSprite->moveTo( 350,270 );
		pauseTextSprite->show();
		field->update();
	} else {
		pauseTextSprite->hide();
		field->update();
	}
}

void GameField::readSprites()
{
//    cloudImg = new QwSpritePixmapSequence( CLOUD1_IMAGE, CLOUD1_MASK, CLOUD1_FRAMES );
    leftMImg = new QwSpritePixmapSequence( PREFIX + L_MUEKE, PREFIX + L_MMASK, L_MFRAMES );
    rightMImg = new QwSpritePixmapSequence( PREFIX + R_MUEKE, PREFIX + R_MMASK, R_MFRAMES );
    leftBImg = new QwSpritePixmapSequence( PREFIX + L_BUCK, PREFIX + L_BMASK, L_BFRAMES );
    rightBImg = new QwSpritePixmapSequence( PREFIX + R_BUCK, PREFIX + R_BMASK, R_BFRAMES );
    GnatKillImg = new QwSpritePixmapSequence( PREFIX + GNATKILL_IMAGE, PREFIX + GNATKILL_MASK, GNATKILL_FRAMES );
    TuxKillImg = new QwSpritePixmapSequence( PREFIX + TUXKILL_IMAGE, PREFIX + TUXKILL_MASK, TUXKILL_FRAMES );
    magImg = new QwSpritePixmapSequence( PREFIX + MAG_IMAGE, PREFIX + MAG_MASK, MAG_FRAMES );
    tuxImg = new QwSpritePixmapSequence( PREFIX + TUX_IMAGE, PREFIX + TUX_MASK, TUX_FRAMES );
}

void GameField::showText( const char *text, const QColor &color )
{
    textSprite->setText( text );
    textSprite->setFont(QFont("helvetica", 32, QFont::Bold));
    textSprite->setColor( color );

    textDy = TEXT_SPEED;

    textSprite->moveTo( (width()-textSprite->boundingRect().width()) / 2, -5 );

    textSprite->show();
}

void GameField::newGame()
{
    reset();
    startTimer( 40 );
}

void GameField::reset()
{
	emit gameReset(shots);
	shots = 0;
}

void GameField::timerEvent( QTimerEvent * )
{
	killTimers();
    startTimer( 40 );

	shootWait++;

	if ( !mags.isEmpty() ) {
	    QwRealMobileSprite *mag;

    	for ( mag = mags.first(); mag; mag = mags.next() )
	    {
			mag->forward( 8 );
			mag->frame( ( mag->frame()+1 ) % MAG_FRAMES );
			if ( mag->x() > 790 ) {
				mag->hide();
				mags.removeRef(mag);
			}
		}
	}

	if ( !tuxs.isEmpty() ) {
	    QwRealMobileSprite *tux;

    	for ( tux = tuxs.first(); tux; tux = tuxs.next() )
	    {
			tux->forward( 9 );
			tux->frame( ( tux->frame()+1 ) % TUX_FRAMES );
			if ( tux->x() > 790 ) {
				tux->hide();
				tuxs.removeRef(tux);
			}
		}
	}

    QwRealMobileSprite *gnat;

    // move insects forward
    for ( gnat = gnats.first(); gnat; gnat = gnats.next() )
    {
		gnat->forward( gnatSpeed );
		gnat->frame( ( gnat->frame()+1 ) % 24 );
		if ( !started )
			gnat->hide();
		else
			gnat->show();
    }

    QwRealMobileSprite *dgnat;

    // Let them splash :-)
    for ( dgnat = dgnats.first(); dgnat; dgnat = dgnats.next() )
    {
		switch ( dgnat->rtti() )
		{
		    case GNAT_DEAD:
		    fc++;
			dgnat->frame( ( dgnat->frame()+1 ) % GNATKILL_FRAMES );
			if ( fc >= dgnat->frameCount() )
				removeDGnat();
			break;
		}
    }

    QwRealMobileSprite *dtux;

    // Let them splash :-)
    for ( dtux = dtuxs.first(); dtux; dtux = dtuxs.next() )
    {
	    ft++;
		dtux->frame( ( dtux->frame() ) % 1 );
		if ( ft >= 32 )
			removeDTux();
    }

    if ( textSprite->visible() && !started ) {
		if ( textDy < 0 && textSprite->boundingRect().y() <= -5 ) {
		    textSprite->hide();
		} else {
		    textSprite->moveBy( 0, textDy );
		}
		if ( textSprite->boundingRect().y() > height()/2 ) {
		    textDy = 0;
		}
    } else {
    	textSprite->hide();
//    	delete(textSprite);
    }

    field->update();


// Can I move the background ???

	x++;
	y++;
//	this->move(-x,0);
//	field->forceRedraw(rect);
}

void GameField::addGnats( int num )
{
    int i;
    double xmov, ymov;

	KGnat *gnat;

    for ( i = 0; i < num; i++ )
    {
   		xmov = (2.0 - (double)(random()%256)/64.0);
    	ymov = (2.0 - (double)(random()%256)/64.0);
	    if ( xmov > 0 ) {
	    	switch ( random() %2 ) {
	    		case 0:
					gnat = new KGnat( leftMImg );
					break;
				case 1:
					gnat = new KGnat( leftBImg );
					break;
				default:
					gnat = new KGnat( leftMImg );
			}
		} else {
			switch ( random() %2){
				case 0:
					gnat = new KGnat( rightMImg );
					break;
				case 1:
					gnat = new KGnat( rightBImg );
					break;
				default:
					gnat = new KGnat( rightMImg );
			}
		}
		
		gnat->setBoundsAction( QwRealMobileSprite::Wrap );
		gnat->setVelocity( xmov,ymov );
		if ( rnd == 3 ) {
			gnat->moveTo( 0, this->height(), 0 );
		} else {
			switch ( random()%4 )
			{
	    		case 0:
				gnat->moveTo( 0, 0, 0 );
				break;

			    case 1:
				gnat->moveTo( this->width(), 0, 0 );
				break;

			    case 2:
				gnat->moveTo( this->width(), this->height(), 0 );
				break;

		    	default:
				gnat->moveTo( 0, this->height(), 0 );
				break;
			}
		}
	gnats.append( gnat );
    }
}


void GameField::addMag( int num )
{
    int i;

    for ( i = 0; i < num; i++ )
    {
	Mag *mag = new Mag( magImg );
	
	mag->setBoundsAction( QwRealMobileSprite::Wrap );
	mag->setVelocity( 1, 0 );
	mag->moveTo( 0,this->height()-20, 0 );

	mags.append( mag );
    }
}

void GameField::addTux( int num )
{
    int i;

    for ( i = 0; i < num; i++ )
    {
	Tux *tux = new Tux( tuxImg );
	
	tux->setBoundsAction( QwRealMobileSprite::Wrap );
	tux->setVelocity( 1, 0 );
	tux->moveTo( 0,this->height()-90, 0 );

	tuxs.append( tux );
    }
}

// This will test the position of the shoot, and kill the gnat
void GameField::shoot(int x, int y)
{
// Check, if a new game is started
	if ( !started )
		return;

	if ( shootWait < 10 ) {
		return;
	} else {
		shootWait = 0;
	}
	if ( shots >= 10 ) {
		if ( sound ) {
			if ( hitSnd->serverStatus() != 0 ) {
			} else {
				hitSnd->play(PREFIX + EMPTY_WAV);
			}
		}
		return;
	}
	shots++;

	if ( sound ) {
		if ( hitSnd->serverStatus() != 0 ) {
		} else {
			hitSnd->play(PREFIX + SHOT_WAV);
		}
	}

    QwRealMobileSprite *gnat;

    // WHere are the gnats ???
    for ( gnat = gnats.first(); gnat; gnat = gnats.next() )
    {
		if (( x >= gnat->x() )&&( x <= gnat->x()+74)&&
			( y >= gnat->y() )&&( y <= gnat->y()+40)) {
			gnat->hide();
			gnats.removeRef( gnat );
			emit gnatKilled(true);
			addGnats(1);
			if ( random()%10 == 3 )
				addMag(1);
			if ( random()%35 == 3 )
				addTux(1);
			showDeadGnat(x,y);
			return;
		}
	}
	if ( !mags.isEmpty() ) {
	    QwRealMobileSprite *mag;

	// WHere are the gnats ???
		for ( mag = mags.first(); mag; mag = mags.next() )
	    {
			if (( x >= mag->x()+5 )&&( x <= mag->x()+30)&&
				( y >= mag->y()+5 )&&( y <= mag->y()+20)) {
				mag->hide();
				mags.removeRef( mag );
				emit magKilled(true);
				showDeadGnat(x,y);
				return;
			}
		}
	}

	if ( !tuxs.isEmpty() ) {
	    QwRealMobileSprite *tux;

	// Killed TUX ??? :-O
		for ( tux = tuxs.first(); tux; tux = tuxs.next() )
	    {
			if (( x >= tux->x()+3 )&&( x <= tux->x()+40)&&
				( y >= tux->y()+5 )&&( y <= tux->y()+80)) {
				tux->hide();
				tuxs.removeRef( tux );
				emit tuxKilled(true);
				showDeadTux(x,y);
				return;
			}
		}
	}

	emit gnatKilled(false);
}

void GameField::showDeadGnat(int x, int y)
{
	KDeadGnat *dgnat = new KDeadGnat(GnatKillImg);

	dgnat->setBoundsAction( QwRealMobileSprite::Wrap );
	dgnat->setVelocity( 0,0 );
	dgnat->moveTo(x-20 , y-20);

	dgnats.append(dgnat);
}

void GameField::showDeadTux(int x, int y)
{
	DeadTux *dtux = new DeadTux(TuxKillImg);

	dtux->setBoundsAction( QwRealMobileSprite::Wrap );
	dtux->setVelocity( 0,0 );
	dtux->moveTo(x-20 , y-20);

	dtuxs.append(dtux);
}

void GameField::removeDGnat()
{
    QwRealMobileSprite *dgnat;

    // WHere are the gnats ???
    for ( dgnat = dgnats.first(); dgnat; dgnat = dgnats.next() )
    {
		dgnat->hide();
		dgnats.removeRef( dgnat );
    }
    fc = 0;
}

void GameField::removeDTux()
{
    QwRealMobileSprite *dtux;

    // WHere are the gnats ???
    for ( dtux = dtuxs.first(); dtux; dtux = dtuxs.next() )
    {
		dtux->hide();
		dtuxs.removeRef( dtux );
    }
    ft = 0;
}

void GameField::reloadGun()
{
// Check, if a new game is started
	if ( !started )
		return;

	if ( shots < 10 ) {
		;
	} else {
		if ( sound ) {
			if ( hitSnd->serverStatus() != 0 ) {
			} else {
				hitSnd->play(PREFIX + LOAD_WAV);
			}
		}
		shots = 0;
		emit reload();
	}
}