summaryrefslogtreecommitdiffstats
path: root/atlantik/libatlantikui/board.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'atlantik/libatlantikui/board.cpp')
-rw-r--r--atlantik/libatlantikui/board.cpp601
1 files changed, 601 insertions, 0 deletions
diff --git a/atlantik/libatlantikui/board.cpp b/atlantik/libatlantikui/board.cpp
new file mode 100644
index 00000000..a4fdf3ce
--- /dev/null
+++ b/atlantik/libatlantikui/board.cpp
@@ -0,0 +1,601 @@
+// Copyright (c) 2002-2004 Rob Kaper <cap@capsi.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 2.1 as published by the Free Software Foundation.
+//
+// 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser 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 <iostream>
+
+#include <qpainter.h>
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <atlantic_core.h>
+#include <player.h>
+#include <estate.h>
+#include <auction.h>
+
+#include "auction_widget.h"
+#include "estatedetails.h"
+#include "estateview.h"
+#include "token.h"
+
+#include "board.h"
+#include "board.moc"
+
+AtlantikBoard::AtlantikBoard(AtlanticCore *atlanticCore, int maxEstates, DisplayMode mode, QWidget *parent, const char *name) : QWidget(parent, name)
+{
+ m_atlanticCore = atlanticCore;
+ m_maxEstates = maxEstates;
+ m_mode = mode;
+ m_animateTokens = false;
+ m_lastServerDisplay = 0;
+
+ setMinimumSize(QSize(500, 500));
+
+ int sideLen = maxEstates/4;
+
+ // Animated token movement
+ m_movingToken = 0;
+ m_timer = new QTimer(this);
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(slotMoveToken()));
+ m_resumeTimer = false;
+
+ m_gridLayout = new QGridLayout(this, sideLen+1, sideLen+1);
+ for(int i=0;i<=sideLen;i++)
+ {
+ if (i==0 || i==sideLen)
+ {
+ m_gridLayout->setRowStretch(i, 3);
+ m_gridLayout->setColStretch(i, 3);
+ }
+ else
+ {
+ m_gridLayout->setRowStretch(i, 2);
+ m_gridLayout->setColStretch(i, 2);
+ }
+ }
+
+// spacer = new QWidget(this);
+// m_gridLayout->addWidget(spacer, sideLen, sideLen); // SE
+
+ m_displayQueue.setAutoDelete(true);
+ m_estateViews.setAutoDelete(true);
+ m_tokens.setAutoDelete(true);
+
+ displayDefault();
+}
+
+AtlantikBoard::~AtlantikBoard()
+{
+ reset();
+}
+
+void AtlantikBoard::reset()
+{
+ kdDebug() << "AtlantikBoard::reset" << endl;
+
+ m_tokens.clear();
+ m_estateViews.clear();
+ m_displayQueue.clear();
+ m_lastServerDisplay = 0;
+ m_movingToken = 0;
+}
+
+void AtlantikBoard::setViewProperties(bool indicateUnowned, bool highliteUnowned, bool darkenMortgaged, bool quartzEffects, bool animateTokens)
+{
+ if (m_animateTokens != animateTokens)
+ m_animateTokens = animateTokens;
+
+ // Update EstateViews
+ EstateView *estateView;
+ for (QPtrListIterator<EstateView> it(m_estateViews); *it; ++it)
+ if ((estateView = dynamic_cast<EstateView*>(*it)))
+ estateView->setViewProperties(indicateUnowned, highliteUnowned, darkenMortgaged, quartzEffects);
+}
+
+int AtlantikBoard::heightForWidth(int width)
+{
+ return width;
+}
+
+EstateView *AtlantikBoard::findEstateView(Estate *estate)
+{
+ EstateView *estateView;
+ for (QPtrListIterator<EstateView> i(m_estateViews); *i; ++i)
+ {
+ estateView = dynamic_cast<EstateView*>(*i);
+ if (estateView && estateView->estate() == estate)
+ return estateView;
+ }
+ return 0;
+}
+
+void AtlantikBoard::addEstateView(Estate *estate, bool indicateUnowned, bool highliteUnowned, bool darkenMortgaged, bool quartzEffects)
+{
+ QString icon = QString();
+ int estateId = estate->id();
+ EstateOrientation orientation = North;
+ int sideLen = m_gridLayout->numRows() - 1;
+
+ if (estateId < sideLen)
+ orientation = North;
+ else if (estateId < 2*sideLen)
+ orientation = East;
+ else if (estateId < 3*sideLen)
+ orientation = South;
+ else //if (estateId < 4*sideLen)
+ orientation = West;
+
+ EstateView *estateView = new EstateView(estate, orientation, icon, indicateUnowned, highliteUnowned, darkenMortgaged, quartzEffects, this, "estateview");
+ m_estateViews.append(estateView);
+
+ connect(estate, SIGNAL(changed()), estateView, SLOT(estateChanged()));
+ connect(estateView, SIGNAL(estateToggleMortgage(Estate *)), estate, SIGNAL(estateToggleMortgage(Estate *)));
+ connect(estateView, SIGNAL(LMBClicked(Estate *)), estate, SIGNAL(LMBClicked(Estate *)));
+ connect(estateView, SIGNAL(estateHouseBuy(Estate *)), estate, SIGNAL(estateHouseBuy(Estate *)));
+ connect(estateView, SIGNAL(estateHouseSell(Estate *)), estate, SIGNAL(estateHouseSell(Estate *)));
+ connect(estateView, SIGNAL(newTrade(Player *)), estate, SIGNAL(newTrade(Player *)));
+
+ // Designer has its own LMBClicked slot
+ if (m_mode == Play)
+ connect(estateView, SIGNAL(LMBClicked(Estate *)), this, SLOT(prependEstateDetails(Estate *)));
+
+ if (estateId<sideLen)
+ m_gridLayout->addWidget(estateView, sideLen, sideLen-estateId);
+ else if (estateId<2*sideLen)
+ m_gridLayout->addWidget(estateView, 2*sideLen-estateId, 0);
+ else if (estateId<3*sideLen)
+ m_gridLayout->addWidget(estateView, 0, estateId-2*sideLen);
+ else
+ m_gridLayout->addWidget(estateView, estateId-3*sideLen, sideLen);
+
+ estateView->show();
+
+ if (m_atlanticCore)
+ {
+ Player *player = 0;
+ QPtrList<Player> playerList = m_atlanticCore->players();
+ for (QPtrListIterator<Player> it(playerList); (player = *it) ; ++it)
+ if (player->location() == estate)
+ addToken(player);
+ }
+}
+
+void AtlantikBoard::addAuctionWidget(Auction *auction)
+{
+ AuctionWidget *auctionW = new AuctionWidget(m_atlanticCore, auction, this);
+ m_lastServerDisplay = auctionW;
+ m_displayQueue.prepend(auctionW);
+ updateCenter();
+
+ connect(auction, SIGNAL(completed()), this, SLOT(displayDefault()));
+}
+
+Token *AtlantikBoard::findToken(Player *player)
+{
+ Token *token = 0;
+ for (QPtrListIterator<Token> it(m_tokens); (token = *it) ; ++it)
+ if (token->player() == player)
+ return token;
+ return 0;
+}
+
+void AtlantikBoard::addToken(Player *player)
+{
+ if (!player->location())
+ {
+ kdDebug() << "addToken ignored - estateView null" << endl;
+ return;
+ }
+
+ Player *playerSelf = 0;
+ if (m_atlanticCore)
+ playerSelf = m_atlanticCore->playerSelf();
+
+ if (playerSelf && playerSelf->game() != player->game() )
+ {
+ kdDebug() << "addToken ignored - not in same game as playerSelf" << endl;
+ return;
+ }
+
+ kdDebug() << "addToken" << endl;
+
+ Token *token = new Token(player, this, "token");
+ m_tokens.append(token);
+ connect(player, SIGNAL(changed(Player *)), token, SLOT(playerChanged()));
+
+ jumpToken(token);
+
+ // Timer to reinit the gameboard _after_ event loop
+ QTimer::singleShot(100, this, SLOT(slotResizeAftermath()));
+}
+
+void AtlantikBoard::playerChanged(Player *player)
+{
+ kdDebug() << "playerChanged: playerLoc " << (player->location() ? player->location()->name() : "none") << endl;
+
+ Player *playerSelf = 0;
+ if (m_atlanticCore)
+ playerSelf = m_atlanticCore->playerSelf();
+
+ // Update token
+ Token *token = findToken(player);
+ if (token)
+ {
+ kdDebug() << "playerChanged: tokenLoc " << (token->location() ? token->location()->name() : "none") << endl;
+ if (player->isBankrupt() || (playerSelf && playerSelf->game() != player->game()) )
+ token->hide();
+ if (player->hasTurn())
+ token->raise();
+
+ bool jump = false, move = false;
+
+ if (token->inJail() != player->inJail())
+ {
+ token->setInJail(player->inJail());
+
+ // If any status such as jail is ever allowed to
+ // change in the future, during movement, this needs
+ // to be addressed in moveToken and subsequent steps.
+ if (token != m_movingToken)
+ jump = true;
+ }
+
+ if (token->location() != player->location())
+ {
+ token->setLocation(player->location());
+ jump = true;
+ }
+
+ if (player->destination() && token->destination() != player->destination())
+ {
+ if (m_animateTokens)
+ {
+ token->setDestination(player->destination());
+ move = true;
+ }
+ else
+ {
+ token->setLocation(player->destination());
+ jump = true;
+ }
+ }
+
+ if (move)
+ moveToken(token);
+ else if (jump)
+ jumpToken(token);
+ }
+ else
+ addToken(player);
+}
+
+void AtlantikBoard::removeToken(Player *player)
+{
+ Token *token = findToken(player);
+ if (!token)
+ return;
+
+ if (token == m_movingToken)
+ {
+ m_timer->stop();
+ m_movingToken = 0;
+ }
+
+ m_tokens.remove(token);
+}
+
+void AtlantikBoard::jumpToken(Token *token)
+{
+ if (!token || !token->location())
+ return;
+
+ kdDebug() << "jumpToken to " << token->location()->name() << endl;
+
+ QPoint tGeom = calculateTokenDestination(token);
+ token->setGeometry(tGeom.x(), tGeom.y(), token->width(), token->height());
+
+ Player *player = token->player();
+ if (player)
+ {
+ player->setLocation(token->location());
+ player->setDestination(0);
+
+ if (token->isHidden() && !player->isBankrupt())
+ token->show();
+ }
+
+ if (token == m_movingToken)
+ {
+ m_timer->stop();
+
+ if (!m_resumeTimer)
+ m_movingToken = 0;
+ }
+
+ emit tokenConfirmation(token->location());
+}
+
+void AtlantikBoard::moveToken(Token *token)
+{
+ kdDebug() << "moveToken to " << token->destination()->name() << endl;
+
+ m_movingToken = token;
+
+ // Start timer
+ m_timer->start(15);
+}
+
+QPoint AtlantikBoard::calculateTokenDestination(Token *token, Estate *eDest)
+{
+ if (!eDest)
+ eDest = token->location();
+
+ EstateView *evDest = findEstateView(eDest);
+ if (!evDest)
+ return QPoint(0, 0);
+
+ int x = 0, y = 0;
+ if (token->player()->inJail())
+ {
+ x = evDest->geometry().right() - token->width() - 2;
+ y = evDest->geometry().top();
+ }
+ else
+ {
+ x = evDest->geometry().center().x() - (token->width()/2);
+ y = evDest->geometry().center().y() - (token->height()/2);
+
+/*
+ // Re-center because of EstateView headers
+ switch(evDest->orientation())
+ {
+ case North:
+ y += evDest->height()/8; break;
+ case East:
+ x -= evDest->width()/8; break;
+ case South:
+ y -= evDest->height()/8; break;
+ case West:
+ x += evDest->width()/8; break;
+ }
+*/
+ }
+ return QPoint(x, y);
+}
+
+void AtlantikBoard::slotMoveToken()
+{
+ // Requires a core with estates to operate on
+ if (!m_atlanticCore)
+ {
+ kdDebug() << "slotMoveToken ignored - no atlanticCore" << endl;
+ return;
+ }
+
+ // Do we actually have a token to move?
+ if (!m_movingToken)
+ {
+ m_timer->stop();
+ return;
+ }
+
+ // Where are we?
+ int xCurrent = m_movingToken->geometry().x();
+ int yCurrent = m_movingToken->geometry().y();
+
+ // Where do we want to go today?
+ Estate *eDest = m_atlanticCore->estateAfter(m_movingToken->location());
+ QPoint tGeom = calculateTokenDestination(m_movingToken, eDest);
+
+ int xDest = tGeom.x();
+ int yDest = tGeom.y();
+
+ if (xDest - xCurrent > 1)
+ xDest = xCurrent + 2;
+ else if (xCurrent - xDest > 1)
+ xDest = xCurrent - 2;
+ else
+ xDest = xCurrent;
+
+ if (yDest - yCurrent > 1)
+ yDest = yCurrent + 2;
+ else if (yCurrent - yDest > 1)
+ yDest = yCurrent - 2;
+ else
+ yDest = yCurrent;
+
+// kdDebug() << "TOKEN: at " << xCurrent << "," << yCurrent << " and going to " << xDest << "," << yDest << endl;
+
+ if (xCurrent != xDest || yCurrent != yDest)
+ {
+ m_movingToken->setGeometry(xDest, yDest, m_movingToken->width(), m_movingToken->height());
+ return;
+ }
+
+ // We have arrived at our destination!
+ m_movingToken->setLocation(eDest);
+ m_movingToken->player()->setLocation(eDest);
+ emit tokenConfirmation(eDest);
+
+ // We have arrived at our _final_ destination!
+ if (eDest == m_movingToken->destination())
+ {
+ m_movingToken->setDestination(0);
+ m_movingToken->player()->setDestination(0);
+
+ m_timer->stop();
+ m_movingToken = 0;
+ }
+}
+
+void AtlantikBoard::resizeEvent(QResizeEvent *)
+{
+ // Stop moving tokens, slotResizeAftermath will re-enable this
+ if (m_timer!=0 && m_timer->isActive())
+ {
+ m_timer->stop();
+ m_resumeTimer=true;
+ }
+
+/*
+ // Adjust spacer to make sure board stays a square
+ int q = e->size().width() - e->size().height();
+ if (q > 0)
+ {
+ QSize s(q, 0);
+ spacer->setFixedSize(s);
+ }
+ else
+ {
+ QSize s(0, -q);
+ spacer->setFixedSize(s);
+ }
+*/
+ // Timer to reinit the gameboard _after_ resizeEvent
+ QTimer::singleShot(0, this, SLOT(slotResizeAftermath()));
+}
+
+void AtlantikBoard::slotResizeAftermath()
+{
+ kdDebug() << "AtlantikBoard::slotResizeAftermath" << endl;
+ // Move tokens back to their last known location (this has to be done
+ // _after_ resizeEvent has returned to make sure we have the correct
+ // adjusted estate geometries.
+
+ Token *token = 0;
+ for (QPtrListIterator<Token> it(m_tokens); (token = *it) ; ++it)
+ jumpToken(token);
+
+ // Restart the timer that was stopped in resizeEvent
+ if (m_resumeTimer && m_timer!=0 && !m_timer->isActive())
+ {
+ m_timer->start(15);
+ m_resumeTimer=false;
+ }
+}
+
+void AtlantikBoard::displayDefault()
+{
+ switch(m_displayQueue.count())
+ {
+ case 0:
+ m_displayQueue.prepend(new QWidget(this));
+ break;
+ case 1:
+ if (EstateDetails *display = dynamic_cast<EstateDetails*>(m_lastServerDisplay))
+ display->setEstate(0);
+ break;
+ default:
+ if (m_displayQueue.getFirst() == m_lastServerDisplay)
+ m_lastServerDisplay = 0;
+ m_displayQueue.removeFirst();
+ break;
+ }
+ updateCenter();
+}
+
+void AtlantikBoard::displayButton(QString command, QString caption, bool enabled)
+{
+ if (EstateDetails *display = dynamic_cast<EstateDetails*>(m_lastServerDisplay))
+ display->addButton(command, caption, enabled);
+}
+
+void AtlantikBoard::addCloseButton()
+{
+ EstateDetails *eDetails = 0;
+ if ((eDetails = dynamic_cast<EstateDetails*>(m_lastServerDisplay)) && eDetails != m_displayQueue.getLast())
+ eDetails->addCloseButton();
+}
+
+void AtlantikBoard::insertDetails(QString text, bool clearText, bool clearButtons, Estate *estate)
+{
+ EstateDetails *eDetails = 0;
+
+ if ((eDetails = dynamic_cast<EstateDetails*>(m_lastServerDisplay)))
+ {
+ if (clearText)
+ eDetails->setText(text);
+ else
+ eDetails->appendText(text);
+
+ if (clearButtons)
+ eDetails->clearButtons();
+
+ eDetails->setEstate(estate);
+ return;
+ }
+
+ if (m_displayQueue.getFirst() != m_lastServerDisplay)
+ m_displayQueue.removeFirst();
+
+ eDetails = new EstateDetails(estate, text, this);
+ m_lastServerDisplay = eDetails;
+ connect(eDetails, SIGNAL(buttonCommand(QString)), this, SIGNAL(buttonCommand(QString)));
+ connect(eDetails, SIGNAL(buttonClose()), this, SLOT(displayDefault()));
+
+ m_displayQueue.insert(0, eDetails);
+ updateCenter();
+}
+
+void AtlantikBoard::prependEstateDetails(Estate *estate)
+{
+ if (!estate)
+ return;
+
+ EstateDetails *eDetails = 0;
+
+ if (m_displayQueue.getFirst() == m_lastServerDisplay)
+ {
+ eDetails = new EstateDetails(estate, QString::null, this);
+ m_displayQueue.prepend(eDetails);
+
+ connect(eDetails, SIGNAL(buttonCommand(QString)), this, SIGNAL(buttonCommand(QString)));
+ connect(eDetails, SIGNAL(buttonClose()), this, SLOT(displayDefault()));
+ }
+ else
+ {
+ eDetails = dynamic_cast<EstateDetails*> ( m_displayQueue.getFirst() );
+ if (eDetails)
+ {
+ eDetails->setEstate(estate);
+ eDetails->setText( QString::null );
+ // eDetails->clearButtons();
+ }
+ else
+ {
+ kdDebug() << "manual estatedetails with first in queue neither server nor details" << endl;
+ return;
+ }
+ }
+
+ eDetails->addDetails();
+ eDetails->addCloseButton();
+
+ updateCenter();
+}
+
+void AtlantikBoard::updateCenter()
+{
+ QWidget *center = m_displayQueue.getFirst();
+ m_gridLayout->addMultiCellWidget(center, 1, m_gridLayout->numRows()-2, 1, m_gridLayout->numCols()-2);
+ center->show();
+}
+
+QWidget *AtlantikBoard::centerWidget()
+{
+ return m_displayQueue.getFirst();
+}