/* * CGarrisonInt.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 "../gui/CIntObject.h" VCMI_LIB_NAMESPACE_BEGIN class CArmedInstance; class CStackInstance; VCMI_LIB_NAMESPACE_END class CGarrisonInt; class CButton; class CAnimImage; class CLabel; enum class EGarrisonType { UPPER, /// up garrison (Garrisoned) LOWER, /// down garrison (Visiting) }; /// A single garrison slot which holds one creature of a specific amount class CGarrisonSlot : public CIntObject { SlotID ID; //for identification CGarrisonInt *owner; const CStackInstance * myStack; //nullptr if slot is empty const CCreature * creature; EGarrisonType upg; std::shared_ptr creatureImage; std::shared_ptr selectionImage; // image for selection, not always visible std::shared_ptr stackCount; public: bool viewInfo(); bool highlightOrDropArtifact(); bool split(); /// If certain creates cannot be moved, the selection should change /// Force reselection in these cases /// * When attempting to take creatures from ally /// * When attempting to swap creatures with an ally /// * When attempting to take unremovable units /// @return Whether reselection must be done bool mustForceReselection() const; void setHighlight(bool on); std::function getDismiss() const; const CArmedInstance * getObj() const; bool our() const; SlotID getSlot() const { return ID; } EGarrisonType getGarrison() const { return upg; } bool ally() const; // CIntObject overrides void showPopupWindow(const Point & cursorPosition) override; void clickPressed(const Point & cursorPosition) override; void hover (bool on) override; //call-in void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override; void update(); CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, EGarrisonType Upg, const CStackInstance * creature_); void splitIntoParts(EGarrisonType type, int amount); bool handleSplittingShortcuts(); /// Returns true when some shortcut is pressed, false otherwise friend class CGarrisonInt; }; /// Class which manages slots of upper and lower garrison, splitting of units class CGarrisonInt :public CIntObject { /// Chosen slot. Should be changed only via selectSlot. CGarrisonSlot * highlighted; bool inSplittingMode; std::vector> availableSlots; ///< Slots of upper and lower garrison void createSlots(); bool checkSelected(const CGarrisonSlot * selected, TQuantity min = 0) const; std::map armedObjs; public: enum class ESlotsLayout { ONE_ROW, TWO_ROWS, REVERSED_TWO_ROWS }; int interx; ///< Space between slots Point garOffset; ///< Offset between garrisons (not used if only one hero) std::vector> splitButtons; ///< May be empty if no buttons bool smallIcons; ///< true - 32x32 imgs, false - 58x64 bool removableUnits; ///< player Can remove units from up ESlotsLayout layout; void selectSlot(CGarrisonSlot * slot); ///< @param slot null = deselect const CGarrisonSlot * getSelection() const; void setSplittingMode(bool on); bool getSplittingMode(); bool hasEmptySlot(EGarrisonType type) const; SlotID getEmptySlot(EGarrisonType type) const; void setArmy(const CArmedInstance * army, EGarrisonType type); void addSplitBtn(std::shared_ptr button); void recreateSlots(); const CArmedInstance* upperArmy() const; const CArmedInstance* lowerArmy() const; const CArmedInstance* army(EGarrisonType which) const; bool isArmyOwned(EGarrisonType which) const; void splitClick(); ///< handles click on split button void splitStacks(const CGarrisonSlot * from, const CArmedInstance * armyDest, SlotID slotDest, int amount); ///< TODO: comment me void moveStackToAnotherArmy(const CGarrisonSlot * selected); void bulkMoveArmy(const CGarrisonSlot * selected); void bulkMergeStacks(const CGarrisonSlot * selected); // Gather all creatures of selected type to the selected slot from other hero/garrison slots void bulkSplitStack(const CGarrisonSlot * selected); // Used to separate one-creature troops from main stack void bulkSmartSplitStack(const CGarrisonSlot * selected); /// Constructor /// @param position Relative position to parent element /// @param slotInterval Distance between slots; /// @param secondGarrisonOffset /// @param s1, s2 Top and bottom armies /// @param _removableUnits You can take units from top /// @param smallImgs Units images size 64x58 or 32x32 /// @param _layout - when TWO_ROWS - Display slots in 2 rows (1st row = 4 slots, 2nd = 3 slots), REVERSED_TWO_ROWS = 3 slots in 1st row CGarrisonInt(const Point & position, int slotInterval, const Point & secondGarrisonOffset, const CArmedInstance * upperArmy, const CArmedInstance * lowerArmy = nullptr, bool _removableUnits = true, bool smallImgs = false, ESlotsLayout _layout = ESlotsLayout::ONE_ROW); };