Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jakub Mrowinski 2025-01-02 00:04:51 +01:00
commit ec895e3481
24 changed files with 3558 additions and 2653 deletions

View file

@ -1,19 +1,20 @@
FROM ubuntu:bionic
MAINTAINER Zach Halpern <zahalpern+github@gmail.com>
FROM ubuntu:24.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y\
build-essential\
cmake\
git\
libprotobuf-dev\
libqt5sql5-mysql\
libmysqlclient-dev\
libqt5websockets5-dev\
protobuf-compiler\
qt5-default\
qtbase5-dev\
qttools5-dev-tools\
qttools5-dev
build-essential \
cmake \
file \
g++ \
git \
libmariadb-dev-compat \
libprotobuf-dev \
libqt6sql6-mysql \
qt6-websockets-dev \
protobuf-compiler \
qt6-tools-dev \
qt6-tools-dev-tools
COPY . /home/servatrice/code/
WORKDIR /home/servatrice/code
@ -25,7 +26,6 @@ RUN cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=
WORKDIR /home/servatrice
EXPOSE 4747
EXPOSE 4747 4748
ENTRYPOINT [ "servatrice", "--log-to-console" ]

View file

@ -282,7 +282,7 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<name>BetaReleaseChannel</name>
<message>
<location filename="src/client/network/release_channel.cpp" line="203"/>
<source>Beta Releases</source>
<source>Beta</source>
<translation type="unfinished"></translation>
</message>
<message>
@ -424,21 +424,29 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<context>
<name>CardInfoFrameWidget</name>
<message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="66"/>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="69"/>
<source>Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="67"/>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="70"/>
<source>Description</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="68"/>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="71"/>
<source>Both</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>CardInfoPictureWidget</name>
<message>
<location filename="src/client/ui/widgets/cards/card_info_picture_widget.cpp" line="256"/>
<source>View related cards</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>CardInfoTextWidget</name>
<message>
@ -481,121 +489,121 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<context>
<name>CardZone</name>
<message>
<location filename="src/game/zones/card_zone.cpp" line="72"/>
<location filename="src/game/zones/card_zone.cpp" line="78"/>
<source>their hand</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="72"/>
<location filename="src/game/zones/card_zone.cpp" line="78"/>
<source>%1&apos;s hand</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="76"/>
<source>their library</source>
<comment>look at zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="77"/>
<source>%1&apos;s library</source>
<comment>look at zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="79"/>
<source>of their library</source>
<comment>top cards of zone,</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="80"/>
<source>of %1&apos;s library</source>
<comment>top cards of zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="82"/>
<source>their library</source>
<comment>reveal zone</comment>
<comment>look at zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="83"/>
<source>%1&apos;s library</source>
<comment>look at zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="85"/>
<source>of their library</source>
<comment>top cards of zone,</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="86"/>
<source>of %1&apos;s library</source>
<comment>top cards of zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="88"/>
<source>their library</source>
<comment>reveal zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="85"/>
<location filename="src/game/zones/card_zone.cpp" line="89"/>
<source>%1&apos;s library</source>
<comment>reveal zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="91"/>
<source>their library</source>
<comment>shuffle</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="85"/>
<location filename="src/game/zones/card_zone.cpp" line="91"/>
<source>%1&apos;s library</source>
<comment>shuffle</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="87"/>
<location filename="src/game/zones/card_zone.cpp" line="93"/>
<source>their library</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="87"/>
<location filename="src/game/zones/card_zone.cpp" line="93"/>
<source>%1&apos;s library</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="90"/>
<source>their graveyard</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="90"/>
<source>%1&apos;s graveyard</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="92"/>
<source>their exile</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="92"/>
<source>%1&apos;s exile</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="96"/>
<source>their graveyard</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="96"/>
<source>%1&apos;s graveyard</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="98"/>
<source>their exile</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="98"/>
<source>%1&apos;s exile</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="102"/>
<source>their sideboard</source>
<comment>look at zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="97"/>
<location filename="src/game/zones/card_zone.cpp" line="103"/>
<source>%1&apos;s sideboard</source>
<comment>look at zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="99"/>
<location filename="src/game/zones/card_zone.cpp" line="105"/>
<source>their sideboard</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="100"/>
<location filename="src/game/zones/card_zone.cpp" line="106"/>
<source>%1&apos;s sideboard</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
@ -4682,7 +4690,7 @@ Cockatrice will now reload the card database.</source>
</message>
<message>
<location filename="src/game/player/player.cpp" line="1901"/>
<location filename="src/game/player/player.cpp" line="3564"/>
<location filename="src/game/player/player.cpp" line="3565"/>
<source>Number:</source>
<translation type="unfinished"></translation>
</message>
@ -4793,7 +4801,7 @@ Cockatrice will now reload the card database.</source>
</message>
<message>
<location filename="src/game/player/player.cpp" line="1753"/>
<location filename="src/game/player/player.cpp" line="4084"/>
<location filename="src/game/player/player.cpp" line="4085"/>
<source>C&amp;reate another %1 token</source>
<translation type="unfinished"></translation>
</message>
@ -4808,47 +4816,47 @@ Cockatrice will now reload the card database.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3351"/>
<location filename="src/game/player/player.cpp" line="3352"/>
<source>Change power/toughness</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3351"/>
<location filename="src/game/player/player.cpp" line="3352"/>
<source>Change stats to:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3470"/>
<location filename="src/game/player/player.cpp" line="3471"/>
<source>Set annotation</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3471"/>
<location filename="src/game/player/player.cpp" line="3472"/>
<source>Please enter the new annotation:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3564"/>
<location filename="src/game/player/player.cpp" line="3565"/>
<source>Set counters</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3839"/>
<location filename="src/game/player/player.cpp" line="3840"/>
<source>Re&amp;veal to...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3909"/>
<location filename="src/game/player/player.cpp" line="3910"/>
<source>View related cards</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3957"/>
<location filename="src/game/player/player.cpp" line="3958"/>
<source>Token: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3974"/>
<location filename="src/game/player/player.cpp" line="3975"/>
<source>All tokens</source>
<translation type="unfinished"></translation>
</message>
@ -5458,7 +5466,7 @@ Please check your shortcut settings!</source>
<name>StableReleaseChannel</name>
<message>
<location filename="src/client/network/release_channel.cpp" line="89"/>
<source>Stable Releases</source>
<source>Default</source>
<translation type="unfinished"></translation>
</message>
<message>
@ -5819,17 +5827,17 @@ Please check your shortcut settings!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1185"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1188"/>
<source>Open in new tab</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1214"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1217"/>
<source>Are you sure?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1215"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1218"/>
<source>The decklist has been modified.
Do you want to save the changes?</source>
<translation type="unfinished"></translation>
@ -5845,8 +5853,8 @@ Do you want to save the changes?</source>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="994"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1015"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1036"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1105"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1117"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1108"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1120"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
@ -5873,12 +5881,12 @@ Please check that the directory is writable and try again.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1105"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1108"/>
<source>There are no cards in your deck to be exported</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1117"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1120"/>
<source>No deck was selected to be saved.</source>
<translation type="unfinished"></translation>
</message>

