mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-21 00:55:09 -07:00
[Game] Playmats (#7101)
* [Game] Playmats Took 19 seconds Took 1 minute * [Playmats] Add fixed override and configurable fallbacks to settings. Took 29 minutes Took 43 seconds * Add main to test. Took 1 minute Took 29 seconds * Move settings to own group Took 11 minutes * Some attempts to refresh macOS compositor Took 2 minutes * Try something else Took 17 minutes * Don't manipulate live list Took 11 minutes * Change things about resolution, address comments. Took 45 minutes Took 12 minutes * Comments. Took 14 minutes Took 8 seconds * Re-order settings menu location Took 2 minutes * Rename PlaymatResolution to Info and add enums Took 8 minutes --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
74a454552a
commit
9eafd90a91
52 changed files with 1931 additions and 28 deletions
|
|
@ -11,6 +11,7 @@ set(HEADERS
|
|||
libcockatrice/deck_list/deck_list_history_manager.h
|
||||
libcockatrice/deck_list/deck_list_node_tree.h
|
||||
libcockatrice/deck_list/deck_list_memento.h
|
||||
libcockatrice/deck_list/playmat_resolver.h
|
||||
libcockatrice/deck_list/sideboard_plan.h
|
||||
)
|
||||
|
||||
|
|
@ -26,6 +27,7 @@ add_library(
|
|||
libcockatrice/deck_list/deck_list.cpp
|
||||
libcockatrice/deck_list/deck_list_history_manager.cpp
|
||||
libcockatrice/deck_list/deck_list_node_tree.cpp
|
||||
libcockatrice/deck_list/playmat_resolver.cpp
|
||||
libcockatrice/deck_list/sideboard_plan.cpp
|
||||
)
|
||||
|
||||
|
|
@ -33,4 +35,7 @@ add_dependencies(libcockatrice_deck_list libcockatrice_protocol)
|
|||
|
||||
target_include_directories(libcockatrice_deck_list PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(libcockatrice_deck_list PUBLIC libcockatrice_protocol libcockatrice_utility ${QT_CORE_MODULE})
|
||||
target_link_libraries(
|
||||
libcockatrice_deck_list PUBLIC libcockatrice_interfaces libcockatrice_protocol libcockatrice_utility
|
||||
${QT_CORE_MODULE}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ static const QString CURRENT_SIDEBOARD_PLAN_KEY = "";
|
|||
|
||||
bool DeckList::Metadata::isEmpty() const
|
||||
{
|
||||
return name.isEmpty() && comments.isEmpty() && bannerCard.isEmpty() && tags.isEmpty();
|
||||
return name.isEmpty() && comments.isEmpty() && bannerCard.isEmpty() && tags.isEmpty() && playmat.card.isEmpty();
|
||||
}
|
||||
|
||||
DeckList::DeckList()
|
||||
|
|
@ -74,6 +74,36 @@ bool DeckList::readElement(QXmlStreamReader *xml)
|
|||
QString providerId = xml->attributes().value("providerId").toString();
|
||||
QString cardName = xml->readElementText();
|
||||
metadata.bannerCard = {cardName, providerId};
|
||||
} else if (childName == "playmatCard") {
|
||||
QString providerId = xml->attributes().value("providerId").toString();
|
||||
bool ok;
|
||||
QString marginLStr = xml->attributes().value("marginPctL").toString();
|
||||
QString marginRStr = xml->attributes().value("marginPctR").toString();
|
||||
QString vOffStr = xml->attributes().value("verticalOffset").toString();
|
||||
QString zoomStr = xml->attributes().value("zoom").toString();
|
||||
QString cardName = xml->readElementText();
|
||||
PlaymatInfo playmat;
|
||||
playmat.card = {cardName, providerId};
|
||||
// Clamp to the same ranges as the settings dialog and the remote
|
||||
// player-properties path so malformed deck files cannot produce
|
||||
// degenerate art rectangles (e.g. a zoom of 0 dividing by zero).
|
||||
playmat.params.marginPctL = qBound(0.0, marginLStr.toDouble(&ok), 0.95);
|
||||
if (!ok) {
|
||||
playmat.params.marginPctL = 0.07;
|
||||
}
|
||||
playmat.params.marginPctR = qBound(0.0, marginRStr.toDouble(&ok), 0.95);
|
||||
if (!ok) {
|
||||
playmat.params.marginPctR = 0.07;
|
||||
}
|
||||
playmat.params.verticalOffset = qBound(0.0, vOffStr.toDouble(&ok), 1.0);
|
||||
if (!ok) {
|
||||
playmat.params.verticalOffset = 0.33;
|
||||
}
|
||||
playmat.params.zoom = qBound(0.1, zoomStr.toDouble(&ok), 4.0);
|
||||
if (!ok) {
|
||||
playmat.params.zoom = 1.0;
|
||||
}
|
||||
metadata.playmat = playmat;
|
||||
} else if (childName == "tags") {
|
||||
metadata.tags.clear(); // Clear existing tags
|
||||
while (xml->readNextStartElement()) {
|
||||
|
|
@ -104,6 +134,16 @@ static void writeMetadata(QXmlStreamWriter *xml, const DeckList::Metadata &metad
|
|||
xml->writeAttribute("providerId", metadata.bannerCard.providerId);
|
||||
xml->writeCharacters(metadata.bannerCard.name);
|
||||
xml->writeEndElement();
|
||||
if (!metadata.playmat.card.isEmpty()) {
|
||||
xml->writeStartElement("playmatCard");
|
||||
xml->writeAttribute("providerId", metadata.playmat.card.providerId);
|
||||
xml->writeAttribute("marginPctL", QString::number(metadata.playmat.params.marginPctL, 'f', 4));
|
||||
xml->writeAttribute("marginPctR", QString::number(metadata.playmat.params.marginPctR, 'f', 4));
|
||||
xml->writeAttribute("verticalOffset", QString::number(metadata.playmat.params.verticalOffset, 'f', 4));
|
||||
xml->writeAttribute("zoom", QString::number(metadata.playmat.params.zoom, 'f', 4));
|
||||
xml->writeCharacters(metadata.playmat.card.name);
|
||||
xml->writeEndElement();
|
||||
}
|
||||
xml->writeTextElement("comments", metadata.comments);
|
||||
|
||||
// Write tags
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
#include <QMap>
|
||||
#include <QVector>
|
||||
#include <QtCore/QXmlStreamReader>
|
||||
#include <libcockatrice/utility/card_ref.h>
|
||||
#include <libcockatrice/utility/playmat_params.h>
|
||||
|
||||
class AbstractDecklistNode;
|
||||
class DecklistCardNode;
|
||||
|
|
@ -70,6 +70,7 @@ public:
|
|||
CardRef bannerCard; ///< Optional representative card for the deck.
|
||||
QStringList tags; ///< User-defined tags for deck classification.
|
||||
QString lastLoadedTimestamp; ///< Timestamp string of last load.
|
||||
PlaymatInfo playmat; ///< Optional playmat background for table+stack zones.
|
||||
|
||||
/**
|
||||
* @brief Checks if all values (except for lastLoadedTimestamp) in the metadata is empty.
|
||||
|
|
@ -115,6 +116,10 @@ public:
|
|||
{
|
||||
metadata.bannerCard = _bannerCard;
|
||||
}
|
||||
void setPlaymat(const PlaymatInfo &_playmat = {})
|
||||
{
|
||||
metadata.playmat = _playmat;
|
||||
}
|
||||
void setLastLoadedTimestamp(const QString &_lastLoadedTimestamp = QString())
|
||||
{
|
||||
metadata.lastLoadedTimestamp = _lastLoadedTimestamp;
|
||||
|
|
@ -170,6 +175,10 @@ public:
|
|||
{
|
||||
return metadata.bannerCard;
|
||||
}
|
||||
PlaymatInfo getPlaymat() const
|
||||
{
|
||||
return metadata.playmat;
|
||||
}
|
||||
QString getLastLoadedTimestamp() const
|
||||
{
|
||||
return metadata.lastLoadedTimestamp;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
#include "playmat_resolver.h"
|
||||
|
||||
#include <QRandomGenerator>
|
||||
|
||||
PlaymatInfo resolveEffectivePlaymat(const DeckList &deck,
|
||||
const PlaymatInfo &force,
|
||||
const QList<PlaymatInfo> &fallbackList,
|
||||
PlaymatFallbackMode fallbackMode,
|
||||
int rotationIndex)
|
||||
{
|
||||
if (!force.card.isEmpty()) {
|
||||
return force;
|
||||
}
|
||||
|
||||
const PlaymatInfo &deckPlaymat = deck.getPlaymat();
|
||||
if (!deckPlaymat.card.isEmpty()) {
|
||||
return deckPlaymat;
|
||||
}
|
||||
|
||||
if (fallbackList.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
switch (fallbackMode) {
|
||||
case PlaymatFallbackModeFixed:
|
||||
return fallbackList.first();
|
||||
case PlaymatFallbackModeRoundRobin:
|
||||
return fallbackList.at(rotationIndex % fallbackList.size());
|
||||
case PlaymatFallbackModeRandom:
|
||||
return fallbackList.at(QRandomGenerator::global()->bounded(fallbackList.size()));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
PlaymatInfo resolvePlaymatForDeck(const DeckList &deck,
|
||||
const QList<PlaymatInfo> &fallbackList,
|
||||
PlaymatMode mode,
|
||||
PlaymatFallbackMode fallbackBehavior,
|
||||
int rotationIndex)
|
||||
{
|
||||
switch (mode) {
|
||||
case PlaymatModeOverrideDeck: {
|
||||
const DeckList emptyDeck;
|
||||
return resolveEffectivePlaymat(emptyDeck, {}, fallbackList, fallbackBehavior, rotationIndex);
|
||||
}
|
||||
case PlaymatModeFallback:
|
||||
return resolveEffectivePlaymat(deck, {}, fallbackList, fallbackBehavior, rotationIndex);
|
||||
case PlaymatModeDeckOnly:
|
||||
return deck.getPlaymat();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef COCKATRICE_PLAYMAT_RESOLVER_H
|
||||
#define COCKATRICE_PLAYMAT_RESOLVER_H
|
||||
|
||||
#include "deck_list.h"
|
||||
|
||||
#include <libcockatrice/interfaces/interface_interface_settings_provider.h>
|
||||
|
||||
/**
|
||||
* @brief Resolves the effective playmat for a deck per the resolution chain:
|
||||
* force override > deck-configured playmat > fallback list > none.
|
||||
*
|
||||
* @param deck The deck to resolve a playmat for.
|
||||
* @param force An optional user-level override; wins over everything. Pass an
|
||||
* empty @ref PlaymatInfo::card to skip it.
|
||||
* @param fallbackList User-level fallback playmats, consulted only when the
|
||||
* deck has no configured playmat.
|
||||
* @param fallbackMode How @p fallbackList is consulted (ignored when empty).
|
||||
* @param rotationIndex In/out cursor for @c PlaymatFallbackModeRoundRobin;
|
||||
* advanced once per call. Unused for the other modes.
|
||||
* @return The effective playmat; an empty @ref PlaymatInfo::card when
|
||||
* nothing in the chain resolves.
|
||||
*/
|
||||
PlaymatInfo resolveEffectivePlaymat(const DeckList &deck,
|
||||
const PlaymatInfo &force,
|
||||
const QList<PlaymatInfo> &fallbackList,
|
||||
PlaymatFallbackMode fallbackMode,
|
||||
int rotationIndex);
|
||||
|
||||
/**
|
||||
* @brief Resolves the playmat to display for a deck according to the user's
|
||||
* collection mode (@ref PlaymatMode), combining the deck with the
|
||||
* given fallback list.
|
||||
*
|
||||
* @param deck The deck to resolve a playmat for.
|
||||
* @param fallbackList User-level fallback playmats.
|
||||
* @param mode How the collection interacts with the deck-configured playmat.
|
||||
* @param fallbackBehavior How @p fallbackList is picked from.
|
||||
* @param rotationIndex Cursor for @c PlaymatFallbackModeRoundRobin.
|
||||
* @return The effective playmat; an empty @ref PlaymatInfo::card when nothing resolves.
|
||||
*/
|
||||
PlaymatInfo resolvePlaymatForDeck(const DeckList &deck,
|
||||
const QList<PlaymatInfo> &fallbackList,
|
||||
PlaymatMode mode,
|
||||
PlaymatFallbackMode fallbackBehavior,
|
||||
int rotationIndex);
|
||||
|
||||
#endif // COCKATRICE_PLAYMAT_RESOLVER_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue