1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
|
/*
* 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
#include "HeroBonus.h"
#include "GameConstants.h"
#include "CArtHandler.h"
class JsonNode;
class CCreature;
class CGHeroInstance;
class CArmedInstance;
class CCreatureArtifactSet;
class JsonSerializeFormat;
class DLL_LINKAGE CStackBasicDescriptor
{
public:
const CCreature *type;
TQuantity count;
CStackBasicDescriptor();
CStackBasicDescriptor(CreatureID id, TQuantity Count);
CStackBasicDescriptor(const CCreature *c, TQuantity Count);
virtual ~CStackBasicDescriptor() = default;
virtual void setType(const CCreature * c);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & type;
h & count;
}
void serializeJson(JsonSerializeFormat & handler);
};
class DLL_LINKAGE CStackInstance : public CBonusSystemNode, public CStackBasicDescriptor, public CArtifactSet
{
protected:
const CArmedInstance *_armyObj; //stack must be part of some army, army must be part of some object
public:
// hlp variable used during loading map, when object (hero or town) have creatures that must have same alignment.
// idRand < 0 -> normal, non-random creature
// idRand / 2 -> level
// idRand % 2 -> upgrade number
int idRand;
const CArmedInstance * const & armyObj; //stack must be part of some army, army must be part of some object
TExpType experience;//commander needs same amount of exp as hero
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CBonusSystemNode&>(*this);
h & static_cast<CStackBasicDescriptor&>(*this);
h & static_cast<CArtifactSet&>(*this);
h & _armyObj;
h & experience;
BONUS_TREE_DESERIALIZATION_FIX
}
void serializeJson(JsonSerializeFormat & handler);
//overrides CBonusSystemNode
std::string bonusToString(const std::shared_ptr<Bonus>& bonus, bool description) const override; // how would bonus description look for this particular type of node
std::string bonusToGraphics(const std::shared_ptr<Bonus>& bonus) const; //file name of graphics from StackSkills , in future possibly others
virtual ui64 getPower() const;
int getQuantityID() const;
std::string getQuantityTXT(bool capitalized = true) const;
virtual int getExpRank() const;
virtual int getLevel() const; //different for regular stack and commander
si32 magicResistance() const override;
CreatureID getCreatureID() const; //-1 if not available
std::string getName() const; //plural or singular
virtual void init();
CStackInstance();
CStackInstance(CreatureID id, TQuantity count);
CStackInstance(const CCreature *cre, TQuantity count);
virtual ~CStackInstance();
void setType(CreatureID creID);
void setType(const CCreature * c) override;
void setArmyObj(const CArmedInstance *ArmyObj);
virtual void giveStackExp(TExpType exp);
bool valid(bool allowUnrandomized) const;
void putArtifact(ArtifactPosition pos, CArtifactInstance * art) override;//from CArtifactSet
ArtBearer::ArtBearer bearerType() const override; //from CArtifactSet
virtual std::string nodeName() const override; //from CBonusSystemnode
void deserializationFix();
};
class DLL_LINKAGE CCommanderInstance : public CStackInstance
{
public:
//TODO: what if Commander is not a part of creature set?
//commander class is determined by its base creature
ui8 alive; //maybe change to bool when breaking save compatibility?
ui8 level; //required only to count callbacks
std::string name; // each Commander has different name
std::vector <ui8> secondarySkills; //ID -> level
std::set <ui8> specialSKills;
//std::vector <CArtifactInstance *> arts;
void init() override;
CCommanderInstance();
CCommanderInstance (CreatureID id);
virtual ~CCommanderInstance();
void setAlive (bool alive);
void giveStackExp (TExpType exp) override;
void levelUp ();
bool gainsLevel() const; //true if commander has lower level than should upon his experience
ui64 getPower() const override {return 0;};
int getExpRank() const override;
int getLevel() const override;
ArtBearer::ArtBearer bearerType() const override; //from CArtifactSet
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CStackInstance&>(*this);
h & alive;
h & level;
h & name;
h & secondarySkills;
h & specialSKills;
}
};
typedef std::map<SlotID, CStackInstance*> TSlots;
typedef std::map<SlotID, std::pair<CreatureID, TQuantity>> TSimpleSlots;
class IArmyDescriptor
{
public:
virtual void clear() = 0;
virtual bool setCreature(SlotID slot, CreatureID cre, TQuantity count) = 0;
};
//simplified version of CCreatureSet
class DLL_LINKAGE CSimpleArmy : public IArmyDescriptor
{
public:
TSimpleSlots army;
void clear() override;
bool setCreature(SlotID slot, CreatureID cre, TQuantity count) override;
operator bool() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & army;
}
};
class DLL_LINKAGE CCreatureSet : public IArmyDescriptor //seven combined creatures
{
CCreatureSet(const CCreatureSet&);
CCreatureSet &operator=(const CCreatureSet&);
public:
TSlots stacks; //slots[slot_id]->> pair(creature_id,creature_quantity)
ui8 formation; //false - wide, true - tight
CCreatureSet();
virtual ~CCreatureSet();
virtual void armyChanged();
const CStackInstance &operator[](SlotID slot) const;
const TSlots &Slots() const {return stacks;}
void addToSlot(SlotID slot, CreatureID cre, TQuantity count, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature
void addToSlot(SlotID slot, CStackInstance *stack, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature
void clear() override;
void setFormation(bool tight);
CArmedInstance *castToArmyObj();
//basic operations
void putStack(SlotID slot, CStackInstance *stack); //adds new stack to the army, slot must be empty
void setStackCount(SlotID slot, TQuantity count); //stack must exist!
CStackInstance *detachStack(SlotID slot); //removes stack from army but doesn't destroy it (so it can be moved somewhere else or safely deleted)
void setStackType(SlotID slot, CreatureID type);
void giveStackExp(TExpType exp);
void setStackExp(SlotID slot, TExpType exp);
//derivative
void eraseStack(SlotID slot); //slot must be occupied
void joinStack(SlotID slot, CStackInstance * stack); //adds new stack to the existing stack of the same type
void changeStackCount(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(SlotID slot) const; //stack must exist
const CStackInstance* getStackPtr(SlotID slot) const; //if stack doesn't exist, returns nullptr
const CCreature* getCreature(SlotID slot) const; //workaround of map issue;
int getStackCount (SlotID slot) const;
TExpType getStackExperience(SlotID slot) const;
SlotID findStack(const CStackInstance *stack) const; //-1 if none
SlotID getSlotFor(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
SlotID getFreeSlot(ui32 slotsAmount = GameConstants::ARMY_SIZE) const;
bool mergableStacks(std::pair<SlotID, SlotID> &out, SlotID preferable = SlotID()) const; //looks for two same stacks, returns slot positions;
bool validTypes(bool allowUnrandomized = false) const; //checks if all types of creatures are set properly
bool slotEmpty(SlotID slot) const;
int stacksCount() const;
virtual bool needsLastStack() const; //true if last stack cannot be taken
ui64 getArmyStrength() const; //sum of AI values of creatures
ui64 getPower (SlotID slot) const; //value of specific stack
std::string getRoughAmount(SlotID slot, int mode = 0) const; //rough size of specific stack
std::string getArmyDescription() const;
bool hasStackAtSlot(SlotID slot) const;
bool contains(const CStackInstance *stack) const;
bool canBeMergedWith(const CCreatureSet &cs, bool allowMergingStacks = true) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stacks;
h & formation;
}
void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName, const boost::optional<int> fixedSize = boost::none);
operator bool() const
{
return !stacks.empty();
}
void sweep();
};
|