mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-06 09:09:40 +02:00
(lib) Bonus subtype is now stored as metaidentifier that can store any
other identifier inside it
This commit is contained in:
@@ -313,7 +313,7 @@ void ExistingSkillRule::evaluateScore(const CGHeroInstance * hero, SecondarySkil
|
|||||||
if(heroSkill.first == skill)
|
if(heroSkill.first == skill)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
upgradesLeft += SecSkillLevel::EXPERT - heroSkill.second;
|
upgradesLeft += MasteryLevel::EXPERT - heroSkill.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(score >= 2 || (score >= 1 && upgradesLeft <= 1))
|
if(score >= 2 || (score >= 1 && upgradesLeft <= 1))
|
||||||
@@ -327,7 +327,7 @@ void WisdomRule::evaluateScore(const CGHeroInstance * hero, SecondarySkill skill
|
|||||||
|
|
||||||
auto wisdomLevel = hero->getSecSkillLevel(SecondarySkill::WISDOM);
|
auto wisdomLevel = hero->getSecSkillLevel(SecondarySkill::WISDOM);
|
||||||
|
|
||||||
if(hero->level > 10 && wisdomLevel == SecSkillLevel::NONE)
|
if(hero->level > 10 && wisdomLevel == MasteryLevel::NONE)
|
||||||
score += 1.5;
|
score += 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,7 +345,7 @@ void AtLeastOneMagicRule::evaluateScore(const CGHeroInstance * hero, SecondarySk
|
|||||||
|
|
||||||
bool heroHasAnyMagic = vstd::contains_if(magicSchools, [&](SecondarySkill skill) -> bool
|
bool heroHasAnyMagic = vstd::contains_if(magicSchools, [&](SecondarySkill skill) -> bool
|
||||||
{
|
{
|
||||||
return hero->getSecSkillLevel(skill) > SecSkillLevel::NONE;
|
return hero->getSecSkillLevel(skill) > MasteryLevel::NONE;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!heroHasAnyMagic)
|
if(!heroHasAnyMagic)
|
||||||
|
|||||||
@@ -538,7 +538,7 @@ float RewardEvaluator::evaluateWitchHutSkillScore(const CGObjectInstance * hut,
|
|||||||
if(!hut->wasVisited(hero->tempOwner))
|
if(!hut->wasVisited(hero->tempOwner))
|
||||||
return role == HeroRole::SCOUT ? 2 : 0;
|
return role == HeroRole::SCOUT ? 2 : 0;
|
||||||
|
|
||||||
if(hero->getSecSkillLevel(skill) != SecSkillLevel::NONE
|
if(hero->getSecSkillLevel(skill) != MasteryLevel::NONE
|
||||||
|| hero->secSkills.size() >= GameConstants::SKILL_PER_HERO)
|
|| hero->secSkills.size() >= GameConstants::SKILL_PER_HERO)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -984,7 +984,7 @@ std::vector<CGPathNode *> AINodeStorage::calculateTeleportations(
|
|||||||
struct TowmPortalFinder
|
struct TowmPortalFinder
|
||||||
{
|
{
|
||||||
const std::vector<CGPathNode *> & initialNodes;
|
const std::vector<CGPathNode *> & initialNodes;
|
||||||
SecSkillLevel::SecSkillLevel townPortalSkillLevel;
|
MasteryLevel townPortalSkillLevel;
|
||||||
uint64_t movementNeeded;
|
uint64_t movementNeeded;
|
||||||
const ChainActor * actor;
|
const ChainActor * actor;
|
||||||
const CGHeroInstance * hero;
|
const CGHeroInstance * hero;
|
||||||
@@ -1006,8 +1006,8 @@ struct TowmPortalFinder
|
|||||||
townPortal = spellID.toSpell();
|
townPortal = spellID.toSpell();
|
||||||
|
|
||||||
// TODO: Copy/Paste from TownPortalMechanics
|
// TODO: Copy/Paste from TownPortalMechanics
|
||||||
townPortalSkillLevel = SecSkillLevel::SecSkillLevel(hero->getSpellSchoolLevel(townPortal));
|
townPortalSkillLevel = MasteryLevel(hero->getSpellSchoolLevel(townPortal));
|
||||||
movementNeeded = GameConstants::BASE_MOVEMENT_COST * (townPortalSkillLevel >= SecSkillLevel::EXPERT ? 2 : 3);
|
movementNeeded = GameConstants::BASE_MOVEMENT_COST * (townPortalSkillLevel >= MasteryLevel::EXPERT ? 2 : 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool actorCanCastTownPortal()
|
bool actorCanCastTownPortal()
|
||||||
@@ -1028,7 +1028,7 @@ struct TowmPortalFinder
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(townPortalSkillLevel < SecSkillLevel::ADVANCED)
|
if(townPortalSkillLevel < MasteryLevel::ADVANCED)
|
||||||
{
|
{
|
||||||
const CGTownInstance * nearestTown = *vstd::minElementByFun(targetTowns, [&](const CGTownInstance * t) -> int
|
const CGTownInstance * nearestTown = *vstd::minElementByFun(targetTowns, [&](const CGTownInstance * t) -> int
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ namespace AIPathfinding
|
|||||||
auto summonBoatSpell = SpellID(SpellID::SUMMON_BOAT).toSpell();
|
auto summonBoatSpell = SpellID(SpellID::SUMMON_BOAT).toSpell();
|
||||||
|
|
||||||
if(hero->canCastThisSpell(summonBoatSpell)
|
if(hero->canCastThisSpell(summonBoatSpell)
|
||||||
&& hero->getSpellSchoolLevel(summonBoatSpell) >= SecSkillLevel::ADVANCED)
|
&& hero->getSpellSchoolLevel(summonBoatSpell) >= MasteryLevel::ADVANCED)
|
||||||
{
|
{
|
||||||
// TODO: For lower school level we might need to check the existance of some boat
|
// TODO: For lower school level we might need to check the existance of some boat
|
||||||
summonableVirtualBoats[hero] = std::make_shared<SummonBoatAction>();
|
summonableVirtualBoats[hero] = std::make_shared<SummonBoatAction>();
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ void AINodeStorage::calculateTownPortalTeleportations(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(skillLevel < SecSkillLevel::ADVANCED)
|
if(skillLevel < MasteryLevel::ADVANCED)
|
||||||
{
|
{
|
||||||
const CGTownInstance * nearestTown = *vstd::minElementByFun(towns, [&](const CGTownInstance * t) -> int
|
const CGTownInstance * nearestTown = *vstd::minElementByFun(towns, [&](const CGTownInstance * t) -> int
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ namespace AIPathfinding
|
|||||||
auto summonBoatSpell = SpellID(SpellID::SUMMON_BOAT).toSpell();
|
auto summonBoatSpell = SpellID(SpellID::SUMMON_BOAT).toSpell();
|
||||||
|
|
||||||
if(hero->canCastThisSpell(summonBoatSpell)
|
if(hero->canCastThisSpell(summonBoatSpell)
|
||||||
&& hero->getSpellSchoolLevel(summonBoatSpell) >= SecSkillLevel::ADVANCED)
|
&& hero->getSpellSchoolLevel(summonBoatSpell) >= MasteryLevel::ADVANCED)
|
||||||
{
|
{
|
||||||
// TODO: For lower school level we might need to check the existance of some boat
|
// TODO: For lower school level we might need to check the existance of some boat
|
||||||
summonableVirtualBoat.reset(new SummonBoatAction());
|
summonableVirtualBoat.reset(new SummonBoatAction());
|
||||||
|
|||||||
@@ -44,10 +44,7 @@
|
|||||||
"description" : "type"
|
"description" : "type"
|
||||||
},
|
},
|
||||||
"subtype" : {
|
"subtype" : {
|
||||||
"anyOf" : [
|
"type" : "string",
|
||||||
{ "type" : "string" },
|
|
||||||
{ "type" : "number" }
|
|
||||||
],
|
|
||||||
"description" : "subtype"
|
"description" : "subtype"
|
||||||
},
|
},
|
||||||
"sourceID" : {
|
"sourceID" : {
|
||||||
|
|||||||
@@ -294,8 +294,9 @@ Heroes affected by this bonus can not retreat or surrender in battle
|
|||||||
|
|
||||||
### NEGATE_ALL_NATURAL_IMMUNITIES
|
### NEGATE_ALL_NATURAL_IMMUNITIES
|
||||||
|
|
||||||
- subtype: TODO
|
Negates all natural immunities for affected stacks. (Orb of Vulnerability)
|
||||||
Orb of Vulnerability
|
|
||||||
|
- subtype: 0 - battle-wide immunity negation, 1 - negation only for enemy stacks
|
||||||
|
|
||||||
### OPENING_BATTLE_SPELL
|
### OPENING_BATTLE_SPELL
|
||||||
|
|
||||||
@@ -878,13 +879,14 @@ Affected unit will deal more damage in all attacks (Adela specialty)
|
|||||||
|
|
||||||
Affected heroes will be under effect of Disguise spell, hiding some of their information from opposing players
|
Affected heroes will be under effect of Disguise spell, hiding some of their information from opposing players
|
||||||
|
|
||||||
- subtype: spell mastery level
|
- val: spell mastery level
|
||||||
|
|
||||||
### VISIONS
|
### VISIONS
|
||||||
|
|
||||||
Affected heroes will be under effect of Visions spell, revealing information of enemy objects in specific range
|
Affected heroes will be under effect of Visions spell, revealing information of enemy objects in specific range
|
||||||
|
|
||||||
- val: multiplier to effect range. Information is revealed within (val \* hero spell power) range
|
- val: multiplier to effect range. Information is revealed within (val \* hero spell power) range
|
||||||
|
- subtype: 0 - reveal information on monsters, 1 - reveal information on heroes, 2 - reveal information on towns
|
||||||
|
|
||||||
### BLOCK_MAGIC_BELOW
|
### BLOCK_MAGIC_BELOW
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class BonusList;
|
class BonusList;
|
||||||
enum class PrimarySkill : int8_t;
|
class PrimarySkill;
|
||||||
|
|
||||||
class DLL_LINKAGE AFactionMember: public IConstBonusProvider, public INativeTerrainProvider
|
class DLL_LINKAGE AFactionMember: public IConstBonusProvider, public INativeTerrainProvider
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ DLL_LINKAGE CArtifactInstance * ArtifactUtils::createScroll(const SpellID & sid)
|
|||||||
{
|
{
|
||||||
auto ret = new CArtifactInstance(VLC->arth->objects[ArtifactID::SPELL_SCROLL]);
|
auto ret = new CArtifactInstance(VLC->arth->objects[ArtifactID::SPELL_SCROLL]);
|
||||||
auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELL,
|
auto bonus = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELL,
|
||||||
BonusSource::ARTIFACT_INSTANCE, -1, ArtifactID::SPELL_SCROLL, sid);
|
BonusSource::ARTIFACT_INSTANCE, -1, ArtifactID::SPELL_SCROLL, TBonusSubtype(sid));
|
||||||
ret->addNewBonus(bonus);
|
ret->addNewBonus(bonus);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ TerrainId AFactionMember::getNativeTerrain() const
|
|||||||
{
|
{
|
||||||
constexpr auto any = TerrainId(ETerrainId::ANY_TERRAIN);
|
constexpr auto any = TerrainId(ETerrainId::ANY_TERRAIN);
|
||||||
const std::string cachingStringNoTerrainPenalty = "type_NO_TERRAIN_PENALTY_sANY";
|
const std::string cachingStringNoTerrainPenalty = "type_NO_TERRAIN_PENALTY_sANY";
|
||||||
static const auto selectorNoTerrainPenalty = Selector::typeSubtype(BonusType::NO_TERRAIN_PENALTY, any);
|
static const auto selectorNoTerrainPenalty = Selector::typeSubtype(BonusType::NO_TERRAIN_PENALTY, TBonusSubtype(any));
|
||||||
|
|
||||||
//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
|
//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
|
||||||
//and in the CGHeroInstance::getNativeTerrain() to setup movement bonuses or/and penalties.
|
//and in the CGHeroInstance::getNativeTerrain() to setup movement bonuses or/and penalties.
|
||||||
@@ -54,7 +54,7 @@ int AFactionMember::getAttack(bool ranged) const
|
|||||||
{
|
{
|
||||||
const std::string cachingStr = "type_PRIMARY_SKILLs_ATTACK";
|
const std::string cachingStr = "type_PRIMARY_SKILLs_ATTACK";
|
||||||
|
|
||||||
static const auto selector = Selector::typeSubtype(BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::ATTACK));
|
static const auto selector = Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::ATTACK));
|
||||||
|
|
||||||
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ int AFactionMember::getDefense(bool ranged) const
|
|||||||
{
|
{
|
||||||
const std::string cachingStr = "type_PRIMARY_SKILLs_DEFENSE";
|
const std::string cachingStr = "type_PRIMARY_SKILLs_DEFENSE";
|
||||||
|
|
||||||
static const auto selector = Selector::typeSubtype(BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::DEFENSE));
|
static const auto selector = Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE));
|
||||||
|
|
||||||
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
||||||
}
|
}
|
||||||
@@ -71,14 +71,14 @@ int AFactionMember::getDefense(bool ranged) const
|
|||||||
int AFactionMember::getMinDamage(bool ranged) const
|
int AFactionMember::getMinDamage(bool ranged) const
|
||||||
{
|
{
|
||||||
const std::string cachingStr = "type_CREATURE_DAMAGEs_0Otype_CREATURE_DAMAGEs_1";
|
const std::string cachingStr = "type_CREATURE_DAMAGEs_0Otype_CREATURE_DAMAGEs_1";
|
||||||
static const auto selector = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 1));
|
static const auto selector = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMin));
|
||||||
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AFactionMember::getMaxDamage(bool ranged) const
|
int AFactionMember::getMaxDamage(bool ranged) const
|
||||||
{
|
{
|
||||||
const std::string cachingStr = "type_CREATURE_DAMAGEs_0Otype_CREATURE_DAMAGEs_2";
|
const std::string cachingStr = "type_CREATURE_DAMAGEs_0Otype_CREATURE_DAMAGEs_2";
|
||||||
static const auto selector = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 2));
|
static const auto selector = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMax));
|
||||||
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ int AFactionMember::getPrimSkillLevel(PrimarySkill id) const
|
|||||||
static const CSelector selectorAllSkills = Selector::type()(BonusType::PRIMARY_SKILL);
|
static const CSelector selectorAllSkills = Selector::type()(BonusType::PRIMARY_SKILL);
|
||||||
static const std::string keyAllSkills = "type_PRIMARY_SKILL";
|
static const std::string keyAllSkills = "type_PRIMARY_SKILL";
|
||||||
auto allSkills = getBonusBearer()->getBonuses(selectorAllSkills, keyAllSkills);
|
auto allSkills = getBonusBearer()->getBonuses(selectorAllSkills, keyAllSkills);
|
||||||
auto ret = allSkills->valOfBonuses(Selector::subtype()(static_cast<int>(id)));
|
auto ret = allSkills->valOfBonuses(Selector::subtype()(TBonusSubtype(id)));
|
||||||
auto minSkillValue = (id == PrimarySkill::SPELL_POWER || id == PrimarySkill::KNOWLEDGE) ? 1 : 0;
|
auto minSkillValue = (id == PrimarySkill::SPELL_POWER || id == PrimarySkill::KNOWLEDGE) ? 1 : 0;
|
||||||
return std::max(ret, minSkillValue); //otherwise, some artifacts may cause negative skill value effect, sp=0 works in old saves
|
return std::max(ret, minSkillValue); //otherwise, some artifacts may cause negative skill value effect, sp=0 works in old saves
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ SpellID CScrollArtifactInstance::getScrollSpellID() const
|
|||||||
logMod->warn("Warning: %s doesn't bear any spell!", artInst->nodeName());
|
logMod->warn("Warning: %s doesn't bear any spell!", artInst->nodeName());
|
||||||
return SpellID::NONE;
|
return SpellID::NONE;
|
||||||
}
|
}
|
||||||
return SpellID(bonus->subtype);
|
return bonus->subtype.as<SpellID>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGrowingArtifactInstance::growingUp()
|
void CGrowingArtifactInstance::growingUp()
|
||||||
|
|||||||
@@ -77,10 +77,10 @@ std::string CBonusTypeHandler::bonusToString(const std::shared_ptr<Bonus> & bonu
|
|||||||
boost::algorithm::replace_all(text, "${val}", std::to_string(bearer->valOfBonuses(Selector::typeSubtype(bonus->type, bonus->subtype))));
|
boost::algorithm::replace_all(text, "${val}", std::to_string(bearer->valOfBonuses(Selector::typeSubtype(bonus->type, bonus->subtype))));
|
||||||
|
|
||||||
if (text.find("${subtype.creature}") != std::string::npos)
|
if (text.find("${subtype.creature}") != std::string::npos)
|
||||||
boost::algorithm::replace_all(text, "${subtype.creature}", CreatureID(bonus->subtype).toCreature()->getNamePluralTranslated());
|
boost::algorithm::replace_all(text, "${subtype.creature}", bonus->subtype.as<CreatureID>().toCreature()->getNamePluralTranslated());
|
||||||
|
|
||||||
if (text.find("${subtype.spell}") != std::string::npos)
|
if (text.find("${subtype.spell}") != std::string::npos)
|
||||||
boost::algorithm::replace_all(text, "${subtype.spell}", SpellID(bonus->subtype).toSpell()->getNameTranslated());
|
boost::algorithm::replace_all(text, "${subtype.spell}", bonus->subtype.as<SpellID>().toSpell()->getNameTranslated());
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@@ -95,57 +95,57 @@ ImagePath CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bonu
|
|||||||
case BonusType::SPELL_IMMUNITY:
|
case BonusType::SPELL_IMMUNITY:
|
||||||
{
|
{
|
||||||
fullPath = true;
|
fullPath = true;
|
||||||
const CSpell * sp = SpellID(bonus->subtype).toSpell();
|
const CSpell * sp = bonus->subtype.as<SpellID>().toSpell();
|
||||||
fileName = sp->getIconImmune();
|
fileName = sp->getIconImmune();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BonusType::SPELL_DAMAGE_REDUCTION: //Spell damage reduction for all schools
|
case BonusType::SPELL_DAMAGE_REDUCTION: //Spell damage reduction for all schools
|
||||||
{
|
{
|
||||||
if (bonus->subtype == SpellSchool::ANY.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::ANY)
|
||||||
fileName = "E_GOLEM.bmp";
|
fileName = "E_GOLEM.bmp";
|
||||||
|
|
||||||
if (bonus->subtype == SpellSchool::AIR.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::AIR)
|
||||||
fileName = "E_LIGHT.bmp";
|
fileName = "E_LIGHT.bmp";
|
||||||
|
|
||||||
if (bonus->subtype == SpellSchool::FIRE.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::FIRE)
|
||||||
fileName = "E_FIRE.bmp";
|
fileName = "E_FIRE.bmp";
|
||||||
|
|
||||||
if (bonus->subtype == SpellSchool::WATER.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::WATER)
|
||||||
fileName = "E_COLD.bmp";
|
fileName = "E_COLD.bmp";
|
||||||
|
|
||||||
if (bonus->subtype == SpellSchool::EARTH.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::EARTH)
|
||||||
fileName = "E_SPEATH1.bmp"; //No separate icon for earth damage
|
fileName = "E_SPEATH1.bmp"; //No separate icon for earth damage
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BonusType::SPELL_SCHOOL_IMMUNITY: //for all school
|
case BonusType::SPELL_SCHOOL_IMMUNITY: //for all school
|
||||||
{
|
{
|
||||||
if (bonus->subtype == SpellSchool::AIR.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::AIR)
|
||||||
fileName = "E_SPAIR.bmp";
|
fileName = "E_SPAIR.bmp";
|
||||||
|
|
||||||
if (bonus->subtype == SpellSchool::FIRE.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::FIRE)
|
||||||
fileName = "E_SPFIRE.bmp";
|
fileName = "E_SPFIRE.bmp";
|
||||||
|
|
||||||
if (bonus->subtype == SpellSchool::WATER.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::WATER)
|
||||||
fileName = "E_SPWATER.bmp";
|
fileName = "E_SPWATER.bmp";
|
||||||
|
|
||||||
if (bonus->subtype == SpellSchool::EARTH.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::EARTH)
|
||||||
fileName = "E_SPEATH.bmp";
|
fileName = "E_SPEATH.bmp";
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BonusType::NEGATIVE_EFFECTS_IMMUNITY:
|
case BonusType::NEGATIVE_EFFECTS_IMMUNITY:
|
||||||
{
|
{
|
||||||
if (bonus->subtype == SpellSchool::AIR.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::AIR)
|
||||||
fileName = "E_SPAIR1.bmp";
|
fileName = "E_SPAIR1.bmp";
|
||||||
|
|
||||||
if (bonus->subtype == SpellSchool::FIRE.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::FIRE)
|
||||||
fileName = "E_SPFIRE1.bmp";
|
fileName = "E_SPFIRE1.bmp";
|
||||||
|
|
||||||
if (bonus->subtype == SpellSchool::WATER.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::WATER)
|
||||||
fileName = "E_SPWATER1.bmp";
|
fileName = "E_SPWATER1.bmp";
|
||||||
|
|
||||||
if (bonus->subtype == SpellSchool::EARTH.getNum())
|
if (bonus->subtype.as<SpellSchool>() == SpellSchool::EARTH)
|
||||||
fileName = "E_SPEATH1.bmp";
|
fileName = "E_SPEATH1.bmp";
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -168,15 +168,12 @@ ImagePath CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bonu
|
|||||||
}
|
}
|
||||||
case BonusType::GENERAL_DAMAGE_REDUCTION:
|
case BonusType::GENERAL_DAMAGE_REDUCTION:
|
||||||
{
|
{
|
||||||
switch(bonus->subtype)
|
if (bonus->subtype == BonusSubtypes::damageTypeMelee)
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
fileName = "DamageReductionMelee.bmp";
|
fileName = "DamageReductionMelee.bmp";
|
||||||
break;
|
|
||||||
case 1:
|
if (bonus->subtype == BonusSubtypes::damageTypeRanged)
|
||||||
fileName = "DamageReductionRanged.bmp";
|
fileName = "DamageReductionRanged.bmp";
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,25 +113,25 @@ FactionID CCreature::getFaction() const
|
|||||||
|
|
||||||
int32_t CCreature::getBaseAttack() const
|
int32_t CCreature::getBaseAttack() const
|
||||||
{
|
{
|
||||||
static const auto SELECTOR = Selector::typeSubtype(BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::ATTACK)).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::ATTACK)).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
||||||
return getExportedBonusList().valOfBonuses(SELECTOR);
|
return getExportedBonusList().valOfBonuses(SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CCreature::getBaseDefense() const
|
int32_t CCreature::getBaseDefense() const
|
||||||
{
|
{
|
||||||
static const auto SELECTOR = Selector::typeSubtype(BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::DEFENSE)).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE)).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
||||||
return getExportedBonusList().valOfBonuses(SELECTOR);
|
return getExportedBonusList().valOfBonuses(SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CCreature::getBaseDamageMin() const
|
int32_t CCreature::getBaseDamageMin() const
|
||||||
{
|
{
|
||||||
static const auto SELECTOR = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 1).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMin).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
||||||
return getExportedBonusList().valOfBonuses(SELECTOR);
|
return getExportedBonusList().valOfBonuses(SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CCreature::getBaseDamageMax() const
|
int32_t CCreature::getBaseDamageMax() const
|
||||||
{
|
{
|
||||||
static const auto SELECTOR = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 2).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMax).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
||||||
return getExportedBonusList().valOfBonuses(SELECTOR);
|
return getExportedBonusList().valOfBonuses(SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,7 +291,7 @@ CCreature::CCreature()
|
|||||||
fightValue = AIValue = growth = hordeGrowth = ammMin = ammMax = 0;
|
fightValue = AIValue = growth = hordeGrowth = ammMin = ammMax = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCreature::addBonus(int val, BonusType type, int subtype)
|
void CCreature::addBonus(int val, BonusType type, TBonusSubtype subtype)
|
||||||
{
|
{
|
||||||
auto selector = Selector::typeSubtype(type, subtype).And(Selector::source(BonusSource::CREATURE_ABILITY, getIndex()));
|
auto selector = Selector::typeSubtype(type, subtype).And(Selector::source(BonusSource::CREATURE_ABILITY, getIndex()));
|
||||||
BonusList & exported = getExportedBonusList();
|
BonusList & exported = getExportedBonusList();
|
||||||
@@ -345,16 +345,16 @@ void CCreature::updateFrom(const JsonNode & data)
|
|||||||
addBonus(configNode["speed"].Integer(), BonusType::STACKS_SPEED);
|
addBonus(configNode["speed"].Integer(), BonusType::STACKS_SPEED);
|
||||||
|
|
||||||
if(!configNode["attack"].isNull())
|
if(!configNode["attack"].isNull())
|
||||||
addBonus(configNode["attack"].Integer(), BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::ATTACK));
|
addBonus(configNode["attack"].Integer(), BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::ATTACK));
|
||||||
|
|
||||||
if(!configNode["defense"].isNull())
|
if(!configNode["defense"].isNull())
|
||||||
addBonus(configNode["defense"].Integer(), BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::DEFENSE));
|
addBonus(configNode["defense"].Integer(), BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE));
|
||||||
|
|
||||||
if(!configNode["damage"]["min"].isNull())
|
if(!configNode["damage"]["min"].isNull())
|
||||||
addBonus(configNode["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, 1);
|
addBonus(configNode["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMin);
|
||||||
|
|
||||||
if(!configNode["damage"]["max"].isNull())
|
if(!configNode["damage"]["max"].isNull())
|
||||||
addBonus(configNode["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, 2);
|
addBonus(configNode["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMax);
|
||||||
|
|
||||||
if(!configNode["shots"].isNull())
|
if(!configNode["shots"].isNull())
|
||||||
addBonus(configNode["shots"].Integer(), BonusType::SHOTS);
|
addBonus(configNode["shots"].Integer(), BonusType::SHOTS);
|
||||||
@@ -604,11 +604,11 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
|
|||||||
|
|
||||||
cre->addBonus(node["hitPoints"].Integer(), BonusType::STACK_HEALTH);
|
cre->addBonus(node["hitPoints"].Integer(), BonusType::STACK_HEALTH);
|
||||||
cre->addBonus(node["speed"].Integer(), BonusType::STACKS_SPEED);
|
cre->addBonus(node["speed"].Integer(), BonusType::STACKS_SPEED);
|
||||||
cre->addBonus(node["attack"].Integer(), BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::ATTACK));
|
cre->addBonus(node["attack"].Integer(), BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::ATTACK));
|
||||||
cre->addBonus(node["defense"].Integer(), BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::DEFENSE));
|
cre->addBonus(node["defense"].Integer(), BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE));
|
||||||
|
|
||||||
cre->addBonus(node["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, 1);
|
cre->addBonus(node["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMin);
|
||||||
cre->addBonus(node["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, 2);
|
cre->addBonus(node["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMax);
|
||||||
|
|
||||||
assert(node["damage"]["min"].Integer() <= node["damage"]["max"].Integer());
|
assert(node["damage"]["min"].Integer() <= node["damage"]["max"].Integer());
|
||||||
|
|
||||||
@@ -1025,19 +1025,19 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
break;
|
break;
|
||||||
case 'A':
|
case 'A':
|
||||||
b.type = BonusType::PRIMARY_SKILL;
|
b.type = BonusType::PRIMARY_SKILL;
|
||||||
b.subtype = static_cast<int>(PrimarySkill::ATTACK);
|
b.subtype = TBonusSubtype(PrimarySkill::ATTACK);
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
b.type = BonusType::PRIMARY_SKILL;
|
b.type = BonusType::PRIMARY_SKILL;
|
||||||
b.subtype = static_cast<int>(PrimarySkill::DEFENSE);
|
b.subtype = TBonusSubtype(PrimarySkill::DEFENSE);
|
||||||
break;
|
break;
|
||||||
case 'M': //Max damage
|
case 'M': //Max damage
|
||||||
b.type = BonusType::CREATURE_DAMAGE;
|
b.type = BonusType::CREATURE_DAMAGE;
|
||||||
b.subtype = 2;
|
b.subtype = BonusSubtypes::creatureDamageMax;
|
||||||
break;
|
break;
|
||||||
case 'm': //Min damage
|
case 'm': //Min damage
|
||||||
b.type = BonusType::CREATURE_DAMAGE;
|
b.type = BonusType::CREATURE_DAMAGE;
|
||||||
b.subtype = 1;
|
b.subtype = BonusSubtypes::creatureDamageMin;
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
b.type = BonusType::STACKS_SPEED; break;
|
b.type = BonusType::STACKS_SPEED; break;
|
||||||
@@ -1051,17 +1051,16 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
b.type = BonusType::DEFENSIVE_STANCE; break;
|
b.type = BonusType::DEFENSIVE_STANCE; break;
|
||||||
case 'e':
|
case 'e':
|
||||||
b.type = BonusType::DOUBLE_DAMAGE_CHANCE;
|
b.type = BonusType::DOUBLE_DAMAGE_CHANCE;
|
||||||
b.subtype = 0;
|
|
||||||
break;
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
b.type = BonusType::DEATH_STARE;
|
b.type = BonusType::DEATH_STARE;
|
||||||
b.subtype = 0; //Gorgon
|
b.subtype = BonusSubtypes::deathStareGorgon;
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
b.type = BonusType::FEAR; break;
|
b.type = BonusType::FEAR; break;
|
||||||
case 'g':
|
case 'g':
|
||||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||||
b.subtype = SpellSchool(ESpellSchool::ANY);
|
b.subtype = TBonusSubtype(SpellSchool::ANY);
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
b.type = BonusType::CASTS; break;
|
b.type = BonusType::CASTS; break;
|
||||||
@@ -1069,7 +1068,6 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
b.type = BonusType::ADDITIONAL_RETALIATION; break;
|
b.type = BonusType::ADDITIONAL_RETALIATION; break;
|
||||||
case 'W':
|
case 'W':
|
||||||
b.type = BonusType::MAGIC_RESISTANCE;
|
b.type = BonusType::MAGIC_RESISTANCE;
|
||||||
b.subtype = 0; //otherwise creature window goes crazy
|
|
||||||
break;
|
break;
|
||||||
case 'f': //on-off skill
|
case 'f': //on-off skill
|
||||||
enable = true; //sometimes format is: 2 -> 0, 1 -> 1
|
enable = true; //sometimes format is: 2 -> 0, 1 -> 1
|
||||||
@@ -1103,7 +1101,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
b.type = BonusType::MIND_IMMUNITY; break;
|
b.type = BonusType::MIND_IMMUNITY; break;
|
||||||
case 'r':
|
case 'r':
|
||||||
b.type = BonusType::REBIRTH; //on/off? makes sense?
|
b.type = BonusType::REBIRTH; //on/off? makes sense?
|
||||||
b.subtype = 0;
|
b.subtype = BonusSubtypes::rebirthRegular;
|
||||||
b.val = 20; //arbitrary value
|
b.val = 20; //arbitrary value
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
@@ -1126,42 +1124,42 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
{
|
{
|
||||||
case 'B': //Blind
|
case 'B': //Blind
|
||||||
b.type = BonusType::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::BLIND;
|
b.subtype = TBonusSubtype(SpellID(SpellID::BLIND));
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'H': //Hypnotize
|
case 'H': //Hypnotize
|
||||||
b.type = BonusType::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::HYPNOTIZE;
|
b.subtype = TBonusSubtype(SpellID(SpellID::HYPNOTIZE));
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'I': //Implosion
|
case 'I': //Implosion
|
||||||
b.type = BonusType::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::IMPLOSION;
|
b.subtype = TBonusSubtype(SpellID(SpellID::IMPLOSION));
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'K': //Berserk
|
case 'K': //Berserk
|
||||||
b.type = BonusType::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::BERSERK;
|
b.subtype = TBonusSubtype(SpellID(SpellID::BERSERK));
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'M': //Meteor Shower
|
case 'M': //Meteor Shower
|
||||||
b.type = BonusType::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::METEOR_SHOWER;
|
b.subtype = TBonusSubtype(SpellID(SpellID::METEOR_SHOWER));
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'N': //dispell beneficial spells
|
case 'N': //dispell beneficial spells
|
||||||
b.type = BonusType::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::DISPEL_HELPFUL_SPELLS;
|
b.subtype = TBonusSubtype(SpellID(SpellID::DISPEL_HELPFUL_SPELLS));
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'R': //Armageddon
|
case 'R': //Armageddon
|
||||||
b.type = BonusType::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::ARMAGEDDON;
|
b.subtype = TBonusSubtype(SpellID(SpellID::ARMAGEDDON));
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'S': //Slow
|
case 'S': //Slow
|
||||||
b.type = BonusType::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::SLOW;
|
b.subtype = TBonusSubtype(SpellID(SpellID::SLOW));
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case '6':
|
case '6':
|
||||||
@@ -1177,51 +1175,51 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
b.type = BonusType::NEGATIVE_EFFECTS_IMMUNITY;
|
b.type = BonusType::NEGATIVE_EFFECTS_IMMUNITY;
|
||||||
b.subtype = SpellSchool(ESpellSchool::FIRE);
|
b.subtype = TBonusSubtype(SpellSchool::FIRE);
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||||
b.subtype = SpellSchool(ESpellSchool::FIRE);
|
b.subtype = TBonusSubtype(SpellSchool::FIRE);
|
||||||
b.val = 100; //Full damage immunity
|
b.val = 100; //Full damage immunity
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
||||||
b.subtype = SpellSchool(ESpellSchool::FIRE);
|
b.subtype = TBonusSubtype(SpellSchool::FIRE);
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
b.type = BonusType::NEGATIVE_EFFECTS_IMMUNITY;
|
b.type = BonusType::NEGATIVE_EFFECTS_IMMUNITY;
|
||||||
b.subtype = SpellSchool(ESpellSchool::WATER);
|
b.subtype = TBonusSubtype(SpellSchool::WATER);
|
||||||
break;
|
break;
|
||||||
case 'W':
|
case 'W':
|
||||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||||
b.subtype = SpellSchool(ESpellSchool::WATER);
|
b.subtype = TBonusSubtype(SpellSchool::WATER);
|
||||||
b.val = 100; //Full damage immunity
|
b.val = 100; //Full damage immunity
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
||||||
b.subtype = SpellSchool(ESpellSchool::WATER);
|
b.subtype = TBonusSubtype(SpellSchool::WATER);
|
||||||
break;
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||||
b.subtype = SpellSchool(ESpellSchool::EARTH);
|
b.subtype = TBonusSubtype(SpellSchool::EARTH);
|
||||||
b.val = 100; //Full damage immunity
|
b.val = 100; //Full damage immunity
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
||||||
b.subtype = SpellSchool(ESpellSchool::EARTH);
|
b.subtype = TBonusSubtype(SpellSchool::EARTH);
|
||||||
break;
|
break;
|
||||||
case 'A':
|
case 'A':
|
||||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||||
b.subtype = SpellSchool(ESpellSchool::AIR);
|
b.subtype = TBonusSubtype(SpellSchool::AIR);
|
||||||
b.val = 100; //Full damage immunity
|
b.val = 100; //Full damage immunity
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
b.type = BonusType::SPELL_SCHOOL_IMMUNITY;
|
||||||
b.subtype = SpellSchool(ESpellSchool::AIR);
|
b.subtype = TBonusSubtype(SpellSchool::AIR);
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||||
b.subtype = SpellSchool(ESpellSchool::ANY);
|
b.subtype = TBonusSubtype(SpellSchool::ANY);
|
||||||
b.val = 100; //Full damage immunity
|
b.val = 100; //Full damage immunity
|
||||||
break;
|
break;
|
||||||
case '0':
|
case '0':
|
||||||
@@ -1250,16 +1248,16 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
case 'K':
|
case 'K':
|
||||||
case 'k':
|
case 'k':
|
||||||
b.type = BonusType::SPELL_AFTER_ATTACK;
|
b.type = BonusType::SPELL_AFTER_ATTACK;
|
||||||
b.subtype = stringToNumber(mod);
|
b.subtype = TBonusSubtype(SpellID(stringToNumber(mod)));
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
b.type = BonusType::HATE;
|
b.type = BonusType::HATE;
|
||||||
b.subtype = stringToNumber(mod);
|
b.subtype = TBonusSubtype(CreatureID(stringToNumber(mod)));
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
case 'J':
|
case 'J':
|
||||||
b.type = BonusType::SPELL_BEFORE_ATTACK;
|
b.type = BonusType::SPELL_BEFORE_ATTACK;
|
||||||
b.subtype = stringToNumber(mod);
|
b.subtype = TBonusSubtype(SpellID(stringToNumber(mod)));
|
||||||
b.additionalInfo = 3; //always expert?
|
b.additionalInfo = 3; //always expert?
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
@@ -1268,7 +1266,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
b.type = BonusType::ENCHANTED;
|
b.type = BonusType::ENCHANTED;
|
||||||
b.subtype = stringToNumber(mod);
|
b.subtype = TBonusSubtype(SpellID(stringToNumber(mod)));
|
||||||
b.valType = BonusValueType::INDEPENDENT_MAX;
|
b.valType = BonusValueType::INDEPENDENT_MAX;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -194,7 +194,8 @@ public:
|
|||||||
|
|
||||||
bool valid() const;
|
bool valid() const;
|
||||||
|
|
||||||
void addBonus(int val, BonusType type, int subtype = -1);
|
void addBonus(int val, BonusType type);
|
||||||
|
void addBonus(int val, BonusType type, TBonusSubtype subtype);
|
||||||
std::string nodeName() const override;
|
std::string nodeName() const override;
|
||||||
|
|
||||||
template<typename RanGen>
|
template<typename RanGen>
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ bool CGameInfoCallback::getTownInfo(const CGObjectInstance * town, InfoAboutTown
|
|||||||
{
|
{
|
||||||
const auto * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
|
const auto * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
|
||||||
if(nullptr != selectedHero)
|
if(nullptr != selectedHero)
|
||||||
detailed = selectedHero->hasVisions(town, 1);
|
detailed = selectedHero->hasVisions(town, BonusSubtypes::visionsTowns);
|
||||||
}
|
}
|
||||||
|
|
||||||
dest.initFromTown(dynamic_cast<const CGTownInstance *>(town), detailed);
|
dest.initFromTown(dynamic_cast<const CGTownInstance *>(town), detailed);
|
||||||
@@ -322,7 +322,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
|
|||||||
{
|
{
|
||||||
const auto * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
|
const auto * selectedHero = dynamic_cast<const CGHeroInstance *>(selectedObject);
|
||||||
if(nullptr != selectedHero)
|
if(nullptr != selectedHero)
|
||||||
if(selectedHero->hasVisions(hero, 1))
|
if(selectedHero->hasVisions(hero, BonusSubtypes::visionsHeroes))
|
||||||
infoLevel = InfoAboutHero::EInfoLevel::DETAILED;
|
infoLevel = InfoAboutHero::EInfoLevel::DETAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +332,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
|
|||||||
if(getPlayerRelations(*getPlayerID(), hero->tempOwner) == PlayerRelations::ENEMIES)
|
if(getPlayerRelations(*getPlayerID(), hero->tempOwner) == PlayerRelations::ENEMIES)
|
||||||
{
|
{
|
||||||
//todo: bonus cashing
|
//todo: bonus cashing
|
||||||
int disguiseLevel = h->valOfBonuses(Selector::typeSubtype(BonusType::DISGUISED, 0));
|
int disguiseLevel = h->valOfBonuses(BonusType::DISGUISED);
|
||||||
|
|
||||||
auto doBasicDisguise = [](InfoAboutHero & info)
|
auto doBasicDisguise = [](InfoAboutHero & info)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -480,7 +480,7 @@ void CHeroHandler::loadHeroSkills(CHero * hero, const JsonNode & node) const
|
|||||||
for(const JsonNode &set : node["skills"].Vector())
|
for(const JsonNode &set : node["skills"].Vector())
|
||||||
{
|
{
|
||||||
int skillLevel = static_cast<int>(boost::range::find(NSecondarySkill::levels, set["level"].String()) - std::begin(NSecondarySkill::levels));
|
int skillLevel = static_cast<int>(boost::range::find(NSecondarySkill::levels, set["level"].String()) - std::begin(NSecondarySkill::levels));
|
||||||
if (skillLevel < SecSkillLevel::LEVELS_SIZE)
|
if (skillLevel < MasteryLevel::LEVELS_SIZE)
|
||||||
{
|
{
|
||||||
size_t currentIndex = hero->secSkillsInit.size();
|
size_t currentIndex = hero->secSkillsInit.size();
|
||||||
hero->secSkillsInit.emplace_back(SecondarySkill(-1), skillLevel);
|
hero->secSkillsInit.emplace_back(SecondarySkill(-1), skillLevel);
|
||||||
@@ -547,7 +547,7 @@ static std::vector<std::shared_ptr<Bonus>> createCreatureSpecialty(CreatureID ba
|
|||||||
{
|
{
|
||||||
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
||||||
bonus->type = BonusType::PRIMARY_SKILL;
|
bonus->type = BonusType::PRIMARY_SKILL;
|
||||||
bonus->subtype = static_cast<int>(PrimarySkill::ATTACK);
|
bonus->subtype = TBonusSubtype(PrimarySkill::ATTACK);
|
||||||
bonus->val = 0;
|
bonus->val = 0;
|
||||||
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
||||||
bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getAttack(false), stepSize));
|
bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getAttack(false), stepSize));
|
||||||
@@ -557,7 +557,7 @@ static std::vector<std::shared_ptr<Bonus>> createCreatureSpecialty(CreatureID ba
|
|||||||
{
|
{
|
||||||
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
||||||
bonus->type = BonusType::PRIMARY_SKILL;
|
bonus->type = BonusType::PRIMARY_SKILL;
|
||||||
bonus->subtype = static_cast<int>(PrimarySkill::DEFENSE);
|
bonus->subtype = TBonusSubtype(PrimarySkill::DEFENSE);
|
||||||
bonus->val = 0;
|
bonus->val = 0;
|
||||||
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
||||||
bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getDefense(false), stepSize));
|
bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getDefense(false), stepSize));
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ void CStack::prepareAttacked(BattleStackAttacked & bsa, vstd::RNG & rand, const
|
|||||||
resurrectedCount += 1;
|
resurrectedCount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(customState->hasBonusOfType(BonusType::REBIRTH, 1))
|
if(customState->hasBonusOfType(BonusType::REBIRTH, BonusSubtypes::rebirthSpecial))
|
||||||
{
|
{
|
||||||
// resurrect at least one Sacred Phoenix
|
// resurrect at least one Sacred Phoenix
|
||||||
vstd::amax(resurrectedCount, 1);
|
vstd::amax(resurrectedCount, 1);
|
||||||
|
|||||||
@@ -527,16 +527,16 @@ void CTownHandler::addBonusesForVanilaBuilding(CBuilding * building) const
|
|||||||
b = createBonus(building, BonusType::LUCK, +2);
|
b = createBonus(building, BonusType::LUCK, +2);
|
||||||
break;
|
break;
|
||||||
case BuildingSubID::SPELL_POWER_GARRISON_BONUS:
|
case BuildingSubID::SPELL_POWER_GARRISON_BONUS:
|
||||||
b = createBonus(building, BonusType::PRIMARY_SKILL, +2, static_cast<int>(PrimarySkill::SPELL_POWER));
|
b = createBonus(building, BonusType::PRIMARY_SKILL, +2, TBonusSubtype(PrimarySkill::SPELL_POWER));
|
||||||
break;
|
break;
|
||||||
case BuildingSubID::ATTACK_GARRISON_BONUS:
|
case BuildingSubID::ATTACK_GARRISON_BONUS:
|
||||||
b = createBonus(building, BonusType::PRIMARY_SKILL, +2, static_cast<int>(PrimarySkill::ATTACK));
|
b = createBonus(building, BonusType::PRIMARY_SKILL, +2, TBonusSubtype(PrimarySkill::ATTACK));
|
||||||
break;
|
break;
|
||||||
case BuildingSubID::DEFENSE_GARRISON_BONUS:
|
case BuildingSubID::DEFENSE_GARRISON_BONUS:
|
||||||
b = createBonus(building, BonusType::PRIMARY_SKILL, +2, static_cast<int>(PrimarySkill::DEFENSE));
|
b = createBonus(building, BonusType::PRIMARY_SKILL, +2, TBonusSubtype(PrimarySkill::DEFENSE));
|
||||||
break;
|
break;
|
||||||
case BuildingSubID::LIGHTHOUSE:
|
case BuildingSubID::LIGHTHOUSE:
|
||||||
b = createBonus(building, BonusType::MOVEMENT, +500, playerPropagator, 0);
|
b = createBonus(building, BonusType::MOVEMENT, +500, BonusSubtypes::heroMovementSea, playerPropagator);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,12 +544,12 @@ void CTownHandler::addBonusesForVanilaBuilding(CBuilding * building) const
|
|||||||
building->addNewBonus(b, building->buildingBonuses);
|
building->addNewBonus(b, building->buildingBonuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, int subtype) const
|
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, TBonusSubtype subtype) const
|
||||||
{
|
{
|
||||||
return createBonus(build, type, val, emptyPropagator(), subtype);
|
return createBonus(build, type, val, subtype, emptyPropagator());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, TPropagatorPtr & prop, int subtype) const
|
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, TBonusSubtype subtype, TPropagatorPtr & prop) const
|
||||||
{
|
{
|
||||||
std::ostringstream descr;
|
std::ostringstream descr;
|
||||||
descr << build->getNameTranslated();
|
descr << build->getNameTranslated();
|
||||||
@@ -561,9 +561,9 @@ std::shared_ptr<Bonus> CTownHandler::createBonusImpl(const BuildingID & building
|
|||||||
int val,
|
int val,
|
||||||
TPropagatorPtr & prop,
|
TPropagatorPtr & prop,
|
||||||
const std::string & description,
|
const std::string & description,
|
||||||
int subtype) const
|
TBonusSubtype subtype) const
|
||||||
{
|
{
|
||||||
auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, type, BonusSource::TOWN_STRUCTURE, val, building, description, subtype);
|
auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, type, BonusSource::TOWN_STRUCTURE, val, building, subtype, description);
|
||||||
|
|
||||||
if(prop)
|
if(prop)
|
||||||
b->addPropagator(prop);
|
b->addPropagator(prop);
|
||||||
|
|||||||
@@ -392,14 +392,15 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
|
|||||||
void loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source);
|
void loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source);
|
||||||
void loadBuildings(CTown * town, const JsonNode & source);
|
void loadBuildings(CTown * town, const JsonNode & source);
|
||||||
|
|
||||||
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, int subtype = -1) const;
|
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val) const;
|
||||||
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, TPropagatorPtr & prop, int subtype = -1) const;
|
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, TBonusSubtype subtype) const;
|
||||||
|
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, TBonusSubtype subtype, TPropagatorPtr & prop) const;
|
||||||
std::shared_ptr<Bonus> createBonusImpl(const BuildingID & building,
|
std::shared_ptr<Bonus> createBonusImpl(const BuildingID & building,
|
||||||
BonusType type,
|
BonusType type,
|
||||||
int val,
|
int val,
|
||||||
TPropagatorPtr & prop,
|
TPropagatorPtr & prop,
|
||||||
const std::string & description,
|
const std::string & description,
|
||||||
int subtype = -1) const;
|
TBonusSubtype subtype) const;
|
||||||
|
|
||||||
/// loads CStructure's into town
|
/// loads CStructure's into town
|
||||||
void loadStructure(CTown & town, const std::string & stringID, const JsonNode & source) const;
|
void loadStructure(CTown & town, const std::string & stringID, const JsonNode & source) const;
|
||||||
|
|||||||
@@ -417,13 +417,31 @@ std::string JsonNode::toJson(bool compact) const
|
|||||||
|
|
||||||
///JsonUtils
|
///JsonUtils
|
||||||
|
|
||||||
void JsonUtils::parseTypedBonusShort(const JsonVector & source, const std::shared_ptr<Bonus> & dest)
|
static void loadBonusSubtype(TBonusSubtype & subtype, BonusType type, const JsonNode & node)
|
||||||
{
|
{
|
||||||
dest->val = static_cast<si32>(source[1].Float());
|
if (node.isNull())
|
||||||
resolveIdentifier(source[2],dest->subtype);
|
{
|
||||||
dest->additionalInfo = static_cast<si32>(source[3].Float());
|
subtype = TBonusSubtype::NONE;
|
||||||
dest->duration = BonusDuration::PERMANENT; //TODO: handle flags (as integer)
|
return;
|
||||||
dest->turnsRemain = 0;
|
}
|
||||||
|
|
||||||
|
if (!node.isString())
|
||||||
|
{
|
||||||
|
logMod->warn("Bonus subtype must be string!");
|
||||||
|
subtype = TBonusSubtype::NONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VLC->identifiers()->requestIdentifier(node, [&subtype, node](int32_t identifier)
|
||||||
|
{
|
||||||
|
assert(0); //TODO
|
||||||
|
subtype = TBonusSubtype("type", node.String(), identifier);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadBonusSourceInstance(int32_t & sourceInstance, BonusSource sourceType, const JsonNode & node)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec)
|
std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec)
|
||||||
@@ -438,7 +456,11 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec)
|
|||||||
}
|
}
|
||||||
b->type = it->second;
|
b->type = it->second;
|
||||||
|
|
||||||
parseTypedBonusShort(ability_vec, b);
|
b->val = static_cast<si32>(ability_vec[1].Float());
|
||||||
|
loadBonusSubtype(b->subtype, b->type, ability_vec[2]);
|
||||||
|
b->additionalInfo = static_cast<si32>(ability_vec[3].Float());
|
||||||
|
b->duration = BonusDuration::PERMANENT; //TODO: handle flags (as integer)
|
||||||
|
b->turnsRemain = 0;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,31 +495,6 @@ const T parseByMapN(const std::map<std::string, T> & map, const JsonNode * val,
|
|||||||
return parseByMap<T>(map, val, err);
|
return parseByMap<T>(map, val, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonUtils::resolveIdentifier(si32 & var, const JsonNode & node, const std::string & name)
|
|
||||||
{
|
|
||||||
const JsonNode &value = node[name];
|
|
||||||
if (!value.isNull())
|
|
||||||
{
|
|
||||||
switch (value.getType())
|
|
||||||
{
|
|
||||||
case JsonNode::JsonType::DATA_INTEGER:
|
|
||||||
var = static_cast<si32>(value.Integer());
|
|
||||||
break;
|
|
||||||
case JsonNode::JsonType::DATA_FLOAT:
|
|
||||||
var = static_cast<si32>(value.Float());
|
|
||||||
break;
|
|
||||||
case JsonNode::JsonType::DATA_STRING:
|
|
||||||
VLC->identifiers()->requestIdentifier(value, [&](si32 identifier)
|
|
||||||
{
|
|
||||||
var = identifier;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logMod->error("Error! Wrong identifier used for value of %s.", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JsonUtils::resolveAddInfo(CAddInfo & var, const JsonNode & node)
|
void JsonUtils::resolveAddInfo(CAddInfo & var, const JsonNode & node)
|
||||||
{
|
{
|
||||||
const JsonNode & value = node["addInfo"];
|
const JsonNode & value = node["addInfo"];
|
||||||
@@ -549,27 +546,6 @@ void JsonUtils::resolveAddInfo(CAddInfo & var, const JsonNode & node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonUtils::resolveIdentifier(const JsonNode &node, si32 &var)
|
|
||||||
{
|
|
||||||
switch (node.getType())
|
|
||||||
{
|
|
||||||
case JsonNode::JsonType::DATA_INTEGER:
|
|
||||||
var = static_cast<si32>(node.Integer());
|
|
||||||
break;
|
|
||||||
case JsonNode::JsonType::DATA_FLOAT:
|
|
||||||
var = static_cast<si32>(node.Float());
|
|
||||||
break;
|
|
||||||
case JsonNode::JsonType::DATA_STRING:
|
|
||||||
VLC->identifiers()->requestIdentifier(node, [&](si32 identifier)
|
|
||||||
{
|
|
||||||
var = identifier;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logMod->error("Error! Wrong identifier used for identifier!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
|
std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
|
||||||
{
|
{
|
||||||
switch(limiter.getType())
|
switch(limiter.getType())
|
||||||
@@ -660,7 +636,7 @@ std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
|
|||||||
bonusLimiter->source = sourceIt->second;
|
bonusLimiter->source = sourceIt->second;
|
||||||
bonusLimiter->isSourceRelevant = true;
|
bonusLimiter->isSourceRelevant = true;
|
||||||
if(!parameter["id"].isNull()) {
|
if(!parameter["id"].isNull()) {
|
||||||
resolveIdentifier(parameter["id"], bonusLimiter->sid);
|
loadBonusSourceInstance(bonusLimiter->sid, bonusLimiter->source, parameter["id"]);
|
||||||
bonusLimiter->isSourceIDRelevant = true;
|
bonusLimiter->isSourceIDRelevant = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -673,7 +649,7 @@ std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
|
|||||||
return bonusLimiter;
|
return bonusLimiter;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resolveIdentifier(parameters[1], bonusLimiter->subtype);
|
loadBonusSubtype(bonusLimiter->subtype, bonusLimiter->type, parameters[1]);
|
||||||
bonusLimiter->isSubtypeRelevant = true;
|
bonusLimiter->isSubtypeRelevant = true;
|
||||||
if(parameters.size() > 2)
|
if(parameters.size() > 2)
|
||||||
findSource(parameters[2]);
|
findSource(parameters[2]);
|
||||||
@@ -765,7 +741,7 @@ std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode & ability, c
|
|||||||
source = BonusSource::TOWN_STRUCTURE
|
source = BonusSource::TOWN_STRUCTURE
|
||||||
bonusType, val, subtype - get from json
|
bonusType, val, subtype - get from json
|
||||||
*/
|
*/
|
||||||
auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::NONE, BonusSource::TOWN_STRUCTURE, 0, building, description, -1);
|
auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::NONE, BonusSource::TOWN_STRUCTURE, 0, building, description);
|
||||||
|
|
||||||
if(!parseBonus(ability, b.get()))
|
if(!parseBonus(ability, b.get()))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -865,7 +841,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
|||||||
else
|
else
|
||||||
b->type = it->second;
|
b->type = it->second;
|
||||||
|
|
||||||
resolveIdentifier(b->subtype, params->isConverted ? params->toJson() : ability, "subtype");
|
loadBonusSubtype(b->subtype, b->type, params->isConverted ? params->toJson() : ability);
|
||||||
|
|
||||||
if(!params->isConverted)
|
if(!params->isConverted)
|
||||||
{
|
{
|
||||||
@@ -996,7 +972,8 @@ CSelector JsonUtils::parseSelector(const JsonNode & ability)
|
|||||||
if(!value->isNull())
|
if(!value->isNull())
|
||||||
{
|
{
|
||||||
TBonusSubtype subtype;
|
TBonusSubtype subtype;
|
||||||
resolveIdentifier(subtype, ability, "subtype");
|
assert(0); //TODO
|
||||||
|
loadBonusSubtype(subtype, BonusType::NONE, ability);
|
||||||
ret = ret.And(Selector::subtype()(subtype));
|
ret = ret.And(Selector::subtype()(subtype));
|
||||||
}
|
}
|
||||||
value = &ability["sourceType"];
|
value = &ability["sourceType"];
|
||||||
@@ -1010,10 +987,9 @@ CSelector JsonUtils::parseSelector(const JsonNode & ability)
|
|||||||
}
|
}
|
||||||
|
|
||||||
value = &ability["sourceID"];
|
value = &ability["sourceID"];
|
||||||
if(!value->isNull())
|
if(!value->isNull() && src.has_value())
|
||||||
{
|
{
|
||||||
id = -1;
|
loadBonusSourceInstance(*id, *src, ability);
|
||||||
resolveIdentifier(*id, ability, "sourceID");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(src && id)
|
if(src && id)
|
||||||
|
|||||||
@@ -127,21 +127,12 @@ public:
|
|||||||
|
|
||||||
namespace JsonUtils
|
namespace JsonUtils
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @brief parse short bonus format, excluding type
|
|
||||||
* @note sets duration to Permament
|
|
||||||
*/
|
|
||||||
DLL_LINKAGE void parseTypedBonusShort(const JsonVector & source, const std::shared_ptr<Bonus> & dest);
|
|
||||||
|
|
||||||
///
|
|
||||||
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonVector & ability_vec);
|
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonVector & ability_vec);
|
||||||
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonNode & ability);
|
DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonNode & ability);
|
||||||
DLL_LINKAGE std::shared_ptr<Bonus> parseBuildingBonus(const JsonNode & ability, const BuildingID & building, const std::string & description);
|
DLL_LINKAGE std::shared_ptr<Bonus> parseBuildingBonus(const JsonNode & ability, const BuildingID & building, const std::string & description);
|
||||||
DLL_LINKAGE bool parseBonus(const JsonNode & ability, Bonus * placement);
|
DLL_LINKAGE bool parseBonus(const JsonNode & ability, Bonus * placement);
|
||||||
DLL_LINKAGE std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
|
DLL_LINKAGE std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
|
||||||
DLL_LINKAGE CSelector parseSelector(const JsonNode &ability);
|
DLL_LINKAGE CSelector parseSelector(const JsonNode &ability);
|
||||||
DLL_LINKAGE void resolveIdentifier(si32 & var, const JsonNode & node, const std::string & name);
|
|
||||||
DLL_LINKAGE void resolveIdentifier(const JsonNode & node, si32 & var);
|
|
||||||
DLL_LINKAGE void resolveAddInfo(CAddInfo & var, const JsonNode & node);
|
DLL_LINKAGE void resolveAddInfo(CAddInfo & var, const JsonNode & node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -442,9 +442,9 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
//native terrain bonuses
|
//native terrain bonuses
|
||||||
static auto nativeTerrain = std::make_shared<CreatureTerrainLimiter>();
|
static auto nativeTerrain = std::make_shared<CreatureTerrainLimiter>();
|
||||||
|
|
||||||
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::STACKS_SPEED, BonusSource::TERRAIN_NATIVE, 1, 0, 0)->addLimiter(nativeTerrain));
|
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::STACKS_SPEED, BonusSource::TERRAIN_NATIVE, 1, 0)->addLimiter(nativeTerrain));
|
||||||
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, 0, static_cast<int>(PrimarySkill::ATTACK))->addLimiter(nativeTerrain));
|
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, 0, TBonusSubtype(PrimarySkill::ATTACK))->addLimiter(nativeTerrain));
|
||||||
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, 0, static_cast<int>(PrimarySkill::DEFENSE))->addLimiter(nativeTerrain));
|
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, 0, TBonusSubtype(PrimarySkill::DEFENSE))->addLimiter(nativeTerrain));
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//tactics
|
//tactics
|
||||||
|
|||||||
@@ -1755,7 +1755,7 @@ SpellID CBattleInfoCallback::getRandomCastedSpell(CRandomGenerator & rand,const
|
|||||||
return SpellID::NONE;
|
return SpellID::NONE;
|
||||||
|
|
||||||
if(bl->size() == 1)
|
if(bl->size() == 1)
|
||||||
return SpellID(bl->front()->subtype);
|
return bl->front()->subtype.as<SpellID>();
|
||||||
|
|
||||||
int totalWeight = 0;
|
int totalWeight = 0;
|
||||||
for(const auto & b : *bl)
|
for(const auto & b : *bl)
|
||||||
@@ -1772,7 +1772,7 @@ SpellID CBattleInfoCallback::getRandomCastedSpell(CRandomGenerator & rand,const
|
|||||||
randomPos -= std::max(b->additionalInfo[0], 0);
|
randomPos -= std::max(b->additionalInfo[0], 0);
|
||||||
if(randomPos < 0)
|
if(randomPos < 0)
|
||||||
{
|
{
|
||||||
return SpellID(b->subtype);
|
return b->subtype.as<SpellID>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -340,10 +340,10 @@ CUnitState::CUnitState():
|
|||||||
health(this),
|
health(this),
|
||||||
shots(this),
|
shots(this),
|
||||||
totalAttacks(this, Selector::type()(BonusType::ADDITIONAL_ATTACK), 1),
|
totalAttacks(this, Selector::type()(BonusType::ADDITIONAL_ATTACK), 1),
|
||||||
minDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 1)), 0),
|
minDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMin)), 0),
|
||||||
maxDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 2)), 0),
|
maxDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusSubtypes::creatureDamageMax)), 0),
|
||||||
attack(this, Selector::typeSubtype(BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::ATTACK)), 0),
|
attack(this, Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::ATTACK)), 0),
|
||||||
defence(this, Selector::typeSubtype(BonusType::PRIMARY_SKILL, static_cast<int>(PrimarySkill::DEFENSE)), 0),
|
defence(this, Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(PrimarySkill::DEFENSE)), 0),
|
||||||
inFrenzy(this, Selector::type()(BonusType::IN_FRENZY)),
|
inFrenzy(this, Selector::type()(BonusType::IN_FRENZY)),
|
||||||
cloneLifetimeMarker(this, Selector::type()(BonusType::NONE).And(Selector::source(BonusSource::SPELL_EFFECT, SpellID::CLONE))),
|
cloneLifetimeMarker(this, Selector::type()(BonusType::NONE).And(Selector::source(BonusSource::SPELL_EFFECT, SpellID::CLONE))),
|
||||||
cloneID(-1)
|
cloneID(-1)
|
||||||
@@ -430,7 +430,7 @@ const CGHeroInstance * CUnitState::getHeroCaster() const
|
|||||||
|
|
||||||
int32_t CUnitState::getSpellSchoolLevel(const spells::Spell * spell, int32_t * outSelectedSchool) const
|
int32_t CUnitState::getSpellSchoolLevel(const spells::Spell * spell, int32_t * outSelectedSchool) const
|
||||||
{
|
{
|
||||||
int32_t skill = valOfBonuses(Selector::typeSubtype(BonusType::SPELLCASTER, spell->getIndex()));
|
int32_t skill = valOfBonuses(Selector::typeSubtype(BonusType::SPELLCASTER, TBonusSubtype(spell->getId())));
|
||||||
vstd::abetween(skill, 0, 3);
|
vstd::abetween(skill, 0, 3);
|
||||||
return skill;
|
return skill;
|
||||||
}
|
}
|
||||||
@@ -466,7 +466,7 @@ int32_t CUnitState::getEnchantPower(const spells::Spell * spell) const
|
|||||||
|
|
||||||
int64_t CUnitState::getEffectValue(const spells::Spell * spell) const
|
int64_t CUnitState::getEffectValue(const spells::Spell * spell) const
|
||||||
{
|
{
|
||||||
return static_cast<int64_t>(getCount()) * valOfBonuses(BonusType::SPECIFIC_SPELL_POWER, spell->getIndex());
|
return static_cast<int64_t>(getCount()) * valOfBonuses(BonusType::SPECIFIC_SPELL_POWER, TBonusSubtype(spell->getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerColor CUnitState::getCasterOwner() const
|
PlayerColor CUnitState::getCasterOwner() const
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ DamageRange DamageCalculator::getBaseDamageSingle() const
|
|||||||
{
|
{
|
||||||
auto retrieveHeroPrimSkill = [&](PrimarySkill skill) -> int
|
auto retrieveHeroPrimSkill = [&](PrimarySkill skill) -> int
|
||||||
{
|
{
|
||||||
std::shared_ptr<const Bonus> b = info.attacker->getBonus(Selector::sourceTypeSel(BonusSource::HERO_BASE_SKILL).And(Selector::typeSubtype(BonusType::PRIMARY_SKILL, static_cast<int>(skill))));
|
std::shared_ptr<const Bonus> b = info.attacker->getBonus(Selector::sourceTypeSel(BonusSource::HERO_BASE_SKILL).And(Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(skill))));
|
||||||
return b ? b->val : 0;
|
return b ? b->val : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,8 +142,9 @@ int DamageCalculator::getActorAttackSlayer() const
|
|||||||
|
|
||||||
if(isAffected)
|
if(isAffected)
|
||||||
{
|
{
|
||||||
int attackBonus = SpellID(SpellID::SLAYER).toSpell()->getLevelPower(spLevel);
|
SpellID spell(SpellID::SLAYER);
|
||||||
if(info.attacker->hasBonusOfType(BonusType::SPECIAL_PECULIAR_ENCHANT, SpellID::SLAYER))
|
int attackBonus = spell.toSpell()->getLevelPower(spLevel);
|
||||||
|
if(info.attacker->hasBonusOfType(BonusType::SPECIAL_PECULIAR_ENCHANT, TBonusSubtype(spell)))
|
||||||
{
|
{
|
||||||
ui8 attackerTier = info.attacker->unitType()->getLevel();
|
ui8 attackerTier = info.attacker->unitType()->getLevel();
|
||||||
ui8 specialtyBonus = std::max(5 - attackerTier, 0);
|
ui8 specialtyBonus = std::max(5 - attackerTier, 0);
|
||||||
@@ -205,11 +206,11 @@ double DamageCalculator::getAttackOffenseArcheryFactor() const
|
|||||||
if(info.shooting)
|
if(info.shooting)
|
||||||
{
|
{
|
||||||
const std::string cachingStrArchery = "type_PERCENTAGE_DAMAGE_BOOSTs_1";
|
const std::string cachingStrArchery = "type_PERCENTAGE_DAMAGE_BOOSTs_1";
|
||||||
static const auto selectorArchery = Selector::typeSubtype(BonusType::PERCENTAGE_DAMAGE_BOOST, 1);
|
static const auto selectorArchery = Selector::typeSubtype(BonusType::PERCENTAGE_DAMAGE_BOOST, BonusSubtypes::damageTypeRanged);
|
||||||
return info.attacker->valOfBonuses(selectorArchery, cachingStrArchery) / 100.0;
|
return info.attacker->valOfBonuses(selectorArchery, cachingStrArchery) / 100.0;
|
||||||
}
|
}
|
||||||
const std::string cachingStrOffence = "type_PERCENTAGE_DAMAGE_BOOSTs_0";
|
const std::string cachingStrOffence = "type_PERCENTAGE_DAMAGE_BOOSTs_0";
|
||||||
static const auto selectorOffence = Selector::typeSubtype(BonusType::PERCENTAGE_DAMAGE_BOOST, 0);
|
static const auto selectorOffence = Selector::typeSubtype(BonusType::PERCENTAGE_DAMAGE_BOOST, BonusSubtypes::damageTypeMelee);
|
||||||
return info.attacker->valOfBonuses(selectorOffence, cachingStrOffence) / 100.0;
|
return info.attacker->valOfBonuses(selectorOffence, cachingStrOffence) / 100.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +232,7 @@ double DamageCalculator::getAttackDoubleDamageFactor() const
|
|||||||
{
|
{
|
||||||
if(info.doubleDamage) {
|
if(info.doubleDamage) {
|
||||||
const auto cachingStr = "type_BONUS_DAMAGE_PERCENTAGEs_" + std::to_string(info.attacker->creatureIndex());
|
const auto cachingStr = "type_BONUS_DAMAGE_PERCENTAGEs_" + std::to_string(info.attacker->creatureIndex());
|
||||||
const auto selector = Selector::typeSubtype(BonusType::BONUS_DAMAGE_PERCENTAGE, info.attacker->creatureIndex());
|
const auto selector = Selector::typeSubtype(BonusType::BONUS_DAMAGE_PERCENTAGE, TBonusSubtype(info.attacker->creatureId()));
|
||||||
return info.attacker->valOfBonuses(selector, cachingStr) / 100.0;
|
return info.attacker->valOfBonuses(selector, cachingStr) / 100.0;
|
||||||
}
|
}
|
||||||
return 0.0;
|
return 0.0;
|
||||||
@@ -259,7 +260,7 @@ double DamageCalculator::getAttackHateFactor() const
|
|||||||
|
|
||||||
auto allHateEffects = info.attacker->getBonuses(selectorHate, cachingStrHate);
|
auto allHateEffects = info.attacker->getBonuses(selectorHate, cachingStrHate);
|
||||||
|
|
||||||
return allHateEffects->valOfBonuses(Selector::subtype()(info.defender->creatureIndex())) / 100.0;
|
return allHateEffects->valOfBonuses(Selector::subtype()(TBonusSubtype(info.defender->creatureId()))) / 100.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double DamageCalculator::getDefenseSkillFactor() const
|
double DamageCalculator::getDefenseSkillFactor() const
|
||||||
@@ -281,7 +282,7 @@ double DamageCalculator::getDefenseSkillFactor() const
|
|||||||
double DamageCalculator::getDefenseArmorerFactor() const
|
double DamageCalculator::getDefenseArmorerFactor() const
|
||||||
{
|
{
|
||||||
const std::string cachingStrArmorer = "type_GENERAL_DAMAGE_REDUCTIONs_N1_NsrcSPELL_EFFECT";
|
const std::string cachingStrArmorer = "type_GENERAL_DAMAGE_REDUCTIONs_N1_NsrcSPELL_EFFECT";
|
||||||
static const auto selectorArmorer = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, -1).And(Selector::sourceTypeSel(BonusSource::SPELL_EFFECT).Not());
|
static const auto selectorArmorer = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypes::damageTypeAll).And(Selector::sourceTypeSel(BonusSource::SPELL_EFFECT).Not());
|
||||||
return info.defender->valOfBonuses(selectorArmorer, cachingStrArmorer) / 100.0;
|
return info.defender->valOfBonuses(selectorArmorer, cachingStrArmorer) / 100.0;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -289,10 +290,10 @@ double DamageCalculator::getDefenseArmorerFactor() const
|
|||||||
double DamageCalculator::getDefenseMagicShieldFactor() const
|
double DamageCalculator::getDefenseMagicShieldFactor() const
|
||||||
{
|
{
|
||||||
const std::string cachingStrMeleeReduction = "type_GENERAL_DAMAGE_REDUCTIONs_0";
|
const std::string cachingStrMeleeReduction = "type_GENERAL_DAMAGE_REDUCTIONs_0";
|
||||||
static const auto selectorMeleeReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, 0);
|
static const auto selectorMeleeReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypes::damageTypeMelee);
|
||||||
|
|
||||||
const std::string cachingStrRangedReduction = "type_GENERAL_DAMAGE_REDUCTIONs_1";
|
const std::string cachingStrRangedReduction = "type_GENERAL_DAMAGE_REDUCTIONs_1";
|
||||||
static const auto selectorRangedReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, 1);
|
static const auto selectorRangedReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypes::damageTypeRanged);
|
||||||
|
|
||||||
//handling spell effects - shield and air shield
|
//handling spell effects - shield and air shield
|
||||||
if(info.shooting)
|
if(info.shooting)
|
||||||
@@ -313,7 +314,7 @@ double DamageCalculator::getDefenseRangePenaltiesFactor() const
|
|||||||
{
|
{
|
||||||
return bonus->source == BonusSource::SPELL_EFFECT
|
return bonus->source == BonusSource::SPELL_EFFECT
|
||||||
&& bonus->sid == SpellID::AIR_SHIELD
|
&& bonus->sid == SpellID::AIR_SHIELD
|
||||||
&& bonus->val >= SecSkillLevel::ADVANCED;
|
&& bonus->val >= MasteryLevel::ADVANCED;
|
||||||
};
|
};
|
||||||
|
|
||||||
const bool distPenalty = callback.battleHasDistancePenalty(info.attacker, attackerPos, defenderPos);
|
const bool distPenalty = callback.battleHasDistancePenalty(info.attacker, attackerPos, defenderPos);
|
||||||
@@ -386,7 +387,7 @@ double DamageCalculator::getDefensePetrificationFactor() const
|
|||||||
{
|
{
|
||||||
// Creatures that are petrified by a Basilisk's Petrifying attack or a Medusa's Stone gaze take 50% damage (R8 = 0.50) from ranged and melee attacks. Taking damage also deactivates the effect.
|
// Creatures that are petrified by a Basilisk's Petrifying attack or a Medusa's Stone gaze take 50% damage (R8 = 0.50) from ranged and melee attacks. Taking damage also deactivates the effect.
|
||||||
const std::string cachingStrAllReduction = "type_GENERAL_DAMAGE_REDUCTIONs_N1_srcSPELL_EFFECT";
|
const std::string cachingStrAllReduction = "type_GENERAL_DAMAGE_REDUCTIONs_N1_srcSPELL_EFFECT";
|
||||||
static const auto selectorAllReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, -1).And(Selector::sourceTypeSel(BonusSource::SPELL_EFFECT));
|
static const auto selectorAllReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, BonusSubtypes::damageTypeAll).And(Selector::sourceTypeSel(BonusSource::SPELL_EFFECT));
|
||||||
|
|
||||||
return info.defender->valOfBonuses(selectorAllReduction, cachingStrAllReduction) / 100.0;
|
return info.defender->valOfBonuses(selectorAllReduction, cachingStrAllReduction) / 100.0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,29 +134,6 @@ std::string Bonus::Description(std::optional<si32> customValue) const
|
|||||||
return str.str();
|
return str.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static JsonNode subtypeToJson(BonusType type, int subtype)
|
|
||||||
{
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case BonusType::PRIMARY_SKILL:
|
|
||||||
return JsonUtils::stringNode("primSkill." + NPrimarySkill::names[subtype]);
|
|
||||||
case BonusType::SPECIAL_SPELL_LEV:
|
|
||||||
case BonusType::SPECIFIC_SPELL_DAMAGE:
|
|
||||||
case BonusType::SPELL:
|
|
||||||
case BonusType::SPECIAL_PECULIAR_ENCHANT:
|
|
||||||
case BonusType::SPECIAL_ADD_VALUE_ENCHANT:
|
|
||||||
case BonusType::SPECIAL_FIXED_VALUE_ENCHANT:
|
|
||||||
return JsonUtils::stringNode(ModUtility::makeFullIdentifier("", "spell", SpellID::encode(subtype)));
|
|
||||||
case BonusType::IMPROVED_NECROMANCY:
|
|
||||||
case BonusType::SPECIAL_UPGRADE:
|
|
||||||
return JsonUtils::stringNode(ModUtility::makeFullIdentifier("", "creature", CreatureID::encode(subtype)));
|
|
||||||
case BonusType::GENERATE_RESOURCE:
|
|
||||||
return JsonUtils::stringNode("resource." + GameConstants::RESOURCE_NAMES[subtype]);
|
|
||||||
default:
|
|
||||||
return JsonUtils::intNode(subtype);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo)
|
static JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo)
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
@@ -173,8 +150,8 @@ JsonNode Bonus::toJsonNode() const
|
|||||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||||
// only add values that might reasonably be found in config files
|
// only add values that might reasonably be found in config files
|
||||||
root["type"].String() = vstd::findKey(bonusNameMap, type);
|
root["type"].String() = vstd::findKey(bonusNameMap, type);
|
||||||
if(subtype != -1)
|
if(subtype != TBonusSubtype::NONE)
|
||||||
root["subtype"] = subtypeToJson(type, subtype);
|
root["subtype"].String() = subtype.toString();
|
||||||
if(additionalInfo != CAddInfo::NONE)
|
if(additionalInfo != CAddInfo::NONE)
|
||||||
root["addInfo"] = additionalInfoToJson(type, additionalInfo);
|
root["addInfo"] = additionalInfoToJson(type, additionalInfo);
|
||||||
if(source != BonusSource::OTHER)
|
if(source != BonusSource::OTHER)
|
||||||
@@ -206,7 +183,7 @@ JsonNode Bonus::toJsonNode() const
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype):
|
Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, TBonusSubtype Subtype, std::string Desc):
|
||||||
duration(Duration),
|
duration(Duration),
|
||||||
type(Type),
|
type(Type),
|
||||||
subtype(Subtype),
|
subtype(Subtype),
|
||||||
@@ -219,7 +196,7 @@ Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32
|
|||||||
targetSourceType = BonusSource::OTHER;
|
targetSourceType = BonusSource::OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, BonusValueType ValType):
|
Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, TBonusSubtype Subtype, BonusValueType ValType):
|
||||||
duration(Duration),
|
duration(Duration),
|
||||||
type(Type),
|
type(Type),
|
||||||
subtype(Subtype),
|
subtype(Subtype),
|
||||||
@@ -247,7 +224,7 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
|
|||||||
|
|
||||||
#define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
|
#define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
|
||||||
printField(val);
|
printField(val);
|
||||||
printField(subtype);
|
out << "\tSubtype: " << bonus.subtype.toString() << "\n";
|
||||||
printField(duration.to_ulong());
|
printField(duration.to_ulong());
|
||||||
printField(source);
|
printField(source);
|
||||||
printField(sid);
|
printField(sid);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "BonusEnum.h"
|
#include "BonusEnum.h"
|
||||||
|
#include "../constants/EntityIdentifiers.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@@ -22,13 +23,48 @@ class IUpdater;
|
|||||||
class BonusList;
|
class BonusList;
|
||||||
class CSelector;
|
class CSelector;
|
||||||
|
|
||||||
using TBonusSubtype = int32_t;
|
using TBonusSubtype = MetaIdentifier;
|
||||||
using TBonusListPtr = std::shared_ptr<BonusList>;
|
using TBonusListPtr = std::shared_ptr<BonusList>;
|
||||||
using TConstBonusListPtr = std::shared_ptr<const BonusList>;
|
using TConstBonusListPtr = std::shared_ptr<const BonusList>;
|
||||||
using TLimiterPtr = std::shared_ptr<ILimiter>;
|
using TLimiterPtr = std::shared_ptr<ILimiter>;
|
||||||
using TPropagatorPtr = std::shared_ptr<IPropagator>;
|
using TPropagatorPtr = std::shared_ptr<IPropagator>;
|
||||||
using TUpdaterPtr = std::shared_ptr<IUpdater>;
|
using TUpdaterPtr = std::shared_ptr<IUpdater>;
|
||||||
|
|
||||||
|
namespace BonusSubtypes
|
||||||
|
{
|
||||||
|
|
||||||
|
static const TBonusSubtype creatureDamageBoth; // 0
|
||||||
|
static const TBonusSubtype creatureDamageMin; // 1
|
||||||
|
static const TBonusSubtype creatureDamageMax; // 2
|
||||||
|
|
||||||
|
static const TBonusSubtype damageTypeAll; // -1
|
||||||
|
static const TBonusSubtype damageTypeMelee; // 0
|
||||||
|
static const TBonusSubtype damageTypeRanged; // 1
|
||||||
|
|
||||||
|
static const TBonusSubtype heroMovementLand; // 1
|
||||||
|
static const TBonusSubtype heroMovementSea; // 0
|
||||||
|
|
||||||
|
static const TBonusSubtype heroMovementPenalty; // 2
|
||||||
|
static const TBonusSubtype heroMovementFull; // 1
|
||||||
|
|
||||||
|
static const TBonusSubtype deathStareGorgon; // 0
|
||||||
|
static const TBonusSubtype deathStareCommander;
|
||||||
|
|
||||||
|
static const TBonusSubtype rebirthRegular; // 0
|
||||||
|
static const TBonusSubtype rebirthSpecial; // 1
|
||||||
|
|
||||||
|
static const TBonusSubtype visionsMonsters; // 0
|
||||||
|
static const TBonusSubtype visionsHeroes; // 1
|
||||||
|
static const TBonusSubtype visionsTowns; // 2
|
||||||
|
|
||||||
|
static const TBonusSubtype immunityBattleWide; // 0
|
||||||
|
static const TBonusSubtype immunityEnemyHero; // 1
|
||||||
|
|
||||||
|
TBonusSubtype spellLevel(int level);
|
||||||
|
TBonusSubtype creatureLevel(int level);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class DLL_LINKAGE CAddInfo : public std::vector<si32>
|
class DLL_LINKAGE CAddInfo : public std::vector<si32>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -56,7 +92,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
|||||||
si16 turnsRemain = 0; //used if duration is N_TURNS, N_DAYS or ONE_WEEK
|
si16 turnsRemain = 0; //used if duration is N_TURNS, N_DAYS or ONE_WEEK
|
||||||
|
|
||||||
BonusType type = BonusType::NONE; //uses BonusType values - says to what is this bonus - 1 byte
|
BonusType type = BonusType::NONE; //uses BonusType values - says to what is this bonus - 1 byte
|
||||||
TBonusSubtype subtype = -1; //-1 if not applicable - 4 bytes
|
TBonusSubtype subtype;
|
||||||
|
|
||||||
BonusSource source = BonusSource::OTHER; //source type" uses BonusSource values - what gave that bonus
|
BonusSource source = BonusSource::OTHER; //source type" uses BonusSource values - what gave that bonus
|
||||||
BonusSource targetSourceType;//Bonuses of what origin this amplifies, uses BonusSource values. Needed for PERCENT_TO_TARGET_TYPE.
|
BonusSource targetSourceType;//Bonuses of what origin this amplifies, uses BonusSource values. Needed for PERCENT_TO_TARGET_TYPE.
|
||||||
@@ -75,8 +111,11 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
|||||||
|
|
||||||
std::string description;
|
std::string description;
|
||||||
|
|
||||||
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1);
|
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 sourceID);
|
||||||
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype=-1, BonusValueType ValType = BonusValueType::ADDITIVE_VALUE);
|
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 sourceID, std::string Desc);
|
||||||
|
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 sourceID, TBonusSubtype subtype);
|
||||||
|
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 sourceID, TBonusSubtype subtype, std::string Desc);
|
||||||
|
Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 sourceID, TBonusSubtype subtype, BonusValueType ValType);
|
||||||
Bonus() = default;
|
Bonus() = default;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
|
|||||||
@@ -81,76 +81,76 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
|
|||||||
else if(deprecatedSubtype == SecondarySkill::SORCERY || deprecatedSubtypeStr == "skill.sorcery")
|
else if(deprecatedSubtype == SecondarySkill::SORCERY || deprecatedSubtypeStr == "skill.sorcery")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELL_DAMAGE;
|
type = BonusType::SPELL_DAMAGE;
|
||||||
subtype = SpellSchool(ESpellSchool::ANY);
|
subtype = TBonusSubtype(ESpellSchool::ANY);
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::SCHOLAR || deprecatedSubtypeStr == "skill.scholar")
|
else if(deprecatedSubtype == SecondarySkill::SCHOLAR || deprecatedSubtypeStr == "skill.scholar")
|
||||||
type = BonusType::LEARN_MEETING_SPELL_LIMIT;
|
type = BonusType::LEARN_MEETING_SPELL_LIMIT;
|
||||||
else if(deprecatedSubtype == SecondarySkill::ARCHERY|| deprecatedSubtypeStr == "skill.archery")
|
else if(deprecatedSubtype == SecondarySkill::ARCHERY|| deprecatedSubtypeStr == "skill.archery")
|
||||||
{
|
{
|
||||||
subtype = 1;
|
subtype = BonusSubtypes::damageTypeRanged;
|
||||||
type = BonusType::PERCENTAGE_DAMAGE_BOOST;
|
type = BonusType::PERCENTAGE_DAMAGE_BOOST;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::OFFENCE || deprecatedSubtypeStr == "skill.offence")
|
else if(deprecatedSubtype == SecondarySkill::OFFENCE || deprecatedSubtypeStr == "skill.offence")
|
||||||
{
|
{
|
||||||
subtype = 0;
|
subtype = BonusSubtypes::damageTypeMelee;
|
||||||
type = BonusType::PERCENTAGE_DAMAGE_BOOST;
|
type = BonusType::PERCENTAGE_DAMAGE_BOOST;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::ARMORER || deprecatedSubtypeStr == "skill.armorer")
|
else if(deprecatedSubtype == SecondarySkill::ARMORER || deprecatedSubtypeStr == "skill.armorer")
|
||||||
{
|
{
|
||||||
subtype = -1;
|
subtype = BonusSubtypes::damageTypeAll;
|
||||||
type = BonusType::GENERAL_DAMAGE_REDUCTION;
|
type = BonusType::GENERAL_DAMAGE_REDUCTION;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::NAVIGATION || deprecatedSubtypeStr == "skill.navigation")
|
else if(deprecatedSubtype == SecondarySkill::NAVIGATION || deprecatedSubtypeStr == "skill.navigation")
|
||||||
{
|
{
|
||||||
subtype = 0;
|
subtype = BonusSubtypes::heroMovementSea;
|
||||||
valueType = BonusValueType::PERCENT_TO_BASE;
|
valueType = BonusValueType::PERCENT_TO_BASE;
|
||||||
type = BonusType::MOVEMENT;
|
type = BonusType::MOVEMENT;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::LOGISTICS || deprecatedSubtypeStr == "skill.logistics")
|
else if(deprecatedSubtype == SecondarySkill::LOGISTICS || deprecatedSubtypeStr == "skill.logistics")
|
||||||
{
|
{
|
||||||
subtype = 1;
|
subtype = BonusSubtypes::heroMovementLand;
|
||||||
valueType = BonusValueType::PERCENT_TO_BASE;
|
valueType = BonusValueType::PERCENT_TO_BASE;
|
||||||
type = BonusType::MOVEMENT;
|
type = BonusType::MOVEMENT;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::ESTATES || deprecatedSubtypeStr == "skill.estates")
|
else if(deprecatedSubtype == SecondarySkill::ESTATES || deprecatedSubtypeStr == "skill.estates")
|
||||||
{
|
{
|
||||||
type = BonusType::GENERATE_RESOURCE;
|
type = BonusType::GENERATE_RESOURCE;
|
||||||
subtype = GameResID(EGameResID::GOLD);
|
subtype = TBonusSubtype(GameResID(EGameResID::GOLD));
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::AIR_MAGIC || deprecatedSubtypeStr == "skill.airMagic")
|
else if(deprecatedSubtype == SecondarySkill::AIR_MAGIC || deprecatedSubtypeStr == "skill.airMagic")
|
||||||
{
|
{
|
||||||
type = BonusType::MAGIC_SCHOOL_SKILL;
|
type = BonusType::MAGIC_SCHOOL_SKILL;
|
||||||
subtype = SpellSchool(ESpellSchool::AIR);
|
subtype = TBonusSubtype(ESpellSchool::AIR);
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::WATER_MAGIC || deprecatedSubtypeStr == "skill.waterMagic")
|
else if(deprecatedSubtype == SecondarySkill::WATER_MAGIC || deprecatedSubtypeStr == "skill.waterMagic")
|
||||||
{
|
{
|
||||||
type = BonusType::MAGIC_SCHOOL_SKILL;
|
type = BonusType::MAGIC_SCHOOL_SKILL;
|
||||||
subtype = SpellSchool(ESpellSchool::WATER);
|
subtype = TBonusSubtype(ESpellSchool::WATER);
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::FIRE_MAGIC || deprecatedSubtypeStr == "skill.fireMagic")
|
else if(deprecatedSubtype == SecondarySkill::FIRE_MAGIC || deprecatedSubtypeStr == "skill.fireMagic")
|
||||||
{
|
{
|
||||||
type = BonusType::MAGIC_SCHOOL_SKILL;
|
type = BonusType::MAGIC_SCHOOL_SKILL;
|
||||||
subtype = SpellSchool(ESpellSchool::FIRE);
|
subtype = TBonusSubtype(ESpellSchool::FIRE);
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::EARTH_MAGIC || deprecatedSubtypeStr == "skill.earthMagic")
|
else if(deprecatedSubtype == SecondarySkill::EARTH_MAGIC || deprecatedSubtypeStr == "skill.earthMagic")
|
||||||
{
|
{
|
||||||
type = BonusType::MAGIC_SCHOOL_SKILL;
|
type = BonusType::MAGIC_SCHOOL_SKILL;
|
||||||
subtype = SpellSchool(ESpellSchool::EARTH);
|
subtype = TBonusSubtype(ESpellSchool::EARTH);
|
||||||
}
|
}
|
||||||
else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
|
else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
|
||||||
{
|
{
|
||||||
type = BonusType::BONUS_DAMAGE_CHANCE;
|
type = BonusType::BONUS_DAMAGE_CHANCE;
|
||||||
subtypeStr = "core:creature.ballista";
|
subtype = TBonusSubtype(CreatureID(CreatureID::BALLISTA));
|
||||||
}
|
}
|
||||||
else if (deprecatedSubtype == SecondarySkill::FIRST_AID || deprecatedSubtypeStr == "skill.firstAid")
|
else if (deprecatedSubtype == SecondarySkill::FIRST_AID || deprecatedSubtypeStr == "skill.firstAid")
|
||||||
{
|
{
|
||||||
type = BonusType::SPECIFIC_SPELL_POWER;
|
type = BonusType::SPECIFIC_SPELL_POWER;
|
||||||
subtypeStr = "core:spell.firstAid";
|
subtype = TBonusSubtype("spell", "firstAid");
|
||||||
}
|
}
|
||||||
else if (deprecatedSubtype == SecondarySkill::BALLISTICS || deprecatedSubtypeStr == "skill.ballistics")
|
else if (deprecatedSubtype == SecondarySkill::BALLISTICS || deprecatedSubtypeStr == "skill.ballistics")
|
||||||
{
|
{
|
||||||
type = BonusType::CATAPULT_EXTRA_SHOTS;
|
type = BonusType::CATAPULT_EXTRA_SHOTS;
|
||||||
subtypeStr = "core:spell.catapultShot";
|
subtype = TBonusSubtype("spell", "catapultShot");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
isConverted = false;
|
isConverted = false;
|
||||||
@@ -162,27 +162,27 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
|
|||||||
else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
|
else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
|
||||||
{
|
{
|
||||||
type = BonusType::HERO_GRANTS_ATTACKS;
|
type = BonusType::HERO_GRANTS_ATTACKS;
|
||||||
subtypeStr = "core:creature.ballista";
|
subtype = TBonusSubtype(CreatureID(CreatureID::BALLISTA));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
isConverted = false;
|
isConverted = false;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "SEA_MOVEMENT")
|
else if (deprecatedTypeStr == "SEA_MOVEMENT")
|
||||||
{
|
{
|
||||||
subtype = 0;
|
subtype = BonusSubtypes::heroMovementSea;
|
||||||
valueType = BonusValueType::ADDITIVE_VALUE;
|
valueType = BonusValueType::ADDITIVE_VALUE;
|
||||||
type = BonusType::MOVEMENT;
|
type = BonusType::MOVEMENT;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "LAND_MOVEMENT")
|
else if (deprecatedTypeStr == "LAND_MOVEMENT")
|
||||||
{
|
{
|
||||||
subtype = 1;
|
subtype = BonusSubtypes::heroMovementLand;
|
||||||
valueType = BonusValueType::ADDITIVE_VALUE;
|
valueType = BonusValueType::ADDITIVE_VALUE;
|
||||||
type = BonusType::MOVEMENT;
|
type = BonusType::MOVEMENT;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "MAXED_SPELL")
|
else if (deprecatedTypeStr == "MAXED_SPELL")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELL;
|
type = BonusType::SPELL;
|
||||||
subtypeStr = deprecatedSubtypeStr;
|
subtype = TBonusSubtype("spell", deprecatedSubtypeStr);
|
||||||
valueType = BonusValueType::INDEPENDENT_MAX;
|
valueType = BonusValueType::INDEPENDENT_MAX;
|
||||||
val = 3;
|
val = 3;
|
||||||
}
|
}
|
||||||
@@ -223,52 +223,52 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
|
|||||||
else if (deprecatedTypeStr == "DIRECT_DAMAGE_IMMUNITY")
|
else if (deprecatedTypeStr == "DIRECT_DAMAGE_IMMUNITY")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELL_DAMAGE_REDUCTION;
|
type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||||
subtype = SpellSchool(ESpellSchool::ANY);
|
subtype = MetaIdentifier(SpellSchool::ANY);
|
||||||
val = 100;
|
val = 100;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "AIR_SPELL_DMG_PREMY")
|
else if (deprecatedTypeStr == "AIR_SPELL_DMG_PREMY")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELL_DAMAGE;
|
type = BonusType::SPELL_DAMAGE;
|
||||||
subtype = SpellSchool(ESpellSchool::AIR);
|
subtype = MetaIdentifier(SpellSchool::AIR);
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "FIRE_SPELL_DMG_PREMY")
|
else if (deprecatedTypeStr == "FIRE_SPELL_DMG_PREMY")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELL_DAMAGE;
|
type = BonusType::SPELL_DAMAGE;
|
||||||
subtype = SpellSchool(ESpellSchool::FIRE);
|
subtype = MetaIdentifier(SpellSchool::FIRE);
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "WATER_SPELL_DMG_PREMY")
|
else if (deprecatedTypeStr == "WATER_SPELL_DMG_PREMY")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELL_DAMAGE;
|
type = BonusType::SPELL_DAMAGE;
|
||||||
subtype = SpellSchool(ESpellSchool::WATER);
|
subtype = MetaIdentifier(SpellSchool::WATER);
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "EARTH_SPELL_DMG_PREMY")
|
else if (deprecatedTypeStr == "EARTH_SPELL_DMG_PREMY")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELL_DAMAGE;
|
type = BonusType::SPELL_DAMAGE;
|
||||||
subtype = SpellSchool(ESpellSchool::EARTH);
|
subtype = MetaIdentifier(SpellSchool::EARTH);
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "AIR_SPELLS")
|
else if (deprecatedTypeStr == "AIR_SPELLS")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELLS_OF_SCHOOL;
|
type = BonusType::SPELLS_OF_SCHOOL;
|
||||||
subtype = SpellSchool(ESpellSchool::AIR);
|
subtype = MetaIdentifier(SpellSchool::AIR);
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "FIRE_SPELLS")
|
else if (deprecatedTypeStr == "FIRE_SPELLS")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELLS_OF_SCHOOL;
|
type = BonusType::SPELLS_OF_SCHOOL;
|
||||||
subtype = SpellSchool(ESpellSchool::FIRE);
|
subtype = MetaIdentifier(SpellSchool::FIRE);
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "WATER_SPELLS")
|
else if (deprecatedTypeStr == "WATER_SPELLS")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELLS_OF_SCHOOL;
|
type = BonusType::SPELLS_OF_SCHOOL;
|
||||||
subtype = SpellSchool(ESpellSchool::WATER);
|
subtype = MetaIdentifier(SpellSchool::WATER);
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "EARTH_SPELLS")
|
else if (deprecatedTypeStr == "EARTH_SPELLS")
|
||||||
{
|
{
|
||||||
type = BonusType::SPELLS_OF_SCHOOL;
|
type = BonusType::SPELLS_OF_SCHOOL;
|
||||||
subtype = SpellSchool(ESpellSchool::EARTH);
|
subtype = MetaIdentifier(SpellSchool::EARTH);
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "AIR_IMMUNITY")
|
else if (deprecatedTypeStr == "AIR_IMMUNITY")
|
||||||
{
|
{
|
||||||
subtype = SpellSchool(ESpellSchool::AIR);
|
subtype = MetaIdentifier(SpellSchool::AIR);
|
||||||
switch(deprecatedSubtype)
|
switch(deprecatedSubtype)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@@ -284,7 +284,7 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
|
|||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "FIRE_IMMUNITY")
|
else if (deprecatedTypeStr == "FIRE_IMMUNITY")
|
||||||
{
|
{
|
||||||
subtype = SpellSchool(ESpellSchool::FIRE);
|
subtype = MetaIdentifier(SpellSchool::FIRE);
|
||||||
switch(deprecatedSubtype)
|
switch(deprecatedSubtype)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@@ -300,7 +300,7 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
|
|||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "WATER_IMMUNITY")
|
else if (deprecatedTypeStr == "WATER_IMMUNITY")
|
||||||
{
|
{
|
||||||
subtype = SpellSchool(ESpellSchool::WATER);
|
subtype = MetaIdentifier(SpellSchool::WATER);
|
||||||
switch(deprecatedSubtype)
|
switch(deprecatedSubtype)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@@ -316,7 +316,7 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
|
|||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "EARTH_IMMUNITY")
|
else if (deprecatedTypeStr == "EARTH_IMMUNITY")
|
||||||
{
|
{
|
||||||
subtype = SpellSchool(ESpellSchool::EARTH);
|
subtype = MetaIdentifier(SpellSchool::EARTH);
|
||||||
switch(deprecatedSubtype)
|
switch(deprecatedSubtype)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@@ -340,10 +340,8 @@ const JsonNode & BonusParams::toJson()
|
|||||||
if(ret.isNull())
|
if(ret.isNull())
|
||||||
{
|
{
|
||||||
ret["type"].String() = vstd::findKey(bonusNameMap, type);
|
ret["type"].String() = vstd::findKey(bonusNameMap, type);
|
||||||
if(subtypeStr)
|
if(subtype)
|
||||||
ret["subtype"].String() = *subtypeStr;
|
ret["subtype"].String() = subtype->toString();
|
||||||
else if(subtype)
|
|
||||||
ret["subtype"].Integer() = *subtype;
|
|
||||||
if(valueType)
|
if(valueType)
|
||||||
ret["valueType"].String() = vstd::findKey(bonusValueMap, *valueType);
|
ret["valueType"].String() = vstd::findKey(bonusValueMap, *valueType);
|
||||||
if(val)
|
if(val)
|
||||||
@@ -358,11 +356,6 @@ const JsonNode & BonusParams::toJson()
|
|||||||
CSelector BonusParams::toSelector()
|
CSelector BonusParams::toSelector()
|
||||||
{
|
{
|
||||||
assert(isConverted);
|
assert(isConverted);
|
||||||
if(subtypeStr)
|
|
||||||
{
|
|
||||||
subtype = -1;
|
|
||||||
JsonUtils::resolveIdentifier(*subtype, toJson(), "subtype");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ret = Selector::type()(type);
|
auto ret = Selector::type()(type);
|
||||||
if(subtype)
|
if(subtype)
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ struct DLL_LINKAGE BonusParams {
|
|||||||
bool isConverted;
|
bool isConverted;
|
||||||
BonusType type = BonusType::NONE;
|
BonusType type = BonusType::NONE;
|
||||||
std::optional<TBonusSubtype> subtype = std::nullopt;
|
std::optional<TBonusSubtype> subtype = std::nullopt;
|
||||||
std::optional<std::string> subtypeStr = std::nullopt;
|
|
||||||
std::optional<BonusValueType> valueType = std::nullopt;
|
std::optional<BonusValueType> valueType = std::nullopt;
|
||||||
std::optional<si32> val = std::nullopt;
|
std::optional<si32> val = std::nullopt;
|
||||||
std::optional<BonusSource> targetType = std::nullopt;
|
std::optional<BonusSource> targetType = std::nullopt;
|
||||||
|
|||||||
@@ -62,20 +62,20 @@ bool IBonusBearer::hasBonusOfType(BonusType type) const
|
|||||||
return hasBonus(s, cachingStr);
|
return hasBonus(s, cachingStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int IBonusBearer::valOfBonuses(BonusType type, int subtype) const
|
int IBonusBearer::valOfBonuses(BonusType type, TBonusSubtype subtype) const
|
||||||
{
|
{
|
||||||
//This part is performance-critical
|
//This part is performance-critical
|
||||||
std::string cachingStr = "type_" + std::to_string(static_cast<int>(type)) + "_" + std::to_string(subtype);
|
std::string cachingStr = "type_" + std::to_string(static_cast<int>(type)) + "_" + subtype.toString();
|
||||||
|
|
||||||
CSelector s = Selector::typeSubtype(type, subtype);
|
CSelector s = Selector::typeSubtype(type, subtype);
|
||||||
|
|
||||||
return valOfBonuses(s, cachingStr);
|
return valOfBonuses(s, cachingStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IBonusBearer::hasBonusOfType(BonusType type, int subtype) const
|
bool IBonusBearer::hasBonusOfType(BonusType type, TBonusSubtype subtype) const
|
||||||
{
|
{
|
||||||
//This part is performance-critical
|
//This part is performance-critical
|
||||||
std::string cachingStr = "type_" + std::to_string(static_cast<int>(type)) + "_" + std::to_string(subtype);
|
std::string cachingStr = "type_" + std::to_string(static_cast<int>(type)) + "_" + subtype.toString();
|
||||||
|
|
||||||
CSelector s = Selector::typeSubtype(type, subtype);
|
CSelector s = Selector::typeSubtype(type, subtype);
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ public:
|
|||||||
//Optimized interface (with auto-caching)
|
//Optimized interface (with auto-caching)
|
||||||
int valOfBonuses(BonusType type) const; //subtype -> subtype of bonus;
|
int valOfBonuses(BonusType type) const; //subtype -> subtype of bonus;
|
||||||
bool hasBonusOfType(BonusType type) const;//determines if hero has a bonus of given type (and optionally subtype)
|
bool hasBonusOfType(BonusType type) const;//determines if hero has a bonus of given type (and optionally subtype)
|
||||||
int valOfBonuses(BonusType type, int subtype) const; //subtype -> subtype of bonus;
|
int valOfBonuses(BonusType type, TBonusSubtype subtype) const; //subtype -> subtype of bonus;
|
||||||
bool hasBonusOfType(BonusType type, int subtype) const;//determines if hero has a bonus of given type (and optionally subtype)
|
bool hasBonusOfType(BonusType type, TBonusSubtype subtype) const;//determines if hero has a bonus of given type (and optionally subtype)
|
||||||
bool hasBonusFrom(BonusSource source, ui32 sourceID) const;
|
bool hasBonusFrom(BonusSource source, ui32 sourceID) const;
|
||||||
|
|
||||||
virtual int64_t getTreeVersion() const = 0;
|
virtual int64_t getTreeVersion() const = 0;
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ JsonNode CCreatureTypeLimiter::toJsonNode() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter( BonusType bonus )
|
HasAnotherBonusLimiter::HasAnotherBonusLimiter( BonusType bonus )
|
||||||
: type(bonus), subtype(0), isSubtypeRelevant(false), isSourceRelevant(false), isSourceIDRelevant(false)
|
: type(bonus), isSubtypeRelevant(false), isSourceRelevant(false), isSourceIDRelevant(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,8 +184,8 @@ std::string HasAnotherBonusLimiter::toString() const
|
|||||||
std::string typeName = vstd::findKey(bonusNameMap, type);
|
std::string typeName = vstd::findKey(bonusNameMap, type);
|
||||||
if(isSubtypeRelevant)
|
if(isSubtypeRelevant)
|
||||||
{
|
{
|
||||||
boost::format fmt("HasAnotherBonusLimiter(type=%s, subtype=%d)");
|
boost::format fmt("HasAnotherBonusLimiter(type=%s, subtype=%s)");
|
||||||
fmt % typeName % subtype;
|
fmt % typeName % subtype.toString();
|
||||||
return fmt.str();
|
return fmt.str();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -205,7 +205,7 @@ JsonNode HasAnotherBonusLimiter::toJsonNode() const
|
|||||||
root["type"].String() = "HAS_ANOTHER_BONUS_LIMITER";
|
root["type"].String() = "HAS_ANOTHER_BONUS_LIMITER";
|
||||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(typeName));
|
root["parameters"].Vector().push_back(JsonUtils::stringNode(typeName));
|
||||||
if(isSubtypeRelevant)
|
if(isSubtypeRelevant)
|
||||||
root["parameters"].Vector().push_back(JsonUtils::intNode(subtype));
|
root["parameters"].Vector().push_back(JsonUtils::stringNode(subtype.toString()));
|
||||||
if(isSourceRelevant)
|
if(isSourceRelevant)
|
||||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(sourceTypeName));
|
root["parameters"].Vector().push_back(JsonUtils::stringNode(sourceTypeName));
|
||||||
|
|
||||||
|
|||||||
@@ -349,6 +349,27 @@ public:
|
|||||||
static std::string entityType();
|
static std::string entityType();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DLL_LINKAGE PrimarySkill : public Identifier<PrimarySkill>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Identifier<PrimarySkill>::Identifier;
|
||||||
|
|
||||||
|
static const PrimarySkill NONE;
|
||||||
|
static const PrimarySkill ATTACK;
|
||||||
|
static const PrimarySkill DEFENSE;
|
||||||
|
static const PrimarySkill SPELL_POWER;
|
||||||
|
static const PrimarySkill KNOWLEDGE;
|
||||||
|
|
||||||
|
static const PrimarySkill BEGIN;
|
||||||
|
static const PrimarySkill END;
|
||||||
|
|
||||||
|
static const PrimarySkill EXPERIENCE;
|
||||||
|
|
||||||
|
static si32 decode(const std::string& identifier);
|
||||||
|
static std::string encode(const si32 index);
|
||||||
|
static std::string entityType();
|
||||||
|
};
|
||||||
|
|
||||||
class DLL_LINKAGE FactionID : public Identifier<FactionID>
|
class DLL_LINKAGE FactionID : public Identifier<FactionID>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -919,6 +940,10 @@ public:
|
|||||||
static const SpellSchool FIRE;
|
static const SpellSchool FIRE;
|
||||||
static const SpellSchool WATER;
|
static const SpellSchool WATER;
|
||||||
static const SpellSchool EARTH;
|
static const SpellSchool EARTH;
|
||||||
|
|
||||||
|
DLL_LINKAGE static si32 decode(const std::string & identifier);
|
||||||
|
DLL_LINKAGE static std::string encode(const si32 index);
|
||||||
|
static std::string entityType();
|
||||||
};
|
};
|
||||||
|
|
||||||
class GameResIDBase : public IdentifierBase
|
class GameResIDBase : public IdentifierBase
|
||||||
@@ -946,6 +971,8 @@ class GameResID : public IdentifierWithEnum<GameResID, GameResIDBase>
|
|||||||
public:
|
public:
|
||||||
using IdentifierWithEnum<GameResID, GameResIDBase>::IdentifierWithEnum;
|
using IdentifierWithEnum<GameResID, GameResIDBase>::IdentifierWithEnum;
|
||||||
|
|
||||||
|
DLL_LINKAGE static si32 decode(const std::string & identifier);
|
||||||
|
DLL_LINKAGE static std::string encode(const si32 index);
|
||||||
static std::string entityType();
|
static std::string entityType();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -958,4 +985,85 @@ using River = RiverId;
|
|||||||
using Road = RoadId;
|
using Road = RoadId;
|
||||||
using ETerrainId = TerrainId;
|
using ETerrainId = TerrainId;
|
||||||
|
|
||||||
|
/// This class represents field that may contain value of multiple different identifer types
|
||||||
|
class MetaIdentifier
|
||||||
|
{
|
||||||
|
std::string entityType;
|
||||||
|
std::string stringForm;
|
||||||
|
int32_t integerForm;
|
||||||
|
|
||||||
|
void onDeserialized();
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const MetaIdentifier NONE;
|
||||||
|
|
||||||
|
MetaIdentifier():
|
||||||
|
integerForm(-1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit MetaIdentifier(const std::string & entityType, const std::string & identifier)
|
||||||
|
: entityType(entityType)
|
||||||
|
, stringForm(identifier)
|
||||||
|
, integerForm(-1)
|
||||||
|
{
|
||||||
|
onDeserialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit MetaIdentifier(const std::string & entityType, const std::string & identifier, int32_t value)
|
||||||
|
: entityType(entityType)
|
||||||
|
, stringForm(identifier)
|
||||||
|
, integerForm(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename IdentifierType>
|
||||||
|
explicit MetaIdentifier(const IdentifierType & identifier )
|
||||||
|
: entityType(IdentifierType::entityType())
|
||||||
|
, integerForm(identifier.getNum())
|
||||||
|
, stringForm(IdentifierType::encode(identifier.getNum()))
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<IdentifierBase, IdentifierType>::value, "MetaIdentifier can only be constructed from Identifer class");
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t getNum() const
|
||||||
|
{
|
||||||
|
return integerForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string toString() const
|
||||||
|
{
|
||||||
|
return stringForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename IdentifierType>
|
||||||
|
IdentifierType as() const
|
||||||
|
{
|
||||||
|
IdentifierType result(integerForm);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
|
{
|
||||||
|
h & stringForm;
|
||||||
|
|
||||||
|
if (!h.saving)
|
||||||
|
onDeserialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator == (const MetaIdentifier & other) const
|
||||||
|
{
|
||||||
|
assert( (stringForm == other.stringForm) ? (integerForm == other.integerForm) : true );
|
||||||
|
|
||||||
|
return stringForm == other.stringForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator != (const MetaIdentifier & other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator < (const MetaIdentifier & other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|||||||
@@ -11,16 +11,6 @@
|
|||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
enum class PrimarySkill : int8_t
|
|
||||||
{
|
|
||||||
NONE = -1,
|
|
||||||
ATTACK,
|
|
||||||
DEFENSE,
|
|
||||||
SPELL_POWER,
|
|
||||||
KNOWLEDGE,
|
|
||||||
EXPERIENCE = 4 //for some reason changePrimSkill uses it
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class EAlignment : int8_t
|
enum class EAlignment : int8_t
|
||||||
{
|
{
|
||||||
GOOD,
|
GOOD,
|
||||||
@@ -143,9 +133,9 @@ enum class ETeleportChannelType : int8_t
|
|||||||
MIXED
|
MIXED
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace SecSkillLevel
|
namespace MasteryLevel
|
||||||
{
|
{
|
||||||
enum SecSkillLevel
|
enum Type
|
||||||
{
|
{
|
||||||
NONE,
|
NONE,
|
||||||
BASIC,
|
BASIC,
|
||||||
|
|||||||
@@ -1871,7 +1871,7 @@ struct statsHLP
|
|||||||
//Heroes can produce gold as well - skill, specialty or arts
|
//Heroes can produce gold as well - skill, specialty or arts
|
||||||
for(const auto & h : ps->heroes)
|
for(const auto & h : ps->heroes)
|
||||||
{
|
{
|
||||||
totalIncome += h->valOfBonuses(Selector::typeSubtype(BonusType::GENERATE_RESOURCE, GameResID(EGameResID::GOLD)));
|
totalIncome += h->valOfBonuses(Selector::typeSubtype(BonusType::GENERATE_RESOURCE, TBonusSubtype(GameResID(GameResID::GOLD))));
|
||||||
|
|
||||||
if(!heroOrTown)
|
if(!heroOrTown)
|
||||||
heroOrTown = h;
|
heroOrTown = h;
|
||||||
|
|||||||
@@ -84,10 +84,10 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(std::vector<CampaignHeroR
|
|||||||
//trimming prim skills
|
//trimming prim skills
|
||||||
for(CGHeroInstance * cgh : crossoverHeroes)
|
for(CGHeroInstance * cgh : crossoverHeroes)
|
||||||
{
|
{
|
||||||
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
|
for(auto g = PrimarySkill::BEGIN; g < PrimarySkill::END; ++g)
|
||||||
{
|
{
|
||||||
auto sel = Selector::type()(BonusType::PRIMARY_SKILL)
|
auto sel = Selector::type()(BonusType::PRIMARY_SKILL)
|
||||||
.And(Selector::subtype()(g))
|
.And(Selector::subtype()(TBonusSubtype(g)))
|
||||||
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL));
|
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL));
|
||||||
|
|
||||||
cgh->getBonusLocalFirst(sel)->val = cgh->type->heroClass->primarySkillInitial[g];
|
cgh->getBonusLocalFirst(sel)->val = cgh->type->heroClass->primarySkillInitial[g];
|
||||||
@@ -118,7 +118,7 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(std::vector<CampaignHeroR
|
|||||||
//trimming artifacts
|
//trimming artifacts
|
||||||
for(CGHeroInstance * hero : crossoverHeroes)
|
for(CGHeroInstance * hero : crossoverHeroes)
|
||||||
{
|
{
|
||||||
auto const & checkAndRemoveArtifact = [&](const ArtifactPosition & artifactPosition )
|
const auto & checkAndRemoveArtifact = [&](const ArtifactPosition & artifactPosition)
|
||||||
{
|
{
|
||||||
if(artifactPosition == ArtifactPosition::SPELLBOOK)
|
if(artifactPosition == ArtifactPosition::SPELLBOOK)
|
||||||
return; // do not handle spellbook this way
|
return; // do not handle spellbook this way
|
||||||
@@ -141,7 +141,7 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(std::vector<CampaignHeroR
|
|||||||
|
|
||||||
// process on copy - removal of artifact will invalidate container
|
// process on copy - removal of artifact will invalidate container
|
||||||
auto artifactsWorn = hero->artifactsWorn;
|
auto artifactsWorn = hero->artifactsWorn;
|
||||||
for (auto const & art : artifactsWorn)
|
for(const auto & art : artifactsWorn)
|
||||||
checkAndRemoveArtifact(art.first);
|
checkAndRemoveArtifact(art.first);
|
||||||
|
|
||||||
// process in reverse - removal of artifact will shift all artifacts after this one
|
// process in reverse - removal of artifact will shift all artifacts after this one
|
||||||
@@ -308,16 +308,14 @@ void CGameStateCampaign::giveCampaignBonusToHero(CGHeroInstance * hero)
|
|||||||
case CampaignBonusType::PRIMARY_SKILL:
|
case CampaignBonusType::PRIMARY_SKILL:
|
||||||
{
|
{
|
||||||
const ui8 * ptr = reinterpret_cast<const ui8 *>(&curBonus->info2);
|
const ui8 * ptr = reinterpret_cast<const ui8 *>(&curBonus->info2);
|
||||||
for(int g = 0; g < GameConstants::PRIMARY_SKILLS; ++g)
|
for(auto g = PrimarySkill::BEGIN; g < PrimarySkill::END; ++g)
|
||||||
{
|
{
|
||||||
int val = ptr[g];
|
int val = ptr[g.getNum()];
|
||||||
if(val == 0)
|
if(val == 0)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
auto bb = std::make_shared<Bonus>(
|
int currentScenario = static_cast<int>(*gameState->scenarioOps->campState->currentScenario());
|
||||||
BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CAMPAIGN_BONUS, val, static_cast<int>(*gameState->scenarioOps->campState->currentScenario()), g
|
auto bb = std::make_shared<Bonus>( BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CAMPAIGN_BONUS, val, currentScenario, TBonusSubtype(g) );
|
||||||
);
|
|
||||||
hero->addNewBonus(bb);
|
hero->addNewBonus(bb);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -386,9 +384,9 @@ std::vector<CampaignHeroReplacement> CGameStateCampaign::generateCampaignHeroesT
|
|||||||
}
|
}
|
||||||
|
|
||||||
//selecting heroes by type
|
//selecting heroes by type
|
||||||
for (auto const * placeholder : placeholdersByType)
|
for(const auto * placeholder : placeholdersByType)
|
||||||
{
|
{
|
||||||
auto const & node = campaignState->getHeroByType(*placeholder->heroType);
|
const auto & node = campaignState->getHeroByType(*placeholder->heroType);
|
||||||
if (node.isNull())
|
if (node.isNull())
|
||||||
{
|
{
|
||||||
logGlobal->info("Hero crossover: Unable to replace placeholder for %d (%s)!", placeholder->heroType->getNum(), VLC->heroTypes()->getById(*placeholder->heroType)->getNameTranslated());
|
logGlobal->info("Hero crossover: Unable to replace placeholder for %d (%s)!", placeholder->heroType->getNum(), VLC->heroTypes()->getById(*placeholder->heroType)->getNameTranslated());
|
||||||
@@ -412,10 +410,10 @@ std::vector<CampaignHeroReplacement> CGameStateCampaign::generateCampaignHeroesT
|
|||||||
return *a->powerRank > *b->powerRank;
|
return *a->powerRank > *b->powerRank;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto const & nodeList = campaignState->getHeroesByPower(lastScenario.value());
|
const auto & nodeList = campaignState->getHeroesByPower(lastScenario.value());
|
||||||
auto nodeListIter = nodeList.begin();
|
auto nodeListIter = nodeList.begin();
|
||||||
|
|
||||||
for (auto const * placeholder : placeholdersByPower)
|
for(const auto * placeholder : placeholdersByPower)
|
||||||
{
|
{
|
||||||
if (nodeListIter == nodeList.end())
|
if (nodeListIter == nodeList.end())
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ std::string CGCreature::getHoverText(PlayerColor player) const
|
|||||||
std::string CGCreature::getHoverText(const CGHeroInstance * hero) const
|
std::string CGCreature::getHoverText(const CGHeroInstance * hero) const
|
||||||
{
|
{
|
||||||
std::string hoverName;
|
std::string hoverName;
|
||||||
if(hero->hasVisions(this, 0))
|
if(hero->hasVisions(this, BonusSubtypes::visionsMonsters))
|
||||||
{
|
{
|
||||||
MetaString ms;
|
MetaString ms;
|
||||||
ms.appendNumber(stacks.begin()->second->count);
|
ms.appendNumber(stacks.begin()->second->count);
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ ui32 CGHeroInstance::getTileMovementCost(const TerrainTile & dest, const Terrain
|
|||||||
}
|
}
|
||||||
else if(ti->nativeTerrain != from.terType->getId() &&//the terrain is not native
|
else if(ti->nativeTerrain != from.terType->getId() &&//the terrain is not native
|
||||||
ti->nativeTerrain != ETerrainId::ANY_TERRAIN && //no special creature bonus
|
ti->nativeTerrain != ETerrainId::ANY_TERRAIN && //no special creature bonus
|
||||||
!ti->hasBonusOfType(BonusType::NO_TERRAIN_PENALTY, from.terType->getIndex())) //no special movement bonus
|
!ti->hasBonusOfType(BonusType::NO_TERRAIN_PENALTY, TBonusSubtype(from.terType->getId()))) //no special movement bonus
|
||||||
{
|
{
|
||||||
|
|
||||||
ret = VLC->terrainTypeHandler->getById(from.terType->getId())->moveCost;
|
ret = VLC->terrainTypeHandler->getById(from.terType->getId())->moveCost;
|
||||||
@@ -249,14 +249,14 @@ void CGHeroInstance::updateArmyMovementBonus(bool onLand, const TurnInfo * ti) c
|
|||||||
lowestCreatureSpeed = realLowestSpeed;
|
lowestCreatureSpeed = realLowestSpeed;
|
||||||
//Let updaters run again
|
//Let updaters run again
|
||||||
treeHasChanged();
|
treeHasChanged();
|
||||||
ti->updateHeroBonuses(BonusType::MOVEMENT, Selector::subtype()(!!onLand));
|
ti->updateHeroBonuses(BonusType::MOVEMENT, Selector::subtype()(onLand ? BonusSubtypes::heroMovementLand : BonusSubtypes::heroMovementSea));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CGHeroInstance::movementPointsLimitCached(bool onLand, const TurnInfo * ti) const
|
int CGHeroInstance::movementPointsLimitCached(bool onLand, const TurnInfo * ti) const
|
||||||
{
|
{
|
||||||
updateArmyMovementBonus(onLand, ti);
|
updateArmyMovementBonus(onLand, ti);
|
||||||
return ti->valOfBonuses(BonusType::MOVEMENT, !!onLand);
|
return ti->valOfBonuses(BonusType::MOVEMENT, onLand ? BonusSubtypes::heroMovementLand : BonusSubtypes::heroMovementSea);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGHeroInstance::CGHeroInstance():
|
CGHeroInstance::CGHeroInstance():
|
||||||
@@ -638,7 +638,7 @@ int32_t CGHeroInstance::getSpellSchoolLevel(const spells::Spell * spell, int32_t
|
|||||||
|
|
||||||
spell->forEachSchool([&, this](const SpellSchool & cnf, bool & stop)
|
spell->forEachSchool([&, this](const SpellSchool & cnf, bool & stop)
|
||||||
{
|
{
|
||||||
int32_t thisSchool = valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, cnf); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies)
|
int32_t thisSchool = valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, TBonusSubtype(cnf)); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies)
|
||||||
if(thisSchool > skill)
|
if(thisSchool > skill)
|
||||||
{
|
{
|
||||||
skill = thisSchool;
|
skill = thisSchool;
|
||||||
@@ -647,8 +647,8 @@ int32_t CGHeroInstance::getSpellSchoolLevel(const spells::Spell * spell, int32_t
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
vstd::amax(skill, valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, SpellSchool(ESpellSchool::ANY))); //any school bonus
|
vstd::amax(skill, valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, TBonusSubtype(SpellSchool::ANY))); //any school bonus
|
||||||
vstd::amax(skill, valOfBonuses(BonusType::SPELL, spell->getIndex())); //given by artifact or other effect
|
vstd::amax(skill, valOfBonuses(BonusType::SPELL, TBonusSubtype(spell->getId()))); //given by artifact or other effect
|
||||||
|
|
||||||
vstd::amax(skill, 0); //in case we don't know any school
|
vstd::amax(skill, 0); //in case we don't know any school
|
||||||
vstd::amin(skill, 3);
|
vstd::amin(skill, 3);
|
||||||
@@ -660,28 +660,28 @@ int64_t CGHeroInstance::getSpellBonus(const spells::Spell * spell, int64_t base,
|
|||||||
//applying sorcery secondary skill
|
//applying sorcery secondary skill
|
||||||
|
|
||||||
if(spell->isMagical())
|
if(spell->isMagical())
|
||||||
base = static_cast<int64_t>(base * (valOfBonuses(BonusType::SPELL_DAMAGE, SpellSchool(ESpellSchool::ANY))) / 100.0);
|
base = static_cast<int64_t>(base * (valOfBonuses(BonusType::SPELL_DAMAGE, TBonusSubtype(SpellSchool::ANY))) / 100.0);
|
||||||
|
|
||||||
base = static_cast<int64_t>(base * (100 + valOfBonuses(BonusType::SPECIFIC_SPELL_DAMAGE, spell->getIndex())) / 100.0);
|
base = static_cast<int64_t>(base * (100 + valOfBonuses(BonusType::SPECIFIC_SPELL_DAMAGE, TBonusSubtype(spell->getId()))) / 100.0);
|
||||||
|
|
||||||
int maxSchoolBonus = 0;
|
int maxSchoolBonus = 0;
|
||||||
|
|
||||||
spell->forEachSchool([&maxSchoolBonus, this](const SpellSchool & cnf, bool & stop)
|
spell->forEachSchool([&maxSchoolBonus, this](const SpellSchool & cnf, bool & stop)
|
||||||
{
|
{
|
||||||
vstd::amax(maxSchoolBonus, valOfBonuses(BonusType::SPELL_DAMAGE, cnf));
|
vstd::amax(maxSchoolBonus, valOfBonuses(BonusType::SPELL_DAMAGE, TBonusSubtype(cnf)));
|
||||||
});
|
});
|
||||||
|
|
||||||
base = static_cast<int64_t>(base * (100 + maxSchoolBonus) / 100.0);
|
base = static_cast<int64_t>(base * (100 + maxSchoolBonus) / 100.0);
|
||||||
|
|
||||||
if(affectedStack && affectedStack->creatureLevel() > 0) //Hero specials like Solmyr, Deemer
|
if(affectedStack && affectedStack->creatureLevel() > 0) //Hero specials like Solmyr, Deemer
|
||||||
base = static_cast<int64_t>(base * static_cast<double>(100 + valOfBonuses(BonusType::SPECIAL_SPELL_LEV, spell->getIndex()) / affectedStack->creatureLevel()) / 100.0);
|
base = static_cast<int64_t>(base * static_cast<double>(100 + valOfBonuses(BonusType::SPECIAL_SPELL_LEV, TBonusSubtype(spell->getId())) / affectedStack->creatureLevel()) / 100.0);
|
||||||
|
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t CGHeroInstance::getSpecificSpellBonus(const spells::Spell * spell, int64_t base) const
|
int64_t CGHeroInstance::getSpecificSpellBonus(const spells::Spell * spell, int64_t base) const
|
||||||
{
|
{
|
||||||
base = static_cast<int64_t>(base * (100 + valOfBonuses(BonusType::SPECIFIC_SPELL_DAMAGE, spell->getIndex())) / 100.0);
|
base = static_cast<int64_t>(base * (100 + valOfBonuses(BonusType::SPECIFIC_SPELL_DAMAGE, TBonusSubtype(spell->getId()))) / 100.0);
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,19 +751,19 @@ bool CGHeroInstance::canCastThisSpell(const spells::Spell * spell) const
|
|||||||
const bool isAllowed = IObjectInterface::cb->isAllowed(0, spell->getIndex());
|
const bool isAllowed = IObjectInterface::cb->isAllowed(0, spell->getIndex());
|
||||||
|
|
||||||
const bool inSpellBook = vstd::contains(spells, spell->getId()) && hasSpellbook();
|
const bool inSpellBook = vstd::contains(spells, spell->getId()) && hasSpellbook();
|
||||||
const bool specificBonus = hasBonusOfType(BonusType::SPELL, spell->getIndex());
|
const bool specificBonus = hasBonusOfType(BonusType::SPELL, TBonusSubtype(spell->getId()));
|
||||||
|
|
||||||
bool schoolBonus = false;
|
bool schoolBonus = false;
|
||||||
|
|
||||||
spell->forEachSchool([this, &schoolBonus](const SpellSchool & cnf, bool & stop)
|
spell->forEachSchool([this, &schoolBonus](const SpellSchool & cnf, bool & stop)
|
||||||
{
|
{
|
||||||
if(hasBonusOfType(BonusType::SPELLS_OF_SCHOOL, cnf))
|
if(hasBonusOfType(BonusType::SPELLS_OF_SCHOOL, TBonusSubtype(cnf)))
|
||||||
{
|
{
|
||||||
schoolBonus = stop = true;
|
schoolBonus = stop = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const bool levelBonus = hasBonusOfType(BonusType::SPELLS_OF_LEVEL, spell->getLevel());
|
const bool levelBonus = hasBonusOfType(BonusType::SPELLS_OF_LEVEL, BonusSubtypes::spellLevel(spell->getLevel()));
|
||||||
|
|
||||||
if(spell->isSpecial())
|
if(spell->isSpecial())
|
||||||
{
|
{
|
||||||
@@ -845,13 +845,6 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
|
|||||||
TConstBonusListPtr improvedNecromancy = getBonuses(Selector::type()(BonusType::IMPROVED_NECROMANCY));
|
TConstBonusListPtr improvedNecromancy = getBonuses(Selector::type()(BonusType::IMPROVED_NECROMANCY));
|
||||||
if(!improvedNecromancy->empty())
|
if(!improvedNecromancy->empty())
|
||||||
{
|
{
|
||||||
auto getCreatureID = [](const std::shared_ptr<Bonus> & bonus) -> CreatureID
|
|
||||||
{
|
|
||||||
assert(bonus->subtype >=0);
|
|
||||||
if(bonus->subtype >= 0)
|
|
||||||
return CreatureID(bonus->subtype);
|
|
||||||
return CreatureID::NONE;
|
|
||||||
};
|
|
||||||
int maxCasualtyLevel = 1;
|
int maxCasualtyLevel = 1;
|
||||||
for(const auto & casualty : casualties)
|
for(const auto & casualty : casualties)
|
||||||
vstd::amax(maxCasualtyLevel, VLC->creatures()->getByIndex(casualty.first)->getLevel());
|
vstd::amax(maxCasualtyLevel, VLC->creatures()->getByIndex(casualty.first)->getLevel());
|
||||||
@@ -868,9 +861,9 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto quality = [getCreatureID](const std::shared_ptr<Bonus> & pick) -> std::tuple<int, int, int>
|
auto quality = [](const std::shared_ptr<Bonus> & pick) -> std::tuple<int, int, int>
|
||||||
{
|
{
|
||||||
const auto * c = getCreatureID(pick).toCreature();
|
const auto * c = pick->subtype.as<CreatureID>().toCreature();
|
||||||
return std::tuple<int, int, int> {c->getLevel(), static_cast<int>(c->getFullRecruitCost().marketValue()), -pick->additionalInfo[1]};
|
return std::tuple<int, int, int> {c->getLevel(), static_cast<int>(c->getFullRecruitCost().marketValue()), -pick->additionalInfo[1]};
|
||||||
};
|
};
|
||||||
if(quality(topPick) < quality(newPick))
|
if(quality(topPick) < quality(newPick))
|
||||||
@@ -879,7 +872,7 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
|
|||||||
}
|
}
|
||||||
if(topPick)
|
if(topPick)
|
||||||
{
|
{
|
||||||
creatureTypeRaised = getCreatureID(topPick);
|
creatureTypeRaised = topPick->subtype.as<CreatureID>();
|
||||||
requiredCasualtyLevel = std::max(topPick->additionalInfo[1], 1);
|
requiredCasualtyLevel = std::max(topPick->additionalInfo[1], 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1015,12 +1008,12 @@ int32_t CGHeroInstance::getSpellCost(const spells::Spell * sp) const
|
|||||||
|
|
||||||
void CGHeroInstance::pushPrimSkill( PrimarySkill which, int val )
|
void CGHeroInstance::pushPrimSkill( PrimarySkill which, int val )
|
||||||
{
|
{
|
||||||
auto sel = Selector::typeSubtype(BonusType::PRIMARY_SKILL, static_cast<int>(which))
|
auto sel = Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(which))
|
||||||
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL));
|
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL));
|
||||||
if(hasBonus(sel))
|
if(hasBonus(sel))
|
||||||
removeBonuses(sel);
|
removeBonuses(sel);
|
||||||
|
|
||||||
addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::HERO_BASE_SKILL, val, id.getNum(), static_cast<int>(which)));
|
addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::HERO_BASE_SKILL, val, id.getNum(), TBonusSubtype(which)));
|
||||||
}
|
}
|
||||||
|
|
||||||
EAlignment CGHeroInstance::getAlignment() const
|
EAlignment CGHeroInstance::getAlignment() const
|
||||||
@@ -1283,7 +1276,7 @@ std::vector<SecondarySkill> CGHeroInstance::getLevelUpProposedSecondarySkills()
|
|||||||
|
|
||||||
for(const auto & elem : secSkills)
|
for(const auto & elem : secSkills)
|
||||||
{
|
{
|
||||||
if(elem.second < SecSkillLevel::EXPERT)
|
if(elem.second < MasteryLevel::EXPERT)
|
||||||
basicAndAdv.insert(elem.first);
|
basicAndAdv.insert(elem.first);
|
||||||
else
|
else
|
||||||
expert.insert(elem.first);
|
expert.insert(elem.first);
|
||||||
@@ -1403,7 +1396,7 @@ void CGHeroInstance::setPrimarySkill(PrimarySkill primarySkill, si64 value, ui8
|
|||||||
if(primarySkill < PrimarySkill::EXPERIENCE)
|
if(primarySkill < PrimarySkill::EXPERIENCE)
|
||||||
{
|
{
|
||||||
auto skill = getBonusLocalFirst(Selector::type()(BonusType::PRIMARY_SKILL)
|
auto skill = getBonusLocalFirst(Selector::type()(BonusType::PRIMARY_SKILL)
|
||||||
.And(Selector::subtype()(static_cast<int>(primarySkill)))
|
.And(Selector::subtype()(TBonusSubtype(primarySkill)))
|
||||||
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
|
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
|
||||||
assert(skill);
|
assert(skill);
|
||||||
|
|
||||||
@@ -1474,13 +1467,10 @@ void CGHeroInstance::levelUpAutomatically(CRandomGenerator & rand)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGHeroInstance::hasVisions(const CGObjectInstance * target, const int subtype) const
|
bool CGHeroInstance::hasVisions(const CGObjectInstance * target, TBonusSubtype subtype) const
|
||||||
{
|
{
|
||||||
//VISIONS spell support
|
//VISIONS spell support
|
||||||
|
const int visionsMultiplier = valOfBonuses(BonusType::VISIONS, subtype);
|
||||||
const auto cached = "type_" + std::to_string(vstd::to_underlying(BonusType::VISIONS)) + "__subtype_" + std::to_string(subtype);
|
|
||||||
|
|
||||||
const int visionsMultiplier = valOfBonuses(Selector::typeSubtype(BonusType::VISIONS,subtype), cached);
|
|
||||||
|
|
||||||
int visionsRange = visionsMultiplier * getPrimSkillLevel(PrimarySkill::SPELL_POWER);
|
int visionsRange = visionsMultiplier * getPrimSkillLevel(PrimarySkill::SPELL_POWER);
|
||||||
|
|
||||||
@@ -1567,11 +1557,11 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
|
|||||||
{
|
{
|
||||||
auto primarySkills = handler.enterStruct("primarySkills");
|
auto primarySkills = handler.enterStruct("primarySkills");
|
||||||
|
|
||||||
for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i)
|
for(auto i = PrimarySkill::BEGIN; i < PrimarySkill::END; ++i)
|
||||||
{
|
{
|
||||||
int value = valOfBonuses(Selector::typeSubtype(BonusType::PRIMARY_SKILL, i).And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
|
int value = valOfBonuses(Selector::typeSubtype(BonusType::PRIMARY_SKILL, TBonusSubtype(i)).And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
|
||||||
|
|
||||||
handler.serializeInt(NPrimarySkill::names[i], value, 0);
|
handler.serializeInt(NPrimarySkill::names[i.getNum()], value, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1762,7 +1752,7 @@ bool CGHeroInstance::isMissionCritical() const
|
|||||||
|
|
||||||
void CGHeroInstance::fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const
|
void CGHeroInstance::fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const
|
||||||
{
|
{
|
||||||
TConstBonusListPtr lista = getBonuses(Selector::typeSubtype(BonusType::SPECIAL_UPGRADE, stack.type->getId()));
|
TConstBonusListPtr lista = getBonuses(Selector::typeSubtype(BonusType::SPECIAL_UPGRADE, TBonusSubtype(stack.type->getId())));
|
||||||
for(const auto & it : *lista)
|
for(const auto & it : *lista)
|
||||||
{
|
{
|
||||||
auto nid = CreatureID(it->additionalInfo[0]);
|
auto nid = CreatureID(it->additionalInfo[0]);
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ public:
|
|||||||
|
|
||||||
void fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const override;
|
void fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const override;
|
||||||
|
|
||||||
bool hasVisions(const CGObjectInstance * target, const int subtype) const;
|
bool hasVisions(const CGObjectInstance * target, TBonusSubtype masteryLevel) const;
|
||||||
/// If this hero perishes, the scenario is failed
|
/// If this hero perishes, the scenario is failed
|
||||||
bool isMissionCritical() const;
|
bool isMissionCritical() const;
|
||||||
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ void COPWBonus::onHeroVisit (const CGHeroInstance * h) const
|
|||||||
if(!h->hasBonusFrom(BonusSource::OBJECT, Obj::STABLES)) //does not stack with advMap Stables
|
if(!h->hasBonusFrom(BonusSource::OBJECT, Obj::STABLES)) //does not stack with advMap Stables
|
||||||
{
|
{
|
||||||
GiveBonus gb;
|
GiveBonus gb;
|
||||||
gb.bonus = Bonus(BonusDuration::ONE_WEEK, BonusType::MOVEMENT, BonusSource::OBJECT, 600, 94, VLC->generaltexth->arraytxt[100], 1);
|
gb.bonus = Bonus(BonusDuration::ONE_WEEK, BonusType::MOVEMENT, BonusSource::OBJECT, 600, Obj::STABLES, BonusSubtypes::heroMovementLand, VLC->generaltexth->arraytxt[100]);
|
||||||
gb.id = heroID.getNum();
|
gb.id = heroID.getNum();
|
||||||
cb->giveHeroBonus(&gb);
|
cb->giveHeroBonus(&gb);
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
//other *-of-legion-like bonuses (%d to growth cumulative with grail)
|
//other *-of-legion-like bonuses (%d to growth cumulative with grail)
|
||||||
TConstBonusListPtr bonuses = getBonuses(Selector::type()(BonusType::CREATURE_GROWTH).And(Selector::subtype()(level)));
|
TConstBonusListPtr bonuses = getBonuses(Selector::typeSubtype(BonusType::CREATURE_GROWTH, BonusSubtypes::creatureLevel(level)));
|
||||||
for(const auto & b : *bonuses)
|
for(const auto & b : *bonuses)
|
||||||
ret.entries.emplace_back(b->val, b->Description());
|
ret.entries.emplace_back(b->val, b->Description());
|
||||||
|
|
||||||
|
|||||||
@@ -836,7 +836,7 @@ void CGArtifact::serializeJsonOptions(JsonSerializeFormat& handler)
|
|||||||
if(handler.saving && ID == Obj::SPELL_SCROLL)
|
if(handler.saving && ID == Obj::SPELL_SCROLL)
|
||||||
{
|
{
|
||||||
const std::shared_ptr<Bonus> b = storedArtifact->getBonusLocalFirst(Selector::type()(BonusType::SPELL));
|
const std::shared_ptr<Bonus> b = storedArtifact->getBonusLocalFirst(Selector::type()(BonusType::SPELL));
|
||||||
SpellID spellId(b->subtype);
|
SpellID spellId(b->subtype.as<SpellID>());
|
||||||
|
|
||||||
handler.serializeId("spell", spellId, SpellID::NONE);
|
handler.serializeId("spell", spellId, SpellID::NONE);
|
||||||
}
|
}
|
||||||
@@ -1204,7 +1204,7 @@ void CGLighthouse::giveBonusTo(const PlayerColor & player, bool onInit) const
|
|||||||
gb.bonus.duration = BonusDuration::PERMANENT;
|
gb.bonus.duration = BonusDuration::PERMANENT;
|
||||||
gb.bonus.source = BonusSource::OBJECT;
|
gb.bonus.source = BonusSource::OBJECT;
|
||||||
gb.bonus.sid = id.getNum();
|
gb.bonus.sid = id.getNum();
|
||||||
gb.bonus.subtype = 0;
|
gb.bonus.subtype = BonusSubtypes::heroMovementSea;
|
||||||
|
|
||||||
// FIXME: This is really dirty hack
|
// FIXME: This is really dirty hack
|
||||||
// Proper fix would be to make CGLighthouse into bonus system node
|
// Proper fix would be to make CGLighthouse into bonus system node
|
||||||
|
|||||||
@@ -531,9 +531,9 @@ const TurnInfo * CPathfinderHelper::getTurnInfo() const
|
|||||||
return turnsInfo[turn];
|
return turnsInfo[turn];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPathfinderHelper::hasBonusOfType(const BonusType type, const int subtype) const
|
bool CPathfinderHelper::hasBonusOfType(const BonusType type) const
|
||||||
{
|
{
|
||||||
return turnsInfo[turn]->hasBonusOfType(type, subtype);
|
return turnsInfo[turn]->hasBonusOfType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CPathfinderHelper::getMaxMovePoints(const EPathfindingLayer & layer) const
|
int CPathfinderHelper::getMaxMovePoints(const EPathfindingLayer & layer) const
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public:
|
|||||||
void updateTurnInfo(const int turn = 0);
|
void updateTurnInfo(const int turn = 0);
|
||||||
bool isLayerAvailable(const EPathfindingLayer & layer) const;
|
bool isLayerAvailable(const EPathfindingLayer & layer) const;
|
||||||
const TurnInfo * getTurnInfo() const;
|
const TurnInfo * getTurnInfo() const;
|
||||||
bool hasBonusOfType(const BonusType type, const int subtype = -1) const;
|
bool hasBonusOfType(BonusType type) const;
|
||||||
int getMaxMovePoints(const EPathfindingLayer & layer) const;
|
int getMaxMovePoints(const EPathfindingLayer & layer) const;
|
||||||
|
|
||||||
std::vector<int3> getCastleGates(const PathNodeInfo & source) const;
|
std::vector<int3> getCastleGates(const PathNodeInfo & source) const;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ TurnInfo::BonusCache::BonusCache(const TConstBonusListPtr & bl)
|
|||||||
for(const auto & terrain : VLC->terrainTypeHandler->objects)
|
for(const auto & terrain : VLC->terrainTypeHandler->objects)
|
||||||
{
|
{
|
||||||
noTerrainPenalty.push_back(static_cast<bool>(
|
noTerrainPenalty.push_back(static_cast<bool>(
|
||||||
bl->getFirst(Selector::type()(BonusType::NO_TERRAIN_PENALTY).And(Selector::subtype()(terrain->getIndex())))));
|
bl->getFirst(Selector::type()(BonusType::NO_TERRAIN_PENALTY).And(Selector::subtype()(TBonusSubtype(terrain->getId()))))));
|
||||||
}
|
}
|
||||||
|
|
||||||
freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type()(BonusType::FREE_SHIP_BOARDING)));
|
freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type()(BonusType::FREE_SHIP_BOARDING)));
|
||||||
@@ -71,7 +71,7 @@ bool TurnInfo::isLayerAvailable(const EPathfindingLayer & layer) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TurnInfo::hasBonusOfType(BonusType type, int subtype) const
|
bool TurnInfo::hasBonusOfType(BonusType type, TBonusSubtype subtype) const
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
@@ -82,14 +82,14 @@ bool TurnInfo::hasBonusOfType(BonusType type, int subtype) const
|
|||||||
case BonusType::WATER_WALKING:
|
case BonusType::WATER_WALKING:
|
||||||
return bonusCache->waterWalking;
|
return bonusCache->waterWalking;
|
||||||
case BonusType::NO_TERRAIN_PENALTY:
|
case BonusType::NO_TERRAIN_PENALTY:
|
||||||
return bonusCache->noTerrainPenalty[subtype];
|
return bonusCache->noTerrainPenalty[subtype.getNum()];
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<bool>(
|
return static_cast<bool>(
|
||||||
bonuses->getFirst(Selector::type()(type).And(Selector::subtype()(subtype))));
|
bonuses->getFirst(Selector::type()(type).And(Selector::subtype()(subtype))));
|
||||||
}
|
}
|
||||||
|
|
||||||
int TurnInfo::valOfBonuses(BonusType type, int subtype) const
|
int TurnInfo::valOfBonuses(BonusType type, TBonusSubtype subtype) const
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,8 +42,10 @@ struct DLL_LINKAGE TurnInfo
|
|||||||
|
|
||||||
TurnInfo(const CGHeroInstance * Hero, const int Turn = 0);
|
TurnInfo(const CGHeroInstance * Hero, const int Turn = 0);
|
||||||
bool isLayerAvailable(const EPathfindingLayer & layer) const;
|
bool isLayerAvailable(const EPathfindingLayer & layer) const;
|
||||||
bool hasBonusOfType(const BonusType type, const int subtype = -1) const;
|
bool hasBonusOfType(const BonusType type) const;
|
||||||
int valOfBonuses(const BonusType type, const int subtype = -1) const;
|
bool hasBonusOfType(const BonusType type, const TBonusSubtype subtype) const;
|
||||||
|
int valOfBonuses(const BonusType type) const;
|
||||||
|
int valOfBonuses(const BonusType type, const TBonusSubtype subtype) const;
|
||||||
void updateHeroBonuses(BonusType type, const CSelector& sel) const;
|
void updateHeroBonuses(BonusType type, const CSelector& sel) const;
|
||||||
int getMaxMovePoints(const EPathfindingLayer & layer) const;
|
int getMaxMovePoints(const EPathfindingLayer & layer) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Rewardable::Reward::Reward()
|
|||||||
, movePercentage(-1)
|
, movePercentage(-1)
|
||||||
, primary(4, 0)
|
, primary(4, 0)
|
||||||
, removeObject(false)
|
, removeObject(false)
|
||||||
, spellCast(SpellID::NONE, SecSkillLevel::NONE)
|
, spellCast(SpellID::NONE, MasteryLevel::NONE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ int32_t AbilityCaster::getSpellSchoolLevel(const Spell * spell, int32_t * outSel
|
|||||||
|
|
||||||
if(spell->getLevel() > 0)
|
if(spell->getLevel() > 0)
|
||||||
{
|
{
|
||||||
vstd::amax(skill, unit->valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, SpellSchool(ESpellSchool::ANY)));
|
vstd::amax(skill, unit->valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, TBonusSubtype(SpellSchool::ANY)));
|
||||||
}
|
}
|
||||||
|
|
||||||
vstd::amax(skill, 0);
|
vstd::amax(skill, 0);
|
||||||
|
|||||||
@@ -383,15 +383,15 @@ int64_t CSpell::adjustRawDamage(const spells::Caster * caster, const battle::Uni
|
|||||||
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
|
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
|
||||||
forEachSchool([&](const SpellSchool & cnf, bool & stop)
|
forEachSchool([&](const SpellSchool & cnf, bool & stop)
|
||||||
{
|
{
|
||||||
if(bearer->hasBonusOfType(BonusType::SPELL_DAMAGE_REDUCTION, cnf))
|
if(bearer->hasBonusOfType(BonusType::SPELL_DAMAGE_REDUCTION, TBonusSubtype(cnf)))
|
||||||
{
|
{
|
||||||
ret *= 100 - bearer->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, cnf);
|
ret *= 100 - bearer->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, TBonusSubtype(cnf));
|
||||||
ret /= 100;
|
ret /= 100;
|
||||||
stop = true; //only bonus from one school is used
|
stop = true; //only bonus from one school is used
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
CSelector selector = Selector::typeSubtype(BonusType::SPELL_DAMAGE_REDUCTION, SpellSchool(ESpellSchool::ANY));
|
CSelector selector = Selector::typeSubtype(BonusType::SPELL_DAMAGE_REDUCTION, TBonusSubtype(SpellSchool::ANY));
|
||||||
auto cachingStr = "type_SPELL_DAMAGE_REDUCTION_s_ANY";
|
auto cachingStr = "type_SPELL_DAMAGE_REDUCTION_s_ANY";
|
||||||
|
|
||||||
//general spell dmg reduction, works only on magical effects
|
//general spell dmg reduction, works only on magical effects
|
||||||
@@ -402,9 +402,9 @@ int64_t CSpell::adjustRawDamage(const spells::Caster * caster, const battle::Uni
|
|||||||
}
|
}
|
||||||
|
|
||||||
//dmg increasing
|
//dmg increasing
|
||||||
if(bearer->hasBonusOfType(BonusType::MORE_DAMAGE_FROM_SPELL, id))
|
if(bearer->hasBonusOfType(BonusType::MORE_DAMAGE_FROM_SPELL, TBonusSubtype(id)))
|
||||||
{
|
{
|
||||||
ret *= 100 + bearer->valOfBonuses(BonusType::MORE_DAMAGE_FROM_SPELL, id.toEnum());
|
ret *= 100 + bearer->valOfBonuses(BonusType::MORE_DAMAGE_FROM_SPELL, TBonusSubtype(id));
|
||||||
ret /= 100;
|
ret /= 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ protected:
|
|||||||
{
|
{
|
||||||
std::stringstream cachingStr;
|
std::stringstream cachingStr;
|
||||||
cachingStr << "type_" << vstd::to_underlying(BonusType::SPELL_IMMUNITY) << "subtype_" << m->getSpellIndex() << "addInfo_1";
|
cachingStr << "type_" << vstd::to_underlying(BonusType::SPELL_IMMUNITY) << "subtype_" << m->getSpellIndex() << "addInfo_1";
|
||||||
return !target->hasBonus(Selector::typeSubtypeInfo(BonusType::SPELL_IMMUNITY, m->getSpellIndex(), 1), cachingStr.str());
|
return !target->hasBonus(Selector::typeSubtypeInfo(BonusType::SPELL_IMMUNITY, TBonusSubtype(m->getSpellId()), 1), cachingStr.str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -179,14 +179,14 @@ protected:
|
|||||||
|
|
||||||
m->getSpell()->forEachSchool([&](const SpellSchool & cnf, bool & stop)
|
m->getSpell()->forEachSchool([&](const SpellSchool & cnf, bool & stop)
|
||||||
{
|
{
|
||||||
if (bearer->hasBonusOfType(BonusType::SPELL_SCHOOL_IMMUNITY, cnf))
|
if (bearer->hasBonusOfType(BonusType::SPELL_SCHOOL_IMMUNITY, TBonusSubtype(cnf)))
|
||||||
{
|
{
|
||||||
elementalImmune = true;
|
elementalImmune = true;
|
||||||
stop = true; //only bonus from one school is used
|
stop = true; //only bonus from one school is used
|
||||||
}
|
}
|
||||||
else if(!m->isPositiveSpell()) //negative or indifferent
|
else if(!m->isPositiveSpell()) //negative or indifferent
|
||||||
{
|
{
|
||||||
if (bearer->hasBonusOfType(BonusType::NEGATIVE_EFFECTS_IMMUNITY, cnf))
|
if (bearer->hasBonusOfType(BonusType::NEGATIVE_EFFECTS_IMMUNITY, TBonusSubtype(cnf)))
|
||||||
{
|
{
|
||||||
elementalImmune = true;
|
elementalImmune = true;
|
||||||
stop = true; //only bonus from one school is used
|
stop = true; //only bonus from one school is used
|
||||||
@@ -231,7 +231,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
bool check(const Mechanics * m, const battle::Unit * target) const override
|
bool check(const Mechanics * m, const battle::Unit * target) const override
|
||||||
{
|
{
|
||||||
return !target->hasBonusOfType(BonusType::SPELL_IMMUNITY, m->getSpellIndex());
|
return !target->hasBonusOfType(BonusType::SPELL_IMMUNITY, TBonusSubtype(m->getSpellId()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -292,8 +292,8 @@ class ImmunityNegationCondition : public TargetConditionItemBase
|
|||||||
protected:
|
protected:
|
||||||
bool check(const Mechanics * m, const battle::Unit * target) const override
|
bool check(const Mechanics * m, const battle::Unit * target) const override
|
||||||
{
|
{
|
||||||
const bool battleWideNegation = target->hasBonusOfType(BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, 0);
|
const bool battleWideNegation = target->hasBonusOfType(BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSubtypes::immunityBattleWide);
|
||||||
const bool heroNegation = target->hasBonusOfType(BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, 1);
|
const bool heroNegation = target->hasBonusOfType(BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, BonusSubtypes::immunityEnemyHero);
|
||||||
//Non-magical effects is not affected by orb of vulnerability
|
//Non-magical effects is not affected by orb of vulnerability
|
||||||
if(!m->isMagicalEffect())
|
if(!m->isMagicalEffect())
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -89,11 +89,11 @@ bool Damage::isReceptive(const Mechanics * m, const battle::Unit * unit) const
|
|||||||
if(!UnitEffect::isReceptive(m, unit))
|
if(!UnitEffect::isReceptive(m, unit))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool isImmune = m->getSpell()->isMagical() && (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, SpellSchool(ESpellSchool::ANY)) >= 100); //General spell damage immunity
|
bool isImmune = m->getSpell()->isMagical() && (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, TBonusSubtype(SpellSchool::ANY)) >= 100); //General spell damage immunity
|
||||||
//elemental immunity for damage
|
//elemental immunity for damage
|
||||||
m->getSpell()->forEachSchool([&](const SpellSchool & cnf, bool & stop)
|
m->getSpell()->forEachSchool([&](const SpellSchool & cnf, bool & stop)
|
||||||
{
|
{
|
||||||
isImmune |= (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, cnf) >= 100); //100% reduction is immunity
|
isImmune |= (unit->getBonusBearer()->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, TBonusSubtype(cnf)) >= 100); //100% reduction is immunity
|
||||||
});
|
});
|
||||||
|
|
||||||
return !isImmune;
|
return !isImmune;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ static void describeEffect(std::vector<MetaString> & log, const Mechanics * m, c
|
|||||||
{
|
{
|
||||||
case BonusType::NOT_ACTIVE:
|
case BonusType::NOT_ACTIVE:
|
||||||
{
|
{
|
||||||
switch(bonus.subtype)
|
switch(bonus.subtype.as<SpellID>().toEnum())
|
||||||
{
|
{
|
||||||
case SpellID::STONE_GAZE:
|
case SpellID::STONE_GAZE:
|
||||||
addLogLine(558, boost::logic::indeterminate);
|
addLogLine(558, boost::logic::indeterminate);
|
||||||
@@ -109,9 +109,9 @@ void Timed::apply(ServerCallback * server, const Mechanics * m, const EffectTarg
|
|||||||
const auto *casterHero = dynamic_cast<const CGHeroInstance *>(m->caster);
|
const auto *casterHero = dynamic_cast<const CGHeroInstance *>(m->caster);
|
||||||
if(casterHero)
|
if(casterHero)
|
||||||
{
|
{
|
||||||
peculiarBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(BonusType::SPECIAL_PECULIAR_ENCHANT, m->getSpellIndex()));
|
peculiarBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(BonusType::SPECIAL_PECULIAR_ENCHANT, TBonusSubtype(m->getSpellId())));
|
||||||
addedValueBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(BonusType::SPECIAL_ADD_VALUE_ENCHANT, m->getSpellIndex()));
|
addedValueBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(BonusType::SPECIAL_ADD_VALUE_ENCHANT, TBonusSubtype(m->getSpellId())));
|
||||||
fixedValueBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(BonusType::SPECIAL_FIXED_VALUE_ENCHANT, m->getSpellIndex()));
|
fixedValueBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(BonusType::SPECIAL_FIXED_VALUE_ENCHANT, TBonusSubtype(m->getSpellId())));
|
||||||
}
|
}
|
||||||
//TODO: does hero specialty should affects his stack casting spells?
|
//TODO: does hero specialty should affects his stack casting spells?
|
||||||
|
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ bool UnitEffect::isReceptive(const Mechanics * m, const battle::Unit * unit) con
|
|||||||
//SPELL_IMMUNITY absolute case
|
//SPELL_IMMUNITY absolute case
|
||||||
std::stringstream cachingStr;
|
std::stringstream cachingStr;
|
||||||
cachingStr << "type_" << vstd::to_underlying(BonusType::SPELL_IMMUNITY) << "subtype_" << m->getSpellIndex() << "addInfo_1";
|
cachingStr << "type_" << vstd::to_underlying(BonusType::SPELL_IMMUNITY) << "subtype_" << m->getSpellIndex() << "addInfo_1";
|
||||||
return !unit->hasBonus(Selector::typeSubtypeInfo(BonusType::SPELL_IMMUNITY, m->getSpellIndex(), 1), cachingStr.str());
|
return !unit->hasBonus(Selector::typeSubtypeInfo(BonusType::SPELL_IMMUNITY, TBonusSubtype(m->getSpellId()), 1), cachingStr.str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user