Merge branch 'master' into tooomm-qt5

This commit is contained in:
tooomm 2026-05-30 14:49:55 +02:00 committed by GitHub
commit 9d4cf57c70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
593 changed files with 12518 additions and 6581 deletions

View file

@ -140,13 +140,15 @@ void ConnectionController::onConnectionClosedEvent(const Event_ConnectionClosed
}
case Event_ConnectionClosed::BANNED: {
reasonStr = tr("Banned by moderator");
if (event.has_end_time())
if (event.has_end_time()) {
reasonStr.append(
"\n" + tr("Expected end time: %1").arg(QDateTime::fromSecsSinceEpoch(event.end_time()).toString()));
else
} else {
reasonStr.append("\n" + tr("This ban lasts indefinitely."));
if (event.has_reason_str())
}
if (event.has_reason_str()) {
reasonStr.append("\n\n" + QString::fromStdString(event.reason_str()));
}
break;
}
case Event_ConnectionClosed::SERVER_SHUTDOWN: {
@ -240,8 +242,9 @@ void ConnectionController::onLoginError(int r,
QString bannedStr =
endTime ? tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString())
: tr("You are banned indefinitely.");
if (!reasonStr.isEmpty())
if (!reasonStr.isEmpty()) {
bannedStr.append("\n\n" + reasonStr);
}
QMessageBox::critical(dialogParent, tr("Error"), bannedStr);
break;
}
@ -354,8 +357,9 @@ void ConnectionController::onRegisterError(int r, QString reasonStr, quint32 end
QString bannedStr =
endTime ? tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString())
: tr("You are banned indefinitely.");
if (!reasonStr.isEmpty())
if (!reasonStr.isEmpty()) {
bannedStr.append("\n\n" + reasonStr);
}
QMessageBox::critical(dialogParent, tr("Error"), bannedStr);
break;
}
@ -545,8 +549,9 @@ QString ConnectionController::extractInvalidUsernameMessage(QString &in)
out +=
"<li>" + tr("can %1 contain numeric characters").arg((rules.at(4).toInt() > 0) ? "" : tr("NOT")) + "</li>";
if (rules.at(6).size() > 0)
if (rules.at(6).size() > 0) {
out += "<li>" + tr("can contain the following punctuation: %1").arg(rules.at(6).toHtmlEscaped()) + "</li>";
}
out += "<li>" +
tr("first character can %1 be a punctuation mark").arg((rules.at(5).toInt() > 0) ? "" : tr("NOT")) +
@ -566,10 +571,11 @@ QString ConnectionController::extractInvalidUsernameMessage(QString &in)
}
}
if (rules.at(8).size() > 0)
if (rules.at(8).size() > 0) {
out += "<li>" +
tr("can not match any of the following expressions: %1").arg(rules.at(8).toHtmlEscaped()) +
"</li>";
}
}
out += "</ul>";

View file

