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.
602 lines
15 KiB
602 lines
15 KiB
// 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 <tqpainter.h>
|
|
#include <tqstring.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, TQWidget *parent, const char *name) : TQWidget(parent, name)
|
|
{
|
|
m_atlanticCore = atlanticCore;
|
|
m_maxEstates = maxEstates;
|
|
m_mode = mode;
|
|
m_animateTokens = false;
|
|
m_lastServerDisplay = 0;
|
|
|
|
setMinimumSize(TQSize(500, 500));
|
|
|
|
int sideLen = maxEstates/4;
|
|
|
|
// Animated token movement
|
|
m_movingToken = 0;
|
|
m_timer = new TQTimer(this);
|
|
connect(m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotMoveToken()));
|
|
m_resumeTimer = false;
|
|
|
|
m_gridLayout = new TQGridLayout(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 TQWidget(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 (TQPtrListIterator<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 (TQPtrListIterator<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)
|
|
{
|
|
TQString icon = TQString();
|
|
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, TQT_SIGNAL(changed()), estateView, TQT_SLOT(estateChanged()));
|
|
connect(estateView, TQT_SIGNAL(estateToggleMortgage(Estate *)), estate, TQT_SIGNAL(estateToggleMortgage(Estate *)));
|
|
connect(estateView, TQT_SIGNAL(LMBClicked(Estate *)), estate, TQT_SIGNAL(LMBClicked(Estate *)));
|
|
connect(estateView, TQT_SIGNAL(estateHouseBuy(Estate *)), estate, TQT_SIGNAL(estateHouseBuy(Estate *)));
|
|
connect(estateView, TQT_SIGNAL(estateHouseSell(Estate *)), estate, TQT_SIGNAL(estateHouseSell(Estate *)));
|
|
connect(estateView, TQT_SIGNAL(newTrade(Player *)), estate, TQT_SIGNAL(newTrade(Player *)));
|
|
|
|
// Designer has its own LMBClicked slot
|
|
if (m_mode == Play)
|
|
connect(estateView, TQT_SIGNAL(LMBClicked(Estate *)), this, TQT_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;
|
|
TQPtrList<Player> playerList = m_atlanticCore->players();
|
|
for (TQPtrListIterator<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, TQT_SIGNAL(completed()), this, TQT_SLOT(displayDefault()));
|
|
}
|
|
|
|
Token *AtlantikBoard::findToken(Player *player)
|
|
{
|
|
Token *token = 0;
|
|
for (TQPtrListIterator<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, TQT_SIGNAL(changed(Player *)), token, TQT_SLOT(playerChanged()));
|
|
|
|
jumpToken(token);
|
|
|
|
// Timer to reinit the gameboard _after_ event loop
|
|
TQTimer::singleShot(100, this, TQT_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;
|
|
|
|
TQPoint 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);
|
|
}
|
|
|
|
TQPoint AtlantikBoard::calculateTokenDestination(Token *token, Estate *eDest)
|
|
{
|
|
if (!eDest)
|
|
eDest = token->location();
|
|
|
|
EstateView *evDest = findEstateView(eDest);
|
|
if (!evDest)
|
|
return TQPoint(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 TQPoint(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());
|
|
TQPoint 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(TQResizeEvent *)
|
|
{
|
|
// 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)
|
|
{
|
|
TQSize s(q, 0);
|
|
spacer->setFixedSize(s);
|
|
}
|
|
else
|
|
{
|
|
TQSize s(0, -q);
|
|
spacer->setFixedSize(s);
|
|
}
|
|
*/
|
|
// Timer to reinit the gameboard _after_ resizeEvent
|
|
TQTimer::singleShot(0, this, TQT_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 (TQPtrListIterator<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 TQWidget(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(TQString command, TQString 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(TQString 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, TQT_SIGNAL(buttonCommand(TQString)), this, TQT_SIGNAL(buttonCommand(TQString)));
|
|
connect(eDetails, TQT_SIGNAL(buttonClose()), this, TQT_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, TQString(), this);
|
|
m_displayQueue.prepend(eDetails);
|
|
|
|
connect(eDetails, TQT_SIGNAL(buttonCommand(TQString)), this, TQT_SIGNAL(buttonCommand(TQString)));
|
|
connect(eDetails, TQT_SIGNAL(buttonClose()), this, TQT_SLOT(displayDefault()));
|
|
}
|
|
else
|
|
{
|
|
eDetails = dynamic_cast<EstateDetails*> ( m_displayQueue.getFirst() );
|
|
if (eDetails)
|
|
{
|
|
eDetails->setEstate(estate);
|
|
eDetails->setText( TQString() );
|
|
// eDetails->clearButtons();
|
|
}
|
|
else
|
|
{
|
|
kdDebug() << "manual estatedetails with first in queue neither server nor details" << endl;
|
|
return;
|
|
}
|
|
}
|
|
|
|
eDetails->addDetails();
|
|
eDetails->addCloseButton();
|
|
|
|
updateCenter();
|
|
}
|
|
|
|
void AtlantikBoard::updateCenter()
|
|
{
|
|
TQWidget *center = m_displayQueue.getFirst();
|
|
m_gridLayout->addMultiCellWidget(center, 1, m_gridLayout->numRows()-2, 1, m_gridLayout->numCols()-2);
|
|
center->show();
|
|
}
|
|
|
|
TQWidget *AtlantikBoard::centerWidget()
|
|
{
|
|
return m_displayQueue.getFirst();
|
|
}
|