mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
Preview token edits live and preserve custom drafts
This commit is contained in:
parent
e08402ac94
commit
7e9c209e9a
7 changed files with 296 additions and 29 deletions
|
|
@ -84,6 +84,7 @@ set(cockatrice_SOURCES
|
|||
src/game_graphics/deckview/tabbed_deck_view_container.cpp
|
||||
src/game_graphics/dialogs/dlg_annotation.cpp
|
||||
src/game_graphics/dialogs/dlg_create_token.cpp
|
||||
src/game_graphics/dialogs/token_preview_widget.cpp
|
||||
src/game_graphics/dialogs/dlg_move_top_cards_until.cpp
|
||||
src/game_graphics/dialogs/dlg_roll_dice.cpp
|
||||
src/game_graphics/game_scene.cpp
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#include "dlg_create_token.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../interface/widgets/cards/card_info_picture_widget.h"
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
#include "libcockatrice/card/database/card_database_querier.h"
|
||||
#include "token_preview_widget.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QChar>
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#include <QModelIndex>
|
||||
#include <QRadioButton>
|
||||
#include <QSet>
|
||||
#include <QSignalBlocker>
|
||||
#include <QTimer>
|
||||
#include <QTreeView>
|
||||
#include <QVBoxLayout>
|
||||
|
|
@ -41,11 +42,12 @@ class QWidget;
|
|||
DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *parent)
|
||||
: QDialog(parent), predefinedTokens(_predefinedTokens)
|
||||
{
|
||||
pic = new CardInfoPictureWidget();
|
||||
pic = new TokenPreviewWidget();
|
||||
pic->setObjectName("pic");
|
||||
|
||||
nameLabel = new QLabel(tr("&Name:"));
|
||||
nameEdit = new QLineEdit(tr("Token"));
|
||||
nameEdit->setObjectName("tokenName");
|
||||
nameEdit->setMaxLength(MAX_NAME_LENGTH);
|
||||
QTimer::singleShot(100, this, [=, this]() {
|
||||
nameEdit->selectAll();
|
||||
|
|
@ -57,6 +59,7 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
|
|||
|
||||
colorLabel = new QLabel(tr("C&olor:"));
|
||||
colorEdit = new QComboBox;
|
||||
colorEdit->setObjectName("tokenColor");
|
||||
colorEdit->addItem(tr("white"), QChar('w'));
|
||||
colorEdit->addItem(tr("blue"), QChar('u'));
|
||||
colorEdit->addItem(tr("black"), QChar('b'));
|
||||
|
|
@ -68,11 +71,13 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
|
|||
|
||||
ptLabel = new QLabel(tr("&P/T:"));
|
||||
ptEdit = new QLineEdit;
|
||||
ptEdit->setObjectName("tokenPT");
|
||||
ptEdit->setMaxLength(MAX_NAME_LENGTH);
|
||||
ptLabel->setBuddy(ptEdit);
|
||||
|
||||
annotationLabel = new QLabel(tr("&Annotation:"));
|
||||
annotationEdit = new QLineEdit;
|
||||
annotationEdit->setObjectName("tokenAnnotation");
|
||||
annotationEdit->setMaxLength(MAX_NAME_LENGTH);
|
||||
annotationLabel->setBuddy(annotationEdit);
|
||||
|
||||
|
|
@ -80,6 +85,7 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
|
|||
destroyCheckBox->setChecked(true);
|
||||
|
||||
faceDownCheckBox = new QCheckBox(tr("Create face-down (Only hides name)"));
|
||||
faceDownCheckBox->setObjectName("tokenFaceDown");
|
||||
connect(faceDownCheckBox, &QCheckBox::toggled, this, &DlgCreateToken::faceDownCheckBoxToggled);
|
||||
|
||||
auto *grid = new QGridLayout;
|
||||
|
|
@ -173,6 +179,12 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
|
|||
|
||||
setWindowTitle(tr("Create token"));
|
||||
|
||||
connect(nameEdit, &QLineEdit::textChanged, this, &DlgCreateToken::updatePreview);
|
||||
connect(colorEdit, qOverload<int>(&QComboBox::currentIndexChanged), this, &DlgCreateToken::updatePreview);
|
||||
connect(ptEdit, &QLineEdit::textChanged, this, &DlgCreateToken::updatePreview);
|
||||
connect(annotationEdit, &QLineEdit::textChanged, this, &DlgCreateToken::updatePreview);
|
||||
updatePreview();
|
||||
|
||||
resize(600, 500);
|
||||
restoreGeometry(SettingsCache::instance().layouts().getTokenDialogGeometry());
|
||||
}
|
||||
|
|
@ -185,17 +197,14 @@ void DlgCreateToken::closeEvent(QCloseEvent *event)
|
|||
|
||||
void DlgCreateToken::faceDownCheckBoxToggled(bool checked)
|
||||
{
|
||||
// Keep the face-up draft so toggling this option is reversible. The outgoing
|
||||
// TokenInfo and preview apply the same face-down color/P/T restrictions.
|
||||
colorEdit->setEnabled(!checked);
|
||||
ptEdit->setEnabled(!checked);
|
||||
if (checked) {
|
||||
colorEdit->setCurrentIndex(6);
|
||||
colorEdit->setEnabled(false);
|
||||
ptEdit->clear();
|
||||
ptEdit->clearFocus();
|
||||
ptEdit->setEnabled(false);
|
||||
} else {
|
||||
colorEdit->setEnabled(true);
|
||||
ptEdit->setEnabled(true);
|
||||
annotationEdit->setEnabled(true);
|
||||
}
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void DlgCreateToken::tokenSelectionChanged(const QModelIndex ¤t, const QModelIndex & /*previous*/)
|
||||
|
|
@ -204,11 +213,14 @@ void DlgCreateToken::tokenSelectionChanged(const QModelIndex ¤t, const QMo
|
|||
|
||||
CardInfoPtr cardInfo;
|
||||
|
||||
if (current.row() >= 0) {
|
||||
if (realIndex.isValid()) {
|
||||
cardInfo = cardDatabaseModel->getCard(realIndex.row());
|
||||
}
|
||||
|
||||
if (cardInfo) {
|
||||
const QSignalBlocker colorBlocker(colorEdit);
|
||||
const QSignalBlocker ptBlocker(ptEdit);
|
||||
const QSignalBlocker annotationBlocker(annotationEdit);
|
||||
updateSearchFieldWithoutUpdatingFilter(cardInfo->getName());
|
||||
const QChar cardColor = cardInfo->getColorChar();
|
||||
colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString));
|
||||
|
|
@ -216,21 +228,22 @@ void DlgCreateToken::tokenSelectionChanged(const QModelIndex ¤t, const QMo
|
|||
if (SettingsCache::instance().userInterface().getAnnotateTokens()) {
|
||||
annotationEdit->setText(cardInfo->getText());
|
||||
}
|
||||
} else {
|
||||
nameEdit->setText("");
|
||||
colorEdit->setCurrentIndex(colorEdit->findData(QString(), Qt::UserRole, Qt::MatchFixedString));
|
||||
ptEdit->setText("");
|
||||
annotationEdit->setText("");
|
||||
}
|
||||
|
||||
pic->setCard(CardDatabaseManager::query()->getPreferredCard(cardInfo));
|
||||
// Filtering, changing the deck/all scope, or reloading the database can
|
||||
// invalidate the current row. None of these actions discard the token draft.
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void DlgCreateToken::updateSearchFieldWithoutUpdatingFilter(const QString &newValue) const
|
||||
{
|
||||
nameEdit->blockSignals(true);
|
||||
const QSignalBlocker blocker(nameEdit);
|
||||
nameEdit->setText(newValue);
|
||||
nameEdit->blockSignals(false);
|
||||
}
|
||||
|
||||
void DlgCreateToken::updatePreview()
|
||||
{
|
||||
pic->setToken(getTokenInfo());
|
||||
}
|
||||
|
||||
void DlgCreateToken::updateSearch(const QString &search)
|
||||
|
|
@ -266,11 +279,24 @@ void DlgCreateToken::actReject()
|
|||
|
||||
TokenInfo DlgCreateToken::getTokenInfo() const
|
||||
{
|
||||
return {.name = nameEdit->text(),
|
||||
.color = colorEdit->itemData(colorEdit->currentIndex()).toString(),
|
||||
.pt = ptEdit->text(),
|
||||
.annotation = annotationEdit->text(),
|
||||
.destroy = destroyCheckBox->isChecked(),
|
||||
.faceDown = faceDownCheckBox->isChecked(),
|
||||
.providerId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(nameEdit->text())};
|
||||
TokenInfo token = {
|
||||
.name = nameEdit->text(),
|
||||
.color = faceDownCheckBox->isChecked() ? QString(QChar())
|
||||
: colorEdit->itemData(colorEdit->currentIndex()).toString(),
|
||||
.pt = faceDownCheckBox->isChecked() ? QString() : ptEdit->text(),
|
||||
.annotation = annotationEdit->text(),
|
||||
.destroy = destroyCheckBox->isChecked(),
|
||||
.faceDown = faceDownCheckBox->isChecked(),
|
||||
.providerId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(nameEdit->text())};
|
||||
|
||||
// Match the normalization applied when the player creates the token, so
|
||||
// manually typed aliases and the default P/T preview the actual result.
|
||||
const ExactCard correctedCard = CardDatabaseManager::query()->guessCard({token.name, token.providerId});
|
||||
if (correctedCard) {
|
||||
token.name = correctedCard.getName();
|
||||
if (!token.faceDown && token.pt.isEmpty()) {
|
||||
token.pt = correctedCard.getInfo().getPowTough();
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class QRadioButton;
|
|||
class QTreeView;
|
||||
class CardDatabaseModel;
|
||||
class TokenDisplayModel;
|
||||
class CardInfoPictureWidget;
|
||||
class TokenPreviewWidget;
|
||||
class QModelIndex;
|
||||
class QWidget;
|
||||
|
||||
|
|
@ -39,6 +39,7 @@ private slots:
|
|||
void faceDownCheckBoxToggled(bool checked);
|
||||
void tokenSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void updateSearch(const QString &search);
|
||||
void updatePreview();
|
||||
void actChooseTokenFromAll(bool checked);
|
||||
void actChooseTokenFromDeck(bool checked);
|
||||
void actOk();
|
||||
|
|
@ -54,7 +55,7 @@ private:
|
|||
QCheckBox *destroyCheckBox;
|
||||
QCheckBox *faceDownCheckBox;
|
||||
QRadioButton *chooseTokenFromAllRadioButton, *chooseTokenFromDeckRadioButton;
|
||||
CardInfoPictureWidget *pic;
|
||||
TokenPreviewWidget *pic;
|
||||
QTreeView *chooseTokenView;
|
||||
|
||||
void updateSearchFieldWithoutUpdatingFilter(const QString &newValue) const;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
#include "token_preview_widget.h"
|
||||
|
||||
#include "../../interface/card_picture_loader/card_picture_loader.h"
|
||||
#include "../board/abstract_card_item.h"
|
||||
|
||||
#include <QGraphicsScene>
|
||||
#include <QPainter>
|
||||
#include <QResizeEvent>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
|
||||
class TokenPreviewCardItem : public AbstractCardItem
|
||||
{
|
||||
public:
|
||||
TokenPreviewCardItem()
|
||||
{
|
||||
setFlag(ItemIsSelectable, false);
|
||||
setAcceptedMouseButtons(Qt::NoButton);
|
||||
setAcceptHoverEvents(false);
|
||||
setCursor(Qt::ArrowCursor);
|
||||
connect(state, &CardState::stateChanged, this, [this] { update(); });
|
||||
}
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
|
||||
{
|
||||
// Use the board's artwork, custom-token background and name rendering. A
|
||||
// face-down preview has no server-assigned card ID to draw on its back.
|
||||
if (getFaceDown()) {
|
||||
QPixmap back;
|
||||
CardPictureLoader::getCardBackPixmap(back, getTranslatedSize(painter).toSize());
|
||||
painter->save();
|
||||
painter->setClipPath(shape());
|
||||
painter->drawPixmap(boundingRect(), back, back.rect());
|
||||
painter->restore();
|
||||
} else {
|
||||
AbstractCardItem::paint(painter, option, widget);
|
||||
}
|
||||
|
||||
const QSizeF translatedSize = getTranslatedSize(painter);
|
||||
const qreal scale = translatedSize.width() / boundingRect().width();
|
||||
painter->save();
|
||||
transformPainter(painter, translatedSize, 0);
|
||||
painter->setPen(Qt::white);
|
||||
painter->setBackground(Qt::black);
|
||||
painter->setBackgroundMode(Qt::OpaqueMode);
|
||||
const QRectF textRect(4 * scale, 4 * scale, translatedSize.width() - 8 * scale,
|
||||
translatedSize.height() - 8 * scale);
|
||||
painter->drawText(textRect, Qt::AlignCenter | Qt::TextWrapAnywhere, state->getAnnotation());
|
||||
if (state->getPT() != getCardInfo().getPowTough()) {
|
||||
painter->setPen(QColor(255, 150, 0));
|
||||
}
|
||||
painter->drawText(textRect, Qt::AlignRight | Qt::AlignBottom, state->getPT());
|
||||
painter->restore();
|
||||
}
|
||||
};
|
||||
|
||||
TokenPreviewWidget::TokenPreviewWidget(QWidget *parent) : QGraphicsView(parent), card(new TokenPreviewCardItem)
|
||||
{
|
||||
auto *previewScene = new QGraphicsScene(this);
|
||||
previewScene->addItem(card);
|
||||
previewScene->setSceneRect(card->boundingRect());
|
||||
setScene(previewScene);
|
||||
setInteractive(false);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
setFrameShape(QFrame::NoFrame);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setMinimumSize(150, 200);
|
||||
setAccessibleName(tr("Token preview"));
|
||||
}
|
||||
|
||||
void TokenPreviewWidget::setToken(const TokenInfo &token)
|
||||
{
|
||||
card->setCardRef({token.name, token.providerId});
|
||||
card->setColor(token.color);
|
||||
card->setFaceDown(token.faceDown);
|
||||
card->getState()->setPT(token.pt);
|
||||
card->getState()->setAnnotation(token.annotation);
|
||||
setToolTip(token.annotation);
|
||||
setAccessibleDescription(token.faceDown ? tr("Face-down token")
|
||||
: token.name + " " + token.pt + " " + token.annotation);
|
||||
}
|
||||
|
||||
QSize TokenPreviewWidget::sizeHint() const
|
||||
{
|
||||
return {200, 280};
|
||||
}
|
||||
|
||||
void TokenPreviewWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QGraphicsView::resizeEvent(event);
|
||||
fitInView(sceneRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
25
cockatrice/src/game_graphics/dialogs/token_preview_widget.h
Normal file
25
cockatrice/src/game_graphics/dialogs/token_preview_widget.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef COCKATRICE_TOKEN_PREVIEW_WIDGET_H
|
||||
#define COCKATRICE_TOKEN_PREVIEW_WIDGET_H
|
||||
|
||||
#include <QGraphicsView>
|
||||
#include <libcockatrice/game/player/token_info.h>
|
||||
|
||||
class TokenPreviewCardItem;
|
||||
|
||||
/** A noninteractive preview of the token that the dialog will create. */
|
||||
class TokenPreviewWidget : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TokenPreviewWidget(QWidget *parent = nullptr);
|
||||
void setToken(const TokenInfo &token);
|
||||
QSize sizeHint() const override;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
TokenPreviewCardItem *card;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -951,7 +951,7 @@ void PlayerActions::actCreateToken(TokenInfo tokenToCreate)
|
|||
lastTokenInfo.name = correctedCard.getName();
|
||||
int tableRow = lastTokenInfo.faceDown ? 2 : correctedCard.getInfo().getUiAttributes().tableRow;
|
||||
lastTokenTableRow = TableZoneLogic::tableRowToGridY(tableRow);
|
||||
if (lastTokenInfo.pt.isEmpty()) {
|
||||
if (!lastTokenInfo.faceDown && lastTokenInfo.pt.isEmpty()) {
|
||||
lastTokenInfo.pt = correctedCard.getInfo().getPowTough();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,25 @@
|
|||
|
||||
#include "gtest/gtest.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QList>
|
||||
#include <QLoggingCategory>
|
||||
#include <QSignalSpy>
|
||||
#include <QStandardPaths>
|
||||
#include <QTemporaryDir>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/game/abstract_game.h>
|
||||
#include <libcockatrice/game/board/card_state.h>
|
||||
#include <libcockatrice/game/game_state.h>
|
||||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/game/player/player_manager.h>
|
||||
#include <libcockatrice/game/zones/hand_zone_logic.h>
|
||||
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
||||
#include <libcockatrice/protocol/pb/command_create_token.pb.h>
|
||||
#include <libcockatrice/protocol/pb/commands.pb.h>
|
||||
#include <libcockatrice/protocol/pending_command.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
@ -25,6 +38,57 @@ CardRef cardRefFor(const QString &name)
|
|||
return cardRef;
|
||||
}
|
||||
|
||||
// Capture the real serialized command at the transport boundary. PlayerActions,
|
||||
// GameEventHandler and PendingCommand retain their production behavior.
|
||||
class CapturingClient : public AbstractClient
|
||||
{
|
||||
public:
|
||||
QList<CommandContainer> commands;
|
||||
|
||||
~CapturingClient() override
|
||||
{
|
||||
for (auto *command : pendingCommands) {
|
||||
delete command;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void sendCommandContainer(const CommandContainer &command) override
|
||||
{
|
||||
commands.append(command);
|
||||
}
|
||||
};
|
||||
|
||||
class TokenCommandTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
// The client outlives the game and its pending-command signal receivers.
|
||||
CapturingClient client;
|
||||
AbstractGame game{nullptr};
|
||||
PlayerLogic *player = nullptr;
|
||||
CardInfoPtr knownToken;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
knownToken = CardInfo::newInstance(QStringLiteral("Token Command Test Goblin"), "", true, {}, {}, {}, {},
|
||||
{.tableRow = 2});
|
||||
knownToken->setColors(QStringLiteral("R"));
|
||||
knownToken->setPowTough(QStringLiteral("2/2"));
|
||||
CardDatabaseManager::getInstance()->addCard(knownToken);
|
||||
|
||||
game.gameState = new GameState(&game, 0, 0, false, {&client}, true, false, 0, false);
|
||||
game.playerManager = new PlayerManager(&game, 0, false, false);
|
||||
ServerInfo_User user;
|
||||
user.set_name("Token command test player");
|
||||
player = game.playerManager->addPlayer(0, user);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
CardDatabaseManager::getInstance()->removeCard(knownToken);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(CardStateTest, AttachmentGraphKeepsBothEndsConsistent)
|
||||
|
|
@ -86,6 +150,64 @@ TEST(CardZoneLogicTest, AsksTheGraphicsSideToCreateCards)
|
|||
EXPECT_TRUE(arguments.at(1).toBool());
|
||||
}
|
||||
|
||||
TEST_F(TokenCommandTest, FaceDownKnownTokenDoesNotRestoreDatabasePowerToughness)
|
||||
{
|
||||
TokenInfo token;
|
||||
token.name = knownToken->getName();
|
||||
token.color = QString(QChar());
|
||||
token.faceDown = true;
|
||||
player->getPlayerActions()->actCreateToken(token);
|
||||
|
||||
ASSERT_EQ(client.commands.size(), 1);
|
||||
ASSERT_EQ(client.commands.first().game_command_size(), 1);
|
||||
const auto &gameCommand = client.commands.first().game_command(0);
|
||||
ASSERT_TRUE(gameCommand.HasExtension(Command_CreateToken::ext));
|
||||
const auto &command = gameCommand.GetExtension(Command_CreateToken::ext);
|
||||
EXPECT_EQ(command.card_name(), knownToken->getName().toStdString());
|
||||
EXPECT_TRUE(command.face_down());
|
||||
EXPECT_TRUE(command.pt().empty());
|
||||
|
||||
player->getPlayerActions()->actCreateAnotherToken();
|
||||
ASSERT_EQ(client.commands.size(), 2);
|
||||
const auto &repeat = client.commands.last().game_command(0).GetExtension(Command_CreateToken::ext);
|
||||
EXPECT_TRUE(repeat.face_down());
|
||||
EXPECT_TRUE(repeat.pt().empty());
|
||||
}
|
||||
|
||||
TEST_F(TokenCommandTest, FaceUpKnownAliasKeepsCanonicalNameAndDefaultPowerToughness)
|
||||
{
|
||||
TokenInfo token;
|
||||
token.name = QStringLiteral("token command test goblin");
|
||||
player->getPlayerActions()->actCreateToken(token);
|
||||
|
||||
ASSERT_EQ(client.commands.size(), 1);
|
||||
ASSERT_EQ(client.commands.first().game_command_size(), 1);
|
||||
const auto &gameCommand = client.commands.first().game_command(0);
|
||||
ASSERT_TRUE(gameCommand.HasExtension(Command_CreateToken::ext));
|
||||
const auto &command = gameCommand.GetExtension(Command_CreateToken::ext);
|
||||
EXPECT_EQ(command.card_name(), knownToken->getName().toStdString());
|
||||
EXPECT_FALSE(command.face_down());
|
||||
EXPECT_EQ(command.pt(), "2/2");
|
||||
}
|
||||
|
||||
TEST_F(TokenCommandTest, FaceUpKnownTokenPreservesExplicitPowerToughness)
|
||||
{
|
||||
TokenInfo token;
|
||||
token.name = knownToken->getName();
|
||||
token.pt = QStringLiteral("7/9");
|
||||
token.annotation = QStringLiteral("Flying");
|
||||
player->getPlayerActions()->actCreateToken(token);
|
||||
|
||||
ASSERT_EQ(client.commands.size(), 1);
|
||||
ASSERT_EQ(client.commands.first().game_command_size(), 1);
|
||||
const auto &gameCommand = client.commands.first().game_command(0);
|
||||
ASSERT_TRUE(gameCommand.HasExtension(Command_CreateToken::ext));
|
||||
const auto &command = gameCommand.GetExtension(Command_CreateToken::ext);
|
||||
EXPECT_FALSE(command.face_down());
|
||||
EXPECT_EQ(command.pt(), "7/9");
|
||||
EXPECT_EQ(command.annotation(), "Flying");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// Keep SettingsCache reads and writes away from the real user profile: the game logic still
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue