diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index 57ffe297..20b893e9 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -588,7 +588,7 @@ void CardDatabase::refreshCachedReverseRelatedCards() } auto *newCardRelation = new CardRelation( - card->getName(), cardRelation->getDoesAttach(), cardRelation->getIsCreateAllExclusion(), + card->getName(), cardRelation->getAttachType(), cardRelation->getIsCreateAllExclusion(), cardRelation->getIsVariable(), cardRelation->getDefaultCount(), cardRelation->getIsPersistent()); cards.value(targetCard)->addReverseRelatedCards2Me(newCardRelation); } @@ -672,12 +672,12 @@ bool CardDatabase::saveCustomTokensToFile() } CardRelation::CardRelation(const QString &_name, - bool _doesAttach, + AttachType _attachType, bool _isCreateAllExclusion, bool _isVariableCount, int _defaultCount, bool _isPersistent) - : name(_name), doesAttach(_doesAttach), isCreateAllExclusion(_isCreateAllExclusion), + : name(_name), attachType(_attachType), isCreateAllExclusion(_isCreateAllExclusion), isVariableCount(_isVariableCount), defaultCount(_defaultCount), isPersistent(_isPersistent) { } diff --git a/cockatrice/src/carddatabase.h b/cockatrice/src/carddatabase.h index 4350c5a5..d8ba8419 100644 --- a/cockatrice/src/carddatabase.h +++ b/cockatrice/src/carddatabase.h @@ -452,9 +452,17 @@ signals: class CardRelation : public QObject { Q_OBJECT +public: + enum AttachType + { + DoesNotAttach = 0, + AttachTo = 1, + TransformInto = 2, + }; + private: QString name; - bool doesAttach; + AttachType attachType; bool isCreateAllExclusion; bool isVariableCount; int defaultCount; @@ -462,7 +470,7 @@ private: public: explicit CardRelation(const QString &_name = QString(), - bool _doesAttach = false, + AttachType _attachType = DoesNotAttach, bool _isCreateAllExclusion = false, bool _isVariableCount = false, int _defaultCount = 1, @@ -472,13 +480,32 @@ public: { return name; } + AttachType getAttachType() const + { + return attachType; + } bool getDoesAttach() const { - return doesAttach; + return attachType != DoesNotAttach; + } + bool getDoesTransform() const + { + return attachType == TransformInto; + } + QString getAttachTypeAsString() const + { + switch (attachType) { + case AttachTo: + return "attach"; + case TransformInto: + return "transform"; + default: + return ""; + } } bool getCanCreateAnother() const { - return !doesAttach; + return !getDoesAttach(); } bool getIsCreateAllExclusion() const { diff --git a/cockatrice/src/carddbparser/cockatricexml3.cpp b/cockatrice/src/carddbparser/cockatricexml3.cpp index d13148e1..098a9def 100644 --- a/cockatrice/src/carddbparser/cockatricexml3.cpp +++ b/cockatrice/src/carddbparser/cockatricexml3.cpp @@ -224,7 +224,7 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml) sets.insert(setName, setInfo); // related cards } else if (xmlName == "related" || xmlName == "reverse-related") { - bool attach = false; + CardRelation::AttachType attach = CardRelation::DoesNotAttach; bool exclude = false; bool variable = false; int count = 1; @@ -246,7 +246,7 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml) } if (attrs.hasAttribute("attach")) { - attach = true; + attach = CardRelation::AttachTo; } if (attrs.hasAttribute("exclude")) { @@ -459,4 +459,4 @@ bool CockatriceXml3Parser::saveToFile(SetNameMap sets, xml.writeEndDocument(); return true; -} \ No newline at end of file +} diff --git a/cockatrice/src/carddbparser/cockatricexml4.cpp b/cockatrice/src/carddbparser/cockatricexml4.cpp index 7e22a7cc..a030ea4d 100644 --- a/cockatrice/src/carddbparser/cockatricexml4.cpp +++ b/cockatrice/src/carddbparser/cockatricexml4.cpp @@ -182,7 +182,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml) } // related cards } else if (xmlName == "related" || xmlName == "reverse-related") { - bool attach = false; + CardRelation::AttachType attachType = CardRelation::DoesNotAttach; bool exclude = false; bool variable = false; bool persistent = false; @@ -205,7 +205,8 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml) } if (attrs.hasAttribute("attach")) { - attach = true; + attachType = attrs.value("attach").toString() == "transform" ? CardRelation::TransformInto + : CardRelation::AttachTo; } if (attrs.hasAttribute("exclude")) { @@ -216,7 +217,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml) persistent = true; } - auto *relation = new CardRelation(cardName, attach, exclude, variable, count, persistent); + auto *relation = new CardRelation(cardName, attachType, exclude, variable, count, persistent); if (xmlName == "reverse-related") { reverseRelatedCards << relation; } else { @@ -294,7 +295,7 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in for (auto i : related) { xml.writeStartElement("related"); if (i->getDoesAttach()) { - xml.writeAttribute("attach", "attach"); + xml.writeAttribute("attach", i->getAttachTypeAsString()); } if (i->getIsCreateAllExclusion()) { xml.writeAttribute("exclude", "exclude"); @@ -318,7 +319,7 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in for (auto i : reverseRelated) { xml.writeStartElement("reverse-related"); if (i->getDoesAttach()) { - xml.writeAttribute("attach", "attach"); + xml.writeAttribute("attach", i->getAttachTypeAsString()); } if (i->getIsCreateAllExclusion()) { diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index 560523f3..cd64dadf 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -1677,7 +1677,7 @@ void Player::actCreateAllRelatedCards() dbName = cardRelationAll->getName(); bool persistent = cardRelationAll->getIsPersistent(); for (int i = 0; i < cardRelationAll->getDefaultCount(); ++i) { - createCard(sourceCard, dbName, false, persistent); + createCard(sourceCard, dbName, CardRelation::DoesNotAttach, persistent); } ++tokensTypesCreated; if (tokensTypesCreated == 1) { @@ -1692,7 +1692,7 @@ void Player::actCreateAllRelatedCards() dbName = cardRelationNotExcluded->getName(); bool persistent = cardRelationNotExcluded->getIsPersistent(); for (int i = 0; i < cardRelationNotExcluded->getDefaultCount(); ++i) { - createCard(sourceCard, dbName, false, persistent); + createCard(sourceCard, dbName, CardRelation::DoesNotAttach, persistent); } ++tokensTypesCreated; if (tokensTypesCreated == 1) { @@ -1731,23 +1731,22 @@ bool Player::createRelatedFromRelation(const CardItem *sourceCard, const CardRel return false; } for (int i = 0; i < count; ++i) { - createCard(sourceCard, dbName, false, persistent); + createCard(sourceCard, dbName, CardRelation::DoesNotAttach, persistent); } } else if (cardRelation->getDefaultCount() > 1) { for (int i = 0; i < cardRelation->getDefaultCount(); ++i) { - createCard(sourceCard, dbName, false, persistent); + createCard(sourceCard, dbName, CardRelation::DoesNotAttach, persistent); } } else { - if (cardRelation->getDoesAttach()) { - createAttachedCard(sourceCard, dbName, persistent); - } else { - createCard(sourceCard, dbName, false, persistent); - } + createCard(sourceCard, dbName, cardRelation->getAttachType(), persistent); } return true; } -void Player::createCard(const CardItem *sourceCard, const QString &dbCardName, bool attach, bool persistent) +void Player::createCard(const CardItem *sourceCard, + const QString &dbCardName, + CardRelation::AttachType attachType, + bool persistent) { CardInfoPtr cardInfo = db->getCard(dbCardName); @@ -1786,18 +1785,24 @@ void Player::createCard(const CardItem *sourceCard, const QString &dbCardName, b cmd.set_x(gridPoint.x()); cmd.set_y(gridPoint.y()); - if (attach) { - cmd.set_target_card_id(sourceCard->getId()); + switch (attachType) { + case CardRelation::DoesNotAttach: + break; + + case CardRelation::AttachTo: + cmd.set_target_card_id(sourceCard->getId()); + cmd.set_target_mode(Command_CreateToken::ATTACH_TO); + break; + + case CardRelation::TransformInto: + cmd.set_target_card_id(sourceCard->getId()); + cmd.set_target_mode(Command_CreateToken::TRANSFORM_INTO); + break; } sendGameCommand(cmd); } -void Player::createAttachedCard(const CardItem *sourceCard, const QString &dbCardName, bool persistent) -{ - createCard(sourceCard, dbCardName, true, persistent); -} - void Player::actSayMessage() { auto *a = qobject_cast(sender()); @@ -3550,6 +3555,7 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu) CardInfoPtr relatedCard = db->getCard(cardRelation->getName()); if (relatedCard == nullptr) continue; + QString relatedCardName; if (relatedCard->getPowTough().size() > 0) { relatedCardName = relatedCard->getPowTough() + " " + relatedCard->getName(); // "n/n name" @@ -3559,7 +3565,8 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu) QString text = tr("Token: "); if (cardRelation->getDoesAttach()) { - text += tr("Attach to ") + "\"" + relatedCardName + "\""; + text += + tr(cardRelation->getDoesTransform() ? "Transform into " : "Attach to ") + "\"" + relatedCardName + "\""; } else if (cardRelation->getIsVariable()) { text += "X " + relatedCardName; } else if (cardRelation->getDefaultCount() != 1) { diff --git a/cockatrice/src/player.h b/cockatrice/src/player.h index 44429567..7f14b7d5 100644 --- a/cockatrice/src/player.h +++ b/cockatrice/src/player.h @@ -287,9 +287,10 @@ private: bool allCards); void addRelatedCardActions(const CardItem *card, QMenu *cardMenu); void addRelatedCardView(const CardItem *card, QMenu *cardMenu); - void - createCard(const CardItem *sourceCard, const QString &dbCardName, bool attach = false, bool persistent = false); - void createAttachedCard(const CardItem *sourceCard, const QString &dbCardName, bool persistent = false); + void createCard(const CardItem *sourceCard, + const QString &dbCardName, + CardRelation::AttachType attach = CardRelation::DoesNotAttach, + bool persistent = false); bool createRelatedFromRelation(const CardItem *sourceCard, const CardRelation *cardRelation); QRectF bRect; diff --git a/common/pb/command_create_token.proto b/common/pb/command_create_token.proto index d5425648..4ee60b28 100644 --- a/common/pb/command_create_token.proto +++ b/common/pb/command_create_token.proto @@ -1,6 +1,14 @@ syntax = "proto2"; import "game_commands.proto"; + message Command_CreateToken { + enum TargetMode { + // Attach the target to the token + ATTACH_TO = 0; + // Transform the target into the token + TRANSFORM_INTO = 1; + } + extend GameCommand { optional Command_CreateToken ext = 1010; } @@ -14,4 +22,7 @@ message Command_CreateToken { optional sint32 y = 8; optional string target_zone = 9; optional sint32 target_card_id = 10 [default = -1]; + + // What to do with the target card. Ignored if there is no target card. + optional TargetMode target_mode = 11; } diff --git a/common/server_card.cpp b/common/server_card.cpp index 0359fa16..5bf8ee78 100644 --- a/common/server_card.cpp +++ b/common/server_card.cpp @@ -19,13 +19,18 @@ ***************************************************************************/ #include "server_card.h" +#include "pb/event_set_card_attr.pb.h" +#include "pb/event_set_card_counter.pb.h" #include "pb/serverinfo_card.pb.h" #include "server_cardzone.h" #include "server_player.h" +#include + 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(), ptString(), annotation(), destroyOnZoneChange(false), doesntUntap(false), parentCard(0) + facedown(false), color(), ptString(), annotation(), destroyOnZoneChange(false), doesntUntap(false), parentCard(0), + stashedCard(nullptr) { } @@ -37,6 +42,11 @@ Server_Card::~Server_Card() if (parentCard) parentCard->removeAttachedCard(this); + + if (stashedCard) { + stashedCard->deleteLater(); + stashedCard = nullptr; + } } void Server_Card::resetState() @@ -51,11 +61,20 @@ void Server_Card::resetState() QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue, bool allCards) { + if (attribute == AttrTapped && avalue != "1" && allCards && doesntUntap) + return QVariant(tapped).toString(); + + return setAttribute(attribute, avalue); +} + +QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue, Event_SetCardAttr *event) +{ + if (event) + event->set_attribute(attribute); + switch (attribute) { case AttrTapped: { - bool value = avalue == "1"; - if (!(!value && allCards && doesntUntap)) - setTapped(value); + setTapped(avalue == "1"); break; } case AttrAttacking: @@ -69,6 +88,8 @@ QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue break; case AttrPT: setPT(avalue); + if (event) + event->set_attr_value(getPT().toStdString()); return getPT(); case AttrAnnotation: setAnnotation(avalue); @@ -77,15 +98,22 @@ QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue setDoesntUntap(avalue == "1"); break; } + if (event) + event->set_attr_value(avalue.toStdString()); return avalue; } -void Server_Card::setCounter(int id, int value) +void Server_Card::setCounter(int id, int value, Event_SetCardCounter *event) { if (value) counters.insert(id, value); else counters.remove(id); + + if (event) { + event->set_counter_id(id); + event->set_counter_value(value); + } } void Server_Card::setParentCard(Server_Card *_parentCard) diff --git a/common/server_card.h b/common/server_card.h index c921f86e..0e1052d9 100644 --- a/common/server_card.h +++ b/common/server_card.h @@ -28,6 +28,8 @@ #include class Server_CardZone; +class Event_SetCardCounter; +class Event_SetCardAttr; class Server_Card : public Server_ArrowTarget { @@ -49,6 +51,7 @@ private: Server_Card *parentCard; QList attachedCards; + Server_Card *stashedCard; public: Server_Card(QString _name, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone = 0); @@ -141,7 +144,7 @@ public: { name = _name; } - void setCounter(int id, int value); + void setCounter(int id, int value, Event_SetCardCounter *event = nullptr); void setTapped(bool _tapped) { tapped = _tapped; @@ -183,9 +186,31 @@ public: { attachedCards.removeOne(card); } + void setStashedCard(Server_Card *card) + { + // setStashedCard should only be called on creation of a new card, so + // there should never be an already existing stashed card. + Q_ASSERT(!stashedCard); + + // Stashed cards can't themselves have stashed cards, and tokens can't + // be stashed. + if (card->stashedCard || card->getDestroyOnZoneChange()) { + stashedCard = card->takeStashedCard(); + card->deleteLater(); + } else { + stashedCard = card; + } + } + Server_Card *takeStashedCard() + { + Server_Card *oldStashedCard = stashedCard; + stashedCard = nullptr; + return oldStashedCard; + } void resetState(); QString setAttribute(CardAttribute attribute, const QString &avalue, bool allCards); + QString setAttribute(CardAttribute attribute, const QString &avalue, Event_SetCardAttr *event = nullptr); void getInfo(ServerInfo_Card *info); }; diff --git a/common/server_player.cpp b/common/server_player.cpp index 5cd95ce9..d10cfc60 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -376,6 +376,36 @@ void Server_Player::revealTopCardIfNeeded(Server_CardZone *zone, GameEventStorag } } +static Event_CreateToken makeCreateTokenEvent(Server_CardZone *zone, Server_Card *card, int xCoord, int yCoord) +{ + Event_CreateToken event; + event.set_zone_name(zone->getName().toStdString()); + event.set_card_id(card->getId()); + event.set_card_name(card->getName().toStdString()); + event.set_color(card->getColor().toStdString()); + event.set_pt(card->getPT().toStdString()); + event.set_annotation(card->getAnnotation().toStdString()); + event.set_destroy_on_zone_change(card->getDestroyOnZoneChange()); + event.set_x(xCoord); + event.set_y(yCoord); + return event; +} + +static Event_AttachCard makeAttachCardEvent(Server_Card *attachedCard, Server_Card *parentCard = nullptr) +{ + Event_AttachCard event; + event.set_start_zone(attachedCard->getZone()->getName().toStdString()); + event.set_card_id(attachedCard->getId()); + + if (parentCard) { + event.set_target_player_id(parentCard->getZone()->getPlayer()->getPlayerId()); + event.set_target_zone(parentCard->getZone()->getName().toStdString()); + event.set_target_card_id(parentCard->getId()); + } + + return event; +} + Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, Server_CardZone *startzone, const QList &_cards, @@ -485,8 +515,19 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, event.set_card_id(static_cast(card->getId())); ges.enqueueGameEvent(event, playerId); - card->deleteLater(); - } else { + if (Server_Card *stashedCard = card->takeStashedCard()) { + stashedCard->setId(newCardId()); + ges.enqueueGameEvent(makeCreateTokenEvent(startzone, stashedCard, card->getX(), card->getY()), + playerId); + card->deleteLater(); + card = stashedCard; + } else { + card->deleteLater(); + card = nullptr; + } + } + + if (card) { ++xIndex; int newX = xCoord + xIndex; @@ -622,10 +663,7 @@ void Server_Player::unattachCard(GameEventStorage &ges, Server_Card *card) Server_Card *parentCard = card->getParentCard(); card->setParentCard(nullptr); - Event_AttachCard event; - event.set_start_zone(zone->getName().toStdString()); - event.set_card_id(card->getId()); - ges.enqueueGameEvent(event, playerId); + ges.enqueueGameEvent(makeAttachCardEvent(card), playerId); auto *cardToMove = new CardToMove; cardToMove->set_card_id(card->getId()); @@ -1280,13 +1318,7 @@ Server_Player::cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer & delete cardToMove; } - Event_AttachCard event; - event.set_start_zone(startzone->getName().toStdString()); - event.set_card_id(card->getId()); - event.set_target_player_id(targetPlayer->getPlayerId()); - event.set_target_zone(targetzone->getName().toStdString()); - event.set_target_card_id(targetCard->getId()); - ges.enqueueGameEvent(event, playerId); + ges.enqueueGameEvent(makeAttachCardEvent(card, targetCard), playerId); startzone->fixFreeSpaces(ges); } else { @@ -1315,9 +1347,40 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer return Response::RespNameNotFound; } - QString cardName = nameFromStdString(cmd.card_name()); int xCoord = cmd.x(); int yCoord = cmd.y(); + + Server_Card *targetCard = nullptr; + if (cmd.has_target_card_id()) { + Server_CardZone *targetZone = zones.value(nameFromStdString(cmd.target_zone())); + if (targetZone) { + targetCard = targetZone->getCard(cmd.target_card_id()); + if (targetCard && cmd.target_mode() == Command_CreateToken::TRANSFORM_INTO) { + if (targetCard->getParentCard()) { + ges.enqueueGameEvent(makeAttachCardEvent(targetCard), playerId); + } + + for (Server_Card *attachedCard : targetCard->getAttachedCards()) { + ges.enqueueGameEvent(makeAttachCardEvent(attachedCard), + attachedCard->getZone()->getPlayer()->getPlayerId()); + } + + if (zone->hasCoords() && zone == targetZone) { + xCoord = targetCard->getX(); + yCoord = targetCard->getY(); + } + + targetZone->removeCard(targetCard); + + Event_DestroyCard event; + event.set_zone_name(targetZone->getName().toStdString()); + event.set_card_id(static_cast<::google::protobuf::uint32>(cmd.target_card_id())); + ges.enqueueGameEvent(event, playerId); + } + } + } + + QString cardName = nameFromStdString(cmd.card_name()); if (zone->hasCoords()) { xCoord = zone->getFreeGridColumn(xCoord, yCoord, cardName, false); } @@ -1336,33 +1399,89 @@ Server_Player::cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer card->setDestroyOnZoneChange(cmd.destroy_on_zone_change()); zone->insertCard(card, xCoord, yCoord); - - Event_CreateToken event; - event.set_zone_name(zone->getName().toStdString()); - event.set_card_id(card->getId()); - event.set_card_name(card->getName().toStdString()); - event.set_color(card->getColor().toStdString()); - event.set_pt(card->getPT().toStdString()); - event.set_annotation(card->getAnnotation().toStdString()); - event.set_destroy_on_zone_change(card->getDestroyOnZoneChange()); - event.set_x(xCoord); - event.set_y(yCoord); - ges.enqueueGameEvent(event, playerId); + ges.enqueueGameEvent(makeCreateTokenEvent(zone, card, xCoord, yCoord), playerId); // check if the token is a replacement for an existing card - if (cmd.target_card_id() < 0) { + if (!targetCard) { return Response::RespOk; } - Command_AttachCard cmd2; - cmd2.set_start_zone(cmd.target_zone()); - cmd2.set_card_id(cmd.target_card_id()); + switch (cmd.target_mode()) { + case Command_CreateToken::ATTACH_TO: { + Command_AttachCard cmd2; + cmd2.set_start_zone(cmd.target_zone()); + cmd2.set_card_id(cmd.target_card_id()); - cmd2.set_target_player_id(zone->getPlayer()->getPlayerId()); - cmd2.set_target_zone(cmd.zone()); - cmd2.set_target_card_id(card->getId()); + cmd2.set_target_player_id(zone->getPlayer()->getPlayerId()); + cmd2.set_target_zone(cmd.zone()); + cmd2.set_target_card_id(card->getId()); - return cmdAttachCard(cmd2, rc, ges); + return cmdAttachCard(cmd2, rc, ges); + } + + case Command_CreateToken::TRANSFORM_INTO: { + // Copy attributes that are not present in the CreateToken event + Event_SetCardAttr event; + event.set_zone_name(card->getZone()->getName().toStdString()); + event.set_card_id(card->getId()); + + if (card->getTapped() != targetCard->getTapped()) { + card->setAttribute(AttrTapped, QVariant(targetCard->getTapped()).toString(), &event); + ges.enqueueGameEvent(event, playerId); + } + + if (card->getAttacking() != targetCard->getAttacking()) { + card->setAttribute(AttrAttacking, QVariant(targetCard->getAttacking()).toString(), &event); + ges.enqueueGameEvent(event, playerId); + } + + if (card->getFaceDown() != targetCard->getFaceDown()) { + card->setAttribute(AttrFaceDown, QVariant(targetCard->getFaceDown()).toString(), &event); + ges.enqueueGameEvent(event, playerId); + } + + if (card->getDoesntUntap() != targetCard->getDoesntUntap()) { + card->setAttribute(AttrDoesntUntap, QVariant(targetCard->getDoesntUntap()).toString(), &event); + ges.enqueueGameEvent(event, playerId); + } + + // Copy counters + QMapIterator i(targetCard->getCounters()); + while (i.hasNext()) { + i.next(); + + Event_SetCardCounter event; + event.set_zone_name(card->getZone()->getName().toStdString()); + event.set_card_id(card->getId()); + + card->setCounter(i.key(), i.value(), &event); + ges.enqueueGameEvent(event, playerId); + } + + // Copy parent card + if (Server_Card *parentCard = targetCard->getParentCard()) { + targetCard->setParentCard(nullptr); + card->setParentCard(parentCard); + + ges.enqueueGameEvent(makeAttachCardEvent(card, parentCard), playerId); + } + + // Copy attachments + while (!targetCard->getAttachedCards().isEmpty()) { + Server_Card *attachedCard = targetCard->getAttachedCards().last(); + attachedCard->setParentCard(card); + + ges.enqueueGameEvent(makeAttachCardEvent(attachedCard, card), + attachedCard->getZone()->getPlayer()->getPlayerId()); + } + + targetCard->resetState(); + card->setStashedCard(targetCard); + break; + } + } + + return Response::RespOk; } Response::ResponseCode @@ -1517,13 +1636,10 @@ Server_Player::cmdSetCardCounter(const Command_SetCardCounter &cmd, ResponseCont return Response::RespNameNotFound; } - card->setCounter(cmd.counter_id(), cmd.counter_value()); - Event_SetCardCounter event; event.set_zone_name(zone->getName().toStdString()); event.set_card_id(card->getId()); - event.set_counter_id(cmd.counter_id()); - event.set_counter_value(cmd.counter_value()); + card->setCounter(cmd.counter_id(), cmd.counter_value(), &event); ges.enqueueGameEvent(event, playerId); return Response::RespOk; diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index bb3b22e3..ae7c35aa 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -370,12 +370,12 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, static const QRegularExpression meldNameRegex{"then meld them into ([^\\.]*)"}; QString additionalName = meldNameRegex.match(text).captured(1); if (!additionalName.isNull()) { - relatedCards.append(new CardRelation(additionalName, true)); + relatedCards.append(new CardRelation(additionalName, CardRelation::TransformInto)); } } else { for (const QString &additionalName : name.split(" // ")) { if (additionalName != faceName) { - relatedCards.append(new CardRelation(additionalName, true)); + relatedCards.append(new CardRelation(additionalName, CardRelation::TransformInto)); } } } @@ -389,7 +389,8 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, if (givenRelated.contains("spellbook")) { auto spbk = givenRelated.value("spellbook").toStringList(); for (const QString &spbkName : spbk) { - relatedCards.append(new CardRelation(spbkName, false, false, false, 1, true)); + relatedCards.append( + new CardRelation(spbkName, CardRelation::DoesNotAttach, false, false, 1, true)); } } }