1
0
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:
Vadim Markovtsev 2016-02-01 20:03:57 +03:00
parent 35c243c30a
commit eb10433535
2 changed files with 35 additions and 33 deletions

View File

@ -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;
}); });
} }

View File

@ -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