mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-14 02:33:51 +02:00
Merge pull request #2108 from rilian-la-te/bonuses-refactor-p2
Split HeroBonus.h to pieces, part2
This commit is contained in:
commit
9373239c03
@ -97,7 +97,7 @@ AttackPossibility AttackPossibility::evaluate(const BattleAttackInfo & attackInf
|
|||||||
auto attacker = attackInfo.attacker;
|
auto attacker = attackInfo.attacker;
|
||||||
auto defender = attackInfo.defender;
|
auto defender = attackInfo.defender;
|
||||||
const std::string cachingStringBlocksRetaliation = "type_BLOCKS_RETALIATION";
|
const std::string cachingStringBlocksRetaliation = "type_BLOCKS_RETALIATION";
|
||||||
static const auto selectorBlocksRetaliation = Selector::type()(Bonus::BLOCKS_RETALIATION);
|
static const auto selectorBlocksRetaliation = Selector::type()(BonusType::BLOCKS_RETALIATION);
|
||||||
const auto attackerSide = state.playerToSide(state.battleGetOwner(attacker));
|
const auto attackerSide = state.playerToSide(state.battleGetOwner(attacker));
|
||||||
const bool counterAttacksBlocked = attacker->hasBonus(selectorBlocksRetaliation, cachingStringBlocksRetaliation);
|
const bool counterAttacksBlocked = attacker->hasBonus(selectorBlocksRetaliation, cachingStringBlocksRetaliation);
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
{
|
{
|
||||||
if(stack->creatureId() == CreatureID::CATAPULT)
|
if(stack->creatureId() == CreatureID::CATAPULT)
|
||||||
return useCatapult(stack);
|
return useCatapult(stack);
|
||||||
if(stack->hasBonusOfType(Bonus::SIEGE_WEAPON) && stack->hasBonusOfType(Bonus::HEALER))
|
if(stack->hasBonusOfType(BonusType::SIEGE_WEAPON) && stack->hasBonusOfType(BonusType::HEALER))
|
||||||
{
|
{
|
||||||
auto healingTargets = cb->battleGetStacks(CBattleInfoEssentials::ONLY_MINE);
|
auto healingTargets = cb->battleGetStacks(CBattleInfoEssentials::ONLY_MINE);
|
||||||
std::map<int, const CStack*> woundHpToStack;
|
std::map<int, const CStack*> woundHpToStack;
|
||||||
@ -137,7 +137,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
std::optional<PossibleSpellcast> bestSpellcast(std::nullopt);
|
std::optional<PossibleSpellcast> bestSpellcast(std::nullopt);
|
||||||
//TODO: faerie dragon type spell should be selected by server
|
//TODO: faerie dragon type spell should be selected by server
|
||||||
SpellID creatureSpellToCast = cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), stack, CBattleInfoCallback::RANDOM_AIMED);
|
SpellID creatureSpellToCast = cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), stack, CBattleInfoCallback::RANDOM_AIMED);
|
||||||
if(stack->hasBonusOfType(Bonus::SPELLCASTER) && stack->canCast() && creatureSpellToCast != SpellID::NONE)
|
if(stack->hasBonusOfType(BonusType::SPELLCASTER) && stack->canCast() && creatureSpellToCast != SpellID::NONE)
|
||||||
{
|
{
|
||||||
const CSpell * spell = creatureSpellToCast.toSpell();
|
const CSpell * spell = creatureSpellToCast.toSpell();
|
||||||
|
|
||||||
@ -241,7 +241,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(score <= EvaluationResult::INEFFECTIVE_SCORE
|
if(score <= EvaluationResult::INEFFECTIVE_SCORE
|
||||||
&& !stack->hasBonusOfType(Bonus::FLYING)
|
&& !stack->hasBonusOfType(BonusType::FLYING)
|
||||||
&& stack->unitSide() == BattleSide::ATTACKER
|
&& stack->unitSide() == BattleSide::ATTACKER
|
||||||
&& cb->battleGetSiegeLevel() >= CGTownInstance::CITADEL)
|
&& cb->battleGetSiegeLevel() >= CGTownInstance::CITADEL)
|
||||||
{
|
{
|
||||||
@ -321,7 +321,7 @@ BattleAction CBattleAI::goTowardsNearest(const CStack * stack, std::vector<Battl
|
|||||||
|
|
||||||
scoreEvaluator.updateReachabilityMap(hb);
|
scoreEvaluator.updateReachabilityMap(hb);
|
||||||
|
|
||||||
if(stack->hasBonusOfType(Bonus::FLYING))
|
if(stack->hasBonusOfType(BonusType::FLYING))
|
||||||
{
|
{
|
||||||
std::set<BattleHex> obstacleHexes;
|
std::set<BattleHex> obstacleHexes;
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ int64_t BattleExchangeVariant::trackAttack(
|
|||||||
bool evaluateOnly)
|
bool evaluateOnly)
|
||||||
{
|
{
|
||||||
const std::string cachingStringBlocksRetaliation = "type_BLOCKS_RETALIATION";
|
const std::string cachingStringBlocksRetaliation = "type_BLOCKS_RETALIATION";
|
||||||
static const auto selectorBlocksRetaliation = Selector::type()(Bonus::BLOCKS_RETALIATION);
|
static const auto selectorBlocksRetaliation = Selector::type()(BonusType::BLOCKS_RETALIATION);
|
||||||
const bool counterAttacksBlocked = attacker->hasBonus(selectorBlocksRetaliation, cachingStringBlocksRetaliation);
|
const bool counterAttacksBlocked = attacker->hasBonus(selectorBlocksRetaliation, cachingStringBlocksRetaliation);
|
||||||
|
|
||||||
DamageEstimation retaliation;
|
DamageEstimation retaliation;
|
||||||
|
@ -22,7 +22,7 @@ PotentialTargets::PotentialTargets(const battle::Unit * attacker, const Hypothet
|
|||||||
const battle::Unit * forcedTarget = nullptr;
|
const battle::Unit * forcedTarget = nullptr;
|
||||||
BattleHex forcedHex;
|
BattleHex forcedHex;
|
||||||
|
|
||||||
if(attackerInfo->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE))
|
if(attackerInfo->hasBonusOfType(BonusType::ATTACKS_NEAREST_CREATURE))
|
||||||
{
|
{
|
||||||
forceTarget = true;
|
forceTarget = true;
|
||||||
auto nearest = state.getNearestStack(attackerInfo);
|
auto nearest = state.getNearestStack(attackerInfo);
|
||||||
|
@ -24,7 +24,7 @@ void actualizeEffect(TBonusListPtr target, const Bonus & ef)
|
|||||||
{
|
{
|
||||||
for(auto & bonus : *target) //TODO: optimize
|
for(auto & bonus : *target) //TODO: optimize
|
||||||
{
|
{
|
||||||
if(bonus->source == Bonus::SPELL_EFFECT && bonus->type == ef.type && bonus->subtype == ef.subtype)
|
if(bonus->source == BonusSource::SPELL_EFFECT && bonus->type == ef.type && bonus->subtype == ef.subtype)
|
||||||
{
|
{
|
||||||
if(bonus->turnsRemain < ef.turnsRemain)
|
if(bonus->turnsRemain < ef.turnsRemain)
|
||||||
{
|
{
|
||||||
@ -126,7 +126,7 @@ TConstBonusListPtr StackWithBonuses::getAllBonuses(const CSelector & selector, c
|
|||||||
{
|
{
|
||||||
if(selector(&bonus) && (!limit || !limit(&bonus)))
|
if(selector(&bonus) && (!limit || !limit(&bonus)))
|
||||||
{
|
{
|
||||||
if(ret->getFirst(Selector::source(Bonus::SPELL_EFFECT, bonus.sid).And(Selector::typeSubtype(bonus.type, bonus.subtype))))
|
if(ret->getFirst(Selector::source(BonusSource::SPELL_EFFECT, bonus.sid).And(Selector::typeSubtype(bonus.type, bonus.subtype))))
|
||||||
{
|
{
|
||||||
actualizeEffect(ret, bonus);
|
actualizeEffect(ret, bonus);
|
||||||
}
|
}
|
||||||
|
@ -307,7 +307,7 @@ bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2
|
|||||||
auto art2 = a2->artType;
|
auto art2 = a2->artType;
|
||||||
|
|
||||||
if(art1->price == art2->price)
|
if(art1->price == art2->price)
|
||||||
return art1->valOfBonuses(Bonus::PRIMARY_SKILL) > art2->valOfBonuses(Bonus::PRIMARY_SKILL);
|
return art1->valOfBonuses(BonusType::PRIMARY_SKILL) > art2->valOfBonuses(BonusType::PRIMARY_SKILL);
|
||||||
else
|
else
|
||||||
return art1->price > art2->price;
|
return art1->price > art2->price;
|
||||||
}
|
}
|
||||||
|
@ -108,12 +108,12 @@ std::vector<SlotInfo> ArmyManager::getBestArmy(const IBonusBearer * armyCarrier,
|
|||||||
uint64_t armyValue = 0;
|
uint64_t armyValue = 0;
|
||||||
|
|
||||||
TemporaryArmy newArmyInstance;
|
TemporaryArmy newArmyInstance;
|
||||||
auto bonusModifiers = armyCarrier->getBonuses(Selector::type()(Bonus::MORALE));
|
auto bonusModifiers = armyCarrier->getBonuses(Selector::type()(BonusType::MORALE));
|
||||||
|
|
||||||
for(auto bonus : *bonusModifiers)
|
for(auto bonus : *bonusModifiers)
|
||||||
{
|
{
|
||||||
// army bonuses will change and object bonuses are temporary
|
// army bonuses will change and object bonuses are temporary
|
||||||
if(bonus->source != Bonus::ARMY && bonus->source != Bonus::OBJECT)
|
if(bonus->source != BonusSource::ARMY && bonus->source != BonusSource::OBJECT)
|
||||||
{
|
{
|
||||||
newArmyInstance.addNewBonus(std::make_shared<Bonus>(*bonus));
|
newArmyInstance.addNewBonus(std::make_shared<Bonus>(*bonus));
|
||||||
}
|
}
|
||||||
|
@ -72,10 +72,10 @@ float HeroManager::evaluateSecSkill(SecondarySkill skill, const CGHeroInstance *
|
|||||||
|
|
||||||
float HeroManager::evaluateSpeciality(const CGHeroInstance * hero) const
|
float HeroManager::evaluateSpeciality(const CGHeroInstance * hero) const
|
||||||
{
|
{
|
||||||
auto heroSpecial = Selector::source(Bonus::HERO_SPECIAL, hero->type->getIndex());
|
auto heroSpecial = Selector::source(BonusSource::HERO_SPECIAL, hero->type->getIndex());
|
||||||
auto secondarySkillBonus = Selector::targetSourceType()(Bonus::SECONDARY_SKILL);
|
auto secondarySkillBonus = Selector::targetSourceType()(BonusSource::SECONDARY_SKILL);
|
||||||
auto specialSecondarySkillBonuses = hero->getBonuses(heroSpecial.And(secondarySkillBonus));
|
auto specialSecondarySkillBonuses = hero->getBonuses(heroSpecial.And(secondarySkillBonus));
|
||||||
auto secondarySkillBonuses = hero->getBonuses(Selector::sourceTypeSel(Bonus::SECONDARY_SKILL));
|
auto secondarySkillBonuses = hero->getBonuses(Selector::sourceTypeSel(BonusSource::SECONDARY_SKILL));
|
||||||
float specialityScore = 0.0f;
|
float specialityScore = 0.0f;
|
||||||
|
|
||||||
for(auto bonus : *secondarySkillBonuses)
|
for(auto bonus : *secondarySkillBonuses)
|
||||||
|
@ -53,14 +53,14 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
|
|||||||
double shootersStrength = 0;
|
double shootersStrength = 0;
|
||||||
ui32 maxSpeed = 0;
|
ui32 maxSpeed = 0;
|
||||||
|
|
||||||
static const CSelector selectorSHOOTER = Selector::type()(Bonus::SHOOTER);
|
static const CSelector selectorSHOOTER = Selector::type()(BonusType::SHOOTER);
|
||||||
static const std::string keySHOOTER = "type_"+std::to_string((int32_t)Bonus::SHOOTER);
|
static const std::string keySHOOTER = "type_"+std::to_string((int32_t)BonusType::SHOOTER);
|
||||||
|
|
||||||
static const CSelector selectorFLYING = Selector::type()(Bonus::FLYING);
|
static const CSelector selectorFLYING = Selector::type()(BonusType::FLYING);
|
||||||
static const std::string keyFLYING = "type_"+std::to_string((int32_t)Bonus::FLYING);
|
static const std::string keyFLYING = "type_"+std::to_string((int32_t)BonusType::FLYING);
|
||||||
|
|
||||||
static const CSelector selectorSTACKS_SPEED = Selector::type()(Bonus::STACKS_SPEED);
|
static const CSelector selectorSTACKS_SPEED = Selector::type()(BonusType::STACKS_SPEED);
|
||||||
static const std::string keySTACKS_SPEED = "type_"+std::to_string((int32_t)Bonus::STACKS_SPEED);
|
static const std::string keySTACKS_SPEED = "type_"+std::to_string((int32_t)BonusType::STACKS_SPEED);
|
||||||
|
|
||||||
for(auto s : army->Slots())
|
for(auto s : army->Slots())
|
||||||
{
|
{
|
||||||
|
@ -210,14 +210,14 @@ uint64_t evaluateArtifactArmyValue(CArtifactInstance * art)
|
|||||||
return 1500;
|
return 1500;
|
||||||
|
|
||||||
auto statsValue =
|
auto statsValue =
|
||||||
10 * art->valOfBonuses(Bonus::MOVEMENT, 1)
|
10 * art->valOfBonuses(BonusType::MOVEMENT, 1)
|
||||||
+ 1200 * art->valOfBonuses(Bonus::STACKS_SPEED)
|
+ 1200 * art->valOfBonuses(BonusType::STACKS_SPEED)
|
||||||
+ 700 * art->valOfBonuses(Bonus::MORALE)
|
+ 700 * art->valOfBonuses(BonusType::MORALE)
|
||||||
+ 700 * art->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK)
|
+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, PrimarySkill::ATTACK)
|
||||||
+ 700 * art->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE)
|
+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, PrimarySkill::DEFENSE)
|
||||||
+ 700 * art->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::KNOWLEDGE)
|
+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, PrimarySkill::KNOWLEDGE)
|
||||||
+ 700 * art->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::SPELL_POWER)
|
+ 700 * art->valOfBonuses(BonusType::PRIMARY_SKILL, PrimarySkill::SPELL_POWER)
|
||||||
+ 500 * art->valOfBonuses(Bonus::LUCK);
|
+ 500 * art->valOfBonuses(BonusType::LUCK);
|
||||||
|
|
||||||
auto classValue = 0;
|
auto classValue = 0;
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
|
|||||||
|
|
||||||
return attack;
|
return attack;
|
||||||
}
|
}
|
||||||
else if(stack->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
else if(stack->hasBonusOfType(BonusType::SIEGE_WEAPON))
|
||||||
{
|
{
|
||||||
return BattleAction::makeDefend(stack);
|
return BattleAction::makeDefend(stack);
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ BattleAction CStupidAI::goTowards(const CStack * stack, std::vector<BattleHex> h
|
|||||||
return BattleAction::makeDefend(stack);
|
return BattleAction::makeDefend(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(stack->hasBonusOfType(Bonus::FLYING))
|
if(stack->hasBonusOfType(BonusType::FLYING))
|
||||||
{
|
{
|
||||||
// Flying stack doesn't go hex by hex, so we can't backtrack using predecessors.
|
// Flying stack doesn't go hex by hex, so we can't backtrack using predecessors.
|
||||||
// We just check all available hexes and pick the one closest to the target.
|
// We just check all available hexes and pick the one closest to the target.
|
||||||
|
@ -257,7 +257,7 @@ bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2
|
|||||||
auto art2 = a2->artType;
|
auto art2 = a2->artType;
|
||||||
|
|
||||||
if(art1->price == art2->price)
|
if(art1->price == art2->price)
|
||||||
return art1->valOfBonuses(Bonus::PRIMARY_SKILL) > art2->valOfBonuses(Bonus::PRIMARY_SKILL);
|
return art1->valOfBonuses(BonusType::PRIMARY_SKILL) > art2->valOfBonuses(BonusType::PRIMARY_SKILL);
|
||||||
else
|
else
|
||||||
return art1->price > art2->price;
|
return art1->price > art2->price;
|
||||||
}
|
}
|
||||||
|
@ -52,14 +52,14 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
|
|||||||
double shootersStrength = 0;
|
double shootersStrength = 0;
|
||||||
ui32 maxSpeed = 0;
|
ui32 maxSpeed = 0;
|
||||||
|
|
||||||
static const CSelector selectorSHOOTER = Selector::type()(Bonus::SHOOTER);
|
static const CSelector selectorSHOOTER = Selector::type()(BonusType::SHOOTER);
|
||||||
static const std::string keySHOOTER = "type_"+std::to_string((int32_t)Bonus::SHOOTER);
|
static const std::string keySHOOTER = "type_"+std::to_string((int32_t)BonusType::SHOOTER);
|
||||||
|
|
||||||
static const CSelector selectorFLYING = Selector::type()(Bonus::FLYING);
|
static const CSelector selectorFLYING = Selector::type()(BonusType::FLYING);
|
||||||
static const std::string keyFLYING = "type_"+std::to_string((int32_t)Bonus::FLYING);
|
static const std::string keyFLYING = "type_"+std::to_string((int32_t)BonusType::FLYING);
|
||||||
|
|
||||||
static const CSelector selectorSTACKS_SPEED = Selector::type()(Bonus::STACKS_SPEED);
|
static const CSelector selectorSTACKS_SPEED = Selector::type()(BonusType::STACKS_SPEED);
|
||||||
static const std::string keySTACKS_SPEED = "type_"+std::to_string((int32_t)Bonus::STACKS_SPEED);
|
static const std::string keySTACKS_SPEED = "type_"+std::to_string((int32_t)BonusType::STACKS_SPEED);
|
||||||
|
|
||||||
for(auto s : army->Slots())
|
for(auto s : army->Slots())
|
||||||
{
|
{
|
||||||
|
@ -1225,11 +1225,11 @@ void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town )
|
|||||||
void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus &bonus, bool gain )
|
void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus &bonus, bool gain )
|
||||||
{
|
{
|
||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
if (bonus.type == Bonus::NONE)
|
if (bonus.type == BonusType::NONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
adventureInt->onHeroChanged(hero);
|
adventureInt->onHeroChanged(hero);
|
||||||
if ((bonus.type == Bonus::FLYING_MOVEMENT || bonus.type == Bonus::WATER_WALKING) && !gain)
|
if ((bonus.type == BonusType::FLYING_MOVEMENT || bonus.type == BonusType::WATER_WALKING) && !gain)
|
||||||
{
|
{
|
||||||
//recalculate paths because hero has lost bonus influencing pathfinding
|
//recalculate paths because hero has lost bonus influencing pathfinding
|
||||||
localState->erasePath(hero);
|
localState->erasePath(hero);
|
||||||
|
@ -706,7 +706,7 @@ void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack &
|
|||||||
|
|
||||||
const CStack *activated = gs.curB->battleGetStackByID(pack.stack);
|
const CStack *activated = gs.curB->battleGetStackByID(pack.stack);
|
||||||
PlayerColor playerToCall; //pack.player that will move activated stack
|
PlayerColor playerToCall; //pack.player that will move activated stack
|
||||||
if (activated->hasBonusOfType(Bonus::HYPNOTIZED))
|
if (activated->hasBonusOfType(BonusType::HYPNOTIZED))
|
||||||
{
|
{
|
||||||
playerToCall = (gs.curB->sides[0].color == activated->unitOwner()
|
playerToCall = (gs.curB->sides[0].color == activated->unitOwner()
|
||||||
? gs.curB->sides[1].color
|
? gs.curB->sides[1].color
|
||||||
|
@ -140,7 +140,7 @@ bool BattleActionsController::isActiveStackSpellcaster() const
|
|||||||
if (!casterStack)
|
if (!casterStack)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool spellcaster = casterStack->hasBonusOfType(Bonus::SPELLCASTER);
|
bool spellcaster = casterStack->hasBonusOfType(BonusType::SPELLCASTER);
|
||||||
return (spellcaster && casterStack->canCast());
|
return (spellcaster && casterStack->canCast());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ void BattleActionsController::reorderPossibleActionsPriority(const CStack * stac
|
|||||||
case PossiblePlayerBattleAction::NO_LOCATION:
|
case PossiblePlayerBattleAction::NO_LOCATION:
|
||||||
case PossiblePlayerBattleAction::FREE_LOCATION:
|
case PossiblePlayerBattleAction::FREE_LOCATION:
|
||||||
case PossiblePlayerBattleAction::OBSTACLE:
|
case PossiblePlayerBattleAction::OBSTACLE:
|
||||||
if(!stack->hasBonusOfType(Bonus::NO_SPELLCAST_BY_DEFAULT) && context == MouseHoveredHexContext::OCCUPIED_HEX)
|
if(!stack->hasBonusOfType(BonusType::NO_SPELLCAST_BY_DEFAULT) && context == MouseHoveredHexContext::OCCUPIED_HEX)
|
||||||
return 1;
|
return 1;
|
||||||
else
|
else
|
||||||
return 100;//bottom priority
|
return 100;//bottom priority
|
||||||
@ -349,7 +349,7 @@ void BattleActionsController::actionSetCursor(PossiblePlayerBattleAction action,
|
|||||||
|
|
||||||
case PossiblePlayerBattleAction::MOVE_TACTICS:
|
case PossiblePlayerBattleAction::MOVE_TACTICS:
|
||||||
case PossiblePlayerBattleAction::MOVE_STACK:
|
case PossiblePlayerBattleAction::MOVE_STACK:
|
||||||
if (owner.stacksController->getActiveStack()->hasBonusOfType(Bonus::FLYING))
|
if (owner.stacksController->getActiveStack()->hasBonusOfType(BonusType::FLYING))
|
||||||
CCS->curh->set(Cursor::Combat::FLY);
|
CCS->curh->set(Cursor::Combat::FLY);
|
||||||
else
|
else
|
||||||
CCS->curh->set(Cursor::Combat::MOVE);
|
CCS->curh->set(Cursor::Combat::MOVE);
|
||||||
@ -434,7 +434,7 @@ std::string BattleActionsController::actionGetStatusMessage(PossiblePlayerBattle
|
|||||||
|
|
||||||
case PossiblePlayerBattleAction::MOVE_TACTICS:
|
case PossiblePlayerBattleAction::MOVE_TACTICS:
|
||||||
case PossiblePlayerBattleAction::MOVE_STACK:
|
case PossiblePlayerBattleAction::MOVE_STACK:
|
||||||
if (owner.stacksController->getActiveStack()->hasBonusOfType(Bonus::FLYING))
|
if (owner.stacksController->getActiveStack()->hasBonusOfType(BonusType::FLYING))
|
||||||
return (boost::format(CGI->generaltexth->allTexts[295]) % owner.stacksController->getActiveStack()->getName()).str(); //Fly %s here
|
return (boost::format(CGI->generaltexth->allTexts[295]) % owner.stacksController->getActiveStack()->getName()).str(); //Fly %s here
|
||||||
else
|
else
|
||||||
return (boost::format(CGI->generaltexth->allTexts[294]) % owner.stacksController->getActiveStack()->getName()).str(); //Move %s here
|
return (boost::format(CGI->generaltexth->allTexts[294]) % owner.stacksController->getActiveStack()->getName()).str(); //Move %s here
|
||||||
@ -863,7 +863,7 @@ void BattleActionsController::tryActivateStackSpellcasting(const CStack *casterS
|
|||||||
{
|
{
|
||||||
creatureSpells.clear();
|
creatureSpells.clear();
|
||||||
|
|
||||||
bool spellcaster = casterStack->hasBonusOfType(Bonus::SPELLCASTER);
|
bool spellcaster = casterStack->hasBonusOfType(BonusType::SPELLCASTER);
|
||||||
if(casterStack->canCast() && spellcaster)
|
if(casterStack->canCast() && spellcaster)
|
||||||
{
|
{
|
||||||
// faerie dragon can cast only one, randomly selected spell until their next move
|
// faerie dragon can cast only one, randomly selected spell until their next move
|
||||||
@ -874,7 +874,7 @@ void BattleActionsController::tryActivateStackSpellcasting(const CStack *casterS
|
|||||||
creatureSpells.push_back(spellToCast);
|
creatureSpells.push_back(spellToCast);
|
||||||
}
|
}
|
||||||
|
|
||||||
TConstBonusListPtr bl = casterStack->getBonuses(Selector::type()(Bonus::SPELLCASTER));
|
TConstBonusListPtr bl = casterStack->getBonuses(Selector::type()(BonusType::SPELLCASTER));
|
||||||
|
|
||||||
for (auto const & bonus : *bl)
|
for (auto const & bonus : *bl)
|
||||||
{
|
{
|
||||||
|
@ -370,7 +370,7 @@ bool MovementAnimation::init()
|
|||||||
distanceX = endPosition.x - begPosition.x;
|
distanceX = endPosition.x - begPosition.x;
|
||||||
distanceY = endPosition.y - begPosition.y;
|
distanceY = endPosition.y - begPosition.y;
|
||||||
|
|
||||||
if (stack->hasBonus(Selector::type()(Bonus::FLYING)))
|
if (stack->hasBonus(Selector::type()(BonusType::FLYING)))
|
||||||
{
|
{
|
||||||
float distance = static_cast<float>(sqrt(distanceX * distanceX + distanceY * distanceY));
|
float distance = static_cast<float>(sqrt(distanceX * distanceX + distanceY * distanceY));
|
||||||
progressPerSecond = AnimationControls::getFlightDistance(stack->unitType()) / distance;
|
progressPerSecond = AnimationControls::getFlightDistance(stack->unitType()) / distance;
|
||||||
|
@ -65,21 +65,21 @@ void BattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bt
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//don't show animation when no HP is regenerated
|
//don't show animation when no HP is regenerated
|
||||||
switch(bte.effect)
|
switch(static_cast<BonusType>(bte.effect))
|
||||||
{
|
{
|
||||||
case Bonus::HP_REGENERATION:
|
case BonusType::HP_REGENERATION:
|
||||||
displayEffect(EBattleEffect::REGENERATION, "REGENER", stack->getPosition());
|
displayEffect(EBattleEffect::REGENERATION, "REGENER", stack->getPosition());
|
||||||
break;
|
break;
|
||||||
case Bonus::MANA_DRAIN:
|
case BonusType::MANA_DRAIN:
|
||||||
displayEffect(EBattleEffect::MANA_DRAIN, "MANADRAI", stack->getPosition());
|
displayEffect(EBattleEffect::MANA_DRAIN, "MANADRAI", stack->getPosition());
|
||||||
break;
|
break;
|
||||||
case Bonus::POISON:
|
case BonusType::POISON:
|
||||||
displayEffect(EBattleEffect::POISON, "POISON", stack->getPosition());
|
displayEffect(EBattleEffect::POISON, "POISON", stack->getPosition());
|
||||||
break;
|
break;
|
||||||
case Bonus::FEAR:
|
case BonusType::FEAR:
|
||||||
displayEffect(EBattleEffect::FEAR, "FEAR", stack->getPosition());
|
displayEffect(EBattleEffect::FEAR, "FEAR", stack->getPosition());
|
||||||
break;
|
break;
|
||||||
case Bonus::MORALE:
|
case BonusType::MORALE:
|
||||||
{
|
{
|
||||||
std::string hlp = CGI->generaltexth->allTexts[33];
|
std::string hlp = CGI->generaltexth->allTexts[33];
|
||||||
boost::algorithm::replace_first(hlp,"%s",(stack->getName()));
|
boost::algorithm::replace_first(hlp,"%s",(stack->getName()));
|
||||||
|
@ -107,7 +107,7 @@ BattleHex BattleStacksController::getStackCurrentPosition(const CStack * stack)
|
|||||||
if ( !stackAnimation.at(stack->unitId())->isMoving())
|
if ( !stackAnimation.at(stack->unitId())->isMoving())
|
||||||
return stack->getPosition();
|
return stack->getPosition();
|
||||||
|
|
||||||
if (stack->hasBonusOfType(Bonus::FLYING) && stackAnimation.at(stack->unitId())->getType() == ECreatureAnimType::MOVING )
|
if (stack->hasBonusOfType(BonusType::FLYING) && stackAnimation.at(stack->unitId())->getType() == ECreatureAnimType::MOVING )
|
||||||
return BattleHex::HEX_AFTER_ALL;
|
return BattleHex::HEX_AFTER_ALL;
|
||||||
|
|
||||||
for (auto & anim : currentAnimations)
|
for (auto & anim : currentAnimations)
|
||||||
@ -247,7 +247,7 @@ void BattleStacksController::setActiveStack(const CStack *stack)
|
|||||||
bool BattleStacksController::stackNeedsAmountBox(const CStack * stack) const
|
bool BattleStacksController::stackNeedsAmountBox(const CStack * stack) const
|
||||||
{
|
{
|
||||||
//do not show box for singular war machines, stacked war machines with box shown are supported as extension feature
|
//do not show box for singular war machines, stacked war machines with box shown are supported as extension feature
|
||||||
if(stack->hasBonusOfType(Bonus::SIEGE_WEAPON) && stack->getCount() == 1)
|
if(stack->hasBonusOfType(BonusType::SIEGE_WEAPON) && stack->getCount() == 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(!stack->alive())
|
if(!stack->alive())
|
||||||
@ -528,7 +528,7 @@ void BattleStacksController::stackMoved(const CStack *stack, std::vector<BattleH
|
|||||||
addNewAnim(new MovementStartAnimation(owner, stack));
|
addNewAnim(new MovementStartAnimation(owner, stack));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!stack->hasBonus(Selector::typeSubtype(Bonus::FLYING, 1)))
|
if (!stack->hasBonus(Selector::typeSubtype(BonusType::FLYING, 1)))
|
||||||
{
|
{
|
||||||
owner.addToAnimationStage(EAnimationEvents::MOVEMENT, [&]()
|
owner.addToAnimationStage(EAnimationEvents::MOVEMENT, [&]()
|
||||||
{
|
{
|
||||||
@ -793,7 +793,7 @@ void BattleStacksController::removeExpiredColorFilters()
|
|||||||
{
|
{
|
||||||
if (!filter.persistent)
|
if (!filter.persistent)
|
||||||
{
|
{
|
||||||
if (filter.source && !filter.target->hasBonus(Selector::source(Bonus::SPELL_EFFECT, filter.source->id), Selector::all))
|
if (filter.source && !filter.target->hasBonus(Selector::source(BonusSource::SPELL_EFFECT, filter.source->id), Selector::all))
|
||||||
return true;
|
return true;
|
||||||
if (filter.effect == ColorFilter::genEmptyShifter())
|
if (filter.effect == ColorFilter::genEmptyShifter())
|
||||||
return true;
|
return true;
|
||||||
|
@ -426,11 +426,11 @@ void BattleWindow::bSpellf()
|
|||||||
{
|
{
|
||||||
//TODO: move to spell mechanics, add more information to spell cast problem
|
//TODO: move to spell mechanics, add more information to spell cast problem
|
||||||
//Handle Orb of Inhibition-like effects -> we want to display dialog with info, why casting is impossible
|
//Handle Orb of Inhibition-like effects -> we want to display dialog with info, why casting is impossible
|
||||||
auto blockingBonus = owner.currentHero()->getBonusLocalFirst(Selector::type()(Bonus::BLOCK_ALL_MAGIC));
|
auto blockingBonus = owner.currentHero()->getBonusLocalFirst(Selector::type()(BonusType::BLOCK_ALL_MAGIC));
|
||||||
if (!blockingBonus)
|
if (!blockingBonus)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (blockingBonus->source == Bonus::ARTIFACT)
|
if (blockingBonus->source == BonusSource::ARTIFACT)
|
||||||
{
|
{
|
||||||
const auto artID = ArtifactID(blockingBonus->sid);
|
const auto artID = ArtifactID(blockingBonus->sid);
|
||||||
//If we have artifact, put name of our hero. Otherwise assume it's the enemy.
|
//If we have artifact, put name of our hero. Otherwise assume it's the enemy.
|
||||||
|
@ -393,21 +393,21 @@ void MoraleLuckBox::set(const AFactionMember * node)
|
|||||||
text = CGI->generaltexth->arraytxt[textId[morale]];
|
text = CGI->generaltexth->arraytxt[textId[morale]];
|
||||||
boost::algorithm::replace_first(text,"%s",CGI->generaltexth->arraytxt[neutralDescr[morale]-mrlt]);
|
boost::algorithm::replace_first(text,"%s",CGI->generaltexth->arraytxt[neutralDescr[morale]-mrlt]);
|
||||||
|
|
||||||
if (morale && node && (node->getBonusBearer()->hasBonusOfType(Bonus::UNDEAD)
|
if (morale && node && (node->getBonusBearer()->hasBonusOfType(BonusType::UNDEAD)
|
||||||
|| node->getBonusBearer()->hasBonusOfType(Bonus::NON_LIVING)))
|
|| node->getBonusBearer()->hasBonusOfType(BonusType::NON_LIVING)))
|
||||||
{
|
{
|
||||||
text += CGI->generaltexth->arraytxt[113]; //unaffected by morale
|
text += CGI->generaltexth->arraytxt[113]; //unaffected by morale
|
||||||
bonusValue = 0;
|
bonusValue = 0;
|
||||||
}
|
}
|
||||||
else if(morale && node && node->getBonusBearer()->hasBonusOfType(Bonus::NO_MORALE))
|
else if(morale && node && node->getBonusBearer()->hasBonusOfType(BonusType::NO_MORALE))
|
||||||
{
|
{
|
||||||
auto noMorale = node->getBonusBearer()->getBonus(Selector::type()(Bonus::NO_MORALE));
|
auto noMorale = node->getBonusBearer()->getBonus(Selector::type()(BonusType::NO_MORALE));
|
||||||
text += "\n" + noMorale->Description();
|
text += "\n" + noMorale->Description();
|
||||||
bonusValue = 0;
|
bonusValue = 0;
|
||||||
}
|
}
|
||||||
else if (!morale && node && node->getBonusBearer()->hasBonusOfType(Bonus::NO_LUCK))
|
else if (!morale && node && node->getBonusBearer()->hasBonusOfType(BonusType::NO_LUCK))
|
||||||
{
|
{
|
||||||
auto noLuck = node->getBonusBearer()->getBonus(Selector::type()(Bonus::NO_LUCK));
|
auto noLuck = node->getBonusBearer()->getBonus(Selector::type()(BonusType::NO_LUCK));
|
||||||
text += "\n" + noLuck->Description();
|
text += "\n" + noLuck->Description();
|
||||||
bonusValue = 0;
|
bonusValue = 0;
|
||||||
}
|
}
|
||||||
@ -458,7 +458,7 @@ CCreaturePic::CCreaturePic(int x, int y, const CCreature * cre, bool Big, bool A
|
|||||||
bg = std::make_shared<CPicture>((*CGI->townh)[faction]->creatureBg120);
|
bg = std::make_shared<CPicture>((*CGI->townh)[faction]->creatureBg120);
|
||||||
anim = std::make_shared<CCreatureAnim>(0, 0, cre->animDefName);
|
anim = std::make_shared<CCreatureAnim>(0, 0, cre->animDefName);
|
||||||
anim->clipRect(cre->isDoubleWide()?170:150, 155, bg->pos.w, bg->pos.h);
|
anim->clipRect(cre->isDoubleWide()?170:150, 155, bg->pos.w, bg->pos.h);
|
||||||
anim->startPreview(cre->hasBonusOfType(Bonus::SIEGE_WEAPON));
|
anim->startPreview(cre->hasBonusOfType(BonusType::SIEGE_WEAPON));
|
||||||
|
|
||||||
amount = std::make_shared<CLabel>(bg->pos.w, bg->pos.h, FONT_MEDIUM, ETextAlignment::BOTTOMRIGHT, Colors::WHITE);
|
amount = std::make_shared<CLabel>(bg->pos.w, bg->pos.h, FONT_MEDIUM, ETextAlignment::BOTTOMRIGHT, Colors::WHITE);
|
||||||
|
|
||||||
|
@ -1705,7 +1705,7 @@ CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance *
|
|||||||
sizes.y+=20;
|
sizes.y+=20;
|
||||||
values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[388], CGI->generaltexth->fcommands[3], getMyCreature()->getMaxHealth()));
|
values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[388], CGI->generaltexth->fcommands[3], getMyCreature()->getMaxHealth()));
|
||||||
sizes.y+=21;
|
sizes.y+=21;
|
||||||
values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[193], CGI->generaltexth->fcommands[4], getMyCreature()->valOfBonuses(Bonus::STACKS_SPEED)));
|
values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[193], CGI->generaltexth->fcommands[4], getMyCreature()->valOfBonuses(BonusType::STACKS_SPEED)));
|
||||||
sizes.y+=20;
|
sizes.y+=20;
|
||||||
values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[194], CGI->generaltexth->fcommands[5], town->creatureGrowth(level)));
|
values.push_back(std::make_shared<LabeledValue>(sizes, CGI->generaltexth->allTexts[194], CGI->generaltexth->fcommands[5], town->creatureGrowth(level)));
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ CStackWindow::ActiveSpellsSection::ActiveSpellsSection(CStackWindow * owner, int
|
|||||||
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
|
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
|
||||||
boost::replace_first(spellText, "%s", spell->getNameTranslated());
|
boost::replace_first(spellText, "%s", spell->getNameTranslated());
|
||||||
//FIXME: support permanent duration
|
//FIXME: support permanent duration
|
||||||
int duration = battleStack->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT,effect))->turnsRemain;
|
int duration = battleStack->getBonusLocalFirst(Selector::source(BonusSource::SPELL_EFFECT,effect))->turnsRemain;
|
||||||
boost::replace_first(spellText, "%d", std::to_string(duration));
|
boost::replace_first(spellText, "%d", std::to_string(duration));
|
||||||
|
|
||||||
spellIcons.push_back(std::make_shared<CAnimImage>("SpellInt", effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));
|
spellIcons.push_back(std::make_shared<CAnimImage>("SpellInt", effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));
|
||||||
@ -510,7 +510,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
|
|||||||
name = std::make_shared<CLabel>(215, 12, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, parent->info->getName());
|
name = std::make_shared<CLabel>(215, 12, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, parent->info->getName());
|
||||||
|
|
||||||
int dmgMultiply = 1;
|
int dmgMultiply = 1;
|
||||||
if(parent->info->owner && parent->info->stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
|
if(parent->info->owner && parent->info->stackNode->hasBonusOfType(BonusType::SIEGE_WEAPON))
|
||||||
dmgMultiply += parent->info->owner->getPrimSkillLevel(PrimarySkill::ATTACK);
|
dmgMultiply += parent->info->owner->getPrimSkillLevel(PrimarySkill::ATTACK);
|
||||||
|
|
||||||
icons = std::make_shared<CPicture>("stackWindow/icons", 117, 32);
|
icons = std::make_shared<CPicture>("stackWindow/icons", 117, 32);
|
||||||
@ -539,8 +539,8 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const bool shooter = parent->info->stackNode->hasBonusOfType(Bonus::SHOOTER) && parent->info->stackNode->valOfBonuses(Bonus::SHOTS);
|
const bool shooter = parent->info->stackNode->hasBonusOfType(BonusType::SHOOTER) && parent->info->stackNode->valOfBonuses(BonusType::SHOTS);
|
||||||
const bool caster = parent->info->stackNode->valOfBonuses(Bonus::CASTS);
|
const bool caster = parent->info->stackNode->valOfBonuses(BonusType::CASTS);
|
||||||
|
|
||||||
addStatLabel(EStat::ATTACK, parent->info->creature->getAttack(shooter), parent->info->stackNode->getAttack(shooter));
|
addStatLabel(EStat::ATTACK, parent->info->creature->getAttack(shooter), parent->info->stackNode->getAttack(shooter));
|
||||||
addStatLabel(EStat::DEFENCE, parent->info->creature->getDefense(shooter), parent->info->stackNode->getDefense(shooter));
|
addStatLabel(EStat::DEFENCE, parent->info->creature->getDefense(shooter), parent->info->stackNode->getDefense(shooter));
|
||||||
@ -549,9 +549,9 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
|
|||||||
addStatLabel(EStat::SPEED, parent->info->creature->speed(), parent->info->stackNode->speed());
|
addStatLabel(EStat::SPEED, parent->info->creature->speed(), parent->info->stackNode->speed());
|
||||||
|
|
||||||
if(shooter)
|
if(shooter)
|
||||||
addStatLabel(EStat::SHOTS, parent->info->stackNode->valOfBonuses(Bonus::SHOTS));
|
addStatLabel(EStat::SHOTS, parent->info->stackNode->valOfBonuses(BonusType::SHOTS));
|
||||||
if(caster)
|
if(caster)
|
||||||
addStatLabel(EStat::MANA, parent->info->stackNode->valOfBonuses(Bonus::CASTS));
|
addStatLabel(EStat::MANA, parent->info->stackNode->valOfBonuses(BonusType::CASTS));
|
||||||
|
|
||||||
morale->set(parent->info->stackNode);
|
morale->set(parent->info->stackNode);
|
||||||
luck->set(parent->info->stackNode);
|
luck->set(parent->info->stackNode);
|
||||||
|
@ -66,7 +66,7 @@ int64_t CHeroWithMaybePickedArtifact::getTreeVersion() const
|
|||||||
si32 CHeroWithMaybePickedArtifact::manaLimit() const
|
si32 CHeroWithMaybePickedArtifact::manaLimit() const
|
||||||
{
|
{
|
||||||
//TODO: reduplicate code with CGHeroInstance
|
//TODO: reduplicate code with CGHeroInstance
|
||||||
return si32(getPrimSkillLevel(PrimarySkill::KNOWLEDGE) * (valOfBonuses(Bonus::MANA_PER_KNOWLEDGE)));
|
return si32(getPrimSkillLevel(PrimarySkill::KNOWLEDGE) * (valOfBonuses(BonusType::MANA_PER_KNOWLEDGE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const IBonusBearer * CHeroWithMaybePickedArtifact::getBonusBearer() const
|
const IBonusBearer * CHeroWithMaybePickedArtifact::getBonusBearer() const
|
||||||
@ -334,7 +334,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
|
|||||||
|
|
||||||
dismissButton->block(!!curHero->visitedTown || noDismiss);
|
dismissButton->block(!!curHero->visitedTown || noDismiss);
|
||||||
|
|
||||||
if(curHero->valOfBonuses(Selector::type()(Bonus::BEFORE_BATTLE_REPOSITION)) == 0)
|
if(curHero->valOfBonuses(Selector::type()(BonusType::BEFORE_BATTLE_REPOSITION)) == 0)
|
||||||
{
|
{
|
||||||
tacticsButton->block(true);
|
tacticsButton->block(true);
|
||||||
}
|
}
|
||||||
|
@ -586,7 +586,7 @@ void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstan
|
|||||||
std::vector<const CGHeroInstance*> heroes = LOCPLINT->cb->getHeroesInfo(true);
|
std::vector<const CGHeroInstance*> heroes = LOCPLINT->cb->getHeroesInfo(true);
|
||||||
for(auto & heroe : heroes)
|
for(auto & heroe : heroes)
|
||||||
{
|
{
|
||||||
totalIncome += heroe->valOfBonuses(Selector::typeSubtype(Bonus::GENERATE_RESOURCE, GameResID(EGameResID::GOLD)));
|
totalIncome += heroe->valOfBonuses(Selector::typeSubtype(BonusType::GENERATE_RESOURCE, GameResID(EGameResID::GOLD)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add town income of all towns
|
//Add town income of all towns
|
||||||
|
@ -28,6 +28,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
|||||||
${MAIN_LIB_DIR}/battle/Unit.cpp
|
${MAIN_LIB_DIR}/battle/Unit.cpp
|
||||||
|
|
||||||
${MAIN_LIB_DIR}/bonuses/Bonus.cpp
|
${MAIN_LIB_DIR}/bonuses/Bonus.cpp
|
||||||
|
${MAIN_LIB_DIR}/bonuses/BonusEnum.cpp
|
||||||
${MAIN_LIB_DIR}/bonuses/BonusList.cpp
|
${MAIN_LIB_DIR}/bonuses/BonusList.cpp
|
||||||
${MAIN_LIB_DIR}/bonuses/BonusParams.cpp
|
${MAIN_LIB_DIR}/bonuses/BonusParams.cpp
|
||||||
${MAIN_LIB_DIR}/bonuses/BonusSelector.cpp
|
${MAIN_LIB_DIR}/bonuses/BonusSelector.cpp
|
||||||
@ -311,6 +312,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
|||||||
${MAIN_LIB_DIR}/battle/Unit.h
|
${MAIN_LIB_DIR}/battle/Unit.h
|
||||||
|
|
||||||
${MAIN_LIB_DIR}/bonuses/Bonus.h
|
${MAIN_LIB_DIR}/bonuses/Bonus.h
|
||||||
|
${MAIN_LIB_DIR}/bonuses/BonusEnum.h
|
||||||
${MAIN_LIB_DIR}/bonuses/BonusList.h
|
${MAIN_LIB_DIR}/bonuses/BonusList.h
|
||||||
${MAIN_LIB_DIR}/bonuses/BonusParams.h
|
${MAIN_LIB_DIR}/bonuses/BonusParams.h
|
||||||
${MAIN_LIB_DIR}/bonuses/BonusSelector.h
|
${MAIN_LIB_DIR}/bonuses/BonusSelector.h
|
||||||
|
@ -232,7 +232,7 @@
|
|||||||
},
|
},
|
||||||
"special":{
|
"special":{
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Special spell. Can be given only by Bonus::SPELL"
|
"description": "Special spell. Can be given only by BonusType::SPELL"
|
||||||
},
|
},
|
||||||
"nonMagical":{
|
"nonMagical":{
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
@ -34,7 +34,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(Bonus::NO_TERRAIN_PENALTY, any);
|
static const auto selectorNoTerrainPenalty = Selector::typeSubtype(BonusType::NO_TERRAIN_PENALTY, 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.
|
||||||
@ -44,7 +44,7 @@ TerrainId AFactionMember::getNativeTerrain() const
|
|||||||
|
|
||||||
int32_t AFactionMember::magicResistance() const
|
int32_t AFactionMember::magicResistance() const
|
||||||
{
|
{
|
||||||
si32 val = getBonusBearer()->valOfBonuses(Selector::type()(Bonus::MAGIC_RESISTANCE));
|
si32 val = getBonusBearer()->valOfBonuses(Selector::type()(BonusType::MAGIC_RESISTANCE));
|
||||||
vstd::amin (val, 100);
|
vstd::amin (val, 100);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -53,7 +53,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(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
|
static const auto selector = Selector::typeSubtype(BonusType::PRIMARY_SKILL, PrimarySkill::ATTACK);
|
||||||
|
|
||||||
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
||||||
}
|
}
|
||||||
@ -62,7 +62,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(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
|
static const auto selector = Selector::typeSubtype(BonusType::PRIMARY_SKILL, PrimarySkill::DEFENSE);
|
||||||
|
|
||||||
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
||||||
}
|
}
|
||||||
@ -70,20 +70,20 @@ 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(Bonus::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 1));
|
static const auto selector = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 1));
|
||||||
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(Bonus::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 2));
|
static const auto selector = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 2));
|
||||||
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AFactionMember::getPrimSkillLevel(PrimarySkill::PrimarySkill id) const
|
int AFactionMember::getPrimSkillLevel(PrimarySkill::PrimarySkill id) const
|
||||||
{
|
{
|
||||||
static const CSelector selectorAllSkills = Selector::type()(Bonus::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()(id));
|
auto ret = allSkills->valOfBonuses(Selector::subtype()(id));
|
||||||
@ -93,8 +93,8 @@ int AFactionMember::getPrimSkillLevel(PrimarySkill::PrimarySkill id) const
|
|||||||
|
|
||||||
int AFactionMember::moraleValAndBonusList(TConstBonusListPtr & bonusList) const
|
int AFactionMember::moraleValAndBonusList(TConstBonusListPtr & bonusList) const
|
||||||
{
|
{
|
||||||
static const auto unaffectedByMoraleSelector = Selector::type()(Bonus::NON_LIVING).Or(Selector::type()(Bonus::UNDEAD))
|
static const auto unaffectedByMoraleSelector = Selector::type()(BonusType::NON_LIVING).Or(Selector::type()(BonusType::UNDEAD))
|
||||||
.Or(Selector::type()(Bonus::SIEGE_WEAPON)).Or(Selector::type()(Bonus::NO_MORALE));
|
.Or(Selector::type()(BonusType::SIEGE_WEAPON)).Or(Selector::type()(BonusType::NO_MORALE));
|
||||||
|
|
||||||
static const std::string cachingStrUn = "AFactionMember::unaffectedByMoraleSelector";
|
static const std::string cachingStrUn = "AFactionMember::unaffectedByMoraleSelector";
|
||||||
auto unaffected = getBonusBearer()->hasBonus(unaffectedByMoraleSelector, cachingStrUn);
|
auto unaffected = getBonusBearer()->hasBonus(unaffectedByMoraleSelector, cachingStrUn);
|
||||||
@ -105,7 +105,7 @@ int AFactionMember::moraleValAndBonusList(TConstBonusListPtr & bonusList) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const auto moraleSelector = Selector::type()(Bonus::MORALE);
|
static const auto moraleSelector = Selector::type()(BonusType::MORALE);
|
||||||
static const std::string cachingStrMor = "type_MORALE";
|
static const std::string cachingStrMor = "type_MORALE";
|
||||||
bonusList = getBonusBearer()->getBonuses(moraleSelector, cachingStrMor);
|
bonusList = getBonusBearer()->getBonuses(moraleSelector, cachingStrMor);
|
||||||
|
|
||||||
@ -117,14 +117,14 @@ int AFactionMember::moraleValAndBonusList(TConstBonusListPtr & bonusList) const
|
|||||||
|
|
||||||
int AFactionMember::luckValAndBonusList(TConstBonusListPtr & bonusList) const
|
int AFactionMember::luckValAndBonusList(TConstBonusListPtr & bonusList) const
|
||||||
{
|
{
|
||||||
if(getBonusBearer()->hasBonusOfType(Bonus::NO_LUCK))
|
if(getBonusBearer()->hasBonusOfType(BonusType::NO_LUCK))
|
||||||
{
|
{
|
||||||
if(bonusList && !bonusList->empty())
|
if(bonusList && !bonusList->empty())
|
||||||
bonusList = std::make_shared<const BonusList>();
|
bonusList = std::make_shared<const BonusList>();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const auto luckSelector = Selector::type()(Bonus::LUCK);
|
static const auto luckSelector = Selector::type()(BonusType::LUCK);
|
||||||
static const std::string cachingStrLuck = "type_LUCK";
|
static const std::string cachingStrLuck = "type_LUCK";
|
||||||
bonusList = getBonusBearer()->getBonuses(luckSelector, cachingStrLuck);
|
bonusList = getBonusBearer()->getBonuses(luckSelector, cachingStrLuck);
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ int AFactionMember::luckVal() const
|
|||||||
ui32 ACreature::getMaxHealth() const
|
ui32 ACreature::getMaxHealth() const
|
||||||
{
|
{
|
||||||
const std::string cachingStr = "type_STACK_HEALTH";
|
const std::string cachingStr = "type_STACK_HEALTH";
|
||||||
static const auto selector = Selector::type()(Bonus::STACK_HEALTH);
|
static const auto selector = Selector::type()(BonusType::STACK_HEALTH);
|
||||||
auto value = getBonusBearer()->valOfBonuses(selector, cachingStr);
|
auto value = getBonusBearer()->valOfBonuses(selector, cachingStr);
|
||||||
return std::max(1, value); //never 0
|
return std::max(1, value); //never 0
|
||||||
}
|
}
|
||||||
@ -157,26 +157,26 @@ ui32 ACreature::getMaxHealth() const
|
|||||||
ui32 ACreature::speed(int turn, bool useBind) const
|
ui32 ACreature::speed(int turn, bool useBind) const
|
||||||
{
|
{
|
||||||
//war machines cannot move
|
//war machines cannot move
|
||||||
if(getBonusBearer()->hasBonus(Selector::type()(Bonus::SIEGE_WEAPON).And(Selector::turns(turn))))
|
if(getBonusBearer()->hasBonus(Selector::type()(BonusType::SIEGE_WEAPON).And(Selector::turns(turn))))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
//bind effect check - doesn't influence stack initiative
|
//bind effect check - doesn't influence stack initiative
|
||||||
if(useBind && getBonusBearer()->hasBonus(Selector::type()(Bonus::BIND_EFFECT).And(Selector::turns(turn))))
|
if(useBind && getBonusBearer()->hasBonus(Selector::type()(BonusType::BIND_EFFECT).And(Selector::turns(turn))))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getBonusBearer()->valOfBonuses(Selector::type()(Bonus::STACKS_SPEED).And(Selector::turns(turn)));
|
return getBonusBearer()->valOfBonuses(Selector::type()(BonusType::STACKS_SPEED).And(Selector::turns(turn)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ACreature::isLiving() const //TODO: theoreticaly there exists "LIVING" bonus in stack experience documentation
|
bool ACreature::isLiving() const //TODO: theoreticaly there exists "LIVING" bonus in stack experience documentation
|
||||||
{
|
{
|
||||||
static const std::string cachingStr = "ACreature::isLiving";
|
static const std::string cachingStr = "ACreature::isLiving";
|
||||||
static const CSelector selector = Selector::type()(Bonus::UNDEAD)
|
static const CSelector selector = Selector::type()(BonusType::UNDEAD)
|
||||||
.Or(Selector::type()(Bonus::NON_LIVING))
|
.Or(Selector::type()(BonusType::NON_LIVING))
|
||||||
.Or(Selector::type()(Bonus::GARGOYLE))
|
.Or(Selector::type()(BonusType::GARGOYLE))
|
||||||
.Or(Selector::type()(Bonus::SIEGE_WEAPON));
|
.Or(Selector::type()(BonusType::SIEGE_WEAPON));
|
||||||
|
|
||||||
return !getBonusBearer()->hasBonus(selector, cachingStr);
|
return !getBonusBearer()->hasBonus(selector, cachingStr);
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ BattleFieldInfo * BattleFieldHandler::loadFromJson(const std::string & scope, co
|
|||||||
{
|
{
|
||||||
auto bonus = JsonUtils::parseBonus(b);
|
auto bonus = JsonUtils::parseBonus(b);
|
||||||
|
|
||||||
bonus->source = Bonus::TERRAIN_OVERLAY;
|
bonus->source = BonusSource::TERRAIN_OVERLAY;
|
||||||
bonus->sid = info->getIndex();
|
bonus->sid = info->getIndex();
|
||||||
bonus->duration = Bonus::ONE_BATTLE;
|
bonus->duration = BonusDuration::ONE_BATTLE;
|
||||||
|
|
||||||
info->bonuses.push_back(bonus);
|
info->bonuses.push_back(bonus);
|
||||||
}
|
}
|
||||||
|
@ -256,8 +256,8 @@ std::string CArtifact::nodeName() const
|
|||||||
|
|
||||||
void CArtifact::addNewBonus(const std::shared_ptr<Bonus>& b)
|
void CArtifact::addNewBonus(const std::shared_ptr<Bonus>& b)
|
||||||
{
|
{
|
||||||
b->source = Bonus::ARTIFACT;
|
b->source = BonusSource::ARTIFACT;
|
||||||
b->duration = Bonus::PERMANENT;
|
b->duration = BonusDuration::PERMANENT;
|
||||||
b->description = getNameTranslated();
|
b->description = getNameTranslated();
|
||||||
CBonusSystemNode::addNewBonus(b);
|
CBonusSystemNode::addNewBonus(b);
|
||||||
}
|
}
|
||||||
@ -275,21 +275,21 @@ void CArtifact::serializeJson(JsonSerializeFormat & handler)
|
|||||||
void CGrowingArtifact::levelUpArtifact (CArtifactInstance * art)
|
void CGrowingArtifact::levelUpArtifact (CArtifactInstance * art)
|
||||||
{
|
{
|
||||||
auto b = std::make_shared<Bonus>();
|
auto b = std::make_shared<Bonus>();
|
||||||
b->type = Bonus::LEVEL_COUNTER;
|
b->type = BonusType::LEVEL_COUNTER;
|
||||||
b->val = 1;
|
b->val = 1;
|
||||||
b->duration = Bonus::COMMANDER_KILLED;
|
b->duration = BonusDuration::COMMANDER_KILLED;
|
||||||
art->accumulateBonus(b);
|
art->accumulateBonus(b);
|
||||||
|
|
||||||
for(const auto & bonus : bonusesPerLevel)
|
for(const auto & bonus : bonusesPerLevel)
|
||||||
{
|
{
|
||||||
if (art->valOfBonuses(Bonus::LEVEL_COUNTER) % bonus.first == 0) //every n levels
|
if (art->valOfBonuses(BonusType::LEVEL_COUNTER) % bonus.first == 0) //every n levels
|
||||||
{
|
{
|
||||||
art->accumulateBonus(std::make_shared<Bonus>(bonus.second));
|
art->accumulateBonus(std::make_shared<Bonus>(bonus.second));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(const auto & bonus : thresholdBonuses)
|
for(const auto & bonus : thresholdBonuses)
|
||||||
{
|
{
|
||||||
if (art->valOfBonuses(Bonus::LEVEL_COUNTER) == bonus.first) //every n levels
|
if (art->valOfBonuses(BonusType::LEVEL_COUNTER) == bonus.first) //every n levels
|
||||||
{
|
{
|
||||||
art->addNewBonus(std::make_shared<Bonus>(bonus.second));
|
art->addNewBonus(std::make_shared<Bonus>(bonus.second));
|
||||||
}
|
}
|
||||||
@ -790,7 +790,7 @@ void CArtHandler::afterLoadFinalization()
|
|||||||
for(auto &bonus : art->getExportedBonusList())
|
for(auto &bonus : art->getExportedBonusList())
|
||||||
{
|
{
|
||||||
assert(art == objects[art->id]);
|
assert(art == objects[art->id]);
|
||||||
assert(bonus->source == Bonus::ARTIFACT);
|
assert(bonus->source == BonusSource::ARTIFACT);
|
||||||
bonus->sid = art->id;
|
bonus->sid = art->id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -822,7 +822,7 @@ std::string CArtifactInstance::nodeName() const
|
|||||||
CArtifactInstance * CArtifactInstance::createScroll(const SpellID & sid)
|
CArtifactInstance * CArtifactInstance::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 b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT_INSTANCE, -1, ArtifactID::SPELL_SCROLL, sid);
|
auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELL, BonusSource::ARTIFACT_INSTANCE, -1, ArtifactID::SPELL_SCROLL, sid);
|
||||||
ret->addNewBonus(b);
|
ret->addNewBonus(b);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -903,7 +903,7 @@ CArtifactInstance * CArtifactInstance::createNewArtifactInstance(CArtifact *Art)
|
|||||||
if (dynamic_cast<CGrowingArtifact *>(Art))
|
if (dynamic_cast<CGrowingArtifact *>(Art))
|
||||||
{
|
{
|
||||||
auto bonus = std::make_shared<Bonus>();
|
auto bonus = std::make_shared<Bonus>();
|
||||||
bonus->type = Bonus::LEVEL_COUNTER;
|
bonus->type = BonusType::LEVEL_COUNTER;
|
||||||
bonus->val = 0;
|
bonus->val = 0;
|
||||||
ret->addNewBonus (bonus);
|
ret->addNewBonus (bonus);
|
||||||
}
|
}
|
||||||
@ -963,7 +963,7 @@ void CArtifactInstance::deserializationFix()
|
|||||||
|
|
||||||
SpellID CArtifactInstance::getScrollSpellID() const
|
SpellID CArtifactInstance::getScrollSpellID() const
|
||||||
{
|
{
|
||||||
const auto b = getBonusLocalFirst(Selector::type()(Bonus::SPELL));
|
const auto b = getBonusLocalFirst(Selector::type()(BonusType::SPELL));
|
||||||
if(!b)
|
if(!b)
|
||||||
{
|
{
|
||||||
logMod->warn("Warning: %s doesn't bear any spell!", nodeName());
|
logMod->warn("Warning: %s doesn't bear any spell!", nodeName());
|
||||||
|
@ -66,7 +66,7 @@ CBonusTypeHandler::~CBonusTypeHandler()
|
|||||||
|
|
||||||
std::string CBonusTypeHandler::bonusToString(const std::shared_ptr<Bonus> & bonus, const IBonusBearer * bearer, bool description) const
|
std::string CBonusTypeHandler::bonusToString(const std::shared_ptr<Bonus> & bonus, const IBonusBearer * bearer, bool description) const
|
||||||
{
|
{
|
||||||
const CBonusType & bt = bonusTypes[bonus->type];
|
const CBonusType & bt = bonusTypes[vstd::to_underlying(bonus->type)];
|
||||||
if(bt.hidden)
|
if(bt.hidden)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
@ -92,14 +92,14 @@ std::string CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bo
|
|||||||
|
|
||||||
switch(bonus->type)
|
switch(bonus->type)
|
||||||
{
|
{
|
||||||
case Bonus::SPELL_IMMUNITY:
|
case BonusType::SPELL_IMMUNITY:
|
||||||
{
|
{
|
||||||
fullPath = true;
|
fullPath = true;
|
||||||
const CSpell * sp = SpellID(bonus->subtype).toSpell();
|
const CSpell * sp = SpellID(bonus->subtype).toSpell();
|
||||||
fileName = sp->getIconImmune();
|
fileName = sp->getIconImmune();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Bonus::FIRE_IMMUNITY:
|
case BonusType::FIRE_IMMUNITY:
|
||||||
switch(bonus->subtype)
|
switch(bonus->subtype)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -113,7 +113,7 @@ std::string CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bo
|
|||||||
break;//direct damage
|
break;//direct damage
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Bonus::WATER_IMMUNITY:
|
case BonusType::WATER_IMMUNITY:
|
||||||
switch(bonus->subtype)
|
switch(bonus->subtype)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -127,7 +127,7 @@ std::string CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bo
|
|||||||
break;//direct damage
|
break;//direct damage
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Bonus::AIR_IMMUNITY:
|
case BonusType::AIR_IMMUNITY:
|
||||||
switch(bonus->subtype)
|
switch(bonus->subtype)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -141,7 +141,7 @@ std::string CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bo
|
|||||||
break;//direct damage
|
break;//direct damage
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Bonus::EARTH_IMMUNITY:
|
case BonusType::EARTH_IMMUNITY:
|
||||||
switch(bonus->subtype)
|
switch(bonus->subtype)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -153,7 +153,7 @@ std::string CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bo
|
|||||||
break;//not positive
|
break;//not positive
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Bonus::LEVEL_SPELL_IMMUNITY:
|
case BonusType::LEVEL_SPELL_IMMUNITY:
|
||||||
{
|
{
|
||||||
if(vstd::iswithin(bonus->val, 1, 5))
|
if(vstd::iswithin(bonus->val, 1, 5))
|
||||||
{
|
{
|
||||||
@ -161,7 +161,7 @@ std::string CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bo
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Bonus::KING:
|
case BonusType::KING:
|
||||||
{
|
{
|
||||||
if(vstd::iswithin(bonus->val, 0, 3))
|
if(vstd::iswithin(bonus->val, 0, 3))
|
||||||
{
|
{
|
||||||
@ -169,7 +169,7 @@ std::string CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bo
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Bonus::GENERAL_DAMAGE_REDUCTION:
|
case BonusType::GENERAL_DAMAGE_REDUCTION:
|
||||||
{
|
{
|
||||||
switch(bonus->subtype)
|
switch(bonus->subtype)
|
||||||
{
|
{
|
||||||
@ -185,7 +185,7 @@ std::string CBonusTypeHandler::bonusToGraphics(const std::shared_ptr<Bonus> & bo
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
const CBonusType & bt = bonusTypes[bonus->type];
|
const CBonusType & bt = bonusTypes[vstd::to_underlying(bonus->type)];
|
||||||
fileName = bt.icon;
|
fileName = bt.icon;
|
||||||
fullPath = true;
|
fullPath = true;
|
||||||
}
|
}
|
||||||
@ -224,7 +224,7 @@ void CBonusTypeHandler::load(const JsonNode & config)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CBonusType & bt = bonusTypes[it->second];
|
CBonusType & bt = bonusTypes[vstd::to_underlying(it->second)];
|
||||||
|
|
||||||
loadItem(node.second, bt, node.first);
|
loadItem(node.second, bt, node.first);
|
||||||
logBonus->trace("Loaded bonus type %s", node.first);
|
logBonus->trace("Loaded bonus type %s", node.first);
|
||||||
|
@ -19,8 +19,6 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
class JsonNode;
|
class JsonNode;
|
||||||
|
|
||||||
using BonusTypeID = Bonus::BonusType;
|
|
||||||
|
|
||||||
class DLL_LINKAGE CBonusType
|
class DLL_LINKAGE CBonusType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -67,7 +65,7 @@ private:
|
|||||||
void load(const JsonNode & config);
|
void load(const JsonNode & config);
|
||||||
void loadItem(const JsonNode & source, CBonusType & dest, const std::string & name) const;
|
void loadItem(const JsonNode & source, CBonusType & dest, const std::string & name) const;
|
||||||
|
|
||||||
std::vector<CBonusType> bonusTypes; //index = BonusTypeID
|
std::vector<CBonusType> bonusTypes; //index = BonusType
|
||||||
};
|
};
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -113,49 +113,49 @@ FactionID CCreature::getFaction() const
|
|||||||
|
|
||||||
int32_t CCreature::getBaseAttack() const
|
int32_t CCreature::getBaseAttack() const
|
||||||
{
|
{
|
||||||
static const auto SELECTOR = Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK).And(Selector::sourceTypeSel(Bonus::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::typeSubtype(BonusType::PRIMARY_SKILL, 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(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE).And(Selector::sourceTypeSel(Bonus::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::typeSubtype(BonusType::PRIMARY_SKILL, 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(Bonus::CREATURE_DAMAGE, 1).And(Selector::sourceTypeSel(Bonus::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 1).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(Bonus::CREATURE_DAMAGE, 2).And(Selector::sourceTypeSel(Bonus::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 2).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
||||||
return getExportedBonusList().valOfBonuses(SELECTOR);
|
return getExportedBonusList().valOfBonuses(SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CCreature::getBaseHitPoints() const
|
int32_t CCreature::getBaseHitPoints() const
|
||||||
{
|
{
|
||||||
static const auto SELECTOR = Selector::type()(Bonus::STACK_HEALTH).And(Selector::sourceTypeSel(Bonus::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::type()(BonusType::STACK_HEALTH).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
||||||
return getExportedBonusList().valOfBonuses(SELECTOR);
|
return getExportedBonusList().valOfBonuses(SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CCreature::getBaseSpellPoints() const
|
int32_t CCreature::getBaseSpellPoints() const
|
||||||
{
|
{
|
||||||
static const auto SELECTOR = Selector::type()(Bonus::CASTS).And(Selector::sourceTypeSel(Bonus::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::type()(BonusType::CASTS).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
||||||
return getExportedBonusList().valOfBonuses(SELECTOR);
|
return getExportedBonusList().valOfBonuses(SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CCreature::getBaseSpeed() const
|
int32_t CCreature::getBaseSpeed() const
|
||||||
{
|
{
|
||||||
static const auto SELECTOR = Selector::type()(Bonus::STACKS_SPEED).And(Selector::sourceTypeSel(Bonus::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::type()(BonusType::STACKS_SPEED).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
||||||
return getExportedBonusList().valOfBonuses(SELECTOR);
|
return getExportedBonusList().valOfBonuses(SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CCreature::getBaseShots() const
|
int32_t CCreature::getBaseShots() const
|
||||||
{
|
{
|
||||||
static const auto SELECTOR = Selector::type()(Bonus::SHOTS).And(Selector::sourceTypeSel(Bonus::CREATURE_ABILITY));
|
static const auto SELECTOR = Selector::type()(BonusType::SHOTS).And(Selector::sourceTypeSel(BonusSource::CREATURE_ABILITY));
|
||||||
return getExportedBonusList().valOfBonuses(SELECTOR);
|
return getExportedBonusList().valOfBonuses(SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,9 +291,9 @@ CCreature::CCreature()
|
|||||||
fightValue = AIValue = growth = hordeGrowth = ammMin = ammMax = 0;
|
fightValue = AIValue = growth = hordeGrowth = ammMin = ammMax = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCreature::addBonus(int val, Bonus::BonusType type, int subtype)
|
void CCreature::addBonus(int val, BonusType type, int subtype)
|
||||||
{
|
{
|
||||||
auto selector = Selector::typeSubtype(type, subtype).And(Selector::source(Bonus::CREATURE_ABILITY, getIndex()));
|
auto selector = Selector::typeSubtype(type, subtype).And(Selector::source(BonusSource::CREATURE_ABILITY, getIndex()));
|
||||||
BonusList & exported = getExportedBonusList();
|
BonusList & exported = getExportedBonusList();
|
||||||
|
|
||||||
BonusList existing;
|
BonusList existing;
|
||||||
@ -301,7 +301,7 @@ void CCreature::addBonus(int val, Bonus::BonusType type, int subtype)
|
|||||||
|
|
||||||
if(existing.empty())
|
if(existing.empty())
|
||||||
{
|
{
|
||||||
auto added = std::make_shared<Bonus>(Bonus::PERMANENT, type, Bonus::CREATURE_ABILITY, val, getIndex(), subtype, Bonus::BASE_NUMBER);
|
auto added = std::make_shared<Bonus>(BonusDuration::PERMANENT, type, BonusSource::CREATURE_ABILITY, val, getIndex(), subtype, BonusValueType::BASE_NUMBER);
|
||||||
addNewBonus(added);
|
addNewBonus(added);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -339,28 +339,28 @@ void CCreature::updateFrom(const JsonNode & data)
|
|||||||
serializeJson(handler);
|
serializeJson(handler);
|
||||||
|
|
||||||
if(!configNode["hitPoints"].isNull())
|
if(!configNode["hitPoints"].isNull())
|
||||||
addBonus(configNode["hitPoints"].Integer(), Bonus::STACK_HEALTH);
|
addBonus(configNode["hitPoints"].Integer(), BonusType::STACK_HEALTH);
|
||||||
|
|
||||||
if(!configNode["speed"].isNull())
|
if(!configNode["speed"].isNull())
|
||||||
addBonus(configNode["speed"].Integer(), Bonus::STACKS_SPEED);
|
addBonus(configNode["speed"].Integer(), BonusType::STACKS_SPEED);
|
||||||
|
|
||||||
if(!configNode["attack"].isNull())
|
if(!configNode["attack"].isNull())
|
||||||
addBonus(configNode["attack"].Integer(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
|
addBonus(configNode["attack"].Integer(), BonusType::PRIMARY_SKILL, PrimarySkill::ATTACK);
|
||||||
|
|
||||||
if(!configNode["defense"].isNull())
|
if(!configNode["defense"].isNull())
|
||||||
addBonus(configNode["defense"].Integer(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
|
addBonus(configNode["defense"].Integer(), BonusType::PRIMARY_SKILL, PrimarySkill::DEFENSE);
|
||||||
|
|
||||||
if(!configNode["damage"]["min"].isNull())
|
if(!configNode["damage"]["min"].isNull())
|
||||||
addBonus(configNode["damage"]["min"].Integer(), Bonus::CREATURE_DAMAGE, 1);
|
addBonus(configNode["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, 1);
|
||||||
|
|
||||||
if(!configNode["damage"]["max"].isNull())
|
if(!configNode["damage"]["max"].isNull())
|
||||||
addBonus(configNode["damage"]["max"].Integer(), Bonus::CREATURE_DAMAGE, 2);
|
addBonus(configNode["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, 2);
|
||||||
|
|
||||||
if(!configNode["shots"].isNull())
|
if(!configNode["shots"].isNull())
|
||||||
addBonus(configNode["shots"].Integer(), Bonus::SHOTS);
|
addBonus(configNode["shots"].Integer(), BonusType::SHOTS);
|
||||||
|
|
||||||
if(!configNode["spellPoints"].isNull())
|
if(!configNode["spellPoints"].isNull())
|
||||||
addBonus(configNode["spellPoints"].Integer(), Bonus::CASTS);
|
addBonus(configNode["spellPoints"].Integer(), BonusType::CASTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -601,18 +601,18 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
|
|||||||
VLC->generaltexth->registerString(scope, cre->getNameSingularTextID(), node["name"]["singular"].String());
|
VLC->generaltexth->registerString(scope, cre->getNameSingularTextID(), node["name"]["singular"].String());
|
||||||
VLC->generaltexth->registerString(scope, cre->getNamePluralTextID(), node["name"]["plural"].String());
|
VLC->generaltexth->registerString(scope, cre->getNamePluralTextID(), node["name"]["plural"].String());
|
||||||
|
|
||||||
cre->addBonus(node["hitPoints"].Integer(), Bonus::STACK_HEALTH);
|
cre->addBonus(node["hitPoints"].Integer(), BonusType::STACK_HEALTH);
|
||||||
cre->addBonus(node["speed"].Integer(), Bonus::STACKS_SPEED);
|
cre->addBonus(node["speed"].Integer(), BonusType::STACKS_SPEED);
|
||||||
cre->addBonus(node["attack"].Integer(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
|
cre->addBonus(node["attack"].Integer(), BonusType::PRIMARY_SKILL, PrimarySkill::ATTACK);
|
||||||
cre->addBonus(node["defense"].Integer(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
|
cre->addBonus(node["defense"].Integer(), BonusType::PRIMARY_SKILL, PrimarySkill::DEFENSE);
|
||||||
|
|
||||||
cre->addBonus(node["damage"]["min"].Integer(), Bonus::CREATURE_DAMAGE, 1);
|
cre->addBonus(node["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, 1);
|
||||||
cre->addBonus(node["damage"]["max"].Integer(), Bonus::CREATURE_DAMAGE, 2);
|
cre->addBonus(node["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, 2);
|
||||||
|
|
||||||
assert(node["damage"]["min"].Integer() <= node["damage"]["max"].Integer());
|
assert(node["damage"]["min"].Integer() <= node["damage"]["max"].Integer());
|
||||||
|
|
||||||
if(!node["shots"].isNull())
|
if(!node["shots"].isNull())
|
||||||
cre->addBonus(node["shots"].Integer(), Bonus::SHOTS);
|
cre->addBonus(node["shots"].Integer(), BonusType::SHOTS);
|
||||||
|
|
||||||
loadStackExperience(cre, node["stackExperience"]);
|
loadStackExperience(cre, node["stackExperience"]);
|
||||||
loadJsonAnimation(cre, node["graphics"]);
|
loadJsonAnimation(cre, node["graphics"]);
|
||||||
@ -708,8 +708,8 @@ void CCreatureHandler::loadCrExpMod()
|
|||||||
expBonParser.endLine();
|
expBonParser.endLine();
|
||||||
}
|
}
|
||||||
//skeleton gets exp penalty
|
//skeleton gets exp penalty
|
||||||
objects[56].get()->addBonus(-50, Bonus::EXP_MULTIPLIER, -1);
|
objects[56].get()->addBonus(-50, BonusType::EXP_MULTIPLIER, -1);
|
||||||
objects[57].get()->addBonus(-50, Bonus::EXP_MULTIPLIER, -1);
|
objects[57].get()->addBonus(-50, BonusType::EXP_MULTIPLIER, -1);
|
||||||
//exp for tier >7, rank 11
|
//exp for tier >7, rank 11
|
||||||
expRanks[0].push_back(147000);
|
expRanks[0].push_back(147000);
|
||||||
expAfterUpgrade = 75; //percent
|
expAfterUpgrade = 75; //percent
|
||||||
@ -740,10 +740,10 @@ void CCreatureHandler::loadCrExpBon(CBonusSystemNode & globalEffects)
|
|||||||
CLegacyConfigParser parser("DATA/CREXPBON.TXT");
|
CLegacyConfigParser parser("DATA/CREXPBON.TXT");
|
||||||
|
|
||||||
Bonus b; //prototype with some default properties
|
Bonus b; //prototype with some default properties
|
||||||
b.source = Bonus::STACK_EXPERIENCE;
|
b.source = BonusSource::STACK_EXPERIENCE;
|
||||||
b.duration = Bonus::PERMANENT;
|
b.duration = BonusDuration::PERMANENT;
|
||||||
b.valType = Bonus::ADDITIVE_VALUE;
|
b.valType = BonusValueType::ADDITIVE_VALUE;
|
||||||
b.effectRange = Bonus::NO_LIMIT;
|
b.effectRange = BonusLimitEffect::NO_LIMIT;
|
||||||
b.additionalInfo = 0;
|
b.additionalInfo = 0;
|
||||||
b.turnsRemain = 0;
|
b.turnsRemain = 0;
|
||||||
BonusList bl;
|
BonusList bl;
|
||||||
@ -887,9 +887,9 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c
|
|||||||
if (!ability.second.isNull())
|
if (!ability.second.isNull())
|
||||||
{
|
{
|
||||||
auto b = JsonUtils::parseBonus(ability.second);
|
auto b = JsonUtils::parseBonus(ability.second);
|
||||||
b->source = Bonus::CREATURE_ABILITY;
|
b->source = BonusSource::CREATURE_ABILITY;
|
||||||
b->sid = creature->getIndex();
|
b->sid = creature->getIndex();
|
||||||
b->duration = Bonus::PERMANENT;
|
b->duration = BonusDuration::PERMANENT;
|
||||||
creature->addNewBonus(b);
|
creature->addNewBonus(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -905,9 +905,9 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto b = JsonUtils::parseBonus(ability);
|
auto b = JsonUtils::parseBonus(ability);
|
||||||
b->source = Bonus::CREATURE_ABILITY;
|
b->source = BonusSource::CREATURE_ABILITY;
|
||||||
b->sid = creature->getIndex();
|
b->sid = creature->getIndex();
|
||||||
b->duration = Bonus::PERMANENT;
|
b->duration = BonusDuration::PERMANENT;
|
||||||
creature->addNewBonus(b);
|
creature->addNewBonus(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -977,8 +977,8 @@ void CCreatureHandler::loadStackExperience(CCreature * creature, const JsonNode
|
|||||||
// we can not create copies since identifiers resolution does not tracks copies
|
// we can not create copies since identifiers resolution does not tracks copies
|
||||||
// leading to unset identifier values in copies
|
// leading to unset identifier values in copies
|
||||||
auto bonus = JsonUtils::parseBonus (exp["bonus"]);
|
auto bonus = JsonUtils::parseBonus (exp["bonus"]);
|
||||||
bonus->source = Bonus::STACK_EXPERIENCE;
|
bonus->source = BonusSource::STACK_EXPERIENCE;
|
||||||
bonus->duration = Bonus::PERMANENT;
|
bonus->duration = BonusDuration::PERMANENT;
|
||||||
bonus->limiter = std::make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit));
|
bonus->limiter = std::make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit));
|
||||||
creature->addNewBonus (bonus);
|
creature->addNewBonus (bonus);
|
||||||
break; //TODO: allow bonuses to turn off?
|
break; //TODO: allow bonuses to turn off?
|
||||||
@ -997,8 +997,8 @@ void CCreatureHandler::loadStackExperience(CCreature * creature, const JsonNode
|
|||||||
bonusInput["val"].Float() = static_cast<int>(val.Float()) - lastVal;
|
bonusInput["val"].Float() = static_cast<int>(val.Float()) - lastVal;
|
||||||
|
|
||||||
auto bonus = JsonUtils::parseBonus (bonusInput);
|
auto bonus = JsonUtils::parseBonus (bonusInput);
|
||||||
bonus->source = Bonus::STACK_EXPERIENCE;
|
bonus->source = BonusSource::STACK_EXPERIENCE;
|
||||||
bonus->duration = Bonus::PERMANENT;
|
bonus->duration = BonusDuration::PERMANENT;
|
||||||
bonus->limiter.reset (new RankRangeLimiter(lowerLimit));
|
bonus->limiter.reset (new RankRangeLimiter(lowerLimit));
|
||||||
creature->addNewBonus (bonus);
|
creature->addNewBonus (bonus);
|
||||||
}
|
}
|
||||||
@ -1018,55 +1018,55 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
switch (buf[0])
|
switch (buf[0])
|
||||||
{
|
{
|
||||||
case 'H':
|
case 'H':
|
||||||
b.type = Bonus::STACK_HEALTH;
|
b.type = BonusType::STACK_HEALTH;
|
||||||
b.valType = Bonus::PERCENT_TO_BASE;
|
b.valType = BonusValueType::PERCENT_TO_BASE;
|
||||||
break;
|
break;
|
||||||
case 'A':
|
case 'A':
|
||||||
b.type = Bonus::PRIMARY_SKILL;
|
b.type = BonusType::PRIMARY_SKILL;
|
||||||
b.subtype = PrimarySkill::ATTACK;
|
b.subtype = PrimarySkill::ATTACK;
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
b.type = Bonus::PRIMARY_SKILL;
|
b.type = BonusType::PRIMARY_SKILL;
|
||||||
b.subtype = PrimarySkill::DEFENSE;
|
b.subtype = PrimarySkill::DEFENSE;
|
||||||
break;
|
break;
|
||||||
case 'M': //Max damage
|
case 'M': //Max damage
|
||||||
b.type = Bonus::CREATURE_DAMAGE;
|
b.type = BonusType::CREATURE_DAMAGE;
|
||||||
b.subtype = 2;
|
b.subtype = 2;
|
||||||
break;
|
break;
|
||||||
case 'm': //Min damage
|
case 'm': //Min damage
|
||||||
b.type = Bonus::CREATURE_DAMAGE;
|
b.type = BonusType::CREATURE_DAMAGE;
|
||||||
b.subtype = 1;
|
b.subtype = 1;
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
b.type = Bonus::STACKS_SPEED; break;
|
b.type = BonusType::STACKS_SPEED; break;
|
||||||
case 'O':
|
case 'O':
|
||||||
b.type = Bonus::SHOTS; break;
|
b.type = BonusType::SHOTS; break;
|
||||||
case 'b':
|
case 'b':
|
||||||
b.type = Bonus::ENEMY_DEFENCE_REDUCTION; break;
|
b.type = BonusType::ENEMY_DEFENCE_REDUCTION; break;
|
||||||
case 'C':
|
case 'C':
|
||||||
b.type = Bonus::CHANGES_SPELL_COST_FOR_ALLY; break;
|
b.type = BonusType::CHANGES_SPELL_COST_FOR_ALLY; break;
|
||||||
case 'd':
|
case 'd':
|
||||||
b.type = Bonus::DEFENSIVE_STANCE; break;
|
b.type = BonusType::DEFENSIVE_STANCE; break;
|
||||||
case 'e':
|
case 'e':
|
||||||
b.type = Bonus::DOUBLE_DAMAGE_CHANCE;
|
b.type = BonusType::DOUBLE_DAMAGE_CHANCE;
|
||||||
b.subtype = 0;
|
b.subtype = 0;
|
||||||
break;
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
b.type = Bonus::DEATH_STARE;
|
b.type = BonusType::DEATH_STARE;
|
||||||
b.subtype = 0; //Gorgon
|
b.subtype = 0; //Gorgon
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
b.type = Bonus::FEAR; break;
|
b.type = BonusType::FEAR; break;
|
||||||
case 'g':
|
case 'g':
|
||||||
b.type = Bonus::SPELL_DAMAGE_REDUCTION;
|
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||||
b.subtype = -1; //all magic schools
|
b.subtype = -1; //all magic schools
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
b.type = Bonus::CASTS; break;
|
b.type = BonusType::CASTS; break;
|
||||||
case 'R':
|
case 'R':
|
||||||
b.type = Bonus::ADDITIONAL_RETALIATION; break;
|
b.type = BonusType::ADDITIONAL_RETALIATION; break;
|
||||||
case 'W':
|
case 'W':
|
||||||
b.type = Bonus::MAGIC_RESISTANCE;
|
b.type = BonusType::MAGIC_RESISTANCE;
|
||||||
b.subtype = 0; //otherwise creature window goes crazy
|
b.subtype = 0; //otherwise creature window goes crazy
|
||||||
break;
|
break;
|
||||||
case 'f': //on-off skill
|
case 'f': //on-off skill
|
||||||
@ -1074,44 +1074,44 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
switch (mod[0])
|
switch (mod[0])
|
||||||
{
|
{
|
||||||
case 'A':
|
case 'A':
|
||||||
b.type = Bonus::ATTACKS_ALL_ADJACENT; break;
|
b.type = BonusType::ATTACKS_ALL_ADJACENT; break;
|
||||||
case 'b':
|
case 'b':
|
||||||
b.type = Bonus::RETURN_AFTER_STRIKE; break;
|
b.type = BonusType::RETURN_AFTER_STRIKE; break;
|
||||||
case 'B':
|
case 'B':
|
||||||
b.type = Bonus::TWO_HEX_ATTACK_BREATH; break;
|
b.type = BonusType::TWO_HEX_ATTACK_BREATH; break;
|
||||||
case 'c':
|
case 'c':
|
||||||
b.type = Bonus::JOUSTING;
|
b.type = BonusType::JOUSTING;
|
||||||
b.val = 5;
|
b.val = 5;
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
b.type = Bonus::ADDITIONAL_ATTACK; break;
|
b.type = BonusType::ADDITIONAL_ATTACK; break;
|
||||||
case 'f':
|
case 'f':
|
||||||
b.type = Bonus::FEARLESS; break;
|
b.type = BonusType::FEARLESS; break;
|
||||||
case 'F':
|
case 'F':
|
||||||
b.type = Bonus::FLYING; break;
|
b.type = BonusType::FLYING; break;
|
||||||
case 'm':
|
case 'm':
|
||||||
b.type = Bonus::MORALE; break;
|
b.type = BonusType::MORALE; break;
|
||||||
b.val = 1;
|
b.val = 1;
|
||||||
b.valType = Bonus::INDEPENDENT_MAX;
|
b.valType = BonusValueType::INDEPENDENT_MAX;
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
b.type = Bonus::NO_MORALE; break;
|
b.type = BonusType::NO_MORALE; break;
|
||||||
case 'p': //Mind spells
|
case 'p': //Mind spells
|
||||||
case 'P':
|
case 'P':
|
||||||
b.type = Bonus::MIND_IMMUNITY; break;
|
b.type = BonusType::MIND_IMMUNITY; break;
|
||||||
case 'r':
|
case 'r':
|
||||||
b.type = Bonus::REBIRTH; //on/off? makes sense?
|
b.type = BonusType::REBIRTH; //on/off? makes sense?
|
||||||
b.subtype = 0;
|
b.subtype = 0;
|
||||||
b.val = 20; //arbitrary value
|
b.val = 20; //arbitrary value
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
b.type = Bonus::BLOCKS_RETALIATION; break;
|
b.type = BonusType::BLOCKS_RETALIATION; break;
|
||||||
case 's':
|
case 's':
|
||||||
b.type = Bonus::FREE_SHOOTING; break;
|
b.type = BonusType::FREE_SHOOTING; break;
|
||||||
case 'u':
|
case 'u':
|
||||||
b.type = Bonus::SPELL_RESISTANCE_AURA; break;
|
b.type = BonusType::SPELL_RESISTANCE_AURA; break;
|
||||||
case 'U':
|
case 'U':
|
||||||
b.type = Bonus::UNDEAD; break;
|
b.type = BonusType::UNDEAD; break;
|
||||||
default:
|
default:
|
||||||
logGlobal->trace("Not parsed bonus %s %s", buf, mod);
|
logGlobal->trace("Not parsed bonus %s %s", buf, mod);
|
||||||
return;
|
return;
|
||||||
@ -1123,42 +1123,42 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
switch (mod[0])
|
switch (mod[0])
|
||||||
{
|
{
|
||||||
case 'B': //Blind
|
case 'B': //Blind
|
||||||
b.type = Bonus::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::BLIND;
|
b.subtype = SpellID::BLIND;
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'H': //Hypnotize
|
case 'H': //Hypnotize
|
||||||
b.type = Bonus::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::HYPNOTIZE;
|
b.subtype = SpellID::HYPNOTIZE;
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'I': //Implosion
|
case 'I': //Implosion
|
||||||
b.type = Bonus::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::IMPLOSION;
|
b.subtype = SpellID::IMPLOSION;
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'K': //Berserk
|
case 'K': //Berserk
|
||||||
b.type = Bonus::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::BERSERK;
|
b.subtype = SpellID::BERSERK;
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'M': //Meteor Shower
|
case 'M': //Meteor Shower
|
||||||
b.type = Bonus::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::METEOR_SHOWER;
|
b.subtype = 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 = Bonus::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::DISPEL_HELPFUL_SPELLS;
|
b.subtype = SpellID::DISPEL_HELPFUL_SPELLS;
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'R': //Armageddon
|
case 'R': //Armageddon
|
||||||
b.type = Bonus::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::ARMAGEDDON;
|
b.subtype = SpellID::ARMAGEDDON;
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
case 'S': //Slow
|
case 'S': //Slow
|
||||||
b.type = Bonus::SPELL_IMMUNITY;
|
b.type = BonusType::SPELL_IMMUNITY;
|
||||||
b.subtype = SpellID::SLOW;
|
b.subtype = SpellID::SLOW;
|
||||||
b.additionalInfo = 0;//normal immunity
|
b.additionalInfo = 0;//normal immunity
|
||||||
break;
|
break;
|
||||||
@ -1166,61 +1166,61 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
case '7':
|
case '7':
|
||||||
case '8':
|
case '8':
|
||||||
case '9':
|
case '9':
|
||||||
b.type = Bonus::LEVEL_SPELL_IMMUNITY;
|
b.type = BonusType::LEVEL_SPELL_IMMUNITY;
|
||||||
b.val = std::atoi(mod.c_str()) - 5;
|
b.val = std::atoi(mod.c_str()) - 5;
|
||||||
break;
|
break;
|
||||||
case ':':
|
case ':':
|
||||||
b.type = Bonus::LEVEL_SPELL_IMMUNITY;
|
b.type = BonusType::LEVEL_SPELL_IMMUNITY;
|
||||||
b.val = GameConstants::SPELL_LEVELS; //in case someone adds higher level spells?
|
b.val = GameConstants::SPELL_LEVELS; //in case someone adds higher level spells?
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
b.type = Bonus::FIRE_IMMUNITY;
|
b.type = BonusType::FIRE_IMMUNITY;
|
||||||
b.subtype = 1; //not positive
|
b.subtype = 1; //not positive
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
b.type = Bonus::FIRE_IMMUNITY;
|
b.type = BonusType::FIRE_IMMUNITY;
|
||||||
b.subtype = 2; //only direct damage
|
b.subtype = 2; //only direct damage
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
b.type = Bonus::FIRE_IMMUNITY;
|
b.type = BonusType::FIRE_IMMUNITY;
|
||||||
b.subtype = 0; //all
|
b.subtype = 0; //all
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
b.type = Bonus::WATER_IMMUNITY;
|
b.type = BonusType::WATER_IMMUNITY;
|
||||||
b.subtype = 1; //not positive
|
b.subtype = 1; //not positive
|
||||||
break;
|
break;
|
||||||
case 'W':
|
case 'W':
|
||||||
b.type = Bonus::WATER_IMMUNITY;
|
b.type = BonusType::WATER_IMMUNITY;
|
||||||
b.subtype = 2; //only direct damage
|
b.subtype = 2; //only direct damage
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
b.type = Bonus::WATER_IMMUNITY;
|
b.type = BonusType::WATER_IMMUNITY;
|
||||||
b.subtype = 0; //all
|
b.subtype = 0; //all
|
||||||
break;
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
b.type = Bonus::EARTH_IMMUNITY;
|
b.type = BonusType::EARTH_IMMUNITY;
|
||||||
b.subtype = 2; //only direct damage
|
b.subtype = 2; //only direct damage
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
b.type = Bonus::EARTH_IMMUNITY;
|
b.type = BonusType::EARTH_IMMUNITY;
|
||||||
b.subtype = 0; //all
|
b.subtype = 0; //all
|
||||||
break;
|
break;
|
||||||
case 'A':
|
case 'A':
|
||||||
b.type = Bonus::AIR_IMMUNITY;
|
b.type = BonusType::AIR_IMMUNITY;
|
||||||
b.subtype = 2; //only direct damage
|
b.subtype = 2; //only direct damage
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
b.type = Bonus::AIR_IMMUNITY;
|
b.type = BonusType::AIR_IMMUNITY;
|
||||||
b.subtype = 0; //all
|
b.subtype = 0; //all
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
b.type = Bonus::DIRECT_DAMAGE_IMMUNITY;
|
b.type = BonusType::DIRECT_DAMAGE_IMMUNITY;
|
||||||
break;
|
break;
|
||||||
case '0':
|
case '0':
|
||||||
b.type = Bonus::RECEPTIVE;
|
b.type = BonusType::RECEPTIVE;
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
b.type = Bonus::MIND_IMMUNITY;
|
b.type = BonusType::MIND_IMMUNITY;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logGlobal->trace("Not parsed bonus %s %s", buf, mod);
|
logGlobal->trace("Not parsed bonus %s %s", buf, mod);
|
||||||
@ -1230,38 +1230,38 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
enable = true;
|
enable = true;
|
||||||
b.type = Bonus::NO_DISTANCE_PENALTY;
|
b.type = BonusType::NO_DISTANCE_PENALTY;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
enable = true;
|
enable = true;
|
||||||
b.type = Bonus::NO_WALL_PENALTY;
|
b.type = BonusType::NO_WALL_PENALTY;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
case 'c':
|
case 'c':
|
||||||
case 'K':
|
case 'K':
|
||||||
case 'k':
|
case 'k':
|
||||||
b.type = Bonus::SPELL_AFTER_ATTACK;
|
b.type = BonusType::SPELL_AFTER_ATTACK;
|
||||||
b.subtype = stringToNumber(mod);
|
b.subtype = stringToNumber(mod);
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
b.type= Bonus::HATE;
|
b.type = BonusType::HATE;
|
||||||
b.subtype = stringToNumber(mod);
|
b.subtype = stringToNumber(mod);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
case 'J':
|
case 'J':
|
||||||
b.type = Bonus::SPELL_BEFORE_ATTACK;
|
b.type = BonusType::SPELL_BEFORE_ATTACK;
|
||||||
b.subtype = stringToNumber(mod);
|
b.subtype = stringToNumber(mod);
|
||||||
b.additionalInfo = 3; //always expert?
|
b.additionalInfo = 3; //always expert?
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
b.type = Bonus::HP_REGENERATION;
|
b.type = BonusType::HP_REGENERATION;
|
||||||
b.val = stringToNumber(mod);
|
b.val = stringToNumber(mod);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
b.type = Bonus::ENCHANTED;
|
b.type = BonusType::ENCHANTED;
|
||||||
b.subtype = stringToNumber(mod);
|
b.subtype = stringToNumber(mod);
|
||||||
b.valType = Bonus::INDEPENDENT_MAX;
|
b.valType = BonusValueType::INDEPENDENT_MAX;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logGlobal->trace("Not parsed bonus %s %s", buf, mod);
|
logGlobal->trace("Not parsed bonus %s %s", buf, mod);
|
||||||
@ -1272,7 +1272,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
case '=': //should we allow percent values to stack or pick highest?
|
case '=': //should we allow percent values to stack or pick highest?
|
||||||
b.valType = Bonus::ADDITIVE_VALUE;
|
b.valType = BonusValueType::ADDITIVE_VALUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1283,7 +1283,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
|
|
||||||
if (enable) //0 and 2 means non-active, 1 - active
|
if (enable) //0 and 2 means non-active, 1 - active
|
||||||
{
|
{
|
||||||
if (b.type != Bonus::REBIRTH)
|
if (b.type != BonusType::REBIRTH)
|
||||||
b.val = 0; //on-off ability, no value specified
|
b.val = 0; //on-off ability, no value specified
|
||||||
parser.readNumber(); // 0 level is never active
|
parser.readNumber(); // 0 level is never active
|
||||||
for (int i = 1; i < 11; ++i)
|
for (int i = 1; i < 11; ++i)
|
||||||
@ -1300,13 +1300,13 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
lastVal = static_cast<si32>(parser.readNumber());
|
lastVal = static_cast<si32>(parser.readNumber());
|
||||||
if (b.type == Bonus::HATE)
|
if (b.type == BonusType::HATE)
|
||||||
lastVal *= 10; //odd fix
|
lastVal *= 10; //odd fix
|
||||||
//FIXME: value for zero level should be stored in our config files (independent of stack exp)
|
//FIXME: value for zero level should be stored in our config files (independent of stack exp)
|
||||||
for (int i = 1; i < 11; ++i)
|
for (int i = 1; i < 11; ++i)
|
||||||
{
|
{
|
||||||
curVal = static_cast<si32>(parser.readNumber());
|
curVal = static_cast<si32>(parser.readNumber());
|
||||||
if (b.type == Bonus::HATE)
|
if (b.type == BonusType::HATE)
|
||||||
curVal *= 10; //odd fix
|
curVal *= 10; //odd fix
|
||||||
if (curVal > lastVal) //threshold, add new bonus
|
if (curVal > lastVal) //threshold, add new bonus
|
||||||
{
|
{
|
||||||
|
@ -202,7 +202,7 @@ public:
|
|||||||
|
|
||||||
bool valid() const;
|
bool valid() const;
|
||||||
|
|
||||||
void addBonus(int val, Bonus::BonusType type, int subtype = -1);
|
void addBonus(int val, BonusType type, int subtype = -1);
|
||||||
std::string nodeName() const override;
|
std::string nodeName() const override;
|
||||||
|
|
||||||
template<typename RanGen>
|
template<typename RanGen>
|
||||||
|
@ -314,7 +314,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
|
|||||||
if(getPlayerRelations(getLocalPlayer(), hero->tempOwner) == PlayerRelations::ENEMIES)
|
if(getPlayerRelations(getLocalPlayer(), hero->tempOwner) == PlayerRelations::ENEMIES)
|
||||||
{
|
{
|
||||||
//todo: bonus cashing
|
//todo: bonus cashing
|
||||||
int disguiseLevel = h->valOfBonuses(Selector::typeSubtype(Bonus::DISGUISED, 0));
|
int disguiseLevel = h->valOfBonuses(Selector::typeSubtype(BonusType::DISGUISED, 0));
|
||||||
|
|
||||||
auto doBasicDisguise = [](InfoAboutHero & info)
|
auto doBasicDisguise = [](InfoAboutHero & info)
|
||||||
{
|
{
|
||||||
|
@ -954,7 +954,7 @@ void CGameState::initGlobalBonuses()
|
|||||||
for(const auto & b : baseBonuses.Struct())
|
for(const auto & b : baseBonuses.Struct())
|
||||||
{
|
{
|
||||||
auto bonus = JsonUtils::parseBonus(b.second);
|
auto bonus = JsonUtils::parseBonus(b.second);
|
||||||
bonus->source = Bonus::GLOBAL;//for all
|
bonus->source = BonusSource::GLOBAL;//for all
|
||||||
bonus->sid = -1; //there is one global object
|
bonus->sid = -1; //there is one global object
|
||||||
globalEffects.addNewBonus(bonus);
|
globalEffects.addNewBonus(bonus);
|
||||||
}
|
}
|
||||||
@ -1282,9 +1282,9 @@ void CGameState::prepareCrossoverHeroes(std::vector<CGameState::CampaignHeroRepl
|
|||||||
{
|
{
|
||||||
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
|
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
|
||||||
{
|
{
|
||||||
auto sel = Selector::type()(Bonus::PRIMARY_SKILL)
|
auto sel = Selector::type()(BonusType::PRIMARY_SKILL)
|
||||||
.And(Selector::subtype()(g))
|
.And(Selector::subtype()(g))
|
||||||
.And(Selector::sourceType()(Bonus::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];
|
||||||
}
|
}
|
||||||
@ -1614,7 +1614,7 @@ void CGameState::giveCampaignBonusToHero(CGHeroInstance * hero)
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto bb = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::CAMPAIGN_BONUS, val, *scenarioOps->campState->currentMap, g);
|
auto bb = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CAMPAIGN_BONUS, val, *scenarioOps->campState->currentMap, g);
|
||||||
hero->addNewBonus(bb);
|
hero->addNewBonus(bb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2022,7 +2022,7 @@ UpgradeInfo CGameState::fillUpgradeInfo(const CStackInstance &stack) const
|
|||||||
t = dynamic_cast<const CGTownInstance *>(stack.armyObj);
|
t = dynamic_cast<const CGTownInstance *>(stack.armyObj);
|
||||||
else if(h)
|
else if(h)
|
||||||
{ //hero specialty
|
{ //hero specialty
|
||||||
TConstBonusListPtr lista = h->getBonuses(Selector::typeSubtype(Bonus::SPECIAL_UPGRADE, base->getId()));
|
TConstBonusListPtr lista = h->getBonuses(Selector::typeSubtype(BonusType::SPECIAL_UPGRADE, base->getId()));
|
||||||
for(const auto & it : *lista)
|
for(const auto & it : *lista)
|
||||||
{
|
{
|
||||||
auto nid = CreatureID(it->additionalInfo[0]);
|
auto nid = CreatureID(it->additionalInfo[0]);
|
||||||
@ -2590,7 +2590,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(Bonus::GENERATE_RESOURCE, GameResID(EGameResID::GOLD)));
|
totalIncome += h->valOfBonuses(Selector::typeSubtype(BonusType::GENERATE_RESOURCE, GameResID(EGameResID::GOLD)));
|
||||||
|
|
||||||
if(!heroOrTown)
|
if(!heroOrTown)
|
||||||
heroOrTown = h;
|
heroOrTown = h;
|
||||||
|
@ -536,14 +536,14 @@ 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->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
||||||
bonus->type = Bonus::STACKS_SPEED;
|
bonus->type = BonusType::STACKS_SPEED;
|
||||||
bonus->val = 1;
|
bonus->val = 1;
|
||||||
result.push_back(bonus);
|
result.push_back(bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
||||||
bonus->type = Bonus::PRIMARY_SKILL;
|
bonus->type = BonusType::PRIMARY_SKILL;
|
||||||
bonus->subtype = PrimarySkill::ATTACK;
|
bonus->subtype = PrimarySkill::ATTACK;
|
||||||
bonus->val = 0;
|
bonus->val = 0;
|
||||||
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
||||||
@ -553,7 +553,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 = Bonus::PRIMARY_SKILL;
|
bonus->type = BonusType::PRIMARY_SKILL;
|
||||||
bonus->subtype = PrimarySkill::DEFENSE;
|
bonus->subtype = PrimarySkill::DEFENSE;
|
||||||
bonus->val = 0;
|
bonus->val = 0;
|
||||||
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
||||||
@ -600,8 +600,8 @@ void CHeroHandler::loadHeroSpecialty(CHero * hero, const JsonNode & node)
|
|||||||
{
|
{
|
||||||
auto prepSpec = [=](std::shared_ptr<Bonus> bonus)
|
auto prepSpec = [=](std::shared_ptr<Bonus> bonus)
|
||||||
{
|
{
|
||||||
bonus->duration = Bonus::PERMANENT;
|
bonus->duration = BonusDuration::PERMANENT;
|
||||||
bonus->source = Bonus::HERO_SPECIAL;
|
bonus->source = BonusSource::HERO_SPECIAL;
|
||||||
bonus->sid = hero->getIndex();
|
bonus->sid = hero->getIndex();
|
||||||
return bonus;
|
return bonus;
|
||||||
};
|
};
|
||||||
|
@ -963,7 +963,7 @@ bool CPathfinderHelper::addTeleportOneWayRandom(const CGTeleport * obj) const
|
|||||||
|
|
||||||
bool CPathfinderHelper::addTeleportWhirlpool(const CGWhirlpool * obj) const
|
bool CPathfinderHelper::addTeleportWhirlpool(const CGWhirlpool * obj) const
|
||||||
{
|
{
|
||||||
return options.useTeleportWhirlpool && hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION) && obj;
|
return options.useTeleportWhirlpool && hasBonusOfType(BonusType::WHIRLPOOL_PROTECTION) && obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CPathfinderHelper::movementPointsAfterEmbark(int movement, int basicCost, bool disembark) const
|
int CPathfinderHelper::movementPointsAfterEmbark(int movement, int basicCost, bool disembark) const
|
||||||
@ -992,15 +992,15 @@ 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()(Bonus::NO_TERRAIN_PENALTY).And(Selector::subtype()(terrain->getIndex())))));
|
bl->getFirst(Selector::type()(BonusType::NO_TERRAIN_PENALTY).And(Selector::subtype()(terrain->getIndex())))));
|
||||||
}
|
}
|
||||||
|
|
||||||
freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type()(Bonus::FREE_SHIP_BOARDING)));
|
freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type()(BonusType::FREE_SHIP_BOARDING)));
|
||||||
flyingMovement = static_cast<bool>(bl->getFirst(Selector::type()(Bonus::FLYING_MOVEMENT)));
|
flyingMovement = static_cast<bool>(bl->getFirst(Selector::type()(BonusType::FLYING_MOVEMENT)));
|
||||||
flyingMovementVal = bl->valOfBonuses(Selector::type()(Bonus::FLYING_MOVEMENT));
|
flyingMovementVal = bl->valOfBonuses(Selector::type()(BonusType::FLYING_MOVEMENT));
|
||||||
waterWalking = static_cast<bool>(bl->getFirst(Selector::type()(Bonus::WATER_WALKING)));
|
waterWalking = static_cast<bool>(bl->getFirst(Selector::type()(BonusType::WATER_WALKING)));
|
||||||
waterWalkingVal = bl->valOfBonuses(Selector::type()(Bonus::WATER_WALKING));
|
waterWalkingVal = bl->valOfBonuses(Selector::type()(BonusType::WATER_WALKING));
|
||||||
pathfindingVal = bl->valOfBonuses(Selector::type()(Bonus::ROUGH_TERRAIN_DISCOUNT));
|
pathfindingVal = bl->valOfBonuses(Selector::type()(BonusType::ROUGH_TERRAIN_DISCOUNT));
|
||||||
}
|
}
|
||||||
|
|
||||||
TurnInfo::TurnInfo(const CGHeroInstance * Hero, const int turn):
|
TurnInfo::TurnInfo(const CGHeroInstance * Hero, const int turn):
|
||||||
@ -1022,7 +1022,7 @@ bool TurnInfo::isLayerAvailable(const EPathfindingLayer & layer) const
|
|||||||
if(hero && hero->boat && hero->boat->layer == EPathfindingLayer::AIR)
|
if(hero && hero->boat && hero->boat->layer == EPathfindingLayer::AIR)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(!hasBonusOfType(Bonus::FLYING_MOVEMENT))
|
if(!hasBonusOfType(BonusType::FLYING_MOVEMENT))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -1031,7 +1031,7 @@ bool TurnInfo::isLayerAvailable(const EPathfindingLayer & layer) const
|
|||||||
if(hero && hero->boat && hero->boat->layer == EPathfindingLayer::WATER)
|
if(hero && hero->boat && hero->boat->layer == EPathfindingLayer::WATER)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(!hasBonusOfType(Bonus::WATER_WALKING))
|
if(!hasBonusOfType(BonusType::WATER_WALKING))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -1040,17 +1040,17 @@ bool TurnInfo::isLayerAvailable(const EPathfindingLayer & layer) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TurnInfo::hasBonusOfType(Bonus::BonusType type, int subtype) const
|
bool TurnInfo::hasBonusOfType(BonusType type, int subtype) const
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case Bonus::FREE_SHIP_BOARDING:
|
case BonusType::FREE_SHIP_BOARDING:
|
||||||
return bonusCache->freeShipBoarding;
|
return bonusCache->freeShipBoarding;
|
||||||
case Bonus::FLYING_MOVEMENT:
|
case BonusType::FLYING_MOVEMENT:
|
||||||
return bonusCache->flyingMovement;
|
return bonusCache->flyingMovement;
|
||||||
case Bonus::WATER_WALKING:
|
case BonusType::WATER_WALKING:
|
||||||
return bonusCache->waterWalking;
|
return bonusCache->waterWalking;
|
||||||
case Bonus::NO_TERRAIN_PENALTY:
|
case BonusType::NO_TERRAIN_PENALTY:
|
||||||
return bonusCache->noTerrainPenalty[subtype];
|
return bonusCache->noTerrainPenalty[subtype];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1058,15 +1058,15 @@ bool TurnInfo::hasBonusOfType(Bonus::BonusType type, int subtype) const
|
|||||||
bonuses->getFirst(Selector::type()(type).And(Selector::subtype()(subtype))));
|
bonuses->getFirst(Selector::type()(type).And(Selector::subtype()(subtype))));
|
||||||
}
|
}
|
||||||
|
|
||||||
int TurnInfo::valOfBonuses(Bonus::BonusType type, int subtype) const
|
int TurnInfo::valOfBonuses(BonusType type, int subtype) const
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case Bonus::FLYING_MOVEMENT:
|
case BonusType::FLYING_MOVEMENT:
|
||||||
return bonusCache->flyingMovementVal;
|
return bonusCache->flyingMovementVal;
|
||||||
case Bonus::WATER_WALKING:
|
case BonusType::WATER_WALKING:
|
||||||
return bonusCache->waterWalkingVal;
|
return bonusCache->waterWalkingVal;
|
||||||
case Bonus::ROUGH_TERRAIN_DISCOUNT:
|
case BonusType::ROUGH_TERRAIN_DISCOUNT:
|
||||||
return bonusCache->pathfindingVal;
|
return bonusCache->pathfindingVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1083,23 +1083,23 @@ int TurnInfo::getMaxMovePoints(const EPathfindingLayer & layer) const
|
|||||||
return layer == EPathfindingLayer::SAIL ? maxMovePointsWater : maxMovePointsLand;
|
return layer == EPathfindingLayer::SAIL ? maxMovePointsWater : maxMovePointsLand;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TurnInfo::updateHeroBonuses(Bonus::BonusType type, const CSelector& sel) const
|
void TurnInfo::updateHeroBonuses(BonusType type, const CSelector& sel) const
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case Bonus::FREE_SHIP_BOARDING:
|
case BonusType::FREE_SHIP_BOARDING:
|
||||||
bonusCache->freeShipBoarding = static_cast<bool>(bonuses->getFirst(Selector::type()(Bonus::FREE_SHIP_BOARDING)));
|
bonusCache->freeShipBoarding = static_cast<bool>(bonuses->getFirst(Selector::type()(BonusType::FREE_SHIP_BOARDING)));
|
||||||
break;
|
break;
|
||||||
case Bonus::FLYING_MOVEMENT:
|
case BonusType::FLYING_MOVEMENT:
|
||||||
bonusCache->flyingMovement = static_cast<bool>(bonuses->getFirst(Selector::type()(Bonus::FLYING_MOVEMENT)));
|
bonusCache->flyingMovement = static_cast<bool>(bonuses->getFirst(Selector::type()(BonusType::FLYING_MOVEMENT)));
|
||||||
bonusCache->flyingMovementVal = bonuses->valOfBonuses(Selector::type()(Bonus::FLYING_MOVEMENT));
|
bonusCache->flyingMovementVal = bonuses->valOfBonuses(Selector::type()(BonusType::FLYING_MOVEMENT));
|
||||||
break;
|
break;
|
||||||
case Bonus::WATER_WALKING:
|
case BonusType::WATER_WALKING:
|
||||||
bonusCache->waterWalking = static_cast<bool>(bonuses->getFirst(Selector::type()(Bonus::WATER_WALKING)));
|
bonusCache->waterWalking = static_cast<bool>(bonuses->getFirst(Selector::type()(BonusType::WATER_WALKING)));
|
||||||
bonusCache->waterWalkingVal = bonuses->valOfBonuses(Selector::type()(Bonus::WATER_WALKING));
|
bonusCache->waterWalkingVal = bonuses->valOfBonuses(Selector::type()(BonusType::WATER_WALKING));
|
||||||
break;
|
break;
|
||||||
case Bonus::ROUGH_TERRAIN_DISCOUNT:
|
case BonusType::ROUGH_TERRAIN_DISCOUNT:
|
||||||
bonusCache->pathfindingVal = bonuses->valOfBonuses(Selector::type()(Bonus::ROUGH_TERRAIN_DISCOUNT));
|
bonusCache->pathfindingVal = bonuses->valOfBonuses(Selector::type()(BonusType::ROUGH_TERRAIN_DISCOUNT));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
bonuses = hero->getAllBonuses(Selector::days(turn), Selector::all, nullptr, "");
|
bonuses = hero->getAllBonuses(Selector::days(turn), Selector::all, nullptr, "");
|
||||||
@ -1162,7 +1162,7 @@ const TurnInfo * CPathfinderHelper::getTurnInfo() const
|
|||||||
return turnsInfo[turn];
|
return turnsInfo[turn];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPathfinderHelper::hasBonusOfType(const Bonus::BonusType type, const int subtype) const
|
bool CPathfinderHelper::hasBonusOfType(const BonusType type, const int subtype) const
|
||||||
{
|
{
|
||||||
return turnsInfo[turn]->hasBonusOfType(type, subtype);
|
return turnsInfo[turn]->hasBonusOfType(type, subtype);
|
||||||
}
|
}
|
||||||
@ -1248,11 +1248,11 @@ int CPathfinderHelper::getMovementCost(
|
|||||||
|
|
||||||
bool isWaterLayer;
|
bool isWaterLayer;
|
||||||
if(indeterminate(isDstWaterLayer))
|
if(indeterminate(isDstWaterLayer))
|
||||||
isWaterLayer = ((hero->boat && hero->boat->layer == EPathfindingLayer::WATER) || ti->hasBonusOfType(Bonus::WATER_WALKING)) && dt->terType->isWater();
|
isWaterLayer = ((hero->boat && hero->boat->layer == EPathfindingLayer::WATER) || ti->hasBonusOfType(BonusType::WATER_WALKING)) && dt->terType->isWater();
|
||||||
else
|
else
|
||||||
isWaterLayer = static_cast<bool>(isDstWaterLayer);
|
isWaterLayer = static_cast<bool>(isDstWaterLayer);
|
||||||
|
|
||||||
bool isAirLayer = (hero->boat && hero->boat->layer == EPathfindingLayer::AIR) || ti->hasBonusOfType(Bonus::FLYING_MOVEMENT);
|
bool isAirLayer = (hero->boat && hero->boat->layer == EPathfindingLayer::AIR) || ti->hasBonusOfType(BonusType::FLYING_MOVEMENT);
|
||||||
|
|
||||||
int ret = hero->getTileCost(*dt, *ct, ti);
|
int ret = hero->getTileCost(*dt, *ct, ti);
|
||||||
if(isSailLayer)
|
if(isSailLayer)
|
||||||
@ -1261,9 +1261,9 @@ int CPathfinderHelper::getMovementCost(
|
|||||||
ret = static_cast<int>(ret * 2.0 / 3);
|
ret = static_cast<int>(ret * 2.0 / 3);
|
||||||
}
|
}
|
||||||
else if(isAirLayer)
|
else if(isAirLayer)
|
||||||
vstd::amin(ret, GameConstants::BASE_MOVEMENT_COST + ti->valOfBonuses(Bonus::FLYING_MOVEMENT));
|
vstd::amin(ret, GameConstants::BASE_MOVEMENT_COST + ti->valOfBonuses(BonusType::FLYING_MOVEMENT));
|
||||||
else if(isWaterLayer && ti->hasBonusOfType(Bonus::WATER_WALKING))
|
else if(isWaterLayer && ti->hasBonusOfType(BonusType::WATER_WALKING))
|
||||||
ret = static_cast<int>(ret * (100.0 + ti->valOfBonuses(Bonus::WATER_WALKING)) / 100.0);
|
ret = static_cast<int>(ret * (100.0 + ti->valOfBonuses(BonusType::WATER_WALKING)) / 100.0);
|
||||||
|
|
||||||
if(src.x != dst.x && src.y != dst.y) //it's diagonal move
|
if(src.x != dst.x && src.y != dst.y) //it's diagonal move
|
||||||
{
|
{
|
||||||
|
@ -530,9 +530,9 @@ 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 Bonus::BonusType type, const int subtype = -1) const;
|
bool hasBonusOfType(const BonusType type, const int subtype = -1) const;
|
||||||
int valOfBonuses(const Bonus::BonusType type, const int subtype = -1) const;
|
int valOfBonuses(const BonusType type, const int subtype = -1) const;
|
||||||
void updateHeroBonuses(Bonus::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;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -561,7 +561,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 Bonus::BonusType type, const int subtype = -1) const;
|
bool hasBonusOfType(const BonusType type, const int subtype = -1) 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;
|
||||||
|
@ -90,9 +90,9 @@ SecondarySkill CSkill::getId() const
|
|||||||
|
|
||||||
void CSkill::addNewBonus(const std::shared_ptr<Bonus> & b, int level)
|
void CSkill::addNewBonus(const std::shared_ptr<Bonus> & b, int level)
|
||||||
{
|
{
|
||||||
b->source = Bonus::SECONDARY_SKILL;
|
b->source = BonusSource::SECONDARY_SKILL;
|
||||||
b->sid = id;
|
b->sid = id;
|
||||||
b->duration = Bonus::PERMANENT;
|
b->duration = BonusDuration::PERMANENT;
|
||||||
b->description = getNameTranslated();
|
b->description = getNameTranslated();
|
||||||
levels[level-1].effects.push_back(b);
|
levels[level-1].effects.push_back(b);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ si32 CStack::magicResistance() const
|
|||||||
for(const auto * one : battle->battleAdjacentUnits(this))
|
for(const auto * one : battle->battleAdjacentUnits(this))
|
||||||
{
|
{
|
||||||
if(one->unitOwner() == owner)
|
if(one->unitOwner() == owner)
|
||||||
vstd::amax(auraBonus, one->valOfBonuses(Bonus::SPELL_RESISTANCE_AURA)); //max value
|
vstd::amax(auraBonus, one->valOfBonuses(BonusType::SPELL_RESISTANCE_AURA)); //max value
|
||||||
}
|
}
|
||||||
vstd::abetween(auraBonus, 0, 100);
|
vstd::abetween(auraBonus, 0, 100);
|
||||||
vstd::abetween(magicResistance, 0, 100);
|
vstd::abetween(magicResistance, 0, 100);
|
||||||
@ -125,11 +125,11 @@ std::vector<si32> CStack::activeSpells() const
|
|||||||
std::vector<si32> ret;
|
std::vector<si32> ret;
|
||||||
|
|
||||||
std::stringstream cachingStr;
|
std::stringstream cachingStr;
|
||||||
cachingStr << "!type_" << Bonus::NONE << "source_" << Bonus::SPELL_EFFECT;
|
cachingStr << "!type_" << vstd::to_underlying(BonusType::NONE) << "source_" << vstd::to_underlying(BonusSource::SPELL_EFFECT);
|
||||||
CSelector selector = Selector::sourceType()(Bonus::SPELL_EFFECT)
|
CSelector selector = Selector::sourceType()(BonusSource::SPELL_EFFECT)
|
||||||
.And(CSelector([](const Bonus * b)->bool
|
.And(CSelector([](const Bonus * b)->bool
|
||||||
{
|
{
|
||||||
return b->type != Bonus::NONE && SpellID(b->sid).toSpell() && !SpellID(b->sid).toSpell()->isAdventure();
|
return b->type != BonusType::NONE && SpellID(b->sid).toSpell() && !SpellID(b->sid).toSpell()->isAdventure();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
TConstBonusListPtr spellEffects = getBonuses(selector, Selector::all, cachingStr.str());
|
TConstBonusListPtr spellEffects = getBonuses(selector, Selector::all, cachingStr.str());
|
||||||
@ -198,7 +198,7 @@ void CStack::prepareAttacked(BattleStackAttacked & bsa, vstd::RNG & rand, const
|
|||||||
{
|
{
|
||||||
bsa.flags |= BattleStackAttacked::KILLED;
|
bsa.flags |= BattleStackAttacked::KILLED;
|
||||||
|
|
||||||
auto resurrectValue = customState->valOfBonuses(Bonus::REBIRTH);
|
auto resurrectValue = customState->valOfBonuses(BonusType::REBIRTH);
|
||||||
|
|
||||||
if(resurrectValue > 0 && customState->canCast()) //there must be casts left
|
if(resurrectValue > 0 && customState->canCast()) //there must be casts left
|
||||||
{
|
{
|
||||||
@ -220,7 +220,7 @@ void CStack::prepareAttacked(BattleStackAttacked & bsa, vstd::RNG & rand, const
|
|||||||
resurrectedCount += 1;
|
resurrectedCount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(customState->hasBonusOfType(Bonus::REBIRTH, 1))
|
if(customState->hasBonusOfType(BonusType::REBIRTH, 1))
|
||||||
{
|
{
|
||||||
// resurrect at least one Sacred Phoenix
|
// resurrect at least one Sacred Phoenix
|
||||||
vstd::amax(resurrectedCount, 1);
|
vstd::amax(resurrectedCount, 1);
|
||||||
@ -308,7 +308,7 @@ std::string CStack::getName() const
|
|||||||
|
|
||||||
bool CStack::canBeHealed() const
|
bool CStack::canBeHealed() const
|
||||||
{
|
{
|
||||||
return getFirstHPleft() < static_cast<int32_t>(getMaxHealth()) && isValidTarget() && !hasBonusOfType(Bonus::SIEGE_WEAPON);
|
return getFirstHPleft() < static_cast<int32_t>(getMaxHealth()) && isValidTarget() && !hasBonusOfType(BonusType::SIEGE_WEAPON);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CStack::isOnNativeTerrain() const
|
bool CStack::isOnNativeTerrain() const
|
||||||
|
@ -500,7 +500,7 @@ void CTownHandler::addBonusesForVanilaBuilding(CBuilding * building) const
|
|||||||
{
|
{
|
||||||
if(building->bid == BuildingID::TAVERN)
|
if(building->bid == BuildingID::TAVERN)
|
||||||
{
|
{
|
||||||
b = createBonus(building, Bonus::MORALE, +1);
|
b = createBonus(building, BonusType::MORALE, +1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -508,23 +508,23 @@ void CTownHandler::addBonusesForVanilaBuilding(CBuilding * building) const
|
|||||||
switch(building->subId)
|
switch(building->subId)
|
||||||
{
|
{
|
||||||
case BuildingSubID::BROTHERHOOD_OF_SWORD:
|
case BuildingSubID::BROTHERHOOD_OF_SWORD:
|
||||||
b = createBonus(building, Bonus::MORALE, +2);
|
b = createBonus(building, BonusType::MORALE, +2);
|
||||||
building->overrideBids.insert(BuildingID::TAVERN);
|
building->overrideBids.insert(BuildingID::TAVERN);
|
||||||
break;
|
break;
|
||||||
case BuildingSubID::FOUNTAIN_OF_FORTUNE:
|
case BuildingSubID::FOUNTAIN_OF_FORTUNE:
|
||||||
b = createBonus(building, Bonus::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, Bonus::PRIMARY_SKILL, +2, PrimarySkill::SPELL_POWER);
|
b = createBonus(building, BonusType::PRIMARY_SKILL, +2, PrimarySkill::SPELL_POWER);
|
||||||
break;
|
break;
|
||||||
case BuildingSubID::ATTACK_GARRISON_BONUS:
|
case BuildingSubID::ATTACK_GARRISON_BONUS:
|
||||||
b = createBonus(building, Bonus::PRIMARY_SKILL, +2, PrimarySkill::ATTACK);
|
b = createBonus(building, BonusType::PRIMARY_SKILL, +2, PrimarySkill::ATTACK);
|
||||||
break;
|
break;
|
||||||
case BuildingSubID::DEFENSE_GARRISON_BONUS:
|
case BuildingSubID::DEFENSE_GARRISON_BONUS:
|
||||||
b = createBonus(building, Bonus::PRIMARY_SKILL, +2, PrimarySkill::DEFENSE);
|
b = createBonus(building, BonusType::PRIMARY_SKILL, +2, PrimarySkill::DEFENSE);
|
||||||
break;
|
break;
|
||||||
case BuildingSubID::LIGHTHOUSE:
|
case BuildingSubID::LIGHTHOUSE:
|
||||||
b = createBonus(building, Bonus::MOVEMENT, +500, playerPropagator, 0);
|
b = createBonus(building, BonusType::MOVEMENT, +500, playerPropagator, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -532,12 +532,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, Bonus::BonusType type, int val, int subtype) const
|
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, int subtype) const
|
||||||
{
|
{
|
||||||
return createBonus(build, type, val, emptyPropagator(), subtype);
|
return createBonus(build, type, val, emptyPropagator(), subtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype) const
|
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, BonusType type, int val, TPropagatorPtr & prop, int subtype) const
|
||||||
{
|
{
|
||||||
std::ostringstream descr;
|
std::ostringstream descr;
|
||||||
descr << build->getNameTranslated();
|
descr << build->getNameTranslated();
|
||||||
@ -545,13 +545,13 @@ std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, Bonus::Bonus
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Bonus> CTownHandler::createBonusImpl(const BuildingID & building,
|
std::shared_ptr<Bonus> CTownHandler::createBonusImpl(const BuildingID & building,
|
||||||
Bonus::BonusType type,
|
BonusType type,
|
||||||
int val,
|
int val,
|
||||||
TPropagatorPtr & prop,
|
TPropagatorPtr & prop,
|
||||||
const std::string & description,
|
const std::string & description,
|
||||||
int subtype) const
|
int subtype) const
|
||||||
{
|
{
|
||||||
auto b = std::make_shared<Bonus>(Bonus::PERMANENT, type, Bonus::TOWN_STRUCTURE, val, building, description, subtype);
|
auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, type, BonusSource::TOWN_STRUCTURE, val, building, description, subtype);
|
||||||
|
|
||||||
if(prop)
|
if(prop)
|
||||||
b->addPropagator(prop);
|
b->addPropagator(prop);
|
||||||
|
@ -376,10 +376,10 @@ 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, Bonus::BonusType type, int val, int subtype = -1) const;
|
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, int subtype = -1) const;
|
||||||
std::shared_ptr<Bonus> createBonus(CBuilding * build, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype = -1) const;
|
std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, TPropagatorPtr & prop, int subtype = -1) const;
|
||||||
std::shared_ptr<Bonus> createBonusImpl(const BuildingID & building,
|
std::shared_ptr<Bonus> createBonusImpl(const BuildingID & building,
|
||||||
Bonus::BonusType type,
|
BonusType type,
|
||||||
int val,
|
int val,
|
||||||
TPropagatorPtr & prop,
|
TPropagatorPtr & prop,
|
||||||
const std::string & description,
|
const std::string & description,
|
||||||
|
@ -485,7 +485,7 @@ void JsonUtils::parseTypedBonusShort(const JsonVector & source, const std::share
|
|||||||
dest->val = static_cast<si32>(source[1].Float());
|
dest->val = static_cast<si32>(source[1].Float());
|
||||||
resolveIdentifier(source[2],dest->subtype);
|
resolveIdentifier(source[2],dest->subtype);
|
||||||
dest->additionalInfo = static_cast<si32>(source[3].Float());
|
dest->additionalInfo = static_cast<si32>(source[3].Float());
|
||||||
dest->duration = Bonus::PERMANENT; //TODO: handle flags (as integer)
|
dest->duration = BonusDuration::PERMANENT; //TODO: handle flags (as integer)
|
||||||
dest->turnsRemain = 0;
|
dest->turnsRemain = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,11 +821,11 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability)
|
|||||||
|
|
||||||
std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode & ability, const BuildingID & building, const std::string & description)
|
std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode & ability, const BuildingID & building, const std::string & description)
|
||||||
{
|
{
|
||||||
/* duration = Bonus::PERMANENT
|
/* duration = BonusDuration::PERMANENT
|
||||||
source = Bonus::TOWN_STRUCTURE
|
source = BonusSource::TOWN_STRUCTURE
|
||||||
bonusType, val, subtype - get from json
|
bonusType, val, subtype - get from json
|
||||||
*/
|
*/
|
||||||
auto b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::NONE, Bonus::TOWN_STRUCTURE, 0, building, description, -1);
|
auto b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::NONE, BonusSource::TOWN_STRUCTURE, 0, building, description, -1);
|
||||||
|
|
||||||
if(!parseBonus(ability, b.get()))
|
if(!parseBonus(ability, b.get()))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -846,14 +846,14 @@ static BonusParams convertDeprecatedBonus(const JsonNode &ability)
|
|||||||
params.val = static_cast<si32>(ability["val"].Float());
|
params.val = static_cast<si32>(ability["val"].Float());
|
||||||
params.valRelevant = true;
|
params.valRelevant = true;
|
||||||
}
|
}
|
||||||
Bonus::ValueType valueType = Bonus::ADDITIVE_VALUE;
|
BonusValueType valueType = BonusValueType::ADDITIVE_VALUE;
|
||||||
if(!ability["valueType"].isNull())
|
if(!ability["valueType"].isNull())
|
||||||
valueType = bonusValueMap.find(ability["valueType"].String())->second;
|
valueType = bonusValueMap.find(ability["valueType"].String())->second;
|
||||||
|
|
||||||
if(ability["type"].String() == "SECONDARY_SKILL_PREMY" && valueType == Bonus::PERCENT_TO_BASE) //assume secondary skill special
|
if(ability["type"].String() == "SECONDARY_SKILL_PREMY" && valueType == BonusValueType::PERCENT_TO_BASE) //assume secondary skill special
|
||||||
{
|
{
|
||||||
params.valueType = Bonus::PERCENT_TO_TARGET_TYPE;
|
params.valueType = BonusValueType::PERCENT_TO_TARGET_TYPE;
|
||||||
params.targetType = Bonus::SECONDARY_SKILL;
|
params.targetType = BonusSource::SECONDARY_SKILL;
|
||||||
params.targetTypeRelevant = true;
|
params.targetTypeRelevant = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -946,7 +946,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
|||||||
|
|
||||||
value = &ability["valueType"];
|
value = &ability["valueType"];
|
||||||
if (!value->isNull())
|
if (!value->isNull())
|
||||||
b->valType = static_cast<Bonus::ValueType>(parseByMapN(bonusValueMap, value, "value type "));
|
b->valType = static_cast<BonusValueType>(parseByMapN(bonusValueMap, value, "value type "));
|
||||||
}
|
}
|
||||||
|
|
||||||
b->stacking = ability["stacking"].String();
|
b->stacking = ability["stacking"].String();
|
||||||
@ -967,7 +967,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
|||||||
|
|
||||||
value = &ability["effectRange"];
|
value = &ability["effectRange"];
|
||||||
if (!value->isNull())
|
if (!value->isNull())
|
||||||
b->effectRange = static_cast<Bonus::LimitEffect>(parseByMapN(bonusLimitEffect, value, "effect range "));
|
b->effectRange = static_cast<BonusLimitEffect>(parseByMapN(bonusLimitEffect, value, "effect range "));
|
||||||
|
|
||||||
value = &ability["duration"];
|
value = &ability["duration"];
|
||||||
if (!value->isNull())
|
if (!value->isNull())
|
||||||
@ -975,17 +975,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
|||||||
switch (value->getType())
|
switch (value->getType())
|
||||||
{
|
{
|
||||||
case JsonNode::JsonType::DATA_STRING:
|
case JsonNode::JsonType::DATA_STRING:
|
||||||
b->duration = static_cast<Bonus::BonusDuration>(parseByMap(bonusDurationMap, value, "duration type "));
|
b->duration = static_cast<BonusDuration>(parseByMap(bonusDurationMap, value, "duration type "));
|
||||||
break;
|
|
||||||
case JsonNode::JsonType::DATA_VECTOR:
|
|
||||||
{
|
|
||||||
ui16 dur = 0;
|
|
||||||
for (const JsonNode & d : value->Vector())
|
|
||||||
{
|
|
||||||
dur |= parseByMapN(bonusDurationMap, &d, "duration type ");
|
|
||||||
}
|
|
||||||
b->duration = static_cast<Bonus::BonusDuration>(dur);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logMod->error("Error! Wrong bonus duration format.");
|
logMod->error("Error! Wrong bonus duration format.");
|
||||||
@ -994,11 +984,11 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
|
|||||||
|
|
||||||
value = &ability["sourceType"];
|
value = &ability["sourceType"];
|
||||||
if (!value->isNull())
|
if (!value->isNull())
|
||||||
b->source = static_cast<Bonus::BonusSource>(parseByMap(bonusSourceMap, value, "source type "));
|
b->source = static_cast<BonusSource>(parseByMap(bonusSourceMap, value, "source type "));
|
||||||
|
|
||||||
value = &ability["targetSourceType"];
|
value = &ability["targetSourceType"];
|
||||||
if (!value->isNull())
|
if (!value->isNull())
|
||||||
b->targetSourceType = static_cast<Bonus::BonusSource>(parseByMap(bonusSourceMap, value, "target type "));
|
b->targetSourceType = static_cast<BonusSource>(parseByMap(bonusSourceMap, value, "target type "));
|
||||||
|
|
||||||
value = &ability["limiters"];
|
value = &ability["limiters"];
|
||||||
if (!value->isNull())
|
if (!value->isNull())
|
||||||
@ -1075,7 +1065,7 @@ CSelector JsonUtils::parseSelector(const JsonNode & ability)
|
|||||||
ret = ret.And(Selector::subtype()(subtype));
|
ret = ret.And(Selector::subtype()(subtype));
|
||||||
}
|
}
|
||||||
value = &ability["sourceType"];
|
value = &ability["sourceType"];
|
||||||
Bonus::BonusSource src = Bonus::OTHER; //Fixes for GCC false maybe-uninitialized
|
BonusSource src = BonusSource::OTHER; //Fixes for GCC false maybe-uninitialized
|
||||||
si32 id = 0;
|
si32 id = 0;
|
||||||
auto sourceIDRelevant = false;
|
auto sourceIDRelevant = false;
|
||||||
auto sourceTypeRelevant = false;
|
auto sourceTypeRelevant = false;
|
||||||
|
@ -982,13 +982,13 @@ void GiveBonus::applyGs(CGameState *gs)
|
|||||||
|
|
||||||
std::string &descr = b->description;
|
std::string &descr = b->description;
|
||||||
|
|
||||||
if(bdescr.message.empty() && (bonus.type == Bonus::LUCK || bonus.type == Bonus::MORALE))
|
if(bdescr.message.empty() && (bonus.type == BonusType::LUCK || bonus.type == BonusType::MORALE))
|
||||||
{
|
{
|
||||||
if (bonus.source == Bonus::OBJECT)
|
if (bonus.source == BonusSource::OBJECT)
|
||||||
{
|
{
|
||||||
descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle"
|
descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle"
|
||||||
}
|
}
|
||||||
else if(bonus.source == Bonus::TOWN_STRUCTURE)
|
else if(bonus.source == BonusSource::TOWN_STRUCTURE)
|
||||||
{
|
{
|
||||||
descr = bonus.description;
|
descr = bonus.description;
|
||||||
return;
|
return;
|
||||||
@ -1124,7 +1124,7 @@ void RemoveBonus::applyGs(CGameState *gs)
|
|||||||
|
|
||||||
for(const auto & b : bonuses)
|
for(const auto & b : bonuses)
|
||||||
{
|
{
|
||||||
if(b->source == source && b->sid == id)
|
if(vstd::to_underlying(b->source) == source && b->sid == id)
|
||||||
{
|
{
|
||||||
bonus = *b; //backup bonus (to show to interfaces later)
|
bonus = *b; //backup bonus (to show to interfaces later)
|
||||||
node->removeBonus(b);
|
node->removeBonus(b);
|
||||||
@ -2155,15 +2155,15 @@ void BattleTriggerEffect::applyGs(CGameState * gs) const
|
|||||||
{
|
{
|
||||||
CStack * st = gs->curB->getStack(stackID);
|
CStack * st = gs->curB->getStack(stackID);
|
||||||
assert(st);
|
assert(st);
|
||||||
switch(effect)
|
switch(static_cast<BonusType>(effect))
|
||||||
{
|
{
|
||||||
case Bonus::HP_REGENERATION:
|
case BonusType::HP_REGENERATION:
|
||||||
{
|
{
|
||||||
int64_t toHeal = val;
|
int64_t toHeal = val;
|
||||||
st->heal(toHeal, EHealLevel::HEAL, EHealPower::PERMANENT);
|
st->heal(toHeal, EHealLevel::HEAL, EHealPower::PERMANENT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Bonus::MANA_DRAIN:
|
case BonusType::MANA_DRAIN:
|
||||||
{
|
{
|
||||||
CGHeroInstance * h = gs->getHero(ObjectInstanceID(additionalInfo));
|
CGHeroInstance * h = gs->getHero(ObjectInstanceID(additionalInfo));
|
||||||
st->drainedMana = true;
|
st->drainedMana = true;
|
||||||
@ -2171,18 +2171,18 @@ void BattleTriggerEffect::applyGs(CGameState * gs) const
|
|||||||
vstd::amax(h->mana, 0);
|
vstd::amax(h->mana, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Bonus::POISON:
|
case BonusType::POISON:
|
||||||
{
|
{
|
||||||
auto b = st->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT, SpellID::POISON)
|
auto b = st->getBonusLocalFirst(Selector::source(BonusSource::SPELL_EFFECT, SpellID::POISON)
|
||||||
.And(Selector::type()(Bonus::STACK_HEALTH)));
|
.And(Selector::type()(BonusType::STACK_HEALTH)));
|
||||||
if (b)
|
if (b)
|
||||||
b->val = val;
|
b->val = val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Bonus::ENCHANTER:
|
case BonusType::ENCHANTER:
|
||||||
case Bonus::MORALE:
|
case BonusType::MORALE:
|
||||||
break;
|
break;
|
||||||
case Bonus::FEAR:
|
case BonusType::FEAR:
|
||||||
st->fear = true;
|
st->fear = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -2477,7 +2477,7 @@ void BattleSetStackProperty::applyGs(CGameState * gs) const
|
|||||||
}
|
}
|
||||||
case UNBIND:
|
case UNBIND:
|
||||||
{
|
{
|
||||||
stack->removeBonusesRecursive(Selector::type()(Bonus::BIND_EFFECT));
|
stack->removeBonusesRecursive(Selector::type()(BonusType::BIND_EFFECT));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CLONED:
|
case CLONED:
|
||||||
|
@ -52,7 +52,7 @@ BattleAction BattleAction::makeMeleeAttack(const battle::Unit * stack, BattleHex
|
|||||||
ba.stackNumber = stack->unitId();
|
ba.stackNumber = stack->unitId();
|
||||||
ba.aimToHex(attackFrom);
|
ba.aimToHex(attackFrom);
|
||||||
ba.aimToHex(destination);
|
ba.aimToHex(destination);
|
||||||
if(returnAfterAttack && stack->hasBonusOfType(Bonus::RETURN_AFTER_STRIKE))
|
if(returnAfterAttack && stack->hasBonusOfType(BonusType::RETURN_AFTER_STRIKE))
|
||||||
ba.aimToHex(stack->getPosition());
|
ba.aimToHex(stack->getPosition());
|
||||||
return ba;
|
return ba;
|
||||||
}
|
}
|
||||||
|
@ -473,9 +473,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>(Bonus::ONE_BATTLE, Bonus::STACKS_SPEED, Bonus::TERRAIN_NATIVE, 1, 0, 0)->addLimiter(nativeTerrain));
|
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>(Bonus::ONE_BATTLE, Bonus::PRIMARY_SKILL, Bonus::TERRAIN_NATIVE, 1, 0, PrimarySkill::ATTACK)->addLimiter(nativeTerrain));
|
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, 0, PrimarySkill::ATTACK)->addLimiter(nativeTerrain));
|
||||||
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::PRIMARY_SKILL, Bonus::TERRAIN_NATIVE, 1, 0, PrimarySkill::DEFENSE)->addLimiter(nativeTerrain));
|
curB->addNewBonus(std::make_shared<Bonus>(BonusDuration::ONE_BATTLE, BonusType::PRIMARY_SKILL, BonusSource::TERRAIN_NATIVE, 1, 0, PrimarySkill::DEFENSE)->addLimiter(nativeTerrain));
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//tactics
|
//tactics
|
||||||
@ -489,8 +489,8 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
|||||||
{
|
{
|
||||||
if(heroes[i])
|
if(heroes[i])
|
||||||
{
|
{
|
||||||
battleRepositionHex[i] += heroes[i]->valOfBonuses(Selector::type()(Bonus::BEFORE_BATTLE_REPOSITION));
|
battleRepositionHex[i] += heroes[i]->valOfBonuses(Selector::type()(BonusType::BEFORE_BATTLE_REPOSITION));
|
||||||
battleRepositionHexBlock[i] += heroes[i]->valOfBonuses(Selector::type()(Bonus::BEFORE_BATTLE_REPOSITION_BLOCK));
|
battleRepositionHexBlock[i] += heroes[i]->valOfBonuses(Selector::type()(BonusType::BEFORE_BATTLE_REPOSITION_BLOCK));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int tacticsSkillDiffAttacker = battleRepositionHex[BattleSide::ATTACKER] - battleRepositionHexBlock[BattleSide::DEFENDER];
|
int tacticsSkillDiffAttacker = battleRepositionHex[BattleSide::ATTACKER] - battleRepositionHexBlock[BattleSide::DEFENDER];
|
||||||
@ -803,7 +803,7 @@ void BattleInfo::setUnitState(uint32_t id, const JsonNode & data, int64_t health
|
|||||||
auto selector = [](const Bonus * b)
|
auto selector = [](const Bonus * b)
|
||||||
{
|
{
|
||||||
//Special case: DISRUPTING_RAY is absolutely permanent
|
//Special case: DISRUPTING_RAY is absolutely permanent
|
||||||
return b->source == Bonus::SPELL_EFFECT && b->sid != SpellID::DISRUPTING_RAY;
|
return b->source == BonusSource::SPELL_EFFECT && b->sid != SpellID::DISRUPTING_RAY;
|
||||||
};
|
};
|
||||||
changedStack->removeBonusesRecursive(selector);
|
changedStack->removeBonusesRecursive(selector);
|
||||||
}
|
}
|
||||||
@ -929,7 +929,7 @@ uint32_t BattleInfo::nextUnitId() const
|
|||||||
|
|
||||||
void BattleInfo::addOrUpdateUnitBonus(CStack * sta, const Bonus & value, bool forceAdd)
|
void BattleInfo::addOrUpdateUnitBonus(CStack * sta, const Bonus & value, bool forceAdd)
|
||||||
{
|
{
|
||||||
if(forceAdd || !sta->hasBonus(Selector::source(Bonus::SPELL_EFFECT, value.sid).And(Selector::typeSubtype(value.type, value.subtype))))
|
if(forceAdd || !sta->hasBonus(Selector::source(BonusSource::SPELL_EFFECT, value.sid).And(Selector::typeSubtype(value.type, value.subtype))))
|
||||||
{
|
{
|
||||||
//no such effect or cumulative - add new
|
//no such effect or cumulative - add new
|
||||||
logBonus->trace("%s receives a new bonus: %s", sta->nodeName(), value.Description());
|
logBonus->trace("%s receives a new bonus: %s", sta->nodeName(), value.Description());
|
||||||
|
@ -126,7 +126,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(con
|
|||||||
|
|
||||||
if(!hero)
|
if(!hero)
|
||||||
return ESpellCastProblem::NO_HERO_TO_CAST_SPELL;
|
return ESpellCastProblem::NO_HERO_TO_CAST_SPELL;
|
||||||
if(hero->hasBonusOfType(Bonus::BLOCK_ALL_MAGIC))
|
if(hero->hasBonusOfType(BonusType::BLOCK_ALL_MAGIC))
|
||||||
return ESpellCastProblem::MAGIC_IS_BLOCKED;
|
return ESpellCastProblem::MAGIC_IS_BLOCKED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -204,7 +204,7 @@ bool CBattleInfoCallback::battleHasWallPenalty(const IBonusBearer * shooter, Bat
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
const std::string cachingStrNoWallPenalty = "type_NO_WALL_PENALTY";
|
const std::string cachingStrNoWallPenalty = "type_NO_WALL_PENALTY";
|
||||||
static const auto selectorNoWallPenalty = Selector::type()(Bonus::NO_WALL_PENALTY);
|
static const auto selectorNoWallPenalty = Selector::type()(BonusType::NO_WALL_PENALTY);
|
||||||
|
|
||||||
if(shooter->hasBonus(selectorNoWallPenalty, cachingStrNoWallPenalty))
|
if(shooter->hasBonus(selectorNoWallPenalty, cachingStrNoWallPenalty))
|
||||||
return false;
|
return false;
|
||||||
@ -227,7 +227,7 @@ std::vector<PossiblePlayerBattleAction> CBattleInfoCallback::getClientActionsFor
|
|||||||
{
|
{
|
||||||
if(stack->canCast()) //TODO: check for battlefield effects that prevent casting?
|
if(stack->canCast()) //TODO: check for battlefield effects that prevent casting?
|
||||||
{
|
{
|
||||||
if(stack->hasBonusOfType(Bonus::SPELLCASTER))
|
if(stack->hasBonusOfType(BonusType::SPELLCASTER))
|
||||||
{
|
{
|
||||||
for(const auto & spellID : data.creatureSpellsToCast)
|
for(const auto & spellID : data.creatureSpellsToCast)
|
||||||
{
|
{
|
||||||
@ -236,12 +236,12 @@ std::vector<PossiblePlayerBattleAction> CBattleInfoCallback::getClientActionsFor
|
|||||||
allowedActionList.push_back(act);
|
allowedActionList.push_back(act);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(stack->hasBonusOfType(Bonus::RANDOM_SPELLCASTER))
|
if(stack->hasBonusOfType(BonusType::RANDOM_SPELLCASTER))
|
||||||
allowedActionList.push_back(PossiblePlayerBattleAction::RANDOM_GENIE_SPELL);
|
allowedActionList.push_back(PossiblePlayerBattleAction::RANDOM_GENIE_SPELL);
|
||||||
}
|
}
|
||||||
if(stack->canShoot())
|
if(stack->canShoot())
|
||||||
allowedActionList.push_back(PossiblePlayerBattleAction::SHOOT);
|
allowedActionList.push_back(PossiblePlayerBattleAction::SHOOT);
|
||||||
if(stack->hasBonusOfType(Bonus::RETURN_AFTER_STRIKE))
|
if(stack->hasBonusOfType(BonusType::RETURN_AFTER_STRIKE))
|
||||||
allowedActionList.push_back(PossiblePlayerBattleAction::ATTACK_AND_RETURN);
|
allowedActionList.push_back(PossiblePlayerBattleAction::ATTACK_AND_RETURN);
|
||||||
|
|
||||||
allowedActionList.push_back(PossiblePlayerBattleAction::ATTACK); //all active stacks can attack
|
allowedActionList.push_back(PossiblePlayerBattleAction::ATTACK); //all active stacks can attack
|
||||||
@ -251,9 +251,9 @@ std::vector<PossiblePlayerBattleAction> CBattleInfoCallback::getClientActionsFor
|
|||||||
allowedActionList.push_back(PossiblePlayerBattleAction::MOVE_STACK);
|
allowedActionList.push_back(PossiblePlayerBattleAction::MOVE_STACK);
|
||||||
|
|
||||||
const auto * siegedTown = battleGetDefendedTown();
|
const auto * siegedTown = battleGetDefendedTown();
|
||||||
if(siegedTown && siegedTown->hasFort() && stack->hasBonusOfType(Bonus::CATAPULT)) //TODO: check shots
|
if(siegedTown && siegedTown->hasFort() && stack->hasBonusOfType(BonusType::CATAPULT)) //TODO: check shots
|
||||||
allowedActionList.push_back(PossiblePlayerBattleAction::CATAPULT);
|
allowedActionList.push_back(PossiblePlayerBattleAction::CATAPULT);
|
||||||
if(stack->hasBonusOfType(Bonus::HEALER))
|
if(stack->hasBonusOfType(BonusType::HEALER))
|
||||||
allowedActionList.push_back(PossiblePlayerBattleAction::HEAL);
|
allowedActionList.push_back(PossiblePlayerBattleAction::HEAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,10 +686,10 @@ bool CBattleInfoCallback::battleCanShoot(const battle::Unit * attacker) const
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
//forgetfulness
|
//forgetfulness
|
||||||
TConstBonusListPtr forgetfulList = attacker->getBonuses(Selector::type()(Bonus::FORGETFULL));
|
TConstBonusListPtr forgetfulList = attacker->getBonuses(Selector::type()(BonusType::FORGETFULL));
|
||||||
if(!forgetfulList->empty())
|
if(!forgetfulList->empty())
|
||||||
{
|
{
|
||||||
int forgetful = forgetfulList->valOfBonuses(Selector::type()(Bonus::FORGETFULL));
|
int forgetful = forgetfulList->valOfBonuses(Selector::type()(BonusType::FORGETFULL));
|
||||||
|
|
||||||
//advanced+ level
|
//advanced+ level
|
||||||
if(forgetful > 1)
|
if(forgetful > 1)
|
||||||
@ -697,7 +697,7 @@ bool CBattleInfoCallback::battleCanShoot(const battle::Unit * attacker) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
return attacker->canShoot() && (!battleIsUnitBlocked(attacker)
|
return attacker->canShoot() && (!battleIsUnitBlocked(attacker)
|
||||||
|| attacker->hasBonusOfType(Bonus::FREE_SHOOTING));
|
|| attacker->hasBonusOfType(BonusType::FREE_SHOOTING));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBattleInfoCallback::battleCanShoot(const battle::Unit * attacker, BattleHex dest) const
|
bool CBattleInfoCallback::battleCanShoot(const battle::Unit * attacker, BattleHex dest) const
|
||||||
@ -712,7 +712,7 @@ bool CBattleInfoCallback::battleCanShoot(const battle::Unit * attacker, BattleHe
|
|||||||
{
|
{
|
||||||
if(battleCanShoot(attacker))
|
if(battleCanShoot(attacker))
|
||||||
{
|
{
|
||||||
auto limitedRangeBonus = attacker->getBonus(Selector::type()(Bonus::LIMITED_SHOOTING_RANGE));
|
auto limitedRangeBonus = attacker->getBonus(Selector::type()(BonusType::LIMITED_SHOOTING_RANGE));
|
||||||
if(limitedRangeBonus == nullptr)
|
if(limitedRangeBonus == nullptr)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -1239,11 +1239,11 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(const battle:
|
|||||||
{
|
{
|
||||||
attackOriginHex = attacker->occupiedHex(attackOriginHex); //the other hex stack stands on
|
attackOriginHex = attacker->occupiedHex(attackOriginHex); //the other hex stack stands on
|
||||||
}
|
}
|
||||||
if(attacker->hasBonusOfType(Bonus::ATTACKS_ALL_ADJACENT))
|
if(attacker->hasBonusOfType(BonusType::ATTACKS_ALL_ADJACENT))
|
||||||
{
|
{
|
||||||
boost::copy(attacker->getSurroundingHexes(attackerPos), vstd::set_inserter(at.hostileCreaturePositions));
|
boost::copy(attacker->getSurroundingHexes(attackerPos), vstd::set_inserter(at.hostileCreaturePositions));
|
||||||
}
|
}
|
||||||
if(attacker->hasBonusOfType(Bonus::THREE_HEADED_ATTACK))
|
if(attacker->hasBonusOfType(BonusType::THREE_HEADED_ATTACK))
|
||||||
{
|
{
|
||||||
std::vector<BattleHex> hexes = attacker->getSurroundingHexes(attackerPos);
|
std::vector<BattleHex> hexes = attacker->getSurroundingHexes(attackerPos);
|
||||||
for(BattleHex tile : hexes)
|
for(BattleHex tile : hexes)
|
||||||
@ -1256,7 +1256,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(const battle:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(attacker->hasBonusOfType(Bonus::WIDE_BREATH))
|
if(attacker->hasBonusOfType(BonusType::WIDE_BREATH))
|
||||||
{
|
{
|
||||||
std::vector<BattleHex> hexes = destinationTile.neighbouringTiles();
|
std::vector<BattleHex> hexes = destinationTile.neighbouringTiles();
|
||||||
for(int i = 0; i<hexes.size(); i++)
|
for(int i = 0; i<hexes.size(); i++)
|
||||||
@ -1275,7 +1275,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(const battle:
|
|||||||
at.friendlyCreaturePositions.insert(tile);
|
at.friendlyCreaturePositions.insert(tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(attacker->hasBonusOfType(Bonus::TWO_HEX_ATTACK_BREATH))
|
else if(attacker->hasBonusOfType(BonusType::TWO_HEX_ATTACK_BREATH))
|
||||||
{
|
{
|
||||||
auto direction = BattleHex::mutualPosition(attackOriginHex, destinationTile);
|
auto direction = BattleHex::mutualPosition(attackOriginHex, destinationTile);
|
||||||
if(direction != BattleHex::NONE) //only adjacent hexes are subject of dragon breath calculation
|
if(direction != BattleHex::NONE) //only adjacent hexes are subject of dragon breath calculation
|
||||||
@ -1312,7 +1312,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyShootableHexes(const battle::
|
|||||||
AttackableTiles at;
|
AttackableTiles at;
|
||||||
RETURN_IF_NOT_BATTLE(at);
|
RETURN_IF_NOT_BATTLE(at);
|
||||||
|
|
||||||
if(attacker->hasBonusOfType(Bonus::SHOOTS_ALL_ADJACENT) && !vstd::contains(attackerPos.neighbouringTiles(), destinationTile))
|
if(attacker->hasBonusOfType(BonusType::SHOOTS_ALL_ADJACENT) && !vstd::contains(attackerPos.neighbouringTiles(), destinationTile))
|
||||||
{
|
{
|
||||||
std::vector<BattleHex> targetHexes = destinationTile.neighbouringTiles();
|
std::vector<BattleHex> targetHexes = destinationTile.neighbouringTiles();
|
||||||
targetHexes.push_back(destinationTile);
|
targetHexes.push_back(destinationTile);
|
||||||
@ -1448,7 +1448,7 @@ bool CBattleInfoCallback::battleHasDistancePenalty(const IBonusBearer * shooter,
|
|||||||
RETURN_IF_NOT_BATTLE(false);
|
RETURN_IF_NOT_BATTLE(false);
|
||||||
|
|
||||||
const std::string cachingStrNoDistancePenalty = "type_NO_DISTANCE_PENALTY";
|
const std::string cachingStrNoDistancePenalty = "type_NO_DISTANCE_PENALTY";
|
||||||
static const auto selectorNoDistancePenalty = Selector::type()(Bonus::NO_DISTANCE_PENALTY);
|
static const auto selectorNoDistancePenalty = Selector::type()(BonusType::NO_DISTANCE_PENALTY);
|
||||||
|
|
||||||
if(shooter->hasBonus(selectorNoDistancePenalty, cachingStrNoDistancePenalty))
|
if(shooter->hasBonus(selectorNoDistancePenalty, cachingStrNoDistancePenalty))
|
||||||
return false;
|
return false;
|
||||||
@ -1458,7 +1458,7 @@ bool CBattleInfoCallback::battleHasDistancePenalty(const IBonusBearer * shooter,
|
|||||||
//If any hex of target creature is within range, there is no penalty
|
//If any hex of target creature is within range, there is no penalty
|
||||||
int range = GameConstants::BATTLE_PENALTY_DISTANCE;
|
int range = GameConstants::BATTLE_PENALTY_DISTANCE;
|
||||||
|
|
||||||
auto bonus = shooter->getBonus(Selector::type()(Bonus::LIMITED_SHOOTING_RANGE));
|
auto bonus = shooter->getBonus(Selector::type()(BonusType::LIMITED_SHOOTING_RANGE));
|
||||||
if(bonus != nullptr && bonus->additionalInfo != CAddInfo::NONE)
|
if(bonus != nullptr && bonus->additionalInfo != CAddInfo::NONE)
|
||||||
range = bonus->additionalInfo[0];
|
range = bonus->additionalInfo[0];
|
||||||
|
|
||||||
@ -1542,13 +1542,13 @@ int32_t CBattleInfoCallback::battleGetSpellCost(const spells::Spell * sp, const
|
|||||||
|
|
||||||
for(const auto * unit : battleAliveUnits())
|
for(const auto * unit : battleAliveUnits())
|
||||||
{
|
{
|
||||||
if(unit->unitOwner() == caster->tempOwner && unit->hasBonusOfType(Bonus::CHANGES_SPELL_COST_FOR_ALLY))
|
if(unit->unitOwner() == caster->tempOwner && unit->hasBonusOfType(BonusType::CHANGES_SPELL_COST_FOR_ALLY))
|
||||||
{
|
{
|
||||||
vstd::amax(manaReduction, unit->valOfBonuses(Bonus::CHANGES_SPELL_COST_FOR_ALLY));
|
vstd::amax(manaReduction, unit->valOfBonuses(BonusType::CHANGES_SPELL_COST_FOR_ALLY));
|
||||||
}
|
}
|
||||||
if(unit->unitOwner() != caster->tempOwner && unit->hasBonusOfType(Bonus::CHANGES_SPELL_COST_FOR_ENEMY))
|
if(unit->unitOwner() != caster->tempOwner && unit->hasBonusOfType(BonusType::CHANGES_SPELL_COST_FOR_ENEMY))
|
||||||
{
|
{
|
||||||
vstd::amax(manaIncrease, unit->valOfBonuses(Bonus::CHANGES_SPELL_COST_FOR_ENEMY));
|
vstd::amax(manaIncrease, unit->valOfBonuses(BonusType::CHANGES_SPELL_COST_FOR_ENEMY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1564,7 +1564,7 @@ bool CBattleInfoCallback::battleIsUnitBlocked(const battle::Unit * unit) const
|
|||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(false);
|
RETURN_IF_NOT_BATTLE(false);
|
||||||
|
|
||||||
if(unit->hasBonusOfType(Bonus::SIEGE_WEAPON)) //siege weapons cannot be blocked
|
if(unit->hasBonusOfType(BonusType::SIEGE_WEAPON)) //siege weapons cannot be blocked
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for(const auto * adjacent : battleAdjacentUnits(unit))
|
for(const auto * adjacent : battleAdjacentUnits(unit))
|
||||||
@ -1635,9 +1635,9 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(CRandomGenerator & rand, c
|
|||||||
for(const SpellID& spellID : allPossibleSpells)
|
for(const SpellID& spellID : allPossibleSpells)
|
||||||
{
|
{
|
||||||
std::stringstream cachingStr;
|
std::stringstream cachingStr;
|
||||||
cachingStr << "source_" << Bonus::SPELL_EFFECT << "id_" << spellID.num;
|
cachingStr << "source_" << vstd::to_underlying(BonusSource::SPELL_EFFECT) << "id_" << spellID.num;
|
||||||
|
|
||||||
if(subject->hasBonus(Selector::source(Bonus::SPELL_EFFECT, spellID), Selector::all, cachingStr.str())
|
if(subject->hasBonus(Selector::source(BonusSource::SPELL_EFFECT, spellID), Selector::all, cachingStr.str())
|
||||||
//TODO: this ability has special limitations
|
//TODO: this ability has special limitations
|
||||||
|| !(spellID.toSpell()->canBeCast(this, spells::Mode::CREATURE_ACTIVE, subject)))
|
|| !(spellID.toSpell()->canBeCast(this, spells::Mode::CREATURE_ACTIVE, subject)))
|
||||||
continue;
|
continue;
|
||||||
@ -1702,7 +1702,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(CRandomGenerator & rand, c
|
|||||||
{
|
{
|
||||||
const auto * kingMonster = getAliveEnemy([&](const CStack * stack) -> bool //look for enemy, non-shooting stack
|
const auto * kingMonster = getAliveEnemy([&](const CStack * stack) -> bool //look for enemy, non-shooting stack
|
||||||
{
|
{
|
||||||
const auto isKing = Selector::type()(Bonus::KING);
|
const auto isKing = Selector::type()(BonusType::KING);
|
||||||
|
|
||||||
return stack->hasBonus(isKing);
|
return stack->hasBonus(isKing);
|
||||||
});
|
});
|
||||||
@ -1729,7 +1729,7 @@ SpellID CBattleInfoCallback::getRandomCastedSpell(CRandomGenerator & rand,const
|
|||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(SpellID::NONE);
|
RETURN_IF_NOT_BATTLE(SpellID::NONE);
|
||||||
|
|
||||||
TConstBonusListPtr bl = caster->getBonuses(Selector::type()(Bonus::SPELLCASTER));
|
TConstBonusListPtr bl = caster->getBonuses(Selector::type()(BonusType::SPELLCASTER));
|
||||||
if (!bl->size())
|
if (!bl->size())
|
||||||
return SpellID::NONE;
|
return SpellID::NONE;
|
||||||
int totalWeight = 0;
|
int totalWeight = 0;
|
||||||
@ -1772,7 +1772,7 @@ int CBattleInfoCallback::battleGetSurrenderCost(const PlayerColor & Player) cons
|
|||||||
ret += unit->getRawSurrenderCost();
|
ret += unit->getRawSurrenderCost();
|
||||||
|
|
||||||
if(const CGHeroInstance * h = battleGetFightingHero(side))
|
if(const CGHeroInstance * h = battleGetFightingHero(side))
|
||||||
discount += h->valOfBonuses(Bonus::SURRENDER_DISCOUNT);
|
discount += h->valOfBonuses(BonusType::SURRENDER_DISCOUNT);
|
||||||
|
|
||||||
ret = static_cast<int>(ret * (100.0 - discount) / 100.0);
|
ret = static_cast<int>(ret * (100.0 - discount) / 100.0);
|
||||||
vstd::amax(ret, 0); //no negative costs for >100% discounts (impossible in original H3 mechanics, but some day...)
|
vstd::amax(ret, 0); //no negative costs for >100% discounts (impossible in original H3 mechanics, but some day...)
|
||||||
@ -1790,7 +1790,7 @@ si8 CBattleInfoCallback::battleMinSpellLevel(ui8 side) const
|
|||||||
if(!node)
|
if(!node)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
auto b = node->getBonuses(Selector::type()(Bonus::BLOCK_MAGIC_BELOW));
|
auto b = node->getBonuses(Selector::type()(BonusType::BLOCK_MAGIC_BELOW));
|
||||||
if(b->size())
|
if(b->size())
|
||||||
return b->totalValue();
|
return b->totalValue();
|
||||||
|
|
||||||
@ -1809,7 +1809,7 @@ si8 CBattleInfoCallback::battleMaxSpellLevel(ui8 side) const
|
|||||||
return GameConstants::SPELL_LEVELS;
|
return GameConstants::SPELL_LEVELS;
|
||||||
|
|
||||||
//We can't "just get value" - it'd be 0 if there are bonuses (and all would be blocked)
|
//We can't "just get value" - it'd be 0 if there are bonuses (and all would be blocked)
|
||||||
auto b = node->getBonuses(Selector::type()(Bonus::BLOCK_MAGIC_ABOVE));
|
auto b = node->getBonuses(Selector::type()(BonusType::BLOCK_MAGIC_ABOVE));
|
||||||
if(b->size())
|
if(b->size())
|
||||||
return b->totalValue();
|
return b->totalValue();
|
||||||
|
|
||||||
@ -1820,7 +1820,7 @@ std::optional<int> CBattleInfoCallback::battleIsFinished() const
|
|||||||
{
|
{
|
||||||
auto units = battleGetUnitsIf([=](const battle::Unit * unit)
|
auto units = battleGetUnitsIf([=](const battle::Unit * unit)
|
||||||
{
|
{
|
||||||
return unit->alive() && !unit->isTurret() && !unit->hasBonusOfType(Bonus::SIEGE_WEAPON);
|
return unit->alive() && !unit->isTurret() && !unit->hasBonusOfType(BonusType::SIEGE_WEAPON);
|
||||||
});
|
});
|
||||||
|
|
||||||
std::array<bool, 2> hasUnit = {false, false}; //index is BattleSide
|
std::array<bool, 2> hasUnit = {false, false}; //index is BattleSide
|
||||||
|
@ -271,7 +271,7 @@ bool CBattleInfoEssentials::battleCanFlee(const PlayerColor & player) const
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
//eg. one of heroes is wearing shakles of war
|
//eg. one of heroes is wearing shakles of war
|
||||||
if(myHero->hasBonusOfType(Bonus::BATTLE_NO_FLEEING))
|
if(myHero->hasBonusOfType(BonusType::BATTLE_NO_FLEEING))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//we are besieged defender
|
//we are besieged defender
|
||||||
@ -394,7 +394,7 @@ PlayerColor CBattleInfoEssentials::battleGetOwner(const battle::Unit * unit) con
|
|||||||
|
|
||||||
PlayerColor initialOwner = getBattle()->getSidePlayer(unit->unitSide());
|
PlayerColor initialOwner = getBattle()->getSidePlayer(unit->unitSide());
|
||||||
|
|
||||||
static CSelector selector = Selector::type()(Bonus::HYPNOTIZED);
|
static CSelector selector = Selector::type()(BonusType::HYPNOTIZED);
|
||||||
static std::string cachingString = "type_103s-1";
|
static std::string cachingString = "type_103s-1";
|
||||||
|
|
||||||
if(unit->hasBonus(selector, cachingString))
|
if(unit->hasBonus(selector, cachingString))
|
||||||
|
@ -85,8 +85,8 @@ void CAmmo::serializeJson(JsonSerializeFormat & handler)
|
|||||||
|
|
||||||
///CShots
|
///CShots
|
||||||
CShots::CShots(const battle::Unit * Owner)
|
CShots::CShots(const battle::Unit * Owner)
|
||||||
: CAmmo(Owner, Selector::type()(Bonus::SHOTS)),
|
: CAmmo(Owner, Selector::type()(BonusType::SHOTS)),
|
||||||
shooter(Owner, Selector::type()(Bonus::SHOOTER))
|
shooter(Owner, Selector::type()(BonusType::SHOOTER))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,16 +117,16 @@ int32_t CShots::total() const
|
|||||||
|
|
||||||
///CCasts
|
///CCasts
|
||||||
CCasts::CCasts(const battle::Unit * Owner):
|
CCasts::CCasts(const battle::Unit * Owner):
|
||||||
CAmmo(Owner, Selector::type()(Bonus::CASTS))
|
CAmmo(Owner, Selector::type()(BonusType::CASTS))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
///CRetaliations
|
///CRetaliations
|
||||||
CRetaliations::CRetaliations(const battle::Unit * Owner)
|
CRetaliations::CRetaliations(const battle::Unit * Owner)
|
||||||
: CAmmo(Owner, Selector::type()(Bonus::ADDITIONAL_RETALIATION)),
|
: CAmmo(Owner, Selector::type()(BonusType::ADDITIONAL_RETALIATION)),
|
||||||
totalCache(0),
|
totalCache(0),
|
||||||
noRetaliation(Owner, Selector::type()(Bonus::SIEGE_WEAPON).Or(Selector::type()(Bonus::HYPNOTIZED)).Or(Selector::type()(Bonus::NO_RETALIATION))),
|
noRetaliation(Owner, Selector::type()(BonusType::SIEGE_WEAPON).Or(Selector::type()(BonusType::HYPNOTIZED)).Or(Selector::type()(BonusType::NO_RETALIATION))),
|
||||||
unlimited(Owner, Selector::type()(Bonus::UNLIMITED_RETALIATIONS))
|
unlimited(Owner, Selector::type()(BonusType::UNLIMITED_RETALIATIONS))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,13 +339,13 @@ CUnitState::CUnitState():
|
|||||||
counterAttacks(this),
|
counterAttacks(this),
|
||||||
health(this),
|
health(this),
|
||||||
shots(this),
|
shots(this),
|
||||||
totalAttacks(this, Selector::type()(Bonus::ADDITIONAL_ATTACK), 1),
|
totalAttacks(this, Selector::type()(BonusType::ADDITIONAL_ATTACK), 1),
|
||||||
minDamage(this, Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 1)), 0),
|
minDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 1)), 0),
|
||||||
maxDamage(this, Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 2)), 0),
|
maxDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, 2)), 0),
|
||||||
attack(this, Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), 0),
|
attack(this, Selector::typeSubtype(BonusType::PRIMARY_SKILL, PrimarySkill::ATTACK), 0),
|
||||||
defence(this, Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), 0),
|
defence(this, Selector::typeSubtype(BonusType::PRIMARY_SKILL, PrimarySkill::DEFENSE), 0),
|
||||||
inFrenzy(this, Selector::type()(Bonus::IN_FRENZY)),
|
inFrenzy(this, Selector::type()(BonusType::IN_FRENZY)),
|
||||||
cloneLifetimeMarker(this, Selector::type()(Bonus::NONE).And(Selector::source(Bonus::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(Bonus::SPELLCASTER, spell->getIndex()));
|
int32_t skill = valOfBonuses(Selector::typeSubtype(BonusType::SPELLCASTER, spell->getIndex()));
|
||||||
vstd::abetween(skill, 0, 3);
|
vstd::abetween(skill, 0, 3);
|
||||||
return skill;
|
return skill;
|
||||||
}
|
}
|
||||||
@ -453,12 +453,12 @@ int32_t CUnitState::getEffectLevel(const spells::Spell * spell) const
|
|||||||
|
|
||||||
int32_t CUnitState::getEffectPower(const spells::Spell * spell) const
|
int32_t CUnitState::getEffectPower(const spells::Spell * spell) const
|
||||||
{
|
{
|
||||||
return valOfBonuses(Bonus::CREATURE_SPELL_POWER) * getCount() / 100;
|
return valOfBonuses(BonusType::CREATURE_SPELL_POWER) * getCount() / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CUnitState::getEnchantPower(const spells::Spell * spell) const
|
int32_t CUnitState::getEnchantPower(const spells::Spell * spell) const
|
||||||
{
|
{
|
||||||
int32_t res = valOfBonuses(Bonus::CREATURE_ENCHANT_POWER);
|
int32_t res = valOfBonuses(BonusType::CREATURE_ENCHANT_POWER);
|
||||||
if(res <= 0)
|
if(res <= 0)
|
||||||
res = 3;//default for creatures
|
res = 3;//default for creatures
|
||||||
return res;
|
return res;
|
||||||
@ -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(Bonus::SPECIFIC_SPELL_POWER, spell->getIndex());
|
return static_cast<int64_t>(getCount()) * valOfBonuses(BonusType::SPECIFIC_SPELL_POWER, spell->getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerColor CUnitState::getCasterOwner() const
|
PlayerColor CUnitState::getCasterOwner() const
|
||||||
@ -511,7 +511,7 @@ bool CUnitState::isGhost() const
|
|||||||
|
|
||||||
bool CUnitState::isFrozen() const
|
bool CUnitState::isFrozen() const
|
||||||
{
|
{
|
||||||
return hasBonus(Selector::source(Bonus::SPELL_EFFECT, SpellID::STONE_GAZE), Selector::all);
|
return hasBonus(Selector::source(BonusSource::SPELL_EFFECT, SpellID::STONE_GAZE), Selector::all);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CUnitState::isValidTarget(bool allowDead) const
|
bool CUnitState::isValidTarget(bool allowDead) const
|
||||||
@ -588,12 +588,12 @@ void CUnitState::setPosition(BattleHex hex)
|
|||||||
|
|
||||||
int32_t CUnitState::getInitiative(int turn) const
|
int32_t CUnitState::getInitiative(int turn) const
|
||||||
{
|
{
|
||||||
return valOfBonuses(Selector::type()(Bonus::STACKS_SPEED).And(Selector::turns(turn)));
|
return valOfBonuses(Selector::type()(BonusType::STACKS_SPEED).And(Selector::turns(turn)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CUnitState::canMove(int turn) const
|
bool CUnitState::canMove(int turn) const
|
||||||
{
|
{
|
||||||
return alive() && !hasBonus(Selector::type()(Bonus::NOT_ACTIVE).And(Selector::turns(turn))); //eg. Ammo Cart or blinded creature
|
return alive() && !hasBonus(Selector::type()(BonusType::NOT_ACTIVE).And(Selector::turns(turn))); //eg. Ammo Cart or blinded creature
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CUnitState::defended(int turn) const
|
bool CUnitState::defended(int turn) const
|
||||||
|
@ -46,13 +46,13 @@ DamageRange DamageCalculator::getBaseDamageSingle() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::string cachingStrSiedgeWeapon = "type_SIEGE_WEAPON";
|
const std::string cachingStrSiedgeWeapon = "type_SIEGE_WEAPON";
|
||||||
static const auto selectorSiedgeWeapon = Selector::type()(Bonus::SIEGE_WEAPON);
|
static const auto selectorSiedgeWeapon = Selector::type()(BonusType::SIEGE_WEAPON);
|
||||||
|
|
||||||
if(info.attacker->hasBonus(selectorSiedgeWeapon, cachingStrSiedgeWeapon) && info.attacker->creatureIndex() != CreatureID::ARROW_TOWERS)
|
if(info.attacker->hasBonus(selectorSiedgeWeapon, cachingStrSiedgeWeapon) && info.attacker->creatureIndex() != CreatureID::ARROW_TOWERS)
|
||||||
{
|
{
|
||||||
auto retrieveHeroPrimSkill = [&](int skill) -> int
|
auto retrieveHeroPrimSkill = [&](int skill) -> int
|
||||||
{
|
{
|
||||||
std::shared_ptr<const Bonus> b = info.attacker->getBonus(Selector::sourceTypeSel(Bonus::HERO_BASE_SKILL).And(Selector::typeSubtype(Bonus::PRIMARY_SKILL, skill)));
|
std::shared_ptr<const Bonus> b = info.attacker->getBonus(Selector::sourceTypeSel(BonusSource::HERO_BASE_SKILL).And(Selector::typeSubtype(BonusType::PRIMARY_SKILL, skill)));
|
||||||
return b ? b->val : 0;
|
return b ? b->val : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,10 +66,10 @@ DamageRange DamageCalculator::getBaseDamageSingle() const
|
|||||||
DamageRange DamageCalculator::getBaseDamageBlessCurse() const
|
DamageRange DamageCalculator::getBaseDamageBlessCurse() const
|
||||||
{
|
{
|
||||||
const std::string cachingStrForcedMinDamage = "type_ALWAYS_MINIMUM_DAMAGE";
|
const std::string cachingStrForcedMinDamage = "type_ALWAYS_MINIMUM_DAMAGE";
|
||||||
static const auto selectorForcedMinDamage = Selector::type()(Bonus::ALWAYS_MINIMUM_DAMAGE);
|
static const auto selectorForcedMinDamage = Selector::type()(BonusType::ALWAYS_MINIMUM_DAMAGE);
|
||||||
|
|
||||||
const std::string cachingStrForcedMaxDamage = "type_ALWAYS_MAXIMUM_DAMAGE";
|
const std::string cachingStrForcedMaxDamage = "type_ALWAYS_MAXIMUM_DAMAGE";
|
||||||
static const auto selectorForcedMaxDamage = Selector::type()(Bonus::ALWAYS_MAXIMUM_DAMAGE);
|
static const auto selectorForcedMaxDamage = Selector::type()(BonusType::ALWAYS_MAXIMUM_DAMAGE);
|
||||||
|
|
||||||
TConstBonusListPtr curseEffects = info.attacker->getBonuses(selectorForcedMinDamage, cachingStrForcedMinDamage);
|
TConstBonusListPtr curseEffects = info.attacker->getBonuses(selectorForcedMinDamage, cachingStrForcedMinDamage);
|
||||||
TConstBonusListPtr blessEffects = info.attacker->getBonuses(selectorForcedMaxDamage, cachingStrForcedMaxDamage);
|
TConstBonusListPtr blessEffects = info.attacker->getBonuses(selectorForcedMaxDamage, cachingStrForcedMaxDamage);
|
||||||
@ -130,10 +130,10 @@ int DamageCalculator::getActorAttackEffective() const
|
|||||||
int DamageCalculator::getActorAttackSlayer() const
|
int DamageCalculator::getActorAttackSlayer() const
|
||||||
{
|
{
|
||||||
const std::string cachingStrSlayer = "type_SLAYER";
|
const std::string cachingStrSlayer = "type_SLAYER";
|
||||||
static const auto selectorSlayer = Selector::type()(Bonus::SLAYER);
|
static const auto selectorSlayer = Selector::type()(BonusType::SLAYER);
|
||||||
|
|
||||||
auto slayerEffects = info.attacker->getBonuses(selectorSlayer, cachingStrSlayer);
|
auto slayerEffects = info.attacker->getBonuses(selectorSlayer, cachingStrSlayer);
|
||||||
auto slayerAffected = info.defender->unitType()->valOfBonuses(Selector::type()(Bonus::KING));
|
auto slayerAffected = info.defender->unitType()->valOfBonuses(Selector::type()(BonusType::KING));
|
||||||
|
|
||||||
if(std::shared_ptr<const Bonus> slayerEffect = slayerEffects->getFirst(Selector::all))
|
if(std::shared_ptr<const Bonus> slayerEffect = slayerEffects->getFirst(Selector::all))
|
||||||
{
|
{
|
||||||
@ -143,7 +143,7 @@ int DamageCalculator::getActorAttackSlayer() const
|
|||||||
if(isAffected)
|
if(isAffected)
|
||||||
{
|
{
|
||||||
int attackBonus = SpellID(SpellID::SLAYER).toSpell()->getLevelPower(spLevel);
|
int attackBonus = SpellID(SpellID::SLAYER).toSpell()->getLevelPower(spLevel);
|
||||||
if(info.attacker->hasBonusOfType(Bonus::SPECIAL_PECULIAR_ENCHANT, SpellID::SLAYER))
|
if(info.attacker->hasBonusOfType(BonusType::SPECIAL_PECULIAR_ENCHANT, SpellID::SLAYER))
|
||||||
{
|
{
|
||||||
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);
|
||||||
@ -167,7 +167,7 @@ int DamageCalculator::getTargetDefenseEffective() const
|
|||||||
|
|
||||||
int DamageCalculator::getTargetDefenseIgnored() const
|
int DamageCalculator::getTargetDefenseIgnored() const
|
||||||
{
|
{
|
||||||
double multDefenceReduction = battleBonusValue(info.attacker, Selector::type()(Bonus::ENEMY_DEFENCE_REDUCTION)) / 100.0;
|
double multDefenceReduction = battleBonusValue(info.attacker, Selector::type()(BonusType::ENEMY_DEFENCE_REDUCTION)) / 100.0;
|
||||||
|
|
||||||
if(multDefenceReduction > 0)
|
if(multDefenceReduction > 0)
|
||||||
{
|
{
|
||||||
@ -195,7 +195,7 @@ double DamageCalculator::getAttackSkillFactor() const
|
|||||||
double DamageCalculator::getAttackBlessFactor() const
|
double DamageCalculator::getAttackBlessFactor() const
|
||||||
{
|
{
|
||||||
const std::string cachingStrDamage = "type_GENERAL_DAMAGE_PREMY";
|
const std::string cachingStrDamage = "type_GENERAL_DAMAGE_PREMY";
|
||||||
static const auto selectorDamage = Selector::type()(Bonus::GENERAL_DAMAGE_PREMY);
|
static const auto selectorDamage = Selector::type()(BonusType::GENERAL_DAMAGE_PREMY);
|
||||||
return info.attacker->valOfBonuses(selectorDamage, cachingStrDamage) / 100.0;
|
return info.attacker->valOfBonuses(selectorDamage, cachingStrDamage) / 100.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,11 +205,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(Bonus::PERCENTAGE_DAMAGE_BOOST, 1);
|
static const auto selectorArchery = Selector::typeSubtype(BonusType::PERCENTAGE_DAMAGE_BOOST, 1);
|
||||||
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(Bonus::PERCENTAGE_DAMAGE_BOOST, 0);
|
static const auto selectorOffence = Selector::typeSubtype(BonusType::PERCENTAGE_DAMAGE_BOOST, 0);
|
||||||
return info.attacker->valOfBonuses(selectorOffence, cachingStrOffence) / 100.0;
|
return info.attacker->valOfBonuses(selectorOffence, cachingStrOffence) / 100.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +231,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(Bonus::BONUS_DAMAGE_PERCENTAGE, info.attacker->creatureIndex());
|
const auto selector = Selector::typeSubtype(BonusType::BONUS_DAMAGE_PERCENTAGE, info.attacker->creatureIndex());
|
||||||
return info.attacker->valOfBonuses(selector, cachingStr) / 100.0;
|
return info.attacker->valOfBonuses(selector, cachingStr) / 100.0;
|
||||||
}
|
}
|
||||||
return 0.0;
|
return 0.0;
|
||||||
@ -240,10 +240,10 @@ double DamageCalculator::getAttackDoubleDamageFactor() const
|
|||||||
double DamageCalculator::getAttackJoustingFactor() const
|
double DamageCalculator::getAttackJoustingFactor() const
|
||||||
{
|
{
|
||||||
const std::string cachingStrJousting = "type_JOUSTING";
|
const std::string cachingStrJousting = "type_JOUSTING";
|
||||||
static const auto selectorJousting = Selector::type()(Bonus::JOUSTING);
|
static const auto selectorJousting = Selector::type()(BonusType::JOUSTING);
|
||||||
|
|
||||||
const std::string cachingStrChargeImmunity = "type_CHARGE_IMMUNITY";
|
const std::string cachingStrChargeImmunity = "type_CHARGE_IMMUNITY";
|
||||||
static const auto selectorChargeImmunity = Selector::type()(Bonus::CHARGE_IMMUNITY);
|
static const auto selectorChargeImmunity = Selector::type()(BonusType::CHARGE_IMMUNITY);
|
||||||
|
|
||||||
//applying jousting bonus
|
//applying jousting bonus
|
||||||
if(info.chargeDistance > 0 && info.attacker->hasBonus(selectorJousting, cachingStrJousting) && !info.defender->hasBonus(selectorChargeImmunity, cachingStrChargeImmunity))
|
if(info.chargeDistance > 0 && info.attacker->hasBonus(selectorJousting, cachingStrJousting) && !info.defender->hasBonus(selectorChargeImmunity, cachingStrChargeImmunity))
|
||||||
@ -255,7 +255,7 @@ double DamageCalculator::getAttackHateFactor() const
|
|||||||
{
|
{
|
||||||
//assume that unit have only few HATE features and cache them all
|
//assume that unit have only few HATE features and cache them all
|
||||||
const std::string cachingStrHate = "type_HATE";
|
const std::string cachingStrHate = "type_HATE";
|
||||||
static const auto selectorHate = Selector::type()(Bonus::HATE);
|
static const auto selectorHate = Selector::type()(BonusType::HATE);
|
||||||
|
|
||||||
auto allHateEffects = info.attacker->getBonuses(selectorHate, cachingStrHate);
|
auto allHateEffects = info.attacker->getBonuses(selectorHate, cachingStrHate);
|
||||||
|
|
||||||
@ -281,7 +281,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(Bonus::GENERAL_DAMAGE_REDUCTION, -1).And(Selector::sourceTypeSel(Bonus::SPELL_EFFECT).Not());
|
static const auto selectorArmorer = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, -1).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 +289,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(Bonus::GENERAL_DAMAGE_REDUCTION, 0);
|
static const auto selectorMeleeReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, 0);
|
||||||
|
|
||||||
const std::string cachingStrRangedReduction = "type_GENERAL_DAMAGE_REDUCTIONs_1";
|
const std::string cachingStrRangedReduction = "type_GENERAL_DAMAGE_REDUCTIONs_1";
|
||||||
static const auto selectorRangedReduction = Selector::typeSubtype(Bonus::GENERAL_DAMAGE_REDUCTION, 1);
|
static const auto selectorRangedReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, 1);
|
||||||
|
|
||||||
//handling spell effects - shield and air shield
|
//handling spell effects - shield and air shield
|
||||||
if(info.shooting)
|
if(info.shooting)
|
||||||
@ -311,7 +311,7 @@ double DamageCalculator::getDefenseRangePenaltiesFactor() const
|
|||||||
const std::string cachingStrAdvAirShield = "isAdvancedAirShield";
|
const std::string cachingStrAdvAirShield = "isAdvancedAirShield";
|
||||||
auto isAdvancedAirShield = [](const Bonus* bonus)
|
auto isAdvancedAirShield = [](const Bonus* bonus)
|
||||||
{
|
{
|
||||||
return bonus->source == Bonus::SPELL_EFFECT
|
return bonus->source == BonusSource::SPELL_EFFECT
|
||||||
&& bonus->sid == SpellID::AIR_SHIELD
|
&& bonus->sid == SpellID::AIR_SHIELD
|
||||||
&& bonus->val >= SecSkillLevel::ADVANCED;
|
&& bonus->val >= SecSkillLevel::ADVANCED;
|
||||||
};
|
};
|
||||||
@ -325,7 +325,7 @@ double DamageCalculator::getDefenseRangePenaltiesFactor() const
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
const std::string cachingStrNoMeleePenalty = "type_NO_MELEE_PENALTY";
|
const std::string cachingStrNoMeleePenalty = "type_NO_MELEE_PENALTY";
|
||||||
static const auto selectorNoMeleePenalty = Selector::type()(Bonus::NO_MELEE_PENALTY);
|
static const auto selectorNoMeleePenalty = Selector::type()(BonusType::NO_MELEE_PENALTY);
|
||||||
|
|
||||||
if(info.attacker->isShooter() && !info.attacker->hasBonus(selectorNoMeleePenalty, cachingStrNoMeleePenalty))
|
if(info.attacker->isShooter() && !info.attacker->hasBonus(selectorNoMeleePenalty, cachingStrNoMeleePenalty))
|
||||||
return 0.5;
|
return 0.5;
|
||||||
@ -356,7 +356,7 @@ double DamageCalculator::getDefenseUnluckyFactor() const
|
|||||||
|
|
||||||
double DamageCalculator::getDefenseBlindParalysisFactor() const
|
double DamageCalculator::getDefenseBlindParalysisFactor() const
|
||||||
{
|
{
|
||||||
double multAttackReduction = battleBonusValue(info.attacker, Selector::type()(Bonus::GENERAL_ATTACK_REDUCTION)) / 100.0;
|
double multAttackReduction = battleBonusValue(info.attacker, Selector::type()(BonusType::GENERAL_ATTACK_REDUCTION)) / 100.0;
|
||||||
return multAttackReduction;
|
return multAttackReduction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,7 +366,7 @@ double DamageCalculator::getDefenseForgetfulnessFactor() const
|
|||||||
{
|
{
|
||||||
//todo: set actual percentage in spell bonus configuration instead of just level; requires non trivial backward compatibility handling
|
//todo: set actual percentage in spell bonus configuration instead of just level; requires non trivial backward compatibility handling
|
||||||
//get list first, total value of 0 also counts
|
//get list first, total value of 0 also counts
|
||||||
TConstBonusListPtr forgetfulList = info.attacker->getBonuses(Selector::type()(Bonus::FORGETFULL),"type_FORGETFULL");
|
TConstBonusListPtr forgetfulList = info.attacker->getBonuses(Selector::type()(BonusType::FORGETFULL),"type_FORGETFULL");
|
||||||
|
|
||||||
if(!forgetfulList->empty())
|
if(!forgetfulList->empty())
|
||||||
{
|
{
|
||||||
@ -386,7 +386,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(Bonus::GENERAL_DAMAGE_REDUCTION, -1).And(Selector::sourceTypeSel(Bonus::SPELL_EFFECT));
|
static const auto selectorAllReduction = Selector::typeSubtype(BonusType::GENERAL_DAMAGE_REDUCTION, -1).And(Selector::sourceTypeSel(BonusSource::SPELL_EFFECT));
|
||||||
|
|
||||||
return info.defender->valOfBonuses(selectorAllReduction, cachingStrAllReduction) / 100.0;
|
return info.defender->valOfBonuses(selectorAllReduction, cachingStrAllReduction) / 100.0;
|
||||||
}
|
}
|
||||||
@ -397,7 +397,7 @@ double DamageCalculator::getDefenseMagicFactor() const
|
|||||||
if(info.attacker->creatureIndex() == CreatureID::MAGIC_ELEMENTAL)
|
if(info.attacker->creatureIndex() == CreatureID::MAGIC_ELEMENTAL)
|
||||||
{
|
{
|
||||||
const std::string cachingStrMagicImmunity = "type_LEVEL_SPELL_IMMUNITY";
|
const std::string cachingStrMagicImmunity = "type_LEVEL_SPELL_IMMUNITY";
|
||||||
static const auto selectorMagicImmunity = Selector::type()(Bonus::LEVEL_SPELL_IMMUNITY);
|
static const auto selectorMagicImmunity = Selector::type()(BonusType::LEVEL_SPELL_IMMUNITY);
|
||||||
|
|
||||||
if(info.defender->valOfBonuses(selectorMagicImmunity, cachingStrMagicImmunity) >= 5)
|
if(info.defender->valOfBonuses(selectorMagicImmunity, cachingStrMagicImmunity) >= 5)
|
||||||
return 0.5;
|
return 0.5;
|
||||||
@ -411,7 +411,7 @@ double DamageCalculator::getDefenseMindFactor() const
|
|||||||
if(info.attacker->creatureIndex() == CreatureID::PSYCHIC_ELEMENTAL)
|
if(info.attacker->creatureIndex() == CreatureID::PSYCHIC_ELEMENTAL)
|
||||||
{
|
{
|
||||||
const std::string cachingStrMindImmunity = "type_MIND_IMMUNITY";
|
const std::string cachingStrMindImmunity = "type_MIND_IMMUNITY";
|
||||||
static const auto selectorMindImmunity = Selector::type()(Bonus::MIND_IMMUNITY);
|
static const auto selectorMindImmunity = Selector::type()(BonusType::MIND_IMMUNITY);
|
||||||
|
|
||||||
if(info.defender->hasBonus(selectorMindImmunity, cachingStrMindImmunity))
|
if(info.defender->hasBonus(selectorMindImmunity, cachingStrMindImmunity))
|
||||||
return 0.5;
|
return 0.5;
|
||||||
@ -471,10 +471,10 @@ int64_t DamageCalculator::getCasualties(int64_t damageDealt) const
|
|||||||
|
|
||||||
int DamageCalculator::battleBonusValue(const IBonusBearer * bearer, const CSelector & selector) const
|
int DamageCalculator::battleBonusValue(const IBonusBearer * bearer, const CSelector & selector) const
|
||||||
{
|
{
|
||||||
auto noLimit = Selector::effectRange()(Bonus::NO_LIMIT);
|
auto noLimit = Selector::effectRange()(BonusLimitEffect::NO_LIMIT);
|
||||||
auto limitMatches = info.shooting
|
auto limitMatches = info.shooting
|
||||||
? Selector::effectRange()(Bonus::ONLY_DISTANCE_FIGHT)
|
? Selector::effectRange()(BonusLimitEffect::ONLY_DISTANCE_FIGHT)
|
||||||
: Selector::effectRange()(Bonus::ONLY_MELEE_FIGHT);
|
: Selector::effectRange()(BonusLimitEffect::ONLY_MELEE_FIGHT);
|
||||||
|
|
||||||
//any regular bonuses or just ones for melee/ranged
|
//any regular bonuses or just ones for melee/ranged
|
||||||
return bearer->getBonuses(selector, noLimit.Or(limitMatches))->totalValue();
|
return bearer->getBonuses(selector, noLimit.Or(limitMatches))->totalValue();
|
||||||
|
@ -19,7 +19,7 @@ ReachabilityInfo::Parameters::Parameters(const battle::Unit * Stack, BattleHex S
|
|||||||
startPosition(StartPosition),
|
startPosition(StartPosition),
|
||||||
doubleWide(Stack->doubleWide()),
|
doubleWide(Stack->doubleWide()),
|
||||||
side(Stack->unitSide()),
|
side(Stack->unitSide()),
|
||||||
flying(Stack->hasBonusOfType(Bonus::FLYING))
|
flying(Stack->hasBonusOfType(BonusType::FLYING))
|
||||||
{
|
{
|
||||||
knownAccessible = battle::Unit::getHexes(startPosition, doubleWide, side);
|
knownAccessible = battle::Unit::getHexes(startPosition, doubleWide, side);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "../CTownHandler.h"
|
#include "../CTownHandler.h"
|
||||||
#include "../CGeneralTextHandler.h"
|
#include "../CGeneralTextHandler.h"
|
||||||
#include "../CSkillHandler.h"
|
#include "../CSkillHandler.h"
|
||||||
#include "../CStack.h"
|
|
||||||
#include "../CArtHandler.h"
|
#include "../CArtHandler.h"
|
||||||
#include "../CModHandler.h"
|
#include "../CModHandler.h"
|
||||||
#include "../TerrainHandler.h"
|
#include "../TerrainHandler.h"
|
||||||
@ -32,44 +31,6 @@
|
|||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
#define BONUS_NAME(x) { #x, Bonus::x },
|
|
||||||
const std::map<std::string, Bonus::BonusType> bonusNameMap = {
|
|
||||||
BONUS_LIST
|
|
||||||
};
|
|
||||||
#undef BONUS_NAME
|
|
||||||
|
|
||||||
#define BONUS_VALUE(x) { #x, Bonus::x },
|
|
||||||
const std::map<std::string, Bonus::ValueType> bonusValueMap = { BONUS_VALUE_LIST };
|
|
||||||
#undef BONUS_VALUE
|
|
||||||
|
|
||||||
#define BONUS_SOURCE(x) { #x, Bonus::x },
|
|
||||||
const std::map<std::string, Bonus::BonusSource> bonusSourceMap = { BONUS_SOURCE_LIST };
|
|
||||||
#undef BONUS_SOURCE
|
|
||||||
|
|
||||||
#define BONUS_ITEM(x) { #x, Bonus::x },
|
|
||||||
|
|
||||||
const std::map<std::string, ui16> bonusDurationMap =
|
|
||||||
{
|
|
||||||
BONUS_ITEM(PERMANENT)
|
|
||||||
BONUS_ITEM(ONE_BATTLE)
|
|
||||||
BONUS_ITEM(ONE_DAY)
|
|
||||||
BONUS_ITEM(ONE_WEEK)
|
|
||||||
BONUS_ITEM(N_TURNS)
|
|
||||||
BONUS_ITEM(N_DAYS)
|
|
||||||
BONUS_ITEM(UNTIL_BEING_ATTACKED)
|
|
||||||
BONUS_ITEM(UNTIL_ATTACK)
|
|
||||||
BONUS_ITEM(STACK_GETS_TURN)
|
|
||||||
BONUS_ITEM(COMMANDER_KILLED)
|
|
||||||
{ "UNITL_BEING_ATTACKED", Bonus::UNTIL_BEING_ATTACKED }//typo, but used in some mods
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::map<std::string, Bonus::LimitEffect> bonusLimitEffect =
|
|
||||||
{
|
|
||||||
BONUS_ITEM(NO_LIMIT)
|
|
||||||
BONUS_ITEM(ONLY_DISTANCE_FIGHT)
|
|
||||||
BONUS_ITEM(ONLY_MELEE_FIGHT)
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::set<std::string> deprecatedBonusSet = {
|
const std::set<std::string> deprecatedBonusSet = {
|
||||||
"SECONDARY_SKILL_PREMY",
|
"SECONDARY_SKILL_PREMY",
|
||||||
"SECONDARY_SKILL_VAL2",
|
"SECONDARY_SKILL_VAL2",
|
||||||
@ -158,20 +119,20 @@ std::string Bonus::Description(std::optional<si32> customValue) const
|
|||||||
{
|
{
|
||||||
switch(source)
|
switch(source)
|
||||||
{
|
{
|
||||||
case ARTIFACT:
|
case BonusSource::ARTIFACT:
|
||||||
str << ArtifactID(sid).toArtifact(VLC->artifacts())->getNameTranslated();
|
str << ArtifactID(sid).toArtifact(VLC->artifacts())->getNameTranslated();
|
||||||
break;
|
break;
|
||||||
case SPELL_EFFECT:
|
case BonusSource::SPELL_EFFECT:
|
||||||
str << SpellID(sid).toSpell(VLC->spells())->getNameTranslated();
|
str << SpellID(sid).toSpell(VLC->spells())->getNameTranslated();
|
||||||
break;
|
break;
|
||||||
case CREATURE_ABILITY:
|
case BonusSource::CREATURE_ABILITY:
|
||||||
str << VLC->creh->objects[sid]->getNamePluralTranslated();
|
str << CreatureID(sid).toCreature(VLC->creatures())->getNamePluralTranslated();
|
||||||
break;
|
break;
|
||||||
case SECONDARY_SKILL:
|
case BonusSource::SECONDARY_SKILL:
|
||||||
str << VLC->skillh->getByIndex(sid)->getNameTranslated();
|
str << VLC->skills()->getByIndex(sid)->getNameTranslated();
|
||||||
break;
|
break;
|
||||||
case HERO_SPECIAL:
|
case BonusSource::HERO_SPECIAL:
|
||||||
str << VLC->heroh->objects[sid]->getNameTranslated();
|
str << VLC->heroTypes()->getByIndex(sid)->getNameTranslated();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//todo: handle all possible sources
|
//todo: handle all possible sources
|
||||||
@ -193,61 +154,40 @@ std::string Bonus::Description(std::optional<si32> customValue) const
|
|||||||
return str.str();
|
return str.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode subtypeToJson(Bonus::BonusType type, int subtype)
|
JsonNode subtypeToJson(BonusType type, int subtype)
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case Bonus::PRIMARY_SKILL:
|
case BonusType::PRIMARY_SKILL:
|
||||||
return JsonUtils::stringNode("primSkill." + PrimarySkill::names[subtype]);
|
return JsonUtils::stringNode("primSkill." + PrimarySkill::names[subtype]);
|
||||||
case Bonus::SPECIAL_SPELL_LEV:
|
case BonusType::SPECIAL_SPELL_LEV:
|
||||||
case Bonus::SPECIFIC_SPELL_DAMAGE:
|
case BonusType::SPECIFIC_SPELL_DAMAGE:
|
||||||
case Bonus::SPELL:
|
case BonusType::SPELL:
|
||||||
case Bonus::SPECIAL_PECULIAR_ENCHANT:
|
case BonusType::SPECIAL_PECULIAR_ENCHANT:
|
||||||
case Bonus::SPECIAL_ADD_VALUE_ENCHANT:
|
case BonusType::SPECIAL_ADD_VALUE_ENCHANT:
|
||||||
case Bonus::SPECIAL_FIXED_VALUE_ENCHANT:
|
case BonusType::SPECIAL_FIXED_VALUE_ENCHANT:
|
||||||
return JsonUtils::stringNode(CModHandler::makeFullIdentifier("", "spell", SpellID::encode(subtype)));
|
return JsonUtils::stringNode(CModHandler::makeFullIdentifier("", "spell", SpellID::encode(subtype)));
|
||||||
case Bonus::IMPROVED_NECROMANCY:
|
case BonusType::IMPROVED_NECROMANCY:
|
||||||
case Bonus::SPECIAL_UPGRADE:
|
case BonusType::SPECIAL_UPGRADE:
|
||||||
return JsonUtils::stringNode(CModHandler::makeFullIdentifier("", "creature", CreatureID::encode(subtype)));
|
return JsonUtils::stringNode(CModHandler::makeFullIdentifier("", "creature", CreatureID::encode(subtype)));
|
||||||
case Bonus::GENERATE_RESOURCE:
|
case BonusType::GENERATE_RESOURCE:
|
||||||
return JsonUtils::stringNode("resource." + GameConstants::RESOURCE_NAMES[subtype]);
|
return JsonUtils::stringNode("resource." + GameConstants::RESOURCE_NAMES[subtype]);
|
||||||
default:
|
default:
|
||||||
return JsonUtils::intNode(subtype);
|
return JsonUtils::intNode(subtype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode additionalInfoToJson(Bonus::BonusType type, CAddInfo addInfo)
|
JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo)
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case Bonus::SPECIAL_UPGRADE:
|
case BonusType::SPECIAL_UPGRADE:
|
||||||
return JsonUtils::stringNode(CModHandler::makeFullIdentifier("", "creature", CreatureID::encode(addInfo[0])));
|
return JsonUtils::stringNode(CModHandler::makeFullIdentifier("", "creature", CreatureID::encode(addInfo[0])));
|
||||||
default:
|
default:
|
||||||
return addInfo.toJsonNode();
|
return addInfo.toJsonNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode durationToJson(ui16 duration)
|
|
||||||
{
|
|
||||||
std::vector<std::string> durationNames;
|
|
||||||
for(ui16 durBit = 1; durBit; durBit = durBit << 1)
|
|
||||||
{
|
|
||||||
if(duration & durBit)
|
|
||||||
durationNames.push_back(vstd::findKey(bonusDurationMap, durBit));
|
|
||||||
}
|
|
||||||
if(durationNames.size() == 1)
|
|
||||||
{
|
|
||||||
return JsonUtils::stringNode(durationNames[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
JsonNode node(JsonNode::JsonType::DATA_VECTOR);
|
|
||||||
for(const std::string & dur : durationNames)
|
|
||||||
node.Vector().push_back(JsonUtils::stringNode(dur));
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonNode Bonus::toJsonNode() const
|
JsonNode Bonus::toJsonNode() const
|
||||||
{
|
{
|
||||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||||
@ -257,36 +197,26 @@ JsonNode Bonus::toJsonNode() const
|
|||||||
root["subtype"] = subtypeToJson(type, subtype);
|
root["subtype"] = subtypeToJson(type, subtype);
|
||||||
if(additionalInfo != CAddInfo::NONE)
|
if(additionalInfo != CAddInfo::NONE)
|
||||||
root["addInfo"] = additionalInfoToJson(type, additionalInfo);
|
root["addInfo"] = additionalInfoToJson(type, additionalInfo);
|
||||||
if(duration != 0)
|
|
||||||
{
|
|
||||||
JsonNode durationVec(JsonNode::JsonType::DATA_VECTOR);
|
|
||||||
for(const auto & kv : bonusDurationMap)
|
|
||||||
{
|
|
||||||
if(duration & kv.second)
|
|
||||||
durationVec.Vector().push_back(JsonUtils::stringNode(kv.first));
|
|
||||||
}
|
|
||||||
root["duration"] = durationVec;
|
|
||||||
}
|
|
||||||
if(turnsRemain != 0)
|
if(turnsRemain != 0)
|
||||||
root["turns"].Integer() = turnsRemain;
|
root["turns"].Integer() = turnsRemain;
|
||||||
if(source != OTHER)
|
if(source != BonusSource::OTHER)
|
||||||
root["sourceType"].String() = vstd::findKey(bonusSourceMap, source);
|
root["sourceType"].String() = vstd::findKey(bonusSourceMap, source);
|
||||||
if(targetSourceType != OTHER)
|
if(targetSourceType != BonusSource::OTHER)
|
||||||
root["targetSourceType"].String() = vstd::findKey(bonusSourceMap, targetSourceType);
|
root["targetSourceType"].String() = vstd::findKey(bonusSourceMap, targetSourceType);
|
||||||
if(sid != 0)
|
if(sid != 0)
|
||||||
root["sourceID"].Integer() = sid;
|
root["sourceID"].Integer() = sid;
|
||||||
if(val != 0)
|
if(val != 0)
|
||||||
root["val"].Integer() = val;
|
root["val"].Integer() = val;
|
||||||
if(valType != ADDITIVE_VALUE)
|
if(valType != BonusValueType::ADDITIVE_VALUE)
|
||||||
root["valueType"].String() = vstd::findKey(bonusValueMap, valType);
|
root["valueType"].String() = vstd::findKey(bonusValueMap, valType);
|
||||||
if(!stacking.empty())
|
if(!stacking.empty())
|
||||||
root["stacking"].String() = stacking;
|
root["stacking"].String() = stacking;
|
||||||
if(!description.empty())
|
if(!description.empty())
|
||||||
root["description"].String() = description;
|
root["description"].String() = description;
|
||||||
if(effectRange != NO_LIMIT)
|
if(effectRange != BonusLimitEffect::NO_LIMIT)
|
||||||
root["effectRange"].String() = vstd::findKey(bonusLimitEffect, effectRange);
|
root["effectRange"].String() = vstd::findKey(bonusLimitEffect, effectRange);
|
||||||
if(duration != PERMANENT)
|
if(duration != BonusDuration::PERMANENT)
|
||||||
root["duration"] = durationToJson(duration);
|
root["duration"].String() = vstd::findKey(bonusDurationMap, duration);
|
||||||
if(turnsRemain)
|
if(turnsRemain)
|
||||||
root["turns"].Integer() = turnsRemain;
|
root["turns"].Integer() = turnsRemain;
|
||||||
if(limiter)
|
if(limiter)
|
||||||
@ -298,32 +228,8 @@ JsonNode Bonus::toJsonNode() const
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Bonus::nameForBonus() const
|
Bonus::Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype):
|
||||||
{
|
duration(Duration),
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case Bonus::PRIMARY_SKILL:
|
|
||||||
return PrimarySkill::names[subtype];
|
|
||||||
case Bonus::SPECIAL_SPELL_LEV:
|
|
||||||
case Bonus::SPECIFIC_SPELL_DAMAGE:
|
|
||||||
case Bonus::SPELL:
|
|
||||||
case Bonus::SPECIAL_PECULIAR_ENCHANT:
|
|
||||||
case Bonus::SPECIAL_ADD_VALUE_ENCHANT:
|
|
||||||
case Bonus::SPECIAL_FIXED_VALUE_ENCHANT:
|
|
||||||
return VLC->spells()->getByIndex(subtype)->getJsonKey();
|
|
||||||
case Bonus::SPECIAL_UPGRADE:
|
|
||||||
return CreatureID::encode(subtype) + "2" + CreatureID::encode(additionalInfo[0]);
|
|
||||||
case Bonus::GENERATE_RESOURCE:
|
|
||||||
return GameConstants::RESOURCE_NAMES[subtype];
|
|
||||||
case Bonus::STACKS_SPEED:
|
|
||||||
return "speed";
|
|
||||||
default:
|
|
||||||
return vstd::findKey(bonusNameMap, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype):
|
|
||||||
duration(static_cast<ui16>(Duration)),
|
|
||||||
type(Type),
|
type(Type),
|
||||||
subtype(Subtype),
|
subtype(Subtype),
|
||||||
source(Src),
|
source(Src),
|
||||||
@ -332,11 +238,11 @@ Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si3
|
|||||||
description(std::move(Desc))
|
description(std::move(Desc))
|
||||||
{
|
{
|
||||||
boost::algorithm::trim(description);
|
boost::algorithm::trim(description);
|
||||||
targetSourceType = OTHER;
|
targetSourceType = BonusSource::OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, ValueType ValType):
|
Bonus::Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, BonusValueType ValType):
|
||||||
duration(static_cast<ui16>(Duration)),
|
duration(Duration),
|
||||||
type(Type),
|
type(Type),
|
||||||
subtype(Subtype),
|
subtype(Subtype),
|
||||||
source(Src),
|
source(Src),
|
||||||
@ -345,8 +251,8 @@ Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si3
|
|||||||
valType(ValType)
|
valType(ValType)
|
||||||
{
|
{
|
||||||
turnsRemain = 0;
|
turnsRemain = 0;
|
||||||
effectRange = NO_LIMIT;
|
effectRange = BonusLimitEffect::NO_LIMIT;
|
||||||
targetSourceType = OTHER;
|
targetSourceType = BonusSource::OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Bonus> Bonus::addPropagator(const TPropagatorPtr & Propagator)
|
std::shared_ptr<Bonus> Bonus::addPropagator(const TPropagatorPtr & Propagator)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "BonusEnum.h"
|
||||||
#include "../JsonNode.h"
|
#include "../JsonNode.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
@ -48,266 +49,24 @@ public:
|
|||||||
|
|
||||||
#define BONUS_TREE_DESERIALIZATION_FIX if(!h.saving && h.smartPointerSerialization) deserializationFix();
|
#define BONUS_TREE_DESERIALIZATION_FIX if(!h.saving && h.smartPointerSerialization) deserializationFix();
|
||||||
|
|
||||||
#define BONUS_LIST \
|
|
||||||
BONUS_NAME(NONE) \
|
|
||||||
BONUS_NAME(LEVEL_COUNTER) /* for commander artifacts*/ \
|
|
||||||
BONUS_NAME(MOVEMENT) /*Subtype is 1 - land, 0 - sea*/ \
|
|
||||||
BONUS_NAME(MORALE) \
|
|
||||||
BONUS_NAME(LUCK) \
|
|
||||||
BONUS_NAME(PRIMARY_SKILL) /*uses subtype to pick skill; additional info if set: 1 - only melee, 2 - only distance*/ \
|
|
||||||
BONUS_NAME(SIGHT_RADIUS) \
|
|
||||||
BONUS_NAME(MANA_REGENERATION) /*points per turn apart from normal (1 + mysticism)*/ \
|
|
||||||
BONUS_NAME(FULL_MANA_REGENERATION) /*all mana points are replenished every day*/ \
|
|
||||||
BONUS_NAME(NONEVIL_ALIGNMENT_MIX) /*good and neutral creatures can be mixed without morale penalty*/ \
|
|
||||||
BONUS_NAME(SURRENDER_DISCOUNT) /*%*/ \
|
|
||||||
BONUS_NAME(STACKS_SPEED) /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - subtracted to this part*/ \
|
|
||||||
BONUS_NAME(FLYING_MOVEMENT) /*value - penalty percentage*/ \
|
|
||||||
BONUS_NAME(SPELL_DURATION) \
|
|
||||||
BONUS_NAME(AIR_SPELL_DMG_PREMY) \
|
|
||||||
BONUS_NAME(EARTH_SPELL_DMG_PREMY) \
|
|
||||||
BONUS_NAME(FIRE_SPELL_DMG_PREMY) \
|
|
||||||
BONUS_NAME(WATER_SPELL_DMG_PREMY) \
|
|
||||||
BONUS_NAME(WATER_WALKING) /*value - penalty percentage*/ \
|
|
||||||
BONUS_NAME(NEGATE_ALL_NATURAL_IMMUNITIES) \
|
|
||||||
BONUS_NAME(STACK_HEALTH) \
|
|
||||||
BONUS_NAME(FIRE_SPELLS) \
|
|
||||||
BONUS_NAME(AIR_SPELLS) \
|
|
||||||
BONUS_NAME(WATER_SPELLS) \
|
|
||||||
BONUS_NAME(EARTH_SPELLS) \
|
|
||||||
BONUS_NAME(GENERATE_RESOURCE) /*daily value, uses subtype (resource type)*/ \
|
|
||||||
BONUS_NAME(CREATURE_GROWTH) /*for legion artifacts: value - week growth bonus, subtype - monster level if aplicable*/ \
|
|
||||||
BONUS_NAME(WHIRLPOOL_PROTECTION) /*hero won't lose army when teleporting through whirlpool*/ \
|
|
||||||
BONUS_NAME(SPELL) /*hero knows spell, val - skill level (0 - 3), subtype - spell id*/ \
|
|
||||||
BONUS_NAME(SPELLS_OF_LEVEL) /*hero knows all spells of given level, val - skill level; subtype - level*/ \
|
|
||||||
BONUS_NAME(BATTLE_NO_FLEEING) /*for shackles of war*/ \
|
|
||||||
BONUS_NAME(MAGIC_SCHOOL_SKILL) /* //eg. for magic plains terrain, subtype: school of magic (0 - all, 1 - fire, 2 - air, 4 - water, 8 - earth), value - level*/ \
|
|
||||||
BONUS_NAME(FREE_SHOOTING) /*stacks can shoot even if otherwise blocked (sharpshooter's bow effect)*/ \
|
|
||||||
BONUS_NAME(OPENING_BATTLE_SPELL) /*casts a spell at expert level at beginning of battle, val - spell power, subtype - spell id*/ \
|
|
||||||
BONUS_NAME(IMPROVED_NECROMANCY) /* raise more powerful creatures: subtype - creature type raised, addInfo - [required necromancy level, required stack level], val - necromancy level for this purpose */ \
|
|
||||||
BONUS_NAME(CREATURE_GROWTH_PERCENT) /*increases growth of all units in all towns, val - percentage*/ \
|
|
||||||
BONUS_NAME(FREE_SHIP_BOARDING) /*movement points preserved with ship boarding and landing*/ \
|
|
||||||
BONUS_NAME(FLYING) \
|
|
||||||
BONUS_NAME(SHOOTER) \
|
|
||||||
BONUS_NAME(CHARGE_IMMUNITY) \
|
|
||||||
BONUS_NAME(ADDITIONAL_ATTACK) \
|
|
||||||
BONUS_NAME(UNLIMITED_RETALIATIONS) \
|
|
||||||
BONUS_NAME(NO_MELEE_PENALTY) \
|
|
||||||
BONUS_NAME(JOUSTING) /*for champions*/ \
|
|
||||||
BONUS_NAME(HATE) /*eg. angels hate devils, subtype - ID of hated creature, val - damage bonus percent */ \
|
|
||||||
BONUS_NAME(KING) /* val - required slayer bonus val to affect */\
|
|
||||||
BONUS_NAME(MAGIC_RESISTANCE) /*in % (value)*/ \
|
|
||||||
BONUS_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \
|
|
||||||
BONUS_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \
|
|
||||||
BONUS_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - chance %, addInfo[0] - level, addInfo[1] -> [0 - all attacks, 1 - shot only, 2 - melee only] */ \
|
|
||||||
BONUS_NAME(SPELL_BEFORE_ATTACK) /* subtype - spell id, value - chance %, addInfo[0] - level, addInfo[1] -> [0 - all attacks, 1 - shot only, 2 - melee only] */ \
|
|
||||||
BONUS_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
|
|
||||||
BONUS_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus */ \
|
|
||||||
BONUS_NAME(BLOCK_MAGIC_ABOVE) /*blocks casting spells of the level > value */ \
|
|
||||||
BONUS_NAME(BLOCK_ALL_MAGIC) /*blocks casting spells*/ \
|
|
||||||
BONUS_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
|
|
||||||
BONUS_NAME(SPELL_DAMAGE_REDUCTION) /*eg. golems; value - reduction in %, subtype - spell school; -1 - all, 0 - air, 1 - fire, 2 - water, 3 - earth*/ \
|
|
||||||
BONUS_NAME(NO_WALL_PENALTY) \
|
|
||||||
BONUS_NAME(NON_LIVING) /*eg. golems, cannot be rised or healed, only neutral morale */ \
|
|
||||||
BONUS_NAME(RANDOM_SPELLCASTER) /*eg. master genie, val - level*/ \
|
|
||||||
BONUS_NAME(BLOCKS_RETALIATION) /*eg. naga*/ \
|
|
||||||
BONUS_NAME(SPELL_IMMUNITY) /*subid - spell id*/ \
|
|
||||||
BONUS_NAME(MANA_CHANNELING) /*value in %, eg. familiar*/ \
|
|
||||||
BONUS_NAME(SPELL_LIKE_ATTACK) /*subtype - spell, value - spell level; range is taken from spell, but damage from creature; eg. magog*/ \
|
|
||||||
BONUS_NAME(THREE_HEADED_ATTACK) /*eg. cerberus*/ \
|
|
||||||
BONUS_NAME(GENERAL_DAMAGE_PREMY) \
|
|
||||||
BONUS_NAME(FIRE_IMMUNITY) /*subtype 0 - all, 1 - all except positive, 2 - only damage spells*/ \
|
|
||||||
BONUS_NAME(WATER_IMMUNITY) \
|
|
||||||
BONUS_NAME(EARTH_IMMUNITY) \
|
|
||||||
BONUS_NAME(AIR_IMMUNITY) \
|
|
||||||
BONUS_NAME(MIND_IMMUNITY) \
|
|
||||||
BONUS_NAME(FIRE_SHIELD) \
|
|
||||||
BONUS_NAME(UNDEAD) \
|
|
||||||
BONUS_NAME(HP_REGENERATION) /*creature regenerates val HP every new round*/ \
|
|
||||||
BONUS_NAME(MANA_DRAIN) /*value - spell points per turn*/ \
|
|
||||||
BONUS_NAME(LIFE_DRAIN) \
|
|
||||||
BONUS_NAME(DOUBLE_DAMAGE_CHANCE) /*value in %, eg. dread knight*/ \
|
|
||||||
BONUS_NAME(RETURN_AFTER_STRIKE) \
|
|
||||||
BONUS_NAME(SPELLCASTER) /*subtype - spell id, value - level of school, additional info - weighted chance. use SPECIFIC_SPELL_POWER, CREATURE_SPELL_POWER or CREATURE_ENCHANT_POWER for calculating the power*/ \
|
|
||||||
BONUS_NAME(CATAPULT) \
|
|
||||||
BONUS_NAME(ENEMY_DEFENCE_REDUCTION) /*in % (value) eg. behemots*/ \
|
|
||||||
BONUS_NAME(GENERAL_DAMAGE_REDUCTION) /* shield / air shield effect, also armorer skill/petrify effect for subtype -1*/ \
|
|
||||||
BONUS_NAME(GENERAL_ATTACK_REDUCTION) /*eg. while stoned or blinded - in %,// subtype not used, use ONLY_MELEE_FIGHT / DISTANCE_FIGHT*/ \
|
|
||||||
BONUS_NAME(DEFENSIVE_STANCE) /* val - bonus to defense while defending */ \
|
|
||||||
BONUS_NAME(ATTACKS_ALL_ADJACENT) /*eg. hydra*/ \
|
|
||||||
BONUS_NAME(MORE_DAMAGE_FROM_SPELL) /*value - damage increase in %, subtype - spell id*/ \
|
|
||||||
BONUS_NAME(FEAR) \
|
|
||||||
BONUS_NAME(FEARLESS) \
|
|
||||||
BONUS_NAME(NO_DISTANCE_PENALTY) \
|
|
||||||
BONUS_NAME(ENCHANTER)/* for Enchanter spells, val - skill level, subtype - spell id, additionalInfo - cooldown */ \
|
|
||||||
BONUS_NAME(HEALER) \
|
|
||||||
BONUS_NAME(SIEGE_WEAPON) \
|
|
||||||
BONUS_NAME(HYPNOTIZED) \
|
|
||||||
BONUS_NAME(NO_RETALIATION) /*temporary bonus for basilisk, unicorn and scorpicore paralyze*/\
|
|
||||||
BONUS_NAME(ADDITIONAL_RETALIATION) /*value - number of additional retaliations*/ \
|
|
||||||
BONUS_NAME(MAGIC_MIRROR) /* value - chance of redirecting in %*/ \
|
|
||||||
BONUS_NAME(ALWAYS_MINIMUM_DAMAGE) /*unit does its minimum damage from range; subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage penalty (it'll subtracted from dmg), additional info - multiplicative anti-bonus for dmg in % [eg 20 means that creature will inflict 80% of normal minimal dmg]*/ \
|
|
||||||
BONUS_NAME(ALWAYS_MAXIMUM_DAMAGE) /*eg. bless effect, subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative bonus for dmg in %*/ \
|
|
||||||
BONUS_NAME(ATTACKS_NEAREST_CREATURE) /*while in berserk*/ \
|
|
||||||
BONUS_NAME(IN_FRENZY) /*value - level*/ \
|
|
||||||
BONUS_NAME(SLAYER) /*value - level*/ \
|
|
||||||
BONUS_NAME(FORGETFULL) /*forgetfulness spell effect, value - level*/ \
|
|
||||||
BONUS_NAME(NOT_ACTIVE) /* subtype - spell ID (paralyze, blind, stone gaze) for graphical effect*/ \
|
|
||||||
BONUS_NAME(NO_LUCK) /*eg. when fighting on cursed ground*/ \
|
|
||||||
BONUS_NAME(NO_MORALE) /*eg. when fighting on cursed ground*/ \
|
|
||||||
BONUS_NAME(DARKNESS) /*val = radius */ \
|
|
||||||
BONUS_NAME(SPECIAL_SPELL_LEV) /*subtype = id, val = value per level in percent*/\
|
|
||||||
BONUS_NAME(SPELL_DAMAGE) /*val = value, now works for sorcery*/\
|
|
||||||
BONUS_NAME(SPECIFIC_SPELL_DAMAGE) /*subtype = id of spell, val = value*/\
|
|
||||||
BONUS_NAME(SPECIAL_PECULIAR_ENCHANT) /*blesses and curses with id = val dependent on unit's level, subtype = 0 or 1 for Coronius*/\
|
|
||||||
BONUS_NAME(SPECIAL_UPGRADE) /*subtype = base, additionalInfo = target */\
|
|
||||||
BONUS_NAME(DRAGON_NATURE) \
|
|
||||||
BONUS_NAME(CREATURE_DAMAGE)/*subtype 0 = both, 1 = min, 2 = max*/\
|
|
||||||
BONUS_NAME(EXP_MULTIPLIER)/* val - percent of additional exp gained by stack/commander (base value 100)*/\
|
|
||||||
BONUS_NAME(SHOTS)\
|
|
||||||
BONUS_NAME(DEATH_STARE) /*subtype 0 - gorgon, 1 - commander*/\
|
|
||||||
BONUS_NAME(POISON) /*val - max health penalty from poison possible*/\
|
|
||||||
BONUS_NAME(BIND_EFFECT) /*doesn't do anything particular, works as a marker)*/\
|
|
||||||
BONUS_NAME(ACID_BREATH) /*additional val damage per creature after attack, additional info - chance in percent*/\
|
|
||||||
BONUS_NAME(RECEPTIVE) /*accepts friendly spells even with immunity*/\
|
|
||||||
BONUS_NAME(DIRECT_DAMAGE_IMMUNITY) /*direct damage spells, that is*/\
|
|
||||||
BONUS_NAME(CASTS) /*how many times creature can cast activated spell*/ \
|
|
||||||
BONUS_NAME(SPECIFIC_SPELL_POWER) /* value used for Thunderbolt and Resurrection cast by units, subtype - spell id */\
|
|
||||||
BONUS_NAME(CREATURE_SPELL_POWER) /* value per unit, divided by 100 (so faerie Dragons have 800)*/ \
|
|
||||||
BONUS_NAME(CREATURE_ENCHANT_POWER) /* total duration of spells cast by creature */ \
|
|
||||||
BONUS_NAME(ENCHANTED) /* permanently enchanted with spell subID of level = val, if val > 3 then spell is mass and has level of val-3*/ \
|
|
||||||
BONUS_NAME(REBIRTH) /* val - percent of life restored, subtype = 0 - regular, 1 - at least one unit (sacred Phoenix) */\
|
|
||||||
BONUS_NAME(ADDITIONAL_UNITS) /*val of units with id = subtype will be added to hero's army at the beginning of battle */\
|
|
||||||
BONUS_NAME(SPOILS_OF_WAR) /*val * 10^-6 * gained exp resources of subtype will be given to hero after battle*/\
|
|
||||||
BONUS_NAME(BLOCK)\
|
|
||||||
BONUS_NAME(DISGUISED) /* subtype - spell level */\
|
|
||||||
BONUS_NAME(VISIONS) /* subtype - spell level */\
|
|
||||||
BONUS_NAME(NO_TERRAIN_PENALTY) /* subtype - terrain type */\
|
|
||||||
BONUS_NAME(SOUL_STEAL) /*val - number of units gained per enemy killed, subtype = 0 - gained units survive after battle, 1 - they do not*/ \
|
|
||||||
BONUS_NAME(TRANSMUTATION) /*val - chance to trigger in %, subtype = 0 - resurrection based on HP, 1 - based on unit count, additional info - target creature ID (attacker default)*/\
|
|
||||||
BONUS_NAME(SUMMON_GUARDIANS) /*val - amount in % of stack count, subtype = creature ID*/\
|
|
||||||
BONUS_NAME(CATAPULT_EXTRA_SHOTS) /*val - power of catapult effect, requires CATAPULT bonus to work*/\
|
|
||||||
BONUS_NAME(RANGED_RETALIATION) /*allows shooters to perform ranged retaliation*/\
|
|
||||||
BONUS_NAME(BLOCKS_RANGED_RETALIATION) /*disallows ranged retaliation for shooter unit, BLOCKS_RETALIATION bonus is for melee retaliation only*/\
|
|
||||||
BONUS_NAME(MANUAL_CONTROL) /* manually control warmachine with id = subtype, chance = val */ \
|
|
||||||
BONUS_NAME(WIDE_BREATH) /* initial desigh: dragon breath affecting multiple nearby hexes */\
|
|
||||||
BONUS_NAME(FIRST_STRIKE) /* first counterattack, then attack if possible */\
|
|
||||||
BONUS_NAME(SYNERGY_TARGET) /* dummy skill for alternative upgrades mod */\
|
|
||||||
BONUS_NAME(SHOOTS_ALL_ADJACENT) /* H4 Cyclops-like shoot (attacks all hexes neighboring with target) without spell-like mechanics */\
|
|
||||||
BONUS_NAME(BLOCK_MAGIC_BELOW) /*blocks casting spells of the level < value */ \
|
|
||||||
BONUS_NAME(DESTRUCTION) /*kills extra units after hit, subtype = 0 - kill percentage of units, 1 - kill amount, val = chance in percent to trigger, additional info - amount/percentage to kill*/ \
|
|
||||||
BONUS_NAME(SPECIAL_CRYSTAL_GENERATION) /*crystal dragon crystal generation*/ \
|
|
||||||
BONUS_NAME(NO_SPELLCAST_BY_DEFAULT) /*spellcast will not be default attack option for this creature*/ \
|
|
||||||
BONUS_NAME(GARGOYLE) /* gargoyle is special than NON_LIVING, cannot be rised or healed */ \
|
|
||||||
BONUS_NAME(SPECIAL_ADD_VALUE_ENCHANT) /*specialty spell like Aenin has, increased effect of spell, additionalInfo = value to add*/\
|
|
||||||
BONUS_NAME(SPECIAL_FIXED_VALUE_ENCHANT) /*specialty spell like Melody has, constant spell effect (i.e. 3 luck), additionalInfo = value to fix.*/\
|
|
||||||
BONUS_NAME(TOWN_MAGIC_WELL) /*one-time pseudo-bonus to implement Magic Well in the town*/\
|
|
||||||
BONUS_NAME(LIMITED_SHOOTING_RANGE) /*limits range of shooting creatures, doesn't adjust any other mechanics (half vs full damage etc). val - range in hexes, additional info - optional new range for broken arrow mechanic */\
|
|
||||||
BONUS_NAME(LEARN_BATTLE_SPELL_CHANCE) /*skill-agnostic eagle eye chance. subtype = 0 - from enemy, 1 - TODO: from entire battlefield*/\
|
|
||||||
BONUS_NAME(LEARN_BATTLE_SPELL_LEVEL_LIMIT) /*skill-agnostic eagle eye limit, subtype - school (-1 for all), others TODO*/\
|
|
||||||
BONUS_NAME(PERCENTAGE_DAMAGE_BOOST) /*skill-agnostic archery and offence, subtype is 0 for offence and 1 for archery*/\
|
|
||||||
BONUS_NAME(LEARN_MEETING_SPELL_LIMIT) /*skill-agnostic scholar, subtype is -1 for all, TODO for others (> 0)*/\
|
|
||||||
BONUS_NAME(ROUGH_TERRAIN_DISCOUNT) /*skill-agnostic pathfinding*/\
|
|
||||||
BONUS_NAME(WANDERING_CREATURES_JOIN_BONUS) /*skill-agnostic diplomacy*/\
|
|
||||||
BONUS_NAME(BEFORE_BATTLE_REPOSITION) /*skill-agnostic tactics, bonus for allowing tactics*/\
|
|
||||||
BONUS_NAME(BEFORE_BATTLE_REPOSITION_BLOCK) /*skill-agnostic tactics, bonus for blocking opposite tactics. For now donble side tactics is TODO.*/\
|
|
||||||
BONUS_NAME(HERO_EXPERIENCE_GAIN_PERCENT) /*skill-agnostic learning, and we can use it as a global effect also*/\
|
|
||||||
BONUS_NAME(UNDEAD_RAISE_PERCENTAGE) /*Percentage of killed enemy creatures to be raised after battle as undead*/\
|
|
||||||
BONUS_NAME(MANA_PER_KNOWLEDGE) /*Percentage rate of translating 10 hero knowledge to mana, used to intelligence and global bonus*/\
|
|
||||||
BONUS_NAME(HERO_GRANTS_ATTACKS) /*If hero can grant additional attacks to creature, value is number of attacks, subtype is creatureID*/\
|
|
||||||
BONUS_NAME(BONUS_DAMAGE_PERCENTAGE) /*If hero can grant conditional damage to creature, value is percentage, subtype is creatureID*/\
|
|
||||||
BONUS_NAME(BONUS_DAMAGE_CHANCE) /*If hero can grant additional damage to creature, value is chance, subtype is creatureID*/\
|
|
||||||
BONUS_NAME(MAX_LEARNABLE_SPELL_LEVEL) /*This can work as wisdom before. val = max learnable spell level*/\
|
|
||||||
/* end of list */
|
|
||||||
|
|
||||||
|
|
||||||
#define BONUS_SOURCE_LIST \
|
|
||||||
BONUS_SOURCE(ARTIFACT)\
|
|
||||||
BONUS_SOURCE(ARTIFACT_INSTANCE)\
|
|
||||||
BONUS_SOURCE(OBJECT)\
|
|
||||||
BONUS_SOURCE(CREATURE_ABILITY)\
|
|
||||||
BONUS_SOURCE(TERRAIN_NATIVE)\
|
|
||||||
BONUS_SOURCE(TERRAIN_OVERLAY)\
|
|
||||||
BONUS_SOURCE(SPELL_EFFECT)\
|
|
||||||
BONUS_SOURCE(TOWN_STRUCTURE)\
|
|
||||||
BONUS_SOURCE(HERO_BASE_SKILL)\
|
|
||||||
BONUS_SOURCE(SECONDARY_SKILL)\
|
|
||||||
BONUS_SOURCE(HERO_SPECIAL)\
|
|
||||||
BONUS_SOURCE(ARMY)\
|
|
||||||
BONUS_SOURCE(CAMPAIGN_BONUS)\
|
|
||||||
BONUS_SOURCE(SPECIAL_WEEK)\
|
|
||||||
BONUS_SOURCE(STACK_EXPERIENCE)\
|
|
||||||
BONUS_SOURCE(COMMANDER) /*TODO: consider using simply STACK_INSTANCE */\
|
|
||||||
BONUS_SOURCE(GLOBAL) /*used for base bonuses which all heroes or all stacks should have*/\
|
|
||||||
BONUS_SOURCE(OTHER) /*used for defensive stance and default value of spell level limit*/
|
|
||||||
|
|
||||||
#define BONUS_VALUE_LIST \
|
|
||||||
BONUS_VALUE(ADDITIVE_VALUE)\
|
|
||||||
BONUS_VALUE(BASE_NUMBER)\
|
|
||||||
BONUS_VALUE(PERCENT_TO_ALL)\
|
|
||||||
BONUS_VALUE(PERCENT_TO_BASE)\
|
|
||||||
BONUS_VALUE(PERCENT_TO_SOURCE) /*Adds value only to bonuses with same source*/\
|
|
||||||
BONUS_VALUE(PERCENT_TO_TARGET_TYPE) /*Adds value only to bonuses with SourceType target*/\
|
|
||||||
BONUS_VALUE(INDEPENDENT_MAX) /*used for SPELL bonus */\
|
|
||||||
BONUS_VALUE(INDEPENDENT_MIN) //used for SECONDARY_SKILL_PREMY bonus
|
|
||||||
|
|
||||||
/// Struct for handling bonuses of several types. Can be transferred to any hero
|
/// Struct for handling bonuses of several types. Can be transferred to any hero
|
||||||
struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
||||||
{
|
{
|
||||||
enum BonusType
|
BonusDuration duration = BonusDuration::PERMANENT; //uses BonusDuration values
|
||||||
{
|
|
||||||
#define BONUS_NAME(x) x,
|
|
||||||
BONUS_LIST
|
|
||||||
#undef BONUS_NAME
|
|
||||||
};
|
|
||||||
enum BonusDuration //when bonus is automatically removed
|
|
||||||
{
|
|
||||||
PERMANENT = 1,
|
|
||||||
ONE_BATTLE = 2, //at the end of battle
|
|
||||||
ONE_DAY = 4, //at the end of day
|
|
||||||
ONE_WEEK = 8, //at the end of week (bonus lasts till the end of week, thats NOT 7 days
|
|
||||||
N_TURNS = 16, //used during battles, after battle bonus is always removed
|
|
||||||
N_DAYS = 32,
|
|
||||||
UNTIL_BEING_ATTACKED = 64, /*removed after attack and counterattacks are performed*/
|
|
||||||
UNTIL_ATTACK = 128, /*removed after attack and counterattacks are performed*/
|
|
||||||
STACK_GETS_TURN = 256, /*removed when stack gets its turn - used for defensive stance*/
|
|
||||||
COMMANDER_KILLED = 512
|
|
||||||
};
|
|
||||||
enum BonusSource
|
|
||||||
{
|
|
||||||
#define BONUS_SOURCE(x) x,
|
|
||||||
BONUS_SOURCE_LIST
|
|
||||||
#undef BONUS_SOURCE
|
|
||||||
NUM_BONUS_SOURCE /*This is a dummy value, which will be always last*/
|
|
||||||
};
|
|
||||||
|
|
||||||
enum LimitEffect
|
|
||||||
{
|
|
||||||
NO_LIMIT = 0,
|
|
||||||
ONLY_DISTANCE_FIGHT=1, ONLY_MELEE_FIGHT, //used to mark bonuses for attack/defense primary skills from spells like Precision (distance only)
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ValueType
|
|
||||||
{
|
|
||||||
#define BONUS_VALUE(x) x,
|
|
||||||
BONUS_VALUE_LIST
|
|
||||||
#undef BONUS_VALUE
|
|
||||||
};
|
|
||||||
|
|
||||||
ui16 duration = PERMANENT; //uses BonusDuration values
|
|
||||||
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 = 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 = -1; //-1 if not applicable - 4 bytes
|
||||||
|
|
||||||
BonusSource source = 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.
|
||||||
si32 val = 0;
|
si32 val = 0;
|
||||||
ui32 sid = 0; //source id: id of object/artifact/spell
|
ui32 sid = 0; //source id: id of object/artifact/spell
|
||||||
ValueType valType = ADDITIVE_VALUE;
|
BonusValueType valType = BonusValueType::ADDITIVE_VALUE;
|
||||||
std::string stacking; // bonuses with the same stacking value don't stack (e.g. Angel/Archangel morale bonus)
|
std::string stacking; // bonuses with the same stacking value don't stack (e.g. Angel/Archangel morale bonus)
|
||||||
|
|
||||||
CAddInfo additionalInfo;
|
CAddInfo additionalInfo;
|
||||||
LimitEffect effectRange = NO_LIMIT; //if not NO_LIMIT, bonus will be omitted by default
|
BonusLimitEffect effectRange = BonusLimitEffect::NO_LIMIT; //if not NO_LIMIT, bonus will be omitted by default
|
||||||
|
|
||||||
TLimiterPtr limiter;
|
TLimiterPtr limiter;
|
||||||
TPropagatorPtr propagator;
|
TPropagatorPtr propagator;
|
||||||
@ -317,7 +76,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
|||||||
std::string description;
|
std::string description;
|
||||||
|
|
||||||
Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1);
|
Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1);
|
||||||
Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype=-1, ValueType ValType = ADDITIVE_VALUE);
|
Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype=-1, BonusValueType ValType = BonusValueType::ADDITIVE_VALUE);
|
||||||
Bonus() = default;
|
Bonus() = default;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
@ -348,43 +107,43 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
|||||||
}
|
}
|
||||||
static bool NDays(const Bonus *hb)
|
static bool NDays(const Bonus *hb)
|
||||||
{
|
{
|
||||||
return hb->duration & Bonus::N_DAYS;
|
return hb->duration == BonusDuration::N_DAYS;
|
||||||
}
|
}
|
||||||
static bool NTurns(const Bonus *hb)
|
static bool NTurns(const Bonus *hb)
|
||||||
{
|
{
|
||||||
return hb->duration & Bonus::N_TURNS;
|
return hb->duration == BonusDuration::N_TURNS;
|
||||||
}
|
}
|
||||||
static bool OneDay(const Bonus *hb)
|
static bool OneDay(const Bonus *hb)
|
||||||
{
|
{
|
||||||
return hb->duration & Bonus::ONE_DAY;
|
return hb->duration == BonusDuration::ONE_DAY;
|
||||||
}
|
}
|
||||||
static bool OneWeek(const Bonus *hb)
|
static bool OneWeek(const Bonus *hb)
|
||||||
{
|
{
|
||||||
return hb->duration & Bonus::ONE_WEEK;
|
return hb->duration == BonusDuration::ONE_WEEK;
|
||||||
}
|
}
|
||||||
static bool OneBattle(const Bonus *hb)
|
static bool OneBattle(const Bonus *hb)
|
||||||
{
|
{
|
||||||
return hb->duration & Bonus::ONE_BATTLE;
|
return hb->duration == BonusDuration::ONE_BATTLE;
|
||||||
}
|
}
|
||||||
static bool Permanent(const Bonus *hb)
|
static bool Permanent(const Bonus *hb)
|
||||||
{
|
{
|
||||||
return hb->duration & Bonus::PERMANENT;
|
return hb->duration == BonusDuration::PERMANENT;
|
||||||
}
|
}
|
||||||
static bool UntilGetsTurn(const Bonus *hb)
|
static bool UntilGetsTurn(const Bonus *hb)
|
||||||
{
|
{
|
||||||
return hb->duration & Bonus::STACK_GETS_TURN;
|
return hb->duration == BonusDuration::STACK_GETS_TURN;
|
||||||
}
|
}
|
||||||
static bool UntilAttack(const Bonus *hb)
|
static bool UntilAttack(const Bonus *hb)
|
||||||
{
|
{
|
||||||
return hb->duration & Bonus::UNTIL_ATTACK;
|
return hb->duration == BonusDuration::UNTIL_ATTACK;
|
||||||
}
|
}
|
||||||
static bool UntilBeingAttacked(const Bonus *hb)
|
static bool UntilBeingAttacked(const Bonus *hb)
|
||||||
{
|
{
|
||||||
return hb->duration & Bonus::UNTIL_BEING_ATTACKED;
|
return hb->duration == BonusDuration::UNTIL_BEING_ATTACKED;
|
||||||
}
|
}
|
||||||
static bool UntilCommanderKilled(const Bonus *hb)
|
static bool UntilCommanderKilled(const Bonus *hb)
|
||||||
{
|
{
|
||||||
return hb->duration & Bonus::COMMANDER_KILLED;
|
return hb->duration == BonusDuration::COMMANDER_KILLED;
|
||||||
}
|
}
|
||||||
inline bool operator == (const BonusType & cf) const
|
inline bool operator == (const BonusType & cf) const
|
||||||
{
|
{
|
||||||
@ -411,7 +170,6 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
|||||||
|
|
||||||
std::string Description(std::optional<si32> customValue = {}) const;
|
std::string Description(std::optional<si32> customValue = {}) const;
|
||||||
JsonNode toJsonNode() const;
|
JsonNode toJsonNode() const;
|
||||||
std::string nameForBonus() const; // generate suitable name for bonus - e.g. for storing in json struct
|
|
||||||
|
|
||||||
std::shared_ptr<Bonus> addLimiter(const TLimiterPtr & Limiter); //returns this for convenient chain-calls
|
std::shared_ptr<Bonus> addLimiter(const TLimiterPtr & Limiter); //returns this for convenient chain-calls
|
||||||
std::shared_ptr<Bonus> addPropagator(const TPropagatorPtr & Propagator); //returns this for convenient chain-calls
|
std::shared_ptr<Bonus> addPropagator(const TPropagatorPtr & Propagator); //returns this for convenient chain-calls
|
||||||
@ -420,11 +178,6 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
|||||||
|
|
||||||
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus);
|
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus);
|
||||||
|
|
||||||
extern DLL_LINKAGE const std::map<std::string, Bonus::BonusType> bonusNameMap;
|
|
||||||
extern DLL_LINKAGE const std::map<std::string, Bonus::ValueType> bonusValueMap;
|
|
||||||
extern DLL_LINKAGE const std::map<std::string, Bonus::BonusSource> bonusSourceMap;
|
|
||||||
extern DLL_LINKAGE const std::map<std::string, ui16> bonusDurationMap;
|
|
||||||
extern DLL_LINKAGE const std::map<std::string, Bonus::LimitEffect> bonusLimitEffect;
|
|
||||||
extern DLL_LINKAGE const std::set<std::string> deprecatedBonusSet;
|
extern DLL_LINKAGE const std::set<std::string> deprecatedBonusSet;
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
58
lib/bonuses/BonusEnum.cpp
Normal file
58
lib/bonuses/BonusEnum.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* BonusEnum.cpp, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "StdInc.h"
|
||||||
|
|
||||||
|
#include "BonusEnum.h"
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#define BONUS_NAME(x) { #x, BonusType::x },
|
||||||
|
const std::map<std::string, BonusType> bonusNameMap = {
|
||||||
|
BONUS_LIST
|
||||||
|
};
|
||||||
|
#undef BONUS_NAME
|
||||||
|
|
||||||
|
#define BONUS_VALUE(x) { #x, BonusValueType::x },
|
||||||
|
const std::map<std::string, BonusValueType> bonusValueMap = { BONUS_VALUE_LIST };
|
||||||
|
#undef BONUS_VALUE
|
||||||
|
|
||||||
|
#define BONUS_SOURCE(x) { #x, BonusSource::x },
|
||||||
|
const std::map<std::string, BonusSource> bonusSourceMap = { BONUS_SOURCE_LIST };
|
||||||
|
#undef BONUS_SOURCE
|
||||||
|
|
||||||
|
#define BONUS_ITEM(x) { #x, BonusDuration::x },
|
||||||
|
const std::map<std::string, BonusDuration> bonusDurationMap =
|
||||||
|
{
|
||||||
|
BONUS_ITEM(PERMANENT)
|
||||||
|
BONUS_ITEM(ONE_BATTLE)
|
||||||
|
BONUS_ITEM(ONE_DAY)
|
||||||
|
BONUS_ITEM(ONE_WEEK)
|
||||||
|
BONUS_ITEM(N_TURNS)
|
||||||
|
BONUS_ITEM(N_DAYS)
|
||||||
|
BONUS_ITEM(UNTIL_BEING_ATTACKED)
|
||||||
|
BONUS_ITEM(UNTIL_ATTACK)
|
||||||
|
BONUS_ITEM(STACK_GETS_TURN)
|
||||||
|
BONUS_ITEM(COMMANDER_KILLED)
|
||||||
|
{ "UNITL_BEING_ATTACKED", BonusDuration::UNTIL_BEING_ATTACKED }//typo, but used in some mods
|
||||||
|
};
|
||||||
|
#undef BONUS_ITEM
|
||||||
|
|
||||||
|
#define BONUS_ITEM(x) { #x, BonusLimitEffect::x },
|
||||||
|
const std::map<std::string, BonusLimitEffect> bonusLimitEffect =
|
||||||
|
{
|
||||||
|
BONUS_ITEM(NO_LIMIT)
|
||||||
|
BONUS_ITEM(ONLY_DISTANCE_FIGHT)
|
||||||
|
BONUS_ITEM(ONLY_MELEE_FIGHT)
|
||||||
|
};
|
||||||
|
#undef BONUS_ITEM
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_END
|
264
lib/bonuses/BonusEnum.h
Normal file
264
lib/bonuses/BonusEnum.h
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* BonusEnum.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#define BONUS_LIST \
|
||||||
|
BONUS_NAME(NONE) \
|
||||||
|
BONUS_NAME(LEVEL_COUNTER) /* for commander artifacts*/ \
|
||||||
|
BONUS_NAME(MOVEMENT) /*Subtype is 1 - land, 0 - sea*/ \
|
||||||
|
BONUS_NAME(MORALE) \
|
||||||
|
BONUS_NAME(LUCK) \
|
||||||
|
BONUS_NAME(PRIMARY_SKILL) /*uses subtype to pick skill; additional info if set: 1 - only melee, 2 - only distance*/ \
|
||||||
|
BONUS_NAME(SIGHT_RADIUS) \
|
||||||
|
BONUS_NAME(MANA_REGENERATION) /*points per turn apart from normal (1 + mysticism)*/ \
|
||||||
|
BONUS_NAME(FULL_MANA_REGENERATION) /*all mana points are replenished every day*/ \
|
||||||
|
BONUS_NAME(NONEVIL_ALIGNMENT_MIX) /*good and neutral creatures can be mixed without morale penalty*/ \
|
||||||
|
BONUS_NAME(SURRENDER_DISCOUNT) /*%*/ \
|
||||||
|
BONUS_NAME(STACKS_SPEED) /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - subtracted to this part*/ \
|
||||||
|
BONUS_NAME(FLYING_MOVEMENT) /*value - penalty percentage*/ \
|
||||||
|
BONUS_NAME(SPELL_DURATION) \
|
||||||
|
BONUS_NAME(AIR_SPELL_DMG_PREMY) \
|
||||||
|
BONUS_NAME(EARTH_SPELL_DMG_PREMY) \
|
||||||
|
BONUS_NAME(FIRE_SPELL_DMG_PREMY) \
|
||||||
|
BONUS_NAME(WATER_SPELL_DMG_PREMY) \
|
||||||
|
BONUS_NAME(WATER_WALKING) /*value - penalty percentage*/ \
|
||||||
|
BONUS_NAME(NEGATE_ALL_NATURAL_IMMUNITIES) \
|
||||||
|
BONUS_NAME(STACK_HEALTH) \
|
||||||
|
BONUS_NAME(FIRE_SPELLS) \
|
||||||
|
BONUS_NAME(AIR_SPELLS) \
|
||||||
|
BONUS_NAME(WATER_SPELLS) \
|
||||||
|
BONUS_NAME(EARTH_SPELLS) \
|
||||||
|
BONUS_NAME(GENERATE_RESOURCE) /*daily value, uses subtype (resource type)*/ \
|
||||||
|
BONUS_NAME(CREATURE_GROWTH) /*for legion artifacts: value - week growth bonus, subtype - monster level if aplicable*/ \
|
||||||
|
BONUS_NAME(WHIRLPOOL_PROTECTION) /*hero won't lose army when teleporting through whirlpool*/ \
|
||||||
|
BONUS_NAME(SPELL) /*hero knows spell, val - skill level (0 - 3), subtype - spell id*/ \
|
||||||
|
BONUS_NAME(SPELLS_OF_LEVEL) /*hero knows all spells of given level, val - skill level; subtype - level*/ \
|
||||||
|
BONUS_NAME(BATTLE_NO_FLEEING) /*for shackles of war*/ \
|
||||||
|
BONUS_NAME(MAGIC_SCHOOL_SKILL) /* //eg. for magic plains terrain, subtype: school of magic (0 - all, 1 - fire, 2 - air, 4 - water, 8 - earth), value - level*/ \
|
||||||
|
BONUS_NAME(FREE_SHOOTING) /*stacks can shoot even if otherwise blocked (sharpshooter's bow effect)*/ \
|
||||||
|
BONUS_NAME(OPENING_BATTLE_SPELL) /*casts a spell at expert level at beginning of battle, val - spell power, subtype - spell id*/ \
|
||||||
|
BONUS_NAME(IMPROVED_NECROMANCY) /* raise more powerful creatures: subtype - creature type raised, addInfo - [required necromancy level, required stack level], val - necromancy level for this purpose */ \
|
||||||
|
BONUS_NAME(CREATURE_GROWTH_PERCENT) /*increases growth of all units in all towns, val - percentage*/ \
|
||||||
|
BONUS_NAME(FREE_SHIP_BOARDING) /*movement points preserved with ship boarding and landing*/ \
|
||||||
|
BONUS_NAME(FLYING) \
|
||||||
|
BONUS_NAME(SHOOTER) \
|
||||||
|
BONUS_NAME(CHARGE_IMMUNITY) \
|
||||||
|
BONUS_NAME(ADDITIONAL_ATTACK) \
|
||||||
|
BONUS_NAME(UNLIMITED_RETALIATIONS) \
|
||||||
|
BONUS_NAME(NO_MELEE_PENALTY) \
|
||||||
|
BONUS_NAME(JOUSTING) /*for champions*/ \
|
||||||
|
BONUS_NAME(HATE) /*eg. angels hate devils, subtype - ID of hated creature, val - damage bonus percent */ \
|
||||||
|
BONUS_NAME(KING) /* val - required slayer bonus val to affect */\
|
||||||
|
BONUS_NAME(MAGIC_RESISTANCE) /*in % (value)*/ \
|
||||||
|
BONUS_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \
|
||||||
|
BONUS_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \
|
||||||
|
BONUS_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - chance %, addInfo[0] - level, addInfo[1] -> [0 - all attacks, 1 - shot only, 2 - melee only] */ \
|
||||||
|
BONUS_NAME(SPELL_BEFORE_ATTACK) /* subtype - spell id, value - chance %, addInfo[0] - level, addInfo[1] -> [0 - all attacks, 1 - shot only, 2 - melee only] */ \
|
||||||
|
BONUS_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
|
||||||
|
BONUS_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus */ \
|
||||||
|
BONUS_NAME(BLOCK_MAGIC_ABOVE) /*blocks casting spells of the level > value */ \
|
||||||
|
BONUS_NAME(BLOCK_ALL_MAGIC) /*blocks casting spells*/ \
|
||||||
|
BONUS_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
|
||||||
|
BONUS_NAME(SPELL_DAMAGE_REDUCTION) /*eg. golems; value - reduction in %, subtype - spell school; -1 - all, 0 - air, 1 - fire, 2 - water, 3 - earth*/ \
|
||||||
|
BONUS_NAME(NO_WALL_PENALTY) \
|
||||||
|
BONUS_NAME(NON_LIVING) /*eg. golems, cannot be rised or healed, only neutral morale */ \
|
||||||
|
BONUS_NAME(RANDOM_SPELLCASTER) /*eg. master genie, val - level*/ \
|
||||||
|
BONUS_NAME(BLOCKS_RETALIATION) /*eg. naga*/ \
|
||||||
|
BONUS_NAME(SPELL_IMMUNITY) /*subid - spell id*/ \
|
||||||
|
BONUS_NAME(MANA_CHANNELING) /*value in %, eg. familiar*/ \
|
||||||
|
BONUS_NAME(SPELL_LIKE_ATTACK) /*subtype - spell, value - spell level; range is taken from spell, but damage from creature; eg. magog*/ \
|
||||||
|
BONUS_NAME(THREE_HEADED_ATTACK) /*eg. cerberus*/ \
|
||||||
|
BONUS_NAME(GENERAL_DAMAGE_PREMY) \
|
||||||
|
BONUS_NAME(FIRE_IMMUNITY) /*subtype 0 - all, 1 - all except positive, 2 - only damage spells*/ \
|
||||||
|
BONUS_NAME(WATER_IMMUNITY) \
|
||||||
|
BONUS_NAME(EARTH_IMMUNITY) \
|
||||||
|
BONUS_NAME(AIR_IMMUNITY) \
|
||||||
|
BONUS_NAME(MIND_IMMUNITY) \
|
||||||
|
BONUS_NAME(FIRE_SHIELD) \
|
||||||
|
BONUS_NAME(UNDEAD) \
|
||||||
|
BONUS_NAME(HP_REGENERATION) /*creature regenerates val HP every new round*/ \
|
||||||
|
BONUS_NAME(MANA_DRAIN) /*value - spell points per turn*/ \
|
||||||
|
BONUS_NAME(LIFE_DRAIN) \
|
||||||
|
BONUS_NAME(DOUBLE_DAMAGE_CHANCE) /*value in %, eg. dread knight*/ \
|
||||||
|
BONUS_NAME(RETURN_AFTER_STRIKE) \
|
||||||
|
BONUS_NAME(SPELLCASTER) /*subtype - spell id, value - level of school, additional info - weighted chance. use SPECIFIC_SPELL_POWER, CREATURE_SPELL_POWER or CREATURE_ENCHANT_POWER for calculating the power*/ \
|
||||||
|
BONUS_NAME(CATAPULT) \
|
||||||
|
BONUS_NAME(ENEMY_DEFENCE_REDUCTION) /*in % (value) eg. behemots*/ \
|
||||||
|
BONUS_NAME(GENERAL_DAMAGE_REDUCTION) /* shield / air shield effect, also armorer skill/petrify effect for subtype -1*/ \
|
||||||
|
BONUS_NAME(GENERAL_ATTACK_REDUCTION) /*eg. while stoned or blinded - in %,// subtype not used, use ONLY_MELEE_FIGHT / DISTANCE_FIGHT*/ \
|
||||||
|
BONUS_NAME(DEFENSIVE_STANCE) /* val - bonus to defense while defending */ \
|
||||||
|
BONUS_NAME(ATTACKS_ALL_ADJACENT) /*eg. hydra*/ \
|
||||||
|
BONUS_NAME(MORE_DAMAGE_FROM_SPELL) /*value - damage increase in %, subtype - spell id*/ \
|
||||||
|
BONUS_NAME(FEAR) \
|
||||||
|
BONUS_NAME(FEARLESS) \
|
||||||
|
BONUS_NAME(NO_DISTANCE_PENALTY) \
|
||||||
|
BONUS_NAME(ENCHANTER)/* for Enchanter spells, val - skill level, subtype - spell id, additionalInfo - cooldown */ \
|
||||||
|
BONUS_NAME(HEALER) \
|
||||||
|
BONUS_NAME(SIEGE_WEAPON) \
|
||||||
|
BONUS_NAME(HYPNOTIZED) \
|
||||||
|
BONUS_NAME(NO_RETALIATION) /*temporary bonus for basilisk, unicorn and scorpicore paralyze*/\
|
||||||
|
BONUS_NAME(ADDITIONAL_RETALIATION) /*value - number of additional retaliations*/ \
|
||||||
|
BONUS_NAME(MAGIC_MIRROR) /* value - chance of redirecting in %*/ \
|
||||||
|
BONUS_NAME(ALWAYS_MINIMUM_DAMAGE) /*unit does its minimum damage from range; subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage penalty (it'll subtracted from dmg), additional info - multiplicative anti-bonus for dmg in % [eg 20 means that creature will inflict 80% of normal minimal dmg]*/ \
|
||||||
|
BONUS_NAME(ALWAYS_MAXIMUM_DAMAGE) /*eg. bless effect, subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative bonus for dmg in %*/ \
|
||||||
|
BONUS_NAME(ATTACKS_NEAREST_CREATURE) /*while in berserk*/ \
|
||||||
|
BONUS_NAME(IN_FRENZY) /*value - level*/ \
|
||||||
|
BONUS_NAME(SLAYER) /*value - level*/ \
|
||||||
|
BONUS_NAME(FORGETFULL) /*forgetfulness spell effect, value - level*/ \
|
||||||
|
BONUS_NAME(NOT_ACTIVE) /* subtype - spell ID (paralyze, blind, stone gaze) for graphical effect*/ \
|
||||||
|
BONUS_NAME(NO_LUCK) /*eg. when fighting on cursed ground*/ \
|
||||||
|
BONUS_NAME(NO_MORALE) /*eg. when fighting on cursed ground*/ \
|
||||||
|
BONUS_NAME(DARKNESS) /*val = radius */ \
|
||||||
|
BONUS_NAME(SPECIAL_SPELL_LEV) /*subtype = id, val = value per level in percent*/\
|
||||||
|
BONUS_NAME(SPELL_DAMAGE) /*val = value, now works for sorcery*/\
|
||||||
|
BONUS_NAME(SPECIFIC_SPELL_DAMAGE) /*subtype = id of spell, val = value*/\
|
||||||
|
BONUS_NAME(SPECIAL_PECULIAR_ENCHANT) /*blesses and curses with id = val dependent on unit's level, subtype = 0 or 1 for Coronius*/\
|
||||||
|
BONUS_NAME(SPECIAL_UPGRADE) /*subtype = base, additionalInfo = target */\
|
||||||
|
BONUS_NAME(DRAGON_NATURE) \
|
||||||
|
BONUS_NAME(CREATURE_DAMAGE)/*subtype 0 = both, 1 = min, 2 = max*/\
|
||||||
|
BONUS_NAME(EXP_MULTIPLIER)/* val - percent of additional exp gained by stack/commander (base value 100)*/\
|
||||||
|
BONUS_NAME(SHOTS)\
|
||||||
|
BONUS_NAME(DEATH_STARE) /*subtype 0 - gorgon, 1 - commander*/\
|
||||||
|
BONUS_NAME(POISON) /*val - max health penalty from poison possible*/\
|
||||||
|
BONUS_NAME(BIND_EFFECT) /*doesn't do anything particular, works as a marker)*/\
|
||||||
|
BONUS_NAME(ACID_BREATH) /*additional val damage per creature after attack, additional info - chance in percent*/\
|
||||||
|
BONUS_NAME(RECEPTIVE) /*accepts friendly spells even with immunity*/\
|
||||||
|
BONUS_NAME(DIRECT_DAMAGE_IMMUNITY) /*direct damage spells, that is*/\
|
||||||
|
BONUS_NAME(CASTS) /*how many times creature can cast activated spell*/ \
|
||||||
|
BONUS_NAME(SPECIFIC_SPELL_POWER) /* value used for Thunderbolt and Resurrection cast by units, subtype - spell id */\
|
||||||
|
BONUS_NAME(CREATURE_SPELL_POWER) /* value per unit, divided by 100 (so faerie Dragons have 800)*/ \
|
||||||
|
BONUS_NAME(CREATURE_ENCHANT_POWER) /* total duration of spells cast by creature */ \
|
||||||
|
BONUS_NAME(ENCHANTED) /* permanently enchanted with spell subID of level = val, if val > 3 then spell is mass and has level of val-3*/ \
|
||||||
|
BONUS_NAME(REBIRTH) /* val - percent of life restored, subtype = 0 - regular, 1 - at least one unit (sacred Phoenix) */\
|
||||||
|
BONUS_NAME(ADDITIONAL_UNITS) /*val of units with id = subtype will be added to hero's army at the beginning of battle */\
|
||||||
|
BONUS_NAME(SPOILS_OF_WAR) /*val * 10^-6 * gained exp resources of subtype will be given to hero after battle*/\
|
||||||
|
BONUS_NAME(BLOCK)\
|
||||||
|
BONUS_NAME(DISGUISED) /* subtype - spell level */\
|
||||||
|
BONUS_NAME(VISIONS) /* subtype - spell level */\
|
||||||
|
BONUS_NAME(NO_TERRAIN_PENALTY) /* subtype - terrain type */\
|
||||||
|
BONUS_NAME(SOUL_STEAL) /*val - number of units gained per enemy killed, subtype = 0 - gained units survive after battle, 1 - they do not*/ \
|
||||||
|
BONUS_NAME(TRANSMUTATION) /*val - chance to trigger in %, subtype = 0 - resurrection based on HP, 1 - based on unit count, additional info - target creature ID (attacker default)*/\
|
||||||
|
BONUS_NAME(SUMMON_GUARDIANS) /*val - amount in % of stack count, subtype = creature ID*/\
|
||||||
|
BONUS_NAME(CATAPULT_EXTRA_SHOTS) /*val - power of catapult effect, requires CATAPULT bonus to work*/\
|
||||||
|
BONUS_NAME(RANGED_RETALIATION) /*allows shooters to perform ranged retaliation*/\
|
||||||
|
BONUS_NAME(BLOCKS_RANGED_RETALIATION) /*disallows ranged retaliation for shooter unit, BLOCKS_RETALIATION bonus is for melee retaliation only*/\
|
||||||
|
BONUS_NAME(MANUAL_CONTROL) /* manually control warmachine with id = subtype, chance = val */ \
|
||||||
|
BONUS_NAME(WIDE_BREATH) /* initial desigh: dragon breath affecting multiple nearby hexes */\
|
||||||
|
BONUS_NAME(FIRST_STRIKE) /* first counterattack, then attack if possible */\
|
||||||
|
BONUS_NAME(SYNERGY_TARGET) /* dummy skill for alternative upgrades mod */\
|
||||||
|
BONUS_NAME(SHOOTS_ALL_ADJACENT) /* H4 Cyclops-like shoot (attacks all hexes neighboring with target) without spell-like mechanics */\
|
||||||
|
BONUS_NAME(BLOCK_MAGIC_BELOW) /*blocks casting spells of the level < value */ \
|
||||||
|
BONUS_NAME(DESTRUCTION) /*kills extra units after hit, subtype = 0 - kill percentage of units, 1 - kill amount, val = chance in percent to trigger, additional info - amount/percentage to kill*/ \
|
||||||
|
BONUS_NAME(SPECIAL_CRYSTAL_GENERATION) /*crystal dragon crystal generation*/ \
|
||||||
|
BONUS_NAME(NO_SPELLCAST_BY_DEFAULT) /*spellcast will not be default attack option for this creature*/ \
|
||||||
|
BONUS_NAME(GARGOYLE) /* gargoyle is special than NON_LIVING, cannot be rised or healed */ \
|
||||||
|
BONUS_NAME(SPECIAL_ADD_VALUE_ENCHANT) /*specialty spell like Aenin has, increased effect of spell, additionalInfo = value to add*/\
|
||||||
|
BONUS_NAME(SPECIAL_FIXED_VALUE_ENCHANT) /*specialty spell like Melody has, constant spell effect (i.e. 3 luck), additionalInfo = value to fix.*/\
|
||||||
|
BONUS_NAME(TOWN_MAGIC_WELL) /*one-time pseudo-bonus to implement Magic Well in the town*/\
|
||||||
|
BONUS_NAME(LIMITED_SHOOTING_RANGE) /*limits range of shooting creatures, doesn't adjust any other mechanics (half vs full damage etc). val - range in hexes, additional info - optional new range for broken arrow mechanic */\
|
||||||
|
BONUS_NAME(LEARN_BATTLE_SPELL_CHANCE) /*skill-agnostic eagle eye chance. subtype = 0 - from enemy, 1 - TODO: from entire battlefield*/\
|
||||||
|
BONUS_NAME(LEARN_BATTLE_SPELL_LEVEL_LIMIT) /*skill-agnostic eagle eye limit, subtype - school (-1 for all), others TODO*/\
|
||||||
|
BONUS_NAME(PERCENTAGE_DAMAGE_BOOST) /*skill-agnostic archery and offence, subtype is 0 for offence and 1 for archery*/\
|
||||||
|
BONUS_NAME(LEARN_MEETING_SPELL_LIMIT) /*skill-agnostic scholar, subtype is -1 for all, TODO for others (> 0)*/\
|
||||||
|
BONUS_NAME(ROUGH_TERRAIN_DISCOUNT) /*skill-agnostic pathfinding*/\
|
||||||
|
BONUS_NAME(WANDERING_CREATURES_JOIN_BONUS) /*skill-agnostic diplomacy*/\
|
||||||
|
BONUS_NAME(BEFORE_BATTLE_REPOSITION) /*skill-agnostic tactics, bonus for allowing tactics*/\
|
||||||
|
BONUS_NAME(BEFORE_BATTLE_REPOSITION_BLOCK) /*skill-agnostic tactics, bonus for blocking opposite tactics. For now donble side tactics is TODO.*/\
|
||||||
|
BONUS_NAME(HERO_EXPERIENCE_GAIN_PERCENT) /*skill-agnostic learning, and we can use it as a global effect also*/\
|
||||||
|
BONUS_NAME(UNDEAD_RAISE_PERCENTAGE) /*Percentage of killed enemy creatures to be raised after battle as undead*/\
|
||||||
|
BONUS_NAME(MANA_PER_KNOWLEDGE) /*Percentage rate of translating 10 hero knowledge to mana, used to intelligence and global bonus*/\
|
||||||
|
BONUS_NAME(HERO_GRANTS_ATTACKS) /*If hero can grant additional attacks to creature, value is number of attacks, subtype is creatureID*/\
|
||||||
|
BONUS_NAME(BONUS_DAMAGE_PERCENTAGE) /*If hero can grant conditional damage to creature, value is percentage, subtype is creatureID*/\
|
||||||
|
BONUS_NAME(BONUS_DAMAGE_CHANCE) /*If hero can grant additional damage to creature, value is chance, subtype is creatureID*/\
|
||||||
|
BONUS_NAME(MAX_LEARNABLE_SPELL_LEVEL) /*This can work as wisdom before. val = max learnable spell level*/\
|
||||||
|
/* end of list */
|
||||||
|
|
||||||
|
|
||||||
|
#define BONUS_SOURCE_LIST \
|
||||||
|
BONUS_SOURCE(ARTIFACT)\
|
||||||
|
BONUS_SOURCE(ARTIFACT_INSTANCE)\
|
||||||
|
BONUS_SOURCE(OBJECT)\
|
||||||
|
BONUS_SOURCE(CREATURE_ABILITY)\
|
||||||
|
BONUS_SOURCE(TERRAIN_NATIVE)\
|
||||||
|
BONUS_SOURCE(TERRAIN_OVERLAY)\
|
||||||
|
BONUS_SOURCE(SPELL_EFFECT)\
|
||||||
|
BONUS_SOURCE(TOWN_STRUCTURE)\
|
||||||
|
BONUS_SOURCE(HERO_BASE_SKILL)\
|
||||||
|
BONUS_SOURCE(SECONDARY_SKILL)\
|
||||||
|
BONUS_SOURCE(HERO_SPECIAL)\
|
||||||
|
BONUS_SOURCE(ARMY)\
|
||||||
|
BONUS_SOURCE(CAMPAIGN_BONUS)\
|
||||||
|
BONUS_SOURCE(SPECIAL_WEEK)\
|
||||||
|
BONUS_SOURCE(STACK_EXPERIENCE)\
|
||||||
|
BONUS_SOURCE(COMMANDER) /*TODO: consider using simply STACK_INSTANCE */\
|
||||||
|
BONUS_SOURCE(GLOBAL) /*used for base bonuses which all heroes or all stacks should have*/\
|
||||||
|
BONUS_SOURCE(OTHER) /*used for defensive stance and default value of spell level limit*/
|
||||||
|
|
||||||
|
#define BONUS_VALUE_LIST \
|
||||||
|
BONUS_VALUE(ADDITIVE_VALUE)\
|
||||||
|
BONUS_VALUE(BASE_NUMBER)\
|
||||||
|
BONUS_VALUE(PERCENT_TO_ALL)\
|
||||||
|
BONUS_VALUE(PERCENT_TO_BASE)\
|
||||||
|
BONUS_VALUE(PERCENT_TO_SOURCE) /*Adds value only to bonuses with same source*/\
|
||||||
|
BONUS_VALUE(PERCENT_TO_TARGET_TYPE) /*Adds value only to bonuses with SourceType target*/\
|
||||||
|
BONUS_VALUE(INDEPENDENT_MAX) /*used for SPELL bonus */\
|
||||||
|
BONUS_VALUE(INDEPENDENT_MIN) //used for SECONDARY_SKILL_PREMY bonus
|
||||||
|
|
||||||
|
|
||||||
|
enum class BonusType
|
||||||
|
{
|
||||||
|
#define BONUS_NAME(x) x,
|
||||||
|
BONUS_LIST
|
||||||
|
#undef BONUS_NAME
|
||||||
|
};
|
||||||
|
enum class BonusDuration : uint16_t //when bonus is automatically removed
|
||||||
|
{
|
||||||
|
PERMANENT = 1,
|
||||||
|
ONE_BATTLE = 2, //at the end of battle
|
||||||
|
ONE_DAY = 4, //at the end of day
|
||||||
|
ONE_WEEK = 8, //at the end of week (bonus lasts till the end of week, thats NOT 7 days
|
||||||
|
N_TURNS = 16, //used during battles, after battle bonus is always removed
|
||||||
|
N_DAYS = 32,
|
||||||
|
UNTIL_BEING_ATTACKED = 64, /*removed after attack and counterattacks are performed*/
|
||||||
|
UNTIL_ATTACK = 128, /*removed after attack and counterattacks are performed*/
|
||||||
|
STACK_GETS_TURN = 256, /*removed when stack gets its turn - used for defensive stance*/
|
||||||
|
COMMANDER_KILLED = 512
|
||||||
|
};
|
||||||
|
enum class BonusSource
|
||||||
|
{
|
||||||
|
#define BONUS_SOURCE(x) x,
|
||||||
|
BONUS_SOURCE_LIST
|
||||||
|
#undef BONUS_SOURCE
|
||||||
|
NUM_BONUS_SOURCE /*This is a dummy value, which will be always last*/
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BonusLimitEffect
|
||||||
|
{
|
||||||
|
NO_LIMIT = 0,
|
||||||
|
ONLY_DISTANCE_FIGHT=1, ONLY_MELEE_FIGHT, //used to mark bonuses for attack/defense primary skills from spells like Precision (distance only)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BonusValueType
|
||||||
|
{
|
||||||
|
#define BONUS_VALUE(x) x,
|
||||||
|
BONUS_VALUE_LIST
|
||||||
|
#undef BONUS_VALUE
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DLL_LINKAGE const std::map<std::string, BonusType> bonusNameMap;
|
||||||
|
extern DLL_LINKAGE const std::map<std::string, BonusValueType> bonusValueMap;
|
||||||
|
extern DLL_LINKAGE const std::map<std::string, BonusSource> bonusSourceMap;
|
||||||
|
extern DLL_LINKAGE const std::map<std::string, BonusDuration> bonusDurationMap;
|
||||||
|
extern DLL_LINKAGE const std::map<std::string, BonusLimitEffect> bonusLimitEffect;
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_END
|
@ -98,7 +98,7 @@ int BonusList::totalValue() const
|
|||||||
auto percent = [](int64_t base, int64_t percent) -> int {
|
auto percent = [](int64_t base, int64_t percent) -> int {
|
||||||
return static_cast<int>(std::clamp<int64_t>((base * (100 + percent)) / 100, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()));
|
return static_cast<int>(std::clamp<int64_t>((base * (100 + percent)) / 100, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()));
|
||||||
};
|
};
|
||||||
std::array <BonusCollection, Bonus::BonusSource::NUM_BONUS_SOURCE> sources = {};
|
std::array <BonusCollection, vstd::to_underlying(BonusSource::NUM_BONUS_SOURCE)> sources = {};
|
||||||
BonusCollection any;
|
BonusCollection any;
|
||||||
bool hasIndepMax = false;
|
bool hasIndepMax = false;
|
||||||
bool hasIndepMin = false;
|
bool hasIndepMin = false;
|
||||||
@ -107,31 +107,31 @@ int BonusList::totalValue() const
|
|||||||
{
|
{
|
||||||
switch(b->valType)
|
switch(b->valType)
|
||||||
{
|
{
|
||||||
case Bonus::BASE_NUMBER:
|
case BonusValueType::BASE_NUMBER:
|
||||||
sources[b->source].base += b->val;
|
sources[vstd::to_underlying(b->source)].base += b->val;
|
||||||
break;
|
break;
|
||||||
case Bonus::PERCENT_TO_ALL:
|
case BonusValueType::PERCENT_TO_ALL:
|
||||||
sources[b->source].percentToAll += b->val;
|
sources[vstd::to_underlying(b->source)].percentToAll += b->val;
|
||||||
break;
|
break;
|
||||||
case Bonus::PERCENT_TO_BASE:
|
case BonusValueType::PERCENT_TO_BASE:
|
||||||
sources[b->source].percentToBase += b->val;
|
sources[vstd::to_underlying(b->source)].percentToBase += b->val;
|
||||||
break;
|
break;
|
||||||
case Bonus::PERCENT_TO_SOURCE:
|
case BonusValueType::PERCENT_TO_SOURCE:
|
||||||
sources[b->source].percentToSource += b->val;
|
sources[vstd::to_underlying(b->source)].percentToSource += b->val;
|
||||||
break;
|
break;
|
||||||
case Bonus::PERCENT_TO_TARGET_TYPE:
|
case BonusValueType::PERCENT_TO_TARGET_TYPE:
|
||||||
sources[b->targetSourceType].percentToSource += b->val;
|
sources[vstd::to_underlying(b->targetSourceType)].percentToSource += b->val;
|
||||||
break;
|
break;
|
||||||
case Bonus::ADDITIVE_VALUE:
|
case BonusValueType::ADDITIVE_VALUE:
|
||||||
sources[b->source].additive += b->val;
|
sources[vstd::to_underlying(b->source)].additive += b->val;
|
||||||
break;
|
break;
|
||||||
case Bonus::INDEPENDENT_MAX:
|
case BonusValueType::INDEPENDENT_MAX:
|
||||||
hasIndepMax = true;
|
hasIndepMax = true;
|
||||||
vstd::amax(sources[b->source].indepMax, b->val);
|
vstd::amax(sources[vstd::to_underlying(b->source)].indepMax, b->val);
|
||||||
break;
|
break;
|
||||||
case Bonus::INDEPENDENT_MIN:
|
case BonusValueType::INDEPENDENT_MIN:
|
||||||
hasIndepMin = true;
|
hasIndepMin = true;
|
||||||
vstd::amin(sources[b->source].indepMin, b->val);
|
vstd::amin(sources[vstd::to_underlying(b->source)].indepMin, b->val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ int BonusList::totalValue() const
|
|||||||
|
|
||||||
const int notIndepBonuses = static_cast<int>(std::count_if(bonuses.cbegin(), bonuses.cend(), [](const std::shared_ptr<Bonus>& b)
|
const int notIndepBonuses = static_cast<int>(std::count_if(bonuses.cbegin(), bonuses.cend(), [](const std::shared_ptr<Bonus>& b)
|
||||||
{
|
{
|
||||||
return b->valType != Bonus::INDEPENDENT_MAX && b->valType != Bonus::INDEPENDENT_MIN;
|
return b->valType != BonusValueType::INDEPENDENT_MAX && b->valType != BonusValueType::INDEPENDENT_MIN;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if(notIndepBonuses)
|
if(notIndepBonuses)
|
||||||
@ -190,7 +190,7 @@ void BonusList::getBonuses(BonusList & out, const CSelector &selector, const CSe
|
|||||||
for(const auto & b : bonuses)
|
for(const auto & b : bonuses)
|
||||||
{
|
{
|
||||||
//add matching bonuses that matches limit predicate or have NO_LIMIT if no given predicate
|
//add matching bonuses that matches limit predicate or have NO_LIMIT if no given predicate
|
||||||
auto noFightLimit = b->effectRange == Bonus::NO_LIMIT;
|
auto noFightLimit = b->effectRange == BonusLimitEffect::NO_LIMIT;
|
||||||
if(selector(b.get()) && ((!limit && noFightLimit) || ((bool)limit && limit(b.get()))))
|
if(selector(b.get()) && ((!limit && noFightLimit) || ((bool)limit && limit(b.get()))))
|
||||||
out.push_back(b);
|
out.push_back(b);
|
||||||
}
|
}
|
||||||
|
@ -23,112 +23,112 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
|
|||||||
if(deprecatedTypeStr == "SECONDARY_SKILL_PREMY" || deprecatedTypeStr == "SPECIAL_SECONDARY_SKILL")
|
if(deprecatedTypeStr == "SECONDARY_SKILL_PREMY" || deprecatedTypeStr == "SPECIAL_SECONDARY_SKILL")
|
||||||
{
|
{
|
||||||
if(deprecatedSubtype == SecondarySkill::PATHFINDING || deprecatedSubtypeStr == "skill.pathfinding")
|
if(deprecatedSubtype == SecondarySkill::PATHFINDING || deprecatedSubtypeStr == "skill.pathfinding")
|
||||||
type = Bonus::ROUGH_TERRAIN_DISCOUNT;
|
type = BonusType::ROUGH_TERRAIN_DISCOUNT;
|
||||||
else if(deprecatedSubtype == SecondarySkill::DIPLOMACY || deprecatedSubtypeStr == "skill.diplomacy")
|
else if(deprecatedSubtype == SecondarySkill::DIPLOMACY || deprecatedSubtypeStr == "skill.diplomacy")
|
||||||
type = Bonus::WANDERING_CREATURES_JOIN_BONUS;
|
type = BonusType::WANDERING_CREATURES_JOIN_BONUS;
|
||||||
else if(deprecatedSubtype == SecondarySkill::WISDOM || deprecatedSubtypeStr == "skill.wisdom")
|
else if(deprecatedSubtype == SecondarySkill::WISDOM || deprecatedSubtypeStr == "skill.wisdom")
|
||||||
type = Bonus::MAX_LEARNABLE_SPELL_LEVEL;
|
type = BonusType::MAX_LEARNABLE_SPELL_LEVEL;
|
||||||
else if(deprecatedSubtype == SecondarySkill::MYSTICISM || deprecatedSubtypeStr == "skill.mysticism")
|
else if(deprecatedSubtype == SecondarySkill::MYSTICISM || deprecatedSubtypeStr == "skill.mysticism")
|
||||||
type = Bonus::MANA_REGENERATION;
|
type = BonusType::MANA_REGENERATION;
|
||||||
else if(deprecatedSubtype == SecondarySkill::NECROMANCY || deprecatedSubtypeStr == "skill.necromancy")
|
else if(deprecatedSubtype == SecondarySkill::NECROMANCY || deprecatedSubtypeStr == "skill.necromancy")
|
||||||
type = Bonus::UNDEAD_RAISE_PERCENTAGE;
|
type = BonusType::UNDEAD_RAISE_PERCENTAGE;
|
||||||
else if(deprecatedSubtype == SecondarySkill::LEARNING || deprecatedSubtypeStr == "skill.learning")
|
else if(deprecatedSubtype == SecondarySkill::LEARNING || deprecatedSubtypeStr == "skill.learning")
|
||||||
type = Bonus::HERO_EXPERIENCE_GAIN_PERCENT;
|
type = BonusType::HERO_EXPERIENCE_GAIN_PERCENT;
|
||||||
else if(deprecatedSubtype == SecondarySkill::RESISTANCE || deprecatedSubtypeStr == "skill.resistance")
|
else if(deprecatedSubtype == SecondarySkill::RESISTANCE || deprecatedSubtypeStr == "skill.resistance")
|
||||||
type = Bonus::MAGIC_RESISTANCE;
|
type = BonusType::MAGIC_RESISTANCE;
|
||||||
else if(deprecatedSubtype == SecondarySkill::EAGLE_EYE || deprecatedSubtypeStr == "skill.eagleEye")
|
else if(deprecatedSubtype == SecondarySkill::EAGLE_EYE || deprecatedSubtypeStr == "skill.eagleEye")
|
||||||
type = Bonus::LEARN_BATTLE_SPELL_CHANCE;
|
type = BonusType::LEARN_BATTLE_SPELL_CHANCE;
|
||||||
else if(deprecatedSubtype == SecondarySkill::SCOUTING || deprecatedSubtypeStr == "skill.scouting")
|
else if(deprecatedSubtype == SecondarySkill::SCOUTING || deprecatedSubtypeStr == "skill.scouting")
|
||||||
type = Bonus::SIGHT_RADIUS;
|
type = BonusType::SIGHT_RADIUS;
|
||||||
else if(deprecatedSubtype == SecondarySkill::INTELLIGENCE || deprecatedSubtypeStr == "skill.intelligence")
|
else if(deprecatedSubtype == SecondarySkill::INTELLIGENCE || deprecatedSubtypeStr == "skill.intelligence")
|
||||||
{
|
{
|
||||||
type = Bonus::MANA_PER_KNOWLEDGE;
|
type = BonusType::MANA_PER_KNOWLEDGE;
|
||||||
valueType = Bonus::PERCENT_TO_BASE;
|
valueType = BonusValueType::PERCENT_TO_BASE;
|
||||||
valueTypeRelevant = true;
|
valueTypeRelevant = true;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::SORCERY || deprecatedSubtypeStr == "skill.sorcery")
|
else if(deprecatedSubtype == SecondarySkill::SORCERY || deprecatedSubtypeStr == "skill.sorcery")
|
||||||
type = Bonus::SPELL_DAMAGE;
|
type = BonusType::SPELL_DAMAGE;
|
||||||
else if(deprecatedSubtype == SecondarySkill::SCHOLAR || deprecatedSubtypeStr == "skill.scholar")
|
else if(deprecatedSubtype == SecondarySkill::SCHOLAR || deprecatedSubtypeStr == "skill.scholar")
|
||||||
type = Bonus::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 = 1;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
type = Bonus::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 = 0;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
type = Bonus::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 = -1;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
type = Bonus::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 = 0;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
valueType = Bonus::PERCENT_TO_BASE;
|
valueType = BonusValueType::PERCENT_TO_BASE;
|
||||||
valueTypeRelevant = true;
|
valueTypeRelevant = true;
|
||||||
type = Bonus::MOVEMENT;
|
type = BonusType::MOVEMENT;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::LOGISTICS || deprecatedSubtypeStr == "skill.logistics")
|
else if(deprecatedSubtype == SecondarySkill::LOGISTICS || deprecatedSubtypeStr == "skill.logistics")
|
||||||
{
|
{
|
||||||
subtype = 1;
|
subtype = 1;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
valueType = Bonus::PERCENT_TO_BASE;
|
valueType = BonusValueType::PERCENT_TO_BASE;
|
||||||
valueTypeRelevant = true;
|
valueTypeRelevant = true;
|
||||||
type = Bonus::MOVEMENT;
|
type = BonusType::MOVEMENT;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::ESTATES || deprecatedSubtypeStr == "skill.estates")
|
else if(deprecatedSubtype == SecondarySkill::ESTATES || deprecatedSubtypeStr == "skill.estates")
|
||||||
{
|
{
|
||||||
type = Bonus::GENERATE_RESOURCE;
|
type = BonusType::GENERATE_RESOURCE;
|
||||||
subtype = GameResID(EGameResID::GOLD);
|
subtype = GameResID(EGameResID::GOLD);
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::AIR_MAGIC || deprecatedSubtypeStr == "skill.airMagic")
|
else if(deprecatedSubtype == SecondarySkill::AIR_MAGIC || deprecatedSubtypeStr == "skill.airMagic")
|
||||||
{
|
{
|
||||||
type = Bonus::MAGIC_SCHOOL_SKILL;
|
type = BonusType::MAGIC_SCHOOL_SKILL;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
subtype = 4;
|
subtype = 4;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::WATER_MAGIC || deprecatedSubtypeStr == "skill.waterMagic")
|
else if(deprecatedSubtype == SecondarySkill::WATER_MAGIC || deprecatedSubtypeStr == "skill.waterMagic")
|
||||||
{
|
{
|
||||||
type = Bonus::MAGIC_SCHOOL_SKILL;
|
type = BonusType::MAGIC_SCHOOL_SKILL;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
subtype = 1;
|
subtype = 1;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::FIRE_MAGIC || deprecatedSubtypeStr == "skill.fireMagic")
|
else if(deprecatedSubtype == SecondarySkill::FIRE_MAGIC || deprecatedSubtypeStr == "skill.fireMagic")
|
||||||
{
|
{
|
||||||
type = Bonus::MAGIC_SCHOOL_SKILL;
|
type = BonusType::MAGIC_SCHOOL_SKILL;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
subtype = 2;
|
subtype = 2;
|
||||||
}
|
}
|
||||||
else if(deprecatedSubtype == SecondarySkill::EARTH_MAGIC || deprecatedSubtypeStr == "skill.earthMagic")
|
else if(deprecatedSubtype == SecondarySkill::EARTH_MAGIC || deprecatedSubtypeStr == "skill.earthMagic")
|
||||||
{
|
{
|
||||||
type = Bonus::MAGIC_SCHOOL_SKILL;
|
type = BonusType::MAGIC_SCHOOL_SKILL;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
subtype = 8;
|
subtype = 8;
|
||||||
}
|
}
|
||||||
else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
|
else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
|
||||||
{
|
{
|
||||||
type = Bonus::BONUS_DAMAGE_CHANCE;
|
type = BonusType::BONUS_DAMAGE_CHANCE;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
subtypeStr = "core:creature.ballista";
|
subtypeStr = "core:creature.ballista";
|
||||||
}
|
}
|
||||||
else if (deprecatedSubtype == SecondarySkill::FIRST_AID || deprecatedSubtypeStr == "skill.firstAid")
|
else if (deprecatedSubtype == SecondarySkill::FIRST_AID || deprecatedSubtypeStr == "skill.firstAid")
|
||||||
{
|
{
|
||||||
type = Bonus::SPECIFIC_SPELL_POWER;
|
type = BonusType::SPECIFIC_SPELL_POWER;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
subtypeStr = "core:spell.firstAid";
|
subtypeStr = "core:spell.firstAid";
|
||||||
}
|
}
|
||||||
else if (deprecatedSubtype == SecondarySkill::BALLISTICS || deprecatedSubtypeStr == "skill.ballistics")
|
else if (deprecatedSubtype == SecondarySkill::BALLISTICS || deprecatedSubtypeStr == "skill.ballistics")
|
||||||
{
|
{
|
||||||
type = Bonus::CATAPULT_EXTRA_SHOTS;
|
type = BonusType::CATAPULT_EXTRA_SHOTS;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
subtypeStr = "core:spell.catapultShot";
|
subtypeStr = "core:spell.catapultShot";
|
||||||
}
|
}
|
||||||
@ -138,10 +138,10 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
|
|||||||
else if (deprecatedTypeStr == "SECONDARY_SKILL_VAL2")
|
else if (deprecatedTypeStr == "SECONDARY_SKILL_VAL2")
|
||||||
{
|
{
|
||||||
if(deprecatedSubtype == SecondarySkill::EAGLE_EYE || deprecatedSubtypeStr == "skill.eagleEye")
|
if(deprecatedSubtype == SecondarySkill::EAGLE_EYE || deprecatedSubtypeStr == "skill.eagleEye")
|
||||||
type = Bonus::LEARN_BATTLE_SPELL_LEVEL_LIMIT;
|
type = BonusType::LEARN_BATTLE_SPELL_LEVEL_LIMIT;
|
||||||
else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
|
else if (deprecatedSubtype == SecondarySkill::ARTILLERY || deprecatedSubtypeStr == "skill.artillery")
|
||||||
{
|
{
|
||||||
type = Bonus::HERO_GRANTS_ATTACKS;
|
type = BonusType::HERO_GRANTS_ATTACKS;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
subtypeStr = "core:creature.ballista";
|
subtypeStr = "core:creature.ballista";
|
||||||
}
|
}
|
||||||
@ -152,68 +152,68 @@ BonusParams::BonusParams(std::string deprecatedTypeStr, std::string deprecatedSu
|
|||||||
{
|
{
|
||||||
subtype = 0;
|
subtype = 0;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
valueType = Bonus::ADDITIVE_VALUE;
|
valueType = BonusValueType::ADDITIVE_VALUE;
|
||||||
valueTypeRelevant = true;
|
valueTypeRelevant = true;
|
||||||
type = Bonus::MOVEMENT;
|
type = BonusType::MOVEMENT;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "LAND_MOVEMENT")
|
else if (deprecatedTypeStr == "LAND_MOVEMENT")
|
||||||
{
|
{
|
||||||
subtype = 1;
|
subtype = 1;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
valueType = Bonus::ADDITIVE_VALUE;
|
valueType = BonusValueType::ADDITIVE_VALUE;
|
||||||
valueTypeRelevant = true;
|
valueTypeRelevant = true;
|
||||||
type = Bonus::MOVEMENT;
|
type = BonusType::MOVEMENT;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "MAXED_SPELL")
|
else if (deprecatedTypeStr == "MAXED_SPELL")
|
||||||
{
|
{
|
||||||
type = Bonus::SPELL;
|
type = BonusType::SPELL;
|
||||||
subtypeStr = deprecatedSubtypeStr;
|
subtypeStr = deprecatedSubtypeStr;
|
||||||
subtypeRelevant = true;
|
subtypeRelevant = true;
|
||||||
valueType = Bonus::INDEPENDENT_MAX;
|
valueType = BonusValueType::INDEPENDENT_MAX;
|
||||||
valueTypeRelevant = true;
|
valueTypeRelevant = true;
|
||||||
val = 3;
|
val = 3;
|
||||||
valRelevant = true;
|
valRelevant = true;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "FULL_HP_REGENERATION")
|
else if (deprecatedTypeStr == "FULL_HP_REGENERATION")
|
||||||
{
|
{
|
||||||
type = Bonus::HP_REGENERATION;
|
type = BonusType::HP_REGENERATION;
|
||||||
val = 100000; //very high value to always chose stack health
|
val = 100000; //very high value to always chose stack health
|
||||||
valRelevant = true;
|
valRelevant = true;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "KING1")
|
else if (deprecatedTypeStr == "KING1")
|
||||||
{
|
{
|
||||||
type = Bonus::KING;
|
type = BonusType::KING;
|
||||||
val = 0;
|
val = 0;
|
||||||
valRelevant = true;
|
valRelevant = true;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "KING2")
|
else if (deprecatedTypeStr == "KING2")
|
||||||
{
|
{
|
||||||
type = Bonus::KING;
|
type = BonusType::KING;
|
||||||
val = 2;
|
val = 2;
|
||||||
valRelevant = true;
|
valRelevant = true;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "KING3")
|
else if (deprecatedTypeStr == "KING3")
|
||||||
{
|
{
|
||||||
type = Bonus::KING;
|
type = BonusType::KING;
|
||||||
val = 3;
|
val = 3;
|
||||||
valRelevant = true;
|
valRelevant = true;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "SIGHT_RADIOUS")
|
else if (deprecatedTypeStr == "SIGHT_RADIOUS")
|
||||||
type = Bonus::SIGHT_RADIUS;
|
type = BonusType::SIGHT_RADIUS;
|
||||||
else if (deprecatedTypeStr == "SELF_MORALE")
|
else if (deprecatedTypeStr == "SELF_MORALE")
|
||||||
{
|
{
|
||||||
type = Bonus::MORALE;
|
type = BonusType::MORALE;
|
||||||
val = 1;
|
val = 1;
|
||||||
valRelevant = true;
|
valRelevant = true;
|
||||||
valueType = Bonus::INDEPENDENT_MAX;
|
valueType = BonusValueType::INDEPENDENT_MAX;
|
||||||
valueTypeRelevant = true;
|
valueTypeRelevant = true;
|
||||||
}
|
}
|
||||||
else if (deprecatedTypeStr == "SELF_LUCK")
|
else if (deprecatedTypeStr == "SELF_LUCK")
|
||||||
{
|
{
|
||||||
type = Bonus::LUCK;
|
type = BonusType::LUCK;
|
||||||
val = 1;
|
val = 1;
|
||||||
valRelevant = true;
|
valRelevant = true;
|
||||||
valueType = Bonus::INDEPENDENT_MAX;
|
valueType = BonusValueType::INDEPENDENT_MAX;
|
||||||
valueTypeRelevant = true;
|
valueTypeRelevant = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -18,15 +18,15 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
struct DLL_LINKAGE BonusParams {
|
struct DLL_LINKAGE BonusParams {
|
||||||
bool isConverted;
|
bool isConverted;
|
||||||
Bonus::BonusType type = Bonus::NONE;
|
BonusType type = BonusType::NONE;
|
||||||
TBonusSubtype subtype = -1;
|
TBonusSubtype subtype = -1;
|
||||||
std::string subtypeStr;
|
std::string subtypeStr;
|
||||||
bool subtypeRelevant = false;
|
bool subtypeRelevant = false;
|
||||||
Bonus::ValueType valueType = Bonus::BASE_NUMBER;
|
BonusValueType valueType = BonusValueType::BASE_NUMBER;
|
||||||
bool valueTypeRelevant = false;
|
bool valueTypeRelevant = false;
|
||||||
si32 val = 0;
|
si32 val = 0;
|
||||||
bool valRelevant = false;
|
bool valRelevant = false;
|
||||||
Bonus::BonusSource targetType = Bonus::SECONDARY_SKILL;
|
BonusSource targetType = BonusSource::SECONDARY_SKILL;
|
||||||
bool targetTypeRelevant = false;
|
bool targetTypeRelevant = false;
|
||||||
|
|
||||||
BonusParams(bool isConverted = true) : isConverted(isConverted) {};
|
BonusParams(bool isConverted = true) : isConverted(isConverted) {};
|
||||||
|
@ -15,9 +15,9 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
namespace Selector
|
namespace Selector
|
||||||
{
|
{
|
||||||
DLL_LINKAGE CSelectFieldEqual<Bonus::BonusType> & type()
|
DLL_LINKAGE CSelectFieldEqual<BonusType> & type()
|
||||||
{
|
{
|
||||||
static CSelectFieldEqual<Bonus::BonusType> stype(&Bonus::type);
|
static CSelectFieldEqual<BonusType> stype(&Bonus::type);
|
||||||
return stype;
|
return stype;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,53 +33,53 @@ namespace Selector
|
|||||||
return sinfo;
|
return sinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & sourceType()
|
DLL_LINKAGE CSelectFieldEqual<BonusSource> & sourceType()
|
||||||
{
|
{
|
||||||
static CSelectFieldEqual<Bonus::BonusSource> ssourceType(&Bonus::source);
|
static CSelectFieldEqual<BonusSource> ssourceType(&Bonus::source);
|
||||||
return ssourceType;
|
return ssourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & targetSourceType()
|
DLL_LINKAGE CSelectFieldEqual<BonusSource> & targetSourceType()
|
||||||
{
|
{
|
||||||
static CSelectFieldEqual<Bonus::BonusSource> ssourceType(&Bonus::targetSourceType);
|
static CSelectFieldEqual<BonusSource> ssourceType(&Bonus::targetSourceType);
|
||||||
return ssourceType;
|
return ssourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> & effectRange()
|
DLL_LINKAGE CSelectFieldEqual<BonusLimitEffect> & effectRange()
|
||||||
{
|
{
|
||||||
static CSelectFieldEqual<Bonus::LimitEffect> seffectRange(&Bonus::effectRange);
|
static CSelectFieldEqual<BonusLimitEffect> seffectRange(&Bonus::effectRange);
|
||||||
return seffectRange;
|
return seffectRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE CWillLastTurns turns;
|
DLL_LINKAGE CWillLastTurns turns;
|
||||||
DLL_LINKAGE CWillLastDays days;
|
DLL_LINKAGE CWillLastDays days;
|
||||||
|
|
||||||
CSelector DLL_LINKAGE typeSubtype(Bonus::BonusType Type, TBonusSubtype Subtype)
|
CSelector DLL_LINKAGE typeSubtype(BonusType Type, TBonusSubtype Subtype)
|
||||||
{
|
{
|
||||||
return type()(Type).And(subtype()(Subtype));
|
return type()(Type).And(subtype()(Subtype));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSelector DLL_LINKAGE typeSubtypeInfo(Bonus::BonusType type, TBonusSubtype subtype, const CAddInfo & info)
|
CSelector DLL_LINKAGE typeSubtypeInfo(BonusType type, TBonusSubtype subtype, const CAddInfo & info)
|
||||||
{
|
{
|
||||||
return CSelectFieldEqual<Bonus::BonusType>(&Bonus::type)(type)
|
return CSelectFieldEqual<BonusType>(&Bonus::type)(type)
|
||||||
.And(CSelectFieldEqual<TBonusSubtype>(&Bonus::subtype)(subtype))
|
.And(CSelectFieldEqual<TBonusSubtype>(&Bonus::subtype)(subtype))
|
||||||
.And(CSelectFieldEqual<CAddInfo>(&Bonus::additionalInfo)(info));
|
.And(CSelectFieldEqual<CAddInfo>(&Bonus::additionalInfo)(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSelector DLL_LINKAGE source(Bonus::BonusSource source, ui32 sourceID)
|
CSelector DLL_LINKAGE source(BonusSource source, ui32 sourceID)
|
||||||
{
|
{
|
||||||
return CSelectFieldEqual<Bonus::BonusSource>(&Bonus::source)(source)
|
return CSelectFieldEqual<BonusSource>(&Bonus::source)(source)
|
||||||
.And(CSelectFieldEqual<ui32>(&Bonus::sid)(sourceID));
|
.And(CSelectFieldEqual<ui32>(&Bonus::sid)(sourceID));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSelector DLL_LINKAGE sourceTypeSel(Bonus::BonusSource source)
|
CSelector DLL_LINKAGE sourceTypeSel(BonusSource source)
|
||||||
{
|
{
|
||||||
return CSelectFieldEqual<Bonus::BonusSource>(&Bonus::source)(source);
|
return CSelectFieldEqual<BonusSource>(&Bonus::source)(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSelector DLL_LINKAGE valueType(Bonus::ValueType valType)
|
CSelector DLL_LINKAGE valueType(BonusValueType valType)
|
||||||
{
|
{
|
||||||
return CSelectFieldEqual<Bonus::ValueType>(&Bonus::valType)(valType);
|
return CSelectFieldEqual<BonusValueType>(&Bonus::valType)(valType);
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE CSelector all([](const Bonus * b){return true;});
|
DLL_LINKAGE CSelector all([](const Bonus * b){return true;});
|
||||||
|
@ -125,20 +125,20 @@ public:
|
|||||||
|
|
||||||
namespace Selector
|
namespace Selector
|
||||||
{
|
{
|
||||||
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusType> & type();
|
extern DLL_LINKAGE CSelectFieldEqual<BonusType> & type();
|
||||||
extern DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> & subtype();
|
extern DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> & subtype();
|
||||||
extern DLL_LINKAGE CSelectFieldEqual<CAddInfo> & info();
|
extern DLL_LINKAGE CSelectFieldEqual<CAddInfo> & info();
|
||||||
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & sourceType();
|
extern DLL_LINKAGE CSelectFieldEqual<BonusSource> & sourceType();
|
||||||
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & targetSourceType();
|
extern DLL_LINKAGE CSelectFieldEqual<BonusSource> & targetSourceType();
|
||||||
extern DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> & effectRange();
|
extern DLL_LINKAGE CSelectFieldEqual<BonusLimitEffect> & effectRange();
|
||||||
extern DLL_LINKAGE CWillLastTurns turns;
|
extern DLL_LINKAGE CWillLastTurns turns;
|
||||||
extern DLL_LINKAGE CWillLastDays days;
|
extern DLL_LINKAGE CWillLastDays days;
|
||||||
|
|
||||||
CSelector DLL_LINKAGE typeSubtype(Bonus::BonusType Type, TBonusSubtype Subtype);
|
CSelector DLL_LINKAGE typeSubtype(BonusType Type, TBonusSubtype Subtype);
|
||||||
CSelector DLL_LINKAGE typeSubtypeInfo(Bonus::BonusType type, TBonusSubtype subtype, const CAddInfo & info);
|
CSelector DLL_LINKAGE typeSubtypeInfo(BonusType type, TBonusSubtype subtype, const CAddInfo & info);
|
||||||
CSelector DLL_LINKAGE source(Bonus::BonusSource source, ui32 sourceID);
|
CSelector DLL_LINKAGE source(BonusSource source, ui32 sourceID);
|
||||||
CSelector DLL_LINKAGE sourceTypeSel(Bonus::BonusSource source);
|
CSelector DLL_LINKAGE sourceTypeSel(BonusSource source);
|
||||||
CSelector DLL_LINKAGE valueType(Bonus::ValueType valType);
|
CSelector DLL_LINKAGE valueType(BonusValueType valType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects all bonuses
|
* Selects all bonuses
|
||||||
|
@ -152,7 +152,7 @@ int CTotalsProxy::getValueAndList(TConstBonusListPtr & outBonusList) const
|
|||||||
|
|
||||||
int CTotalsProxy::getMeleeValue() const
|
int CTotalsProxy::getMeleeValue() const
|
||||||
{
|
{
|
||||||
static const auto limit = Selector::effectRange()(Bonus::NO_LIMIT).Or(Selector::effectRange()(Bonus::ONLY_MELEE_FIGHT));
|
static const auto limit = Selector::effectRange()(BonusLimitEffect::NO_LIMIT).Or(Selector::effectRange()(BonusLimitEffect::ONLY_MELEE_FIGHT));
|
||||||
|
|
||||||
const auto treeVersion = target->getTreeVersion();
|
const auto treeVersion = target->getTreeVersion();
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ int CTotalsProxy::getMeleeValue() const
|
|||||||
|
|
||||||
int CTotalsProxy::getRangedValue() const
|
int CTotalsProxy::getRangedValue() const
|
||||||
{
|
{
|
||||||
static const auto limit = Selector::effectRange()(Bonus::NO_LIMIT).Or(Selector::effectRange()(Bonus::ONLY_DISTANCE_FIGHT));
|
static const auto limit = Selector::effectRange()(BonusLimitEffect::NO_LIMIT).Or(Selector::effectRange()(BonusLimitEffect::ONLY_DISTANCE_FIGHT));
|
||||||
|
|
||||||
const auto treeVersion = target->getTreeVersion();
|
const auto treeVersion = target->getTreeVersion();
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
int IBonusBearer::valOfBonuses(Bonus::BonusType type, int subtype) const
|
int IBonusBearer::valOfBonuses(BonusType type, int 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)) + "_" + std::to_string(subtype);
|
||||||
@ -44,7 +44,7 @@ bool IBonusBearer::hasBonus(const CSelector &selector, const CSelector &limit, c
|
|||||||
return getBonuses(selector, limit, cachingStr)->size() > 0;
|
return getBonuses(selector, limit, cachingStr)->size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IBonusBearer::hasBonusOfType(Bonus::BonusType type, int subtype) const
|
bool IBonusBearer::hasBonusOfType(BonusType type, int subtype) const
|
||||||
{
|
{
|
||||||
//This part is performance-ciritcal
|
//This part is performance-ciritcal
|
||||||
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)) + "_" + std::to_string(subtype);
|
||||||
@ -66,7 +66,7 @@ TConstBonusListPtr IBonusBearer::getBonuses(const CSelector &selector, const CSe
|
|||||||
return getAllBonuses(selector, limit, nullptr, cachingStr);
|
return getAllBonuses(selector, limit, nullptr, cachingStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IBonusBearer::hasBonusFrom(Bonus::BonusSource source, ui32 sourceID) const
|
bool IBonusBearer::hasBonusFrom(BonusSource source, ui32 sourceID) const
|
||||||
{
|
{
|
||||||
boost::format fmt("source_%did_%d");
|
boost::format fmt("source_%did_%d");
|
||||||
fmt % static_cast<int>(source) % sourceID;
|
fmt % static_cast<int>(source) % sourceID;
|
||||||
|
@ -33,9 +33,9 @@ public:
|
|||||||
std::shared_ptr<const Bonus> getBonus(const CSelector &selector) const; //returns any bonus visible on node that matches (or nullptr if none matches)
|
std::shared_ptr<const Bonus> getBonus(const CSelector &selector) const; //returns any bonus visible on node that matches (or nullptr if none matches)
|
||||||
|
|
||||||
//Optimized interface (with auto-caching)
|
//Optimized interface (with auto-caching)
|
||||||
int valOfBonuses(Bonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then anyt;
|
int valOfBonuses(BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then anyt;
|
||||||
bool hasBonusOfType(Bonus::BonusType type, int subtype = -1) const;//determines if hero has a bonus of given type (and optionally subtype)
|
bool hasBonusOfType(BonusType type, int subtype = -1) const;//determines if hero has a bonus of given type (and optionally subtype)
|
||||||
bool hasBonusFrom(Bonus::BonusSource source, ui32 sourceID) const;
|
bool hasBonusFrom(BonusSource source, ui32 sourceID) const;
|
||||||
|
|
||||||
virtual int64_t getTreeVersion() const = 0;
|
virtual int64_t getTreeVersion() const = 0;
|
||||||
};
|
};
|
||||||
|
@ -30,9 +30,9 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
const std::map<std::string, TLimiterPtr> bonusLimiterMap =
|
const std::map<std::string, TLimiterPtr> bonusLimiterMap =
|
||||||
{
|
{
|
||||||
{"SHOOTER_ONLY", std::make_shared<HasAnotherBonusLimiter>(Bonus::SHOOTER)},
|
{"SHOOTER_ONLY", std::make_shared<HasAnotherBonusLimiter>(BonusType::SHOOTER)},
|
||||||
{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE)},
|
{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(BonusType::DRAGON_NATURE)},
|
||||||
{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)},
|
{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(BonusType::UNDEAD)},
|
||||||
{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()},
|
{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()},
|
||||||
{"CREATURE_FACTION", std::make_shared<AllOfLimiter>(std::initializer_list<TLimiterPtr>{std::make_shared<CreatureLevelLimiter>(), std::make_shared<FactionLimiter>()})},
|
{"CREATURE_FACTION", std::make_shared<AllOfLimiter>(std::initializer_list<TLimiterPtr>{std::make_shared<CreatureLevelLimiter>(), std::make_shared<FactionLimiter>()})},
|
||||||
{"SAME_FACTION", std::make_shared<FactionLimiter>()},
|
{"SAME_FACTION", std::make_shared<FactionLimiter>()},
|
||||||
@ -136,22 +136,22 @@ JsonNode CCreatureTypeLimiter::toJsonNode() const
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter( Bonus::BonusType bonus )
|
HasAnotherBonusLimiter::HasAnotherBonusLimiter( BonusType bonus )
|
||||||
: type(bonus), subtype(0), isSubtypeRelevant(false), isSourceRelevant(false), isSourceIDRelevant(false)
|
: type(bonus), subtype(0), isSubtypeRelevant(false), isSourceRelevant(false), isSourceIDRelevant(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter( Bonus::BonusType bonus, TBonusSubtype _subtype )
|
HasAnotherBonusLimiter::HasAnotherBonusLimiter( BonusType bonus, TBonusSubtype _subtype )
|
||||||
: type(bonus), subtype(_subtype), isSubtypeRelevant(true), isSourceRelevant(false), isSourceIDRelevant(false)
|
: type(bonus), subtype(_subtype), isSubtypeRelevant(true), isSourceRelevant(false), isSourceIDRelevant(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter(Bonus::BonusType bonus, Bonus::BonusSource src)
|
HasAnotherBonusLimiter::HasAnotherBonusLimiter(BonusType bonus, BonusSource src)
|
||||||
: type(bonus), source(src), isSubtypeRelevant(false), isSourceRelevant(true), isSourceIDRelevant(false)
|
: type(bonus), source(src), isSubtypeRelevant(false), isSourceRelevant(true), isSourceIDRelevant(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype, Bonus::BonusSource src)
|
HasAnotherBonusLimiter::HasAnotherBonusLimiter(BonusType bonus, TBonusSubtype _subtype, BonusSource src)
|
||||||
: type(bonus), subtype(_subtype), isSubtypeRelevant(true), source(src), isSourceRelevant(true), isSourceIDRelevant(false)
|
: type(bonus), subtype(_subtype), isSubtypeRelevant(true), source(src), isSourceRelevant(true), isSourceIDRelevant(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -303,10 +303,10 @@ ILimiter::EDecision FactionLimiter::limit(const BonusLimitationContext &context)
|
|||||||
|
|
||||||
switch(context.b.source)
|
switch(context.b.source)
|
||||||
{
|
{
|
||||||
case Bonus::CREATURE_ABILITY:
|
case BonusSource::CREATURE_ABILITY:
|
||||||
return bearer->getFaction() == CreatureID(context.b.sid).toCreature()->getFaction() ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
return bearer->getFaction() == CreatureID(context.b.sid).toCreature()->getFaction() ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||||
|
|
||||||
case Bonus::TOWN_STRUCTURE:
|
case BonusSource::TOWN_STRUCTURE:
|
||||||
return bearer->getFaction() == FactionID(Bonus::getHighFromSid32(context.b.sid)) ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
return bearer->getFaction() == FactionID(Bonus::getHighFromSid32(context.b.sid)) ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||||
|
|
||||||
//TODO: other sources of bonuses
|
//TODO: other sources of bonuses
|
||||||
|
@ -111,18 +111,18 @@ public:
|
|||||||
class DLL_LINKAGE HasAnotherBonusLimiter : public ILimiter //applies only to nodes that have another bonus working
|
class DLL_LINKAGE HasAnotherBonusLimiter : public ILimiter //applies only to nodes that have another bonus working
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Bonus::BonusType type;
|
BonusType type;
|
||||||
TBonusSubtype subtype;
|
TBonusSubtype subtype;
|
||||||
Bonus::BonusSource source;
|
BonusSource source;
|
||||||
si32 sid;
|
si32 sid;
|
||||||
bool isSubtypeRelevant; //check for subtype only if this is true
|
bool isSubtypeRelevant; //check for subtype only if this is true
|
||||||
bool isSourceRelevant; //check for bonus source only if this is true
|
bool isSourceRelevant; //check for bonus source only if this is true
|
||||||
bool isSourceIDRelevant; //check for bonus source only if this is true
|
bool isSourceIDRelevant; //check for bonus source only if this is true
|
||||||
|
|
||||||
HasAnotherBonusLimiter(Bonus::BonusType bonus = Bonus::NONE);
|
HasAnotherBonusLimiter(BonusType bonus = BonusType::NONE);
|
||||||
HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype);
|
HasAnotherBonusLimiter(BonusType bonus, TBonusSubtype _subtype);
|
||||||
HasAnotherBonusLimiter(Bonus::BonusType bonus, Bonus::BonusSource src);
|
HasAnotherBonusLimiter(BonusType bonus, BonusSource src);
|
||||||
HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype, Bonus::BonusSource src);
|
HasAnotherBonusLimiter(BonusType bonus, TBonusSubtype _subtype, BonusSource src);
|
||||||
|
|
||||||
EDecision limit(const BonusLimitationContext &context) const override;
|
EDecision limit(const BonusLimitationContext &context) const override;
|
||||||
std::string toString() const override;
|
std::string toString() const override;
|
||||||
|
@ -118,17 +118,17 @@ ArmyMovementUpdater::ArmyMovementUpdater(int base, int divider, int multiplier,
|
|||||||
|
|
||||||
std::shared_ptr<Bonus> ArmyMovementUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const
|
std::shared_ptr<Bonus> ArmyMovementUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const
|
||||||
{
|
{
|
||||||
if(b->type == Bonus::MOVEMENT && context.getNodeType() == CBonusSystemNode::HERO)
|
if(b->type == BonusType::MOVEMENT && context.getNodeType() == CBonusSystemNode::HERO)
|
||||||
{
|
{
|
||||||
auto speed = static_cast<const CGHeroInstance &>(context).getLowestCreatureSpeed();
|
auto speed = static_cast<const CGHeroInstance &>(context).getLowestCreatureSpeed();
|
||||||
si32 armySpeed = speed * base / divider;
|
si32 armySpeed = speed * base / divider;
|
||||||
auto counted = armySpeed * multiplier;
|
auto counted = armySpeed * multiplier;
|
||||||
auto newBonus = std::make_shared<Bonus>(*b);
|
auto newBonus = std::make_shared<Bonus>(*b);
|
||||||
newBonus->source = Bonus::ARMY;
|
newBonus->source = BonusSource::ARMY;
|
||||||
newBonus->val += vstd::amin(counted, max);
|
newBonus->val += vstd::amin(counted, max);
|
||||||
return newBonus;
|
return newBonus;
|
||||||
}
|
}
|
||||||
if(b->type != Bonus::MOVEMENT)
|
if(b->type != BonusType::MOVEMENT)
|
||||||
logGlobal->error("ArmyMovementUpdater should only be used for MOVEMENT bonus!");
|
logGlobal->error("ArmyMovementUpdater should only be used for MOVEMENT bonus!");
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ std::shared_ptr<Bonus> OwnerUpdater::createUpdatedBonus(const std::shared_ptr<Bo
|
|||||||
owner = PlayerColor::NEUTRAL;
|
owner = PlayerColor::NEUTRAL;
|
||||||
|
|
||||||
std::shared_ptr<Bonus> updated =
|
std::shared_ptr<Bonus> updated =
|
||||||
std::make_shared<Bonus>(static_cast<Bonus::BonusDuration>(b->duration), b->type, b->source, b->val, b->sid, b->subtype, b->valType);
|
std::make_shared<Bonus>(b->duration, b->type, b->source, b->val, b->sid, b->subtype, b->valType);
|
||||||
updated->limiter = std::make_shared<OppositeSideLimiter>(owner);
|
updated->limiter = std::make_shared<OppositeSideLimiter>(owner);
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ void CArmedInstance::randomizeArmy(int type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Take Angelic Alliance troop-mixing freedom of non-evil units into account.
|
// Take Angelic Alliance troop-mixing freedom of non-evil units into account.
|
||||||
CSelector CArmedInstance::nonEvilAlignmentMixSelector = Selector::type()(Bonus::NONEVIL_ALIGNMENT_MIX);
|
CSelector CArmedInstance::nonEvilAlignmentMixSelector = Selector::type()(BonusType::NONEVIL_ALIGNMENT_MIX);
|
||||||
|
|
||||||
CArmedInstance::CArmedInstance()
|
CArmedInstance::CArmedInstance()
|
||||||
:CArmedInstance(false)
|
:CArmedInstance(false)
|
||||||
@ -56,10 +56,10 @@ void CArmedInstance::updateMoraleBonusFromArmy()
|
|||||||
if(!validTypes(false)) //object not randomized, don't bother
|
if(!validTypes(false)) //object not randomized, don't bother
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto b = getExportedBonusList().getFirst(Selector::sourceType()(Bonus::ARMY).And(Selector::type()(Bonus::MORALE)));
|
auto b = getExportedBonusList().getFirst(Selector::sourceType()(BonusSource::ARMY).And(Selector::type()(BonusType::MORALE)));
|
||||||
if(!b)
|
if(!b)
|
||||||
{
|
{
|
||||||
b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
|
b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, 0, -1);
|
||||||
addNewBonus(b);
|
addNewBonus(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
|
|||||||
bool hasUndead = false;
|
bool hasUndead = false;
|
||||||
|
|
||||||
const std::string undeadCacheKey = "type_UNDEAD";
|
const std::string undeadCacheKey = "type_UNDEAD";
|
||||||
static const CSelector undeadSelector = Selector::type()(Bonus::UNDEAD);
|
static const CSelector undeadSelector = Selector::type()(BonusType::UNDEAD);
|
||||||
|
|
||||||
for(const auto & slot : Slots())
|
for(const auto & slot : Slots())
|
||||||
{
|
{
|
||||||
@ -121,12 +121,12 @@ void CArmedInstance::updateMoraleBonusFromArmy()
|
|||||||
|
|
||||||
//-1 modifier for any Undead unit in army
|
//-1 modifier for any Undead unit in army
|
||||||
const ui8 UNDEAD_MODIFIER_ID = -2;
|
const ui8 UNDEAD_MODIFIER_ID = -2;
|
||||||
auto undeadModifier = getExportedBonusList().getFirst(Selector::source(Bonus::ARMY, UNDEAD_MODIFIER_ID));
|
auto undeadModifier = getExportedBonusList().getFirst(Selector::source(BonusSource::ARMY, UNDEAD_MODIFIER_ID));
|
||||||
if(hasUndead)
|
if(hasUndead)
|
||||||
{
|
{
|
||||||
if(!undeadModifier)
|
if(!undeadModifier)
|
||||||
{
|
{
|
||||||
undeadModifier = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, -1, UNDEAD_MODIFIER_ID, VLC->generaltexth->arraytxt[116]);
|
undeadModifier = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, -1, UNDEAD_MODIFIER_ID, VLC->generaltexth->arraytxt[116]);
|
||||||
undeadModifier->description = undeadModifier->description.substr(0, undeadModifier->description.size()-2);//trim value
|
undeadModifier->description = undeadModifier->description.substr(0, undeadModifier->description.size()-2);//trim value
|
||||||
addNewBonus(undeadModifier);
|
addNewBonus(undeadModifier);
|
||||||
}
|
}
|
||||||
|
@ -169,10 +169,10 @@ void CBank::doVisit(const CGHeroInstance * hero) const
|
|||||||
{
|
{
|
||||||
GiveBonus gbonus;
|
GiveBonus gbonus;
|
||||||
gbonus.id = hero->id.getNum();
|
gbonus.id = hero->id.getNum();
|
||||||
gbonus.bonus.duration = Bonus::ONE_BATTLE;
|
gbonus.bonus.duration = BonusDuration::ONE_BATTLE;
|
||||||
gbonus.bonus.source = Bonus::OBJECT;
|
gbonus.bonus.source = BonusSource::OBJECT;
|
||||||
gbonus.bonus.sid = ID;
|
gbonus.bonus.sid = ID;
|
||||||
gbonus.bonus.type = Bonus::MORALE;
|
gbonus.bonus.type = BonusType::MORALE;
|
||||||
gbonus.bonus.val = -1;
|
gbonus.bonus.val = -1;
|
||||||
switch (ID)
|
switch (ID)
|
||||||
{
|
{
|
||||||
@ -197,7 +197,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const
|
|||||||
case Obj::PYRAMID:
|
case Obj::PYRAMID:
|
||||||
{
|
{
|
||||||
GiveBonus gb;
|
GiveBonus gb;
|
||||||
gb.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::LUCK, Bonus::OBJECT, -2, id.getNum(), VLC->generaltexth->arraytxt[70]);
|
gb.bonus = Bonus(BonusDuration::ONE_BATTLE, BonusType::LUCK, BonusSource::OBJECT, -2, id.getNum(), VLC->generaltexth->arraytxt[70]);
|
||||||
gb.id = hero->id.getNum();
|
gb.id = hero->id.getNum();
|
||||||
cb->giveHeroBonus(&gb);
|
cb->giveHeroBonus(&gb);
|
||||||
textID = 107;
|
textID = 107;
|
||||||
|
@ -253,7 +253,7 @@ void CGDwelling::newTurn(CRandomGenerator & rand) const
|
|||||||
creaturesAccumulate = VLC->settings()->getBoolean(EGameSettings::DWELLINGS_ACCUMULATE_WHEN_NEUTRAL);
|
creaturesAccumulate = VLC->settings()->getBoolean(EGameSettings::DWELLINGS_ACCUMULATE_WHEN_NEUTRAL);
|
||||||
|
|
||||||
CCreature *cre = VLC->creh->objects[creatures[i].second[0]];
|
CCreature *cre = VLC->creh->objects[creatures[i].second[0]];
|
||||||
TQuantity amount = cre->getGrowth() * (1 + cre->valOfBonuses(Bonus::CREATURE_GROWTH_PERCENT)/100) + cre->valOfBonuses(Bonus::CREATURE_GROWTH);
|
TQuantity amount = cre->getGrowth() * (1 + cre->valOfBonuses(BonusType::CREATURE_GROWTH_PERCENT)/100) + cre->valOfBonuses(BonusType::CREATURE_GROWTH);
|
||||||
if (creaturesAccumulate && ID != Obj::REFUGEE_CAMP) //camp should not try to accumulate different kinds of creatures
|
if (creaturesAccumulate && ID != Obj::REFUGEE_CAMP) //camp should not try to accumulate different kinds of creatures
|
||||||
sac.creatures[i].first += amount;
|
sac.creatures[i].first += amount;
|
||||||
else
|
else
|
||||||
|
@ -39,8 +39,8 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
static int lowestSpeed(const CGHeroInstance * chi)
|
static int lowestSpeed(const CGHeroInstance * chi)
|
||||||
{
|
{
|
||||||
static const CSelector selectorSTACKS_SPEED = Selector::type()(Bonus::STACKS_SPEED);
|
static const CSelector selectorSTACKS_SPEED = Selector::type()(BonusType::STACKS_SPEED);
|
||||||
static const std::string keySTACKS_SPEED = "type_" + std::to_string(static_cast<si32>(Bonus::STACKS_SPEED));
|
static const std::string keySTACKS_SPEED = "type_" + std::to_string(static_cast<si32>(BonusType::STACKS_SPEED));
|
||||||
|
|
||||||
if(!chi->stacksCount())
|
if(!chi->stacksCount())
|
||||||
{
|
{
|
||||||
@ -73,11 +73,11 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile & dest, const TerrainTile & f
|
|||||||
}
|
}
|
||||||
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(Bonus::NO_TERRAIN_PENALTY, from.terType->getIndex())) //no special movement bonus
|
!ti->hasBonusOfType(BonusType::NO_TERRAIN_PENALTY, from.terType->getIndex())) //no special movement bonus
|
||||||
{
|
{
|
||||||
|
|
||||||
ret = VLC->terrainTypeHandler->getById(dest.terType->getId())->moveCost;
|
ret = VLC->terrainTypeHandler->getById(dest.terType->getId())->moveCost;
|
||||||
ret -= ti->valOfBonuses(Bonus::ROUGH_TERRAIN_DISCOUNT);
|
ret -= ti->valOfBonuses(BonusType::ROUGH_TERRAIN_DISCOUNT);
|
||||||
if(ret < GameConstants::BASE_MOVEMENT_COST)
|
if(ret < GameConstants::BASE_MOVEMENT_COST)
|
||||||
ret = GameConstants::BASE_MOVEMENT_COST;
|
ret = GameConstants::BASE_MOVEMENT_COST;
|
||||||
}
|
}
|
||||||
@ -212,14 +212,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(Bonus::MOVEMENT, Selector::subtype()(!!onLand));
|
ti->updateHeroBonuses(BonusType::MOVEMENT, Selector::subtype()(!!onLand));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CGHeroInstance::maxMovePointsCached(bool onLand, const TurnInfo * ti) const
|
int CGHeroInstance::maxMovePointsCached(bool onLand, const TurnInfo * ti) const
|
||||||
{
|
{
|
||||||
updateArmyMovementBonus(onLand, ti);
|
updateArmyMovementBonus(onLand, ti);
|
||||||
return ti->valOfBonuses(Bonus::MOVEMENT, !!onLand);
|
return ti->valOfBonuses(BonusType::MOVEMENT, !!onLand);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGHeroInstance::CGHeroInstance():
|
CGHeroInstance::CGHeroInstance():
|
||||||
@ -286,7 +286,7 @@ void CGHeroInstance::initHero(CRandomGenerator & rand)
|
|||||||
|
|
||||||
if(portrait < 0 || portrait == 255)
|
if(portrait < 0 || portrait == 255)
|
||||||
portrait = type->imageIndex;
|
portrait = type->imageIndex;
|
||||||
if(!hasBonus(Selector::sourceType()(Bonus::HERO_BASE_SKILL)))
|
if(!hasBonus(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)))
|
||||||
{
|
{
|
||||||
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
|
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
|
||||||
{
|
{
|
||||||
@ -327,9 +327,9 @@ void CGHeroInstance::initHero(CRandomGenerator & rand)
|
|||||||
for(const auto & b : baseBonuses.Struct())
|
for(const auto & b : baseBonuses.Struct())
|
||||||
{
|
{
|
||||||
auto bonus = JsonUtils::parseBonus(b.second);
|
auto bonus = JsonUtils::parseBonus(b.second);
|
||||||
bonus->source = Bonus::HERO_BASE_SKILL;
|
bonus->source = BonusSource::HERO_BASE_SKILL;
|
||||||
bonus->sid = id.getNum();
|
bonus->sid = id.getNum();
|
||||||
bonus->duration = Bonus::PERMANENT;
|
bonus->duration = BonusDuration::PERMANENT;
|
||||||
addNewBonus(bonus);
|
addNewBonus(bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,7 +529,7 @@ void CGHeroInstance::initObj(CRandomGenerator & rand)
|
|||||||
|
|
||||||
void CGHeroInstance::recreateSecondarySkillsBonuses()
|
void CGHeroInstance::recreateSecondarySkillsBonuses()
|
||||||
{
|
{
|
||||||
auto secondarySkillsBonuses = getBonuses(Selector::sourceType()(Bonus::SECONDARY_SKILL));
|
auto secondarySkillsBonuses = getBonuses(Selector::sourceType()(BonusSource::SECONDARY_SKILL));
|
||||||
for(const auto & bonus : *secondarySkillsBonuses)
|
for(const auto & bonus : *secondarySkillsBonuses)
|
||||||
removeBonus(bonus);
|
removeBonus(bonus);
|
||||||
|
|
||||||
@ -540,7 +540,7 @@ void CGHeroInstance::recreateSecondarySkillsBonuses()
|
|||||||
|
|
||||||
void CGHeroInstance::updateSkillBonus(const SecondarySkill & which, int val)
|
void CGHeroInstance::updateSkillBonus(const SecondarySkill & which, int val)
|
||||||
{
|
{
|
||||||
removeBonuses(Selector::source(Bonus::SECONDARY_SKILL, which));
|
removeBonuses(Selector::source(BonusSource::SECONDARY_SKILL, which));
|
||||||
auto skillBonus = (*VLC->skillh)[which]->at(val).effects;
|
auto skillBonus = (*VLC->skillh)[which]->at(val).effects;
|
||||||
for(const auto & b : skillBonus)
|
for(const auto & b : skillBonus)
|
||||||
addNewBonus(std::make_shared<Bonus>(*b));
|
addNewBonus(std::make_shared<Bonus>(*b));
|
||||||
@ -575,7 +575,7 @@ ui64 CGHeroInstance::getTotalStrength() const
|
|||||||
|
|
||||||
TExpType CGHeroInstance::calculateXp(TExpType exp) const
|
TExpType CGHeroInstance::calculateXp(TExpType exp) const
|
||||||
{
|
{
|
||||||
return static_cast<TExpType>(exp * (valOfBonuses(Bonus::HERO_EXPERIENCE_GAIN_PERCENT)) / 100.0);
|
return static_cast<TExpType>(exp * (valOfBonuses(BonusType::HERO_EXPERIENCE_GAIN_PERCENT)) / 100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CGHeroInstance::getCasterUnitId() const
|
int32_t CGHeroInstance::getCasterUnitId() const
|
||||||
@ -589,7 +589,7 @@ int32_t CGHeroInstance::getSpellSchoolLevel(const spells::Spell * spell, int32_t
|
|||||||
|
|
||||||
spell->forEachSchool([&, this](const spells::SchoolInfo & cnf, bool & stop)
|
spell->forEachSchool([&, this](const spells::SchoolInfo & cnf, bool & stop)
|
||||||
{
|
{
|
||||||
int32_t thisSchool = valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 1 << (static_cast<ui8>(cnf.id))); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies)
|
int32_t thisSchool = valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, 1 << (static_cast<ui8>(cnf.id))); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies)
|
||||||
if(thisSchool > skill)
|
if(thisSchool > skill)
|
||||||
{
|
{
|
||||||
skill = thisSchool;
|
skill = thisSchool;
|
||||||
@ -598,8 +598,8 @@ int32_t CGHeroInstance::getSpellSchoolLevel(const spells::Spell * spell, int32_t
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
vstd::amax(skill, valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 0)); //any school bonus
|
vstd::amax(skill, valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, 0)); //any school bonus
|
||||||
vstd::amax(skill, valOfBonuses(Bonus::SPELL, spell->getIndex())); //given by artifact or other effect
|
vstd::amax(skill, valOfBonuses(BonusType::SPELL, spell->getIndex())); //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);
|
||||||
@ -611,9 +611,9 @@ 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(Bonus::SPELL_DAMAGE)) / 100.0);
|
base = static_cast<int64_t>(base * (valOfBonuses(BonusType::SPELL_DAMAGE)) / 100.0);
|
||||||
|
|
||||||
base = static_cast<int64_t>(base * (100 + valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, spell->getIndex())) / 100.0);
|
base = static_cast<int64_t>(base * (100 + valOfBonuses(BonusType::SPECIFIC_SPELL_DAMAGE, spell->getIndex())) / 100.0);
|
||||||
|
|
||||||
int maxSchoolBonus = 0;
|
int maxSchoolBonus = 0;
|
||||||
|
|
||||||
@ -625,14 +625,14 @@ int64_t CGHeroInstance::getSpellBonus(const spells::Spell * spell, int64_t base,
|
|||||||
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(Bonus::SPECIAL_SPELL_LEV, spell->getIndex()) / affectedStack->creatureLevel()) / 100.0);
|
base = static_cast<int64_t>(base * static_cast<double>(100 + valOfBonuses(BonusType::SPECIAL_SPELL_LEV, spell->getIndex()) / 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(Bonus::SPECIFIC_SPELL_DAMAGE, spell->getIndex())) / 100.0);
|
base = static_cast<int64_t>(base * (100 + valOfBonuses(BonusType::SPECIFIC_SPELL_DAMAGE, spell->getIndex())) / 100.0);
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,7 +648,7 @@ int32_t CGHeroInstance::getEffectPower(const spells::Spell * spell) const
|
|||||||
|
|
||||||
int32_t CGHeroInstance::getEnchantPower(const spells::Spell * spell) const
|
int32_t CGHeroInstance::getEnchantPower(const spells::Spell * spell) const
|
||||||
{
|
{
|
||||||
return getPrimSkillLevel(PrimarySkill::SPELL_POWER) + valOfBonuses(Bonus::SPELL_DURATION);
|
return getPrimSkillLevel(PrimarySkill::SPELL_POWER) + valOfBonuses(BonusType::SPELL_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t CGHeroInstance::getEffectValue(const spells::Spell * spell) const
|
int64_t CGHeroInstance::getEffectValue(const spells::Spell * spell) const
|
||||||
@ -702,7 +702,7 @@ 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(Bonus::SPELL, spell->getIndex());
|
const bool specificBonus = hasBonusOfType(BonusType::SPELL, spell->getIndex());
|
||||||
|
|
||||||
bool schoolBonus = false;
|
bool schoolBonus = false;
|
||||||
|
|
||||||
@ -714,7 +714,7 @@ bool CGHeroInstance::canCastThisSpell(const spells::Spell * spell) const
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const bool levelBonus = hasBonusOfType(Bonus::SPELLS_OF_LEVEL, spell->getLevel());
|
const bool levelBonus = hasBonusOfType(BonusType::SPELLS_OF_LEVEL, spell->getLevel());
|
||||||
|
|
||||||
if(spell->isSpecial())
|
if(spell->isSpecial())
|
||||||
{
|
{
|
||||||
@ -781,19 +781,19 @@ bool CGHeroInstance::canLearnSpell(const spells::Spell * spell) const
|
|||||||
*/
|
*/
|
||||||
CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &battleResult) const
|
CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &battleResult) const
|
||||||
{
|
{
|
||||||
bool hasImprovedNecromancy = hasBonusOfType(Bonus::IMPROVED_NECROMANCY);
|
bool hasImprovedNecromancy = hasBonusOfType(BonusType::IMPROVED_NECROMANCY);
|
||||||
|
|
||||||
// need skill or cloak of undead king - lesser artifacts don't work without skill
|
// need skill or cloak of undead king - lesser artifacts don't work without skill
|
||||||
if (hasImprovedNecromancy)
|
if (hasImprovedNecromancy)
|
||||||
{
|
{
|
||||||
double necromancySkill = valOfBonuses(Bonus::UNDEAD_RAISE_PERCENTAGE) / 100.0;
|
double necromancySkill = valOfBonuses(BonusType::UNDEAD_RAISE_PERCENTAGE) / 100.0;
|
||||||
const ui8 necromancyLevel = valOfBonuses(Bonus::IMPROVED_NECROMANCY);
|
const ui8 necromancyLevel = valOfBonuses(BonusType::IMPROVED_NECROMANCY);
|
||||||
vstd::amin(necromancySkill, 1.0); //it's impossible to raise more creatures than all...
|
vstd::amin(necromancySkill, 1.0); //it's impossible to raise more creatures than all...
|
||||||
const std::map<ui32,si32> &casualties = battleResult.casualties[!battleResult.winner];
|
const std::map<ui32,si32> &casualties = battleResult.casualties[!battleResult.winner];
|
||||||
// figure out what to raise - pick strongest creature meeting requirements
|
// figure out what to raise - pick strongest creature meeting requirements
|
||||||
auto creatureTypeRaised = CreatureID::NONE; //now we always have IMPROVED_NECROMANCY, no need for hardcode
|
auto creatureTypeRaised = CreatureID::NONE; //now we always have IMPROVED_NECROMANCY, no need for hardcode
|
||||||
int requiredCasualtyLevel = 1;
|
int requiredCasualtyLevel = 1;
|
||||||
TConstBonusListPtr improvedNecromancy = getBonuses(Selector::type()(Bonus::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
|
auto getCreatureID = [](const std::shared_ptr<Bonus> & bonus) -> CreatureID
|
||||||
@ -899,15 +899,15 @@ int3 CGHeroInstance::getSightCenter() const
|
|||||||
|
|
||||||
int CGHeroInstance::getSightRadius() const
|
int CGHeroInstance::getSightRadius() const
|
||||||
{
|
{
|
||||||
return valOfBonuses(Bonus::SIGHT_RADIUS); // scouting gives SIGHT_RADIUS bonus
|
return valOfBonuses(BonusType::SIGHT_RADIUS); // scouting gives SIGHT_RADIUS bonus
|
||||||
}
|
}
|
||||||
|
|
||||||
si32 CGHeroInstance::manaRegain() const
|
si32 CGHeroInstance::manaRegain() const
|
||||||
{
|
{
|
||||||
if (hasBonusOfType(Bonus::FULL_MANA_REGENERATION))
|
if (hasBonusOfType(BonusType::FULL_MANA_REGENERATION))
|
||||||
return manaLimit();
|
return manaLimit();
|
||||||
|
|
||||||
return valOfBonuses(Bonus::MANA_REGENERATION);
|
return valOfBonuses(BonusType::MANA_REGENERATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
si32 CGHeroInstance::getManaNewTurn() const
|
si32 CGHeroInstance::getManaNewTurn() const
|
||||||
@ -963,9 +963,9 @@ int32_t CGHeroInstance::getSpellCost(const spells::Spell * sp) const
|
|||||||
|
|
||||||
void CGHeroInstance::pushPrimSkill( PrimarySkill::PrimarySkill which, int val )
|
void CGHeroInstance::pushPrimSkill( PrimarySkill::PrimarySkill which, int val )
|
||||||
{
|
{
|
||||||
assert(!hasBonus(Selector::typeSubtype(Bonus::PRIMARY_SKILL, which)
|
assert(!hasBonus(Selector::typeSubtype(BonusType::PRIMARY_SKILL, which)
|
||||||
.And(Selector::sourceType()(Bonus::HERO_BASE_SKILL))));
|
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL))));
|
||||||
addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::HERO_BASE_SKILL, val, id.getNum(), which));
|
addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::HERO_BASE_SKILL, val, id.getNum(), which));
|
||||||
}
|
}
|
||||||
|
|
||||||
EAlignment CGHeroInstance::getAlignment() const
|
EAlignment CGHeroInstance::getAlignment() const
|
||||||
@ -986,7 +986,7 @@ std::string CGHeroInstance::nodeName() const
|
|||||||
si32 CGHeroInstance::manaLimit() const
|
si32 CGHeroInstance::manaLimit() const
|
||||||
{
|
{
|
||||||
return si32(getPrimSkillLevel(PrimarySkill::KNOWLEDGE)
|
return si32(getPrimSkillLevel(PrimarySkill::KNOWLEDGE)
|
||||||
* (valOfBonuses(Bonus::MANA_PER_KNOWLEDGE)));
|
* (valOfBonuses(BonusType::MANA_PER_KNOWLEDGE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CGHeroInstance::getNameTranslated() const
|
std::string CGHeroInstance::getNameTranslated() const
|
||||||
@ -1070,7 +1070,7 @@ const std::set<SpellID> & CGHeroInstance::getSpellsInSpellbook() const
|
|||||||
|
|
||||||
int CGHeroInstance::maxSpellLevel() const
|
int CGHeroInstance::maxSpellLevel() const
|
||||||
{
|
{
|
||||||
return std::min(GameConstants::SPELL_LEVELS, valOfBonuses(Selector::type()(Bonus::MAX_LEARNABLE_SPELL_LEVEL)));
|
return std::min(GameConstants::SPELL_LEVELS, valOfBonuses(Selector::type()(BonusType::MAX_LEARNABLE_SPELL_LEVEL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGHeroInstance::deserializationFix()
|
void CGHeroInstance::deserializationFix()
|
||||||
@ -1118,7 +1118,7 @@ int CGHeroInstance::movementPointsAfterEmbark(int MPsBefore, int basicCost, bool
|
|||||||
ti = turnInfoLocal.get();
|
ti = turnInfoLocal.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ti->hasBonusOfType(Bonus::FREE_SHIP_BOARDING))
|
if(!ti->hasBonusOfType(BonusType::FREE_SHIP_BOARDING))
|
||||||
return 0; // take all MPs by default
|
return 0; // take all MPs by default
|
||||||
|
|
||||||
auto boatLayer = boat ? boat->layer : EPathfindingLayer::SAIL;
|
auto boatLayer = boat ? boat->layer : EPathfindingLayer::SAIL;
|
||||||
@ -1313,9 +1313,9 @@ void CGHeroInstance::setPrimarySkill(PrimarySkill::PrimarySkill primarySkill, si
|
|||||||
{
|
{
|
||||||
if(primarySkill < PrimarySkill::EXPERIENCE)
|
if(primarySkill < PrimarySkill::EXPERIENCE)
|
||||||
{
|
{
|
||||||
auto skill = getBonusLocalFirst(Selector::type()(Bonus::PRIMARY_SKILL)
|
auto skill = getBonusLocalFirst(Selector::type()(BonusType::PRIMARY_SKILL)
|
||||||
.And(Selector::subtype()(primarySkill))
|
.And(Selector::subtype()(primarySkill))
|
||||||
.And(Selector::sourceType()(Bonus::HERO_BASE_SKILL)));
|
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
|
||||||
assert(skill);
|
assert(skill);
|
||||||
|
|
||||||
if(abs)
|
if(abs)
|
||||||
@ -1389,9 +1389,9 @@ bool CGHeroInstance::hasVisions(const CGObjectInstance * target, const int subty
|
|||||||
{
|
{
|
||||||
//VISIONS spell support
|
//VISIONS spell support
|
||||||
|
|
||||||
const std::string cached = boost::to_string((boost::format("type_%d__subtype_%d") % Bonus::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(Bonus::VISIONS,subtype), cached);
|
const int visionsMultiplier = valOfBonuses(Selector::typeSubtype(BonusType::VISIONS,subtype), cached);
|
||||||
|
|
||||||
int visionsRange = visionsMultiplier * getPrimSkillLevel(PrimarySkill::SPELL_POWER);
|
int visionsRange = visionsMultiplier * getPrimSkillLevel(PrimarySkill::SPELL_POWER);
|
||||||
|
|
||||||
@ -1505,7 +1505,7 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
|
|||||||
//primary skills
|
//primary skills
|
||||||
if(handler.saving)
|
if(handler.saving)
|
||||||
{
|
{
|
||||||
const bool haveSkills = hasBonus(Selector::type()(Bonus::PRIMARY_SKILL).And(Selector::sourceType()(Bonus::HERO_BASE_SKILL)));
|
const bool haveSkills = hasBonus(Selector::type()(BonusType::PRIMARY_SKILL).And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
|
||||||
|
|
||||||
if(haveSkills)
|
if(haveSkills)
|
||||||
{
|
{
|
||||||
@ -1513,7 +1513,7 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
|
|||||||
|
|
||||||
for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i)
|
for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i)
|
||||||
{
|
{
|
||||||
int value = valOfBonuses(Selector::typeSubtype(Bonus::PRIMARY_SKILL, i).And(Selector::sourceType()(Bonus::HERO_BASE_SKILL)));
|
int value = valOfBonuses(Selector::typeSubtype(BonusType::PRIMARY_SKILL, i).And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
|
||||||
|
|
||||||
handler.serializeInt(PrimarySkill::names[i], value, 0);
|
handler.serializeInt(PrimarySkill::names[i], value, 0);
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ void CGPandoraBox::giveContentsAfterExp(const CGHeroInstance *h) const
|
|||||||
iw.components.emplace_back(Component::EComponentType::MORALE, 0, moraleDiff, 0);
|
iw.components.emplace_back(Component::EComponentType::MORALE, 0, moraleDiff, 0);
|
||||||
cb->showInfoDialog(&iw);
|
cb->showInfoDialog(&iw);
|
||||||
GiveBonus gb;
|
GiveBonus gb;
|
||||||
gb.bonus = Bonus(Bonus::ONE_BATTLE,Bonus::MORALE,Bonus::OBJECT,moraleDiff,id.getNum(),"");
|
gb.bonus = Bonus(BonusDuration::ONE_BATTLE,BonusType::MORALE,BonusSource::OBJECT,moraleDiff,id.getNum(),"");
|
||||||
gb.id = h->id.getNum();
|
gb.id = h->id.getNum();
|
||||||
cb->giveHeroBonus(&gb);
|
cb->giveHeroBonus(&gb);
|
||||||
}
|
}
|
||||||
@ -194,7 +194,7 @@ void CGPandoraBox::giveContentsAfterExp(const CGHeroInstance *h) const
|
|||||||
iw.components.emplace_back(Component::EComponentType::LUCK, 0, luckDiff, 0);
|
iw.components.emplace_back(Component::EComponentType::LUCK, 0, luckDiff, 0);
|
||||||
cb->showInfoDialog(&iw);
|
cb->showInfoDialog(&iw);
|
||||||
GiveBonus gb;
|
GiveBonus gb;
|
||||||
gb.bonus = Bonus(Bonus::ONE_BATTLE,Bonus::LUCK,Bonus::OBJECT,luckDiff,id.getNum(),"");
|
gb.bonus = Bonus(BonusDuration::ONE_BATTLE,BonusType::LUCK,BonusSource::OBJECT,luckDiff,id.getNum(),"");
|
||||||
gb.id = h->id.getNum();
|
gb.id = h->id.getNum();
|
||||||
cb->giveHeroBonus(&gb);
|
cb->giveHeroBonus(&gb);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ std::string CGTownBuilding::getVisitingBonusGreeting() const
|
|||||||
|
|
||||||
std::string CGTownBuilding::getCustomBonusGreeting(const Bonus & bonus) const
|
std::string CGTownBuilding::getCustomBonusGreeting(const Bonus & bonus) const
|
||||||
{
|
{
|
||||||
if(bonus.type == Bonus::TOWN_MAGIC_WELL)
|
if(bonus.type == BonusType::TOWN_MAGIC_WELL)
|
||||||
{
|
{
|
||||||
auto bonusGreeting = std::string(VLC->generaltexth->translate("vcmi.townHall.greetingInTownMagicWell"));
|
auto bonusGreeting = std::string(VLC->generaltexth->translate("vcmi.townHall.greetingInTownMagicWell"));
|
||||||
auto buildingName = town->getTown()->getSpecialBuilding(bType)->getNameTranslated();
|
auto buildingName = town->getTown()->getSpecialBuilding(bType)->getNameTranslated();
|
||||||
@ -95,12 +95,12 @@ std::string CGTownBuilding::getCustomBonusGreeting(const Bonus & bonus) const
|
|||||||
std::string param;
|
std::string param;
|
||||||
std::string until;
|
std::string until;
|
||||||
|
|
||||||
if(bonus.type == Bonus::MORALE)
|
if(bonus.type == BonusType::MORALE)
|
||||||
param = VLC->generaltexth->allTexts[384];
|
param = VLC->generaltexth->allTexts[384];
|
||||||
else if(bonus.type == Bonus::LUCK)
|
else if(bonus.type == BonusType::LUCK)
|
||||||
param = VLC->generaltexth->allTexts[385];
|
param = VLC->generaltexth->allTexts[385];
|
||||||
|
|
||||||
until = bonus.duration == static_cast<ui16>(Bonus::ONE_BATTLE)
|
until = bonus.duration == BonusDuration::ONE_BATTLE
|
||||||
? VLC->generaltexth->translate("vcmi.townHall.greetingCustomUntil")
|
? VLC->generaltexth->translate("vcmi.townHall.greetingCustomUntil")
|
||||||
: ".";
|
: ".";
|
||||||
|
|
||||||
@ -142,10 +142,10 @@ void COPWBonus::onHeroVisit (const CGHeroInstance * h) const
|
|||||||
switch (this->bType)
|
switch (this->bType)
|
||||||
{
|
{
|
||||||
case BuildingSubID::STABLES:
|
case BuildingSubID::STABLES:
|
||||||
if(!h->hasBonusFrom(Bonus::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(Bonus::ONE_WEEK, Bonus::MOVEMENT, Bonus::OBJECT, 600, 94, VLC->generaltexth->arraytxt[100], 1);
|
gb.bonus = Bonus(BonusDuration::ONE_WEEK, BonusType::MOVEMENT, BonusSource::OBJECT, 600, 94, VLC->generaltexth->arraytxt[100], 1);
|
||||||
gb.id = heroID.getNum();
|
gb.id = heroID.getNum();
|
||||||
cb->giveHeroBonus(&gb);
|
cb->giveHeroBonus(&gb);
|
||||||
|
|
||||||
@ -234,7 +234,7 @@ void CTownBonus::onHeroVisit (const CGHeroInstance * h) const
|
|||||||
|
|
||||||
case BuildingSubID::CUSTOM_VISITING_BONUS:
|
case BuildingSubID::CUSTOM_VISITING_BONUS:
|
||||||
const auto building = town->getTown()->buildings.at(bID);
|
const auto building = town->getTown()->buildings.at(bID);
|
||||||
if(!h->hasBonusFrom(Bonus::TOWN_STRUCTURE, Bonus::getSid32(building->town->faction->getIndex(), building->bid)))
|
if(!h->hasBonusFrom(BonusSource::TOWN_STRUCTURE, Bonus::getSid32(building->town->faction->getIndex(), building->bid)))
|
||||||
{
|
{
|
||||||
const auto & bonuses = building->onVisitBonuses;
|
const auto & bonuses = building->onVisitBonuses;
|
||||||
applyBonuses(const_cast<CGHeroInstance *>(h), bonuses);
|
applyBonuses(const_cast<CGHeroInstance *>(h), bonuses);
|
||||||
@ -262,18 +262,18 @@ void CTownBonus::applyBonuses(CGHeroInstance * h, const BonusList & bonuses) con
|
|||||||
GiveBonus gb;
|
GiveBonus gb;
|
||||||
InfoWindow iw;
|
InfoWindow iw;
|
||||||
|
|
||||||
if(bonus->type == Bonus::TOWN_MAGIC_WELL)
|
if(bonus->type == BonusType::TOWN_MAGIC_WELL)
|
||||||
{
|
{
|
||||||
if(h->mana >= h->manaLimit())
|
if(h->mana >= h->manaLimit())
|
||||||
return;
|
return;
|
||||||
cb->setManaPoints(h->id, h->manaLimit());
|
cb->setManaPoints(h->id, h->manaLimit());
|
||||||
bonus->duration = Bonus::ONE_DAY;
|
bonus->duration = BonusDuration::ONE_DAY;
|
||||||
}
|
}
|
||||||
gb.bonus = * bonus;
|
gb.bonus = * bonus;
|
||||||
gb.id = h->id.getNum();
|
gb.id = h->id.getNum();
|
||||||
cb->giveHeroBonus(&gb);
|
cb->giveHeroBonus(&gb);
|
||||||
|
|
||||||
if(bonus->duration == Bonus::PERMANENT)
|
if(bonus->duration == BonusDuration::PERMANENT)
|
||||||
addToVisitors = true;
|
addToVisitors = true;
|
||||||
|
|
||||||
iw.player = cb->getOwner(h->id);
|
iw.player = cb->getOwner(h->id);
|
||||||
|
@ -147,7 +147,7 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
|
|||||||
ret.entries.emplace_back(subID, BuildingID::HORDE_2, creature->getHorde());
|
ret.entries.emplace_back(subID, BuildingID::HORDE_2, creature->getHorde());
|
||||||
|
|
||||||
//statue-of-legion-like bonus: % to base+castle
|
//statue-of-legion-like bonus: % to base+castle
|
||||||
TConstBonusListPtr bonuses2 = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH_PERCENT));
|
TConstBonusListPtr bonuses2 = getBonuses(Selector::type()(BonusType::CREATURE_GROWTH_PERCENT));
|
||||||
for(const auto & b : *bonuses2)
|
for(const auto & b : *bonuses2)
|
||||||
{
|
{
|
||||||
const auto growth = b->val * (base + castleBonus) / 100;
|
const auto growth = b->val * (base + castleBonus) / 100;
|
||||||
@ -155,7 +155,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()(Bonus::CREATURE_GROWTH).And(Selector::subtype()(level)));
|
TConstBonusListPtr bonuses = getBonuses(Selector::type()(BonusType::CREATURE_GROWTH).And(Selector::subtype()(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());
|
||||||
|
|
||||||
@ -764,10 +764,10 @@ void CGTownInstance::deserializationFix()
|
|||||||
|
|
||||||
void CGTownInstance::updateMoraleBonusFromArmy()
|
void CGTownInstance::updateMoraleBonusFromArmy()
|
||||||
{
|
{
|
||||||
auto b = getExportedBonusList().getFirst(Selector::sourceType()(Bonus::ARMY).And(Selector::type()(Bonus::MORALE)));
|
auto b = getExportedBonusList().getFirst(Selector::sourceType()(BonusSource::ARMY).And(Selector::type()(BonusType::MORALE)));
|
||||||
if(!b)
|
if(!b)
|
||||||
{
|
{
|
||||||
b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
|
b = std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::MORALE, BonusSource::ARMY, 0, -1);
|
||||||
addNewBonus(b);
|
addNewBonus(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,7 +783,7 @@ void CGTownInstance::updateMoraleBonusFromArmy()
|
|||||||
void CGTownInstance::recreateBuildingsBonuses()
|
void CGTownInstance::recreateBuildingsBonuses()
|
||||||
{
|
{
|
||||||
BonusList bl;
|
BonusList bl;
|
||||||
getExportedBonusList().getBonuses(bl, Selector::sourceType()(Bonus::TOWN_STRUCTURE));
|
getExportedBonusList().getBonuses(bl, Selector::sourceType()(BonusSource::TOWN_STRUCTURE));
|
||||||
|
|
||||||
for(const auto & b : bl)
|
for(const auto & b : bl)
|
||||||
removeBonus(b);
|
removeBonus(b);
|
||||||
|
@ -272,13 +272,13 @@ int3 CGObjectInstance::getVisitableOffset() const
|
|||||||
return appearance->getVisitableOffset();
|
return appearance->getVisitableOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGObjectInstance::giveDummyBonus(const ObjectInstanceID & heroID, ui8 duration) const
|
void CGObjectInstance::giveDummyBonus(const ObjectInstanceID & heroID, BonusDuration duration) const
|
||||||
{
|
{
|
||||||
GiveBonus gbonus;
|
GiveBonus gbonus;
|
||||||
gbonus.bonus.type = Bonus::NONE;
|
gbonus.bonus.type = BonusType::NONE;
|
||||||
gbonus.id = heroID.getNum();
|
gbonus.id = heroID.getNum();
|
||||||
gbonus.bonus.duration = static_cast<Bonus::BonusDuration>(duration);
|
gbonus.bonus.duration = duration;
|
||||||
gbonus.bonus.source = Bonus::OBJECT;
|
gbonus.bonus.source = BonusSource::OBJECT;
|
||||||
gbonus.bonus.sid = ID;
|
gbonus.bonus.sid = ID;
|
||||||
cb->giveHeroBonus(&gbonus);
|
cb->giveHeroBonus(&gbonus);
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,7 @@ protected:
|
|||||||
virtual void setPropertyDer(ui8 what, ui32 val);
|
virtual void setPropertyDer(ui8 what, ui32 val);
|
||||||
|
|
||||||
/// Gives dummy bonus from this object to hero. Can be used to track visited state
|
/// Gives dummy bonus from this object to hero. Can be used to track visited state
|
||||||
void giveDummyBonus(const ObjectInstanceID & heroID, ui8 duration = Bonus::ONE_DAY) const;
|
void giveDummyBonus(const ObjectInstanceID & heroID, BonusDuration duration = BonusDuration::ONE_DAY) const;
|
||||||
|
|
||||||
///Serialize object-type specific options
|
///Serialize object-type specific options
|
||||||
virtual void serializeJsonOptions(JsonSerializeFormat & handler);
|
virtual void serializeJsonOptions(JsonSerializeFormat & handler);
|
||||||
|
@ -850,8 +850,8 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
|
|||||||
}
|
}
|
||||||
case MORALE_BONUS: case LUCK_BONUS:
|
case MORALE_BONUS: case LUCK_BONUS:
|
||||||
{
|
{
|
||||||
Bonus hb(Bonus::ONE_WEEK, (rewardType == 3 ? Bonus::MORALE : Bonus::LUCK),
|
Bonus hb(BonusDuration::ONE_WEEK, (rewardType == 3 ? BonusType::MORALE : BonusType::LUCK),
|
||||||
Bonus::OBJECT, rVal, h->id.getNum(), "", -1);
|
BonusSource::OBJECT, rVal, h->id.getNum(), "", -1);
|
||||||
GiveBonus gb;
|
GiveBonus gb;
|
||||||
gb.id = h->id.getNum();
|
gb.id = h->id.getNum();
|
||||||
gb.bonus = hb;
|
gb.bonus = hb;
|
||||||
|
@ -48,12 +48,12 @@ void CRewardableConstructor::configureObject(CGObjectInstance * object, CRandomG
|
|||||||
{
|
{
|
||||||
for (auto & bonus : rewardInfo.reward.bonuses)
|
for (auto & bonus : rewardInfo.reward.bonuses)
|
||||||
{
|
{
|
||||||
bonus.source = Bonus::OBJECT;
|
bonus.source = BonusSource::OBJECT;
|
||||||
bonus.sid = rewardableObject->ID;
|
bonus.sid = rewardableObject->ID;
|
||||||
//TODO: bonus.description = object->getObjectName();
|
//TODO: bonus.description = object->getObjectName();
|
||||||
if (bonus.type == Bonus::MORALE)
|
if (bonus.type == BonusType::MORALE)
|
||||||
rewardInfo.reward.extraComponents.emplace_back(Component::EComponentType::MORALE, 0, bonus.val, 0);
|
rewardInfo.reward.extraComponents.emplace_back(Component::EComponentType::MORALE, 0, bonus.val, 0);
|
||||||
if (bonus.type == Bonus::LUCK)
|
if (bonus.type == BonusType::LUCK)
|
||||||
rewardInfo.reward.extraComponents.emplace_back(Component::EComponentType::LUCK, 0, bonus.val, 0);
|
rewardInfo.reward.extraComponents.emplace_back(Component::EComponentType::LUCK, 0, bonus.val, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ bool CRewardableObject::wasVisitedBefore(const CGHeroInstance * contextHero) con
|
|||||||
case Rewardable::VISIT_PLAYER:
|
case Rewardable::VISIT_PLAYER:
|
||||||
return vstd::contains(cb->getPlayerState(contextHero->getOwner())->visitedObjects, ObjectInstanceID(id));
|
return vstd::contains(cb->getPlayerState(contextHero->getOwner())->visitedObjects, ObjectInstanceID(id));
|
||||||
case Rewardable::VISIT_BONUS:
|
case Rewardable::VISIT_BONUS:
|
||||||
return contextHero->hasBonusFrom(Bonus::OBJECT, ID);
|
return contextHero->hasBonusFrom(BonusSource::OBJECT, ID);
|
||||||
case Rewardable::VISIT_HERO:
|
case Rewardable::VISIT_HERO:
|
||||||
return contextHero->visitedObjects.count(ObjectInstanceID(id));
|
return contextHero->visitedObjects.count(ObjectInstanceID(id));
|
||||||
default:
|
default:
|
||||||
@ -211,7 +211,7 @@ bool CRewardableObject::wasVisited(const CGHeroInstance * h) const
|
|||||||
switch (configuration.visitMode)
|
switch (configuration.visitMode)
|
||||||
{
|
{
|
||||||
case Rewardable::VISIT_BONUS:
|
case Rewardable::VISIT_BONUS:
|
||||||
return h->hasBonusFrom(Bonus::OBJECT, ID);
|
return h->hasBonusFrom(BonusSource::OBJECT, ID);
|
||||||
case Rewardable::VISIT_HERO:
|
case Rewardable::VISIT_HERO:
|
||||||
return h->visitedObjects.count(ObjectInstanceID(id));
|
return h->visitedObjects.count(ObjectInstanceID(id));
|
||||||
default:
|
default:
|
||||||
|
@ -435,12 +435,12 @@ static void addStackToArmy(IObjectInfo::CArmyStructure & army, const CCreature *
|
|||||||
army.totalStrength += crea->getFightValue() * amount;
|
army.totalStrength += crea->getFightValue() * amount;
|
||||||
|
|
||||||
bool walker = true;
|
bool walker = true;
|
||||||
if(crea->hasBonusOfType(Bonus::SHOOTER))
|
if(crea->hasBonusOfType(BonusType::SHOOTER))
|
||||||
{
|
{
|
||||||
army.shootersStrength += crea->getFightValue() * amount;
|
army.shootersStrength += crea->getFightValue() * amount;
|
||||||
walker = false;
|
walker = false;
|
||||||
}
|
}
|
||||||
if(crea->hasBonusOfType(Bonus::FLYING))
|
if(crea->hasBonusOfType(BonusType::FLYING))
|
||||||
{
|
{
|
||||||
army.flyersStrength += crea->getFightValue() * amount;
|
army.flyersStrength += crea->getFightValue() * amount;
|
||||||
walker = false;
|
walker = false;
|
||||||
|
@ -312,7 +312,7 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
|
|||||||
if(count*2 > totalCount)
|
if(count*2 > totalCount)
|
||||||
sympathy++; // 2 - hero have similar creatures more that 50%
|
sympathy++; // 2 - hero have similar creatures more that 50%
|
||||||
|
|
||||||
int diplomacy = h->valOfBonuses(Bonus::WANDERING_CREATURES_JOIN_BONUS);
|
int diplomacy = h->valOfBonuses(BonusType::WANDERING_CREATURES_JOIN_BONUS);
|
||||||
int charisma = powerFactor + diplomacy + sympathy;
|
int charisma = powerFactor + diplomacy + sympathy;
|
||||||
|
|
||||||
if(charisma < character)
|
if(charisma < character)
|
||||||
@ -1232,7 +1232,7 @@ void CGWhirlpool::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer
|
|||||||
|
|
||||||
bool CGWhirlpool::isProtected(const CGHeroInstance * h)
|
bool CGWhirlpool::isProtected(const CGHeroInstance * h)
|
||||||
{
|
{
|
||||||
return h->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION)
|
return h->hasBonusOfType(BonusType::WHIRLPOOL_PROTECTION)
|
||||||
|| (h->stacksCount() == 1 && h->Slots().begin()->second->count == 1);
|
|| (h->stacksCount() == 1 && h->Slots().begin()->second->count == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1384,7 +1384,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()(Bonus::SPELL));
|
const std::shared_ptr<Bonus> b = storedArtifact->getBonusLocalFirst(Selector::type()(BonusType::SPELL));
|
||||||
SpellID spellId(b->subtype);
|
SpellID spellId(b->subtype);
|
||||||
|
|
||||||
handler.serializeId("spell", spellId, SpellID::NONE);
|
handler.serializeId("spell", spellId, SpellID::NONE);
|
||||||
@ -1866,21 +1866,21 @@ void CGSirens::initObj(CRandomGenerator & rand)
|
|||||||
|
|
||||||
std::string CGSirens::getHoverText(const CGHeroInstance * hero) const
|
std::string CGSirens::getHoverText(const CGHeroInstance * hero) const
|
||||||
{
|
{
|
||||||
return getObjectName() + " " + visitedTxt(hero->hasBonusFrom(Bonus::OBJECT,ID));
|
return getObjectName() + " " + visitedTxt(hero->hasBonusFrom(BonusSource::OBJECT,ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
|
void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
|
||||||
{
|
{
|
||||||
InfoWindow iw;
|
InfoWindow iw;
|
||||||
iw.player = h->tempOwner;
|
iw.player = h->tempOwner;
|
||||||
if(h->hasBonusFrom(Bonus::OBJECT,ID)) //has already visited Sirens
|
if(h->hasBonusFrom(BonusSource::OBJECT,ID)) //has already visited Sirens
|
||||||
{
|
{
|
||||||
iw.type = EInfoWindowMode::AUTO;
|
iw.type = EInfoWindowMode::AUTO;
|
||||||
iw.text.addTxt(MetaString::ADVOB_TXT,133);
|
iw.text.addTxt(MetaString::ADVOB_TXT,133);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
giveDummyBonus(h->id, Bonus::ONE_BATTLE);
|
giveDummyBonus(h->id, BonusDuration::ONE_BATTLE);
|
||||||
TExpType xp = 0;
|
TExpType xp = 0;
|
||||||
|
|
||||||
for (auto i = h->Slots().begin(); i != h->Slots().end(); i++)
|
for (auto i = h->Slots().begin(); i != h->Slots().end(); i++)
|
||||||
@ -2120,7 +2120,7 @@ void CGLighthouse::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
{
|
{
|
||||||
RemoveBonus rb(GiveBonus::ETarget::PLAYER);
|
RemoveBonus rb(GiveBonus::ETarget::PLAYER);
|
||||||
rb.whoID = oldOwner.getNum();
|
rb.whoID = oldOwner.getNum();
|
||||||
rb.source = Bonus::OBJECT;
|
rb.source = vstd::to_underlying(BonusSource::OBJECT);
|
||||||
rb.id = id.getNum();
|
rb.id = id.getNum();
|
||||||
cb->sendAndApply(&rb);
|
cb->sendAndApply(&rb);
|
||||||
}
|
}
|
||||||
@ -2139,11 +2139,11 @@ void CGLighthouse::initObj(CRandomGenerator & rand)
|
|||||||
void CGLighthouse::giveBonusTo(const PlayerColor & player, bool onInit) const
|
void CGLighthouse::giveBonusTo(const PlayerColor & player, bool onInit) const
|
||||||
{
|
{
|
||||||
GiveBonus gb(GiveBonus::ETarget::PLAYER);
|
GiveBonus gb(GiveBonus::ETarget::PLAYER);
|
||||||
gb.bonus.type = Bonus::MOVEMENT;
|
gb.bonus.type = BonusType::MOVEMENT;
|
||||||
gb.bonus.val = 500;
|
gb.bonus.val = 500;
|
||||||
gb.id = player.getNum();
|
gb.id = player.getNum();
|
||||||
gb.bonus.duration = Bonus::PERMANENT;
|
gb.bonus.duration = BonusDuration::PERMANENT;
|
||||||
gb.bonus.source = Bonus::OBJECT;
|
gb.bonus.source = BonusSource::OBJECT;
|
||||||
gb.bonus.sid = id.getNum();
|
gb.bonus.sid = id.getNum();
|
||||||
gb.bonus.subtype = 0;
|
gb.bonus.subtype = 0;
|
||||||
|
|
||||||
|
@ -1720,7 +1720,7 @@ CGObjectInstance * CMapLoaderH3M::readHero(const int3 & mapPosition, const Objec
|
|||||||
bool hasCustomPrimSkills = reader->readBool();
|
bool hasCustomPrimSkills = reader->readBool();
|
||||||
if(hasCustomPrimSkills)
|
if(hasCustomPrimSkills)
|
||||||
{
|
{
|
||||||
auto ps = object->getAllBonuses(Selector::type()(Bonus::PRIMARY_SKILL).And(Selector::sourceType()(Bonus::HERO_BASE_SKILL)), nullptr);
|
auto ps = object->getAllBonuses(Selector::type()(BonusType::PRIMARY_SKILL).And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)), nullptr);
|
||||||
if(ps->size())
|
if(ps->size())
|
||||||
{
|
{
|
||||||
logGlobal->warn("Hero %s subID=%d has set primary skills twice (in map properties and on adventure map instance). Using the latter set...", object->getNameTranslated(), object->subID );
|
logGlobal->warn("Hero %s subID=%d has set primary skills twice (in map properties and on adventure map instance). Using the latter set...", object->getNameTranslated(), object->subID );
|
||||||
|
@ -91,7 +91,7 @@ void Rewardable::Interface::grantRewardAfterLevelup(IGameCallback * cb, const Re
|
|||||||
|
|
||||||
for(const Bonus & bonus : info.reward.bonuses)
|
for(const Bonus & bonus : info.reward.bonuses)
|
||||||
{
|
{
|
||||||
assert(bonus.source == Bonus::OBJECT);
|
assert(bonus.source == BonusSource::OBJECT);
|
||||||
GiveBonus gb;
|
GiveBonus gb;
|
||||||
gb.who = GiveBonus::ETarget::HERO;
|
gb.who = GiveBonus::ETarget::HERO;
|
||||||
gb.bonus = bonus;
|
gb.bonus = bonus;
|
||||||
|
@ -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(Bonus::MAGIC_SCHOOL_SKILL, 0));
|
vstd::amax(skill, unit->valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
vstd::amax(skill, 0);
|
vstd::amax(skill, 0);
|
||||||
|
@ -307,9 +307,9 @@ ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(SpellCastEnvironm
|
|||||||
const int movementCost = GameConstants::BASE_MOVEMENT_COST * ((schoolLevel >= 3) ? 2 : 3);
|
const int movementCost = GameConstants::BASE_MOVEMENT_COST * ((schoolLevel >= 3) ? 2 : 3);
|
||||||
|
|
||||||
std::stringstream cachingStr;
|
std::stringstream cachingStr;
|
||||||
cachingStr << "source_" << Bonus::SPELL_EFFECT << "id_" << owner->id.num;
|
cachingStr << "source_" << vstd::to_underlying(BonusSource::SPELL_EFFECT) << "id_" << owner->id.num;
|
||||||
|
|
||||||
if(parameters.caster->getHeroCaster()->getBonuses(Selector::source(Bonus::SPELL_EFFECT, owner->id), Selector::all, cachingStr.str())->size() >= owner->getLevelPower(schoolLevel)) //limit casts per turn
|
if(parameters.caster->getHeroCaster()->getBonuses(Selector::source(BonusSource::SPELL_EFFECT, owner->id), Selector::all, cachingStr.str())->size() >= owner->getLevelPower(schoolLevel)) //limit casts per turn
|
||||||
{
|
{
|
||||||
InfoWindow iw;
|
InfoWindow iw;
|
||||||
iw.player = parameters.caster->getCasterOwner();
|
iw.player = parameters.caster->getCasterOwner();
|
||||||
@ -321,7 +321,7 @@ ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(SpellCastEnvironm
|
|||||||
|
|
||||||
GiveBonus gb;
|
GiveBonus gb;
|
||||||
gb.id = parameters.caster->getCasterUnitId();
|
gb.id = parameters.caster->getCasterUnitId();
|
||||||
gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::NONE, Bonus::SPELL_EFFECT, 0, owner->id);
|
gb.bonus = Bonus(BonusDuration::ONE_DAY, BonusType::NONE, BonusSource::SPELL_EFFECT, 0, owner->id);
|
||||||
env->apply(&gb);
|
env->apply(&gb);
|
||||||
|
|
||||||
if(!dest->isClear(curr)) //wrong dest tile
|
if(!dest->isClear(curr)) //wrong dest tile
|
||||||
|
@ -283,7 +283,7 @@ void BattleSpellMechanics::cast(ServerCallback * server, const Target & target)
|
|||||||
{
|
{
|
||||||
if(stack->unitOwner() == otherHero->tempOwner)
|
if(stack->unitOwner() == otherHero->tempOwner)
|
||||||
{
|
{
|
||||||
vstd::amax(manaChannel, stack->valOfBonuses(Bonus::MANA_CHANNELING));
|
vstd::amax(manaChannel, stack->valOfBonuses(BonusType::MANA_CHANNELING));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sc.manaGained = (manaChannel * spellCost) / 100;
|
sc.manaGained = (manaChannel * spellCost) / 100;
|
||||||
@ -467,7 +467,7 @@ void BattleSpellMechanics::doRemoveEffects(ServerCallback * server, const std::v
|
|||||||
|
|
||||||
bool BattleSpellMechanics::counteringSelector(const Bonus * bonus) const
|
bool BattleSpellMechanics::counteringSelector(const Bonus * bonus) const
|
||||||
{
|
{
|
||||||
if(bonus->source != Bonus::SPELL_EFFECT)
|
if(bonus->source != BonusSource::SPELL_EFFECT)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for(const SpellID & id : owner->counteredSpells)
|
for(const SpellID & id : owner->counteredSpells)
|
||||||
|
@ -42,35 +42,35 @@ static const spells::SchoolInfo SCHOOL[4] =
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
ESpellSchool::AIR,
|
ESpellSchool::AIR,
|
||||||
Bonus::AIR_SPELL_DMG_PREMY,
|
BonusType::AIR_SPELL_DMG_PREMY,
|
||||||
Bonus::AIR_IMMUNITY,
|
BonusType::AIR_IMMUNITY,
|
||||||
"air",
|
"air",
|
||||||
SecondarySkill::AIR_MAGIC,
|
SecondarySkill::AIR_MAGIC,
|
||||||
Bonus::AIR_SPELLS
|
BonusType::AIR_SPELLS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ESpellSchool::FIRE,
|
ESpellSchool::FIRE,
|
||||||
Bonus::FIRE_SPELL_DMG_PREMY,
|
BonusType::FIRE_SPELL_DMG_PREMY,
|
||||||
Bonus::FIRE_IMMUNITY,
|
BonusType::FIRE_IMMUNITY,
|
||||||
"fire",
|
"fire",
|
||||||
SecondarySkill::FIRE_MAGIC,
|
SecondarySkill::FIRE_MAGIC,
|
||||||
Bonus::FIRE_SPELLS
|
BonusType::FIRE_SPELLS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ESpellSchool::WATER,
|
ESpellSchool::WATER,
|
||||||
Bonus::WATER_SPELL_DMG_PREMY,
|
BonusType::WATER_SPELL_DMG_PREMY,
|
||||||
Bonus::WATER_IMMUNITY,
|
BonusType::WATER_IMMUNITY,
|
||||||
"water",
|
"water",
|
||||||
SecondarySkill::WATER_MAGIC,
|
SecondarySkill::WATER_MAGIC,
|
||||||
Bonus::WATER_SPELLS
|
BonusType::WATER_SPELLS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ESpellSchool::EARTH,
|
ESpellSchool::EARTH,
|
||||||
Bonus::EARTH_SPELL_DMG_PREMY,
|
BonusType::EARTH_SPELL_DMG_PREMY,
|
||||||
Bonus::EARTH_IMMUNITY,
|
BonusType::EARTH_IMMUNITY,
|
||||||
"earth",
|
"earth",
|
||||||
SecondarySkill::EARTH_MAGIC,
|
SecondarySkill::EARTH_MAGIC,
|
||||||
Bonus::EARTH_SPELLS
|
BonusType::EARTH_SPELLS
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -393,15 +393,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 spells::SchoolInfo & cnf, bool & stop)
|
forEachSchool([&](const spells::SchoolInfo & cnf, bool & stop)
|
||||||
{
|
{
|
||||||
if(bearer->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, static_cast<ui8>(cnf.id)))
|
if(bearer->hasBonusOfType(BonusType::SPELL_DAMAGE_REDUCTION, static_cast<ui8>(cnf.id)))
|
||||||
{
|
{
|
||||||
ret *= 100 - bearer->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, static_cast<ui8>(cnf.id));
|
ret *= 100 - bearer->valOfBonuses(BonusType::SPELL_DAMAGE_REDUCTION, static_cast<ui8>(cnf.id));
|
||||||
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::type()(Bonus::SPELL_DAMAGE_REDUCTION).And(Selector::subtype()(-1));
|
CSelector selector = Selector::type()(BonusType::SPELL_DAMAGE_REDUCTION).And(Selector::subtype()(-1));
|
||||||
|
|
||||||
//general spell dmg reduction, works only on magical effects
|
//general spell dmg reduction, works only on magical effects
|
||||||
if(bearer->hasBonus(selector) && isMagical())
|
if(bearer->hasBonus(selector) && isMagical())
|
||||||
@ -411,9 +411,9 @@ int64_t CSpell::adjustRawDamage(const spells::Caster * caster, const battle::Uni
|
|||||||
}
|
}
|
||||||
|
|
||||||
//dmg increasing
|
//dmg increasing
|
||||||
if(bearer->hasBonusOfType(Bonus::MORE_DAMAGE_FROM_SPELL, id))
|
if(bearer->hasBonusOfType(BonusType::MORE_DAMAGE_FROM_SPELL, id))
|
||||||
{
|
{
|
||||||
ret *= 100 + bearer->valOfBonuses(Bonus::MORE_DAMAGE_FROM_SPELL, id.toEnum());
|
ret *= 100 + bearer->valOfBonuses(BonusType::MORE_DAMAGE_FROM_SPELL, id.toEnum());
|
||||||
ret /= 100;
|
ret /= 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -452,8 +452,8 @@ JsonNode CSpell::convertTargetCondition(const BTVector & immunity, const BTVecto
|
|||||||
static const std::string CONDITION_NORMAL = "normal";
|
static const std::string CONDITION_NORMAL = "normal";
|
||||||
static const std::string CONDITION_ABSOLUTE = "absolute";
|
static const std::string CONDITION_ABSOLUTE = "absolute";
|
||||||
|
|
||||||
#define BONUS_NAME(x) { Bonus::x, #x },
|
#define BONUS_NAME(x) { BonusType::x, #x },
|
||||||
static const std::map<Bonus::BonusType, std::string> bonusNameRMap = { BONUS_LIST };
|
static const std::map<BonusType, std::string> bonusNameRMap = { BONUS_LIST };
|
||||||
#undef BONUS_NAME
|
#undef BONUS_NAME
|
||||||
|
|
||||||
JsonNode res;
|
JsonNode res;
|
||||||
@ -791,7 +791,7 @@ CSpell * CSpellHandler::loadFromJson(const std::string & scope, const JsonNode &
|
|||||||
|
|
||||||
spell->special = flags["special"].Bool();
|
spell->special = flags["special"].Bool();
|
||||||
|
|
||||||
auto findBonus = [&](const std::string & name, std::vector<Bonus::BonusType> & vec)
|
auto findBonus = [&](const std::string & name, std::vector<BonusType> & vec)
|
||||||
{
|
{
|
||||||
auto it = bonusNameMap.find(name);
|
auto it = bonusNameMap.find(name);
|
||||||
if(it == bonusNameMap.end())
|
if(it == bonusNameMap.end())
|
||||||
@ -800,11 +800,11 @@ CSpell * CSpellHandler::loadFromJson(const std::string & scope, const JsonNode &
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vec.push_back(static_cast<Bonus::BonusType>(it->second));
|
vec.push_back(static_cast<BonusType>(it->second));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto readBonusStruct = [&](const std::string & name, std::vector<Bonus::BonusType> & vec)
|
auto readBonusStruct = [&](const std::string & name, std::vector<BonusType> & vec)
|
||||||
{
|
{
|
||||||
for(auto bonusData: json[name].Struct())
|
for(auto bonusData: json[name].Struct())
|
||||||
{
|
{
|
||||||
@ -933,7 +933,7 @@ CSpell * CSpellHandler::loadFromJson(const std::string & scope, const JsonNode &
|
|||||||
const bool usePowerAsValue = bonusNode["val"].isNull();
|
const bool usePowerAsValue = bonusNode["val"].isNull();
|
||||||
|
|
||||||
b->sid = spell->id; //for all
|
b->sid = spell->id; //for all
|
||||||
b->source = Bonus::SPELL_EFFECT;//for all
|
b->source = BonusSource::SPELL_EFFECT;//for all
|
||||||
|
|
||||||
if(usePowerAsValue)
|
if(usePowerAsValue)
|
||||||
b->val = levelPower;
|
b->val = levelPower;
|
||||||
@ -948,7 +948,7 @@ CSpell * CSpellHandler::loadFromJson(const std::string & scope, const JsonNode &
|
|||||||
const bool usePowerAsValue = bonusNode["val"].isNull();
|
const bool usePowerAsValue = bonusNode["val"].isNull();
|
||||||
|
|
||||||
b->sid = spell->id; //for all
|
b->sid = spell->id; //for all
|
||||||
b->source = Bonus::SPELL_EFFECT;//for all
|
b->source = BonusSource::SPELL_EFFECT;//for all
|
||||||
|
|
||||||
if(usePowerAsValue)
|
if(usePowerAsValue)
|
||||||
b->val = levelPower;
|
b->val = levelPower;
|
||||||
|
@ -44,11 +44,11 @@ class IBattleCast;
|
|||||||
struct SchoolInfo
|
struct SchoolInfo
|
||||||
{
|
{
|
||||||
ESpellSchool id; //backlink
|
ESpellSchool id; //backlink
|
||||||
Bonus::BonusType damagePremyBonus;
|
BonusType damagePremyBonus;
|
||||||
Bonus::BonusType immunityBonus;
|
BonusType immunityBonus;
|
||||||
std::string jsonName;
|
std::string jsonName;
|
||||||
SecondarySkill::ESecondarySkill skill;
|
SecondarySkill::ESecondarySkill skill;
|
||||||
Bonus::BonusType knoledgeBonus;
|
BonusType knoledgeBonus;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -184,7 +184,7 @@ public:
|
|||||||
TargetInfo(const CSpell * spell, const int32_t level, spells::Mode mode);
|
TargetInfo(const CSpell * spell, const int32_t level, spells::Mode mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
using BTVector = std::vector<Bonus::BonusType>;
|
using BTVector = std::vector<BonusType>;
|
||||||
|
|
||||||
si32 level;
|
si32 level;
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ void BattleCast::cast(ServerCallback * server, Target target)
|
|||||||
if(tryMagicMirror)
|
if(tryMagicMirror)
|
||||||
{
|
{
|
||||||
const std::string magicMirrorCacheStr = "type_MAGIC_MIRROR";
|
const std::string magicMirrorCacheStr = "type_MAGIC_MIRROR";
|
||||||
static const auto magicMirrorSelector = Selector::type()(Bonus::MAGIC_MIRROR);
|
static const auto magicMirrorSelector = Selector::type()(BonusType::MAGIC_MIRROR);
|
||||||
|
|
||||||
auto rangeGen = server->getRNG()->getInt64Range(0, 99);
|
auto rangeGen = server->getRNG()->getInt64Range(0, 99);
|
||||||
|
|
||||||
@ -484,9 +484,9 @@ bool BaseMechanics::adaptProblem(ESpellCastProblem::ESpellCastProblem source, Pr
|
|||||||
return adaptGenericProblem(target);
|
return adaptGenericProblem(target);
|
||||||
|
|
||||||
//Recanter's Cloak or similar effect. Try to retrieve bonus
|
//Recanter's Cloak or similar effect. Try to retrieve bonus
|
||||||
const auto b = hero->getBonusLocalFirst(Selector::type()(Bonus::BLOCK_MAGIC_ABOVE));
|
const auto b = hero->getBonusLocalFirst(Selector::type()(BonusType::BLOCK_MAGIC_ABOVE));
|
||||||
//TODO what about other values and non-artifact sources?
|
//TODO what about other values and non-artifact sources?
|
||||||
if(b && b->val == 2 && b->source == Bonus::ARTIFACT)
|
if(b && b->val == 2 && b->source == BonusSource::ARTIFACT)
|
||||||
{
|
{
|
||||||
//The %s prevents %s from casting 3rd level or higher spells.
|
//The %s prevents %s from casting 3rd level or higher spells.
|
||||||
text.addTxt(MetaString::GENERAL_TXT, 536);
|
text.addTxt(MetaString::GENERAL_TXT, 536);
|
||||||
@ -494,7 +494,7 @@ bool BaseMechanics::adaptProblem(ESpellCastProblem::ESpellCastProblem source, Pr
|
|||||||
caster->getCasterName(text);
|
caster->getCasterName(text);
|
||||||
target.add(std::move(text), spells::Problem::NORMAL);
|
target.add(std::move(text), spells::Problem::NORMAL);
|
||||||
}
|
}
|
||||||
else if(b && b->source == Bonus::TERRAIN_OVERLAY && VLC->battlefields()->getByIndex(b->sid)->identifier == "cursed_ground")
|
else if(b && b->source == BonusSource::TERRAIN_OVERLAY && VLC->battlefields()->getByIndex(b->sid)->identifier == "cursed_ground")
|
||||||
{
|
{
|
||||||
text.addTxt(MetaString::GENERAL_TXT, 537);
|
text.addTxt(MetaString::GENERAL_TXT, 537);
|
||||||
target.add(std::move(text), spells::Problem::NORMAL);
|
target.add(std::move(text), spells::Problem::NORMAL);
|
||||||
@ -620,9 +620,9 @@ int64_t BaseMechanics::calculateRawEffectValue(int32_t basePowerMultiplier, int3
|
|||||||
return owner->calculateRawEffectValue(getEffectLevel(), basePowerMultiplier, levelPowerMultiplier);
|
return owner->calculateRawEffectValue(getEffectLevel(), basePowerMultiplier, levelPowerMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Bonus::BonusType> BaseMechanics::getElementalImmunity() const
|
std::vector<BonusType> BaseMechanics::getElementalImmunity() const
|
||||||
{
|
{
|
||||||
std::vector<Bonus::BonusType> ret;
|
std::vector<BonusType> ret;
|
||||||
|
|
||||||
owner->forEachSchool([&](const SchoolInfo & cnf, bool & stop)
|
owner->forEachSchool([&](const SchoolInfo & cnf, bool & stop)
|
||||||
{
|
{
|
||||||
|
@ -235,7 +235,7 @@ public:
|
|||||||
virtual int64_t applySpecificSpellBonus(int64_t value) const = 0;
|
virtual int64_t applySpecificSpellBonus(int64_t value) const = 0;
|
||||||
virtual int64_t calculateRawEffectValue(int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const = 0;
|
virtual int64_t calculateRawEffectValue(int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const = 0;
|
||||||
|
|
||||||
virtual std::vector<Bonus::BonusType> getElementalImmunity() const = 0;
|
virtual std::vector<BonusType> getElementalImmunity() const = 0;
|
||||||
|
|
||||||
//Battle facade
|
//Battle facade
|
||||||
virtual bool ownerMatches(const battle::Unit * unit) const = 0;
|
virtual bool ownerMatches(const battle::Unit * unit) const = 0;
|
||||||
@ -296,7 +296,7 @@ public:
|
|||||||
int64_t applySpecificSpellBonus(int64_t value) const override;
|
int64_t applySpecificSpellBonus(int64_t value) const override;
|
||||||
int64_t calculateRawEffectValue(int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const override;
|
int64_t calculateRawEffectValue(int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const override;
|
||||||
|
|
||||||
std::vector<Bonus::BonusType> getElementalImmunity() const override;
|
std::vector<BonusType> getElementalImmunity() const override;
|
||||||
|
|
||||||
bool ownerMatches(const battle::Unit * unit) const override;
|
bool ownerMatches(const battle::Unit * unit) const override;
|
||||||
bool ownerMatches(const battle::Unit * unit, const boost::logic::tribool positivness) const override;
|
bool ownerMatches(const battle::Unit * unit, const boost::logic::tribool positivness) const override;
|
||||||
|
@ -121,9 +121,9 @@ protected:
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
std::stringstream cachingStr;
|
std::stringstream cachingStr;
|
||||||
cachingStr << "type_" << Bonus::LEVEL_SPELL_IMMUNITY << "addInfo_1";
|
cachingStr << "type_" << vstd::to_underlying(BonusType::LEVEL_SPELL_IMMUNITY) << "addInfo_1";
|
||||||
|
|
||||||
TConstBonusListPtr levelImmunities = target->getBonuses(Selector::type()(Bonus::LEVEL_SPELL_IMMUNITY).And(Selector::info()(1)), cachingStr.str());
|
TConstBonusListPtr levelImmunities = target->getBonuses(Selector::type()(BonusType::LEVEL_SPELL_IMMUNITY).And(Selector::info()(1)), cachingStr.str());
|
||||||
return (levelImmunities->size() == 0 || levelImmunities->totalValue() < m->getSpellLevel() || m->getSpellLevel() <= 0);
|
return (levelImmunities->size() == 0 || levelImmunities->totalValue() < m->getSpellLevel() || m->getSpellLevel() <= 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -141,8 +141,8 @@ protected:
|
|||||||
bool check(const Mechanics * m, const battle::Unit * target) const override
|
bool check(const Mechanics * m, const battle::Unit * target) const override
|
||||||
{
|
{
|
||||||
std::stringstream cachingStr;
|
std::stringstream cachingStr;
|
||||||
cachingStr << "type_" << Bonus::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(Bonus::SPELL_IMMUNITY, m->getSpellIndex(), 1), cachingStr.str());
|
return !target->hasBonus(Selector::typeSubtypeInfo(BonusType::SPELL_IMMUNITY, m->getSpellIndex(), 1), cachingStr.str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -197,7 +197,7 @@ protected:
|
|||||||
{
|
{
|
||||||
if(!m->isMagicalEffect()) //Always pass on non-magical
|
if(!m->isMagicalEffect()) //Always pass on non-magical
|
||||||
return true;
|
return true;
|
||||||
TConstBonusListPtr levelImmunities = target->getBonuses(Selector::type()(Bonus::LEVEL_SPELL_IMMUNITY));
|
TConstBonusListPtr levelImmunities = target->getBonuses(Selector::type()(BonusType::LEVEL_SPELL_IMMUNITY));
|
||||||
return levelImmunities->size() == 0 ||
|
return levelImmunities->size() == 0 ||
|
||||||
levelImmunities->totalValue() < m->getSpellLevel() ||
|
levelImmunities->totalValue() < m->getSpellLevel() ||
|
||||||
m->getSpellLevel() <= 0;
|
m->getSpellLevel() <= 0;
|
||||||
@ -216,7 +216,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(Bonus::SPELL_IMMUNITY, m->getSpellIndex());
|
return !target->hasBonusOfType(BonusType::SPELL_IMMUNITY, m->getSpellIndex());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -241,10 +241,10 @@ public:
|
|||||||
SpellEffectCondition(const SpellID & spellID_): spellID(spellID_)
|
SpellEffectCondition(const SpellID & spellID_): spellID(spellID_)
|
||||||
{
|
{
|
||||||
std::stringstream builder;
|
std::stringstream builder;
|
||||||
builder << "source_" << Bonus::SPELL_EFFECT << "id_" << spellID.num;
|
builder << "source_" << vstd::to_underlying(BonusSource::SPELL_EFFECT) << "id_" << spellID.num;
|
||||||
cachingString = builder.str();
|
cachingString = builder.str();
|
||||||
|
|
||||||
selector = Selector::source(Bonus::SPELL_EFFECT, spellID.num);
|
selector = Selector::source(BonusSource::SPELL_EFFECT, spellID.num);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -268,7 +268,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSelector selector = Selector::type()(Bonus::RECEPTIVE);
|
CSelector selector = Selector::type()(BonusType::RECEPTIVE);
|
||||||
std::string cachingString = "type_RECEPTIVE";
|
std::string cachingString = "type_RECEPTIVE";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -277,8 +277,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(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES, 0);
|
const bool battleWideNegation = target->hasBonusOfType(BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, 0);
|
||||||
const bool heroNegation = target->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES, 1);
|
const bool heroNegation = target->hasBonusOfType(BonusType::NEGATE_ALL_NATURAL_IMMUNITIES, 1);
|
||||||
//anyone can cast on artifact holder`s stacks
|
//anyone can cast on artifact holder`s stacks
|
||||||
if(heroNegation)
|
if(heroNegation)
|
||||||
{
|
{
|
||||||
|
@ -89,7 +89,7 @@ void Clone::apply(ServerCallback * server, const Mechanics * m, const EffectTarg
|
|||||||
server->apply(&cloneFlags);
|
server->apply(&cloneFlags);
|
||||||
|
|
||||||
SetStackEffect sse;
|
SetStackEffect sse;
|
||||||
Bonus lifeTimeMarker(Bonus::N_TURNS, Bonus::NONE, Bonus::SPELL_EFFECT, 0, SpellID::CLONE); //TODO: use special bonus type
|
Bonus lifeTimeMarker(BonusDuration::N_TURNS, BonusType::NONE, BonusSource::SPELL_EFFECT, 0, SpellID::CLONE); //TODO: use special bonus type
|
||||||
lifeTimeMarker.turnsRemain = m->getEffectDuration();
|
lifeTimeMarker.turnsRemain = m->getEffectDuration();
|
||||||
std::vector<Bonus> buffer;
|
std::vector<Bonus> buffer;
|
||||||
buffer.push_back(lifeTimeMarker);
|
buffer.push_back(lifeTimeMarker);
|
||||||
|
@ -85,7 +85,7 @@ std::shared_ptr<const BonusList> Dispel::getBonuses(const Mechanics * m, const b
|
|||||||
{
|
{
|
||||||
auto sel = [=](const Bonus * bonus)
|
auto sel = [=](const Bonus * bonus)
|
||||||
{
|
{
|
||||||
if(bonus->source == Bonus::SPELL_EFFECT)
|
if(bonus->source == BonusSource::SPELL_EFFECT)
|
||||||
{
|
{
|
||||||
const Spell * sourceSpell = SpellID(bonus->sid).toSpell(m->spells());
|
const Spell * sourceSpell = SpellID(bonus->sid).toSpell(m->spells());
|
||||||
if(!sourceSpell)
|
if(!sourceSpell)
|
||||||
|
@ -80,17 +80,17 @@ void Moat::convertBonus(const Mechanics * m, std::vector<Bonus> & converted) con
|
|||||||
Bonus nb(*b);
|
Bonus nb(*b);
|
||||||
|
|
||||||
//Moat battlefield effect is always permanent
|
//Moat battlefield effect is always permanent
|
||||||
nb.duration = Bonus::ONE_BATTLE;
|
nb.duration = BonusDuration::ONE_BATTLE;
|
||||||
|
|
||||||
if(m->battle()->battleGetDefendedTown() && m->battle()->battleGetSiegeLevel() >= CGTownInstance::CITADEL)
|
if(m->battle()->battleGetDefendedTown() && m->battle()->battleGetSiegeLevel() >= CGTownInstance::CITADEL)
|
||||||
{
|
{
|
||||||
nb.sid = Bonus::getSid32(m->battle()->battleGetDefendedTown()->getFaction(), BuildingID::CITADEL);
|
nb.sid = Bonus::getSid32(m->battle()->battleGetDefendedTown()->getFaction(), BuildingID::CITADEL);
|
||||||
nb.source = Bonus::TOWN_STRUCTURE;
|
nb.source = BonusSource::TOWN_STRUCTURE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nb.sid = m->getSpellIndex(); //for all
|
nb.sid = m->getSpellIndex(); //for all
|
||||||
nb.source = Bonus::SPELL_EFFECT;//for all
|
nb.source = BonusSource::SPELL_EFFECT;//for all
|
||||||
}
|
}
|
||||||
std::set<BattleHex> flatMoatHexes;
|
std::set<BattleHex> flatMoatHexes;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ static void describeEffect(std::vector<MetaString> & log, const Mechanics * m, c
|
|||||||
{
|
{
|
||||||
switch(bonus.type)
|
switch(bonus.type)
|
||||||
{
|
{
|
||||||
case Bonus::NOT_ACTIVE:
|
case BonusType::NOT_ACTIVE:
|
||||||
{
|
{
|
||||||
switch(bonus.subtype)
|
switch(bonus.subtype)
|
||||||
{
|
{
|
||||||
@ -60,17 +60,17 @@ static void describeEffect(std::vector<MetaString> & log, const Mechanics * m, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Bonus::POISON:
|
case BonusType::POISON:
|
||||||
addLogLine(561, boost::logic::indeterminate);
|
addLogLine(561, boost::logic::indeterminate);
|
||||||
return;
|
return;
|
||||||
case Bonus::BIND_EFFECT:
|
case BonusType::BIND_EFFECT:
|
||||||
addLogLine(-560, true);
|
addLogLine(-560, true);
|
||||||
return;
|
return;
|
||||||
case Bonus::STACK_HEALTH:
|
case BonusType::STACK_HEALTH:
|
||||||
{
|
{
|
||||||
if(bonus.val < 0)
|
if(bonus.val < 0)
|
||||||
{
|
{
|
||||||
BonusList unitHealth = *target->getBonuses(Selector::type()(Bonus::STACK_HEALTH));
|
BonusList unitHealth = *target->getBonuses(Selector::type()(BonusType::STACK_HEALTH));
|
||||||
|
|
||||||
auto oldHealth = unitHealth.totalValue();
|
auto oldHealth = unitHealth.totalValue();
|
||||||
unitHealth.push_back(std::make_shared<Bonus>(bonus));
|
unitHealth.push_back(std::make_shared<Bonus>(bonus));
|
||||||
@ -108,9 +108,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(Bonus::SPECIAL_PECULIAR_ENCHANT, m->getSpellIndex()));
|
peculiarBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(BonusType::SPECIAL_PECULIAR_ENCHANT, m->getSpellIndex()));
|
||||||
addedValueBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(Bonus::SPECIAL_ADD_VALUE_ENCHANT, m->getSpellIndex()));
|
addedValueBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(BonusType::SPECIAL_ADD_VALUE_ENCHANT, m->getSpellIndex()));
|
||||||
fixedValueBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(Bonus::SPECIAL_FIXED_VALUE_ENCHANT, m->getSpellIndex()));
|
fixedValueBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(BonusType::SPECIAL_FIXED_VALUE_ENCHANT, m->getSpellIndex()));
|
||||||
}
|
}
|
||||||
//TODO: does hero specialty should affects his stack casting spells?
|
//TODO: does hero specialty should affects his stack casting spells?
|
||||||
|
|
||||||
@ -220,13 +220,13 @@ void Timed::convertBonus(const Mechanics * m, int32_t & duration, std::vector<Bo
|
|||||||
vstd::amax(maxDuration, nb.turnsRemain);
|
vstd::amax(maxDuration, nb.turnsRemain);
|
||||||
|
|
||||||
nb.sid = m->getSpellIndex(); //for all
|
nb.sid = m->getSpellIndex(); //for all
|
||||||
nb.source = Bonus::SPELL_EFFECT;//for all
|
nb.source = BonusSource::SPELL_EFFECT;//for all
|
||||||
|
|
||||||
//fix to original config: shield should display damage reduction
|
//fix to original config: shield should display damage reduction
|
||||||
if((nb.sid == SpellID::SHIELD || nb.sid == SpellID::AIR_SHIELD) && (nb.type == Bonus::GENERAL_DAMAGE_REDUCTION))
|
if((nb.sid == SpellID::SHIELD || nb.sid == SpellID::AIR_SHIELD) && (nb.type == BonusType::GENERAL_DAMAGE_REDUCTION))
|
||||||
nb.val = 100 - nb.val;
|
nb.val = 100 - nb.val;
|
||||||
//we need to know who cast Bind
|
//we need to know who cast Bind
|
||||||
else if(nb.sid == SpellID::BIND && nb.type == Bonus::BIND_EFFECT && m->caster->getHeroCaster() == nullptr)
|
else if(nb.sid == SpellID::BIND && nb.type == BonusType::BIND_EFFECT && m->caster->getHeroCaster() == nullptr)
|
||||||
nb.additionalInfo = m->caster->getCasterUnitId();
|
nb.additionalInfo = m->caster->getCasterUnitId();
|
||||||
|
|
||||||
converted.push_back(nb);
|
converted.push_back(nb);
|
||||||
|
@ -252,8 +252,8 @@ 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_" << Bonus::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(Bonus::SPELL_IMMUNITY, m->getSpellIndex(), 1), cachingStr.str());
|
return !unit->hasBonus(Selector::typeSubtypeInfo(BonusType::SPELL_IMMUNITY, m->getSpellIndex(), 1), cachingStr.str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -136,7 +136,7 @@ static void giveExp(BattleResult &r)
|
|||||||
r.exp[1] = 0;
|
r.exp[1] = 0;
|
||||||
for (auto i = r.casualties[!r.winner].begin(); i!=r.casualties[!r.winner].end(); i++)
|
for (auto i = r.casualties[!r.winner].begin(); i!=r.casualties[!r.winner].end(); i++)
|
||||||
{
|
{
|
||||||
r.exp[r.winner] += VLC->creh->objects.at(i->first)->valOfBonuses(Bonus::STACK_HEALTH) * i->second;
|
r.exp[r.winner] += VLC->creh->objects.at(i->first)->valOfBonuses(BonusType::STACK_HEALTH) * i->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,10 +361,10 @@ void CGameHandler::levelUpCommander (const CCommanderInstance * c, int skill)
|
|||||||
|
|
||||||
scp.accumulatedBonus.subtype = 0;
|
scp.accumulatedBonus.subtype = 0;
|
||||||
scp.accumulatedBonus.additionalInfo = 0;
|
scp.accumulatedBonus.additionalInfo = 0;
|
||||||
scp.accumulatedBonus.duration = Bonus::PERMANENT;
|
scp.accumulatedBonus.duration = BonusDuration::PERMANENT;
|
||||||
scp.accumulatedBonus.turnsRemain = 0;
|
scp.accumulatedBonus.turnsRemain = 0;
|
||||||
scp.accumulatedBonus.source = Bonus::COMMANDER;
|
scp.accumulatedBonus.source = BonusSource::COMMANDER;
|
||||||
scp.accumulatedBonus.valType = Bonus::BASE_NUMBER;
|
scp.accumulatedBonus.valType = BonusValueType::BASE_NUMBER;
|
||||||
if (skill <= ECommander::SPELL_POWER)
|
if (skill <= ECommander::SPELL_POWER)
|
||||||
{
|
{
|
||||||
scp.which = SetCommanderProperty::BONUS;
|
scp.which = SetCommanderProperty::BONUS;
|
||||||
@ -378,36 +378,36 @@ void CGameHandler::levelUpCommander (const CCommanderInstance * c, int skill)
|
|||||||
switch (skill)
|
switch (skill)
|
||||||
{
|
{
|
||||||
case ECommander::ATTACK:
|
case ECommander::ATTACK:
|
||||||
scp.accumulatedBonus.type = Bonus::PRIMARY_SKILL;
|
scp.accumulatedBonus.type = BonusType::PRIMARY_SKILL;
|
||||||
scp.accumulatedBonus.subtype = PrimarySkill::ATTACK;
|
scp.accumulatedBonus.subtype = PrimarySkill::ATTACK;
|
||||||
break;
|
break;
|
||||||
case ECommander::DEFENSE:
|
case ECommander::DEFENSE:
|
||||||
scp.accumulatedBonus.type = Bonus::PRIMARY_SKILL;
|
scp.accumulatedBonus.type = BonusType::PRIMARY_SKILL;
|
||||||
scp.accumulatedBonus.subtype = PrimarySkill::DEFENSE;
|
scp.accumulatedBonus.subtype = PrimarySkill::DEFENSE;
|
||||||
break;
|
break;
|
||||||
case ECommander::HEALTH:
|
case ECommander::HEALTH:
|
||||||
scp.accumulatedBonus.type = Bonus::STACK_HEALTH;
|
scp.accumulatedBonus.type = BonusType::STACK_HEALTH;
|
||||||
scp.accumulatedBonus.valType = Bonus::PERCENT_TO_BASE;
|
scp.accumulatedBonus.valType = BonusValueType::PERCENT_TO_BASE;
|
||||||
break;
|
break;
|
||||||
case ECommander::DAMAGE:
|
case ECommander::DAMAGE:
|
||||||
scp.accumulatedBonus.type = Bonus::CREATURE_DAMAGE;
|
scp.accumulatedBonus.type = BonusType::CREATURE_DAMAGE;
|
||||||
scp.accumulatedBonus.subtype = 0;
|
scp.accumulatedBonus.subtype = 0;
|
||||||
scp.accumulatedBonus.valType = Bonus::PERCENT_TO_BASE;
|
scp.accumulatedBonus.valType = BonusValueType::PERCENT_TO_BASE;
|
||||||
break;
|
break;
|
||||||
case ECommander::SPEED:
|
case ECommander::SPEED:
|
||||||
scp.accumulatedBonus.type = Bonus::STACKS_SPEED;
|
scp.accumulatedBonus.type = BonusType::STACKS_SPEED;
|
||||||
break;
|
break;
|
||||||
case ECommander::SPELL_POWER:
|
case ECommander::SPELL_POWER:
|
||||||
scp.accumulatedBonus.type = Bonus::MAGIC_RESISTANCE;
|
scp.accumulatedBonus.type = BonusType::MAGIC_RESISTANCE;
|
||||||
scp.accumulatedBonus.val = difference (VLC->creh->skillLevels, c->secondarySkills, ECommander::RESISTANCE);
|
scp.accumulatedBonus.val = difference (VLC->creh->skillLevels, c->secondarySkills, ECommander::RESISTANCE);
|
||||||
sendAndApply (&scp); //additional pack
|
sendAndApply (&scp); //additional pack
|
||||||
scp.accumulatedBonus.type = Bonus::CREATURE_SPELL_POWER;
|
scp.accumulatedBonus.type = BonusType::CREATURE_SPELL_POWER;
|
||||||
scp.accumulatedBonus.val = difference (VLC->creh->skillLevels, c->secondarySkills, ECommander::SPELL_POWER) * 100; //like hero with spellpower = ability level
|
scp.accumulatedBonus.val = difference (VLC->creh->skillLevels, c->secondarySkills, ECommander::SPELL_POWER) * 100; //like hero with spellpower = ability level
|
||||||
sendAndApply (&scp); //additional pack
|
sendAndApply (&scp); //additional pack
|
||||||
scp.accumulatedBonus.type = Bonus::CASTS;
|
scp.accumulatedBonus.type = BonusType::CASTS;
|
||||||
scp.accumulatedBonus.val = difference (VLC->creh->skillLevels, c->secondarySkills, ECommander::CASTS);
|
scp.accumulatedBonus.val = difference (VLC->creh->skillLevels, c->secondarySkills, ECommander::CASTS);
|
||||||
sendAndApply (&scp); //additional pack
|
sendAndApply (&scp); //additional pack
|
||||||
scp.accumulatedBonus.type = Bonus::CREATURE_ENCHANT_POWER; //send normally
|
scp.accumulatedBonus.type = BonusType::CREATURE_ENCHANT_POWER; //send normally
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -632,9 +632,9 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
|
|||||||
|
|
||||||
if(!finishingBattle->isDraw() && finishingBattle->winnerHero)
|
if(!finishingBattle->isDraw() && finishingBattle->winnerHero)
|
||||||
{
|
{
|
||||||
if (int eagleEyeLevel = finishingBattle->winnerHero->valOfBonuses(Bonus::LEARN_BATTLE_SPELL_LEVEL_LIMIT, -1))
|
if (int eagleEyeLevel = finishingBattle->winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_LEVEL_LIMIT, -1))
|
||||||
{
|
{
|
||||||
double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(Bonus::LEARN_BATTLE_SPELL_CHANCE, 0);
|
double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_CHANCE, 0);
|
||||||
for(auto & spellId : battleInfo->sides.at(!battleResult.data->winner).usedSpellsHistory)
|
for(auto & spellId : battleInfo->sides.at(!battleResult.data->winner).usedSpellsHistory)
|
||||||
{
|
{
|
||||||
auto spell = spellId.toSpell(VLC->spells());
|
auto spell = spellId.toSpell(VLC->spells());
|
||||||
@ -946,7 +946,7 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
bat.flags |= BattleAttack::UNLUCKY;
|
bat.flags |= BattleAttack::UNLUCKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getRandomGenerator().nextInt(99) < attacker->valOfBonuses(Bonus::DOUBLE_DAMAGE_CHANCE))
|
if (getRandomGenerator().nextInt(99) < attacker->valOfBonuses(BonusType::DOUBLE_DAMAGE_CHANCE))
|
||||||
{
|
{
|
||||||
bat.flags |= BattleAttack::DEATH_BLOW;
|
bat.flags |= BattleAttack::DEATH_BLOW;
|
||||||
}
|
}
|
||||||
@ -954,7 +954,7 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
const auto * owner = gs->curB->getHero(attacker->unitOwner());
|
const auto * owner = gs->curB->getHero(attacker->unitOwner());
|
||||||
if(owner)
|
if(owner)
|
||||||
{
|
{
|
||||||
int chance = owner->valOfBonuses(Bonus::BONUS_DAMAGE_CHANCE, attacker->creatureIndex());
|
int chance = owner->valOfBonuses(BonusType::BONUS_DAMAGE_CHANCE, attacker->creatureIndex());
|
||||||
if (chance > getRandomGenerator().nextInt(99))
|
if (chance > getRandomGenerator().nextInt(99))
|
||||||
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
||||||
}
|
}
|
||||||
@ -973,7 +973,7 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
drainedLife += applyBattleEffects(bat, attackerState, fireShield, stack, distance, true);
|
drainedLife += applyBattleEffects(bat, attackerState, fireShield, stack, distance, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const Bonus> bonus = attacker->getBonusLocalFirst(Selector::type()(Bonus::SPELL_LIKE_ATTACK));
|
std::shared_ptr<const Bonus> bonus = attacker->getBonusLocalFirst(Selector::type()(BonusType::SPELL_LIKE_ATTACK));
|
||||||
if(bonus && ranged) //TODO: make it work in melee?
|
if(bonus && ranged) //TODO: make it work in melee?
|
||||||
{
|
{
|
||||||
//this is need for displaying hit animation
|
//this is need for displaying hit animation
|
||||||
@ -1142,23 +1142,23 @@ int64_t CGameHandler::applyBattleEffects(BattleAttack & bat, std::shared_ptr<bat
|
|||||||
int64_t drainedLife = 0;
|
int64_t drainedLife = 0;
|
||||||
|
|
||||||
//life drain handling
|
//life drain handling
|
||||||
if(attackerState->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
|
if(attackerState->hasBonusOfType(BonusType::LIFE_DRAIN) && def->isLiving())
|
||||||
{
|
{
|
||||||
int64_t toHeal = bsa.damageAmount * attackerState->valOfBonuses(Bonus::LIFE_DRAIN) / 100;
|
int64_t toHeal = bsa.damageAmount * attackerState->valOfBonuses(BonusType::LIFE_DRAIN) / 100;
|
||||||
attackerState->heal(toHeal, EHealLevel::RESURRECT, EHealPower::PERMANENT);
|
attackerState->heal(toHeal, EHealLevel::RESURRECT, EHealPower::PERMANENT);
|
||||||
drainedLife += toHeal;
|
drainedLife += toHeal;
|
||||||
}
|
}
|
||||||
|
|
||||||
//soul steal handling
|
//soul steal handling
|
||||||
if(attackerState->hasBonusOfType(Bonus::SOUL_STEAL) && def->isLiving())
|
if(attackerState->hasBonusOfType(BonusType::SOUL_STEAL) && def->isLiving())
|
||||||
{
|
{
|
||||||
//we can have two bonuses - one with subtype 0 and another with subtype 1
|
//we can have two bonuses - one with subtype 0 and another with subtype 1
|
||||||
//try to use permanent first, use only one of two
|
//try to use permanent first, use only one of two
|
||||||
for(si32 subtype = 1; subtype >= 0; subtype--)
|
for(si32 subtype = 1; subtype >= 0; subtype--)
|
||||||
{
|
{
|
||||||
if(attackerState->hasBonusOfType(Bonus::SOUL_STEAL, subtype))
|
if(attackerState->hasBonusOfType(BonusType::SOUL_STEAL, subtype))
|
||||||
{
|
{
|
||||||
int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(Bonus::SOUL_STEAL, subtype) * attackerState->getMaxHealth();
|
int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(BonusType::SOUL_STEAL, subtype) * attackerState->getMaxHealth();
|
||||||
attackerState->heal(toHeal, EHealLevel::OVERHEAL, ((subtype == 0) ? EHealPower::ONE_BATTLE : EHealPower::PERMANENT));
|
attackerState->heal(toHeal, EHealLevel::OVERHEAL, ((subtype == 0) ? EHealPower::ONE_BATTLE : EHealPower::PERMANENT));
|
||||||
drainedLife += toHeal;
|
drainedLife += toHeal;
|
||||||
break;
|
break;
|
||||||
@ -1170,13 +1170,13 @@ int64_t CGameHandler::applyBattleEffects(BattleAttack & bat, std::shared_ptr<bat
|
|||||||
//fire shield handling
|
//fire shield handling
|
||||||
if(!bat.shot() &&
|
if(!bat.shot() &&
|
||||||
!def->isClone() &&
|
!def->isClone() &&
|
||||||
def->hasBonusOfType(Bonus::FIRE_SHIELD) &&
|
def->hasBonusOfType(BonusType::FIRE_SHIELD) &&
|
||||||
!attackerState->hasBonusOfType(Bonus::FIRE_IMMUNITY) &&
|
!attackerState->hasBonusOfType(BonusType::FIRE_IMMUNITY) &&
|
||||||
CStack::isMeleeAttackPossible(attackerState.get(), def) // attacked needs to be adjacent to defender for fire shield to trigger (e.g. Dragon Breath attack)
|
CStack::isMeleeAttackPossible(attackerState.get(), def) // attacked needs to be adjacent to defender for fire shield to trigger (e.g. Dragon Breath attack)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
//TODO: use damage with bonus but without penalties
|
//TODO: use damage with bonus but without penalties
|
||||||
auto fireShieldDamage = (std::min<int64_t>(def->getAvailableHealth(), bsa.damageAmount) * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100;
|
auto fireShieldDamage = (std::min<int64_t>(def->getAvailableHealth(), bsa.damageAmount) * def->valOfBonuses(BonusType::FIRE_SHIELD)) / 100;
|
||||||
fireShield.push_back(std::make_pair(def, fireShieldDamage));
|
fireShield.push_back(std::make_pair(def, fireShieldDamage));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1371,7 +1371,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (curStack->hasBonusOfType(Bonus::FLYING))
|
if (curStack->hasBonusOfType(BonusType::FLYING))
|
||||||
{
|
{
|
||||||
if (path.second <= creSpeed && path.first.size() > 0)
|
if (path.second <= creSpeed && path.first.size() > 0)
|
||||||
{
|
{
|
||||||
@ -1825,7 +1825,7 @@ void CGameHandler::newTurn()
|
|||||||
{
|
{
|
||||||
for(auto stack : hero->stacks)
|
for(auto stack : hero->stacks)
|
||||||
{
|
{
|
||||||
if(stack.second->hasBonusOfType(Bonus::SPECIAL_CRYSTAL_GENERATION))
|
if(stack.second->hasBonusOfType(BonusType::SPECIAL_CRYSTAL_GENERATION))
|
||||||
{
|
{
|
||||||
hasCrystalGenCreature = true;
|
hasCrystalGenCreature = true;
|
||||||
break;
|
break;
|
||||||
@ -1838,7 +1838,7 @@ void CGameHandler::newTurn()
|
|||||||
{
|
{
|
||||||
for(auto stack : town->stacks)
|
for(auto stack : town->stacks)
|
||||||
{
|
{
|
||||||
if(stack.second->hasBonusOfType(Bonus::SPECIAL_CRYSTAL_GENERATION))
|
if(stack.second->hasBonusOfType(BonusType::SPECIAL_CRYSTAL_GENERATION))
|
||||||
{
|
{
|
||||||
hasCrystalGenCreature = true;
|
hasCrystalGenCreature = true;
|
||||||
break;
|
break;
|
||||||
@ -1868,7 +1868,7 @@ void CGameHandler::newTurn()
|
|||||||
{
|
{
|
||||||
for (int k = 0; k < GameConstants::RESOURCE_QUANTITY; k++)
|
for (int k = 0; k < GameConstants::RESOURCE_QUANTITY; k++)
|
||||||
{
|
{
|
||||||
n.res[elem.first][k] += h->valOfBonuses(Bonus::GENERATE_RESOURCE, k);
|
n.res[elem.first][k] += h->valOfBonuses(BonusType::GENERATE_RESOURCE, k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1951,13 +1951,13 @@ void CGameHandler::newTurn()
|
|||||||
sendAndApply (&fw);
|
sendAndApply (&fw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (t->hasBonusOfType (Bonus::DARKNESS))
|
if (t->hasBonusOfType (BonusType::DARKNESS))
|
||||||
{
|
{
|
||||||
for (auto & player : gs->players)
|
for (auto & player : gs->players)
|
||||||
{
|
{
|
||||||
if (getPlayerStatus(player.first) == EPlayerStatus::INGAME &&
|
if (getPlayerStatus(player.first) == EPlayerStatus::INGAME &&
|
||||||
getPlayerRelations(player.first, t->tempOwner) == PlayerRelations::ENEMIES)
|
getPlayerRelations(player.first, t->tempOwner) == PlayerRelations::ENEMIES)
|
||||||
changeFogOfWar(t->visitablePos(), t->getBonusLocalFirst(Selector::type()(Bonus::DARKNESS))->val, player.first, true);
|
changeFogOfWar(t->visitablePos(), t->getBonusLocalFirst(Selector::type()(BonusType::DARKNESS))->val, player.first, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2281,8 +2281,8 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
|||||||
auto pathfinderHelper = std::make_unique<CPathfinderHelper>(gs, h, PathfinderOptions());
|
auto pathfinderHelper = std::make_unique<CPathfinderHelper>(gs, h, PathfinderOptions());
|
||||||
auto ti = pathfinderHelper->getTurnInfo();
|
auto ti = pathfinderHelper->getTurnInfo();
|
||||||
|
|
||||||
const bool canFly = pathfinderHelper->hasBonusOfType(Bonus::FLYING_MOVEMENT) || (h->boat && h->boat->layer == EPathfindingLayer::AIR);
|
const bool canFly = pathfinderHelper->hasBonusOfType(BonusType::FLYING_MOVEMENT) || (h->boat && h->boat->layer == EPathfindingLayer::AIR);
|
||||||
const bool canWalkOnSea = pathfinderHelper->hasBonusOfType(Bonus::WATER_WALKING) || (h->boat && h->boat->layer == EPathfindingLayer::WATER);
|
const bool canWalkOnSea = pathfinderHelper->hasBonusOfType(BonusType::WATER_WALKING) || (h->boat && h->boat->layer == EPathfindingLayer::WATER);
|
||||||
const int cost = pathfinderHelper->getMovementCost(h->visitablePos(), hmpos, nullptr, nullptr, h->movement);
|
const int cost = pathfinderHelper->getMovementCost(h->visitablePos(), hmpos, nullptr, nullptr, h->movement);
|
||||||
|
|
||||||
//it's a rock or blocked and not visitable tile
|
//it's a rock or blocked and not visitable tile
|
||||||
@ -2751,8 +2751,8 @@ void CGameHandler::useScholarSkill(ObjectInstanceID fromHero, ObjectInstanceID t
|
|||||||
{
|
{
|
||||||
const CGHeroInstance * h1 = getHero(fromHero);
|
const CGHeroInstance * h1 = getHero(fromHero);
|
||||||
const CGHeroInstance * h2 = getHero(toHero);
|
const CGHeroInstance * h2 = getHero(toHero);
|
||||||
int h1_scholarSpellLevel = h1->valOfBonuses(Bonus::LEARN_MEETING_SPELL_LIMIT, -1);
|
int h1_scholarSpellLevel = h1->valOfBonuses(BonusType::LEARN_MEETING_SPELL_LIMIT, -1);
|
||||||
int h2_scholarSpellLevel = h2->valOfBonuses(Bonus::LEARN_MEETING_SPELL_LIMIT, -1);
|
int h2_scholarSpellLevel = h2->valOfBonuses(BonusType::LEARN_MEETING_SPELL_LIMIT, -1);
|
||||||
|
|
||||||
if (h1_scholarSpellLevel < h2_scholarSpellLevel)
|
if (h1_scholarSpellLevel < h2_scholarSpellLevel)
|
||||||
{
|
{
|
||||||
@ -3636,7 +3636,7 @@ bool CGameHandler::razeStructure (ObjectInstanceID tid, BuildingID bid)
|
|||||||
// {
|
// {
|
||||||
// RemoveBonus rb(RemoveBonus::TOWN);
|
// RemoveBonus rb(RemoveBonus::TOWN);
|
||||||
// rb.whoID = t->id;
|
// rb.whoID = t->id;
|
||||||
// rb.source = Bonus::TOWN_STRUCTURE;
|
// rb.source = BonusSource::TOWN_STRUCTURE;
|
||||||
// rb.id = 17;
|
// rb.id = 17;
|
||||||
// sendAndApply(&rb);
|
// sendAndApply(&rb);
|
||||||
// }
|
// }
|
||||||
@ -4322,8 +4322,8 @@ bool CGameHandler::transformInUndead(const IMarket *market, const CGHeroInstance
|
|||||||
//resulting creature - bone dragons or skeletons
|
//resulting creature - bone dragons or skeletons
|
||||||
CreatureID resCreature = CreatureID::SKELETON;
|
CreatureID resCreature = CreatureID::SKELETON;
|
||||||
|
|
||||||
if ((s.hasBonusOfType(Bonus::DRAGON_NATURE)
|
if ((s.hasBonusOfType(BonusType::DRAGON_NATURE)
|
||||||
&& !(s.hasBonusOfType(Bonus::UNDEAD)))
|
&& !(s.hasBonusOfType(BonusType::UNDEAD)))
|
||||||
|| (s.getCreatureID() == CreatureID::HYDRA)
|
|| (s.getCreatureID() == CreatureID::HYDRA)
|
||||||
|| (s.getCreatureID() == CreatureID::CHAOS_HYDRA))
|
|| (s.getCreatureID() == CreatureID::CHAOS_HYDRA))
|
||||||
resCreature = CreatureID::BONE_DRAGON;
|
resCreature = CreatureID::BONE_DRAGON;
|
||||||
@ -4619,12 +4619,12 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
{
|
{
|
||||||
//defensive stance, TODO: filter out spell boosts from bonus (stone skin etc.)
|
//defensive stance, TODO: filter out spell boosts from bonus (stone skin etc.)
|
||||||
SetStackEffect sse;
|
SetStackEffect sse;
|
||||||
Bonus defenseBonusToAdd(Bonus::STACK_GETS_TURN, Bonus::PRIMARY_SKILL, Bonus::OTHER, 20, -1, PrimarySkill::DEFENSE, Bonus::PERCENT_TO_ALL);
|
Bonus defenseBonusToAdd(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 20, -1, PrimarySkill::DEFENSE, BonusValueType::PERCENT_TO_ALL);
|
||||||
Bonus bonus2(Bonus::STACK_GETS_TURN, Bonus::PRIMARY_SKILL, Bonus::OTHER, stack->valOfBonuses(Bonus::DEFENSIVE_STANCE),
|
Bonus bonus2(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, stack->valOfBonuses(BonusType::DEFENSIVE_STANCE),
|
||||||
-1, PrimarySkill::DEFENSE, Bonus::ADDITIVE_VALUE);
|
-1, PrimarySkill::DEFENSE, BonusValueType::ADDITIVE_VALUE);
|
||||||
Bonus alternativeWeakCreatureBonus(Bonus::STACK_GETS_TURN, Bonus::PRIMARY_SKILL, Bonus::OTHER, 1, -1, PrimarySkill::DEFENSE, Bonus::ADDITIVE_VALUE);
|
Bonus alternativeWeakCreatureBonus(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 1, -1, PrimarySkill::DEFENSE, BonusValueType::ADDITIVE_VALUE);
|
||||||
|
|
||||||
BonusList defence = *stack->getBonuses(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE));
|
BonusList defence = *stack->getBonuses(Selector::typeSubtype(BonusType::PRIMARY_SKILL, PrimarySkill::DEFENSE));
|
||||||
int oldDefenceValue = defence.totalValue();
|
int oldDefenceValue = defence.totalValue();
|
||||||
|
|
||||||
defence.push_back(std::make_shared<Bonus>(defenseBonusToAdd));
|
defence.push_back(std::make_shared<Bonus>(defenseBonusToAdd));
|
||||||
@ -4757,11 +4757,11 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
const auto * attackingHero = gs->curB->battleGetFightingHero(ba.side);
|
const auto * attackingHero = gs->curB->battleGetFightingHero(ba.side);
|
||||||
if(attackingHero)
|
if(attackingHero)
|
||||||
{
|
{
|
||||||
totalAttacks += attackingHero->valOfBonuses(Bonus::HERO_GRANTS_ATTACKS, stack->creatureIndex());
|
totalAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, stack->creatureIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const bool firstStrike = destinationStack->hasBonusOfType(Bonus::FIRST_STRIKE);
|
const bool firstStrike = destinationStack->hasBonusOfType(BonusType::FIRST_STRIKE);
|
||||||
const bool retaliation = destinationStack->ableToRetaliate();
|
const bool retaliation = destinationStack->ableToRetaliate();
|
||||||
for (int i = 0; i < totalAttacks; ++i)
|
for (int i = 0; i < totalAttacks; ++i)
|
||||||
{
|
{
|
||||||
@ -4772,7 +4772,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//move can cause death, eg. by walking into the moat, first strike can cause death or paralysis/petrification
|
//move can cause death, eg. by walking into the moat, first strike can cause death or paralysis/petrification
|
||||||
if(stack->alive() && !stack->hasBonusOfType(Bonus::NOT_ACTIVE) && destinationStack->alive())
|
if(stack->alive() && !stack->hasBonusOfType(BonusType::NOT_ACTIVE) && destinationStack->alive())
|
||||||
{
|
{
|
||||||
makeAttack(stack, destinationStack, (i ? 0 : distance), destinationTile, i==0, false, false);//no distance travelled on second attack
|
makeAttack(stack, destinationStack, (i ? 0 : distance), destinationTile, i==0, false, false);//no distance travelled on second attack
|
||||||
}
|
}
|
||||||
@ -4780,7 +4780,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
//counterattack
|
//counterattack
|
||||||
//we check retaliation twice, so if it unblocked during attack it will work only on next attack
|
//we check retaliation twice, so if it unblocked during attack it will work only on next attack
|
||||||
if(stack->alive()
|
if(stack->alive()
|
||||||
&& !stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
|
&& !stack->hasBonusOfType(BonusType::BLOCKS_RETALIATION)
|
||||||
&& (i == 0 && !firstStrike)
|
&& (i == 0 && !firstStrike)
|
||||||
&& retaliation && destinationStack->ableToRetaliate())
|
&& retaliation && destinationStack->ableToRetaliate())
|
||||||
{
|
{
|
||||||
@ -4789,7 +4789,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//return
|
//return
|
||||||
if(stack->hasBonusOfType(Bonus::RETURN_AFTER_STRIKE)
|
if(stack->hasBonusOfType(BonusType::RETURN_AFTER_STRIKE)
|
||||||
&& target.size() == 3
|
&& target.size() == 3
|
||||||
&& startingPos != stack->getPosition()
|
&& startingPos != stack->getPosition()
|
||||||
&& startingPos == target.at(2).hexValue
|
&& startingPos == target.at(2).hexValue
|
||||||
@ -4829,8 +4829,8 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
makeAttack(stack, destinationStack, 0, destination, true, true, false);
|
makeAttack(stack, destinationStack, 0, destination, true, true, false);
|
||||||
|
|
||||||
//ranged counterattack
|
//ranged counterattack
|
||||||
if (destinationStack->hasBonusOfType(Bonus::RANGED_RETALIATION)
|
if (destinationStack->hasBonusOfType(BonusType::RANGED_RETALIATION)
|
||||||
&& !stack->hasBonusOfType(Bonus::BLOCKS_RANGED_RETALIATION)
|
&& !stack->hasBonusOfType(BonusType::BLOCKS_RANGED_RETALIATION)
|
||||||
&& destinationStack->ableToRetaliate()
|
&& destinationStack->ableToRetaliate()
|
||||||
&& gs->curB->battleCanShoot(destinationStack, stack->getPosition())
|
&& gs->curB->battleCanShoot(destinationStack, stack->getPosition())
|
||||||
&& stack->alive()) //attacker may have died (fire shield)
|
&& stack->alive()) //attacker may have died (fire shield)
|
||||||
@ -4845,7 +4845,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
const auto * attackingHero = gs->curB->battleGetFightingHero(ba.side);
|
const auto * attackingHero = gs->curB->battleGetFightingHero(ba.side);
|
||||||
if(attackingHero)
|
if(attackingHero)
|
||||||
{
|
{
|
||||||
totalRangedAttacks += attackingHero->valOfBonuses(Bonus::HERO_GRANTS_ATTACKS, stack->creatureIndex());
|
totalRangedAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, stack->creatureIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4866,7 +4866,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
{
|
{
|
||||||
auto wrapper = wrapAction(ba);
|
auto wrapper = wrapAction(ba);
|
||||||
const CStack * shooter = gs->curB->battleGetStackByID(ba.stackNumber);
|
const CStack * shooter = gs->curB->battleGetStackByID(ba.stackNumber);
|
||||||
std::shared_ptr<const Bonus> catapultAbility = stack->getBonusLocalFirst(Selector::type()(Bonus::CATAPULT));
|
std::shared_ptr<const Bonus> catapultAbility = stack->getBonusLocalFirst(Selector::type()(BonusType::CATAPULT));
|
||||||
if(!catapultAbility || catapultAbility->subtype < 0)
|
if(!catapultAbility || catapultAbility->subtype < 0)
|
||||||
{
|
{
|
||||||
complain("We do not know how to shoot :P");
|
complain("We do not know how to shoot :P");
|
||||||
@ -4875,7 +4875,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
{
|
{
|
||||||
const CSpell * spell = SpellID(catapultAbility->subtype).toSpell();
|
const CSpell * spell = SpellID(catapultAbility->subtype).toSpell();
|
||||||
spells::BattleCast parameters(gs->curB, shooter, spells::Mode::SPELL_LIKE_ATTACK, spell); //We can shot infinitely by catapult
|
spells::BattleCast parameters(gs->curB, shooter, spells::Mode::SPELL_LIKE_ATTACK, spell); //We can shot infinitely by catapult
|
||||||
auto shotLevel = stack->valOfBonuses(Selector::typeSubtype(Bonus::CATAPULT_EXTRA_SHOTS, catapultAbility->subtype));
|
auto shotLevel = stack->valOfBonuses(Selector::typeSubtype(BonusType::CATAPULT_EXTRA_SHOTS, catapultAbility->subtype));
|
||||||
parameters.setSpellLevel(shotLevel);
|
parameters.setSpellLevel(shotLevel);
|
||||||
parameters.cast(spellEnv, target);
|
parameters.cast(spellEnv, target);
|
||||||
}
|
}
|
||||||
@ -4895,7 +4895,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const battle::Unit * destStack = nullptr;
|
const battle::Unit * destStack = nullptr;
|
||||||
std::shared_ptr<const Bonus> healerAbility = stack->getBonusLocalFirst(Selector::type()(Bonus::HEALER));
|
std::shared_ptr<const Bonus> healerAbility = stack->getBonusLocalFirst(Selector::type()(BonusType::HEALER));
|
||||||
|
|
||||||
if(target.at(0).unitValue)
|
if(target.at(0).unitValue)
|
||||||
destStack = target.at(0).unitValue;
|
destStack = target.at(0).unitValue;
|
||||||
@ -4923,8 +4923,8 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
|||||||
const CStack * stack = gs->curB->battleGetStackByID(ba.stackNumber);
|
const CStack * stack = gs->curB->battleGetStackByID(ba.stackNumber);
|
||||||
SpellID spellID = SpellID(ba.actionSubtype);
|
SpellID spellID = SpellID(ba.actionSubtype);
|
||||||
|
|
||||||
std::shared_ptr<const Bonus> randSpellcaster = stack->getBonus(Selector::type()(Bonus::RANDOM_SPELLCASTER));
|
std::shared_ptr<const Bonus> randSpellcaster = stack->getBonus(Selector::type()(BonusType::RANDOM_SPELLCASTER));
|
||||||
std::shared_ptr<const Bonus> spellcaster = stack->getBonus(Selector::typeSubtype(Bonus::SPELLCASTER, spellID));
|
std::shared_ptr<const Bonus> spellcaster = stack->getBonus(Selector::typeSubtype(BonusType::SPELLCASTER, spellID));
|
||||||
|
|
||||||
//TODO special bonus for genies ability
|
//TODO special bonus for genies ability
|
||||||
if (randSpellcaster && battleGetRandomStackSpell(getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_AIMED) < 0)
|
if (randSpellcaster && battleGetRandomStackSpell(getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_AIMED) < 0)
|
||||||
@ -5148,7 +5148,7 @@ bool CGameHandler::makeCustomAction(BattleAction & ba)
|
|||||||
|
|
||||||
void CGameHandler::stackEnchantedTrigger(const CStack * st)
|
void CGameHandler::stackEnchantedTrigger(const CStack * st)
|
||||||
{
|
{
|
||||||
auto bl = *(st->getBonuses(Selector::type()(Bonus::ENCHANTED)));
|
auto bl = *(st->getBonuses(Selector::type()(BonusType::ENCHANTED)));
|
||||||
for(auto b : bl)
|
for(auto b : bl)
|
||||||
{
|
{
|
||||||
const CSpell * sp = SpellID(b->subtype).toSpell();
|
const CSpell * sp = SpellID(b->subtype).toSpell();
|
||||||
@ -5188,10 +5188,10 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
|
|||||||
if (st->alive())
|
if (st->alive())
|
||||||
{
|
{
|
||||||
//unbind
|
//unbind
|
||||||
if (st->hasBonus(Selector::type()(Bonus::BIND_EFFECT)))
|
if (st->hasBonus(Selector::type()(BonusType::BIND_EFFECT)))
|
||||||
{
|
{
|
||||||
bool unbind = true;
|
bool unbind = true;
|
||||||
BonusList bl = *(st->getBonuses(Selector::type()(Bonus::BIND_EFFECT)));
|
BonusList bl = *(st->getBonuses(Selector::type()(BonusType::BIND_EFFECT)));
|
||||||
auto adjacent = gs->curB->battleAdjacentUnits(st);
|
auto adjacent = gs->curB->battleAdjacentUnits(st);
|
||||||
|
|
||||||
for (auto b : bl)
|
for (auto b : bl)
|
||||||
@ -5219,42 +5219,42 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->hasBonusOfType(Bonus::POISON))
|
if (st->hasBonusOfType(BonusType::POISON))
|
||||||
{
|
{
|
||||||
std::shared_ptr<const Bonus> b = st->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT, SpellID::POISON).And(Selector::type()(Bonus::STACK_HEALTH)));
|
std::shared_ptr<const Bonus> b = st->getBonusLocalFirst(Selector::source(BonusSource::SPELL_EFFECT, SpellID::POISON).And(Selector::type()(BonusType::STACK_HEALTH)));
|
||||||
if (b) //TODO: what if not?...
|
if (b) //TODO: what if not?...
|
||||||
{
|
{
|
||||||
bte.val = std::max (b->val - 10, -(st->valOfBonuses(Bonus::POISON)));
|
bte.val = std::max (b->val - 10, -(st->valOfBonuses(BonusType::POISON)));
|
||||||
if (bte.val < b->val) //(negative) poison effect increases - update it
|
if (bte.val < b->val) //(negative) poison effect increases - update it
|
||||||
{
|
{
|
||||||
bte.effect = Bonus::POISON;
|
bte.effect = vstd::to_underlying(BonusType::POISON);
|
||||||
sendAndApply(&bte);
|
sendAndApply(&bte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(st->hasBonusOfType(Bonus::MANA_DRAIN) && !st->drainedMana)
|
if(st->hasBonusOfType(BonusType::MANA_DRAIN) && !st->drainedMana)
|
||||||
{
|
{
|
||||||
const PlayerColor opponent = gs->curB->otherPlayer(gs->curB->battleGetOwner(st));
|
const PlayerColor opponent = gs->curB->otherPlayer(gs->curB->battleGetOwner(st));
|
||||||
const CGHeroInstance * opponentHero = gs->curB->getHero(opponent);
|
const CGHeroInstance * opponentHero = gs->curB->getHero(opponent);
|
||||||
if(opponentHero)
|
if(opponentHero)
|
||||||
{
|
{
|
||||||
ui32 manaDrained = st->valOfBonuses(Bonus::MANA_DRAIN);
|
ui32 manaDrained = st->valOfBonuses(BonusType::MANA_DRAIN);
|
||||||
vstd::amin(manaDrained, opponentHero->mana);
|
vstd::amin(manaDrained, opponentHero->mana);
|
||||||
if(manaDrained)
|
if(manaDrained)
|
||||||
{
|
{
|
||||||
bte.effect = Bonus::MANA_DRAIN;
|
bte.effect = vstd::to_underlying(BonusType::MANA_DRAIN);
|
||||||
bte.val = manaDrained;
|
bte.val = manaDrained;
|
||||||
bte.additionalInfo = opponentHero->id.getNum(); //for sanity
|
bte.additionalInfo = opponentHero->id.getNum(); //for sanity
|
||||||
sendAndApply(&bte);
|
sendAndApply(&bte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (st->isLiving() && !st->hasBonusOfType(Bonus::FEARLESS))
|
if (st->isLiving() && !st->hasBonusOfType(BonusType::FEARLESS))
|
||||||
{
|
{
|
||||||
bool fearsomeCreature = false;
|
bool fearsomeCreature = false;
|
||||||
for (CStack * stack : gs->curB->stacks)
|
for (CStack * stack : gs->curB->stacks)
|
||||||
{
|
{
|
||||||
if (battleMatchOwner(st, stack) && stack->alive() && stack->hasBonusOfType(Bonus::FEAR))
|
if (battleMatchOwner(st, stack) && stack->alive() && stack->hasBonusOfType(BonusType::FEAR))
|
||||||
{
|
{
|
||||||
fearsomeCreature = true;
|
fearsomeCreature = true;
|
||||||
break;
|
break;
|
||||||
@ -5264,12 +5264,12 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
|
|||||||
{
|
{
|
||||||
if (getRandomGenerator().nextInt(99) < 10) //fixed 10%
|
if (getRandomGenerator().nextInt(99) < 10) //fixed 10%
|
||||||
{
|
{
|
||||||
bte.effect = Bonus::FEAR;
|
bte.effect = vstd::to_underlying(BonusType::FEAR);
|
||||||
sendAndApply(&bte);
|
sendAndApply(&bte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BonusList bl = *(st->getBonuses(Selector::type()(Bonus::ENCHANTER)));
|
BonusList bl = *(st->getBonuses(Selector::type()(BonusType::ENCHANTER)));
|
||||||
int side = gs->curB->whatSide(st->unitOwner());
|
int side = gs->curB->whatSide(st->unitOwner());
|
||||||
if(st->canCast() && gs->curB->battleGetEnchanterCounter(side) == 0)
|
if(st->canCast() && gs->curB->battleGetEnchanterCounter(side) == 0)
|
||||||
{
|
{
|
||||||
@ -5829,7 +5829,7 @@ bool CGameHandler::dig(const CGHeroInstance *h)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::attackCasting(bool ranged, Bonus::BonusType attackMode, const battle::Unit * attacker, const battle::Unit * defender)
|
void CGameHandler::attackCasting(bool ranged, BonusType attackMode, const battle::Unit * attacker, const battle::Unit * defender)
|
||||||
{
|
{
|
||||||
if(attacker->hasBonusOfType(attackMode))
|
if(attacker->hasBonusOfType(attackMode))
|
||||||
{
|
{
|
||||||
@ -5899,7 +5899,7 @@ void CGameHandler::attackCasting(bool ranged, Bonus::BonusType attackMode, const
|
|||||||
|
|
||||||
void CGameHandler::handleAttackBeforeCasting(bool ranged, const CStack * attacker, const CStack * defender)
|
void CGameHandler::handleAttackBeforeCasting(bool ranged, const CStack * attacker, const CStack * defender)
|
||||||
{
|
{
|
||||||
attackCasting(ranged, Bonus::SPELL_BEFORE_ATTACK, attacker, defender); //no death stare / acid breath needed?
|
attackCasting(ranged, BonusType::SPELL_BEFORE_ATTACK, attacker, defender); //no death stare / acid breath needed?
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker, const CStack * defender)
|
void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker, const CStack * defender)
|
||||||
@ -5907,7 +5907,7 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
|||||||
if(!attacker->alive() || !defender->alive()) // can be already dead
|
if(!attacker->alive() || !defender->alive()) // can be already dead
|
||||||
return;
|
return;
|
||||||
|
|
||||||
attackCasting(ranged, Bonus::SPELL_AFTER_ATTACK, attacker, defender);
|
attackCasting(ranged, BonusType::SPELL_AFTER_ATTACK, attacker, defender);
|
||||||
|
|
||||||
if(!defender->alive())
|
if(!defender->alive())
|
||||||
{
|
{
|
||||||
@ -5915,13 +5915,13 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(attacker->hasBonusOfType(Bonus::DEATH_STARE))
|
if(attacker->hasBonusOfType(BonusType::DEATH_STARE))
|
||||||
{
|
{
|
||||||
// mechanics of Death Stare as in H3:
|
// mechanics of Death Stare as in H3:
|
||||||
// each gorgon have 10% chance to kill (counted separately in H3) -> binomial distribution
|
// each gorgon have 10% chance to kill (counted separately in H3) -> binomial distribution
|
||||||
//original formula x = min(x, (gorgons_count + 9)/10);
|
//original formula x = min(x, (gorgons_count + 9)/10);
|
||||||
|
|
||||||
double chanceToKill = attacker->valOfBonuses(Bonus::DEATH_STARE, 0) / 100.0f;
|
double chanceToKill = attacker->valOfBonuses(BonusType::DEATH_STARE, 0) / 100.0f;
|
||||||
vstd::amin(chanceToKill, 1); //cap at 100%
|
vstd::amin(chanceToKill, 1); //cap at 100%
|
||||||
|
|
||||||
std::binomial_distribution<> distribution(attacker->getCount(), chanceToKill);
|
std::binomial_distribution<> distribution(attacker->getCount(), chanceToKill);
|
||||||
@ -5932,7 +5932,7 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
|||||||
int maxToKill = static_cast<int>((attacker->getCount() + cap - 1) / cap); //not much more than chance * count
|
int maxToKill = static_cast<int>((attacker->getCount() + cap - 1) / cap); //not much more than chance * count
|
||||||
vstd::amin(staredCreatures, maxToKill);
|
vstd::amin(staredCreatures, maxToKill);
|
||||||
|
|
||||||
staredCreatures += (attacker->level() * attacker->valOfBonuses(Bonus::DEATH_STARE, 1)) / defender->level();
|
staredCreatures += (attacker->level() * attacker->valOfBonuses(BonusType::DEATH_STARE, 1)) / defender->level();
|
||||||
if(staredCreatures)
|
if(staredCreatures)
|
||||||
{
|
{
|
||||||
//TODO: death stare was not originally available for multiple-hex attacks, but...
|
//TODO: death stare was not originally available for multiple-hex attacks, but...
|
||||||
@ -5952,7 +5952,7 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
int64_t acidDamage = 0;
|
int64_t acidDamage = 0;
|
||||||
TConstBonusListPtr acidBreath = attacker->getBonuses(Selector::type()(Bonus::ACID_BREATH));
|
TConstBonusListPtr acidBreath = attacker->getBonuses(Selector::type()(BonusType::ACID_BREATH));
|
||||||
for(const auto & b : *acidBreath)
|
for(const auto & b : *acidBreath)
|
||||||
{
|
{
|
||||||
if(b->additionalInfo[0] > getRandomGenerator().nextInt(99))
|
if(b->additionalInfo[0] > getRandomGenerator().nextInt(99))
|
||||||
@ -5977,15 +5977,15 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
|||||||
if(!defender->alive())
|
if(!defender->alive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(attacker->hasBonusOfType(Bonus::TRANSMUTATION) && defender->isLiving()) //transmutation mechanics, similar to WoG werewolf ability
|
if(attacker->hasBonusOfType(BonusType::TRANSMUTATION) && defender->isLiving()) //transmutation mechanics, similar to WoG werewolf ability
|
||||||
{
|
{
|
||||||
double chanceToTrigger = attacker->valOfBonuses(Bonus::TRANSMUTATION) / 100.0f;
|
double chanceToTrigger = attacker->valOfBonuses(BonusType::TRANSMUTATION) / 100.0f;
|
||||||
vstd::amin(chanceToTrigger, 1); //cap at 100%
|
vstd::amin(chanceToTrigger, 1); //cap at 100%
|
||||||
|
|
||||||
if(getRandomGenerator().getDoubleRange(0, 1)() > chanceToTrigger)
|
if(getRandomGenerator().getDoubleRange(0, 1)() > chanceToTrigger)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int bonusAdditionalInfo = attacker->getBonus(Selector::type()(Bonus::TRANSMUTATION))->additionalInfo[0];
|
int bonusAdditionalInfo = attacker->getBonus(Selector::type()(BonusType::TRANSMUTATION))->additionalInfo[0];
|
||||||
|
|
||||||
if(defender->unitType()->getId() == bonusAdditionalInfo ||
|
if(defender->unitType()->getId() == bonusAdditionalInfo ||
|
||||||
(bonusAdditionalInfo == CAddInfo::NONE && defender->unitType()->getId() == attacker->unitType()->getId()))
|
(bonusAdditionalInfo == CAddInfo::NONE && defender->unitType()->getId() == attacker->unitType()->getId()))
|
||||||
@ -6002,9 +6002,9 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
|||||||
else
|
else
|
||||||
resurrectInfo.type = attacker->creatureId();
|
resurrectInfo.type = attacker->creatureId();
|
||||||
|
|
||||||
if(attacker->hasBonusOfType((Bonus::TRANSMUTATION), 0))
|
if(attacker->hasBonusOfType((BonusType::TRANSMUTATION), 0))
|
||||||
resurrectInfo.count = std::max((defender->getCount() * defender->getMaxHealth()) / resurrectInfo.type.toCreature()->getMaxHealth(), 1u);
|
resurrectInfo.count = std::max((defender->getCount() * defender->getMaxHealth()) / resurrectInfo.type.toCreature()->getMaxHealth(), 1u);
|
||||||
else if (attacker->hasBonusOfType((Bonus::TRANSMUTATION), 1))
|
else if (attacker->hasBonusOfType((BonusType::TRANSMUTATION), 1))
|
||||||
resurrectInfo.count = defender->getCount();
|
resurrectInfo.count = defender->getCount();
|
||||||
else
|
else
|
||||||
return; //wrong subtype
|
return; //wrong subtype
|
||||||
@ -6019,21 +6019,21 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
|
|||||||
sendAndApply(&addUnits);
|
sendAndApply(&addUnits);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(attacker->hasBonusOfType(Bonus::DESTRUCTION, 0) || attacker->hasBonusOfType(Bonus::DESTRUCTION, 1))
|
if(attacker->hasBonusOfType(BonusType::DESTRUCTION, 0) || attacker->hasBonusOfType(BonusType::DESTRUCTION, 1))
|
||||||
{
|
{
|
||||||
double chanceToTrigger = 0;
|
double chanceToTrigger = 0;
|
||||||
int amountToDie = 0;
|
int amountToDie = 0;
|
||||||
|
|
||||||
if(attacker->hasBonusOfType(Bonus::DESTRUCTION, 0)) //killing by percentage
|
if(attacker->hasBonusOfType(BonusType::DESTRUCTION, 0)) //killing by percentage
|
||||||
{
|
{
|
||||||
chanceToTrigger = attacker->valOfBonuses(Bonus::DESTRUCTION, 0) / 100.0f;
|
chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, 0) / 100.0f;
|
||||||
int percentageToDie = attacker->getBonus(Selector::type()(Bonus::DESTRUCTION).And(Selector::subtype()(0)))->additionalInfo[0];
|
int percentageToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(0)))->additionalInfo[0];
|
||||||
amountToDie = static_cast<int>(defender->getCount() * percentageToDie * 0.01f);
|
amountToDie = static_cast<int>(defender->getCount() * percentageToDie * 0.01f);
|
||||||
}
|
}
|
||||||
else if(attacker->hasBonusOfType(Bonus::DESTRUCTION, 1)) //killing by count
|
else if(attacker->hasBonusOfType(BonusType::DESTRUCTION, 1)) //killing by count
|
||||||
{
|
{
|
||||||
chanceToTrigger = attacker->valOfBonuses(Bonus::DESTRUCTION, 1) / 100.0f;
|
chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, 1) / 100.0f;
|
||||||
amountToDie = attacker->getBonus(Selector::type()(Bonus::DESTRUCTION).And(Selector::subtype()(1)))->additionalInfo[0];
|
amountToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(1)))->additionalInfo[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100%
|
vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100%
|
||||||
@ -6371,9 +6371,9 @@ void CGameHandler::runBattle()
|
|||||||
|
|
||||||
for (CStack * stack : initialStacks)
|
for (CStack * stack : initialStacks)
|
||||||
{
|
{
|
||||||
if (stack->hasBonusOfType(Bonus::SUMMON_GUARDIANS))
|
if (stack->hasBonusOfType(BonusType::SUMMON_GUARDIANS))
|
||||||
{
|
{
|
||||||
std::shared_ptr<const Bonus> summonInfo = stack->getBonus(Selector::type()(Bonus::SUMMON_GUARDIANS));
|
std::shared_ptr<const Bonus> summonInfo = stack->getBonus(Selector::type()(BonusType::SUMMON_GUARDIANS));
|
||||||
auto accessibility = getAccesibility();
|
auto accessibility = getAccesibility();
|
||||||
CreatureID creatureData = CreatureID(summonInfo->subtype);
|
CreatureID creatureData = CreatureID(summonInfo->subtype);
|
||||||
std::vector<BattleHex> targetHexes;
|
std::vector<BattleHex> targetHexes;
|
||||||
@ -6418,7 +6418,7 @@ void CGameHandler::runBattle()
|
|||||||
auto h = gs->curB->battleGetFightingHero(i);
|
auto h = gs->curB->battleGetFightingHero(i);
|
||||||
if (h)
|
if (h)
|
||||||
{
|
{
|
||||||
TConstBonusListPtr bl = h->getBonuses(Selector::type()(Bonus::OPENING_BATTLE_SPELL));
|
TConstBonusListPtr bl = h->getBonuses(Selector::type()(BonusType::OPENING_BATTLE_SPELL));
|
||||||
|
|
||||||
for (auto b : *bl)
|
for (auto b : *bl)
|
||||||
{
|
{
|
||||||
@ -6486,11 +6486,11 @@ void CGameHandler::runBattle()
|
|||||||
{
|
{
|
||||||
BattleTriggerEffect bte;
|
BattleTriggerEffect bte;
|
||||||
bte.stackID = stack->unitId();
|
bte.stackID = stack->unitId();
|
||||||
bte.effect = Bonus::HP_REGENERATION;
|
bte.effect = vstd::to_underlying(BonusType::HP_REGENERATION);
|
||||||
|
|
||||||
const int32_t lostHealth = stack->getMaxHealth() - stack->getFirstHPleft();
|
const int32_t lostHealth = stack->getMaxHealth() - stack->getFirstHPleft();
|
||||||
if(stack->hasBonusOfType(Bonus::HP_REGENERATION))
|
if(stack->hasBonusOfType(BonusType::HP_REGENERATION))
|
||||||
bte.val = std::min(lostHealth, stack->valOfBonuses(Bonus::HP_REGENERATION));
|
bte.val = std::min(lostHealth, stack->valOfBonuses(BonusType::HP_REGENERATION));
|
||||||
|
|
||||||
if(bte.val) // anything to heal
|
if(bte.val) // anything to heal
|
||||||
sendAndApply(&bte);
|
sendAndApply(&bte);
|
||||||
@ -6537,7 +6537,7 @@ void CGameHandler::runBattle()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE)) //while in berserk
|
if (next->hasBonusOfType(BonusType::ATTACKS_NEAREST_CREATURE)) //while in berserk
|
||||||
{
|
{
|
||||||
logGlobal->trace("Handle Berserk effect");
|
logGlobal->trace("Handle Berserk effect");
|
||||||
std::pair<const battle::Unit *, BattleHex> attackInfo = curB.getNearestStack(next);
|
std::pair<const battle::Unit *, BattleHex> attackInfo = curB.getNearestStack(next);
|
||||||
@ -6565,7 +6565,7 @@ void CGameHandler::runBattle()
|
|||||||
const int stackCreatureId = next->unitType()->getId();
|
const int stackCreatureId = next->unitType()->getId();
|
||||||
|
|
||||||
if ((stackCreatureId == CreatureID::ARROW_TOWERS || stackCreatureId == CreatureID::BALLISTA)
|
if ((stackCreatureId == CreatureID::ARROW_TOWERS || stackCreatureId == CreatureID::BALLISTA)
|
||||||
&& (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(Bonus::MANUAL_CONTROL, stackCreatureId)))
|
&& (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, stackCreatureId)))
|
||||||
{
|
{
|
||||||
BattleAction attack;
|
BattleAction attack;
|
||||||
attack.actionType = EActionType::SHOOT;
|
attack.actionType = EActionType::SHOOT;
|
||||||
@ -6610,7 +6610,7 @@ void CGameHandler::runBattle()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(Bonus::MANUAL_CONTROL, CreatureID::CATAPULT))
|
if (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, CreatureID::CATAPULT))
|
||||||
{
|
{
|
||||||
BattleAction attack;
|
BattleAction attack;
|
||||||
attack.actionType = EActionType::CATAPULT;
|
attack.actionType = EActionType::CATAPULT;
|
||||||
@ -6635,7 +6635,7 @@ void CGameHandler::runBattle()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(Bonus::MANUAL_CONTROL, CreatureID::FIRST_AID_TENT))
|
if (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(BonusType::MANUAL_CONTROL, CreatureID::FIRST_AID_TENT))
|
||||||
{
|
{
|
||||||
RandomGeneratorUtil::randomShuffle(possibleStacks, getRandomGenerator());
|
RandomGeneratorUtil::randomShuffle(possibleStacks, getRandomGenerator());
|
||||||
const CStack * toBeHealed = possibleStacks.front();
|
const CStack * toBeHealed = possibleStacks.front();
|
||||||
@ -6720,7 +6720,7 @@ void CGameHandler::runBattle()
|
|||||||
{
|
{
|
||||||
BattleTriggerEffect bte;
|
BattleTriggerEffect bte;
|
||||||
bte.stackID = next->unitId();
|
bte.stackID = next->unitId();
|
||||||
bte.effect = Bonus::MORALE;
|
bte.effect = vstd::to_underlying(BonusType::MORALE);
|
||||||
bte.val = 1;
|
bte.val = 1;
|
||||||
bte.additionalInfo = 0;
|
bte.additionalInfo = 0;
|
||||||
sendAndApply(&bte); //play animation
|
sendAndApply(&bte); //play animation
|
||||||
@ -6872,7 +6872,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
|
|||||||
///Give all spells with bonus (to allow banned spells)
|
///Give all spells with bonus (to allow banned spells)
|
||||||
GiveBonus giveBonus(GiveBonus::ETarget::HERO);
|
GiveBonus giveBonus(GiveBonus::ETarget::HERO);
|
||||||
giveBonus.id = hero->id.getNum();
|
giveBonus.id = hero->id.getNum();
|
||||||
giveBonus.bonus = Bonus(Bonus::PERMANENT, Bonus::SPELLS_OF_LEVEL, Bonus::OTHER, 0, 0);
|
giveBonus.bonus = Bonus(BonusDuration::PERMANENT, BonusType::SPELLS_OF_LEVEL, BonusSource::OTHER, 0, 0);
|
||||||
//start with level 0 to skip abilities
|
//start with level 0 to skip abilities
|
||||||
for (int level = 1; level <= GameConstants::SPELL_LEVELS; level++)
|
for (int level = 1; level <= GameConstants::SPELL_LEVELS; level++)
|
||||||
{
|
{
|
||||||
@ -7017,9 +7017,9 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
|
|||||||
sendAndApply(&smp);
|
sendAndApply(&smp);
|
||||||
|
|
||||||
GiveBonus gb(GiveBonus::ETarget::HERO);
|
GiveBonus gb(GiveBonus::ETarget::HERO);
|
||||||
gb.bonus.type = Bonus::FREE_SHIP_BOARDING;
|
gb.bonus.type = BonusType::FREE_SHIP_BOARDING;
|
||||||
gb.bonus.duration = Bonus::ONE_DAY;
|
gb.bonus.duration = BonusDuration::ONE_DAY;
|
||||||
gb.bonus.source = Bonus::OTHER;
|
gb.bonus.source = BonusSource::OTHER;
|
||||||
gb.id = hero->id.getNum();
|
gb.id = hero->id.getNum();
|
||||||
giveHeroBonus(&gb);
|
giveHeroBonus(&gb);
|
||||||
}
|
}
|
||||||
|
@ -343,7 +343,7 @@ public:
|
|||||||
void newTurn();
|
void newTurn();
|
||||||
void handleAttackBeforeCasting(bool ranged, const CStack * attacker, const CStack * defender);
|
void handleAttackBeforeCasting(bool ranged, const CStack * attacker, const CStack * defender);
|
||||||
void handleAfterAttackCasting(bool ranged, const CStack * attacker, const CStack * defender);
|
void handleAfterAttackCasting(bool ranged, const CStack * attacker, const CStack * defender);
|
||||||
void attackCasting(bool ranged, Bonus::BonusType attackMode, const battle::Unit * attacker, const battle::Unit * defender);
|
void attackCasting(bool ranged, BonusType attackMode, const battle::Unit * attacker, const battle::Unit * defender);
|
||||||
bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, const std::vector<ArtifactPosition> & slot);
|
bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, const std::vector<ArtifactPosition> & slot);
|
||||||
void spawnWanderingMonsters(CreatureID creatureID);
|
void spawnWanderingMonsters(CreatureID creatureID);
|
||||||
void handleCheatCode(std::string & cheat, PlayerColor player, const CGHeroInstance * hero, const CGTownInstance * town, bool & cheated);
|
void handleCheatCode(std::string & cheat, PlayerColor player, const CGHeroInstance * hero, const CGTownInstance * town, bool & cheated);
|
||||||
|
@ -49,7 +49,7 @@ public:
|
|||||||
|
|
||||||
void makeWarMachine()
|
void makeWarMachine()
|
||||||
{
|
{
|
||||||
addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::SIEGE_WEAPON, Bonus::CREATURE_ABILITY, 1, 0));
|
addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SIEGE_WEAPON, BonusSource::CREATURE_ABILITY, 1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void redirectBonusesToFake()
|
void redirectBonusesToFake()
|
||||||
@ -325,7 +325,7 @@ TEST_F(BattleMatchOwnerTest, hypnotizedToSelf)
|
|||||||
{
|
{
|
||||||
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
||||||
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
||||||
unit1.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::HYPNOTIZED, Bonus::CREATURE_ABILITY, 0, 0));
|
unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, 0));
|
||||||
|
|
||||||
setDefaultExpectations();
|
setDefaultExpectations();
|
||||||
|
|
||||||
@ -356,7 +356,7 @@ TEST_F(BattleMatchOwnerTest, hypnotizedToNormalAlly)
|
|||||||
{
|
{
|
||||||
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
||||||
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
||||||
unit1.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::HYPNOTIZED, Bonus::CREATURE_ABILITY, 0, 0));
|
unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, 0));
|
||||||
|
|
||||||
UnitFake & unit2 = unitsFake.add(BattleSide::ATTACKER);
|
UnitFake & unit2 = unitsFake.add(BattleSide::ATTACKER);
|
||||||
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
||||||
@ -376,7 +376,7 @@ TEST_F(BattleMatchOwnerTest, normalToHypnotizedAlly)
|
|||||||
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
||||||
UnitFake & unit2 = unitsFake.add(BattleSide::ATTACKER);
|
UnitFake & unit2 = unitsFake.add(BattleSide::ATTACKER);
|
||||||
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
||||||
unit2.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::HYPNOTIZED, Bonus::CREATURE_ABILITY, 0, 0));
|
unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, 0));
|
||||||
|
|
||||||
setDefaultExpectations();
|
setDefaultExpectations();
|
||||||
|
|
||||||
@ -391,11 +391,11 @@ TEST_F(BattleMatchOwnerTest, hypnotizedToHypnotizedAlly)
|
|||||||
{
|
{
|
||||||
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
||||||
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
||||||
unit1.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::HYPNOTIZED, Bonus::CREATURE_ABILITY, 0, 0));
|
unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, 0));
|
||||||
|
|
||||||
UnitFake & unit2 = unitsFake.add(BattleSide::ATTACKER);
|
UnitFake & unit2 = unitsFake.add(BattleSide::ATTACKER);
|
||||||
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
||||||
unit2.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::HYPNOTIZED, Bonus::CREATURE_ABILITY, 0, 0));
|
unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, 0));
|
||||||
|
|
||||||
setDefaultExpectations();
|
setDefaultExpectations();
|
||||||
|
|
||||||
@ -427,7 +427,7 @@ TEST_F(BattleMatchOwnerTest, hypnotizedToNormalEnemy)
|
|||||||
{
|
{
|
||||||
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
||||||
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
||||||
unit1.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::HYPNOTIZED, Bonus::CREATURE_ABILITY, 0, 0));
|
unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, 0));
|
||||||
|
|
||||||
UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
|
UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
|
||||||
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
||||||
@ -447,7 +447,7 @@ TEST_F(BattleMatchOwnerTest, normalToHypnotizedEnemy)
|
|||||||
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
||||||
UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
|
UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
|
||||||
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
||||||
unit2.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::HYPNOTIZED, Bonus::CREATURE_ABILITY, 0, 0));
|
unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, 0));
|
||||||
|
|
||||||
setDefaultExpectations();
|
setDefaultExpectations();
|
||||||
|
|
||||||
@ -462,11 +462,11 @@ TEST_F(BattleMatchOwnerTest, hypnotizedToHypnotizedEnemy)
|
|||||||
{
|
{
|
||||||
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
||||||
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
EXPECT_CALL(unit1, unitId()).WillRepeatedly(Return(42));
|
||||||
unit1.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::HYPNOTIZED, Bonus::CREATURE_ABILITY, 0, 0));
|
unit1.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, 0));
|
||||||
|
|
||||||
UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
|
UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
|
||||||
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
EXPECT_CALL(unit2, unitId()).WillRepeatedly(Return(4242));
|
||||||
unit2.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::HYPNOTIZED, Bonus::CREATURE_ABILITY, 0, 0));
|
unit2.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::HYPNOTIZED, BonusSource::CREATURE_ABILITY, 0, 0));
|
||||||
|
|
||||||
setDefaultExpectations();
|
setDefaultExpectations();
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
EXPECT_CALL(mock, getAllBonuses(_, _, _, _)).WillRepeatedly(Invoke(&bonusMock, &BonusBearerMock::getAllBonuses));
|
EXPECT_CALL(mock, getAllBonuses(_, _, _, _)).WillRepeatedly(Invoke(&bonusMock, &BonusBearerMock::getAllBonuses));
|
||||||
EXPECT_CALL(mock, getTreeVersion()).WillRepeatedly(Return(1));
|
EXPECT_CALL(mock, getTreeVersion()).WillRepeatedly(Return(1));
|
||||||
|
|
||||||
bonusMock.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::STACK_HEALTH, Bonus::CREATURE_ABILITY, UNIT_HEALTH, 0));
|
bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, UNIT_HEALTH, 0));
|
||||||
|
|
||||||
EXPECT_CALL(mock, unitBaseAmount()).WillRepeatedly(Return(UNIT_AMOUNT));
|
EXPECT_CALL(mock, unitBaseAmount()).WillRepeatedly(Return(UNIT_AMOUNT));
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ TEST_F(HealthTest, singleUnitStack)
|
|||||||
EXPECT_CALL(mock, getAllBonuses(_, _, _, _)).WillRepeatedly(Invoke(&bonusMock, &BonusBearerMock::getAllBonuses));
|
EXPECT_CALL(mock, getAllBonuses(_, _, _, _)).WillRepeatedly(Invoke(&bonusMock, &BonusBearerMock::getAllBonuses));
|
||||||
EXPECT_CALL(mock, getTreeVersion()).WillRepeatedly(Return(1));
|
EXPECT_CALL(mock, getTreeVersion()).WillRepeatedly(Return(1));
|
||||||
|
|
||||||
bonusMock.addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::STACK_HEALTH, Bonus::CREATURE_ABILITY, 300, 0));
|
bonusMock.addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::STACK_HEALTH, BonusSource::CREATURE_ABILITY, 300, 0));
|
||||||
|
|
||||||
EXPECT_CALL(mock, unitBaseAmount()).WillRepeatedly(Return(1));
|
EXPECT_CALL(mock, unitBaseAmount()).WillRepeatedly(Return(1));
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user