mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge pull request #3500 from IvanSavenko/fix_dendroid_bind
[1.4.3] Fix handling of Dendroid's Bind ability
This commit is contained in:
commit
a582cb554e
@ -147,7 +147,7 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
|
||||
(int)bestAttack.from,
|
||||
(int)bestAttack.attack.attacker->getPosition().hex,
|
||||
bestAttack.attack.chargeDistance,
|
||||
bestAttack.attack.attacker->speed(0, true),
|
||||
bestAttack.attack.attacker->getMovementRange(0),
|
||||
bestAttack.defenderDamageReduce,
|
||||
bestAttack.attackerDamageReduce,
|
||||
score
|
||||
@ -553,7 +553,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
|
||||
auto needFullEval = vstd::contains_if(allUnits, [&](const battle::Unit * u) -> bool
|
||||
{
|
||||
auto original = cb->getBattle(battleID)->battleGetUnitByID(u->unitId());
|
||||
return !original || u->speed() != original->speed();
|
||||
return !original || u->getMovementRange() != original->getMovementRange();
|
||||
});
|
||||
|
||||
DamageCache safeCopy = damageCache;
|
||||
|
@ -297,7 +297,7 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
|
||||
if(targets.unreachableEnemies.empty())
|
||||
return result;
|
||||
|
||||
auto speed = activeStack->speed();
|
||||
auto speed = activeStack->getMovementRange();
|
||||
|
||||
if(speed == 0)
|
||||
return result;
|
||||
@ -324,7 +324,7 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
|
||||
|
||||
auto turnsToRich = (distance - 1) / speed + 1;
|
||||
auto hexes = closestStack->getSurroundingHexes();
|
||||
auto enemySpeed = closestStack->speed();
|
||||
auto enemySpeed = closestStack->getMovementRange();
|
||||
auto speedRatio = speed / static_cast<float>(enemySpeed);
|
||||
auto multiplier = speedRatio > 1 ? 1 : speedRatio;
|
||||
|
||||
@ -753,7 +753,7 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUn
|
||||
continue;
|
||||
}
|
||||
|
||||
auto unitSpeed = unit->speed(turn);
|
||||
auto unitSpeed = unit->getMovementRange(turn);
|
||||
auto radius = unitSpeed * (turn + 1);
|
||||
|
||||
ReachabilityInfo unitReachability = vstd::getOrCompute(
|
||||
@ -819,7 +819,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
|
||||
float ratio = blockedUnitDamage / (float)(blockedUnitDamage + activeUnitDamage + 0.01);
|
||||
|
||||
auto unitReachability = turnBattle.getReachability(unit);
|
||||
auto unitSpeed = unit->speed(turn); // Cached value, to avoid performance hit
|
||||
auto unitSpeed = unit->getMovementRange(turn); // Cached value, to avoid performance hit
|
||||
|
||||
for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex = hex + 1)
|
||||
{
|
||||
|
@ -117,7 +117,7 @@ std::vector<SlotInfo>::iterator ArmyManager::getWeakestCreature(std::vector<Slot
|
||||
if(left.creature->getLevel() != right.creature->getLevel())
|
||||
return left.creature->getLevel() < right.creature->getLevel();
|
||||
|
||||
return left.creature->speed() > right.creature->speed();
|
||||
return left.creature->getMovementRange() > right.creature->getMovementRange();
|
||||
});
|
||||
|
||||
return weakest;
|
||||
|
@ -63,7 +63,7 @@ std::vector<SlotInfo>::iterator ArmyManager::getWeakestCreature(std::vector<Slot
|
||||
if(left.creature->getLevel() != right.creature->getLevel())
|
||||
return left.creature->getLevel() < right.creature->getLevel();
|
||||
|
||||
return left.creature->speed() > right.creature->speed();
|
||||
return left.creature->getMovementRange() > right.creature->getMovementRange();
|
||||
});
|
||||
|
||||
return weakest;
|
||||
|
@ -568,7 +568,7 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, B
|
||||
switch (action.get())
|
||||
{
|
||||
case PossiblePlayerBattleAction::CHOOSE_TACTICS_STACK:
|
||||
return (targetStack && targetStackOwned && targetStack->speed() > 0);
|
||||
return (targetStack && targetStackOwned && targetStack->getMovementRange() > 0);
|
||||
|
||||
case PossiblePlayerBattleAction::CREATURE_INFO:
|
||||
return (targetStack && targetStackOwned && targetStack->alive());
|
||||
|
@ -363,7 +363,7 @@ bool MovementAnimation::init()
|
||||
Point begPosition = owner.stacksController->getStackPositionAtHex(prevHex, stack);
|
||||
Point endPosition = owner.stacksController->getStackPositionAtHex(nextHex, stack);
|
||||
|
||||
progressPerSecond = AnimationControls::getMovementDistance(stack->unitType());
|
||||
progressPerSecond = AnimationControls::getMovementRange(stack->unitType());
|
||||
|
||||
begX = begPosition.x;
|
||||
begY = begPosition.y;
|
||||
|
@ -640,7 +640,7 @@ void BattleInterface::tacticPhaseEnd()
|
||||
|
||||
static bool immobile(const CStack *s)
|
||||
{
|
||||
return !s->speed(0, true); //should bound stacks be immobile?
|
||||
return s->getMovementRange() == 0; //should bound stacks be immobile?
|
||||
}
|
||||
|
||||
void BattleInterface::tacticNextStack(const CStack * current)
|
||||
|
@ -148,7 +148,7 @@ float AnimationControls::getSpellEffectSpeed()
|
||||
return static_cast<float>(getAnimationSpeedFactor() * 10);
|
||||
}
|
||||
|
||||
float AnimationControls::getMovementDistance(const CCreature * creature)
|
||||
float AnimationControls::getMovementRange(const CCreature * creature)
|
||||
{
|
||||
// H3 speed: 2/4/6 tiles per second
|
||||
return static_cast<float>( 2.0 * getAnimationSpeedFactor() / creature->animation.walkAnimationTime);
|
||||
|
@ -50,7 +50,7 @@ namespace AnimationControls
|
||||
float getSpellEffectSpeed();
|
||||
|
||||
/// returns speed of movement animation across the screen, in tiles per second
|
||||
float getMovementDistance(const CCreature * creature);
|
||||
float getMovementRange(const CCreature * creature);
|
||||
|
||||
/// returns speed of movement animation across the screen, in pixels per seconds
|
||||
float getFlightDistance(const CCreature * creature);
|
||||
|
@ -543,7 +543,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
|
||||
addStatLabel(EStat::DEFENCE, parent->info->creature->getDefense(battleStack->isShooter()), battleStack->getDefense(battleStack->isShooter()));
|
||||
addStatLabel(EStat::DAMAGE, parent->info->stackNode->getMinDamage(battleStack->isShooter()) * dmgMultiply, battleStack->getMaxDamage(battleStack->isShooter()) * dmgMultiply);
|
||||
addStatLabel(EStat::HEALTH, parent->info->creature->getMaxHealth(), battleStack->getMaxHealth());
|
||||
addStatLabel(EStat::SPEED, parent->info->creature->speed(), battleStack->speed());
|
||||
addStatLabel(EStat::SPEED, parent->info->creature->getMovementRange(), battleStack->getMovementRange());
|
||||
|
||||
if(battleStack->isShooter())
|
||||
addStatLabel(EStat::SHOTS, battleStack->shots.total(), battleStack->shots.available());
|
||||
@ -563,7 +563,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
|
||||
addStatLabel(EStat::DEFENCE, parent->info->creature->getDefense(shooter), parent->info->stackNode->getDefense(shooter));
|
||||
addStatLabel(EStat::DAMAGE, parent->info->stackNode->getMinDamage(shooter) * dmgMultiply, parent->info->stackNode->getMaxDamage(shooter) * dmgMultiply);
|
||||
addStatLabel(EStat::HEALTH, parent->info->creature->getMaxHealth(), parent->info->stackNode->getMaxHealth());
|
||||
addStatLabel(EStat::SPEED, parent->info->creature->speed(), parent->info->stackNode->speed());
|
||||
addStatLabel(EStat::SPEED, parent->info->creature->getMovementRange(), parent->info->stackNode->getMovementRange());
|
||||
|
||||
if(shooter)
|
||||
addStatLabel(EStat::SHOTS, parent->info->stackNode->valOfBonuses(BonusType::SHOTS));
|
||||
|
@ -788,7 +788,7 @@ Determines how many times per combat affected creature can cast its targeted spe
|
||||
- subtype - spell id, eg. spell.iceBolt
|
||||
- value - chance (percent)
|
||||
- additional info - \[X, Y, Z\]
|
||||
- X - spell level
|
||||
- X - spell mastery level (1 - Basic, 3 - Expert)
|
||||
- Y = 0 - all attacks, 1 - shot only, 2 - melee only
|
||||
- Z (optional) - layer for multiple SPELL_AFTER_ATTACK bonuses and multi-turn casting. Empty or value less than 0 = not participating in layering.
|
||||
When enabled - spells from specific layer will not be cast until target has all spells from previous layer on him. Spell from last layer is on repeat if none of spells on lower layers expired.
|
||||
@ -798,7 +798,7 @@ Determines how many times per combat affected creature can cast its targeted spe
|
||||
- subtype - spell id
|
||||
- value - chance %
|
||||
- additional info - \[X, Y, Z\]
|
||||
- X - spell level
|
||||
- X - spell mastery level (1 - Basic, 3 - Expert)
|
||||
- Y = 0 - all attacks, 1 - shot only, 2 - melee only
|
||||
- Z (optional) - layer for multiple SPELL_BEFORE_ATTACK bonuses and multi-turn casting. Empty or value less than 0 = not participating in layering.
|
||||
When enabled - spells from specific layer will not be cast until target has all spells from previous layer on him. Spell from last layer is on repeat if none of spells on lower layers expired.
|
||||
|
@ -23,7 +23,7 @@ class DLL_LINKAGE ACreature: public AFactionMember
|
||||
{
|
||||
public:
|
||||
bool isLiving() const; //non-undead, non-non living or alive
|
||||
ui32 speed(int turn = 0, bool useBind = false) const; //get speed (in moving tiles) of creature with all modificators
|
||||
ui32 getMovementRange(int turn = 0) const; //get speed (in moving tiles) of creature with all modificators
|
||||
virtual ui32 getMaxHealth() const; //get max HP of stack with all modifiers
|
||||
};
|
||||
|
||||
|
@ -168,15 +168,14 @@ ui32 ACreature::getMaxHealth() const
|
||||
return std::max(1, value); //never 0
|
||||
}
|
||||
|
||||
ui32 ACreature::speed(int turn, bool useBind) const
|
||||
ui32 ACreature::getMovementRange(int turn) const
|
||||
{
|
||||
//war machines cannot move
|
||||
if(getBonusBearer()->hasBonus(Selector::type()(BonusType::SIEGE_WEAPON).And(Selector::turns(turn))))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
//bind effect check - doesn't influence stack initiative
|
||||
if(useBind && getBonusBearer()->hasBonus(Selector::type()(BonusType::BIND_EFFECT).And(Selector::turns(turn))))
|
||||
if(getBonusBearer()->hasBonus(Selector::type()(BonusType::BIND_EFFECT).And(Selector::turns(turn))))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ std::vector<PossiblePlayerBattleAction> CBattleInfoCallback::getClientActionsFor
|
||||
allowedActionList.push_back(PossiblePlayerBattleAction::ATTACK); //all active stacks can attack
|
||||
allowedActionList.push_back(PossiblePlayerBattleAction::WALK_AND_ATTACK); //not all stacks can always walk, but we will check this elsewhere
|
||||
|
||||
if(stack->canMove() && stack->speed(0, true)) //probably no reason to try move war machines or bound stacks
|
||||
if(stack->canMove() && stack->getMovementRange(0)) //probably no reason to try move war machines or bound stacks
|
||||
allowedActionList.push_back(PossiblePlayerBattleAction::MOVE_STACK);
|
||||
|
||||
const auto * siegedTown = battleGetDefendedTown();
|
||||
@ -570,7 +570,7 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetAvailableHexes(const Reacha
|
||||
if(!unit->getPosition().isValid()) //turrets
|
||||
return ret;
|
||||
|
||||
auto unitSpeed = unit->speed(0, true);
|
||||
auto unitSpeed = unit->getMovementRange(0);
|
||||
|
||||
const bool tacticsPhase = battleTacticDist() && battleGetTacticsSide() == unit->unitSide();
|
||||
|
||||
@ -741,15 +741,15 @@ DamageEstimation CBattleInfoCallback::battleEstimateDamage(const battle::Unit *
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE({});
|
||||
auto reachability = battleGetDistances(attacker, attacker->getPosition());
|
||||
int movementDistance = reachability[attackerPosition];
|
||||
return battleEstimateDamage(attacker, defender, movementDistance, retaliationDmg);
|
||||
int getMovementRange = reachability[attackerPosition];
|
||||
return battleEstimateDamage(attacker, defender, getMovementRange, retaliationDmg);
|
||||
}
|
||||
|
||||
DamageEstimation CBattleInfoCallback::battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, int movementDistance, DamageEstimation * retaliationDmg) const
|
||||
DamageEstimation CBattleInfoCallback::battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, int getMovementRange, DamageEstimation * retaliationDmg) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE({});
|
||||
const bool shooting = battleCanShoot(attacker, defender->getPosition());
|
||||
const BattleAttackInfo bai(attacker, defender, movementDistance, shooting);
|
||||
const BattleAttackInfo bai(attacker, defender, getMovementRange, shooting);
|
||||
return battleEstimateDamage(bai, retaliationDmg);
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ public:
|
||||
/// returns pair <min dmg, max dmg>
|
||||
DamageEstimation battleEstimateDamage(const BattleAttackInfo & bai, DamageEstimation * retaliationDmg = nullptr) const;
|
||||
DamageEstimation battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, BattleHex attackerPosition, DamageEstimation * retaliationDmg = nullptr) const;
|
||||
DamageEstimation battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, int movementDistance, DamageEstimation * retaliationDmg = nullptr) const;
|
||||
DamageEstimation battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, int getMovementRange, DamageEstimation * retaliationDmg = nullptr) const;
|
||||
|
||||
bool battleHasPenaltyOnLine(BattleHex from, BattleHex dest, bool checkWall, bool checkMoat) const;
|
||||
bool battleHasDistancePenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const;
|
||||
|
@ -659,7 +659,7 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
|
||||
|
||||
ret = path.second;
|
||||
|
||||
int creSpeed = curStack->speed(0, true);
|
||||
int creSpeed = curStack->getMovementRange(0);
|
||||
|
||||
if (battle.battleGetTacticDist() > 0 && creSpeed > 0)
|
||||
creSpeed = GameConstants::BFIELD_SIZE;
|
||||
@ -1139,18 +1139,10 @@ void BattleActionProcessor::attackCasting(const CBattleInfoCallback & battle, bo
|
||||
for(const auto & sf : *spellsByType)
|
||||
{
|
||||
int meleeRanged;
|
||||
if(sf->additionalInfo.size() < 2)
|
||||
{
|
||||
// legacy format
|
||||
vstd::amax(spellLevel, sf->additionalInfo[0] % 1000);
|
||||
meleeRanged = sf->additionalInfo[0] / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
vstd::amax(spellLevel, sf->additionalInfo[0]);
|
||||
meleeRanged = sf->additionalInfo[1];
|
||||
}
|
||||
if (meleeRanged == 0 || (meleeRanged == 1 && ranged) || (meleeRanged == 2 && !ranged))
|
||||
vstd::amax(spellLevel, sf->additionalInfo[0]);
|
||||
meleeRanged = sf->additionalInfo[1];
|
||||
|
||||
if (meleeRanged == CAddInfo::NONE || meleeRanged == 0 || (meleeRanged == 1 && ranged) || (meleeRanged == 2 && !ranged))
|
||||
castMe = true;
|
||||
}
|
||||
int chance = attacker->valOfBonuses((Selector::typeSubtype(attackMode, BonusSubtypeID(spellID))));
|
||||
|
Loading…
Reference in New Issue
Block a user