View file

@ -64,6 +64,7 @@ void TabDeckEditor::createDeckDock()
deckView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
deckView->installEventFilter(&deckViewKeySignals);
deckView->setContextMenuPolicy(Qt::CustomContextMenu);
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this,
SLOT(updateCardInfoRight(const QModelIndex &, const QModelIndex &)));
connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this,
@ -1038,6 +1039,9 @@ bool TabDeckEditor::actSaveDeckAs()
return false;
}
setModified(false);
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
return true;
}
@ -1238,6 +1242,23 @@ CardInfoPtr TabDeckEditor::currentCardInfo() const
return CardDatabaseManager::getInstance()->getCard(cardName);
}
/**
* Gets the index of all the currently selected card nodes in the decklist table.
* The list is in reverse order of the visual selection, so that rows can be deleted while iterating over them.
*
* @return A model index list containing all selected card nodes
*/
QModelIndexList TabDeckEditor::getSelectedCardNodes() const
{
auto selectedRows = deckView->selectionModel()->selectedRows();
const auto notLeafNode = [this](const auto &index) { return deckModel->hasChildren(index); };
selectedRows.erase(std::remove_if(selectedRows.begin(), selectedRows.end(), notLeafNode), selectedRows.end());
std::reverse(selectedRows.begin(), selectedRows.end());
return selectedRows;
}
void TabDeckEditor::addCardHelper(QString zoneName)
{
const CardInfoPtr info = currentCardInfo();
@ -1248,6 +1269,7 @@ void TabDeckEditor::addCardHelper(QString zoneName)
QModelIndex newCardIndex = deckModel->addPreferredPrintingCard(info->getName(), zoneName, false);
recursiveExpand(newCardIndex);
deckView->clearSelection();
deckView->setCurrentIndex(newCardIndex);
setModified(true);
searchEdit->setSelection(0, searchEdit->text().length());
@ -1296,25 +1318,41 @@ void TabDeckEditor::actAddCardToSideboard()
void TabDeckEditor::actRemoveCard()
{
const QModelIndex &currentIndex = deckView->selectionModel()->currentIndex();
if (!currentIndex.isValid() || deckModel->hasChildren(currentIndex))
return;
deckModel->removeRow(currentIndex.row(), currentIndex.parent());
auto selectedRows = getSelectedCardNodes();
DeckLoader *const deck = deckModel->getDeckList();
setSaveStatus(!deck->isEmpty());
setModified(true);
// hack to maintain the old reselection behavior when currently selected row of a single-selection gets deleted
// TODO: remove the hack and also handle reselection when all rows of a multi-selection gets deleted
if (selectedRows.length() == 1) {
deckView->setSelectionMode(QAbstractItemView::SingleSelection);
}
bool modified = false;
for (const auto &index : selectedRows) {
if (!index.isValid() || deckModel->hasChildren(index)) {
continue;
}
deckModel->removeRow(index.row(), index.parent());
modified = true;
}
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (modified) {
DeckLoader *const deck = deckModel->getDeckList();
setSaveStatus(!deck->isEmpty());
setModified(true);
}
}
void TabDeckEditor::offsetCountAtIndex(const QModelIndex &idx, int offset)
{
if (!idx.isValid() || offset == 0)
if (!idx.isValid() || deckModel->hasChildren(idx)) {
return;
}
const QModelIndex numberIndex = idx.sibling(idx.row(), 0);
const int count = deckModel->data(numberIndex, Qt::EditRole).toInt();
const int new_count = count + offset;
deckView->setCurrentIndex(numberIndex);
if (new_count <= 0)
deckModel->removeRow(idx.row(), idx.parent());
else
@ -1325,14 +1363,18 @@ void TabDeckEditor::offsetCountAtIndex(const QModelIndex &idx, int offset)
void TabDeckEditor::decrementCardHelper(QString zoneName)
{
const CardInfoPtr info = currentCardInfo();
QModelIndex idx;
if (!info)
return;
if (info->getIsToken())
zoneName = DECK_ZONE_TOKENS;
idx = deckModel->findCard(info->getName(), zoneName);
QModelIndex idx = deckModel->findCard(info->getName(), zoneName);
if (!idx.isValid()) {
return;
}
deckView->clearSelection();
deckView->setCurrentIndex(idx);
offsetCountAtIndex(idx, -1);
}
@ -1354,14 +1396,28 @@ void TabDeckEditor::copyDatabaseCellContents()
void TabDeckEditor::actIncrement()
{
const QModelIndex &currentIndex = deckView->selectionModel()->currentIndex();
offsetCountAtIndex(currentIndex, 1);
auto selectedRows = getSelectedCardNodes();
for (const auto &index : selectedRows) {
offsetCountAtIndex(index, 1);
}
}
void TabDeckEditor::actDecrement()
{
const QModelIndex &currentIndex = deckView->selectionModel()->currentIndex();
offsetCountAtIndex(currentIndex, -1);
auto selectedRows = getSelectedCardNodes();
// hack to maintain the old reselection behavior when currently selected row of a single-selection gets deleted
// TODO: remove the hack and also handle reselection when all rows of a multi-selection gets deleted
if (selectedRows.length() == 1) {
deckView->setSelectionMode(QAbstractItemView::SingleSelection);
}
for (const auto &index : selectedRows) {
offsetCountAtIndex(index, -1);
}
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
}
void TabDeckEditor::setDeck(DeckLoader *_deck)

View file

@ -111,6 +111,8 @@ private:
void recursiveExpand(const QModelIndex &index);
void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation);
QModelIndexList getSelectedCardNodes() const;
CardDatabaseModel *databaseModel;
CardDatabaseDisplayModel *databaseDisplayModel;
DeckListModel *deckModel;

View file

@ -25,7 +25,7 @@ AbstractCardItem::AbstractCardItem(QGraphicsItem *parent,
setCacheMode(DeviceCoordinateCache);
connect(&SettingsCache::instance(), SIGNAL(displayCardNamesChanged()), this, SLOT(callUpdate()));
cardInfoUpdated();
refreshCardInfo();
}
AbstractCardItem::~AbstractCardItem()
@ -51,7 +51,7 @@ void AbstractCardItem::pixmapUpdated()
emit sigPixmapUpdated();
}
void AbstractCardItem::cardInfoUpdated()
void AbstractCardItem::refreshCardInfo()
{
info = CardDatabaseManager::getInstance()->getCardByNameAndProviderId(name, providerId);
@ -185,7 +185,7 @@ void AbstractCardItem::setName(const QString &_name)
disconnect(info.data(), nullptr, this, nullptr);
name = _name;
cardInfoUpdated();
refreshCardInfo();
}
void AbstractCardItem::setProviderId(const QString &_providerId)
@ -200,7 +200,7 @@ void AbstractCardItem::setProviderId(const QString &_providerId)
}
providerId = _providerId;
cardInfoUpdated();
refreshCardInfo();
}
void AbstractCardItem::setHovered(bool _hovered)

