1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Merge remote-tracking branch 'upstream/develop' into town-buildings

# Conflicts:
#	lib/CTownHandler.cpp
#	lib/rewardable/Interface.cpp
This commit is contained in:
nordsoft
2023-05-04 22:23:44 +04:00
180 changed files with 5495 additions and 5139 deletions

View File

@@ -136,7 +136,7 @@ static void giveExp(BattleResult &r)
r.exp[1] = 0;
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.additionalInfo = 0;
scp.accumulatedBonus.duration = Bonus::PERMANENT;
scp.accumulatedBonus.duration = BonusDuration::PERMANENT;
scp.accumulatedBonus.turnsRemain = 0;
scp.accumulatedBonus.source = Bonus::COMMANDER;
scp.accumulatedBonus.valType = Bonus::BASE_NUMBER;
scp.accumulatedBonus.source = BonusSource::COMMANDER;
scp.accumulatedBonus.valType = BonusValueType::BASE_NUMBER;
if (skill <= ECommander::SPELL_POWER)
{
scp.which = SetCommanderProperty::BONUS;
@@ -378,36 +378,36 @@ void CGameHandler::levelUpCommander (const CCommanderInstance * c, int skill)
switch (skill)
{
case ECommander::ATTACK:
scp.accumulatedBonus.type = Bonus::PRIMARY_SKILL;
scp.accumulatedBonus.type = BonusType::PRIMARY_SKILL;
scp.accumulatedBonus.subtype = PrimarySkill::ATTACK;
break;
case ECommander::DEFENSE:
scp.accumulatedBonus.type = Bonus::PRIMARY_SKILL;
scp.accumulatedBonus.type = BonusType::PRIMARY_SKILL;
scp.accumulatedBonus.subtype = PrimarySkill::DEFENSE;
break;
case ECommander::HEALTH:
scp.accumulatedBonus.type = Bonus::STACK_HEALTH;
scp.accumulatedBonus.valType = Bonus::PERCENT_TO_BASE;
scp.accumulatedBonus.type = BonusType::STACK_HEALTH;
scp.accumulatedBonus.valType = BonusValueType::PERCENT_TO_BASE;
break;
case ECommander::DAMAGE:
scp.accumulatedBonus.type = Bonus::CREATURE_DAMAGE;
scp.accumulatedBonus.type = BonusType::CREATURE_DAMAGE;
scp.accumulatedBonus.subtype = 0;
scp.accumulatedBonus.valType = Bonus::PERCENT_TO_BASE;
scp.accumulatedBonus.valType = BonusValueType::PERCENT_TO_BASE;
break;
case ECommander::SPEED:
scp.accumulatedBonus.type = Bonus::STACKS_SPEED;
scp.accumulatedBonus.type = BonusType::STACKS_SPEED;
break;
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);
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
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);
sendAndApply (&scp); //additional pack
scp.accumulatedBonus.type = Bonus::CREATURE_ENCHANT_POWER; //send normally
scp.accumulatedBonus.type = BonusType::CREATURE_ENCHANT_POWER; //send normally
break;
}
@@ -632,9 +632,9 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo)
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)
{
auto spell = spellId.toSpell(VLC->spells());
@@ -926,7 +926,7 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
if(counter)
bat.flags |= BattleAttack::COUNTER;
const int attackerLuck = attacker->LuckVal();
const int attackerLuck = attacker->luckVal();
if(attackerLuck > 0)
{
@@ -946,7 +946,7 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
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;
}
@@ -954,7 +954,7 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
const auto * owner = gs->curB->getHero(attacker->unitOwner());
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))
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);
}
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?
{
//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;
//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);
drainedLife += toHeal;
}
//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
//try to use permanent first, use only one of two
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->MaxHealth();
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));
drainedLife += toHeal;
break;
@@ -1170,13 +1170,13 @@ int64_t CGameHandler::applyBattleEffects(BattleAttack & bat, std::shared_ptr<bat
//fire shield handling
if(!bat.shot() &&
!def->isClone() &&
def->hasBonusOfType(Bonus::FIRE_SHIELD) &&
!attackerState->hasBonusOfType(Bonus::FIRE_IMMUNITY) &&
def->hasBonusOfType(BonusType::FIRE_SHIELD) &&
!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)
)
{
//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));
}
@@ -1334,7 +1334,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
ret = path.second;
int creSpeed = curStack->Speed(0, true);
int creSpeed = curStack->speed(0, true);
if (gs->curB->tacticDistance > 0 && creSpeed > 0)
creSpeed = GameConstants::BFIELD_SIZE;
@@ -1371,7 +1371,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
return false;
};
if (curStack->hasBonusOfType(Bonus::FLYING))
if (curStack->hasBonusOfType(BonusType::FLYING))
{
if (path.second <= creSpeed && path.first.size() > 0)
{
@@ -1825,7 +1825,7 @@ void CGameHandler::newTurn()
{
for(auto stack : hero->stacks)
{
if(stack.second->hasBonusOfType(Bonus::SPECIAL_CRYSTAL_GENERATION))
if(stack.second->hasBonusOfType(BonusType::SPECIAL_CRYSTAL_GENERATION))
{
hasCrystalGenCreature = true;
break;
@@ -1838,7 +1838,7 @@ void CGameHandler::newTurn()
{
for(auto stack : town->stacks)
{
if(stack.second->hasBonusOfType(Bonus::SPECIAL_CRYSTAL_GENERATION))
if(stack.second->hasBonusOfType(BonusType::SPECIAL_CRYSTAL_GENERATION))
{
hasCrystalGenCreature = true;
break;
@@ -1868,7 +1868,7 @@ void CGameHandler::newTurn()
{
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);
}
}
if (t->hasBonusOfType (Bonus::DARKNESS))
if (t->hasBonusOfType (BonusType::DARKNESS))
{
for (auto & player : gs->players)
{
if (getPlayerStatus(player.first) == EPlayerStatus::INGAME &&
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 ti = pathfinderHelper->getTurnInfo();
const bool canFly = pathfinderHelper->hasBonusOfType(Bonus::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 canFly = pathfinderHelper->hasBonusOfType(BonusType::FLYING_MOVEMENT) || (h->boat && h->boat->layer == EPathfindingLayer::AIR);
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);
//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 * h2 = getHero(toHero);
int h1_scholarSpellLevel = h1->valOfBonuses(Bonus::LEARN_MEETING_SPELL_LIMIT, -1);
int h2_scholarSpellLevel = h2->valOfBonuses(Bonus::LEARN_MEETING_SPELL_LIMIT, -1);
int h1_scholarSpellLevel = h1->valOfBonuses(BonusType::LEARN_MEETING_SPELL_LIMIT, -1);
int h2_scholarSpellLevel = h2->valOfBonuses(BonusType::LEARN_MEETING_SPELL_LIMIT, -1);
if (h1_scholarSpellLevel < h2_scholarSpellLevel)
{
@@ -3636,7 +3636,7 @@ bool CGameHandler::razeStructure (ObjectInstanceID tid, BuildingID bid)
// {
// RemoveBonus rb(RemoveBonus::TOWN);
// rb.whoID = t->id;
// rb.source = Bonus::TOWN_STRUCTURE;
// rb.source = BonusSource::TOWN_STRUCTURE;
// rb.id = 17;
// sendAndApply(&rb);
// }
@@ -4322,8 +4322,8 @@ bool CGameHandler::transformInUndead(const IMarket *market, const CGHeroInstance
//resulting creature - bone dragons or skeletons
CreatureID resCreature = CreatureID::SKELETON;
if ((s.hasBonusOfType(Bonus::DRAGON_NATURE)
&& !(s.hasBonusOfType(Bonus::UNDEAD)))
if ((s.hasBonusOfType(BonusType::DRAGON_NATURE)
&& !(s.hasBonusOfType(BonusType::UNDEAD)))
|| (s.getCreatureID() == CreatureID::HYDRA)
|| (s.getCreatureID() == CreatureID::CHAOS_HYDRA))
resCreature = CreatureID::BONE_DRAGON;
@@ -4618,12 +4618,12 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
{
//defensive stance, TODO: filter out spell boosts from bonus (stone skin etc.)
SetStackEffect sse;
Bonus defenseBonusToAdd(Bonus::STACK_GETS_TURN, Bonus::PRIMARY_SKILL, Bonus::OTHER, 20, -1, PrimarySkill::DEFENSE, Bonus::PERCENT_TO_ALL);
Bonus bonus2(Bonus::STACK_GETS_TURN, Bonus::PRIMARY_SKILL, Bonus::OTHER, stack->valOfBonuses(Bonus::DEFENSIVE_STANCE),
-1, PrimarySkill::DEFENSE, Bonus::ADDITIVE_VALUE);
Bonus alternativeWeakCreatureBonus(Bonus::STACK_GETS_TURN, Bonus::PRIMARY_SKILL, Bonus::OTHER, 1, -1, PrimarySkill::DEFENSE, Bonus::ADDITIVE_VALUE);
Bonus defenseBonusToAdd(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 20, -1, PrimarySkill::DEFENSE, BonusValueType::PERCENT_TO_ALL);
Bonus bonus2(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, stack->valOfBonuses(BonusType::DEFENSIVE_STANCE),
-1, PrimarySkill::DEFENSE, BonusValueType::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();
defence.push_back(std::make_shared<Bonus>(defenseBonusToAdd));
@@ -4756,11 +4756,11 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
const auto * attackingHero = gs->curB->battleGetFightingHero(ba.side);
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();
for (int i = 0; i < totalAttacks; ++i)
{
@@ -4771,7 +4771,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
}
//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
}
@@ -4779,7 +4779,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
//counterattack
//we check retaliation twice, so if it unblocked during attack it will work only on next attack
if(stack->alive()
&& !stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
&& !stack->hasBonusOfType(BonusType::BLOCKS_RETALIATION)
&& (i == 0 && !firstStrike)
&& retaliation && destinationStack->ableToRetaliate())
{
@@ -4788,7 +4788,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
}
//return
if(stack->hasBonusOfType(Bonus::RETURN_AFTER_STRIKE)
if(stack->hasBonusOfType(BonusType::RETURN_AFTER_STRIKE)
&& target.size() == 3
&& startingPos != stack->getPosition()
&& startingPos == target.at(2).hexValue
@@ -4828,8 +4828,8 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
makeAttack(stack, destinationStack, 0, destination, true, true, false);
//ranged counterattack
if (destinationStack->hasBonusOfType(Bonus::RANGED_RETALIATION)
&& !stack->hasBonusOfType(Bonus::BLOCKS_RANGED_RETALIATION)
if (destinationStack->hasBonusOfType(BonusType::RANGED_RETALIATION)
&& !stack->hasBonusOfType(BonusType::BLOCKS_RANGED_RETALIATION)
&& destinationStack->ableToRetaliate()
&& gs->curB->battleCanShoot(destinationStack, stack->getPosition())
&& stack->alive()) //attacker may have died (fire shield)
@@ -4844,7 +4844,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
const auto * attackingHero = gs->curB->battleGetFightingHero(ba.side);
if(attackingHero)
{
totalRangedAttacks += attackingHero->valOfBonuses(Bonus::HERO_GRANTS_ATTACKS, stack->creatureIndex());
totalRangedAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, stack->creatureIndex());
}
@@ -4865,7 +4865,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
{
auto wrapper = wrapAction(ba);
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)
{
complain("We do not know how to shoot :P");
@@ -4874,7 +4874,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
{
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
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.cast(spellEnv, target);
}
@@ -4894,7 +4894,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
}
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)
destStack = target.at(0).unitValue;
@@ -4922,8 +4922,8 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
const CStack * stack = gs->curB->battleGetStackByID(ba.stackNumber);
SpellID spellID = SpellID(ba.actionSubtype);
std::shared_ptr<const Bonus> randSpellcaster = stack->getBonus(Selector::type()(Bonus::RANDOM_SPELLCASTER));
std::shared_ptr<const Bonus> spellcaster = stack->getBonus(Selector::typeSubtype(Bonus::SPELLCASTER, spellID));
std::shared_ptr<const Bonus> randSpellcaster = stack->getBonus(Selector::type()(BonusType::RANDOM_SPELLCASTER));
std::shared_ptr<const Bonus> spellcaster = stack->getBonus(Selector::typeSubtype(BonusType::SPELLCASTER, spellID));
//TODO special bonus for genies ability
if (randSpellcaster && battleGetRandomStackSpell(getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_AIMED) < 0)
@@ -5147,7 +5147,7 @@ bool CGameHandler::makeCustomAction(BattleAction & ba)
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)
{
const CSpell * sp = SpellID(b->subtype).toSpell();
@@ -5187,10 +5187,10 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
if (st->alive())
{
//unbind
if (st->hasBonus(Selector::type()(Bonus::BIND_EFFECT)))
if (st->hasBonus(Selector::type()(BonusType::BIND_EFFECT)))
{
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);
for (auto b : bl)
@@ -5218,42 +5218,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?...
{
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
{
bte.effect = Bonus::POISON;
bte.effect = vstd::to_underlying(BonusType::POISON);
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 CGHeroInstance * opponentHero = gs->curB->getHero(opponent);
if(opponentHero)
{
ui32 manaDrained = st->valOfBonuses(Bonus::MANA_DRAIN);
ui32 manaDrained = st->valOfBonuses(BonusType::MANA_DRAIN);
vstd::amin(manaDrained, opponentHero->mana);
if(manaDrained)
{
bte.effect = Bonus::MANA_DRAIN;
bte.effect = vstd::to_underlying(BonusType::MANA_DRAIN);
bte.val = manaDrained;
bte.additionalInfo = opponentHero->id.getNum(); //for sanity
sendAndApply(&bte);
}
}
}
if (st->isLiving() && !st->hasBonusOfType(Bonus::FEARLESS))
if (st->isLiving() && !st->hasBonusOfType(BonusType::FEARLESS))
{
bool fearsomeCreature = false;
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;
break;
@@ -5263,12 +5263,12 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
{
if (getRandomGenerator().nextInt(99) < 10) //fixed 10%
{
bte.effect = Bonus::FEAR;
bte.effect = vstd::to_underlying(BonusType::FEAR);
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());
if(st->canCast() && gs->curB->battleGetEnchanterCounter(side) == 0)
{
@@ -5828,7 +5828,7 @@ bool CGameHandler::dig(const CGHeroInstance *h)
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))
{
@@ -5898,7 +5898,7 @@ void CGameHandler::attackCasting(bool ranged, Bonus::BonusType attackMode, const
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)
@@ -5906,7 +5906,7 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
if(!attacker->alive() || !defender->alive()) // can be already dead
return;
attackCasting(ranged, Bonus::SPELL_AFTER_ATTACK, attacker, defender);
attackCasting(ranged, BonusType::SPELL_AFTER_ATTACK, attacker, defender);
if(!defender->alive())
{
@@ -5914,13 +5914,13 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
return;
}
if(attacker->hasBonusOfType(Bonus::DEATH_STARE))
if(attacker->hasBonusOfType(BonusType::DEATH_STARE))
{
// mechanics of Death Stare as in H3:
// each gorgon have 10% chance to kill (counted separately in H3) -> binomial distribution
//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%
std::binomial_distribution<> distribution(attacker->getCount(), chanceToKill);
@@ -5931,7 +5931,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
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)
{
//TODO: death stare was not originally available for multiple-hex attacks, but...
@@ -5951,7 +5951,7 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
return;
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)
{
if(b->additionalInfo[0] > getRandomGenerator().nextInt(99))
@@ -5976,15 +5976,15 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
if(!defender->alive())
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%
if(getRandomGenerator().getDoubleRange(0, 1)() > chanceToTrigger)
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 ||
(bonusAdditionalInfo == CAddInfo::NONE && defender->unitType()->getId() == attacker->unitType()->getId()))
@@ -6001,9 +6001,9 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
else
resurrectInfo.type = attacker->creatureId();
if(attacker->hasBonusOfType((Bonus::TRANSMUTATION), 0))
resurrectInfo.count = std::max((defender->getCount() * defender->MaxHealth()) / resurrectInfo.type.toCreature()->MaxHealth(), 1u);
else if (attacker->hasBonusOfType((Bonus::TRANSMUTATION), 1))
if(attacker->hasBonusOfType((BonusType::TRANSMUTATION), 0))
resurrectInfo.count = std::max((defender->getCount() * defender->getMaxHealth()) / resurrectInfo.type.toCreature()->getMaxHealth(), 1u);
else if (attacker->hasBonusOfType((BonusType::TRANSMUTATION), 1))
resurrectInfo.count = defender->getCount();
else
return; //wrong subtype
@@ -6018,21 +6018,21 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
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;
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;
int percentageToDie = attacker->getBonus(Selector::type()(Bonus::DESTRUCTION).And(Selector::subtype()(0)))->additionalInfo[0];
chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, 0) / 100.0f;
int percentageToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(0)))->additionalInfo[0];
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;
amountToDie = attacker->getBonus(Selector::type()(Bonus::DESTRUCTION).And(Selector::subtype()(1)))->additionalInfo[0];
chanceToTrigger = attacker->valOfBonuses(BonusType::DESTRUCTION, 1) / 100.0f;
amountToDie = attacker->getBonus(Selector::type()(BonusType::DESTRUCTION).And(Selector::subtype()(1)))->additionalInfo[0];
}
vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100%
@@ -6043,7 +6043,7 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
BattleStackAttacked bsa;
bsa.attackerID = -1;
bsa.stackAttacked = defender->unitId();
bsa.damageAmount = amountToDie * defender->MaxHealth();
bsa.damageAmount = amountToDie * defender->getMaxHealth();
bsa.flags = BattleStackAttacked::SPELL_EFFECT;
bsa.spellID = SpellID::SLAYER;
defender->prepareAttacked(bsa, getRandomGenerator());
@@ -6370,9 +6370,9 @@ void CGameHandler::runBattle()
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();
CreatureID creatureData = CreatureID(summonInfo->subtype);
std::vector<BattleHex> targetHexes;
@@ -6417,7 +6417,7 @@ void CGameHandler::runBattle()
auto h = gs->curB->battleGetFightingHero(i);
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)
{
@@ -6485,11 +6485,11 @@ void CGameHandler::runBattle()
{
BattleTriggerEffect bte;
bte.stackID = stack->unitId();
bte.effect = Bonus::HP_REGENERATION;
bte.effect = vstd::to_underlying(BonusType::HP_REGENERATION);
const int32_t lostHealth = stack->MaxHealth() - stack->getFirstHPleft();
if(stack->hasBonusOfType(Bonus::HP_REGENERATION))
bte.val = std::min(lostHealth, stack->valOfBonuses(Bonus::HP_REGENERATION));
const int32_t lostHealth = stack->getMaxHealth() - stack->getFirstHPleft();
if(stack->hasBonusOfType(BonusType::HP_REGENERATION))
bte.val = std::min(lostHealth, stack->valOfBonuses(BonusType::HP_REGENERATION));
if(bte.val) // anything to heal
sendAndApply(&bte);
@@ -6517,7 +6517,7 @@ void CGameHandler::runBattle()
sendAndApply(&removeGhosts);
// check for bad morale => freeze
int nextStackMorale = next->MoraleVal();
int nextStackMorale = next->moraleVal();
if(!next->hadMorale && !next->waited() && nextStackMorale < 0)
{
auto diceSize = VLC->settings()->getVector(EGameSettings::COMBAT_BAD_MORALE_DICE);
@@ -6536,7 +6536,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");
std::pair<const battle::Unit *, BattleHex> attackInfo = curB.getNearestStack(next);
@@ -6564,7 +6564,7 @@ void CGameHandler::runBattle()
const int stackCreatureId = next->unitType()->getId();
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;
attack.actionType = EActionType::SHOOT;
@@ -6609,7 +6609,7 @@ void CGameHandler::runBattle()
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;
attack.actionType = EActionType::CATAPULT;
@@ -6634,7 +6634,7 @@ void CGameHandler::runBattle()
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());
const CStack * toBeHealed = possibleStacks.front();
@@ -6703,7 +6703,7 @@ void CGameHandler::runBattle()
if(next != nullptr)
{
//check for good morale
nextStackMorale = next->MoraleVal();
nextStackMorale = next->moraleVal();
if( !battleResult.get()
&& !next->hadMorale
&& !next->defending
@@ -6719,7 +6719,7 @@ void CGameHandler::runBattle()
{
BattleTriggerEffect bte;
bte.stackID = next->unitId();
bte.effect = Bonus::MORALE;
bte.effect = vstd::to_underlying(BonusType::MORALE);
bte.val = 1;
bte.additionalInfo = 0;
sendAndApply(&bte); //play animation
@@ -6871,7 +6871,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
///Give all spells with bonus (to allow banned spells)
GiveBonus giveBonus(GiveBonus::ETarget::HERO);
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
for (int level = 1; level <= GameConstants::SPELL_LEVELS; level++)
{
@@ -7016,9 +7016,9 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
sendAndApply(&smp);
GiveBonus gb(GiveBonus::ETarget::HERO);
gb.bonus.type = Bonus::FREE_SHIP_BOARDING;
gb.bonus.duration = Bonus::ONE_DAY;
gb.bonus.source = Bonus::OTHER;
gb.bonus.type = BonusType::FREE_SHIP_BOARDING;
gb.bonus.duration = BonusDuration::ONE_DAY;
gb.bonus.source = BonusSource::OTHER;
gb.id = hero->id.getNum();
giveHeroBonus(&gb);
}

View File

@@ -343,7 +343,7 @@ public:
void newTurn();
void handleAttackBeforeCasting(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);
void spawnWanderingMonsters(CreatureID creatureID);
void handleCheatCode(std::string & cheat, PlayerColor player, const CGHeroInstance * hero, const CGTownInstance * town, bool & cheated);