@ -1,8 +1,8 @@
/**
* @file deck_stats_interface.h
* @ingroup ApiInterfaces
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DECKSTATS_INTERFACE_H
#define DECKSTATS_INTERFACE_H

View file

@ -99,14 +99,16 @@ void TappedOutInterface::copyDeckSplitMainAndSide(const DeckList &source, DeckLi
{
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
if (!dbCard || dbCard->getIsToken())
if (!dbCard || dbCard->getIsToken()) {
return;
}
DecklistCardNode *addedCard;
if (node->getName() == DECK_ZONE_SIDE)
if (node->getName() == DECK_ZONE_SIDE) {
addedCard = sideboard.addCard(card->getName(), node->getName(), -1);
else
} else {
addedCard = mainboard.addCard(card->getName(), node->getName(), -1);
}
addedCard->setNumber(card->getNumber());
};

View file

@ -1,8 +1,8 @@
/**
* @file tapped_out_interface.h
* @ingroup ApiInterfaces
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef TAPPEDOUT_INTERFACE_H
#define TAPPEDOUT_INTERFACE_H

View file

@ -1,8 +1,8 @@
/**
* @file deck_link_to_api_transformer.h
* @ingroup ApiInterfaces
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DECK_LINK_TO_API_TRANSFORMER_H
#define DECK_LINK_TO_API_TRANSFORMER_H

View file

@ -1,8 +1,8 @@
/**
* @file interface_json_deck_parser.h
* @ingroup ApiInterfaces
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef INTERFACE_JSON_DECK_PARSER_H
#define INTERFACE_JSON_DECK_PARSER_H

View file

@ -1,8 +1,8 @@
/**
* @file spoiler_background_updater.h
* @ingroup Client
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_SPOILER_DOWNLOADER_H
#define COCKATRICE_SPOILER_DOWNLOADER_H

View file

@ -1,8 +1,8 @@
/**
* @file client_update_checker.h
* @ingroup ClientUpdate
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef CLIENT_UPDATE_CHECKER_H
#define CLIENT_UPDATE_CHECKER_H

View file

@ -129,8 +129,9 @@ void StableReleaseChannel::releaseListFinished()
return;
}
if (!lastRelease)
if (!lastRelease) {
lastRelease = new Release;
}
lastRelease->setName(resultMap["name"].toString());
lastRelease->setDescriptionUrl(resultMap["html_url"].toString());
@ -246,8 +247,9 @@ void BetaReleaseChannel::releaseListFinished()
return;
}
if (lastRelease == nullptr)
if (lastRelease == nullptr) {
lastRelease = new Release;
}
lastRelease->setCommitHash(resultMap["target_commitish"].toString());
lastRelease->setPublishDate(resultMap["published_at"].toDate());

View file

@ -1,8 +1,8 @@
/**
* @file release_channel.h
* @ingroup ClientUpdate
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef RELEASECHANNEL_H
#define RELEASECHANNEL_H

View file

@ -10,8 +10,9 @@ UpdateDownloader::UpdateDownloader(QObject *parent) : QObject(parent), response(
void UpdateDownloader::beginDownload(QUrl downloadUrl)
{
// Save the original URL because we need it for the filename
if (originalUrl.isEmpty())
if (originalUrl.isEmpty()) {
originalUrl = downloadUrl;
}
response = netMan->get(QNetworkRequest(downloadUrl));
connect(response, &QNetworkReply::finished, this, &UpdateDownloader::fileFinished);
@ -21,8 +22,9 @@ void UpdateDownloader::beginDownload(QUrl downloadUrl)
void UpdateDownloader::downloadError(QNetworkReply::NetworkError)
{
if (response == nullptr)
if (response == nullptr) {
return;
}
emit error(response->errorString().toUtf8());
}

View file

@ -1,8 +1,8 @@
/**
* @file update_downloader.h
* @ingroup ClientUpdate
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_UPDATEDOWNLOADER_H
#define COCKATRICE_UPDATEDOWNLOADER_H

View file

@ -1,5 +1,7 @@
#include "cache_settings.h"
#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h"
#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h"
#include "../network/update/client/release_channel.h"
#include "card_counter_settings.h"
#include "version_string.h"
@ -24,10 +26,11 @@ SettingsCache &SettingsCache::instance()
QString SettingsCache::getDataPath()
{
if (isPortableBuild)
if (isPortableBuild) {
return qApp->applicationDirPath() + "/data";
else
} else {
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
}
}
QString SettingsCache::getSettingsPath()
@ -37,10 +40,11 @@ QString SettingsCache::getSettingsPath()
QString SettingsCache::getCachePath() const
{
if (isPortableBuild)
if (isPortableBuild) {
return qApp->applicationDirPath() + "/cache";
else
} else {
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
}
}
QString SettingsCache::getNetworkCachePath() const
@ -50,14 +54,17 @@ QString SettingsCache::getNetworkCachePath() const
void SettingsCache::translateLegacySettings()
{
if (isPortableBuild)
if (isPortableBuild) {
return;
}
// Layouts
QFile layoutFile(getSettingsPath() + "layouts/deckLayout.ini");
if (layoutFile.exists())
if (layoutFile.copy(getSettingsPath() + "layouts.ini"))
if (layoutFile.exists()) {
if (layoutFile.copy(getSettingsPath() + "layouts.ini")) {
layoutFile.remove();
}
}
QStringList usedKeys;
QSettings legacySetting;
@ -116,10 +123,11 @@ void SettingsCache::translateLegacySettings()
gameFilters().setHideIgnoredUserGames(legacySetting.value("hide_ignored_user_games").toBool());
gameFilters().setMinPlayers(legacySetting.value("min_players").toInt());
if (legacySetting.value("max_players").toInt() > 1)
if (legacySetting.value("max_players").toInt() > 1) {
gameFilters().setMaxPlayers(legacySetting.value("max_players").toInt());
else
} else {
gameFilters().setMaxPlayers(99); // This prevents a bug where no games will show if max was not set before
}
QStringList allFilters = legacySetting.allKeys();
for (int i = 0; i < allFilters.size(); ++i) {
@ -135,8 +143,9 @@ void SettingsCache::translateLegacySettings()
QStringList allLegacyKeys = legacySetting.allKeys();
for (int i = 0; i < allLegacyKeys.size(); ++i) {
if (usedKeys.contains(allLegacyKeys.at(i)))
if (usedKeys.contains(allLegacyKeys.at(i))) {
continue;
}
settings->setValue(allLegacyKeys.at(i), legacySetting.value(allLegacyKeys.at(i)));
}
}
@ -147,8 +156,9 @@ QString SettingsCache::getSafeConfigPath(QString configEntry, QString defaultPat
// if the config settings is empty or refers to a not-existing folder,
// ensure that the defaut path exists and return it
if (tmp.isEmpty() || !QDir(tmp).exists()) {
if (!QDir().mkpath(defaultPath))
if (!QDir().mkpath(defaultPath)) {
qCInfo(SettingsCacheLog) << "[SettingsCache] Could not create folder:" << defaultPath;
}
tmp = defaultPath;
}
return tmp;
@ -159,8 +169,9 @@ QString SettingsCache::getSafeConfigFilePath(QString configEntry, QString defaul
QString tmp = settings->value(configEntry).toString();
// if the config settings is empty or refers to a not-existing file,
// return the default Path
if (!QFile::exists(tmp) || tmp.isEmpty())
if (!QFile::exists(tmp) || tmp.isEmpty()) {
tmp = std::move(defaultPath);
}
return tmp;
}
@ -168,8 +179,9 @@ SettingsCache::SettingsCache()
{
// first, figure out if we are running in portable mode
isPortableBuild = QFile::exists(qApp->applicationDirPath() + "/portable.dat");
if (isPortableBuild)
if (isPortableBuild) {
qCInfo(SettingsCacheLog) << "Portable mode enabled";
}
// define a dummy context that will be used where needed
QString dummy = QT_TRANSLATE_NOOP("i18n", "English");
@ -189,8 +201,9 @@ SettingsCache::SettingsCache()
cardCounterSettings = new CardCounterSettings(settingsPath, this);
if (!QFile(settingsPath + "global.ini").exists())
if (!QFile(settingsPath + "global.ini").exists()) {
translateLegacySettings();
}
// updates - don't reorder them or their index in the settings won't match
// append channels one by one, or msvc will add them in the wrong order.
@ -257,14 +270,26 @@ SettingsCache::SettingsCache()
settings->setValue("personal/pixmapCacheSize", pixmapCacheSize);
settings->setValue("personal/picturedownloadhq", false);
settings->setValue("revert/pixmapCacheSize", true);
} else
} else {
pixmapCacheSize = settings->value("personal/pixmapCacheSize", PIXMAPCACHE_SIZE_DEFAULT).toInt();
}
// sanity check
if (pixmapCacheSize < PIXMAPCACHE_SIZE_MIN || pixmapCacheSize > PIXMAPCACHE_SIZE_MAX)
if (pixmapCacheSize < PIXMAPCACHE_SIZE_MIN || pixmapCacheSize > PIXMAPCACHE_SIZE_MAX) {
pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT;
}
networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt();
redirectCacheTtl = settings->value("personal/redirectCacheTtl", NETWORK_REDIRECT_CACHE_TTL_DEFAULT).toInt();
cardPictureLoaderCacheMethod =
settings
->value("personal/cardPictureLoaderCacheMethod",
static_cast<int>(CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE))
.toInt();
localCardImageStorageNamingScheme =
settings
->value("personal/localCardImageStorageNamingScheme",
static_cast<int>(CardPictureLoaderLocalSchemes::NamingScheme::Set_Folder_Name_Set_Collector))
.toInt();
picDownload = settings->value("personal/picturedownload", true).toBool();
showStatusBar = settings->value("personal/showStatusBar", false).toBool();
@ -770,8 +795,9 @@ void SettingsCache::setPrintingSelectorCardSize(int _printingSelectorCardSize)
void SettingsCache::setIncludeRebalancedCards(bool _includeRebalancedCards)
{
if (includeRebalancedCards == _includeRebalancedCards)
if (includeRebalancedCards == _includeRebalancedCards) {
return;
}
includeRebalancedCards = _includeRebalancedCards;
settings->setValue("cards/includerebalancedcards", includeRebalancedCards);
@ -1098,6 +1124,13 @@ void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
emit pixmapCacheSizeChanged(pixmapCacheSize);
}
void SettingsCache::setCardImageCacheMethod(const CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod)
{
cardPictureLoaderCacheMethod = static_cast<int>(_cardImageCachingMethod);
settings->setValue("personal/cardPictureLoaderCacheMethod", cardPictureLoaderCacheMethod);
emit cardPictureLoaderCacheMethodChanged(cardPictureLoaderCacheMethod);
}
void SettingsCache::setNetworkCacheSizeInMB(const int _networkCacheSize)
{
networkCacheSize = _networkCacheSize;
@ -1112,6 +1145,14 @@ void SettingsCache::setNetworkRedirectCacheTtl(const int _redirectCacheTtl)
emit redirectCacheTtlChanged(redirectCacheTtl);
}
void SettingsCache::setLocalCardImageStorageNamingScheme(
const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme)
{
localCardImageStorageNamingScheme = static_cast<int>(_localCardImageStorageNamingScheme);
settings->setValue("personal/localCardImageStorageNamingScheme", localCardImageStorageNamingScheme);
emit localCardImageStorageNamingSchemeChanged(localCardImageStorageNamingScheme);
}
void SettingsCache::setClientID(const QString &_clientID)
{
clientID = _clientID;
@ -1310,8 +1351,9 @@ void SettingsCache::setMaxFontSize(int _max)
void SettingsCache::setRoundCardCorners(bool _roundCardCorners)
{
if (_roundCardCorners == roundCardCorners)
if (_roundCardCorners == roundCardCorners) {
return;
}
roundCardCorners = _roundCardCorners;
settings->setValue("cards/roundcardcorners", _roundCardCorners);

View file

@ -1,12 +1,14 @@
/**
* @file cache_settings.h
* @ingroup Settings
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef SETTINGSCACHE_H
#define SETTINGSCACHE_H
#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h"
#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h"
#include "shortcuts_settings.h"
#include <QDate>
@ -184,6 +186,8 @@ signals:
void pixmapCacheSizeChanged(int newSizeInMBs);
void networkCacheSizeChanged(int newSizeInMBs);
void redirectCacheTtlChanged(int newTtl);
void cardPictureLoaderCacheMethodChanged(int cardPictureLoaderCacheMethod);
void localCardImageStorageNamingSchemeChanged(int localCardImageStorageNamingScheme);
void masterVolumeChanged(int value);
void chatMentionCompleterChanged();
void downloadSpoilerTimeIndexChanged();
@ -303,6 +307,8 @@ private:
int pixmapCacheSize;
int networkCacheSize;
int redirectCacheTtl;
int cardPictureLoaderCacheMethod;
int localCardImageStorageNamingScheme;
bool scaleCards;
int verticalCardOverlapPercent;
bool showMessagePopups;
@ -786,6 +792,10 @@ public:
{
return pixmapCacheSize;
}
[[nodiscard]] CardPictureLoaderCacheMethod::CacheMethod getCardPictureLoaderCacheMethod() const
{
return static_cast<CardPictureLoaderCacheMethod::CacheMethod>(cardPictureLoaderCacheMethod);
}
[[nodiscard]] int getNetworkCacheSizeInMB() const
{
return networkCacheSize;
@ -794,6 +804,10 @@ public:
{
return redirectCacheTtl;
}
[[nodiscard]] CardPictureLoaderLocalSchemes::NamingScheme getLocalCardImageStorageNamingScheme() const
{
return static_cast<CardPictureLoaderLocalSchemes::NamingScheme>(localCardImageStorageNamingScheme);
}
[[nodiscard]] bool getScaleCards() const
{
return scaleCards;
@ -1098,8 +1112,11 @@ public slots:
void setIgnoreUnregisteredUsers(QT_STATE_CHANGED_T _ignoreUnregisteredUsers);
void setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignoreUnregisteredUserMessages);
void setPixmapCacheSize(const int _pixmapCacheSize);
void setCardImageCacheMethod(CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod);
void setNetworkCacheSizeInMB(const int _networkCacheSize);
void setNetworkRedirectCacheTtl(const int _redirectCacheTtl);
void setLocalCardImageStorageNamingScheme(
const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme);
void setCardScaling(const QT_STATE_CHANGED_T _scaleCards);
void setStackCardOverlapPercent(const int _verticalCardOverlapPercent);
void setShowMessagePopups(const QT_STATE_CHANGED_T _showMessagePopups);

View file

@ -15,8 +15,9 @@ void CardCounterSettings::setColor(int counterId, const QColor &color)
QString key = QString("cards/counters/%1/color").arg(counterId);
if (settings.value(key).value<QColor>() == color)
if (settings.value(key).value<QColor>() == color) {
return;
}
settings.setValue(key, color);
emit colorChanged(counterId, color);

View file

@ -1,8 +1,8 @@
/**
* @file card_counter_settings.h
* @ingroup GameSettings
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef CARD_COUNTER_SETTINGS_H
#define CARD_COUNTER_SETTINGS_H

View file

@ -1,8 +1,8 @@
/**
* @file shortcut_treeview.h
* @ingroup CoreSettings
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef SHORTCUT_TREEVIEW_H
#define SHORTCUT_TREEVIEW_H

View file

@ -64,8 +64,13 @@ ShortcutsSettings::ShortcutsSettings(const QString &settingsPath, QObject *paren
}
}
/// PR 5079 changes Textbox/unfocusTextBox to Player/unfocusTextBox and tab_game/aFocusChat to Player/aFocusChat.
/// A migration is necessary to let players keep their already configured shortcuts.
/**
* @brief Migrates legacy shortcut key names to current naming scheme.
*
* PR 5079 changed Textbox/unfocusTextBox to Player/unfocusTextBox and
* tab_game/aFocusChat to Player/aFocusChat. This migration allows players
* to keep their already configured shortcuts.
*/
void ShortcutsSettings::migrateShortcuts()
{
if (QFile(settingsFilePath).exists()) {
@ -236,9 +241,7 @@ bool ShortcutsSettings::isValid(const QString &name, const QString &sequences) c
return findOverlaps(name, sequences).isEmpty();
}
/**
* Checks if the shortcut is a shortcut that is active in all windows
*/
/** @brief Checks if the shortcut is a shortcut that is active in all windows. */
static bool isAlwaysActiveShortcut(const QString &shortcutName)
{
return shortcutName.startsWith("MainWindow") || shortcutName.startsWith("Tabs");

View file

@ -1,8 +1,8 @@
/**
* @file shortcuts_settings.h
* @ingroup CoreSettings
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef SHORTCUTSSETTINGS_H
#define SHORTCUTSSETTINGS_H
@ -537,6 +537,9 @@ private:
{"Player/aSetAnnotation", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Annotation..."),
parseSequenceString("Alt+N"),
ShortcutGroup::Playing_Area)},
{"Player/aReduceLifeByPower", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Reduce Life by Power"),
parseSequenceString("Ctrl+Shift+L"),
ShortcutGroup::Playing_Area)},
{"Player/aSelectAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Select All Cards in Zone"),
parseSequenceString("Ctrl+A"),
ShortcutGroup::Playing_Area)},

View file

@ -95,8 +95,9 @@ QStringMap &SoundEngine::getAvailableThemes()
dir.setPath(SettingsCache::instance().getDataPath() + "/sounds");
for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
if (!availableThemes.contains(themeName))
if (!availableThemes.contains(themeName)) {
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
}
}
// load themes from cockatrice system dir
@ -111,8 +112,9 @@ QStringMap &SoundEngine::getAvailableThemes()
);
for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
if (!availableThemes.contains(themeName))
if (!availableThemes.contains(themeName)) {
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
}
}
return availableThemes;

View file

@ -1,8 +1,8 @@
/**
* @file sound_engine.h
* @ingroup Core
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef SOUNDENGINE_H
#define SOUNDENGINE_H

View file

@ -88,20 +88,27 @@ static void setupParserRules()
const auto arg = std::any_cast<int>(sv[1]);
const auto op = std::any_cast<QString>(sv[0]);
if (op == ">")
if (op == ">") {
return [=](const int s) { return s > arg; };
if (op == ">=")
}
if (op == ">=") {
return [=](const int s) { return s >= arg; };
if (op == "<")
}
if (op == "<") {
return [=](const int s) { return s < arg; };
if (op == "<=")
}
if (op == "<=") {
return [=](const int s) { return s <= arg; };
if (op == "=")
}
if (op == "=") {
return [=](const int s) { return s == arg; };
if (op == ":")
}
if (op == ":") {
return [=](const int s) { return s == arg; };
if (op == "!=")
}
if (op == "!=") {
return [=](const int s) { return s != arg; };
}
return [](int) { return false; };
};

View file

@ -1,8 +1,8 @@
/**
* @file deck_filter_string.h
* @ingroup DeckStorageWidgets
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DECK_FILTER_STRING_H
#define DECK_FILTER_STRING_H

View file

@ -11,13 +11,15 @@ FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
{
filterCombo = new QComboBox;
filterCombo->setObjectName("filterCombo");
for (int i = 0; i < CardFilter::AttrEnd; i++)
for (int i = 0; i < CardFilter::AttrEnd; i++) {
filterCombo->addItem(CardFilter::attrName(static_cast<CardFilter::Attr>(i)), QVariant(i));
}
typeCombo = new QComboBox;
typeCombo->setObjectName("typeCombo");
for (int i = 0; i < CardFilter::TypeEnd; i++)
for (int i = 0; i < CardFilter::TypeEnd; i++) {
typeCombo->addItem(CardFilter::typeName(static_cast<CardFilter::Type>(i)), QVariant(i));
}
QPushButton *ok = new QPushButton(QPixmap("theme:icons/increment"), QString());
ok->setObjectName("ok");
@ -53,8 +55,9 @@ FilterBuilder::~FilterBuilder()
void FilterBuilder::destroyFilter()
{
if (fltr)
if (fltr) {
delete fltr;
}
}
static int comboCurrentIntData(const QComboBox *combo)
@ -67,8 +70,9 @@ void FilterBuilder::emit_add()
QString txt;
txt = edit->text();
if (txt.length() < 1)
if (txt.length() < 1) {
return;
}
destroyFilter();
fltr = new CardFilter(txt, static_cast<CardFilter::Type>(comboCurrentIntData(typeCombo)),

View file

@ -1,8 +1,8 @@
/**
* @file filter_builder.h
* @ingroup CardDatabaseModelFilters
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef FILTERBUILDER_H
#define FILTERBUILDER_H

View file

@ -23,8 +23,9 @@ void FilterTreeModel::proxyBeginInsertRow(const FilterTreeNode *node, int i)
int idx;
idx = node->index();
if (idx >= 0)
if (idx >= 0) {
beginInsertRows(createIndex(idx, 0, (void *)node), i, i);
}
}
void FilterTreeModel::proxyEndInsertRow(const FilterTreeNode *node, int)
@ -32,8 +33,9 @@ void FilterTreeModel::proxyEndInsertRow(const FilterTreeNode *node, int)
int idx;
idx = node->index();
if (idx >= 0)
if (idx >= 0) {
endInsertRows();
}
}
void FilterTreeModel::proxyBeginRemoveRow(const FilterTreeNode *node, int i)
@ -41,8 +43,9 @@ void FilterTreeModel::proxyBeginRemoveRow(const FilterTreeNode *node, int i)
int idx;
idx = node->index();
if (idx >= 0)
if (idx >= 0) {
beginRemoveRows(createIndex(idx, 0, (void *)node), i, i);
}
}
void FilterTreeModel::proxyEndRemoveRow(const FilterTreeNode *node, int)
@ -50,8 +53,9 @@ void FilterTreeModel::proxyEndRemoveRow(const FilterTreeNode *node, int)
int idx;
idx = node->index();
if (idx >= 0)
if (idx >= 0) {
endRemoveRows();
}
}
FilterTreeNode *FilterTreeModel::indexToNode(const QModelIndex &idx) const
@ -59,12 +63,14 @@ FilterTreeNode *FilterTreeModel::indexToNode(const QModelIndex &idx) const
void *ip;
FilterTreeNode *node;
if (!idx.isValid())
if (!idx.isValid()) {
return fTree;
}
ip = idx.internalPointer();
if (ip == NULL)
if (ip == NULL) {
return fTree;
}
node = static_cast<FilterTreeNode *>(ip);
return node;
@ -145,14 +151,16 @@ int FilterTreeModel::rowCount(const QModelIndex &parent) const
const FilterTreeNode *node;
int result;
if (parent.column() > 0)
if (parent.column() > 0) {
return 0;
}
node = indexToNode(parent);
if (node)
if (node) {
result = node->childCount();
else
} else {
result = 0;
}
return result;
}
@ -166,14 +174,17 @@ QVariant FilterTreeModel::data(const QModelIndex &index, int role) const
{
const FilterTreeNode *node;
if (!index.isValid())
if (!index.isValid()) {
return QVariant();
if (index.column() >= columnCount())
}
if (index.column() >= columnCount()) {
return QVariant();
}
node = indexToNode(index);
if (node == NULL)
if (node == NULL) {
return QVariant();
}
switch (role) {
case Qt::FontRole:
@ -190,10 +201,11 @@ QVariant FilterTreeModel::data(const QModelIndex &index, int role) const
case Qt::WhatsThisRole:
return node->text();
case Qt::CheckStateRole:
if (node->isEnabled())
if (node->isEnabled()) {
return Qt::Checked;
else
} else {
return Qt::Unchecked;
}
default:
return QVariant();
}
@ -205,22 +217,27 @@ bool FilterTreeModel::setData(const QModelIndex &index, const QVariant &value, i
{
FilterTreeNode *node;
if (!index.isValid())
if (!index.isValid()) {
return false;
if (index.column() >= columnCount())
}
if (index.column() >= columnCount()) {
return false;
if (role != Qt::CheckStateRole)
}
if (role != Qt::CheckStateRole) {
return false;
}
node = indexToNode(index);
if (node == NULL || node == fTree)
if (node == NULL || node == fTree) {
return false;
}
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
if (state == Qt::Checked)
if (state == Qt::Checked) {
node->enable();
else
} else {
node->disable();
}
emit dataChanged(index, index);
return true;
@ -231,16 +248,19 @@ Qt::ItemFlags FilterTreeModel::flags(const QModelIndex &index) const
const FilterTreeNode *node;
Qt::ItemFlags result;
if (!index.isValid())
if (!index.isValid()) {
return Qt::NoItemFlags;
}
node = indexToNode(index);
if (node == NULL)
if (node == NULL) {
return Qt::NoItemFlags;
}
result = Qt::ItemIsEnabled;
if (node == fTree)
if (node == fTree) {
return result;
}
result |= Qt::ItemIsSelectable;
result |= Qt::ItemIsUserCheckable;
@ -252,8 +272,9 @@ QModelIndex FilterTreeModel::nodeIndex(const FilterTreeNode *node, int row, int
{
FilterTreeNode *child;
if (column > 0 || row >= node->childCount())
if (column > 0 || row >= node->childCount()) {
return QModelIndex();
}
child = node->nodeAt(row);
return createIndex(row, column, child);
@ -263,12 +284,14 @@ QModelIndex FilterTreeModel::index(int row, int column, const QModelIndex &paren
{
const FilterTreeNode *node;
if (!hasIndex(row, column, parent))
if (!hasIndex(row, column, parent)) {
return QModelIndex();
}
node = indexToNode(parent);
if (node == NULL)
if (node == NULL) {
return QModelIndex();
}
return nodeIndex(node, row, column);
}
@ -279,18 +302,21 @@ QModelIndex FilterTreeModel::parent(const QModelIndex &ind) const
FilterTreeNode *parent;
QModelIndex idx;
if (!ind.isValid())
if (!ind.isValid()) {
return QModelIndex();
}
node = indexToNode(ind);
if (node == NULL || node == fTree)
if (node == NULL || node == fTree) {
return QModelIndex();
}
parent = node->parent();
if (parent) {
int row = parent->index();
if (row < 0)
if (row < 0) {
return QModelIndex();
}
idx = createIndex(row, 0, parent);
return idx;
}
@ -304,18 +330,22 @@ bool FilterTreeModel::removeRows(int row, int count, const QModelIndex &parent)
int i, last;
last = row + count - 1;
if (!parent.isValid() || count < 1 || row < 0)
if (!parent.isValid() || count < 1 || row < 0) {
return false;
}
node = indexToNode(parent);
if (node == NULL || last >= node->childCount())
if (node == NULL || last >= node->childCount()) {
return false;
}
for (i = 0; i < count; i++)
for (i = 0; i < count; i++) {
node->deleteAt(row);
}
if (node != fTree && node->childCount() < 1)
if (node != fTree && node->childCount() < 1) {
return removeRow(parent.row(), parent.parent());
}
return true;
}

View file

@ -1,8 +1,8 @@
/**
* @file filter_tree_model.h
* @ingroup CardDatabaseModelFilters
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef FILTERTREEMODEL_H
#define FILTERTREEMODEL_H

View file

@ -2,8 +2,8 @@
* @file syntax_help.h
* @ingroup CardDatabaseModelFilters
* @ingroup DeckStorageWidgets
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef SEARCH_SYNTAX_HELP_H
#define SEARCH_SYNTAX_HELP_H

View file

@ -1,7 +1,7 @@
#include "abstract_game.h"
#include "../interface/widgets/tabs/tab_game.h"
#include "player/player.h"
#include "player/player_logic.h"
AbstractGame::AbstractGame(TabGame *_tab) : QObject(_tab), tab(_tab)
{
@ -24,10 +24,11 @@ AbstractClient *AbstractGame::getClientForPlayer(int playerId) const
}
return gameState->getClients().at(playerId);
} else if (gameState->getClients().isEmpty())
} else if (gameState->getClients().isEmpty()) {
return nullptr;
else
} else {
return gameState->getClients().first();
}
}
void AbstractGame::loadReplay(GameReplay *replay)
@ -43,13 +44,15 @@ void AbstractGame::setActiveCard(CardItem *card)
CardItem *AbstractGame::getCard(int playerId, const QString &zoneName, int cardId) const
{
Player *player = playerManager->getPlayer(playerId);
if (!player)
PlayerLogic *player = playerManager->getPlayer(playerId);
if (!player) {
return nullptr;
}
CardZoneLogic *zone = player->getZones().value(zoneName, 0);
if (!zone)
if (!zone) {
return nullptr;
}
return zone->getCard(cardId);
}

View file

@ -1,8 +1,8 @@
/**
* @file abstract_game.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_ABSTRACT_GAME_H
#define COCKATRICE_ABSTRACT_GAME_H

View file

@ -25,11 +25,12 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
setCursor(Qt::ClosedHandCursor);
setZValue(ZValues::DRAG_ITEM);
}
if (item->getTapped())
if (item->getTapped()) {
setTransform(QTransform()
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
.rotate(90)
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
}
setCacheMode(DeviceCoordinateCache);

View file

@ -1,8 +1,8 @@
/**
* @file abstract_card_drag_item.h
* @ingroup GameGraphicsCards
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef ABSTRACTCARDDRAGITEM_H
#define ABSTRACTCARDDRAGITEM_H

View file

@ -13,7 +13,7 @@
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/card/database/card_database_manager.h>
AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef, Player *_owner, int _id)
AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef, PlayerLogic *_owner, int _id)
: ArrowTarget(_owner, parent), id(_id), cardRef(cardRef), tapped(false), facedown(false), tapAngle(0),
bgColor(Qt::transparent), isHovered(false), realZValue(0)
{
@ -85,7 +85,12 @@ const CardInfo &AbstractCardItem::getCardInfo() const
void AbstractCardItem::setRealZValue(qreal _zValue)
{
realZValue = _zValue;
setZValue(_zValue);
// During hover, zValue is overridden to HOVERED_CARD. Layout operations
// like reorganizeCards() call setRealZValue() on all cards including the
// hovered one — skip setZValue() here to avoid clobbering the override.
if (!isHovered) {
setZValue(_zValue);
}
}
QSizeF AbstractCardItem::getTranslatedSize(QPainter *painter) const
@ -126,8 +131,9 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
// don't even spend time trying to load the picture if our size is too small
if (translatedSize.width() > 10) {
CardPictureLoader::getPixmap(translatedPixmap, exactCard, translatedSize.toSize());
if (translatedPixmap.isNull())
if (translatedPixmap.isNull()) {
paintImage = false;
}
} else {
paintImage = false;
}
@ -152,9 +158,9 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
painter->setBackground(Qt::black);
painter->setBackgroundMode(Qt::OpaqueMode);
QString nameStr;
if (facedown)
if (facedown) {
nameStr = "# " + QString::number(id);
else {
} else {
QString prefix = "";
if (SettingsCache::instance().debug().getShowCardId()) {
prefix = "#" + QString::number(id) + " ";
@ -181,10 +187,12 @@ void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *
if (isSelected() || isHovered) {
QPen pen;
if (isHovered)
if (isHovered) {
pen.setColor(Qt::yellow);
if (isSelected())
}
if (isSelected()) {
pen.setColor(Qt::red);
}
pen.setWidth(0); // Cosmetic pen
painter->setPen(pen);
painter->drawPath(shape());
@ -210,11 +218,20 @@ void AbstractCardItem::setCardRef(const CardRef &_cardRef)
void AbstractCardItem::setHovered(bool _hovered)
{
if (isHovered == _hovered)
if (isHovered == _hovered) {
return;
}
if (_hovered)
if (_hovered) {
processHoverEvent();
} else {
// Mark the hovered card's current scene footprint dirty so overlapped
// sibling zones (e.g. StackZone) repaint after the card moves away.
if (scene()) {
scene()->update(sceneBoundingRect());
}
}
isHovered = _hovered;
setZValue(_hovered ? ZValues::HOVERED_CARD : realZValue);
setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1);
@ -265,13 +282,14 @@ void AbstractCardItem::cacheBgColor()
void AbstractCardItem::setTapped(bool _tapped, bool canAnimate)
{
if (tapped == _tapped)
if (tapped == _tapped) {
return;
}
tapped = _tapped;
if (SettingsCache::instance().getTapAnimation() && canAnimate)
if (SettingsCache::instance().getTapAnimation() && canAnimate) {
static_cast<GameScene *>(scene())->registerAnimationItem(this);
else {
} else {
tapAngle = tapped ? 90 : 0;
setTransform(QTransform()
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
@ -297,17 +315,19 @@ void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
scene()->clearSelection();
setSelected(true);
}
if (event->button() == Qt::LeftButton)
if (event->button() == Qt::LeftButton) {
setCursor(Qt::ClosedHandCursor);
else if (event->button() == Qt::MiddleButton)
} else if (event->button() == Qt::MiddleButton) {
emit showCardInfoPopup(event->screenPos(), cardRef);
}
event->accept();
}
void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::MiddleButton)
if (event->button() == Qt::MiddleButton) {
emit deleteCardInfoPopup(cardRef.name);
}
// This function ensures the parent function doesn't mess around with our selection.
event->accept();
@ -323,6 +343,7 @@ QVariant AbstractCardItem::itemChange(QGraphicsItem::GraphicsItemChange change,
if (change == ItemSelectedHasChanged) {
update();
return value;
} else
} else {
return ArrowTarget::itemChange(change, value);
}
}

View file

@ -1,7 +1,7 @@
/**
* @file abstract_card_item.h
* @ingroup GameGraphicsCards
* @brief TODO: Document this.
* @brief Base class for graphical card items, providing shared rendering, identity, and interaction logic.
*/
#ifndef ABSTRACTCARDITEM_H
@ -14,7 +14,7 @@
#include <libcockatrice/card/printing/exact_card.h>
#include <libcockatrice/utility/card_ref.h>
class Player;
class PlayerLogic;
class AbstractCardItem : public ArrowTarget
{
@ -56,7 +56,7 @@ public:
}
explicit AbstractCardItem(QGraphicsItem *parent = nullptr,
const CardRef &cardRef = {},
Player *_owner = nullptr,
PlayerLogic *_owner = nullptr,
int _id = -1);
~AbstractCardItem() override;
QRectF boundingRect() const override;
@ -96,6 +96,10 @@ public:
}
void setRealZValue(qreal _zValue);
void setHovered(bool _hovered);
bool getIsHovered() const
{
return isHovered;
}
QString getColor() const
{
return color;

View file

@ -2,13 +2,14 @@
#include "../../client/settings/cache_settings.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "../player/player_logic.h"
#include "translate_counter_name.h"
#include <QAction>
#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <QKeyEvent>
#include <QMenu>
#include <QString>
@ -16,24 +17,24 @@
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
#include <libcockatrice/utility/expression.h>
AbstractCounter::AbstractCounter(Player *_player,
int _id,
const QString &_name,
AbstractCounter::AbstractCounter(CounterState *state,
PlayerLogic *_player,
bool _shownInCounterArea,
int _value,
bool _useNameForShortcut,
QGraphicsItem *parent)
: QGraphicsItem(parent), player(_player), id(_id), name(_name), value(_value),
useNameForShortcut(_useNameForShortcut), hovered(false), aDec(nullptr), aInc(nullptr), dialogSemaphore(false),
deleteAfterDialog(false), shownInCounterArea(_shownInCounterArea)
: QGraphicsItem(parent), player(_player), id(state->getId()), name(state->getName()), value(state->getValue()),
color(state->getColor()), radius(state->getRadius()), useNameForShortcut(_useNameForShortcut),
shownInCounterArea(_shownInCounterArea)
{
setAcceptHoverEvents(true);
shortcutActive = false;
connect(state, &CounterState::valueChanged, this, [this](int, int newValue) {
value = newValue;
update();
});
if (player->getPlayerInfo()->getLocalOrJudge()) {
QString displayName = TranslateCounterName::getDisplayName(_name);
menu = new TearOffMenu(displayName);
menu = new TearOffMenu(TranslateCounterName::getDisplayName(state->getName()));
aSet = new QAction(this);
connect(aSet, &QAction::triggered, this, &AbstractCounter::setCounter);
menu->addAction(aSet);
@ -41,16 +42,18 @@ AbstractCounter::AbstractCounter(Player *_player,
for (int i = 10; i >= -10; --i) {
if (i == 0) {
menu->addSeparator();
} else {
QAction *aIncrement = new QAction(QString(i < 0 ? "%1" : "+%1").arg(i), this);
if (i == -1)
aDec = aIncrement;
else if (i == 1)
aInc = aIncrement;
aIncrement->setData(i);
connect(aIncrement, &QAction::triggered, this, &AbstractCounter::incrementCounter);
menu->addAction(aIncrement);
continue;
}
auto *a = new QAction(QString(i < 0 ? "%1" : "+%1").arg(i), this);
if (i == -1) {
aDec = a;
}
if (i == 1) {
aInc = a;
}
a->setData(i);
connect(a, &QAction::triggered, this, &AbstractCounter::incrementCounter);
menu->addAction(a);
}
} else {
menu = nullptr;
@ -69,39 +72,35 @@ AbstractCounter::~AbstractCounter()
void AbstractCounter::delCounter()
{
if (dialogSemaphore)
if (dialogSemaphore) {
deleteAfterDialog = true;
else
} else {
deleteLater();
}
}
void AbstractCounter::retranslateUi()
{
if (menu) {
if (aSet) {
aSet->setText(tr("&Set counter..."));
}
}
void AbstractCounter::setShortcutsActive()
{
if (!menu) {
if (!menu || !player->getPlayerInfo()->getLocal()) {
return;
}
if (!player->getPlayerInfo()->getLocal()) {
return;
}
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
ShortcutsSettings &sc = SettingsCache::instance().shortcuts();
shortcutActive = true;
if (name == "life") {
shortcutActive = true;
aSet->setShortcuts(shortcuts.getShortcut("Player/aSet"));
aDec->setShortcuts(shortcuts.getShortcut("Player/aDec"));
aInc->setShortcuts(shortcuts.getShortcut("Player/aInc"));
aSet->setShortcuts(sc.getShortcut("Player/aSet"));
aDec->setShortcuts(sc.getShortcut("Player/aDec"));
aInc->setShortcuts(sc.getShortcut("Player/aInc"));
} else if (useNameForShortcut) {
shortcutActive = true;
aSet->setShortcuts(shortcuts.getShortcut("Player/aSetCounter_" + name));
aDec->setShortcuts(shortcuts.getShortcut("Player/aDecCounter_" + name));
aInc->setShortcuts(shortcuts.getShortcut("Player/aIncCounter_" + name));
aSet->setShortcuts(sc.getShortcut("Player/aSetCounter_" + name));
aDec->setShortcuts(sc.getShortcut("Player/aDecCounter_" + name));
aInc->setShortcuts(sc.getShortcut("Player/aIncCounter_" + name));
}
}
@ -126,43 +125,32 @@ void AbstractCounter::refreshShortcuts()
}
}
void AbstractCounter::setValue(int _value)
{
value = _value;
update();
}
void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (isUnderMouse() && player->getPlayerInfo()->getLocalOrJudge()) {
if (event->button() == Qt::MiddleButton || (QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
if (menu)
menu->exec(event->screenPos());
event->accept();
} else if (event->button() == Qt::LeftButton) {
Command_IncCounter cmd;
cmd.set_counter_id(id);
cmd.set_delta(1);
player->getPlayerActions()->sendGameCommand(cmd);
event->accept();
} else if (event->button() == Qt::RightButton) {
Command_IncCounter cmd;
cmd.set_counter_id(id);
cmd.set_delta(-1);
player->getPlayerActions()->sendGameCommand(cmd);
event->accept();
}
} else
if (!isUnderMouse() || !player->getPlayerInfo()->getLocalOrJudge()) {
event->ignore();
return;
}
if (event->button() == Qt::MiddleButton || QApplication::keyboardModifiers() & Qt::ShiftModifier) {
if (menu) {
menu->exec(event->screenPos());
}
} else {
Command_IncCounter cmd;
cmd.set_counter_id(id);
cmd.set_delta(event->button() == Qt::LeftButton ? 1 : -1);
player->getPlayerActions()->sendGameCommand(cmd);
}
event->accept();
}
void AbstractCounter::hoverEnterEvent(QGraphicsSceneHoverEvent * /*event*/)
void AbstractCounter::hoverEnterEvent(QGraphicsSceneHoverEvent *)
{
hovered = true;
update();
}
void AbstractCounter::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/)
void AbstractCounter::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
{
hovered = false;
update();
@ -170,34 +158,36 @@ void AbstractCounter::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/)
void AbstractCounter::incrementCounter()
{
const int delta = static_cast<QAction *>(sender())->data().toInt();
Command_IncCounter cmd;
cmd.set_counter_id(id);
cmd.set_delta(delta);
cmd.set_delta(static_cast<QAction *>(sender())->data().toInt());
player->getPlayerActions()->sendGameCommand(cmd);
}
void AbstractCounter::setCounter()
{
QWidget *parent = nullptr;
if (auto *view = scene() ? scene()->views().value(0) : nullptr) {
parent = view->window();
}
dialogSemaphore = true;
AbstractCounterDialog dialog(name, QString::number(value), player->getGame()->getTab());
const int ok = dialog.exec();
AbstractCounterDialog dlg(name, QString::number(value), parent);
const int ok = dlg.exec();
dialogSemaphore = false;
if (deleteAfterDialog) {
deleteLater();
return;
}
dialogSemaphore = false;
if (!ok)
if (!ok) {
return;
}
Expression exp(value);
int newValue = static_cast<int>(exp.parse(dialog.textValue()));
Command_SetCounter cmd;
cmd.set_counter_id(id);
cmd.set_value(newValue);
cmd.set_value(static_cast<int>(exp.parse(dlg.textValue())));
player->getPlayerActions()->sendGameCommand(cmd);
}
@ -231,8 +221,9 @@ void AbstractCounterDialog::changeValue(int diff)
{
bool ok;
int curValue = textValue().toInt(&ok);
if (!ok)
if (!ok) {
return;
}
curValue += diff;
setTextValue(QString::number(curValue));
}

View file

@ -1,19 +1,20 @@
/**
* @file abstract_counter.h
* @ingroup GameGraphicsPlayers
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COUNTER_H
#define COUNTER_H
#include "../../interface/widgets/menus/tearoff_menu.h"
#include "../player/menu/abstract_player_component.h"
#include "counter_state.h"
#include <QGraphicsItem>
#include <QInputDialog>
class Player;
class PlayerLogic;
class QAction;
class QKeyEvent;
class QMenu;
@ -25,22 +26,26 @@ class AbstractCounter : public QObject, public QGraphicsItem, public AbstractPla
Q_INTERFACES(QGraphicsItem)
protected:
Player *player;
PlayerLogic *player;
int id;
QString name;
int value;
bool useNameForShortcut, hovered;
QColor color;
int radius;
bool hovered = false;
bool useNameForShortcut;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
private:
QAction *aSet, *aDec, *aInc;
TearOffMenu *menu;
bool dialogSemaphore, deleteAfterDialog;
QAction *aSet = nullptr, *aDec = nullptr, *aInc = nullptr;
TearOffMenu *menu = nullptr;
bool dialogSemaphore = false;
bool deleteAfterDialog = false;
bool shownInCounterArea;
bool shortcutActive;
bool shortcutActive = false;
private slots:
void refreshShortcuts();
@ -48,17 +53,14 @@ private slots:
void setCounter();
public:
AbstractCounter(Player *_player,
int _id,
const QString &_name,
bool _shownInCounterArea,
int _value,
bool _useNameForShortcut = false,
AbstractCounter(CounterState *state,
PlayerLogic *player,
bool shownInCounterArea,
bool useNameForShortcut = false,
QGraphicsItem *parent = nullptr);
~AbstractCounter() override;
void retranslateUi() override;
void setValue(int _value);
void setShortcutsActive() override;
void setShortcutsInactive() override;
void delCounter();
@ -67,7 +69,6 @@ public:
{
return menu;
}
int getId() const
{
return id;
@ -76,14 +77,22 @@ public:
{
return name;
}
bool getShownInCounterArea() const
QColor getColor() const
{
return shownInCounterArea;
return color;
}
int getRadius() const
{
return radius;
}
int getValue() const
{
return value;
}
bool getShownInCounterArea() const
{
return shownInCounterArea;
}
};
class AbstractCounterDialog : public QInputDialog

View file

@ -0,0 +1,19 @@
#include "arrow_data.h"
ArrowData ArrowData::fromProto(const ServerInfo_Arrow &arrow)
{
ArrowData data;
data.id = arrow.id();
data.startPlayerId = arrow.start_player_id();
data.startZone = QString::fromStdString(arrow.start_zone());
data.startCardId = arrow.start_card_id();
data.targetPlayerId = arrow.target_player_id();
data.color = convertColorToQColor(arrow.arrow_color());
if (arrow.has_target_zone()) {
data.targetZone = QString::fromStdString(arrow.target_zone());
data.targetCardId = arrow.target_card_id();
}
return data;
}

View file

@ -0,0 +1,28 @@
#ifndef COCKATRICE_ARROW_DATA_H
#define COCKATRICE_ARROW_DATA_H
#include <QColor>
#include <QString>
#include <libcockatrice/protocol/pb/serverinfo_arrow.pb.h>
#include <libcockatrice/utility/color.h>
struct ArrowData
{
int id;
int startPlayerId;
QString startZone;
int startCardId;
int targetPlayerId;
QString targetZone; // empty = targeting a player
int targetCardId = -1; // -1 = targeting a player
QColor color;
static ArrowData fromProto(const ServerInfo_Arrow &arrow);
bool isPlayerTargeted() const
{
return targetZone.isEmpty();
}
};
#endif // COCKATRICE_ARROW_DATA_H

View file

@ -2,11 +2,11 @@
#include "arrow_item.h"
#include "../../client/settings/cache_settings.h"
#include "../player/player.h"
#include "../../game_graphics/zones/card_zone.h"
#include "../player/player_actions.h"
#include "../player/player_logic.h"
#include "../player/player_target.h"
#include "../z_values.h"
#include "../zones/card_zone.h"
#include "card_item.h"
#include <QDebug>
@ -21,46 +21,53 @@
#include <libcockatrice/utility/color.h>
#include <libcockatrice/utility/zone_names.h>
ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color)
: QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), targetLocked(false),
color(_color), fullColor(true)
ArrowItem::ArrowItem(PlayerLogic *_player,
int _id,
ArrowTarget *_startItem,
ArrowTarget *_targetItem,
const QColor &_color)
: player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), color(_color)
{
setZValue(ZValues::ARROWS);
if (startItem)
startItem->addArrowFrom(this);
if (targetItem)
targetItem->addArrowTo(this);
auto doUpdate = [this]() {
if (startItem && targetItem) {
updatePath();
}
};
if (startItem && targetItem)
if (startItem) {
connect(startItem, &ArrowTarget::scenePositionChanged, this, doUpdate);
connect(startItem, &QObject::destroyed, this, &ArrowItem::onTargetDestroyed);
}
if (targetItem) {
connect(targetItem, &ArrowTarget::scenePositionChanged, this, doUpdate);
connect(targetItem, &QObject::destroyed, this, &ArrowItem::onTargetDestroyed);
}
if (startItem && targetItem) {
updatePath();
}
}
ArrowItem::~ArrowItem()
void ArrowItem::onTargetDestroyed()
{
emit requestDeletion(id);
}
void ArrowItem::delArrow()
{
if (startItem) {
startItem->removeArrowFrom(this);
startItem = 0;
}
if (targetItem) {
targetItem->setBeingPointedAt(false);
targetItem->removeArrowTo(this);
targetItem = 0;
}
player->removeArrow(this);
deleteLater();
}
void ArrowItem::updatePath()
{
if (!targetItem)
if (!targetItem) {
return;
}
QPointF endPoint = targetItem->mapToScene(
QPointF(targetItem->boundingRect().width() / 2, targetItem->boundingRect().height() / 2));
@ -75,8 +82,9 @@ void ArrowItem::updatePath(const QPointF &endPoint)
headWidth / qPow(2, 0.5); // aka headWidth / sqrt (2) but this produces a compile error with MSVC++
const double phi = 15;
if (!startItem)
if (!startItem) {
return;
}
QPointF startPoint =
startItem->mapToScene(QPointF(startItem->boundingRect().width() / 2, startItem->boundingRect().height() / 2));
@ -84,9 +92,9 @@ void ArrowItem::updatePath(const QPointF &endPoint)
qreal lineLength = line.length();
prepareGeometryChange();
if (lineLength < 30)
if (lineLength < 30) {
path = QPainterPath();
else {
} else {
QPointF c(lineLength / 2, qTan(phi * M_PI / 180) * lineLength);
QPainterPath centerLine;
@ -123,10 +131,11 @@ void ArrowItem::updatePath(const QPointF &endPoint)
void ArrowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QColor paintColor(color);
if (fullColor)
if (fullColor) {
paintColor.setAlpha(200);
else
} else {
paintColor.setAlpha(150);
}
painter->setBrush(paintColor);
painter->drawPath(path);
}
@ -138,8 +147,7 @@ void ArrowItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
return;
}
QList<QGraphicsItem *> colliding = scene()->items(event->scenePos());
for (QGraphicsItem *item : colliding) {
for (auto *item : scene()->items(event->scenePos())) {
if (qgraphicsitem_cast<CardItem *>(item)) {
event->ignore();
return;
@ -148,80 +156,86 @@ void ArrowItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
event->accept();
if (event->button() == Qt::RightButton) {
Command_DeleteArrow cmd;
cmd.set_arrow_id(id);
player->getPlayerActions()->sendGameCommand(cmd);
emit requestDeletion(id);
}
}
ArrowDragItem::ArrowDragItem(Player *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase)
: ArrowItem(_owner, -1, _startItem, 0, _color), deleteInPhase(_deleteInPhase)
// ArrowDragItem
ArrowDragItem::ArrowDragItem(PlayerLogic *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase)
: ArrowItem(_owner, -1, _startItem, nullptr, _color), deleteInPhase(_deleteInPhase)
{
}
void ArrowDragItem::addChildArrow(ArrowDragItem *childArrow)
void ArrowDragItem::addChildArrow(ArrowDragItem *child)
{
childArrows.append(childArrow);
childArrows.append(child);
}
void ArrowDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
// This ensures that if a mouse move event happens after a call to delArrow(),
// the event will be discarded as it would create some stray pointers.
if (targetLocked || !startItem)
if (targetLocked || !startItem) {
return;
}
QPointF endPos = event->scenePos();
const QPointF endPos = event->scenePos();
QList<QGraphicsItem *> colliding = scene()->items(endPos);
ArrowTarget *cursorItem = 0;
ArrowTarget *cursorItem = nullptr;
qreal cursorItemZ = -1;
for (int i = colliding.size() - 1; i >= 0; i--) {
if (qgraphicsitem_cast<PlayerTarget *>(colliding.at(i)) || qgraphicsitem_cast<CardItem *>(colliding.at(i))) {
if (colliding.at(i)->zValue() > cursorItemZ) {
cursorItem = static_cast<ArrowTarget *>(colliding.at(i));
cursorItemZ = cursorItem->zValue();
}
for (auto *item : scene()->items(endPos)) {
ArrowTarget *candidate = nullptr;
if (auto *card = qgraphicsitem_cast<CardItem *>(item)) {
candidate = card;
} else if (auto *pt = qgraphicsitem_cast<PlayerTarget *>(item)) {
candidate = pt;
}
if (candidate && candidate->zValue() > cursorItemZ) {
cursorItem = candidate;
cursorItemZ = candidate->zValue();
}
}
if ((cursorItem != targetItem) && targetItem) {
targetItem->setBeingPointedAt(false);
targetItem->removeArrowTo(this);
}
if (!cursorItem) {
fullColor = false;
targetItem = 0;
updatePath(endPos);
} else {
if (cursorItem != targetItem) {
fullColor = true;
if (cursorItem != startItem) {
cursorItem->setBeingPointedAt(true);
cursorItem->addArrowTo(this);
}
targetItem = cursorItem;
if (cursorItem != targetItem) {
if (targetItem) {
disconnect(positionConnection);
targetItem->setBeingPointedAt(false);
}
targetItem = cursorItem;
fullColor = (cursorItem != nullptr);
if (cursorItem && cursorItem != startItem) {
cursorItem->setBeingPointedAt(true);
positionConnection =
connect(cursorItem, &ArrowTarget::scenePositionChanged, this, [this]() { updatePath(); });
}
updatePath();
}
targetItem ? updatePath() : updatePath(endPos);
update();
for (ArrowDragItem *child : childArrows) {
for (auto *child : childArrows) {
child->mouseMoveEvent(event);
}
}
void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (!startItem)
if (!startItem) {
return;
}
if (targetItem && (targetItem != startItem)) {
CardZoneLogic *startZone = static_cast<CardItem *>(startItem)->getZone();
if (targetItem && targetItem != startItem) {
CardItem *startCard = qgraphicsitem_cast<CardItem *>(startItem);
// For now, we can safely assume that the start item is always a card.
// The target item can be a player as well.
CardItem *startCard = qgraphicsitem_cast<CardItem *>(startItem);
CardItem *targetCard = qgraphicsitem_cast<CardItem *>(targetItem);
if (!startCard) {
delArrow();
return;
}
CardZoneLogic *startZone = startCard->getZone();
Command_CreateArrow cmd;
cmd.mutable_arrow_color()->CopyFrom(convertQColorToColor(color));
@ -229,14 +243,16 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
cmd.set_start_zone(startZone->getName().toStdString());
cmd.set_start_card_id(startCard->getId());
if (targetCard) {
if (auto *targetCard = qgraphicsitem_cast<CardItem *>(targetItem)) {
CardZoneLogic *targetZone = targetCard->getZone();
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(targetZone->getName().toStdString());
cmd.set_target_card_id(targetCard->getId());
} else { // failed to cast target to card, this means it's a player
PlayerTarget *targetPlayer = qgraphicsitem_cast<PlayerTarget *>(targetItem);
} else if (auto *targetPlayer = qgraphicsitem_cast<PlayerTarget *>(targetItem)) {
cmd.set_target_player_id(targetPlayer->getOwner()->getPlayerInfo()->getId());
} else {
delArrow();
return;
}
// if the card is in hand then we will move the card to stack or table as part of drawing the arrow
@ -246,10 +262,11 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
bool playToStack = SettingsCache::instance().getPlayToStack();
if (ci && ((!playToStack && ci->getUiAttributes().tableRow == 3) ||
(playToStack && ci->getUiAttributes().tableRow != 0 &&
startCard->getZone()->getName() != ZoneNames::STACK)))
startCard->getZone()->getName() != ZoneNames::STACK))) {
cmd.set_start_zone(ZoneNames::STACK);
else
} else {
cmd.set_start_zone(playToStack ? ZoneNames::STACK : ZoneNames::TABLE);
}
}
if (deleteInPhase != 0) {
@ -258,111 +275,109 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
player->getPlayerActions()->sendGameCommand(cmd);
}
delArrow();
for (ArrowDragItem *child : childArrows) {
delArrow();
for (auto *child : childArrows) {
child->mouseReleaseEvent(event);
}
}
// ArrowAttachItem
ArrowAttachItem::ArrowAttachItem(ArrowTarget *_startItem)
: ArrowItem(_startItem->getOwner(), -1, _startItem, 0, Qt::green)
: ArrowItem(_startItem->getOwner(), -1, _startItem, nullptr, Qt::green)
{
}
void ArrowAttachItem::addChildArrow(ArrowAttachItem *childArrow)
void ArrowAttachItem::addChildArrow(ArrowAttachItem *child)
{
childArrows.append(childArrow);
childArrows.append(child);
}
void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (targetLocked || !startItem)
if (targetLocked || !startItem) {
return;
}
QPointF endPos = event->scenePos();
const QPointF endPos = event->scenePos();
QList<QGraphicsItem *> colliding = scene()->items(endPos);
ArrowTarget *cursorItem = 0;
ArrowTarget *cursorItem = nullptr;
qreal cursorItemZ = -1;
for (int i = colliding.size() - 1; i >= 0; i--) {
if (qgraphicsitem_cast<CardItem *>(colliding.at(i))) {
if (colliding.at(i)->zValue() > cursorItemZ) {
cursorItem = static_cast<ArrowTarget *>(colliding.at(i));
cursorItemZ = cursorItem->zValue();
for (auto *item : scene()->items(endPos)) {
if (auto *card = qgraphicsitem_cast<CardItem *>(item)) {
if (card->zValue() > cursorItemZ) {
cursorItem = card;
cursorItemZ = card->zValue();
}
}
}
if ((cursorItem != targetItem) && targetItem) {
targetItem->setBeingPointedAt(false);
}
if (!cursorItem) {
fullColor = false;
targetItem = 0;
updatePath(endPos);
} else {
fullColor = true;
if (cursorItem != startItem) {
cursorItem->setBeingPointedAt(true);
if (cursorItem != targetItem) {
if (targetItem) {
disconnect(positionConnection);
targetItem->setBeingPointedAt(false);
}
targetItem = cursorItem;
updatePath();
fullColor = (cursorItem != nullptr);
if (cursorItem && cursorItem != startItem) {
cursorItem->setBeingPointedAt(true);
positionConnection =
connect(cursorItem, &ArrowTarget::scenePositionChanged, this, [this]() { updatePath(); });
}
}
targetItem ? updatePath() : updatePath(endPos);
update();
for (ArrowAttachItem *child : childArrows) {
for (auto *child : childArrows) {
child->mouseMoveEvent(event);
}
}
void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard)
{
// do nothing if target is already attached to another card or is not in play
if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != ZoneNames::TABLE) {
return;
}
CardZoneLogic *startZone = startCard->getZone();
CardZoneLogic *targetZone = targetCard->getZone();
// move card onto table first if attaching from some other zone
if (startZone->getName() != ZoneNames::TABLE) {
player->getPlayerActions()->playCardToTable(startCard, false);
}
Command_AttachCard cmd;
cmd.set_start_zone(ZoneNames::TABLE);
cmd.set_card_id(startCard->getId());
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(targetZone->getName().toStdString());
cmd.set_target_card_id(targetCard->getId());
player->getPlayerActions()->sendGameCommand(cmd);
}
void ArrowAttachItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (!startItem)
if (!startItem) {
return;
}
// Attaching could move startItem under the current cursor position, causing all children to retarget to it right
// before they are processed. Prevent that.
for (ArrowAttachItem *child : childArrows) {
for (auto *child : childArrows) {
child->setTargetLocked(true);
}
if (targetItem && (targetItem != startItem)) {
auto startCard = qgraphicsitem_cast<CardItem *>(startItem);
auto targetCard = qgraphicsitem_cast<CardItem *>(targetItem);
if (targetItem && targetItem != startItem) {
auto *startCard = qgraphicsitem_cast<CardItem *>(startItem);
auto *targetCard = qgraphicsitem_cast<CardItem *>(targetItem);
if (startCard && targetCard) {
attachCards(startCard, targetCard);
}
}
delArrow();
for (ArrowAttachItem *child : childArrows) {
for (auto *child : childArrows) {
child->mouseReleaseEvent(event);
}
}
void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard)
{
if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != ZoneNames::TABLE) {
return;
}
// move card onto table first if attaching from some other zone
if (startCard->getZone()->getName() != ZoneNames::TABLE) {
player->getPlayerActions()->playCardToTable(startCard, false);
}
Command_AttachCard cmd;
cmd.set_start_zone(ZoneNames::TABLE);
cmd.set_card_id(startCard->getId());
cmd.set_target_player_id(targetCard->getZone()->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(targetCard->getZone()->getName().toStdString());
cmd.set_target_card_id(targetCard->getId());
player->getPlayerActions()->sendGameCommand(cmd);
}

View file

@ -1,40 +1,47 @@
/**
* @file arrow_item.h
* @ingroup GameGraphics
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef ARROWITEM_H
#define ARROWITEM_H
#include "arrow_target.h"
#include <QGraphicsItem>
#include <QPointer>
class CardItem;
class QGraphicsSceneMouseEvent;
class QMenu;
class Player;
class ArrowTarget;
class PlayerLogic;
class ArrowItem : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
signals:
void requestDeletion(int id);
private:
QPainterPath path;
QMenu *menu;
protected:
Player *player;
PlayerLogic *player;
int id;
ArrowTarget *startItem, *targetItem;
bool targetLocked;
QPointer<ArrowTarget> startItem;
QPointer<ArrowTarget> targetItem;
bool targetLocked = false;
QColor color;
bool fullColor;
bool fullColor = true;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
public:
ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &color);
~ArrowItem() override;
ArrowItem(PlayerLogic *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color);
void onTargetDestroyed();
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
[[nodiscard]] QRectF boundingRect() const override
{
@ -44,6 +51,7 @@ public:
{
return path;
}
void updatePath();
void updatePath(const QPointF &endPoint);
@ -51,18 +59,10 @@ public:
{
return id;
}
[[nodiscard]] Player *getPlayer() const
[[nodiscard]] PlayerLogic *getPlayer() const
{
return player;
}
void setStartItem(ArrowTarget *_item)
{
startItem = _item;
}
void setTargetItem(ArrowTarget *_item)
{
targetItem = _item;
}
[[nodiscard]] ArrowTarget *getStartItem() const
{
return startItem;
@ -75,6 +75,7 @@ public:
{
targetLocked = _targetLocked;
}
void delArrow();
};
@ -84,10 +85,11 @@ class ArrowDragItem : public ArrowItem
private:
int deleteInPhase;
QList<ArrowDragItem *> childArrows;
QMetaObject::Connection positionConnection;
public:
ArrowDragItem(Player *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase);
void addChildArrow(ArrowDragItem *childArrow);
ArrowDragItem(PlayerLogic *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase);
void addChildArrow(ArrowDragItem *child);
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
@ -99,12 +101,12 @@ class ArrowAttachItem : public ArrowItem
Q_OBJECT
private:
QList<ArrowAttachItem *> childArrows;
QMetaObject::Connection positionConnection;
void attachCards(CardItem *startCard, const CardItem *targetCard);
public:
explicit ArrowAttachItem(ArrowTarget *_startItem);
void addChildArrow(ArrowAttachItem *childArrow);
void addChildArrow(ArrowAttachItem *child);
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;

View file

@ -1,41 +1,23 @@
#include "arrow_target.h"
#include "../player/player.h"
#include "../player/player_logic.h"
#include "arrow_item.h"
ArrowTarget::ArrowTarget(Player *_owner, QGraphicsItem *parent)
: AbstractGraphicsItem(parent), owner(_owner), beingPointedAt(false)
ArrowTarget::ArrowTarget(PlayerLogic *_owner, QGraphicsItem *parent) : AbstractGraphicsItem(parent), owner(_owner)
{
setFlag(ItemSendsScenePositionChanges);
}
ArrowTarget::~ArrowTarget()
{
for (int i = 0; i < arrowsFrom.size(); ++i) {
arrowsFrom[i]->setStartItem(0);
arrowsFrom[i]->delArrow();
}
for (int i = 0; i < arrowsTo.size(); ++i) {
arrowsTo[i]->setTargetItem(0);
arrowsTo[i]->delArrow();
}
}
void ArrowTarget::setBeingPointedAt(bool _beingPointedAt)
{
beingPointedAt = _beingPointedAt;
update();
}
QVariant ArrowTarget::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
QVariant ArrowTarget::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemScenePositionHasChanged && scene()) {
for (auto *arrow : arrowsFrom)
arrow->updatePath();
for (auto *arrow : arrowsTo)
arrow->updatePath();
if (change == ItemScenePositionHasChanged) {
emit scenePositionChanged();
}
return QGraphicsItem::itemChange(change, value);
}
return AbstractGraphicsItem::itemChange(change, value);
}

View file

@ -1,8 +1,8 @@
/**
* @file arrow_target.h
* @ingroup GameGraphics
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef ARROWTARGET_H
#define ARROWTARGET_H
@ -11,24 +11,26 @@
#include <QList>
class Player;
class PlayerLogic;
class ArrowItem;
class ArrowTarget : public AbstractGraphicsItem
{
Q_OBJECT
protected:
Player *owner;
PlayerLogic *owner;
private:
bool beingPointedAt;
QList<ArrowItem *> arrowsFrom, arrowsTo;
bool beingPointedAt = false;
signals:
void scenePositionChanged();
public:
explicit ArrowTarget(Player *_owner, QGraphicsItem *parent = nullptr);
~ArrowTarget() override;
explicit ArrowTarget(PlayerLogic *_owner, QGraphicsItem *parent = nullptr);
~ArrowTarget() override = default;
[[nodiscard]] Player *getOwner() const
[[nodiscard]] PlayerLogic *getOwner() const
{
return owner;
}
@ -39,32 +41,7 @@ public:
return beingPointedAt;
}
[[nodiscard]] const QList<ArrowItem *> &getArrowsFrom() const
{
return arrowsFrom;
}
void addArrowFrom(ArrowItem *arrow)
{
arrowsFrom.append(arrow);
}
void removeArrowFrom(ArrowItem *arrow)
{
arrowsFrom.removeOne(arrow);
}
[[nodiscard]] const QList<ArrowItem *> &getArrowsTo() const
{
return arrowsTo;
}
void addArrowTo(ArrowItem *arrow)
{
arrowsTo.append(arrow);
}
void removeArrowTo(ArrowItem *arrow)
{
arrowsTo.removeOne(arrow);
}
protected:
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
};
#endif

View file

@ -1,9 +1,9 @@
#include "card_drag_item.h"
#include "../../game_graphics/zones/card_zone.h"
#include "../../game_graphics/zones/table_zone.h"
#include "../../game_graphics/zones/view_zone.h"
#include "../game_scene.h"
#include "../zones/card_zone.h"
#include "../zones/table_zone.h"
#include "../zones/view_zone.h"
#include "card_item.h"
#include <QCursor>
@ -24,8 +24,9 @@ void CardDragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
{
AbstractCardDragItem::paint(painter, option, widget);
if (occupied)
if (occupied) {
painter->fillPath(shape(), QColor(200, 0, 0, 100));
}
}
void CardDragItem::updatePosition(const QPointF &cursorScenePos)
@ -38,16 +39,19 @@ void CardDragItem::updatePosition(const QPointF &cursorScenePos)
ZoneViewZone *zoneViewZone = 0;
for (int i = colliding.size() - 1; i >= 0; i--) {
CardZone *temp = qgraphicsitem_cast<CardZone *>(colliding.at(i));
if (!cardZone)
if (!cardZone) {
cardZone = temp;
if (!zoneViewZone)
}
if (!zoneViewZone) {
zoneViewZone = qobject_cast<ZoneViewZone *>(temp);
}
}
CardZone *cursorZone = 0;
if (zoneViewZone)
if (zoneViewZone) {
cursorZone = zoneViewZone;
else if (cardZone)
} else if (cardZone) {
cursorZone = cardZone;
}
// Always update the current zone, even if its null, to cancel the drag
// instead of dropping cards into an non-intuitive location.
@ -59,8 +63,9 @@ void CardDragItem::updatePosition(const QPointF &cursorScenePos)
QPointF newPos = cursorScenePos - hotSpot;
if (newPos != pos()) {
for (int i = 0; i < childDrags.size(); i++)
for (int i = 0; i < childDrags.size(); i++) {
childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
}
setPos(newPos);
}
@ -78,23 +83,27 @@ void CardDragItem::updatePosition(const QPointF &cursorScenePos)
// position.
TableZone *tableZone = qobject_cast<TableZone *>(cursorZone);
QPointF closestGridPoint;
if (tableZone)
if (tableZone) {
closestGridPoint = tableZone->closestGridPoint(cursorPosInZone);
else
} else {
closestGridPoint = cursorPosInZone - hotSpot;
}
QPointF newPos = zonePos + closestGridPoint;
if (newPos != pos()) {
for (int i = 0; i < childDrags.size(); i++)
for (int i = 0; i < childDrags.size(); i++) {
childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
}
setPos(newPos);
bool newOccupied = false;
TableZone *table = qobject_cast<TableZone *>(cursorZone);
if (table)
if (table->getCardFromCoords(closestGridPoint))
if (table) {
if (table->getCardFromCoords(closestGridPoint)) {
newOccupied = true;
}
}
if (newOccupied != occupied) {
occupied = newOccupied;
update();

View file

@ -1,8 +1,8 @@
/**
* @file card_drag_item.h
* @ingroup GameGraphicsCards
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef CARDDRAGITEM_H
#define CARDDRAGITEM_H

View file

@ -1,14 +1,14 @@
#include "card_item.h"
#include "../../client/settings/cache_settings.h"
#include "../../game_graphics/zones/table_zone.h"
#include "../../game_graphics/zones/view_zone.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../game_scene.h"
#include "../phase.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "../zones/logic/view_zone_logic.h"
#include "../zones/table_zone.h"
#include "../zones/view_zone.h"
#include "../player/player_logic.h"
#include "../zones/view_zone_logic.h"
#include "arrow_item.h"
#include "card_drag_item.h"
@ -20,15 +20,19 @@
#include <libcockatrice/card/card_info.h>
#include <libcockatrice/protocol/pb/serverinfo_card.pb.h>
CardItem::CardItem(Player *_owner, QGraphicsItem *parent, const CardRef &cardRef, int _cardid, CardZoneLogic *_zone)
: AbstractCardItem(parent, cardRef, _owner, _cardid), zone(_zone), attacking(false), destroyOnZoneChange(false),
doesntUntap(false), dragItem(nullptr), attachedTo(nullptr)
CardItem::CardItem(PlayerLogic *_owner,
QGraphicsItem *parent,
const CardRef &cardRef,
int _cardid,
CardZoneLogic *_zone)
: AbstractCardItem(parent, cardRef, _owner, _cardid), state(new CardState(this, _zone)), dragItem(nullptr)
{
owner->addCard(this);
connect(&SettingsCache::instance().cardCounters(), &CardCounterSettings::colorChanged, this, [this](int counterId) {
if (counters.contains(counterId))
if (state->getCounters().contains(counterId)) {
update();
}
});
}
@ -47,23 +51,24 @@ void CardItem::prepareDelete()
attachedCards.first()->setAttachedTo(nullptr);
}
if (attachedTo != nullptr) {
attachedTo->removeAttachedCard(this);
attachedTo = nullptr;
if (state->getAttachedTo() != nullptr) {
state->getAttachedTo()->removeAttachedCard(this);
state->setAttachedTo(nullptr);
}
}
void CardItem::deleteLater()
{
prepareDelete();
if (scene())
if (scene()) {
static_cast<GameScene *>(scene())->unregisterAnimationItem(this);
}
AbstractCardItem::deleteLater();
}
void CardItem::setZone(CardZoneLogic *_zone)
{
zone = _zone;
state->setZone(_zone);
}
void CardItem::retranslateUi()
@ -78,23 +83,23 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
AbstractCardItem::paint(painter, option, widget);
int i = 0;
QMapIterator<int, int> counterIterator(counters);
QMapIterator<int, int> counterIterator(state->getCounters());
while (counterIterator.hasNext()) {
counterIterator.next();
QColor _color = cardCounterSettings.color(counterIterator.key());
paintNumberEllipse(counterIterator.value(), 14, _color, i, counters.size(), painter);
paintNumberEllipse(counterIterator.value(), 14, _color, i, state->getCounters().size(), painter);
++i;
}
QSizeF translatedSize = getTranslatedSize(painter);
qreal scaleFactor = translatedSize.width() / boundingRect().width();
if (!pt.isEmpty()) {
if (!state->getPT().isEmpty()) {
painter->save();
transformPainter(painter, translatedSize, tapAngle);
if (!getFaceDown() && pt == exactCard.getInfo().getPowTough()) {
if (!getFaceDown() && state->getPT() == exactCard.getInfo().getPowTough()) {
painter->setPen(Qt::white);
} else {
painter->setPen(QColor(255, 150, 0)); // dark orange
@ -105,11 +110,11 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->drawText(QRectF(4 * scaleFactor, 4 * scaleFactor, translatedSize.width() - 10 * scaleFactor,
translatedSize.height() - 8 * scaleFactor),
Qt::AlignRight | Qt::AlignBottom, pt);
Qt::AlignRight | Qt::AlignBottom, state->getPT());
painter->restore();
}
if (!annotation.isEmpty()) {
if (!state->getAnnotation().isEmpty()) {
painter->save();
transformPainter(painter, translatedSize, tapAngle);
@ -119,7 +124,7 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->drawText(QRectF(4 * scaleFactor, 4 * scaleFactor, translatedSize.width() - 8 * scaleFactor,
translatedSize.height() - 8 * scaleFactor),
Qt::AlignCenter | Qt::TextWrapAnywhere, annotation);
Qt::AlignCenter | Qt::TextWrapAnywhere, state->getAnnotation());
painter->restore();
}
@ -127,7 +132,7 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->fillPath(shape(), QBrush(QColor(255, 0, 0, 100)));
}
if (doesntUntap) {
if (state->getDoesntUntap()) {
painter->save();
painter->setRenderHint(QPainter::Antialiasing, false);
@ -146,69 +151,66 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
void CardItem::setAttacking(bool _attacking)
{
attacking = _attacking;
state->setAttacking(_attacking);
update();
}
void CardItem::setCounter(int _id, int _value)
{
if (_value)
counters.insert(_id, _value);
else
counters.remove(_id);
state->setCounter(_id, _value);
update();
}
void CardItem::setAnnotation(const QString &_annotation)
{
annotation = _annotation;
state->setAnnotation(_annotation);
update();
}
void CardItem::setDoesntUntap(bool _doesntUntap)
{
doesntUntap = _doesntUntap;
state->setDoesntUntap(_doesntUntap);
update();
}
void CardItem::setPT(const QString &_pt)
{
pt = _pt;
state->setPT(_pt);
update();
}
void CardItem::setAttachedTo(CardItem *_attachedTo)
{
if (attachedTo != nullptr) {
attachedTo->removeAttachedCard(this);
if (state->getAttachedTo() != nullptr) {
state->getAttachedTo()->removeAttachedCard(this);
}
gridPoint.setX(-1);
attachedTo = _attachedTo;
if (attachedTo != nullptr) {
state->setAttachedTo(_attachedTo);
if (state->getAttachedTo() != nullptr) {
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its
// attached cards
if (attachedTo->zone == nullptr) {
if (state->getAttachedTo()->getZone() == nullptr) {
deleteLater();
} else {
emit attachedTo->zone->cardAdded(this);
attachedTo->addAttachedCard(this);
if (zone != attachedTo->getZone()) {
attachedTo->getZone()->reorganizeCards();
emit state->getAttachedTo()->getZone()->cardAdded(this);
state->getAttachedTo()->addAttachedCard(this);
if (state->getZone() != state->getAttachedTo()->getZone()) {
state->getAttachedTo()->getZone()->reorganizeCards();
}
}
} else {
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its
// attached cards
if (zone == nullptr) {
if (state->getZone() == nullptr) {
deleteLater();
} else {
emit zone->cardAdded(this);
emit state->getZone()->cardAdded(this);
}
}
if (zone != nullptr) {
zone->reorganizeCards();
if (state->getZone() != nullptr) {
state->getZone()->reorganizeCards();
}
}
@ -217,28 +219,23 @@ void CardItem::setAttachedTo(CardItem *_attachedTo)
*/
void CardItem::resetState(bool keepAnnotations)
{
attacking = false;
counters.clear();
pt.clear();
if (!keepAnnotations) {
annotation.clear();
}
attachedTo = 0;
state->resetState(keepAnnotations);
attachedCards.clear();
setTapped(false, false);
setDoesntUntap(false);
if (scene())
if (scene()) {
static_cast<GameScene *>(scene())->unregisterAnimationItem(this);
}
update();
}
void CardItem::processCardInfo(const ServerInfo_Card &_info)
{
counters.clear();
state->clearCounters();
const int counterListSize = _info.counter_list_size();
for (int i = 0; i < counterListSize; ++i) {
const ServerInfo_CardCounter &counterInfo = _info.counter_list(i);
counters.insert(counterInfo.id(), counterInfo.value());
state->insertCounter(counterInfo.id(), counterInfo.value());
}
setId(_info.id());
@ -275,11 +272,12 @@ void CardItem::deleteDragItem()
void CardItem::drawArrow(const QColor &arrowColor)
{
if (owner->getGame()->getPlayerManager()->isSpectator())
if (owner->getGame()->getPlayerManager()->isSpectator()) {
return;
}
auto *game = owner->getGame();
Player *arrowOwner = game->getPlayerManager()->getActiveLocalPlayer(game->getGameState()->getActivePlayer());
PlayerLogic *arrowOwner = game->getPlayerManager()->getActiveLocalPlayer(game->getGameState()->getActivePlayer());
int phase = 0; // 0 means to not set the phase
if (SettingsCache::instance().getDoNotDeleteArrowsInSubPhases()) {
int currentPhase = game->getGameState()->getCurrentPhase();
@ -291,10 +289,12 @@ void CardItem::drawArrow(const QColor &arrowColor)
for (const auto &item : scene()->selectedItems()) {
CardItem *card = qgraphicsitem_cast<CardItem *>(item);
if (card == nullptr || card == this)
if (card == nullptr || card == this) {
continue;
if (card->getZone() != zone)
}
if (card->getZone() != state->getZone()) {
continue;
}
ArrowDragItem *childArrow = new ArrowDragItem(arrowOwner, card, arrowColor, phase);
scene()->addItem(childArrow);
@ -304,8 +304,9 @@ void CardItem::drawArrow(const QColor &arrowColor)
void CardItem::drawAttachArrow()
{
if (owner->getGame()->getPlayerManager()->isSpectator())
if (owner->getGame()->getPlayerManager()->isSpectator()) {
return;
}
auto *arrow = new ArrowAttachItem(this);
scene()->addItem(arrow);
@ -313,10 +314,12 @@ void CardItem::drawAttachArrow()
for (const auto &item : scene()->selectedItems()) {
CardItem *card = qgraphicsitem_cast<CardItem *>(item);
if (card == nullptr)
if (card == nullptr) {
continue;
if (card->getZone() != zone)
}
if (card->getZone() != state->getZone()) {
continue;
}
ArrowAttachItem *childArrow = new ArrowAttachItem(card);
scene()->addItem(childArrow);
@ -328,27 +331,32 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (event->buttons().testFlag(Qt::RightButton)) {
if ((event->screenPos() - event->buttonDownScreenPos(Qt::RightButton)).manhattanLength() <
2 * QApplication::startDragDistance())
2 * QApplication::startDragDistance()) {
return;
}
QColor arrowColor = Qt::red;
if (event->modifiers().testFlag(Qt::ControlModifier))
if (event->modifiers().testFlag(Qt::ControlModifier)) {
arrowColor = Qt::yellow;
else if (event->modifiers().testFlag(Qt::AltModifier))
} else if (event->modifiers().testFlag(Qt::AltModifier)) {
arrowColor = Qt::blue;
else if (event->modifiers().testFlag(Qt::ShiftModifier))
} else if (event->modifiers().testFlag(Qt::ShiftModifier)) {
arrowColor = Qt::green;
}
drawArrow(arrowColor);
} else if (event->buttons().testFlag(Qt::LeftButton)) {
if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() <
2 * QApplication::startDragDistance())
2 * QApplication::startDragDistance()) {
return;
if (const ZoneViewZoneLogic *view = qobject_cast<const ZoneViewZoneLogic *>(zone)) {
if (view->getRevealZone() && !view->getWriteableRevealZone())
}
if (const ZoneViewZoneLogic *view = qobject_cast<const ZoneViewZoneLogic *>(state->getZone())) {
if (view->getRevealZone() && !view->getWriteableRevealZone()) {
return;
} else if (!owner->getPlayerInfo()->getLocalOrJudge())
}
} else if (!owner->getPlayerInfo()->getLocalOrJudge()) {
return;
}
bool forceFaceDown = event->modifiers().testFlag(Qt::ShiftModifier);
@ -360,14 +368,16 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
int childIndex = 0;
for (const auto &item : scene()->selectedItems()) {
CardItem *card = static_cast<CardItem *>(item);
if ((card == this) || (card->getZone() != zone))
if ((card == this) || (card->getZone() != state->getZone())) {
continue;
}
++childIndex;
QPointF childPos;
if (zone->getHasCardAttr())
if (state->getZone()->getHasCardAttr()) {
childPos = card->pos() - pos();
else
} else {
childPos = QPointF(childIndex * CardDimensions::WIDTH_HALF_F, 0);
}
CardDragItem *drag =
new CardDragItem(card, card->getId(), childPos, card->getFaceDown() || forceFaceDown, dragItem);
drag->setPos(dragItem->pos() + childPos);
@ -380,18 +390,19 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void CardItem::playCard(bool faceDown)
{
// Do nothing if the card belongs to another player
if (!owner->getPlayerInfo()->getLocalOrJudge())
if (!owner->getPlayerInfo()->getLocalOrJudge()) {
return;
}
TableZoneLogic *tz = qobject_cast<TableZoneLogic *>(zone);
if (tz)
TableZoneLogic *tz = qobject_cast<TableZoneLogic *>(state->getZone());
if (tz) {
emit tz->toggleTapped();
else {
} else {
if (SettingsCache::instance().getClickPlaysAllSelected()) {
faceDown ? zone->getPlayer()->getPlayerActions()->actPlayFacedown()
: zone->getPlayer()->getPlayerActions()->actPlay();
faceDown ? state->getZone()->getPlayer()->getPlayerActions()->actPlayFacedown()
: state->getZone()->getPlayer()->getPlayerActions()->actPlay();
} else {
zone->getPlayer()->getPlayerActions()->playCard(this, faceDown);
state->getZone()->getPlayer()->getPlayerActions()->playCard(this, faceDown);
}
}
}
@ -447,11 +458,11 @@ static bool isUnwritableRevealZone(CardZoneLogic *zone)
*/
void CardItem::handleClickedToPlay(bool shiftHeld)
{
if (isUnwritableRevealZone(zone)) {
if (isUnwritableRevealZone(state->getZone())) {
if (SettingsCache::instance().getClickPlaysAllSelected()) {
zone->getPlayer()->getPlayerActions()->actHide();
state->getZone()->getPlayer()->getPlayerActions()->actHide();
} else {
zone->removeCard(this);
state->getZone()->removeCard(this);
}
} else {
playCard(shiftHeld);
@ -493,8 +504,9 @@ bool CardItem::animationEvent()
{
int rotation = ROTATION_DEGREES_PER_FRAME;
bool animationIncomplete = true;
if (!tapped)
if (!tapped) {
rotation *= -1;
}
tapAngle += rotation;
if (tapped && (tapAngle > 90)) {

View file

@ -1,42 +1,37 @@
/**
* @file card_item.h
* @ingroup GameGraphicsCards
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef CARDITEM_H
#define CARDITEM_H
#include "../zones/logic/card_zone_logic.h"
#include "../zones/card_zone_logic.h"
#include "abstract_card_item.h"
#include "card_state.h"
#include <libcockatrice/network/server/remote/game/server_card.h>
#include <libcockatrice/utility/trice_limits.h>
class CardDatabase;
class CardDragItem;
class CardZone;
class ServerInfo_Card;
class Player;
class PlayerLogic;
class QAction;
class QColor;
const int MAX_COUNTERS_ON_CARD = 999;
const int ROTATION_DEGREES_PER_FRAME = 10;
class CardItem : public AbstractCardItem
{
Q_OBJECT
private:
CardZoneLogic *zone;
bool attacking;
QMap<int, int> counters;
QString annotation;
QString pt;
bool destroyOnZoneChange;
bool doesntUntap;
CardState *state;
QPoint gridPoint;
CardDragItem *dragItem;
CardItem *attachedTo;
QList<CardItem *> attachedCards;
void prepareDelete();
@ -53,16 +48,20 @@ public:
{
return Type;
}
explicit CardItem(Player *_owner,
explicit CardItem(PlayerLogic *_owner,
QGraphicsItem *parent = nullptr,
const CardRef &cardRef = {},
int _cardid = -1,
CardZoneLogic *_zone = nullptr);
void retranslateUi();
[[nodiscard]] CardState *getState() const
{
return state;
}
[[nodiscard]] CardZoneLogic *getZone() const
{
return zone;
return state->getZone();
}
void setZone(CardZoneLogic *_zone);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
@ -78,50 +77,50 @@ public:
{
return gridPoint;
}
[[nodiscard]] Player *getOwner() const
[[nodiscard]] PlayerLogic *getOwner() const
{
return owner;
}
void setOwner(Player *_owner)
void setOwner(PlayerLogic *_owner)
{
owner = _owner;
}
[[nodiscard]] bool getAttacking() const
{
return attacking;
return state->getAttacking();
}
void setAttacking(bool _attacking);
[[nodiscard]] const QMap<int, int> &getCounters() const
{
return counters;
return state->getCounters();
}
void setCounter(int _id, int _value);
[[nodiscard]] QString getAnnotation() const
{
return annotation;
return state->getAnnotation();
}
void setAnnotation(const QString &_annotation);
[[nodiscard]] bool getDoesntUntap() const
{
return doesntUntap;
return state->getDoesntUntap();
}
void setDoesntUntap(bool _doesntUntap);
[[nodiscard]] QString getPT() const
{
return pt;
return state->getPT();
}
void setPT(const QString &_pt);
[[nodiscard]] bool getDestroyOnZoneChange() const
{
return destroyOnZoneChange;
return state->getDestroyOnZoneChange();
}
void setDestroyOnZoneChange(bool _destroy)
{
destroyOnZoneChange = _destroy;
state->setDestroyOnZoneChange(_destroy);
}
[[nodiscard]] CardItem *getAttachedTo() const
{
return attachedTo;
return state->getAttachedTo();
}
void setAttachedTo(CardItem *_attachedTo);
void addAttachedCard(CardItem *card)

View file

@ -1,8 +1,8 @@
/**
* @file card_list.h
* @ingroup GameLogicCards
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef CARDLIST_H
#define CARDLIST_H

View file

@ -0,0 +1,111 @@
#include "card_state.h"
void CardState::resetState(bool keepAnnotations)
{
attacking = false;
counters.clear();
pt.clear();
if (!keepAnnotations) {
annotation.clear();
}
attachedTo = nullptr;
}
void CardState::setZone(CardZoneLogic *_zone)
{
if (zone == _zone) {
return;
}
zone = _zone;
emit zoneChanged(this, zone);
emit stateChanged();
}
void CardState::setAttacking(bool _attacking)
{
if (attacking == _attacking) {
return;
}
attacking = _attacking;
emit attackingChanged(_attacking);
emit stateChanged();
}
void CardState::insertCounter(int id, int value)
{
counters.insert(id, value);
emit countersChanged(counters);
emit stateChanged();
}
void CardState::setCounter(int id, int value)
{
if (value) {
counters[id] = value;
} else {
counters.remove(id);
}
emit countersChanged(counters);
emit stateChanged();
}
void CardState::clearCounters()
{
counters.clear();
emit countersChanged(counters);
emit stateChanged();
}
void CardState::setAnnotation(const QString &_annotation)
{
if (annotation == _annotation) {
return;
}
annotation = _annotation;
emit annotationChanged(annotation);
emit stateChanged();
}
void CardState::setPT(const QString &_pt)
{
if (pt == _pt) {
return;
}
pt = _pt;
emit ptChanged(pt);
emit stateChanged();
}
void CardState::setDoesntUntap(bool _doesntUntap)
{
if (doesntUntap == _doesntUntap) {
return;
}
doesntUntap = _doesntUntap;
emit doesntUntapChanged(_doesntUntap);
emit stateChanged();
}
void CardState::setDestroyOnZoneChange(bool _destroyOnZoneChange)
{
if (destroyOnZoneChange == _destroyOnZoneChange) {
return;
}
destroyOnZoneChange = _destroyOnZoneChange;
emit destroyOnZoneChangeChanged(_destroyOnZoneChange);
emit stateChanged();
}
void CardState::setAttachedTo(CardItem *_attachedTo)
{
if (attachedTo == _attachedTo) {
return;
}
attachedTo = _attachedTo;
emit attachedToChanged(_attachedTo);
emit stateChanged();
}

View file

@ -0,0 +1,103 @@
#ifndef COCKATRICE_CARD_STATE_H
#define COCKATRICE_CARD_STATE_H
#include <QMap>
#include <QObject>
class CardZoneLogic;
class CardItem;
class CardState : public QObject
{
Q_OBJECT
private:
bool attacking = false;
QMap<int, int> counters;
QString annotation;
QString pt;
bool doesntUntap = false;
bool destroyOnZoneChange = false;
CardItem *attachedTo = nullptr;
CardZoneLogic *zone = nullptr;
signals:
void stateChanged();
void attackingChanged(bool newValue);
void countersChanged(const QMap<int, int> &newCounters);
void annotationChanged(const QString &newAnnotation);
void ptChanged(const QString &newPt);
void doesntUntapChanged(bool newValue);
void destroyOnZoneChangeChanged(bool newValue);
void attachedToChanged(CardItem *newAttachedTo);
void zoneChanged(CardState *changedCard, CardZoneLogic *newZone);
public:
explicit CardState(QObject *parent, CardZoneLogic *_zone) : QObject(parent), zone(_zone)
{
}
void resetState(bool keepAnnotations);
CardZoneLogic *getZone() const
{
return zone;
}
void setZone(CardZoneLogic *_zone);
bool getAttacking() const
{
return attacking;
}
void setAttacking(bool _attacking);
const QMap<int, int> &getCounters() const
{
return counters;
}
void insertCounter(int id, int value);
void setCounter(int id, int value);
void clearCounters();
QString getAnnotation() const
{
return annotation;
}
void setAnnotation(const QString &_annotation);
QString getPT() const
{
return pt;
}
void setPT(const QString &_pt);
bool getDoesntUntap() const
{
return doesntUntap;
}
void setDoesntUntap(bool _doesntUntap);
bool getDestroyOnZoneChange() const
{
return destroyOnZoneChange;
}
void setDestroyOnZoneChange(bool _destroyOnZoneChange);
CardItem *getAttachedTo() const
{
return attachedTo;
}
void setAttachedTo(CardItem *_attachedTo);
};
#endif // COCKATRICE_CARD_STATE_H

View file

@ -5,15 +5,8 @@
#include <QPainter>
GeneralCounter::GeneralCounter(Player *_player,
int _id,
const QString &_name,
const QColor &_color,
int _radius,
int _value,
bool useNameForShortcut,
QGraphicsItem *parent)
: AbstractCounter(_player, _id, _name, true, _value, useNameForShortcut, parent), color(_color), radius(_radius)
GeneralCounter::GeneralCounter(CounterState *state, PlayerLogic *player, bool useNameForShortcut, QGraphicsItem *parent)
: AbstractCounter(state, player, true, useNameForShortcut, parent)
{
setCacheMode(DeviceCoordinateCache);
}

View file

@ -1,8 +1,8 @@
/**
* @file counter_general.h
* @ingroup GameGraphicsPlayers
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COUNTER_GENERAL_H
#define COUNTER_GENERAL_H
@ -12,17 +12,10 @@
class GeneralCounter : public AbstractCounter
{
Q_OBJECT
private:
QColor color;
int radius;
public:
GeneralCounter(Player *_player,
int _id,
const QString &_name,
const QColor &_color,
int _radius,
int _value,
GeneralCounter(CounterState *state,
PlayerLogic *player,
bool useNameForShortcut = false,
QGraphicsItem *parent = nullptr);
QRectF boundingRect() const override;

View file

@ -0,0 +1,24 @@
#include "counter_state.h"
#include <libcockatrice/utility/color.h>
CounterState::CounterState(int id, const QString &name, const QColor &color, int radius, int value, QObject *parent)
: QObject(parent), id(id), name(name), color(color), radius(radius), value(value)
{
}
CounterState *CounterState::fromProto(const ServerInfo_Counter &counter, QObject *parent)
{
return new CounterState(counter.id(), QString::fromStdString(counter.name()),
convertColorToQColor(counter.counter_color()), counter.radius(), counter.count(), parent);
}
void CounterState::setValue(int newValue)
{
if (newValue == value) {
return;
}
int old = value;
value = newValue;
emit valueChanged(old, newValue);
}

View file

@ -0,0 +1,51 @@
#ifndef COCKATRICE_COUNTER_STATE_H
#define COCKATRICE_COUNTER_STATE_H
#include <QColor>
#include <QObject>
#include <QString>
#include <libcockatrice/protocol/pb/serverinfo_counter.pb.h>
class CounterState : public QObject
{
Q_OBJECT
public:
CounterState(int id, const QString &name, const QColor &color, int radius, int value, QObject *parent = nullptr);
static CounterState *fromProto(const ServerInfo_Counter &counter, QObject *parent = nullptr);
int getId() const
{
return id;
}
QString getName() const
{
return name;
}
QColor getColor() const
{
return color;
}
int getRadius() const
{
return radius;
}
int getValue() const
{
return value;
}
void setValue(int newValue);
signals:
void valueChanged(int oldValue, int newValue);
private:
int id;
QString name;
QColor color;
int radius;
int value;
};
#endif // COCKATRICE_COUNTER_STATE_H

View file

@ -1,8 +1,8 @@
/**
* @file translate_counter_name.h
* @ingroup GameGraphicsPlayers
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef TRANSLATECOUNTERNAME_H
#define TRANSLATECOUNTERNAME_H

View file

@ -12,16 +12,16 @@
*/
namespace CardDimensions
{
/// Card width in pixels
/** @brief Card width in pixels. */
constexpr int WIDTH = 72;
/// Card height in pixels
/** @brief Card height in pixels. */
constexpr int HEIGHT = 102;
/// Pre-converted for floating-point contexts (Z-value calculations)
/** @brief Pre-converted for floating-point contexts (Z-value calculations). */
constexpr qreal WIDTH_F = static_cast<qreal>(WIDTH);
constexpr qreal HEIGHT_F = static_cast<qreal>(HEIGHT);
/// Half-dimensions for centering and rotation transforms
/** @brief Half-dimensions for centering and rotation transforms. */
constexpr qreal WIDTH_HALF_F = WIDTH_F / 2;
constexpr qreal HEIGHT_HALF_F = HEIGHT_F / 2;
} // namespace CardDimensions

View file

@ -24,17 +24,21 @@ void DeckViewCardDragItem::updatePosition(const QPointF &cursorScenePos)
QList<QGraphicsItem *> colliding = scene()->items(cursorScenePos);
DeckViewCardContainer *cursorZone = 0;
for (int i = colliding.size() - 1; i >= 0; i--)
if ((cursorZone = qgraphicsitem_cast<DeckViewCardContainer *>(colliding.at(i))))
for (int i = colliding.size() - 1; i >= 0; i--) {
if ((cursorZone = qgraphicsitem_cast<DeckViewCardContainer *>(colliding.at(i)))) {
break;
if (!cursorZone)
}
}
if (!cursorZone) {
return;
}
currentZone = cursorZone;
QPointF newPos = cursorScenePos;
if (newPos != pos()) {
for (int i = 0; i < childDrags.size(); i++)
for (int i = 0; i < childDrags.size(); i++) {
childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
}
setPos(newPos);
}
}
@ -104,11 +108,13 @@ void DeckViewCard::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() <
2 * QApplication::startDragDistance())
2 * QApplication::startDragDistance()) {
return;
}
if (static_cast<DeckViewScene *>(scene())->getLocked())
if (static_cast<DeckViewScene *>(scene())->getLocked()) {
return;
}
delete dragItem;
dragItem = new DeckViewCardDragItem(this, event->pos());
@ -120,8 +126,9 @@ void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
int j = 0;
for (int i = 0; i < sel.size(); i++) {
auto *c = static_cast<DeckViewCard *>(sel.at(i));
if (c == this)
if (c == this) {
continue;
}
++j;
auto childPos = QPointF(j * CardDimensions::WIDTH_HALF_F, 0);
auto *drag = new DeckViewCardDragItem(c, childPos, dragItem);
@ -133,8 +140,9 @@ void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void DeckView::mouseDoubleClickEvent(QMouseEvent *event)
{
if (static_cast<DeckViewScene *>(scene())->getLocked())
if (static_cast<DeckViewScene *>(scene())->getLocked()) {
return;
}
if (event->button() == Qt::LeftButton) {
QList<MoveCard_ToZone> result;
@ -147,12 +155,13 @@ void DeckView::mouseDoubleClickEvent(QMouseEvent *event)
m.set_card_name(c->getName().toStdString());
m.set_start_zone(zone->getName().toStdString());
if (zone->getName() == DECK_ZONE_MAIN)
if (zone->getName() == DECK_ZONE_MAIN) {
m.set_target_zone(DECK_ZONE_SIDE);
else if (zone->getName() == DECK_ZONE_SIDE)
} else if (zone->getName() == DECK_ZONE_SIDE) {
m.set_target_zone(DECK_ZONE_MAIN);
else // Trying to move from another zone
} else { // Trying to move from another zone
m.set_target_zone(zone->getName().toStdString());
}
result.append(m);
}
@ -232,8 +241,9 @@ QList<QPair<int, int>> DeckViewCardContainer::getRowsAndCols() const
{
QList<QPair<int, int>> result;
QList<QString> cardTypeList = cardsByType.uniqueKeys();
for (int i = 0; i < cardTypeList.size(); ++i)
for (int i = 0; i < cardTypeList.size(); ++i) {
result.append(QPair<int, int>(1, cardsByType.count(cardTypeList[i])));
}
return result;
}
@ -262,8 +272,9 @@ QSizeF DeckViewCardContainer::calculateBoundingRect(const QList<QPair<int, int>>
// Calculate space needed for cards
for (int i = 0; i < rowsAndCols.size(); ++i) {
totalHeight += CardDimensions::HEIGHT_F * rowsAndCols[i].first + paddingY;
if (CardDimensions::WIDTH_F * rowsAndCols[i].second > totalWidth)
if (CardDimensions::WIDTH_F * rowsAndCols[i].second > totalWidth) {
totalWidth = CardDimensions::WIDTH_F * rowsAndCols[i].second;
}
}
return QSizeF(getCardTypeTextWidth() + totalWidth, totalHeight + separatorY + paddingY);
@ -271,8 +282,9 @@ QSizeF DeckViewCardContainer::calculateBoundingRect(const QList<QPair<int, int>>
bool DeckViewCardContainer::sortCardsByName(DeckViewCard *c1, DeckViewCard *c2)
{
if (c1 && c2)
if (c1 && c2) {
return c1->getName() < c2->getName();
}
return false;
}
@ -322,15 +334,17 @@ DeckViewScene::~DeckViewScene()
void DeckViewScene::clearContents()
{
QMapIterator<QString, DeckViewCardContainer *> i(cardContainers);
while (i.hasNext())
while (i.hasNext()) {
delete i.next().value();
}
cardContainers.clear();
}
void DeckViewScene::setDeck(const DeckList &_deck)
{
if (deck)
if (deck) {
delete deck;
}
deck = new DeckList(_deck.writeToString_Native());
rebuildTree();
@ -342,8 +356,9 @@ void DeckViewScene::rebuildTree()
{
clearContents();
if (!deck)
if (!deck) {
return;
}
for (auto *currentZone : deck->getZoneNodes()) {
DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0);
@ -355,8 +370,9 @@ void DeckViewScene::rebuildTree()
for (int j = 0; j < currentZone->size(); j++) {
auto *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
if (!currentCard)
if (!currentCard) {
continue;
}
for (int k = 0; k < currentCard->getNumber(); ++k) {
auto *newCard = new DeckViewCard(container, currentCard->toCardRef(), currentZone->getName());
@ -373,18 +389,21 @@ void DeckViewScene::applySideboardPlan(const QList<MoveCard_ToZone> &plan)
const MoveCard_ToZone &m = plan[i];
DeckViewCardContainer *start = cardContainers.value(QString::fromStdString(m.start_zone()));
DeckViewCardContainer *target = cardContainers.value(QString::fromStdString(m.target_zone()));
if (!start || !target)
if (!start || !target) {
continue;
}
DeckViewCard *card = 0;
const QList<DeckViewCard *> &cardList = start->getCards();
for (int j = 0; j < cardList.size(); ++j)
for (int j = 0; j < cardList.size(); ++j) {
if (cardList[j]->getName() == QString::fromStdString(m.card_name())) {
card = cardList[j];
break;
}
if (!card)
}
if (!card) {
continue;
}
start->removeCard(card);
target->addCard(card);
@ -405,8 +424,9 @@ void DeckViewScene::rearrangeItems()
rowsAndColsList.append(rowsAndCols);
cardCountList.append(QList<int>());
for (int j = 0; j < rowsAndCols.size(); ++j)
for (int j = 0; j < rowsAndCols.size(); ++j) {
cardCountList[i].append(rowsAndCols[j].second);
}
}
qreal totalHeight, totalWidth;
@ -417,23 +437,27 @@ void DeckViewScene::rearrangeItems()
for (int i = 0; i < contList.size(); ++i) {
QSizeF contSize = contList[i]->calculateBoundingRect(rowsAndColsList[i]);
totalHeight += contSize.height() + spacing;
if (contSize.width() > totalWidth)
if (contSize.width() > totalWidth) {
totalWidth = contSize.width();
}
}
// We're done when the aspect ratio shifts from too high to too low.
if (totalWidth / totalHeight <= optimalAspectRatio)
if (totalWidth / totalHeight <= optimalAspectRatio) {
break;
}
// Find category with highest column count
int maxIndex1 = -1, maxIndex2 = -1, maxCols = 0;
for (int i = 0; i < rowsAndColsList.size(); ++i)
for (int j = 0; j < rowsAndColsList[i].size(); ++j)
for (int i = 0; i < rowsAndColsList.size(); ++i) {
for (int j = 0; j < rowsAndColsList[i].size(); ++j) {
if (rowsAndColsList[i][j].second > maxCols) {
maxIndex1 = i;
maxIndex2 = j;
maxCols = rowsAndColsList[i][j].second;
}
}
}
// Add row to category
const int maxRows = rowsAndColsList[maxIndex1][maxIndex2].first;
@ -451,8 +475,9 @@ void DeckViewScene::rearrangeItems()
}
totalWidth = totalHeight * optimalAspectRatio;
for (int i = 0; i < contList.size(); ++i)
for (int i = 0; i < contList.size(); ++i) {
contList[i]->setWidth(totalWidth);
}
setSceneRect(QRectF(0, 0, totalWidth, totalHeight));
}
@ -470,7 +495,7 @@ QList<MoveCard_ToZone> DeckViewScene::getSideboardPlan() const
while (containerIterator.hasNext()) {
DeckViewCardContainer *cont = containerIterator.next().value();
const QList<DeckViewCard *> cardList = cont->getCards();
for (int i = 0; i < cardList.size(); ++i)
for (int i = 0; i < cardList.size(); ++i) {
if (cardList[i]->getOriginZone() != cont->getName()) {
MoveCard_ToZone m;
m.set_card_name(cardList[i]->getName().toStdString());
@ -478,6 +503,7 @@ QList<MoveCard_ToZone> DeckViewScene::getSideboardPlan() const
m.set_target_zone(cont->getName().toStdString());
result.append(m);
}
}
}
return result;
}

View file

@ -1,8 +1,8 @@
/**
* @file deck_view.h
* @ingroup Lobby
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DECKVIEW_H
#define DECKVIEW_H

View file

@ -251,8 +251,9 @@ void DeckViewContainer::unloadDeck()
void DeckViewContainer::loadLocalDeck()
{
DlgLoadDeck dialog(this);
if (!dialog.exec())
if (!dialog.exec()) {
return;
}
loadDeckFromFile(dialog.selectedFiles().at(0));
}
@ -364,8 +365,9 @@ void DeckViewContainer::sideboardPlanChanged()
{
Command_SetSideboardPlan cmd;
const QList<MoveCard_ToZone> &newPlan = deckView->getSideboardPlan();
for (const auto &i : newPlan)
for (const auto &i : newPlan) {
cmd.add_move_list()->CopyFrom(i);
}
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
}
@ -404,8 +406,9 @@ void DeckViewContainer::setSideboardLocked(bool locked)
{
sideboardLockButton->setState(!locked);
deckView->setLocked(readyStartButton->getState() || !sideboardLockButton->getState());
if (locked)
if (locked) {
deckView->resetSideboardPlan();
}
}
void DeckViewContainer::setDeck(const DeckList &deck)

View file

@ -1,8 +1,8 @@
/**
* @file deck_view_container.h
* @ingroup Lobby
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DECK_VIEW_CONTAINER_H
#define DECK_VIEW_CONTAINER_H

View file

@ -1,8 +1,8 @@
/**
* @file tabbed_deck_view_container.h
* @ingroup Lobby
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef TABBED_DECK_VIEW_CONTAINER_H
#define TABBED_DECK_VIEW_CONTAINER_H

View file

@ -101,8 +101,9 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
chooseTokenView->resizeColumnToContents(0);
chooseTokenView->setWordWrap(true);
if (!deckHeaderState.isNull())
if (!deckHeaderState.isNull()) {
chooseTokenView->header()->restoreState(deckHeaderState);
}
chooseTokenView->header()->setStretchLastSection(false);
chooseTokenView->header()->hideSection(1); // Sets
@ -185,8 +186,9 @@ void DlgCreateToken::tokenSelectionChanged(const QModelIndex &current, const QMo
const QChar cardColor = cardInfo->getColorChar();
colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString));
ptEdit->setText(cardInfo->getPowTough());
if (SettingsCache::instance().getAnnotateTokens())
if (SettingsCache::instance().getAnnotateTokens()) {
annotationEdit->setText(cardInfo->getText());
}
} else {
nameEdit->setText("");
colorEdit->setCurrentIndex(colorEdit->findData(QString(), Qt::UserRole, Qt::MatchFixedString));

View file

@ -1,8 +1,8 @@
/**
* @file dlg_create_token.h
* @ingroup GameDialogs
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DLG_CREATETOKEN_H
#define DLG_CREATETOKEN_H

View file

@ -1,8 +1,8 @@
/**
* @file dlg_move_top_cards_until.h
* @ingroup GameDialogs
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DLG_MOVE_TOP_CARDS_UNTIL_H
#define DLG_MOVE_TOP_CARDS_UNTIL_H

View file

@ -1,8 +1,8 @@
/**
* @file dlg_roll_dice.h
* @ingroup GameDialogs
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DLG_ROLL_DICE_H
#define DLG_ROLL_DICE_H

View file

@ -1,8 +1,8 @@
/**
* @file game.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_GAME_H
#define COCKATRICE_GAME_H

View file

@ -36,8 +36,9 @@ GameEventHandler::GameEventHandler(AbstractGame *_game) : QObject(_game), game(_
void GameEventHandler::sendGameCommand(PendingCommand *pend, int playerId)
{
AbstractClient *client = game->getClientForPlayer(playerId);
if (!client)
if (!client) {
return;
}
connect(pend, &PendingCommand::finished, this, &GameEventHandler::commandFinished);
client->sendCommand(pend);
@ -46,8 +47,9 @@ void GameEventHandler::sendGameCommand(PendingCommand *pend, int playerId)
void GameEventHandler::sendGameCommand(const google::protobuf::Message &command, int playerId)
{
AbstractClient *client = game->getClientForPlayer(playerId);
if (!client)
if (!client) {
return;
}
PendingCommand *pend = prepareGameCommand(command);
connect(pend, &PendingCommand::finished, this, &GameEventHandler::commandFinished);
@ -56,8 +58,9 @@ void GameEventHandler::sendGameCommand(const google::protobuf::Message &command,
void GameEventHandler::commandFinished(const Response &response)
{
if (response.response_code() == Response::RespChatFlood)
if (response.response_code() == Response::RespChatFlood) {
emit gameFlooded();
}
}
PendingCommand *GameEventHandler::prepareGameCommand(const ::google::protobuf::Message &cmd)
@ -96,7 +99,7 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
if (cont.has_forced_by_judge()) {
auto id = cont.forced_by_judge();
Player *judgep = game->getPlayerManager()->getPlayers().value(id, nullptr);
PlayerLogic *judgep = game->getPlayerManager()->getPlayers().value(id, nullptr);
if (judgep) {
emit setContextJudgeName(judgep->getPlayerInfo()->getName());
} else if (game->getPlayerManager()->getSpectators().contains(id)) {
@ -117,9 +120,11 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
break;
}
} else {
if ((game->getGameState()->getClients().size() > 1) && (playerId != -1))
if (game->getGameState()->getClients().at(playerId) != client)
if ((game->getGameState()->getClients().size() > 1) && (playerId != -1)) {
if (game->getGameState()->getClients().at(playerId) != client) {
continue;
}
}
switch (eventType) {
case GameEvent::GAME_STATE_CHANGED:
@ -155,7 +160,7 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
break;
default: {
Player *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
if (!player) {
qCWarning(GameEventHandlerLog) << "unhandled game event: invalid player id";
break;
@ -212,7 +217,20 @@ void GameEventHandler::handleArrowDeletion(int arrowId)
{
Command_DeleteArrow cmd;
cmd.set_arrow_id(arrowId);
sendGameCommand(cmd);
auto preparedCommand = prepareGameCommand(cmd);
connect(preparedCommand, &PendingCommand::finished, this,
[arrowId, this](const Response &response) { handleArrowDeletionFinished(response, arrowId); });
sendGameCommand(preparedCommand);
}
void GameEventHandler::handleArrowDeletionFinished(const Response &response, int arrowId)
{
if (response.response_code() == Response::RespNameNotFound) {
emit arrowDeleted(arrowId);
}
}
void GameEventHandler::eventSpectatorSay(const Event_GameSay &event,
@ -256,7 +274,7 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event
emit spectatorJoined(prop);
}
} else {
Player *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
if (!player) {
player = game->getPlayerManager()->addPlayer(playerId, prop.user_info());
emit playerJoined(prop);
@ -284,8 +302,9 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event
if (event.game_started() && !game->getGameMetaInfo()->started()) {
game->getGameState()->setResuming(!game->getGameState()->isGameStateKnown());
game->getGameMetaInfo()->setStarted(event.game_started());
if (game->getGameState()->isGameStateKnown())
if (game->getGameState()->isGameStateKnown()) {
emit logGameStart();
}
game->getGameState()->setActivePlayer(event.active_player_id());
game->getGameState()->setCurrentPhase(event.active_phase());
} else if (!event.game_started() && game->getGameMetaInfo()->started()) {
@ -304,9 +323,10 @@ void GameEventHandler::processCardAttachmentsForPlayers(const Event_GameStateCha
const ServerInfo_Player &playerInfo = event.player_list(i);
const ServerInfo_PlayerProperties &prop = playerInfo.properties();
if (!prop.spectator()) {
Player *player = game->getPlayerManager()->getPlayers().value(prop.player_id(), 0);
if (!player)
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(prop.player_id(), 0);
if (!player) {
continue;
}
player->processCardAttachment(playerInfo);
}
}
@ -316,9 +336,10 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
int eventPlayerId,
const GameEventContext &context)
{
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player)
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player) {
return;
}
const ServerInfo_PlayerProperties &prop = event.player_properties();
emit playerPropertiesChanged(prop, eventPlayerId);
@ -326,8 +347,9 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
switch (contextType) {
case GameEventContext::READY_START: {
bool ready = prop.ready_start();
if (player->getPlayerInfo()->getLocal())
if (player->getPlayerInfo()->getLocal()) {
emit localPlayerReadyStateChanged(player->getPlayerInfo()->getId(), ready);
}
if (ready) {
emit logReadyStart(player);
} else {
@ -338,9 +360,10 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
case GameEventContext::CONCEDE: {
player->setConceded(true);
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext())
QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext()) {
playerIterator.next().value()->updateZones();
}
emit logConcede(eventPlayerId);
@ -349,9 +372,10 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
case GameEventContext::UNCONCEDE: {
player->setConceded(false);
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext())
QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext()) {
playerIterator.next().value()->updateZones();
}
emit logUnconcede(eventPlayerId);
@ -389,15 +413,16 @@ void GameEventHandler::eventJoin(const Event_Join &event, int /*eventPlayerId*/,
QString playerName = QString::fromStdString(playerInfo.user_info().name());
emit addPlayerToAutoCompleteList(playerName);
if (game->getPlayerManager()->getPlayers().contains(playerId))
if (game->getPlayerManager()->getPlayers().contains(playerId)) {
return;
}
if (playerInfo.spectator()) {
game->getPlayerManager()->addSpectator(playerId, playerInfo);
emit logJoinSpectator(playerName);
emit spectatorJoined(playerInfo);
} else {
Player *newPlayer = game->getPlayerManager()->addPlayer(playerId, playerInfo.user_info());
PlayerLogic *newPlayer = game->getPlayerManager()->addPlayer(playerId, playerInfo.user_info());
emit logJoinPlayer(newPlayer);
emit playerJoined(playerInfo);
}
@ -425,9 +450,10 @@ QString GameEventHandler::getLeaveReason(Event_Leave::LeaveReason reason)
}
void GameEventHandler::eventLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext & /*context*/)
{
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player)
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player) {
return;
}
player->clear();
emit playerLeft(eventPlayerId);
@ -439,9 +465,10 @@ void GameEventHandler::eventLeave(const Event_Leave &event, int eventPlayerId, c
player->deleteLater();
// Rearrange all remaining zones so that attachment relationship updates take place
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext())
QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext()) {
playerIterator.next().value()->updateZones();
}
emitUserEvent();
}
@ -460,9 +487,10 @@ void GameEventHandler::eventReverseTurn(const Event_ReverseTurn &event,
int eventPlayerId,
const GameEventContext & /*context*/)
{
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player)
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player) {
return;
}
emit logTurnReversed(player, event.reversed());
}
@ -490,9 +518,10 @@ void GameEventHandler::eventSetActivePlayer(const Event_SetActivePlayer &event,
const GameEventContext & /*context*/)
{
game->getGameState()->setActivePlayer(event.active_player_id());
Player *player = game->getPlayerManager()->getPlayer(event.active_player_id());
if (!player)
PlayerLogic *player = game->getPlayerManager()->getPlayer(event.active_player_id());
if (!player) {
return;
}
emit logActivePlayer(player);
emitUserEvent();
}

View file

@ -1,8 +1,8 @@
/**
* @file game_event_handler.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_GAME_EVENT_HANDLER_H
#define COCKATRICE_GAME_EVENT_HANDLER_H
@ -38,7 +38,7 @@ class Event_Kicked;
class Event_ReverseTurn;
class AbstractGame;
class PendingCommand;
class Player;
class PlayerLogic;
inline Q_LOGGING_CATEGORY(GameEventHandlerLog, "game_event_handler");
@ -61,6 +61,7 @@ public:
void handleGameLeft();
void handleChatMessageSent(const QString &chatMessage);
void handleArrowDeletion(int arrowId);
void handleArrowDeletionFinished(const Response &response, int arrowId);
void eventSpectatorSay(const Event_GameSay &event, int eventPlayerId, const GameEventContext &context);
void eventSpectatorLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
@ -95,7 +96,7 @@ public slots:
signals:
void emitUserEvent();
void addPlayerToAutoCompleteList(QString playerName);
void localPlayerDeckSelected(Player *localPlayer, int playerId, ServerInfo_Player playerInfo);
void localPlayerDeckSelected(PlayerLogic *localPlayer, int playerId, ServerInfo_Player playerInfo);
void remotePlayerDeckSelected(QString deckList, int playerId, QString playerName);
void remotePlayersDecksSelected(QVector<QPair<int, QPair<QString, QString>>> opponentDecks);
void localPlayerSideboardLocked(int playerId, bool sideboardLocked);
@ -112,21 +113,22 @@ signals:
void containerProcessingStarted(GameEventContext context);
void setContextJudgeName(QString judgeName);
void containerProcessingDone();
void arrowDeleted(int arrowId);
void logSpectatorSay(ServerInfo_User userInfo, QString message);
void logSpectatorLeave(QString name, QString reason);
void logGameStart();
void logReadyStart(Player *player);
void logNotReadyStart(Player *player);
void logDeckSelect(Player *player, QString deckHash, int sideboardSize);
void logSideboardLockSet(Player *player, bool sideboardLocked);
void logConnectionStateChanged(Player *player, bool connected);
void logReadyStart(PlayerLogic *player);
void logNotReadyStart(PlayerLogic *player);
void logDeckSelect(PlayerLogic *player, QString deckHash, int sideboardSize);
void logSideboardLockSet(PlayerLogic *player, bool sideboardLocked);
void logConnectionStateChanged(PlayerLogic *player, bool connected);
void logJoinSpectator(QString spectatorName);
void logJoinPlayer(Player *player);
void logLeave(Player *player, QString reason);
void logJoinPlayer(PlayerLogic *player);
void logLeave(PlayerLogic *player, QString reason);
void logKicked();
void logTurnReversed(Player *player, bool reversed);
void logTurnReversed(PlayerLogic *player, bool reversed);
void logGameClosed();
void logActivePlayer(Player *activePlayer);
void logActivePlayer(PlayerLogic *activePlayer);
void logActivePhaseChanged(int activePhase);
void logConcede(int playerId);
void logUnconcede(int playerId);

View file

@ -1,8 +1,8 @@
/**
* @file game_meta_info.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef GAME_META_INFO_H
#define GAME_META_INFO_H
@ -87,15 +87,17 @@ public:
public slots:
void setStarted(bool s)
{
if (gameInfo_.started() == s)
if (gameInfo_.started() == s) {
return;
}
gameInfo_.set_started(s);
emit startedChanged(s);
}
void setSpectatorsOmniscient(bool v)
{
if (gameInfo_.spectators_omniscient() == v)
if (gameInfo_.spectators_omniscient() == v) {
return;
}
gameInfo_.set_spectators_omniscient(v);
emit spectatorsOmniscienceChanged(v);
}

View file

@ -1,12 +1,13 @@
#include "game_scene.h"
#include "../client/settings/cache_settings.h"
#include "../game_graphics/zones/select_zone.h"
#include "../game_graphics/zones/view_zone.h"
#include "../game_graphics/zones/view_zone_widget.h"
#include "board/card_item.h"
#include "phases_toolbar.h"
#include "player/player.h"
#include "player/player_graphics_item.h"
#include "zones/view_zone.h"
#include "zones/view_zone_widget.h"
#include "player/player_logic.h"
#include <QBasicTimer>
#include <QDebug>
@ -54,8 +55,9 @@ GameScene::~GameScene()
*/
void GameScene::retranslateUi()
{
for (ZoneViewWidget *view : zoneViews)
for (ZoneViewWidget *view : zoneViews) {
view->retranslateUi();
}
}
QList<CardItem *> GameScene::selectedCards() const
@ -76,13 +78,30 @@ QList<CardItem *> GameScene::selectedCards() const
*
* Connects to the player's sizeChanged signal to recompute layout on resize.
*/
void GameScene::addPlayer(Player *player)
void GameScene::addPlayer(PlayerLogic *player)
{
qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::addPlayer name=" << player->getPlayerInfo()->getName();
players << player->getGraphicsItem();
playerViews.insert(player->getPlayerInfo()->getId(), player->getGraphicsItem());
addItem(player->getGraphicsItem());
connect(player->getGraphicsItem(), &PlayerGraphicsItem::sizeChanged, this, &GameScene::rearrange);
connect(player, &PlayerLogic::concededChanged, this, [this](int id, bool conceded) {
if (conceded) {
clearArrowsForPlayer(id);
}
rearrange();
});
connect(player, &PlayerLogic::arrowDeleted, this, &GameScene::deleteArrow);
connect(player, &PlayerLogic::arrowCreateRequested, this, &GameScene::addArrow);
connect(player, &PlayerLogic::arrowDeleteRequested, this, &GameScene::requestArrowDeletion);
connect(player, &PlayerLogic::arrowsCleared, this,
[this, id = player->getPlayerInfo()->getId()]() { clearArrowsForPlayer(id); });
connect(player->getPlayerEventHandler(), &PlayerEventHandler::cardZoneChanged, this, &GameScene::onCardZoneChanged);
rearrange();
}
/**
@ -91,17 +110,19 @@ void GameScene::addPlayer(Player *player)
*
* Closes any zone views associated with the player and recomputes layout.
*/
void GameScene::removePlayer(Player *player)
void GameScene::removePlayer(PlayerLogic *player)
{
qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::removePlayer name=" << player->getPlayerInfo()->getName();
clearArrowsForPlayer(player->getPlayerInfo()->getId());
for (ZoneViewWidget *zone : zoneViews) {
if (zone->getPlayer() == player) {
zone->close();
}
}
players.removeOne(player->getGraphicsItem());
removeItem(player->getGraphicsItem());
auto *view = playerViews.take(player->getPlayerInfo()->getId());
removeItem(view);
rearrange();
}
@ -176,14 +197,14 @@ void GameScene::processViewSizeChange(const QSize &newSize)
*
* Used to determine rotation and layout order.
*/
QList<Player *> GameScene::collectActivePlayers(int &firstPlayerIndex) const
QList<PlayerLogic *> GameScene::collectActivePlayers(int &firstPlayerIndex) const
{
QList<Player *> activePlayers;
QList<PlayerLogic *> activePlayers;
firstPlayerIndex = 0;
bool firstPlayerFound = false;
for (auto *pgItem : players) {
Player *p = pgItem->getPlayer();
for (auto *pgItem : playerViews.values()) {
PlayerLogic *p = pgItem->getPlayer();
if (p && !p->getConceded()) {
activePlayers.append(p);
if (!firstPlayerFound && p->getPlayerInfo()->getLocal()) {
@ -203,15 +224,17 @@ QList<Player *> GameScene::collectActivePlayers(int &firstPlayerIndex) const
*
* Applies rotation offset and ensures the list wraps correctly.
*/
QList<Player *> GameScene::rotatePlayers(const QList<Player *> &activePlayers, int firstPlayerIndex) const
QList<PlayerLogic *> GameScene::rotatePlayers(const QList<PlayerLogic *> &activePlayers, int firstPlayerIndex) const
{
QList<Player *> rotated = activePlayers;
QList<PlayerLogic *> rotated = activePlayers;
if (!rotated.isEmpty()) {
int totalRotation = firstPlayerIndex + playerRotation;
while (totalRotation < 0)
while (totalRotation < 0) {
totalRotation += rotated.size();
for (int i = 0; i < totalRotation; ++i)
}
for (int i = 0; i < totalRotation; ++i) {
rotated.append(rotated.takeFirst());
}
}
return rotated;
}
@ -234,7 +257,7 @@ int GameScene::determineColumnCount(int playerCount)
* - Position players in columns with spacing.
* - Mirror graphics for visual balance.
*/
QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<Player *> &playersPlaying, int columns)
QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<PlayerLogic *> &playersPlaying, int columns)
{
playersByColumn.clear();
@ -242,7 +265,7 @@ QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<Player *> &players
qreal sceneHeight = 0, sceneWidth = -playerAreaSpacing;
QList<int> columnWidth;
QListIterator<Player *> playersIter(playersPlaying);
QListIterator<PlayerLogic *> playersIter(playersPlaying);
for (int col = 0; col < columns; ++col) {
playersByColumn.append(QList<PlayerGraphicsItem *>());
columnWidth.append(0);
@ -250,11 +273,12 @@ QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<Player *> &players
int rowsInColumn = rows - (playersPlaying.size() % columns) * col; // Adjust rows for uneven columns
for (int j = 0; j < rowsInColumn; ++j) {
Player *player = playersIter.next();
if (col == 0)
PlayerLogic *player = playersIter.next();
if (col == 0) {
playersByColumn[col].prepend(player->getGraphicsItem());
else
} else {
playersByColumn[col].append(player->getGraphicsItem());
}
auto *pgItem = player->getGraphicsItem();
thisColumnHeight += pgItem->boundingRect().height() + playerAreaSpacing;
@ -293,8 +317,9 @@ QList<qreal> GameScene::calculateMinWidthByColumn() const
QList<qreal> minWidthByColumn;
for (const auto &col : playersByColumn) {
qreal maxWidth = 0;
for (PlayerGraphicsItem *player : col)
for (PlayerGraphicsItem *player : col) {
maxWidth = std::max(maxWidth, player->getMinimumWidth());
}
minWidthByColumn.append(maxWidth);
}
return minWidthByColumn;
@ -342,6 +367,99 @@ void GameScene::resizeColumnsAndPlayers(const QList<qreal> &minWidthByColumn, qr
}
}
void GameScene::addArrow(const ArrowData &data)
{
auto *startView = playerViews.value(data.startPlayerId);
auto *targetView = playerViews.value(data.targetPlayerId);
if (!startView || !targetView) {
return;
}
PlayerLogic *startLogic = startView->getPlayer();
auto *startZone = startLogic->getZones().value(data.startZone);
if (!startZone) {
return;
}
CardItem *startCard = startZone->getCard(data.startCardId);
if (!startCard) {
return;
}
ArrowTarget *targetItem = nullptr;
if (data.isPlayerTargeted()) {
targetItem = targetView->getPlayerTarget();
} else {
auto *zone = targetView->getPlayer()->getZones().value(data.targetZone);
if (zone) {
targetItem = zone->getCard(data.targetCardId);
}
}
if (!targetItem) {
return;
}
auto *arrow = new ArrowItem(startView->getPlayer(), data.id, startCard, targetItem, data.color);
addItem(arrow);
arrowRegistry.insert(data.id, arrow);
connect(arrow, &ArrowItem::requestDeletion, this, &GameScene::requestArrowDeletion);
}
void GameScene::deleteArrow(int arrowId)
{
if (arrowRegistry.contains(arrowId)) {
arrowRegistry.take(arrowId)->delArrow();
}
}
void GameScene::clearArrowsForPlayer(int playerId)
{
QList<int> toDelete;
for (auto i = arrowRegistry.cbegin(); i != arrowRegistry.cend(); ++i) {
auto *arrow = i.value();
if (arrow->getPlayer()->getPlayerInfo()->getId() == playerId) {
toDelete.append(i.key());
}
}
for (int arrowId : toDelete) {
arrowRegistry.take(arrowId)->delArrow();
}
}
void GameScene::requestArrowDeletion(int arrowId)
{
if (arrowRegistry.contains(arrowId)) {
emit arrowDeletionRequested(arrowId);
}
}
void GameScene::requestClearArrowsForPlayer(int playerId)
{
for (auto *arrow : arrowRegistry.values()) {
if (arrow->getPlayer()->getPlayerInfo()->getId() == playerId) {
emit requestArrowDeletion(arrow->getId());
}
}
}
void GameScene::onCardZoneChanged(CardItem *card, bool sameZone)
{
QList<ArrowItem *> toDelete;
for (auto *arrow : arrowRegistry.values()) {
if (arrow->getStartItem() == card || arrow->getTargetItem() == card) {
if (sameZone) {
arrow->updatePath();
} else {
toDelete.append(arrow);
}
}
}
for (auto *arrow : toDelete) {
deleteArrow(arrow->getId());
}
}
// ---------- Hover Handling ----------
void GameScene::updateHover(const QPointF &scenePos)
@ -355,18 +473,38 @@ void GameScene::updateHover(const QPointF &scenePos)
void GameScene::updateHoveredCard(CardItem *newCard)
{
if (hoveredCard && (newCard != hoveredCard))
hoveredCard->setHovered(false);
if (newCard && (newCard != hoveredCard))
newCard->setHovered(true);
if (hoveredCard && (newCard != hoveredCard)) {
endCardHover(hoveredCard);
}
if (newCard && (newCard != hoveredCard)) {
beginCardHover(newCard);
}
hoveredCard = newCard;
}
void GameScene::beginCardHover(CardItem *card)
{
card->setHovered(true);
if (auto *zone = SelectZone::findOwningSelectZone(card)) {
zone->escapeClipForHover(card);
}
}
void GameScene::endCardHover(CardItem *card)
{
if (auto *zone = SelectZone::findOwningSelectZone(card)) {
zone->restoreClipAfterHover(card);
}
card->setHovered(false);
}
CardZone *GameScene::findTopmostZone(const QList<QGraphicsItem *> &items)
{
for (QGraphicsItem *item : items)
if (auto *zone = qgraphicsitem_cast<CardZone *>(item))
for (QGraphicsItem *item : items) {
if (auto *zone = qgraphicsitem_cast<CardZone *>(item)) {
return zone;
}
}
return nullptr;
}
@ -377,14 +515,17 @@ CardItem *GameScene::findTopmostCardInZone(const QList<QGraphicsItem *> &items,
for (QGraphicsItem *item : items) {
CardItem *card = qgraphicsitem_cast<CardItem *>(item);
if (!card)
if (!card) {
continue;
}
if (card->getAttachedTo()) {
if (card->getAttachedTo()->getZone() != zone->getLogic())
if (card->getAttachedTo()->getZone() != zone->getLogic()) {
continue;
} else if (card->getZone() != zone->getLogic())
}
} else if (card->getZone() != zone->getLogic()) {
continue;
}
if (card->getRealZValue() > maxZ) {
maxZ = card->getRealZValue();
@ -406,7 +547,7 @@ CardItem *GameScene::findTopmostCardInZone(const QList<QGraphicsItem *> &items,
* If an identical view exists, it is closed. Otherwise, a new ZoneViewWidget is created
* and positioned based on zone type.
*/
void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numberCards, bool isReversed)
void GameScene::toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed)
{
for (auto &view : zoneViews) {
ZoneViewZone *temp = view->getZone();
@ -423,12 +564,13 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb
connect(item, &ZoneViewWidget::closePressed, this, &GameScene::removeZoneView);
addItem(item);
if (zoneName == ZoneNames::GRAVE)
if (zoneName == ZoneNames::GRAVE) {
item->setPos(360, 100);
else if (zoneName == ZoneNames::EXILE)
} else if (zoneName == ZoneNames::EXILE) {
item->setPos(380, 120);
else
} else {
item->setPos(340, 80);
}
}
/**
@ -438,7 +580,7 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb
* @param cardList List of cards to show.
* @param withWritePermission Whether edits are allowed.
*/
void GameScene::addRevealedZoneView(Player *player,
void GameScene::addRevealedZoneView(PlayerLogic *player,
CardZoneLogic *zone,
const QList<const ServerInfo_Card *> &cardList,
bool withWritePermission)
@ -465,8 +607,9 @@ void GameScene::removeZoneView(ZoneViewWidget *item)
*/
void GameScene::clearViews()
{
while (!zoneViews.isEmpty())
while (!zoneViews.isEmpty()) {
zoneViews.first()->close();
}
}
/**
@ -474,8 +617,9 @@ void GameScene::clearViews()
*/
void GameScene::closeMostRecentZoneView()
{
if (!zoneViews.isEmpty())
if (!zoneViews.isEmpty()) {
zoneViews.last()->close();
}
}
// ---------- View Transforms ----------
@ -494,8 +638,11 @@ QTransform GameScene::getViewportTransform() const
bool GameScene::event(QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneMouseMove)
if (event->type() == QEvent::GraphicsSceneMouseMove) {
updateHover(static_cast<QGraphicsSceneMouseEvent *>(event)->scenePos());
} else if (event->type() == QEvent::Leave) {
updateHoveredCard(nullptr);
}
return QGraphicsScene::event(event);
}
@ -505,25 +652,29 @@ void GameScene::timerEvent(QTimerEvent * /*event*/)
QMutableSetIterator<CardItem *> i(cardsToAnimate);
while (i.hasNext()) {
i.next();
if (!i.value()->animationEvent())
if (!i.value()->animationEvent()) {
i.remove();
}
}
if (cardsToAnimate.isEmpty())
if (cardsToAnimate.isEmpty()) {
animationTimer->stop();
}
}
void GameScene::registerAnimationItem(AbstractCardItem *card)
{
cardsToAnimate.insert(static_cast<CardItem *>(card));
if (!animationTimer->isActive())
if (!animationTimer->isActive()) {
animationTimer->start(10, this);
}
}
void GameScene::unregisterAnimationItem(AbstractCardItem *card)
{
cardsToAnimate.remove(static_cast<CardItem *>(card));
if (cardsToAnimate.isEmpty())
if (cardsToAnimate.isEmpty()) {
animationTimer->stop();
}
}
// ---------- Rubber Band ----------

View file

@ -1,7 +1,9 @@
#ifndef GAMESCENE_H
#define GAMESCENE_H
#include "zones/logic/card_zone_logic.h"
#include "board/arrow_data.h"
#include "board/arrow_item.h"
#include "zones/card_zone_logic.h"
#include <QGraphicsScene>
#include <QList>
@ -12,7 +14,7 @@
inline Q_LOGGING_CATEGORY(GameSceneLog, "game_scene");
inline Q_LOGGING_CATEGORY(GameScenePlayerAdditionRemovalLog, "game_scene.player_addition_removal");
class Player;
class PlayerLogic;
class PlayerGraphicsItem;
class ZoneViewWidget;
class CardZone;
@ -41,8 +43,9 @@ private:
static const int playerAreaSpacing = 5; ///< Space between player areas
PhasesToolbar *phasesToolbar; ///< Toolbar showing game phases
QList<PlayerGraphicsItem *> players; ///< All player graphics items
QMap<int, PlayerGraphicsItem *> playerViews; ///< ID lookup for player graphics items
QList<QList<PlayerGraphicsItem *>> playersByColumn; ///< Players organized by column
QMap<int, ArrowItem *> arrowRegistry; ///< ID registry for arrow graphics items
QList<ZoneViewWidget *> zoneViews; ///< Active zone view widgets
QSize viewSize; ///< Current view size
QPointer<CardItem> hoveredCard; ///< Currently hovered card
@ -56,6 +59,14 @@ private:
*/
void updateHover(const QPointF &scenePos);
/**
* @brief Activates hover state and escapes the card from its clip container
* so hover scaling is visible beyond zone bounds.
*/
void beginCardHover(CardItem *card);
/** @brief Deactivates hover state and restores the card to its clip container. */
void endCardHover(CardItem *card);
public:
/**
* @brief Constructs the GameScene.
@ -64,26 +75,26 @@ public:
*/
explicit GameScene(PhasesToolbar *_phasesToolbar, QObject *parent = nullptr);
/** Destructor, cleans up timer and zone views. */
/** @brief Destructor, cleans up timer and zone views. */
~GameScene() override;
/** Updates UI text for all zone views. */
/** @brief Updates UI text for all zone views. */
void retranslateUi();
/** Gets all selected CardItems */
/** @brief Gets all selected CardItems. */
QList<CardItem *> selectedCards() const;
/**
* @brief Adds a player to the scene and stores their graphics item.
* @param player Player to add.
*/
void addPlayer(Player *player);
void addPlayer(PlayerLogic *player);
/**
* @brief Removes a player from the scene.
* @param player Player to remove.
*/
void removePlayer(Player *player);
void removePlayer(PlayerLogic *player);
/**
* @brief Adjusts the global rotation offset for player layout.
@ -91,7 +102,7 @@ public:
*/
void adjustPlayerRotation(int rotationAdjustment);
/** Recomputes the layout of players and the scene size. */
/** @brief Recomputes the layout of players and the scene size. */
void rearrange();
/**
@ -105,7 +116,7 @@ public:
* @param firstPlayerIndex Output index of first local player.
* @return List of active players.
*/
QList<Player *> collectActivePlayers(int &firstPlayerIndex) const;
QList<PlayerLogic *> collectActivePlayers(int &firstPlayerIndex) const;
/**
* @brief Rotates the list of players for layout.
@ -113,7 +124,7 @@ public:
* @param firstPlayerIndex Index of first local player.
* @return Rotated list.
*/
QList<Player *> rotatePlayers(const QList<Player *> &players, int firstPlayerIndex) const;
QList<PlayerLogic *> rotatePlayers(const QList<PlayerLogic *> &players, int firstPlayerIndex) const;
/**
* @brief Determines the number of columns to display players in.
@ -128,7 +139,7 @@ public:
* @param columns Number of columns to split into.
* @return Calculated scene size.
*/
QSizeF computeSceneSizeAndPlayerLayout(const QList<Player *> &playersPlaying, int columns);
QSizeF computeSceneSizeAndPlayerLayout(const QList<PlayerLogic *> &playersPlaying, int columns);
/**
* @brief Computes the minimum width for each column based on player minimum widths.
@ -151,56 +162,68 @@ public:
*/
void resizeColumnsAndPlayers(const QList<qreal> &minWidthByColumn, qreal newWidth);
/** Finds the topmost card zone under the cursor. */
/** @brief Finds the topmost card zone under the cursor. */
static CardZone *findTopmostZone(const QList<QGraphicsItem *> &items);
/** Finds the topmost card in a given zone, considering attachments and Z-order. */
/** @brief Finds the topmost card in a given zone, considering attachments and Z-order. */
static CardItem *findTopmostCardInZone(const QList<QGraphicsItem *> &items, CardZone *zone);
/** Updates hovered card highlighting. */
/** @brief Updates hovered card highlighting. */
void updateHoveredCard(CardItem *newCard);
/** Registers a card for animation updates. */
/** @brief Registers a card for animation updates. */
void registerAnimationItem(AbstractCardItem *card);
/** Unregisters a card from animation updates. */
/** @brief Unregisters a card from animation updates. */
void unregisterAnimationItem(AbstractCardItem *card);
void startRubberBand(const QPointF &selectionOrigin);
void resizeRubberBand(const QPointF &cursorPoint, int selectedCount);
void stopRubberBand();
public slots:
/** Toggles a zone view for a player. */
void toggleZoneView(Player *player, const QString &zoneName, int numberCards, bool isReversed = false);
/** @brief Toggles a zone view for a player. */
void toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed = false);
/** Adds a revealed zone view (for shown cards). */
void addRevealedZoneView(Player *player,
/** @brief Adds a revealed zone view (for shown cards). */
void addRevealedZoneView(PlayerLogic *player,
CardZoneLogic *zone,
const QList<const ServerInfo_Card *> &cardList,
bool withWritePermission);
/** Removes a zone view widget from the scene. */
/** @brief Removes a zone view widget from the scene. */
void removeZoneView(ZoneViewWidget *item);
/** Closes all zone views. */
/** @brief Closes all zone views. */
void clearViews();
/** Closes the most recently added zone view. */
/** @brief Closes the most recently added zone view. */
void closeMostRecentZoneView();
QTransform getViewTransform() const;
QTransform getViewportTransform() const;
/// Directly modifies the scene
void addArrow(const ArrowData &data);
void deleteArrow(int arrowId);
void clearArrowsForPlayer(int playerId);
/// Queues up arrow deletion but doesn't directly modify the scene
void requestArrowDeletion(int arrowId);
void requestClearArrowsForPlayer(int playerId);
void onCardZoneChanged(CardItem *card, bool sameZone);
protected:
/** Handles hover updates. */
/** @brief Handles hover updates. */
bool event(QEvent *event) override;
/** Handles animation timer updates. */
/** @brief Handles animation timer updates. */
void timerEvent(QTimerEvent *event) override;
signals:
void sigStartRubberBand(const QPointF &selectionOrigin);
void sigResizeRubberBand(const QPointF &cursorPoint, int selectedCount);
void sigStopRubberBand();
void arrowDeletionRequested(int arrowId);
};
#endif

View file

@ -1,8 +1,8 @@
/**
* @file game_state.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_GAME_STATE_H
#define COCKATRICE_GAME_STATE_H

View file

@ -75,8 +75,9 @@ void GameView::resizeEvent(QResizeEvent *event)
QGraphicsView::resizeEvent(event);
GameScene *s = dynamic_cast<GameScene *>(scene());
if (s)
if (s) {
s->processViewSizeChange(event->size());
}
updateSceneRect(scene()->sceneRect());
updateTotalSelectionCount(event->size());
@ -89,8 +90,9 @@ void GameView::updateSceneRect(const QRectF &rect)
void GameView::startRubberBand(const QPointF &_selectionOrigin)
{
if (!rubberBand)
if (!rubberBand) {
return;
}
selectionOrigin = _selectionOrigin;
rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0)));
@ -99,8 +101,9 @@ void GameView::startRubberBand(const QPointF &_selectionOrigin)
void GameView::resizeRubberBand(const QPointF &cursorPoint, int selectedCount)
{
if (!rubberBand)
if (!rubberBand) {
return;
}
constexpr int kLabelPaddingInPixels = 4;
@ -145,8 +148,9 @@ void GameView::resizeRubberBand(const QPointF &cursorPoint, int selectedCount)
void GameView::stopRubberBand()
{
if (!rubberBand)
if (!rubberBand) {
return;
}
rubberBand->hide();
dragCountLabel->hide();

View file

@ -1,8 +1,8 @@
/**
* @file game_view.h
* @ingroup GameGraphics
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef GAMEVIEW_H
#define GAMEVIEW_H

View file

@ -1,6 +1,6 @@
#include "hand_counter.h"
#include "zones/card_zone.h"
#include "../game_graphics/zones/card_zone.h"
#include <QGraphicsSceneMouseEvent>
#include <QPainter>

View file

@ -1,8 +1,8 @@
/**
* @file hand_counter.h
* @ingroup GameGraphicsPlayers
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef HANDCOUNTER_H
#define HANDCOUNTER_H

View file

@ -5,7 +5,7 @@
#include "../board/card_item.h"
#include "../board/translate_counter_name.h"
#include "../phase.h"
#include "../player/player.h"
#include "../player/player_logic.h"
#include <../../client/settings/card_counter_settings.h>
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
@ -105,7 +105,7 @@ void MessageLogWidget::containerProcessingStarted(const GameEventContext &contex
}
}
void MessageLogWidget::logAlwaysRevealTopCard(Player *player, CardZoneLogic *zone, bool reveal)
void MessageLogWidget::logAlwaysRevealTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal)
{
appendHtmlServerMessage((reveal ? tr("%1 is now keeping the top card %2 revealed.")
: tr("%1 is not revealing the top card %2 any longer."))
@ -113,7 +113,7 @@ void MessageLogWidget::logAlwaysRevealTopCard(Player *player, CardZoneLogic *zon
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
}
void MessageLogWidget::logAlwaysLookAtTopCard(Player *player, CardZoneLogic *zone, bool reveal)
void MessageLogWidget::logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal)
{
appendHtmlServerMessage((reveal ? tr("%1 can now look at top card %2 at any time.")
: tr("%1 no longer can look at top card %2 at any time."))
@ -121,7 +121,10 @@ void MessageLogWidget::logAlwaysLookAtTopCard(Player *player, CardZoneLogic *zon
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
}
void MessageLogWidget::logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName)
void MessageLogWidget::logAttachCard(PlayerLogic *player,
QString cardName,
PlayerLogic *targetPlayer,
QString targetCardName)
{
appendHtmlServerMessage(tr("%1 attaches %2 to %3's %4.")
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
@ -148,7 +151,7 @@ void MessageLogWidget::logUnconcede(int playerId)
true);
}
void MessageLogWidget::logConnectionStateChanged(Player *player, bool connectionState)
void MessageLogWidget::logConnectionStateChanged(PlayerLogic *player, bool connectionState)
{
if (connectionState) {
soundEngine->playSound("player_reconnect");
@ -161,10 +164,10 @@ void MessageLogWidget::logConnectionStateChanged(Player *player, bool connection
}
}
void MessageLogWidget::logCreateArrow(Player *player,
Player *startPlayer,
void MessageLogWidget::logCreateArrow(PlayerLogic *player,
PlayerLogic *startPlayer,
QString startCard,
Player *targetPlayer,
PlayerLogic *targetPlayer,
QString targetCard,
bool playerTarget)
{
@ -220,7 +223,7 @@ void MessageLogWidget::logCreateArrow(Player *player,
}
}
void MessageLogWidget::logCreateToken(Player *player, QString cardName, QString pt, bool faceDown)
void MessageLogWidget::logCreateToken(PlayerLogic *player, QString cardName, QString pt, bool faceDown)
{
if (faceDown) {
appendHtmlServerMessage(
@ -233,7 +236,7 @@ void MessageLogWidget::logCreateToken(Player *player, QString cardName, QString
}
}
void MessageLogWidget::logDeckSelect(Player *player, QString deckHash, int sideboardSize)
void MessageLogWidget::logDeckSelect(PlayerLogic *player, QString deckHash, int sideboardSize)
{
if (sideboardSize < 0) {
appendHtmlServerMessage(
@ -246,13 +249,13 @@ void MessageLogWidget::logDeckSelect(Player *player, QString deckHash, int sideb
}
}
void MessageLogWidget::logDestroyCard(Player *player, QString cardName)
void MessageLogWidget::logDestroyCard(PlayerLogic *player, QString cardName)
{
appendHtmlServerMessage(
tr("%1 destroys %2.").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(std::move(cardName))));
}
void MessageLogWidget::logMoveCard(Player *player,
void MessageLogWidget::logMoveCard(PlayerLogic *player,
CardItem *card,
CardZoneLogic *startZone,
int oldX,
@ -359,7 +362,7 @@ void MessageLogWidget::logMoveCard(Player *player,
appendHtmlServerMessage(message);
}
void MessageLogWidget::logDrawCards(Player *player, int number, bool deckIsEmpty)
void MessageLogWidget::logDrawCards(PlayerLogic *player, int number, bool deckIsEmpty)
{
soundEngine->playSound("draw_card");
if (currentContext == MessageContext_Mulligan) {
@ -376,7 +379,7 @@ void MessageLogWidget::logDrawCards(Player *player, int number, bool deckIsEmpty
}
}
void MessageLogWidget::logDumpZone(Player *player, CardZoneLogic *zone, int numberCards, bool isReversed)
void MessageLogWidget::logDumpZone(PlayerLogic *player, CardZoneLogic *zone, int numberCards, bool isReversed)
{
if (numberCards == -1) {
appendHtmlServerMessage(tr("%1 is looking at %2.")
@ -392,7 +395,7 @@ void MessageLogWidget::logDumpZone(Player *player, CardZoneLogic *zone, int numb
}
}
void MessageLogWidget::logFlipCard(Player *player, QString cardName, bool faceDown)
void MessageLogWidget::logFlipCard(PlayerLogic *player, QString cardName, bool faceDown)
{
if (faceDown) {
appendHtmlServerMessage(
@ -418,7 +421,7 @@ void MessageLogWidget::logGameFlooded()
appendMessage(tr("You are flooding the game. Please wait a couple of seconds."));
}
void MessageLogWidget::logJoin(Player *player)
void MessageLogWidget::logJoin(PlayerLogic *player)
{
soundEngine->playSound("player_join");
appendHtmlServerMessage(tr("%1 has joined the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
@ -435,7 +438,7 @@ void MessageLogWidget::logKicked()
appendHtmlServerMessage(tr("You have been kicked out of the game."), true);
}
void MessageLogWidget::logLeave(Player *player, QString reason)
void MessageLogWidget::logLeave(PlayerLogic *player, QString reason)
{
soundEngine->playSound("player_leave");
appendHtmlServerMessage(tr("%1 has left the game (%2).")
@ -450,13 +453,13 @@ void MessageLogWidget::logLeaveSpectator(QString name, QString reason)
.arg(sanitizeHtml(std::move(name)), sanitizeHtml(std::move(reason))));
}
void MessageLogWidget::logNotReadyStart(Player *player)
void MessageLogWidget::logNotReadyStart(PlayerLogic *player)
{
appendHtmlServerMessage(
tr("%1 is not ready to start the game any more.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
}
void MessageLogWidget::logMulligan(Player *player, int number)
void MessageLogWidget::logMulligan(PlayerLogic *player, int number)
{
if (!player) {
return;
@ -476,16 +479,16 @@ void MessageLogWidget::logReplayStarted(int gameId)
appendHtmlServerMessage(tr("You are watching a replay of game #%1.").arg(gameId));
}
void MessageLogWidget::logReadyStart(Player *player)
void MessageLogWidget::logReadyStart(PlayerLogic *player)
{
appendHtmlServerMessage(tr("%1 is ready to start the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
}
void MessageLogWidget::logRevealCards(Player *player,
void MessageLogWidget::logRevealCards(PlayerLogic *player,
CardZoneLogic *zone,
int cardId,
QString cardName,
Player *otherPlayer,
PlayerLogic *otherPlayer,
bool faceDown,
int amount,
bool isLentToAnotherPlayer)
@ -568,14 +571,14 @@ void MessageLogWidget::logRevealCards(Player *player,
}
}
void MessageLogWidget::logReverseTurn(Player *player, bool reversed)
void MessageLogWidget::logReverseTurn(PlayerLogic *player, bool reversed)
{
appendHtmlServerMessage(tr("%1 reversed turn order, now it's %2.")
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
.arg(reversed ? tr("reversed") : tr("normal")));
}
void MessageLogWidget::logRollDie(Player *player, int sides, const QList<uint> &rolls)
void MessageLogWidget::logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls)
{
if (rolls.length() == 1) {
const auto roll = rolls.at(0);
@ -612,7 +615,7 @@ void MessageLogWidget::logRollDie(Player *player, int sides, const QList<uint> &
soundEngine->playSound("roll_dice");
}
void MessageLogWidget::logSay(Player *player, QString message)
void MessageLogWidget::logSay(PlayerLogic *player, QString message)
{
appendMessage(std::move(message), {}, *player->getPlayerInfo()->getUserInfo(), true);
}
@ -627,13 +630,13 @@ void MessageLogWidget::logSetActivePhase(int phaseNumber)
phase.getName() + "</b></font>");
}
void MessageLogWidget::logSetActivePlayer(Player *player)
void MessageLogWidget::logSetActivePlayer(PlayerLogic *player)
{
appendHtml("<br><font color=\"green\"><b>" + QDateTime::currentDateTime().toString("[hh:mm:ss] ") +
QString(tr("%1's turn.")).arg(player->getPlayerInfo()->getName()) + "</b></font><br>");
}
void MessageLogWidget::logSetAnnotation(Player *player, CardItem *card, QString newAnnotation)
void MessageLogWidget::logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation)
{
appendHtmlServerMessage(
QString(tr("%1 sets annotation of %2 to %3."))
@ -642,25 +645,27 @@ void MessageLogWidget::logSetAnnotation(Player *player, CardItem *card, QString
.arg(QString("&quot;<font class=\"blue\">%1</font>&quot;").arg(sanitizeHtml(std::move(newAnnotation)))));
}
void MessageLogWidget::logSetCardCounter(Player *player, QString cardName, int counterId, int value, int oldValue)
void MessageLogWidget::logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue)
{
QString finalStr;
int delta = abs(oldValue - value);
if (value > oldValue) {
finalStr = tr("%1 places %2 \"%3\" counter(s) on %4 (now %5).", "", delta);
finalStr = tr("%1 places %2 %3%4 counter(s) on %5 (now %6).", "", delta);
} else {
finalStr = tr("%1 removes %2 \"%3\" counter(s) from %4 (now %5).", "", delta);
finalStr = tr("%1 removes %2 %3%4 counter(s) from %5 (now %6).", "", delta);
}
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
QString hex = cardCounterSettings.color(counterId).name();
appendHtmlServerMessage(finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
.arg("<font class=\"blue\">" + QString::number(delta) + "</font>")
.arg("<font color=\"" + hex + "\">●</font>")
.arg(cardCounterSettings.displayName(counterId))
.arg(cardLink(std::move(cardName)))
.arg(value));
}
void MessageLogWidget::logSetCounter(Player *player, QString counterName, int value, int oldValue)
void MessageLogWidget::logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue)
{
if (counterName == "life") {
soundEngine->playSound("life_change");
@ -675,7 +680,7 @@ void MessageLogWidget::logSetCounter(Player *player, QString counterName, int va
.arg(value - oldValue));
}
void MessageLogWidget::logSetDoesntUntap(Player *player, CardItem *card, bool doesntUntap)
void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap)
{
QString str;
if (doesntUntap) {
@ -686,7 +691,7 @@ void MessageLogWidget::logSetDoesntUntap(Player *player, CardItem *card, bool do
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(card->getName())));
}
void MessageLogWidget::logSetPT(Player *player, CardItem *card, QString newPT)
void MessageLogWidget::logSetPT(PlayerLogic *player, CardItem *card, QString newPT)
{
if (currentContext == MessageContext_MoveCard) {
return;
@ -713,7 +718,7 @@ void MessageLogWidget::logSetPT(Player *player, CardItem *card, QString newPT)
}
}
void MessageLogWidget::logSetSideboardLock(Player *player, bool locked)
void MessageLogWidget::logSetSideboardLock(PlayerLogic *player, bool locked)
{
if (locked) {
appendHtmlServerMessage(
@ -724,7 +729,7 @@ void MessageLogWidget::logSetSideboardLock(Player *player, bool locked)
}
}
void MessageLogWidget::logSetTapped(Player *player, CardItem *card, bool tapped)
void MessageLogWidget::logSetTapped(PlayerLogic *player, CardItem *card, bool tapped)
{
if (currentContext == MessageContext_MoveCard) {
return;
@ -747,7 +752,7 @@ void MessageLogWidget::logSetTapped(Player *player, CardItem *card, bool tapped)
}
}
void MessageLogWidget::logShuffle(Player *player, CardZoneLogic *zone, int start, int end)
void MessageLogWidget::logShuffle(PlayerLogic *player, CardZoneLogic *zone, int start, int end)
{
if (currentContext == MessageContext_Mulligan) {
return;
@ -784,14 +789,14 @@ void MessageLogWidget::logSpectatorSay(const ServerInfo_User &spectator, QString
appendMessage(std::move(message), {}, spectator, false);
}
void MessageLogWidget::logUnattachCard(Player *player, QString cardName)
void MessageLogWidget::logUnattachCard(PlayerLogic *player, QString cardName)
{
appendHtmlServerMessage(tr("%1 unattaches %2.")
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
.arg(cardLink(std::move(cardName))));
}
void MessageLogWidget::logUndoDraw(Player *player, QString cardName)
void MessageLogWidget::logUndoDraw(PlayerLogic *player, QString cardName)
{
if (cardName.isEmpty()) {
appendHtmlServerMessage(tr("%1 undoes their last draw.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
@ -803,6 +808,12 @@ void MessageLogWidget::logUndoDraw(Player *player, QString cardName)
}
}
void MessageLogWidget::logUndoDrawFailed(PlayerLogic *player)
{
appendHtmlServerMessage(
tr("%1 failed to undo their last draw.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
}
void MessageLogWidget::setContextJudgeName(QString name)
{
messagePrefix = QString("<span style=\"color:black\">");
@ -836,6 +847,7 @@ void MessageLogWidget::connectToPlayerEventHandler(PlayerEventHandler *playerEve
connect(playerEventHandler, &PlayerEventHandler::logDumpZone, this, &MessageLogWidget::logDumpZone);
connect(playerEventHandler, &PlayerEventHandler::logDrawCards, this, &MessageLogWidget::logDrawCards);
connect(playerEventHandler, &PlayerEventHandler::logUndoDraw, this, &MessageLogWidget::logUndoDraw);
connect(playerEventHandler, &PlayerEventHandler::logUndoDrawFailed, this, &MessageLogWidget::logUndoDrawFailed);
connect(playerEventHandler, &PlayerEventHandler::logRevealCards, this, &MessageLogWidget::logRevealCards);
connect(playerEventHandler, &PlayerEventHandler::logAlwaysRevealTopCard, this,
&MessageLogWidget::logAlwaysRevealTopCard);

View file

@ -1,19 +1,19 @@
/**
* @file message_log_widget.h
* @ingroup GameWidgets
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef MESSAGELOGWIDGET_H
#define MESSAGELOGWIDGET_H
#include "../../interface/widgets/server/chat_view/chat_view.h"
#include "../zones/logic/card_zone_logic.h"
#include "../zones/card_zone_logic.h"
class AbstractGame;
class CardItem;
class GameEventContext;
class Player;
class PlayerLogic;
class PlayerEventHandler;
class MessageLogWidget : public ChatView
@ -39,66 +39,67 @@ public:
public slots:
void containerProcessingDone();
void containerProcessingStarted(const GameEventContext &context);
void logAlwaysRevealTopCard(Player *player, CardZoneLogic *zone, bool reveal);
void logAlwaysLookAtTopCard(Player *player, CardZoneLogic *zone, bool reveal);
void logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName);
void logAlwaysRevealTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
void logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
void logAttachCard(PlayerLogic *player, QString cardName, PlayerLogic *targetPlayer, QString targetCardName);
void logConcede(int playerId);
void logUnconcede(int playerId);
void logConnectionStateChanged(Player *player, bool connectionState);
void logCreateArrow(Player *player,
Player *startPlayer,
void logConnectionStateChanged(PlayerLogic *player, bool connectionState);
void logCreateArrow(PlayerLogic *player,
PlayerLogic *startPlayer,
QString startCard,
Player *targetPlayer,
PlayerLogic *targetPlayer,
QString targetCard,
bool playerTarget);
void logCreateToken(Player *player, QString cardName, QString pt, bool faceDown);
void logDeckSelect(Player *player, QString deckHash, int sideboardSize);
void logDestroyCard(Player *player, QString cardName);
void logDrawCards(Player *player, int number, bool deckIsEmpty);
void logDumpZone(Player *player, CardZoneLogic *zone, int numberCards, bool isReversed = false);
void logFlipCard(Player *player, QString cardName, bool faceDown);
void logCreateToken(PlayerLogic *player, QString cardName, QString pt, bool faceDown);
void logDeckSelect(PlayerLogic *player, QString deckHash, int sideboardSize);
void logDestroyCard(PlayerLogic *player, QString cardName);
void logDrawCards(PlayerLogic *player, int number, bool deckIsEmpty);
void logDumpZone(PlayerLogic *player, CardZoneLogic *zone, int numberCards, bool isReversed = false);
void logFlipCard(PlayerLogic *player, QString cardName, bool faceDown);
void logGameClosed();
void logGameStart();
void logGameFlooded();
void logJoin(Player *player);
void logJoin(PlayerLogic *player);
void logJoinSpectator(QString name);
void logKicked();
void logLeave(Player *player, QString reason);
void logLeave(PlayerLogic *player, QString reason);
void logLeaveSpectator(QString name, QString reason);
void logNotReadyStart(Player *player);
void logMoveCard(Player *player,
void logNotReadyStart(PlayerLogic *player);
void logMoveCard(PlayerLogic *player,
CardItem *card,
CardZoneLogic *startZone,
int oldX,
CardZoneLogic *targetZone,
int newX);
void logMulligan(Player *player, int number);
void logMulligan(PlayerLogic *player, int number);
void logReplayStarted(int gameId);
void logReadyStart(Player *player);
void logRevealCards(Player *player,
void logReadyStart(PlayerLogic *player);
void logRevealCards(PlayerLogic *player,
CardZoneLogic *zone,
int cardId,
QString cardName,
Player *otherPlayer,
PlayerLogic *otherPlayer,
bool faceDown,
int amount,
bool isLentToAnotherPlayer);
void logReverseTurn(Player *player, bool reversed);
void logRollDie(Player *player, int sides, const QList<uint> &rolls);
void logSay(Player *player, QString message);
void logReverseTurn(PlayerLogic *player, bool reversed);
void logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls);
void logSay(PlayerLogic *player, QString message);
void logSetActivePhase(int phase);
void logSetActivePlayer(Player *player);
void logSetAnnotation(Player *player, CardItem *card, QString newAnnotation);
void logSetCardCounter(Player *player, QString cardName, int counterId, int value, int oldValue);
void logSetCounter(Player *player, QString counterName, int value, int oldValue);
void logSetDoesntUntap(Player *player, CardItem *card, bool doesntUntap);
void logSetPT(Player *player, CardItem *card, QString newPT);
void logSetSideboardLock(Player *player, bool locked);
void logSetTapped(Player *player, CardItem *card, bool tapped);
void logShuffle(Player *player, CardZoneLogic *zone, int start, int end);
void logSetActivePlayer(PlayerLogic *player);
void logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation);
void logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue);
void logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue);
void logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap);
void logSetPT(PlayerLogic *player, CardItem *card, QString newPT);
void logSetSideboardLock(PlayerLogic *player, bool locked);
void logSetTapped(PlayerLogic *player, CardItem *card, bool tapped);
void logShuffle(PlayerLogic *player, CardZoneLogic *zone, int start, int end);
void logSpectatorSay(const ServerInfo_User &spectator, QString message);
void logUnattachCard(Player *player, QString cardName);
void logUndoDraw(Player *player, QString cardName);
void logUnattachCard(PlayerLogic *player, QString cardName);
void logUndoDraw(PlayerLogic *player, QString cardName);
void logUndoDrawFailed(PlayerLogic *player);
void setContextJudgeName(QString player);
void appendHtmlServerMessage(const QString &html,
bool optionalIsBold = false,

View file

@ -1,8 +1,8 @@
/**
* @file phase.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef PHASE_H
#define PHASE_H

View file

@ -21,8 +21,9 @@ PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_
activeAnimationTimer = new QTimer(this);
connect(activeAnimationTimer, &QTimer::timeout, this, &PhaseButton::updateAnimation);
activeAnimationTimer->setSingleShot(false);
} else
} else {
activeAnimationCounter = 9;
}
setCacheMode(DeviceCoordinateCache);
}
@ -63,8 +64,9 @@ void PhaseButton::setWidth(double _width)
void PhaseButton::setActive(bool _active)
{
if ((active == _active) || !highlightable)
if ((active == _active) || !highlightable) {
return;
}
active = _active;
activeAnimationTimer->start(25);
@ -72,8 +74,9 @@ void PhaseButton::setActive(bool _active)
void PhaseButton::updateAnimation()
{
if (!highlightable)
if (!highlightable) {
return;
}
// the counter ticks up to 10 when active and down to 0 when inactive
if (active && activeAnimationCounter < 10) {
@ -99,8 +102,9 @@ void PhaseButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * /*event*/)
void PhaseButton::triggerDoubleClickAction()
{
if (doubleClickAction)
if (doubleClickAction) {
doubleClickAction->trigger();
}
}
PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
@ -126,8 +130,9 @@ PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
buttonList << untapButton << upkeepButton << drawButton << main1Button << combatStartButton << combatAttackersButton
<< combatBlockersButton << combatDamageButton << combatEndButton << main2Button << cleanupButton;
for (auto &i : buttonList)
for (auto &i : buttonList) {
connect(i, &PhaseButton::clicked, this, &PhasesToolbar::phaseButtonClicked);
}
nextTurnButton = new PhaseButton("nextturn", this, nullptr, false);
connect(nextTurnButton, &PhaseButton::clicked, this, &PhasesToolbar::actNextTurn);
@ -144,8 +149,9 @@ QRectF PhasesToolbar::boundingRect() const
void PhasesToolbar::retranslateUi()
{
for (int i = 0; i < buttonList.size(); ++i)
for (int i = 0; i < buttonList.size(); ++i) {
buttonList[i]->setToolTip(getLongPhaseName(i));
}
}
QString PhasesToolbar::getLongPhaseName(int phase) const
@ -187,8 +193,9 @@ const double PhasesToolbar::marginSize = 3;
void PhasesToolbar::rearrangeButtons()
{
for (auto &i : buttonList)
for (auto &i : buttonList) {
i->setWidth(symbolSize);
}
nextTurnButton->setWidth(symbolSize);
double y = marginSize;
@ -226,11 +233,13 @@ void PhasesToolbar::setHeight(double _height)
void PhasesToolbar::setActivePhase(int phase)
{
if (phase >= buttonList.size())
if (phase >= buttonList.size()) {
return;
}
for (int i = 0; i < buttonList.size(); ++i)
for (int i = 0; i < buttonList.size(); ++i) {
buttonList[i]->setActive(i == phase);
}
}
void PhasesToolbar::triggerPhaseAction(int phase)
@ -243,8 +252,9 @@ void PhasesToolbar::triggerPhaseAction(int phase)
void PhasesToolbar::phaseButtonClicked()
{
auto *button = qobject_cast<PhaseButton *>(sender());
if (button->getActive())
if (button->getActive()) {
button->triggerDoubleClickAction();
}
Command_SetActivePhase cmd;
cmd.set_phase(static_cast<google::protobuf::uint32>(buttonList.indexOf(button)));

View file

@ -2,8 +2,8 @@
* @file phases_toolbar.h
* @ingroup GameGraphics
* @ingroup GameWidgets
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef PHASESTOOLBAR_H
#define PHASESTOOLBAR_H
@ -21,7 +21,7 @@ namespace protobuf
class Message;
}
} // namespace google
class Player;
class PlayerLogic;
class GameCommand;
class PhaseButton : public QObject, public QGraphicsItem

View file

@ -1,8 +1,8 @@
/**
* @file card_menu_action_type.h
* @ingroup GameMenusPlayers
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_CARD_MENU_ACTION_TYPE_H
#define COCKATRICE_CARD_MENU_ACTION_TYPE_H

View file

@ -1,8 +1,8 @@
/**
* @file event_processing_options.h
* @ingroup GameLogicPlayers
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_EVENT_PROCESSING_OPTIONS_H
#define COCKATRICE_EVENT_PROCESSING_OPTIONS_H

View file

@ -19,13 +19,13 @@ class AbstractPlayerComponent
public:
virtual ~AbstractPlayerComponent() = default;
/// Bind keyboard shortcuts. Called when this player gains focus.
/** @brief Bind keyboard shortcuts. Called when this player gains focus. */
virtual void setShortcutsActive() = 0;
/// Unbind keyboard shortcuts. Called when this player loses focus.
/** @brief Unbind keyboard shortcuts. Called when this player loses focus. */
virtual void setShortcutsInactive() = 0;
/// Retranslate all user-visible strings. Called on language change.
/** @brief Retranslate all user-visible strings. Called on language change. */
virtual void retranslateUi() = 0;
};

View file

@ -3,23 +3,40 @@
#include "../../../client/settings/card_counter_settings.h"
#include "../../../interface/widgets/tabs/tab_game.h"
#include "../../board/card_item.h"
#include "../../zones/logic/view_zone_logic.h"
#include "../../zones/view_zone_logic.h"
#include "../card_menu_action_type.h"
#include "../player.h"
#include "../player_actions.h"
#include "../player_logic.h"
#include "move_menu.h"
#include "pt_menu.h"
#include <QPainter>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/card/relation/card_relation.h>
#include <libcockatrice/utility/zone_names.h>
CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive)
/**
* @brief Creates a circular icon filled with the specified color.
*/
static QIcon createCircleIcon(const QColor &color)
{
QPixmap pixmap(32, 32);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
painter.setBrush(color);
painter.drawEllipse(pixmap.rect());
return QIcon(pixmap);
}
CardMenu::CardMenu(PlayerLogic *_player, const CardItem *_card, bool _shortcutsActive)
: player(_player), card(_card), shortcutsActive(_shortcutsActive)
{
auto playerActions = player->getPlayerActions();
const QList<Player *> &players = player->getGame()->getPlayerManager()->getPlayers().values();
const QList<PlayerLogic *> &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto playerToAdd : players) {
if (playerToAdd == player) {
@ -62,6 +79,9 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive
aSelectColumn = new QAction(this);
connect(aSelectColumn, &QAction::triggered, playerActions, &PlayerActions::actSelectColumn);
aReduceLifeByPower = new QAction(this);
connect(aReduceLifeByPower, &QAction::triggered, playerActions, &PlayerActions::actReduceLifeByPower);
aPlay = new QAction(this);
connect(aPlay, &QAction::triggered, playerActions, &PlayerActions::actPlay);
aHide = new QAction(this);
@ -74,9 +94,21 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive
mCardCounters = new QMenu;
for (int i = 0; i < 6; ++i) {
QColor color = SettingsCache::instance().cardCounters().color(i);
QIcon circleIcon = createCircleIcon(color);
auto *tempAddCounter = new QAction(this);
tempAddCounter->setIconVisibleInMenu(true);
tempAddCounter->setIcon(circleIcon);
auto *tempRemoveCounter = new QAction(this);
tempRemoveCounter->setIconVisibleInMenu(true);
tempRemoveCounter->setIcon(circleIcon);
auto *tempSetCounter = new QAction(this);
tempSetCounter->setIconVisibleInMenu(true);
tempSetCounter->setIcon(circleIcon);
aAddCounter.append(tempAddCounter);
aRemoveCounter.append(tempRemoveCounter);
aSetCounter.append(tempSetCounter);
@ -134,7 +166,7 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive
}
}
void CardMenu::removePlayer(Player *playerToRemove)
void CardMenu::removePlayer(PlayerLogic *playerToRemove)
{
for (auto it = playersInfo.begin(); it != playersInfo.end();) {
if (it->second == playerToRemove->getPlayerInfo()->getId()) {
@ -153,6 +185,8 @@ void CardMenu::createTableMenu(bool canModifyCard)
addSeparator();
addAction(aClone);
addSeparator();
addAction(aReduceLifeByPower);
addSeparator();
addAction(aSelectAll);
addAction(aSelectRow);
addRelatedCardView();
@ -179,6 +213,8 @@ void CardMenu::createTableMenu(bool canModifyCard)
addMenu(new PtMenu(player));
addAction(aSetAnnotation);
addSeparator();
addAction(aReduceLifeByPower);
addSeparator();
addAction(aSelectAll);
addAction(aSelectRow);
@ -463,6 +499,7 @@ void CardMenu::retranslateUi()
aUnattach->setText(tr("Unattac&h"));
aDrawArrow->setText(tr("&Draw arrow..."));
aSetAnnotation->setText(tr("&Set annotation..."));
aReduceLifeByPower->setText(tr("Reduce life by power"));
mCardCounters->setTitle(tr("Ca&rd counters"));
@ -497,6 +534,7 @@ void CardMenu::setShortcutsActive()
aUnattach->setShortcuts(shortcuts.getShortcut("Player/aUnattach"));
aDrawArrow->setShortcuts(shortcuts.getShortcut("Player/aDrawArrow"));
aSetAnnotation->setShortcuts(shortcuts.getShortcut("Player/aSetAnnotation"));
aReduceLifeByPower->setShortcuts(shortcuts.getShortcut("Player/aReduceLifeByPower"));
aSelectAll->setShortcuts(shortcuts.getShortcut("Player/aSelectAll"));
aSelectRow->setShortcuts(shortcuts.getShortcut("Player/aSelectRow"));

View file

@ -1,8 +1,8 @@
/**
* @file card_menu.h
* @ingroup GameMenusCards
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_CARD_MENU_H
#define COCKATRICE_CARD_MENU_H
@ -10,14 +10,14 @@
#include <QMenu>
class CardItem;
class Player;
class PlayerLogic;
class CardMenu : public QMenu
{
Q_OBJECT
public:
explicit CardMenu(Player *player, const CardItem *card, bool shortcutsActive);
void removePlayer(Player *playerToRemove);
explicit CardMenu(PlayerLogic *player, const CardItem *card, bool shortcutsActive);
void removePlayer(PlayerLogic *playerToRemove);
void createTableMenu(bool canModifyCard);
void createStackMenu(bool canModifyCard);
void createGraveyardOrExileMenu(bool canModifyCard);
@ -36,11 +36,12 @@ public:
QAction *aFlip, *aPeek;
QAction *aAttach, *aUnattach;
QAction *aSetAnnotation;
QAction *aReduceLifeByPower;
QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter;
private:
Player *player;
PlayerLogic *player;
const CardItem *card;
QList<QPair<QString, int>> playersInfo;
bool shortcutsActive;

View file

@ -1,13 +1,13 @@
#include "custom_zone_menu.h"
#include "../player.h"
#include "../player_logic.h"
CustomZoneMenu::CustomZoneMenu(Player *_player) : player(_player)
CustomZoneMenu::CustomZoneMenu(PlayerLogic *_player) : player(_player)
{
menuAction()->setVisible(false);
connect(player, &Player::clearCustomZonesMenu, this, &CustomZoneMenu::clearCustomZonesMenu);
connect(player, &Player::addViewCustomZoneActionToCustomZoneMenu, this,
connect(player, &PlayerLogic::clearCustomZonesMenu, this, &CustomZoneMenu::clearCustomZonesMenu);
connect(player, &PlayerLogic::addViewCustomZoneActionToCustomZoneMenu, this,
&CustomZoneMenu::addViewCustomZoneActionToCustomZoneMenu);
retranslateUi();

View file

@ -1,8 +1,8 @@
/**
* @file custom_zone_menu.h
* @ingroup GameMenusZones
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_CUSTOM_ZONE_MENU_H
#define COCKATRICE_CUSTOM_ZONE_MENU_H
@ -11,12 +11,12 @@
#include <QMenu>
class Player;
class PlayerLogic;
class CustomZoneMenu : public QMenu, public AbstractPlayerComponent
{
Q_OBJECT
public:
explicit CustomZoneMenu(Player *player);
explicit CustomZoneMenu(PlayerLogic *player);
void retranslateUi() override;
void setShortcutsActive() override
{
@ -26,7 +26,7 @@ public:
}
private:
Player *player;
PlayerLogic *player;
private slots:
void clearCustomZonesMenu();
void addViewCustomZoneActionToCustomZoneMenu(QString zoneName);

View file

@ -1,14 +1,14 @@
#include "grave_menu.h"
#include "../../abstract_game.h"
#include "../player.h"
#include "../player_actions.h"
#include "../player_logic.h"
#include <QAction>
#include <QMenu>
#include <libcockatrice/utility/zone_names.h>
GraveyardMenu::GraveyardMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
GraveyardMenu::GraveyardMenu(PlayerLogic *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
createMoveActions();
createViewActions();
@ -78,8 +78,9 @@ void GraveyardMenu::populateRevealRandomMenuWithActivePlayers()
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player)
if (other == player) {
continue;
}
QAction *a = mRevealRandomGraveyardCard->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &GraveyardMenu::onRevealRandomTriggered);

View file

@ -1,8 +1,8 @@
/**
* @file grave_menu.h
* @ingroup GameMenusZones
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_GRAVE_MENU_H
#define COCKATRICE_GRAVE_MENU_H
@ -13,7 +13,7 @@
#include <QAction>
#include <QMenu>
class Player;
class PlayerLogic;
class GraveyardMenu : public TearOffMenu, public AbstractPlayerComponent
{
Q_OBJECT
@ -21,7 +21,7 @@ signals:
void newPlayerActionCreated(QAction *action);
public:
explicit GraveyardMenu(Player *player, QWidget *parent = nullptr);
explicit GraveyardMenu(PlayerLogic *player, QWidget *parent = nullptr);
void createMoveActions();
void createViewActions();
void populateRevealRandomMenuWithActivePlayers();
@ -40,7 +40,7 @@ public:
QAction *aMoveGraveToRfg = nullptr;
private:
Player *player;
PlayerLogic *player;
};
#endif // COCKATRICE_GRAVE_MENU_H

View file

@ -2,16 +2,16 @@
#include "../../../client/settings/cache_settings.h"
#include "../../../client/settings/shortcuts_settings.h"
#include "../../../game_graphics/zones/hand_zone.h"
#include "../../abstract_game.h"
#include "../../zones/hand_zone.h"
#include "../player.h"
#include "../player_actions.h"
#include "../player_logic.h"
#include <QAction>
#include <QMenu>
#include <libcockatrice/utility/zone_names.h>
HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : TearOffMenu(parent), player(_player)
HandMenu::HandMenu(PlayerLogic *_player, PlayerActions *actions, QWidget *parent) : TearOffMenu(parent), player(_player)
{
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
aViewHand = new QAction(this);
@ -168,8 +168,9 @@ void HandMenu::populateRevealHandMenuWithActivePlayers()
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player)
if (other == player) {
continue;
}
QAction *a = mRevealHand->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &HandMenu::onRevealHandTriggered);
@ -186,8 +187,9 @@ void HandMenu::populateRevealRandomHandCardMenuWithActivePlayers()
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player)
if (other == player) {
continue;
}
QAction *a = mRevealRandomHandCard->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardTriggered);
@ -197,8 +199,9 @@ void HandMenu::populateRevealRandomHandCardMenuWithActivePlayers()
void HandMenu::onRevealHandTriggered()
{
auto *action = qobject_cast<QAction *>(sender());
if (!action)
if (!action) {
return;
}
const int targetId = action->data().toInt();
player->getPlayerActions()->actRevealHand(targetId);
@ -207,8 +210,9 @@ void HandMenu::onRevealHandTriggered()
void HandMenu::onRevealRandomHandCardTriggered()
{
auto *action = qobject_cast<QAction *>(sender());
if (!action)
if (!action) {
return;
}
const int targetId = action->data().toInt();
player->getPlayerActions()->actRevealRandomHandCard(targetId);

View file

@ -1,8 +1,8 @@
/**
* @file hand_menu.h
* @ingroup GameMenusZones
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_HAND_MENU_H
#define COCKATRICE_HAND_MENU_H
@ -13,7 +13,7 @@
#include <QAction>
#include <QMenu>
class Player;
class PlayerLogic;
class PlayerActions;
class HandMenu : public TearOffMenu, public AbstractPlayerComponent
@ -21,7 +21,7 @@ class HandMenu : public TearOffMenu, public AbstractPlayerComponent
Q_OBJECT
public:
HandMenu(Player *player, PlayerActions *actions, QWidget *parent = nullptr);
HandMenu(PlayerLogic *player, PlayerActions *actions, QWidget *parent = nullptr);
QMenu *revealHandMenu() const
{
@ -43,7 +43,7 @@ private slots:
void onRevealRandomHandCardTriggered();
private:
Player *player;
PlayerLogic *player;
QAction *aViewHand = nullptr;
QAction *aMulligan = nullptr;

View file

@ -4,13 +4,13 @@
#include "../../../client/settings/shortcuts_settings.h"
#include "../../../interface/widgets/tabs/tab_game.h"
#include "../../abstract_game.h"
#include "../player.h"
#include "../player_actions.h"
#include "../player_logic.h"
#include <QAction>
#include <QMenu>
LibraryMenu::LibraryMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
LibraryMenu::LibraryMenu(PlayerLogic *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
createDrawActions();
createShuffleActions();
@ -75,8 +75,8 @@ LibraryMenu::LibraryMenu(Player *_player, QWidget *parent) : TearOffMenu(parent)
bottomLibraryMenu->addSeparator();
bottomLibraryMenu->addAction(aShuffleBottomCards);
connect(player, &Player::resetTopCardMenuActions, this, &LibraryMenu::resetTopCardMenuActions);
connect(player, &Player::deckChanged, this, &LibraryMenu::enableOpenInDeckEditorAction);
connect(player, &PlayerLogic::resetTopCardMenuActions, this, &LibraryMenu::resetTopCardMenuActions);
connect(player, &PlayerLogic::deckChanged, this, &LibraryMenu::enableOpenInDeckEditorAction);
retranslateUi();
}
@ -265,8 +265,9 @@ void LibraryMenu::populateRevealLibraryMenuWithActivePlayers()
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player)
if (other == player) {
continue;
}
QAction *a = mRevealLibrary->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &LibraryMenu::onRevealLibraryTriggered);
@ -279,8 +280,9 @@ void LibraryMenu::populateLendLibraryMenuWithActivePlayers()
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player)
if (other == player) {
continue;
}
QAction *a = mLendLibrary->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &LibraryMenu::onLendLibraryTriggered);
@ -299,8 +301,9 @@ void LibraryMenu::populateRevealTopCardMenuWithActivePlayers()
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) {
if (other == player)
if (other == player) {
continue;
}
QAction *a = mRevealTopCard->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &LibraryMenu::onRevealTopCardTriggered);

View file

@ -1,8 +1,8 @@
/**
* @file library_menu.h
* @ingroup GameMenusZones
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_LIBRARY_MENU_H
#define COCKATRICE_LIBRARY_MENU_H
@ -13,7 +13,7 @@
#include <QAction>
#include <QMenu>
class Player;
class PlayerLogic;
class PlayerActions;
class LibraryMenu : public TearOffMenu, public AbstractPlayerComponent
@ -24,7 +24,7 @@ public slots:
void resetTopCardMenuActions();
public:
LibraryMenu(Player *player, QWidget *parent = nullptr);
LibraryMenu(PlayerLogic *player, QWidget *parent = nullptr);
void createDrawActions();
void createShuffleActions();
void createMoveActions();
@ -111,7 +111,7 @@ public:
int defaultNumberTopCards = 1;
private:
Player *player;
PlayerLogic *player;
};
#endif // COCKATRICE_LIBRARY_MENU_H

View file

@ -1,10 +1,10 @@
#include "move_menu.h"
#include "../card_menu_action_type.h"
#include "../player.h"
#include "../player_actions.h"
#include "../player_logic.h"
MoveMenu::MoveMenu(Player *player) : QMenu(tr("Move to"))
MoveMenu::MoveMenu(PlayerLogic *player) : QMenu(tr("Move to"))
{
aMoveToTopLibrary = new QAction(this);
aMoveToTopLibrary->setData(cmMoveToTopLibrary);

View file

@ -1,20 +1,20 @@
/**
* @file move_menu.h
* @ingroup GameMenusZones
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_MOVE_MENU_H
#define COCKATRICE_MOVE_MENU_H
#include <QMenu>
class Player;
class PlayerLogic;
class MoveMenu : public QMenu
{
Q_OBJECT
public:
explicit MoveMenu(Player *player);
explicit MoveMenu(PlayerLogic *player);
void setShortcutsActive();
void retranslateUi();

View file

@ -1,16 +1,16 @@
#include "player_menu.h"
#include "../../../game_graphics/zones/hand_zone.h"
#include "../../../game_graphics/zones/pile_zone.h"
#include "../../../game_graphics/zones/table_zone.h"
#include "../../../interface/widgets/tabs/tab_game.h"
#include "../../board/card_item.h"
#include "../../zones/hand_zone.h"
#include "../../zones/pile_zone.h"
#include "../../zones/table_zone.h"
#include "card_menu.h"
#include "hand_menu.h"
#include <libcockatrice/protocol/pb/command_reveal_cards.pb.h>
PlayerMenu::PlayerMenu(Player *_player) : QObject(_player), player(_player)
PlayerMenu::PlayerMenu(PlayerLogic *_player) : QObject(_player), player(_player)
{
playerMenu = new TearOffMenu();
@ -97,10 +97,7 @@ void PlayerMenu::retranslateUi()
countersMenu->setTitle(tr("&Counters"));
}
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
while (counterIterator.hasNext()) {
counterIterator.next().value()->retranslateUi();
}
emit retranslateRequested();
}
void PlayerMenu::refreshShortcuts()
@ -120,30 +117,17 @@ void PlayerMenu::refreshShortcuts()
void PlayerMenu::setShortcutsActive()
{
shortcutsActive = true;
for (auto *component : managedComponents) {
component->setShortcutsActive();
}
// Counters implement AbstractPlayerComponent but are iterated via Player::counters
// (the authoritative source) rather than managedComponents to avoid a redundant
// list that must stay in sync with the map.
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
while (counterIterator.hasNext()) {
counterIterator.next().value()->setShortcutsActive();
for (auto *c : managedComponents) {
c->setShortcutsActive();
}
emit shortcutsActivated();
}
void PlayerMenu::setShortcutsInactive()
{
shortcutsActive = false;
for (auto *component : managedComponents) {
component->setShortcutsInactive();
}
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
while (counterIterator.hasNext()) {
counterIterator.next().value()->setShortcutsInactive();
for (auto *c : managedComponents) {
c->setShortcutsInactive();
}
emit shortcutsDeactivated();
}

View file

@ -8,7 +8,7 @@
#define COCKATRICE_PLAYER_MENU_H
#include "../../../interface/widgets/menus/tearoff_menu.h"
#include "../player.h"
#include "../player_logic.h"
#include "custom_zone_menu.h"
#include "grave_menu.h"
#include "hand_menu.h"
@ -29,6 +29,9 @@ class PlayerMenu : public QObject
signals:
void cardMenuUpdated(QMenu *cardMenu);
void shortcutsActivated();
void shortcutsDeactivated();
void retranslateRequested();
public slots:
void setMenusForGraphicItems();
@ -37,8 +40,8 @@ private slots:
void refreshShortcuts();
public:
explicit PlayerMenu(Player *player);
/// Lifecycle methods: delegate to all managedComponents, plus counters separately via player->getCounters().
explicit PlayerMenu(PlayerLogic *player);
/** @brief Retranslate all user-visible strings. Called on language change. */
void retranslateUi();
QMenu *updateCardMenu(const CardItem *card);
@ -68,13 +71,13 @@ public:
return shortcutsActive;
}
/// Delegates to all managedComponents, plus counters separately.
/** @brief Bind keyboard shortcuts. Called when this player gains focus. */
void setShortcutsActive();
/// Delegates to all managedComponents, plus counters separately.
/** @brief Unbind keyboard shortcuts. Called when this player loses focus. */
void setShortcutsInactive();
private:
Player *player;
PlayerLogic *player;
TearOffMenu *playerMenu;
QMenu *countersMenu;
HandMenu *handMenu;
@ -86,11 +89,13 @@ private:
SayMenu *sayMenu;
CustomZoneMenu *customZonesMenu;
/// Drives AbstractPlayerComponent lifecycle delegation. Counters are iterated separately via player->getCounters().
/** @brief Drives AbstractPlayerComponent lifecycle delegation. Counters are iterated separately via
* player->getCounters().
*/
QList<AbstractPlayerComponent *> managedComponents;
bool shortcutsActive = false;
/// Creates component, adds it as a submenu of playerMenu, and registers in managedComponents.
/** @brief Creates component, adds it as a submenu of playerMenu, and registers in managedComponents. */
template <typename MenuT, typename... Args> MenuT *addManagedMenu(Args &&...args)
{
auto *menu = new MenuT(std::forward<Args>(args)...);
@ -99,7 +104,7 @@ private:
return menu;
}
/// Creates component and registers in managedComponents, but does NOT add it as a submenu.
/** @brief Creates component and registers in managedComponents, but does NOT add it as a submenu. */
template <typename ComponentT, typename... Args> ComponentT *createManagedComponent(Args &&...args)
{
auto *component = new ComponentT(std::forward<Args>(args)...);

View file

@ -1,9 +1,9 @@
#include "pt_menu.h"
#include "../player.h"
#include "../player_actions.h"
#include "../player_logic.h"
PtMenu::PtMenu(Player *player) : QMenu(tr("Power / toughness"))
PtMenu::PtMenu(PlayerLogic *player) : QMenu(tr("Power / toughness"))
{
PlayerActions *playerActions = player->getPlayerActions();

View file

@ -1,21 +1,21 @@
/**
* @file pt_menu.h
* @ingroup GameMenusCards
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_PT_MENU_H
#define COCKATRICE_PT_MENU_H
#include <QMenu>
class Player;
class PlayerLogic;
class PtMenu : public QMenu
{
Q_OBJECT
public:
explicit PtMenu(Player *player);
explicit PtMenu(PlayerLogic *player);
void retranslateUi();
void setShortcutsActive();

View file

@ -1,11 +1,11 @@
#include "rfg_menu.h"
#include "../player.h"
#include "../player_actions.h"
#include "../player_logic.h"
#include <libcockatrice/utility/zone_names.h>
RfgMenu::RfgMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
RfgMenu::RfgMenu(PlayerLogic *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{
createMoveActions();
createViewActions();

Some files were not shown because too many files have changed in this diff Show more