View file

@ -28,11 +28,14 @@ private:
qreal realZValue;
private slots:
void pixmapUpdated();
void cardInfoUpdated();
void callUpdate()
{
update();
}
public slots:
void refreshCardInfo();
signals:
void hovered(AbstractCardItem *card);
void showCardInfoPopup(const QPoint &pos, const QString &cardName, const QString &providerId);

View file

@ -217,13 +217,15 @@ void CardItem::setAttachedTo(CardItem *_attachedTo)
}
}
void CardItem::resetState()
void CardItem::resetState(bool keepAnnotations)
{
attacking = false;
facedown = false;
counters.clear();
pt.clear();
annotation.clear();
if (!keepAnnotations) {
annotation.clear();
}
attachedTo = 0;
attachedCards.clear();
setTapped(false, false);

View file

@ -139,7 +139,7 @@ public:
{
return attachedCards;
}
void resetState();
void resetState(bool keepAnnotations = false);
void processCardInfo(const ServerInfo_Card &_info);
QMenu *getCardMenu() const

View file

@ -1,5 +1,6 @@
#include "card_zone.h"
#include "../cards/card_database_manager.h"
#include "../cards/card_item.h"
#include "../player/player.h"
#include "pb/command_move_card.pb.h"
@ -31,6 +32,11 @@ CardZone::CardZone(Player *_p,
{
if (!isView)
player->addZone(this);
// If we join a game before the card db finishes loading, the cards might have the wrong printings.
// Force refresh all cards in the zone when db finishes loading to fix that.
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
&CardZone::refreshCardInfos);
}
CardZone::~CardZone()
@ -119,6 +125,13 @@ bool CardZone::showContextMenu(const QPoint &screenPos)
return false;
}
void CardZone::refreshCardInfos()
{
for (const auto &cardItem : cards) {
cardItem->refreshCardInfo();
}
}
void CardZone::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::RightButton) {

View file

@ -43,6 +43,9 @@ public slots:
void moveAllToZone();
bool showContextMenu(const QPoint &screenPos);
private slots:
void refreshCardInfos();
public:
enum
{

View file

@ -37,7 +37,7 @@ void StackZone::addCardImpl(CardItem *card, int x, int /*y*/)
card->setName();
}
card->setParentItem(this);
card->resetState();
card->resetState(true);
card->setVisible(true);
card->update();
}

