This commit is contained in:
Skagra42 2026-09-20 15:39:03 -07:00 committed by GitHub
commit 3ccfc1f4ea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 124 additions and 3 deletions

View file

@ -512,6 +512,9 @@ private:
{"Player/aDoesntUntap", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Toggle Skip Untapping"), {"Player/aDoesntUntap", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Toggle Skip Untapping"),
parseSequenceString("Alt+U"), parseSequenceString("Alt+U"),
ShortcutGroup::Playing_Area)}, ShortcutGroup::Playing_Area)},
{"Player/aDoesntUntapOnce", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Toggle Skip Untapping (One Turn)"),
parseSequenceString(""),
ShortcutGroup::Playing_Area)},
{"Player/aFlip", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Turn Card Over"), {"Player/aFlip", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Turn Card Over"),
parseSequenceString("Alt+F"), parseSequenceString("Alt+F"),
ShortcutGroup::Playing_Area)}, ShortcutGroup::Playing_Area)},

View file

@ -89,6 +89,16 @@ void CardState::setDoesntUntap(bool _doesntUntap)
emit stateChanged(); emit stateChanged();
} }
void CardState::setDoesntUntapOnce(bool _doesntUntapOnce)
{
if (doesntUntapOnce == _doesntUntapOnce) {
return;
}
doesntUntapOnce = _doesntUntapOnce;
emit doesntUntapOnceChanged(_doesntUntapOnce);
emit stateChanged();
}
void CardState::setDestroyOnZoneChange(bool _destroyOnZoneChange) void CardState::setDestroyOnZoneChange(bool _destroyOnZoneChange)
{ {
if (destroyOnZoneChange == _destroyOnZoneChange) { if (destroyOnZoneChange == _destroyOnZoneChange) {

View file

@ -16,6 +16,7 @@ private:
QString annotation; QString annotation;
QString pt; QString pt;
bool doesntUntap = false; bool doesntUntap = false;
bool doesntUntapOnce = false;
bool destroyOnZoneChange = false; bool destroyOnZoneChange = false;
CardItem *attachedTo = nullptr; CardItem *attachedTo = nullptr;
@ -29,6 +30,7 @@ signals:
void annotationChanged(const QString &newAnnotation); void annotationChanged(const QString &newAnnotation);
void ptChanged(const QString &newPt); void ptChanged(const QString &newPt);
void doesntUntapChanged(bool newValue); void doesntUntapChanged(bool newValue);
void doesntUntapOnceChanged(bool newValue);
void destroyOnZoneChangeChanged(bool newValue); void destroyOnZoneChangeChanged(bool newValue);
void attachedToChanged(CardItem *newAttachedTo); void attachedToChanged(CardItem *newAttachedTo);
void zoneChanged(CardState *changedCard, CardZoneLogic *newZone); void zoneChanged(CardState *changedCard, CardZoneLogic *newZone);
@ -85,6 +87,13 @@ public:
void setDoesntUntap(bool _doesntUntap); void setDoesntUntap(bool _doesntUntap);
bool getDoesntUntapOnce() const
{
return doesntUntapOnce;
}
void setDoesntUntapOnce(bool _doesntUntapOnce);
bool getDestroyOnZoneChange() const bool getDestroyOnZoneChange() const
{ {
return destroyOnZoneChange; return destroyOnZoneChange;

View file

@ -1785,6 +1785,15 @@ void PlayerActions::cardMenuAction(QList<CardItem *> selectedCards, CardMenuActi
commandList.append(cmd); commandList.append(cmd);
break; break;
} }
case cmDoesntUntapOnce: {
auto *cmd = new Command_SetCardAttr;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_attribute(AttrDoesntUntapOnce);
cmd->set_attr_value(card->getDoesntUntapOnce() ? "0" : "1");
commandList.append(cmd);
break;
}
case cmFlip: { case cmFlip: {
auto *cmd = new Command_FlipCard; auto *cmd = new Command_FlipCard;
cmd->set_zone(card->getZone()->getName().toStdString()); cmd->set_zone(card->getZone()->getName().toStdString());

View file

@ -199,12 +199,15 @@ void PlayerEventHandler::setCardAttrHelper(const GameEventContext &context,
switch (attribute) { switch (attribute) {
case AttrTapped: { case AttrTapped: {
bool tapped = avalue == "1"; bool tapped = avalue == "1";
if (!(!tapped && card->getDoesntUntap() && allCards)) { if (!(!tapped && card->getDoesntUntap() && allCards) &&
!(!tapped && card->getDoesntUntapOnce() && allCards)) {
if (!allCards) { if (!allCards) {
emit logSetTapped(player, card, tapped); emit logSetTapped(player, card, tapped);
} }
bool canAnimate = !options.testFlag(SKIP_TAP_ANIMATION) && !moveCardContext; bool canAnimate = !options.testFlag(SKIP_TAP_ANIMATION) && !moveCardContext;
card->setTapped(tapped, canAnimate); card->setTapped(tapped, canAnimate);
} else if (!tapped && card->getDoesntUntapOnce() && allCards) {
card->setDoesntUntapOnce(false);
} }
break; break;
} }
@ -231,6 +234,12 @@ void PlayerEventHandler::setCardAttrHelper(const GameEventContext &context,
card->setDoesntUntap(value); card->setDoesntUntap(value);
break; break;
} }
case AttrDoesntUntapOnce: {
bool value = (avalue == "1");
emit logSetDoesntUntapOnce(player, card, value);
card->setDoesntUntapOnce(value);
break;
}
case AttrPT: { case AttrPT: {
emit logSetPT(player, card, avalue); emit logSetPT(player, card, avalue);
card->setPT(avalue); card->setPT(avalue);

View file

@ -248,6 +248,7 @@ signals:
void logSetTapped(PlayerLogic *player, CardItem *card, bool tapped); void logSetTapped(PlayerLogic *player, CardItem *card, bool tapped);
void logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue); void logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue);
void logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap); void logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap);
void logSetDoesntUntapOnce(PlayerLogic *player, CardItem *card, bool doesntUntapOnce);
void logSetPT(PlayerLogic *player, CardItem *card, QString newPT); void logSetPT(PlayerLogic *player, CardItem *card, QString newPT);
void logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation); void logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation);
void logDumpZone(PlayerLogic *player, CardZoneLogic *zone, int numberCards, bool isReversed = false); void logDumpZone(PlayerLogic *player, CardZoneLogic *zone, int numberCards, bool isReversed = false);

View file

@ -148,6 +148,20 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->restore(); painter->restore();
} }
if (state->getDoesntUntapOnce()) {
painter->save();
painter->setRenderHint(QPainter::Antialiasing, false);
QPen pen;
pen.setColor(Qt::cyan);
pen.setWidth(0); // Cosmetic pen
painter->setPen(pen);
painter->drawPath(shape());
painter->restore();
}
painter->restore(); painter->restore();
} }
@ -175,6 +189,12 @@ void CardItem::setDoesntUntap(bool _doesntUntap)
update(); update();
} }
void CardItem::setDoesntUntapOnce(bool _doesntUntapOnce)
{
state->setDoesntUntapOnce(_doesntUntapOnce);
update();
}
void CardItem::setPT(const QString &_pt) void CardItem::setPT(const QString &_pt)
{ {
state->setPT(_pt); state->setPT(_pt);
@ -225,6 +245,7 @@ void CardItem::resetState(bool keepAnnotations)
attachedCards.clear(); attachedCards.clear();
setTapped(false, false); setTapped(false, false);
setDoesntUntap(false); setDoesntUntap(false);
setDoesntUntapOnce(false);
if (scene()) { if (scene()) {
static_cast<GameScene *>(scene())->unregisterAnimationItem(this); static_cast<GameScene *>(scene())->unregisterAnimationItem(this);
} }
@ -250,6 +271,7 @@ void CardItem::processCardInfo(const ServerInfo_Card &_info)
setTapped(_info.tapped()); setTapped(_info.tapped());
setDestroyOnZoneChange(_info.destroy_on_zone_change()); setDestroyOnZoneChange(_info.destroy_on_zone_change());
setDoesntUntap(_info.doesnt_untap()); setDoesntUntap(_info.doesnt_untap());
setDoesntUntapOnce(_info.doesnt_untap_once());
} }
CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool forceFaceDown) CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool forceFaceDown)

