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/kwin4/kwin4/kwin4.cpp

627 lines
17 KiB

/***************************************************************************
twin4 - Boardgame for KDE
-------------------
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 files for QT
#include <tqstring.h>
#include <tqlayout.h>
#include <tqhgroupbox.h>
#include <tqvbox.h>
#include <tqradiobutton.h>
#include <tqvbuttongroup.h>
#include <tqlcdnumber.h>
// include files for KDE
#include <kapplication.h>
#include <kstdgameaction.h>
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <khelpmenu.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kstdaction.h>
#include <kaction.h>
#include <tqpushbutton.h>
#include <kstatusbar.h>
#include <kconfigdialog.h>
#include <kchatdialog.h>
#include <kgamechat.h>
#include <dialogs/kgamedialog.h>
#include <dialogs/kgamedialogconfig.h>
#include <dialogs/kgameconnectdialog.h>
#include <dialogs/kgameerrordialog.h>
#include <dialogs/kgamedebugdialog.h>
// application specific includes
#include "twin4.h"
#include "twin4view.h"
#include "twin4doc.h"
#include "prefs.h"
#include "settings.h"
#include "statistics.h"
#define ACTION(x) (actionCollection()->action(x))
#define ID_STATUS_MSG 1003
#define ID_STATUS_MOVER 1002
/**
* Constructor for the chat widget. This widget
* is derived from the libtdegames chat widget
*/
ChatDlg::ChatDlg(KGame *game,TQWidget *parent)
: KDialogBase(Plain,i18n("Chat Dlg"),Ok,Ok,parent,0,false,true),mChat(0), mChatDlg(0)
{
setMinimumSize(TQSize(200,200));
TQGridLayout* mGridLayout=new TQGridLayout(plainPage());
TQHBoxLayout* h = new TQHBoxLayout(plainPage());
TQHGroupBox* b = new TQHGroupBox(i18n("Chat"), plainPage());
mChat = new KGameChat(game, 10000, b);
h->addWidget(b, 1);
h->addSpacing(10);
mGridLayout->addLayout(h,0,0);
TQPushButton *mButton=new TQPushButton(i18n("Configure..."),plainPage());
mGridLayout->addWidget(mButton,1,1);
adjustSize();
mChatDlg=new KChatDialog(mChat,plainPage(),true);
connect(mButton,TQT_SIGNAL(clicked()),mChatDlg,TQT_SLOT(show()));
}
/**
* Set the player in who does the chat. This should be
* the local player.
*/
void ChatDlg::setPlayer(Kwin4Player *p)
{
if (!mChat)
{
kdError() << "ChatDlg::setPlayer::Chat not defined can't set player" << endl;
return ;
}
if (!p)
{
kdError() << "ChatDlg::setPlayer::Player not defined can't set player" << endl;
return ;
}
mChat->setFromPlayer(p);
}
/**
* Construct the main application window
*/
Kwin4App::Kwin4App(TQWidget *parent, const char *name) : KMainWindow(parent,name), view(0), doc(0), mChat(0), mMyChatDlg(0)
{
initGUI();
initStatusBar();
initDocument();
view = new Kwin4View(doc,this);
doc->setView(view);
setCentralWidget(view);
doc->initPlayers();
setMinimumSize(640,400); // TODO
setMaximumSize(800,600);
setupGUI();
doc->ReadConfig(kapp->config());
checkMenus();
}
/**
* This method is called from various places
* and signals to check, uncheck and enable
* or disable all menu items.
* The menu parameter can limit this operation
* to one or more of the main menues (File,View,...)
*/
void Kwin4App::checkMenus(CheckFlags menu)
{
bool localgame=(!doc->isNetwork());
bool isRunning = (doc->gametqStatus()==KGame::Run);
if (!menu || (menu&CheckFileMenu))
{
changeAction("hint", !(!isRunning && localgame));
changeAction("new_game", !isRunning);
changeAction("save", isRunning);
changeAction("end_game", isRunning);
}
if (!menu || (menu&CheckEditMenu))
{
if (!isRunning || !localgame)
{
disableAction("edit_undo");
}
else if (doc->QueryHistoryCnt()==0)
{
disableAction("edit_undo");
}
else if (doc->QueryCurrentMove()<1 )
{
disableAction("edit_undo");
}
else
{
enableAction("edit_undo");
}
// Show redo
if (!isRunning || !localgame)
{
disableAction("edit_redo");
}
else if (doc->QueryHistoryCnt()==doc->QueryMaxMove())
{
disableAction("edit_redo");
}
else
{
enableAction("edit_redo");
}
}
}
/**
* Function to create the actions for the menu. This
* works together with the xml guirc file
*/
void Kwin4App::initGUI()
{
KStdGameAction::gameNew(TQT_TQOBJECT(this), TQT_SLOT(newGame()), actionCollection(), "new_game");
ACTION("new_game")->setStatusText(i18n("Start a new game"));
KStdGameAction::load(TQT_TQOBJECT(this), TQT_SLOT(slotOpenGame()), actionCollection(), "open");
ACTION("open")->setStatusText(i18n("Open a saved game..."));
KStdGameAction::save(TQT_TQOBJECT(this), TQT_SLOT(slotSaveGame()), actionCollection(), "save");
ACTION("save")->setStatusText(i18n("Save a game..."));
KStdGameAction::end(TQT_TQOBJECT(this), TQT_SLOT(endGame()), actionCollection(), "end_game");
ACTION("end_game")->setStatusText(i18n("Ending the current game..."));
ACTION("end_game")->setWhatsThis(i18n("Aborts a currently played game. No winner will be declared."));
new KAction(i18n("&Network Configuration..."),0, TQT_TQOBJECT(this), TQT_SLOT(slotInitNetwork()),
actionCollection(), "network_conf");
new KAction(i18n("Network Chat..."),0, TQT_TQOBJECT(this), TQT_SLOT(slotChat()),
actionCollection(), "network_chat");
if (global_debug>0)
new KAction(i18n("Debug KGame"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotDebugKGame()),
actionCollection(), "file_debug");
new KAction(i18n("&Show Statistics"),"flag", 0, TQT_TQOBJECT(this),
TQT_SLOT(showStatistics()), actionCollection(), "statistics");
ACTION("statistics")->setStatusText(i18n("Show statistics."));
KStdGameAction::hint(TQT_TQOBJECT(doc), TQT_SLOT(calcHint()), actionCollection(), "hint");
ACTION("hint")->setStatusText(i18n("Shows a hint on how to move."));
KStdGameAction::quit(TQT_TQOBJECT(this), TQT_SLOT(close()), actionCollection(), "game_exit");
ACTION("game_exit")->setStatusText(i18n("Quits the program."));
KStdGameAction::undo(TQT_TQOBJECT(this), TQT_SLOT(slotUndo()), actionCollection(), "edit_undo");
ACTION("edit_undo")->setStatusText(i18n("Undo last move."));
KStdGameAction::redo(TQT_TQOBJECT(this), TQT_SLOT(slotRedo()), actionCollection(), "edit_redo");
ACTION("edit_redo")->setStatusText(i18n("Redo last move."));
actionCollection()->setHighlightingEnabled(true);
connect(actionCollection(), TQT_SIGNAL(actionStatusText(const TQString &)), TQT_SLOT(slotStatusMsg(const TQString &)));
connect(actionCollection(), TQT_SIGNAL(clearStatusText()), TQT_SLOT(slotClearStatusText()));
KStdAction::preferences(TQT_TQOBJECT(this), TQT_SLOT(showSettings()), actionCollection());
}
/**
* Set the status message to Ready
*/
void Kwin4App::slotClearStatusText()
{
slotStatusMsg(i18n("Ready"));
}
/**
* Create the status bar with the message part, the
* player part
*/
void Kwin4App::initStatusBar()
{
statusBar()->insertItem(i18n("This leaves space for the mover"),ID_STATUS_MOVER,0,true);
statusBar()->insertItem(i18n("Ready"), ID_STATUS_MSG);
slotStatusMover(i18n("(c) Martin Heni "));
slotStatusMsg(i18n("Welcome to KWin4"));
}
/**
* Set up the document, i.e. the KGame object
* and connect all signals emitted by it
*/
void Kwin4App::initDocument()
{
doc = new Kwin4Doc(this);
// Game Over signal
connect(doc,TQT_SIGNAL(signalGameOver(int, KPlayer *,KGame *)),
this,TQT_SLOT(slotGameOver(int, KPlayer *,KGame *)));
connect(doc,TQT_SIGNAL(signalMoveDone(int, int)),
this,TQT_SLOT(slotMoveDone(int, int)));
connect(doc,TQT_SIGNAL(signalClientLeftGame(int, int,KGame *)),
this,TQT_SLOT(slotNetworkBroken(int, int, KGame *)));
connect(doc,TQT_SIGNAL(signalNextPlayer()),
this,TQT_SLOT(slotStatusNames()));
connect(doc,TQT_SIGNAL(signalGameRun()),
this,TQT_SLOT(slotNewGame()));
}
void Kwin4App::changeAction(const char *action, bool enable){
if (!action)
return;
KAction *act=actionCollection()->action(action);
if (act)
act->setEnabled(enable);
}
/**
* Store the current game
*/
void Kwin4App::saveProperties(KConfig *cfg)
{
TQString tempfile = kapp->tempSaveName(TQDir::currentDirPath()+"twin4");
cfg->writePathEntry("filename", tempfile );
doc->save(tempfile);
}
/**
* Load game back
*/
void Kwin4App::readProperties(KConfig* cfg)
{
TQString filename = cfg->readPathEntry("filename");
if(!filename.isEmpty())
doc->load(filename);
}
/**
* Load a game
*/
void Kwin4App::slotOpenGame()
{
TQString dir(":<twin4>");
TQString filter("*");
TQString file("/tmp/twin.save");
if (global_debug < 10)
file=KFileDialog::getOpenFileName(dir,filter,this);
doc->load(file,true);
checkMenus();
}
/**
* Save game
*/
void Kwin4App::slotSaveGame()
{
TQString dir(":<twin4>");
TQString filter("*");
TQString file("/tmp/twin.save");
if (global_debug < 10)
file=KFileDialog::getSaveFileName(dir,filter,this);
doc->save(file);
}
/**
* Start a new game
*/
void Kwin4App::newGame()
{
// End the intro if it is running
doc->setGametqStatus(Kwin4Doc::End);
// Init the board and Clear the old game out
doc->setGametqStatus(Kwin4Doc::Init);
// Run it
doc->setGametqStatus(Kwin4Doc::Run);
}
/**
* Slot: Noticed that a new game started...update menues
*/
void Kwin4App::slotNewGame()
{
slotStatusNames();
//checkMenus(CheckFileMenu|CheckEditMenu);
checkMenus(All);
}
/**
* Abort a running game
*/
void Kwin4App::endGame()
{
doc->setGametqStatus(Kwin4Doc::Abort);
}
/**
* Show statistics dialog
*/
void Kwin4App::showStatistics()
{
Statistics *dlg=new Statistics(this,"Game statistics");
dlg->p1_name->setText(doc->QueryName(Gelb));
dlg->p1_won->display(doc->QueryStat(Gelb, TWin));
dlg->p1_drawn->display(doc->QueryStat(Gelb, TRemis));
dlg->p1_lost->display(doc->QueryStat(Gelb, TLost));
dlg->p1_aborted->display(doc->QueryStat(Gelb, TBrk));
dlg->p1_sum->display(doc->QueryStat(Gelb, TSum));
dlg->p2_name->setText(doc->QueryName(Rot));
dlg->p2_won->display(doc->QueryStat(Rot, TWin));
dlg->p2_drawn->display(doc->QueryStat(Rot, TRemis));
dlg->p2_lost->display(doc->QueryStat(Rot, TLost));
dlg->p2_aborted->display(doc->QueryStat(Rot, TBrk));
dlg->p2_sum->display(doc->QueryStat(Rot, TSum));
if(dlg->exec() == TQDialog::Rejected)
doc->ResetStat();
}
/**
* Undo menu call
*/
void Kwin4App::slotUndo()
{
doc->UndoMove();
// Undo twice if computer is moving then
if (doc->playedBy(doc->QueryCurrentPlayer())==KGameIO::ProcessIO)
doc->UndoMove();
// Prepare menus
slotStatusNames();
checkMenus(CheckEditMenu);
}
/**
* Redo menu call
*/
void Kwin4App::slotRedo()
{
doc->RedoMove();
if (doc->playedBy(doc->QueryCurrentPlayer())==KGameIO::ProcessIO)
doc->RedoMove();
slotStatusNames();
checkMenus(CheckEditMenu);
}
/**
* Set the given text into the statusbar
* change status message permanently
*/
void Kwin4App::slotStatusMsg(const TQString &text)
{
statusBar()->clear();
statusBar()->changeItem(text, ID_STATUS_MSG);
}
/**
* Set the string in the statusbar window for
* the player currently moving
* change status mover permanently
*/
void Kwin4App::slotStatusMover(const TQString &text)
{
statusBar()->clear();
statusBar()->changeItem(text, ID_STATUS_MOVER);
}
/**
* Ends the current game
* Called by the gameover signal
*/
void Kwin4App::EndGame(TABLE mode)
{
doc->EndGame(mode);
doc->SwitchStartPlayer();
slotStatusNames();
checkMenus();
}
/**
* Set the names in the mover field
*/
void Kwin4App::slotStatusNames(){
TQString msg;
if (!(doc->gametqStatus()==KGame::Run))
msg=i18n("No game ");
else if (doc->QueryCurrentPlayer()==Gelb)
msg=TQString(" ")+doc->QueryName(Gelb)+ i18n(" - Yellow ");
else if (doc->QueryCurrentPlayer())
msg=TQString(" ")+doc->QueryName(Rot)+ i18n(" - Red ");
else
msg=i18n("Nobody ");
slotStatusMover(msg);
}
/**
* The network connection is lost
*/
void Kwin4App::slotNetworkBroken(int /*id*/, int oldstatus ,KGame * /*game */)
{
kdDebug(12010) << "Kwin4App::slotNetworkBroken" << endl;
if (doc->playedBy(Gelb)==0)
doc->setPlayedBy(Gelb,KGameIO::MouseIO);
if (doc->playedBy(Rot)==0)
doc->setPlayedBy(Rot,KGameIO::MouseIO);
kdDebug(12010) << "CurrrentPlayer=" << doc->QueryCurrentPlayer() << endl;
kdDebug(12010) << " " << doc->getPlayer(doc->QueryCurrentPlayer()) << endl;
doc->getPlayer(doc->QueryCurrentPlayer())->setTurn(true,true);
KMessageBox::information(this,i18n("The network game ended!\n"));
doc->setGametqStatus(oldstatus);
}
/**
* A move is done. update status
*/
void Kwin4App::slotMoveDone(int /* x */ ,int /* y */ )
{
checkMenus(CheckEditMenu);
slotStatusNames();
slotStatusMsg(i18n("Game running..."));
}
/**
* The game is over or aborted
*/
void Kwin4App::slotGameOver(int status, KPlayer * p, KGame * /*me*/)
{
if (status==-1) // remis
{
EndGame(TRemis);
slotStatusMsg(i18n("The game is drawn. Please restart next round."));
}
else if (status==1)
{
if (p->userId()==Gelb)
EndGame(TWin);
else
EndGame(TLost);
TQString msg=i18n("%1 won the game. Please restart next round.").tqarg(doc->QueryName(((FARBE)p->userId())));
slotStatusMsg(msg);
}
else if (status==2) // Abort
{
EndGame(TBrk);
TQString m=i18n(" Game aborted. Please restart next round.");
slotStatusMsg(m);
}
else
{
kdError() << "Gameover with status " << status << ". This is unexpected and a serious problem" << endl;
}
checkMenus(CheckEditMenu);
}
void Kwin4App::slotInitNetwork()
{
if (doc->gametqStatus()==Kwin4Doc::Intro) doc->setGametqStatus(Kwin4Doc::Pause);
TQString host = Prefs::host();
int port=Prefs::port();
// just for testing - should be non-modal
KGameDialog dlg(doc, 0, i18n("Network Configuration"), this,
KGameDialog::NetworkConfig, 20000, true);
dlg.networkConfig()->setDefaultNetworkInfo(host, port);
dlg.networkConfig()->setDiscoveryInfo("_twin4._tcp",Prefs::gamename());
TQVBox *box=dlg.configPage(KGameDialog::NetworkConfig);
TQVBoxLayout *l=(TQVBoxLayout *)(box->tqlayout());
mColorGroup=new TQVButtonGroup(box);
connect(mColorGroup, TQT_SIGNAL(clicked(int)), TQT_TQOBJECT(this), TQT_SLOT(slotRemoteChanged(int)));
connect(dlg.networkConfig(), TQT_SIGNAL(signalServerTypeChanged(int)), TQT_TQOBJECT(this), TQT_SLOT(slotServerTypeChanged(int)));
new TQRadioButton(i18n("Yellow should be played by remote"), mColorGroup);
new TQRadioButton(i18n("Red should be played by remote"), mColorGroup);
l->addWidget(mColorGroup);
mColorGroup->setButton(0);
slotRemoteChanged(0);
dlg.exec();// note: we don't have to check for the result - maybe a bug
}
/**
* Arg can't get rid of this function in KGame's current state.
* Can't pass a int signal to a bool slot, so this must be here
*/
void Kwin4App::slotServerTypeChanged(int t)
{
mColorGroup->setDisabled(t);
}
/**
* The remove player changed
*/
void Kwin4App::slotRemoteChanged(int button)
{
if (button==0)
{
doc->getPlayer(Gelb)->setNetworkPriority(0);
doc->getPlayer(Rot)->setNetworkPriority(10);
}
else
{
doc->getPlayer(Gelb)->setNetworkPriority(10);
doc->getPlayer(Rot)->setNetworkPriority(0);
}
}
void Kwin4App::slotChat()
{
if (!mMyChatDlg)
{
mMyChatDlg=new ChatDlg(doc,this);
Kwin4Player *p=doc->getPlayer(Gelb);
if (!p->isVirtual())
mMyChatDlg->setPlayer(doc->getPlayer(Gelb));
else
mMyChatDlg->setPlayer(doc->getPlayer(Rot));
connect(doc,TQT_SIGNAL(signalChatChanged(Kwin4Player *)),
mMyChatDlg,TQT_SLOT(setPlayer(Kwin4Player *)));
}
if (mMyChatDlg->isHidden())
mMyChatDlg->show();
else
mMyChatDlg->hide();
}
/**
* Show the KGame debug window
*/
void Kwin4App::slotDebugKGame()
{
KGameDebugDialog* debugWindow = new KGameDebugDialog(doc, this);
debugWindow->show();
}
/**
* Show Configure dialog.
*/
void Kwin4App::showSettings(){
if(KConfigDialog::showDialog("settings"))
return;
KConfigDialog *dialog = new KConfigDialog(this, "settings", Prefs::self(), KDialogBase::Swallow);
Settings *general = new Settings(0, "General");
dialog->addPage(general, i18n("General"), "package_settings");
connect(dialog, TQT_SIGNAL(settingsChanged()), doc, TQT_SLOT(loadSettings()));
dialog->show();
}
#include "twin4.moc"