File diff suppressed because it is too large Load diff

View file

@ -281,8 +281,8 @@ This is only saved for moderators and cannot be seen by the banned person.</tran
<name>BetaReleaseChannel</name>
<message>
<location filename="src/client/network/release_channel.cpp" line="203"/>
<source>Beta Releases</source>
<translation>Beta Releases</translation>
<source>Beta</source>
<translation>Beta</translation>
</message>
<message>
<location filename="src/client/network/release_channel.cpp" line="229"/>
@ -423,21 +423,29 @@ This is only saved for moderators and cannot be seen by the banned person.</tran
<context>
<name>CardInfoFrameWidget</name>
<message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="66"/>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="69"/>
<source>Image</source>
<translation>Image</translation>
</message>
<message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="67"/>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="70"/>
<source>Description</source>
<translation>Description</translation>
</message>
<message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="68"/>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="71"/>
<source>Both</source>
<translation>Both</translation>
</message>
</context>
<context>
<name>CardInfoPictureWidget</name>
<message>
<location filename="src/client/ui/widgets/cards/card_info_picture_widget.cpp" line="256"/>
<source>View related cards</source>
<translation>View related cards</translation>
</message>
</context>
<context>
<name>CardInfoTextWidget</name>
<message>
@ -480,121 +488,121 @@ This is only saved for moderators and cannot be seen by the banned person.</tran
<context>
<name>CardZone</name>
<message>
<location filename="src/game/zones/card_zone.cpp" line="72"/>
<location filename="src/game/zones/card_zone.cpp" line="78"/>
<source>their hand</source>
<comment>nominative</comment>
<translation>their hand</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="72"/>
<location filename="src/game/zones/card_zone.cpp" line="78"/>
<source>%1&apos;s hand</source>
<comment>nominative</comment>
<translation>%1&apos;s hand</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="76"/>
<source>their library</source>
<comment>look at zone</comment>
<translation>their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="77"/>
<source>%1&apos;s library</source>
<comment>look at zone</comment>
<translation>%1&apos;s library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="79"/>
<source>of their library</source>
<comment>top cards of zone,</comment>
<translation>of their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="80"/>
<source>of %1&apos;s library</source>
<comment>top cards of zone</comment>
<translation>of %1&apos;s library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="82"/>
<source>their library</source>
<comment>reveal zone</comment>
<comment>look at zone</comment>
<translation>their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="83"/>
<source>%1&apos;s library</source>
<comment>look at zone</comment>
<translation>%1&apos;s library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="85"/>
<source>of their library</source>
<comment>top cards of zone,</comment>
<translation>of their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="86"/>
<source>of %1&apos;s library</source>
<comment>top cards of zone</comment>
<translation>of %1&apos;s library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="88"/>
<source>their library</source>
<comment>reveal zone</comment>
<translation>their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="89"/>
<source>%1&apos;s library</source>
<comment>reveal zone</comment>
<translation>%1&apos;s library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="85"/>
<location filename="src/game/zones/card_zone.cpp" line="91"/>
<source>their library</source>
<comment>shuffle</comment>
<translation>their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="85"/>
<location filename="src/game/zones/card_zone.cpp" line="91"/>
<source>%1&apos;s library</source>
<comment>shuffle</comment>
<translation>%1&apos;s library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="87"/>
<location filename="src/game/zones/card_zone.cpp" line="93"/>
<source>their library</source>
<comment>nominative</comment>
<translation>their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="87"/>
<location filename="src/game/zones/card_zone.cpp" line="93"/>
<source>%1&apos;s library</source>
<comment>nominative</comment>
<translation>%1&apos;s library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="90"/>
<location filename="src/game/zones/card_zone.cpp" line="96"/>
<source>their graveyard</source>
<comment>nominative</comment>
<translation>their graveyard</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="90"/>
<location filename="src/game/zones/card_zone.cpp" line="96"/>
<source>%1&apos;s graveyard</source>
<comment>nominative</comment>
<translation>%1&apos;s graveyard</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="92"/>
<location filename="src/game/zones/card_zone.cpp" line="98"/>
<source>their exile</source>
<comment>nominative</comment>
<translation>their exile</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="92"/>
<location filename="src/game/zones/card_zone.cpp" line="98"/>
<source>%1&apos;s exile</source>
<comment>nominative</comment>
<translation>%1&apos;s exile</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="96"/>
<location filename="src/game/zones/card_zone.cpp" line="102"/>
<source>their sideboard</source>
<comment>look at zone</comment>
<translation>their sideboard</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="97"/>
<location filename="src/game/zones/card_zone.cpp" line="103"/>
<source>%1&apos;s sideboard</source>
<comment>look at zone</comment>
<translation>%1&apos;s sideboard</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="99"/>
<location filename="src/game/zones/card_zone.cpp" line="105"/>
<source>their sideboard</source>
<comment>nominative</comment>
<translation>their sideboard</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="100"/>
<location filename="src/game/zones/card_zone.cpp" line="106"/>
<source>%1&apos;s sideboard</source>
<comment>nominative</comment>
<translation>%1&apos;s sideboard</translation>
@ -4705,7 +4713,7 @@ Cockatrice will now reload the card database.</translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="1901"/>
<location filename="src/game/player/player.cpp" line="3564"/>
<location filename="src/game/player/player.cpp" line="3565"/>
<source>Number:</source>
<translation>Number:</translation>
</message>
@ -4816,7 +4824,7 @@ Cockatrice will now reload the card database.</translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="1753"/>
<location filename="src/game/player/player.cpp" line="4084"/>
<location filename="src/game/player/player.cpp" line="4085"/>
<source>C&amp;reate another %1 token</source>
<translation>C&amp;reate another %1 token</translation>
</message>
@ -4831,47 +4839,47 @@ Cockatrice will now reload the card database.</translation>
<translation>Place card X cards from top of library</translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3351"/>
<location filename="src/game/player/player.cpp" line="3352"/>
<source>Change power/toughness</source>
<translation>Change power/toughness</translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3351"/>
<location filename="src/game/player/player.cpp" line="3352"/>
<source>Change stats to:</source>
<translation>Change stats to:</translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3470"/>
<location filename="src/game/player/player.cpp" line="3471"/>
<source>Set annotation</source>
<translation>Set annotation</translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3471"/>
<location filename="src/game/player/player.cpp" line="3472"/>
<source>Please enter the new annotation:</source>
<translation>Please enter the new annotation:</translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3564"/>
<location filename="src/game/player/player.cpp" line="3565"/>
<source>Set counters</source>
<translation>Set counters</translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3839"/>
<location filename="src/game/player/player.cpp" line="3840"/>
<source>Re&amp;veal to...</source>
<translation>Re&amp;veal to...</translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3909"/>
<location filename="src/game/player/player.cpp" line="3910"/>
<source>View related cards</source>
<translation>View related cards</translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3957"/>
<location filename="src/game/player/player.cpp" line="3958"/>
<source>Token: </source>
<translation>Token: </translation>
</message>
<message>
<location filename="src/game/player/player.cpp" line="3974"/>
<location filename="src/game/player/player.cpp" line="3975"/>
<source>All tokens</source>
<translation>All tokens</translation>
</message>
@ -5483,8 +5491,8 @@ Please check your shortcut settings!</translation>
<name>StableReleaseChannel</name>
<message>
<location filename="src/client/network/release_channel.cpp" line="89"/>
<source>Stable Releases</source>
<translation>Stable Releases</translation>
<source>Default</source>
<translation>Default</translation>
</message>
<message>
<location filename="src/client/network/release_channel.cpp" line="105"/>
@ -5844,17 +5852,17 @@ Please check your shortcut settings!</translation>
<translation>Could not open deck at %1</translation>
</message>
<message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1185"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1188"/>
<source>Open in new tab</source>
<translation>Open in new tab</translation>
</message>
<message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1214"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1217"/>
<source>Are you sure?</source>
<translation>Are you sure?</translation>
</message>
<message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1215"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1218"/>
<source>The decklist has been modified.
Do you want to save the changes?</source>
<translation>The decklist has been modified.
@ -5871,8 +5879,8 @@ Do you want to save the changes?</translation>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="994"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1015"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1036"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1105"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1117"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1108"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1120"/>
<source>Error</source>
<translation>Error</translation>
</message>
@ -5900,12 +5908,12 @@ Please check that the directory is writable and try again.</translation>
<translation>Save deck</translation>
</message>
<message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1105"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1108"/>
<source>There are no cards in your deck to be exported</source>
<translation>There are no cards in your deck to be exported</translation>
</message>
<message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1117"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1120"/>
<source>No deck was selected to be saved.</source>
<translation>No deck was selected to be saved.</translation>
</message>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -54,13 +54,15 @@ Server_Card::~Server_Card()
}
}
void Server_Card::resetState()
void Server_Card::resetState(bool keepAnnotations)
{
counters.clear();
setTapped(false);
setAttacking(false);
setPT(QString());
setAnnotation(QString());
if (!keepAnnotations) {
setAnnotation(QString());
}
setDoesntUntap(false);
}

