mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-11 16:44:48 -07:00
Some checks are pending
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 15 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker Image / amd64 & arm64 (push) Waiting to run
* [Game][Player] Pull out graphics_items out of player_logic Took 25 seconds Took 9 minutes * [Game] Move graphics files into game_graphics Took 1 minute Took 2 minutes Took 23 seconds Took 1 minute Took 2 seconds * Include. Took 4 minutes Took 3 minutes Took 4 minutes Took 1 minute Took 3 minutes --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
336 lines
10 KiB
C++
336 lines
10 KiB
C++
#include "player_logic.h"
|
|
|
|
#include "../../game_graphics/board/arrow_item.h"
|
|
#include "../../game_graphics/board/card_item.h"
|
|
#include "../../game_graphics/board/counter_general.h"
|
|
#include "../../game_graphics/game_scene.h"
|
|
#include "../../game_graphics/player/player_target.h"
|
|
#include "../../game_graphics/zones/hand_zone.h"
|
|
#include "../../game_graphics/zones/pile_zone.h"
|
|
#include "../../game_graphics/zones/stack_zone.h"
|
|
#include "../../game_graphics/zones/table_zone.h"
|
|
#include "../../interface/theme_manager.h"
|
|
#include "../../interface/widgets/tabs/tab_game.h"
|
|
#include "../board/card_list.h"
|
|
#include "player_actions.h"
|
|
|
|
#include <QDebug>
|
|
#include <QMenu>
|
|
#include <QMetaType>
|
|
#include <QPainter>
|
|
#include <QtConcurrent>
|
|
#include <libcockatrice/protocol/pb/command_attach_card.pb.h>
|
|
#include <libcockatrice/protocol/pb/command_set_card_counter.pb.h>
|
|
#include <libcockatrice/protocol/pb/event_create_arrow.pb.h>
|
|
#include <libcockatrice/protocol/pb/event_create_counter.pb.h>
|
|
#include <libcockatrice/protocol/pb/event_draw_cards.pb.h>
|
|
#include <libcockatrice/protocol/pb/serverinfo_player.pb.h>
|
|
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
|
|
#include <libcockatrice/protocol/pb/serverinfo_zone.pb.h>
|
|
#include <libcockatrice/utility/color.h>
|
|
|
|
PlayerLogic::PlayerLogic(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent)
|
|
: QObject(_parent), game(_parent), playerInfo(new PlayerInfo(info, _id, _local, _judge)),
|
|
playerEventHandler(new PlayerEventHandler(this)), playerActions(new PlayerActions(this)), active(false),
|
|
conceded(false), zoneId(0), dialogSemaphore(false)
|
|
{
|
|
initializeZones();
|
|
}
|
|
|
|
void PlayerLogic::initializeZones()
|
|
{
|
|
addZone(new PileZoneLogic(this, ZoneNames::DECK, false, true, false, this));
|
|
addZone(new PileZoneLogic(this, ZoneNames::GRAVE, false, false, true, this));
|
|
addZone(new PileZoneLogic(this, ZoneNames::EXILE, false, false, true, this));
|
|
addZone(new PileZoneLogic(this, ZoneNames::SIDEBOARD, false, false, false, this));
|
|
addZone(new TableZoneLogic(this, ZoneNames::TABLE, true, false, true, this));
|
|
addZone(new StackZoneLogic(this, ZoneNames::STACK, true, false, true, this));
|
|
bool visibleHand = playerInfo->getLocalOrJudge() ||
|
|
(game->getPlayerManager()->isSpectator() && game->getGameMetaInfo()->spectatorsOmniscient());
|
|
addZone(new HandZoneLogic(this, ZoneNames::HAND, false, false, visibleHand, this));
|
|
}
|
|
|
|
PlayerLogic::~PlayerLogic()
|
|
{
|
|
qCInfo(PlayerLog) << "Player destructor:" << getPlayerInfo()->getName();
|
|
|
|
QMapIterator<QString, CardZoneLogic *> i(zones);
|
|
while (i.hasNext()) {
|
|
delete i.next().value();
|
|
}
|
|
zones.clear();
|
|
|
|
delete getPlayerInfo()->userInfo;
|
|
}
|
|
|
|
void PlayerLogic::clear()
|
|
{
|
|
emit arrowsClearedLocally();
|
|
|
|
QMapIterator<QString, CardZoneLogic *> i(zones);
|
|
while (i.hasNext()) {
|
|
i.next().value()->clearContents();
|
|
}
|
|
|
|
clearCounters();
|
|
}
|
|
|
|
void PlayerLogic::setConceded(bool _conceded)
|
|
{
|
|
if (conceded != _conceded) {
|
|
conceded = _conceded;
|
|
|
|
if (conceded) {
|
|
clear();
|
|
}
|
|
emit concededChanged(getPlayerInfo()->getId(), conceded);
|
|
}
|
|
}
|
|
|
|
void PlayerLogic::setZoneId(int _zoneId)
|
|
{
|
|
if (zoneId != _zoneId) {
|
|
zoneId = _zoneId;
|
|
emit zoneIdChanged(zoneId);
|
|
}
|
|
}
|
|
|
|
void PlayerLogic::processPlayerInfo(const ServerInfo_Player &info)
|
|
{
|
|
static QSet<QString> builtinZones{/* PileZones */
|
|
ZoneNames::DECK, ZoneNames::GRAVE, ZoneNames::EXILE, ZoneNames::SIDEBOARD,
|
|
/* TableZone */
|
|
ZoneNames::TABLE,
|
|
/* StackZone */
|
|
ZoneNames::STACK,
|
|
/* HandZone */
|
|
ZoneNames::HAND};
|
|
clearCounters();
|
|
emit arrowsClearedLocally();
|
|
|
|
QMutableMapIterator<QString, CardZoneLogic *> zoneIt(zones);
|
|
while (zoneIt.hasNext()) {
|
|
zoneIt.next().value()->clearContents();
|
|
|
|
if (!builtinZones.contains(zoneIt.key())) {
|
|
zoneIt.remove();
|
|
}
|
|
}
|
|
|
|
emit clearCustomZonesMenu();
|
|
|
|
const int zoneListSize = info.zone_list_size();
|
|
for (int i = 0; i < zoneListSize; ++i) {
|
|
const ServerInfo_Zone &zoneInfo = info.zone_list(i);
|
|
|
|
QString zoneName = QString::fromStdString(zoneInfo.name());
|
|
CardZoneLogic *zone = zones.value(zoneName, 0);
|
|
if (!zone) {
|
|
// Create a new CardZone if it doesn't exist
|
|
|
|
if (zoneInfo.with_coords()) {
|
|
// Visibility not currently supported for TableZone
|
|
zone = addZone(new TableZoneLogic(this, zoneName, true, false, true, this));
|
|
} else {
|
|
// Zones without coordinats are always treated as non-shufflable
|
|
// PileZones, although supporting alternate hand or stack zones
|
|
// might make sense in some scenarios.
|
|
bool contentsKnown;
|
|
|
|
switch (zoneInfo.type()) {
|
|
case ServerInfo_Zone::PrivateZone:
|
|
contentsKnown =
|
|
playerInfo->getLocalOrJudge() || (game->getPlayerManager()->isSpectator() &&
|
|
game->getGameMetaInfo()->spectatorsOmniscient());
|
|
break;
|
|
|
|
case ServerInfo_Zone::PublicZone:
|
|
contentsKnown = true;
|
|
break;
|
|
|
|
case ServerInfo_Zone::HiddenZone:
|
|
contentsKnown = false;
|
|
break;
|
|
}
|
|
|
|
zone = addZone(new PileZoneLogic(this, zoneName, false, /* isShufflable */ false, contentsKnown, this));
|
|
}
|
|
|
|
// Non-builtin zones are hidden by default and can't be interacted
|
|
// with, except through menus.
|
|
emit zone->setGraphicsVisibility(false);
|
|
|
|
emit addViewCustomZoneActionToCustomZoneMenu(zoneName);
|
|
|
|
continue;
|
|
}
|
|
|
|
const int cardListSize = zoneInfo.card_list_size();
|
|
if (!cardListSize) {
|
|
for (int j = 0; j < zoneInfo.card_count(); ++j) {
|
|
zone->addCard(new CardItem(this), false, -1);
|
|
}
|
|
} else {
|
|
for (int j = 0; j < cardListSize; ++j) {
|
|
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
|
|
auto *card = new CardItem(this);
|
|
card->processCardInfo(cardInfo);
|
|
zone->addCard(card, false, cardInfo.x(), cardInfo.y());
|
|
}
|
|
}
|
|
if (zoneInfo.has_always_reveal_top_card()) {
|
|
zone->setAlwaysRevealTopCard(zoneInfo.always_reveal_top_card());
|
|
}
|
|
|
|
zone->reorganizeCards();
|
|
}
|
|
|
|
const int counterListSize = info.counter_list_size();
|
|
for (int i = 0; i < counterListSize; ++i) {
|
|
addCounter(info.counter_list(i));
|
|
}
|
|
|
|
setConceded(info.properties().conceded());
|
|
}
|
|
|
|
void PlayerLogic::processCardAttachment(const ServerInfo_Player &info)
|
|
{
|
|
const int zoneListSize = info.zone_list_size();
|
|
for (int i = 0; i < zoneListSize; ++i) {
|
|
const ServerInfo_Zone &zoneInfo = info.zone_list(i);
|
|
CardZoneLogic *zone = zones.value(QString::fromStdString(zoneInfo.name()), 0);
|
|
if (!zone) {
|
|
continue;
|
|
}
|
|
|
|
const int cardListSize = zoneInfo.card_list_size();
|
|
for (int j = 0; j < cardListSize; ++j) {
|
|
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
|
|
if (cardInfo.has_attach_player_id()) {
|
|
CardItem *startCard = zone->getCard(cardInfo.id());
|
|
CardItem *targetCard =
|
|
game->getCard(cardInfo.attach_player_id(), QString::fromStdString(cardInfo.attach_zone()),
|
|
cardInfo.attach_card_id());
|
|
if (!targetCard) {
|
|
continue;
|
|
}
|
|
|
|
startCard->setAttachedTo(targetCard);
|
|
}
|
|
}
|
|
}
|
|
|
|
const int arrowListSize = info.arrow_list_size();
|
|
for (int i = 0; i < arrowListSize; ++i) {
|
|
emit arrowCreateRequested(QSharedPointer<ArrowData>::create(
|
|
ArrowData::fromProto(info.arrow_list(i), getPlayerInfo()->getId(), getPlayerInfo()->getLocal())));
|
|
}
|
|
}
|
|
|
|
void PlayerLogic::addCard(CardItem *card)
|
|
{
|
|
emit newCardAdded(card);
|
|
}
|
|
|
|
void PlayerLogic::deleteCard(CardItem *card)
|
|
{
|
|
if (card == nullptr) {
|
|
return;
|
|
} else if (dialogSemaphore) {
|
|
cardsToDelete.append(card);
|
|
} else {
|
|
card->deleteLater();
|
|
}
|
|
}
|
|
|
|
void PlayerLogic::setDeck(const DeckList &_deck)
|
|
{
|
|
deck = _deck;
|
|
|
|
emit deckChanged();
|
|
}
|
|
|
|
CounterState *PlayerLogic::addCounter(const ServerInfo_Counter &counter)
|
|
{
|
|
return addCounter(counter.id(), QString::fromStdString(counter.name()),
|
|
convertColorToQColor(counter.counter_color()), counter.radius(), counter.count());
|
|
}
|
|
|
|
CounterState *PlayerLogic::addCounter(int id, const QString &name, const QColor &color, int radius, int value)
|
|
{
|
|
if (counters.contains(id)) {
|
|
return nullptr;
|
|
}
|
|
auto *state = new CounterState(id, name, color, radius, value, this);
|
|
counters.insert(id, state);
|
|
emit counterAdded(state);
|
|
return state;
|
|
}
|
|
|
|
void PlayerLogic::delCounter(int id)
|
|
{
|
|
auto *state = counters.take(id);
|
|
if (!state) {
|
|
return;
|
|
}
|
|
emit counterRemoved(id);
|
|
state->deleteLater();
|
|
}
|
|
|
|
void PlayerLogic::clearCounters()
|
|
{
|
|
for (int id : counters.keys()) {
|
|
emit counterRemoved(id);
|
|
}
|
|
qDeleteAll(counters);
|
|
counters.clear();
|
|
}
|
|
|
|
CounterState *PlayerLogic::getLifeCounter() const
|
|
{
|
|
for (auto *s : counters.values()) {
|
|
if (s->getName() == "life") {
|
|
return s;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool PlayerLogic::clearCardsToDelete()
|
|
{
|
|
if (cardsToDelete.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
for (auto &i : cardsToDelete) {
|
|
if (i != nullptr) {
|
|
i->deleteLater();
|
|
}
|
|
}
|
|
cardsToDelete.clear();
|
|
|
|
return true;
|
|
}
|
|
|
|
void PlayerLogic::setActive(bool _active)
|
|
{
|
|
active = _active;
|
|
emit activeChanged(active);
|
|
}
|
|
void PlayerLogic::onRequestZoneViewToggle(const QString &zoneName, int numberCards, bool isReversed)
|
|
{
|
|
emit requestZoneViewToggle(this, zoneName, numberCards, isReversed);
|
|
}
|
|
|
|
void PlayerLogic::updateZones()
|
|
{
|
|
getTableZone()->reorganizeCards();
|
|
}
|
|
|
|
void PlayerLogic::setGameStarted()
|
|
{
|
|
if (playerInfo->local) {
|
|
emit resetTopCardMenuActions();
|
|
}
|
|
setConceded(false);
|
|
}
|