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/twin4/twin4/twin4view.cpp

730 lines
18 KiB

/***************************************************************************
twin4view.cpp - View of the twin4 program
-------------------
begin : Sun Mar 26 12:50:12 CEST 2000
copyright : (C) |1995-2000 by Martin Heni
email : martin@heni-online.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 "twin4view.h"
#include <stdio.h>
#include <math.h>
#include <tdeconfig.h>
#include <tdelocale.h>
#include <tdeapplication.h>
#include <kstandarddirs.h>
#include "twin4doc.h"
#include "scorewidget.h"
#include "statuswidget.h"
#include "kspritecache.h"
#include <tqlabel.h>
#include <tqlcdnumber.h>
#define COL_STATUSLIGHT TQColor(210,210,255)
#define COL_STATUSFIELD TQColor(130,130,255)
#define COL_STATUSDARK TQColor(0,0,65)
#define COL_STATUSBORDER black
#define COL_PLAYER TQColor(255,255,0)
#define COL_RED red
#define COL_YELLOW yellow
class KIntroMove : public KSpriteMove
{
public:
KIntroMove() : KSpriteMove() {mode=0;cnt=0;}
virtual bool spriteMove(double tx,double ty,KSprite *sp)
{
double sign=1.0;
if (!dir) sign=-1.0;
if (mode==0)
{
cnt++;
if (sp->x()<120.0)
{
sp->spriteMove(tx,ty);
return true;
}
else
{
cnt=0;
mode=1;
cx=sp->x();
cy=sp->y()-sign*50;
}
}
if (mode==1)
{
if (cnt<360)
{
double x,y;
x=cx+50*cos((sign*90.0-sign*(double)cnt)/180.0*M_PI);
y=cy+50*sin((sign*90.0-sign*(double)cnt)/180.0*M_PI);
sp->move(x,y);
cnt+=5;
}
else
{
cnt=0;
mode=2;
}
}
if (mode==2)
{
return sp->spriteMove(tx,ty);
}
return true;
}
void setDir(bool d) {dir=d;}
private:
bool dir;
int mode;
int cnt;
double cx,cy;
};
Kwin4View::Kwin4View(Kwin4Doc *theDoc, TQWidget *parent, const char *name)
: TQCanvasView(0,parent, name), doc(theDoc)
{
mLastArrow=-1;
// localise data file
TQString file="twin4/grafix/default/grafix.rc";
TQString mGrafix=kapp->dirs()->findResourceDir("data",file);
if (mGrafix.isNull())
mGrafix="grafix/default/";
else
mGrafix+="twin4/grafix/default/";
if (global_debug>3)
kdDebug(12010) << "Localised grafix dir " << mGrafix << endl;
// Allow overriding of the grafix directory
// This is a cheap and dirty way for theming
kapp->config()->setGroup("Themes");
mGrafix = kapp->config()->readPathEntry("grafixdir", mGrafix);
setVScrollBarMode(AlwaysOff);
setHScrollBarMode(AlwaysOff);
//setBackgroundMode(PaletteBase);
setBackgroundColor(TQColor(0,0,128));
mCanvas=new TQCanvas(TQT_TQOBJECT(parent));
mCanvas->resize(parent->width(),parent->height());
mCanvas->setDoubleBuffering(true);
mCanvas->setBackgroundColor(TQColor(0,0,128));
setCanvas(mCanvas);
mCache=new KSpriteCache(mGrafix,TQT_TQOBJECT(this));
mCache->setCanvas(mCanvas);
TDEConfig *config=mCache->config();
TQPoint pnt;
config->setGroup("game");
pnt=config->readPointEntry("scorewidget");
mScoreWidget=new ScoreWidget(viewport());
addChild(mScoreWidget);
mScoreWidget->move(pnt);
pnt=config->readPointEntry("statuswidget");
mStatusWidget=new StatusWidget(this);
mStatusWidget->move(pnt);
TQPalette pal;
pal.setColor(TQColorGroup::Light, COL_STATUSLIGHT);
pal.setColor(TQColorGroup::Mid, COL_STATUSFIELD);
pal.setColor(TQColorGroup::Dark, COL_STATUSDARK);
mStatusWidget->setPalette(pal);
mStatusWidget->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->wins->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->draws->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->loses->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->num->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->bk->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p1_name->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p1_w->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p1_d->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p1_l->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p1_n->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p1_b->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p2_name->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p2_w->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p2_d->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p2_l->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p2_n->setBackgroundColor(COL_STATUSFIELD);
mStatusWidget->p2_b->setBackgroundColor(COL_STATUSFIELD);
mScoreWidget->hide();
mStatusWidget->hide();
move(0,0);
adjustSize();
initView(false);
}
void Kwin4View::initView(bool deleteall)
{
KSprite *sprite=0;
// mCanvas->setAdvancePeriod(period);
mCanvas->setAdvancePeriod(15);
TDEConfig *config=mCache->config();
config->setGroup("game");
mSpreadX=config->readNumEntry("spread_x",0);
mSpreadY=config->readNumEntry("spread_y",0);
//kdDebug(12010) << "Spread : x=" << mSpreadX << " y=" << mSpreadY << endl;
TQPixmap *pixmap=loadPixmap("background.png");
if (pixmap)
mCanvas->setBackgroundPixmap(*pixmap);
else
mCanvas->setBackgroundColor(TQColor(0,0,128));
delete pixmap;
if (doc->gameStatus()==KGame::Intro)
{
mScoreWidget->hide();
mStatusWidget->hide();
drawIntro(deleteall);
}
else
{
// TODO in start functions to distinguish from intro
kdDebug(12010) << "Clearing board" <<endl;
drawBoard(deleteall);
mScoreWidget->show();
mStatusWidget->show();
// Hide pieces in any case
for (int i=0;i<42;i++)
{
sprite=(KSprite *)(mCache->getItem("piece",i));
if (sprite)
{
introMoveDone(sprite,0 );
sprite->hide();
}
}
hideIntro();
}
// Hide stars in any case
for (int i=0;i<8;i++)
{
sprite=(KSprite *)(mCache->getItem("star",i));
if (sprite) sprite->hide();
}
// Hide GameOver in any case
sprite=(KSprite *)(mCache->getItem("gameover",1));
if (sprite) sprite->hide();
// Hide hint in any case
setHint(0,0,false);
// Clear error text
clearError();
}
TQPixmap *Kwin4View::loadPixmap(TQString name)
{
if (!mCache)
return 0;
return mCache->loadPixmap(name);
}
/**
* Called by the doc/app to signal the end of the game
*/
void Kwin4View::EndGame()
{
KSprite *sprite;
sprite=(KSprite *)(mCache->getItem("gameover",1));
TDEConfig *config=mCache->config();
int dest=config->readNumEntry("destY",150);
int src=config->readNumEntry("y",0);
//kdDebug(12010) << "MOVING gameover to " << dest << endl;
if (sprite)
{
sprite->show();
sprite->setY(src);
sprite->moveTo(sprite->x(),dest);
}
}
/**
* Draw Sprites
*/
void Kwin4View::drawStar(int x,int y,int no)
{
int dx,dy;
y=5-y;
KSprite *piece=(KSprite *)(mCache->getItem("piece",0));
if (piece)
{
dx=piece->width();
dy=piece->height();
}
else
{
dx=0;
dy=0;
}
KSprite *sprite=(KSprite *)(mCache->getItem("star",no));
//kdDebug(12010) << " setStar("<<x<<","<<y<<","<<no<<") sprite=" << sprite<<endl;
if (sprite)
{
sprite->move(dx/2-sprite->width()/2+x*(dx+mSpreadX)+mBoardX,
dy/2-sprite->height()/2+y*(dy+mSpreadY)+mBoardY);
sprite->show();
sprite->setAnimation(0);
}
}
void Kwin4View::hideIntro()
{
KSprite *sprite=0;
sprite=(KSprite *)(mCache->getItem("about",1));
if (sprite) sprite->hide();
sprite=(KSprite *)(mCache->getItem("win4about",1));
if (sprite) sprite->hide();
sprite=(KSprite *)(mCache->getItem("win4about",2));
if (sprite) sprite->hide();
TQCanvasText *text;
text=(TQCanvasText *)(mCache->getItem("intro1",1));
if (text) text->hide();
text=(TQCanvasText *)(mCache->getItem("intro2",1));
if (text) text->hide();
text=(TQCanvasText *)(mCache->getItem("intro3",1));
if (text) text->hide();
}
void Kwin4View::drawIntro(bool /*remove*/)
{
KSprite *sprite=0;
// background
sprite=(KSprite *)(mCache->getItem("about",1));
if (sprite) sprite->show();
sprite=(KSprite *)(mCache->getItem("win4about",1));
if (sprite) sprite->show();
sprite=(KSprite *)(mCache->getItem("win4about",2));
if (sprite)
{
TDEConfig *config=mCache->config();
double dest=config->readDoubleNumEntry("x2",250.0);
sprite->setX(dest);
sprite->show();
}
TQCanvasText *text;
text=(TQCanvasText *)(mCache->getItem("intro1",1));
if (text)
{
text->setText(i18n("1. intro line, welcome to win4","Welcome"));
text->show();
}
text=(TQCanvasText *)(mCache->getItem("intro2",1));
if (text)
{
text->setText(i18n("2. intro line, welcome to win4","to"));
text->show();
}
text=(TQCanvasText *)(mCache->getItem("intro3",1));
if (text)
{
text->setText(i18n("3. intro line, welcome to win4","TWin4"));
text->show();
}
// text
// animation
for (int no=0;no<42;no++)
{
sprite=(KSprite *)(mCache->getItem("piece",no));
if (sprite)
{
KIntroMove *move=new KIntroMove;
connect(sprite->createNotify(),TQT_SIGNAL(signalNotify(TQCanvasItem *,int)),
this,TQT_SLOT(introMoveDone(TQCanvasItem *,int)));
sprite->setMoveObject(move);
if (no%2==0)
{
sprite->move(0-20*no,0);
sprite->moveTo(150+2*no,105+4*no);
move->setDir(true);
sprite->setFrame((no/2)%2);
}
else
{
sprite->move(0-20*no,height());
sprite->moveTo(340-2*(no-1),105+4*(no-1));
move->setDir(false);
sprite->setFrame(((no-1)/2)%2);
}
// Increase the nz coord for consecutive peices
// to allow proper intro
// Carefule: The number must be more then the
// z coord of [empty] and less than [empty2]
sprite->setZ(sprite->z()+no/2);
// kdDebug(12010) << "Z("<<no<<")="<<sprite->z()<<endl;
sprite->show();
}
}
}
/**
* received after the movment of an intro sprite is finished
**/
void Kwin4View::introMoveDone(TQCanvasItem *item,int )
{
KSprite *sprite=(KSprite *)item;
sprite->deleteNotify();
KIntroMove *move=(KIntroMove *)sprite->moveObject();
if (move)
{
delete move;
sprite->setMoveObject(0);
}
}
void Kwin4View::drawBoard(bool remove)
{
KSprite *sprite=0;
KSprite *board=0;
int x,y;
// Board
// TODO: Without number as it is unique item
board=(KSprite *)(mCache->getItem("board",1));
if (board)
{
if (remove) board->hide();
else if (!board->isVisible()) board->show();
mBoardX=(int)(board->x());
mBoardY=(int)(board->y());
}
else
{
mBoardX=0;
mBoardY=0;
}
//kdDebug(12010) << "Board X=" << mBoardX << " y="<<mBoardY<<endl;
// Arrows
for (x=0;x<7;x++)
{
sprite=(KSprite *)(mCache->getItem("arrow",x));
if (sprite)
{
sprite->setFrame(0);
sprite->setX(x*(sprite->width()+mSpreadX)+mBoardX);
if (remove) sprite->hide();
else if (!sprite->isVisible()) sprite->show();
}
}/* end arrows */
// Field
for (y=5;y>=0;y--)
{
for (x=0;x<7;x++)
{
// Lower layer
sprite=(KSprite *)(mCache->getItem("empty2",x+7*y));
if (sprite)
{
sprite->move(x*(sprite->width()+mSpreadX)+mBoardX,
y*(sprite->height())+mBoardY);
if (remove) sprite->hide();
else if (!sprite->isVisible()) sprite->show();
}
// upper layer
sprite=(KSprite *)(mCache->getItem("empty",x+7*y));
if (sprite)
{
sprite->move(x*(sprite->width()+mSpreadX)+mBoardX,
y*(sprite->height())+mBoardY);
if (remove) sprite->hide();
else if (!sprite->isVisible()) sprite->show();
}
}
}/* end field */
}
void Kwin4View::setSprite(int no, int x, int col, bool enable)
{
KSprite *sprite;
sprite=(KSprite *)(mCache->getItem("piece",no));
if (sprite) sprite->setVisible(enable);
setArrow(x,col);
}
void Kwin4View::setHint(int x,int y,bool enabled)
{
KSprite *sprite;
sprite=(KSprite *)(mCache->getItem("hint",1));
y=5-y;
if (sprite)
{
if (enabled)
{
sprite->move(x*(sprite->width()+mSpreadX)+mBoardX,
y*(sprite->height()+mSpreadY)+mBoardY);
}
sprite->setVisible(enabled);
}
}
void Kwin4View::setPiece(int x,int y,int color,int no,bool animation)
{
KSprite *sprite=0;
y=5-y;
sprite=(KSprite *)(mCache->getItem("piece",no));
//kdDebug(12010) << " setPiece("<<x<<","<<y<<","<<color<<","<<no<<") sprite=" << sprite<<endl;
// Check for removal of sprite
if (color==Niemand)
{
sprite->hide();
return ;
}
// Make sure the frames are ok
int c;
if (color==Gelb) c=0;
else c=1;
if (sprite)
{
if (animation)
{
sprite->move(x*(sprite->width()+mSpreadX)+mBoardX,
mBoardY-sprite->height()-mSpreadY);
sprite->moveTo(sprite->x(),
sprite->y()+y*(sprite->height()+mSpreadY)+mBoardY);
connect(sprite->createNotify(),TQT_SIGNAL(signalNotify(TQCanvasItem *,int)),
doc,TQT_SLOT(moveDone(TQCanvasItem *,int)));
}
else
{
sprite->move(x*(sprite->width()+mSpreadX)+mBoardX,
mBoardY-sprite->height()-mSpreadY+
y*(sprite->height()+mSpreadY)+mBoardY);
// Prevent moving (== speed =0)
sprite->moveTo(sprite->x(),sprite->y());
connect(sprite->createNotify(),TQT_SIGNAL(signalNotify(TQCanvasItem *,int)),
doc,TQT_SLOT(moveDone(TQCanvasItem *,int)));
sprite->emitNotify(3);
}
sprite->setFrame(c);
sprite->show();
}
}
void Kwin4View::setArrow(int x,int color)
{
KSprite *sprite=0;
if (mLastArrow>=0)
sprite=(KSprite *)(mCache->getItem("arrow",mLastArrow));
else
sprite=0;
if (sprite)
sprite->setFrame(0);
sprite=(KSprite *)(mCache->getItem("arrow",x));
//kdDebug(12010) << " setArrow("<<x<<","<<color<<") sprite=" << sprite<<endl;
// Make sure the frames are ok
int c = 0;
if (color==Gelb)
c=1;
else if (color==Rot)
c=2;
if (sprite)
sprite->setFrame(c);
mLastArrow=x;
}
/**
* Error message if the wrong player moved
*/
bool Kwin4View::wrongPlayer(KPlayer *player,KGameIO::IOMode io)
{
// Hack to find out whether there is a IO Device whose turn it is
KGame::KGamePlayerList *playerList=doc->playerList();
KPlayer *p;
bool flag=false;
for ( p=playerList->first(); p!= 0; p=playerList->next() )
{
if (p==player) continue;
if (p->hasRtti(io) && p->myTurn()) flag=true;
}
if (flag)
return false;
clearError();
int rnd=(kapp->random()%4) +1;
TQString m;
m=TQString("text%1").arg(rnd);
TQString ms;
if (rnd==1) ms=i18n("Hold on... the other player has not been yet...");
else if (rnd==2) ms=i18n("Hold your horses...");
else if (rnd==3) ms=i18n("Ah ah ah... only one go at a time...");
else ms=i18n("Please wait... it is not your turn.");
// TODO MH can be unique
TQCanvasText *text=(TQCanvasText *)(mCache->getItem(m,1));
if (text)
{
text->setText(ms);
text->show();
}
return true;
}
/**
* This slot is called when a key event is received. It then prduces a
* valid move for the game.
**/
// This is analogous to the mouse event only it is called when a key is
// pressed
void Kwin4View::slotKeyInput(KGameIO *input,TQDataStream &stream,TQKeyEvent *e,bool *eatevent)
{
// Ignore non running
if (!doc->isRunning())
return;
// kdDebug(12010) << "KEY EVENT" << e->ascii() << endl;
// Ignore non key press
if (e->type() != TQEvent::KeyPress) return ;
// Our player
KPlayer *player=input->player();
if (!player->myTurn())
{
*eatevent=wrongPlayer(player,KGameIO::KeyIO);
return;
}
int code=e->ascii();
if (code<'1' || code>'7')
{
//kdDebug(12010) << "Key not supported\n";
return ;
}
// Create a move
TQ_INT32 move,pl;
move=code-'1';
pl=player->userId();
stream << pl << move;
*eatevent=true;
}
/**
* This slot is called when a mouse key is pressed. As the mouse is used as
* input for all players
* this slot is called to generate a player move out of a mouse input, i.e.
* it converts a TQMouseEvent into a move for the game. We do here some
* simple nonsense and use the position of the mouse to generate
* moves containing the keycodes
*/
void Kwin4View::slotMouseInput(KGameIO *input,TQDataStream &stream,TQMouseEvent *mouse,bool *eatevent)
{
// Only react to key pressed not released
if (mouse->type() != TQEvent::MouseButtonPress ) return ;
if (!doc->isRunning())
return;
// Our player
KPlayer *player=input->player();
if (!player->myTurn())
{
*eatevent=wrongPlayer(player,KGameIO::MouseIO);
return;
}
if (mouse->button()!=Qt::LeftButton) return ;
//if (!doc->IsRunning()) return ;
TQPoint point;
int x,y;
point=mouse->pos() - TQPoint(15,40) - TQPoint(20,20);
if (point.x()<0) return ;
x=point.x()/FIELD_SPACING;
y=point.y()/FIELD_SPACING;
if (y>=FIELD_SIZE_Y) return ;
if (x<0 || x>=FIELD_SIZE_X) return;
// Create a move
TQ_INT32 move,pl;
move=x;
pl=player->userId();
stream << pl << move;
*eatevent=true;
// kdDebug(12010) << "Mouse input done..eatevent=true" << endl;
}
/**
* Hide all the error sprites
*/
void Kwin4View::clearError()
{
TQCanvasText *text;
text=(TQCanvasText *)(mCache->getItem("text1",1));
if (text) text->hide();
text=(TQCanvasText *)(mCache->getItem("text2",1));
if (text) text->hide();
text=(TQCanvasText *)(mCache->getItem("text3",1));
if (text) text->hide();
text=(TQCanvasText *)(mCache->getItem("text4",1));
if (text) text->hide();
}
void Kwin4View::resizeEvent(TQResizeEvent *e)
{
if (mCanvas) mCanvas->resize(e->size().width(),e->size().height());
}
#include "twin4view.moc"