2023-10-19 16:19:09 +02:00
/*
* CCreatureSet . 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
2025-07-07 19:12:31 +03:00
# include "CSimpleArmy.h"
2023-10-19 16:19:09 +02:00
2025-07-07 19:12:31 +03:00
# include "serializer/Serializeable.h"
2023-10-19 16:19:09 +02:00
VCMI_LIB_NAMESPACE_BEGIN
2025-07-07 19:12:31 +03:00
class CStackInstance ;
2023-10-19 16:19:09 +02:00
class CArmedInstance ;
2025-07-07 19:12:31 +03:00
class CStackBasicDescriptor ;
2023-10-19 16:19:09 +02:00
class JsonSerializeFormat ;
2025-03-17 21:11:06 +00:00
using TSlots = std : : map < SlotID , std : : unique_ptr < CStackInstance > > ;
2023-10-19 16:19:09 +02:00
using TPairCreatureSlot = std : : pair < const CCreature * , SlotID > ;
using TMapCreatureSlot = std : : map < const CCreature * , SlotID > ;
struct DLL_LINKAGE CreatureSlotComparer
{
bool operator ( ) ( const TPairCreatureSlot & lhs , const TPairCreatureSlot & rhs ) ;
} ;
using TCreatureQueue = std : : priority_queue < TPairCreatureSlot , std : : vector < TPairCreatureSlot > , CreatureSlotComparer > ;
namespace NArmyFormation
{
static const std : : vector < std : : string > names { " wide " , " tight " } ;
}
2024-05-07 19:17:05 +00:00
class DLL_LINKAGE CCreatureSet : public IArmyDescriptor , public virtual Serializeable //seven combined creatures
2023-10-19 16:19:09 +02:00
{
CCreatureSet ( const CCreatureSet & ) = delete ;
CCreatureSet & operator = ( const CCreatureSet & ) ;
2025-03-18 23:30:06 +00:00
public :
2023-10-19 16:19:09 +02:00
TSlots stacks ; //slots[slot_id]->> pair(creature_id,creature_quantity)
EArmyFormation formation = EArmyFormation : : LOOSE ; //0 - wide, 1 - tight
CCreatureSet ( ) = default ; //Should be here to avoid compile errors
virtual ~ CCreatureSet ( ) ;
virtual void armyChanged ( ) ;
const CStackInstance & operator [ ] ( const SlotID & slot ) const ;
const TSlots & Slots ( ) const { return stacks ; }
void addToSlot ( const SlotID & slot , const CreatureID & cre , TQuantity count , bool allowMerging = true ) ; //Adds stack to slot. Slot must be empty or with same type creature
2025-03-17 21:11:06 +00:00
void addToSlot ( const SlotID & slot , std : : unique_ptr < CStackInstance > stack , bool allowMerging = true ) ; //Adds stack to slot. Slot must be empty or with same type creature
2023-10-19 16:19:09 +02:00
void clearSlots ( ) override ;
2023-11-06 18:27:16 +02:00
void setFormation ( EArmyFormation tight ) ;
2025-03-18 23:30:06 +00:00
virtual CArmedInstance * getArmy ( ) { return nullptr ; }
virtual const CArmedInstance * getArmy ( ) const { return nullptr ; }
2023-10-19 16:19:09 +02:00
//basic operations
2025-03-17 21:11:06 +00:00
void putStack ( const SlotID & slot , std : : unique_ptr < CStackInstance > stack ) ; //adds new stack to the army, slot must be empty
2023-10-19 16:19:09 +02:00
void setStackCount ( const SlotID & slot , TQuantity count ) ; //stack must exist!
2025-03-17 21:11:06 +00:00
std : : unique_ptr < CStackInstance > detachStack ( const SlotID & slot ) ; //removes stack from army but doesn't destroy it (so it can be moved somewhere else or safely deleted)
2023-10-19 16:19:09 +02:00
void setStackType ( const SlotID & slot , const CreatureID & type ) ;
2025-05-01 13:41:48 +03:00
/// Give specified amount of experience to all units in army
/// Amount of granted experience is scaled by unit stack size
void giveAverageStackExperience ( TExpType exp ) ;
/// Give specified amount of experience to unit in specified slot
/// Amount of granted experience is not scaled by unit stack size
void giveTotalStackExperience ( const SlotID & slot , TExpType exp ) ;
/// Erased stack from specified slot. Slot must be non-empty
void eraseStack ( const SlotID & slot ) ;
/// Joins stack into stack that occupies targeted slot.
/// Slot must be non-empty and contain same creature type
2025-03-17 21:11:06 +00:00
void joinStack ( const SlotID & slot , std : : unique_ptr < CStackInstance > stack ) ; //adds new stack to the existing stack of the same type
2025-05-01 13:41:48 +03:00
/// Splits off some units of specified stack and returns newly created stack
/// Slot must be non-empty and contain more units that split quantity
std : : unique_ptr < CStackInstance > splitStack ( const SlotID & slot , TQuantity toSplit ) ;
2023-10-19 16:19:09 +02:00
void changeStackCount ( const SlotID & slot , TQuantity toAdd ) ; //stack must exist!
bool setCreature ( SlotID slot , CreatureID type , TQuantity quantity ) override ; //replaces creature in stack; slots 0 to 6, if quantity=0 erases stack
void setToArmy ( CSimpleArmy & src ) ; //erases all our army and moves stacks from src to us; src MUST NOT be an armed object! WARNING: use it wisely. Or better do not use at all.
const CStackInstance & getStack ( const SlotID & slot ) const ; //stack must exist
2023-10-23 19:37:18 +03:00
CStackInstance * getStackPtr ( const SlotID & slot ) const ; //if stack doesn't exist, returns nullptr
2023-10-19 16:19:09 +02:00
const CCreature * getCreature ( const SlotID & slot ) const ; //workaround of map issue;
int getStackCount ( const SlotID & slot ) const ;
2025-05-01 13:41:48 +03:00
TExpType getStackTotalExperience ( const SlotID & slot ) const ;
TExpType getStackAverageExperience ( const SlotID & slot ) const ;
2023-10-19 16:19:09 +02:00
SlotID findStack ( const CStackInstance * stack ) const ; //-1 if none
SlotID getSlotFor ( const CreatureID & creature , ui32 slotsAmount = GameConstants : : ARMY_SIZE ) const ; //returns -1 if no slot available
SlotID getSlotFor ( const CCreature * c , ui32 slotsAmount = GameConstants : : ARMY_SIZE ) const ; //returns -1 if no slot available
bool hasCreatureSlots ( const CCreature * c , const SlotID & exclude ) const ;
std : : vector < SlotID > getCreatureSlots ( const CCreature * c , const SlotID & exclude , TQuantity ignoreAmount = - 1 ) const ;
bool isCreatureBalanced ( const CCreature * c , TQuantity ignoreAmount = 1 ) const ; // Check if the creature is evenly distributed across slots
SlotID getFreeSlot ( ui32 slotsAmount = GameConstants : : ARMY_SIZE ) const ; //returns first free slot
std : : vector < SlotID > getFreeSlots ( ui32 slotsAmount = GameConstants : : ARMY_SIZE ) const ;
std : : queue < SlotID > getFreeSlotsQueue ( ui32 slotsAmount = GameConstants : : ARMY_SIZE ) const ;
TMapCreatureSlot getCreatureMap ( ) const ;
TCreatureQueue getCreatureQueue ( const SlotID & exclude ) const ;
2024-06-24 03:23:26 +02:00
bool mergeableStacks ( std : : pair < SlotID , SlotID > & out , const SlotID & preferable = SlotID ( ) ) const ; //looks for two same stacks, returns slot positions;
2023-10-19 16:19:09 +02:00
bool validTypes ( bool allowUnrandomized = false ) const ; //checks if all types of creatures are set properly
bool slotEmpty ( const SlotID & slot ) const ;
int stacksCount ( ) const ;
virtual bool needsLastStack ( ) const ; //true if last stack cannot be taken
2024-12-28 12:40:44 +01:00
ui64 getArmyStrength ( int fortLevel = 0 ) const ; //sum of AI values of creatures
2024-07-07 22:38:37 +02:00
ui64 getArmyCost ( ) const ; //sum of cost of creatures
2023-10-19 16:19:09 +02:00
ui64 getPower ( const SlotID & slot ) const ; //value of specific stack
std : : string getRoughAmount ( const SlotID & slot , int mode = 0 ) const ; //rough size of specific stack
std : : string getArmyDescription ( ) const ;
bool hasStackAtSlot ( const SlotID & slot ) const ;
bool contains ( const CStackInstance * stack ) const ;
bool canBeMergedWith ( const CCreatureSet & cs , bool allowMergingStacks = true ) const ;
2025-05-07 15:55:48 +03:00
/// Returns true if this creature set contains all listed units
/// If requireLastStack is true, then this function will also
/// require presence of any unit other than requested (or more units than requested)
bool hasUnits ( const std : : vector < CStackBasicDescriptor > & units , bool requireLastStack = true ) const ;
2024-01-20 20:34:51 +02:00
template < typename Handler > void serialize ( Handler & h )
2023-10-19 16:19:09 +02:00
{
h & stacks ;
h & formation ;
}
void serializeJson ( JsonSerializeFormat & handler , const std : : string & armyFieldName , const std : : optional < int > fixedSize = std : : nullopt ) ;
operator bool ( ) const
{
return ! stacks . empty ( ) ;
}
} ;
VCMI_LIB_NAMESPACE_END