Cockatrice/cockatrice/src/game/player/player_logic.h
Vasco Guerreiro Vintém Morais 5acce8998e Implement in-game navigation with keyboard
Implements a start to the keyboard navigation with the direction arrows
and the space key for card selection.
Some binds are still needed, but navigating the board is now possible.
The feature includes tests for the implemented feature.

Closes #5043

Co-authored-by: Manuel Ramos Monge <manuel.monge@tecnico.ulisboa.pt>
2026-06-02 17:09:39 +01:00

266 lines
5.9 KiB
C++

/**
* @file player.h
* @ingroup GameLogicPlayers
*/
//! \todo Document this file.
#ifndef PLAYER_H
#define PLAYER_H
#include "../../interface/widgets/menus/tearoff_menu.h"
#include "../board/arrow_data.h"
#include "../interface/deck_loader/loaded_deck.h"
#include "../zones/hand_zone_logic.h"
#include "../zones/pile_zone_logic.h"
#include "../zones/stack_zone_logic.h"
#include "../zones/table_zone_logic.h"
#include "menu/player_menu.h"
#include "player_area.h"
#include "player_event_handler.h"
#include "player_graphics_item.h"
#include "player_info.h"
#include <QInputDialog>
#include <QLoggingCategory>
#include <QMap>
#include <QTimer>
#include <libcockatrice/filters/filter_string.h>
#include <libcockatrice/protocol/pb/card_attributes.pb.h>
#include <libcockatrice/protocol/pb/game_event.pb.h>
#include <libcockatrice/utility/zone_names.h>
inline Q_LOGGING_CATEGORY(PlayerLog, "player");
namespace google
{
namespace protobuf
{
class Message;
}
} // namespace google
class AbstractCardItem;
class AbstractGame;
class ArrowItem;
class ArrowTarget;
class CardDatabase;
class CardZone;
class CommandContainer;
class GameCommand;
class GameEvent;
class PlayerInfo;
class PlayerEventHandler;
class PlayerActions;
class PlayerMenu;
class QAction;
class QMenu;
class ServerInfo_Arrow;
class ServerInfo_Counter;
class ServerInfo_Player;
class ServerInfo_User;
class TabGame;
const int MAX_TOKENS_PER_DIALOG = 99;
class PlayerLogic : public QObject
{
Q_OBJECT
signals:
void openDeckEditor(const LoadedDeck &deck);
void deckChanged();
void newCardAdded(AbstractCardItem *card);
void counterAdded(CounterState *state);
void counterRemoved(int counterId);
void rearrangeCounters();
void activeChanged(bool active);
void zoneIdChanged(int zoneId);
void concededChanged(int playerId, bool conceded);
void clearCustomZonesMenu();
void addViewCustomZoneActionToCustomZoneMenu(QString zoneName);
void resetTopCardMenuActions();
void arrowCreateRequested(ArrowData data);
void arrowDeleteRequested(int arrowId);
void arrowDeleted(int arrowId);
void arrowsCleared(); // fires on clear() and processPlayerInfo
public slots:
void setActive(bool _active);
public:
PlayerLogic(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent);
~PlayerLogic() override;
void initializeZones();
void updateZones();
void clear();
void processPlayerInfo(const ServerInfo_Player &info);
void processCardAttachment(const ServerInfo_Player &info);
void addCard(CardItem *c);
void deleteCard(CardItem *c);
bool clearCardsToDelete();
bool getActive() const
{
return active;
}
AbstractGame *getGame() const
{
return game;
}
GameScene *getGameScene();
[[nodiscard]] PlayerGraphicsItem *getGraphicsItem();
[[nodiscard]] PlayerActions *getPlayerActions() const
{
return playerActions;
}
[[nodiscard]] PlayerEventHandler *getPlayerEventHandler() const
{
return playerEventHandler;
}
[[nodiscard]] PlayerInfo *getPlayerInfo() const
{
return playerInfo;
}
[[nodiscard]] PlayerMenu *getPlayerMenu() const
{
return playerMenu;
}
void setDeck(const DeckList &_deck);
[[nodiscard]] const DeckList &getDeck() const
{
return deck;
}
template <typename T> T *addZone(T *zone)
{
zones.insert(zone->getName(), zone);
return zone;
}
CardZoneLogic *getZone(const QString zoneName)
{
return zones.value(zoneName);
}
const QMap<QString, CardZoneLogic *> &getZones() const
{
return zones;
}
PileZoneLogic *getDeckZone()
{
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::DECK));
}
PileZoneLogic *getGraveZone()
{
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::GRAVE));
}
PileZoneLogic *getRfgZone()
{
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::EXILE));
}
PileZoneLogic *getSideboardZone()
{
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::SIDEBOARD));
}
TableZoneLogic *getTableZone()
{
return qobject_cast<TableZoneLogic *>(zones.value(ZoneNames::TABLE));
}
StackZoneLogic *getStackZone()
{
return qobject_cast<StackZoneLogic *>(zones.value(ZoneNames::STACK));
}
HandZoneLogic *getHandZone()
{
return qobject_cast<HandZoneLogic *>(zones.value(ZoneNames::HAND));
}
CounterState *addCounter(const ServerInfo_Counter &counter);
CounterState *addCounter(int id, const QString &name, const QColor &color, int radius, int value);
void delCounter(int counterId);
void clearCounters();
QMap<int, CounterState *> getCounters() const
{
return counters;
}
/**
* Gets the counter that represents the life total.
*/
CounterState *getLifeCounter() const;
void setConceded(bool _conceded);
bool getConceded() const
{
return conceded;
}
void setGameStarted();
void setDialogSemaphore(const bool _active)
{
dialogSemaphore = _active;
}
int getZoneId() const
{
return zoneId;
}
void setZoneId(int _zoneId);
void hoverFirstCardInHand();
private:
AbstractGame *game;
PlayerInfo *playerInfo;
PlayerEventHandler *playerEventHandler;
PlayerActions *playerActions;
PlayerMenu *playerMenu;
PlayerGraphicsItem *graphicsItem;
bool active;
bool conceded;
DeckList deck;
int zoneId;
QMap<QString, CardZoneLogic *> zones;
QMap<int, CounterState *> counters;
bool dialogSemaphore;
QList<CardItem *> cardsToDelete;
};
class AnnotationDialog : public QInputDialog
{
Q_OBJECT
void keyPressEvent(QKeyEvent *e) override;
public:
explicit AnnotationDialog(QWidget *parent = nullptr) : QInputDialog(parent)
{
}
};
#endif