View file

@ -218,7 +218,7 @@ public:
return oldStashedCard;
}
void resetState();
void resetState(bool keepAnnotations = false);
QString setAttribute(CardAttribute attribute, const QString &avalue, bool allCards);
QString setAttribute(CardAttribute attribute, const QString &avalue, Event_SetCardAttr *event = nullptr);

View file

@ -548,7 +548,7 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges,
newX = targetzone->getFreeGridColumn(newX, yCoord, card->getName(), faceDown);
} else {
yCoord = 0;
card->resetState();
card->resetState(targetzone->getName() == "stack");
}
targetzone->insertCard(card, newX, yCoord);

View file

@ -89,7 +89,7 @@ e pedine che verranno usate da Cockatrice.</translation>
<message>
<location filename="src/oraclewizard.cpp" line="336"/>
<source>Please choose a file.</source>
<translation>Selezina un file.</translation>
<translation>Seleziona un file.</translation>
</message>
<message>
<location filename="src/oraclewizard.cpp" line="341"/>
@ -246,7 +246,7 @@ e pedine che verranno usate da Cockatrice.</translation>
<context>
<name>OracleImporter</name>
<message>
<location filename="src/oracleimporter.cpp" line="460"/>
<location filename="src/oracleimporter.cpp" line="465"/>
<source>Dummy set containing tokens</source>
<translation>Set finto contenente i token</translation>
</message>

