mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-15 03:28:49 -07:00
* move message_log_widget to game * move files * update headers * fix cmakelists * oracle fixes * split implementation out to cpp * fix recursive import * fix main file * format
This commit is contained in:
parent
f484c98152
commit
17dcaf9afa
337 changed files with 728 additions and 721 deletions
|
|
@ -1,9 +1,9 @@
|
|||
#include "chat_view.h"
|
||||
|
||||
#include "../../client/sound_engine.h"
|
||||
#include "../../client/tabs/tab_account.h"
|
||||
#include "../../client/ui/pixel_map_generator.h"
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "../../settings/cache_settings.h"
|
||||
#include "../../tabs/tab_account.h"
|
||||
#include "../user/user_context_menu.h"
|
||||
#include "../user/user_list_manager.h"
|
||||
#include "../user/user_list_proxy.h"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef CHATVIEW_H
|
||||
#define CHATVIEW_H
|
||||
|
||||
#include "../../client/tabs/tab_supervisor.h"
|
||||
#include "../../tabs/tab_supervisor.h"
|
||||
#include "../user/user_list_widget.h"
|
||||
#include "room_message_type.h"
|
||||
#include "user_level.h"
|
||||
|
|
|
|||
393
cockatrice/src/server/game_selector.cpp
Normal file
393
cockatrice/src/server/game_selector.cpp
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
#include "game_selector.h"
|
||||
|
||||
#include "../client/get_text_with_max.h"
|
||||
#include "../dialogs/dlg_create_game.h"
|
||||
#include "../dialogs/dlg_filter_games.h"
|
||||
#include "../tabs/tab_account.h"
|
||||
#include "../tabs/tab_game.h"
|
||||
#include "../tabs/tab_room.h"
|
||||
#include "../tabs/tab_supervisor.h"
|
||||
#include "abstract_client.h"
|
||||
#include "games_model.h"
|
||||
#include "pb/response.pb.h"
|
||||
#include "pb/room_commands.pb.h"
|
||||
#include "pb/serverinfo_game.pb.h"
|
||||
#include "pending_command.h"
|
||||
#include "user/user_list_manager.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QDebug>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QInputDialog>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTreeView>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
GameSelector::GameSelector(AbstractClient *_client,
|
||||
TabSupervisor *_tabSupervisor,
|
||||
TabRoom *_room,
|
||||
const QMap<int, QString> &_rooms,
|
||||
const QMap<int, GameTypeMap> &_gameTypes,
|
||||
const bool restoresettings,
|
||||
const bool _showfilters,
|
||||
QWidget *parent)
|
||||
: QGroupBox(parent), client(_client), tabSupervisor(_tabSupervisor), room(_room), showFilters(_showfilters)
|
||||
{
|
||||
gameListView = new QTreeView;
|
||||
gameListView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(gameListView, &QTreeView::customContextMenuRequested, this, &GameSelector::customContextMenu);
|
||||
|
||||
gameListModel = new GamesModel(_rooms, _gameTypes, this);
|
||||
if (showFilters) {
|
||||
gameListProxyModel = new GamesProxyModel(this, tabSupervisor->getUserListManager());
|
||||
gameListProxyModel->setSourceModel(gameListModel);
|
||||
gameListProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
gameListView->setModel(gameListProxyModel);
|
||||
} else {
|
||||
gameListView->setModel(gameListModel);
|
||||
}
|
||||
gameListView->setIconSize(QSize(13, 13));
|
||||
gameListView->setSortingEnabled(true);
|
||||
gameListView->sortByColumn(gameListModel->startTimeColIndex(), Qt::AscendingOrder);
|
||||
gameListView->setAlternatingRowColors(true);
|
||||
gameListView->setRootIsDecorated(true);
|
||||
// game created width
|
||||
gameListView->setColumnWidth(1, gameListView->columnWidth(2) * 0.7);
|
||||
// players width
|
||||
gameListView->resizeColumnToContents(6);
|
||||
// description width
|
||||
gameListView->setColumnWidth(2, gameListView->columnWidth(2) * 1.7);
|
||||
// creator width
|
||||
gameListView->setColumnWidth(3, gameListView->columnWidth(3) * 1.2);
|
||||
// game type width
|
||||
gameListView->setColumnWidth(4, gameListView->columnWidth(4) * 1.4);
|
||||
if (_room)
|
||||
gameListView->header()->hideSection(gameListModel->roomColIndex());
|
||||
|
||||
if (room)
|
||||
gameTypeMap = gameListModel->getGameTypes().value(room->getRoomId());
|
||||
|
||||
if (showFilters && restoresettings)
|
||||
gameListProxyModel->loadFilterParameters(gameTypeMap);
|
||||
|
||||
gameListView->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||
|
||||
filterButton = new QPushButton;
|
||||
filterButton->setIcon(QPixmap("theme:icons/search"));
|
||||
connect(filterButton, &QPushButton::clicked, this, &GameSelector::actSetFilter);
|
||||
clearFilterButton = new QPushButton;
|
||||
clearFilterButton->setIcon(QPixmap("theme:icons/clearsearch"));
|
||||
bool filtersSetToDefault = showFilters && gameListProxyModel->areFilterParametersSetToDefaults();
|
||||
clearFilterButton->setEnabled(!filtersSetToDefault);
|
||||
connect(clearFilterButton, &QPushButton::clicked, this, &GameSelector::actClearFilter);
|
||||
|
||||
if (room) {
|
||||
createButton = new QPushButton;
|
||||
connect(createButton, &QPushButton::clicked, this, &GameSelector::actCreate);
|
||||
} else {
|
||||
createButton = nullptr;
|
||||
}
|
||||
joinButton = new QPushButton;
|
||||
spectateButton = new QPushButton;
|
||||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout;
|
||||
if (showFilters) {
|
||||
buttonLayout->addWidget(filterButton);
|
||||
buttonLayout->addWidget(clearFilterButton);
|
||||
}
|
||||
buttonLayout->addStretch();
|
||||
if (room)
|
||||
buttonLayout->addWidget(createButton);
|
||||
buttonLayout->addWidget(joinButton);
|
||||
buttonLayout->addWidget(spectateButton);
|
||||
buttonLayout->setAlignment(Qt::AlignTop);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(gameListView);
|
||||
mainLayout->addLayout(buttonLayout);
|
||||
|
||||
retranslateUi();
|
||||
setLayout(mainLayout);
|
||||
|
||||
setMinimumWidth((qreal)(gameListView->columnWidth(0) * gameListModel->columnCount()) / 1.5);
|
||||
setMinimumHeight(200);
|
||||
|
||||
connect(joinButton, &QPushButton::clicked, this, &GameSelector::actJoin);
|
||||
connect(spectateButton, &QPushButton::clicked, this, &GameSelector::actSpectate);
|
||||
connect(gameListView->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
|
||||
&GameSelector::actSelectedGameChanged);
|
||||
connect(gameListView, &QTreeView::activated, this, &GameSelector::actJoin);
|
||||
|
||||
connect(client, &AbstractClient::ignoreListReceived, this, &GameSelector::ignoreListReceived);
|
||||
connect(client, &AbstractClient::addToListEventReceived, this, &GameSelector::processAddToListEvent);
|
||||
connect(client, &AbstractClient::removeFromListEventReceived, this, &GameSelector::processRemoveFromListEvent);
|
||||
}
|
||||
|
||||
void GameSelector::ignoreListReceived(const QList<ServerInfo_User> &)
|
||||
{
|
||||
gameListProxyModel->refresh();
|
||||
}
|
||||
|
||||
void GameSelector::processAddToListEvent(const Event_AddToList &event)
|
||||
{
|
||||
if (event.list_name() == "ignore") {
|
||||
gameListProxyModel->refresh();
|
||||
}
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
void GameSelector::processRemoveFromListEvent(const Event_RemoveFromList &event)
|
||||
{
|
||||
if (event.list_name() == "ignore") {
|
||||
gameListProxyModel->refresh();
|
||||
}
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
void GameSelector::actSetFilter()
|
||||
{
|
||||
DlgFilterGames dlg(gameTypeMap, gameListProxyModel, this);
|
||||
|
||||
if (!dlg.exec())
|
||||
return;
|
||||
|
||||
gameListProxyModel->setHideBuddiesOnlyGames(dlg.getHideBuddiesOnlyGames());
|
||||
gameListProxyModel->setHideFullGames(dlg.getHideFullGames());
|
||||
gameListProxyModel->setHideGamesThatStarted(dlg.getHideGamesThatStarted());
|
||||
gameListProxyModel->setHidePasswordProtectedGames(dlg.getHidePasswordProtectedGames());
|
||||
gameListProxyModel->setHideIgnoredUserGames(dlg.getHideIgnoredUserGames());
|
||||
gameListProxyModel->setHideNotBuddyCreatedGames(dlg.getHideNotBuddyCreatedGames());
|
||||
gameListProxyModel->setHideOpenDecklistGames(dlg.getHideOpenDecklistGames());
|
||||
gameListProxyModel->setGameNameFilter(dlg.getGameNameFilter());
|
||||
gameListProxyModel->setCreatorNameFilter(dlg.getCreatorNameFilter());
|
||||
gameListProxyModel->setGameTypeFilter(dlg.getGameTypeFilter());
|
||||
gameListProxyModel->setMaxPlayersFilter(dlg.getMaxPlayersFilterMin(), dlg.getMaxPlayersFilterMax());
|
||||
gameListProxyModel->setMaxGameAge(dlg.getMaxGameAge());
|
||||
gameListProxyModel->setShowOnlyIfSpectatorsCanWatch(dlg.getShowOnlyIfSpectatorsCanWatch());
|
||||
gameListProxyModel->setShowSpectatorPasswordProtected(dlg.getShowSpectatorPasswordProtected());
|
||||
gameListProxyModel->setShowOnlyIfSpectatorsCanChat(dlg.getShowOnlyIfSpectatorsCanChat());
|
||||
gameListProxyModel->setShowOnlyIfSpectatorsCanSeeHands(dlg.getShowOnlyIfSpectatorsCanSeeHands());
|
||||
gameListProxyModel->saveFilterParameters(gameTypeMap);
|
||||
|
||||
clearFilterButton->setEnabled(!gameListProxyModel->areFilterParametersSetToDefaults());
|
||||
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
void GameSelector::actClearFilter()
|
||||
{
|
||||
clearFilterButton->setEnabled(false);
|
||||
|
||||
gameListProxyModel->resetFilterParameters();
|
||||
gameListProxyModel->saveFilterParameters(gameTypeMap);
|
||||
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
void GameSelector::actCreate()
|
||||
{
|
||||
if (room == nullptr) {
|
||||
qWarning() << "Attempted to create game, but the room was null";
|
||||
return;
|
||||
}
|
||||
|
||||
DlgCreateGame dlg(room, room->getGameTypes(), this);
|
||||
dlg.exec();
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
void GameSelector::checkResponse(const Response &response)
|
||||
{
|
||||
// NB: We re-enable buttons for the currently selected game, which may not
|
||||
// be the same game as the one for which we are processing a response.
|
||||
// This could lead to situations where we join a game, select a different
|
||||
// game, join the new game, then receive the response for the original
|
||||
// join, which would re-activate the buttons for the second game too soon.
|
||||
// However, that is better than doing things the other ways, because then
|
||||
// the response to the first game could lock us out of join/join as
|
||||
// spectator for the second game!
|
||||
//
|
||||
// Ideally we should have a way to figure out if the current game is the
|
||||
// same as the one we are getting a response for, but it's probably not
|
||||
// worth the trouble.
|
||||
enableButtons();
|
||||
|
||||
switch (response.response_code()) {
|
||||
case Response::RespNotInRoom:
|
||||
QMessageBox::critical(this, tr("Error"), tr("Please join the appropriate room first."));
|
||||
break;
|
||||
case Response::RespWrongPassword:
|
||||
QMessageBox::critical(this, tr("Error"), tr("Wrong password."));
|
||||
break;
|
||||
case Response::RespSpectatorsNotAllowed:
|
||||
QMessageBox::critical(this, tr("Error"), tr("Spectators are not allowed in this game."));
|
||||
break;
|
||||
case Response::RespGameFull:
|
||||
QMessageBox::critical(this, tr("Error"), tr("The game is already full."));
|
||||
break;
|
||||
case Response::RespNameNotFound:
|
||||
QMessageBox::critical(this, tr("Error"), tr("The game does not exist any more."));
|
||||
break;
|
||||
case Response::RespUserLevelTooLow:
|
||||
QMessageBox::critical(this, tr("Error"), tr("This game is only open to registered users."));
|
||||
break;
|
||||
case Response::RespOnlyBuddies:
|
||||
QMessageBox::critical(this, tr("Error"), tr("This game is only open to its creator's buddies."));
|
||||
break;
|
||||
case Response::RespInIgnoreList:
|
||||
QMessageBox::critical(this, tr("Error"), tr("You are being ignored by the creator of this game."));
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
void GameSelector::actJoin()
|
||||
{
|
||||
return joinGame(false);
|
||||
}
|
||||
|
||||
void GameSelector::actSpectate()
|
||||
{
|
||||
return joinGame(true);
|
||||
}
|
||||
|
||||
void GameSelector::customContextMenu(const QPoint &point)
|
||||
{
|
||||
const auto &index = gameListView->indexAt(point);
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QAction joinGame(tr("Join Game"));
|
||||
connect(&joinGame, &QAction::triggered, this, &GameSelector::actJoin);
|
||||
|
||||
QAction spectateGame(tr("Spectate Game"));
|
||||
connect(&spectateGame, &QAction::triggered, this, &GameSelector::actSpectate);
|
||||
|
||||
QAction getGameInfo(tr("Game Information"));
|
||||
connect(&getGameInfo, &QAction::triggered, this, [=, this]() {
|
||||
const ServerInfo_Game &gameInfo = gameListModel->getGame(index.data(Qt::UserRole).toInt());
|
||||
const QMap<int, QString> &gameTypes = gameListModel->getGameTypes().value(gameInfo.room_id());
|
||||
|
||||
DlgCreateGame dlg(gameInfo, gameTypes, this);
|
||||
dlg.exec();
|
||||
});
|
||||
|
||||
QMenu menu;
|
||||
menu.addAction(&joinGame);
|
||||
menu.addAction(&spectateGame);
|
||||
menu.addAction(&getGameInfo);
|
||||
menu.exec(gameListView->mapToGlobal(point));
|
||||
}
|
||||
|
||||
void GameSelector::joinGame(const bool isSpectator)
|
||||
{
|
||||
QModelIndex ind = gameListView->currentIndex();
|
||||
if (!ind.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ServerInfo_Game &game = gameListModel->getGame(ind.data(Qt::UserRole).toInt());
|
||||
if (tabSupervisor->switchToGameTabIfAlreadyExists(game.game_id())) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool spectator = isSpectator || game.player_count() == game.max_players();
|
||||
|
||||
bool overrideRestrictions = !tabSupervisor->getAdminLocked();
|
||||
QString password;
|
||||
if (game.with_password() && !(spectator && !game.spectators_need_password()) && !overrideRestrictions) {
|
||||
bool ok;
|
||||
password = getTextWithMax(this, tr("Join game"), tr("Password:"), QLineEdit::Password, QString(), &ok);
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Command_JoinGame cmd;
|
||||
cmd.set_game_id(game.game_id());
|
||||
cmd.set_password(password.toStdString());
|
||||
cmd.set_spectator(spectator);
|
||||
cmd.set_override_restrictions(overrideRestrictions);
|
||||
cmd.set_join_as_judge((QApplication::keyboardModifiers() & Qt::ShiftModifier) != 0);
|
||||
|
||||
TabRoom *r = tabSupervisor->getRoomTabs().value(game.room_id());
|
||||
if (!r) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Please join the respective room first."));
|
||||
return;
|
||||
}
|
||||
|
||||
PendingCommand *pend = r->prepareRoomCommand(cmd);
|
||||
connect(pend, &PendingCommand::finished, this, &GameSelector::checkResponse);
|
||||
r->sendRoomCommand(pend);
|
||||
|
||||
disableButtons();
|
||||
}
|
||||
|
||||
void GameSelector::disableButtons()
|
||||
{
|
||||
if (createButton)
|
||||
createButton->setEnabled(false);
|
||||
|
||||
joinButton->setEnabled(false);
|
||||
spectateButton->setEnabled(false);
|
||||
}
|
||||
|
||||
void GameSelector::enableButtons()
|
||||
{
|
||||
if (createButton)
|
||||
createButton->setEnabled(true);
|
||||
|
||||
// Enable buttons for the currently selected game
|
||||
enableButtonsForIndex(gameListView->currentIndex());
|
||||
}
|
||||
|
||||
void GameSelector::enableButtonsForIndex(const QModelIndex ¤t)
|
||||
{
|
||||
if (!current.isValid())
|
||||
return;
|
||||
|
||||
const ServerInfo_Game &game = gameListModel->getGame(current.data(Qt::UserRole).toInt());
|
||||
bool overrideRestrictions = !tabSupervisor->getAdminLocked();
|
||||
|
||||
spectateButton->setEnabled(game.spectators_allowed() || overrideRestrictions);
|
||||
joinButton->setEnabled(game.player_count() < game.max_players() || overrideRestrictions);
|
||||
}
|
||||
|
||||
void GameSelector::retranslateUi()
|
||||
{
|
||||
filterButton->setText(tr("&Filter games"));
|
||||
clearFilterButton->setText(tr("C&lear filter"));
|
||||
if (createButton)
|
||||
createButton->setText(tr("C&reate"));
|
||||
joinButton->setText(tr("&Join"));
|
||||
spectateButton->setText(tr("J&oin as spectator"));
|
||||
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
void GameSelector::processGameInfo(const ServerInfo_Game &info)
|
||||
{
|
||||
gameListModel->updateGameList(info);
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
void GameSelector::actSelectedGameChanged(const QModelIndex ¤t, const QModelIndex & /* previous */)
|
||||
{
|
||||
enableButtonsForIndex(current);
|
||||
}
|
||||
|
||||
void GameSelector::updateTitle()
|
||||
{
|
||||
if (showFilters) {
|
||||
const int totalGames = gameListModel->rowCount();
|
||||
const int shownGames = totalGames - gameListProxyModel->getNumFilteredGames();
|
||||
setTitle(tr("Games shown: %1 / %2").arg(shownGames).arg(totalGames));
|
||||
} else {
|
||||
setTitle(tr("Games"));
|
||||
}
|
||||
}
|
||||
75
cockatrice/src/server/game_selector.h
Normal file
75
cockatrice/src/server/game_selector.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#ifndef GAMESELECTOR_H
|
||||
#define GAMESELECTOR_H
|
||||
|
||||
#include "game_type_map.h"
|
||||
|
||||
#include <QGroupBox>
|
||||
#include <common/pb/event_add_to_list.pb.h>
|
||||
#include <common/pb/event_remove_from_list.pb.h>
|
||||
#include <pb/commands.pb.h>
|
||||
|
||||
class QTreeView;
|
||||
class GamesModel;
|
||||
class GamesProxyModel;
|
||||
class QPushButton;
|
||||
class QCheckBox;
|
||||
class QLabel;
|
||||
class AbstractClient;
|
||||
class TabSupervisor;
|
||||
class TabRoom;
|
||||
class ServerInfo_Game;
|
||||
class Response;
|
||||
|
||||
class GameSelector : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void actSetFilter();
|
||||
void actClearFilter();
|
||||
void actCreate();
|
||||
|
||||
void actJoin();
|
||||
void actSpectate();
|
||||
void customContextMenu(const QPoint &point);
|
||||
|
||||
void actSelectedGameChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void checkResponse(const Response &response);
|
||||
|
||||
void ignoreListReceived(const QList<ServerInfo_User> &_ignoreList);
|
||||
void processAddToListEvent(const Event_AddToList &event);
|
||||
void processRemoveFromListEvent(const Event_RemoveFromList &event);
|
||||
signals:
|
||||
void gameJoined(int gameId);
|
||||
|
||||
private:
|
||||
AbstractClient *client;
|
||||
TabSupervisor *tabSupervisor;
|
||||
TabRoom *room;
|
||||
|
||||
QTreeView *gameListView;
|
||||
GamesModel *gameListModel;
|
||||
GamesProxyModel *gameListProxyModel;
|
||||
QPushButton *filterButton, *clearFilterButton, *createButton, *joinButton, *spectateButton;
|
||||
const bool showFilters;
|
||||
GameTypeMap gameTypeMap;
|
||||
|
||||
void updateTitle();
|
||||
void disableButtons();
|
||||
void enableButtons();
|
||||
void enableButtonsForIndex(const QModelIndex ¤t);
|
||||
void joinGame(const bool isSpectator);
|
||||
|
||||
public:
|
||||
GameSelector(AbstractClient *_client,
|
||||
TabSupervisor *_tabSupervisor,
|
||||
TabRoom *_room,
|
||||
const QMap<int, QString> &_rooms,
|
||||
const QMap<int, GameTypeMap> &_gameTypes,
|
||||
const bool restoresettings,
|
||||
const bool _showfilters,
|
||||
QWidget *parent = nullptr);
|
||||
void retranslateUi();
|
||||
void processGameInfo(const ServerInfo_Game &info);
|
||||
};
|
||||
|
||||
#endif
|
||||
8
cockatrice/src/server/game_type_map.h
Normal file
8
cockatrice/src/server/game_type_map.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef GAMETYPEMAP_H
|
||||
#define GAMETYPEMAP_H
|
||||
|
||||
#include <QMap>
|
||||
|
||||
typedef QMap<int, QString> GameTypeMap;
|
||||
|
||||
#endif
|
||||
581
cockatrice/src/server/games_model.cpp
Normal file
581
cockatrice/src/server/games_model.cpp
Normal file
|
|
@ -0,0 +1,581 @@
|
|||
#include "games_model.h"
|
||||
|
||||
#include "../interface/pixel_map_generator.h"
|
||||
#include "../settings/cache_settings.h"
|
||||
#include "../tabs/tab_account.h"
|
||||
#include "pb/serverinfo_game.pb.h"
|
||||
#include "user/user_list_manager.h"
|
||||
#include "user/user_list_widget.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QIcon>
|
||||
#include <QStringList>
|
||||
#include <QTime>
|
||||
#include <QTimeZone>
|
||||
|
||||
enum GameListColumn
|
||||
{
|
||||
ROOM,
|
||||
CREATED,
|
||||
DESCRIPTION,
|
||||
CREATOR,
|
||||
GAME_TYPE,
|
||||
RESTRICTIONS,
|
||||
PLAYERS,
|
||||
SPECTATORS
|
||||
};
|
||||
|
||||
const int DEFAULT_MAX_PLAYERS_MIN = 1;
|
||||
const int DEFAULT_MAX_PLAYERS_MAX = 99;
|
||||
constexpr QTime DEFAULT_MAX_GAME_AGE = QTime();
|
||||
|
||||
const QString GamesModel::getGameCreatedString(const int secs)
|
||||
{
|
||||
static const QTime zeroTime{0, 0};
|
||||
static const int halfHourSecs = zeroTime.secsTo(QTime(1, 0)) / 2;
|
||||
static const int halfMinSecs = zeroTime.secsTo(QTime(0, 1)) / 2;
|
||||
static const int wrapSeconds = zeroTime.secsTo(zeroTime.addSecs(-halfHourSecs)); // round up
|
||||
|
||||
if (secs >= wrapSeconds) { // QTime wraps after a day
|
||||
return tr(">1 day");
|
||||
}
|
||||
|
||||
QTime total = zeroTime.addSecs(secs);
|
||||
QTime totalRounded = total.addSecs(halfMinSecs); // round up
|
||||
QString form;
|
||||
int amount;
|
||||
if (totalRounded.hour()) {
|
||||
amount = total.addSecs(halfHourSecs).hour(); // round up separately
|
||||
form = tr("%1%2 hr", "short age in hours", amount);
|
||||
} else if (total.minute() < 2) { // games are new during their first minute
|
||||
return tr("new");
|
||||
} else {
|
||||
amount = totalRounded.minute();
|
||||
form = tr("%1%2 min", "short age in minutes", amount);
|
||||
}
|
||||
|
||||
for (int aggregate : {40, 20, 10, 5}) { // floor to values in this list
|
||||
if (amount >= aggregate) {
|
||||
return form.arg(">").arg(aggregate);
|
||||
}
|
||||
}
|
||||
return form.arg("").arg(amount);
|
||||
}
|
||||
|
||||
GamesModel::GamesModel(const QMap<int, QString> &_rooms, const QMap<int, GameTypeMap> &_gameTypes, QObject *parent)
|
||||
: QAbstractTableModel(parent), rooms(_rooms), gameTypes(_gameTypes)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant GamesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
if (role == Qt::UserRole)
|
||||
return index.row();
|
||||
if (role != Qt::DisplayRole && role != SORT_ROLE && role != Qt::DecorationRole && role != Qt::TextAlignmentRole)
|
||||
return QVariant();
|
||||
if ((index.row() >= gameList.size()) || (index.column() >= columnCount()))
|
||||
return QVariant();
|
||||
|
||||
const ServerInfo_Game &gameentry = gameList[index.row()];
|
||||
switch (index.column()) {
|
||||
case ROOM:
|
||||
return rooms.value(gameentry.room_id());
|
||||
case CREATED: {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
|
||||
auto then = QDateTime::fromSecsSinceEpoch(gameentry.start_time(), QTimeZone::UTC);
|
||||
#else
|
||||
auto then = QDateTime::fromSecsSinceEpoch(gameentry.start_time(), Qt::UTC);
|
||||
#endif
|
||||
int secs = then.secsTo(QDateTime::currentDateTimeUtc());
|
||||
return getGameCreatedString(secs);
|
||||
}
|
||||
case SORT_ROLE:
|
||||
return QVariant(-static_cast<qint64>(gameentry.start_time()));
|
||||
case Qt::TextAlignmentRole:
|
||||
return Qt::AlignCenter;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case DESCRIPTION:
|
||||
switch (role) {
|
||||
case SORT_ROLE:
|
||||
case Qt::DisplayRole:
|
||||
return QString::fromStdString(gameentry.description());
|
||||
case Qt::TextAlignmentRole:
|
||||
return Qt::AlignLeft;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
case CREATOR: {
|
||||
switch (role) {
|
||||
case SORT_ROLE:
|
||||
case Qt::DisplayRole:
|
||||
return QString::fromStdString(gameentry.creator_info().name());
|
||||
case Qt::DecorationRole: {
|
||||
return UserLevelPixmapGenerator::generateIcon(
|
||||
13, UserLevelFlags(gameentry.creator_info().user_level()),
|
||||
gameentry.creator_info().pawn_colors(), false,
|
||||
QString::fromStdString(gameentry.creator_info().privlevel()));
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case GAME_TYPE:
|
||||
switch (role) {
|
||||
case SORT_ROLE:
|
||||
case Qt::DisplayRole: {
|
||||
QStringList result;
|
||||
GameTypeMap gameTypeMap = gameTypes.value(gameentry.room_id());
|
||||
for (int i = gameentry.game_types_size() - 1; i >= 0; --i)
|
||||
result.append(gameTypeMap.value(gameentry.game_types(i)));
|
||||
return result.join(", ");
|
||||
}
|
||||
case Qt::TextAlignmentRole:
|
||||
return Qt::AlignLeft;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
case RESTRICTIONS:
|
||||
switch (role) {
|
||||
case SORT_ROLE:
|
||||
case Qt::DisplayRole: {
|
||||
QStringList result;
|
||||
if (gameentry.with_password())
|
||||
result.append(tr("password"));
|
||||
if (gameentry.only_buddies())
|
||||
result.append(tr("buddies only"));
|
||||
if (gameentry.only_registered())
|
||||
result.append(tr("reg. users only"));
|
||||
if (gameentry.share_decklists_on_load())
|
||||
result.append(tr("open decklists"));
|
||||
return result.join(", ");
|
||||
}
|
||||
case Qt::DecorationRole: {
|
||||
return gameentry.with_password() ? QIcon(LockPixmapGenerator::generatePixmap(13)) : QVariant();
|
||||
case Qt::TextAlignmentRole:
|
||||
return Qt::AlignLeft;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case PLAYERS:
|
||||
switch (role) {
|
||||
case SORT_ROLE:
|
||||
case Qt::DisplayRole:
|
||||
return QString("%1/%2").arg(gameentry.player_count()).arg(gameentry.max_players());
|
||||
case Qt::TextAlignmentRole:
|
||||
return Qt::AlignCenter;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
case SPECTATORS:
|
||||
switch (role) {
|
||||
case SORT_ROLE:
|
||||
case Qt::DisplayRole: {
|
||||
if (gameentry.spectators_allowed()) {
|
||||
QString result;
|
||||
result.append(QString::number(gameentry.spectators_count()));
|
||||
|
||||
if (gameentry.spectators_can_chat() && gameentry.spectators_omniscient()) {
|
||||
result.append(" (")
|
||||
.append(tr("can chat"))
|
||||
.append(" & ")
|
||||
.append(tr("see hands"))
|
||||
.append(")");
|
||||
} else if (gameentry.spectators_can_chat()) {
|
||||
result.append(" (").append(tr("can chat")).append(")");
|
||||
} else if (gameentry.spectators_omniscient()) {
|
||||
result.append(" (").append(tr("can see hands")).append(")");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return QVariant(tr("not allowed"));
|
||||
}
|
||||
case Qt::TextAlignmentRole:
|
||||
return Qt::AlignLeft;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant GamesModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
|
||||
{
|
||||
if ((role != Qt::DisplayRole) && (role != Qt::TextAlignmentRole))
|
||||
return QVariant();
|
||||
switch (section) {
|
||||
case ROOM:
|
||||
return tr("Room");
|
||||
case CREATED: {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return tr("Age");
|
||||
case Qt::TextAlignmentRole:
|
||||
return Qt::AlignCenter;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case DESCRIPTION:
|
||||
return tr("Description");
|
||||
case CREATOR:
|
||||
return tr("Creator");
|
||||
case GAME_TYPE:
|
||||
return tr("Type");
|
||||
case RESTRICTIONS:
|
||||
return tr("Restrictions");
|
||||
case PLAYERS: {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return tr("Players");
|
||||
case Qt::TextAlignmentRole:
|
||||
return Qt::AlignCenter;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case SPECTATORS:
|
||||
return tr("Spectators");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
const ServerInfo_Game &GamesModel::getGame(int row)
|
||||
{
|
||||
Q_ASSERT(row < gameList.size());
|
||||
return gameList[row];
|
||||
}
|
||||
|
||||
void GamesModel::updateGameList(const ServerInfo_Game &game)
|
||||
{
|
||||
for (int i = 0; i < gameList.size(); i++) {
|
||||
if (gameList[i].game_id() == game.game_id()) {
|
||||
if (game.closed()) {
|
||||
beginRemoveRows(QModelIndex(), i, i);
|
||||
gameList.removeAt(i);
|
||||
endRemoveRows();
|
||||
} else {
|
||||
gameList[i].MergeFrom(game);
|
||||
emit dataChanged(index(i, 0), index(i, NUM_COLS - 1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
beginInsertRows(QModelIndex(), gameList.size(), gameList.size());
|
||||
gameList.append(game);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
GamesProxyModel::GamesProxyModel(QObject *parent, const UserListProxy *_userListProxy)
|
||||
: QSortFilterProxyModel(parent), userListProxy(_userListProxy)
|
||||
{
|
||||
resetFilterParameters();
|
||||
setSortRole(GamesModel::SORT_ROLE);
|
||||
setDynamicSortFilter(true);
|
||||
}
|
||||
|
||||
void GamesProxyModel::setHideBuddiesOnlyGames(bool _showBuddiesOnlyGames)
|
||||
{
|
||||
hideBuddiesOnlyGames = _showBuddiesOnlyGames;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setHideIgnoredUserGames(bool _hideIgnoredUserGames)
|
||||
{
|
||||
hideIgnoredUserGames = _hideIgnoredUserGames;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setHideFullGames(bool _showFullGames)
|
||||
{
|
||||
hideFullGames = _showFullGames;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setHideGamesThatStarted(bool _showGamesThatStarted)
|
||||
{
|
||||
hideGamesThatStarted = _showGamesThatStarted;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setHidePasswordProtectedGames(bool _showPasswordProtectedGames)
|
||||
{
|
||||
hidePasswordProtectedGames = _showPasswordProtectedGames;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setHideNotBuddyCreatedGames(bool value)
|
||||
{
|
||||
hideNotBuddyCreatedGames = value;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setHideOpenDecklistGames(bool _hideOpenDecklistGames)
|
||||
{
|
||||
hideOpenDecklistGames = _hideOpenDecklistGames;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setGameNameFilter(const QString &_gameNameFilter)
|
||||
{
|
||||
gameNameFilter = _gameNameFilter;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setCreatorNameFilter(const QString &_creatorNameFilter)
|
||||
{
|
||||
creatorNameFilter = _creatorNameFilter;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setGameTypeFilter(const QSet<int> &_gameTypeFilter)
|
||||
{
|
||||
gameTypeFilter = _gameTypeFilter;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax)
|
||||
{
|
||||
maxPlayersFilterMin = _maxPlayersFilterMin;
|
||||
maxPlayersFilterMax = _maxPlayersFilterMax;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setMaxGameAge(const QTime &_maxGameAge)
|
||||
{
|
||||
maxGameAge = _maxGameAge;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setShowOnlyIfSpectatorsCanWatch(bool _showOnlyIfSpectatorsCanWatch)
|
||||
{
|
||||
showOnlyIfSpectatorsCanWatch = _showOnlyIfSpectatorsCanWatch;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setShowSpectatorPasswordProtected(bool _showSpectatorPasswordProtected)
|
||||
{
|
||||
showSpectatorPasswordProtected = _showSpectatorPasswordProtected;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setShowOnlyIfSpectatorsCanChat(bool _showOnlyIfSpectatorsCanChat)
|
||||
{
|
||||
showOnlyIfSpectatorsCanChat = _showOnlyIfSpectatorsCanChat;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::setShowOnlyIfSpectatorsCanSeeHands(bool _showOnlyIfSpectatorsCanSeeHands)
|
||||
{
|
||||
showOnlyIfSpectatorsCanSeeHands = _showOnlyIfSpectatorsCanSeeHands;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
int GamesProxyModel::getNumFilteredGames() const
|
||||
{
|
||||
GamesModel *model = qobject_cast<GamesModel *>(sourceModel());
|
||||
if (!model)
|
||||
return 0;
|
||||
|
||||
int numFilteredGames = 0;
|
||||
for (int row = 0; row < model->rowCount(); ++row) {
|
||||
if (!filterAcceptsRow(row)) {
|
||||
++numFilteredGames;
|
||||
}
|
||||
}
|
||||
return numFilteredGames;
|
||||
}
|
||||
|
||||
void GamesProxyModel::resetFilterParameters()
|
||||
{
|
||||
hideFullGames = false;
|
||||
hideGamesThatStarted = false;
|
||||
hidePasswordProtectedGames = false;
|
||||
hideBuddiesOnlyGames = false;
|
||||
hideIgnoredUserGames = false;
|
||||
hideNotBuddyCreatedGames = false;
|
||||
hideOpenDecklistGames = false;
|
||||
gameNameFilter = QString();
|
||||
creatorNameFilter = QString();
|
||||
gameTypeFilter.clear();
|
||||
maxPlayersFilterMin = DEFAULT_MAX_PLAYERS_MIN;
|
||||
maxPlayersFilterMax = DEFAULT_MAX_PLAYERS_MAX;
|
||||
maxGameAge = DEFAULT_MAX_GAME_AGE;
|
||||
showOnlyIfSpectatorsCanWatch = false;
|
||||
showSpectatorPasswordProtected = false;
|
||||
showOnlyIfSpectatorsCanChat = false;
|
||||
showOnlyIfSpectatorsCanSeeHands = false;
|
||||
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool GamesProxyModel::areFilterParametersSetToDefaults() const
|
||||
{
|
||||
return !hideFullGames && !hideGamesThatStarted && !hidePasswordProtectedGames && !hideBuddiesOnlyGames &&
|
||||
!hideOpenDecklistGames && !hideIgnoredUserGames && !hideNotBuddyCreatedGames && gameNameFilter.isEmpty() &&
|
||||
creatorNameFilter.isEmpty() && gameTypeFilter.isEmpty() && maxPlayersFilterMin == DEFAULT_MAX_PLAYERS_MIN &&
|
||||
maxPlayersFilterMax == DEFAULT_MAX_PLAYERS_MAX && maxGameAge == DEFAULT_MAX_GAME_AGE &&
|
||||
!showOnlyIfSpectatorsCanWatch && !showSpectatorPasswordProtected && !showOnlyIfSpectatorsCanChat &&
|
||||
!showOnlyIfSpectatorsCanSeeHands;
|
||||
}
|
||||
|
||||
void GamesProxyModel::loadFilterParameters(const QMap<int, QString> &allGameTypes)
|
||||
{
|
||||
GameFiltersSettings &gameFilters = SettingsCache::instance().gameFilters();
|
||||
hideFullGames = gameFilters.isHideFullGames();
|
||||
hideGamesThatStarted = gameFilters.isHideGamesThatStarted();
|
||||
hidePasswordProtectedGames = gameFilters.isHidePasswordProtectedGames();
|
||||
hideIgnoredUserGames = gameFilters.isHideIgnoredUserGames();
|
||||
hideBuddiesOnlyGames = gameFilters.isHideBuddiesOnlyGames();
|
||||
hideNotBuddyCreatedGames = gameFilters.isHideNotBuddyCreatedGames();
|
||||
hideOpenDecklistGames = gameFilters.isHideOpenDecklistGames();
|
||||
gameNameFilter = gameFilters.getGameNameFilter();
|
||||
creatorNameFilter = gameFilters.getCreatorNameFilter();
|
||||
maxPlayersFilterMin = gameFilters.getMinPlayers();
|
||||
maxPlayersFilterMax = gameFilters.getMaxPlayers();
|
||||
maxGameAge = gameFilters.getMaxGameAge();
|
||||
showOnlyIfSpectatorsCanWatch = gameFilters.isShowOnlyIfSpectatorsCanWatch();
|
||||
showSpectatorPasswordProtected = gameFilters.isShowSpectatorPasswordProtected();
|
||||
showOnlyIfSpectatorsCanChat = gameFilters.isShowOnlyIfSpectatorsCanChat();
|
||||
showOnlyIfSpectatorsCanSeeHands = gameFilters.isShowOnlyIfSpectatorsCanSeeHands();
|
||||
|
||||
QMapIterator<int, QString> gameTypesIterator(allGameTypes);
|
||||
while (gameTypesIterator.hasNext()) {
|
||||
gameTypesIterator.next();
|
||||
if (gameFilters.isGameTypeEnabled(gameTypesIterator.value())) {
|
||||
gameTypeFilter.insert(gameTypesIterator.key());
|
||||
}
|
||||
}
|
||||
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void GamesProxyModel::saveFilterParameters(const QMap<int, QString> &allGameTypes)
|
||||
{
|
||||
GameFiltersSettings &gameFilters = SettingsCache::instance().gameFilters();
|
||||
gameFilters.setHideBuddiesOnlyGames(hideBuddiesOnlyGames);
|
||||
gameFilters.setHideFullGames(hideFullGames);
|
||||
gameFilters.setHideGamesThatStarted(hideGamesThatStarted);
|
||||
gameFilters.setHidePasswordProtectedGames(hidePasswordProtectedGames);
|
||||
gameFilters.setHideIgnoredUserGames(hideIgnoredUserGames);
|
||||
gameFilters.setHideNotBuddyCreatedGames(hideNotBuddyCreatedGames);
|
||||
gameFilters.setHideOpenDecklistGames(hideOpenDecklistGames);
|
||||
gameFilters.setGameNameFilter(gameNameFilter);
|
||||
gameFilters.setCreatorNameFilter(creatorNameFilter);
|
||||
|
||||
QMapIterator<int, QString> gameTypeIterator(allGameTypes);
|
||||
while (gameTypeIterator.hasNext()) {
|
||||
gameTypeIterator.next();
|
||||
bool enabled = gameTypeFilter.contains(gameTypeIterator.key());
|
||||
gameFilters.setGameTypeEnabled(gameTypeIterator.value(), enabled);
|
||||
}
|
||||
|
||||
gameFilters.setMinPlayers(maxPlayersFilterMin);
|
||||
gameFilters.setMaxPlayers(maxPlayersFilterMax);
|
||||
gameFilters.setMaxGameAge(maxGameAge);
|
||||
|
||||
gameFilters.setShowOnlyIfSpectatorsCanWatch(showOnlyIfSpectatorsCanWatch);
|
||||
gameFilters.setShowSpectatorPasswordProtected(showSpectatorPasswordProtected);
|
||||
gameFilters.setShowOnlyIfSpectatorsCanChat(showOnlyIfSpectatorsCanChat);
|
||||
gameFilters.setShowOnlyIfSpectatorsCanSeeHands(showOnlyIfSpectatorsCanSeeHands);
|
||||
}
|
||||
|
||||
bool GamesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex & /*sourceParent*/) const
|
||||
{
|
||||
return filterAcceptsRow(sourceRow);
|
||||
}
|
||||
|
||||
bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
|
||||
static const QDate epochDate = QDateTime::fromSecsSinceEpoch(0, QTimeZone::UTC).date();
|
||||
#elif (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
|
||||
static const QDate epochDate = QDateTime::fromSecsSinceEpoch(0, Qt::UTC).date();
|
||||
#else
|
||||
static const QDate epochDate = QDateTime::fromTime_t(0, Qt::UTC).date();
|
||||
#endif
|
||||
auto *model = qobject_cast<GamesModel *>(sourceModel());
|
||||
if (!model)
|
||||
return false;
|
||||
|
||||
const ServerInfo_Game &game = model->getGame(sourceRow);
|
||||
|
||||
if (hideBuddiesOnlyGames && game.only_buddies()) {
|
||||
return false;
|
||||
}
|
||||
if (hideOpenDecklistGames && game.share_decklists_on_load()) {
|
||||
return false;
|
||||
}
|
||||
if (hideIgnoredUserGames && userListProxy->isUserIgnored(QString::fromStdString(game.creator_info().name()))) {
|
||||
return false;
|
||||
}
|
||||
if (hideNotBuddyCreatedGames && !userListProxy->isUserBuddy(QString::fromStdString(game.creator_info().name()))) {
|
||||
return false;
|
||||
}
|
||||
if (hideFullGames && game.player_count() == game.max_players())
|
||||
return false;
|
||||
if (hideGamesThatStarted && game.started())
|
||||
return false;
|
||||
if (!userListProxy->isOwnUserRegistered())
|
||||
if (game.only_registered())
|
||||
return false;
|
||||
if (hidePasswordProtectedGames && game.with_password())
|
||||
return false;
|
||||
if (!gameNameFilter.isEmpty())
|
||||
if (!QString::fromStdString(game.description()).contains(gameNameFilter, Qt::CaseInsensitive))
|
||||
return false;
|
||||
if (!creatorNameFilter.isEmpty())
|
||||
if (!QString::fromStdString(game.creator_info().name()).contains(creatorNameFilter, Qt::CaseInsensitive))
|
||||
return false;
|
||||
|
||||
QSet<int> gameTypes;
|
||||
for (int i = 0; i < game.game_types_size(); ++i)
|
||||
gameTypes.insert(game.game_types(i));
|
||||
if (!gameTypeFilter.isEmpty() && gameTypes.intersect(gameTypeFilter).isEmpty())
|
||||
return false;
|
||||
|
||||
if (game.max_players() < maxPlayersFilterMin)
|
||||
return false;
|
||||
if (game.max_players() > maxPlayersFilterMax)
|
||||
return false;
|
||||
|
||||
if (maxGameAge.isValid()) {
|
||||
QDateTime now = QDateTime::currentDateTimeUtc();
|
||||
qint64 signed_start_time = game.start_time(); // cast to 64 bit value to allow signed value
|
||||
QDateTime total = now.addSecs(-signed_start_time); // a 32 bit value would wrap at 2038-1-19
|
||||
// games shouldn't have negative ages but we'll not filter them
|
||||
// because qtime wraps after a day we consider all games older than a day to be too old
|
||||
if (total.isValid() && total.date() >= epochDate && (total.date() > epochDate || total.time() > maxGameAge)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (showOnlyIfSpectatorsCanWatch) {
|
||||
if (!game.spectators_allowed())
|
||||
return false;
|
||||
if (!showSpectatorPasswordProtected && game.spectators_need_password())
|
||||
return false;
|
||||
if (showOnlyIfSpectatorsCanChat && !game.spectators_can_chat())
|
||||
return false;
|
||||
if (showOnlyIfSpectatorsCanSeeHands && !game.spectators_omniscient())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GamesProxyModel::refresh()
|
||||
{
|
||||
invalidateFilter();
|
||||
}
|
||||
192
cockatrice/src/server/games_model.h
Normal file
192
cockatrice/src/server/games_model.h
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
#ifndef GAMESMODEL_H
|
||||
#define GAMESMODEL_H
|
||||
|
||||
#include "game_type_map.h"
|
||||
#include "pb/serverinfo_game.pb.h"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStringList>
|
||||
#include <QTime>
|
||||
|
||||
class UserListProxy;
|
||||
|
||||
class GamesModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QList<ServerInfo_Game> gameList;
|
||||
QMap<int, QString> rooms;
|
||||
QMap<int, GameTypeMap> gameTypes;
|
||||
|
||||
static const int NUM_COLS = 8;
|
||||
|
||||
public:
|
||||
static const int SORT_ROLE = Qt::UserRole + 1;
|
||||
|
||||
GamesModel(const QMap<int, QString> &_rooms, const QMap<int, GameTypeMap> &_gameTypes, QObject *parent = nullptr);
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||
{
|
||||
return parent.isValid() ? 0 : gameList.size();
|
||||
}
|
||||
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override
|
||||
{
|
||||
return NUM_COLS;
|
||||
}
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
static const QString getGameCreatedString(const int secs);
|
||||
const ServerInfo_Game &getGame(int row);
|
||||
|
||||
/**
|
||||
* Update game list with a (possibly new) game.
|
||||
*/
|
||||
void updateGameList(const ServerInfo_Game &game);
|
||||
|
||||
int roomColIndex()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int startTimeColIndex()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const QMap<int, GameTypeMap> &getGameTypes()
|
||||
{
|
||||
return gameTypes;
|
||||
}
|
||||
};
|
||||
|
||||
class ServerInfo_User;
|
||||
|
||||
class GamesProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
const UserListProxy *userListProxy;
|
||||
|
||||
// If adding any additional filters, make sure to update:
|
||||
// - GamesProxyModel()
|
||||
// - resetFilterParameters()
|
||||
// - areFilterParametersSetToDefaults()
|
||||
// - loadFilterParameters()
|
||||
// - saveFilterParameters()
|
||||
// - filterAcceptsRow()
|
||||
bool hideBuddiesOnlyGames;
|
||||
bool hideIgnoredUserGames;
|
||||
bool hideFullGames;
|
||||
bool hideGamesThatStarted;
|
||||
bool hidePasswordProtectedGames;
|
||||
bool hideNotBuddyCreatedGames;
|
||||
bool hideOpenDecklistGames;
|
||||
QString gameNameFilter, creatorNameFilter;
|
||||
QSet<int> gameTypeFilter;
|
||||
quint32 maxPlayersFilterMin, maxPlayersFilterMax;
|
||||
QTime maxGameAge;
|
||||
bool showOnlyIfSpectatorsCanWatch, showSpectatorPasswordProtected, showOnlyIfSpectatorsCanChat,
|
||||
showOnlyIfSpectatorsCanSeeHands;
|
||||
|
||||
public:
|
||||
explicit GamesProxyModel(QObject *parent = nullptr, const UserListProxy *_userListProxy = nullptr);
|
||||
|
||||
bool getHideBuddiesOnlyGames() const
|
||||
{
|
||||
return hideBuddiesOnlyGames;
|
||||
}
|
||||
void setHideBuddiesOnlyGames(bool _showBuddiesOnlyGames);
|
||||
bool getHideIgnoredUserGames() const
|
||||
{
|
||||
return hideIgnoredUserGames;
|
||||
}
|
||||
void setHideIgnoredUserGames(bool _hideIgnoredUserGames);
|
||||
bool getHideFullGames() const
|
||||
{
|
||||
return hideFullGames;
|
||||
}
|
||||
void setHideFullGames(bool _showFullGames);
|
||||
bool getHideGamesThatStarted() const
|
||||
{
|
||||
return hideGamesThatStarted;
|
||||
}
|
||||
void setHideGamesThatStarted(bool _showGamesThatStarted);
|
||||
bool getHidePasswordProtectedGames() const
|
||||
{
|
||||
return hidePasswordProtectedGames;
|
||||
}
|
||||
void setHidePasswordProtectedGames(bool _showPasswordProtectedGames);
|
||||
bool getHideNotBuddyCreatedGames() const
|
||||
{
|
||||
return hideNotBuddyCreatedGames;
|
||||
}
|
||||
void setHideNotBuddyCreatedGames(bool value);
|
||||
bool getHideOpenDecklistGames() const
|
||||
{
|
||||
return hideOpenDecklistGames;
|
||||
}
|
||||
void setHideOpenDecklistGames(bool _hideOpenDecklistGames);
|
||||
QString getGameNameFilter() const
|
||||
{
|
||||
return gameNameFilter;
|
||||
}
|
||||
void setGameNameFilter(const QString &_gameNameFilter);
|
||||
QString getCreatorNameFilter() const
|
||||
{
|
||||
return creatorNameFilter;
|
||||
}
|
||||
void setCreatorNameFilter(const QString &_creatorNameFilter);
|
||||
QSet<int> getGameTypeFilter() const
|
||||
{
|
||||
return gameTypeFilter;
|
||||
}
|
||||
void setGameTypeFilter(const QSet<int> &_gameTypeFilter);
|
||||
int getMaxPlayersFilterMin() const
|
||||
{
|
||||
return maxPlayersFilterMin;
|
||||
}
|
||||
int getMaxPlayersFilterMax() const
|
||||
{
|
||||
return maxPlayersFilterMax;
|
||||
}
|
||||
void setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax);
|
||||
const QTime &getMaxGameAge() const
|
||||
{
|
||||
return maxGameAge;
|
||||
}
|
||||
void setMaxGameAge(const QTime &_maxGameAge);
|
||||
bool getShowOnlyIfSpectatorsCanWatch() const
|
||||
{
|
||||
return showOnlyIfSpectatorsCanWatch;
|
||||
}
|
||||
void setShowOnlyIfSpectatorsCanWatch(bool _showOnlyIfSpectatorsCanWatch);
|
||||
bool getShowSpectatorPasswordProtected() const
|
||||
{
|
||||
return showSpectatorPasswordProtected;
|
||||
}
|
||||
void setShowSpectatorPasswordProtected(bool _showSpectatorPasswordProtected);
|
||||
bool getShowOnlyIfSpectatorsCanChat() const
|
||||
{
|
||||
return showOnlyIfSpectatorsCanChat;
|
||||
}
|
||||
void setShowOnlyIfSpectatorsCanChat(bool _showOnlyIfSpectatorsCanChat);
|
||||
bool getShowOnlyIfSpectatorsCanSeeHands() const
|
||||
{
|
||||
return showOnlyIfSpectatorsCanSeeHands;
|
||||
}
|
||||
void setShowOnlyIfSpectatorsCanSeeHands(bool _showOnlyIfSpectatorsCanSeeHands);
|
||||
|
||||
int getNumFilteredGames() const;
|
||||
void resetFilterParameters();
|
||||
bool areFilterParametersSetToDefaults() const;
|
||||
void loadFilterParameters(const QMap<int, QString> &allGameTypes);
|
||||
void saveFilterParameters(const QMap<int, QString> &allGameTypes);
|
||||
void refresh();
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
bool filterAcceptsRow(int sourceRow) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,842 +0,0 @@
|
|||
#include "message_log_widget.h"
|
||||
|
||||
#include "../client/sound_engine.h"
|
||||
#include "../client/tabs/tab_game.h"
|
||||
#include "../client/translate_counter_name.h"
|
||||
#include "../game/board/card_item.h"
|
||||
#include "../game/phase.h"
|
||||
#include "../game/player/player.h"
|
||||
#include "../game/zones/card_zone.h"
|
||||
#include "../settings/card_counter_settings.h"
|
||||
#include "pb/context_move_card.pb.h"
|
||||
#include "pb/context_mulligan.pb.h"
|
||||
#include "pb/serverinfo_user.pb.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
static const QString TABLE_ZONE_NAME = "table";
|
||||
static const QString GRAVE_ZONE_NAME = "grave";
|
||||
static const QString EXILE_ZONE_NAME = "rfg";
|
||||
static const QString HAND_ZONE_NAME = "hand";
|
||||
static const QString DECK_ZONE_NAME = "deck";
|
||||
static const QString SIDEBOARD_ZONE_NAME = "sb";
|
||||
static const QString STACK_ZONE_NAME = "stack";
|
||||
|
||||
static QString sanitizeHtml(QString dirty)
|
||||
{
|
||||
return dirty.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """);
|
||||
}
|
||||
|
||||
static QString cardLink(const QString &cardName)
|
||||
{
|
||||
return QString("<i><a href=\"card://%1\">%2</a></i>").arg(cardName).arg(cardName);
|
||||
}
|
||||
|
||||
QPair<QString, QString>
|
||||
MessageLogWidget::getFromStr(CardZoneLogic *zone, QString cardName, int position, bool ownerChange)
|
||||
{
|
||||
bool cardNameContainsStartZone = false;
|
||||
QString fromStr;
|
||||
QString zoneName = zone->getName();
|
||||
|
||||
if (zoneName == TABLE_ZONE_NAME) {
|
||||
fromStr = tr(" from play");
|
||||
} else if (zoneName == GRAVE_ZONE_NAME) {
|
||||
fromStr = tr(" from their graveyard");
|
||||
} else if (zoneName == EXILE_ZONE_NAME) {
|
||||
fromStr = tr(" from exile");
|
||||
} else if (zoneName == HAND_ZONE_NAME) {
|
||||
fromStr = tr(" from their hand");
|
||||
} else if (zoneName == DECK_ZONE_NAME) {
|
||||
if (position == 0) {
|
||||
if (cardName.isEmpty()) {
|
||||
if (ownerChange) {
|
||||
cardName = tr("the top card of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||
} else {
|
||||
cardName = tr("the top card of their library");
|
||||
}
|
||||
cardNameContainsStartZone = true;
|
||||
} else {
|
||||
if (ownerChange) {
|
||||
fromStr = tr(" from the top of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||
} else {
|
||||
fromStr = tr(" from the top of their library");
|
||||
}
|
||||
}
|
||||
} else if (position >= zone->getCards().size() - 1) {
|
||||
if (cardName.isEmpty()) {
|
||||
if (ownerChange) {
|
||||
cardName = tr("the bottom card of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||
} else {
|
||||
cardName = tr("the bottom card of their library");
|
||||
}
|
||||
cardNameContainsStartZone = true;
|
||||
} else {
|
||||
if (ownerChange) {
|
||||
fromStr = tr(" from the bottom of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||
} else {
|
||||
fromStr = tr(" from the bottom of their library");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ownerChange) {
|
||||
fromStr = tr(" from %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||
} else {
|
||||
fromStr = tr(" from their library");
|
||||
}
|
||||
}
|
||||
} else if (zoneName == SIDEBOARD_ZONE_NAME) {
|
||||
fromStr = tr(" from sideboard");
|
||||
} else if (zoneName == STACK_ZONE_NAME) {
|
||||
fromStr = tr(" from the stack");
|
||||
} else {
|
||||
fromStr = tr(" from custom zone '%1'").arg(zoneName);
|
||||
}
|
||||
|
||||
if (!cardNameContainsStartZone) {
|
||||
cardName.clear();
|
||||
}
|
||||
return {cardName, fromStr};
|
||||
}
|
||||
|
||||
void MessageLogWidget::containerProcessingDone()
|
||||
{
|
||||
currentContext = MessageContext_None;
|
||||
messageSuffix = messagePrefix = QString();
|
||||
}
|
||||
|
||||
void MessageLogWidget::containerProcessingStarted(const GameEventContext &context)
|
||||
{
|
||||
if (context.HasExtension(Context_MoveCard::ext)) {
|
||||
currentContext = MessageContext_MoveCard;
|
||||
} else if (context.HasExtension(Context_Mulligan::ext)) {
|
||||
currentContext = MessageContext_Mulligan;
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logAlwaysRevealTopCard(Player *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."))
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logAlwaysLookAtTopCard(Player *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."))
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName)
|
||||
{
|
||||
appendHtmlServerMessage(tr("%1 attaches %2 to %3's %4.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(std::move(cardName)))
|
||||
.arg(sanitizeHtml(targetPlayer->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(std::move(targetCardName))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logConcede(int playerId)
|
||||
{
|
||||
soundEngine->playSound("player_concede");
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has conceded the game.")
|
||||
.arg(sanitizeHtml(game->getPlayerManager()->getPlayer(playerId)->getPlayerInfo()->getName())),
|
||||
true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logUnconcede(int playerId)
|
||||
{
|
||||
soundEngine->playSound("player_concede");
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has unconceded the game.")
|
||||
.arg(sanitizeHtml(game->getPlayerManager()->getPlayer(playerId)->getPlayerInfo()->getName())),
|
||||
true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logConnectionStateChanged(Player *player, bool connectionState)
|
||||
{
|
||||
if (connectionState) {
|
||||
soundEngine->playSound("player_reconnect");
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has restored connection to the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())), true);
|
||||
} else {
|
||||
soundEngine->playSound("player_disconnect");
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has lost connection to the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())), true);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logCreateArrow(Player *player,
|
||||
Player *startPlayer,
|
||||
QString startCard,
|
||||
Player *targetPlayer,
|
||||
QString targetCard,
|
||||
bool playerTarget)
|
||||
{
|
||||
startCard = cardLink(startCard);
|
||||
targetCard = cardLink(targetCard);
|
||||
QString str;
|
||||
if (playerTarget) {
|
||||
if (player == startPlayer && player == targetPlayer) {
|
||||
str = tr("%1 points from their %2 to themselves.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(startCard));
|
||||
} else if (player == startPlayer) {
|
||||
str = tr("%1 points from their %2 to %3.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(startCard)
|
||||
.arg(sanitizeHtml(targetPlayer->getPlayerInfo()->getName())));
|
||||
} else if (player == targetPlayer) {
|
||||
str = tr("%1 points from %2's %3 to themselves.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(sanitizeHtml(startPlayer->getPlayerInfo()->getName()))
|
||||
.arg(startCard));
|
||||
} else {
|
||||
str = tr("%1 points from %2's %3 to %4.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(sanitizeHtml(startPlayer->getPlayerInfo()->getName()))
|
||||
.arg(startCard)
|
||||
.arg(sanitizeHtml(targetPlayer->getPlayerInfo()->getName())));
|
||||
}
|
||||
} else {
|
||||
if (player == startPlayer && player == targetPlayer) {
|
||||
str = tr("%1 points from their %2 to their %3.");
|
||||
appendHtmlServerMessage(
|
||||
str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(startCard).arg(targetCard));
|
||||
} else if (player == startPlayer) {
|
||||
str = tr("%1 points from their %2 to %3's %4.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(startCard)
|
||||
.arg(sanitizeHtml(targetPlayer->getPlayerInfo()->getName()))
|
||||
.arg(targetCard));
|
||||
} else if (player == targetPlayer) {
|
||||
str = tr("%1 points from %2's %3 to their own %4.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(sanitizeHtml(startPlayer->getPlayerInfo()->getName()))
|
||||
.arg(startCard)
|
||||
.arg(targetCard));
|
||||
} else {
|
||||
str = tr("%1 points from %2's %3 to %4's %5.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(sanitizeHtml(startPlayer->getPlayerInfo()->getName()))
|
||||
.arg(startCard)
|
||||
.arg(sanitizeHtml(targetPlayer->getPlayerInfo()->getName()))
|
||||
.arg(targetCard));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logCreateToken(Player *player, QString cardName, QString pt, bool faceDown)
|
||||
{
|
||||
if (faceDown) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 creates a face down token.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 creates token: %2%3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(std::move(cardName)))
|
||||
.arg(pt.isEmpty() ? QString() : QString(" (%1)").arg(sanitizeHtml(pt))));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logDeckSelect(Player *player, QString deckHash, int sideboardSize)
|
||||
{
|
||||
if (sideboardSize < 0) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has loaded a deck (%2).").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(deckHash));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 has loaded a deck with %2 sideboard cards (%3).")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(sideboardSize) + "</font>")
|
||||
.arg(deckHash));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logDestroyCard(Player *player, QString cardName)
|
||||
{
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 destroys %2.").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(std::move(cardName))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logMoveCard(Player *player,
|
||||
CardItem *card,
|
||||
CardZoneLogic *startZone,
|
||||
int oldX,
|
||||
CardZoneLogic *targetZone,
|
||||
int newX)
|
||||
{
|
||||
if (currentContext == MessageContext_Mulligan) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString startZoneName = startZone->getName();
|
||||
QString targetZoneName = targetZone->getName();
|
||||
bool ownerChanged = startZone->getPlayer() != targetZone->getPlayer();
|
||||
|
||||
// do not log if moved within the same zone
|
||||
if ((startZoneName == TABLE_ZONE_NAME && targetZoneName == TABLE_ZONE_NAME && !ownerChanged) ||
|
||||
(startZoneName == HAND_ZONE_NAME && targetZoneName == HAND_ZONE_NAME) ||
|
||||
(startZoneName == EXILE_ZONE_NAME && targetZoneName == EXILE_ZONE_NAME)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString cardName = card->getName();
|
||||
QPair<QString, QString> nameFrom = getFromStr(startZone, cardName, oldX, ownerChanged);
|
||||
if (!nameFrom.first.isEmpty()) {
|
||||
cardName = nameFrom.first;
|
||||
}
|
||||
|
||||
QString cardStr;
|
||||
if (!nameFrom.first.isEmpty()) {
|
||||
cardStr = cardName;
|
||||
} else if (cardName.isEmpty()) {
|
||||
cardStr = tr("a card");
|
||||
} else {
|
||||
cardStr = cardLink(cardName);
|
||||
}
|
||||
|
||||
if (ownerChanged && (startZone->getPlayer() == player)) {
|
||||
appendHtmlServerMessage(tr("%1 gives %2 control over %3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(sanitizeHtml(targetZone->getPlayer()->getPlayerInfo()->getName()))
|
||||
.arg(cardStr));
|
||||
return;
|
||||
}
|
||||
|
||||
QString finalStr;
|
||||
std::optional<QString> fourthArg;
|
||||
if (targetZoneName == TABLE_ZONE_NAME) {
|
||||
soundEngine->playSound("play_card");
|
||||
if (card->getFaceDown()) {
|
||||
finalStr = tr("%1 puts %2 into play%3 face down.");
|
||||
} else {
|
||||
finalStr = tr("%1 puts %2 into play%3.");
|
||||
}
|
||||
} else if (targetZoneName == GRAVE_ZONE_NAME) {
|
||||
finalStr = tr("%1 puts %2%3 into their graveyard.");
|
||||
} else if (targetZoneName == EXILE_ZONE_NAME) {
|
||||
finalStr = tr("%1 exiles %2%3.");
|
||||
} else if (targetZoneName == HAND_ZONE_NAME) {
|
||||
finalStr = tr("%1 moves %2%3 to their hand.");
|
||||
} else if (targetZoneName == DECK_ZONE_NAME) {
|
||||
if (newX == -1) {
|
||||
finalStr = tr("%1 puts %2%3 into their library.");
|
||||
} else if (newX >= targetZone->getCards().size()) {
|
||||
finalStr = tr("%1 puts %2%3 onto the bottom of their library.");
|
||||
} else if (newX == 0) {
|
||||
finalStr = tr("%1 puts %2%3 on top of their library.");
|
||||
} else {
|
||||
++newX;
|
||||
fourthArg = QString::number(newX);
|
||||
finalStr = tr("%1 puts %2%3 into their library %4 cards from the top.");
|
||||
}
|
||||
} else if (targetZoneName == SIDEBOARD_ZONE_NAME) {
|
||||
finalStr = tr("%1 moves %2%3 to sideboard.");
|
||||
} else if (targetZoneName == STACK_ZONE_NAME) {
|
||||
soundEngine->playSound("play_card");
|
||||
finalStr = tr("%1 plays %2%3.");
|
||||
} else {
|
||||
fourthArg = targetZoneName;
|
||||
finalStr = tr("%1 moves %2%3 to custom zone '%4'.");
|
||||
}
|
||||
|
||||
QString message = finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()), cardStr, nameFrom.second);
|
||||
|
||||
if (fourthArg.has_value()) {
|
||||
message = message.arg(fourthArg.value());
|
||||
}
|
||||
|
||||
appendHtmlServerMessage(message);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logDrawCards(Player *player, int number, bool deckIsEmpty)
|
||||
{
|
||||
soundEngine->playSound("draw_card");
|
||||
if (currentContext == MessageContext_Mulligan) {
|
||||
logMulligan(player, number);
|
||||
} else {
|
||||
if (deckIsEmpty && number == 0) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 tries to draw from an empty library").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 draws %2 card(s).", "", number)
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(number) + "</font>"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logDumpZone(Player *player, CardZoneLogic *zone, int numberCards, bool isReversed)
|
||||
{
|
||||
if (numberCards == -1) {
|
||||
appendHtmlServerMessage(tr("%1 is looking at %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(zone->getPlayer() == player, CaseLookAtZone)));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 is looking at the %4 %3 card(s) %2.", "top card for singular, top %3 cards for plural", numberCards)
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(zone->getPlayer() == player, CaseTopCardsOfZone))
|
||||
.arg("<font class=\"blue\">" + QString::number(numberCards) + "</font>")
|
||||
.arg(isReversed ? tr("bottom") : tr("top")));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logFlipCard(Player *player, QString cardName, bool faceDown)
|
||||
{
|
||||
if (faceDown) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 turns %2 face-down.").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(cardName)));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 turns %2 face-up.").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(cardName)));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logGameClosed()
|
||||
{
|
||||
appendHtmlServerMessage(tr("The game has been closed."));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logGameStart()
|
||||
{
|
||||
appendHtmlServerMessage(tr("The game has started."));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logGameFlooded()
|
||||
{
|
||||
appendMessage(tr("You are flooding the game. Please wait a couple of seconds."));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logJoin(Player *player)
|
||||
{
|
||||
soundEngine->playSound("player_join");
|
||||
appendHtmlServerMessage(tr("%1 has joined the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logJoinSpectator(QString name)
|
||||
{
|
||||
soundEngine->playSound("spectator_join");
|
||||
appendHtmlServerMessage(tr("%1 is now watching the game.").arg(sanitizeHtml(std::move(name))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logKicked()
|
||||
{
|
||||
appendHtmlServerMessage(tr("You have been kicked out of the game."), true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logLeave(Player *player, QString reason)
|
||||
{
|
||||
soundEngine->playSound("player_leave");
|
||||
appendHtmlServerMessage(tr("%1 has left the game (%2).")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()), sanitizeHtml(std::move(reason))),
|
||||
true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logLeaveSpectator(QString name, QString reason)
|
||||
{
|
||||
soundEngine->playSound("spectator_leave");
|
||||
appendHtmlServerMessage(tr("%1 is not watching the game any more (%2).")
|
||||
.arg(sanitizeHtml(std::move(name)), sanitizeHtml(std::move(reason))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logNotReadyStart(Player *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)
|
||||
{
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
if (number > 0) {
|
||||
appendHtmlServerMessage(tr("%1 shuffles their deck and draws a new hand of %2 card(s).", "", number)
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(number));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 shuffles their deck and draws a new hand.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logReplayStarted(int gameId)
|
||||
{
|
||||
appendHtmlServerMessage(tr("You are watching a replay of game #%1.").arg(gameId));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logReadyStart(Player *player)
|
||||
{
|
||||
appendHtmlServerMessage(tr("%1 is ready to start the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logRevealCards(Player *player,
|
||||
CardZoneLogic *zone,
|
||||
int cardId,
|
||||
QString cardName,
|
||||
Player *otherPlayer,
|
||||
bool faceDown,
|
||||
int amount,
|
||||
bool isLentToAnotherPlayer)
|
||||
{
|
||||
// getFromStr uses cardname.empty() to check if it should contain the start zone, it's not actually used
|
||||
QPair<QString, QString> temp = getFromStr(zone, amount == 1 ? cardName : QString::number(amount), cardId, false);
|
||||
bool cardNameContainsStartZone = false;
|
||||
if (!temp.first.isEmpty()) {
|
||||
cardNameContainsStartZone = true;
|
||||
cardName = temp.first;
|
||||
}
|
||||
QString fromStr = temp.second;
|
||||
|
||||
QString cardStr;
|
||||
if (cardNameContainsStartZone) {
|
||||
cardStr = cardName;
|
||||
} else if (cardName.isEmpty()) {
|
||||
if (amount == 0) {
|
||||
cardStr = tr("cards", "an unknown amount of cards");
|
||||
} else {
|
||||
cardStr = tr("%1 card(s)", "a card for singular, %1 cards for plural", amount)
|
||||
.arg("<font class=\"blue\">" + QString::number(amount) + "</font>");
|
||||
}
|
||||
} else {
|
||||
cardStr = cardLink(cardName);
|
||||
}
|
||||
if (cardId == -1) {
|
||||
if (otherPlayer) {
|
||||
if (isLentToAnotherPlayer) {
|
||||
appendHtmlServerMessage(tr("%1 lends %2 to %3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseRevealZone))
|
||||
.arg(sanitizeHtml(otherPlayer->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 reveals %2 to %3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseRevealZone))
|
||||
.arg(sanitizeHtml(otherPlayer->getPlayerInfo()->getName())));
|
||||
}
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 reveals %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseRevealZone)));
|
||||
}
|
||||
} else if (cardId == -2) {
|
||||
if (otherPlayer) {
|
||||
appendHtmlServerMessage(tr("%1 randomly reveals %2%3 to %4.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardStr)
|
||||
.arg(fromStr)
|
||||
.arg(sanitizeHtml(otherPlayer->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 randomly reveals %2%3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardStr)
|
||||
.arg(fromStr));
|
||||
}
|
||||
} else {
|
||||
if (faceDown && player == otherPlayer) {
|
||||
if (cardName.isEmpty()) {
|
||||
appendHtmlServerMessage(tr("%1 peeks at face down card #%2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardId));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 peeks at face down card #%2: %3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardId)
|
||||
.arg(cardStr));
|
||||
}
|
||||
} else if (otherPlayer) {
|
||||
appendHtmlServerMessage(tr("%1 reveals %2%3 to %4.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardStr)
|
||||
.arg(fromStr)
|
||||
.arg(sanitizeHtml(otherPlayer->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 reveals %2%3.").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardStr).arg(fromStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logReverseTurn(Player *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)
|
||||
{
|
||||
if (rolls.length() == 1) {
|
||||
const auto roll = rolls.at(0);
|
||||
if (sides == 2) {
|
||||
QString coinOptions[2] = {tr("Heads") + " (1)", tr("Tails") + " (2)"};
|
||||
appendHtmlServerMessage(tr("%1 flipped a coin. It landed as %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + coinOptions[roll - 1] + "</font>"));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 rolls a %2 with a %3-sided die.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(roll) + "</font>")
|
||||
.arg("<font class=\"blue\">" + QString::number(sides) + "</font>"));
|
||||
}
|
||||
} else {
|
||||
if (sides == 2) {
|
||||
appendHtmlServerMessage(tr("%1 flips %2 coins. There are %3 heads and %4 tails.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(rolls.length()) + "</font>")
|
||||
.arg("<font class=\"blue\">" + QString::number(rolls.count(1)) + "</font>")
|
||||
.arg("<font class=\"blue\">" + QString::number(rolls.count(2)) + "</font>"));
|
||||
} else {
|
||||
QStringList rollsStrings;
|
||||
for (const auto &roll : rolls) {
|
||||
rollsStrings.append(QString::number(roll));
|
||||
}
|
||||
appendHtmlServerMessage(tr("%1 rolls a %2-sided dice %3 times: %4.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(sides) + "</font>")
|
||||
.arg("<font class=\"blue\">" + QString::number(rolls.length()) + "</font>")
|
||||
.arg("<font class=\"blue\">" + rollsStrings.join(", ") + "</font>"));
|
||||
}
|
||||
}
|
||||
soundEngine->playSound("roll_dice");
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSay(Player *player, QString message)
|
||||
{
|
||||
appendMessage(std::move(message), {}, *player->getPlayerInfo()->getUserInfo(), true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetActivePhase(int phaseNumber)
|
||||
{
|
||||
Phase phase = Phases::getPhase(phaseNumber);
|
||||
|
||||
soundEngine->playSound(phase.soundFileName);
|
||||
|
||||
appendHtml("<font color=\"" + phase.color + "\"><b>" + QDateTime::currentDateTime().toString("[hh:mm:ss] ") +
|
||||
phase.getName() + "</b></font>");
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetActivePlayer(Player *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)
|
||||
{
|
||||
appendHtmlServerMessage(
|
||||
QString(tr("%1 sets annotation of %2 to %3."))
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(card->getName()))
|
||||
.arg(QString(""<font class=\"blue\">%1</font>"").arg(sanitizeHtml(std::move(newAnnotation)))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetCardCounter(Player *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);
|
||||
} else {
|
||||
finalStr = tr("%1 removes %2 \"%3\" counter(s) from %4 (now %5).", "", delta);
|
||||
}
|
||||
|
||||
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
|
||||
appendHtmlServerMessage(finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(delta) + "</font>")
|
||||
.arg(cardCounterSettings.displayName(counterId))
|
||||
.arg(cardLink(std::move(cardName)))
|
||||
.arg(value));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetCounter(Player *player, QString counterName, int value, int oldValue)
|
||||
{
|
||||
if (counterName == "life") {
|
||||
soundEngine->playSound("life_change");
|
||||
}
|
||||
|
||||
QString counterDisplayName = TranslateCounterName::getDisplayName(counterName);
|
||||
appendHtmlServerMessage(tr("%1 sets counter %2 to %3 (%4%5).")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(QString("<font class=\"blue\">%1</font>").arg(sanitizeHtml(counterDisplayName)))
|
||||
.arg(QString("<font class=\"blue\">%1</font>").arg(value))
|
||||
.arg(value > oldValue ? "+" : "")
|
||||
.arg(value - oldValue));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetDoesntUntap(Player *player, CardItem *card, bool doesntUntap)
|
||||
{
|
||||
QString str;
|
||||
if (doesntUntap) {
|
||||
str = tr("%1 sets %2 to not untap normally.");
|
||||
} else {
|
||||
str = tr("%1 sets %2 to untap normally.");
|
||||
}
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(card->getName())));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetPT(Player *player, CardItem *card, QString newPT)
|
||||
{
|
||||
if (currentContext == MessageContext_MoveCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString name = card->getName();
|
||||
if (name.isEmpty()) {
|
||||
name = QString("<font class=\"blue\">card #%1</font>").arg(sanitizeHtml(QString::number(card->getId())));
|
||||
} else {
|
||||
name = cardLink(name);
|
||||
}
|
||||
QString playerName = sanitizeHtml(player->getPlayerInfo()->getName());
|
||||
if (newPT.isEmpty()) {
|
||||
appendHtmlServerMessage(tr("%1 removes the PT of %2.").arg(playerName).arg(name));
|
||||
} else {
|
||||
QString oldPT = card->getPT();
|
||||
if (oldPT.isEmpty()) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 changes the PT of %2 from nothing to %4.").arg(playerName).arg(name).arg(newPT));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 changes the PT of %2 from %3 to %4.").arg(playerName).arg(name).arg(oldPT).arg(newPT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetSideboardLock(Player *player, bool locked)
|
||||
{
|
||||
if (locked) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has locked their sideboard.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has unlocked their sideboard.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetTapped(Player *player, CardItem *card, bool tapped)
|
||||
{
|
||||
if (currentContext == MessageContext_MoveCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tapped) {
|
||||
soundEngine->playSound("tap_card");
|
||||
} else {
|
||||
soundEngine->playSound("untap_card");
|
||||
}
|
||||
|
||||
QString str;
|
||||
if (!card) {
|
||||
appendHtmlServerMessage((tapped ? tr("%1 taps their permanents.") : tr("%1 untaps their permanents."))
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage((tapped ? tr("%1 taps %2.") : tr("%1 untaps %2."))
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(card->getName())));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logShuffle(Player *player, CardZoneLogic *zone, int start, int end)
|
||||
{
|
||||
if (currentContext == MessageContext_Mulligan) {
|
||||
return;
|
||||
}
|
||||
|
||||
soundEngine->playSound("shuffle");
|
||||
// start and end are indexes into the portion of the deck that was shuffled
|
||||
// with negitive numbers counging from the bottom up.
|
||||
if (start == 0 && end == -1) {
|
||||
appendHtmlServerMessage(tr("%1 shuffles %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseShuffleZone)));
|
||||
} else if (start < 0 && end == -1) {
|
||||
appendHtmlServerMessage(tr("%1 shuffles the bottom %3 cards of %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseShuffleZone))
|
||||
.arg(-start));
|
||||
} else if (start < 0 && end > 0) {
|
||||
appendHtmlServerMessage(tr("%1 shuffles the top %3 cards of %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseShuffleZone))
|
||||
.arg(end + 1));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 shuffles cards %3 - %4 of %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseShuffleZone))
|
||||
.arg(start)
|
||||
.arg(end));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSpectatorSay(const ServerInfo_User &spectator, QString message)
|
||||
{
|
||||
appendMessage(std::move(message), {}, spectator, false);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logUnattachCard(Player *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)
|
||||
{
|
||||
if (cardName.isEmpty()) {
|
||||
appendHtmlServerMessage(tr("%1 undoes their last draw.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 undoes their last draw (%2).")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(QString("<a href=\"card://%1\">%2</a>").arg(sanitizeHtml(cardName)).arg(sanitizeHtml(cardName))));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::setContextJudgeName(QString name)
|
||||
{
|
||||
messagePrefix = QString("<span style=\"color:black\">");
|
||||
messageSuffix = QString("</span> [<img height=12 src=\"theme:icons/scales\"> %1]").arg(sanitizeHtml(name));
|
||||
}
|
||||
|
||||
void MessageLogWidget::appendHtmlServerMessage(const QString &html, bool optionalIsBold, QString optionalFontColor)
|
||||
{
|
||||
|
||||
ChatView::appendHtmlServerMessage(messagePrefix + html + messageSuffix, optionalIsBold, optionalFontColor);
|
||||
}
|
||||
|
||||
void MessageLogWidget::connectToPlayerEventHandler(PlayerEventHandler *playerEventHandler)
|
||||
{
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSay, this, &MessageLogWidget::logSay);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logShuffle, this, &MessageLogWidget::logShuffle);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logRollDie, this, &MessageLogWidget::logRollDie);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logCreateArrow, this, &MessageLogWidget::logCreateArrow);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logCreateToken, this, &MessageLogWidget::logCreateToken);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetCounter, this, &MessageLogWidget::logSetCounter);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetCardCounter, this, &MessageLogWidget::logSetCardCounter);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetTapped, this, &MessageLogWidget::logSetTapped);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetDoesntUntap, this, &MessageLogWidget::logSetDoesntUntap);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetPT, this, &MessageLogWidget::logSetPT);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetAnnotation, this, &MessageLogWidget::logSetAnnotation);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logMoveCard, this, &MessageLogWidget::logMoveCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logFlipCard, this, &MessageLogWidget::logFlipCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logDestroyCard, this, &MessageLogWidget::logDestroyCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logAttachCard, this, &MessageLogWidget::logAttachCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logUnattachCard, this, &MessageLogWidget::logUnattachCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logDumpZone, this, &MessageLogWidget::logDumpZone);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logDrawCards, this, &MessageLogWidget::logDrawCards);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logUndoDraw, this, &MessageLogWidget::logUndoDraw);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logRevealCards, this, &MessageLogWidget::logRevealCards);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logAlwaysRevealTopCard, this,
|
||||
&MessageLogWidget::logAlwaysRevealTopCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logAlwaysLookAtTopCard, this,
|
||||
&MessageLogWidget::logAlwaysLookAtTopCard);
|
||||
}
|
||||
|
||||
MessageLogWidget::MessageLogWidget(TabSupervisor *_tabSupervisor, AbstractGame *_game, QWidget *parent)
|
||||
: ChatView(_tabSupervisor, _game, true, parent), currentContext(MessageContext_None)
|
||||
{
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
#ifndef MESSAGELOGWIDGET_H
|
||||
#define MESSAGELOGWIDGET_H
|
||||
|
||||
#include "../client/translation.h"
|
||||
#include "../game/zones/logic/card_zone_logic.h"
|
||||
#include "chat_view/chat_view.h"
|
||||
#include "user_level.h"
|
||||
|
||||
class AbstractGame;
|
||||
class CardItem;
|
||||
class GameEventContext;
|
||||
class Player;
|
||||
class PlayerEventHandler;
|
||||
|
||||
class MessageLogWidget : public ChatView
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
enum MessageContext
|
||||
{
|
||||
MessageContext_None,
|
||||
MessageContext_MoveCard,
|
||||
MessageContext_Mulligan
|
||||
};
|
||||
|
||||
MessageContext currentContext;
|
||||
QString messagePrefix, messageSuffix;
|
||||
|
||||
static QPair<QString, QString> getFromStr(CardZoneLogic *zone, QString cardName, int position, bool ownerChange);
|
||||
|
||||
public:
|
||||
void connectToPlayerEventHandler(PlayerEventHandler *player);
|
||||
MessageLogWidget(TabSupervisor *_tabSupervisor, AbstractGame *_game, QWidget *parent = nullptr);
|
||||
|
||||
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 logConcede(int playerId);
|
||||
void logUnconcede(int playerId);
|
||||
void logConnectionStateChanged(Player *player, bool connectionState);
|
||||
void logCreateArrow(Player *player,
|
||||
Player *startPlayer,
|
||||
QString startCard,
|
||||
Player *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 logGameClosed();
|
||||
void logGameStart();
|
||||
void logGameFlooded();
|
||||
void logJoin(Player *player);
|
||||
void logJoinSpectator(QString name);
|
||||
void logKicked();
|
||||
void logLeave(Player *player, QString reason);
|
||||
void logLeaveSpectator(QString name, QString reason);
|
||||
void logNotReadyStart(Player *player);
|
||||
void logMoveCard(Player *player,
|
||||
CardItem *card,
|
||||
CardZoneLogic *startZone,
|
||||
int oldX,
|
||||
CardZoneLogic *targetZone,
|
||||
int newX);
|
||||
void logMulligan(Player *player, int number);
|
||||
void logReplayStarted(int gameId);
|
||||
void logReadyStart(Player *player);
|
||||
void logRevealCards(Player *player,
|
||||
CardZoneLogic *zone,
|
||||
int cardId,
|
||||
QString cardName,
|
||||
Player *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 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 logSpectatorSay(const ServerInfo_User &spectator, QString message);
|
||||
void logUnattachCard(Player *player, QString cardName);
|
||||
void logUndoDraw(Player *player, QString cardName);
|
||||
void setContextJudgeName(QString player);
|
||||
void appendHtmlServerMessage(const QString &html,
|
||||
bool optionalIsBold = false,
|
||||
QString optionalFontColor = QString()) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
#include "user_context_menu.h"
|
||||
|
||||
#include "../../client/tabs/tab_account.h"
|
||||
#include "../../client/tabs/tab_game.h"
|
||||
#include "../../client/tabs/tab_supervisor.h"
|
||||
#include "../../game/game_selector.h"
|
||||
#include "../../tabs/tab_account.h"
|
||||
#include "../../tabs/tab_game.h"
|
||||
#include "../../tabs/tab_supervisor.h"
|
||||
#include "../abstract_client.h"
|
||||
#include "../chat_view/chat_view.h"
|
||||
#include "../game_selector.h"
|
||||
#include "../pending_command.h"
|
||||
#include "pb/command_kick_from_game.pb.h"
|
||||
#include "pb/commands.pb.h"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#include "user_info_box.h"
|
||||
|
||||
#include "../../client/get_text_with_max.h"
|
||||
#include "../../client/ui/pixel_map_generator.h"
|
||||
#include "../../dialogs/dlg_edit_avatar.h"
|
||||
#include "../../dialogs/dlg_edit_password.h"
|
||||
#include "../../dialogs/dlg_edit_user.h"
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "../abstract_client.h"
|
||||
#include "../pending_command.h"
|
||||
#include "passwordhasher.h"
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
#include "user_list_widget.h"
|
||||
|
||||
#include "../../client/tabs/tab_account.h"
|
||||
#include "../../client/tabs/tab_supervisor.h"
|
||||
#include "../../client/ui/pixel_map_generator.h"
|
||||
#include "../../game/game_selector.h"
|
||||
#include "../../server/user/user_list_manager.h"
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "../../tabs/tab_account.h"
|
||||
#include "../../tabs/tab_supervisor.h"
|
||||
#include "../abstract_client.h"
|
||||
#include "../game_selector.h"
|
||||
#include "../pending_command.h"
|
||||
#include "pb/moderator_commands.pb.h"
|
||||
#include "pb/response_get_games_of_user.pb.h"
|
||||
|
|
@ -13,6 +12,7 @@
|
|||
#include "pb/session_commands.pb.h"
|
||||
#include "trice_limits.h"
|
||||
#include "user_context_menu.h"
|
||||
#include "user_list_manager.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue