/* * GUIClasses.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 "CWindowObject.h" #include "../lib/GameConstants.h" #include "../lib/ResourceSet.h" #include "../lib/CConfigHandler.h" #include "../widgets/CArtifactHolder.h" #include "../widgets/CGarrisonInt.h" #include "../widgets/Images.h" VCMI_LIB_NAMESPACE_BEGIN class CGDwelling; class IMarket; VCMI_LIB_NAMESPACE_END class CreatureCostBox; class CCreaturePic; class MoraleLuckBox; class CHeroArea; class CMinorResDataBar; class CSlider; class CComponentBox; class CTextInput; class CListBox; class CLabelGroup; class CToggleButton; class CToggleGroup; class CVolumeSlider; class CGStatusBar; class CTextBox; class CResDataBar; class CHeroWithMaybePickedArtifact; /// Recruitment window where you can recruit creatures class CRecruitmentWindow : public CStatusbarWindow { class CCreatureCard : public CIntObject, public std::enable_shared_from_this { CRecruitmentWindow * parent; std::shared_ptr animation; bool selected; public: const CCreature * creature; si32 amount; void select(bool on); CCreatureCard(CRecruitmentWindow * window, const CCreature * crea, int totalAmount); void clickLeft(tribool down, bool previousState) override; void clickRight(tribool down, bool previousState) override; void showAll(SDL_Surface * to) override; }; std::function onRecruit; //void (int ID, int amount) <-- call to recruit creatures int level; const CArmedInstance * dst; std::shared_ptr selected; std::vector> cards; std::shared_ptr slider; std::shared_ptr maxButton; std::shared_ptr buyButton; std::shared_ptr cancelButton; std::shared_ptr title; std::shared_ptr availableValue; std::shared_ptr toRecruitValue; std::shared_ptr availableTitle; std::shared_ptr toRecruitTitle; std::shared_ptr costPerTroopValue; std::shared_ptr totalCostValue; void select(std::shared_ptr card); void buy(); void sliderMoved(int to); void showAll(SDL_Surface * to) override; public: const CGDwelling * const dwelling; CRecruitmentWindow(const CGDwelling * Dwelling, int Level, const CArmedInstance * Dst, const std::function & Recruit, int y_offset = 0); void availableCreaturesChanged(); }; /// Split window where creatures can be split up into two single unit stacks class CSplitWindow : public CWindowObject { std::function callback; int leftAmount; int rightAmount; int leftMin; int rightMin; std::shared_ptr title; std::shared_ptr slider; std::shared_ptr animLeft; std::shared_ptr animRight; std::shared_ptr ok; std::shared_ptr cancel; std::shared_ptr leftInput; std::shared_ptr rightInput; void setAmountText(std::string text, bool left); void setAmount(int value, bool left); void sliderMoved(int value); void apply(); public: /** * creature - displayed creature * callback(leftAmount, rightAmount) - function to call on close * leftMin, rightMin - minimal amount of creatures in each stack * leftAmount, rightAmount - amount of creatures in each stack */ CSplitWindow(const CCreature * creature, std::function callback, int leftMin, int rightMin, int leftAmount, int rightAmount); }; /// Raised up level window where you can select one out of two skills class CLevelWindow : public CWindowObject { std::shared_ptr portrait; std::shared_ptr ok; std::shared_ptr mainTitle; std::shared_ptr levelTitle; std::shared_ptr skillIcon; std::shared_ptr skillValue; std::shared_ptr box; //skills to select std::function cb; void selectionChanged(unsigned to); public: CLevelWindow(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector &skills, std::function callback); ~CLevelWindow(); }; /// Town portal, castle gate window class CObjectListWindow : public CWindowObject { class CItem : public CIntObject { CObjectListWindow * parent; std::shared_ptr text; std::shared_ptr border; public: const size_t index; CItem(CObjectListWindow * parent, size_t id, std::string text); void select(bool on); void clickLeft(tribool down, bool previousState) override; }; std::function onSelect;//called when OK button is pressed, returns id of selected item. std::shared_ptr titleWidget; std::shared_ptr title; std::shared_ptr descr; std::shared_ptr list; std::shared_ptr ok; std::shared_ptr exit; std::vector< std::pair > items;//all items present in list void init(std::shared_ptr titleWidget_, std::string _title, std::string _descr); void exitPressed(); public: size_t selected;//index of currently selected item std::function onExit;//optional exit callback /// Callback will be called when OK button is pressed, returns id of selected item. initState = initially selected item /// Image can be nullptr ///item names will be taken from map objects CObjectListWindow(const std::vector &_items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection = 0); CObjectListWindow(const std::vector &_items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection = 0); std::shared_ptr genItem(size_t index); void elementSelected();//call callback and close this window void changeSelection(size_t which); void keyPressed (const SDL_KeyboardEvent & key) override; }; class CSystemOptionsWindow : public CWindowObject { private: std::shared_ptr title; std::shared_ptr leftGroup; std::shared_ptr rightGroup; std::shared_ptr load; std::shared_ptr save; std::shared_ptr restart; std::shared_ptr mainMenu; std::shared_ptr quitGame; std::shared_ptr backToMap; //load and restart are not used yet std::shared_ptr heroMoveSpeed; std::shared_ptr enemyMoveSpeed; std::shared_ptr mapScrollSpeed; std::shared_ptr musicVolume; std::shared_ptr effectsVolume; std::shared_ptr showReminder; std::shared_ptr quickCombat; std::shared_ptr spellbookAnim; std::shared_ptr fullscreen; std::shared_ptr gameResButton; std::shared_ptr gameResLabel; SettingsListener onFullscreenChanged; //functions bound to buttons void bloadf(); //load game void bsavef(); //save game void bquitf(); //quit game void breturnf(); //return to game void brestartf(); //restart game void bmainmenuf(); //return to main menu void selectGameRes(); void setGameRes(int index); void closeAndPushEvent(int eventType, int code = 0); public: CSystemOptionsWindow(); }; class CTavernWindow : public CStatusbarWindow { public: class HeroPortrait : public CIntObject { public: std::string hoverName; std::string description; // "XXX is a level Y ZZZ with N artifacts" const CGHeroInstance * h; void clickLeft(tribool down, bool previousState) override; void clickRight(tribool down, bool previousState) override; void hover (bool on) override; HeroPortrait(int & sel, int id, int x, int y, const CGHeroInstance * H); private: int *_sel; const int _id; std::shared_ptr portrait; }; //recruitable heroes std::shared_ptr h1; std::shared_ptr h2; //recruitable heroes int selected;//0 (left) or 1 (right) int oldSelected;//0 (left) or 1 (right) std::shared_ptr thiefGuild; std::shared_ptr cancel; std::shared_ptr recruit; const CGObjectInstance * tavernObj; std::shared_ptr title; std::shared_ptr cost; std::shared_ptr rumor; CTavernWindow(const CGObjectInstance * TavernObj); ~CTavernWindow(); void recruitb(); void thievesguildb(); void show(SDL_Surface * to) override; }; class CCallback; class CExchangeWindow; struct HeroArtifact { const CGHeroInstance * hero; const CArtifactInstance * artifact; ArtifactPosition artPosition; HeroArtifact(const CGHeroInstance * hero, const CArtifactInstance * artifact, ArtifactPosition artPosition) :hero(hero), artifact(artifact), artPosition(artPosition) { } }; class CExchangeController { private: const CGHeroInstance * left; const CGHeroInstance * right; std::shared_ptr cb; CExchangeWindow * view; public: CExchangeController(CExchangeWindow * view, ObjectInstanceID hero1, ObjectInstanceID hero2); std::function onMoveArmyToRight(); std::function onSwapArmy(); std::function onMoveArmyToLeft(); std::function onSwapArtifacts(); std::function onMoveArtifactsToLeft(); std::function onMoveArtifactsToRight(); std::function onMoveStackToLeft(SlotID slotID); std::function onMoveStackToRight(SlotID slotID); private: void moveArmy(bool leftToRight); void moveArtifacts(bool leftToRight); void moveArtifact(const CGHeroInstance * source, const CGHeroInstance * target, ArtifactPosition srcPosition); void moveStack(const CGHeroInstance * source, const CGHeroInstance * target, SlotID sourceSlot); }; class CExchangeWindow : public CStatusbarWindow, public CGarrisonHolder, public CWindowWithArtifacts { std::array, 2> herosWArt; std::array, 2> titles; std::vector> primSkillImages;//shared for both heroes std::array>, 2> primSkillValues; std::array>, 2> secSkillIcons; std::array, 2> specImages; std::array, 2> expImages; std::array, 2> expValues; std::array, 2> manaImages; std::array, 2> manaValues; std::array, 2> portraits; std::vector> primSkillAreas; std::array>, 2> secSkillAreas; std::array, 2> heroAreas; std::array, 2> specialtyAreas; std::array, 2> experienceAreas; std::array, 2> spellPointsAreas; std::array, 2> morale; std::array, 2> luck; std::shared_ptr quit; std::array, 2> questlogButton; std::shared_ptr garr; std::shared_ptr moveAllGarrButtonLeft; std::shared_ptr echangeGarrButton; std::shared_ptr moveAllGarrButtonRight; std::shared_ptr moveArtifactsButtonLeft; std::shared_ptr echangeArtifactsButton; std::shared_ptr moveArtifactsButtonRight; std::vector> moveStackLeftButtons; std::vector> moveStackRightButtons; CExchangeController controller; public: std::array heroInst; std::array, 2> artifs; void updateGarrisons() override; void questlog(int whichHero); //questlog button callback; whichHero: 0 - left, 1 - right void updateWidgets(); const CGarrisonSlot * getSelectedSlotID() const; CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID); ~CExchangeWindow(); }; /// Here you can buy ships class CShipyardWindow : public CStatusbarWindow { std::shared_ptr bgWater; std::shared_ptr bgShip; std::shared_ptr title; std::shared_ptr costLabel; std::shared_ptr woodPic; std::shared_ptr goldPic; std::shared_ptr woodCost; std::shared_ptr goldCost; std::shared_ptr build; std::shared_ptr quit; public: CShipyardWindow(const std::vector & cost, int state, int boatType, const std::function & onBuy); }; /// Puzzle screen which gets uncovered when you visit obilisks class CPuzzleWindow : public CWindowObject { private: int3 grailPos; std::shared_ptr logo; std::shared_ptr title; std::shared_ptr quitb; std::shared_ptr resDataBar; std::vector> piecesToRemove; std::vector> visiblePieces; ui8 currentAlpha; public: void showAll(SDL_Surface * to) override; void show(SDL_Surface * to) override; CPuzzleWindow(const int3 & grailPos, double discoveredRatio); }; /// Creature transformer window class CTransformerWindow : public CStatusbarWindow, public CGarrisonHolder { class CItem : public CIntObject { public: int id;//position of creature in hero army bool left;//position of the item int size; //size of creature stack CTransformerWindow * parent; std::shared_ptr icon; std::shared_ptr count; void move(); void clickLeft(tribool down, bool previousState) override; void update(); CItem(CTransformerWindow * parent, int size, int id); }; const CArmedInstance * army;//object with army for transforming (hero or town) const CGHeroInstance * hero;//only if we have hero in town const CGTownInstance * town;//market, town garrison is used if hero == nullptr std::shared_ptr titleLeft; std::shared_ptr titleRight; std::shared_ptr helpLeft; std::shared_ptr helpRight; std::vector> items; std::shared_ptr all; std::shared_ptr convert; std::shared_ptr cancel; public: void makeDeal(); void addAll(); void updateGarrisons() override; CTransformerWindow(const CGHeroInstance * _hero, const CGTownInstance * _town); }; class CUniversityWindow : public CStatusbarWindow { class CItem : public CIntObject { std::shared_ptr icon; std::shared_ptr topBar; std::shared_ptr bottomBar; std::shared_ptr name; std::shared_ptr level; public: int ID;//id of selected skill CUniversityWindow * parent; void showAll(SDL_Surface * to) override; void clickLeft(tribool down, bool previousState) override; void clickRight(tribool down, bool previousState) override; void hover(bool on) override; int state();//0=can't learn, 1=learned, 2=can learn CItem(CUniversityWindow * _parent, int _ID, int X, int Y); }; const CGHeroInstance * hero; const IMarket * market; std::shared_ptr bars; std::vector> items; std::shared_ptr cancel; std::shared_ptr titlePic; std::shared_ptr title; std::shared_ptr clerkSpeech; public: CUniversityWindow(const CGHeroInstance * _hero, const IMarket * _market); void makeDeal(int skill); }; /// Confirmation window for University class CUnivConfirmWindow : public CStatusbarWindow { std::shared_ptr clerkSpeech; std::shared_ptr name; std::shared_ptr level; std::shared_ptr icon; CUniversityWindow * owner; std::shared_ptr confirm; std::shared_ptr cancel; std::shared_ptr costIcon; std::shared_ptr cost; void makeDeal(int skill); public: CUnivConfirmWindow(CUniversityWindow * PARENT, int SKILL, bool available); }; /// Garrison window where you can take creatures out of the hero to place it on the garrison class CGarrisonWindow : public CWindowObject, public CGarrisonHolder { std::shared_ptr title; std::shared_ptr banner; std::shared_ptr portrait; std::shared_ptr garr; public: std::shared_ptr quit; CGarrisonWindow(const CArmedInstance * up, const CGHeroInstance * down, bool removableUnits); void updateGarrisons() override; }; /// Hill fort is the building where you can upgrade units class CHillFortWindow : public CStatusbarWindow, public CGarrisonHolder { private: static const int slotsCount = 7; //todo: mithril support static const int resCount = 7; const CGObjectInstance * fort; const CGHeroInstance * hero; std::shared_ptr title; std::shared_ptr heroPic; std::array, resCount> totalIcons; std::array, resCount> totalLabels; std::array, slotsCount> upgrade;//upgrade single creature std::array currState;//current state of slot - to avoid calls to getState or updating buttons //there is a place for only 2 resources per slot std::array< std::array, 2>, slotsCount> slotIcons; std::array< std::array, 2>, slotsCount> slotLabels; std::shared_ptr upgradeAll; std::shared_ptr quit; std::shared_ptr garr; std::string getDefForSlot(SlotID slot); std::string getTextForSlot(SlotID slot); void makeDeal(SlotID slot);//-1 for upgrading all creatures int getState(SlotID slot); //-1 = no creature 0=can't upgrade, 1=upgraded, 2=can upgrade public: CHillFortWindow(const CGHeroInstance * visitor, const CGObjectInstance * object); void updateGarrisons() override;//update buttons after garrison changes }; class CThievesGuildWindow : public CStatusbarWindow { const CGObjectInstance * owner; std::shared_ptr exitb; std::shared_ptr resdatabar; std::vector> rowHeaders; std::vector> columnBackgrounds; std::vector> columnHeaders; std::vector> cells; std::vector> banners; std::vector> bestHeroes; std::vector> primSkillHeaders; std::vector> primSkillValues; std::vector> bestCreatures; std::vector> personalities; public: CThievesGuildWindow(const CGObjectInstance * _owner); };