| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- /*
- * CStackInstance.cpp, 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
- *
- */
- #include "StdInc.h"
- #include "CStackInstance.h"
- #include "CArmedInstance.h"
- #include "../../CConfigHandler.h"
- #include "../../GameLibrary.h"
- #include "../../IGameSettings.h"
- #include "../../callback/IGameInfoCallback.h"
- #include "../../entities/faction/CFaction.h"
- #include "../../texts/CGeneralTextHandler.h"
- #include "../../IBonusTypeHandler.h"
- #include "../../serializer/JsonSerializeFormat.h"
- VCMI_LIB_NAMESPACE_BEGIN
- CStackInstance::CStackInstance(IGameInfoCallback * cb)
- : CStackInstance(cb, BonusNodeType::STACK_INSTANCE, false)
- {
- }
- CStackInstance::CStackInstance(IGameInfoCallback * cb, BonusNodeType nodeType, bool isHypothetic)
- : CBonusSystemNode(nodeType, isHypothetic)
- , CStackBasicDescriptor(nullptr, 0)
- , CArtifactSet(cb)
- , GameCallbackHolder(cb)
- , nativeTerrain(this, Selector::type()(BonusType::TERRAIN_NATIVE))
- , initiative(this, Selector::type()(BonusType::STACKS_SPEED))
- , totalExperience(0)
- {
- }
- CStackInstance::CStackInstance(IGameInfoCallback * cb, const CreatureID & id, TQuantity Count, bool isHypothetic)
- : CStackInstance(cb, BonusNodeType::STACK_INSTANCE, false)
- {
- setType(id);
- setCount(Count);
- }
- CCreature::CreatureQuantityId CStackInstance::getQuantityID() const
- {
- return CCreature::getQuantityID(getCount());
- }
- int CStackInstance::getExpRank() const
- {
- if(!LIBRARY->engineSettings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
- return 0;
- int tier = getType()->getLevel();
- if(vstd::iswithin(tier, 1, 7))
- {
- for(int i = static_cast<int>(LIBRARY->creh->expRanks[tier].size()) - 2; i > -1; --i) //sic!
- { //exp values vary from 1st level to max exp at 11th level
- if(getAverageExperience() >= LIBRARY->creh->expRanks[tier][i])
- return ++i; //faster, but confusing - 0 index mean 1st level of experience
- }
- return 0;
- }
- else //higher tier
- {
- for(int i = static_cast<int>(LIBRARY->creh->expRanks[0].size()) - 2; i > -1; --i)
- {
- if(getAverageExperience() >= LIBRARY->creh->expRanks[0][i])
- return ++i;
- }
- return 0;
- }
- }
- int CStackInstance::getLevel() const
- {
- return std::max(1, getType()->getLevel());
- }
- void CStackInstance::giveAverageStackExperience(TExpType desiredAmountPerUnit)
- {
- if(!canGainExperience())
- return;
- int level = std::clamp(getLevel(), 1, 7);
- TExpType maxAmountPerUnit = LIBRARY->creh->expRanks[level].back();
- TExpType actualAmountPerUnit = std::min(desiredAmountPerUnit, maxAmountPerUnit * LIBRARY->creh->maxExpPerBattle[level] / 100);
- TExpType maxExperience = maxAmountPerUnit * getCount();
- TExpType maxExperienceToGain = maxExperience - totalExperience;
- TExpType actualGainedExperience = std::min(maxExperienceToGain, actualAmountPerUnit * getCount());
- totalExperience += actualGainedExperience;
- }
- void CStackInstance::giveTotalStackExperience(TExpType experienceToGive)
- {
- if(!canGainExperience())
- return;
- totalExperience += experienceToGive;
- }
- TExpType CStackInstance::getTotalExperience() const
- {
- return totalExperience;
- }
- TExpType CStackInstance::getAverageExperience() const
- {
- return totalExperience / getCount();
- }
- bool CStackInstance::canGainExperience() const
- {
- return cb->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE);
- }
- void CStackInstance::setType(const CreatureID & creID)
- {
- if(creID == CreatureID::NONE)
- setType(nullptr); //FIXME: unused branch?
- else
- setType(creID.toCreature());
- }
- void CStackInstance::setType(const CCreature * c)
- {
- if(getCreature())
- {
- detachFromSource(*getCreature());
- if(LIBRARY->engineSettings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
- totalExperience = totalExperience * LIBRARY->creh->expAfterUpgrade / 100;
- }
- CStackBasicDescriptor::setType(c);
- if(getCreature())
- attachToSource(*getCreature());
- }
- void CStackInstance::setCount(TQuantity newCount)
- {
- assert(newCount >= 0);
- if(newCount < getCount())
- {
- TExpType averageExperience = totalExperience / getCount();
- totalExperience = averageExperience * newCount;
- }
- CStackBasicDescriptor::setCount(newCount);
- nodeHasChanged();
- }
- std::string CStackInstance::bonusToString(const std::shared_ptr<Bonus> & bonus) const
- {
- if(!bonus->description.empty())
- return bonus->description.toString();
- else
- return LIBRARY->getBth()->bonusToString(bonus, this);
- }
- ImagePath CStackInstance::bonusToGraphics(const std::shared_ptr<Bonus> & bonus) const
- {
- if(!bonus->customIconPath.empty())
- return bonus->customIconPath;
- return LIBRARY->getBth()->bonusToGraphics(bonus);
- }
- CArmedInstance * CStackInstance::getArmy()
- {
- return armyInstance;
- }
- const CArmedInstance * CStackInstance::getArmy() const
- {
- return armyInstance;
- }
- void CStackInstance::setArmy(CArmedInstance * ArmyObj)
- {
- auto oldArmy = getArmy();
- if(oldArmy)
- {
- detachFrom(*oldArmy);
- armyInstance = nullptr;
- }
- if(ArmyObj)
- {
- attachTo(const_cast<CArmedInstance &>(*ArmyObj));
- armyInstance = ArmyObj;
- }
- }
- std::string CStackInstance::getQuantityTXT(bool capitalized) const
- {
- CCreature::CreatureQuantityId quantity = getQuantityID();
- if((int)quantity)
- {
- if(settings["gameTweaks"]["numericCreaturesQuantities"].Bool())
- return CCreature::getQuantityRangeStringForId(quantity);
- return LIBRARY->generaltexth->arraytxt[174 + (int)quantity * 3 - 1 - capitalized];
- }
- else
- return "";
- }
- bool CStackInstance::valid(bool allowUnrandomized) const
- {
- if(!randomStack)
- {
- return (getType() && getType() == getId().toEntity(LIBRARY));
- }
- else
- return allowUnrandomized;
- }
- std::string CStackInstance::nodeName() const
- {
- std::ostringstream oss;
- oss << "Stack of " << getCount() << " of ";
- if(getType())
- oss << getType()->getNamePluralTextID();
- else
- oss << "[UNDEFINED TYPE]";
- return oss.str();
- }
- PlayerColor CStackInstance::getOwner() const
- {
- auto army = getArmy();
- return army ? army->getOwner() : PlayerColor::NEUTRAL;
- }
- int32_t CStackInstance::getInitiative(int turn) const
- {
- if(turn == 0)
- return initiative.getValue();
- return ACreature::getInitiative(turn);
- }
- TerrainId CStackInstance::getNativeTerrain() const
- {
- if(nativeTerrain.hasBonus())
- return TerrainId::ANY_TERRAIN;
- return getFactionID().toEntity(LIBRARY)->getNativeTerrain();
- }
- TerrainId CStackInstance::getCurrentTerrain() const
- {
- assert(getArmy() != nullptr);
- return getArmy()->getCurrentTerrain();
- }
- CreatureID CStackInstance::getCreatureID() const
- {
- if(getType())
- return getType()->getId();
- else
- return CreatureID::NONE;
- }
- std::string CStackInstance::getName() const
- {
- return (getCount() > 1) ? getType()->getNamePluralTranslated() : getType()->getNameSingularTranslated();
- }
- ui64 CStackInstance::getPower() const
- {
- assert(getType());
- return static_cast<ui64>(getType()->getAIValue()) * getCount();
- }
- ui64 CStackInstance::getMarketValue() const
- {
- assert(getType());
- return getType()->getFullRecruitCost().marketValue() * getCount();
- }
- ArtBearer CStackInstance::bearerType() const
- {
- return ArtBearer::CREATURE;
- }
- CStackInstance::ArtPlacementMap CStackInstance::putArtifact(const ArtifactPosition & pos, const CArtifactInstance * art)
- {
- assert(!getArt(pos));
- assert(art->canBePutAt(this, pos));
- attachToSource(*art);
- return CArtifactSet::putArtifact(pos, art);
- }
- void CStackInstance::removeArtifact(const ArtifactPosition & pos)
- {
- assert(getArt(pos));
- detachFromSource(*getArt(pos));
- CArtifactSet::removeArtifact(pos);
- }
- void CStackInstance::serializeJson(JsonSerializeFormat & handler)
- {
- //todo: artifacts
- CStackBasicDescriptor::serializeJson(handler); //must be first
- if(handler.saving)
- {
- if(randomStack)
- {
- int level = randomStack->level;
- int upgrade = randomStack->upgrade;
- handler.serializeInt("level", level, 0);
- handler.serializeInt("upgraded", upgrade, 0);
- }
- }
- else
- {
- //type set by CStackBasicDescriptor::serializeJson
- if(getType() == nullptr)
- {
- uint8_t level = 0;
- uint8_t upgrade = 0;
- handler.serializeInt("level", level, 0);
- handler.serializeInt("upgrade", upgrade, 0);
- randomStack = RandomStackInfo{level, upgrade};
- }
- }
- }
- FactionID CStackInstance::getFactionID() const
- {
- if(getType())
- return getType()->getFactionID();
- return FactionID::NEUTRAL;
- }
- const IBonusBearer * CStackInstance::getBonusBearer() const
- {
- return this;
- }
- VCMI_LIB_NAMESPACE_END
|