1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-26 08:41:13 +02:00
vcmi/client/CPreGame.h

651 lines
18 KiB
C++

/*
* CPreGame.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "../lib/StartInfo.h"
#include "../lib/FunctionList.h"
#include "../lib/mapping/CMapInfo.h"
#include "../lib/rmg/CMapGenerator.h"
#include "windows/CWindowObject.h"
class CMapInfo;
class CMusicHandler;
class CMapHeader;
class CCampaignHeader;
class CTextInput;
class CCampaign;
class CGStatusBar;
class CTextBox;
class CCampaignState;
class CConnection;
class JsonNode;
class CMapGenOptions;
class CRandomMapTab;
struct CPackForSelectionScreen;
struct PlayerInfo;
class CMultiLineLabel;
class CToggleButton;
class CToggleGroup;
class CTabbedInt;
class IImage;
class CAnimation;
class CAnimImage;
class CButton;
class CLabel;
class CSlider;
namespace boost{ class thread; class recursive_mutex;}
enum ESortBy{_playerAm, _size, _format, _name, _viccon, _loscon, _numOfMaps, _fileName}; //_numOfMaps is for campaigns
/// Class which handles map sorting by different criteria
class mapSorter
{
public:
ESortBy sortBy;
bool operator()(const CMapInfo *aaa, const CMapInfo *bbb);
mapSorter(ESortBy es):sortBy(es){};
};
/// The main menu screens listed in the EState enum
class CMenuScreen : public CIntObject
{
const JsonNode& config;
CTabbedInt *tabs;
CPicture * background;
std::vector<CPicture*> images;
CIntObject *createTab(size_t index);
public:
std::vector<std::string> menuNameToEntry;
enum EState { //where are we?
mainMenu, newGame, loadGame, campaignMain, saveGame, scenarioInfo, campaignList
};
enum EGameMode {
SINGLE_PLAYER = 0, MULTI_HOT_SEAT, MULTI_NETWORK_HOST, MULTI_NETWORK_GUEST, SINGLE_CAMPAIGN
};
CMenuScreen(const JsonNode& configNode);
void showAll(SDL_Surface * to) override;
void show(SDL_Surface * to) override;
void activate() override;
void deactivate() override;
void switchToTab(size_t index);
};
class CMenuEntry : public CIntObject
{
std::vector<CPicture*> images;
std::vector<CButton*> buttons;
CButton* createButton(CMenuScreen* parent, const JsonNode& button);
public:
CMenuEntry(CMenuScreen* parent, const JsonNode &config);
};
class CreditsScreen : public CIntObject
{
int positionCounter;
CMultiLineLabel* credits;
public:
CreditsScreen();
void show(SDL_Surface * to) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
};
/// Implementation of the chat box
class CChatBox : public CIntObject
{
public:
CTextBox *chatHistory;
CTextInput *inputBox;
CChatBox(const Rect &rect);
void keyPressed(const SDL_KeyboardEvent & key) override;
void addNewMessage(const std::string &text);
};
class InfoCard : public CIntObject
{
CAnimImage * victory, * loss, *sizes;
std::shared_ptr<CAnimation> sFlags;
public:
CPicture *bg;
bool network;
bool chatOn; //if chat is shown, then description is hidden
CTextBox *mapDescription;
CChatBox *chat;
CPicture *playerListBg;
CToggleGroup *difficulty;
void changeSelection(const CMapInfo *to);
void showAll(SDL_Surface * to) override;
void clickRight(tribool down, bool previousState) override;
void showTeamsPopup();
void toggleChat();
void setChat(bool activateChat);
InfoCard(bool Network = false);
~InfoCard();
};
/// The selection tab which is shown at the map selection screen
class SelectionTab : public CIntObject
{
private:
std::shared_ptr<CAnimation> formatIcons;
void parseMaps(const std::unordered_set<ResourceID> &files);
void parseGames(const std::unordered_set<ResourceID> &files, CMenuScreen::EGameMode gameMode);
std::unordered_set<ResourceID> getFiles(std::string dirURI, int resType);
void parseCampaigns(const std::unordered_set<ResourceID> & files );
CMenuScreen::EState tabType;
public:
int positions; //how many entries (games/maps) can be shown
CPicture *bg; //general bg image
CSlider *slider;
std::vector<CMapInfo> allItems;
std::vector<CMapInfo*> curItems;
size_t selectionPos;
std::function<void(CMapInfo *)> onSelect;
ESortBy sortingBy;
ESortBy generalSortingBy;
bool ascending;
CTextInput *txt;
void filter(int size, bool selectFirst = false); //0 - all
void select(int position); //position: <0 - positions> position on the screen
void selectAbs(int position); //position: absolute position in curItems vector
int getPosition(int x, int y); //convert mouse coords to entry position; -1 means none
void sliderMove(int slidPos);
void sortBy(int criteria);
void sort();
void printMaps(SDL_Surface *to);
int getLine();
void selectFName(std::string fname);
const CMapInfo * getSelectedMapInfo() const;
void showAll(SDL_Surface * to) override;
void clickLeft(tribool down, bool previousState) override;
void keyPressed(const SDL_KeyboardEvent & key) override;
void onDoubleClick() override;
SelectionTab(CMenuScreen::EState Type, const std::function<void(CMapInfo *)> &OnSelect, CMenuScreen::EGameMode GameMode = CMenuScreen::SINGLE_PLAYER);
~SelectionTab();
};
/// The options tab which is shown at the map selection phase.
class OptionsTab : public CIntObject
{
CPicture *bg;
public:
enum SelType {TOWN, HERO, BONUS};
struct CPlayerSettingsHelper
{
const PlayerSettings & settings;
const SelType type;
CPlayerSettingsHelper(const PlayerSettings & settings, SelType type):
settings(settings),
type(type)
{}
/// visible image settings
size_t getImageIndex();
std::string getImageName();
std::string getName(); /// name visible in options dialog
std::string getTitle(); /// title in popup box
std::string getSubtitle(); /// popup box subtitle
std::string getDescription();/// popup box description, not always present
};
class CPregameTooltipBox : public CWindowObject, public CPlayerSettingsHelper
{
void genHeader();
void genTownWindow();
void genHeroWindow();
void genBonusWindow();
public:
CPregameTooltipBox(CPlayerSettingsHelper & helper);
};
struct SelectedBox : public CIntObject, public CPlayerSettingsHelper //img with current town/hero/bonus
{
CAnimImage * image;
CLabel *subtitle;
SelectedBox(Point position, PlayerSettings & settings, SelType type);
void clickRight(tribool down, bool previousState) override;
void update();
};
struct PlayerOptionsEntry : public CIntObject
{
PlayerInfo &pi;
PlayerSettings &s;
CPicture *bg;
CButton *btns[6]; //left and right for town, hero, bonus
CButton *flag;
SelectedBox *town;
SelectedBox *hero;
SelectedBox *bonus;
enum {HUMAN_OR_CPU, HUMAN, CPU} whoCanPlay;
PlayerOptionsEntry(OptionsTab *owner, PlayerSettings &S);
void selectButtons(); //hides unavailable buttons
void showAll(SDL_Surface * to) override;
void update();
};
CSlider *turnDuration;
std::set<int> usedHeroes;
struct PlayerToRestore
{
PlayerColor color;
int id;
void reset() { id = -1; color = PlayerColor::CANNOT_DETERMINE; }
PlayerToRestore(){ reset(); }
} playerToRestore;
std::map<PlayerColor, PlayerOptionsEntry *> entries; //indexed by color
void nextCastle(PlayerColor player, int dir); //dir == -1 or +1
void nextHero(PlayerColor player, int dir); //dir == -1 or +1
void nextBonus(PlayerColor player, int dir); //dir == -1 or +1
void setTurnLength(int npos);
void flagPressed(PlayerColor player);
void recreate();
OptionsTab();
~OptionsTab();
void showAll(SDL_Surface * to) override;
int nextAllowedHero(PlayerColor player, int min, int max, int incl, int dir );
bool canUseThisHero(PlayerColor player, int ID );
};
/// The random map tab shows options for generating a random map.
class CRandomMapTab : public CIntObject
{
public:
CRandomMapTab();
void showAll(SDL_Surface * to) override;
void updateMapInfo();
CFunctionList<void (const CMapInfo *)> & getMapInfoChanged();
const CMapInfo * getMapInfo() const;
const CMapGenOptions & getMapGenOptions() const;
void setMapGenOptions(std::shared_ptr<CMapGenOptions> opts);
private:
void addButtonsToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex) const;
void addButtonsWithRandToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex, int helpRandIndex) const;
void deactivateButtonsFrom(CToggleGroup * group, int startId);
void validatePlayersCnt(int playersCnt);
void validateCompOnlyPlayersCnt(int compOnlyPlayersCnt);
std::vector<int> getPossibleMapSizes();
CPicture * bg;
CToggleButton * twoLevelsBtn;
CToggleGroup * mapSizeBtnGroup, * playersCntGroup, * teamsCntGroup, * compOnlyPlayersCntGroup,
* compOnlyTeamsCntGroup, * waterContentGroup, * monsterStrengthGroup;
CButton * showRandMaps;
CMapGenOptions mapGenOptions;
std::unique_ptr<CMapInfo> mapInfo;
CFunctionList<void(const CMapInfo *)> mapInfoChanged;
};
/// Interface for selecting a map.
class ISelectionScreenInfo
{
public:
CMenuScreen::EGameMode gameMode;
CMenuScreen::EState screenType; //new/save/load#Game
const CMapInfo *current;
StartInfo sInfo;
std::map<ui8, std::string> playerNames; // id of player <-> player name; 0 is reserved as ID of AI "players"
ISelectionScreenInfo(const std::map<ui8, std::string> *Names = nullptr);
virtual ~ISelectionScreenInfo();
virtual void update(){};
virtual void propagateOptions() {};
virtual void postRequest(ui8 what, ui8 dir) {};
virtual void postChatMessage(const std::string &txt){};
void setPlayer(PlayerSettings &pset, ui8 player);
void updateStartInfo(std::string filename, StartInfo & sInfo, const std::unique_ptr<CMapHeader> & mapHeader);
ui8 getIdOfFirstUnallocatedPlayer(); //returns 0 if none
bool isGuest() const;
bool isHost() const;
};
/// The actual map selection screen which consists of the options and selection tab
class CSelectionScreen : public CIntObject, public ISelectionScreenInfo
{
bool bordered;
public:
CPicture *bg; //general bg image
InfoCard *card;
OptionsTab *opt;
CRandomMapTab * randMapTab;
CButton *start, *back;
SelectionTab *sel;
CIntObject *curTab;
boost::thread *serverHandlingThread;
boost::recursive_mutex *mx;
std::list<CPackForSelectionScreen *> upcomingPacks; //protected by mx
CConnection *serv; //connection to server, used in MP mode
bool ongoingClosing;
ui8 myNameID; //used when networking - otherwise all player are "mine"
CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EGameMode GameMode = CMenuScreen::SINGLE_PLAYER, const std::map<ui8, std::string> * Names = nullptr, const std::string & Address = "", const ui16 Port = 0);
~CSelectionScreen();
void toggleTab(CIntObject *tab);
void changeSelection(const CMapInfo *to);
void startCampaign();
void startScenario();
void difficultyChange(int to);
void handleConnection();
void processPacks();
void setSInfo(const StartInfo &si);
void update() override;
void propagateOptions() override;
void postRequest(ui8 what, ui8 dir) override;
void postChatMessage(const std::string &txt) override;
void propagateNames();
void showAll(SDL_Surface *to) override;
};
/// Save game screen
class CSavingScreen : public CSelectionScreen
{
public:
const CMapInfo *ourGame;
CSavingScreen(bool hotseat = false);
~CSavingScreen();
};
/// Scenario information screen shown during the game (thus not really a "pre-game" but fits here anyway)
class CScenarioInfo : public CIntObject, public ISelectionScreenInfo
{
public:
CButton *back;
InfoCard *card;
OptionsTab *opt;
CScenarioInfo(const CMapHeader *mapHeader, const StartInfo *startInfo);
~CScenarioInfo();
};
/// Multiplayer mode
class CMultiMode : public CIntObject
{
public:
CPicture *bg;
CTextInput *txt;
CButton *btns[7]; //0 - hotseat, 6 - cancel
CGStatusBar *bar;
CMultiMode();
void openHotseat();
void hostTCP();
void joinTCP();
};
/// Hot seat player window
class CHotSeatPlayers : public CIntObject
{
CPicture *bg;
CTextBox *title;
CTextInput* txt[8];
CButton *ok, *cancel;
CGStatusBar *bar;
void onChange(std::string newText);
void enterSelectionScreen();
public:
CHotSeatPlayers(const std::string &firstPlayer);
};
class CPrologEpilogVideo : public CWindowObject
{
CCampaignScenario::SScenarioPrologEpilog spe;
int positionCounter;
int voiceSoundHandle;
std::function<void()> exitCb;
CMultiLineLabel * text;
public:
CPrologEpilogVideo(CCampaignScenario::SScenarioPrologEpilog _spe, std::function<void()> callback);
void clickLeft(tribool down, bool previousState) override;
void show(SDL_Surface * to) override;
};
/// Campaign screen where you can choose one out of three starting bonuses
class CBonusSelection : public CIntObject
{
public:
CBonusSelection(const std::string & campaignFName);
CBonusSelection(std::shared_ptr<CCampaignState> _ourCampaign);
~CBonusSelection();
void showAll(SDL_Surface * to) override;
void show(SDL_Surface * to) override;
private:
struct SCampPositions
{
std::string campPrefix;
int colorSuffixLength;
struct SRegionDesc
{
std::string infix;
int xpos, ypos;
};
std::vector<SRegionDesc> regions;
};
class CRegion : public CIntObject
{
CBonusSelection * owner;
SDL_Surface* graphics[3]; //[0] - not selected, [1] - selected, [2] - striped
bool accessible; //false if region should be striped
bool selectable; //true if region should be selectable
int myNumber; //number of region
public:
std::string rclickText;
CRegion(CBonusSelection * _owner, bool _accessible, bool _selectable, int _myNumber);
~CRegion();
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void show(SDL_Surface * to) override;
};
void init();
void loadPositionsOfGraphics();
void updateStartButtonState(int selected = -1); //-1 -- no bonus is selected
void updateBonusSelection();
void updateCampaignState();
// Event handlers
void goBack();
void startMap();
void restartMap();
void selectMap(int mapNr, bool initialSelect);
void selectBonus(int id);
void increaseDifficulty();
void decreaseDifficulty();
// GUI components
SDL_Surface * background;
CButton * startB, * restartB, * backB;
CTextBox * campaignDescription, * mapDescription;
std::vector<SCampPositions> campDescriptions;
std::vector<CRegion *> regions;
CRegion * highlightedRegion;
CToggleGroup * bonuses;
std::array<CAnimImage *, 5> diffPics; //pictures of difficulties, user-selectable (or not if campaign locks this)
CButton * diffLb, * diffRb; //buttons for changing difficulty
CAnimImage * sizes;//icons of map sizes
std::shared_ptr<CAnimation> sFlags;
// Data
std::shared_ptr<CCampaignState> ourCampaign;
int selectedMap;
boost::optional<int> selectedBonus;
StartInfo startInfo;
std::unique_ptr<CMapHeader> ourHeader;
};
/// Campaign selection screen
class CCampaignScreen : public CIntObject
{
public:
enum CampaignStatus {DEFAULT = 0, ENABLED, DISABLED, COMPLETED}; // the status of the campaign
private:
/// A button which plays a video when you move the mouse cursor over it
class CCampaignButton : public CIntObject
{
private:
CLabel *hoverLabel;
CampaignStatus status;
std::string campFile; // the filename/resourcename of the campaign
std::string video; // the resource name of the video
std::string hoverText;
void clickLeft(tribool down, bool previousState) override;
void hover(bool on) override;
public:
CCampaignButton(const JsonNode &config );
void show(SDL_Surface * to) override;
};
std::vector<CCampaignButton*> campButtons;
std::vector<CPicture*> images;
CButton* createExitButton(const JsonNode& button);
public:
enum CampaignSet {ROE, AB, SOD, WOG};
CCampaignScreen(const JsonNode &config);
void showAll(SDL_Surface *to) override;
};
/// Manages the configuration of pregame GUI elements like campaign screen, main menu, loading screen,...
class CGPreGameConfig
{
public:
static CGPreGameConfig & get();
const JsonNode & getConfig() const;
const JsonNode & getCampaigns() const;
private:
CGPreGameConfig();
const JsonNode campaignSets;
const JsonNode config;
};
/// Handles background screen, loads graphics for victory/loss condition and random town or hero selection
class CGPreGame : public CIntObject, public IUpdateable
{
void loadGraphics();
void disposeGraphics();
CGPreGame(); //Use createIfNotPresent
public:
CMenuScreen * menu;
std::shared_ptr<CAnimation> victoryIcons, lossIcons;
~CGPreGame();
void update() override;
void openSel(CMenuScreen::EState type, CMenuScreen::EGameMode gameMode = CMenuScreen::SINGLE_PLAYER);
void openCampaignScreen(std::string name);
static CGPreGame * create();
void removeFromGui();
static void showLoadingScreen(std::function<void()> loader);
};
class CLoadingScreen : public CWindowObject
{
boost::thread loadingThread;
std::string getBackground();
public:
CLoadingScreen(std::function<void()> loader);
~CLoadingScreen();
void showAll(SDL_Surface *to) override;
};
/// Simple window to enter the server's address.
class CSimpleJoinScreen : public CIntObject
{
CPicture * bg;
CTextBox * title;
CButton * ok, * cancel;
CGStatusBar * bar;
CTextInput * address;
CTextInput * port;
void enterSelectionScreen(CMenuScreen::EGameMode mode);
void onChange(const std::string & newText);
public:
CSimpleJoinScreen(CMenuScreen::EGameMode mode);
};
extern ISelectionScreenInfo *SEL;
extern CGPreGame *CGP;