From 9411396b971e32d855abca41dbf20918651c7d80 Mon Sep 17 00:00:00 2001 From: ebbit1q Date: Sun, 3 Mar 2019 22:24:57 +0100 Subject: [PATCH] rework pt setting (#3584) * rework pt setting save pt as a string serverside set the pt of cards that enter the battlefield to empty (was -1/0) implement old behaviour as changePT clientside display old pt to messagelog add new keybind for new set behaviour (default ctrl+shift+p) add flow pt actions and keybinds that increase while decreasing put more braces everywhere various refactors like adding consts and for loops remove a single superfluous semicolon does not change the way pt is displayed client side does not fix 3455 fully * fix drawing of pt remove search for / in carditem's paint() (crash) ptstring is now always orange unless it's a faceup card with a pt that matches the cardinfo pt set changept to remove the pt if the field is empty set changept to keep the old value if one side is empty return in changept for +0/+0 clean up some if statements * return on change to +0/+0 * change log message for empty original pts * typo * remove changept add parsept to unify reading pt strings change setpt behavior to be an "upgraded" version of the old setpt add arbitrary strings as anything that starts with / * clangify * remove debug lines * add tip of the day * add missing images * clangify --- cockatrice/cockatrice.qrc | 4 +- cockatrice/resources/tips/images/setpt.png | Bin 0 -> 18593 bytes .../resources/tips/images/shortcuts.png | Bin 0 -> 21308 bytes cockatrice/resources/tips/tips_of_the_day.xml | 9 +- cockatrice/src/carditem.cpp | 13 +- cockatrice/src/messagelogwidget.cpp | 167 ++-- cockatrice/src/player.cpp | 214 +++-- cockatrice/src/player.h | 9 +- cockatrice/src/sequenceEdit/ui_shortcutstab.h | 104 ++- cockatrice/src/shortcutssettings.h | 2 + common/server_card.cpp | 64 +- common/server_card.h | 12 +- common/server_player.cpp | 731 +++++++++++------- 13 files changed, 831 insertions(+), 498 deletions(-) create mode 100644 cockatrice/resources/tips/images/setpt.png create mode 100644 cockatrice/resources/tips/images/shortcuts.png diff --git a/cockatrice/cockatrice.qrc b/cockatrice/cockatrice.qrc index 8fd40bb4..76015af4 100644 --- a/cockatrice/cockatrice.qrc +++ b/cockatrice/cockatrice.qrc @@ -347,7 +347,6 @@ resources/userlevels/admin_vip_buddy.svg - resources/tips/tips_of_the_day.xml resources/tips/images/accounts_tab.png resources/tips/images/arrows.png resources/tips/images/cockatrice_register.png @@ -358,8 +357,11 @@ resources/tips/images/filter_games.png resources/tips/images/github_logo.png resources/tips/images/gitter.png + resources/tips/images/setpt.png + resources/tips/images/shortcuts.png resources/tips/images/themes.png resources/tips/images/tip_of_the_day.png + resources/tips/tips_of_the_day.xml resources/help/search.md diff --git a/cockatrice/resources/tips/images/setpt.png b/cockatrice/resources/tips/images/setpt.png new file mode 100644 index 0000000000000000000000000000000000000000..974c0224ab296251108d76795dbfee82faec2e02 GIT binary patch literal 18593 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 I4DC+&8(#EI*Z=?k literal 0 HcmV?d00001 diff --git a/cockatrice/resources/tips/images/shortcuts.png b/cockatrice/resources/tips/images/shortcuts.png new file mode 100644 index 0000000000000000000000000000000000000000..2034fdfd8a260cf302c8d0d9b9c440e30769ff7e GIT binary patch literal 21308 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 literal 0 HcmV?d00001 diff --git a/cockatrice/resources/tips/tips_of_the_day.xml b/cockatrice/resources/tips/tips_of_the_day.xml index aa2cb463..786391c9 100644 --- a/cockatrice/resources/tips/tips_of_the_day.xml +++ b/cockatrice/resources/tips/tips_of_the_day.xml @@ -63,6 +63,7 @@ <br>Change Life: CTRL + L <br>All shortcuts can be customized via Settings->Shortcuts! + shortcuts.png 2018-03-01 @@ -89,4 +90,10 @@ counter_expression.png 2019-02-02 - \ No newline at end of file + + Power and Toughness + You can add and subtract to a creature's stats.<br>With a card selected, set the power and toughness ( default: ctrl + p ) and enter +3/-1 to increase power by three while decreasing toughness by one.<br>You can also reset it to the original value ( default: ctrl + alt + 0 ). + setpt.png + 2019-03-02 + + diff --git a/cockatrice/src/carditem.cpp b/cockatrice/src/carditem.cpp index 00b42bd9..20bf2fe1 100644 --- a/cockatrice/src/carditem.cpp +++ b/cockatrice/src/carditem.cpp @@ -106,17 +106,12 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, painter->save(); transformPainter(painter, translatedSize, tapAngle); - if (info) { - QStringList ptSplit = pt.split("/"); - QStringList ptDbSplit = info->getPowTough().split("/"); - - if (getFaceDown() || ptDbSplit.at(0) != ptSplit.at(0) || ptDbSplit.at(1) != ptSplit.at(1)) - painter->setPen(QColor(255, 150, 0)); - else - painter->setPen(Qt::white); - } else { + if (!getFaceDown() && info && pt == info->getPowTough()) { painter->setPen(Qt::white); + } else { + painter->setPen(QColor(255, 150, 0)); // dark orange } + painter->setBackground(Qt::black); painter->setBackgroundMode(Qt::OpaqueMode); diff --git a/cockatrice/src/messagelogwidget.cpp b/cockatrice/src/messagelogwidget.cpp index 14e705f1..8ae75595 100644 --- a/cockatrice/src/messagelogwidget.cpp +++ b/cockatrice/src/messagelogwidget.cpp @@ -68,54 +68,61 @@ MessageLogWidget::getFromStr(CardZone *zone, QString cardName, int position, boo QString fromStr; QString zoneName = zone->getName(); - if (zoneName == tableConstant()) + if (zoneName == tableConstant()) { fromStr = tr(" from play"); - else if (zoneName == graveyardConstant()) + } else if (zoneName == graveyardConstant()) { fromStr = tr(" from their graveyard"); - else if (zoneName == exileConstant()) + } else if (zoneName == exileConstant()) { fromStr = tr(" from exile"); - else if (zoneName == handConstant()) + } else if (zoneName == handConstant()) { fromStr = tr(" from their hand"); - else if (zoneName == deckConstant()) { + } else if (zoneName == deckConstant()) { if (position == 0) { if (cardName.isEmpty()) { - if (ownerChange) + if (ownerChange) { cardName = tr("the top card of %1's library").arg(zone->getPlayer()->getName()); - else + } else { cardName = tr("the top card of their library"); + } cardNameContainsStartZone = true; } else { - if (ownerChange) + if (ownerChange) { fromStr = tr(" from the top of %1's library").arg(zone->getPlayer()->getName()); - else + } else { fromStr = tr(" from the top of their library"); + } } } else if (position >= zone->getCards().size() - 1) { if (cardName.isEmpty()) { - if (ownerChange) + if (ownerChange) { cardName = tr("the bottom card of %1's library").arg(zone->getPlayer()->getName()); - else + } else { cardName = tr("the bottom card of their library"); + } cardNameContainsStartZone = true; } else { - if (ownerChange) + if (ownerChange) { fromStr = tr(" from the bottom of %1's library").arg(zone->getPlayer()->getName()); - else + } else { fromStr = tr(" from the bottom of their library"); + } } } else { - if (ownerChange) + if (ownerChange) { fromStr = tr(" from %1's library").arg(zone->getPlayer()->getName()); - else + } else { fromStr = tr(" from their library"); + } } - } else if (zoneName == sideboardConstant()) + } else if (zoneName == sideboardConstant()) { fromStr = tr(" from sideboard"); - else if (zoneName == stackConstant()) + } else if (zoneName == stackConstant()) { fromStr = tr(" from the stack"); + } - if (!cardNameContainsStartZone) + if (!cardNameContainsStartZone) { cardName.clear(); + } return QPair(cardName, fromStr); } @@ -123,9 +130,9 @@ void MessageLogWidget::containerProcessingDone() { if (currentContext == MessageContext_MoveCard) { - for (auto &i : moveCardQueue) + for (auto &i : moveCardQueue) { logDoMoveCard(i); - + } moveCardQueue.clear(); moveCardTapped.clear(); moveCardExtras.clear(); @@ -141,9 +148,9 @@ void MessageLogWidget::containerProcessingDone() void MessageLogWidget::containerProcessingStarted(const GameEventContext &context) { - if (context.HasExtension(Context_MoveCard::ext)) + if (context.HasExtension(Context_MoveCard::ext)) { currentContext = MessageContext_MoveCard; - else if (context.HasExtension(Context_Mulligan::ext)) { + } else if (context.HasExtension(Context_Mulligan::ext)) { const Context_Mulligan &contextMulligan = context.GetExtension(Context_Mulligan::ext); currentContext = MessageContext_Mulligan; mulliganPlayer = nullptr; @@ -258,13 +265,14 @@ void MessageLogWidget::logCreateToken(Player *player, QString cardName, QString void MessageLogWidget::logDeckSelect(Player *player, QString deckHash, int sideboardSize) { - if (sideboardSize < 0) + if (sideboardSize < 0) { appendHtmlServerMessage(tr("%1 has loaded a deck (%2).").arg(sanitizeHtml(player->getName())).arg(deckHash)); - else + } else { appendHtmlServerMessage(tr("%1 has loaded a deck with %2 sideboard cards (%3).") .arg(sanitizeHtml(player->getName())) .arg("" + QString::number(sideboardSize) + "") .arg(deckHash)); + } } void MessageLogWidget::logDestroyCard(Player *player, QString cardName) @@ -282,21 +290,24 @@ void MessageLogWidget::logDoMoveCard(LogMoveCard &lmc) // do not log if moved within the same zone if ((startZone == tableConstant() && targetZone == tableConstant() && !ownerChanged) || (startZone == handConstant() && targetZone == handConstant()) || - (startZone == exileConstant() && targetZone == exileConstant())) + (startZone == exileConstant() && targetZone == exileConstant())) { return; + } QString cardName = lmc.cardName; QPair nameFrom = getFromStr(lmc.startZone, cardName, lmc.oldX, ownerChanged); - if (!nameFrom.first.isEmpty()) + if (!nameFrom.first.isEmpty()) { cardName = nameFrom.first; + } QString cardStr; - if (!nameFrom.first.isEmpty()) + if (!nameFrom.first.isEmpty()) { cardStr = cardName; - else if (cardName.isEmpty()) + } else if (cardName.isEmpty()) { cardStr = tr("a card"); - else + } else { cardStr = cardLink(cardName); + } if (ownerChanged && (lmc.startZone->getPlayer() == lmc.player)) { appendHtmlServerMessage(tr("%1 gives %2 control over %3.") @@ -310,17 +321,18 @@ void MessageLogWidget::logDoMoveCard(LogMoveCard &lmc) bool usesNewX = false; if (targetZone == tableConstant()) { soundEngine->playSound("play_card"); - if (moveCardTapped.value(lmc.card)) + if (moveCardTapped.value(lmc.card)) { finalStr = tr("%1 puts %2 into play tapped%3."); - else + } else { finalStr = tr("%1 puts %2 into play%3."); - } else if (targetZone == graveyardConstant()) + } + } else if (targetZone == graveyardConstant()) { finalStr = tr("%1 puts %2%3 into their graveyard."); - else if (targetZone == exileConstant()) + } else if (targetZone == exileConstant()) { finalStr = tr("%1 exiles %2%3."); - else if (targetZone == handConstant()) + } else if (targetZone == handConstant()) { finalStr = tr("%1 moves %2%3 to their hand."); - else if (targetZone == deckConstant()) { + } else if (targetZone == deckConstant()) { if (moveCardExtras.contains("shuffle_partial")) { finalStr = tr("%1 puts %2%3 on bottom of their library randomly."); } else if (lmc.newX == -1) { @@ -330,13 +342,13 @@ void MessageLogWidget::logDoMoveCard(LogMoveCard &lmc) } else if (lmc.newX == 0) { finalStr = tr("%1 puts %2%3 on top of their library."); } else { - lmc.newX++; + ++lmc.newX; usesNewX = true; finalStr = tr("%1 puts %2%3 into their library %4 cards from the top."); } - } else if (targetZone == sideboardConstant()) + } else if (targetZone == sideboardConstant()) { finalStr = tr("%1 moves %2%3 to sideboard."); - else if (targetZone == stackConstant()) { + } else if (targetZone == stackConstant()) { soundEngine->playSound("play_card"); finalStr = tr("%1 plays %2%3."); } @@ -351,9 +363,9 @@ void MessageLogWidget::logDoMoveCard(LogMoveCard &lmc) void MessageLogWidget::logDrawCards(Player *player, int number) { - if (currentContext == MessageContext_Mulligan) + if (currentContext == MessageContext_Mulligan) { mulliganPlayer = player; - else { + } else { soundEngine->playSound("draw_card"); appendHtmlServerMessage(tr("%1 draws %2 card(s).", "", number) .arg(sanitizeHtml(player->getName())) @@ -363,16 +375,17 @@ void MessageLogWidget::logDrawCards(Player *player, int number) void MessageLogWidget::logDumpZone(Player *player, CardZone *zone, int numberCards) { - if (numberCards == -1) + if (numberCards == -1) { appendHtmlServerMessage(tr("%1 is looking at %2.") .arg(sanitizeHtml(player->getName())) .arg(zone->getTranslatedName(zone->getPlayer() == player, CaseLookAtZone))); - else + } else { appendHtmlServerMessage( tr("%1 is looking at the top %3 card(s) %2.", "top card for singular, top %3 cards for plural", numberCards) .arg(sanitizeHtml(player->getName())) .arg(zone->getTranslatedName(zone->getPlayer() == player, CaseTopCardsOfZone)) .arg("" + QString::number(numberCards) + "")); + } } void MessageLogWidget::logFlipCard(Player *player, QString cardName, bool faceDown) @@ -438,22 +451,25 @@ void MessageLogWidget::logMoveCard(Player *player, int newX) { LogMoveCard attributes = {player, card, card->getName(), startZone, oldX, targetZone, newX}; - if (currentContext == MessageContext_MoveCard) + if (currentContext == MessageContext_MoveCard) { moveCardQueue.append(attributes); - else if (currentContext == MessageContext_Mulligan) + } else if (currentContext == MessageContext_Mulligan) { mulliganPlayer = player; - else + } else { logDoMoveCard(attributes); + } } void MessageLogWidget::logMulligan(Player *player, int number) { - if (!player) + if (!player) { return; - if (number > -1) + } + if (number > -1) { appendHtmlServerMessage(tr("%1 takes a mulligan to %2.").arg(sanitizeHtml(player->getName())).arg(number)); - else + } else { appendHtmlServerMessage(tr("%1 draws their initial hand.").arg(sanitizeHtml(player->getName()))); + } } void MessageLogWidget::logReplayStarted(int gameId) @@ -549,11 +565,12 @@ void MessageLogWidget::logRollDie(Player *player, int sides, int roll) appendHtmlServerMessage(tr("%1 flipped a coin. It landed as %2.") .arg(sanitizeHtml(player->getName())) .arg("" + coinOptions[roll - 1] + "")); - } else + } else { appendHtmlServerMessage(tr("%1 rolls a %2 with a %3-sided die.") .arg(sanitizeHtml(player->getName())) .arg("" + QString::number(roll) + "") .arg("" + QString::number(sides) + "")); + } soundEngine->playSound("roll_dice"); } @@ -567,7 +584,7 @@ void MessageLogWidget::logSetActivePhase(int phase) { QString phaseName; QString color; - switch (phase) { + switch (phase) { // TODO: define phases case 0: phaseName = tr("Untap"); soundEngine->playSound("untap_step"); @@ -651,10 +668,11 @@ void MessageLogWidget::logSetCardCounter(Player *player, QString cardName, int c { QString finalStr; int delta = abs(oldValue - value); - if (value > oldValue) + if (value > oldValue) { finalStr = tr("%1 places %2 %3 on %4 (now %5)."); - else + } else { finalStr = tr("%1 removes %2 %3 from %4 (now %5)."); + } QString colorStr; switch (counterId) { @@ -679,8 +697,9 @@ void MessageLogWidget::logSetCardCounter(Player *player, QString cardName, int c void MessageLogWidget::logSetCounter(Player *player, QString counterName, int value, int oldValue) { - if (counterName == "life") + if (counterName == "life") { soundEngine->playSound("life_change"); + } appendHtmlServerMessage(tr("%1 sets counter %2 to %3 (%4%5).") .arg(sanitizeHtml(player->getName())) @@ -693,10 +712,11 @@ void MessageLogWidget::logSetCounter(Player *player, QString counterName, int va void MessageLogWidget::logSetDoesntUntap(Player *player, CardItem *card, bool doesntUntap) { QString str; - if (doesntUntap) + if (doesntUntap) { str = tr("%1 sets %2 to not untap normally."); - else + } else { str = tr("%1 sets %2 to untap normally."); + } appendHtmlServerMessage(str.arg(sanitizeHtml(player->getName())).arg(cardLink(card->getName()))); } @@ -712,40 +732,50 @@ void MessageLogWidget::logSetPT(Player *player, CardItem *card, QString newPT) } else { name = cardLink(name); } + QString playerName = sanitizeHtml(player->getName()); if (newPT.isEmpty()) { - appendHtmlServerMessage(tr("%1 removes the PT of %2.").arg(sanitizeHtml(player->getName())).arg(name)); + appendHtmlServerMessage(tr("%1 removes the PT of %2.").arg(playerName).arg(name)); } else { - appendHtmlServerMessage( - tr("%1 sets PT of %2 to %3.").arg(sanitizeHtml(player->getName())).arg(name).arg(newPT)); + QString oldPT = card->getPT(); + if (oldPT.isEmpty()) { + appendHtmlServerMessage( + tr("%1 changes the PT of %2 from nothing to %4.").arg(playerName).arg(name).arg(newPT)); + } else { + appendHtmlServerMessage( + tr("%1 changes the PT of %2 from %3 to %4.").arg(playerName).arg(name).arg(oldPT).arg(newPT)); + } } } void MessageLogWidget::logSetSideboardLock(Player *player, bool locked) { - if (locked) + if (locked) { appendHtmlServerMessage(tr("%1 has locked their sideboard.").arg(sanitizeHtml(player->getName()))); - else + } else { appendHtmlServerMessage(tr("%1 has unlocked their sideboard.").arg(sanitizeHtml(player->getName()))); + } } void MessageLogWidget::logSetTapped(Player *player, CardItem *card, bool tapped) { - if (tapped) + if (tapped) { soundEngine->playSound("tap_card"); - else + } else { soundEngine->playSound("untap_card"); + } - if (currentContext == MessageContext_MoveCard) + if (currentContext == MessageContext_MoveCard) { moveCardTapped.insert(card, tapped); - else { + } else { QString str; - if (!card) + if (!card) { appendHtmlServerMessage((tapped ? tr("%1 taps their permanents.") : tr("%1 untaps their permanents.")) .arg(sanitizeHtml(player->getName()))); - else + } else { appendHtmlServerMessage((tapped ? tr("%1 taps %2.") : tr("%1 untaps %2.")) .arg(sanitizeHtml(player->getName())) .arg(cardLink(card->getName()))); + } } } @@ -809,13 +839,14 @@ void MessageLogWidget::logUnattachCard(Player *player, QString cardName) void MessageLogWidget::logUndoDraw(Player *player, QString cardName) { - if (cardName.isEmpty()) + if (cardName.isEmpty()) { appendHtmlServerMessage(tr("%1 undoes their last draw.").arg(sanitizeHtml(player->getName()))); - else + } else { appendHtmlServerMessage( tr("%1 undoes their last draw (%2).") .arg(sanitizeHtml(player->getName())) .arg(QString("%2").arg(sanitizeHtml(cardName)).arg(sanitizeHtml(cardName)))); + } } void MessageLogWidget::setContextJudgeName(QString name) diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index f6e7509e..75e6d713 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -410,6 +410,10 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T connect(aIncPT, SIGNAL(triggered()), this, SLOT(actIncPT())); aDecPT = new QAction(this); connect(aDecPT, SIGNAL(triggered()), this, SLOT(actDecPT())); + aFlowP = new QAction(this); + connect(aFlowP, SIGNAL(triggered()), this, SLOT(actFlowP())); + aFlowT = new QAction(this); + connect(aFlowT, SIGNAL(triggered()), this, SLOT(actFlowT())); aSetPT = new QAction(this); connect(aSetPT, SIGNAL(triggered()), this, SLOT(actSetPT())); aResetPT = new QAction(this); @@ -466,8 +470,9 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T } const QList &players = game->getPlayers().values(); - for (auto player : players) + for (const auto player : players) { addPlayer(player); + } rearrangeZones(); retranslateUi(); @@ -706,8 +711,9 @@ void Player::retranslateUi() aCardMenu->setText(tr("C&ard")); - for (auto &allPlayersAction : allPlayersActions) + for (auto &allPlayersAction : allPlayersActions) { allPlayersAction->setText(tr("&All players")); + } } if (local) { @@ -735,6 +741,8 @@ void Player::retranslateUi() aDecT->setText(tr("D&ecrease toughness")); aIncPT->setText(tr("In&crease power and toughness")); aDecPT->setText(tr("Dec&rease power and toughness")); + aFlowP->setText(tr("Increase power and decrease toughness")); + aFlowT->setText(tr("Decrease power and increase toughness")); aSetPT->setText(tr("Set &power and toughness...")); aResetPT->setText(tr("Reset p&ower and toughness")); aSetAnnotation->setText(tr("&Set annotation...")); @@ -787,6 +795,8 @@ void Player::setShortcutsActive() aDecT->setShortcuts(shortcuts.getShortcut("Player/aDecT")); aIncPT->setShortcuts(shortcuts.getShortcut("Player/aIncPT")); aDecPT->setShortcuts(shortcuts.getShortcut("Player/aDecPT")); + aFlowP->setShortcuts(shortcuts.getShortcut("Player/aFlowP")); + aFlowT->setShortcuts(shortcuts.getShortcut("Player/aFlowT")); aSetPT->setShortcuts(shortcuts.getShortcut("Player/aSetPT")); aResetPT->setShortcuts(shortcuts.getShortcut("Player/aResetPT")); aSetAnnotation->setShortcuts(shortcuts.getShortcut("Player/aSetAnnotation")); @@ -1849,7 +1859,7 @@ void Player::eventRevealCards(const Event_RevealCards &event) } if (peeking) { - for (auto &card : cardList) { + for (const auto &card : cardList) { QString cardName = QString::fromStdString(card->name()); CardItem *cardItem = zone->getCard(card->id(), QString()); if (!cardItem) { @@ -2245,11 +2255,9 @@ void Player::rearrangeCounters() // Determine total height of bounding rectangles qreal totalHeight = 0; - QMapIterator counterIterator(counters); - while (counterIterator.hasNext()) { - counterIterator.next(); - if (counterIterator.value()->getShownInCounterArea()) { - totalHeight += counterIterator.value()->boundingRect().height(); + for (const auto &counter : counters) { + if (counter->getShownInCounterArea()) { + totalHeight += counter->boundingRect().height(); } } @@ -2257,8 +2265,8 @@ void Player::rearrangeCounters() qreal ySize = boundingRect().y() + marginTop; // Place objects - for (counterIterator.toFront(); counterIterator.hasNext();) { - AbstractCounter *ctr = counterIterator.next().value(); + for (const auto &counter : counters) { + AbstractCounter *ctr = counter; if (!ctr->getShownInCounterArea()) { continue; @@ -2351,6 +2359,10 @@ void Player::actMoveCardXCardsFromTop() defaultNumberTopCardsToPlaceBelow = number; QList sel = scene()->selectedItems(); + if (sel.isEmpty()) { + return; + } + QList cardList; while (!sel.isEmpty()) { cardList.append(qgraphicsitem_cast(sel.takeFirst())); @@ -2358,14 +2370,10 @@ void Player::actMoveCardXCardsFromTop() QList commandList; ListOfCardsToMove idList; - for (auto &i : cardList) { + for (const auto &i : cardList) { idList.add_card()->set_card_id(i->getId()); } - if (cardList.isEmpty()) { - return; - } - int startPlayerId = cardList[0]->getZone()->getPlayer()->getId(); QString startZone = cardList[0]->getZone()->getName(); @@ -2397,7 +2405,7 @@ void Player::cardMenuAction() QList commandList; if (a->data().toInt() <= (int)cmClone) { - for (auto card : cardList) { + for (const auto &card : cardList) { switch (static_cast(a->data().toInt())) { // Leaving both for compatibility with server case cmUntap: @@ -2461,7 +2469,7 @@ void Player::cardMenuAction() } } else { ListOfCardsToMove idList; - for (auto &i : cardList) { + for (const auto &i : cardList) { idList.add_card()->set_card_id(i->getId()); } int startPlayerId = cardList[0]->getZone()->getPlayer()->getId(); @@ -2552,18 +2560,28 @@ void Player::cardMenuAction() void Player::actIncPT(int deltaP, int deltaT) { - QString ptString = "+" + QString::number(deltaP) + "/+" + QString::number(deltaT); int playerid = id; QList commandList; - QListIterator j(scene()->selectedItems()); - while (j.hasNext()) { - auto *card = static_cast(j.next()); + for (const auto &item : scene()->selectedItems()) { + auto *card = static_cast(item); + QString pt = card->getPT(); + const auto ptList = parsePT(pt); + QString newpt; + if (ptList.isEmpty()) { + newpt = QString::number(deltaP) + (deltaT ? "/" + QString::number(deltaT) : ""); + } else if (ptList.size() == 1) { + newpt = QString::number(ptList.at(0).toInt() + deltaP) + (deltaT ? "/" + QString::number(deltaT) : ""); + } else { + newpt = + QString::number(ptList.at(0).toInt() + deltaP) + "/" + QString::number(ptList.at(1).toInt() + deltaT); + } + auto *cmd = new Command_SetCardAttr; cmd->set_zone(card->getZone()->getName().toStdString()); cmd->set_card_id(card->getId()); cmd->set_attribute(AttrPT); - cmd->set_attr_value(ptString.toStdString()); + cmd->set_attr_value(newpt.toStdString()); commandList.append(cmd); if (local) { @@ -2578,9 +2596,8 @@ void Player::actResetPT() { int playerid = id; QList commandList; - QListIterator selected(scene()->selectedItems()); - while (selected.hasNext()) { - auto *card = static_cast(selected.next()); + for (const auto &item : scene()->selectedItems()) { + auto *card = static_cast(item); QString ptString; if (!card->getFaceDown()) { // leave the pt empty if the card is face down CardInfoPtr info = card->getInfo(); @@ -2607,39 +2624,85 @@ void Player::actResetPT() game->sendGameCommand(prepareGameCommand(commandList), playerid); } +QVariantList Player::parsePT(const QString &pt) +{ + QVariantList ptList = QVariantList(); + if (!pt.isEmpty()) { + int sep = pt.indexOf('/'); + if (sep == 0) { + ptList.append(QVariant(pt.mid(1))); // cut off starting '/' and take full string + } else { + int start = 0; + for (;;) { + QString item = pt.mid(start, sep - start); + if (item.isEmpty()) { + ptList.append(QVariant(QString())); + } else if (item[0] == '+') { + ptList.append(QVariant(item.mid(1).toInt())); // add as int + } else if (item[0] == '-') { + ptList.append(QVariant(item.toInt())); // add as int + } else { + ptList.append(QVariant(item)); // add as qstring + } + if (sep == -1) { + break; + } + start = sep + 1; + sep = pt.indexOf('/', start); + } + } + } + return ptList; +} + void Player::actSetPT() { QString oldPT; int playerid = id; - QListIterator i(scene()->selectedItems()); - while (i.hasNext()) { - auto *card = static_cast(i.next()); + auto sel = scene()->selectedItems(); + for (const auto &item : sel) { + auto *card = static_cast(item); if (!card->getPT().isEmpty()) { oldPT = card->getPT(); } } bool ok; dialogSemaphore = true; - QString pt = QInputDialog::getText(nullptr, tr("Set power/toughness"), tr("Please enter the new PT:"), - QLineEdit::Normal, oldPT, &ok); + QString pt = QInputDialog::getText(nullptr, tr("Change power/toughness"), tr("Change stats to:"), QLineEdit::Normal, + oldPT, &ok); dialogSemaphore = false; - if (clearCardsToDelete()) { - return; - } - if (!ok) { + if (clearCardsToDelete() || !ok) { return; } + const auto ptList = parsePT(pt); + bool empty = ptList.isEmpty(); + QList commandList; - QListIterator j(scene()->selectedItems()); - while (j.hasNext()) { - auto *card = static_cast(j.next()); + for (const auto &item : sel) { + auto *card = static_cast(item); auto *cmd = new Command_SetCardAttr; + QString newpt = QString(); + if (!empty) { + const auto oldpt = parsePT(card->getPT()); + int ptIter = 0; + for (const auto &item : ptList) { + if (item.type() == QVariant::Int) { + int oldItem = ptIter < oldpt.size() ? oldpt.at(ptIter).toInt() : 0; + newpt += '/' + QString::number(oldItem + item.toInt()); + } else { + newpt += '/' + item.toString(); + } + ++ptIter; + } + newpt = newpt.mid(1); + } + cmd->set_zone(card->getZone()->getName().toStdString()); cmd->set_card_id(card->getId()); cmd->set_attribute(AttrPT); - cmd->set_attr_value(pt.toStdString()); + cmd->set_attr_value(newpt.toStdString()); commandList.append(cmd); if (local) { @@ -2689,12 +2752,22 @@ void Player::actDecPT() actIncPT(-1, -1); } +void Player::actFlowP() +{ + actIncPT(1, -1); +} + +void Player::actFlowT() +{ + actIncPT(-1, 1); +} + void Player::actSetAnnotation() { QString oldAnnotation; - QListIterator i(scene()->selectedItems()); - while (i.hasNext()) { - auto *card = static_cast(i.next()); + auto sel = scene()->selectedItems(); + for (const auto &item : sel) { + auto *card = static_cast(item); if (!card->getAnnotation().isEmpty()) { oldAnnotation = card->getAnnotation(); } @@ -2705,17 +2778,13 @@ void Player::actSetAnnotation() QString annotation = QInputDialog::getText(nullptr, tr("Set annotation"), tr("Please enter the new annotation:"), QLineEdit::Normal, oldAnnotation, &ok); dialogSemaphore = false; - if (clearCardsToDelete()) { - return; - } - if (!ok) { + if (clearCardsToDelete() || !ok) { return; } QList commandList; - i.toFront(); - while (i.hasNext()) { - auto *card = static_cast(i.next()); + for (const auto &item : sel) { + auto *card = static_cast(item); auto *cmd = new Command_SetCardAttr; cmd->set_zone(card->getZone()->getName().toStdString()); cmd->set_card_id(card->getId()); @@ -2728,11 +2797,12 @@ void Player::actSetAnnotation() void Player::actAttach() { - if (!game->getActiveCard()) { + auto *card = game->getActiveCard(); + if (!card) { return; } - auto *arrow = new ArrowAttachItem(game->getActiveCard()); + auto *arrow = new ArrowAttachItem(card); scene()->addItem(arrow); arrow->grabMouse(); } @@ -2754,11 +2824,10 @@ void Player::actCardCounterTrigger() auto *action = static_cast(sender()); int counterId = action->data().toInt() / 1000; QList commandList; - switch (action->data().toInt() % 1000) { // TODO: define case numbers - case 9: { - QListIterator i(scene()->selectedItems()); - while (i.hasNext()) { - auto *card = static_cast(i.next()); + switch (action->data().toInt() % 1000) { + case 9: { // increment counter + for (const auto &item : scene()->selectedItems()) { + auto *card = static_cast(item); if (card->getCounters().value(counterId, 0) < MAX_COUNTERS_ON_CARD) { auto *cmd = new Command_SetCardCounter; cmd->set_zone(card->getZone()->getName().toStdString()); @@ -2770,10 +2839,9 @@ void Player::actCardCounterTrigger() } break; } - case 10: { - QListIterator i(scene()->selectedItems()); - while (i.hasNext()) { - auto *card = static_cast(i.next()); + case 10: { // decrement counter + for (const auto &item : scene()->selectedItems()) { + auto *card = static_cast(item); if (card->getCounters().value(counterId, 0)) { auto *cmd = new Command_SetCardCounter; cmd->set_zone(card->getZone()->getName().toStdString()); @@ -2785,7 +2853,7 @@ void Player::actCardCounterTrigger() } break; } - case 11: { + case 11: { // set counter with dialog bool ok; dialogSemaphore = true; int number = @@ -2795,9 +2863,8 @@ void Player::actCardCounterTrigger() return; } - QListIterator i(scene()->selectedItems()); - while (i.hasNext()) { - auto *card = static_cast(i.next()); + for (const auto &item : scene()->selectedItems()) { + auto *card = static_cast(item); auto *cmd = new Command_SetCardCounter; cmd->set_zone(card->getZone()->getName().toStdString()); cmd->set_card_id(card->getId()); @@ -2900,9 +2967,11 @@ void Player::updateCardMenu(const CardItem *card) if (ptMenu->isEmpty()) { ptMenu->addAction(aIncP); ptMenu->addAction(aDecP); + ptMenu->addAction(aFlowP); ptMenu->addSeparator(); ptMenu->addAction(aIncT); ptMenu->addAction(aDecT); + ptMenu->addAction(aFlowT); ptMenu->addSeparator(); ptMenu->addAction(aIncPT); ptMenu->addAction(aDecPT); @@ -2986,11 +3055,15 @@ void Player::updateCardMenu(const CardItem *card) void Player::addRelatedCardView(const CardItem *card, QMenu *cardMenu) { - if (card == nullptr || cardMenu == nullptr || card->getInfo() == nullptr) { + if (!card || !cardMenu) { + return; + } + auto cardInfo = card->getInfo(); + if (!cardInfo) { return; } - QList relatedCards = card->getInfo()->getRelatedCards(); + QList relatedCards = cardInfo->getRelatedCards(); if (relatedCards.isEmpty()) { return; } @@ -3009,13 +3082,16 @@ void Player::addRelatedCardView(const CardItem *card, QMenu *cardMenu) void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu) { - if (card == nullptr || cardMenu == nullptr || card->getInfo() == nullptr) { + if (!card || !cardMenu) { + return; + } + auto cardInfo = card->getInfo(); + if (!cardInfo) { return; } - QList relatedCards(card->getInfo()->getRelatedCards()); - relatedCards.append(card->getInfo()->getReverseRelatedCards2Me()); - if (relatedCards.empty()) { + QList relatedCards = cardInfo->getRelatedCards(); + if (relatedCards.isEmpty()) { return; } diff --git a/cockatrice/src/player.h b/cockatrice/src/player.h index f8a5b2fa..e5f06693 100644 --- a/cockatrice/src/player.h +++ b/cockatrice/src/player.h @@ -192,6 +192,8 @@ private slots: void actDecT(); void actIncPT(); void actDecPT(); + void actFlowP(); + void actFlowT(); void actSetAnnotation(); void actPlay(); void actHide(); @@ -215,8 +217,9 @@ private: QList aAddCounter, aSetCounter, aRemoveCounter; QAction *aPlay, *aPlayFacedown, *aHide, *aTap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aResetPT, - *aIncP, *aDecP, *aIncT, *aDecT, *aIncPT, *aDecPT, *aSetAnnotation, *aFlip, *aPeek, *aClone, *aMoveToTopLibrary, - *aMoveToBottomLibrary, *aMoveToHand, *aMoveToGraveyard, *aMoveToExile, *aMoveToXfromTopOfLibrary; + *aIncP, *aDecP, *aIncT, *aDecT, *aIncPT, *aDecPT, *aFlowP, *aFlowT, *aSetAnnotation, *aFlip, *aPeek, *aClone, + *aMoveToTopLibrary, *aMoveToBottomLibrary, *aMoveToHand, *aMoveToGraveyard, *aMoveToExile, + *aMoveToXfromTopOfLibrary; bool shortcutsActive; int defaultNumberTopCards; @@ -288,6 +291,8 @@ private: void eventRevealCards(const Event_RevealCards &event); void eventChangeZoneProperties(const Event_ChangeZoneProperties &event); + QVariantList parsePT(const QString &pt); + public: static const int counterAreaWidth = 55; enum CardMenuActionType diff --git a/cockatrice/src/sequenceEdit/ui_shortcutstab.h b/cockatrice/src/sequenceEdit/ui_shortcutstab.h index 4fb14772..2bafe80d 100644 --- a/cockatrice/src/sequenceEdit/ui_shortcutstab.h +++ b/cockatrice/src/sequenceEdit/ui_shortcutstab.h @@ -199,26 +199,30 @@ public: QVBoxLayout *verticalLayout; QGroupBox *groupBox_12; QGridLayout *gridLayout_12; - SequenceEdit *Player_aDecPT; - SequenceEdit *Player_aIncPT; QLabel *lbl_Player_aIncPT; + SequenceEdit *Player_aIncPT; QLabel *lbl_Player_aDecPT; - SequenceEdit *Player_aSetPT; + SequenceEdit *Player_aDecPT; QLabel *lbl_Player_aSetPT; - SequenceEdit *Player_aResetPT; + SequenceEdit *Player_aSetPT; QLabel *lbl_Player_aResetPT; + SequenceEdit *Player_aResetPT; QGroupBox *groupBox_11; QGridLayout *gridLayout_11; QLabel *lbl_Player_aDecT; SequenceEdit *Player_aDecT; QLabel *lbl_Player_aIncT; SequenceEdit *Player_aIncT; + QLabel *lbl_Player_aFlowT; + SequenceEdit *Player_aFlowT; QGroupBox *groupBox_10; QGridLayout *gridLayout_10; QLabel *lbl_Player_aDecP; SequenceEdit *Player_aDecP; - SequenceEdit *Player_aIncP; QLabel *lbl_Player_aIncP; + SequenceEdit *Player_aIncP; + QLabel *lbl_Player_aFlowP; + SequenceEdit *Player_aFlowP; QGroupBox *groupBox_8; QGridLayout *gridLayout_5; QLabel *lbl_TabGame_phase0; @@ -1083,36 +1087,20 @@ public: verticalLayout->addWidget(groupBox_12); - groupBox_11 = new QGroupBox(groupBox_9); - groupBox_11->setObjectName("groupBox_11"); - gridLayout_11 = new QGridLayout(groupBox_11); - gridLayout_11->setObjectName("gridLayout_11"); - lbl_Player_aDecT = new QLabel(groupBox_11); - lbl_Player_aDecT->setObjectName("lbl_Player_aDecT"); - - gridLayout_11->addWidget(lbl_Player_aDecT, 1, 0, 1, 1); - - Player_aDecT = new SequenceEdit("Player/aDecT", groupBox_11); - Player_aDecT->setObjectName("Player_aDecT"); - - gridLayout_11->addWidget(Player_aDecT, 1, 1, 1, 1); - - lbl_Player_aIncT = new QLabel(groupBox_11); - lbl_Player_aIncT->setObjectName("lbl_Player_aIncT"); - - gridLayout_11->addWidget(lbl_Player_aIncT, 0, 0, 1, 1); - - Player_aIncT = new SequenceEdit("Player/aIncT", groupBox_11); - Player_aIncT->setObjectName("Player_aIncT"); - - gridLayout_11->addWidget(Player_aIncT, 0, 1, 1, 1); - - verticalLayout->addWidget(groupBox_11); - groupBox_10 = new QGroupBox(groupBox_9); groupBox_10->setObjectName("groupBox_10"); gridLayout_10 = new QGridLayout(groupBox_10); gridLayout_10->setObjectName("gridLayout_10"); + lbl_Player_aIncP = new QLabel(groupBox_10); + lbl_Player_aIncP->setObjectName("lbl_Player_aIncP"); + + gridLayout_10->addWidget(lbl_Player_aIncP, 0, 0, 1, 1); + + Player_aIncP = new SequenceEdit("Player/aIncP", groupBox_10); + Player_aIncP->setObjectName("Player_aIncP"); + + gridLayout_10->addWidget(Player_aIncP, 0, 1, 1, 1); + lbl_Player_aDecP = new QLabel(groupBox_10); lbl_Player_aDecP->setObjectName("lbl_Player_aDecP"); @@ -1123,18 +1111,54 @@ public: gridLayout_10->addWidget(Player_aDecP, 1, 1, 1, 1); - Player_aIncP = new SequenceEdit("Player/aIncP", groupBox_10); - Player_aIncP->setObjectName("Player_aIncP"); + lbl_Player_aFlowP = new QLabel(groupBox_10); + lbl_Player_aFlowP->setObjectName("lbl_Player_aFlowP"); - gridLayout_10->addWidget(Player_aIncP, 0, 1, 1, 1); + gridLayout_10->addWidget(lbl_Player_aFlowP, 2, 0, 1, 1); - lbl_Player_aIncP = new QLabel(groupBox_10); - lbl_Player_aIncP->setObjectName("lbl_Player_aIncP"); + Player_aFlowP = new SequenceEdit("Player/aFlowP", groupBox_10); + Player_aFlowP->setObjectName("Player_aFlowP"); - gridLayout_10->addWidget(lbl_Player_aIncP, 0, 0, 1, 1); + gridLayout_10->addWidget(Player_aFlowP, 2, 1, 1, 1); verticalLayout->addWidget(groupBox_10); + groupBox_11 = new QGroupBox(groupBox_9); + groupBox_11->setObjectName("groupBox_11"); + gridLayout_11 = new QGridLayout(groupBox_11); + gridLayout_11->setObjectName("gridLayout_11"); + lbl_Player_aIncT = new QLabel(groupBox_11); + lbl_Player_aIncT->setObjectName("lbl_Player_aIncT"); + + gridLayout_11->addWidget(lbl_Player_aIncT, 0, 0, 1, 1); + + Player_aIncT = new SequenceEdit("Player/aIncT", groupBox_11); + Player_aIncT->setObjectName("Player_aIncT"); + + gridLayout_11->addWidget(Player_aIncT, 0, 1, 1, 1); + + lbl_Player_aDecT = new QLabel(groupBox_11); + lbl_Player_aDecT->setObjectName("lbl_Player_aDecT"); + + gridLayout_11->addWidget(lbl_Player_aDecT, 1, 0, 1, 1); + + Player_aDecT = new SequenceEdit("Player/aDecT", groupBox_11); + Player_aDecT->setObjectName("Player_aDecT"); + + gridLayout_11->addWidget(Player_aDecT, 1, 1, 1, 1); + + lbl_Player_aFlowT = new QLabel(groupBox_11); + lbl_Player_aFlowT->setObjectName("lbl_Player_aFlowT"); + + gridLayout_11->addWidget(lbl_Player_aFlowT, 2, 0, 1, 1); + + Player_aFlowT = new SequenceEdit("Player/aFlowT", groupBox_11); + Player_aFlowT->setObjectName("Player_aFlowT"); + + gridLayout_11->addWidget(Player_aFlowT, 2, 1, 1, 1); + + verticalLayout->addWidget(groupBox_11); + gridLayout_17->addWidget(groupBox_9, 0, 1, 1, 1); groupBox_8 = new QGroupBox(tab_2); @@ -1929,9 +1953,11 @@ public: groupBox_11->setTitle(QApplication::translate("shortcutsTab", "Toughness")); lbl_Player_aDecT->setText(QApplication::translate("shortcutsTab", "Remove (-0/-1)")); lbl_Player_aIncT->setText(QApplication::translate("shortcutsTab", "Add (+0/+1)")); + lbl_Player_aFlowT->setText(QApplication::translate("shortcutsTab", "Move (-1/+1)")); groupBox_10->setTitle(QApplication::translate("shortcutsTab", "Power")); - lbl_Player_aDecP->setText(QApplication::translate("shortcutsTab", "Remove (-1/-nullptr)")); - lbl_Player_aIncP->setText(QApplication::translate("shortcutsTab", "Add (+1/+nullptr)")); + lbl_Player_aDecP->setText(QApplication::translate("shortcutsTab", "Remove (-1/-0)")); + lbl_Player_aIncP->setText(QApplication::translate("shortcutsTab", "Add (+1/+0)")); + lbl_Player_aFlowP->setText(QApplication::translate("shortcutsTab", "Move (+1/-1)")); groupBox_8->setTitle(QApplication::translate("shortcutsTab", "Game Phases")); lbl_TabGame_phase0->setText(QApplication::translate("shortcutsTab", "Untap")); lbl_TabGame_phase1->setText(QApplication::translate("shortcutsTab", "Upkeep")); diff --git a/cockatrice/src/shortcutssettings.h b/cockatrice/src/shortcutssettings.h index 6887cf75..954cd5ed 100644 --- a/cockatrice/src/shortcutssettings.h +++ b/cockatrice/src/shortcutssettings.h @@ -139,6 +139,8 @@ private: {"Player/aIncT", parseSequenceString("Alt++")}, {"Player/aSetPT", parseSequenceString("Ctrl+P")}, {"Player/aResetPT", parseSequenceString("Ctrl+Alt+0")}, + {"Player/aFlowP", parseSequenceString("")}, + {"Player/aFlowT", parseSequenceString("")}, {"Player/aConcede", parseSequenceString("F2")}, {"Player/aLeaveGame", parseSequenceString("Ctrl+Q")}, diff --git a/common/server_card.cpp b/common/server_card.cpp index b1af9d5b..a8b5f1f1 100644 --- a/common/server_card.cpp +++ b/common/server_card.cpp @@ -24,8 +24,7 @@ Server_Card::Server_Card(QString _name, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone) : zone(_zone), id(_id), coord_x(_coord_x), coord_y(_coord_y), name(_name), tapped(false), attacking(false), - facedown(false), color(QString()), power(-1), toughness(-1), annotation(QString()), destroyOnZoneChange(false), - doesntUntap(false), parentCard(0) + facedown(false), color(), ptString(), annotation(), destroyOnZoneChange(false), doesntUntap(false), parentCard(0) { } @@ -44,8 +43,7 @@ void Server_Card::resetState() counters.clear(); setTapped(false); setAttacking(false); - power = -1; - toughness = -1; + setPT(QString()); setAnnotation(QString()); setDoesntUntap(false); } @@ -89,40 +87,6 @@ void Server_Card::setCounter(int id, int value) counters.remove(id); } -void Server_Card::setPT(const QString &_pt) -{ - if (_pt.isEmpty()) { - power = 0; - toughness = -1; - } else { - int sep = _pt.indexOf('/'); - QString p1 = _pt.left(sep); - QString p2 = _pt.mid(sep + 1); - if (p1.isEmpty() || p2.isEmpty()) - return; - - if ((p1[0] == '+') || (p2[0] == '+')) - if (toughness < 0) - toughness = 0; - if (p1[0] == '+') - power += p1.mid(1).toInt(); - else - power = p1.toInt(); - - if (p2[0] == '+') - toughness += p2.mid(1).toInt(); - else - toughness = p2.toInt(); - } -} - -QString Server_Card::getPT() const -{ - if (toughness < 0) - return QString(""); - return QString::number(power) + "/" + QString::number(toughness); -} - void Server_Card::setParentCard(Server_Card *_parentCard) { if (parentCard) @@ -140,24 +104,28 @@ void Server_Card::getInfo(ServerInfo_Card *info) info->set_name(displayedName.toStdString()); info->set_x(coord_x); info->set_y(coord_y); - QString ptStr = getPT(); if (facedown) { info->set_face_down(true); - ptStr = getPT(); } info->set_tapped(tapped); - if (attacking) + if (attacking) { info->set_attacking(true); - if (!color.isEmpty()) + } + if (!color.isEmpty()) { info->set_color(color.toStdString()); - if (!ptStr.isEmpty()) - info->set_pt(ptStr.toStdString()); - if (!annotation.isEmpty()) + } + if (!ptString.isEmpty()) { + info->set_pt(ptString.toStdString()); + } + if (!annotation.isEmpty()) { info->set_annotation(annotation.toStdString()); - if (destroyOnZoneChange) + } + if (destroyOnZoneChange) { info->set_destroy_on_zone_change(true); - if (doesntUntap) + } + if (doesntUntap) { info->set_doesnt_untap(true); + } QMapIterator cardCounterIterator(counters); while (cardCounterIterator.hasNext()) { @@ -172,4 +140,4 @@ void Server_Card::getInfo(ServerInfo_Card *info) info->set_attach_zone(parentCard->getZone()->getName().toStdString()); info->set_attach_card_id(parentCard->getId()); } -} \ No newline at end of file +} diff --git a/common/server_card.h b/common/server_card.h index a3564bbc..b397e555 100644 --- a/common/server_card.h +++ b/common/server_card.h @@ -41,7 +41,7 @@ private: bool attacking; bool facedown; QString color; - int power, toughness; + QString ptString; QString annotation; bool destroyOnZoneChange; bool doesntUntap; @@ -102,7 +102,10 @@ public: { return color; } - QString getPT() const; + QString getPT() const + { + return ptString; + } QString getAnnotation() const { return annotation; @@ -154,7 +157,10 @@ public: { color = _color; } - void setPT(const QString &_pt); + void setPT(const QString &_pt) + { + ptString = _pt; + } void setAnnotation(const QString &_annotation) { annotation = _annotation; diff --git a/common/server_player.cpp b/common/server_player.cpp index 8289c640..28acf518 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -102,8 +102,9 @@ void Server_Player::prepareDestroy() delete deck; playerMutex.lock(); - if (userInterface) + if (userInterface) { userInterface->playerRemovedFromGame(game); + } playerMutex.unlock(); clearZones(); @@ -122,8 +123,9 @@ int Server_Player::newCounterId() const QMapIterator i(counters); while (i.hasNext()) { Server_Counter *c = i.next().value(); - if (c->getId() > id) + if (c->getId() > id) { id = c->getId(); + } } return id + 1; } @@ -131,11 +133,10 @@ int Server_Player::newCounterId() const int Server_Player::newArrowId() const { int id = 0; - QMapIterator i(arrows); - while (i.hasNext()) { - Server_Arrow *a = i.next().value(); - if (a->getId() > id) + for (Server_Arrow *a : arrows) { + if (a->getId() > id) { id = a->getId(); + } } return id + 1; } @@ -175,19 +176,22 @@ void Server_Player::setupZones() for (int i = 0; i < listRoot->size(); ++i) { auto *currentZone = dynamic_cast(listRoot->at(i)); Server_CardZone *z; - if (currentZone->getName() == DECK_ZONE_MAIN) + if (currentZone->getName() == DECK_ZONE_MAIN) { z = deckZone; - else if (currentZone->getName() == DECK_ZONE_SIDE) + } else if (currentZone->getName() == DECK_ZONE_SIDE) { z = sbZone; - else + } else { continue; + } for (int j = 0; j < currentZone->size(); ++j) { auto *currentCard = dynamic_cast(currentZone->at(j)); - if (!currentCard) + if (!currentCard) { continue; - for (int k = 0; k < currentCard->getNumber(); ++k) + } + for (int k = 0; k < currentCard->getNumber(); ++k) { z->insertCard(new Server_Card(currentCard->getName(), nextCardId++, 0, 0, z), -1, 0); + } } } @@ -197,25 +201,28 @@ void Server_Player::setupZones() const QString targetZone = QString::fromStdString(m.target_zone()); Server_CardZone *start, *target; - if (startZone == DECK_ZONE_MAIN) + if (startZone == DECK_ZONE_MAIN) { start = deckZone; - else if (startZone == DECK_ZONE_SIDE) + } else if (startZone == DECK_ZONE_SIDE) { start = sbZone; - else + } else { continue; - if (targetZone == DECK_ZONE_MAIN) + } + if (targetZone == DECK_ZONE_MAIN) { target = deckZone; - else if (targetZone == DECK_ZONE_SIDE) + } else if (targetZone == DECK_ZONE_SIDE) { target = sbZone; - else + } else { continue; + } - for (int j = 0; j < start->getCards().size(); ++j) + for (int j = 0; j < start->getCards().size(); ++j) { if (start->getCards()[j]->getName() == QString::fromStdString(m.card_name())) { Server_Card *card = start->getCard(j, nullptr, true); target->insertCard(card, -1, 0); break; } + } } deckZone->shuffle(); @@ -223,19 +230,19 @@ void Server_Player::setupZones() void Server_Player::clearZones() { - QMapIterator zoneIterator(zones); - while (zoneIterator.hasNext()) - delete zoneIterator.next().value(); + for (Server_CardZone *zone : zones) { + delete zone; + } zones.clear(); - QMapIterator counterIterator(counters); - while (counterIterator.hasNext()) - delete counterIterator.next().value(); + for (Server_Counter *counter : counters) { + delete counter; + } counters.clear(); - QMapIterator arrowIterator(arrows); - while (arrowIterator.hasNext()) - delete arrowIterator.next().value(); + for (Server_Arrow *arrow : arrows) { + delete arrow; + } arrows.clear(); lastDrawList.clear(); @@ -244,8 +251,9 @@ void Server_Player::clearZones() void Server_Player::getProperties(ServerInfo_PlayerProperties &result, bool withUserInfo) { result.set_player_id(playerId); - if (withUserInfo) + if (withUserInfo) { copyUserInfo(*(result.mutable_user_info()), true); + } result.set_spectator(spectator); if (!spectator) { result.set_conceded(conceded); @@ -253,8 +261,9 @@ void Server_Player::getProperties(ServerInfo_PlayerProperties &result, bool with result.set_ready_start(readyStart); } result.set_judge(judge); - if (deck) + if (deck) { result.set_deck_hash(deck->getDeckHash().toStdString()); + } result.set_ping_seconds(pingTime); } @@ -271,8 +280,9 @@ void Server_Player::addArrow(Server_Arrow *arrow) bool Server_Player::deleteArrow(int arrowId) { Server_Arrow *arrow = arrows.value(arrowId, 0); - if (!arrow) + if (!arrow) { return false; + } arrows.remove(arrowId); delete arrow; return true; @@ -287,8 +297,9 @@ Response::ResponseCode Server_Player::drawCards(GameEventStorage &ges, int numbe { Server_CardZone *deckZone = zones.value("deck"); Server_CardZone *handZone = zones.value("hand"); - if (deckZone->getCards().size() < number) + if (deckZone->getCards().size() < number) { number = deckZone->getCards().size(); + } Event_DrawCards eventOthers; eventOthers.set_number(number); @@ -331,15 +342,17 @@ public: inline bool operator()(QPair a, QPair b) { if (a.second < x) { - if (b.second >= x) + if (b.second >= x) { return false; - else + } else { return (a.second > b.second); + } } else { - if (b.second < x) + if (b.second < x) { return true; - else + } else { return (a.second < b.second); + } } } }; @@ -355,36 +368,43 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, { // Disallow controller change to other zones than the table. if (((targetzone->getType() != ServerInfo_Zone::PublicZone) || !targetzone->hasCoords()) && - (startzone->getPlayer() != targetzone->getPlayer()) && !judge) + (startzone->getPlayer() != targetzone->getPlayer()) && !judge) { return Response::RespContextError; + } - if (!targetzone->hasCoords() && (x <= -1)) + if (!targetzone->hasCoords() && (x <= -1)) { x = targetzone->getCards().size(); + } QList> cardsToMove; QMap cardProperties; QSet cardIdsToMove; for (auto _card : _cards) { // The same card being moved twice would lead to undefined behaviour. - if (cardIdsToMove.contains(_card->card_id())) + if (cardIdsToMove.contains(_card->card_id())) { continue; + } cardIdsToMove.insert(_card->card_id()); // Consistency checks. In case the command contains illegal moves, try to resolve the legal ones still. int position; Server_Card *card = startzone->getCard(_card->card_id(), &position); - if (!card) + if (!card) { return Response::RespNameNotFound; - if (card->getParentCard()) + } + if (card->getParentCard()) { continue; - if (!card->getAttachedCards().isEmpty() && !targetzone->isColumnEmpty(x, y)) + } + if (!card->getAttachedCards().isEmpty() && !targetzone->isColumnEmpty(x, y)) { continue; + } cardsToMove.append(QPair(card, position)); cardProperties.insert(card, _card); } // In case all moves were filtered out, abort. - if (cardsToMove.isEmpty()) + if (cardsToMove.isEmpty()) { return Response::RespContextError; + } // 0 performs no sorting // 1 reverses the sorting @@ -398,40 +418,46 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, Server_Card *card = cardsToMove[cardIndex].first; const CardToMove *thisCardProperties = cardProperties.value(card); bool faceDown = thisCardProperties->has_face_down() ? thisCardProperties->face_down() : card->getFaceDown(); - if (!targetzone->hasCoords()) + if (!targetzone->hasCoords()) { faceDown = false; + } int originalPosition = cardsToMove[cardIndex].second; int position = startzone->removeCard(card); if (startzone->getName() == "hand") { - if (undoingDraw) + if (undoingDraw) { lastDrawList.removeAt(lastDrawList.indexOf(card->getId())); - else if (lastDrawList.contains(card->getId())) + } else if (lastDrawList.contains(card->getId())) { lastDrawList.clear(); + } } if ((startzone == targetzone) && !startzone->hasCoords()) { if (!secondHalf && (originalPosition < x)) { xIndex = -1; secondHalf = true; - } else if (secondHalf) + } else if (secondHalf) { --xIndex; - else + } else { ++xIndex; - } else + } + } else { ++xIndex; + } int newX = x + xIndex; // Attachment relationships can be retained when moving a card onto the opponent's table if (startzone->getName() != targetzone->getName()) { // Delete all attachment relationships - if (card->getParentCard()) + if (card->getParentCard()) { card->setParentCard(nullptr); + } // Make a copy of the list because the original one gets modified during the loop QList attachedCards = card->getAttachedCards(); - for (auto &attachedCard : attachedCards) + for (auto &attachedCard : attachedCards) { attachedCard->getZone()->getPlayer()->unattachCard(ges, attachedCard); + } } if (startzone != targetzone) { @@ -445,8 +471,9 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, if ((arrow->getStartCard() == card) || (arrow->getTargetItem() == card)) arrowsToDelete.append(arrow->getId()); } - for (int j : arrowsToDelete) + for (int j : arrowsToDelete) { player->deleteArrow(j); + } } } @@ -461,8 +488,9 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, if (!targetzone->hasCoords()) { y = 0; card->resetState(); - } else + } else { newX = targetzone->getFreeGridColumn(newX, y, card->getName(), faceDown); + } targetzone->insertCard(card, newX, y); @@ -479,14 +507,17 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, bool sourceHiddenToOthers = card->getFaceDown() || (startzone->getType() != ServerInfo_Zone::PublicZone); QString privateCardName, publicCardName; - if (!(sourceHiddenToPlayer && targetHiddenToPlayer)) + if (!(sourceHiddenToPlayer && targetHiddenToPlayer)) { privateCardName = card->getName(); - if (!(sourceHiddenToOthers && targetHiddenToOthers)) + } + if (!(sourceHiddenToOthers && targetHiddenToOthers)) { publicCardName = card->getName(); + } int oldCardId = card->getId(); - if ((faceDown && (startzone != targetzone)) || (targetzone->getPlayer() != startzone->getPlayer())) + if ((faceDown && (startzone != targetzone)) || (targetzone->getPlayer() != startzone->getPlayer())) { card->setId(targetzone->getPlayer()->newCardId()); + } card->setFaceDown(faceDown); // The player does not get to see which card he moved if it moves between two parts of hidden zones which @@ -499,8 +530,9 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, privateCardName = QString(); } int privatePosition = -1; - if (startzone->getType() == ServerInfo_Zone::HiddenZone) + if (startzone->getType() == ServerInfo_Zone::HiddenZone) { privatePosition = position; + } int publicNewX = newX; @@ -508,15 +540,17 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, eventOthers.set_start_player_id(startzone->getPlayer()->getPlayerId()); eventOthers.set_start_zone(startzone->getName().toStdString()); eventOthers.set_target_player_id(targetzone->getPlayer()->getPlayerId()); - if (startzone != targetzone) + if (startzone != targetzone) { eventOthers.set_target_zone(targetzone->getName().toStdString()); + } eventOthers.set_y(y); eventOthers.set_face_down(faceDown); Event_MoveCard eventPrivate(eventOthers); eventPrivate.set_card_id(privateOldCardId); - if (!privateCardName.isEmpty()) + if (!privateCardName.isEmpty()) { eventPrivate.set_card_name(privateCardName.toStdString()); + } eventPrivate.set_position(privatePosition); eventPrivate.set_new_card_id(privateNewCardId); eventPrivate.set_x(newX); @@ -526,32 +560,38 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, // all cards are equal. if (((startzone->getType() == ServerInfo_Zone::HiddenZone) && ((startzone->getCardsBeingLookedAt() > position) || (startzone->getCardsBeingLookedAt() == -1))) || - (startzone->getType() == ServerInfo_Zone::PublicZone)) + (startzone->getType() == ServerInfo_Zone::PublicZone)) { position = -1; + } if ((targetzone->getType() == ServerInfo_Zone::HiddenZone) && - ((targetzone->getCardsBeingLookedAt() > newX) || (targetzone->getCardsBeingLookedAt() == -1))) + ((targetzone->getCardsBeingLookedAt() > newX) || (targetzone->getCardsBeingLookedAt() == -1))) { publicNewX = -1; + } eventOthers.set_x(publicNewX); eventOthers.set_position(position); if ((startzone->getType() == ServerInfo_Zone::PublicZone) || (targetzone->getType() == ServerInfo_Zone::PublicZone)) { eventOthers.set_card_id(oldCardId); - if (!publicCardName.isEmpty()) + if (!publicCardName.isEmpty()) { eventOthers.set_card_name(publicCardName.toStdString()); + } eventOthers.set_new_card_id(card->getId()); } ges.enqueueGameEvent(eventPrivate, playerId, GameEventStorageItem::SendToPrivate, playerId); ges.enqueueGameEvent(eventOthers, playerId, GameEventStorageItem::SendToOthers); - if (thisCardProperties->tapped()) + if (thisCardProperties->tapped()) { setCardAttrHelper(ges, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), card->getId(), AttrTapped, "1"); + } QString ptString = QString::fromStdString(thisCardProperties->pt()); - if (!ptString.isEmpty() && !faceDown) - setCardAttrHelper(ges, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), card->getId(), - AttrPT, ptString); + if (!faceDown) { + ptString = QString::fromStdString(thisCardProperties->pt()); + } + setCardAttrHelper(ges, targetzone->getPlayer()->getPlayerId(), targetzone->getName(), card->getId(), AttrPT, + ptString); } if (startzone->getAlwaysRevealTopCard() && !startzone->getCards().isEmpty() && (originalPosition == 0)) { Event_RevealCards revealEvent; @@ -570,13 +610,15 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, ges.enqueueGameEvent(revealEvent, playerId); } } - if (undoingDraw) + if (undoingDraw) { ges.setGameEventContext(Context_UndoDraw()); - else + } else { ges.setGameEventContext(Context_MoveCard()); + } - if (startzone->hasCoords() && fixFreeSpaces) + if (startzone->hasCoords() && fixFreeSpaces) { startzone->fixFreeSpaces(ges); + } return Response::RespOk; } @@ -597,8 +639,9 @@ void Server_Player::unattachCard(GameEventStorage &ges, Server_Card *card) moveCard(ges, zone, QList() << cardToMove, zone, -1, card->getY(), card->getFaceDown()); delete cardToMove; - if (parentCard->getZone()) + if (parentCard->getZone()) { parentCard->getZone()->updateCardCoordinates(parentCard, parentCard->getX(), parentCard->getY()); + } } Response::ResponseCode Server_Player::setCardAttrHelper(GameEventStorage &ges, @@ -609,32 +652,38 @@ Response::ResponseCode Server_Player::setCardAttrHelper(GameEventStorage &ges, const QString &attrValue) { Server_CardZone *zone = getZones().value(zoneName); - if (!zone) + if (!zone) { return Response::RespNameNotFound; - if (!zone->hasCoords()) + } + if (!zone->hasCoords()) { return Response::RespContextError; + } QString result; if (cardId == -1) { QListIterator CardIterator(zone->getCards()); while (CardIterator.hasNext()) { result = CardIterator.next()->setAttribute(attribute, attrValue, true); - if (result.isNull()) + if (result.isNull()) { return Response::RespInvalidCommand; + } } } else { Server_Card *card = zone->getCard(cardId); - if (!card) + if (!card) { return Response::RespNameNotFound; + } result = card->setAttribute(attribute, attrValue, false); - if (result.isNull()) + if (result.isNull()) { return Response::RespInvalidCommand; + } } Event_SetCardAttr event; event.set_zone_name(zone->getName().toStdString()); - if (cardId != -1) + if (cardId != -1) { event.set_card_id(cardId); + } event.set_attribute(attribute); event.set_attr_value(result.toStdString()); ges.enqueueGameEvent(event, targetPlayerId); @@ -652,11 +701,13 @@ Server_Player::cmdLeaveGame(const Command_LeaveGame & /*cmd*/, ResponseContainer Response::ResponseCode Server_Player::cmdKickFromGame(const Command_KickFromGame &cmd, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { - if ((game->getHostId() != playerId) && !(userInfo->user_level() & ServerInfo_User::IsModerator)) + if ((game->getHostId() != playerId) && !(userInfo->user_level() & ServerInfo_User::IsModerator)) { return Response::RespFunctionNotAllowed; + } - if (!game->kickPlayer(cmd.player_id())) + if (!game->kickPlayer(cmd.player_id())) { return Response::RespNameNotFound; + } return Response::RespOk; } @@ -664,8 +715,9 @@ Server_Player::cmdKickFromGame(const Command_KickFromGame &cmd, ResponseContaine Response::ResponseCode Server_Player::cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &rc, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } DeckList *newDeck; if (cmd.has_deck_id()) { @@ -675,11 +727,13 @@ Server_Player::cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &r } catch (Response::ResponseCode &r) { return r; } - } else + } else { newDeck = new DeckList(QString::fromStdString(cmd.deck())); + } - if (!newDeck) + if (!newDeck) { return Response::RespInternalError; + } delete deck; deck = newDeck; @@ -706,18 +760,23 @@ Response::ResponseCode Server_Player::cmdSetSideboardPlan(const Command_SetSideb ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; - if (readyStart) + } + if (readyStart) { return Response::RespContextError; - if (!deck) + } + if (!deck) { return Response::RespContextError; - if (sideboardLocked) + } + if (sideboardLocked) { return Response::RespContextError; + } QList sideboardPlan; - for (int i = 0; i < cmd.move_list_size(); ++i) + for (int i = 0; i < cmd.move_list_size(); ++i) { sideboardPlan.append(cmd.move_list(i)); + } deck->setCurrentSideboardPlan(sideboardPlan); return Response::RespOk; @@ -727,18 +786,23 @@ Response::ResponseCode Server_Player::cmdSetSideboardLock(const Command_SetSideb ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; - if (readyStart) + } + if (readyStart) { return Response::RespContextError; - if (!deck) + } + if (!deck) { return Response::RespContextError; - if (sideboardLocked == cmd.locked()) + } + if (sideboardLocked == cmd.locked()) { return Response::RespContextError; + } sideboardLocked = cmd.locked(); - if (sideboardLocked) + if (sideboardLocked) { deck->setCurrentSideboardPlan(QList()); + } Event_PlayerPropertiesChanged event; event.mutable_player_properties()->set_sideboard_locked(sideboardLocked); @@ -751,12 +815,15 @@ Response::ResponseCode Server_Player::cmdSetSideboardLock(const Command_SetSideb Response::ResponseCode Server_Player::cmdConcede(const Command_Concede & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; - if (!game->getGameStarted()) + } + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } setConceded(true); game->removeArrowsRelatedToPlayer(ges, this); @@ -769,8 +836,9 @@ Server_Player::cmdConcede(const Command_Concede & /*cmd*/, ResponseContainer & / ges.setGameEventContext(Context_Concede()); game->stopGameIfFinished(); - if (game->getGameStarted() && (game->getActivePlayer() == playerId)) + if (game->getGameStarted() && (game->getActivePlayer() == playerId)) { game->nextTurn(); + } return Response::RespOk; } @@ -778,12 +846,15 @@ Server_Player::cmdConcede(const Command_Concede & /*cmd*/, ResponseContainer & / Response::ResponseCode Server_Player::cmdUnconcede(const Command_Unconcede & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; - if (!game->getGameStarted()) + } + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (!conceded) + } + if (!conceded) { return Response::RespContextError; + } setConceded(false); @@ -820,14 +891,17 @@ Response::ResponseCode Server_Player::cmdJudge(const Command_Judge &cmd, Respons Response::ResponseCode Server_Player::cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!deck || game->getGameStarted()) + if (!deck || game->getGameStarted()) { return Response::RespContextError; + } - if (readyStart == cmd.ready()) + if (readyStart == cmd.ready()) { return Response::RespContextError; + } setReadyStart(cmd.ready()); @@ -836,8 +910,9 @@ Server_Player::cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer & ges.enqueueGameEvent(event, playerId); ges.setGameEventContext(Context_ReadyStart()); - if (cmd.ready()) + if (cmd.ready()) { game->startGameIfReady(); + } return Response::RespOk; } @@ -845,8 +920,9 @@ Server_Player::cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer & Response::ResponseCode Server_Player::cmdGameSay(const Command_GameSay &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator && !game->getSpectatorsCanTalk() && !(userInfo->user_level() & ServerInfo_User::IsModerator)) + if (spectator && !game->getSpectatorsCanTalk() && !(userInfo->user_level() & ServerInfo_User::IsModerator)) { return Response::RespFunctionNotAllowed; + } Event_GameSay event; event.set_message(cmd.message()); @@ -863,21 +939,26 @@ Server_Player::cmdGameSay(const Command_GameSay &cmd, ResponseContainer & /*rc*/ Response::ResponseCode Server_Player::cmdShuffle(const Command_Shuffle &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; + } - if (conceded) + if (conceded) { return Response::RespContextError; + } - if (cmd.has_zone_name() && cmd.zone_name() != "deck") + if (cmd.has_zone_name() && cmd.zone_name() != "deck") { return Response::RespFunctionNotAllowed; + } Server_CardZone *zone = zones.value("deck"); - if (!zone) + if (!zone) { return Response::RespNameNotFound; + } zone->shuffle(cmd.start(), cmd.end()); @@ -902,13 +983,16 @@ Server_Player::cmdShuffle(const Command_Shuffle &cmd, ResponseContainer & /*rc*/ Response::ResponseCode Server_Player::cmdMulligan(const Command_Mulligan & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_CardZone *hand = zones.value("hand"); int number = (hand->getCards().size() <= 1) ? initialCards : hand->getCards().size() - 1; @@ -926,8 +1010,9 @@ Server_Player::cmdMulligan(const Command_Mulligan & /*cmd*/, ResponseContainer & drawCards(ges, number); - if (number == initialCards) + if (number == initialCards) { number = -1; + } Context_Mulligan context; context.set_number(static_cast(number)); @@ -939,10 +1024,12 @@ Server_Player::cmdMulligan(const Command_Mulligan & /*cmd*/, ResponseContainer & Response::ResponseCode Server_Player::cmdRollDie(const Command_RollDie &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Event_RollDie event; event.set_sides(cmd.sides()); @@ -955,13 +1042,16 @@ Server_Player::cmdRollDie(const Command_RollDie &cmd, ResponseContainer & /*rc*/ Response::ResponseCode Server_Player::cmdDrawCards(const Command_DrawCards &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } return drawCards(ges, cmd.number()); } @@ -969,16 +1059,20 @@ Server_Player::cmdDrawCards(const Command_DrawCards &cmd, ResponseContainer & /* Response::ResponseCode Server_Player::cmdUndoDraw(const Command_UndoDraw & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } - if (lastDrawList.isEmpty()) + if (lastDrawList.isEmpty()) { return Response::RespContextError; + } Response::ResponseCode retVal; auto *cardToMove = new CardToMove; @@ -993,37 +1087,47 @@ Server_Player::cmdUndoDraw(const Command_UndoDraw & /*cmd*/, ResponseContainer & Response::ResponseCode Server_Player::cmdMoveCard(const Command_MoveCard &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_Player *startPlayer = game->getPlayers().value(cmd.has_start_player_id() ? cmd.start_player_id() : playerId); - if (!startPlayer) + if (!startPlayer) { return Response::RespNameNotFound; + } Server_CardZone *startZone = startPlayer->getZones().value(QString::fromStdString(cmd.start_zone())); - if (!startZone) + if (!startZone) { return Response::RespNameNotFound; + } - if ((startPlayer != this) && (!startZone->getPlayersWithWritePermission().contains(playerId)) && !judge) + if ((startPlayer != this) && (!startZone->getPlayersWithWritePermission().contains(playerId)) && !judge) { return Response::RespContextError; + } Server_Player *targetPlayer = game->getPlayers().value(cmd.target_player_id()); - if (!targetPlayer) + if (!targetPlayer) { return Response::RespNameNotFound; + } Server_CardZone *targetZone = targetPlayer->getZones().value(QString::fromStdString(cmd.target_zone())); - if (!targetZone) + if (!targetZone) { return Response::RespNameNotFound; + } - if ((startPlayer != this) && (targetPlayer != this) && !judge) + if ((startPlayer != this) && (targetPlayer != this) && !judge) { return Response::RespContextError; + } QList cardsToMove; - for (int i = 0; i < cmd.cards_to_move().card_size(); ++i) + for (int i = 0; i < cmd.cards_to_move().card_size(); ++i) { cardsToMove.append(&cmd.cards_to_move().card(i)); + } return moveCard(ges, startZone, cardsToMove, targetZone, cmd.x(), cmd.y()); } @@ -1031,41 +1135,50 @@ Server_Player::cmdMoveCard(const Command_MoveCard &cmd, ResponseContainer & /*rc Response::ResponseCode Server_Player::cmdFlipCard(const Command_FlipCard &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_CardZone *zone = zones.value(QString::fromStdString(cmd.zone())); - if (!zone) + if (!zone) { return Response::RespNameNotFound; - if (!zone->hasCoords()) + } + if (!zone->hasCoords()) { return Response::RespContextError; + } Server_Card *card = zone->getCard(cmd.card_id()); - if (!card) + if (!card) { return Response::RespNameNotFound; + } const bool faceDown = cmd.face_down(); - if (faceDown == card->getFaceDown()) + if (faceDown == card->getFaceDown()) { return Response::RespContextError; + } card->setFaceDown(faceDown); Event_FlipCard event; event.set_zone_name(zone->getName().toStdString()); event.set_card_id(card->getId()); - if (!faceDown) + if (!faceDown) { event.set_card_name(card->getName().toStdString()); + } event.set_face_down(faceDown); ges.enqueueGameEvent(event, playerId); QString ptString = QString::fromStdString(cmd.pt()); - if (!ptString.isEmpty() && !faceDown) + if (!ptString.isEmpty() && !faceDown) { setCardAttrHelper(ges, playerId, zone->getName(), card->getId(), AttrPT, ptString); + } return Response::RespOk; } @@ -1073,21 +1186,26 @@ Server_Player::cmdFlipCard(const Command_FlipCard &cmd, ResponseContainer & /*rc Response::ResponseCode Server_Player::cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_CardZone *startzone = zones.value(QString::fromStdString(cmd.start_zone())); - if (!startzone) + if (!startzone) { return Response::RespNameNotFound; + } Server_Card *card = startzone->getCard(cmd.card_id()); - if (!card) + if (!card) { return Response::RespNameNotFound; + } Server_Player *targetPlayer = nullptr; Server_CardZone *targetzone = nullptr; @@ -1095,27 +1213,35 @@ Server_Player::cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer & if (cmd.has_target_player_id()) { targetPlayer = game->getPlayers().value(cmd.target_player_id()); - if (!targetPlayer) + if (!targetPlayer) { return Response::RespNameNotFound; - } else if (!card->getParentCard()) + } + } else if (!card->getParentCard()) { return Response::RespContextError; - if (targetPlayer) + } + if (targetPlayer) { targetzone = targetPlayer->getZones().value(QString::fromStdString(cmd.target_zone())); + } if (targetzone) { // This is currently enough to make sure cards don't get attached to a card that is not on the table. // Possibly a flag will have to be introduced for this sometime. - if (!targetzone->hasCoords()) + if (!targetzone->hasCoords()) { return Response::RespContextError; - if (cmd.has_target_card_id()) + } + if (cmd.has_target_card_id()) { targetCard = targetzone->getCard(cmd.target_card_id()); + } if (targetCard) { - if (targetCard->getParentCard()) + if (targetCard->getParentCard()) { return Response::RespContextError; - } else + } + } else { return Response::RespNameNotFound; + } } - if (!startzone->hasCoords()) + if (!startzone->hasCoords()) { return Response::RespContextError; + } // Get all arrows pointing to or originating from the card being attached and delete them. QMapIterator playerIterator(game->getPlayers()); @@ -1125,8 +1251,9 @@ Server_Player::cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer & QList toDelete; for (auto a : arrows) { auto *tCard = qobject_cast(a->getTargetItem()); - if ((tCard == card) || (a->getStartCard() == card)) + if ((tCard == card) || (a->getStartCard() == card)) { toDelete.append(a); + } } for (auto &i : toDelete) { Event_DeleteArrow event; @@ -1140,8 +1267,9 @@ Server_Player::cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer & // Unattach all cards attached to the card being attached. // Make a copy of the list because its contents change during the loop otherwise. QList attachedList = card->getAttachedCards(); - for (auto &i : attachedList) + for (const auto &i : attachedList) { i->getZone()->getPlayer()->unattachCard(ges, i); + } card->setParentCard(targetCard); const int oldX = card->getX(); @@ -1166,8 +1294,9 @@ Server_Player::cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer & ges.enqueueGameEvent(event, playerId); startzone->fixFreeSpaces(ges); - } else + } else { unattachCard(ges, card); + } return Response::RespOk; } @@ -1175,27 +1304,34 @@ Server_Player::cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer & Response::ResponseCode Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer &rc, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_CardZone *zone = zones.value(QString::fromStdString(cmd.zone())); - if (!zone) + if (!zone) { return Response::RespNameNotFound; + } QString cardName = QString::fromStdString(cmd.card_name()); int x = cmd.x(); int y = cmd.y(); - if (zone->hasCoords()) + if (zone->hasCoords()) { x = zone->getFreeGridColumn(x, y, cardName, false); - if (x < 0) + } + if (x < 0) { x = 0; - if (y < 0) + } + if (y < 0) { y = 0; + } Server_Card *card = new Server_Card(cardName, newCardId(), x, y); card->moveToThread(thread()); @@ -1219,8 +1355,9 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer ges.enqueueGameEvent(event, playerId); // check if the token is a replacement for an existing card - if (cmd.target_card_id() < 0) + if (cmd.target_card_id() < 0) { return Response::RespOk; + } Command_AttachCard cmd2; cmd2.set_start_zone(cmd.target_zone()); @@ -1236,51 +1373,63 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer Response::ResponseCode Server_Player::cmdCreateArrow(const Command_CreateArrow &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_Player *startPlayer = game->getPlayers().value(cmd.start_player_id()); Server_Player *targetPlayer = game->getPlayers().value(cmd.target_player_id()); - if (!startPlayer || !targetPlayer) + if (!startPlayer || !targetPlayer) { return Response::RespNameNotFound; + } QString startZoneName = QString::fromStdString(cmd.start_zone()); Server_CardZone *startZone = startPlayer->getZones().value(startZoneName); bool playerTarget = !cmd.has_target_zone(); Server_CardZone *targetZone = nullptr; - if (!playerTarget) + if (!playerTarget) { targetZone = targetPlayer->getZones().value(QString::fromStdString(cmd.target_zone())); - if (!startZone || (!targetZone && !playerTarget)) + } + if (!startZone || (!targetZone && !playerTarget)) { return Response::RespNameNotFound; - if (startZone->getType() != ServerInfo_Zone::PublicZone) + } + if (startZone->getType() != ServerInfo_Zone::PublicZone) { return Response::RespContextError; + } Server_Card *startCard = startZone->getCard(cmd.start_card_id()); - if (!startCard) + if (!startCard) { return Response::RespNameNotFound; + } Server_Card *targetCard = nullptr; if (!playerTarget) { - if (targetZone->getType() != ServerInfo_Zone::PublicZone) + if (targetZone->getType() != ServerInfo_Zone::PublicZone) { return Response::RespContextError; + } targetCard = targetZone->getCard(cmd.target_card_id()); } Server_ArrowTarget *targetItem; - if (playerTarget) + if (playerTarget) { targetItem = targetPlayer; - else + } else { targetItem = targetCard; - if (!targetItem) + } + if (!targetItem) { return Response::RespNameNotFound; + } QMapIterator arrowIterator(arrows); while (arrowIterator.hasNext()) { Server_Arrow *temp = arrowIterator.next().value(); - if ((temp->getStartCard() == startCard) && (temp->getTargetItem() == targetItem)) + if ((temp->getStartCard() == startCard) && (temp->getTargetItem() == targetItem)) { return Response::RespContextError; + } } auto arrow = new Server_Arrow(newArrowId(), startCard, targetItem, cmd.arrow_color()); @@ -1306,16 +1455,20 @@ Server_Player::cmdCreateArrow(const Command_CreateArrow &cmd, ResponseContainer Response::ResponseCode Server_Player::cmdDeleteArrow(const Command_DeleteArrow &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } - if (!deleteArrow(cmd.arrow_id())) + if (!deleteArrow(cmd.arrow_id())) { return Response::RespNameNotFound; + } Event_DeleteArrow event; event.set_arrow_id(cmd.arrow_id()); @@ -1327,13 +1480,16 @@ Server_Player::cmdDeleteArrow(const Command_DeleteArrow &cmd, ResponseContainer Response::ResponseCode Server_Player::cmdSetCardAttr(const Command_SetCardAttr &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } return setCardAttrHelper(ges, playerId, QString::fromStdString(cmd.zone()), cmd.card_id(), cmd.attribute(), QString::fromStdString(cmd.attr_value())); @@ -1342,23 +1498,29 @@ Server_Player::cmdSetCardAttr(const Command_SetCardAttr &cmd, ResponseContainer Response::ResponseCode Server_Player::cmdSetCardCounter(const Command_SetCardCounter &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_CardZone *zone = zones.value(QString::fromStdString(cmd.zone())); - if (!zone) + if (!zone) { return Response::RespNameNotFound; - if (!zone->hasCoords()) + } + if (!zone->hasCoords()) { return Response::RespContextError; + } Server_Card *card = zone->getCard(cmd.card_id()); - if (!card) + if (!card) { return Response::RespNameNotFound; + } card->setCounter(cmd.counter_id(), cmd.counter_value()); @@ -1375,23 +1537,29 @@ Server_Player::cmdSetCardCounter(const Command_SetCardCounter &cmd, ResponseCont Response::ResponseCode Server_Player::cmdIncCardCounter(const Command_IncCardCounter &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_CardZone *zone = zones.value(QString::fromStdString(cmd.zone())); - if (!zone) + if (!zone) { return Response::RespNameNotFound; - if (!zone->hasCoords()) + } + if (!zone->hasCoords()) { return Response::RespContextError; + } Server_Card *card = zone->getCard(cmd.card_id()); - if (!card) + if (!card) { return Response::RespNameNotFound; + } int newValue = card->getCounter(cmd.counter_id()) + cmd.counter_delta(); card->setCounter(cmd.counter_id(), newValue); @@ -1409,17 +1577,21 @@ Server_Player::cmdIncCardCounter(const Command_IncCardCounter &cmd, ResponseCont Response::ResponseCode Server_Player::cmdIncCounter(const Command_IncCounter &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_Counter *c = counters.value(cmd.counter_id(), 0); - if (!c) + if (!c) { return Response::RespNameNotFound; + } c->setCount(c->getCount() + cmd.delta()); @@ -1434,13 +1606,16 @@ Server_Player::cmdIncCounter(const Command_IncCounter &cmd, ResponseContainer & Response::ResponseCode Server_Player::cmdCreateCounter(const Command_CreateCounter &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_Counter *c = new Server_Counter(newCounterId(), QString::fromStdString(cmd.counter_name()), cmd.counter_color(), cmd.radius(), cmd.value()); @@ -1461,18 +1636,21 @@ Server_Player::cmdCreateCounter(const Command_CreateCounter &cmd, ResponseContai Response::ResponseCode Server_Player::cmdSetCounter(const Command_SetCounter &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_Counter *c = counters.value(cmd.counter_id(), 0); - ; - if (!c) + if (!c) { return Response::RespNameNotFound; + } c->setCount(cmd.value()); @@ -1487,17 +1665,21 @@ Server_Player::cmdSetCounter(const Command_SetCounter &cmd, ResponseContainer & Response::ResponseCode Server_Player::cmdDelCounter(const Command_DelCounter &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_Counter *counter = counters.value(cmd.counter_id(), 0); - if (!counter) + if (!counter) { return Response::RespNameNotFound; + } counters.remove(cmd.counter_id()); delete counter; @@ -1511,15 +1693,18 @@ Server_Player::cmdDelCounter(const Command_DelCounter &cmd, ResponseContainer & Response::ResponseCode Server_Player::cmdNextTurn(const Command_NextTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; + } if (!judge) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (conceded) + if (conceded) { return Response::RespContextError; + } } game->nextTurn(); @@ -1530,18 +1715,22 @@ Response::ResponseCode Server_Player::cmdSetActivePhase(const Command_SetActiveP ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; + } if (!judge) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (conceded) + if (conceded) { return Response::RespContextError; + } - if (game->getActivePlayer() != playerId) + if (game->getActivePlayer() != playerId) { return Response::RespContextError; + } } game->setActivePhase(cmd.phase()); @@ -1552,17 +1741,21 @@ Response::ResponseCode Server_Player::cmdSetActivePhase(const Command_SetActiveP Response::ResponseCode Server_Player::cmdDumpZone(const Command_DumpZone &cmd, ResponseContainer &rc, GameEventStorage &ges) { - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; + } Server_Player *otherPlayer = game->getPlayers().value(cmd.player_id()); - if (!otherPlayer) + if (!otherPlayer) { return Response::RespNameNotFound; + } Server_CardZone *zone = otherPlayer->getZones().value(QString::fromStdString(cmd.zone_name())); - if (!zone) + if (!zone) { return Response::RespNameNotFound; - if (!((zone->getType() == ServerInfo_Zone::PublicZone) || (this == otherPlayer))) + } + if (!((zone->getType() == ServerInfo_Zone::PublicZone) || (this == otherPlayer))) { return Response::RespContextError; + } int numberCards = cmd.number_cards(); const QList &cards = zone->getCards(); @@ -1579,9 +1772,9 @@ Server_Player::cmdDumpZone(const Command_DumpZone &cmd, ResponseContainer &rc, G QString displayedName = card->getFaceDown() ? QString() : card->getName(); ServerInfo_Card *cardInfo = zoneInfo->add_card_list(); cardInfo->set_name(displayedName.toStdString()); - if (zone->getType() == ServerInfo_Zone::HiddenZone) + if (zone->getType() == ServerInfo_Zone::HiddenZone) { cardInfo->set_id(i); - else { + } else { cardInfo->set_id(card->getId()); cardInfo->set_x(card->getX()); cardInfo->set_y(card->getY()); @@ -1625,17 +1818,21 @@ Server_Player::cmdDumpZone(const Command_DumpZone &cmd, ResponseContainer &rc, G Response::ResponseCode Server_Player::cmdStopDumpZone(const Command_StopDumpZone &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } Server_Player *otherPlayer = game->getPlayers().value(cmd.player_id()); - if (!otherPlayer) + if (!otherPlayer) { return Response::RespNameNotFound; + } Server_CardZone *zone = otherPlayer->getZones().value(QString::fromStdString(cmd.zone_name())); - if (!zone) + if (!zone) { return Response::RespNameNotFound; + } if (zone->getType() == ServerInfo_Zone::HiddenZone) { zone->setCardsBeingLookedAt(0); @@ -1651,13 +1848,16 @@ Server_Player::cmdStopDumpZone(const Command_StopDumpZone &cmd, ResponseContaine Response::ResponseCode Server_Player::cmdRevealCards(const Command_RevealCards &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { - if (spectator) + if (spectator) { return Response::RespFunctionNotAllowed; + } - if (!game->getGameStarted()) + if (!game->getGameStarted()) { return Response::RespGameNotStarted; - if (conceded) + } + if (conceded) { return Response::RespContextError; + } if (cmd.has_player_id()) { Server_Player *otherPlayer = game->getPlayers().value(cmd.player_id()); @@ -1665,27 +1865,31 @@ Server_Player::cmdRevealCards(const Command_RevealCards &cmd, ResponseContainer return Response::RespNameNotFound; } Server_CardZone *zone = zones.value(QString::fromStdString(cmd.zone_name())); - if (!zone) + if (!zone) { return Response::RespNameNotFound; + } QList cardsToReveal; if (cmd.top_cards() != -1) { for (int i = 0; i < cmd.top_cards(); i++) { Server_Card *card = zone->getCard(i); - if (!card) + if (!card) { return Response::RespNameNotFound; + } cardsToReveal.append(card); } - } else if (!cmd.has_card_id()) + } else if (!cmd.has_card_id()) { cardsToReveal = zone->getCards(); - else if (cmd.card_id() == -2) { - if (zone->getCards().isEmpty()) + } else if (cmd.card_id() == -2) { + if (zone->getCards().isEmpty()) { return Response::RespContextError; + } cardsToReveal.append(zone->getCards().at(rng->rand(0, zone->getCards().size() - 1))); } else { Server_Card *card = zone->getCard(cmd.card_id()); - if (!card) + if (!card) { return Response::RespNameNotFound; + } cardsToReveal.append(card); } @@ -1693,10 +1897,12 @@ Server_Player::cmdRevealCards(const Command_RevealCards &cmd, ResponseContainer eventOthers.set_grant_write_access(cmd.grant_write_access()); eventOthers.set_zone_name(zone->getName().toStdString()); eventOthers.set_number_of_cards(cardsToReveal.size()); - if (cmd.has_card_id()) + if (cmd.has_card_id()) { eventOthers.set_card_id(cmd.card_id()); - if (cmd.has_player_id()) + } + if (cmd.has_player_id()) { eventOthers.set_other_player_id(cmd.player_id()); + } Event_RevealCards eventPrivate(eventOthers); @@ -1732,16 +1938,18 @@ Server_Player::cmdRevealCards(const Command_RevealCards &cmd, ResponseContainer } if (cmd.has_player_id()) { - if (cmd.grant_write_access()) + if (cmd.grant_write_access()) { zone->addWritePermission(cmd.player_id()); + } ges.enqueueGameEvent(eventPrivate, playerId, GameEventStorageItem::SendToPrivate, cmd.player_id()); ges.enqueueGameEvent(eventOthers, playerId, GameEventStorageItem::SendToOthers); } else { if (cmd.grant_write_access()) { const QList &playerIds = game->getPlayers().keys(); - for (int playerId : playerIds) + for (int playerId : playerIds) { zone->addWritePermission(playerId); + } } ges.enqueueGameEvent(eventPrivate, playerId); @@ -1755,15 +1963,17 @@ Response::ResponseCode Server_Player::cmdChangeZoneProperties(const Command_Chan GameEventStorage &ges) { Server_CardZone *zone = zones.value(QString::fromStdString(cmd.zone_name())); - if (!zone) + if (!zone) { return Response::RespNameNotFound; + } Event_ChangeZoneProperties event; event.set_zone_name(cmd.zone_name()); if (cmd.has_always_reveal_top_card()) { - if (zone->getAlwaysRevealTopCard() == cmd.always_reveal_top_card()) + if (zone->getAlwaysRevealTopCard() == cmd.always_reveal_top_card()) { return Response::RespContextError; + } zone->setAlwaysRevealTopCard(cmd.always_reveal_top_card()); event.set_always_reveal_top_card(cmd.always_reveal_top_card()); @@ -1778,8 +1988,9 @@ Response::ResponseCode Server_Player::cmdChangeZoneProperties(const Command_Chan ges.enqueueGameEvent(revealEvent, playerId); } return Response::RespOk; - } else + } else { return Response::RespContextError; + } } Response::ResponseCode @@ -1898,8 +2109,9 @@ void Server_Player::sendGameEvent(const GameEventContainer &cont) { QMutexLocker locker(&playerMutex); - if (userInterface) + if (userInterface) { userInterface->sendProtocolItem(cont); + } } void Server_Player::setUserInterface(Server_AbstractUserInterface *_userInterface) @@ -1921,10 +2133,11 @@ void Server_Player::setUserInterface(Server_AbstractUserInterface *_userInterfac void Server_Player::disconnectClient() { - if (!(userInfo->user_level() & ServerInfo_User::IsRegistered) || spectator) + if (!(userInfo->user_level() & ServerInfo_User::IsRegistered) || spectator) { game->removePlayer(this, Event_Leave::USER_DISCONNECTED); - else + } else { setUserInterface(nullptr); + } } void Server_Player::getInfo(ServerInfo_Player *info, @@ -1933,19 +2146,21 @@ void Server_Player::getInfo(ServerInfo_Player *info, bool withUserInfo) { getProperties(*info->mutable_properties(), withUserInfo); - if (playerWhosAsking == this) - if (deck) + if (playerWhosAsking == this) { + if (deck) { info->set_deck_list(deck->writeToString_Native().toStdString()); + } + } - QMapIterator arrowIterator(arrows); - while (arrowIterator.hasNext()) - arrowIterator.next().value()->getInfo(info->add_arrow_list()); + for (Server_Arrow *arrow : arrows) { + arrow->getInfo(info->add_arrow_list()); + } - QMapIterator counterIterator(counters); - while (counterIterator.hasNext()) - counterIterator.next().value()->getInfo(info->add_counter_list()); + for (Server_Counter *counter : counters) { + counter->getInfo(info->add_counter_list()); + } - QMapIterator zoneIterator(zones); - while (zoneIterator.hasNext()) - zoneIterator.next().value()->getInfo(info->add_zone_list(), playerWhosAsking, omniscient); + for (Server_CardZone *zone : zones) { + zone->getInfo(info->add_zone_list(), playerWhosAsking, omniscient); + } }