View file

@ -104,6 +104,11 @@ public:
return state->getDoesntUntap(); return state->getDoesntUntap();
} }
void setDoesntUntap(bool _doesntUntap); void setDoesntUntap(bool _doesntUntap);
[[nodiscard]] bool getDoesntUntapOnce() const
{
return state->getDoesntUntapOnce();
}
void setDoesntUntapOnce(bool _doesntUntapOnce);
[[nodiscard]] QString getPT() const [[nodiscard]] QString getPT() const
{ {
return state->getPT(); return state->getPT();

View file

@ -691,6 +691,17 @@ void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardItem *card, bo
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(card->getName()))); appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(card->getName())));
} }
void MessageLogWidget::logSetDoesntUntapOnce(PlayerLogic *player, CardItem *card, bool doesntUntapOnce)
{
QString str;
if (doesntUntapOnce) {
str = tr("%1 sets %2 to not untap during its controller's next untap step.");
} else {
str = tr("%1 sets %2 to untap normally.");
}
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(card->getName())));
}
void MessageLogWidget::logSetPT(PlayerLogic *player, CardItem *card, QString newPT) void MessageLogWidget::logSetPT(PlayerLogic *player, CardItem *card, QString newPT)
{ {
if (currentContext == MessageContext_MoveCard) { if (currentContext == MessageContext_MoveCard) {
@ -837,6 +848,8 @@ void MessageLogWidget::connectToPlayerEventHandler(PlayerEventHandler *playerEve
connect(playerEventHandler, &PlayerEventHandler::logSetCardCounter, this, &MessageLogWidget::logSetCardCounter); connect(playerEventHandler, &PlayerEventHandler::logSetCardCounter, this, &MessageLogWidget::logSetCardCounter);
connect(playerEventHandler, &PlayerEventHandler::logSetTapped, this, &MessageLogWidget::logSetTapped); connect(playerEventHandler, &PlayerEventHandler::logSetTapped, this, &MessageLogWidget::logSetTapped);
connect(playerEventHandler, &PlayerEventHandler::logSetDoesntUntap, this, &MessageLogWidget::logSetDoesntUntap); connect(playerEventHandler, &PlayerEventHandler::logSetDoesntUntap, this, &MessageLogWidget::logSetDoesntUntap);
connect(playerEventHandler, &PlayerEventHandler::logSetDoesntUntapOnce, this,
&MessageLogWidget::logSetDoesntUntapOnce);
connect(playerEventHandler, &PlayerEventHandler::logSetPT, this, &MessageLogWidget::logSetPT); connect(playerEventHandler, &PlayerEventHandler::logSetPT, this, &MessageLogWidget::logSetPT);
connect(playerEventHandler, &PlayerEventHandler::logSetAnnotation, this, &MessageLogWidget::logSetAnnotation); connect(playerEventHandler, &PlayerEventHandler::logSetAnnotation, this, &MessageLogWidget::logSetAnnotation);
connect(playerEventHandler, &PlayerEventHandler::logMoveCard, this, &MessageLogWidget::logMoveCard); connect(playerEventHandler, &PlayerEventHandler::logMoveCard, this, &MessageLogWidget::logMoveCard);

View file

@ -92,6 +92,7 @@ public slots:
void logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue); void logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue);
void logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue); void logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue);
void logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap); void logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap);
void logSetDoesntUntapOnce(PlayerLogic *player, CardItem *card, bool doesntUntapOnce);
void logSetPT(PlayerLogic *player, CardItem *card, QString newPT); void logSetPT(PlayerLogic *player, CardItem *card, QString newPT);
void logSetSideboardLock(PlayerLogic *player, bool locked); void logSetSideboardLock(PlayerLogic *player, bool locked);
void logSetTapped(PlayerLogic *player, CardItem *card, bool tapped); void logSetTapped(PlayerLogic *player, CardItem *card, bool tapped);

