mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-13 13:30:00 -08:00
Merge pull request #1 from Continuum-Universes-Studio/feature/continuumatrice-zone-bands
Continuumatrice: colored Front / Support / Command battlefield
This commit is contained in:
commit
ccab482668
3 changed files with 173 additions and 17 deletions
|
|
@ -12,6 +12,15 @@
|
|||
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QFont>
|
||||
#include <QFontDatabase>
|
||||
#include <QHash>
|
||||
#include <QPen>
|
||||
#include <QSettings>
|
||||
#include <QStringList>
|
||||
#include <QGradient>
|
||||
#include <QGraphicsItem>
|
||||
#include <QGraphicsScene>
|
||||
|
|
@ -71,6 +80,7 @@ TableZone::TableZone(TableZoneLogic *_logic, bool _mirrored, QGraphicsItem *pare
|
|||
|
||||
void TableZone::updateBg()
|
||||
{
|
||||
reloadBattlefieldAppearance();
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
@ -126,6 +136,8 @@ void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*opti
|
|||
painter->fillRect(boundingRect(), brush);
|
||||
}
|
||||
|
||||
paintBattlefieldRows(painter);
|
||||
|
||||
if (active) {
|
||||
paintZoneOutline(painter);
|
||||
} else {
|
||||
|
|
@ -141,7 +153,6 @@ void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*opti
|
|||
painter->fillRect(boundingRect(), shimmerColor);
|
||||
}
|
||||
|
||||
paintLandDivider(painter);
|
||||
}
|
||||
|
||||
void TableZone::onPlaymatChanged(bool active)
|
||||
|
|
@ -179,21 +190,127 @@ void TableZone::paintZoneOutline(QPainter *painter)
|
|||
painter->fillRect(QRectF(width - BOX_LINE_WIDTH, 0, BOX_LINE_WIDTH, height), QBrush(grad1));
|
||||
}
|
||||
|
||||
/**
|
||||
Render a division line for land placement
|
||||
|
||||
@painter QPainter object
|
||||
/**
|
||||
* Draw Front, Support, and Command on Cockatrice's existing three-row table.
|
||||
* This changes presentation only, not gameplay or network-zone identifiers.
|
||||
*/
|
||||
void TableZone::paintLandDivider(QPainter *painter)
|
||||
void TableZone::paintBattlefieldRows(QPainter *painter)
|
||||
{
|
||||
// Place the line 2 grid heights down then back it off just enough to allow
|
||||
// some space between a 3-card stack and the land area.
|
||||
qreal separatorY = MARGIN_TOP + 2 * (CardDimensions::HEIGHT + PADDING_Y) - STACKED_CARD_OFFSET_Y / 2;
|
||||
if (isInverted()) {
|
||||
separatorY = height - separatorY;
|
||||
painter->save();
|
||||
|
||||
const qreal rowStride = CardDimensions::HEIGHT + PADDING_Y;
|
||||
const bool inverted = isInverted();
|
||||
QFont font(zoneLabelFontFamily);
|
||||
font.setPixelSize(18);
|
||||
painter->setFont(font);
|
||||
|
||||
for (int visualRow = 0; visualRow < TableZoneLogic::ROW_COUNT; ++visualRow) {
|
||||
// Table logical grid Y: 0 = Command, 1 = Support, 2 = Front.
|
||||
const int row = inverted ? TableZoneLogic::ROW_COUNT - 1 - visualRow : visualRow;
|
||||
QString label;
|
||||
QColor color;
|
||||
|
||||
switch (row) {
|
||||
case 0:
|
||||
label = tr("COMMAND ZONE");
|
||||
color = commandZoneColor;
|
||||
break;
|
||||
case 1:
|
||||
label = tr("SUPPORT ZONE");
|
||||
color = supportZoneColor;
|
||||
break;
|
||||
default:
|
||||
label = tr("FRONT ZONE");
|
||||
color = frontZoneColor;
|
||||
break;
|
||||
}
|
||||
|
||||
const qreal top = visualRow * rowStride;
|
||||
const qreal bottom = visualRow == TableZoneLogic::ROW_COUNT - 1 ? height : top + rowStride;
|
||||
painter->fillRect(QRectF(0, top, width, bottom - top), color);
|
||||
|
||||
const QRectF labelRect(16, top + 3, qMax(0, width - 32), 24);
|
||||
painter->setPen(QColor(0, 0, 0, 210));
|
||||
painter->drawText(labelRect.translated(1, 1), Qt::AlignHCenter | Qt::AlignVCenter, label);
|
||||
painter->setPen(QColor(250, 248, 244));
|
||||
painter->drawText(labelRect, Qt::AlignHCenter | Qt::AlignVCenter, label);
|
||||
|
||||
if (visualRow > 0) {
|
||||
painter->setPen(QPen(QColor(255, 255, 255, 95), 2));
|
||||
painter->drawLine(QPointF(0, top), QPointF(width, top));
|
||||
}
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Each theme may provide a battlefield.ini and/or Continuumorphous font file.
|
||||
* Optional assets avoid build failures when the proprietary font is absent.
|
||||
*/
|
||||
void TableZone::reloadBattlefieldAppearance()
|
||||
{
|
||||
frontZoneColor = QColor(142, 52, 61, 128);
|
||||
supportZoneColor = QColor(40, 105, 129, 128);
|
||||
commandZoneColor = QColor(94, 66, 140, 128);
|
||||
|
||||
const QString themePath = themeManager->getCurrentThemePath();
|
||||
if (!themePath.isEmpty()) {
|
||||
const QString iniPath = QDir(themePath).filePath(QStringLiteral("battlefield.ini"));
|
||||
if (QFileInfo::exists(iniPath)) {
|
||||
QSettings settings(iniPath, QSettings::IniFormat);
|
||||
const auto readColor = [&settings](const QString &key, const QColor &fallback) {
|
||||
const QColor parsed(settings.value(key, fallback.name(QColor::HexArgb)).toString());
|
||||
return parsed.isValid() ? parsed : fallback;
|
||||
};
|
||||
frontZoneColor = readColor(QStringLiteral("Zones/Front"), frontZoneColor);
|
||||
supportZoneColor = readColor(QStringLiteral("Zones/Support"), supportZoneColor);
|
||||
commandZoneColor = readColor(QStringLiteral("Zones/Command"), commandZoneColor);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList fontPaths;
|
||||
if (!themePath.isEmpty()) {
|
||||
const QDir themeDir(themePath);
|
||||
fontPaths << themeDir.filePath(QStringLiteral("fonts/Continuumorphous-Regular.ttf"))
|
||||
<< themeDir.filePath(QStringLiteral("fonts/Continuumorphous-Regular.otf"));
|
||||
}
|
||||
const QDir binaryDir(QCoreApplication::applicationDirPath());
|
||||
fontPaths << binaryDir.filePath(QStringLiteral("fonts/Continuumorphous-Regular.ttf"))
|
||||
<< binaryDir.filePath(QStringLiteral("fonts/Continuumorphous-Regular.otf"));
|
||||
|
||||
static QHash<QString, QString> loadedFamilies;
|
||||
zoneLabelFontFamily.clear();
|
||||
for (const QString &path : fontPaths) {
|
||||
if (!QFileInfo::isFile(path)) {
|
||||
continue;
|
||||
}
|
||||
if (loadedFamilies.contains(path)) {
|
||||
zoneLabelFontFamily = loadedFamilies.value(path);
|
||||
} else {
|
||||
const int id = QFontDatabase::addApplicationFont(path);
|
||||
const QStringList families = QFontDatabase::applicationFontFamilies(id);
|
||||
if (!families.isEmpty()) {
|
||||
zoneLabelFontFamily = families.constFirst();
|
||||
loadedFamilies.insert(path, zoneLabelFontFamily);
|
||||
}
|
||||
}
|
||||
if (!zoneLabelFontFamily.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (zoneLabelFontFamily.isEmpty()) {
|
||||
const QStringList installed = QFontDatabase::families();
|
||||
if (installed.contains(QStringLiteral("Continuumorphous Regular"), Qt::CaseInsensitive)) {
|
||||
zoneLabelFontFamily = QStringLiteral("Continuumorphous Regular");
|
||||
} else if (installed.contains(QStringLiteral("Continuumorphous"), Qt::CaseInsensitive)) {
|
||||
zoneLabelFontFamily = QStringLiteral("Continuumorphous");
|
||||
} else {
|
||||
zoneLabelFontFamily = QFont().family();
|
||||
}
|
||||
}
|
||||
painter->setPen(QColor(255, 255, 255, 40));
|
||||
painter->drawLine(QPointF(0, separatorY), QPointF(width, separatorY));
|
||||
}
|
||||
|
||||
void TableZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "../card_dimensions.h"
|
||||
#include "select_zone.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QElapsedTimer>
|
||||
#include <QMap>
|
||||
#include <QPixmap>
|
||||
|
|
@ -47,10 +48,10 @@ private:
|
|||
*/
|
||||
static const int MARGIN_LEFT = 20;
|
||||
static const int MARGIN_RIGHT = 15;
|
||||
static const int MARGIN_TOP = 10;
|
||||
static const int MARGIN_BOTTOM = 30;
|
||||
static const int MARGIN_TOP = 30; // Space for zone labels.
|
||||
static const int MARGIN_BOTTOM = 26;
|
||||
static const int PADDING_X = 35;
|
||||
static const int PADDING_Y = 30;
|
||||
static const int PADDING_Y = 50;
|
||||
|
||||
/*
|
||||
Minimum width of the table zone including margins.
|
||||
|
|
@ -61,7 +62,7 @@ private:
|
|||
Offset sizes when cards are stacked on each other in the grid
|
||||
*/
|
||||
static const int STACKED_CARD_OFFSET_X = CardDimensions::WIDTH / 3;
|
||||
static const int STACKED_CARD_OFFSET_Y = PADDING_Y / 3;
|
||||
static const int STACKED_CARD_OFFSET_Y = 8; // Avoid covering the next zone label.
|
||||
|
||||
/*
|
||||
Width of the box line drawn in the margin around the active player's area
|
||||
|
|
@ -100,6 +101,11 @@ private:
|
|||
bool mirrored = false;
|
||||
bool playmatActive = false;
|
||||
|
||||
QColor frontZoneColor;
|
||||
QColor supportZoneColor;
|
||||
QColor commandZoneColor;
|
||||
QString zoneLabelFontFamily;
|
||||
|
||||
[[nodiscard]] bool isInverted() const;
|
||||
|
||||
private slots:
|
||||
|
|
@ -220,7 +226,8 @@ private:
|
|||
qreal damageShimmerAlpha = 0.0;
|
||||
|
||||
void paintZoneOutline(QPainter *painter);
|
||||
void paintLandDivider(QPainter *painter);
|
||||
void paintBattlefieldRows(QPainter *painter);
|
||||
void reloadBattlefieldAppearance();
|
||||
|
||||
/*
|
||||
Calculates card stack widths so mapping functions work properly
|
||||
|
|
|
|||
32
doc/continuumatrice-battlefield.md
Normal file
32
doc/continuumatrice-battlefield.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Continuumatrice battlefield style
|
||||
|
||||
Cockatrice's three visual table rows are reused as **Front**, **Support**, and **Command**. This is purely a display change: the server still sees a single `table` zone.
|
||||
|
||||
| Card XML `<tablerow>` | Position |
|
||||
| --- | --- |
|
||||
| `0` | Front |
|
||||
| `1` | Support |
|
||||
| `2` | Command |
|
||||
|
||||
## Optional color customization
|
||||
|
||||
Create `battlefield.ini` in the active Cockatrice theme directory:
|
||||
|
||||
```ini
|
||||
[Zones]
|
||||
Front = #A08E343D
|
||||
Support = #A0286981
|
||||
Command = #A05E428C
|
||||
```
|
||||
|
||||
The Qt color notation is `#AARRGGBB`, including transparency. Without this file, built-in red, teal, and purple shades are used. Reload the theme to apply changes. The row order follows the player's mirrored/inverted layout, so Front always faces the battlefield center.
|
||||
|
||||
## Font
|
||||
|
||||
To render labels using your own **Continuumorphous Regular**, copy either `Continuumorphous-Regular.ttf` or `Continuumorphous-Regular.otf` into `fonts/` inside the current theme directory, or into a `fonts/` directory beside the Continuumatrice executable.
|
||||
|
||||
The font is also detected if already installed as "Continuumorphous Regular" or "Continuumorphous". If not found, a Qt default font is used. The font asset is not included in this change; no resource entry was added that would break builds when the file is missing.
|
||||
|
||||
## Compatibility
|
||||
|
||||
The existing drag/drop, row mapping, stacking, card counters, playmats, and multiplayer protocols are preserved. This does **not** enforce gameplay placement restrictions.
|
||||
Loading…
Add table
Add a link
Reference in a new issue