[Refactor] Name the gates in Server_AbstractPlayer::moveCard (#7879)

This commit is contained in:
AI-scor 2026-11-10 18:25:24 +01:00 • committed by GitHub
parent 58ca953926
commit a0113d0e8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -282,6 +282,23 @@ static bool shouldBeFromTheBottom(const Server_CardZone *startZone, const std::s
return true; return true;
} }
/**
* @brief Whether the attachment rules forbid moving this card to the given target.
*
* A card attached to a host on the table must move together with that host, and a card that
* itself has attachments must not be stacked onto another card.
*/
static bool violatesAttachmentRules(const Server_Card *card, const Server_CardZone *targetZone, int xCoord, int yCoord)
{
// do not allow attached cards to move around on the table
if (card->getParentCard() && targetZone->getName() == ZoneNames::TABLE) {
return true;
}
// do not allow cards with attachments to stack with other cards
return !card->getAttachedCards().isEmpty() && !targetZone->isColumnEmpty(xCoord, yCoord);
}
Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges, Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges,
Server_CardZone *startzone, Server_CardZone *startzone,
const QList<const CardToMove *> &_cards, const QList<const CardToMove *> &_cards,
@ -292,9 +309,10 @@ Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges,
bool undoingDraw, bool undoingDraw,
bool isReversed) bool isReversed)
{ {
// Disallow controller change to other zones than the table. // A move that changes the controller is only allowed onto the table, unless a judge does it.
if (((targetzone->getType() != ServerInfo_Zone::PublicZone) || !targetzone->hasCoords()) && const bool changesController = startzone->getPlayer() != targetzone->getPlayer();
(startzone->getPlayer() != targetzone->getPlayer()) && !isJudge()) { const bool targetIsTable = targetzone->getType() == ServerInfo_Zone::PublicZone && targetzone->hasCoords();
if (changesController && !targetIsTable && !isJudge()) {
return Response::RespContextError; return Response::RespContextError;
} }
@ -307,31 +325,25 @@ Response::ResponseCode Server_AbstractPlayer::moveCard(GameEventStorage &ges,
std::set<MoveCardStruct> cardsToMove; std::set<MoveCardStruct> cardsToMove;
QSet<int> cardIdsToMove; QSet<int> cardIdsToMove;
for (auto _card : _cards) { for (const CardToMove *cardToMove : _cards) {
// The same card being moved twice would lead to undefined behaviour. // The same card being moved twice would lead to undefined behaviour.
if (cardIdsToMove.contains(_card->card_id())) { if (cardIdsToMove.contains(cardToMove->card_id())) {
continue; continue;
} }
cardIdsToMove.insert(_card->card_id()); cardIdsToMove.insert(cardToMove->card_id());
// Consistency checks. In case the command contains illegal moves, try to resolve the legal ones still. // Consistency checks. In case the command contains illegal moves, try to resolve the legal ones still.
int position; int position;
Server_Card *card = startzone->getCard(_card->card_id(), &position); Server_Card *card = startzone->getCard(cardToMove->card_id(), &position);
if (!card) { if (!card) {
return Response::RespNameNotFound; return Response::RespNameNotFound;
} }
// do not allow attached cards to move around on the table if (violatesAttachmentRules(card, targetzone, xCoord, yCoord)) {
if (card->getParentCard() && targetzone->getName() == ZoneNames::TABLE) {
continue; continue;
} }
// do not allow cards with attachments to stack with other cards cardsToMove.insert(MoveCardStruct{card, position, cardToMove});
if (!card->getAttachedCards().isEmpty() && !targetzone->isColumnEmpty(xCoord, yCoord)) {
continue;
}
cardsToMove.insert(MoveCardStruct{card, position, _card});
} }
// In case all moves were filtered out, abort. // In case all moves were filtered out, abort.
if (cardsToMove.empty()) { if (cardsToMove.empty()) {