mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Implement psychic elementals vs mind immune units
This commit is contained in:
parent
35c243c30a
commit
eb10433535
@ -187,11 +187,11 @@ TStacks CBattleInfoEssentials::battleGetStacksIf(TStackFilter predicate, bool in
|
|||||||
{
|
{
|
||||||
TStacks ret;
|
TStacks ret;
|
||||||
RETURN_IF_NOT_BATTLE(ret);
|
RETURN_IF_NOT_BATTLE(ret);
|
||||||
|
|
||||||
vstd::copy_if(getBattle()->stacks, std::back_inserter(ret), [=](const CStack * s){
|
vstd::copy_if(getBattle()->stacks, std::back_inserter(ret), [=](const CStack * s){
|
||||||
return predicate(s) && (includeTurrets || !(s->type->idNumber == CreatureID::ARROW_TOWERS));
|
return predicate(s) && (includeTurrets || !(s->type->idNumber == CreatureID::ARROW_TOWERS));
|
||||||
});
|
});
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -784,23 +784,23 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetAvailableHexes(const CStack
|
|||||||
bool CBattleInfoCallback::battleCanAttack(const CStack * stack, const CStack * target, BattleHex dest) const
|
bool CBattleInfoCallback::battleCanAttack(const CStack * stack, const CStack * target, BattleHex dest) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(false);
|
RETURN_IF_NOT_BATTLE(false);
|
||||||
|
|
||||||
if(battleTacticDist())
|
if(battleTacticDist())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!stack || !target)
|
if (!stack || !target)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (stack->owner == target->owner)
|
if (stack->owner == target->owner)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto &id = stack->getCreature()->idNumber;
|
auto &id = stack->getCreature()->idNumber;
|
||||||
if (id == CreatureID::FIRST_AID_TENT || id == CreatureID::CATAPULT)
|
if (id == CreatureID::FIRST_AID_TENT || id == CreatureID::CATAPULT)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!target->alive())
|
if (!target->alive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -997,7 +997,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c
|
|||||||
const bool distPenalty = !info.attackerBonuses->hasBonusOfType(Bonus::NO_DISTANCE_PENALTY) && battleHasDistancePenalty(info.attackerBonuses, info.attackerPosition, info.defenderPosition);
|
const bool distPenalty = !info.attackerBonuses->hasBonusOfType(Bonus::NO_DISTANCE_PENALTY) && battleHasDistancePenalty(info.attackerBonuses, info.attackerPosition, info.defenderPosition);
|
||||||
const bool obstaclePenalty = battleHasWallPenalty(info.attackerBonuses, info.attackerPosition, info.defenderPosition);
|
const bool obstaclePenalty = battleHasWallPenalty(info.attackerBonuses, info.attackerPosition, info.defenderPosition);
|
||||||
|
|
||||||
if (info.shooting)
|
if(info.shooting)
|
||||||
{
|
{
|
||||||
if (distPenalty || info.defenderBonuses->hasBonus(isAdvancedAirShield))
|
if (distPenalty || info.defenderBonuses->hasBonus(isAdvancedAirShield))
|
||||||
{
|
{
|
||||||
@ -1013,9 +1013,14 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c
|
|||||||
multBonus *= 0.5;
|
multBonus *= 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// psychic elementals versus mind immune units 50%
|
||||||
|
if(attackerType->idNumber == CreatureID::PSYCHIC_ELEMENTAL
|
||||||
|
&& info.defenderBonuses->hasBonusOfType(Bonus::MIND_IMMUNITY))
|
||||||
|
{
|
||||||
|
multBonus *= 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO attack on petrified unit 50%
|
// TODO attack on petrified unit 50%
|
||||||
// psychic elementals versus mind immune units 50%
|
|
||||||
// blinded unit retaliates
|
// blinded unit retaliates
|
||||||
|
|
||||||
minDmg *= additiveBonus * multBonus;
|
minDmg *= additiveBonus * multBonus;
|
||||||
@ -1265,8 +1270,8 @@ std::pair<const CStack *, BattleHex> CBattleInfoCallback::getNearestStack(const
|
|||||||
// I hate std::pairs with their undescriptive member names first / second
|
// I hate std::pairs with their undescriptive member names first / second
|
||||||
struct DistStack
|
struct DistStack
|
||||||
{
|
{
|
||||||
int distanceToPred;
|
int distanceToPred;
|
||||||
BattleHex destination;
|
BattleHex destination;
|
||||||
const CStack *stack;
|
const CStack *stack;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1276,7 +1281,7 @@ std::pair<const CStack *, BattleHex> CBattleInfoCallback::getNearestStack(const
|
|||||||
{
|
{
|
||||||
return s != closest && s->alive() && (boost::logic::indeterminate(attackerOwned) || s->attackerOwned == attackerOwned);
|
return s != closest && s->alive() && (boost::logic::indeterminate(attackerOwned) || s->attackerOwned == attackerOwned);
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
for(const CStack * st : possibleStacks)
|
for(const CStack * st : possibleStacks)
|
||||||
for(BattleHex hex : avHexes)
|
for(BattleHex hex : avHexes)
|
||||||
if(CStack::isMeleeAttackPossible(closest, st, hex))
|
if(CStack::isMeleeAttackPossible(closest, st, hex))
|
||||||
@ -1628,9 +1633,9 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
|
|||||||
return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
|
return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
|
||||||
|
|
||||||
const ESpellCastProblem::ESpellCastProblem specificProblem = spell->canBeCast(this, player);
|
const ESpellCastProblem::ESpellCastProblem specificProblem = spell->canBeCast(this, player);
|
||||||
|
|
||||||
if(specificProblem != ESpellCastProblem::OK)
|
if(specificProblem != ESpellCastProblem::OK)
|
||||||
return specificProblem;
|
return specificProblem;
|
||||||
|
|
||||||
if(spell->isNegative() || spell->hasEffects())
|
if(spell->isNegative() || spell->hasEffects())
|
||||||
{
|
{
|
||||||
@ -1667,7 +1672,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
|
|||||||
{
|
{
|
||||||
bool immune = ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack);
|
bool immune = ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack);
|
||||||
bool casterStack = stack->owner == caster->getOwner();
|
bool casterStack = stack->owner == caster->getOwner();
|
||||||
|
|
||||||
if(!immune)
|
if(!immune)
|
||||||
{
|
{
|
||||||
switch (spell->positiveness)
|
switch (spell->positiveness)
|
||||||
@ -1716,12 +1721,12 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetPossibleTargets(PlayerColor
|
|||||||
{
|
{
|
||||||
const CGHeroInstance * caster = battleGetFightingHero(playerToSide(player)); //TODO
|
const CGHeroInstance * caster = battleGetFightingHero(playerToSide(player)); //TODO
|
||||||
const CSpell::TargetInfo ti(spell, caster->getSpellSchoolLevel(spell));
|
const CSpell::TargetInfo ti(spell, caster->getSpellSchoolLevel(spell));
|
||||||
|
|
||||||
for(const CStack * stack : battleAliveStacks())
|
for(const CStack * stack : battleAliveStacks())
|
||||||
{
|
{
|
||||||
bool immune = ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack);
|
bool immune = ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack);
|
||||||
bool casterStack = stack->owner == caster->getOwner();
|
bool casterStack = stack->owner == caster->getOwner();
|
||||||
|
|
||||||
if(!immune)
|
if(!immune)
|
||||||
switch (spell->positiveness)
|
switch (spell->positiveness)
|
||||||
{
|
{
|
||||||
@ -1784,7 +1789,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
|
|||||||
{
|
{
|
||||||
logGlobal->errorStream() << "CBattleInfoCallback::battleCanCastThisSpellHere: no spellcaster.";
|
logGlobal->errorStream() << "CBattleInfoCallback::battleCanCastThisSpellHere: no spellcaster.";
|
||||||
return ESpellCastProblem::INVALID;
|
return ESpellCastProblem::INVALID;
|
||||||
}
|
}
|
||||||
const PlayerColor player = caster->getOwner();
|
const PlayerColor player = caster->getOwner();
|
||||||
ESpellCastProblem::ESpellCastProblem moreGeneralProblem = battleCanCastThisSpell(caster, spell, mode);
|
ESpellCastProblem::ESpellCastProblem moreGeneralProblem = battleCanCastThisSpell(caster, spell, mode);
|
||||||
if(moreGeneralProblem != ESpellCastProblem::OK)
|
if(moreGeneralProblem != ESpellCastProblem::OK)
|
||||||
@ -1894,19 +1899,19 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
|
|||||||
RETURN_IF_NOT_BATTLE(SpellID::NONE);
|
RETURN_IF_NOT_BATTLE(SpellID::NONE);
|
||||||
//This is complete list. No spells from mods.
|
//This is complete list. No spells from mods.
|
||||||
//todo: this should be Spellbook of caster Stack
|
//todo: this should be Spellbook of caster Stack
|
||||||
static const std::set<SpellID> allPossibleSpells =
|
static const std::set<SpellID> allPossibleSpells =
|
||||||
{
|
{
|
||||||
SpellID::AIR_SHIELD,
|
SpellID::AIR_SHIELD,
|
||||||
SpellID::ANTI_MAGIC,
|
SpellID::ANTI_MAGIC,
|
||||||
SpellID::BLESS,
|
SpellID::BLESS,
|
||||||
SpellID::BLOODLUST,
|
SpellID::BLOODLUST,
|
||||||
SpellID::COUNTERSTRIKE,
|
SpellID::COUNTERSTRIKE,
|
||||||
SpellID::CURE,
|
SpellID::CURE,
|
||||||
SpellID::FIRE_SHIELD,
|
SpellID::FIRE_SHIELD,
|
||||||
SpellID::FORTUNE,
|
SpellID::FORTUNE,
|
||||||
SpellID::HASTE,
|
SpellID::HASTE,
|
||||||
SpellID::MAGIC_MIRROR,
|
SpellID::MAGIC_MIRROR,
|
||||||
SpellID::MIRTH,
|
SpellID::MIRTH,
|
||||||
SpellID::PRAYER,
|
SpellID::PRAYER,
|
||||||
SpellID::PRECISION,
|
SpellID::PRECISION,
|
||||||
SpellID::PROTECTION_FROM_AIR,
|
SpellID::PROTECTION_FROM_AIR,
|
||||||
@ -1918,7 +1923,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
|
|||||||
SpellID::STONE_SKIN
|
SpellID::STONE_SKIN
|
||||||
};
|
};
|
||||||
std::vector<SpellID> beneficialSpells;
|
std::vector<SpellID> beneficialSpells;
|
||||||
|
|
||||||
auto getAliveEnemy = [=](const std::function<bool(const CStack * )> & pred)
|
auto getAliveEnemy = [=](const std::function<bool(const CStack * )> & pred)
|
||||||
{
|
{
|
||||||
return getStackIf([=](const CStack * stack)
|
return getStackIf([=](const CStack * stack)
|
||||||
@ -1938,7 +1943,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
|
|||||||
{
|
{
|
||||||
case SpellID::SHIELD:
|
case SpellID::SHIELD:
|
||||||
case SpellID::FIRE_SHIELD: // not if all enemy units are shooters
|
case SpellID::FIRE_SHIELD: // not if all enemy units are shooters
|
||||||
{
|
{
|
||||||
auto walker = getAliveEnemy([&](const CStack * stack) //look for enemy, non-shooting stack
|
auto walker = getAliveEnemy([&](const CStack * stack) //look for enemy, non-shooting stack
|
||||||
{
|
{
|
||||||
return !stack->shots;
|
return !stack->shots;
|
||||||
@ -1963,7 +1968,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
|
|||||||
case SpellID::PROTECTION_FROM_AIR:
|
case SpellID::PROTECTION_FROM_AIR:
|
||||||
case SpellID::PROTECTION_FROM_EARTH:
|
case SpellID::PROTECTION_FROM_EARTH:
|
||||||
case SpellID::PROTECTION_FROM_FIRE:
|
case SpellID::PROTECTION_FROM_FIRE:
|
||||||
case SpellID::PROTECTION_FROM_WATER:
|
case SpellID::PROTECTION_FROM_WATER:
|
||||||
{
|
{
|
||||||
const ui8 enemySide = (ui8)subject->attackerOwned;
|
const ui8 enemySide = (ui8)subject->attackerOwned;
|
||||||
//todo: only if enemy has spellbook
|
//todo: only if enemy has spellbook
|
||||||
@ -2006,7 +2011,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
beneficialSpells.push_back(spellID);
|
beneficialSpells.push_back(spellID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!beneficialSpells.empty())
|
if(!beneficialSpells.empty())
|
||||||
@ -2190,13 +2195,13 @@ TStacks CPlayerBattleCallback::battleGetStacks(EStackOwnership whose /*= MINE_AN
|
|||||||
{
|
{
|
||||||
ASSERT_IF_CALLED_WITH_PLAYER
|
ASSERT_IF_CALLED_WITH_PLAYER
|
||||||
}
|
}
|
||||||
|
|
||||||
return battleGetStacksIf([=](const CStack * s){
|
return battleGetStacksIf([=](const CStack * s){
|
||||||
const bool ownerMatches = (whose == MINE_AND_ENEMY)
|
const bool ownerMatches = (whose == MINE_AND_ENEMY)
|
||||||
|| (whose == ONLY_MINE && s->owner == player)
|
|| (whose == ONLY_MINE && s->owner == player)
|
||||||
|| (whose == ONLY_ENEMY && s->owner != player);
|
|| (whose == ONLY_ENEMY && s->owner != player);
|
||||||
const bool alivenessMatches = s->alive() || !onlyAlive;
|
const bool alivenessMatches = s->alive() || !onlyAlive;
|
||||||
return ownerMatches && alivenessMatches;
|
return ownerMatches && alivenessMatches;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -968,6 +968,7 @@ public:
|
|||||||
WATER_ELEMENTAL = 115,
|
WATER_ELEMENTAL = 115,
|
||||||
GOLD_GOLEM = 116,
|
GOLD_GOLEM = 116,
|
||||||
DIAMOND_GOLEM = 117,
|
DIAMOND_GOLEM = 117,
|
||||||
|
PSYCHIC_ELEMENTAL = 120,
|
||||||
CATAPULT = 145,
|
CATAPULT = 145,
|
||||||
BALLISTA = 146,
|
BALLISTA = 146,
|
||||||
FIRST_AID_TENT = 147,
|
FIRST_AID_TENT = 147,
|
||||||
@ -1053,7 +1054,3 @@ typedef int TRmgTemplateZoneId;
|
|||||||
#undef ID_LIKE_OPERATORS_INTERNAL
|
#undef ID_LIKE_OPERATORS_INTERNAL
|
||||||
#undef INSTID_LIKE_CLASS_COMMON
|
#undef INSTID_LIKE_CLASS_COMMON
|
||||||
#undef OP_DECL_INT
|
#undef OP_DECL_INT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user