File indexing completed on 2023-12-03 11:03:42
0001 // Copyright (c) 2002-2004 Rob Kaper <cap@capsi.com> 0002 // 0003 // This library is free software; you can redistribute it and/or 0004 // modify it under the terms of the GNU Lesser General Public 0005 // License version 2.1 as published by the Free Software Foundation. 0006 // 0007 // This library is distributed in the hope that it will be useful, 0008 // but WITHOUT ANY WARRANTY; without even the implied warranty of 0009 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0010 // Lesser General Public License for more details. 0011 // 0012 // You should have received a copy of the GNU Lesser General Public License 0013 // along with this library; see the file COPYING.LIB. If not, write to 0014 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0015 // Boston, MA 02110-1301, USA. 0016 0017 #include <iostream> 0018 0019 #include <qtextcodec.h> 0020 #include <QTimer> 0021 #include <QTcpSocket> 0022 #include <QHostAddress> 0023 0024 #include <klocalizedstring.h> 0025 0026 #include <atlantic_core.h> 0027 #include <auction.h> 0028 #include <card.h> 0029 #include <configoption.h> 0030 #include <estate.h> 0031 #include <estategroup.h> 0032 #include <game.h> 0033 #include <player.h> 0034 #include <trade.h> 0035 0036 #include "atlantik_network.h" 0037 0038 #include <libatlantikclient_debug.h> 0039 0040 AtlantikNetwork::AtlantikNetwork(AtlanticCore *atlanticCore) 0041 : QObject() 0042 , m_atlanticCore(atlanticCore) 0043 , m_monopdsocket(nullptr) 0044 , m_playerId(-1) 0045 { 0046 reset(); 0047 } 0048 0049 AtlantikNetwork::~AtlantikNetwork(void) 0050 { 0051 disconnect(); 0052 } 0053 0054 void AtlantikNetwork::disconnect() 0055 { 0056 if (m_monopdsocket) { 0057 m_monopdstream.setDevice(nullptr); 0058 m_monopdsocket->close(); 0059 delete m_monopdsocket; 0060 m_monopdsocket = nullptr; 0061 } 0062 } 0063 0064 void AtlantikNetwork::reset() 0065 { 0066 disconnect(); 0067 m_monopdsocket = new QTcpSocket(this); 0068 m_monopdsocket->setSocketOption(QAbstractSocket::LowDelayOption, true); 0069 0070 connect(m_monopdsocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(slotConnectionFailed(QAbstractSocket::SocketError))); 0071 connect(m_monopdsocket, SIGNAL(connected()), this, SLOT(slotConnectionSuccess())); 0072 connect(m_monopdsocket, SIGNAL(hostFound()), this, SLOT(slotLookupFinished())); 0073 connect(m_monopdsocket, SIGNAL(disconnected()), this, SLOT(slotDisconnected())); 0074 } 0075 0076 QString AtlantikNetwork::host() const 0077 { 0078 return isConnected() 0079 ? m_monopdsocket->peerAddress().toString() 0080 : QString(); 0081 } 0082 0083 int AtlantikNetwork::port() const 0084 { 0085 return isConnected() 0086 ? m_monopdsocket->peerPort() 0087 : -1; 0088 } 0089 0090 bool AtlantikNetwork::isConnected() const 0091 { 0092 return m_monopdsocket && m_monopdsocket->state() == QAbstractSocket::ConnectedState; 0093 } 0094 0095 void AtlantikNetwork::slotwriteData(const QString &msg) 0096 { 0097 Q_EMIT networkEvent(msg, ET_NetOut); 0098 0099 } 0100 0101 void AtlantikNetwork::slotRead() 0102 { 0103 if (!m_monopdstream.device()) 0104 return; 0105 0106 const QString line = m_monopdstream.readLine(); 0107 if (!line.isNull()) 0108 { 0109 0110 processMsg(line); 0111 0112 // There might be more data; Do we really need this? 0113 QTimer::singleShot(0, this, SLOT(slotRead())); 0114 } 0115 else 0116 { 0117 // Maximum message size. Messages won't get bigger than 32k anyway, so 0118 // if we didn't receive a newline by now, we probably won't anyway. 0119 if (m_monopdsocket->bytesAvailable() > (1024 * 32)) 0120 m_monopdsocket->flush(); 0121 } 0122 } 0123 0124 0125 0126 void AtlantikNetwork::serverConnect(const QString &host, int port) 0127 { 0128 Q_EMIT msgStatus(i18n("Connecting to %1:%2...", host, QString::number(port)), ET_NetGeneric); 0129 m_host = host; 0130 m_port = port; 0131 m_monopdsocket->connectToHost(host, port); 0132 } 0133 0134 void AtlantikNetwork::slotLookupFinished() 0135 { 0136 Q_EMIT msgStatus(i18n("Server host name lookup finished..."), ET_NetGeneric); 0137 } 0138 0139 void AtlantikNetwork::slotConnectionSuccess() 0140 { 0141 Q_EMIT msgStatus(i18n("Connected to %1:%2.", m_host, QString::number(m_port)), ET_NetConnected); 0142 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0143 m_monopdstream.setCodec(QTextCodec::codecForName("UTF-8")); 0144 #endif 0145 m_monopdstream.setDevice(m_monopdsocket); 0146 connect(m_monopdsocket, SIGNAL(readyRead()), this, SLOT(slotRead())); 0147 0148 Q_EMIT connectionSuccess(); 0149 } 0150 0151 void AtlantikNetwork::slotConnectionFailed(QAbstractSocket::SocketError error) 0152 { 0153 Q_EMIT connectionFailed(error); 0154 Q_EMIT msgStatus(i18n("Connection failed! Error code: %1", error), ET_NetError); 0155 } 0156 0157 void AtlantikNetwork::slotDisconnected() 0158 { 0159 Q_EMIT msgStatus(i18n("Disconnected from %1:%2.", m_host, QString::number(m_port)), ET_NetGeneric); 0160 Q_EMIT disconnected(); 0161 } 0162 0163 void AtlantikNetwork::writeData(const QString &data) { 0164 0165 Q_EMIT networkEvent(data, ET_NetOut); 0166 //data.append("\n"); 0167 m_monopdstream << data << '\n'; 0168 m_monopdstream.flush(); 0169 qCDebug(LIBATLANTIKCLIENT_LOG) << "writing data:" << data; 0170 0171 } 0172 0173 //Atlantik-specific stuff follows here 0174 //Perhaps it is better to separate this out in another class 0175 0176 void AtlantikNetwork::rollDice() 0177 { 0178 writeData(QStringLiteral(".r")); 0179 } 0180 0181 void AtlantikNetwork::buyEstate() 0182 { 0183 writeData(QStringLiteral(".eb")); 0184 } 0185 0186 void AtlantikNetwork::auctionEstate() 0187 { 0188 writeData(QStringLiteral(".ea")); 0189 } 0190 0191 void AtlantikNetwork::startGame() 0192 { 0193 writeData(QStringLiteral(".gs")); 0194 } 0195 0196 void AtlantikNetwork::reconnect(const QString &cookie) 0197 { 0198 writeData(QStringLiteral(".R") + cookie); 0199 } 0200 0201 void AtlantikNetwork::leaveGame() 0202 { 0203 writeData(QStringLiteral(".gx")); 0204 } 0205 0206 void AtlantikNetwork::endTurn() 0207 { 0208 writeData(QStringLiteral(".E")); 0209 } 0210 0211 void AtlantikNetwork::setName(const QString &name) 0212 { 0213 // Almost deprecated, will be replaced by libmonopdprotocol 0214 writeData(QStringLiteral(".n%1").arg(name)); 0215 qCDebug(LIBATLANTIKCLIENT_LOG) << "set name to:" << name; 0216 } 0217 0218 void AtlantikNetwork::tokenConfirmation(Estate *estate) 0219 { 0220 writeData(QStringLiteral(".t%1").arg(estate ? estate->id() : -1)); 0221 } 0222 0223 void AtlantikNetwork::estateToggleMortgage(Estate *estate) 0224 { 0225 writeData(QStringLiteral(".em%1").arg(estate ? estate->id() : -1)); 0226 } 0227 0228 void AtlantikNetwork::estateHouseBuy(Estate *estate) 0229 { 0230 writeData(QStringLiteral(".hb%1").arg(estate ? estate->id() : -1)); 0231 } 0232 0233 void AtlantikNetwork::estateHouseSell(Estate *estate) 0234 { 0235 writeData(QStringLiteral(".hs%1").arg(estate ? estate->id() : -1)); 0236 } 0237 0238 void AtlantikNetwork::estateSell(Estate *estate) 0239 { 0240 writeData(QStringLiteral(".es%1").arg(estate ? estate->id() : -1)); 0241 } 0242 0243 void AtlantikNetwork::newGame(const QString &gameType) 0244 { 0245 writeData(QStringLiteral(".gn%1").arg(gameType)); 0246 } 0247 0248 void AtlantikNetwork::joinGame(int gameId) 0249 { 0250 writeData(QStringLiteral(".gj%1").arg(gameId)); 0251 qCDebug(LIBATLANTIKCLIENT_LOG) << "joining game" << gameId; 0252 } 0253 0254 void AtlantikNetwork::watchGame(int gameId) 0255 { 0256 writeData(QStringLiteral(".gS%1").arg(gameId)); 0257 qCDebug(LIBATLANTIKCLIENT_LOG) << "watching game" << gameId; 0258 } 0259 0260 void AtlantikNetwork::cmdChat(const QString &msg) 0261 { 0262 writeData(msg); 0263 } 0264 0265 void AtlantikNetwork::newTrade(Player *player) 0266 { 0267 writeData(QStringLiteral(".Tn%1").arg(player ? player->id() : -1)); 0268 } 0269 0270 void AtlantikNetwork::kickPlayer(Player *player) 0271 { 0272 writeData(QStringLiteral(".gk%1").arg(player ? player->id() : -1)); 0273 } 0274 0275 void AtlantikNetwork::tradeUpdateEstate(Trade *trade, Estate *estate, Player *player) 0276 { 0277 writeData(QStringLiteral(".Te%1:%2:%3").arg(trade ? trade->tradeId() : -1).arg(estate ? estate->id() : -1).arg(player ? player->id() : -1)); 0278 } 0279 0280 void AtlantikNetwork::tradeUpdateMoney(Trade *trade, unsigned int money, Player *pFrom, Player *pTo) 0281 { 0282 writeData(QStringLiteral(".Tm%1:%2:%3:%4").arg(trade ? trade->tradeId() : -1).arg(pFrom ? pFrom->id() : -1).arg(pTo ? pTo->id() : -1).arg(money)); 0283 } 0284 0285 void AtlantikNetwork::tradeUpdateCard(Trade *trade, Card *card, Player *pTo) 0286 { 0287 writeData(QStringLiteral(".Tc%1:%2:%3").arg(trade ? trade->tradeId() : -1).arg(card ? card->cardId() : -1).arg(pTo ? pTo->id() : -1)); 0288 } 0289 0290 void AtlantikNetwork::tradeReject(Trade *trade) 0291 { 0292 writeData(QStringLiteral(".Tr%1").arg(trade ? trade->tradeId() : -1)); 0293 } 0294 0295 void AtlantikNetwork::tradeAccept(Trade *trade) 0296 { 0297 writeData(QStringLiteral(".Ta%1:%2").arg(trade ? trade->tradeId() : -1).arg(trade ? trade->revision() : -1)); 0298 } 0299 0300 void AtlantikNetwork::auctionBid(Auction *auction, int amount) 0301 { 0302 writeData(QStringLiteral(".ab%1:%2").arg(auction ? auction->auctionId() : -1).arg(amount)); 0303 } 0304 0305 void AtlantikNetwork::setImage(const QString &name) 0306 { 0307 writeData(QStringLiteral(".pi%1").arg(name)); 0308 } 0309 0310 void AtlantikNetwork::jailPay() 0311 { 0312 writeData(QStringLiteral(".jp")); 0313 } 0314 0315 void AtlantikNetwork::jailRoll() 0316 { 0317 writeData(QStringLiteral(".jr")); 0318 } 0319 0320 void AtlantikNetwork::jailCard() 0321 { 0322 writeData(QStringLiteral(".jc")); 0323 } 0324 0325 void AtlantikNetwork::changeOption(int configId, const QString &value) 0326 { 0327 writeData(QStringLiteral(".gc%1:%2").arg(configId).arg(value)); 0328 } 0329 0330 0331 void AtlantikNetwork::processMsg(const QString &msg) { 0332 Q_EMIT networkEvent(msg, ET_NetIn); 0333 qCDebug(LIBATLANTIKCLIENT_LOG) << msg; 0334 QDomDocument dom; 0335 dom.setContent(msg); 0336 QDomElement e = dom.documentElement(); 0337 if (e.tagName() != QLatin1String("monopd")) { 0338 // Invalid data, request full update from server 0339 writeData(QStringLiteral(".f")); 0340 return; 0341 } 0342 QDomNode n = e.firstChild(); 0343 processNode(n); 0344 if (LIBATLANTIKCLIENT_LOG().isDebugEnabled()) 0345 m_atlanticCore->printDebug(); 0346 } 0347 0348 void AtlantikNetwork::processNode(QDomNode n) { 0349 QDomAttr a; 0350 0351 for ( ; !n.isNull() ; n = n.nextSibling() ) { 0352 QDomElement e = n.toElement(); 0353 if(!e.isNull()) { 0354 if (e.tagName() == QLatin1String("server")) { 0355 a = e.attributeNode(QStringLiteral("version")); 0356 if ( !a.isNull() ) 0357 m_serverVersion = a.value(); 0358 qCDebug(LIBATLANTIKCLIENT_LOG) << "receivedHandshake"; 0359 Q_EMIT receivedHandshake(); 0360 } else if (e.tagName() == QLatin1String("msg")) { 0361 a = e.attributeNode(QStringLiteral("type")); 0362 if (!a.isNull()) { 0363 if (a.value() == QLatin1String("error")) 0364 Q_EMIT msgError(e.attributeNode(QStringLiteral("value")).value()); 0365 else if (a.value() == QLatin1String("info")) 0366 Q_EMIT msgInfo(e.attributeNode(QStringLiteral("value")).value()); 0367 else if (a.value() == QLatin1String("chat")) 0368 Q_EMIT msgChat(e.attributeNode(QStringLiteral("author")).value(), e.attributeNode(QStringLiteral("value")).value()); 0369 } 0370 } else if (e.tagName() == QLatin1String("display")) { 0371 Estate *estate = nullptr; 0372 bool hasEstateId = false; 0373 0374 a = e.attributeNode(QStringLiteral("estateid")); 0375 if (!a.isNull()) { 0376 estate = m_atlanticCore->findEstate(a.value().toInt()); 0377 hasEstateId = true; 0378 } 0379 if (hasEstateId) { 0380 Q_EMIT displayDetails(e.attributeNode(QStringLiteral("text")).value(), e.attributeNode(QStringLiteral("cleartext")).value().toInt(), e.attributeNode(QStringLiteral("clearbuttons")).value().toInt(), estate); 0381 } else { 0382 Q_EMIT displayText(e.attributeNode(QStringLiteral("text")).value(), e.attributeNode(QStringLiteral("cleartext")).value().toInt(), e.attributeNode(QStringLiteral("clearbuttons")).value().toInt()); 0383 } 0384 0385 bool hasButtons = false; 0386 for( QDomNode nButtons = n.firstChild() ; !nButtons.isNull() ; nButtons = nButtons.nextSibling() ) { 0387 QDomElement eButton = nButtons.toElement(); 0388 if (!eButton.isNull() && eButton.tagName() == QLatin1String("button")) { 0389 Q_EMIT addCommandButton(eButton.attributeNode(QStringLiteral("command")).value(), eButton.attributeNode(QStringLiteral("caption")).value(), eButton.attributeNode(QStringLiteral("enabled")).value().toInt()); 0390 hasButtons = true; 0391 } 0392 } 0393 0394 if (!hasButtons) 0395 Q_EMIT addCloseButton(); 0396 } else if (e.tagName() == QLatin1String("client")) { 0397 a = e.attributeNode(QStringLiteral("playerid")); 0398 if (!a.isNull()) 0399 m_playerId = a.value().toInt(); 0400 0401 a = e.attributeNode(QStringLiteral("cookie")); 0402 if (!a.isNull()) 0403 Q_EMIT clientCookie(a.value()); 0404 } else if (e.tagName() == QLatin1String("configupdate")) { 0405 Game *game = nullptr; 0406 a = e.attributeNode(QStringLiteral("gameid")); 0407 if (!a.isNull()) { 0408 int gameId = a.value().toInt(); 0409 game = m_atlanticCore->findGame(gameId); 0410 } 0411 0412 a = e.attributeNode(QStringLiteral("configid")); 0413 if (!a.isNull() && game) { 0414 int configId = a.value().toInt(); 0415 ConfigOption *configOption = game->findConfigOption(configId); 0416 bool created = false; 0417 if (!configOption) { 0418 configOption = new ConfigOption(configId); 0419 created = true; 0420 } 0421 0422 a = e.attributeNode(QStringLiteral("name")); 0423 if (configOption && !a.isNull()) 0424 configOption->setName(a.value()); 0425 0426 a = e.attributeNode(QStringLiteral("description")); 0427 if (configOption && !a.isNull()) 0428 configOption->setDescription(a.value()); 0429 0430 a = e.attributeNode(QStringLiteral("edit")); 0431 if (configOption && !a.isNull()) 0432 configOption->setEdit(a.value().toInt()); 0433 0434 a = e.attributeNode(QStringLiteral("type")); 0435 if (configOption && !a.isNull()) 0436 configOption->setType(a.value()); 0437 0438 a = e.attributeNode(QStringLiteral("value")); 0439 if (configOption && !a.isNull()) 0440 configOption->setValue(a.value()); 0441 0442 configOption->update(); 0443 if (created) 0444 game->addConfigOption(configOption); 0445 } 0446 } else if (e.tagName() == QLatin1String("deletegame")) { 0447 a = e.attributeNode(QStringLiteral("gameid")); 0448 if (!a.isNull()) { 0449 int gameId = a.value().toInt(); 0450 0451 Game *game = m_atlanticCore->findGame(gameId); 0452 if (game) 0453 m_atlanticCore->removeGame(game); 0454 } 0455 } else if (e.tagName() == QLatin1String("gameupdate")) { 0456 int gameId = -1; 0457 0458 a = e.attributeNode(QStringLiteral("gameid")); 0459 if (!a.isNull()) { 0460 gameId = a.value().toInt(); 0461 0462 Player *playerSelf = m_atlanticCore->playerSelf(); 0463 if ( playerSelf && playerSelf->game() ) 0464 qCDebug(LIBATLANTIKCLIENT_LOG) << "gameupdate for" << gameId << "with playerSelf in game" << playerSelf->game()->id(); 0465 else 0466 qCDebug(LIBATLANTIKCLIENT_LOG) << "gameupdate for" << gameId; 0467 0468 0469 Game *game = nullptr; 0470 if (gameId == -1) { 0471 a = e.attributeNode(QStringLiteral("gametype")); 0472 if ( !a.isNull() && !(game = m_atlanticCore->findGame(a.value())) ) 0473 game = m_atlanticCore->newGame(gameId, a.value()); 0474 } else if (!(game = m_atlanticCore->findGame(gameId))) 0475 game = m_atlanticCore->newGame(gameId); 0476 0477 a = e.attributeNode(QStringLiteral("canbejoined")); 0478 if (game && !a.isNull()) 0479 game->setCanBeJoined(a.value().toInt()); 0480 0481 a = e.attributeNode(QStringLiteral("canbewatched")); 0482 if (game && !a.isNull()) 0483 game->setCanBeWatched(a.value().toInt()); 0484 0485 a = e.attributeNode(QStringLiteral("description")); 0486 if (game && !a.isNull()) 0487 game->setDescription(a.value()); 0488 0489 a = e.attributeNode(QStringLiteral("name")); 0490 if (game && !a.isNull()) 0491 game->setName(a.value()); 0492 0493 a = e.attributeNode(QStringLiteral("players")); 0494 if (game && !a.isNull()) 0495 game->setPlayers(a.value().toInt()); 0496 0497 a = e.attributeNode(QStringLiteral("master")); 0498 if (game && !a.isNull()) { 0499 // Ensure setMaster succeeds by creating player if necessary 0500 Player *player = m_atlanticCore->findPlayer( a.value().toInt() ); 0501 if ( !player ) 0502 player = m_atlanticCore->newPlayer( a.value().toInt() ); 0503 game->setMaster( player ); 0504 } 0505 0506 QString status = e.attributeNode(QStringLiteral("status")).value(); 0507 if ( m_serverVersion.left(4) == QLatin1String("0.9.") || (playerSelf && playerSelf->game() == game) ) { 0508 if (status == QLatin1String("config")) 0509 Q_EMIT gameConfig(); 0510 else if (status == QLatin1String("init")) 0511 Q_EMIT gameInit(); 0512 else if (status == QLatin1String("run")) 0513 Q_EMIT gameRun(); 0514 else if (status == QLatin1String("end")) 0515 Q_EMIT gameEnd(); 0516 } 0517 0518 if (game) 0519 game->update(); 0520 } 0521 } else if (e.tagName() == QLatin1String("deleteplayer")) { 0522 a = e.attributeNode(QStringLiteral("playerid")); 0523 if (!a.isNull()) { 0524 int playerId = a.value().toInt(); 0525 0526 Player *player = m_atlanticCore->findPlayer(playerId); 0527 if (player) { 0528 m_playerLocationMap.remove(player); 0529 m_atlanticCore->removePlayer(player); 0530 } 0531 } 0532 } else if (e.tagName() == QLatin1String("playerupdate")) { 0533 int playerId = -1; 0534 0535 a = e.attributeNode(QStringLiteral("playerid")); 0536 if (!a.isNull()) { 0537 playerId = a.value().toInt(); 0538 0539 Player *player; 0540 if (!(player = m_atlanticCore->findPlayer(playerId))) 0541 player = m_atlanticCore->newPlayer( playerId, (m_playerId == playerId) ); 0542 else if (m_playerId == playerId) 0543 m_atlanticCore->setPlayerSelf(player); 0544 0545 // Update player name 0546 a = e.attributeNode(QStringLiteral("name")); 0547 if (player && !a.isNull()) 0548 player->setName(a.value()); 0549 0550 // Update player game 0551 a = e.attributeNode(QStringLiteral("game")); 0552 if (player && !a.isNull()) { 0553 int gameId = a.value().toInt(); 0554 if (gameId == -1) 0555 player->setGame( nullptr ); 0556 else { 0557 // Ensure setGame succeeds by creating game if necessary 0558 Game *game = m_atlanticCore->findGame(a.value().toInt()); 0559 if (!game) 0560 game = m_atlanticCore->newGame(a.value().toInt()); // 0561 player->setGame( game ); 0562 } 0563 } 0564 0565 // Update player host 0566 a = e.attributeNode(QStringLiteral("host")); 0567 if (player && !a.isNull()) 0568 player->setHost(a.value()); 0569 0570 // Update player image/token 0571 a = e.attributeNode(QStringLiteral("image")); 0572 if (player && !a.isNull()) 0573 player->setImage(a.value()); 0574 0575 // Update player money 0576 a = e.attributeNode(QStringLiteral("money")); 0577 if (player && !a.isNull()) 0578 player->setMoney(a.value().toInt()); 0579 0580 a = e.attributeNode(QStringLiteral("bankrupt")); 0581 if (player && !a.isNull()) 0582 player->setBankrupt(a.value().toInt()); 0583 0584 a = e.attributeNode(QStringLiteral("hasdebt")); 0585 if (player && !a.isNull()) 0586 player->setHasDebt(a.value().toInt()); 0587 0588 a = e.attributeNode(QStringLiteral("hasturn")); 0589 if (player && !a.isNull()) 0590 player->setHasTurn(a.value().toInt()); 0591 0592 // Update whether player can roll 0593 a = e.attributeNode(QStringLiteral("can_roll")); 0594 if (player && !a.isNull()) 0595 player->setCanRoll(a.value().toInt()); 0596 0597 // Update whether player can buy 0598 a = e.attributeNode(QStringLiteral("can_buyestate")); 0599 if (player && !a.isNull()) 0600 player->setCanBuy(a.value().toInt()); 0601 0602 // Update whether player can auction 0603 a = e.attributeNode(QStringLiteral("canauction")); 0604 if (player && !a.isNull()) 0605 player->setCanAuction(a.value().toInt()); 0606 0607 // Update whether player can use a card 0608 a = e.attributeNode(QStringLiteral("canusecard")); 0609 if (player && !a.isNull()) 0610 player->setCanUseCard(a.value().toInt()); 0611 0612 // Update whether player is jailed 0613 a = e.attributeNode(QStringLiteral("jailed")); 0614 if (player && !a.isNull()) { 0615 player->setInJail(a.value().toInt()); 0616 // TODO: emit signal with player ptr so board can setText and display something 0617 } 0618 0619 // Update whether player is a spectator 0620 a = e.attributeNode(QStringLiteral("spectator")); 0621 if (player && !a.isNull()) 0622 player->setSpectator(a.value().toInt()); 0623 0624 // Update player location 0625 a = e.attributeNode(QStringLiteral("location")); 0626 if (!a.isNull()) { 0627 m_playerLocationMap.insert(player, a.value().toInt()); 0628 0629 bool directMove = false; 0630 0631 Estate *estate = m_atlanticCore->findEstate(a.value().toInt()); 0632 0633 a = e.attributeNode(QStringLiteral("directmove")); 0634 if (!a.isNull()) 0635 directMove = a.value().toInt(); 0636 0637 if (player && estate) { 0638 if (directMove) 0639 player->setLocation(estate); 0640 else 0641 player->setDestination(estate); 0642 } 0643 } 0644 0645 if (player) 0646 player->update(); 0647 } 0648 } else if (e.tagName() == QLatin1String("estategroupupdate")) { 0649 a = e.attributeNode(QStringLiteral("groupid")); 0650 if (!a.isNull()) { 0651 int groupId = a.value().toInt(); 0652 0653 EstateGroup *estateGroup = nullptr; 0654 bool b_newEstateGroup = false; 0655 0656 if (!(estateGroup = m_atlanticCore->findEstateGroup(groupId))) { 0657 // Create EstateGroup object 0658 estateGroup = m_atlanticCore->newEstateGroup(a.value().toInt()); 0659 b_newEstateGroup = true; 0660 } 0661 0662 a = e.attributeNode(QStringLiteral("name")); 0663 if (estateGroup && !a.isNull()) 0664 estateGroup->setName(a.value()); 0665 0666 // Emit signal so GUI implementations can create view(s) 0667 // TODO: port to atlanticcore and create view there 0668 if (estateGroup) { 0669 if (b_newEstateGroup) 0670 Q_EMIT newEstateGroup(estateGroup); 0671 estateGroup->update(); 0672 } 0673 } 0674 } else if (e.tagName() == QLatin1String("estateupdate")) { 0675 int estateId = -1; 0676 0677 a = e.attributeNode(QStringLiteral("estateid")); 0678 if (!a.isNull()) { 0679 estateId = a.value().toInt(); 0680 0681 Estate *estate = nullptr; 0682 bool b_newEstate = false; 0683 0684 // FIXME: allow any estateId, GUI should not use it to determin its geometry 0685 if (estateId >= 0 && estateId < 100 && !(estate = m_atlanticCore->findEstate(a.value().toInt()))) { 0686 // Create estate object 0687 estate = m_atlanticCore->newEstate(estateId); 0688 b_newEstate = true; 0689 0690 QObject::connect(estate, SIGNAL(estateToggleMortgage(Estate *)), this, SLOT(estateToggleMortgage(Estate *))); 0691 QObject::connect(estate, SIGNAL(estateHouseBuy(Estate *)), this, SLOT(estateHouseBuy(Estate *))); 0692 QObject::connect(estate, SIGNAL(estateHouseSell(Estate *)), this, SLOT(estateHouseSell(Estate *))); 0693 QObject::connect(estate, SIGNAL(estateSell(Estate *)), this, SLOT(estateSell(Estate *))); 0694 QObject::connect(estate, SIGNAL(newTrade(Player *)), this, SLOT(newTrade(Player *))); 0695 0696 // Players without estate should get one 0697 foreach (Player *player, m_atlanticCore->players()) 0698 if (m_playerLocationMap.value(player) == estate->id()) 0699 player->setLocation(estate); 0700 } 0701 0702 a = e.attributeNode(QStringLiteral("name")); 0703 if (estate && !a.isNull()) 0704 estate->setName(a.value()); 0705 0706 a = e.attributeNode(QStringLiteral("color")); 0707 if (estate && !a.isNull() && !a.value().isEmpty()) 0708 estate->setColor(a.value()); 0709 0710 a = e.attributeNode(QStringLiteral("bgcolor")); 0711 if (estate && !a.isNull()) 0712 estate->setBgColor(a.value()); 0713 0714 a = e.attributeNode(QStringLiteral("owner")); 0715 Player *player = m_atlanticCore->findPlayer(a.value().toInt()); 0716 if (estate && !a.isNull()) 0717 estate->setOwner(player); 0718 0719 a = e.attributeNode(QStringLiteral("houses")); 0720 if (estate && !a.isNull()) 0721 estate->setHouses(a.value().toInt()); 0722 0723 a = e.attributeNode(QStringLiteral("mortgaged")); 0724 if (estate && !a.isNull()) 0725 estate->setIsMortgaged(a.value().toInt()); 0726 0727 a = e.attributeNode(QStringLiteral("group")); 0728 if (!a.isNull()) { 0729 EstateGroup *estateGroup = m_atlanticCore->findEstateGroup(a.value().toInt()); 0730 if (estate) 0731 estate->setEstateGroup(estateGroup); 0732 } 0733 0734 a = e.attributeNode(QStringLiteral("can_toggle_mortgage")); 0735 if (estate && !a.isNull()) 0736 estate->setCanToggleMortgage(a.value().toInt()); 0737 0738 a = e.attributeNode(QStringLiteral("can_be_owned")); 0739 if (estate && !a.isNull()) 0740 estate->setCanBeOwned(a.value().toInt()); 0741 0742 a = e.attributeNode(QStringLiteral("can_buy_houses")); 0743 if (estate && !a.isNull()) 0744 estate->setCanBuyHouses(a.value().toInt()); 0745 0746 a = e.attributeNode(QStringLiteral("can_sell_houses")); 0747 if (estate && !a.isNull()) 0748 estate->setCanSellHouses(a.value().toInt()); 0749 0750 a = e.attributeNode(QStringLiteral("price")); 0751 if (estate && !a.isNull()) 0752 estate->setPrice(a.value().toInt()); 0753 0754 a = e.attributeNode(QStringLiteral("houseprice")); 0755 if (estate && !a.isNull()) 0756 estate->setHousePrice(a.value().toInt()); 0757 0758 a = e.attributeNode(QStringLiteral("sellhouseprice")); 0759 if (estate && !a.isNull()) 0760 estate->setHouseSellPrice(a.value().toInt()); 0761 0762 a = e.attributeNode(QStringLiteral("mortgageprice")); 0763 if (estate && !a.isNull()) 0764 estate->setMortgagePrice(a.value().toInt()); 0765 0766 a = e.attributeNode(QStringLiteral("unmortgageprice")); 0767 if (estate && !a.isNull()) 0768 estate->setUnmortgagePrice(a.value().toInt()); 0769 0770 a = e.attributeNode(QStringLiteral("money")); 0771 if (estate && !a.isNull()) 0772 estate->setMoney(a.value().toInt()); 0773 0774 a = e.attributeNode(QStringLiteral("icon")); 0775 if (estate && !a.isNull()) 0776 estate->setIcon(a.value()); 0777 0778 // Emit signal so GUI implementations can create view(s) 0779 // TODO: port to atlanticcore and create view there 0780 if (estate) { 0781 if (b_newEstate) 0782 Q_EMIT newEstate(estate); 0783 estate->update(); 0784 } 0785 } 0786 } else if (e.tagName() == QLatin1String("tradeupdate")) { 0787 a = e.attributeNode(QStringLiteral("tradeid")); 0788 if (!a.isNull()) { 0789 int tradeId = a.value().toInt(); 0790 0791 Trade *trade = m_atlanticCore->findTrade(tradeId); 0792 if (!trade) { 0793 // Create trade object 0794 trade = m_atlanticCore->newTrade(tradeId); 0795 0796 QObject::connect(trade, SIGNAL(updateEstate(Trade *, Estate *, Player *)), this, SLOT(tradeUpdateEstate(Trade *, Estate *, Player *))); 0797 QObject::connect(trade, SIGNAL(updateMoney(Trade *, unsigned int, Player *, Player *)), this, SLOT(tradeUpdateMoney(Trade *, unsigned int, Player *, Player *))); 0798 QObject::connect(trade, SIGNAL(updateCard(Trade *, Card *, Player *)), this, SLOT(tradeUpdateCard(Trade *, Card *, Player *))); 0799 QObject::connect(trade, SIGNAL(reject(Trade *)), this, SLOT(tradeReject(Trade *))); 0800 QObject::connect(trade, SIGNAL(accept(Trade *)), this, SLOT(tradeAccept(Trade *))); 0801 } 0802 0803 a = e.attributeNode(QStringLiteral("revision")); 0804 if (trade && !a.isNull()) 0805 trade->setRevision(a.value().toInt()); 0806 0807 QString type = e.attributeNode(QStringLiteral("type")).value(); 0808 if (type == QLatin1String("new")) { 0809 // TODO: trade->setActor 0810 // Player *player = m_atlanticCore->findPlayer(e.attributeNode(QStringLiteral("actor")).value().toInt()); 0811 // if (trade && player) 0812 // trade->setActor(player); 0813 0814 QDomNode n_player = n.firstChild(); 0815 while(!n_player.isNull()) { 0816 QDomElement e_player = n_player.toElement(); 0817 if (!e_player.isNull() && e_player.tagName() == QLatin1String("tradeplayer")) { 0818 Player *player = m_atlanticCore->findPlayer(e_player.attributeNode(QStringLiteral("playerid")).value().toInt()); 0819 if (trade && player) { 0820 trade->addPlayer(player); 0821 QObject::connect(m_atlanticCore, SIGNAL(removePlayer(Player *)), trade, SLOT(removePlayer(Player *))); 0822 } 0823 } 0824 n_player = n_player.nextSibling(); 0825 } 0826 } else if (type == QLatin1String("accepted") && trade) 0827 Q_EMIT msgTradeUpdateAccepted(trade); 0828 else if (type == QLatin1String("completed") && trade) { 0829 m_atlanticCore->removeTrade(trade); 0830 trade = nullptr; 0831 } else if (type == QLatin1String("rejected")) { 0832 Player *player = m_atlanticCore->findPlayer(e.attributeNode(QStringLiteral("actor")).value().toInt()); 0833 if (trade) 0834 trade->reject(player); 0835 if ( player && player == m_atlanticCore->playerSelf() ) { 0836 m_atlanticCore->removeTrade(trade); 0837 trade = nullptr; 0838 } 0839 } else { 0840 // No type specified, edit is implied. 0841 0842 QDomNode n_child = n.firstChild(); 0843 while(!n_child.isNull()) { 0844 QDomElement e_child = n_child.toElement(); 0845 if (!e_child.isNull()) { 0846 if (e_child.tagName() == QLatin1String("tradeplayer")) { 0847 a = e_child.attributeNode(QStringLiteral("playerid")); 0848 if (!a.isNull()) { 0849 Player *player = m_atlanticCore->findPlayer(a.value().toInt()); 0850 0851 a = e_child.attributeNode(QStringLiteral("accept")); 0852 if (trade && player && !a.isNull()) 0853 trade->updateAccept(player, (bool)(a.value().toInt())); 0854 } 0855 } else if (e_child.tagName() == QLatin1String("tradeestate")) { 0856 a = e_child.attributeNode(QStringLiteral("estateid")); 0857 if (!a.isNull()) { 0858 Estate *estate = m_atlanticCore->findEstate(a.value().toInt()); 0859 a = e_child.attributeNode(QStringLiteral("targetplayer")); 0860 if (!a.isNull()) { 0861 Player *player = m_atlanticCore->findPlayer(a.value().toInt()); 0862 // Allow NULL player, it will remove the component 0863 if (trade && estate) 0864 trade->updateEstate(estate, player); 0865 } 0866 } 0867 } else if (e_child.tagName() == QLatin1String("trademoney")) { 0868 Player *pFrom = nullptr, *pTo = nullptr; 0869 0870 a = e_child.attributeNode(QStringLiteral("playerfrom")); 0871 if (!a.isNull()) 0872 pFrom = m_atlanticCore->findPlayer(a.value().toInt()); 0873 0874 a = e_child.attributeNode(QStringLiteral("playerto")); 0875 if (!a.isNull()) 0876 pTo = m_atlanticCore->findPlayer(a.value().toInt()); 0877 0878 a = e_child.attributeNode(QStringLiteral("money")); 0879 qCDebug(LIBATLANTIKCLIENT_LOG) << "tradeupdatemoney" << (pFrom ? "1" : "0") << (pTo ? "1" : "0") << (a.isNull() ? "0" : "1"); 0880 if (trade && pFrom && pTo && !a.isNull()) 0881 trade->updateMoney(a.value().toInt(), pFrom, pTo); 0882 } else if (e_child.tagName() == QLatin1String("tradecard")) { 0883 a = e_child.attributeNode(QStringLiteral("cardid")); 0884 if (!a.isNull()) { 0885 Card *card = m_atlanticCore->findCard(a.value().toInt()); 0886 a = e_child.attributeNode(QStringLiteral("targetplayer")); 0887 if (!a.isNull()) { 0888 Player *player = m_atlanticCore->findPlayer(a.value().toInt()); 0889 // Allow NULL player, it will remove the component 0890 if (trade && card) 0891 trade->updateCard(card, player); 0892 } 0893 } 0894 } 0895 } 0896 n_child = n_child.nextSibling(); 0897 } 0898 } 0899 0900 if (trade) 0901 trade->update(); 0902 } 0903 } else if (e.tagName() == QLatin1String("auctionupdate")) { 0904 a = e.attributeNode(QStringLiteral("auctionid")); 0905 if (!a.isNull()) { 0906 int auctionId = a.value().toInt(); 0907 0908 Auction *auction = m_atlanticCore->findAuction(auctionId); 0909 bool b_newAuction = false; 0910 if (!auction) { 0911 // Create auction object 0912 auction = m_atlanticCore->newAuction(auctionId, m_atlanticCore->findEstate(e.attributeNode(QStringLiteral("estateid")).value().toInt())); 0913 0914 QObject::connect(auction, SIGNAL(bid(Auction *, int)), this, SLOT(auctionBid(Auction *, int))); 0915 0916 b_newAuction = true; 0917 } 0918 0919 a = e.attributeNode(QStringLiteral("highbidder")); 0920 if (!a.isNull()) { 0921 Player *player = m_atlanticCore->findPlayer(e.attributeNode(QStringLiteral("highbidder")).value().toInt()); 0922 a = e.attributeNode(QStringLiteral("highbid")); 0923 if (auction && !a.isNull()) 0924 auction->newBid(player, a.value().toInt()); 0925 } 0926 0927 a = e.attributeNode(QStringLiteral("status")); 0928 if (auction && !a.isNull()) { 0929 int status = a.value().toInt(); 0930 auction->setStatus(status); 0931 0932 // TODO: find a good way to visually represent "sold!" 0933 if (status == 3) { 0934 m_atlanticCore->delAuction(auction); 0935 auction = nullptr; 0936 } 0937 } 0938 0939 // Emit signal so GUI implementations can create view(s) 0940 // TODO: port to atlanticcore and create view there 0941 if (auction) { 0942 if (b_newAuction) 0943 Q_EMIT newAuction(auction); 0944 auction->update(); 0945 } 0946 } 0947 } else if (e.tagName() == QLatin1String("cardupdate")) { 0948 a = e.attributeNode(QStringLiteral("cardid")); 0949 if (!a.isNull()) { 0950 int cardId = a.value().toInt(); 0951 0952 Card *card; 0953 if (!(card = m_atlanticCore->findCard(cardId))) 0954 card = m_atlanticCore->newCard(cardId); 0955 0956 // Update card owner 0957 a = e.attributeNode(QStringLiteral("owner")); 0958 if (!a.isNull()) { 0959 Player *player = m_atlanticCore->findPlayer(a.value().toInt()); 0960 card->setOwner(player); 0961 } 0962 0963 // Update card title 0964 a = e.attributeNode(QStringLiteral("title")); 0965 if (!a.isNull()) 0966 card->setTitle(a.value()); 0967 0968 if (card) 0969 card->update(); 0970 } 0971 } else 0972 qCDebug(LIBATLANTIKCLIENT_LOG) << "ignored TAG:" << e.tagName(); 0973 } 0974 // TODO: remove permanently? 0975 // QDomNode node = n.firstChild(); 0976 // processNode(node); 0977 } 0978 } 0979 0980 #include "moc_atlantik_network.cpp"