/*************************************************************************** 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 #include #include #include #include #include #include // include files for KDE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 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(":"); 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(":"); 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"