View file

@ -0,0 +1,11 @@
-- Servatrice db migration from version 30 to version 31
ALTER TABLE cockatrice_log DROP INDEX `target_type`;
ALTER TABLE cockatrice_forgot_password ADD INDEX idx_emailed (`emailed`);
ALTER TABLE cockatrice_sessions ADD INDEX idx_start_time (`start_time`);
ALTER TABLE cockatrice_users ADD INDEX idx_admin (`admin`);
ALTER TABLE cockatrice_users ADD INDEX idx_active (`active`);
ALTER TABLE cockatrice_users ADD INDEX idx_privlevel (`privlevel`);
UPDATE cockatrice_schema_version SET version=31 WHERE version=30;

View file

@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS `cockatrice_schema_version` (
PRIMARY KEY (`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
INSERT INTO cockatrice_schema_version VALUES(30);
INSERT INTO cockatrice_schema_version VALUES(31);
-- users and user data tables
CREATE TABLE IF NOT EXISTS `cockatrice_users` (
@ -44,7 +44,10 @@ CREATE TABLE IF NOT EXISTS `cockatrice_users` (
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
KEY `token` (`token`),
KEY `email` (`email`)
KEY `email` (`email`),
INDEX `idx_admin` (`admin`),
INDEX `idx_active` (`active`),
INDEX `idx_privlevel` (`privlevel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `cockatrice_decklist_files` (
@ -190,7 +193,8 @@ CREATE TABLE IF NOT EXISTS `cockatrice_sessions` (
`clientid` varchar(15) NOT NULL,
`connection_type` ENUM('tcp', 'websocket'),
PRIMARY KEY (`id`),
KEY `username` (`user_name`)
KEY `username` (`user_name`),
INDEX `idx_start_time` (`start_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
-- server moderation
@ -230,7 +234,6 @@ CREATE TABLE IF NOT EXISTS `cockatrice_log` (
`target_name` varchar(50) NOT NULL,
KEY `sender_name` (`sender_name`),
KEY `sender_ip` (`sender_ip`),
KEY `target_type` (`target_type`),
KEY `target_id` (`target_id`),
KEY `target_name` (`target_name`),
FOREIGN KEY(`sender_id`) REFERENCES `cockatrice_users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
@ -269,7 +272,8 @@ CREATE TABLE IF NOT EXISTS `cockatrice_forgot_password` (
`requestDate` datetime NOT NULL default '0000-00-00 00:00:00',
`emailed` tinyint(1) NOT NULL default 0,
PRIMARY KEY (`id`),
KEY `user_name` (`name`)
KEY `user_name` (`name`),
INDEX `idx_emailed` (`emailed`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `cockatrice_audit` (

View file

@ -103,12 +103,25 @@ bool Servatrice_DatabaseInterface::openDatabase()
bool Servatrice_DatabaseInterface::checkSql()
{
if (!sqlDatabase.isValid())
if (!sqlDatabase.isValid()) {
return false;
}
auto query = QSqlQuery(sqlDatabase);
if (query.exec("select 1") && query.isActive())
if (query.exec("select 1") && query.isActive()) {
return openDatabase();
}
if (query.lastError().isValid()) {
const auto &poolStr = instanceId == -1 ? QString("main") : QString("pool %1").arg(instanceId);
qCritical() << QString("[%1] Error executing query: %2, resetting connection")
.arg(poolStr)
.arg(query.lastError().text());
sqlDatabase.close();
return openDatabase();
}
return true;
}
@ -1197,6 +1210,11 @@ QList<ServerInfo_ChatMessage> Servatrice_DatabaseInterface::getMessageLogHistory
if (!checkSql())
return results;
if (user.isEmpty() && ipaddress.isEmpty() && gameid.isEmpty() && gamename.isEmpty()) {
// To ensure quick results and minimal lag, require an indexed field
return results;
}
// BUILD QUERY STRING BASED ON PASSED IN VALUES
QString queryString = "SELECT * FROM {prefix}_log WHERE `sender_ip` IS NOT NULL";
if (!user.isEmpty())

View file

@ -9,7 +9,7 @@
#include <QObject>
#include <QSqlDatabase>
#define DATABASE_SCHEMA_VERSION 30
#define DATABASE_SCHEMA_VERSION 31
class Servatrice;

View file

@ -158,7 +158,7 @@
"LS": "Lesotho",
"LT": "Lituania",
"LU": "Lussemburgo",
"LV": "Latvia",
"LV": "Lettonia",
"LY": "Libia",
"MA": "Marocco",
"MC": "Monaco",
@ -298,7 +298,7 @@
"subtitle": "Un portale digitale multi-piattaforma per giochi di carte multigiocatore"
},
"footer": {
"registerPrompt": "Non ancora registrato?",
"registerPrompt": "Non sei ancora registrato?",
"registerAction": "Crea un nuovo account",
"credit": "Cockatrice è un progetto open source",
"version": "Versione"
@ -314,17 +314,17 @@
},
"UnsupportedContainer": {
"title": "Browser non supportato",
"subtitle1": "Per favore aggiornare il browser e/o controllare i permessi.",
"subtitle1": "Aggiornare il browser e/o controllare i permessi.",
"subtitle2": "Nota: la navigazione Privata può far si che il browser disabiliti certi permessi o funzionalità."
},
"AccountActivationDialog": {
"title": "Attivazione dell'account",
"subtitle1": "Il tuo account non è ancora stato attivato.",
"subtitle2": "È necessario fornire il token di attivazione ricevuto nell'e-mail di attivazione."
"subtitle2": "È necessario fornire il codice ricevuto nell'e-mail di attivazione."
},
"KnownHostDialog": {
"title": "{modalità, seleziona, modifica {Modifica} altro {Aggiungi}} Host conosciuto",
"subtitle": "L'aggiunta di un nuovo host consente di connettersi a server diversi. Inserisci i dettagli di seguito nella tua lista di host."
"subtitle": "L'aggiunta di un nuovo host consente di connettersi a server diversi. Inserisci i dettagli di seguito nella lista degli host."
},
"RegistrationDialog": {
"title": "Crea un nuovo account"