View file

@ -13,6 +13,7 @@ enum CardMenuActionType
cmTap, cmTap,
cmUntap, cmUntap,
cmDoesntUntap, cmDoesntUntap,
cmDoesntUntapOnce,
cmFlip, cmFlip,
cmPeek, cmPeek,
cmClone, cmClone,

View file

@ -74,6 +74,8 @@ CardMenu::CardMenu(PlayerGraphicsItem *_player, const CardItem *_card, bool _sho
// Actions using invoke (type dispatch, need selection) // Actions using invoke (type dispatch, need selection)
aTap = makeAction(this, invoke(cmTap)); aTap = makeAction(this, invoke(cmTap));
aDoesntUntap = makeAction(this, invoke(cmDoesntUntap), /*checkable=*/true, card && card->getDoesntUntap()); aDoesntUntap = makeAction(this, invoke(cmDoesntUntap), /*checkable=*/true, card && card->getDoesntUntap());
aDoesntUntapOnce =
makeAction(this, invoke(cmDoesntUntapOnce), /*checkable=*/true, card && card->getDoesntUntapOnce());
aFlip = makeAction(this, invoke(cmFlip)); aFlip = makeAction(this, invoke(cmFlip));
aPeek = makeAction(this, invoke(cmPeek)); aPeek = makeAction(this, invoke(cmPeek));
aClone = makeAction(this, invoke(cmClone)); aClone = makeAction(this, invoke(cmClone));
@ -197,6 +199,7 @@ void CardMenu::createTableMenu(bool canModifyCard)
addAction(aTap); addAction(aTap);
addAction(aDoesntUntap); addAction(aDoesntUntap);
addAction(aDoesntUntapOnce);
addAction(aFlip); addAction(aFlip);
if (card->getFaceDown()) { if (card->getFaceDown()) {
addAction(aPeek); addAction(aPeek);
@ -492,6 +495,7 @@ void CardMenu::retranslateUi()
//: Turn sideways or back again //: Turn sideways or back again
aTap->setText(tr("&Tap / Untap")); aTap->setText(tr("&Tap / Untap"));
aDoesntUntap->setText(tr("Skip &untapping")); aDoesntUntap->setText(tr("Skip &untapping"));
aDoesntUntapOnce->setText(tr("Skip &Untapping (One Turn)"));
//: Turn face up/face down //: Turn face up/face down
aFlip->setText(tr("T&urn Over")); // Only the user facing names in client got renamed to "turn over" aFlip->setText(tr("T&urn Over")); // Only the user facing names in client got renamed to "turn over"
// All code and proto bits are still unchanged (flip) for compatibility reasons // All code and proto bits are still unchanged (flip) for compatibility reasons
@ -530,6 +534,7 @@ void CardMenu::setShortcutsActive()
aTap->setShortcuts(shortcuts.getShortcut("Player/aTap")); aTap->setShortcuts(shortcuts.getShortcut("Player/aTap"));
aDoesntUntap->setShortcuts(shortcuts.getShortcut("Player/aDoesntUntap")); aDoesntUntap->setShortcuts(shortcuts.getShortcut("Player/aDoesntUntap"));
aDoesntUntapOnce->setShortcuts(shortcuts.getShortcut("Player/aDoesntUntapOnce"));
aFlip->setShortcuts(shortcuts.getShortcut("Player/aFlip")); aFlip->setShortcuts(shortcuts.getShortcut("Player/aFlip"));
aPeek->setShortcuts(shortcuts.getShortcut("Player/aPeek")); aPeek->setShortcuts(shortcuts.getShortcut("Player/aPeek"));
aClone->setShortcuts(shortcuts.getShortcut("Player/aClone")); aClone->setShortcuts(shortcuts.getShortcut("Player/aClone"));

View file

@ -37,7 +37,7 @@ public:
QAction *aClone; QAction *aClone;
QAction *aSelectAll, *aSelectRow, *aSelectColumn; QAction *aSelectAll, *aSelectRow, *aSelectColumn;
QAction *aDrawArrow; QAction *aDrawArrow;
QAction *aTap, *aDoesntUntap; QAction *aTap, *aDoesntUntap, *aDoesntUntapOnce;
QAction *aFlip, *aPeek; QAction *aFlip, *aPeek;
QAction *aAttach, *aUnattach; QAction *aAttach, *aUnattach;
QAction *aSetAnnotation; QAction *aSetAnnotation;

View file

@ -1085,6 +1085,11 @@ Server_AbstractPlayer::cmdCreateToken(const Command_CreateToken &cmd, ResponseCo
ges.enqueueGameEvent(event, playerId); ges.enqueueGameEvent(event, playerId);
} }
if (card->getDoesntUntapOnce() != targetCard->getDoesntUntapOnce()) {
card->setAttribute(AttrDoesntUntapOnce, QVariant(targetCard->getDoesntUntapOnce()).toString(), &event);
ges.enqueueGameEvent(event, playerId);
}
// Copy counters // Copy counters
QMapIterator<int, int> i(targetCard->getCounters()); QMapIterator<int, int> i(targetCard->getCounters());
while (i.hasNext()) { while (i.hasNext()) {
@ -1442,6 +1447,7 @@ Server_AbstractPlayer::cmdDumpZone(const Command_DumpZone &cmd, ResponseContaine
cardInfo->set_annotation(card->getAnnotation().toStdString()); cardInfo->set_annotation(card->getAnnotation().toStdString());
cardInfo->set_destroy_on_zone_change(card->getDestroyOnZoneChange()); cardInfo->set_destroy_on_zone_change(card->getDestroyOnZoneChange());
cardInfo->set_doesnt_untap(card->getDoesntUntap()); cardInfo->set_doesnt_untap(card->getDoesntUntap());
cardInfo->set_doesnt_untap_once(card->getDoesntUntapOnce());
QMapIterator<int, int> cardCounterIterator(card->getCounters()); QMapIterator<int, int> cardCounterIterator(card->getCounters());
while (cardCounterIterator.hasNext()) { while (cardCounterIterator.hasNext()) {
@ -1554,6 +1560,7 @@ Server_AbstractPlayer::cmdRevealCards(const Command_RevealCards &cmd, ResponseCo
cardInfo->set_annotation(card->getAnnotation().toStdString()); cardInfo->set_annotation(card->getAnnotation().toStdString());
cardInfo->set_destroy_on_zone_change(card->getDestroyOnZoneChange()); cardInfo->set_destroy_on_zone_change(card->getDestroyOnZoneChange());
cardInfo->set_doesnt_untap(card->getDoesntUntap()); cardInfo->set_doesnt_untap(card->getDoesntUntap());
cardInfo->set_doesnt_untap_once(card->getDoesntUntapOnce());
QMapIterator<int, int> cardCounterIterator(card->getCounters()); QMapIterator<int, int> cardCounterIterator(card->getCounters());
while (cardCounterIterator.hasNext()) { while (cardCounterIterator.hasNext()) {

View file

@ -32,7 +32,8 @@
Server_Card::Server_Card(const CardRef &cardRef, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone) Server_Card::Server_Card(const CardRef &cardRef, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone)
: zone(_zone), id(_id), coord_x(_coord_x), coord_y(_coord_y), cardRef(cardRef), tapped(false), attacking(false), : zone(_zone), id(_id), coord_x(_coord_x), coord_y(_coord_y), cardRef(cardRef), tapped(false), attacking(false),
facedown(false), destroyOnZoneChange(false), doesntUntap(false), parentCard(0), stashedCard(nullptr) facedown(false), destroyOnZoneChange(false), doesntUntap(false), doesntUntapOnce(false), parentCard(0),
stashedCard(nullptr)
{ {
} }
@ -63,10 +64,16 @@ void Server_Card::resetState(bool keepAnnotations)
setAnnotation(QString()); setAnnotation(QString());
} }
setDoesntUntap(false); setDoesntUntap(false);
setDoesntUntapOnce(false);
} }
QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue, bool allCards) QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue, bool allCards)
{ {
if (attribute == AttrTapped && avalue != "1" && allCards && doesntUntapOnce) {
setDoesntUntapOnce(false);
return QVariant(tapped).toString();
}
if (attribute == AttrTapped && avalue != "1" && allCards && doesntUntap) { if (attribute == AttrTapped && avalue != "1" && allCards && doesntUntap) {
return QVariant(tapped).toString(); return QVariant(tapped).toString();
} }
@ -106,6 +113,9 @@ QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue
case AttrDoesntUntap: case AttrDoesntUntap:
setDoesntUntap(avalue == "1"); setDoesntUntap(avalue == "1");
break; break;
case AttrDoesntUntapOnce:
setDoesntUntapOnce(avalue == "1");
break;
} }
if (event) { if (event) {
event->set_attr_value(avalue.toStdString()); event->set_attr_value(avalue.toStdString());
@ -203,6 +213,9 @@ void Server_Card::getInfo(ServerInfo_Card *info)
if (doesntUntap) { if (doesntUntap) {
info->set_doesnt_untap(true); info->set_doesnt_untap(true);
} }
if (doesntUntapOnce) {
info->set_doesnt_untap_once(true);
}
QMapIterator<int, int> cardCounterIterator(counters); QMapIterator<int, int> cardCounterIterator(counters);
while (cardCounterIterator.hasNext()) { while (cardCounterIterator.hasNext()) {

View file

@ -49,6 +49,7 @@ private:
QString annotation; QString annotation;
bool destroyOnZoneChange; bool destroyOnZoneChange;
bool doesntUntap; bool doesntUntap;
bool doesntUntapOnce;
Server_Card *parentCard; Server_Card *parentCard;
QList<Server_Card *> attachedCards; QList<Server_Card *> attachedCards;
@ -127,6 +128,10 @@ public:
{ {
return doesntUntap; return doesntUntap;
} }
bool getDoesntUntapOnce() const
{
return doesntUntapOnce;
}
bool getDestroyOnZoneChange() const bool getDestroyOnZoneChange() const
{ {
return destroyOnZoneChange; return destroyOnZoneChange;
@ -203,6 +208,10 @@ public:
{ {
doesntUntap = _doesntUntap; doesntUntap = _doesntUntap;
} }
void setDoesntUntapOnce(bool _doesntUntapOnce)
{
doesntUntapOnce = _doesntUntapOnce;
}
void setParentCard(Server_Card *_parentCard); void setParentCard(Server_Card *_parentCard);
void addAttachedCard(Server_Card *card) void addAttachedCard(Server_Card *card)
{ {

View file

@ -7,4 +7,5 @@ enum CardAttribute {
AttrPT = 5; AttrPT = 5;
AttrAnnotation = 6; AttrAnnotation = 6;
AttrDoesntUntap = 7; AttrDoesntUntap = 7;
AttrDoesntUntapOnce = 8;
} }

View file

@ -53,4 +53,7 @@ message ServerInfo_Card {
// unique id of this kind of card, extends the name to specify a specific printing of a card // unique id of this kind of card, extends the name to specify a specific printing of a card
optional string provider_id = 17; optional string provider_id = 17;
// whether the card should not be untapped during its controller's next turn
optional bool doesnt_untap_once = 18;
} }